Fix bundle adjuster perturbation assertions Avoid debug-mode assertions from zero width normal distributions when optional perturbations are disabled. Change-Id: Ic078482a5f845ba3095ba4389a1bcdadf426944e
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e3ba5c4..355fc25 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt
@@ -102,6 +102,19 @@ bal_problem.cc) target_link_libraries(bundle_adjuster PRIVATE absl::log_initialize absl::flags absl::flags_parse Ceres::ceres) +if (BUILD_TESTING) + add_executable(bal_problem_test + bal_problem_test.cc + bal_problem.cc) + target_compile_definitions(bal_problem_test PRIVATE + CERES_TEST_DATA_DIR="${Ceres_SOURCE_DIR}/data") + target_link_libraries(bal_problem_test PRIVATE + absl::log_initialize + Ceres::ceres + GTest::gmock_main) + add_test(NAME bal_problem_test COMMAND bal_problem_test) +endif (BUILD_TESTING) + add_executable(libmv_bundle_adjuster libmv_bundle_adjuster.cc) target_link_libraries(libmv_bundle_adjuster PRIVATE absl::log_initialize absl::flags absl::flags_parse Ceres::ceres)
diff --git a/examples/bal_problem.cc b/examples/bal_problem.cc index d6cb2b7..28b3bb9 100644 --- a/examples/bal_problem.cc +++ b/examples/bal_problem.cc
@@ -298,34 +298,36 @@ CHECK_GE(rotation_sigma, 0.0); CHECK_GE(translation_sigma, 0.0); std::mt19937 prng; - std::normal_distribution<double> point_noise_distribution(0.0, point_sigma); double* points = mutable_points(); if (point_sigma > 0) { + std::normal_distribution<double> point_noise_distribution(0.0, point_sigma); for (int i = 0; i < num_points_; ++i) { PerturbPoint3(std::bind(point_noise_distribution, std::ref(prng)), points + 3 * i); } } - std::normal_distribution<double> rotation_noise_distribution(0.0, - point_sigma); - std::normal_distribution<double> translation_noise_distribution( - 0.0, translation_sigma); - for (int i = 0; i < num_cameras_; ++i) { - double* camera = mutable_cameras() + camera_block_size() * i; - - double angle_axis[3]; - double center[3]; - // Perturb in the rotation of the camera in the angle-axis - // representation. - CameraToAngleAxisAndCenter(camera, angle_axis, center); - if (rotation_sigma > 0.0) { + if (rotation_sigma > 0.0) { + std::normal_distribution<double> rotation_noise_distribution( + 0.0, rotation_sigma); + for (int i = 0; i < num_cameras_; ++i) { + double* camera = mutable_cameras() + camera_block_size() * i; + double angle_axis[3]; + double center[3]; + // Perturb in the rotation of the camera in the angle-axis + // representation. + CameraToAngleAxisAndCenter(camera, angle_axis, center); PerturbPoint3(std::bind(rotation_noise_distribution, std::ref(prng)), angle_axis); + AngleAxisAndCenterToCamera(angle_axis, center, camera); } - AngleAxisAndCenterToCamera(angle_axis, center, camera); + } - if (translation_sigma > 0.0) { + if (translation_sigma > 0.0) { + std::normal_distribution<double> translation_noise_distribution( + 0.0, translation_sigma); + for (int i = 0; i < num_cameras_; ++i) { + double* camera = mutable_cameras() + camera_block_size() * i; PerturbPoint3(std::bind(translation_noise_distribution, std::ref(prng)), camera + camera_block_size() - 6); }
diff --git a/examples/bal_problem_test.cc b/examples/bal_problem_test.cc new file mode 100644 index 0000000..5be8965 --- /dev/null +++ b/examples/bal_problem_test.cc
@@ -0,0 +1,66 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2026 Google Inc. All rights reserved. +// http://ceres-solver.org/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sergiu.deitsch@gmail.com (Sergiu Deitsch) + +#include "bal_problem.h" + +#include <algorithm> +#include <cmath> +#include <vector> + +#include "gtest/gtest.h" + +namespace ceres::examples { +namespace { + +TEST(BALProblem, PerturbsRotationWhenPointPerturbationIsDisabled) { + constexpr const char* kProblemFile = + CERES_TEST_DATA_DIR "/problem-16-22106-pre.txt"; + BALProblem baseline(kProblemFile, false); + BALProblem problem(kProblemFile, false); + const int num_camera_parameters = + problem.num_cameras() * problem.camera_block_size(); + + constexpr double kRotationSigma = 1.0; + constexpr double kNoRotationSigma = 0.0; + constexpr double kNoTranslationSigma = 0.0; + constexpr double kNoPointSigma = 0.0; + baseline.Perturb(kNoRotationSigma, kNoTranslationSigma, kNoPointSigma); + problem.Perturb(kRotationSigma, kNoTranslationSigma, kNoPointSigma); + + double maximum_change = 0.0; + for (int i = 0; i < num_camera_parameters; ++i) { + maximum_change = std::max( + maximum_change, std::abs(baseline.cameras()[i] - problem.cameras()[i])); + } + EXPECT_GT(maximum_change, 0.0); +} + +} // namespace +} // namespace ceres::examples