# Neural Network Multi-input

Utilizes [NeuralNetwork](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/neural_network.md) node to run a NN
model which concatenates two input images and runs "inference" on the combined image.

One of the input images is a static image sent from the host at startup (and it re-used for every frame), the other one is a live
frame from the camera.

## Demo

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

## Pipeline

## Source code

#### Python

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

# Get the absolute path of the current script's directory
script_dir = Path(__file__).resolve().parent
examplesRoot = (script_dir / Path('../')).resolve()  # This resolves the parent directory correctly
models = examplesRoot / 'models'
tagImage = models / 'lenna.png'

# Decode the image using OpenCV
lenaImage = cv2.imread(str(tagImage.resolve()))
lenaImage = cv2.resize(lenaImage, (256, 256))
lenaImage = np.array(lenaImage)

device = dai.Device()
platform = device.getPlatform()
if(platform == dai.Platform.RVC2):
    daiType = dai.ImgFrame.Type.RGB888p
elif(platform == dai.Platform.RVC4):
    daiType = dai.ImgFrame.Type.RGB888i
else:
    raise RuntimeError("Platform not supported")

daiLenaImage = dai.ImgFrame()

daiLenaImage.setCvFrame(lenaImage, daiType)

with dai.Pipeline(device) as pipeline:
    model = dai.NNModelDescription("depthai-test-models/simple-concatenate-model")
    model.platform = platform.name

    nnArchive = dai.NNArchive(dai.getModelFromZoo(model))
    cam = pipeline.create(dai.node.Camera).build()
    camOut = cam.requestOutput((256,256), daiType)

    neuralNetwork = pipeline.create(dai.node.NeuralNetwork)
    neuralNetwork.setNNArchive(nnArchive)
    camOut.link(neuralNetwork.inputs["image1"])
    lennaInputQueue = neuralNetwork.inputs["image2"].createInputQueue()
    # No need to send the second image everytime
    neuralNetwork.inputs["image2"].setReusePreviousMessage(True)
    qNNData = neuralNetwork.out.createOutputQueue()
    pipeline.start()
    lennaInputQueue.send(daiLenaImage)
    while pipeline.isRunning():
        inNNData: dai.NNData = qNNData.get()
        tensor : np.ndarray = inNNData.getFirstTensor()
        # Drop the first dimension
        tensor = tensor.squeeze().astype(np.uint8)
        # Check the shape - in case 3 is not the last dimension, permute it to the last
        if tensor.shape[0] == 3:
            tensor = np.transpose(tensor, (1, 2, 0))
        print(tensor.shape)
        cv2.imshow("Combined", tensor)
        key = cv2.waitKey(1)
        if key == ord('q'):
            break
```

#### C++

```cpp
#include <atomic>
#include <csignal>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <xtensor/containers/xarray.hpp>

#include "depthai/depthai.hpp"
#include "depthai/modelzoo/Zoo.hpp"

std::atomic<bool> quitEvent(false);

void signalHandler(int) {
    quitEvent = true;
}

int main() {
    signal(SIGTERM, signalHandler);
    signal(SIGINT, signalHandler);

    // Decode the image using OpenCV
    cv::Mat lenaImage = cv::imread(LENNA_PATH);
    cv::resize(lenaImage, lenaImage, cv::Size(256, 256));

    // Create pipeline
    dai::Pipeline pipeline;

    // Create model description
    dai::NNModelDescription model;
    model.model = "depthai-test-models/simple-concatenate-model";
    model.platform = pipeline.getDefaultDevice()->getPlatformAsString();
    dai::NNArchive archive(dai::getModelFromZoo(model));

    dai::ImgFrame::Type daiType;
    if(pipeline.getDefaultDevice()->getPlatform() == dai::Platform::RVC2) {
        daiType = dai::ImgFrame::Type::RGB888p;
    } else {
        daiType = dai::ImgFrame::Type::RGB888i;
    }

    // Create and set up nodes
    auto cam = pipeline.create<dai::node::Camera>()->build();
    auto camOut = cam->requestOutput(std::make_pair(256, 256), daiType);

    auto neuralNetwork = pipeline.create<dai::node::NeuralNetwork>();
    neuralNetwork->setNNArchive(archive);
    camOut->link(neuralNetwork->inputs["image1"]);

    auto lennaInputQueue = neuralNetwork->inputs["image2"].createInputQueue();
    // No need to send the second image everytime
    neuralNetwork->inputs["image2"].setReusePreviousMessage(true);

    auto qNNData = neuralNetwork->out.createOutputQueue();

    // Stt pipeline
    pipeline.start();
    // Create and set the image frame
    auto daiLenaImage = std::make_shared<dai::ImgFrame>();
    daiLenaImage->setCvFrame(lenaImage, daiType);
    lennaInputQueue->send(daiLenaImage);

    // Main loop
    while(pipeline.isRunning() && !quitEvent) {
        auto inNNData = qNNData->get<dai::NNData>();
        auto tensor = inNNData->getFirstTensor<float>();
        auto tensor_uint8 = xt::eval(xt::squeeze(xt::cast<uint8_t>(tensor), 0));

        cv::Mat output;
        if(tensor_uint8.shape()[0] == 3) {
            tensor_uint8 = xt::transpose(tensor_uint8, {1, 2, 0});
        }
        output = cv::Mat(tensor_uint8.shape()[0], tensor_uint8.shape()[1], CV_8UC3);
        std::memcpy(output.data, tensor_uint8.data(), tensor_uint8.size());

        cv::imshow("Combined", output);

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

    pipeline.stop();
    pipeline.wait();

    return 0;
}
```

### Need assistance?

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