Halcon之3D位姿-个人学习笔记篇(待完善)
文章目录
- 1.3D 视觉
- 2 基本概念
- 3.使用单个相机在指定平面上进行测量
1.3D 视觉
三维测量变得越来越重要,HALCON 提供了许多3D 测量的方法,这个解决方案指导给你了一个所有这些方法的概述,它帮助你正确的选择和应用恰当的方法。
不同方法的简单特点在第一章给出,3D位姿转换和相机模型的描述可以在第2章找到。之后,详细描 述执行3D 测量的方法。
关于这章中的HDevelop中的例程可以指定的HALCON 目录的子目录中找到。
1.1 前言
利用HALCON 你可以通过多种方法执行3D 视觉。主要的应用包括三维位姿识别和三维检测,其中两者 都各自由不同特征的集中不同方法组成,因此,对于一个范围很大的3D 视觉任务,需要提供一个合适的 解决方案。
这个解决方案指导给你提供了这些可以使用的方法的详细信息,包括一些值在特定情形下使用 的辅助方法。
1.1,1 对于3D 视觉你需要那些基本的知识?
典型的,你需要先标定你的相机在执行一个3D 任务之前,尤其是你想要获得精确的结果,相机标定是必须的,因为在镜头畸变了两个像素的情况下提取1/40像素的边缘是没有用的。当你使用远心镜头时,这是适用的。但是不要害怕相机的标定,在HALCON 中这只需要仅仅几行的代码就可以完成。为了准备相机标 定,第2 章详细介绍了相机模型和参数,之后准确的相机标定在第三章描述。
使用相机标定,你可以将图像处理结果转换到任意的3D坐标系中,之后从图像中获取测量信息,不管物体相对与相机的位置和方向是什么样的。换而言之,你可以执行3D 测量在任意的物体平面上,这个平面相对于相机的方向可以是任意的。这很有用,比如在摄像机无法安装成与物体垂直的情况。
因此,除了单纯的相机标定,第三章说明了怎么使用一个相机在指定的平面上执行一个3D任务。此外,其展示了怎样校正一副图像使图像看起来像是由一个没有镜头畸变的且垂直于物体平面的相机获取。这是有用的在 OCR 或物体的识别和定位中,即获取的图像不能相对与训练的图像有太大的畸变。
在你开发视觉应用之前,我们建议你先读第二章和第三章,然后根据你目前的任务,跳到你的具体应 用需要的开发3D 视觉方法的描述处。
1.1.2 怎样获取一个物体的三维位姿和方向?
一个物体对于给定的3D 坐标细的位置和方向是需要的,比如拿起和放下的应用(3D对齐技术),物体的位置和方向的获取,可以使用第四章中描述的方法。
1).根据相关点估计一个已知物体的位姿是一个一般的方法,其包括相机标定和至少3个已知坐标系的标志点,这种方法也被称作 “ mono 3D ” 。
2).HALCON的3D匹配定位物体,基于物体已知的一个3D 模型。特别的,其自动的在搜索范围内搜索和3D 模型相关的物体,获取他们的位姿。模型必须被提供,比如一个CAD 模型。可用的 方法有基于形状的3D 匹配(4.2 节),其在二维图像中搜索模型;基于表面的3D 匹配在3D场景中搜索模型,比如在一组可以作为3D 模型的3D点中,模型可以被获取利用立体或 sheet of light 的3D重构方法。注意基于表面的匹配也被称作“立体匹配”,虽然它只依赖于物体表面 的点。
3). HALCON 的3D 基元拟合拟合一个原始的三维模型,比如圆柱、球或三维场景中的平面,比如可以作为3D 模型的一系列3D 点,其可以被获取通过3D 分割再加立体或 sheet of light 的 3D 重 构方法。
4).校准透视匹配定位图像中透视变形的平面物体基于2D 模型。尤其的,其自动寻找图像中相关于2D 模型的物体并确定他们的3D 位姿。模型从一个模型具有代表性的图像中过去。有用的
方法是矫正透视变形匹配,通过边界描述模型; descriptor-based matching 通过一组被叫做兴趣 点的特征点来描述模型。
5). 圆位姿估计(4.8 节)和矩形位姿估计(4.9 节)以一种非常简单的方法利用圆或矩形的透视畸变来确定包含圆或矩形的平面物体的位姿
1.1.3 如何测量一个3D 物体?
3D 物体测量可以有多种不同方法,如果在一个特定的足够的平面,你可以使用相机标定加2D测量, 这在(第3章描述)
如果需要一个3D 物体的表面信息或者测量不能减少到一个指定平面上,你可以是用3D重建和3D测量方法。即,你使用由3D重建返回的3D物体的点,表面或者高度信息来测量物体,比如,和指定的点、 平面或高度比较。
图1提供了概览关于三维位姿识别和3D 测量的方法,对于3D 模型的介绍,请到2.3 节。

1.1.4 怎样重建3D 物体?
确定任意物体上的3D 点,可用以下方法:
1).HALCON 的立体视觉功能(第5 章)允许确定物体表面任意点的3D 坐标系使用两个(双目立体视觉)或多个(多目视觉)从不同角度获取的合适图像(通过不同的相机)。使用多目立体视 觉,你可以重建整个3D 物体,特别的,你可以从不同面重建它。
2).使用sheet of light 的激光三角法,允许得到物体的高度信息。注意除了一个相机,其他的硬件,一个激光硬件发生器、一个使物体相对于相机移动的装置,以及激光是需要的。
3). 聚焦深度测量(第7 章),使用这种方法,一个高度信息的获取可以通过使用一个远心镜头在不同的焦点位置处获取的图像来实现。为了变换焦点信息,需要位移变换平台或线性压电平台 等其他硬件。注意,根据焦点位置改变的方向,结果对应于一个高度图像或一个距离图像。高 度图包含一个指定物体或测量平面与物体点之间的距离,而距离图包含物体点和相机间的距 离信息。两者都可以被称作深度图或者 “ Z image ” 。
4).使用光度立体法 ( Reference Manual, chapter “3D Reconstruction . Photometric Stereo” ) , 一个高度图可以被获取通过使用一个远心相机获取的多幅图像,其中相机需要使用至少 3 种不同的光 源,每种光源相对于相机的立体关系需要被知道。注意,高度图只是反映了相对高度,比如使 用光度立体方法,不标定的 3D 重构是可能的。
5).除了 HALCON 提供的 3D 重建方法,你可以获取 3D 信息通过指定的 3D 传感器,比如 TOF相机,或特定的程序使用结构光,这些相机已经被标定,并返回 X 、 Y 、 Z 图像。 表1.2 比较了几种不同3D 重构方法的特征。

1.1.5 怎样把3D 视觉延伸到机器人视觉?
3D视觉的一个典型应用就是机器人视觉,比如使用机器视觉的结果去命令一个机器人,在这种应用中, 你必须执行一个额外的标定,所谓的手眼标定,其确定了相机和机器人坐标系间的关系。此外,这个标定 之只能被执行一次。它的结果允许你快速的将机器视觉结果由相机坐标系转换到机器人坐标系。
1.1.6 还需要什么其他任务?
如果你想要观测的物体太大一副图像不能覆盖使用理想的方法,多副图像,每幅图像只是覆盖物体的 一部分,可以被结合为一副大的拼接图像。这可以被完成通过一个精度非常高的标定的相机模型或高度自 动化的对于任意的或甚至变化的图像配置。
如果一副图像表现出的畸变不是通常的透视畸变或镜头畸变,比如,由一个不水平的物体引起的畸变, 一个叫做网格校正的方法可以被用来校正图像。
2 基本概念
2.1 3D 转换和位姿
在开始解释在HALCON中如何实现世界坐标系中的机器视觉应用之前,我们首先了解一下与使用 3D 坐 标相关的一些基础知识:
1).如何表示点在空间坐标的转换(平移和旋转);
2).如何表示空间坐标系;
3).如何表示某空间坐标系与另外一个空间坐标系之间的相对位置和相对方位;
4).如何确定某空间坐标系中的一点在另外一个坐标系中的坐标,也就是说如何在不同的坐标系中 进行坐标转换。
实际上,所有这些任务都可以使用同样的手段实现,就是相似变换矩阵和与其等价的 3D 位姿。
2.1.1 三维坐标
三维空间中某个点的位置可以由三个坐标
表示。这个坐标也可以认为是一个三维向量(由一个黑体小写字母表示)每个三维空间点的坐标都是相对于某个坐标系,这个坐标系的名称表示为三 维向量或三维坐标的右上角。例如:点P 在摄像机坐标系(表示为c)中的坐标以及该点在世界坐标系(表 示为w)的坐标为:
图2.1表示在测量平面上的某个点P,以及它分别在摄像机坐标系和世界坐标系中的坐标。
2.1.2 平移
2.1.2.1 点的平移
在图2.2中,示例点沿摄像机坐标系的x轴进行了平移。

平移后得到的点P2的坐标可以通过计算两个三维向量的和得到,起始点p1的坐标向量和平移向量t:
如果对点进行多次平移,则可以通过再添加平移向量。这些操作是没有次序要求的,是可交换的,也就是说平移的次序不影响最终的结果。
2.1.2.2 坐标系的平移
坐标系的平移和点的平移很相似。在图2.3的示例中,坐标系c1通过平移得到坐标系c2。然后,坐标系c2在坐标系c1中的位置,也就是c2坐标系原点在坐标系c1中的坐标向量 o c 2 c 1 o_{c_2}^{c_1} oc2c1,与平移向量相等。
t c 1 = o c 2 c 1 (2.2) t^{c_1} = o_{c_2}^{c_1} \tag{2.2} tc1=oc2c1(2.2)
2.1.2.3 坐标平移
现在我们来考虑一下如何在原始坐标系和平移后的坐标系之间进行坐标变换。实际上,一个点的平移 可以考虑为这个点随同它本身的坐标系一起平移。图2.3 是坐标平移的一个示例:坐标系c1 与点Q1 使用 平移向量t 进行平移,得到坐标系c2 和点Q2。点Q1 和Q2 在它们各自的坐标系中有相同的坐标,也就是说 q c 1 c 1 = q c 2 c 2 q_{c_1}^{c_1} = q_{c_2}^{c_2} qc1c1=qc2c2
如果坐标系只是相对于另一个坐标系进行平移,在不同坐标系下的坐标变换非常容易,只需要加上他 们之间的转换向量即可:
q 2 c 1 = q 2 c 2 + t c 1 = q 2 c 2 + o c 2 c 1 (2.3) q_2^{c_1} = q_2^{c_2} + t^{c_1} = q_2^{c_2} + o_{c_2}^{c_1} \tag{2.3} q2c1=q2c2+tc1=q2c2+oc2c1(2.3)
实际上,图五已经形象的表示了这个方程式:q2c1,也就是点Q2在坐标系c1中的坐标,就是由Q2点在坐标系c2中的坐标向量加上平移向量t得到的。第一眼看上去,图五底侧的图标指的是平移向量的方向似乎与坐标系平移方向相反:从坐标系c1到c2的向量方向,而不是从坐标系c2到c1的平移向量。
q 1 c 2 = q 1 c 1 − t c 1 = q 1 c 1 − o c 2 c 1 (2.4) q_1^{c_2} = q_1^{c_1} - t^{c_1} = q_1^{c_1} - o_{c_2}^{c_1} \tag{2.4} q1c2=q1c1−tc1=q1c1−oc2c1(2.4)
2.1.2.4 总结
1).空间中某一点平移后的坐标就是平移前的坐标加上平移向量。坐标系的平移也与之类似,坐标系 的平移就相当于加上坐标系原点的平移向量(坐标向量)。
2).如果需要将某个点的坐标从平移后的坐标系c2中转换到原始坐标系c1中,应该在这个点上加上 一个平移向量,这个平移向量就是我们用来转换坐标系的平移向量。也就是说,我们在点的坐标上加上我 们用来将坐标系c1转换到c2的平移向量。
3).如果进行多次平移,就可以在坐标向量上加上所有的平移向量;平移的次序不影响最终的结果。
2.1.3 旋转
2.1.3.1 点的旋转
在图2.4a中,点p1绕摄像机坐标系的z轴旋转-90度。
经过旋转操作后的点的坐标可以由原始坐标乘以一个 3 × 3 3 \times 3 3×3 的旋转矩阵 R \mathbf{R} R。绕 z z z 轴的旋转矩阵如下所示:
绕 x x x 轴和 y y y 轴的旋转矩阵如下:
R y ( β ) = [ cos β 0 sin β 0 1 0 − sin β 0 cos β ] R x ( α ) = [ 1 0 0 0 cos α − sin α 0 sin α cos α ] (2.6) R_y(\beta) = \begin{bmatrix} \cos\beta & 0 & \sin\beta \\ 0 & 1 & 0 \\ -\sin\beta & 0 & \cos\beta \end{bmatrix} \quad\quad R_x(\alpha) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos\alpha & -\sin\alpha \\ 0 & \sin\alpha & \cos\alpha \end{bmatrix} \tag{2.6} Ry(β)= cosβ0−sinβ010sinβ0cosβ Rx(α)= 1000cosαsinα0−sinαcosα (2.6)
2.1.3.2 连续旋转
在图 2.4b 中,旋转后的点又绕 y y y 轴进行了一次旋转。类似这样的一系列旋转可以表示为与一系列的旋转矩阵相乘:
p 4 = R y ( β ) ⋅ p 3 = R y ( β ) ⋅ R z ( γ ) ⋅ p 1 (2.7) p_4 = R_y(\beta) \cdot p_3 = R_y(\beta) \cdot R_z(\gamma) \cdot p_1 \tag{2.7} p4=Ry(β)⋅p3=Ry(β)⋅Rz(γ)⋅p1(2.7)
注意:与标量的乘法不同,矩阵的乘法是不可交换的,也就是说如果改变旋转矩阵的序列,你将得到不同的结果。
2.1.3.3 坐标系的旋转
坐标系和点不同的是,坐标系和其他坐标系之间不仅有相对的位置关系,并且存在相对的方位关系。如果坐标系发生旋转,这个方位将发生变化。例如,在图 2.5a 中坐标系 c 3 c3 c3 绕坐标系 c 1 c1 c1 的 y y y 轴发生旋转,导致摄像机的方位发生变化。注意,为了在想象中旋转一个坐标系,可以想象这个轴向量上的点也都进行了旋转。
就像可以直接通过平移向量来表示坐标系的位置(等式 2.2),坐标系的方位页包含在旋转矩阵中:旋转矩阵的列就对应于旋转后的坐标系的轴向量在原始坐标系中的值:
p 4 = [ x c 3 c 1 , y c 3 c 1 , z c 3 c 1 ] (2.8) p_4 = \left[ x_{c_3}^{c_1}, y_{c_3}^{c_1}, z_{c_3}^{c_1} \right] \tag{2.8} p4=[xc3c1,yc3c1,zc3c1](2.8)
例如,在图 2.5a 中所示,坐标系 c 3 c3 c3 的轴向量可以由相应的旋转矩阵 R y ( 90 ° ) R_y(90°) Ry(90°) 确定,你可以非常容易的在图中核对这个结果。
⇒ x c 3 c 1 = ( 0 0 − 1 ) , y c 3 c 1 = ( 0 1 0 ) , z c 3 c 1 = ( 1 0 0 ) \Rightarrow x_{c_3}^{c_1} = \begin{pmatrix} 0 \\ 0 \\ -1 \end{pmatrix}, y_{c_3}^{c_1} = \begin{pmatrix} 0 \\ 1 \\ 0 \end{pmatrix}, z_{c_3}^{c_1} = \begin{pmatrix} 1 \\ 0 \\ 0 \end{pmatrix} ⇒xc3c1= 00−1 ,yc3c1= 010 ,zc3c1= 100
2.1.3.4 坐标变换
和平移的情况类似,如果需要将点的坐标由旋转后的坐标系 c 3 c3 c3 转换到原始坐标系 c 1 c1 c1,你也可以将应用在坐标系 c 3 c3 c3 的转换应用到这些点上。也就是说,可以用点的坐标乘以用来将坐标系 c 1 c1 c1 旋转到 c 3 c3 c3 的旋转矩阵:
q 3 c 1 = c 1 R c 3 ⋅ q 3 c 3 (2.9) q_3^{c_1} = {}^{c_1}R_{c_3} \cdot q_3^{c_3} \tag{2.9} q3c1=c1Rc3⋅q3c3(2.9)
在图 2.5 中还描述了如何进行一系列旋转,这一系列旋转对应于下面的方程式:
q 4 c 1 = c 1 R c 2 ⋅ c 2 R c 4 ⋅ q 4 c 4 = R y ( β ) ⋅ R z ( γ ) ⋅ q 4 c 4 = c 1 R c 4 q 4 c 4 (2.10) q_4^{c_1} = {}^{c_1}R_{c_2} \cdot {}^{c_2}R_{c_4} \cdot q_4^{c_4} = R_y(\beta) \cdot R_z(\gamma) \cdot q_4^{c_4} = {}^{c_1}R_{c_4} q_4^{c_4} \tag{2.10} q4c1=c1Rc2⋅c2Rc4⋅q4c4=Ry(β)⋅Rz(γ)⋅q4c4=c1Rc4q4c4(2.10)
2.1.3.5 旋转次序的影响以及如何确定绕哪个轴旋转
如果你对比图 2.4 和图 2.5 中的一系列旋转,并且比较等式 2.7 和等式 2.10,你将发现两种不同的旋转次序可以使用一系列同样的矩阵乘积进行表示:在图 2.4 中,点首先绕 z z z 轴旋转,然后绕 y y y 轴旋转,然而在图 2.5 中,坐标系首先绕 y y y 轴旋转,然后绕 z z z 轴旋转。但是,两者都可以用等式 R y ( β ) ⋅ R z ( γ ) R_y(\beta) \cdot R_z(\gamma) Ry(β)⋅Rz(γ) 表示!

这种看起来自相矛盾的情形是可以进行解释的,两个例子中旋转矩阵相乘的等式可以从不同的方向"读":在图 2.4 中可以从右向左读,在图 2.5 中则是从左向右读。
然而,两个序列应该还是应该存在不同之处,因为我们曾经提起过,旋转矩阵的乘法是不可交换的。这个不同可以通过题目中第二个问题进行解答,就是应该绕哪个轴进行旋转。
让我们从图 2.5b 中坐标系的第二次旋转开始。这里可以绕两组坐标轴进行旋转:一组是"旧"坐标系 c 1 c1 c1 的坐标轴,另外一组是第一次旋转后的"新"坐标系 c 3 c3 c3 的坐标轴。在这个例子中,第二次旋转是绕"新"的 z z z 轴进行旋转。
与之相比,在图 2.4 中进行点的旋转时,这里只可以绕一组坐标轴进行旋转,就是"旧"坐标系的坐标轴。
从这些我们可以得到下面几条规则:
(1)当我们从左向右读一个旋转序列时,需要绕"新"的坐标轴进行旋转。
(2)当我们从右向左读一个旋转序列时,需要绕"旧"的坐标轴进行旋转。
我们上面已经谈到,点的旋转序列只能从右向左读。在坐标系旋转的情况下,可以选择两种读法。在大多数情况下,人们从直觉上还是从左向右读。
图 2.6 表示从两个不同的方向读取获得同样的结果。
2.1.3.6 总结
(1)点的旋转通过将它们的坐标向量乘以一个旋转矩阵。
(2)如果你要旋转一个坐标系,旋转矩阵描述了结果坐标系的方位:旋转矩阵的列向量相应于结果坐标系的各个轴在原始坐标系中的轴向量。
(3)将点的坐标由旋转得到的坐标系 c 3 c3 c3 转换到原始坐标系 c 1 c1 c1 中,可以将转换坐标系的旋转矩阵应用在点的坐标上,也就是说用点的坐标乘以旋转矩阵。
(4)多次旋转可以表示为一个序列的旋转矩阵相乘,这个序列可以从两种方向读,如果从左向右读,需要绕"新"坐标轴旋转;当从右向左读,需要绕"旧"坐标轴旋转。
2.1.4 刚性变换和相似变换矩阵
2.1.4.1 点的刚性转换
如果将平移和旋转组合在一起,就可以称之为刚性转换。例如,在图 2.7 中将图 2.2 中的平移和图 2.4 中的旋转组合在一起。这种转换可以由下式进行表示:
p 5 = R ⋅ p 1 + t (2.11) p_5 = R \cdot p_1 + t \tag{2.11} p5=R⋅p1+t(2.11)
如果进行多次转换,这种表示方法会变得复杂,下面的等式只是进行两次转换:
p 6 = R a ⋅ ( R b ⋅ p 1 + t b ) + t a = R a ⋅ R b ⋅ p 1 + t a (2.12) p_6 = R_a \cdot (R_b \cdot p_1 + t_b) + t_a = R_a \cdot R_b \cdot p_1 + t_a \tag{2.12} p6=Ra⋅(Rb⋅p1+tb)+ta=Ra⋅Rb⋅p1+ta(2.12)
刚性转换另外一个非常好的表示方法称为相似转换矩阵以及相应的相似向量。一个相似转换矩阵 H \mathbf{H} H 包含旋转矩阵和平移向量。例如,等式 2.11 中表示的刚性转换可以用相似转换矩阵重写为:
2.1.4.2 坐标系的刚性转换
坐标系的刚性转换和我们讨论过的单独的平移和旋转方法一致。也就是说相似变换矩阵 c 1 H c 5 {}^{c_1}\mathbf{H}_{c_5} c1Hc5 描述了坐标系 c 1 c1 c1 到坐标系 c 5 c5 c5 的转换。同时,描述了坐标系 c 5 c5 c5 相对于坐标系 c 1 c1 c1 的位置和方位:相似变换矩阵的各个列向量表示坐标系 c 5 c5 c5 各个坐标轴在坐标系 c 1 c1 c1 中的轴向量以及坐标系 c 5 c5 c5 的原点在坐标系 c 1 c1 c1 中的坐标。
c 1 H c 5 = [ x c 5 c 1 y c 5 c 1 z c 5 c 1 o c 5 c 1 0 0 0 1 ] (2.16) {}^{c_1}\mathbf{H}_{c_5} = \begin{bmatrix} \mathbf{x}_{c_5}^{c_1} & \mathbf{y}_{c_5}^{c_1} & \mathbf{z}_{c_5}^{c_1} & \mathbf{o}_{c_5}^{c_1} \\ 0 & 0 & 0 & 1 \end{bmatrix} \tag{2.16} c1Hc5=[xc5c10yc5c10zc5c10oc5c11](2.16)
和讨论旋转的情况一样,对坐标系进行一系列的刚性转换一般都是从左向右读。因此,上面的一个序列 H \mathbf{H} H 就可以这样理解,首先对坐标系进行平移,然后绕"新"的 y y y 轴进行旋转,最终绕"最新"的 z z z 轴进行旋转。
2.1.4.3 坐标转换
在分别对平移和旋转进行讨论时我们得出,对点的坐标转换其实就是将应用在坐标系上的转换应用到点的坐标上。如果我们希望将点的坐标由刚性转换后的坐标系 c 5 c5 c5 转换到原始坐标系 c 1 c1 c1 中,我们可以将应用在坐标系上的转换应用到点上即可,也就是说,我们将点的坐标与相似变换矩阵相乘:
( p 5 c 1 1 ) = c 1 H c 5 ⋅ ( p 5 c 5 1 ) (2.17) \begin{pmatrix} p_5^{c_1} \\ 1 \end{pmatrix} = {}^{c_1}\mathbf{H}_{c_5} \cdot \begin{pmatrix} p_5^{c_5} \\ 1 \end{pmatrix} \tag{2.17} (p5c11)=c1Hc5⋅(p5c51)(2.17)
一般情况下,在不发生歧义的情况下可以将齐次坐标省掉,简单的写成:
p 5 c 1 = c 1 H c 5 ⋅ p 5 c 5 (2.18) p_5^{c_1} = {}^{c_1}\mathbf{H}_{c_5} \cdot p_5^{c_5} \tag{2.18} p5c1=c1Hc5⋅p5c5(2.18)
2.1.4.4 总结
(1)刚性转换包含一个旋转和一个平移。可以使用相似变换矩阵来表示一个刚性转换,在相似变换矩阵中既包含旋转矩阵也包含平移向量。
(2)对点进行刚性转换,可以通过点的坐标向量和相似变换矩阵相乘。
(3)如果需要转换一个坐标系,相似变换矩阵描述了转换后坐标系的位置和方位:矩阵的列向量对应于每个坐标轴向
(4)量以及坐标系原点在原始坐标系中的坐标。因此,可以说相似变换矩阵就"表示"一个坐标系的位置和方位。
(5)如果需要将点的坐标由刚性转换后的坐标系 c 5 c5 c5 转换到原始坐标系 c 1 c1 c1 中,可以把对坐标系的转换应用到点上。也就是说,将坐标系 c 1 c1 c1 转换到坐标系 c 5 c5 c5 时用到的相似变换矩阵乘以点的坐标即可。
(6)一系列的刚性转换可以描述为一个系列的相似变换矩阵的乘积,同样可以从两个方向读。当我们从左向右读的时候,需要绕"新"轴进行旋转;当我们从右向左读的时候,需要绕"旧"轴进行旋转。
2.1.4.5 HALCON 算子
我们在 section 2.1 的开始曾经提出关于 3D 坐标的几个问题,相似变换矩阵就是所有这些问题的答案。因此,他们就构成了 HALCON 中与三维转换相关的函数的基础。下面,我们就列出与之相关的一些函数。如果需要更详细的信息,请参考 Reference Manual。
(1)hom_mat3d_identity 创建一个相似变换矩阵,这个相似变换矩阵不会导致任何转换,只提供一个相似变换矩阵的初始值,供下面一些函数调用
(2)hom_mat3d_translate 沿"旧"坐标轴进行平移: H 2 = H ( t ) ⋅ H 1 \mathbf{H}_2 = \mathbf{H}(\mathbf{t}) \cdot \mathbf{H}_1 H2=H(t)⋅H1
(3)hom_mat3d_translate_local 沿"新"坐标轴进行平移: H 2 = H 1 ⋅ H ( t ) \mathbf{H}_2 = \mathbf{H}_1 \cdot \mathbf{H}(\mathbf{t}) H2=H1⋅H(t)
(4)hom_mat3d_rotate 沿"旧"坐标轴进行旋转: H 2 = H ( R ) ⋅ H 1 \mathbf{H}_2 = \mathbf{H}(\mathbf{R}) \cdot \mathbf{H}_1 H2=H(R)⋅H1
(5)hom_mat3d_rotate_local 沿"新"坐标轴进行旋转: H 2 = H 1 ⋅ H ( R ) \mathbf{H}_2 = \mathbf{H}_1 \cdot \mathbf{H}(\mathbf{R}) H2=H1⋅H(R)
(6)hom_mat3d_compose 将两个相似变换矩阵相乘: H 3 = H 1 ⋅ H 2 \mathbf{H}_3 = \mathbf{H}_1 \cdot \mathbf{H}_2 H3=H1⋅H2
(7)hom_mat3d_invert 求一个相似变换矩阵的逆矩阵: H 2 = H 1 − 1 \mathbf{H}_2 = \mathbf{H}_1^{-1} H2=H1−1
(8)affine_trans_point_3d 使用一个相似变换矩阵转换一个点的坐标: p 2 = H 0 ⋅ p 1 p_2 = \mathbf{H}_0 \cdot p_1 p2=H0⋅p1
2.1.5 3D 位姿
相似变换矩阵是一种非常好的描述转换的方式,并且也方便进行计算。但是它们的内容也就是矩阵中的元素非常难以理解,尤其是旋转矩阵部分,非常难以从矩阵中读出旋转了多少角度等信息。使用称为三维位姿表示可以解决这个问题。
一个三维位姿其实就是刚性转换的一种比较容易理解的表示方式:代替相似变换矩阵的 12 个元素,一个位姿使用六个参数描述刚性转换,三个参数描述旋转,另外三个描述平移:(TransX, TransY, TransZ, RotX, RotY, RotZ)。位姿这种表示方式依据的主要原理是在坐标系中绕任意一个轴的旋转都可以表示为绕坐标系 x、y、z 三个轴的旋转序列。
在 HALCON 中,可以使用 create_pose 函数创建一个三维位姿;在三维位姿和相应的相似变换矩阵之间的转换可以使用函数 hom_mat3d_to_pose 和 pose_to_hom_mat3d。
2.1.5.1 旋转顺序
其实使用三个参数表示一个任意的旋转不只有一种方式。这个方式在 HALCON 函数 create_pose 中可以反映出来,在这个函数中你可以通过参数 OrderOfRotation 选择不同的位姿类型。如果选择这个参数的值为 ‘gba’,旋转可以表示为下面等式表述的旋转序列:
R g b a = R x ( RotX ) ⋅ R y ( RotY ) ⋅ R z ( RotZ ) (2.19) \mathbf{R}_{gba} = \mathbf{R}_x(\text{RotX}) \cdot \mathbf{R}_y(\text{RotY}) \cdot \mathbf{R}_z(\text{RotZ}) \tag{2.19} Rgba=Rx(RotX)⋅Ry(RotY)⋅Rz(RotZ)(2.19)
也可以将这个参数设置为 ‘abg’,这样旋转序列与上面的旋转序列相反:
R a b g = R z ( RotZ ) ⋅ R y ( RotY ) ⋅ R x ( RotX ) (2.20) \mathbf{R}_{abg} = \mathbf{R}_z(\text{RotZ}) \cdot \mathbf{R}_y(\text{RotY}) \cdot \mathbf{R}_x(\text{RotX}) \tag{2.20} Rabg=Rz(RotZ)⋅Ry(RotY)⋅Rx(RotX)(2.20)
例如,在上一节中讨论的转换可以用下面这个相似变换矩阵描述:
使用旋转次序为 ‘gba’ 的相应的三维位姿表示这个转换会更加直观:
( TransX = x t , TransY = y t , TransZ = z t , RotX = 0 , RotY = 90 ° , RotZ = − 90 ° ) (\text{TransX} = x_t, \text{TransY} = y_t, \text{TransZ} = z_t, \text{RotX} = 0, \text{RotY} = 90°, \text{RotZ} = -90°) (TransX=xt,TransY=yt,TransZ=zt,RotX=0,RotY=90°,RotZ=−90°)
如果你仔细看过图 2.5 的话,你能够理解这个旋转同样可以表示为序列 R z ( 90 ° ) R x ( 90 ° ) \mathbf{R}_z(90°) \mathbf{R}_x(90°) Rz(90°)Rx(90°)。因此,这个转换也可以使用下面的三维位姿(旋转序列为 ‘abg’)表示:
( TransX = x t , TransY = y t , TransZ = z t , RotX = − 90 ° , RotY = 0 , RotZ = − 90 ° ) (\text{TransX} = x_t, \text{TransY} = y_t, \text{TransZ} = z_t, \text{RotX} = -90°, \text{RotY} = 0, \text{RotZ} = -90°) (TransX=xt,TransY=yt,TransZ=zt,RotX=−90°,RotY=0,RotZ=−90°)

2.1.5.2 HALCON 算子
下面简要介绍一些 HALCON 中与处理三维位姿相关的一些函数。如果需要更详细的了解这些函数,请参考 Reference Manual。
(1)create_pose 创建一个三维位姿
(2)hom_mat3d_to_pose 将一个相似变换矩阵转换为一个三维位姿
(3)pose_to_hom_mat3d 将一个三维位姿转换为一个相似变换矩阵
(4)convert_pose_type 改变一个三维位姿的类型
(5)write_pose 将一个三维位姿写入一个文件
(6)read_pose 从一个文件中读取三维位姿
(7)set_origin_pose 沿"新"的坐标轴平移一个三维位姿
2.1.5.3 HALCON 如何确定一个坐标系的三维位姿
前面的章节我们介绍了如何用平移向量、旋转矩阵、相似变换矩阵或三维位姿表示一个已知的转换。但是有时我们需要使用一个三维位姿来表示一个坐标系的位置和方位,这种需要有时是必须的。比如当你使用你自己的标定物体,并且需要确定摄像机外参的初始值时。(section 3.1.3)
图 2.8 显示了一个非常简单的例子,这个例子是要确定世界坐标系相对于摄像机坐标系的三维位姿。
在这种情况下,我们建议使用单个平移和从左向右的旋转组成这个刚性转换。因此,在图十中摄像机坐标系首先进行平移,使坐标系原点和世界坐标系原点重合。这时,两个坐标系的 y 轴重合;通过绕平移后的摄像机坐标系的"新"的 y 轴旋转 180 度,就可以使摄像机坐标系和世界坐标系完全重合。这时就完成了这次的刚性转换,也就可以得到世界坐标系在摄像机坐标系中的三维位姿。
2.1.6 对偶四元数
2.1.6.1 单位对偶四元数,刚性转换及螺旋
与表示 3D 旋转的单位四元数相比,单位对偶四元数可以表示整个的 3D 刚性转换,比如 3D 旋转和平移。因此,单位对偶四元数是表示 3D 位姿和 3D 齐次变换矩阵的刚性转换的又一种表示形式。与含有 12 个元素的变换矩阵相比,含有 8 个元素的对偶四元数是一个更紧凑的表示方法。和变换矩阵类似,对偶四元数也可以容易的连接多个转换。此外,他们允许在两个 3D 刚性转换之间允许有一个平滑的插值,且在对于 3D 直接变换具有较高效率。
2.1.6.2 对偶四元数的介绍
一个对偶公式 q ^ = q r + ε ⋅ q d \hat{q} = q_r + \varepsilon \cdot q_d q^=qr+ε⋅qd 包含两部分 q r q_r qr 和 q d q_d qd, q r q_r qr 是实数部分, q d q_d qd 是对偶部分, ε \varepsilon ε 是对偶部分的单位,每一个公式 q = w + i x + j y + k z q = w + ix + jy + kz q=w+ix+jy+kz 由标量部分 w w w 和矢量部分 v = ( x , y , z ) v = (x, y, z) v=(x,y,z) 组成,其中 ( 1 , x , y , z ) (1, x, y, z) (1,x,y,z) 是四元数向量空间中的基元。
2.1.6.3 在 HALCON 中表示对偶四元数

在HALCON中,一个对偶四元数由一个含有8个元素的数组 [ w r , x r , y r , z r , w d , x d , y d , z d ] [w_r, x_r, y_r, z_r, w_d, x_d, y_d, z_d] [wr,xr,yr,zr,wd,xd,yd,zd] 组成,其中 w r w_r wr 和 v r \mathbf{v}_r vr 是实数部分的标量和向量部分, w d w_d wd 和 v d \mathbf{v}_d vd 是对偶部分的标量和向量部分。
每一个 3D 刚性变换都可以被表示成一个螺旋。
充分描述螺旋的具体参数是:

(1)旋转角度 θ \theta θ。
(2)螺旋平移 d d d。
(3)关于螺旋轴的方向 L = ( L x , L y , L z ) T \mathbf{L} = (L^x, L^y, L^z)^T L=(Lx,Ly,Lz)T,其中 ∥ L ∥ = 1 \|\mathbf{L}\| = 1 ∥L∥=1。
(4)关于螺旋轴矩 M = ( M x , M y , M z ) T \mathbf{M} = (M^x, M^y, M^z)^T M=(Mx,My,Mz)T,其中 L ⋅ M = 0 \mathbf{L} \cdot \mathbf{M} = 0 L⋅M=0。
一个螺旋由通过通过 L \mathbf{L} L 和 M \mathbf{M} M 得出的绕螺旋轴旋转的角度 θ \theta θ 和由 d d d 的表示的沿这个轴的平移组成。螺旋轴的位置由它的矩相对于坐标系的原点确定。 M \mathbf{M} M 是一个垂直于螺旋轴 L \mathbf{L} L 方向的矩,且垂直于由原点和旋转轴上的点 P 0 \mathbf{P}_0 P0 组成的向量。它同过向量积 M = P 0 × L \mathbf{M} = \mathbf{P}_0 \times \mathbf{L} M=P0×L 计算得到。
因此 M \mathbf{M} M 是由螺旋轴和原点组成的平面的法向量。注意, M = P 0 × L \mathbf{M} = \mathbf{P}_0 \times \mathbf{L} M=P0×L 是旋转轴 ( L , M ) (\mathbf{L}, \mathbf{M}) (L,M) 上的点,且其是旋转轴上距离原点最近的点。一个单位对偶四元数的元素以如下公式的形式相关于 3D 刚性变化的螺旋参数:
注意 q \mathbf{q} q 和 − q -\mathbf{q} −q 表示相同的刚性转换。此外注意一个单位对偶四元数的逆是它的共轭,比如(关于详细的对偶四元数的共轭的信息看算子 dual_quat_conjugate)。
2.1.6.4 HALCON 算子
(1)pose_to_dual_quat 将一个 3D 位姿转换为一个单位对偶四元数。
(2)dual_quat_to_pose 将一个单位对偶四元数转换为 3D 位姿。
(3)dual_quat_compose 两个单位对偶四元数相乘。
(4)dual_quat_interpolate 对两个对偶四元数间进行插值计算。
(5)dual_quat_to_screw 将一个单位对偶四元数转换为一个螺旋变换。
(6)screw_to_dual_quat 将旋转变换为对偶四元数
(7)dual_quat_to_hom_mat3d 将一个单位对偶四元数转换为一个齐次变换矩阵。
(8)dual_quat_trans_line_3d 利用单位对偶四元数选择一条直线 3D
(9)dual_quat_conjugate 求单位对偶四元数的共轭。
(10)dual_quat_normalize 规范化一个对偶四元数。
(11)serialize_dual_quat 序列化一个对偶四元数。
(12)deserialize_dual_quat deserializes 反序列化的对偶四元数。
2.2 相机模型和参数
如果你想从图像中获得精确的世界坐标,你需要首先标定你的摄像机。对摄像机进行标定,需要了解摄像机模型,即如何将世界坐标系中的某点通过摄像机、镜头和图像采集设备映射到二维图像中。
使用 HALCON 可以对两种不同类型的摄像机进行标定:面阵摄像机和线阵摄像机。面阵摄像机只需要一步就可以获得图像,线阵摄像机拍摄图像需要一行一行的采集。(可以参看 HALCON 应用文档中的"图像获取"部分的 section 6.6)因此,线阵摄像机拍摄过程就需要物体和摄像机之间有相对运动。
有两种不同类型的镜头,应据不同的机器视觉任务选择适用的镜头。第一种镜头和人眼类似,通过透视投影从世界坐标转换到图像坐标。使用这种镜头时,物体距离摄像机越远,它所成的像就越小。这种镜头和摄像机一起就组成针孔摄像机模型,因为透视投影也可以通过下述的装置实现,在一个非常薄的平面物体上钻一个小孔,然后将这个平面平行放置在另一个平面(成像平面)前。
第二种和机器视觉相关的镜头成为远心镜头。它和第一种镜头的主要区别是在从世界坐标转换到图像坐标时是平行投影(物体和摄像机之间距离在某个确定的范围内)。这就表明物体在图像中的大小不随物体离摄像机的距离发生变化。这种镜头和摄像机的组合称为远心摄像机模型。
下面我们首先详细介绍面阵摄像机模型,然后再介绍线阵摄像机。
2.2.1 世界坐标系中点映射到像素坐标
将世界坐标系中点 3D 点 p w = ( x w , y w , z w ) T p^w = (x^w, y^w, z^w)^T pw=(xw,yw,zw)T 转换到像素坐标系中的 2D 点,需要一系列的转换。
p w → p c → q c → q ~ c [ → q t ] → q i (2.22) p^w \rightarrow p^c \rightarrow q^c \rightarrow \tilde{q}^c \left[\rightarrow q^t\right] \rightarrow q^i \tag{2.22} pw→pc→qc→q~c[→qt]→qi(2.22)
首先, p w p^w pw 转换到摄像机坐标系表示为 p c p^c pc,然后 p c p^c pc 被透视映射到图像平面,比如转换到 2D 点 q c q^c qc, q c q^c qc 任意度量单位。然后,镜头畸变应用与 q c q^c qc,将其转换到畸变的点 q ~ c \tilde{q}^c q~c,如果使用的是一个倾斜的镜头, q ~ c \tilde{q}^c q~c 要取决于一个没有倾斜系统中的虚拟图像平面。这通过将 q ~ c \tilde{q}^c q~c 透视到倾斜的图像平面上的 q t q^t qt 校正。最后,畸变的点 q ~ c \tilde{q}^c q~c(或 q t q^t qt)被转换到像素坐标系,产生最后的结果点 q i q^i qi。
2.2.2 面扫描相机
图 2.11 中表示了针孔摄像机的投影透视。世界坐标系中某点 P \mathbf{P} P 通过镜头的光心投影到图像平面的 P ′ \mathbf{P}' P′ 点,图像平面位于镜头光心后端 f f f 处。 f f f 是镜头的焦距。
虽然图像平面事实上是在镜头光心的后端,我们可以假设图像平面在镜头光心前端 f f f 处(图 2.12)。这时图像坐标系和世界坐标系的坐标系的方向一致(横轴向右,纵轴向下),这样可以简化大多数的计算。
2.2.2.1 转换到相机坐标系(外部相机参数)
现在我们就开始描述三维世界坐标系中的物体如何投影到二维图像平面以及相应的摄像机参数。首先我们应该注意世界坐标系(WCS)中点 P \mathbf{P} P。为了能够投影到图像平面,这些点应该首先被转换到摄像机坐标系(CCS)中。摄像机坐标系的 x x x 轴和 y y y 轴分别与图像坐标系的纵轴和横轴平行,它的 z z z 轴垂直于图像平面,它的原点在镜头的光心处。
从世界坐标系到摄像机坐标系的转换是刚性转换,可以使用三维位姿或相似变换矩阵 c H w {}^c\mathbf{H}_w cHw 表示。因此,摄像机坐标系中的某点 P \mathbf{P} P 的坐标 p c = ( x c , y c , z c ) T p^c = (x^c, y^c, z^c)^T pc=(xc,yc,zc)T 可以通过该点在世界坐标系中的坐标 p w = ( x w , y w , z w ) T p^w = (x^w, y^w, z^w)^T pw=(xw,yw,zw)T 计算得到:
p c = c H w ⋅ p w (2.23) p^c = {}^c\mathbf{H}_w \cdot p^w \tag{2.23} pc=cHw⋅pw(2.23)
这个转换的六个参数(三个平移参数 t x , t y t_x, t_y tx,ty 和 t z t_z tz 以及三个旋转参数 α , β , γ \alpha, \beta, \gamma α,β,γ)被称为摄像机的外部参数,因为它们决定了摄像机在世界坐标系中的位置和方位。在 HALCON 中,摄像机的外参存为一个 pose,也就是一个描述平移和旋转次序的代号。
2.2.2.2 投影
下一步就是将摄像机坐标系中的某个三维点投影到图像平面坐标系(IPCS)。对针孔摄像机模型来说,这个投影是投射投影,可以使用下面的公式表示:
q c = ( u v ) = f z c ( x c y c ) (2.24) q^c = \begin{pmatrix} u \\ v \end{pmatrix} = \frac{f}{z^c} \begin{pmatrix} x^c \\ y^c \end{pmatrix} \tag{2.24} qc=(uv)=zcf(xcyc)(2.24)
对于远心摄像机模型,投影是平行投影,使用下面公式表示:
q c = ( u v ) = m ( x c y c ) (2.25) q^c = \begin{pmatrix} u \\ v \end{pmatrix} = m \begin{pmatrix} x^c \\ y^c \end{pmatrix} \tag{2.25} qc=(uv)=m(xcyc)(2.25)
2.2.2.3 镜头畸变
投影到图像平面后,镜头畸变使 ( u , v ) T (u, v)^T (u,v)T 坐标系中点 q c q^c qc 变到 q ~ c = ( u ~ , v ~ ) T \tilde{q}^c = (\tilde{u}, \tilde{v})^T q~c=(u~,v~)T。这种影响在图 2.13 中被说明。如果没有透视投影畸变, P ′ \mathbf{P}' P′ 应该在 P \mathbf{P} P 点与光心连线的延长线上,镜头畸变导致投影点的位置发生了改变。
镜头畸变是一种可以在图像平面上建模的变换,比如三维信息不是必须的。在 HALCON 中畸变可以被表示为区域模型或多项式模型。
区域模型使用一个参数 ( k ) (k) (k) 表示径向畸变模型。若区域模型被使用,下述公式将畸变了的图像平面坐标系转换到没有畸变的图像平面坐标系。
u = u ~ 1 + κ ( u ~ 2 + v ~ 2 ) and v = v ~ 1 + κ ( u ~ 2 + v ~ 2 ) (2.26) u = \frac{\tilde{u}}{1 + \kappa(\tilde{u}^2 + \tilde{v}^2)} \quad \text{and} \quad v = \frac{\tilde{v}}{1 + \kappa(\tilde{u}^2 + \tilde{v}^2)} \tag{2.26} u=1+κ(u~2+v~2)u~andv=1+κ(u~2+v~2)v~(2.26)
这些公式可以被反向分析,得到下述公式,如果使用的是区域模型,则公式表示将畸变的图像坐标转换到未畸变的图像坐标系。
u ~ = 2 u 1 + 1 − 4 κ ( u 2 + v 2 ) and v ~ = 2 v 1 + 1 − 4 κ ( u 2 + v 2 ) (2.27) \tilde{u} = \frac{2u}{1 + \sqrt{1 - 4\kappa(u^2 + v^2)}} \quad \text{and} \quad \tilde{v} = \frac{2v}{1 + \sqrt{1 - 4\kappa(u^2 + v^2)}} \tag{2.27} u~=1+1−4κ(u2+v2)2uandv~=1+1−4κ(u2+v2)2v(2.27)



参数 κ \kappa κ 表示了径向畸变的形式。如果 κ \kappa κ 为负值,表示为桶形畸变,若为正值,表示为枕形畸变(看图 2.14)。
多项式模型使用三个参数 ( K 1 , K 2 , K 3 ) (K_1, K_2, K_3) (K1,K2,K3) 来表示径向畸变,使用参数 ( P 1 , P 2 ) (P_1, P_2) (P1,P2) 来表示偏心畸变。若使用多项式模型,则下述公式将畸变的图像平面坐标转换为未畸变的图像坐标。

u = u ~ + u ~ ( K 1 r 2 + K 2 r 4 + K 3 r 6 ) + 2 P 1 u ~ v ~ + P 2 ( r 2 + 2 u ~ 2 ) v = v ~ + v ~ ( K 1 r 2 + K 2 r 4 + K 3 r 6 ) + P 1 ( r 2 + 2 v ~ 2 ) + 2 P 2 u ~ v ~ (2.28, 2.29) \begin{aligned} u &= \tilde{u} + \tilde{u}(K_1 r^2 + K_2 r^4 + K_3 r^6) + 2P_1 \tilde{u}\tilde{v} + P_2(r^2 + 2\tilde{u}^2) \\ v &= \tilde{v} + \tilde{v}(K_1 r^2 + K_2 r^4 + K_3 r^6) + P_1(r^2 + 2\tilde{v}^2) + 2P_2 \tilde{u}\tilde{v} \end{aligned} \tag{2.28, 2.29} uv=u~+u~(K1r2+K2r4+K3r6)+2P1u~v~+P2(r2+2u~2)=v~+v~(K1r2+K2r4+K3r6)+P1(r2+2v~2)+2P2u~v~(2.28, 2.29)
其中 r = u ~ 2 + v ~ 2 r = \sqrt{\tilde{u}^2 + \tilde{v}^2} r=u~2+v~2。这些公式不能被反向分析。因此,畸变的图像平面坐标必须由未畸变图像平面坐标来表示。
一些可以用多项式模型来表示的畸变的例子展示在图 2.15 中。
| K 1 K_1 K1 | K 2 K_2 K2 | K 3 K_3 K3 | P 1 P_1 P1 | P 2 P_2 P2 | |
|---|---|---|---|---|---|
| (a) | < 0 < 0 <0 | 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 |
| (b) | > 0 > 0 >0 | 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 |
| © | < 0 < 0 <0 | > 0 > 0 >0 | < 0 < 0 <0 | 0 0 0 | 0 0 0 |
| (d) | < 0 < 0 <0 | 0 0 0 | 0 0 0 | < 0 < 0 <0 | 0 0 0 |
| (e) | < 0 < 0 <0 | 0 0 0 | 0 0 0 | 0 0 0 | < 0 < 0 <0 |
| (f) | < 0 < 0 <0 | > 0 > 0 >0 | < 0 < 0 <0 | < 0 < 0 <0 | > 0 > 0 >0 |
2.2.2.4 镜头倾斜
如果是一个倾斜镜头,镜头相对于图像平面的倾斜由两个参数来描述,旋转角度 ρ \rho ρ( 0 ° ≤ ρ < 360 ° 0° \le \rho < 360° 0°≤ρ<360°),描述了倾斜轴的方向,以及倾斜角 τ \tau τ( 0 ° ≤ τ ≤ 90 ° 0° \le \tau \le 90° 0°≤τ≤90°),描述了光轴和传感器之间的倾斜(图 2.16)。
对于倾斜的镜头,有不同的相机模型,他们也有不同的几何表示(图 2.17),进一步注意,光不同的入射角将得到不同的结果。


对于投影透视倾斜和物体侧远心镜头倾斜,依赖于倾斜图像平面的由 q ~ c = ( u ~ , v ~ ) T \tilde{q}^c = \begin{pmatrix} \tilde{u}, \tilde{v} \end{pmatrix}^T q~c=(u~,v~)T 到 q t = ( u ^ , v ^ ) T q^t = \begin{pmatrix} \hat{u}, \hat{v} \end{pmatrix}^T qt=(u^,v^)T 的投影由一个 2D 投影转换来表示,比如用齐次矩阵 H \mathbf{H} H。
q t = H ⋅ q ~ c (2.30) q^t = \mathbf{H} \cdot \tilde{q}^c \tag{2.30} qt=H⋅q~c(2.30)
其中
其中 Rot = ρ \text{Rot} = \rho Rot=ρ, Tilt = τ \text{Tilt} = \tau Tilt=τ。
对于图像侧远心镜头倾斜和双边远心镜头倾斜,到倾斜图像平面的映射有一个线性 2D 转换表示,比如通过一个 2 × 2 2 \times 2 2×2 矩阵。
H = ( h 11 h 12 h 21 h 22 ) = 1 q 11 q 22 − q 12 q 21 ( q 22 − q 12 − q 21 q 11 ) (2.32) \mathbf{H} = \begin{pmatrix} h_{11} & h_{12} \\ h_{21} & h_{22} \end{pmatrix} = \frac{1}{q_{11}q_{22} - q_{12}q_{21}} \begin{pmatrix} q_{22} & -q_{12} \\ -q_{21} & q_{11} \end{pmatrix} \tag{2.32} H=(h11h21h12h22)=q11q22−q12q211(q22−q21−q12q11)(2.32)
其中 Q \mathbf{Q} Q 如上所示,为镜头投影被定义。
2.2.2.5 转换为像素坐标
最后,点 q c = ( u , v ~ ) T q^c = \begin{pmatrix} u, \tilde{v} \end{pmatrix}^T qc=(u,v~)T(或者 q t q^t qt,若镜头倾斜)由图像平面坐标系转换到图像坐标系(像素坐标系)。
q i = ( r c ) = ( v ^ S y + C y u ^ S x + C x ) (2.33) q^i = \begin{pmatrix} r \\ c \end{pmatrix} = \begin{pmatrix} \dfrac{\hat{v}}{S_y} + C_y \\ \dfrac{\hat{u}}{S_x} + C_x \end{pmatrix} \tag{2.33} qi=(rc)= Syv^+CySxu^+Cx (2.33)
在这里, S x S_x Sx 和 S y S_y Sy 是比例因子。对于针孔相机,它们代表相机中 CCD 芯片上传感器单元的水平和垂直距离。对于远心相机,它们代表了一个像素在世界坐标系中的尺寸(不考虑镜头畸变)。 ( C x , C y ) T (C_x, C_y)^T (Cx,Cy)T 是图像的主点。对于针孔相机,这是由光学中心垂直投影到了图像平面,比如,通过光学中心垂直于图像平面的点。其也定义了径向畸变的中心,对于远心镜头,不存在光学中心,主点仅通过光学畸变定义。
参数 f f f,放大率, k ; K 1 ; K 2 ; K 3 ; P 1 ; P 2 ; t ; ρ ; S x ; S y ; C x ; C y k; K_1; K_2; K_3; P_1; P_2; t; \rho; S_x; S_y; C_x; C_y k;K1;K2;K3;P1;P2;t;ρ;Sx;Sy;Cx;Cy 被称作相机内部参数,因为他们决定了由相机完成的由 3D 到 2D 的映射。此外注意,相机类型,图像宽高,以及仅对于 object-side telecentric 倾斜镜头时的参数 ImagePlaneDist,需要被给出。依赖于相机类型,镜头类型以及镜头畸变模型,需要的一系列的参数列表如下:

创建相机参数数组,可以使用 HALCON 中不同的算子。其中一个算子适用于任何的相机模型,gen_cam_par_area_scan_division。
v相机标定的过程就是确定相机内部参数和外部参数 ( t x ; t y ; t z ; α ; β ; γ ) (t_x; t_y; t_z; \alpha; \beta; \gamma) (tx;ty;tz;α;β;γ) 的过程。
2.2.3 倾斜镜头和移轴景深光学原理
在正常的程序中图像平面正交于镜头的光轴。为防止有些时候导致不理想的作用的严重的放大,以一定角度观察的物体由于有限的景深物体的一部分会对焦不准。
为避免这种情况,镜头或者图像平面可能会倾斜来迎合交线条件:图像平面、镜头平面以及焦平面相交于一条直线。这样,即可能使物体的成像平是完全焦距对准的(清晰的),即使他们不垂直于相机。
使用倾斜的镜头是非常有效的在景深不大的情况下,比如由于视野比较小,大的放大倍数,或小的焦距。在这些情况下,使用一个倾斜的镜头来适应焦平面以更好的适应观察到的场景是有必要的。
这是一些典型的情形:
(1)物理遮挡:如果空间对象的正上方被遮挡,比如传送带上的一些部件,相机只能以一定角度安装才能看到整个物体。倾斜的镜头即可以用来是焦平面与物体平面对齐。
(2)立体视觉:在大多数的立体视觉程序中,使用的相机在不同的角度观察场景。这意味着,当使用普通镜头时,他们的焦平面不是平行的,比如每一个相机焦距对准覆盖物体的不同体积。当景深更小或相机间角度更大时,可以使焦距对准的体积会更小,这可能会导师严重的问题对于重建。倾斜的镜头可以被使用来连接不同相机的焦平面(1.1.3节)。

