Weibo

Gallery

路 纸巾筒 猫 goggles_translation britpop - 有谁能把全部人都认出来? 水乐坊

John Mayer

最简单的MATLAB车牌字符分割(附源码)

有一天,王老师说,他的车牌识别率可以达到86%(当然,不知道是以什么标准,在怎样的环境下,识别怎样的车牌),我总觉得我能用我的方法做得再好一点。试着写了下面这一个简单的字符分割Script,出来结果后才发现自己是多么幼稚阿··· 这笨方法只能当作入门了。

先说明,这是一个最简单的车牌字符分割程序,结果连我自己都觉得惨不忍睹··· 太打击了。

正如前文提到的,传统LPR通常要求在识别任务前先做一个字符分割。应该算是整个LPR程序中最简单的一步了。只是,就连这么简单的步骤也需要我们的很多考虑,需要牺牲大量的脑细胞来得到个还算说得过去的办法。你看完就知道了。

程序大概分为3步:1、灰度化/二值化/直方图均衡化/归一化大小;  2、去噪; 3、分割。

由于使用MATLAB作为平台,第一步几乎可以以一句话完成。这里不做过多陈述:

bgs_img = filter2(fspecial('average',2),im2bw(histeq(rgb2gray(ori_img)),0.8));

而对于去噪一步,需要花一点心思。不要以为去噪就是传统的高斯、中值滤波之类的东西,在自然环境中,干扰是无穷无尽的。对于我们的车牌识别程序,干扰我们的通常会有光照、车牌上的污点等等,这些干扰通常会使用普通图像处理手段来解决,比如用高斯等平滑滤波,用直方图均衡化等。然而,还有另外一些干扰也要引起我们的注意,就是车牌的边沿、螺丝等等,这些是几乎每个车都有的问题,因此解决这种问题更显得程序的通用性。

MM520

网上摘录的车牌

给出一个网上摘录下来的车牌(好牌号呀!),我们可以看到,尽管车牌已经比较完美地定位(切割)了出来,但是对于提取纯字符任务来说,我们还面临着边沿、螺丝、空隙等挑战。

在这里尝试采用比较常见的统计手段来解决这个问题:

在得到二值化图像之后,我们可以得到一个二值矩阵(这不废话),当某位置的值等于0的时候,表示该像素点为全黑,反之,则该像素点为纯白。然后我们可以对此二值矩阵分别对行、列进行求和统计。

下一页是代码摘要和详解

试谈MATLAB代码性优化及编程策略

相信用过Matlab的朋友,特别是需要处理大数据(matrix/cell/structure…)的朋友,必然深深地体会到Matlab的“慢”与“肥”。不仅脚本执行效率不高(不是不高,是Matlab简直就是性能低下),就连Initialize都要半天。还有经常性清脆地“滴”一声之后,出现红色的提示“Out of memory”。还有对多线程的支持不好、CPU无法满载、打开*.mat数据大小限制等等问题,总之一言难尽。

在写了不多,但是也不算少的matlab程序之后,特别是大量跟数据搏斗的程序,我开始渐渐有些体会。这里提出一些方法,是一些小技巧,是小人物、破机器跟贱数据搏斗之后,大难不死的一些心得,也有一些是引用别人的心得。趁着假期将它们逐渐整理出来,或许不是很全,有一些曾经注意过的地方有遗漏,所以或许还会有续集。

