- 一般直方图概念是基于图像像素值,其实对图像梯度、每个像素的角度、等一切图像的属性值,我们都可以建立直方图。
这个才是直方图的概念真正意义,不过是基于图像像素灰度直方图是最常见的。 - 直方图最常见的几个属性:
dims 表示维度,对灰度图像来说只有一个通道值dims=1
bins 表示在维度中子区域大小划分,bins=256,划分为256个级别(0-255总共256个区域)
range 表示值得范围,灰度值范围为[0~255]之间
split// 把多通道图像分为多个单通道图像
(
const Mat &src, //输入图像
Mat* mvbegin)// 输出的通道图像数组
calcHist//从数据创建直方图
(
const Mat* images,//输入图像指针
int images,// images中包含的数组个数
const int* channels,//通道数
InputArray mask,// 输入mask,可选,不用
OutputArray hist,//输出的直方图数据
int dims,// 维数
const int* histsize,// 直方图级数,hist sizes in each dim
const float* ranges,// 值域范围,'dims' pairs set bin sizes
bool uniform,// true for uniform binning
bool accumulate//add to 'hist' else replace
)
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat src;
src = imread("../path.jpg");
if (src.empty())
{
cout << "could not load image..." << endl;
return -1;
}
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", src);
//多通道显示
vector<Mat> dst;//可以用稀疏矩阵SparseMat类型来表示直方图
//多通道矩阵→多个单通道矩阵
split(src, dst);
//namedWindow("dst", WINDOW_AUTOSIZE);
//imshow("dst", dst[0]);
//计算直方图
int histSize = 256;//每个维度中的区间的个数
float ranges[] = { 0 ,256 };//ranges范围,uniform为true,下界包含,上界不包含/uniform为false,下界包含,(上界-1)不包含
const float *histRanges = { ranges };//histSize每个区间对应的值由ranges来指定
Mat b_hist, g_hist, r_hist;
//从数据创建直方图,可以从一个或多个数组中创建直方图
calcHist(&dst[0], //Mat* images
1,//上个参数(images)中包含的数组个数
0,//在计算直方图时,使用输入数据中的哪些参数
Mat(),//掩膜,用来选择images中每个数组中哪些像素与直方图的计算
b_hist,//直方图计算的输出值
1,//输出直方图的维度
&histSize,//每个维度中的区间的个数 /const float** histSize//hist sizes in each dim
&histRanges,//histSize每个区间对应的值由ranges来指定//'dims' pairs set bin sizes
true,//uniform//ranges[i]表示第i维中区间的结构,如果uniform为true,那么第i维中所有的区间都等长,如果uniform为false,假如第i维中有n个bins,那么ranges[i]中必须有n个元素
false);//告诉opencv从images得到的数据被累加进入hist之前,不要将其中的元素删除,重新分配或是设置为0
calcHist(&dst[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRanges, true, false);
calcHist(&dst[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRanges, true, false);
// 归一化
int hist_h = 400;//直方图的高度,假设为400
int hist_w = 512; //直方图的宽度 256 *2
Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));//定义直方图矩阵
//把输出的直方图范围元素(主要是直方图高度) 映射到(0,hist_h)即(0,400)
normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX/*映射到区间[0, hist_h]*/, -1/*深度*/, Mat());
normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
//绘制直方图
int bin_w = hist_w / histSize;//维度中子区域大小划分 = 直方图的宽度 / 每个维度中的区间的个数
for (int i = 1; i < histSize; i++)
{
line(histImage,//绘制在Mat 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);
}
namedWindow("Histogram", WINDOW_AUTOSIZE);
imshow("Histogram", histImage);
waitKey(0);
return 0;
}
输出结果: