Search code examples
pythontkinterpython-imaging-library

Why does the picture change to a white area?


I had again a problem while coding my video editor... Here is a simplified code (the variables are in German language, don't wonder and feel free to ask if you don't understand something):

from tkinter import *
from tkinter.filedialog import askopenfilename
from PIL import Image, ImageTk
import cv2
Fenster = Tk()
Fenster.geometry(f"{Fenster.winfo_screenwidth()}x{Fenster.winfo_screenheight()}")
Maximale_Breite = int(Fenster.winfo_screenwidth() * 0.08)
Maximale_Höhe = int(Fenster.winfo_screenheight() * 0.08)
Medien_Importierungen = 0
Medien = Canvas(Fenster, width=Fenster.winfo_screenwidth() * 0.2, height=Fenster.winfo_screenheight(),
                highlightbackground="#dd6800")
Medien.pack(side=LEFT)
Medien_Importieren = Label(Medien, text="Import media")
Medien_Importieren.place(x=int(Fenster.winfo_screenwidth() / 10 - Medien_Importieren.winfo_reqwidth() / 2),
                         y=Fenster.winfo_screenheight() / 20)
def Medien_Hinzufügen(event):
    global Medien_Importierungen, Maximale_Breite, Maximale_Höhe, Tkinter_Bild
    Videopfad = askopenfilename(filetypes=[('Video Files', '*.mp4')])
    if Videopfad:
        Geladenes_Video = cv2.VideoCapture(Videopfad)
        Rückgabe, Einzelbild = Geladenes_Video.read()
        if Einzelbild.shape[0] / Maximale_Höhe > Einzelbild.shape[1] / Maximale_Breite:
            height = Maximale_Höhe
            width = int(Einzelbild.shape[1] * height / Einzelbild.shape[0])
        else:
            width = Maximale_Breite
            height = int(Einzelbild.shape[0] * width / Einzelbild.shape[1])
        Einzelbild = cv2.resize(Einzelbild, (width, height))
        Tkinter_Bild = ImageTk.PhotoImage(image=Image.fromarray(cv2.cvtColor(Einzelbild, cv2.COLOR_BGR2RGB)))
        Thumbnail = Label(Medien, image=Tkinter_Bild)
        if Medien_Importierungen % 2 == 0:
            x_position = Fenster.winfo_screenwidth() * 0.01 + Maximale_Breite / 2 - Einzelbild.shape[1] / 2
        else:
            x_position = Fenster.winfo_screenwidth() * 0.11 + Maximale_Breite / 2 - Einzelbild.shape[1] / 2
        y_position = (Fenster.winfo_screenheight() / 10 +
                        (Fenster.winfo_screenwidth() * 0.01 + Maximale_Höhe) * (Medien_Importierungen // 2) +
                        Maximale_Höhe / 2 - Einzelbild.shape[0] / 2)
        Thumbnail.place(x=x_position, y=y_position)
        Medien_Importierungen += 1
Medien_Importieren.bind("<Button-1>", Medien_Hinzufügen)
mainloop()

"Medien_Hinzufügen(x)" is a function which will be executed when a button is clicked to import a video. Now it shows every time I import a video the first time the first frame of the video, but when I execute the function a second time the picture from the first time will be white and only the first frame from the second video will be showed. That repeats every time I import a video and I don't know how to remedy that problem...

I tried to create the whole label in the if-else-condition but that didn't work either...


Solution

  • It is because same global variable Tkinter_Bild is used for storing the references of the image of new label created, so the previous one will be garbage collected.

    One of the ways to keep the reference of the image is using an attribute of the label:

    ...
    Tkinter_Bild = ImageTk.PhotoImage(image=Image.fromarray(cv2.cvtColor(Einzelbild, cv2.COLOR_BGR2RGB)))
    Thumbnail = Label(Medien, image = Tkinter_Bild)
    Thumbnail.image = Tkinter_Bild  # keep the reference using an attribute of the label
    ...