原文:http://ycwangshuai2008.blog.163.com/blog/static/50669331200982294220688/
“连续自适应均值偏移”算法,即Continuously Adaptive Mean-Shift Algorithm,简称CAMShift算法。它是一种计算快速的颜色跟踪算法,适用于跟踪颜色特定的目标,对于人脸跟踪来说,目标颜色即为肤色。
CAMShifft算法主要通过视频图像中运动物体的颜色信息来达到跟踪的目的。我把这个算法分解成三个部分,以便于理解:
? Back Projection计算;
? Mean Shift算法;
? CamShift算法。
****************************************************************************************
一、Back Projection:反向投影
肤色在颜色空间的分布相当集中,但照明强度和人种的不同对它有很大影响。算法采用HSV颜色空间,使目标颜色与亮度分离,以减少光照的影响。把每个像素从RGB颜色空间转化到HSV颜色空间,统计H分量的直方图,并做归一化处理,可得肤色在H空间的概率分布f(H)。
为利用目标的空间信息,CAMShift采用反向投影技术把目标模型和候选区域的概率分布映射到观测图像。反向投影就是把观测图像中每个像素值的H分量用肤色直方图中对应的值代替,即对每个像素进行H→f(H)映射,输出图像即称为观测图像的颜色概率分布图像(PDI)。这时,PDI中每一点的值就代表该像素在肤色统计直方图中的出现概率。
计算Back Projection的步骤是这样的:
1. 计算被跟踪目标的色彩直方图。在各种色彩空间中,只有HSI空间(或与HSI类似的色彩空间)中的H(hue:色调)分量可以表示颜色信息。所以在具体的计算过程中,首先将其他的色彩空间的值转化到HSI空间,然后将其中的H分量做1D直方图计算。
2. 根据获得的色彩直方图将原始图像转化成色彩概率分布图像,这个过程就被称作"Back Projection"。在OpenCV中的直方图函数中,包含Back Projection的函数。
下面给出计算Back Projection的OpenCV代码。
1.准备一张包含被跟踪目标的图片,将色彩空间转化到HSI空间,获得其中的H分量:
IplImage* target=cvLoadImage("target.bmp",-1); //装载图片
IplImage* target_hsv=cvCreateImage( cvGetSize(target), IPL_DEPTH_8U, 3 );
IplImage* target_hue=cvCreateImage( cvGetSize(target), IPL_DEPTH_8U, 3 );
cvCvtColor(target,target_hsv,CV_BGR2HSV); //转化到HSV空间
cvSplit( target_hsv, target_hue, NULL, NULL, NULL ); //获得H分量
2.计算H分量的直方图,即1D直方图:
IplImage* h_plane=cvCreateImage( cvGetSize(target_hsv),IPL_DEPTH_8U,1 );
int hist_size[]={255}; //将H分量的值量化到[0,255]
float* ranges[]={ {0,360} }; //H分量的取值范围是[0,360)
CvHistogram* hist=cvCreateHist(1, hist_size, ranges, 1);
cvCalcHist(&target_hue, hist, 0, NULL);
在这里需要考虑H分量的取值范围的问题,H分量的取值范围是[0,360),这个取值范围的值不能用一个byte来表示,为了能用一个byte表示,需要将H值做适当的量化处理,在这里我们将H分量的范围量化到[0,255].
3.计算Back Projection:
IplImage* rawImage;
//----------------------------------------------
//get from video frame,unsigned byte,on
//----------------------------------------------
IplImage* result=cvCreateImage(cvGetSize(rawImage),IPL_DEPTH_8U,1);
cvCalcBackProject(&rawImage,result,hist);
result即为我们需要的。
【算法分析】
用在cvCalcBackProject处理中的模板是目标图像色调(HUE)的直方图,而直方图可以看作是一种概率分布图。在处理前,目标图像中的每一个象素的值描述的在这一点的颜色信息,而处理后,图像中每一个象素的值就变成了这个颜色信息出现在此处的可能性的一种离散化的度量,出现的可能性大,象素的值就大,反之则小。这样就为后面的匹配和跟踪提供了线索。
****************************************************************************************
二、Mean Shift算法
在讨论Mean Shift算法之前,首先讨论在2D概率分布图像中,如何计算某个区域的重心(Mass Center)的问题,重心可以通过以下公式来计算:
1.计算区域内0阶矩
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
M00+=I(i,j)
2.区域内1阶矩:
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
{
M10+=i*I(i,j);
M01+=j*I(i,j);
}
3.则Mass Center为:
Xc=M10/M00; Yc=M01/M00
接下来,讨论Mean Shift算法的具体步骤,Mean Shift算法可以分为以下4步:
1.选择窗的大小和初始位置.
2.计算此时窗口内的Mass Center.
3.调整窗口的中心到Mass Center.
4.重复2和3,直到窗口中心"会聚",即每次窗口移动的距离小于一定的阈值。
在OpenCV中,提供Mean Shift算法的函数。
附:图像的阶矩的概念:
0阶:M_00=∑∑I(i,j)
1阶:M_10=i*∑∑I(i,j)
M_01=j*∑∑I(i,j)
2阶:M_20=i*i*∑∑I(i,j)
M_02=j*j*∑∑I(i,j) ,其中I(i,j) 为像素点值。
****************************************************************************************
三、CAMShift算法
将MeanShift算法扩展到连续图像序列(例如:视频图像序列),这样就形成了CAMShift算法。它的基本思想是对视频图像的所有帧作MeanShift运算,并将上一帧的结果(即搜索窗口的中心和大小)作为下一帧MeanShift算法的搜索窗口的初始值,如此迭代下去,就可以实现对目标的跟踪。整个算法的具体步骤:
1:将整个图像设为搜寻区域。
2:初始化搜索窗口的大小和位置。
3:计算搜索窗口内的彩色概率分布,此区域的大小比搜索窗口要稍微大一点。
4:运行MeanShift。获得搜索窗口新的位置和大小。
5:在下一帧视频图像中,用3获得的值初始化搜索窗口的位置和大小。跳转到3继续运行。
在OpenCV中,有实现CamShift算法的函数。