Claude: Docker Phase 1

This commit is contained in:
chk
2026-06-02 17:16:24 +02:00
parent 5ad956be81
commit 6179510d48
376 changed files with 137515 additions and 171806 deletions

View File

@@ -1,9 +0,0 @@
FROM linuxserver/blender:latest
USER root
RUN pip3 install --no-cache-dir \
numpy \
opencv-python
WORKDIR /workspace

View File

@@ -0,0 +1,23 @@
# ──────────────────────────────────────────────────────────────────
# Pipeline-Container: schlank, GPU-frei. Das eigentliche Produkt
# (Roboter-Pose aus Fotos — läuft auch mit echten Webcam-Bildern).
# Kein Blender, nur numpy/scipy/opencv. ~200 MB, CI-tauglich.
# ──────────────────────────────────────────────────────────────────
FROM python:3.11-slim
# libglib2.0-0 + libgomp1: von opencv(-headless) zur Laufzeit benötigt.
RUN apt-get update && apt-get install -y --no-install-recommends \
libglib2.0-0 libgomp1 \
&& rm -rf /var/lib/apt/lists/*
COPY setup/generateSets/requirements.pipeline.txt /tmp/req.txt
RUN pip install --no-cache-dir -r /tmp/req.txt
ENV ROBOT_JSON=/workspace/data/robot/robot.json
WORKDIR /workspace
# Flexibler Einstieg: python3 <script> ...
# docker compose run --rm pipeline pipeline/run_pipeline.py data/simulation/Scene8
# docker compose run --rm pipeline benchmark/run_benchmark.py --scenes 8
ENTRYPOINT ["python3"]
CMD ["pipeline/run_pipeline.py", "--help"]

View File

@@ -0,0 +1,44 @@
# ──────────────────────────────────────────────────────────────────
# Renderer-Container: Blender 4.5 (headless) + cv2/numpy in Blenders Python
# Erzeugt aus robot.json die synthetischen Szenen (Bilder, npz, Ground-Truth).
# Schwer (~1-2 GB) und nur für Test-Datengenerierung — getrennt vom Pipeline-Image.
# ──────────────────────────────────────────────────────────────────
FROM ubuntu:22.04
# Exakte Blender-Patch-Version ggf. anpassen (muss unter download.blender.org existieren).
ARG BLENDER_SERIES=4.5
ARG BLENDER_VERSION=4.5.0
ENV DEBIAN_FRONTEND=noninteractive
# System-Python (für render_Loop.py) + Laufzeit-Libs für headless Blender/Cycles.
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 wget xz-utils ca-certificates \
libx11-6 libxi6 libxxf86vm1 libxfixes3 libxrender1 libxkbcommon0 \
libgl1 libegl1 libsm6 libice6 libxext6 \
&& rm -rf /var/lib/apt/lists/*
# Blender herunterladen und nach /opt/blender entpacken.
RUN wget -q "https://download.blender.org/release/Blender${BLENDER_SERIES}/blender-${BLENDER_VERSION}-linux-x64.tar.xz" \
-O /tmp/blender.tar.xz \
&& mkdir -p /opt/blender \
&& tar -xJf /tmp/blender.tar.xz -C /opt/blender --strip-components=1 \
&& rm /tmp/blender.tar.xz \
&& ln -s /opt/blender/blender /usr/local/bin/blender
# WICHTIG: cv2 in BLENDERS gebündeltes Python installieren (NICHT das System-Python) —
# render_robot.py erzeugt die ArUco-Marker mit cv2.aruco innerhalb von Blender.
RUN BPY="$(ls /opt/blender/${BLENDER_SERIES}/python/bin/python3*)" \
&& "$BPY" -m ensurepip \
&& "$BPY" -m pip install --no-cache-dir --upgrade pip \
&& "$BPY" -m pip install --no-cache-dir "opencv-python-headless==4.10.0.84"
ENV BLENDER_EXE=/usr/local/bin/blender \
ROBOT_JSON=/workspace/data/robot/robot.json \
RENDER_OUTPUT=/workspace/data/simulation/debug/render.png
WORKDIR /workspace
# Standard: render_Loop.py (Argumente werden angehängt, z.B. --poses 8).
# CPU-Rendering ist der Default; für GPU den Container mit NVIDIA-Runtime starten.
ENTRYPOINT ["python3", "setup/generateSets/render_Loop.py"]
CMD []

View File

@@ -0,0 +1,69 @@
# Docker — Phase 1
Zwei getrennte Images (siehe `doc/docker_containerization_roadmap.md`):
| Image | Dockerfile | Zweck |
|---|---|---|
| `approbot/blender-renderer:4.5` | `Dockerfile.renderer` | Blender 4.5 headless → erzeugt Test-Szenen (Bilder, npz, Ground-Truth) |
| `approbot/pose-pipeline:latest` | `Dockerfile.pipeline` | schlanke Pose-Schätzung (das eigentliche Produkt) |
Beide teilen sich das `data/`-Volume: Der Renderer schreibt nach `data/simulation/SceneX`,
die Pipeline liest von dort und schreibt nach `data/evaluations/SceneX`.
## Bauen
```bash
cd setup/generateSets
docker compose build
```
Die Blender-Patch-Version steht in `Dockerfile.renderer` (`ARG BLENDER_VERSION=4.5.0`) —
muss unter download.blender.org existieren; bei Bedarf anpassen:
```bash
docker compose build --build-arg BLENDER_VERSION=4.5.3 renderer
```
## Rendern (Test-Daten erzeugen)
```bash
docker compose run --rm renderer --poses 8 # nur Pose 8
docker compose run --rm renderer # alle robot_test_poses
```
CPU-Rendering ist Default. Für GPU (Cycles, deutlich schneller): NVIDIA Container Toolkit
installieren und den `deploy:`-Block in `docker-compose.yml` einkommentieren.
## Pose-Pipeline ausführen
```bash
docker compose run --rm pipeline pipeline/run_pipeline.py data/simulation/Scene8
# -> data/evaluations/Scene8/robot_state.json
```
## Benchmark gegen Ground-Truth
```bash
docker compose run --rm pipeline benchmark/run_benchmark.py --scenes 8
docker compose run --rm pipeline benchmark/eval_pose.py \
data/evaluations/Scene8/robot_state.json data/simulation/Scene8/pose.json
```
## Hinweise
* **cv2 im Renderer** liegt in *Blenders* gebündeltem Python (nicht System-Python) —
siehe `Dockerfile.renderer`. Das frühere `Dockerfile` mit `pip3 install opencv-python`
installierte ins falsche Python und ist ersetzt.
* **robot.json wird beim Rendern mutiert** (Kamera/Pose pro Bild). Für einen einzelnen
sequentiellen Lauf ok; für *parallele* Render-Jobs muss das vorher auf eine temporäre
Config pro Job umgestellt werden (Roadmap Phase 2/4, Schlüsselpunkt 3).
* **Code wird als Volume gemountet** — Änderungen an Python-Scripten wirken ohne Rebuild.
Nur bei geänderten Abhängigkeiten (`requirements.pipeline.txt`) oder Blender-Version neu bauen.
## Portainer-Stack (optional)
`create-portainer-stack.bat` legt den Stack per Portainer-API an. In **cmd.exe** ausführen
(dort ist `curl` = curl.exe). In **PowerShell** zum Testen `curl.exe` statt `curl` verwenden,
da `curl` dort ein Alias für `Invoke-WebRequest` ist:
```powershell
curl.exe -k -H "X-API-Key: <KEY>" https://localhost:9443/api/endpoints
```

View File

@@ -0,0 +1,26 @@
@echo off
setlocal
REM Anpassungen
set "PORTAINER_URL=https://localhost:9443"
set "API_KEY=ptr_flNQoaROQLF4L+4fHAfv7db774Exgv+pDJ04dc4W7Bs="
set "ENDPOINT_ID=1"
set "STACK_NAME=robot-renderer"
set "COMPOSE_FILE=%~dp0docker-compose.yml"
set "PAYLOAD=%TEMP%\portainer_stack_payload.json"
REM JSON-Payload aus der Compose-Datei erzeugen
powershell -NoProfile -Command ^
"$compose = Get-Content -Raw -Path '%COMPOSE_FILE%';" ^
"$obj = [ordered]@{ name = '%STACK_NAME%'; StackFileContent = $compose };" ^
"$obj | ConvertTo-Json -Compress | Set-Content -Encoding utf8 '%PAYLOAD%'"
REM Stack in Portainer anlegen
curl.exe -k -sS -X POST "%PORTAINER_URL%/api/stacks/create/standalone/string?endpointId=%ENDPOINT_ID%" ^
-H "X-API-Key: %API_KEY%" ^
-H "Content-Type: application/json" ^
--data-binary "@%PAYLOAD%"
del "%PAYLOAD%"
endlocal
pause

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -euo pipefail
PORTAINER_URL="https://portainer.local:9443"
API_KEY="HIER_DEIN_API_KEY"
ENDPOINT_ID="1"
STACK_NAME="robot-renderer"
COMPOSE_FILE="$(dirname "$0")/docker-compose.yml"
PAYLOAD="$(python - <<'PY'
import json, pathlib, os
compose_file = pathlib.Path(os.environ["COMPOSE_FILE"])
compose = compose_file.read_text(encoding="utf-8")
print(json.dumps({
"name": os.environ["STACK_NAME"],
"StackFileContent": compose
}))
PY
)"
curl -k -sS -X POST \
"$PORTAINER_URL/api/stacks/create/standalone/string?endpointId=$ENDPOINT_ID" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
--data-raw "$PAYLOAD"

View File

@@ -0,0 +1,38 @@
# Zwei getrennte Images:
# renderer Blender 4.5, erzeugt Test-Szenen (Bilder/npz/Ground-Truth)
# pipeline schlanke Pose-Schätzung (das eigentliche Produkt)
#
# Aufruf aus diesem Ordner (setup/generateSets/):
# docker compose build
# docker compose run --rm renderer --poses 8
# docker compose run --rm pipeline pipeline/run_pipeline.py data/simulation/Scene8
# docker compose run --rm pipeline benchmark/run_benchmark.py --scenes 8
services:
renderer:
build:
context: ../..
dockerfile: setup/generateSets/Dockerfile.renderer
image: approbot/blender-renderer:4.5
volumes:
- ../../data:/workspace/data
- ../../setup:/workspace/setup
- ../../pipeline:/workspace/pipeline
# GPU (optional): NVIDIA Container Toolkit nötig, dann einkommentieren:
# deploy:
# resources:
# reservations:
# devices:
# - driver: nvidia
# count: all
# capabilities: [gpu]
pipeline:
build:
context: ../..
dockerfile: setup/generateSets/Dockerfile.pipeline
image: approbot/pose-pipeline:latest
volumes:
- ../../data:/workspace/data
- ../../pipeline:/workspace/pipeline
- ../../benchmark:/workspace/benchmark

View File

@@ -78,10 +78,15 @@ def load_render_config(robot_json_file):
cam_targets = data.get("test_camera_targets", {}) or {}
rinfo = data.get("renderingInfo", {}) or {}
# WICHTIG: renderingInfo.width/height/dofFStop sind TRANSIENT — update_robot_json
# überschreibt sie bei jedem Render. Als Default für Posen ohne eigenes "rendering"
# daher das STABILE Feld 'renderDefaults' verwenden, sonst "vergiftet" ein
# Override-Render (z.B. 9b mit 4896x3264) den Default für alle folgenden Läufe.
rd = rinfo.get("renderDefaults", {}) or {}
default_rendering = {
"width": int(rinfo.get("width", 1280)),
"height": int(rinfo.get("height", 720)),
"dofFStop": float(rinfo.get("dofFStop", 11)),
"width": int(rd.get("width", 1280)),
"height": int(rd.get("height", 720)),
"dofFStop": float(rd.get("dofFStop", 11)),
}
return poses, cam_positions, cam_targets, default_rendering
@@ -99,7 +104,7 @@ def main():
BASE = Path(__file__).resolve().parents[2]
BLENDER_EXE = str("C:/Program Files/Blender Foundation/Blender 4.5/blender.exe")
BLENDER_EXE = os.environ.get("BLENDER_EXE", "C:/Program Files/Blender Foundation/Blender 4.5/blender.exe")
ROBOT_JSON_FILE = str(BASE / "data" / "robot" / "robot.json")
OUTPUT_DIR = str(BASE / "data" / "simulation" / "debug")

View File

@@ -16,13 +16,15 @@ from mathutils import Matrix
# Holt dynamisch den Pfad zum aktuellen Benutzerverzeichnis (z.B. C:\Users\Name)
import os
USER_HOME = Path.home()
BASE = Path(__file__).resolve().parents[2]
# Kombiniert den Benutzerpfad mit dem spezifischen Ordnerpfad und konvertiert direkt zu str
ROBOT_JSON_FILE = str(BASE / "data" / "robot" / "robot.json")
OUTPUT_FILE = str(BASE / "data" / "simulation" / "debug" / "render.png")
# Pfade: env-Variablen (Container) mit Fallback auf repo-relative Pfade (lokal unverändert).
ROBOT_JSON_FILE = os.environ.get("ROBOT_JSON", str(BASE / "data" / "robot" / "robot.json"))
OUTPUT_FILE = os.environ.get("RENDER_OUTPUT", str(BASE / "data" / "simulation" / "debug" / "render.png"))
print("Using robot JSON file:", ROBOT_JSON_FILE)
print("Using output file:", OUTPUT_FILE)

View File

@@ -0,0 +1,5 @@
# Pose-Pipeline-Abhängigkeiten (gepinnt für reproduzierbare Ergebnisse).
# ArUco steckt in opencv-contrib (nicht im Basis-opencv); headless = ohne GUI-Libs.
numpy==1.26.4
scipy==1.13.1
opencv-contrib-python-headless==4.10.0.84