详解为什么OpenCV的直方图计算函数calcHist()计算出的灰度值为255的像素个数为0

Posted 昊虹算法

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解为什么OpenCV的直方图计算函数calcHist()计算出的灰度值为255的像素个数为0相关的知识,希望对你有一定的参考价值。

在使用OpenCV的直方图计算函数calcHist()时,发现灰度值为255的像素个数总是为0。
哪怕图像中灰度值为255的像素个数不为0,使用OpenCV的直方图计算函数calcHist()计算出的结果也为0。
一个例子如下:

//OpenCV版本3.0
//作者微信/QQ 2487872782
//有问题可以联系作者交流
//欢迎加入图像处理交流群,群号271891601

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <iostream>

int main( )

	// 读取源图像并转化为灰度图像
	cv::Mat srcImage = cv::imread("F:/material/images/P0027-coin-01.png");
	// 判断文件是否读入正确
	if( !srcImage.data ) 
		return 1;

	cv::Mat ImageGray;
	cv::cvtColor(srcImage,ImageGray,CV_BGR2GRAY);


	// 定义直方图参数
    const int channels[1]=0;
    const int histSize[1]=256;
    float pranges[2]=0,255;
    const float* ranges[1]=pranges;

	cv::MatND hist;

	cv::calcHist(&ImageGray,1,channels,cv::Mat(),hist,1,histSize,ranges);

	std::cout<<hist<<std::endl;

	// 找到图像像素的最大值
    double maxVal=0;
    cv::minMaxLoc(ImageGray, 0, &maxVal, 0, 0);
	std::cout<<"图像像素的最大值为:"<<maxVal<<std::endl;

	return 0;

程序中用到的图片“P0027-coin-01.png”下载链接:
链接:https://pan.baidu.com/s/1k13r2DdhEXuXWlxV-IbxNA 提取码:kwgo
程序运行结果如下图所示:

从上面的截图可以看出,函数calcHist()计算出的灰度值为255的像素个数为0,但是从“图像像素的最大值为:255”这句话可以看出,其个数肯定不为0,至少是大于等于1的。
怎么会出现这样的情况呢?查阅函数calcHist()的官方文档,原型如下:

void cv::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 
)		

注意到第8个参数“ranges”的说明:
“ranges Array of the dims arrays of the histogram bin boundaries in each dimension. When the histogram is uniform ( uniform =true), then for each dimension i it is enough to specify the lower (inclusive) boundary of the 0-th histogram bin and the upper (exclusive) boundary”
注意上面这段说明中我标注为红色的单词。从这段话可知,这个ranges确定的灰度统计范围区间是左闭右开区间。
为什么OpenCV的这个函数不将这个ranges确定的灰度统计范围区间设为左闭右闭区间呢?
这要从直方图的绘制说起。
我们从一个简单的灰度直方图说起。
设现在我们要统计绘制的灰度直方图参数如下:
统计区间个数:2,即上面代码中的 histSize[1]=2;
灰度值统计范围:0~4,即上面代码中的 pranges[2]=0,4;
在这样的参数情况下,我们的直方图把0~4的灰度范围分为两个统计区间,分别为0~2和2~4,如下图所示:

这里关键要明白两个统计区间具体统计的是哪些灰度值的个数。
在第①个区间内,统计的是灰度值为0和1的像素个数,请注意,不包括右边界2的像素个数
在第②个区间内,统计的是灰度值为2和3的像素个数,请注意,不包括右边界4的像素个数
明白了上面红色标注的内容后,大家应该就明白了,如果我的灰度值统计范围为0~4,那么我在绘制直方图时是不需要右边界4的像素个数的,所以我也就不需要统计其相应的像素个数了。
同理,如果我的我的灰度值统计范围为0~255,那么我在绘制直方图时是不需要右边界255的像素个数的,所以我也就不需要统计其相应的像素个数了。这就是为什么函数calcHist()计算统计出的255灰度值像素个数为0的原因。
有时候我们又需要知道灰度值为255的像素个数,那怎么办呢?
很简单,把灰度值范围写为0~266就行了,即上面代码中的

float pranges[2]=0,255;

写为

float pranges[2]=0,256;

我们将上面的代码改成如下的代码:

//OpenCV版本3.0
//作者微信/QQ 2487872782
//有问题可以联系作者交流
//图像处理开发资料、图像处理技术交流请加QQ群,群号 271891601

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <iostream>

int main( )

	// 读取源图像并转化为灰度图像
	cv::Mat srcImage = cv::imread("F:/material/images/P0027-coin-01.png");
	// 判断文件是否读入正确
	if( !srcImage.data ) 
		return 1;

	cv::Mat ImageGray;
	cv::cvtColor(srcImage,ImageGray,CV_BGR2GRAY);


	// 定义直方图参数
    const int channels[1]=0;
    const int histSize[1]=256;
    float pranges[2]=0,256;
    const float* ranges[1]=pranges;

	cv::MatND hist;

	cv::calcHist(&ImageGray,1,channels,cv::Mat(),hist,1,histSize,ranges);

	std::cout<<hist<<std::endl;

	// 找到图像像素的最大值
    double maxVal=0;
    cv::minMaxLoc(ImageGray, 0, &maxVal, 0, 0);
	std::cout<<"图像像素的最大值为:"<<maxVal<<std::endl;

	return 0;


讲到这里,相信大家也就明白了“为什么OpenCV的直方图计算函数calcHist()计算出的灰度值为255的像素个数为0”。如果还是不明白,可以添加博主的微信/QQ 2487872782 交流。

以上是关于详解为什么OpenCV的直方图计算函数calcHist()计算出的灰度值为255的像素个数为0的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV-Python图像直方图计算calcHist函数详解示例及图形呈现

直方图的反向投影的原理详解及OpenCV下的示例源码

详解什么叫二维直方图,并利用OpenCV的函数calcHist()绘制图像的H-S二维直方图

OpenCV实战——直方图详解

OpenCV实战——直方图详解

OpenCV实战(10)——积分图像详解