一、话说反向投影
首先,讲解下它的英文名,projection除了项目工程的意思外,还有投影的意思,数学中也用 表示投影。
反向投影其实是直方图运算的逆过程。直方图运算是统计每个灰度值对应的像素个数,而反向投影则是将像素个数回送到该像素个数对应灰度区间的像素位置。来看一个例子。
假设有下面这个图像矩阵:
然后计算直方图,将灰度值划分为如下四个区间:[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。以此类推,得到反向投影后的矩阵:
二、一般步骤
前面讲过,反向投影是基于直方图的逆运算,而直方图则反应了图像的色彩(亮度)特征,当两幅相似的图像仅发生位置的变化而色彩(光线)几乎不变时,对应的两幅直方图相似度肥肠高。
但直方图只是得到了特征,反向投影则是将特征“反映”到图像上,对于物体特征识别和分割有着很大的作用。
进行反向投影的一般步骤:
API:
dst=cv2.calcBackProject(images, channels, hist, ranges, scale[, dst])
三、实验
话不多说,上代码
Mat srcImage, hsvImage, hueImage;
const int hueBinMaxValue = 180;
int hueBinValue = 25;
//声明回调函数
void Hist_and_Backprojection(int, void*);
int main()
{
srcImage = imread("D:\\cv_study\\随机练\\1.jpg");
imshow("原图", srcImage);
//判断图像是否加载成功
if (srcImage.empty())
{
cout << "图像加载失败" << endl;
return -1;
}
else
cout << "图像加载成功..." << endl << endl;
//将图像转化为HSV图像
cvtColor(srcImage, hsvImage, CV_BGR2HSV);
//只使用图像的H参数
hueImage.create(hsvImage.size(), hsvImage.depth());
int ch[] = { 0,0 };
mixChannels(&hsvImage, 1, &hueImage, 1, ch, 1);
//轨迹条参数设置
namedWindow("SourceImage", WINDOW_AUTOSIZE);
//创建轨迹条并调用回调函数
createTrackbar("值", "SourceImage", &hueBinValue, hueBinMaxValue, Hist_and_Backprojection);
Hist_and_Backprojection(hueBinValue, 0);
imshow("SourceImage", srcImage);
waitKey(0);
return 0;
}
void Hist_and_Backprojection(int, void*)
{
MatND hist;
int histsize = MAX(hueBinValue, 2);
float hue_range[] = { 0,180 };
const float* ranges = { hue_range };
//计算图像直方图并归一化处理
calcHist(&hueImage, 1, 0, Mat(), hist, 1, &histsize, &ranges, true, false);
normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());
//获取反向投影
MatND backProjection;
calcBackProject(&hueImage, 1, 0, hist, backProjection, &ranges, 1, true);
//输出反向投影
imshow("BackProjection", backProjection);
//绘制图像直方图
int w = 400;
int h = 400;
int bin_w = cvRound((double)w / histsize);
Mat histImage = Mat::zeros(w, h, CV_8UC3);
for (int i = 0; i < hueBinValue; i++)
{
rectangle(histImage, Point(i*bin_w, h), Point((i + 1)*bin_w, h - cvRound(hist.at(i)*h / 255.0)), Scalar(0, 0, 255), -1);
}
imshow("HistImage", histImage);
}
结果如下:
这里将反向投影的结果复现出来,那么反向投影有什么用呢,就我所知道的在目标跟踪算法mean-shift和camshift中都会用到,计算目标区域的反向投影,然后进行匹配,一系列的迭代和逼近,这里我就不多说了,有兴趣的可以搜索一下上面说的算法。知识有限,错误的地方请批评指正,谢谢