Picamera wie am besten intigrieren

Fragen zu Tkinter.
Streifenhase1
User
Beiträge: 90
Registriert: Dienstag 22. Mai 2018, 07:15

Hallo

Hab jetzt schon ne Weile gesucht aber noch nicht das richtige gefunden.

Ich habe mit tkinter ein Fenster mit 3 Buttons und einem Hintergrundbild erstellt.

Ein Button soll Picamera mit Live Bild starten.

Jetzt weiß ich nicht wie ich es so richtig einbinde.


Am besten währe es wenn die Buttons bleiben und das live Bild quasi als Hintergrund läuft.

Könnt ihr mir da einen anstupsen geben?

Danke
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich glaube dafür ist Tkinter nicht so super. Kivy kommt mit picamera Unterstützung daher. Moderner und hübscher ist es obendrein. Das solltest du dir mal anschauen.
Streifenhase1
User
Beiträge: 90
Registriert: Dienstag 22. Mai 2018, 07:15

Da ich blutiger Anfänger bin und mich gerade etwas mit Tkinter auseinander gesetzt habe wollte ich es erst ein mal damit versuchen. Wie es jetzt ausschaut scheint es für meine zwecke zu reichen. Kivy scheint mir auf den ersten blick momentan noch zu kompliziert.

Ich habe mit Hilfe von Tutorial schon soweit einiges hinbekommen.
Kurze Erklärung....
Ich habe ein Hauptfenster mit 3 Buttons.
mit einem Starte ich PiCamera in einem Fenster über dem Hauptfenster. so weit so gut.
Jetzt möchte ich aber wieder das Fenster in dem Picamera läuft über einen Button auf dem Hauptfenster schließen. Bekomme es aber nicht hin.

def. Capture öffnet die PiCamera

def. Exit soll sie wieder schließen.


Hier mal mein Code

Code: Alles auswählen

from tkinter import *
from tkinter import messagebox
import tkinter as tk
"import picamera"
import time
import datetime

timestamp = time.strftime('%y-%m-%y   %H:%M:%S')






# Kamera Einstellungen #
def Capture():

        camera = picamera.PiCamera(resolution=(1920,1080))
        camera.vflip=True
        camera.hflip=True
        camera.awb_mode='auto'
        camera.exposure_mode='sports'
        camera.video_stabilization=True
        camera.preview_fullscreen=False
        camera.preview_window=(48, 105, 800, 720)
        camera.start_preview()

def EXIT():
        camera = picamera.PiCamera(resolution=(1920,1080))
        camera.stop_preview()
        camera.close()
        quit()



def action_get_info_dialog():
	m_text = "\
************************\n\
Autor: *******\n\
Date: 31.05.18\n\
Version: 1.00\n\
************************"
	messagebox.showinfo(message=m_text, title = "Infos")


# Hauptfenster
fenster = Tk()
fenster.title("Kamera Laser")
fenster.geometry('800x720')
#Hintergrundbild
Hintergrundbild = "Unbenannt-1.gif"
background_image = tk.PhotoImage(file=Hintergrundbild)
tk.Label(fenster, image=background_image).place(x=0, y=0)

# Menüleiste
menuleiste = Menu(fenster)

# Menü
datei_menu = Menu(menuleiste, tearoff=0)
help_menu = Menu(menuleiste, tearoff=0)

# Beim Klick auf Datei oder auf Help sollen nun weitere Einträge erscheinen.
# Diese werden also u "datei_menu" und "help_menu" hinzugefügt
datei_menu.add_command(label="Info", command=action_get_info_dialog)
datei_menu.add_separator() # Fügt eine Trennlinie hinzu
datei_menu.add_command(label="Exit", command=fenster.quit)

# "Drop-Down-Menü" 
menuleiste.add_cascade(label="Datei", menu=datei_menu)

# Die Menüleiste mit den Menüeinrägen dem Fenster übergeben.
fenster.config(menu=menuleiste)          


# Label und Buttons

Start_button = Button(fenster, text="Kamera Starten", command=Capture)
Stop_button = Button(fenster, text="Kamera Stopen", command=EXIT)
exit_button = Button(fenster, text="Beenden", command=fenster.destroy)
anweisungs_label = Label(fenster, text=timestamp)


# Label und entsprechender Button 

