首先你要知道这是PAMI 2003的一篇文章,非常经典的哦,Mean Shift: A Robust Approach Toward Feature Space Analysis。当然原文有17页,都是一些复杂的公式。。。。。
Mean shift主要用在图像平滑和图像分割(那个跟踪我现在还不清楚),先介绍一下平滑的原理:
输入是一个5维的空间,2维的(x,y)地理坐标,3维的(L,u,v)的颜色空间坐标,当然你原理也可以改写成rgb色彩空间或者是纹理特征空间。
先介绍一下核函数,有uniform的,也有高斯的核函数,不管是哪个的,其基本思想如下:简单的平滑算法用一个模板平均一下,对所有的像素,利用周围的像素平均一下就完事了,
这个mean shift的是基于概率密度分布来的,而且是一种无参的取样。有参的取样就是假设所有的样本服从一个有参数的概率分布函数,比如说泊松分布,正态分布等等,高中生都知道概率公式里面是有参数的,在说一下特征空间是一个5维的空间,距离用欧几里德空间就可以了,至少代码里就是这样实现的,而本文的无参取样是这样的:在特征空间里有3维的窗口(想象一下2维空间的窗口),对于一个特征空间的点,对应一个5维的向量,可以计算该点的一个密度函数,如果是有参的直接带入该点的坐标就可以求出概率密度了,基于窗函数的思想就是考虑它邻近窗口里的点对它的贡献, 它假设密度会往密集一点的地方转移,算出移动之后的一个5维坐标,该坐标并会稳定,迭代了几次之后,稳定的地方是modes。这样每一个像素点都对应一个这么一个modes,用该点的后3维的值就是平滑的结果了,当然在算每个点的时候,有些地方可能重复计算了,有兴趣的化你可以参考一下源代码,确实是可以优化的。总结一下mean shift的平滑原理就是在特征空间中向密度更高的地方shift(转移)。
其次是怎么利用mean shift分割图像
先对图像进行平滑,
第2步利用平滑结果建立区域邻接矩阵或者区域邻接链表,就是在特征空间比较近的二间在2维的图像平面也比较接近的像素算成一个区域,这样就对应一个区域的邻接链表,记录每个像素点的label值。当然代码中有一个传递凸胞的计算,合并2个表面张力很接近的相邻区域,这个我还没想怎么明白,希望比较清楚的朋友讲一讲。最后还有一个合并面积较小的区域的操作,一个区域不是对应一个modes值嘛,在待合并的较小的那个区域中,寻找所有的邻接区域,找到距离最小的那个区域,合并到那个区域就ok了。
void msImageProcessor::Filter(int sigmaS, float sigmaR, SpeedUpLevel speedUpLevel)这个是平滑操作,sigmaS是2维的平面窗口的窗函数,sigmaR是颜色空间的窗函数,最后一个参数表示是否加速算法。
void msImageProcessor::FuseRegions(float sigmaS, int minRegion)这个就是合并较小区域的一个函数。
void msImageProcessor::Segment(int sigmaS, float sigmaR, int minRegion, SpeedUpLevel speedUpLevel)这个是分割函数,里面包括了平滑功能。再详细的我也不说了。。。。。
最后是怎么调用问题:void CImageProcessing::mydebug()
{
int x,y;
int width_ = imageWidth;
int height_ = imageHeight;
unsigned char *tmp = new unsigned char[width_ * height_ * 3];
unsigned char *dst = tmp;
for (x = 0;x < imageHeight; x ++)
for(y = 0;y < imageWidth; y++)
{
//Color tmp = (*imageData_RGB)(y, x);
//uchar * data = &CV_IMAGE_ELEM(ip,uchar,x,y*3) ;
// *(dst++) = data[2] ;
// *(dst++) = data[1] ;
// *(dst++) = data[0] ;
*(dst++) = (*imageData_RGB)(y, x).channel[0];
*(dst++) = (*imageData_RGB)(y, x).channel[1];
*(dst++) = (*imageData_RGB)(y, x).channel[2];
}
cbgImage_->SetImageFromRGB( tmp, width_, height_, true);
delete []tmp;
msImageProcessor *iProc = new msImageProcessor();
iProc->DefineImage(cbgImage_->im_, COLOR, height_, width_);
iProc->SetSpeedThreshold(0.1);
iProc->Segment(5,8,10,NO_SPEEDUP);
// iProc->Filter(5,8,NO_SPEEDUP);
// iProc->FuseRegions(mWinSize,mAreaSize);//°ë¾¶ºÍ×îСÇøÓòÃæ»ý
} 至于怎么调试编译我看我是说不清楚了。。。。。。。。。。。。。。。。。。。。。。