一、简介

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   else
10     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<Rect_<float>> &outRects) {
 3   Mat src_threshold;
 4
 5   sobelOper(src, src_threshold, m_GaussianBlurSize, m_MorphSizeWidth,
 6             m_MorphSizeHeight);
 7
 8   vector<vector<Point>> contours;
 9   findContours(src_threshold,
10                contours,               // a vector of contours
11                CV_RETR_EXTERNAL,
12                CV_CHAIN_APPROX_NONE);  // all pixels of each contours
13
14   vector<vector<Point>>::iterator itc = contours.begin();
15
16   vector<RotatedRect> 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_<float> 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

EasyPR源码剖析(4):车牌定位之Sobel算子定位相关推荐

  1. easyPR源码解析之chars_segment.h

    chars_segment.h用于从已经通过SVM判别得到的车牌区域中将车牌的字符分割开,用于下一步的ANN字符识别. namespace easypr { class CCharsSegment { ...

  2. Mongoose源码剖析:外篇之web服务器

    引言 在深入Mongoose源码剖析之前,我们应该清楚web服务器是什么?它提供什么服务?怎样提供服务?使用什么协议?客户端如何唯一标识web服务器的资源?下面我们抛开Mongoose,来介绍一个we ...

  3. Spring源码剖析——Bean的配置与启动

    IOC介绍   相信大多数人在学习Spring时 IOC 和 Bean 算得上是最常听到的两个名词,IOC在学习Spring当中出现频率如此之高必然有其原因.如果我们做一个比喻的话,把Bean说成Sp ...

  4. 【Java集合源码剖析】TreeMap源码剖析

    2019独角兽企业重金招聘Python工程师标准>>> 前言 本文不打算延续前几篇的风格(对所有的源码加入注释),因为要理解透TreeMap的所有源码,对博主来说,确实需要耗费大量的 ...

  5. mysql启用组提交变量_MySQL的COMMIT_ORDER模式下组提交分组实现与BUG案例源码剖析...

    背景 自MySQL 5.7以来,组提交大面积应用,已经不断地得到优化.但网上有关组提交的实现机制,却还不够详细.故障多的时候,往往会发生一些模棱两可的揣测和猜疑.因此,笔者有了从自己的角度,去分析组提 ...

  6. sarscape 将dem文件转化成stl_STL源码剖析 阅读笔记(一)介绍

    一.学习动机 对C++的理解:最近因为工作原因需要重新对C++进行学习,而上一次系统.全局的学习C++已经是在本科时期了,然后是读研期间的第一年学过一点皮毛,后来对C++的学习都是边用边学.纵然这样已 ...

  7. Spring循环依赖源码剖析

    Spring循环依赖源码剖析 一.场景介绍 二.整理执行流程总结 三.源码分析 编写测试类 /*** 测试循环依赖*/@Testpublic void testCyclicDependence(){A ...

  8. Python envoy 模块源码剖析

    Kenneth Reitz 是公认的这个世界上 Python 代码写得最好的人之一.抱着学习的心态,我阅读了 Reitz 写的 envoy 模块的源码,将笔记记录如下. 介绍 和 requests 模 ...

  9. 转 Spring源码剖析——核心IOC容器原理

    Spring源码剖析--核心IOC容器原理 2016年08月05日 15:06:16 阅读数:8312 标签: spring 源码 ioc 编程 bean 更多 个人分类: Java https:// ...

最新文章

  1. 给虚拟机中的linux系统增加一个硬盘
  2. 前端图片压缩上传(纯js的质量压缩,非长宽压缩)
  3. Java 面向对象:static的理解
  4. 【redis】分布式锁实现,与分布式定时任务
  5. linux如何打开dhcp服务,怎么开启DHCP服务器啊
  6. vue3.0实现地图功能
  7. Git教程_1 简介
  8. 华为手机怎么移除云盘内容_华为手机网盘怎么样删除
  9. 计算机二级知识普及挑战赛答案,全国计算机二级试题库
  10. 计算机平均分函数a,平均值计算函数Average、Averagea、AverageIfs、Trimmean
  11. 上海电力大学计算机专业全国排名,上海电力大学怎么样 最好的专业有哪些
  12. linux查询网络连接状态,Linux 查看网络连接状态
  13. 计算机视频接口有,HDMI,DVI为什么我们的计算机有这么多视频接口?
  14. 最近很火的ChatGPT和GPT4
  15. matlab fir1 filter,Matlab滤波器设计
  16. 将一串数字拆分成单个数字
  17. c语言简单的字符串处理
  18. matlab汽车驱动力与行驶阻力,汽车理论课程设计:基于Matlab的汽车动力性的仿真...
  19. Chrome浏览器发送两次请求
  20. meedu对接易支付 个人免签支付

热门文章

  1. 文章中运用到的数学公式
  2. yolov4实现口罩佩戴检测,在验证集上做到了0.954的mAP
  3. 中文命名实体识别,HMM,CRF,BiLSTM,BiLSTM+CRF的具体实现
  4. CNN卷积特征的可视化
  5. GBDT+LR算法解析及Python实现
  6. scratch数学编程100例_《scratch编程+数学》课程:编程实现数字黑洞冰雹猜想
  7. k8s部署jar包_K8S部署SpringBoot应用_都超的博客-CSDN博客_k8s springboot
  8. Linux centos hook,centos7 U盘安装卡在 starting dracut initqueue hook
  9. 双显卡单独分辨率_甜点光追显卡—带你实现GAMING梦!!!
  10. java路径在那_Java 路径