一、简介

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=,
double scale=,
double delta=,
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, , , , 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, , , , scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_y, abs_grad_y );
/// Total Gradient (approximate)
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, , grad );

二、Sobel算子定位

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

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

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

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

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

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

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

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

具体实现代码如下所示:

 int CPlateLocate::sobelOper(const Mat &in, Mat &out, int blurSize, int morphW,int morphH) {
Mat mat_blur;
mat_blur = in.clone();
GaussianBlur(in, mat_blur, Size(blurSize, blurSize), , , BORDER_DEFAULT); Mat mat_gray;
if (mat_blur.channels() == )
cvtColor(mat_blur, mat_gray, CV_RGB2GRAY);
else
mat_gray = mat_blur; int scale = SOBEL_SCALE;
int delta = SOBEL_DELTA;
int ddepth = SOBEL_DDEPTH; Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y; Sobel(mat_gray, grad_x, ddepth, , , , scale, delta, BORDER_DEFAULT);
convertScaleAbs(grad_x, abs_grad_x); Mat grad;
addWeighted(abs_grad_x, SOBEL_X_WEIGHT, , , , grad); Mat mat_threshold;
double otsu_thresh_val =
threshold(grad, mat_threshold, , , CV_THRESH_OTSU + CV_THRESH_BINARY); Mat element = getStructuringElement(MORPH_RECT, Size(morphW, morphH));
morphologyEx(mat_threshold, mat_threshold, MORPH_CLOSE, element); out = mat_threshold; return ;
}

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

 int CPlateLocate::sobelFrtSearch(const Mat &src,
vector<Rect_<float>> &outRects) {
Mat src_threshold; sobelOper(src, src_threshold, m_GaussianBlurSize, m_MorphSizeWidth,
m_MorphSizeHeight); vector<vector<Point>> contours;
findContours(src_threshold,
contours, // a vector of contours
CV_RETR_EXTERNAL,
CV_CHAIN_APPROX_NONE); // all pixels of each contours vector<vector<Point>>::iterator itc = contours.begin(); vector<RotatedRect> first_rects; while (itc != contours.end()) {
RotatedRect mr = minAreaRect(Mat(*itc)); if (verifySizes(mr)) {
first_rects.push_back(mr); float area = mr.size.height * mr.size.width;
float r = (float) mr.size.width / (float) mr.size.height;
if (r < ) r = (float) mr.size.height / (float) mr.size.width;
} ++itc;
} for (size_t i = ; i < first_rects.size(); i++) {
RotatedRect roi_rect = first_rects[i]; Rect_<float> safeBoundRect;
if (!calcSafeRect(roi_rect, src, safeBoundRect)) continue; outRects.push_back(safeBoundRect);
}
return ;
}

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

