Skip to content

Commit 5b4daba

Browse files
authored
Merge pull request #1443 from luxonis/v3_dcl_readMePatch
Update README.md
2 parents a281eeb + 4af4913 commit 5b4daba

File tree

10 files changed

+133
-60
lines changed

10 files changed

+133
-60
lines changed

examples/cpp/DynamicCalibration/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ cmake_minimum_required(VERSION 3.10)
44
## function: dai_add_example(example_name example_src enable_test use_pcl)
55
## function: dai_set_example_test_labels(example_name ...)
66

7-
dai_add_example(calib_quality_dynamic calib_quality_dynamic.cpp ON OFF)
8-
dai_add_example(calibrate_dynamic calibrate_dynamic.cpp ON OFF)
9-
dai_add_example(calib_integration calib_integration.cpp ON OFF)
7+
dai_add_example(calibration_quality_dynamic calibration_quality_dynamic.cpp ON OFF)
8+
dai_add_example(calibration_dynamic calibration_dynamic.cpp ON OFF)
9+
dai_add_example(calibration_integration calibration_integration.cpp ON OFF)

examples/cpp/DynamicCalibration/README.md

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Dynamic Calibration (C++) — DepthAI
22

3-
This folder contains two minimal, end-to-end **C++** examples that use **`dai::node::DynamicCalibration`** to (a) **calibrate** a stereo rig live and (b) **evaluate** calibration quality on demandboth while streaming synchronized stereo frames and disparity for visual feedback.
3+
This folder contains three minimal, end-to-end **C++** examples that use **`dai::node::DynamicCalibration`** to (a) **calibrate** a stereo rig live and (b) **evaluate** calibration quality on demand, (c) combination of both while streaming synchronized stereo frames and disparity for visual feedback.
44

55
> Close your preview window or stop the program to quit.
66
@@ -9,10 +9,10 @@ This folder contains two minimal, end-to-end **C++** examples that use **`dai::n
99
## What the node does
1010

1111
`dai::node::DynamicCalibration` consumes **raw, unrectified** left/right mono frames and:
12-
- Streams **coverage feedback** (how well the calibration pattern is seen across the image).
12+
- Streams **coverage feedback**.
1313
- Produces either:
1414
- a **new calibration** (`CalibrationHandler`) you can apply on the device, or
15-
- a **quality report** comparing *current* vs *achievable* calibration.
15+
- a **quality report** comparing *current* vs *achieved* calibration.
1616

1717
### Outputs & metrics (C++ message types)
1818

@@ -37,36 +37,69 @@ This folder contains two minimal, end-to-end **C++** examples that use **`dai::n
3737

3838
## 1) Live dynamic calibration (apply new calibration)
3939

40-
**File idea:** `calibrate_dynamic.cpp`
40+
**File idea:** `calibration_dynamic.cpp`
4141

4242
**Flow:**
4343
1. Create mono cameras → request **full-res NV12** (unrectified) → link to:
4444
- `DynamicCalibration.left/right`
4545
- `StereoDepth.left/right` (for live disparity view)
4646
2. Start the pipeline, give AE a moment to settle.
47-
3. **Start calibration** by sending `DynamicCalibrationControl(StartCalibrationCommand{})`.
47+
3. **Start calibration** by sending `DynamicCalibrationControl::Command::StartCalibration{}`.
4848
4. In the loop:
4949
- Show `left`, `right`, and `disparity`.
5050
- Poll `coverageOutput` for progress.
5151
- Poll `calibrationOutput` for a result.
5252
5. When a result arrives:
53-
- **Apply** it by sending `ApplyCalibrationCommand(newCalibration)` on the control queue.
53+
- **Apply** it by sending `DynamicCalibrationControl::Command::ApplyCalibration{newCalibration}` on the control queue.
5454
- Print quality deltas.
5555

5656
---
5757

5858
## 2) Calibration **quality check** (no applying)
5959

60-
**File idea:** `quality_dynamic.cpp`
60+
**File idea:** `calibration_quality_dynamic.cpp`
6161

