Search
Duplicate

OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝/ 이진화와 모폴로지

영상의 이진화

이진화

영상의 이진화(binarization)는 영상의 각 픽셀을 두 개의 부류로 나누는 작업이다.
예컨대 입력 영상을 주요 객체 영역과 배경으로 나누거나 또는 영상에서 중요도가 높은 관심 영역(ROI, Region Of Interest)과 그렇지 않은 비관심 영역으로 구분하는 용도로 이진화가 사용될 수 있다.
원래 디지털 컴퓨팅 분야에서 이진화는 입력 값을 0 또는 1로 설정하지만 영상의 이진화는 픽셀 값을 0 또는 255로 설정한다.
그러므로 이진화가 적용된 이진 영상은 흰색과 검은색 픽셀로만 구성된다.
영상의 이진화는 기본적으로 영상의 각 픽셀값을 이용한다. 그레이스케일 영상에 대해 이진화를 수행하려면 영상의 픽셀 값이 특정 값보다 크면 255로 설정하고, 작으면 0으로 설정한다.
이때 각 픽셀과의 크기 비교 대상이 되는 값을 임계값(threshold) 또는 문턱치라고 한다.
임계값은 그레이스케일 범위인 0-255 사이의 정수를 지정할 수 있다.
dst(x,y)={255src(x,y)>T0elsedst(x, y) = \begin{cases} 255 & src(x, y) > T \\ 0 & else \end{cases}
OpenCV에서 이진화는 threshold() 함수를 이용하여 수행할 수 있다.
threshold() 함수의 동작은 type 인자에 의해 결정된다. type 인자에는 ThresholdTypes 열거형 상수를 지정할 수 있다.
Search
ThresholdTypes
설명
THRES_BINARY_INV
Open
THRES_TRUNC
Open
THRES_TOZERO
Open
THRES_TOZERO_INV
Open
THRES_OTSU
Open
오츠(Otsu) 알고리즘을 이용한 자동 임계값 결정
THRES_TRIANGLE
Open
삼각(triangle) 알고리즘을 이용한 자동 임계값 결정
threshold() 함수를 이용하여 영상을 이진화하려면 maxval 인자에 255를 지정하고 type 인자에 THRES_BINARY 또는 THRES_BINARY_INV를 지정한다.
THRES_BINARY_INV 방법으로 이진화하는 것은 THRES_BINARY 방법으로 이진화를 수행한 후 영상을 반전하는 것과 동일하다.
ThresholdTypes 열거형 상수 중 THRES_OTSU와 THRES_TRIANGLE는 임계값을 자동으로 결정할 때 사용한다.
두 방법 모두 픽셀 값 분포를 분석하여 임계값을 자동으로 결정하고, 결정된 임계값을 이용하여 임계값 연산을 수행한다.
두 상수는 보통 논리합 연산자(|)를 이용하여 다른 ThresholdTypes 상수와 함께 사용된다.
자동 이진화를 수행할 경우 threshold() 함수 내부에서 임계값을 자체적으로 계산하여 사용하기 때문에 threshold(0 함수의 세 번째 인자로 전달한 thresh 값은 사용되지 않는다.
자동 임계값 결정 방법은 CV_8UC1 타입의 영상에만 적용할 수 있다.

적응형 이진화

threshold() 함수는 지정한 임계값을 영상 전체 픽셀에 동일하게 적용하여 이진화 영상을 생성한다. 이러한 방식을 전역 이진화(global binarization)라고 한다.
그런데 영상의 특성에 따라 적녁 이진화를 어려운 경우가 있는데, (아래 이미지와 같이 불균일한 조명 환경에서 촬영된 영상의 경우) 이런 경우 각 픽셀마다 서로 다른 임계값을 사용하는 적응형 이진화(adaptive binarization)기법을 사용하는 것이 효과적이다.
적응형 이진화는 영상의 모든 픽셀에서 정해진 크기의 사각형 블록 영역을 설정하고, 블록 영역 내부의 픽셀 값 분포로부터 고유의 임계값을 결정하여 이진화하는 방식이다.
이때 (x, y) 좌표에서의 임계값 T(x, y)는 다음 수식을 이용하여 결정한다.
T(x,y)=μ(x,y)CT(x, y) = \mu(x, y) - C
위 수식에서 μ(x,y)\mu(x, y)는 (x, y) 주변 블록 영역의 픽셀값 평균이고 C는 임계값의 크기를 조정하는 상수이다.
블록 내부 픽셀 값의 평균 μ(x,y)\mu(x, y)는 일반적인 산술 평균을 사용하거나 또는 가수이산 함수 형태의 가중치를 적용한 가중 평균을 사용한다.
상수 C는 영상의 특성에 따라 사용자가 결정한다.
OpenCV에서 적응형 이진화는 adpativeThreshold() 함수를 이용하여 수행할 수 있다.
adpativeThreshold() 함수는 각 픽셀 주변의 blocksize x blocksize 영역에서 평균을 구하고, 평균에서 상수 C를 뺀 값을 해당 픽셀의 임계값으로 사용한다.
이때 블록 영역의 평균을 구하는 방식은 adaptiveMethod 인자를 통해 설정할 수 있다. adaptiveMethod 인자에 ADAPTIVE_THRESH_MEAN_C를 지정하면 산술평균을 이용하고, ADAPTIVE_THRESH_GAUSSIAN_C를 지정하면 가우시안 마스크를 적용하여 가우시안 가중 평균을 계산한다.

모폴로지 연산

이진 영상의 침식과 팽창

모폴로지(morphology)는 형태 또는 모양에 관한 학문을 의미하는데, 영상 처리 분야에서 모폴로지는 객체의 형태 및 구조에 대해 분석하고 처리하는 기법을 의미하며, 수학적 모폴로지(mathematical morphology)라고도 한다.
모폴로지 기법은 그레이스케일 영상과 이진 영상에 대해 모두 적용할 수 있지만 주로 이진 영상에서 객체의 모양을 단순화시키거나 잡음을 제거하는 용도로 사용된다.
모폴로지 연산을 정의하려면 먼저 구조 요소(structuring element)를 정의해야 한다.
구조 요소는 마치 필터링에서 사용되는 마스크처럼 모폴로지 연산의 동작을 결정하는 작은 크기의 행렬이다.
구조 요소는 다양한 크기와 모양으로 정의할 수 있으며, 다양한 구조 요소의 예를 아래 그림에 표현하였다.
필요에 따라 원하는 구조 요소를 선택하여 사용할 수도 있지만, 대부분의 모폴로지 연산에서는 아래 그림의 4번째에 있는 3×3 정방형 구조요소를 사용한다.
영상의 모폴로지 기법 중 가장 기본이 되는 연산은 침식(erosion)과 팽창(dilation)이다.
침식 연산은 객체 영역의 외곽을 골고루 깎아내는 연산으로 전체적으로 객체 영역은 축소되고 배경 영역은 확대된다.
침식 연산은 구조 요소를 영상 전체에 대해 스캔하면서, 구조 요소가 객체 영역 내부에 완전히 포한될 경우 고정점 위치 픽셀을 255로 설정한다.
이진 영상의 팽창 연산은 객체 외곽을 확대하는 연산이다. 팽창 연산을 수행하면 객체 영역은 확대되고, 배경 영역은 줄어든다.
팽창 연산은 구조 요소를 영상 전체에 대해 이동시키면서, 구조 요소와 객체 영역이 한 픽셀이라도 만날 경우 고정점 위치 픽셀을 255로 설정한다.
작은 크기의 영상에서 3×3 정방형 구조요소를 이용하여 침식과 팽창 연산을 수행한 예시가 아래 그림과 같다.
(a)는 12×12 크기의 입력 이진 영상을 확대하여 나타낸 것이며, 이 영상에는 흰색으로 표시된 객체가 하나 있다. (b)는 3×3 정방형 구조 요소이다.
(a) 영상에 대해 (b) 구조 요소를 이용하여 침식 연산을 수행한 결과가 (c)에 나타났다. 침식 연산에 의해 객체 모양이 상하좌우 모든 방향에 대해 1픽셀 정도 깎인 것 같이 변경되었다. 특히 객체 윗 부분의 튀어나온 부분은 매끈하게 제거 되었다.
(a) 영상에 팽창 연산을 수행한 결과는 (d)와 같다. 객체 영역이 상하좌우 모든 방향에 대해 1픽셀 정도 확대된 것 같이 변경되었다. 특히 객체 하단의 패인 부분이 깔끔하게 매워졌다.
OpenCV에서 구조 요소는 원소 값이 0 또는 1로 구성된 CV_8UC1 타입의 Mat 행렬로 표현된다.
구조 요소 행렬에서 값이 1인 원소만을 이용하여 구조 요소의 모양을 결정한다.
OpenCV는 널리 사용되는 모양의 구조 요소 행렬을 간단하게 생성할 수 있도록 getStructuringElement() 함수를 제공한다.
getStructuringElement() 함수는 지정한 모양과 크기에 해당하는 구조 요소 행렬을 반환한다.
shape은 구조 요소의 모양을 결정하는 역할을 하며, MorphShapes 열거형 상수 중 하나를 지정할 수 있다.
구조 요소의 크기는 ksize 인자를 통해 지정하며, 보통 가로와 세로 크기를 모두 홀수로 지정한다.
Search
MorphShapes
설명
MORPH_RECT
Open
사각형 모양의 구조 요소
MORPH_CROSS
Open
십자가 모양의 구조 요소
MORPH_ELLIPSE
Open
타원 모양의 구조 요소. 지정한 구조 요소 크기의 사각형에 내접하는 타원을 이용한다.
OpenCV에서 영상의 침식연산은 erode() 함수를 이용하여 수행한다.
erode() 함수의 kernel에는 getStructuringElement() 함수로 생성한 구조 요소 행렬을 지정할 수 있다.
다만 kernel 인자에 Mat() 또는 noArray()를 지정하면 3×3 정방형 구조 요소를 사용하여 침식 연산을 수행한다.
OpenCV에서 영상의 팽창 연산을 수행하려면 dilate() 함수를 사용한다.
dilate() 함수의 인자 구성과 사용법은 erode와 동일하다.
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); Mat dst1, dst2; erode(bin, dst1, Mat()); dilate(bin, dst2, Mat()); imshow("src", src); imshow("bin", bin); imshow("erode", dst1); imshow("dilate", dst2); waitKey(); destroyAllWindows(); }
C++

