본문 바로가기
코딩/OpenCV

[C++ opencv] 효율적인 Histogram 이용한 이미지 밝기 조절

by DIYver 2020. 6. 25.

본문 목표

이미지의 Histogram 정보를 통해서 이미지의 밝기를 효과적으로 조절할 수 있다.

OpenCV 에서도 해당 기능을 지원하는데, 이를 적용해보도록 한다.

 

 

키워드 : equalizeHistHistogram equalization,  히스토그램 equalizeHist

 

 

 

 

 

 

 

 

 

 

히스토그램 - 원리 이해

 

히스토그램은 이미지의 밝기 값이 0~255 까지 있을 때,

 

픽셀들이 얼마나 그 값들을 갖고 있는지 나타내주는 그래프 이다.

 

예를 들면, 위와 같이 a 라는 이미지의 픽셀들 값이 행렬처럼 존재한다고 하면

 

오른쪽 그래프처럼 10의 값을 갖고 있는 픽셀 6개, 20의 값을 갖고 있는 픽셀 4개, 50의 값을 갖고있는 픽셀 7개, 90의 값을 갖고있는 픽셀 3개 로 나타낼 수 있다.

 

 

이런 히스토그램을 이미지에 적용한다면 다음과 같은 결과를 볼 수 있다.

 

왼쪽 사진의 히스토그램이 오른쪽 그래프이다.

 

한눈에 봐도 가운데 값(60~140)에 픽셀들의 값이 쏠려있는 것을 확인할 수 있다.

 

사람눈으로 봐도 왼쪽 사진은 흐려서 보기 좋지 못한 사진이라고 할 수 있다.

 

당연히 이런 사진은 컴퓨터에서 연산하기에도 좋지 않은 사진이다.

 

이러한 사진을 효과적으로 밝기를 조절할 수 있는데,

 

우리는 이 방식을 Histogram equalization 이라고 한다.

 

가운데 쏠려있는 밝기 정보를 골고루 분산시켜 주는 것이다.

 

결과부터 보자면 위와 같이 히스토그램 정보를 통해서 균일하게 펼쳐주었음을 확인할 수 있다.

 

확실히 전의 사진보다 뚜렷해졌음을 확인할 수 있다.

 

 

즉, 히스토그램 정보를 통해서 균일하게 밝기 값을 효과적으로 조절할 수 있는 것이다.

 

사칙연산만으로는 위와같은 결과를 얻기는 분명 힘들 것이므로, 효과적이라 할 수 있다.

 

 

 

위의 사진들도 마찬가지다.

 

어두운 상황의 사진을 보면 히스토그램 정보가 어두운 값에 몰려있는데,

 

이를 균일하게 펴주면서 아래와 같이 뚜렷한 결과물을 얻을 수 있게 되는 것이다.

 

 

 

 

 

 

 

 

 

 

 

 

 

알아볼 함수 원형

- 히스토그램 계산 ( calcHist )

...
	MatND histogram;

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

	calcHist(&img_1, 1,channel_numbers, Mat(), histogram, 1, &number_bins, &channel_ranges);
 ...

 

https://swprog.tistory.com/entry/OpenCV-histogram

 

OpenCV : calcHist함수를 이용한 histogram 구하기 - Gray이미지에 대해

Histogram 그리기 이미지에서 픽셀들이 가지는 값들의 출현빈도를 히스토그램 (histogram)이라고 한다. 예를 들어, gray 이미지에서 각 픽셀은 0부터 255까지의 값을 갖는다. 이미지의 크기를 300 x 300 이

swprog.tistory.com

자세한 사용 방법은 위의 블로그에서 친절하게 다뤄주고 있으니, 참고하면 좋을것 같다.

 

calcHist( ) 함수는 이미지의 히스토그램 정보를 계산하는 역할을 한다.

 

다만 이 결과값을 확인하기가 까다로우니 아래의 예제코드를 참고하는 것이 정신건강에 이로울 것이다.

 

 

 

 

 

 

히스토그램 분석 코드 테스트 결과

- CODE

#include <opencv2/opencv.hpp>
//#include <iostream>

