Python과 OpenCV – 17 : 이미지의 등치선(Contours) – 3/5

이 글의 원문은 https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contour_properties/py_contour_properties.html#contour-properties 입니다.

Contour(등치선)에 대해 자주 사용되는 몇가지 속성에 대해 좀더 살펴보겠습니다. 그 속성에는 Solidity, Equivalent Diameter, Mask image, Mean Intensity 등입니다.

먼저 Aspect Ratio인데, 객체(Contour를 표현되는 것)에 대한 경계상자의 높이와 너비에 대한 비율이며 아래와 같습니다.

OpenCV에서는 다음과 같은 코드를 통해 얻을 수 있습니다.

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

다음은 Extent입니다. 이 속성은 경계상자의 넓이에 대한 객체의 실제 넓이의 비율입니다.

코드는 다음과 같습니다.

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

다음은 Equivalent Diameter입니다. 이 속성은 객체의 실제 면적와 동일한 면적을 갖는 원의 지름입니다.

코드는 다음과 같습니다.

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

다음은 Solidity입니다. 이 값은 객체의 볼록껍질 면적에 대한 객체의 면적 비율입니다.

코드는 다음과 같습니다.

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

다음은 Orientation입니다. 이 속성은 객체가 놓여진 방향에 대한 각도인데, 다음 식은 주축과 보조축으로써 표현한 코드 예로 angle 변수값이 각도입니다.

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

다음은 Mask과 Pixel Points입니다. 어떤 경우에 객체를 구성하는 모든 포인트가 필요할 수 있습니다. 이를 위해 다음 코드가 사용됩니다.

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

pixelpoints1와 pixelpoints2는 동일한 결과인데, 각각 Numpy와 OpenCV를 사용한 방식입니다.

다음은 최대값, 최소값과 위치값입니다. 이 값들은 마스크 이미지를 사용해 얻을 수 있습니다.

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

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

위의 1,2번 코드는 마스크 이미지를 생성합니다. 이 마스크 이미지는 최대, 최소값과 이 값들의 위치가 어디인지에 대한 범위를 제한하는데 사용됩니다. mask 이미지의 적용은 옵션입니다.

다음은 평균 색상과 평균 강도입니다. 마스크 이미지를 적용해 해당 마스크 이미지 범위에 존재하는 픽셀들의 평균색상 또는 평균강도 값을 얻는 코드는 다음과 같습니다.

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

끝으로 Extreme Points입니다. 이 속성은 객체의 최상단, 최하단, 좌측끝단, 우측끝단의 포인트를 의미하는데, 먼저 코드를 보면..

import numpy as np
import cv2
 
img = cv2.imread('./data/thunder.png')
imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
 
cnt = contours[0]
 
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.circle(img, leftmost, 10, (0,0,255), -1)
cv2.circle(img, rightmost, 10, (0,0,255), -1)
cv2.circle(img, topmost, 10, (0,0,255), -1)
cv2.circle(img, bottommost, 5, (0,255,255), -1)

cv2.imshow('img', img)
cv2.waitKey()
cv2.destroyAllWindows()

위의 코드 중 11-14번과 16-19번이 최상단, 최하단, 좌측끝단, 우측끝단의 포인트를 얻고 그려주는 코드입니다. 결과는 다음과 같습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다