如果空间点在两个或多个视图中出现,如何恢复景物的具体外观呢?

两视图重建

假定某物理点出现在两个视角的图片中,基于图像匹配的算法,我们确定了这对点集:视图重建

三维重建的任务是确定摄像机矩阵 视图重建 以及三维坐标点X。如果我们已经得到了P和P’,计算方法下一篇会做详细的阐述。

根据摄像机模型:

视图重建

通过叉积构建齐次线性方程组 视图重建 , 展开:

视图重建

叉乘得到

视图重建

所以:

视图重建

考虑两个对应点(视图),得到:

视图重建

视图重建

这里是从每个视图中取两个方程,得到4个方程,这是一个冗余方程组,可采用最小二乘法求解即可。

多点反投影(重建)

相机的RT参数:

struct camera_params_t
{
    double R[9];     /* Rotation */
    double T[3];     /* Translation */
    double t[3];     /*-RT*/
};

反投影函数:

v3_t triangulate_Pre( vector<v2_t> &p, vector<camera_params_t>& params, double &error_out)

其中 视图重建 ,有:

视图重建

所以:

视图重建

程序实现:

v3_t triangulate_Pre( vector<v2_t> &p, vector<camera_params_t>& params, double &error_out) 
{//T
    int num_points = p.size();
    int num_eqs = 2 * num_points;
    int num_vars = 3;

    double *A = (double *) malloc(sizeof(double) * num_eqs * num_vars);
    double *b = (double *) malloc(sizeof(double) * num_eqs);
    double *x = (double *) malloc(sizeof(double) * num_vars);

    int i;
    double error;
    v3_t r;

    for (i = 0; i < num_points; i++) {
        int row = 6 * i;
        int brow = 2 * i;

        A[row + 0] = params[i].R[0] - Vx(p[i]) * params[i].R[6];  
        A[row + 1] = params[i].R[1] - Vx(p[i]) * params[i].R[7];  
        A[row + 2] = params[i].R[2] - Vx(p[i]) * params[i].R[8];

        A[row + 3] = params[i].R[3] - Vy(p[i]) * params[i].R[6];  
        A[row + 4] = params[i].R[4] - Vy(p[i]) * params[i].R[7];  
        A[row + 5] = params[i].R[5] - Vy(p[i]) * params[i].R[8];

        b[brow + 0] = params[i].T[2] * Vx(p[i]) - params[i].T[0];
        b[brow + 1] = params[i].T[2] * Vy(p[i]) - params[i].T[1];
    }
    
    /* Find the least squares result */
    dgelsy_driver(A, b, x, num_eqs, num_vars, 1);
    error = 0.0;
    for (i = 0; i < num_points; i++) {
        double dx, dy;
        double pp[3];

        /* Compute projection error */
        matrix_product331(params[i].R , x, pp);
        pp[0] += params[i].T[0];
        pp[1] += params[i].T[1];
        pp[2] += params[i].T[2];

        dx = pp[0] / pp[2] - Vx(p[i]);
        dy = pp[1] / pp[2] - Vy(p[i]);

        error += dx * dx + dy * dy;
    }
    error = sqrt(error / num_points);
    printf("1:triangulate error is %f \n", error);
    /* Run a non-linear optimization to refine the result */
    global_num_points = num_points;
    global_p = p;
    global_params = params;
    lmdif_driver(triangulate_n_residual, num_eqs, num_vars, x, 1.0e-5);

    error = 0.0;
    for (i = 0; i < num_points; i++) {
        double dx, dy;
        double pp[3];

        /* Compute projection error */
        matrix_product331(params[i].R , x, pp);
        pp[0] += params[i].T[0];
        pp[1] += params[i].T[1];
        pp[2] += params[i].T[2];

        dx = pp[0] / pp[2] - Vx(p[i]);
        dy = pp[1] / pp[2] - Vy(p[i]);

        error += dx * dx + dy * dy;
    }
    error = sqrt(error / num_points);
    printf("2:triangulate error is %f \n", error);

    if (error_out != NULL) {
        error_out = error;
    }
    r = v3_new(x[0], x[1], x[2]);
    free(A);
    free(b);
    free(x);
    return r;
}

求优函数参考:https://github.com/TheFrenchLeaf/Bundler/blob/master/lib/matrix/matrix.h

dgelsy_driver函数: Driver for the lapack function dgelss, which finds x to minimize norm(b - A * x)

lmdif_driver函数:Driver for the minpack function lmdif, which uses Levenberg-Marquardt for non-linear least squares minimization (可参见:https://www.math.utah.edu/software/minpack/minpack/lmdif.html)

具体函数的不同见下一篇:最小二乘法

void triangulate_n_residual(const int *m, const int *n, 
    double *x, double *fvec, double *iflag) {
    int i;
    for (i = 0; i < global_num_points; i++) {
        /* Project the point into the view */
        v2_t p = project(i, x);
        fvec[2 * i + 0] = Vx(global_p[i]) - Vx(p);
        fvec[2 * i + 1] = Vy(global_p[i]) - Vy(p);
    }
}
//
v2_t project(int index, double *P) {
    /* Rigid transform */
    double tmp[3], tmp2[3];
    matrix_product331(global_params[index].R, P, tmp);
    matrix_sum(3, 1, 3, 1, tmp, global_params[index].T, tmp2);

    /* Perspective division */
    v2_t result;
    Vx(result) = tmp2[0] / tmp2[2];
    Vy(result) = tmp2[1] / tmp2[2];

    return result;
}

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-04-19
  • 2022-12-23
  • 2021-12-26
  • 2021-05-06
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-07-16
  • 2021-06-16
  • 2021-07-03
相关资源
相似解决方案