機器學習的研究方向主要分為三大類:聚類,分類與回歸。
MeanShift作為聚類方法之一,在視覺領域有着廣泛的應用,尤其是作為深度學習回歸后的后處理模塊而存在着。
接下來,我們先介紹下基本功能流程,然后會用代碼的形式來分析。
一、算法原理:
MeanShift,顧名思義,由Mean(均值)和shift(偏移)組成。也就是有一個點x,周圍有很多點xi,我們計算點x移動到每個點所需要的偏移量之和,求平均,就得到平均偏移量。該偏移量包含大小和方向 ,方向就是周圍分布密集的方向。然后點x往平均偏移量方向移動,再以此為新起點,不斷迭代直到滿足一定條件結束。

中心點就是我們上面所說的
周圍的小紅點就是
黃色的箭頭就是我們求解得到的平均偏移向量。那么圖中“大圓圈”是什么東西呢?我們上面所說的周圍的點
周圍是個什么概念?總的有個東西來限制一下吧。那個“圓圈”就是我們的限制條件,或者說在圖像處理中,就是我們搜索迭代時的窗口大小。
步驟1、首先設定起始點 ,我們說了,是球,所以有半徑 , 所有在球內的點就是 , 黑色箭頭就是我們計算出來的向量 , 將所有的向量 進行求和計算平均就得到我們的meanshift 向量,也就是圖中黃色的向量。
接着,再以meanshift向量的重點為圓心,再做一個高維的球,如下圖所示,重復上面的步驟,最終就可以收斂到點的分布中密度最大的地方

最后得到結果如下:

通過在數據集中尋找被低密度區域分離的高密度區域,將分離出的高密度區域作為一個獨立的類別。
優點:可自動決定類別的數目。
二、數學推導
給定d維空間Rd的n個樣本點 ,i=1,…,n,在空間中任選一點x,那么 meanshift 向量的基本定義如下:

其中
是一個半徑為
的高維度區域。定義如下:

表示在這n個樣本點xi中,有k個點落入
區域中.
然后,我們對meanshift向量進行升級,加入核函數(比如高斯核),則meanshift算法變為:

高斯核函數是一種應用廣泛的核函數:
![]()
其中h為bandwidth 帶寬,不同帶寬的核函數形式也不一樣
由上圖可以看到,橫坐標指的是兩變量之間的距離。距離越近(接近於0)則函數值越大,否則越小。h越大,相同距離的情況下 函數值會越小。因此我們可以選取適當的h值,得到滿足上述要求的那種權重(兩變量距離越近,得到權重越大),故經過核函數改進后的均值漂移為:
核函數K():h為半徑,
為單位密度,要使得上式f得到最大,最容易想到的就是對上式進行求導,的確meanshift就是對上式進行求導.

令
, 則我們可以得到:

由於我們使用的是高斯核,所以第一項等於

第二項就相當於一個meanshift向量的式子:

則上述公式可以表示為:

圖解公式的結構如下:

當然,我們求得meanshift向量的時候,其密度最大的地方也就是極值點的地方,此時梯度為0,也就是
,當且僅當
的時候成立,此時我們就可以得到新的原點坐標:

