直方图计算(Histogram)

1、直方图概念;
2、相关API;
3、代码演示;

直方图

1、直方图:像素值经统计得到的图像;一切图像的属性值,都可以建立直方图,基于图像像素的灰度直方图是最常见的;

2、直方图的属性:

  • dims : 维度(通道值)
  • bins : 表示在维度中子区域大小的划分,如上图;
  • range : 表示值的范围;

相关API

1、API : split() : 将多通道图像分为多个单通道图像;

	split(
		const Mat & src,   //输入的多通道图像
		Mat* mvbegin   // 输出的单通道图像数组
	)

2、API : calcHist() : 计算直方图

直方图显示

Code

思路:先将传入图像分离为单通道图像(Split()函数),然后调用calcHist()计算每个单通道图像的直方图值,再创建绘制窗口对RGB的直方图值进行显示,为显示所有数据需要对直方图的值归一化到新建的窗口高度范围内,然后调用画直线AP依次画出直方图曲线;

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

using namespace std;
using namespace cv;

int main(int argc ,char** argv)
{
   
	Mat src = imread("C:\\Users\\hello\\Desktop\\18.jpg");
	if (!src.data)
	{
   
		cout << "could not load the image..." << endl;
		return -1;
	}
	namedWindow("input image", CV_WINDOW_AUTOSIZE);
	imshow("input image", src);

	//定义一个数组
	vector<Mat> bgr_image;
	split(src, bgr_image);

	//分通道显示
	imshow("blue channel image", bgr_image[0]);
	imshow("green channel image", bgr_image[1]);
	imshow("red channel image", bgr_image[2]);

	int histSize = 256;
	float range[] = {
    0,256 };  //256为空
	const float *histRanges = {
    range };  

	Mat b_hist, g_hist, r_hist;

	//计算直方图
	calcHist(&bgr_image[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRanges, true, false);
	calcHist(&bgr_image[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRanges, true, false);
	calcHist(&bgr_image[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRanges, true, false);

	//绘制直方图
	int hist_h = 400;   //高度匹配
	int hist_w = 512;
	int bin_w = hist_w / histSize;
	//归一化直方图计算数据, 进行高度匹配 防止像素的最大次数超过400
	normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1);
	normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1);
	normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1);

	Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));  //创建一个合适大小类型的Mat对象

	//render histogram chart 绘制直方图曲线
	for (int i = 1; i < histSize; i++)
	{
   
		line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(b_hist.at<float>(i - 1))), 
			Point((i)*bin_w, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, LINE_AA);

		line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(g_hist.at<float>(i - 1))),
			Point((i)*bin_w, hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, LINE_AA);

		line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(r_hist.at<float>(i - 1))),
			Point((i)*bin_w, hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, LINE_AA);
	}

	imshow("histogram image", histImage);

	waitKey(0);
	return 0;
}

效果

显示曲线如下:直方图可以用来寻找阈值