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; 031 032import java.io.DataInput; 033import java.io.DataOutput; 034import java.io.IOException; 035import java.io.PrintWriter; 036import java.util.AbstractList; 037import java.util.List; 038import java.util.Scanner; 039 040import org.openimaj.feature.FloatFV; 041import org.openimaj.feature.local.list.LocalFeatureList; 042import org.openimaj.feature.normalisation.Normaliser; 043import org.openimaj.util.array.ArrayUtils; 044 045/** 046 * This class is designed as a wrapper around any form of local feature and 047 * provides a way of exposing that feature as a {@link FloatFV}, without the 048 * cost of necessarily storing the underlying feature as a {@link FloatFV}. For 049 * example, this can be used to make a Keypoint look like it's backed by a float 050 * array rather than a byte array, without incurring the four-times increase in 051 * storage this would incur. 052 * <p> 053 * The implementation also allows a normalisation process to occur during 054 * conversion through a {@link Normaliser}. 055 * 056 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 057 * 058 * @param <L> 059 * The type of {@link Location} 060 */ 061public class FloatLocalFeatureAdaptor<L extends Location> implements LocalFeature<L, FloatFV> { 062 LocalFeature<L, ?> localFeature; 063 Normaliser<FloatFV> normaliser; 064 065 /** 066 * Construct a new {@link FloatLocalFeatureAdaptor} with the given 067 * underlying feature 068 * 069 * @param localFeature 070 * the underlying feature 071 */ 072 public FloatLocalFeatureAdaptor(LocalFeature<L, ?> localFeature) { 073 this.localFeature = localFeature; 074 } 075 076 /** 077 * Construct a new {@link FloatLocalFeatureAdaptor} with the given 078 * underlying feature and normaliser. 079 * 080 * @param localFeature 081 * the underlying feature 082 * @param normaliser 083 * the normaliser 084 */ 085 public FloatLocalFeatureAdaptor(LocalFeature<L, ?> localFeature, Normaliser<FloatFV> normaliser) { 086 this.localFeature = localFeature; 087 this.normaliser = normaliser; 088 } 089 090 @Override 091 public void readASCII(Scanner in) throws IOException { 092 throw new UnsupportedOperationException(); 093 } 094 095 @Override 096 public String asciiHeader() { 097 throw new UnsupportedOperationException(); 098 } 099 100 @Override 101 public void readBinary(DataInput in) throws IOException { 102 throw new UnsupportedOperationException(); 103 } 104 105 @Override 106 public byte[] binaryHeader() { 107 throw new UnsupportedOperationException(); 108 } 109 110 @Override 111 public void writeASCII(PrintWriter out) throws IOException { 112 throw new UnsupportedOperationException(); 113 } 114 115 @Override 116 public void writeBinary(DataOutput out) throws IOException { 117 throw new UnsupportedOperationException(); 118 } 119 120 @Override 121 public FloatFV getFeatureVector() { 122 final FloatFV fv = new FloatFV(ArrayUtils.convertToFloat(localFeature.getFeatureVector().asDoubleFV().values)); 123 124 if (normaliser != null) 125 normaliser.normalise(fv); 126 127 return fv; 128 } 129 130 @Override 131 public L getLocation() { 132 return localFeature.getLocation(); 133 } 134 135 @Override 136 public boolean equals(Object obj) { 137 if (!(obj instanceof FloatLocalFeatureAdaptor)) 138 return false; 139 140 return ((FloatLocalFeatureAdaptor<?>) obj).localFeature.equals(localFeature); 141 } 142 143 /* 144 * (non-Javadoc) 145 * 146 * @see java.lang.Object#hashCode() 147 */ 148 @Override 149 public int hashCode() { 150 final int prime = 31; 151 int result = 1; 152 result = prime * result + ((localFeature == null) ? 0 : localFeature.hashCode()); 153 return result; 154 } 155 156 /** 157 * Produce a {@link LocalFeatureList} of {@link FloatLocalFeatureAdaptor} by 158 * wrapping the input list, and dynamically wrapping with the 159 * {@link FloatLocalFeatureAdaptor}s on demand. 160 * 161 * @param list 162 * the input list 163 * @return the wrapped list 164 */ 165 public static <L extends Location> List<FloatLocalFeatureAdaptor<L>> wrap( 166 final List<? extends LocalFeature<L, ?>> list) 167 { 168 return wrap(list, null); 169 } 170 171 /** 172 * Produce a {@link LocalFeatureList} of {@link FloatLocalFeatureAdaptor} by 173 * wrapping the input list, and dynamically wrapping with the 174 * {@link FloatLocalFeatureAdaptor}s on demand. 175 * 176 * @param list 177 * the input list 178 * @return the wrapped list 179 */ 180 public static List<FloatLocalFeatureAdaptor<?>> wrapUntyped( 181 final List<? extends LocalFeature<?, ?>> list) 182 { 183 return wrapUntyped(list, null); 184 } 185 186 /** 187 * Produce a {@link LocalFeatureList} of {@link FloatLocalFeatureAdaptor} by 188 * wrapping the input list, and dynamically wrapping with the 189 * {@link FloatLocalFeatureAdaptor}s on demand. 190 * 191 * @param list 192 * the input list 193 * @param normaliser 194 * the normaliser 195 * @return the wrapped list 196 */ 197 public static <L extends Location> List<FloatLocalFeatureAdaptor<L>> wrap( 198 final List<? extends LocalFeature<L, ?>> list, final Normaliser<FloatFV> normaliser) 199 { 200 final List<FloatLocalFeatureAdaptor<L>> out = new AbstractList<FloatLocalFeatureAdaptor<L>>() { 201 202 @Override 203 public FloatLocalFeatureAdaptor<L> get(int index) { 204 return new FloatLocalFeatureAdaptor<L>(list.get(index), normaliser); 205 } 206 207 @Override 208 public int size() { 209 return list.size(); 210 } 211 }; 212 213 return out; 214 } 215 216 /** 217 * Produce a {@link LocalFeatureList} of {@link FloatLocalFeatureAdaptor} by 218 * wrapping the input list, and dynamically wrapping with the 219 * {@link FloatLocalFeatureAdaptor}s on demand. 220 * 221 * @param list 222 * the input list 223 * @param normaliser 224 * the normaliser 225 * @return the wrapped list 226 */ 227 public static List<FloatLocalFeatureAdaptor<?>> wrapUntyped( 228 final List<? extends LocalFeature<?, ?>> list, final Normaliser<FloatFV> normaliser) 229 { 230 final List<FloatLocalFeatureAdaptor<?>> out = new AbstractList<FloatLocalFeatureAdaptor<?>>() { 231 232 @SuppressWarnings("unchecked") 233 @Override 234 public FloatLocalFeatureAdaptor<?> get(int index) { 235 return new FloatLocalFeatureAdaptor<Location>((LocalFeature<Location, ?>) list.get(index), normaliser); 236 } 237 238 @Override 239 public int size() { 240 return list.size(); 241 } 242 }; 243 244 return out; 245 } 246}