设有原灰度图像矩阵:
Image=
1 2 3 4
5 6 7 7
9 8 0 1
5 6 7 6
将灰度值划分为如下四个区间:
[0,2] [3,5] [6,7] [8,10]
很容易得到这个图像矩阵的直方图hist= 4 4 6 2
好,接下来计算反向投影矩阵:
反向投影矩阵的大小和原灰度图像矩阵的大小相同!
原图像中坐标为(0,0)的灰度值为1,1位于区间[0,2] 中,区间[0,2] 对应的直方图值为4,所以反向投影矩阵中中坐标为(0,0)的值记为4
按上面的计算方法,可以得到Image的直方图反向投影矩阵为:
back_Projection=
4 4 4 4
4 6 6 6
2 2 4 4
4 6 6 6
从上面的计算过程我们来理解直方图的反向投影到底代表什么?
我们看到,实际上是原图像的256个灰度值被置为很少的几个值了,具体有几个值,要看把0~255划分为多少个区间!反向投影矩阵中某点的值就是它对应的原图像中的点所在区间的灰度直方图值。所以我们可以看出,一个区间点越多,在反向投影矩阵中就越亮。
那么怎么理解反向投影矩阵中的“反向”二字呢?从这个过程可以看出,我们是先求出原图像的直方图,再由直方图得到反向投影矩阵,由直方图到反向投影矩阵实际上就是一个反向的过程,所以叫反向。
通过图像的反向投影矩阵,我们实际上把原图像简单化了,简单化的过程实际上就是提取出图像的某个特征。所以以后我们可以用这个特征来对比两幅图,如果两幅图的反向投影矩阵相似或相同,那么我们就可以判定这两幅图这个特征是相同的。
以上定义摘自该篇博客:https://blog.csdn.net/michaelhan3/article/details/73550643
API函数:calcBackProject(&image, 1, 0, h_hist, backProject, &ranges);
参数解释:单通道图像地址,计算多少张通常取1,通道数通常取0,单通道图形的直方图统计结果,方向投影图像,灰度范围。
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void callback(int, void*);
Mat src, dst, hue, hsv,h_hist,backProject;
int histSize = 20;
int main(int arc, char** argv)
{
src = imread("1.jpg");
namedWindow("input",CV_WINDOW_AUTOSIZE);
imshow("input", src);
cvtColor(src, hsv, CV_BGR2HSV);
vector<Mat> channels;
split(hsv, channels);
hue = channels[0];
namedWindow("output", CV_WINDOW_AUTOSIZE);
createTrackbar("Histogram Bin", "output", &histSize, 180, callback);
callback(0, 0);
waitKey(0);
return 0;
}
void callback(int, void*) {
float range[] = { 0, 255 };
const float* ranges = { range };
calcHist(&hue, 1, 0, Mat(), h_hist, 1, &histSize, &ranges);
// 归一化
normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());
//直方图反向投影
calcBackProject(&hue, 1, 0, h_hist, backProject, &ranges);
imshow("output", backProject);
}
运行结果如下: