2. Halcon 3D基础:对象模型、数据读写与坐标系变换

好,我们正式开始接触 Halcon 3D 的核心概念。这一章是地基,打不牢后面会很痛苦。我个人习惯,学任何新东西,先搞清楚它到底在操作什么“东西”。在 Halcon 3D 的世界里,这个“东西”就是 ObjectModel3D。

2.1 什么是 ObjectModel3D?

说白了,ObjectModel3D 就是一个“大箱子”。这个箱子里装着描述一个三维物体的所有信息。它不像 2D 图像那样只是一堆像素矩阵,它里面装的是点云、三角网格、法向量、颜色信息等等。

你可以把它理解成一个结构体,或者一个对象。Halcon 通过一个句柄(Handle)来管理它。你创建它、往里面塞数据、然后调用各种算子处理它。

核心要点: ObjectModel3D 是 Halcon 3D 操作的唯一数据载体。所有 3D 数据,无论来自激光轮廓仪、双目相机还是 CAD 文件,最终都要装进这个“箱子”里。

2.2 3D数据读取与显示

拿到一个 3D 数据文件,怎么把它读进来?Halcon 提供了非常直接的算子。我最常用的是 read_object_model_3d。

2.2.1 读取点云数据

支持的格式很多,比如 PLY、OBJ、STL、DXF 等等。代码很简单:

* 读取一个 PLY 格式的点云文件
read_object_model_3d ('point_cloud.ply', 'm', [], [], ObjectModel3D)

* 读取一个 STL 格式的三角网格模型
read_object_model_3d ('mesh.stl', 'm', [], [], ObjectModel3D)

第二个参数 'm' 是什么意思?它告诉 Halcon,读取的数据单位是“米”。如果你从其他软件导出的数据单位是毫米,那就得用 'mm'。这个单位信息会存储在 ObjectModel3D 的属性里,后续所有测量都会基于这个单位。我在项目中遇到过,有人从不同设备采集数据,单位没统一,结果测量出来的尺寸差了 1000 倍,排查了半天才发现是单位问题。

2.2.2 显示 3D 数据

读进来之后,怎么看到它?Halcon 的显示机制和 2D 不太一样。2D 图像可以直接用 disp_image,但 3D 需要先创建一个窗口,然后用 visualize_object_model_3d 这个交互式显示算子。

* 创建显示窗口
dev_open_window (0, 0, 800, 600, 'black', WindowHandle)

* 交互式显示 3D 对象
visualize_object_model_3d (WindowHandle, ObjectModel3D, [], [], \
                           ['color_0'], ['green'], [], [], [], PoseOut)

这个算子非常强大。它会打开一个交互窗口,你可以用鼠标拖拽旋转、缩放、平移。我个人习惯把背景色设成黑色,点云颜色设成绿色,这样对比度高,看得清楚。

小技巧: 如果点云太大,显示会卡顿。可以用 sample_object_model_3d 算子对点云进行下采样,减少点数,提高交互流畅度。我曾经处理过几千万个点的数据,不采样根本拖不动。

2.3 3D坐标系统与坐标系变换

这是 3D 视觉里最容易出错的地方。你想想看,一个物体在相机坐标系下是一个位置,在机器人坐标系下又是另一个位置。怎么把它们统一起来?这就涉及到坐标系变换。

2.3.1 Halcon 中的坐标系定义

Halcon 3D 使用右手坐标系。这一点和很多工业软件一致。具体来说:

  • X 轴: 向右
  • Y 轴: 向下(注意!这和很多 OpenGL 或机器人坐标系不同,它们 Y 轴通常向上)
  • Z 轴: 指向屏幕外(朝向观察者)

为什么 Y 轴向下?因为 Halcon 是从 2D 图像处理起家的,2D 图像的原点在左上角,行坐标向下增加。为了保持一致性,3D 坐标系也沿用了这个习惯。

坐标系 X 轴 Y 轴 Z 轴 备注
Halcon 3D 向右 向下 向外 右手系,Y 轴向下
机器人基坐标系 向前 向左 向上 右手系,Z 轴向上
OpenGL 向右 向上 向外 右手系,Y 轴向上

2.3.2 坐标系变换:从相机到世界

坐标系变换的核心是 位姿(Pose)。在 Halcon 里,位姿用一个 7 元组表示:[X, Y, Z, RotX, RotY, RotZ, Order]。

  • X, Y, Z: 平移量
  • RotX, RotY, RotZ: 旋转角度(单位是弧度或度)
  • Order: 旋转顺序。比如 'gba' 表示先绕 Z 轴转,再绕 Y 轴,最后绕 X 轴。

为什么要指定旋转顺序?因为旋转不满足交换律。先绕 X 轴转 90 度再绕 Y 轴转 90 度,和先绕 Y 轴再绕 X 轴,结果完全不同。这个 Order 参数就是用来消除歧义的。

常用的变换算子:

* 创建一个位姿:平移 (100, 50, 0) 毫米,绕 Z 轴旋转 45 度
create_pose (100, 50, 0, 0, 0, 45, 'Rp+T', 'gba', 'point', Pose)

* 将一个 3D 对象从相机坐标系变换到世界坐标系
affine_trans_object_model_3d (ObjectModel3D, Pose, ObjectModel3D_World)

避坑指南: 我曾经在标定手眼系统时,死活对不上机器人和相机的坐标。折腾了两天,最后发现是 create_pose 里的 'Rp+T' 和 'R+T' 搞混了。前者是先旋转后平移,后者是先平移后旋转。在 Halcon 里,绝大多数情况用 'Rp+T',也就是先旋转点,再平移点。记住这个顺序,能省很多调试时间。

2.4 知识体系总览

为了让你更直观地理解这一章的知识结构,我画了一张图。你可以看到,所有操作都围绕着 ObjectModel3D 这个核心展开。

Halcon 3D 基础:知识体系结构图 ObjectModel3D 数据读取 数据可视化 坐标系变换 PLY / OBJ STL / DXF visualize_object_model_3d create_pose affine_trans 核心逻辑:所有 3D 数据最终都封装在 ObjectModel3D 中 通过读取、可视化、变换三个基本操作进行加工

2.5 本章小结

这一章我们搞清楚了三个问题:

  1. 操作对象是什么? —— ObjectModel3D,一个装点云、网格、法向量的“大箱子”。
  2. 怎么读写和显示? —— 用 read_object_model_3d 读,用 visualize_object_model_3d 看。
  3. 坐标系怎么玩? —— 右手系,Y 轴向下。用 Pose 做变换,注意旋转顺序和先旋转后平移的原则。

嗯,这些都是基础中的基础。你可能会觉得有点枯燥,但相信我,后面做标定、做测量的时候,你会无数次回来翻这一章的内容。尤其是坐标系变换,搞不清楚的话,标定出来的结果全是错的。

我的建议: 打开 Halcon,随便找一个 PLY 文件,亲手跑一遍读取和显示的代码。然后用鼠标在可视化窗口里转一转,感受一下坐标轴的方向。动手做一遍,比看十遍书都管用。