Fork me on GitHub

EasyPR--开发详解(3)高斯模糊、灰度化和Sobel算子

  上篇文章中我们了解了PlateLocate的过程中的所有步骤。在本篇文章中我们对前3个步骤,分别是高斯模糊、灰度化和Sobel算子进行分析。

一、高斯模糊

 1.目标

  对图像去噪,为边缘检测算法做准备。  

 2.效果

  在我们的车牌定位中的第一步就是高斯模糊处理。

  

图1 高斯模糊效果

 3.理论 

  详细说明可以看这篇:阮一峰讲高斯模糊

  高斯模糊是非常有名的一种图像处理技术。顾名思义,其一般应用是将图像变得模糊,但同时高斯模糊也应用在图像的预处理阶段。理解高斯模糊前,先看一下平均模糊算法。平均模糊的算法非常简单。见下图,每一个像素的值都取周围所有像素(共8个)的平均值。



图2 平均模糊示意图


  在上图中,左边红色点的像素值本来是2,经过模糊后,就成了1(取周围所有像素的均值)。在平均模糊中,周围像素的权值都是一样的,都是1。如果周围像素的权值不一样,并且与二维的高斯分布的值一样,那么就叫做高斯模糊。

  在上面的模糊过程中,每个像素取的是周围一圈的平均值,也称为模糊半径为1。如果取周围三圈,则称之为半径为3。半径增大的话,会更加深模糊的效果。

 4.实践

  在PlateLocate中是这样调用高斯模糊的。

    //高斯模糊。Size中的数字影响车牌定位的效果。
    GaussianBlur( src, src_blur, Size(m_GaussianBlurSize, m_GaussianBlurSize), 
        0, 0, BORDER_DEFAULT );

  其中Size字段的参数指定了高斯模糊的半径。值是CPlateLocate类的m_GaussianBlurSize变量。由于opencv的高斯模糊仅接收奇数的半径,因此变量为偶数值会抛出异常。

  这里给出了opencv的高斯模糊的API(英文,2.48以上版本)。

  高斯模糊这个过程一定是必要的么。笔者的回答是必要的,倘若我们将这句代码注释并稍作修改,重新运行一下。你会发现plateLocate过程在闭操作时就和原来发生了变化。最后结果如下。

图3 不采用高斯模糊后的结果  

  可以看出,车牌所在的矩形产生了偏斜。最后得到的候选“车牌”图块如下:

                

图4 不采用高斯模糊后的“车牌”图块

  如果不使用高斯模糊而直接用边缘检测算法,我们得到的候选“车牌”达到了8个!这样不仅会增加车牌判断的处理时间,还增加了判断出错的概率。由于得到的车牌图块中车牌是斜着的,如果我们的字符识别算法需要一个水平的车牌图块,那么几乎肯定我们会无法得到正确的字符识别效果。

   高斯模糊中的半径也会给结果带来明显的变化。有的图片,高斯模糊半径过高了,车牌就定位不出来。有的图片,高斯模糊半径偏低了,车牌也定位不出来。因 此、高斯模糊的半径既不宜过高,也不能过低。CPlateLocate类中的值为5的静态常量DEFAULT_GAUSSIANBLUR_SIZE,标示 着推荐的高斯模糊的半径。这个值是对于近千张图片经过测试后得出的综合定位率最高的一个值。在CPlateLocate类的构造函数 中,m_GaussianBlurSize被赋予了DEFAULT_GAUSSIANBLUR_SIZE的值,因此,默认的高斯模糊的半径就是5。如果不 是特殊情况,不需要修改它。

  在数次的实验以后,必须承认,保留高斯模糊过程与半径值为5是最佳的实践。为应对特殊需求,在CPlateLocate类中也应该提供了方法修改高斯半径的值,调用代码(假设需要一个为3的高斯模糊半径)如下:

    CPlateLocate plate;
    plate.setGaussianBlurSize(3);

   目前EasyPR的处理步骤是先进行高斯模糊,再进行灰度化。从目前的实验结果来看,基于色彩的高斯模糊过程比灰度后的高斯模糊过程更容易检测到边缘点。

 

