58 const size_t cur_iter,
const double cur_total_sq_error,
59 const size_t max_iters,
64 const double avr_err =
65 std::sqrt(cur_total_sq_error / input_observations.size());
67 if ((cur_iter % 10) == 0)
69 cout <<
"[PROGRESS] Iter: " << cur_iter
70 <<
" avrg err in px: " << avr_err << endl;
82 cout <<
"Optimizing " << allObs.size() <<
" feature observations.\n";
86 extra_params[
"max_iterations"] = 2000;
89 extra_params[
"robust_kernel"] = 0;
90 extra_params[
"kernel_param"] = 5.0;
91 extra_params[
"profiler"] = 1;
94 allObs, camera_params, frame_poses, landmark_points, extra_params,
105 int main(
int argc,
char** argv)
110 if ((argc != 1 && argc != 3 && argc != 4) ||
111 (argc == 2 && !
strcpy(argv[1],
"--help")))
114 << argv[0] <<
" --help -> Shows this help\n" 115 << argv[0] <<
" -> Simulation\n" 117 <<
" <feats.txt> <cam_model.cfg> -> Data in MRPT format\n" 119 <<
" <cams.txt> <points.cfg> <calib.txt> -> SBA format\n";
133 landmark_points_noisy;
142 camera_params.
ncols = 800;
143 camera_params.
nrows = 600;
144 camera_params.
fx(400);
145 camera_params.
fy(400);
146 camera_params.
cx(400);
147 camera_params.
cy(300);
151 const size_t nPts = 100;
154 const double L2 = 10;
155 const double L3 = 10;
156 const double max_camera_dist = L1 * 4;
158 const double cameraPathLen = L1 * 1.2;
162 const double STD_PX_ERROR = 0.10;
164 const double STD_PX_ERROR_OUTLIER = 5;
165 const double PROBABILITY_OUTLIERS = 0;
167 const double STD_PT3D = 0.10;
168 const double STD_CAM_XYZ = 0.05;
169 const double STD_CAM_ANG =
DEG2RAD(5);
171 landmark_points_real.resize(nPts);
172 for (
size_t i = 0; i < nPts; i++)
174 landmark_points_real[i].x = rg.drawUniform(-L1, L1);
175 landmark_points_real[i].y = rg.drawUniform(-L2, L2);
176 landmark_points_real[i].z = rg.drawUniform(-L3, L3);
180 const double camPosesSteps = 2 * cameraPathLen / 20;
181 frame_poses_real.clear();
183 for (
double x = -cameraPathLen;
x < cameraPathLen;
196 frame_poses_real.push_back(
202 size_t numOutliers = 0;
204 map<TCameraPoseID, size_t> numViewedFrom;
205 for (
size_t i = 0; i < frame_poses_real.size();
209 for (
size_t j = 0; j < landmark_points_real.size(); j++)
214 camera_params, frame_poses_real[i],
215 landmark_points_real[j]);
217 const bool is_outlier =
218 (rg.drawUniform(0.0, 1.0) < PROBABILITY_OUTLIERS);
219 px.
x += rg.drawGaussian1D(
220 0, is_outlier ? STD_PX_ERROR_OUTLIER : STD_PX_ERROR);
221 px.
y += rg.drawGaussian1D(
222 0, is_outlier ? STD_PX_ERROR_OUTLIER : STD_PX_ERROR);
225 if (px.
x < 0 || px.
y < 0 || px.
x > camera_params.ncols ||
226 px.
y > camera_params.nrows)
231 TPoint3D(frame_poses_real[i].asTPose()),
232 landmark_points_real[j]);
233 if (dist > max_camera_dist)
continue;
236 if (is_outlier) numOutliers++;
241 cout <<
"Simulated: " << allObs.size()
242 <<
" observations (of which: " << numOutliers
243 <<
" are outliers).\n";
245 ASSERT_EQUAL_(numViewedFrom.size(), frame_poses_real.size());
249 std::map<TCameraPoseID, TCameraPoseID> old2new_camIDs;
250 std::map<TLandmarkID, TLandmarkID> old2new_lmIDs;
251 allObs2.
compressIDs(&old2new_camIDs, &old2new_lmIDs);
253 ASSERT_EQUAL_(old2new_camIDs.size(), frame_poses_real.size());
255 old2new_lmIDs.size(), landmark_points_real.size());
259 frame_poses_noisy = frame_poses_real;
260 landmark_points_noisy = landmark_points_real;
261 for (
size_t i = 0; i < landmark_points_noisy.size(); i++)
262 landmark_points_noisy[i] +=
TPoint3D(
263 rg.drawGaussian1D(0, STD_PT3D),
264 rg.drawGaussian1D(0, STD_PT3D),
265 rg.drawGaussian1D(0, STD_PT3D));
267 for (
size_t i = 1; i < frame_poses_noisy.size();
270 CPose3D bef = frame_poses_noisy[i];
272 frame_poses_noisy[i].
x() +
273 rg.drawGaussian1D(0, STD_CAM_XYZ),
274 frame_poses_noisy[i].y() +
275 rg.drawGaussian1D(0, STD_CAM_XYZ),
276 frame_poses_noisy[i].z() +
277 rg.drawGaussian1D(0, STD_CAM_XYZ),
278 frame_poses_noisy[i].yaw() +
279 rg.drawGaussian1D(0, STD_CAM_ANG),
280 frame_poses_noisy[i].pitch() +
281 rg.drawGaussian1D(0, STD_CAM_ANG),
282 frame_poses_noisy[i].roll() +
283 rg.drawGaussian1D(0, STD_CAM_ANG));
287 frame_poses = frame_poses_noisy;
288 landmark_points = landmark_points_noisy;
291 vector<std::array<double,2> > resids;
293 cout <<
"Initial avr error in px: " << std::sqrt(initial_total_sq_err/allObs.size()) << endl;
298 camera_params, allObs, frame_poses, landmark_points);
301 double landmarks_total_sq_err = 0;
302 for (
size_t i = 0; i < landmark_points.size(); i++)
303 landmarks_total_sq_err +=
square(
304 landmark_points_real[i].distanceTo(landmark_points[i]));
306 double cam_point_total_sq_err = 0;
307 for (
size_t i = 0; i < frame_poses.size(); i++)
308 cam_point_total_sq_err +=
309 square(frame_poses[i].distanceTo(frame_poses_real[i]));
311 cout <<
"RMSE of recovered landmark positions: " 312 << std::sqrt(landmarks_total_sq_err / landmark_points.size())
314 cout <<
"RMSE of recovered camera positions: " 315 << std::sqrt(cam_point_total_sq_err / frame_poses.size())
324 const string feats_fil =
string(argv[1]);
325 const string cam_fil =
string(argv[2]);
327 cout <<
"Loading observations from: " << feats_fil <<
"...";
336 cout <<
"Loading camera params from: " << cam_fil;
338 camera_params.loadFromConfigFile(
"CAMERA", cfgCam);
341 cout <<
"Initial gross estimate...";
343 allObs, camera_params, frame_poses, landmark_points);
350 const string cam_frames_fil =
string(argv[1]);
351 const string obs_fil =
string(argv[2]);
352 const string calib_fil =
string(argv[3]);
355 cout <<
"Loading initial camera frames from: " 356 << cam_frames_fil <<
"...";
362 std::istringstream ss;
363 while (fil.getNextLine(ss))
366 ss >>
q[0] >>
q[1] >>
q[2] >>
q[3] >>
t[0] >>
t[1] >>
370 q[0],
q[1],
q[2],
q[3]));
375 cout <<
"Done. " << frame_poses.size()
376 <<
" cam frames loaded\n";
378 frame_poses_noisy = frame_poses;
383 cout <<
"Loading observations & feature 3D points from: " 388 landmark_points.clear();
391 std::istringstream ss;
392 while (fil.getNextLine(ss))
397 ss >>
t[0] >>
t[1] >>
t[2] >> N;
399 const TLandmarkID feat_id = landmark_points.size();
401 landmark_points.push_back(pt);
404 for (
size_t i = 0; i < N; i++)
408 ss >> frame_id >> px.
x >> px.
y;
417 cout <<
"Done. " << landmark_points.size() <<
" points, " 418 << allObs.size() <<
" observations read.\n";
420 landmark_points_real = landmark_points;
426 cam_pars.loadFromTextFile(calib_fil);
430 camera_params.fx(cam_pars(0, 0));
431 camera_params.fy(cam_pars(1, 1));
432 camera_params.cx(cam_pars(0, 2));
433 camera_params.cy(cam_pars(1, 2));
435 cout <<
"camera calib:\n" << camera_params.dumpAsText() << endl;
443 camera_params, allObs, frame_poses, landmark_points);
454 -200, 200, -200, 200, 0, 5);
455 obj->setColor(0.7, 0.7, 0.7);
459 if (!landmark_points_real.empty())
462 obj->setPointSize(2);
463 obj->setColor(0, 0, 0);
464 obj->loadFromPointsList(landmark_points_real);
468 if (!landmark_points_noisy.empty())
471 obj->setPointSize(4);
472 obj->setColor(0.7, 0.2, 0.2, 0);
473 obj->loadFromPointsList(landmark_points_noisy);
480 obj->setPointSize(3);
481 obj->setColor(0, 0, 1, 1.0);
482 obj->loadFromPointsList(landmark_points);
492 win.setCameraZoom(100);
494 win.unlockAccess3DScene();
499 "Avr log-error with iterations", 500, 200);
504 cout <<
"Close the 3D window or press a key to exit.\n";
509 catch (std::exception& e)
511 std::cout <<
"MRPT exception caught: " << e.what() << std::endl;
516 printf(
"Untyped exception!!");
525 mrpt::make_aligned_shared<mrpt::opengl::CSetOfObjects>();
527 for (
size_t i = 0; i < poses.size(); i++)
536 corner->setName(
format(
"%u", (
unsigned int)i));
537 corner->enableShowName();
double x() const
Common members of all points & poses classes.
void loadFromTextFile(const std::string &filName)
Load from a text file, in the format described in saveToTextFile.
uint64_t TCameraPoseID
Unique IDs for camera frames (poses)
Create a GUI window and display plots with MATLAB-like interfaces and commands.
uint64_t TLandmarkID
Unique IDs for landmarks.
double fx() const
Get the value of the focal length x-value (in pixels).
double DEG2RAD(const double x)
Degrees to radians.
GLdouble GLdouble GLdouble GLdouble q
This class allows loading and storing values and vectors of different types from ".ini" files easily.
bool fileExists(const std::string &fileName)
Test if a given file (or directory) exists.
double fy() const
Get the value of the focal length y-value (in pixels).
A class for parsing text files, returning each non-empty and non-comment line, along its line number...
Column vector, like Eigen::MatrixX*, but automatically initialized to zeros since construction...
One feature observation entry, used within sequences with TSequenceFeatureObservations.
A pair (x,y) of pixel coordinates (subpixel resolution).
void ba_initial_estimate(const mrpt::vision::TSequenceFeatureObservations &observations, const mrpt::img::TCamera &camera_params, mrpt::vision::TFramePosesVec &frame_poses, mrpt::vision::TLandmarkLocationsVec &landmark_points)
Fills the frames & landmark points maps with an initial gross estimate from the sequence observations...
A thred-safe pseudo random number generator, based on an internal MT19937 randomness generator...
GLsizei GLsizei GLuint * obj
A complete sequence of observations of features from different camera frames (poses).
T square(const T x)
Inline function for the square of a number.
#define ASSERT_(f)
Defines an assertion mechanism.
This base provides a set of functions for maths stuff.
double cy() const
Get the value of the principal point y-coordinate (in pixels).
#define ASSERT_EQUAL_(__A, __B)
Assert comparing two values, reporting their actual values upon failure.
void my_BundleAdjustmentFeedbackFunctor(const size_t cur_iter, const double cur_total_sq_error, const size_t max_iters, const TSequenceFeatureObservations &input_observations, const TFramePosesVec ¤t_frame_estimate, const TLandmarkLocationsVec ¤t_landmark_estimate)
Classes for computer vision, detectors, features, etc.
Structure to hold the parameters of a pinhole camera model.
A class used to store a 3D pose as a translation (x,y,z) and a quaternion (qr,qx,qy,qz).
double reprojectionResiduals(const mrpt::vision::TSequenceFeatureObservations &observations, const mrpt::img::TCamera &camera_params, const mrpt::vision::TFramePosesVec &frame_poses, const mrpt::vision::TLandmarkLocationsVec &landmark_points, std::vector< std::array< double, 2 >> &out_residuals, const bool frame_poses_are_inverse, const bool use_robust_kernel=true, const double kernel_param=3.0, std::vector< double > *out_kernel_1st_deriv=nullptr)
Compute reprojection error vector (used from within Bundle Adjustment methods, but can be used in gen...
mrpt::gui::CDisplayWindow3D::Ptr win
GLsizei const GLchar ** string
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
double cx() const
Get the value of the principal point x-coordinate (in pixels).
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
mrpt::img::TPixelCoordf projectPoint_no_distortion(const mrpt::img::TCamera &cam_params, const mrpt::poses::CPose3D &F, const mrpt::math::TPoint3D &P)
Project a single 3D point with global coordinates P into a camera at pose F, without distortion param...
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
CSetOfObjects::Ptr CornerXYZSimple(float scale=1.0, float lineWidth=1.0)
Returns three arrows representing a X,Y,Z 3D corner (just thick lines instead of complex arrows for f...
void setFromValues(const double x0, const double y0, const double z0, const double yaw=0, const double pitch=0, const double roll=0)
Set the pose from a 3D position (meters) and yaw/pitch/roll angles (radians) - This method recomputes...
Lightweight 3D pose (three spatial coordinates, plus three angular coordinates).
mrpt::aligned_std_vector< mrpt::poses::CPose3D > TFramePosesVec
A list of camera frames (6D poses), which assumes indexes are unique, consecutive IDs...
The namespace for 3D scene representation and rendering.
void bundle_adj_full_demo(const TCamera &camera_params, const TSequenceFeatureObservations &allObs, TFramePosesVec &frame_poses, TLandmarkLocationsVec &landmark_points)
Classes for creating GUI windows for 2D and 3D visualization.
A quaternion, which can represent a 3D rotation as pair , with a real part "r" and a 3D vector ...
double bundle_adj_full(const mrpt::vision::TSequenceFeatureObservations &observations, const mrpt::img::TCamera &camera_params, mrpt::vision::TFramePosesVec &frame_poses, mrpt::vision::TLandmarkLocationsVec &landmark_points, const mrpt::system::TParametersDouble &extra_params=mrpt::system::TParametersDouble(), const mrpt::vision::TBundleAdjustmentFeedbackFunctor user_feedback=mrpt::vision::TBundleAdjustmentFeedbackFunctor())
Sparse Levenberg-Marquart solution to bundle adjustment - optimizes all the camera frames & the landm...
char * strcpy(char *dest, size_t destSize, const char *source) noexcept
An OS-independent version of strcpy.
std::vector< mrpt::math::TPoint3D > TLandmarkLocationsVec
A list of landmarks (3D points), which assumes indexes are unique, consecutive IDs.
CVectorDouble history_avr_err
uint32_t ncols
Camera resolution.
void compressIDs(std::map< TCameraPoseID, TCameraPoseID > *old2new_camIDs=nullptr, std::map< TLandmarkID, TLandmarkID > *old2new_lmIDs=nullptr)
Rearrange frame and feature IDs such as they start at 0 and there are no gaps.
mrpt::opengl::CSetOfObjects::Ptr framePosesVecVisualize(const TFramePosesVec &poses, const double len, const double lineWidth)
double distance(const TPoint2D &p1, const TPoint2D &p2)
Gets the distance between two points in a 2D space.
void decimateCameraFrames(const size_t decimate_ratio)
Remove all but one out of decimate_ratio camera frame IDs from the list (eg: from N camera pose IDs a...
A graphical user interface (GUI) for efficiently rendering 3D scenes in real-time.