1. 程式人生 > 其它 >Opencv學習(三)輪廓檢測

Opencv學習(三)輪廓檢測

什麼是輪廓檢測

輪廓檢測就是在一張只有0和1的圖片上繪製一系列的點,這些點就是影象中的曲線。函式findContours()就是從二值影象中尋找輪廓,在這個函式中,輸入影象可以是從Canny()函式得到的有邊緣畫素的影象,或者是通過threshold()、adaptiveThreshold()處理後得到的影象。

比如下面這張0-9的原始圖片

經過輪廓檢測後得到的圖片

如何進行輪廓檢測

findcontours函式

在opencv中使用函式findContours()來進行輪廓檢測
下面是函式原型
python:cv.FindContours(image, storage, mode=CV_RETR_LIST, method=CV_CHAIN_APPROX_SIMPLE, offset=(0, 0))


C++: void findContours(InputOutputArray image, OutputArrayOfArrays contours, int mode, int method, Point offset=Point())

findcontours引數介紹

1.image:原始影象,必須是8bit單通道影象,並且應該是二值影象,(如果不是--非0值被當做1,0值仍然是0)。該引數傳入後會在原始影象上直接修改,因此,一般使用時傳入原影象的副本

2.contours:被檢測到的輪廓,是一個儲存座標點的向量。(在py中,作為第一個返回值。在c++中是一個傳入傳出引數。)

3.mode:輪廓檢測方法。

| CV_RETR_EXTERNAL | 只檢測外輪廓 |
| CV_RETR_LIST | 檢測所有輪廓(內和外)但不建立任何層次關係 |
| CV_RETR_CCOMP | 檢索所有輪廓並將它們組織成一個兩級層次結構(頂層--外輪廓,底層--內輪廓) |
| CV_RETR_TREE | 檢索所有輪廓並重建巢狀輪廓的完整層次結構 |

4.method:輪廓近似方法。

| CV_CHAIN_APPROX_NONE | 用絕對值儲存所有輪廓點 |
| CV_CHAIN_APPROX_SIMPLE | 壓縮水平、垂直和對角線段,只留下它們的端點。 |

5.offset:每個輪廓點移位的可選偏移量

drawContours函式

該函式用來繪製經過檢測的輪廓
函式原型
Python: cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])
C++: void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )

drawContours引數介紹

1.image:輸入影象,(在C++中為輸入輸出引數)
2.contours:所有檢測到的輪廓,每個元素作為一個Point儲存在vector中
3.contourIdx:表示要繪製的輪廓引數,如果為-1就繪製所有輪廓
4.color:繪製的顏色,是一個Scalar
5.thickness:繪製線條的粗細
6.lineType:線條型別,常用LINE_AA
7~9 可選引數,沒用過,不知道效果如何

注意事項:
1.一般是在讀入的原始影象上進行繪製,如果在灰度圖或者二值圖上繪製,好像沒有效果(上次很久繪製不出來,一直找不到原因,踩坑+1)
2.drawContours的第二個引數可以直接用-1。但是如果是在迴圈中,可以用迴圈因子來繪製每個輪廓,效果都是一樣的

使用例項

#讀取影象
template=cv2.imread("D:\image\template.png")
imshow("image",template)
#化為灰度圖
ref_template=cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)
imshow("ref_gray",ref_template)
#化為二值圖
ref_template=cv2.threshold(ref_template,10,255,cv2.THRESH_BINARY_INV)[1]
imshow("ref_threshold",ref_template)

#輪廓檢測
##findContours 只接受二值圖   RETR_EXTERNAL 只檢測外輪廓   CHAIN_APPROX_SIMPLE 只保留終點座標
#在opencv4中要用hierarchy接收,而不能直接取[1]
refCnts,hierarchy=cv2.findContours(ref_template.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#繪製輪廓
cv2.drawContours(template,refCnts,-1,(0,0,255),3)
imshow("draw_contours",template)

結果展示

1.讀取的原始影象

2.灰度圖

3.二值圖

4.繪製檢測的輪廓


如果我想把每個數字用一個矩形框而不是繪製它的邊框,該怎麼解決?-----輪廓近似

什麼是輪廓近似

將輪廓形狀近似到另外一種由更少點組成的輪廓形狀,新輪廓的點的數目由我們設定的準確度來決定
比如在上面的幾個數字中,我想把邊界用矩形框住,此時就需要使用到輪廓近似

如何進行輪廓近似

假設我們要在一幅影象中查詢一個矩形,但是由於影象的種種原因我們不能得到一個完美的矩形,而是一個“壞形狀”,現在就可以使用這個函式來近似這個形狀,第二個引數是epsilon,它是從原始輪廓到近似輪廓的最大距離,它是一個準確度引數。

float peri = arcLength(threshCnts[i], true);//周長
//輪廓近似
approxPolyDP(threshCnts[i], contoursPoly[i], 0.02 * peri, true);
rectangle(cur_img, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 0, 255), 2);

結果展示

1.直接繪製輪廓效果

2.輪廓近似後效果