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.descriptor.gradient; 031 032import org.openimaj.citation.annotation.Reference; 033import org.openimaj.citation.annotation.ReferenceType; 034import org.openimaj.feature.OrientedFeatureVector; 035import org.openimaj.util.array.ArrayUtils; 036 037/** 038 * Irregular binning SIFT descriptor based on this paper: 039 * {@link <a href="http://www.mpi-inf.mpg.de/~hasler/download/CuiHasThoSei09igSIFT.pdf">CuiHasThoSei09igSIFT.pdf</a>} 040 * 041 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 042 */ 043@Reference( 044 type = ReferenceType.Inproceedings, 045 author = { "Cui, Yan", "Hasler, Nils", "Thorm\"{a}hlen, Thorsten", "Seidel, Hans-Peter" }, 046 title = "Scale Invariant Feature Transform with Irregular Orientation Histogram Binning", 047 year = "2009", 048 booktitle = "Proceedings of the 6th International Conference on Image Analysis and Recognition", 049 pages = { "258", "", "267" }, 050 publisher = "Springer-Verlag", 051 series = "ICIAR '09", 052 customData = { 053 "Address", "Berlin, Heidelberg" 054 }) 055public class IrregularBinningSIFTFeatureProvider implements GradientFeatureProvider, GradientFeatureProviderFactory { 056 private final static float TWO_PI_FLOAT = (float) (Math.PI * 2); 057 058 private final static float FULL_SIZE = 1; 059 private final static float HALF_SIZE = 1 / 2; 060 private final static float QUARTER_SIZE = 1 / 4; 061 private final static float THREE_QUARTER_SIZE = HALF_SIZE + QUARTER_SIZE; 062 private final static float THREE_EIGHTHS_SIZE = 3 / 8; 063 private final static float FIVE_EIGHTHS_SIZE = 5 / 8; 064 065 /** Number of orientation bins in the histograms */ 066 protected int numOriBins = 8; 067 068 /** Threshold for the maximum allowed value in the histogram */ 069 protected float valueThreshold = 0.2f; 070 071 protected float patchOrientation; 072 073 protected float[] vec; 074 075 /** 076 * Construct a IrregularBinningSIFTFeatureExtractor with the default 077 * parameters. 078 */ 079 public IrregularBinningSIFTFeatureProvider() { 080 vec = new float[16 * numOriBins]; 081 } 082 083 /** 084 * Construct a IrregularBinningSIFTFeatureExtractor with the default 085 * parameters. 086 * 087 * @param numOriBins 088 * the number of orientation bins (default 8) 089 */ 090 public IrregularBinningSIFTFeatureProvider(int numOriBins) { 091 this.numOriBins = numOriBins; 092 vec = new float[16 * numOriBins]; 093 } 094 095 /** 096 * Construct a IrregularBinningSIFTFeatureExtractor with the default 097 * parameters. 098 * 099 * @param numOriBins 100 * the number of orientation bins (default 8) 101 * @param valueThreshold 102 * threshold for the maximum value allowed in the histogram 103 * (default 0.2) 104 */ 105 public IrregularBinningSIFTFeatureProvider(int numOriBins, float valueThreshold) { 106 this.numOriBins = numOriBins; 107 this.valueThreshold = valueThreshold; 108 vec = new float[16 * numOriBins]; 109 } 110 111 @Override 112 public void addSample(float x, float y, float gradmag, float gradori) { 113 // adjust the gradient angle to be relative to the patch angle 114 float ori = gradori - patchOrientation; 115 116 // adjust range to 0<=ori<2PI 117 ori = ((ori %= TWO_PI_FLOAT) >= 0 ? ori : (ori + TWO_PI_FLOAT)); 118 119 if (x >= 0 && x < HALF_SIZE && y >= 0 && y < HALF_SIZE) 120 assignOri(0, 0, ori, gradmag); 121 if (x >= QUARTER_SIZE && x < THREE_QUARTER_SIZE && y >= 0 && y < HALF_SIZE) 122 assignOri(0, 1, ori, gradmag); 123 if (x >= HALF_SIZE && x < FULL_SIZE && y >= 0 && y < HALF_SIZE) 124 assignOri(0, 2, ori, gradmag); 125 126 if (x >= 0 && x < HALF_SIZE && y >= QUARTER_SIZE && y < THREE_QUARTER_SIZE) 127 assignOri(0, 3, ori, gradmag); 128 if (x >= HALF_SIZE && x < FULL_SIZE && y >= QUARTER_SIZE && y < THREE_QUARTER_SIZE) 129 assignOri(1, 0, ori, gradmag); 130 131 if (x >= 0 && x < HALF_SIZE && y >= HALF_SIZE && y < FULL_SIZE) 132 assignOri(1, 1, ori, gradmag); 133 if (x >= QUARTER_SIZE && x < THREE_QUARTER_SIZE && y >= HALF_SIZE && y < FULL_SIZE) 134 assignOri(1, 2, ori, gradmag); 135 if (x >= HALF_SIZE && x < FULL_SIZE && y >= HALF_SIZE && y < FULL_SIZE) 136 assignOri(1, 3, ori, gradmag); 137 138 if (x >= QUARTER_SIZE && x < HALF_SIZE && y >= QUARTER_SIZE && y < HALF_SIZE) 139 assignOri(2, 0, ori, gradmag); 140 if (x >= HALF_SIZE && x < THREE_QUARTER_SIZE && y >= QUARTER_SIZE && y < HALF_SIZE) 141 assignOri(2, 1, ori, gradmag); 142 143 if (x >= QUARTER_SIZE && x < HALF_SIZE && y >= HALF_SIZE && y < THREE_QUARTER_SIZE) 144 assignOri(2, 2, ori, gradmag); 145 if (x >= HALF_SIZE && x < THREE_QUARTER_SIZE && y >= HALF_SIZE && y < THREE_QUARTER_SIZE) 146 assignOri(2, 3, ori, gradmag); 147 148 if (x >= THREE_EIGHTHS_SIZE && x < HALF_SIZE && y >= THREE_EIGHTHS_SIZE && y < HALF_SIZE) 149 assignOri(3, 0, ori, gradmag); 150 if (x >= HALF_SIZE && x < FIVE_EIGHTHS_SIZE && y >= THREE_EIGHTHS_SIZE && y < HALF_SIZE) 151 assignOri(3, 1, ori, gradmag); 152 if (x >= THREE_EIGHTHS_SIZE && x < HALF_SIZE && y >= HALF_SIZE && y < FIVE_EIGHTHS_SIZE) 153 assignOri(3, 2, ori, gradmag); 154 if (x >= HALF_SIZE && x < FIVE_EIGHTHS_SIZE && y >= HALF_SIZE && y < FIVE_EIGHTHS_SIZE) 155 assignOri(3, 3, ori, gradmag); 156 } 157 158 protected void assignOri(int r, int c, float orif, float mag) { 159 final float oval = (float) (numOriBins * orif / (2 * Math.PI)); 160 final int oi = (int) ((oval >= 0.0f) ? oval : oval - 1.0f); 161 162 final float ofrac = oval - oi; 163 164 for (int or = 0; or < 2; or++) { 165 int oindex = oi + or; 166 if (oindex >= numOriBins) // Orientation wraps at 2PI. 167 oindex = 0; 168 final float oweight = mag * ((or == 0) ? 1.0f - ofrac : ofrac); 169 170 vec[(4 * numOriBins * r) + (numOriBins * c) + oindex] += oweight; 171 } 172 } 173 174 @Override 175 public OrientedFeatureVector getFeatureVector() { 176 ArrayUtils.normalise(vec); 177 178 boolean changed = false; 179 for (int i = 0; i < vec.length; i++) { 180 if (vec[i] > valueThreshold) { 181 vec[i] = valueThreshold; 182 changed = true; 183 } 184 } 185 186 if (changed) 187 ArrayUtils.normalise(vec); 188 189 // Construct the actual feature vector 190 final OrientedFeatureVector fv = new OrientedFeatureVector(vec.length, patchOrientation); 191 for (int i = 0; i < vec.length; i++) { 192 final int intval = (int) (512.0 * vec[i]); 193 194 fv.values[i] = (byte) (Math.min(255, intval) - 128); 195 } 196 197 return fv; 198 } 199 200 @Override 201 public void setPatchOrientation(float patchOrientation) { 202 this.patchOrientation = patchOrientation; 203 } 204 205 @Override 206 public GradientFeatureProvider newProvider() { 207 return new IrregularBinningSIFTFeatureProvider(numOriBins, valueThreshold); 208 } 209 210 @Override 211 public float getOversamplingAmount() { 212 // no need to over-sample for this feature 213 return 0; 214 } 215}