(3)片光(Sheet of Light):在片光程序中,一条激光被投影到场景中,而相机接受射到物体上光线的反射。为得到更精确的结果,将相机的焦平面连接起来是理想的,其中片光由激光器产生。而使用正常的镜头这通常是不可能的。
注意:如果没有可用的倾斜的镜头,在一些应用中通过使用一个更高焦距的镜头来提高景深是充分的,比如,一个小孔。当然,这表明需要增加曝光时间(这可能会增加整个周期时间)或使用更强的光照。
2.2.4 线阵相机
线阵摄像机的感光芯片是由感光元素组成的一维线段,也就是说,如果想得到一个物体的图像,摄像机必须和物体之间发生相对运动。可以在固定物体上方移动摄像机、在固定摄像机前移动物体或者摄像机和物体两个都发生运动。
摄像机和被测物体之间的相对运动在HALCON中被表示为摄像机的内参。在HALCON中,假设这个相对运动有以下几个属性。
1).摄像机的运动——相对于被测物体——是沿一条直线的匀速运动。
2).摄像机相对于物体的方位在运动的过程中是固定不变的。
3).摄像机的运动在拍摄所有图像期间保持一致。
这个运动被表示为一个运动向量 V = ( V x , V Y , V Z ) T V = (V_x, V_Y, V_Z)^T V=(Vx,VY,VZ)T,这个向量在摄像机坐标系中定义,其中元素的单位为[meters/scanline]。这个运动向量描述了摄像机的运动,也就是说它假定物体是固定不动的。实际上,这个向量等价于在一个固定摄像机前物体以速度 − V -V −V 移动。
线阵摄像机的摄像机坐标系的定义可以参看(figure2.21):摄像机坐标系的原点在投影中心。Z轴与光轴方向一致并且保证所有可视点的Z坐标都为正。Y轴垂直于Z轴和线阵传感器组成的平面,它的方向保证运动向量的 y y y 元素为正值,也就是说如果假设物体固定不动, y y y 轴的方向就是指向摄像机移动的方向。X轴垂直于Y轴和Z轴形成的平面,并且三个轴组成右旋坐标系(right-handed coordinate system)。
与线阵摄像机类似,世界坐标系中的某点投影到图像中分为两个步骤:首先,这个点从世界坐标系转换到摄像机坐标系中。然后在映射到图像中。
图像采集的过程中摄像机在被测物体上方移动,此时摄像机坐标系和物体也会发生相对运动,也就是说在拍摄每一行图像时摄像机的位置都不同。这就意味着每一行图像数据都对应着一个单独的三维位姿。为了使这个事情简单化,在HALCON中所有世界坐标系与摄像机坐标系之间的相互转换都是基于拍摄第一行图像数据时摄像机的位姿。在进行点的投影时,HALCON会将运动向量 V V V 考虑进去。
从世界坐标系到拍摄第一行图像数据时摄像机坐标系的转换是一个刚性转换,可以表示为一个三维位姿或一个相似变换矩阵 c H w ^cH_w cHw。因此,摄像机坐标系中某点P的坐标 p c = ( x c , y c , z c ) T p^c = (x_c, y_c, z_c)^T pc=(xc,yc,zc)T 可以通过该点在世界坐标系中的坐标 p w = ( x w , y w , z w ) T p^w = (x_w, y_w, z_w)^T pw=(xw,yw,zw)T 计算得到:
p c = c H w ⋅ p w (2.34) p^c = {^cH_w} \cdot p^w \tag{2.34} pc=cHw⋅pw(2.34)

这个转换的六个参数(三个平移参数 t x , t y , t z t_x, t_y, t_z tx,ty,tz 和三个旋转参数 α , β , γ \alpha, \beta, \gamma α,β,γ)被称为摄像机的外参,它们确定摄像机在世界坐标系中的位置和方位。在HALCON中这个外参存为一个pose,表示某种顺序的平移和旋转。
对线阵摄像机来讲,摄像机坐标系中的点 p c p^c pc 到图像中第一行的某个像素(亚像素)[r,c]的投影可以通过下述方程来表示:
假设
p c = ( x y z ) p^c = \begin{pmatrix} x \\ y \\ z \end{pmatrix} pc=
xyz
通过下面几个等式求出 m , u m, u m,u 和 t t t:
m ⋅ D ⋅ u ~ = x − t ⋅ V x − m ⋅ D ⋅ p v = y − t ⋅ V y m ⋅ f = z − t ⋅ V z \begin{aligned} m \cdot D \cdot \tilde{u} &= x - t \cdot V_x \\ -m \cdot D \cdot p_v &= y - t \cdot V_y \\ m \cdot f &= z - t \cdot V_z \end{aligned} m⋅D⋅u~−m⋅D⋅pvm⋅f=x−t⋅Vx=y−t⋅Vy=z−t⋅Vz
并且
D = 1 1 + κ ( u ~ 2 + p v 2 ) p v = S y ⋅ C y \begin{aligned} D &= \frac{1}{1 + \kappa(\tilde{u}^2 + p_v^2)} \\ p_v &= S_y \cdot C_y \end{aligned} Dpv=1+κ(u~2+pv2)1=Sy⋅Cy
这些等式中已经包含了对径向畸变的校正。
最后,点的坐标可以转换到图像坐标系中,也就是像素坐标系中:
c = u ~ S x + C x and r = t c = \frac{\tilde{u}}{S_x} + C_x \quad \text{and} \quad r = t c=Sxu~+Cxandr=t
S x S_x Sx 和 S y S_y Sy 是缩放比例因子。 S x S_x Sx 表示线阵CCD上各个传感器元素之间的距离, S y S_y Sy 是各个传感器元素在 y y y 方向的长度。点 ( C x , C y ) T (C_x, C_y)^T (Cx,Cy)T 是主要点。注意与面阵摄像机有所不同, ( C x , C y ) T (C_x, C_y)^T (Cx,Cy)T 并不是表示这个主要点在图像坐标系中的位置,而是表示这个点与线阵CCD传感器之间的相对位置。
对于小孔线阵摄像机模型来说,上述九个参数 ( f , k , S x , S y , C x , C y , V x , V y , V z ) (f, k, S_x, S_y, C_x, C_y, V_x, V_y, V_z) (f,k,Sx,Sy,Cx,Cy,Vx,Vy,Vz) 被称为摄像机的内参,因为这些参数决定了三维空间到二维图像中的投影关系。
和线阵摄像机一样,线阵摄像机的标定其实就是确定线阵摄像机内参 ( f , k , S x , S y , C x , C y , V x , V y , V z ) (f, k, S_x, S_y, C_x, C_y, V_x, V_y, V_z) (f,k,Sx,Sy,Cx,Cy,Vx,Vy,Vz) 与拍摄图像第一行时摄像机外参 ( t x , t y , t z , α , β , γ ) (t_x, t_y, t_z, \alpha, \beta, \gamma) (tx,ty,tz,α,β,γ) 的过程。
2.3 3D物体模型
三维物体模型是一种描述三维物体的数据结构。3D物体模型可以通过多种方式得到,且他们可能包括不同类型的数据。此外,使用3D物体模型的不同算子关于模型的内容有不同的要求。因此,不是每一个算子都可以被应用到每一三维物体模型上。以下章节提供了关于对3D模型相关应用的基本知识
1).怎样获得三维物体模型(2.3.1节)。
2).三维物体模型中存储了哪些信息(2.3.2节)。
3).怎样改变三维模型(2.3.3)。
4).如何访问三维物体模型的特定特征(2.3.4)。
5).怎样表示(register)三维物体模型,也就是,怎样匹配相同物体的不同模型或者匹配重叠的物体的一部分(2.3.5节)。
6).怎样观看三维物体模型(2.3.6节)。
2.3.1 获取三维物体模型
下述章节简单介绍了可以获取三维物体模型的几种方式。通产,3D物体模型可以是
1).创建通过开始时物体表面的点的坐标或通过设置一个简单3D形状的参数(2.3.1.1节)。
2).从CAD获取(2.3.1.2节)。
3).从一种可行的3D重建方法中导出(2.3.1.3节)。
2.3.1.1 从开始创建三维物体模型
三维物体模型可以从开始被创建通过使用给出的近似物体表面的点或通过使用简单的三维物体模型参数,比如长方体、球、圆柱、或平面等被称作"3D基元"的简单形状。特别的,一下算子可以用来从开始创建三维物体模型。
1). gen_empty_object_model_3d 创建一个可以填充内容的空的三维物体模型,比如,使用2.3.3.2节中介绍的算子 set_object_model_3d_attrib_mod 或 set_object_model_3d_attrib。
2). gen_object_model_3d_from_points 创建一个由点组成的三维物体模型。
3). gen_box_object_model_3d 创建一个长方体原始基元。
4). gen_sphere_object_model_3d 或 gen_sphere_object_model_3d_center 创建一个球形3D基元。
5). gen_cylinder_object_model_3d 创建一个圆柱形3D物体基元。
6). gen_plane_object_model_3d 创建一个平面型3D物体基元。
比如,在HDevelop例程hdevelop\3D-Object-Model\Creation\set_object_model_3d_attrib.hdev,利用算子 gen_empty_object_model_3d 创建了一个空的三维物体模型,并使用算子 set_object_model_3d_attrib_mod 填充了一个立方体的点的坐标(2.3.3.2节)。一个简单点集的3D模型结果显示在图2.22的左侧。
gen_empty_object_model_3d (ObjectModel3D)
PointCoordX := [0.5,0.1,1.1,0.0,1.1,0] - 0.5
PointCoordY := [0,1.1,1.1,1.0,0.0,0] - 0.5
PointCoordZ := [0.5,0.0,1.1,1.0,0.0,1.1] - 0.5
set_object_model_3d_attrib_mod (ObjectModel3D, ['point_coord_x', 'point_coord_y','point_coord_z'], [], \
[PointCoordX,PointCoordY,PointCoordZ])
相比的,HDevelop例程hdevelop\3D-Object-Model\Creation\gen_primitives_object_model_3d.hdev通过指定它们的参数创建不同的3D基元。结果的3D模型显示在图2.22的右侧。
gen_plane_object_model_3d ([0.0,0.0,0.0,0.0], [], [], ObjectModel3DPlane1)
gen_sphere_object_model_3d ([0.0,3.0,0.0,0.0], 0.5, ObjectModel3DSphere1)
gen_sphere_object_model_3d_center (-1, 0, 1, 1, ObjectModel3DSphere2)
gen_cylinder_object_model_3d ([1,-1.2,0.0,60.0], 0.5, -1, 1, \ObjectModel3DCylinder)
gen_box_object_model_3d ([-1.2,1.0,0.0,90.0], 1, 2, 1, ObjectModel3DBox)
2.3.1.2 从CAD获取三维物体模型
如果3D模型已经是一个可用的CAD模型,比如DXF或PLY文件,3D模型可简单的利用算子 read_object_model_3d 获取。如图所示,比如HDevelop例程 hdevelop\3D-Object-Model\Features\smallest_bounding_box_object_model_3d.hdev(图2.33)。请到算子目录看算子 read_object_model_3d 支持的所有格式及他们的描述。
read_object_model_3d (‘pipe_joint’, ‘m’, [], [], ObjectModel3D, Status)

2.3.1.3 通过三维重建获取三维物体模型
所有的三维重建方法都可以显示或隐式的导出三维物体模型。比如使用夺目立体视觉你可以明确的获取3D物体模型。而使用一个3D传感器可以获取X,Y和Z图像及焦点深度图。
X,Y和Z图像隐式的包含了3D物体模型需要的信息。因此你可以利用X,Y和Z图像导出一个三维物体模型使用算子 xyz_to_object_model_3d,如图所示,比如在HDevelop例程hdevelop\3D-Object-Model\Features\select_object_model_3d.hdev(图2.24)。
ImagePath := 'time_of_flight'
read_image (Image, ImagePath + 'engine_cover_xyz_01')
scale_image (Image, Image, .001, 0)
zoom_image_factor (Image, Image, 2, 2, 'constant')
decompose3 (Image, X, Y, Z)
xyz_to_object_model_3d (X, Y, Z, ObjectModel3DID)
如果 Π \Pi Π 是一个(标定过的)深度图,即一个Z图像,你可以这样创建相关的X及Y图像:X和Y图像必须和Z图像有相同的尺寸。其中X图像的创建是通过将Z图像的column数设置为X图像相应列(column)的每一个row坐标,Y图像的创建是通过将Z图像的row数设置为Y图像相应行的每一个column坐标,图2.25是简单(像素精度)的插图示例。之后X,Y,Z图像即可被再次转换为一个3D物体模型。

