지난 시간에는 이미지의 출력을 간단한 예제와 함께 살펴보았다. 이번에는 입력 받아둔 이미지를 간단한 변환인 가우시안블러를 적용해보도록 하자.

 

1. 가우시안 블러 GaussianBlur()


가우시안 블러는 이미지를 부드럽게 만들어주는 필터 같은 것이다. 가우시안이나 이와 비슷한 커널을 활용해서 이미지에 담긴 정보량을 줄여준다. 이미지 처리에서는 너무 많은 정보로 인해 오히려 정보 사이의 유의미한 연결 고리를 찾기 어려울 수 있으므로 가우시안 블러를 통해 줄여주는 것이다.

 

결과부터 먼저 살펴보자.

왼쪽이 가우시안블러가 적용된 이미지, 오른쪽이 원본이미지이다. 뿌옇게 변한 것이 가우시안 블러이다. 

 

실습을 바로 해보도록 하자.

#include <opencv2/opencv.hpp>			// 헤더 파일을 가볍게 만들기 위해 교체!

using namespace cv;

int main(int argc, char** argv) {
	Mat img = imread("cat.png");
	Mat blurredImg;						//가우시안 처리가 된 이미지를 담을 변수

	if (img.empty()) 
		return -1;

	namedWindow("img", WINDOW_AUTOSIZE);		// 입력 결과를 넣을 윈도우 만들기
	namedWindow("blurredImg", WINDOW_AUTOSIZE);	// 출력 결과를 넣을 윈도우 만들기

	imshow("img", img);		

	GaussianBlur(img, blurredImg, Size(5, 5), 3,  3);
	GaussianBlur(blurredImg, blurredImg, Size(5, 5), 3, 3);

	imshow("blurredImg", blurredImg);

	waitKey(0);

	
}

지난 시간에 적용했던 코드를 활용하고 있다.

 

Mat img = imread("cat.png");

Mat blurredImg;

입력에는 img 변수를 사용하고 있으며, 출력에는 blurredImg를 선언해서 넣어주려고 한다. 여기서는 OpenCV가 자동으로 가우시안블러를 적용함으로써 줄어든 메모리를 자동으로 할당하고 메모리 크기를 조정해준다는 점이다. (간단히 우리를 편리하게 자동으로 조정/재할당 해준다.)

 

namedWindow("img", WINDOWnamedWindow("img", WINDOW_AUTOSIZE); 
namedWindow("blurredImg", WINDOW_AUTOSIZE); 

입력과 출력 결과를 넣을 윈도우를 먼저 만들어줘야 한다. 우리의 눈에 비교가 되야 어떤 부분이 달라진지 알 수 있지 않겠는가? 그래서 두 개의 윈도우 창을 만들어 준다. 

imshow("img", img);

먼저, 가우시안블러를 적용하기 전이므로 원본 이미지를 출력해준다.


GaussianBlur(img, blurredImg, Size(5, 5), 3,  3);
GaussianBlur(blurredImg, blurredImg, Size(5, 5), 3, 3);

그 다음으로 가우시안 블러를 적용해준다. 여기서는 두 번 연속으로 가우시안블러를 적용하고 있다. 1번만 해도 상관없지만 조금 더 들여다 보기 위해 2번의 가우시안 블러를 적용해보았다. 2번 째 중복된 가우시안 블러 호출은 자기 자신이 입력과 출력으로 사용되는 위에서 이야기했듯이, Mat 구조체에 해당하는 메모리가 자동으로 조정/재할당을 함으로써 메모리 사용을 최적화해준다. (아주 편리하다! 감사합니다 개발자님들)


imshow("blurredImg", blurredImg);
가우시안 블러가 완료된 것을 윈도우에 출력해준다. 


waitKey(0);

사용자 입력을 대기함으로써 마무리가 된다.

 


GaussianBlur(img, blurredImg, Size(5, 5), 3,  3);
GaussianBlur(blurredImg, blurredImg, Size(5, 5), 3, 3);

 

우리는 이 부분을 조금 더 살펴보기 위해서 코드를 조금 조정할 필요가 있다.

 

일단 코드는 이렇다.

#include <opencv2/opencv.hpp>			// 헤더 파일을 가볍게 만들기 위해 교체!

using namespace cv;

int main(int argc, char** argv) {
	Mat img = imread("cat.png");
	Mat blurredImg1, blurredImg2;						//가우시안 처리가 된 이미지를 담을 변수

	if (img.empty()) 
		return -1;

	namedWindow("img", WINDOW_AUTOSIZE);		// 입력 결과를 넣을 윈도우 만들기
	namedWindow("blurredImg1", WINDOW_AUTOSIZE);	//중간 결과를 넣을 윈도우 만들기
	namedWindow("blurredImg2", WINDOW_AUTOSIZE);	// 마지막 결과를 넣을 윈도우 만들기

	imshow("img", img);		

	GaussianBlur(img, blurredImg1, Size(5, 5), 3,  3);
	GaussianBlur(blurredImg1, blurredImg2, Size(5, 5), 3, 3);

	imshow("blurredImg1", blurredImg1);
	imshow("blurredImg2", blurredImg2);

	waitKey(0);

	
}

중간 과정을 넣을 

namedWindow("blurredImg1", WINDOW_AUTOSIZE); 를 추가했으며, 

 

imshow("blurredImg1", blurredImg1);
imshow("blurredImg2", blurredImg2);

 

확인할 수 있는 코드를 두 개 정도 더 추가해서 변화 과정을 관찰하고자 하였다.

 

다음과 같이 블러가 점진적으로 진행됨을 확인할 수 있다.

 

그렇다면 가우시안 블러의 함수 원형을 살펴보도록 하자.

 

기본 원형은

void cv::GaussianBlur( InoutArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY = 0, int borderType = BORDER_DEFAULT)

로 이루어져 있다. src는 원본 소스, dst는 출력할 소스를 의미한다. Size는 가우시안 블러를 어떤 범위로 처리할 것인지에 대한 이야기를 하고 있다. 여기서는 5×5 형태로 만들어주고 있으며, 값에 따른 결과는 한번 확인해보도록 하자.(다만 영역의 중심 픽셀에서부터 처리되므로 홀수로 처리해야 한다.)

 

가우스안블러는 수학에서 사용되는 수식을 활용하는데, 정확한 수학적 근거를 보고 싶은 사람은 이곳을 방문하자. 수학적인 해석은 차후 시간이 되면 다루도록 하겠다.

 

* 수식을 풀어서 간단히 요약해서 말하자면 사각형의 범위를 두고 그 범위에 해당하는 수치의 적당한 값으로 수치를 변경해버리는 것이다.

정확한 계산은 아니지만 이런 느낌으로 만들어버리는 것이다. 


여기서 추가로 다운 샘플링 등과 같은 복잡한 형태의 이미지 변환도 존재한다. 이는 나중에 다루도록 하겠다.

 

출처

Computer Vision: Algorithms and Applications, 2nd ed, 2021 Richard Szeliski , szeliski.org/Book/ 

docs.opencv.org/2.4/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.html

docs.opencv.org/4.5.1/d4/d86/group__imgproc__filter.html#gaabe8c836e97159a9193fb0b11ac52cf1

 

+ Recent posts