社区计算机视觉课程文档

简介

Hugging Face's logo
加入 Hugging Face 社区

并获得增强型文档体验

开始使用

简介

本节介绍立体视觉的工作原理,以及如何利用它来找到周围物体三维结构。立体视觉包括从不同位置和视角捕获同一个场景的两个或多个图像。这些图像可以通过多个相机获取,也可以通过重新定位同一个相机获取。

问题陈述

让我们通过了解图像形成的几何形状来理解找到物体三维结构的问题陈述。如图 1 所示,我们有一个具有 x、y、z 坐标的三维点 P。点 P 通过针孔投影到相机的图像平面上。这也可被视为将三维点投影到二维图像平面上。

现在,假设我们得到了这个二维图像以及点 P 在此图像中的像素坐标位置。我们想要找到点 P 的三维坐标。这可能吗?点 P 是唯一的,还是有其他三维点也映射到与点 P 相同的像素坐标?答案是,所有连接点 P 和针孔的直线上的三维点都将映射到二维图像平面上相同的像素坐标。

我们的目标是解决确定物体三维结构的问题。在我们的问题陈述中,我们可以将三维物体表示为一组三维点。找到每个点的三维坐标有助于我们确定物体的三维结构。

Figure 1: Image formation using single camera

图 1:使用单个相机进行图像形成

解决方案

假设我们得到以下信息:

  1. 场景点 P 的单个图像
  2. 图像中点 P 的像素坐标
  3. 用于捕获图像的相机的定位和方向。为了简单起见,我们也可以将 XYZ 坐标系放置在针孔的位置,z 轴垂直于图像平面,x 轴和 y 轴平行于图像平面,如图 1 所示。
  4. 相机的内部参数,例如焦距和主点的坐标。主点是光轴与图像平面的交点。它在图像平面中的坐标通常用 (Ox,Oy) 表示。

有了上述信息,我们可以找到一条从点 P 的像素坐标(点 P 在图像平面上的投影)开始,穿过针孔并延伸到无穷远的 3D 线。根据图像形成几何学的原理,我们可以得出结论,点 P 一定存在于这条线上的某处。

  1. 最初(没有图像)点 P 可以存在于三维空间中的任何地方。
  2. 使用单个图像,我们将点 P 的可能位置缩减到三维空间中的一条直线上。
  3. 现在,让我们考虑是否可以进一步缩小潜在位置,以确定点 P 在这条 3D 线上的精确位置。
  4. 想象一下,将相机移动到不同的位置。让坐标系保持固定在先前的位置。我们找到的 3D 线也保持不变,点 P 仍然位于这条线上的某处。
  5. 从这个新的相机位置,捕捉同一个场景点 P 的另一个图像。同样,利用点 P 在这个新图像中的像素坐标,并考虑相机针孔的更新位置,找到点 P 必须位于其上的 3D 线。
  6. 现在我们有 2 条 3D 线,点 P 位于这两条线上的某处。因此,点 P 必须位于这两条线的交点上。

给定 3D 空间中的 2 条线,它们相交有三种可能:

  1. 精确地在 1 个点处相交
  2. 在无穷多个点处相交
  3. 不相交

如果两个图像(原始和新的相机位置)都包含点 P,我们可以得出结论,这两条 3D 线至少要相交一次,并且交点就是点 P。此外,如果两条线共线,我们可以想象出这两条线在无穷多个点处相交。如果新的相机位置处的针孔位于原始 3D 线上的某处,则可以实现这一点。对于新的相机位置的所有其他位置和方向,这两条 3D 线必须精确地在一点处相交,点 P 就位于该点。

因此,使用同一个场景点 P 的 2 张图像、已知的相机位置和方向以及已知的相机内部参数,我们可以精确地找到点 P 在三维空间中的位置。

简化解决方案

由于可以选择的相机位置和方向有很多种,因此我们可以选择一个使数学运算更简单、更不复杂,并减少在计算机或嵌入式设备上运行时计算处理的位置。图 2 显示了一种流行且通常使用的配置。我们在这种配置中使用 2 个相机,相当于使用单个相机从 2 个不同的位置捕获 2 张图像。

