直方图反向投影的用途这里暂时不讲,先给大家看一个简单的例子,通过这个例子让大家了解到直方图反向投影是怎么样的一种运算,大家了解它的运算后就可以发挥自己的才智去运用它了。
设有原灰度图像矩阵:
Image=
9 5 7 9
1 2 3 5
6 7 8 1
2 3 5 6
将灰度值划分为如下四个区间:
[0,2] [3,5] [6,7] [8,10]
很容易得到这个图像矩阵的直方图hist= 4 5 4 3
好,接下来计算反向投影矩阵:
反向投影矩阵的大小和原灰度图像矩阵的大小相同!
原图像中坐标为(0,0)的灰度值为9,9位于区间[8,10] 中,区间[8,10] 对应的直方图值为3,所以反向投影矩阵中中坐标为(0,0)的值记为3
按上面的计算方法,可以得到Image的直方图反向投影矩阵为:
back_Projection=
3 5 4 3
4 4 5 5
4 4 3 4
4 5 5 4
从上面的计算过程我们来理解直方图的反向投影到底代表什么?
各位朋友,如果你想知道“直方图的反向投影到底代表什么”,可以搜索公众号"qxsf321",并关注,然后回复0018获取答案。
OpenCV提供了函数calcBackProject来计算图像的直方图反向投影,函数原型如下:
C++: void calcBackProject(const Mat* images, int nimages, const int* channels, InputArray hist, OutputArray backProject, const float** ranges, double scale=1, bool uniform=true )
参数介绍下:
images:源图像数组指针
nimages:源图像张数
channels:要计算直方图反向投影的通道编号。通道编号方法:第一张图的通道编号为0至images[0].channels()-1,第二张图的通道编号为images[0].channels()至images[0].channels() + images[1].channels()-1,以此类推,注意这个参数是指针。
hist:图像的直方图矩阵
backProject:函数计算出的直方图反向投影图的存储矩阵
ranges:各个通道取值的边界值或区间划分。
scale:反向投影图的尺度系数。最终函数生成的的反向投影图会乘以这个系数。
uniform:直方图是否均匀化的标志,意义暂时不清楚,等以后搞清楚了再来补充说明。
用函数calcBackProject来计算图像的直方图反向投影的源代码如下:
源码中使用的图像下载链接:http://pan.baidu.com/s/1kUJMx1t 密码:r3d3
//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 img = imread("02.jpg");
if (img.empty())
{
cout << "Error: Could not load image" << endl;
return 0;
}
Mat srcImage;
cvtColor(img, srcImage, CV_BGR2GRAY);
imshow("【原图的灰度图】", srcImage);
//为计算直方图配置变量
//首先是需要计算的通道编号,就是需要计算哪个通道的直方图(BGR空间需要确定计算,计算方法见帖子中对相关参数的说明)
int channels = 0;
//然后是定义直方图计算结果的存储空间
Mat dstHist;
//接下来是直方图的每一个维度的数目(这个数目用于将每一维度的数值分组)
int histSize[] = { 256 };
//最后是确定每个维度的取值范围,就是每一维度的横坐标的取值范围
//首先得定义一个数组用来存储单个维度的的取值范围
float midRanges[] = { 0, 256 };
//然后把这个数组再放到一个二维数组中
const float *ranges[] = { midRanges };
const float *ranges2 = { midRanges };
//准备工作做好后,就可以调用calcHis函数计算直方图数据了
calcHist(&srcImage, 1, &channels, Mat(), dstHist, 1, histSize, ranges, true, false);
//calcHist函数调用结束后,dstHist变量中将储存直方图数据
//对直方图数据进行归一化处理,把值归一化到0到255
normalize(dstHist, dstHist, 0, 255, NORM_MINMAX, -1, Mat());
// 计算反向投影
Mat backproj;
calcBackProject(&srcImage, 1, 0, dstHist, backproj, &ranges2, 1, true);
/// Draw the backproj
imshow("BackProj", backproj);
waitKey(0);
return 0;
}
代码说明:
计算直方图的代码这里就不说了,不清楚的可参看博文https://blog.csdn.net/lehuoziyuan/article/details/84064822
这里说下归一化函数normalize,原型如下:
C++: void normalize(InputArray src, InputOutputArray dst, double alpha=1, double beta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray() )
参数意义如下:
src:待归一化的矩阵
dst:归一化后的矩阵
alpha:归一化后值的下边界
beta: 归一化后值的上边界,这个值当normType=NORM_L1或normType=NORM_L2时无效。
normType:归一化类型,具体类型如下有NORM_INF, NORM_L1, or NORM_L2,实际上是选择哪个数成为归一化后的最大值。当为NORM_INF时,最大值为beta;当为NORM_L1时,最大值为矩阵的L1范数;当为NORM_L2时,最大值为矩阵的L2范数;
dtype:当这个值为负值时,输出矩阵和输入矩阵的数据类型一致;当为其它值时,不仅数据类型要一致,深度和通道数也要一样。
mask:掩码阵列。掩码中的非0元素对应的图像元素将会被计算,0元素则被屏蔽不参与计算,可选参数。
程度运行结果截图如下: