【问题标题】:Tkinter program works fine in IDE (Visual Studio) but when using pyinstaller to compile to .exe threading does not work same like it does in IDETkinter 程序在 IDE (Visual Studio) 中运行良好,但是当使用 pyinstaller 编译为 .exe 时,线程的工作方式与在 IDE 中不同
【发布时间】:2021-10-08 23:14:09
【问题描述】:

当我在我的 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}"       

【问题讨论】:

  • 代码太多了。请尝试将其减少到minimal reproducible example
  • 仅仅说我的线程组件不像在IDE中那样工作是不够的。请说明有什么不同、不满意或出乎意料的地方。
  • @BryanOakley 我将代码简化为重要的部分,我保留在 VideoCapture 类中只是为了上下文,并且只包含了线程启动的方法。感谢您的反馈
  • @BoarGules 感谢您的回复。我添加了更多解释。总而言之,当我对图像进行推断时,就会出现线程问题。 tkinter 上显示的实时提要与 GUI 本身一起冻结,直到图像有结果。

标签: python tkinter pyinstaller python-multithreading


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2021-03-24
    • 1970-01-01
    • 2020-09-03
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    • 2018-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多