11장. Canny 와 Edge 비교
1단계 블러와 2단계 기울기
비탈길에 자갈이 잔뜩 깔려 있으면, 발바닥으로 느끼는 기울기가 자갈 하나하나 때문에 들쭉날쭉합니다. 자갈을 고르게 쓸어 낸 뒤에야 "여기서부터 오르막"이 또렷이 느껴집니다. Canny 의 1단계 블러가 자갈을 쓸어 내는 일이고, 2단계가 비탈의 세기와 방향을 재는 일입니다.
그림처럼 블러로 노이즈를 줄인 뒤 10장의 Sobel 로 가로 기울기(gx)와 세로 기울기(gy)를 재고, 두 값을 합쳐 크기를, 두 값의 비율로 방향을 구합니다. Canny 는 방향을 0도, 45도, 90도, 135도 네 갈래로 반올림해서 씁니다. 여기서 자갈이 노이즈, 비탈의 세기가 기울기 크기, 오르막 쪽이 기울기 방향입니다.
10차시에서 가져올 것
| 낱말 | 10차시에서 배운 뜻 | Canny 에서 쓰는 곳 |
|---|---|---|
| 기울기 | 옆 칸끼리 밝기를 뺀 값 | 경계 후보를 찾는 재료 |
| gx, gy | 가로로, 세로로 잰 기울기(cv2.Sobel) | 크기와 방향 계산 |
| 기울기의 크기 | gx 와 gy 를 합친 세기(cv2.magnitude) | 3·4단계에서 견주는 값 |
| 기울기의 방향 | 밝기가 가장 가파르게 바뀌는 쪽(cv2.phase) | 3단계에서 어느 이웃과 견줄지 정한다 |
| 블러를 먼저 하는 까닭 | 노이즈도 옆 칸과 차이가 커서 기울기가 크게 나온다 | 1단계 |
기울기 크기 두 가지
cv2.Canny 는 크기를 두 가지로 잴 수 있습니다. gx = 30, gy = 40 인 칸으로 계산해 봅니다.
| 방법 | 식 | 계산 | 결과 | ||||
|---|---|---|---|---|---|---|---|
| 기본값(L1) | \ | gx\ | + \ | gy\ | 30 + 40 | 70 | |
| L2gradient=True | √(gx² + gy²) | √(900 + 1600) = √2500 | 50 |
L1 은 절댓값을 더하기만 해서 빠르지만 조금 크게 나옵니다. L2 는 10장의 피타고라스 크기와 같습니다.
방향을 네 갈래로 반올림하기
왼쪽 그림은 방향 0~180도를 네 구역으로 나눈 것입니다. 22.5도보다 작거나 157.5도 이상이면 0도, 22.5~67.5도면 45도, 67.5~112.5도면 90도, 112.5~157.5도면 135도로 반올림합니다. 오른쪽의 3×3 칸 네 장은 방향마다 3단계에서 견줄 이웃 두 칸(다홍)을 보여 줍니다. 0도는 왼쪽·오른쪽, 90도는 위·아래, 45도와 135도는 대각선 이웃입니다.
짧은 예시
import numpy as np
# 칸 세 개의 (gx, gy) 로 방향을 구하고 네 갈래로 반올림한다
for gx, gy in [(100, 5), (60, 70), (-50, 80)]:
# arctan2: 두 값의 비율로 각도를 구한다. degrees 로 도 단위로 바꾸고 0~180 으로 접는다
angle = np.degrees(np.arctan2(gy, gx)) % 180 # 그림 전체라면 10차시의 cv2.phase 를 쓴다
# 45 로 나눠 반올림하고 4 로 나눈 나머지에 45 를 곱하면 0, 45, 90, 135 가운데 하나
rounded = int(np.round(angle / 45) % 4 * 45)
print(f"gx={gx:4}, gy={gy:3} → {round(float(angle), 1):5}도 → {rounded}도")교안 PC 에서는 2.9도 → 0도, 49.4도 → 45도, 122.0도 → 135도가 나옵니다. 그림의 y 축은 아래로 갈수록 커지므로, 45도는 오른쪽 아래를 가리킵니다.
주의할 점
- 방향은 경계선의 방향이 아니라 경계선과 직각인 쪽입니다. 세로로 선 경계는 밝기가 가로로 바뀌므로 방향이 0도입니다.
- 블러를 너무 세게 하면 약한 경계의 기울기까지 작아져 놓칩니다. 실습 4에서 블러 크기마다 견줘 봅니다.