AttributeError:“ PhotoImage”对象没有属性“ _PhotoImage__photo”。无法在tkinter屏幕上加载和显示视频

时间:2020-07-31 08:33:06

标签: python python-3.x opencv tkinter python-imaging-library

我正在尝试为游戏编写代码,但是我在加载视频时遇到了一些麻烦。运行代码时出现此错误。我知道以前曾问过类似的问题,但我在这里找不到问题。当我运行代码时,会播放视频的前几秒钟,然后屏幕变成空白,并弹出此错误。


    Exception in Tkinter callback
    Traceback (most recent call last):
      File "C:\Users\jovan\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
        return self.func(*args)
      File "C:\Users\jovan\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 804, in callit   
        func(*args)
      File "c:/Jovan/Pycharm Projects/school projects/project_files/main_game2.py", line 69, in update
        photo = ImageTk.PhotoImage(image=img)
      File "C:\Users\jovan\AppData\Local\Programs\Python\Python38-32\lib\site-packages\PIL\ImageTk.py", line 112, in __init__
        self.__photo = tkinter.PhotoImage(**kw)
        Image.__init__(self, 'photo', name, cnf, master, **kw)
      File "C:\Users\jovan\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 4006, in __init__
        self.tk.call(('image', 'create', imgtype, name,) + options)
    _tkinter.TclError: not enough free memory for image buffer
    Exception ignored in: <function PhotoImage.__del__ at 0x03C570B8>
    Traceback (most recent call last):
      File "C:\Users\jovan\AppData\Local\Programs\Python\Python38-32\lib\site-packages\PIL\ImageTk.py", line 118, in __del__
        name = self.__photo.name
    AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'

