SLAM十四讲与VINS重投影误差计算的对比


今天是2021年8月1日,刚看了东奥男子100米决赛的比赛,心情还久久不能平静,尽管我比赛前比运动员还紧张,比赛后心脏还一直激动,心情难以平复,但我还是要大喊一声,苏神牛逼!这是历史的一刻,致敬中国速度!

下面开始正文

投影模型与代价函数

在高博《VSLAM十四讲》第二版的242页,推导重投影代价函数时,使用了三步推导:

  • 1.将路标点的世界坐标转换为局部坐标,并将局部坐标投影至归一化平面坐标。
  • 2.归一化坐标加上畸变映射,转为相机成像时的归一化坐标。(实际图像在相机中会有畸变)
  • 3.畸变图像坐标(归一化平面上的成像坐标),投影为相机的图像坐标。

假设上述变换用一个函数 h ( T , p ) h(T,p) h(T,p)表示, T T T表示相机位姿,p为路标点,这样转换后,路标点的当前观测 z = [ u s , v s ] T z={[u_s,v_s]}^T z=[us,vs]T的误差可以写为:
e = z − h ( T , p ) e=z-h(T,p) e=zh(T,p)
将所有位姿 T i T_i Ti下对路标点 p j p_j pj观测进行累计,就可以获得总的误差:
1 2 ∑ i = 1 m ∑ j = 1 n ∥ e i j ∥ 2 = 1 2 ∑ i = 1 m ∑ j = 1 n ∥ z i j − h ( T i , p j ) ∥ 2 \frac{1}{2}\sum_{i=1}^{m}\sum_{j=1}^{n}{\left \| e_{ij}\right \|}^2=\frac{1}{2}\sum_{i=1}^{m}\sum_{j=1}^{n}{\left \| z_{ij}-h(T_i,p_j)\right \|}^2 21i=1mj=1neij2=21i=1mj=1nzijh(Ti,pj)2

在我看来,这个推导很有误导性,主要有以下几个方面。

  • 1.图像坐标系中数据确实是相机的直接观测,但是图像坐标的单位是像素,是正整数,这个特性对接下来的最小二乘法优化其实是不利的,添加了坐标的正整数限制。
  • 2.从归一化平面再投影到图像坐标其实是多余的,既然都有了归一化平面上的观测点数据,那么此刻相机对路标的测量(作为预测点),可以直接逆投影到归一化平面上,此时同样可以算误差,并且少了像素坐标的限制。
  • 相机畸变过程是一个高度非线性过程,这里直接使用了简单的径向畸变变换 u d = u ( 1 + k 1 r c 2 + k 2 r c 4 ) u_d=u(1+k_1r_c^2+k_2r_c^4) ud=u(1+k1rc2+k2rc4)来处理。由于观测数据的处理直接影响最后优化结果的好坏,这里粗糙的做法必然带来不好的效果。

但我们知道,高博这本书主要是入门书籍,所以很多地方都是以讲概念为主,让大家知道这里要做什么,目的是什么,所以还是不能吹毛求疵。

工程上的做法,以VINS-MONO为例

vins中的重投影误差:
在这里插入图片描述
重投影误差图示:
在这里插入图片描述

解释:vins中的重投影误差,同样也是观测值减去预测值(后面对路标的观测称为预测值,第一次对路标的观测称为观测值),其思想是将第一次测量得到的观测值 p l i p^i_l pli转换到当前计算预测值的相机坐标系下(公式17的第三个式子,最长那个),此时是局部坐标系下的坐标 p l j p^j_l plj(三维点)。
设第一次观测的相机位姿为 T i T_i Ti,此时为 T j T_j Tj,对路标点在当前相机坐标系下坐标 p l j p^j_l plj,计算其单位方向向量,而对当前的预测值 p ^ l j \hat p^j_l p^lj的观测,是图像坐标,将其逆投影至单位圆面上(理解为与观测值的单位向量同方向的单位向量就行),计算这两个单位向量的向量差(图中红色箭头部分),然后将向量差分别投影到 p ^ l j \hat p^j_l p^lj逆投影后单位向量所在球面的切平面的两个正交基上,这两个投影就是此次重投影的二维误差。

