정보공간_1

[6기 강북 이보희] 디지털 영상처리 - Filter 편 #1 본문

IT 놀이터/Elite Member Tech & Talk

[6기 강북 이보희] 디지털 영상처리 - Filter 편 #1

알 수 없는 사용자 2014. 9. 18. 01:06

 안녕하세요. 지난편에서 빛에서부터 이미지 데이터를 얻는 과정에 대해서 설명 드렸는데요, 이번에는 얻어진 데이터들을 가공하는 방법에 대해서 알아보도록 하겠습니다. 

 이미지 데이터에 연산을 하고 목적에 따른 결과를 얻는 것을 Filtering 이라고 하는데, 신호처리에서 사용되는 주파수 관련용어와 같은 단어입니다. 이번 글에서는 예제를 통해 자주 쓰이는 몇가지 Filter 알고리즘을 설명하겠습니다. 각 알고리즘에 대한 깊은 설명보다는 간단한 원리 위주의 설명을 할 예정이며 영상처리의 기초를 배우시려는 분들이 이글을 통해 감을 잡았으면 좋겠습니다.


1. Linear Filtering.

 가장 기본적인 필터로, 주로 노이즈를 제거하기 위한 용도로 쓰입니다. 여기서 노이즈란 다음과 같은 파형으로 생각할 수 있습니다. 

 1,3 번은 주위의 값들과 비슷한 값을 유지하고 있는 반면 2번은 주위의 값보다 튀는 값을 갖고 있습니다. 이렇게 주변보다 튀는 값을 가진 2번 부분을 노이즈라고 볼 수 있는데요. 그럼 이런 노이즈를 어떻게 하면 없앨 수 있을까요? 영상처리에서 가장 간단히 사용하는 방법은 다음과 같은 Box filter를 사용하는 것입니다. ( 아래와 같은 행렬형태의 화소 그룹을 box filter 혹은 마스크(mask), 커널(kernel), 윈도우(window )등 다양한 이름으로 부릅니다. 이 글에서는 편의상 box filter를 사용하겠습니다.)

...①

 Box filter는 주로 3x3 형태이며 가운데 값을 정하기 위해 주위의 값을 이용하는 것으로 각 숫자는 대부분 원본 데이터에 곱해지는 수를 의미합니다. 3x3 형태 말고도 5x5, 7x7 등의 box도 사용가능하지만 연산량이 급격히 늘어나기 때문에 주로 3x3을 사용합니다.

 ...②

 위와 같은 이미지가 있다고 가정했을때, 빨간색으로 표시된 픽셀에 ① 필터를 적용하면 


120x0 + 112x0 + 123x0 + 100x0 + 98x1 + 101x0 + 103x0 + 100x0 + 102x0 = 98 


 이 되고, 98인 원본 픽셀값이 그대로 유지되는 것을 알 수 있습니다.

 이제 몇가지 선형필터의 종류에 대해 알아보겠습니다.


 1) 평균값 필터

   평균값 필터는 다음과 같은 box filter를 사용하며, 가운데 픽셀값을 얻기 위해 주위 픽셀의 평균값을 이용하는 것을 뜻합니다. ②의 그림에서 빨간색으로 표시된 픽셀에 평균값 필터를 적용하면 다음과 같습니다.


(120x1 + 112x1 + 123x1 + 100x1 + 98x1 + 101x1 + 103x1 + 100x1 + 102x1)/9 = 106


  따라서 평균값 필터를 적용한 후, 가운데 픽셀값은 98에서 106으로 바뀌게 됩니다. opencv에서 평균값 필터를 적용시키기 위해서는 다음과 같은 함수를 사용하면 됩니다.


  cvSmooth(원본 이미지, 저장할 이미지, CV_BLUR);


 위 함수의 원형은 다음과 같습니다.


void cvSmooth( const CvArr* src, 

CvArr* dst, 

int smoothtype=CV_GAUSSIAN, 

int param1=3, 

int param2=0, 

double param3=0, 

double param4=0

);


 2) 중간값 필터

 중간값 필터는 이웃픽셀의 값들 중 중간값을 선택하는 것입니다. ②의 그림에서 빨간색으로 표시된 픽셀에 중간값 필터를 적용하면 다음과 같습니다. 

  이웃 픽셀에 있는 값들을 모두 정렬한 후 가운데 값을 선택해 빨간색 픽셀을 대체시키는 것으로, opencv에서 다음 함수를 사용하면 됩니다.

  cvSmooth(원본 이미지, 저장할 이미지, CV_MEDIAN);


 3) 가우시안 필터

...③    ...④

  ③과 같은 필터는 가운데 픽셀과 이웃픽셀의 차이가 큰 모양을 하고 있습니다. 이 필터를 이미지에 적용시킬 경우 결과 이미지가 마치 블럭처럼 보이게 됩니다. 이를 해결하려면 ④과 같은 필터를 사용하면 되는데, 이 필터가 가우시안 필터이며 다음과 같은 식으로 나타낼 수 있습니다.

 필터와 ④ 필터를 사용한 차이는 다음과 같습니다.


 가우시안 필터는 opencv에서 다음 함수를 사용하면 됩니다.


 cvSmooth(원본 이미지, 저장할 이미지, CV_GAUSSIAN);


 위 1), 2), 3)번을 openCV를 이용해 테스트하는 소스와 결과는 아래와 같습니다. 차이가 조금씩 있지만 모든 경우에서 잡음이 줄어들고 원본 이미지가 흐릿해지는 것을 볼 수 있습니다.


#include "opencv\cv.h"

#include "opencv\highgui.h"


void main()

{

IplImage* img;

img = cvLoadImage("lenna.bmp", -1); // 이미지 읽기

int width = img->width;

int height = img->height;


IplImage* imgAvg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);

IplImage* imgMedian = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);

IplImage* imgGaussian = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);


if( img != 0 )

{

cvNamedWindow("lenna", 0); // 이름이 "lenna인 윈도우 생성

cvShowImage("lenna", img); // "lenna" 윈도우에 원본 이미지 출력


cvSmooth(img, imgAvg, CV_BLUR, 3); // 3x3 크기의 이웃 픽셀값의 평균

cvNamedWindow("Avg Filter", 0);

cvShowImage("Avg Filter", imgAvg);

cvSmooth(img, imgMedian, CV_MEDIAN, 3); // 3x3 크기의 이웃 픽셀값 중 중간값

cvNamedWindow("Median Filter", 0);

cvShowImage("Median Filter", imgMedian);


cvSmooth(img, imgGaussian, CV_GAUSSIAN, 3); // 3x3 크기의 양방향 필터 적용

cvNamedWindow("Gaussian Filter", 0);

cvShowImage("Gaussian Filter", imgGaussian);


cvWaitKey(0); // 키보드 입력을 기다립니다. 

cvReleaseImage(&img); // 이미지에 할당된 리소스 해제

}

}

 

 이 외에도 노이즈를 제거하는 방법으로는 모폴로지 연산(침식, 팽창 등)이 있으며 노이즈 제거로 인해 뿌옇게 된 영상을 선명하게 만드는 언샤프(Unsharp) 연산도 있습니다. 이 외에도 다양한 선형 필터가 존재하며 필요에 따라 사용할 수 있습니다.