6262
**Flow:**
6363
1. Same camera / StereoDepth / DynamicCalibration setup as above.
6464
2. In the loop:
65-
- Send **coverage** request (`LoadImageCommand{}`) and read `coverageOutput`.
66-
- Send **quality** request (`CalibrationQualityCommand{}`) and read `qualityOutput`.
65+
- Send **coverage** request (`DynamicCalibrationControl::Command::LoadImage{}`) and read `coverageOutput`.
66+
- Send **quality** request (`DynamicCalibrationControl::Command::CalibrationQuality{}`) and read `qualityOutput`.
6767
3. If `qualityData` is present, print rotation/Sampson/depth-error metrics.
68-
4. Optionally reset internal sample store (`ResetDataCommand{}`).
68+
4. Optionally reset internal sample store (`DynamicCalibrationControl::Command::ResetData{}`).
6969

70+
71+
---
72+
73+
## 3) Continuous monitoring **+ auto-recalibration** (single binary)
74+
75+
**File:** `calibration_integration.cpp`
76+
77+
**What it does:**
78+
Runs one loop that periodically checks calibration quality and, if drift is detected, starts calibration and applies the new calibration automatically — while showing `left`, `right`, and a colorized `disparity` preview.
79+
80+
**Flow:**
81+
1. Create mono cameras → request **full-res NV12** (unrectified) → link to `dai::node::DynamicCalibration` and `dai::node::StereoDepth` for live disparity. Read the device’s current calibration as the baseline.
82+
2. On a fixed interval (e.g., ~3 seconds), send on the control queue:
83+
- `DynamicCalibrationControl::Command::LoadImage{}` to compute coverage on the current frames, and
84+
- `DynamicCalibrationControl::Command::CalibrationQuality{true}` to request a (forced) quality estimate.
85+
3. When a **quality** message arrives on `qualityOutput`:
86+
- Log status; if `qualityData` is present, you may **reset** the internal data store with `DynamicCalibrationControl::Command::ResetData{}`.
87+
- If quality indicates drift (for example, `abs(sampsonErrorNew - sampsonErrorCurrent) > 0.05f`), **start calibration** with `DynamicCalibrationControl::Command::StartCalibration{}`.
88+
4. When a **calibration** message arrives on `calibrationOutput`:
89+
- **Apply** the new `CalibrationHandler` with `DynamicCalibrationControl::Command::ApplyCalibration{result.newCalibration}`, then **reset** data again (`ResetData{}`) to begin monitoring afresh.
90+
5. Exit on `q` keypress or window close.
91+
92+
**Notes & defaults:**
93+
- Disparity preview can be auto-scaled to the observed maximum; zero disparity can be rendered black for clarity.
94+
- The 0.05 px Sampson threshold is a simple heuristic — tune to your tolerance and noise profile.
95+
96+
**Example console output:**
97+
```
98+
Dynamic calibration status: success
99+
Successfully evaluated Quality
100+
Start recalibration process
101+
Successfully calibrated
102+
```
70103
---
71104

