pyvista.ImageDataFilters.resample

pyvista.ImageDataFilters.resample#

ImageDataFilters.resample(
sample_rate: float | VectorLike[float] | None = None,
interpolation: Literal['nearest', 'linear', 'cubic', 'lanczos', 'hamming', 'blackman'] = 'nearest',
*,
reference_image: ImageData | None = None,
dimensions: VectorLike[int] | None = None,
anti_aliasing: bool = False,
extend_border: bool | None = None,
scalars: str | None = None,
preference: Literal['point', 'cell'] = 'point',
inplace: bool = False,
progress_bar: bool = False,
)[source]#

Resample the image to modify its dimensions and spacing.

The resampling can be controlled in several ways:

  1. Specify the output geometry using a reference_image.

  2. Specify the dimensions explicitly.

  3. Specify the sample_rate explicitly.

Use reference_image for full control of the resampled geometry. For all other options, the geometry is implicitly defined such that the resampled image fits the bounds of the input.

This filter may be used to resample either point or cell data. For point data, this filter assumes the data is from discrete samples in space which represent pixels or voxels; the resampled bounds are therefore extended by 1/2 voxel spacing by default though this may be disabled.

Note

Singleton dimensions are not resampled by this filter, e.g. 2D images will remain 2D.

Added in version 0.45.

Parameters:
sample_ratefloat | VectorLike[float], optional

Sampling rate(s) to use. Can be a single value or vector of three values for each axis. Values greater than 1.0 will up-sample the axis and values less than 1.0 will down-sample it. Values must be greater than 0.

interpolation‘nearest’ | ‘linear’ | ‘cubic’, ‘lanczos’, ‘hamming’, ‘blackman’, default: ‘nearest’

Interpolation mode to use. By default, 'nearest' is used which duplicates (if upsampling) or removes (if downsampling) values but does not modify them. The 'linear' and 'cubic' modes use linear and cubic interpolation, respectively, and may modify the values. The 'lanczos', 'hamming', and 'blackman' use a windowed sinc filter and may be used to preserve sharp details and/or reduce image artifacts.

Note

  • use 'nearest' for pixel art or categorical data such as segmentation masks

  • use 'linear' for speed-critical tasks

  • use 'cubic' for upscaling or general-purpose resampling

  • use 'lanczos' for high-detail downsampling (at the cost of some ringing)

  • use 'blackman' for minimizing ringing artifacts (at the cost of some detail)

  • use 'hamming' for a balance between detail-preservation and reducing ringing

reference_imageImageData, optional

Reference image to use. If specified, the input is resampled to match the geometry of the reference. The dimensions, spacing, origin, offset, and direction_matrix of the resampled image will all match the reference image.

dimensionsVectorLike[int]

Set the output dimensions of the resampled image.

Note

Dimensions is the number of points along each axis. If resampling cell data, each dimension should be one more than the number of desired output cells (since there are N cells and N+1 points along each axis). See examples.

anti_aliasingbool, default: False

Enable antialiasing. This will blur the image as part of the resampling to reduce image artifacts when down-sampling. Has no effect when up-sampling.

extend_borderbool, optional

Extend the apparent input border by approximately half the spacing. If enabled, the bounds of the resampled points will be larger than the input image bounds. Enabling this option also has the effect that the re-sampled spacing will directly correlate with the resampled dimensions, e.g. if the dimensions are doubled the spacing will be halved. See examples.

This option is enabled by default when resampling point data. Has no effect when resampling cell data or when a reference_image is provided.

scalarsstr, optional

Name of scalars to resample. Defaults to currently active scalars.

preferencestr, default: ‘point’

When scalars is specified, this is the preferred array type to search for in the dataset. Must be either 'point' or 'cell'.

inplacebool, default: False

If True, resample the image inplace. By default, a new ImageData instance is returned.

progress_barbool, default: False

Display a progress bar to indicate progress.

Returns:
ImageData

Resampled image.

See also

sample()

Resample array data from one mesh onto another.

interpolate()

Interpolate values from one mesh onto another.

Image Data Representations

Compare images represented as points vs. cells.

Examples

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 uses 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) -> pv.Plotter:
...     pl = pv.Plotter()
...     image = image.points_to_cells()
...     pl.add_mesh(
...         image,
...         lighting=False,
...         show_edges=True,
...         cmap='grey',
...         show_scalar_bar=False,
...     )
...     pl.view_xy()
...     pl.camera.tight()
...     return pl

Show the image.

>>> plot = image_plotter(image)
>>> plot.show()
../../../_images/pyvista-ImageDataFilters-resample-1_00_00.png

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()
../../../_images/pyvista-ImageDataFilters-resample-1_01_00.png

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()
../../../_images/pyvista-ImageDataFilters-resample-1_02_00.png

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()
../../../_images/pyvista-ImageDataFilters-resample-1_03_00.png

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

>>> image
ImageData (...)
  N Cells:      2
  N Points:     6
  X Bounds:     0.000e+00, 2.000e+00
  Y Bounds:     0.000e+00, 1.000e+00
  Z Bounds:     0.000e+00, 0.000e+00
  Dimensions:   3, 2, 1
  Spacing:      1.000e+00, 1.000e+00, 1.000e+00
  N Arrays:     1
