OpenCV 비전 실무9장 · Morphology: 침식, 팽창, 열기, 닫기6 / 21← 이전목차다음 →MetaContents

9장. Morphology: 침식, 팽창, 열기, 닫기

팽창

흰 종이에 물감 한 방울을 떨어뜨리면 둘레로 조금씩 번집니다. 번진 물감이 옆의 다른 방울과 닿으면 두 방울이 하나로 이어지고, 방울 사이의 작은 틈은 물감으로 메워집니다. 팽창은 흰 덩어리를 한 겹 부풀립니다. 덩어리가 커지고, 가까운 덩어리끼리 붙고, 작은 검은 구멍은 흰색으로 메워집니다.

도장 놓기, 하나라도 흰가, 결과 쓰기의 세 단계 흐름도

그림의 세 단계는 침식과 둘째 칸만 다릅니다. 도장의 1 자리에 흰 칸이 하나라도 있으면 흰색을 씁니다. 여기서 물감 방울이 흰 덩어리이고, 번지는 너비가 도장의 크기입니다.

손으로 계산해 보기

침식과 같은 8×8 그림을 같은 3×3 도장으로 팽창합니다.

8×8 원본과 3×3 도장으로 팽창한 결과를 0 과 1 로 적은 손계산 그림

왼쪽의 다홍 테두리 두 개는 원래 0 이던 칸에 댄 도장입니다. (2, 6) 에 댄 도장 안에는 튀어나온 칸 하나가 들어 있어 1 이 되고, (5, 5) 에 댄 도장 안에는 네모 귀퉁이와 떨어진 점이 함께 들어 있어 1 이 됩니다. 오른쪽 결과에서는 네모가 사방으로 한 겹 커졌고, 떨어져 있던 점도 3×3 으로 부풀어 네모와 이어졌습니다.

도장을 댄 칸(세로, 가로)원래 값도장 안의 1하나라도 1 인가결과
(2, 6)0튀어나온 칸 1개그렇다1
(5, 5)0네모 귀퉁이, 떨어진 점그렇다1
(7, 1)0없음아니다0

흰 칸은 18개에서 47개로 늘었고, 흰 덩어리는 두 개(네모, 점)에서 하나로 줄었습니다.

짧은 예시

Python
import cv2
import numpy as np

# 침식 절과 같은 8×8 그림과 3×3 도장
img = np.zeros((8, 8), np.uint8)
img[1:5, 1:5] = 255
img[3, 5] = 255
img[6, 6] = 255
se = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))

# dilate = 넓히다, 부풀리다
dilated = cv2.dilate(img, se)
print("흰 칸:", int((img == 255).sum()), "→", int((dilated == 255).sum()))
# connectedComponents: (흰 덩어리 수 + 바탕 1, 칸마다의 덩어리 번호)를 돌려준다. 첫 값에서 1 을 뺀다
before = cv2.connectedComponents(img)[0] - 1
after = cv2.connectedComponents(dilated)[0] - 1
print("흰 덩어리:", before, "→", after)
# 결과: 흰 칸 18 → 47, 흰 덩어리 2 → 1

cv2.connectedComponents 는 맞닿은 흰 칸끼리 한 무리로 묶어 번호를 매깁니다. 바탕(검은 칸)에도 0 번을 주므로 첫 값에서 1 을 빼야 흰 덩어리 수가 됩니다. 이 함수는 12장에서 자세히 배우고, 이 장에서는 개수만 셉니다.

주의할 점

  • 팽창은 흰 덩어리를 굵게 만듭니다. 구멍을 메우고 싶어도 물체가 한 겹 커지므로, 실제로는 침식과 묶어(닫기) 씁니다.
  • 침식과 팽창은 서로를 되돌리지 못합니다. 침식으로 사라진 점은 팽창해도 돌아오지 않고, 팽창으로 메운 구멍은 침식해도 다시 열리지 않습니다. 열기와 닫기는 이 성질을 이용합니다.
← 이전 절9장 · 침식다음 절 →9장 · 크기와 횟수