opencv c++ 히스토그램을 이용하여 이미지 밝기 조절

  • 최초 작성일: 2022년 1월 11일(화)

목차

[TOC]


목표

우선, 히스토그램이 무엇인지 알아보고 가자.

image

히스토그램(histogram)은 표로 되어 있는 도수 분포를 정보 그림으로 나타낸 것이다.

더 간단하게 말하면, 도수분포표를 그래프로 나타낸 것이다.

그러므로, 히스토그램을 이미지에 접목을 시키면, 각 픽셀의 값들의 분포를 그래프로 표기할 수가 있다.

그러면 불러온 이미지의 픽셀 값들에 대한 분포도를 가시적으로 더 쉽게 확인할 수 있다.

히스토그램의 기능들 중에 equalization이라는 기능이 있는데, 그것은 밝기 값들이 한 곳으로 모여있다면, 그 값들을 균등하게 분산시키는 기능이다.

아래의 사진은 가운데에 모여있는 값들을 보이는 이미지를 equaliation해준 결과를 보여준다.

image

image

즉, 이 작업으로 밝기 값들을 효과적으로 조절할 수 있는 것이다.

사칙 연산만으로는 이러한 결과를 얻기에는 많은 어려움이 있을 것이기 때문에, 효과적인 방법이라 할 수 있다.


실습

자, 그럼 이번에는, 히스토그램으로 불러온 이미지의 밝기를 조절해보자.

불러온 이미지들의 밝기 값들의 분포도를 확인 및 비교해보자.

그리고 나서, 이미지에 histogram equalization 함수 실행 결과를 확인해보자.


소스 코드

#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main(int ac, char** av) {

	Mat img1 = imread("lion.png", 0); //grayscale image
	// Mat img1 = imread("doctor.png", 0); //grayscale image

	Mat img_hist;

	Mat hist_equal;
	
	equalizeHist(img1, hist_equal);

	MatND histogram;
	MatND histogram_;

	const int* channelN = { 0 };
	float channel_range[] = { 0.0, 255.0 };
	const float* channel_ranges = channel_range;
	int binsNum = 255;

	calcHist(&img1, 1, channelN, Mat(), histogram, 1, &binsNum, &channel_ranges);
	calcHist(&hist_equal, 1, channelN, Mat(), histogram_, 1, &binsNum, &channel_ranges);

	int hist_w = img1.cols;
	int hist_h = img1.rows;
	int bin_w = cvRound((double)hist_w / binsNum);

	int hist_w_ = hist_equal.cols;
	int hist_h_ = hist_equal.rows;
	int bin_w_ = cvRound((double)hist_w_ / binsNum);

	Mat hist_img(hist_h, hist_w, CV_8UC1, Scalar::all(0));
	Mat hist_img_(hist_h_, hist_w_, CV_8UC1, Scalar::all(0));

	normalize(histogram, histogram, 0, hist_img.rows, NORM_MINMAX, -1, Mat());
	normalize(histogram_, histogram_, 0, hist_img_.rows, NORM_MINMAX, -1, Mat());

	for (int i = 1; i < binsNum; i++) {
		line(hist_img, Point(bin_w * (i - 1), hist_h - cvRound(histogram.at<float>(i - 1))), Point(bin_w * (i), hist_h - cvRound(histogram.at<float>(i))), Scalar(255, 0, 0), 1, 8, 0);
	}
	for (int i = 1; i < binsNum; i++) {
		line(hist_img_, Point(bin_w_ * (i - 1), hist_h_ - cvRound(histogram_.at<float>(i - 1))), Point(bin_w_ * (i), hist_h_ - cvRound(histogram_.at<float>(i))), Scalar(255, 0, 0), 1, 8, 0);
	}

	imshow("origin", img1);
	imshow("histogram", hist_img);

	imshow("hist_equal", hist_equal);
	imshow("histogram_equal", hist_img_);

	waitKey(0);

	return(0);
}


결과

아래의 사진은 불러온 이미지를 히스토그램으로 표현한 것이다.

사자 사진의 히스토그램을 보면, 잘 안 보이겠지만 왼쪽에 값들의 분포가 치우쳐져있다. 그 이유는, 바탕 화면이 검정색이라 낮은 픽셀 값들의 분포도가 높아서 그런 모습을 보이는 것이다.

반면에, 두번째 의사 사진의 히스토그램을 보면, 비교적 중간값들의 분포도가 높은 것을 볼 수 있다.

추가로, 이미지를 histogram equalization 한 결과도 확인할 수 있다.

image

image