|
|
import customtkinter as ctk
|
|
|
from tkinter import filedialog, messagebox, StringVar, Menu, DoubleVar
|
|
|
from PIL import Image, ImageTk, ImageEnhance
|
|
|
import numpy as np
|
|
|
import torch
|
|
|
import random
|
|
|
import cv2
|
|
|
import time
|
|
|
|
|
|
|
|
|
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
|
|
print(f"Verwendetes Gerät: {device}")
|
|
|
|
|
|
|
|
|
class Connection:
|
|
|
def __init__(self, target_node, weight=None):
|
|
|
self.target_node = target_node
|
|
|
self.weight = weight if weight is not None else random.uniform(0.1, 1.0)
|
|
|
self.weight_history = []
|
|
|
|
|
|
|
|
|
class Node:
|
|
|
def __init__(self, label):
|
|
|
self.label = label
|
|
|
self.connections = []
|
|
|
self.activation = 0.0
|
|
|
self.activation_history = []
|
|
|
|
|
|
def add_connection(self, target_node, weight=None):
|
|
|
self.connections.append(Connection(target_node, weight))
|
|
|
|
|
|
def propagate_signal(self, input_signal):
|
|
|
self.activation = max(0, input_signal)
|
|
|
self.activation_history.append(self.activation)
|
|
|
for connection in self.connections:
|
|
|
connection.target_node.activation += self.activation * connection.weight
|
|
|
connection.weight_history.append(connection.weight)
|
|
|
|
|
|
|
|
|
class ImageNode(Node):
|
|
|
def __init__(self, label):
|
|
|
super().__init__(label)
|
|
|
self.image = None
|
|
|
|
|
|
def generate_image(self, category_nodes, original_image, brightness_factor, contrast_factor):
|
|
|
self.image = self.generate_image_from_categories(category_nodes, original_image, brightness_factor, contrast_factor)
|
|
|
|
|
|
def generate_image_from_categories(self, category_nodes, original_image, brightness_factor, contrast_factor):
|
|
|
image_array = np.array(original_image) / 255.0
|
|
|
image_tensor = torch.tensor(image_array, dtype=torch.float32).permute(2, 0, 1).to(device)
|
|
|
|
|
|
modified_image_tensor = self.process_image(image_tensor, category_nodes, brightness_factor, contrast_factor)
|
|
|
return modified_image_tensor
|
|
|
|
|
|
def process_image(self, image_tensor, category_nodes, brightness_factor, contrast_factor):
|
|
|
modified_image_tensor = image_tensor.clone()
|
|
|
for x in range(modified_image_tensor.shape[1]):
|
|
|
for y in range(modified_image_tensor.shape[2]):
|
|
|
pixel = modified_image_tensor[:, x, y]
|
|
|
brightness = float(brightness_factor)
|
|
|
contrast = float(contrast_factor)
|
|
|
for node in category_nodes:
|
|
|
brightness += node.activation * 0.1
|
|
|
contrast += node.activation * 0.1
|
|
|
pixel = torch.clamp((pixel - 0.5) * contrast + 0.5 + brightness, 0, 1)
|
|
|
modified_image_tensor[:, x, y] = pixel
|
|
|
return modified_image_tensor
|
|
|
|
|
|
def get_color_from_label(self, label):
|
|
|
color_map = {
|
|
|
"Rot": torch.tensor([1, 0, 0], device=device),
|
|
|
"Grün": torch.tensor([0, 1, 0], device=device),
|
|
|
"Blau": torch.tensor([0, 0, 1], device=device),
|
|
|
"Gelb": torch.tensor([1, 1, 0], device=device),
|
|
|
"Cyan": torch.tensor([0, 1, 1], device=device),
|
|
|
"Magenta": torch.tensor([1, 0, 1], device=device)
|
|
|
}
|
|
|
return color_map.get(label, torch.tensor([1, 1, 1], device=device))
|
|
|
|
|
|
|
|
|
def extract_main_colors(image):
|
|
|
image_array = np.array(image)
|
|
|
colors = {}
|
|
|
for i in range(image_array.shape[0]):
|
|
|
for j in range(image_array.shape[1]):
|
|
|
color = tuple(image_array[i, j])
|
|
|
if sum(color) > 30:
|
|
|
if color in colors:
|
|
|
colors[color] += 1
|
|
|
else:
|
|
|
colors[color] = 1
|
|
|
|
|
|
sorted_colors = sorted(colors.items(), key=lambda item: item[1], reverse=True)
|
|
|
main_colors = [color for color, count in sorted_colors[:6]]
|
|
|
|
|
|
|
|
|
scaled_colors = [(min(c[0] + 50, 255), min(c[1] + 50, 255), min(c[2] + 50, 255)) for c in main_colors]
|
|
|
return scaled_colors
|
|
|
|
|
|
|
|
|
def create_neural_network(main_colors):
|
|
|
category_nodes = [Node(label) for label in ["Rot", "Grün", "Blau", "Gelb", "Cyan", "Magenta"]]
|
|
|
for node in category_nodes:
|
|
|
for target_node in category_nodes:
|
|
|
if node != target_node:
|
|
|
node.add_connection(target_node, weight=random.uniform(0.01, 8.0))
|
|
|
return category_nodes
|
|
|
|
|
|
|
|
|
def save_image(image_tensor, filename, resolution, original_size=None):
|
|
|
resolutions = {
|
|
|
"HD": (1280, 720),
|
|
|
"Full HD": (1920, 1080),
|
|
|
"2K": (2048, 2048),
|
|
|
"4K": (5760, 3240),
|
|
|
"8K": (10670, 6000),
|
|
|
"Cover": (1024, 1024),
|
|
|
"Original (2K)": (2048,2048)
|
|
|
}
|
|
|
|
|
|
if resolution == "Original (2K)" and original_size:
|
|
|
width, height = original_size
|
|
|
else:
|
|
|
width, height = resolutions.get(resolution, (1920, 1080))
|
|
|
|
|
|
image = Image.fromarray((image_tensor.cpu().numpy().transpose(1, 2, 0) * 255).astype(np.uint8))
|
|
|
image = image.resize((width, height), Image.Resampling.LANCZOS)
|
|
|
image.save(filename, format='PNG')
|
|
|
print(f"Bild erfolgreich gespeichert als {filename} mit Auflösung {resolution}")
|
|
|
|
|
|
|
|
|
def sharpen_image(image):
|
|
|
enhancer = ImageEnhance.Sharpness(image)
|
|
|
sharpened_image = enhancer.enhance(1.5)
|
|
|
return sharpened_image
|
|
|
|
|
|
|
|
|
def match_histogram(source, template):
|
|
|
source = cv2.cvtColor(np.array(source), cv2.COLOR_RGB2LAB).astype("float32")
|
|
|
template = cv2.cvtColor(np.array(template), cv2.COLOR_RGB2LAB).astype("float32")
|
|
|
|
|
|
(l, a, b) = cv2.split(source)
|
|
|
(lH, aH, bH) = cv2.split(template)
|
|
|
|
|
|
|
|
|
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
|
|
|
l = clahe.apply((l * 255).astype(np.uint8)) / 255.0
|
|
|
|
|
|
|
|
|
a = cv2.equalizeHist((a * 255).astype(np.uint8)) / 255.0
|
|
|
b = cv2.equalizeHist((b * 255).astype(np.uint8)) / 255.0
|
|
|
|
|
|
result = cv2.merge((l, a, b))
|
|
|
result = cv2.cvtColor(result.astype("uint8"), cv2.COLOR_LAB2RGB)
|
|
|
|
|
|
return Image.fromarray(result)
|
|
|
|
|
|
|
|
|
def load_image():
|
|
|
file_path = filedialog.askopenfilename(filetypes=[("Image Files", "*.png;*.jpg;*.jpeg;*.bmp;*.gif")])
|
|
|
if file_path:
|
|
|
image = Image.open(file_path)
|
|
|
|
|
|
|
|
|
global original_image_size
|
|
|
original_image_size = image.size
|
|
|
|
|
|
image = image.resize((1920, 1080), Image.Resampling.LANCZOS)
|
|
|
img_tk = ImageTk.PhotoImage(image)
|
|
|
image_label.configure(image=img_tk)
|
|
|
image_label.image = img_tk
|
|
|
global loaded_image
|
|
|
loaded_image = image
|
|
|
|
|
|
|
|
|
global brightness_var, contrast_var
|
|
|
brightness_value = calculate_brightness(image)
|
|
|
contrast_value = calculate_contrast(image)
|
|
|
|
|
|
brightness_var.set(brightness_value)
|
|
|
contrast_var.set(contrast_value)
|
|
|
|
|
|
print(f"Bild geladen: {file_path}")
|
|
|
|
|
|
def calculate_brightness(image):
|
|
|
image_array = np.array(image).astype(float)
|
|
|
mean_brightness = np.mean(image_array) / 255.0
|
|
|
|
|
|
return (mean_brightness * 2) -1
|
|
|
|
|
|
def calculate_contrast(image):
|
|
|
image_array = np.array(image).astype(float)
|
|
|
mean_brightness = np.mean(image_array)
|
|
|
|
|
|
|
|
|
std_dev = np.std(image_array)
|
|
|
contrast = (std_dev / 128.0)
|
|
|
|
|
|
|
|
|
contrast = (contrast * 1.0) + 1.0
|
|
|
contrast = max(0.5, min(2.0, contrast))
|
|
|
|
|
|
return contrast
|
|
|
|
|
|
|
|
|
def generate_image():
|
|
|
if loaded_image:
|
|
|
start_time = time.time()
|
|
|
|
|
|
|
|
|
main_colors = extract_main_colors(loaded_image)
|
|
|
print(f"Hauptfarbwerte: {main_colors}")
|
|
|
|
|
|
|
|
|
if len(main_colors) < 6 or all(sum(color) < 150 for color in main_colors):
|
|
|
print("Hauptfarben zu dunkel oder zu wenige Farben, Standardfarben werden verwendet.")
|
|
|
main_colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (0, 255, 255), (255, 0, 255)]
|
|
|
|
|
|
|
|
|
main_colors = [(r / 255.0, g / 255.0, b / 255.0) for r, g, b in main_colors]
|
|
|
|
|
|
|
|
|
category_nodes = create_neural_network(main_colors)
|
|
|
|
|
|
|
|
|
for node, color in zip(category_nodes, main_colors):
|
|
|
node.activation = sum(color) / 3
|
|
|
print(f"Knoten {node.label}: Aktivierung = {node.activation}, Farbe = {color}")
|
|
|
|
|
|
|
|
|
brightness_factor = brightness_var.get()
|
|
|
contrast_factor = contrast_var.get()
|
|
|
image_node = ImageNode("Image")
|
|
|
image_node.generate_image(category_nodes, loaded_image, brightness_factor, contrast_factor)
|
|
|
|
|
|
|
|
|
generated_image = Image.fromarray((image_node.image.cpu().numpy().transpose(1, 2, 0) * 255).astype(np.uint8))
|
|
|
generated_image = sharpen_image(generated_image)
|
|
|
generated_image = match_histogram(generated_image, loaded_image)
|
|
|
generated_image = generated_image.resize((64, 64), Image.Resampling.LANCZOS)
|
|
|
img_tk = ImageTk.PhotoImage(generated_image)
|
|
|
generated_image_label.configure(image=img_tk)
|
|
|
generated_image_label.image = img_tk
|
|
|
|
|
|
|
|
|
resolution = resolution_var.get()
|
|
|
save_image(image_node.image, "kunst.png", resolution, original_size=original_image_size if resolution == "Original (2K)" else None)
|
|
|
|
|
|
end_time = time.time()
|
|
|
generation_time = end_time - start_time
|
|
|
print(f"Bild erfolgreich generiert und angezeigt. Generierungszeit: {generation_time:.2f} Sekunden")
|
|
|
else:
|
|
|
messagebox.showwarning("Warnung", "Bitte laden Sie zuerst ein Bild.")
|
|
|
|
|
|
|
|
|
def start_gui():
|
|
|
global image_label, generated_image_label, loaded_image, resolution_var, brightness_var, contrast_var, original_image_size
|
|
|
loaded_image = None
|
|
|
original_image_size = None
|
|
|
|
|
|
ctk.set_appearance_mode("dark")
|
|
|
ctk.set_default_color_theme("blue")
|
|
|
|
|
|
root = ctk.CTk()
|
|
|
root.title("Bildgenerierung")
|
|
|
root.geometry("550x400")
|
|
|
|
|
|
|
|
|
menubar = Menu(root)
|
|
|
root.config(menu=menubar)
|
|
|
|
|
|
file_menu = Menu(menubar, tearoff=0)
|
|
|
menubar.add_cascade(label="Datei", menu=file_menu)
|
|
|
file_menu.add_command(label="Bild laden", command=load_image)
|
|
|
file_menu.add_command(label="Bild generieren", command=generate_image)
|
|
|
file_menu.add_separator()
|
|
|
file_menu.add_command(label="Beenden", command=root.quit)
|
|
|
|
|
|
resolution_var = StringVar(value="Full HD")
|
|
|
resolution_label = ctk.CTkLabel(root, text="Bildauflösung:")
|
|
|
resolution_label.pack(pady=5)
|
|
|
resolution_combobox = ctk.CTkComboBox(root, variable=resolution_var, values=["HD", "2K", "Full HD", "4K", "8K", "Cover", "Original (2K)"])
|
|
|
resolution_combobox.pack(pady=5)
|
|
|
|
|
|
brightness_var = DoubleVar(value=0.0)
|
|
|
brightness_label = ctk.CTkLabel(root, text="Helligkeit:")
|
|
|
brightness_label.pack(pady=5)
|
|
|
brightness_scale = ctk.CTkSlider(root, from_=-1.0, to=1.0, number_of_steps=20, orientation=ctk.HORIZONTAL, variable=brightness_var)
|
|
|
brightness_scale.pack(pady=5)
|
|
|
|
|
|
contrast_var = DoubleVar(value=1.0)
|
|
|
contrast_label = ctk.CTkLabel(root, text="Kontrast:")
|
|
|
contrast_label.pack(pady=5)
|
|
|
contrast_scale = ctk.CTkSlider(root, from_=0.5, to=2.0, number_of_steps=15, orientation=ctk.HORIZONTAL, variable=contrast_var)
|
|
|
contrast_scale.pack(pady=5)
|
|
|
|
|
|
image_label = ctk.CTkLabel(root)
|
|
|
image_label.pack(pady=10)
|
|
|
|
|
|
generated_image_label = ctk.CTkLabel(root)
|
|
|
generated_image_label.pack(pady=10)
|
|
|
|
|
|
root.mainloop()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
start_gui() |