6장. 평균 필터와 Gaussian 필터
평균 필터
반 학생 아홉 명의 시험 점수를 한 사람씩 발표하면 한두 명이 유난히 높거나 낮아 들쭉날쭉합니다. 대신 "우리 모둠 평균"을 말하면 숫자가 고르게 다듬어집니다. 평균 필터는 칸마다 자기와 이웃의 평균을 새 값으로 씁니다. 튀는 칸은 이웃과 섞여 누그러지고, 고른 면은 그대로 고르게 남습니다.
그림의 세 상자는 OpenCV 에서 평균 필터를 거는 방법입니다. 왼쪽 둘은 같은 결과를 내고, 오른쪽은 평균을 내지 않고 합만 구합니다. 여기서 모둠이 커널 크기만큼의 이웃이고, 모둠 평균이 새 값입니다.
평균 필터를 거는 함수
| 함수 | 쓰는 법 | 하는 일 |
|---|---|---|
cv2.blur | cv2.blur(img, (3, 3)) | 3×3 이웃의 평균. 가장 간단하다 |
cv2.boxFilter | cv2.boxFilter(img, -1, (3, 3)) | cv2.blur 와 같다. 둘째 인자 -1 은 "원본과 같은 자료형으로" |
cv2.boxFilter + normalize=False | cv2.boxFilter(img, cv2.CV_32F, (3, 3), normalize=False) | 나누지 않고 아홉 칸의 합만. 합은 255 를 넘으므로 소수(CV_32F)로 받는다 |
normalize 는 "고르게 맞추다"라는 뜻으로, 여기서는 칸 수로 나눠 평균을 낸다는 말입니다. CV_32F 는 32비트 소수(float)라는 뜻입니다. ksize 는 (가로, 세로) 순서로 주며, 이 장에서는 늘 정사각형을 씁니다.
짧은 예시
import cv2
import numpy as np
# 고른 면(100) 가운데에 손계산과 같은 3×3 숫자를 넣은 5×5 그림
a = np.full((5, 5), 100, dtype=np.uint8)
a[1:4, 1:4] = [[98, 103, 101], [97, 145, 99], [102, 100, 96]]
# blur = 흐리게 하다. (3, 3) 은 커널 크기
print(int(cv2.blur(a, (3, 3))[2, 2])) # 결과: 105 → 손계산과 같다
print(int(cv2.boxFilter(a, -1, (3, 3))[2, 2])) # 결과: 105 → blur 와 같다
print(float(cv2.boxFilter(a, cv2.CV_32F, (3, 3), normalize=False)[2, 2])) # 결과: 941.0 → 합a[2, 2] 가 손계산의 가운데 칸입니다. 손으로 구한 105 와 OpenCV 가 구한 105 가 같습니다.
주의할 점
- 평균 필터는 튄 칸을 없애지 않고 이웃에 나눠 퍼뜨립니다. 145 의 튄 몫이 둘레 여덟 칸에도 조금씩 섞여, 둘레의 100 근처 칸들도 104~105 로 오릅니다.
- 컬러 그림에 걸면 B, G, R 채널마다 따로 평균을 냅니다. 함수는 같습니다.