@@ -54,6 +54,27 @@ BOOST_AUTO_TEST_CASE(BUNDLE_ADJUSTMENT_EffectiveMinimization_Pinhole)
5454 BOOST_CHECK_LT (dResidual_after, dResidual_before);
5555}
5656
57+ BOOST_AUTO_TEST_CASE (BUNDLE_ADJUSTMENT_EffectiveMinimization_Relative_Pinhole)
58+ {
59+ const int nviews = 3 ;
60+ const int npoints = 6 ;
61+ NViewDatasetConfigurator config;
62+ config._useRelative = true ;
63+ const NViewDataSet d = NRealisticCamerasRing (nviews, npoints, config);
64+
65+ // Translate the input dataset to a SfMData scene
66+ SfMData sfmData = getInputScene (d, config, EINTRINSIC::PINHOLE_CAMERA, EDISTORTION::DISTORTION_NONE);
67+
68+ const double dResidual_before = RMSE (sfmData);
69+
70+ // Call the BA interface and let it refine (Structure and Camera parameters [Intrinsics|Motion])
71+ std::shared_ptr<BundleAdjustment> ba_object = std::make_shared<BundleAdjustmentCeres>();
72+ BOOST_CHECK (ba_object->adjust (sfmData));
73+
74+ const double dResidual_after = RMSE (sfmData);
75+ BOOST_CHECK_LT (dResidual_after, dResidual_before);
76+ }
77+
5778BOOST_AUTO_TEST_CASE (BUNDLE_ADJUSTMENT_EffectiveMinimization_PinholeRadialK1)
5879{
5980 const int nviews = 3 ;
@@ -246,15 +267,26 @@ double RMSE(const SfMData& sfm_data)
246267{
247268 // Compute residuals for each observation
248269 std::vector<double > vec;
249- for (Landmarks::const_iterator iterTracks = sfm_data. getLandmarks (). begin (); iterTracks != sfm_data.getLandmarks (). end (); ++iterTracks )
270+ for (const auto & [lid, landmark]: sfm_data.getLandmarks ())
250271 {
251- const Observations& observations = iterTracks->second .getObservations ();
252- for (Observations::const_iterator itObs = observations.begin (); itObs != observations.end (); ++itObs)
272+ const Observations& observations = landmark.getObservations ();
273+
274+
275+ Pose3 world_T_reference;
276+ if (landmark.referenceViewIndex != UndefinedIndexT)
253277 {
254- const View* view = sfm_data.getViews ().find (itObs->first )->second .get ();
255- const Pose3 pose = sfm_data.getPose (*view).getTransform ();
256- const std::shared_ptr<IntrinsicBase> intrinsic = sfm_data.getIntrinsics ().find (view->getIntrinsicId ())->second ;
257- const Vec2 residual = intrinsic->residual (pose, iterTracks->second .X .homogeneous (), itObs->second .getCoordinates ());
278+ const View & refView = sfm_data.getView (landmark.referenceViewIndex );
279+ world_T_reference = sfm_data.getPose (refView).getTransform ().inverse ();
280+ }
281+
282+ for (const auto [idView, observation] : observations)
283+ {
284+ const View & view = sfm_data.getView (idView);
285+ const Pose3 camera_T_world = sfm_data.getPose (view).getTransform ();
286+ const Pose3 camera_T_reference = camera_T_world * world_T_reference;
287+ const IntrinsicBase & intrinsic = sfm_data.getIntrinsic (view.getIntrinsicId ());
288+ const Vec2 residual = intrinsic.residual (camera_T_reference, landmark.X .homogeneous (), observation.getCoordinates ());
289+
258290 vec.push_back (residual (0 ));
259291 vec.push_back (residual (1 ));
260292 }
@@ -308,15 +340,24 @@ SfMData getInputScene(const NViewDataSet& d, const NViewDatasetConfigurator& con
308340 // Collect the image of point i in each frame.
309341 Landmark landmark;
310342 landmark.X = d._X .col (i);
343+
344+ if (config._useRelative )
345+ {
346+ landmark.referenceViewIndex = nviews / 2 ;
347+ geometry::Pose3 p = sfm_data.getAbsolutePose (landmark.referenceViewIndex ).getTransform ();
348+ landmark.X = p (landmark.X );
349+ }
350+
311351 for (int j = 0 ; j < nviews; ++j)
312352 {
313353 Vec2 pt = d._x [j].col (i);
314354 // => random noise between [-.5,.5] is added
315- pt (0 ) += rand () / RAND_MAX - .5 ;
316- pt (1 ) += rand () / RAND_MAX - .5 ;
355+ pt (0 ) += double ( rand ()) / double ( RAND_MAX) - .5 ;
356+ pt (1 ) += double ( rand ()) / double ( RAND_MAX) - .5 ;
317357
318358 landmark.getObservations ()[j] = Observation (pt, i, unknownScale);
319359 }
360+
320361 sfm_data.getLandmarks ()[i] = landmark;
321362 }
322363
0 commit comments