详解什么叫二维直方图,并利用OpenCV的函数calcHist()绘制图像的H-S二维直方图
Posted 昊虹算法
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解什么叫二维直方图,并利用OpenCV的函数calcHist()绘制图像的H-S二维直方图相关的知识,希望对你有一定的参考价值。
在阅读这篇博文前,请大家先阅读一下我的上一篇博文,链接如下:
对OpenCV的函数calcHist()进行透彻解析,并利用它实例绘制一个一维灰度直方图
图像的二维直方图是图像在两个维度上的直方图联合统计结果。
上面这句话有点抽象,举个简单的例子,大家就能清晰明了的理解了。
设图像A有两个通道,其两个通道的数据分别如下:
使用calcHist()计算两个通道的二维直方图的参数设置如下:
int channels[] = 0, 1;
int histSize[] = 2, 3;
float Ranges_1[] = 0, 4;
float Ranges_2[] = 0, 6;
const float *ranges[] = Ranges_1, Ranges_2;
由于两个通道的histSize值分别为2和3,则最终计算得到的二维直方图数据,即calcHist中的输出参数“hist”将是一个二维的矩阵,并且其行数为2,列数为3,总共2×3=6个元素。
下面我们分别来说这6个元素的含义并求这6个元素的值,明白了这6个元素的含义和值的求法,便知道了二维直方图的含义。
首先我们要知道对于第1个通道而言,其histSize的值为2,ranges为0~4,则0~4被划分为两个区间,
第一个区间为[0,2) ,第二个区间为[2,4) ,注意区间为左闭右开区间。
对于第二个通道而言,其histSize的值为3,ranges为0~6,则0~6被划分为三个区间,
第一个区间为[0,2) ,第二个区间为[2,4) ,第三个区间为[4,6),注意区间为左闭右开区间。
我们设his这个二维矩阵的左上角为坐标原点,则其各元素的含义和值如下:
(0,0) 表示同时满足以下两个条件的像素值个数:
第1通道的灰度值在区间[0,2)内且第2通道的灰度值在区间[0,2)内。结合两个通道的具体数值,我们可知其值为0
(0,1) 表示同时满足以下两个条件的像素值个数:
第1通道的灰度值在区间[0,2)内且第2通道的灰度值在区间[2,4)内。结合两个通道的具体数值,我们可知其值为3
(0,2) 表示同时满足以下两个条件的像素值个数:
第1通道的灰度值在区间[0,2)内且第2通道的灰度值在区间[4,6)内。结合两个通道的具体数值,我们可知其值为0
(1,0) 表示同时满足以下两个条件的像素值个数:
第1通道的灰度值在区间[2,4)内且第2通道的灰度值在区间[0,2)内。结合两个通道的具体数值,我们可知其值为0
(1,1) 表示同时满足以下两个条件的像素值个数:
第1通道的灰度值在区间[2,4)内且第2通道的灰度值在区间[2,4)内。结合两个通道的具体数值,我们可知其值为3
(1,2) 表示同时满足以下两个条件的像素值个数:
第1通道的灰度值在区间[2,4)内且第2通道的灰度值在区间[4,6)内。结合两个通道的具体数值,我们可知其值为0
所以这个hist二维矩阵的内容应该如下:
我们用程序来实际验证一下看下是不是这个结果:
代码如下:
//博主微信/QQ 2487872782
//有问题可以联系博主交流
//有图像处理需求也可联系博主
//图像处理技术交流QQ群 271891601
//OpenCV版本:3.0
//VS版本:2012
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
Mat Image1( 2, 3, CV_8UC2, cv::Scalar(1,2) );
for (int j = 0; j < Image1.cols; j++)
Image1.at<Vec2b>(1, j)[0] = 2;
for (int j = 0; j < Image1.cols; j++)
Image1.at<Vec2b>(0, j)[1] = 3;
int channels[] = 0, 1;
int histSize[] = 2, 3;
float Ranges_1[] = 0, 4;
float Ranges_2[] = 0, 6;
const float *ranges[] = Ranges_1, Ranges_2;
Mat dstHist;
calcHist(&Image1, 1, channels, Mat(), dstHist, 2, histSize, ranges, true, false);
cout<<dstHist<<endl<<endl;
return 0;
运行结果如下:
可见,和我们手工计算出的结果是一样的。
至此,大家就应该知道二维直方图的含义了。
接下来我们利用OpenCV的函数calcHist()绘制图像的H-S二维直方图。
对于彩色图像,我们通常需要同时考虑图像的色调(hue)和饱和度(saturation),所以有时候我们需要计算图像的“色调-饱和度二维直方图”,即H-S直方图。
下面给出利用OpenCV的函数calcHist()绘制彩色图像H-S直方图的示例代码。
代码中用到的图像下载链接:
链接:https://pan.baidu.com/s/1GQrl1ATIdarzXm3EdLJRzg?pwd=avsa
//博主微信/QQ 2487872782
//有问题可以联系博主交流
//有图像处理需求也可联系博主
//图像处理技术交流QQ群 271891601
//OpenCV版本:3.0
//VS版本:2012
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
Mat srcImage = imread("F:/material/images/P0005-BaoXiaofeng.jpg");
imshow("【原图】", srcImage);
Mat hsvImage;
//因为要计算H-S的直方图,所以需要先进行颜色空间的转换
cvtColor(srcImage, hsvImage, CV_BGR2HSV);
//计算H-S二维直方图的参数配置
int channels[] = 0, 1 ;
Mat dstHist;
int histSize[] = 30, 32 ;
float HRanges[] = 0, 180 ;
float SRanges[] = 0, 256 ;
const float *ranges[] = HRanges, SRanges ;
//参数配置好后,就可以调用calcHis函数计算直方图数据了
calcHist(&hsvImage, 1, channels, Mat(), dstHist, 2, histSize, ranges, true, false);
//calcHist函数调用结束后,dstHist变量中将储存直方图数据
///接下来绘制直方图
//首先先创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像
Mat drawImage = Mat::zeros(Size(300, 320), CV_8UC3);
//因为数据矩阵中的某个值的总个数可能会超出所定义的图像的尺寸,所以要对个数进行归一化处理
//先用 minMaxLoc函数来得到计算直方图中的最大数据,这个函数的使用方法大家一看函数原型便知
double g_dHistMaxValue;
minMaxLoc(dstHist, 0, &g_dHistMaxValue, 0, 0);
//遍历直方图数据,对数据进行归一化和绘图处理
for (int i = 0; i < 30; i++)
for (int j = 0; j < 32; j++)
int value = cvRound(dstHist.at<float>(i, j) * 255/ g_dHistMaxValue);
rectangle(drawImage, Point(10 * i, j * 10), Point((i + 1) * 10 - 1, (j + 1) * 10 - 1), Scalar(0,0,value), -1);
imshow("【H-S二维联合直方图】", drawImage);
waitKey(0);
return 0;
上面的代码比较难理解的部分是:根据计算出的二维直方图数据绘制直方图的两句代码,即下面两句:
int value = cvRound(dstHist.at<float>(i, j) * 255/ g_dHistMaxValue);
rectangle(drawImage, Point(10 * i, j * 10), Point((i + 1) * 10 - 1, (j + 1) * 10 - 1), Scalar(0,0,value), -1);
这两句代码要补充说几句。
1 这两句代码把hist里的数据归一化到0~255。
2 这两句代码把二维直方图进行了按比例放大绘制,本来hist的大小是30×32的,但在绘制的时候我们把其放大到了300×320,这是为了便于我们观察。
3 我们是用三通道的彩色图绘制二维直方图的,这样做也是便于我们肉眼观察,每一块矩形我们都用不同程度的红色来绘制,其红色的程度值就是hist里对应点进行归一化后的值。
上面代码的运行结果如下图所示:
以上是关于详解什么叫二维直方图,并利用OpenCV的函数calcHist()绘制图像的H-S二维直方图的主要内容,如果未能解决你的问题,请参考以下文章
详解为什么OpenCV的直方图计算函数calcHist()计算出的灰度值为255的像素个数为0
对OpenCV的函数calcHist()进行透彻解析,并利用它实例绘制一个一维灰度直方图
opencv —— calcHistminMaxLoc 计算并绘制图像直方图寻找图像全局最大最小值