計算任意視訊中各人物的出鏡時間(附Python實現)
作者:Pulkit Sharma
編譯:Bing
編者按:本文作者Pulkit Sharma分享了一篇有趣的專案,以《貓和老鼠》為例,計算任意視訊中湯姆貓和傑瑞鼠的出鏡時長。這一模型也可以用於其他電影,輕鬆統計各演員的上鏡時間。
簡介
當我開始接觸深度學習時,學到的第一件事就是影象分類。這個話題非常有趣,包括我在內的很多人都沉浸在它的魅力之中。但是在我處理影象分類時總會思考,如果我能將學到的東西遷移到視訊上就好了。
是否有一種模型能在特定時間內自動識別視訊中的某個人物呢?結果證明的確可以做到,下面就將我的方法分享給你們!
影視明星的出鏡時間是非常重要的,直接影響他們的片酬。舉個例子,在《蜘蛛俠:英雄歸來》中,小羅伯特唐尼僅僅出鏡15分鐘就有高達1000萬美元的片酬。
如果我能計算任意影片中所有演員的出鏡時間,那就太棒了!在這篇文章中,我將幫你理解如何在視訊資料中使用深度學習。我們就用《貓和老鼠》作為例子,計算任意視訊中,湯姆和傑瑞的出現時間。
注:本文需要讀者有一定的深度學習影象分類的先驗知識。如果沒有的話,我推薦你閱讀這篇文章,瞭解有關深度學習和影象分類的基本概念。
目錄
- 讀取視訊並提取幀
- 如何用Python處理視訊檔案
- 計算出鏡時間——一種簡單的解決方案
- 我的收穫
讀取視訊並提取幀

如上面的動圖所示,,每一頁紙上都有不同的畫面,隨著我們翻動書頁,可以看到一隻跳舞的鯊魚,而且翻動的速度越快,效果越好。這也可以看作一種視訊,換句話說,這種視覺效果是不同影象以特定順序排列在一起產生的。
同樣的,視訊也是由一系列圖片組成的,這些圖片稱為“幀”,可以通過組合得到原始視訊。所以與視訊資料有關的問題和影象分類或者目標檢測問題並沒有什麼不同。只是從視訊中提取幀需要多一個步驟。
我們這次的目的試計算湯姆和傑瑞在視訊中各自的出鏡時間,首先讓我們確定一下文中要做的步驟:
- 匯入並讀取視訊,從中提取幀,將它們儲存為圖片
- 標記一些圖片用於模型的訓練(這一步我已經做好了)
- 在訓練資料上搭建自己的模型
- 對剩餘圖片進行預測
- 計算湯姆和傑瑞各自的出鏡時間
跟著以下步驟學習,將會幫助你解決很多深度學習相關的問題。
如何用Python處理視訊檔案
首先要下載所有必需的庫:

第一步:讀取視訊並從中提取幀,將其儲存為影象
現在我們要下載視訊,並將它轉換成幀的形式。首先我們可以用VideoCapture( )函式從給定目錄中提取視訊,然後從視訊中提取幀,用imwrite( )函式將它們儲存為影象。
視訊下載地址: drive.google.com/file/d/1_DcwBhYo15j7AU-v2gN61qGGd1ZablGK/view

這個過程完成後,螢幕上會出現“Done!”的字樣。下面我們試著對影象(幀)進行視覺化,首先用matplotlib中的imread( )函式讀取影象,然後用imshow( )函式顯示影象。


這就是視訊中的第一幀。我們從每秒中提取一幀,由於視訊時長為4:58(共298秒),我們現在一共有298張照片。
我們的任務時確定哪張照片上有湯姆,哪張有傑瑞。如果我們提取出的影象能和常見的ImageNet資料集中的圖片有很大的相似性,那麼這個問題就能輕而易舉地解決了。但是這樣的樂趣在哪裡?
我們的是動畫片,所以要讓任何預訓練模型在給定的視訊中定位湯姆和傑瑞還是有難度的。
第二步:標記圖片訓練模型
要實現標記圖片,一種可能的方案是手動貼標籤。一旦模型學會了特定模式,我們就能用它在之前沒見過的影象上作出預測。
要記住的一點是,有些幀裡可能沒有湯姆和傑瑞的鏡頭,所以我們要將其看成是多種類的分類問題:
- 0:沒有湯姆和傑瑞的鏡頭
- 1:傑瑞
- 2:湯姆
我已經給所有圖片打上了標籤,所以直接在mapping.csv檔案中下載即可。


