DepthAI
Software Stack

ON THIS PAGE

  • Pipeline
  • Source code

ImageManip remap

Supported on:RVC2RVC4
This examples shows an application that processes a camera stream through two image manipulation nodes with 90-degree rotations and different output sizes, displaying the original and manipulated frames with synchronized rotated rectangles, using DepthAI's pipeline and transformation handling.This example requires the DepthAI v3 API, see installation instructions.

Pipeline

Source code

Python

Python
GitHub
1import depthai as dai
2import cv2
3import numpy as np
4
5def draw_rotated_rectangle(frame, center, size, angle, color, thickness=2):
6    """
7    Draws a rotated rectangle on the given frame.
8
9    Args:
10        frame (numpy.ndarray): The image/frame to draw on.
11        center (tuple): The (x, y) coordinates of the rectangle's center.
12        size (tuple): The (width, height) of the rectangle.
13        angle (float): The rotation angle of the rectangle in degrees (counter-clockwise).
14        color (tuple): The color of the rectangle in BGR format (e.g., (0, 255, 0) for green).
15        thickness (int): The thickness of the rectangle edges. Default is 2.
16    """
17    # Create a rotated rectangle
18    rect = ((center[0], center[1]), (size[0], size[1]), angle)
19
20    # Get the four vertices of the rotated rectangle
21    box = cv2.boxPoints(rect)
22    box = np.intp(box)  # Convert to integer coordinates
23
24    # Draw the rectangle on the frame
25    cv2.polylines(frame, [box], isClosed=True, color=color, thickness=thickness)
26
27with dai.Pipeline() as pipeline:
28    cam = pipeline.create(dai.node.Camera).build()
29    camOut = cam.requestOutput((640, 400), dai.ImgFrame.Type.BGR888i, fps = 30.0)
30    manip1 = pipeline.create(dai.node.ImageManip)
31    manip2 = pipeline.create(dai.node.ImageManip)
32
33    # GPU is not available on RVC2 and some RVC4 devices
34    backend = dai.node.ImageManip.Backend.GPU if pipeline.getDefaultDevice().hasGPU() else dai.node.ImageManip.Backend.CPU
35    manip1.setBackend(backend)
36    manip2.setBackend(backend)
37
38    camOut.link(manip1.inputImage)
39    manip1.out.link(manip2.inputImage)
40
41    manip1.initialConfig.addRotateDeg(90)
42    manip1.initialConfig.setOutputSize(200, 320)
43
44    manip2.initialConfig.addRotateDeg(90)
45    manip2.initialConfig.setOutputSize(320, 200)
46
47    outQcam = camOut.createOutputQueue()
48    outQ1 = manip1.out.createOutputQueue()
49    outQ2 = manip2.out.createOutputQueue()
50
51    pipeline.start()
52
53    while True:
54        camFrame: dai.ImgFrame = outQcam.get()
55        manip1Frame: dai.ImgFrame = outQ1.get()
56        manip2Frame: dai.ImgFrame = outQ2.get()
57
58        camCv = camFrame.getCvFrame()
59        manip1Cv = manip1Frame.getCvFrame()
60        manip2Cv = manip2Frame.getCvFrame()
61
62        rect2 = dai.RotatedRect(dai.Rect(dai.Point2f(100, 100), dai.Point2f(200, 150)), 0)
63        rect1 = manip2Frame.getTransformation().remapRectTo(manip1Frame.getTransformation(), rect2)
64        rectcam = manip1Frame.getTransformation().remapRectTo(camFrame.getTransformation(), rect1)
65
66        draw_rotated_rectangle(manip2Cv, (rect2.center.x, rect2.center.y), (rect2.size.width, rect2.size.height), rect2.angle, (255, 0, 0))
67        draw_rotated_rectangle(manip1Cv, (rect1.center.x, rect1.center.y), (rect1.size.width, rect1.size.height), rect1.angle, (255, 0, 0))
68        draw_rotated_rectangle(camCv, (rectcam.center.x, rectcam.center.y), (rectcam.size.width, rectcam.size.height), rectcam.angle, (255, 0, 0))
69
70        cv2.imshow("cam", camCv)
71        cv2.imshow("manip1", manip1Cv)
72        cv2.imshow("manip2", manip2Cv)
73        if cv2.waitKey(1) == ord('q'):
74            break

C++

