[OpenCV] 04-5. Morphological Transformations
🐍Python/OpenCV

[OpenCV] 04-5. Morphological Transformations

728x90
반응형

< 4-5. Morphological Transformations >

이번에는 Erosion(침식), Dilation(팽창), Opening, Closing등과 같은 서로 다른 형태학적 기능에 대해서 볼 것이다.

  • cv2.erode(), cv2.dilate(), cv2.morphologyEx()에 대해서 배울 것이다.

Theory

형태의 변환은 이미지 모양에 기반한 간단한 기능이다. 이는 보통 이원의 이미지에서 작동된다. 이는 두 개의 입력을 필요로 하는데, 하나는 원래의 이미지, 두 번째로는 기능의 성질을 결정하는 “구성 요소” 나 “커널”이라고 불리는 것이다. 두 개의 기본적인 현태학적 기능은 Erosion과 Dilation이다. 그리고 이들은 Opening, Closing, Gradient등 과 같은 형태로 변하여 등장했다.

앞의 실험에 사용할 기본 이미지는 다음과 같다.



1. Erosion

erosion의 기본 아이디어는 토양이 부식되는 것 처럼, 눈에 띄는 객체의 경계를 부식시키는 것이다. (객체는 흰색으로 유지한체로) 커널은 이미지를 통과한다. 원본 이미지의 픽셀(1,0)은 커널 아래의 모든 픽셀이 1인 경우에만 원본 영상의 픽셀이 1로 간주되고 그렇지 않으면 지워진다.

경계 주변의 픽셀들은 커널의 크기에 따라 지워지게된다. 그래서 객체의 두께나 크기가 줄어들거나 간단하게는 이미지내의 하얀 부분이 줄어든다. 이는 작은 화이트 노이즈를 제거하는데나, 두 개의 연결된 객체를 분리하는등에 매우 유용하다.

여기서는 차이를 눈에 잘 보이게 하기 위해 20 X 20 커널을 사용했다.

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('./images/charm.jpg')
kernel = np.ones((20,20),np.uint8)

erosion = cv2.erode(img,kernel,iterations=1)
plt.imshow(erosion)
plt.axis('off')
plt.show()


2. Dilation

그냥 erosion의 반대이다! 커널 아래의 적어도 한 픽셀이 1이면 픽셀 성분이 1이다. 그래서 이미지 내의 흰색 지역이나 객체의 크기가 증가하게되는 것이다. 일반적으로, 노이즈 제거와 같은 경우, erosion후에 dilation을 한다. 왜냐하면, erosion은 화이트 노이즈들을 제거하지만, 우리의 객체를 축소시키기 때문이다. 그래서 dilate하는 것이다. 노이즈가 사라지면 다시 돌아오지 않기 때문이다. (하지만 객체는 커진다) 또한 이는 객체의 부서진 부분을 합치는데 유용하다.

img = cv2.imread('./images/charm.jpg')
dilation = cv2.dilate(img,kernel,iterations=1)

plt.imshow(dilation,'gray')
plt.axis('off')
plt.show()


3. Opening

Opening은 erosion 이후에 dilation을 하는 것의 다른 이름이다. 이는 노이즈를 제거하는데 유용하다. cv2.morphologyEx()로 실행할 수 있다.

# 노이즈가 포함된 이미지를 로드한다. 
img_n = cv2.imread('./images/img_n.jpg',0)
kernel = np.ones((20,20),np.uint8)
opening = cv2.morphologyEx(img_n,cv2.MORPH_OPEN,kernel)

plt.figure(figsize=(12,8))

plt.subplot(1,2,1), plt.imshow(img_n,'gray')
plt.title('Original Images with Noise')
plt.axis('off')

plt.subplot(1,2,2), plt.imshow(opening,'gray')
plt.title('Opening')
plt.axis('off')
plt.show()


노이즈가 제거된 모습을 볼 수 있다.

4. Closing

Closing은 Opening의 반대로, dilation이후에 erosion한 것이다. 이는 객체 내의 작은 구멍이나 검은 점을 없애는데 도움을 준다.

# 노이즈가 포함된 이미지를 로드한다. 
img_n = cv2.imread('./images/img_n.jpg',0)
kernel = np.ones((20,20),np.uint8)
closing = cv2.morphologyEx(img_n,cv2.MORPH_CLOSE,kernel)


plt.figure(figsize=(12,8))

plt.subplot(1,2,1), plt.imshow(img_n,'gray')
plt.title('Original Images with Noise')
plt.axis('off')

plt.subplot(1,2,2), plt.imshow(closing,'gray')
plt.title('Closing')
plt.axis('off')
plt.show()


Opening이나 Closing이다 객체 내외부의 노이즈를 잘 제거하는 모습을 보인다.

5. Morphological Gradient

이는 이미지의 dilation과 erosion의 차이이다.

결과는 객체의 외곽선이 된다. 커널이 작아질 수록 윤곽선 또한 얇아진다.

 img = cv2.imread('./images/charm.jpg',0)
kernel = np.ones((10,10),np.uint8)
gradient = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)


plt.figure(figsize=(12,8))

plt.subplot(1,2,1), plt.imshow(img,'gray')
plt.title('Original Images')
plt.axis('off')

plt.subplot(1,2,2), plt.imshow(gradient,'gray')
plt.title('Gradient')
plt.axis('off')
plt.show()


윤곽선만 도출된 것을 볼 수 있다.

6. Top Hat

이는 입력 이미지와 이미지의 Opening 간의 차이점이다. 아래는 50x50 커널을 사용한 결과이다.

 img = cv2.imread('./images/charm.jpg',0)
kernel = np.ones((50,50),np.uint8)
tophat = cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)


plt.figure(figsize=(12,8))

plt.subplot(1,2,1), plt.imshow(img,'gray')
plt.title('Original Images')
plt.axis('off')

plt.subplot(1,2,2), plt.imshow(tophat,'gray')
plt.title('Top Hat')
plt.axis('off')
plt.show()


7. Black Hat

이는 입력 이미지의 closing과 입력 이미지간의 차이점이다.

 img = cv2.imread('./images/charm.jpg',0)
kernel = np.ones((50,50),np.uint8)
blackhat = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT,kernel)


plt.figure(figsize=(12,8))

plt.subplot(1,2,1), plt.imshow(img,'gray')
plt.title('Original Images')
plt.axis('off')

plt.subplot(1,2,2), plt.imshow(blackhat,'gray')
plt.title('Black Hat')
plt.axis('off')
plt.show()


Structuring Element

우리는 구성 성분들을 넘파이를 이용하여 직접 만들었다. 이는 직사각형의 모양이다. 하지만 다른 경우에, 타원형/원형 모약의 커널이 필요할 수 있다. 이러한 목적을 위해, OpenCV는 cv2.getStructuringElement()라는 함수를 제공한다. 그냥 커널의 shape과 크기를 입력하면 원하는 커널을 얻을 수 있다.

# 직사각형 커널
rec = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))

plt.figure(figsize=(12,8))
plt.subplot(1,3,1)
plt.imshow(rec,'gray')
plt.axis('off')
plt.title('Rectangular')

# 타원형 커널
elip = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
plt.subplot(1,3,2)
plt.imshow(elip,'gray')
plt.axis('off')
plt.title('Eliptical')

# 십자형 커널
cross = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
plt.subplot(1,3,3)
plt.imshow(cross,'gray')
plt.axis('off')
plt.title('Cross')

plt.show()


728x90
반응형