opencv實現車牌識別之車牌號定位_2,opencv_2
簡介
前一篇講解到了將用藍色篩選後的圖片,再一次灰階/二值化。現在從這裡繼續講解。
矩形檢測
因為車牌是一個矩形。所以接著將又一次二值化之後的圖片,進行膨脹,之後在進行矩形檢測。框選出可能是車牌號的矩形地區。代碼如下:
int** car_License_box(Mat& mat1, Mat& mat2, int* number){Mat threshold_output;vector<vector<Point> > contours;vector<Vec4i> hierarchy;Point s1, s2;int width_1, height_1;int width = mat1.rows;int height = mat1.cols;int sum = 0; int morph_elem = 3;int morph_size = 3; int** a = (int**)malloc(width * sizeof(int*)); //腐蝕Mat element = getStructuringElement(MORPH_RECT, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( -1, -1));dilate(mat1, mat1, element); /// 找到輪廓findContours(mat1, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); /// 多邊形逼近輪廓 + 擷取矩形和圓形邊界框vector<vector<Point> > contours_poly( contours.size() );vector<Rect> boundRect( contours.size() );vector<Point2f>center( contours.size() );vector<float>radius( contours.size() ); for( int i = 0; i < contours.size(); i++ ){ approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );boundRect[i] = boundingRect( Mat(contours_poly[i]) );minEnclosingCircle( contours_poly[i], center[i], radius[i] );} /// 畫多邊形輪廓 + 包圍的矩形框 + 圓形框mat2 = Mat::zeros(mat1.size(), CV_8UC3 );for( int i = 0; i< contours.size(); i++ ){s1 = boundRect[i].tl();s2 = boundRect[i].br();height_1 = s2.x - s1.x;width_1 = s2.y - s1.y; if((height_1 > (3 * width_1)) && (width_1 > (width / 2))){a[sum] = (int* )malloc(4 * sizeof(int));a[sum][0] = s1.x;a[sum][1] = s1.y;a[sum][2] = s2.x;a[sum][3] = s2.y;sum += 1;}}*number = sum;return a;} int main(int argc, char **argv){ ............. pic_gray(img_3, img_3); threshold = histogram_Calculate(img_3, 3); pic_Thresholding(img_3, threshold); address_1 = car_License_box(img_3, img_4, &address_Number_1); sprintf(str, "%d", i); namedWindow(str); imshow(str, img_3); } } waitKey(0); return 0;}
在函數car_License_box中,img_3為傳入的源映像,然後檢測出合適矩形,將矩形左上和右下那個角點儲存在二維數組address_1中,檢測到的矩形數量儲存在address_Number_1中。 該函數的具體流程如下:1、使用dilate來進行映像的膨脹。 2、使用opencv教程中講解過的輪廓尋找,並將檢測到的矩形角點儲存在boundRect中。 3、根據矩形左上和右下的角點,可以計算出矩形的寬與高。車牌所在的矩形應該長至少是寬的三倍。 同時在之前分割的圖片中,車牌的寬度至少應該是這個分割圖片的一半以上才正常。 4、將滿足了要求的矩形角點儲存在二維數組a中,並將矩形探測計數+1,最後返回對應儲存的二維數組。
矩形分割
上面矩形分割,已經將可能是車牌的矩形位置角點儲存在了address_1中,這裡我們根據address_1中的角點座標,將對應的矩形從原映像中複製到新映像中顯示:
void pic_cutting_1(Mat& mat1, Mat& mat2, Point s1, Point s2){ int i, j; IplImage pI_1; IplImage pI_2; CvScalar s; mat2 = cv::Mat(s2.y - s1.y, s2.x - s1.x, CV_8UC3, 1); pI_1 = mat1; pI_2 = mat2; for(i = s1.y; i < s2.y; i++){ for(j=s1.x; j<s2.x; j++){ s = cvGet2D(&pI_1, i, j); cvSet2D(&pI_2, i-s1.y, j-s1.x, s); } }} int main(int argc, char** argv){ ..................... address_1 = car_License_box(img_3, img_4, &address_Number_1); for(j=0; j< address_Number_1; j++){ DE("address_0:%d, %d, %d, %d\n", address_1[j][0], address_1[j][1], address_1[j][2], address_1[j][3]); s1.y = address_1[j][1] + selection_1[i][0]; s1.x = address_1[j][0]; s2.y = address_1[j][1] + selection_1[i][1]; s2.x = address_1[j][2]; DE("address:%d, %d, %d, %d\n", s1.x, s1.y, s2.x, s2.y); pic_cutting_1(img, img_5, s1, s2); sprintf(str, "%d", j); namedWindow(str); imshow(str, img_5); } } } namedWindow("img"); imshow("img",img); waitKey(0); return 0;}
這一步很簡單,效果顯示如下:
最後定位
在上面的片中,我們看到現在探測出了兩個可能是車牌的矩形位置。繼續做一次篩選判斷來確定車牌真正所在的位置。
int box_selection(Mat& mat1){ int width_1, height_1; int width = mat1.rows; int height = mat1.cols; int i, j; IplImage pI_1 = mat1; CvScalar s; int find_blue = 0; int blueToWhite = 0; int sum =0; for(i=0; i<width; i++){ find_blue = 0; blueToWhite = 0; for(j=0; j<height; j++){ s = cvGet2D(&pI_1, i, j); if((s.val[0] - s.val[1] > 10) && (s.val[0] - s.val[2] > 10) && (s.val[1] < 150) && (s.val[2] < 150)){ find_blue = 1; } else if((s.val[1] > 150) && (s.val[2] > 150) && (s.val[0] > 150) && (find_blue == 1)){ blueToWhite += 1; find_blue = 0; } } if(blueToWhite > 5){ sum += 1; } } return sum;} int main(int argc, char **argv){ ............ for(j=0; j< address_Number_1; j++){ DE("address_0:%d, %d, %d, %d\n", address_1[j][0], address_1[j][1], address_1[j][2], address_1[j][3]); s1.y = address_1[j][1] + selection_1[i][0]; s1.x = address_1[j][0]; s2.y = address_1[j][1] + selection_1[i][1]; s2.x = address_1[j][2]; DE("address:%d, %d, %d, %d\n", s1.x, s1.y, s2.x, s2.y); pic_cutting_1(img, img_5, s1, s2); box_flag = box_selection(img_5); DE("box_flag:%d\n", box_flag); if(box_flag > 5){ rectangle(img, s1, s2, color, 2, 8, 0 ); sprintf(str, "%d", j); namedWindow(str); imshow(str, img_5); } } } } namedWindow("img"); imshow("img",img); waitKey(0); return 0;}
因為車牌號是藍底白字,同時會交替出現7次。所以在box_selection,我們在藍色之後,跳變到白色的次數至少大於五次,表示該矩形位置是框選了車牌。來排除掉其他的矩形,最後將確定的車牌位置新映像顯示出來,同時在原映像車牌的位置畫上黃色方框。 進而最後的效果示範如下:
注意
該方法的準確率並不太高。如可能出現如下情況:
代碼下載如下:http://download.csdn.net/detail/u011630458/8431445