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

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

순서가 왜 중요한가

빨래를 떠올려 봅시다. 빨래를 먼저 하고 다림질하면 옷이 반듯하지만, 다림질을 먼저 하고 빨래하면 다시 구겨집니다. 같은 두 가지 일이라도 순서가 바뀌면 결과가 달라집니다. 열기와 닫기는 침식과 팽창의 순서만 바꾼 것인데 하는 일이 정반대입니다. 그리고 잡티와 구멍이 함께 있는 그림에서는 열기와 닫기 가운데 무엇을 먼저 하느냐도 결과를 바꿉니다.

열기와 닫기의 순서와 하는 일을 견준 비교 그림

왼쪽 초록 상자의 열기는 침식이 먼저라 흰 잡티를 지우고, 오른쪽 다홍 상자의 닫기는 팽창이 먼저라 검은 구멍을 메웁니다. 여기서 빨래와 다림질이 침식과 팽창이고, 그 순서가 열기냐 닫기냐를 정합니다.

잡티와 끊김, 구멍이 함께 있는 글자에 열기 → 닫기와 닫기 → 열기를 건 결과를 나란히 놓은 그림

왼쪽은 끊긴 글자에 씨앗 912 로 흰 잡티 60개를 더 뿌린 그림입니다. 가운데의 열기 → 닫기는 잡티는 지웠지만 M, R, H 의 틈이 남았습니다. 열기의 침식이 먼저 틈과 구멍의 둘레를 깎아 넓혀 놓아서, 뒤의 닫기가 메우지 못한 것입니다. 오른쪽의 닫기 → 열기는 틈과 구멍을 먼저 메운 뒤 잡티를 지워 본래 글자에 훨씬 가깝습니다. 다만 위쪽 가장자리에 닿은 잡티 둘과 M 아래의 잡티 하나가 남았습니다. M 아래의 것은 가까운 잡티 둘을 닫기가 먼저 이어 붙여 도장보다 커진 것이고, 가장자리의 둘은 열기의 침식이 그림 밖을 흰색으로 쳐서 깎지 못한 것입니다.

두 순서 견주기

견줄 것열기 → 닫기닫기 → 열기
먼저 하는 일잡티 지우기구멍·틈 메우기
좋은 점잡티가 많을 때 잡티끼리 붙어 커지는 일이 없다틈과 구멍이 넓어지기 전에 메운다
약한 점침식이 틈과 구멍을 넓혀 닫기가 못 메울 수 있다가까운 잡티끼리, 잡티와 물체가 먼저 붙을 수 있다
이 장의 글자에서덩어리 8개, 본래 글자와 다른 칸 900개덩어리 8개, 다른 칸 282개

본래 글자는 덩어리 5개입니다. 두 순서 모두 3개가 많지만 까닭이 다릅니다. 열기 → 닫기는 잡티를 모두 지웠지만 M 이 두 조각으로 갈리고 R 과 H 에서 작은 조각이 떨어져 나갔습니다. 닫기 → 열기는 글자 다섯 개가 온전하고, 남은 셋은 가장자리에 붙은 잡티 둘과, 닫기가 먼저 이어 붙여 도장보다 커진 잡티 하나입니다. 다른 칸은 닫기 → 열기가 3분의 1 아래입니다.

짧은 예시

Python
import cv2
import numpy as np

clean = cv2.imread("ch09_letters_clean.png", cv2.IMREAD_GRAYSCALE)
dirty = cv2.imread("ch09_letters_broken.png", cv2.IMREAD_GRAYSCALE)
# 씨앗 912 로 흰 잡티 60개를 뿌린다(반지름 1~2 칸의 흰 원)
rng = np.random.default_rng(912)
h, w = dirty.shape
for _ in range(60):
    cv2.circle(dirty, (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))
open_close = cv2.morphologyEx(cv2.morphologyEx(dirty, cv2.MORPH_OPEN, se), cv2.MORPH_CLOSE, se)
close_open = cv2.morphologyEx(cv2.morphologyEx(dirty, cv2.MORPH_CLOSE, se), cv2.MORPH_OPEN, se)
for name, out in [("열기 → 닫기", open_close), ("닫기 → 열기", close_open)]:
    count = cv2.connectedComponents(out)[0] - 1
    print(name, "덩어리:", count, "/ 다른 칸:", int((out != clean).sum()))
# 결과: 위 표의 마지막 줄과 같다

주의할 점

  • 어느 순서가 늘 좋다고 정해져 있지 않습니다. 잡티가 빽빽하면 열기 먼저, 틈과 구멍이 넓어지면 곤란한 그림이면 닫기 먼저가 낫습니다. 두 순서를 모두 해 보고 정답이나 개수로 견줍니다.
  • 가장자리에 닿은 잡티를 지우려면, 그림 둘레에 검은 띠를 덧대고(cv2.copyMakeBorder) 연산한 뒤 띠를 잘라 내는 방법이 있습니다. 이 장에서는 이름만 알아 둡니다.
← 이전 절9장 · 닫기다음 절 →9장 · 그 밖의 모폴로지 연산