Figure 2: Image formation using 2 cameras

图 2:使用 2 个相机进行图像形成

  1. 坐标系的原点放置在第一个相机(通常是左边的相机)的针孔处。
  2. 坐标系的 Z 轴定义为垂直于图像平面。
  3. 坐标系的 X 轴和 Y 轴定义为平行于图像平面。
  4. 我们还在二维图像中具有 X 和 Y 方向。X 是水平方向,Y 是垂直方向。我们将分别将图像平面中的这些方向称为 u 和 v。因此,点的像素坐标使用 (u,v) 值定义。
  5. 坐标系的 X 轴定义为图像平面中的 u 方向 / 水平方向。
  6. 类似地,坐标系的 Y 轴定义为图像平面中的 v 方向 / 垂直方向。
  7. 第二个相机(更准确地说,是第二个相机的针孔)放置在距离第一个相机右侧称为基线的 b 的距离处,该距离在正 x 方向上。因此,第二个相机的针孔的 x,y,z 坐标为 (b,0,0)
  8. 第二个相机的图像平面与第一个相机的图像平面平行。
  9. 第二个/右侧相机图像平面中的 u 和 v 方向与第一个/左侧相机图像平面中的 u 和 v 方向对齐。
  10. 假设左右两个相机都具有相同的内部参数,例如焦距和主点的定位。

在上述配置到位后,我们有以下公式,将三维空间中的点映射到二维空间的图像平面。

  1. 左侧相机
    1. u_left=f_xxz+O_xu\_left = f\_x * \frac{x}{z} + O\_x
    2. v_left=f_yyz+O_yv\_left = f\_y * \frac{y}{z} + O\_y
  2. 右侧相机
    1. u_right=f_xxbz+O_xu\_right = f\_x * \frac{x-b}{z} + O\_x
    2. v_right=f_yyz+O_yv\_right = f\_y * \frac{y}{z} + O\_y

上述公式中使用的不同符号定义如下。

  • u_leftu\_left,v_leftv\_left指的是左侧图像中点 P 的像素坐标。
  • u_rightu\_right, v_rightv\_right指的是右侧图像中点 P 的像素坐标。
  • f_xf\_x指的是 x 方向上的焦距(以像素为单位),并且f_yf\_y指的是 y 方向上的焦距(以像素为单位)。实际上,相机只有一个焦距,即针孔(透镜的光学中心)到图像平面的距离。但是,像素可能是矩形的,而不是完美的正方形,当我们将 f 表示为像素时,会导致不同的 fx 和 fy 值。
  • x、y、z 是点 P 的三维坐标(可以使用任何单位,例如厘米、英尺等)。
  • O_xO\_xO_yO\_y指的是主点的像素坐标。
  • b 被称为基线,指的是左相机和右相机之间的距离。b 和 x,y,z 坐标使用相同的单位(任何单位,例如厘米、英尺等都可以使用)。

我们上面有 4 个方程和 3 个未知数——3D 点 P 的 x、y 和 z 坐标。假设内在相机参数(焦距和主点)已知。等式 1.2 和 2.2 表明左图像和右图像中的 v 坐标值相同。

  1. v_left=v_rightv\_left = v\_right

使用等式 1.1、1.2 和 2.1,我们可以推导出点 P 的 x、y、z 坐标。

  1. x=b(u_leftO_x)u_leftu_rightx = \frac{b * (u\_left - O\_x)}{u\_left - u\_right}
  2. y=bf_x(v_leftO_y)f_y(u_leftu_right)y = \frac{b * f\_x * (v\_left - O\_y)}{ f\_y * (u\_left - u\_right)}
  3. z=bf_xu_leftu_rightz = \frac{b * f\_x}{u\_left - u\_right}