1#include <atomic>
2#include <csignal>
3#include <iostream>
4#include <memory>
5#include <opencv2/opencv.hpp>
6
7#include "depthai/depthai.hpp"
8
9// Global flag for graceful shutdown
10std::atomic<bool> quitEvent(false);
11
12// Signal handler
13void signalHandler(int signum) {
14    quitEvent = true;
15}
16
17// Helper function to draw rotated rectangle
18void draw_rotated_rectangle(cv::Mat& frame, const cv::Point2f& center, const cv::Size2f& size, float angle, const cv::Scalar& color, int thickness = 2) {
19    // Create a rotated rectangle
20    cv::RotatedRect rect(center, size, angle);
21
22    // Get the four vertices of the rotated rectangle
23    cv::Point2f vertices[4];
24    rect.points(vertices);
25
26    // Convert to integer points for drawing
27    std::vector<cv::Point> points;
28    for(int i = 0; i < 4; i++) {
29        points.push_back(cv::Point(static_cast<int>(vertices[i].x), static_cast<int>(vertices[i].y)));
30    }
31
32    // Draw the rectangle on the frame
33    cv::polylines(frame, std::vector<std::vector<cv::Point>>{points}, true, color, thickness);
34}
35
36int main() {
37    // Set up signal handlers
38    signal(SIGTERM, signalHandler);
39    signal(SIGINT, signalHandler);
40
41    try {
42        // Create pipeline
43        dai::Pipeline pipeline;
44
45        // Create nodes
46        auto cam = pipeline.create<dai::node::Camera>();
47        cam->build();
48
49        auto manip1 = pipeline.create<dai::node::ImageManip>();
50        auto manip2 = pipeline.create<dai::node::ImageManip>();
51
52        // GPU is not available on RVC2 and some RVC4 devices
53        auto backend = pipeline.getDefaultDevice()->hasGPU() ? dai::node::ImageManip::Backend::GPU : dai::node::ImageManip::Backend::CPU;
54        manip1->setBackend(backend);
55        manip2->setBackend(backend);
56
57        // Configure camera output
58        auto* camOut = cam->requestOutput(std::make_pair(640, 400), dai::ImgFrame::Type::BGR888i, dai::ImgResizeMode::LETTERBOX, 20, 20);
59
60        // Configure image manipulators
61        manip1->initialConfig->addRotateDeg(90);
62        manip1->initialConfig->setOutputSize(200, 320);
63
64        manip2->initialConfig->addRotateDeg(90);
65        manip2->initialConfig->setOutputSize(320, 200);
66
67        // Linking
68        camOut->link(manip1->inputImage);
69        manip1->out.link(manip2->inputImage);
70
71        // Create output queues
72        auto outQcam = camOut->createOutputQueue();
73        auto outQ1 = manip1->out.createOutputQueue();
74        auto outQ2 = manip2->out.createOutputQueue();
75
76        // Start pipeline
77        pipeline.start();
78
79        // Main loop
80        while(!quitEvent) {
81            // Get frames
82            auto camFrame = outQcam->get<dai::ImgFrame>();
83            auto manip1Frame = outQ1->get<dai::ImgFrame>();
84            auto manip2Frame = outQ2->get<dai::ImgFrame>();
85
86            // Convert to OpenCV format
87            cv::Mat camCv = camFrame->getCvFrame();
88            cv::Mat manip1Cv = manip1Frame->getCvFrame();
89            cv::Mat manip2Cv = manip2Frame->getCvFrame();
90
91            // Create and remap rectangles
92            dai::RotatedRect rect2(dai::Rect(dai::Point2f(100, 100), dai::Point2f(200, 150)), 0);
93            auto rect1 = manip2Frame->transformation.remapRectTo(manip1Frame->transformation, rect2);
94            auto rectcam = manip1Frame->transformation.remapRectTo(camFrame->transformation, rect1);
95
96            // Draw rectangles
97            draw_rotated_rectangle(
98                manip2Cv, cv::Point2f(rect2.center.x, rect2.center.y), cv::Size2f(rect2.size.width, rect2.size.height), rect2.angle, cv::Scalar(255, 0, 0));
99
100            draw_rotated_rectangle(
101                manip1Cv, cv::Point2f(rect1.center.x, rect1.center.y), cv::Size2f(rect1.size.width, rect1.size.height), rect1.angle, cv::Scalar(255, 0, 0));
102
103            draw_rotated_rectangle(camCv,
104                                   cv::Point2f(rectcam.center.x, rectcam.center.y),
105                                   cv::Size2f(rectcam.size.width, rectcam.size.height),
106                                   rectcam.angle,
107                                   cv::Scalar(255, 0, 0));
108
109            // Display frames
110            cv::imshow("cam", camCv);
111            cv::imshow("manip1", manip1Cv);
112            cv::imshow("manip2", manip2Cv);
113
114            // Check for quit key
115            if(cv::waitKey(1) == 'q') {
116                break;
117            }
118        }
119
120        // Cleanup
121        pipeline.stop();
122        pipeline.wait();
123
124    } catch(const std::exception& e) {
125        std::cerr << "Error: " << e.what() << std::endl;
126        return 1;
127    }
128
129    return 0;
130}

Need assistance?

Head over to Discussion Forum for technical support or any other questions you might have.