def parse_region( in_image: Image, top: Size, left: Size, width: Size, height: Size, tier_idx: int = 0, tier_type: TierIndexType = TierIndexType.LEVEL, silent_oob: bool = False ) -> Region: """ Parse a region Parameters ---------- in_image Image in which region is extracted top left width height tier_idx Tier index to use as reference tier_type Type of tier index silent_oob Whether out of bounds region should raise an error or not. Returns ------- region The parsed region Raises ------ BadRequestException If a region coordinate is out of bound and silent_oob is False. """ if tier_type == TierIndexType.ZOOM: check_zoom_validity(in_image.pyramid, tier_idx) ref_tier = in_image.pyramid.get_tier_at_zoom(tier_idx) else: check_level_validity(in_image.pyramid, tier_idx) ref_tier = in_image.pyramid.get_tier_at_level(tier_idx) if type(top) == float: top *= ref_tier.height if type(left) == float: left *= ref_tier.width if type(width) == float: width *= ref_tier.width if type(height) == float: height *= ref_tier.height downsample = (ref_tier.width_factor, ref_tier.height_factor) region = Region(top, left, width, height, downsample) if not silent_oob: clipped = copy(region).clip(ref_tier.width, ref_tier.height) if clipped != region: raise BadRequestException( detail=f"Some coordinates of region {region} are out of bounds." ) return region
def test_check_zoom_validity(): with not_raises(BadRequestException): check_zoom_validity(FakeImagePyramid(100, 100, 1).pyramid, 0) check_zoom_validity(FakeImagePyramid(100, 100, 20).pyramid, 10) check_zoom_validity(FakeImagePyramid(100, 100, 20).pyramid, None) with pytest.raises(BadRequestException): check_zoom_validity(FakeImagePyramid(100, 100, 1).pyramid, 1) with pytest.raises(BadRequestException): check_zoom_validity(FakeImagePyramid(100, 100, 20).pyramid, 25)
def _show_mask( request: Request, response: Response, # required for @cache # noqa path: Path, annotations, context_factor, height, width, length, zoom, level, extension, headers, config): in_image = path.get_spatial() check_representation_existence(in_image) annots = parse_annotations(ensure_list(annotations), ignore_fields=['stroke_width', 'stroke_color'], default={'fill_color': WHITE}, origin=headers.annot_origin, im_height=in_image.height) region = get_annotation_region(in_image, annots, context_factor) out_format, mimetype = get_output_format(extension, headers.accept, PROCESSING_MIMETYPES) check_zoom_validity(in_image.pyramid, zoom) check_level_validity(in_image.pyramid, level) req_size = get_window_output_dimensions(in_image, region, height, width, length, zoom, level) out_size = safeguard_output_dimensions(headers.safe_mode, config.output_size_limit, *req_size) out_width, out_height = out_size affine = annotation_crop_affine_matrix(annots.region, region, out_width, out_height) return MaskResponse(in_image, annots, affine, out_width, out_height, 8, out_format).http_response( mimetype, extra_headers=add_image_size_limit_header( dict(), *req_size, *out_size))
def _show_resized( request: Request, response: Response, # required for @cache # noqa path: Path, height, width, length, zoom, level, channels, z_slices, timepoints, min_intensities, max_intensities, filters, gammas, threshold, bits, colorspace, extension, headers, config: Settings, colormaps=None, c_reduction=ChannelReduction.ADD, z_reduction=None, t_reduction=None ): in_image = path.get_spatial() check_representation_existence(in_image) out_format, mimetype = get_output_format(extension, headers.accept, PROCESSING_MIMETYPES) check_zoom_validity(in_image.pyramid, zoom) check_level_validity(in_image.pyramid, level) req_size = get_thumb_output_dimensions(in_image, height, width, length, zoom, level) out_size = safeguard_output_dimensions(headers.safe_mode, config.output_size_limit, *req_size) out_width, out_height = out_size channels = ensure_list(channels) z_slices = ensure_list(z_slices) timepoints = ensure_list(timepoints) channels = get_channel_indexes(in_image, channels) check_reduction_validity(channels, c_reduction, 'channels') z_slices = get_zslice_indexes(in_image, z_slices) check_reduction_validity(z_slices, z_reduction, 'z_slices') timepoints = get_timepoint_indexes(in_image, timepoints) check_reduction_validity(timepoints, t_reduction, 'timepoints') min_intensities = ensure_list(min_intensities) max_intensities = ensure_list(max_intensities) colormaps = ensure_list(colormaps) filters = ensure_list(filters) gammas = ensure_list(gammas) array_parameters = ('min_intensities', 'max_intensities', 'colormaps', 'gammas') check_array_size_parameters( array_parameters, locals(), allowed=[0, 1, len(channels)], nullable=False ) intensities = parse_intensity_bounds( in_image, channels, z_slices, timepoints, min_intensities, max_intensities ) min_intensities, max_intensities = intensities colormaps = parse_colormap_ids(colormaps, ALL_COLORMAPS, channels, in_image.channels) array_parameters = ('filters',) check_array_size_parameters( array_parameters, locals(), allowed=[0, 1], nullable=False ) filters = parse_filter_ids(filters, FILTERS) out_bitdepth = parse_bitdepth(in_image, bits) return ResizedResponse( in_image, channels, z_slices, timepoints, out_format, out_width, out_height, c_reduction, z_reduction, t_reduction, gammas, filters, colormaps, min_intensities, max_intensities, False, out_bitdepth, threshold, colorspace ).http_response( mimetype, extra_headers=add_image_size_limit_header(dict(), *req_size, *out_size) )
def _show_window( request: Request, response: Response, # required for @cache # noqa path: Path, region: Union[Region, dict], height, width, length, zoom, level, channels, z_slices, timepoints, min_intensities, max_intensities, filters, gammas, threshold, bits, colorspace, annotations: Union[ParsedAnnotations, dict, List[dict]], annotation_style: dict, extension, headers, config: Settings, colormaps=None, c_reduction=ChannelReduction.ADD, z_reduction=None, t_reduction=None ): in_image = path.get_spatial() check_representation_existence(in_image) if not isinstance(region, Region): tier_index_type = region['tier_index_type'] reference_tier_index = region['reference_tier_index'] if reference_tier_index is None: if tier_index_type == TierIndexType.LEVEL: reference_tier_index = 0 else: reference_tier_index = in_image.pyramid.max_zoom if 'top' in region: # Parse raw WindowRegion to Region region = parse_region( in_image, region['top'], region['left'], region['width'], region['height'], reference_tier_index, tier_index_type, silent_oob=False ) elif 'ti' in region: # Parse raw WindowTileIndex region to Region check_tileindex_validity( in_image.pyramid, region['ti'], reference_tier_index, tier_index_type ) region = in_image.pyramid.get_tier_at( reference_tier_index, tier_index_type ).get_ti_tile(region['ti']) elif ('tx', 'ty') in region: # Parse raw WindowTileCoord region to Region check_tilecoord_validity( in_image.pyramid, region['tx'], region['ty'], reference_tier_index, tier_index_type ) region = in_image.pyramid.get_tier_at( reference_tier_index, tier_index_type ).get_txty_tile(region['tx'], region['ty']) out_format, mimetype = get_output_format(extension, headers.accept, VISUALISATION_MIMETYPES) check_zoom_validity(in_image.pyramid, zoom) check_level_validity(in_image.pyramid, level) req_size = get_window_output_dimensions(in_image, region, height, width, length, zoom, level) out_size = safeguard_output_dimensions(headers.safe_mode, config.output_size_limit, *req_size) out_width, out_height = out_size channels = ensure_list(channels) z_slices = ensure_list(z_slices) timepoints = ensure_list(timepoints) channels = get_channel_indexes(in_image, channels) check_reduction_validity(channels, c_reduction, 'channels') z_slices = get_zslice_indexes(in_image, z_slices) check_reduction_validity(z_slices, z_reduction, 'z_slices') timepoints = get_timepoint_indexes(in_image, timepoints) check_reduction_validity(timepoints, t_reduction, 'timepoints') min_intensities = ensure_list(min_intensities) max_intensities = ensure_list(max_intensities) colormaps = ensure_list(colormaps) filters = ensure_list(filters) gammas = ensure_list(gammas) array_parameters = ('min_intensities', 'max_intensities', 'colormaps', 'gammas') check_array_size_parameters( array_parameters, locals(), allowed=[0, 1, len(channels)], nullable=False ) intensities = parse_intensity_bounds( in_image, channels, z_slices, timepoints, min_intensities, max_intensities ) min_intensities, max_intensities = intensities colormaps = parse_colormap_ids(colormaps, ALL_COLORMAPS, channels, in_image.channels) array_parameters = ('filters',) check_array_size_parameters( array_parameters, locals(), allowed=[0, 1], nullable=False ) filters = parse_filter_ids(filters, FILTERS) out_bitdepth = parse_bitdepth(in_image, bits) if annotations and annotation_style and not isinstance(annotations, ParsedAnnotations): if annotation_style['mode'] == AnnotationStyleMode.DRAWING: ignore_fields = ['fill_color'] default = {'stroke_color': RED, 'stroke_width': 1} point_envelope_length = annotation_style['point_envelope_length'] else: ignore_fields = ['stroke_width', 'stroke_color'] default = {'fill_color': WHITE} point_envelope_length = None annotations = parse_annotations( ensure_list(annotations), ignore_fields, default, point_envelope_length, origin=headers.annot_origin, im_height=in_image.height ) affine = None if annotations: affine = annotation_crop_affine_matrix(annotations.region, region, *out_size) if annotations and annotation_style and \ annotation_style['mode'] == AnnotationStyleMode.MASK: window = MaskResponse( in_image, annotations, affine, out_width, out_height, out_bitdepth, out_format ) else: window = WindowResponse( in_image, channels, z_slices, timepoints, region, out_format, out_width, out_height, c_reduction, z_reduction, t_reduction, gammas, filters, colormaps, min_intensities, max_intensities, False, out_bitdepth, threshold, colorspace, annotations, affine, annotation_style ) return window.http_response( mimetype, extra_headers=add_image_size_limit_header(dict(), *req_size, *out_size) )