wwwht / wwwht.github.io

daily notes
1 stars 0 forks source link

【转载】双目视觉模型和三角定位 #2

Open wwwht opened 4 days ago

wwwht commented 4 days ago

原文:Yin的笔记本,非常推荐 图片部分来自知乎,大黑 本文大部分内容来自上方链接,在此基础上加入了一些自己的思考。非原创,仅作为个人笔记。

0. 主要内容

任务 场景数据 相机数据 输入 输出
Pose Estimation 已知 测得 相机视野内各特征点在空间中的位置 相机位姿
Triangulation 测得 已知 双目相机位姿和相机视野内特征点在图片上的位置 各特征点在空间中的位置
Epipolar Geometry 部分已知 测得 双目相机视野内特征点在图片上的位置 相机位姿和各特征点在空间中的位置
Reconstruction 测得 测得 相机视野内2D图片 相机视野内各点在空间中的位置

首先是3D视觉四个大任务简单的介绍,

  1. 姿态估计(Pose Estimation):场景数据可以简单理解为特征点的三维坐标,例如标定物自身建立的3维坐标系下每个标定点的位置。相机数据可以理解为这些特征点在左右相机中的像素坐标。输入则需要我们进行特征点的对齐,即每个特征点的3D坐标和左右视图像素坐标的匹配。输出则是相机的位姿,方法可以使用解PnP方法,例如Opencv中的cv::solvePnP, cv::solvePnPRansac等。应用场景有例如增强现实(AR):根据现实世界的 3D 点与相机图像匹配,估计相机位置;机器人导航:通过环境中的特征点估计相机(机器人)的运动轨迹。
  2. 三角定位(Triangulation):根据双目相机中相同特征点在左右视图中的位置(像素坐标),结合相机的位姿,计算这些特征点的三维位置。已知信息有同一个3D特征点投影到左右视图的像素坐标(假设已经确定了对应关系),和相机的内外参,求特征点的3D坐标。方法就是一系列三角测量的方法,例如cv::triangulatePoints。应用例如特征点定位等。
  3. 对极几何(Epipolar Geometry):这个范围比较广,它描述了一类几何关系,后面会有详细讲解。借用维基百科的描述:

    对极几何立体视觉中的一种几何关系。当两个摄像机从两个不同的位置观察3D场景时,3D点及其在2D图像上的投影之间存在许多几何关系,从而导致图像点之间的约束。这些关系是基于针孔相机模型的假设推导出来的。

image.png

  1. 三维重建(Reconstruction):通过单目或多目相机拍摄的图像重建场景中点云或表面的三维结构。例如通过 SfM(Structure from Motion)恢复相机的运动轨迹和三维结构;Nerf, 3D Gaussian等三维重建方法,是现在研究的热门方向。

1. 三角定位 Triangulation

Triangulation解决的是从两张图片中计算对应点的三维坐标的问题。

这个问题的假设是:

这样我们就可以从这两张图片中计算出指向该点方向的两条光线,进而求其交点就得这个点对应的三维坐标 image.png|725

理想情况的三角定位

我们首先研究简化的情况,这个情况的假设就是两个相机的内参矩阵是 完全一样 的,而且两个相机 在x方向是完全对齐的。

这样我们就可以有如下的模型。

image.png|500 其中b被称为baseline,代表的是两个相机的光心对应的距离。图中分别以 $C_lP$ 和 $C_rP$ 为斜边可见左右两个直角三角形,其直角边可以写出如下的关系式: image.png

image.png

误差

image.png

所以我们可以得出一下几个结论:

我们同时还可以总结一下baseline对他们的影响:

那么我们就知道怎样来提高双目相机系统的精度了:

带误差的三角定位

理想情况的三角定位很好,但是在现实生活中,由于生产和装配误差,再好的双目相机,两个相机之间也不可能是完全对齐的,求出来的光线也不一定能精准相交。于是,我们需要在相没对齐光线也不能相交的情况下求解点的坐标:

image.png|525 直接上截图了: Yin的另一篇相机参数的讲解也非常推荐:相机参数 image.png

image.png

[!TIP] 后续更新自己实现的triangulation方法,论文参考的是Triangulation: Why Optimize? 先贴个图,容易忘

image.png

实现如下,逻辑有时间开帖单独聊

bool triangulateIDWMidpoint(const Eigen::Vector3d &x0,  
                            const Eigen::Vector3d &x1,  
                            const Eigen::Matrix3d &rotation,  
                            const Eigen::Vector3d &translation,  
                            Eigen::Ref<Eigen::Vector3d> result_point,  
                            double &error) {  
  Eigen::Vector3d rx0;  

  rx0 = rotation * x0;  

  const double p_norm = rx0.cross(x1).norm();  
  const double q_norm = rx0.cross(translation).norm();  
  const double r_norm = x1.cross(translation).norm();  

  const Eigen::Vector3d xprime1 =  
          (q_norm / (q_norm + r_norm)) *  
          (translation + (r_norm / p_norm) * (rx0 + x1));  

  result_point = rotation.transpose() * (xprime1 - translation);  

  const Eigen::Vector3d lambda0_rx0 = (r_norm / p_norm) * rx0;  
  const Eigen::Vector3d lambda1_x1  = (q_norm / p_norm) * x1;  

  error = (translation + lambda0_rx0 - lambda1_x1).norm();  

  /*  
  ** Eq. (9) - test adequacy  
  */  return (error * error) <  
         (std::min)((std::min)((translation + lambda0_rx0 + lambda1_x1)  
                                       .squaredNorm(),  
                               (translation - lambda0_rx0 - lambda1_x1)  
                                       .squaredNorm()),  
                    (translation - lambda0_rx0 + lambda1_x1).squaredNorm());  
}

