摘要
车牌识别主要包括三大方面:车牌定位、字符分割、字符识别,今天先整理第一部分
主要处理步骤如下,方法不单一,也可以在HSV图做车牌定位,我这里用了灰度图
- 灰度处理
- 二值化
- 边缘检测
- 生态学检测
一、灰度处理
把RGB图处理成灰度图,方便二值化
//灰度处理
Mat MainWindow::GRAY(Mat img)
{
Mat img_gray;
cvtColor(img, img_gray, COLOR_BGR2GRAY);//颜色空间转换
return img_gray;
}
二、二值化处理
这里主要利用了opencv的threshold()
函数,255是最大阈值,120是当前阈值,根据实际情况更改
//二值化处理
Mat MainWindow::Two_Value(Mat img)
{
Mat two_value_img;
threshold(img, two_value_img, 150, 255, THRESH_BINARY);
return two_value_img;
}
这个奥迪二值化完了好酷,忍不住贴出来
或者可以用adaptiveThreshold
函数,自适应二值化,可以更改底色,需要添加#include <opencv2/imgproc.hpp>
//二值化处理
Mat MainWindow::Two_Value(Mat img)
{
Mat two_value_img;
adaptiveThreshold(img, two_value_img,255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, 9);
/** @brief 自适应二值化
*@param _src 要二值化的灰度图
*@param _dst 二值化后的图
*@param maxValue 二值化后要设置的那个值
*@param method 块计算的方法(ADAPTIVE_THRESH_MEAN_C 平均值,ADAPTIVE_THRESH_GAUSSIAN_C 高斯分布加权和)
*@param type 二值化类型(CV_THRESH_BINARY 大于为最大值,CV_THRESH_BINARY_INV 小于为最大值)
*@param blockSize 块大小(奇数,大于1)
*@param delta 差值(正值底色为白色)
*/
return two_value_img;
}
三、边缘检测(膨胀腐蚀)
提取出图像中的轮廓,这里直接用的canny算子,也可以单独膨胀腐蚀处理,程序在下面
//边缘检测
Mat MainWindow::EDGE(Mat img)
{
Mat edge_img;
Canny(img,edge_img,120,100,3);
// edge_img = Dilate(img);
// edge_img = Erode(edge_img);
// edge_img = Dilate(edge_img);
return edge_img;
}
//膨胀
Mat MainWindow::Dilate(Mat img)
{
Mat edge_img;
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3), Point(1, 1));
dilate(img, edge_img, element);
return edge_img;
}
//腐蚀
Mat MainWindow::Erode(Mat img)
{
Mat edge_img;
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3), Point(1, 1));
erode(img, edge_img, element);
return edge_img;
}
换张图试一下,二值化的程度不太一样,大众轮廓效果有点差,下面我还是开奥迪吧!
四、生态学检测
1、车牌比例
(1)去Bing图片找到中国车牌的标准,尺寸为440mm*140mm,比例大概是3.14,程序可以放宽这个比例,比如2.5到4来寻找符合要求的轮廓
(2)但是感觉上面奥迪那个车标外边框看起来也是这个比例,有可能成为干扰项
2.定位车牌
(1)核心程序是使用findContours函数检测车牌的轮廓
函数定义如下→来剽窃一下函数用法
findContours( InputOutputArray image, OutputArrayOfArrays contours,
OutputArray hierarchy, int mode,
int method, Point offset=Point());
- 先建立一个单通道幕布来显示轮廓 ,因为画到原图上是看不出来的,下面是按照大小创建的->Mat8种创建方式
int with = ui->target_img_label->width();//设置宽度
int height = ui->target_img_label->height();//设置高度
Mat target_img = Mat::ones(Size(height,with),CV_8UC1);
像这样
- 将轮廓从canny处理过的图中用findContours提取出来
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
float temp = 0;
findContours(edge_img,contours,hierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_NONE,Point());
- 把轮廓画到幕布上
//生态学检测
Mat MainWindow::MORG(Mat img)
{
for(int i=0;i<contours.size();i++)
{
//计算每个轮廓的面积
temp = fabs(contourArea(contours[i]));
if(temp>1000)
{
//绘制出contours向量内第i个轮廓
drawContours(target_img,contours,i,Scalar(255),1,8,hierarchy);
cout<<"i="<<i<<" Contour_Area="<<temp<<endl;
}
}
return target_img;
}
有两点跟我想的不一样:我把大于1000的轮廓画出来了,幸运的发现就是车牌;虽然提取出来了,但是是个斜的?
感觉上是因为幕布不够大,像素放不下,错位了,那么改大一点试试
Mat target_img = Mat::ones(Size(500,400),CV_8UC1);
果然,但是效果真辣鸡
实际上应该按照比例找轮廓的,就不演示了,下班下班