Videoaufnahme mit cv2 aus pygame starten

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
G-Rizzle
User
Beiträge: 90
Registriert: Donnerstag 18. Februar 2021, 12:26

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
Sirius3
User
Beiträge: 17761
Registriert: Sonntag 21. Oktober 2012, 17:20

`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()
G-Rizzle
User
Beiträge: 90
Registriert: Donnerstag 18. Februar 2021, 12:26

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() ).
Benutzeravatar
__blackjack__
User
Beiträge: 13123
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@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…
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
G-Rizzle
User
Beiträge: 90
Registriert: Donnerstag 18. Februar 2021, 12:26

danke, das hilft mir schonmal gut weiter!
G-Rizzle
User
Beiträge: 90
Registriert: Donnerstag 18. Februar 2021, 12:26

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()
?
Benutzeravatar
__blackjack__
User
Beiträge: 13123
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@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. 🤡
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
G-Rizzle
User
Beiträge: 90
Registriert: Donnerstag 18. Februar 2021, 12:26

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
Benutzeravatar
__blackjack__
User
Beiträge: 13123
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@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. 😜
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
G-Rizzle
User
Beiträge: 90
Registriert: Donnerstag 18. Februar 2021, 12:26

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?
Antworten