>>> upsampled
ImageData (...)
  N Cells:      15
  N Points:     24
  X Bounds:     -2.500e-01, 2.250e+00
  Y Bounds:     -2.500e-01, 1.250e+00
  Z Bounds:     0.000e+00, 0.000e+00
  Dimensions:   6, 4, 1
  Spacing:      5.000e-01, 5.000e-01, 1.000e+00
  N Arrays:     1

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
(0.0, 0.0, 0.0)
>>> upsampled.origin
(-0.25, -0.25, 0.0)

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
BoundsTuple(x_min=-0.5, x_max=2.5, y_min=-0.5, y_max=1.5, z_min=0.0, z_max=0.0)
>>> upsampled_as_cells = upsampled.points_to_cells()
>>> upsampled_as_cells.bounds
BoundsTuple(x_min=-0.5, x_max=2.5, y_min=-0.5, y_max=1.5, z_min=0.0, z_max=0.0)

Plot the two images together as wireframe to visualize them. The original is in red, and the resampled image is in black.

>>> plt = pv.Plotter()
>>> _ = plt.add_mesh(
...     image_as_cells, style='wireframe', color='red', line_width=10
... )
>>> _ = plt.add_mesh(
...     upsampled_as_cells, style='wireframe', color='black', line_width=2
... )
>>> plt.view_xy()
>>> plt.camera.tight()
>>> plt.show()
../../../_images/pyvista-ImageDataFilters-resample-1_04_00.png

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
ImageData (...)
  N Cells:      2
  N Points:     6
  X Bounds:     0.000e+00, 2.000e+00
  Y Bounds:     0.000e+00, 1.000e+00
  Z Bounds:     0.000e+00, 0.000e+00
  Dimensions:   3, 2, 1
  Spacing:      1.000e+00, 1.000e+00, 1.000e+00
  N Arrays:     1
>>> upsampled
ImageData (...)
  N Cells:      15
  N Points:     24
  X Bounds:     0.000e+00, 2.000e+00
  Y Bounds:     0.000e+00, 1.000e+00
  Z Bounds:     0.000e+00, 0.000e+00
  Dimensions:   6, 4, 1
  Spacing:      4.000e-01, 3.333e-01, 1.000e+00
  N Arrays:     1

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 necessaru to ensure the bounds remain the same. Also unlike before, the origin is unaffected:

>>> image.origin
(0.0, 0.0, 0.0)
>>> upsampled.origin
(0.0, 0.0, 0.0)

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')
../../../_images/pyvista-ImageDataFilters-resample-1_05_00.png

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')
../../../_images/pyvista-ImageDataFilters-resample-1_06_00.png

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')
../../../_images/pyvista-ImageDataFilters-resample-1_07_00.png

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

>>> volume.bounds
BoundsTuple(x_min=-0.5, x_max=2.5, y_min=-0.5, y_max=1.5, z_min=-0.5, z_max=0.5)
>>> resampled.bounds
BoundsTuple(x_min=-0.5, x_max=2.5, y_min=-0.5, y_max=1.5, z_min=-0.5, z_max=0.5)

Use a reference image to control the resampling instead. Here we load two images with different dimensions: download_puppy() and download_gourds().

>>> puppy = examples.download_puppy()
>>> puppy.dimensions
(1600, 1200, 1)
>>> gourds = examples.download_gourds()
>>> gourds.dimensions
(640, 480, 1)

Use reference_image to resample the puppy to match the gourds geometry or vice-versa.

>>> puppy_resampled = puppy.resample(reference_image=gourds)
>>> puppy_resampled.dimensions
(640, 480, 1)
>>> gourds_resampled = gourds.resample(reference_image=puppy)
>>> gourds_resampled.dimensions
(1600, 1200, 1)

Downsample the puppy image to 1/10th its original resolution using 'lanczos' interpolation.

>>> downsampled = puppy.resample(0.1, 'lanczos')
>>> downsampled.dimensions
(160, 120, 1)

Compare the downsampled image to the original and zoom in to show detail.

>>> def compare_images_plotter(image1, image2):
...     plt = pv.Plotter(shape=(1, 2))
...     _ = plt.add_mesh(image1, rgba=True, show_edges=False, lighting=False)
...     plt.subplot(0, 1)
...     _ = plt.add_mesh(image2, rgba=True, show_edges=False, lighting=False)
...     plt.link_views()
...     plt.view_xy()
...     plt.camera.zoom(3.0)
...     return plt
>>> plt = compare_images_plotter(puppy, downsampled)
>>> plt.show()
../../../_images/pyvista-ImageDataFilters-resample-1_08_00.png

Note that downsampling can create image artifacts caused by aliasing. Enable anti-aliasing to smooth the image before resampling.

>>> downsampled2 = puppy.resample(0.1, 'lanczos', anti_aliasing=True)

Compare down-sampling with aliasing (left) to without aliasing (right).

>>> plt = compare_images_plotter(downsampled, downsampled2)
>>> plt.show()
../../../_images/pyvista-ImageDataFilters-resample-1_09_00.png