calcHist函数在Opencv中是极难理解的一个函数,一方面是参数说明晦涩难懂,另一方面,说明书给出的实例也不足以令人完全搞清楚该函数的使用方式。最难理解的是第6,7,8个参数dims、histSize和ranges。以前一直都是想当然认为,该函数可以一次统计多张图片每个通道的灰度值数据,实际上calcHist函数一次只能统计一个通道上的直方图。我估计许多同学都犯过和我类似的错误,认为第5个参数hist,可以根据dims设定维度,比如dims=3,则输出的hist的维度就是3,并且会想当然的认为这个三维矩阵会保存三个通道上的直方图统计,悲哀的是,错了。它实际上是在三维坐标上统计的直方图,比如以第0个通道的灰度值有效统计范围(比如0~255)作为纵坐标,类似于笛卡尔坐标的y轴;以第1个通道灰度值统计有效范围作为横坐标,类似于笛卡尔坐标的x轴;以第2个通道的灰度值有效统计范围作为z轴。这三个轴坐标作为统计的依据。比如坐标(6,7,8),表示统计满足“0通道上灰度值为1;1通道上灰度为7;2通道上灰度为8的像素”,在整个图像上的像素个数。

当然,当dims=1时,就好理解了,就是对某一个单一通道上的灰度值直方图统计。

还有很重要一点,那就是,calcHist函数有bug。当图像尺度小于9*12,直方图均匀分布,并且直方条个数histSize为4时,会有统计错误,在后面的实例中我们会看到。

calcHist函数的声明如下:

OpenCV提供了两个重载的calcHist函数,它可以计算一系列阵列的直方图,这些系列通常是图像或像平面。它最多可以同时处理32个图像。

C++: 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 )

C++: void calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, SparseMat& hist, int dims, const int* histSize, const float** ranges, bool uniform = true, bool accumulate= false )

参数说明:

images –  源图像数组,它们有同样的位深CV_8U或 CV_32F ,同样的尺寸;图像阵列中的每一个图像都可以有任意多个通道

nimages –  源图像的数目。

channels – 维度通道序列,第一幅图像的通道标号从0~image[0].channels( )-1。Image[0]表示图像数组中的第一幅图像,channels()表示该图像的通道数量。同理,图像阵列中的第二幅图像,通道标号从image[0].channerls( )开始,到image[1].channels( )-1为止;第三、四幅图像的通道标号顺序依此类推;也就是说图像阵列中的所有图像的通道根据图像排列顺序,排成一个通道队列。

mask –    可选择的mask。如果该矩阵不空的话,它必须是一个8-bit的矩阵,与images[i]同尺寸。在图像中,只有被mask覆盖的区域的像素才参与直方图统计。如果这个参数想用默认值,输入Mat()就可以了。

hist –      输出直方图, 它是一个稠密或稀疏矩阵,具有dims个维度;

dims –     直方图的维度,一定是正值, CV_MAX_DIMS(当前OpenCV版本是32个);

histSize –   数组,即histSize[i]表示第i个维度上bin的个数;这里的维度可以理解为通道。

ranges –   当uniform=true时,ranges是多个二元数组组成的数组;当uniform=false时,ranges是多元数组组成的数组。当在每个维度(或通道)上每个直方条等宽时,即uniform=true时,灰度值的有效统计范围的下界用L0表示,上界用UhistSize[i]-1表示,角标中的i表示第i个维度(或通道),上下界值可以表示为hrange[i]={ L0, UhistSize[i]-1}, 在统计时, L0和UhistSize[i]-1不在统计范围内。而ranges={ hrange[0], hrange[1], …… , hrange[dims]}。ranges的元素个数由参数dims决定。
其中,L0表示在该通道上第0个直方条(bin)的下边界,UhistSize[i]-1表示最后一个直方条histSize[i]-1的上边界。在该维度上直方条的个数为histSize[i],如hrange[0]={ L0,
UhistSize[0]},hrange[1]={ L1, UhistSize[1]}, hrange[2]={
L2, UhistSize[2]}, …… , hrange[dims]={ L0, UhistSize[0]}。
当uniform=false时,ranges中的每个元素ranges[i]都是一个多元数组,元素个数为histSize[i]+1,它们分别是:L0 , U0=L1, U1= L2,
…… ,UhistSize[i]-2 , LhistSize[i]-1 , UhistSize[i]-1
。所以,ranges[i]={ L0 , L1, L2, …… , LhistSize[i]-1 ,UhistSize[i]-1}

