신호 처리 관점에서 잡음이란 원본 신호에 추가된 원치 않은 신호를 의미한다. 영상에서 잡음은 주로 영상을 획득하는 과정에서 발생하며, 디지컬 카메라에서 사진을 촬영하는 경우에는 광학적 신호를 전기적 신호로 변환하는 센서에서 주로 잡음이 추가된다.
f(x, y) = s(x, y) + n(x, y)
원본신호가 s, 잡음을 n 이라고 표현하면 실제로 획득되는 영상 신호는 f로 표현된다. 가장 대표적인 잡음모델은 가우시안 잡음 모델이다. 표준 편차가 작은 가우시안 잡음 모델일 수록 잡음에 의한 픽셀 값 변화가 적고, 표준 편차가 클수록 잡음에 의한 픽셀 값 변화가 크게 나타난다.
위 개념을 이용해 OpenCV 함수를 이용하여 영상에 인위적으로 잡음을 추가할 수 있다.
void randn(InputOutputArray dst, InputArray mean, InputArray stddev);
dst : 가우시안 난수로 채워질 행렬
mean : 가우시안 분포 평균
stddev : 가우시안 분포 표준 편차
void noise_gaussian() {
Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return;
}
imshow("src", src);
for (int stddev = 10; stddev <= 30; stddev += 10) {
Mat noise(src.size(), CV_32SC1);
randn(noise, 0, stddev);
Mat dst;
add(src, noise, dst, Mat(), CV_8U);
String desc = format("stddev = %d", stddev);
putText(dst, desc, Point(10, 30), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255), 1, LINE_AA);
imshow("dst", dst);
waitKey();
}
destroyAllWindows();
}
픽셀 값이 급격하게 변경되는 에지 근방에 동일한 가우시안 필터가 적용되면 잡음 뿐아니라 에지 성분까지 함께 감소하게 된다. 즉, 잡음이 줄어 들면서 함께 에지도 무뎌져 윤곽이 흐릿해 지는 것이다.
이 단점을 보완하기 위해 에지 정보는 그대로 유지하며 잡음만 제거하는 에지 보전 잡음 제거 필터에 대해 연구 했고, 그 알고리즘 중 양방향 필터가 있다.
양방향 필터는 두 점 사이의 거리에 대한 가우시안 함수와, 두점의 픽셀 값 차이에 의한 가우시안 함수를 모두 고려하여 연산한다. 에지를 사이에 두는 두 픽셀에 대해 픽셀 값의 차가 크게 나타나므로 상대적으로 가우시안 함수가 0에 가까운 값이 되는 것이다. 이로인해 가우시안 블러링 효과가 거의 나타나지 않고 에지가 보존된다.!
OpenCV 에서는 bilateralFilter()함수를 이용하여 양방향 필터를 수행할 수 있다.
bilateralFilter()
void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType = BORDER_DEFAULT);
src : 입력영상
dst : 출력영상
d : 필터링에 사용할 이웃 픽셀과의 거리
sigmaColor : 색 공간에서의 가우시안 필터 표준 편차
sigmaSpace : 좌표 공간에서의 가우시안 필터 표준 편차
borderType : 가장자리 픽셀 확장 방식
randn()
가우시안 잡음으로 구성된 행렬을 생성하여 반환
void randn(InputOutputArray dst, InputArray mean, InputArray stddev);
void filter_bilateral() {
Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return;
}
imshow("src", src);
Mat noise(src.size(), CV_32SC1);
randn(noise, 0, 5);
add(src, noise, src, Mat(), CV_8U);
Mat dst1;
GaussianBlur(src, dst1, Size(), 5);
Mat dst2;
bilateralFilter(src, dst2, -1, 10, 5);
imshow("dst1", dst1);
imshow("dst2", dst2);
waitKey();
destroyAllWindows();
}
입력 영상에서 자기 자신 픽셀과 주변 픽셀 값 중에서 중간값을 선택하여 결과 영상 픽셀 값으로 설정하는 필터링 기법이다. 마스크 행렬과 입력 영상 픽셀값을 서로 곱한후 모두 더하는 형태의 연산을 사용하지 않고, 주변 픽셀 값들의 중간값을 선택하기 위해 내부에서 픽셀 값 정렬 과정이 사용된다.
OpenCV 에서는 medianBlur() 함수를 이용하여 미디언 필터링을 수행할 수 있다.
medianBlur()
void medianBlur(InputArray src, OutputArray dst, int ksize);
src : 입력영상
dst : 출력영상
ksize : 필터 크기
void filter_median() {
Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return;
}
int num = (int)(src.total() * 0.1);
for (int i = 0; i < num; i++) {
int x = rand() % src.cols;
int y = rand() % src.rows;
src.at<uchar>(y, x) = (i % 2) * 255;
}
Mat dst1;
GaussianBlur(src, dst1, Size(), 1);
Mat dst2;
medianBlur(src, dst2, 3);
imshow("src", src);
imshow("dst1", dst1);
imshow("dst2", dst2);
waitKey();
destroyAllWindows();
}