1. 反向投影是一种记录像素点或者像素块如何适应已知直方图模型中分布的方式。可以先计算出图像中某一区域的特征直方图模型,然后利用该模型在图像中寻找相应的特征。OpenCv 1.0中的反向投影函数为:
void cvCalcBackProject(IplImage * image,CvArr * back_project,const CvHistogram * hist)
2. 反向投影原理:图像的反向投影图是用输入图像的某一位置上像素值(多维或灰度)对应在直方图的一个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。
3. 在用CamShift做目标跟踪时,也用到了反向投影.
#include
#include
//初始图像,HSV图像,掩膜,直方图,反投影
IplImage * img,*hsv,*hue,*mask,*histimg,*backproject;
CvHistogram * hist;
//bin的个数
int bins=16;
float hrange[]={0,180};
float * ranges[]={hrange};
//选择的感兴趣区域
CvRect selection=cvRect(0,0,100,100);
#include
#include
CvScalar hsv2rgb( float hue )
{
int rgb[3], p, sector;
static const int sector_data[][3]=
{{0,2,1}, {1,2,0}, {1,0,2}, {2,0,1}, {2,1,0}, {0,1,2}};
hue *= 0.033333333333333333333333333333333f;
sector = cvFloor(hue);
p = cvRound(255*(hue - sector));
p ^= sector & 1 ? 255 : 0;
rgb[sector_data[sector][0]] = 255;
rgb[sector_data[sector][1]] = 0;
rgb[sector_data[sector][2]] = p;
return cvScalar(rgb[2], rgb[1], rgb[0],0);
}
//处理反向投影
void BackProject()
{
int hbins=bins;
//转换为HSV空间
cvCvtColor(img,hsv,CV_BGR2HSV);
//定义掩膜
cvInRangeS(hsv,cvScalar(0,30,10,0),cvScalar(180,256,256,0),mask);
//创建直方图
hist=cvCreateHist(1,&hbins,CV_HIST_ARRAY,ranges,1);
//分离hue通道
cvSplit(hsv,hue,0,0,0);
//设置感兴趣区域
cvSetImageROI(hue,selection);
cvSetImageROI(mask,selection);
//统计直方图
cvCalcHist(&hue,hist,CV_HIST_ARRAY,mask);
cvResetImageROI(hue);
cvResetImageROI(mask);
int bin_w=histimg->width/hbins;
for(int i=0;ibins,i)*histimg->height/255);
CvScalar color=hsv2rgb(i*180.f/hbins);
cvRectangle(histimg,cvPoint(i*bin_w,histimg->height),
cvPoint((i+1)*bin_w,histimg->height-val),color,-1,8,0);
}
cvNamedWindow("hist");
cvShowImage("hist",histimg);
//反向投影
cvCalcBackProject(&hue,backproject,hist);
cvAnd(backproject,mask,backproject,0);
//显示反投影
cvNamedWindow("backproject");
cvShowImage("backproject",backproject);
cvRectangle(img,cvPoint(selection.x,selection.y),
cvPoint(selection.x+selection.width,selection.y+selection.height),cvScalar(255,0,0),1,8,0);
cvShowImage("img",img);
}
int num=0;
void on_mouse(int event,int x,int y,int flags,void * param)
{
switch(event)
{
case CV_EVENT_LBUTTONDOWN:
num++;
selection.x=x;
selection.y=y;
if(num>1)
{
cvReleaseHist(&hist);
cvZero(histimg);
}
break;
case CV_EVENT_LBUTTONUP:
selection.width=x-selection.x;
selection.height=y-selection.y;
BackProject();
break;
}
}
void main()
{
img=cvLoadImage("f:\\capture_huangfei.jpg");
cvNamedWindow("img");
//分配内存
CvSize size=cvGetSize(img);
hsv=cvCreateImage(size,8,3);
hue=cvCreateImage(size,8,1);
mask=cvCreateImage(size,8,1);
backproject=cvCreateImage(size,8,1);
histimg=cvCreateImage(cvSize(320,200),8,3);
cvZero(histimg);
cvShowImage("img",img);
//添加鼠标消息响应
cvSetMouseCallback("img",on_mouse,0);
cvCreateTrackbar("hbins","img",&bins,180,0);
cvWaitKey(0);
}