uniform –  标识,用于说明直方条bin是否是均匀等宽的。

accumulate – 累积标识。如果该项设置,当直方图重新分配时,直方图在开始清零。这个特征可以使你通过几幅图像,累积计算一个简单的直方图,或者及时更新直方图。

函数calcHist可以计算一幅或多幅图像的直方图。在元组中增量一个直方图的时候,就是从输入图像组中的原位置提取一幅图像,并计算出它的直方图,并添加到元组中。

当参数dims>1时,输出矩阵Hist是二维矩阵。

calcHist示例:单通道灰度图像

int main()
{
Mat hist;
//这是一个9行12列的单通道图像
Mat img=(Mat_<uchar>(,)
<<,,,,,,,,,,,,
,,,,,,,,,,,,
,,,,,,,,,,,,
,,,,,,,,,,,,
,,,,,,,,,,,,
,,,,,,,,,,,,
,,,,,,,,,,,,
,,,,,,,,,,,,
,,,,,,,,,,,);

//灰度值有效范围是1~12,所以设定为hr1[]={1,13};将灰度范围均分为3部分,三个直方条取值范围分别为:第1部分1~4,第2部分5~8,第3部分9~12。
    //因此令histSize[1]={3},这里的3意味着整个图像灰度范围1~12被均分为3部分,分别统计像素个数。
    int histSize[]={};
int channels[]={};
float hr1[]={,};//矩阵b的灰度值有效范围是1<=V<13
const float* ranges[]={hr1}; calcHist(&img,,channels,Mat(),hist,,histSize,ranges,true);
cout<<"img="<<endl<<img<<endl;
cout<<"hist="<<endl<< hist<<endl;
return ;
}

输出结果如下:

本来一切都很完美,不过可惜,该函数有bug。

calcHist函数的bug

依然以上面的示例为例,当histSize[1]={3};或{6};或{12}都不会有问题。可是当histSize[1]={2};或{4}时,虽然uniform=true,但是在整个图像上灰度范围上,并没有被平均分割为2个或4个灰度直方条进行像素统计。输出结果如下所示:

 

经过测试,猜测,大概直方条的宽度含有3的整数倍时,均匀直方统计就会失效。如将上例中的图像改成9*15,灰度取值范围1~15,直方条个数为5,即直方条的宽度为3,则该函数的均匀直方统计就会失效,如下左图。然而,当直方条宽度为5时,则有正确输出结果,如下右图:

  

不过也有解决的办法,就是将灰度值统计范围的左值,也就是L0,减1,即L0=L0-1。还是以上面的例子为例,灰度值有效范围:1~15。令bin=3,但是hr1={0,16},经验证可以得到正确的统计结果,如下图所示:

其他数据大家可以自行验证,都是正确的。

