All Downloads are FREE. Search and download functionalities are using the official Maven repository.

boofcv.factory.geo.FactoryMultiViewRobust Maven / Gradle / Ivy

Go to download

BoofCV is an open source Java library for real-time computer vision and robotics applications.

There is a newer version: 1.1.7
Show newest version
/*
 * Copyright (c) 2011-2018, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package boofcv.factory.geo;

import boofcv.abst.geo.Estimate1ofEpipolar;
import boofcv.abst.geo.Estimate1ofPnP;
import boofcv.abst.geo.Estimate1ofTrifocalTensor;
import boofcv.abst.geo.Triangulate2ViewsMetric;
import boofcv.abst.geo.fitting.DistanceFromModelResidual;
import boofcv.abst.geo.fitting.GenerateEpipolarMatrix;
import boofcv.abst.geo.fitting.ModelManagerEpipolarMatrix;
import boofcv.alg.geo.DistanceFromModelMultiView;
import boofcv.alg.geo.f.FundamentalResidualSampson;
import boofcv.alg.geo.pose.PnPDistanceReprojectionSq;
import boofcv.alg.geo.robust.*;
import boofcv.struct.geo.AssociatedPair;
import boofcv.struct.geo.AssociatedTriple;
import boofcv.struct.geo.Point2D3D;
import boofcv.struct.geo.TrifocalTensor;
import georegression.fitting.homography.ModelManagerHomography2D_F64;
import georegression.fitting.se.ModelManagerSe3_F64;
import georegression.struct.homography.Homography2D_F64;
import georegression.struct.se.Se3_F64;
import org.ddogleg.fitting.modelset.DistanceFromModel;
import org.ddogleg.fitting.modelset.ModelGenerator;
import org.ddogleg.fitting.modelset.ModelManager;
import org.ddogleg.fitting.modelset.ModelMatcher;
import org.ddogleg.fitting.modelset.lmeds.LeastMedianOfSquares;
import org.ddogleg.fitting.modelset.ransac.Ransac;
import org.ejml.data.DMatrixRMaj;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
 * Factory for creating robust false-positive tolerant estimation algorithms in multi-view geometry.  These
 * algorithms tend to have a lot of boilerplate associated with them and the goal of this factory
 * is to make their use much easier and less error prone.
 *
 * @author Peter Abeles
 */
public class FactoryMultiViewRobust {

