이미지 컨투어
컨투어 (contour)란 동일한 색 또는 동일한 픽셀값 (강도,intensity)을 가지고 있는 영역의 경계선 정보다. 물체의 윤곽선, 외형을 파악하는데 사용된다.
OpenCV의 findContours 함수로 이미지의 컨투어 정보, 컨투어의 상하구조 (hierachy) 정보를 출력한다. 흑백 이미지 또는 이진화된 이미지만 적용할 수 있다.
images, contours, hierachy = cv2.findContours(image, mode, method)
|
import cv2
from skimage.data import horse
img_raw = horse().astype('uint8')
img_raw = np.ones(img_raw.shape) - img_raw
img = img_raw.copy().astype('uint8')
images, contours, hierachy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_TC89_KCOS)
컨투어 정보는 컨투어를 구성하는 점들로 이루어진 배열의 리스트다. 리스트의 원소의 갯수는 컨투어의 갯수와 같다.
len(contours)
2
contours[0].shape
(312, 1, 2)
np.squeeze(contours[0])[:5]
array([[350, 9],
[346, 13],
[345, 13],
[339, 19],
[330, 20]], dtype=int32)
x0, y0 = zip(*np.squeeze(contours[0]))
plt.plot(x0, y0, c="b")
plt.show()
상하구조 (hierarchy)는 1, 0, -1 값으로 이루어진 (컨투어 수 x 4) 크기의 행렬이다.
|
다음 값에서 첫 번째 컨투어 라인이 가장 상위 컨투어라는 것을 알 수 있다.
hierachy
array([[[-1, -1, 1, -1],
[-1, -1, -1, 0]]], dtype=int32)
drawContours 함수를 사용하면 컨투어 정보에서 비트맵 이미지를 만들 수 있다.
drawContours(image, contours, contourIdx, color)
|
image = cv2.drawContours(img, contours, 0, 2)
plt.subplot(1, 2, 1)
plt.imshow(img_raw, cmap='bone')
plt.title("원본 이미지")
plt.axis('off')
plt.subplot(1, 2, 2)
plt.imshow(image, cmap='bone')
plt.title("컨투어 이미지")
plt.axis('off')
plt.tight_layout()
plt.show()
이미지 모멘트
이미지 모멘트는 컨투어에 관한 특징 값을 뜻한다. OpenCV에서는 moments 함수로 이미지 모멘트를 구한다. 컨투어 포인트 배열을 입력하면 해당 컨투어의 모멘트를 딕셔너리 타입으로 반환한다. 반환하는 모멘트는 총 24개로 10개의 위치 모멘트, 7개의 중심 모멘트, 7개의 정규화된 중심 모멘트로 이루어져 있다.
|
c0 = contours[0]
M = cv2.moments(c0)
M
{'m00': 42355.0,
'm10': 7943000.166666666,
'm01': 6115675.833333333,
'm20': 1914995009.1666665,
'm11': 1043128904.8333333,
'm02': 1041817606.0,
'm30': 517465951777.85004,
'm21': 233874687443.69998,
'm12': 169430720481.3,
'm03': 200904428563.85,
'mu20': 425412866.6175771,
'mu11': -103767899.87557864,
'mu02': 158769774.61250484,
'mu30': -1219318387.8395386,
'mu21': -3713125246.697487,
'mu12': 4020833974.2852783,
'mu03': 4625649126.278534,
'nu20': 0.2371380524771235,
'nu11': -0.0578433790256196,
'nu02': 0.08850309451896964,
'nu30': -0.003302595676372647,
'nu21': -0.010057218449154588,
'nu12': 0.010890665663146169,
'nu03': 0.012528843128440374}
컨투어의 면적은 모멘트의 m00 값이고, cv2.contourArea() 함수로도 구할 수 있다.
cv2.contourArea(c0)
42355.0
컨투어의 둘레는 arcLength 함수로 구할 수 있다. 두번째 파라미터인 closed의 의미는 폐곡선의 여부로, 설정한 값이 True 일 때는 컨투어의 시작점과 끝점을 이어 도형을 구성하고 그 둘레 값을 계산한다. False인 경우 시작점과 끝점을 잇지 않고 둘레를 계산한다.
cv2.arcLength(c0, closed=True), cv2.arcLength(c0, closed=False)
(2203.678272008896, 2199.678272008896)
컨투어를 둘러싸는 박스는 boundingRect 함수로 구한다.
x, y, w, h = cv2.boundingRect(c0)
x, y, w, h
(18, 9, 371, 304)
plt.plot(x0, y0, c="b")
plt.plot(
[x, x + w, x + w, x, x],
[y, y, y + h, y + h, y],
c="r"
)
plt.show()
가로 세로 비율은 바운딩 박스에서 구할 수 있다.
aspect_ratio = float(w) / h
aspect_ratio
1.2203947368421053
컨투어 라인의 중심점과 좌우상하의 끝점은 다음처럼 구한다.
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'])
leftmost = tuple(c0[c0[:, :, 0].argmin()][0])
rightmost = tuple(c0[c0[:, :, 0].argmax()][0])
topmost = tuple(c0[c0[:, :, 1].argmin()][0])
bottommost = tuple(c0[c0[:, :, 1].argmax()][0])
plt.subplot(1,2,1)
plt.imshow(image, cmap='bone')
plt.title("컨투어의 중심점")
plt.axis('off')
plt.scatter([cx], [cy], c="r", s=30)
plt.subplot(1,2,2)
plt.imshow(img_raw, cmap='bone')
plt.axis("off")
plt.scatter(
[leftmost[0], rightmost[0], topmost[0], bottommost[0]],
[leftmost[1], rightmost[1], topmost[1], bottommost[1]],
c="b", s=30)
plt.title("Extream Points")
plt.show()
'AI-driven Methodology > CV (Computer Vision)' 카테고리의 다른 글
[Computer Vision] 이미지 변환 (0) | 2022.06.13 |
---|---|
[Computer Vision] 컨투어 추정 (0) | 2022.06.13 |
[Computer Vision] Scikit-Image (0) | 2022.06.13 |
[Computer Vision] Pillow를 이용한 이미지 처리 (0) | 2022.06.13 |
[Computer Vision] 이미지 파일 형식 (0) | 2022.06.13 |