循环生成带图片的Tkinter Canvas仅最后一个显示问题求助
问题解决方案
问题核心原因
- 引用丢失触发垃圾回收:循环生成的
PhotoImage仅存在于局部列表images中,当__init__方法执行完毕后,局部变量会被Python垃圾回收机制清理。仅最后一个PhotoImage因被self.img_tk持有引用得以保留,其余均被回收,导致对应Canvas无法显示图片。 - 图像格式不匹配:
cv2.imread读取的图像为BGR格式,而PIL.Image.fromarray默认处理RGB格式,直接转换会导致颜色显示异常(虽非当前显示问题的直接原因,但需同步修正)。
修正后的代码
import tkinter as tk import cv2 from PIL import Image, ImageTk class App(object): def __init__(self): self.root = tk.Tk() # 候选区域坐标列表 candidates = [[0,100,100,100], [15,15,200,200], [30,30,200,200], [50,50,200,200], [100,100,200,200], [200,200,200,200]] # 读取图像并转换为RGB格式 self.im = cv2.imread(r"你的图片路径") self.im = cv2.cvtColor(self.im, cv2.COLOR_BGR2RGB) j = 0 i = 0 # 将列表改为实例变量,确保引用持久化 self.frames = [] self.images = [] self.refs = [] for candidate in candidates: x,y,w,h = tuple(candidate) # 裁剪指定区域图像 img_crop = Image.fromarray(self.im[y:y+h, x:x+w]) # 缩放至Canvas尺寸(可选,避免图像超出画布) img_crop = img_crop.resize((100, 100), Image.Resampling.LANCZOS) img_tk = ImageTk.PhotoImage(img_crop) canvas = tk.Canvas(self.root, bg='white', highlightthickness=1, highlightbackground="black", width=100, height=100) canvas.grid(row=i, column=j, sticky='wens', padx=5, pady=5) ref = canvas.create_image(0, 0, image=img_tk, anchor="nw") self.images.append(img_tk) self.refs.append(ref) self.frames.append(canvas) if j < 2: j += 1 else: j = 0 i += 1 app = App() app.root.mainloop()
关键修改说明
- 持久化引用:将
frames、images、refs从局部变量改为实例变量(self.xxx),确保这些对象在App实例存活期间始终有引用,不会被垃圾回收。 - 格式转换:通过
cv2.cvtColor将BGR图像转为RGB,保证颜色显示正确。 - 图像适配:添加图像缩放步骤,确保裁剪后的图像能完全适配Canvas的100x100尺寸(若你的裁剪区域刚好为100x100可省略)。
- 避免变量覆盖:循环中不再复用
self.img_tk,直接使用局部变量创建PhotoImage并存入实例列表,消除不必要的变量覆盖。
内容的提问来源于stack exchange,提问作者Jkind9
相关产品推荐
相关产品推荐

