标题: 基于opencv的车牌识别 [打印本页]

作者: shi'biao1234    时间: 2018-4-16 09:41
标题: 基于opencv的车牌识别
车牌识别流程:


高斯模糊:
车牌识别中利用高斯模糊将图片平滑化,去除干扰的噪声对后续图像处理的影响。
高斯模糊(GaussianBlur()),也叫高斯平滑。
周边像素的平均值,所谓"模糊",可以理解成每一个像素都取周边像素的平均值。
    上图中,2是中间点,周边点都是1。"中间点"取"周围点"的平均值,就会变成1。在数值上,这是一种"平滑化"。在图形上,就相当于产生"模糊"效果,"中间点"失去细节(上图右)。显然,计算平均值时,取值范围越大,"模糊效果"越强烈。

左图分别是原图、模糊半径3像素、模糊半径10像素的效果。模糊半径越大,图像就越模糊。从数值角度看,就是数值越平滑。
接下来的问题就是,既然每个点都要取周边像素的平均值,那么应该如何分配权重呢?
如果使用简单平均,显然不是很合理,因为图像都是连续的,越靠近的点关系越密切,越远离的点关系越疏远。因此,加权平均更合理,距离越近的点权重越大,距离越远的点权重越小。

OpenCV中函数
void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT)
参数详解:
src:输入图片,可以使是任意通道数,该函数对通道是独立处理的,但是深度只能是CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
dst:输出图片,和输入图片相同大小和深度。
ksize:高斯内核大小。ksize.width和ksize.height允许不相同但他们必须是正奇数。或者等于0,由参数sigma的乘机决定。
sigmaX:高斯内核在X方向的标准方差。
sigmaY:高斯内核在Y方向的标准方差。如果sigmaY为0,他将和sigmaX的值相同,如果他们都为0,那么他们由ksize.width和ksize.height计算得出。
borderType:用于判断图像边界的模式。
1 Mat Gaussian(Mat &img) {2     Mat out;3     GaussianBlur(img, out, Size(3, 3),4         0, 0, BORDER_DEFAULT);5     return out;6 7 }
View Code
原图:(来自百度)
  

灰度化:
在车牌识别中我们需要将图像转化为灰度图像,这样有利于后续步骤的开展,如Soble算子只能作用于灰度图像。
灰度化,在RGB模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。
Opencv中函数
void cvtColor(InputArray src,  OutputArray dst,  int code,  int dstCn=0 )
参数详解:
src输入图像:8位无符号的16位无符号(cv_16uc…)或单精度浮点。
dst的大小和深度src.
code输出图像颜色空间转换的代码。
dstCn目标图像中的信道数;如果参数为0,则从SRC和代码自动导出信道的数目。
1 Mat Grayscale(Mat &img) {2     Mat out;3     cvtColor(img, out, CV_RGB2GRAY);4 5     return out;6 }
View Code


Sobel算子(X方向):
车牌定位的核心算法,水平方向上的边缘检测,检测出车牌区域。
主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测。在技术上,它是一个离散的一阶差分算子,用来计算图像亮度函数的一阶梯度之近似值。在图像的任何一点使用此算子,将会产生该点对应的梯度矢量或是其法矢量。
该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像,其公式如下:


图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小。


可用以下公式计算梯度方向。


在以上例子中,如果以上的角度Θ等于零,即代表图像该处拥有纵向边缘,左方较右方暗。

