관리 메뉴

공부 기록장 💻

[OpenCV/C++] 히스토그램 분석: 히스토그램 스트레칭 (Histogram Stretching) 과 히스토그램 평활화, 균등화, 평탄화 본문

# Tech Studies/Computer Vision • OpenCV

[OpenCV/C++] 히스토그램 분석: 히스토그램 스트레칭 (Histogram Stretching) 과 히스토그램 평활화, 균등화, 평탄화

dream_for 2022. 11. 30. 02:30
 

Open CV 4로 배우는 컴퓨터 비전과 머신러닝 CH5 영상의 밝기와 명암비 조절  정리

 

히스토그램 스트레칭

 

히스토그램 스트래칭(Histogram Stretching) 이란, 영상의 히스토그램이 그레이스케일 전 구간에 걸쳐서 나타나도록 변경하는 선형 변환 기법이다.
보통 명암비가 낮은 영상은 히스토그램이 특정 구간에 집중되어 나타나는데, 이러한 히스토그램을 마치 고무줄을 잡아 늘이듯 펼쳐서 히스토그램 그래프가 그레이스케일 전 구간에서 나타나도록 변환하는 기법이다. 히스토그램 스트레칭을 수행한 영상은 명암비가 높아져서 대체로 선명하고 보기 좋은 사진으로 바뀐다.

히스토그램 스트레칭의 수식은 다음과 같이 표현할 수 있다.



Gmax가 입력 영상의 픽셀 값중 가장 큰 그레이스케일 값, Gmin이 가장 작은 그레이스케일 값이라 할 때,
그레이스케일 전체 분포를 양방향으로 늘려 Gmin은 0으로, GMax는 255가 되도록 변환하는 수식이다.

다음과 같이 히스토그램 스트레칭을 통해, (a)의 레나 영상이 (c) 영상으로 변환되어 명암비가 증가하여 더욱 뚜렷한 이미지가 나타남을 확인할 수 있다.
히스토그램 그래프의 분포도 또한 전체적으로 양 옆으로 늘어났고, 픽셀 값의 최솟값이었던 Gmin은 0으로, 최댓값이었던 Gmax는 255 값으로 변환된 것 또한 확인할 수 있다.


위의 (b)의 변환 함수 그래프를 통해 히스토그램 스트레칭을 수행하게 되는데,
이는 (Gmax, 0), (Gmin, 255)을 각각 지나가는 직선의 방정식을 구하여 얻을 수 있다.

아래와 같이 직선의 기울기와 y 절편을 구하면 되는데,
직선의 기울기는 255 / (Gmax - Gmin) 이고, y절편은 비례식을 이용해 구하면 -255*Gmin / (Gmax - Gmin) 으로,
결과적으로 직선의 방정식은 다음과 같이 결정된다.


히스토그램 스트레칭을 수행하기 위한 함수는 OpenCV에서 제공하지 않지만,
기본적인 산술 연산 재정의를 지원하므로, Gmin과 Gmax 값을 minMaxLoc() 함수를 사용하면 위의 수식을 소스 코드로 변경할 수 있다.

// 히스토그램 스트레칭
void histogram_stretching() {
	Mat src = imread("hawkes.bmp", IMREAD_GRAYSCALE);
	if (src.empty()) {
		cerr << "Image load failed!" << endl;
		return;
	}
	double gmin, gmax;
	minMaxLoc(src, &gmin, &gmax); // 그레이스케일 영상의 최솟값과 최댓값 구하기
	Mat dst = (src - gmin) * 255 / (gmax - gmin); // 히스토그램 스트레칭 수식 적용하여 dst에 적용

	// 입력 영상의 히스토그램 그래프
	imshow("src", src);
	imshow("srcHist", getGrayHistImage(calcGrayHist(src)));

	// 결과 영상의 스트레칭 결과 히스토그램 그래프
	imshow("dst", dst);
	imshow("dstHist", getGrayHistImage(calcGrayHist(dst)));

	waitKey();
	destroyAllWindows();
}


결과는 다음과 같다.
가운데에서 약간 오른쪽 위치에 분포해있던 히스토그램 그래프가 전체적으로 양 옆으로 넓게 퍼지며,
영상은 전체적으로 어두워졌고 명암비가 증가하여 뚜렷한 이미지가 나타탐을 확인할 수 있다.

 


 

 

히스토그램 평활화


히스토그램 평활화(Histogram Equalization)은 히스토그램 스트레칭과 더불어, 영상의 픽셀 값 분포가 그레이스케일 전체 영역에서 골고루 나타나도록 변경하는 알고리즘 중 하나이다.
이는 히스토그램 그래프에서 특정 그레시으케일 값 근방에서 픽셀 분포가 너무 많이 뭉쳐 있는 경우 이를 넓게 펼쳐 주는 방식으로 픽셀 값 분포를 조절한다.
히스토그램 평활화는 히스토그램 균등화, 히스토그램 평탄화라는 용어로도 번역되어 사용되고 있다.

히스토그램 그레이스케일 값 g에 대하여, 해당 g의 픽셀 개수를 함수 h(g) 로 표현해보자.
히스토그램 평활화를 계산하기 위해서는 누적함수 H(g)를 구해야 한다.

히스토그램 평활화는 H(g)를 픽셀 값 변환 함수로 사용하는데, 우선 H(g) 함수의 최댓값이 255가 되도록 정규화 과정을 거쳐야 한다.
입력 영상의 픽셀 개수를 NM이라 표기할 때, 히스토그램 평활화는 다음의 형태로 정의된다.


Lmax는 영상이 가질 수 있는 최대 밝기 값을 의미한하고, (일반적으로는 Lmax=255이다.) round()는 반올림 함수를 나타낸다.

4x4의 간단한 예시 영상을 통해 확인해보자.
h(g)는 0~7 사이의 픽셀값 g에 대한 픽셀 개수를 나타내는 함수이며, H(g)는 누적 함수이다.
영상의 최대 밝기 값이 7이고, 전체 픽셀 개수가 16이므로 정규화를 위한 상수는 7/16으로, 각각의 H(g)이 7/16을 곱한 값을 결과 영상의 픽셀 값으로 설정하게 된다.

결국 정규화 과정을 거친 결과는 (c)와 같이 나타난다.


OpenCV에서는 그레이스케일 영상의 히스토그램 평활화를 수행하는 equalizeHist() 함수를 제공하는데, 함수 원형은 다음과 같다.

입력 영상은 8비트 1채널인 그레이스케일 영상 (CV_8UC1) 만 허용한다.

// 히스토그램 평활화
void histogram_equalization() {
	Mat src = imread("hawkes.bmp", IMREAD_GRAYSCALE);
	if (src.empty()) {
		cerr << "Image load failed" << endl;
		return;
	}

	Mat dst;
	equalizeHist(src, dst);

	imshow("src", src);
	imshow("srcHist", getGrayHistImage(calcGrayHist(src)));

	imshow("dst", dst);
	imshow("dstHist", getGrayHistImage(calcGrayHist(dst)));

	waitKey();
	destroyAllWindows();
}


입력 영상과 히스토그램 평활화를 수행한 결과 영상은 다음과 같이 나타난다.
히스토그램 평활화를 수행한 결과 영상의 히스토그램 그래프가 전체적으로 넓게 퍼져 분포되어 뚜렷한 결과 이미지가 나타남을 확인할 수 있다.

 

728x90
반응형
Comments