EasyPR源碼剖析(4):車牌定位之Sobel算子定位


一、簡介

sobel算子主要是用於獲得數字圖像的一階梯度,常見的應用是邊緣檢測。

Ⅰ.水平變化: 將 I 與一個奇數大小的內核進行卷積。比如,當內核大小為3時, 的計算結果為:

 

Ⅱ.垂直變化: 將: I 與一個奇數大小的內核進行卷積。比如,當內核大小為3時, 的計算結果為:

 

 

Opencv中Sobel函數使用擴展的Sobel算子,來計算一階、二階、三階或混合圖像差分。

 

CV_EXPORTS_W void Sobel( InputArray src, 
OutputArray dst,
int ddepth,
int dx,
int dy,
int ksize=3,
double scale=1,
double delta=0,
int borderType=BORDER_DEFAULT );
  • 第一個參數,InputArray 類型的src,為輸入圖像,填Mat類型即可。
  • 第二個參數,OutputArray類型的dst,即目標圖像,函數的輸出參數,需要和源圖片有一樣的尺寸和類型。
  • 第三個參數,int類型的ddepth,輸出圖像的深度。
  • 第四個參數,int類型dx,x 方向上的差分階數。
  • 第五個參數,int類型dy,y方向上的差分階數。
  • 第六個參數,int類型ksize,有默認值3,表示Sobel核的大小;必須取1,3,5或7。
  • 第七個參數,double類型的scale,計算導數值時可選的縮放因子,默認值是1,表示默認情況下是沒有應用縮放的。我們可以在文檔中查閱getDerivKernels的相關介紹,來得到這個參數的更多信息。
  • 第八個參數,double類型的delta,表示在結果存入目標圖(第二個參數dst)之前可選的delta值,有默認值0。
  • 第九個參數, int類型的borderType,我們的老朋友了(萬年是最后一個參數),邊界模式,默認值為BORDER_DEFAULT。這個參數可以在官方文檔中borderInterpolate處得到更詳細的信息。

具體的Sobel算子使用實例如下面代碼所示:

/// Generate grad_x and grad_y  
Mat grad_x, grad_y;  
Mat abs_grad_x, abs_grad_y;  
/// Gradient X  
//Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );  
//Calculates the first, second, third, or mixed image derivatives using an extended Sobel operator.  
Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );     
convertScaleAbs( grad_x, abs_grad_x );  
/// Gradient Y    
//Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );  
Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );     
convertScaleAbs( grad_y, abs_grad_y );  
/// Total Gradient (approximate)  
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad ); 

 

二、Sobel算子定位

 Sobel定位主要函數為 plateSobelLocate() ,主要處理函數有兩個,一個是 sobelFrtSearch() ,另一個是對定位區域進行偏斜扭轉的函數deskew(),deskew()后面會統一詳細講解,這邊我們主要看一下通過sobel算子定位的函數 sobelFrtSearch() 。

sobelFrtSearch()函數中通過 sobelOper() 進行sobel定位,主要步驟如下:

1、對圖像進行高斯濾波,為Sobel算子計算去除干擾噪聲;

2、圖像灰度化,提高運算速度;

3、對圖像進行Sobel運算,得到圖像的一階水平方向導數;

4、通過otsu進行閾值分割;

5、通過形態學閉操作,連接車牌區域。

此處通過Sobel算子進行車牌定位,僅僅做水平方向求導,而不做垂直方向求導。這樣做的意義是,如果做了垂直方向求導,會檢測出很多水平邊緣。水平邊緣多也許有利於生成更精確的輪廓,但是由於有些車子前端太多的水平邊緣了,例如車頭排氣孔,標志等等,很多的水平邊緣會誤導我們的連接結果,導致我們得不到一個恰好的車牌位置。

具體實現代碼如下所示:

 1 int CPlateLocate::sobelOper(const Mat &in, Mat &out, int blurSize, int morphW,int morphH) {
 2   Mat mat_blur;
 3   mat_blur = in.clone();
 4   GaussianBlur(in, mat_blur, Size(blurSize, blurSize), 0, 0, BORDER_DEFAULT);
 5 
 6   Mat mat_gray;
 7   if (mat_blur.channels() == 3)
 8     cvtColor(mat_blur, mat_gray, CV_RGB2GRAY);
 9   else
10     mat_gray = mat_blur;
11 
12   int scale = SOBEL_SCALE;
13   int delta = SOBEL_DELTA;
14   int ddepth = SOBEL_DDEPTH;
15 
16   Mat grad_x, grad_y;
17   Mat abs_grad_x, abs_grad_y;
18 
19 
20   Sobel(mat_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
21   convertScaleAbs(grad_x, abs_grad_x);
22 
23   Mat grad;
24   addWeighted(abs_grad_x, SOBEL_X_WEIGHT, 0, 0, 0, grad);
25 
26   Mat mat_threshold;
27   double otsu_thresh_val =
28       threshold(grad, mat_threshold, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);
29 
30 
31   Mat element = getStructuringElement(MORPH_RECT, Size(morphW, morphH));
32   morphologyEx(mat_threshold, mat_threshold, MORPH_CLOSE, element);
33 
34   out = mat_threshold;
35 
36   return 0;
37 }
View Code

上述圖像經過處理之后,可以直接對圖像輪廓進行搜索,輪廓搜索將全圖的輪廓都搜索出來了,需要進行篩選,對輪廓求最小外接矩形,並在 verifySizes() 中進行驗證,不滿足條件的刪除。 具體實現代碼如下所示:

 1 int CPlateLocate::sobelFrtSearch(const Mat &src,
 2                                  vector<Rect_<float>> &outRects) {
 3   Mat src_threshold;
 4 
 5   sobelOper(src, src_threshold, m_GaussianBlurSize, m_MorphSizeWidth,
 6             m_MorphSizeHeight);
 7 
 8   vector<vector<Point>> contours;
 9   findContours(src_threshold,
10                contours,               // a vector of contours
11                CV_RETR_EXTERNAL,
12                CV_CHAIN_APPROX_NONE);  // all pixels of each contours
13 
14   vector<vector<Point>>::iterator itc = contours.begin();
15 
16   vector<RotatedRect> first_rects;
17 
18   while (itc != contours.end()) {
19     RotatedRect mr = minAreaRect(Mat(*itc));
20 
21 
22     if (verifySizes(mr)) {
23       first_rects.push_back(mr);
24 
25       float area = mr.size.height * mr.size.width;
26       float r = (float) mr.size.width / (float) mr.size.height;
27       if (r < 1) r = (float) mr.size.height / (float) mr.size.width;
28     }
29 
30     ++itc;
31   }
32 
33   for (size_t i = 0; i < first_rects.size(); i++) {
34     RotatedRect roi_rect = first_rects[i];
35 
36     Rect_<float> safeBoundRect;
37     if (!calcSafeRect(roi_rect, src, safeBoundRect)) continue;
38 
39     outRects.push_back(safeBoundRect);
40   }
41   return 0;
42 }
View Code

 經過上述步驟后,為了進一步提高搜索的准確性,EasyPR里面對第一次搜索出的矩形擴大一定范圍后,進行了二次搜素,具體函數為 sobelSecSearchPart() 。sobelSecSearchPart() 函數和 sobelFrtSearch() 大致過程是類似的,此處不再詳細敘述,唯一的不同是sobelSecSearchPart() 對車牌上鉚釘的去除進行了對應的處理。之后對定位區域進行偏斜扭轉 deskew()處理之后,即可得到車牌定位的結果。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM