图像识别入门6 车牌定位方法

Posted 神马学习

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图像识别入门6 车牌定位方法相关的知识,希望对你有一定的参考价值。

      利用车牌的颜色特征,将原图像分别在HSV 颜色空间和 RGB颜色空间下处理得到两幅二值图像;根据这两幅二值图像的纹理特点,在HSV 颜色空间下得到的二值图像定位出车牌的上下边界,再按照定位出的上下边界坐标从RGB颜色空间下的二值图像上水平切割出车牌区域;根据车牌的几何特征,从切割出的水平区域中得到精确的车牌区域。

预处理

设定目标矩形:int areas;

//该函数用来验证是否是我们想要的区域,车牌定位原理其实就是在图片上寻找矩形,我们可以用长宽比例以及面积来验证是否是我们想要的矩形,宽高比为520/110=4.7272 (车牌的长除以宽),区域面积最小为15个像素,最大为125个像素。

灰度化:

       因为人眼对不同颜色敏感度不一样,因此权值法中的权值可以得到最合适的灰度图像。 在本文中用的是Opencv 提供的库函数,该函数采用的方法也是加权值法.

二值化: 

      一般我们采集到的图像都是 RGB模型的,为了使二值化后的图像干扰区域尽可能少,把 RGB模型转换到HSV模型。HSV模型中,H 是色彩的基本属性,就是平常所说的颜色名称;S是指色彩的纯 度,值越高色彩越纯,值越低则逐渐变灰;V是指亮度。

    二值化中阈值的选定就按不同车牌颜色对应的 h、s、v值的范围,如 围:94~115,S值 围:90~255,V 围:36~255。使 Opencv  cvinranges函数进行二值化.

数学形态学除噪:

blur(img_gray, img_blur, Size(5, 5));//用来降噪;

定位:

      根据车牌图像二值化后字符之间连续跳变的规律性,来按行进行判定,把符合条件的相邻行连在一起,并且这样的连续行大于某个阈值时,就把这样的区域作为车牌备选区域,记录下这个区域的开始行坐标和结束行坐标,一幅图像自上而下扫描一遍后,就能得到车牌备选区域集合。

程序:

#include<opencv2\opencv.hpp>

#include<iostream>

using namespace cv;

using namespace std;

int areas;

//该函数用来验证是否是我们想要的区域,车牌定位原理其实就是在图片上寻找矩形,我们可以用长宽比例以及面积来验证是否是我们想要的矩形,宽高比为520/110=4.7272 (车牌的长除以宽),区域面积最小为15个像素,最大为125个像素

bool VerifySize(RotatedRect candidate) {

float error = 0.4; //40%的误差范围

float aspect = 4.7272;//宽高比例

int min = 15 * aspect * 15; //最小像素为15

int max = 125 * aspect * 125;//最大像素为125

float rmin = aspect - aspect * error;//最小误差

float rmax = aspect + aspect * error;//最大误差

int area = candidate.size.height*candidate.size.width;//求面积

float r = (float)candidate.size.width / (float)candidate.size.height;//长宽比

if (r < 1)

r = 1 / r;

if (area<min || area>max || r<rmin || r>rmax)

return false;

else

return true;

}

