Imaging utils

Preprocessing

dpipe.im.preprocessing.normalize(x: ndarray, mean: bool = True, std: bool = True, percentiles: Optional[Union[float, Sequence[float]]] = None, axis: Optional[Union[int, Sequence[int]]] = None, dtype=None) ndarray[source]

Normalize x’s values to make mean and std independently along axes equal to 0 and 1 respectively (if specified).

Parameters
  • x

  • mean – whether to make mean == zero

  • std – whether to make std == 1

  • percentiles – if pair (a, b) - the percentiles between which mean and/or std will be estimated if scalar (s) - same as (s, 100 - s) if None - same as (0, 100).

  • axis – axes along which mean and/or std will be estimated independently. If None - the statistics will be estimated globally.

  • dtype – the dtype of the output.

dpipe.im.preprocessing.min_max_scale(x: ndarray, axis: Optional[Union[int, Sequence[int]]] = None) ndarray[source]

Scale x’s values so that its minimum and maximum become 0 and 1 respectively independently along axes.

dpipe.im.preprocessing.bytescale(x: ndarray) ndarray[source]

Scales x’s values so that its minimum and maximum become 0 and 255 respectively. Afterwards converts it to uint8.

dpipe.im.preprocessing.describe_connected_components(mask: ndarray, background: int = 0, drop_background: bool = True)[source]

Get the connected components of mask as well as their labels and volumes.

Parameters
  • mask

  • background – the label of the background. The pixels with this label will be marked as the background component (even if it is not connected).

  • drop_background – whether to exclude the background from the returned components’ descriptions.

Returns

  • labeled_mask – array of the same shape as mask.

  • labels – a list of labels from the labeled_mask. The background label is always 0. The labels are sorted according to their corresponding volumes.

  • volumes – a list of corresponding labels’ volumes.

dpipe.im.preprocessing.get_greatest_component(mask: ndarray, background: int = 0, drop_background: bool = True) ndarray[source]

Get the greatest connected component from mask. See describe_connected_components for details.

Shape operations

dpipe.im.shape_ops.zoom(x: ndarray, scale_factor: Union[float, Sequence[float]], axis: Optional[Union[int, Sequence[int]]] = None, order: int = 1, fill_value: Union[float, Callable] = 0, num_threads: int = -1, backend: Optional[Union[str, Backend, Type[Backend]]] = None) ndarray[source]

Rescale x according to scale_factor along the axis.

Uses a fast parallelizable implementation for fp32 / fp64 inputs, ndim <= 3 and order = 1.

Parameters
  • x

  • scale_factor

  • axis – axis along which the tensor will be scaled.

  • order – order of interpolation.

  • fill_value – value to fill past edges. If Callable (e.g. numpy.min) - fill_value(x) will be used.

  • num_threads – the number of threads to use for computation. Default = the cpu count.

  • backend – which backend to use. numba, cython and scipy are available, cython is used by default.

dpipe.im.shape_ops.zoom_to_shape(x: ndarray, shape: Union[int, Sequence[int]], axis: Optional[Union[int, Sequence[int]]] = None, order: int = 1, fill_value: Union[float, Callable] = 0, num_threads: int = -1, backend: Optional[Union[str, Backend, Type[Backend]]] = None) ndarray[source]

Rescale x to match shape along the axis.

Uses a fast parallelizable implementation for fp32 / fp64 inputs, ndim <= 3 and order = 1.

Parameters
  • x

  • shape – final shape.

  • axis – axes along which the tensor will be scaled.

  • order – order of interpolation.

  • fill_value – value to fill past edges. If Callable (e.g. numpy.min) - fill_value(x) will be used.

  • num_threads – the number of threads to use for computation. Default = the cpu count.

  • backend – which backend to use. numba, cython and scipy are available, cython is used by default.

dpipe.im.shape_ops.proportional_zoom_to_shape(x: ndarray, shape: Union[int, Sequence[int]], axis: Optional[Union[int, Sequence[int]]] = None, padding_values: Union[float, Sequence[float], Callable] = 0, order: int = 1) ndarray[source]

