관리 메뉴

공부 기록장 💻

[OpenCV/C++] 영상의 이진화 2 - 모폴로지 연산, 침식과 팽창, 열기와 닫기 (Image Binarization, Morphology, Erode, Dilate, Opening, Closing) 본문

# Tech Studies/Computer Vision • OpenCV

[OpenCV/C++] 영상의 이진화 2 - 모폴로지 연산, 침식과 팽창, 열기와 닫기 (Image Binarization, Morphology, Erode, Dilate, Opening, Closing)

dream_for 2022. 12. 21. 16:50

OpenCV 4로 배우는 영상 처리와 컴퓨터 비전 CH 11.이진화와 모폴로지  정리

 

모폴로지 연산 (Morphology)

모폴로지 연산은 영상 내부 객체의 형태와 구조를 분석하고 처리하는 기법이다. 이는 그레이스케일 영상과 이진 영상에 모두 적용 가능하지만, 주로 이진화된 영상에서 객체의 모양을 변형하는 용도로 사용된다. 

이진 영상에서 사용되는 기본적인 모폴로지 연산 동작에 대해 이해해보고, 모폴로지 함수 사용 방법에 대해 알아보자.

 

이진 영상의 침식과 팽창

모폴로지(Morphology)는 형태 또는 모양에 관한 학문을 의미한다. 영상 처리 분야에서 모폴로지는 영상에서 객체의 형태 및 구조에 대해 분석하고 처리하는 기법을 의미하며, 수학적 모폴로지(mathematical morphology)라고도 한다. 모폴로지 그레이스케일 영상과 이진 영상에 대해 모두 적용할 수 있지만, 주로 이진 영상에서 객체의 모양을 단순화시키거나 잡음을 제거하는 등의 용도로 사용된다.

 

모폴로지 연산을 정의하려면 먼저 구조 요소(structuring element)를 정의해야 한다. 구조 요소란 마치 필터링에서 사용되는 마스크처럼 모폴로지 연산의 동작을 결정하는 작은 크기의 행렬을 말한다. 다양한 크기와 모양의 구조 요소의 예는 다음과 같다.

 

 

필요에 따라 원하는 구조 요소를 선택하여 사용할 수 있지만, 대부분의 모폴로지 연산에서는 4번째에 나타난 3x3 정방형 구조 요소를 사용한다. 각각의 구조 요소 행렬에서 진한 색으로 표시한 원소는, 연산 결과가 저장될 위치를 나타내는 고정점(anchor point)이며, 대부분의 경우 구조 요소의 중심을 고정점으로 사용한다.

 

 

 

영상의 모폴로지 기법 중 가장 기본이 되는 연산은 침식(erosion)팽창(dilation)이다.

침식 연산은 객체 영역의 외곽을 골고루 깎아 내는 연산으로 전체적으로 객체 영역이 축소되고 배경이 확대된다. 침식 연산은 구조 요소를 영상 전체에 대해 스캔하면서, 구조 요소가 객체 영역 내부에 완전히 포함될 경우, 고정점 위치 픽셀을 255로 설정한다. 

팽창 연산은 객체 외곽을 확대하는 연산이다. 이로 인해 객체 영역이 확대되며 배경 영역이 줄어든다. 팽창 연산은 구조 요소를 영상 전체에 대해 이동시키면서, 구조 요소와 객체 영역이 한 픽셀이라도 만날 경우 고정점 위치 픽셀을 255로 설정한다. 

 

작은 크기의 영상에서 3x3 정방형 구조 요소를 사용해 침식, 팽창 연산을 수행한 결과는 다음과 같다.

 

 

12x12 크기의 입력 이진 영상 (a)에 대하여 3x3 크기의 정방형 구조 요소 (b)를 침식 연산한 결과가 (c)이고 팽창 연산한 결과가 (d)로 나타난다. 침식 연산에 의해 윗 부분이 매끄럽게 깎인 것을 확인할 수 있다. 그리고 팽창 연산에 의해서는 객체 아래 쪽에 작게 패인 부분이 깔끔하게 메워진 것을 확인할 수 있다.

 

 

