一、图像直方图的概念

图像直方图是反映一个图像像素分布的统计表,其实横坐标代表了图像像素的种类,可以是灰度的,也可以是彩色的。纵坐标代表了每一种颜色值在图像中的像素总数或者占所有像素个数的百分比。

图像是由像素构成,因为反映像素分布的直方图往往可以作为图像一个很重要的特征。在实际工程中,图像直方图在特征提取、图像匹配等方面都有很好的应用。

二、利用OpenCV计算图像的直方图

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:要计算直方图的图像的个数。此函数可以为多图像求直方图,我们通常情况下都只作用于单一图像,所以通常nimages=1。

const int* channels:图像的通道,它是一个数组,如果是灰度图像则channels[1]={0};如果是彩色图像则channels[3]={0,1,2};如果是只是求彩色图像第2个通道的直方图,则channels[1]={1};

IuputArray mask:是一个遮罩图像用于确定哪些点参与计算,实际应用中是个很好的参数,默认情况我们都设置为一个空图像,即:Mat()。

OutArray hist:计算得到的直方图

int dims:得到的直方图的维数,灰度图像为1维,彩色图像为3维。

const int* histSize:直方图横坐标的区间数。如果是10,则它会横坐标分为10份,然后统计每个区间的像素点总和。

const float** ranges:这是一个二维数组,用来指出每个区间的范围。

后面两个参数都有默认值,uniform参数表明直方图是否等距,最后一个参数与多图像下直方图的显示与存储有关。

下面我们来计算一幅图像的灰度直方图,彩色直方图以及自定义的灰度分布图。

灰度直方图:

int main()
{
Mat Image=imread("../cat.png");
cvtColor(Image,Image,CV_BGR2GRAY); const int channels[]={};
const int histSize[]={};
float hranges[]={,};
const float* ranges[]={hranges};
MatND hist;
calcHist(&Image,,channels,Mat(),hist,,histSize,ranges); return ;
}

彩色直方图:

int main()
{
Mat Image=imread("../cat.png"); const int channels[]={,,};
const int histSize[]={,,};
float hranges[]={,};
const float* ranges[]={hranges,hranges,hranges};
MatND hist;
calcHist(&Image,,channels,Mat(),hist,,histSize,ranges); return ;
}

不均匀直方图,我们分别统计0-50,50-80,80-150,150-230,230-255区间的灰度分布:

int main()
{
Mat Image=imread("../cat.png");
cvtColor(Image,Image,CV_BGR2GRAY); const int channels[]={};
int histSize[]={};
float hranges[]={,,,,,};
const float* ranges[]={hranges}; MatND hist;
calcHist(&Image,,channels,Mat(),hist,,histSize,ranges,false); return ;
}

三、直方图的显示

从上面的例子中我们可以看出,直方图计算得到的实际上是一个多维数组,这并不够直观,我们希望能够像在Excel中把相关数据通过表的形式表示出来。

下面通过划线函数来把一个灰度直方图显示出来:

Mat getHistImg(const MatND& hist)
{
double maxVal=;
double minVal=; //找到直方图中的最大值和最小值
minMaxLoc(hist,&minVal,&maxVal,,);
int histSize=hist.rows;
Mat histImg(histSize,histSize,CV_8U,Scalar());
// 设置最大峰值为图像高度的90%
int hpt=static_cast<int>(0.9*histSize); for(int h=;h<histSize;h++)
{
float binVal=hist.at<float>(h);
int intensity=static_cast<int>(binVal*hpt/maxVal);
line(histImg,Point(h,histSize),Point(h,histSize-intensity),Scalar::all());
} return histImg;
}

四、直方图变换

直方图变换是图像处理中一个很重要的概念,图像直方图可以反映出图像对比度,明暗程度等特征,所以我们可以利用直方图的变换进行图像画面的调节。

直方图变换在实际工程中的应用很广,一些美化照片的软件很多工具都是在图像的直方图上作文章,如果有读者对这这方面感兴趣的推荐:http://www.cnblogs.com/Imageshop/

下面介绍两个简单的直方图变换函数:直方图拉伸与直方图均衡化。

如果图像的灰度在直方图上显示集中在某一个区间,则说明图像色彩单一,我们可以将其扩展到更宽的灰度范围内让图像更有层次感。

变换函数:将图像的一种灰度值经过变换得到另一个灰度。

直方图变换的核心就是变换函数,s=T(r),r是变换前的灰度值,s是变换后的灰度值,如要我们想将[a,b]区间的灰度变换到[0,255]范围内,则变换函数是:T(r)=255*(r-a)/(b-a)。

我们在OpenCV中创建这样一个变换函数:

// 创建一个1*256的矢量
Mat lut(,,CV_8U);
for(int i=;i<;i++)
{
if(lut.at<uchar>(i)<imin)
lut.at<uchar>(i)=;
else if(lut.at<uchar>(i)>imax)
lut.at<uchar>(i)=;
else
lut.at<uchar>(i)=static_cast<uchar>(
255.0*(i-imin)/(imax-imin)+0.5);
}

其中imax,imin是图像中的最小灰度与最大灰度。我们可以从直方图中求出:

int imax,imin;
for(imin=;imin<;imin++)
{
if(hist.at<uchar>(imin)>minValue)
break;
}
for(imax=;imax>-;imax--)
{
if(hist.at<uchar>(imax)>minValue)
break;
}

最后我们应用OpenCV中的LUT函数,把变换应用在直方图上即可。

LUT(image,lut,result);

第二个参数就像一个查找表一样,将原图像中的灰度按表查找,然后把灰度值替换为表中对应的值。

