首页 > 代码库 > 《opencv实战》 之 车牌定位

《opencv实战》 之 车牌定位

目标:  提取车牌所在的区域

       PS:现在还没学习文字检测,以后再来补充~~

技术分享

思路:

    1.利用形态学+梯度+轮廓检测,但是这个形态学要求比较高,得调节到适当的参数。

    2.利用HSV颜色分离+梯度+形态学+轮廓检测,这个方法的适应度比较高,行比较上面的方法较难理解。

本文使用第二种方法实现:

PS:不要问为什么用这种方法,没有为什么的方法,只有解决问题的方法,手动操作一下就懂了。

先上效果图:

技术分享

梯度检测图(1-1)

 技术分享

S空间图(1-2)

 技术分享

S空间分离蓝色图(1-3)

 

技术分享

(HSV图像分离+梯度)结合图(1-4)

 技术分享

轮廓检测处理图(1-5)

 

 技术分享

最终效果图(1-6)

 

 上代码:

  1 #if 1
  2 #include <opencv2/opencv.hpp>
  3 #include <iostream>
  4 #include "math.h"
  5 
  6 using namespace cv;
  7 using namespace std;
  8 
  9 int main(int argc, char**argv)
 10 {
 11     Mat input_image;
 12     input_image = imread("car.jpg");
 13     if (input_image.data =http://www.mamicode.com/= NULL) {
 14         return -1; cout << "can‘t open image.../";
 15     }
 16     //-----------------------------------------------------------------------------------//
 17     //------------------------------梯度检测图像--------------------------------------//
 18     //-----------------------------------------------------------------------------------//
 19     Mat input_image1;
 20     input_image.copyTo(input_image1);
 21     cvtColor(input_image1, input_image1, CV_BGR2GRAY);
 22     input_image1.convertTo(input_image1, CV_32FC1);
 23     Mat sobelx = (Mat_<float>(3, 3) << -0.125, 0, 0.125, -0.25, 0, 0.25, -0.125, 0, 0.125);
 24     filter2D(input_image1, input_image1, input_image1.type(), sobelx);
 25     Mat mul_image;
 26     multiply(input_image1, input_image1, mul_image);
 27     const int scaleValue = http://www.mamicode.com/4;
 28     double threshold = scaleValue * mean(mul_image).val[0];//4 * img_s的平均值
 29     Mat resultImage = Mat::zeros(mul_image.size(), mul_image.type());
 30     float* pDataimg_s  = (float*)(mul_image.data);
 31     float* pDataresult = (float*)(resultImage.data);
 32     const int height = input_image1.rows;
 33     const int width  = input_image1.cols;
 34     //--- 非极大值抑制 + 阈值分割
 35     for (size_t i = 1; i < height-1; i++)
 36     {
 37         for (size_t j = 1; j < width-1; j++)
 38         {
 39             bool b1 = (pDataimg_s[i*height + j] > pDataimg_s[i*height + j - 1]);
 40             bool b2 = (pDataimg_s[i*height + j] > pDataimg_s[i*height + j + 1]);
 41             bool b3 = (pDataimg_s[i*height + j] > pDataimg_s[(i - 1)*height + j]);
 42             bool b4 = (pDataimg_s[i*height + j] > pDataimg_s[(i + 1)*height + j]);
 43             pDataresult[i*height + j] = 255 * ((pDataimg_s[i*height + j] > threshold) && ((b1&&b2) || (b3&&b4)));
 44         }
 45     }
 46     resultImage.convertTo(resultImage, CV_8UC1);
 47     //-----------------------------------------------------------------------------------//
 48     //---------------------------------HSV通道提取---------------------------------------//
 49     //-----------------------------------------------------------------------------------//
 50     Mat input_image2;
 51     input_image.copyTo(input_image2);
 52     Mat img_h, img_s, img_v, img_hsv;
 53     cvtColor(input_image2, img_hsv, CV_BGR2HSV);
 54     vector<Mat> hsv_vec;
 55     split(img_hsv, hsv_vec);
 56     img_h = hsv_vec[0];
 57     img_s = hsv_vec[1];
 58     img_v = hsv_vec[2];
 59     img_h.convertTo(img_h, CV_32F);
 60     img_s.convertTo(img_s, CV_32F);
 61     img_v.convertTo(img_v, CV_32F);
 62     normalize(img_h, img_h, 0, 1, NORM_MINMAX);
 63     normalize(img_s, img_s, 0, 1, NORM_MINMAX);
 64     normalize(img_v, img_v, 0, 1, NORM_MINMAX);
 65     //----下面的操作等同上面的归一化--------//
 66     //double h_max, s_max, v_max;
 67     ////minMaxIdx(img_h, 0, &h_max);
 68     //minMaxLoc(img_h, 0, &h_max);
 69     //minMaxLoc(img_s, 0, &s_max);
 70     //minMaxLoc(img_v, 0, &v_max);
 71     //img_h /= h_max;
 72     //img_s /= s_max;
 73     //img_v /= v_max;
 74     Mat img_vblue = ((img_h > 0.45)&(img_h < 0.75)&(img_s > 0.15)&(img_v > 0.25));//蓝色通道提取
 75     Mat vbule_gradient = Mat::zeros(input_image2.size(), CV_8UC1);
 76     for (size_t i = 1; i < height-1; i++)
 77     {
 78         for (size_t j = 1; j < width-1; j++)
 79         {
 80             /*Rect rec;
 81             rec.x = j - 1;
 82             rec.y = i - 1;
 83             rec.width  = 3;
 84             rec.height = 3;*/
 85             //----梯度和蓝色区域重合的部分,也可以用上面的矩形3X3的判断
 86             vbule_gradient.at<uchar>(i, j) = (resultImage.at<uchar>(i, j) == 255 && img_vblue.at<uchar>(i,j) != 0) ? 255 : 0;
 87             //vbule_gradient.at<uchar>(i, j) = (resultImage.at<uchar>(i, j) == 255 && countNonZero(img_vblue(rec)) >= 1) ? 255 : 0;
 88         }
 89     }
 90     //-----------------------------------------------------------------------------------//
 91     //-----------------------------形态学+轮廓提取车牌-----------------------------------//
 92     //-----------------------------------------------------------------------------------//
 93     Mat morph;
 94     morphologyEx(vbule_gradient, morph, MORPH_CLOSE, Mat::ones(2, 25, CV_8UC1));
 95     vector<vector<Point>> contours;
 96     vector<Vec4i> hierarchy;
 97     findContours(morph, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));
 98     Rect rec_adapt;
 99     for (size_t i = 0; i < contours.size(); i++)
100     {
101         //----矩形区域非零像素占总的比例,防止有较大的空白区域干扰检测结果
102         //----矩形的长宽限制,也可以再增加额外条件:长宽比例等
103         int true_pix_count = countNonZero(morph(boundingRect(contours[i])));
104         double true_pix_rate = static_cast<double>(true_pix_count) / static_cast<double>(boundingRect(contours[i]).area());
105         if (boundingRect(contours[i]).height > 10 && boundingRect(contours[i]).width > 80 && true_pix_rate > 0.7)
106         {
107             rec_adapt = boundingRect(contours[i]);
108             drawContours(morph, contours, static_cast<int>(i), Scalar(255, 255, 255), 2);
109         }        
110     }
111     imshow("Area Brand", input_image(rec_adapt));
112     waitKey(0);
113     return 0;
114 }
115 #endif

 

 

参考:《opencv图像处理编程实例》

 

《opencv实战》 之 车牌定位