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

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

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

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

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

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

直方图并不包含位置信息,相同的图像一定对应同一个直方图,而相同的直方图有可能所对应的图像千差万别,一个明显的例子是一幅选择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. CentOS 7.3 源码安装 OpenVAS 9

    https://my.oschina.net/u/2613235/blog/1583198

  2. webstorm(二):拼写warning

    逼死强迫症之对拼写进行检查,警告 typo:in word “msgfromfather”

  3. BZOJ——1611: [Usaco2008 Feb]Meteor Shower流星雨

    http://www.lydsy.com/JudgeOnline/problem.php?id=1611 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1 ...

  4. Spring 详解(一)------- AOP前序

    目录 1. AOP 简介 2. 示例需求 3. 解决方法一:使用静态代理 4. 解决方法二:使用动态代理 1. AOP 简介 ​ AOP(Aspect Oriented Programming),通常 ...

  5. Effective Java P2 Item1 Consider static factory methods instead of constructors

    获得一个类的实例的传统方法是公共的构造方法,还可以提供一个公共的静态工厂方法(一个返回值为该类实例的简单静态方法), 例如Boolean(boolean 的封装类) public static Boo ...

  6. How to fill the background with image in landscape in IOS? 如何使image水平铺满屏幕

    UIImageView *backgroundImage = [[UIImageView alloc] initWithFrame:self.view.frame];    [backgroundIm ...

  7. 【面试 JVM】【第六篇】JVM调优

    六部分内容: 一.内存模型 1.程序计数器,方法区,堆,栈,本地方法栈的作用,保存那些数据 可以画个大图出来,很清晰 jvm内存模型主要指运行时的数据区,包括5个部分. 栈也叫方法栈,是线程私有的,线 ...

  8. MySQL---笔记之视图的使用详解

    什么是视图  视图是从一个或多个表中导出来的表,是一种虚拟存在的表. 视图就像一个窗口,通过这个窗口可以看到系统专门提供的数据. 这样,用户可以不用看到整个数据库中的数据,而之关心对自己有用的数据. ...

  9. chromium爱好者不可错过的一个开源分支

    这次我要推荐下http://bloomberg.github.com/chromium.bb, 名字就叫chromium.bb,特点是专门的windows ports,关键是极大的简化了原版chrom ...

  10. 【转】Spring框架深入理解

    参考这篇文章: http://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/ Spring内部分为Beans, Context 和 ...