C++ Implementation of the SQPnL algorithm.
The algorithm is the generic Perspective-n-Line (PnL) solver described in the paper "Fast and Consistently Accurate Perspective-n-Line Pose Estimation". Supplementary material here.
For a similar PnP solver, see SQPnP.
SQPnL requires the Eigen library to build. Besides rank revealing QR and optionally SVD, the use of Eigen is confined to matrix addition, transposition and multiplication. Choosing Eigen was motivated by its increasing popularity and lightweight character. There are also two examples of using the solver in this repository. The first example requires OpenCV while the second uses plain C-style arrays only. Build will proceed with one of the examples, depending on whether OpenCV is found or not.
The repository uses a shared lbrary (with sqpnp) called SQPEngine which is included as a submodule. In the sqpnl root, initialize the submodules recursively,
git submodule update --init --recursive
Create a build directory in the root of the cloned repository and run cmake:
mkdir build
cd build
cmake ..
or, for a release build,
cmake .. -DCMAKE_BUILD_TYPE=Release
The latter will allow for more accurate timing of average execution time. Finally build everything:
make
To run the PnL example(s), once in the build directory,
./examples/sqpnl_example
The parameters controlling SQPnL are of two types, i.e. those of the SQPEngine and those of SQPnL itself.
See struct EngineParameters in SQPEngine/sqp_engin/sqp_engine.h which contains SQPEngine's parameters that can be specified by the caller.
For instance, to use SVD instead of the default RRQR for the nullspace basis of Omega, the following fragment can be used:
// call solver with user-specified parameters (and equal weights for all lines).
// Note that lines and projections can be defined by pairs of points (points1-points2 and projections1-projections2)
// or with vectors of sqpnl::Line and sqpnl::Projection objects.
sqp_engine::EngineParameters engine_params;
engine_params.omega_nullspace_method = sqp_engine::OmegaNullspaceMethod::SVD;
sqp_engine::PnLSolver solver(points1, points2, projections1, projections2, std::vector<Eigen::Vector3d>(), std::vector<double>(n, 1.0), engine_params);
// sqp_engine::PnLSolver solver(lines, projections, std::vector<Eigen::Vector3d>(), std::vector<double>(n, 1.0), engine_params); // altSimilarly, to use SVD in place of FOAM for the nearest rotation matrix computations, use
engine_params.nearest_rotation_method = sqp_engine::NearestRotationMethod::SVD;For SQPnL's parameters, see struct Parameters in sqpnl/types.h.
For example, to specify that the translation should be computed using the formulation of Mirzaei & Roumeliotis, use
sqp_engine::EngineParameters engine_params;
// set engine_params...
sqpnl::Parameters sqpnl_params;
sqpnl_params.translation_method = sqpnl::TranslationMethod::MIRZAEI;
sqp_engine::PnLSolver solver(points1, points2, projections1, projections2, std::vector<Eigen::Vector3d>(), std::vector<double>(n, 1.0), engine_params, sqpnl_params);If you use this code in your published work, please cite the following paper:
@inproceedings{terzakis2024fast,
title={Fast and Consistently Accurate Perspective-n-Line Pose Estimation},
author={Terzakis, George and Lourakis, Manolis},
booktitle={International Conference on Pattern Recognition},
pages={97--112},
year={2024},
publisher={Springer-Verlag},
url={https://doi.org/10.1007/978-3-031-78456-9_7}
}