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.pixel.sampling; 031 032import org.openimaj.image.FImage; 033import org.openimaj.math.geometry.line.Line2d; 034import org.openimaj.math.geometry.point.Point2d; 035 036/** 037 * Methods for sampling along a line in an {@link FImage}. 038 * 039 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 040 */ 041public enum FLineSampler implements LineSampler<FImage, float[]> { 042 /** 043 * Sample at 1-pixel intervals about the centre of the 044 * line using nearest-neighbour interpolation. The 045 * overall length of the line is ignored. Values 046 * outside the image are considered to be 0. 047 * 048 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 049 */ 050 PIXELSTEP_NEAREST_NEIGHBOUR { 051 @Override 052 public float[] extractSamples(Line2d line, FImage image, int numSamples) { 053 Line2d scaled = getSampleLine(line, image, numSamples); 054 055 return NEAREST_NEIGHBOUR.extractSamples(scaled, image, numSamples); 056 } 057 058 @Override 059 public Line2d getSampleLine(Line2d line, FImage image, int numSamples) { 060 Line2d scaled = line.clone(); 061 scaled.scaleCentroid((float) (numSamples / line.calculateLength())); 062 return scaled; 063 } 064 }, 065 /** 066 * Sample the pixel values at regular intervals along the full length 067 * of the line taking the sample value from the nearest pixel. Pixels 068 * outside the image have a value of 0. 069 * 070 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 071 */ 072 NEAREST_NEIGHBOUR { 073 @Override 074 public float[] extractSamples(Line2d line, FImage image, int numSamples) { 075 float[] samples = new float[numSamples]; 076 077 final Point2d p1 = line.getBeginPoint(); 078 final Point2d p2 = line.getEndPoint(); 079 float x = p1.getX(); 080 float y = p1.getY(); 081 final float dxStep = (p2.getX() - x) / (numSamples-1); 082 final float dyStep = (p2.getY() - y) / (numSamples-1); 083 084 final int width = image.width; 085 final int height = image.height; 086 087 for (int i=0; i<numSamples; i++) { 088 int ix = Math.round(x); 089 int iy = Math.round(y); 090 091 if (ix < 0 || ix >= width || iy < 0 || iy >= height) 092 samples[i] = 0; 093 else 094 samples[i] = image.getPixelNative(ix, iy); 095 096 x += dxStep; 097 y += dyStep; 098 } 099 100 return samples; 101 } 102 }, 103 /** 104 * Sample at 1-pixel intervals about the centre of the 105 * line using bilinear interpolation to estimate sub-pixel 106 * values. The overall length of the line is ignored. Values 107 * outside the image are considered to be 0. 108 * 109 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 110 */ 111 PIXELSTEP_INTERPOLATED { 112 @Override 113 public float[] extractSamples(Line2d line, FImage image, int numSamples) { 114 Line2d scaled = getSampleLine(line, image, numSamples); 115 116 return INTERPOLATED.extractSamples(scaled, image, numSamples); 117 } 118 119 @Override 120 public Line2d getSampleLine(Line2d line, FImage image, int numSamples) { 121 Line2d scaled = line.clone(); 122 scaled.scaleCentroid((float) (numSamples / line.calculateLength())); 123 return scaled; 124 } 125 }, 126 /** 127 * Sample the pixel values at regular intervals along the full 128 * length of the line using bilinear interpolation to get 129 * sub-pixel values. 130 * 131 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 132 */ 133 INTERPOLATED { 134 @Override 135 public float[] extractSamples(Line2d line, FImage image, int numSamples) { 136 float[] samples = new float[numSamples]; 137 138 Point2d p1 = line.getBeginPoint(); 139 Point2d p2 = line.getEndPoint(); 140 float x = p1.getX(); 141 float y = p1.getY(); 142 float dxStep = (p2.getX() - x) / (numSamples-1); 143 float dyStep = (p2.getY() - y) / (numSamples-1); 144 145 for (int i=0; i<numSamples; i++) { 146 samples[i] = image.getPixelInterpNative(x, y, 0); 147 148 x += dxStep; 149 y += dyStep; 150 } 151 152 return samples; 153 } 154 }, 155 /** 156 * Sample at 1-pixel intervals about the centre of the 157 * line using nearest neighbour interpolation to estimate values 158 * and then compute the derivative using [1 0 -1] filter. The number of 159 * regular samples is two bigger than the requested number so 160 * the number of derivative samples is as requested. 161 * The overall length of the line is ignored. Values 162 * outside the image are considered to be 0. 163 * 164 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 165 */ 166 PIXELSTEP_NEAREST_NEIGHBOUR_DERIVATIVE { 167 @Override 168 public float[] extractSamples(Line2d line, FImage image, int numSamples) { 169 Line2d scaled = getSampleLine(line, image, numSamples+2); 170 171 return NEAREST_NEIGHBOUR_DERIVATIVE.extractSamples(scaled, image, numSamples); 172 } 173 174 @Override 175 public Line2d getSampleLine(Line2d line, FImage image, int numSamples) { 176 Line2d scaled = line.clone(); 177 scaled.scaleCentroid((float) (numSamples / line.calculateLength())); 178 return scaled; 179 } 180 }, 181 /** 182 * Sample the pixel values at regular intervals along the full 183 * length of the line using nearest-neighbour pixels and then 184 * compute the derivative using [1 0 -1] filter. The number of 185 * regular samples is two bigger than the requested number so 186 * the number of derivative samples is as requested. 187 * 188 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 189 */ 190 NEAREST_NEIGHBOUR_DERIVATIVE { 191 @Override 192 public float[] extractSamples(Line2d line, FImage image, int numSamples) { 193 float[] samples = NEAREST_NEIGHBOUR.extractSamples(line, image, numSamples+2); 194 return computeDerivative(samples); 195 } 196 }, 197 /** 198 * Sample at 1-pixel intervals about the centre of the 199 * line using bilinear interpolation to estimate sub-pixel values 200 * and then compute the derivative using [1 0 -1] filter. The number of 201 * regular samples is two bigger than the requested number so 202 * the number of derivative samples is as requested. 203 * The overall length of the line is ignored. Values 204 * outside the image are considered to be 0. 205 * 206 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 207 */ 208 PIXELSTEP_INTERPOLATED_DERIVATIVE { 209 @Override 210 public float[] extractSamples(Line2d line, FImage image, int numSamples) { 211 Line2d scaled = getSampleLine(line, image, numSamples+2); 212 213 return NEAREST_NEIGHBOUR_DERIVATIVE.extractSamples(scaled, image, numSamples); 214 } 215 216 @Override 217 public Line2d getSampleLine(Line2d line, FImage image, int numSamples) { 218 Line2d scaled = line.clone(); 219 scaled.scaleCentroid((float) (numSamples / line.calculateLength())); 220 return scaled; 221 } 222 }, 223 /** 224 * Sample the pixel values at regular intervals along the full 225 * length of the line using bilinear interpolation and then 226 * compute the derivative using [1 0 -1] filter. The number 227 * of regular samples is two bigger than the requested number 228 * so the number of derivative samples is as requested. 229 * 230 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 231 */ 232 INTERPOLATED_DERIVATIVE { 233 @Override 234 public float[] extractSamples(Line2d line, FImage image, int numSamples) { 235 float[] samples = INTERPOLATED.extractSamples(line, image, numSamples+2); 236 return computeDerivative(samples); 237 } 238 } 239 ; 240 241 /** 242 * Compute the derivative with a [1 0 -1] filter. The returned 243 * derivatives will have a length of samples.length-2. 244 * @param samples the samples to differentiate 245 * @return differentiated samples 246 */ 247 private static float[] computeDerivative(float[] samples) { 248 final int numSamples = samples.length - 2; 249 final float[] dsamples = new float[numSamples]; 250 251 for (int i=0; i<numSamples; i++) { 252 dsamples[i] = samples[i] - samples[i+2]; 253 } 254 255 return dsamples; 256 } 257 258 259 @Override 260 public Line2d getSampleLine(Line2d line, FImage image, int numSamples) { 261 //most implementations sample the full length of the line 262 return line; 263 } 264 265 @Override 266 public abstract float[] extractSamples(Line2d line, FImage image, int numSamples); 267}