이번엔 http://opencvexamples.blogspot.com/p/learning-opencv-functions-step-by-step.html에 있는 6번째 예제를 공부하자.
6. Gaussian Filter, Bilateral Filter, Median Filter
이 세 필터는 모두 이미지를 부드럽게 만드는, 즉 블러링(blurring) or smoothing에 사용되는 대표적인 필터들이다. 블러링을 하는 이유는 여러가지가 있지만, 여기서는 노이즈 제거하는 것에 초점을 맞춘다.
1) Gaussian Filter
현재 픽셀값과 주변 이웃 픽셀값들의 가중 평균(weighted average)을 이용해서 현재 픽셀의 값을 대체한다. 현재 픽셀에서 가까울수록 더 큰 가중치를 갖고 멀수록 더 작은 가중치를 갖는다. 가우시안 필터는 이미지는 공간적으로 천천히 변하기 때문에 가까이 있는 픽셀들은 비슷한 값들을 갖는다는 사실에 기반하여 만들어졌다. 그래서 노이즈 값은 상대적으로 이웃 픽셀들 값과 상관성이 작기 때문에 이웃 픽셀값들의 가중 평균의 방식으로 완화시킬 수 있다. 하지만 엣지(edge)와 같이 공간적으로 급변하는 부분에서는 단점을 보인다. 엣지도 무뎌진다. 이것도 사실 가우시안 필터의 중요한 장점이기도 하지만, 노이즈 제거의 목적에서는 단점이다. 노이즈는 제거하면서도 엣지 정보는 그대로 유지해야하기 때문이다. 이점을 보완하기 위해 Bilateral 필터가 나왔다.
GaussianBlur 함수는 아래와 같이 활용한다.
void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT )
각 파라미터들은 아래와 같은 의미를 갖는다.
- src: 소스 이미지
- dst: 목표 이미지, 즉 처리된 이미지를 담을 변수
- ksize: 가우시안 커널 사이즈로써 홀수여야 한다.
- sigmaX: 가우시안 커널의 x방향의 표준 편차
- sigmaY: 가우시안 커널의 y방향의 표준 편차
시그마 값들이 클수록 더 부드러워진다.
2) Bilateral Filter
Bilateral 필터는 엣지를 보존하면서 노이즈를 제거하는 비선형 필터다. 각 픽셀에서의 세기값은 주변 픽셀값의 가중평균으로 대체된다. 여기서 가중치는 현재 픽셀과 이웃하는 픽셀 사이의 유클리디안 거리 뿐만 아니라, radiometric 차이(예를 들어, 색깔 강도와 깊이 거리 등과 같은 range 차이들)와도 연관된다. 좀 더 쉽게 말하면, 현재 픽셀과 이웃하는 픽셀 사이의 거리와 픽셀값의 차이를 동시에 가중치에 반영한다. 픽셀 사이의 거리만을 가중치에 반영하는 가우시안 필터의 좀 더 발전된 버전이라 생각할 수 있다.
bilateralFilter 함수를 살펴보자.
void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT )
각 파라미터들은 아래와 같은 의미를 갖는다.
- src: 소스 이미지
- dst: 목표 이미지, 즉 처리된 이미지를 담을 변수
- d: Diameter of each pixel neighborhood that is used during filtering.
- sigmaColor: Filter sigma in the color space. A larger value of the parameter means that farther colors within the pixel neighborhood will be mixed together, resulting in larger areas of semi-equal color.
- sigmaSpace: Filter sigma in the coordinate space. A larger value of the parameter means that farther pixels will influence each other as long as their colors are close enough.
시그마값들이 클수록 더 강하게 영향을 미친다.
3) Median Filter
미디안 필터는 각 픽셀값을 이웃하는 픽셀들의 미디안 값으로 대체한다. 결과적으로 이미지가 부드러워진다.
void medianBlur(InputArray src, OutputArray dst, int ksize)
각 파라미터들은 아래와 같은 의미를 갖는다.
- src: 소스 이미지
- dst: 목표 이미지, 즉 처리된 이미지를 담을 변수
- ksize: 커널 사이즈로써 홀수여야하고 1보다 커야 한다. 즉 3부터 가능하다.
아래는 bilateralFilter, GaussianBlur, medianBlur 함수를 포함한 소스코드다. 노이즈를 최대한 없애는 쪽에 초점을 맞춰서 파라미터를 설정했다.
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat src = imread("hee_sp.bmp", 1);
Mat dst1, dst2, dst3;
Mat gray;
//Apply gaussian blur filter
GaussianBlur(src, dst2, Size(5, 5), 3, 3);
//Apply bilateral filter
bilateralFilter(src, dst1, 5, 250, 10);
//Apply median blur filter
medianBlur(src, dst3, 3);
imshow("source", src);
imshow("Gaussian filter result", dst2);
imshow("bilateral filter result", dst1);
imshow("median filter result", dst3);
waitKey(0);
return 0;
}
결과 이미지는 그림 1에 있다. 이 예제 이미지에서는 미디안 필터가 가장 효과적으로 salt&pepper 노이즈를 제거했다. 미디안 필터는 픽셀값들을 주변 픽셀들의 미디안 값(즉, 중간값)으로 대체하다보니, 한 픽셀씩 연관성없이 바뀌어 있는 salt&pepper 노이즈를 제거하는데는 매우 탁월한 것 같다. 반면 가우시안 필터는 노이즈를 어느 정도 제거했지만, 엣지도 둔화시켰다. bilateral 필터도 노이즈를 제거하는데는 일정부분 성공했지만, 엣지 정보가 손실되었다. 가우시안 필터 정도는 아니지만..
그림 1. 필터처리한 이미지들. 왼쪽 위부터 순서대로 원본 이미지, 가우시안 필터된 이미지, bilateral 필터된 이미지, 미디안 필터된 이미지.
그리고 추가로 히스토그램의 변화를 살펴봤다 (그림 2, 3, 4, 5). 그림 2는 원본이미지의 히스토그램이다. 픽셀값 0과 255에 뜬금없이 높이 솟구쳐 있는 것들이 노이즈와 관련된 것 같다.
그림 2. 원본 이미지 히스토그램
그림 3은 bilateral 필터된 이미지의 히스토그램이다. 픽셀값 0과 255에 뜬금없이 높이 솟구쳐 있는 것들이 사라졌음을 확인할 수 있다. 하지만 90과 180정도의 픽셀값들이 통째로 사라진 것도 확인할 수 있다 (자세히 보면 비어있다). 이유는 잘 모르겠다.
그림 3. bilateral 필터된 이미지 히스토그램
그림 4는 가우시안 필터된 이미지의 히스토그램이다. 픽셀값 0과 255에 뜬금없이 높이 솟구쳐 있는 것들이 사라졌음을 확인할 수 있다. 하지만 bilateral과 동일하게 90과 180정도의 픽셀값들이 통째로 사라진 것도 확인할 수 있다.
그림 4. 가우시안 필터된 이미지 히스토그램
그림 5는 미디안 필터된 이미지의 히스토그램이다. 역시 노이즈 픽셀값으로 추측되는 0과 255는 줄어들었다. 그리고 bilateral과 가우시안 필터의 결과와 같이 픽셀값들이 완전히 비어버리는 현상도 없다.
그림 5. 미디안 필터된 이미지의 히스토그램
<참고 자료>
[1] http://eehoeskrap.tistory.com/125, 코드를 간결하게 잘 소개해 놓으셨다.
[2] http://docs.opencv.org/2.4/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.html#smoothing, 필터들에 대한 전반적인 소개와 코드를 포함하고 있다.
[3] http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html#Introduction, 가우시안 필터와 bilateral 필터에 대해서 설명되어 있다.
[4] https://en.wikipedia.org/wiki/Bilateral_filter, bilateral 필터에 대한 위키피디아 설명.
'Dev > C, C++' 카테고리의 다른 글
포인터의 이해 (6) | 2017.10.09 |
---|---|
opencv에서 픽셀값 접근하기 (2) | 2017.07.05 |
[Learn opencv by examples] 8 (1). Sobel 엣지 검출 (6) | 2017.06.15 |
[Learn opencv by examples] 7. 2D 컨볼루션 / 새로운 필터 만들기 (0) | 2017.06.14 |
[Learn opencv by examples] 5. 영상 이진화, Threshold operation (0) | 2017.06.02 |
[Learn opencv by examples] 4. RGB 이미지를 그레이 영상 또는 다른 컬러 공간으로 전환하기 (0) | 2017.06.02 |
[Learn opencv by examples] 3. 기본적인 드로잉 예제들 (0) | 2017.05.16 |
[Learn opencv by examples] 2. 카메라로부터 비디오 캡쳐하기 (0) | 2017.05.12 |