관심쟁이 영호

[#19] OpenCV (With. C++) ㅣ 모폴로지 -침식, 팽창 연산 본문

학교공부/OpenCV

[#19] OpenCV (With. C++) ㅣ 모폴로지 -침식, 팽창 연산

관심쟁이 영호 2020. 11. 26. 01:30
반응형

안녕하세요!

관심쟁이 영호입니다!

 

오늘 공부할 과목은

OpenCV입니다!

 


오늘은 모폴로지에 대해서 공부를 할 예정이에요!

 

모폴로지란?

영상 처리에서 모폴로지는 영상의 객체들의 형태를 분석하고 처리하는 기법이에요!

영상의 경계, 골격, 블록 등등의 형태를 표현하는데 필요한 요소를 추출해주는데요!

 

모폴로지를 통해서 영상 내의 객체를 좀 더 밝게, 크게, 작게, 어둡게 등등 임의의 조작을 하는데 도움을 줍니다.

 

모폴로지 - 침식 연산

 

모폴로지를 통해서 객체가 검출되면 해당 객체를 침식하는 연산이에요!

침식 연산을 하게 되면, 크기는 축소! 배경은 확장!

 

그럼 어떻게 하는가?

 

1. 가장 먼저 침식 마스크를 설정합니다. 침식 마스크는 아래의 표와 같이 이루어져 있어요!

0 1 0
1 1 1
0 1 0

2. 영상의 중심 화소를 가져와서 침식 마스크와 비교를 해봅니다!

 

비교 방법은 - 영상에서 어떠한 화소와 그것을 둘러싸고 있는 화소 8개를 같이 가지고 옵니다!

 

1 0 1 ----------------- 0 1 0
1 1 1 1 1 1
1 1 1 0 1 0
영상의 화소들   침식 마스크

비교해보면 1행의 2열 부분이 0 - 1로 일치하지 않아요! (침식 마스크에서 1에 해당하는 부분만 비교합니다!)

이렇게 되면 최종적으로 중앙 화소를 0으로 바꾸어 주는 거예요!

 

그럼 침식 마스크의 1인 부분과 똑같이 영상의 화소들도 1이면 중앙 화소는 1로 출력이 되는 겁니다!

 

모폴로지 - 팽창 연산

 

팽창 연산은 침식 연산과는 반대로!

하나라도 일치하면 1로 출력!

하나라도 일치하는 것이 없다면 0으로 출력!

 

그럼 코드로 살펴볼게요.

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

using namespace cv;
using namespace std;

bool check_match(Mat img, Point start, Mat mask, int mode = 0) {
	for (int u = 0; u < mask.rows; u++)
	{
		for (int v = 0; v < mask.cols; v++)
		{
			Point pt(v, u);
			int m = mask.at<uchar>(pt);
			int p = img.at<uchar>(start + pt);

			bool ch = (p == 255);
			if (m == 1 && ch == mode)
				return false;
		}


	}
	return true;
}

void erosion(Mat img, Mat& dst, Mat mask) {
	dst = Mat(img.size(), CV_8U, Scalar(0));
	if (mask.empty()) mask = Mat(3, 3, CV_8UC1, Scalar(1));


	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- h_m.x; j++)
		{
			Point start = Point(j, i) - h_m;
			bool check = check_match(img, start, mask, 0);
			dst.at<uchar>(i, j) = (check) ? 255 : 0;
				
		}

	}
	}
void dilation(Mat img, Mat& dst, Mat mask) {
	dst = Mat(img.size(), CV_8U, Scalar(0));
	if (mask.empty()) mask = Mat(3, 3, CV_8UC1, 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 - h_m.x; j++)
		{
			Point start = Point(j, i) - h_m;
			bool check = check_match(img, start, mask, 1);
			dst.at<uchar>(i, j) = (check) ? 0 : 255;

		}

	}
}
	
int main()
{
	Mat image = imread("../image/sample.jpg", IMREAD_GRAYSCALE);
	
	CV_Assert(image.data);
	
	Mat th_img, dst1, dst2, dst3, dst4;
	threshold(image, th_img, 128, 255, THRESH_BINARY);

	uchar data[] = { 0,1,0,
					1, 1, 1,
					0, 1, 0 };
	Mat mask2(3, 3, CV_8UC1, data);

	erosion(th_img, dst3, (Mat)mask2);
	morphologyEx(th_img, dst4, MORPH_ERODE, mask2);




	
	Matx<uchar, 3, 3> mask;

	mask <<  0, 1, 0, 1, 1, 1, 0, 1, 1 ;

	dilation(th_img, dst1, (Mat)mask);

	morphologyEx(th_img, dst2, MORPH_DILATE, mask);

	imshow("image", image);
	imshow("OpenCV_dilation - 침식", dst2);
	imshow("OpenCV_dilation - 팽창", dst4);
	



	

	waitKey(0);

		return 0;
}

코드는 사용자가 직접 팽창, 침식 연산하는 erosion, dilation 함수가 있어요!

그리고 출력된 영상은 morphologyEx함수를 이용해서 모폴로지 팽창/침식 연산을 해준 것입니다.

옵션으로는 MORPH_ERODE(침식), MORPH_DILATE(팽창) 이렇게 있어요!

 


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

 

저두 정확히는 이해가 되지 않아서

얼버부린 면이 많네요 ㅠㅠ

 

더 자세한 사항이 궁금하시면 댓글 달아주세요!!

 

300x250
Comments