OpenCV-Python實現(xiàn)輪廓檢測實例分析
相比C++而言,Python適合做原型。本系列的文章介紹如何在Python中用OpenCV圖形庫,以及與C++調(diào)用相應OpenCV函數(shù)的不同之處。這篇文章介紹在Python中使用OpenCV檢測并繪制輪廓。
提示:
轉(zhuǎn)載請詳細注明原作者及出處,謝謝!
本文介紹在OpenCV-Python中檢測并繪制輪廓的方法。
本文不介詳細的理論知識,讀者可從其他資料中獲取相應的背景知識。筆者推薦清華大學出版社的《圖像處理與計算機視覺算法及應用(第2版)》。
輪廓檢測
輪廓檢測也是圖像處理中經(jīng)常用到的。OpenCV-Python接口中使用cv2.findContours()函數(shù)來查找檢測物體的輪廓。
實現(xiàn)
使用方式如下:
import cv2 img = cv2.imread('D:\\test\\contour.jpg') gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(img,contours,-1,(0,0,255),3) cv2.imshow("img", img) cv2.waitKey(0)
需要注意的是cv2.findContours()函數(shù)接受的參數(shù)為二值圖,即黑白的(不是灰度圖),所以讀取的圖像要先轉(zhuǎn)成灰度的,再轉(zhuǎn)成二值圖,參見4、5兩行。第六行是檢測輪廓,第七行是繪制輪廓。
結(jié)果
原圖如下:
檢測結(jié)果如下:
注意,findcontours函數(shù)會“原地”修改輸入的圖像。這一點可通過下面的語句驗證:
cv2.imshow("binary", binary) contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) cv2.imshow("binary2", binary)
執(zhí)行這些語句后會發(fā)現(xiàn)原圖被修改了。
cv2.findContours()函數(shù)
函數(shù)的原型為
cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])
返回兩個值:contours:hierarchy。
參數(shù)
第一個參數(shù)是尋找輪廓的圖像;
第二個參數(shù)表示輪廓的檢索模式,有四種(本文介紹的都是新的cv2接口):
cv2.RETR_EXTERNAL表示只檢測外輪廓
cv2.RETR_LIST檢測的輪廓不建立等級關(guān)系
cv2.RETR_CCOMP建立兩個等級的輪廓,上面的一層為外邊界,里面的一層為內(nèi)孔的邊界信息。如果內(nèi)孔內(nèi)還有一個連通物體,這個物體的邊界也在頂層。
cv2.RETR_TREE建立一個等級樹結(jié)構(gòu)的輪廓。
第三個參數(shù)method為輪廓的近似辦法
cv2.CHAIN_APPROX_NONE存儲所有的輪廓點,相鄰的兩個點的像素位置差不超過1,即max(abs(x1-x2),abs(y2-y1))==1
cv2.CHAIN_APPROX_SIMPLE壓縮水平方向,垂直方向,對角線方向的元素,只保留該方向的終點坐標,例如一個矩形輪廓只需4個點來保存輪廓信息
cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
返回值
cv2.findContours()函數(shù)返回兩個值,一個是輪廓本身,還有一個是每條輪廓對應的屬性。
contour返回值
cv2.findContours()函數(shù)首先返回一個list,list中每個元素都是圖像中的一個輪廓,用numpy中的ndarray表示。這個概念非常重要。在下面drawContours中會看見。通過
print (type(contours)) print (type(contours[0])) print (len(contours))
可以驗證上述信息。會看到本例中有兩條輪廓,一個是五角星的,一個是矩形的。每個輪廓是一個ndarray,每個ndarray是輪廓上的點的集合。
由于我們知道返回的輪廓有兩個,因此可通過
cv2.drawContours(img,contours,0,(0,0,255),3)
和
cv2.drawContours(img,contours,1,(0,255,0),3)
分別繪制兩個輪廓,關(guān)于該參數(shù)可參見下面一節(jié)的內(nèi)容。同時通過
print (len(contours[0])) print (len(contours[1]))
輸出兩個輪廓中存儲的點的個數(shù),可以看到,第一個輪廓中只有4個元素,這是因為輪廓中并不是存儲輪廓上所有的點,而是只存儲可以用直線描述輪廓的點的個數(shù),比如一個“正立”的矩形,只需4個頂點就能描述輪廓了。
hierarchy返回值
此外,該函數(shù)還可返回一個可選的hiararchy結(jié)果,這是一個ndarray,其中的元素個數(shù)和輪廓個數(shù)相同,每個輪廓contours[i]對應4個hierarchy元素hierarchy[i][0]~hierarchy[i][3],分別表示后一個輪廓、前一個輪廓、父輪廓、內(nèi)嵌輪廓的索引編號,如果沒有對應項,則該值為負數(shù)。
通過
print (type(hierarchy)) print (hierarchy.ndim) print (hierarchy[0].ndim) print (hierarchy.shape)
得到
3 2 (1, 2, 4)
可以看出,hierarchy本身包含兩個ndarray,每個ndarray對應一個輪廓,每個輪廓有四個屬性。
輪廓的繪制
OpenCV中通過cv2.drawContours在圖像上繪制輪廓。
cv2.drawContours()函數(shù)
cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]])
第一個參數(shù)是指明在哪幅圖像上繪制輪廓;
第二個參數(shù)是輪廓本身,在Python中是一個list。
第三個參數(shù)指定繪制輪廓list中的哪條輪廓,如果是-1,則繪制其中的所有輪廓。后面的參數(shù)很簡單。其中thickness表明輪廓線的寬度,如果是-1(cv2.FILLED),則為填充模式。繪制參數(shù)將在以后獨立詳細介紹。
補充:
寫著寫著發(fā)現(xiàn)一篇文章介紹不完,所以這里先作為入門的。更多關(guān)于輪廓的信息有機會再開一篇文章介紹。
但有朋友提出計算輪廓的極值點??捎孟旅娴姆绞接嬎愕玫剑缦?/p>
pentagram = contours[1] #第二條輪廓是五角星 leftmost = tuple(pentagram[:,0][pentagram[:,:,0].argmin()]) rightmost = tuple(pentagram[:,0][pentagram[:,:,0].argmin()]) cv2.circle(img, leftmost, 2, (0,255,0),3) cv2.circle(img, rightmost, 2, (0,0,255),3)
注意!假設(shè)輪廓有100個點,OpenCV返回的ndarray的維數(shù)是(100,1,2)?。。《皇俏覀冋J為的(100,2)。切記!??!人民郵電出版社出版了一本《NumPy攻略:Python科學計算與數(shù)據(jù)分析》,推薦去看一下。
更新:關(guān)于pentagram[:,0]的意思
在numpy的數(shù)組中,用逗號分隔的是軸的索引。舉個例子,假設(shè)有如下的數(shù)組:
a = np.array([[[3,4]], [[1,2]],[[5,7]],[[3,7]],[[1,8]]])
其shape是(5, 1, 2)。與我們的輪廓是相同的。那么a[:,0]的結(jié)果就是:
[3,4], [1,2], [5,7], [3,7], [1,8]
這里a[:,0]的意思就是a[0:5,0],也就是a[0:5,0:0:2],這三者是等價的。
回頭看一下,a的shape是(5,1,2),表明是三個軸的。在numpy的數(shù)組中,軸的索引是通過逗號分隔的。同時冒號索引“:”表示的是該軸的所有元素。因此a[:,0]表示的是第一個軸的所有元素和第二個軸的第一個元素。在這里既等價于a[0:5,0]。
再者,若給出的索引數(shù)少于數(shù)組中總索引數(shù),則將已給出的索引樹默認按順序指派到軸上。比如a[0:5,0]只給出了兩個軸的索引,則第一個索引就是第一個軸的,第二個索引是第二個軸的,而第三個索引沒有,則默認為[:],即該軸的所有內(nèi)容。因此a[0:5,0]也等價于a[0:5,0:0:2]。
再詳細一點,a的全體內(nèi)容為:[[[3,4]],[[1,2]],[[5,7]],[[3,7]],[[1,8]]]。去掉第一層方括號,其中有五個元素,每個元素為[[3,4]]這樣的,所以第一個索引的范圍為[0:5]。注意OpenCV函數(shù)返回的多維數(shù)組和常見的numpy數(shù)組的不同之處!
觀察[[3,4]],我們發(fā)現(xiàn)其中只有一個元素,即[3,4],第二個索引為[0:1]。
再去掉一層方括號,我們面對的是[3,4],有兩個元素,所以第三個索引的范圍為[0:2]。
再次強調(diào)一下OpenCVPython接口函數(shù)返回的NumPy數(shù)組和普通的NumPy數(shù)組在組織上的不同之處。
PS:OpenCV-Python討論群——219962286,歡迎大家加入互相探討學習。
得到的結(jié)果為如下:
總結(jié)
以上就是本文關(guān)于OpenCV-Python實現(xiàn)輪廓檢測實例分析的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:
python+opencv實現(xiàn)的簡單人臉識別代碼示例
如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
相關(guān)文章
python使用Scrapy庫進行數(shù)據(jù)提取和處理的方法詳解
在我們的初級教程中,我們介紹了如何使用Scrapy創(chuàng)建和運行一個簡單的爬蟲,在這篇文章中,我們將深入了解Scrapy的強大功能,學習如何使用Scrapy提取和處理數(shù)據(jù)2023-09-09python項目報錯:bs4.FeatureNotFound:?Couldn‘t?find?a?tree?bu
這篇文章主要給大家介紹了python項目報錯:bs4.FeatureNotFound:?Couldn‘t?find?a?tree?builder?with?the?features?you?requests的解決方式,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2022-09-09Python的3種運行方式:命令行窗口、Python解釋器、IDLE的實現(xiàn)
這篇文章主要介紹了Python的3種運行方式:命令行窗口、Python解釋器、IDLE的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-10-10Python獲取多進程執(zhí)行的返回值實現(xiàn)
本文主要介紹了Python獲取多進程執(zhí)行的返回值實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-03-03Django在視圖中使用表單并和數(shù)據(jù)庫進行數(shù)據(jù)交互的實現(xiàn)
本文主要介紹了Django在視圖中使用表單并和數(shù)據(jù)庫進行數(shù)據(jù)交互,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07