【搞事情】利用PyQt爲目標檢測SSD300添加界面(一)

【原創文章】歡迎正常授權轉載(聯繫作者)
【反對惡意複製粘貼,如有發現必維權】
【微信公衆號原文傳送門


SSD界面
CSDN上好多人留言想要我上面程序的源碼,但是真的抱歉,由於種種原因我不能直接將這個代碼給大家。但我會利用大概幾節教程中詳細介紹如何實現視頻流的採集–實時檢測–顯示界面,並重新寫一個項目,並將代碼分享。

本節教程主要從思想上給大家分享項目是如何實現的。
在下一教程中,我將結合之前發過的教程《基於Keras搭建的SSD300目標檢測神經網絡》(沒學的趕快點進去學呀,哈哈)詳細介紹代碼實現,並將源代碼分享給大家。


1. 需求描述

項目要實現視頻流採集圖像,然後將圖像送入SSD300檢測,再將檢測結果繪製在採集到的圖像,最後將圖像在界面上顯示出來,同時界面要控制上述流程。
做之前需要了解的幾點注意事項

(1) opencv中圖像保存在numpy.array類型的數組中,PyQt顯示控件無法直接使用,顯示opencv的圖像是需要轉換一下。
(2) 不同進程在內存上是隔離的,變量不能在進程間直接調用(也可以實現共享內存)。
(3) PyQt界面自己有一套信號傳遞處理循環機制來處理人機交互的命令,並且在一個GUI線程中完成。
(4) 基於keras+TensorFlow的模型預測需要在進程中執行,不能在線程中。

簡單的思考後我們可以畫出一個關係圖。
關係流程圖
從上面看是不是太簡單了?真的這樣嗎?簡單實現一張圖片的檢測並顯示在界面裏是挺簡單的,但是我們的目標是不斷採集視頻流、檢測並在界面上顯示出來,因此重要的是上面紅線,如何通過界面控制採集檢測顯示出來(人機交互嘛,最基本的要可以點擊按鈕來控制檢測顯示開始結束吧?要不要界面幹什麼?)


2. 解決方案1

熟悉使用opencv + 幀循環的同學簡單思考一下就可以獲得一個最簡單的解決方案(如下圖):點擊“開始”後直接創建幀循環獲取視頻圖像,再檢測,然後在顯示界面上,之後繼續進入下一循環,直到點擊“結束”改變條件跳出循環就行了呀。
解決方案1流程
簡直完美有沒有?但是實際這麼做的時候你就會發現如果把幀循環放在“開始”按鈕的響應函數裏,你的界面什麼也不會有,鼠標點擊後還在出現“程序無響應”,這是爲什麼呢?代碼搞錯了?並不是,這是界面“假死”了,現在回過頭去看看上面的注意事項(3),這是因爲PyQt裏的“更新”機制是在執行你按鈕響應函數後,由它自己的機制去顯示你對控件外觀的改變(就是顯示你的圖片),而你的響應函數下有個循環呀~它在一直跑呀,所有這個按鈕響應函數根本沒有執行完呀,它怎麼會去執行更新顯示呢?

通常我們遇到這種需要長時間run的循環是單獨把它放在線程裏,這樣就不影響界面的GUI線程了,但是注意事項(4)怎麼說的?不行了吧?

那我放在進程裏,這個是可以了,但是需要把圖像採集的過程也放在這個進程裏,因爲注意事項(2)說進程之間的內存不共享。如果放在同一進程下,那對這個進程的控制會變得很複雜,新手(作者就是)有好多問題處理不好的,會越來越麻煩;如果放在不同的進程,那大量圖片數據通過進程通信是沒辦法的,雖然Python下也有進程共享內存處理方法,但涉及數據轉換,經測試耗時嚴重,不能實時,而且也很複雜。

我的處理方法是意外發現了這個函數

QApplication.processEvents()

這個函數可以實現強制GUI線程“立刻更新”你對界面控件作出的改變,只要在幀循環裏執行顯示後加上這一句就可以完美完成上面的需求。

進一步思考:上面的方案對於攝像頭現採集的視頻流進行檢測時,沒有什麼大的問題,只要你的計算機算力足夠,那麼實時顯示沒有問題(在英偉達750M上測試過基本流暢檢測顯示),但對於視頻文件而言問題就來了,如果你的電腦太快,畫面就是“加速播放”,因爲沒有控制幀率。


3. 解決方案2

強調:該方法尚未測試不知道是否可行。

這個方法主要就是爲了解決文件視頻流出現加速播放的問題(作者是窮鬼沒有好設備,沒遇到速度太快的問題,所以沒測試,嚶嚶嚶~)

基本想法就是用QTimer(計時器)來解決,計時器可以設置一個計時,只要時間到了就會給對應的槽函數發送一個信號來執行槽函數,然後重新計時,一直重複這個過程,直到計時器被停止,我們可以利用計時器來代替幀循環。

基本流程如下圖,點擊“開始”後,啓動計時器開始計時,時間(1/FPS 單位:s)一到就執行計時器槽函數(採集圖像–檢測–顯示);結束時關閉計時器就好。

解決方案2流程
進一步思考:上面的方案如果可行就能解決檢測視頻時播放速度不對的問題,當然計時器的時間設計要考慮到預測耗時。對應算力有限的同學來說,無論是解決方案1還是解決方案2,基本面臨的情況是:畫面一幀一幀的卡過(簡直要把窮人逼瘋),有些時候其實也不用每幀圖像都檢測呀~能不能隔一段時間檢測一下,實現流暢的播放視頻呢?畢竟咱沒泰坦呀。請閱讀解決方案3


4. 解決方案3

強調:該方法已測試確認可行,放心操作。

這個方法主要就是“抽幀”檢測,跳過檢測時在播放顯示的那些幀,做到播放視頻與檢測並行運行。顯然這種方法要是將檢測結果顯示出來,那目標框就會在視頻中一閃而過,所以這個方法適合將檢測結果獨立顯示出來。
基本實現就是利用多進程+進程共享內存。基本流程如下圖所示。
解決方案3流程
軟件初始化時單獨建立SSD進程及共享內存,圖像採集及播放顯示由定時器完成,採集到的圖像複製到共享內存,SSD進程獲得圖片後進行檢測,檢測結束後通知計時器可以向共享內存寫入圖片了,然後一直循環往復進行下去。

多進程及共享內存:

# 多進程及進程通訊
from multiprocessing import Process, Queue
# 共享內存
from multiprocessing.sharedctypes import RawArray, RawValue
# RawArray :共享數組變量
# RawValue :共享值變量,具體什麼類型可設置

最近在趕畢業論文,沒時間更新了,下一節詳細介紹代碼的估計要一週後更新了。
需要的請關注公衆號,第一時間獲取更新

如果你讀後有收穫,歡迎關注我的微信公衆號
上面有更多完全免費教程,我也會不定期更新
ღ ღ ღ 打開微信掃描下方二維碼關注 ღ ღ ღ

在這裏插入圖片描述

發佈了13 篇原創文章 · 獲贊 24 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章