博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
在ARM-Linux下实现车牌识别(一)------车牌提取
阅读量:4298 次
发布时间:2019-05-27

本文共 5800 字,大约阅读时间需要 19 分钟。

最近在弄车牌识别这个项目,对于机器视觉有些了解的人都知道,这个东西算是比较成熟了,在书里也有代码。

网上能找到的资料也比较多,所及借着这个机会在ARM开发板上实现以下车牌识别。
反正对于神经网络这些什么的我是不知道了,所以代码也是网上借鉴了的,我稍微整理注释了下。
先放下移植opencv的步骤:移植opencv到嵌入式arm详细过程
第一步做的就是车牌提取:

代码如下:

#include 
#include
#include
#include
#include
#include
#include
#include
#include
using namespace cv; using namespace std;//车牌宽高比为520/110=4.727272左右,误差不超过40%//车牌高度范围在15~125之间,视摄像头距离而定(图像大小)bool verifySizes_closeImg(const RotatedRect & candidate){ float error = 0.4;//误差40% const float aspect = 4.7272;//44/14; //长宽比 int min = 15*aspect*15;//20*aspect*20; //面积下限,最小区域 int max = 125*aspect*125;//180*aspect*180; //面积上限,最大区域 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;}void RgbConvToGray(const Mat& inputImage,Mat & outpuImage) //g = 0.3R+0.59G+0.11B{ outpuImage = Mat(inputImage.rows ,inputImage.cols ,CV_8UC1); for (int i = 0 ;i
(i); const Vec3b * ptrRgb = inputImage.ptr
(i); for (int j = 0 ;j
&rects_optimal, vector
& output_area ){ float r,angle; for (int i = 0 ;i< rects_optimal.size() ; ++i) { //旋转区域 angle = rects_optimal[i].angle; r = (float)rects_optimal[i].size.width / (float) (float)rects_optimal[i].size.height; if(r<1) angle = 90 + angle;//旋转图像使其得到长大于高度图像。 Mat rotmat = getRotationMatrix2D(rects_optimal[i].center , angle,1);//获得变形矩阵对象 Mat img_rotated; warpAffine(intputImg ,img_rotated,rotmat, intputImg.size(),CV_INTER_CUBIC); imwrite("car_rotated.jpg",img_rotated);//得到旋转图像 //裁剪图像 Size rect_size = rects_optimal[i].size; if(r<1) swap(rect_size.width, rect_size.height); //交换高和宽 Mat img_crop; getRectSubPix(img_rotated ,rect_size,rects_optimal[i].center , img_crop );//图像切割 //用光照直方图调整所有裁剪得到的图像,使具有相同宽度和高度,适用于训练和分类 Mat resultResized; //别人写的: /*resultResized.create(33,144,CV32FC1); resize(img_crop , resultResized,resultResized.size() , 0,0,INTER_CUBIC); resultResized.convertTo(resultResized, CV32FC1); resultResized = resultResized.reshape(1,1);*/ resultResized.create(33,144,CV_8UC3);//CV32FC1???? resize(img_crop , resultResized,resultResized.size() , 0,0,INTER_CUBIC); Mat grayResult; RgbConvToGray(resultResized ,grayResult); //blur(grayResult ,grayResult,Size(3,3)); equalizeHist(grayResult,grayResult); output_area.push_back(grayResult); }}int main(int argc, char* argv[]){ Mat img_input= imread("./car.jpg");//加载图片 if(img_input.empty())//如果读入图像失败 { cout << "Can not load image" << endl; return -1; } Mat hsvImg ; cvtColor(img_input,hsvImg,CV_BGR2HSV);//RGB模型转换成HSV模型 imwrite("car_hsv.jpg",hsvImg);//看下hsv效果 vector
hsvSplit; split(hsvImg,hsvSplit);//将图像的各个通道分离 equalizeHist(hsvSplit[2],hsvSplit[2]);//直方图均衡化,提高图像的质量 merge(hsvSplit,hsvImg);//将分离的多个单通道合成一幅多通道图像 imwrite("car_hsv1.jpg",hsvImg);//看下处理效果 const int min_blue =100;//最小蓝车区域 const int max_blue =240;//最大蓝车区域 int avg_h = (min_blue+max_blue)/2; int channels = hsvImg.channels(); int nRows = hsvImg.rows; //图像数据列需要考虑通道数的影响; int nCols = hsvImg.cols * channels; if (hsvImg.isContinuous())//连续存储的数据,按一行处理 { nCols *= nRows; nRows = 1; } int i, j; unsigned char* p; const float minref_sv = 64; //参考的S V的值 const float max_sv = 255; // S V 的最大值 for (i = 0; i < nRows; ++i)//根据蓝色在HSV在的区域每个通道的取值范围将此作为阈值,提取出图片中蓝色部分作为备选区域 { p = hsvImg.ptr
(i);//有效提高了车牌和车色颜色在不相差较大的情况下的识别率 for (j = 0; j < nCols; j += 3)//致命问题:蓝色的车和蓝色的牌照? { int H = int(p[j]); //0-180 int S = int(p[j + 1]); //0-255 int V = int(p[j + 2]); //0-255 bool colorMatched = false; if (H > min_blue && H < max_blue) { int Hdiff = 0; float Hdiff_p = float(Hdiff) / 40; float min_sv = 0; if (H > avg_h) { Hdiff = H - avg_h; } else { Hdiff = avg_h - H; } min_sv = minref_sv - minref_sv / 2 * (1 - Hdiff_p); if ((S > 70&& S < 255) &&(V > 70 && V < 255)) colorMatched = true; } if (colorMatched == true) { p[j] = 0; p[j + 1] = 0; p[j + 2] = 255; } else { p[j] = 0; p[j + 1] = 0; p[j + 2] = 0; } } } Mat src_grey; Mat img_threshold; vector
hsvSplit_done; split(hsvImg, hsvSplit_done); src_grey = hsvSplit_done[2];//提取黑色分量 imwrite("car_hsvSplit.jpg",src_grey);//查看分离通道出来的车牌 vector
rects; Mat element = getStructuringElement(MORPH_RECT ,Size(17 ,3)); //闭形态学的结构元素 morphologyEx(src_grey ,img_threshold,CV_MOP_CLOSE,element); //闭运算,先膨胀后腐蚀,连通近邻区域(填补白色区域的间隙) morphologyEx(img_threshold,img_threshold,MORPH_OPEN,element);//形态学处理 imwrite("car_morphology.jpg",img_threshold);//查看threshold vector< vector
> contours;//寻找车牌区域的轮廓 findContours(img_threshold ,contours,CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//只检测外轮廓。存储所以轮廓点 //绘制轮廓 /*for(int find=0; find < contours.size(); find++) drawContours(img_threshold, contours, find, Scalar(255), 2); imwrite("car_contours.jpg",img_threshold);//查看轮廓*/ //对候选的轮廓进行进一步筛选 vector< vector
> ::iterator itc = contours.begin(); while( itc != contours.end()) { RotatedRect mr = minAreaRect(Mat( *itc )); //返回每个轮廓的最小有界矩形区域 if(!verifySizes_closeImg(mr)) //判断矩形轮廓是否符合要求 { itc = contours.erase(itc); } else { rects.push_back(mr); ++itc; } } vector
output_area; normal_area(img_input ,rects,output_area); //获得144*33的候选车牌区域output_area imwrite("car_area.jpg",output_area[0]);//得到候选区域,这里可能会获得多个候选区域,最好使用svm训练一下 return 0; }

 

我们看下效果:
原图car.jpg,我在学校随便拍的一张图:

car

看下hsv的效果图car_hsv.jpg:

hsv

接着直方图均衡化后的图car_hsv1.jpg:

hsv1

提取蓝车区域后,分离出来,提取分量 car_hsvSplit.jpg:

split

可以看出,找到了车牌部分。我拍的这图质量还好,当车辆与车牌都是蓝色时就不好弄出这个了

接着看下形态学处理 car_morphology.jpg:

morphology

白色区域都被联通了。

然后看下旋转的图像 car_rotated.jpg:

rotated

最后,剪切出车牌即可 car_area.jpg:

area

这样就提取车了一张车牌。

因为这图比较理想,事实上,可能识别出多个蓝车区域多为车牌,也就是多个候选区域。这里我们图像理想,只识别出一个候选区域,所以我直接把候选区域0,即output_area[0]打印出来就是车牌了,事实上,我们应该加入SVM训练,作为最后判断是否是车牌的依据。

最后说一句,这程序只能识别蓝色的车牌,因为他是直接查找蓝色矩形区域的!

在ARM-Linux下实现车牌识别(二)------车牌识别
 

你可能感兴趣的文章
读书笔记_量化交易如何建立自己的算法交易01
查看>>
设计模式03_工厂
查看>>
设计模式04_抽象工厂
查看>>
设计模式05_单例
查看>>
设计模式06_原型
查看>>
设计模式07_建造者
查看>>
设计模式08_适配器
查看>>
设计模式09_代理模式
查看>>
设计模式10_桥接
查看>>
设计模式11_装饰器
查看>>
设计模式12_外观模式
查看>>
设计模式13_享元模式
查看>>
设计模式14_组合结构
查看>>
设计模式15_模板
查看>>
海龟交易法则01_玩风险的交易者
查看>>
CTA策略02_boll
查看>>
vnpy通过jqdatasdk初始化实时数据及历史数据下载
查看>>
设计模式19_状态
查看>>
设计模式20_观察者
查看>>
vnpy学习10_常见坑
查看>>