對映檔案包含兩部分:
- image_ID:包含每張照片的名稱
- Class.Image_ID:含有每張圖對應的種類
下一步是讀取圖片資訊,即他們的Image_ID部分:

現在我們就有了圖片,記住,我們要用兩部分訓練模型:
- 訓練圖片
- 對應的種類
由於這裡有三種不同情況,我們將用keras.utils中的to_cateforical( )函式對他們進行獨熱編碼。

圖片再輸入到VGG16訓練前,尺寸需變為224×224×3,所以我們的圖片在輸入前要重設尺寸。我們要用到skimage.transform中的resize( )函式。

尺寸調整好後,我們還要對每個模型的需求進行預處理,否則模型就不會表現得很好。利用keras.applications.vgg16中的preprocess_input( )函式來完成這一步驟。

我們還需要一個驗證集來檢查模型在陌生圖片上的效能,這裡就需要用到sklearn.model_selection模組中的train_test_split( )函式來隨機將圖片分成訓練集和驗證集。

第三步:搭建模型
下一步就是搭建自己的模型。我們會用VGG16預訓練模型來完成這一任務。首先匯入所需的庫:

下載VGG16與訓練模型,並將其儲存為base_model:

用該模型對X_train和X_valid進行預測,得到特徵,再用特徵重新訓練模型。

X_train和X_valid的尺寸分別為(208,7,7,512)和(90,7,7,512)。為了輸入到神經網路,我們必須把它重新修改成1—D尺寸。

現在對影象進行預處理,去中心化,讓模型收斂得更快。

最後,我們將搭建自己的模型,這一步可以分為三小步:
- 搭建模型
- 編譯模型
- 訓練模型

用summary( )函式檢查模型的彙總資訊:


模型中有一隱藏層,有1024個神經元,輸出層有3個神經元(因為我們有3種不同的預測情況)。現在我們開始編譯模型。

最後一步,我們要訓練模型,並且用驗證集檢測它在陌生影象上的表現:


可以看到在驗證集上的表現很不錯,精確度達到85%。這就是我們如何在視訊資料上訓練模型,再對每一幀作出預測的步驟。
下面,我將計算湯姆和傑瑞在新視訊中的出鏡時間。
計算出鏡時間——一種簡單的解決方案
首先下載我們要用到的視訊。一旦完成,可以從中提取幀:

從新視訊中提取幀之後,我們就要下載test.csv檔案,它包含每個提取出的幀的名字:

接著,我們將匯入用於測試的圖片,然後針對之前提到的預訓練模型重新修改尺寸:


接著,我們還要對這些圖片進行調整,就像之前處理訓練圖片那樣:

由於我們之前訓練了模型,就可以用它做出預測了。
第四步:對剩餘影象進行預測

第五步:計算湯姆和傑瑞的出鏡時間
剛剛我們規定了1代表傑瑞,2代表湯姆,這樣就可以用上述的預測來計算兩個角色的出鏡時長了:


結果如上。
我的收穫
為了完成這一專案,我遇到了很多問題。下面是我遇到的一些挑戰及做出的應對對策。
首先,我嘗試在沒有刪除最頂層的情況下使用預訓練模型,結果並不理想。原因可能是由於我們的模型之前沒有在動畫片上接受訓練。為了解決這個問題,我重新用圖片訓練模型,結果好了很多。
但是儘管用帶有標記的圖片訓練,精確度仍然不理想。模型在訓練影象上表現得並不好。所以,我試著增加圖層數量。這種做法結果不錯,但訓練和驗證精度之間並不對應。模型出現了過度擬合,它在陌生資料上表現得也不好。所以我在密集層之後增加了Dropout層,這樣就解決了。
我注意到,湯姆的出鏡時間更長,所以模型得出的很多結論都是湯姆。為了讓模型平衡預測,我用了sklearn.utils.class_weight模組中的compute_class_weight( )函式。它在數值計數較低的類別中分配了更高的權重,在較高的數值計數中分配較低權重。
另外,我還用Model Checkpoint儲存了最佳模型。
最終,我們在驗證資料上達到了88%左右的結果,在測試資料上達到了64%的精確度結果。
欲檢視完整程式碼,請點選原文地址: www.analyticsvidhya.com/blog/2018/09/deep-learning-video-classification-python/