Skip to content

Astra Pro深度相机折腾记

约 1469 字大约 5 分钟

折腾

2025-07-11

最近在闲鱼花了45元淘了台深度相机,折腾出一套3D目标检测系统:用YOLOv8识别物体,结合深度信息生成3D边界框,Open3D可视化点云。踩了不少坑,在此记录一下。

缘起:一台从闲鱼来的相机

前段时间在闲鱼上刷到了一台 ASTRA Pro 深度相机,价格美丽,卖家说是公司项目结束后的闲置设备。想着最近在尝试点云重建的研究,于是果断入手了。收到货后发现品相不错,就开始了我的深度相机折腾之旅。 外观

什么是深度相机?

简单来说,深度相机不仅能拍摄普通的彩色图像,还能获取场景中每个像素点的距离信息。这就像给普通相机加上了"透视眼",能够感知到三维空间的深度信息。

ASTRA Pro 是奥比中光(Orbbec)出品的一款深度相机,主要特点:

  • 支持 RGB 彩色图像和深度图像同时输出
  • 基于结构光技术,在室内环境下表现不错
  • 支持 OpenNI2 接口,开发起来相对友好

搭建开发环境

首先需要安装一堆依赖库:

# 主要依赖
pip install opencv-python
pip install numpy
pip install open3d
pip install ultralytics
pip install PyYAML

然后是 OpenNI2 的安装,这个稍微麻烦一些,需要根据系统版本下载对应的驱动。

1. 驱动安装

2. OpenNI SDK配置

  • 下载SDK:Orbbec OpenNI SDK
  • 安装步骤:
    1. 解压压缩包
    2. 复制Win64-Release文件夹内容到 C:\Program Files\Orbbec\OpenNI
  • 测试工具:运行 OpenNI\tools\NiViewer\NiViewer.exe

3. 环境变量设置

临时设置(当前会话有效)

$Env:OPENNI2_REDIST64="C:/Program Files/Orbbec/OpenNI/sdk/libs"

永久设置(需要重启终端)

[Environment]::SetEnvironmentVariable("OPENNI2_REDIST64", "C:/Program Files/Orbbec/OpenNI/sdk/libs", "Machine")

代码架构设计

整个程序的核心思路是:

  1. 同时获取 RGB 图像和深度图像
  2. 用 YOLOv8 检测 RGB 图像中的物体
  3. 结合深度信息生成 3D 边界框
  4. 用 Open3D 实现点云和 3D 边界框的可视化

配置文件管理

为了方便调试,我把相机参数都写在了 YAML 配置文件里:

Camera:
  width: 640
  height: 480
  fps: 30
  fx: 570.3
  fy: 570.3
  cx: 320.0
  cy: 240.0
  DepthMapFactor: 1000.0

Viewer:
  point_size: 4.0
  background_color: [0, 0, 0]

这样调参数的时候就不用重新编译了,改完配置文件重启程序就行。

核心功能实现

1. 双摄像头同步

最开始遇到的问题是 RGB 摄像头和深度摄像头的同步问题。深度相机内置的 RGB 模块质量一般,所以我另外接了一个 USB 摄像头。

# 初始化深度流
depth_stream = dev.create_depth_stream()
depth_stream.set_video_mode(...)
depth_stream.start()

# 初始化 RGB 摄像头
cap = cv2.VideoCapture(1)  # 注意索引号

2. YOLO 目标检测

用的是 YOLOv8n 模型,轻量级,在我的笔记本上跑起来还算流畅:

model = YOLO('yolov8n.pt')
results = model(rgb_frame, conf=0.4, iou=0.7)

3. 3D 边界框生成

这部分是最有趣的,通过深度信息把 2D 检测框转换成 3D 边界框:

def get_3d_bbox_from_2d(x1, y1, x2, y2, depth, fx, fy, cx, cy):
    # 获取边界框区域的深度值
    mask = depth[y1:y2, x1:x2]
    valid_depths = mask[mask > 0]
    
    # 计算深度范围
    zmin, zmax = np.percentile(valid_depths, [10, 90])
    
    # 投影到3D空间
    # ... 详细计算过程

4. 目标跟踪

为了让检测结果更稳定,加了个简单的基于 IoU 的目标跟踪:

def track_boxes(prev_boxes, new_boxes, iou_threshold=0.5):
    # 计算新旧边界框的重叠度
    # 关联最匹配的边界框
    # 对于消失的目标,逐渐降低置信度

这样就避免了检测框在连续帧间剧烈跳动的问题。

实际效果

点云与3D边界框可视化

生成的点云效果还是很不错的,同时检测到的物体会用不同颜色的 3D 边界框标出来,并且显示距离信息:

深度图可视化

深度图用热力图的形式展示,近的地方是红色,远的地方是浅黄色:

遇到的坑

1. 相机内参标定

最开始直接用了网上找的参数,结果投影出来的 3D 点云完全变形了。后来老老实实用棋盘格标定了一遍,效果好了很多。

2. 坐标系转换

OpenCV、Open3D 和深度相机的坐标系都不太一样,需要做坐标转换。我用了一个变换矩阵:

COORD_TRANSFORM = np.array([
    [1, 0, 0, 0],
    [0, -1, 0, 0],
    [0, 0, -1, 0],
    [0, 0, 0, 1]
])

3. 性能优化

最开始程序跑起来很卡,后来发现是点云密度太高了。加了体素下采样后流畅了很多:

pcl = pcl.voxel_down_sample(voxel_size=0.005)

4. 内存管理

Open3D 的几何体对象需要手动管理,不然会内存泄漏。特别是在循环中创建 LineSet 的时候,需要复用对象而不是每次都创建新的。

交互控制

加了一些简单的键盘控制:

  • +- 键控制缩放
  • q 键退出程序
key = cv2.waitKey(1)
if key == ord('+'):
    zoom_level = max(0.1, zoom_level * 0.8)
    vis.get_view_control().set_zoom(zoom_level)
elif key == ord('q'):
    break

后续计划

这个小项目还有很多可以改进的地方:

  1. SLAM 功能:加入视觉里程计,实现实时建图
  2. 手势识别:利用深度信息识别手势
  3. 物体抓取:结合机械臂做物体抓取
  4. AR 应用:在现实场景中叠加虚拟物体

P.S. 点云的世界远比我想象的要精彩,这只是个开始... 🚀