【opencv】(6) 图像轮廓处理
各位同學好,今天和大家分享一下opencv中如何獲取圖像輪廓,以及對輪廓的一些其他操作。內容有:
(1)輪廓檢測:cv2.findContours();(2)輪廓繪制:cv2.drawContours();(3)輪廓近似:cv2.approxPolyDP();(4)面積計算:cv2.contourArea();(5)周長計算:cv2.arcLength();(6)外接矩形:cv2.rectangle();(7)外接圓:cv2.circle()
在開始前,先導入需要用到的庫文件以及圖像數據,定義一個圖像顯示函數,方便后續繪圖。
import cv2
import numpy as np
# 獲取圖片所在文件夾
filepath = 'C:\\...\\opencv\\img'
# 獲取文件夾中的某一張圖片
img = cv2.imread(filepath+'\\test2.png')
# 定義繪圖函數
def cv_show(name,img):# 傳入自定義圖像名,即圖像變量cv2.imshow(name,img) # 圖片不會自動消失cv2.waitKey(0)# 手動關閉窗口cv2.destroyWindow()
1. 圖像輪廓
1.1 獲取圖像輪廓
方法: contours, hierarchy =?cv2.findContours(img, mode, method)
參數:
img:輸入的圖像,最好是二值圖
mode:輪廓檢索模式,如下
RETR_EXTERNAL:只檢索最外面的輪廓
RETR_LIST:檢索所有的輪廓,并將其保存到一條鏈表中
RETR_CCOMP:檢索所有的輪廓,并將它們組織為兩層:頂層是各部分的外部邊界,第二層是空洞的邊界
RETR_TREE:常用,檢索所有的輪廓,并重構嵌套輪廓的整個層次。保存了所有的輪廓,用哪個調用哪個
method:輪廓逼近方法,如下
CHAIN_APPROX_NONE:以Freeman鏈碼的方式輸出輪廓,所有其他方法輸出多邊形(頂點的序列)。正常畫出所有輪廓
CHAIN_APPROX_SIMPLE:壓縮水平的、垂直的、斜的部分,即函數只保留他們的終點坐標。壓縮得到更精簡的結果,例如一個矩形輪廓只需4個點來保存輪廓信息
返回值:
contours:列表,保存輪廓信息。每一個元素都是圖像的輪廓
hierarchy:數組,分層保存輪廓信息。元素數和輪廓數一致
1.2 繪制圖像輪廓
方法: cv2.drawContours(img, contours, contourIdx, color, thickness)
參數:
img:指明在哪幅圖像上繪制輪廓;image為三通道才能顯示輪廓
contours:圖像輪廓信息,列表形式
contours:指定繪制輪廓列表中的哪條輪廓。如果是-1,則繪制其中的所有輪廓。
color:代表繪制輪廓的線條顏色,根據BGR調整,若為(0,0,255)則為紅色。
thickness:線條粗細
1.3 代碼演示
首先將讀入的圖像變成灰度圖cv2.cvtColor(),再使用圖像閾值處理方法將灰度圖轉換成二值圖cv2.threshold(),像素值超過閾值127的變成255,低于127的像素值變成0,實現二值化。將二值化處理后的圖像thresh傳入輪廓檢測函數。圖像閾值處理方法見下文第4節:【opencv】(2) 圖像處理:邊界填充、圖像融合、圖像閾值、數值計算
#(1)圖像處理
# 將讀入的圖像變成灰度圖
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 圖像數值超過127取255,小于127的變成0
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
# ret接收閾值,thresh接收處理后的圖像
#(2)輪廓檢測
# 輸入圖像最好是二值圖
contours,hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 返回值:contours輪廓信息;hierarchy層級,把結果保存在一個層級中
#(3)繪制輪廓
# 注意要將原圖(彩色圖)復制一份,不然原圖會在函數處理完之后改變
draw = img.copy() #draw改變不會導致img改變
# 在draw畫板上繪制輪廓;畫第幾個輪廓,-1代表所有輪廓;BGR分別對應(0,0,255),用紅色線畫輪廓;線條寬2
res = cv2.drawContours(draw, contours,-1, (0, 0, 255), 2)
# 展示圖像
cv_show('res',res)
第1張為原始圖像,第2張為contourIdx=-1時繪制輪廓后的圖像 ,第3張為contourIdx=3時繪制的輪廓。contourIdx中保存了所有的輪廓信息。
???
?2. 輪廓特征
2.1 輪廓計算
輪廓計算有非常多種方法,這里只介紹兩個,計算輪廓周長和面積。
在圖像輪廓獲取函數中cv2.findContours(),我們獲取了輪廓信息返回值contours,在計算時,不能將輪廓全部放進去計算,計算時需要選出其中一個。下面使用輪廓信息中的第0個輪廓計算它的面積和周長。
# 獲取某一個輪廓用于計算
cnt = contours[0]
# ==1== 面積
cv2.contourArea(cnt) # 8500.5
# ==2== 周長
cv2.arcLength(cnt,True) # 437.948
2.2 輪廓近似
方法: cv2.approxPolyDP(curve, epsilon, closed)
參數:
curve: 需要進行近似的輪廓
epsilon: 判斷點到相對應的線段的距離的閾值,這是原始曲線與其近似值之間的最大距離。閾值越小,折線的形狀越接近曲線。
closed: 若為true,曲線第一個點與最后一個點連接形成閉合曲線,若為false,曲線不閉合。
下面使用的閾值是cv2.arcLength(cnt,True),即輪廓的周長。取輪廓周長的0.1倍來作為contours[0]輪廓的近似。
# 獲取圖像
img = cv2.imread(filepath+'\\test1.png') # 獲取一張圖像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 灰度圖
ret,thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 二值化
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) # 輪廓提取
cnt = contours[0] # 獲取其中一層輪廓
draw = img.copy() # 繪制輪廓
res = cv2.drawContours(draw, [cnt], -1, (0,0,255), 2) # 在draw圖像中繪制cnt輪廓
cv_show('res',res) # 繪圖
# 輪廓近似
epsilon = 0.1*cv2.arcLength(cnt,True) # 以周長的百分比作為閾值,指定的越小,得到的輪廓和原來的區別較小
approx = cv2.approxPolyDP(cnt, epsilon, True) # 近似函數,cnt為輪廓,epsilon閾值。返回近似后的輪廓
# 繪圖展示
draw = img.copy()
res = cv2.drawContours(draw, [approx], -1, (255,0,0), 2) # 將近似后的輪廓approx畫在原圖上,用藍色表示,線條粗2
cv_show('res',res)
第一張圖為圖像輪廓,第二張圖為輪廓近似后的結果
? ?
2.3 輪廓的外接矩形
首先在輪廓提取函數的返回值contours中,選取一個輪廓信息用于求它的外接矩形。
計算輪廓的垂直邊界最小矩形,矩形是與圖像上下邊界平行的
x, y, w, h = cv2.boundingRect(輪廓信息)
返回四個值。x,y是矩陣左上點的坐標;w,h是矩陣的寬和高。
外接矩形繪制函數
cv2.rectangle(img, pt1, pt2, color, thickness)
參數:
img:?原始圖片作為畫板
pt1: 長方形框左上角坐標 (x, y)
pt2: 長方形框右下角坐標 (x+w, y+h)
color: 線條顏色(B, G, R)
thickness: 線條粗細
在圖片img上畫長方形,坐標原點是圖片左上角,向右為x軸正方向,向下為y軸正方向。
?
# 獲取輪廓信息
img = cv2.imread(filepath+'\\test1.png') # 讀取圖像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 灰度處理
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) # 二值化處理
contours,hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) # 獲取輪廓信息
cnt = contours[0] # 指定某一層輪廓
# 輪廓的外接矩形
x,y,w,h = cv2.boundingRect(cnt) # 計算外接矩形,返回矩形的左上坐標點,和一長一寬
rectangle = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2) # 根據坐標繪制矩形,綠色線條
cv_show('rectangle',rectangle)
得到矩形的寬和高,接下來就可以計算輪廓面積和外接矩形面積的比值。
area = cv2.contourArea(cnt) # 輪廓面積計算函數
x,y,w,h = cv2.boundingRect(cnt) # 獲取坐標點和邊長
rect_area = w*h # 計算外接矩形面積
extent = area/rect_area # 計算比值
print('輪廓面積和外接矩形面積之比:',extent)
2.4 輪廓的外接圓
獲取輪廓的圓心坐標和半徑
(x,y), radius = cv2.minEnclosingCircle(輪廓信息)
輪廓外接圓函數
cv2.circle(img, center, radius, color, thickness, shift)
img:?輸入的圖片作為畫板
center:?圓心位置
radius: 圓的半徑
color: 圓的顏色
thickness: 正數表示圓形輪廓的粗細。負數表示要繪制實心圓。
shift:?圓心坐標點和半徑值的小數點位數
# 輪廓外接圓
# 返回圓心坐標和半徑
(x,y),radius = cv2.minEnclosingCircle(cnt)
# 圓心坐標
center = (int(x),int(y))
# 半徑
radius = int(radius)
# 繪制外接圓,輸入整型
circle = cv2.circle(img,center,radius,(255,0,0),2)
cv_show('circle',circle)
總結
以上是生活随笔為你收集整理的【opencv】(6) 图像轮廓处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【opencv】(4) 形态学处理:腐蚀
- 下一篇: 【opencv】(7) 图像匹配、直方图