Proportionally rescale x to fit shape along axes then pad it to that shape. :param x: :param shape: final shape. :param axis: axes along which x will be padded. If None - the last len(shape) axes are used. :param padding_values: values to pad with. :param order: order of interpolation.

dpipe.im.shape_ops.crop_to_shape(x: ndarray, shape: Union[int, Sequence[int]], axis: Optional[Union[int, Sequence[int]]] = None, ratio: Union[float, Sequence[float]] = 0.5) ndarray[source]

Crop x to match shape along axes. :param x: :param shape: final shape. :param axis: axes along which x will be padded. If None - the last len(shape) axes are used. :param ratio: the fraction of the crop that will be applied to the left, 1 - ratio will be applied to the right.

dpipe.im.shape_ops.crop_to_box(x: ndarray, box: ndarray, axis: Optional[Union[int, Sequence[int]]] = None, padding_values: Optional[Union[float, Sequence[float]]] = None) ndarray[source]

Crop x according to box along axis.

dpipe.im.shape_ops.restore_crop(x: ndarray, box: ndarray, shape: Union[int, Sequence[int]], padding_values: Union[float, Sequence[float]] = 0) ndarray[source]

Pad x to match shape. The left padding is taken equal to box’s start.

dpipe.im.shape_ops.pad(x: ndarray, padding: Union[int, Sequence[int], Sequence[Sequence[int]]], axis: Optional[Union[int, Sequence[int]]] = None, padding_values: Union[float, Sequence[float], Callable] = 0) ndarray[source]

Pad x according to padding along the axes.

Parameters
  • x – tensor to pad.

  • padding – if 2D array [[start_1, stop_1], …, [start_n, stop_n]] - specifies individual padding for each axis from axis. The length of the array must either be equal to 1 or match the length of axis. If 1D array [val_1, …, val_n] - same as [[val_1, val_1], …, [val_n, val_n]]. If scalar (val) - same as [[val, val]].

  • padding_values – values to pad with, must be broadcastable to the resulting array. If Callable (e.g. numpy.min) - padding_values(x) will be used.

  • axis – axis along which x will be padded.

dpipe.im.shape_ops.pad_to_shape(x: ndarray, shape: Union[int, Sequence[int]], axis: Optional[Union[int, Sequence[int]]] = None, padding_values: Union[float, Sequence[float], Callable] = 0, ratio: Union[float, Sequence[float]] = 0.5) ndarray[source]

Pad x to match shape along the axis.

Parameters
  • x

  • shape – final shape.

  • padding_values – values to pad with. If Callable (e.g. numpy.min) - padding_values(x) will be used.

  • axis – axis along which x will be padded.

  • ratio – the fraction of the padding that will be applied to the left, 1.0 - ratio will be applied to the right. By default ratio=0.5, i.e. it is applied uniformly to the left and right.

dpipe.im.shape_ops.pad_to_divisible(x: ndarray, divisor: Union[int, Sequence[int]], axis: Optional[Union[int, Sequence[int]]] = None, padding_values: Union[float, Sequence[float], Callable] = 0, ratio: Union[float, Sequence[float]] = 0.5, remainder: Union[int, Sequence[int]] = 0)[source]

Pad x to be divisible by divisor along the axes.

Parameters
  • x

  • divisor – a value an incoming array should be divisible by.

  • remainderx will be padded such that its shape gives the remainder remainder when divided by divisor.

  • axis – axes along which the array will be padded. If None - the last len(divisor) axes are used.

  • padding_values – values to pad with. If Callable (e.g. numpy.min) - padding_values(x) will be used.

  • ratio – the fraction of the padding that will be applied to the left, 1 - ratio will be applied to the right.

References

pad_to_shape

Data augmentation

dpipe.im.augmentation.elastic_transform(x: ndarray, amplitude: float, axis: Optional[Union[int, Sequence[int]]] = None, order: int = 1)[source]

Apply a gaussian elastic distortion with a given amplitude to a tensor along the given axes.

Metrics

