图像直方图是反映图像中像素分布特性的统计表,一般显示如下:

其中横坐标代表的是图像像素的种类,或者说是灰度级,纵坐标代表的是每一级灰度下像素数或者该灰度级下像素数在所有图像总像素数总所占的百分比。

直方图反映了图像像素的整体分布,是图像的一个很重要的特征,直方图处理也是很多空间域图像处理的基础,在特征提取,图像增强,图像匹配等方面都占有一席之地。

直观上看,若直方图的分量主要集中在左侧低灰度级的区域,说明该图像整体灰度偏低,欠曝或者环境昏暗就有可能造成灰度偏低;

若直方图的分量主要集中在右侧高灰度级的区域,说明图像整体灰度偏高,过曝或环境光过于明亮就有可能造成灰度偏高;

若直方图的分量在各个灰度级分布均匀,占据了整个灰度级,则说明该幅图像对比度明显,一般情况下,具有这种直方图分布的图像的灰度细节比较丰富,图像质量较好。

直方图并不包含位置信息,相同的图像一定对应同一个直方图,而相同的直方图有可能所对应的图像千差万别,一个明显的例子是一幅选择180°的图像跟原图像的直方图分布是一致的,但是图像在表现上已经把图像倒置了,是完全不同的两幅图像。

opencv中计算直方图使用的是calcHist()函数,函数原型:

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 );

第一个参数:const Mat类型的images指针,可以是单幅图像或数组;

第二个参数:int型的nimages,是number of images的缩写,表示 输入数组的个数,单通道值为1;

第三个参数:const int型的channesl,需要统计的通道 (dim)索引数,单通道灰度图像为0;

第四个参数:InputArray类型的Mat()掩码,传入Mat()表示未定义,不使用掩码;

第五个参数:OutputArray类型的r_hist,储存直方图的矩阵;

第六个参数:int型的dims,直方图维数;

第七个参数:const int型的histSize指针,表示直方图的bin数目,即灰度级;

第八个参数:const float型的histRange指针,表示每个维度的取值范围;

第九和第十个参数:uniform 和 accumulate,bin大小相同,清楚直方图痕迹,分别是指为true和false

直方图opencv calcHist函数实现:

#include "core/core.hpp"
#include "highgui/highgui.hpp"
#include "imgproc/imgproc.hpp" using namespace cv; int main(int argc,char *argv[])
{
Mat image,imageGray,imageHist,imageNormalize;
image=imread(argv[1]);
if(!image.data)
{
return -1;
}
// RGB三通道图像转化成单通道灰度图像
// 也可以直接在imread函数里第二个参数设为0获取灰度图像
cvtColor(image,imageGray,CV_RGB2GRAY);
const int histSize=255; //定义灰度级数量
float histR[]={0,255}; //定义每个灰度级下取值范围
const float *histRange=histR; //计算直方图
calcHist(&imageGray,1,0,Mat(),imageHist,1,&histSize,&histRange,true,false); //直方图归一化到范围[0,histSize]
normalize(imageHist,imageNormalize,0,histSize,NORM_MINMAX,-1,Mat()); //创建直方图画布
Mat imageShowHist(histSize,histR[1],CV_8UC3,Scalar(0,0,0)); //分别画出每个灰度级下的直方图分布
for(int i=0;i<histSize;i++)
{
line(imageShowHist,Point(i,histR[1]),Point(i,histR[1]-cvRound(imageNormalize.at<float>(i))),Scalar(0,0,255),1,8,0);
}
imshow("Moon",image); imshow("MoonGray",imageGray);
imshow("Hist",imageShowHist);
waitKey();
return 0;
}

运行效果:
           

从直方图上特性上分析,灰度级基本上在每个数量级上都有分布,对比度和细节较为明显,但图像整体稍微偏暗,对比灰度图像,可以印证这些特性。

值得探讨的是我觉得在opencv文档里的教程中对直方图的计算应该有误,原文链接:

Opencv文档教程之直方图计算

例程代码照抄如下:

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h> using namespace std;
using namespace cv; /** @函数 main */
int main( int argc, char** argv )
{
Mat src, dst; /// 装载图像
src = imread( argv[1], 1 ); if( !src.data )
{ return -1; } /// 分割成3个单通道图像 ( R, G 和 B )
vector<Mat> rgb_planes;
split( src, 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;
<span style="color:#ff0000;">int bin_w = cvRound( (double) hist_w/histSize );</span> 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++ )
{
// 加入了三个if语句,为了比对直方图,不是例程程序所有
if(i==180)
{
imshow("180",histImage);
}
if(i==200)
{
imshow("199",histImage);
}
if(i==210)
{
imshow("210",histImage);
} line( histImage, <span style="color:#ff0000;">Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) )</span> ,
Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
Scalar( 0, 0, 255), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
Scalar( 0, 255, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
Scalar( 255, 0, 0), 2, 8, 0 );
} /// 显示直方图
namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE );
imshow("calcHist Demo", histImage ); waitKey(0); return 0; }

例程中所设直方图灰度级为255,直方图画布cols为400, int bin_w = cvRound( (double) hist_w/histSize )计算出来值为2;

