一句話一幅圖理解meanshift算法:
對於集合中的每一個元素,對它執行下面的操作:把該元素移動到它鄰域中所有元素的特征值的均值的位置,不斷重復直到收斂。
准確的說,不是真正移動元素,而是把該元素與它的收斂位置的元素標記為同一類。對於圖像來說,所有元素程矩陣排列,特征值便是像素的灰度值。
Meanshift的這種思想可以應用於目標跟蹤、圖像平滑、邊緣檢測、聚類等,是一種適應性很好的算法,缺點是速度非常慢。
本文以圖像平滑為例對其說明
從網上找代碼不如自己動手寫。說明一下兩個參數的含義,hs和hr是核函數的窗口大小,hs是距離核函數,控制子窗口的大小,同時也影響計算速度。hr是顏色核函數,是顏色差值的閾值,maxiter是最大迭代次數。轉載請注明出處,謝謝。本文算法只是用作實驗之用,沒有進行優化,計算時會有重復計算的地方,速度非常慢,且只支持3通道圖像。
1 void MyTreasureBox::MeanShiftSmooth(const IplImage* src, IplImage* dst, int hs, int hr, int maxIter) 2 { 3 if(!src)return ; 4 5 IplImage* srcLUV = cvCreateImage( cvGetSize( src ), src->depth, src->nChannels ); 6 IplImage* dstLUV = cvCreateImage( cvGetSize( src ), src->depth, src->nChannels ); 7 8 cvCvtColor( src, srcLUV, CV_RGB2Luv); 9 cvCopy( srcLUV, dstLUV ); 10 11 int widthstep = srcLUV->widthStep; 12 int channel = srcLUV->nChannels; 13 14 for( int y = 0; y<src->height; y++ ) 15 { 16 for( int x = 0; x<src->width; x++ ) 17 { 18 uchar L = (uchar)srcLUV->imageData[y *widthstep + x *channel]; 19 uchar U = (uchar)srcLUV->imageData[y *widthstep + x *channel + 1]; 20 uchar V = (uchar)srcLUV->imageData[y *widthstep + x *channel + 2]; 21 int xx = x; 22 int yy = y; 23 24 int nIter = 0; 25 int count, sumL, sumu, sumv, sumx, sumy; 26 27 while(nIter < maxIter) 28 { 29 count = 0; 30 sumL = sumu = sumv = 0; 31 sumx = sumy = 0; 32 33 for( int m = yy - hs; m <= yy + hs; m++ ) 34 { 35 for( int n = xx - hs; n <= xx + hs; n++ ) 36 { 37 if(m >= 0 && m < src->height && n >= 0 && n < src->width) 38 { 39 uchar l = (uchar)srcLUV->imageData[m *widthstep + n *channel]; 40 uchar u = (uchar)srcLUV->imageData[m *widthstep + n *channel + 1]; 41 uchar v = (uchar)srcLUV->imageData[m *widthstep + n *channel + 2]; 42 43 double dist = sqrt( (double)((L - l)^2 + (U - u)^2 + (V - v)^2) ); 44 if( dist < hr ) 45 { 46 count++; 47 sumL += l; 48 sumu += u; 49 sumv += v; 50 sumx += n; 51 sumy += m; 52 } 53 } 54 } 55 } 56 if(count == 0)break; 57 L = sumL / count; 58 U = sumu / count; 59 V = sumv / count; 60 xx = sumx / count; 61 yy = sumy / count; 62 63 nIter++; 64 } 65 dstLUV->imageData[y *widthstep + x *channel] = L; 66 dstLUV->imageData[y *widthstep + x *channel + 1] = U; 67 dstLUV->imageData[y *widthstep + x *channel + 2] = V; 68 } 69 } 70 71 cvCvtColor( dstLUV, dst, CV_Luv2RGB ); 72 cvReleaseImage(&srcLUV); 73 cvReleaseImage(&dstLUV); 74 }
hs和hr的控制可以參閱下圖