织梦CMS - 轻松建站从此开始!

罗索

OpenCV下车牌定位算法实现代码(一)

罗索客 发布于 2010-05-11 19:34 点击:次 
车牌定位算法在车牌识别技术中占有很重要地位,一个车牌识别系统的识别率往往取决于车牌定位的成功率及准确度。车牌定位有很多种算法,从最简单的来,车牌在图像中一般被认为是长方形,由于图像摄取角度不同也可能是四边形。
TAG:

车牌定位算法在车牌识别技术中占有很重要地位,一个车牌识别系统的识别率往往取决于车牌定位的成功率及准确度。

车牌定位有很多种算法,从最简单的来,车牌在图像中一般被认为是长方形,由于图像摄取角度不同也可能是四边形。我们可以使用OpenCV中的实例: C:\Program Files\OpenCV\samples\c.squares.c 这是一个搜索图片中矩形的一个算法。我们只要稍微修改一下就可以实现定位车牌。

在这个实例中使用了canny算法进行边缘检测,然后二值化,接着用cvFindContours搜索轮廓,最后从找到的轮廓中根据角点的个数,角的度数和轮廓大小确定,矩形位置。以下是效果图:

这个算法可以找到一些车牌位置,但在复杂噪声背景下,或者车牌图像灰度与背景相差不大就很难定位车牌

所以我们需要寻找更好的定位算法。下面是squares的代码:

  1. #ifdef _CH_  
  2. #pragma package <opencv>  
  3. #endif  
  4.  
  5. #ifndef _EiC  
  6. #include "cv.h"  
  7. #include "highgui.h"  
  8. #include <stdio.h>  
  9. #include <math.h>  
  10. #include <string.h>  
  11. #endif  
  12.  
  13. int thresh = 50;  
  14. IplImage* img = 0;  
  15. IplImage* img0 = 0;  
  16. CvMemStorage* storage = 0;  
  17. CvPoint pt[4];  
  18. const char* wndname = "Square Detection Demo";  
  19.  
  20. // helper function:  
  21. // finds a cosine of angle between vectors  
  22. // from pt0->pt1 and from pt0->pt2   
  23. double angle( CvPoint* pt1, CvPoint* pt2, CvPoint* pt0 )  
  24. {  
  25. double dx1 = pt1->x - pt0->x;  
  26. double dy1 = pt1->y - pt0->y;  
  27. double dx2 = pt2->x - pt0->x;  
  28. double dy2 = pt2->y - pt0->y;  
  29. return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);  
  30. }  
  31.  
  32. // returns sequence of squares detected on the image.  
  33. // the sequence is stored in the specified memory storage  
  34. CvSeq* findSquares4( IplImage* img, CvMemStorage* storage )  
  35. {  
  36.     CvSeq* contours;  
  37.     int i, c, l, N = 11;  
  38.     CvSize sz = cvSize( img->width & -2, img->height & -2 );  
  39.     IplImage* timg = cvCloneImage( img ); // make a copy of input image  
  40.     IplImage* gray = cvCreateImage( sz, 8, 1 );   
  41.     IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 );  
  42.     IplImage* tgray;  
  43.     CvSeq* result;  
  44.     double s, t;  
  45.     // create empty sequence that will contain points -  
  46.     // 4 points per square (the square's vertices)  
  47.     CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage );  
  48.  
  49.     // select the maximum ROI in the image  
  50.     // with the width and height divisible by 2  
  51.     cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height ));  
  52.  
  53.     // down-scale and upscale the image to filter out the noise  
  54.     cvPyrDown( timg, pyr, 7 );  
  55.     cvPyrUp( pyr, timg, 7 );  
  56.     tgray = cvCreateImage( sz, 8, 1 );  
  57.  
  58.     // find squares in every color plane of the image  
  59.     for( c = 0; c < 3; c++ )  
  60.     {  
  61.         // extract the c-th color plane  
  62.         cvSetImageCOI( timg, c+1 );  
  63.         cvCopy( timg, tgray, 0 );  
  64.  
  65.         // try several threshold levels  
  66.         for( l = 0; l < N; l++ )  
  67.         {  
  68. // hack: use Canny instead of zero threshold level.  
  69. // Canny helps to catch squares with gradient shading     
  70.             if( l == 0 )  
  71.             {  
  72. // apply Canny. Take the upper threshold from slider  
  73. // and set the lower to 0 (which forces edges merging)   
  74. cvCanny( tgray, gray,60, 180, 3 );  
  75. // dilate canny output to remove potential  
  76. // holes between edge segments   
  77. cvDilate( gray, gray, 0, 1 );  
  78.             }  
  79.             else 
  80.             {  
  81. //apply threshold if l!=0:  
  82. //tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0  
  83. //cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY );  
  84. cvThreshold( tgray, gray, 50, 255, CV_THRESH_BINARY );  
  85.             }
  86.  
  87. // find contours and store them all as a list  
  88. cvFindContours( gray, storage, &contours, sizeof(CvContour),  
  89. CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );  
  90.  
  91.  
  92. // test each contour  
  93. while( contours )  
  94. {  
  95. // approximate contour with accuracy proportional  
  96. // to the contour perimeter  
  97. result = cvApproxPoly( contours, sizeof(CvContour), storage,  
  98.   CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 );  
  99. // square contours should have 4 vertices after approximation  
  100. // relatively large area (to filter out noisy contours)  
  101. // and be convex.  
  102. // Note: absolute value of an area is used because  
  103. // area may be positive or negative - in accordance with the  
  104. // contour orientation  
  105. if( result->total == 4 &&  
  106. fabs(cvContourArea(result,CV_WHOLE_SEQ)) > 1000 &&  
  107. cvCheckContourConvexity(result) )  
  108. {  
  109. s = 0;  
  110.  
  111. for( i = 0; i < 5; i++ )  
  112. {  
  113. // find minimum angle between joint  
  114. // edges (maximum of cosine)  
  115. if( i >= 2 )
  116. {
  117. t = fabs(angle(
  118. (CvPoint*)cvGetSeqElem( result, i ),
  119. (CvPoint*)cvGetSeqElem( result, i-2 ),
  120.    (CvPoint*)cvGetSeqElem( result, i-1 )));
  121.    s = s > t ? s : t;
  122.  }
  123. }  
  124.  
  125.  
  126.                     // if cosines of all angles are small  
  127.                     // (all angles are ~90 degree) then write quandrange  
  128.                     // vertices to resultant sequence   
  129.                     if( s < 0.3 )  
  130.                         for( i = 0; i < 4; i++ )  
  131.                             cvSeqPush( squares,  
  132.                                 (CvPoint*)cvGetSeqElem( result, i ));  
  133.                 }  
  134.                   
  135.                 // take the next contour  
  136.                 contours = contours->h_next;  
  137.             }  
  138.         }  
  139.     }  
  140.       
  141.     // release all the temporary images  
  142.     cvReleaseImage( &gray );  
  143.     cvReleaseImage( &pyr );  
  144.     cvReleaseImage( &tgray );  
  145.     cvReleaseImage( &timg );  
  146.       
  147.     return squares;  
  148. }  
  149.  
  150.  
  151. // the function draws all the squares in the image  
  152. void drawSquares( IplImage* img, CvSeq* squares )  
  153. {  
  154.     CvSeqReader reader;  
  155.     IplImage* cpy = cvCloneImage( img );  
  156.     int i;  
  157.       
  158.     // initialize reader of the sequence  
  159.     cvStartReadSeq( squares, &reader, 0 );  
  160.       
  161.     // read 4 sequence elements at a time (all vertices of a square)  
  162.     for( i = 0; i < squares->total; i += 4 )  
  163.     {  
  164.         CvPoint* rect = pt;  
  165.         int count = 4;  
  166.           
  167.         // read 4 vertices  
  168.         memcpy( pt, reader.ptr, squares->elem_size );  
  169.         CV_NEXT_SEQ_ELEM( squares->elem_size, reader );  
  170.         memcpy( pt + 1, reader.ptr, squares->elem_size );  
  171.         CV_NEXT_SEQ_ELEM( squares->elem_size, reader );  
  172.         memcpy( pt + 2, reader.ptr, squares->elem_size );  
  173.         CV_NEXT_SEQ_ELEM( squares->elem_size, reader );  
  174.         memcpy( pt + 3, reader.ptr, squares->elem_size );  
  175.         CV_NEXT_SEQ_ELEM( squares->elem_size, reader );  
  176.           
  177.         // draw the square as a closed polyline   
  178.         cvPolyLine( cpy, &rect, &count, 1, 1, CV_RGB(0,255,0), 3, CV_AA, 0 );  
  179.     }  
  180.       
  181.     // show the resultant image  
  182.     cvShowImage( wndname, cpy );  
  183.     cvReleaseImage( &cpy );  
  184. }  
  185.  
  186.  
  187. void on_trackbar( int a )  
  188. {  
  189.     if( img )  
  190.         drawSquares( img, findSquares4( img, storage ) );  
  191. }  
  192.  
  193. char* names[] = { "pic1.png""pic2.png""pic3.png",  
  194.                   "pic4.png""pic5.png""pic6.png", 0 };  
  195.  
  196. int main(int argc, char** argv)  
  197. {  
  198.     int i, c;  
  199.     // create memory storage that will contain all the dynamic data  
  200.     storage = cvCreateMemStorage(0);  
  201.  
  202.     for( i = 0; names[i] != 0; i++ )  
  203.     {  
  204.         // load i-th image  
  205.         img0 = cvLoadImage( names[i], 1 );  
  206.         if( !img0 )  
  207.         {  
  208.             printf("Couldn't load %s\n", names[i] );  
  209.             continue;  
  210.         }  
  211.         img = cvCloneImage( img0 );  
  212.           
  213. // create window and a trackbar (slider) with parent "image" and set callback  
  214. // (the slider regulates upper threshold, passed to Canny edge detector)   
  215. cvNamedWindow( wndname,0 );  
  216. cvCreateTrackbar( "canny thresh", wndname, &thresh, 1000, on_trackbar );  
  217.           
  218. // force the image processing  
  219. on_trackbar(0);  
  220. // wait for key.  
  221. // Also the function cvWaitKey takes care of event processing  
  222. c = cvWaitKey(0);  
  223. // release both images  
  224. cvReleaseImage( &img );  
  225. cvReleaseImage( &img0 );  
  226. // clear memory storage - reset free space position  
  227. cvClearMemStorage( storage );  
  228. if( c == 27 )break;  
  229. }
  230. cvDestroyWindow( wndname );  
  231. return 0;  
  232. }  
  233.  
  234. #ifdef _EiC  
  235. main(1,"squares.c");  
  236. #endif 

原文:http://blog.csdn.net/heihei723/

(heihei723)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201005/9390.html]
本文出处:CSDN博客 作者:heihei723
顶一下
(13)
81.3%
踩一下
(3)
18.7%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容