Edge Filter
기본 미분 필터
경계(엣지)를 검출하기 위해서는 픽셀 값이 급격하게 변하는 지점을 찾아야 합니다. 경계 부분에서는 당연히 픽셀 값이 급격히 변하겠죠? 이는 연속된 픽셀 값에 미분을 하여 찾아낼 수 있습니다. 하지만 픽셀은 연속 공간 안에 있지 않으므로 미분 근사값을 구해야 합니다. 미분 근사값은 간단합니다. 서로 붙어 있는 픽셀 값을 빼면 됩니다. x방향, y방향으로 각각 픽셀 값을 빼면 미분 근사값이 됩니다.
import numpy as np
gx_kernel = np.array([[ -1, 1]])
gy_kernel = np.array([[ -1],[ 1]])
edge_gx = cv2.filter2D(img, -1, gx_kernel)
edge_gy = cv2.filter2D(img, -1, gy_kernel)
x방향 미분 필터는 좌우 픽셀 값의 차를 기반으로 필터링했기 때문에 세로 방향의 경계를 검출한 것이고, 반대로 y방향 미분 필터는 상하 픽셀 값의 차를 기반으로 필터링했기 때문에 가로 방향의 경계를 검출한 것입니다.'
로버츠 교차 필터
로렌스 로버츠라는 미국 엔지니어는 기본 미분 필터를 개선한 로버츠 교차 필터를 제안했습니다.
이 커널은 대각선 방향으로 +1과 -1을 배치시켜 사선 경계 검출 효과를 높였습니다. 하지만 노이즈에 민감하다는 단점이 있습니다.
gx_kernel = np.array([[1,0], [0,-1]])
gy_kernel = np.array([[0, 1],[-1,0]])
edge_gx = cv2.filter2D(img, -1, gx_kernel)
edge_gy = cv2.filter2D(img, -1, gy_kernel)
프리윗 필터
프리윗 필터는 x축과 y축의 각 방향으로 차분을 세 번 계산하여 경계를 검출하는 필터입니다. 프리윗 필터는 상하/좌우 경계는 뚜렷하게 잘 검출하지만 대각선 검출이 약합니다.
gx_k = np.array([[-1,0,1], [-1,0,1],[-1,0,1]])
gy_k = np.array([[-1,-1,-1],[0,0,0], [1,1,1]])
edge_gx = cv2.filter2D(img, -1, gx_k)
edge_gy = cv2.filter2D(img, -1, gy_k)
소벨 필터
소벨 필터는 중심 픽셀의 차분 비중을 두 배로 준 필터입니다. 따라서 소벨 필터는 x축, y축, 대각선 방향의 경계 검출에 모두 강합니다.
앞서 설명한 로버츠 필터와 프리윗 필터는 현재는 거의 쓰이지 않습니다. 반면 소벨 필터는 실무적으로도 쓰이므로 OpenCV에서 별도의 함수를 제공합니다.
src: 입력 영상
ddepth: 출력 영상의 dtype (-1: 입력 영상과 동일)
dx, dy: 미분 차수 (0, 1, 2 중 선택, 둘 다 0일 수는 없음)
ksize: 커널의 크기 (1, 3, 5, 7 중 선택)
scale: 미분에 사용할 계수
delta: 연산 결과에 가산할 값
dst = cv2.Sobel(src, ddepth, dx, dy, dst, ksize, scale, delta, borderType)
샤르 필터
소벨 필터는 커널의 중심에서 멀어질수록 엣지 방향성의 정확도가 떨어집니다. 이를 개선한 필터가 샤르 필터입니다.
ksize가 없다는 것을 제외하면 모든 파라미터는 cv2.Sobel()과 동일합니다.
dst = cv2.Scharr(src, ddepth, dx, dy, dst, scale, delta, borderType)
라플라시안 필터
라플라시안 필터는 2차 미분을 적용한 필터입니다. 경계를 더 제대로 검출할 수 있습니다.
파라미터는 cv2.Sobel()과 동일합니다.
dst = cv2.Laplacian(src, ddepth, dst, ksize, scale, delta, borderType)
캐니 엣지
캐니 엣지는 지금까지 살펴본 것처럼 한 가지 필터만 사용하는 것이 아니라 다음의 4단계 알고리즘에 따라 경계를 검출합니다.
1. 노이즈 제거: 5 x 5 가우시안 블러링 필터로 노이즈 제거
2. 경계 그레디언트 방향 계산: 소벨 필터로 경계 및 그레디언트 방향 검출
3. 비최대치 억제(Non-Maximum Suppression): 그레디언트 방향에서 검출된 경계 중 가장 큰 값만 선택하고 나머지는 제거
4. 이력 스레시홀딩: 두 개의 경계 값(Max, Min)을 지정해서 경계 영역에 있는 픽셀들 중 큰 경계 값(Max) 밖의 픽셀과 연결성이 없는 픽셀 제거
img: 입력 영상
threshold1, threshold2: 이력 스레시홀딩에 사용할 Min, Max 값
apertureSize: 소벨 마스크에 사용할 커널 크기
L2gradient: 그레디언트 강도를 구할 방식 (True: 제곱 합의 루트 False: 절댓값의 합)
edges: 엣지 결과 값을 갖는 2차원 배열
edges = cv2.Canny(img, threshold1, threshold2, edges, apertureSize, L2gardient)