10장. Sobel 과 Laplacian 경계 검출
Sobel 연산자
떡볶이 가게 세 곳의 맛을 견줄 때 한 그릇만 먹고 판단하면, 그날 따라 짜게 나온 그릇 때문에 틀릴 수 있습니다. 같은 가게에서 위아래로 이웃한 그릇까지 맛보되 가운데 그릇에 조금 더 무게를 두면 더 믿을 만합니다. Sobel 연산자가 이렇게 합니다. 가로로 빼기([-1, 0, 1])를 하되, 한 줄만 보지 않고 위·가운데·아래 세 줄을 1-2-1 무게로 섞어서 뺍니다.
![빼기 [-1, 0, 1] 과 무게 [1, 2, 1] 을 나란히 놓고, 두 줄을 곱해 Sobel 커널을 만든다는 비교 그림](assets/img/diagram/ch10_sobel_idea.svg)
왼쪽 상자가 변화량을 재는 빼기, 오른쪽 상자가 세 줄을 섞는 무게입니다. 1-2-1 은 6장의 Gaussian 필터에서 본 무게로, 살짝 흐리게 해서 노이즈 한 칸에 덜 흔들리게 합니다. 여기서 한 그릇의 맛이 한 줄의 변화량이고, 이웃 그릇까지 맛보는 일이 1-2-1 무게입니다.
산호 칸은 빼고, 연두 칸은 더하고, 크림 칸(0)은 쓰지 않습니다. x 방향 커널은 오른쪽 열을 더하고 왼쪽 열을 빼며, 가운데 줄에 2 를 줍니다. y 방향 커널은 같은 표를 눕힌 꼴로, 아래 줄을 더하고 위 줄을 뺍니다. 무게 1-2-1 을 세로로 세우고 빼기 -1, 0, 1 을 가로로 눕혀 칸마다 곱하면 x 방향 커널이 나옵니다(예: 둘째 줄 첫 칸 = 2 × (−1) = −2).
커널로 손계산하기
네모의 왼쪽 변(가로 60)에 걸친 3×3 이웃입니다. 위·가운데·아래 줄이 모두 50, 50, 200 입니다.
| 단계 | 계산 |
|---|---|
| ① 왼쪽 열 × 왼쪽 무게 | 50 × (−1) + 50 × (−2) + 50 × (−1) = −200 |
| ② 가운데 열 × 0 | 0 |
| ③ 오른쪽 열 × 오른쪽 무게 | 200 × 1 + 200 × 2 + 200 × 1 = 800 |
| ④ 모두 더하기 | −200 + 0 + 800 = 600 |
[-1, 0, 1] 로는 150 이었는데 Sobel 은 600 입니다. 무게 1 + 2 + 1 = 4 를 곱한 만큼 커졌습니다. 값의 크기는 커널마다 다르므로, 숫자 자체보다 "경계에서 크고 고른 면에서 0"이라는 점을 봅니다.
cv2.Sobel 의 인자
| 순서 | 인자 | 이 장의 보통 값 | 뜻 |
|---|---|---|---|
| 1 | src | img | 입력 그림. 보통 흑백 |
| 2 | ddepth | cv2.CV_64F | 결과의 자료형. 음수를 담으려면 소수 |
| 3 | dx | 1 또는 0 | 가로로 몇 번 뺄까. 1 이면 가로 기울기 |
| 4 | dy | 0 또는 1 | 세로로 몇 번 뺄까. 1 이면 세로 기울기 |
| 5 | ksize | 3 | 커널 크기. 1, 3, 5, 7 중 하나. 기본값 3 |
짧은 예시
import cv2
img = cv2.imread("ch10_shapes.png", cv2.IMREAD_GRAYSCALE)
gx = cv2.Sobel(img, # src: 흑백 그림
cv2.CV_64F, # ddepth: 음수까지 담는 64비트 소수
1, # dx: 가로로 한 번 뺀다
0, # dy: 세로로는 빼지 않는다
ksize=3) # ksize: 3×3 커널
print(gx[80, 57:63].tolist()) # 결과: [0.0, 0.0, 600.0, 600.0, 0.0, 0.0] → 밝아지는 왼쪽 변
print(gx[80, 137:143].tolist()) # 결과: [0.0, 0.0, -600.0, -600.0, 0.0, 0.0] → 어두워지는 오른쪽 변
# dx=0, dy=1 이면 세로 기울기
gy = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
print(gy[37:43, 100].tolist()) # 결과: [0.0, 0.0, 600.0, 600.0, 0.0, 0.0] → 네모의 위 변손계산의 600 이 그대로 나옵니다. 네모의 오른쪽 변은 200 에서 50 으로 어두워지므로 −600 입니다.
주의할 점
dx=1, dy=1을 함께 주면 가로·세로 기울기 두 장이 나오는 것이 아니라, 가로로 빼고 다시 세로로 뺀 전혀 다른 값 한 장이 나옵니다. 두 방향이 필요하면cv2.Sobel을 두 번 부릅니다.ksize는 1, 3, 5, 7 처럼 홀수만 됩니다. 1 을 주면 무게 없이[-1, 0, 1]만 씁니다.