# AutoCalibration

`AutoCalibration` is a host node that runs automatic stereo calibration workflows in a pipeline and provides calibration quality
results during runtime.

It is important to separate the two layers:

 * `AutoCalibration` is a host node that you add to your pipeline.
 * Internally, it controls and uses `DynamicCalibration` in the background.
 * `DEPTHAI_AUTOCALIBRATION` is a global deployment switch for automatic calibration.

## Three ways to enable automatic calibration

Choose based on how much control you need:

 * Global variable (`DEPTHAI_AUTOCALIBRATION`) Best for deployed pipelines where you want to enable automatic behavior without
   changing code.
 * AutoCalibration host node Best when you want explicit pipeline-level control over mode, retries, validation, flashing, and
   result handling.
 * Pipeline setter (`pipeline.setAutoCalibrationMode(...)`) Best when you want lightweight code-level control without adding the
   `AutoCalibration` host node.

## Automatic calibration via global variable

Use one of the following environment values:

```bash
DEPTHAI_AUTOCALIBRATION=ON_START
DEPTHAI_AUTOCALIBRATION=CONTINUOUS
DEPTHAI_AUTOCALIBRATION=OFF
```

These values run automatic calibration without adding node-level API handling in your application.

> **Note**
> From `DepthAI 3.6`, automatic calibration is enabled by default in `ON_START` mode. Use `DEPTHAI_AUTOCALIBRATION=OFF` or `pipeline.setAutoCalibrationMode(...OFF)` to disable it.

