--- a +++ b/pathaia/patches/visu.py @@ -0,0 +1,69 @@ +# coding: utf8 +"""Useful functions for visualizing patches in WSIs.""" + +import numpy +from skimage.morphology import binary_dilation, disk +import openslide +from typing import Sequence, Tuple, Optional +from ..util.types import NDByteImage, Patch, Coord + + +def preview_from_queries( + slide: openslide.OpenSlide, + queries: Sequence[Patch], + min_res: int = 512, + color: Tuple[int, int, int] = (255, 255, 0), + thickness: int = 2, + cell_size: int = 20, + size_0: Optional[Coord] = None, +) -> NDByteImage: + """ + Give thumbnail with patches displayed. + + Args: + slide: openslide object + queries: patch objects to preview from + min_res: minimum size for the smallest side of the thumbnail (usually the width) + color: rgb color for patch boundaries + thickness: thickness of patch boundaries + cell_size: size of a cell representing a patch in the grid + psize: size of a patch at level 0 + + Returns: + Thumbnail image with patches displayed. + + """ + # get thumbnail first + slide_size = Coord(slide.dimensions) + if size_0 is None: + size_0 = Coord(queries[0].size_0) if len(queries) != 0 else Coord(min_res) + thickness = 2 * (thickness // 2) + 1 + res = slide_size / size_0 * (thickness + cell_size) + thickness + thumb_w = max(min_res, res.x) + thumb_h = max(min_res, res.y) + image = slide.get_thumbnail((thumb_w, thumb_h)) + thumb_size = Coord(image.size) + dsr_x = slide_size[0] / thumb_size[0] + dsr_y = slide_size[1] / thumb_size[1] + image = numpy.array(image)[:, :, 0:3] + # get grid + grid = numpy.zeros((thumb_size.y, thumb_size.x), numpy.uint8) + for query in queries: + # position in queries are absolute + x, y = round(query.position[0] / dsr_x), round(query.position[1] / dsr_y) + dx, dy = round(query.size_0[0] / dsr_x), round(query.size_0[1] / dsr_y) + #? startx = numpy.clip(x, 0, thumb_size.x - 1) + startx = min(x, thumb_size.x - 1) + starty = min(y, thumb_size.y - 1) + endx = min(x + dx, thumb_size.x - 1) + endy = min(y + dy, thumb_size.y - 1) + # horizontal segments + grid[starty, startx:endx] = 1 + grid[endy - 1, startx:endx] = 1 + # vertical segments + grid[starty:endy, startx] = 1 + grid[starty:endy, endx - 1] = 1 + d = disk(thickness//2) + grid = binary_dilation(grid, d) + image[grid] = color + return image