72105
## Pipeline diagram
@@ -101,8 +134,11 @@ find_package(depthai CONFIG REQUIRED) # provides depthai::core
101134
add_executable(calibrate_dynamic calibrate_dynamic.cpp)
102135
target_link_libraries(calibrate_dynamic PRIVATE depthai::core)
103136
104-
add_executable(quality_dynamic quality_dynamic.cpp)
105-
target_link_libraries(quality_dynamic PRIVATE depthai::core)
137+
add_executable(calibration_quality_dynamic calibration_quality_dynamic.cpp)
138+
target_link_libraries(calibration_quality_dynamic PRIVATE depthai::core)
139+
140+
add_executable(calibration_integration calibration_integration.cpp)
141+
target_link_libraries(calibration_integration PRIVATE depthai::core)
106142
```
107143

108144
Build:
@@ -114,27 +150,28 @@ cmake --build . -j
114150

115151
Run:
116152
```bash
117-
./calibrate_dynamic # applies new calibration when ready
118-
./quality_dynamic # reports metrics; does not apply
153+
./calibration_dynamic # applies new calibration when ready
154+
./calibration_quality_dynamic # reports metrics; does not apply
155+
./calibration_integration # monitors quality, auto-recalibrates, and applies in one loop
119156
```
120157

121158
---
122159

123160
## Commands overview (C++)
124161

125-
- `DynamicCalibrationControl::StartCalibrationCommand{}`
126-
Begins dynamic calibration collection/solve. Combine with performance modes if available.
162+
- `DynamicCalibrationControl::Command::StartCalibration{}`
163+
Begins dynamic calibration collection/solve.
127164

128-
- `DynamicCalibrationControl::ApplyCalibrationCommand{CalibrationHandler}`
165+
- `DynamicCalibrationControl::Command::ApplyCalibration{CalibrationHandler}`
129166
Applies the provided calibration on-device (affects downstream nodes in-session).
130167

131-
- `DynamicCalibrationControl::LoadImageCommand{}`
168+
- `DynamicCalibrationControl::Command::LoadImage{}`
132169
Triggers coverage computation for the latest frames.
133170

134-
- `DynamicCalibrationControl::CalibrationQualityCommand{bool force=false}`
171+
- `DynamicCalibrationControl::Command::CalibrationQuality{bool force=false}`
135172
Produces a `CalibrationQuality` message with `qualityData` if estimation is possible.
136173

137-
- `DynamicCalibrationControl::ResetDataCommand{}`
174+
- `DynamicCalibrationControl::Command::ResetData{}`
138175
Clears accumulated samples/coverage state.
139176

140177
---

examples/python/CMakeLists.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -343,12 +343,12 @@ dai_set_example_test_labels(image_filters rvc2_all rvc4 ci)
343343

344344
# DynamicCalibration
345345
if(DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT)
346-
add_python_example(calib_integration DynamicCalibration/calib_integration.py)
347-
dai_set_example_test_labels(calib_integration ondevice rvc2_all rvc4 ci)
346+
add_python_example(calibration_integration DynamicCalibration/calibration_integration.py)
347+
dai_set_example_test_labels(calibration_integration ondevice rvc2_all rvc4 ci)
348348

349-
add_python_example(calib_quality_dynamic DynamicCalibration/calib_quality_dynamic.py)
350-
dai_set_example_test_labels(calib_quality_dynamic ondevice rvc2_all rvc4 ci)
349+
add_python_example(calibration_quality_dynamic DynamicCalibration/calibration_quality_dynamic.py)
350+
dai_set_example_test_labels(calibration_quality_dynamic ondevice rvc2_all rvc4 ci)
351351

352-
add_python_example(calibrate_dynamic DynamicCalibration/calibrate_dynamic.py)
353-
dai_set_example_test_labels(calibrate_dynamic ondevice rvc2_all rvc4 ci)
352+
add_python_example(calibration_dynamic DynamicCalibration/calibration_dynamic.py)
353+
dai_set_example_test_labels(calibration_dynamic ondevice rvc2_all rvc4 ci)
354354
endif()

examples/python/DynamicCalibration/README.md

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Dynamic Calibration (Python) — DepthAI
22

3-
This folder contains two minimal, end-to-end examples that use **`dai.node.DynamicCalibration`** to (a) **calibrate** a stereo rig live and (b) **evaluate** calibration quality on demand both while streaming synchronized stereo frames and disparity for visual feedback.
3+
This folder contains three minimal, end-to-end examples that use **`dai.node.DynamicCalibration`** to (a) **calibrate** a stereo device real-time and (b) **evaluate** calibration quality on demand (c) combination of both while streaming synchronized stereo frames and disparity for visual feedback.
44

55
> Press **`q`** in the preview window to quit either example.
66
@@ -9,24 +9,24 @@ This folder contains two minimal, end-to-end examples that use **`dai.node.Dynam
99
## What the node does
1010

1111
`dai.node.DynamicCalibration` consumes **raw, unrectified** left/right mono frames and:
12-
- Streams **coverage feedback** (how well the calibration pattern is seen across the image).
12+
- Streams **coverage feedback**
1313
- Produces either:
14-
- a **new calibration** (intrinsics/extrinsics) you can apply on the device, or
15-
- a **quality report** comparing *current* vs *achievable* calibration.
14+
- a **new calibration** (extrinsics) you can apply on the device, or
15+
- a **quality report** comparing *current* vs *achieved* calibration.
1616

1717
### Outputs & metrics
1818

1919
- **CoverageData** (`coverageOutput`)
20-
- `meanCoverage` — overall spatial coverage [0–1].
21-
- `dataAcquired` — amount of calibration-relevant data gathered [0–1].
22-
- `coveragePerCellA/B` - matrix of spatial coverage of imager A or B
20+
- `meanCoverage: float` — overall spatial coverage [0–1].
21+
- `dataAcquired: float` — amount of calibration-relevant data gathered [0–1].
22+
- `coveragePerCellA/B: list[list[float]]` - matrix of spatial coverage of imager A or B [0-1].
2323

