/*- * #%L * Fiji distribution of ImageJ for the life sciences. * %% * Copyright (C) 2007 - 2017 Fiji developers. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-2.0.html>. * #L% */ package spim.process.interestpointregistration; import java.text.NumberFormat; import java.util.ArrayList; import spim.fiji.ImgLib2Temp.Pair; import spim.fiji.ImgLib2Temp.ValuePair; import mpicbg.models.Model; import mpicbg.models.NotEnoughDataPointsException; import mpicbg.models.PointMatch; import mpicbg.pointdescriptor.LinkedPoint; import mpicbg.spim.mpicbg.PointMatchGeneric; /** * * @author Stephan Preibisch (stephan.preibisch@gmx.de) * */ public class RANSAC { public static Pair< String, Double > computeRANSAC( final ArrayList< PointMatchGeneric < Detection > > correspondenceCandidates, final ArrayList< PointMatchGeneric < Detection > > inlierList, final Model<?> model, final double maxEpsilon, final double minInlierRatio, final double minNumberInlierFactor, final int numIterations ) { final int numCorrespondences = correspondenceCandidates.size(); final int minNumCorrespondences = Math.max( model.getMinNumMatches(), (int)Math.round( model.getMinNumMatches() * minNumberInlierFactor ) ); /* * First remove the inconsistent correspondences */ // I do not think anymore that this is required // removeInconsistentCorrespondences( correspondenceCandidates ); // if there are not enough correspondences for the used model if ( numCorrespondences < minNumCorrespondences ) return new ValuePair< String, Double >( "Not enough correspondences found " + numCorrespondences + ", should be at least " + minNumCorrespondences, Double.NaN ); /** * The ArrayList that stores the inliers after RANSAC, contains PointMatches of LinkedPoints * so that MultiThreading is possible */ //final ArrayList< PointMatchGeneric<LinkedPoint<T>> > candidates = new ArrayList<PointMatchGeneric<LinkedPoint<T>>>(); final ArrayList< PointMatch > candidates = new ArrayList< PointMatch >(); final ArrayList< PointMatch > inliers = new ArrayList< PointMatch >(); // clone the beads for the RANSAC as we are working multithreaded and they will be modified for ( final PointMatchGeneric< Detection > correspondence : correspondenceCandidates ) { final Detection detectionA = correspondence.getPoint1(); final Detection detectionB = correspondence.getPoint2(); final LinkedPoint< Detection > pA = new LinkedPoint< Detection >( detectionA.getL(), detectionA.getW(), detectionA ); final LinkedPoint< Detection > pB = new LinkedPoint< Detection >( detectionB.getL(), detectionB.getW(), detectionB ); final double weight = correspondence.getWeight(); candidates.add( new PointMatchGeneric< LinkedPoint< Detection > >( pA, pB, weight ) ); } boolean modelFound = false; try { /*modelFound = m.ransac( candidates, inliers, numIterations, maxEpsilon, minInlierRatio );*/ modelFound = model.filterRansac( candidates, inliers, numIterations, maxEpsilon, minInlierRatio ); } catch ( NotEnoughDataPointsException e ) { return new ValuePair< String, Double >( e.toString(), Double.NaN ); } final NumberFormat nf = NumberFormat.getPercentInstance(); final double ratio = ( (double)inliers.size() / (double)candidates.size() ); if ( modelFound && inliers.size() >= minNumCorrespondences ) { for ( final PointMatch pointMatch : inliers ) { @SuppressWarnings("unchecked") final PointMatchGeneric<LinkedPoint< Detection > > pm = (PointMatchGeneric< LinkedPoint< Detection > >) pointMatch; final Detection detectionA = pm.getPoint1().getLinkedObject(); final Detection detectionB = pm.getPoint2().getLinkedObject(); inlierList.add( new PointMatchGeneric< Detection >( detectionA, detectionB ) ); } return new ValuePair< String, Double >( "Remaining inliers after RANSAC: " + inliers.size() + " of " + candidates.size() + " (" + nf.format(ratio) + ") with average error " + model.getCost(), model.getCost() ); } else { if ( modelFound ) return new ValuePair< String, Double >( "Model found but not enough remaining inliers (" + inliers.size() + "/" + minNumCorrespondences + ") after RANSAC of " + candidates.size(), Double.NaN ); else return new ValuePair< String, Double >( "NO Model found after RANSAC of " + candidates.size(), Double.NaN ); } } }