二、灰度化处理

 1.目标

  为边缘检测算法准备灰度化环境。

 2.效果

  灰度化的效果如下。

图5 灰度化效果

 3.理论

  在灰度化处理步骤中,争议最大的就是信息的损失。无疑的,原先plateLocate过程面对的图片是彩色图片,而从这一步以后,就会面对的是灰度图片。在前面,已经说过这步骤是利是弊是需要讨论的。

   无疑,对于计算机而言,色彩图像相对于灰度图像难处理多了,很多图像处理算法仅仅只适用于灰度图像,例如后面提到的Sobel算子。在这种情况下,你除 了把图片转成灰度图像再进行处理别无它法,除非重新设计算法。但另一方面,转化成灰度图像后恰恰失去了最丰富的细节。要知道,真实世界是彩色的,人类对于 事物的辨别是基于彩色的框架。甚至可以这样说,因为我们的肉眼能够区别彩色,所以我们对于事物的区分,辨别,记忆的能力就非常的强。

   车牌定位环节中去掉彩色的利弊也是同理。转换成灰度图像虽然利于使用各种专用的算法,但失去了真实世界中辨别的最重要工具---色彩的区分。举个简单的例 子,人怎么在一张图片中找到车牌?非常简单,一眼望去,一个合适大小的矩形,蓝色的、或者黄色的、或者其他颜色的在另一个黑色,或者白色的大的跟车形类似 的矩形中。这个过程非常直观,明显,而且可以排除模糊,色泽,不清楚等很多影响。如果使用灰度图像,就必须借助水平,垂直求导等方法。

   未来如果PlateLocate过程可以使用颜色来判断,可能会比现在的定位更清楚、准确。但这需要研究与实验过程,在EasyPR的未来版本中可能会 实现。但无疑,使用色彩判断是一种趋势,因为它不仅符合人眼识别的规律,更趋近于人工智能的本质,而且它更准确,速度更快。

 4.实践 

  在PlateLocate过程中是这样调用灰度化的。

cvtColor( src_blur, src_gray, CV_RGB2GRAY );

  这里给出了opencv的灰度化的API(英文,2.48以上版本)。

 

三.Sobel算子

 1.目标

  检测图像中的垂直边缘,便于区分车牌。

 2.效果

  下图是Sobel算子的效果。


图6 Sobel效果 

 3.理论  

  如果要说哪个步骤是plateLocate中的核心与灵魂,毫无疑问是Sobel算子。没有Sobel算子,也就没有垂直边缘的检测,也就无法得到车牌 的可能位置,也就没有后面的一系列的车牌判断、字符识别过程。通过Sobel算子,可以很方便的得到车牌的一个相对准确的位置,为我们的后续处理打好坚实 的基础。在上面的plateLocate的执行过程中可以看到,正是通过Sobel算子,将车牌中的字符与车的背景明显区分开来,为后面的二值化与闭操作 打下了基础。那么Sobel算子是如何运作的呢?

  Soble算子原理是对图像求一阶的水平与垂直方向导数,根据导数值的大小来判断是否是边缘。请详见CSDN小魏的博客(小心她博客里把Gx和Gy弄反了)。

  为了计算方便,Soble算子并没有真正去求导,而是使用了周边值的加权和的方法,学术上称作“卷积”。权值称为“卷积模板”。例如下图左边就是Sobel的Gx卷积模板(计算垂直边缘),中间是原图像,右边是经过卷积模板后的新图像。

  图7 Sobel算子Gx示意图

  在这里演示了通过卷积模板,原始图像红色的像素点原本是5的值,经过卷积计算(- 1 * 3 - 2 * 3 - 1 * 4 + 1 * 5 + 2 * 7 + 1 * 6 = 12)后红色像素的值变成了12。

 4.实践

  在代码中调用Soble算子需要较多的步骤。

    /// Generate grad_x and grad_y
    Mat grad_x, grad_y;
    Mat abs_grad_x, abs_grad_y;

    /// Gradient X
    //Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
    Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
    convertScaleAbs( grad_x, abs_grad_x );

    /// Gradient Y
    //Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
    Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
    convertScaleAbs( grad_y, abs_grad_y );

    /// Total Gradient (approximate)
    addWeighted( abs_grad_x, SOBEL_X_WEIGHT, abs_grad_y, SOBEL_Y_WEIGHT, 0, grad );

  这里给出了opencv的Sobel的API(英文,2.48以上版本)

  在调用参数中有两个常量SOBEL_X_WEIGHT与SOBEL_Y_WEIGHT代表水平方向和垂直方向的权值,默认前者是1,后者是0,代表仅仅做水平方向求导,而不做垂直方向求导。这样做的意义是,如果我们做了垂直方向求导,会检测出很多水平边缘。水平边缘多也许有利于生成更精确的轮廓,但是由于有些车子前端太多的水平边缘了,例如车头排气孔,标志等等,很多的水平边缘会误导我们的连接结果,导致我们得不到一个恰好的车牌位置。例如,我们对于测试的图做如下实验,将SOBEL_X_WEIGHT与SOBEL_Y_WEIGHT都设置为0.5(代表两者的权值相等),那么最后得到的闭操作后的结果图为

  由于Sobel算子如此重要,可以将车牌与其他区域明显区分出来,那么问题就来了,有没有与Sobel功能类似的算子可以达到一致的效果,或者有没有比Sobel效果更好的算子?

  Sobel算子求图像的一阶导数,Laplace算子则是求图像的二阶导数,在通常情况下,也能检测出边缘,不过Laplace算子的检测不分水平和垂直。下图是Laplace算子与Sobel算子的一个对比。

图8 Sobel与Laplace示意图
  

  可以看出,通过Laplace算子的图像包含了水平边缘和垂直边缘,根据我们刚才的描述。水平边缘对于车牌的检测一般无利反而有害。经过对近百幅图像的测试,Sobel算子的效果优于Laplace算子,因此不适宜采用Laplace算子替代Sobel算子。

  除了Sobel算子,还有一个算子,Shcarr算子。但这个算子其实只是Sobel算子的一个变种,由于Sobel算子在3*3的卷积模板上计算往往不太精确,因此有一个特殊的Sobel算子,其权值按照下图来表达,称之为Scharr算子。下图是Sobel算子与Scharr算子的一个对比。


  图9 Sobel与Scharr示意图


  一般来说,Scharr算子能够比Sobel算子检测边缘的效果更好,从上图也可以看出。但是,这个“更好”是一把双刃剑。我们的目的并不是画出图像的边缘,而是确定车牌的一个区域,越精细的边缘越会干扰后面的闭运算。因此,针对大量的图片的测试,Sobel算子一般都优于Scharr算子。

  关于Sobel算子更详细的解释和Scharr算子与Sobel算子的同异,可以参看官网的介绍:Sobel与Scharr

  综上所述,在求图像边缘的过程中,Sobel算子是一个最佳的契合车牌定位需求的算子,Laplace算子与Scharr算子的效果都不如它。

  有一点要说明的:Sobel算子仅能对灰度图像有效果,不能将色彩图像作为输入。因此在进行Soble算子前必须进行前面的灰度化工作。

   

版权说明:

  本文中的所有文字,图片,代码的版权都是属于作者和博客园共同所有。欢迎转载,但是务必注明作者与出处。任何未经允许的剽窃以及爬虫抓取都属于侵权,作者和博客园保留所有权利。

 

参考文献:

  1.http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html

  2.http://blog.csdn.net/xiaowei_cqu/article/details/7829481

  3.http://docs.opencv.org/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.html

posted @ 2014-10-14 16:50 计算机的潜意识 阅读(...) 评论(...) 编辑 收藏