getStructuringElement() 함수

 

OpenCV 에서 구조 요소는 원소 값이 0 또는 1로 구성된 CV_8UC1 타입의 Mat 행렬로 표현하며, 널리 사용되는 모양의 구조 요소 행렬을 간단하게 생성하는 getStructuringElement() 함수를 제공한다. 

 

구조 요소의 행렬을 반환하는 getStructuringElement() 함수

 

위 함수는 지정한 모양과 크기에 해당하는 구조 요소 행렬을 반환하고, 첫번째 인자 shape는 구조 요소 모양을 결정하는 역할을 하며, MorphShapes 열거형 상수와 의미는 다음의 표에서 자세하게 확인할 수 있다.

구조 요소의 크기는 ksize 인자를 통해 지정하며 보통 가로와 세로 크기는 모두 홀수로 지정한다.

 

MorphShapes 열거형 상수

 

 

erode() 함수

OpenCV 에서 영상의 침식 연산은 erode() 함수를 이용해 수행하며, 원형은 다음과 같다.

src, dst, kernel 인자를 제외한 나머지는 기본값이 설정되어 있으므로 생략이 가능하다.

kernel에는 getStructuringElement() 함수로 생성한 구조 요소 행렬을 지정할 수 있다. 다만 해당 인자에 Mat() 또는 noArray() 를 지정하면 3x3 정방형 구조 요소를 사용해 자동 침식 연산을 수행한다.

 

침식 연산을 수행하는 erode() 함수

 

 

dilate() 함수

팽창 연산은 dialte() 함수를 사용하며 원형은 다음과 같으며, erode() 함수와 인자 구성이 완전히 동일하다.

 

팽창 연산을 수행하는 dilate() 함수

 

 

erode()와 dilate() 을 이용하여 모폴로지 침식과 팽창 연산을 수행하는 예제를 살펴보도록 하자.

 

// 모폴로지 침식, 팽창 연산 수행
void erode_dilate() {
	Mat src = imread("milkdrop.bmp", IMREAD_GRAYSCALE);

	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	Mat bin;
	threshold(src, bin, 0, 255, THRESH_BINARY | THRESH_OTSU); // otsu 알고리즘으로 자동 이진화 수행
	
	Mat dst1, dst2;
	erode(bin, dst1, Mat());	// 3x3 정방형 구조 요소를 이용한 침식 연산
	dilate(bin, dst2, Mat());	//  3x3 정방형 구조 요소를 이용한 팽창 연산

	imshow("src", src);
	imshow("bin", bin);
	imshow("erode", dst1);
	imshow("dilate", dst2);

	waitKey();
	destroyAllWindows();
}

 

mildrop.bmp 영상을 이진화한 후, 침식과 팽창 연산을 각각 수행하여 결과를 화면에 출력하면 다음과 같다.

src 원본 이미지에 대해 오츠 알고리즘을 이용해 이진화 한 결과가 bin 에 나타나고 있다.

침식 결과인 좌측 하단의 erode 결과 영상을 보면, bin 영상에 비해 객체 외관이 다소 작아졌고, 영상의 우측 하단에 있는 작은 한두 픽셀 짜리의 작은 흰색 객체가 사라진 것을 확인할 수 있다.

팽창 결과인 우측 하단의 dilate 결과 영상을 보면 객체 외관이 확대되었으며, 객체 내부의 검은색 구멍은 사라지거나 좁아진 것을 확인할 수 있다. 

 

 

 


이진 영상의 열기와 닫기

모폴로지 기법 중에서 열기(opening)닫기(closing) 연산에 대해 알아보자. 열기와 닫기 연산은 위의 침식과 팽창 연산을 이용해 쉽게 구현할 수 있는 연산이다. 

 

열기 연산은 입력 영상에 대해 침식 연산을 수행한 후, 다시 팽창 연산을 수행하는 연산이고 닫기 연산은 팽창 연산을 먼저 수행한 후, 침식 연산을 수행하는 연산이다.  열기와 닫기는 각각 침식과 팽창 연산이 한 번씩 적용되므로 객체 영역의 크기가 크게 바뀌지 않지만, 침식과 팽창 연산을 적용하는 순서에 따라 서로 다른 효과가 발생한다.