using namespace cv;
using namespace std;

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

	Mat img_1 = imread("Lenna.png",0);	//이미지를 grayscale로 불러옴

	Mat img_2 = img_1 * 2;
	Mat img_3 = img_1 / 2;
	Mat img_hist;

	MatND histogram;

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

	calcHist(&img_1, 1,channel_numbers, Mat(), histogram, 1, &number_bins, &channel_ranges);

	// plot the histogram
	int hist_w = img_1.cols;
	int hist_h = img_1.rows;
	int bin_w = cvRound((double)hist_w / number_bins);

	Mat hist_img(hist_h, hist_w, CV_8UC1, Scalar::all(0));
	normalize(histogram, histogram, 0, hist_img.rows, NORM_MINMAX, -1, Mat());

	for (int i = 1; i < number_bins; 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("Origianl",img_1);
	imshow("Histogram", hist_img);
	


	//imshow("original", img_1);
	//imshow("img_mul", img_2);
	//imshow("img_div", img_3);

	waitKey(0);


	return 0;
}

 

- RESULT

 

위의 Lenna 사진에 대한 히스토그램 정보를 그래프로 확인 가능하다.

 

비교적 Lenna 이미지는 균일한 히스토그램 분포를 갖고 있는 것으로 판단된다.

 

한눈에 봐도 인물이 뚜렷하게 나와있어서, 이는 영상처리에 사용되어도 큰 문제 없을듯 싶다.

 

 

 

 

 

 

 

 

 

 

 

 

 

알아볼 함수 원형

- 히스토그램 균일화 ( equalizeHist )

...

	Mat img_1 = imread("Lenna.png", 0);	//이미지를 grayscale로 불러옴

	Mat hist_img;

	equalizeHist(img_1, hist_img);
    
...

 

equalizeHist(Input Array, Output Array) : Input Array(입력 이미지)의 히스토그램 정보를 통해서 균일화를 해준 후 해당 정보를 Output Array(결과 이미지)에 저장한다.

 

해당 함수는 사용하기가 정말 쉽다.

 

그냥 입력 이미지와 연산 처리 된 결과를 저장한 결과 이미지 변수만 필요하다.

 

자동으로 균일하게 히스토그램을 분포시켜준다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

히스토그램 균일화  코드 테스트 결과

- CODE

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

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

	Mat img_1 = imread("Lenna.png", 0);	//이미지를 grayscale로 불러옴

	Mat hist_img;

	equalizeHist(img_1, hist_img);

	imshow("Original", img_1);
	imshow("Histogram equalization", hist_img);

	waitKey(0);



	return 0;
}

 

- RESULT

 

원본 이미지
히스토그램 균일화 이미지

 

분명 원본 이미지도 괜찮다고 생각했었는데,

 

히스토그램 균일화 작업을 하니까 이미지가 더 선명해졌음을 알 수 있다.

 

결과만 놓고 쉽게 이해하자면

 

기본 이미지에 대비를 더 심하게 한것과 동일한 결과라 할 수 있다.

 

하지만 히스토그램 균일화 작업을 대비를 높였다라고 쉽게 부르지는 않는다.

 

대비를 높였다라기 보다는 이미지 밝기를 고르게 만드는 작업이기 때문이다.

 

 

아무튼, 이런 이미지 밝기 조절 기법은 OpenCV를 떠나서 모든 영상처리에 기본적으로 사용된다.

 

이 작업을 하지 않으면 상황이 바뀔 때, 노이즈가 많이 잡히거나, 정상적인 처리를 할 수 없게 되는 것이다.

 

 

하지만 단순히 어두운 이미지를 밝게 한다면 덧셈이나 곱셈 연산을 사용하는것이 Histogram equalization 보다 더 빠를 것이다.

 

왜냐하면 Histogram equalizationhistogram을 한 번 분석하고 그거를 균일화 시키는 작업이 필요하기 때문이다.

 

상황에 맞는 방법으로 이미지 밝기를 조절하길 바란다.

 

 

 

 

 

 

 

 

도움이 되었거나, 문제가 있는 경우 댓글로 알려주세요~!

감사의 댓글은 작성자에게 큰 힘이 됩니다 ^^

 

댓글