推文:OpenCV-Python教程(11、輪廓檢測)
輪廓發現
是基於圖像邊緣提取的基礎,尋找對象輪廓的方法,所以邊緣提取的閾值選定會影響最終輪廓的發現
相關API
findContours 發現輪廓
drawContours繪制輪廓
操作步驟
1.轉換圖像為二值化圖像:threshold方法或者canny邊緣提取獲取的都是二值化圖像 2.通過二值化圖像尋找輪廓:findContours 3.描繪輪廓:drawContours
一:使用直接使用閾值方法threshold方法獲取二值化圖像來選擇輪廓
def contours_demo(image): dst = cv.GaussianBlur(image,(9,9),15) #高斯模糊,消除噪聲 gray = cv.cvtColor(dst,cv.COLOR_BGR2GRAY) #先變灰度圖像 ret, binary = cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) #獲取二值圖像 cv.imshow("binary image",binary) # cloneImage,contours,heriachy = cv.findContours(binary,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE) #RETR_TREE包含檢測內部 cloneImage,contours,heriachy = cv.findContours(binary,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) #RETR_EXTERNAL檢測外部輪廓 for i, contour in enumerate(contours): # cv.drawContours(image,contours,i,(0,0,255),2) #繪制輪廓 cv.drawContours(image,contours,i,(0,0,255),-1) #填充輪廓 print(i) cv.imshow("detect contours",image) src = cv.imread("./lk.png") #讀取圖片 cv.namedWindow("input image",cv.WINDOW_AUTOSIZE) #創建GUI窗口,形式為自適應 cv.imshow("input image",src) #通過名字將圖像和窗口聯系 contours_demo(src) cv.waitKey(0) #等待用戶操作,里面等待參數是毫秒,我們填寫0,代表是永遠,等待用戶操作 cv.destroyAllWindows() #銷毀所有窗口
二:使用canny邊緣檢測獲取二值化圖像
def contours_demo(image): binary = edge_demo(image) cloneImage,contours,heriachy = cv.findContours(binary,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE) #RETR_TREE包含檢測內部 for i, contour in enumerate(contours): # cv.drawContours(image,contours,i,(0,0,255),2) cv.drawContours(image,contours,i,(0,0,255),-1) print(i) cv.imshow("detect contours",image) def edge_demo(image): dst = cv.GaussianBlur(image,(3,3),0) gray = cv.cvtColor(dst,cv.COLOR_BGR2GRAY) #先變灰度圖像 edge_output = cv.Canny(gray,50,108) cv.imshow("detect contours",edge_output) return edge_output src = cv.imread("./lk.png") #讀取圖片 cv.namedWindow("input image",cv.WINDOW_AUTOSIZE) #創建GUI窗口,形式為自適應 cv.imshow("input image",src) #通過名字將圖像和窗口聯系 contours_demo(src) cv.waitKey(0) #等待用戶操作,里面等待參數是毫秒,我們填寫0,代表是永遠,等待用戶操作 cv.destroyAllWindows() #銷毀所有窗口
相關知識補充
(一)findContours尋找輪廓
cv.findContours(binary,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)
def findContours(image, mode, method, contours=None, hierarchy=None, offset=None): # real signature unknown; restored from __doc__
1.image:輸入圖像,圖像必須為8-bit單通道圖像,圖像中的非零像素將被視為1,0像素保留其像素值,故加載圖像后會自動轉換為二值圖像。可以通過threshold和canny獲取
2.mode:輪廓檢索模式
RETR_EXTERNAL:表示只檢測最外層輪廓,對所有輪廓設置hierarchy[i][2]=hierarchy[i][3]=-1 RETR_LIST:提取所有輪廓,並放置在list中,檢測的輪廓不建立等級關系 RETR_CCOMP:提取所有輪廓,並將輪廓組織成雙層結構(two-level hierarchy),頂層為連通域的外圍邊界,次層位內層邊界 RETR_TREE:提取所有輪廓並重新建立網狀輪廓結構 RETR_FLOODFILL:官網沒有介紹,應該是洪水填充法
3.method:輪廓近似方法
CHAIN_APPROX_NONE:獲取每個輪廓的每個像素,相鄰的兩個點的像素位置差不超過1
CHAIN_APPROX_SIMPLE:壓縮水平方向,垂直方向,對角線方向的元素,值保留該方向的重點坐標,如果一個矩形輪廓只需4個點來保存輪廓信息
CHAIN_APPROX_TC89_L1和CHAIN_APPROX_TC89_KCOS使用Teh-Chinl鏈逼近算法中的一種
返回值:
ret = cv.findContours(binary, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
cloneImage,contours,heriachy = cv.findContours(binary,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE) #RETR_TREE包含檢測內部
返回一個元組,內部有三個元素 <class 'numpy.ndarray'> <class 'list'> <class 'numpy.ndarray'>
第一個返回值:cloneImage是我們傳入的二值化圖像
第二個返回值:contours是一個列表,是輪廓本身,含有輪廓上面的各個點的位置信息
第三個返回值:heriachy是每條輪廓對應的屬性
(二)drawContours繪制輪廓
cv.drawContours(image,contours,i,(0,0,255),2) cv.drawContours(image,contours,i,(0,0,255),-1)
def drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None): # real signature unknown; restored from __doc__
1.image:輸入輸出圖像,Mat類型即可 2.contours:使用findContours檢測到的輪廓數據,每個輪廓以點向量的形式存儲 3.contourIdx:繪制輪廓的只是變量,如果為負值則繪制所有輸入輪廓 4.color:輪廓顏色 5.thickness:繪制輪廓所用線條粗細度,如果值為負值,則在輪廓內部繪制