图2.26指导使用不同的方法导出可以使用的3D物体模型,比如下面的3D识别方法。
2.3.2 三维物体模型的内容
以下章节简要给出了如下信息:
(1)3D对象模型中存储的是什么信息(2.3.2.1节)。
(2)怎样获取指定的3D对象模型中的信息(2.3.2.2节)。
2.3.2.1 三维物体模型中包含的信息
由于三位对象模型可以通过多种方法获取,3D物体模型中包含的信息随模型的不同而不同。比如,如果一个三维对象模型被明确的通过给出的点使用算子gen_object_model_3d_from_points创建,这个三维对象模型中的基本信息是一系列点的坐标。相反,由一个的3D基元参数显示的创建的3D模型不包含点的信息,但包含相关的简单3D形状参数。
通常,一个指定的3D模型包含的内容取决于模型创建或导出的具体过程。例如,如果一个3D模型由一个(标定的)3D重建过程得出,例如立体视觉,片光,或深度聚焦,其包含点信息。如果在这样一个3D模型应用一个3D基元拟合,生成的3D模型包含点及基元的参数。含有这样三维信息的3D模型比知识通过3D基元参数创建的3D模型包含更多的信息。
一个有X,Y,Z图像获取的3D物体信息通常包含3D点的坐标信息及相关的二维映射,比如,3D点到二维图像平面的映射,而由多目立体视觉获取的3D对象模型会包含更多的信息。
例如,物体模型可能表面可能被三角形或多边形化。三角形也可以显示的被应用在包含点的3D对象模型上使用算子triangulate_object_model_3d。其他的修改3D物体模型的操作在2.3.3节介绍。
下面列出了三维物体模型中包含的不同类型数据。
1).点:三维点的坐标。
如果点信息被包含在三维物体模型中,更多参数可以是:
- 三角形:表达三角形的3D点的索引。
- 线:表达线的3D点的索引。
- 面:表达面的3D点的索引。
- 法线:法向量。
- xyz映射:3D点到图像坐标的映射。
2).基础
如果原始信息包含在3D物体模型中,更多的参数是:
- 初始类型:初始的类型(平面,球,立方体,圆柱)。
- 初始位姿:初始模型的位置和方向。
- 初始的Rms:初始参数的精度(只在其是在将基础模型拟合成点云时确定的的情况下有效)。
注意一个3D模型最多可能包含一个基础模型。
3).扩展属性
- 属性名称:为3D模型定义的扩展属性的名称。
- 属性类型:为3D模型定义的扩展属性的类型。
(3)附加属性
- 基于形状的数据:3D模型是否已经准备好基于形状的3D匹配的标志。
- 距离计算:3D模型是否已经准备好距离计算的标志。
内容以属性的形式被表示,且可以通过算子get_object_model_3d_params获取。详细信息看算子目录。
2.3.2.2 从指定三维物体模型中获取信息
由于存在许多获取和修改3D物体模型的方法,也有许多不同组合的信息可以包含在模型中。来获取一个指定的3D物体模型的实际的内容信息,可以使用算子get_object_model_3d_params。利用该算子,可以查询所谓的’attribute’的具体信息是否包含在模型中。比如,可以查询3D物体模型是否包含基元信息,点信息,法线,‘三角化’,面,2D映射等信息。若一个属性被包含在3D模型中,你可以查询该属性具体的值用相同的算子。
注意这里值是列出了一些比较常用的属性。3D物体模型中可以包含的所有属性信息及他们的描述可以提供在算子手册set_object_model_3d_params中。
另一个可以检查3D物体模型信息的方法是HDevelop中的一个专门的检测窗口。这里,在之前章节中列出的三维物体模型的参数属性被显示出来如HDevelop User’s Guide, section 6.7.7 on page 196.描述的一样。
2.3.3 修改三维物体模型
下面章节叙述了怎样修改3D物体模型。
1).为接下来的3D位姿识别做准备(2.3.3.1节)。
2).添加属性内容(2.3.3.2节)。
3).减少内容为指定的属性(2.3.3.3节)。
4).改变他们包含的点集,比如,减少点的数量或选择具有具体特征的点(2.3.3.4节)。
5).转换他们(2.3.3.5节)。
6).将几个3D物体模型结合成一个(2.3.3.6节)。
2.3.3.1 为3D位姿识别准备3D对象模型
一些3D位姿识别方法需要3D物体模型作为输入。尤其是3D基元拟合(4.5节)中应用的基于形状的3D匹配(4.2节)和分割需要的指定信息可能只是隐式的包含在3D物体模型中。为这些3D识别方法中的一种准备一个三维物体模型,也就是,更快的访问这些信息,你可以使用算子prepare_object_model_3d。那里,对于基于形状的3D匹配,参数Purpose需要被设置为'shape_based_matching_3d',而对于3D分割其需要被设置为'segmentation'。
注意,基于表面的3D匹配则不需要这样的准备,但是仍可能被需要如果使用参数'hidden_surface_removal'或'min_face_angle'的可视化的操作符project_object_model_3d被使用。之后,和基于形状的3D匹配类似,prepare_object_model_3d中的参数Purpose需要被设置为'shape_based_matching_3d'。
2.3.3.2 为3D对象模型添加属性
有时,对于接下来的操作需要指定的属性信息,这些信息没有明确的包含在3D模型中而知识隐式的包含在3D物体模型中。之后,不同的操作可以被用来使隐式的信息变为显式的或手动的增加或改变指定的属性,比如:
1).set_object_model_3d_attrib和set_object_model_3d_attrib_mod可以被用来手动的增加3D模型的属性或改变已有的属性。两个算子的不同之处在于set_object_model_3d_attrib返回一个新的3D物体模型而set_object_model_3d_attrib_mod是改变输入的3D物体模型。除了在创建或改变3D物体模型时可以利用不同的算子获取标准的属性,一个所谓的外部(“extended”)属性可以被设置,比如新的属性可以被用户自己定义并添加到模型上。这些属性必须在参数名称(Name)中在前面用符号"&"标明。
2).surface_normals_object_model_3d 可以被用来添加法线属性到三维物体模型上。
3).triangulate_object_model_3d 可以被用来为一个包含点和点法线的 3D 物体模型添加三角属性。特别的,包含三角剖分的 3D 物体模型信息或者和 3D 物体模型中点集完美拟合("greedy"算法)或者近似拟合("implicit"算法)。
4).fit_primitives_object_model_3d 可以用来获取 3D 基元相关的属性信息。特别的,其可以被用来给与 3D 原始模型中的点集拟合非常好的 3D 基元添加参数信息。注意,在这样的 3D 基元拟合之前通常会有一个分割将 3D 物体模型分割成不同的 3D 物体模型,其中这些 3D 物体模型就像 4.5 节中描述的那样有相似的特征。
怎样使用算子set_object_model_3d_attrib和set_object_model_3d_attrib_mod有例程hdevelop\3D-Object-Model\Creation\set_object_model_3d_attrib.hdev。在该例程中,立方体角落点坐标信息被添加到一个空的3D物体模型中,这已经在2.3.1.1节中介绍过。此外,三角属性及相关的三角化信息被添加。
2.3.3.3 去除3D物体模型的属性
减少存储在3D模型中的数据的数量,选择的3D模型中的属性可以被从3D模型中除去,如果他们不再被需要。特别的,算子copy_object_model_3d可以被用来复制一个3D模型,这样只有选择的属性才能被拷贝到新的3D模型中。
例如,在例程hdevelop\3D-Object-Model\Segmentation\segment_object_model_3d.hdev中一个分割和3D基元拟合被同时应用在由一个由X,Y,Z图像生成的3D模型上。
为节省内存,诸如点的坐标和2D映射等在由X,Y,Z图像生成3D对象模型时自动获取的信息,即可被从模型中除去,通过仅拷贝和3D基元相关的数据。
segment_object_model_3d (ObjectModel3DID, ['segmentation','fitting'], \
['fitting_segmentation','fitting'], ObjectModel3DIDOut)
for Index := 0 to |ObjectModel3DIDOut| - 1 by 1
copy_object_model_3d (ObjectModel3DIDOut[Index], 'primitives_all', \
'copy', ObjectModel3DID)
endfor
2.3.3.4 修改3D物体模型的点集
提供了多个算子来修改3D物体模型的点集或者分割3D物体模型为多个部分。比如:
1).set_object_model_3d_attrib_mod可以被用来直接修改就像2.3.2中展示的点的坐标。
2).select_points_object_model_3d应用阈值到选择的属性上,使点集减少位于指定的属性范围内。
3).reduce_object_model_3d_by_view可以被用来将点集减少到一个指定的二维区域内,该区域被定义是为了表示3D模型的2D投影。
4).sample_object_model_3d可以被用来完成一个具有统一密度的3D模型。点和点之间有指定的距离。这通常适用于减少点的密度。比如,使后续算子执行更快。比如三角化或者3D对象模型有的部分包含的点的密度比模型的其他部分高。后一种情况可能会导致:比如来自多目立体重建或未多重3D物体模型的配准和融合。
注意:依赖于点之间具体的距离,结果的3D物体模型中点的密度可能甚至比初始的模型更高。
5).simplify_object_model_3d可以被用来减少三角化的3D物体模型中的点的数量。尤其是对于3D模型中平滑的部分,即这部分中高的点的密度不是必须的。这可能被使用,比如加快后续算子的调用通过使用减少了复杂程度的3D物体模型。典型的,简化的3D模型的点的密度是不均匀的。需要更多的点来表示物体几何信息的部分具有更高的点的密度,而光滑部分点的密度需求更低。这与算子sample_object_model_3d形成对比,这个算子将获取均匀的点的密度。
6).smooth_object_model_3d平滑3D物体模型的表面。典型的,这个算子被用来为表面三角化或平滑3D物体模型中的噪声点数据来准备一个3D物体模型。
7).connection_object_model_3d分割一个3D物体模型为几个连接的部件组成的部分。而两部分被认为是连接的依据用户指定的标准,尤其是属性或距离函数和他们相关的阈值。
例如,例程hdevelop\3D-Object-Model\Features\select_object_model_3d.hdev中,算子select_points_object_model_3d被用来选择一个3D物体模型中的点使用三维坐标阈值。所以,图2.29左侧显示的引擎盖的各个部分被从背景中分割出来(图2.29的右侧)。
2.3.3.5 转换3D物体模型
三维物体模型可以通过几种方式在空间转换,特别的,你可以转换3D物体模型通过:
1).刚性转换可以使用算子rigid_trans_object_model_3d。
2).任意的三维放射变换使用算子affine_trans_object_model_3d。
3).任意的3D投影变换使用算子projective_trans_object_model_3d。
注意:3D转换后的3D模型仅包含可以表示一个3D模型的数据。比如,三维放射变换后,没有3D基元会包含在转换后的3D对象模型中。3D基元的变换只有刚性变换是适合的。
2.3.3.6 结合 3D 物体模型
把几个3D物体模型结合为一个单独的3D对象模型,你可以应用算子 union_object_model_3d。注意结果3D模型中只包含所有的输入模型都有的属性。
2.3.4 提取 3D 物体模型的特征
下面章节显示怎样:
1. 计算或获取3D物体模型的指定特征。
2. 通过他们的特征选择3D对象模型。
2.3.4.1 计算或获取 3D 物体模型的特征
3D物体模型中显式的或隐式的包含几种特征信息。一方面,3D物体模型中显式的包含了2.3.2节中介绍的几种不同的的特征信息。这些特征可以点坐标、法线、三角形、面,或3D基元参数等特征相关,且他们可以通过算子 get_object_model_3d_params 获取。
另一方面,3D物体模型包隐式信息关于指定的几何特征,即包含的信息可以被用来显式的计算这些特征使用HALCON提供的许多可用的算子中的一个:
1. area_object_model_3d 计算3D物体表面的面积。
2. distance_object_model_3d 计算一个3D模型中的点和另一个3D模型中点、三角形,或基元之间的距离。
3. max_diameter_object_model_3d 计算3D物体模型的最大直径。
4. moments_object_model_3d 计算3D物体模型的二阶原点矩或二阶中心矩。
5. smallest_bounding_box_object_model_3d 和 smallest_sphere_object_model_3d 计算3D物体模型的最小外接立方体或最小外接球。
6. volume_object_model_3d_relative_to_plane 计算3D模型相对于平面的体积,三角形或多边形需要包含在3D模型中。
7. intersect_plane_object_model_3d 计算3D模型和平面的相交部分并返回横截面,即用线连接起来的一系列3D点(看图2.31,显示了例程 hdevelop\3D-Object-Model\Transformations\intersect_plane_object_model_3d.hdev 的结果)。
在例程hdevelop\3D-Object-Model\Features\select_object_model_3d.hdev中 2.3.3.4 节中介绍的 3D 模型的连接的部分的最大直径和体积被计算(图 2.32)

volume_object_model_3d_relative_to_plane (ObjectModel3DIDConnections, [0, 0, \
MaxValue, 0, 0, 0, 0], 'signed', \
'true', Volume)
max_diameter_object_model_3d (ObjectModel3DIDConnections, Diameter)
2.3.4.2 通过特征选择 3D 物体模型
如果许多3D模型中只需要含有特定信息的模型,可以使用算子 select_object_model_3d。其从一组 D模型中根据全局特征如存在的指定属性或指定的特征的范围如物体的平均直径或体积选择 3D 模型。
select_object_model_3d (ObjectModel3DTranslated, ['volume', 'diameter_object'], 'and', \
[MinVolume, MinDiameter], \[MaxVolume, MaxDiameter], \
ObjectModel3DSelected)

