이미지 처리 분야에서 가우시안 필터(Gaussian Filter)는 노이즈를 효과적으로 줄이는 데 널리 사용되는 대표적인 기법입니다. 이미지 블러링(blurring)이나 에지 검출 전의 전처리 단계 등 다양한 용도로 활용되며, 그 핵심에는 2차원 가우시안 커널(kernel)이 있습니다. 이 글에서는 C++을 이용해 5×5 크기의 2D 가우시안 커널을 직접 생성하는 방법을 살펴보겠습니다.
2D 가우시안 분포 공식
2차원 가우시안 커널의 각 요소는 다음 수식으로 계산됩니다.
$$G(x,y)= \frac{1}{2\pi\sigma^{2}}e^{-\frac{x^{2}+y^{2}}{2\sigma^{2}}}$$
여기서 σ(sigma)는 분포가 얼마나 퍼져 있는지를 결정하는 표준 편차입니다. σ 값이 클수록 커널 전체가 완만해지고, 작을수록 값이 중앙에 집중됩니다.
C++ 구현 예제
아래 코드는 5×5 크기의 가우시안 커널을 생성하고 이를 출력하는 전체 구현 예제입니다.
#include <cmath>
#include <iomanip>
#include <iostream>
#define PI 3.1415
using namespace std;
void calc_filter(double kernel[][5]) {
double sigma = 1.0;
double p, q = 2.0 * sigma * sigma;
double sum = 0.0;
for (int x = -2; x <= 2; x++) {
for (int y = -2; y <= 2; y++) {
p = sqrt(x * x + y * y);
kernel[x + 2][y + 2] = (exp(-(p * p) / q)) / (PI * q);
sum += kernel[x + 2][y + 2];
}
}
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
kernel[i][j] /= sum;
}
int main() {
double kernel[5][5];
calc_filter(kernel);
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 5; ++j)
cout << kernel[i][j] << " ";
cout << endl;
}
}
코드 동작 원리
- sigma = 1.0 : 표준 편차를 1.0으로 설정하여 커널의 형태를 결정합니다.
- q = 2 × σ² : 지수 함수와 분모에서 반복적으로 사용되는 값을 미리 계산해 성능을 높입니다.
- -2부터 2까지 반복 : 커널의 중앙을 원점(0, 0)으로 간주하고 x, y 좌표를 순회하며 각 위치의 가우시안 값을 계산합니다. 인덱스 계산 시 +2를 더해 배열 범위(0~4)에 맞춥니다.
- 정규화(Normalization) : 모든 커널 요소의 합을 구한 뒤, 각 요소를 총합으로 나누어 합이 1이 되도록 만듭니다. 이 과정이 있어야 필터를 이미지에 적용했을 때 전체 밝기가 변하지 않습니다.
실행 결과
0.00296902 0.0133062 0.0219382 0.0133062 0.00296902 0.0133062 0.0596343 0.0983203 0.0596343 0.0133062 0.0219382 0.0983203 0.162103 0.0983203 0.0219382 0.0133062 0.0596343 0.0983203 0.0133062 0.00296902 0.00296902 0.0133062 0.0219382 0.0133062 0.00296902
실행 결과를 보면 커널의 중앙값(약 0.162)이 가장 크고, 중앙에서 멀어질수록 값이 대칭적으로 감소하는 것을 확인할 수 있습니다. 이는 가우시안 분포 특유의 종(bell-shaped) 모양을 그대로 반영한 것입니다. 또한 모든 요소의 합이 1에 가깝기 때문에, 이 커널을 이미지에 합성곱(convolution)하면 노이즈는 부드럽게 제거되면서도 전체적인 명도는 유지됩니다.
참고로 위 예제에서는 π를 3.1415로 근사했습니다. 더 높은 정밀도가 필요하다면 <cmath> 헤더에서 제공하는 M_PI 상수를 사용하는 것이 좋습니다.