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.AbstractList; 033import java.util.AbstractMap; 034import java.util.AbstractSet; 035import java.util.Iterator; 036import java.util.Set; 037 038import org.openimaj.data.dataset.GroupedDataset; 039import org.openimaj.data.dataset.ListBackedDataset; 040import org.openimaj.data.dataset.ListDataset; 041import org.openimaj.data.dataset.MapBackedDataset; 042 043/** 044 * Static methods to generate datasets of features from datasets of objects 045 * using a feature extractor. 046 * 047 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 048 */ 049public class DatasetExtractors { 050 private DatasetExtractors() { 051 } 052 053 /** 054 * Create a {@link ListDataset} of features from the given 055 * {@link ListDataset} of objects by extracting the features from the 056 * objects with the given feature extractor. 057 * <p> 058 * This function is produces a lazy {@link ListDataset} instance that 059 * extracts features on demand. No caching is performed, so if you 060 * <code>get</code> from the resultant list for the same element many times, 061 * you'll invoke the feature extractor each time. 062 * 063 * @param input 064 * the {@link ListDataset} of input objects 065 * @param extractor 066 * the feature extractor 067 * @return a {@link ListDataset} of features 068 */ 069 public static <FEATURE, OBJECT> ListDataset<FEATURE> createLazyFeatureDataset(final ListDataset<OBJECT> input, 070 final FeatureExtractor<FEATURE, OBJECT> extractor) 071 { 072 return new ListBackedDataset<FEATURE>(new AbstractList<FEATURE>() { 073 @Override 074 public FEATURE get(int index) { 075 return extractor.extractFeature(input.get(index)); 076 } 077 078 @Override 079 public int size() { 080 return input.size(); 081 } 082 }); 083 } 084 085 /** 086 * Create a {@link GroupedDataset} of keys to {@link ListDataset} of 087 * features from the given {@link GroupedDataset} of keys to 088 * {@link ListDataset}s of objects by extracting the features from the 089 * objects with the given feature extractor. 090 * <p> 091 * This function is produces a lazy {@link GroupedDataset} instance that 092 * extracts features on demand. No caching is performed, so if you 093 * <code>get</code> from the resultant list for the same element many times, 094 * you'll invoke the feature extractor each time. 095 * 096 * @param input 097 * the {@link GroupedDataset} of input objects 098 * @param extractor 099 * the feature extractor 100 * @return a {@link GroupedDataset} of features 101 */ 102 public static <FEATURE, OBJECT, KEY> GroupedDataset<KEY, ListDataset<FEATURE>, FEATURE> createLazyFeatureDataset( 103 final GroupedDataset<KEY, ? extends ListDataset<OBJECT>, OBJECT> input, 104 final FeatureExtractor<FEATURE, OBJECT> extractor) 105 { 106 return new MapBackedDataset<KEY, ListDataset<FEATURE>, FEATURE>(new AbstractMap<KEY, ListDataset<FEATURE>>() { 107 @Override 108 public int size() { 109 return input.size(); 110 } 111 112 @Override 113 public boolean isEmpty() { 114 return input.isEmpty(); 115 } 116 117 @Override 118 public boolean containsKey(Object key) { 119 return input.containsKey(key); 120 } 121 122 @Override 123 public ListDataset<FEATURE> get(Object key) { 124 return createLazyFeatureDataset(input.get(key), extractor); 125 } 126 127 @Override 128 public Set<KEY> keySet() { 129 return input.keySet(); 130 } 131 132 @Override 133 public Set<java.util.Map.Entry<KEY, ListDataset<FEATURE>>> entrySet() { 134 return new AbstractSet<Entry<KEY, ListDataset<FEATURE>>>() { 135 136 @Override 137 public Iterator<java.util.Map.Entry<KEY, ListDataset<FEATURE>>> iterator() { 138 return new Iterator<Entry<KEY, ListDataset<FEATURE>>>() { 139 Iterator<?> internal = input.entrySet().iterator(); 140 141 @Override 142 public boolean hasNext() { 143 return internal.hasNext(); 144 } 145 146 @Override 147 public Entry<KEY, ListDataset<FEATURE>> next() { 148 return new Entry<KEY, ListDataset<FEATURE>>() { 149 @SuppressWarnings("unchecked") 150 Entry<KEY, OBJECT> next = (Entry<KEY, OBJECT>) internal.next(); 151 152 @Override 153 public KEY getKey() { 154 return next.getKey(); 155 } 156 157 @SuppressWarnings("unchecked") 158 @Override 159 public ListDataset<FEATURE> getValue() { 160 return createLazyFeatureDataset((ListDataset<OBJECT>) next.getValue(), extractor); 161 } 162 163 @Override 164 public ListDataset<FEATURE> setValue(ListDataset<FEATURE> value) { 165 throw new UnsupportedOperationException(); 166 } 167 }; 168 } 169 170 @Override 171 public void remove() { 172 throw new UnsupportedOperationException(); 173 } 174 }; 175 } 176 177 @Override 178 public int size() { 179 return input.size(); 180 } 181 }; 182 } 183 184 }); 185 } 186}