9장. Morphology: 침식, 팽창, 열기, 닫기
고르는 기준과 Median 필터와의 견주기
집 안 먼지를 치우는 길은 두 가지입니다. 빗자루로 바닥 전체를 쓸 수도 있고, 이미 쓰레받기에 모은 뒤 손으로 큰 것만 골라낼 수도 있습니다. 점 잡티를 지우는 길도 두 가지입니다. 7장의 Median 필터는 이진화하기 전의 흑백 사진을 통째로 쓸고, 이 장의 열기는 이진화한 뒤의 그림에서 도장보다 작은 흰 점을 골라냅니다.
연산을 고르는 순서는 그림처럼 네 단계입니다. 이진 그림을 크게 띄워 보고, 바탕에 흰 점이 있으면 열기, 덩어리 속이 비거나 획이 끊겼으면 닫기를 고르고, 마지막에 덩어리 수를 세어 정답과 견줍니다. 여기서 빗자루질과 손으로 골라내기가 Median 과 열기입니다.
왼쪽 초록 상자의 Median 은 흑백 사진에 바로 걸어 칸마다 이웃의 중앙값으로 바꿉니다. 오른쪽 다홍 상자의 열기는 이진 그림에 걸어 도장보다 작은 흰 것을 지웁니다.
같은 잡티 그림에 Median 필터를 걸면, 크기 3 에서는 잡티가 거의 그대로 남습니다. 반지름 1 칸짜리 흰 점은 3×3 이웃 아홉 칸 가운데 다섯 칸을 차지해 중앙값도 흰색이기 때문입니다. 크기 5 에서는 잡티가 많이 줄지만 몇 개가 남고 글자 모서리가 조금 무뎌집니다. 열기 5×5 는 잡티를 모두 지우고 글자 모양도 지킵니다.
고르는 기준
| 이진 그림의 형편 | 고를 연산 | 도장 크기를 정하는 법 |
|---|---|---|
| 바탕에 흰 점이 튄다 | 열기 | 가장 큰 잡티보다 크게, 가장 가는 획보다 작게 |
| 물체 속에 검은 구멍이 있다 | 닫기 | 가장 큰 구멍보다 크게, 지킬 구멍(O 의 안쪽 등)보다 작게 |
| 획이 끊겼다 | 닫기 | 가장 넓은 틈보다 크게, 물체 사이 틈보다 작게 |
| 둘 다 있다 | 닫기 → 열기 또는 열기 → 닫기 | 두 순서를 다 해 보고 견준다 |
| 테두리만 필요하다 | 그레이디언트 | 테두리 굵기만큼 |
Median 과 열기 견주기
| 견줄 것 | Median 필터(7차시) | 열기(9차시) |
|---|---|---|
| 거는 곳 | 흑백·컬러 사진(이진화 앞) | 이진 그림(이진화 뒤) |
| 하는 일 | 이웃의 중앙값으로 바꾼다 | 도장보다 작은 흰 것을 지운다 |
| 흰 점과 검은 점 | 둘 다 줄인다 | 흰 점만 지운다(검은 점은 닫기) |
| 물체 모양 | 모서리가 조금 무뎌진다 | 도장보다 큰 모양은 거의 그대로 |
| 잡티 그림(흰 덩어리 47개)에서 | 크기 3: 47개, 크기 5: 27개 | 5×5: 5개(본래 글자 수) |
짧은 예시
import cv2
import numpy as np
clean = cv2.imread("ch09_letters_clean.png", cv2.IMREAD_GRAYSCALE)
noisy = clean.copy()
# 씨앗 911 로 흰 잡티 60개를 뿌린다
rng = np.random.default_rng(911)
h, w = noisy.shape
for _ in range(60):
cv2.circle(noisy, (int(rng.integers(0, w)), int(rng.integers(0, h))), int(rng.integers(1, 3)), 255, -1)
se = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
results = {"잡티 그림": noisy, "Median 3": cv2.medianBlur(noisy, 3),
"Median 5": cv2.medianBlur(noisy, 5), "열기 5×5": cv2.morphologyEx(noisy, cv2.MORPH_OPEN, se)}
for name, out in results.items():
print(name, "흰 덩어리:", cv2.connectedComponents(out)[0] - 1)
# 결과: 47, 47, 27, 5주의할 점
- 이진화 앞에 Median 으로 노이즈를 줄이고, 이진화 뒤에 남은 잡티를 열기로 지우는 것처럼 둘을 함께 쓸 수도 있습니다. 8장에서 블러를 먼저 한 것과 같은 생각입니다.
- 흑백 사진에 침식·팽창을 걸면 칸마다 도장 안의 가장 작은 값·가장 큰 값을 고릅니다. 이진 그림에서 "모두 흰가", "하나라도 흰가"는 이 규칙이 0 과 255 에서 보이는 모습입니다.