dpipe.im.metrics.dice_score(x: ndarray, y: ndarray) float[source]
dpipe.im.metrics.sensitivity(y_true, y_pred)[source]
dpipe.im.metrics.specificity(y_true, y_pred)[source]
dpipe.im.metrics.precision(y_true, y_pred)[source]
dpipe.im.metrics.recall(y_true, y_pred)[source]
dpipe.im.metrics.iou(x: ndarray, y: ndarray) float[source]
dpipe.im.metrics.assd(x, y, voxel_shape=None)[source]
dpipe.im.metrics.hausdorff_distance(x, y, voxel_shape=None)[source]
dpipe.im.metrics.cross_entropy_with_logits(target: ~numpy.ndarray, logits: ~numpy.ndarray, axis: int = 1, reduce: ~typing.Optional[~typing.Callable] = <function mean>)[source]

A numerically stable cross entropy for numpy arrays. target and logits must have the same shape except for axis.

Parameters
  • target – integer array of shape (d1, …, di, dj, …, dn)

  • logits – array of shape (d1, …, di, k, dj, …, dn)

  • axis – the axis containing the logits for each class: logits.shape[axis] == k

  • reduce – the reduction operation to be applied to the final loss. If None - no reduction will be performed.

dpipe.im.metrics.convert_to_aggregated(metrics: ~typing.Dict[str, ~typing.Callable], aggregate_fn: ~typing.Callable = <function mean>, key_prefix: str = '', key_suffix: str = '', *args, **kwargs)[source]
dpipe.im.metrics.to_aggregated(metric: ~typing.Callable, aggregate: ~typing.Callable = <function mean>, *args, **kwargs)[source]

Converts a metric that receives two values to a metric that receives two sequences and returns an aggregated value.

args and kwargs are passed as additional arguments ot aggregate.

Examples

>>> mean_dice = to_aggregated(dice_score)
>>> worst_dice = to_aggregated(dice_score, aggregate=np.min)
dpipe.im.metrics.fraction(numerator, denominator, empty_val: float = 1)[source]

Box

Functions to work with boxes: immutable numpy arrays of shape (2, n) which represent the coordinates of the upper left and lower right corners of an n-dimensional rectangle.

In slicing operations, as everywhere in Python, the left corner is inclusive, and the right one is non-inclusive.

dpipe.im.box.make_box_(iterable) ndarray[source]

Returns a box, generated inplace from the iterable. If iterable was a numpy array, will make it immutable and return.

dpipe.im.box.returns_box(func: Callable) Callable[source]

Returns function, decorated so that it returns a box.

dpipe.im.box.get_containing_box(shape: tuple) ndarray[source]

Returns box that contains complete array of shape shape.

dpipe.im.box.broadcast_box(box: ndarray, shape: tuple, dims: tuple) ndarray[source]

Returns box, such that it contains box across dims and whole array with shape shape across other dimensions.

dpipe.im.box.limit_box(box, limit) ndarray[source]

Returns a box, maximum subset of the input box so that start would be non-negative and stop would be limited by the limit.

dpipe.im.box.get_box_padding(box: ndarray, limit)[source]
Returns padding that is necessary to get box from array of shape limit.

Returns padding in numpy form, so it can be given to numpy.pad.

dpipe.im.box.add_margin(box: ndarray, margin) ndarray[source]

Returns a box with size increased by the margin (need to be broadcastable to the box) compared to the input box.

dpipe.im.box.get_centered_box(center: ndarray, box_size: ndarray) ndarray[source]

Get box of size box_size, centered in the center. If box_size is odd, center will be closer to the right.

dpipe.im.box.mask2bounding_box(mask: ndarray) ndarray[source]

Find the smallest box that contains all true values of the mask.

Grid splitters

Function for working with patches from tensors. See the Working with patches tutorial for more details.

dpipe.im.grid.get_boxes(shape: Union[int, Sequence[int]], box_size: Union[int, Sequence[int]], stride: Union[int, Sequence[int]], axis: Optional[Union[int, Sequence[int]]] = None, valid: bool = True) Iterable[ndarray][source]

Yield boxes appropriate for a tensor of shape shape in a convolution-like fashion.

