관심쟁이 영호

[#15] OpenCV (With. CPP) ㅣ 영역처리 ver.1 ㅣ 회선, 블러링 본문

학교공부/OpenCV

[#15] OpenCV (With. CPP) ㅣ 영역처리 ver.1 ㅣ 회선, 블러링

관심쟁이 영호 2020. 11. 22. 18:32
반응형

안녕하세요.

관심쟁이 영호입니다!

 

오늘은 OpenCV를 공부해볼게요!

 


오늘은 영역처리 부분에서

회선과 블러링에 대해서 공부를 해볼게요.

 

영역처리란?

영상처리 작업을 하다보면 공간영역, 주파수 영역에 대한 표현을 자주 접할 수가 있어요!

말 그대로 공간, 주파수를 영역으로 나누어 처리를 하는 것입니다.

 

공간영역은 영상에서 다루어질 화소공간을 의미합니다!

이것을 더욱 세분화하면 화소점 하나하나의 개념이라기 보다는 화소가 모인 특정 범위의 화소 배열을 의미해요!

 

그리고 대부분 마스크 또는 윈도우라고 불리는 커널을 이용하여 회선을 수행합니다!

 

회선이란?

어떠한 마스크값을 영상영역에 전반적으로 곱하여 출력되는 값을 모든 출력화소값에 대해 이동하면서 수행하는 것을 하는 것을 말합니다. 이때, 이 마스크는 커널, 윈도우, 필터 등의 다른 용어로도 불려집니다.

 

한마디로, 영상 데이터 행렬이 있으면

어떤 정해진 값을 돌려가면서 곱해서 큰 값들은 더욱 크게, 작은 값들은 더욱 작게 변환해주는 작업이라고 생각하시면 편해요!

(크게 작게 말고도 큰값 작은값들을 고르게 평균에 맞춰주기도 가능하구요!)

 

그러면 이러한 것을 바탕으로 블러링 처리를 해볼게요.

 

블러링이란?

영상의 어떠한 부분을 흐리게 만드는 작업이에요!

영상에서 화소값이 급격하게 변하는 부분들을 감소하여 점진적으로 변하게 하여 영상이 부드럽게 해주는 원리입니다.

"스무딩"이라고 불리는 경우도 있어요.

 

위에서 말씀드렸듯이, 블러링에 해당하는 마스크가 존재합니다!

 

1/9 1/9 1/9
1/9 1/9 1/9
1/9 1/9 1/9

이 마스크 값을 이용하여 곱해주는 겁니다!

마스크 행렬의 모든 값은 1이 되어야 입력 영상의 밝기가 유지가 됩니다.

 

그럼 말로 풀어서 왜 이것을 곱해졌을 때, 블러링이 되는지 말씀드리자면!

입력 영상에 해당 값을 나누어 주면

90 -> 10 / 9 -> 1 이렇게 값이 작아지죠!

90의 값은 80이 줄었고, 9의 값은 8이 줄었습니다.

 

큰 값들은 큰폭으로, 작은 값들은 작은 폭으로 줄어들기 때문에 전반적으로 고르게 작아지는 것을 확인할 수 있어요!

 

그럼 코드로 살펴봅시다.

 

먼저 순서를 살펴보면

1. 이미지를 읽는다.

2. 마스크 값을 배열에 저장한다.

3. filter함수에 이미지, 마스크를 전달하고 순회하여 이미지 값에 마스크를 곱해준다.

4. 곱해준 값을 저장하고 blur 행렬 변수에 저장한다.

 

이렇게 순서를 정할 수가 있겠네요!

// Project1.cpp : 이 파일에는 'main' 함수가 포함됩니다. 거기서 프로그램 실행이 시작되고 종료됩니다.
//

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

void filter(Mat img, Mat& dst, Mat mask) {
	dst = Mat(img.size(), CV_32F, Scalar(0));
	Point h_m = mask.size() / 2;

	for (int i = h_m.y; i < img.rows - h_m.y; i++) // 입력 행렬 반복 순회
	{
		for (int j = h_m.x; j < img.cols; j++)
		{
			float sum = 0;

			for (int u = 0; u < mask.rows; u++) //마스크 원소를 순회한다.
			{
				for (int v = 0; v < mask.cols; v++)
				{
					int y = i + u - h_m.y;
					int x = j + v - h_m.x;
					sum += mask.at<float>(u, v) * img.at<uchar>(y, x); //회선 수식!
				}

			}
			dst.at<float>(i, j) = sum; //회선 누적값 출력화소 저장!
		}

	}
}

int main()
{
	Mat image = imread("../image/sample.jpg", IMREAD_COLOR);
	
	CV_Assert(image.data);

	float data[] = {						//블러링 마스크 지정
		1 / 9.f, 1 / 9.f, 1 / 9.f,
		1 / 9.f, 1 / 9.f, 1 / 9.f,
		1 / 9.f, 1 / 9.f, 1 / 9.f
	};

	Mat mask(3, 3, CV_32F, data);
	Mat blur;
	filter(image, blur, mask); //회선 수행
	blur.convertTo(blur, CV_8U);


	imshow("image", image), imshow("blur", blur);
	waitKey(0);

		return 0;
}

결과는 이렇게 나와요!!

 

이해 되셨나요~?

 


오늘은 여기까지 하겠습니다!

300x250
Comments