Matlab性能优化,通过优化代码,通常主要优化的对象是两个,一是效率、速度,二是系统资源的占用

  • 【速度优化】慎用for、while循环,多用矩阵运算(Vectorizing your code)。
    习惯于c/c++等非高级语言的朋友在开始接触Matlab的时候通常会忽略很重要的一点,就是matlab它自身带有非常强大的矩阵运算(Vectorized function),不习惯或者不知晓这种方式的朋友通常会选择使用for等循环方式来对矩阵中的单元格进行遍历处理。其实for循环在Matlab当中是非常慢的,尽管有文章声称Matlab已经改进一些Matlab基础方法(basic components)的速度,但是在2009b版本仍然没有看到太大的改善。所以在需要对矩阵进行操作时候,最好灵活应用矩阵运算方法。
    矩阵运算方法是一个不大不小的学问,其实我觉得看书的能学到的技巧微乎其微,关键还是要靠自己平时的积累,以下列举一个遍历矩阵的实例:需要遍历一个30×30的矩阵A,找出等于7的项,并对其执行相应的操作。
    position = find(A==9);
    上面的命令返回一个列向量指出A中等于7的位置
    然后我们对A进行操作,对等于7的地方赋予717,对于第一种用find命令得到的position可以这样写:
    A(position)=717;
    又或者,如果position变量你只用到一次的话,其实可以省下一个position变量,直接这样写:
    A(find(A==7))=717;
    再举一例吧,这次假设我们一定非得要用for循环来对矩阵进行遍历,这时候我们只需要一个for循环就可以实现对矩阵实行遍历:
    for i=1:(size(A,1)*size(A,2)) Do_Something_Here(); end
    因为Matlab中矩阵的格子有一个单一的索引号从第一列开始从上到下数完全部行之后再移到下一列,因此只一个for循环就ok了。
    忍不住再举一例,也算是一个技巧。某些情况下我们还是需要用两个for循环来对矩阵进行操作,这时候我们可以把对列(column)的循环写到外面,把对行(row)的循环写到里面。因为这样会快一倍左右。至于为什么会快一点呢?我懒得翻译了,直接给出传说中的答案:
    Modern CPUs use a fast cache to reduce the average time taken to access main memory. Your code achieves maximum cache efficiency when it traverses monotonically increasing memory locations. Because MATLAB stores matrix columns in monotonically increasing memory locations, processing data column-wise results in maximum cache efficiency.
    最后列出一些常用的矩阵运算时候经常用到的命令:
    all end logical repmat squeeze
    any find ndgrid reshape sub2ind
    cumsum ind2sub permute shiftdim sum
    diff ipermute prod sort -

 

  • 【速度优化】先定义矩阵大小,防止矩阵在程序中不断变换大小。
    其实Matlab中不一定要先定义变量,因为Matlab中的变量是非常灵活的。但是这种灵活性不代表Matlab就会智能到知晓一切,比如你的变量的大小。于是很多人都可能会忽略一点就是,在循环中让你的矩阵变量不定型地变换大小是非常致命的(总要自己试过才知道是多致命)。而唯一的终极解决的方法就是不要那么懒(大忌),在循环之前先计算好矩阵的大小,然后预先给你的矩阵指定大小(用zeros或者ones,随你)。如此,速度可能会是1000倍速以上,不信你试试···
  • 【速度优化】function比script更快
    其实这个我也是在网上看到的,说是运行脚本会把不必要的变量加载到内存,而函数只加载一次。我自己并没有太多感觉。但是function的确比script好的一个地方就是,function结束以后,除了在function头定义的输出变量之外,并没有其他任何function所涉及到的变量会被保留,这个首先就是不会造成宝贵的内存空间的浪费,再就是debug的时候不会头晕晕将变量都搞糊涂了(除非你有非常统一的变量命名规则,我就不信你永远都不会用i、j之类的临时循环计数变量)。
  • 【速度优化】关于Matlab中的I/O
    先说说数据文件格式的选择。当我们保存数据、再读取数据的时候,我们应该首先考虑mat类型的数据文件格式。首先mat类型的通用性比较好,只要Include一个mat.h的头文件,在c程序中也可以实现读取mat文件,而不必担心它的格式不通用的问题。再者,由mat文件读入数据后,可以轻易地用Matlab自带函数(如csvwrite、xlswrite等)将其转换成其他通用数据格式诸如csv、xls。还有一个考虑到的地方将会在下面提到,是关于Matlab中I/O命令的执行效率问题。
    在Matlab中,load/save命令是加载mat格式文件用到的两个命令,其已经对读取文件进行过优化,效率要比fopen之类的要高。所以在I/O命令的选择上面,除非碰到.txt/.dat之类的非通用格式的文件没办法外,我们一般都建议使用load/save来加载mat文件。
    最后还有非常重要的地方要提一下,就是在进行对硬盘中文件I/O操作的时候,千万不要再开其他程序对那些文件或者其所在的文件夹进行读取或者写入。首先,两个程序同时对一个文件夹操作会造成文件检索、文件读写缓慢,甚至能让Matlab假死的情况出现。平时我用Linux系统的时候更是感觉文件系统不及windows快速,打开多文件的文件夹速度明显不如windows,不知道是GNOME桌面还是Nautilus的问题。还有一点,就是一个程序在那个文件夹里面增加/减少文件,会导致另外一个程序的I/O错误,比如说这边删掉了一个文件,那边却正在读那个文件,当然就是crash啦。
  • 【速度优化】关于不必要的变量(Unnecessary Variables)

