Seite 1 von 1

Videoaufnahme mit cv2 aus pygame starten

Verfasst: Dienstag 6. April 2021, 10:40
von G-Rizzle
hi,

ich versuche eine Videoaufnahme über pygame zu starten (im pygame Fenster läuft ein Livestream der Kamera, zusätzlich ist dort z.B. der "Aufnahme starten" Button). Ich habe bereits gelernt, dass das am besten über Multithreading läuft. Versuche ich das ganze ohne pygame funktioniert es schon. Leider klappt es jedoch mit pygame nicht (Es heißt immer Videofehler im Videoplayer, wenn ich das Video öffnen will, ich vermute dass die einzelnen Frames nicht zusammengefügt werden).
Grundgedanke: Im "videorekorder.py" modul gibt es die Klasse Videorekorder() Wenn man den "Aufnahme starten" Button klickt, ändert sich die Objekteigenschaft self.action auf True. Dadurch wird, wie der Name sagt, eine Aktion ausgelöst. Wenn Objekteigenschaft self.aufnahme_akitv == Falsch, dann wird sie entsprechend gestartet und self.action wieder auf False gesetzt. Wenn Der Button im self.aufnahme_aktiv Modus geklickt wird, wird self.action == True gesetzt, Aufnahme gestoppt und self.action wieder auf False gesetzt.

Mein Code bisher sieht so aus:

--> pygame-while Schleife:

Code: Alles auswählen

while True:
...
	videorekorder.videorekorder_button.zeichne_button(SCREEN)
	videorekorder.videorekorder_button.listener()

Code: Alles auswählen



in der kommenden Klasse habe ich alles was den Button angeht weggelassen, da in meinen Augen nicht relevant und eher verwirrend
class Videorekorder():



    def __init__(self, action, aufnahme_aktiv):
        
        self.action = action
	self.aufnahme_aktiv = aufnahme_aktiv


      
    def listener(self):

        # Aufnahmebutton geklickt --> action --> aufnehmen
        
        if self.action == True and self.aufnahme_aktiv == False:
            self.recorder()



        # Aufnahme stoppen Button geklickt --> action --> aufnahme stoppen
        
        elif self.action == True and self.aufnahme_aktiv == True:

            self.aufnahme_aktiv = False
            recorder.join()


    def recorder(self):
        global recorder
        recorder = Thread(target=self.videoRecorder)
        recorder.start()



    def videoRecorder(self):


        # create a VideoWrite object, recoring to ./video.avi
        VIDEO_BREITE, VIDEO_HOEHE = 500, 500
        video = cv2.VideoWriter('video_temp.avi', cv2.VideoWriter_fourcc(*'XVID'), 30, (VIDEO_BREITE, VIDEO_HOEHE))

        self.aufnahme_aktiv = True

        while self.aufnahme_aktiv == True:

            video.write(dronen_initialisierung.frame_read.frame)
            time.sleep(1 / 60)

        video.release()

da ich komplett neu bin was threading angeht: liegt einfach nur ein logischer fehler vor? programmiert man das so?

