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

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


上篇詳細介紹實現利用PyQt給SSD加界面的三種方案(沒學的趕快點進來學呀,哈哈)。這篇將詳細介紹方案1的實現代碼(代碼獲取見文章末尾)。

下載好的代碼中項目文件構成如下:
文件目錄
其中 “ssd” 文件夾中是SSD檢測的關鍵文件,關於這部分之前寫文章了,裏面詳細介紹瞭如何訓練一個屬於自己的SSD300,有代碼、有預訓練的權值文件,不清楚的請移步這裏

接下來詳細介紹實現,先看看流程圖,實現的關鍵在於 檢測循環顯示

在這裏插入圖片描述

01 繪製界面

這裏推薦一個非常方便的PyQt開發IDE—— eric,整體開發過程有點像MFC的感覺,可以直觀看見控件的動作信號,並直接創建對應的槽函數,開發非常有效率,可以節省大把時間。
創建一個對話框窗口或者主窗口,拖拽一個QLabel在主窗口中用於顯示,兩個QPushButton用於控制開始/停止,一個QTextEdit用於顯示檢測結果。當然添加什麼控件還是按照自己的需求來。爲了講解下面的代碼,這裏我把用到的控件和名稱列在下面。界面的佈置如下圖。

界面控件
控件類型 ObjectName 作用
QLabel label_imgshow 畫面顯示
QPushButton pushButton_start 開始
QPushButton pushButton_end 結束
QTextEdit textEdit 顯示檢測結果

在這裏插入圖片描述
繪製好ui文件(對應文件:MainWindow.ui)後將其轉爲.py文件(Ui_MainWindow.py)。eric 可以十分方便的完成轉化,唯一麻煩的是,每次ui文件改變了都需要重新再“轉化更新”一次。

02 界面顯示

界面顯示主要是要將opencv的圖像數據(numpy.array)顯示在界面的QLabel(label_imgshow)中,項目中構建了一個類成員函數實現。

def show_img(self, img):
   showImg = QImage(img.data, img.shape[1], img.shape[0],
                    img.shape[1] * 3,     # 每行數據個數,3通道 所以width*3
                    QImage.Format_RGB888)
   self.label_imgshow.setPixmap(QPixmap.fromImage(showImg))  # 展示圖片

代碼非常簡單,就是先將numpy.array的數據轉爲QImage,再通過Qlabel控件的setPixmap將圖像顯示出來。每次更新顯示時將opencv的圖像數據作爲參數,調用一次函數就行。

03 幀循環實現

接下來就是最複雜(其實超簡單)的幀循環了。在窗口實例化時,將SSD300模型建立並導入訓練好的權值,點擊‘開始’後時開始幀循環檢測(循環在點擊‘開始’的槽函數中),點擊‘結束’後結束幀循環(通過控制循環條件實現)。

下面詳細介紹構造函數及“開始/結束按鈕點擊的槽函數

構造函數

功能:主要完成SSD的初始化以及一些依賴變量的初始化。

這裏建議那些利用該方案來給自己搭建的網絡添加界面的同學,建議將網絡單獨封裝成類,界面類中使用時會非常便利。

def __init__(self, parent=None):

   super(MainWindow, self).__init__(parent)  # 父類初始化
   self.setupUi(self)      # 窗口‘穿衣服’,變成我們設計的樣子

# 初始化界面
   # 設置圖片自適應顯示
   self.label_imgshow.setScaledContents(True)
   # 創建一幅白色圖片,在停止的時候顯示
   self.img_none = np.ones((420, 720, 3), dtype=np.uint8)*255
   self.show_img(self.img_none)

   # 初始化SSD
   # 目標名稱,按順序
   self.obj_names = ['Aeroplane', 'Bicycle', 'Bird', 'Boat', 'Bottle',
                     'Bus', 'Car', 'Cat', 'Chair', 'Cow', 'Diningtable',
                     'Dog', 'Horse', 'Motorbike', 'Person', 'Pottedplant',
                     'Sheep', 'Sofa', 'Train', 'Tvmonitor']
   # 需要顯示的目標list, 用於過濾
   self.include_class = self.obj_names
   # 導入權值文件,關聯檢測目標類別名
   self.ssd = SSD_test(weight_path='./ssd/weights/weights_SSD300.hdf5', class_nam_list=self.obj_names)
   # 攝像頭索引號或者視頻文件路徑
   self.camera_index = 0      # 電腦連接的攝像頭默認爲0
   # opencv 支持 ip攝像頭
   # self.camera_index = './Voc_test.avi'
   # 主循環flg,控制循環, False時循環停止
   self.video_flg = True

‘開始’點擊槽函數

功能:獲取圖像數據流,之後開始幀循環檢測

幀循環基本流程:讀入圖片–>預處理–>SSD檢測–>處理檢測結果–>結果繪製在圖像上–>更新顯示

@pyqtSlot()
def on_pushButton_start_clicked(self):
    # 獲取圖像數據流
    self.cap = cv2.VideoCapture(self.camera_index)
    # 判斷數據流是否打開
    if self.cap.isOpened():
        # ‘開始’按鈕設置爲不可用
        # 以免二次誤點造成錯誤
        self.pushButton_start.setEnabled(False)

     # 開始幀循環
        self.video_flg = True
        while self.video_flg:
            # 按幀讀取圖像
            ret, self.img_scr = self.cap.read()
            # opencv中圖像爲BGR,這裏轉爲RGB
            # 因爲我的SSD訓練時用的是RGB圖像,順序錯誤會影響檢測準確性
            self.img_scr = cv2.cvtColor(self.img_scr, cv2.COLOR_BGR2RGB)

            # SSD檢測
            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)
            
            # 將檢測結果顯示在QTextEdit控件上
            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)

            # 強制更新UI
            # 如果沒有,界面就‘假死’了,因爲一直處於循環裏
            QApplication.processEvents()
     else:
        self.textEdit.setText('攝像頭未打開!!!\n請檢查')

‘結束’點擊槽函數

功能:改變幀循環條件停止循環;爲下一次開始做準備

@pyqtSlot()
 def on_pushButton_end_clicked(self):
     # 改變循環條件,停止循環
     self.video_flg = False
     # 顯示空白圖片
     self.show_img(self.img_none)
     # 清除TextEdit中的顯示
     self.textEdit.clear()
     # 釋放攝像頭/數據流
     # 先判斷是不是當前實例是不是有‘cap’成員
     # 防止攝像頭已經釋放完了,再次點擊時報錯
     if hasattr(self, 'cap'):
         # 釋放攝像頭
         self.cap.release()
         # 刪除成員變量
         del self.cap
         
     # 將‘開始’設置爲可以點擊,爲再開始做準備
     self.pushButton_start.setEnabled(True)

關注下方公衆號,回覆關鍵字即可獲取下載地址。
  • 方案1源代碼下載:

    回覆“SSD界面1”獲取。


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

在這裏插入圖片描述

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