利用OpenCV和深度學習來實現人類活動識別

AIBigbull2050發表於2020-01-07

作者:Adrian Rosebrock

翻譯:吳振東

校對:趙春光

本文約 5700字,建議閱讀 16分鐘。

這篇教程會告訴你如何利用OpenCV和深度學習來實現人類動作識別。

透過閱讀這篇教程,你可以學到如何利用OpenCV和深度學習來實現人類動作識別。

我們實現的人類活動識別模型可以識別超過400類活動,其中準確率在78.4-94.5%之間(取決於任務類別)。 比如,活動類別的可包括:

1. Archery 射箭

2. arm wrestling 掰手腕

3. baking cookies 烤餅乾

4. counting money 數錢

5. driving tractor 開拖拉機

6. eating hotdog 吃熱狗

7. flying kite 放風箏

8. getting a tattoo 刺紋身

9. grooming horse 給馬梳毛

10. hugging 擁抱

11. ice skating 溜冰

12. juggling fire 火焰雜耍

13. kissing 親吻

14. laughing 大笑

15. motorcycling 騎摩托車

16. news anchoring 播報新聞

17. opening present 拆禮物

18. playing guitar 彈吉他

19. playing tennis 打網球

20. robot dancing機械人跳舞

21. sailing 開帆船

22. scuba diving 潛水

23. snowboarding 單板滑雪

24. tasting beer 喝啤酒

25. trimming beard 修剪鬍子

26. using computer使用電腦

27. washing dishes 洗盤子

28. welding 焊接

29. yoga 練瑜伽

30. …and more! 其他

人類活動識別可用於的實踐應用包括:

  • 給硬碟中的影片資料集自動分類/分組。
  • 訓練或監察新員工準確地完成任務(例如做披薩時的步驟和流程是否合適,其中包括揉麵團、上烤爐加熱、加鹽、加芝士、加餡料等等)。
  • 驗證食品的服務生從洗手間出來或手工處理食物時有沒有洗手,以免出現交叉汙染(比如說雞肉上的沙門氏菌)。
  • 檢查酒吧或飯店裡的顧客沒有被過度服務(灌酒)。

想要學習如何利用OpenCV和深度學習來實現人類動作檢測,請繼續閱讀本教程。

在這篇教程的第一部分,我們先來討論下Kinetics資料集,該資料集用來訓練人類活動識別模型。

在那之後我們可以聊聊如何來擴充套件ResNet, 該網路通常使用2D核函式,而我們將採用3D核函式,這樣就引入了活動識別模型可利用的時空維度成分。

接下來我們將會實現兩種版本的人類活動識別,使用的都是OpenCV庫和Python程式語言。

最後,我們應用人類活動識別模型到幾個影片樣例上,並看一下驗證結果。

Kinetics資料集

利用OpenCV和深度學習來實現人類活動識別(附連結)

圖1:教程中所採用的人類活動識別深度學習模型是利用Kinetics 400資料集來完成預訓練的

我們的人類活動識別模型是利用Kinetics 400資料集來完成訓練的。

該資料集包括:

  • 400種人類活動識別分類。
  • 每個類別至少400個影片片段(下載自YouTube)。
  • 一共有300,000個影片。

你可以點選這一連結來查詢該模型可以識別的型別名單:

想要了解關於該資料集的更多資訊,包括是如何去整合資料,請參考Kay 等人在2017年發表的論文《The Kinetics Human Action Video Dataset》。

《The Kinetics Human Action Video Dataset》

用於人類動作識別的3D ResNet

利用OpenCV和深度學習來實現人類活動識別(附連結)

圖2:深度神經網路利用ImageNet在影像識別上的進度已經使深度學習在活動識別方面趨於成功(在影片方向),在這篇教程中,我們會利用OpenCV進行深度學習的活動識別(照片源自Hara等人的論文)

我們用於人類活動識別的模型來自於Hara 等人在2018年發表於CVPR的論文《Can Spatiotemporal 3D CNNs Retrace the History of 2D CNNs and ImageNet》

該論文作者對現有的最先進的2D結構(比如說ResNet,ResNeXt,DenseNet等)進行了探索,將它們擴充套件為3D核函式從而用於影片分類。

《Can Spatiotemporal 3D CNNs Retrace the History of 2D CNNs and ImageNet》

上述文章的作者認為:

  • 這些網路架構都成功地應用到了影像分類中。
  • 經過大規模資料集ImageNet的訓練,這些模型都達到了非常高的準確率。
  • Kinetics資料集的規範同樣足夠大。

