1. 程式人生 > >《opencv實戰》 之 車牌定位

《opencv實戰》 之 車牌定位

apt cnblogs blog ges simple mes class waitkey opencv2

目標:  提取車牌所在的區域

     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 == 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 = 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實戰》 之 車牌定位