Contents
  1. I. What Is an Image Histogram
  2. II. How to Compute an Image Histogram
  3. III. Two-Dimensional Histograms

I. What Is an Image Histogram

  An image histogram is a statistical feature of image pixel values. It is inexpensive to compute and has many advantages, including invariance to image translation, rotation, and scaling. It is widely used across image processing, especially for grayscale image thresholding, color-based image retrieval, image classification, and backprojection tracking. Common types are grayscale histograms and color histograms.

  Simply put, to a computer an image is just the values of individual pixels, and those pixel values fall within a certain range, so we can count how often each value appears—the statistical result is a histogram.

  After operations such as translating or rotating an image, its histogram information does not change. Therefore, even if two images have identical histograms, they may not be the same image.

II. How to Compute an Image Histogram

OpenCV provides the following function for computing an image histogram:

void calcHist(
		const Mat* 		images,			//源图像组
		int 			nimages,		//源图像组图像个数
		const int* 		channels,		//图像信道
		InputArray 		mask,			//可选的掩码,如果不为空,则必须是8-bit数组,而且大小和原图像相同
		OutputArray 	hist,			//输出直方图数组
		int 			dims,			//处理直方图的维数正数
		const int* 		histSize,		//每一维的直方图的尺寸大小
		const float** 	ranges,			//直方图每一维的数据大小范围
		bool 			uniform=true,
		bool		 	accumulate=false
);

An example program is shown below:

void MyDemo::histShow_Demo(Mat& image) {
	// 三通道分离,用于分别绘制三个通道的直方图
	std::vector<Mat> bgr_plane;
	split(image, bgr_plane);
	// 定义参数变量
	const int channels[1] = { 0 };
	const int bins[1] = { 256 };
	float hranges[2] = { 0,255 };
	const float* ranges[1] = { hranges };
	Mat b_hist;
	Mat g_hist;
	Mat r_hist;
	// 计算Blue, Green, Red通道的直方图
	calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
	calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
	calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);

	// 显示直方图
	int hist_w = 512;
	int hist_h = 400;
	int bin_w = cvRound((double)hist_w / bins[0]);
	Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
	// 归一化直方图数据
	normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	// 绘制直方图曲线
	for (int i = 1; i < bins[0]; i++) {
		line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
			Point(bin_w * (i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
		line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
			Point(bin_w * (i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
		line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
			Point(bin_w * (i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
	}
	// 显示直方图
	namedWindow("Histogram Demo", WINDOW_AUTOSIZE);
	imshow("Histogram Demo", histImage);
}

II. How to Compute an Image Histogram

III. Two-Dimensional Histograms

  We know that although RGB has three channels, in the HSV color space only H and S represent color, while V represents brightness. Therefore, representing an image’s color requires only two dimensions, H and S, which can form a planar histogram.

  Computing a two-dimensional histogram uses the same function as a one-dimensional histogram. The approach is as follows:

void MyDemo::histShow2_Demo(Mat& image) {
	// 2D 直方图
	Mat hsv, hs_hist;
	cvtColor(image, hsv, COLOR_BGR2HSV);	//RGB转HSV
	int hbins = 30, sbins = 32;				//设置二维直方图的直方个数
	int hist_bins[] = { hbins, sbins };
	float h_range[] = { 0, 180 };			//H:0-180
	float s_range[] = { 0, 256 };			//S:0-256
	const float* hs_ranges[] = { h_range, s_range };
	int hs_channels[] = { 0, 1 };			//选择通道0和通道1
	calcHist(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_ranges, true, false);

	//进行归一化
	double maxVal = 0;
	minMaxLoc(hs_hist, 0, &maxVal, 0, 0);	//找到最大值
	int scale = 10;
	Mat hist2d_image = Mat::zeros(sbins * scale, hbins * scale, CV_8UC3);
	for (int h = 0; h < hbins; h++) {
		for (int s = 0; s < sbins; s++)
		{
			float binVal = hs_hist.at<float>(h, s);
			int intensity = cvRound(binVal * 255 / maxVal);
			rectangle(hist2d_image, Point(h * scale, s * scale),
				Point((h + 1) * scale - 1, (s + 1) * scale - 1),
				Scalar::all(intensity),
				-1);
		}
	}
	applyColorMap(hist2d_image, hist2d_image, COLORMAP_JET);
	imshow("H-S Histogram", hist2d_image);
}

III. Two-Dimensional Histograms