ceres是C++常用的最小二乘问题求解库,最近研究colmap代码,顺便学习一下
下面举两个简单例子来说明:
问题一:一维优化,让x收敛到0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| struct CostFunctor { template <typename T> bool operator()(const T* const x, T* residual) const { residual[0] = T(10.0) - x[0]; return true; } }; int main(int argc, char** argv){ double x = 0.0;
ceres::Problem problem; problem.AddResidualBlock( new ceres::AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor), nullptr, &x ); ceres::Solver::Options options; options.linear_solver_type = ceres::DENSE_QR; options.minimizer_progress_to_stdout = true;
ceres::Solver::Summary summary; ceres::Solver(options, &problem, &summary);
std::cout << summary.BriefReport() << std::endl; std::cout << "Final x: " << x << std::endl; return 0; }
|
问题二:曲线拟合y=e^{ax+b},优化a、b
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| struct CostFunctor { CostFunctor(double x, double y) : x_(x), y_(y) {} template <typename T> bool operator()(const T* const ab, T* residual) const { residual[0] = y_ - exp(ab[0] * x_ + ab[1]); return true; } double x_, y_; }; int main(int argc, char** argv){ double ab[2] = {0.0, 0.0}; ceres::Problem problem; for (int 1 = 0; i < x_data.size(); ++i){ problem.AddResidualBlock( new ceres::AutoDiffCostFunction<CostFunctor, 1, 2>( new CostFunctor(x_data[i], y_data[i]) ), nullptr, ab ); } ceres::Solver::Options options; options.linear_solver_type = ceres::DENSE_QR; options.minimizer_progress_to_stdout = true; ceres::Solver::Summary summary; ceres::Solver(options, &problem, &summary); std::cout << summary.BriefReport() << std::endl; std::cout << "Final a, b: " << ab[0] << ", " << ab[1] << std::endl; return 0; }
|
注意理解残差维度不等于参数维度,举例:
- 输入x、y,输出z,残差维度=1,参数维度=2;
- 输入x,输出坐标 (u, v),残差维度=2,参数维度=1;
还有其他一些使用技巧,例如核函数、给problem设置固定参数和上下界,这里就不赘述了