001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.feature.local.matcher.consistent; 031 032import java.util.ArrayList; 033import java.util.List; 034 035import org.openimaj.feature.local.LocalFeature; 036import org.openimaj.feature.local.matcher.LocalFeatureMatcher; 037import org.openimaj.math.geometry.point.Point2d; 038import org.openimaj.math.model.Model; 039import org.openimaj.math.model.fit.RobustModelFitting; 040import org.openimaj.util.pair.IndependentPair; 041import org.openimaj.util.pair.Pair; 042 043/** 044 * Object to attempt to find a consistent geometric mapping of two sets of local 045 * features according to a given model. 046 * 047 * The initial matching is performed by a separate matcher that is provided in 048 * the constructor. The list of initial matches is then passed to the 049 * modelfitter which attempts to estimate the model and provide a list of inlier 050 * pairs, which are then used to populate the consistent matches. 051 * 052 * @author Jonathon Hare 053 * @param <T> 054 * The type of LocalFeature 055 * 056 */ 057public class ConsistentLocalFeatureMatcher2d<T extends LocalFeature<?, ?> & Point2d> 058 implements 059 ModelFittingLocalFeatureMatcher<T> 060{ 061 protected LocalFeatureMatcher<T> innerMatcher; 062 protected RobustModelFitting<Point2d, Point2d, ?> modelfit; 063 protected List<Pair<T>> consistentMatches; 064 065 /** 066 * Default constructor 067 * 068 * @param innerMatcher 069 * the internal matcher for getting seed matches 070 */ 071 public ConsistentLocalFeatureMatcher2d(LocalFeatureMatcher<T> innerMatcher) { 072 this.innerMatcher = innerMatcher; 073 074 modelfit = null; 075 consistentMatches = new ArrayList<Pair<T>>(); 076 } 077 078 /** 079 * Default constructor 080 * 081 * @param innerMatcher 082 * the internal matcher for getting seed matches 083 * @param fit 084 * the points against which to test consistency 085 */ 086 public ConsistentLocalFeatureMatcher2d(LocalFeatureMatcher<T> innerMatcher, 087 RobustModelFitting<Point2d, Point2d, ?> fit) 088 { 089 this(innerMatcher); 090 091 modelfit = fit; 092 } 093 094 /** 095 * @return a list of consistent matching keypoints according to the 096 * estimated model parameters. 097 */ 098 @Override 099 public List<Pair<T>> getMatches() { 100 return consistentMatches; 101 } 102 103 /** 104 * @return a list of all matches irrespective of whether they fit the model 105 */ 106 public List<Pair<T>> getAllMatches() { 107 return innerMatcher.getMatches(); 108 } 109 110 @Override 111 public Model<Point2d, Point2d> getModel() { 112 return modelfit.getModel(); 113 } 114 115 @SuppressWarnings("unchecked") 116 @Override 117 public boolean findMatches(List<T> keys1) 118 { 119 // if we're gonna re-use the object, we need to reset everything! 120 consistentMatches = new ArrayList<Pair<T>>(); 121 122 // find the initial matches using the inner matcher 123 innerMatcher.findMatches(keys1); 124 final List<Pair<T>> matches = innerMatcher.getMatches(); 125 126 if (matches.size() < modelfit.numItemsToEstimate()) { 127 consistentMatches.clear(); 128 consistentMatches.addAll(matches); 129 return false; 130 } 131 132 final List<Pair<Point2d>> li_p2d = new ArrayList<Pair<Point2d>>(); 133 for (final Pair<T> m : matches) { 134 li_p2d.add(new Pair<Point2d>(m.firstObject(), m.secondObject())); 135 } 136 137 // fit the model 138 final boolean didfit = modelfit.fitData(li_p2d); 139 140 // get the inliers and build the list of consistent matches 141 for (final IndependentPair<Point2d, Point2d> p : modelfit.getInliers()) { 142 final Object op = p; 143 consistentMatches.add((Pair<T>) op); 144 } 145 146 return didfit; 147 } 148 149 @Override 150 public void setFittingModel(RobustModelFitting<Point2d, Point2d, ?> mf) { 151 modelfit = mf; 152 } 153 154 @Override 155 public void setModelFeatures(List<T> modelkeys) { 156 innerMatcher.setModelFeatures(modelkeys); 157 } 158}