博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
EasyPR源码剖析(4):车牌定位之Sobel算子定位
阅读量:5117 次
发布时间:2019-06-13

本文共 4787 字,大约阅读时间需要 15 分钟。

一、简介

sobel算子主要是用于获得数字图像的一阶梯度,常见的应用是边缘检测。

Ⅰ.水平变化: 将 I 与一个奇数大小的内核进行卷积。比如,当内核大小为3时, 的计算结果为:

 

Ⅱ.垂直变化: 将: I 与一个奇数大小的内核进行卷积。比如,当内核大小为3时, 的计算结果为:

 

 

Opencv中Sobel函数使用扩展的Sobel算子,来计算一阶、二阶、三阶或混合图像差分。

 

CV_EXPORTS_W void Sobel( InputArray src,  OutputArray dst, int ddepth,                           int dx, int dy, int ksize=3,                    double scale=1, double delta=0,   int borderType=BORDER_DEFAULT );
  • 第一个参数,InputArray 类型的src,为输入图像,填Mat类型即可。
  • 第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。
  • 第三个参数,int类型的ddepth,输出图像的深度。
  • 第四个参数,int类型dx,x 方向上的差分阶数。
  • 第五个参数,int类型dy,y方向上的差分阶数。
  • 第六个参数,int类型ksize,有默认值3,表示Sobel核的大小;必须取1,3,5或7。
  • 第七个参数,double类型的scale,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。我们可以在文档中查阅getDerivKernels的相关介绍,来得到这个参数的更多信息。
  • 第八个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
  • 第九个参数, int类型的borderType,我们的老朋友了(万年是最后一个参数),边界模式,默认值为BORDER_DEFAULT。这个参数可以在官方文档中borderInterpolate处得到更详细的信息。

具体的Sobel算子使用实例如下面代码所示:

/// 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 );  //Calculates the first, second, third, or mixed image derivatives using an extended Sobel operator.  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, 0.5, abs_grad_y, 0.5, 0, grad );

 

二、Sobel算子定位

 Sobel定位主要函数为 plateSobelLocate() ,主要处理函数有两个,一个是 sobelFrtSearch() ,另一个是对定位区域进行偏斜扭转的函数deskew(),deskew()后面会统一详细讲解,这边我们主要看一下通过sobel算子定位的函数 sobelFrtSearch() 。

sobelFrtSearch()函数中通过 sobelOper() 进行sobel定位,主要步骤如下:

1、对图像进行高斯滤波,为Sobel算子计算去除干扰噪声;

2、图像灰度化,提高运算速度;

3、对图像进行Sobel运算,得到图像的一阶水平方向导数;

4、通过otsu进行阈值分割;

5、通过形态学闭操作,连接车牌区域。

此处通过Sobel算子进行车牌定位,仅仅做水平方向求导,而不做垂直方向求导。这样做的意义是,如果做了垂直方向求导,会检测出很多水平边缘。水平边缘多也许有利于生成更精确的轮廓,但是由于有些车子前端太多的水平边缘了,例如车头排气孔,标志等等,很多的水平边缘会误导我们的连接结果,导致我们得不到一个恰好的车牌位置。

具体实现代码如下所示:

1 int CPlateLocate::sobelOper(const Mat &in, Mat &out, int blurSize, int morphW,int morphH) { 2   Mat mat_blur; 3   mat_blur = in.clone(); 4   GaussianBlur(in, mat_blur, Size(blurSize, blurSize), 0, 0, BORDER_DEFAULT); 5  6   Mat mat_gray; 7   if (mat_blur.channels() == 3) 8     cvtColor(mat_blur, mat_gray, CV_RGB2GRAY); 9   else10     mat_gray = mat_blur;11 12   int scale = SOBEL_SCALE;13   int delta = SOBEL_DELTA;14   int ddepth = SOBEL_DDEPTH;15 16   Mat grad_x, grad_y;17   Mat abs_grad_x, abs_grad_y;18 19 20   Sobel(mat_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);21   convertScaleAbs(grad_x, abs_grad_x);22 23   Mat grad;24   addWeighted(abs_grad_x, SOBEL_X_WEIGHT, 0, 0, 0, grad);25 26   Mat mat_threshold;27   double otsu_thresh_val =28       threshold(grad, mat_threshold, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);29 30 31   Mat element = getStructuringElement(MORPH_RECT, Size(morphW, morphH));32   morphologyEx(mat_threshold, mat_threshold, MORPH_CLOSE, element);33 34   out = mat_threshold;35 36   return 0;37 }
View Code

