.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/003_interpolate_2D_images.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. or to run this example in your browser via JupyterLite or Binder .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_003_interpolate_2D_images.py: Interpolate 2D Images ===================== Interpolate 2D images with standard interpolation, least-squares, and oblique projection. Compare them to SciPy zoom. We compute SNR and MSE only on a central region to exclude boundary artifacts. A summary of the cost/benefit tradeoff of the three methods is provided at the bottom of this page. You can download this example at the tab at right (Python script or Jupyter notebook. .. GENERATED FROM PYTHON SOURCE LINES 14-19 Required Libraries ------------------ We import the required libraries, including NumPy for numerical computations, Matplotlib for plotting, and the custom `resize` function from the `splineops` package. .. GENERATED FROM PYTHON SOURCE LINES 19-30 .. code-block:: Python import numpy as np import matplotlib.pyplot as plt import requests from io import BytesIO from PIL import Image from scipy.ndimage import zoom # For SciPy's zoom comparison from splineops.resize.resize import resize # Unified resize function import time .. GENERATED FROM PYTHON SOURCE LINES 31-38 Helper Functions ---------------- We define - a utility to crop out ~20% borders around the image; - SNR and MSE on that central cropped area; - resizing functions. .. GENERATED FROM PYTHON SOURCE LINES 38-134 .. code-block:: Python def crop_to_central_region(image, border_fraction): """ Return a central sub-region of 'image', skipping 'border_fraction' of the width/height on all sides. """ H, W = image.shape top = int(H * border_fraction) bottom = int(H * (1 - border_fraction)) left = int(W * border_fraction) right = int(W * (1 - border_fraction)) # Guard against degenerate cases top = max(top, 0) left = max(left, 0) bottom = min(bottom, H) right = min(right, W) return image[top:bottom, left:right] def compute_snr_and_mse_cropped(original, processed, border_fraction): """ Compute SNR and MSE on the 'central' cropped area, ignoring border_fraction of the image on each side. """ # Crop both images consistently orig_cropped = crop_to_central_region(original, border_fraction) proc_cropped = crop_to_central_region(processed, border_fraction) # Now compute SNR/MSE on that region signal_power = np.mean(orig_cropped**2) noise_power = np.mean((orig_cropped - proc_cropped)**2) mse_val = noise_power if noise_power <= 1e-30: # near-zero difference snr_val = float('inf') else: snr_val = 10 * np.log10(signal_power / noise_power) return snr_val, mse_val def resize_with_scipy_zoom(input_image, zoom_factors, degree, border_fraction): """ Resize using SciPy's zoom, then resize back and compute SNR/MSE *only on a central region* to avoid boundary artifacts. """ start_time = time.perf_counter() resized_image = zoom(input_image, zoom_factors, order=degree) time_elapsed = time.perf_counter() - start_time reverse_zoom_factors = 1.0 / np.array(zoom_factors) recovered_image = zoom(resized_image, reverse_zoom_factors, order=degree) # Compute SNR/MSE on central region snr, mse = compute_snr_and_mse_cropped(input_image, recovered_image, border_fraction) return resized_image, recovered_image, snr, mse, time_elapsed def resize_and_compute_metrics(input_image, method, degree, zoom_factors, border_fraction): """ Resize a 2D image using the specified method, then resize back to original size and compute SNR, MSE, and timing *only on a central region*. """ if np.isscalar(zoom_factors): zoom_factors = (zoom_factors, zoom_factors) if method == "scipy": return resize_with_scipy_zoom( input_image, zoom_factors, degree, border_fraction ) else: start_time = time.perf_counter() resized_image = resize( data=input_image, zoom_factors=zoom_factors, degree=degree, method=method ) time_elapsed = time.perf_counter() - start_time # Resize back to original shape: original_shape = input_image.shape recovered_image = resize( data=resized_image, output_size=original_shape, degree=degree, method=method ) # Compute SNR/MSE on central region snr, mse = compute_snr_and_mse_cropped(input_image, recovered_image, border_fraction) return resized_image, recovered_image, snr, mse, time_elapsed .. GENERATED FROM PYTHON SOURCE LINES 135-142 Plot Helpers ------------ We define three plotting helpers. 1) plot_resized_image(): Show the resized 2D image 2) plot_recovered_image(): Show the image after resizing back 3) plot_difference_image(): Show the difference (original - recovered) .. GENERATED FROM PYTHON SOURCE LINES 142-235 .. code-block:: Python def plot_resized_image(original, resized, method, zoom_factors, time_elapsed): """ Display the resized 2D image. If any zoom factor < 1, we place the resized image on a white canvas matching the original shape. """ zoom_out = any(zf < 1.0 for zf in zoom_factors) # Convert images to 0..255 for visualization def to_uint8(arr): arr_min, arr_max = arr.min(), arr.max() if arr_max > arr_min: arr_scaled = (arr - arr_min) / (arr_max - arr_min) else: arr_scaled = arr * 0.0 return (arr_scaled * 255).astype(np.uint8) orig_8 = to_uint8(original) resized_8 = to_uint8(resized) if zoom_out: canvas_8 = np.full_like(orig_8, 255, dtype=np.uint8) # white canvas rh, rw = resized_8.shape canvas_8[:rh, :rw] = resized_8 resized_display = canvas_8 else: resized_display = resized_8 plt.figure(figsize=(5, 5)) plt.imshow(resized_display, cmap='gray', aspect='equal') plt.title( f"{method.capitalize()} Resized\n" f"Zoom: {zoom_factors}, Time: {time_elapsed:.4f}s" ) plt.axis('off') plt.show() def plot_recovered_image(recovered): """ Display the recovered image after resizing back to the original shape. """ plt.figure(figsize=(6, 5)) plt.imshow(recovered, cmap='gray', aspect='equal') plt.title("Recovered Image") plt.axis('off') plt.show() from mpl_toolkits.axes_grid1 import make_axes_locatable def plot_difference_image(original, recovered, snr, mse): """ Display the difference (original - recovered) with a colorbar that fits the image height and preserves aspect ratio. The difference is shown in the *original numeric range*, not uint8, so the colorbar reflects the actual difference scale. Color scale is fixed to [-0.8, +0.8] for consistency across plots. """ difference = original - recovered h, w = difference.shape # shape of the difference image # Compute aspect ratio (height / width). aspect_ratio = h / float(w) # Choose a reference figure width and derive the figure height # to preserve the aspect ratio. Adjust fig_width as needed. fig_width = 6.0 fig_height = fig_width * aspect_ratio fig, ax = plt.subplots(figsize=(fig_width, fig_height)) im = ax.imshow( difference, cmap='bwr', aspect='equal', # ensure each pixel is square vmin=-0.8, vmax=0.8 ) ax.set_title(f"Difference\nSNR: {snr:.2f} dB, MSE: {mse:.2e}") ax.axis('off') # Use make_axes_locatable to create a colorbar axis matching the image height divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) # colorbar is 5% width, 0.05 pad cb = plt.colorbar(im, cax=cax) cb.set_label('Difference (units)') plt.tight_layout() plt.show() .. GENERATED FROM PYTHON SOURCE LINES 236-241 Load and Normalize an Image --------------------------- Here, we load an example image from an online repository. We convert it to grayscale in [0, 1]. .. GENERATED FROM PYTHON SOURCE LINES 241-269 .. code-block:: Python url = 'https://people.math.sc.edu/Burkardt/data/tif/columns.tif' response = requests.get(url) img = Image.open(BytesIO(response.content)) data = np.array(img, dtype=np.float64) # Convert to [0..1] input_image_normalized = data / 255.0 # Convert to grayscale via simple weighting input_image_normalized = ( input_image_normalized[:, :, 0] * 0.2989 + # Red channel input_image_normalized[:, :, 1] * 0.5870 + # Green channel input_image_normalized[:, :, 2] * 0.1140 # Blue channel ) degree = 3 zoom_factors_2d = (0.25, 0.25) border_fraction = 0.3 # We plot the original grayscale image. plt.figure(figsize=(6, 5)) plt.imshow(input_image_normalized, cmap='gray', aspect='equal') plt.title("Original Image") plt.axis("off") plt.show() .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_001.png :alt: Original Image :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 270-274 SciPy Interpolation ------------------- For comparison purposes, we also use the SciPy zoom method for resizing. .. GENERATED FROM PYTHON SOURCE LINES 274-289 .. code-block:: Python ( resized_2d_scipy, recovered_2d_scipy, snr_2d_scipy, mse_2d_scipy, time_2d_scipy ) = resize_and_compute_metrics( input_image_normalized, method="scipy", degree=degree, zoom_factors=zoom_factors_2d, border_fraction=border_fraction ) .. GENERATED FROM PYTHON SOURCE LINES 290-294 Resized Image ~~~~~~~~~~~~~ We plot the resized image with SciPy interpolation. .. GENERATED FROM PYTHON SOURCE LINES 294-303 .. code-block:: Python plot_resized_image( original=input_image_normalized, resized=resized_2d_scipy, method="scipy", zoom_factors=zoom_factors_2d, time_elapsed=time_2d_scipy ) .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_002.png :alt: Scipy Resized Zoom: (0.25, 0.25), Time: 0.0074s :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 304-308 Recovered Image ~~~~~~~~~~~~~~~ We plot the recovered image after a reversing of the zoom factors. .. GENERATED FROM PYTHON SOURCE LINES 308-311 .. code-block:: Python plot_recovered_image(recovered_2d_scipy) .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_003.png :alt: Recovered Image :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_003.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 312-316 Difference Image ~~~~~~~~~~~~~~~~ Display the difference image (original - recovered) with colorbar. .. GENERATED FROM PYTHON SOURCE LINES 316-324 .. code-block:: Python plot_difference_image( original=input_image_normalized, recovered=recovered_2d_scipy, snr=snr_2d_scipy, mse=mse_2d_scipy ) .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_004.png :alt: Difference SNR: 20.62 dB, MSE: 8.45e-04 :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_004.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 325-329 Trivial Interpolation --------------------- We use our standard interpolation method. .. GENERATED FROM PYTHON SOURCE LINES 329-344 .. code-block:: Python ( resized_2d_interp, recovered_2d_interp, snr_2d_interp, mse_2d_interp, time_2d_interp ) = resize_and_compute_metrics( input_image_normalized, method="interpolation", degree=degree, zoom_factors=zoom_factors_2d, border_fraction=border_fraction ) .. GENERATED FROM PYTHON SOURCE LINES 345-349 Resized Image ~~~~~~~~~~~~~ We plot the resized image with standard interpolation. .. GENERATED FROM PYTHON SOURCE LINES 349-358 .. code-block:: Python plot_resized_image( original=input_image_normalized, resized=resized_2d_interp, method="interpolation", zoom_factors=zoom_factors_2d, time_elapsed=time_2d_interp ) .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_005.png :alt: Interpolation Resized Zoom: (0.25, 0.25), Time: 0.0139s :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_005.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 359-363 Recovered Image ~~~~~~~~~~~~~~~ We plot the recovered image after a reversing of the zoom factors. .. GENERATED FROM PYTHON SOURCE LINES 363-366 .. code-block:: Python plot_recovered_image(recovered_2d_interp) .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_006.png :alt: Recovered Image :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_006.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 367-371 Difference image ~~~~~~~~~~~~~~~~ Display the difference image (original - recovered) with colorbar. .. GENERATED FROM PYTHON SOURCE LINES 371-379 .. code-block:: Python plot_difference_image( original=input_image_normalized, recovered=recovered_2d_interp, snr=snr_2d_interp, mse=mse_2d_interp ) .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_007.png :alt: Difference SNR: 20.62 dB, MSE: 8.45e-04 :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_007.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 380-388 Difference with SciPy ~~~~~~~~~~~~~~~~~~~~~ Now we compute the difference between the recovered image from the trivial interpolation and the SciPy interpolation. We also compute SNR and MSE on the central region and display them. Because they are nearly identical, we conclude that the two interpolation methods produce the same results. .. GENERATED FROM PYTHON SOURCE LINES 388-400 .. code-block:: Python snr_scipy_vs_interp, mse_scipy_vs_interp = compute_snr_and_mse_cropped( recovered_2d_scipy, recovered_2d_interp, border_fraction ) plot_difference_image( original=recovered_2d_scipy, recovered=recovered_2d_interp, snr=snr_scipy_vs_interp, mse=mse_scipy_vs_interp ) .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_008.png :alt: Difference SNR: inf dB, MSE: 1.39e-31 :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_008.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 401-406 Alternative with TensorSpline ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ As an alternative, we can replicate the same interpolation manually using the ``TensorSpline`` class, which underpins the `resize()` function behind the scene. .. GENERATED FROM PYTHON SOURCE LINES 406-463 .. code-block:: Python from splineops.interpolate.tensorspline import TensorSpline # 1) Build uniform coordinate arrays that match the shape of 'input_image_normalized' height, width = input_image_normalized.shape x_coords = np.linspace(0, height - 1, height) y_coords = np.linspace(0, width - 1, width) coordinates_2d = (x_coords, y_coords) # 2) For "cubic interpolation", pick "bspline3". # For boundary handling, we can pick "mirror", "zero", etc. ts = TensorSpline( data=input_image_normalized, coordinates=coordinates_2d, bases="bspline3", # cubic B-splines modes="mirror" # handles boundaries with mirroring ) # 3) Define new coordinate grids for the "zoomed" shape. zoomed_height = int(height * zoom_factors_2d[0]) zoomed_width = int(width * zoom_factors_2d[1]) x_coords_zoomed = np.linspace(0, height - 1, zoomed_height) y_coords_zoomed = np.linspace(0, width - 1, zoomed_width) coords_zoomed_2d = (x_coords_zoomed, y_coords_zoomed) # Evaluate (forward pass): zoom in or out resized_direct_ts = ts(coordinates=coords_zoomed_2d) # 4) Define coordinate grids for returning to the original shape x_coords_orig = np.linspace(0, height - 1, height) y_coords_orig = np.linspace(0, width - 1, width) coords_orig_2d = (x_coords_orig, y_coords_orig) # Evaluate (backward pass): from zoomed shape back to original ts_zoomed = TensorSpline( data=resized_direct_ts, coordinates=coords_zoomed_2d, bases="bspline3", modes="mirror" ) recovered_direct_ts = ts_zoomed(coordinates=coords_orig_2d) # Now, resized_direct_ts / recovered_direct_ts should be very similar # to 'resized_2d_interp' / 'recovered_2d_interp' from the high-level "resize()" approach. # Let's compute MSE to confirm: mse_forward = np.mean((resized_direct_ts - resized_2d_interp) ** 2) mse_backward = np.mean((recovered_direct_ts - recovered_2d_interp) ** 2) print(f"MSE (TensorSpline vs. resize()) resized: {mse_forward:.6e}") print(f"MSE (TensorSpline vs. resize()) recovered: {mse_backward:.6e}") .. rst-class:: sphx-glr-script-out .. code-block:: none MSE (TensorSpline vs. resize()) resized: 0.000000e+00 MSE (TensorSpline vs. resize()) recovered: 1.133506e-30 .. GENERATED FROM PYTHON SOURCE LINES 464-468 Least-Squares Projection ------------------------ We use the least-squares projection method. .. GENERATED FROM PYTHON SOURCE LINES 468-483 .. code-block:: Python ( resized_2d_ls, recovered_2d_ls, snr_2d_ls, mse_2d_ls, time_2d_ls ) = resize_and_compute_metrics( input_image_normalized, method="least-squares", degree=degree, zoom_factors=zoom_factors_2d, border_fraction=border_fraction ) .. GENERATED FROM PYTHON SOURCE LINES 484-488 Resized Image ~~~~~~~~~~~~~ We plot the resized image with least-squares projection method. .. GENERATED FROM PYTHON SOURCE LINES 488-497 .. code-block:: Python plot_resized_image( original=input_image_normalized, resized=resized_2d_ls, method="least-squares", zoom_factors=zoom_factors_2d, time_elapsed=time_2d_ls ) .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_009.png :alt: Least-squares Resized Zoom: (0.25, 0.25), Time: 1.1896s :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_009.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 498-502 Recovered Image ~~~~~~~~~~~~~~~ We plot the recovered image after reversing zoom factors. .. GENERATED FROM PYTHON SOURCE LINES 502-505 .. code-block:: Python plot_recovered_image(recovered_2d_ls) .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_010.png :alt: Recovered Image :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_010.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 506-510 Difference Image ~~~~~~~~~~~~~~~~ Display the difference image (original - recovered) with colorbar. .. GENERATED FROM PYTHON SOURCE LINES 510-518 .. code-block:: Python plot_difference_image( original=input_image_normalized, recovered=recovered_2d_ls, snr=snr_2d_ls, mse=mse_2d_ls ) .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_011.png :alt: Difference SNR: 22.52 dB, MSE: 5.45e-04 :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_011.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 519-523 Oblique Projection ------------------ We use the oblique-projection method. .. GENERATED FROM PYTHON SOURCE LINES 523-538 .. code-block:: Python ( resized_2d_ob, recovered_2d_ob, snr_2d_ob, mse_2d_ob, time_2d_ob ) = resize_and_compute_metrics( input_image_normalized, method="oblique", degree=degree, zoom_factors=zoom_factors_2d, border_fraction=border_fraction ) .. GENERATED FROM PYTHON SOURCE LINES 539-543 Resized Image ~~~~~~~~~~~~~ We plot the resized image with the oblique-projection method. .. GENERATED FROM PYTHON SOURCE LINES 543-552 .. code-block:: Python plot_resized_image( original=input_image_normalized, resized=resized_2d_ob, method="oblique", zoom_factors=zoom_factors_2d, time_elapsed=time_2d_ob ) .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_012.png :alt: Oblique Resized Zoom: (0.25, 0.25), Time: 0.9304s :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_012.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 553-557 Recovered Image ~~~~~~~~~~~~~~~ We plot the recovered image after a reversing of the zoom factors. .. GENERATED FROM PYTHON SOURCE LINES 557-560 .. code-block:: Python plot_recovered_image(recovered_2d_ob) .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_013.png :alt: Recovered Image :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_013.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 561-565 Difference Image ~~~~~~~~~~~~~~~~ Display the difference image (original - recovered) with colorbar. .. GENERATED FROM PYTHON SOURCE LINES 565-573 .. code-block:: Python plot_difference_image( original=input_image_normalized, recovered=recovered_2d_ob, snr=snr_2d_ob, mse=mse_2d_ob ) .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_014.png :alt: Difference SNR: 22.44 dB, MSE: 5.55e-04 :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_014.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 574-578 Comparison ---------- We compare the performance of the different methods being analyzed. .. GENERATED FROM PYTHON SOURCE LINES 580-584 Comparison Table ~~~~~~~~~~~~~~~~ We print the SNR, MSE, and timing data for each method. .. GENERATED FROM PYTHON SOURCE LINES 584-603 .. code-block:: Python methods = [ ("SciPy Interpolation", snr_2d_scipy, mse_2d_scipy, time_2d_scipy), ("Trivial Interpolation", snr_2d_interp, mse_2d_interp, time_2d_interp), ("Least-Squares Projection", snr_2d_ls, mse_2d_ls, time_2d_ls), ("Oblique Projection", snr_2d_ob, mse_2d_ob, time_2d_ob), ] # Print the table header using the same widths as we'll use for data header_line = f"{'Method':<25} {'SNR (dB)':>10} {'MSE':>16} {'Time (s)':>12}" print(header_line) print("-" * len(header_line)) # or manually set a dash length, e.g. 67 # Now print each row with the matching format for method_name, snr_val, mse_val, time_val in methods: row_line = f"{method_name:<25} {snr_val:>10.2f} {mse_val:>16.2e} {time_val:>12.4f}" print(row_line) .. rst-class:: sphx-glr-script-out .. code-block:: none Method SNR (dB) MSE Time (s) ------------------------------------------------------------------ SciPy Interpolation 20.62 8.45e-04 0.0074 Trivial Interpolation 20.62 8.45e-04 0.0139 Least-Squares Projection 22.52 5.45e-04 1.1896 Oblique Projection 22.44 5.55e-04 0.9304 .. GENERATED FROM PYTHON SOURCE LINES 604-613 Comparison Plot ~~~~~~~~~~~~~~~ Here, we compare how standard interpolation, least-squares, and oblique projection perform (in terms of SNR) across multiple zoom factors in [0.05, 0.9]. For each method at each zoom factor, we compute the SNR between the recovered image and the original, and plot the results on a single y-axis. Note that we don't compare with Scipy interpolation as it virtually gives the same values as the trivial interpolation. .. GENERATED FROM PYTHON SOURCE LINES 613-670 .. code-block:: Python zoom_values = np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.7, 0.9]) snr_scipy_list = [] snr_ls_list = [] snr_ob_list = [] for z in zoom_values: # Interpolation _, recovered_scipy, snr_scipy_z, _, _ = resize_and_compute_metrics( input_image_normalized, method="interpolation", degree=degree, zoom_factors=z, border_fraction=border_fraction ) snr_scipy_list.append(snr_scipy_z) # Least-Squares _, recovered_ls, snr_ls_z, _, _ = resize_and_compute_metrics( input_image_normalized, method="least-squares", degree=degree, zoom_factors=z, border_fraction=border_fraction ) snr_ls_list.append(snr_ls_z) # Oblique _, recovered_ob, snr_ob_z, _, _ = resize_and_compute_metrics( input_image_normalized, method="oblique", degree=degree, zoom_factors=z, border_fraction=border_fraction ) snr_ob_list.append(snr_ob_z) # Now we plot SNR in the same figure fig, ax1 = plt.subplots(figsize=(7, 5)) # Plot SNR (dB) p1 = ax1.plot(zoom_values, snr_scipy_list, 'bo-', label='Trivial SNR (dB)') p2 = ax1.plot(zoom_values, snr_ls_list, 'go-', label='LS SNR (dB)') p3 = ax1.plot(zoom_values, snr_ob_list, 'ro-', label='Oblique SNR (dB)') # Set the reduction factor axis to log scale ax1.set_xscale('log') ax1.set_xlabel('Reduction factor (log scale)') ax1.set_ylabel('SNR (dB)') ax1.set_title('Trivial, Least-Squares, and Oblique interpolation\nSNR vs. Reduction Factor') ax1.legend(loc='best') plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_003_interpolate_2D_images_015.png :alt: Trivial, Least-Squares, and Oblique interpolation SNR vs. Reduction Factor :srcset: /auto_examples/images/sphx_glr_003_interpolate_2D_images_015.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (1 minutes 11.749 seconds) .. _sphx_glr_download_auto_examples_003_interpolate_2D_images.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: binder-badge .. image:: images/binder_badge_logo.svg :target: https://mybinder.org/v2/gh/splineops/splineops.github.io/main?urlpath=lab/tree/notebooks_binder/auto_examples/003_interpolate_2D_images.ipynb :alt: Launch binder :width: 150 px .. container:: lite-badge .. image:: images/jupyterlite_badge_logo.svg :target: ../lite/lab/index.html?path=auto_examples/003_interpolate_2D_images.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: 003_interpolate_2D_images.ipynb <003_interpolate_2D_images.ipynb>` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: 003_interpolate_2D_images.py <003_interpolate_2D_images.py>` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: 003_interpolate_2D_images.zip <003_interpolate_2D_images.zip>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_