lab-camera-optimizer 1.0.2__tar.gz → 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lab_camera_optimizer-1.0.2/lab_camera_optimizer.egg-info → lab_camera_optimizer-1.1.0}/PKG-INFO +23 -4
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/README.md +22 -3
- lab_camera_optimizer-1.1.0/configs/ISM_fast.yaml +108 -0
- lab_camera_optimizer-1.1.0/configs/evaluate_labo_CHU.yaml +212 -0
- lab_camera_optimizer-1.1.0/configs/example_evaluation_CHU.yaml +66 -0
- lab_camera_optimizer-1.1.0/configs/labo_CHU_10ZED_3iPad.yaml +136 -0
- lab_camera_optimizer-1.1.0/configs/labo_CHU_bis.yaml +190 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/core/candidates.py +42 -18
- lab_camera_optimizer-1.1.0/core/combo_worker.py +171 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/core/config_loader.py +175 -3
- lab_camera_optimizer-1.1.0/core/greedy.py +536 -0
- lab_camera_optimizer-1.1.0/core/reporting.py +82 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/core/room.py +40 -8
- lab_camera_optimizer-1.1.0/core/scoring.py +433 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/core/visualize.py +81 -50
- lab_camera_optimizer-1.1.0/evaluate.py +167 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/init_project.py +23 -12
- lab_camera_optimizer-1.1.0/lab_camera_optimizer/__init__.py +3 -0
- lab_camera_optimizer-1.1.0/lab_camera_optimizer/configs/T_zone_direction_change.yaml +200 -0
- lab_camera_optimizer-1.1.0/lab_camera_optimizer/configs/evaluate_labo_CHU.yaml +212 -0
- lab_camera_optimizer-1.1.0/lab_camera_optimizer/configs/example_evaluation_CHU.yaml +66 -0
- lab_camera_optimizer-1.1.0/lab_camera_optimizer/configs/example_real_world.yaml +270 -0
- lab_camera_optimizer-1.1.0/lab_camera_optimizer/configs/example_simple.yaml +180 -0
- lab_camera_optimizer-1.1.0/lab_camera_optimizer/configs/labo_CHU.yaml +268 -0
- lab_camera_optimizer-1.1.0/lab_camera_optimizer/configs/labo_CHU_bis.yaml +190 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0/lab_camera_optimizer.egg-info}/PKG-INFO +23 -4
- lab_camera_optimizer-1.1.0/lab_camera_optimizer.egg-info/SOURCES.txt +44 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/lab_camera_optimizer.egg-info/entry_points.txt +1 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/lab_camera_optimizer.egg-info/top_level.txt +2 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/optimize.py +260 -216
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/pyproject.toml +5 -4
- lab_camera_optimizer-1.1.0/tests/test_candidates.py +67 -0
- lab_camera_optimizer-1.1.0/tests/test_config_loader.py +291 -0
- lab_camera_optimizer-1.1.0/tests/test_room.py +272 -0
- lab_camera_optimizer-1.1.0/tests/test_scoring.py +199 -0
- lab_camera_optimizer-1.0.2/core/greedy.py +0 -470
- lab_camera_optimizer-1.0.2/core/scoring.py +0 -248
- lab_camera_optimizer-1.0.2/lab_camera_optimizer.egg-info/SOURCES.txt +0 -24
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/LICENSE +0 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/MANIFEST.in +0 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/configs/T_zone_direction_change.yaml +0 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/configs/example_real_world.yaml +0 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/configs/example_simple.yaml +0 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/configs/labo_CHU.yaml +0 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/core/__init__.py +0 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/lab_camera_optimizer.egg-info/dependency_links.txt +0 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/lab_camera_optimizer.egg-info/requires.txt +0 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/preview_room.py +0 -0
- {lab_camera_optimizer-1.0.2 → lab_camera_optimizer-1.1.0}/setup.cfg +0 -0
{lab_camera_optimizer-1.0.2/lab_camera_optimizer.egg-info → lab_camera_optimizer-1.1.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lab-camera-optimizer
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Automated camera placement optimiser for markerless biomechanics motion capture labs
|
|
5
5
|
Author: Florian Delaplace
|
|
6
6
|
License-Expression: MIT
|
|
@@ -41,7 +41,8 @@ all evaluation points, with optional bilateral coverage constraints.
|
|
|
41
41
|
|
|
42
42
|
- **Any room shape** — define any polygon floor plan (L-shaped, rectangular, etc.)
|
|
43
43
|
- **Obstacles & walls** — pillars, partial-height furniture, irregular wall segments
|
|
44
|
-
- **Multiple camera sets** — wall-mounted cameras +
|
|
44
|
+
- **Multiple camera sets** — wall-mounted cameras + tripod cameras, both placed by the same zone-wide optimiser
|
|
45
|
+
- **Camera budget** — fix an exact count per set, *or* give a total and let the optimiser choose the wall/tripod split (`total_cameras` + per-set `count_min`/`count_max`)
|
|
45
46
|
- **Per-camera height variation** — each camera in the same configuration can be at a different height
|
|
46
47
|
- **3D visibility** — checks both horizontal FOV and vertical body coverage (0 → subject height)
|
|
47
48
|
- **Line-of-sight** — occlusion by walls and floor-to-ceiling obstacles
|
|
@@ -207,12 +208,25 @@ camera_sets:
|
|
|
207
208
|
height_options: [2.0, 2.2] # tested heights (metres)
|
|
208
209
|
max_range: 10.0
|
|
209
210
|
min_range: 0.5
|
|
210
|
-
|
|
211
|
+
count_max: 8 # max cameras of this set (alias: max_count)
|
|
212
|
+
count_min: 0 # min cameras of this set (free mode only)
|
|
211
213
|
min_spacing: 1.2
|
|
212
|
-
score_weight: 1.0
|
|
214
|
+
score_weight: 1.0 # weight of this set in the score
|
|
215
|
+
score_factor: 1.0 # extra per-set multiplier (e.g. 0.5 to down-weight)
|
|
213
216
|
color: "#1f77b4"
|
|
214
217
|
```
|
|
215
218
|
|
|
219
|
+
#### Camera budget — fixed vs free allocation
|
|
220
|
+
|
|
221
|
+
```yaml
|
|
222
|
+
optimization:
|
|
223
|
+
# total_cameras absent → FIXED: each set places exactly its count_max
|
|
224
|
+
# (wall-only: tripod count_max 0; "5 wall + 3 tripod": set each count_max)
|
|
225
|
+
# total_cameras present → FREE: the optimiser splits the total across sets
|
|
226
|
+
# within each set's [count_min, count_max] to maximise the score.
|
|
227
|
+
total_cameras: 8
|
|
228
|
+
```
|
|
229
|
+
|
|
216
230
|
#### `capture_zones` — where coverage matters
|
|
217
231
|
|
|
218
232
|
**Corridor-based** (walking path):
|
|
@@ -266,6 +280,7 @@ optimization:
|
|
|
266
280
|
bilateral_weight: 0.8 # 0 = disabled, 1 = fully enforced
|
|
267
281
|
vertical_coverage_threshold: 0.9
|
|
268
282
|
restarts_per_combo: 15
|
|
283
|
+
total_cameras: null # null = fixed mode; an int = free allocation
|
|
269
284
|
algo: "greedy_1opt" # greedy | greedy_1opt
|
|
270
285
|
early_stop: 5 # stop after N restarts with no improvement
|
|
271
286
|
graph_mode: "best_per_combo" # all | records_only | best_per_combo
|
|
@@ -275,6 +290,10 @@ optimization:
|
|
|
275
290
|
distance_quality_factor: 0.001
|
|
276
291
|
```
|
|
277
292
|
|
|
293
|
+
> **Note:** the `point` (STS) capture zone is **optional**. With no `point` zone
|
|
294
|
+
> declared, cameras simply optimise coverage of the corridor / analysis /
|
|
295
|
+
> polygon zones — useful for tripod-only or pure zone-wide setups.
|
|
296
|
+
|
|
278
297
|
### Step 3 — Preview, then run
|
|
279
298
|
|
|
280
299
|
```bash
|
|
@@ -14,7 +14,8 @@ all evaluation points, with optional bilateral coverage constraints.
|
|
|
14
14
|
|
|
15
15
|
- **Any room shape** — define any polygon floor plan (L-shaped, rectangular, etc.)
|
|
16
16
|
- **Obstacles & walls** — pillars, partial-height furniture, irregular wall segments
|
|
17
|
-
- **Multiple camera sets** — wall-mounted cameras +
|
|
17
|
+
- **Multiple camera sets** — wall-mounted cameras + tripod cameras, both placed by the same zone-wide optimiser
|
|
18
|
+
- **Camera budget** — fix an exact count per set, *or* give a total and let the optimiser choose the wall/tripod split (`total_cameras` + per-set `count_min`/`count_max`)
|
|
18
19
|
- **Per-camera height variation** — each camera in the same configuration can be at a different height
|
|
19
20
|
- **3D visibility** — checks both horizontal FOV and vertical body coverage (0 → subject height)
|
|
20
21
|
- **Line-of-sight** — occlusion by walls and floor-to-ceiling obstacles
|
|
@@ -180,12 +181,25 @@ camera_sets:
|
|
|
180
181
|
height_options: [2.0, 2.2] # tested heights (metres)
|
|
181
182
|
max_range: 10.0
|
|
182
183
|
min_range: 0.5
|
|
183
|
-
|
|
184
|
+
count_max: 8 # max cameras of this set (alias: max_count)
|
|
185
|
+
count_min: 0 # min cameras of this set (free mode only)
|
|
184
186
|
min_spacing: 1.2
|
|
185
|
-
score_weight: 1.0
|
|
187
|
+
score_weight: 1.0 # weight of this set in the score
|
|
188
|
+
score_factor: 1.0 # extra per-set multiplier (e.g. 0.5 to down-weight)
|
|
186
189
|
color: "#1f77b4"
|
|
187
190
|
```
|
|
188
191
|
|
|
192
|
+
#### Camera budget — fixed vs free allocation
|
|
193
|
+
|
|
194
|
+
```yaml
|
|
195
|
+
optimization:
|
|
196
|
+
# total_cameras absent → FIXED: each set places exactly its count_max
|
|
197
|
+
# (wall-only: tripod count_max 0; "5 wall + 3 tripod": set each count_max)
|
|
198
|
+
# total_cameras present → FREE: the optimiser splits the total across sets
|
|
199
|
+
# within each set's [count_min, count_max] to maximise the score.
|
|
200
|
+
total_cameras: 8
|
|
201
|
+
```
|
|
202
|
+
|
|
189
203
|
#### `capture_zones` — where coverage matters
|
|
190
204
|
|
|
191
205
|
**Corridor-based** (walking path):
|
|
@@ -239,6 +253,7 @@ optimization:
|
|
|
239
253
|
bilateral_weight: 0.8 # 0 = disabled, 1 = fully enforced
|
|
240
254
|
vertical_coverage_threshold: 0.9
|
|
241
255
|
restarts_per_combo: 15
|
|
256
|
+
total_cameras: null # null = fixed mode; an int = free allocation
|
|
242
257
|
algo: "greedy_1opt" # greedy | greedy_1opt
|
|
243
258
|
early_stop: 5 # stop after N restarts with no improvement
|
|
244
259
|
graph_mode: "best_per_combo" # all | records_only | best_per_combo
|
|
@@ -248,6 +263,10 @@ optimization:
|
|
|
248
263
|
distance_quality_factor: 0.001
|
|
249
264
|
```
|
|
250
265
|
|
|
266
|
+
> **Note:** the `point` (STS) capture zone is **optional**. With no `point` zone
|
|
267
|
+
> declared, cameras simply optimise coverage of the corridor / analysis /
|
|
268
|
+
> polygon zones — useful for tripod-only or pure zone-wide setups.
|
|
269
|
+
|
|
251
270
|
### Step 3 — Preview, then run
|
|
252
271
|
|
|
253
272
|
```bash
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# =============================================================
|
|
2
|
+
# ISM lab — FAST preview config (tripod-only)
|
|
3
|
+
# Same room / cameras / zones as example_real_world_ISM, but with
|
|
4
|
+
# coarser candidate grids and fewer restarts for a quick first look.
|
|
5
|
+
# Increase grid resolution + restarts once the layout looks right.
|
|
6
|
+
# =============================================================
|
|
7
|
+
|
|
8
|
+
room:
|
|
9
|
+
corners:
|
|
10
|
+
- [0, 0 ]
|
|
11
|
+
- [0.87, 0 ]
|
|
12
|
+
- [0.87, -0.4]
|
|
13
|
+
- [3.48, -0.4]
|
|
14
|
+
- [3.48, 0]
|
|
15
|
+
- [17.55, 0]
|
|
16
|
+
- [17.55, 8.19]
|
|
17
|
+
- [0, 8.19]
|
|
18
|
+
height: 6.44
|
|
19
|
+
|
|
20
|
+
obstacles:
|
|
21
|
+
- type: rect
|
|
22
|
+
bounds: [7.6, 5.7, 10, 7.2]
|
|
23
|
+
height: 1.5
|
|
24
|
+
label: "Table"
|
|
25
|
+
can_mount_camera: false
|
|
26
|
+
|
|
27
|
+
- type: polygon
|
|
28
|
+
vertices:
|
|
29
|
+
- [5.2, 6.89]
|
|
30
|
+
- [4.7, 7.69]
|
|
31
|
+
- [5.1, 8]
|
|
32
|
+
- [5.65, 7.14]
|
|
33
|
+
height: 1.05
|
|
34
|
+
label: "Console"
|
|
35
|
+
can_mount_camera: false
|
|
36
|
+
|
|
37
|
+
subject:
|
|
38
|
+
height: 2.3
|
|
39
|
+
foot_z: 0.0
|
|
40
|
+
|
|
41
|
+
camera_sets:
|
|
42
|
+
- id: "cam_B"
|
|
43
|
+
name: "tripod setup"
|
|
44
|
+
mounting: "tripod"
|
|
45
|
+
optional: false
|
|
46
|
+
fov_h_landscape: 54.0
|
|
47
|
+
fov_v_landscape: 42.0
|
|
48
|
+
fov_h_portrait: 42.0
|
|
49
|
+
fov_v_portrait: 54.0
|
|
50
|
+
max_range: 9.0
|
|
51
|
+
min_range: 2.0
|
|
52
|
+
height_options: [0.65, 3.0]
|
|
53
|
+
count_max: 18
|
|
54
|
+
min_spacing: 0.5
|
|
55
|
+
walk_axis_margin: 2.0
|
|
56
|
+
score_weight: 1.0
|
|
57
|
+
color: "#1f77b4"
|
|
58
|
+
|
|
59
|
+
- id: "cam_A"
|
|
60
|
+
name: "Wall camera"
|
|
61
|
+
mounting: "wall"
|
|
62
|
+
optional: false
|
|
63
|
+
fov_h_landscape: 110.0
|
|
64
|
+
fov_v_landscape: 70.0
|
|
65
|
+
fov_h_portrait: 70.0
|
|
66
|
+
fov_v_portrait: 110.0
|
|
67
|
+
max_range: 12.0
|
|
68
|
+
min_range: 0.5
|
|
69
|
+
height_options: [2.0, 2.2]
|
|
70
|
+
count_max: 0
|
|
71
|
+
min_spacing: 1.2
|
|
72
|
+
score_weight: 1.0
|
|
73
|
+
color: "#d62728"
|
|
74
|
+
|
|
75
|
+
capture_zones:
|
|
76
|
+
- id: "platform_zone"
|
|
77
|
+
type: "polygon"
|
|
78
|
+
priority: 1
|
|
79
|
+
grid_step: 0.40 # coarser (was 0.20) → fewer eval points
|
|
80
|
+
vertices:
|
|
81
|
+
- [0.0, 0.0]
|
|
82
|
+
- [6.0, 1.0]
|
|
83
|
+
- [6.0, 2.8]
|
|
84
|
+
- [0.0, 1.8]
|
|
85
|
+
placement:
|
|
86
|
+
x_offsets: [3.0]
|
|
87
|
+
y_offsets: [1.5]
|
|
88
|
+
|
|
89
|
+
- id: "treadmill_zone"
|
|
90
|
+
type: "corridor"
|
|
91
|
+
priority: 1
|
|
92
|
+
length: 1.8
|
|
93
|
+
width: 1.0
|
|
94
|
+
placement:
|
|
95
|
+
x_start_options: [1.75]
|
|
96
|
+
y_options: [4.6]
|
|
97
|
+
|
|
98
|
+
optimization:
|
|
99
|
+
target_coverage: 3
|
|
100
|
+
bilateral_weight: 0.9
|
|
101
|
+
vertical_coverage_threshold: 0.85 # slightly relaxed (was 0.90) — the 42° vertical
|
|
102
|
+
# FOV on a 2.3 m subject is geometrically tight
|
|
103
|
+
restarts_per_combo: 4 # fewer (was 10) for a fast first look
|
|
104
|
+
wall_step: 0.35
|
|
105
|
+
tripod_grid_step: 1.10 # coarser (was 0.70) → far fewer tripod candidates
|
|
106
|
+
distance_quality_factor: 0.001
|
|
107
|
+
algo: "greedy_1opt"
|
|
108
|
+
graph_mode: "best_per_combo" # one figure per combo (was "all")
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# =============================================================
|
|
2
|
+
# Lab Camera Optimizer — Configuration file (EVALUATION MODE)
|
|
3
|
+
# Project : CHU Biomechanics Lab — L-shaped room
|
|
4
|
+
# =============================================================
|
|
5
|
+
# Units : metres for all distances, degrees for all angles.
|
|
6
|
+
# Angles follow the standard mathematical convention:
|
|
7
|
+
# 0° = East (+X), 90° = North (+Y), 180°/-180° = West (-X)
|
|
8
|
+
# =============================================================
|
|
9
|
+
|
|
10
|
+
# ─────────────────────────────────────────────────────────────
|
|
11
|
+
# 1. ROOM GEOMETRY
|
|
12
|
+
# ─────────────────────────────────────────────────────────────
|
|
13
|
+
room:
|
|
14
|
+
corners:
|
|
15
|
+
- [0, 0 ]
|
|
16
|
+
- [13, 0 ]
|
|
17
|
+
- [13, 3.0]
|
|
18
|
+
- [8, 3.0]
|
|
19
|
+
- [8, 4.7]
|
|
20
|
+
- [0, 4.7]
|
|
21
|
+
height: 3.0
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# ─────────────────────────────────────────────────────────────
|
|
25
|
+
# 2. OBSTACLES
|
|
26
|
+
# ─────────────────────────────────────────────────────────────
|
|
27
|
+
obstacles:
|
|
28
|
+
- type: rect
|
|
29
|
+
bounds: [1.70, 0.00, 2.04, 0.34]
|
|
30
|
+
height: 3.0
|
|
31
|
+
label: "Stub 1"
|
|
32
|
+
can_mount_camera: true
|
|
33
|
+
|
|
34
|
+
- type: rect
|
|
35
|
+
bounds: [5.39, 0.00, 5.59, 0.42]
|
|
36
|
+
height: 3.0
|
|
37
|
+
label: "Stub 2"
|
|
38
|
+
can_mount_camera: true
|
|
39
|
+
|
|
40
|
+
- type: rect
|
|
41
|
+
bounds: [8.94, 0.00, 9.14, 0.42]
|
|
42
|
+
height: 3.0
|
|
43
|
+
label: "Stub 3"
|
|
44
|
+
can_mount_camera: true
|
|
45
|
+
|
|
46
|
+
- type: rect
|
|
47
|
+
bounds: [5.65, 3.85, 5.85, 4.25]
|
|
48
|
+
height: 3.0
|
|
49
|
+
label: "Stub 4"
|
|
50
|
+
can_mount_camera: true
|
|
51
|
+
|
|
52
|
+
- type: rect
|
|
53
|
+
bounds: [5.65, 2.85, 6.35, 3.55]
|
|
54
|
+
height: 1.4
|
|
55
|
+
label: "Object 1"
|
|
56
|
+
can_mount_camera: false # partial-height object, no camera mount
|
|
57
|
+
|
|
58
|
+
- type: polygon
|
|
59
|
+
vertices:
|
|
60
|
+
- [1.47, 4.70]
|
|
61
|
+
- [1.47, 4.38]
|
|
62
|
+
- [1.71, 4.38]
|
|
63
|
+
- [1.71, 3.88]
|
|
64
|
+
- [2.04, 3.88]
|
|
65
|
+
- [2.04, 4.27]
|
|
66
|
+
- [3.02, 4.27]
|
|
67
|
+
- [3.02, 4.70]
|
|
68
|
+
height: 3.0
|
|
69
|
+
label: "Wall N"
|
|
70
|
+
can_mount_camera: true
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# ─────────────────────────────────────────────────────────────
|
|
74
|
+
# 3. SUBJECT (person being recorded)
|
|
75
|
+
# ─────────────────────────────────────────────────────────────
|
|
76
|
+
subject:
|
|
77
|
+
height: 1.9 # total height feet-to-head (metres)
|
|
78
|
+
foot_z: 0.0 # height of feet above floor (metres, usually 0)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# ─────────────────────────────────────────────────────────────
|
|
82
|
+
# 4. CAMERA SETS
|
|
83
|
+
# ─────────────────────────────────────────────────────────────
|
|
84
|
+
camera_sets:
|
|
85
|
+
|
|
86
|
+
- id: "cam_A"
|
|
87
|
+
name: "ZED2i"
|
|
88
|
+
mounting: "wall"
|
|
89
|
+
optional: false
|
|
90
|
+
|
|
91
|
+
fov_h_landscape: 110.0
|
|
92
|
+
fov_v_landscape: 70.0
|
|
93
|
+
fov_h_portrait: 70.0
|
|
94
|
+
fov_v_portrait: 110.0
|
|
95
|
+
|
|
96
|
+
max_range: 15.0
|
|
97
|
+
min_range: 0.5
|
|
98
|
+
|
|
99
|
+
height_options: [2.0, 2.2]
|
|
100
|
+
|
|
101
|
+
max_count: 7
|
|
102
|
+
min_spacing: 1.5
|
|
103
|
+
|
|
104
|
+
score_weight: 1.0
|
|
105
|
+
color: "#1f77b4"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
- id: "cam_B"
|
|
109
|
+
name: "iPad"
|
|
110
|
+
mounting: "tripod"
|
|
111
|
+
optional: true
|
|
112
|
+
|
|
113
|
+
fov_h_landscape: 80.0
|
|
114
|
+
fov_v_landscape: 58.0
|
|
115
|
+
fov_h_portrait: 58.0
|
|
116
|
+
fov_v_portrait: 80.0
|
|
117
|
+
|
|
118
|
+
max_range: 10.0
|
|
119
|
+
min_range: 0.5
|
|
120
|
+
|
|
121
|
+
height_options: [1.5]
|
|
122
|
+
|
|
123
|
+
max_count: 2
|
|
124
|
+
min_spacing: 1.5
|
|
125
|
+
walk_axis_margin: 0.7
|
|
126
|
+
|
|
127
|
+
score_weight: 0.6
|
|
128
|
+
color: "#d62728"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
# ─────────────────────────────────────────────────────────────
|
|
132
|
+
# 5. CAPTURE ZONES
|
|
133
|
+
# ─────────────────────────────────────────────────────────────
|
|
134
|
+
capture_zones:
|
|
135
|
+
|
|
136
|
+
- id: "full_corridor"
|
|
137
|
+
type: "corridor"
|
|
138
|
+
priority: 0.5
|
|
139
|
+
|
|
140
|
+
length: 8.0
|
|
141
|
+
width: 1.0
|
|
142
|
+
|
|
143
|
+
placement:
|
|
144
|
+
x_start_options: [2.0]
|
|
145
|
+
y_options: [1.70]
|
|
146
|
+
|
|
147
|
+
- id: "analysis_zone"
|
|
148
|
+
type: "sub_zone"
|
|
149
|
+
priority: 1.0
|
|
150
|
+
|
|
151
|
+
length: 6.0
|
|
152
|
+
contained_in: "full_corridor"
|
|
153
|
+
offset_options: [1.0] # Laisse 1m de run-up et 1m de decelération dans le couloir de 8m
|
|
154
|
+
|
|
155
|
+
- id: "sts_point"
|
|
156
|
+
type: "point"
|
|
157
|
+
priority: 2.0
|
|
158
|
+
|
|
159
|
+
radius: 0.6
|
|
160
|
+
contained_in: "analysis_zone"
|
|
161
|
+
auto_optimize: true
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
# ─────────────────────────────────────────────────────────────
|
|
165
|
+
# 6. OPTIMISATION PARAMETERS
|
|
166
|
+
# ─────────────────────────────────────────────────────────────
|
|
167
|
+
optimization:
|
|
168
|
+
target_coverage: 6
|
|
169
|
+
bilateral_weight: 0.8
|
|
170
|
+
vertical_coverage_threshold: 0.9
|
|
171
|
+
restarts_per_combo: 50
|
|
172
|
+
|
|
173
|
+
wall_step: 0.35
|
|
174
|
+
angle_steps: 24
|
|
175
|
+
tripod_grid_step: 0.70
|
|
176
|
+
distance_quality_factor: 0.015
|
|
177
|
+
|
|
178
|
+
algo: "greedy_1opt"
|
|
179
|
+
graph_mode: "all"
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
# ─────────────────────────────────────────────────────────────
|
|
183
|
+
# 7. EVALUATION SETUP (NEW SECTION)
|
|
184
|
+
# ─────────────────────────────────────────────────────────────
|
|
185
|
+
# This section defines the exact fixed camera setup to evaluate.
|
|
186
|
+
# It completely bypasses the optimization process.
|
|
187
|
+
#
|
|
188
|
+
# Run with: python evaluate.py --config configs/evaluate_labo_CHU.yaml
|
|
189
|
+
#
|
|
190
|
+
# Note: The 'tilt' angle is still automatically calculated by the engine
|
|
191
|
+
# to point optimally towards the corridor height.
|
|
192
|
+
# ─────────────────────────────────────────────────────────────
|
|
193
|
+
evaluation_setup:
|
|
194
|
+
fixed_cameras:
|
|
195
|
+
# Cam 1 : Mur Sud
|
|
196
|
+
- { set_id: "cam_A", x: 5.30, y: 0.00, z: 2.3, angle: 120, orientation: "L" }
|
|
197
|
+
# Cam 2 : Mur Sud
|
|
198
|
+
- { set_id: "cam_A", x: 7.25, y: 0.00, z: 2.3, angle: 120, orientation: "L" }
|
|
199
|
+
# Cam 3 : Mur Sud
|
|
200
|
+
- { set_id: "cam_A", x: 11.50, y: 0.00, z: 2.3, angle: 120, orientation: "L" }
|
|
201
|
+
# Cam 4 : Mur Est
|
|
202
|
+
- { set_id: "cam_A", x: 13.00, y: 1.70, z: 2.3, angle: 180, orientation: "L" }
|
|
203
|
+
# Cam 5 : Renfoncement (Mur orienté Sud)
|
|
204
|
+
- { set_id: "cam_A", x: 8.10, y: 3.00, z: 2.3, angle: 300, orientation: "L" }
|
|
205
|
+
# Cam 6 : Sur le Stub 4 (Pilier orienté Sud)
|
|
206
|
+
- { set_id: "cam_A", x: 5.70, y: 3.85, z: 2.3, angle: 290, orientation: "L" }
|
|
207
|
+
# Cam 7 : Sur le Polygone (Mur orienté Sud)
|
|
208
|
+
- { set_id: "cam_A", x: 2.50, y: 4.27, z: 2.3, angle: 310, orientation: "L" }
|
|
209
|
+
# iPad 1 : Avant le couloir, regarde le long de l'axe (vers l'Est)
|
|
210
|
+
- { set_id: "cam_B", x: 1.50, y: 1.70, z: 1.5, angle: 0, orientation: "L" }
|
|
211
|
+
# iPad 2 : Au Nord du couloir, regarde vers la zone de marche (vers le Sud)
|
|
212
|
+
- { set_id: "cam_B", x: 4.70, y: 3.40, z: 1.5, angle: 290, orientation: "L" }
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# ==============================================================================
|
|
2
|
+
# EXAMPLE CONFIG: EVALUATION MODE
|
|
3
|
+
# ==============================================================================
|
|
4
|
+
# This file demonstrates the "Evaluation Mode". Instead of optimizing camera
|
|
5
|
+
# positions, it evaluates a predefined setup from the `evaluation_setup`
|
|
6
|
+
# section below.
|
|
7
|
+
#
|
|
8
|
+
# To run:
|
|
9
|
+
# python evaluate.py --config configs/example_evaluation_CHU.yaml
|
|
10
|
+
#
|
|
11
|
+
# ==============================================================================
|
|
12
|
+
|
|
13
|
+
room:
|
|
14
|
+
corners: [[0,0], [13,0], [13,5], [10,5], [10,3], [0,3]] # L-shaped room
|
|
15
|
+
height: 3.0
|
|
16
|
+
|
|
17
|
+
obstacles:
|
|
18
|
+
- type: polygon
|
|
19
|
+
vertices: [[1.0,0.0],[1.2,0.0],[1.2,0.5],[1.0,0.5]]
|
|
20
|
+
height: 3.0
|
|
21
|
+
label: "Pillar A"
|
|
22
|
+
can_mount_camera: false
|
|
23
|
+
|
|
24
|
+
subject:
|
|
25
|
+
height: 1.8
|
|
26
|
+
foot_z: 0.0
|
|
27
|
+
|
|
28
|
+
camera_sets:
|
|
29
|
+
- id: "wall_cams"
|
|
30
|
+
name: "Wall-mounted Vicon"
|
|
31
|
+
mounting: "wall"
|
|
32
|
+
fov_h_landscape: 80.0
|
|
33
|
+
fov_v_landscape: 50.0
|
|
34
|
+
fov_h_portrait: 50.0
|
|
35
|
+
fov_v_portrait: 80.0
|
|
36
|
+
height_options: [2.0, 2.2, 2.4]
|
|
37
|
+
max_range: 12.0
|
|
38
|
+
min_range: 0.5
|
|
39
|
+
max_count: 8
|
|
40
|
+
min_spacing: 1.5
|
|
41
|
+
score_weight: 1.0
|
|
42
|
+
color: "#1f77b4"
|
|
43
|
+
|
|
44
|
+
capture_zones:
|
|
45
|
+
- id: "analysis_zone"
|
|
46
|
+
type: "corridor"
|
|
47
|
+
priority: 1.0
|
|
48
|
+
length: 6.0
|
|
49
|
+
width: 1.2
|
|
50
|
+
placement:
|
|
51
|
+
x_start_options: [3.0]
|
|
52
|
+
y_options: [1.5]
|
|
53
|
+
|
|
54
|
+
optimization:
|
|
55
|
+
target_coverage: 4
|
|
56
|
+
bilateral_weight: 0.8
|
|
57
|
+
vertical_coverage_threshold: 0.9
|
|
58
|
+
|
|
59
|
+
evaluation_setup:
|
|
60
|
+
fixed_cameras:
|
|
61
|
+
- { set_id: "wall_cams", x: 0.1, y: 0.1, z: 2.2, angle: 45, orientation: "L" }
|
|
62
|
+
- { set_id: "wall_cams", x: 5.0, y: 0.1, z: 2.2, angle: 90, orientation: "P" }
|
|
63
|
+
- { set_id: "wall_cams", x: 12.9, y: 0.1, z: 2.4, angle: 135, orientation: "L" }
|
|
64
|
+
- { set_id: "wall_cams", x: 12.9, y: 4.9, z: 2.4, angle: 225, orientation: "L" }
|
|
65
|
+
- { set_id: "wall_cams", x: 10.1, y: 4.9, z: 2.2, angle: 270, orientation: "P" }
|
|
66
|
+
- { set_id: "wall_cams", x: 0.1, y: 2.9, z: 2.2, angle: 315, orientation: "L" }
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# =============================================================
|
|
2
|
+
# Lab Camera Optimizer — CHU Biomechanics Lab
|
|
3
|
+
# Run config: 10 ZED (wall) + 3 iPad (tripod), walking corridor + STS point.
|
|
4
|
+
# Derived from labo_CHU.yaml (iPad count 2→3, graph_mode → best_per_combo).
|
|
5
|
+
# =============================================================
|
|
6
|
+
|
|
7
|
+
room:
|
|
8
|
+
corners:
|
|
9
|
+
- [0, 0 ]
|
|
10
|
+
- [13, 0 ]
|
|
11
|
+
- [13, 3.0]
|
|
12
|
+
- [8, 3.0]
|
|
13
|
+
- [8, 4.7]
|
|
14
|
+
- [0, 4.7]
|
|
15
|
+
height: 3.0
|
|
16
|
+
|
|
17
|
+
obstacles:
|
|
18
|
+
- type: rect
|
|
19
|
+
bounds: [1.70, 0.00, 2.04, 0.34]
|
|
20
|
+
height: 3.0
|
|
21
|
+
label: "Stub 1"
|
|
22
|
+
can_mount_camera: true
|
|
23
|
+
|
|
24
|
+
- type: rect
|
|
25
|
+
bounds: [5.39, 0.00, 5.59, 0.42]
|
|
26
|
+
height: 3.0
|
|
27
|
+
label: "Stub 2"
|
|
28
|
+
can_mount_camera: true
|
|
29
|
+
|
|
30
|
+
- type: rect
|
|
31
|
+
bounds: [8.94, 0.00, 9.14, 0.42]
|
|
32
|
+
height: 3.0
|
|
33
|
+
label: "Stub 3"
|
|
34
|
+
can_mount_camera: true
|
|
35
|
+
|
|
36
|
+
- type: rect
|
|
37
|
+
bounds: [5.65, 3.85, 5.85, 4.25]
|
|
38
|
+
height: 3.0
|
|
39
|
+
label: "Stub 4"
|
|
40
|
+
can_mount_camera: true
|
|
41
|
+
|
|
42
|
+
- type: rect
|
|
43
|
+
bounds: [5.65, 2.85, 6.35, 3.55]
|
|
44
|
+
height: 1.4
|
|
45
|
+
label: "Object 1"
|
|
46
|
+
can_mount_camera: false
|
|
47
|
+
|
|
48
|
+
- type: polygon
|
|
49
|
+
vertices:
|
|
50
|
+
- [1.47, 4.70]
|
|
51
|
+
- [1.47, 4.38]
|
|
52
|
+
- [1.71, 4.38]
|
|
53
|
+
- [1.71, 3.88]
|
|
54
|
+
- [2.04, 3.88]
|
|
55
|
+
- [2.04, 4.27]
|
|
56
|
+
- [3.02, 4.27]
|
|
57
|
+
- [3.02, 4.70]
|
|
58
|
+
height: 3.0
|
|
59
|
+
label: "Wall N"
|
|
60
|
+
can_mount_camera: true
|
|
61
|
+
|
|
62
|
+
subject:
|
|
63
|
+
height: 1.9
|
|
64
|
+
foot_z: 0.0
|
|
65
|
+
|
|
66
|
+
camera_sets:
|
|
67
|
+
|
|
68
|
+
- id: "cam_A"
|
|
69
|
+
name: "ZED2i"
|
|
70
|
+
mounting: "wall"
|
|
71
|
+
optional: false
|
|
72
|
+
fov_h_landscape: 110.0
|
|
73
|
+
fov_v_landscape: 70.0
|
|
74
|
+
fov_h_portrait: 70.0
|
|
75
|
+
fov_v_portrait: 110.0
|
|
76
|
+
max_range: 15.0
|
|
77
|
+
min_range: 0.5
|
|
78
|
+
height_options: [1.8, 2.0, 2.2, 2.5] # wall mount heights to test (1.8 → 2.5 m)
|
|
79
|
+
max_count: 10 # 10 ZED on the walls
|
|
80
|
+
min_spacing: 1.5
|
|
81
|
+
score_weight: 1.0
|
|
82
|
+
color: "#1f77b4"
|
|
83
|
+
|
|
84
|
+
- id: "cam_B"
|
|
85
|
+
name: "iPad"
|
|
86
|
+
mounting: "tripod"
|
|
87
|
+
optional: false
|
|
88
|
+
fov_h_landscape: 80.0
|
|
89
|
+
fov_v_landscape: 58.0
|
|
90
|
+
fov_h_portrait: 58.0
|
|
91
|
+
fov_v_portrait: 80.0
|
|
92
|
+
max_range: 10.0
|
|
93
|
+
min_range: 0.5
|
|
94
|
+
height_options: [1.5]
|
|
95
|
+
max_count: 3 # 3 iPad on tripods
|
|
96
|
+
min_spacing: 1.5
|
|
97
|
+
walk_axis_margin: 0.7
|
|
98
|
+
score_weight: 0.6
|
|
99
|
+
color: "#d62728"
|
|
100
|
+
|
|
101
|
+
capture_zones:
|
|
102
|
+
|
|
103
|
+
- id: "full_corridor"
|
|
104
|
+
type: "corridor"
|
|
105
|
+
priority: 0.5
|
|
106
|
+
length: 10.0
|
|
107
|
+
width: 1.0
|
|
108
|
+
placement:
|
|
109
|
+
x_start_options: [1.0, 2.0]
|
|
110
|
+
y_options: [1.0, 1.4, 1.8]
|
|
111
|
+
|
|
112
|
+
- id: "analysis_zone"
|
|
113
|
+
type: "sub_zone"
|
|
114
|
+
priority: 1.0
|
|
115
|
+
length: 6.0
|
|
116
|
+
contained_in: "full_corridor"
|
|
117
|
+
offset_options: [1.0, 2.0, 3.0]
|
|
118
|
+
|
|
119
|
+
- id: "sts_point"
|
|
120
|
+
type: "point"
|
|
121
|
+
priority: 2.0
|
|
122
|
+
radius: 0.6
|
|
123
|
+
contained_in: "analysis_zone"
|
|
124
|
+
auto_optimize: true
|
|
125
|
+
|
|
126
|
+
optimization:
|
|
127
|
+
target_coverage: 6
|
|
128
|
+
bilateral_weight: 0.9
|
|
129
|
+
vertical_coverage_threshold: 0.9
|
|
130
|
+
restarts_per_combo: 35 # Maximale
|
|
131
|
+
wall_step: 0.25 # finer wall candidate spacing
|
|
132
|
+
angle_steps: 24
|
|
133
|
+
tripod_grid_step: 0.50 # finer tripod grid
|
|
134
|
+
distance_quality_factor: 0.001
|
|
135
|
+
algo: "greedy_1opt"
|
|
136
|
+
graph_mode: "best_per_combo"
|