int main(int argc, char** argv) {


Mat src;

src = imread("D:\\abc\\222.jpg");//读取含车牌的图片

if (!src.data)

{

cout << "Could not open Car.jph.." << endl;

return -1;

}

Mat img_gray;

cvtColor(src, img_gray, CV_BGR2GRAY);//灰度转换

Mat img_blur;

blur(img_gray, img_blur, Size(5, 5));//用来降噪

Mat img_sobel;

Sobel(img_gray, img_sobel, CV_8U, 1, 0, 3);//Sobel滤波,对x进行求导,就是强调y方向,对y进行求导,就是强调x方向,在此我们对x求导,查找图片中的竖直边

Mat img_threshold;

threshold(img_sobel, img_threshold, 0, 255, THRESH_BINARY | THRESH_OTSU);

Mat element = getStructuringElement(MORPH_RECT, Size(21, 5));//这个Size很重要!!不同的图片适应不同的Size,待会在下面放图,大家就知道区别了

morphologyEx(img_threshold, img_threshold, MORPH_CLOSE, element);//闭操作,就是先膨胀后腐蚀,目的就是将图片联通起来,取决于element的Size。

/*接下来就是提取轮廓*/

vector<vector<Point>>contours;

findContours(img_threshold, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

Mat result = Mat::zeros(src.size(), CV_8U);

drawContours(result, contours, -1, Scalar(255));

vector<RotatedRect> rects; //用来存放旋转矩形的容器

//Mat result1 = Mat::zeros(src.size(), CV_8U);

Mat result1;

src.copyTo(result1);

for (size_t i = 0; i < contours.size(); i++)

{

Point2f vertices[4];//用来存放旋转矩形的四个点

RotatedRect mr = minAreaRect(Mat(contours[i]));

//minAreaRect 寻找最小的矩形

if (VerifySize(mr))//筛选是否是我们需要的区域,如果验证成功,就放到rects里,

{

//if (mr.angle > -30) {

mr.points(vertices);

for (size_t j = 0; j < 4; j++)

{

line(result1, vertices[j], vertices[(j + 1) % 4], Scalar(0, 0, 255), 2, 8);

cout << "矩形坐标" << j << "为" << vertices[j] << endl;

}

cout << "height:" << mr.size.height << endl << "weight:" << mr.size.width << endl;

rects.push_back(mr);

cout << "矩形角度:" << mr.angle << endl;

//  }

}

}

vector<Mat>output;//用于存放识别到的图像

for (size_t i = 0; i < rects.size(); i++)

{

Mat dst_warp;

Mat dst_warp_rotate;

Mat rotMat(2, 3, CV_32FC1);

dst_warp = Mat::zeros(src.size(), src.type());

float r = (float)rects[i].size.width / (float)rects[i].size.height;

float  angle = rects[i].angle;

if (r < 1)

angle = angle + 90;

rotMat = getRotationMatrix2D(rects[i].center, angle, 1);//其中的angle参数,正值表示逆时针旋转,关于旋转矩形的角度,以为哪个是长哪个是宽,在下面会说到

warpAffine(src, dst_warp_rotate, rotMat, dst_warp.size());//将矩形修正回来

Size rect_size = rects[i].size;

if (r < 1)

swap(rect_size.width, rect_size.height);

Mat dst(rects[i].size, CV_8U);

getRectSubPix(dst_warp_rotate, rect_size, rects[i].center, dst);//裁剪矩形

/*以下代码是将裁减到的矩形设置为相同大小,并且提高对比度*/

Mat resultResized;

resultResized.create(33, 144, CV_8UC3);

resize(dst, resultResized, resultResized.size(), 0, 0, INTER_CUBIC);

Mat grayResult;

cvtColor(resultResized, grayResult, CV_BGR2GRAY);

blur(grayResult, grayResult, Size(3, 3));

equalizeHist(grayResult, grayResult); //均值化提高对比度

output.push_back(grayResult); //存放图片

}

char name[20] = "";

for (size_t i = 0; i < output.size(); i++)

{

sprintf_s(name, "识别到的第%d个车牌", i + 1);

imshow(name, output[i]);

}

waitKey(0);

return 0;

}

原图像:

运行结果:


以上是关于图像识别入门6 车牌定位方法的主要内容,如果未能解决你的问题,请参考以下文章

车牌识别-车牌定位

车牌识别基于matlab GUI模板匹配车牌识别含Matlab源码 958期

移动端车牌识别sdk-手机拍照识别车牌技术

移动端车牌识别sdk-手机拍照识别车牌技术

手持端移动端车牌识别技术

车牌识别模板匹配新能源轿车货车车牌识别含GUI Matlab源码 2169期