直方图反向投影的作用

来源:互联网 发布:java md5加密源代码 编辑:程序博客网 时间:2024/06/09 13:45

我们先通过一幅图来理解反向投影:图片来源点击打开链接

这副图的箭头表示了反向投影过程:直方图—>反向投影图像。

反向投影的作用是什么呢?Opencv中文网站这样说:所谓反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征。

更通俗一点,反向投影可以通过颜色直方图来理解,我们检测图像中某个像素点的颜色是否位于直方图中,如果位于则将颜色加亮,通过对图像的检测,得出结果图像,结果图像一定和直方图像匹配。那么对于图像颜色的取样点越多,越能更好的找出目标图形。这里直方图的作用在于提供一个比较标准(也就是模版),即对于要检测的图像来说,需要给它提供一个模版,用于识别出和模版相应的特征。
我们也通过一幅图片来理解。图片来源:点击打开链接

我们在sourse图像(原图像)中识别头部图像(模版图像,中间那个),在结果图像中(最右边那个)较亮部分就是人头部识别出的位置!
1.经过上面的分析,下面给出反向投影的作用:反向投影用于在输入图像(通常较大)中查找特定图像(通常较小或者仅1个像素,以下将其称为模板图像)最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置。
2.反向投影查找原理:查找的方式就是不断的在输入图像中切割跟模板图像大小一致的图像块,并用直方图对比的方式与模板图像进行比较。
假设我们有一张100x100的输入图像,有一张10x10的模板图像,查找的过程是这样的:
(1)从输入图像的左上角(0,0)开始,切割一块(0,0)至(10,10)的临时图像;
(2)生成临时图像的直方图;
(3)用临时图像的直方图和模板图像的直方图对比,对比结果记为c;
(4)直方图对比结果c,就是结果图像(0,0)处的像素值;
(5)切割输入图像从(0,1)至(10,11)的临时图像,对比直方图,并记录到结果图像;
(6)重复(1)~(5)步直到输入图像的右下角。
3.反向投影的结果包含了:以每个输入图像像素点为起点的直方图对比结果。可以把它看成是一个二维的浮点型数组,二维矩阵,或者单通道的浮点型图像。
可以这样理解:对于calcBackProjectPatch,也就是是基于块的反向投影形式,利用直方图做匹配,类似于模板匹配,只不过这些模板转换为直方图,而原图中以某点为基准,抠出来作对比的部分也转换为直方图,两个直方图作匹配,匹配的结果作为此点的值。 结果会是一张灰度图。
4.如果输入图像和模板图像一样大,那么反向投影相当于直方图对比。如果输入图像比模板图像还小,无法进行反向投影。
5.基于块的反向投影函数:
void cvCalcBackProjectPatch(         IplImage** image,   /*输入图像:是一个单通道图像数组,而非实际图像*/        CvArr* dst,         /*输出结果:是一个单通道32位浮点图像,它的宽度为W-w+1,高度为H-h+1,这里的W和H是输入图像的宽度和高度,w和h是模板图像的宽度和高度*/        CvSize patch_size,  /*模板图像的大小:宽度和高度*/        CvHistogram* hist,  /*模板图像的直方图:直方图的维数和输入图像的个数相同,并且次序要一致;例如:输入图像包含色调和饱和度,那么直方图的第0维是色调,第1维是饱和度*/        int method,         /*对比方式:跟直方图对比中的方式类似,可以是:CORREL(相关)、CHISQR(卡方)、INTERSECT(相交)、BHATTACHARYYA*/        float factor        /*归一化因子,一般都设置成1,否则很可能会出错;*/    );

