OpenCV 비전 실무13장 · Shape 분석과 ROI 처리7 / 21← 이전목차다음 →MetaContents

13장. Shape 분석과 ROI 처리

볼록 껍질과 볼록 비율

선물을 포장할 때 물건 둘레에 고무줄을 한 바퀴 감는다고 해 봅시다. 공이나 상자는 고무줄이 몸에 딱 붙습니다. 그런데 별 모양 쿠키나 초승달 모양 빵에 감으면, 고무줄은 뾰족한 끝끼리 곧게 이어지고 움푹한 곳은 비어 있습니다. 고무줄이 만든 모양이 볼록 껍질이고, 물체가 그 안을 얼마나 채우는지가 볼록 비율입니다.

별, 초승달, 네모의 둘레에 고무줄처럼 볼록 껍질을 겹쳐 그리고 볼록 비율을 적은 그림

그림의 다홍 선이 고무줄, 곧 cv2.convexHull 로 구한 볼록 껍질입니다. 네모는 고무줄이 몸에 딱 붙어 볼록 비율이 1 입니다. 별은 뾰족한 끝 사이가 비어 0.51 쯤, 초승달은 안쪽이 크게 비어 0.58 쯤입니다. 여기서 고무줄 안의 넓이가 볼록 껍질 넓이이고, 고무줄과 물체 사이의 빈 곳이 볼록 비율을 깎는 몫입니다.

볼록과 움푹 견주기

견줄 것볼록한 모양움푹한 모양
예원, 네모, 세모, 팔각형별, 초승달, 톱니바퀴, 알파벳 C
고무줄몸에 딱 붙는다움푹한 곳 위로 곧게 지나간다
볼록 비율1 에 가깝다(0.95 넘음)1 보다 뚜렷이 작다
isContourConvex (근사 다각형에 쓸 때)TrueFalse

짧은 예시

Python
import cv2

img = cv2.imread("ch13_shapes.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(gray, 60, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 넓이가 가장 작은 것(1,230)이 별이다
star = min(contours, key=cv2.contourArea)
hull = cv2.convexHull(star)                  # 고무줄을 감은 모양의 꼭짓점들
solidity = cv2.contourArea(star) / cv2.contourArea(hull)
print(round(solidity, 3))                    # 결과: 0.507

# isContourConvex 는 근사 다각형에 써야 뜻이 분명하다
approx = cv2.approxPolyDP(star, 0.01 * cv2.arcLength(star, True), True)
print(cv2.isContourConvex(approx))           # 결과: False → 움푹한 곳이 있다
print(cv2.isContourConvex(cv2.convexHull(star)))   # 결과: True → 고무줄은 언제나 볼록

별의 넓이는 볼록 껍질 넓이의 절반쯤입니다. 뾰족한 끝 다섯 개 사이의 빈 곳이 그만큼 큽니다.

주의할 점

  • 볼록하게 그린 원도 그림 속에서는 칸의 계단 때문에 윤곽선 그대로는 isContourConvex 가 False 로 나올 수 있습니다. 근사 다각형으로 바꾼 뒤 묻거나, 볼록 비율(0.95 넘음)로 판단합니다.
  • 볼록 비율은 "얼마나 움푹한가"만 알려 줍니다. 별과 초승달처럼 움푹한 것끼리는 꼭짓점 수 같은 다른 숫자로 가릅니다.
← 이전 절13장 · 종횡비와 채움 비율다음 절 →13장 · 모양 분류 규칙 만들기