有人可能会认为,不必要的变量只是会占用内存空间而已(虽然已经够致命了)。其实不然,多余的变量还会影响速度。试用下面两个代码段作比较:

    %% segment 1.
    tic;
    x=myfun(x);
    t_seg1=toc;
    disp(t_seg1);
    %% segment 2.
    tic;
    y=myfun(x);
    t_seg2=toc;
    disp(t_seg2);
    结果是t_seg2比t_seg1大了两个数量级,两个代码的区别是seg1比sge2少创建一个不必要的变量y。至于为什么减少不必要的变量可以使速度变快呢?原因很简单,还是那个,你创建一个新变量,必须在内存中给它allocate一个空间,必须赋值给它,这些都是需要时间的,虽然处理小数据的时候,这些并没有什么太大分别,但是当你需要与大数据、小内存搏斗时,你就要开始考虑这些细节了。

还有下一页… 好臭好长…

HMM中的前向法(Forward Agorithm)

在假期的前几天颓废了好一阵之后,终于重新拾起未完成的事情。根据计划是按照HMM -> MEM -> CRF -> hCRF 这个伟大目标前进的。HMM已经在之前写了一个文章(惊喜地发现在google里面搜“HMM模型”,它出现在了第一页 ;-) ),这里写的是HMM中,解决第一个问题,即估值问题的一个快速算法 – 前向法(Forward Agorithm)。过几天还会陆续完全弄懂、写好Viterbi与Baum-Welch算法。

本文目录:

  • Page 1: 前文提要
  • Page 2: 普通的穷举算法
  • Page 3: 可行的替代算法 – 前向法
  • Page 4: 参考书目
Last Modified:2010/07/09 21:06 All rights reserved.

前文提要:

在之前的HMM文章中提到,HMM模型将涉及到3个问题:

  1. 给定一个观察到得序列O,及参数\lambda,求出P(O|\lambda),即发生这种观察序列的可能性。对应上面例子中,即是我给定一个最终确定了的水果序列S,求我选到这样的水果的可能性。
  2. 给定一个观察到的序列O,及参数\lambda,求出最有可能产生这种序列的状态序列S。对应上面例子中,即我给定一个最终确定了的水果序列S,求我最可能的选水果筐路径。
  3. 同样给定一个观察得到的序列O,求如何调整参数\lambda,使P(O|\lambda)最大。

这里讨论的将会是第一个问题,即所谓的估值问题。

再次,在问题一中我们的目标是求出可见序列O在参数集\lambda(包含Transition Matrix、Emission Matrix、N、M、Pi)中的发生概率,即求P(O|\lambda),请着眼于这个概率,以下将以P(O|\lambda)作为主角。

(请留意换页… Next Page »)

The Way Life’s Meant to Be

忽然听这首歌的时候很有感触,从未有过的悲哀。

Electric Light Orchester – Light (the cover)

It seemed to be [a pessimistic view] on that song. Yeah, well, and absolute that song… He’s walking down the same street that it was before, like say a hundred years before. But uh, even though he’s on the same bit of ground, everything that he knew is, . . . → Read More: The Way Life’s Meant to Be

当时你我都还小,都还不怎么操。

. . . → Read More: 当时你我都还小,都还不怎么操。