2424
- **DynamicCalibrationResult** (`calibrationOutput`)
25-
- `newCalibration``CalibrationHandler` with updated parameters.
25+
- `newCalibration: dai.CalibrationHanlder``CalibrationHandler` with updated parameters.
2626
- `calibrationDifference` — quality deltas between current and new:
27-
- `rotationChange[3]` — extrinsic angle deltas (deg).
28-
- `sampsonErrorCurrent`, `sampsonErrorNew` — reprojection proxy (px).
29-
- `depthErrorDifference[4]` — theoretical depth error change at 1/2/5/10 m (%).
27+
- `rotationChange[3]: list[float]` — extrinsic angle deltas (deg).
28+
- `sampsonErrorCurrent: float`, `sampsonErrorNew: float` — reprojection proxy (px).
29+
- `depthErrorDifference[4]: list[float]` — theoretical depth error change at 1/2/5/10 m (%).
3030
- `info` — human-readable status (e.g., "success").
3131

3232
- **CalibrationQuality** (`qualityOutput`)
@@ -35,9 +35,9 @@ This folder contains two minimal, end-to-end examples that use **`dai.node.Dynam
3535

3636
---
3737

38-
## 1) Live dynamic calibration (apply new calibration)
38+
## 1) Real-time dynamic calibration (apply new calibration)
3939

40-
**Script idea:** `calibrate_dynamic.py` (based on your first snippet)
40+
**Script:** `calibration_dynamic.py`
4141

4242
**Flow:**
4343
1. Create mono cameras → request **full-res NV12** (unrectified) → link to:
@@ -47,7 +47,7 @@ This folder contains two minimal, end-to-end examples that use **`dai.node.Dynam
4747
3. **Start calibration** with:
4848
```python
4949
dynCalibInputControl.send(
50-
dai.StartCalibrationCommand()
50+
dai.DynamicCalibrationControl(dai.DynamicCalibrationControl.Commands.StartCalibration())
5151
)
5252
```
5353
4. In the loop:
@@ -57,7 +57,7 @@ This folder contains two minimal, end-to-end examples that use **`dai.node.Dynam
5757
5. When a result arrives:
5858
- **Apply** it:
5959
```python
60-
dynCalibInputControl.send(dai.ApplyCalibrationCommand(calibrationData.newCalibration))
60+
dynCalibInputControl.send(dai.DynamicCalibrationControl(dai.DynamicCalibrationControl.Commands.ApplyCalibration(calibrationData.newCalibration)))
6161
```
6262
- Print quality deltas: rotation magnitude, Sampson errors, depth-error deltas.
6363

@@ -77,28 +77,28 @@ Theoretical Depth Error Difference @1m:-4.20%, 2m:-3.10%, 5m:-1.60%, 10m:-0.90%
7777
7878
---
7979
80-
## 2) Calibration **quality check** (no applying)
80+
## 2) Calibration **quality check**
8181
82-
**Script idea:** `quality_dynamic.py` (based on your second snippet)
82+
**Script:** `calibration_quality_dynamic.py`
8383
8484
**Flow:**
8585
1. Same camera / StereoDepth / DynamicCalibration setup as above.
8686
2. In the loop:
8787
- Show `left`, `right`, and `disparity`.
8888
- Ask for **coverage** on demand:
8989
```python
90-
dynCalibInputControl.send(dai.LoadImageCommand())
90+
dynCalibInputControl.send(dai.DynamicCalibrationControl(dai.DynamicCalibrationControl.Commands.LoadImage()))
9191
coverage = dynCalibCoverageQueue.get()
9292
```
9393
- Ask for **quality** on demand:
9494
```python
95-
dynCalibInputControl.send(dai.CalibrationQualityCommand())
95+
dynCalibInputControl.send(dai.DynamicCalibrationControl(dai.DynamicCalibrationControl.Commands.dai.CalibrationQuality()))
9696
dynQualityResult = dynCalibQualityQueue.get()
9797
```
9898
3. If `qualityData` is present, print rotation/Sampson/depth-error metrics.
9999
4. Optionally reset the internal sample store:
100100
```python
101-
dynCalibInputControl.send(dai.ResetDataCommand())
101+
dynCalibInputControl.send(dai.DynamicCalibrationControl(dai.DynamicCalibrationControl.Commands.ResetData()))
102102
```
103103

104104
**Use this when:**
@@ -107,6 +107,39 @@ Theoretical Depth Error Difference @1m:-4.20%, 2m:-3.10%, 5m:-1.60%, 10m:-0.90%
107107

108108
---
109109

110+
## 3) Continuous monitoring **+ auto-recalibration** (single script)
111+
112+
**Script:** `calibration_integration.py`
113+
114+
**What it does:**
115+
Runs one loop that periodically checks calibration quality and, if drift is detected, starts calibration and applies the new calibration automatically — while showing `left`, `right`, and colorized `disparity` previews.
116+
117+
**Flow:**
118+
1. Create mono cameras → request **full-res NV12** → link to `DynamicCalibration` and `StereoDepth` for live disparity. Read the device’s current calibration as baseline.
119+
2. On a fixed interval (for example, every ~3 seconds), send:
120+
- `LoadImage()` to compute coverage on the current frames, and
121+
- `CalibrationQuality(True)` (or equivalent) to request a quality estimate.
122+
3. When a quality result arrives:
123+
- Log status; if quality data is present, **reset** the internal data store.
124+
- If the quality indicates drift (e.g., a Sampson error delta above a small threshold like 0.05 px), **start calibration** (`StartCalibration()`).
125+
4. When a calibration result arrives:
126+
- **Apply** the new `CalibrationHandler` to the device and **reset** data again.
127+
5. Press **`q`** to exit.
128+
129+
**Notes & defaults:**
130+
- Disparity preview is auto-scaled to the observed maximum; **zero disparity appears black** for clarity.
131+
- The 0.05 px Sampson threshold is a simple heuristic — adjust per your tolerance.
132+
133+
**Example console output:**
134+
```
135+
Dynamic calibration status: success
136+
Successfully evaluated Quality
137+
Start recalibration process
138+
Successfully calibrated
139+
```
140+
141+
---
142+
110143
## Pipeline diagram
111144

112145
```
@@ -137,10 +170,13 @@ pip install depthai opencv-python numpy
137170

