Incident: CI-Verlust in Bild-KI

Das Problem: Generierte KI-Bilder aus unserem Stable-Diffusion-XL-basierten Bildgenerator ignorierten spezifische Brand-Hex-Codes systematisch. Aus dem exakten Askeve-Grünton (#44d6a5 = RGB 68, 214, 165) wurde in der vollautomatisierten Generierung von Social-Media-Grafiken je nach Seed ein Mint (#5DEFE0), ein Neonblau (#44B3D6) oder ein zu gesättigtes Grasgrün (#44D667). Über 200 automatisch generierte LinkedIn-Banner und Instagram-Posts in zwei Wochen: davon nur 34 % on-brand, 66 % mussten manuell nachbearbeitet werden.

Warum Diffusionsmodelle Hex-Codes nicht deterministisch umsetzen

Das fundamentale Problem liegt in der Natur von Diffusionsmodellen: SDXL operiert im latenten Raum, einem komprimierten 4-Kanal-Repräsentationsraum (bei SDXL mit 128×128 Latents für 1024×1024-Ausgaben). Farbinformationen sind dort nicht als diskrete RGB-Werte kodiert, sondern als kontinuierliche, hochdimensionale Aktivierungsmuster. Das Modell hat während des Trainings auf Milliarden von Bild-Text-Paaren gelernt, welche visuellen Konzepte mit welchen Textbeschreibungen korrelieren. Der Begriff „türkis" oder „aquamarin" ist ein diffuses Cluster im CLIP-Text-Embedding-Raum, das zu einem breiten Spektrum ähnlicher Farbtöne führt. Eine exakte Hex-Angabe im Prompt wird intern durch CLIP tokenisiert und verliert dabei ihre metrische Präzision – CLIP hat keine Arithmetik über Farbcodes gelernt, sondern Assoziationen. Prompt-Gewichtungen wie (exact color #44d6a5:2.0) verstärken nur das Konzept „dieser Farbton", treffen aber niemals reproduzierbar den exakten Hex-Wert.

Color Matching Split Screen

Der deterministische OpenCV Hybrid-Ansatz

Die Lösung kombiniert das Kreativpotenzial der KI mit der mathematischen Präzision klassischer Computer Vision. Phase 1 (KI-Generierung): SDXL generiert das Bild mit einem Prompt, der bewusst keine exakten Farbangaben enthält, sondern nur Motiv und visuellen Stil beschreibt. Das Modell produziert Komposition, Beleuchtung und Textur – alles, was es gut kann. Phase 2 (OpenCV-Farbkorrektur): Das generierte Bild wird an eine Python-Pipeline übergeben. Schritt 1: Konvertierung von BGR nach HSV-Farbraum, da HSV eine semantisch sinnvollere Segmentierung von Farbbereichen erlaubt als RGB. Schritt 2: Definition einer HSV-Maske für alle Pixel im Ziel-Farbbereich (Hue: 150–170°, Saturation: >40, Value: >40 – entspricht dem grün-türkisen Cluster). Schritt 3: Ersetzen aller gemaskten Pixel mit dem exakten Ziel-BGR-Wert. Kritisch für die Bildqualität: Vor der Ersetzung wird eine Gaussian-Blur-Maske mit Kernel-Größe 5×5 auf die Maskenränder angewendet, um harte Farbschnitte an Objektgrenzen zu vermeiden.

import cv2
import numpy as np
from pathlib import Path

# Askeve Brand Color in OpenCV BGR format (note: OpenCV uses BGR, not RGB)
# Hex #44D6A5 = R:68, G:214, B:165 -> BGR = [165, 214, 68]
ASKEVE_GREEN_BGR = np.array([165, 214, 68])

def enforce_brand_color(
    image_path: str,
    output_path: str,
    target_bgr = ASKEVE_GREEN_BGR,
    hue_range: tuple = (150, 170),
    edge_blend_kernel: int = 5
) -> dict:
    image = cv2.imread(image_path)
    original = image.copy()
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

    # Segment all pixels in the target hue range
    lower = np.array([hue_range[0], 40, 40])
    upper = np.array([hue_range[1], 255, 255])
    mask = cv2.inRange(hsv, lower, upper)

    # Soft edge blending to prevent hard color cuts at object boundaries
    mask_blurred = cv2.GaussianBlur(mask, (edge_blend_kernel, edge_blend_kernel), 0)
    mask_normalized = mask_blurred / 255.0

    # Create target color layer and blend
    color_layer = np.full_like(image, target_bgr)
    for c in range(3):  # BGR channels
        image[:, :, c] = (
            color_layer[:, :, c] * mask_normalized +
            original[:, :, c] * (1 - mask_normalized)
        ).astype(np.uint8)

    cv2.imwrite(output_path, image)
    pixels_corrected = int(np.sum(mask > 0))
    return {
        'output': output_path,
        'pixels_corrected': pixels_corrected,
        'coverage_pct': round(pixels_corrected / mask.size * 100, 2)
    }

# Automated batch processing
for img_path in Path('generated/').glob('*.png'):
    result = enforce_brand_color(str(img_path), f'branded/{img_path.name}')
    print(f'[BRAND] {img_path.name}: {result["coverage_pct"]}% corrected')

Automatisierte QA und Ergebnis

Nach der Farbkorrektur läuft ein automatischer QA-Check: Ein separates Skript berechnet den Delta-E-Wert zwischen den korrigierten Pixeln und dem Ziel-Hex im CIELAB-Farbraum (der wahrnehmungslinear ist). Delta-E < 2 gilt als „nicht vom menschlichen Auge unterscheidbar". Unser Post-Processing erreicht Delta-E < 0.8 auf allen korrigierten Pixeln. Der Anteil on-brand generierter Bilder stieg von 34 % auf 100 %. Die manuelle Nachbearbeitungszeit sank von 45 Minuten täglich auf null. Die gesamte Pipeline (Generierung + Korrektur + QA) dauert ca. 18 Sekunden pro Bild auf einer NVIDIA RTX 3060.