본문 바로가기

Computer Vision by OpenCV

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

반응형


Histogram 그리기


이미지에서 픽셀들이 가지는 값들의 출현빈도를 히스토그램 (histogram)이라고 한다. 

예를 들어, gray 이미지에서 각 픽셀은 0부터 255까지의 값을 갖는다.

이미지의 크기를 300 x 300 이라고 한다면, 총 90,000개의 픽셀들을 0~255 값에 따라 분류하여

각 개별값을 갖는 픽셀들이 몇 개씩인지 알아낸 것이 히스토그램이다.


히스토그램은 contranst enhancement (안 보이는 부분을 잘 보이게) 등에 사용되는데,

이 때 사용되는 기술이 histogram equalization이다. 이것의 원리는 이 <<블로그>>를 참조한다.


OpenCV에서는 이미지의 히스토그램 계산이 쉽도록 함수 calcHist( )를 제공한다.


void cv::calcHist(const Mat * images,
int nimages,
const int * channels,
InputArray mask,
OutputArray hist,
int dims,
const int * histSize,
const float ** ranges,
bool uniform = true,
bool accumulate = false 
)



images: Histogram을 계산할 이미지들에 대한 배열이다.

nimages: images 배열에 포함된 이미지의 개수 이다.

channels: Histogram을 계산할 채널 번호들의 배열이다. 예를 들어, 아래 그림과 같이 BGR 이미지 2장에 대해, 첫 번째 이미지는 B 채널, 두 번째 이미지는 G 채널에 대해서 histogram을 구하고자 한다면 {0, 4}를 배열에 넣어서 전달해야 한다.



mask: Histogram을 계산할 영역을 지정할 수 있다. 옵션사항이고, emptry mask (즉, Mat( ))를 전달하면 아무런 동작도 하지 않는다.

hist: Histogram 계산결과를 저장한다.

dims: Histogram 계산결과를 저장한 hist의 차원을 가리킨다. 

histSize: 각 차원의 bin 개수, 즉 빈도수를 분류할 칸의 개수를 의미한다.

ranges: 각 차원의 분류 bin의 최소값과 최대값을 의미한다.


아래는 gray 이미지에 대해 픽셀값 0 ~ 255에 대해 histogram을 계산하여 그래프로 표시한 결과이다.


<그림 1> Histogram을 계산할 대상 이미지 (gray)


<그림 2> 그림 1에 대한 Histogram 계산결과를 시각화한 결과


위의 결과를 만들어 내기 위한 프로그램의 소스코드이다.


<소스코드 1> 히스토그램을 계산하고 그래프로 시각화하는 프로그램

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

#define SCALE 0.2

int main(int argc, char** argv)
{

	if (argc != 2)
	{
		cout << " Provide image name to read" << endl;
		return -1;
	}

	Mat inputImg;
	Mat greyImg;

	inputImg = imread(argv[1], CV_LOAD_IMAGE_COLOR);
	resize(inputImg, inputImg, Size(), SCALE, SCALE, CV_INTER_AREA);

	// inputImg를 gray영상(greyImg)으로 변환한다.
	cvtColor(inputImg, greyImg, CV_BGR2GRAY);

	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(&greyImg, 1, channel_numbers, Mat(), histogram, 1, &number_bins, &channel_ranges);

	// Plot the histogram
	int hist_w = 512; int hist_h = 400;
	int bin_w = cvRound((double)hist_w / number_bins);

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

	for (int i = 1; i < number_bins; i++)
	{
		line(histImage, 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), 2, 8, 0);
	}

	namedWindow("Original", CV_WINDOW_AUTOSIZE);
	namedWindow("Histogram", CV_WINDOW_AUTOSIZE);
	
	moveWindow("Original", 100, 100);
	moveWindow("Histogram", 120, 120);

	imshow("Original", greyImg);
	imshow("Histogram", histImage);

	waitKey(0);
	return 0;
}


반응형