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 ******************************************************************************/
009
010package imagingbook.common.image.interpolation;
011
012import imagingbook.common.image.access.ScalarAccessor;
013
014/**
015 * <p>
016 * A {@link PixelInterpolator} implementing bicubic interpolation in 2D. See Sec. 22.5.3 (Alg. 22.1) of [1] for
017 * additional details.
018 * </p>
019 * <p>
020 * [1] W. Burger, M.J. Burge, <em>Digital Image Processing &ndash; An Algorithmic Introduction</em>, 3rd ed, Springer
021 * (2022).
022 * </p>
023 *
024 * @author WB
025 */
026public class BicubicInterpolator implements PixelInterpolator {
027        
028        private final double a;         // sharpness factor
029        
030        /**
031         * Constructor using default sharpness factor a = 0.5;.
032         */
033        public BicubicInterpolator() {
034                this(0.5);
035        }
036        
037        /**
038         * Constructor accepting a specific sharpness factor a.
039         * @param a sharpness factor
040         */
041        public BicubicInterpolator(double a) {
042                this.a = a;
043        }
044        
045        @Override
046        public float getInterpolatedValue(ScalarAccessor ia, double x, double y) {
047                final int u0 = (int) Math.floor(x);
048                final int v0 = (int) Math.floor(y);
049                double q = 0;
050                for (int j = 0, v = v0 - 1; j <= 3; j++, v++) {
051//                      int v = v0 - 1 + j;
052                        double p = 0;
053                        for (int i = 0, u = u0 - 1; i <= 3; i++, u++) {
054//                              int u = u0 - 1 + i;
055                                p = p + w_cub(x - u) * ia.getVal(u, v);
056                        }
057                        q = q + w_cub(y - v) * p;
058                }
059                return (float) q;
060        }
061        
062        // 1D cubic interpolation
063        private final double w_cub(double x) {
064                x = Math.abs(x);
065                double z = 0;
066                if (x < 1)
067                        z = (-a + 2) * x * x * x + (a - 3) * x * x + 1;
068                else if (x < 2)
069                        z = -a * x * x * x + 5 * a * x * x - 8 * a * x + 4 * a;
070                return z;
071        }
072
073        @Override
074        public double getWeight(double x) {
075                return w_cub(x);
076        }
077
078
079}