# 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.

> 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 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.

> 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);
```

> 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

#### 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

> `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.