열기 연산의 경우, 침식을 먼저 수행하므로 한두 픽셀짜리 작은 영역이 먼저 제거된 후, 팽창 연산이 수행된다. 그 결과 입력 이진 영상에 존재하는 작은 크기의 객체가 효과적으로 제거된다.

닫기 연산은 팽창 연산을 먼저 수행하므로 객체 내부의 작은 구멍이 메워진 후에 침식 연산이 수행된다.

 

아래 그림을 통해 열기와 닫기 연산을 시각적으로 이해해보자.

 

(a)의 원본 영상에 대해 3x3 정방형 구조 요소를 사용해 열기와 닫기 연산을 수행한 결과 (b)와 (c)를 살펴보자.

열기 연산의 결과 영상인 (b)를 통해 큰 객체 외곽에 돌출된 한두 픽셀이 제거되었고, 중앙의 위, 아래에 위치한 1x1 픽셀과 2x2 픽셀이 사라진 것을 확인할 수 있다.

닫기 연산 결과 영상인 (c)의 경우 객체 내부의 작은 구멍이 사라졌고, 오른쪽 객체 외곽에 오목하게 들어간 부분이 메꿔진 것을 확인할 수 있다.

 

 

morphologyEx() 함수

 

morpholotyEx() 함수는 OpenCV에서 열기와 닫기 연산을 수행하며, 침식, 팽창과 같은 일반적인 모폴로지 연산도 수행할 수 있는 범용적인 모폴로지 연산 함수이다.

 

모폴로지 침식과 팽창, 열기와 닫기 연산을 수행하는 morphologyEx() 함수

 

위 함수는 세번째 인자 op를 지정하여 모폴로지 연산 방법을 지정한다. MorphTypes 열거형 상수를 통해 지정할 수 있으며, MORPH_GRADIENT 상수는 팽창 결과 영상에서 침식 결과 영상을 빼는 연산을 수행하며, 객체의 외곽선이 추출되는 효과가 있다.

 

 

morphologyEx() 함수를 이용해 이진 영상에 모폴로지 열기와 닫기 연산을 수행하는 예제를 살펴 보자.

 

// 모폴로지 열기와 닫기 연산 수행
void open_close() {
	Mat src = imread("milkdrop.bmp", IMREAD_GRAYSCALE);

	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}

	Mat bin;
	threshold(src, bin, 0, 255, THRESH_BINARY | THRESH_OTSU);

	Mat dst1, dst2;
	morphologyEx(bin, dst1, MORPH_OPEN, Mat());		// 3x3 정방형 구조 요소를 이용한 열기 연산
	morphologyEx(bin, dst2, MORPH_CLOSE, Mat());	// 3x3 정방형 구조 요소를 이용한 열기 연산

	imshow("src", src);
	imshow("bin", bin);
	imshow("erode", dst1);
	imshow("dilate", dst2);

	waitKey();
	destroyAllWindows();
}

 

열기와 닫기 연산을 수행한 결과는 다음과 같다.

 

 

opening 열기 연산 결과 영상의 경우, 영상의 우측 하단에 있던 미세한 한두픽셀짜리 영역이 효과적으로 제거되었고,

closing 닫기 연산 결과 영상의 경우, 흰색 객체 내부의 미세한 구멍들이 메꾸어져 사라진 것을 확인할 수 있다.

 

 

즉 요약해보자면,

열기 연산은 침식 연산 후 팽창 연산을 수행한다. 따라서 객체 외부에 있는 미세한 영역을 효과적으로 제거하는데 쓰일 수 있는 기법이며,

닫기 연산은 팽창 연산 후 침식 연산을 수행한다. 따라서 객체 내부에 있는 미세한 영역을 효과적으로 제거하는데 쓰일 수 있는 기법이다.

728x90
반응형
Comments