上篇博文(https://blog.csdn.net/lehuoziyuan/article/details/84064822)介绍了灰度直方图的计算,是一维的直方图,这篇博文介绍运用calcHist计算二维联合直方图的方法。以HSV空间的H-S的二维联合直方图为例。
需要说明的是,二维直方图并不是一个通道一个通道的分别独立平行计算,而是将两个通道的数据整合起来计算出的二维直方图。
calcHist函数就不介绍了,上一篇帖子已经讲进了,详情见我的上篇博客!
直接上源码吧!
源码中使用的图像下载链接:http://pan.baidu.com/s/1jHHh7sM 密码:78cr
图像处理开发资料、图像处理开发需求、图像处理接私活挣零花钱,可以搜索公众号"qxsf321",并关注!
//opencv版本:OpenCV3.0
//VS版本:VS2013
//Author:qxsf321.net
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat srcImage = imread("linger.jpg");
imshow("【原图】", srcImage);
Mat hsvImage;
//因为要计算H-S的直方图,所以需要得到一个HSV空间的图像
cvtColor(srcImage, hsvImage, CV_BGR2HSV);
//imshow("【HSV空间的原图】", hsvImage);
//为计算直方图配置变量
//首先是需要计算的通道编号,就是需要计算哪个通道的直方图(BGR空间需要确定计算,计算方法见帖子中对相关参数的说明)
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) * 256 / g_dHistMaxValue);
rectangle(drawImage, Point(10 * i, j * 10), Point((i + 1) * 10 - 1, (j + 1) * 10 - 1), Scalar(value), -1);
}
}
imshow("【H-S二维联合直方图】", drawImage);
waitKey(0);
return 0;
}
代码说明:
rectangle的两个point参数分别为一个矩阵的左上角顶点坐标和右下角顶点坐标!
运行结果截图如下: