在图像分析、物体和信息识别过程中,我们常常想把严重看到的物体用直方图(histogram)表示,直方图可以用来描述各种不同的事情,如物体的色彩分布、物体边缘梯度模板,以及表示目标位置的当前假设。例如,我们可以从输入视频中检测到感兴趣区域,然后计算这些感兴趣区域周围的边缘梯度方向,将得到的边缘地图方向放到一个方向直方图相应的bin中,然后将直方图与手势模板进行匹配,从而识别出手势。直方图广泛应用于很多计算机视觉应用中,通过标记帧与帧之间显著的边缘和颜色的统计变化,直方图被用来检测时品种场景的变换。通过为每个兴趣点设置一个有相近特征的直方图构成的标签,用以确定图像中的兴趣点。边缘、色彩、角等直方图构成了可以被传递个目标识别分类器的一个通用特征。色彩和边缘的直方图序列还可以用来识别网络视频是否被复制。直方图是计算计算机视觉中最经典的工具之一。
简单地说,直方图就是对数据进行统计,将统计知足知道一系列实现定义好的bin中。bin中的数值是从数据中计算车的特征的统计量,这些数据可以是梯度、方向、色彩或任何其他特征。直方图就是数据分布的统计图。
换句话说,直方图是一个简单地表,他给出了一幅图像或一组图像中拥有给定数值的像素数量。因此,灰度图像的直方图有256个条目(或称容器)。0号容器给出值为0的像素个数,1号容器给出值为1的像素个数,等等。显然,对直方图的所有项求和,会得到像素的总数。直方图也可以被归一化,归一化后的所有项之和等于1.在这种情况下,每一项给出的都是拥有特定数值的像素在图像中占得比例。下面开始对直方图进行具体分析。
计算直方图函数:void 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)
参数详解: images : 输入图像,如果是多个图像时需要有相同的深度CV_8U或CV_32F,每个图像可以有任意的通道数
nimages : 输入图像的个数
channels : 用来计算直方图维数的通道列表,第一个输入数组通道被识别为0到images[0].channels()-1,第二个输入数组通道被识别为images[0].channels()到images[0].channels()+images[1].channels() -1.等等。
mask : 掩膜,可选,如果矩阵非空,则务必是一个与images[i]相同大小的8位数组,非0的mask元素标记到直方图中
hist : 输出直方图,是一个dense or sparse 维的数组
dims : 直方图维度,务必是大于0的,<CV_MAX_DIMS(32)
histSize : 每一维直方图大小的数组
ranges : Array of the dims arrays of the histogram bin boundaries in each dimension. When the histogram is uniform (uniform =true), then for each dimension i it is enough to specify the lower (inclusive) boundary
of the 0-th histogram bin and the upper (exclusive) boundary
for the last histogram bin histSize[i]-1 . That is, in case of a uniform histogram each of ranges[i] is an array of 2 elements.
When the histogram is not uniform ( uniform=false ), then each of ranges[i] containshistSize[i]+1 elements:
. The array elements,
that are not between
and
, are not counted in the histogram
uniform : 是否为均匀or非均匀直方图
accumulate: 积累标志,如果为真,直方图在开始阶段不清空,保持积累状态,这个作用就是使你能够计算几个图像的直方图
好了,用实例验证下吧。先开始一维直方图
histogram.h文件
#include<opencv2/opencv.hpp>
class Histogram1D
{
private:
int histSize[1];
float hranges[2];
const float * ranges[1];
int channels[1];
public:
Histogram1D();
cv::MatND getHistogram(const cv::Mat &image);
cv::Mat getHistogramImage(const cv::Mat &image);
};
histogram.cpp 文件
#include"histogram1D.h"
Histogram1D::Histogram1D()
{
histSize[0]=256;
hranges[0]=0.0;
hranges[1]=255.0;
ranges[0]=hranges;
channels[0]=0;
}
cv::MatND Histogram1D::getHistogram(const cv::Mat &image )
{
cv::MatND hist;
cv::calcHist(&image,1,channels,cv::Mat(),hist,1,histSize,ranges);
return hist;
}
cv::Mat Histogram1D::getHistogramImage(const cv::Mat &image)
{
cv::MatND hist = getHistogram(image);
double maxVal=0;
double minVal=0;
cv::minMaxLoc(hist,&minVal,&maxVal,0,0);
cv::Mat histImg(histSize[0],histSize[0],CV_8U,cv::Scalar(255));
int hpt=static_cast<int>(0.9*histSize[0]);
for(int h=0;h<histSize[0];h++)
{
float binVal = hist.at<float>(h);
int intensity = static_cast<int>(binVal*hpt/maxVal);
cv::line(histImg,cv::Point(h,histSize[0]),cv::Point(h,histSize[0]-intensity),cv::Scalar::all(0));
}
return histImg;
}
main()函数
#include"histogram1D.h"
#include<iostream>
int main()
{
cv::Mat image=cv::imread("g:\\carlicense\\1.jpg");
Histogram1D h;
cv::namedWindow("histogram");
cv::imshow("histogram",h.getHistogramImage(image));
cv::Mat threshold_img;
//cv::threshold(image,threshold_img,80,255,cv::THRESH_BINARY);
// cv::imshow("threshold",threshold_img);
cv::waitKey();
return 0;
}
运行结果:

好了,下面开始贴上多维直方图的代码。