더북(TheBook)

8.4.1 가우시안 잡음 생성

영상에서 잡음noise이란 영상의 픽셀 값에 추가되는 원치 않는 형태의 신호를 의미한다. 예를 들어 디지털 카메라로부터 영상을 획득하는 경우, 렌즈로부터 들어오는 광학 신호를 전기적 신호로 변환하는 센서sensor에 잡음이 추가될 수 있다. 그러므로 카메라로부터 획득한 영상을 f(x, y)라고 하고 실제로 카메라 렌즈가 바라보는 화면 신호를 s(x, y)라고 할 경우, 다음과 같은 관계가 성립된다.

f(x, y) = s(x, y) + n(x, y)

위 수식에서 n(x, y)는 잡음 신호를 나타낸다. 이러한 잡음은 항상 일정하지 않기 때문에 영상을 획득하는 시점에 따라 임의의 값으로 변할 수 있다. 즉, 카메라를 전혀 움직이지 않고 고정된 화면을 두 번 연속으로 촬영한다 하더라도, 획득된 두 영상은 완벽하게 동일한 픽셀 값을 가지지 않는다. 눈으로 보기에는 거의 동일한 밝기와 색상을 갖는 것처럼 보이지만 실제 픽셀 값을 살펴보면 아주 미세한 차이가 발생하는 것을 확인할 수 있을 것이다.

보통 카메라 센서에서 추가되는 잡음은 가우시안 분포 함수의 형태를 따른다. 이처럼 잡음으로 추가되는 값이 가우시안 함수 형태를 따르는 잡음을 가우시안 잡음Gaussian noise이라고 부른다. 가우시안 잡음은 앞서 배웠던 평균 값 필터, 가우시안 필터 등을 이용하여 어느 정도 그 효과를 감쇠시킬 수 있다. 그러나 평균 값 필터, 가우시안 필터 등은 잡음뿐만 아니라 엣지 같은 의미 있는 정보도 함께 뭉개는 효과가 있기 때문에 주의해서 사용해야 한다.

평균이 0이고, 표준 편차가 1인 가우시안 분포를 정상 분포normal distribution라고도 한다. 정상 분포를 갖는 난수를 발생시키기 위하여 이 책에서는 C++11에서 새로 도입된 유사 난수pseudorandom number 발생기를 사용하려고 한다. 기존의 C/C++에서는 오직 균일한 분포를 갖는 난수 생성 함수 rand()만을 제공하였지만 C++11부터는 정상 분포를 포함한 다양한 분포 형태의 유사 난수 발생 도구를 제공하고 있다. C++11에서 제공하는 정상 분포 난수 발생기를 이용하여 평균이 0이고, 표준 편차가 1인 가우시안 난수 10개를 발생시키기 위해서는 다음과 같이 코드를 작성하면 된다.

std::default_random_engine generator;
std::normal_distribution<double> distribution(0.0, 1.0);

for (int i = 0; i < 10; i++)
    std::cout << distribution(generator) << std::endl;

그러나 위 난수 발생 코드에는 한 가지 문제점이 있다. 위와 같은 코드를 프로그램에 추가하여 난수를 발생시켜 보면 항상 동일한 값의 난수가 차례대로 출력된다는 점이다. 물론 출력되는 실숫값들은 가우시안 분포를 따르고 있지만, 프로그램을 실행할 때마다 항상 동일한 값이 순서대로 나타나는 것은 바람직하지 않아 보인다. 이 점을 수정하기 위해 default_random_engine 객체 선언 시 임의의 숫자 값을 시드seed 값으로 부여해야 한다. 아래 소스 코드를 살펴보자.

unsigned int seed = static_cast<unsigned int>(time(NULL));
std::default_random_engine generator(seed);
std::normal_distribution<double> distribution(0.0, 1.0);

앞의 코드에서는 time() 함수를 이용하여 현재 시스템 시간을 초단위로 얻어와 시드 값으로 사용하였다. 그러므로 위 코드가 1초 이내의 동일한 시간에 실행되지 않는 한, 항상 다른 형태의 정상 분포 난수가 발생하게 될 것이다. 만약 더욱 정교한 시드 값을 사용하고자 한다면 C++11의 chrono 라이브러리를 사용하는 것이 좋으며, 이에 대해서는 다른 C++ 문서를 참고하기 바란다.

신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.