OpenCV中函数:
void Sobel(InputArray src, OutputArray dst, int ddepth, int xorder, int yorder, int ksize=3, double scale=1, double delta=0, int borderType=BORDER_DEFAULT )
参数:
src源图像。
dst:相同大小和相同数量的通道的目标图像。
ddepth:目标图像的深度。
xorder:阶导数的X.
yorder:阶导数的Y.
ksize:扩展Sobel算子–大小。它必须是1, 3, 5,或者7。
scale计算衍生值的可选刻度因子。默认情况下,不应用缩放。看到getderivkernels()详情。
delta :可选的delta值,在将它们存储在DST之前添加到结果中。
bordertype:像素外推方法。
convertScaleAbs()——先缩放元素再取绝对值,最后转换格式为8bit型。
1 Mat Sobel(Mat &img) { 2     Mat out; 3     Mat grad_x, grad_y; 4     Mat abs_grad_x, abs_grad_y; 5 6     //X方向 7     //Sobel(img, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT); 8     //convertScaleAbs(grad_x, abs_grad_x); 9     Sobel(img, img, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);10     convertScaleAbs(img, out);11 12     //Y方向13     //Sobel(img, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);14     //convertScaleAbs(grad_y, abs_grad_y);15     //convertScaleAbs(img, out);16 17     //合并18     //addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, out);19 20     return out;21 }
View Code


二值化:
进一步对图像进行处理,强化目标区域,弱化背景。
图像的二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。
OpenCV中函数
double threshold(InputArray src, OutputArray dst, double thresh, double maxVal, int thresholdType)
参数:
src源阵列(单通道,32位浮点8位)。
dst:相同大小和类型的目标数组。
thresh门限阈值。
Maxval:最大值使用的thresh_binary和thresh_binary_inv阈值类型。
thresholdtype:阈值型,如下。
THRESH_BINARY  当前点值大于阈值时,取Maxval,也就是第四个参数,下面再不说明,否则设置为0
THRESH_BINARY_INV 当前点值大于阈值时,设置为0,否则设置为Maxval
THRESH_TRUNC 当前点值大于阈值时,设置为阈值,否则不改变
THRESH_TOZERO 当前点值大于阈值时,不改变,否则设置为0
THRESH_TOZERO_INV 当前点值大于阈值时,设置为0,否则不改变
1 Mat TwoValued(Mat &img) {2     Mat out;3     threshold(img, out, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);4     //threshold(img, out, 100, 255, CV_THRESH_BINARY);5 6     return out;7 }
View Code


闭操作:
闭操作可以将目标区域连成一个整体,便于后续轮廓的提取。
闭操作可使轮廓线更光滑,但与开操作相反的是,闭操作通常消弥狭窄的间断和长细的鸿沟,消除小的空洞,并填补轮廓线中的断裂。
使用结构元素B对集合A进行闭操作,定义为


这个公式表明,使用结构元素B对集合A的闭操作就是用B对A进行膨胀,然后用B对结果进行腐蚀

OpenCV中函数
void morphologyEx(InputArray src, OutputArray dst, int op, InputArray element, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() )
参数:
src:源图像。
dst:相同大小和类型的目标图像。
element内核类型    用getStructuringElement函数得到。
OP:
可以是以下形式之一的形态学操作的类型:
morph_open -开启操作
morph_close -闭合操作
morph_gradient -形态学梯度
morph_tophat“顶帽”
morph_blackhat -“黑帽”
iterations侵蚀和膨胀的次数被应用。
bordertype–像素外推方法。
bordervalue–边界值在一个恒定的边界情况。默认值有特殊含义。
关注前4个参数即可,后面用默认参数。

1 Mat Close(Mat &img) {2     Mat out;3     //Mat element(5, 5, CV_8U, cv::Scalar(1));4     Mat element = getStructuringElement(MORPH_RECT, Size(17, 5));5     morphologyEx(img, out, cv::MORPH_CLOSE, element);6 7     return out;8 }
View Code


取轮廓:
将前面处理的车牌目标区域提取出来。
相关函数:
查找轮廓:
void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
image输入的 8-比特、单通道图像. 非零元素被当成 1, 0 象素值保留为 0 - 从而图像被看成二值的。为了从灰度图像中得到这样的二值图像,可以使用 cvThreshold, cvAdaptiveThreshold 或 cvCanny. 本函数改变输入图像内容。
storage :得到的轮廓的存储容器
first_contour :输出参数:包含第一个输出轮廓的指针
header_size :如果 method=CV_CHAIN_CODE,则序列头的大小 >=sizeof(CvChain),否则 >=sizeof(CvContour) .
mode
提取模式.
CV_RETR_EXTERNAL - 只提取最外层的轮廓
CV_RETR_LIST - 提取所有轮廓,并且放置在 list 中
CV_RETR_CCOMP - 提取所有轮廓,并且将其组织为两层的 hierarchy: 顶层为连通域的外围边界,次层为洞的内层边界。
CV_RETR_TREE - 提取所有轮廓,并且重构嵌套轮廓的全部 hierarchy
method :
逼近方法 (对所有节点, 不包括使用内部逼近的 CV_RETR_RUNS).
CV_CHAIN_CODE - Freeman 链码的输出轮廓. 其它方法输出多边形(定点序列).
CV_CHAIN_APPROX_NONE - 将所有点由链码形式翻译(转化)为点序列形式
CV_CHAIN_APPROX_SIMPLE - 压缩水平、垂直和对角分割,即函数只保留末端的象素点;
CV_CHAIN_APPROX_TC89_L1,
CV_CHAIN_APPROX_TC89_KCOS - 应用 Teh-Chin 链逼近算法. CV_LINK_RUNS - 通过连接为 1 的水平碎片使用完全不同的轮廓提取算法。仅有 CV_RETR_LIST 提取模式可以在本方法中应用.
offset :
每一个轮廓点的偏移量. 当轮廓是从图像 ROI 中提取出来的时候,使用偏移量有用,因为可以从整个图像上下文来对轮廓做分析.
函数 cvFindContours 从二值图像中提取轮廓,并且返回提取轮廓的数目。指针 first_contour 的内容由函数填写。它包含第一个最外层轮廓的指针,如果指针为 NULL,则没有检测到轮廓(比如图像是全黑的)。其它轮廓可以从 first_contour 利用 h_next 和 v_next 链接访问到。 在 cvDrawContours 的样例显示如何使用轮廓来进行连通域的检测。轮廓也可以用来做形状分析和对象识别 - 见CVPR2001 教程中的 squares 样例。该教程可以在 SourceForge 网站上找到。

绘制轮廓:
void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, intthickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )


相关参数参考——http://www.opencv.org.cn/opencvd ... urs#cv.DrawContours

漫水填充算法:
int floodFill(InputOutputArray image, Point seed, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), ScalarupDiff=Scalar(), int flags=4 )


相关参数参考——http://www.opencv.org.cn/opencvd ... odfill#cv.FloodFill

aec379310a55b31961a2c69743a98226cefc17fc.jpg (6.65 KB, 下载次数: 92)

aec379310a55b31961a2c69743a98226cefc17fc.jpg





欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1