一、什么是直方图

  直方图广泛应用于很多计算机视觉处理当中。通过标记帧与帧之间显著的边缘和颜色的变化,可以检测视频中的场景变化。在每个兴趣点设置一个有相似特征的直方图所构成的“标签”,可以用来标记各种不同的事情,比如图像的色彩分布,物体边缘梯度模板等等。是计算机视觉中最经典的工具之一。
  简单来说直方图就是对数据进行统计的一种方法,它将统计值组织到一系列事先定义好的bin中。bin中的数值是从数据中计算出的特征的统计量,这些数据可以是梯度、方向、色彩以及其他任何特征。直方图获取的是数据分布的统计图,通常情况下,直方图的维度要低于原始数据。由于原始数据可以表示任何事情,直方图就可以很好的表示图像的特征。

二、直方图的相关函数

1、计算直方图 calcHist()

  函数cv: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 
	) 	

  其中,第一个参数表示输入的数组或数组集,它们需要相同的深度和相同的尺寸。第二个参数表示输入数组的个数,也就是第一个参数中有几个原数组。第三个参数表示需要统计的通道索引。第四个参数表示可选的操作掩码,如果不为空,那么必须为8位,并且与images[i]有同样大小的尺寸,这里的非零掩码元素用于标记出统计直方图的数组元素数据。第五个参数表示输出的目标直方图,是一个二维数组。第六个参数表示需要计算的直方图维度,必须是正数。第七个参数表示存放每个维度的直方图尺寸的数组。第八个参数表示每一维数值的取值范围,第九个参数表示直方图是否均匀的标识符,默认为true。第十个参数表示累计标识符,有默认值false。若为true,直方图在配置阶段不会被清零。此功能主要是允许从多个阵列中计算单个直方图,或者用于在特定的时间更新直方图。

2、找寻最值 minMaxLoc()

  函数minMaxLoc() 查找最小和最大元素值及其位置。在整个数组中搜索极值,如果掩码不是空数组,则在指定的数组区域中搜索极值。

void cv::minMaxLoc 	( 	InputArray  	src,
		double *  	minVal,
		double *  	maxVal = 0,
		Point *  	minLoc = 0,
		Point *  	maxLoc = 0,
		InputArray  	mask = noArray() 
	) 	

  其中第一个参数表示输入的单通道列阵。第二个参数表示返回最小值的指针,若无须返回则为NULL。第三个参数表示返回的最大值的指针,若无须返回则为NULL。第四个参数表示返回最小位置的指针若无须返回则为NULL。第五个参数表示返回最大位置的指针若无须返回则为NULL。

三、程序演示

1、色调 —— 饱和度直方图

  下面我们来说明一下如何计算彩色图像的色调 —— 饱和度直方图。

#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;

int main()
{
	// 读取图像并创建一个Mat对象来存储图像数据
	Mat src, hsv;
	src = imread("C://Users//86173//Desktop//c.png");

	// 检查图像是否成功加载
	if (!src.data)
		return -1;

	// 将图像从BGR颜色空间转换为HSV颜色空间
	cvtColor(src, hsv, COLOR_BGR2HSV);

	// 定义直方图的参数
	int hbins = 30, sbins = 32;
	int histSize[] = { hbins, sbins };
	float hranges[] = { 0, 180 };
	float sranges[] = { 0, 256 };
	const float* ranges[] = { hranges, sranges };

	// 创建一个用于存储直方图的Mat对象
	MatND hist;

	// 指定通道
	int channels[] = { 0, 1 };

	// 计算直方图
	calcHist(&hsv, 1, channels, Mat(), hist, 2, histSize, ranges, true, false);

	// 寻找直方图的最大值
	double maxVal = 0;
	minMaxLoc(hist, 0, &maxVal, 0, 0);

	// 定义绘制直方图的参数
	int scale = 10;
	Mat histImg = Mat::zeros(sbins * scale, hbins * 10, CV_8UC3);

	// 绘制直方图
	for (int h = 0; h < hbins; h++)
	{
		for (int s = 0; s < sbins; s++)
		{
			float binVal = hist.at<float>(h, s);
			int intensity = cvRound(binVal * 255 / maxVal);
			rectangle(histImg, Point(h * scale, s * scale), Point((h + 1) * scale - 1, (s + 1) * scale - 1), Scalar::all(intensity), -1);
		}
	}

	// 创建并显示源图像窗口
	namedWindow("Source", 1);
	imshow("Source", src);

	// 创建并显示H-S直方图窗口
	namedWindow("H-S Histogram", 1);
	imshow("H-S Histogram", histImg);

	waitKey();
}

【OpenCV • c++】直方图计算 | 绘制 H-S 直方图 | 绘制一维直方图 | 绘制 RGB 三色直方图-LMLPHP

2、一维直方图

  下面我们来介绍一下如何计算绘制图像一维直方图。

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/utils/logger.hpp>

using namespace cv;
using namespace std;