anweisungs_label.grid(row=0, column=0, pady = 20,)
Start_button.grid(row=0, column=2, pady = 20, padx = 20)
Stop_button.grid(row=0, column=4, pady = 0, padx = 20)
exit_button.grid(row=0, column=6, pady = 0, padx = 20)
anweisungs_label.place(x = 100, y = 260, width=150, height=30)

# In der Ereignisschleife auf Eingabe des Benutzers warten.
fenster.mainloop()
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du musst schon das ursprüngliche Camera Objekt benutzen. Und darauf stop aufrufen. Dazu musst du dir die Kamera merken, zb in einer globalen Variablen. Das ist zwar hässlich , aber am einfachsten. Besser ist es objektorientiert zu arbeiten.

Und zu guter letzt: Kivy ist nicht komplizierter als tkinter. Was du bisher hast ist fast nichts. Wenn du weiter auf tkinter setzt, werden Fortgeschrittene Dinge wie Buttons auf der Kameraausgabe schwerer bis unmöglich. Sei dir also sehr sicher auf welches Pferd du hier setzt.
Streifenhase1
User
Beiträge: 90
Registriert: Dienstag 22. Mai 2018, 07:15

Könntest du mir das mit dem merken über globale Variablen an einem Beispiel erklären ? (Code)
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Code: Alles auswählen

def Capture():
        camera = picamera.PiCamera(resolution=(1920,1080))

def EXIT():
        camera = picamera.PiCamera(resolution=(1920,1080))
Hi,
die beiden Objekte camera in den Funktionen Capture() und EXIT() sind nicht dieselben!
Wenn die Funktion Capture() beendet wird, werden alle darin erzeugten Objekte/Variablen gelöscht.
Die Funktion EXIT() erzeugt ein neues camera Objekt und beendet/schließt dieses dann.

Du benötigst also ein globales Objekt camera.
Dieses erzeugst du auf der Hauptebene und erzeugst durch die Definition als globale Variable in den Funktionen eine Zugriffsmöglichkeit.
Wenn du dich irgendwann an objektorientiertes Programmieren begibst, kannst du eleganteren Code erzeugen.

Code: Alles auswählen

camera = picamera.PiCamera(resolution=(1920,1080))

def Capture():
        global camera
        camera.vflip=True
        camera.hflip=True
        camera.awb_mode='auto'
        camera.exposure_mode='sports'
        camera.video_stabilization=True
        camera.preview_fullscreen=False
        camera.preview_window=(48, 105, 800, 720)
        camera.start_preview()

def EXIT():
        global camera
        camera.stop_preview()
        camera.close()
        quit()
Wenn du mal etwas Zeit hast, schau dir mal diesen Link an.
http://gki.informatik.uni-freiburg.de/t ... guide.html
Da geht es um die Formatierung des Python Codes.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Streifenhase1
User
Beiträge: 90
Registriert: Dienstag 22. Mai 2018, 07:15

Ok Danke.

Leuchtet mir ein wenn ich mir das so anschaue...
Vielen Dank

Werde mich sobald ich Zeit finde daran versuchen 😁
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

ThomasL hat geschrieben: Samstag 2. Juni 2018, 10:16

Code: Alles auswählen

camera = picamera.PiCamera(resolution=(1920,1080))

def Capture():
        global camera
        camera.vflip=True
        camera.hflip=True
        camera.awb_mode='auto'
        camera.exposure_mode='sports'
        camera.video_stabilization=True
        camera.preview_fullscreen=False
        camera.preview_window=(48, 105, 800, 720)
        camera.start_preview()

def EXIT():
        global camera
        camera.stop_preview()
        camera.close()
        quit()
Das ist nicht richtig. Wenn man hier die global-Statements weglässt, funktioniert es genauso. global würde man nur benötigen, wenn man in den Funktionen an camera zuweisen würde. Variablen entstehen bei Zuweisung in dem Scope, wo die Zuweisung stattfindet, außer man deklariert die Variable in diesem Scope als global. BTW: Auf Modulebene, welche immer den äußersten Scope darstellt, ist eine Deklaration als global folglich niemals nötig.
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

