opencv 圖像輪廓的實現示例
圖像輪廓
Contours:輪廓
輪廓是將沒有連著一起的邊緣連著一起。
邊緣檢測檢測出邊緣,邊緣有些未連接在一起。
注意問題
1.對象為二值圖像,首先進行閾值分割或者邊緣檢測。
2.查找輪廓需要更改原始圖像,通常使用原始圖像的一份進行拷貝。
3.在opencv里,是從黑色背景里找白色。因此對象必須是白色,背景為黑色。
方法
- cv2.findContours()
- cv2.drawContours()
通過cv2.findContours() 查找輪廓在哪里,再通過 cv2.drawContours()將查找的輪廓繪制出來。
contours,hierarchy=cv2.findContours(image,mode,method)
contours:輪廓
hierarchy:圖像的拓撲信息(輪廓層次)(存儲上一個輪廓,父輪廓…)
image:原始圖像
mode:輪廓檢索方式
method:輪廓的近似方法
r=cv2.drawContours(image, contours, contourIdx, color[, thickness])
r:目標圖像
image:原始圖像
contours: 所有的輸入輪廓邊緣數組
contourIdx :需要繪制的邊緣索引,如果全部繪制為-1。如果有多個目標,可以繪制第一個目標0,第二個目標1,第三個目標2.。。
color:繪制的顏色,為BGR格式的SCalar
thickness:可選,繪制的密度,即輪廓的畫筆粗細
import cv2 import numpy as np o = cv2.imread('lena256.bmp') gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)#BGR-灰度 ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#二值圖像 contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) co=o.copy()#對原始圖像進行繪制 r=cv2.drawContours(co,contours,-1,(0,127,127),4)#co為復制圖像,輪廓會修改原始圖像 cv2.imshow("original",o) cv2.imshow("contours",r) cv2.waitKey()
cv2.cvtColor(input_image, flag)用于顏色空間轉換。
input_image:需要轉換的圖像
flag:轉換類型
cv2.COLOR_BGR2GRAY : BGR -灰度
cv2.COLOR_BGR2RGB:BGR-RGB
cv2.COLOR_BGR2HSV:BGR-HSV
最小外接圓
函數cv2.minEnclosingCircle() 可以幫我們找到一個對象的外切圓。它是所有能夠包括對象的圓中面積最小的一個。
案例:現有下面這樣一張圖片,要求將圖片中心的花朵標記出來。
代碼:
import numpy as np import cv2 as cv img=cv.imread("image.jpg",0) #為了顯示方便,這里將圖片進行縮放 x,y=img.shape img=cv.resize(img,(y//2,x//2)) #將圖片二值化,由于前景物體是黑色的,因此在二值化時采用cv.THRESH_TOZERO_INV這種方式 ret,thresh=cv.threshold(img,127,255,cv.THRESH_TOZERO_INV) #尋找圖片中的輪廓,mode=cv.RETR_EXTERNAL,這是為了尋找最外層的輪廓 im,contour,hierarchy=cv.findContours(thresh,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) #cv.minEnclosingCircle函數的參數要求是ndarray類型,因此這里將找到的 # 輪廓中的所有的點存放在一個列表中,然后使用這個列表創(chuàng)建數組 point_list=[] for i in contour: for j in i: point_list.append(j[0]) point_array=np.array(point_list) #使用最小外接圓函數,返回值為這個圓的圓心坐標和圓半徑長度 (x,y),radius=cv.minEnclosingCircle(point_array) #圖片上的坐標均為整數,圓的半徑也要求是整數,因此將它們強制轉換為int類型 center=(int(x),int(y)) color=cv.cvtColor(img,cv.COLOR_GRAY2BGR) color=cv.circle(color,center,radius=int(radius),color=(0,0,255),thickness=2) #顯示圖片 cv.imshow("color",color) cv.waitKey(0) cv.destroyAllWindows()
程序結果:
凸包
凸包與輪廓近似相似,但不同,雖然有些情況下它們給出的結果是一樣的。函數cv2.convexHull() 可以用來檢測一個曲線是否具有凸性缺陷,并能糾正缺陷。一般來說,凸性曲線總是凸出來的,至少是平的。在opencv中使用函數cv.convexhull來尋找輪廓的凸包,該函數的定義為:
hull=cv.convexHull( points[, hull[, clockwise[, returnPoints]]])
這個函數的參數如下:
Points:我們需要傳入的輪廓
Hull:輸出,通常不需要
clockwise: 取向標志,如果為True,凸包的方向是順時針方向,否則為逆時針方向;
returnPoints: 默認為True. 它會返回凸包上點的坐標。如果設置為False,就會返回與凸包點對應的輪廓上的點。
還是上面的這副圖片,我們對上面的代碼稍加修改,可以得到凸包的形狀,代碼如下:
import numpy as np import cv2 as cv img=cv.imread("image.jpg",0) #為了顯示方便,這里將圖片進行縮放 x,y=img.shape img=cv.resize(img,(y//2,x//2)) #將圖片二值化,由于前景物體是黑色的,因此在二值化時采用cv.THRESH_TOZERO_INV這種方式 ret,thresh=cv.threshold(img,127,255,cv.THRESH_TOZERO_INV) #尋找圖片中的輪廓,mode=cv.RETR_EXTERNAL,這是為了尋找最外層的輪廓 im,contour,hierarchy=cv.findContours(thresh,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) #cv.minEnclosingCircle函數的參數要求是ndarray類型,因此這里將找到的 # 輪廓中的所有的點存放在一個列表中,然后使用這個列表創(chuàng)建數組 point_list=[] for i in contour: for j in i: point_list.append(j[0]) point_array=np.array(point_list) #尋找凸包,返回值是凸包上的點 hull=cv.convexHull(point_array,returnPoints=True) color=cv.cvtColor(img,cv.COLOR_GRAY2BGR) #將凸包繪制出來,需要注意的是:這里需要將凸包上點的坐標寫成一個 #列表傳入函數cv.ploylines,否則繪制出來的只是凸包上的一系列點 color=cv.polylines(color,[hull],True,(0,0,255),2) #顯示圖片 cv.imshow("color",color) cv.waitKey(0) cv.destroyAllWindows()
程序運行結果為:
圖像掩模和像素點
有時我們需要構成對象的所有像素點,我們可以將圖像的所有輪廓提取出來,然后使用函數cv.drawContours()將輪廓內的區(qū)域填充為指定的顏色。然后使用cv.findNonZeros()函數將非零像素點的坐標提取出來,這樣就得到了構成對象的像素點。我們還是在上面的圖片上進行操作,代碼如下:
import numpy as np import cv2 as cv img=cv.imread("image.jpg",0) #為了顯示方便,這里將圖片進行縮放 x,y=img.shape img=cv.resize(img,(y//2,x//2)) #將圖片二值化,由于前景物體是黑色的,因此在二值化時采用cv.THRESH_TOZERO_INV這種方式 ret,thresh=cv.threshold(img,127,255,cv.THRESH_TOZERO_INV) #尋找圖片中的輪廓,mode=cv.RETR_EXTERNAL,這是為了尋找最外層的輪廓 im,contour,hierarchy=cv.findContours(thresh,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) #創(chuàng)建一個填充輪廓內像素點的畫板,背景顏色為黑色,這里我們使用numpy創(chuàng)建一個全零的二維數組 mask=np.zeros(img.shape,dtype=np.uint8) #將參數thickness設置為-1,這樣cv.drawContours函數就會將輪廓內的像素點填充為指定的顏色 mask=cv.drawContours(mask,contour,contourIdx=-1,color=(255,255,255),thickness=-1) #尋找mask內非零像素點,將其存放為一個numpy數組 NonZeroPoints=np.array(cv.findNonZero(mask)) #形狀變換,將其改變?yōu)橐粋€二維數組,數組的每一行存放一個非零像素點的坐標 NonZeroPoints=NonZeroPoints.reshape((-1,2)) #驗證我們提取出來的像素點坐標是否正確,我們使用變量 #column和row分別存放非零像素點在圖像中坐標的列數和行數 column=NonZeroPoints[:,0] row=NonZeroPoints[:,1] #在新的畫板上將這些點繪制出來,將這些坐標對應的像素點的值設為255 mask1=np.zeros(img.shape) mask1[row,column]=255 #顯示結果 cv.imshow("mask",mask) cv.imshow("mask1",mask1) cv.waitKey(0) cv.destroyAllWindows()
程序運行結果:
通過上面兩幅圖的對比結果,我們可以看到:對象的組成像素點被正確地提取出來了。
到此這篇關于opencv 圖像輪廓的實現示例的文章就介紹到這了,更多相關opencv 圖像輪廓內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
python中threading和queue庫實現多線程編程
這篇文章主要介紹了python中threading和queue庫實現多線程編程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-02-02