- 过滤的点云 — 仅有效点(z > 0),输出以米为单位。
- 有序点云 — 保留所有
width × height的点,输出以毫米为单位。 - 相机到相机变换 — 使用
setTargetCoordinateSystem(CameraBoardSocket)将点云变换到另一个相机的坐标系。 - 自定义 4×4 变换 — 通过
setTransformationMatrix应用任意旋转矩阵,同时输出透传深度。 - 彩色点云 — 链接对齐的 RGB 输入以生成带有颜色的点。
源代码
Python
PythonGitHub
1#!/usr/bin/env python3
2"""
3PointCloud Node Showcase
4
5Demonstrates filtered/organized output, camera-to-camera transforms,
6housing coordinate system transforms, and custom 4x4 matrix transforms.
7
8See examples/cpp/PointCloud/README.md for full documentation.
9"""
10
11import time
12import depthai as dai
13
14
15# ---------------------------------------------------------------------------
16# Print helpers
17# ---------------------------------------------------------------------------
18def printHeader(title: str) -> None:
19 print("\n╔══════════════════════════════════════════════╗")
20 print(f"║ {title:<44s}║")
21 print("╚══════════════════════════════════════════════╝")
22
23
24def printPointCloudInfo(pcd: dai.PointCloudData, frameNum: int) -> None:
25 points = pcd.getPoints()
26 print(f"\n--- Frame {frameNum} ---")
27 print(f" Points : {len(points)}")
28 print(f" Width×Height : {pcd.getWidth()} × {pcd.getHeight()}")
29 print(f" Organized : {'yes' if pcd.isOrganized() else 'no'}")
30 print(f" Color : {'yes' if pcd.isColor() else 'no'}")
31 print(f" Bounding box :"
32 f" X [{pcd.getMinX()}, {pcd.getMaxX()}]"
33 f" Y [{pcd.getMinY()}, {pcd.getMaxY()}]"
34 f" Z [{pcd.getMinZ()}, {pcd.getMaxZ()}]")
35
36
37# ===========================================================================
38NUM_FRAMES = 3
39
40
41def main() -> None:
42 print("PointCloud Node Showcase")
43 print("========================")
44 print("Connecting to device...")
45
46 device = dai.Device()
47 print(f"Device: {device.getDeviceName()} (ID: {device.getDeviceId()})\n")
48
49 # ------------------------------------------------------------------
50 # Single pipeline – shared Camera + StereoDepth, multiple PointCloud
51 # nodes configured differently.
52 # ------------------------------------------------------------------
53 with dai.Pipeline(device) as pipeline:
54 colorSockets = device.getConnectedCameras(dai.CameraSensorType.COLOR)
55 colorSocket = colorSockets[0] if colorSockets else dai.CameraBoardSocket.CAM_A
56 color = pipeline.create(dai.node.Camera).build(colorSocket)
57 colorOut = color.requestOutput(
58 (640, 400), type=dai.ImgFrame.Type.RGB888i,
59 resizeMode=dai.ImgResizeMode.CROP, enableUndistortion=True,
60 )
61
62 depth = pipeline.create(dai.node.Depth).build(dai.node.Depth.Algorithm.AUTO, None, (640, 400))
63 depth.setAlignTo(colorOut)
64
65 # ── 1. Filtered point cloud (METER) ────
66 pcSparse = pipeline.create(dai.node.PointCloud)
67 pcSparse.setRunOnHost(True)
68 pcSparse.initialConfig.setLengthUnit(dai.LengthUnit.METER)
69 depth.depth.link(pcSparse.inputDepth)
70 qSparse = pcSparse.outputPointCloud.createOutputQueue(maxSize=4, blocking=False)
71
72 # ── 2. Organized point cloud (MILLIMETER) ───────
73 pcOrganized = pipeline.create(dai.node.PointCloud)
74 pcOrganized.setRunOnHost(True)
75 pcOrganized.initialConfig.setLengthUnit(dai.LengthUnit.MILLIMETER)
76 pcOrganized.initialConfig.setOrganized(True)
77 depth.depth.link(pcOrganized.inputDepth)
78 qOrganized = pcOrganized.outputPointCloud.createOutputQueue(maxSize=4, blocking=False)
79
80 # ── 3. Transform pointcloud into another device's coordinate system ───
81 pcCam = pipeline.create(dai.node.PointCloud)
82 pcCam.setRunOnHost(True)
83 pcCam.initialConfig.setLengthUnit(dai.LengthUnit.MILLIMETER)
84 pcCam.initialConfig.setTargetCoordinateSystem(dai.CameraBoardSocket.CAM_A)
85 # Or transform to a housing coordinate system instead, e.g.:
86 # pcCam.initialConfig.setTargetCoordinateSystem(dai.HousingCoordinateSystem.VESA_A)
87 depth.depth.link(pcCam.inputDepth)
88 qCam = pcCam.outputPointCloud.createOutputQueue(maxSize=4, blocking=False)
89
90 # ── 4. Custom 4×4 transform (90° Z rotation) + passthrough ──────
91 pcCustom = pipeline.create(dai.node.PointCloud)
92 pcCustom.setRunOnHost(True)
93 pcCustom.initialConfig.setLengthUnit(dai.LengthUnit.MILLIMETER)
94 pcCustom.useCPU()
95 transform = [
96 [0.0, -1.0, 0.0, 0.0],
97 [1.0, 0.0, 0.0, 0.0],
98 [0.0, 0.0, 1.0, 0.0],
99 [0.0, 0.0, 0.0, 1.0],
100 ]
101 pcCustom.initialConfig.setTransformationMatrix(transform)
102 depth.depth.link(pcCustom.inputDepth)
103 qCustom = pcCustom.outputPointCloud.createOutputQueue(maxSize=4, blocking=False)
104 qDepth = pcCustom.passthroughDepth.createOutputQueue(maxSize=4, blocking=False)
105
106 # ── 5. Colorized point cloud (aligned RGB from color camera) ─────
107 pcColorized = pipeline.create(dai.node.PointCloud)
108 pcColorized.setRunOnHost(True)
109 pcColorized.initialConfig.setLengthUnit(dai.LengthUnit.METER)
110 depth.depth.link(pcColorized.inputDepth)
111 colorOut.link(pcColorized.inputColor)
112 qColorized = pcColorized.outputPointCloud.createOutputQueue(maxSize=4, blocking=False)
113
114 # Note: Housing coordinate system transform is also available, e.g.:
115 # pc.initialConfig.setTargetCoordinateSystem(dai.HousingCoordinateSystem.VESA_A)
116 # See the docstring at the top of this file for all available
117 # CameraBoardSocket and HousingCoordinateSystem values.
118
119 sparseFrames = []
120 organizedFrames = []
121 camFrames = []
122 customFrames = []
123 depthFrames = []
124 colorizedFrames = []
125
126 pipeline.start()
127
128 # Wait for auto-exposure to settle and stereo depth to stabilize
129 print("Waiting for auto-exposure to settle...")
130 time.sleep(1)
131
132 # Drain stale frames that arrived during warm-up
133 qSparse.tryGetAll()
134 qOrganized.tryGetAll()
135 qCam.tryGetAll()
136 qCustom.tryGetAll()
137 qDepth.tryGetAll()
138 qColorized.tryGetAll()
139
140 for _ in range(NUM_FRAMES):
141 sparseFrames.append(qSparse.get())
142 organizedFrames.append(qOrganized.get())
143 camFrames.append(qCam.get())
144 customFrames.append(qCustom.get())
145 depthFrames.append(qDepth.get())
146 colorizedFrames.append(qColorized.get())
147
148 # ------------------------------------------------------------------
149 # Display results grouped by feature
150 # ------------------------------------------------------------------
151
152 # 1 ── Sparse point cloud
153 printHeader("1. Basic sparse point cloud")
154 print(" Config: METER")
155 for i, pcd in enumerate(sparseFrames):
156 printPointCloudInfo(pcd, i)
157
158 # 2 ── Organized point cloud
159 printHeader("2. Organized point cloud")
160 print(" Config: MILLIMETER, initialConfig.setOrganized(True)")
161 for i, pcd in enumerate(organizedFrames):
162 printPointCloudInfo(pcd, i)
163
164 # 3 ── Transform pointcloud into another device's coordinate system
165 printHeader("3. Camera-to-camera transform")
166 print(" Config: setTargetCoordinateSystem(CAM_A)")
167 for i, pcd in enumerate(camFrames):
168 printPointCloudInfo(pcd, i)
169
170 # 4 ── Custom transform + passthrough depth
171 printHeader("4. Custom transform matrix + passthrough")
172 print(" Config: 90° Z rotation via initialConfig")
173 if len(customFrames) != len(depthFrames):
174 raise RuntimeError("customFrames and depthFrames must have the same length")
175 for i, (pcd, depth) in enumerate(zip(customFrames, depthFrames)):
176 printPointCloudInfo(pcd, i)
177 print(f" Depth frame : {depth.getWidth()} × {depth.getHeight()}")
178
179 # 5 ── Colorized point cloud
180 printHeader("5. Colorized point cloud (RGB)")
181 print(" Config: METER, aligned color camera linked to inputColor")
182 for i, pcd in enumerate(colorizedFrames):
183 printPointCloudInfo(pcd, i)
184
185 print("\nAll demos completed.")
186
187
188if __name__ == "__main__":
189 main()需要帮助?
请前往 OAKChina 官网 获取技术支持或解答您的任何疑问。