# Examples from pyvista.ImageDataFilters.resample
# ===============================================

# Create a small 2D grayscale image with dimensions `3 x 2` for demonstration.
import pyvista as pv
import numpy as np
from pyvista import examples
image = pv.ImageData(dimensions=(3, 2, 1))
image.point_data['data'] = np.linspace(0, 255, 6, dtype=np.uint8)

# Define a custom plotter to show the image. Although the image data is defined
# as point data, we use `points_to_cells()` to display the image as
# `PIXEL` (or `VOXEL`) cells
# instead. Grayscale coloring is used and the camera is adjusted to fit the image.
def image_plotter(image: pv.ImageData, clim=(0, 255)) -> pv.Plotter:
    pl = pv.Plotter()
    image = image.points_to_cells()
    pl.add_mesh(
        image,
        lighting=False,
        show_edges=True,
        cmap='grey',
        clim=clim,
        show_scalar_bar=False,
        line_width=3,
    )
    pl.view_xy()
    pl.camera.tight()
    pl.enable_anti_aliasing()
    return pl

# Show the image.
plot = image_plotter(image)
plot.show()

# Use `sample_rate` to up-sample the image. `'nearest'` interpolation is
# used by default.
upsampled = image.resample(sample_rate=2.0)
plot = image_plotter(upsampled)
plot.show()

# Use `'linear'` interpolation. Note that the argument names `sample_rate`
# and `interpolation` may be omitted.
upsampled = image.resample(2.0, 'linear')
plot = image_plotter(upsampled)
plot.show()

# Use `'cubic'` interpolation. Here we also specify the output
# `dimensions` explicitly instead of using `sample_rate`.
upsampled = image.resample(dimensions=(6, 4, 1), interpolation='cubic')
plot = image_plotter(upsampled)
plot.show()

# Compare the relative physical size of the image before and after resampling.
image

upsampled

# Note that the upsampled `dimensions` are doubled and
# the `spacing` is halved (as expected). Also note,
# however, that the physical bounds of the input differ from the output.
# The upsampled `origin` also differs:
image.origin
upsampled.origin

# This is because the resampling is done with `extend_border` enabled by default
# which adds a half cell-width border to the image and adjusts the origin and
# spacing such that the bounds match when the image is represented as cells.
# Apply `points_to_cells()` to the input and resampled images and show that
# the bounds match.
image_as_cells = image.points_to_cells()
image_as_cells.bounds

upsampled_as_cells = upsampled.points_to_cells()
upsampled_as_cells.bounds

# Plot the two images together as wireframe to visualize them. The original is in
# red, and the resampled image is in black.
pl = pv.Plotter()
_ = pl.add_mesh(
    image_as_cells, style='wireframe', color='red', line_width=10
)
_ = pl.add_mesh(
    upsampled_as_cells, style='wireframe', color='black', line_width=2
)
pl.view_xy()
pl.camera.tight()
pl.show()

# Disable `extend_border` to force the input and output bounds of the points
# to be the same instead.
upsampled = image.resample(sample_rate=2, extend_border=False)

# Compare the two images again.
image

upsampled

# This time the input and output bounds match without any further processing.
# Like before, the dimensions have doubled; unlike before, however, the spacing is
# not halved, but is instead smaller than half which is necessary to ensure the
# bounds remain the same. Also unlike before, the origin is unaffected:
image.origin
upsampled.origin

# All the above examples are with 2D images with point data. However, the filter
# also works with 3D volumes and will also work with cell data.
# Convert the 2D image with point data into a 3D volume with cell data and plot
# it for context.
volume = image.points_to_cells(dimensionality='3D')
volume.plot(show_edges=True, cmap='grey')

# Up-sample the volume. Set the sampling rate for each axis separately.
resampled = volume.resample(sample_rate=(3.0, 2.0, 1.0))
resampled.plot(show_edges=True, cmap='grey')

# Alternatively, we could have set the dimensions explicitly. Since we want
# `9 x 4 x 1` cells along the x-y-z axes (respectively), we set the dimensions
# to `(10, 5, 2)`, i.e. one more than the desired number of cells.
resampled = volume.resample(dimensions=(10, 5, 2))
resampled.plot(show_edges=True, cmap='grey')

# Compare the bounds before and after resampling. Unlike with point data, the
# bounds are not (and cannot be) extended.
volume.bounds
resampled.bounds

# Use a reference image to control the resampling instead. Here we load two
# images with different dimensions:
# `download_bird()` and
# `download_gourds()`.
bird = examples.download_bird()
bird.dimensions

gourds = examples.download_gourds()
gourds.dimensions

# Use `reference_image` to resample the bird to match the gourds geometry or
# vice-versa.
bird_resampled = bird.resample(reference_image=gourds)
bird_resampled.dimensions

gourds_resampled = gourds.resample(reference_image=bird)
gourds_resampled.dimensions

# Downsample the gourds image to 1/10th its original resolution using `'lanczos'`
# interpolation.
downsampled = gourds.resample(1 / 8, 'lanczos')
downsampled.dimensions

# Compare the downsampled image to the original and zoom in to show detail.
def compare_images_plotter(image1, image2):
    pl = pv.Plotter(shape=(1, 2))
    _ = pl.add_mesh(image1, rgba=True, show_edges=False, lighting=False)
    pl.subplot(0, 1)
    _ = pl.add_mesh(image2, rgba=True, show_edges=False, lighting=False)
    pl.link_views()
    pl.view_xy()
    pl.camera.zoom(3.0)
    return pl

pl = compare_images_plotter(gourds, downsampled)
pl.show()

# Note that downsampling can create image artifacts caused by aliasing. Enable
# anti-aliasing to smooth the image before resampling.
downsampled2 = gourds.resample(1 / 8, 'lanczos', anti_aliasing=True)

# Compare down-sampling with aliasing (left) to without aliasing (right).
pl = compare_images_plotter(downsampled, downsampled2)
pl.show()

# Load an MRI of a knee and downsample it.
knee = pv.examples.download_knee().resample(
    0.1, 'linear', anti_aliasing=True
)

# Crop and plot it.
knee = knee.crop(normalized_bounds=[0.2, 0.8, 0.2, 0.8, 0.0, 1.0])
vmin = knee.active_scalars.min()
vmax = knee.active_scalars.max()
pl = image_plotter(knee, clim=[vmin, vmax])
pl.show()

# Upsample it with B-spline interpolation. The interpolation is very smooth.
upsampled = knee.resample(2.0, 'bspline', border_mode='clamp')
pl = image_plotter(upsampled, clim=[vmin, vmax])
pl.show()

# Use the `'wrap'` border mode. Note how points at the border are brighter than previously,
# since the bright pixels from the opposite edge are now included in the interpolation.
upsampled = knee.resample(2.0, 'bspline', border_mode='wrap')
pl = image_plotter(upsampled, clim=[vmin, vmax])
pl.show()

# Compare B-spline interpolation to `'hamming'`.
upsampled = knee.resample(2.0, 'hamming')
pl = image_plotter(upsampled, clim=[vmin, vmax])
pl.show()

# ----------------------------------------------------------------------
# Generated by sphinx-examples-as-code https://github.com/pyvista/sphinx-examples-as-code

