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 014import static imagingbook.common.math.Arithmetic.sqr; 015 016/** 017 * <p> 018 * A {@link PixelInterpolator} implementing Lanczos interpolation in 2D. See Sec. 22.5.4 of [1] for additional details. 019 * </p> 020 * <p> 021 * [1] W. Burger, M.J. Burge, <em>Digital Image Processing – An Algorithmic Introduction</em>, 3rd ed, Springer 022 * (2022). 023 * </p> 024 * 025 * @author WB 026 */ 027public class LanczosInterpolator implements PixelInterpolator { 028 029 private final int n; // order (tap count) of this interpolator 030 private final int d; // kernel width 031 032 /** 033 * Constructor creating a Lanczos interpolator of order n = 2. 034 */ 035 public LanczosInterpolator() { 036 this(2); 037 } 038 039 /** 040 * Constructor creating a Lanczos interpolator of arbitrary order n ≥ 2. 041 * @param n order of the interpolator 042 */ 043 public LanczosInterpolator(int n) { 044 if (n < 2) { 045 throw new IllegalArgumentException("Lanczos order must be >= 2"); 046 } 047 this.n = n; // order >= 2 048 this.d = 2 * n - 1; 049 } 050 051 @Override 052 public float getInterpolatedValue(ScalarAccessor ia, double x, double y) { 053 final int u0 = (int) Math.floor(x); // use floor to handle negative coordinates too 054 final int v0 = (int) Math.floor(y); 055 double q = 0; 056 for (int j = 0; j <= d; j++) { 057 int v = v0 + j - n + 1; 058 double p = 0; 059 for (int i = 0; i <= d; i++) { 060 int u = u0 + i - n + 1; 061 p = p + wLn(x - u) * ia.getVal(u, v); 062 } 063 q = q + wLn(y - v) * p; 064 } 065 return (float) q; 066 } 067 068 069 private static final double pi = Math.PI; 070 private static final double pi2 = sqr(pi); 071 072 private double wLn(double x) { // 1D Lanczos interpolator of order n 073 final double r = Math.abs(x); 074 if (r < 0.001) 075 return 1.0; 076 if (r < n) { 077 return n * (Math.sin(pi * r / n) * Math.sin(pi * r)) / (pi2 * sqr(r)); 078 } 079 else 080 return 0.0; 081 } 082 083 @Override 084 public double getWeight(double x) { 085 return wLn(x); 086 } 087 088 089}