函數推導,參考自鏈接:https://blog.csdn.net/csdnforyou/article/details/81161840
三、算法步驟:
1)在未被標記的數據點中隨機選擇一個點作為起始中心點center;
2)找出以center為中心半徑為radius的區域中出現的所有數據點,認為這些點同屬於一個聚類C,同時在該聚類中記錄數據點出現的次數加1;
3)以center為中心點,計算從center開始到集合M中每個元素的向量,將這些向量相加,得到向量shift;
4)center=center+shift,即center沿着shift方向移動,移動距離為||shift||;
5)重復步驟2,3,4,直到shift很小,記得此時的center。注意,這個迭代過程中遇到的點都應該歸類到簇C;
6)如果收斂時當前簇C的center與其它已經存在的簇C2中心的距離小於閾值,那么把C2與C合並,數據點出現次數也對應合並。否則把C作為新的聚類;
7)重復1,2,3,4,5直到所有點都被標記為已訪問;
8)分類:根據每個類,對每個點的訪問頻率,取訪問頻率最大的那個類,作為當前點集的所屬類。
四、代碼流程:
from sklearn.cluster import MeanShift @staticmethod def _cluster(prediction, bandwidth): ms = MeanShift(bandwidth, bin_seeding=True) # log.info('開始Mean shift聚類 ...') tic = time.time() try: ms.fit(prediction) except ValueError as err: log.error(err) return 0, [], [] # log.info('Mean Shift耗時: {:.5f}s'.format(time.time() - tic)) labels = ms.labels_ cluster_centers = ms.cluster_centers_ num_clusters = cluster_centers.shape[0] # log.info('聚類簇個數為: {:d}'.format(num_clusters)) return num_clusters, labels, cluster_centers
五、場景應用
5.1 目標跟蹤
opencv中已經有庫函數:int cvMeanShift(const CvArr* prob_image,CvRect window,CvTermCriteria criteria,CvConnectedComp* comp )
輸入參數需是反向投影圖(反向投影圖是用輸入圖像的某一位置上像素值(多維或灰度)對應在直方圖的一個bin上的值來代替該像素值,所以得到的反向投影圖是單通的。用統計學術語,輸出圖像象素點的值是觀測數組在某個分布(直方圖)下的概率),舉例:
1)度圖像如下
Image=[0 1 2 3
4 5 6 7
8 9 10 11
8 9 14 15]
2)該灰度圖的直方圖為(bin指定的區間為[0,3),[4,7),[8,11),[12,16))
Histogram= [4 4 6 2]
3)反向投影圖
Back_Projection=[4 4 4 4
4 4 4 4
6 6 6 6
6 6 2 2]
例如位置(0,0)上的像素值為0,對應的bin為[0,3),所以反向直方圖在該位置上的值這個bin的值4。其實就是一張圖像的像素密度分布圖.
meanshift算法本身就是依靠密度分布進行工作的
全自動跟蹤思路:輸入視頻,對運動物體進行跟蹤。
第一步:運用運動檢測算法將運動的物體與背景分割開來。
第二步:提取運動物體的輪廓,並從原圖中獲取運動圖像的信息。
第三步:對這個信息進行反向投影,獲取反向投影圖。
第四步:根據反向投影圖和物體的輪廓(也就是輸入的方框)進行meanshift迭代,由於它是向重心移動,即向反向投影圖中概率大的地方移動,所以始終會移動到物體上。
第五步:然后下一幀圖像時用上一幀輸出的方框來迭代即可。
meanShift算法用於視頻目標跟蹤時,其實就是采用目標的顏色直方圖作為搜索特征,通過不斷迭代meanShift向量使得算法收斂於目標的真實位置,從而達到跟蹤的目的。
meanshift優勢:
(1)計算量不大,在目標區域已知情況下可以做到實時跟蹤;
(2)采用核函數直方圖模型,對邊緣遮擋、目標旋轉、變形和背景運動不敏感。
meanShift缺點:
(1)缺乏必要的模板更新;
(2)跟蹤過程中由於窗口寬度大小保持不變,當目標尺度有所變化時,跟蹤就會失敗;
(3)當目標速度較快時,跟蹤效果不好;
(4)直方圖特征在目標顏色特征描述方面略顯匱乏,缺少空間信息;
由於其計算速度快,對目標變形和遮擋有一定的魯棒性,其中一些在工程實際中也可以對其作出一些改進和調整如下:
(1)引入一定的目標位置變化的預測機制,從而更進一步減少meanShift跟蹤的搜索時間,降低計算量;
(2)可以采用一定的方式來增加用於目標匹配的“特征”;
(3)將傳統meanShift算法中的核函數固定帶寬改為動態變化的帶寬;
(4)采用一定的方式對整體模板進行學習和更新;
