一、概述
? ? ? ?輪廓檢測是計算機視覺中的基礎技術,用于識別和提取圖像中物體的邊界。與邊緣檢測不同,輪廓檢測更關注將邊緣像素連接成有意義的整體,形成封閉的邊界。
輪廓檢測的核心價值
- 物體識別:通過輪廓可以識別圖像中的獨立物體
- 形狀分析:輪廓包含了物體的形狀特征信息
- 測量計算:基于輪廓可進行面積、周長等測量
- 圖像分割:是許多分割算法的基礎步驟
二、OpenCV輪廓檢測基礎
1.cv2.findContours
2. cv2.drawContours()

3.示例代碼
#查找輪廓的API:image,contours,hierarchy = cv2.findContours(img, mode, method)#
# 參數:img:需要實現輪廓檢測的原圖# mode:輪廓的檢索模式,主要有四種方式:
# CV2.RETR_EXTERNAL:只檢測外輪廓,所有子輪廓被忽略并
# CV2.RETR_LIST:檢測的輪廓不建立等級關系,所有輪廊屬于同一等級
# CV2.RETR_CCOMP:返回所有的輪廓,只建立兩個級的輪。一個對象的外輪為第1級組織結構。
# 而對象內部中空洞的輪廊為第2級組織結構,空洞中的任何對象的輪又是第 1級組織結構。
# cV2.RETR_TREE:返回所有的輪廓,建立一個完整的組織結構的輪廓。# method:輪廓的近似方法,主要有以下兩種:
# CV2.CHAIN APPROX NONE:在儲所有的輪點。
# CV2.CHAIN_APPROX_SIMPLE:壓縮模式,只保留該方向的終點坐標,例如一個矩形輪廊只需4 個點來保存輪信息。
# 返回:image:返回處理的原圖# contours:包含圖像中所有輪廊的list對象。其中每一個獨立的輪廊信息以邊界點坐標(x,y)的形式儲存在numpy數組中。# hierarchy:輪廊的層次結構。一個包含4個值的數組:[Next,Previous,First child, Parent]
# Next:與當前輪廓處于同一層級的下一條輪
# Previous:與當前輪廓處于同一層級的上一條輪
# First child:當前輪廓的第一條子輪康
# Parent:當前輪廓的父輪廓并
# 注意:做輪廊檢測前需要將圖片讀取為二值數據,即像素值只為0和255.import cv2
phone = cv2.imread('phone.png')
phone_grey=cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
cv2.imshow('phone_b',phone_grey)
cv2.waitKey(0)ret,phone_binary=cv2.threshold(phone_grey,120,255,cv2.THRESH_BINARY)
cv2.imshow('phone_binary',phone_binary)
cv2.waitKey(0)_,contours,hierarchy = cv2.findContours(phone_binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)# # 輪廓的繪制
# # cv2.drawContours(image, contours, contourIdx, color, thickness=None,
# # lineType=None, hierarchy=None, maxLevel=None, offset=None)
# # 參數含義如下:
# # image:要在其上繪制輪廓的輸入圖像。
# # contours:輪廓列表,通常由cv2.findContours()函數返回。
# # contourIdx:要繪制的輪廓的索引。如果為負數,則繪制所有輪廓。 -1
# # color:輪廓的顏色,以BGR格式表示。例如,(0, 255, 0)表示綠色。
# # thickness:輪廓線的粗細。默認值為1。
# # lineType:輪廓線的類型。默認值為cv2.LINE_8。
# # hierarchy:輪廓層次結構。通常由cv2.findContours()函數返回。
# # maxLevel:繪制的最大輪廓層級。默認值為None,表示繪制所有層級。
# # offset:輪廓點的偏移量。默認值為None。
image_copy=phone.copy()
image_copy=cv2.drawContours(image=image_copy,contours=contours,contourIdx=-1,color=(0,255,0),thickness=2)
cv2.imshow('Contours',image_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()
?三、輪廓特征提取與分析
1. 基本特征計算
面積
??
周長
?
import cv2phone = cv2.imread('phone.png')
phone_grey=cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)
cv2.imshow('phone_b',phone_grey)
cv2.waitKey(0)ret,phone_binary=cv2.threshold(phone_grey,120,255,cv2.THRESH_BINARY)
cv2.imshow('phone_binary',phone_binary)
cv2.waitKey(0)_,contours,hierarchy = cv2.findContours(phone_binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)# #輪廓特征
# cv2.contourArea(contour[, oriented]) → retval 面積
# contour:頂點構成的二維向量組(如輪廓列表contours中的一個輪廓)
# oriented:定向區域標志,默認值為 False,返回面積的絕對值,Ture 時則根據輪廓方向返回帶符號的數值area_0 = cv2.contourArea(contours[0])
print(area_0)
area_1 = cv2.contourArea(contours[1])
print(area_1)# arcLength(InputArray curve, bool closed) 周長
# curve,輸入的二維點集(輪廓頂點),可以是 vector 或 Mat 類型。
# closed,用于指示曲線是否封閉。
length = cv2.arcLength(contours[0],closed=True)
print(length)
# 根據面積顯示特定輪廓
a_list=[]
# for i in range(len(contours)):
# if cv2.contourArea(contours[i])>10000:
# a_list.append(contours[i])
for i in contours:if cv2.contourArea(i)>10000:a_list.append(i)
image_copy = phone.copy()
image_copy = cv2.drawContours(image=image_copy, contours=a_list, contourIdx=-1,color=(0,255,0),thickness=3)
cv2.imshow('Contours_show_10000', image_copy)
cv2.waitKey(0)
2. 輪廓近似
# 輪廓的近似
# approx = cv2.approxPolyDP(curve, epsilon, closed)
# 參數說明:
# curve:輸入輪廓。
# epsilon:近似精度,即兩個輪廓之間最大的歐式距離。該參數越小,得到的近似結果越接近實際輪廓;反之,得到的近似結果會更加粗略。
# closed:布爾類型的參數,表示是否封閉輪廓。如果是 True,表示輸入輪廓是封閉的,近似結果也會是封閉的;否則表示輸入輪廓不是封閉的,近似結果也不會是封閉的。
# 返回值:approx:近似結果,是一個ndarray數組,為1個近似后的輪廓,包含了被近似出來的輪廓上的點的坐標
import cv2phone = cv2.imread('phone.png')
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY) #轉換為灰度圖
ret,phone_thresh = cv2.threshold(phone_gray,120,255,cv2.THRESH_BINARY) #二值化image, contours, hierarchy = cv2.findContours(phone_thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)#獲取輪廓
# #計算所有輪廓面積并存儲在列表中
contours_with_area=[(cnt,cv2.contourArea(cnt)) for cnt in contours]
#根據輪廓面積降序排列
sorted_contours=sorted(contours_with_area,key=lambda x:x[1],reverse=True)
#如果你只需要降序后的輪廓,可以直接提取出來
aa=sorted_contours[0][0]
print(aa)epsilon = 0.01 * cv2.arcLength(aa,True) #設置近似精度
approx = cv2.approxPolyDP(aa, epsilon, True) #對輪廓進行近似
print(approx.shape)
phone_new = phone.copy()
image_contours = cv2.drawContours(phone_new,[approx],contourIdx=-1,color=(0,255,0),thickness=3)#繪制輪廓
cv2.imshow('phone',phone)
cv2.waitKey(0)
cv2.imshow('image_contours',image_contours)
cv2.waitKey(0)
# # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
# # 外接圓、外接矩形,...
cnt = contours[6]
(x,y),r = cv2.minEnclosingCircle(cnt)#計算輪廓的外接圓
phone_circle = cv2.circle(phone,(int(x),int(y)),int(r),(0,255,0),2)#繪制外接圓的方法
cv2.imshow('phone_circle',phone_circle)
cv2.waitKey(0)x,y,w,h = cv2.boundingRect(cnt)#計算輪廓的最小外接矩形
phone_rectangle = cv2.rectangle(phone,(x,y),(x+w,y+h),(0,255,0),2) #在圖像上繪制矩形
cv2.imshow('phone_rectangle',phone_rectangle)
cv2.waitKey(0)
3. 輪廓匹配
# 形狀匹配(值越小匹配越好)
match_value = cv2.matchShapes(cnt1, cnt2, cv2.CONTOURS_MATCH_I1, 0)# 模板匹配
template = cv2.imread('template.png',0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where(res >= threshold)
總結
? ? ? ?OpenCV的輪廓檢測功能強大而靈活,從簡單的物體識別到復雜的形狀分析都能勝任。掌握輪廓檢測技術需要注意以下幾點:
1. 良好的預處理是成功的關鍵
2. 根據應用場景選擇合適的輪廓檢索模式
3. 合理利用輪廓特征進行篩選和分析
4. 高級應用常需要結合其他圖像處理技術