…,因此這些網路架構也應該可以適用於影片分類,透過:1.改變輸入集的維度來引入時空維度上的資訊;2.在這些網路架構中使用3D核函式。

事實證明上述文章的作者的觀點是正確的!

透過改變輸出集的維度和卷積核的維度,上述作者獲得瞭如下效果:

  • 在Kinetics測試資料集上的準確率是78.4%。
  • 在UCF-101測試資料集上的準確率是94.5%。
  • 在HMDB-51測試資料集上的準確率是70.2%。

這些結果與利用ImageNet訓練的最先進的模型所釋出的R1準確率近似,因此這證明了這些模型架構可以用於影片分類,只需要簡單地加上時空資訊以及用3D核函式來代替2D核函式。

下載OpenCV人類活動識別模型

利用OpenCV和深度學習來實現人類活動識別(附連結)

圖3:利用OpenCV和深度學習實現人類活動識別所需檔案

對於接下來的教程,你所需要下載的有:

  • 人類活動模型
  • Python + OpenCV原始碼
  • 用於影片分類的樣例

你可以在公眾號中下載含有全部內容的壓縮檔案。一旦完成下載,你可以繼續閱讀本教程。

專案結構

讓我們來檢查一下專案檔案:

利用OpenCV和深度學習來實現人類活動識別(附連結)

我們的專案包含三個附屬檔案:

  • action_recognition_kinetics.txt : Kinetics資料集的類別標籤。
  • resnet-34_kinetics.onx : Hara 等人提出的人類活動識別卷積神經網路,並已利用Kinetics資料集完成預訓練和序列化。
  • example_activities.mp4 :一段用於測試人類活動識別的剪輯片段合集。

我們將會回顧一下兩個Python指令碼,每一個都會接收上面三個檔案作為輸入:

  • human_activity_reco.py :我們的人類活動識別指令碼每次將N幀影像作為取樣,用於活動分類預測。
  • human_activity_reco_deque.py :一個類似的人類活動識別指令碼,使用了一個移動平均數佇列。這個指令碼跑起來要更慢,不管怎樣,我在這裡提供這個實現方式,這樣你就可以對其進行試驗並從中學到一些東西。

利用OpenCV的人類活動識別實現

讓我們開始使用OpenCV來完成人類活動識別實現。這一實現是基於OpenCV的官方樣例,而我又進行了一些調整(都位於這個和下個樣例中),並新增了一些註釋(對程式碼的作用進行了詳細的解釋)。

開啟human_activity_reco.py檔案,來看一下下面這段程式碼:

利用OpenCV和深度學習來實現人類活動識別(附連結)

2-6行是引入包。對於今天這份教程,你需要安裝OpenCV4和imutils。如果你沒有安裝OpenCV的話,利用pip install opencv指令來進行安裝。

pip install opencv

https://www.pyimagesearch.com/2018/09/19/pip-install-opencv/

10-16行來解析指令行引數:

  • --model :訓練人類活動識別模型的路徑。
  • --classes :活動識別類別標籤文件的路徑。
  • --input 一個用於存放輸入影片檔案的可選路徑。這個引數並沒有包括在命令列之內,你的網路是想頭也可以在這裡被呼叫。

從這裡開始我們來執行初始化:

利用OpenCV和深度學習來實現人類活動識別(附連結)

第21行是載入文字檔案中的類別標籤。

第22和23行定義取樣持續時長(用於分類的幀數)和取樣尺寸(每一幀的空間維度大小)。

接下來,我們將會載入並初始化人類活動識別模型:

利用OpenCV和深度學習來實現人類活動識別(附連結)

第27行利用OpenCV的DNN模組來讀取PyTorch中預訓練的人類活動識別模型。

第31行是對我們的影片流進行例項化,或者是選擇一個影片檔案,或者是使用網路攝像頭。

我們現在準備開始對幀影像進行迴圈,並執行人類活動識別:

利用OpenCV和深度學習來實現人類活動識別(附連結)

第34行開始迴圈我們的幀影像,其中幀的批處理將會經過神經網路(第37行)。

第40-53行用於從我們的影片流中構建幀的批處理。第52行將對每一幀影像調整尺寸至400畫素寬,而且保持原長寬比不變。

讓我們建立自己的輸入幀的二進位制物件blob,我們此後把它交給人類活動識別卷積網路來處理:

利用OpenCV和深度學習來實現人類活動識別(附連結)

第56-60行是從輸入幀列表中建立二進位制blob物件。

請注意我們用了blobFromImages (複數形式),而不是blobFromImage (單數形式)作為函式——原因是我們構建了一個多幅圖片的批次來進入人類活動識別網路,從而獲取了時空資訊。

