社区计算机视觉课程文档

简介

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

简介

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

问题陈述

让我们通过理解图像形成的几何原理来理解找到物体 3D 结构的问题陈述。如图 1 所示,我们在 3D 空间中有一个点 P,其坐标为 x、y、z。点 P 通过针孔投影到相机的图像平面上。这也可以看作是将 3D 点投影到 2D 图像平面。

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

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

Figure 1: Image formation using single camera

图 1:使用单摄像头的图像形成

解决方案

让我们假设我们获得了以下信息

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

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

  1. 最初(没有图像时),点 P 可能存在于 3D 空间中的任何位置。
  2. 使用单张图像,我们将点 P 的可能位置缩小到 3D 空间中的一条线上。
  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 在 3D 空间中的位置。

简化的解决方案

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

Figure 2: Image formation using 2 cameras

图 2:使用 2 个摄像头的图像形成

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

在上述配置就位的情况下,我们有以下公式,这些公式将 3D 空间中的点映射到 2D 图像平面中。

  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 的 3D 坐标(可以使用任何单位,如厘米、英尺等)。
  • 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 值是关于左侧相机的,因为坐标系的原点与左侧相机对齐。上面的公式表明,我们可以使用从 2 个不同相机位置捕获的同一点的 2 张图像来找到点 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 坐标计算

在场景中选择了十二个点,它们的 (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(厘米) 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% 或更小。

尺寸 计算值(厘米) 实际值(厘米) % 误差
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 上更新