《OpenCV》☞ Contours

1.Start

          Contours可被認爲是一條連續點點點(這些點具有相同的顏色或亮度)沿邊界相連的曲線。Contours對與形狀分析和目標的檢測、識別是一種有用的工具。

(1)爲了更好的準確性,使用二值圖像,尋找Contours之前,先應用閾值化或Canny邊緣檢測

(2)OpenCV中,找Contours就像從黑色背景中找到白色前景對象,so尋找的目標應當是白色,背景是黑色

# 找Contours
cv2.findContours(src,retrieval mode,approximation method)


# 描繪Contours,能夠畫出任何形狀
cv2.drawContours(src, contours, contour_index, color, thickness)

#Contours存儲形狀邊界的(x,y)座標

Contour近似法:輪廓是一個形狀的邊界,具有相同的亮度或顏色。它存儲形狀邊界的(x,y)座標。但它並非存儲boundary所有的座標,存儲哪些座標是由輪廓近似法規定的。cv2.CHAIN_APPROX_NONE,存儲所有邊界點;如找到一條直線輪廓。並不需要直線上所有點來表示這條直線,只需要兩個端點便可。cv2.CHAIN_APPROX_SIMPLE ,刪除所有冗餘點進行壓縮,節省內存。

2.Contours特徵

(1)找出輪廓的不同特徵,如面積、周長、質心、邊界框等

# 此函數給出計算出的所有moment值的一個字典
M = cv2.moments(counter)

'''
Centroid:
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])

'''
# 計算Contour面積
area = cv2.contourArea(cnt)

# 計算Contour周長
perimeter = cv2.arcLength(contour,isClosed)

# Contour近似
cv2.approxPolyDP(cnt,epsilon,isClosed)

# 檢查一條曲線是否凸性的,返回True或False
k = cv2.isContourConvex(cnt)

# 凸殼檢測,檢查曲線是否存在凸性缺陷,並對其進行糾正
hull = cv2.convexHull(points[, hull[, clockwise[, returnPoints]]
'''
points是傳入的Contour
hull是輸出,通常省略
clock-wise:方向flag,True時輸出的hull爲順時針方向,False時爲逆時針
returnPoints:默認True,返回hull point的座標,False時返回hall point索引
如:returnPoints=True時獲得[[[234 202]], [[ 51 202]], [[ 51 79]], [[234 79]]]
    returnPoints=False獲得[[129],[ 67],[ 0],[142]].
    而cnt[129] = [[234, 202]]
'''

# 找到Contour的矩形邊框
'''
a.正Bounding Rectangle,不考慮Contour目標的旋轉,該矩形框面積將不是最小矩形
x,y 表示矩形框的左上角座標,w,h是寬高
'''
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

'''
考慮旋轉狀態,此時的矩形框面積最小,返回一個Box2D結構,包含(x,y,w,h,angle of rotation)
描繪出該矩形框時需要獲得四點cv2.boxPoints()
'''
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
im = cv2.drawContours(im,[box],0,(0,0,255),2)

# 找到包圍Contour的最小閉環邊框
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img,center,radius,(0,255,0),2)

# 找到包圍Contour的內接橢圓邊框
ellipse = cv2.fitEllipse(cnt)
im = cv2.ellipse(im,ellipse,(0,255,0),2)

# 擬合一條直線
rows,cols = img.shape[:2]
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
img = cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)

3.Contour Properties

(1)目標Contour矩形框的寬高比

x,y,w,h = cv2.boundingRect(cnt)
aspect_ratio = float(w)/h

(2)輪廓面積與矩形包圍狂面積比

area = cv2.contourArea(cnt)
x,y,w,h = cv2.boundingRect(cnt)
rect_area = w*h
extent = float(area)/rect_area

(3)Contour面積與凸殼面積之比

area = cv2.contourArea(cnt)
hull = cv2.convexHull(cnt)
hull_area = cv2.contourArea(hull)
solidity = float(area)/hull_area

(4)等效直徑是面積與Contour面積相等的圓的直徑。

area = cv2.contourArea(cnt)
equi_diameter = np.sqrt(4*area/np.pi)

(5)物體所指向的角度,以下方法也給出了主軸和副主軸的長度。

(x,y),(MA,ma),angle = cv2.fitEllipse(cnt)

(6)掩碼和像素點

mask = np.zeros(imgray.shape,np.uint8)
cv2.drawContours(mask,[cnt],0,255,-1)
pixelpoints = np.transpose(np.nonzero(mask))
#pixelpoints = cv2.findNonZero(mask)

(7)最大值、最小值及其位置

min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray,mask = mask)

(8)尋找一個目標的平均color或grayscale模式下的平均intensity

mean_val = cv2.mean(im,mask = mask)

(9)極值點,指object的最上、最下、最右、最左的點。

leftmost = tuple(cnt[cnt[:,:,0].argmin()][0])
rightmost = tuple(cnt[cnt[:,:,0].argmax()][0])
topmost = tuple(cnt[cnt[:,:,1].argmin()][0])
bottommost = tuple(cnt[cnt[:,:,1].argmax()][0])

(10)計算凸性缺陷,目標與凸殼的任何偏差都被當作是一種凸性缺陷

# 爲找到凸性缺陷時,在尋找凸殼時將returnPoints設爲False
hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)

# 返回一個數組,每行分別包含--
[start point,end point, farthest point, 
approximate distance to father point]

import cv2
import numpy as np
img = cv2.imread('star.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 127, 255,0)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt = contours[0]
hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)
for i in range(defects.shape[0]):
s,e,f,d = defects[i,0]
start = tuple(cnt[s][0])
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])
cv2.line(img,start,end,[0,255,0],2)
cv2.circle(img,far,5,[0,0,255],-1)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

(11)多邊形點測試,尋找圖像中任一點到一個Contour的最短距離。point位於Contour外時返回值爲負,內時爲正,位於Contour上一點爲0。如下計算點(50,50)到Contour的距離

dist = cv2.pointPolygonTest(cnt,(50,50),True)
# 第三個參數爲measureDist
# measureDist爲True時,求距離,爲False時,求該點是否在contour內部(此時返回+1,-1, 0)
# 若不需要距離時,將measureDist設爲False,節省運行時間

(12)形狀匹配,cv2.matchShapes() -- 比較兩個形狀或兩個contours並且返回一個相似性度量值,值越小,表示兩形狀越相像。該計算基於hu-moment值。hu-moment是平移、旋轉和尺度不變的七個矩,第七個是斜不變的。可以使用cv2.HuMoments()函數找到這些值。

import cv2
import numpy as np
img1 = cv2.imread('star.jpg',0)
img2 = cv2.imread('star2.jpg',0)
ret, thresh = cv2.threshold(img1, 127, 255,0)
ret, thresh2 = cv2.threshold(img2, 127, 255,0)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt1 = contours[0]
contours,hierarchy = cv2.findContours(thresh2,2,1)
cnt2 = contours[0]
ret = cv2.matchShapes(cnt1,cnt2,1,0.0)
print ret

'''
結果:
• Matching Image A with itself = 0.0
• Matching Image A with Image B = 0.001946
• Matching Image A with Image C = 0.326911
'''

4.Contour中的層次結構,即親子關係

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章