# ToF

The ToF node converts raw Time-of-Flight sensor data into depth and exposes both base and filtered outputs. It is available on
devices with integrated ToF sensors, such as:

 * [OAK-D ToF](https://shop.luxonis.com/products/oak-d-sr-poe)
 * [OAK-FFC ToF 33D](https://shop.luxonis.com/products/oak-ffc-tof-33d)

ToF depth can be used directly with spatial nodes, for example
[SpatialDetectionNetwork](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/spatial_detection_network.md) and
[SpatialLocationCalculator](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/spatial_location_calculator.md).

For depth quality comparisons with stereo, see [ToF depth
accuracy](https://docs.luxonis.com/hardware/platform/depth/depth-accuracy.md).

## How to place it

#### Python

```python
pipeline = dai.Pipeline()
tof = pipeline.create(dai.node.ToF)
```

#### C++

```cpp
dai::Pipeline pipeline;
auto tof = pipeline.create<dai::node::ToF>();
```

## Inputs and Outputs

## DepthAI v3 ToF architecture

DepthAI v3 ToF pipelines are best understood as two layers:

 1. ToF base decode Converts sensor measurements into base signals (rawDepth, amplitude, intensity, phase) and handles
    ToF-specific decode settings such as phase unwrapping.
 2. Filtering stage Produces filtered depth output (depth) using ToF-oriented filtering presets and runtime filter configuration.

On RVC2, the filtering stage is host-run.

## Setup differences on ToF cameras

Many OAK depth examples assume a classic stereo layout (one color camera + mono stereo pair on CAM_* sockets). ToF cameras are
typically used as a ToF + color camera setup (two functional camera sources), where depth comes from dai.node.ToF, not from
StereoDepth.

Common integration pitfall in generic apps:

 * Do not treat the ToF sensor as a normal color preview source.
 * Do not auto-create default mono stereo-pair streams on ToF-only devices.
 * Build depth from ToF, and add a color stream only if needed (for example, alignment/overlay).

## ToF settings

Common base decode settings (from
[ToFConfig](https://docs.luxonis.com/software-v3/depthai/depthai-components/messages/tof_config.md)):

 * Optical correction: converts radial distance to depth (Z-map) so behavior matches stereo depth usage.
 * Undistortion: depth and amplitude are undistorted by default.
 * Phase unwrapping: extends range at the cost of more noise.
 * Phase shuffle temporal filter: reduces noise by combining shuffled/non-shuffled captures.
 * Burst mode: avoids frame reuse in decode, trading output rate for reduced motion artifacts.

Approximate range by unwrapping level:

 * 0 (disabled): up to ~1.87 m (80 MHz)
 * 1: up to ~3.0 m
 * 2: up to ~4.5 m
 * 3: up to ~6.0 m
 * 4: up to ~7.5 m

Post-processing is configured via
[ImageFilters](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/image_filters.md) and
[ImageFiltersConfig](https://docs.luxonis.com/software-v3/depthai/depthai-components/messages/image_filters_config.md). For
confidence-driven cleanup, see
[ToFDepthConfidenceFilterConfig](https://docs.luxonis.com/software-v3/depthai/depthai-components/messages/tof_depth_confidence_filter_config.md).

## Quick Tuning Guide: Depth Image Filters

The tuning goal is to balance a clean, noise-free depth map with fast, accurate updates of moving objects. For ToF depth outputs,
delta is typically interpreted in depth units (usually millimeters), while alpha is a blending factor in [0.0, 1.0]. Treat all
values below as starting points and tune for your scene.

### Step 1: Blank slate

Before tuning, disable all filters. This helps you measure baseline noise, verify sensor placement/lighting, and avoid masking
setup issues with software filtering.

### Step 2: Temporal filter (start here)

Tune TemporalFilterParams first because it controls dynamic smoothing over time.

 * delta: threshold for deciding whether a depth change is significant vs noise.
   * Start with delta = 15.
   * For larger objects (for example ~50 mm object height), use delta = 25 so motion updates quickly.
   * For small objects, tighten to delta = 10.
 * alpha: blending weight of current frame vs history.
   * Lower alpha (for example 0.1) gives smoother output but can introduce lag/trails.
   * Higher alpha (for example 0.4) updates faster but smooths less.
 * Important: delta = 0 makes nearly every change significant and largely bypasses temporal blending.

### Step 3: Speckle filter

Use SpeckleFilterParams to remove isolated blobs and salt-and-pepper-like artifacts in single frames.

 * differenceThreshold (boss alias: max_diff): threshold for grouping neighboring pixels into the same region.
 * speckleRange (boss alias: max_speckle_size): maximum region size to remove.
 * Tuning strategy: gradually increase speckleRange to remove larger floating blobs, but avoid values that delete real small
   objects.

### Step 4: Spatial filter

Use SpatialFilterParams to smooth object surfaces while preserving edges.

 * alpha: smoothing intensity (lower values usually smooth more).
 * delta: edge-preservation threshold; larger depth jumps are treated as edges and are not blended.
 * holeFillingRadius: fills invalid (0) pixels from surrounding valid data.
 * numIterations: more passes can refine output at slight processing cost.

### Step 5: Median filter

Use MedianFilterParams for final aggressive cleanup when residual salt-and-pepper noise remains.

 * Supported modes in this node: MEDIAN_OFF, KERNEL_3x3, KERNEL_5x5.
 * Use the smallest kernel that solves the noise to minimize edge/detail loss.

### Tuning quick reference

| Filter | Key Parameters | Primary Use Case | Trade-off |
| --- | --- | --- | --- |
| Temporal | `delta`, `alpha` | Smoothing dynamic noise over time | Smoothness vs motion lag |
| Speckle | `speckleRange`, `differenceThreshold` | Removing isolated blobs/noise | Cleanliness vs deleting small objects |
| Spatial | `delta`, `alpha`, `holeFillingRadius`, `numIterations` | Surface smoothing with edge preservation | Smoothness vs
processing cost |
| Median | `KERNEL_3x3`, `KERNEL_5x5` | Aggressive salt-and-pepper cleanup | Noise removal vs edge/detail blur |

For full parameter definitions and runtime configuration flow, see
[ImageFilters](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/image_filters.md),
[ImageFiltersConfig](https://docs.luxonis.com/software-v3/depthai/depthai-components/messages/image_filters_config.md), and
[ToFDepthConfidenceFilterConfig](https://docs.luxonis.com/software-v3/depthai/depthai-components/messages/tof_depth_confidence_filter_config.md).

## ToF motion blur

To reduce motion blur:

 * Increase sensor FPS (up to 160 FPS), while accounting for higher system load and reduced exposure time.
 * Disable phase shuffle temporal filter (higher noise).
 * Disable phase unwrapping (reduces max range).
 * Enable burst mode when applicable.

## Max distance

Maximum distance depends on modulation frequency and phase unwrapping settings.

```math
c = 299792458.0 # speed of light in m/s

MAX_80MHZ_M = c / (80000000 * 2) = 1.873 m
MAX_100MHZ_M = c / (100000000 * 2) = 1.498 m

MAX_DIST_80MHZ_M = (phaseUnwrappingLevel + 1) * 1.873 + (phaseUnwrapErrorThreshold / 2)
MAX_DIST_100MHZ_M = (phaseUnwrappingLevel + 1) * 1.498 + (phaseUnwrapErrorThreshold / 2)
```

## ToF FPS

Sensor/emitter can run up to 160 FPS. Effective depth output depends on decode/filter settings (for example burst mode and phase
processing).

## Usage

#### Python

```python
pipeline = dai.Pipeline()

socket = dai.CameraBoardSocket.AUTO
preset = dai.ImageFiltersPresetMode.TOF_MID_RANGE
tof = pipeline.create(dai.node.ToF).build(socket, preset)

# Base and filtered outputs
raw_depth_q = tof.rawDepth.createOutputQueue()
depth_q = tof.depth.createOutputQueue()

# Runtime configuration queues (where available in the selected API binding)
base_cfg_q = tof.tofBaseInputConfig.createInputQueue()
filters_cfg_q = tof.imageFiltersInputConfig.createInputQueue()
```

#### C++

```cpp
dai::Pipeline pipeline;

auto tof = pipeline.create<dai::node::ToF>()->build(
    dai::CameraBoardSocket::AUTO,
    dai::ImageFiltersPresetMode::TOF_MID_RANGE
);

auto rawDepthQ = tof->rawDepth.createOutputQueue();
auto depthQ = tof->depth.createOutputQueue();
```

## Examples

 * [RVC2 ToF example](https://docs.luxonis.com/software-v3/depthai/examples/rvc2/tof/tof.md)
 * [ToF pointcloud + runtime tuning
   (oak-examples)](https://github.com/luxonis/oak-examples/tree/bbc446232ad9378e03e9cb89b04dbb9f99f2448f/depth-measurement/3d-measurement/tof-pointcloud)

## Reference

### dai::node::ToF

Kind: class

#### Subnode < ToFBase > tofBase

Kind: variable

#### Subnode < ImageFilters > imageFilters

Kind: variable

#### Output & rawDepth

Kind: variable

Raw depth output from ToF sensor

#### Output & depth

Kind: variable

Filtered depth output

#### Output & amplitude

Kind: variable

Amplitude output

#### Output & intensity

Kind: variable

Intensity output

#### Output & phase

Kind: variable

Phase output

#### Input & tofBaseInputConfig

Kind: variable

Input config for ToF base node

#### Input & imageFiltersInputConfig

Kind: variable

Input config for image filters

#### ToFBase & tofBaseNode

Kind: variable

ToF base node

#### ImageFilters & imageFiltersNode

Kind: variable

Image filters node

#### ToF(const std::shared_ptr< Device > & device)

Kind: function

#### ~ToF()

Kind: function

#### void buildInternal()

Kind: function

Function called from within the

#### std::shared_ptr< ToF > build(dai::CameraBoardSocket boardSocket, dai::ImageFiltersPresetMode presetMode, std::optional< float
> fps)

Kind: function

### Need assistance?

Head over to [Discussion Forum](https://discuss.luxonis.com/) for technical support or any other questions you might have.