请注意,上面的 x 和 y 值与左相机有关,因为坐标系的原点与左相机对齐。上面的等式表明,我们可以使用从两个不同相机位置捕获的两个图像来找到点 P 的 3D 坐标。z 值也称为深度值。使用此技术,我们可以找到图像中不同像素的深度值及其真实世界的 x 和 y 坐标。我们还可以找到图像中不同点之间的真实世界距离。

演示

设置

我们将通过一个例子,捕捉一些图像,并进行一些计算,以确定我们上面的假设和数学是否有效!为了捕捉图像,我们将使用一种名为 OAK-D Lite 的硬件(OAK 代表 OpenCV AI Kit)。这款设备配备了 3 个摄像头——左右单目(黑白)和一个中心彩色摄像头。我们将使用左右单目摄像头进行我们的实验。也可以使用普通的智能手机摄像头,但 OAK-D Lite 有一些以下列出的优点。

  • OAK-D Lite 的内在摄像头参数(如焦距和主点位置)是已知的,因为该设备经过预先校准,这些参数可以通过其 Python API 从设备读取。对于智能手机摄像头,需要确定内在参数,可以通过执行摄像头校准来找到,或者有时在使用智能手机拍摄的图像的元数据中提供。
  • 上面的主要假设之一是左右摄像头的位姿是已知的。使用智能手机摄像头,可能难以确定此信息,或者可能需要额外的校准。另一方面,对于 OAK-D Lite 设备,左右摄像头的位姿是固定的,已知的,预先校准的,并且与上面提到的简化解决方案的几何形状非常相似。尽管仍然需要对原始图像进行一些后处理/图像校正,如以下所述。

原始左、右图像

OAK-D Lite 中的左右摄像头与上面详细介绍的简化解决方案的几何形状类似。左右摄像头之间的基线距离为 7.5 厘米。使用该设备捕获的场景的左、右图像显示在下面。该图还显示了这些图像水平堆叠,并在恒定高度(即在恒定 v 值处)绘制了一条红线。我们将水平 x 轴称为 u,垂直 y 轴称为 v。

原始左图像

Raw Left Image

原始右图像

Raw Right Image

原始堆叠的左、右图像

Raw Stacked Left and Right Images

让我们关注一个点——笔记本电脑的左上角。根据上面的公式 3,v_left=v_rightv\_left = v\_right对于左、右图像中的同一点。但是,请注意,红线(处于恒定 v 值)在左图像中与笔记本电脑的左上角相交,但在右图像中,该点偏离了几个像素。这种差异有两个主要原因:

  • 左、右摄像头的内在参数不同。左摄像头的主点位于 (319.13, 233.86),而右摄像头的主点位于 (298.85, 245.52)。左摄像头的焦距为 450.9,而右摄像头的焦距为 452.9。对于左、右摄像头,fx 的值等于 fy。这些内在参数是使用其 Python API 从设备读取的,对于不同的 OAK-D Lite 设备,这些参数可能不同。
  • 左、右摄像头方向与上面详细介绍的简化解决方案的几何形状略有不同。

校正后的左、右图像

我们可以执行图像校正/后处理以纠正左、右摄像头内在参数和方向的差异。此过程涉及执行 3x3 矩阵变换。在 OAK-D Lite API 中,立体节点执行这些计算并输出校正后的左、右图像。详细信息和源代码可以在 此处 查看。在此特定实现中,使用内在摄像头矩阵对内在参数进行校正,并使用左、右摄像头的旋转矩阵(校准参数的一部分)对方向进行校正。校正后的左图像被变换,就像左摄像头具有与右摄像头相同的内在参数一样。因此,在我们所有后续计算中,我们将使用右摄像头的内在参数,即焦距为 452.9,主点位于 (298.85, 245.52)。在下面的校正和堆叠图像中,请注意,在左、右图像中,位于恒定 v 的红线都与笔记本电脑的左上角相交。

校正后的左图像

Rectified Left Image

校正后的右图像

Rectified Right Image

校正和堆叠的左、右图像

Rectified and Stacked Left and Right Images

