PySide2開發“安全帽檢測”界面遇到的問題及其解決方案

0 說明

系統:Win7

python版本:python 3.7.4

目標檢測模型:yolo v3

1 實現的界面

功能說明:在開始檢測之前,需要手動選擇視頻進行檢測,當點擊“開始檢測”的時候,會使用子線程進行yolov3目標檢測,然後在主線程中更新界面(注意,一定要在子線程中處理耗時的操作,在主線程中進行界面的更新),主線程和子線程是採用signal和slot的通信方式。

2 主要內容(遇到的問題及其解決方案)

2.1 在子線程中進行檢測,在主線程中更新界面

最初的時候,我是重寫python中的Thread類來開闢一個子線程進行處理目標檢測耗時操作,需要循環讀取視頻,也就是需要在子線程中循環發送signal。但是在實驗的時候,slot無法接收到signal發送到的信息,具體原因不明來。在網上查找相關資料之後,使用PySide2中自帶的QThread來開闢一個子線程進行處理。

在使用QThread進行檢測和更新的時候,有兩種方式可以實現(這邊以循環發送signal爲例)

第一種方式:將Signal和QThread進行綁定

# 創建Signal的子類
class DemoSignal(QObject):
    msg = Signal(str)

    def __init__(self):
        super().__init__()

    def run(self):
        for i in range(100):
            self.msg.emit('這是信號{}'.format(i))


# 創建QThread的子類
class DemoQThread(QThread):
    def __init__(self):
        super().__init__()


class Status(QWidget):
    def __init__(self):
        super().__init__()
        # 創建Signal和QThread的實例對象
        self.signal = DemoSignal()
        self.qThread = DemoQThread()
        # 設置signal的slot
        self.signal.msg.connect(self.receiveSignal)
        # 將signal放到子線程中
        self.signal.moveToThread(self.qThread)
        # 將signal和qthread進行綁定
        self.qThread.started.connect(self.signal.run)
        self.qThread.start()

第二種方式:將Signal作爲QThread的一個屬性

 

# 創建QThread的子類
class DemoQThread(QThread):
    msg = Signal(str)

    def __init__(self):
        super().__init__()

    def run(self):
        for i in range(1000):
            self.msg.emit('這是信號{}'.format(i))



# 創建一個顯示界面
class Status(QWidget):
    def __init__(self):
        super().__init__()
        # 實例化QThread
        # 注意一定要有self
        self.qthread = DemoQThread()
        self.qthread.msg.connect(self.receiveSignal)
        self.qthread.start()

參考資料地址:https://www.bilibili.com/video/BV154411n79k?p=88

 

2.2 使用pyinstaller進行封裝成exe文件的時候,無法正常顯示圖片資源

在做界面的時候,我用到以一些圖片來美化界面的顯示,但是運行exe文件之後,無法正常顯示,這是因爲pyintaller在封裝成exe文件的時候,並不會將你的資源文件也進行封裝,也就是說你的png,jpg等資源文件並會封裝在dist中,exe文件是找不到相關圖片或者相關資源進行顯示的。所以爲了解決這個問題,我們可以將資源文件保存在py文件中,然後導入相關的py文件就可以了。

但是,在下面進行封裝的時候pyinstaller無法識別自定義的模塊,需要進行額外的處理,就把這個步驟通過另外一種方式給覆蓋覆蓋掉了,也就是說,如果你進行了2.3就沒有必要進行2.2。當然,如果你的項目中不包含自定義的模塊,僅僅包含圖片資源的話,只需要進行這一步就行了。但是相比於2.3而言,2.2就顯得複雜一些。

具體思路:(將.png圖片轉換成.py文件,使用的使用,從.py文件中讀取數據並以.png的格式進行保存)

(1)將.png或者.jpg格式的圖片轉換成.py文件(在.py文件中,圖片是以base64編碼格式進行存儲的)

# -*- coding: utf-8 -*-
# @Time    : 2018/6/6 18:29
# @Author  : Octan3
# @Email   : [email protected]
# @File    : Pic2py.py
# @Software: PyCharm
 
