< Contour Properties >
여기서는 고체성(Solidity), 등가 지름(Equivalent Diameter), 마스크 이미지, 평균 강도등과 같이 자주 사용되는 물체의 특성을 추출하는 방법을 배울 것이다. 자세한 내용은 Matlab regionprops문서에서 확인할 수 있다. Matlab regionprops documentation.
1. Aspect Ratio
이 비율은 객체의 bounding rect의 높이에 대한 폭의 비율이다.
x,y,w,h = cv2.boundRect(cnt)
aspect_ratio = float(w)/h
2. Extent
Extent는 bounding rec 영역에 대한 contour 영역의 비율이다.
area = cv2.contourArea(cnt)
x,y,w,h = cv2.boundingRect(cnt)
rect_area = w*h
extent = float(area) / rect_area
3. Solidity
Solidity는 convex hull 영역에 대한 contour 영역의 비율이다.
area = cv2.contourArea(cnt)
hull = cv2.convexHull(cnt)
hull_area = cv2.contourArea(hull)
solidity = float(area)/hull_area
4. Equivalent Diameter
Equivalent Diameter는 contour영역과 같은 원의 지름이다.
area = cv2.contourArea(cnt)
equi_diameter = np.sqrt(4*area/np.pi)
5. Orientation
Orientation은 객체가 향하는 각도이다. 다음의 방법은 또한 주축의 길이와 보조축의 길이를 알려준다.
(x,y),(MA,ma),angle = cv2.fitEllipse(cnt)
6. Mask and Pixel Points
어떤 경우에선, 우리는 그 객체를 구성하는 모든 점이 필요할 것 이다. 다음처럼 할 수 있다.
mask = np.zeros(imgray,shape,np.uint8)
cv2.drawContours(mask,[cnt],0,255,-1)
pixelpoints = np.transpose(np.nonzero(mask))
#pixelpoints = cv2.findNonzero(mask)
여기서는 Numpy를 사용하는 방법, OpenCV를 사용하는 방법 등 두 가지가 있다. 결과는 같지만 약간의 차이가 있다. Numpy는 (행,열) 형식으로 좌표를 제공하고 OpenCV는 (x,y) 형식으로 좌표를 제공한다.
7. Maximum Value, Minimum Value and their locations
마스크 이미지를 사용하여 이 파라미터들을 찾을 수 있다.
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray,mask = mask)
8. Mean Color or Mean Intensity
객체의 평균 색을 차즐 수 있다. 또는 흑백 모드에서의 객체의 평균 강도가 될 수 있다. 마스크를 써서 사용할 수 있다.
mean_val = cv2.mean(img,mask=mask)
9. Extreme Points
Extreme Points는 객체의 topmost, bottommost, rightmost, leftmost 점을 말한다.
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])
예를 들어 다음의 결과와 같다.
위의 사진에서 “ㅅ” 글자에서의 극단점들을 찾은 것이다. 코드는 다음과 같다.
import cv2
import numpy as np
img = cv2.imread('./images/charm.jpg')
imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
imgray = cv2.GaussianBlur(imgray,(5,5),0)
ret, thr = cv2.threshold(imgray,45,255,cv2.THRESH_BINARY)
thr = cv2.erode(thr, None, iterations=2)
thr = cv2.dilate(thr, None, iterations=2)
contours,_ = cv2.findContours(thr,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
# cnt = max(contours,key=cv2.contourArea)
cnt = contours[4]
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])
cv2.drawContours(imgray,[cnt],-1,(0,255,255),2)
cv2.circle(img,leftmost,8,(0,0,255),-1) # 빨간색
cv2.circle(img,rightmost,8,(0,255,0),-1) # 초록색
cv2.circle(img,topmost,8,(255,0,0),-1) # 파란색
cv2.circle(img,bottommost,8,(255,255,0),-1) # 하늘색
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()