### Behavior notes

 * Applies to stereo `1280x800` and `640x400` pipelines.
 * Flashes calibration as user calibration.
 * Factory calibration remains untouched.
 * If your pipeline already includes a
   [`DynamicCalibration`](https://docs.luxonis.com/software-v3/depthai/depthai-components/host_nodes/dynamic_calibration.md) node
   or an `AutoCalibration` node, `AutoCalibrationMode` - based automatic procedure is not initialized.

> **Note**
> In both `ON_START` and `CONTINUOUS` procedures, the new calibration is flashed as user calibration. This overwrites the existing user calibration currently stored on the device.

### ON_START procedure

Runs automatic calibration during startup and then continues with normal pipeline execution.

#### Example

```bash
DEPTHAI_AUTOCALIBRATION=ON_START python3 examples/Stereo/stereo.py
```

Optional detailed logs:

```bash
DEPTHAI_LEVEL=info DEPTHAI_AUTOCALIBRATION=ON_START python3 examples/Stereo/stereo.py
```

If startup calibration fails validation, no new calibration is flashed.

Typical startup timing depends on scene coverage and retries:

 * Fast path: about `2.5s`.
 * Common retry path: about `6s`.
 * Worst-case retries (`maxIterations = 10`): up to about `25s`.

### CONTINUOUS procedure

Runs calibration continuously during runtime, adapting to changing thermal/mechanical conditions.

#### Example

```bash
DEPTHAI_AUTOCALIBRATION=CONTINUOUS python3 examples/Stereo/stereo.py
```

Optional detailed logs:

```bash
DEPTHAI_LEVEL=info DEPTHAI_AUTOCALIBRATION=CONTINUOUS python3 examples/Stereo/stereo.py
```

This mode adds ongoing processing overhead, unlike `ON_START`.

## Automatic calibration via pipeline setter

Use `pipeline.setAutoCalibrationMode(...)` when you want explicit mode control in code without adding the `AutoCalibration` host
node.

#### Python

```python
pipeline = dai.Pipeline()
pipeline.setAutoCalibrationMode(dai.Pipeline.AutoCalibrationMode.ON_START)
# Or run continuously:
# pipeline.setAutoCalibrationMode(dai.Pipeline.AutoCalibrationMode.CONTINUOUS)

# Disable automatic calibration
pipeline.setAutoCalibrationMode(dai.Pipeline.AutoCalibrationMode.OFF)
```

#### C++

```cpp
dai::Pipeline pipeline;
pipeline.setAutoCalibrationMode(dai::Pipeline::AutoCalibrationMode::ON_START);
// Or run continuously:
// pipeline.setAutoCalibrationMode(dai::Pipeline::AutoCalibrationMode::CONTINUOUS);

// Disable automatic calibration
pipeline.setAutoCalibrationMode(dai::Pipeline::AutoCalibrationMode::OFF);
```

> **Note**
> If both `DEPTHAI_AUTOCALIBRATION` and `pipeline.setAutoCalibrationMode(...)` are set, the pipeline-local mode set in code overrides the environment variable.

## AutoCalibration host node in your pipeline

Use this approach when you want explicit control and direct access to runtime outputs.

### Example

The examples below use `1280x800` stereo inputs, but the same AutoCalibration workflow also supports `640x400`.

#### Python

```python
import cv2 as cv
import numpy as np
import depthai as dai

# Create pipeline
with dai.Pipeline() as pipeline:
    device = pipeline.getDefaultDevice()
    botchCalibration(device)

    camLeft = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_B)
    camRight = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_C)
    stereo = pipeline.create(dai.node.StereoDepth)

    dcWorker = pipeline.create(dai.node.AutoCalibration).build(camLeft, camRight)
    dcWorker.initialConfig.maxIterations = 2
    dcWorker.initialConfig.sleepingTime = 10
    dcWorker.initialConfig.flashCalibration = False 
    dcWorker.initialConfig.mode = dai.AutoCalibrationConfig.CONTINUOUS  # ON_START
    dcWorker.initialConfig.validationSetSize = 5 
    dcWorker.initialConfig.dataConfidenceThreshold = 0.7
    workerOutputQueue = dcWorker.output.createOutputQueue()

    videoQueueLeft = camLeft.requestOutput((1280, 800), fps=30)
    videoQueueRight = camRight.requestOutput((1280, 800), fps=30)

    videoQueueLeft.link(stereo.left)
    videoQueueRight.link(stereo.right)

    stereoOut = stereo.depth.createOutputQueue()
    pipeline.start()

    while pipeline.isRunning():
        workerOutput = workerOutputQueue.tryGet()
        if workerOutput is not None:
            if workerOutput.passed:
                print("Passed")
                print(f"dataConfidence = {workerOutput.dataConfidence}")
                print(f"calibrationConfidence = {workerOutput.calibrationConfidence}")
            else:
                print("Did not pass")

        depth = stereoOut.get()
        cv.imshow("Depth", depth)

        if cv.waitKey(1) == ord("q"):
            break
        
    pipeline.stop()
```

#### C++

```cpp
#include <iostream>
#include <memory>
#include <opencv2/opencv.hpp>
#include <vector>

#include "depthai/depthai.hpp"
int main() {
    dai::Pipeline pipeline;

    // Create device
    auto device = pipeline.getDefaultDevice();

    // Nodes
    auto camLeft = pipeline.create<dai::node::Camera>()->build(dai::CameraBoardSocket::CAM_B);
    auto camRight = pipeline.create<dai::node::Camera>()->build(dai::CameraBoardSocket::CAM_C);
    auto stereo = pipeline.create<dai::node::StereoDepth>();

    // AutoCalibration node
    auto dcWorker = pipeline.create<dai::node::AutoCalibration>();
    dcWorker->build(camLeft, camRight);

    auto config = dcWorker->initialConfig;
    config->maxIterations = 2;
    config->sleepingTime = 10;
    config->flashCalibration = false;
    config->mode = dai::AutoCalibrationConfig::CONTINUOUS;
    config->validationSetSize = 5;
    config->dataConfidenceThreshold = 0.7;

    // Links
    camLeft->requestOutput({1280, 800})->link(stereo->left);
    camRight->requestOutput({1280, 800})->link(stereo->right);

    // Queues
    auto workerOutputQueue = dcWorker->output.createOutputQueue();
    auto stereoOut = stereo->depth.createOutputQueue();

    pipeline.start();

    while(pipeline.isRunning()) {
        auto workerOutput = workerOutputQueue->tryGet<dai::AutoCalibrationResult>();
        if(workerOutput != nullptr) {
            if(workerOutput->passed) {
                std::cout << "Passed. Confidence: " << workerOutput->dataConfidence << std::endl;
            } else {
                std::cout << "Did not pass." << std::endl;
            }
        }

        auto depth = stereoOut->get<dai::ImgFrame>();
        cv::imshow("Depth", depth);

        if(cv::waitKey(1) == 'q') break;
    }

    return 0;
}
```

### Configuration Parameters

Configure behavior through `auto_calib.initialConfig`:

 * `mode` Selects the automatic calibration procedure (`ON_START` or `CONTINUOUS`).
 * `flashCalibration` If `true`, calibration is flashed as user calibration after successful validation.
 * `maxIterations` Maximum number of calibration attempts.
 * `sleepingTime` Delay between calibration attempts/iterations.
 * `validationSetSize` Number of validation samples used before accepting calibration.

### Node Output (Result)

The node provides `AutoCalibrationResult` messages. Common fields:

 * `passed` Whether calibration/validation succeeded.
 * `dataQuality` Quality indicator of the collected calibration data.
 * `calibrationConfidence` Confidence score for the resulting calibration.

## Availability and rollout status

 * `DepthAI 3.5.0` provides startup automatic calibration as an opt-in beta through `DEPTHAI_AUTOCALIBRATION`.
 * From `DepthAI 3.6`, automatic calibration is enabled by default in `ON_START` mode.
 * Use `DEPTHAI_AUTOCALIBRATION=OFF` or `pipeline.setAutoCalibrationMode(...OFF)` to disable it.

Install example:

```bash
python3 -m pip install depthai==3.5.0
```

## Feedback

> **Note**
> `AutoCalibration` is an actively evolving feature. If you want to help shape it, use the node in real deployments and share feedback with us on GitHub: what worked well, what failed, and what parameters or outputs you want to see improved. We prioritize API improvements based on user feedback.

If you encounter issues or want API improvements, report them via:

 * Forum: [discuss.luxonis.com](https://discuss.luxonis.com/)
 * GitHub: [luxonis/depthai-core](https://github.com/luxonis/depthai-core)
 * For calibration data collection during debugging, use [Stereo Tuning
   Assistance](https://www.luxonis.com/stereo-tuning-assistance) and attach the captured zip folder.

## Reference

### dai::node::AutoCalibration

Kind: class

#### dai::DynamicCalibrationControl DCC

Kind: enum

#### std::shared_ptr< AutoCalibrationConfig > initialConfig

Kind: variable

#### Output output

Kind: variable

#### std::shared_ptr< AutoCalibration > build(const std::shared_ptr< Camera > & cameraLeft, const std::shared_ptr< Camera > & cameraRight)

Kind: function

#### ~AutoCalibration()

Kind: function

#### void run()

Kind: function

#### void setRunOnHost(bool runOnHost)

Kind: function

#### bool runOnHost()

Kind: function

Returns true or false whether the node should be run on host or not.

#### void buildInternal()

Kind: function

Function called from within the

#### DeviceNodeCRTP()

Kind: function

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

Kind: function

#### DeviceNodeCRTP(std::unique_ptr< Properties > props)

Kind: function

#### DeviceNodeCRTP(std::unique_ptr< Properties > props, bool confMode)

Kind: function

#### DeviceNodeCRTP(const std::shared_ptr< Device > & device, std::unique_ptr< Properties > props, bool confMode)

Kind: function

### Need assistance?

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