什么是直方图,以下摘自opencv国内论坛:
什么是直方图?
直方图是对数据的集合 统计 ,并将统计结果分布于一系列预定义的 bins 中。
这里的 数据 不仅仅指的是灰度值 (如上一篇您所看到的), 统计数据可能是任何能有效描述图像的特征。
先看一个例子吧。 假设有一个矩阵包含一张图像的信息 (灰度值 0-255):
如果我们按照某种方式去 统计 这些数字,会发生什么情况呢? 既然已知数字的 范围 包含 256 个值, 我们可以将这个范围分割成子区域(称作 bins), 如:
然后再统计掉入每一个 bin_{i} 的像素数目。采用这一方法来统计上面的数字矩阵,我们可以得到下图( x轴表示 bin, y轴表示各个bin中的像素个数)。
以上只是一个说明直方图如何工作以及它的用处的简单示例。直方图可以统计的不仅仅是颜色灰度, 它可以统计任何图像特征 (如 梯度, 方向等等)。
让我们再来搞清楚直方图的一些具体细节:
dims: 需要统计的特征的数目, 在上例中, dims = 1 因为我们仅仅统计了灰度值(灰度图像)。
bins: 每个特征空间 子区段 的数目,在上例中, bins = 16
range: 每个特征空间的取值范围,在上例中, range = [0,255]
怎样去统计两个特征呢? 在这种情况下, 直方图就是3维的了,x轴和y轴分别代表一个特征, z轴是掉入 (bin_{x}, bin_{y}) 组合中的样本数目。 同样的方法适用于更高维的情形 (当然会变得很复杂)。
不罗嗦了吧 下面直接上实验代码,还是之前的环境,在Qt mainwindow 程序里修改main函数,直方图函数应用,代码里有注解:
#include "mainwindow.h"
#include
#include
#include
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
Mat globalMat;//全局变量
void RGBHistogram(Mat intMat);//rgb的直方图统计
void GrayHistogram(Mat intMat);//显示灰度直方图
void GrayHistogram2(Mat intMat);//显示灰度直方图
void EqualizeHistogram(Mat intMat);//均值化图及灰度直方图
void EqualizeHistogram2(Mat intMat);//均值化图及灰度直方图
int main(int argc, char *argv[])
{
QApplication a(argc, argv);//QT mainwindow程序自带不用管
globalMat = imread("D:/source.png", 1 );//j加载图片,0为灰度,1为彩色
RGBHistogram(globalMat);//rgb 直方图
GrayHistogram(globalMat);//显示灰度直方图
GrayHistogram2(globalMat);//显示灰度直方图
EqualizeHistogram(globalMat);//均值化图及灰度直方图
EqualizeHistogram2(globalMat);//均值化图及灰度直方图
MainWindow w;//QT mainwindow程序自带不用管
w.show();//QT mainwindow程序自带不用管
return a.exec();//QT mainwindow程序自带不用管
}
//RGBHistogram黑底直方图
void RGBHistogram(Mat intMat)
{
/// 分割成3个单通道图像 ( R, G 和 B )
vector rgb_planes;
split(intMat, rgb_planes );
/// 设定bin数目
int histSize = 255;
/// 设定取值范围 ( R,G,B) )
float range[] = { 0, 255 } ;
const float* histRange = { range };
bool uniform = true;
bool accumulate = false;
Mat r_hist, g_hist, b_hist;
/// 计算直方图:
calcHist( &rgb_planes[0], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &rgb_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &rgb_planes[2], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
// 创建直方图画布
int hist_w = 400; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_w, hist_h, CV_8UC3, Scalar( 0,0,0) );
/// 将直方图归一化到范围 [ 0, histImage.rows ]
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
/// 在直方图画布上画出直方图
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(r_hist.at(i)) ),
Scalar( 0, 0, 255), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(g_hist.at(i)) ),
Scalar( 0, 255, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(b_hist.at(i)) ),
Scalar( 255, 0, 0), 2, 8, 0 );
}
/// 显示直方图
namedWindow("RGB Histogram", CV_WINDOW_AUTOSIZE );//创建窗口
imshow("RGB Histogram", histImage );//窗口中显示直方图
namedWindow("original image", CV_WINDOW_AUTOSIZE );//创建窗口
imshow("original image", globalMat );//窗口中显示原图
waitKey(0);
}
//黑底直方图
void GrayHistogram(Mat intMat)
{
#define cvQueryHistValue_1D( hist, idx0 )\
((float)cvGetReal1D( (hist)->bins, (idx0)))
// 宏 cvQueryHistValue_*D 返回 1D, 2D, 3D 或 N-D 直方图的指定直方块
// 的值。对稀疏直方图,如果方块在直方图中不存在,函数返回 0, 而且不创
// 建新的直方块。
IplImage *src= &IplImage(intMat);
IplImage* gray_plane= cvCreateImage(cvGetSize(src),8,1);//根据原图创建一个空白图
cvCvtColor(src,gray_plane,CV_RGB2GRAY);//转成灰度图
int hist_size = 256; //直方图尺寸
int hist_height = 256;//直方图高度
float range[] = {0,255}; //灰度级的范围
float* ranges[]={range};//创建一个数组
//创建一维直方图,统计图像在[0 255]像素的均匀分布
CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
// ************************cvCreateHist()函数解释 *******************************
// 函数 cvCreateHist 创建一个指定尺寸的直方图,并且返回创建的直方图的
// 指针。 如果数组的 ranges 是 0, 则直方块的范围必须由函数
// cvSetHistBinRanges 或者cvCalcHist 和 cvCalcBackProject稍后指定。
// 虽然 cvCalcHist 和 cvCalcBackProject可以处理 8-比特图像而无需设
// 置任何直方块的范围,但它们都被假设等分0..255 之间的空间。
///
// CvHistogram* cvCreateHist( int dims, // 直方图维数的数目
// int* sizes, //直方图维数尺寸的数组
// int type, // 直方图的表示格式
// float** ranges=NULL, //图中方块范围的数组
// int uniform=1 ); //归一化标识
// type
// 直方图的表示格式: CV_HIST_ARRAY 意味着直方图数据表示为多维密集数组 CvMatND;
// CV_HIST_TREE 意味着直方图数据表示为多维稀疏数组 CvSparseMat;
// ranges
// 图中方块范围的数组. 它的内容取决于参数 uniform 的值。这个范围的用处是确定何时计算直方
// 图或决定反向映射(backprojected ),每个方块对应于输入图像的哪个/哪组值。
// uniform
// 归一化标识。 如果不为 0,则ranges[i](0<=ibins, (idx0)))
IplImage *src= &IplImage(intMat);//加载图片转换成IplImage
IplImage* gray_plane = cvCreateImage(cvGetSize(src),8,1);
cvCvtColor(src,gray_plane,CV_RGB2GRAY);//彩色转灰度
int hist_size = 256; //直方图尺寸
int hist_height = 256; //直方图尺寸
float range[] = {0,255}; //灰度级的范围
float* ranges[]={range};//创建一个数组
//创建一维直方图,统计图像在[0 255]像素的均匀分布
CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
cvCalcHist(&gray_plane,gray_hist,0,0);//计算灰度图像的一维直方图
IplImage *pHistImage = cvCreateImage(cvSize(hist_size * 2, hist_height), IPL_DEPTH_8U, 1);
cvRectangle(pHistImage, cvPoint(0, 0), cvPoint(pHistImage->width, pHistImage->height), CV_RGB(255, 255, 255), CV_FILLED);
float fMaxHistValue = 0;//统计直方图中的最大直方块
cvGetMinMaxHistValue(gray_hist, NULL, &fMaxHistValue, NULL, NULL);//统计直方图中的最大直方块
//分别将每个直方块的值绘制到图中
for( int i = 0; i < 256; i++)
{
float fHistValue = cvQueryHistValue_1D(gray_hist, i); //像素为i的直方块大小
int nRealHeight = cvRound((fHistValue / fMaxHistValue) *256); //要绘制的高度
cvRectangle(pHistImage,
cvPoint(i * 2, 256 - 1),
cvPoint((i + 1) * 2 - 1, 256 - nRealHeight),
cvScalar(i, 0, 0, 0),
CV_FILLED);
}
Mat outMat=cvarrToMat(pHistImage);//IplImage转Mat
// 显示直方图
namedWindow("Gray Histogram2", CV_WINDOW_AUTOSIZE );//创建窗口
imshow("Gray Histogram2", outMat);//窗口中显示直方图
namedWindow("original image", CV_WINDOW_AUTOSIZE );//创建窗口
imshow("original image", globalMat );//窗口中显示原图
waitKey(0);
}
//黑底直方图
void EqualizeHistogram(Mat intMat)
{
#define cvQueryHistValue_1D( hist, idx0 )\
((float)cvGetReal1D( (hist)->bins, (idx0)))
IplImage *src= &IplImage(intMat);
IplImage* gray_plane = cvCreateImage(cvGetSize(src),8,1);
IplImage* EqualizeImg = cvCreateImage(cvGetSize(src),8,1);
cvCvtColor(src,gray_plane,CV_RGB2GRAY);
cvEqualizeHist(gray_plane, EqualizeImg); // 均衡化
int hist_size = 256; //直方图尺寸
int hist_height = 256;
float range[] = {0,255}; //灰度级的范围
float* ranges[]={range};
//创建一维直方图,统计图像在[0 255]像素的均匀分布
CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
cvCalcHist(&EqualizeImg,gray_hist,0,0);//计算灰度图像的一维直方图
cvNormalizeHist(gray_hist,1.0);//归一化直方图
int scale = 2;
//创建一张一维直方图的“图,横坐标为灰度级,纵坐标为像素个数(*scale)
IplImage* hist_image = cvCreateImage(cvSize(hist_size*scale,hist_height),8,3);
cvZero(hist_image);
//统计直方图中的最大直方块
float max_value = 0;
cvGetMinMaxHistValue(gray_hist, 0,&max_value,0,0);
//分别将每个直方块的值绘制到图中
for(int i=0;ibins, (idx0)))
IplImage *src= &IplImage(intMat);
IplImage* gray_plane = cvCreateImage(cvGetSize(src),8,1);
IplImage* EqualizeImg = cvCreateImage(cvGetSize(src),8,1);
cvCvtColor(src,gray_plane,CV_RGB2GRAY);//彩色转灰度
cvEqualizeHist(gray_plane, EqualizeImg); // 均衡化
int hist_size = 256; //直方图尺寸
int hist_height = 256; //直方图尺寸
float range[] = {0,255}; //灰度级的范围
float* ranges[]={range};
CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);//创建一维直方图,统计图像在[0 255]像素的均匀分布
cvCalcHist(&EqualizeImg,gray_hist,0,0);//计算灰度图像的一维直方图
cvNormalizeHist(gray_hist,1.0);//归一化直方图
IplImage *pHistImage = cvCreateImage(cvSize(hist_size * 2, hist_height), IPL_DEPTH_8U, 1);
cvRectangle(pHistImage, cvPoint(0, 0), cvPoint(pHistImage->width, pHistImage->height), CV_RGB(255, 255, 255), CV_FILLED);
float fMaxHistValue = 0;//统计直方图中的最大直方块
cvGetMinMaxHistValue(gray_hist, NULL, &fMaxHistValue, NULL, NULL);//统计直方图中的最大直方块
//分别将每个直方块的值绘制到图中
for(int i = 0; i < 256; i++)
{
float fHistValue = cvQueryHistValue_1D(gray_hist, i); //像素为i的直方块大小
int nRealHeight = cvRound((fHistValue / fMaxHistValue) *256); //要绘制的高度
cvRectangle(pHistImage,
cvPoint(i * 2, 256 - 1),
cvPoint((i + 1) * 2 - 1, 256 - nRealHeight),
cvScalar(i, 0, 0, 0),
CV_FILLED);
}
Mat outMat=cvarrToMat(pHistImage);//IplImage转Mat
Mat outMat2=cvarrToMat(EqualizeImg);//IplImage转Mat
// 显示直方图
namedWindow("Equalize Histogram", CV_WINDOW_AUTOSIZE );//创建窗口
imshow("Equalize Histogram", outMat);//窗口中显示直方图
namedWindow("Equalize", CV_WINDOW_AUTOSIZE );//创建窗口
imshow("Equalize",outMat2);//窗口中显示直方图
namedWindow("original image", CV_WINDOW_AUTOSIZE );//创建窗口
imshow("original image", globalMat );//窗口中显示原图
waitKey(0);
}
RGB直方图:
灰度直方图白底:
灰度直方图黑底:
均值化直方图白底:
均值化直方图黑底:
均值化图和原图: