基于OpenCV的车牌识别(Sobel、颜色定位)

栏目: 数据库 · 发布时间: 6年前

内容简介:车牌识别大体上需要经历过Sobel定位、颜色定位、SVM对定位来的候选车牌进行评测,给出评分,最后通过提取HOG特征按照训练模型进入ANN识别。这一章节介绍 定位相关的逻辑代码,其中定位用到 Sobel定位(边缘检测定位), 颜色定位:对应代码里的CarSobelPlateLocation,CarColorPlateLocation;两者定位后得到一些候选的图片,把这些图片送去SVM进行评测,SVM基于HOG提取边缘信息特征,HOG类同之前处理纹理特征的LBP,项目代码在Clion上开发的,源码地址前往C

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

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

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、 边缘检测 让车牌更加突出  在调用时需要以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、闭操作
    // 将相邻的白色区域扩大 连接成一个整体
    Mat close;
    Mat element = getStructuringElement(MORPH_RECT, Size(17, 3));
    morphologyEx(shold, close, MORPH_CLOSE, element);
    imshow("闭操作", close);
复制代码

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

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

//6、查找轮廓
    //获得初步筛选车牌轮廓================================================================
    //轮廓检测
    vector< vector<Point>> 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));
        //进行初步的筛选 把完全不符合的轮廓给排除掉 ( 比如:1x1,5x1000 )
        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) / 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;
    //矩形的比例
    float r = (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) {

    //获得旋转矩阵
    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);
    //截取 尽量把车牌多余的区域截取掉
    getRectSubPix(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°,青色为180°,品红为300°;

饱和度S

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

明度V

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

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

基于OpenCV的车牌识别(Sobel、颜色定位)

按照上面的表格找到蓝色区域 (100 ~ 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 = int(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;
            }
        }
    }
复制代码

得到下面的图:

基于OpenCV的车牌识别(Sobel、颜色定位)

接下来抽取亮度:

//把亮度数据抽出来
    //把h、s、v分离出来
    vector<Mat> hsv_split;
    split(hsv, hsv_split);

复制代码

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

// 整个图片+经过初步赛选的车牌 + 得到的候选车牌
    tortuosity(src, vec_sobel_roi, dst);

    for (Mat s: dst) {
        imshow("候选", s);
        waitKey();
    }
复制代码

筛选出来一个集合:

基于OpenCV的车牌识别(Sobel、颜色定位)

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

vector< Mat > sobel_plates;
//sobel定位
plateLocation->location(src, sobel_plates);

//颜色定位
vector< Mat > color_plates;
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

blog.csdn.net/liukun321/a…

简单来说,SVM就是用于区分不同的类型(车牌、非车牌)。SVM的训练数据既有特征又有标签,通过训练,让机器可以自己找到特征和标签之间的联系,在面对只有特征没有标签的数据时,可以判断出标签。属于机器学习中的监督学习。线性可分、线性不可分,不可分的时候用核函数来区分:

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

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

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

svm = SVM::load(svm_model);
CarPlateRecgnize p("/Users/xiuchengyin/Documents/Tina-NDK/OpencvCarRecgnize/resource/HOG_SVM_DATA2.xml");
复制代码

HOG特征

局部归一化的梯度方向直方图,是一种对图像局部重叠区域的密集型描述符, 它通过计算局部区域的梯度方向直方图来构成特征。

参数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);
复制代码
基于OpenCV的车牌识别(Sobel、颜色定位)
基于OpenCV的车牌识别(Sobel、颜色定位)

检测窗口被分为:((128-16)/8+1)*((64-16)/8+1)=105个块(Block);

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

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

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

简单来说,车牌的边缘与内部文字组成的一组信息(在边缘和角点的梯度值是很大的,边缘和角点包含了很多物体的形状信息),HOG就是抽取这些信息组成一个直方图。

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_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)
    {
        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 = features.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 (score < 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();
    }
    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…


以上所述就是小编给大家介绍的《基于OpenCV的车牌识别(Sobel、颜色定位)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

微创新

微创新

德鲁•博迪、雅各布•戈登堡 / 钟莉婷 / 中信出版社 / 2014-4-5 / 42.00

好产品不一定要颠覆,微小改进就能让用户尖叫! 引爆创新领域的全新方法论 互联网时代行之有效的5大创新策略 创业者、产品经理必读的创新行动指南 《怪诞行为学》作者 丹•艾瑞里 《影响力》作者 罗伯特•西奥迪尼 全球50位最具影响力的商业思想家之一丹尼尔•平克 周鸿祎、黎万强、罗振宇、牛文文、张鹏 联袂重磅推荐 为什么iPod可以在众多mp3产品中......一起来看看 《微创新》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具