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}