Skip to content

Commit 3be4958

Browse files
committed
Updated ToF docs, added diagram, updated settings
1 parent 193eb17 commit 3be4958

File tree

5 files changed

+58
-34
lines changed

5 files changed

+58
-34
lines changed
416 KB
Loading

docs/source/components/nodes/color_camera.rst

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,12 @@ For IMX378 (12MP), the **post-processing** works like this:
6969
│ ISP ├────────────────►│ video ├───────────────►│ preview │
7070
└─────┘ max 3840x2160 └─────────┘ and cropping └──────────┘
7171
72-
If resolution was set to 12MP, and we were to use ``video``, we'd get a 4K frame (3840x2160) cropped from the center of the 12MP frame.
72+
If the resolution is set to 12MP and video mode is used, a 4K frame (3840x2160) will be cropped from the center of the 12MP frame.
7373

7474
Full FOV
7575
########
7676

77-
Some sensors (let's take IXM378 for an example) will, by default, have 1080P resolution set, which is a crop from the full sensor resolution.
78-
You can print sensor features to see how FOV is affected by the selected sensor resolution:
77+
Some sensors, such as the IXM378, default to a 1080P resolution, which is a crop from the full sensor resolution. You can print sensor features to see how the field of view (FOV) is affected by the selected sensor resolution:
7978

8079
.. code-block:: python
8180
@@ -104,8 +103,8 @@ You can print sensor features to see how FOV is affected by the selected sensor
104103
# {width: 1280, height: 800, minFps: 1.687, maxFps: 129.6, type: MONO, fov: {x:0, y: 0, width: 1280, height: 800}}
105104
# {width: 640, height: 400, minFps: 1.687, maxFps: 255.7, type: MONO, fov: {x:0, y: 0, width: 1280, height: 800}}
106105
107-
So for IMX378, if we select 4K or 1080P resolution, FOV will be cropped ~5% horizontally and ~29% vertically. So we can either select ``THE_12_MP``,
108-
``THE_1352X1012``, or ``THE_2024X1520`` resolution to get the full sensor FOV.
106+
For the IMX378 sensor, selecting a 4K or 1080P resolution results in approximately 5% horizontal and 29% vertical FOV cropping.
107+
To utilize the full sensor FOV, you should choose one of the following resolutions: ``THE_12_MP``, ``THE_1352X1012``, or ``THE_2024X1520``.
109108

110109
Usage
111110
#####

docs/source/components/nodes/tof.rst

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,40 @@ In :ref:`ToF depth` example we allow users to quickly configure ToF settings. Th
6161

6262
And these settings are up to the user:
6363

64-
- Optical Correction: It's a process that corrects the optical effect (On -> ToF returns distance represented by Green Line), so it matches :ref:`StereoDepth` depth reporting. It does rectification and distance to depth conversion (Z-map).
64+
(level+1)*1.5m + phaseUnwrapErrorThreshold/2
65+
- Optical Correction: It's a process that corrects the optical effect. When enabled, the ToF returns depth map (represented by Green Line on graph below) instead of distance, so it matches :ref:`StereoDepth` depth reporting. It does rectification and distance to depth conversion (Z-map).
6566
- Phase Unwrapping - Process that corrects the phase wrapping effect of the ToF sensor. You can set it to [0..5 are optimized]. The higher the number, the longer the ToF range, but it also increases the noise.
66-
- `0` - Disabled.
67-
- `1` - Up to 1.5 meters
68-
- `2` - Up to 3 meters
69-
- `3` - Up to 4.5 meters
70-
- `4` - Up to 6 meters
71-
- `5` - Up to 7.5 meters (not recommended for most applications)
67+
- `0` - Disabled, up to ~1.5 meters
68+
- `1` - Up to ~3 meters
69+
- `2` - Up to ~4.5 meters
70+
- `3` - Up to ~6 meters
71+
- `4` - Up to ~7.5 meters
72+
- Burst mode: When enabled, ToF node won't reuse frames, as shown on the graph below. It's related to post-processing of the ToF frames, not the actual sensor/projector. It's disabled by default.
73+
- Phase shuffle Temporal filter: Averages shuffled and non-shuffled frames of the same modulation frequency to reduce noise. It's enabled by default. You can disable it to reduce :ref:`ToF motion blur` and system load.
7274

7375
.. image:: /_static/images/components/tof-optical-correction.png
7476

77+
.. image:: /_static/images/components/tof-diagram.png
78+
79+
Phase unwrapping
80+
################
81+
82+
If the time it takes for the light to travel from ToF sensor and back exceeds the period of the emitted wave (1.5m or 1.8m), the resulting measurement will "wrap" back to a lower value. This is called phase wrapping.
83+
It's similar to how a clock resets after 12 hours. Phase unwrapping is possible as our ToF has two different modulation frequencies (80Mhz and 100MHz).
84+
85+
Phase unwrapping aims to correct this by allowing the sensor to interpret longer distances without confusion. It uses algorithms to keep track of how many cycles (round trips of the wave) have occurred,
86+
thus correcting the "wrapped" phases. The downside is that the more cycles the sensor has to keep track of, the more noise it introduces into the measurement.
87+
88+
ToF motion blur
89+
###############
90+
91+
To reduce motion blur, we recommend these settings:
92+
93+
- Increase camera FPS. It goes up to 160 FPS, which causes frame capture to be the fastest (6.25ms between frames). This will reduce motion blur as ToF combines multiple frames to get the depth. Note that 160FPS will increase system load significantly (see :ref:`Debugging <Debugging DepthAI pipeline>`). Note also that higher FPS -> lower exposure times, which can increase noise.
94+
- Disable phase shuffle temporal filter. This will introduce more noise.
95+
- Disable phase unwrapping. This will reduce max distance to 1.5 meters, so about 1 cubic meter of space will be visible.
96+
- Enable burst mode. This is irrelevant if shuffle filter and phase unwrapping are disabled (see diagram above). When enabled, ToF node won't reuse frames (lower FPS).
97+
7598
Max distance
7699
############
77100

@@ -84,10 +107,10 @@ Maximum ToF distance depends on the phase unwrapping level and modulation freque
84107
c & = 299792458.0 \quad \text{//! speed of light in m/s} \\
85108
MAX\_80MHZ\_MM & = \frac{c}{80000000 \times 2} \times 1000 \quad \text{//! convert speed of light to mm/160ns} \\
86109
MAX\_MM\_80MHZ & = \text{round}(MAX\_80MHZ\_MM) \quad \text{// round(1873.7) -> 1874} \\
87-
MAX\_DIST\_80MHZ & = 1874 \times (\text{phaseUnwrappingLevel} + 1) \quad \text{//! in mm for 80 MHz} \\
110+
MAX\_DIST\_80MHZ & = (\text{phaseUnwrappingLevel} + 1) \times 1.5 \times 1000 + \frac{\text{phaseUnwrapErrorThreshold}}{2} \quad \text{//! corrected formula in mm for 80 MHz} \\
88111
MAX\_100MHZ\_MM & = \frac{c}{100000000 \times 2} \times 1000 \quad \text{//! convert speed of light to mm/200ns} \\
89112
MAX\_MM\_100MHZ & = \text{round}(MAX\_100MHZ\_MM) \quad \text{// round(1498.9636) -> 1499} \\
90-
MAX\_DIST\_100MHZ & = 1499 \times (\text{phaseUnwrappingLevel} + 1) \quad \text{//! in mm for 100 MHz}
113+
MAX\_DIST\_100MHZ & = (\text{phaseUnwrappingLevel} + 1) \times 1.5 \times 1000 + \frac{\text{phaseUnwrapErrorThreshold}}{2} \quad \text{//! corrected formula in mm for 100 MHz} \\
91114
\end{align*}
92115
93116
Usage
@@ -113,6 +136,14 @@ Usage
113136
# Median filter, kernel size 5x5
114137
tof.initialConfig.setMedianFilter(dai.MedianFilter.KERNEL_5x5)
115138

139+
tofConfig = tof.initialConfig.get()
140+
# Temporal filter averages shuffle/non-shuffle frequencies
141+
tofConfig.enablePhaseShuffleTemporalFilter = True
142+
# Phase unwrapping, for longer range.
143+
tofConfig.phaseUnwrappingLevel = 4 # Up to 7.5 meters
144+
tofConfig.phaseUnwrapErrorThreshold = 300
145+
tof.initialConfig.set(tofConfig)
146+
116147
# ToF node converts raw sensor frames into depth
117148
tof_cam.raw.link(tof.input)
118149

docs/source/samples/ToF/tof_depth.rst

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ With keyboard you can configure ToF settings:
2222
- Temperature Correction: Turn on/off with `t`. It's a process that corrects the temperature effect of the ToF sensor. Should be enabled.
2323
- Optical Correction: Turn on/off with `o`. It's a process that corrects the optical effect (On -> ToF returns distance represented by Green Line), so it matches stereo depth reporting.
2424
- Phase Unwrapping - Process that corrects the phase wrapping effect of the ToF sensor. The higher the number, the longer the ToF range, but it also increases the noise.
25-
- `0` - Disabled.
26-
- `1` - Up to 1.5 meters
27-
- `2` - Up to 3 meters
28-
- `3` - Up to 4.5 meters
29-
- `4` - Up to 6 meters
30-
- `5` - Up to 6 meters
25+
- `0` - Disabled, up to ~1.5 meters
26+
- `1` - Up to ~3 meters
27+
- `2` - Up to ~4.5 meters
28+
- `3` - Up to ~6 meters
29+
- `4` - Up to ~7.5 meters
30+
- `5` - Up to ~9 meters (increased noise - not recommended for most applications)
3131

3232
.. image:: /_static/images/components/tof-optical-correction.png
3333

examples/ToF/tof_depth.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ def create_pipeline():
1818

1919
# Configure the ToF node
2020
tofConfig = tof.initialConfig.get()
21+
# Disable for debugging:
2122
tofConfig.enableFPPNCorrection = True
22-
tofConfig.enableOpticalCorrection = True
2323
tofConfig.enableWiggleCorrection = True
24-
tofConfig.enableTemperatureCorrection = False
24+
tofConfig.enableTemperatureCorrection = True
25+
# Optional:
26+
tofConfig.enableOpticalCorrection = True
2527
tofConfig.phaseUnwrappingLevel = 4
2628
tofConfig.phaseUnwrapErrorThreshold = 300
2729
xinTofConfig = pipeline.create(dai.node.XLinkIn)
@@ -32,7 +34,7 @@ def create_pipeline():
3234

3335
cam_tof = pipeline.create(dai.node.Camera)
3436
cam_tof.properties.numFramesPoolRaw = 5
35-
cam_tof.setFps(60)
37+
cam_tof.setFps(60) # ToF node will produce depth frames at /2 of this rate
3638
cam_tof.setImageOrientation(dai.CameraImageOrientation.ROTATE_180_DEG)
3739
cam_tof.setBoardSocket(dai.CameraBoardSocket.CAM_A)
3840
cam_tof.raw.link(tof.input)
@@ -41,7 +43,6 @@ def create_pipeline():
4143
xout.setStreamName("depth")
4244
tof.depth.link(xout.input)
4345

44-
4546
tofConfig = tof.initialConfig.get()
4647

4748
return pipeline, tofConfig
@@ -76,7 +77,7 @@ def create_pipeline():
7677
break
7778
elif key == ord('0'):
7879
tofConfig.enablePhaseUnwrapping = False
79-
tofConfig.phaseUnwrappingLevel = 4
80+
tofConfig.phaseUnwrappingLevel = 0
8081
tofConfigInQueue.send(tofConfig)
8182
elif key == ord('1'):
8283
tofConfig.enablePhaseUnwrapping = True
@@ -114,15 +115,8 @@ def create_pipeline():
114115

115116
imgFrame = qDepth.get() # blocking call, will wait until a new data has arrived
116117
depth_map = imgFrame.getFrame()
117-
118-
depth_downscaled = depth_map[::4]
119-
non_zero_depth = depth_downscaled[depth_downscaled != 0] # Remove invalid depth values
120-
if len(non_zero_depth) == 0:
121-
min_depth, max_depth = 0, 0
122-
else:
123-
min_depth = 200
124-
max_depth = 6000
125-
depth_colorized = np.interp(depth_map, (min_depth, max_depth), (0, 255)).astype(np.uint8)
118+
max_depth = (tofConfig.phaseUnwrappingLevel - 1) * 1874 # 80MHz modulation freq.
119+
depth_colorized = np.interp(depth_map, (0, max_depth), (0, 255)).astype(np.uint8)
126120
depth_colorized = cv2.applyColorMap(depth_colorized, cvColorMap)
127121

128122
cv2.imshow("Colorized depth", depth_colorized)

0 commit comments

Comments
 (0)