Parameters
  • shape – the input tensor’s shape.

  • box_size

  • axis – axes along which the slices will be taken.

  • stride – the stride (step-size) of the slice.

  • valid – whether boxes of size smaller than box_size should be left out.

References

See the Working with patches tutorial for more details.

dpipe.im.grid.divide(x: ~numpy.ndarray, patch_size: ~typing.Union[int, ~typing.Sequence[int]], stride: ~typing.Union[int, ~typing.Sequence[int]], axis: ~typing.Optional[~typing.Union[int, ~typing.Sequence[int]]] = None, valid: bool = False, get_boxes: ~typing.Callable = <function get_boxes>) Iterable[ndarray][source]

A convolution-like approach to generating patches from a tensor.

Parameters
  • x

  • patch_size

  • axis – dimensions along which the slices will be taken.

  • stride – the stride (step-size) of the slice.

  • valid – whether patches of size smaller than patch_size should be left out.

  • get_boxes – function that yields boxes, for signature see get_boxes

References

See the Working with patches tutorial for more details.

dpipe.im.grid.combine(patches: ~typing.Iterable[~numpy.ndarray], output_shape: ~typing.Union[int, ~typing.Sequence[int]], stride: ~typing.Union[int, ~typing.Sequence[int]], axis: ~typing.Optional[~typing.Union[int, ~typing.Sequence[int]]] = None, valid: bool = False, combiner: ~typing.Type[~dpipe.im.grid.PatchCombiner] = <class 'dpipe.im.grid.Average'>, get_boxes: ~typing.Callable = <function get_boxes>) ndarray[source]

Build a tensor of shape output_shape from patches obtained in a convolution-like approach with corresponding parameters. The overlapping parts are aggregated using the strategy from combiner - Average by default.

References

See the Working with patches tutorial for more details.

class dpipe.im.grid.PatchCombiner(shape: Tuple[int, ...], dtype: dtype)[source]

Bases: object

update(box: ndarray, patch: ndarray)[source]
build() ndarray[source]
class dpipe.im.grid.Average(shape: Tuple[int, ...], dtype: dtype)[source]

Bases: PatchCombiner

update(box: ndarray, patch: ndarray)[source]
build()[source]

Patch

Tools for patch extraction and generation.

dpipe.im.patch.uniform(shape, random_state: Optional[RandomState] = None)[source]
dpipe.im.patch.sample_box_center_uniformly(shape, box_size: array, random_state: Optional[RandomState] = None)[source]

Returns the center of a sampled uniformly box of size box_size, contained in the array of shape shape.

dpipe.im.patch.get_random_patch(*arrays: ~numpy.ndarray, patch_size: ~typing.Union[int, ~typing.Sequence[int]], axis: ~typing.Optional[~typing.Union[int, ~typing.Sequence[int]]] = None, distribution: ~typing.Callable = <function uniform>)[source]

Get a random patch of size path_size along the axes for each of the arrays. The patch position is equal for all the arrays.

Parameters
  • arrays

  • patch_size

  • axis

  • distribution (Callable(shape)) – function that samples a random number in the range [0, n) for each axis. Defaults to a uniform distribution.

dpipe.im.patch.get_random_box(shape: ~typing.Union[int, ~typing.Sequence[int]], box_shape: ~typing.Union[int, ~typing.Sequence[int]], axis: ~typing.Union[int, ~typing.Sequence[int]] = None, distribution: ~typing.Callable = <function uniform>) ndarray[source]

Get a random box of shape box_shape that fits in the shape along the given axes.

Distributions

Module for calculation of various statistics given a discrete or piecewise-linear distribution.

dpipe.im.dist.weighted_sum(weights: Union[ndarray, torch.Tensor], axis: Union[int, Sequence[int]], values_range: Callable) Union[ndarray, torch.Tensor][source]

Calculates a weighted sum of values returned by values_range with the corresponding weights along a given axis.

Parameters
  • weights

  • axis

  • values_range – takes n as input and returns an array of n values where n = weights.shape[axis].

dpipe.im.dist.expectation(distribution: ~typing.Union[~numpy.ndarray, torch.Tensor], axis: int, integral: ~typing.Callable = <function polynomial>, *args, **kwargs) Union[ndarray, torch.Tensor][source]

