/*-
* #%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.geometricdescriptor;
import fiji.util.KDTree;
import fiji.util.NNearestNeighborSearch;
import java.util.ArrayList;
import mpicbg.pointdescriptor.AbstractPointDescriptor;
import mpicbg.pointdescriptor.SimplePointDescriptor;
import mpicbg.pointdescriptor.exception.NoSuitablePointsException;
import mpicbg.pointdescriptor.matcher.Matcher;
import mpicbg.pointdescriptor.matcher.SubsetMatcher;
import mpicbg.pointdescriptor.similarity.SimilarityMeasure;
import mpicbg.pointdescriptor.similarity.SquareDistance;
import mpicbg.spim.mpicbg.PointMatchGeneric;
import spim.process.interestpointregistration.Detection;
public class RGLDMMatcher
{
public ArrayList< PointMatchGeneric< Detection > > extractCorrespondenceCandidates(
final ArrayList< Detection > nodeListA,
final ArrayList< Detection > nodeListB,
final int numNeighbors,
final int redundancy,
final double ratioOfDistance,
final double differenceThreshold )
{
/* create KDTrees */
final KDTree< Detection > treeA = new KDTree< Detection >( nodeListA );
final KDTree< Detection > treeB = new KDTree< Detection >( nodeListB );
/* extract point descriptors */
final Matcher matcher = new SubsetMatcher( numNeighbors, numNeighbors + redundancy );
final int numRequiredNeighbors = matcher.getRequiredNumNeighbors();
final SimilarityMeasure similarityMeasure = new SquareDistance();
final ArrayList< SimplePointDescriptor<Detection> > descriptorsA = createSimplePointDescriptors( treeA, nodeListA, numRequiredNeighbors, matcher, similarityMeasure );
final ArrayList< SimplePointDescriptor<Detection> > descriptorsB = createSimplePointDescriptors( treeB, nodeListB, numRequiredNeighbors, matcher, similarityMeasure );
return findCorrespondingDescriptors( descriptorsA, descriptorsB, ratioOfDistance, differenceThreshold );
}
protected static final <D extends AbstractPointDescriptor<Detection, D>> ArrayList<PointMatchGeneric< Detection >> findCorrespondingDescriptors(
final ArrayList<D> descriptorsA,
final ArrayList<D> descriptorsB,
final double nTimesBetter,
final double differenceThreshold )
{
final ArrayList<PointMatchGeneric< Detection >> correspondenceCandidates = new ArrayList<PointMatchGeneric< Detection >>();
for ( final D descriptorA : descriptorsA )
{
double bestDifference = Double.MAX_VALUE;
double secondBestDifference = Double.MAX_VALUE;
D bestMatch = null;
D secondBestMatch = null;
for ( final D descriptorB : descriptorsB )
{
final double difference = descriptorA.descriptorDistance( descriptorB );
if ( difference < secondBestDifference )
{
secondBestDifference = difference;
secondBestMatch = descriptorB;
if ( secondBestDifference < bestDifference )
{
double tmpDiff = secondBestDifference;
D tmpMatch = secondBestMatch;
secondBestDifference = bestDifference;
secondBestMatch = bestMatch;
bestDifference = tmpDiff;
bestMatch = tmpMatch;
}
}
}
if ( bestDifference < differenceThreshold && bestDifference * nTimesBetter < secondBestDifference )
{
// add correspondence for the two basis points of the descriptor
Detection detectionA = descriptorA.getBasisPoint();
Detection detectionB = bestMatch.getBasisPoint();
// for RANSAC
correspondenceCandidates.add( new PointMatchGeneric<Detection>( detectionA, detectionB ) );
}
}
return correspondenceCandidates;
}
protected static ArrayList< SimplePointDescriptor<Detection> > createSimplePointDescriptors( final KDTree< Detection > tree, final ArrayList< Detection > basisPoints,
final int numNeighbors, final Matcher matcher, final SimilarityMeasure similarityMeasure )
{
final NNearestNeighborSearch< Detection > nnsearch = new NNearestNeighborSearch< Detection >( tree );
final ArrayList< SimplePointDescriptor<Detection> > descriptors = new ArrayList< SimplePointDescriptor<Detection> > ( );
for ( final Detection p : basisPoints )
{
final ArrayList< Detection > neighbors = new ArrayList< Detection >();
final Detection neighborList[] = nnsearch.findNNearestNeighbors( p, numNeighbors + 1 );
// the first hit is always the point itself
for ( int n = 1; n < neighborList.length; ++n )
neighbors.add( neighborList[ n ] );
try
{
descriptors.add( new SimplePointDescriptor<Detection>( p, neighbors, similarityMeasure, matcher ) );
}
catch ( NoSuitablePointsException e )
{
e.printStackTrace();
}
}
return descriptors;
}
}