4. 深度图采集:相机驱动安装、参数设置与实时采集保存

好,到了真正动手的环节了。前面我们聊了深度图的理论、标定板的设计,现在终于要把相机点亮,看到第一帧深度图了。说实话,每次做新项目,我最期待的就是这一刻——硬件连上,软件跑通,数据出来,那种成就感是写代码给不了的。

这一章,我们聚焦三个核心动作:驱动安装、参数调优、实时采集与保存。每一步都有坑,我尽量把踩过的坑都指出来。

4.1 相机驱动安装——别让第一步卡住你

驱动安装听起来简单,但不同品牌的深度相机差异很大。我习惯把驱动分为两类:

相机类型 典型品牌 驱动安装方式 常见坑点
USB 3.0 深度相机 Intel RealSense, Orbbec 官方 SDK 安装包(含驱动) USB 带宽不足,需插在独立 USB 控制器上
GigE 工业相机 Basler, Hikrobot 单独安装 Pylon / MVS 驱动包 IP 地址配置、网卡巨型帧设置
Camera Link / CoaXPress Teledyne Dalsa, Euresys 采集卡驱动 + 相机配置文件 采集卡固件版本与相机不匹配
⚠ 我曾经遇到过一次:RealSense D435 插在机箱前置 USB 口,死活枚举不到设备。折腾了两小时,换到后置主板 USB 口,一次成功。USB 3.0 深度相机对线缆质量和端口供电非常敏感,建议用原装线,插主板直出的 USB 口。

安装完成后,怎么确认驱动生效?我一般用两个方法:

  • 设备管理器(Windows):查看是否有黄色感叹号,或者是否出现在「相机」或「图像设备」分类下。
  • 官方工具:比如 RealSense Viewer、Basler pylon Viewer,能直接看到相机型号和固件版本。

嗯,这一步别急。驱动没装好,后面所有代码都跑不起来。

4.2 参数设置——曝光、增益、帧率的三角关系

相机亮了,但画面可能过曝、太暗、或者卡顿。这时候就要调三个关键参数:曝光时间、增益、帧率。它们之间是互相制约的,我画了一张图帮你理解:

深度相机参数三角关系 曝光时间 增益 帧率 核心约束: 曝光时间 ↑ → 帧率 ↓(帧周期 = 曝光时间 + 读出时间) 增益 ↑ → 噪声 ↑ → 深度精度 ↓(信噪比恶化) 帧率 ↑ → 每帧可用光量 ↓ → 可能需要提高增益或曝光

说白了,这三者是一个跷跷板。你要根据应用场景做取舍:

  • 静态场景(如工件检测):曝光可以长一些(比如 20-50ms),增益压低,帧率 10-15 FPS 就够。
  • 动态场景(如传送带抓取):帧率要 30 FPS 以上,曝光必须短(5-10ms),增益适当提高。
  • 高反光物体:曝光要低,否则过曝区域深度值会丢失。
💡 我的个人习惯:先固定帧率(比如 15 FPS),然后调曝光让画面亮度适中,最后用增益微调。增益尽量控制在 6dB 以内,超过 12dB 噪声会明显影响深度图质量。

4.3 Halcon 中的参数设置实战

在 Halcon 里操作深度相机,我一般走这个流程:

  1. 打开相机:用 open_framegrabber 连接设备。
  2. 枚举参数:用 get_framegrabber_param 查看支持哪些参数。
  3. 设置参数:用 set_framegrabber_param 写入曝光、增益、帧率。
  4. 验证:抓一帧看看效果。

下面是一个完整的 Halcon 代码示例,以 RealSense D435 为例:

* 打开 RealSense 相机
open_framegrabber('RealSense', 1, 1, 0, 0, 0, 0, 'default', -1, 'default', -1, 'false', 'default', '0', 0, -1, AcqHandle)

* 设置深度流分辨率
set_framegrabber_param(AcqHandle, 'depth_resolution', '848x480')

* 设置帧率
set_framegrabber_param(AcqHandle, 'framerate', 30)

* 设置曝光时间(单位:微秒)
set_framegrabber_param(AcqHandle, 'exposure_time', 8000)

* 设置增益
set_framegrabber_param(AcqHandle, 'gain', 4.0)

* 抓取一帧深度图
grab_image_start(AcqHandle, -1)
grab_image_async(DepthImage, AcqHandle, -1)

* 显示
dev_display(DepthImage)
⚠ 注意:不同相机的参数名称不一样。比如 RealSense 用 exposure_time,Basler 用 ExposureTimeAbs。建议先用官方工具(如 RealSense Viewer)找到参数名,再写到 Halcon 代码里。我曾经因为参数名写错,调了一下午没反应。

4.4 实时深度图采集与保存

参数调好了,接下来就是连续采集。实时采集的核心是循环抓帧,同时要考虑性能——别让采集线程把 CPU 吃满。

我常用的采集循环结构:

* 循环采集 100 帧
for Index := 1 to 100 by 1
    grab_image_start(AcqHandle, -1)
    grab_image_async(DepthImage, AcqHandle, -1)

    * 保存为 PNG 或 TIFF(保留深度值)
    write_image(DepthImage, 'tiff', 0, 'depth_frame_' + Index$'03d' + '.tif')

    * 可选:保存为点云(PLY 格式)
    * 需要先转成点云
    * xyz_to_object_model_3d(DepthImage, CamParam, ObjectModel3D)
    * write_object_model_3d(ObjectModel3D, 'ply', 'pointcloud_' + Index$'03d' + '.ply')

    * 显示当前帧号
    disp_message(WindowHandle, 'Frame: ' + Index$'03d', 'window', 12, 12, 'black', 'true')
endfor

保存格式怎么选?我整理了一个对比表:

格式 优点 缺点 适用场景
TIFF(16位) 无损、保留原始深度值 文件较大 离线分析、标定数据
PNG(16位) 无损压缩、文件较小 部分软件不支持 16 位 PNG 存档、传输
PLY 直接是点云,可带颜色 文件大、写入慢 三维重建、可视化
HALCON 原生格式(hobj) 加载快、保留全部元数据 仅 Halcon 可读 中间处理、调试
📌 关键建议:标定用的深度图,一定要保存为 16 位 TIFF 或 PNG。8 位图会丢失深度精度,标定结果会偏差很大。我见过有人用 8 位图做标定,结果深度误差直接翻倍。

4.5 避坑指南——我踩过的几个雷

最后,分享几个实战中容易翻车的地方:

  • USB 带宽不足:同时开 RGB 流和深度流,USB 3.0 带宽可能不够。我一般只开深度流,或者降低分辨率到 640x480。
  • 曝光时间与帧率冲突:如果你设了 30 FPS,但曝光时间设了 50ms,相机实际帧率会自动降到 20 FPS 以下。Halcon 不会报错,但你会觉得「怎么帧率上不去」。
  • 保存路径权限:在 Windows 下,如果程序装在 Program Files 里,可能没有写入权限。我习惯把数据保存到 D:\depth_data\ 这种独立目录。
  • 热噪声:深度相机连续工作 30 分钟后,传感器温度升高,噪声会变大。如果做精密标定,建议开机预热 10 分钟再采集。

嗯,这一章的内容就到这里。驱动装好、参数调对、数据能存下来,后面的事情就好办了。记住一句话:采集质量决定标定上限。花时间把这一步做扎实,后面会省很多事。