12장. Contour Detection 과 객체 분석
점 줄이기: CHAIN_APPROX_NONE 과 SIMPLE
친구에게 공원 산책길을 알려 준다고 해 봅시다. "한 걸음, 한 걸음, 한 걸음…" 하고 걸음마다 알려 줄 수도 있지만, "정문에서 분수대까지 곧장, 거기서 왼쪽으로 벤치까지 곧장"이라고 꺾이는 곳만 알려 줘도 길은 똑같이 전해집니다. 곧은 길에서는 가운데 걸음을 빼도 됩니다.
초록 상자의 CHAIN_APPROX_NONE 은 테두리의 칸을 하나도 빼지 않고 모두 담습니다. 다홍 상자의 CHAIN_APPROX_SIMPLE 은 가로, 세로, 대각선으로 곧게 이어지는 칸은 양 끝만 남기고 가운데를 뺍니다. 여기서 걸음마다 알려 주기가 NONE, 꺾이는 곳만 알려 주기가 SIMPLE 입니다.
왼쪽 NONE 은 네모와 원의 테두리가 다홍 점으로 빽빽합니다. 오른쪽 SIMPLE 은 네모에 꼭짓점 4개만 남았고, 원은 계단처럼 꺾이는 곳마다 점이 남아 절반 남짓으로 줄었습니다.
두 방식 견주기
| 견줄 것 | CHAIN_APPROX_NONE | CHAIN_APPROX_SIMPLE |
|---|---|---|
| 담는 점 | 테두리 칸 모두 | 곧은 줄의 양 끝 |
| 80×50 네모 | 256점 | 4점 |
| 반지름 35 원 | 196점 | 100점 |
| 면적·둘레 | 같다 | 같다 |
| 쓰는 곳 | 테두리 칸 하나하나가 필요할 때 | 대부분(메모리를 아낀다) |
짧은 예시
import cv2
shapes = cv2.imread("ch12_shapes.png", cv2.IMREAD_GRAYSCALE)
full, _ = cv2.findContours(shapes, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
short, _ = cv2.findContours(shapes, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print("NONE 전체 점 수:", sum(len(c) for c in full))
print("SIMPLE 전체 점 수:", sum(len(c) for c in short))
# 점을 줄여도 면적은 그대로인지 마지막 윤곽선(네모)으로 확인한다
print("네모의 면적:", cv2.contourArea(full[-1]), "/", cv2.contourArea(short[-1]))교안 PC 에서는 NONE 이 1,291점, SIMPLE 이 620점으로 절반 아래로 줄었고, 네모의 면적은 두 방식 모두 3871.0 입니다. 빠진 점은 곧은 줄 위에 있던 점이라 점을 이은 도형이 바뀌지 않기 때문입니다.
주의할 점
- SIMPLE 이 줄이는 것은 가로, 세로, 45도 대각선으로 곧은 줄뿐입니다. 비스듬한 선은 계단 모양이라 점이 많이 남습니다.
- 꼭짓점 몇 개로 모양을 어림하는 일(다각형 근사,
cv2.approxPolyDP)은 SIMPLE 과 다른 일입니다. 13장에서 배웁니다.