View Javadoc

1   /**
2    * Copyright (c) 2011, The University of Southampton and the individual contributors.
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without modification,
6    * are permitted provided that the following conditions are met:
7    *
8    *   * 	Redistributions of source code must retain the above copyright notice,
9    * 	this list of conditions and the following disclaimer.
10   *
11   *   *	Redistributions in binary form must reproduce the above copyright notice,
12   * 	this list of conditions and the following disclaimer in the documentation
13   * 	and/or other materials provided with the distribution.
14   *
15   *   *	Neither the name of the University of Southampton nor the names of its
16   * 	contributors may be used to endorse or promote products derived from this
17   * 	software without specific prior written permission.
18   *
19   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package org.openimaj.image.feature.dense.gradient.dsift;
31  
32  import org.openimaj.feature.local.list.LocalFeatureList;
33  import org.openimaj.feature.local.list.MemoryLocalFeatureList;
34  import org.openimaj.image.MBFImage;
35  import org.openimaj.image.colour.ColourSpace;
36  import org.openimaj.math.geometry.shape.Rectangle;
37  
38  /**
39   * Implementation of colour dense-sift. The algorithm works by applying the
40   * {@link DenseSIFT} extractor to each channel of the image (in the target
41   * {@link ColourSpace}) and then aggregating the descriptors across all
42   * {@link ColourSpace}s for the same spatial location.
43   * <p>
44   * Any {@link ColourSpace} can be used. To compute the contrast energy of a
45   * descriptor, the luminance is extracted across channels using
46   * {@link ColourSpace#computeIntensity(float[])}. This means that if you choose
47   * a {@link ColourSpace} that doesn't support intensities, then the contrast
48   * energy will be zero. In practice this should not matter as it's most usual to
49   * use the {@link ColourSpace#RGB}, {@link ColourSpace#HSV} or
50   * {@link ColourSpace#OPPONENT} colour spaces, which can compute intensities.
51   * 
52   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
53   * 
54   */
55  public class ColourDenseSIFT extends AbstractDenseSIFT<MBFImage> {
56  	DenseSIFT dsift;
57  	ColourSpace colourSpace;
58  
59  	volatile float[][] descriptors;
60  	volatile float[] energies;
61  
62  	/**
63  	 * Construct with the given internal {@link DenseSIFT} extractor to apply to
64  	 * each band of the image created by converting the input to
65  	 * {@link #analyseImage(MBFImage)} or
66  	 * {@link #analyseImage(MBFImage, Rectangle)} to the given
67  	 * {@link ColourSpace}.
68  	 * 
69  	 * @param dsift
70  	 *            the dense sift extractor
71  	 * @param colourSpace
72  	 *            the target colour space
73  	 */
74  	public ColourDenseSIFT(DenseSIFT dsift, ColourSpace colourSpace) {
75  		this.dsift = dsift;
76  		this.colourSpace = colourSpace;
77  	}
78  
79  	@Override
80  	public void analyseImage(MBFImage image, Rectangle bounds) {
81  		// handle colour conversion?
82  		final MBFImage cimg = colourSpace.convert(image);
83  
84  		// first band:
85  		dsift.analyseImage(cimg.bands.get(0), bounds);
86  		final int len = dsift.descriptors[0].length;
87  		descriptors = new float[dsift.descriptors.length][len * cimg.bands.size()];
88  		final float[][] tmpEnergies = new float[dsift.descriptors.length][cimg.bands.size()];
89  
90  		for (int i = 0; i < descriptors.length; i++) {
91  			System.arraycopy(dsift.descriptors[i], 0, descriptors[i], 0, len);
92  			tmpEnergies[i][0] = dsift.energies[i];
93  		}
94  
95  		// other bands
96  		for (int j = 1; j < cimg.bands.size(); j++) {
97  			dsift.analyseImage(cimg.bands.get(j), bounds);
98  			for (int i = 0; i < descriptors.length; i++) {
99  				System.arraycopy(dsift.descriptors[i], 0, descriptors[i], j * len, len);
100 				tmpEnergies[i][j] = dsift.energies[i];
101 			}
102 		}
103 
104 		// deal with energies
105 		energies = new float[descriptors.length];
106 		for (int i = 0; i < descriptors.length; i++) {
107 			energies[i] = colourSpace.computeIntensity(tmpEnergies[i]);
108 		}
109 	}
110 
111 	@Override
112 	public LocalFeatureList<FloatDSIFTKeypoint> getFloatKeypoints() {
113 		final MemoryLocalFeatureList<FloatDSIFTKeypoint> keys = new MemoryLocalFeatureList<FloatDSIFTKeypoint>(
114 				dsift.numOriBins
115 						* dsift.numBinsX * dsift.numBinsY, descriptors.length);
116 
117 		final int frameSizeX = dsift.binWidth * (dsift.numBinsX - 1) + 1;
118 		final int frameSizeY = dsift.binHeight * (dsift.numBinsY - 1) + 1;
119 
120 		final float deltaCenterX = 0.5F * dsift.binWidth * (dsift.numBinsX - 1);
121 		final float deltaCenterY = 0.5F * dsift.binHeight * (dsift.numBinsY - 1);
122 
123 		for (int framey = dsift.data.boundMinY, i = 0; framey <= dsift.data.boundMaxY - frameSizeY + 1; framey += dsift.stepY)
124 		{
125 			for (int framex = dsift.data.boundMinX; framex <= dsift.data.boundMaxX - frameSizeX + 1; framex += dsift.stepX, i++)
126 			{
127 				keys.add(new FloatDSIFTKeypoint(framex + deltaCenterX, framey + deltaCenterY, descriptors[i], energies[i]));
128 			}
129 		}
130 
131 		return keys;
132 	}
133 
134 	@Override
135 	public LocalFeatureList<ByteDSIFTKeypoint> getByteKeypoints() {
136 		final MemoryLocalFeatureList<ByteDSIFTKeypoint> keys = new MemoryLocalFeatureList<ByteDSIFTKeypoint>(
137 				dsift.numOriBins
138 						* dsift.numBinsX * dsift.numBinsY, descriptors.length);
139 
140 		final int frameSizeX = dsift.binWidth * (dsift.numBinsX - 1) + 1;
141 		final int frameSizeY = dsift.binHeight * (dsift.numBinsY - 1) + 1;
142 
143 		final float deltaCenterX = 0.5F * dsift.binWidth * (dsift.numBinsX - 1);
144 		final float deltaCenterY = 0.5F * dsift.binHeight * (dsift.numBinsY - 1);
145 
146 		for (int framey = dsift.data.boundMinY, i = 0; framey <= dsift.data.boundMaxY - frameSizeY + 1; framey += dsift.stepY)
147 		{
148 			for (int framex = dsift.data.boundMinX; framex <= dsift.data.boundMaxX - frameSizeX + 1; framex += dsift.stepX, i++)
149 			{
150 				keys.add(new ByteDSIFTKeypoint(framex + deltaCenterX, framey + deltaCenterY, descriptors[i], energies[i]));
151 			}
152 		}
153 
154 		return keys;
155 	}
156 
157 	@Override
158 	public LocalFeatureList<FloatDSIFTKeypoint> getFloatKeypoints(float energyThreshold) {
159 		final MemoryLocalFeatureList<FloatDSIFTKeypoint> keys = new MemoryLocalFeatureList<FloatDSIFTKeypoint>(
160 				dsift.numOriBins
161 						* dsift.numBinsX * dsift.numBinsY);
162 
163 		final int frameSizeX = dsift.binWidth * (dsift.numBinsX - 1) + 1;
164 		final int frameSizeY = dsift.binHeight * (dsift.numBinsY - 1) + 1;
165 
166 		final float deltaCenterX = 0.5F * dsift.binWidth * (dsift.numBinsX - 1);
167 		final float deltaCenterY = 0.5F * dsift.binHeight * (dsift.numBinsY - 1);
168 
169 		for (int framey = dsift.data.boundMinY, i = 0; framey <= dsift.data.boundMaxY - frameSizeY + 1; framey += dsift.stepY)
170 		{
171 			for (int framex = dsift.data.boundMinX; framex <= dsift.data.boundMaxX - frameSizeX + 1; framex += dsift.stepX, i++)
172 			{
173 				if (energies[i] >= energyThreshold)
174 					keys.add(new FloatDSIFTKeypoint(framex + deltaCenterX, framey + deltaCenterY, descriptors[i],
175 							energies[i]));
176 			}
177 		}
178 
179 		return keys;
180 	}
181 
182 	@Override
183 	public LocalFeatureList<ByteDSIFTKeypoint> getByteKeypoints(float energyThreshold) {
184 		final MemoryLocalFeatureList<ByteDSIFTKeypoint> keys = new MemoryLocalFeatureList<ByteDSIFTKeypoint>(
185 				dsift.numOriBins
186 						* dsift.numBinsX * dsift.numBinsY);
187 
188 		final int frameSizeX = dsift.binWidth * (dsift.numBinsX - 1) + 1;
189 		final int frameSizeY = dsift.binHeight * (dsift.numBinsY - 1) + 1;
190 
191 		final float deltaCenterX = 0.5F * dsift.binWidth * (dsift.numBinsX - 1);
192 		final float deltaCenterY = 0.5F * dsift.binHeight * (dsift.numBinsY - 1);
193 
194 		for (int framey = dsift.data.boundMinY, i = 0; framey <= dsift.data.boundMaxY - frameSizeY + 1; framey += dsift.stepY)
195 		{
196 			for (int framex = dsift.data.boundMinX; framex <= dsift.data.boundMaxX - frameSizeX + 1; framex += dsift.stepX, i++)
197 			{
198 				if (energies[i] >= energyThreshold)
199 					keys.add(new ByteDSIFTKeypoint(framex + deltaCenterX, framey + deltaCenterY, descriptors[i],
200 							energies[i]));
201 			}
202 		}
203 
204 		return keys;
205 	}
206 
207 	@Override
208 	public void setBinWidth(int size) {
209 		this.dsift.setBinWidth(size);
210 	}
211 
212 	@Override
213 	public void setBinHeight(int size) {
214 		this.dsift.setBinHeight(size);
215 	}
216 
217 	@Override
218 	public int getBinWidth() {
219 		// TODO Auto-generated method stub
220 		return 0;
221 	}
222 
223 	@Override
224 	public int getBinHeight() {
225 		// TODO Auto-generated method stub
226 		return 0;
227 	}
228 
229 	@Override
230 	public int getNumBinsX() {
231 		// TODO Auto-generated method stub
232 		return 0;
233 	}
234 
235 	@Override
236 	public int getNumBinsY() {
237 		// TODO Auto-generated method stub
238 		return 0;
239 	}
240 
241 	@Override
242 	public int getNumOriBins() {
243 		// TODO Auto-generated method stub
244 		return 0;
245 	}
246 
247 	@Override
248 	public float[][] getDescriptors() {
249 		return descriptors;
250 	}
251 }