138171
```bash
139172
# Live calibration (applies new calibration when ready)
140-
python calibrate_dynamic.py
173+
python calibration_dynamic.py
174+
175+
# Quality evaluation (reports metrics of when recalibration is required)
176+
python calibration_quality_dynamic.py
141177

142-
# Quality evaluation (reports metrics; does not apply)
143-
python quality_dynamic.py
178+
# Integration example (starts new calibration when the quality reports major changes)
179+
python calibration_integration.py
144180
```
145181

146182
> Tip: Ensure your calibration target is well-lit, sharp, and observed across the **entire** FOV. Aim for high `meanCoverage` and steadily increasing `dataAcquired`.
@@ -149,19 +185,19 @@ python quality_dynamic.py
149185

150186
## Commands overview
151187

152-
- `StartCalibrationCommand()`
153-
Begins dynamic calibration collection/solve. Use `OPTIMIZE_SPEED` for speed or `OPTIMIZE_PERFORMANCE` for more robust estimation.
188+
- `StartCalibration()`
189+
Begins dynamic calibration collection/solve.
154190

155-
- `ApplyCalibrationCommand(calibration)`
191+
- `ApplyCalibration(calibration)`
156192
Applies the provided `CalibrationHandler` to the device (affects downstream nodes in this session).
157193

158-
- `LoadImageCommand()`
194+
- `LoadImage()`
159195
Triggers coverage computation for the current frame(s).
160196

161-
- `CalibrationQualityCommand()`
197+
- `CalibrationQuality()`
162198
Produces a `CalibrationQuality` message with `qualityData` if estimation is possible.
163199

164-
- `ResetDataCommand()`
200+
- `ResetData()`
165201
Clears accumulated samples/coverage state to start fresh.
166202

167203
---
@@ -187,9 +223,9 @@ python quality_dynamic.py
187223
Ensure the pattern is visible, not motion-blurred, and covers diverse regions of the image. Increase lighting, adjust exposure, or hold the rig steady.
188224

189225
- **Disparity looks worse after apply**
190-
Re-run to collect more diverse views (tilt/translate the target), or try `OPTIMIZE_PERFORMANCE`. Check for lens smudges and ensure focus is appropriate.
226+
Re-run to collect more diverse views (tilt/translate the target).
191227

192228
- **Typos in prints**
193229
The examples should print “Successfully calibrated” and “Rotation difference” (avoid “Succesfully”/“dofference” if copying code).
194230

195-
---
231+
---

0 commit comments

Comments
 (0)