一个图像有不同的像素值构成,像素值在图像中的分布情况是这幅图片的一重要特征。直方图可以描述图像内容、检测图像中的特定对象或纹理,你将学习如何计算直方图来修改图像外观。opencv提供了 cv::calcHist这个函数,可以计算任意类型的多通道图像。下面我们先定义一个类classHistogram1D,成员变量
private:
float m_hranges[2];//像素的最小及最大值 0.0 255.0
int m_histSize[1];//项的数目 256
const float*m_ranges[1];//像素的最大最小数组指针
int channels[1];//仅用到一个通道 通道0
然后在构造函数中初始化:
public:
Histogram1D()
{
//准备1D 直方图的参数
m_hranges[0] = 0.0;
m_hranges[1] = 255.0;
m_histSize[0] = 256;
m_ranges[0] = m_hranges;
channels[0] = 0;
};
然后计算直方图:
//计算1D直方图
cv::MatND getHistogram(const cv::Mat &image)
{
cv::MatND hist;
//计算直方图
cv::calcHist(&image, //图片
1, //计算单张图片的直方图
channels, //通道数量
cv::Mat(), //不使用图像作为掩码
hist, //返回的直方图
1, //这是1D的直方图
m_histSize, //项的数量
m_ranges //像素值的范围
);
return hist;
};
接着你可以遍历 hist 的256个条目,它是一个一维数组
for (int i = 0; i < 256; i++)
//遍历这256个值对应的像素点个数
cout << "value" << i << "=" << histo.at<float>(i) << endl;
为了更直观的把数值显示出来,更方便的方式是将直方图可视化,我们在类 classHistogram1D
添加 getHistogramImage() 方法,计算1D的直方图,并返回柱状图。
//计算1D直方图,并返回一张图像
cv::Mat 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(m_histSize[0], m_histSize[0], CV_8U, cv::Scalar(255));
int hpt = static_cast<int>(0.9*m_histSize[0]);
//每个条目都绘制一条垂直线
for (int h = 0; h < m_histSize[0]; h++)
{
float binVal = hist.at<float>(h);
int intensity = static_cast<int>(binVal*hpt / maxVal);
//两点之间绘制一条直线
cv::line(histImg, cv::Point(h, m_histSize[0]), //底部点
cv::Point(h, m_histSize[0] - intensity),//顶部点
cv::Scalar::all(0));//黑色
}
return histImg;
};
相似的,我们可以定义一个类来计算彩色的 BGR 图像的直方图:
classColorhistogram
{
private:
intm_histSize[3];//项的数目
floatm_hranges[2];//像素的最小及最大值
constfloat*m_ranges[3];
intm_channels[3];
public:
Colorhistogram()
{
m_histSize[0] = m_histSize[1] = m_histSize[2] = 256;
m_hranges[0] = 0.0;
m_hranges[1] = 255.0;
m_ranges[0] = m_hranges;
m_ranges[1] = m_hranges;
m_ranges[2] = m_hranges;
m_channels[0] = 0;
m_channels[1] = 0;
m_channels[2] = 0;
};
cv::MatNDgetHistogram(constcv::Mat&image)
{
cv::MatNDhist;
// BGR color histogram
m_hranges[0] = 0.0; //
BRG range
m_hranges[1] = 255.0;
m_channels[0] = 0; //
the three channels
m_channels[1] = 1;
m_channels[2] = 2;
// Compute histogram
cv::calcHist(&image,
1, //
histogram of 1 image only
m_channels, //
the channel used
cv::Mat(), //
no mask is used
hist, //
the resulting histogram
3, //
it is a 3D histogram
m_histSize, //
number of bins
m_ranges //
pixel value range
);
returnhist;
}
// Computes the histogram.
cv::SparseMatgetSparseHistogram(constcv::Mat&image)
{
cv::SparseMathist(3,
m_histSize,CV_32F);
// BGR color histogram
m_hranges[0] = 0.0; //
BRG range
m_hranges[1] = 255.0;
m_channels[0] = 0; //
the three channels
m_channels[1] = 1;
m_channels[2] = 2;
// Compute histogram
cv::calcHist(&image,
1, //
histogram of 1 image only
m_channels, //
the channel used
cv::Mat(), //
no mask is used
hist, //
the resulting histogram
3, //
it is a 3D histogram
m_histSize, //
number of bins
m_ranges //
pixel value range
);
returnhist;
}
// Computes the 2D ab histogram.
// BGR source image is
converted to Lab
cv::MatNDgetabHistogram(constcv::Mat&image)
{
cv::MatNDhist;
// Convert to Lab
color space
cv::Matlab;
cv::cvtColor(image,
lab,
CV_BGR2Lab);
// Prepare arguments
for a 2D color histogram
m_hranges[0] = -128.0;
m_hranges[1] = 127.0;
m_channels[0] = 1;//
the two channels used are ab
m_channels[1] = 2;
// Compute histogram
returnhist;
}
// Computes the 1D Hue
histogram with a mask.
// BGR source image is
converted to HSV
cv::MatNDgetHueHistogram(constcv::Mat&image)
{
cv::MatNDhist;
// Convert to Lab
color space
cv::Mathue;
cv::cvtColor(image,
hue,
CV_BGR2HSV);
// Prepare arguments
for a 1D hue histogram
m_hranges[0] = 0.0;
m_hranges[1] = 180.0;
m_channels[0] = 0;//
the hue channel
//
Compute histogram
cv::calcHist(&hue,
1, //
histogram of 1 image only
m_channels, //
the channel used
cv::Mat(), //
no mask is used
hist, //
the resulting histogram
1, //
it is a 1D histogram
m_histSize, //
number of bins
m_ranges //
pixel value range
);
returnhist;
}
cv::MatcolorReduce(constcv::Mat&image,intdiv=
64) {
intn
=static_cast<int>(log(static_cast<double>(div))
/ log(2.0));
// mask used to
round the pixel value
ucharmask
= 0xFF << n;// e.g. for div=16, mask= 0xF0
cv::Mat_<cv::Vec3b>::const_iteratorit
=image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::const_iteratoritend
=image.end<cv::Vec3b>();
// Set output image
(always 1-channel)
cv::Matresult(image.rows,image.cols,image.type());
cv::Mat_<cv::Vec3b>::iteratoritr
= result.begin<cv::Vec3b>();
for(;
it!=itend;++it,++itr)
{
(*itr)[0]=
((*it)[0]&
mask) +div/ 2;
(*itr)[1]=
((*it)[1]&
mask) +div/ 2;
(*itr)[2]=
((*it)[2]&
mask) +div/ 2;
}
returnresult;
}
};