Calculates the expectation of a function h given its integral and a distribution.

args and kwargs are passed to integral as additional arguments.

Parameters
  • distribution – the distribution by which the expectation will be calculated. Must sum to 1 along the axis.

  • axis – the axis along which the expectation is calculated.

  • integral – the definite integral of the function h. See polynomial for an example.

Notes

This function calculates the expectation by a piecewise-linear distribution in the range \([0, N]\) where N = distribution.shape[axis] + 1:

\[\mathbb{E}_F[h] = \int\limits_0^N h(x) dF(x) = \sum\limits_0^{N-1} \int\limits_i^{i+1} h(x) dF(x) = \sum\limits_0^{N-1} distribution_i \int\limits_i^{i+1} h(x) dx = \sum\limits_0^{N-1} distribution_i \cdot (H(i+1) - H(i)),\]

where \(distribution_i\) are taken along axis, \(H(i) = \int\limits_0^{i} h(x) dx\) are returned by integral.

References

polynomial

dpipe.im.dist.marginal_expectation(distribution: ~typing.Union[~numpy.ndarray, torch.Tensor], axis: ~typing.Union[int, ~typing.Sequence[int]], integrals: ~typing.Union[~typing.Callable, ~typing.Sequence[~typing.Callable]] = <function polynomial>, *args, **kwargs) list[source]

Computes expectations along the axis according to integrals independently.

args and kwargs are passed to integral as additional arguments.

dpipe.im.dist.polynomial(n: int, order=1) ndarray[source]

The definite integral for a polynomial function of a given order from 0 to n - 1.

Examples

>>> polynomial(10, 1) # x ** 2 / 2 from 0 to 9
array([ 0. ,  0.5,  2. ,  4.5,  8. , 12.5, 18. , 24.5, 32. , 40.5])

Slicing

dpipe.im.slices.iterate_slices(*data: ndarray, axis: int)[source]

Iterate over slices of a series of tensors along a given axis.

dpipe.im.slices.iterate_axis(x: ndarray, axis: int)[source]

Images visualization

dpipe.im.visualize.slice3d(*data: ndarray, axis: int = -1, scale: int = 5, max_columns: Optional[int] = None, colorbar: bool = False, show_axes: bool = False, cmap: Union[Colormap, str] = 'gray', vlim: Optional[Union[float, Sequence[float]]] = None, titles: Optional[Sequence[Optional[str]]] = None)[source]

Creates an interactive plot, simultaneously showing slices along a given axis for all the passed images.

Parameters
  • data

  • axis

  • scale – the figure scale.

  • max_columns – the maximal number of figures in a row. If None - all figures will be in the same row.

  • colorbar – Whether to display a colorbar.

  • show_axes – Whether to do display grid on the image.

  • cmap

  • vlim – used to normalize luminance data. If None - the limits are determined automatically. Must be broadcastable to (len(data), 2). See matplotlib.pyplot.imshow (vmin and vmax) for details.

dpipe.im.visualize.animate3d(*data: ndarray, output_path: Union[Path, str], axis: int = -1, scale: int = 5, max_columns: Optional[int] = None, colorbar: bool = False, show_axes: bool = False, cmap: str = 'gray', vlim=(None, None), fps: int = 30, writer: str = 'imagemagick', repeat: bool = True)[source]

Saves an animation to output_path, simultaneously showing slices along a given axis for all the passed images.

Parameters
  • data (np.ndarray) –

  • output_path (str) –

  • axis (int) –

  • scale (int) – the figure scale.

  • max_columns (int) – the maximal number of figures in a row. If None - all figures will be in the same row.

  • colorbar (bool) – Whether to display a colorbar. Works only if ``vlim``s are not None.

  • show_axes (bool) – Whether to do display grid on the image.

  • cmap – parameters passed to matplotlib.pyplot.imshow

  • vlim – parameters passed to matplotlib.pyplot.imshow

  • fps (int) –

  • writer (str) –

  • repeat (bool) – whether the animation should repeat when the sequence of frames is completed.