这里会有问题:当计算200灰度级下的直方图时,Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)))所在的点已经超出了直方图画布的宽度400,意味着200~255灰度级的直方图被截取舍弃了,直方图并不完整。

以下是180,199和210灰度下直方图对比:

   

   

可以看到,199灰阶下已经绘制到了画布的边缘,其后的200~255灰阶超出了画布范围,没有再绘制出来,直方图也不再有变化;

把200~255灰阶补充完整的直方图如下:

可以明显看到绿色线代表的直方图分布,在200~255灰阶下有一个下降的过程曲线,做了补充绘制。

opencv直方图该怎么画的更多相关文章

  1. OpenCV直方图(直方图、直方图均衡,直方图匹配,原理、实现)

    1 直方图 灰度级范围为 \([0,L-1]\) 的数字图像的直方图是离散函数 \(h(r_k) = n_k\) , 其中 \(r_k\) 是第\(k\)级灰度值,\(n_k\) 是图像中灰度为 \( ...

  2. openCV 直方图统计

    直方图显示 #include <opencv2/opencv.hpp> using namespace std; using namespace cv; int main(int argc ...

  3. OPENCV直方图与匹配

    直方图可以用来描述不同的参数和事物,如物体的色彩分布,物体的边缘梯度模版以及目标位置的当前假设的概率分布. 直方图就是对数据进行统计的一种方法,并且将统计值定义到一系列定义好的bin(组距)中,获得一 ...

  4. OpenCV——直方图均衡化(用于图像增强)

    #include <opencv2/opencv.hpp> #include <iostream> #include <math.h> using namespac ...

  5. opencv:直方图操作

    示例程序: #include <opencv.hpp> using namespace cv; using namespace std; int main() { Mat src, dst ...

  6. opencv 直方图

    1.简介 对输入图像进行直方图均衡化处理,提升后续对象检测的准确率在OpenCV人脸检测的代码演示中已经很常见.此外对医学影像图像与卫星遥感图像也经常通过直方图均衡化来提升图像质量. 图像直方图均衡化 ...

  7. opencv直方图均衡化

    #include <iostream> #include "highgui.h" #include "cv.h" #include "cx ...

  8. opencv直方图拉伸

    1.首先计算出一幅图像的直方图 //计算直方图 cv::MatND ImageHist::getHist(const cv::Mat &image){ cv::Mat im; if(image ...

  9. Opencv 直方图比较

    #include <iostream>#include <opencv2/opencv.hpp> using namespace std;using namespace cv; ...

随机推荐

  1. 利用jquery实现向左滚动效果及offset的使用

    昨天和今天做了一个轮播图,它的tab标签不是1,2,3这样的数据表示,而是使用圆圈表示,效果如下:

  2. 【Java TCP/IP Socket】基于NIO的TCP通信(含代码)

    NIO主要原理及使用 NIO采取通道(Channel)和缓冲区(Buffer)来传输和保存数据,它是非阻塞式的I/O,即在等待连接.读写数据(这些都是在一线程以客户端的程序中会阻塞线程的操作)的时候, ...

  3. Apache Beam 传 大数据杂谈

    1月10日,Apache软件基金会宣布,Apache Beam成功孵化,成为该基金会的一个新的顶级项目,基于Apache V2许可证开源. 2003年,谷歌发布了著名的大数据三篇论文,史称三驾马车:G ...

  4. MVC Html.AntiForgeryToken() 防止CSRF攻击 - CSDN博客

    原文:MVC Html.AntiForgeryToken() 防止CSRF攻击 - CSDN博客 (一)MVC Html.AntiForgeryToken() 防止CSRF攻击 MVC中的Html.A ...

  5. weex 项目开发(六)weexpack 项目 打包、签名、发布

    一. weexpack build android  和  weexpack run android 的 区别. (1)单纯打包 weexpack build android (2)打包并运行 wee ...

  6. 一篇很好的讲解SIFT算法的文章

    http://blog.csdn.net/zddblog/article/details/7521424

  7. String、StringBilder和StringBuffer之间的区别

    1.三者在执行速度方面的比较:StringBuilder >  StringBuffer  >  String 2.String <(StringBuffer,StringBuild ...

  8. Pycharm下运行程序查看每个变量的值的方法(类似于Spyder和MATLAB)

    昨天,用了大量篇幅讲了Spyder的各种问题,之所以要用Spyder,最重要的一个原因就是能够非常方便的查看中间变量的值.类似MATLAB的工作空间,非常方便.如下图所示: 但是Spyder的代码自动 ...

  9. wxpython中控件对键盘输入无响应的可能原因

    问题描述: 开发环境:Win7 32bit + Python2.7.6 + WxPython 3.0.1-b20140707 开发某初级CAD软件中,需要实现点击TreeCtrl控件的相应选择,实现G ...

  10. Highmaps的天津地图数据JSON格式

    Highmaps的天津地图数据JSON格式 Highmaps的天津地图数据JSON格式 下载链接: http://pan.baidu.com/s/1eQgxECU password: tjmj 天津地 ...