[OpenCV] 1. 그레이스케일에서 영상 명암

이번글에서는 영상의 명암에 대해 알아보겠습니다.

영상에서 명암비란 밝기 차이의 강도를 의미하고, 전반적으로 비슷한 밝기의 픽셀로 이루어질 경우 명암비가 낮다고 하고 밝은 픽셀과 어두운 픽셀이 골고루 있을 경우 명암비가 높다고 합니다.

오른쪽 레나가 왼쪽 레나보다 명암비가 높습니다.

오른쪽 레나가 왼쪽 레나보다 명암비가 높습니다.

영상에서 명암비를 높이기 위해서는 어두운 부분을 더 어둡게 만들고, 밝은 부분을 더 밝게 만들어야 합니다.
어두운 부분과 밝은 부분의 기준이 되는 값은, 그레이스케일에서 중간 값을 가지는 128입니다.

이 값보다 낮은 값은 더 낮게, 높은 값은 더 높게 하는 소스는 아래와 같습니다.

Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

if (src.empty())
{
	cerr << "image load fail" << endl;
	return;
}

Mat dst(src.rows, src.cols, CV_8UC1);

for (int iRow = 0 ; iRow < src.rows ; iRow++)
{
	for (int iCol = 0 ; iCol < src.cols ; iCol++)
	{
		uchar pixel = src.at<uchar>(iRow, iCol);
		uchar alpha = 50;
		if (128 < pixel)
        	pixel = saturate_cast<uchar>(pixel + alpha); // 밝은 픽셀을 더 밝게
        else if (pixel < 128)
        	pixel = saturate_cast<uchar>(pixel - alpha); // 어두운 픽셀을 더 어둡게

		dst.at<uchar>(iRow, iCol) = pixel;
	}
}

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

waitKey();
destroyAllWindows();

위 소스를 실행할 경우 아래와 같이 출력합니다.

위 코드를 통해 명암비가 더 높아졌지만 이미지가 부자연스러워 졌습니다. 모든 영역에 대해 같은 알파값을 연산해서 그렇습니다.
자연스럽게 명암비를 올리려면 아래 수식을 사용하면 됩니다.

dst(x, y) = src(x, y) + (src(x, y) - 128) * alpha;

위 수식을 코드로 변환하면 아래와 같습니다.

Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

if (src.empty())
{
	cerr << "image load fail" << endl;
	return;
}

float alpha = 1.0f;
Mat dst = src + (src - 128) * alpha;

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

waitKey();
destroyAllWindows();

실행 결과는 아래와 같습니다.

alpah값이 0보다 큰 경우 명암비가 높아지며, 0보다 작은 경우 명암비가 낮아집니다.

다음 글에서는 히스토그램을 이용한 명암비 조절에 대해 알아보겠습니다.