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.tools.globalfeature; 031 032import java.util.Arrays; 033 034import org.kohsuke.args4j.CmdLineException; 035import org.kohsuke.args4j.CmdLineParser; 036import org.kohsuke.args4j.MBFImageOptionHandler; 037import org.kohsuke.args4j.Option; 038import org.kohsuke.args4j.ProxyOptionHandler; 039import org.openimaj.feature.ByteFV; 040import org.openimaj.feature.ByteFVComparison; 041import org.openimaj.feature.DoubleFV; 042import org.openimaj.feature.DoubleFVComparison; 043import org.openimaj.feature.FVComparator; 044import org.openimaj.feature.FeatureVector; 045import org.openimaj.feature.FloatFV; 046import org.openimaj.feature.FloatFVComparison; 047import org.openimaj.feature.IntFV; 048import org.openimaj.feature.IntFVComparison; 049import org.openimaj.feature.ShortFV; 050import org.openimaj.feature.ShortFVComparison; 051import org.openimaj.image.FImage; 052import org.openimaj.image.MBFImage; 053import org.openimaj.image.analysis.algorithm.FloodFill; 054import org.openimaj.tools.globalfeature.ShapeFeatures.ShapeFeaturesOp; 055 056/** 057 * A tool for computing the similarities/distances between two images based 058 * on a feature from the foreground object in the image. The flood-fill algorithm is 059 * used to segment the foreground/background based 060 * on a seed pixel and distance threshold. 061 * 062 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 063 */ 064public class SegmentingPairWiseComparisonTool { 065 @Option(name="--image-1", aliases="-im1", usage="first image", handler=MBFImageOptionHandler.class, required=true) 066 private MBFImage im1; 067 068 @Option(name="--image-2", aliases="-im2", usage="second image", handler=MBFImageOptionHandler.class, required=true) 069 private MBFImage im2; 070 071 @Option(name="--metric", aliases="-m", usage="comparison metric", required=true) 072 private FeatureComparison compare; 073 074 @Option(name="--feature-type", aliases="-f", handler=ProxyOptionHandler.class, usage="Feature type", required=true) 075 private ShapeFeatures feature; 076 private ShapeFeaturesOp featureOp; 077 078 @Option(name = "--px1", aliases="-px1", required=false, usage="x-position of the starting pixel in image 1") 079 private int px1 = 0; 080 081 @Option(name = "--py1", aliases="-py1", required=false, usage="y-position of the starting pixel in image 1") 082 private int py1 = 0; 083 084 @Option(name = "--thresh1", aliases="-thresh1", required=false, usage="threshold for flood-fill algorithm in image 1") 085 private float thresh1 = 25F/255F; 086 087 @Option(name = "--px2", aliases="-px2", required=false, usage="x-position of the starting pixel in image 2") 088 private int px2 = 0; 089 090 @Option(name = "--py2", aliases="-py2", required=false, usage="y-position of the starting pixel in image 2") 091 private int py2 = 0; 092 093 @Option(name = "--thresh2", aliases="-thresh2", required=false, usage="threshold for flood-fill algorithm in image 2") 094 private float thresh2 = 25F/255F; 095 096 097 @SuppressWarnings("unchecked") 098 protected <T extends FeatureVector> FVComparator<T> getComp(T fv, FeatureComparison type) { 099 if (fv instanceof ByteFV) return (FVComparator<T>) ByteFVComparison.valueOf(type.name()); 100 if (fv instanceof ShortFV) return (FVComparator<T>) ShortFVComparison.valueOf(type.name()); 101 if (fv instanceof IntFV) return (FVComparator<T>) IntFVComparison.valueOf(type.name()); 102 if (fv instanceof FloatFV) return (FVComparator<T>) FloatFVComparison.valueOf(type.name()); 103 if (fv instanceof DoubleFV) return (FVComparator<T>) DoubleFVComparison.valueOf(type.name()); 104 return null; 105 } 106 107 double execute() { 108 FImage mask1 = FloodFill.floodFill(im1, px1, py1, thresh1); 109 FImage mask2 = FloodFill.floodFill(im2, px2, py2, thresh2); 110 111 FeatureVector fv1 = featureOp.execute(im1, mask1); 112 FeatureVector fv2 = featureOp.execute(im2, mask2); 113 114 if (compare == FeatureComparison.EQUALS) { 115 if (Arrays.equals(fv1.asDoubleVector(), fv2.asDoubleVector())) 116 return 1; 117 return 0; 118 } else { 119 return getComp(fv1, compare).compare(fv1, fv2); 120 } 121 } 122 123 /** 124 * The main method of the tool. 125 * @param args 126 */ 127 public static void main(String [] args) { 128 SegmentingPairWiseComparisonTool tool = new SegmentingPairWiseComparisonTool(); 129 130 CmdLineParser parser = new CmdLineParser(tool); 131 132 try { 133 parser.parseArgument(args); 134 } catch (CmdLineException e) { 135 System.err.println(e.getMessage()); 136 System.err.println("Usage: pairwisecomp [options...]"); 137 parser.printUsage(System.err); 138 139 if (tool.feature == null) { 140 for (GlobalFeatureType m : GlobalFeatureType.values()) { 141 System.err.println(); 142 System.err.println(m + " options: "); 143 new CmdLineParser(m.getOptions()).printUsage(System.err); 144 } 145 } 146 return; 147 } 148 149 System.out.println(tool.execute()); 150 } 151}