c# opencv车牌识别(爆肝手码!基于OpenCV的车牌识别(Sobel、颜色定位),绝对干货)

车牌识别大体上需要经历过Sobel定位、颜色定位、SVM对定位来的候选车牌进行评测,给出评分,最后通过提取HOG特征按照训练模型进入ANN识别。

这一章节介绍 定位相关的逻辑代码,其中定位用到 Sobel定位(边缘检测定位), 颜色定位:对应代码里的CarSobelPlateLocation,CarColorPlateLocation;两者定位后得到一些候选的图片,把这些图片送去SVM进行评测,SVM基于HOG提取边缘信息特征,HOG类同之前处理纹理特征的LBP,项目代码在Clion上开发的。源码地址前往

车牌定位(

https://github.com/yinxiucheng/OpencvCarR【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.ecgnize)。

Sobel定位

CarSobelPlateLocation,通过以下的一些步骤进行降噪:

高斯模糊灰度化边缘化二值化闭操作

高斯模糊

//预处理 :去噪 让车牌区域更加突出 Mat blur; //1、高斯模糊(平滑) (1、为了后续操作 2、降噪 ) GaussianBlur(src, blur, Size(5, 5), 0); //imshow(“高斯模糊”,blur);

灰度化

Mat gray; //2、灰度化 去掉颜色 因为它对于我们这里没用 降噪 cvtColor(blur, gray, COLOR_BGR2GRAY); imshow(“灰度”, gray);

边缘化

Mat sobel_16; //3、【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业. 边缘检测 让车牌更加突出 在调用时需要以16位来保存数据 在后续操作 以及显示的时候需要转回8位 Sobel(gray, sobel_16, CV_16S, 1, 0); //转为8位 Mat sobel; convertScaleAbs(sobel_16, sobel); imshow(“Sobel”, sobel);

二值化

//4. 二值化 黑白 Mat shold; //大律法 最大类间算法 threshold(sobel, shold, 0, 255, THRESH_OTSU + THRESH_BINARY); imshow(“二值”, shold);

闭操作

//5、闭操作 // 将相邻的白色区域扩大 连接成一个整体M【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.atclose; Mat element = getStructuringElement(MORPH_RECT, Size(17, 3)); morphologyEx(shold, close, MORPH_CLOSE, element); imshow(“闭操作”, close);

以上的操作是在处理降噪,第六步初步赛选。

第六步:最大面积、最小面积.宽高逼。

//6、查找轮廓 //获得初步筛选车牌轮廓================================================================ //轮廓检测 vector< vector<Point>>【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业. contours;//查找轮廓 提取最外层的轮廓 将结果变成点序列放入 集合 findContours(close, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE); //遍历 vector<RotatedRect> vec_sobel_roi; for(vector<Point> point:contours){ RotatedRect rotatedRect= minAreaRect(point); //rectangle(src, rotatedRect.boundingRect(), Scalar(255, 0, 255)); //进行初步的筛选 【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.把完全不符合的轮廓给排除掉 ( 比如:1×1,5×1000 ) if (verifySizes(rotatedRect)) { vec_sobel_roi.push_back(rotatedRect); } }

初步赛选:宽高比 float aspec,把不符合的删除掉(1 * 1的, 5* 1000的等候选矩形)

int CarPlateLocation::verifySizes(RotatedRect rotated_rect) { //容错率 float error = 0.75f; //训练时候模型的宽高 136 * 32 //获得宽高比 float aspect = float(136)【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业. /float(32); //最小 最大面积 不符合的丢弃 //给个大概就行 随时调整 //尽量给大一些没关系, 这还是初步筛选。 int min = 20 * aspect * 20; int max = 180 * aspect * 180; //比例浮动 error认为也满足 //最小宽、高比 float rmin = aspect – aspect * error; //最大的宽高比 float rmax = aspect + aspect * error; //矩形的面积 float area = rotated_rect.size.height * rotated_rect.size.width; //矩形的比例 floatr =【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业. (float) rotated_rect.size.width / (float) rotated_rect.size.height; if ((area < min || area > max) || (r < rmin || r > rmax)) return 0; return 1; }

把斜的图片转正:仿射变换

//1、矫正前 2、矫正后 3、矩形的大小 4、矩形中心点坐标 5、角度 void CarPlateLocation::rotation(Mat src, Mat &dst, Size rect_size, Point2f center, double angle) { //获得旋转矩【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业. Mat rot_mat = getRotationMatrix2D(center, angle, 1); //运用仿射变换 Mat mat_rotated; //矫正后 大小会不一样,但是对角线肯定能容纳 int max = sqrt(pow(src.rows, 2) + pow(src.cols, 2)); //仿射变换 warpAffine(src, mat_rotated, rot_mat, Size(max, max), CV_INTER_CUBIC); imshow(“旋转前”, src); imshow(“旋转”, mat_rotated); //截取 尽量把车牌多余的区域截取掉g【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.etRectSubPix(mat_rotated, Size(rect_size.width, rect_size.height), center, dst); imshow(“截取”, dst); mat_rotated.release(); rot_mat.release();

颜色定位

HSV颜色模型

色调(H), 饱和度(S), 明度(V);

BGR 转成 HSV

cvtColor(src,hsv,COLOR_BGR2HSV);

色调H

用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.色为180°,品红为300°;

饱和度S

饱和度S表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。

明度V

明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)

在OpenCV中hsv 数据为8UC则取值分别为 0-180 0-255 0-255 ,即蓝色应该是120

按照上面的表格找到蓝色区域 (1【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.00 ~ 124), 然后将HSV中的H、S转为 0, V变为255。其它区域的HSV赋值为0。

//3通道 int chanles = hsv.channels(); //高 int h = hsv.rows; //宽数据长度 int w = hsv.cols * 3; //判断数据是否为一行存储的 //内存足够的话 mat的数据是一块连续的内存进行存储 if (hsv.isContinuous()) { w *= h; h = 1; } for (size_t i = 0; i < h; ++i) { //第i 行的数据 hsv的数据 uchar = java byte uchar *p = hsv.ptr<uchar>(i); for (size_t j = 0; j < w; j += 3) { int h = in【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.t(p[j]); int s = int(p[j + 1]); int v = int(p[j + 2]); bool blue = false; //蓝色 if (h >= 100 && h <= 124 && s >= 43 && s <= 255 && v >= 46 && v <= 255) { blue = true; } if (blue){ p[j] = 0; p[j + 1]=0; p[j + 2]=255; }else { //hsv 模型 h:0 红色 亮度和饱和度都是0 ,也就变成了黑色 p[j] = 0; p[j + 1] = 0; p[j + 2] = 0; } } }

得到下面的图:

接下来抽取亮度:

//把亮度数据抽出来 //把h、s、v分离出来 vector<Mat> hsv_split; split(hsv, hsv_s【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.plit);

然后跟sobel一样通过二值化、大律法等操作

// 整个图片+经过初步赛选的车牌 + 得到的候选车牌 tortuosity(src, vec_sobel_roi, dst); for (Mat s: dst) { imshow(“候选”, s); waitKey(); }

筛选出来一个集合:

把两个结合结合起来,然后通过SVM进行评测, 因为不像人脸检测是没有现成的模型。

vector< Mat > sobel_plates; //sobel定位 plateLocation->location(src, sobel_plates); //颜色定位 vector< Mat > color_plates;【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业. plateColorLocation->location(src, color_plates);vector<Mat> plates; //把sobel_plates的内容 全部加入plates向量 plates.insert(plates.end(),sobel_plates.begin(), sobel_plates.end()); plates.insert(plates.end(), color_plates.begin(), color_plates.end());

SVM

简单来说,SVM就是用于区分不同的类型(车牌、非车牌)。SVM的训练数据既有特征又有标签,通过训练,【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.让机器可以自己找到特征和标签之间的联系,在面对只有特征没有标签的数据时,可以判断出标签。属于机器学习中的监督学习。线性可分、线性不可分,不可分的时候用核函数来区分:

核函数: 用于将不同类型进行提维

人脸检测用的LBP提取特征,这里采取HOG来提取特征。

SVM load模型, 模型是同样是xml文件

svm = SVM::load(svm_model); CarPlateRecgnize p(“/Users/xiuchengyin/Documents/Tina-NDK/OpencvCarRecgnize/resource/HOG_SVM_DATA2.xml”);

HOG特征

局部归一化的梯度方向直方图,是一种【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.对图像局部重叠区域的密集型描述符, 它通过计算局部区域的梯度方向直方图来构成特征。

参数1(检测窗口)的宽- 参数2(块大小)的宽 结果与参数3(块滑动增量)的余数要为0 高也一样

参数4是胞元大小,参数5是梯度方向

HOGDescriptor hog(Size(128, 64), Size(16, 16), Size(8, 8), Size(8, 8), 3);

初始化HOG变量

//参数1的宽-参数2的宽 结果与参数3的余数为0 高也一样 svmHog = new HOGDescriptor(Size(128,64),Size(16,16),Size(8,8),Size(8,8),3);

检测窗口被分为:(【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.(128-16)/8+1)*((64-16)/8+1)=105个块(Block);

一个Block有4个胞元(Cell);

一个Cell的Hog描述子向量的长度是9;

统计梯度直方图特征,就是将梯度方向(0-360)划分为x个区间,将图像化为16×16的若干个窗口,每个窗口又划分为x个block,每个block再化为4个cell(8×8)。对每一个cell,算出每一像素点的梯度方向,按梯度方向增加对应bin的值,最终综合N个cell的梯度直方图组成特征。

简单来说,车牌的边缘与内部文字组成的一组信息(在边缘和角点的梯度值是很大的,边缘和角点包含了很多物体的形状信息),HOG就是抽取这些信息组成一个直方【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.图。

HOG : 梯度方向弱化光照的影响,适合捕获轮廓。

LBP : 中心像素的LBP值反映了该像素周围区域的纹理信息。

SVM 依据HOG提取的特征将所给的候选图片进行评分,选取最优的:

string CarPlateRecgnize::plateRecgnize(Mat src) { vector< Mat > sobel_plates; //sobel定位 sobelPlateLocation->location(src, sobel_plates); //颜色定位 vector< Mat > color_plates; colorPlateLocation->location(src, color【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业._plates);vector< Mat > plates; //把sobel_plates的内容 全部加入plates向量 plates.insert(plates.end(),sobel_plates.begin(), sobel_plates.end()); plates.insert(plates.end(), color_plates.begin(), color_plates.end()); int index = -1; float minScore = FLT_MAX; //float的最大值 //使用 svm 进行 评测 for (int i = 0;i< plates.size();++i)【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业. { Mat plate = plates[i];//先灰度化,再二值化,灰度化只剩下一个通道 Mat gray; cvtColor(plate, gray,COLOR_BGR2GRAY); //二值化 必须是以单通道进行 Mat shold; threshold(gray, shold, 0, 255, THRESH_OTSU + THRESH_BINARY); //提取特征 Mat features; getHogFeatures(svmHog, shold, features); //features 进行转化,把数据保存成一行Mat samples = feat【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.ures.reshape(1,1); //转化数据存储格式 samples.convertTo(samples, CV_32FC1 ); //原始模式 // svm: 直接告诉你这个数据是属于什么类型. // RAW_OUTPUT:让svm 给出一个评分 // char name[100]; // sprintf(name, “候选车牌%d”, i); // imshow(name, plate); float score = svm->predict(samples, noArray(), StatModel::Flags::RAW_OUTPUT); printf(“评分:%f\n”,score); if(scor【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.e < minScore) { minScore = score; index = i; } gray.release(); shold.release(); features.release(); samples.release(); } Mat dst;if (index >= 0) { dst = plates[index].clone(); } // imshow(“车牌”, dst); // waitKey(); // 释放 for(Mat p : plates) { p.release(); 【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业. }return string(“123”); }

svm评分如下:

/Users/xiuchengyin/Documents/Tina-NDK/OpencvCarRecgnize/cmake-build-debug/OpencvCarRecgnize 评分:-1.224322 评分:1.255759 评分:1.831937 评分:-0.070820 评分:1.525869 评分:1.117042

测试最终取出来的就是我们的车牌选图了。

参考:github.com/liuruoze/Ea…

www.cnblogs.com/subconsciou…

来源:掘金

https://juejin.cn/pos【我.爱.线.报.网.】52xbw .cn 每日持.续更新.可.实操.的副.业.t/6844903714470232078

推荐阅读

给力项目线报网会员可免费下载 加入会员
友情提醒: 请尽量登录购买,防止付款了不发货!
QQ交流群:226333560 站长微信:qgzmt2
温馨提示:本站提供的一切软件、教程和内容信息都来自网络收集整理,仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负,版权争议与本站无关。用户必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。如果您喜欢该程序和内容,请支持正版,购买注册,得到更好的正版服务。我们非常重视版权问题,如有侵权请邮件与我们联系处理。敬请谅解!

给TA打赏
共{{data.count}}人
人已打赏
行业资讯

用bigger造比较句子(big,bigger,biggest这样的比较级用法太Lower,今天学更Higher)

2024-4-13 16:04:00

行业资讯

阵亡士兵名单查询官网(阵亡率达500%,依然死战不退的铁军,你听说过么?)

2024-4-13 16:24:33

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索