2. 对极几何

刚才说的是知道了内参外参和点的对应关系之后,怎样进行三角定位。那往回推一步,怎样找点之间的对应关系呢?

如果直接在两张图里面找对应提取关键点进行匹配,只有在左右两边都找到的关键点才有可能匹配成功。如果对任意一点进行匹配的话,马上就会变成一个对左右两张图片所有像素的穷举搜索,复杂度为 $O(hwh'w')$ ,其中h,w和h′,w′分别为左右两图片的长宽。

在已知相对位姿的双目相机中,能不能简化一些? 能!现在有了相对的位姿约束,我们可以将这 个二维的搜索问题,降低到一维。

image.png|400

如图所示,两个相机之间的相对位姿,为我们提供了一个很好的先验知识: 已知相机位姿的情况下,从左边相机中发出的指向某个特征点的射线在右边相机中的投影可以计算出来,所以直接在这条投影线上搜索特征点即可。

image.png|550

通过这个方法,我们就可以将二维搜索问题降低到一维。

image.png

对极约束

image.png image.png|525

去掉相机内参,还原出对应点在左右两侧相机坐标系下的坐标 $x1,x2$ :( $x_1, x_2$ 是归一化归一化图像平面坐标, $x,x'$ 是像素坐标)

$$ \begin{aligned} \boldsymbol{x}_1 &= \boldsymbol{K}_1^{-1} \boldsymbol{x} = \boldsymbol{X} \ \boldsymbol{x}_2 &= \boldsymbol{K}_2^{-1} \boldsymbol{x}' = \boldsymbol{R}\boldsymbol{X} + \boldsymbol{t} \end{aligned} $$

那么右侧相机的$x2$就可从左侧相机的 $x_1$ 经过变换得到:

$$ {{x}_2} = {R} {{x}_1} + {t} $$

image.png

本质矩阵 essential matrix

image.png image.png|525

image.png

基础矩阵 fundamental matrix

image.png

求基础矩阵:八点算法 8-point algorithm

image.png

image.png image.png 关于本质矩阵和基础矩阵秩为2,可以从以下几个角度来思考: 首先是反对陈矩阵 $[\mathbf{t}]_\times$ ,是一个 $3 \times 3$ 的矩阵,用于描述三维空间中的叉积操作。关于反对称矩阵,直接解特征值: image.png

所以反对称矩阵的秩为2,旋转矩阵R是 $3 \times 3$ 的满秩矩阵,所以 $[\mathbf{t}]_\times R$ 的秩仍然为2(一个矩阵乘上满秩矩阵,秩不变),所以E的秩为2 由于内参K可逆满秩,所以F的秩也为2。也可以从奇异值分解和几何意义的角度去解释,详细的推理可以看经典文献

Hartley, R., & Zisserman, A. (2004). Multiple View Geometry in Computer Vision. Cambridge University Press.

image.png image.png 这里作者没有打完,我们继续补全已知本质矩阵,求解相机外参t和R的过程: image.png

image.png image.png 代码实现可以研究Opencv的:

int cv::recoverPose(
    InputArray E,         // 本质矩阵
    InputArray points1,   // 第一幅图像中的点
    InputArray points2,   // 第二幅图像中的点
    InputArray cameraMatrix,  // 相机内参矩阵
    OutputArray R,        // 输出旋转矩阵
    OutputArray t,        // 输出平移向量
    OutputArray mask = noArray() // 有效点的掩码
);

实例:已知基础矩阵和左图特征点位置求右图特征点搜索空间

就是求右图极线

image.png|525 image.png|500

实例:已知基础矩阵求极点位置

设左相机的极点坐标为e,而极点物理含义是左右相机中心连线OO'与相机成像平面的交点,其显然在极线上,且其相当于右侧相机(即坐标原点)在左侧成像平面上的位置: image.png|525

image.png

image.png

import numpy as np

def find_epipole(F):
    """
    使用 SVD 求解基础矩阵 F 的极点 e
    :param F: 基础矩阵 (3x3)
    :return: 极点 e 的齐次坐标
    """
    # 对 F 进行 SVD 分解
    U, S, Vt = np.linalg.svd(F)

    # 极点 e 是 V 的最后一列(V 是 Vt 的转置)
    e = Vt[-1]  # 最后一行的转置就是最后一列

    # 齐次归一化
    e = e / e[-1]

    return e

单应矩阵 Homography

除了基本矩阵和本质矩阵,我们还有一种称为单应矩阵H的东西,它描述了两个平面之间的映射关系。若场景中的特征点都落在同一平面上(比如墙,地面等),则可以通过单应性来进行运动估计。这种情况在无人机携带的俯视相机,或扫地机携带的顶视相机中比较常见。

image.png 其中 $n$ 是该平面的法向量 $n = [n_1, n_2, n_3]^{T}$ , $d$ 是偏移量。如果点 $X$在该平面上,则满足上述平面约束。

image.png

单应矩阵H在双目视觉中应用非常广泛,例如cv2.warpPerspective透视变换等。

3. 双目矫正 stereo rectification

这部分内容在工作中未用到,感兴趣可以看原作者blog

wwwht commented 4 days ago

未完待续。。。