# 配置立体深度

我们的 [StereoDepth 节点](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/stereo_depth.md)
具有高度的可配置性，本教程将介绍一些配置和故障排除方法，帮助您获得最佳效果。

本文档分为7个章节：

 1. [立体深度基础](#Stereo%20Depth%20Basics)
 2. [立体深度预设规格](#Stereo%20Depth%20Preset%20specifications)
 3. [修复噪声深度](#Fixing%20noisy%20depth)
 4. [提高深度精度](#Improving%20depth%20accuracy)
 5. [短程立体深度](#Short%20range%20stereo%20depth)
 6. [长程立体深度](#Long%20range%20stereo%20depth)
 7. [修复噪声点云](#Fixing%20noisy%20pointcloud)

### 立体深度基础

[立体深度视觉](https://en.wikipedia.org/wiki/Computer_stereo_vision) 通过计算从略微不同位置拍摄的两幅图像之间的视差来工作。

立体视觉的工作原理与我们的眼睛非常相似。我们的大脑（下意识地）根据左眼和右眼所看到的差异来估计物体和场景的深度。在 OAK-D 相机上，原理完全相同：我们有左、右相机（立体相机对），而 OAK 在设备上进行视差匹配，以估计物体和场景的深度。

视差 指的是立体对中左右图像上两个对应点之间的距离。

### 从视差计算深度

首先来看看深度是如何计算的：

 * depth_cm - 以厘米为单位的深度
 * fx_px - 以像素为单位的[焦距](#Focal%20Length)
 * baseline_cm - 立体相机对中两个相机之间的距离
 * disparity_px - 以像素为单位的视差

计算深度值的示例，使用 OAK-D（7.5cm 基线，OV9282），分辨率为 400P，视差为 50 像素：

#### 焦距

焦距是相机镜头到图像传感器之间的距离。焦距越大，视场角（FOV）越小。

您可以从校准数据中读取相机的焦距（以像素为单位），请参阅
[此处的校准转储](https://docs.luxonis.com/software-v3/depthai/examples/calibration/calibration_dump.md)。该值本身取决于相机型号和分辨率。

推荐方法： 使用 [ImgTransformations](https://docs.luxonis.com/software-v3/depthai/api/cpp.md) 获取内参矩阵，因为它是对图像帧应用实际变换的主要事实来源：

```python
import depthai as dai

# 通过 ImgTransformations 获取内参（推荐）
disparity = disparityQueue.get()  # 或 depthQueue.get()
intrinsics = disparity.getTransformation().getSourceIntrinsicMatrix()
print('像素焦距:', intrinsics[0][0])
```

替代方法： 您也可以从校准数据中读取相机的焦距：

```python
import depthai as dai

with dai.Device() as device:
  calibData = device.readCalibration()
  intrinsics = calibData.getCameraIntrinsics(dai.CameraBoardSocket.CAM_C)
  print('右单色相机像素焦距:', intrinsics[0][0])
```

像素焦距写在相机内参中（intrinsics[0][0]）：

#### 视差

视差与深度成反比。随着视差减小，深度根据基线和焦距呈指数增长。也就是说，如果视差接近零，则视差的微小变化会导致深度的大幅变化。同样，如果视差值较大，则视差的变化不会导致深度的大幅变化（精度更高）。

以下图表显示了 OAK-D（7.5cm 基线距离）在 800P 分辨率下视差与深度的关系：

[完整图表在此](https://docs.google.com/spreadsheets/d/1ymn-0D4HcCbzYP-iPycj_PIdSwmrLenlGryuZDyA4rQ/edit#gid=0)

注意深度数据以 uint16 存储，其中 0 表示距离无效/未知。

### 基线距离和焦距如何影响深度

从上面的深度公式可以看出，较大的基线距离或较大的焦距都会在相同视差下产生更远的深度，这意味着深度精度会更好。

因此，要获得长程深度感知，可以增加基线距离和/或减小 FOV。

> 较宽的 FOV 会导致深度精度变差，即使在较近距离（精度下降不太明显）也是如此。

### 最小立体深度距离

如果近距离物体的深度结果看起来异常，很可能是因为它们低于设备的最小深度感知距离。

您可以计算最小立体深度距离，例如 OAK-D 的基线为 7.5cm，像素焦距为 882.5 像素，默认的视差最大值（像素）为 95。视差参数的最大值（注意是反比关系，所以最大值会产生最小结果）如下：

即大约 70cm。

然而，通过以下选项，该距离可以减半（对于 OAK-D 大约为 35cm）：

 1. 将分辨率改为 640x400，而不是标准的 1280x800。

 2. 启用扩展视差（Extended Disparity）。

扩展视差模式将视差级别从标准的 96 像素增加到 191 像素，从而将最小深度减半。它通过在原始 1280x720 和缩小后的 640x360 图像上计算 96 像素的视差，然后合并成 191 级视差来实现。更多信息请参阅
[当前可配置模块](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/stereo_depth.md) 中的扩展视差选项卡。

使用前面的 OAK-D 示例，视差像素现在变为 190，最小距离为：

```python
min_distance = focal_length_in_pixels * baseline / disparity_in_pixels = 882.5 * 7.5cm / 190 = 34.84cm
```

即大约 35cm。

> 这两个选项可以同时应用，这将使最小深度降至标准设置的 1/4，但在如此短的距离下，最小深度受限于焦距（19.6cm），因为 OAK-D 单色相机具有固定对焦距离：19.6cm 到无穷远。

请参阅[这些示例](https://github.com/luxonis/oak-examples/tree/master/gen2-camera-demo#real-time-depth-from-depthai-stereo-pair)了解如何启用扩展视差。

#### 将相机移近物体

查看[从视差计算深度](#Depth%20from%20disparity)部分，从图表中可以清楚地看出，在 95 视差像素（近距离）处，视差像素之间的深度变化（例如 95->94）最小，因此深度精度最佳。

Depth accuracy decreases exponentially with the distance from the camera. Note that with [Stereo Subpixel
mode](#Stereo%20Subpixel%20mode) enabled you can have better depth accuracy (even at a longer distance) but it only works to some
extent.

So to conclude, object/scene you are measuring should be as close as possible to MinZ (minimal depth perception) of the camera for
best depth accuracy. You can find MinZ specification for each device in the [Hardware
documentation](https://docs.luxonis.com/hardware.md).

### Max stereo depth distance

The maximum depth perception distance depends on [how baseline distance and focal length affect
depth](#How%20baseline%20distance%20and%20focal%20length%20affect%20depth). The formula used to calculate this distance is an
approximation, but is as follows:

```python
Dm = (baseline/2) * tan((90 - HFOV / HPixels)*pi/180)
```

So using this formula for existing models the theoretical max distance is:

```python
# For OAK-D (7.5cm baseline)
Dm = (7.5/2) * tan((90 - 71.9/1280)*pi/180) = 3825.03cm = 38.25 meters

# For OAK-D-CM4 (9cm baseline)
Dm = (9/2) * tan((90 - 71.9/1280)*pi/180) = 4590.04cm = 45.9 meters
```

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/hardware/products/OAK-FFC%25204P.md) device or design your own baseboard PCB with required
baseline. For more information see Subpixel Disparity under the Stereo Mode tab in [Currently configurable
blocks](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/stereo_depth.md).

### Stereo Depth Preset specifications

The StereoDepth node provides several profile presets that can be used to quickly configure the node for different scenarios. Each
preset applies a specific combination of filters and parameters optimized for particular use cases.

For information about FPS performance for each preset, see the [Platform-Specific
Configuration](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/stereo_depth.md).

#### RVC2

### Available Presets

RVC2 supports the following presets:

 * DEFAULT: General purpose configuration with balanced settings
 * ROBOTICS: Optimized for navigation and obstacle detection, without motion blur
 * FACE: Optimized for face tracking (short range)
 * HIGH_DETAIL: Designed to capture fine details and small objects in the scene, prioritizing maximum detail while accepting
   increased noise for enhanced feature visibility
 * FAST_DENSITY: Prioritizes high fill-rate and with faster processing
 * FAST_ACCURACY: Prioritizes high accuracy with faster processing but lower fill-rate

### Preset-Specific Differences

For details on the filters, see [Platform-Specific
Configuration](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/stereo_depth.md).

DEFAULT Preset:

 * Extended Disparity: False
 * Subpixel: True (3 bits)
 * Left-Right Check: True
 * Median Filter: KERNEL_7x7
 * Spatial Filter: enable=True, delta=3, holeFillingRadius=1
 * Speckle Filter: enable=True, speckleRange=200
 * Temporal Filter: enable=True, alpha=0.5
 * Decimation Filter: decimationFactor=2
 * Threshold Filter: 0 to 15 meters (minRange=0, maxRange=15000)
 * Confidence Threshold: 15

ROBOTICS Preset:

 * Extended Disparity: False
 * Subpixel: True (3 bits)
 * Left-Right Check: True
 * Median Filter: KERNEL_7x7
 * Spatial Filter: enable=True, delta=20, holeFillingRadius=2
 * Speckle Filter: enable=True, speckleRange=200
 * Temporal Filter: enable=False
 * Decimation Filter: decimationFactor=2
 * Threshold Filter: 0 to 10 meters (minRange=0, maxRange=10000)
 * Confidence Threshold: 15

FACE Preset:

 * Extended Disparity: True
 * Subpixel: True (5 bits)
 * Left-Right Check: True
 * Median Filter: MEDIAN_OFF
 * Spatial Filter: enable=True, delta=3, holeFillingRadius=1
 * Speckle Filter: enable=True, speckleRange=200
 * Temporal Filter: enable=True, alpha=0.5
 * Decimation Filter: decimationFactor=2
 * Threshold Filter: 0.03 to 3 meters (minRange=30, maxRange=3000)
 * Confidence Threshold: 15

HIGH_DETAIL Preset:

 * Extended Disparity: True
 * Subpixel: True (5 bits)
 * Left-Right Check: True (threshold: 5)
 * Median Filter: MEDIAN_OFF
 * Spatial Filter: enable=True, delta=3, holeFillingRadius=1
 * Speckle Filter: enable=True, speckleRange=200
 * Temporal Filter: enable=True, alpha=0.5
 * Decimation Filter: decimationFactor=2
 * Threshold Filter: 0 to 15 meters (minRange=0, maxRange=15000)
 * Confidence Threshold: 55

FAST_DENSITY Preset:

 * Extended Disparity: False
 * Subpixel: True (5 bits)
 * Left-Right Check: True
 * Median Filter: MEDIAN_OFF
 * Spatial Filter: enable=False
 * Speckle Filter: enable=False
 * Temporal Filter: enable=False
 * Decimation Filter: decimationFactor=1 (disabled)
 * Max Disparity: 3040.0 (reduced for speed)
 * Confidence Threshold: 15

FAST_ACCURACY Preset:

 * Extended Disparity: False
 * Subpixel: True (5 bits)
 * Left-Right Check: True (threshold: 5)
 * Median Filter: MEDIAN_OFF
 * Spatial Filter: enable=False
 * Speckle Filter: enable=False
 * Temporal Filter: enable=False
 * Decimation Filter: decimationFactor=1 (disabled)
 * Max Disparity: 3040.0 (reduced for speed)
 * Confidence Threshold: 55

### Common Parameters

Most parameters are consistent across all RVC2 presets:

 * Disparity Shift: 0

 * Left-Right Check Threshold: 10 (varies: 5 for HIGH_DETAIL, FAST_ACCURACY)

 * Census Transform
   
   * Enable Mean Mode: True
   * Noise Threshold Offset: 1
   * Noise Threshold Scale: 1

 * Cost Aggregation
   
   * Division Factor: 1
   * Horizontal Penalty P1: 250
   * Horizontal Penalty P2: 500
   * Vertical Penalty P1: 250
   * Vertical Penalty P2: 500

 * Postprocessing - Brightness Filter
   
   * Min: 0
   * Max: 256

#### RVC4

### Available Presets

RVC4 supports the following presets:

 * ACCURACY: Prioritizes depth accuracy over fill-rate for precise depth measurements
 * DENSITY: Prioritizes fill-rate and processing speed for dense depth maps at higher frame rates

### Preset-Specific Differences

For details on the filters, see [Platform-Specific
Configuration](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/stereo_depth.md).

ACCURACY Preset:

 * Extended Disparity: True
 * Subpixel: True (4 bits, fixed for RVC4)
 * Software Left-Right Check: False
 * Median Filter: MEDIAN_OFF
 * Spatial Filter: enable=False
 * Speckle Filter: enable=True, speckleRange=200, differenceThreshold=2
 * Temporal Filter: enable=False
 * Decimation Filter: decimationFactor=1 (disabled), decimationMode=NON_ZERO_MEAN
 * Adaptive Median Filter: enable=True, confidenceThreshold=200
 * Hole Filling: enable=True, highConfidenceThreshold=240, fillConfidenceThreshold=251, minValidDisparity=1
 * Confidence Threshold: 97
 * Confidence Metrics:
   * Occlusion Confidence Weight: 14
   * Motion Vector Confidence Weight: 16
   * Motion Vector Confidence Threshold: 1
   * Flatness Confidence Weight: 2
   * Flatness Confidence Threshold: 4
   * Flatness Override: False
 * Census Transform: noiseThresholdOffset=0, noiseThresholdScale=84
 * Threshold Filter: minRange=0, maxRange=65535
 * Brightness Filter: minBrightness=0, maxBrightness=256

DENSITY Preset:

 * Extended Disparity: True
 * Subpixel: True（4 位，RVC4 固定）
 * Software Left-Right Check: True（阈值：4）
 * Median Filter: KERNEL_5x5
 * Spatial Filter: enable=False
 * Speckle Filter: enable=True, speckleRange=200, differenceThreshold=2
 * Temporal Filter: enable=False
 * Decimation Filter: decimationFactor=1（禁用）, decimationMode=PIXEL_SKIPPING
 * Adaptive Median Filter: enable=True, confidenceThreshold=200
 * Hole Filling: enable=False
 * Confidence Threshold: 20
 * Confidence Metrics:
   * Occlusion Confidence Weight: 28
   * Motion Vector Confidence Weight: 0
   * Motion Vector Confidence Threshold: 1
   * Flatness Confidence Weight: 4
   * Flatness Confidence Threshold: 4
   * Flatness Override: False
 * Census Transform: noiseThresholdOffset=0, noiseThresholdScale=-40
 * Threshold Filter: minRange=0, maxRange=65535
 * Brightness Filter: minBrightness=-1, maxBrightness=256

### 常见参数

大多数参数在所有 RVC4 预设中保持一致：

 * Subpixel：4 位（RVC4 固定）
 * Extended Disparity：True
 * Spatial Filter：enable=False
 * Speckle Filter：enable=True, speckleRange=200, differenceThreshold=2
 * Temporal Filter：enable=False
 * Decimation Filter：decimationFactor=1（禁用）
 * Adaptive Median Filter：enable=True, confidenceThreshold=200
 * Threshold Filter：minRange=0, maxRange=65535

### Fixing noisy depth

我们注意到一些与立体深度质量相关的主题：

 * [场景纹理](#Scene%20Texture)
 * [立体深度置信度阈值](#Stereo%20depth%20confidence%20threshold)
 * [双目相机噪声](#Stereo%20camera%20pair%20noise)
 * [深度后处理滤波](#Stereo%20postprocessing%20filters)

### 场景纹理

由于立体匹配算法的工作方式，被动立体深度需要场景具有良好的纹理，否则深度会存在噪声或无效。低视觉兴趣表面（纹理极少或无纹理的空白表面），例如墙壁或地板。

解决方案： 我们的 OAK Pro 版本 OAK
相机板载了[红外激光点阵投影器](https://docs.luxonis.com/hardware/platform/features/ir-perception/dot-projector.md)，可在场景中投射成千上万个微小点，这为立体匹配算法提供了更多纹理，有助于提升效果。

我们使用的技术称为
ASV（[常规主动立体视觉](https://en.wikipedia.org/wiki/Computer_stereo_vision#Conventional_active_stereo_vision_(ASV))），立体匹配在设备上以与被动立体 OAK-D
相同的方式执行。

### 立体深度置信度阈值

在计算视差时，立体匹配算法会为视差图中的每个像素分配一个置信度值 0..255。这个置信度分数是反向的（与神经网络置信度相比）：

 * 0 - 认为有效值的最大置信度
 * 255 - 最小置信度，因此该值可能不正确的概率更大

对于最终的视差图，基于置信度阈值进行滤波：置信度分数大于阈值的像素会被无效化，即其视差值被设为零。您可以通过以下 API 设置置信度阈值。

这意味着，通过置信度阈值，用户可以在填充率或精度之间进行权衡。

#### Python

```python
# 创建 StereoDepth 节点
stereo_depth = pipeline.create(dai.node.StereoDepth)
stereo_depth.initialConfig.setConfidenceThreshold(threshold)

# 或者，设置立体预设模式：
# 优先填充率，设置置信度阈值为 245
stereo_depth.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.HIGH_DENSITY)
# 优先精度，设置置信度阈值为 200
stereo_depth.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.HIGH_ACCURACY)
```

#### C++

```cpp
// 创建 StereoDepth 节点
auto stereo_depth = pipeline.create<dai::node::StereoDepth>();
stereo_depth->initialConfig.setConfidenceThreshold(threshold);

// 或者，设置立体预设模式：
// 优先填充率，设置置信度阈值为 245
stereo_depth->setDefaultProfilePreset(dai::node::StereoDepth::Preset::HIGH_DENSITY);
// 优先精度，设置置信度阈值为 200
stereo_depth->setDefaultProfilePreset(dai::node::StereoDepth::Preset::HIGH_ACCURACY);
```

### 双目相机噪声

如果输入左右图像有噪声，视差图也会存在噪声。因此，良好深度的前提是高质量的左右立体图像（参见[图像质量](https://docs.luxonis.com/hardware/platform/sensors/image-quality.md)文档）。主动立体（OAK
Pro 版本 OAK 相机）在很大程度上缓解了这个问题，但对于被动立体相机，您可以采取一些措施来提高立体相机对的质量。

立体相机对最好使用单色（灰度）相机，因为它们没有彩色（拜耳）滤波器，具有更高的量子效率（QE）。更高的 QE 意味着相同光照（光子）下会产生更多信号，从而带来更好的信噪比（SNR）。

为了更好的低光性能，建议使用较长的曝光时间而不是较高的增益（ISO），因为这会提高 SNR。有时这意味着降低相机帧率——在 30 FPS 时，可以使用 1/30s 曝光时间；在 15 FPS 时，可以使用 1/15s
曝光时间，依此类推。更多信息，请参见[低光增强灵敏度](https://docs.luxonis.com/hardware/platform/sensors/image-quality.md)。

另一个潜在改进是调整传感器的 ISP 设置，例如色度和亮度降噪以及锐度。更多信息，请参见[彩色相机 ISP 配置](https://docs.luxonis.com/hardware/platform/sensors/image-quality.md)。

### 深度后处理滤波

[StereoDepth](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/stereo_depth.md)
节点有几个在设备上运行的后处理滤波器，可以启用这些滤波器来提高视差图的质量。有关 实现（API）细节，请参见[StereoDepth
可配置模块](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/stereo_depth.md)。

由于这些滤波器在设备上运行，会带来一定的性能开销，这意味着在高分辨率帧（1MP）下可能会限制帧率。为了降低开销，可以考虑使用较低分辨率的帧（例如
400P）和/或使用[抽取滤波器](#Decimation%20filter)。由于额外的处理，这些滤波器也会引入[额外的延迟](https://docs.luxonis.com/software-v3/depthai/tutorials/optimizing.md)。

> 如果管道提示 shave/内存分配不足，请尝试使用
> `setPostProcessingHardwareResources(n_shaves, n_cmx)`
> 增加后处理中使用的硬件资源 ——
> `stereoDepth.setPostProcessingHardwareResources(3, 3)`
> 。

#### 中值滤波器

这是一种非边缘保持的中值滤波器，可用于减少噪声并平滑深度图。中值滤波器在硬件中实现，因此是最快的滤波器。

#### 散斑滤波器

散斑滤波器用于减少散斑噪声。散斑噪声是相邻视差/深度像素之间方差较大的区域，散斑滤波器会尝试滤除该区域。

#### 时间滤波器

时间滤波器旨在通过基于先前帧操纵每个像素值来提高深度数据的持久性。该过滤器对数据执行单次传递，调整深度值同时更新跟踪历史。

在像素数据缺失或无效的情况下，过滤器会使用用户定义的持久性模式来决定是否应利用存储的数据来改进缺失值。请注意，由于依赖历史数据，过滤器可能会引入可见的运动模糊/拖影伪影，因此最适合 静态场景。

#### 空间滤波器

空间边缘保留滤波器将使用有效的相邻深度像素填充无效的深度像素。它执行一系列一维水平和垂直传递或迭代，以增强重建数据的平滑度。基于[这篇研究论文](https://www.inf.ufrgs.br/~eslgastal/DomainTransform/)。

#### 亮度滤波器

亮度滤波器将过滤（无效化，设为0）所有输入立体相机图像像素亮度超出配置的 min/max 阈值范围的深度像素。当您有高动态范围场景（如户外明亮白天）或立体相机对直接看到光源时，此滤波器非常有用：

它还有助于消除校正“伪影”，特别是当您使用广角镜头并应用 alpha 参数时。当没有可用像素时，StereoDepth 节点默认将该区域设为0（黑色），但可以通过 stereoDepth.setRectifyEdgeFillColor(int8)
更改。此黑色区域随后可通过亮度滤波器无效化，如下所示：

#### 阈值滤波器

阈值滤波器将过滤掉所有超出配置的 min/max 阈值范围的深度像素。在已知场景确切距离范围（如30cm-2m）的受控环境中，建议使用此滤波器。

#### 降采样滤波器

降采样滤波器将对深度图进行子采样，即降低深度场景复杂度，使其他滤波器运行更快。将 decimationFactor
设为2可将1280x800的深度图缩小至640x400。我们可以选择像素跳过、中值或均值降采样模式，后两种模式也有助于滤波。decimationFactor 为1时禁用该滤波器。

它对于[点云](#Decimation%20filter%20for%20pointcloud)也非常有用。

#### 滤波顺序

滤波顺序很重要，因为一个滤波器的输出是下一个滤波器的输入。滤波顺序可自定义，可通过以下方式设置：

```python
config.postProcessing.filteringOrder = [
  dai.RawStereoDepthConfig.PostProcessing.Filter.TEMPORAL,
  dai.RawStereoDepthConfig.PostProcessing.Filter.SPECKLE,
  dai.RawStereoDepthConfig.PostProcessing.Filter.SPATIAL,
  dai.RawStereoDepthConfig.PostProcessing.Filter.MEDIAN,
  dai.RawStereoDepthConfig.PostProcessing.Filter.DECIMATION
]
```

### 提高深度精度

上一章我们关注的是噪声，但这并非深度不准确的唯一原因。

有几种方法可以提高深度精度：

 * （上文提到）[修复噪声深度](#Fixing%20noisy%20depth) - 深度必须高质量才能保证准确
 * （上文提到）[立体深度置信度阈值](#Stereo%20depth%20confidence%20threshold) 应设置得较低以获得最佳精度
 * 启用[立体子像素模式](#Stereo%20Subpixel%20mode)，特别是当物体/场景距离相机 MinZ 较远时

### 立体子像素模式

首先，让我们了解立体子像素模式是什么以及它是如何工作的。关于图像子像素的解释，请参见[什么是子像素？](https://dsp.stackexchange.com/questions/34103/subpixel-what-is-it)。

> 立体深度流水线非常复杂（请参见
> [StereoDepth 节点内部框图](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/stereo_depth.md)
> ），为了便于理解，我们在此简化。实际上它并不使用置信度（例如
> `stereoDepth.confidenceMap`
> 输出），而是使用成本转储（cost dump），这是用于计算置信度值的。

在计算视差深度时，立体匹配算法为每个视差像素分配一个“置信度”分数，这意味着深度图像的每个像素包含96字节（用于置信度）。如果您对这些成本值感兴趣，可以使用 stereoDepth.debugDispCostDump 输出，但请注意，每帧输出非常大（例如
1280*800*96 => 98MB）。

立体子像素模式通过查看每个方向上两个相邻视差像素的置信度值来计算子像素视差。在上面的示例图中，在普通模式下，StereoDepth 只会得到最大视差 = 34 像素，但在子像素模式下，它会返回稍多一点的值，例如 34.375 像素，因为像素 35 和 36
的置信度也相当高。

TL;DR： 立体子像素模式应始终提供更精确的深度，但会消耗额外的硬件资源（关于影响请参见[立体深度
FPS](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/stereo_depth.md)）。

#### 立体子像素对分层的影响

默认立体深度输出有 0..95 个视差像素，产生 96 个独特的深度值。这在点云表示中尤其明显，会看到离散的“层”点，而不是平滑过渡：

这种分层在较远距离尤为明显，这些层之间的距离呈指数级增大。

但启用立体子像素模式后，会有更多可能的唯一值，从而产生更细粒度的深度步长，因此点云更平滑。

| 子像素小数位数 | 唯一值数量 |
| --- | --- |
| 3 | 754 |
| 4 | 1506 |
| 5 | 3010 |

可以通过设置 stereoDepth.setSubpixelFractionalBits(int) 参数（值为 3、4 或 5 位）来更改子像素位数。

### 短距离立体深度

要获得精确的短距离深度，您首先需要执行[提高深度精度](#Improving%20depth%20accuracy)步骤。对于大多数标准 FOV、OV9282 OAK-D* 相机，您希望物体/场景距离相机约 70cm，此时误差低于
2%（在良好的[场景纹理](#Scene%20Texture)条件下），即 ± 1.5cm 误差。

但是如何获得更好的深度精度，例如亚厘米级立体深度精度？正如我们在 [基线距离和焦距如何影响深度](#How%20baseline%20distance%20and%20focal%20length%20affect%20depth)中所学到的，
我们希望有更近的基线距离和/或更窄的视场角镜头。

这就是为什么对于短距离深度感知，我们建议使用 [OAK-D SR](https://docs.luxonis.com/hardware/products/OAK-D%2520SR.md)或[OAK-D
ToF](https://docs.luxonis.com/hardware/products/OAK-D%2520ToF.md)， 因为它们具有2厘米的基线距离、800P分辨率，并且非常适合最远1米的深度感知。

回到[视差深度](#Depth%20from%20disparity)，最小深度感知 （MinZ）由以下公式定义，其中视差为95像素（视差搜索的最大像素数）：

### 如何降低 MinZ

如果近距离物体的深度结果看起来奇怪，这很可能是因为它们低于OAK相机的MinZ距离。您可以通过以下方式降低OAK相机的MinZ：

 * [降低分辨率](#Lowering%20resolution%20to%20decrease%20MinZ)
 * 启用[立体扩展视差模式](#Stereo%20Extended%20Disparity%20mode)
 * 启用[立体压缩扩展模式](#Stereo%20companding%20mode)
 * 使用[视差偏移](#Disparity%20shift) - 建议在受控环境中使用，此时MaxZ已知

最后两个选项可以同时启用，这将使最小深度降至标准设置的1/4，但在如此近的距离下，MinZ可能受限于焦距。

#### 降低分辨率以减小 MinZ

上面我们有MinZ的公式，通过降低分辨率，我们降低了焦距（以像素为单位），所以让我们再看一下公式：

如您所见，将分辨率降低2倍，也会使MinZ降低2倍。请注意，由于像素更少，深度精度（厘米级）也会降低。

#### 立体扩展视差模式

与[降低分辨率以减小MinZ](#Lowering%20resolution%20to%20decrease%20MinZ)非常相似， 扩展模式会运行两次立体深度管道（因此消耗更多硬件资源）；一次使用传递给
[StereoDepth](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/stereo_depth.md)节点的帧分辨率，另一次使用分辨率降低2倍后的帧，
然后将两个输出视差图合并。

#### 立体压缩扩展模式

视差压缩扩展执行稀疏视差匹配：

 * 前48个像素逐像素匹配，这意味着在更远距离上没有缺点
 * 接下来32个像素每2个像素匹配一次，因此精度减半（在更近距离上）
 * 最后16个像素每4个像素匹配一次，因此精度降低四分之一（在最近距离上）。由于在最近距离上精度已经最好，这可以是一个很好的权衡。

与扩展模式相比，压缩扩展模式速度更快，因为它不需要执行两次视差匹配。请注意，压缩扩展模式不能与扩展模式同时使用。

[点击此处查看Google表格](https://docs.google.com/spreadsheets/d/1N_glGDBCTkgbjEN0IUja5JQJrr-OLoaLbt6P-34u0hk/edit?usp=sharing)用于上述图表。请注意，此图表针对全像素视差，
当启用子像素模式时，精度会更好（参见[立体深度精度文档](https://docs.luxonis.com/hardware/platform/depth/depth-accuracy.md)）。

```python
stereo = pipeline.create(dai.node.StereoDepth)
cfg = stereo.initialConfig.get()
# 启用压缩扩展模式
cfg.costMatching.enableCompanding = True
stereo.initialConfig.set(cfg)
```

#### 视差偏移

在受控环境中，如果MaxZ已知，为了感知更近的深度范围，建议使用视差偏移，因为它不会像上述两种方法那样降低深度精度。

视差偏移会移动视差搜索的起始点，这将显著降低MaxZ，但也会降低MinZ。视差偏移可以与扩展/子像素/左右校验模式结合使用。

左侧图表显示了[OAK-D](https://docs.luxonis.com/hardware/products/OAK-D.md)（7.5厘米基线，800P分辨率，~70°水平视场角）默认情况下（视差偏移=0）的最小和最大视差及深度。参见[视差深度](#Depth%20from%20disparity)。
由于硬件（立体块）具有固定的95像素视差搜索，DepthAI将从0像素（深度=无穷远）搜索到95像素（深度=71厘米）。

局限性：右侧图表显示了相同情况，但视差偏移设置为30像素。这意味着视差搜索将从30像素（深度=2.2米）到125像素（深度=50厘米）。这也意味着深度在短距离上非常准确（理论上深度误差低于5毫米）。

 * 由于视差与深度成反比关系，随着视差偏移的增加，MaxZ的下降速度会比MinZ快得多。因此，建议不要使用大于必要值的视差偏移。
 * 通过这种方式降低MinZ的代价是，距离超过MaxZ的物体将不可见。
 * 由于上述原因，我们仅建议在已知MaxZ的情况下使用视差偏移，例如将深度摄像头安装在桌子上方并指向桌面表面。
 * 输出视差图不会扩展，只有深度图会扩展。因此，如果视差偏移设置为50，且获得的视差值为90，则实际视差为140。

与扩展视差相比，视差偏移：

 * (+) 速度更快，因为它不需要额外计算，这意味着也没有额外延迟
 * (-) 会减小MaxZ（显著），而扩展视差仅减小MinZ。

视差偏移可以与扩展视差结合使用。

### setDisparityShift(self, arg0: typing.SupportsInt) -> StereoDepthConfig: StereoDepthConfig

Kind: Method

Shift input frame by a number of pixels to increase minimum depth. For example
shifting by 48 will change effective disparity search range from (0,95] to
[48,143]. An alternative approach to reducing the minZ. We normally only
recommend doing this when it is known that there will be no objects farther away
than MaxZ, such as having a depth camera mounted above a table pointing down at
the table surface.

### 近距离深度限制

由于深度是根据视差计算的，而视差需要像素重叠，因此在左单目相机的左侧和右单目相机的右侧存在一个垂直带，无法计算深度，因为它只能被一个立体相机看到。该带在下图中标记为B。

在非常近的距离下，即使启用了 [立体扩展视差模式](#Stereo%20Extended%20Disparity%20mode)和 [降低分辨率](#Lowering%20resolution%20to%20decrease%20MinZ)，也会注意到
这个垂直带上存在无效深度像素。

图中变量的含义：

 * BL [cm] - 立体相机的基线。
 * Dv [cm] - 两个相机都能看到物体的最小距离（从而可以计算深度）。
 * B [像素] - 无法计算深度的条带宽度。
 * W [像素] - 单目相机的像素宽度或水平像素数，在其他公式中也表示为 HPixels。
 * D [cm] - 从相机平面到物体的距离（见图 [测量真实世界物体尺寸](#Measuring%20real-world%20object%20dimensions)）。
 * F [cm] - 在距离 D 处的图像宽度。

使用 tan 函数，可以得到以下公式：

 * F = 2 * D * tan(HFOV/2)
 * Dv = (BL/2) * tan(90 - HFOV/2)

为了得到 B，我们可以再次使用 tan 函数（与计算 F 相同），但这次还要乘以 W 与 F 的比值以将单位转换为像素。这得到以下公式：

示例：如果我们使用 OAK-D，其 HFOV 为 72°，基线（BL）为 7.5 cm，使用 640x400 (400P) 分辨率，因此 W = 640，物体距离 D = 100 cm，我们可以按以下方式计算 B：

```bash
Dv = 7.5 / 2 * tan(90 - 72/2) = 3.75 * tan(54°) = 5.16 cm
B = 640 * 5.16 / 100 = 33 # 像素
```

计算和图像的功劳归功于我们的社区成员
gregflurry，他在这篇[文章](https://discuss.luxonis.com/d/339-naive-question-regarding-stereodepth-disparity-and-depth-outputs/7)中进行了这些计算。

### 测量真实世界物体尺寸

由于深度图包含 Z 距离，平行于相机的物体可以标准精确测量。对于不平行的物体，可以使用欧几里得距离计算。请参考以下内容：

例如，在运行 [RGB & Yolo with spatial data](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/detection_network.md)
示例时，您可以使用以下代码（在示例代码第 143 行之后）从 XYZ
坐标（[SpatialImgDetections](https://docs.luxonis.com/software-v3/depthai/depthai-components/messages/spatial_img_detections.md)）计算到检测物体的距离：

```python
distance = math.sqrt(detection.spatialCoordinates.x ** 2 + detection.spatialCoordinates.y ** 2 + detection.spatialCoordinates.z ** 2) # mm
```

### 长距离立体深度

要获得准确的长距离深度，我们应首先检查 [提高深度精度](#Improving%20depth%20accuracy) 的步骤，因为这些步骤特别适用于长距离深度。

对于长距离深度，我们还应考虑以下因素：

 * 窄视场（FOV）镜头
 * 立体相机之间较宽的基线距离

因此，对于长距离，我们建议使用 [OAK-D Long Range](https://docs.luxonis.com/hardware/products/OAK-D%2520LR.md)，其基线距离（更大）为 15 cm，默认视场角为 60°。它配备
[M12 卡口镜头](https://docs.luxonis.com/hardware.md#m12-selectable-fov)，用户可以将其替换为更窄（或更宽）视场角的镜头。

### 修复噪点云

对于噪点云，我们建议采用几种方法：

 * （上面提到）从 [修复噪点深度](#Fixing%20noisy%20depth) 章节开始，否则噪点会在点云中产生大量点
 * （上面提到）继续阅读 [提高深度精度](#Improving%20depth%20accuracy) 章节——深度不精确在点云中很容易看到
   * 启用 Stereo 子像素模式，特别是由于 [立体子像素对分层的影响](#Stereo%20subpixel%20effect%20on%20layering)
 * [点云的下采样滤波器](#Decimation%20filter%20for%20pointcloud) 用于更快的处理（FPS）和额外的过滤
 * [使角落周围的像素无效](#Invalidating%20pixels%20around%20the%20corner) 应该有助于减少深度帧角落周围的噪点
 * [主机端点云过滤](#Host-side%20pointcloud%20filtering) 用于额外的过滤

### 点云的下采样滤波器

[下采样滤波器](#Decimation%20filter) 特别适用于点云，您实际上不想要一百万个点（尽管听起来很适合营销），因为数据量太大无法处理。下采样滤波器在这里有帮助，并且在使用点云时应启用。

当对点云使用下采样滤波器时，您应启用中值/均值模式降采样，因为它将提供额外的过滤（与像素跳过模式相比）。它还能使其他 [立体后期处理滤波器](#Stereo%20postprocessing%20filters) 更快，因为需要处理的数据会更少。

### 使角落周围的像素无效

角落周围经常有无效/噪点像素，我们看到一些客户预防性地使深度图像角落周围的少量像素（例如 3 个）无效。我们还建议启用 [亮度滤波器](#Brightness%20filter)，尤其是由于校正“伪影”。

### 主机端点云过滤

除了设备端的 [立体后期处理滤波器](#Stereo%20postprocessing%20filters)，我们还建议运行主机端点云过滤（使用例如 [Open3D](https://www.open3d.org/) 或
[PCL](https://pointclouds.org/) 库）。

我们特别建议使用点云体素化和移除统计离群值技术，[示例在此](https://github.com/luxonis/oak-examples/blob/master/gen2-box_measurement/projector_3d.py#L35-L38)
涵盖了这两种技术。
