Search in sources :

Example 1 with EstimatePlaneAtInfinityGivenK

use of boofcv.alg.geo.selfcalib.EstimatePlaneAtInfinityGivenK in project BoofCV by lessthanoptimal.

the class ExampleStereoUncalibrated method main.

public static void main(String[] args) {
    // Solution below is unstable. Turning concurrency off so that it always produces a valid solution
    // The two view case is very challenging and I've not seen a stable algorithm yet
    BoofConcurrency.USE_CONCURRENT = false;
    // Successful
    String name = "bobcats_";
    // String name = "mono_wall_";
    // String name = "minecraft_cave1_";
    // String name = "chicken_";
    // String name = "books_";
    // Successful Failures
    // String name = "triflowers_";
    // Failures
    // String name = "rock_leaves_";
    // String name = "minecraft_distant_";
    // String name = "rockview_";
    // String name = "pebbles_";
    // String name = "skull_";
    // String name = "turkey_";
    BufferedImage buff01 = UtilImageIO.loadImageNotNull(UtilIO.pathExample("triple/" + name + "01.jpg"));
    BufferedImage buff02 = UtilImageIO.loadImageNotNull(UtilIO.pathExample("triple/" + name + "02.jpg"));
    Planar<GrayU8> color01 = ConvertBufferedImage.convertFrom(buff01, true, ImageType.pl(3, GrayU8.class));
    Planar<GrayU8> color02 = ConvertBufferedImage.convertFrom(buff02, true, ImageType.pl(3, GrayU8.class));
    GrayU8 image01 = ConvertImage.average(color01, null);
    GrayU8 image02 = ConvertImage.average(color02, null);
    // Find a set of point feature matches
    List<AssociatedPair> matches = ExampleComputeFundamentalMatrix.computeMatches(buff01, buff02);
    // Prune matches using the epipolar constraint. use a low threshold to prune more false matches
    var inliers = new ArrayList<AssociatedPair>();
    DMatrixRMaj F = ExampleComputeFundamentalMatrix.robustFundamental(matches, inliers, 0.1);
    // Perform self calibration using the projective view extracted from F
    // Note that P1 = [I|0]
    System.out.println("Self calibration");
    DMatrixRMaj P2 = MultiViewOps.fundamentalToProjective(F);
    // Take a crude guess at the intrinsic parameters. Bundle adjustment will fix this later.
    int width = buff01.getWidth(), height = buff02.getHeight();
    double fx = width / 2;
    double fy = fx;
    double cx = width / 2;
    double cy = height / 2;
    // Compute a transform from projective to metric by assuming we know the camera's calibration
    var estimateV = new EstimatePlaneAtInfinityGivenK();
    estimateV.setCamera1(fx, fy, 0, cx, cy);
    estimateV.setCamera2(fx, fy, 0, cx, cy);
    // plane at infinity
    var v = new Vector3D_F64();
    if (!estimateV.estimatePlaneAtInfinity(P2, v))
        throw new RuntimeException("Failed!");
    DMatrixRMaj K = PerspectiveOps.pinholeToMatrix(fx, fy, 0, cx, cy);
    DMatrixRMaj H = MultiViewOps.createProjectiveToMetric(K, v.x, v.y, v.z, 1, null);
    var P2m = new DMatrixRMaj(3, 4);
    CommonOps_DDRM.mult(P2, H, P2m);
    // Decompose and get the initial estimate for translation
    var tmp = new DMatrixRMaj(3, 3);
    var view1_to_view2 = new Se3_F64();
    MultiViewOps.decomposeMetricCamera(P2m, tmp, view1_to_view2);
    // ------------------------- Setting up bundle adjustment
    // bundle adjustment will provide a more refined and accurate estimate of these parameters
    System.out.println("Configuring bundle adjustment");
    // Construct bundle adjustment data structure
    var structure = new SceneStructureMetric(false);
    var observations = new SceneObservations();
    // We will assume that the camera has fixed intrinsic parameters
    structure.initialize(1, 2, inliers.size());
    observations.initialize(2);
    var bp = new BundlePinholeSimplified();
    bp.f = fx;
    structure.setCamera(0, false, bp);
    // The first view is the world coordinate system
    structure.setView(0, 0, true, new Se3_F64());
    // Second view was estimated previously
    structure.setView(1, 0, false, view1_to_view2);
    for (int i = 0; i < inliers.size(); i++) {
        AssociatedPair t = inliers.get(i);
        // substract out the camera center from points. This allows a simple camera model to be used and
        // errors in the this coordinate tend to be non-fatal
        observations.getView(0).add(i, (float) (t.p1.x - cx), (float) (t.p1.y - cy));
        observations.getView(1).add(i, (float) (t.p2.x - cx), (float) (t.p2.y - cy));
        // each point is visible in both of the views
        structure.connectPointToView(i, 0);
        structure.connectPointToView(i, 1);
    }
    // initial location of points is found through triangulation
    MultiViewOps.triangulatePoints(structure, observations);
    // ------------------ Running Bundle Adjustment
    System.out.println("Performing bundle adjustment");
    var configLM = new ConfigLevenbergMarquardt();
    configLM.dampeningInitial = 1e-3;
    configLM.hessianScaling = false;
    var configSBA = new ConfigBundleAdjustment();
    configSBA.configOptimizer = configLM;
    // Create and configure the bundle adjustment solver
    BundleAdjustment<SceneStructureMetric> bundleAdjustment = FactoryMultiView.bundleSparseMetric(configSBA);
    // prints out useful debugging information that lets you know how well it's converging
    bundleAdjustment.setVerbose(System.out, null);
    // Specifies convergence criteria
    bundleAdjustment.configure(1e-6, 1e-6, 100);
    // Scaling improve accuracy of numerical calculations
    var bundleScale = new ScaleSceneStructure();
    bundleScale.applyScale(structure, observations);
    bundleAdjustment.setParameters(structure, observations);
    bundleAdjustment.optimize(structure);
    // Sometimes pruning outliers help improve the solution. In the stereo case the errors are likely
    // to already fatal
    var pruner = new PruneStructureFromSceneMetric(structure, observations);
    pruner.pruneObservationsByErrorRank(0.85);
    pruner.prunePoints(1);
    bundleAdjustment.setParameters(structure, observations);
    bundleAdjustment.optimize(structure);
    bundleScale.undoScale(structure, observations);
    System.out.println("\nCamera");
    for (int i = 0; i < structure.cameras.size; i++) {
        System.out.println(structure.cameras.data[i].getModel().toString());
    }
    System.out.println("\n\nworldToView");
    for (int i = 0; i < structure.views.size; i++) {
        System.out.println(structure.getParentToView(i).toString());
    }
    // display the inlier matches found using the robust estimator
    System.out.println("\n\nComputing Stereo Disparity");
    BundlePinholeSimplified cp = structure.getCameras().get(0).getModel();
    var intrinsic = new CameraPinholeBrown();
    intrinsic.fsetK(cp.f, cp.f, 0, cx, cy, width, height);
    intrinsic.fsetRadial(cp.k1, cp.k2);
    Se3_F64 leftToRight = structure.getParentToView(1);
    computeStereoCloud(image01, image02, color01, color02, intrinsic, intrinsic, leftToRight, 0, 250);
}
Also used : AssociatedPair(boofcv.struct.geo.AssociatedPair) EstimatePlaneAtInfinityGivenK(boofcv.alg.geo.selfcalib.EstimatePlaneAtInfinityGivenK) CameraPinholeBrown(boofcv.struct.calib.CameraPinholeBrown) BundlePinholeSimplified(boofcv.alg.geo.bundle.cameras.BundlePinholeSimplified) ArrayList(java.util.ArrayList) DMatrixRMaj(org.ejml.data.DMatrixRMaj) BufferedImage(java.awt.image.BufferedImage) ConvertBufferedImage(boofcv.io.image.ConvertBufferedImage) ConfigBundleAdjustment(boofcv.factory.geo.ConfigBundleAdjustment) Vector3D_F64(georegression.struct.point.Vector3D_F64) ConfigLevenbergMarquardt(org.ddogleg.optimization.lm.ConfigLevenbergMarquardt) GrayU8(boofcv.struct.image.GrayU8) Se3_F64(georegression.struct.se.Se3_F64)

Aggregations

BundlePinholeSimplified (boofcv.alg.geo.bundle.cameras.BundlePinholeSimplified)1 EstimatePlaneAtInfinityGivenK (boofcv.alg.geo.selfcalib.EstimatePlaneAtInfinityGivenK)1 ConfigBundleAdjustment (boofcv.factory.geo.ConfigBundleAdjustment)1 ConvertBufferedImage (boofcv.io.image.ConvertBufferedImage)1 CameraPinholeBrown (boofcv.struct.calib.CameraPinholeBrown)1 AssociatedPair (boofcv.struct.geo.AssociatedPair)1 GrayU8 (boofcv.struct.image.GrayU8)1 Vector3D_F64 (georegression.struct.point.Vector3D_F64)1 Se3_F64 (georegression.struct.se.Se3_F64)1 BufferedImage (java.awt.image.BufferedImage)1 ArrayList (java.util.ArrayList)1 ConfigLevenbergMarquardt (org.ddogleg.optimization.lm.ConfigLevenbergMarquardt)1 DMatrixRMaj (org.ejml.data.DMatrixRMaj)1