Skip to content

Commit b2c34e2

Browse files
authored
Merge pull request #776 from luxonis/stereo_docs
Started working on stereo
2 parents 656c2f3 + 191551c commit b2c34e2

File tree

10 files changed

+569
-238
lines changed

10 files changed

+569
-238
lines changed
22.2 KB
Loading
22.7 KB
Loading
86.3 KB
Loading
22.2 KB
Loading

docs/source/components/bootloader.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,10 @@ to the pipeline. Instead of transferring the whole package, only Pipeline descri
9797
Depthai application package (**.dap**) consists of:
9898

9999
- SBR (512B header which describes sections of data)
100-
- Depthai device firmware (section __firmware)
101-
- Pipeline description (section pipeline)
102-
- Assets structure (section assets)
103-
- Asset storage (section asset_storage)
100+
- Depthai device firmware (section "__firmware")
101+
- Pipeline description (section "pipeline")
102+
- Assets structure (section "assets")
103+
- Asset storage (section "asset_storage")
104104

105105
MAC address
106106
###########

docs/source/components/nodes/stereo_depth.rst

Lines changed: 18 additions & 232 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
StereoDepth
22
###########
33

4-
StereoDepth node calculates the disparity/depth from the stereo camera pair (2x :ref:`MonoCamera <MonoCamera>`).
4+
StereoDepth node calculates the disparity/depth from the stereo camera pair (2x :ref:`MonoCamera <MonoCamera>`/:ref:`ColorCamera`).
55

66
How to place it
77
===============
@@ -47,28 +47,29 @@ Inputs and Outputs
4747

4848
.. tab:: **Inputs**
4949

50-
- :code:`left` - :ref:`ImgFrame` from the left :ref:`MonoCamera`
51-
- :code:`right` - :ref:`ImgFrame` from the right :ref:`MonoCamera`
52-
- :code:`inputConfig` - :ref:`StereoDepthConfig`
50+
- ``left`` - :ref:`ImgFrame` from the left stereo camera
51+
- ``right`` - :ref:`ImgFrame` from the right stereo camera
52+
- ``inputConfig`` - :ref:`StereoDepthConfig`
5353

5454
.. tab:: **Outputs**
5555

56-
- :code:`confidenceMap` - :ref:`ImgFrame`
57-
- :code:`rectifiedLeft` - :ref:`ImgFrame`
58-
- :code:`syncedLeft` - :ref:`ImgFrame`
59-
- :code:`depth` - :ref:`ImgFrame`: UINT16 values - depth in depth units (millimeter by default)
60-
- :code:`disparity` - :ref:`ImgFrame`: UINT8 or UINT16 if Subpixel mode
61-
- :code:`rectifiedRight` - :ref:`ImgFrame`
62-
- :code:`syncedRight` - :ref:`ImgFrame`
63-
- :code:`outConfig` - :ref:`StereoDepthConfig`
56+
- ``confidenceMap`` - :ref:`ImgFrame`
57+
- ``rectifiedLeft`` - :ref:`ImgFrame`
58+
- ``syncedLeft`` - :ref:`ImgFrame`
59+
- ``depth`` - :ref:`ImgFrame`: UINT16 values - depth in depth units (millimeter by default)
60+
- ``disparity`` - :ref:`ImgFrame`: UINT8 or UINT16 if Subpixel mode
61+
- ``rectifiedRight`` - :ref:`ImgFrame`
62+
- ``syncedRight`` - :ref:`ImgFrame`
63+
- ``outConfig`` - :ref:`StereoDepthConfig`
6464

6565
.. tab:: **Debug outputs**
6666

67-
- :code:`debugDispLrCheckIt1` - :ref:`ImgFrame`
68-
- :code:`debugDispLrCheckIt2` - :ref:`ImgFrame`
69-
- :code:`debugExtDispLrCheckIt1` - :ref:`ImgFrame`
70-
- :code:`debugExtDispLrCheckIt2` - :ref:`ImgFrame`
71-
- :code:`debugDispCostDump` - :ref:`ImgFrame`
67+
- ``debugDispLrCheckIt1`` - :ref:`ImgFrame`
68+
- ``debugDispLrCheckIt2`` - :ref:`ImgFrame`
69+
- ``debugExtDispLrCheckIt1`` - :ref:`ImgFrame`
70+
- ``debugExtDispLrCheckIt2`` - :ref:`ImgFrame`
71+
- ``debugDispCostDump`` - :ref:`ImgFrame`
72+
- ``confidenceMap`` - :ref:`ImgFrame`
7273