import base64
 
def pic2py(picture_name):
    """
    將圖像文件轉換爲py文件
    :param picture_name:
    :return:
    """
    open_pic = open("%s" % picture_name, 'rb')
    b64str = base64.b64encode(open_pic.read())
    open_pic.close()
    # 注意這邊b64str一定要加上.decode()
    write_data = 'img = "%s"' % b64str.decode()
    f = open('%s.py' % picture_name.replace('.png', '_png'), 'w+')
    f.write(write_data)
    f.close()
 
if __name__ == '__main__':
    # 其中pics列表中保存的圖片的地址,你可以使用相對地址或者絕地地址
    pics = ["one.png", "two.png", "com.png", "socket.png", "win.png"]
    for i in pics:
        pic2py(i)
    print("ok")

運行之後,你會發現在當前的圖片所在的文件夾下會新增幾個_png.py文件。如果你想使用圖片,你只需要導入這個模塊就行

(2)在程序中引用

from one_png import img as one    #引入img變量,賦別名爲one
...
# 將.py文件中的數據讀取出來並以.png的格式進行保存
tmp = open('one.png', 'wb')        #創建臨時的文件
tmp.write(base64.b64decode(one))    ##把這個one圖片解碼出來,寫入文件中去。
tmp.close()                
#現在就能用了,用完(加載到程序裏之後)刪了就好
 
#xxxxxx     #這裏one.png 就已經拿出來了,可以用來。下面就可以對此進行你想要的操作了。
do_something_with(one.png)        #做任何你想做的
#xxxxxx    
 
 
os.remove('one.png')    #用完可以刪除這個臨時圖片

參考資料:https://blog.csdn.net/Monster_li57/article/details/80601050

 

2.3 封裝的exe文件無法使用自定義的模塊

爲了方便維護,我將yolo檢測模型單獨放置在一個package下了,但是封裝之後的exe程序並不能夠加載自定義的模塊,所有才會導致運行exe文件的時候,無法進行目標檢測。所以我們需要做的就是告訴我們自定義的模塊在哪個位置。

(1) 先生成.spec文件

語法:使用 pyi-makespec yourScript.py 得到yourScript.spect文件

# 在我這邊是這樣的(注意.dll後面是有;.的)

C:\Users\cumt\PycharmProjects\HelmetDetection>pyi-makespec -F -w --add-binary C:\Users\cumt\AppData\
Local\Programs\Python\Python37\Lib\site-packages\cv2\opencv_videoio_ffmpeg412_64.dll;. -i C:\Users\c

其中:-F表示只顯示一個文件夾;-w表示運行程序的時候不顯示命令行;--add-binary表示要加載的動態鏈接庫(因爲我需要調用opencv讀取視頻,因此需要添加這個動態鏈接庫。這個動態鏈接庫的地址是(注意):<PATH_TO_PYTHON>\Lib\site-packages\cv2\opencv_ffmpeg320_64.dll)

(2)對.spec文件進行修改

主要有兩個方面:一方面要將所有的.py文件加載到第一個列表中;另一個方面將你用到的所有的資源文件都加載到datas中(這個方法和2.3的重複了)

(2)然後運行.spec文件生成.exe文件,注意這邊即使使用參數也沒有效果(需要在第一步中使用參數)

pyinstaller yourScript.spec

參考資料:

[1] https://blog.csdn.net/djshichaoren/article/details/79801531

[2] https://www.cnblogs.com/guyuyun/p/11074424.html

 

2.4 使用pyinstaller封裝的exe文件無法調用opencv進行視頻的讀取

這是因爲運行exe文件的時候,我們缺少opencv讀取視頻的動態鏈接庫,我們要做的就是在封裝的時候,需要將這個動態鏈接庫複製到exe所在的文件夾下就可以了。

參考資料:https://stackoverflow.com/questions/44415424/videocapture-opencv-python-pyinstaller-not-opening

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章