11장. Canny 와 Edge 비교
3단계 비최대 억제
산맥을 옆에서 바라보면 능선을 따라 높은 곳이 이어집니다. 산의 높이를 그리려는데 비탈까지 모두 칠하면 산이 뭉툭한 덩어리로 보입니다. 능선의 가장 높은 곳만 점으로 찍어 이으면 날렵한 선 하나가 됩니다. 비최대 억제는 기울기 크기라는 산에서 꼭대기만 남기고 옆 비탈을 지우는 단계입니다.
왼쪽은 경계를 가로지르는 한 줄의 기울기 크기 다섯 칸입니다. 90 이 꼭대기이고 양옆의 40, 60 은 비탈입니다. 칸마다 기울기 방향의 이웃 두 칸과 견줘, 둘 다보다 크거나 같으면 남기고 아니면 0 으로 지웁니다. 오른쪽처럼 90 만 남습니다. 여기서 능선의 꼭대기가 기울기 크기가 가장 큰 칸이고, 비탈이 그 옆의 칸들입니다.
손으로 계산해 보기
기울기 방향이 0도(왼쪽·오른쪽 이웃과 견줌)인 한 줄 10, 40, 90, 60, 20 입니다. 양 끝 칸은 바깥 이웃을 0 으로 칩니다.
| 칸 | 크기 | 왼쪽 이웃 | 오른쪽 이웃 | 둘 다보다 크거나 같은가 | 결과 |
|---|---|---|---|---|---|
| 1 | 10 | 0 | 40 | 아니다 | 0 |
| 2 | 40 | 10 | 90 | 아니다 | 0 |
| 3 | 90 | 40 | 60 | 그렇다 | 90 |
| 4 | 60 | 90 | 20 | 아니다 | 0 |
| 5 | 20 | 60 | 0 | 아니다 | 0 |
실제 그림에서도 같습니다. 도형 그림의 원 테두리 한 부분을 크게 키웠습니다. 왼쪽은 블러 뒤 기울기 크기가 50 을 넘는 칸으로, 테두리를 따라 4~5칸 두께의 띠입니다. 오른쪽은 비최대 억제 뒤 50 을 넘는 칸으로, 띠가 한 칸 두께의 선으로 깎였습니다.
짧은 예시
import numpy as np
row = np.array([10, 40, 90, 60, 20])
# 양 끝에 0 을 하나씩 붙여 모든 칸이 왼쪽·오른쪽 이웃을 갖게 한다
padded = np.pad(row, 1)
left, right = padded[:-2], padded[2:]
# 이웃 두 칸보다 크거나 같은 칸만 남긴다
kept = np.where((row >= left) & (row >= right), row, 0)
print(kept.tolist()) # 결과: [0, 0, 90, 0, 0]np.pad(row, 1) 은 배열의 양 끝에 0 을 한 칸씩 덧붙입니다(pad 는 "덧대다"라는 뜻). 그러면 padded[:-2] 가 칸마다 왼쪽 이웃, padded[2:] 가 오른쪽 이웃이 됩니다.
주의할 점
- 비최대 억제는 칸을 지우기만 하고 새로 만들지 않습니다. 남은 칸의 값도 바꾸지 않습니다.
- 이 단계만으로는 아주 약한 꼭대기(바탕의 작은 얼룩)도 남습니다. 그런 칸은 4단계의 기준값이 걸러 냅니다.