2.3.5 三维匹配
HALCON提供了三维匹配的功能,其代表了相同的物体或相同物体的覆盖部分。这种匹配也被称作3D物 体的“registration”(配准?)
下面的章节
1).介绍了关于3D物体模型的双向和全局配准(2.3.5.1节)。
2).介绍怎样配准和深入修改的3模型可以被使用来导出一个表面模型用与基于形状的3D匹配(2.3.5.2节)。
2.3.5.1 配准3D 模型
使用算子 register_object_model_3d_pair 你可以应用一个匹配在两个三维物体模型间来获取表示他 们之间空间关系的位姿。这个过程也被称作3D模型的双向配准。匹配确定了一个初始的位姿,该位姿接着即被改善,因此两个三维模型重叠部分的不同即变到最小。最后的位姿即可以被用来将第一个3D模型转换 到第二个模型的坐标系。他们之间的初始位姿已经隐式的被知道。之后,算子也可被用在不进行初始的 匹配只改善位姿的模式下。
使用算子 register_object_model_3d_global 可以提高许多3D模型间的相对位姿,也被称作3D模型的全局配准(“global registration”)。
特别的,如果一个3D模型由几个重叠的3D物体模型组成,指定的重叠部分被使用来确定一组齐次变换矩阵,利用这组矩阵,模型可以被变换,这样所有模型间的关系被改善,即实现了所有模型间的相互区别最小,这可以使完整的对象的表示更好。
对于两个算子,配准的结果典型的被应用与转换初始的三维模型使用算子affine_trans_object_model_3d。
2.3.5.2 实例应用:从一系列3D 图像中导出表面模型
例程hdevelop\Applications\Robot-Vision\reconstruct_3d_object_model_for_matching.hdev 显 示了配准是怎样被使用的来导出一个唯一的表面模型对于基于表面的3D匹配(4.3节),表面模型通过一个 3D传感器从同一物体的不同视角获取。特别的,对于3D物体模型的每一个视角及相关的灰度图像是有效的。
第一步:配准3D模型 使用双向配准,下述的全局配准或相关的仿射变换,物体上的初始视图的3D模型被对齐。特别的,一 个双向配准被应用对于所有连续视图下的3D物体模型。

read_object_model_3d('universal_joint_part/universal_joint_part_xyz_00.om3', \'m', [],
[], ObjectModel3D, Status)
PreviousOM3 := ObjectModel3D
RegisteredOM3s := ObjectModel3D
for Index := 1 to NumTrainingImages - 1 by 1
read_object_model_3d ('universal_joint_part/universal_joint_part_xyz_' + Index$'02d',
\'m', [], [], ObjectModel3D, Status)
register_object_model_3d_pair (ObjectModel3D, PreviousOM3, 'matching', \'default_parameters', 'accurate', Pose, \Score)
pose_to_hom_mat3d (Pose, HomMat3D)
RegisteredOM3s := [RegisteredOM3s,ObjectModel3D]
Offsets := [Offsets,HomMat3D]
PreviousOM3 := ObjectModel3D
endfor
例如,视图12和13视角下的3D物体模型的相关图像及转换到同一坐标系下的3D物体模型显示在图2.35中。
在所有的双向匹配被应用后,所有的3D模型都可以被转换到第一个模型的坐标系下(图2.36,左)。之后转换的模型时间的关系通过一个全局配准及相关的仿射变换所改善(图2.36,右)。
register_object_model_3d_global (RegisteredOM3s, Offsets, 'previous', [], \
'max_num_iterations', 1, HomMat3DRefined, \Score)
affine_trans_object_model_3d (RegisteredOM3s, HomMat3DRefined, \GloballyRegisteredOM3s)

第二步:从配准的3D物体模型中提取表面模型
配准的3D模型由不同的结构组成,特别的一个通用的连接件,即具体的模型应该被使用作为表面模型即部分背景。从一组对齐的3D模型中提取表面模型在几部内被完成。首先,模型被结合为一个单独的3D物体模型使用算子 union_object_model_3d(图2.37,左),为获取密度小的均匀点,算子 sample_object_model_3d 被使用(图2.37右)。
union_object_model_3d (GloballyRegisteredOM3s, 'points_surface', \UnionOptimized)
MinNumPoints := 5
SampleDistance := 0.5
sample_object_model_3d (UnionOptimized, 'accurate', SampleDistance, \'min_num_points', MinNumPoints, \
SampleExact)
之后,物体表面被平滑且表面法线被计算。在这个例子中,模型被临时移动,以使坐标系的原点位于物体模型下面。
以这种方式,结合参数设置为 mls_force_inwards 的算子 smooth_object_model_3d,这样平滑的模型饿法线会是点向下的,这使基于表面的3D匹配更加鲁棒。
get_object_model_3d_params (SampleExact, 'center', Center)
get_object_model_3d_params (SampleExact, 'bounding_box1', BoundingBox)
hom_mat3d_identity (HomMat3DTrans)
hom_mat3d_translate_local (HomMat3DTrans, -Center[0], -Center[1], \-BoundingBox[2], \
HomMat3DTranslate)
affine_trans_object_model_3d (SampleExact, HomMat3DTranslate, \SampleExactTrans)
smooth_object_model_3d (SampleExactTrans, 'mls', 'mls_force_inwards', \
'true', SmoothObject3DTrans)
hom_mat3d_invert (HomMat3DTranslate, HomMat3DInvert)
affine_trans_object_model_3d (SmoothObject3DTrans, HomMat3DInvert, \

之后,结果模型被三角化使用算子triangulate_object_model_3d,且连接的部分被确定使用算子 connection_object_model_3d(图2.38)。

为从背景分出应该被用来进行基于形状的3D匹配组成部分,select_object_model_3d被调用使用通用的图像特征。(图2.39)
select_object_model_3d (ObjectModel3DConnected, ['has_triangles', \
'num_triangles'], 'and', [1, 2000], [1, 100000], \
\ObjectModel3DSelected)
select_object_model_3d (ObjectModel3DSelected, ['central_moment_2_x', \
'central_moment_2_y'], 'and', [150, 200], [400, 230], \
\ObjectModel3DCross)
第三步:使用形状模型为基于形状的3D匹配
获取的3D物体模型现在被用于基于表面的3D匹配。匹配首先被示范基于首先被用来创建表面模型的数据,即在由3D传感器获取的模型物体上的初始视角下(图2.40)。
之后,一个匹配被应用在多目立体图像中,这些图像是一组不同视角下的万向节(图2.41)。获取详细的关于表面匹配和多目立体视觉重建的信息,请查看4.3节和5.4节。

2.3.6 可视化三维物体模型
对 3D 物体模型的可视化,可以使用不同的算子和程序。
1).使用算子 disp_object_model_3d 可视化单个 3D 模型
- 一般独立的物体模型不需要设置参数和窗口。
- 算子
disp_object_model_3d提供了一个简单的接口用于可视化一个或少数的 3D 物体模型。
2).多个物体模型的可视化
- 一个被称为作 “3D 场景”(“3D scene”),使用算子
disp_scene_3d。 - 最好选择如果多个 3D 模型需要被可视化。
- 1.多个相机可以被定义来从不同位置观察 3D 场景。
- 2.窗口可以添加到指定的 3D 点。
- 3.平滑显示的运动场景,由于与帧可以管理显卡上物体的内存。
- 4.交互式可改变 3D 物体模型,使用算子
visualize_object_model_3d。
3).交互式 3D 物体模型的可视化
- 第 2.3.6 节 中描述的方法的位置和方向。
- 注意,算子 3D 物体模型需要
genImage1、GIS1、1.2i以及openGL_EXT_framebuffer_object和GL_EXT framebuffer_blit,如果没有满足这些要求。 - 此外,由于使用的编解码器协议(Windows Remote Desktop)或完全不支持(VSB),这并不意味着其底层框架的兼容模式自动被使用。
2.3.6.1 可视化独立的 3D 物体模型
要简单的在屏幕上单个窗口中显示 3D 物体模型,可以使用算子 disp_object_model_3d。这里可以指定相机参数和定义有关交点的视角的值。此外,使用算子 get_disp_object_model_info,可以获得当前窗口中每一个位置指定的信息,特别的是,对于一个行列表,可以查看以表示某个物体的物理模型的信息或 3D 物体模型的深度信息(测量从相机到接触点)。
例如,disp_object_model_3d 应该怎么使用算子 disp_object_model_3d 比如,以下不同颜色显示 3D 信息:
disp_object_model_3d (WindowHandle, ObjectModel3DIDs, CameraParam, ObjPose, ['colored'],
'disp_pose', [])
注意: 最简单调用
disp_object_model_3d的方式仅要求 3D 模型的句柄和窗口。这样它可以被调用为:
disp_object_model_3d (WindowHandle, ObjectModel3DIDs, [], [], [], [])
在这种情况下,位置和相机的内在参数被设定,这将影响物体的形状可见性。
在这种情况下,传给相机模型的内部参数缺失时,该完整的物理研究可见。
如果调用 object_model_3d 产生的问题不能只是被显示器,而存在唯一一幅图像中,你可以使用算子 render_object_model_3d。
如果对于给定的图像需要 3D 物体模型的轮廓,则可以使用算子 project_object_model_3d。
2.3.6.2 使用句柄可视化多个 3D 物体模型
另一个 display_3d 算子的方式是场景算子:
- 例用
display_scene_3d和dev_new_snow来创建和显示 3D 场景。
首先一个场景被创建通过 create_scene_3d,使能 3D 物体的可视化:
create_scene_3d (SceneID)
一个场景需要有至少一个相机,一个相机可以被添加到场景中使用算子 add_scene_3d_camera。相机的位置可以被选择的特性参数:
add_scene_3d_camera (SceneID, CameraParam, CameraPose)
例如,此示例可以使用以下参数创建相机:
set_scene_3d_camera_pose (SceneID, CameraIndex, [0.0,-0.4,0.0,0,0])
一个光源可以通过使用相同的接口用于 3D 场景。光源信息可以使用添加到场景中使用算子 add_scene_3d_light 及其他属性,比如关于辐射部分的线性基函数,可以被设置和使用算子 set_scene_3d_light_param:
add_scene_3d_light (SceneID, [1.0,0.1,0.1], 'point_light', ['lighter'])
set_scene_3d_light_param (SceneID, LightIndex, 'diffuse', [0.8,0.8,0.8])
set_scene_3d_light_param (SceneID, LightIndex, 'ambient', [0.2,0.2,0.2])
现在,物体可以被添加到场景中使用 add_scene_3d_object_model。这个算子要求一个 3D 物体模型和其相对于 3D 场景中坐标系的位置。注意,世界坐标系中的 3D 场景的位姿可以被设置使用算子 set_scene_3d_to_world_pose。
add_scene_3d_instance (SceneID, ObjectModel3D, Pose1, Instance1Index)
set_scene_3d_instance_param (SceneID, Instance1Index, 'alpha', 0.7)
add_scene_3d_instance (SceneID, ObjectModel3D, Pose2, Instance2Index)
set_scene_3d_instance_param (SceneID, Instance2Index, 'color', '#28216G')
标签可以选择的被添加到指定的点:
add_scene_3d_label (SceneID, 'Instance1', Pose1[0:2], 'bottom_left', \
'point', InstanceLabel1ID)
add_scene_3d_label (SceneID, 'Instance2', Pose2[0:2], 'top', 'point', \
InstanceLabel2ID)
3D模型可以被显示利用算子 disp_scene_3d:
display_scene_3d (WindowHandle, SceneID, CameraIndex)
场景图像可以由数据保存到句柄 render_scene_3d:
render_scene_3d (Image, SceneID, CameraIndex)
最后,释放分配的内容,场景需要被删除:
clear_scene_3d (SceneID)
2.3.6.3 交互式可视化多个 3D 物体模型
一个方便的方式来可视化 3D 物体模型且可以被移动的和旋转可以使用提供的外部函数 visualize_object_model_3d。
3.使用单个相机在指定平面上进行测量
这种测量只能通过同一时刻拍摄在不同于位置摄像的进行从真实的世界的坐标系的测量。我们称这种为立体视觉方法。
在工业检测领域,我们经常只可以使用一只摄像机,并且在前面的也不允许进行指定在立体图像对寻找对应点(立体匹配过程)这种恢复的场景,不知道其通过设置头相机标定物体的图像。并且物体在类似装配线的已知平面上。就可以通过这个摄像机进行世界坐标系的二维测量。对于针孔摄像机,通过在一个平面内光线(视线)交进行三维测量。
因此,只要将物体放置在一个平面上,进行三维测量就是可能实现的,不管这个平面与光轴之间是否倾斜。唯一的先决条件是摄像机会必须预先进行标定。在HALCON中,摄像机标定的过程非常容易,可以从下面第一个例子中体会到这里——这一点:这个例子介绍了在摄像机标定中必须的一些基本参数。
进行摄像机标定要两个标准的方法就是使用HALCON标定的标定板。你只需要拍摄标定板的几幅图像(图 3.1),在其中每幅图像标定板直接放在测量平面上。
以下常用来做几件事:
1).标相机(3.2节)
2).将图像转换到世界坐标系(3.3节)
3).定位图像,比如,从只剩去除镜头畸变(3.4节)。
最后,简短的看一下一个测量——物体的例子。
3.1 第一个例程
例程 solution_guide/3d_vision/camera_calibration_multi_image.hdev 显示怎样简单的标定相机并使用标定结果将测量转换到三维世界坐标系。
首先,指定标定参数:
create_calib_data ('calibration_object', 1, 1, CalibDataID)
set_calib_data_cam_param (CalibDataID, 0, [], StartCamPar)
set_calib_data_calib_object (CalibDataID, 0, 'calplate_30mm.cpd')
之后,读取标定的图像。使用算子 find_calib_object,寻找标定板、提取标志点轮廓和中心、及估算标定位姿。获取的数值存储在标定数据模型中:
for I := 1 to NumImages by 1
read_image (Image, ImgPath + 'calib_image_' + I$'02d')
find_calib_object (Image, CalibDataID, 0, 0, I, [], [])
endfor
现在,使用算子 calibrate_cameras 执行标定:
calibrate_cameras (CalibDataID, Errors)
之后,可以获取标定结果,即相机的内部参和指定图像中标定板的位姿:
get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam)
get_calib_data (CalibDataID, 'calib_obj_pose', [0, I], Pose)
这个位姿被用为相机外参,即在摄像机坐标系中世界坐标系的位姿。在该例程中,世界坐标系坐落在尺子上(图 3.2)。为补偿标定板的厚度,位姿被移动相关的值:
set_origin_pose (Pose, 0, 0, 0.002, Pose)
现在,执行测量。对于此,我们获取了一个不被标定板遮挡的尺子的图像:
read_image (Image, ImgPath + 'ruler')
gen_measure_rectangle2 (690, 680, rad(-0.25), 480, 8, 1280, 960, 'bilinear', \
MeasureHandle)
measure_pairs (Image, MeasureHandle, 0.5, 5, 'all', 'all', RowEdgeFirst, \
ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, \
ColumnEdgeSecond, AmplitudeSecond, IntraDistance, \InterDistance)
Row := (RowEdgeFirst + RowEdgeSecond) / 2.0
Col := (ColumnEdgeFirst + ColumnEdgeSecond) / 2.0
利用相机的内参和外参,测量结果就被转换到世界坐标系中使用算子 image_points_to_world_plane:
image_points_to_world_plane (CamParam, Pose, Row, Col, 'mm', X1, Y1)

