Canny Edge Detection¶
- 1986년 John F. Canny가 제안.
- Edge detection에서 가장 널리 사용되는 방법 중의 하나임.
Canny Edge Detection은 다음과 같이 4단계로 구성된 algorithm임.
단계 1: Noise Reduction
- Gussian Filtering을 하여 noise 제거
- edge 는 noise와 구분하기 어려운 특징 (gradient를 구할 경우, noise도 매우 큰 값을 가진다)을 가지므로 Gaussian filtering으로 이를 최대한 억제한 이후 gradient를 구하는게 일반적임.
단계 2: Gradient Extraction
- Sobel filter등을 이용하여 gradient 벡터의 magnitude 및 direction 을 추출.
- blurred image에서 모든 pixel 에서 1st derivative의 magnitude와 direction이 구해짐. (1st derivative, 1차 도함수, gradient)
단계 3: Non-maximum Supression
- \(3\times 3\) kernel을 사용하여 gradient vector 방향에서 gradient 크기가 최대값인 pixel 만 남기고 나머지는 0으로 제거.
- edge에 기여하지 않는 pixel들이 제거됨.
- NMS를 통해 thin edge 가 구해짐 (=검출된 edge가 가늘어짐).
- The resulting edge pixel들은 회색으로 배경색이 칠해짐.
- gradient vector가 항상 edge에 orthogonal (perpendicular) 한 성질을 이용함.
단계 4: Hysteresis Thresholding (=Double Thresholding)
- 연결된 edge를 얻기 위해 두 개의 threshold(임계치)을 사용.
Max_Threshold(threshold2)
를 사용하여 gradient 방향에서Min_Threshold(threshold1)
가 나올 때까지 추적(tracking)하여 edge를 연결해 나감.Max_Threshold
와 연결성이 없는 경우 edge에서 제거됨.
- Here,
A
andB
are sure-edges as they are aboveMax_Threshold
. Similarly,D
is a sure non-edge. - Both
E
andC
are weak edges but sinceC
is connected toB
which is a sure edge,C
is also considered as a strong edge. - Using the same logic
E
is discarded.
Hysteresis 는 우리나라 말로 이력현상 이라고 불림. 다음 URL에 간략히 설명되어 있음 : hysteresis
Sobel 함수나 Laplacian 과 같은 simple edge detection 을 통해 얻은 simple binary edge map 의 일반적으로 다음과 같은 단점이 있다.
- 첫째, 검출된 edge가 필요 이상으로 두꺼워 객체를 훨씬 더 식별 하기 어렵게 만든다. (← non maximum supression 가 해법)
- 둘째, 영상의 모든 중요한 edge를 검출하기 위한 명확한 threshold을 찾기가 어렵거나 불가능 할 때가 있다. (←hysteresis thresholding 가 해법)
이를 해결한 알고리즘이 바로 Canny Edge Algorithm 임.
위의 각 문제점에 대해 Canny algorithm 의 해법이 가로 안에 기재되어 있으니 이를 참고할 것.
cv2.Canny¶
OpenCV 에서는 cv2.Canny
를 통해 제공함. 다음과 같은 parameter로 구성됨.
- Gradient mangitude를 기본으로는 l1-norm으로 구함.
edge_map = cv2.Canny(
image,
min_threshold,
max_threshold,
edge_map=None, # result가 저장될 변수. return value로 처리해도 되어 None이 기본.
apertureSize=3, # Soble Filter의 kenrnel size.
L2gradient=False # grad. magnitude를 l2-norm로 구할지, l1-norm으로 구할지결정.
)
다음은 이를 이용한 간단한 예제임.
import cv2
import numpy as np
import matplotlib.pyplot as plt
from google.colab.patches import cv2_imshow # for goole colab
def get_img_cv(url):
image_ndarray = np.asarray(bytearray(requests.get(url).content), dtype=np.uint8)
img = cv2.imdecode(image_ndarray, cv2.IMREAD_COLOR)
print(img.shape)
return img
url = 'https://raw.githubusercontent.com/dsaint31x/OpenCV_Python_Tutorial/master/images/sudoku.jpg'
#img = cv2.imread(img_path)
img = get_img_cv(url)
print(img.shape,img.max(),img.min())
edge = cv2.Canny(img,120,200)
print(edge.shape)
cv2_imshow(edge)
관련 ipynb 파일은 다음 URL을 참고 : DIP_Canny_Edge_Detection