# DepthAI V3 迁移指南

本文档描述了DepthAI v2和v3 API之间的变化，以及如何迁移现有代码。

## v3 API 的新特性

 * 不再需要显式的XLink节点 - XLink“桥接”会自动创建。

 * 主机节点 - 在主机上运行的节点现在能与设备端节点无缝协作。

 * 自定义主机节点 - 用户可以创建在主机上运行的自定义节点
   
   * 支持 ThreadedHostNode 和 HostNode。
   * ThreadedHostNode 的工作方式与 ScriptNode 类似；用户指定一个 run 函数，该函数在单独的线程中执行。
   * HostNode 暴露一个输入映射 inputs，其条目会隐式同步。
   * 在 Python 和 C++ 中均可用。

 * 录制与回放节点。

 * Pipeline 现在拥有一个在管道创建期间可查询的活动设备。

 * 支持新的 模型库。

 * ImageManip 拥有刷新后的 API，行为定义更清晰。

 * ColorCamera 和 MonoCamera 已被弃用，推荐使用新的 Camera 节点。

## 最小必要更改

 * 移除显式创建 dai.Device（除非你故意通过管道构造函数传递活动设备句柄——这是一种罕见的边界情况）。
 * 移除显式的 XLink 节点。
 * 将 dai.Device(pipeline) 替换为 pipeline.start()。
 * 将所有 .getOutputQueue() 调用替换为 output.createOutputQueue()。
 * 将所有 .getInputQueue() 调用替换为 input.createInputQueue()。

## 快速迁移：简单的 RGB 流示例

下方，旧版 v2 代码以 # ORIG 注释，新版代码以 # NEW 注释。

```python
#!/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
```

此示例在RVC2设备上运行。注意 ColorCamera/MonoCamera 节点在RVC4上已被弃用；请参见下一节使用 Camera 替代。

## 将 ColorCamera / MonoCamera 的使用迁移到 Camera

新的 Camera 节点可以根据需要暴露任意多个输出。

```python
camRgb = pipeline.create(dai.node.ColorCamera)
camRgb.setPreviewSize(300, 300)
camRgb.setInterleaved(False)
camRgb.setColorOrder(dai.ColorCameraProperties.ColorOrder.RGB)
outputQueue = camRgb.preview.createOutputQueue()
```

转化为

```python
camRgb = pipeline.create(dai.node.Camera).build()  # 不要忘记 .build()
cameraOutput = camRgb.requestOutput((300, 300), type=dai.ImgFrame.Type.RGB888p)  # 替换 .preview
outputQueue = cameraOutput.createOutputQueue()
```

只需再次调用 requestOutput 即可请求多个输出。对于之前使用 .isp 的全分辨率用例，请改用 requestFullResolutionOutput()。

对于之前的 MonoCamera 管道，将 .out 输出替换为 requestOutput，例如

```python
mono = pipeline.create(dai.node.Camera).build()
monoOut = mono.requestOutput((1280, 720), type=dai.ImgFrame.Type.GRAY8)
```

## 将旧的 ImageManip 迁移到新 API

新 API
按顺序跟踪每次变换，并将最终图像的缩放方式分离出来。有关完整详情，请参阅[官方文档](https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes/image_manip.md)。

### v2 示例

```python
#!/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 等效代码：

```python
#!/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
```
