# Create and Compare Resizing Interpolation Kernels

This example shows how to define a kernel for image resizing and compare different interpolation kernels on a sample image.

An interpolation kernel calculates the value of a pixel using a weighted average of neighboring pixel values. The `imresize` function offers many built-in kernels that perform bilinear, bicubic, and Lanczos resampling. You can also define a custom kernel and then resize images using the custom kernel.

To evaluate and compare interpolation kernels, this example magnifies a small image using each kernel. Fully assessing the performance of interpolation kernels requires examining a variety of different images and scale factors.

### Create Kernels Based on `imresize` Interpolation Methods

The bilinear method uses a triangular interpolation kernel, which is defined as:

`$\mathit{f}\left(\mathit{x}\right)=\left\{\begin{array}{ll}1-|\mathit{x}|& |\mathit{x}|\le 1\\ 0& \mathrm{otherwise}\end{array}$`

Create a bilinear interpolation kernel using a function called `triangleResampling`. This function is defined in the Helper Functions section at the end of this example. Then, display the bilinear interpolation kernel for a neighborhood of [-3.5, 3.5].

```nhood = [-3.5 3.5]; fplot(@triangleResampling,nhood) title("Bilinear (Triangular) Interpolation Kernel")```

The bicubic method uses this piecewise cubic interpolation kernel:

`$\mathit{f}\left(\mathit{x}\right)=\left\{\begin{array}{ll}1.5{|\mathit{x}|}^{3}-2.5{|\mathit{x}|}^{2}+1& |\mathit{x}|\le 1\\ -0.5{|\mathit{x}|}^{3}+2.5{|\mathit{x}|}^{2}-4|\mathit{x}|+2& 1\le |\mathit{x}|\le 2\\ 0& \mathrm{otherwise}\end{array}$`

Create a bicubic interpolation kernel using a helper function called `bicubicResampling`. This function is defined in the Helper Functions section at the end of this example. Then, display the bicubic interpolation kernel.

```fplot(@bicubicResampling,nhood) title("Bicubic Interpolation Kernel")```

The `lanczos2` and `lanczos3` kernels are based on the Lanczos family of interpolation kernels. The Lanczos kernels are defined as follows, with $\mathit{a}=2$ or $\mathit{a}=3$, respectively:

`$\mathit{f}\left(\mathit{x}\right)=\left\{\begin{array}{ll}\mathrm{sinc}\left(\mathit{x}\right)\mathrm{sinc}\left(\mathit{x}/\mathit{a}\right)& |\mathit{x}|\le \mathit{a}\\ 0& \mathrm{otherwise}\end{array}$`

Create a lanczos2 and lanczos3 interpolation kernel using a function called `lanczosResampling` and specifying the factor $\mathit{a}$.

```lanczos2 = @(x) lanczosResampling(x,2); lanczos3 = @(x) lanczosResampling(x,3);```

Display the `lanczos2` and `lanczos3` interpolation kernels.

```fplot(lanczos2,nhood) hold on fplot(lanczos3,nhood) hold off legend(["Lanczos 2","Lanczos 3"]) title("lanczos2 and lanczos3 Interpolation Kernels")```

### Define Custom Interpolation Kernel

Consider a piecewise rational function based on osculatory rational interpolation [1].

`$\mathit{f}\left(\mathit{x}\right)=\left\{\begin{array}{ll}\frac{-0.168{|\mathit{x}|}^{2}-0.9129|\mathit{x}|+1.0808}{{|\mathit{x}|}^{2}-0.8319|\mathit{x}|+1.0808}& |\mathit{x}|\le 1\\ \frac{0.1953{|\mathit{x}|}^{2}-0.5858|\mathit{x}|+0.3905}{{|\mathit{x}|}^{2}-2.4402|\mathit{x}|+1.7676}& 1<|\mathit{x}|\le 2\\ 0& 2<|\mathit{x}|\end{array}$`