如果你在程式碼中插入一行 print(blob.shape)的指令,你會注意到這個blob的維度是這樣的:

(1, 3, 16, 112, 112)

讓我們對這組維度有一個更清楚的瞭解:

  • 1:批次維度。我們只有單個資料點經過網路(“單個資料點”在這裡代表著N幀影像經過網路只為了獲得單個類別)。
  • 3:輸入幀影像的通道數。
  • 16: 每一個blob中幀影像的總數量。
  • 112(第一個):幀影像的高度。
  • 112(第二個):幀影像的寬度。

至此,我們已經做好了執行人類活動識別推斷的準備,然後在給每一幀影像標註上預測的標籤,並將預測結果展示在螢幕上:

利用OpenCV和深度學習來實現人類活動識別(附連結)

第64和65行將blob透過網路,獲得輸出列表(預測結果)。

隨後我們選取最高的預測結果作為這個blob的標籤(第66行)。

利用這個標籤,我們可以抽取出幀影像列表中每個幀影像的預測結果(69-73行),顯示輸出幀影像,直到按下q鍵時就打破迴圈並退出。

一個利用雙佇列(Deque)資料結構的人類活動實現的替代品

在上一章節關於的人類活動識別中,你從會注意到這幾行程式碼:

利用OpenCV和深度學習來實現人類活動識別(附連結)

這一實現意味著:

  • 程式會去從我們的輸入影片中讀取全部SAMPLE_DURATION幀數的影像。
  • 程式會將所有幀影像輸入到人類活動識別模型中來獲得輸出。
  • 接著程式會讀取另外一部分SAMPLE_DURATION幀數的影像,然後繼續重複這個過程。

因此,我們的程式實現並不是一個移動的預測。

與之相反,它只是簡單地抓取一個樣本的幀影像,然後進行分類,然後再去處理下一批次。上一批次的任意一幀影像都是被丟棄的。

我們之所以這樣做是為了提高處理速度。

如果我們給每一幀單獨分類的話,那我們執行腳步的時間就會被拉長。

這說明,透過deque資料結構來進行移動幀影像預測可以獲得更好的結果,因為它不會放棄前面全部的幀影像——移動幀影像預測只會丟棄列表中最早進入的幀影像,為那新到的幀影像騰出空間。

為了更好的展示為什麼這個問題會與推斷速度相關,讓我們設想一個含有N幀影像的影片檔案:

  • 如果我們用移動幀影像預測,我們進行N次分類,即每1幀影像都進行1次(當然是等deque資料結構被填滿時)。
  • 如果我們不用移動影像預測,我們只需要進行 N /SAMPLE_DURATION次分類,這會顯著地縮短程式執行一個影片流的總時間。
利用OpenCV和深度學習來實現人類活動識別(附連結)

圖4:移動預測(藍色)利用一個完全填充的FIFO佇列視窗來進行預測

批次預測(紅色)不需要一幀一幀地移動。移動預測需要更多的計算力,但對於利用OpenCV和深度學習的人類活動識別來說會有更好的效果。

OpenCV的這一dnn模組並不被大多數GPU(包括英偉達的GPU)所支援,我建議你不要對於大多數應用來說還是不要使用移動幀預測。

在今天這篇教程的.zip檔案中,你會找到一個名為human_activity_reco_deque.py的檔案,這一檔案包括一個利用移動幀預測的人類活動識別實現。

這一個指令碼與上一個非常相似,我把它放在這裡是讓你去嘗試一下:

利用OpenCV和深度學習來實現人類活動識別(附連結)

引入的庫與之前是完全相同的,除了需要再加上Python中collections 模組的deque 實現(第二行)。

在第28行,我們初始化了一個FIFO幀佇列,其中最大的長度等於我們的取樣時長。我們的“先進先出”(FIFO)佇列將會自動彈出最先進入的幀並接收新的幀。我們針對幀佇列進行移動推斷。

其餘所有的程式碼都是相同的,接下來讓我們來檢查一下處理幀影像的迴圈:

利用OpenCV和深度學習來實現人類活動識別(附連結)

第41-57行與我們之前的指令碼是不一樣的。

在上一個版本的指令碼中,我們抽取了一個帶有SAMPLE_DURATION數量幀的一個批次,然後再在這個批次上進行推斷。

