Mean shift實時跟蹤視訊流中物體
1 均值漂移演算法簡介
均值漂移演算法是一種基於密度梯度上升的非引數方法,通過迭代運算找到目標位置,實現目標跟蹤。所謂跟蹤,就是通過已知的影象幀中的目標位置找到目標在下一幀中的位置。均值漂移演算法顯著的優點是演算法計算量小,簡單易實現,很適合於實時跟蹤場合;但是跟蹤小目標和快速移動目標時常常失敗,而且在全部遮擋情況下不能自我恢復跟蹤。通過實驗提出應用核直方圖來計算目標分佈,證明了均值漂移演算法具有很好的實時性特點。均值漂移在聚類、影象平滑、分割、跟蹤等方面有著廣泛的應用。
2 均值漂移演算法中的非引數估計方法
非引數估計和引數估計(即,監督引數估計和非監督引數估計)共同構成了概率密度估計方法。非引數估計也有人將其稱之為無參密度估計,它是一種對先驗知識要求最少,完全依靠訓練資料進行估計,而且可以用於任意形狀密度估計的方法。常見的非引數估計方法有以下幾種:
A.直方圖:
B.核密度估計(Kernel Density Estimates,簡稱KDE):就是採用平滑的峰值函式(“核”)來擬合觀察到的資料點,從而對真實的概率分佈曲線進行模擬。原理和直方圖有些類似,是一種平滑的無參密度估計方法。對於一組取樣資料,把資料的值域分為若干相等的區間,每個區間稱為一個bin,資料就按區間分為若干組,每組資料的個數和總引數個數的比率就是每個bin的概率值。相對於直方圖法,它多了一個用於平滑資料的核函式。核密度估計方法適用於中小規模的資料集,可以很快地產生一個漸近無偏的密度估計,有良好的概率統計性質。具體來說,如果資料為x1,x2,…,xn,在任意點x的一種核密度估計為:
繪製成直方圖是這樣的:
而使用KDE則是:
其中 K(*)稱為核函式,滿足對稱性及 ,h稱為頻寬,一般,h越大,估計的密度函式就越光滑,但偏差可能較大,如果h選的較小,那麼估計的密度曲線和樣本擬合的較好,但可能很不光滑,選擇的原則是使得均方誤差最小為宜(交叉驗證法,直接插入法)。該估計利用資料點xi到x的距離來決定xi在估計點x的 密度時所起的作用,距離x越近的樣本點所起的作用就越大,其權值也就越大。常用的核函式有:矩形、Epanechnikov曲線、高斯曲線等。
C.區域性多項式密度估計:目前最流行,效果很好的密度估計 方法。對每一個點x擬合一個區域性多項式來估計該點的密度。
D.K近鄰估計:
令d1<=…<=dn表示按升冪排列的x到所有n個樣本點的歐氏距離。K的取值決定了估計密度曲線的光滑程度,k越大越光滑。與核估計結合起來定義廣義的k近鄰估計:
E.多元密度估計:上述的幾種估計方法都是一元密度估計方法。假定x為d維向量,則多元密度估計可以為 :
其中,。
3 OpenCV中的均值漂移演算法
均值漂移演算法以迭代的方式鎖定概率函式的區域性最大值。比如有一個矩形視窗將一幅影象的某個部分框住,原理就是尋找預定義視窗中資料點的重心,或者說加權平均值。該演算法將視窗中心移動到資料點的重心處,並重復這個過程直到視窗重心收斂到一個穩定點。在OpenCV中,該演算法的執行有兩種終止條件:達到最大迭代次數終止MAX_ITER和迭代到閾值終止EPS。
//終止條件:第二個引數為迭代的最大次數,最後一個引數是特定的閾值
TermCriteria criteria(TermCriteria::MAX_ITER,10,0.01);
//result為HSV中H通道對原圖的直方圖反投影影象,rect為預定義視窗
meanShift(result,rect,criteria);
- 1
- 2
- 3
- 4
因此,迭代完成的結果的好與壞取決於輸入的概率圖(上述中的預定義視窗)和它的初始位置。
整個跟蹤步驟:
- 設定初始跟蹤目標,即框住待跟蹤目標
- 獲取待跟蹤目標的HSV中的色度H通道影象的直方圖
- 待跟蹤直方圖歸一化
- 到新的資料幀影象中反投影待跟蹤直方圖
- 均值漂移,更新跟蹤位置
在這之前,我們還需要了解怎麼通過反投影直方圖以檢測特定的影象內容:
OpenCV【5】—通過反投影直方圖以檢測特定的影象內容
4 測試程式
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/video.hpp>
#include "colorhistogram.h"
#include "contentfinder.h"
using namespace cv;
using namespace std;
bool pause = false;
bool is_tracking = false;
Rect drawing_box;
Mat current;
MatND colorhist;
ContentFinder finder;
void meanShiftTracking(Mat current)
{
//設定跟蹤直方圖
finder.setHistogram(colorhist);
//轉換到HSV空間
Mat hsv;
vector<Mat> v;
cvtColor(current,hsv,CV_BGR2HSV);
//分割影象
split(hsv,v);
//識別低飽和度(S)的畫素
int minSat = 65;
threshold(v[1],v[1],minSat,255,THRESH_BINARY);
//獲取直方圖的反投影
Mat result;
int ch[1]={0};
result = finder.find(hsv,0.0f,180.0f,ch,1);
//去除低飽和度的畫素
//result(根據H色度反投影的影象)和v[1]是一樣大小,此時的result受飽和度S影響較大
bitwise_and(result,v[1],result);
//使用meanShift演算法更新矩形位置
//迭代演算法的終止條件:達到最大迭代次數終止MAX_ITER,迭代到閾值終止EPS
//第二個引數為迭代的最大次數,最後一個引數是特定的閾值
TermCriteria criteria(TermCriteria::MAX_ITER,10,0.01);
//使用CamShift演算法,改進版的均值漂移演算法,搜尋視窗的尺寸和朝向會發生改變
CamShift(result,drawing_box,criteria);
meanShift(result,drawing_box,criteria);
//更新矩形位置顯示
cv::rectangle(current, drawing_box, cv::Scalar(0,0,255),2);
imshow("VideoCapture Mean Shift Track Object",current);
}
void onMouse( int event, int x, int y, int flags, void *param )
{
if (pause)
{
Mat imageROI;
ColorHistogram hc;
int minSat = 65;
switch(event)
{
case CV_EVENT_LBUTTONDOWN:
drawing_box.x = x;
drawing_box.y = y;
break;
case CV_EVENT_LBUTTONUP:
drawing_box.width = x - drawing_box.x;
drawing_box.height = y - drawing_box.y;
imageROI = current(drawing_box).clone();
//顯示滑鼠畫的目標框
rectangle(current,drawing_box,Scalar(0,0,255),2);
imshow("VideoCapture Mean Shift Track Object",current);
//獲取色調通道的直方圖
//最小閾值:小於等於65為0,大於65為255
colorhist = hc.getHueHistogram(imageROI,minSat);
is_tracking = true;
break;
default:
break;
}
}
}
int main(int, char**)
{
//開啟PC預設攝像頭
VideoCapture cap(0);
if(!cap.isOpened())
return -1;
while(1){
Mat frame;
//從攝像頭獲取一幀影象
cap >> frame;
current = frame;
if(is_tracking){
meanShiftTracking(current);
}
uchar cmd = waitKey(1);
//暫停
if(cmd == 'p')
{
pause = true;
// 第一個引數跟視窗的名字有關
// 即回撥函式需要註冊到的視窗名字,即產生事件的視窗。
setMouseCallback("VideoCapture Mean Shift Track Object",onMouse,0);
}
//退出
else if(cmd == 'b'){
break;
}
while(pause){
if(waitKey(0) == 'p')
pause = false;
}
imshow("VideoCapture Mean Shift Track Object",current);
}
//camera 將會隨著程式的結束在解構函式中自動釋放記憶體
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
效果截圖:
使用改進版的均值漂移演算法CamShift效果:
meanShift
演算法用於視訊目標跟蹤時,採用目標的顏色直方圖作為搜尋特徵,通過不斷迭代meanShift向量使得演算法收斂於目標的真實位置,從而達到跟蹤的目的。傳統的meanShift
演算法在跟蹤中有幾個優勢:
(1)演算法計算量不大,在目標區域已知的情況下完全可以做到實時跟蹤;
(2)採用核函式直方圖模型,對邊緣遮擋、目標旋轉、變形和背景運動不敏感。
同時,meanShift演算法也存在著以下一些缺點:
(1)缺乏必要的模板更新;
(2)跟蹤過程中由於視窗寬度大小保持不變,當目標尺度有所變化時,跟蹤就會失敗;
(3)當目標速度較快時,跟蹤效果不好;
(4)直方圖特徵在目標顏色特徵描述方面略顯匱乏,缺少空間資訊;
由於其計算速度快,對目標變形和遮擋有一定的魯棒性,所以,在目標跟蹤領域,meanShift演算法目前依然受到大家的重視。但考慮到其缺點,在工程實際中也可以對其作出一些改進和調整;例如:
(1)引入一定的目標位置變化的預測機制,從而更進一步減少meanShift跟蹤的搜尋時間,降低計算量;
(2)可以採用一定的方式來增加用於目標匹配的“特徵”;
(3)將傳統meanShift演算法中的核函式固定頻寬改為動態變化的頻寬;
(4)採用一定的方式對整體模板進行學習和更新;