我遇到一个问题,Tkinter 应用程序在转换为 exe 时,每次加载 YOLO 模型时都会冻结并打开一个新窗口。我原来的程序非常广泛,所以我重新创建了一个来演示该问题:
from io import StringIO
memory_buffer = StringIO()
sys.stdout = memory_buffer
import tkinter as tk
from ultralytics import YOLO
import cv2 as cv
global testimg
testimg = cv.imread("testimg.jpg")
class MyGUI:
def __init__(self):
self.root = tk.Tk() # root here is window name now
self.root.geometry("600x400")
self.root.columnconfigure(0, weight = 1)
self.root.rowconfigure(0, weight = 1)
self.root.rowconfigure(1, weight = 1)
self.root.rowconfigure(2, weight = 1)
self.buttonmodel1 = tk.Button(self.root, text = "Model 1", bg = "#c9c9c9", bd= 5, width = 200, command = self.button1pressed)
self.buttonmodel1.grid(row =0, column=0, sticky= "WENS", padx = 3)
self.buttonmodel2 = tk.Button(self.root, text = "Model 2", bg = "#c9c9c9", bd= 5, width = 200)
self.buttonmodel2.grid(row =1, column=0, sticky= "WENS", padx = 3)
self.buttonmodel3 = tk.Button(self.root, text = "Model 3", bg = "#c9c9c9", bd= 5, width = 200)
self.buttonmodel3.grid(row =2, column=0, sticky= "WENS", padx = 3)
self.root.mainloop()
def button1pressed(self):
global testimg
model1 = YOLO("model1.pt")
model2 = YOLO("model2.pt")
model3 = YOLO("model3.pt")
resultsmodel1 = model1.predict(testimg)
print("model1")
resultsmodel2 = model2.predict(testimg)
print("model2")
resultsmodel3 = model3.predict(testimg)
print("model3")
MyGUI()
转换为exe使用:
pyinstaller --collect-data ultralytics Model_Test.py --onefile --windowed
与
from io import StringIO
memory_buffer = StringIO()
sys.stdout = memory_buffer
用于缓解使用 ultralytics + pyinstaller 的已知问题:
https://github.com/ultralytics/ultralytics/issues/7064
使用 Ultralytics 将 Python 转换为 EXE 文件时出现问题
在 VS 2022 中调试时不存在此类问题,只有当程序打包并作为 exe 运行时才会出现此类问题。所有模型文件与exe位于同一目录中。
看起来,一旦调用
.predict()
,主窗口就会冻结,控制台会立即弹出,并出现一个新的相同窗口。如果关闭,程序将按预期恢复,不会出现其他错误:
似乎是一个非常小众的问题,我猜想 Ultralytics + Pyinstaller + Tkinter 出了问题。
如果需要更多信息,请提供建议或让我知道。
看起来您遇到了一个问题,并且 tkinter 循环之间的复杂交互有解决方案:
这是代码解决方案:
import tkinter as tk
from ultralytics import YOLO
import cv2 as cv
import threading
import sys
from io import StringIO
memory_buffer = StringIO() # Output Handling
sys.stdout = memory_buffer
global testimg
testimg = cv.imread("testimg.jpg")
class MyGUI:
def __init__(self):
self.root = tk.Tk()
self.root.geometry("600x400")
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
self.root.rowconfigure(1, weight=1)
self.root.rowconfigure(2, weight=1)
self.buttonmodel1 = tk.Button(self.root, text="Model 1", bg="#c9c9c9", bd=5, width=200, command=self.button1pressed)
self.buttonmodel1.grid(row=0, column=0, sticky="WENS", padx=3)
self.buttonmodel2 = tk.Button(self.root, text="Model 2", bg="#c9c9c9", bd=5, width=200)
self.buttonmodel2.grid(row=1, column=0, sticky="WENS", padx=3)
self.buttonmodel3 = tk.Button(self.root, text="Model 3", bg="#c9c9c9", bd=5, width=200)
self.buttonmodel3.grid(row=2, column=0, sticky="WENS", padx=3)
self.root.mainloop()
def button1pressed(self):
threading.Thread(target=self.run_models).start() # Threading solution
def run_models(self):
global testimg
model1 = YOLO("model1.pt")
model2 = YOLO("model2.pt")
model3 = YOLO("model3.pt")
resultsmodel1 = model1.predict(testimg)
print("model1")
resultsmodel2 = model2.predict(testimg)
print("model2")
resultsmodel3 = model3.predict(testimg)
print("model3")
MyGUI()
PyInstaller Script 4 与你的相同
如果问题仍然存在,请执行以下操作:
--windowed
运行:如果问题仍然存在,请查看控制台进行调试