/** * */ package fr.unistra.pelican.algorithms.geometric; import fr.unistra.pelican.Algorithm; import fr.unistra.pelican.AlgorithmException; import fr.unistra.pelican.Image; import fr.unistra.pelican.algorithms.io.ImageLoader; import fr.unistra.pelican.algorithms.visualisation.MViewer; import fr.unistra.pelican.util.Tools; /** * Expand XY dimensions of an image. This can not be used for shrinking (at least this would be a very bad idea). * * Possible interpolation methods are * - nearest neighbor * - bilinear * - bicubic spline (approximation of Catmull-Rom definition) * * @TODO add Lanczos interpolation method * * @author Benjamin Perret * */ public class ExpandXY extends Algorithm { /** * Supported interpolation method * @author Benjamin Perret * */ public static enum InterpolationMethod {Nearest, Bilinear, BiCubic}; /** * Input image */ public Image inputImage; /** * x dim of output image */ public int newXDim; /** * y dim of output image */ public int newYDim; /** * Method used for interpolation (default is bicubic) */ public InterpolationMethod method=InterpolationMethod.BiCubic; /** * output image */ public Image outputImage; /** * increment in input image xdim */ private double dx; /** * increment in input image ydim */ private double dy; /** * rounding precision (number of digits after decimal point) */ private int precision=5; public ExpandXY(){ super.inputs="inputImage,newXDim,newYDim"; super.options="method"; super.outputs="outputImage"; } /* (non-Javadoc) * @see fr.unistra.pelican.Algorithm#launch() */ @Override public void launch() throws AlgorithmException { if(newXDim <inputImage.xdim || newYDim < inputImage.ydim) throw new AlgorithmException("New image size must be strictly greater than input Image"); outputImage= inputImage.newInstance(newXDim, newYDim, inputImage.zdim, inputImage.tdim, inputImage.bdim); switch (method){ case Nearest: dx=((double)inputImage.xdim)/(double)(newXDim); dy=((double)inputImage.ydim)/(double)(newYDim); nearestNeighboor(); break; case Bilinear: dx=((double)inputImage.xdim-1.0)/(double)(newXDim-1.0); dy=((double)inputImage.ydim-1.0)/(double)(newYDim-1.0); bilinear(); break; case BiCubic: dx=((double)inputImage.xdim-1.0)/(double)(newXDim-1.0); dy=((double)inputImage.ydim-1.0)/(double)(newYDim-1.0); bicubic(); break; } } private void nearestNeighboor() { for(int t=0;t<outputImage.tdim;t++) { for(int z=0;z<outputImage.zdim;z++) { for(int b=0;b<outputImage.bdim;b++) { double yOri=0.0; for(int y=0;y<outputImage.ydim;y++) { double xOri=0.0; for(int x=0;x<outputImage.xdim;x++) { double v=inputImage.getPixelDouble((int)Math.floor(xOri), (int)Math.floor(yOri), z, t, b); outputImage.setPixelDouble(x, y, z, t, b, v); xOri+=dx; } yOri+=dy; } } } } } private void bilinear() { for(int t=0;t<outputImage.tdim;t++) { for(int z=0;z<outputImage.zdim;z++) { for(int b=0;b<outputImage.bdim;b++) { double yOri=0.0; for(int y=0;y<outputImage.ydim;y++) { double xOri=0.0; for(int x=0;x<outputImage.xdim;x++) { //System.out.println("["+Tools.round(xOri,precision)+";"+Tools.round(yOri,precision)+"]"); double v=Tools.getBilinearInterpolation(inputImage, Tools.round(xOri,precision), Tools.round(yOri,precision), z, t, b); outputImage.setPixelDouble(x, y, z, t, b, v); xOri+=dx; } yOri+=dy; } } } } } private void bicubic() { for(int t=0;t<outputImage.tdim;t++) { for(int z=0;z<outputImage.zdim;z++) { for(int b=0;b<outputImage.bdim;b++) { double yOri=0.0; for(int y=0;y<outputImage.ydim;y++) { double xOri=0.0; for(int x=0;x<outputImage.xdim;x++) { double v=Tools.getBiCubicInterpolation(inputImage, Tools.round(xOri,precision), Tools.round(yOri,precision), z, t, b); outputImage.setPixelDouble(x, y, z, t, b, v); xOri+=dx; } yOri+=dy; } } } } } @SuppressWarnings("unchecked") public static <T extends Image> T exec(T inputImage, int newXDim, int newYDim){ return (T)new ExpandXY().process(inputImage,newXDim, newYDim); } @SuppressWarnings("unchecked") public static <T extends Image> T exec(T inputImage, int newXDim, int newYDim, InterpolationMethod method){ return (T)new ExpandXY().process(inputImage,newXDim, newYDim,method); } /** * @param args */ public static void main(String[] args) { /*DoubleImage im = new DoubleImage(5,5,1,1,1); double [] vals={5.0,20.0,4.0,-40.0,-500, 0.0,45.0,-3.0,-70.0,-600, -2.0,800,5,0,-40, -50,90,30,20,-80, 200,0,20,-90,900}; im.pixels=vals; im.setPixelXYDouble(0, 0, 0.0); im.setPixelXYDouble(1, 1, 50.0); im.setPixelXYDouble(0, 1, -5.0); im.setPixelXYDouble(1, 0, 5.0); int nx=100; int ny=100; */ Image im=ImageLoader.exec("samples/lenna512.png"); int nx=100; int ny=100; Image near=ExpandXY.exec(im, nx, ny, InterpolationMethod.Nearest); Image bili=ExpandXY.exec(im, nx, ny, InterpolationMethod.Bilinear); Image bicu=ExpandXY.exec(im, nx, ny, InterpolationMethod.BiCubic); MViewer.exec(im,near,bili,bicu); } }