Create a custom interpolation kernel that performs osculatory rational interpolation using a function called `oscResampling`. This function is defined in the Helper Functions section at the end of this example. Then, display the custom interpolation kernel.

```fplot(@oscResampling,nhood) title("Custom Osculatory Rational Interpolation Kernel")```

### Resize Image Using Interpolation Kernels

Read and display a small icon image at 100% magnification.

```A = imread("region-analyzer-icon.png"); imshow(A,"InitialMagnification",100)```

Resize the image by a factor `f` using each built-in interpolation method. Note that the nearest-neighbor method does not take a weighted average of neighborhood pixels. Instead, the nearest neighbor method assigns the output pixels the value of the nearest input pixel.

```f = 10; B_nearest = imresize(A,f,'nearest'); B_bilinear = imresize(A,f,'bilinear'); B_bicubic = imresize(A,f,'bicubic'); B_lanczos2 = imresize(A,f,'lanczos2'); B_lanczos3 = imresize(A,f,'lanczos3');```

To resize the image using the custom kernel, specify the function handle and the nonzero kernel width as the `method` argument for `imresize`:

```width = 4; B_osc = imresize(A,f,{@oscResampling,width});```

Display the resized images as a tiled image, and compare the results subjectively.

The nearest-neighbor result (upper left) appears quite blocky. The bilinear result (upper center) is better in most respects than the nearest-neighbor result but looks a little blurry. The bicubic result (upper right) and lanczos2 result (lower left) appear very similar and are sharper than the bilinear result. For example, look closely at the digits "3" and "8" near the top of the image. The lanczos3 result (lower center) is sharper than the bicubic and lanczos2 results but exhibits a visible "ringing" artifact. The ringing artifact appears as a faint echo outside the gray boundary, or by looking just to the left and right of the thick black stripe running down the middle of the image.

The custom interpolation result (lower right) is slightly sharper than the bicubic and lanczos2 results with slightly smoother diagonal edges. The custom interpolation result does not exhibit a ringing artifact.

```t = imtile({B_nearest,B_bilinear,B_bicubic, ... B_lanczos2,B_lanczos3,B_osc},BackgroundColor="white"); imshow(t)```

### Helper Functions

The `triangleResampling` helper function performs bilinear interpolation.

```function f = triangleResampling(x) f = (1 - abs(x)) .* (abs(x) <= 1); end```

The `bicubicResampling` helper function performs bicubic interpolation.

```function f = bicubicResampling(x) absx = abs(x); absx2 = absx.^2; absx3 = absx.^3; f = (1.5*absx3 - 2.5*absx2 + 1) .* (absx <= 1) + ... (-0.5*absx3 + 2.5*absx2 - 4*absx + 2) .* ... ((1 < absx) & (absx <= 2)); end```

The `lanczosResampling` helper function performs Lanczos interpolation using a specified factor `a`.

```function f = lanczosResampling(x,a) f = a*sin(pi*x) .* sin(pi*x/a) ./ ... (pi^2 * x.^2); f(abs(x) > a) = 0; f(x == 0) = 1; end```

The `oscResampling` helper function performs osculatory rational interpolation.

```function f = oscResampling(x) absx = abs(x); absx2 = absx.^2; f = (absx <= 1) .* ... ((-0.168*absx2 - 0.9129*absx + 1.0808) ./ ... (absx2 - 0.8319*absx + 1.0808)) ... + ... ((1 < absx) & (absx <= 2)) .* ... ((0.1953*absx2 - 0.5858*absx + 0.3905) ./ ... (absx2 - 2.4402*absx + 1.7676)); end```

## References

[1] Hu, Min, and Jieqing Tan. "Adaptive Osculatory Rational Interpolation for Image Processing." Journal of Computational and Applied Mathematics 195, no. 1–2 (October 2006): 46–53. https://doi.org/10.1016/j.cam.2005.07.011.