diff --git a/change.txt b/change.txt index 50921b6700..2679f77d4c 100644 --- a/change.txt +++ b/change.txt @@ -6,6 +6,12 @@ Version Meaning: .. - Second digit indicates if a new feature was added and/or if only a minor refactoring has been done - Last digit always indicates a bug fix and other minor changes +--------------------------------------------- +Date : 2024/Feb/ +Version : 1.1.3 + +- CalibrateStereoPlanar provides valid results once again + --------------------------------------------- Date : 2023/Nov/05 Version : 1.1.2 diff --git a/main/boofcv-geo/src/main/java/boofcv/abst/geo/calibration/CalibrateStereoPlanar.java b/main/boofcv-geo/src/main/java/boofcv/abst/geo/calibration/CalibrateStereoPlanar.java index abb0ec175a..c5098cc3c5 100644 --- a/main/boofcv-geo/src/main/java/boofcv/abst/geo/calibration/CalibrateStereoPlanar.java +++ b/main/boofcv-geo/src/main/java/boofcv/abst/geo/calibration/CalibrateStereoPlanar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Peter Abeles. All Rights Reserved. + * Copyright (c) 2024, Peter Abeles. All Rights Reserved. * * This file is part of BoofCV (http://boofcv.org). * @@ -83,7 +83,7 @@ public class CalibrateStereoPlanar implements VerbosePrint { List> layouts; - MetricBundleAdjustmentUtils bundleUtils = new MetricBundleAdjustmentUtils(); + MetricBundleAdjustmentUtils bundleUtils = new MetricBundleAdjustmentUtils(null, false); @Nullable PrintStream verbose; @@ -287,8 +287,10 @@ private void refineAll( StereoParameters parameters ) { } if (verbose != null) verbose.println("Joint bundle adjustment"); - if (!bundleUtils.process()) + if (!bundleUtils.process()) { + if (verbose != null) verbose.println("Bundle adjustment failed"); return; + } // save the output structure.motions.get(left_to_right_idx).parent_to_view.invert(parameters.right_to_left); @@ -322,6 +324,15 @@ public static String computeQualityText( List namesLeft, List errors, CalibrationQuality qualityLeft, CalibrationQuality qualityRight ) { + // Determine the longest name to make formatting nice + int nameLength = 0; + for (int imageIdx = 0, i = 0; imageIdx < namesLeft.size(); imageIdx++) { + if (used != null && !used.get(imageIdx)) + continue; + nameLength = Math.max(nameLength, namesLeft.get(imageIdx).length()); + } + nameLength += 1; + double averageError = 0.0; double maxError = 0.0; for (int i = 0; i < errors.size(); i++) { @@ -340,16 +351,19 @@ public static String computeQualityText( List namesLeft, 100*qualityRight.geometric); text += "\n"; text += String.format("Reprojection Errors (px):\nmean=%.3f max=%.3f\n\n", averageError, maxError); - text += String.format("%-10s | %8s\n", "image", "max (px)"); + text += String.format("%-"+nameLength+"s | %8s\n", "image", "max (px)"); + + String format = "%-"+nameLength+"s %8.3f\n"; + for (int imageIdx = 0, i = 0; imageIdx < namesLeft.size(); imageIdx++) { if (used != null && !used.get(imageIdx)) continue; String imageName = namesLeft.get(imageIdx); ImageResults r = errors.get(i); - text += String.format("%-12s %8.3f\n", imageName, r.maxError); + text += String.format(format, imageName, r.maxError); // print right image now r = errors.get(i + 1); - text += String.format("%-12s %8.3f\n", "", r.maxError); + text += String.format(format, "", r.maxError); i += 2; } @@ -361,12 +375,12 @@ public List computeErrors() { final SceneObservations observations = bundleUtils.getObservations(); List errors = new ArrayList<>(); - double[] parameters = new double[structure.getParameterCount()]; - double[] residuals = new double[observations.getObservationCount()*2]; - CodecSceneStructureMetric codec = new CodecSceneStructureMetric(); + var parameters = new double[structure.getParameterCount()]; + var residuals = new double[observations.getObservationCount()*2]; + var codec = new CodecSceneStructureMetric(); codec.encode(structure, parameters); - BundleAdjustmentMetricResidualFunction function = new BundleAdjustmentMetricResidualFunction(); + var function = new BundleAdjustmentMetricResidualFunction(); function.configure(structure, observations); function.process(parameters, residuals); diff --git a/main/boofcv-geo/src/test/java/boofcv/abst/geo/calibration/TestCalibrateStereoPlanar.java b/main/boofcv-geo/src/test/java/boofcv/abst/geo/calibration/TestCalibrateStereoPlanar.java index 7bcc7baaf5..f3dfe1123c 100644 --- a/main/boofcv-geo/src/test/java/boofcv/abst/geo/calibration/TestCalibrateStereoPlanar.java +++ b/main/boofcv-geo/src/test/java/boofcv/abst/geo/calibration/TestCalibrateStereoPlanar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Peter Abeles. All Rights Reserved. + * Copyright (c) 2024, Peter Abeles. All Rights Reserved. * * This file is part of BoofCV (http://boofcv.org). * @@ -30,14 +30,14 @@ import georegression.struct.se.Se3_F64; import georegression.struct.se.SpecialEuclideanOps_F64; import georegression.transform.se.SePointOps_F64; +import org.ejml.UtilEjml; import org.ejml.dense.row.MatrixFeatures_DDRM; import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; public class TestCalibrateStereoPlanar extends BoofStandardJUnit { CameraPinholeBrown intrinsic = new CameraPinholeBrown(250, 260, 0, 320, 240, 640, 480). @@ -89,6 +89,16 @@ public TestCalibrateStereoPlanar() { assertEquals(0, expected.getT().distance(rightToLeft.T), Math.abs(rightToLeft.T.x)*0.01); assertTrue(MatrixFeatures_DDRM.isIdentity(rightToLeft.getR(), 2e-3)); + + // See if it blew up + List errors = alg.computeErrors(); + for (var e : errors) { + assertTrue(e.maxError < 1e-3); + assertFalse(UtilEjml.isUncountable(e.maxError)); + assertFalse(UtilEjml.isUncountable(e.meanError)); + assertFalse(UtilEjml.isUncountable(e.biasX)); + assertFalse(UtilEjml.isUncountable(e.biasY)); + } } /**