OpenCV(三)车牌识别SVM训练与hsv定位

SVM训练

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

HOG特征

在训练时,我们将使用HOG来提取一张图片的特征。HOG全称为:Histogram of Oriented Gridients,方向梯度
直方图。是计算机视觉、模式识别领域很常用的一种描述图像局部纹理的特征。
先计算图片某一区域中不同方向上梯度的值,然后进行累积,得到的直方图就可以代表这块区域,也就是作为特 征,可以输入到分类器里面。 简单来说,车牌的边缘与内部文字组成的一组信息(在边缘和角点的梯度值是很大 的,边缘和角点包含了很多物体的形状信息),HOG就是抽取这些信息组成一个直方图。

样本+标签,数据格式
xx.png--->HOG---> Mat(相当于图片数据矩阵)
正样本对应标签----> 1
负样本对应标签----> -1
每张图片放在一行,每行就是一个样本数据
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX

在OpenCV中对图像使用HOG提取特征:

 //1、灰度化,保存至gray
Mat gray;
cvtColor(plate, gray, COLOR_BGR2GRAY); //2、二值化,保存至shold
Mat shold;
threshold(gray, shold, 0, 255, THRESH_OTSU); //3、提取特征,保存至features
Mat features;
getHogFeatures(svmHog, shold, features);

-----------

//提取特征
void CarPlateRecgnize::getHogFeatures(HOGDescriptor *hog, Mat src, Mat &out) {
    //重新定义大小 缩放 提取特征的时候数据需要为  :CV_32S 有符号的32位数据
    Mat trainImg = Mat(hog->winSize, CV_32S);
    resize(src, trainImg, hog->winSize);
    //计算特征 获得float集合
    vector<float> d;
    hog->compute(trainImg, d, Size(8, 8));

    Mat features(d);
    //特征矩阵
    features.copyTo(out);
    features.release();
    trainImg.release();
}


训练数据

能够提取特征后,接下来就要进行SVM的训练了。opencv中的svm是使用的LIBSVM,LIBSVM是台湾大学林智仁
(Lin Chih-Jen)教授2001年开发的一套支持向量机的库。

深度学习就是调整参数的过程。我们使用的参数都是默认的,肯定不是最好的,但是基本稳定。不同参数效
果不同、训练检测速度不同,同时也影响着模型文件的大小。

我们将使用136x36规格的车牌图片作为正样本,任意136x36的图片作为负样本来进行训练。

struct TrainStruct{
    string file;
    int label;
};
---------
    //样本集合
    vector<TrainStruct> svm_data;

----------

    //正样本 标签是:1
    for(auto file : pos_files){
        svm_data.push_back({file,1});
    }
    //负样本 标签为:-1
    vector<string> neg_files;
    getFiles(SVM_NEG, neg_files);
    for(auto file : neg_files){
        svm_data.push_back({file,-1});
    }

现在我们的所有样本都被打上标签记录在 svm_data 中。接下来我们对样本进行特征提取并记录。

Mat samples;
    vector<int> responses;
    for(auto data:svm_data){
        auto image = imread(data.file,IMREAD_GRAYSCALE);
        if (image.empty()) {
            printf("加载样本失败 image: %s.\n", data.file.c_str());
            continue;
        }
        //二值
        threshold(image, image, 0, 255, THRESH_BINARY+THRESH_OTSU);
        Mat feature;
        //获得hog特征
        getSvmHOGFeatures(image, feature);
        //调整为一行
        feature = feature.reshape(1, 1);
        // 图片数据:x x x
        // samples:x x x
        //         x x x
        //保存特征数据
        samples.push_back(feature);
        //记录对应的标签
        responses.push_back(data.label);
    }

现在我们获得了samples与 labelsÏ两个数据。其中 samples 为样本特征数据,存储在矩阵中,每一行就是一个样 本的特征数据。加上我们正负样本各有三个,那么 samples 中记录的数据就为:宽:x,高为:3+3=6。看起来是 这样的:

样本.png

同时与 samples 对应的有一个 labels 标签集合,记录这些特征数据所属于的标签。 我们准备样本时,将正样本标 签置为1,负样本为-1。因此现在 labels 中的数据为 {1,1,1,-1,-1,-1}与 samples 相匹配。
下面我们将 samples 与 lables 包装为OpenCV中的训练数据集: TrainData

训练

我们的训练数据 TrainData 已经准备完成,接下来需要使用OpenCV提供的SVM进行训练。

//训练数据  行
    Ptr <TrainData> trainData = TrainData::create(samples, SampleTypes::ROW_SAMPLE, responses);
    printf("训练数据准备完成,开始训练!\n");
    //其他参数都是默认值 为了把
    //最后一个参数设置true 则会创建更平衡的验证子集
    //也就是如果是2类分类的话能得到更准确的结果
    classifier->trainAuto(trainData, 10, SVM::getDefaultGrid(SVM::C),
                          SVM::getDefaultGrid(SVM::GAMMA), SVM::getDefaultGrid(SVM::P),
                          SVM::getDefaultGrid(SVM::NU), SVM::getDefaultGrid(SVM::COEF),
                          SVM::getDefaultGrid(SVM::DEGREE), true);

    classifier->save( SVM_XML );

    printf("训练完成 ,模型保存: %s  \n", SVM_XML);

