Claude: Docker Phase 1
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
FROM linuxserver/blender:latest
|
||||
|
||||
USER root
|
||||
|
||||
RUN pip3 install --no-cache-dir \
|
||||
numpy \
|
||||
opencv-python
|
||||
|
||||
WORKDIR /workspace
|
||||
23
setup/generateSets/Dockerfile.pipeline
Normal file
23
setup/generateSets/Dockerfile.pipeline
Normal 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"]
|
||||
44
setup/generateSets/Dockerfile.renderer
Normal file
44
setup/generateSets/Dockerfile.renderer
Normal 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 []
|
||||
69
setup/generateSets/README.docker.md
Normal file
69
setup/generateSets/README.docker.md
Normal 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
|
||||
```
|
||||
Binary file not shown.
Binary file not shown.
26
setup/generateSets/create-portainer-stack.bat
Normal file
26
setup/generateSets/create-portainer-stack.bat
Normal 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
|
||||
25
setup/generateSets/create-portainer-stack.sh
Normal file
25
setup/generateSets/create-portainer-stack.sh
Normal 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"
|
||||
38
setup/generateSets/docker-compose.yml
Normal file
38
setup/generateSets/docker-compose.yml
Normal 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
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
5
setup/generateSets/requirements.pipeline.txt
Normal file
5
setup/generateSets/requirements.pipeline.txt
Normal 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
|
||||
Reference in New Issue
Block a user