639 lines
30 KiB
Python
639 lines
30 KiB
Python
import tkinter as tk
|
|
import PIL.Image, PIL.ImageTk
|
|
import numpy as np
|
|
from tkinter import ttk
|
|
from tkinter.font import Font
|
|
from tkinter import filedialog, messagebox
|
|
import subprocess
|
|
import os
|
|
import shutil
|
|
|
|
class User_Interface():
|
|
def __init__(self, camera, preview_processing, gpio_instance, still_image_processing):
|
|
#Instanzvariablen laden
|
|
self.still_image_processing = still_image_processing
|
|
self.preview_processing = preview_processing
|
|
self.gpio_instance = gpio_instance
|
|
self.camera = camera
|
|
self.root = tk.Tk()
|
|
|
|
#Verzögerung des Vorschaubildes
|
|
self.video_feed_delay = 5
|
|
|
|
#Seitenverhältnis der Kamera und des Widgets auslesen, zur Platzierung des Vorschaubildes in diesem
|
|
self.camera_aspect_ratio = self.camera.get_aspect_ratio()
|
|
self.video_widget_aspect_ratio = None
|
|
self.new_width = 1280
|
|
self.new_height = 800
|
|
|
|
#Flags für das derzeit aktive Menü
|
|
self.current_menu_right = None
|
|
self.current_menu_down = None
|
|
self.current_menu_down_right = None
|
|
self.submenu = False
|
|
|
|
#Ein leerer Pixel, wird zur quadratischen Form der Buttons benötigt
|
|
self.pixel = tk.PhotoImage()
|
|
|
|
|
|
self.keyboard_process = None
|
|
|
|
#Parameter des Lineals, mit Aktion verknüpft, sobald der Wert im Eingabefeld geändert wird
|
|
self.ruler_vertical_start = tk.StringVar()
|
|
self.ruler_vertical_end = tk.StringVar()
|
|
self.ruler_horizontal_start = tk.StringVar()
|
|
self.ruler_horizontal_end = tk.StringVar()
|
|
|
|
self.ruler_vertical_start.set(0)
|
|
self.ruler_vertical_end.set(50)
|
|
self.ruler_horizontal_start.set(0)
|
|
self.ruler_horizontal_end.set(100)
|
|
|
|
self.ruler_vertical_start.trace_add("write", lambda var, indx, mode: self.entry_fields_changed("ruler_vertical_start"))
|
|
self.ruler_vertical_end.trace_add("write", lambda var, indx, mode: self.entry_fields_changed("ruler_vertical_end"))
|
|
self.ruler_horizontal_start.trace_add("write", lambda var, indx, mode: self.entry_fields_changed("ruler_horizontal_start"))
|
|
self.ruler_horizontal_end.trace_add("write", lambda var, indx, mode: self.entry_fields_changed("ruler_horizontal_end"))
|
|
|
|
|
|
#Blitz / permanente Beleuchtung an / aus
|
|
self.permanent_lighting = False
|
|
self.activate_flash = False
|
|
|
|
#Vollbild an / aus
|
|
self.fullscreen_active = True
|
|
|
|
# Definiere Schriftarten
|
|
self.font_bold = Font(family="Helvetica", size=12, weight="bold")
|
|
self.font_normal = Font(family="Helvetica", size=12)
|
|
|
|
# Checkbox Größe anpassen
|
|
self.style = ttk.Style()
|
|
self.style.configure("LargeCheckbutton.TCheckbutton", font=self.font_normal, size=25)
|
|
|
|
#Variablen für den Dateinamen, ebenfalls mit Aktion verknüpft
|
|
self.storage_path_var = tk.StringVar(name="storage_path_var")
|
|
self.storage_path_var.set("/home/pi")
|
|
self.destination_path_var = tk.StringVar(name="destination_path_var")
|
|
self.filename_var = tk.StringVar(name="filename_var")
|
|
self.date_var = tk.BooleanVar(name="date_var")
|
|
self.time_var = tk.BooleanVar(name="time_var")
|
|
self.date_var.set(True)
|
|
self.time_var.set(True)
|
|
|
|
self.storage_path_var.trace_add("write", lambda *args: self.entry_fields_changed("Speicherpfad", *args))
|
|
self.destination_path_var.trace_add("write", lambda *args: self.entry_fields_changed("Zielpfad", *args))
|
|
self.filename_var.trace_add("write", lambda *args: self.entry_fields_changed("Dateiname", *args))
|
|
self.date_var.trace_add("write", lambda *args: self.entry_fields_changed("Datum", *args))
|
|
self.time_var.trace_add("write", lambda *args: self.entry_fields_changed("Uhrzeit", *args))
|
|
|
|
|
|
#GUI soll im Vollbild starten
|
|
def window_settings(self):
|
|
self.root.attributes('-fullscreen', True)
|
|
self.root.title('Titel')
|
|
|
|
def start_interface(self):
|
|
self.root.mainloop()
|
|
|
|
#Erstellen der Widgets aller Menüs
|
|
def build_widgets(self):
|
|
self.build_video_widget()
|
|
self.build_hide_menu_button()
|
|
self.main_menu_frame()
|
|
self.crop_menu_frame()
|
|
self.settings_menu_frame()
|
|
self.file_menu_frame()
|
|
self.main_menu_widgets()
|
|
self.crop_menu_widgets()
|
|
self.settings_menu_widgets()
|
|
self.file_menu_widgets()
|
|
|
|
self.root.grid_rowconfigure(0, weight=1)
|
|
self.root.grid_columnconfigure(0, weight=1)
|
|
self.root.grid_columnconfigure(1, minsize=0)
|
|
|
|
|
|
def build_video_widget(self):
|
|
self.video_widget = tk.Canvas(self.root, width=1280, height=800, highlightthickness=0)
|
|
self.video_widget.grid(row=0, column=0, sticky="nsew")
|
|
|
|
#Button "<", ">" zum Anzeigen / Verstecken des Menüs
|
|
def build_hide_menu_button(self):
|
|
self.hide_menu_button_container = tk.Frame(self.video_widget, background="white", bd=0, highlightthickness=0)
|
|
self.hide_menu_button_container.place(relx=1.0, rely=0.0, anchor="ne")
|
|
|
|
self.hide_menu_button_settings = {
|
|
"master": self.hide_menu_button_container,
|
|
"image": self.pixel,
|
|
"compound": "c",
|
|
"height": 30,
|
|
"width": 30,
|
|
"command": self.toggle_menu
|
|
}
|
|
|
|
self.hide_menu_button = tk.Button(**self.hide_menu_button_settings, text="<")
|
|
self.hide_menu_button.pack(side="right", padx=0, pady=0)
|
|
|
|
|
|
#Frames des Hauptmenüs, alle Menüs teilen sich in 3 Frames auf: Rechts vom Vorschaubild, Unter dem Vorschaubild sowie ein Frame unten rechts zwischen dem rechten und dem unteren Frame (2x2-Raster)
|
|
def main_menu_frame(self):
|
|
self.main_menu_frame_right = tk.Frame(self.root)
|
|
self.main_menu_frame_right.grid(row=0, column=1, sticky="nsew")
|
|
|
|
self.main_menu_frame_down = tk.Frame(self.root)
|
|
self.main_menu_frame_down.grid(row=1, column=0, sticky="nsew")
|
|
|
|
self.main_menu_frame_down_right = tk.Frame(self.root)
|
|
self.main_menu_frame_down_right.grid(row=1, column=1, sticky="nsew")
|
|
|
|
self.main_menu_frame_right.grid_remove()
|
|
self.main_menu_frame_down.grid_remove()
|
|
self.main_menu_frame_down_right.grid_remove()
|
|
|
|
|
|
#Frames des Zuschnitt-Menüs
|
|
def crop_menu_frame(self):
|
|
self.crop_menu_frame_right = tk.Frame(self.root)
|
|
self.crop_menu_frame_right.grid(row=0, column=1, sticky="nsew")
|
|
|
|
self.crop_menu_frame_down = tk.Frame(self.root)
|
|
self.crop_menu_frame_down.grid(row=1, column=0, sticky="nsew")
|
|
|
|
self.crop_menu_frame_down_right = tk.Frame(self.root)
|
|
self.crop_menu_frame_down_right.grid(row=1, column=1, sticky="nsew")
|
|
|
|
self.crop_menu_frame_right.grid_remove()
|
|
self.crop_menu_frame_down.grid_remove()
|
|
self.crop_menu_frame_down_right.grid_remove()
|
|
|
|
#Frames des Bildeinstellungsmenüs
|
|
def settings_menu_frame(self):
|
|
self.settings_menu_frame_right = tk.Frame(self.root)
|
|
self.settings_menu_frame_right.grid(row=0, column=1, sticky="nsew")
|
|
|
|
self.settings_menu_frame_down = tk.Frame(self.root)
|
|
self.settings_menu_frame_down.grid(row=1, column=0, sticky="nsew")
|
|
|
|
self.settings_menu_frame_down_right = tk.Frame(self.root)
|
|
self.settings_menu_frame_down_right.grid(row=1, column=1, sticky="nsew")
|
|
|
|
self.settings_menu_frame_right.grid_remove()
|
|
self.settings_menu_frame_down.grid_remove()
|
|
self.settings_menu_frame_down_right.grid_remove()
|
|
|
|
#Frames des Dateimenüs
|
|
def file_menu_frame(self):
|
|
self.file_menu_frame_right = tk.Frame(self.root)
|
|
self.file_menu_frame_right.grid(row=0, column=1, sticky="nsew")
|
|
|
|
self.file_menu_frame_down = tk.Frame(self.root)
|
|
self.file_menu_frame_down.grid(row=1, column=0, sticky="nsew")
|
|
|
|
self.file_menu_frame_down_right = tk.Frame(self.root)
|
|
self.file_menu_frame_down_right.grid(row=1, column=1, sticky="nsew")
|
|
|
|
self.file_menu_frame_right.grid_remove()
|
|
self.file_menu_frame_down.grid_remove()
|
|
self.file_menu_frame_down_right.grid_remove()
|
|
|
|
|
|
#Widgets für das Hauptmenü erstellen
|
|
def main_menu_widgets(self):
|
|
self.settings_menu_button = tk.Button(self.main_menu_frame_right, text="Bild-\neinstellungen", image=self.pixel, compound="c", height=80, width=80, command=self.show_settings_menu)
|
|
self.settings_menu_button.pack(pady=10)
|
|
|
|
self.crop_menu_button = tk.Button(self.main_menu_frame_right, text="Zuschnitt", image=self.pixel, compound="c", height=80, width=80, command=self.show_crop_menu)
|
|
self.crop_menu_button.pack(pady=30)
|
|
|
|
self.file_menu_button = tk.Button(self.main_menu_frame_right, text="Datei-\neinstellungen", image=self.pixel, compound="c", height=80, width=80, command=self.show_file_menu)
|
|
self.file_menu_button.pack(pady=30)
|
|
|
|
buttons_frame_down = tk.Frame(self.main_menu_frame_down)
|
|
buttons_frame_down.pack(pady=10, fill='x', anchor='center')
|
|
|
|
#Einen Frame erstellen, um die beiden unteren Buttons zentriert auszurichten
|
|
buttons_frame_down.grid_columnconfigure(0, weight=1)
|
|
buttons_frame_down.grid_columnconfigure(3, weight=1)
|
|
|
|
# Vollbild beenden Button zentriert im Grid platzieren
|
|
self.fullscreen_button = tk.Button(buttons_frame_down, text="Vollbild beenden", command=self.toggle_fullscreen, width=20)
|
|
self.fullscreen_button.grid(row=0, column=1, padx=20)
|
|
|
|
# Zoom Button zentriert im Grid und neben dem Vollbild beenden Button platzieren
|
|
self.zoom_button_state = tk.BooleanVar(value=False)
|
|
self.zoom_button = tk.Button(buttons_frame_down, text="Zoom", command=self.toggle_zoom, width=20)
|
|
self.zoom_button.grid(row=0, column=2, padx=20)
|
|
|
|
|
|
#Widgets des Zuschnittmenüs / Slider für ROI
|
|
def crop_menu_widgets(self):
|
|
back_button = tk.Button(self.crop_menu_frame_down_right, text="Zurück", image=self.pixel, compound="c", height=40, width=40, command=self.show_main_menu)
|
|
back_button.pack(pady=10)
|
|
|
|
self.crop_width_value = tk.IntVar()
|
|
self.crop_width_slider = tk.Scale(self.crop_menu_frame_down, from_=1280, to=0, resolution= 2, orient='horizontal', variable=self.crop_width_value, command=self.update_value, width=30)
|
|
self.crop_width_slider.pack(fill='x', padx=50)
|
|
self.crop_width_value.set(1280)
|
|
|
|
self.crop_height_value = tk.IntVar()
|
|
self.crop_height_slider = tk.Scale(self.crop_menu_frame_right, from_=800, to=0, resolution= 2, orient='vertical', variable=self.crop_height_value, command=self.update_value, width=30)
|
|
self.crop_height_slider.pack(fill='y', expand=True, pady=25, padx=10)
|
|
self.crop_height_value.set(800)
|
|
|
|
|
|
def settings_menu_widgets(self):
|
|
self.ext_lighting_state = tk.BooleanVar(value=False)
|
|
self.ext_lighting_button = tk.Button(self.settings_menu_frame_right, text="Beleuchtung \nPermanent", image=self.pixel, compound="c", height=80, width=80, command=self.toggle_ext_lighting)
|
|
self.ext_lighting_button.pack(pady=10)
|
|
|
|
self.ext_flash_state = tk.BooleanVar(value=False)
|
|
self.ext_flash_button = tk.Button(self.settings_menu_frame_right, text="Blitz", image=self.pixel, compound="c", height=80, width=80, command=self.toggle_flash)
|
|
self.ext_flash_button.pack(pady=10)
|
|
|
|
back_button = tk.Button(self.settings_menu_frame_down_right, text="Zurück", image=self.pixel, compound="c", height=40, width=40, command=self.show_main_menu)
|
|
back_button.pack(pady=10)
|
|
|
|
self.show_preview_grid_state = tk.BooleanVar(value=False)
|
|
self.show_preview_grid_button = tk.Button(self.settings_menu_frame_right, text="Gitter", image=self.pixel, compound="c", height=80, width=80, command=self.toggle_preview_grid)
|
|
self.show_preview_grid_button.pack(pady=30)
|
|
|
|
|
|
buttons_frame = tk.Frame(self.settings_menu_frame_down)
|
|
buttons_frame.pack(pady=15, fill='x', expand=True)
|
|
|
|
# Button für das Lineal
|
|
self.show_preview_ruler_state = tk.BooleanVar(value=False)
|
|
self.show_preview_ruler_button = tk.Button(buttons_frame, text="Lineal", image=self.pixel, compound="c", height=30, width=80, command=self.toggle_preview_ruler)
|
|
self.show_preview_ruler_button.pack(side='left', padx=20)
|
|
|
|
# Container für Lineal horizontal mit zentrierten Eingabefeldern
|
|
horizontal_ruler_frame = tk.Frame(buttons_frame, height=60)
|
|
horizontal_ruler_frame.pack(side='left', padx=10)
|
|
tk.Label(horizontal_ruler_frame, text="Lineal horizontal", height=1).pack()
|
|
|
|
# Frame für die Eingabefelder, um sie zentriert unter dem Text zu positionieren
|
|
horizontal_ruler_entries_frame = tk.Frame(horizontal_ruler_frame)
|
|
horizontal_ruler_entries_frame.pack()
|
|
tk.Entry(horizontal_ruler_entries_frame, width=5, textvariable=self.ruler_horizontal_start).pack(side='left', padx=(0, 5)) # Ein wenig Platz zwischen den Feldern
|
|
tk.Entry(horizontal_ruler_entries_frame, width=5, textvariable=self.ruler_horizontal_end).pack(side='left')
|
|
|
|
# Container für Lineal vertikal mit zentrierten Eingabefeldern
|
|
vertical_ruler_frame = tk.Frame(buttons_frame, height=60)
|
|
vertical_ruler_frame.pack(side='left', padx=10)
|
|
tk.Label(vertical_ruler_frame, text="Lineal vertikal", height=1).pack()
|
|
|
|
# Frame für die Eingabefelder, um sie zentriert unter dem Text zu positionieren
|
|
vertical_ruler_entries_frame = tk.Frame(vertical_ruler_frame)
|
|
vertical_ruler_entries_frame.pack()
|
|
tk.Entry(vertical_ruler_entries_frame, width=5, textvariable=self.ruler_vertical_start).pack(side='left', padx=(0, 5)) # Ein wenig Platz zwischen den Feldern
|
|
tk.Entry(vertical_ruler_entries_frame, width=5, textvariable=self.ruler_vertical_end).pack(side='left')
|
|
|
|
# Button für die Uhrzeit
|
|
self.show_preview_clock_state = tk.BooleanVar(value=False)
|
|
self.show_preview_clock_button = tk.Button(buttons_frame, text="Uhrzeit", image=self.pixel, compound="c", height=30, width=80, command=self.toggle_preview_clock)
|
|
self.show_preview_clock_button.pack(side='left', padx=20)
|
|
|
|
# Button für die Tastatur
|
|
keyboard_button = tk.Button(buttons_frame, text="Tastatur", image=self.pixel, compound="c", height=30, width=80, command=self.toggle_keyboard)
|
|
keyboard_button.pack(side='left', padx=20)
|
|
|
|
|
|
|
|
|
|
def file_menu_widgets(self):
|
|
back_button_frame = tk.Frame(self.file_menu_frame_down_right)
|
|
back_button_frame.pack(side='right', padx=10, pady=10)
|
|
back_button = tk.Button(back_button_frame, text="Zurück", image=self.pixel, compound="c", height=40, width=40, command=self.show_main_menu)
|
|
back_button.pack()
|
|
|
|
text_font = Font(family="Helvetica", size=14)
|
|
self.style.configure("LargeCheckbutton.TCheckbutton", font=('Helvetica', 14))
|
|
|
|
# "Kopiermenü"-Label
|
|
label_copy_menu = tk.Label(self.file_menu_frame_right, text="Kopieren - Zielordner", font=self.font_bold)
|
|
label_copy_menu.pack(pady=(15, 5))
|
|
|
|
# "Zielpfad"-Bereich
|
|
destination_path_frame = tk.Frame(self.file_menu_frame_right)
|
|
destination_path_frame.pack(pady=5, fill='x', padx=10)
|
|
|
|
self.entry_destination_path = tk.Entry(destination_path_frame, textvariable=self.destination_path_var, font=text_font, width=40)
|
|
self.entry_destination_path.pack(side='left')
|
|
|
|
browse_button_destination = tk.Button(destination_path_frame, text="...", command=lambda: self.choose_directory(self.entry_destination_path))
|
|
browse_button_destination.pack(side='left', padx=(5, 0))
|
|
|
|
# "Kopieren"-Button
|
|
button_copy = tk.Button(self.file_menu_frame_right, text="Kopieren", command=self.copy, font=self.font_normal)
|
|
button_copy.pack(pady=15)
|
|
|
|
keyboard_button = tk.Button(self.file_menu_frame_down, text="Tastatur", font=self.font_normal, command=self.toggle_keyboard)
|
|
keyboard_button.pack(pady=10)
|
|
|
|
# Horizontaler Trennstrich
|
|
separator = ttk.Separator(self.file_menu_frame_right, orient='horizontal')
|
|
separator.pack(fill='x', pady=5)
|
|
|
|
label_file_menu = tk.Label(self.file_menu_frame_right, text="Dateimenü", font=self.font_bold)
|
|
label_file_menu.pack(pady=(5, 5))
|
|
|
|
# "Speicherpfad"-Bereich
|
|
label_storage_path = tk.Label(self.file_menu_frame_right, text="Speicherpfad", font=self.font_normal)
|
|
label_storage_path.pack(pady=5)
|
|
storage_path_frame = tk.Frame(self.file_menu_frame_right)
|
|
storage_path_frame.pack(pady=5, fill='x', padx=10) # padx=10 fügt Abstand zum linken Rand hinzu
|
|
|
|
self.entry_storage_path = tk.Entry(storage_path_frame, textvariable=self.storage_path_var, font=text_font, width=40) # Reduzierte Breite
|
|
self.entry_storage_path.pack(side='left')
|
|
|
|
browse_button_storage = tk.Button(storage_path_frame, text="...", command=lambda: self.choose_directory(self.entry_storage_path))
|
|
browse_button_storage.pack(side='left', padx=(5, 0))
|
|
|
|
# "Dateiname"-Label und Eingabefeld
|
|
label_filename = tk.Label(self.file_menu_frame_right, text="Dateiname", font=self.font_normal)
|
|
label_filename.pack(pady=5)
|
|
self.entry_filename = tk.Entry(self.file_menu_frame_right, textvariable=self.filename_var, font=text_font, width=40)
|
|
self.entry_filename.pack(pady=5)
|
|
|
|
# Gemeinsamer Rahmen für Datum- und Uhrzeit-Checkboxen
|
|
datetime_frame = tk.Frame(self.file_menu_frame_right)
|
|
datetime_frame.pack(pady=5, fill='x')
|
|
|
|
# Datum-Checkbox und Label
|
|
date_frame = tk.Frame(datetime_frame)
|
|
date_frame.pack(side='left', expand=True, padx=5)
|
|
checkbox_date = ttk.Checkbutton(date_frame, text="Datum", style="LargeCheckbutton.TCheckbutton", variable=self.date_var)
|
|
checkbox_date.grid(row=0, column=0, sticky="w")
|
|
date_label = tk.Label(date_frame, text="", font=self.font_normal)
|
|
date_label.grid(row=0, column=1, sticky="w")
|
|
|
|
# Uhrzeit-Checkbox und Label
|
|
time_frame = tk.Frame(datetime_frame)
|
|
time_frame.pack(side='left', expand=True, padx=5)
|
|
checkbox_time = ttk.Checkbutton(time_frame, text="Uhrzeit", style="LargeCheckbutton.TCheckbutton", variable=self.time_var)
|
|
checkbox_time.grid(row=0, column=0, sticky="w")
|
|
time_label = tk.Label(time_frame, text="", font=self.font_normal)
|
|
time_label.grid(row=0, column=1, sticky="w")
|
|
|
|
|
|
#Methode, um die Daten vom Arbeitspfad in den Zielordner zu kopieren
|
|
def copy(self):
|
|
try:
|
|
if not os.path.exists(self.destination_path_var.get()):
|
|
os.makedirs(self.destination_path_var.get())
|
|
|
|
for item in os.listdir(self.storage_path_var.get()):
|
|
source_item = os.path.join(self.storage_path_var.get(), item)
|
|
destination_item = os.path.join(self.destination_path_var.get(), item)
|
|
|
|
if os.path.isdir(source_item):
|
|
shutil.copytree(source_item, destination_item, dirs_exist_ok=True)
|
|
else:
|
|
shutil.copy2(source_item, destination_item)
|
|
|
|
self.show_success_message("Kopieren erfolgreich", "Alle Inhalte wurden erfolgreich kopiert.")
|
|
|
|
except Exception as e:
|
|
messagebox.showerror("Fehler", f"Ein Fehler ist aufgetreten: {e}")
|
|
|
|
|
|
#Methode, um ein Nachrichtenfenster anzuzeigen
|
|
def show_success_message(self, title, message):
|
|
msg_window = tk.Toplevel(self.root)
|
|
msg_window.title(title)
|
|
msg_window.geometry("300x100")
|
|
tk.Label(msg_window, text=message).pack(pady=10)
|
|
|
|
# OK-Button zum Schließen des Fensters
|
|
ok_button = tk.Button(msg_window, text="OK", command=msg_window.destroy)
|
|
ok_button.pack(pady=5)
|
|
|
|
# Fenster automatisch nach 5 Sekunden schließen
|
|
msg_window.after(5000, msg_window.destroy)
|
|
|
|
|
|
#Aktuell aktives Menü schließen
|
|
def close_menu(self):
|
|
self.current_menu_right.grid_remove()
|
|
self.current_menu_down.grid_remove()
|
|
self.current_menu_down_right.grid_remove()
|
|
|
|
#Aktuell aktives Menü öffnen (z.B. nachdem der Button ">", "<" gedrückt wurde)
|
|
def open_menu(self):
|
|
self.current_menu_right.grid()
|
|
self.current_menu_down.grid()
|
|
self.current_menu_down_right.grid()
|
|
self.update_aspect_ratio()
|
|
|
|
def show_main_menu(self):
|
|
self.close_menu()
|
|
self.current_menu_right = self.main_menu_frame_right
|
|
self.current_menu_down = self.main_menu_frame_down
|
|
self.current_menu_down_right = self.main_menu_frame_down_right
|
|
self.open_menu()
|
|
|
|
def show_crop_menu(self):
|
|
self.close_menu()
|
|
self.current_menu_right = self.crop_menu_frame_right
|
|
self.current_menu_down = self.crop_menu_frame_down
|
|
self.current_menu_down_right = self.crop_menu_frame_down_right
|
|
self.open_menu()
|
|
|
|
def show_settings_menu(self):
|
|
self.close_menu()
|
|
self.current_menu_right = self.settings_menu_frame_right
|
|
self.current_menu_down = self.settings_menu_frame_down
|
|
self.current_menu_down_right = self.settings_menu_frame_down_right
|
|
self.open_menu()
|
|
|
|
def show_file_menu(self):
|
|
self.close_menu()
|
|
self.current_menu_right = self.file_menu_frame_right
|
|
self.current_menu_down = self.file_menu_frame_down
|
|
self.current_menu_down_right = self.file_menu_frame_down_right
|
|
self.open_menu()
|
|
|
|
#Methode, um den File-Browser zu öffnen
|
|
def choose_directory(self, entry_field):
|
|
folder_selected = filedialog.askdirectory()
|
|
if folder_selected:
|
|
entry_field.delete(0, tk.END)
|
|
entry_field.insert(0, folder_selected)
|
|
|
|
|
|
#Methode wird ausgeführt, sobald sich der Wert in einem der Eingabefelder geändert hat
|
|
def entry_fields_changed(self, var_name, *args):
|
|
self.still_image_processing.update_file_parameters(self.filename_var.get(), self.storage_path_var.get(),
|
|
self.destination_path_var.get(), self.date_var.get(),
|
|
self.time_var.get())
|
|
|
|
self.ip.update_ruler_values(int(self.ruler_vertical_start.get()), int(self.ruler_vertical_end.get()),
|
|
int(self.ruler_horizontal_start.get()), int(self.ruler_horizontal_end.get()))
|
|
|
|
self.still_image_processing.get_ruler_settings(int(self.ruler_vertical_start.get()), int(self.ruler_vertical_end.get()),
|
|
int(self.ruler_horizontal_start.get()), int(self.ruler_horizontal_end.get()))
|
|
|
|
|
|
#Blendet das Menü ein bzw. aus
|
|
def toggle_menu(self):
|
|
if self.current_menu_right and self.current_menu_right.grid_info():
|
|
self.root.grid_columnconfigure(1, minsize=0)
|
|
self.close_menu()
|
|
self.update_aspect_ratio()
|
|
self.video_widget.grid(row=0, column=0, sticky="nsew")
|
|
self.hide_menu_button.config(text="<")
|
|
|
|
else:
|
|
if not self.current_menu_right:
|
|
self.current_menu_right = self.main_menu_frame_right
|
|
self.current_menu_down = self.main_menu_frame_down
|
|
self.current_menu_down_right = self.main_menu_frame_down_right
|
|
self.root.grid_columnconfigure(1, minsize=30)
|
|
self.open_menu()
|
|
self.menu_width = self.current_menu_right.winfo_width()
|
|
self.video_widget.grid(row=0, column=0, sticky="nsew")
|
|
self.hide_menu_button.config(text=">")
|
|
|
|
|
|
#Methode um die ROI-Werte an die Bildbearbeitung zu übergeben
|
|
def update_value(self, value):
|
|
self.preview_processing.update_roi(self.crop_width_value.get(), self.crop_height_value.get())
|
|
self.still_image_processing.update_roi(self.crop_width_value.get(), self.crop_height_value.get())
|
|
|
|
|
|
|
|
|
|
#Externe Beleuchtung permanent ein- / ausschalten
|
|
def toggle_ext_lighting(self):
|
|
self.ext_lighting_state.set(not self.ext_lighting_state.get())
|
|
self.update_button_appearance(self.ext_lighting_button, self.ext_lighting_state)
|
|
|
|
if self.ext_lighting_state.get():
|
|
self.permanent_lighting = True
|
|
else:
|
|
self.permanent_lighting = False
|
|
self.gpio_instance.get_gui_settings(self.activate_flash, self.permanent_lighting)
|
|
|
|
#Blitz ein- / ausschalten
|
|
def toggle_flash(self):
|
|
self.ext_flash_state.set(not self.ext_flash_state.get())
|
|
self.update_button_appearance(self.ext_flash_button, self.ext_flash_state)
|
|
|
|
if self.ext_flash_state.get():
|
|
self.activate_flash = True
|
|
else:
|
|
self.activate_flash = False
|
|
self.gpio_instance.get_gui_settings(self.activate_flash, self.permanent_lighting)
|
|
|
|
|
|
#Button Gitter ein- aus
|
|
def toggle_preview_grid(self):
|
|
self.show_preview_grid_state.set(not self.show_preview_grid_state.get())
|
|
self.update_button_appearance(self.show_preview_grid_button, self.show_preview_grid_state)
|
|
self.send_settings()
|
|
|
|
#Button Lineal ein- aus
|
|
def toggle_preview_ruler(self):
|
|
self.show_preview_ruler_state.set(not self.show_preview_ruler_state.get())
|
|
self.update_button_appearance(self.show_preview_ruler_button, self.show_preview_ruler_state)
|
|
self.send_settings()
|
|
|
|
#Button Uhr ein - aus
|
|
def toggle_preview_clock(self):
|
|
self.show_preview_clock_state.set(not self.show_preview_clock_state.get())
|
|
self.update_button_appearance(self.show_preview_clock_button, self.show_preview_clock_state)
|
|
self.send_settings()
|
|
|
|
#Button Zoom ein- aus
|
|
def toggle_zoom(self):
|
|
self.zoom_button_state.set(not self.zoom_button_state.get())
|
|
self.update_button_appearance(self.zoom_button, self.zoom_button_state)
|
|
self.change_preview_resolution()
|
|
self.send_settings()
|
|
|
|
|
|
#Aussehen der Toggle-Buttons variieren
|
|
def update_button_appearance(self, button, state_var):
|
|
if state_var.get():
|
|
button.config(relief="sunken", bg="dimgray") # Eingeschalteter Zustand
|
|
|
|
else:
|
|
button.config(relief="raised", bg="lightgray") # Ausgeschalteter Zustand
|
|
|
|
|
|
#Einstellungen der Toggle-Buttons an die bildverarbeitenden Instanzen übergeben
|
|
def send_settings(self):
|
|
self.preview_processing.get_settings(self.show_preview_grid_state.get(), self.show_preview_ruler_state.get(),
|
|
self.show_preview_clock_state.get(), self.zoom_button_state.get())
|
|
|
|
self.still_image_processing.update_picture_parameters(self.show_preview_clock_state.get(),
|
|
self.show_preview_ruler_state.get())
|
|
|
|
|
|
#Seitenverhältnis anpassen, sodass das video_widget sich entsprechend der ROI anpasst
|
|
def update_aspect_ratio(self):
|
|
self.root.update_idletasks()
|
|
self.video_widget_width = self.video_widget.winfo_width()
|
|
self.video_widget_height = self.video_widget.winfo_height()
|
|
self.video_widget_aspect_ratio = self.video_widget_width / self.video_widget_height
|
|
|
|
if self.video_widget_aspect_ratio is None:
|
|
self.new_width = 1280
|
|
self.new_height = 800
|
|
else:
|
|
self.new_width = self.video_widget_width
|
|
self.new_height = int(self.new_width / self.camera_aspect_ratio)
|
|
|
|
#Tastatur ein- aus
|
|
def toggle_keyboard(self):
|
|
if self.keyboard_process:
|
|
self.keyboard_process.terminate()
|
|
self.keyboard_process = None
|
|
else:
|
|
self.keyboard_process = subprocess.Popen(['matchbox-keyboard'])
|
|
|
|
|
|
#Vorschaubild im video_widget aktualisieren
|
|
def update_video_widget(self):
|
|
image = self.camera.get_preview_image() #Bild aus der Kamera holen
|
|
image = self.preview_processing.get_preview_image(image) # Weitere Bildverarbeitung
|
|
|
|
#Abfragen, falls das Bild in einem unerwarteten Format auftritt
|
|
if image.shape[2] not in [3, 4]:
|
|
raise ValueError("Das Bild muss 3 (RGB) oder 4 (RGBA) Farbkanäle haben")
|
|
|
|
if image.dtype != np.uint8:
|
|
image = (image - image.min()) / (image.max() - image.min()) * 255.0
|
|
image = image.astype(np.uint8)
|
|
|
|
# Erzeugen des PIL-Bildes aus dem Array und Skalieren auf die neue Größe
|
|
resized_image = PIL.Image.fromarray(image).resize((self.new_width, self.new_height), PIL.Image.ANTIALIAS)
|
|
|
|
self.preview_image = PIL.ImageTk.PhotoImage(image=resized_image)
|
|
self.video_widget.create_image(0, 0, image=self.preview_image, anchor=tk.NW)
|
|
self.root.after(self.video_feed_delay, self.update_video_widget)
|
|
|
|
|
|
#Erhöhen der Vorschauauflösung, um den gezoomten Bereich klarer darzustellen
|
|
def change_preview_resolution(self):
|
|
self.camera.get_highres_preview()
|
|
|
|
|
|
#Vollbild ein- ausschalten
|
|
def toggle_fullscreen(self):
|
|
if self.fullscreen_active == True:
|
|
self.root.attributes('-fullscreen', False)
|
|
self.fullscreen_button.config(text="Vollbild")
|
|
self.fullscreen_active = False
|
|
|
|
else:
|
|
self.root.attributes('-fullscreen', True)
|
|
self.fullscreen_button.config(text="Vollbild beenden")
|
|
self.fullscreen_active = True
|
|
|
|
|
|
|
|
|
|
|
|
|