dpipe.im.visualize.default_clip(image, body_organ='Brain')[source]

Clips image (CT) pixels/voxels to ranges, typically used for different body organs.

Parameters

numpy.array (image -) –

:param : :param body_organ - str: possible values: Brain, Lungs :param : possible values: Brain, Lungs

Color space conversion

dpipe.im.hsv.hsv_image(hue, saturation, value)[source]

Creates image in HSV format from HSV data.

dpipe.im.hsv.rgb_from_hsv_data(hue, saturation, value)[source]

Creates image in RGB format from HSV data.

dpipe.im.hsv.gray_image_colored_mask(gray_image, mask, hue)[source]

Creates gray image with colored mask. Keeps intensities intact, so dark areas on gray image will be hard to see even after colorization.

dpipe.im.hsv.gray_image_bright_colored_mask(gray_image, mask, hue)[source]

Creates gray image with colored mask. Changes mask intensities, so dark areas on gray image will be easy to see after colorization.

dpipe.im.hsv.segmentation_probabilities(image, probabilities, hue)[source]
dpipe.im.hsv.masked_segmentation_probabilities(image, probabilities, hue, mask)[source]

Various utils

dpipe.im.utils.apply_along_axes(func: Callable, x: ndarray, axis: Union[int, Sequence[int]], *args, **kwargs)[source]

Apply func to slices from x taken along axes. args and kwargs are passed as additional arguments.

Notes

func must return an array of the same shape as it received.

dpipe.im.utils.build_slices(start: Sequence[int], stop: Optional[Sequence[int]] = None) Tuple[slice, ...][source]

Returns a tuple of slices built from start and stop.

Examples

>>> build_slices([1, 2, 3], [4, 5, 6])
(slice(1, 4), slice(2, 5), slice(3, 6))
>>> build_slices([10, 11])
(slice(10), slice(11))
dpipe.im.utils.composition(func: Callable, *args, **kwargs)[source]

Applies func to the output of the decorated function. args and kwargs are passed as additional positional and keyword arguments respectively.

dpipe.im.utils.get_mask_volume(mask: ndarray, *spacing: Union[float, Sequence[float]], location: bool = False) float[source]

Calculates the mask volume given its spatial spacing.

Parameters
  • mask

  • spacing – each value represents the spacing for the corresponding axis. If float - the values are uniformly spaced along this axis. If Sequence[float] - the values are non-uniformly spaced.

  • location – whether to interpret the Sequence[float] in spacing as values’ locations or spacings. If True - the deltas are used as spacings.

Shape utils

dpipe.im.shape_utils.extract_dims(array, ndim=1)[source]

Decrease the dimensionality of array by extracting ndim leading singleton dimensions.

dpipe.im.shape_utils.prepend_dims(array, ndim=1)[source]

Increase the dimensionality of array by adding ndim leading singleton dimensions.

dpipe.im.shape_utils.append_dims(array, ndim=1)[source]

Increase the dimensionality of array by adding ndim singleton dimensions to the end of its shape.

dpipe.im.shape_utils.insert_dims(array, index=0, ndim=1)[source]

Increase the dimensionality of array by adding ndim singleton dimensions before the specified ``index` of its shape.

dpipe.im.shape_utils.shape_after_convolution(shape: Union[int, Sequence[int]], kernel_size: Union[int, Sequence[int]], stride: Union[int, Sequence[int]] = 1, padding: Union[int, Sequence[int]] = 0, dilation: Union[int, Sequence[int]] = 1, valid: bool = True) tuple[source]

Get the shape of a tensor after applying a convolution with corresponding parameters.

dpipe.im.shape_utils.shape_after_full_convolution(shape: Union[int, Sequence[int]], kernel_size: Union[int, Sequence[int]], axis: Optional[Union[int, Sequence[int]]] = None, stride: Union[int, Sequence[int]] = 1, padding: Union[int, Sequence[int]] = 0, dilation: Union[int, Sequence[int]] = 1, valid: bool = True) tuple[source]

Get the shape of a tensor after applying a convolution with corresponding parameters along the given axes. The dimensions along the remaining axes will become singleton.