让我们也叠加校正后的左、右图像以查看差异。我们可以看到,左、右图像中不同点的 v 值大多保持恒定。但是,u 值发生了变化,而 u 值的这种差异有助于我们找到场景中不同点的深度信息,如上面的公式 6 所示。‘u’ 值的这种差异u_leftu_rightu\_left - u\_right称为视差,我们可以注意到,靠近摄像头的点的视差比远处点的视差更大。深度 z 和视差u_leftu_rightu\_left - u\_right成反比,如公式 6 所示。

校正和叠加的左、右图像

Rectified and Overlapped Left and Right Images

带注释的校正后的左、右图像

让我们找到场景中一些点的 3D 坐标。选择了一些点,并用其 (u,v) 值手动标注,如以下图像所示。除了手动标注之外,我们还可以使用基于模板的匹配、SIFT 等特征检测算法来查找左、右图像中的对应点。

带注释的左图像

Annotated Left Image

带注释的右图像

Annotated Right Image

3D 坐标计算

在场景中选择了 12 个点,它们在左、右图像中的 (u,v) 值如下表所示。使用公式 4、5 和 6,计算这些点的 (x,y,z) 坐标,并在下表中列出。X 和 Y 坐标相对于左摄像头,原点位于左摄像头的针孔(或镜头的光学中心)。因此,左、上方的 3D 点分别具有负的 X 和 Y 值。

u_leftu\_left v_leftv\_left u_rightu\_right v_rightv\_right 深度/z(cm) x_wrt_leftx\_wrt\_left y_wrt_lefty\_wrt\_left
pt1 138 219 102 219 94.36 -33.51 -5.53
pt2 264 216 234 217 113.23 -8.72 -7.38
pt3 137 320 101 321 94.36 -33.72 15.52
pt4 263 303 233 302 113.23 -8.97 14.37
pt5 307 211 280 211 125.81 2.26 -9.59
pt6 367 212 339 212 121.32 18.25 -8.98
pt7 305 298 278 298 125.81 1.71 14.58
pt8 365 299 338 299 125.81 18.37 14.86
pt9 466 225 415 225 66.61 24.58 -3.02
pt10 581 225 530 226 66.61 41.49 -3.02
pt11 464 387 413 388 66.61 24.29 20.81
pt12 579 388 528 390 66.61 41.2 20.95

尺寸计算和精度

我们也可以使用 (x,y,z) 值计算不同点之间的 3D 距离,使用公式distance=(x_2x_1)2+(y_2y_1)2+(z_2z_1)2distance = \sqrt{(x\_2 - x\_1)^2 + (y\_2 - y\_1)^2 + (z\_2 - z\_1)^2}. 计算的一些点的距离以及它们的实际测量值列在下面。 百分比误差((actualmeasured)100actual( \frac{(actual-measured) * 100}{actual}) 也被计算并列出。 注意,计算值和实际值非常吻合,百分比误差小于或等于 1.2%。

维度 计算值 (cm) 实际值 (cm) 百分比误差
d1(1-2) 31.2 31.2 0
d2(1-3) 21.1 21.3 0.94
d3(5-6) 16.6 16.7 0.6
d4(5-7) 24.2 24 0.83
d5(9-10) 16.9 16.7 1.2
d6(9-11) 23.8 24 0.83

计算尺寸结果
Calculated Dimension Results

结论

  1. 总之,我们学习了立体视觉的工作原理,用于找到给定其从不同视角捕获的两个图像的点 P 的真实世界坐标 (x, y, z) 的方程,并将理论值与实验结果进行了比较。
  2. 我们假设相机固有参数(焦距和主点)是已知的,以及它们的位置和方向信息。 这也被称为校准立体视觉。
  3. 有趣的是,如果相机的位置和方向未知,也可以找到点 P 的 3D 坐标。 事实上,可以使用图像本身找到相机彼此之间的位置和方向。 这被称为非校准立体视觉!

参考文献

  1. 3D 重建 - 多个视角 Coursera
  2. 使用 OpenCV AI Kit 的立体视觉和深度估计 LearnOpenCV
  3. OAK-D Lite Luxonics
< > 在 GitHub 上更新