有了上面灰度拉伸的例子就不难理解图像的直方图均衡了,直方图均衡化可以让图像灰度分布更加均匀,让图像的对比度增强。

在OpenCV中直方图均衡不用像灰度拉伸那样先构造一个变换函数,它有直接对应的函数,当然你如果有兴趣也可以去尝试写一下变换函数均衡化的变换原理会稍复杂一些,在OpenCV这个系列里面,不会太多的介绍数字图像中的算法,以后有机会再专门来讨论。

int main()
{
Mat Image=imread("../cat.png");
cvtColor(Image,Image,CV_BGR2GRAY); Mat result;
equalizeHist(Image,result); return ;
}

OpenCV成长之路(4):图像直方图的更多相关文章

  1. OpenCV成长之路:图像直方图的应用

    OpenCV成长之路:图像直方图的应用 2014-04-11 13:57:03 标签:opencv 图像 直方图 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否 ...

  2. OpenCV成长之路:图像直方图

    http://ronny.blog.51cto.com/8801997/1394115 2014-04-11 13:47:27 标签:opencv 直方图 统计表 原创作品,允许转载,转载时请务必以超 ...

  3. OpenCV成长之路:图像滤波

    http://ronny.blog.51cto.com/8801997/1394138 OpenCV成长之路:图像滤波 2014-04-11 14:28:44 标签:opencv 边缘检测 sobel ...

  4. OpenCV成长之路:直线、轮廓的提取与描述

    http://ronny.blog.51cto.com/8801997/1394139 OpenCV成长之路:直线.轮廓的提取与描述 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 . ...

  5. OpenCV成长之路(5):图像直方图的应用

    正如第4篇文章所说的图像直方图在特征提取方面有着很重要的作用,本文将举两个实际工程中非常实用的例子来说明图像直方图的应用. 一.直方图的反向映射. 我们以人脸检测举例,在人脸检测中,我们第一步往往需要 ...

  6. Python+OpenCV图像处理(八)—— 图像直方图

    直方图简介:图像的直方图是用来表现图像中亮度分布的直方图,给出的是图像中某个亮度或者某个范围亮度下共有几个像素.还不明白?就是统计一幅图某个亮度像素数量.比如对于灰度值12,一幅图里面有2000 个像 ...

  7. Python 图像处理 OpenCV (16):图像直方图

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...

  8. OpenCV成长之路(2):图像的遍历

    我们在实际应用中对图像进行的操作,往往并不是将图像作为一个整体进行操作,而是对图像中的所有点或特殊点进行运算,所以遍历图像就显得很重要,如何高效的遍历图像是一个很值得探讨的问题. 一.遍历图像的4种方 ...

  9. OpenCV成长之路(7):图像滤波

    滤波实际上是信号处理里的一个概念,而图像本身也可以看成是一个二维的信号.其中像素点灰度值的高低代表信号的强弱. 高频:图像中灰度变化剧烈的点. 低频:图像中平坦的,灰度变化不大的点. 根据图像的高频与 ...

随机推荐

  1. Jquery 的事件方法

    1.$(selector).bind(event,data,function,map) //给元素添加一个事件 2.当元素失去焦点时发生 blur 事件,获得焦点时触发focus事件: $(" ...

  2. 20145212 实验五《Java网络编程》

    20145212 实验五<Java网络编程> 一.实验内容 1.运行下载的TCP代码,结对进行,一人服务器,一人客户端: 2.利用加解密代码包,编译运行代码,一人加密,一人解密: 3.集成 ...

  3. 枚举类型Enum

    包java.dataStructure中,文件名Enum_demo.java 在JDK5中引入了一个新的关键字——enum,可以直接定义枚举类型 在申明枚举类的时候,也可以申明属性.方法和构造函数,但 ...

  4. -[UIKeyboardLayoutStar release]: message sent to deallocated instance

    网上大家都说是因为替换了系统的objextAtIndex方法,但是为了减少应用崩溃的可能,是要进行Hook的,所以不想取消Hook. 解决办法,关掉键盘进入后台. - (void)applicatio ...

  5. IdentityDbContext

    Move the ApplicationUser definition to your DAL. Inherit your MyDbContext from IdentityDbContext< ...

  6. redis入侵小结

    redis安装: windows安装包:http://pan.baidu.com/s/1i3jLlC5 下载下来之后,开始安装: redis-server.exe redis.conf: 简单一步,安 ...

  7. Python开发【第十六篇】:AJAX全套

    概述 对于WEB应用程序:用户浏览器发送请求,服务器接收并处理请求,然后返回结果,往往返回就是字符串(HTML),浏览器将字符串(HTML)渲染并显示浏览器上. 1.传统的Web应用 一个简单操作需要 ...

  8. Linux命令笔记(一)

    vi 有三种模式,输入模式,编辑模式,“:”命令模式vi 进入以后默认是编辑模式vi 编辑模式默认的快捷键 上下左右分别是 J K H Lvi 在编辑模式使用 i 可以进入输入模式vi 输入模式只能输 ...

  9. Linux启动管理:grub

    1.grub中分区表示 Linux 中 /dev/sda1   在grub中为   hd0,0    代表第一个硬盘的第一个分区 Linux中 /dev/sdb3是扩展分区     在grub中为   ...

  10. Lnmp的安装、配置

    一.首先在本地安装好虚拟机,在虚拟机上安装centos6.5,由于习惯问题,不喜欢直接在虚拟机上操作linux系统,习惯了ssh过去,直接用xshell操作,这完全是个人习惯问题: 1.  用xshe ...