opencv 圖像輪廓的實現(xiàn)示例
圖像輪廓
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: 所有的輸入輪廓邊緣數(shù)組
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為復(fù)制圖像,輪廓會修改原始圖像 cv2.imshow("original",o) cv2.imshow("contours",r) cv2.waitKey()
cv2.cvtColor(input_image, flag)用于顏色空間轉(zhuǎn)換。
input_image:需要轉(zhuǎn)換的圖像
flag:轉(zhuǎn)換類型
cv2.COLOR_BGR2GRAY : BGR -灰度
cv2.COLOR_BGR2RGB:BGR-RGB
cv2.COLOR_BGR2HSV:BGR-HSV
最小外接圓
函數(shù)cv2.minEnclosingCircle() 可以幫我們找到一個對象的外切圓。它是所有能夠包括對象的圓中面積最小的一個。
案例:現(xiàn)有下面這樣一張圖片,要求將圖片中心的花朵標記出來。
代碼:
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函數(shù)的參數(shù)要求是ndarray類型,因此這里將找到的 # 輪廓中的所有的點存放在一個列表中,然后使用這個列表創(chuàng)建數(shù)組 point_list=[] for i in contour: for j in i: point_list.append(j[0]) point_array=np.array(point_list) #使用最小外接圓函數(shù),返回值為這個圓的圓心坐標和圓半徑長度 (x,y),radius=cv.minEnclosingCircle(point_array) #圖片上的坐標均為整數(shù),圓的半徑也要求是整數(shù),因此將它們強制轉(zhuǎn)換為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()
程序結(jié)果:
凸包
凸包與輪廓近似相似,但不同,雖然有些情況下它們給出的結(jié)果是一樣的。函數(shù)cv2.convexHull() 可以用來檢測一個曲線是否具有凸性缺陷,并能糾正缺陷。一般來說,凸性曲線總是凸出來的,至少是平的。在opencv中使用函數(shù)cv.convexhull來尋找輪廓的凸包,該函數(shù)的定義為:
hull=cv.convexHull( points[, hull[, clockwise[, returnPoints]]])
這個函數(shù)的參數(shù)如下:
Points:我們需要傳入的輪廓
Hull:輸出,通常不需要
clockwise: 取向標志,如果為True,凸包的方向是順時針方向,否則為逆時針方向;
returnPoints: 默認為True. 它會返回凸包上點的坐標。如果設(shè)置為False,就會返回與凸包點對應(yīng)的輪廓上的點。
還是上面的這副圖片,我們對上面的代碼稍加修改,可以得到凸包的形狀,代碼如下:
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函數(shù)的參數(shù)要求是ndarray類型,因此這里將找到的 # 輪廓中的所有的點存放在一個列表中,然后使用這個列表創(chuàng)建數(shù)組 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) #將凸包繪制出來,需要注意的是:這里需要將凸包上點的坐標寫成一個 #列表傳入函數(shù)cv.ploylines,否則繪制出來的只是凸包上的一系列點 color=cv.polylines(color,[hull],True,(0,0,255),2) #顯示圖片 cv.imshow("color",color) cv.waitKey(0) cv.destroyAllWindows()
程序運行結(jié)果為:
圖像掩模和像素點
有時我們需要構(gòu)成對象的所有像素點,我們可以將圖像的所有輪廓提取出來,然后使用函數(shù)cv.drawContours()將輪廓內(nèi)的區(qū)域填充為指定的顏色。然后使用cv.findNonZeros()函數(shù)將非零像素點的坐標提取出來,這樣就得到了構(gòu)成對象的像素點。我們還是在上面的圖片上進行操作,代碼如下:
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)建一個填充輪廓內(nèi)像素點的畫板,背景顏色為黑色,這里我們使用numpy創(chuàng)建一個全零的二維數(shù)組 mask=np.zeros(img.shape,dtype=np.uint8) #將參數(shù)thickness設(shè)置為-1,這樣cv.drawContours函數(shù)就會將輪廓內(nèi)的像素點填充為指定的顏色 mask=cv.drawContours(mask,contour,contourIdx=-1,color=(255,255,255),thickness=-1) #尋找mask內(nèi)非零像素點,將其存放為一個numpy數(shù)組 NonZeroPoints=np.array(cv.findNonZero(mask)) #形狀變換,將其改變?yōu)橐粋€二維數(shù)組,數(shù)組的每一行存放一個非零像素點的坐標 NonZeroPoints=NonZeroPoints.reshape((-1,2)) #驗證我們提取出來的像素點坐標是否正確,我們使用變量 #column和row分別存放非零像素點在圖像中坐標的列數(shù)和行數(shù) column=NonZeroPoints[:,0] row=NonZeroPoints[:,1] #在新的畫板上將這些點繪制出來,將這些坐標對應(yīng)的像素點的值設(shè)為255 mask1=np.zeros(img.shape) mask1[row,column]=255 #顯示結(jié)果 cv.imshow("mask",mask) cv.imshow("mask1",mask1) cv.waitKey(0) cv.destroyAllWindows()
程序運行結(jié)果:
通過上面兩幅圖的對比結(jié)果,我們可以看到:對象的組成像素點被正確地提取出來了。
到此這篇關(guān)于opencv 圖像輪廓的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)opencv 圖像輪廓內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python中threading和queue庫實現(xiàn)多線程編程
這篇文章主要介紹了python中threading和queue庫實現(xiàn)多線程編程,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02Python高階函數(shù)與裝飾器函數(shù)的深入講解
這篇文章主要給大家介紹了關(guān)于Python高階函數(shù)與裝飾器函數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11