pillmuncher hat geschrieben: Samstag 2. Juni 2018, 12:30 global würde man nur benötigen, wenn man in den Funktionen an camera zuweisen würde.
stimmt, beim tippen nicht dran gedacht
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Streifenhase1
User
Beiträge: 90
Registriert: Dienstag 22. Mai 2018, 07:15

Konnte es noch nicht Testen da ich gerade die Kamera nicht da habe.

Könntet ihr mal schauen ob das so funktionieren könnte mit der Kamera und Aufnahme. Danke

Code: Alles auswählen

camera = picamera.PiCamera(resolution=(1920,1080))
camera.vflip=True
camera.hflip=True
camera.awb_mode='auto'
camera.exposure_mode='sports'
camera.video_stabilization=True
camera.preview_fullscreen=False


def get_date():
    return datetime.datetime.now().strftime("%d-%m-%Y %H:%M")


# Kamera Einstellungen #

AUFNAHMEPFAD = "/media/pi/Transcend/Aufnahmen/"
# Zeit in Sekunden
AUFNAMEINTERVALL = 300
AUFNAHMEDAUER = 60

def Capture():
        camera.preview_window=(48, 105, 800, 720)
        camera.start_preview()
        zeit_letzte_aufnahme = datetime.timedelta(seconds=0)
        aufnahmestart = False
        if AUFNAHMEDAUER > AUFNAMEINTERVALL:

                print("Dauer muss kleiner sein als Intervall")
        sys.exit(1)

# Logik für Aufnahme
        if (datetime.datetime.now() - zeit_letzte_aufnahme) > datetime.timedelta(seconds=AUFNAMEINTERVALL):
                camera.start_recording(os.path.join(AUFNAHMEPFAD, get_date(), ".h264"))
                aufnahmestart = datetime.datetime.now()
        if aufnahmestart:
                if (datetime.datetime.now() - zeit_letzte_aufnahme) > datetime.timedelta(seconds=AUFNAHMEDAUER):
                        camera.stop_recording()
                        aufnahmestart = False

        Capture()

__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Da sind diverse Fehler drin. zeit_letzte_aufnahme ist ein timedelta Objekt, das ist falsch, es muss ein Zeitstempel sein, also datetime. Die erste erste if Abfrage ist an der Stelle falsch, und sollte auch eher ein assert auf modul Ebene sein. Denn diese Einstellungen sind ja fix, die kannst du nur falsch setzen als Programmierer.

Die Bedingungen danach sind auf diverse Art daneben, aber der entscheidende Punkt ist: das klappt alles überhaupt nicht, weil du eine Rekursion (den Aufrufe von Capture am Ende) benutzt. Das wird erstens krachen weil man nur beschränkt viele Funktionsaufrufe schachteln kann, bevor der Speicher ausgeht und der Interpreter einen abwürgt. Vor allem aber übernehmen die funktionasaufrufe NICHT den Zustand der Variablen, sondern erzeugen die neu.

Und selbst wenn du das unter Verwendung einer while-Schleife machst, hilft das am Ende auch nichts. Denn du willst ja obendrein eine GUI schreiben, und GUIs können keine while-schleifen vertragen. Dann blockieren sie und werden nutzlos. Stattdessen musst du mit Tkinters after Methode arbeiten. Das wird hier gefühlt in jedem zweiten Forumsbeitrag zu Tkinter erläutert, schau da mal durch die Themen der letzen paar Monate.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Einrückungen sind falsch. Außerdem sollte immer mit 4 Leerzeichen pro Ebene eingerückt werden, sonst ist der Code kaum lesbar. `sys.exit` sollte in keinem sinnvollen Programm vorkommen. Du hast eine Endlos-Rekursion, die zu einem baldigen Stacküberlauf führt. In Deiner Aufnahme-"Logik" ermittelst Du 4 mal die aktuelle Zeit, wo es eigentlich nur einmal passieren sollte.

`zeit_letzte_aufnahme` ist eine Zeitdauer von 0 Sekunden. Wenn man das von der aktuellen Zeit abzieht, kann keine Zeitdauer herauskommen, so dass die if-Abfragen logisch falsch sind.

Versuch mal in Worten zu beschreiben, was Du erreichen wolltest.
Streifenhase1
User
Beiträge: 90
Registriert: Dienstag 22. Mai 2018, 07:15