EasyPR源码剖析(4):车牌定位之Sobel算子定位的更多相关文章

  1. EasyPR源码剖析(5):车牌定位之偏斜扭转

    一.简介 通过颜色定位和Sobel算子定位可以计算出一个个的矩形区域,这些区域都是潜在车牌区域,但是在进行SVM判别是否是车牌之前,还需要进行一定的处理.主要是考虑到以下几个问题: 1.定位区域存在一 ...

  2. EasyPR源码剖析(2):车牌定位

    上一篇主要介绍了车牌识别的整体框架和流程,车牌识别主要划分为了两个过程:即车牌检测和字符识别,而车牌识别的核心环节就是这一节主要介绍的车牌定位,即 Plate Locate.车牌定位主要是将图片中有可 ...

  3. EasyPR源码剖析(1):概述

    EasyPR(Easy to do Plate Recognition)是本人在opencv学习过程中接触的一个开源的中文车牌识别系统,项目Git地址为https://github.com/liuru ...

  4. EasyPR源码剖析(3):车牌定位之颜色定位

    一.简介 对车牌颜色进行识别,可能大部分人首先想到的是RGB模型, 但是此处RGB模型有一定的局限性,譬如蓝色,其值是255,还需要另外两个分量都为0,不然很有可能你得到的值是白色.黄色更麻烦,它是由 ...

  5. EasyPR源码剖析(7):车牌判断之SVM

    前面的文章中我们主要介绍了车牌定位的相关技术,但是定位出来的相关区域可能并非是真实的车牌区域,EasyPR通过SVM支持向量机,一种机器学习算法来判定截取的图块是否是真的“车牌”,本节主要对相关的技术 ...

  6. EasyPR源码剖析(6):车牌判断之LBP特征

    一.LBP特征 LBP指局部二值模式,英文全称:Local Binary Pattern,是一种用来描述图像局部特征的算子,LBP特征具有灰度不变性和旋转不变性等显著优点. 原始的LBP算子定义在像素 ...

  7. EasyPR源码剖析(8):字符分割

    通过前面的学习,我们已经可以从图像中定位出车牌区域,并且通过SVM模型删除“虚假”车牌,下面我们需要对车牌检测步骤中获取到的车牌图像,进行光学字符识别(OCR),在进行光学字符识别之前,需要对车牌图块 ...

  8. EasyPR源码剖析(9):字符识别

    在上一篇文章的介绍中,我们已经通过相应的字符分割方法,将车牌区域进行分割,得到7个分割字符图块,接下来要做的就是将字符图块放入训练好的神经网络模型,通过模型来预测每个图块所表示的具体字符.神经网络的介 ...

  9. HashMap源码剖析

    HashMap源码剖析 无论是在平时的练习还是项目当中,HashMap用的是非常的广,真可谓无处不在.平时用的时候只知道HashMap是用来存储键值对的,却不知道它的底层是如何实现的. 一.HashM ...

随机推荐

  1. 【Python学习】Python3 环境搭建

    参考地址:http://www.runoob.com/python3/python3-install.html Python3 环境搭建 本章节我们将向大家介绍如何在本地搭建 Python3 开发环境 ...

  2. jtable时间编辑器

    最近在做一个项目,很烦,用的swing,但是不管怎样也还是啃下来了,但是碰到一个问题,要在jtable里编辑时用一个时间选择器,因为走了许多弯路,找到挺多jar包,耗时较久,所以记录一下,便于以后查阅 ...

  3. 使用 nodeJs 开发微信公众号(设置自动回复消息)

    微信向第三方服务器发送请求时会降 signature .timestamp. nonce . openid(用户标识),发送内容会以 xml 的形式附加在请求中 回复消息前提我们得拿到用户id , 用 ...

  4. nodeJs 代码热更新

    在开发node过程中,每次修改代码都需要重新启动服务,是一件很抓狂的事情 使用nodemon热加载可以帮我们很好的解决这一问题 1. 安装 npm install nodemon -g 2. 修改np ...

  5. python视频学习笔记3(循环)

    一.程序的三大流程 二.while 初始条件设置 —— 通常是重复执行的 计数器 while 条件(判断 计数器 是否达到 目标次数): 条件满足时,做的事情1 条件满足时,做的事情2 条件满足时,做 ...

  6. [Docker] 容器持久化数据的首选机制 Volume

    Volume 是 docker 容器生成持久化数据的首选机制.bind mounts 依赖主机机器的目录机构,volume 完全由 docker 管理.volume 较 bind mounts 有几个 ...

  7. COM接口调用,CreateDispatch失败的问题

    有一个自动化处理Office文档的程序,原本运行的很好,基于效率和UI效果的问题,改成了多线程处理,编译没问题,一运行就报错找不到Office软件. 程序中产生错误的地方就是创建COM对象失败,以前好 ...

  8. spring @Autowired与@Resource的区别

    1.@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上. 2.@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必 ...

  9. WPF常用布局介绍

    概述:本文简要介绍了WPF中布局常用控件及布局相关的属性 1 Canvas Canvas是一个类似于坐标系的面板,所有的元素通过设置坐标来决定其在坐标系中的位置..具体表现为使用Left.Top.Ri ...

  10. PhoenixFD插件流体模拟——UI布局【Interaction】详解

    流体交互 本文主要讲解Interaction折叠栏中的内容.原文地址:https://docs.chaosgroup.com/display/PHX3MAX/Liquid+Interaction 主要 ...