[OpenCV] 영상의 이진화 – adaptiveThreshold

이전 글에서는 영상의 이진화에 대해서 알아 보았고 threshold 에 대해서도 알아보았습니다.

이제 threshold 함수로 임계값을 설정하고, 임계값보다 크면 255, 작으면 0으로 만드는 이진화 작업을 할 수 있습니다.
하지만 아래와 수도쿠 이미지에서는 한곳은 너무 어둡고,  한곳은 너무 밝아서 threshold 함수를 사용하는게 적절하지 않습니다.

그 이유는 이미지 좌하단과 우상단의 밝기 차이가 있어 적절한 임계값을 찾기 힘들기 때문입니다.

이 경우에는 adaptiveThreshold 함수를 사용하여 적절하게 영상을 이진화 할 수 있습니다.

설명

함수를 알아보기 전에 threshold함수의 문제점과 adaptiveThreshold 함수의 연산방식에 대해 알아보겠습니다.

threshold의 문제점은 영상의 모든 픽셀값에 대하여 하나의 임계값으로 이진화를 시켰다는 겁니다. 영상의 모든 부분이 하나의 임계값으로 이진화가 되다보니 밝은 영역과 어두운 영역을 모두 만족하는 임계값 임계값을 설정하기 어려웠다는 의미입니다.

adaptiveThreshold는 이러한 문제점을 해결하기 위해 각 영역마다 서로 다른 임계값을 사용하여 이진화를 효과적으로 해결하였습니다.

함수

adaptiveThreshold 함수의 설명은 아래와 같습니다.

/** 
@param src 입력 영상
@param dst 출력 영상
@param maxValue 이진화 결과 최대값
@param adaptiveMethod 이진화 블록 평균 계산 방법(AdaptiveThresholdTypes 열거형 상수)
@param thresholdType 타입(THRESH_BINARY 또는 THRESH_BINARY_INV)
@param blockSize 연산시 사용되는 블록 크기
@param C 상수
 */
void adaptiveThreshold( InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C );

예제 코드

adaptiveThreshold 예제 코드를 알아보겠습니다. main 함수에 아래와 같이 코딩합니다.

Mat src = imread("sudoku.jpg", IMREAD_GRAYSCALE);
if (src.empty())
{
	cerr << "image open fail" << endl;
	return -1;
}

imshow("src", src);
imshow("dst", src);

createTrackbar("Threshold", "dst", 0, 200, trackbar_sudoku, &src);
setTrackbarPos("Threshold", "dst", 3);

waitKey();
destroyAllWindows();

return 0;

트랙바에 대한 trackbar_sudoku 콜백 함수를 아래와 같이 만듭니다.

void trackbar_sudoku(int pos, void* userdata)
{
	Mat *pSrc = (Mat *)userdata;
	if (pSrc == nullptr)
		return;


	int bSize = pos;
	if (bSize % 2 == 0) bSize--; // 홀수로 만들기
	if (bSize < 3 ) bSize = 3; // 3보다 크게

	Mat dst;
	adaptiveThreshold(*pSrc, dst, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, bSize, 5);
	imshow("dst", dst);
}

실행 하면 아래와 같이 표시됩니다. threshold 함수와 다르게 전반적으로 이진화가 잘 된 모습을 볼 수 있습니다.

이상으로 adaptiveThreshold에 대해 알아보았습니다.