티스토리 뷰

영상처리/OpenCV

08. Downsampling

빠리빵 2019. 4. 22. 22:36

이번 주제에서는 DownSampling과 그 과정에서 사용되는 filter 이야기를 해보고자 한다. 이미지의 사이즈를 줄이는 것을 Downsampling이라고 하는데(반대는 Upsampling), 사이즈를 줄이는 것은 생각보다 간단하지 않다. 결과를 먼저 보자. 위는 low pass filter를 사용하지 않고 downSampling을 한 것이며, 아래는 사용 후 진행한 것이다. 위의 영상에서는 image의 quality가 좋지 않다. (자연스럽지 않고, pixel간 차이가 너무 커서 경계가 있어 보인다. 아래는 blur해보이지만, 둘 중 한 가지를 선택한다면 아래를 선택하는 것이 원본의 신호를 그나마 더 잘 표현하였다.)


Low pass filter를 사용하지 않고 downsampling을 진행하면 왜 위와 같은 결과가 나오는지 알아보자. 우선 downsampling 방법으로는 행과 열 방향으로 4개 픽셀 당 1개(1/4로 변환하는 예)의 픽셀을 나열하였다. 그러자 다양한 artifact가 발생하였는데, 이는 Spatial aliasing이라 불리는 현상 때문이다. 이것은 high frequency를 표현하기에는 image가 너무 작아서 발생하는 현상이다. 미세한 detail은 high frequency 영역에 해당하는데, 영상이 작아지며 그것을 표현하지 못하는 것이다. 아래의 자동차 예를 보면, resolution이 작아질 수록 얇은 선(high frequency)을 표현하기에는 무리가 있어 영상에서 artifact가 발생하는 것이다. 따라서 우리는 downsampling 전에 low pass filter를 거쳐 표현하지 못하는 영역을 제거할 필요가 있다.

 

결과를 다시 한번 보자. filter를 사용하지 않으면 high frequency 영역(깃털, 눈동자 등)에서는 표현이 부자연스럽다.


Syquist Shannon theorem에서는 우리가 analog signal을 sampling하는 경우에 sampling의 frequency를 어떻게 정해야 하는지에 대한 이야기를 다룬다. 예로, 음악, 가스신호 등 다양한 signal 등이 존재할텐데, sampling rate를 빠르게 하여 더 정밀한 결과를 필요로 하는 상황이 있겠고, 굳이 resource를 낭비하면서까지 정밀한 결과를 필요로 하지 않는 상황이 있을 수 있다. 그러한 상황에서 이 이론은 "원래 정보를 왜곡하지 않는 최소의 sampling frequency는 해당 signal의 highest frequency component의 2배가 되어야 한다." 라고 이야기하고 있다. (이것은 영상에서는 흰색과 검정이 반복된 선을 생각해보면 쉽다.. 적어도 흰색과 검정이 반복되는 주기의 2배의 sampling rate를 사용하여야 흰색과 검정을 모두 추출할 수 있다.) 따라서 위의 이론에 의하면 우리가 downsampling 하는 과정에서 줄어든 사이즈만큼 표현할 수 있는 frequency 또한 동일하게 줄어든다. 그래서 원본에서 제대로 표현할 수 있었던 high frequency 중에서 표현하지 못하는 부분이 생겨나는 것이다. 우리는 그 부분을 제거할 필요가 있다. 

openCV로 넘어와서, downSampling과 upSampling을 해주는 fuction이 있는데, cv::pyrDown, cv::pyrUp이다. pyrDown fuction은 위의 문제점을 고려하여 5x5 gaussian filter를 적용 후 size를 줄인다. pyrUp의 알고리즘은 upsampling을 위해 기존 pixel의 사이에 0을 넣은 후, 0의 값은 5x5 gaussian filter를 적용한 값으로 변경한다. 이때 coefficient(면적을 1로 만들기 위해 사용되던 변수)의 값은 4로 곱해준다. 4로 곱해주는 이유는 gaussian filter가 적용되는 값들에서 1/4은 0으로 비어있는 값임을 고려한 결과이다. 


그러면 upsampling을 진행한 후, downsampling을 진행하면 결과가 같을까? 라는 물음에 아니라고 대답할 수 있겠다. upsampling을 진행하는 과정에서 일정 high frequency 성분이 사라지고, downsampling 하는 과정에서 채워지는 값들은 그 high frequency가 사라진 pixel value들을 gaussain filter로 계산하여 채워넣은 결과다. 따라서 완벽하게 원본과 같지는 않으며 실제로 결과 영상을 비교해도 확인할 수 있다.

   

위의 function 외에 resize라는 함수도 존재한다. 이 함수는 지정한 size로(down, up resizing) 변경할 수 있도록 해준다. 정확한 함수 사용법은 appendix를 참고하길 바라며, 추가로 size 뿐만 아니라 interpolation 방식을 지정할 수 있다. 크게 3가지 방식으로 1. nearest neighbor, 2. Bilinear, 3. bicubic 방식이 존재한다. Nearest neighbor 방식은 아래 그림에서 볼 수 있듯, original image의 가장 가까운 pixel의 value를 새로운 pixel value로 결정하는 것이다. Bilinear의 경우 2차원 linear interpolation이며, 이웃 좌표들의 value들의 중간 값으로 interpolation한다. Bicubi은 인접 4x4 pixel들이 interpolation에 사용되며, 더 정밀한 값을 얻어낼 수 있겠지만 계산 측면에서 loss가 생겨날 수 있다.   

#include<opencv2/imgproc.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/core.hpp>
#include<iostream>

using namespace std;
using namespace cv;

Mat downSampling(Mat input, int scaleFactor) {
	Mat output = Mat(Size(input.cols / scaleFactor, input.rows / scaleFactor), CV_8UC1);
	
	for (int row = 0; row < output.rows; row++) {
		for (int col = 0; col < output.cols; col++) {
			output.at<uchar>(row, col) = input.at<uchar>(row * scaleFactor, col * scaleFactor);
		}
	}
	return output;
}


int main() {
	Mat original = imread("lena.tif", IMREAD_GRAYSCALE);
	Mat gaussian;

	GaussianBlur(original, gaussian, Size(11, 11), 2.0);

	Mat withoutFilter = downSampling(original, 2);
	Mat withGaussianFilter = downSampling(gaussian, 2);

	imwrite("original.bmp", original);
	imwrite("withoutFilter.bmp", withoutFilter);
	imwrite("withGaussian.bmp", withGaussianFilter);
	/****************************************/
	Mat reducedImage; 
	Mat increasedImage;

	pyrDown(original, reducedImage); 
	pyrUp(original, increasedImage);

	imwrite("pyrDown.bmp", reducedImage);
	imwrite("pyrUp.bmp", increasedImage);
	/****************************************/
	Mat resizedImage;
	Mat resizedImage2;
	Mat resizedImage3;

	resize(original, resizedImage, Size(3000, 3000));
	resize(original, resizedImage2, Size(), 0.5, 0.5);
	resize(original, resizedImage3, Size(), 0.5, 0.5, INTER_NEAREST);

	imwrite("resizedImage.bmp", resizedImage);
	imwrite("resizedImage2.bmp", resizedImage2);
	imwrite("resizedImage3.bmp", resizedImage3);
}

'영상처리 > OpenCV' 카테고리의 다른 글

10. Directional Filter(Sobel)  (0) 2019.04.27
09. Median filter  (2) 2019.04.24
07. mean / gaussian filter  (1) 2019.04.18
06. Writing efficient scanning loops  (0) 2019.04.16
05. Scanning with iterator  (0) 2019.04.15
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함