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}