OpenCV 비전 실무6장 · 평균 필터와 Gaussian 필터4 / 21← 이전목차다음 →MetaContents

6장. 평균 필터와 Gaussian 필터

필터와 커널

신문의 작은 글씨를 돋보기로 한 군데씩 옮겨 가며 읽는 장면을 떠올려 봅시다. 돋보기는 늘 둘레 몇 글자를 함께 보여 줍니다. 필터도 사진 위에 작은 창을 올려놓고, 창 안의 이웃 칸들을 보고 가운데 칸의 새 값을 정합니다. 그리고 한 칸 옆으로 옮겨 같은 일을 되풀이합니다. 이 창에 적힌 작은 숫자 표가 커널입니다.

커널 놓기, 칸마다 곱하기, 모두 더하기, 가운데에 쓰고 옮기기의 네 단계 흐름도

그림의 네 단계가 칸 하나의 새 값을 정하는 순서입니다. 이 네 단계를 모든 칸에서 되풀이하면 새 사진 한 장이 됩니다. 여기서 돋보기가 커널이고, 돋보기에 비친 글자들이 이웃 칸이고, 돋보기를 옮기며 읽는 일이 필터를 거는 일입니다. 비유와 다른 점이 하나 있습니다. 돋보기는 보기만 하지만, 커널은 칸마다 무게(곱할 숫자)를 가지고 있어 계산을 합니다.

3×3 커널로 손계산하기

노이즈 때문에 가운데 칸만 145 로 튀어 오른 곳이 있다고 해 봅시다. 평균 필터의 커널은 아홉 칸이 모두 1/9 입니다.

3×3 이웃의 숫자, 1/9 씩 채운 커널, 곱해 더한 결과 105 를 차례로 놓은 계산 그림

왼쪽이 이웃 아홉 칸의 밝기, 가운데가 커널, 오른쪽이 결과입니다. 칸마다 같은 자리의 숫자끼리 곱해 모두 더하면 가운데 칸의 새 값이 됩니다.

단계계산
① 이웃 아홉 칸98, 103, 101, 97, 145, 99, 102, 100, 96
② 칸마다 1/9 을 곱해 더하기(98 + 103 + 101 + 97 + 145 + 99 + 102 + 100 + 96) × 1/9
③ 더한 값941 × 1/9 = 104.56
④ 정수로 반올림105

145 로 튀었던 칸이 105 가 되었습니다. 둘레가 100 근처이므로 튄 값이 이웃에 섞여 크게 누그러진 것입니다.

짧은 예시

Python
import numpy as np

patch = np.array([[98, 103, 101],
                  [97, 145, 99],
                  [102, 100, 96]], dtype=np.float64)
# 평균 필터의 커널: 아홉 칸 모두 1/9
kernel = np.full((3, 3), 1 / 9)

# 같은 자리끼리 곱한 뒤(*) 모두 더한다(sum)
value = (patch * kernel).sum()
print(round(float(value), 2), round(float(value)))   # 결과: 104.56 105

np.full((3, 3), 1 / 9) 은 3×3 칸을 모두 1/9 로 채운 표입니다. full 은 "가득 채운"이라는 뜻입니다.

주의할 점

  • 새 값은 원래 그림의 이웃으로 계산합니다. 앞 칸에서 이미 바꾼 값을 다음 칸의 계산에 쓰지 않습니다. OpenCV 는 결과를 새 그림에 따로 담으므로 걱정하지 않아도 됩니다.
  • 커널을 밀며 곱해 더하는 계산을 넓게 합성곱이라고 부릅니다. 딥러닝의 CNN 은 이 커널의 숫자를 사람이 정하지 않고 데이터로 배웁니다.
← 이전 절6장 · 노이즈란다음 절 →6장 · 평균 필터