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.analysis.algorithm; 031 032import org.openimaj.image.FImage; 033import org.openimaj.image.analyser.ImageAnalyser; 034import org.openimaj.math.util.Interpolation; 035 036/** 037 * An {@link ImageAnalyser} that can provide interpolate pixel values using a 038 * variety of interpolation approaches. 039 * 040 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 041 * 042 */ 043public class ImageInterpolation implements ImageAnalyser<FImage> { 044 /** 045 * Interface defining an object capable of performing pixel interpolation 046 * 047 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 048 * 049 */ 050 public static interface Interpolator { 051 /** 052 * Interpolate a pixel value 053 * 054 * @param x 055 * the x-ordinate 056 * @param y 057 * the y-ordinate 058 * @param image 059 * the image 060 * @param workingSpace 061 * the working space required 062 * @return the interpolated pixel value 063 */ 064 public float interpolate(float x, float y, FImage image, Object workingSpace); 065 066 /** 067 * Create the working space required for interpolation 068 * 069 * @return the working space (can be <code>null</code>) 070 */ 071 public Object createWorkingSpace(); 072 } 073 074 /** 075 * Standard interpolation types. 076 * 077 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 078 * 079 */ 080 public static enum InterpolationType implements Interpolator { 081 /** 082 * Nearest neighbour interpolation 083 */ 084 NEAREST_NEIGHBOUR { 085 @Override 086 public float interpolate(float x, float y, FImage image, Object workingSpace) { 087 x = Math.round(x); 088 y = Math.round(y); 089 090 if (x < 0 || x >= image.width || y < 0 || y >= image.height) 091 return 0; 092 093 return image.pixels[(int) y][(int) x]; 094 } 095 096 @Override 097 public Object createWorkingSpace() { 098 return null; 099 } 100 }, 101 /** 102 * Bilinear interpolation 103 */ 104 BILINEAR { 105 @Override 106 public float interpolate(float x, float y, FImage image, Object workingSpace) { 107 return image.getPixelInterpNative(x, y, 0); 108 } 109 110 @Override 111 public Object createWorkingSpace() { 112 return null; 113 } 114 }, 115 /** 116 * Bicubic interpolation 117 */ 118 BICUBIC { 119 @Override 120 public float interpolate(float x, float y, FImage image, Object workingSpace) { 121 final float[][] working = (float[][]) workingSpace; 122 123 final int sx = (int) Math.floor(x) - 1; 124 final int sy = (int) Math.floor(y) - 1; 125 final int ex = sx + 3; 126 final int ey = sy + 3; 127 128 for (int yy = sy, i = 0; yy <= ey; yy++, i++) { 129 for (int xx = sx, j = 0; xx <= ex; xx++, j++) { 130 final int px = xx < 0 ? 0 : xx >= image.width ? image.width - 1 : xx; 131 final int py = yy < 0 ? 0 : yy >= image.height ? image.height - 1 : yy; 132 133 working[i][j] = image.pixels[py][px]; 134 } 135 } 136 137 final float dx = (float) (x - Math.floor(x)); 138 final float dy = (float) (y - Math.floor(y)); 139 return Interpolation.bicubicInterp(dx, dy, working); 140 } 141 142 @Override 143 public Object createWorkingSpace() { 144 return new float[4][4]; 145 } 146 }; 147 } 148 149 protected Interpolator interpolator; 150 protected Object workingSpace; 151 protected FImage image; 152 153 /** 154 * Default constructor. 155 * 156 * @param interpolator 157 * the interpolator to use 158 */ 159 public ImageInterpolation(Interpolator interpolator) { 160 this.interpolator = interpolator; 161 this.workingSpace = interpolator.createWorkingSpace(); 162 } 163 164 @Override 165 public void analyseImage(FImage image) { 166 this.image = image; 167 } 168 169 /** 170 * Get the interpolated pixel value of the previously analysed image 171 * 172 * @param x 173 * the x-ordinate 174 * @param y 175 * the y-ordinate 176 * @return the interpolated pixel value 177 */ 178 public float getPixelInterpolated(float x, float y) { 179 return interpolator.interpolate(x, y, image, workingSpace); 180 } 181}