上述图像经过处理之后,可以直接对图像轮廓进行搜索,轮廓搜索将全图的轮廓都搜索出来了,需要进行筛选,对轮廓求最小外接矩形,并在 verifySizes() 中进行验证,不满足条件的删除。 具体实现代码如下所示:

1 int CPlateLocate::sobelFrtSearch(const Mat &src, 2                                  vector
> &outRects) { 3 Mat src_threshold; 4 5 sobelOper(src, src_threshold, m_GaussianBlurSize, m_MorphSizeWidth, 6 m_MorphSizeHeight); 7 8 vector
> contours; 9 findContours(src_threshold,10 contours, // a vector of contours11 CV_RETR_EXTERNAL,12 CV_CHAIN_APPROX_NONE); // all pixels of each contours13 14 vector
>::iterator itc = contours.begin();15 16 vector
first_rects;17 18 while (itc != contours.end()) {19 RotatedRect mr = minAreaRect(Mat(*itc));20 21 22 if (verifySizes(mr)) {23 first_rects.push_back(mr);24 25 float area = mr.size.height * mr.size.width;26 float r = (float) mr.size.width / (float) mr.size.height;27 if (r < 1) r = (float) mr.size.height / (float) mr.size.width;28 }29 30 ++itc;31 }32 33 for (size_t i = 0; i < first_rects.size(); i++) {34 RotatedRect roi_rect = first_rects[i];35 36 Rect_
safeBoundRect;37 if (!calcSafeRect(roi_rect, src, safeBoundRect)) continue;38 39 outRects.push_back(safeBoundRect);40 }41 return 0;42 }
View Code

 经过上述步骤后,为了进一步提高搜索的准确性,EasyPR里面对第一次搜索出的矩形扩大一定范围后,进行了二次搜素,具体函数为 sobelSecSearchPart() 。sobelSecSearchPart() 函数和 sobelFrtSearch() 大致过程是类似的,此处不再详细叙述,唯一的不同是sobelSecSearchPart() 对车牌上铆钉的去除进行了对应的处理。之后对定位区域进行偏斜扭转 deskew()处理之后,即可得到车牌定位的结果。

 

 

 

 

转载于:https://www.cnblogs.com/freedomker/p/7248393.html

你可能感兴趣的文章
如何处理Win10电脑黑屏后出现代码0xc0000225的错误?
查看>>
局域网内手机访问电脑网站注意几点
查看>>
[Serializable]的应用--注册码的生成,加密和验证
查看>>
Day19内容回顾
查看>>
第七次作业
查看>>
SpringBoot项目打包
查看>>
Linux操作系统 和 Windows操作系统 的区别
查看>>
《QQ欢乐斗地主》山寨版
查看>>
文件流的使用以及序列化和反序列化的方法使用
查看>>
Android-多线程AsyncTask
查看>>
第一个Spring冲刺周期团队进展报告
查看>>
红黑树 c++ 实现
查看>>
Android 获取网络链接类型
查看>>
linux中启动与终止lnmp的脚本
查看>>
gdb中信号的处理[转]
查看>>
LeetCode【709. 转换成小写字母】
查看>>
如何在Access2007中使用日期类型查询数据
查看>>
Jzoj4757 树上摩托
查看>>
CF992E Nastya and King-Shamans(线段树二分+思维)
查看>>
第一个Java Web程序
查看>>