- Python 100%
| data | ||
| iterations | ||
| style | ||
| .gitignore | ||
| CLAUDE.md | ||
| CONTRIBUTING.md | ||
| generate.py | ||
| LICENSE | ||
| README.md | ||
| viewer.py | ||
act-img-gen
Open-Source-Pipeline zur Erzeugung eines konsistent gestylten Bilddatensatzes für jedes Lebensmittel im Bundeslebensmittelschlüssel 4.0 (BLS — der vom Max Rubner-Institut gepflegte Lebensmittelkatalog Deutschlands, 7140 Items).
Bestandteil von ACT, einer Tracking-App für die deutsche Ernährungsdatenbank. ACT braucht für jedes Lebensmittel ein erkennbares, visuell konsistentes Icon — bei 7140 Items ist Stockfotografie keine Option, und kommerzielle Datasets gibt es für BLS nicht.
ACT-Hauptrepo: https://git.moritz.run/moritz/act
Sieger-Setup
| Style | comic_v4 — flacher Sticker ohne Outlines, englische Prompts mit 5 universellen Regeln |
| Prompter-LLM | gpt-5-mini (OpenAI direkt, sync, reasoning_effort: "minimal") |
| Image-Modell | gpt-image-2 quality low (272 Output-Tokens) via Batch API |
| Background-Removal | birefnet-massive lokal via rembg (Apache 2.0, ~1.5 GB ONNX) |
| Auflösung | 1024 × 1024 PNG mit Alpha-Kanal (transparenter Hintergrund) |
| Preis pro Bild | ~$0.0044 (LLM ~$0.001 + Bild ~$0.003 im Batch-Tarif; Bg-Removal lokal = $0) |
| Komplettes BLS 4.0 (7140 Items) | ~$31 API-Kosten + ~32h CPU-Zeit fürs Bg-Removal (oder ~3h auf GPU) |
Drei Schritte
BLS-Item ──┐
▼ ┌─→ output/comic_v4/<SBLS>/prompt.md
[1] gpt-5-mini sync ───── englischer Prompt ────┘
├─→ output/comic_v4/<SBLS>/openai__gpt-image-2-low_raw.png
│ (rohes API-PNG mit weißem Hintergrund, als Backup)
[2] gpt-image-2 batch ─── 1024×1024 PNG ────────┤
└─→ output/comic_v4/<SBLS>/openai__gpt-image-2-low.png
(transparente Production-Datei für ACT)
[3] BiRefNet-massive ──── Hintergrund weg ──────┘
20 Sieger-Beispiele aus data/benchmark_items.csv (Bezeichnungen exakt aus
BLS 4.0). Hot-pink Hintergrund ist nicht Teil der Production-Bilder —
ist nur eingeblendet, damit man sieht wo die Transparenz funktioniert. Die
echten Production-PNGs haben Alpha-Kanal und sind hintergrundlos für ACT.
Vollständiger Algorithmen-Vergleich (PIL vs. ISNet vs. BiRefNet-general vs.
BiRefNet-massive) in iterations/comparison.md:
Verwendung
# Voraussetzungen:
# - OPENAI_API_KEY in .env
# - Python-Deps: requests Pillow rembg[cpu] numpy scipy onnxruntime
# - Verifizierte OpenAI-Org (gpt-image-2 freigeschaltet)
python3 generate.py --dry-run # Kostenschätzung
python3 generate.py # Submit Batch (Schritt 1+2)
python3 generate.py --fetch latest # Bilder abholen + Bg-Removal (Schritt 2+3)
python3 generate.py --postprocess # Schritt 3 nachträglich auf alten Bildern
python3 viewer.py # interaktiver HTML-Viewer mit Lightbox
Drei-Schritt-Pipeline läuft mit einem einzigen Tool (generate.py).
Submit gibt eine Batch-ID zurück; --fetch erledigt automatisch sowohl
Image-Download als auch Hintergrund-Removal in einem Lauf. --no-postprocess
falls man Schritt 3 überspringen möchte.
Items kommen aus data/benchmark_items.csv (20 zufällige BLS-Items mit
Seed 42 für die Iteration). Für den vollen 7140-Lauf muss diese CSV durch
eine Vollliste ersetzt werden — Spalten: sbls,name_de,name_en,hauptgruppe.
Warum das so kompliziert war
Erste Iteration (siehe iterations/openai-prototype/) war ein einzelner
Studio-Foto-Prompt, an alle Items gleich verschickt. Resultat: Schweinshaxe
vor reinweißem Hintergrund sah grotesk aus, Apfelkompott kam ohne Schüssel
auf den nackten Boden. Plus: gpt-image @ photo-quality kostet ~$0.04 pro
Bild. Bei 7140 Items wären das mindestens $300 für eine Stilvariante,
und das Ergebnis war optisch unbrauchbar.
Drei Erkenntnisse daraus:
- Der Stil muss flach sein, nicht foto. Sonst überdramatisieren die Modelle Items, die im echten Leben nüchtern aussehen (Joghurt, rohes Fleisch, Suppe). Comic-Sticker schluckt das.
- Pro Item braucht's einen eigenen Prompt, der die "Anrichtung" entscheidet (Glas? Schüssel? freistehend?). Ein cheap LLM davor löst das günstig.
- Der Hintergrund muss raus — die App hat dunkle und helle Themes, und ein weißer Block hinter jedem Item sieht überall furchtbar aus.
Die folgende Iteration hat systematisch durch alle drei Achsen gegrast.
Was alles probiert wurde
Image-Modelle (alle auf 20 Benchmark-Items)
| Modell | Provider | Kosten/Bild | Verwurf-Grund |
|---|---|---|---|
recraft/recraft-v4 |
OpenRouter | $0.040 | sehr teuer, keine Style-Konsistenz |
sourceful/riverflow-v2-fast |
OpenRouter | $0.020 | uneinheitlicher Look zwischen Items |
openai/gpt-5-image-mini |
OpenRouter | $0.044 | OpenRouter-Bundle: GPT-5-mini wrappt gpt-image-1-mini → 2.5× teurer als Direkt-API |
openai/gpt-image-1-mini @ high |
OpenAI direkt | $0.017 | cremefarbener Hintergrund-Bias statt cleanem Weiß |
openai/gpt-image-2 @ medium |
OpenAI Batch | $0.030 | 7× teurer als low ohne sichtbaren Mehrwert beim flachen Sticker |
openai/gpt-image-2 @ low |
OpenAI Batch | $0.003 | Sieger — sauberes Weiß, gute Anweisungs-Befolgung |
Style-Spezifikationen (style/)
Alle Stile sind dieselben Kompositions-/Anrichtungsregeln, nur der Zeichen-Look + die Prompt-Sprache ändern sich:
| Style | Look | Prompt-Sprache | Status |
|---|---|---|---|
comic_v1 |
Comic mit Outlines | Deutsch (Kimi K2.6) | verworfen — Outlines verschmutzten kleine Items |
comic_v2 |
Flat ohne Outlines | Deutsch (Kimi K2.6) | besser, aber auf Englisch nochmal sichtbar besser |
comic_v3 |
Flat ohne Outlines | Englisch (gpt-5-mini) | großer Sprung in Anweisungs-Befolgung |
comic_v5 |
Soft-3D mit Verlauf | Englisch | nett, aber lenkt vom Item ab |
comic_v6 |
Claymation 3D-Render | Englisch | sah aus wie WWDC-Pics — schön, aber zu "designed" für eine neutrale Lebensmittel-DB |
comic_v7 |
Pixel-Art 16-bit | Englisch | distinktiv, aber zu retro für eine moderne Health-App |
comic_v8 |
Neon-Cyber dezent | Englisch | dito — visuelles Nischen-Statement |
comic_v4 |
Flat ohne Outlines | Englisch + 5 universelle Regeln | Sieger |
Was comic_v4 über comic_v3 hinaus addiert sind fünf
universelle Prompt-Regeln, die das Image-Modell sauberer steuern
(Details in style/comic_v4.md):
- A — Nicht-visuelle Eigenschaften weglassen ("egg-free pasta" verwirrt das Bildmodell).
- B — Zusammengesetzte Items als Einheit darstellen ("Knäckebrot mit Käse und Möhre" → ein composed bite, nicht drei separate Zutaten).
- C — Mehrdeutige Items: eine Konsumform wählen und committen, keine "either/or"-Formulierungen.
- D — Visuell beschreiben statt Fachbegriff aneinanderreihen ("Roggenmischbrot" → "round dark rye-and-wheat loaf with crusty surface").
- E — Farbe explizit nennen wo nicht offensichtlich ("Quark" → "white", "Sauerkraut" → "pale yellowish-white").
Prompter-LLM (Erzeugung des Bild-Prompts pro Item)
| LLM | Provider | $/Prompt | Verwurf-Grund |
|---|---|---|---|
moonshotai/kimi-k2.6 |
OpenRouter | ~$0.002 | unnötiger Provider-Hop, OpenAI-Stack ohnehin nötig |
gpt-5-mini |
OpenAI direkt | ~$0.001 | Sieger — günstiger und ein-Provider-Setup |
reasoning_effort: "minimal" ist Pflicht — sonst rechnet die gpt-5-Familie
hidden reasoning tokens für eine strukturierte Aufgabe, die kein Reasoning
braucht (~5× teurer).
Background-Removal-Algorithmen
OpenAIs gpt-image-2 unterstützt background: "transparent" nicht
(nur gpt-image-1/-1.5). Also Post-Processing nötig. Vier getestet auf
den 20 Sieger-Bildern (in iterations/comparison.md mit pinkem Hintergrund
visualisiert):
| Algo | Speed/Bild (CPU) | 7140 Items | Knäckebrot-Test | Milchglas-Test |
|---|---|---|---|---|
| PIL Flood-Fill (kein ML) | 5 ms | ~1 min | ✓ | leichte Halos bei AA-Kanten |
birefnet-general |
17 s | ~33 h | ✗ komplett gegessen | ok |
isnet-general-use |
1.2 s | ~2.4 h | ✓ | leichte Halos |
birefnet-massive |
16 s | ~32 h | ✓ | sauber, auch bei weißem Innen-Item |
birefnet-massive gewinnt klar bei semantischer Trennung "Item vs.
Hintergrund" — bricht weder bei tatsächlich weißen Vordergrund-Items
(Quark, Milch, Hartkäse) noch bei dünnen Items (Knäckebrot) ein.
Geschwindigkeit auf CPU ist zwar langsam, aber ein einmal-Vorgang.
Sync vs. Batch
OpenAI's Batch API gibt 50 % Rabatt auf alles, asynchron mit max. 24h Bearbeitungsfenster (in der Praxis 5–30 Min für die Größenordnung hier). Da der ganze Production-Lauf nicht echtzeitfähig sein muss, ist Batch ein no-brainer.
Vollständiger Vergleich
Alle 19 (Style × Image-Modell × Prompter)-Kombinationen plus die 4 Background-Removal-Algorithmen mit eingebetteten Bildern direkt im Repo sichtbar:
(Bilder sind 256-px-Thumbnails, vollauflösende Originale wurden für
Repo-Größe nicht mitgeshippt — können via python3 generate.py mit dem
zugehörigen Style neu generiert werden, Prompts liegen unter
iterations/output/<style>/<sbls>/prompt.md.)
Layout
generate.py Drei-Schritt-Pipeline (Submit + Fetch + Bg-Removal)
viewer.py Interaktiver HTML-Viewer (Drag-Drop-Sortierung, Lightbox)
data/
sample_benchmark.py Stratified random sample aus BLS xlsx
benchmark_items.csv 20 Test-Items (Seed 42, getrackt)
style/
comic_v4.md Sieger-Style-Spec (verbindlich, unverändert)
output/ Generierter Output (gitignored)
comic_v4/<SBLS>/
manifest.json
prompt.md
openai__gpt-image-2-low.png finale Production-Datei (transparent)
openai__gpt-image-2-low_raw.png rohes API-PNG (mit weißem Hintergrund)
iterations/ Verworfene Stile + Vergleichsbilder als Doku (getrackt)
README.md Erklärt das Iterationsmaterial
comparison.md Markdown-Viewer mit allen Iterations-Bildern
build_comparison_md.py Generator für comparison.md
styles/ 7 verworfene Style-Specs (v1, v2, v3, v5–v8)
output/ 256-px-Thumbnails der Iteration-Bilder
unbackground.py Plan B (PIL Flood-Fill) — historisch
unbackground_ml.py Plan C+ (rembg, parametrisierbar) — historisch
test_transparent.py Test der OpenAI-nativen Alpha-Variante (failed)
openai-prototype/ Erster fehlgeschlagener Photo-Studio-Versuch
LICENSE MIT
CLAUDE.md Architektur-Notizen für Claude Code (Tooling)
Lizenz
Code unter MIT (siehe LICENSE).
Die generierten Bilder selbst sind als kreatives Output von OpenAIs gpt-image-2 zu betrachten — siehe OpenAIs Terms of Use zur kommerziellen Verwendung.
Die zugrundeliegenden BLS-Item-Bezeichnungen stammen aus dem
Bundeslebensmittelschlüssel 4.0 (Max Rubner-Institut, lizenzpflichtig).
Die BLS-Quelldatei selbst (xlsx) ist nicht Teil dieses Repos — nur
die 20 Benchmark-Item-Namen + SBLS-Codes sind in data/benchmark_items.csv
enthalten, was unter dem Doktrin "kurze Identifikationsdaten zur Demonstration"
fällt. Wer den vollen 7140-Item-Lauf durchführen möchte, braucht eine
eigene BLS 4.0-Lizenz.



















