OpenCV 비전 실무12장 · Contour Detection 과 객체 분석12 / 21← 이전목차다음 →MetaContents

12장. Contour Detection 과 객체 분석

분석 결과를 표로 정리하기

학교에서 건강 검진을 하면 학생마다 번호, 키, 몸무게를 한 줄씩 적은 표가 나옵니다. 번호가 있으니 "17번 학생"을 찾아갈 수 있습니다. 물체 분석도 같습니다. 물체마다 번호를 붙이고 면적, 둘레, 중심, 상자를 한 줄씩 적은 표를 만들고, 그림에도 같은 번호를 써 둡니다.

윤곽선, 숫자 재기, 행 하나, 표 만들기, 번호 쓰기의 다섯 단계 흐름도

그림의 다섯 단계로 표를 만듭니다. 거르고 남은 윤곽선마다 숫자를 재고, 물체 하나를 사전 하나(행 하나)로 만들고, 사전 목록을 pandas 의 DataFrame 으로 바꾼 뒤, 그림에도 같은 번호를 씁니다. 여기서 학생이 물체, 검진표의 한 줄이 사전 하나, 학생 번호가 물체 번호입니다.

작업대 사진의 부품 12개에 곧은 상자와 번호를 그린 그림

작업대 사진의 부품마다 곧은 상자(초록)와 번호(다홍)를 그렸습니다. 번호는 위쪽 줄부터, 같은 줄에서는 왼쪽부터 매겼습니다. cv2.findContours 가 준 차례 그대로 번호를 매기면 아래쪽 물체가 1번이 되어 표를 읽기 어렵습니다.

표의 열과 재는 함수

열재는 함수단위
번호위치로 정렬한 차례-
면적cv2.contourArea칸의 넓이
둘레cv2.arcLength(c, True)칸
중심 x, ycv2.moments 의 m10 ÷ m00, m01 ÷ m00칸
상자 x, y, w, hcv2.boundingRect칸

cv2.putText 로 번호 쓰기

cv2.putText(그림, 글, 왼쪽 아래 좌표, 글꼴, 크기, 색, 두께) 로 그림에 글자를 씁니다. 글꼴은 cv2.FONT_HERSHEY_SIMPLEX 처럼 OpenCV 에 든 것만 쓸 수 있고, 이 글꼴에는 한글이 없습니다. 그래서 그림에는 숫자와 영문(작음은 S, 보통은 M, 큼은 L 처럼)만 쓰고, 한글 설명은 표나 Matplotlib 제목에 씁니다. OpenCV 5.0 의 cv2.putText 는 글자 가장자리를 부드럽게 그리므로, 보기용 그림에는 그대로 써도 되지만 이진 그림에 쓰면 0 과 255 사이의 값이 생깁니다.

짧은 예시

Python
import cv2
import pandas as pd

gray = cv2.imread("ch12_tray.png", cv2.IMREAD_GRAYSCALE)
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
parts = [c for c in contours if cv2.contourArea(c) >= 100]

rows = []
for c in parts:
    m = cv2.moments(c)
    x, y, w, h = cv2.boundingRect(c)
    rows.append({"면적": cv2.contourArea(c), "둘레": round(cv2.arcLength(c, True), 1),
                 "cx": round(m["m10"] / m["m00"], 1), "cy": round(m["m01"] / m["m00"], 1),
                 "x": x, "y": y, "w": w, "h": h})
table = pd.DataFrame(rows)
# 위치로 정렬: cy 를 80 칸 단위의 줄로 나누고, 같은 줄에서는 cx 가 작은 쪽부터
table["줄"] = (table["cy"] // 80).astype(int)
table = table.sort_values(["줄", "cx"]).reset_index(drop=True)
table.index = table.index + 1                     # 번호를 1 부터
print(table.head(4))

교안 PC 에서는 첫 줄(1번)이 왼쪽 위의 큰 원으로, 면적 1542.0, 중심 (40.0, 45.0) 입니다. 줄을 80 칸으로 나눈 것은 이 사진에서 부품이 세 줄로 놓였기 때문입니다. 다른 사진에서는 부품 크기에 맞춰 줄 높이를 고칩니다.

주의할 점

  • 정렬하기 전 차례와 정렬한 뒤 차례가 다르므로, 그림에 번호를 쓸 때는 정렬한 표의 번호를 씁니다. 표에 상자 좌표를 함께 두면 그림에 그릴 때 그대로 꺼내 쓸 수 있습니다.
  • cv2.putText 의 좌표는 글자의 왼쪽 아래입니다. 상자의 왼쪽 위 (x, y) 에 쓰면 글자가 상자 위로 올라가는데, 그림 맨 위의 물체면 글자가 잘립니다. max(y - 3, 12) 처럼 아래로 내려 줍니다.
← 이전 절12장 · 개수 세기와 잡티 걸러 내기다음 절 →12장 · 실습 지도