Ja also nach starten der Kamera sollte alle x Minuten eine Aufnahme von x Sekunden gemacht werden bei permanenten live Bild.
Die Aufnahmen sollen auf USB Stick gespeichert werden und als Dateiname den Poststempel haben.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Streifenhase1 hat geschrieben: Sonntag 3. Juni 2018, 14:32 Ja also nach starten der Kamera sollte alle x Minuten eine Aufnahme von x Sekunden gemacht werden bei permanenten live Bild.
Die Aufnahmen sollen auf USB Stick gespeichert werden und als Dateiname den Poststempel haben.
ich glaube, ich habe ein deja-vue, ich meine sowas habe ich schon mal irgendwo gelesen
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Streifenhase1: die erste Variante mit dem Tk-Fenster und den Knöpfen war schon deutlich näher an Deinem Ziel. Jetzt brauchst Du eben noch Knöpfe zum Starten und Stoppen der Aufnahme. Wenn das mal Läuft, kannst Du anfangen, automatisch die Aufnahme zu stoppen, dafür gibt es dann bei TK ›after‹.
Streifenhase1
User
Beiträge: 90
Registriert: Dienstag 22. Mai 2018, 07:15

Soo ich habe jetzt versucht etwas zwecks aufnahmen hin zu bekommen, Mit der Aufnahme in Schleife das nach einer bestimmten Zeit Aufgenommen hat scheint zu funktionieren.
Aber jetzt habe ich ein neues Problem und zwar das während das Script läuft die Buttons nicht mehr gehen bzw. der Button mit dem ich das Script Starte betätigt bleibt.
Könnt ihr mir da Bitte weiterhelfen.

Hier der Teil mit dem Scrip

Code: Alles auswählen

import tkinter as tk
import picamera
import time
import datetime as dt
import datetime
import sched, time


date = datetime.datetime.now().strftime("%d-%m-%Y-%H-%M")
s = sched.scheduler(time.time, time.sleep)

# Aufnahme Pfad #

AUFNAHMEPFAD = "/media/pi/39C7-1803/Aufnahmen/"

# Zeit in Sekunden
AUFNAMEINTERVALL = 300
AUFNAHMEDAUER = 5

def Capture():
    camera.start_preview()
    def do_something(sc):
        
        camera.annotate_background = picamera.Color('black')
        camera.annotate_text = dt.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    
        camera.start_recording(AUFNAHMEPFAD + date + ".h264")
        start = dt.datetime.now()
        while (dt.datetime.now() - start).seconds < AUFNAHMEDAUER:
            camera.annotate_text = dt.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            camera.wait_recording(0.2)
            s.enter(60,1, do_something, (sc,))
    s.enter(60, 1, do_something, (s,))
    s.run()
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn ich mich mal selbst aus diesem Thread von vor 2 Tagen oder so zitieren darf:
__deets__ hat geschrieben: Sonntag 3. Juni 2018, 10:07 Und selbst wenn du das unter Verwendung einer while-Schleife machst, hilft das am Ende auch nichts. Denn du willst ja obendrein eine GUI schreiben, und GUIs können keine while-schleifen vertragen. Dann blockieren sie und werden nutzlos. Stattdessen musst du mit Tkinters after Methode arbeiten. Das wird hier gefühlt in jedem zweiten Forumsbeitrag zu Tkinter erläutert, schau da mal durch die Themen der letzen paar Monate.
Nachtrag:

Hier zB ein einfaches Beispiel: viewtopic.php?f=18&t=42358

Nachtrag 2: das war leider nicht gut, das hier meinte ich: viewtopic.php?f=18&t=42163
Streifenhase1
User
Beiträge: 90
Registriert: Dienstag 22. Mai 2018, 07:15

Mit after das habe ich schon wahr genommen. Weiß aber nicht wie ich das hier richtig einsetze
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

So, wie in den verlinkten Beispielen beschrieben. Statt sched einzusetzen, und wait_recording brauchst Du eben verschieden Funktionen zum Start und zum Stop, die jeweils passend über after aufgerufen werden.
Streifenhase1
User
Beiträge: 90
Registriert: Dienstag 22. Mai 2018, 07:15

Ist noch zu hoch für mich.
Habe auch schon nach Beispielen direkt für Aufnahmen gesucht um.mich besser reindenken zu können aber erfolglos..
Antworten