Wieso wird das Bild nicht richtig angezeigt?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
AlexDK
User
Beiträge: 1
Registriert: Mittwoch 31. Juli 2024, 20:12

Hallo,

ich bin mal wieder auf ein Problem gestoßen, dass ich mit Google wohl einfach nicht lösen kann...
Folgendes sind die von mir importierten Module:

from tkinter import *
from tkinter.filedialog import askopenfilename
from threading import Thread
from PIL import Image, ImageTk
import cv2
import threading
import os
import time
import pickle

Und ein Ausschnitt des Codes meines Video Editors:

global Medien_Importierungen, Maximale_Breite, Maximale_Höhe
Videopfad = askopenfilename(filetypes =[('Video Files', '*.mp4')])
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:
Thumbnail.place(x = Fenster.winfo_screenwidth() * 0.01, y = Fenster.winfo_screenheight() / 10 + (Fenster.winfo_screenwidth() * 0.01 + Maximale_Höhe) * (int(Medien_Importierungen / 2)))
else:
Thumbnail.place(x = Fenster.winfo_screenwidth() * 0.11, y = Fenster.winfo_screenheight() / 10 + (Fenster.winfo_screenwidth() * 0.01 + Maximale_Höhe) * (int(Medien_Importierungen / 2)))
Medien_Importierungen += 1
Statt einem Bild wird jetzt nur ein weißes Bild angezeigt. Durch das verdoppeln der Zeile, in der ich die Funktion

Geladenes_Video.read()
angewendet habe, wurde auch nichts gelöst...

Bitte helft mir...

Alex
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Das ist nicht der gesamte relevante Code, so dass man hier nur raten kann.
Wahrscheinlich existiert Tkinter_Bild nicht dauerhaft, was es aber muß, damit das Bild im Speicher bleibt und angezeigt werden kann.
Threads und GUIs sind ein schwieriges Thema, wo man auch viel falsch machen kann, was zu komischen Effekten führen kann.
*-Importe machen den Code unübersichtlich, weil man nicht nachvollziehen kann, woher welcher Name stammt.
Globale Variablen darf es nicht geben, weil sonst nicht klar ist, wo welche Variable verwendet wird.
pickle ist nur dann sinnvoll, wenn man kurzzeitig Daten serialisieren möchte, z.B. um sie von einer Instanz zu einer anderen über ein Netzwerk zu übertragen. Den Anwendungsfall sehe ich bei Dir nicht.
Variablen werden generell komplett klein geschrieben, um sie von Klassen unterscheiden zu können.
place bentutzt man nicht. Du scheinst ja die Bilder in einem Grid anordnen zu wollen, dafür ist grid ideal.
Statt Echter Division, um gleich danach das Ergebnis in ein int umzuwandeln, benutzt man Ganzzahldivision //.
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ergänzend: Konstanten werden KOMPLETT_GROSS geschrieben um sie leichter als solche zu erkennen und es macht keinen Sinn die als ``global`` zu deklarieren, denn Konstanten ändert man ja nicht.

Der Code geht nicht sauber damit um falls der Anwender den Dateiuauswahldialog abbricht statt eine Datei auszuwählen.

`Rückgabe` ist ein sehr generischer Name und auch hier wird nicht darauf reagiert falls das Bild aus dem Video nicht geladen wurde. Genau dafür ist dieser Wert ja da. Die OpenCV-Methoden und Funktionen arbeiten mit Fehlerrückgabewerten statt mit Ausnahmen, da muss man also selber aufpassen und prüfen.

Wonach wurde eigentlich entschieden wann ein Name deutsch und wann englisch sein soll?

`Medien` und `Fenster` kommen aus dem ”nichts”, das scheinen also auch globale Variablen zu sein, was nicht sein sollte. Bei GUI-Anwendungen kommt man nicht um objektorientierte Programmierung herum.

Bei der Entscheidung ob die Medienanzahl gerade oder ungerade ist, scheint eine Menge kopierter Code zu sein, der sich nur an *einer* Stelle in einem Zahlenwert unterscheidet.

Zwischenstand:

Code: Alles auswählen

    def importiere_medium(self):
        videodateiname = askopenfilename(filetypes=[("Video Files", "*.mp4")])
        if videodateiname:
            is_ok, bild = cv2.VideoCapture(videodateiname).read()
            if is_ok:
                if (
                    bild.shape[0] / MAXIMALE_HOEHE
                    > bild.shape[1] / MAXIMALE_BREITE
                ):
                    height = MAXIMALE_HOEHE
                    width = bild.shape[1] * height // bild.shape[0]
                else:
                    width = MAXIMALE_BREITE
                    height = bild.shape[0] * width // bild.shape[1]

                photo_image = ImageTk.PhotoImage(
                    image=Image.fromarray(
                        cv2.cvtColor(
                            cv2.resize(bild, (width, height)),
                            cv2.COLOR_BGR2RGB,
                        )
                    )
                )
                thumbnail = tk.Label(self.medien_widget, image=photo_image)
                thumbnail.place(
                    x=(
                        self.winfo_screenwidth()
                        * (0.01 if self.medienanzahl % 2 == 0 else 0.11)
                    ),
                    y=(
                        self.winfo_screenheight() / 10
                        + (self.winfo_screenwidth() * 0.01 + MAXIMALE_HOEHE)
                        * (self.medienanzahl // 2)
                    ),
                )

                self.medienanzahl += 1
Aber wie Sirius3 schon erwähnte, sollte das `place()` nicht verwendet werden. Und falls es nicht *wirklich* wichtig ist die Grössenänderung von OpenCV erledigen zu lassen, bietet PIL eine Funktion um Vorschaubilder zu erstellen, wo man sich die eigenhändige Berechnung sparen kann. Dann bliebe am Ende so etwas:

Code: Alles auswählen

    def importiere_medium(self):
        videodateiname = askopenfilename(filetypes=[("Video Files", "*.mp4")])
        if videodateiname:
            is_ok, bilddaten = cv2.VideoCapture(videodateiname).read()
            if is_ok:
                bild = Image.fromarray(
                    cv2.cvtColor(bilddaten, cv2.COLOR_BGR2RGB)
                )
                bild.thumbnail((MAXIMALE_BREITE, MAXIMALE_HOEHE))
                photo_image = ImageTk.PhotoImage(image=bild)
                zeilenindex, spaltenindex = divmod(self.medienanzahl, 2)
                thumbnail = tk.Label(self.medien_widget, image=photo_image)
                thumbnail.grid(row=zeilenindex, column=spaltenindex)
                self.medienanzahl += 1
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten