目录
实验原理
calcHist
函数通常是指在计算机视觉和图像处理中用于计算图像直方图的一个函数。
cv:calcHist
() 用于计算一个或多个数组的直方图。它可以处理图像数据并返回一个表示像素强度分布的向量(对于灰度图像)或颜色分布(对于彩色图像)。用于计算一个或多个数组的直方图。它可以处理图像数据并返回一个表示像素强度分布的向量(对于灰度图像)或颜色分布(对于彩色图像)。
calcHist
函数原型
C++: void calcHist(const Mat* arrays, int narrays,
const int* channels, InputArray mask, OutputArray hist,
int dims, const int* histSize, const float** ranges,
bool uniform=true, bool accumulate=false );
C++: void calcHist(const Mat* arrays, int narrays,
const int* channels, InputArray mask, SparseMat& hist,
int dims, const int* histSize, const float** ranges,
bool uniform=true, bool accumulate=false );
参数解释:
arrays: 指向输入图像数组的指针。这些数组通常是图像数据。
narrays: 输入数组的数量。
channels: 指定要处理的通道索引数组。对于每个输入数组,可以指定一个或多个通道。
表示要处理的图像通道数。例如,在 RGB 图像中,[0] 表示蓝色通道,[1] 表示绿色通道,[2] 表示红色通道。
mask: 可选的掩码,用于指定感兴趣的区域(ROI)。如果未提供掩码,则使用整个输入数组(整个图像)。
hist: 输出直方图。可以是一个密集矩阵 (OutputArray) 或稀疏矩阵 (SparseMat)。
dims: 直方图的维度数量。对于单通道直方图,维度为 1;对于多通道直方图,维度等于通道数量。
histSize: 每个维度上的直方图区间数量(bins 数量)。
ranges: 每个维度上的直方图区间范围。通常是一个包含两个元素的数组,表示区间起始值和结束值。
uniform : 如果为 true,则 ranges 是均匀间隔的。默认为 true。
accumulate: 如果为 true,则将计算出的直方图累加到已有的 hist 上;如果为 false,则覆盖 hist。默认为 false。
说明
calcHist 函数用于计算一个或多个数组的直方图。它可以处理图像数据,并生成一个表示像素强度分布(对于灰度图像)或颜色分布(对于彩色图像)的直方图。
密集直方图 (OutputArray hist): 当输出为密集矩阵时,hist 将是一个包含直方图数据的一维或多维矩阵。
稀疏直方图 (SparseMat& hist): 当输出为稀疏矩阵时,hist 将是一个稀疏矩阵,适用于数据稀疏的情况。
你可以根据需要选择密集矩阵或稀疏矩阵作为输出,以便优化内存使用和处理速度。
实验代码
#include "pch.h"
#include <iostream>
#include<opencv2/opencv.hpp>
#include <opencv2\imgproc\types_c.h> //for CV_RGB2GRAY
using namespace cv; //所有opencv类都在命名空间cv下
using namespace std;
//#pragma comment(lib, "opencv_world450d.lib") //引用引入库
//绘制灰度直方图
int main()
{
Mat src, gray;
src = imread("027.jpeg"); //读取工程目录下的图片
if (src.empty()) //判断原图是否加载成功
{
cout << "图像加载失败" << endl;
return -1;
}
cvtColor(src, gray, CV_RGB2GRAY); //转换为灰度图
int bins = 256; //定义直方图的参数,包括 bin 数量(这里是256),范围是从0到256,表示灰度级的范围。 定义直方图的 bins 数量 bins 变量定义了直方图的 bins(区间)数量。在这里,我们设置为 256,意味着我们将灰度值区间 [0, 255] 分成 256 个等宽的小区间。
int hist_size[] = { bins };//定义直方图尺寸 hist_size 是一个整数数组,用于指定直方图的尺寸。在这里,只有一个维度(因为我们计算的是单通道直方图),尺寸为 bins。
float range[] = { 0, 256 };//定义直方图范围 range 是一个浮点数数组,用于指定直方图的范围。在这里,我们设置了从 0 到 256 的范围,这是因为我们的灰度值是从 0 到 255。
const float* ranges[] = { range }; //定义直方图的范围指针数组 ranges 是一个指针数组,其中包含了指向 range 的指针。这是因为 calcHist 函数需要一个指针数组来接收每个维度的范围。在这种情况下,我们只有一个维度,所以只需要一个指针。
MatND hist;//定义输出直方图矩阵,hist 是一个 MatND 类型的变量,用于存储计算得到的直方图数据。MatND 是一个多维矩阵类型,可以存储任意维度的数据。在这里,它是一个一维的直方图数据。
int channels[] = { 0 }; //定义通道索引数组 channels 是一个整数数组,用于指定要处理的图像通道。在这里,我们只处理第一个通道(即灰度图像的唯一通道),索引为 0。
//计算出灰度直方图
calcHist(&gray, 1, channels, Mat(), // do not use mask
hist, 1, hist_size, ranges,
true, // the histogram is uniform
false);
//画出直方图
double max_val;
minMaxLoc(hist, 0, &max_val, 0, 0); //定位矩阵中最小值、最大值的位置
int scale = 2;//scale 是一个缩放因子,用于调整直方图图像的宽度。
int hist_height = 256;//hist_height 是直方图图像的高度。在这个例子中,hist_height 被设定为 256。
Mat hist_img = Mat::zeros(hist_height, bins*scale, CV_8UC3); //创建一个全0的特殊矩阵
//bins * scale 计算了直方图图像的宽度,即 256 * 2 = 512。
//这行代码创建了一个高度为 hist_height(256)、宽度为 bins * scale(512)的三通道 RGB 图像。所有的像素都被初始化为黑色(因为所有通道的值都是 0)。
for (int i = 0; i < bins; i++)
{
float bin_val = hist.at<float>(i); //获取当前 bin (i) 的值。
int intensity = cvRound(bin_val*hist_height / max_val); //要绘制的高度 计算当前 bin 在图像上应绘制的高度。
rectangle(hist_img, Point(i*scale, hist_height - 1), //画矩形
Point((i + 1)*scale - 1, hist_height - intensity),
CV_RGB(255, 255, 255));
//使用 rectangle 函数在 hist_img 上绘制一个矩形,表示当前 bin 的直方图柱状图。矩形的位置和高度决定了直方图的形状:
//注意此处的原点坐标 位于左上角
//左下角位于 (i*scale, hist_height - 1)。
//右上角位于 ((i + 1)*scale - 1, hist_height - intensity)。
//每个 bin 的宽度为 scale 个像素,高度为 intensity 像素,颜色为白色。
}
//显示原图和直方图
namedWindow("原图片", WINDOW_NORMAL);
imshow("原图片", src);
namedWindow("灰度图片", WINDOW_NORMAL);
imshow("灰度图片", gray);
namedWindow("灰度直方图", WINDOW_NORMAL);
imshow("灰度直方图", hist_img);
waitKey(0);
return 0;
}
运行结果
示例扩展
尚需后续调整完善
//#include <cv.h>
//#include <highgui.h>
#include "pch.h"
#include <iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat src, hsv;
src = imread("A.jpg");
if (src.empty()) //判断原图是否加载成功
{
cout << "图像加载失败" << endl;
return -1;
}
cvtColor(src, hsv, CV_BGR2HSV);
// Quantize the hue to 30 levels
// and the saturation to 32 levels
int hbins = 30, sbins = 32;
int histSize[] = { hbins, sbins };
// hue varies from 0 to 179, see cvtColor
float hranges[] = { 0, 180 };
// saturation varies from 0 (black-gray-white) to
// 255 (pure spectrum color)
float sranges[] = { 0, 256 };
const float* ranges[] = { hranges, sranges };
MatND hist;
// we compute the histogram from the 0-th and 1-st channels
int channels[] = { 0, 1 };
calcHist(&hsv, 1, channels, Mat(), // do not use mask
hist, 2, histSize, ranges,
true, // the histogram is uniform
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),
CV_FILLED);
}
namedWindow("Source", 1);
imshow("Source", src);
namedWindow("H-S Histogram", 1);
imshow("H-S Histogram", histImg);
waitKey();
}