ropecam/1280 x 800/Gui_Grid.py
2025-02-17 14:52:43 +01:00

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