# Warp Mesh

This example shows usage of [Warp](https://docs.luxonis.com/software/depthai-components/nodes/warp.md) node to warp the input
image frame.

## Setup

Please run the [install script](https://github.com/luxonis/depthai-python/blob/main/examples/install_requirements.py) to download
all required dependencies. Please note that this script must be ran from git context, so you have to download the
[depthai-python](https://github.com/luxonis/depthai-python) repository first and then run the script

```bash
git clone https://github.com/luxonis/depthai-python.git
cd depthai-python/examples
python3 install_requirements.py
```

For additional information, please follow the [installation guide](https://docs.luxonis.com/software/depthai/manual-install.md).

## Demo

## Source code

#### Python

```python
#!/usr/bin/env python3
import cv2
import depthai as dai
import numpy as np

# Create pipeline
pipeline = dai.Pipeline()

camRgb = pipeline.create(dai.node.ColorCamera)
camRgb.setPreviewSize(496, 496)
camRgb.setInterleaved(False)
maxFrameSize = camRgb.getPreviewWidth() * camRgb.getPreviewHeight() * 3

# Warp preview frame 1
warp1 = pipeline.create(dai.node.Warp)
# Create a custom warp mesh
tl = dai.Point2f(20, 20)
tr = dai.Point2f(460, 20)
ml = dai.Point2f(100, 250)
mr = dai.Point2f(400, 250)
bl = dai.Point2f(20, 460)
br = dai.Point2f(460, 460)
warp1.setWarpMesh([tl,tr,ml,mr,bl,br], 2, 3)
WARP1_OUTPUT_FRAME_SIZE = (992,500)
warp1.setOutputSize(WARP1_OUTPUT_FRAME_SIZE)
warp1.setMaxOutputFrameSize(WARP1_OUTPUT_FRAME_SIZE[0] * WARP1_OUTPUT_FRAME_SIZE[1] * 3)
warp1.setHwIds([1])
warp1.setInterpolation(dai.Interpolation.NEAREST_NEIGHBOR)

camRgb.preview.link(warp1.inputImage)
xout1 = pipeline.create(dai.node.XLinkOut)
xout1.setStreamName('out1')
warp1.out.link(xout1.input)

# Warp preview frame 2
warp2 = pipeline.create(dai.node.Warp)
# Create a custom warp mesh
mesh2 = [
    (20, 20), (250, 100), (460, 20),
    (100, 250), (250, 250), (400, 250),
    (20, 480), (250, 400), (460,480)
]
warp2.setWarpMesh(mesh2, 3, 3)
warp2.setMaxOutputFrameSize(maxFrameSize)
warp1.setHwIds([2])
warp2.setInterpolation(dai.Interpolation.BICUBIC)

camRgb.preview.link(warp2.inputImage)
xout2 = pipeline.create(dai.node.XLinkOut)
xout2.setStreamName('out2')
warp2.out.link(xout2.input)

# Connect to device and start pipeline
with dai.Device(pipeline) as device:
    # Output queue will be used to get the rgb frames from the output defined above
    q1 = device.getOutputQueue(name="out1", maxSize=8, blocking=False)
    q2 = device.getOutputQueue(name="out2", maxSize=8, blocking=False)

    while True:
        in1 = q1.get()
        if in1 is not None:
            cv2.imshow("Warped preview 1", in1.getCvFrame())
        in2 = q2.get()
        if in2 is not None:
            cv2.imshow("Warped preview 2", in2.getCvFrame())

        if cv2.waitKey(1) == ord('q'):
            break
```

#### C++

```cpp
#include <iostream>

// Inludes common necessary includes for development using depthai library
#include "depthai/depthai.hpp"

int main() {
    using namespace std;

    // Create pipeline
    dai::Pipeline pipeline;

    auto camRgb = pipeline.create<dai::node::ColorCamera>();
    camRgb->setPreviewSize(496, 496);
    camRgb->setInterleaved(false);
    auto maxFrameSize = camRgb->getPreviewWidth() * camRgb->getPreviewHeight() * 3;

    // Warp preview frame 1
    auto warp1 = pipeline.create<dai::node::Warp>();
    // Create a custom warp mesh
    dai::Point2f tl(20, 20);
    dai::Point2f tr(460, 20);
    dai::Point2f ml(100, 250);
    dai::Point2f mr(400, 250);
    dai::Point2f bl(20, 460);
    dai::Point2f br(460, 460);
    warp1->setWarpMesh({tl, tr, ml, mr, bl, br}, 2, 3);
    constexpr std::tuple<int, int> WARP1_OUTPUT_FRAME_SIZE = {992, 500};
    warp1->setOutputSize(WARP1_OUTPUT_FRAME_SIZE);
    warp1->setMaxOutputFrameSize(std::get<0>(WARP1_OUTPUT_FRAME_SIZE) * std::get<1>(WARP1_OUTPUT_FRAME_SIZE) * 3);
    warp1->setInterpolation(dai::Interpolation::NEAREST_NEIGHBOR);
    warp1->setHwIds({1});

    camRgb->preview.link(warp1->inputImage);
    auto xout1 = pipeline.create<dai::node::XLinkOut>();
    xout1->setStreamName("out1");
    warp1->out.link(xout1->input);

    // Warp preview frame 2
    auto warp2 = pipeline.create<dai::node::Warp>();
    // Create a custom warp mesh
    // clang-format off
    std::vector<dai::Point2f> mesh2 = {
        {20, 20}, {250, 100}, {460, 20},
        {100,250}, {250, 250}, {400, 250},
        {20, 480}, {250,400}, {460,480}
    };
    // clang-format on
    warp2->setWarpMesh(mesh2, 3, 3);
    warp2->setMaxOutputFrameSize(maxFrameSize);
    warp2->setInterpolation(dai::Interpolation::BICUBIC);
    warp2->setHwIds({2});

    camRgb->preview.link(warp2->inputImage);
    auto xout2 = pipeline.create<dai::node::XLinkOut>();
    xout2->setStreamName("out2");
    warp2->out.link(xout2->input);

    dai::Device device(pipeline);
    auto q1 = device.getOutputQueue("out1", 8, false);
    auto q2 = device.getOutputQueue("out2", 8, false);
    while(true) {
        auto in1 = q1->get<dai::ImgFrame>();
        if(in1) {
            cv::imshow("Warped preview 1", in1->getCvFrame());
        }
        auto in2 = q2->get<dai::ImgFrame>();
        if(in2) {
            cv::imshow("Warped preview 2", in2->getCvFrame());
        }
        int key = cv::waitKey(1);
        if(key == 'q' || key == 'Q') return 0;
    }
    return 0;
}
```

## Pipeline

### examples/warp_mesh.pipeline.json

```json
{"pipeline": {"connections": [{"node1Id": 1, "node1Output": "out", "node1OutputGroup": "", "node2Id": 4, "node2Input": "in", "node2InputGroup": ""}, {"node1Id": 0, "node1Output": "0", "node1OutputGroup": "dynamicOutputs", "node2Id": 2, "node2Input": "in", "node2InputGroup": ""}, {"node1Id": 0, "node1Output": "0", "node1OutputGroup": "dynamicOutputs", "node2Id": 1, "node2Input": "inputImage", "node2InputGroup": ""}], "globalProperties": {"calibData": null, "cameraTuningBlobSize": null, "cameraTuningBlobUri": "", "leonCssFrequencyHz": 700000000.0, "leonMssFrequencyHz": 700000000.0, "pipelineName": null, "pipelineVersion": null, "sippBufferSize": 18432, "sippDmaBufferSize": 16384, "xlinkChunkSize": -1}, "nodes": [[4, {"alias": "", "id": 4, "ioInfo": [[["", "in"], {"blocking": true, "group": "", "id": 7, "name": "in", "queueSize": 3, "type": 3, "waitForMessage": false}]], "logLevel": 3, "name": "XLinkOut", "parentId": -1, "properties": {"maxFpsLimit": -1.0, "metadataOnly": false, "streamName": "__x_1_out"}}], [2, {"alias": "", "id": 2, "ioInfo": [[["", "in"], {"blocking": true, "group": "", "id": 6, "name": "in", "queueSize": 3, "type": 3, "waitForMessage": false}]], "logLevel": 3, "name": "XLinkOut", "parentId": -1, "properties": {"maxFpsLimit": -1.0, "metadataOnly": false, "streamName": "__x_0_0"}}], [1, {"alias": "", "id": 1, "ioInfo": [[["", "out"], {"blocking": false, "group": "", "id": 5, "name": "out", "queueSize": 8, "type": 0, "waitForMessage": false}], [["", "inputImage"], {"blocking": true, "group": "", "id": 4, "name": "inputImage", "queueSize": 3, "type": 3, "waitForMessage": false}]], "logLevel": 3, "name": "Warp", "parentId": -1, "properties": {"interpolation": 0, "meshHeight": 3, "meshUri": "asset:mesh", "meshWidth": 3, "numFramesPool": 4, "outputFrameSize": 921600, "outputHeight": 480, "outputWidth": 640, "warpHwIds": []}}], [0, {"alias": "", "id": 0, "ioInfo": [[["dynamicOutputs", "0"], {"blocking": false, "group": "dynamicOutputs", "id": 3, "name": "0", "queueSize": 8, "type": 0, "waitForMessage": false}], [["", "raw"], {"blocking": false, "group": "", "id": 2, "name": "raw", "queueSize": 8, "type": 0, "waitForMessage": false}], [["", "mockIsp"], {"blocking": true, "group": "", "id": 1, "name": "mockIsp", "queueSize": 8, "type": 3, "waitForMessage": false}], [["", "inputControl"], {"blocking": true, "group": "", "id": 0, "name": "inputControl", "queueSize": 3, "type": 3, "waitForMessage": false}]], "logLevel": 3, "name": "Camera", "parentId": -1, "properties": {"boardSocket": 0, "cameraName": "", "fps": -1.0, "imageOrientation": -1, "initialControl": {"aeLockMode": false, "aeMaxExposureTimeUs": 100663297, "aeRegion": {"height": 0, "priority": 3429757504, "width": 0, "x": 4163, "y": 1}, "afRegion": {"height": 0, "priority": 0, "width": 0, "x": 23127, "y": 0}, "antiBandingMode": 109, "autoFocusMode": 3, "awbLockMode": false, "awbMode": 136, "brightness": -105, "captureIntent": 204, "chromaDenoise": 0, "cmdMask": 0, "contrast": -33, "controlMode": 87, "effectMode": 90, "enableHdr": false, "expCompensation": 39, "expManual": {"exposureTimeUs": 23127, "frameDurationUs": 23127, "sensitivityIso": 3429757612}, "frameSyncMode": 0, "lensPosAutoInfinity": 192, "lensPosAutoMacro": 242, "lensPosition": 0, "lensPositionRaw": 0.0, "lowPowerNumFramesBurst": 0, "lowPowerNumFramesDiscard": 0, "lumaDenoise": 0, "miscControls": [], "saturation": -34, "sceneMode": 242, "sharpness": 0, "strobeConfig": {"activeLevel": 232, "enable": 0, "gpioNumber": -8}, "strobeTimings": {"durationUs": 16, "exposureBeginOffsetUs": 23127, "exposureEndOffsetUs": 17}, "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": 8}], "resolutionHeight": -1, "resolutionWidth": -1}}]]}}
```

### Need assistance?

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