import cv2 import numpy as np import math import datetime import os class Still_Image_Processing(): def __init__(self): #Einstellungen für den Dateinamen / Kopiermenü self.file_name_gui = "" self.storage_path = "/home/pi" self.copy_path = "" self.filename_add_date = False self.filename_add_time = False self.filename = "" #Flags, ob die Zeit bzw. das Lineal im finalen Bild zu sehen sind self.add_time = False self.add_ruler = False #Parameter des Vorschaubilds und des finalen Bilds, werden zur Skalierung benötigt self.preview_width = 800 self.preview_height = 480 self.preview_width_roi = 800 self.preview_height_roi = 480 self.still_width_roi = 4056 self.still_height_roi = 3040 self.still_width = 4056 self.still_height = 3040 #Parameter für ROI self.still_width_offset = 0 self.still_height_offset = 0 #Einstellungen für die Uhr self.font = cv2.FONT_HERSHEY_SIMPLEX self.font_size = 1 self.font_color = (0, 0, 0, 255) self.background_color = (255, 255, 255, 255) self.text_thickness = 2 self.line_type = cv2.LINE_AA #Einstellungen für das Lineal self.horizontal_ruler_start = 0 self.horizontal_ruler_end = 100 self.vertical_ruler_start = 0 self.vertical_ruler_end = 50 self.ruler_thickness = 80 self.ruler_font_size = 2 self.ruler_font = cv2.FONT_HERSHEY_PLAIN self.ruler_color = (255, 255, 255, 255) # Weiß self.ruler_text_color = (0, 0, 0, 255) # Schwarz self.ruler_line_color = (0, 0, 0, 255) # Schwarz self.ruler_initial_width = self.preview_width self.ruler_initial_height = self.preview_height self.still_image = None #Einstellungen für Dateinamen werden durch die Benutzeroberfläche definiert def update_file_parameters(self, file_name, storage_path, copy_path, filename_add_date, filename_add_time): self.file_name_gui = file_name self.storage_path = storage_path self.copy_path = copy_path self.filename_add_date = filename_add_date self.filename_add_time = filename_add_time #Bildung des Dateinamens. Standard ist "Bild-{Nummerierung}". Ggf. kann das Bild mit Datum / Zeit versehen werden oder einen individuellen Namen erhalten def update_filename(self): base_name = self.file_name_gui.rstrip(".png") if self.file_name_gui else "Bild" time_date_now = datetime.datetime.now() if self.filename_add_date: base_name += time_date_now.strftime("_%Y-%m-%d") if self.filename_add_time: base_name += time_date_now.strftime("_%H-%M-%S") final_name = base_name counter = 1 while os.path.exists(os.path.join(self.storage_path, final_name + ".png")): #Wenn Bild mit dem Namen bereits existiert, wird der Zähler erhöht, bis kein Bild gefunden wurde final_name = f"{base_name}-{counter}" counter += 1 self.file_name = os.path.join(self.storage_path, final_name + ".png") #Methode zum Speichern des Bildes def save_picture(self): self.update_filename() rgb_image = cv2.cvtColor(self.still_image, cv2.COLOR_BGR2RGB) #Konvertierung von BGR zu RGB erforderlich cv2.imwrite(self.file_name, rgb_image) #Es wird aus der GUI übergeben, ob die Uhr bzw. das Lineal angezeigt werden sollen def update_picture_parameters(self, add_time_to_image, add_ruler_to_image): self.add_time = add_time_to_image self.add_ruler = add_ruler_to_image #Aktualisieren der ROI und der erforderlichen Parameter def update_roi(self, roi_width, roi_height): self.preview_width_roi = roi_width self.preview_height_roi = roi_height self.roi_width_factor = self.preview_width_roi / self.preview_width self.roi_height_factor = self.preview_height_roi / self.preview_height self.still_width_roi = round(self.roi_width_factor * self.still_width) self.still_height_roi = round(self.roi_height_factor * self.still_height) self.still_width_offset = round(((self.still_width - self.still_width_roi) / 2)) self.still_height_offset = round(((self.still_height - self.still_height_roi) / 2)) #Uhrzeit im Bild einblenden def add_time_to_image(self): if self.add_time == True: timestamp = datetime.datetime.now().strftime("%H:%M") image_height, image_width = self.still_image.shape[:2] # Abstand vom linken Rand abhängig vom Lineal margin_x = self.ruler_thickness + 5 if self.add_ruler else 5 # Konstanter Abstand vom unteren Rand margin_y = 30 # Padding erhöhen, um die Box größer zu machen padding = 5 # Dynamische Schriftgröße basierend auf Bildhöhe font_scale = image_height / 800 # Textgröße und -position berechnen (text_width, text_height), base_line = cv2.getTextSize(timestamp, self.font, font_scale, self.text_thickness) # Die y-Position des Textes unter Berücksichtigung des unteren Randes text_position_y = image_height - margin_y - base_line - padding text_position = (margin_x + padding, text_position_y) # Berechnung der Hintergrundpositionen background_l = (text_position[0] - padding, text_position[1] - text_height - padding) background_r = (text_position[0] + text_width + padding, text_position[1] + base_line + padding) cv2.rectangle(self.still_image, background_l, background_r, self.background_color, -1) cv2.putText(self.still_image, timestamp, text_position, self.font, font_scale, self.font_color, self.text_thickness, self.line_type) #Einstellungen des Lineals aus der Benutzeroberfläche laden def get_ruler_settings(self, ruler_vertical_start, ruler_vertical_end, ruler_horizontal_start, ruler_horizontal_end): self.vertical_ruler_start = ruler_vertical_start self.vertical_ruler_end = ruler_vertical_end self.horizontal_ruler_start = ruler_horizontal_start self.horizontal_ruler_end = ruler_horizontal_end #Erforderliche Einstellungen des Lineals bearbeiten, dieses passt sich an den linken bzw. oberen Bildrand an def update_ruler_settings(self): self.ruler_scaling_width = self.still_image.shape[1] / self.still_width self.ruler_scaling_height = self.still_image.shape[0] / self.still_height self.ruler_horizontal_end = (self.horizontal_ruler_end - self.horizontal_ruler_start) * self.ruler_scaling_width self.ruler_vertical_end = (self.vertical_ruler_end - self.vertical_ruler_start) * self.ruler_scaling_height self.px_mm_horizontal = math.ceil(self.still_image.shape[1] / self.ruler_horizontal_end) self.px_mm_vertical = math.ceil(self.still_image.shape[0] / self.ruler_vertical_end) def add_ruler_to_image(self): if self.add_ruler: self.update_ruler_settings() # Initialisierung des horizontalen Lineals am oberen Rand als RGB-Bild self.ruler_horizontal = np.zeros((self.ruler_thickness, self.still_image.shape[1], 3), dtype=np.uint8) self.ruler_horizontal[:, :] = self.ruler_color[:3] self.ruler_vertical = np.zeros((self.still_image.shape[0], self.ruler_thickness, 3), dtype=np.uint8) self.ruler_vertical[:, :] = self.ruler_color[:3] # Markierungen und Beschriftungen zum horizontalen Lineal hinzufügen for pos in range(self.ruler_thickness, self.still_image.shape[1], self.px_mm_horizontal * 5): is_thick_line = (pos-self.ruler_thickness) % (self.px_mm_horizontal * 10) == 0 line_thickness = 2 if is_thick_line else 1 cv2.line(self.ruler_horizontal, (pos, 0), (pos, self.ruler_thickness), self.ruler_line_color, line_thickness) if is_thick_line: text = f"{int((pos-self.ruler_thickness) / self.px_mm_horizontal)}" text_x = pos + self.ruler_thickness // 2 - cv2.getTextSize(text, self.ruler_font, self.ruler_font_size, 1)[0][0] // 2 text_y = self.ruler_thickness - 5 cv2.putText(self.ruler_horizontal, text, (text_x, text_y), self.ruler_font, self.ruler_font_size, self.ruler_text_color, 1) # Markierungen und Beschriftungen zum vertikalen Lineal hinzufügen for pos in range(self.ruler_thickness, self.still_image.shape[0], self.px_mm_vertical * 5): is_thick_line = (pos-self.ruler_thickness) % (self.px_mm_vertical * 10) == 0 line_thickness = 2 if is_thick_line else 1 cv2.line(self.ruler_vertical, (0, pos), (self.ruler_thickness, pos), self.ruler_line_color, line_thickness) if is_thick_line: text = f"{int((pos-self.ruler_thickness) / self.px_mm_vertical)}" cv2.putText(self.ruler_vertical, text, (2, pos - 5), self.ruler_font, self.ruler_font_size, self.ruler_text_color, 1) # Anbringen des horizontalen Lineals am oberen Rand des Bildes self.still_image[:self.ruler_thickness, :] = self.ruler_horizontal # Anbringen des vertikalen Lineals am linken Rand des Bildes self.still_image[:, :self.ruler_thickness] = self.ruler_vertical #Alle Schritte zur Bearbeitung des finalen Bildes def process_image(self, image): self.still_image = image self.crop_image() self.add_time_to_image() self.add_ruler_to_image() self.save_picture() #Der in der ROI definierten Bildbereich extrahieren def crop_image(self): if self.still_width_roi != self.still_width or self.still_height_roi != self.still_height: self.still_image = self.still_image[self.still_height_offset:(self.still_height - self.still_height_offset), self.still_width_offset:(self.still_width - self.still_width_offset), :]