267 lines
10 KiB
Python
267 lines
10 KiB
Python
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 = 1280
|
|
self.preview_height = 800
|
|
self.preview_width_roi = 1280
|
|
self.preview_height_roi = 800
|
|
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), :]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|