【目標跟蹤】使用深度特徵來跟蹤目標

這次我們來分享一下如何將深度特徵結合到目標跟蹤中,代碼仍然放在我的倉庫:

xfmao/Visual_Tracking_api

tutorials目錄下的DeepDCF.ipynb,Visualize_deep_features.ipynb

(目前計劃後面在這個倉庫中增加在VOT,OTB等公開數據集上做性能評估的演算法介面,現在還在補全中,因為只有我一個人,所以進度比較慢。本人只是一個學生,寫的代碼可能不專業也可能會有bug,請各位盡量提出一些寶貴意見。另外覺得好的老哥別忘了打個星鼓勵一下,學生黨維護代碼不容易。。。)

—————————————————————————————————————————

需要的庫:

我們使用pytorch來實現所有的深度計算

引子

這部分引子的代碼地址:Visualize_deep_features.ipynb

在開始之前,我們需要簡單了解一下如何提取圖像的深度特徵。

提取深度特徵最簡單的做法是將圖像輸入到預訓練的網路,進行一次前向計算,獲得卷積層的輸出激活值。在本實驗中,使用vgg19作為預訓練好的模型,首先來看看vgg19長啥樣:

以上圖是vgg大家族的匯總,而vgg19就是最右邊一列E的結構(作為好的CVer請務必背下所有vgg的結構,真的很有用!!)

我們用pytorch來實現vgg19的結構

from torch import nncfg = [64, 64, M, 128, 128, M, 256, 256, 256, 256, M, 512, 512, 512, 512, M, 512, 512, 512, 512, M]class VGG_19(nn.Module): def __init__(self, outputlayer=[26]): assert (type(outputlayer)==list) super(VGG_19, self).__init__() layers = [] in_channels = 3 self.outputlayer = outputlayer for v in cfg: if v == M: layers += [nn.MaxPool2d(kernel_size=2, stride=2)] else: conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1) layers += [conv2d, nn.ReLU(inplace=True)] in_channels = v self.features = nn.Sequential(*layers) def forward(self, x): for module in self.features._modules.values(): x = module(x) if self.features._modules.values().index(module) in self.outputlayer: break return x

這段程序修改自torchversion的vgg19實現,我們不需要vgg模型輸出分類結果的FC層,所以在定義當中把FC層去掉了,這也是為了節約內存,為了輸出某一層的激活值,我們在初始化中定義了outputlayer參數,輸出指定層的激活值。

然後就是載入模型參數了,使用torchversion提供的vgg19參數:VGG19

下載下來以後,不能一次性載入進去,因為裡面帶有FC層權值,直接load會報錯,需要過濾一下參數信息:

# network initmodel = vgg.VGG_19(outputlayer=[3])# load partial weightsmodel_dict = model.state_dict()params = torch.load(vgg19.pth)load_dict = {k:v for k,v in params.items() if features in k}model_dict.update(load_dict)model.load_state_dict(model_dict)

如上,那麼所有步驟就都完成了。我們定義的是一個返回Conv1-2層(outputlayer=[3])激活值的模型。

讓我們看看Conv1-2的輸出長啥樣吧:

img = misc.imread(example.jpg)img_m = utils.get_subwindow(img,pos=[212.,212.],sz=np.array([100,100]))

# extract featuresimgMean = np.array([0.485, 0.456, 0.406], np.float)imgStd = np.array([0.229,0.224,0.225])img_m = misc.imresize(img_m,(224,224))/255.img_m = (img_m-imgMean)/imgStdimg_m = np.transpose(img_m, (2,0,1))feature2 = model(Variable(torch.from_numpy(img_m[None,:,:,:]).float()))feature = feature2.data[0].numpy()x = ndimage.zoom(feature, (1, float(100)/feature.shape[1], float(100)/feature.shape[2]), order=1)Visualize.imshow_grid(x,shape=[8,8])

跟蹤流程

代碼地址:DeepDCF.ipynb

仍然使用DCF的框架,但是這次我們嘗試一種新的尺度跟蹤策略,之前在【目標跟蹤】尺度估計跟蹤DSST教程中提到的尺度跟蹤,是為尺度預測訓練了一個模型,劃分為33個尺度來預測,這種方法雖然很全面,但是要提取33個尺度的深度特徵,顯然不太合適(33次前向傳播也是需要花費很長時間的)。所以我們需要盡量減少尺度數量。

接下來介紹一種用暴力搜索預測最佳尺度的方法:

1.取出序列中的第一幀和目標boundingbox

2.提取目標位置候選窗口的特徵x,變換到傅里葉域xf

3.生成目標位置回歸矩陣y,變換到傅里葉域yf

4.訓練得到位置跟蹤模板

5.對於序列中未來的所有幀:

6. 對於所有n個尺度乘子:

7. 將候選窗口變換到n個不同的尺度下,提取特徵,再resize到同一大小

8. 用位置跟蹤模板去計算候選窗口上的響應response

9. 求得最大響應處位置pos和最大響應值

10. 比較各個尺度的最大響應值,獲得響應最大對應尺度乘子和pos

11. 獲得最佳boundingbox尺寸和位置

12.預測完所有幀,結束

這是尺度的窮舉搜索,雖然看著很low,但是運用起來比較靈活,也比較簡便。但窮舉的缺陷也是很明顯的,候選尺度過多的情況下,速度會變得很慢,所以這裡我們就使用了3個尺度:

scale_factors = [1.0, 1.02, 0.98]

哪一層卷積特徵用於跟蹤效果是最好的

近些年有很多論文都討論過這個問題,我通過一些程序運行的結果,簡單的探討一下這個問題(只考慮單層特徵,不考慮多層特徵):

1.從vgg19來看,最高層(Conv5)的特徵用來跟蹤是很難行得通的,準確率會大大降低。

2.對於困難序列(遮擋,變形等),使用深度特徵確實有很大提高。

3.對於簡單序列,使用深度特徵提高不多,有時反而會被淺層特徵(hog,灰度)超越。

4.高層的特徵雖然準確率低,但是在遮擋的情況下,不容易失敗,Robustness很高。相反底層特徵只要被遮擋,經常會失敗。

5.我的結果顯示vgg19的Conv2-2和Conv3處的特徵有較好的準確率。

參考文獻就不貼了。最後貼一下簡單序列上的結果:

看到評論區有人問幀率,補一個對比圖吧(自己的結果,僅供參考):


推薦閱讀:

簡單易懂的講解深度學習(入門系列之陸)
人臉識別中的活體檢測
VOT2017結果分析及CFWCR經驗分享
OpenPose 是如何通過 500 個攝像頭跟蹤身體、讀懂人類情緒的

TAG:计算机视觉 | 深度学习DeepLearning | 图像处理 |