10장. Sobel 과 Laplacian 경계 검출
커널 크기와 Scharr
돋보기 대신 넓은 창으로 거리를 내다보면 자잘한 얼룩은 덜 보이고 큰 건물의 윤곽이 또렷해집니다. 대신 바짝 붙은 두 간판은 하나로 뭉쳐 보입니다. Sobel 의 ksize 를 키우는 일이 이렇습니다. 커널이 넓을수록 더 넓게 흐리며 빼므로 노이즈에 덜 흔들리지만, 경계가 굵어지고 가까운 선끼리 붙습니다.
세 상자는 자주 쓰는 세 가지 선택지입니다. ksize=3 이 기본이고, 노이즈가 많으면 5 로 키웁니다. Scharr 는 3×3 크기를 지키면서 무게를 3-10-3 으로 바꿔, 비스듬한 경계의 방향을 Sobel 3×3 보다 더 정확히 잽니다. 여기서 창의 넓이가 커널 크기입니다.
네모의 왼쪽 변(가로 60) 둘레에서 잰 gx 입니다. 초록(ksize=3)은 두 칸에서 600, 보라(Scharr)는 두 칸에서 2,400, 다홍(ksize=5)은 네 칸에 걸쳐 솟고 가장 높은 곳이 7,200 입니다. 크기가 클수록 경계가 넓게 퍼지고 값이 커집니다.
세 커널 견주기
| 커널 | 가로 기울기 커널의 무게 | 계단 150 에서의 값 | 경계 폭 | 쓰는 법 |
|---|---|---|---|---|
| Sobel 3×3 | 1-2-1 | 150 × 4 = 600 | 2칸 | cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3) |
| Scharr 3×3 | 3-10-3 | 150 × 16 = 2,400 | 2칸 | cv2.Scharr(img, cv2.CV_64F, 1, 0) |
| Sobel 5×5 | 1-4-6-4-1 쪽으로 넓다 | 7,200 | 4칸 | cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5) |
짧은 예시
import cv2
img = cv2.imread("ch10_shapes.png", cv2.IMREAD_GRAYSCALE)
for name, g in [("Sobel 3", cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)),
("Scharr", cv2.Scharr(img, cv2.CV_64F, 1, 0)),
("Sobel 5", cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5))]:
line = g[80, 50:71]
# 가장 큰 값과, 0 이 아닌 칸 수(경계 폭)
print(name, int(line.max()), int((line != 0).sum()))
# 결과: Sobel 3 600 2 / Scharr 2400 2 / Sobel 5 7200 4cv2.Scharr 는 커널 크기를 받지 않습니다. 언제나 3×3 입니다. cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=-1) 처럼 ksize 에 −1 을 주어도 Scharr 커널을 씁니다.
주의할 점
- 커널마다 값의 크기가 다르므로, 크기 그림에 임계값을 걸 때는 쓴 커널에 맞춰 기준을 다시 정합니다. ksize 3 에서 정한 기준 100 을 ksize 5 에 그대로 쓰면 경계가 너무 많이 남습니다.
- 경계를 가늘게 지키고 싶으면
ksize=3을 쓰고, 노이즈는 다음 절처럼 블러로 먼저 줄이는 편이 낫습니다.