[OpenCV] 04-6. Image Gradients
🐍Python/OpenCV

[OpenCV] 04-6. Image Gradients

728x90
반응형

< 4-6. Image Gradients >

이미지의 gradients(경사도), edges(가장자리)를 찾는다.

  • cv2.Sobel(), cv2.Scharr(), cv2.Laplacian()등의 함수에 대해서 볼 것 이다.

Theory

OpenCV는 세 가지 유형의 gradients 필터 또는 High-pass 필터인 Sobel, Sharr, Laplacian을 제공한다.

1. Sobel and Scharr Derivatives

Sobel 연산자는 joint Gaussian smoothing + 미분 연산이므로 노이즈에 대한 내성이 더 강하다. 수직, 수평으로 취할 미분(derivatives)의 방향을 지정할 수 있다. (argument의 yorder, xorder로 각각 가능하다.) 또한 ksize를 통해 커널의 크기를 정할 수 있다. 만약에 ksize가 -1이면, 3x3 Scharr 필터는 3x3 Sobel 필터보다 좋은 결과를 내기에 사용한다. 커널 문서를 참고하자.

2. Laplacian Derivatives

주어진 식(편미분)으로 이미지의 Laplacian을 계산한다.

Δsrc=2srcx2+2srcy2

편미분은 Sobel 알고리즘을 사용한다. ksize가 1일 경우 아래의 커널을 사용한다.

kernel=010111120

Code

아래의 코드는 모든 연산자를 단일 다이어그램으로 표시한다. 모든 커널은 5x5 크기이다. 출력 이미지의 깊이는 np.uint8 타입으로 결과를 얻기 위해 -1을 입력한다.

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

img = cv2.imread('./images/block.jpg',0)

laplacian = cv2.Laplacian(img,cv2.CV_64F)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)

plt.figure(figsize=(12,8))
plt.subplot(2,2,1), plt.imshow(img,'gray')
plt.title('Original'), plt.axis('off')
plt.subplot(2,2,2), plt.imshow(laplacian,'gray')
plt.title('Laplacian'), plt.axis('off')
plt.subplot(2,2,3), plt.imshow(sobelx,'gray')
plt.title('Sobel X'), plt.axis('off')
plt.subplot(2,2,4), plt.imshow(sobely,'gray')
plt.title('Sobel Y'), plt.axis('off')
plt.show()


sobel x의 경우 세로선이 강조되고, sobel y의 경우 반대로 가로선이 강조된다.

One Important Matter!

마지막 예에서, 결과 데이터타입은 cv2.CV_8U나 np.uint8이다. 하지만 이 부분에 살짝 문제가 있다. 검정에서 흑백(B2W) 전환은 양의 기울기(양수 값이 있음), 백흑(W2B) 전환은 음의 기울기로 취한다. 그래서 데이터를 np.uint8로 변환할 때, 모든 음의 기울기는 0으로 만들어진다. 간단하게, 가장자리를 놓친다는 것이다.

만약에 양쪽의 가장자리를 인식하고 싶으면, cv2.CV_16S, cv2.CV_64F등과 같은 상위 형태로 유지하고, 절대값을 취하고 cv2.CV_8U로 다시 변환하는 것이 더 나은 선택될 수 있다. 아래의 코드는 수평 Sobel 필터 와 다른 결과의 과정을 증명한다.

img = cv2.imread('./images/box.jpg',0)

# 출력 데이터 타입 = cv2.CV_8U
sobelx8u = cv2.Sobel(img,cv2.CV_8U,1,0,ksize=5)

# 출력 데이터 타입 = cv2.CV_64F, 그리고 절대값 취ㅣ하고 cv2.CV_8U로 변환
sobelx64f = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
sobelx64f = np.absolute(sobelx64f)
sobel64f_to_8u = cv2.Sobel(sobelx64f,cv2.CV_8U,1,0,ksize=5)

plt.figure(figsize=(12,8))
plt.subplot(1,3,1), plt.imshow(img,'gray')
plt.title('Original'), plt.axis('off')
plt.subplot(1,3,2), plt.imshow(sobelx8u,'gray')
plt.title('Sobel CV_8U'), plt.axis('off')
plt.subplot(1,3,3), plt.imshow(sobel64f_to_8u,'gray')
plt.title('Sobel abs[CV_64F]'), plt.axis('off')
plt.show()


기존의 8U의 경우는 좌측 가장자리만 인식하여 4개의 선을 보여준다. 반면에 64F -> 절대값 -> 8U로 한 것은 양쪽 가장자리를 다 인식하여 총 8개의 직선을 보여준다.

728x90
반응형