2D-3D变换求解相机位姿ceres实现(与自己源码实现结果一样)

在这里插入图片描述github :地址 程序下载
测试数据:

16.012  79.963   5083.205    5852.099      527.925
88.56   81.134   5780.02     5906.365      571.549
13.362  -79.37   5210.879     4258.446     461.81
82.24   -80.027  5909.264    4314.283     455.484

测试数据2

-86.15 -68.99 36589.41 25273.32 2195.17
-53.40 82.21 37631.08 31324.51 728.69
-14.78 -76.63 39100.97 24934.98 2386.50
10.46 64.43 40426.54 30319.81 757.31
#include <iostream>
#include <opencv2/core/core.hpp>
#include <ceres/ceres.h>
#include <chrono>
#include<eigen3/Eigen/Core>
#include<eigen3/Eigen/Dense>
#include<fstream>
#include<math.h>
using namespace std;
double sumVector(vector<double> x)
{
     double sum=0.0;
     for(int i=0; i<x.size();++i)
     {
         sum+=x[i];
     }
     return sum/x.size();
}
// 代价函数的计算模型
struct Resection
{
    Resection ( double X,double Y,double Z,double x, double y,double f ) :_X(X),_Y(Y),_Z(Z), _x ( x ), _y ( y ),_f(f) {}
    // 残差的计算
    template <typename T>
    bool operator() (const T* const camPose, T* residual ) const     // 残差
    {
            T Xs=camPose[0];
            T Ys=camPose[1];
            T Zs=camPose[2];
            T w=camPose[3];
            T p=camPose[4];
            T k=camPose[5];
            T a1=cos(k)*cos(p);
            T b1=-sin(k)*cos(w) + sin(p)*sin(w)*cos(k);
            T c1=sin(k)*sin(w) + sin(p)*cos(k)*cos(w);
            T a2=sin(k)*cos(p);
            T b2=sin(k)*sin(p)*sin(w) + cos(k)*cos(w);
            T c2=sin(k)*sin(p)*cos(w) - sin(w)*cos(k);
            T a3=-sin(p);
            T b3=sin(w)*cos(p);
            T c3=cos(p)*cos(w);
//            R=rotationVectorToMatrix(omega,pho,kappa);
            residual[0]=T(_x)-T(_f)*T((a1*(_X-Xs)+b1*(_Y-Ys)+c1*(_Z-Zs))/(a3*(_X-Xs)+b3*(_Y-Ys)+c3*(_Z-Zs)));
            residual[1]=T(_y)-T(_f)*T((a2*(_X-Xs)+b2*(_Y-Ys)+c2*(_Z-Zs))/(a3*(_X-Xs)+b3*(_Y-Ys)+c3*(_Z-Zs)));
            return true; //千万不要写成return 0,要写成return true
    }
private:
    const double _x;
    const double _y;
    const double _f;
    const double _X;
    const double _Y;
    const double _Z;
};

int main ( int argc, char** argv )
{
    google::InitGoogleLogging(argv[0]);
    //read file
    string filename=argv[1];
    ifstream fin(filename.c_str());
    string line;
    vector<double> x;
    vector<double> y;
    vector<double> X;
    vector<double> Y;
    vector<double> Z;
    while(getline(fin,line))
    {
        char* pEnd;
        double a,b,c,d,e;
        a=strtod(line.c_str(),&pEnd);
        b=strtod(pEnd,&pEnd);
        c=strtod(pEnd,&pEnd);
        d=strtod(pEnd,&pEnd);
        e=strtod(pEnd,nullptr);
        x.push_back(a);
        y.push_back(b);
        X.push_back(c);
        Y.push_back(d);
        Z.push_back(e);
    }
    //初始化参数
    double camPose[6]={0};
    camPose[0]=sumVector(X);
    camPose[1]=sumVector(Y);
    camPose[2]=sumVector(Z);
    double f = 153.24; //mm
//    camPose[2]=50*f;
    //构建最小二乘
    ceres::Problem problem;
    try
    {
        for(int i=0;i<x.size();++i)
        {
            ceres::CostFunction *costfunction=new ceres::AutoDiffCostFunction<Resection,2,6>(new Resection(X[i],Y[i],Z[i],x[i]/1000,y[i]/1000,f/1000));
            //将残差方程和观测值加入到problem,nullptr表示核函数为无,
            problem.AddResidualBlock(costfunction,nullptr,camPose);
        }
    }
    catch(...)
    {
        cout<<"costFunction error"<<endl;
    }

    // 配置求解器
    ceres::Solver::Options options;     // 这里有很多配置项可以填
    options.linear_solver_type = ceres::DENSE_QR;  // 增量方程如何求解
    options.minimizer_progress_to_stdout = true;   // 输出到cout
//    options.max_num_iterations=25;
    ceres::Solver::Summary summary;                // 优化信息
    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    ceres::Solve ( options, &problem, &summary );  // 开始优化
    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
    chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>( t2-t1 );
    cout<<"solve time cost = "<<time_used.count()<<" seconds. "<<endl;

    // 输出结果
    cout<<summary.BriefReport() <<endl;
    cout<<"*************结果****************"<<endl;
    cout<<"estimated Xs,Ys,Zs,omega,pho,kappa = ";
    for ( auto p:camPose) cout<<p<<" ";
    cout<<endl;

    return 0;
}


- 纠正以上错误,刚仔细看了一下,犯了大错,才发现ceres solver 出来的结果是no convergence(不收敛)

哪里出错了尼?

原来是初始化了初值(不能初始化,只能全0初始化)
这是修改后的代码(要注意)

    double camPose[6]={};
//    camPose[0]=sumVector(X);
//    camPose[1]=sumVector(Y);
//    camPose[2]=sumVector(Z);

正确截图:
在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Ceres Solver 是一个用于非线性最小二乘问题的开源C++库。要使用 Ceres Solver 求解二维变换矩阵,需要定义一个误差函数,并用 Ceres Solver 最小化这个误差函数。 假设我们有一组原始点 $(x_i, y_i)$ 和目标点 $(u_i, v_i)$,要求一个二维变换矩阵 $H$,使得原始点通过 $H$ 变换后的坐标 $(x'_i, y'_i)$ 尽可能接近目标点 $(u_i, v_i)$。可以定义一个误差函数为: $$ E(H) = \sum_{i=1}^n \left\| \begin{bmatrix} u_i \\ v_i \\ 1 \end{bmatrix} - H \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix} \right\|^2 $$ 其中 $\left\| \cdot \right\|$ 表示向量的欧几里得范数。接下来,使用 Ceres Solver 最小化这个误差函数。Ceres Solver 需要提供一个初始的变换矩阵 $H_0$,可以使用单位矩阵作为初始值。 下面是一个使用 Ceres Solver 求解二维变换矩阵的例子: ```c++ #include <ceres/ceres.h> #include <ceres/rotation.h> struct TransformCostFunctor { TransformCostFunctor(double u, double v, double x, double y) : u(u), v(v), x(x), y(y) {} template <typename T> bool operator()(const T* const h, T* residual) const { T x_transformed = h[0] * T(x) + h[1] * T(y) + h[2]; T y_transformed = h[3] * T(x) + h[4] * T(y) + h[5]; T w_transformed = h[6] * T(x) + h[7] * T(y) + h[8]; // 将齐次坐标转换为非齐次坐标 x_transformed /= w_transformed; y_transformed /= w_transformed; // 计算残差 residual[0] = T(u) - x_transformed; residual[1] = T(v) - y_transformed; return true; } const double u, v, x, y; }; int main() { std::vector<double> x = { 1, 2, 3, 4 }; std::vector<double> y = { 1, 3, 4, 2 }; std::vector<double> u = { 2, 4, 6, 8 }; std::vector<double> v = { 2, 6, 8, 4 }; double h[9] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; // 初始变换矩阵 ceres::Problem problem; for (int i = 0; i < x.size(); i++) { ceres::CostFunction* cost_function = new ceres::AutoDiffCostFunction<TransformCostFunctor, 2, 9>( new TransformCostFunctor(u[i], v[i], x[i], y[i])); problem.AddResidualBlock(cost_function, nullptr, h); } ceres::Solver::Options options; options.max_num_iterations = 1000; options.linear_solver_type = ceres::DENSE_QR; options.minimizer_progress_to_stdout = true; ceres::Solver::Summary summary; ceres::Solve(options, &problem, &summary); std::cout << summary.FullReport() << std::endl; std::cout << "Final transformation matrix: " << std::endl; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { std::cout << h[i * 3 + j] << " "; } std::cout << std::endl; } return 0; } ``` 在上面的代码中,我们定义了一个 `TransformCostFunctor` 类,用来计算每个点的误差。这个类重载了 `()` 运算符,接受一个变换矩阵 $H$ 和一个原始点 $(x_i, y_i)$,并计算变换后的坐标 $(x'_i, y'_i)$。然后,将变换后的坐标 $(x'_i, y'_i)$ 和目标点 $(u_i, v_i)$ 的差作为残差返回。 在 `main()` 函数中,我们首先定义了原始点和目标点的坐标。然后,定义了一个初始变换矩阵 `h`。接下来,使用 Ceres Solver 将每个点的误差加入到问题中,并设置求解器的参数。最后调用 `ceres::Solve()` 函数求解变换矩阵,并输出求解结果。 注意,这个例子中使用的是自动微分(AutoDiff),因此需要在 `ceres::AutoDiffCostFunction` 中指定 `TransformCostFunctor` 类的模板参数。如果你想使用其他的求导方法,可以使用 `ceres::NumericDiffCostFunction` 或自己实现 `ceres::CostFunction` 类。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值