int main()
{
    // 读取图像
    Mat srcImage = imread("C://Users//86173//Desktop//c.png");
    if (!srcImage.data)
    {
        printf("fail to load image!\n");
        return 0;
    }
    // 显示原始图像
    imshow("【原始图】", srcImage);

    // 计算直方图
    MatND dstHist;
    int dims = 1;
    float hranges[] = { 0, 255 };
    const float* ranges[] = { hranges };
    int size = 256;
    int channels = 0;

    calcHist(&srcImage, 1, &channels, Mat(), dstHist, dims, &size, ranges, true, false);

    // 创建用于显示直方图的图像
    int scale = 1;
    Mat dstImage(size * scale, size, CV_8U, Scalar(0));

    // 获取直方图的最小值和最大值
    double minValue = 0;
    double maxValue = 0;
    minMaxLoc(dstHist, &minValue, &maxValue, 0, 0);

    // 绘制直方图
    int hpt = saturate_cast<int>(0.9 * size);
    for (int i = 0; i < 256; i++)
    {
        float binValue = dstHist.at<float>(i);
        int realValue = saturate_cast<int>(binValue * hpt / maxValue);
        rectangle(dstImage, Point(i * scale, size - 1), Point((i + 1) * scale - 1, size - realValue), Scalar(255));
    }
    // 显示一维直方图
    imshow("一维直方图", dstImage);

    waitKey(0);
    return 0;
}

【OpenCV • c++】直方图计算 | 绘制 H-S 直方图 | 绘制一维直方图 | 绘制 RGB 三色直方图-LMLPHP

3、RGB 三色直方图

  下面我们来介绍一下如何绘制图像的 RGB 三色直方图。

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/utils/logger.hpp>

using namespace cv;
using namespace std;

int main()
{
    // 读取图像
    Mat srcImage = imread("C://Users//86173//Desktop//c.png");
    if (!srcImage.data)
    {
        printf("fail to load image!\n");
        return 0;
    }
    imshow("【原始图】", srcImage);

    int bins = 256;
    int hist_size[] = { bins };
    float range[] = { 0, 256 };
    const float* ranges[] = { range };
    MatND redHist, grayHist, blueHist;

    // 计算红色分量的直方图
    int channels_r[] = { 0 };
    calcHist(&srcImage, 1, channels_r, Mat(), redHist, 1, hist_size, ranges, true, false);

    // 计算绿色分量的直方图
    int channels_g[] = { 1 };
    calcHist(&srcImage, 1, channels_g, Mat(), grayHist, 1, hist_size, ranges, true, false);

    // 计算蓝色分量的直方图
    int channels_b[] = { 2 };
    calcHist(&srcImage, 1, channels_b, Mat(), blueHist, 1, hist_size, ranges, true, false);

    // 绘制三色直方图
    // 参数准备
    double maxValue_red, maxValue_green, maxValue_blue;
    minMaxLoc(redHist, 0, &maxValue_red, 0, 0);
    minMaxLoc(grayHist, 0, &maxValue_green, 0, 0);
    minMaxLoc(blueHist, 0, &maxValue_blue, 0, 0);

    int scale = 1;
    int histHeight = 256;
    Mat histImage = Mat::zeros(histHeight, bins * 3, CV_8UC3);

    // 正式绘制
    for (int i = 0; i < bins; i++)
    {
        // 参数准备
        float binValue_red = redHist.at<float>(i);
        float binValue_green = grayHist.at<float>(i);
        float binValue_blue = blueHist.at<float>(i);
        int intensity_red = cvRound(binValue_red * histHeight / maxValue_red);    // 要绘制的高度
        int intensity_green = cvRound(binValue_green * histHeight / maxValue_green);    // 要绘制的高度
        int intensity_blue = cvRound(binValue_blue * histHeight / maxValue_blue);    // 要绘制的高度

        // 绘制红色分量的直方图
        rectangle(histImage, Point(i * scale, histHeight - 1), Point((i + 1) * scale - 1, histHeight - intensity_red), Scalar(255, 0, 0));
        // 绘制绿色分量的直方图
        rectangle(histImage, Point((i + bins) * scale, histHeight - 1), Point((i + bins + 1) * scale - 1, histHeight - intensity_green), Scalar(0, 255, 0));
        // 绘制蓝色分量的直方图
        rectangle(histImage, Point((i + bins * 2) * scale, histHeight - 1), Point((i + bins * 2 + 1) * scale - 1, histHeight - intensity_blue), Scalar(0, 0, 255));
    }
    // 显示直方图
    imshow("图像的RGB直方图", histImage);

    waitKey(0);
    return 0;
}

【OpenCV • c++】直方图计算 | 绘制 H-S 直方图 | 绘制一维直方图 | 绘制 RGB 三色直方图-LMLPHP

【OpenCV • c++】直方图计算 | 绘制 H-S 直方图 | 绘制一维直方图 | 绘制 RGB 三色直方图-LMLPHP

更多专栏订阅推荐:

【OpenCV • c++】直方图计算 | 绘制 H-S 直方图 | 绘制一维直方图 | 绘制 RGB 三色直方图-LMLPHP

09-10 20:53