车牌定位流程:
1、高斯模糊:http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html
目的:对图像去噪,为边缘检测算法做准备。
2、灰度化
目的:为边缘检测算法准备灰度化环境。
3、sobel运算(得到图像的一阶水平方向导数):https://docs.opencv.org/2.4/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.html
目的:检测图像中的垂直边缘,便于区分车牌。(Sobel运算只能对灰度图像有效,因此进行sobel运算前必须进行前面的灰度化工作)
4、二值化:(非黑即白)
目的:对图像的每个像素做一个阈值处理。为后续的形态学操作准备。
(灰度图像中,每个像素值是0-255,表示灰暗程度。设定一个阈值t,小于t的设为0,否则设为1)
5、形态学操作(闭操作)
目的:将车牌字符连接成一个连通区域,便于取轮廓
形态学操作的对象是二值化图像,腐蚀,膨胀是许多形态学操作的基础。
腐蚀:
原理:像素x至于模板的中心,根据模版的大小,遍历所有被模板覆盖的其他像素,修改像素x的值为所有像素中最小的值。(对于中心点像素x,模板范围内没有黑色则保留,否则该像素涂黑)
膨胀:
原理:与腐蚀操作相反
开操作:
原理:先腐蚀,再膨胀
闭操作:
原理:先膨胀,再腐蚀
6、求轮廓
目的:将连通域的外围画出来,便于形成外接矩形
7、尺寸判断
目的:初步筛选排除不可能是车牌的矩形(中国车牌的一般大小是440mm*140mm,宽高比为3.14)
/**
* 尺寸校验(宽高比&面积)
*/
int PlateLocate::verifySizes(RotatedRect rotatedRect)
{
//容错率
float error = 0.75f;
//理想宽高比
float aspect = float(136) / float(36);
//真实宽高比
float realAspect = float(rotatedRect.size.width) / float(rotatedRect.size.height);
if (realAspect < 1) realAspect = (float)rotatedRect.size.height / (float)rotatedRect.size.width;
//真实面积
float area = rotatedRect.size.height * rotatedRect.size.width;
//最小 最大面积 不符合的丢弃
//给个大概就行 随时调整
//尽量给大一些没关系, 这还是初步筛选。
int areaMin = 44 * aspect * 14;
int areaMax = 440 * aspect * 140;
//比例浮动 error认为也满足
//最小宽高比
float aspectMin = aspect - aspect * error;
//最大宽高比
float aspectMax = aspect + aspect * error;
if ((area < areaMin || area > areaMax) || (realAspect < aspectMin || realAspect > aspectMax))
return 0;
return 1;
}
8、角度判断
目的:初步筛选排除不可能是车牌的矩形
9、旋转矩形
目的:将偏斜的车牌调整为水平,为后面的车牌判断与字符识别提高成功率
/**
* 转换安全矩形,防止矩形框超出图像边界
*/
void PlateLocate::safeRect(Mat src, RotatedRect rect, Rect2f& safa_rect)
{
//RotatedRect 没有坐标
//转为正常的带坐标的边框
Rect2f boudRect = rect.boundingRect2f();
//左上角 x,y
float tl_x = boudRect.x > 0 ? boudRect.x : 0;
float tl_y = boudRect.y > 0 ? boudRect.y : 0;
//这里是拿 坐标 x,y 从0开始的 所以-1
//比如宽长度是10,x坐标最大是9, 所以src.clos-1
//右下角
float br_x = boudRect.x + boudRect.width < src.cols
? boudRect.x + boudRect.width - 1
: src.cols - 1;
float br_y = boudRect.y + boudRect.height < src.rows
? boudRect.y + boudRect.height - 1
: src.rows - 1;
float w = br_x - tl_x;
float h = br_y - tl_y;
if (w <= 0 || h <= 0) return;
safa_rect = Rect2f(tl_x, tl_y, w, h);
}
/**
* 旋转
*/
void PlateLocate::rotation(Mat src, Mat& dst, Size rect_size, Point2f center, double angle)
{
//获得旋转矩阵
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),
INTER_CUBIC);
//imshow("旋转前", src);
//imshow("旋转后", mat_rotated);
//截取 尽量把车牌多余的区域截取掉
getRectSubPix(mat_rotated, Size(rect_size.width, rect_size.height), center, dst);
//imshow("截取后", dst);
//waitKey();
mat_rotated.release();
rot_mat.release();
}
/**
* 矩形矫正
*/
void PlateLocate::tortuosity(Mat src, vector<RotatedRect>& rects, vector<Mat>& dst_plates)
{
//循环要处理的矩形
for (RotatedRect roi_rect : rects) {
//矩形角度
float roi_angle = roi_rect.angle;
float r = (float)roi_rect.size.width / (float)roi_rect.size.height;
if (r < 1) {
roi_angle = 90 + roi_angle;
}
//矩形大小
Size roi_rect_size = roi_rect.size;
//让rect在一个安全的范围(不能超过src)
Rect2f safa_rect;
safeRect(src, roi_rect, safa_rect);
//候选车牌
//抠图 这里不是产生一张新图片 而是在src身上定位到一个Mat 让我们处理
//数据和src是同一份
Mat src_rect = src(safa_rect);
//真正的候选车牌
Mat dst;
//不需要旋转的 旋转角度小没必要旋转了
if (roi_angle - 5 < 0 && roi_angle + 5 > 0) {
dst = src_rect.clone();
}
else {
//相对于roi的中心点 不减去左上角坐标是相对于整个图的
//减去左上角则是相对于候选车牌的中心点 坐标
Point2f roi_ref_center = roi_rect.center - safa_rect.tl();
Mat rotated_mat;
//矫正 rotated_mat: 矫正后的图片
rotation(src_rect, rotated_mat, roi_rect_size, roi_ref_center, roi_angle);
dst = rotated_mat;
}
//调整大小
Mat plate_mat;
//高+宽
plate_mat.create(36, 136, CV_8UC3);
resize(dst, plate_mat, plate_mat.size());
dst_plates.push_back(plate_mat);
dst.release();
}
}
10、调整大小
目的:确保候选车牌导入机器学习模型之前尺寸一致
HSV颜色模型
如果我们想找出一副图像中的蓝色部分,我们需要检查rgb分量中的blue分量就可以了。一般blue分量是0-255的值,即便蓝色分量255了,由于另外两个分量的影响,需要考虑各个分量的配比问题,rgb作为颜色判断很难实现,就有了hsv模型hsv,photoshop中hsb
HSV(Hue, Saturation, Value)是根据颜色的直观特性由A. R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)。这个模型中颜色的参数分别是:色调(H),饱和度(S),明度(V)。
色调H
用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°;
饱和度S
饱和度S表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。
亮度V
亮度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。
在OpenCV中hsv 数据为8UC则取值分别为 0-180 0-255 0-255 ,即蓝色应该是120。