# IR Projectors Control

Displays left/right mono streams and lets you change [IR dot
projector](https://docs.luxonis.com/hardware/platform/features/ir-perception/dot-projector.md) and flood light (aka. flood LED)
intensities on the device at runtime. Enabling flood lights allows for better depth detection. Controls: W/S for dot intensity,
A/D for flood intensity, Q to quit. Works only with [Pro-series devices](#IR%2520Projectors%2520Control-Supported%2520devices).

## Demo

This example requires the DepthAI v3 API, see [installation instructions](https://docs.luxonis.com/software-v3/depthai.md).

## Supported devices

 * OAK4-D Pro
 * OAK-D Pro W PoE
 * OAK-D Pro W
 * OAK-D Pro PoE
 * OAK-D Pro

## Pipeline

### examples/projectors.pipeline.json

```json
{
  "pipeline": {
    "connections": [],
    "globalProperties": {
      "calibData": null,
      "cameraTuningBlobSize": null,
      "cameraTuningBlobUri": "",
      "eepromId": 0,
      "leonCssFrequencyHz": 700000000.0,
      "leonMssFrequencyHz": 700000000.0,
      "pipelineName": null,
      "pipelineVersion": null,
      "sippBufferSize": 18432,
      "sippDmaBufferSize": 16384,
      "xlinkChunkSize": -1
    },
    "nodes": [
      [
        0,
        {
          "alias": "",
          "id": 0,
          "ioInfo": [
            [
              [
                "",
                "inputControl"
              ],
              {
                "blocking": true,
                "group": "",
                "id": 0,
                "name": "inputControl",
                "queueSize": 3,
                "type": 3,
                "waitForMessage": false
              }
            ],
            [
              [
                "dynamicOutputs",
                "0"
              ],
              {
                "blocking": false,
                "group": "dynamicOutputs",
                "id": 3,
                "name": "0",
                "queueSize": 8,
                "type": 0,
                "waitForMessage": false
              }
            ],
            [
              [
                "",
                "mockIsp"
              ],
              {
                "blocking": true,
                "group": "",
                "id": 1,
                "name": "mockIsp",
                "queueSize": 8,
                "type": 3,
                "waitForMessage": false
              }
            ],
            [
              [
                "",
                "raw"
              ],
              {
                "blocking": false,
                "group": "",
                "id": 2,
                "name": "raw",
                "queueSize": 8,
                "type": 0,
                "waitForMessage": false
              }
            ]
          ],
          "logLevel": 3,
          "name": "Camera",
          "parentId": -1,
          "properties": {
            "boardSocket": 1,
            "cameraName": "",
            "fps": -1.0,
            "imageOrientation": -1,
            "initialControl": {
              "aeLockMode": false,
              "aeMaxExposureTimeUs": 0,
              "aeRegion": {
                "height": 0,
                "priority": 0,
                "width": 0,
                "x": 0,
                "y": 0
              },
              "afRegion": {
                "height": 0,
                "priority": 0,
                "width": 0,
                "x": 0,
                "y": 0
              },
              "antiBandingMode": 0,
              "autoFocusMode": 3,
              "awbLockMode": false,
              "awbMode": 0,
              "brightness": 0,
              "captureIntent": 0,
              "chromaDenoise": 0,
              "cmdMask": 0,
              "contrast": 0,
              "controlMode": 0,
              "effectMode": 0,
              "enableHdr": false,
              "expCompensation": 0,
              "expManual": {
                "exposureTimeUs": 0,
                "frameDurationUs": 0,
                "sensitivityIso": 0
              },
              "frameSyncMode": 0,
              "lensPosAutoInfinity": 0,
              "lensPosAutoMacro": 0,
              "lensPosition": 0,
              "lensPositionRaw": 0.0,
              "lowPowerNumFramesBurst": 0,
              "lowPowerNumFramesDiscard": 0,
              "lumaDenoise": 0,
              "miscControls": [],
              "saturation": 0,
              "sceneMode": 0,
              "sharpness": 0,
              "strobeConfig": {
                "activeLevel": 0,
                "enable": 0,
                "gpioNumber": 0
              },
              "strobeTimings": {
                "durationUs": 0,
                "exposureBeginOffsetUs": 0,
                "exposureEndOffsetUs": 0
              },
              "wbColorTemp": 0
            },
            "isp3aFps": 0,
            "mockIspHeight": -1,
            "mockIspWidth": -1,
            "numFramesPoolIsp": 3,
            "numFramesPoolPreview": 4,
            "numFramesPoolRaw": 3,
            "numFramesPoolStill": 4,
            "numFramesPoolVideo": 4,
            "outputRequests": [
              {
                "enableUndistortion": null,
                "fps": {
                  "value": null
                },
                "resizeMode": 0,
                "size": {
                  "value": {
                    "index": 0,
                    "value": [
                      1280,
                      800
                    ]
                  }
                },
                "type": 22
              }
            ],
            "resolutionHeight": -1,
            "resolutionWidth": -1,
            "sensorType": -1
          }
        }
      ],
      [
        1,
        {
          "alias": "",
          "id": 1,
          "ioInfo": [
            [
              [
                "",
                "inputControl"
              ],
              {
                "blocking": true,
                "group": "",
                "id": 4,
                "name": "inputControl",
                "queueSize": 3,
                "type": 3,
                "waitForMessage": false
              }
            ],
            [
              [
                "dynamicOutputs",
                "0"
              ],
              {
                "blocking": false,
                "group": "dynamicOutputs",
                "id": 7,
                "name": "0",
                "queueSize": 8,
                "type": 0,
                "waitForMessage": false
              }
            ],
            [
              [
                "",
                "mockIsp"
              ],
              {
                "blocking": true,
                "group": "",
                "id": 5,
                "name": "mockIsp",
                "queueSize": 8,
                "type": 3,
                "waitForMessage": false
              }
            ],
            [
              [
                "",
                "raw"
              ],
              {
                "blocking": false,
                "group": "",
                "id": 6,
                "name": "raw",
                "queueSize": 8,
                "type": 0,
                "waitForMessage": false
              }
            ]
          ],
          "logLevel": 3,
          "name": "Camera",
          "parentId": -1,
          "properties": {
            "boardSocket": 2,
            "cameraName": "",
            "fps": -1.0,
            "imageOrientation": -1,
            "initialControl": {
              "aeLockMode": false,
              "aeMaxExposureTimeUs": 2811104752,
              "aeRegion": {
                "height": 0,
                "priority": 2811104880,
                "width": 528,
                "x": 35376,
                "y": 42896
              },
              "afRegion": {
                "height": 42889,
                "priority": 528,
                "width": 31728,
                "x": 528,
                "y": 0
              },
              "antiBandingMode": 12,
              "autoFocusMode": 3,
              "awbLockMode": false,
              "awbMode": 176,
              "brightness": 0,
              "captureIntent": 201,
              "chromaDenoise": 16,
              "cmdMask": 0,
              "contrast": 112,
              "controlMode": 16,
              "effectMode": 2,
              "enableHdr": false,
              "expCompensation": 0,
              "expManual": {
                "exposureTimeUs": 528,
                "frameDurationUs": 528,
                "sensitivityIso": 3373060416
              },
              "frameSyncMode": 0,
              "lensPosAutoInfinity": 112,
              "lensPosAutoMacro": 18,
              "lensPosition": 0,
              "lensPositionRaw": 0.0,
              "lowPowerNumFramesBurst": 112,
              "lowPowerNumFramesDiscard": 157,
              "lumaDenoise": 167,
              "miscControls": [],
              "saturation": 16,
              "sceneMode": 209,
              "sharpness": 142,
              "strobeConfig": {
                "activeLevel": 240,
                "enable": 0,
                "gpioNumber": 0
              },
              "strobeTimings": {
                "durationUs": 528,
                "exposureBeginOffsetUs": 528,
                "exposureEndOffsetUs": -1483865232
              },
              "wbColorTemp": 0
            },
            "isp3aFps": 0,
            "mockIspHeight": -1,
            "mockIspWidth": -1,
            "numFramesPoolIsp": 3,
            "numFramesPoolPreview": 4,
            "numFramesPoolRaw": 3,
            "numFramesPoolStill": 4,
            "numFramesPoolVideo": 4,
            "outputRequests": [
              {
                "enableUndistortion": null,
                "fps": {
                  "value": null
                },
                "resizeMode": 0,
                "size": {
                  "value": {
                    "index": 0,
                    "value": [
                      1280,
                      800
                    ]
                  }
                },
                "type": 22
              }
            ],
            "resolutionHeight": -1,
            "resolutionWidth": -1,
            "sensorType": -1
          }
        }
      ]
    ]
  }
}
```

## Source code

#### Python

```python
#!/usr/bin/env python3

import cv2
import depthai as dai

dot_intensity = 1
DOT_STEP = 0.1

flood_intensity = 1
FLOOD_STEP = 0.1

# Create pipeline
device = dai.Device()
with dai.Pipeline(device) as pipeline:
    monoLeft = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_B)
    monoRight = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_C)

    # Linking
    monoLeftOut = monoLeft.requestFullResolutionOutput(type=dai.ImgFrame.Type.NV12)
    monoRightOut = monoRight.requestFullResolutionOutput(type=dai.ImgFrame.Type.NV12)

    leftQueue = monoLeftOut.createOutputQueue()
    rightQueue = monoRightOut.createOutputQueue()

    pipeline.start()
    pipeline.getDefaultDevice().setIrLaserDotProjectorIntensity(dot_intensity)
    pipeline.getDefaultDevice().setIrFloodLightIntensity(flood_intensity)
    while pipeline.isRunning():
        leftSynced = leftQueue.get()
        rightSynced = rightQueue.get()
        assert isinstance(leftSynced, dai.ImgFrame)
        assert isinstance(rightSynced, dai.ImgFrame)
        cv2.imshow(f"left", leftSynced.getCvFrame())
        cv2.imshow(f"right", rightSynced.getCvFrame())

        key = cv2.waitKey(1)
        if key == ord('q'):
            pipeline.stop()
            break
        elif key == ord("w"):
            dot_intensity += DOT_STEP
            if dot_intensity > 1:
                dot_intensity = 1
            pipeline.getDefaultDevice().setIrLaserDotProjectorIntensity(dot_intensity)
            print(f"Dot intensity: {dot_intensity}")
        elif key == ord("s"):
            dot_intensity -= DOT_STEP
            if dot_intensity < 0:
                dot_intensity = 0
            pipeline.getDefaultDevice().setIrLaserDotProjectorIntensity(dot_intensity)
            print(f"Dot intensity: {dot_intensity}")
        elif key == ord("a"):
            flood_intensity += FLOOD_STEP
            if flood_intensity > 1:
                flood_intensity = 1
            pipeline.getDefaultDevice().setIrFloodLightIntensity(flood_intensity)
            print(f"Flood intensity: {flood_intensity}")
        elif key == ord("d"):
            flood_intensity -= FLOOD_STEP
            if flood_intensity < 0:
                flood_intensity = 0
            pipeline.getDefaultDevice().setIrFloodLightIntensity(flood_intensity)
            print(f"Flood intensity: {flood_intensity}")
```

#### C++

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

#include "depthai/depthai.hpp"

// Global flag for graceful shutdown
std::atomic<bool> quitEvent(false);

// Signal handler
void signalHandler(int signum) {
    quitEvent = true;
}

// Constants for intensity control
constexpr float DOT_STEP = 0.1f;
constexpr float FLOOD_STEP = 0.1f;

int main() {
    // Set up signal handlers
    signal(SIGTERM, signalHandler);
    signal(SIGINT, signalHandler);

    try {
        // Create device
        auto device = std::make_shared<dai::Device>();

        // Create pipeline
        dai::Pipeline pipeline(device);

        // Create camera nodes
        auto monoLeft = pipeline.create<dai::node::Camera>()->build(dai::CameraBoardSocket::CAM_B);
        auto monoRight = pipeline.create<dai::node::Camera>()->build(dai::CameraBoardSocket::CAM_C);

        // Configure outputs
        auto monoLeftOut = monoLeft->requestFullResolutionOutput(dai::ImgFrame::Type::NV12);
        auto monoRightOut = monoRight->requestFullResolutionOutput(dai::ImgFrame::Type::NV12);

        // Create output queues
        auto leftQueue = monoLeftOut->createOutputQueue();
        auto rightQueue = monoRightOut->createOutputQueue();

        // Start pipeline
        pipeline.start();

        // Initialize intensities
        float dot_intensity = 1.0f;
        float flood_intensity = 1.0f;

        // Set initial intensities
        device->setIrLaserDotProjectorIntensity(dot_intensity);
        device->setIrFloodLightIntensity(flood_intensity);

        std::cout << "Controls:" << std::endl;
        std::cout << "  W/S: Increase/decrease dot projector intensity" << std::endl;
        std::cout << "  A/D: Increase/decrease flood light intensity" << std::endl;
        std::cout << "  Q: Quit" << std::endl;

        while(pipeline.isRunning() && !quitEvent) {
            auto leftSynced = leftQueue->get<dai::ImgFrame>();
            auto rightSynced = rightQueue->get<dai::ImgFrame>();

            if(leftSynced == nullptr || rightSynced == nullptr) continue;

            cv::imshow("left", leftSynced->getCvFrame());
            cv::imshow("right", rightSynced->getCvFrame());

            int key = cv::waitKey(1);
            if(key == 'q') {
                break;
            } else if(key == 'w') {
                dot_intensity += DOT_STEP;
                if(dot_intensity > 1.0f) dot_intensity = 1.0f;
                device->setIrLaserDotProjectorIntensity(dot_intensity);
                std::cout << "Dot intensity: " << dot_intensity << std::endl;
            } else if(key == 's') {
                dot_intensity -= DOT_STEP;
                if(dot_intensity < 0.0f) dot_intensity = 0.0f;
                device->setIrLaserDotProjectorIntensity(dot_intensity);
                std::cout << "Dot intensity: " << dot_intensity << std::endl;
            } else if(key == 'a') {
                flood_intensity += FLOOD_STEP;
                if(flood_intensity > 1.0f) flood_intensity = 1.0f;
                device->setIrFloodLightIntensity(flood_intensity);
                std::cout << "Flood intensity: " << flood_intensity << std::endl;
            } else if(key == 'd') {
                flood_intensity -= FLOOD_STEP;
                if(flood_intensity < 0.0f) flood_intensity = 0.0f;
                device->setIrFloodLightIntensity(flood_intensity);
                std::cout << "Flood intensity: " << flood_intensity << std::endl;
            }
        }

        // Cleanup
        pipeline.stop();
        pipeline.wait();

    } catch(const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}
```

### Need assistance?

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