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;
031
032import java.util.HashMap;
033
034import org.openimaj.data.identity.Identifiable;
035
036/**
037 * A simple wrapper for a feature extractor that caches the extracted feature to
038 * a {@link HashMap}. If a feature has already been generated for a given
039 * object, it will be re-read from the {@link HashMap}
040 * 
041 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
042 * 
043 * @param <FEATURE>
044 *            Type of feature
045 * @param <OBJECT>
046 *            Type of object
047 */
048public class CachingFeatureExtractor<FEATURE, OBJECT extends Identifiable>
049                implements
050                FeatureExtractor<FEATURE, OBJECT>
051{
052        private FeatureExtractor<FEATURE, OBJECT> extractor;
053        private boolean force;
054
055        private HashMap<String, FEATURE> cache;
056
057        /**
058         * Construct the cache {@link HashMap}. The given extractor will be used to
059         * generate the features.
060         * 
061         * @param extractor
062         *            the feature extractor
063         */
064        public CachingFeatureExtractor(FeatureExtractor<FEATURE, OBJECT> extractor) {
065                this(extractor, false);
066        }
067
068        /**
069         * Construct the cache {@link HashMap} The given extractor will be used to
070         * generate the features. Optionally, all features can be regenerated.
071         * 
072         * @param extractor
073         *            the feature extractor
074         * @param force
075         *            if true, then all features will be regenerated and saved,
076         *            rather than being loaded.
077         */
078        public CachingFeatureExtractor(FeatureExtractor<FEATURE, OBJECT> extractor, boolean force) {
079                this.cache = new HashMap<String, FEATURE>();
080                this.extractor = extractor;
081                this.force = force;
082        }
083
084        @Override
085        public FEATURE extractFeature(OBJECT object) {
086                final FEATURE cachedFeature = this.cache.get(object.getID());
087
088                FEATURE feature = null;
089                if (!force && cachedFeature != null) {
090                        feature = cachedFeature;
091
092                        if (feature != null)
093                                return feature;
094                }
095
096                feature = extractor.extractFeature(object);
097                this.cache.put(object.getID(), feature);
098                return feature;
099        }
100
101        @Override
102        public String toString() {
103                return this.extractor.toString();
104        }
105
106}