13장. Shape 분석과 ROI 처리
모양 ROI
쿠키를 만들 때 반죽 위에 쿠키 틀을 눌러 찍으면 틀 모양대로만 반죽이 떨어집니다. 네모 칼로 자르면 네모만 나오지만, 틀을 쓰면 동그라미, 별, 하트 모양도 오려 낼 수 있습니다. 사진에서는 마스크가 쿠키 틀입니다. 검은 판에 원하는 모양을 흰색으로 칠하고, cv2.bitwise_and 로 흰 곳만 남깁니다.
그림의 네 단계를 따라 모양 ROI 를 만듭니다. 그림과 같은 크기의 검은 판을 만들고, cv2.circle, cv2.fillPoly, cv2.drawContours 로 원하는 곳을 흰색(255)으로 칠합니다. 그다음 3장에서 본 cv2.bitwise_and(img, img, mask=마스크) 로 흰 곳의 원래 색만 남깁니다. 여기서 쿠키 틀이 마스크, 틀 안의 반죽이 ROI 입니다.
위 줄이 마스크, 아래 줄이 마스크를 씌운 결과입니다. 왼쪽은 cv2.circle 로 칠한 동그라미, 가운데는 cv2.fillPoly 로 칠한 다섯 꼭짓점 다각형, 오른쪽은 윤곽선을 cv2.drawContours 의 두께 -1 로 속까지 칠한 마스크입니다. 아래 줄에서 마스크 밖은 모두 검정입니다.
마스크를 칠하는 세 함수
| 함수 | 원래 말 | 주는 것 | 쓰는 때 |
|---|---|---|---|
cv2.circle(mask, (x, y), r, 255, -1) | circle(원) | 가운데와 반지름 | 동그란 물체 |
cv2.fillPoly(mask, [점들], 255) | fill polygon(다각형 채우기) | 꼭짓점 목록 | 사람이 정한 다각형 |
cv2.drawContours(mask, [c], -1, 255, -1) | draw contours(윤곽선 그리기) | 찾은 윤곽선 | 물체 모양 그대로 |
두께 자리에 -1 을 주면 선이 아니라 속까지 채웁니다(cv2.FILLED 와 같습니다).
짧은 예시
import cv2
import numpy as np
img = cv2.imread("ch13_parcel.png")
# 그림과 같은 세로·가로의 검은 판(0). 채널은 하나, 자료형은 uint8
mask = np.zeros(img.shape[:2], dtype=np.uint8)
# 꼭짓점 다섯 개짜리 다각형을 흰색으로 채운다. 점은 (x, y) 순서, 자료형은 int32
pts = np.array([[60, 40], [205, 40], [205, 110], [130, 130], [60, 110]], dtype=np.int32)
cv2.fillPoly(mask, [pts], 255)
print(int((mask == 255).sum())) # 흰 칸 수
# 마스크의 흰 곳만 원래 색, 나머지는 검정
only = cv2.bitwise_and(img, img, mask=mask)
print([int(v) for v in only[60, 100]], [int(v) for v in only[200, 100]])
# 결과: 송장 안의 칸은 원래 색, 다각형 밖의 칸은 [0, 0, 0]주의할 점
- 모양 ROI 는 그림의 크기가 그대로이고 바깥만 검정이 됩니다. 칸 수를 줄여 빠르게 하려면 마스크를 씌운 뒤
boundingRect로 다시 네모로 자릅니다. cv2.fillPoly의 점은int32정수 배열이어야 합니다. 소수 배열을 주면 오류가 납니다. 그리고 점 목록을 대괄호로 한 번 더 감싸[pts]로 줍니다(다각형 여러 개를 한 번에 받기 때문입니다).- 검정(0)이 원래 그림에도 있으면 "마스크 밖"과 구별되지 않습니다. 평균이나 히스토그램을 낼 때는 4장처럼
mask=인자를 줘서 흰 칸만 셉니다.