反向投影:
OpenCV 资料里给出的概念是“一种记录给定图像中的像素点如何适应直方图模型像素分布的方式。简单的讲, 所谓反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征。”简单一点理解就是模板匹配,给定一个目标模板,然后再逐个遍历原图像和模板图像相同的图像块,对比图像块和模板的直方图,然后把比较结果存入一个新的图像中,新图像中的全局极值就是模板在原图像中所在的位置。
如果用统计学术语,输出图像象素点的值是观测数组在某个分布(直方图)下的概率。用下式表示:
来自参考博客:反向投影图
其中b(xi)表示在位置xi上像素对应的直方图第b(xi)个bin(可以理解为第b(xi)个灰度级区间),直方图共m个bin,qu表示第u个bin的值。
Image=
0 1 2 3
4 5 6 7
8 9 10 11
8 9 14 15
Histogram=
4 4 6 2(3)反向投影图
Back_Projection=
4 4 4 4
4 4 4 4
6 6 6 6
6 6 2 2
例如位置(0,0)上的像素值为0,对应的bin为[0,3),所以反向直方图在该位置上的bin值为4。
同时参考博客中还给出了测试代码。。。
图像的反向投影图是用输入图像的某一位置上像素值(多维或灰度)对应在直方图的一个bin上的值来代替该像素值,所以得到的反向投影图是单通的。通常情况下我们需要将RGB空间的彩色图像转换到HSV彩色空间。在HSV空间中,H(hue)代表色调,包括了图像的颜色信息,通常不会与S和V通道相互影响。但是如果在CamShift算法中跟踪的区域的H、V值很低的话,表示照明度和对比度不高,会影响跟踪效果。因为有很多噪声影响H通道。
下面给一个OpenCV中关于反向投影的demo:
#include <iostream>
#include "cv.h"
#include "highgui.h"
using namespace std;
using namespace cv;
//declare image matrix
//initialize bin number
Mat srcImg;
Mat hsv;
Mat hue;
int bins = 25;
void histAndBackProject(int,void *)
{
MatND hist;
int histSize = max(bins,2);
float hueRange[] = {0,180};
const float* range = {hueRange};
//calc hist and normalize
calcHist(&hue,1,0,Mat(),hist,1,&histSize,&range,true,false);
// normalize to [0,255]
normalize(hist,hist,0,255,NORM_MINMAX,-1,Mat());
//calc back projection
MatND backProj;
calcBackProject(&hue,1,0,hist,backProj,&range,1,true);
//show back projection
imshow("Back Projection",backProj);
//show 1-D hist
int w = 400;
int h = 400;
int binW = cvRound((double)w/histSize);
Mat histImg = Mat::zeros(w,h,CV_8UC3);
for(int i = 0;i < bins;i++)
{
rectangle(histImg,Point(i*binW,h),
Point((i+1)*binW,h-cvRound(hist.at<float>(i)*h/255.0)),Scalar(0,0,255),-1);
}
imshow("Histogram",histImg);
}
int main(int argc,char** argv)
{
srcImg = imread("lena.jpg");
cvtColor(srcImg,hsv,CV_BGR2HSV);
//only used H channel to create 1-D histogram,we can also create H-S histogram
hue.create(hsv.size(),hsv.depth());
int ch[] = {0,0};
// &hsv: 一系列输入图像的数组, 被拷贝的通道的来源;
// 1: 输入数组中图像的数目;
// &hue: 一系列目的图像的数组, 储存拷贝的通道;
// 1: 目的数组中图像的数目;
// ch[] = {0,0}: 通道索引对的数组,指示如何将输入图像的某一通道拷贝到目的图像的某一通道,
// 在这里,&hsv图像的Hue(0) 通道被拷贝到&hue图像(单通道)的0 通道;
// 1: 通道索引对数目;
mixChannels(&hsv,1,&hue,1,ch,1);
char* windowImg = "Source Image";
namedWindow(windowImg,CV_WINDOW_AUTOSIZE);
// 创建Trackbar方便用户输入bin数目;
// Trackbar的任何变动将会调用函数histAndBackProject
createTrackbar("Hue bins ",windowImg,&bins,180,histAndBackProject);
histAndBackProject(0,0);
imshow(windowImg,srcImg);
cvWaitKey(0);
return 0;
}
这篇博客中介绍了几种实现反向投影的理论方法:点这里