HSV 定位

我们已经使用了边缘定位,边缘定位是通过图像的各种处理,将车牌区域连接成一块整体从而进行轮廓查 找得到的候选车牌集合,但是边缘定位在某些情况下可能把背景也混合成一块整体。这样得到的车牌并不是最合适 的。所以我们再加入颜色定位同时进行筛选。以蓝色车牌举例,如果以BGR值来确定颜色,就算B为255,但是一 旦混合了G与R得到的结果可能并不是蓝色。以BGR来进行颜色的分辨并不容易。

而HSV(也可称为HSB)是根据颜色的直观特性创建的一种颜色空间,也称六角锥体模型。这个模型中颜色的参数分 别是:

  • 色度(Hue):用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°, 蓝色为240°;
  • 饱和度(Saturation): 取值范围为0-1。降低S,饱和度越低,颜色越白;
  • 透明度 (Value/brightness ): 取值范围为0-1。降低V,亮度月底,颜色越黑 。
hsv.png

经过查询发现,H为:200°-280°范围,S为0.37-1之间,V也是0.37-1之间。这个范围可能并不是非常精准,但是足 够了。
而OpenCV中H被定义为:0-180的范围(缩小一半)。而S与V都为0-255的范围(乘以255)。
因此最终认为 使用OpenCV获得HSV图像,某个像素点,H在100-140S与V都在95-255之间则该像素点为蓝色。那么使用颜色 定位的流程为:

转换HSV流程.png

转换HSV

 Mat hsv;
cvtColor(src, hsv, COLOR_BGR2HSV);

颜色匹配

循环处理每个像素点,根据蓝色HSV取值范围,如果像素点为蓝色,则将其HSV数据置为:0,0,255(只保留亮 度);若像素点非蓝色,则置为0,0,0(纯黑色)。这样只有蓝色的区域被保留下来。

    //3通道
    int chanles = hsv.channels();
    //高
    int h = hsv.rows;
    //宽数据长度
    int w = hsv.cols * chanles;
    //判断数据是否为一行存储的
    //头一行的末尾在内存里和下一行的开头是相连的
    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);
        //处理3个数据 所以+=3
        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;
            // h:蓝色就可以了
            //当V和S都达到最高值,也就是1时(opencv*255,0-255),颜色是最纯正的。
            // 降低S,颜色越发趋向于变白。降低V,颜色趋向于变黑,当V为0时,颜色变为黑色。
            if (h >= 100 && h <= 140 && s >= 95 && s <= 255 && v >= 95 && v <= 255) {
                blue = true;
            }
            //把蓝色像素 凸显出来 ,其他的区域全变成黑色
            if (blue) {
                p[j] = 0;
                p[j+1] = 0;
                p[j + 2] = 255;
            }
            else {
                //变成黑色
                p[j] = 0;
                p[j + 1] = 0;
                p[j + 2] = 0;
            }
        }
    }

此时,显示出来的图像为:

HSV结果.png

之所以会呈现红色,是因为 imshow 会将输出的Mat视为BGR数据进行显示。那么在我们的处理中蓝色被处理为: 0,0,255。如果看为BGR,则为R=255,所以为红色。

分离HSV

 vector<Mat> hsv_split;
split(hsv, hsv_split);

对上一步的结果进行分离,得到了三个元素(H、S、V)的向量集合 vector 。在这个集合中,我们直接取出第2个元 素,即为S饱和度数据矩阵。此矩阵Mat即为二值化的图像。

二值化.png

接下来的操作和边缘定位一致,对二值图像进行闭操作、查找轮廓、初步筛选最后旋转角度。即可获得候选车牌集 合。

后续处理

OpenCV(三)应用车牌识别

    //闭操作
    Mat close;
    Mat element = getStructuringElement(MORPH_RECT, Size(17, 3));
    morphologyEx(shold, close, MORPH_CLOSE, element);
    imshow("close",close);
    waitKey();

    //6、查找轮廓
    //获得初步筛选车牌轮廓================================================================
    //轮廓检测
    vector< vector<Point> > contours;
    //查找轮廓 提取最外层的轮廓  将结果变成点序列放入 集合
    findContours(close, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
    //遍历
    vector<RotatedRect> vec_color_roi;
    for (vector<Point> point : contours) {
        RotatedRect rotatedRect = minAreaRect(point);
        //rectangle(src, rotatedRect.boundingRect(), Scalar(255, 0, 255));
        //进行初步的筛选 把完全不符合的轮廓给排除掉 ( 比如:1x1,5x1000 )
        if (verifySizes(rotatedRect)) {
            vec_color_roi.push_back(rotatedRect);
        }
    }

    tortuosity(src, vec_color_roi, dst);

补充知识

机器学习算法-------> 核函数

交错数据

例子:
花生,石头,瓜子散落在桌子上,用里拍桌子,物体起落有高有低,就容易在空间维度划分区域

二维线性不可分------> 三维空间

SVM 向量机

上面的参数可以模拟运行

在线PS工具

跳变-----》黑色,白色变化(干扰物比较小)用来区分干扰,因为我们的数据是按照行来的 如GB888888

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容