001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 * image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause).
006 * Copyright (c) 2006-2023 Wilhelm Burger, Mark J. Burge. All rights reserved.
007 * Visit https://imagingbook.com for additional details.
008 ******************************************************************************/
009package Ch22_Pixel_Interpolation;
010
011import Ch21_Geometric_Operations.Draw_Test_Grid;
012import ij.ImagePlus;
013import ij.gui.GenericDialog;
014import ij.plugin.filter.PlugInFilter;
015import ij.process.ImageProcessor;
016import imagingbook.common.ij.DialogUtils;
017import imagingbook.common.ij.IjUtils;
018import imagingbook.common.image.OutOfBoundsStrategy;
019import imagingbook.common.image.access.ImageAccessor;
020import imagingbook.common.image.interpolation.InterpolationMethod;
021import imagingbook.core.jdoc.JavaDocHelp;
022
023/**
024 * <p>
025 * This ImageJ plugin demonstrates the use of various pixel interpolation methods and out-of-bounds strategies.
026 * Sub-pixel translation is used as the geometric transformation (parameters can be specified). Note the use if the
027 * {@link ImageAccessor} class which gives uniform access to all types of images. See Ch. 22 of [1] for more details.
028 * </p>
029 * <p>
030 * [1] W. Burger, M.J. Burge, <em>Digital Image Processing &ndash; An Algorithmic Introduction</em>, 3rd ed, Springer
031 * (2022).
032 * </p>
033 *
034 * @author WB
035 * @version 2022/11/28
036 * @see InterpolationMethod
037 * @see OutOfBoundsStrategy
038 * @see ImageAccessor
039 */
040public class Pixel_Interpolation_Demo implements PlugInFilter, JavaDocHelp {
041        
042        private static InterpolationMethod IPM = InterpolationMethod.Bicubic;
043        private static OutOfBoundsStrategy OBS = OutOfBoundsStrategy.ZeroValues;
044        
045        private static double dx = 10.50;       // translation parameters
046        private static double dy = -3.25;
047        
048        private ImagePlus im;
049        
050        /**
051         * Constructor, asks to open a predefined sample image if no other image
052         * is currently open.
053         */
054        public Pixel_Interpolation_Demo() {
055//              if (IjUtils.noCurrentImage()) {
056//                      DialogUtils.askForSampleImage(GeneralSampleImage.Kepler);
057//              }
058                if (IjUtils.noCurrentImage() && DialogUtils.askForSampleImage()) {
059                        IjUtils.runPlugIn(Draw_Test_Grid.class);
060                }
061        }
062        
063        // ----------------------------------------
064        
065    @Override
066        public int setup(String arg, ImagePlus im) {
067        this.im = im;
068        return DOES_ALL + NO_CHANGES;
069    }
070
071    @Override
072        public void run(ImageProcessor source) {
073        if (!runDialog())
074                        return;
075        
076        final int w = source.getWidth();
077        final int h = source.getHeight();
078        
079        // create the target image (same type as source):
080        ImageProcessor target = source.createProcessor(w, h);
081        
082        // create ImageAccessor's for the source and target  image:
083        ImageAccessor sA = ImageAccessor.create(source, OBS, IPM);
084        ImageAccessor tA = ImageAccessor.create(target);
085        
086        // iterate over all pixels of the target image:
087        for (int u = 0; u < w; u++) {   // discrete target position (u,v)
088                for (int v = 0; v < h; v++) {
089                        double x = u + dx;      // continuous source position (x,y)
090                        double y = v + dy;
091                        float[] val = sA.getPix(x, y);
092                        tA.setPix(u, v, val);   // update target pixel
093                }
094        }
095        
096        // display the target image:
097        (new ImagePlus(im.getShortTitle() + "-" + IPM.toString(), target)).show();
098    }
099    
100    // --------------------------------------------
101    
102        private boolean runDialog() {
103                GenericDialog gd = new GenericDialog(this.getClass().getSimpleName());
104                gd.addHelp(getJavaDocUrl());
105                gd.addNumericField("Translation dx", dx, 2);
106                gd.addNumericField("Translation dy", dy, 2);
107                gd.addEnumChoice("Interpolation method", IPM);
108                gd.addEnumChoice("Out-of-bounds strategy", OBS);
109
110                gd.showDialog();
111                if (gd.wasCanceled())
112                        return false;
113                
114                dx = gd.getNextNumber();
115                dy = gd.getNextNumber();
116                IPM = gd.getNextEnumChoice(InterpolationMethod.class);
117                OBS = gd.getNextEnumChoice(OutOfBoundsStrategy.class);
118                return true;
119        }
120}