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

boofcv.alg.geo.trifocal.RefineThreeViewProjectiveGeometric Maven / Gradle / Ivy

/*
 * 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.alg.geo.trifocal;

import boofcv.abst.geo.TriangulateNViewsProjective;
import boofcv.abst.geo.bundle.*;
import boofcv.factory.geo.ConfigBundleAdjustment;
import boofcv.factory.geo.ConfigTriangulation;
import boofcv.factory.geo.FactoryMultiView;
import boofcv.misc.ConfigConverge;
import boofcv.struct.geo.AssociatedTriple;
import georegression.struct.point.Point2D_F64;
import georegression.struct.point.Point4D_F64;
import org.ddogleg.optimization.lm.ConfigLevenbergMarquardt;
import org.ejml.data.DMatrixRMaj;
import org.ejml.dense.row.CommonOps_DDRM;

import java.util.ArrayList;
import java.util.List;

/**
 * Improves the estimated camera projection matrices for three views, with the first view assumed to be P1 = [I|0].
 * It's recommended that the observations be normalized to ensure that they are zero mean with a standard deviation
 * of 1, or similar, first.
 *
 * This is known as the Gold Standard algorithm in [1]
 *
 * 
    *
  • R. Hartley, and A. Zisserman, "Multiple View Geometry in Computer Vision", 2nd Ed, Cambridge 2003
  • *
* * @author Peter Abeles */ public class RefineThreeViewProjectiveGeometric { // Computes initial location of points TriangulateNViewsProjective triangulator; // data structures for SBA SceneStructureProjective structure; SceneObservations observations; // first view is assumed to be [I|0] DMatrixRMaj P1 = CommonOps_DDRM.identity(3,4); // convergence criteria for SBA ConfigConverge converge = new ConfigConverge(1e-8,1e-8,200); BundleAdjustment sba; // if true scaling is done before running bundle adjustment. Only set to false if pixel coordinate have // already been scaled boolean scale = true; ScaleSceneStructure scaler = new ScaleSceneStructure(); /** * Creates a constructor using default triangulation and SBA configuration */ public RefineThreeViewProjectiveGeometric() { triangulator = FactoryMultiView.triangulateNView(ConfigTriangulation.GEOMETRIC); ConfigLevenbergMarquardt configLM = new ConfigLevenbergMarquardt(); configLM.hessianScaling = false; // seems to do better without this. Reconsider later on ConfigBundleAdjustment configSBA = new ConfigBundleAdjustment(); configSBA.configOptimizer = configLM; sba = FactoryMultiView.bundleAdjustmentProjective(configSBA); } public RefineThreeViewProjectiveGeometric(TriangulateNViewsProjective triangulator, BundleAdjustment sba) { this.triangulator = triangulator; this.sba = sba; } /** * Refines P2 and P3 using SBA. View 1 is assumed to be P1 = [I|0] * * @param listObs Observations from the three views * @param P2 camera matrix for view 2. modified * @param P3 camera matrix for view 3. modified * @return true if successful */ public boolean refine(List listObs , DMatrixRMaj P2 , DMatrixRMaj P3 ) { CommonOps_DDRM.setIdentity(P1); initializeStructure(listObs, P2, P3); if( scale ) { scaler.applyScale(structure,observations); } // sba.setVerbose(System.out,0); sba.setParameters(structure,observations); sba.configure(converge.ftol,converge.gtol,converge.maxIterations); if( !sba.optimize(structure) ) { return false; } // save the results P2.set(structure.views[1].worldToView); P3.set(structure.views[2].worldToView); if( scale ) { // don't use built in unscaling function because it undoes scaling on points. Those are disposable scaler.pixelScaling.get(1).remove(P2,P2); scaler.pixelScaling.get(2).remove(P3,P3); } return true; } /** * Sets up data structures for SBA */ private void initializeStructure(List listObs, DMatrixRMaj P2, DMatrixRMaj P3) { List cameraMatrices = new ArrayList<>(); cameraMatrices.add(P1); cameraMatrices.add(P2); cameraMatrices.add(P3); List triangObs = new ArrayList<>(); triangObs.add(null); triangObs.add(null); triangObs.add(null); structure = new SceneStructureProjective(true); structure.initialize(3,listObs.size()); observations = new SceneObservations(3); structure.setView(0,true, P1,0,0); structure.setView(1,false,P2,0,0); structure.setView(2,false,P3,0,0); boolean needsPruning = false; Point4D_F64 X = new Point4D_F64(); for (int i = 0; i < listObs.size(); i++) { AssociatedTriple t = listObs.get(i); triangObs.set(0,t.p1); triangObs.set(1,t.p2); triangObs.set(2,t.p3); // triangulation can fail if all 3 views have the same pixel value. This has been observed in // simulated 3D scenes if( triangulator.triangulate(triangObs,cameraMatrices,X)) { observations.getView(0).add(i,(float)t.p1.x,(float)t.p1.y); observations.getView(1).add(i,(float)t.p2.x,(float)t.p2.y); observations.getView(2).add(i,(float)t.p3.x,(float)t.p3.y); structure.points[i].set(X.x,X.y,X.z,X.w); } else { needsPruning = true; } } if( needsPruning ) { PruneStructureFromSceneProjective pruner = new PruneStructureFromSceneProjective(structure,observations); pruner.prunePoints(1); } } public TriangulateNViewsProjective getTriangulator() { return triangulator; } public SceneStructureProjective getStructure() { return structure; } public SceneObservations getObservations() { return observations; } public BundleAdjustment getSba() { return sba; } public boolean isScale() { return scale; } public void setScale(boolean scale) { this.scale = scale; } public ConfigConverge getConverge() { return converge; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy