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}