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.aggregate;
031
032import java.util.ArrayList;
033import java.util.Collection;
034import java.util.List;
035
036import org.openimaj.feature.ArrayFeatureVector;
037import org.openimaj.feature.SparseIntFV;
038import org.openimaj.feature.local.LocalFeature;
039import org.openimaj.feature.local.Location;
040import org.openimaj.feature.local.quantised.QuantisedLocalFeature;
041import org.openimaj.ml.clustering.assignment.HardAssigner;
042
043/**
044 * Implementation of an object capable of extracting basic (hard-assignment) Bag
045 * of Visual Words (BoVW) representations of an image given a list of local
046 * features and an {@link HardAssigner} with an associated codebook.
047 * 
048 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
049 * 
050 * @param <T>
051 *            Primitive array type of the {@link ArrayFeatureVector}s used by
052 *            the {@link LocalFeature}s that will be processed.
053 */
054public class BagOfVisualWords<T> implements VectorAggregator<ArrayFeatureVector<T>, SparseIntFV> {
055        private HardAssigner<T, ?, ?> assigner;
056
057        /**
058         * Construct with the given assigner.
059         * 
060         * @param assigner
061         *            the assigner
062         */
063        public BagOfVisualWords(HardAssigner<T, ?, ?> assigner) {
064                this.assigner = assigner;
065        }
066
067        /**
068         * Utility method to construct a list of quantised local features (local
069         * features with visual word assignments) from a list of features and a
070         * {@link HardAssigner}.
071         * 
072         * @param assigner
073         *            the assigner to apply to the feature vectors to create the
074         *            visual word identifiers
075         * @param features
076         *            the features to process
077         * @return a list of features with visual word assignments
078         */
079        public static <L extends Location, T> List<QuantisedLocalFeature<L>> computeQuantisedFeatures(
080                        HardAssigner<T, ?, ?> assigner,
081                        List<? extends LocalFeature<L, ? extends ArrayFeatureVector<T>>> features)
082        {
083                final List<QuantisedLocalFeature<L>> out = new ArrayList<QuantisedLocalFeature<L>>(features.size());
084
085                for (final LocalFeature<L, ? extends ArrayFeatureVector<T>> f : features) {
086                        final int idx = assigner.assign(f.getFeatureVector().values);
087                        out.add(new QuantisedLocalFeature<L>(f.getLocation(), idx));
088                }
089
090                return out;
091        }
092
093        /**
094         * Utility method to quickly convert a collection of quantised local
095         * features to a histogram of their corresponding visual word identifiers.
096         * 
097         * @param qfeatures
098         *            the quantised features.
099         * @param nfeatures
100         *            the number of visual words.
101         * @return a histogram of the occurrences of the visual words
102         */
103        public static <L extends Location>
104                        SparseIntFV
105                        extractFeatureFromQuantised(Collection<? extends QuantisedLocalFeature<L>> qfeatures, final int nfeatures)
106        {
107                final SparseIntFV fv = new SparseIntFV(nfeatures);
108
109                for (final QuantisedLocalFeature<L> qf : qfeatures) {
110                        fv.values.increment(qf.id, 1);
111                }
112
113                return fv;
114        }
115
116        @Override
117        public SparseIntFV aggregate(List<? extends LocalFeature<?, ? extends ArrayFeatureVector<T>>> features) {
118                final SparseIntFV fv = new SparseIntFV(this.assigner.size());
119
120                for (final LocalFeature<?, ? extends ArrayFeatureVector<T>> f : features) {
121                        final int idx = assigner.assign(f.getFeatureVector().values);
122
123                        fv.values.increment(idx, 1);
124                }
125
126                return fv;
127        }
128
129        @Override
130        public SparseIntFV aggregateVectors(List<? extends ArrayFeatureVector<T>> features) {
131                final SparseIntFV fv = new SparseIntFV(this.assigner.size());
132
133                for (final ArrayFeatureVector<T> f : features) {
134                        final int idx = assigner.assign(f.values);
135
136                        fv.values.increment(idx, 1);
137                }
138
139                return fv;
140        }
141
142        /**
143         * Aggregate the given features into a vector.
144         * 
145         * @param features
146         *            the features to aggregate
147         * @return the aggregated vector
148         */
149        public SparseIntFV aggregateVectorsRaw(List<T> features) {
150                final SparseIntFV fv = new SparseIntFV(this.assigner.size());
151
152                for (final T f : features) {
153                        final int idx = assigner.assign(f);
154
155                        fv.values.increment(idx, 1);
156                }
157
158                return fv;
159        }
160}