基於vs2015+opencv3.3的簡易的車牌定位

基於vs2015+opencv3.3的簡易的車牌定位

直接上代碼

#include<opencv2\opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int areas;
//該函數用來驗證是否是我們想要的區域,車牌定位原理其實就是在圖片上尋找矩形,我們可以用長寬比例以及面積來驗證是否是我們想要的矩形,寬高比爲520/110=4.7272 (車牌的長除以寬),區域面積最小爲15個像素,最大爲125個像素
bool VerifySize(RotatedRect candidate) {
    float error = 0.4; //40%的誤差範圍
    float aspect = 4.7272;//寬高比例
    int min = 15 * aspect * 15; //最小像素爲15
    int max = 125 * aspect * 125;//最大像素爲125
    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;
}
int main(int argc, char** argv) {

    Mat src;
    src = imread("D:\\Car.jpg");//讀取含車牌的圖片
    if (!src.data)
    {
        cout << "Could not open Car.jph.." << endl;
        return -1;
    }
    Mat img_gray;
    cvtColor(src, img_gray, CV_BGR2GRAY);//灰度轉換
    Mat img_blur;
    blur(img_gray, img_blur, Size(5, 5));//用來降噪
    Mat img_sobel;
    Sobel(img_gray, img_sobel, CV_8U, 1, 0, 3);//Sobel濾波,對x進行求導,就是強調y方向,對y進行求導,就是強調x方向,在此我們對x求導,查找圖片中的豎直邊
    Mat img_threshold;
    threshold(img_sobel, img_threshold, 0, 255, THRESH_BINARY | THRESH_OTSU);
    Mat element = getStructuringElement(MORPH_RECT, Size(21, 5));//這個Size很重要!!不同的圖片適應不同的Size,待會在下面放圖,大家就知道區別了
    morphologyEx(img_threshold, img_threshold,MORPH_CLOSE,element);//閉操作,就是先膨脹後腐蝕,目的就是將圖片聯通起來,取決於element的Size。
    /*接下來就是提取輪廓*/
    vector<vector<Point>>contours; 
    findContours(img_threshold, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    Mat result = Mat::zeros(src.size(), CV_8U);
    drawContours(result, contours, -1, Scalar(255));
    vector<RotatedRect> rects; //用來存放旋轉矩形的容器
    //Mat result1 = Mat::zeros(src.size(), CV_8U);
    Mat result1;
    src.copyTo(result1);
    for (size_t i = 0; i < contours.size(); i++)
    {
        Point2f vertices[4];//用來存放旋轉矩形的四個點
        RotatedRect mr = minAreaRect(Mat(contours[i]));
    //minAreaRect 尋找最小的矩形
        if (VerifySize(mr))//篩選是否是我們需要的區域,如果驗證成功,就放到rects裏,
        {
            //if (mr.angle > -30) {
            mr.points(vertices);
            for (size_t j = 0; j < 4; j++)
            {
                line(result1, vertices[j], vertices[(j + 1) % 4], Scalar(0, 0, 255), 2, 8);
                        cout << "矩形座標"<<j<<"爲" << vertices[j] << endl;
            }
                cout << "height:" << mr.size.height << endl << "weight:" << mr.size.width << endl;
            rects.push_back(mr);
                cout << "矩形角度:" << mr.angle << endl;
    //  }
        }
    }
    vector<Mat>output;//用於存放識別到的圖像
    for (size_t i = 0; i < rects.size(); i++)
    {
        Mat dst_warp;
        Mat dst_warp_rotate;
        Mat rotMat(2, 3, CV_32FC1);
        dst_warp = Mat::zeros(src.size(), src.type());
        float r = (float)rects[i].size.width / (float)rects[i].size.height;
        float  angle = rects[i].angle;
        if (r < 1)
            angle = angle + 90; 
        rotMat = getRotationMatrix2D(rects[i].center,angle, 1);//其中的angle參數,正值表示逆時針旋轉,關於旋轉矩形的角度,以爲哪個是長哪個是寬,在下面會說到
        warpAffine(src, dst_warp_rotate, rotMat, dst_warp.size());//將矩形修正回來
        Size rect_size = rects[i].size;
        if (r < 1)
            swap(rect_size.width, rect_size.height);
        Mat dst(rects[i].size, CV_8U);
        getRectSubPix(dst_warp_rotate, rect_size, rects[i].center, dst);//裁剪矩形
        /*以下代碼是將裁減到的矩形設置爲相同大小,並且提高對比度*/
        Mat resultResized;
        resultResized.create(33, 144, CV_8UC3);
        resize(dst, resultResized, resultResized.size(), 0, 0, INTER_CUBIC);
        Mat grayResult;
        cvtColor(resultResized, grayResult, CV_BGR2GRAY);
        blur(grayResult, grayResult, Size(3, 3));
        equalizeHist(grayResult, grayResult); //均值化提高對比度
        output.push_back(grayResult); //存放圖片
    }
    char name[20] = "";
    for (size_t i = 0; i < output.size(); i++)
    {
        sprintf_s(name, "識別到的第%d個車牌", i+1);
        imshow(name, output[i]);
    } 
    waitKey(0);
    return 0;
}

現在來說一下element的Size的問題,我們要的是將車牌區域連通,我們來看一下9*3的Size
這裏寫圖片描述
再來看一下17*3的情況
這裏寫圖片描述
我們來看一下 車牌區域連通在一起了 ,這就是我們所需要的Size了
PS:不同的圖片需要修改不同的Size 這個問題我還沒解決。。

現在來說下旋轉矩形的問題,左上角爲原點,水平方向爲x,豎直方向爲y方向
angle爲x軸逆時針旋轉 先碰到的第一個邊所成的夾角(夾角範圍-90,0),並且該邊爲width ,我們附加一張圖片就可以很清楚了這裏寫圖片描述
上面有段代碼是
if (r < 1)
angle = angle + 90; 大家結合上面那張圖想想,假設是-89度,並且r是<1的 ,我們如果沒有這個angle+90,在 getRotationMatrix2D方法中旋轉-89度,他會變成垂直,如果加上90,就變成1度,他旋轉1度,就修正成水平了。 接下來放圖。
這裏寫圖片描述
這裏寫圖片描述
灰度轉換
這裏寫圖片描述
濾波
這裏寫圖片描述
二值化
這裏寫圖片描述
提取輪廓
這裏寫圖片描述
紅色框出我們得到的車牌
這裏寫圖片描述
最終顯示的圖片
其實車牌識別就是尋找矩形+SVM分類..,前期簡單的矩形識別已經完成了,就是結合SVM分類器進行篩選了。

發佈了33 篇原創文章 · 獲贊 38 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章