I have been attempting to estimate a bunch of 3d coordinates viewed via a multi-view setup with known poses, I have the code running, but the output of ceres seems baffling.
There are 7 image frames/poses, and only the re-projection error with respect to the last pose(7th frame) is close to 0. 2d Reprojections of the ceres-estimated 3dpoint onto rest of the frames(1-6) do not match with the actual pixel measurements. If I reduce the number of frames, it gives out a different 3d point whose 2d projections again match only with the last frame.
I'm adding code snippets here, can someone just look at the code and give any insights as to why this could be happening?
class ReprojectionError {
public:
ReprojectionError(
const Eigen::Matrix<double, 3, 4>& projection_matrix,
const Eigen::Vector2d& feature)
: projection_matrix_(projection_matrix), feature_(feature) {}
template <typename T>
bool operator()(const T* input_point, T* reprojection_error) const {
Eigen::Map<const Eigen::Matrix<T, 4, 1> > point(input_point);
// Multiply the point with the projection matrix, then perform homogeneous
// normalization to obtain the 2D pixel location of the reprojection.
const Eigen::Matrix<T, 2, 1> reprojected_pixel = (projection_matrix_ * point).hnormalized();
// Reprojection error is the distance from the reprojection to the observed
// feature location.
cout << point << endl;
reprojection_error[0] = feature_[0] - reprojected_pixel[0];
reprojection_error[1] = feature_[1] - reprojected_pixel[1];
return true;
}
static ceres::CostFunction * Create(const Eigen::Matrix<double, 3, 4>& projection_matrix_,
const Eigen::Vector2d& feature_) {
return (new ceres::AutoDiffCostFunction<ReprojectionError, 2,4>
(new ReprojectionError(projection_matrix_,feature_)));
}
private:
const Eigen::Matrix<double, 3, 4>& projection_matrix_;
const Eigen::Vector2d& feature_;
};
Eigen::Vector3d Triangulate(std::vector<std::pair
<Eigen::Matrix<double, 3, 4>,Eigen::Vector2d>> datas) {
Eigen::Vector4d x;
x << 0,0,0,1;
ceres::Problem problem;
ceres::Solver::Options options;
ceres::LossFunction* loss= nullptr;
ceres::Solver::Summary summary;
for(auto data:datas) {
problem.AddResidualBlock(ReprojectionError::Create(data.first,data.second),loss,&x[0]);
}
ceres::Solve(options,&problem, &summary);
std::cout << summary.FullReport() << "\n";
return x.hnormalized();
}
Here's the summary:
Solver Summary (v 2.0.0-eigen-(3.3.4)-lapack-suitesparse-(5.1.2)-cxsparse-(3.1.9)-eigensparse-no_openmp)
Original Reduced
Parameter blocks 1 1
Parameters 4 4
Residual blocks 7 7
Residuals 14 14
Minimizer TRUST_REGION
Sparse linear algebra library SUITE_SPARSE
Trust region strategy LEVENBERG_MARQUARDT
Given Used
Linear solver SPARSE_NORMAL_CHOLESKY SPARSE_NORMAL_CHOLESKY
Threads 1 1
Linear solver ordering AUTOMATIC 1
Cost:
Initial 4.220501e+04
Final 2.554256e-13
Change 4.220501e+04
Minimizer iterations 5
Successful steps 5
Unsuccessful steps 0
Time (in seconds):
Preprocessor 0.000060
Residual only evaluation 0.000774 (5)
Jacobian & residual evaluation 0.002446 (5)
Linear solver 0.000053 (5)
Minimizer 0.003332
Postprocessor 0.000002
Total 0.003394
Termination: CONVERGENCE (Parameter tolerance reached. Relative step_norm: 1.091788e-09 <= 1.000000e-08.)