185 lines
7.0 KiB
Markdown
185 lines
7.0 KiB
Markdown
# Kamera-Anzahl-Studie
|
||
|
||
Untersucht, wie sich die Pose-Schätzgenauigkeit verändert, wenn weniger Kameras
|
||
verwendet werden. Hauptergebnis ist eine Kurve **k Kameras → Positionsfehler in mm**
|
||
an zwei Punkten des Roboters (Handgelenk und Finger).
|
||
|
||
Hintergrundfrage und Entscheidungslogik: [`doc/camera_number_roadmap.md`](../../doc/camera_number_roadmap.md)
|
||
|
||
---
|
||
|
||
## Voraussetzungen
|
||
|
||
Pro Szene müssen vorhanden sein:
|
||
|
||
| Datei | Woher |
|
||
|---|---|
|
||
| `data/simulation/SceneX/render_*.png` | Blender-Renderer |
|
||
| `data/simulation/SceneX/render_*.npz` | Kamera-Intrinsik |
|
||
| `data/simulation/SceneX/pose.json` | Ground-Truth-Pose |
|
||
| `data/robot/robot.json` | Robotermodell |
|
||
|
||
Neue Szenen werden **automatisch erkannt** — kein Skript anpassen nötig.
|
||
Für die Plots zusätzlich `matplotlib` (`pip install matplotlib`); ohne läuft
|
||
alles, nur das PNG entfällt.
|
||
|
||
---
|
||
|
||
## Metriken
|
||
|
||
Pro Kamera-Subset werden zwei Positionsfehler per Vorwärtskinematik berechnet —
|
||
der euklidische Abstand zwischen geschätzter und wahrer Position eines Punktes:
|
||
|
||
| Metrik | Punkt | Hängt ab von | Bedeutung |
|
||
|---|---|---|---|
|
||
| `wrist_error_mm` | Hand-Ursprung | Armgelenke `x,y,z,a` | Wie genau ist der Arm bis zum Handgelenk? |
|
||
| `finger_error_mm` | FingerA-Spitze | volle Kette `x..e` | Wie genau ist die ganze Pose inkl. Hand/Finger? |
|
||
|
||
**Unbeobachtbare Gelenke → leerer Wert (n/a).** Sieht ein Subset z. B. die Hand
|
||
nicht, ist `b/c/e` unbeobachtbar — dann ist die *wahre* Fingerposition schlicht
|
||
unbekannt und `finger_error_mm` bleibt **leer** (statt mit einer falschen 0
|
||
gefüllt zu werden). Das Handgelenk hängt nur von den Armgelenken ab und ist
|
||
deshalb meist auch mit wenigen Kameras bestimmbar.
|
||
|
||
Welche Gelenke einen Punkt bewegen, wird **numerisch** ermittelt (kleine
|
||
Auslenkung je Gelenk) — funktioniert daher auch, wenn sich das Robotermodell ändert.
|
||
|
||
Zusätzliche Spalten:
|
||
|
||
- `n_unobservable` — Anzahl der 7 Gelenke, die in diesem Subset unbeobachtbar waren.
|
||
- `mean_abs_deg` / `max_abs_deg` — Gelenkwinkelfehler (nur **beobachtbare** Gelenke).
|
||
- `mean_abs_mm` / `max_abs_mm` — Lineargelenkfehler (`x`, `e`).
|
||
|
||
> Hinweis: Winkelfehler zählen unbeobachtbare Gelenke **nicht** mit, die
|
||
> mm-Positionsfehler lassen sie als n/a aus. Beide blenden also dieselben Fälle
|
||
> aus — die `n/a`-Spalte zeigt, wie oft das passiert.
|
||
|
||
---
|
||
|
||
## Schritt 1 — Studie laufen lassen
|
||
|
||
```bat
|
||
run\run_camera_study.bat
|
||
```
|
||
|
||
Das wertet alle verfügbaren Szenen aus, k = 3 bis (alle verfügbaren Kameras),
|
||
10 zufällige Subsets pro k.
|
||
|
||
**Optionen:**
|
||
|
||
```bat
|
||
REM Nur bestimmte Szenen
|
||
run\run_camera_study.bat --scenes Scene7 Scene9
|
||
|
||
REM Kamerabereich einschränken
|
||
run\run_camera_study.bat --k-min 3 --k-max 5
|
||
|
||
REM Weniger Samples — schneller, weniger repräsentativ
|
||
run\run_camera_study.bat --samples 3
|
||
|
||
REM Pipeline für vorhandene Subsets erneut laufen lassen
|
||
run\run_camera_study.bat --force
|
||
|
||
REM VOLLSTÄNDIGER Neustart: alles löschen und neu rechnen
|
||
run\run_camera_study.bat --clean
|
||
|
||
REM Nur eine re-gerenderte Szene komplett neu rechnen (Rest bleibt erhalten)
|
||
run\run_camera_study.bat --clean --scenes Scene10
|
||
```
|
||
|
||
Oder direkt über Python (z. B. in einer Linux-Umgebung / Docker):
|
||
|
||
```bash
|
||
python benchmark/camera_count/run_camera_study.py --samples 10
|
||
```
|
||
|
||
**Laufzeit & Wiederholläufe:** Pro Kamera-Subset läuft die volle Pipeline
|
||
(Schritt 1–4). Bereits gerechnete Subsets werden **übersprungen** (kein `--force`
|
||
nötig für Fortsetzung) — die mm-Auswertung wird dabei trotzdem frisch berechnet,
|
||
ein erneuter Lauf ohne `--force` ist also schnell.
|
||
|
||
**Drei Stufen der Wiederholung:**
|
||
|
||
| Flag | Wirkung |
|
||
|---|---|
|
||
| *(kein Flag)* | Vorhandene `robot_state.json` werden wiederverwendet, nur die Auswertung neu gerechnet. Schnell. |
|
||
| `--force` | Pipeline läuft erneut, überschreibt `robot_state.json`. Für geänderte Pipeline-Logik. |
|
||
| `--clean` | Löscht Zwischenergebnisse vorher komplett. **Nötig nach Re-Rendering.** Ohne `--scenes` wird alles inkl. Ergebnisdateien zurückgesetzt; mit `--scenes` nur die genannten Szenen. |
|
||
|
||
**Merge:** Ein Lauf über einzelne Szenen (`--scenes`) aktualisiert nur deren
|
||
Zeilen in `camera_study.json/.csv` — die übrigen Szenen bleiben erhalten. Du
|
||
kannst also eine re-gerenderte Szene neu rechnen, ohne die Gesamtauswertung zu verlieren.
|
||
|
||
---
|
||
|
||
## Schritt 2 — Auswertung
|
||
|
||
```bash
|
||
python benchmark/camera_count/analyze.py # finger_error_mm (Standard)
|
||
python benchmark/camera_count/analyze.py --metric wrist_error_mm
|
||
python benchmark/camera_count/analyze.py --metric mean_abs_deg
|
||
```
|
||
|
||
Beispielausgabe (nur Scene10):
|
||
|
||
```
|
||
Kamera-Anzahl vs. finger_error_mm
|
||
k | n | n/a | Mittel | Median | Std | Min | Max
|
||
--------------------------------------------------------------------------
|
||
3 | 4 | 6 | 1.775 | 1.583 | 0.986 | 0.710 | 3.225
|
||
4 | 10 | 0 | 1.955 | 2.034 | 0.696 | 0.503 | 3.317
|
||
5 | 10 | 0 | 1.391 | 1.322 | 0.646 | 0.614 | 2.468
|
||
6 | 7 | 0 | 1.306 | 1.288 | 0.389 | 0.697 | 1.992
|
||
7 | 1 | 0 | 1.251 | 1.251 | 0.000 | 1.251 | 1.251
|
||
|
||
n/a = Subsets, bei denen dieser Punkt unbeobachtbar war (nicht eingerechnet).
|
||
|
||
Beste / schlechteste Subsets je k (finger_error_mm):
|
||
k=3: best [Scene10] bcd (0.710) worst [Scene10] acf (3.225)
|
||
...
|
||
```
|
||
|
||
Hier sieht man sofort: bei **k=3 konnten 6 von 10 Subsets den Finger gar nicht
|
||
sehen** (n/a=6). Das ist die eigentliche Aussage — nicht „der Fehler ist klein",
|
||
sondern „die meisten 3-Kamera-Anordnungen verlieren die Hand komplett".
|
||
|
||
Verfügbare Metriken: `finger_error_mm` (Standard), `wrist_error_mm`,
|
||
`mean_abs_deg`, `max_abs_deg`, `mean_abs_mm`, `max_abs_mm`.
|
||
|
||
---
|
||
|
||
## Ausgabedateien
|
||
|
||
| Pfad | Inhalt |
|
||
|---|---|
|
||
| `benchmark/camera_count/results/camera_study.json` | Alle Einzelergebnisse |
|
||
| `benchmark/camera_count/results/camera_study.csv` | Dasselbe als CSV (Spalten inkl. `wrist_error_mm`, `finger_error_mm`, `n_unobservable`) |
|
||
| `benchmark/camera_count/results/camera_count_<metric>.png` | Boxplot je Metrik |
|
||
| `data/camera_study/SceneX/k3_abc/` | Pipeline-Zwischenergebnisse pro Subset |
|
||
|
||
Die Zwischenergebnisse in `data/camera_study/` sind groß — nicht committen.
|
||
|
||
---
|
||
|
||
## Ergebnis interpretieren
|
||
|
||
Die Studie beantwortet vier Fragen:
|
||
|
||
1. **Wird die Hand überhaupt gesehen?**
|
||
→ `n/a`-Spalte bei `finger_error_mm`. Viele n/a bei k=3 heißt: zu wenige
|
||
Kameras verlieren die Hand systematisch.
|
||
|
||
2. **Ab welchem k wird der Fehler stabil?**
|
||
→ Knick in der Kurve zeigt den Sättigungspunkt.
|
||
|
||
3. **Welche Kamera-Kombination ist bei kleinem k am besten?**
|
||
→ `analyze.py` gibt beste und schlechteste Subsets aus.
|
||
|
||
4. **Arm vs. Hand getrennt:** Das Handgelenk (`wrist_error_mm`) ist meist schon
|
||
mit 3 Kameras gut bestimmt — der kritische Teil ist die Hand/Finger-Orientierung.
|
||
|
||
Eine praktische Entscheidungsregel: 3 Kameras gelten als ausreichend, wenn
|
||
(a) der Finger in fast allen Subsets beobachtbar ist (wenig n/a) **und**
|
||
(b) `finger_error_mm` bei k=3 nicht wesentlich schlechter ist als beim Maximum.
|
||
(Schwellwert je nach Anwendung anpassen.)
|