使用PyInstaller打包Python程序为exe后遇figurecanvasagg交互性报错求助
解决打包后Matplotlib非交互式后端问题
问题原因
你遇到的警告是因为Matplotlib在打包环境中默认使用了非交互式的Agg后端,而你的程序基于Tkinter构建,后端不匹配导致无法正常显示图像。安装PyQt6无效是因为程序未使用Qt框架,对应的QtAgg后端和Tkinter环境不兼容。
解决方案
1. 指定Matplotlib后端为TkAgg
在导入matplotlib相关模块前,强制设置后端为TkAgg,确保和Tkinter环境匹配:
import matplotlib # 指定适配Tkinter的后端 matplotlib.use('TkAgg') from matplotlib import pyplot as pl from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
2. 修改图像显示逻辑(适配Tkinter框架)
替换原代码中的pl.show(),将Matplotlib图像嵌入到Tkinter窗口中,避免独立弹窗的兼容性问题。修改ox_photo函数末尾的绘图代码:
# 原代码: # pl.imshow(cv2.cvtColor(final_image, cv2.COLOR_BGR2RGB)) # pl.show() # 替换为: # 创建Matplotlib画布 fig = pl.figure(figsize=(10, 8)) pl.imshow(cv2.cvtColor(final_image, cv2.COLOR_BGR2RGB)) pl.axis('off') # 隐藏坐标轴 # 在Tkinter弹窗中显示图像 img_window = tk.Toplevel(root) img_window.title("识别结果") canvas = FigureCanvasTkAgg(fig, master=img_window) canvas.draw() canvas.get_tk_widget().pack()
3. 打包时确保依赖被正确包含
使用PyInstaller打包时,添加参数确保Matplotlib的Tk后端依赖被完整打包:
pyinstaller --onefile --windowed --hidden-import=matplotlib.backends.backend_tkagg --hidden-import=tkinter your_script_name.py
--onefile:生成单个可执行文件--windowed:隐藏控制台窗口(不需要控制台输出时使用)--hidden-import:手动指定PyInstaller未自动检测到的依赖项
修改后的完整代码示例
import cv2 import numpy as np import imutils import easyocr import matplotlib matplotlib.use('TkAgg') from matplotlib import pyplot as pl from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg import tkinter as tk from tkinter import filedialog def ox_photo(filepath : str): img = cv2.imread(filepath) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_filter = cv2.bilateralFilter(gray, 11, 15, 15) edges = cv2.Canny(img_filter, 30, 200) cont = cv2.findContours(edges.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) cont = imutils.grab_contours(cont) cont = sorted(cont, key=cv2.contourArea, reverse=True) pos = None for c in cont: approx = cv2.approxPolyDP(c, 10, True) if len(approx) == 4: pos = approx break mask = np.zeros(gray.shape, np.uint8) new_img = cv2.drawContours(mask, [pos], 0, 255, -1) bitwise_img = cv2.bitwise_and(img, img, mask=mask) (z, v) = np.where(mask == 255) (z1, v1) = (np.min(z), np.min(v)) (z2, v2) = (np.max(z), np.max(v)) crop = gray[z1:z2, v1:v2] text = easyocr.Reader(['en']) text = text.readtext(crop) res = text[0][-2] final_image = cv2.putText(img, res, (z1, v2 - 100), cv2.FONT_HERSHEY_PLAIN, 5, (255, 255, 255), 5) final_image = cv2.rectangle(img, (v1, z1), (v2, z2), (0, 255, 0), 5) # 嵌入到Tkinter窗口显示结果 fig = pl.figure(figsize=(10, 8)) pl.imshow(cv2.cvtColor(final_image, cv2.COLOR_BGR2RGB)) pl.axis('off') img_window = tk.Toplevel(root) img_window.title("识别结果") canvas = FigureCanvasTkAgg(fig, master=img_window) canvas.draw() canvas.get_tk_widget().pack() def open_image(): filepath = filedialog.askopenfilename(title="Выберите картинку", filetypes=[("Image Files", ".jpg .jpeg .png .bmp")]) if filepath: ox_photo(filepath) root = tk.Tk() root.title("Выбор картинки") label = tk.Label(root, text="Выберите картинку:") label.pack() button = tk.Button(root, text="Обзор", command=open_image) button.pack() root.mainloop()
额外注意事项
- 如果不需要嵌入Tkinter窗口,仅修改后端设置并保留
pl.show(),打包时添加对应hidden-import参数也可解决问题,但嵌入方式的兼容性更好。 - 打包前确保所有依赖包(matplotlib、tkinter、cv2等)为最新稳定版本。
内容的提问来源于stack exchange,提问作者Xxxx999
相关产品推荐
相关产品推荐