Opencv实现代码:
#include "highgui.h"#include <cv.h>int main(int argc, char** argv)  {  const char* img_file = "d://12.jpg";  //原图像const char* model_file = "d://4.jpg";//模版图像////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////const char* wd_imgsrc = "原图像";const char* wd_model_hist = "模板的HS直方图";const char* wd_template = "模板匹配结果";const char* wd_backpro = "反向投影匹配结果";const char* wd_block_backpro = "block反向投影匹配结果";cvNamedWindow(wd_imgsrc,1);cvNamedWindow(wd_model_hist,1);cvNamedWindow(wd_template,1);cvNamedWindow(wd_backpro,1);cvNamedWindow(wd_block_backpro,1);cvNamedWindow("模版图像",1);//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////IplImage* imgsrc = cvLoadImage(img_file);//载入原图像IplImage* imgmodel = cvLoadImage(model_file);//载入模版图像//创建处理后的结果图像IplImage* img_template = cvCreateImage(cvSize(imgsrc->width - imgmodel->width + 1, imgsrc->height - imgmodel->height + 1), 32, 1); //模板匹配结果图像IplImage* img_backpro = cvCreateImage(cvGetSize(imgsrc), 8, 1); //反向投影结果图,必须是8bit图像,不能是32bitCvSize patch_size = cvGetSize(imgmodel);  //block大小IplImage* img_block_backpro = cvCreateImage(cvGetSize(img_template), IPL_DEPTH_32F, 1); //block反向投影结果图//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////建立imgsrc 和 imgmodel 的单通道图像数组IplImage* model_hsv = cvCreateImage(cvGetSize(imgmodel), 8 , 3);  cvCvtColor(imgmodel, model_hsv, CV_BGR2HSV);    //将模版图像转换成hsv图像IplImage* h_plane =  cvCreateImage(cvGetSize(imgmodel), 8 , 1); IplImage* s_plane =  cvCreateImage(cvGetSize(imgmodel), 8 , 1); IplImage* v_plane =  cvCreateImage(cvGetSize(imgmodel), 8 , 1); IplImage* planes[] = {h_plane, s_plane}; //计算直方图cvCalcHist()的参数 IplImage**cvSplit(model_hsv, h_plane, s_plane, v_plane, NULL);  // 得到h,s,v单通道图像IplImage* imgsrc_hsv = cvCreateImage(cvGetSize(imgsrc), 8 , 3);  cvCvtColor(imgsrc, imgsrc_hsv, CV_BGR2HSV);    //将原图像转换成hsv图像IplImage* src_h_plane =  cvCreateImage(cvGetSize(imgsrc), 8 , 1); IplImage* src_s_plane =  cvCreateImage(cvGetSize(imgsrc), 8 , 1); IplImage* src_v_plane =  cvCreateImage(cvGetSize(imgsrc), 8 , 1); IplImage* imgsrc_planes[] = {src_h_plane, src_s_plane}; //计算直方图cvCalcHist()的参数 IplImage**cvSplit(imgsrc_hsv, src_h_plane, src_s_plane, src_v_plane, NULL);  //得到h,s,v单通道图像/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////计算model的HS直方图;h,s直方图是二维直方图int h_bins = 30;int s_bins = 32;CvHistogram *model_hist, *model_hist_normalized;int hist_size[] = {h_bins, s_bins};  //直方图大小 = h_bins * s_binsfloat h_ranges[] = {0, 180};  //均匀bin, range只需要最大最小边界float s_ranges[] = {0,255};float* ranges[] = {h_ranges, s_ranges};model_hist = cvCreateHist(2,//生成HS二维直方图hist_size,CV_HIST_ARRAY,ranges,1);   model_hist_normalized = cvCreateHist(2,   //用来计算归一化的直方图hist_size,CV_HIST_ARRAY,ranges,1);   cvCalcHist(planes, model_hist, 0, 0);   //计算匹配模板的HS直方图cvCopyHist(model_hist, &model_hist_normalized);cvNormalizeHist( model_hist_normalized, 1.0); //对HS直方图进行归一化.//显示匹配模板的HS直方图int scale =10;IplImage* model_hist_img = cvCreateImage( cvSize(h_bins * scale, s_bins * scale), 8, 3); cvZero( model_hist_img);float max_value = 0;cvGetMinMaxHistValue( model_hist, 0, &max_value, 0, 0);for( int h = 0; h< h_bins; h++)for( int s = 0; s< s_bins; s++){float bin_val = cvQueryHistValue_2D( model_hist, h, s);//查询相应序号h,s对应的直方块的值。int intensity = cvRound(bin_val * 255/ max_value); //cvRound, cvFloor, cvCeil 用一种舍入方法将输入浮点数转换成整数.      //cvRound 返回和参数最接近的整数值. //直方图归一化不影响归一化颜色值后直方图的显示cvRectangle( model_hist_img,  cvPoint(h*scale, s* scale), cvPoint((h+1)*scale-1, (s+1)*scale -1), CV_RGB(intensity, intensity, intensity),  //rgb值相等时,呈现的是明亮的灰度 CV_FILLED );}///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////计算反向投影,block反向投影,template匹配cvCalcBackProject(imgsrc_planes, img_backpro, model_hist);  //参数1是输入图像;参数2是输出图像;参数3是直方图。要可视化反向投影结果,则不能用归一化直方图, 因为结果图像中的值就是hist相应bin的值cvCalcBackProjectPatch( imgsrc_planes, img_block_backpro, patch_size, model_hist_normalized, CV_COMP_CHISQR, 1);  //CHISQR方法中,低分匹配度高cvMatchTemplate( imgsrc, imgmodel, img_template, CV_TM_CCOEFF_NORMED); //CCOEFF方法,最大值表示最佳匹配//cvMatchTemplate是模板匹配,通过在输入图像上滑动模板图像块对实际的图像块和输入图像进行匹配,比如要在一堆图像中寻找指定人脸,就可以利用此算法在图像中找到此人脸的最佳匹配,确定相似度。//用cvMinMaxLoc() 找到block反向投影和模板匹配中的最佳匹配位置,并处标记圆形CvPoint min_loc_block, max_loc_templ;cvMinMaxLoc(img_block_backpro, 0, 0, &min_loc_block, 0, 0);  //block反向投影,CHISQR的最小值的位置cvMinMaxLoc(img_template, 0, 0, 0, &max_loc_templ, 0);        //CCOEFF方法,最大值表示最佳匹配,所以此处是找最大值的位置//标记极值点cvCircle(img_block_backpro, min_loc_block, 30, CV_RGB(0,255,0));  //画绿色的圆cvCircle(img_template, max_loc_templ, 30, CV_RGB(255,0,0));  //画红色的圆cvCircle(imgsrc,   //在原图像中标记找到的目标物体cvPoint(max_loc_templ.x + patch_size.width /2, max_loc_templ.y + patch_size.height/2),   //目标点再原图像中的位置40,CV_RGB(0,255,0));cvShowImage(wd_imgsrc, imgsrc);//原图像cvShowImage("模版图像",  imgmodel);//模版图像cvShowImage(wd_model_hist, model_hist_img);//模版图像的直方图cvShowImage(wd_template, img_template);//模版匹配cvShowImage(wd_backpro, img_backpro);//反向投影cvShowImage(wd_block_backpro, img_block_backpro);//块反向投影cvWaitKey();cvReleaseImage(&imgsrc);cvReleaseImage(&model_hist_img);cvDestroyAllWindows();   return 0;  }  




解释一下:(1)下面三张图的匹配结果中,手上都有空洞,原因应该就是原图像中手的颜色不一样,仔细观察发现,原图像中手的颜色有红有白,并且有暗亮之分。
                    (2)匹配结果正确。block反向投影匹配结果最黑的部分和模版匹配最亮的部分为匹配点。



0 0
原创粉丝点击