使用Tkinter+OpenCV加载图片报错:'NoneType'无create_image属性
Tkinter+OpenCV图片显示报错:AttributeError: 'NoneType' object has no attribute 'create_image'
报错信息
AttributeError: 'NoneType' object has no attribute 'create_image'
问题背景
使用Python的tkinter开发GUI,尝试将OpenCV读取的图片显示到tkinter画布时触发上述错误。采用features_ex.py和main_ex.py双文件类结构开发,单文件运行正常,多文件模式下出错。
代码文件
features_ex.py(原版本)
from tkinter import * from tkinter import Canvas from tkinter import Button from tkinter import ALL from tkinter import filedialog import os import sys import cv2 as cv import tkinter as tk from PIL import ImageTk from PIL import Image class features(): def __init__(self, root) : self.path = '' self.root = root self.canvas = '' def LoadImage(self): self.path = filedialog.askopenfilename() print(self.path) self.origin=cv.imread(str(self.path), cv.COLOR_BGR2RGB) self.origin = cv.resize(self.origin, (500, 500)) features.show_image(self) def Canvas(self): self.canvas = Canvas(self.root, width=500, height=500, bg='gray91', border=1.25, relief='solid') self.canvas.pack(anchor='nw') def btn(self): self.btn = Button(self.root, text='Load', font='SimSun 15', border=1.25, command=lambda:features.LoadImage(self)) self.btn.place(relx=0.015, rely=0.75) def show_image(self): print(str(self.path)) self.img = Image.fromarray(self.origin) self.img = ImageTk.PhotoImage(image=self.img) self.canvas.create_image(0, 0, image=self.img, anchor='nw' )
main_ex.py(原版本)
from tkinter import * from Features_ex import * class app: def __init__ (self, interactive = False): ### Title Bar self.root=Tk() self.root.title("Example") self.root.geometry('1280x720') self.root.resizable(1,1) ### Create button self.btn_load = features.btn(self) self.canvas = features.Canvas(self) self.root.mainloop() if __name__ == '__main__' : app()
错误原因分析
- 类实例化错误:
main_ex.py中直接通过features.btn(self)和features.Canvas(self)调用类方法,这里的self是app类的实例,而非features类的实例,导致features类的__init__未执行,self.canvas始终为初始空值,调用create_image时触发错误。 - 方法调用不规范:
features类内部LoadImage方法中,用features.show_image(self)调用方法,不符合实例方法调用规范,应改为self.show_image()。 - OpenCV图片处理错误:
cv.imread的第二个参数误用了cv.COLOR_BGR2RGB(这是颜色转换常量),正确读取模式应为cv.IMREAD_COLOR,之后需单独调用cv.cvtColor转换为RGB格式。 - 图片引用回收问题:
PhotoImage对象若无实例变量引用,会被Python垃圾回收机制回收,导致画布无法显示图片。
修正后的代码
修正后的main_ex.py
from tkinter import * from Features_ex import features class app: def __init__ (self, interactive = False): self.root = Tk() self.root.title("Example") self.root.geometry('1280x720') self.root.resizable(1,1) # 正确实例化features类,传入主窗口对象 self.features = features(self.root) # 调用实例方法创建画布和按钮 self.features.create_canvas() self.features.create_button() self.root.mainloop() if __name__ == '__main__' : app()
修正后的features_ex.py
from tkinter import * from tkinter import Canvas from tkinter import Button from tkinter import filedialog import cv2 as cv from PIL import ImageTk from PIL import Image class features(): def __init__(self, root) : self.path = '' self.root = root self.canvas = None self.img = None # 保存图片引用,防止被GC回收 def LoadImage(self): self.path = filedialog.askopenfilename() print(self.path) # 修正图片读取与颜色转换逻辑 self.origin = cv.imread(str(self.path), cv.IMREAD_COLOR) self.origin = cv.cvtColor(self.origin, cv.COLOR_BGR2RGB) self.origin = cv.resize(self.origin, (500, 500)) self.show_image() # 实例方法规范调用 def create_canvas(self): # 方法名改为小写开头,避免与Canvas类名冲突 self.canvas = Canvas(self.root, width=500, height=500, bg='gray91', border=1.25, relief='solid') self.canvas.pack(anchor='nw') def create_button(self): # 统一方法命名风格 self.btn = Button(self.root, text='Load', font='SimSun 15', border=1.25, command=self.LoadImage) self.btn.place(relx=0.015, rely=0.75) def show_image(self): print(str(self.path)) self.img = Image.fromarray(self.origin) self.img = ImageTk.PhotoImage(image=self.img) self.canvas.create_image(0, 0, image=self.img, anchor='nw' )
环境信息
Python 3.11.8
Windows 11
Visual Studio Code
内容的提问来源于stack exchange,提问作者Yamm
相关产品推荐
相关产品推荐

