【搞事情】利用PyQt为目标检测SSD300添加界面(三)
【原創文章】歡迎正常授權轉載(聯系作者)
【反對惡意復制粘貼,如有發現必維權】
【微信公眾號原文傳送門】
系列文章鏈接
1. 問題總體描述及三種方案;
2. 方案1詳解(附代碼);
這篇文章將詳細介紹方案2的實現(代碼獲取見文章末尾)。
老規矩先看看下載好的代碼文件構成。
其中 “ssd” 文件夾中是SSD檢測的關鍵文件,關于這部分之前寫文章了,里面詳細介紹了如何訓練一個屬于自己的SSD300,有代碼、有預訓練的權值文件,不清楚的請移步這里。
需求分析
先簡單做一個需求分析,看看我們要怎樣實現。
首先,要解決的問題:電腦性能太好(如果你有的話,土豪交朋友嗎?),導致使用幀循環的方法時,視頻會被“加速”播放,我們想讓它按正常的速度播放。
之后,我們先了解一個概念FPS(每秒幀數),對應的可以計算出一幀應該顯示幾秒。例如:
只要控制 讀取圖像–>檢測–>顯示 的節奏,讓顯示圖像的時間與視頻的 FPS 對應,那么看起來視頻就是正常播放的啦。
通過 計時器(QTimer) 可以很好的實現這個需求,計時器時間一到就會發送 “超時”信號 給對應的槽函數(用于檢測顯示),槽函數收到信號后就開始執行,槽函數執行結束后等待再一次被調用。
最后一個需求是要通過界面的按鈕來控制 開始 和 結束 ,這個就很簡單,構造函數里實例化計時器,然后在對應的槽函數里 開始 或 停止 計時器就可以了。
代碼分析
下面開始詳細介紹代碼。主要介紹下面幾個函數,其他的函數在上篇文章中已經講過或者比較簡單,就不介紹了。(偷個懶,嘿嘿嘿)
1. 構造函數
def __init__(self, parent=None): """...上一篇文章已經介紹過......這里就不寫了......這里說點不一樣的... """ # 視頻文件路徑self.camera_index = None # 用于保存視頻文件路徑self.FPS = None # 用于保存視頻文件FPS ?# 初始化計時器self.timer = QTimer(self) # 更新計時器self.timer.timeout.connect(self.timer_update) # 超時信號連接對應的槽函數在構造函數中初始化必要的變量,同時實例化一個 QTimer計時器 ,并將 “超時”信號 與對應的槽函數綁定起來。代碼中self.timer_update為計時器超時信號的槽函數,這里作為參數傳入不可以加’()’,后面會詳細說。
2. ‘開始’點擊槽函數
?def on_pushButton_start_clicked(self):"""Slot documentation goes here."""# TODO: not implemented yet# 獲取數據流self.cap = cv2.VideoCapture(self.camera_index)if self.cap.isOpened():# 獲取視頻的FPS# FPS ---- 每秒多少幀self.FPS = self.cap.get(cv2.CAP_PROP_FPS)if isinstance(self.FPS, float): # 正常獲取的FPS是floatself.FPS = int(self.FPS) # 如果正確獲取FPS就保存在變量else:self.FPS = 20 # 沒正確獲取則設為 20幀/s ?# 計時器開始計時# 計時器的參數為 ms 為了正常速度播放,計時器的參數計算為 1/FPS * 1000 = 1000/FPSself.timer.start(int(1000/self.FPS)) ?# 鎖定開始按鈕self.pushButton_start.setEnabled(False)else:QMessageBox.warning(self, '數據流打開警告', '數據流打開錯誤!\n請重新嘗試。')該函數的主要功能是:打開視頻數據流;獲取視頻流的FPS;計時器開始計時。需要注意的是計時器的時間設置問題。
函數self.timer.start(時間,單位:ms)的參數與 1/FPS 之間還需要乘以 1000 ,同時這個值還應該考慮到圖像預處理以及檢測的時間,適當的減小這個值,如果不考慮的話可能會出現“慢速播放”。
3. ‘結束’點擊槽函數
該函數比較簡單,主要功能是停止計時器的功能,同時為下一次檢測做準備。
def on_pushButton_end_clicked(self):"""Slot documentation goes here."""# TODO: not implemented yet# 重設self.resst_detector() # 詳細代碼在下方# 清除顯示self.textEdit.clear()def resst_detector(self):"""重設檢測器,為下一次檢測準備:return:"""# 釋放攝像頭if hasattr(self, 'cap'):self.cap.release()del self.cap# 釋放‘開始’按鈕self.pushButton_start.setEnabled(True)# 顯示空白圖片self.show_img(self.img_none)# 停止計時器self.timer.stop()4. 計時器槽函數
def timer_update(self):"""計時器槽函數:return:"""if self.cap.isOpened():# 讀取圖像ret, self.img_scr = self.cap.read()# 如果視頻讀取完畢if not ret:# 計時器停止計時self.timer.stop()# 對話框提示QMessageBox.information(self, '播放提示', '視頻已播放完畢!')# 釋放攝像頭if hasattr(self, 'cap'):self.cap.release()del self.cap# 釋放‘開始’按鈕self.pushButton_start.setEnabled(True) ?# 預處理圖片# 轉為RGBself.img_scr = cv2.cvtColor(self.img_scr, cv2.COLOR_BGR2RGB) ?# 檢測self.preds = self.ssd.Predict(self.img_scr)# 過濾self.preds = self.filter(self.preds, inclued_class=self.include_class)self.img_scr = self.draw_img(self.img_scr, self.preds) ?h, w = self.img_scr.shape[:2]self.text = self.decode_preds(self.preds, w=w, h=h)self.textEdit.setText(self.text) ?# 顯示圖像self.show_img(self.img_scr) ?# 響應UIQApplication.processEvents()else:self.textEdit.setText('數據流未打開!!!\n請檢查')self.resst_detector() # 沒有打開就重設一下看過上篇文章的是不是很熟悉,沒錯。基本就是幀循環里面的東西。
5. ‘文件打開’槽函數
為了方便更換被檢測視頻,創建了一個按鈕用于打開文件對話框選擇文件,基本功能就是為了實現給變量self.camera_index賦值。
def on_pushButton_open_clicked(self):"""Slot documentation goes here."""# TODO: not implemented yet# 打開文件對話框path = QFileDialog.getOpenFileName(self, '打開待檢測視頻', './', '*.avi;;*.mp4;;AllFile(*.*)', '')if path[0] != '': # 點‘取消’,path[0]的值會為‘’path = os.path.normpath(os.path.abspath(path[0]))self.camera_index = pathself.textEdit.setText('{}已選中!'.format(path))else:self.textEdit.setText('當前未選中任何文件')?預告:方案3應該下周整理完畢并更新
關注下方公眾號,回復關鍵字即可獲取下載地址。
-
本文配套源代碼下載地址::
回復“SSD界面2”獲取。
如果你讀后有收獲,歡迎關注我的微信公眾號
上面有更多完全免費教程,我也會不定期更新
? ? ? 打開微信掃描下方二維碼關注 ? ? ?
總結
以上是生活随笔為你收集整理的【搞事情】利用PyQt为目标检测SSD300添加界面(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 世界那么大我要出网关
- 下一篇: “你的项目靠谱吗?”“我胸大我先说”