【拜小白opencv】44-灰度直方图(一维直方图)calcHist()函数、minMaxLoc()函数、normalize()函数
来源:互联网 发布:手机mysql服务器 编辑:程序博客网 时间:2024/05/16 05:29
常言道“温故而知新”,写此文章就是对自己目前学习内容的小小的总结与记录。
本文力求用最简洁的语言,详细的代码将此部分内容讲解清楚,但由于博主同样是刚刚接触OpenCV,或许表达上有些瑕疵,还望读者能够指教探讨,大家共同进步。
博主机器配置为:VS2013+opencv2.4.13+Win-64bit。
若本文能给读者带来一点点启示与帮助,我就很开心了。
====================分割线====================
直方图的定义
直方图(Histogram)又称柱状图、质量分布图,是一种统计报告图。直方图由一系列高度不等的纵向条纹或线段表示数据分布的情况。一般用横轴表示数据类型,纵轴表示分布情况。在图像处理上,直方图是图像信息统计的有力工具。其实也就是统计一幅图某个亮度像素数量。
1-换个角度认识图像(直方图)
第一个就是当我们面对图像的时候,我们面对的是抽象的矩阵,如下图,下面是0-255的灰度图像的表示,密密麻麻的。
那么我们做的直方图,其实就是对这些像素值的统计。例如:首先,我们需要把0-255分成 17 个 区域(bin),如下图所示:
我们对每个范围中的灰度值进行统计排序,做出如下的表格:
我们是以图像的灰度为例子说明这个直方图,当然直方图不仅仅用于灰度特种统计排序,还可以用于图像的梯度、方向等特征。
灰度直方图是灰度级的函数,描述图像中该灰度级的像素个数(或该灰度级像素出现的频率):其横坐标是灰度级,纵坐标表示图像中该灰度级出现的个数(频率)。
在以上的过程中,我们使用到一些重要的参数,理解这些参数帮助我们更好的使用API函数。
- dims:需要统计的特征的数目,我们上面只统计了 灰度值这个特征,所以, dims =1。
- bins:一般翻译为箱子,看上图,一共有16个bins,其实就和我们平时见得简单函数差不多。在图像直方图中,你可以把一个灰度值设置为一个bins,0~255强度的灰度值一共就需要256个bins,是不是很简单。
- Range:就是范围啦,规定一个bins能够达到的最大和最小的范围。比如一张图片10*10,那么就有100个像素。然后前面已经说过,直方图是按照亮度统计像素数量,那么范围就是0~100啦。这里有一个地方要说一下,刚刚0~100还是对于比较小的图像,那么对于比较大的图像1000*1000,那么范围太大了。我们统计像素数量的时候肯定没有问题,但是要画直方图的时候,难道有一个包含100000个像素,岂不是要化的很长?所以,一般在画直方图的时候,会有一个比例缩放的过程,比如我提前定好我直方图最大的高度只能够是256,那么你就可以用(最大的高度/最大的像素量)统计到的像素量来进行缩放。这样就简单多了。我这里提到的缩放方式只是一种,你可以随便定义喜欢的缩放方式。
一维直方图的结构表示为:
再结合上面画的示意图,应该就很好理解了。
基本的概念其实很简答,想的时候要不要想复杂了,那么基本概念就到这里了。
===============分割线===============
2-相关函数说明
当然了,首先介绍的是计算直方图的函数了。
直方图计算: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 );参数解释:
- 参数1:输入源图像。注意这里的格式是const Mat*,也就是说,你要传入一个地址,输入的数组(图片)或者数组集(一堆图片)需要为相同的深度(CV_8U或CV_32F)和相同的尺寸。
- 参数2:int类型的nimages,输入数组的个数,也就是第一个参数中存放了多少张“图像”,有几个原数组。
- 参数3:const int*类型的channels,用来计算直方图的channes的数组,需要统计的通道(dim)索引。第一个数组通道从0到images[0].channels()-1,而第二个数组通道从images[0]计算到images[0].channels()+images[1].channels()-1,以此类推。比如输入是2副图像,第一副图像有0,1,2共三个channel,第二幅图像只有0一个channel,那么输入就一共有4个channes,如果int channels[3] = {3, 2, 0},那么就表示是使用第二副图像的第一个通道和第一副图像的第2和第0个通道来计算直方图。(这句表示没看懂)。
- 参数4:InputArray类型的mask,可选的操作掩码。如果此掩码不为空,那么它必须为8位(CV_8U)的数组,并且与images[i]有同样大小的尺寸,值为1的点将用来计算直方图。这里的非零掩码元素用于标记出统计直方图的数组元素数据。
- 参数5:OutputArray类型的hist,输出的计算出来的直方图,一个二维数组。
- 参数6:int类型dims,需要计算的直方图的维度,必须是正数,且不大于CV_MAX_DIMS。(32)
- 参数7:const int*类型的histSize,存放每个维度的直方图尺寸的数组。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。
- 参数8:const float**类型的ranges,表示每一个维度数组(第6个参数dims)的每一维的边界阵列,可以理解为每一维数值的取值范围。比如 float rang1[] = {0, 20};float rang2[] = {30, 40}; const float*rangs[] = {rang1, rang2};那么就是对0,20和30,40范围的值进行统计。
- 参数9:bool类型的uniform,表示直方图是否均匀的标识符,即每一个竖条的宽度是否相等。有默认值true。
- 参数10:bool类型的accumulate,累计标识符,有默认值false。若其为true,直方图在配置阶段不会被清零。此功能主要是允许从多个阵列中计算单个直方图,或者用于在特定的时间更新直方图。
void minMaxLoc(InputArray src, CV_OUT double* minVal, CV_OUT double* maxVal=0, CV_OUT Point* minLoc=0, CV_OUT Point* maxLoc=0, InputArray mask=noArray());参数解释
- 参数1:InputArray类型的src,输入单通道数组(图像)。
- 参数2:double*类型的minVal,返回最小值的指针。若无须返回,此值置为NULL。
- 参数3:double*类型的maxVal,返回最大值的指针。若无须返回,此值置为NULL。
- 参数4:Point*类型的minLoc,返回最小位置的指针(二维情况下)。若无须返回,此值置为NULL。
- 参数5:Point*类型的maxLoc,返回最大位置的指针(二维情况下)。若无须返回,此值置为NULL。
- 参数6:InputArray类型的mask,用于选择子阵列的可选掩膜。
void normalize( InputArray src, OutputArray dst, double alpha=1, double beta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray());参数解释:
- 参数1:InputArray类型的src,输入数组(图像)。
- 参数2:OutputArray类似的dst,输出数组(图像),与输入图像类型尺寸一样。
- 参数3:alpha,表示range normalization模式的最小值。有默认值为1。
- 参数4:beta,表示range normalization模式的最大值,不用于norm normalization(范数归一化)模式。有默认值为0。
- 参数5:normType,表示归一化的类型,可以有以下的取值:
---------------NORM_INF:此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化数组的C-范数(绝对值的最大值)。
- 参数6:有默认值为-1。dtype为负数时,输出数组的type与输入数组的type相同;否则,输出数组与输入数组只是通道数相同,而tpye=CV_MAT_DEPTH(dtype)。
- 参数7:操作掩膜,用于指示函数是否仅仅对指定的元素进行操作。
3-程序演示
//************************************************//功能:灰度直方图的实现--即一维直方图 *///包括2种方式绘制出直方图图像*///************************************************#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream> using namespace std;using namespace cv;int main(){Mat srcImage, grayImage;//------------【1】读取源图像并检查图像是否读取成功------------ srcImage = imread("D:/OutPutResult/ImageTest/jianzhu6.jpg");if (!srcImage.data){cout << "读取图片错误,请重新输入正确路径!\n";system("pause");return -1;}//将彩色图转换为灰度图像cvtColor(srcImage, grayImage, CV_BGR2GRAY);imshow("【灰度图】", grayImage);//------------【2】定义直方图参数并计算直方图------------//1--计算的图像的通道,就是需要计算图像的哪个通道(BGR空间需要确定计算 B或G或R空间)const int channels[] = { 0 };//2--配置输出的结果存储的 空间 ,用MatND类型来存储结果MatND hist;//3--设置计算直方图的维度int dims = 1;//4--直方图的每一个维度的柱条的数目(就是将数值分组,共有多少组)const int histSize[] = { 256 }; //如果这里写成int histSize = 256; 那么下面调用计算直方图的calcHist()函数的时候,该变量需要写 &histSize//5--最后是确定每个维度的取值范围,就是横坐标的总数float pranges[] = { 0, 255 };//首先得定义一个变量用来存储单个维度的数值的取值范围const float* ranges[] = { pranges };//6--计算直方图calcHist(&grayImage, 1, channels, Mat(), hist, dims, histSize, ranges, true, false);//------------【3】绘制直方图------------//*********绘制直方图(绘制方式一)*********int scale = 2;int hist_height = 256;Mat hist_img = Mat::zeros(hist_height, 256 * scale, CV_8UC3); //创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像//因为任何一个图像的某个像素的总个数,都有可能会有很多,会超出所定义的图像的尺寸,针对这种情况,先对个数进行范围的限制//先用 minMaxLoc函数来得到计算直方图后的像素的最大个数double max_val;minMaxLoc(hist, 0, &max_val, 0, 0);//将像素的个数整合到 图像的最大范围内//遍历直方图得到的数据for (int i = 0; i < 256; i++){float bin_val = hist.at<float>(i); //注意hist中是float类型int intensity = cvRound(bin_val*hist_height / max_val); //要绘制的高度 rectangle(hist_img, Point(i*scale, hist_height - 1), Point((i + 1)*scale - 1, hist_height - intensity), Scalar(255, 255, 255));//line(hist_img, Point(i*scale, hist_height - 1), Point((i + 1)*scale - 1, hist_height - intensity), Scalar(255, 255, 255), 2, 8, 0);}//*********绘制直方图(绘制方式二)*********int hist_w = 500;int hist_h = 300;int nHistSize = 256;int bin_w = cvRound((double)hist_w / nHistSize);//区间Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));//创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像//将直方图归一化到[0,histImage.rows]normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());//在直方图画布上画出直方图for (int i = 1; i < nHistSize; i++){line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(hist.at<float>(i - 1))),Point(bin_w*(i), hist_h - cvRound(hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);}//显示直方图imshow("【灰度直方图--方式一绘制】", hist_img);imshow("【灰度直方图--方式二绘制】", histImage);waitKey(0);return 0;}==================分割线=============
4-显示结果
5-程序说明
<1> float bin_val = hist.at<float>(i); 要注意直方图数据为浮点类型。
<2>画出直方图其实有多种方式,可以使用line()或rectangle()都可以。
参考文献:
【OpenCV】绘制直方图
Opencv2系列学习笔记4(灰度直方图)
OpenCV从入门到放弃(七):直方图那些事儿
Opencv图像识别从零到精通(8)-----灰度直方图
================END=====================
- 【拜小白opencv】44-灰度直方图(一维直方图)calcHist()函数、minMaxLoc()函数、normalize()函数
- 【拜小白opencv】45-二维H-S直方图绘制----calcHist()函数、minMaxLoc()函数
- 【拜小白opencv】46-RGB直方图计算与绘制----calcHist()函数、normalize()函数
- openCV学习笔记(4):绘制直方图和calcHist()函数、normalize()函数的解析
- opencv2 直方图 calchist函数
- OpenCV 直方图计算函数 calcHist源码深度剖析
- opencv2 直方图之calchist函数使用
- calcHist函数来计算图像直方图
- opencv 灰度直方图 一维直方图
- openCV直方图相关函数
- 关于opencv直方图计算函数 calcHist()的channels参数的理解
- opencv 直方图calcHist
- opencv 图像直方图 calcHist
- opencv 计算直方图 calcHist()
- opencv之直方图caluHist函数
- openCV 直方图比较compareHist函数
- 利用OpenCV的calcHist绘制灰度直方图、H-S直方图、BGR直方图和自定义直方图的源码及说明
- Opencv之直方图计算calcHist
- 51nod 1195 斐波那契数列的循环节【斐波那契数列&&二次剩余&&欧拉判定准则】
- java中使用Jedis操作Redis实例
- HDU P1004 Let the Balloon Rise
- LightCNN C++接口抽取人脸特征
- Spark Metrics配置详解
- 【拜小白opencv】44-灰度直方图(一维直方图)calcHist()函数、minMaxLoc()函数、normalize()函数
- faster-rcnn tensorflow windows demo运行
- Insertion_sort
- 复习三:java基础知识点
- 《看透springMVC源码》之Container分析
- 查看APK的签名的方法,和应用商店更改签名导致第三方无法登录问题
- 这5步让我们职场的2018顺风顺水
- unittest的简单应用
- Tree ensemble算法中feature importance计算方法