[OpenCV] 모폴로지 – 침식(erode), 팽창(dilate)

이번 글에서는 모폴로지의 기본적인 설명과 침식과 팽창에 대해 알아보겠습니다.

우선 모폴로지(morphology)는 형태학을 의미하며, 생물의 구조, 외형 등등 형태 또는 모양에 관한 학문을 의미합니다.
영상처리에서 모폴로지는, 영상에서 객체의 형태 및 구조에 대해 분석하고 처리하는 기법을 의미합니다.
모폴로지는 주로 객체를 단순화하거나 잡음 제거 용도로 많이 사용 됩니다.
침식과 팽창은 이러한 모폴로지 기법 중에서 기본이 되는 연산입니다.
침식과 팽창 연산을 하기 위해서는 구조 요소가 필요하며 구조 요소는 필요에 따라 원하는 모양으로 사용됩니다.
이 글에서는 구조 요소는 3 X 3의 십자가 모양의 구조 요소를 사용하겠습니다.

침식

침식(erosion)은 단어 그대로 깍아 내는 것을 말합니다. 영상에서는 이미지를 깍아 내는 연산을 의미합니다. 침식 연산으로 보통 잡음을 제거하는 작업을 많이 합니다.

침식 연산은 구조 요소를 영상에 올려 놓았을 때 구조요소에 만족하게 올려놓을 수 없으면 해당 부분을 0으로 변경합니다. 예를 들어 아래 그림과 같이 입력된 영상(초록색)이 있을 때, 구조 요소(회색 십자가)를 사용하여 침식 연산을 하면 1로 표시된 부분에만 구조 요소를 올려 놓을 수 있습니다.

침식 연산 과정

이렇게 1로 된 영역을 제외하고 다른 영역을 0으로 만듦으로써 결국 이미지가 깎이는 침식 연산을 수행하게 됩니다.

침식 전, 후

OpenCV에서 침식 연산은 erode 함수를 사용하여 수행 가능합니다.

/** 
@param src 입력 영상
@param dst 출력 영상
@param kernel 구조 요소
@param anchor 고정점 위치
@param iterations 반복 횟수
@param borderType 가장자리 확장 방식
@param borderValue borderType이 BORDER_CONSTANT인 경우 확장된 가장자리를 채울 값
 */
void erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );

아래 코드는 erode를 이용하여 잡음을 제거하는 샘플 코드입니다.

Mat src = imread("address.png", IMREAD_GRAYSCALE);
if (src.empty())
{
	cerr << "image load fail" << endl;
	return -1;
}

Mat matErode;
erode(src, matErode, Mat()); // 침식

imshow("src", src);
imshow("erode", matErode);

waitKey();
destroyAllWindows();

침식 연산으로 잡음이 제거된 것을 볼 수 있습니다.

팽창

팽창(dilation)은 침식과 반대로 이미지를 확장하는 것을 의미합니다. 팽창 연산은 구조 요소를 입력 영상에 올려놓아 영역을 확장 시킵니다.

팽창 연산 과정

결과적으로 아래와 같이 팽창됩니다.

팽창 전, 후

OpenCV에서는 dilate 함수로 팽창 연산을 제공합니다.

/**
@param src 입력 영상
@param dst 출력 영상
@param kernel 구조 요소
@param anchor 고정점 위치
@param iterations 반복 횟수
@param borderType 가장자리 확장 방식
@param borderValue borderType이 BORDER_CONSTANT인 경우 확장된 가장자리 채울 값
 */
void dilate( InputArray src, OutputArray dst, InputArray kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = morphologyDefaultBorderValue() );

아래는 샘플 코드입니다.

Mat src = imread("address2.png", IMREAD_GRAYSCALE);
if (src.empty())
{
	cerr << "image load fail" << endl;
	return -1;
}


Mat matDilate;
dilate(src, matDilate, Mat()); // 팽창

imshow("src", src);
imshow("dilate", matDilate);

waitKey();
destroyAllWindows();

코드를 수행하면 아래와 같이 검은 부분이 팽창 연산으로 채워진 것을 볼 수 있습니다.

이상으로 침식과 팽창에 대해 알아보았습니다.