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}