opencv 輪廓判別法(find contour)使用詳解

本週學習了手寫數字識別

////////////////////////////////////////////////////////////////////////////////////////////////////

我先嚐試了第一種方法:基於輪廓查找的識別方法

這種方法主要運用了兩個函數:findcontourdrawcontour

其中,第一個函數可以實現對於數字圖像的輪廓查找,將查找到的點通過點向量的形式保存在了contour(爲findcontour的第二個函數參數)中,然後通過drawcontour將查找到的輪廓描出來!

NOTE:需要注意的是,這兩個函數是共同使用的,即有find則有draw。最重要的一點是他們共同使用了contour中的數據,換句話說,findcontour查找到了二值圖像中的點向量信息(必須是二值圖像,而且還必須是黑底白字貌似才能查找),然後在drawcontour函數中,就回會得到contour的數據。

好處在於,灰度圖得到的數據,可以在原彩色圖中被利用,從而實現了彩色圖像數據的檢測。

如圖所示:

 

 

通過上圖可以看出,我們獲得了contour是(函數的第二個參數)後,將org彩色圖給了lunkuo,在原圖上就可以檢測出數字。

NOTE:這裏有一個問題一定要注意!!!!

(1)函數findcontours從二值圖像中提取輪廓,並且返回提取輪廓的數目。指針First_contour的內容由函數填寫。它包含第一個最外層輪廓的指針,如果指針爲NULL,則沒有檢測到輪廓(比如圖像全部爲黑)。

 

(2)在做閾值處理時,一定要注意最終二值圖像必須爲黑底白字,如果是白底黑字,那麼我們就需要用:

 

如果此處我們改爲白底黑字,即CV_THRESH_BINARY,則會出現了誤檢情況,如圖所示,最外層紅色大框爲誤檢測!!

 

而正常情況下黑底白字,能夠正常識別,這點需要注意!

 

 

3注意:findContours()運行的時候,這個圖像會被直接塗改,因此如果是將來還有用的圖像,應該複製之後再傳給findContours()

即不能將經過findcontour處理運行後的圖像在顯示或者拿來用,因爲該圖片已經被處理過了!!這就需要重新引用原圖!!

此處我將findcontour運行過的out圖直接拿來進行輪廓檢測,結果出現瞭如下情況:

 

 

圖像變成了黑色,但是我設置斷點運行,並且查看打了contour中確實有返回參數,即輪廓參數時正常的,這就驗證了上面所說的觀點。即indContours()運行的時候,這個圖像會被直接塗改!!

因此,不能將處理過後的out拿來運行。

所以正確的操作應該是:

 

//////////////////////////////////////////////////////////////////////////////////////////////

EXAMPLE在二值圖像中,進行檢測:實測:

如圖所示:

(1)我們輸入一個經過處理後的圖像:  該圖像我們定義爲org(原圖)

 

 

(2) 我們將原圖org經過處理反二值變化濾波後得到了圖像out(輸出)

 

 

findContours(out, contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);//查找所有外輪廓,輸入圖像必須爲二值圖

使用find contour查找輪廓(NOTE:1)必須二值圖像2)必須爲黑底白字)

我們用藍色描繪出字體,處理流程結果如上圖所示。

(3)進行檢測

 

 

此處在findContours(out, contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE)

我們需要知道:

1. MODE 4種類型:

CV_RETR_EXTERNAL 只檢測出最外輪廓即c0。圖2中第一個輪廓指向最外的序列,除此之外沒有別的連接。

    CV_RETR_LIST 檢測出所有的輪廓並將他們保存到表(list)中,圖2中描繪了這個表,被找到的9條輪廓相互之間由h_prev和h_next連接。這裏並沒有表達出縱向的連接關係,沒有使用v_prev和v_next.

    CV_RETR_COMP 檢測出所有的輪廓並將他們組織成雙層的結構,第一層是外部輪廓邊界,第二層邊界是孔的邊界。從圖2可以看到5個輪廓的邊界,其中3個包含孔。最外層邊界c0有兩個孔,c0之間的所有孔相互間由h_prev和h_next指針連接。

CV_RETR_TREE 檢測出所有輪廓並且重新建立網狀的輪廓結構。圖2中,根節點是最外層的邊界c0,c0之下是孔h00,在同一層中與另一個孔h01相連接。同理,每個孔都有子節點(相對於c000和c010),這些子節點和父節點被垂直連接起來。這個步驟一直持續到圖像最內層的輪廓,這些輪廓會成爲樹葉節點。

2. METHOD 5個值

CV_CHAIN_CODE 用freeman鏈碼輸出輪廓,其他方法輸出多邊形(頂點的序列)。

    CV_CHAIN_APPROX_NONE將鏈碼編碼中的所有點轉換爲點序列形式(差不多就是把所有點都描出來)

    CV_CHAIN_APPROX_SIMPLE壓縮水平,垂直或斜的部分,只保存最後一個點。

    CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_QPPROX_TC89_KCOS使用Teh-Chin鏈逼近算法中的一個。

    CV_LINK_RUNS與上述的算法完全不同,連接所有的水平層次的輪廓。

 

此處:我們選擇CHAIN_APPROX_SIMPLE可以成功識別所有數字和字母。

如果使用CHAIN_APPROX_NONE, 字幕E無法檢測出來。

//////////////////////////////////////////////////////////////////////////////////////

 

 

//////////////////////////////////////////////////////////////////////////////////////

 

以上所描述的方法,仍存在以下問題:

(1)輸入的圖像是經過二次截圖後的二值圖像,最開始無法單獨檢測,再次截圖後,加載截圖後的圖像,才能分別檢測出三個字符。

這個問題可以從修改程序,定義一個有返回值return的函數,讓它把二次處理後的圖片直接return給主函數。

(2)是否可以使用canny 邊緣檢測處理。

預處理思路爲:灰度→二值(自適應or大津閾值(參考車道線檢測))→腐蝕→canny檢測

(3)如何去除圖像邊緣的白色干擾??

S1 : 運用車牌號檢測程序的方法,自動截取上下左右邊界,從而去除外邊界框的干擾

S2 : 設置感興趣ROI區域?

S3 : 結合實際,我們發現第一次檢測往往會出現將三個數字都框起來的誤檢情況,能夠將第一次誤檢框出的圖片自動截取保存,然後在次基礎上,進行第二次輪廓檢測,從而實現分別檢測。(具體過程實際和上文方法一樣,上文程序的實現,就是手動截取了第一次三個數都框起來的圖片,然後重新輸入後,得到的檢測結果)

該方法可以驗證!!

(4)可以採用垂直投影方法檢測

混合方法:用輪廓檢測/或者車牌號 得到理想的區域,使用垂直投影檢測分割。

NOTE:

分割程序:

//************************************* 切割出定位的矩*********************************///

char filenamew[255];

sprintf_s(filenamew,"定位矩形");

char rectnum[255];

char file[255];

Mat pic;

for (int i = 0; i<contours.size(); i++)

{

sprintf_s(file,"%s%d", filenamew, i);

sprintf_s(rectnum,"%s%d.bmp", filenamew, i);

Rect r = boundingRect(Mat(contours[i]));

pic= yuchuli(r);//選定roi

 // resize(pic,pic,Size(128,128));//把切割的圖片縮放成1128*1128

imwrite(rectnum, pic);

imshow(file, pic);

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章