DepthAI v2 → v3 Porting Guide
June 5, 2025 · View on GitHub
This document describes the changes between the v2 and v3 APIs of DepthAI and how to migrate existing code.
ℹ️ Tip: Copy this documents raw Markdown (not the rendered HTML) and paste it into your preferred large-language-model (LLM) alongside the code you want to port. The model usually generates a solid starting point for porting your code.
What's new in the v3 API
-
No more explicit XLink nodes – the XLink “bridges” are created automatically.
-
Host nodes – nodes that run on the host machine now work cleanly with device‑side nodes.
-
Custom host nodes – users can create custom nodes that run on the host machine
- Both
ThreadedHostNodeandHostNodeare supported. ThreadedHostNodeworks similarly toScriptNode; the user specifies arunfunction that executes in a separate thread.HostNodeexposes an input mapinputswhose entries are implicitly synced.- Available in both Python and C++.
- Both
-
Record‑and‑replay nodes.
-
Pipelinenow has a live device that can be queried during pipeline creation. -
Support for the new Model Zoo.
-
ImageManiphas a refreshed API with better‑defined behaviour. -
ColorCameraandMonoCameraare deprecated in favour of the newCameranode.
Minimal changes required
- Remove the explicit creation of
dai.Device(unless you intentionally pass a live device handle via the pipeline constructor – a rare edge case). - Remove explicit XLink nodes.
- Replace
dai.Device(pipeline)withpipeline.start(). - Replace any
.getOutputQueue()calls withoutput.createOutputQueue(). - Replace any
.getInputQueue()calls withinput.createInputQueue().
Quick port: simple RGB stream example
Below, the old v2 code is commented with # ORIG and the new code with # NEW.
#!/usr/bin/env python3
import cv2
import depthai as dai
# Create pipeline
pipeline = dai.Pipeline()
# Define source and output
camRgb = pipeline.create(dai.node.ColorCamera)
# ORIG – explicit XLink removed in v3
# xoutVideo = pipeline.create(dai.node.XLinkOut)
# xoutVideo.setStreamName("video")
# Properties
camRgb.setBoardSocket(dai.CameraBoardSocket.CAM_A)
camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P)
camRgb.setVideoSize(1920, 1080)
# Linking
# ORIG
# camRgb.video.link(xoutVideo.input)
# NEW – output queue straight from the node
videoQueue = camRgb.video.createOutputQueue()
# ORIG – entire `with dai.Device` block removed
# with dai.Device(pipeline) as device:
# video = device.getOutputQueue(name="video", maxSize=1, blocking=False)
# while True:
# NEW – start the pipeline
pipeline.start()
while pipeline.isRunning():
videoIn = videoQueue.get() # blocking
cv2.imshow("video", videoIn.getCvFrame())
if cv2.waitKey(1) == ord('q'):
break
This runs on RVC2 devices. Note that ColorCamera/MonoCamera nodes are deprecated on RVC4; see the next section for using Camera instead.
Porting ColorCamera / MonoCamera usage to Camera
The new Camera node can expose as many outputs as you request.
camRgb = pipeline.create(dai.node.ColorCamera)
camRgb.setPreviewSize(300, 300)
camRgb.setInterleaved(False)
camRgb.setColorOrder(dai.ColorCameraProperties.ColorOrder.RGB)
outputQueue = camRgb.preview.createOutputQueue()
turns into
camRgb = pipeline.create(dai.node.Camera).build() # don’t forget .build()
cameraOutput = camRgb.requestOutput((300, 300), type=dai.ImgFrame.Type.RGB888p) # replaces .preview
outputQueue = cameraOutput.createOutputQueue()
Request multiple outputs simply by calling requestOutput again. For full‑resolution use‑cases that previously used .isp, call requestFullResolutionOutput() instead.
For former MonoCamera pipelines, replace the .out output with requestOutput, e.g.
mono = pipeline.create(dai.node.Camera).build()
monoOut = mono.requestOutput((1280, 720), type=dai.ImgFrame.Type.GRAY8)
Porting the old ImageManip to the new API
The new API tracks every transformation in sequence and separates how the final image is resized. See the official documentation for full details.
v2 example
#!/usr/bin/env python3
import cv2
import depthai as dai
# Create pipeline
pipeline = dai.Pipeline()
camRgb = pipeline.create(dai.node.ColorCamera)
camRgb.setPreviewSize(1000, 500)
camRgb.setInterleaved(False)
maxFrameSize = camRgb.getPreviewHeight() * camRgb.getPreviewWidth() * 3
# In this example we use 2 imageManips for splitting the original 1000x500
# preview frame into 2 500x500 frames
manip1 = pipeline.create(dai.node.ImageManip)
manip1.initialConfig.setCropRect(0, 0, 0.5, 1)
manip1.setMaxOutputFrameSize(maxFrameSize)
camRgb.preview.link(manip1.inputImage)
manip2 = pipeline.create(dai.node.ImageManip)
manip2.initialConfig.setCropRect(0.5, 0, 1, 1)
manip2.setMaxOutputFrameSize(maxFrameSize)
camRgb.preview.link(manip2.inputImage)
xout1 = pipeline.create(dai.node.XLinkOut)
xout1.setStreamName('out1')
manip1.out.link(xout1.input)
xout2 = pipeline.create(dai.node.XLinkOut)
xout2.setStreamName('out2')
manip2.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=4, blocking=False)
q2 = device.getOutputQueue(name="out2", maxSize=4, blocking=False)
while True:
if q1.has():
cv2.imshow("Tile 1", q1.get().getCvFrame())
if q2.has():
cv2.imshow("Tile 2", q2.get().getCvFrame())
if cv2.waitKey(1) == ord('q'):
break
v3 equivalent:
#!/usr/bin/env python3
import cv2
import depthai as dai
# Create pipeline
pipeline = dai.Pipeline()
camRgb = pipeline.create(dai.node.Camera).build()
preview = camRgb.requestOutput((1000, 500), type=dai.ImgFrame.Type.RGB888p)
# In this example we use 2 imageManips for splitting the original 1000x500
# preview frame into 2 500x500 frames
manip1 = pipeline.create(dai.node.ImageManip)
manip1.initialConfig.addCrop(0, 0, 500, 500)
preview.link(manip1.inputImage)
manip2 = pipeline.create(dai.node.ImageManip)
manip2.initialConfig.addCrop(500, 0, 500, 500)
preview.link(manip2.inputImage)
q1 = manip1.out.createOutputQueue()
q2 = manip2.out.createOutputQueue()
pipeline.start()
with pipeline:
while pipeline.isRunning():
if q1.has():
cv2.imshow("Tile 1", q1.get().getCvFrame())
if q2.has():
cv2.imshow("Tile 2", q2.get().getCvFrame())
if cv2.waitKey(1) == ord('q'):
break