我尝试运行部分与类分开加载和显示视频的代码,然后运行良好。我不知道发生了什么事,因为我是opencv和tkinter的新手。谁能帮我吗?为什么会发生这种情况,我该如何解决?这是代码


    from tkinter import * 
    from tkinter import messagebox
    from random import *
    from PIL import ImageTk,Image 
    import cv2
                                        
    root = Tk()                            
    root.title("Captain!") 
    root.geometry("1280x720")
    #root.geometry("660x560")
    
    class Game :
        def __init__(self): 
            self.m_cur = {1:["Military",50]}
            self.c_cur = {1:["People's",50]}
            self.r_cur = {1:["Research",50]}
            self.i_cur = {1:["Industrial",50]}
            self.p_cur = {1:["Research",50]}
    
        def clear(self):
            for widget in root.winfo_children():
                widget.destroy()
    
        def exit(self):
            msg = messagebox.askquestion("Thank you for playing","Are you sure you want to exit?")
            if msg == "yes" :
                root.destroy()
            else:
                Game.main(self)
                                        
        def start(self):
            Label(root,text="Hello, what should we call you?",font=("segoe print",20)).grid(row=0,column=0)
            name = Entry(root,width=20)
            name.grid(row=1,column=0)
            Button(root,text="Enter",font=("segoe print",20),command=lambda: Game.main(self)).grid(row=1,column=1)
            self.name=name.get()
       
        def main(self):
            Game.clear(self)
            Label(root,text="Welcome to the game",font=("segoe print",20)).grid(row=0,column=0)
            Label(root,text='What do you want to do?',font=("segoe print",20)).grid(row=1,column=0)
            qn_num = randint(1,3)
            Button(root,text="Start Game",font=("segoe print",20),command=lambda: Game.intro(self,qn_num)).grid(row=2,column=0)
            Button(root,text="Exit Game",font=("segoe print",20),command=lambda: Game.exit(self)).grid(row=3,column=0)
            #resetting values of the variables
            self.r_cur[1][1] = 50
            self.c_cur[1][1] = 50 
            self.i_cur[1][1] = 50
            self.m_cur[1][1] = 50
            self.p_cur[1][1] = 50
                               
        def intro(self,qn_num):
            Game.clear(self)
            vid = cv2.VideoCapture("project_files\\video.mp4")
            width = vid.get(cv2.CAP_PROP_FRAME_WIDTH)
            height = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
            def get_frame():
                ret,frame = vid.read()
                if ret :
                    return(ret,cv2.cvtColor(frame,cv2.COLOR_BGR2RGB))
                else :
                    return(ret,None)
            def update():
                canvas = Canvas(root, width = width, height = height)
                canvas.place(relx=0.5,rely=0.5,anchor=CENTER)
                ret,frame = get_frame()
                if ret :
                    img = Image.fromarray(frame)
                    photo = ImageTk.PhotoImage(image=img)
                    photo.image=img
                    canvas.create_image(0, 0, image = photo, anchor = NW)
                    canvas.image=photo
                root.after(delay,update)
    
            delay = 15
            update()
            Game.qn_func(self,qn_num)
    
        def game_over(self,x_cur):
            if x_cur[1][1]<=0 or x_cur[1][1]>=100 :
                Game.clear(self)
                Label(root,text=f"{x_cur[1][0]} faction rebelled").place(relx=0.4,rely=0.4)
                Label(root,text="GAME OVER",font=("ariel",20)).place(relx=0.5,rely=0.5,anchor=CENTER)
                Button(root,text="Continue",font=("segoe print",20),command=lambda: Game.main(self)).place(relx=0.37,rely=0.6)
    
        def qn_func(self,qn_num) :
            Game.clear(self)
            with open("project_files\\questions_file.txt") as q_file :
                #reading the question, options, next qn numbers and the character name from the file
                qn_list = q_file.readlines() 
                qn = qn_list[qn_num-1].strip().split("$")[1]
                char_name = qn_list[qn_num-1].strip().split("$")[2]
                qn1 = qn_list[qn_num-1].strip().split("$")[3]
                qn2 = qn_list[qn_num-1].strip().split("$")[5]
                n_qn1 = int(qn_list[qn_num-1].strip().split("$")[4])
                n_qn2 = int(qn_list[qn_num-1].strip().split("$")[6])
            #displaying the character name and the question as a label frame widget with character name as parent
            label_frame = LabelFrame(root,text = char_name,font = ("segoe print",20))
            label = Label(label_frame,text = qn,font = ("segoe print",20))
            label_frame.place(relx=0.5,rely=0.5,anchor=CENTER)
            label.pack()
            #displaying the buttons on the screen
            Button(root,text=qn1,command=lambda: Game.qn_func(self,n_qn1)).place(relx=0.2,rely=0.7,anchor=W,width=200,height=50)
            Button(root,text=qn2,command=lambda: Game.qn_func(self,n_qn2)).place(relx=0.8,rely=0.7,anchor=E,width=200,height=50)
            #running each variable through game_over to see if you are dead
            Game.game_over(self,self.r_cur)
            Game.game_over(self,self.c_cur)
            Game.game_over(self,self.i_cur)
            Game.game_over(self,self.m_cur)
            Game.game_over(self,self.p_cur)
            #defining the Doublevar variables
            s_var1 = DoubleVar()
            s_var2 = DoubleVar()
            s_var3 = DoubleVar()
            s_var4 = DoubleVar()
            s_var5 = DoubleVar()                        
            #setting the values in the scales
            s_var1.set(self.r_cur[1][1])
            s_var2.set(self.c_cur[1][1])
            s_var3.set(self.i_cur[1][1])
            s_var4.set(self.m_cur[1][1])
            s_var5.set(self.p_cur[1][1])
            #variables as scale widgets
            scale1 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var1)
            scale2 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var2)
            scale3 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var3)
            scale4 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var4)
            scale5 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var5)
            #opening images to be displayed under scales
            img_r = ImageTk.PhotoImage(Image.open("project_files\\research.PNG"))
            img_c = ImageTk.PhotoImage(Image.open("project_files\\com_ppl.PNG"))
            img_i = ImageTk.PhotoImage(Image.open("project_files\\money.PNG"))
            img_m = ImageTk.PhotoImage(Image.open("project_files\\military.PNG"))
            img_p = ImageTk.PhotoImage(Image.open("project_files\\productivity.PNG"))
            #the label widgets for images
            img_l1 = Label(root,image=img_r)
            img_l2 = Label(root,image=img_c)
            img_l3 = Label(root,image=img_i)
            img_l4 = Label(root,image=img_m)
            img_l5 = Label(root,image=img_p)
            #saving a reference of images
            img_l1.image = img_r
            img_l2.image = img_c
            img_l3.image = img_i
            img_l4.image = img_m
            img_l5.image = img_p
            #displaying images
            img_l1.grid(row=1,column=0)
            img_l2.grid(row=1,column=1)
            img_l3.grid(row=1,column=2)
            img_l4.grid(row=1,column=3)
            img_l5.grid(row=1,column=4)
            #displaying the scale widgets on the screen
            scale1.grid(row=0,column=0,padx=40,pady=10)
            scale2.grid(row=0,column=1,padx=40,pady=10)
            scale3.grid(row=0,column=2,padx=40,pady=10)
            scale4.grid(row=0,column=3,padx=40,pady=10)
            scale5.grid(row=0,column=4,padx=40,pady=10)
            #disabling the scales
            scale1.config(state=DISABLED)
            scale2.config(state=DISABLED)
            scale3.config(state=DISABLED)
            scale4.config(state=DISABLED)
            scale5.config(state=DISABLED)
            with open("project_files\\variables.txt") as v_file :
                #reading values of variables from file
                v_list = v_file.readlines()
                self.r_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[1])
                self.c_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[2])
                self.i_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[3])
                self.m_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[4])
                self.p_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[5])
    
    #driver code
    game = Game()
    game.start()
    root.mainloop()

谢谢!

1 个答案:

答案 0 :(得分:0)

问题在于,每次调用update()时我都在创建一个新列表,并且所有这些列表都在内存中堆积。我通过调用一个函数来解决问题,每次调用update()时,该函数都会破坏屏幕上当前所有的小部件。工作代码的相关部分在下面给出


    def clear(self):
        for widget in root.winfo_children():
            widget.destroy()
        
    def intro(self):
        Game.clear(self)
        vid = cv2.VideoCapture("project_files\\video.mp4")
        width = vid.get(cv2.CAP_PROP_FRAME_WIDTH)
        height = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
        def get_frame():
            ret,frame = vid.read()
            if ret :
                return(ret,cv2.cvtColor(frame,cv2.COLOR_BGR2RGB))
            else :
                return(ret,None)
        def update():
            Game.clear(self)    #i added this to delete the labels.
            ret,frame = get_frame()
            print(ret)
            if ret :
                img = Image.fromarray(frame)
                photo = ImageTk.PhotoImage(image=img)
                photo.image=img
                label = Label(root,image=photo)
                label.place(relx=0.5,rely=0.5,anchor=CENTER)
                label.image=photo
            root.after(delay,update)
    
        delay = 15
        update()
        Game.qn_call(self,"a",iteration=0)