3.2 三维相机标定
该节详细介绍了3D相机标定的过程。注意你可以轻松标定你的相机使用标定助手。
相机标定包括三个步骤:
- 准备
- 标定
- 获取结果
获取结果之后,你可以存储他们并释放标定模型的内存(3.2.9节)。
执行标定前的准备
标定的所有信息被传递到一个被所称作的标定数据模型中。特别的,可以:
- 创建模型并指定诸如要标定的相机数量等基本信息(3.2.1节)
- 指定相机内参的初始值(3.2.2节)
- 描述标定物体(3.2.3节)
- 从不同角度(图像)观测标定物体并存储提取的信息(3.2.4节)
- 选择性的限制某一标定参数,保持其他的固定(3.2.5)
准确执行标定
在HALCON中,使用算子calibrate_cameras标定一个或多个相机,需要一个标定数据模型作为输入(3.2.6节获取更多信息)
获取标定结果
calibrate_cameras再次存储它的结果,尤其是标定的相机参数和标定板的位姿,在标定数据模型中。你可以获取它们(及其他标定参数)使用算子get_calib_data(3.2.7节)。
3.2.1 创建标定数据模型
使用算子create_calib_data创建标定数据模型,指出相机的数量和标定物体的数量。当使用一个相机,也通常使用一个标定物体。
create_calib_data ('calibration_object', 1, 1, CalibDataID)
之后,继续:
1. 指定相机内参的初始值(3.2.2节)
2. 描述标定物体(3.2.3节)
3.2.2 指定相机初始内参
设置相机内参使用算子set_calib_data_cam_param。
set_calib_data_cam_param (CalibDataID, 0, [], 'area_scan_division', \
[0.012, 0, 0.00000375, 0.00000375, 640, 480, 1280, 960, \
StartCamPar])
除了标定数据模型,算子需要以下参数作为输入:
- CameraIdx:相机的指数(一个相机时设置为0)
- CameraType:相机类型
- CameraParam:相机内参数组
接下来,你发现:
1. 支持的相机类型和他们的参数列表(3.2.2.1节)
2. 怎样选择合适的畸变模型的建议(3.2.2.2节)
3. 面扫描相机特别的提示
4. 线扫描相机特别的提示
3.2.2.1 相机类型和内参
1). 面扫描相机 (Area Scan Camera)
面扫描相机是最常见的相机类型,使用二维成像传感器。
2) 畸变模型:division
set_calib_data_cam_param (CalibDataID, 0, [], 'area_scan_division', \
[Focus, Kappa, Sx, Sy, Cx, Cy, ImageWidth, ImageHeight])
参数说明:
| 参数 | 符号 | 单位 | 描述 |
|---|---|---|---|
| Focus | f | 米 | 焦距 |
| Kappa | κ | - | 径向畸变系数 |
| Sx | sx | 米/像素 | 像素在x方向的物理尺寸 |
| Sy | sy | 米/像素 | 像素在y方向的物理尺寸 |
| Cx | cx | 像素 | 主点在x方向的坐标 |
| Cy | cy | 像素 | 主点在y方向的坐标 |
| ImageWidth | - | 像素 | 图像宽度 |
| ImageHeight | - | 像素 | 图像高度 |
3).畸变模型:polynomial
set_calib_data_cam_param (CalibDataID, 0, [], 'area_scan_polynomial', \
[Focus, K1, K2, K3, P1, P2, Sx, Sy, Cx, Cy, ImageWidth, ImageHeight])
参数说明:
| 参数 | 符号 | 描述 |
|---|---|---|
| Focus | f | 焦距 |
| K1, K2, K3 | k₁, k₂, k₃ | 径向畸变系数(1阶、2阶、3阶) |
| P1, P2 | p₁, p₂ | 切向畸变系数 |
| Sx, Sy | sx, sy | 像素物理尺寸 |
| Cx, Cy | cx, cy | 主点坐标 |
| ImageWidth, ImageHeight | - | 图像尺寸 |
4) 线扫描相机 (Line Scan Camera)
线扫描相机使用一维传感器,通过物体移动或相机移动来获取二维图像。
set_calib_data_cam_param (CalibDataID, 0, [], 'line_scan_division', \
[Focus, Kappa, Sx, Sy, Cx, Cy, ImageWidth, ImageHeight, Vx, Vy, Vz])
额外参数:
| 参数 | 符号 | 描述 |
|---|---|---|
| Vx, Vy, Vz | vx, vy, vz | 运动向量(描述相机与被测物体的相对运动) |
3.2.2.2 畸变模型选择建议
division 模型(推荐用于一般情况)
优点:
- 参数少,计算效率高
- 对大多数工业相机足够精确
- 数值稳定性好
适用场景:
- 标准工业相机
- 畸变程度中等或较小
- 实时性要求高的应用
set_calib_data_cam_param (CalibDataID, 0, [], 'area_scan_division', CamParam)
polynomial 模型(用于高精度或大畸变)
优点:
- 可以建模更复杂的畸变
- 包含切向畸变校正
- 适合广角镜头、鱼眼镜头
适用场景:
- 广角相机
- 鱼眼镜头
- 需要高精度测量的应用
set_calib_data_cam_param (CalibDataID, 0, [], 'area_scan_polynomial', CamParam)
3.2.3 描述标定物体
在HALCON中,标定物体通常是标定板(calibration plate)。你需要指定标定板的描述文件。
set_calib_data_calib_object (CalibDataID, 0, 'calibration_object.cpd')
参数说明:
| 参数 | 描述 |
|---|---|
| CalibDataID | 标定数据模型句柄 |
| 0 | 标定物体索引 |
| ‘calibration_object.cpd’ | 标定板描述文件路径 |
3.2.3.1 标准HALCON标定板
使用预先定义的标定板描述文件:
set_calib_data_calib_object (CalibDataID, 0, 'calib_30mm.cpd')
3.2.3.2 自定义标定板
创建自定义标定板描述文件(.cpd格式):
# 标定板描述文件示例
# 单位:米
# 标定板厚度
0.001
# 标记点数量
49
# 标记点坐标 (X, Y, Z)
0.000 0.000 0.000
0.005 0.000 0.000
0.010 0.000 0.000
...
3.2.4 采集标定图像
标定需要多张从不同角度拍摄的标定板图像。推荐采集15-20张图像。
3.2.4.1 图像采集流程
* 读取图像
read_image (Image, 'calib_image_01')
* 查找标定板
find_calib_object (Image, CalibDataID, 0, 0, 1, [], [])
* 提取标记点
dev_display (Image)
dev_display_calib_data (CalibDataID, 'calib_object', 0, [], WindowHandle)
3.2.4.2 图像采集建议
1. 覆盖整个视野:标定板应出现在图像的不同位置
2. 不同角度:倾斜标定板,获取不同视角
3. 不同距离:在不同距离拍摄
4. 避免遮挡:确保标定板完整可见
5. 光照均匀:避免阴影和反光
3.2.4.3 图像数量建议
| 相机类型 | 最少图像数 | 推荐图像数 |
|---|---|---|
| 单相机 | 10 | 15-20 |
| 多相机 | 15×相机数 | 20×相机数 |
3.2.5 设置标定参数约束
可以固定某些参数,只优化其他参数。
3.2.5.1 固定内参
* 固定焦距
set_calib_data (CalibDataID, 'camera', 0, 'params', \
['focus', 'kappa'], [Focus, Kappa])
3.2.5.2 固定畸变系数
* 只优化焦距和主点,固定畸变系数
set_calib_data (CalibDataID, 'camera', 0, 'params', \
['kappa'], [0.0])
3.2.6 执行相机标定
使用calibrate_cameras算子执行标定:
* 执行标定
calibrate_cameras (CalibDataID, Error)
* 显示标定误差
dev_disp_text ('Calibration error: ' + Error + ' pixels', 'window', 12, 12, 'black', [], [])
3.2.6.1 标定误差评估
| 误差范围 | 评估 | 建议 |
|---|---|---|
| < 0.1 像素 | 优秀 | 标定质量很高 |
| 0.1 - 0.3 像素 | 良好 | 可用于高精度测量 |
| 0.3 - 0.5 像素 | 一般 | 可用于一般应用 |
| > 0.5 像素 | 较差 | 建议重新采集图像标定 |
3.2.7 获取标定结果
标定完成后,可以获取相机内参、外参等信息。
3.2.7.1 获取相机内参
* 获取相机内参
get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam)
* 获取相机位姿(相对于标定板)
get_calib_data (CalibDataID, 'calib_obj_pose', [0, 0], 'pose', Pose)
3.2.7.2 内参数据结构
对于area_scan_division模型:
CamParam = [Focus, Kappa, Sx, Sy, Cx, Cy, ImageWidth, ImageHeight]
3.2.7.3 位姿数据结构
Pose = [X, Y, Z, RotX, RotY, RotZ, Type]
| 元素 | 描述 |
|---|---|
| X, Y, Z | 平移量(米) |
| RotX, RotY, RotZ | 旋转角度(度或弧度,由Type决定) |
| Type | 位姿类型(0=直接,1=欧拉角) |
3.2.8 保存和加载标定数据
3.2.8.1 保存标定结果
* 保存标定数据模型
write_calib_data (CalibDataID, 'calibration_result.cad')
* 保存相机参数到文件
write_cam_par (CamParam, 'camera_params.dat')
* 保存位姿到文件
write_pose (Pose, 'camera_pose.dat')
3.2.8.2加载标定结果
* 读取标定数据模型
read_calib_data ('calibration_result.cad', CalibDataID)
* 读取相机参数
read_cam_par ('camera_params.dat', CamParam)
* 读取位姿
read_pose ('camera_pose.dat', Pose)
3.2.9 释放标定资源
* 清除标定数据模型
clear_calib_data (CalibDataID)
3.2.9.1 完整标定代码示例
* ============================================================
* 完整的三维相机标定流程
* ============================================================
* 1. 创建标定数据模型
create_calib_data ('calibration_object', 1, 1, CalibDataID)
* 2. 设置相机初始内参(示例:面扫描相机,division模型)
* 参数说明:[焦距, 畸变系数, Sx, Sy, Cx, Cy, 图像宽, 图像高]
set_calib_data_cam_param (CalibDataID, 0, [], 'area_scan_division', \
[0.012, 0, 0.00000375, 0.00000375, 640, 480, 1280, 960])
* 3. 设置标定物体
set_calib_data_calib_object (CalibDataID, 0, 'calib_30mm.cpd')
* 4. 采集并处理标定图像
ImageFiles := ['calib_01.png', 'calib_02.png', 'calib_03.png', \
'calib_04.png', 'calib_05.png', 'calib_06.png', \
'calib_07.png', 'calib_08.png', 'calib_09.png', \
'calib_10.png', 'calib_11.png', 'calib_12.png', \
'calib_13.png', 'calib_14.png', 'calib_15.png']
for Index := 0 to |ImageFiles| - 1 by 1
read_image (Image, ImageFiles[Index])
find_calib_object (Image, CalibDataID, 0, 0, Index, [], [])
endfor
* 5. 执行标定
calibrate_cameras (CalibDataID, Error)
* 6. 获取标定结果
get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam)
get_calib_data (CalibDataID, 'calib_obj_pose', [0, 0], 'pose', Pose)
* 7. 显示结果
dev_disp_text ('Calibration completed!', 'window', 12, 12, 'green', [], [])
dev_disp_text ('Error: ' + Error + ' pixels', 'window', 40, 12, 'black', [], [])
dev_disp_text ('Camera parameters: ' + CamParam, 'window', 68, 12, 'black', [], [])
* 8. 保存结果
write_cam_par (CamParam, 'camera_params.dat')
write_pose (Pose, 'camera_pose.dat')
* 9. 清理
clear_calib_data (CalibDataID)
3.2.9.2 标定质量检查清单
- 采集了足够数量的图像(≥15张)
- 图像覆盖整个视野范围
- 标定板在不同角度都有拍摄
- 标定板在不同距离都有拍摄
- 标定板在图像中清晰可见,无遮挡
- 光照均匀,无明显阴影
- 标定误差 < 0.3 像素
- 所有标记点都被正确检测
3.2.9.3 常见问题与解决方案
Q1: 标定误差过大怎么办?
可能原因:
- 图像数量不足
- 标定板角度变化不够
- 标记点检测失败
解决方案:
- 增加图像数量到20张以上
- 确保标定板在多个角度拍摄
- 检查图像质量,确保标记点清晰可见
Q2: 无法检测到标定板?
可能原因:
- 标定板描述文件不匹配
- 图像质量差
- 标定板不在视野内
解决方案:
- 确认使用正确的.cpd文件
- 改善光照条件
- 调整相机与标定板的距离
Q3: 焦距估计不准确?
可能原因:
- 初始值设置不合理
- 图像角度变化太小
解决方案:
- 根据相机规格设置合理的初始焦距
- 增加大角度拍摄的图像
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)