	/**
	 * Robust solution to PnP problem using {@link LeastMedianOfSquares LMedS}.  Input observations are
	 * in normalized image coordinates.
	 *
	 * 
    *
  • Input observations are in normalized image coordinates NOT pixels
  • *
  • Error units are pixels squared.
  • *
* *

See code for all the details.

* * @param configPnP PnP parameters. Can't be null. * @param configLMedS Parameters for LMedS. Can't be null. * @return Robust Se3_F64 estimator */ public static ModelMatcherMultiview pnpLMedS(@Nullable ConfigPnP configPnP, @Nonnull ConfigLMedS configLMedS) { if( configPnP == null ) configPnP = new ConfigPnP(); configPnP.checkValidity(); configLMedS.checkValidity(); Estimate1ofPnP estimatorPnP = FactoryMultiView.pnp_1( configPnP.which , configPnP.epnpIterations, configPnP.numResolve); DistanceFromModelMultiView distance = new PnPDistanceReprojectionSq(); ModelManagerSe3_F64 manager = new ModelManagerSe3_F64(); EstimatorToGenerator generator = new EstimatorToGenerator<>(estimatorPnP); LeastMedianOfSquaresMultiView lmeds = new LeastMedianOfSquaresMultiView<>(configLMedS.randSeed, configLMedS.totalCycles, manager, generator, distance); lmeds.setErrorFraction(configLMedS.errorFraction); return lmeds; } /** * Robust solution to PnP problem using {@link Ransac}. Input observations are in normalized * image coordinates. Found transform is from world to camera. * *

NOTE: Observations are in normalized image coordinates NOT pixels.

* *

See code for all the details.

* * @see Estimate1ofPnP * * @param pnp PnP parameters. Can't be null. * @param ransac Parameters for RANSAC. Can't be null. * @return Robust Se3_F64 estimator */ public static ModelMatcherMultiview pnpRansac( @Nullable ConfigPnP pnp, @Nonnull ConfigRansac ransac ) { if( pnp == null ) pnp = new ConfigPnP(); pnp.checkValidity(); ransac.checkValidity(); Estimate1ofPnP estimatorPnP = FactoryMultiView.pnp_1(pnp.which, pnp.epnpIterations, pnp.numResolve); DistanceFromModelMultiView distance = new PnPDistanceReprojectionSq(); ModelManagerSe3_F64 manager = new ModelManagerSe3_F64(); EstimatorToGenerator generator = new EstimatorToGenerator<>(estimatorPnP); // convert from pixels to pixels squared double threshold = ransac.inlierThreshold*ransac.inlierThreshold; return new RansacMultiView<>(ransac.randSeed, manager, generator, distance, ransac.maxIterations, threshold); } /** * Robust solution for estimating {@link Se3_F64} using epipolar geometry from two views with * {@link LeastMedianOfSquares LMedS}. Input observations are in normalized image coordinates. * *
    *
  • Error units is pixels squared times two
  • *
* *

See code for all the details.

* * @param essential Essential matrix estimation parameters. Can't be null. * @param lmeds Parameters for RANSAC. Can't be null. * @return Robust Se3_F64 estimator */ public static ModelMatcherMultiview baselineLMedS( @Nullable ConfigEssential essential, @Nonnull ConfigLMedS lmeds ) { if( essential == null ) essential = new ConfigEssential(); else essential.checkValidity(); Estimate1ofEpipolar epipolar = FactoryMultiView. essential_1(essential.which, essential.numResolve); Triangulate2ViewsMetric triangulate = FactoryMultiView.triangulate2ViewMetric( new ConfigTriangulation(ConfigTriangulation.Type.GEOMETRIC)); ModelManager manager = new ModelManagerSe3_F64(); ModelGenerator generateEpipolarMotion = new Se3FromEssentialGenerator(epipolar, triangulate); DistanceFromModelMultiView distanceSe3 = new DistanceSe3SymmetricSq(triangulate); LeastMedianOfSquaresMultiView config = new LeastMedianOfSquaresMultiView<> (lmeds.randSeed, lmeds.totalCycles, manager, generateEpipolarMotion, distanceSe3); config.setErrorFraction(lmeds.errorFraction); return config; } public static ModelMatcher fundamentalLMedS(@Nonnull ConfigFundamental fundamental, @Nonnull ConfigLMedS lmeds ) { fundamental.checkValidity(); lmeds.checkValidity(); ModelManager managerF = new ModelManagerEpipolarMatrix(); Estimate1ofEpipolar estimateF = FactoryMultiView.fundamental_1(fundamental.which, fundamental.numResolve); GenerateEpipolarMatrix generateF = new GenerateEpipolarMatrix(estimateF); // How the error is measured DistanceFromModel errorMetric; switch( fundamental.errorModel ) { case SAMPSON: errorMetric = new DistanceFromModelResidual<>(new FundamentalResidualSampson()); break; case GEOMETRIC: errorMetric = new DistanceFundamentalGeometric(); break; default: throw new RuntimeException("Unknown"); } LeastMedianOfSquares config = new LeastMedianOfSquares<> (lmeds.randSeed, lmeds.totalCycles, managerF, generateF, errorMetric); config.setErrorFraction(lmeds.errorFraction); return config; } /** * Robust solution for estimating the stereo baseline {@link Se3_F64} using epipolar geometry from two views with * {@link RansacMultiView}. Input observations are in normalized image coordinates. * *

See code for all the details.

* * @param essential Essential matrix estimation parameters. * @param ransac Parameters for RANSAC. Can't be null. * @return Robust Se3_F64 estimator */ public static ModelMatcherMultiview baselineRansac(@Nullable ConfigEssential essential, @Nonnull ConfigRansac ransac ) { if( essential == null ) essential = new ConfigEssential(); else essential.checkValidity(); ransac.checkValidity(); if( essential.errorModel != ConfigEssential.ErrorModel.GEOMETRIC) { throw new RuntimeException("Error model has to be Euclidean"); } Estimate1ofEpipolar epipolar = FactoryMultiView. essential_1(essential.which, essential.numResolve); Triangulate2ViewsMetric triangulate = FactoryMultiView.triangulate2ViewMetric( new ConfigTriangulation(ConfigTriangulation.Type.GEOMETRIC)); ModelManager manager = new ModelManagerSe3_F64(); ModelGenerator generateEpipolarMotion = new Se3FromEssentialGenerator(epipolar, triangulate); DistanceFromModelMultiView distanceSe3 = new DistanceSe3SymmetricSq(triangulate); double ransacTOL = ransac.inlierThreshold * ransac.inlierThreshold * 2.0; return new RansacMultiView<>(ransac.randSeed, manager, generateEpipolarMotion, distanceSe3, ransac.maxIterations, ransacTOL); } public static ModelMatcherMultiview essentialRansac(@Nullable ConfigEssential essential, @Nonnull ConfigRansac ransac ) { if( essential == null ) essential = new ConfigEssential(); else essential.checkValidity(); ransac.checkValidity(); if( essential.errorModel == ConfigEssential.ErrorModel.GEOMETRIC) { // The best error has been selected. Compute using the baseline algorithm then convert back into // essential matrix return new MmmvSe3ToEssential(baselineRansac(essential,ransac)); } ModelManager managerE = new ModelManagerEpipolarMatrix(); Estimate1ofEpipolar estimateF = FactoryMultiView.essential_1(essential.which, essential.numResolve); GenerateEpipolarMatrix generateE = new GenerateEpipolarMatrix(estimateF); // How the error is measured DistanceFromModelMultiView errorMetric = new DistanceMultiView_EssentialSampson(); double ransacTOL = ransac.inlierThreshold * ransac.inlierThreshold; return new RansacMultiView<>(ransac.randSeed, managerE, generateE, errorMetric, ransac.maxIterations, ransacTOL); } public static ModelMatcher fundamentalRansac(@Nonnull ConfigFundamental fundamental, @Nonnull ConfigRansac ransac ) { fundamental.checkValidity(); ransac.checkValidity(); ModelManager managerF = new ModelManagerEpipolarMatrix(); Estimate1ofEpipolar estimateF = FactoryMultiView.fundamental_1(fundamental.which, fundamental.numResolve); GenerateEpipolarMatrix generateF = new GenerateEpipolarMatrix(estimateF); // How the error is measured DistanceFromModel errorMetric; switch( fundamental.errorModel ) { case SAMPSON: errorMetric = new DistanceFromModelResidual<>(new FundamentalResidualSampson()); break; case GEOMETRIC: errorMetric = new DistanceFundamentalGeometric(); break; default: throw new RuntimeException("Unknown"); } double ransacTOL = ransac.inlierThreshold * ransac.inlierThreshold; return new Ransac<>(ransac.randSeed, managerF, generateF, errorMetric, ransac.maxIterations, ransacTOL); } /** * Robust solution for estimating {@link Homography2D_F64} with {@link LeastMedianOfSquares LMedS}. Input * observations are in pixel coordinates. * *
    *
  • Four point linear is used internally

    *
  • inlierThreshold is in pixels

    *
* *

See code for all the details.

* * @param homography Homography estimation parameters. If null default is used. * @param configLMedS Parameters for LMedS. Can't be null. * @return Homography estimator */ public static LeastMedianOfSquares homographyLMedS(@Nullable ConfigHomography homography , @Nonnull ConfigLMedS configLMedS ) { if( homography == null ) homography = new ConfigHomography(); ModelManager manager = new ModelManagerHomography2D_F64(); GenerateHomographyLinear modelFitter = new GenerateHomographyLinear(homography.normalize); DistanceHomographySq distance = new DistanceHomographySq(); LeastMedianOfSquares lmeds= new LeastMedianOfSquares<> (configLMedS.randSeed, configLMedS.totalCycles, manager, modelFitter, distance); lmeds.setErrorFraction(configLMedS.errorFraction); return lmeds; } /** * Robust solution for estimating {@link Homography2D_F64} with {@link Ransac}. Input * observations are in pixel coordinates. * *
    *
  • Four point linear is used internally

    *
  • inlierThreshold is in pixels

    *
* *

See code for all the details.

* * @param homography Homography estimation parameters. If null default is used. * @param ransac Parameters for RANSAC. Can't be null. * @return Homography estimator */ public static Ransac homographyRansac( @Nullable ConfigHomography homography , @Nonnull ConfigRansac ransac ) { if( homography == null ) homography = new ConfigHomography(); ModelManager manager = new ModelManagerHomography2D_F64(); GenerateHomographyLinear modelFitter = new GenerateHomographyLinear(homography.normalize); DistanceHomographySq distance = new DistanceHomographySq(); double ransacTol = ransac.inlierThreshold*ransac.inlierThreshold; return new Ransac<>(ransac.randSeed, manager, modelFitter, distance, ransac.maxIterations, ransacTol); } /** * Estimates a homography from normalized image coordinates but computes the error in pixel coordinates * * @see GenerateHomographyLinear * @see DistanceHomographyCalibratedSq * * @param ransac RANSAC configuration * @return Ransac */ public static RansacMultiView homographyCalibratedRansac( @Nonnull ConfigRansac ransac ) { ModelManager manager = new ModelManagerHomography2D_F64(); GenerateHomographyLinear modelFitter = new GenerateHomographyLinear(false); DistanceHomographyCalibratedSq distance = new DistanceHomographyCalibratedSq(); double ransacTol = ransac.inlierThreshold*ransac.inlierThreshold; return new RansacMultiView<> (ransac.randSeed, manager, modelFitter, distance, ransac.maxIterations, ransacTol); } /** * Robust RANSAC based estimator for * * @see FactoryMultiView#trifocal_1 * * @param trifocal Configuration for trifocal tensor calculation * @param error Configuration for how trifocal error is computed * @param ransac Configuration for RANSAC * @return RANSAC */ public static Ransac trifocalRansac( @Nullable ConfigTrifocal trifocal , @Nullable ConfigTrifocalError error, @Nonnull ConfigRansac ransac ) { if( trifocal == null ) trifocal = new ConfigTrifocal(); if( error == null ) error = new ConfigTrifocalError(); trifocal.checkValidity(); double ransacTol; DistanceFromModel distance; switch( error.model) { case REPROJECTION: { ransacTol = 3.0*ransac.inlierThreshold*ransac.inlierThreshold; distance = new DistanceTrifocalReprojectionSq(); } break; case REPROJECTION_REFINE: ransacTol = 3.0*ransac.inlierThreshold*ransac.inlierThreshold; distance = new DistanceTrifocalReprojectionSq(error.converge.gtol,error.converge.maxIterations); break; case POINT_TRANSFER: ransacTol = 2.0*ransac.inlierThreshold*ransac.inlierThreshold; distance = new DistanceTrifocalTransferSq(); break; default: throw new IllegalArgumentException("Unknown error model "+error.model); } Estimate1ofTrifocalTensor estimator = FactoryMultiView.trifocal_1(trifocal); ModelManager manager = new ManagerTrifocalTensor(); ModelGenerator generator = new GenerateTrifocalTensor(estimator); return new Ransac<>(ransac.randSeed, manager, generator, distance, ransac.maxIterations, ransacTol); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy