dlup package#

Subpackages#

Submodules#

dlup.annotations module#

Annotation module for dlup.

There are three types of annotations, in the AnnotationType variable: - points - boxes (which are internally polygons) - polygons

When working with annotations it is assumed that for each label, the type is always the same. So a label e.g., “lymphocyte” would always be a box and not suddenly a polygon. In the latter case you better have labels such as lymphocyte_point, ‘lymphocyte_box` or so.

Assumed: - The type of object (point, box, polygon) is fixed per label. - The mpp is fixed per label.

Supported file formats: - ASAP XML - Darwin V7 JSON - GeoJSON - HaloXML

class dlup.annotations.AnnotationClass(label: 'str', a_cls: 'AnnotationType')[source]#

Bases: object

a_cls: dlup.annotations.AnnotationType#
label: str#
class dlup.annotations.AnnotationSorting(value)[source]#

Bases: enum.Enum

The ways to sort the annotations. This is used in the constructors of the WsiAnnotations class, and applied to the output of WsiAnnotations.read_region().

  • REVERSE: Sort the output in reverse order.

  • BY_AREA: Often when the annotation tools do not properly support hierarchical order, one would annotate in a way

    that the smaller objects are on top of the larger objects. This option sorts the output by area, so that the larger objects appear first in the output and then the smaller objects.

  • NONE: Do not apply any sorting and output as is presented in the input file.

BY_AREA = 'by_area'#
NONE = 'none'#
REVERSE = 'reverse'#
class dlup.annotations.AnnotationType(value)[source]#

Bases: enum.Enum

An enumeration.

BOX = 'box'#
POINT = 'point'#
POLYGON = 'polygon'#
class dlup.annotations.CoordinatesDict[source]#

Bases: TypedDict

coordinates: list[list[list[float]]]#
type: str#
class dlup.annotations.GeoJsonDict[source]#

Bases: TypedDict

TypedDict for standard GeoJSON output

features: list[dict[str, str | dict[str, str]]]#
id: str | None#
type: str#
class dlup.annotations.Point(coord: tuple[float, float], *args: Any, **kwargs: Any)[source]#

Bases: shapely.geometry.point.Point

property annotation_class: dlup.annotations.AnnotationClass#
property label: str#
name: str#
property type: dlup.annotations.AnnotationType#
class dlup.annotations.Polygon(coord: tuple[float, float], *args: Any, **kwargs: Any)[source]#

Bases: shapely.geometry.polygon.Polygon

property annotation_class: dlup.annotations.AnnotationClass#
property label: str#
name: str#
property type: dlup.annotations.AnnotationType#
class dlup.annotations.SingleAnnotationWrapper(a_cls: dlup.annotations.AnnotationClass, annotation: list[dlup.annotations.Polygon | dlup.annotations.Point])[source]#

Bases: object

Class to hold the annotations of one specific label (class) for a whole slide image

property annotation_class: dlup.annotations.AnnotationClass#
append(sample: dlup.annotations.Polygon | dlup.annotations.Point) None[source]#
as_json() list[Any][source]#

Return the annotation as json format.

Returns
dict
as_list() list[dlup.annotations.Polygon | dlup.annotations.Point][source]#
as_strtree() shapely.strtree.STRtree[source]#
property bounding_boxes: tuple[tuple[tuple[int, int], tuple[int, int]], ...]#
property label: str#

The label name for this annotation.

simplify(tolerance: float, *, preserve_topology: bool = True) None[source]#
property type: dlup.annotations.AnnotationType#

The type of annotation, e.g. box, polygon or points.

class dlup.annotations.WsiAnnotations(annotations: list[dlup.annotations.SingleAnnotationWrapper], sorting: dlup.annotations.AnnotationSorting = AnnotationSorting.NONE, offset_to_slide_bounds: bool = False)[source]#

Bases: object

Class to hold the annotations of all labels specific label for a whole slide image.

Parameters
annotationslist[SingleAnnotationWrapper]

A list of annotations for a single label.

sortingAnnotationSorting

How to sort the annotations returned from the read_region() function.

offset_to_slide_boundsbool

If true, will set the property offset_to_slide_bounds to True. This means that the annotations need to be offset to the slide bounds. This is useful when the annotations are read from a file format which requires this, for instance HaloXML.

as_geojson() dlup.annotations.GeoJsonDict[source]#

Output the annotations as proper geojson. These outputs are sorted according to the AnnotationSorting selected for the annotations. This ensures the annotations are correctly sorted in the output.

Returns
list of (str, GeoJsonDict)
property bounding_box: tuple[tuple[float, float], tuple[float, float]]#

Return the bounding box of all annotations.

Returns
tuple[tuple[float, float], tuple[float, float]]

Bounding box of the form ((x, y), (w, h)).

copy() dlup.annotations.WsiAnnotations[source]#

Make a copy of the object.

filter(labels: str | list[str] | tuple[str]) None[source]#

Filter annotations based on the given label list. If annotations with the same name but a different type are present, they will all be added irrespective of the type.

Parameters
labelstuple or list

The list or tuple of labels

Returns
None
classmethod from_asap_xml(asap_xml: Union[str, pathlib.Path], scaling: Optional[float] = None, sorting: dlup.annotations.AnnotationSorting = AnnotationSorting.BY_AREA) dlup.annotations.WsiAnnotations[source]#

Read annotations as an ASAP [1] XML file. ASAP is a tool for viewing and annotating whole slide images.

Parameters
asap_xmlPathLike

Path to ASAP XML annotation file.

scalingfloat, optional
sorting: AnnotationSorting

The sorting to apply to the annotations. Check the AnnotationSorting enum for more information. By default, the annotations are sorted by area.

Returns
WsiAnnotations

References

1

https://github.com/computationalpathologygroup/ASAP

classmethod from_darwin_json(darwin_json: Union[str, pathlib.Path], scaling: Optional[float] = None, sorting: dlup.annotations.AnnotationSorting = AnnotationSorting.NONE) dlup.annotations.WsiAnnotations[source]#

Read annotations as a V7 Darwin [1] JSON file.

Parameters
darwin_jsonPathLike

Path to the Darwin JSON file.

scalingfloat, optional

The scaling to apply to the annotations.

sorting: AnnotationSorting

The sorting to apply to the annotations. Check the AnnotationSorting enum for more information. By default, the annotations are not sorted as V7 Darwin supports hierarchical annotations.

Returns
WsiAnnotations

References

1

https://darwin.v7labs.com/

classmethod from_geojson(geojsons: Union[str, pathlib.Path, Iterable[Union[str, pathlib.Path]]], scaling: Optional[float] = None, sorting: dlup.annotations.AnnotationSorting = AnnotationSorting.BY_AREA) dlup.annotations._TWsiAnnotations[source]#

Constructs an WsiAnnotations object from geojson.

Parameters
geojsonsIterable, or PathLike

List of geojsons representing objects. The properties object must have the name which is the label of this object.

scalingfloat, optional

The scaling to apply to the annotations.

sorting: AnnotationSorting

The sorting to apply to the annotations. Check the AnnotationSorting enum for more information. By default, the annotations are sorted by area.

Returns
WsiAnnotations
classmethod from_halo_xml(halo_xml: Union[str, pathlib.Path], scaling: Optional[float] = None, sorting: dlup.annotations.AnnotationSorting = AnnotationSorting.NONE) dlup.annotations.WsiAnnotations[source]#

Read annotations as a Halo [1] XML file. This function requires pyhaloxml [2] to be installed.

Parameters
halo_xmlPathLike

Path to the Halo XML file.

scalingfloat, optional

The scaling to apply to the annotations.

sorting: AnnotationSorting

The sorting to apply to the annotations. Check the AnnotationSorting enum for more information. By default the annotations are not sorted as HALO supports hierarchical annotations.

Returns
WsiAnnotations

References

1

https://indicalab.com/halo/

2

https://github.com/rharkes/pyhaloxml

property offset_to_slide_bounds: bool#

If True, the annotations need to be offset to the slide bounds. This is useful when the annotations are read from a file format which requires this, for instance HaloXML.

Returns
bool
read_region(location: numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]] | tuple[Union[int, float], Union[int, float]], scaling: float, size: numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]] | tuple[Union[int, float], Union[int, float]]) list[dlup.annotations.Polygon | dlup.annotations.Point][source]#

Reads the region of the annotations. API is the same as dlup.SlideImage so they can be used in conjunction.

The process is as follows:

  1. All the annotations which overlap with the requested region of interested are filtered with an STRTree.

  2. The annotations are filtered by name (if the names are the same they are in order of POINT, BOX and POLYGON) , and subsequently by area from large to small. The reason this is implemented this way is because sometimes one can annotate a larger region, and the smaller regions should overwrite the previous part. A function dlup.data.transforms.convert_annotations can be used to convert such outputs to a mask.

  3. The annotations are cropped to the region-of-interest, or filtered in case of points. Polygons which convert into points after intersection are removed. If it’s a image-level label, nothing happens.

  4. The annotation is rescaled and shifted to the origin to match the local patch coordinate system.

The final returned data is a list of dlup.annotations.Polygon or dlup.annotations.Point.

Parameters
location: np.ndarray or tuple
sizenp.ndarray or tuple
scalingfloat
Returns
list[tuple[str, ShapelyTypes]]

List of tuples denoting the name of the annotation and a shapely object.

Examples

  1. To read geojson annotations and convert them into masks:

>>> from pathlib import Path
>>> from dlup import SlideImage
>>> import numpy as np
>>> from rasterio.features import rasterize
>>> wsi = SlideImage.from_file_path(Path("path/to/image.svs"))
>>> wsi = wsi.get_scaled_view(scaling=0.5)
>>> wsi = wsi.read_region(location=(0,0), size=wsi.size)
>>> annotations = WsiAnnotations.from_geojson([Path("path/to/geojson.json")], labels=["class_name"])
>>> polygons: list[Polygons] = annotations.read_region(location=(0,0), size=wsi.size, scaling=0.01)

The polygons can be converted to masks using dlup.data.transforms.convert_annotations or dlup.data.transforms.ConvertAnnotationsToMask.

relabel(labels: tuple[tuple[dlup.annotations.AnnotationClass, dlup.annotations.AnnotationClass], ...]) None[source]#

Rename labels in the class in-place.

Parameters
labelstuple

Tuple of tuples of the form (original_annotation_class, new_annotation_class). Labels which are not present will be kept the same.

Returns
None
simplify(tolerance: float, *, preserve_topology: bool = True) None[source]#

Simplify the polygons in the annotation (i.e. reduce points). Other annotations will remain unchanged. All points in the resulting polygons object will be in the tolerance distance of the original polygon.

Parameters
tolerancefloat
preserve_topologybool

Preserve the topology, if false, this function will be much faster. Internally the shapely simplify algorithm is used.

Returns
None
dlup.annotations.rescale_geometry(geometry: Union[dlup.annotations.Point, dlup.annotations.Polygon], scaling: Optional[float] = None) Union[dlup.annotations.Point, dlup.annotations.Polygon][source]#
dlup.annotations.shape(coordinates: dlup.annotations.CoordinatesDict, label: str, multiplier: float = 1.0) list[dlup.annotations.Polygon | dlup.annotations.Point][source]#

dlup.background module#

Utilities to handle background / foreground masks.

dlup.background.is_foreground(slide_image: SlideImage, background_mask: MaskTypes, region: tuple[float, float, int, int, float], threshold: float | None = 1.0) bool[source]#

Check if a region is foreground.

Parameters
slide_imageSlideImage

Slide image to check

background_masknp.ndarray or SlideImage or WsiAnnotations

Background mask to check against

regiontuple[float, float, int, int, float]

Region to check

thresholdfloat or None

Threshold to check against. The foreground percentage should be strictly larger than threshold. If None anything is foreground. If 1, the region must be completely foreground. Other values are in between, for instance if 0.5, the region must be at least 50% foreground.

Returns
bool

dlup.logging module#

dlup.logging.build_cli_logger(name: str, log_to_file: bool, verbosity_level: int, log_directory: Union[str, pathlib.Path] = '.') None[source]#

Setup logging for DLUP.

Parameters
namestr

Human readable identifier for the current log.

log_to_filebool

Whether to save log as a file additionally to having it on stdout.

verbosity_level: int

How verbose the log should be. 0 is least verbose, 2 is most verbose.

log_directoryPathLike

Directory to save log file in.

Returns
None
dlup.logging.setup_logging(filename: Optional[pathlib.Path] = None, use_stdout: bool = True, log_level: str = 'INFO', formatter_str: str = '[%(asctime)s | %(name)s | %(levelname)s] - %(message)s') None[source]#

Setup logging for dlup.

Parameters
use_stdoutbool

Write output to standard out.

filenamePathLike

Filename to write log to.

log_levelstr

Logging level as in the python.logging library.

formatter_strstr

Formatting string to be used for logging messages.

Returns
——-
None

dlup.tiling module#

class dlup.tiling.Grid(coordinates: list[numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]]], order: str | dlup.tiling.GridOrder = GridOrder.C)[source]#

Bases: collections.abc.Sequence[numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]]]

Facilitates the access to the coordinates of an n-dimensional grid.

Initialize a lattice given a set of basis vectors.

classmethod from_tiling(offset: Union[numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]], Sequence[Union[int, float]]], size: Union[numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]], Sequence[Union[int, float]]], tile_size: Union[numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]], Sequence[Union[int, float]]], tile_overlap: Union[numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]], Sequence[Union[int, float]], int, float] = 0, mode: dlup.tiling.TilingMode = TilingMode.skip, order: dlup.tiling.GridOrder = GridOrder.C) dlup.tiling.Grid[source]#

Generate a grid from a set of tiling parameters.

property size: tuple[int, int]#

Return the size of the generated lattice.

class dlup.tiling.GridOrder(value)[source]#

Bases: str, enum.Enum

Order of the grid.

Fortran is column-major order, and C is in row-major order, that is, the tiles are created in a column-by-column fashion or in a row by row fashion.

C = 'C'#
F = 'F'#
class dlup.tiling.TilingMode(value)[source]#

Bases: str, enum.Enum

Type of tiling.

Skip will skip the border tiles if they don’t fit the region. Overflow counts as last tile even if it’s overflowing.

overflow = 'overflow'#
skip = 'skip'#
dlup.tiling.indexed_ndmesh(bases: Sequence[Union[numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]], Sequence[Union[int, float]]]], indexing: Literal['xy', 'ij'] = 'ij') numpy.ndarray[Any, numpy.dtype[numpy.int64]][source]#

Converts a list of arrays into an n-dimensional indexed mesh.

Examples

import dlup
mesh = dlup.tiling.indexed_ndmesh(((1, 2, 3), (4, 5, 6)))
assert mesh[0, 0] == (1, 4)
assert mesh[0, 1] == (1, 5)
dlup.tiling.tiles_grid_coordinates(size: Union[numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]], Sequence[Union[int, float]]], tile_size: Union[numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]], Sequence[Union[int, float]]], tile_overlap: Union[numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]], Sequence[Union[int, float]], int, float] = 0, mode: dlup.tiling.TilingMode = TilingMode.skip) list[numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]]][source]#

Generate a list of coordinates for each dimension representing a tile location.

The first tile has the corner located at (0, 0).

dlup.tools module#

Utility classes to easily extend sequences logic without creating new classes.

class dlup.tools.ConcatSequences(sequences: List[Sequence[dlup.tools.T]])[source]#

Bases: collections.abc.Sequence[dlup.tools.T]

Concatenate two or more sequences.

class dlup.tools.MapSequence(function: Callable[[Any, dlup.tools.T], dlup.tools.T], sequence: Sequence[dlup.tools.T])[source]#

Bases: collections.abc.Sequence[dlup.tools.T]

Wraps the __getitem__ function of a sequence.

It’s similar to the built-in map(), although instead of returning an iterator, a sequence object is returned instead.

dlup.types module#

dlup.writers module#

Classes to write image and mask files

class dlup.writers.ImageWriter[source]#

Bases: object

Base writer class

class dlup.writers.TiffCompression(value)[source]#

Bases: str, enum.Enum

An enumeration.

CCITTFAX4 = 'ccittfax4'#
DEFLATE = 'deflate'#
JP2K = 'jp2k'#
JP2K_LOSSY = 'jp2k_lossy'#
JPEG = 'jpeg'#
LZW = 'lzw'#
NONE = 'none'#
PACKBITS = 'packbits'#
PNG = 'png'#
WEBP = 'webp'#
ZSTD = 'zstd'#
class dlup.writers.TifffileImageWriter(filename: Union[str, pathlib.Path], size: tuple[int, int] | tuple[int, int, int], mpp: float | tuple[float, float], tile_size: tuple[int, int] = (512, 512), pyramid: bool = False, colormap: Optional[dict[int, str]] = None, compression: dlup.writers.TiffCompression | None = TiffCompression.JPEG, interpolator: dlup._image.Resampling | None = Resampling.LANCZOS, anti_aliasing: bool = False, quality: int | None = 100, metadata: Optional[dict[str, str]] = None)[source]#

Bases: dlup.writers.ImageWriter

Image writer that writes tile-by-tile to tiff.

Writer based on tifffile.

Parameters
filenamePathLike

Filename where to write

sizetuple

Size of the image to be written. This is defined as (height, width, num_channels), or rather (rows, columns, num_channels) and is important value to get correct. In case of a mask with a single channel the value is given by (rows, columns).

mppint, or tuple[int, int]
tile_sizetuple[int, int]

Tiff tile_size, defined as (height, width).

pyramidbool

Whether to write a pyramidal image.

colormapdict[int, str]

Colormap to use for the image. This is only used when the image is a mask.

compressionTiffCompression

Compressor to use.

interpolatorResampling, optional

Interpolator to use when downsampling. For masks you should select nearest, as the interpolation could otherwise lead to unexpected results (i.e. add values which are actually not there!). By default the Lanczos interpolator is used.

anti_aliasingbool, optional

Whether to use anti-aliasing when downsampling. By default this is set to False.

qualityint

Quality in case a lossy compressor is used.

metadatadict[str, str]

Metadata to write to the tiff file.

from_pil(pil_image: PIL.Image.Image) None[source]#

Create tiff image from a PIL image

Parameters
pil_imagePIL.Image
from_tiles_iterator(iterator: Iterator[numpy.ndarray[Any, numpy.dtype[numpy.int64]]]) None[source]#

Generate the tiff from a tiles iterator. The tiles should be in row-major (C-order) order. The dlup.tiling.Grid class has the possibility to generate such grids using GridOrder.C.

Parameters
iteratorIterator

Iterator providing the tiles as numpy arrays. They are expected to be (tile_height, tile_width, num_channels) when RGB(A) images or (tile_height, tile_width) when masks. The tiles can be smaller at the border.

Module contents#

class dlup.BoundaryMode(value)[source]#

Bases: str, enum.Enum

Define the policy to sample outside the region.

crop = 'crop'#
zero = 'zero'#
class dlup.RegionView(boundary_mode: Optional[dlup._region.BoundaryMode] = None)[source]#

Bases: abc.ABC

A generic image object from which you can extract a region.

A unit ‘U’ is assumed to be consistent across this interface. Could be for instance pixels.

TODO(lromor): Add features like cyclic boundary conditions or zero padding, or “hard” walls. TODO(lromor): Add another feature to return a subregion. The logic could stay in the abstract class. This is especially useful to tile subregions instead of a whole level.

read_region(location: Union[numpy.ndarray[Any, numpy.dtype[numpy.float64]], Iterable[float]], size: Union[numpy.ndarray[Any, numpy.dtype[numpy.int64]], Iterable[int]]) PIL.Image.Image[source]#

Returns the requested region as a numpy array.

abstract property size: tuple[int, ...]#

Returns size of the region in U units.

class dlup.SlideImage(wsi: dlup.backends.common.AbstractSlideBackend, identifier: Optional[str] = None, interpolator: Optional[dlup._image.Resampling] = Resampling.LANCZOS, overwrite_mpp: Optional[tuple[float, float]] = None, apply_color_profile: bool = False)[source]#

Bases: object

Utility class to simplify whole-slide pyramidal images management.

This helper class furtherly abstracts openslide access to WSIs by validating some of the properties and giving access to a continuous pyramid. Layer values are interpolated from the closest high resolution layer. Each horizontal slices of the pyramid can be accessed using a scaling value z as index.

Examples

>>> import dlup
>>> wsi = dlup.SlideImage.from_file_path('path/to/slide.svs')

Initialize a whole slide image and validate its properties. This class allows to read whole-slide images at any arbitrary resolution. This class can read images from any backend that implements the AbstractSlideBackend interface.

Parameters
wsiAbstractSlideBackend

The slide object.

identifierstr, optional

A user-defined identifier for the slide, used in e.g. exceptions.

interpolatorResampling, optional

The interpolator to use when reading regions. For images typically LANCZOS is the best choice. Masks can use NEAREST. If set to None, will use LANCZOS.

overwrite_mpptuple[float, float], optional

Overwrite the mpp of the slide. For instance, if the mpp is not available, or when sourcing from and external database.

apply_color_profilebool

Whether to apply the color profile to the output regions.

Returns
None
Raises
UnsupportedSlideError

If the slide is not supported, or when the mpp is not valid (too anisotropic).

property aspect_ratio: float#

Returns width / height.

close() None[source]#

Close the underlying image.

property color_profile: PIL.ImageCms.ImageCmsProfile | None#

Returns the ICC profile of the image.

Each image in the pyramid has the same ICC profile, but the associated images might have their own. If you wish to apply the ICC profile (which is also available as a property in the region itself).

Returns
ImageCmsProfile

The ICC profile of the image.

classmethod from_file_path(wsi_file_path: Union[str, pathlib.Path], identifier: Optional[str] = None, backend: Union[dlup.experimental_backends.ImageBackend, Type[dlup.backends.common.AbstractSlideBackend]] = ImageBackend.OPENSLIDE, **kwargs: Any) dlup._image._TSlideImage[source]#
get_closest_native_level(mpp: float) int[source]#

Returns the closest native level to the given mpp.

Returns
int

The closest level.

get_closest_native_mpp(mpp: float) tuple[float, float][source]#

Returns the closest native mpp to the given mpp.

Returns
tuple[float, float]

The closest mpp in the format (mpp_x, mpp_y).

get_mpp(scaling: float) float[source]#

Returns the respective mpp from the scaling.

get_scaled_size(scaling: Union[int, float], limit_bounds: Optional[bool] = False) tuple[int, int][source]#

Compute slide image size at specific scaling.

Parameters
scaling: GenericNumber

The factor by which the image needs to be scaled.

limit_bounds: Optional[bool]

If True, the scaled size will be calculated using the slide bounds of the whole slide image. This is generally the specific area within a whole slide image where we can find the tissue specimen.

Returns
size: tuple[int, int]

The scaled size of the image.

get_scaled_slide_bounds(scaling: float) tuple[tuple[int, int], tuple[int, int]][source]#

Returns the bounds of the slide at a specific scaling level. This takes the slide bounds into account and scales them to the appropriate scaling level.

Parameters
scalingfloat

The scaling level to use.

Returns
tuple[tuple[int, int], tuple[int, int]]

The slide bounds at the given scaling level.

get_scaled_view(scaling: Union[int, float]) dlup._image._SlideImageRegionView[source]#

Returns a RegionView at a specific level.

get_scaling(mpp: float | None) float[source]#

Inverse of get_mpp().

get_thumbnail(size: tuple[int, int] = (512, 512)) PIL.Image.Image[source]#

Returns an RGB PIL.Image.Image thumbnail for the current slide.

Parameters
sizetuple[int, int]

Maximum bounding box for the thumbnail expressed as (width, height).

Returns
PIL.Image.Image

The thumbnail as a PIL image.

property identifier: str | None#

Returns a user-defined identifier.

property magnification: float | None#

Returns the objective power at which the WSI was sampled.

property mpp: float#

Returns the microns per pixel of the high res image.

property properties: dict[str, str | int | float | bool] | None#

Returns any extra associated properties with the image.

read_region(location: Union[numpy.ndarray[Any, numpy.dtype[numpy.int64 | numpy.float64]], Iterable[Union[int, float]], tuple[Union[int, float], Union[int, float]]], scaling: float, size: numpy.ndarray[Any, numpy.dtype[numpy.int64]] | tuple[int, int]) PIL.Image.Image[source]#

Return a region at a specific scaling level of the pyramid.

A typical slide is made of several levels at different mpps. In normal cirmustances, it’s not possible to retrieve an image of intermediate mpp between these levels. This method takes care of subsampling the closest high resolution level to extract a target region via interpolation.

Once the best layer is selected, a native resolution region is extracted, with enough padding to include the samples necessary to downsample the final region (considering LANCZOS interpolation method basis functions).

The steps are approximately the following:

  1. Map the region that we want to extract to the below layer.

  2. Add some extra values (left and right) to the native region we want to extract to take into account the interpolation samples at the border (“native_extra_pixels”).

  3. Map the location to the level0 coordinates, floor it to add extra information on the left (level_zero_location_adapted).

  4. Re-map the integral level-0 location to the native_level.

  5. Compute the right bound of the region adding the native_size and extra pixels (native_size_adapted). The size is also clipped so that any extra pixel will fit within the native level.

  6. Since the native_size_adapted needs to be passed to openslide and has to be an integer, we ceil it to avoid problems with possible overflows of the right boundary of the target region being greater than the right boundary of the sample region (native_location + native_size > native_size_adapted + native_location_adapted).

  7. Crop the target region from within the sampled region by computing the relative coordinates (fractional_coordinates).

Parameters
location

Location from the top left (x, y) in pixel coordinates given at the requested scaling.

scaling

The scaling to be applied compared to level 0.

size

Region size of the resulting region.

Returns
PIL.Image

The extract region.

Examples

The locations are defined at the requested scaling (with respect to level 0), so if we want to extract at location (location_x, location_y) of a scaling 0.5 (with respect to level 0), and have resulting tile size of (tile_size, tile_size) with a scaling factor of 0.5, we can use: >>> wsi.read_region(location=(coordinate_x, coordinate_y), scaling=0.5, size=(tile_size, tile_size))

property size: tuple[int, int]#

Returns the highest resolution image size in pixels. Returns in (width, height).

property slide_bounds: tuple[tuple[int, int], tuple[int, int]]#

Returns the bounds of the slide. These can be smaller than the image itself. These bounds are in the format (x, y), (width, height), and are defined at level 0 of the image.

property thumbnail: PIL.Image.Image#

Returns the thumbnail.

property vendor: str | None#

Returns the scanner vendor.

exception dlup.UnsupportedSlideError(msg: str, identifier: Optional[str] = None)[source]#

Bases: dlup._exceptions.DlupError