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.workinprogress;
031
032import java.io.File;
033
034import org.openimaj.feature.local.list.LocalFeatureList;
035import org.openimaj.feature.local.list.MemoryLocalFeatureList;
036import org.openimaj.feature.local.matcher.FastBasicKeypointMatcher;
037import org.openimaj.feature.local.matcher.consistent.ConsistentLocalFeatureMatcher2d;
038import org.openimaj.image.DisplayUtilities;
039import org.openimaj.image.FImage;
040import org.openimaj.image.feature.local.engine.DoGSIFTEngine;
041import org.openimaj.image.feature.local.keypoints.Keypoint;
042import org.openimaj.image.processing.resize.ResizeProcessor;
043import org.openimaj.math.geometry.point.Point2d;
044import org.openimaj.math.geometry.point.Point2dImpl;
045import org.openimaj.math.geometry.transforms.estimation.RobustAffineTransformEstimator;
046import org.openimaj.video.capture.VideoCapture;
047
048public class Snap {
049        MemoryLocalFeatureList<Keypoint> mapData = new MemoryLocalFeatureList<Keypoint>();
050        File[] mapKeypointFiles = {
051                        new File("/Users/jon/Consulting/MapSnapper/map_data/MAP_DATA_2K/NY42.key"),
052                        new File("/Users/jon/Consulting/MapSnapper/map_data/MAP_DATA_2K/NY44.key"),
053                        new File("/Users/jon/Consulting/MapSnapper/map_data/MAP_DATA_2K/NY46.key")
054        };
055        int[] baseNorthing = { 200, 400, 600 };
056        int[] baseEasting = { 400, 400, 400 };
057
058        // scale_factor determines how many pixels correspond to one grid square
059        int scaleFactor = 100;
060
061        // map_dimension is the height/width of each map tile (they must all be the
062        // same size)
063        int mapDimension = 2000;
064        private DoGSIFTEngine engine;
065        private ConsistentLocalFeatureMatcher2d<Keypoint> matcher;
066
067        public Snap() {
068                loadMapData();
069
070                engine = new DoGSIFTEngine();
071                // engine.getOptions().setDoubleInitialImage(false);
072
073                final FastBasicKeypointMatcher<Keypoint> innerMatcher = new FastBasicKeypointMatcher<Keypoint>(8);
074                matcher = new ConsistentLocalFeatureMatcher2d<Keypoint>(innerMatcher);
075                final RobustAffineTransformEstimator estimator = new RobustAffineTransformEstimator(0.5);
076                matcher.setFittingModel(estimator);
077                matcher.setModelFeatures(mapData);
078
079        }
080
081        protected void loadMapData() {
082                for (int i = 0; i < mapKeypointFiles.length; i++) {
083                        try {
084                                // read keypoints for current tile
085                                final MemoryLocalFeatureList<Keypoint> map = MemoryLocalFeatureList.read(mapKeypointFiles[i],
086                                                Keypoint.class);
087
088                                // loop through each keypoint in the tile and
089                                // adjust its position, so that the keypoints
090                                // x and y position is its true OSGB grid ref!
091                                for (final Keypoint k : map) {
092                                        final int east = baseEasting[i] + Math.round(10.0f * (k.getX() / scaleFactor));
093                                        final int north = baseNorthing[i]
094                                                        + Math.round(10.0f * ((mapDimension - k.getY()) / scaleFactor)); // different
095                                        // coord systems!!
096
097                                        k.setX(east);
098                                        k.setY(north);
099                                }
100
101                                mapData.addAll(map);
102                        } catch (final Exception ex) {
103                                System.out.println(ex);
104                                System.exit(1);
105                        }
106                }
107        }
108
109        /**
110         * Estimate a grid reference from an image using the MapSnapper algorithm.
111         * 
112         * @param image
113         *
114         * @return grid reference string
115         * @throws Exception
116         */
117        public String getGridRef(FImage image) throws Exception {
118                final LocalFeatureList<Keypoint> keys = engine.findFeatures(image);
119                if (matcher.findMatches(keys)) {
120                        System.out.println("Done! -- Found Match");
121
122                        final Point2d coords = matcher.getModel().predict(
123                                        new Point2dImpl(image.width / 2.0f, image.height / 2.0f));
124
125                        final int east = Math.round(coords.getX());
126                        final int north = Math.round(coords.getY());
127
128                        final Object[] gr = { "NY", east, north };
129                        return String.format("%2s%3d%3d\n", gr);
130                } else {
131                        return "Match Not Found";
132                }
133        }
134
135        public static void main(String[] args) throws Exception {
136                final Snap snap = new Snap();
137                final VideoCapture vc = new VideoCapture(640, 480);
138
139                while (true) {
140                        final FImage img = vc.getNextFrame().flatten();
141                        DisplayUtilities.displayName(img, "Live Video");
142                        final FImage patch = ResizeProcessor.resample(img, 160, 120);// .extractCenter(120,
143                        // 120);
144                        final String res = snap.getGridRef(patch);
145                        if (!res.contains("Not"))
146                                System.out.println(res);
147                }
148        }
149}