10장. Sobel 과 Laplacian 경계 검출
기울기: 옆 칸끼리 빼기
산길을 걸을 때 "한 걸음에 몇 cm 오르는가"를 재면 길이 얼마나 가파른지 알 수 있습니다. 평지에서는 0cm, 완만한 비탈에서는 조금, 계단에서는 한 걸음에 크게 오릅니다. 그림에서는 한 걸음이 옆 칸 하나입니다. 오른쪽 칸의 밝기에서 왼쪽 칸의 밝기를 빼면 "한 칸 옮길 때 밝기가 얼마나 바뀌나"가 나옵니다. 이 값이 변화량이고, 변화량으로 잰 가파른 정도를 기울기라고 부릅니다.
![한 줄의 밝기 50, 50, 50, 200, 200 과, 옆 칸 빼기 결과, [-1, 0, 1] 커널 결과를 위아래로 놓은 계산 그림](assets/img/diagram/ch10_diff_calc.svg)
맨 위 줄이 밝기 다섯 칸입니다. 가운데 줄은 옆 칸끼리 뺀 값으로, 칸과 칸 사이마다 하나씩 나옵니다. 50 과 50 사이는 0, 50 과 200 사이만 150 입니다. 아래 줄은 다음에 볼 [-1, 0, 1] 커널의 결과로, 칸마다 "오른쪽 이웃 − 왼쪽 이웃"을 적습니다. 여기서 한 걸음이 옆 칸 하나이고, 한 걸음에 오른 높이가 변화량입니다. 수학에서는 이런 계산을 미분이라고 부르지만, 이 과정에서는 "변화량을 재는 계산"이라고만 생각하면 됩니다.
손으로 계산하기
| 칸 번호 | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| 밝기 | 50 | 50 | 50 | 200 | 200 |
| 옆 칸 빼기 (오른쪽 − 자기) | 50 − 50 = 0 | 50 − 50 = 0 | 200 − 50 = 150 | 200 − 200 = 0 | (오른쪽 없음) |
[-1, 0, 1] (오른쪽 − 왼쪽) | (왼쪽 없음) | 50 − 50 = 0 | 200 − 50 = 150 | 200 − 50 = 150 | (오른쪽 없음) |
옆 칸 빼기는 칸 2 에서만 150 이고, [-1, 0, 1] 은 칸 2 와 칸 3 두 칸에서 150 입니다. [-1, 0, 1] 은 자기 칸을 건너뛰고 양옆을 빼므로, 경계를 사이에 둔 두 칸이 모두 큰 값을 받습니다. 경계는 그 두 칸 사이에 있습니다. 거꾸로 200 에서 50 으로 떨어지는 곳이면 값이 −150 이 됩니다. 부호는 밝아지는지(+) 어두워지는지(−)를 알려 줍니다.
짧은 예시
import numpy as np
row = np.array([50, 50, 50, 200, 200])
# np.diff: 옆 칸끼리 뺀 값(오른쪽 − 왼쪽)을 돌려준다. 칸이 하나 줄어든다
print(np.diff(row).tolist()) # 결과: [0, 0, 150, 0]
# [-1, 0, 1] 을 손으로: 칸마다 오른쪽 이웃 − 왼쪽 이웃
print((row[2:] - row[:-2]).tolist()) # 결과: [0, 150, 150] → 칸 1, 2, 3 의 값np.diff 의 diff 는 difference(차이)를 줄인 이름입니다. row[2:] - row[:-2] 는 "두 칸 오른쪽으로 민 줄"에서 "원래 줄"을 빼서, 칸마다 양옆의 차이를 한 번에 구합니다.
주의할 점
- 그림에서 바로 꺼낸 줄은
uint8입니다.uint8끼리 빼서 음수가 되면 1장에서 본 시계 바늘처럼 돌아가, 50 − 200 이 106 이 됩니다. 빼기 전에astype(int)로 바꿉니다. 실습 1에서 직접 봅니다. - 변화량은 "얼마나 밝은가"가 아니라 "얼마나 바뀌나"입니다. 50 → 200 과 100 → 250 은 밝기가 달라도 변화량은 똑같이 150 입니다.