모폴로지(morphology)란 생물의 구조나 외형을 연구하는 학문을 말하는데요. 영상 분야에서는 객체의 형태에 대해 분석하고 처리하는 기법을 말하며 노이즈를 제거하거나, 영역 간 경계를 변형하는 등에 사용됩니다. 검은색과 흰색으로만 구성되어 있는 이진 영상(binary)에 적용할 수 있으며 이미지 전처리(pre-processing), 후처리(post-processing)를 위해 자주 사용됩니다.
침식 연산은 이미지 내 객체 형태를 깎아 내는 연산을 말합니다. 0과 1로 구성된 구조화 요소 커널(Structuring Element Kernel)을 활용하하는데요. 1로 채워진 커널을 올려 놓을 수 없으면, 해당 픽셀을 0으로 변경하여 형태를 지워 버립니다. 이를 통해 객체 크기는 축소되는 반면, 배경은 확대 됩니다. 침식 연산은 어두운 부분의 노이즈를 제거하는데 효과가 있습니다.
cv2.erode(src, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)
- src : 입력 영상
- kernel : 구조 요소. getStructuringElement() 함수에 의해 생성 가능. 만약 None을 지정하면 3x3 사각형 구성 요소를 사용.
- dst : 출력 영상. src와 동일한 크기와 타입.
- anchor : 고정점 위치. 기본값 (-1, -1)을 사용하면 중앙점을 사용.
- iterations : 반복 횟수. 기본값은 1.
- borderType : 가장자리 픽셀 확장 방식. 기본값은 cv2.BORDER_CONSTANT.
- borderValue : cv2.BORDER_CONSTANT인 경우, 확장된 가장자리 픽셀을 채울 값.
cv2.getStructuringElement(shape, ksize, anchor=None)
- shape : 구조 요소 모양을 나타내는 플래그
- anchor : MORPH_CROSS 모양의 구조 요소에서 고정점 좌표. (-1, -1)을 지정하면 구조 요소의 중앙을 고정점으로 사용.
- retval : 0과 1로 구성된 cv2.CV_8UC1 타입 행렬. numpy.ndarray. (1의 위치가 구조 요소 모양을 결정)
shape : 구조 요소 커널 플래그 유형
shape | 설명 |
---|---|
cv2.MORPH_RECT | 사각형 모양 |
cv2.MORPH_CROSS | 십자가 모양 |
cv2.MORPH_ELLIPSE | 사각형에 내접하는 타원 |
팽창 연산은 침식 연산과는 반대로 구조 요소 커널과 객체 영역이 한 픽셀이라도 만날 경우 고정점 픽셀을 255로 설정하여 객체 외곽을 확대시킵니다. 이를 통해 객체 크기는 커지고 배경은 축소됩니다. 팽창 연산을 반복해서 수행하면, 객체 영역(흰색)이 점점 커져서 내부의 홀(구멍)이 채워지게 됩니다. 팽창 연산은 밝은 부분의 노이즈를 제거하는데 효과가 있습니다.
cv2.dilate(src, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)
- src : 입력 영상
- kernel : 구조 요소. getStructuringElement() 함수에 의해 생성 가능. 만약 None을 지정하면 3x3 사각형 구성 요소를 사용.
- dst : 출력 영상. src와 동일한 크기와 타입.
- anchor : 고정점 위치. 기본값 (-1, -1)을 사용하면 중앙점을 사용.
- iterations : 반복 횟수. 기본값은 1.
- borderType : 가장자리 픽셀 확장 방식. 기본값은 cv2.BORDER_CONSTANT.
- borderValue : cv2.BORDER_CONSTANT인 경우, 확장된 가장자리 픽셀을 채울 값.
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('./images/lecorbusier.jpg', cv2.IMREAD_COLOR)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.threshold(gray, 75, 150, cv2.THRESH_BINARY+cv2.THRESH_OTSU )[1]
rectKernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
erode = cv2.morphologyEx(gray, cv2.MORPH_ERODE, rectKernel)
dilate = cv2.morphologyEx(gray, cv2.MORPH_DILATE, rectKernel)
plt_imshow(["image", "gray+otsu", "erode", "dilate"], [image, gray, erode, dilate])
[출력]
열림과 닫힘은 앞서 언급한 침식과 팽창 연산을 바탕으로 수행합니다. 열림은 침식 + 팽창 으로, 침식 연산을 먼저 수행하여 외부의 작은 픽셀을 제거하고 팽창 연산을 이용하여 윤곽선을 단순화 시킵니다. 반대로 닫힘은 팽창 + 침식 으로, 팽창 연산을 먼저 수행하여 객체 내부 빈 공간을 메꾸고 윤곽선이 두터워지게 만든 후 침식 연산을 수행하여 내부 공간을 단단하게 만듭니다.
열림 연산으로 외곽을 제거하고, 닫힘 연산으로 내부를 채울 수 있습니다.
그래디언트 연산은 팽창 - 침식 으로, 팽창 연산을 적용한 이미지에서 침식 연산을 적용한 이미지를 빼면 경계 픽셀만 얻게 되는데, 이는 에지 검출과 비슷합니다.
탑햇 연산은 원본 - 열림 으로, 원본 이미지에서 열림 연산의 적용 결과를 빼면 밝은 영역을 강조할 수 있습니다.
블랙햇 연산은 닫힘 - 원본 으로, 닫힘 연산에서 원본을 빼면 어두운 부분을 강조할 수 있습니다.
cv2.morphologyEx(src, op, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)
- src : 입력 영상
- op : 모폴로지 연산 플래그
- kernel : 커널
- dst : 출력 영상
op : 모폴로지 연산 플래그 유형
op | 설명 | 효과 |
---|---|---|
cv2.MORPH_ERODE | 침식 | 어두운 영역 노이즈 제거 |
cv2.MORPH_DILATE | 팽창 | 밝은 영역 노이즈 제거 |
cv2.MORPH_OPEN | 열기 | 외곽 제거 |
cv2.MORPH_CLOSE | 닫기 | 내부 채우기 |
cv2.MORPH_GRADIENT | 그래디언트 | 팽창 - 침식 |
cv2.MORPH_TOPHAT | 탑햇 | 원본 - 열림 |
cv2.MORPH_BLACKHAT | 블랙햇 | 닫힘 - 원본 |
import cv2
import matplotlib.pyplot as plt
image = cv2.imread('./images/lecorbusier.jpg', cv2.IMREAD_COLOR)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.threshold(gray, 75, 150, cv2.THRESH_BINARY+cv2.THRESH_OTSU )[1]
rectKernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
opend = cv2.morphologyEx(gray, cv2.MORPH_OPEN, rectKernel)
close = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, rectKernel)
gradient = cv2.morphologyEx(gray, cv2.MORPH_GRADIENT, rectKernel)
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
balckhat = cv2.morphologyEx(gray, cv2.MORPH_BLACKHAT, rectKernel)
plt_imshow(["opend", "close", "gradient", "tophat", "balckhat"]
, [opend, close, gradient, tophat, balckhat])
[출력]