影像处理的统计直方图,可以知道一张图片在该色彩空间的数据分布状况,而这边,就要介绍到直方图反向投影的函式,直方图反向投影,也就是将数据分布的状况依照Look-up table的方式对应回去,实际上,这个函式是跟前面介绍到的cvLUT()是一样的,只不过,差别是差异在cvLUT()的第三个自变量改变成CvHistogram数据结构的输入,直方图反向投影,cvCalcBackProject()的第一个自变量是输入单信道IplImage数据结构,第二个自变量是输出单信道IplImage反向投影图形数据结构,第三个自变量是选定要被反向投影的CvHistogram直方图数据结构,而cvCalcBackProject()把前面提到的Look-up table的计算方式包在cvCalcBackProject()函式的底层,因此,它可以整合CvHistogram这个数据结构做更多的应用,下面这个就是修改前面的范例"OpenCV统计应用-CvHistogram直方图数据结构",来做直方图反向投影的程序
灰阶直方图反向投影
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
int HistogramBins = 50 ;
int HistogramBinWidth;
float HistogramRange1[ 2 ]={ 0 , 255 };
float *HistogramRange[ 1 ]={ & HistogramRange1[ 0 ]};
CvPoint Point1;
CvPoint Point2;
int main()
{
IplImage *GrayImage1;
IplImage *Image1;
IplImage *Image2;
IplImage *BackProjectImage;
CvHistogram *Histogram1;
IplImage *HistogramImage1;
Image1=cvLoadImage( "Riverbank.jpg" , 1 );
Image2=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U, 3 );
GrayImage1=cvLoadImage( "Riverbank.jpg" , 0 );
BackProjectImage=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U, 1 );
Histogram1 = cvCreateHist( 1 , & HistogramBins,CV_HIST_ARRAY,HistogramRange);
HistogramImage1 = cvCreateImage(cvSize( 256 , 300 ), 8 , 3 );
cvSetZero(HistogramImage1);
HistogramImage1->origin= 1 ;
HistogramBinWidth= 256 /HistogramBins;
cvCalcHist( & GrayImage1,Histogram1);
cvNormalizeHist(Histogram1, 5000 );
cvThreshHist(Histogram1, 50 );
cvCalcBackProject( & GrayImage1,BackProjectImage,Histogram1);
cvCopy(Image1,Image2,BackProjectImage);
for(int i= 0 ;i<HistogramBins;i++)
{
printf( "%f\n" ,cvQueryHistValue_1D(Histogram1,i));
Point1=cvPoint(i*HistogramBinWidth, 0 );
Point2=cvPoint((i+ 1 )*HistogramBinWidth,(int) cvQueryHistValue_1D(Histogram1,i));
cvRectangle(HistogramImage1,Point1,Point2,CV_RGB( 127 , 127 , 127 ));
}
cvNamedWindow( "Histogram1" , 1 );
cvNamedWindow( "Riverbank" , 1 );
cvNamedWindow( "Back Project RiverBank" , 1 );
cvShowImage( "Riverbank" ,Image1);
cvShowImage( "Back Project RiverBank" ,Image2);
cvShowImage( "Histogram1" ,HistogramImage1);
cvWaitKey( 0 );
}
执行结果:
![](https://img-my.csdn.net/uploads/201211/04/1352000963_7215.jpg)
这边就是拿前面灰阶去除较小直方图区块的程序代码做修改,然后将前面去除最小区块的部份,对应到彩色的图片去了,显示的结果会是,只要是影像里面灰阶值分布数量比较少的数据,全部都被对应成黑色的像素,也就是全部都变成0,而cvCalcBackProject(),就跟cvLUT()一样直接拿直方图的数据去对应,假设一个直方图从头开始的数据为254,129,80,70....那么只要是图片内像素值为1的数据就会对应到254,1的图片里面像素值的数据就会直接变成254,像素值为2的就会对应到129,2的数据就会直接变成129,以此类推,因此,用cvThreshHist()去除小于50的直方图区段,让小于50的全部归0,再来,对他做一个图片的反向投影,所对应出来的结果虽然不是0或255,可是它却可以直接拿来当做是屏蔽,也就是说,直接拿来给cvCopy()来做对应,因此,反向投影的结果就出来啦,在屏蔽的部份就要参考"数据结构操作与运算-图形的Mask屏蔽实作",而这段程序代码则是用到"OpenCV统计应用-CvHistogram数据结构操作"里面的部份.
在OpenCV Documentation的部份有提到cvCalcBackProject()可以对HSV色彩空间的Hue做反向投影,到底是怎么实作出来呢?在OpenCV的Sample Code里面有一个camshift.c的程序,就是用到这个反向投影的函式,而它的反向投影的简单范例,原理就如下所示
HSV色彩空间反向投影
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
IplImage *Image1,*Image2;
IplImage *HSVImage;
IplImage *HueImage;
IplImage *BackProjectHueImage,*BackProjectImage;
CvHistogram *Histogram1;
IplImage *HistogramImage1;
CvPoint Point1,Point2;
int HueValue= 0 ;
int HistogramBins = 180 ;
int HistogramBinWidth;
float HistogramRange1[ 2 ]={ 0 , 180 };
float *HistogramRange[ 1 ]={ & HistogramRange1[ 0 ]};
void onTrackbar(int position);
int main()
{
Image1 =cvLoadImage( "Riverbank.jpg" , 1 );
HSVImage = cvCreateImage( cvGetSize(Image1), 8 , 3 );
HueImage = cvCreateImage( cvGetSize(Image1), 8 , 1 );
BackProjectHueImage = cvCreateImage( cvGetSize(Image1), 8 , 1 );
BackProjectImage = cvCreateImage( cvGetSize(Image1), 8 , 3 );
Histogram1 = cvCreateHist( 1 , & HistogramBins,CV_HIST_ARRAY,HistogramRange);
HistogramImage1 = cvCreateImage(cvSize( 180 , 300 ), 8 , 3 );
HistogramImage1->origin= 1 ;
cvCvtColor( Image1, HSVImage, CV_BGR2HSV );
cvSplit(HSVImage,HueImage, 0 , 0 , 0 );
cvCalcHist( & HueImage, Histogram1);
cvNormalizeHist(Histogram1, 5000 );
cvZero( HistogramImage1 );
cvNot(HistogramImage1,HistogramImage1);
HistogramBinWidth = HistogramImage1->width/HistogramBins;
for(int i= 0 ;i<HistogramBins;i++)
{
Point1=cvPoint(i, 0 );
Point2=cvPoint(i,(int)cvQueryHistValue_1D(Histogram1,i));
printf( "%d\n" ,(int)cvQueryHistValue_1D(Histogram1,i));
cvLine(HistogramImage1,Point1,Point2,CV_RGB( 127 , 127 , 127 ));
}
cvNamedWindow( "Riverbank" , 1 );
cvNamedWindow( "Hue Histogram" , 1 );
cvCreateTrackbar( "Hue Thresh" , "Riverbank" , & HueValue, 250 ,onTrackbar);
cvShowImage( "Riverbank" ,Image1);
cvShowImage( "Hue Histogram" ,HistogramImage1);
cvWaitKey( 0 );
}
void onTrackbar(int position)
{
IplImage *Image2=cvCreateImage( cvGetSize(Image1), 8 , 3 );
CvHistogram *Histogram2= cvCreateHist( 1 , & HistogramBins,CV_HIST_ARRAY,HistogramRange);
cvCopyHist(Histogram1, & Histogram2);
cvThreshHist(Histogram2,position);
cvCalcBackProject( & HueImage, BackProjectHueImage, Histogram2);
cvCopy(Image1,Image2,BackProjectHueImage);
cvZero( HistogramImage1 );
cvNot(HistogramImage1,HistogramImage1);
HistogramBinWidth = HistogramImage1->width/HistogramBins;
for(int i= 0 ;i<HistogramBins;i++)
{
Point1=cvPoint(i, 0 );
Point2=cvPoint(i,(int)cvQueryHistValue_1D(Histogram2,i));
printf( "%d\n" ,(int)cvQueryHistValue_1D(Histogram2,i));
cvLine(HistogramImage1,Point1,Point2,CV_RGB( 127 , 127 , 127 ));
}
cvShowImage( "Hue Histogram" ,HistogramImage1);
cvShowImage( "Riverbank" ,Image2);
}
执行结果:
![](https://img-my.csdn.net/uploads/201211/04/1352001016_3956.jpg)
在OpenCV里面,HSV色彩空间,色调(Hue)值的范围在0~180,饱和度(Saturation)的范围在0~255,亮度(Value)的范围在0~255,而这边就只取色调(Hue)值在做反向投影,开启了一个Track bar的功能,并且利用cvCvtColor()将BGR的色彩空间转换成HSV,并且用cvSplit()信道分割取Hue信道的图片,计算Hue值的直方图,在onTrackbar()的部份,则是用Trackbar来调整去除cvThreshHist()的最小区块的临界值,去除之后在反向投影到原始的Hue的图片,在由反向投影的结果当做屏蔽,直接跟彩色图片做对应.
而cvCalcBackProject()不单单只有这样的功能,它可以对多维度空间的色彩直方图做对应,cvCalcBackProject()提供了一个当CvHistogram数据结构维度为3的时候的一个反向投影,下面的这个例子就以HSV的色彩空间为例,建构一个三维的CvHistogram数据结构
HSV三维直方图反向投影
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
IplImage *Image1,*Image2;
IplImage *HSV;
IplImage *HueImage,*SaturationImage,*ValueImage;
IplImage *ImageArray[3];
IplImage *BackProjectImage;
CvHistogram *Histogram1;
IplImage *HistogramImage1;
CvPoint Point1,Point2;
int HueValue= 0 ;
int HistogramBins[ 3 ] ={ 180 , 256 , 256 };
int HistogramBinWidth;
float HistogramRange1[ 6 ]={ 0 , 180 , 0 , 255 , 0 , 255 };
float *HistogramRange[ 3 ]={ & HistogramRange1[ 0 ], & HistogramRange1[ 2 ], & HistogramRange1[ 4 ]};
void onTrackbar(int position);
int main()
{
Image1 =cvLoadImage( "Riverbank.jpg" , 1 );
HSV = cvCreateImage( cvGetSize(Image1), 8 , 3 );
HueImage = cvCreateImage( cvGetSize(Image1), 8 , 1 );
SaturationImage = cvCreateImage( cvGetSize(Image1), 8 , 1 );
ValueImage = cvCreateImage( cvGetSize(Image1), 8 , 1 );
ImageArray[ 0 ]=HueImage;
ImageArray[ 1 ]=SaturationImage;
ImageArray[ 2 ]=ValueImage;
BackProjectImage = cvCreateImage( cvGetSize(Image1), 8 , 3 );
Histogram1 = cvCreateHist( 3 ,HistogramBins,CV_HIST_SPARSE,HistogramRange);
cvCvtColor( Image1, HSV, CV_BGR2HSV );
cvSplit(HSV,HueImage,SaturationImage,ValueImage, 0 );
cvCalcHist( ImageArray, Histogram1);
cvNamedWindow( "Riverbank" , 1 );
cvCreateTrackbar( "Hue Thresh" , "Riverbank" , & HueValue, 200 ,onTrackbar);
cvShowImage( "Riverbank" ,Image1);
cvWaitKey( 0 );
}
void onTrackbar(int position)
{
CvHistogram *Histogram2= cvCreateHist( 3 ,HistogramBins,CV_HIST_SPARSE,HistogramRange);
IplImage *Image2=cvCreateImage( cvGetSize(Image1), 8 , 3 );
IplImage *BackProjectImage = cvCreateImage( cvGetSize(Image1), 8 , 1 );
cvCopyHist(Histogram1, & Histogram2);
cvThreshHist(Histogram2,position);
cvCalcBackProject( ImageArray, BackProjectImage, Histogram2);
cvCopy(Image1,Image2,BackProjectImage);
cvShowImage( "Riverbank" ,Image2);
}
执行结果:
![](https://img-my.csdn.net/uploads/201211/04/1352001047_2320.jpg)
在三维空间的作法上面,就要参考到前面"OpenCV统计应用-CvHistogram直方图数据结构"关于三维空间制作的部份,除了用cvCvtColor()将色彩空间转换,用cvSplit()将信道做分割,还要做个图形数组(ImageArray)来让cvCalcHist()这个函式做运算,计算出来的结果为一个CvHistogram的三维空间稀疏矩阵直方图,而在onTrackbar()的部份,cvCalcBackProject()直方图反向投影亦是同样要用ImageArray做输入,而输出则是一个单信道的图形,在稀疏矩阵里面,由于维度为三维,所以他所形成的统计直方图数值都是极小,所以门坎值只要一点点就快要全部都分布了,而这个三维空间的反向投影可以如此建构,是基于Look-up table的功能来实现,只不过他的缺点是,每一个维度的Look-up table范围是0~255,因此如果是像Hue值的范围0~180,它的数值就会被模糊化,也就是数据会被些许位移,但是仍不会影响它出来结果的精确度
在这个直方图反向投影的部份,也可以结合连通成分来做去除某一门坎值的连通分量
cvCalcBackProject()
将统计直方图的分布数据根据Look-up table对应回去,也就是说,当今天CvHistogram数据结构内的数据分布是243,110,0,60...则使用cvCalcBackProject()函式单信道的图片像素值会是,当遇到像素值为1的时候变243,像素值为2的时候变110,依此类推,cvCalcBackProject()直方图反向投影可以根据多维度设计,而cvCalcBackProject()第一个自变量为输入单信道IplImage或CvMat数据结构,第二个自变量为输入单通道反向投影IplImage或CvMat数据结构,第三个自变量为输入CvHistogram数据结构
cvCalcBackProject(输入单信道IplImage或CvMat数据结构,输入单信道反向投影IplImage或CvMat数据结构,输入CvHistogram数据结构)
灰阶直方图反向投影
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
int HistogramBins = 50 ;
int HistogramBinWidth;
float HistogramRange1[ 2 ]={ 0 , 255 };
float *HistogramRange[ 1 ]={ & HistogramRange1[ 0 ]};
CvPoint Point1;
CvPoint Point2;
int main()
{
IplImage *GrayImage1;
IplImage *Image1;
IplImage *Image2;
IplImage *BackProjectImage;
CvHistogram *Histogram1;
IplImage *HistogramImage1;
Image1=cvLoadImage( "Riverbank.jpg" , 1 );
Image2=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U, 3 );
GrayImage1=cvLoadImage( "Riverbank.jpg" , 0 );
BackProjectImage=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U, 1 );
Histogram1 = cvCreateHist( 1 , & HistogramBins,CV_HIST_ARRAY,HistogramRange);
HistogramImage1 = cvCreateImage(cvSize( 256 , 300 ), 8 , 3 );
cvSetZero(HistogramImage1);
HistogramImage1->origin= 1 ;
HistogramBinWidth= 256 /HistogramBins;
cvCalcHist( & GrayImage1,Histogram1);
cvNormalizeHist(Histogram1, 5000 );
cvThreshHist(Histogram1, 50 );
cvCalcBackProject( & GrayImage1,BackProjectImage,Histogram1);
cvCopy(Image1,Image2,BackProjectImage);
for(int i= 0 ;i<HistogramBins;i++)
{
printf( "%f\n" ,cvQueryHistValue_1D(Histogram1,i));
Point1=cvPoint(i*HistogramBinWidth, 0 );
Point2=cvPoint((i+ 1 )*HistogramBinWidth,(int) cvQueryHistValue_1D(Histogram1,i));
cvRectangle(HistogramImage1,Point1,Point2,CV_RGB( 127 , 127 , 127 ));
}
cvNamedWindow( "Histogram1" , 1 );
cvNamedWindow( "Riverbank" , 1 );
cvNamedWindow( "Back Project RiverBank" , 1 );
cvShowImage( "Riverbank" ,Image1);
cvShowImage( "Back Project RiverBank" ,Image2);
cvShowImage( "Histogram1" ,HistogramImage1);
cvWaitKey( 0 );
}
执行结果:
![](https://img-my.csdn.net/uploads/201211/04/1352000963_7215.jpg)
这边就是拿前面灰阶去除较小直方图区块的程序代码做修改,然后将前面去除最小区块的部份,对应到彩色的图片去了,显示的结果会是,只要是影像里面灰阶值分布数量比较少的数据,全部都被对应成黑色的像素,也就是全部都变成0,而cvCalcBackProject(),就跟cvLUT()一样直接拿直方图的数据去对应,假设一个直方图从头开始的数据为254,129,80,70....那么只要是图片内像素值为1的数据就会对应到254,1的图片里面像素值的数据就会直接变成254,像素值为2的就会对应到129,2的数据就会直接变成129,以此类推,因此,用cvThreshHist()去除小于50的直方图区段,让小于50的全部归0,再来,对他做一个图片的反向投影,所对应出来的结果虽然不是0或255,可是它却可以直接拿来当做是屏蔽,也就是说,直接拿来给cvCopy()来做对应,因此,反向投影的结果就出来啦,在屏蔽的部份就要参考"数据结构操作与运算-图形的Mask屏蔽实作",而这段程序代码则是用到"OpenCV统计应用-CvHistogram数据结构操作"里面的部份.
在OpenCV Documentation的部份有提到cvCalcBackProject()可以对HSV色彩空间的Hue做反向投影,到底是怎么实作出来呢?在OpenCV的Sample Code里面有一个camshift.c的程序,就是用到这个反向投影的函式,而它的反向投影的简单范例,原理就如下所示
HSV色彩空间反向投影
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
IplImage *Image1,*Image2;
IplImage *HSVImage;
IplImage *HueImage;
IplImage *BackProjectHueImage,*BackProjectImage;
CvHistogram *Histogram1;
IplImage *HistogramImage1;
CvPoint Point1,Point2;
int HueValue= 0 ;
int HistogramBins = 180 ;
int HistogramBinWidth;
float HistogramRange1[ 2 ]={ 0 , 180 };
float *HistogramRange[ 1 ]={ & HistogramRange1[ 0 ]};
void onTrackbar(int position);
int main()
{
Image1 =cvLoadImage( "Riverbank.jpg" , 1 );
HSVImage = cvCreateImage( cvGetSize(Image1), 8 , 3 );
HueImage = cvCreateImage( cvGetSize(Image1), 8 , 1 );
BackProjectHueImage = cvCreateImage( cvGetSize(Image1), 8 , 1 );
BackProjectImage = cvCreateImage( cvGetSize(Image1), 8 , 3 );
Histogram1 = cvCreateHist( 1 , & HistogramBins,CV_HIST_ARRAY,HistogramRange);
HistogramImage1 = cvCreateImage(cvSize( 180 , 300 ), 8 , 3 );
HistogramImage1->origin= 1 ;
cvCvtColor( Image1, HSVImage, CV_BGR2HSV );
cvSplit(HSVImage,HueImage, 0 , 0 , 0 );
cvCalcHist( & HueImage, Histogram1);
cvNormalizeHist(Histogram1, 5000 );
cvZero( HistogramImage1 );
cvNot(HistogramImage1,HistogramImage1);
HistogramBinWidth = HistogramImage1->width/HistogramBins;
for(int i= 0 ;i<HistogramBins;i++)
{
Point1=cvPoint(i, 0 );
Point2=cvPoint(i,(int)cvQueryHistValue_1D(Histogram1,i));
printf( "%d\n" ,(int)cvQueryHistValue_1D(Histogram1,i));
cvLine(HistogramImage1,Point1,Point2,CV_RGB( 127 , 127 , 127 ));
}
cvNamedWindow( "Riverbank" , 1 );
cvNamedWindow( "Hue Histogram" , 1 );
cvCreateTrackbar( "Hue Thresh" , "Riverbank" , & HueValue, 250 ,onTrackbar);
cvShowImage( "Riverbank" ,Image1);
cvShowImage( "Hue Histogram" ,HistogramImage1);
cvWaitKey( 0 );
}
void onTrackbar(int position)
{
IplImage *Image2=cvCreateImage( cvGetSize(Image1), 8 , 3 );
CvHistogram *Histogram2= cvCreateHist( 1 , & HistogramBins,CV_HIST_ARRAY,HistogramRange);
cvCopyHist(Histogram1, & Histogram2);
cvThreshHist(Histogram2,position);
cvCalcBackProject( & HueImage, BackProjectHueImage, Histogram2);
cvCopy(Image1,Image2,BackProjectHueImage);
cvZero( HistogramImage1 );
cvNot(HistogramImage1,HistogramImage1);
HistogramBinWidth = HistogramImage1->width/HistogramBins;
for(int i= 0 ;i<HistogramBins;i++)
{
Point1=cvPoint(i, 0 );
Point2=cvPoint(i,(int)cvQueryHistValue_1D(Histogram2,i));
printf( "%d\n" ,(int)cvQueryHistValue_1D(Histogram2,i));
cvLine(HistogramImage1,Point1,Point2,CV_RGB( 127 , 127 , 127 ));
}
cvShowImage( "Hue Histogram" ,HistogramImage1);
cvShowImage( "Riverbank" ,Image2);
}
执行结果:
![](https://img-my.csdn.net/uploads/201211/04/1352001016_3956.jpg)
在OpenCV里面,HSV色彩空间,色调(Hue)值的范围在0~180,饱和度(Saturation)的范围在0~255,亮度(Value)的范围在0~255,而这边就只取色调(Hue)值在做反向投影,开启了一个Track bar的功能,并且利用cvCvtColor()将BGR的色彩空间转换成HSV,并且用cvSplit()信道分割取Hue信道的图片,计算Hue值的直方图,在onTrackbar()的部份,则是用Trackbar来调整去除cvThreshHist()的最小区块的临界值,去除之后在反向投影到原始的Hue的图片,在由反向投影的结果当做屏蔽,直接跟彩色图片做对应.
而cvCalcBackProject()不单单只有这样的功能,它可以对多维度空间的色彩直方图做对应,cvCalcBackProject()提供了一个当CvHistogram数据结构维度为3的时候的一个反向投影,下面的这个例子就以HSV的色彩空间为例,建构一个三维的CvHistogram数据结构
HSV三维直方图反向投影
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
IplImage *Image1,*Image2;
IplImage *HSV;
IplImage *HueImage,*SaturationImage,*ValueImage;
IplImage *ImageArray[3];
IplImage *BackProjectImage;
CvHistogram *Histogram1;
IplImage *HistogramImage1;
CvPoint Point1,Point2;
int HueValue= 0 ;
int HistogramBins[ 3 ] ={ 180 , 256 , 256 };
int HistogramBinWidth;
float HistogramRange1[ 6 ]={ 0 , 180 , 0 , 255 , 0 , 255 };
float *HistogramRange[ 3 ]={ & HistogramRange1[ 0 ], & HistogramRange1[ 2 ], & HistogramRange1[ 4 ]};
void onTrackbar(int position);
int main()
{
Image1 =cvLoadImage( "Riverbank.jpg" , 1 );
HSV = cvCreateImage( cvGetSize(Image1), 8 , 3 );
HueImage = cvCreateImage( cvGetSize(Image1), 8 , 1 );
SaturationImage = cvCreateImage( cvGetSize(Image1), 8 , 1 );
ValueImage = cvCreateImage( cvGetSize(Image1), 8 , 1 );
ImageArray[ 0 ]=HueImage;
ImageArray[ 1 ]=SaturationImage;
ImageArray[ 2 ]=ValueImage;
BackProjectImage = cvCreateImage( cvGetSize(Image1), 8 , 3 );
Histogram1 = cvCreateHist( 3 ,HistogramBins,CV_HIST_SPARSE,HistogramRange);
cvCvtColor( Image1, HSV, CV_BGR2HSV );
cvSplit(HSV,HueImage,SaturationImage,ValueImage, 0 );
cvCalcHist( ImageArray, Histogram1);
cvNamedWindow( "Riverbank" , 1 );
cvCreateTrackbar( "Hue Thresh" , "Riverbank" , & HueValue, 200 ,onTrackbar);
cvShowImage( "Riverbank" ,Image1);
cvWaitKey( 0 );
}
void onTrackbar(int position)
{
CvHistogram *Histogram2= cvCreateHist( 3 ,HistogramBins,CV_HIST_SPARSE,HistogramRange);
IplImage *Image2=cvCreateImage( cvGetSize(Image1), 8 , 3 );
IplImage *BackProjectImage = cvCreateImage( cvGetSize(Image1), 8 , 1 );
cvCopyHist(Histogram1, & Histogram2);
cvThreshHist(Histogram2,position);
cvCalcBackProject( ImageArray, BackProjectImage, Histogram2);
cvCopy(Image1,Image2,BackProjectImage);
cvShowImage( "Riverbank" ,Image2);
}
执行结果:
![](https://img-my.csdn.net/uploads/201211/04/1352001047_2320.jpg)
在三维空间的作法上面,就要参考到前面"OpenCV统计应用-CvHistogram直方图数据结构"关于三维空间制作的部份,除了用cvCvtColor()将色彩空间转换,用cvSplit()将信道做分割,还要做个图形数组(ImageArray)来让cvCalcHist()这个函式做运算,计算出来的结果为一个CvHistogram的三维空间稀疏矩阵直方图,而在onTrackbar()的部份,cvCalcBackProject()直方图反向投影亦是同样要用ImageArray做输入,而输出则是一个单信道的图形,在稀疏矩阵里面,由于维度为三维,所以他所形成的统计直方图数值都是极小,所以门坎值只要一点点就快要全部都分布了,而这个三维空间的反向投影可以如此建构,是基于Look-up table的功能来实现,只不过他的缺点是,每一个维度的Look-up table范围是0~255,因此如果是像Hue值的范围0~180,它的数值就会被模糊化,也就是数据会被些许位移,但是仍不会影响它出来结果的精确度
在这个直方图反向投影的部份,也可以结合连通成分来做去除某一门坎值的连通分量
cvCalcBackProject()
将统计直方图的分布数据根据Look-up table对应回去,也就是说,当今天CvHistogram数据结构内的数据分布是243,110,0,60...则使用cvCalcBackProject()函式单信道的图片像素值会是,当遇到像素值为1的时候变243,像素值为2的时候变110,依此类推,cvCalcBackProject()直方图反向投影可以根据多维度设计,而cvCalcBackProject()第一个自变量为输入单信道IplImage或CvMat数据结构,第二个自变量为输入单通道反向投影IplImage或CvMat数据结构,第三个自变量为输入CvHistogram数据结构
cvCalcBackProject(输入单信道IplImage或CvMat数据结构,输入单信道反向投影IplImage或CvMat数据结构,输入CvHistogram数据结构)