在這個指令碼中,我們依舊是以批次為單位進行推斷,但現在是移動批次。不同點就在我們在第52行把幀影像放入到了FIFO佇列裡。如上文介紹,這個佇列擁有maxlen 個單位的取樣時長,而且佇列的頭部永遠是我們的影片流的當前幀。一旦這個佇列被填滿,舊的幀影像就會被這個FIFO雙端佇列實現自動彈出。

這個移動實現的結果就是一旦當佇列被填滿,每一個給出的幀影像(對於第一幀影像來說例外)就會被“觸碰”(被包含在移動批次裡)一次以上。這個方法的效率要低一些;但是它卻能獲得更高的活動識別準確率,特別是當影片或現場的活動週期性改變時。

第56和57使得我們的幀佇列在做出任何推斷之前,把幀對列填充好。(例如在圖4藍色區域的前16幀所顯示的)。

一旦這個佇列被填滿,我們將可以執行一個移動的人類活動識別預測:

利用OpenCV和深度學習來實現人類活動識別(附連結)

這一段程式碼塊包含的每一行程式碼與我們之前的指令碼是相同的,在這裡我們進行了以下操作:

  • 從我們的幀佇列中建立了一個blob。
  • 進行了推斷,並獲得了blob中機率最高的預測。
  • 用平均移動佇列所生成的人類活動識別標籤對當前幀影像進行註釋和顯示。
  • 一旦按下q鍵,程式將會退出。

人類活動識別在實際應用中的結果

讓我們看看人類活動識別在實際應用中的結果。

在這裡,開啟terminal,執行以下命令:

利用OpenCV和深度學習來實現人類活動識別(附連結)

請注意我們的人類活動識別模型要求的OpenCV最低版本是4.1.2.

如果你使用的OpenCV版本過低,那麼就會收到以下報錯資訊:

利用OpenCV和深度學習來實現人類活動識別(附連結)

如果你收到以上資訊,說明你需要更新你的OpenCV版本至4.1.2以上。

下面這個例子就是我們的模型正確地給這段影片打上“瑜伽”的標籤。

請注意我們的模型在識別時對預測是“瑜伽”還是“拉伸腿部”猶豫不決——當你在做下犬式姿勢時,這兩個動作術語從技術層面來看都是正確的。從定義上來講,你在做瑜伽的同時,也是在拉伸腿部。

在下一個樣例中,人類活動識別模型正確地預測出了這是在做“滑板運動”。

你可以看到模型也會把這個活動預測為“跑酷”。滑滑板的人在欄杆上跳躍,這很像是跑酷者可能的動作。

有人餓了嗎?

如果誰餓了,一定會對這個“做披薩”感興趣:

但在你吃披薩前,請確保你已經“洗手”:

如果你沉浸於“喝啤酒”,你最好注意一下飲酒量,酒吧侍者有可能會把你灌醉:

你可以看出,我們的人類活動識別模型可能不夠完美,但是考慮到本技術上的簡單性(只是將ResNet的2D輸入改為3D),它的表現還是不錯的。

人類活動識別問題還遠遠沒有解決,但在深度學習和卷積神經網路的幫助下,我們已經朝這個方向邁出了一大步。

總結

在這篇教程中告訴你如何用OpenCV和深度學習來實現人類活動識別。

為了完成這一任務,我們藉助了Kinetics資料集對人類活動識別模型進行了預訓練,這一資料集包含400-700種人類活動(取決於你使用的資料集的版本)和超過300,000個影片剪輯。

我們使用的模型是帶有變動的ResNet, 改動的方面是用3D核函式代替了原本的2D濾鏡,使得模型具有了可用於活動識別的時間維度成分。

想要了解更多,你可以閱讀Hara等人在2018年發表的論文《Can Spatiotemporal 3D CNNs Retrace the History of 2D CNNs and ImageNet》

最後,我們用OpenCV和Hara等人的在PyTorch上的實現OpenCV的dnn模型,生成了人類活動識別模型。

基於我們所取得的結果,我們可以看出這個模型可能不夠完美,但是表現還是不錯的。

原文標題:

Human Activity Recognition with OpenCV and Deep Learning

原文連結:

https://www.pyimagesearch.com/2019/11/25/human-activity-recognition-with-opencv-and-deep-learning/

編輯:王菁

校對:林亦

譯者簡介

利用OpenCV和深度學習來實現人類活動識別(附連結)


吳振東,法國洛林大學計算機與決策專業碩士。現從事人工智慧和大資料相關工作,以成為資料科學家為終生奮鬥目標。來自山東濟南,不會開挖掘機,但寫得了Java、Python和PPT。


—完—



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946223/viewspace-2672244/,如需轉載,請註明出處,否則將追究法律責任。

相關文章