概括来说,就是图像预测向单位球面投影,观测值也向单位球面投影,然后计算这两者投影之差(投影误差向切平面正交基投影),这里的单位圆可以等同于单位平面。都是在空间中拿了一个中间过渡层来计算误差,不过单位圆模型比单位平面适应相机的范围更广。

而对于畸变的处理,查看vins-mono源码如下

/**
 * \brief Lifts a point from the image plane to its projective ray
 * 该函数为逆投影,即把图像点坐标投影到相机归一化平面
 * \param p image coordinates
 * \param P coordinates of the projective ray
 */
void
PinholeCamera::liftProjective(const Eigen::Vector2d& p, Eigen::Vector3d& P) const
{
    double mx_d, my_d,mx2_d, mxy_d, my2_d, mx_u, my_u;
    double rho2_d, rho4_d, radDist_d, Dx_d, Dy_d, inv_denom_d;
    //double lambda;

    // Lift points to normalised plane
    //m_inv_k11为fx的倒数,m_in_k13为-cx/fx
    mx_d = m_inv_K11 * p(0) + m_inv_K13;//归一化平面的X
    my_d = m_inv_K22 * p(1) + m_inv_K23;//归一化平面的y

    if (m_noDistortion)
    {
        mx_u = mx_d;
        my_u = my_d;
    }
    else
    {
        if (0)
        {
            //获取配置文件中的畸变参数,k1,k2径向畸变,p1,p2切向畸变参数
            double k1 = mParameters.k1();
            double k2 = mParameters.k2();
            double p1 = mParameters.p1();
            double p2 = mParameters.p2();

            // Apply inverse distortion model
            // proposed by Heikkila
            mx2_d = mx_d*mx_d;//x^2
            my2_d = my_d*my_d;//y^2
            mxy_d = mx_d*my_d;//xy
            rho2_d = mx2_d+my2_d;//x^2+y^2,r^2
            rho4_d = rho2_d*rho2_d;//r^4
            radDist_d = k1*rho2_d+k2*rho4_d;
            Dx_d = mx_d*radDist_d + p2*(rho2_d+2*mx2_d) + 2*p1*mxy_d;//畸变量
            Dy_d = my_d*radDist_d + p1*(rho2_d+2*my2_d) + 2*p2*mxy_d;//畸变量
            inv_denom_d = 1/(1+4*k1*rho2_d+6*k2*rho4_d+8*p1*my_d+8*p2*mx_d);

            mx_u = mx_d - inv_denom_d*Dx_d;//原x减畸变量,那么图像是校准后的图像
            my_u = my_d - inv_denom_d*Dy_d;
        }
        else
        {
            // Recursive distortion model
            int n = 8;
            Eigen::Vector2d d_u;
            distortion(Eigen::Vector2d(mx_d, my_d), d_u);
            // Approximate value
            mx_u = mx_d - d_u(0);
            my_u = my_d - d_u(1);

            for (int i = 1; i < n; ++i)
            {
                distortion(Eigen::Vector2d(mx_u, my_u), d_u);
                mx_u = mx_d - d_u(0);
                my_u = my_d - d_u(1);
            }
        }
    }

    // Obtain a projective ray
    P << mx_u, my_u, 1.0;
}

可以看到作者对畸变处理进行了改进,第一次是使用函数近视处理的方法(if分支),这里同时考虑了径向畸变和切向畸变,但估计这样效果不好,于是作者改为使用迭代畸变模型,循环迭代八次,这样效果比函数近视好,而速度也比opencv的API快。

在作者保留代码的变动过程中,我们也可也看到,工程中去除畸变的过程不是那么简单的。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值