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.image.feature.local.interest.experiment; 031 032import java.io.File; 033import java.io.IOException; 034import java.util.ArrayList; 035import java.util.HashMap; 036import java.util.List; 037 038import org.apache.log4j.BasicConfigurator; 039import org.apache.log4j.Level; 040import org.apache.log4j.Logger; 041import org.openimaj.feature.local.list.LocalFeatureList; 042import org.openimaj.feature.local.list.MemoryLocalFeatureList; 043import org.openimaj.image.ImageUtilities; 044import org.openimaj.image.MBFImage; 045import org.openimaj.image.colour.Transforms; 046import org.openimaj.image.feature.local.detector.ipd.collector.CircularInterestPointKeypoint; 047import org.openimaj.image.feature.local.engine.ipd.FinderMode; 048import org.openimaj.image.feature.local.engine.ipd.IPDSIFTEngine; 049import org.openimaj.image.feature.local.interest.AffineAdaption; 050import org.openimaj.image.feature.local.interest.HarrisIPD; 051import org.openimaj.image.feature.local.interest.IPDSelectionMode; 052import org.openimaj.image.feature.local.interest.InterestPointData; 053import org.openimaj.image.feature.local.keypoints.InterestPointKeypoint; 054import org.openimaj.io.IOUtils; 055 056import Jama.Matrix; 057 058 059 060public class OxfordRepeatabilityExperiment { 061 private static final String DEFAULT_FEATURE_DUMP_PATH = "/tmp/featurePath"; 062 static Logger logger = Logger.getLogger(AffineAdaption.class); 063 static{ 064 BasicConfigurator.configure(); 065 logger.setLevel(Level.DEBUG); 066 } 067 static class ExperimentException extends Exception{ 068 069 public ExperimentException(String string) { 070 super(string); 071 } 072 073 /** 074 * 075 */ 076 private static final long serialVersionUID = 1L; 077 078 } 079 080 private int nExperiments; 081 private String transformName; 082 private String imageName; 083 private HashMap<String, List<InterestPointData>> features; 084 private HashMap<String, Matrix> transforms; 085 private HashMap<String, MBFImage> images; 086 private ExperimentFeatureExtraction experiemtnFeatureExtraction; 087 private String featureDumpPath = DEFAULT_FEATURE_DUMP_PATH; 088 089 OxfordRepeatabilityExperiment(String experimentRoot, String transformName, String imageName, int nImages, ExperimentFeatureExtraction expFE, String featureDumpPath) throws IOException{ 090 this.nExperiments = nImages - 1; 091 this.transformName = transformName; 092 this.imageName = imageName; 093 this.experiemtnFeatureExtraction = expFE; 094 this.featureDumpPath = featureDumpPath; 095 transforms = new HashMap<String,Matrix>(); 096 images = new HashMap<String, MBFImage>(); 097 098 String imageNameFormated = String.format(imageName, 1); 099 String imageLocation = experimentRoot + "/" + imageNameFormated; 100 logger.debug("Loading image: " + imageLocation ); 101 MBFImage im = ImageUtilities.readMBF(this.getClass().getResourceAsStream(imageLocation)); 102 if(im == null){ 103 throw new IOException("Can't load image: " + imageLocation); 104 } 105 images.put(imageNameFormated, im); 106 107 for (int i = 1; i < nImages; i++) { 108 String transformNameFormated = String.format(transformName, 1, i + 1); 109 String transformLocation = experimentRoot + "/" + transformNameFormated; 110 logger.debug("Loading trasnform: " + transformLocation); 111 transforms.put(transformNameFormated,IPDRepeatability.readHomography(this.getClass().getResourceAsStream(transformLocation))); 112 imageNameFormated = String.format(imageName, i+1); 113 imageLocation = experimentRoot + "/" + imageNameFormated; 114 logger.debug("Loading image: " + imageLocation ); 115 images.put(imageNameFormated, ImageUtilities.readMBF(this.getClass().getResourceAsStream(imageLocation))); 116 } 117 118 this.features = new HashMap<String, List<InterestPointData>>(); 119 } 120 121 public OxfordRepeatabilityExperiment(String expBase, String transformName,String imgName, int nExperiments, ExperimentFeatureExtraction experiemtnFeatureExtraction) throws IOException { 122 this(expBase, transformName, imgName, nExperiments, experiemtnFeatureExtraction, DEFAULT_FEATURE_DUMP_PATH); 123 } 124 125 public IPDRepeatability<InterestPointData> experimentWith(int n) throws ExperimentException{ 126 if(n > this.nExperiments) 127 return null; 128 String image1Name = String.format(imageName, 1); 129 String image2Name = String.format(imageName, n+1); 130 131 if(!this.images.containsKey(image1Name) || this.images.get(image1Name) == null){ 132 throw new ExperimentException("Couldn't load: " + image1Name); 133 } 134 135 if(!this.images.containsKey(image2Name)){ 136 throw new ExperimentException("Couldn't load: " + image2Name); 137 } 138 139 List<InterestPointData> image1Features = getFeatures(image1Name); 140 List<InterestPointData> image2Features = getFeatures(image2Name); 141 142 if(image1Features == null || image2Features == null){ 143 throw new ExperimentException("Couldn't load features correctly"); 144 } 145 146 String transformNameFormatted = String.format(this.transformName, 1,n+1); 147 148 if(!this.transforms.containsKey(transformNameFormatted)){ 149 throw new ExperimentException("Couldn't load: " + transformNameFormatted); 150 } 151 152 153 154 return IPDRepeatability.repeatability( 155 this.images.get(image1Name), 156 this.images.get(image2Name), 157 image1Features, 158 image2Features, 159 this.transforms.get(transformNameFormatted), 160 4 161 ); 162 } 163 164 private List<InterestPointData> getFeatures(String imageNameFormatted) { 165 166 if(!this.features.containsKey(imageNameFormatted)){ 167 File featureDump = new File(featureDumpPath ,String.format("%s/%s.%s",experiemtnFeatureExtraction.experimentName(),imageNameFormatted,experiemtnFeatureExtraction.experimentName())); 168 featureDump.getParentFile().mkdir(); 169 LocalFeatureList<? extends InterestPointKeypoint<InterestPointData>> kpts = null; 170 if(featureDump.exists()){ 171 try { 172 kpts = MemoryLocalFeatureList.read(featureDump, CircularInterestPointKeypoint.class); 173 } catch (IOException e) { 174 e.printStackTrace(); 175 } 176 } 177 if(kpts==null){ 178// HarrisIPD hIPD = new HarrisIPD(1.4f); 179// hIPD.setImageBlurred(true); 180// // AffineAdaption affineIPD = new AffineAdaption(harrisIPD,new 181// // IPDSelectionMode.Threshold(10000f)); 182// IPDSIFTEngine engine = new IPDSIFTEngine(hIPD); 183// engine.setAcrossScales(true); 184// engine.setFinderMode(new FinderMode.Characteristic<InterestPointData>()); 185 IPDSIFTEngine engine = experiemtnFeatureExtraction.engine(); 186 kpts = engine.findFeatures(Transforms.calculateIntensityNTSC(this.images.get(imageNameFormatted))); 187 188 try { 189 IOUtils.writeBinary(featureDump, kpts); 190 } catch (IOException e) { 191 e.printStackTrace(); 192 } 193 } 194 195 List<InterestPointData> ipts = new ArrayList<InterestPointData>(); 196 for (InterestPointKeypoint<InterestPointData> interestPointKeypoint : kpts) { 197 ipts.add(interestPointKeypoint.location); 198 } 199 this.features.put(imageNameFormatted, ipts); 200 } 201 202 203 204 return this.features.get(imageNameFormatted); 205 } 206 207 static interface ExperimentFeatureExtraction{ 208 public class AffineHarris implements ExperimentFeatureExtraction { 209 @Override 210 public String experimentName() { 211 return "affineharris"; 212 } 213 214 @Override 215 public IPDSIFTEngine engine() { 216 217 return null; 218 } 219 220 } 221 222 public String experimentName(); 223 public IPDSIFTEngine engine(); 224 225 static class Harris implements ExperimentFeatureExtraction{ 226 227 @Override 228 public String experimentName() { 229 return "harris"; 230 } 231 232 @Override 233 public IPDSIFTEngine engine() { 234 HarrisIPD hIPD = new HarrisIPD(1.4f); 235 hIPD.setImageBlurred(true); 236 // AffineAdaption affineIPD = new AffineAdaption(harrisIPD,new 237 // IPDSelectionMode.Threshold(10000f)); 238 IPDSIFTEngine engine = new IPDSIFTEngine(hIPD); 239 engine.setSelectionMode(new IPDSelectionMode.Threshold(10000f)); 240 engine.setAcrossScales(true); 241 engine.setFinderMode(new FinderMode.Characteristic<InterestPointData>()); 242 return engine; 243 } 244 245 } 246 } 247 248 public static void main(String args[]) throws IOException, ExperimentException{ 249 String expBase = "/org/openimaj/image/feature/validator/graf"; 250 String imgName = "img%d.ppm"; 251 OxfordRepeatabilityExperiment exp = new OxfordRepeatabilityExperiment( 252 expBase, // The root of all the images and transforms 253 "H%dto%dp", // the name format of the transform 254 imgName, // the name format of the image 255 6, // the number of experiments to expect 256 new ExperimentFeatureExtraction.Harris() 257 ); 258 259 for(int i = 1; i < 6;i++) 260 { 261 IPDRepeatability<InterestPointData> experiment = exp.experimentWith(i); 262 System.out.println(String.format(imgName + ": %f", i+1, experiment.repeatability(0.6f))); 263 } 264// IPDRepeatability<InterestPointData> experiment1v2 = exp.experimentWith(1); 265// 266// System.out.println("Experiment 1 v 2"); 267// for(float error = 0.1f; error <= .9f; error +=0.1f){ 268// float overlap = 1.f - error; 269// System.out.format("Minimum overlap %f (err=%f): %f\n",overlap,error,experiment1v2.repeatability(overlap)); 270// } 271 } 272}