7374
Internal block diagram of StereoDepth node
7475
==========================================
@@ -285,221 +286,6 @@ as:
285286
For the final disparity map, a filtering is applied based on the confidence threshold value: the pixels that have their confidence score larger than
286287
the threshold get invalidated, i.e. their disparity value is set to zero. You can set the confidence threshold with :code:`stereo.initialConfig.setConfidenceThreshold()`.
287288

288-
Calculate depth using disparity map
289-
===================================
290-
291-
Disparity and depth are inversely related. As disparity decreases, depth increases exponentially depending on baseline and focal length. Meaning, if the disparity value is close to zero, then a small change in disparity generates a large change in depth. Similarly, if the disparity value is big, then large changes in disparity do not lead to a large change in depth.
292-
293-
By considering this fact, depth can be calculated using this formula:
294-
295-
.. code-block:: python
296-
297-
depth = focal_length_in_pixels * baseline / disparity_in_pixels
298-
299-
Where baseline is the distance between two mono cameras. Note the unit used for baseline and depth is the same.
300-
301-
To get focal length in pixels, you can :ref:`read camera calibration <Calibration Reader>`, as focal length in pixels is
302-
written in camera intrinsics (``intrinsics[0][0]``):
303-
304-
.. code-block:: python
305-
306-
import depthai as dai
307-
308-
with dai.Device() as device:
309-
calibData = device.readCalibration()
310-
intrinsics = calibData.getCameraIntrinsics(dai.CameraBoardSocket.RIGHT)
311-
print('Right mono camera focal length in pixels:', intrinsics[0][0])
312-
313-
Here's theoretical calculation of the focal length in pixels:
314-
315-
.. code-block:: python
316-
317-
focal_length_in_pixels = image_width_in_pixels * 0.5 / tan(HFOV * 0.5 * PI/180)
318-
319-
# With 400P mono camera resolution where HFOV=71.9 degrees
320-
focal_length_in_pixels = 640 * 0.5 / tan(71.9 * 0.5 * PI / 180) = 441.25
321-
322-
# With 800P mono camera resolution where HFOV=71.9 degrees
323-
focal_length_in_pixels = 1280 * 0.5 / tan(71.9 * 0.5 * PI / 180) = 882.5
324-
325-
Examples for calculating the depth value, using the OAK-D (7.5cm baseline):
326-
327-
.. code-block:: python
328-
329-
# For OAK-D @ 400P mono cameras and disparity of eg. 50 pixels
330-
depth = 441.25 * 7.5 / 50 = 66.19 # cm
331-
332-
# For OAK-D @ 800P mono cameras and disparity of eg. 10 pixels
333-
depth = 882.5 * 7.5 / 10 = 661.88 # cm
334-
335-
Note the value of disparity depth data is stored in :code:`uint16`, where 0 is a special value, meaning that distance is unknown.
336-
337-
Min stereo depth distance
338-
=========================
339-
340-
If the depth results for close-in objects look weird, this is likely because they are below the minimum depth-perception distance of the device.
341-
342-
To calculate this minimum distance, use the :ref:`depth formula <Calculate depth using disparity map>` and choose the maximum value for disparity_in_pixels parameter (keep in mind it is inveresly related, so maximum value will yield the smallest result).
343-
344-
For example OAK-D has a baseline of **7.5cm**, focal_length_in_pixels of **882.5 pixels** and the default maximum value for disparity_in_pixels is **95**. By using the :ref:`depth formula <Calculate depth using disparity map>` we get:
345-
346-
.. code-block:: python
347-
348-
min_distance = focal_length_in_pixels * baseline / disparity_in_pixels = 882.5 * 7.5cm / 95 = 69.67cm
349-
350-
or roughly 70cm.
351-
352-
However this distance can be cut in 1/2 (to around 35cm for the OAK-D) with the following options:
353-
354-
1. Changing the resolution to 640x400, instead of the standard 1280x800.
355-
356-
2. Enabling Extended Disparity.
357-
358-
Extended Disparity mode increases the levels of disparity to 191 from the standard 96 pixels, thereby 1/2-ing the minimum depth. It does so by computing the 96-pixel disparities on the original 1280x720 and on the downscaled 640x360 image, which are then merged to a 191-level disparity. For more information see the Extended Disparity tab in :ref:`this table <Currently configurable blocks>`.
359-
360-
Using the previous OAK-D example, disparity_in_pixels now becomes **190** and the minimum distance is:
361-
362-
.. code-block:: python
363-
364-
min_distance = focal_length_in_pixels * baseline / disparity_in_pixels = 882.5 * 7.5cm / 190 = 34.84cm
365-
366-
or roughly 35cm.
367-
368-
.. note::
369-
370-
Applying both of those options is possible, which would set the minimum depth to 1/4 of the standard settings, but at such short distances the minimum depth is limited by focal length, which is 19.6cm, since OAK-D mono cameras have fixed focus distance: 19.6cm - infinity.
371-
372-
See `these examples <https://github.com/luxonis/depthai-experiments/tree/master/gen2-camera-demo#real-time-depth-from-depthai-stereo-pair>`__ for how to enable Extended Disparity.
373-
374-
Disparity shift to lower min depth perception
375-
---------------------------------------------
376-
377-
Another option to perceive closer depth range is to use disparity shift. Disparity shift will shift the starting point
378-
of the disparity search, which will significantly decrease max depth (MazZ) perception, but it will also decrease min depth (MinZ) perception.
379-
Disparity shift can be combined with extended/subpixel/LR-check modes.
380-
381-
.. image:: https://user-images.githubusercontent.com/18037362/189375017-2fa137d2-ad6b-46de-8899-6304bbc6c9d7.png
382-
383-
**Left graph** shows min and max disparity and depth for OAK-D (7.5cm baseline, 800P resolution, ~70° HFOV) by default (disparity shift=0). See :ref:`Calculate depth using disparity map`.
384-
Since hardware (stereo block) has a fixed 95 pixel disparity search, DepthAI will search from 0 pixels (depth=INF) to 95 pixels (depth=71cm).
385-
386-
**Right graph** shows the same, but at disparity shift set to 30 pixels. This means that disparity search will be from 30 pixels (depth=2.2m) to 125 pixels (depth=50cm).
387-
This also means that depth will be very accurate at the short range (**theoretically** below 5mm depth error).
388-
389-
**Limitations**:
390-
391-
- Because of the inverse relationship between disparity and depth, MaxZ will decrease much faster than MinZ as the disparity shift is increased. Therefore, it is **advised not to use a larger than necessary disparity shift**.
392-
- Tradeoff in reducing the MinZ this way is that objects at **distances farther away than MaxZ will not be seen**.
393-
- Because of the point above, **we only recommend using disparity shift when MaxZ is known**, such as having a depth camera mounted above a table pointing down at the table surface.
394-
- Output disparity map is not expanded, only the depth map. So if disparity shift is set to 50, and disparity value obtained is 90, the real disparity is 140.
395-
396-
**Compared to Extended disparity**, disparity shift:
397-
398-
- **(+)** Is faster, as it doesn't require an extra computation, which means there's also no extra latency
399-
- **(-)** Reduces the MaxZ (significantly), while extended disparity only reduces MinZ.
400-
401-
Disparity shift can be combined with extended disparity.
402-
403-
.. doxygenfunction:: dai::StereoDepthConfig::setDisparityShift
404-
:project: depthai-core
405-
:no-link:
406-
407-
Max stereo depth distance
408-
=========================
409-
410-
The maximum depth perception distance depends on the :ref:`accuracy of the depth perception <Depth perception accuracy>`. The formula used to calculate this distance is an approximation, but is as follows:
411-
412-
.. code-block:: python
413-
414-
Dm = (baseline/2) * tan((90 - HFOV / HPixels)*pi/180)
415-
416-
So using this formula for existing models the *theoretical* max distance is:
417-
418-
.. code-block:: python
419-
420-
# For OAK-D (7.5cm baseline)
421-
Dm = (7.5/2) * tan((90 - 71.9/1280)*pi/180) = 3825.03cm = 38.25 meters
422-
423-
# For OAK-D-CM4 (9cm baseline)
424-
Dm = (9/2) * tan((90 - 71.9/1280)*pi/180) = 4590.04cm = 45.9 meters
425-
426-
If greater precision for long range measurements is required, consider enabling Subpixel Disparity or using a larger baseline distance between mono cameras. For a custom baseline, you could consider using `OAK-FFC <https://docs.luxonis.com/projects/hardware/en/latest/pages/DM1090.html>`__ device or design your own baseboard PCB with required baseline. For more information see Subpixel Disparity under the Stereo Mode tab in :ref:`this table <Currently configurable blocks>`.
427-
428-
Depth perception accuracy
429-
=========================
430-
431-
Disparity depth works by matching features from one image to the other and its accuracy is based on multiple parameters:
432-
433-
* Texture of objects / backgrounds
434-
435-
Backgrounds may interfere with the object detection, since backgrounds are objects too, which will make depth perception less accurate. So disparity depth works very well outdoors as there are very rarely perfectly-clean/blank surfaces there - but these are relatively commonplace indoors (in clean buildings at least).
436-
437-
* Lighting
438-
439-
If the illumination is low, the diparity map will be of low confidence, which will result in a noisy depth map.
440-
441-
* Baseline / distance to objects
442-
443-
Lower baseline enables us to detect the depth at a closer distance as long as the object is visible in both the frames. However, this reduces the accuracy for large distances due to less pixels representing the object and disparity decreasing towards 0 much faster.
444-
So the common norm is to adjust the baseline according to how far/close we want to be able to detect objects.
445-
446-
Limitation
447-
==========
448-
449-
Since depth is calculated from disparity, which requires the pixels to overlap, there is inherently a vertical
450-
band on the left side of the left mono camera and on the right side of the right mono camera, where depth
451-
cannot be calculated, since it is seen by only 1 camera. That band is marked with :code:`B`
452-
on the following picture.
453-
454-
.. image:: https://user-images.githubusercontent.com/59799831/135310921-67726c28-07e7-4ffa-bc8d-74861049517e.png
455-
456-
Meaning of variables on the picture:
457-
458-
- ``BL [cm]`` - Baseline of stereo cameras.
459-
- ``Dv [cm]`` - Minimum distace where both cameras see an object (thus where depth can be calculated).
460-
- ``B [pixels]`` - Width of the band where depth cannot be calculated.
461-
- ``W [pixels]`` - Width of mono in pixels camera or amount of horizontal pixels, also noted as :code:`HPixels` in other formulas.
462-
- ``D [cm]`` - Distance from the **camera plane** to an object (see image :ref:`here <Measuring real-world object dimensions>`).
463-
- ``F [cm]`` - Width of image at the distance ``D``.
464-
465-
.. image:: https://user-images.githubusercontent.com/59799831/135310972-c37ba40b-20ad-4967-92a7-c71078bcef99.png
466-
467-
With the use of the :code:`tan` function, the following formulas can be obtained:
468-
469-
- :code:`F = 2 * D * tan(HFOV/2)`
470-
- :code:`Dv = (BL/2) * tan(90 - HFOV/2)`
471-
472-
In order to obtain :code:`B`, we can use :code:`tan` function again (same as for :code:`F`), but this time
473-
we must also multiply it by the ratio between :code:`W` and :code:`F` in order to convert units to pixels.
474-
That gives the following formula:
475-
476-
.. code-block:: python
477-
478-
B = 2 * Dv * tan(HFOV/2) * W / F
479-
B = 2 * Dv * tan(HFOV/2) * W / (2 * D * tan(HFOV/2))
480-
B = W * Dv / D # pixels
481-
482-
Example: If we are using OAK-D, which has a :code:`HFOV` of 72°, a baseline (:code:`BL`) of 7.5 cm and
483-
:code:`640x400 (400P)` resolution is used, therefore :code:`W = 640` and an object is :code:`D = 100` cm away, we can
484-
calculate :code:`B` in the following way:
485-
486-
.. code-block::
487-
488-
Dv = 7.5 / 2 * tan(90 - 72/2) = 3.75 * tan(54°) = 5.16 cm
489-
B = 640 * 5.16 / 100 = 33 # pixels
490-
491-
Credit for calculations and images goes to our community member gregflurry, which he made on
492-
`this <https://discuss.luxonis.com/d/339-naive-question-regarding-stereodepth-disparity-and-depth-outputs/7>`__
493-
forum post.
494-
495-
.. note::
496-
497-
OAK-D-PRO will include both IR dot projector and IR LED, which will enable operation in no light.
498-
IR LED is used to illuminate the whole area (for mono/color frames), while IR dot projector is mostly
499-
for accurate disparity matching - to have good quality depth maps on blank surfaces as well. For outdoors,
500-
the IR laser dot projector is only relevant at night. For more information see the development progress
501-
`here <https://github.com/luxonis/depthai-hardware/issues/114>`__.
502-
503289
Measuring real-world object dimensions
504290
======================================
505291