Opencv中直方图函数calcHist的更多相关文章

  1. 【Opencv】直方图函数 calchist()

    calchist函数需要包含头文件 #include <opencv2/imgproc/imgproc.hpp> 函数声明(三个重载 calchist函数): //! computes t ...

  2. 【计算机视觉】OpenCV中直方图处理函数简述

    计算直方图calcHist 直方图是对数据集合的统计 ,并将统计结果分布于一系列提前定义的bins中.这里的数据不只指的是灰度值 ,统计数据可能是不论什么能有效描写叙述图像的特征. 如果有一个矩阵包括 ...

  3. OpenCV中phase函数计算方向场

    一.函数原型 ​该函数参数angleInDegrees默认为false,即弧度,当置为true时,则输出为角度. phase函数根据函数来计算角度,计算精度大约为0.3弧度,当x,y相等时,angle ...

  4. OpenCV中threshold函数的使用

    转自:https://blog.csdn.net/u012566751/article/details/77046445 一篇很好的介绍threshold文章: 图像的二值化就是将图像上的像素点的灰度 ...

  5. 5. openCV中常用函数学习

    一.前言 经过两个星期的努力,一边学习,一边写代码,初步完成了毕业论文系统的界面和一些基本功能,主要包括:1 数据的读写和显示,及相关的基本操作(放大.缩小和移动):2 样本数据的选择:3 数据归一化 ...

  6. openCV中直方图均衡化算法的理解

    直方图均衡化就是调整灰度直方图的分布,即将原图中的灰度值映射为一个新的值.映射的结果直观表现是灰度图的分布变得均匀,从0到255都有分布,不像原图那样集中.图像上的表现就是对比度变大,亮的更亮,暗的更 ...

  7. 【短道速滑一】OpenCV中cvResize函数使用双线性插值缩小图像到长宽大小一半时速度飞快(比最近邻还快)之异象解析和自我实现。

    今天,一个朋友想使用我的SSE优化Demo里的双线性插值算法,他已经在项目里使用了OpenCV,因此,我就建议他直接使用OpenCV,朋友的程序非常注意效率和实时性(因为是处理视频),因此希望我能测试 ...

  8. OpenCV中cvWaitKey()函数注意事项

    注意:这个函数是HighGUI中唯一能够获取和操作事件的函数,所以在一般的事件处理中,它需要周期地被调用,除非HighGUI被用在某些能够处理事件的环境中.比如在MFC环境下,这个函数不起作用.

  9. OpenCV中 常用 函数 的作用

    1.CV_Assert函数作用: CV_Assert()若括号中的表达式值为false,则返回一个错误信息.

随机推荐

  1. string::erase

    sequence (1) string& erase (size_t pos = 0, size_t len = npos);两个参数都有默认值,传递的唯一参数匹配第一个 character ...

  2. 第二章 Vue快速入门--20 品牌案例-完成品牌列表的添加功能+ 21 品牌案例-根据Id完成品牌的删除

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  3. C#中引用参数ref和输出参数out

    引用参数 用于按引用传递自变量. 为引用参数传递的自变量必须是具有明确值的变量,并且在方法执行期间,引用参数指明的存储位置与自变量相同. 引用参数使用 ref 修饰符进行声明. 输出参数 用于按引用传 ...

  4. 【JZOJ5428】【NOIP2017提高A组集训10.27】查询

    题目 给出一个长度为n的序列a[] 给出q组询问,每组询问形如\(<x,y>\),求a序列的所有区间中,数字x的出现次数与数字y的出现次数相同的区间有多少个. 分析 我们可以维护一个前缀和 ...

  5. [洛谷P4040] AHOI2014 宅男计划

    题目背景 自从迷上了拼图,JYY就变成了个彻底的宅男.为了解决温饱问题,JYY不得不依靠叫外卖来维持生计. 问题描述 外卖店一共有N种食物,分别有1到N编号.第i种食物有固定的价钱Pi和保质期Si.第 ...

  6. element-ui 弹出添加拖拽功能

    1.新建dialog.js文件2.在main.js 中引入dialog.js  import ‘./utils/dialog.js’3. 使用:<el-dialog v-dialogDrag&g ...

  7. CSS定位——文档流定位

    关于CSS的定位机制Ⅰ ㈠概念 对于盒子模型来说,也就是页面元素,这些盒子究竟在页面的什么位置,怎样排列它,那么找到它的位置,确定它的位置,这个就是定位机制所决定的. ㈡分类 文档流, 浮动定位,层定 ...

  8. 手动升级 Confluence 6 - 升级问题解决

    升级失败了? 如果你需要对你的升级进行回退,你必须首先恢复你老的 Confluence 备份.不要尝试再次进行升级,也不要尝试再次对升级失败的 Confluence 进行再次启动.  在升级过程中遇到 ...

  9. mysql内存分配问题

    云数据库 MySQL 的内存是重要的性能参数,常出现由异常 SQL 请求以及待优化的数据库导致的内存利用率升高的情况,严重时还会出现由于 OOM 导致实例发生 HA 切换,影响业务的稳定及可用性. M ...

  10. HDU 3669 [Cross the Wall] DP斜率优化

    问题分析 首先,如果一个人的\(w\)和\(h\)均小于另一个人,那么这个人显然可以被省略.如果我们将剩下的人按\(w[i]\)递增排序,那么\(h[i]\)就是递减. 之后我们考虑DP. 我们设\( ...