DepthAI Tutorials
DepthAI API References

ON THIS PAGE

  • Interactive Warp Mesh
  • Setup
  • Demo
  • Source code

Interactive Warp Mesh

This example shows usage of Warp node to warp the input image frame. It let's you interactively change the mesh points to warp the image. After changing the points, user has to press r to restart the pipeline and apply the changes.User-defined arguments:
  • --mesh_dims - Mesh dimensions (default: 4x4).
  • --resolution - Resolution of the input image (default: 512x512). Width must be divisible by 16.
  • --random - To generate random mesh points (disabled by default).
Originally developed by geaxgx.

Setup

Please run the install script to download all required dependencies. Please note that this script must be ran from git context, so you have to download the depthai-python repository first and then run the script
Command Line
1git clone https://github.com/luxonis/depthai-python.git
2cd depthai-python/examples
3python3 install_requirements.py
For additional information, please follow the installation guide.

Demo

Source code

Python
C++
Python
GitHub
1#!/usr/bin/env python3
2import cv2
3import depthai as dai
4import numpy as np
5import argparse
6import re
7import sys
8from random import randint
9
10parser = argparse.ArgumentParser()
11parser.add_argument("-m", "--mesh_dims", type=str, default="4x4", help="mesh dimensions widthxheight (default=%(default)s)")
12parser.add_argument("-r", "--resolution", type=str, default="512x512", help="preview resolution (default=%(default)s)")
13parser.add_argument("-rnd", "--random", action="store_true", help="Generate random initial mesh")
14args = parser.parse_args()
15
16# mesh dimensions
17match = re.search(r'.*?(\d+)x(\d+).*', args.mesh_dims)
18if not match:
19    raise Exception(f"Mesh dimensions format incorrect '{args.resolution}'!")
20mesh_w = int(match.group(1))
21mesh_h = int(match.group(2))
22
23# Preview resolution
24match = re.search(r'.*?(\d+)x(\d+).*', args.resolution)
25if not match:
26    raise Exception(f"Resolution format incorrect '{args.resolution}'!")
27preview_w = int(match.group(1))
28preview_h = int(match.group(2))
29if preview_w % 16 != 0:
30    raise Exception(f"Preview width must be a multiple of 16!")
31
32# Create an initial mesh (optionally random) of dimension mesh_w x mesh_h
33first_point_x = int(preview_w / 10)
34between_points_x = int(4 * preview_w / (5 * (mesh_w - 1)))
35first_point_y = int(preview_h / 10)
36between_points_y = int(4 * preview_h / (5 * (mesh_h - 1)))
37if args.random:
38    max_rnd_x = int(between_points_x / 4)
39    max_rnd_y = int(between_points_y / 4)
40mesh = []
41for i in range(mesh_h):
42    for j in range(mesh_w):
43        x = first_point_x + j * between_points_x
44        y = first_point_y + i * between_points_y
45        if args.random:
46            rnd_x = randint(-max_rnd_x, max_rnd_x)
47            if x + rnd_x > 0 and x + rnd_x < preview_w:
48                x += rnd_x
49            rnd_y = randint(-max_rnd_y, max_rnd_y)
50            if y + rnd_y > 0 and y + rnd_y < preview_h:
51                y += rnd_y
52        mesh.append((x, y))
53
54def create_pipeline(mesh):
55    print(mesh)
56    # Create pipeline
57    pipeline = dai.Pipeline()
58
59    camRgb = pipeline.create(dai.node.ColorCamera)
60    camRgb.setPreviewSize(preview_w, preview_h)
61    camRgb.setInterleaved(False)
62    width = camRgb.getPreviewWidth()
63    height = camRgb.getPreviewHeight()
64
65    # Output source
66    xout_source = pipeline.create(dai.node.XLinkOut)
67    xout_source.setStreamName('source')
68    camRgb.preview.link(xout_source.input)
69    # Warp source frame
70    warp = pipeline.create(dai.node.Warp)
71    warp.setWarpMesh(mesh, mesh_w, mesh_h)
72    warp.setOutputSize(width, height)
73    warp.setMaxOutputFrameSize(width * height * 3)
74    camRgb.preview.link(warp.inputImage)
75
76    warp.setHwIds([1])
77    warp.setInterpolation(dai.Interpolation.NEAREST_NEIGHBOR)
78    # Output warped
79    xout_warped = pipeline.create(dai.node.XLinkOut)
80    xout_warped.setStreamName('warped')
81    warp.out.link(xout_warped.input)
82    return pipeline
83
84point_selected = None
85
86def mouse_callback(event, x, y, flags, param):
87    global mesh, point_selected, mesh_changed
88    if event == cv2.EVENT_LBUTTONDOWN:
89        if point_selected is None:
90            # Which point is selected ?
91            min_dist = 100
92
93            for i in range(len(mesh)):
94                dist = np.linalg.norm((x - mesh[i][0], y - mesh[i][1]))
95                if dist < 20 and dist < min_dist:
96                    min_dist = dist
97                    point_selected = i
98            if point_selected is not None:
99                mesh[point_selected] = (x, y)
100                mesh_changed = True
101
102    elif event == cv2.EVENT_LBUTTONUP:
103        point_selected = None
104    elif event == cv2.EVENT_MOUSEMOVE:
105        if point_selected is not None:
106            mesh[point_selected] = (x, y)
107            mesh_changed = True
108
109
110cv2.namedWindow("Source")
111cv2.setMouseCallback("Source", mouse_callback)
112
113running = True
114
115print("Use your mouse to modify the mesh by clicking/moving points of the mesh in the Source window")
116print("Then press 'r' key to restart the device/pipeline")
117while running:
118    pipeline = create_pipeline(mesh)
119    # Connect to device and start pipeline
120    with dai.Device(pipeline) as device:
121        print("Starting device")
122        # Output queue will be used to get the rgb frames from the output defined above
123        q_source = device.getOutputQueue(name="source", maxSize=4, blocking=False)
124        q_warped = device.getOutputQueue(name="warped", maxSize=4, blocking=False)
125
126        restart_device = False
127        mesh_changed = False
128        while not restart_device:
129            in0 = q_source.get()
130            if in0 is not None:
131                source = in0.getCvFrame()
132                color = (0, 0,255) if mesh_changed else (0,255,0)
133                for i in range(len(mesh)):
134                    cv2.circle(source, (mesh[i][0], mesh[i][1]), 4, color, -1)
135                    if i % mesh_w != mesh_w -1:
136                        cv2.line(source, (mesh[i][0], mesh[i][1]), (mesh[i+1][0], mesh[i+1][1]), color, 2)
137                    if i + mesh_w < len(mesh):
138                        cv2.line(source, (mesh[i][0], mesh[i][1]), (mesh[i+mesh_w][0], mesh[i+mesh_w][1]), color, 2)
139                cv2.imshow("Source", source)
140
141            in1 = q_warped.get()
142            if in1 is not None:
143                cv2.imshow("Warped", in1.getCvFrame())
144
145            key = cv2.waitKey(1)
146            if key == ord('r'): # Restart the device if mesh has changed
147                if mesh_changed:
148                    print("Restart requested...")
149                    mesh_changed = False
150                    restart_device = True
151            elif key == 27 or key == ord('q'): # Exit
152                running = False
153                break

Need assistance?

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