würde mich über tipps von profis freuen (:
danke

Re: Videoaufnahme mit cv2 aus pygame starten

Verfasst: Dienstag 6. April 2021, 12:30
von Sirius3
`global` sollte man nicht verwenden, vor allem, wenn man schon eine Klasse hat.
Methoden sollten nach Tätigkeiten benannt werden, `recorder` oder `videoRecorder` ist keine Tätigkeit.
Man prüft nicht explizit auf True oder False.
Konstanten werden außerhalb von Methoden definiert.
`dronen_initialisierung` kommt aus dem Nichts. Der Name ist auch seltsam. Was hat eine Initialisierung mit einem Frame zu tun?

Wenn man mit Threads arbeitet, darf es keinen gemeinsamen Zugriff auf Attribute geben. Statt des Flags benutzt man Event.

Code: Alles auswählen

class Videorecorder():
    VIDEO_BREITE, VIDEO_HOEHE = 500, 500
    
    def __init__(self, action, dronen_initialisierung):
        self.action = action
        self.aufnahme_aktiv = None
        self.recorder = None
        self.dronen_initialisierung = dronen_initialisierung

    def listener(self):
        if self.action:
            if self.aufnahme_aktiv is None:
                # Aufnahmebutton geklickt --> action --> aufnehmen
                self.start_recorder()
            else
                # Aufnahme stoppen Button geklickt --> action --> aufnahme stoppen
                self.aufnahme_aktiv.set()
                self.recorder.join()
                self.aufnahme_aktiv = None

    def start_recorder(self):
        self.aufnahme_aktiv = threading.Event()
        self.recorder = threading.Thread(target=self.record_video)
        self.recorder.start()

    def record_video(self):
        # create a VideoWrite object, recoring to ./video.avi
        video = cv2.VideoWriter('video_temp.avi', cv2.VideoWriter_fourcc(*'XVID'), 30, (self.VIDEO_BREITE, self.VIDEO_HOEHE))
        while not self.aufnahme_aktiv.is_set():
            video.write(self.dronen_initialisierung.frame_read.frame)
            time.sleep(1 / 60)
        video.release()

Re: Videoaufnahme mit cv2 aus pygame starten

Verfasst: Dienstag 6. April 2021, 13:04
von G-Rizzle
Sirius3 hat geschrieben: Dienstag 6. April 2021, 12:30 `global` sollte man nicht verwenden, vor allem, wenn man schon eine Klasse hat.

Man prüft nicht explizit auf True oder False.

`dronen_initialisierung` kommt aus dem Nichts. Der Name ist auch seltsam. Was hat eine Initialisierung mit einem Frame zu tun?

danke mal wieder!
warum wird das, was du in den ersten beiden aussagen schreibst, die ich hier zitiere, so getätigt?

zur 3. zeile: dronen initialisierung: das ist das modul, in der ich sämtliche funktionen der drone anstelle (drone.connect(), drone.streamon(), drone.get_frame() ).

Re: Videoaufnahme mit cv2 aus pygame starten

Verfasst: Dienstag 6. April 2021, 13:35
von __blackjack__
@G-Rizzle: ``global`` benutzt man nicht. Weil das dann globale Variablen sind. Globale Variablen benutzt man nicht. Schon gar nicht wenn man Klassen benutzt, denn dann braucht man die gar nicht. Und schon mal überhaupt nicht wenn da auch noch Threads beteiligt sind.

Wenn man mit `True` oder `False` vergleicht dann kommt da wieder `True` oder `False` heraus. Man vergleicht ja aber schon `True` oder `False`. Das macht also gar keinen Sinn, denn man kann den ursprünglichen Wert nehmen, oder dessen Gegenteil mit ``not``.

Ad 3.: Das war schon klar, aber warum heisst das so? Das stimmt doch gar nicht. `get_frame()` hat nix mit Initialisierung zu tun. Und der Zugriff den Du da machst sieht so aus als würdest Du da den Wert einer globalen Variable verwenden der von woanders, eventuell auch in einem anderen Thread gesetzt wird. NEIN! Man benutzt keine globalen Variablen. Man packt ja auch nicht mit der Hand auf heisse Herdplatten…

Re: Videoaufnahme mit cv2 aus pygame starten

Verfasst: Dienstag 6. April 2021, 16:18
von G-Rizzle
danke, das hilft mir schonmal gut weiter!

Re: Videoaufnahme mit cv2 aus pygame starten

Verfasst: Dienstag 6. April 2021, 17:07
von G-Rizzle
Sirius3 hat geschrieben: Dienstag 6. April 2021, 12:30 `global` sollte man nicht verwenden, vor allem, wenn man schon eine Klasse hat.
Methoden sollten nach Tätigkeiten benannt werden, `recorder` oder `videoRecorder` ist keine Tätigkeit.
Man prüft nicht explizit auf True oder False.
Konstanten werden außerhalb von Methoden definiert.
`dronen_initialisierung` kommt aus dem Nichts. Der Name ist auch seltsam. Was hat eine Initialisierung mit einem Frame zu tun?

Wenn man mit Threads arbeitet, darf es keinen gemeinsamen Zugriff auf Attribute geben. Statt des Flags benutzt man Event.

Code: Alles auswählen

class Videorecorder():
    VIDEO_BREITE, VIDEO_HOEHE = 500, 500
    
    def __init__(self, action, dronen_initialisierung):
        self.action = action
        self.aufnahme_aktiv = None
        self.recorder = None
        self.dronen_initialisierung = dronen_initialisierung

    def listener(self):
        if self.action:
            if self.aufnahme_aktiv is None:
                # Aufnahmebutton geklickt --> action --> aufnehmen
                self.start_recorder()
            else
                # Aufnahme stoppen Button geklickt --> action --> aufnahme stoppen
                self.aufnahme_aktiv.set()
                self.recorder.join()
                self.aufnahme_aktiv = None

    def start_recorder(self):
        self.aufnahme_aktiv = threading.Event()
        self.recorder = threading.Thread(target=self.record_video)
        self.recorder.start()

    def record_video(self):
        # create a VideoWrite object, recoring to ./video.avi
        video = cv2.VideoWriter('video_temp.avi', cv2.VideoWriter_fourcc(*'XVID'), 30, (self.VIDEO_BREITE, self.VIDEO_HOEHE))
        while not self.aufnahme_aktiv.is_set():
            video.write(self.dronen_initialisierung.frame_read.frame)
            time.sleep(1 / 60)
        video.release()
doch noch 2 fragen:

1. verstehe trotzdem nicht warum man global variablen nicht nutzen sollte wenn es in python angeboten wird.
und 2: was genau bewirkt die zeile

Code: Alles auswählen

 self.aufnahme_aktiv.set()
?

Re: Videoaufnahme mit cv2 aus pygame starten

Verfasst: Dienstag 6. April 2021, 17:49
von __blackjack__
@G-Rizzle: Du kannst auch mit der Hand auf die heisse Herdplatte packen. Das Gerät bietet diese Funktionalität ja an. 😎

Du kannst auch alle Variablen ``global`` deklarieren, alle Namen auf maximal zwei Zeichen begrenzen, und das `goto-statement`-Package installieren und verwenden. Python bietet so etwas ja an. 🤡

Re: Videoaufnahme mit cv2 aus pygame starten

Verfasst: Dienstag 6. April 2021, 18:31
von G-Rizzle
ich kann mit der antwort nichts anfangen :D
ich verstehe nicht wo das problem ist eine globale variable im system zu haben, die von allen modulen genutzt werden kann. sie wird ja nur von einem modul verändert, alle anderen lesen nur

Re: Videoaufnahme mit cv2 aus pygame starten

Verfasst: Dienstag 6. April 2021, 19:47
von __blackjack__
@G-Rizzle: Das Problem ist globaler Zustand. Den will man nicht haben. Wirst'e irgendwann selber merken. Oder auch nicht. Sind Deine Programme halt scheisse. 😜

Re: Videoaufnahme mit cv2 aus pygame starten

Verfasst: Mittwoch 7. April 2021, 17:56
von G-Rizzle
die Videoaufnahme an sich funktioniert jetzt, logischerweise bleibt währenddessen nun jedoch das bild im Livestream hängen. Natürlich logisch, da das Programm in der

Code: Alles auswählen

while not self.aufnahme_aktiv.is_set():
hängt.

Um diese Funktion gleichzeitig zum restlichen Programm laufen zu lassen (um z.b. die Drohne währenddessen weiter fliegen zu können, das Livebild im pygamestream zu sehen etc. ) ist das Thema multiprocessing das richtige stichwort, oder?