@@ -318,8 +318,8 @@ py::tuple BAHelpers::BundleLocal(
318318bool BAHelpers::TriangulateGCP (
319319 const map::GroundControlPoint& point,
320320 const std::unordered_map<map::ShotId, map::Shot>& shots,
321+ float reproj_threshold,
321322 Vec3d& coordinates) {
322- constexpr auto reproj_threshold{1.0 };
323323 constexpr auto min_ray_angle = 0.1 * M_PI / 180.0 ;
324324 constexpr auto min_depth = 1e-3 ; // Assume GCPs 1mm+ away from the camera
325325 MatX3d os, bs;
@@ -357,52 +357,65 @@ size_t BAHelpers::AddGCPToBundle(
357357 const auto & reference = map.GetTopocentricConverter ();
358358 const auto & shots = map.GetShots ();
359359
360- const auto dominant_terms = ba.GetRigInstances ().size () +
361- ba.GetProjectionsCount () +
362- ba.GetRelativeMotionsCount ();
363360
364- size_t total_terms = 0 ;
365- for (const auto & point : gcp) {
366- Vec3d coordinates;
367- if (TriangulateGCP (point, shots, coordinates) || !point.lla_ .empty ()) {
368- ++total_terms;
369- }
370- for (const auto & obs : point.observations_ ) {
371- total_terms += (shots.count (obs.shot_id_ ) > 0 );
372- }
373- }
374-
375- double global_weight = config[" gcp_global_weight" ].cast <double >() *
376- dominant_terms / std::max<size_t >(1 , total_terms);
361+ const float reproj_threshold =
362+ config[" gcp_reprojection_error_threshold" ].cast <float >();
377363
378364 size_t added_gcp_observations = 0 ;
379365 for (const auto & point : gcp) {
380366 const auto point_id = " gcp-" + point.id_ ;
381367 Vec3d coordinates;
382- if (!TriangulateGCP (point, shots, coordinates)) {
368+ if (!TriangulateGCP (point, shots, reproj_threshold, coordinates)) {
383369 if (!point.lla_ .empty ()) {
384370 coordinates = reference.ToTopocentric (point.GetLlaVec3d ());
385371 } else {
386372 continue ;
387373 }
388374 }
375+
376+ double avg_observations = 0 .;
377+ int valid_shots = 0 ;
378+ for (const auto & obs : point.observations_ ) {
379+ const auto shot_it = shots.find (obs.shot_id_ );
380+ if (shot_it != shots.end ()) {
381+ const auto & shot = (shot_it->second );
382+ avg_observations += shot.GetLandmarkObservations ().size ();
383+ ++valid_shots;
384+ }
385+ }
386+
387+ if (!valid_shots) {
388+ continue ;
389+ }
390+ avg_observations /= valid_shots;
391+
392+ int gcp_obs = 0 ;
393+ for (const auto & obs : point.observations_ ) {
394+ const auto & shot_id = obs.shot_id_ ;
395+ if (shots.count (shot_id) > 0 ) {
396+ ++gcp_obs;
397+ }
398+ }
399+
400+ const double prior_weight = config[" gcp_global_weight" ].cast <double >() * avg_observations / gcp_obs;
389401 constexpr auto point_constant{false };
390402 ba.AddPoint (point_id, coordinates, point_constant);
391403 if (!point.lla_ .empty ()) {
392404 const auto point_std = Vec3d (config[" gcp_horizontal_sd" ].cast <double >(),
393405 config[" gcp_horizontal_sd" ].cast <double >(),
394406 config[" gcp_vertical_sd" ].cast <double >());
395407 ba.AddPointPrior (point_id, reference.ToTopocentric (point.GetLlaVec3d ()),
396- point_std / global_weight , point.has_altitude_ );
408+ point_std / prior_weight , point.has_altitude_ );
397409 }
398410
399411 // Now iterate through the observations
412+ const double obs_weight = config[" gcp_global_weight" ].cast <double >() * avg_observations / gcp_obs;
400413 for (const auto & obs : point.observations_ ) {
401414 const auto & shot_id = obs.shot_id_ ;
402415 if (shots.count (shot_id) > 0 ) {
403416 constexpr double scale{0.001 };
404417 ba.AddPointProjectionObservation (shot_id, point_id, obs.projection_ ,
405- scale / global_weight );
418+ scale / obs_weight );
406419 ++added_gcp_observations;
407420 }
408421 }
@@ -718,7 +731,7 @@ py::dict BAHelpers::Bundle(
718731 AddGCPToBundle (ba, map, gcp, config);
719732 }
720733
721- if (config[" bundle_compensate_gps_bias" ].cast <bool >()) {
734+ if (config[" bundle_compensate_gps_bias" ].cast <bool >() && !gcp. empty () ) {
722735 const auto & biases = map.GetBiases ();
723736 for (const auto & camera : map.GetCameras ()) {
724737 ba.SetCameraBias (camera.first , biases.at (camera.first ));
@@ -861,7 +874,7 @@ void BAHelpers::AlignmentConstraints(
861874 continue ;
862875 }
863876 Vec3d coordinates;
864- if (TriangulateGCP (point, shots, coordinates)) {
877+ if (TriangulateGCP (point, shots, config[ " gcp_reprojection_error_threshold " ]. cast < float >(), coordinates)) {
865878 Xp.row (idx) = topocentricConverter.ToTopocentric (point.GetLlaVec3d ());
866879 X.row (idx) = coordinates;
867880 ++idx;
0 commit comments