@@ -351,8 +351,8 @@ py::tuple BAHelpers::BundleLocal(
351351bool BAHelpers::TriangulateGCP (
352352 const map::GroundControlPoint& point,
353353 const std::unordered_map<map::ShotId, map::Shot>& shots,
354+ float reproj_threshold,
354355 Vec3d& coordinates) {
355- constexpr auto reproj_threshold{1.0 };
356356 constexpr auto min_ray_angle = 0.1 * M_PI / 180.0 ;
357357 constexpr auto min_depth = 1e-3 ; // Assume GCPs 1mm+ away from the camera
358358 MatX3d os, bs;
@@ -394,48 +394,56 @@ size_t BAHelpers::AddGCPToBundle(
394394 ba.GetProjectionsCount () +
395395 ba.GetRelativeMotionsCount ();
396396
397- size_t total_terms = 0 ;
398- for (const auto & point : gcp) {
399- Vec3d coordinates;
400- if (TriangulateGCP (point, shots, coordinates) || !point.lla_ .empty ()) {
401- ++total_terms;
402- }
403- for (const auto & obs : point.observations_ ) {
404- total_terms += (shots.count (obs.shot_id_ ) > 0 );
405- }
406- }
407-
408- double global_weight = config[" gcp_global_weight" ].cast <double >() *
409- dominant_terms / std::max<size_t >(1 , total_terms);
397+ const float reproj_threshold =
398+ config[" gcp_reprojection_error_threshold" ].cast <float >();
410399
411400 size_t added_gcp_observations = 0 ;
412401 for (const auto & point : gcp) {
413402 const auto point_id = " gcp-" + point.id_ ;
414403 Vec3d coordinates;
415- if (!TriangulateGCP (point, shots, coordinates)) {
404+ if (!TriangulateGCP (point, shots, reproj_threshold, coordinates)) {
416405 if (!point.lla_ .empty ()) {
417406 coordinates = reference.ToTopocentric (point.GetLlaVec3d ());
418407 } else {
419408 continue ;
420409 }
421410 }
411+
412+ double avg_observations = 0 .;
413+ int valid_shots = 0 ;
414+ for (const auto & obs : point.observations_ ) {
415+ const auto shot_it = shots.find (obs.shot_id_ );
416+ if (shot_it != shots.end ()) {
417+ const auto & shot = (shot_it->second );
418+ avg_observations += shot.GetLandmarkObservations ().size ();
419+ ++valid_shots;
420+ }
421+ }
422+
423+ if (!valid_shots) {
424+ continue ;
425+ }
426+ avg_observations /= valid_shots;
427+
428+ const double prior_weight = config[" gcp_global_weight" ].cast <double >() * avg_observations;
422429 constexpr auto point_constant{false };
423430 ba.AddPoint (point_id, coordinates, point_constant);
424431 if (!point.lla_ .empty ()) {
425432 const auto point_std = Vec3d (config[" gcp_horizontal_sd" ].cast <double >(),
426433 config[" gcp_horizontal_sd" ].cast <double >(),
427434 config[" gcp_vertical_sd" ].cast <double >());
428435 ba.AddPointPrior (point_id, reference.ToTopocentric (point.GetLlaVec3d ()),
429- point_std / global_weight , point.has_altitude_ );
436+ point_std / prior_weight , point.has_altitude_ );
430437 }
431438
432439 // Now iterate through the observations
440+ const double obs_weight = config[" gcp_global_weight" ].cast <double >() * avg_observations;
433441 for (const auto & obs : point.observations_ ) {
434442 const auto & shot_id = obs.shot_id_ ;
435443 if (shots.count (shot_id) > 0 ) {
436444 constexpr double scale{0.001 };
437445 ba.AddPointProjectionObservation (shot_id, point_id, obs.projection_ ,
438- scale / global_weight );
446+ scale / obs_weight );
439447 ++added_gcp_observations;
440448 }
441449 }
@@ -829,7 +837,7 @@ py::dict BAHelpers::Bundle(
829837 AddGCPToBundle (ba, map, gcp, config);
830838 }
831839
832- if (config[" bundle_compensate_gps_bias" ].cast <bool >()) {
840+ if (config[" bundle_compensate_gps_bias" ].cast <bool >() && !gcp. empty () ) {
833841 const auto & biases = map.GetBiases ();
834842 for (const auto & camera : map.GetCameras ()) {
835843 ba.SetCameraBias (camera.first , biases.at (camera.first ));
@@ -989,7 +997,7 @@ void BAHelpers::AlignmentConstraints(
989997 continue ;
990998 }
991999 Vec3d coordinates;
992- if (TriangulateGCP (point, shots, coordinates)) {
1000+ if (TriangulateGCP (point, shots, config[ " gcp_reprojection_error_threshold " ]. cast < float >(), coordinates)) {
9931001 Xp.row (idx) = topocentricConverter.ToTopocentric (point.GetLlaVec3d ());
9941002 X.row (idx) = coordinates;
9951003 ++idx;
0 commit comments