docs/source/index.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,17 @@ node functionalities are presented with code.
7171
:hidden:
7272
:caption: Tutorials:
7373

74-
tutorials/hello_world.rst
7574
tutorials/standalone_mode.rst
7675
tutorials/message_syncing.rst
76+
tutorials/configuring-stereo-depth.rst
7777
tutorials/multiple.rst
7878
tutorials/maximize_fov.rst
7979
tutorials/debugging.rst
8080
tutorials/ram_usage.rst
8181
tutorials/dispaying_detections.rst
8282
tutorials/image_quality.rst
8383
tutorials/low-latency.rst
84+
tutorials/hello_world.rst
8485

8586
.. toctree::
8687
:maxdepth: 1

docs/source/samples/calibration/calibration_reader.rst

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,43 @@ This example shows how to read calibration data stored on device over XLink. Thi
99
- :ref:`Calibration Flash`
1010
- :ref:`Calibration Load`
1111

12+
Camera intrinsics
13+
~~~~~~~~~~~~~~~~~
14+
15+
Calibration also contains camera intrinsics and extrinsics parameters.
16+
17+
.. code-block:: python
18+
19+
import depthai as dai
20+
21+
with dai.Device() as device:
22+
calibData = device.readCalibration()
23+
intrinsics = calibData.getCameraIntrinsics(dai.CameraBoardSocket.RIGHT)
24+
print('Right mono camera focal length in pixels:', intrinsics[0][0])
25+
26+
Here's theoretical calculation of the focal length in pixels:
27+
28+
.. math::
29+
30+
focal_length_in_pixels = image_width_in_pixels * 0.5 / tan(HFOV * 0.5 * PI/180)
31+
32+
// With 400P mono camera resolution where HFOV=71.9 degrees
33+
focal_length_in_pixels = 640 * 0.5 / tan(71.9 * 0.5 * PI / 180) = 441.25
34+
35+
// With 800P mono camera resolution where HFOV=71.9 degrees
36+
focal_length_in_pixels = 1280 * 0.5 / tan(71.9 * 0.5 * PI / 180) = 882.5
37+
38+
Examples for calculating the depth value, using the OAK-D (7.5cm baseline):
39+
40+
.. math::
41+
42+
# For OAK-D @ 400P resolution and disparity of eg. 50 pixels
43+
depth = 441.25 * 7.5 / 50 = 66.19 # cm
44+
45+
# For OAK-D @ 800P resolution and disparity of eg. 10 pixels
46+
depth = 882.5 * 7.5 / 10 = 661.88 # cm
47+
48+
1249
Setup
1350
#####
1451

0 commit comments

Comments
 (0)