이진 영상의 열기와 닫기

모폴로지 기법 중 열기(opening)과 닫기(closing) 연산은 침식과 팽창을 이용하여 구현할 수 있는 연산이다.
열기 연산은 입력 영상에 대해 침식 연산을 먼저 수행한 후 그 다음에 팽창 연산을 수행하는 연산이며, 닫기 연산은 팽창 연산을 먼저 수행한 후 그 다음에 침식 연산을 수행하는 연산이다.
열기와 닫기 연산은 각각 침식과 팽창이 한 번 씩 적용되기 때문에 객체 영역의 크기가 바뀌지는 않지만 침식과 팽창 연산을 적용하는 순서에 따라 서로 다른 효과가 발생한다.
열기 연산은 침식 연산을 먼저 수행하기 때문에 한두 픽셀짜리 영역이 제거된 후, 팽창 연산이 수행되므로 이진 영상에 존재하는 작은 크기의 객체가 효과적으로 제거된다.
반면 닫기 연산은 팽창 연산을 먼저 수행하기 때문에 객체 내부의 작은 구멍이 메워지게 된다.
작은 크기의 영상에서 3×3 정방형 구조 요소를 이용하여 열기와 닫기를 수행한 결과는 아래 그림과 같다.
(a)는 원본영상이며, (b)는 열기 연산의 결과, (c)는 닫기 연산의 결과이다.
OpenCV에서 모폴로지 열기와 닫기 연산은 morphologyEx() 함수를 이용하여 수행할 수 있다.
morphologyEx() 함수는 열기와 닫기 뿐만 아니라 침식과 팽창과 같은 일반적인 모폴로지 연산도 수행할 수 있는 범용적인 모폴로지 연산 함수이다.
morphologyEx() 함수는 세 번째 연산 인자인 op를 이용하여 모폴로지 연산 방법을 지정한다. op 인자에는 MorphTypes 열거형 상수 중 하나를 지정할 수 있으며, 이진 영상에 대해 자주 사용하는 MorphTypes 상수에 대해 아래 표로 정리하였다.
MORPH_GRADIENT 상수는 팽창 결과 영상에서 침식 결과 영상을 빼는 연산을 수행하며 객체의 외곽선이 추출되는 효과가 있다.
Search
MorphTYpes
설명
MORPH_ERODE
Open
침식 연산
MORPH_DILATE
Open
팽창 연산
MORPH_OPEN
Open
열기 연산
MORPH_CLOSE
Open
닫기 연산
MORPH_GRADIENT
Open
모폴로지 그래디언트 계산dst = dilate(src, element) – erode(src, element)