首页 > 解决方案 > Tkinter 程序在 IDE (Visual Studio) 中运行良好,但是当使用 pyinstaller 编译为 .exe 时,线程的工作方式与在 IDE 中不同

问题描述

当我在我的 IDE 中运行我的 python 项目时,GUI 和一切都是响应式的并且运行良好。但是当我作为 .exe 运行时,我的线程组件不像在 IDE 中那样工作。该程序的目标是通过 RTSP 获取实时提要并使用 opencv 显示图像。这是在它自己的线程中完成的。


import time
import threading
import cv2
import PIL.Image


"""TODO: add docstring"""


class VideoCapture:

    def __init__(self, xmlDict=None, width=None, height=None, fps=None):
        """TODO: add docstring"""

        self.xmlDict = xmlDict
        self.width = width
        self.height = height
        self.fps = int(self.xmlDict['FPS'])

        self.running = False

        # Open the video source
        self.vid = cv2.VideoCapture(self.xmlDict['IpAddress'])
        if not self.vid.isOpened():
            raise ValueError("[MyVideoCapture] Unable to open video source", xmlDict['IpAddress'])

        # Get video source width and height
        if not self.width:
            self.width = int(self.vid.get(cv2.CAP_PROP_FRAME_WIDTH))    # convert float to int
        if not self.height:
            self.height = int(self.vid.get(cv2.CAP_PROP_FRAME_HEIGHT))  # convert float to int
        if not self.fps:
            self.fps = int(self.vid.get(cv2.CAP_PROP_FPS))              # convert float to int

        # default value at start
        self.ret = False
        self.frame = None

        self.convert_color = cv2.COLOR_BGR2RGB
        #self.convert_color = cv2.COLOR_BGR2GRAY
        self.convert_pillow = True



        # start thread
        self.running = True
        self.thread = threading.Thread(target=self.process)
        self.thread.start()

    def process(self):
        """TODO: add docstring"""

        while self.running:
            ret, frame = self.vid.read()

            if ret:
                # process image
                frame = cv2.resize(frame, (self.width, self.height))

                # it has to record before converting colors
              

                if self.convert_pillow:
                    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                    frame = PIL.Image.fromarray(frame)
            else:
                print('[MyVideoCapture] stream end:', self.video_source)
                # TODO: reopen stream
                self.running = False
                if self.recording:
                    self.stop_recording()
                break

            # assign new frame
            self.ret = ret
            self.frame = frame

            # sleep for next frame
            #if self.fps != "FULL":
            #    time.sleep(1/int(self.fps))

我有一个名为 start 的按钮设置,它每 2 秒推断一次图像并打印出标签和置信度。当我在 .exe 中执行此操作时,实时提要和 GUI 在进行推理时会冻结,但是当我在 IDE 中使用程序时,它不会冻结。这是执行此操作的代码。

#Button to start inference
self.btn_snapshot = tk.Button(self.btnFrame,width = 10,height = 2, text="Start", command=lambda:threading.Thread(target = self.snapshot).start())
self.btn_snapshot.grid(row = 1,column = 0)
#snapshot function

def snapshot(self):
        self.recording = True
        while self.recording:
            filename = self.vid.snapshot()  
            result = self.predictImage(filename)
            output = self.calculatePassFail(result)
            if self.manager:
                self.manager.onClick(output)
            else:
                print('something')

            time.sleep(2)

快照函数调用的另外两个方法是 predictImage 和 calculatePassFail。



    def predictImage(self,imageName):

        onnxModel = ImageModel.load(self.xmlDict['ModelPath'])
        result = onnxModel.predict_from_file(imageName)
        return result
        
                
    def calculatePassFail(self,result):
        calcResult = result.labels[0]
        self.labelName = calcResult[0]
        self.imgScore = calcResult[1]*100

        return f"{self.labelName} with score{self.imgScore}"       

标签: pythontkinterpyinstallerpython-multithreading

解决方案


所以我找到了一个解决这个问题的方法,不确定它是否是一个正确的修复,但它可以工作。因此,由于某种原因,当我使用 pyinstaller 创建 .exe 并且有一个控制台窗口时,我遇到了问题,但是当我在使用 pyinstaller 创建 w/out 控制台时使用标志 --noconsole 时,问题就消失了,我对图像的推断起作用了在它自己的线程中,就像在我的 IDE 中一样。不知道为什么会这样,但我猜它有效。


推荐阅读