def run( self, stack: ImageStack, *args, ) -> ImageStack: """Performs the dimension reduction with the specifed function Parameters ---------- stack : ImageStack Stack to be filtered. Returns ------- ImageStack : If in-place is False, return the results of filter as a new stack. Otherwise return the original stack. """ # Apply the reducing function reduced = stack._data.reduce( self.func, dim=[Axes(dim).value for dim in self.dims]) # Add the reduced dims back and align with the original stack reduced = reduced.expand_dims( tuple(Axes(dim).value for dim in self.dims)) reduced = reduced.transpose(*stack.xarray.dims) if self.clip_method == Clip.CLIP: reduced = preserve_float_range(reduced, rescale=False) else: reduced = preserve_float_range(reduced, rescale=True) # Update the physical coordinates physical_coords: MutableMapping[Coordinates, Sequence[Number]] = {} for axis, coord in ((Axes.X, Coordinates.X), (Axes.Y, Coordinates.Y), (Axes.ZPLANE, Coordinates.Z)): if axis in self.dims: # this axis was projected out of existence. assert coord.value not in reduced.coords physical_coords[coord] = [ np.average(stack._data.coords[coord.value]) ] else: physical_coords[coord] = reduced.coords[coord.value] reduced_stack = ImageStack.from_numpy(reduced.values, coordinates=physical_coords) return reduced_stack
def run( self, stack: ImageStack, in_place: bool = False, verbose: bool = False, n_processes: Optional[int] = None, *args, ) -> ImageStack: """Perform filtering of an image stack Parameters ---------- stack : ImageStack Stack to be filtered. in_place : bool if True, process ImageStack in-place, otherwise return a new stack verbose : bool if True, report on filtering progress (default = False) n_processes : Optional[int] Number of parallel processes to devote to calculating the filter Returns ------- ImageStack : If in-place is False, return the results of filter as a new stack. Otherwise return the original stack. """ return stack.max_proj(*tuple(Axes(dim) for dim in self.dims))
def __init__( self, dims: Iterable[Union[Axes, str]], func: Union[str, FunctionSourceBundle] = "max", module: Optional[FunctionSource] = None, level_method: Levels = Levels.CLIP, **kwargs ) -> None: self.dims: Iterable[Axes] = set(Axes(dim) for dim in dims) if isinstance(func, str): if module is not None: warnings.warn( f"The module parameter is being deprecated. Use " f"`func=FunctionSource.{module.name}{func} instead.", DeprecationWarning) else: module = FunctionSource.np self.func = module(func) elif isinstance(func, FunctionSourceBundle): if module is not None: raise ValueError( f"When passing in the function as a `FunctionSourceBundle`, module should not " f"be set." ) self.func = func self.level_method = level_method self.kwargs = kwargs
def from_json(cls, url_or_path: str) -> "TransformsList": """ Load a TransformsList from a json file or a url pointing to such a file Loads slicedimage version configuration from :py:class:`starfish.config.StarfishConfig` Parameters ---------- url_or_path : str Either an absolute URL or a filesystem path to a transformsList. Returns ------- TransformsList """ config = StarfishConfig() transforms_list: List[Tuple[Mapping[Axes, int], TransformType, GeometricTransform]] = list() backend, name, _ = resolve_path_or_url( url_or_path, backend_config=config.slicedimage) with backend.read_contextmanager(name) as fh: transforms_array = json.load(fh) for selectors_str, transform_type_str, transforms_matrix in transforms_array: selectors = {Axes(k): v for k, v in selectors_str.items()} transform_type = TransformType(transform_type_str) transform_object = transformsTypeMapping[transform_type]( np.array(transforms_matrix)) transforms_list.append( (selectors, transform_type, transform_object)) return cls(transforms_list)
def run(self, image: ImageStack, *args, **kwargs) -> BinaryMaskCollection: if image.num_rounds != 1: raise ValueError( f"{ThresholdBinarize.__name__} given an image with more than one round " f"{image.num_rounds}") if image.num_chs != 1: raise ValueError( f"{ThresholdBinarize.__name__} given an image with more than one channel " f"{image.num_chs}") result_array = np.empty( shape=[image.shape[axis] for axis, _ in zip(*_get_axes_names(3))], dtype=np.bool) self._binarize(result_array, image.xarray[0, 0]) pixel_ticks: Mapping[Axes, ArrayLike[int]] = { Axes(axis): axis_data for axis, axis_data in image.xarray.coords.items() if axis in _get_axes_names(3)[0] } physical_ticks: Mapping[Coordinates, ArrayLike[Number]] = { Coordinates(coord): coord_data for coord, coord_data in image.xarray.coords.items() if coord in _get_axes_names(3)[1] } return BinaryMaskCollection.from_binary_arrays_and_ticks( (result_array, ), pixel_ticks, physical_ticks, image.log, )
def __init__( self, func: Union[str, FunctionSourceBundle], *func_args, module: Optional[FunctionSource] = None, in_place: bool = False, group_by: Optional[Set[Union[Axes, str]]] = None, level_method: Levels = Levels.CLIP, **func_kwargs, ) -> None: if isinstance(func, str): if module is not None: warnings.warn( f"The module parameter is being deprecated. Use " f"`func=FunctionSource.{module.name}{func} instead.", DeprecationWarning) else: module = FunctionSource.np self.func = module(func) elif isinstance(func, FunctionSourceBundle): if module is not None: raise ValueError( "When passing in the function as a `FunctionSourceBundle`, module should not " "be set.") self.func = func self.in_place = in_place if group_by is None: group_by = {Axes.ROUND, Axes.CH, Axes.ZPLANE} self.group_by: Set[Axes] = {Axes(axis) for axis in group_by} self.level_method = level_method self.func_args = func_args self.func_kwargs = func_kwargs
def _normalize_pixel_ticks( pixel_ticks: Optional[Union[Mapping[Axes, ArrayLike[int]], Mapping[str, ArrayLike[int]]]], ) -> MutableMapping[Axes, ArrayLike[int]]: """Given pixel ticks in a mapping from an axis or a string representing an axis, return a mapping from an axis. The mapping may also not be present (i.e., None), in which an empty dictionary is returned. """ normalized_pixel_ticks = {} for axis, axis_data in (pixel_ticks or {}).items(): if isinstance(axis_data, xr.DataArray): normalized_pixel_ticks[Axes(axis)] = axis_data.data else: normalized_pixel_ticks[Axes(axis)] = axis_data return normalized_pixel_ticks
def __init__(self, dims: Iterable[Union[Axes, str]], func: str = "max", module: FunctionSource = FunctionSource.np, clip_method: Clip = Clip.CLIP, **kwargs) -> None: self.dims: Iterable[Axes] = set(Axes(dim) for dim in dims) self.func = module._resolve_method(func) self.clip_method = clip_method self.kwargs = kwargs
def run( # type: ignore self, image: ImageStack, markers: Optional[BinaryMaskCollection] = None, mask: Optional[BinaryMaskCollection] = None, *args, **kwargs ) -> BinaryMaskCollection: """Runs scikit-image's watershed """ if image.num_rounds != 1: raise ValueError( f"{WatershedSegment.__name__} given an image with more than one round " f"{image.num_rounds}") if image.num_chs != 1: raise ValueError( f"{WatershedSegment.__name__} given an image with more than one channel " f"{image.num_chs}") if mask is not None and len(mask) != 1: raise ValueError( f"{WatershedSegment.__name__} given a mask given a mask with more than one " f"channel {image.num_chs}") if len(args) != 0 or len(kwargs) != 0: raise ValueError( f"{WatershedSegment.__name__}'s run method should not have additional arguments.") image_npy = 1 - image._squeezed_numpy(Axes.ROUND, Axes.CH) markers_npy = np.asarray(markers.to_label_image().xarray) if markers is not None else None mask_npy = mask.uncropped_mask(0) if mask is not None else None watershed_output = watershed( image_npy, markers=markers_npy, mask=mask_npy, **self.watershed_kwargs ) pixel_ticks: Mapping[Axes, ArrayLike[int]] = { Axes(axis): axis_data for axis, axis_data in image.xarray.coords.items() if axis in _get_axes_names(3)[0] } physical_ticks: Mapping[Coordinates, ArrayLike[Number]] = { Coordinates(coord): coord_data for coord, coord_data in image.xarray.coords.items() if coord in _get_axes_names(3)[1] } return BinaryMaskCollection.from_label_array_and_ticks( watershed_output, pixel_ticks, physical_ticks, image.log, # FIXME: (ttung) this should somehow include the provenance of markers and # mask. )
def _cli(ctx, input, output, blobs_stack, blobs_axis): """detect spots""" print('Detecting Spots ...') _blobs_axes = tuple(Axes(_blobs_axis) for _blobs_axis in blobs_axis) ctx.obj = dict( component=DetectSpots, image_stack=input, output=output, blobs_stack=blobs_stack, blobs_axes=_blobs_axes, )
def _normalize_pixel_ticks( pixel_ticks: Optional[Union[Mapping[Axes, ArrayLike[int]], Mapping[str, ArrayLike[int]]]], ) -> MutableMapping[Axes, ArrayLike[int]]: """Given pixel ticks in a mapping from an axis or a string representing an axis, return a mapping from an axis. The mapping may also not be present (i.e., None), in which an empty dictionary is returned. """ return { Axes(axis): axis_data for axis, axis_data in (pixel_ticks or {}).items() }
def __init__( self, func: str, *func_args, module: FunctionSource = FunctionSource.np, in_place: bool = False, group_by: Optional[Set[Union[Axes, str]]] = None, clip_method: Clip = Clip.CLIP, **func_kwargs, ) -> None: self.func = module._resolve_method(func) self.in_place = in_place if group_by is None: group_by = {Axes.ROUND, Axes.CH, Axes.ZPLANE} self.group_by: Set[Axes] = {Axes(axis) for axis in group_by} self.clip_method = clip_method self.func_args = func_args self.func_kwargs = func_kwargs
def run(self, image: ImageStack, *args, **kwargs) -> BinaryMaskCollection: if image.num_rounds != 1: raise ValueError( f"{ThresholdBinarize.__name__} given an image with more than one round " f"{image.num_rounds}") if image.num_chs != 1: raise ValueError( f"{ThresholdBinarize.__name__} given an image with more than one channel " f"{image.num_chs}") result_array = np.empty( shape=[image.shape[axis] for axis, _ in zip(*_get_axes_names(3))], dtype=np.bool) # TODO: (ttung) This could theoretically be done with ImageStack.transform, but # ImageStack.transform doesn't provide the selectors to the worker method. In this case, # we need the selectors to select the correct region of the output array. The alternative # is for each worker thread to create a new array, and then merge them at the end, but that # effectively doubles our memory consumption. # # For now, we will just do it in-process, because it's not a particularly compute-intensive # task. self._binarize(result_array, image.xarray[0, 0]) pixel_ticks: Mapping[Axes, ArrayLike[int]] = { Axes(axis): axis_data for axis, axis_data in image.xarray.coords.items() if axis in _get_axes_names(3)[0] } physical_ticks: Mapping[Coordinates, ArrayLike[Number]] = { Coordinates(coord): coord_data for coord, coord_data in image.xarray.coords.items() if coord in _get_axes_names(3)[1] } return BinaryMaskCollection.from_binary_arrays_and_ticks( (result_array, ), pixel_ticks, physical_ticks, image.log, )
def from_dict(cls, transforms_document: dict) -> "TransformsList": """ Load a TransformsList from a Python dictionary. Returns ------- TransformsList """ version_str = transforms_document[DocumentKeys.VERSION_KEY] cls._verify_version(version_str) transforms_array = transforms_document[DocumentKeys.TRANSFORMS_LIST] transforms_list: List[Tuple[Mapping[Axes, int], TransformType, GeometricTransform]] = list() for selectors_str, transform_type_str, transforms_matrix in transforms_array: selectors = {Axes(k): v for k, v in selectors_str.items()} transform_type = TransformType(transform_type_str) transform_object = transformsTypeMapping[transform_type]( np.array(transforms_matrix)) transforms_list.append( (selectors, transform_type, transform_object)) return cls(transforms_list)
def selector(self) -> Mapping[Axes, int]: return { Axes(axis_str): index for axis_str, index in self._wrapped_tile.indices.items() }
def _cli(ctx, reference_stack, axes, upsampling): ctx.obj["component"]._cli_run( ctx, Translation( reference_stack=reference_stack, axes=Axes(axes), upsampling=upsampling))
def __init__(self, dims: Iterable[Union[Axes, str]]) -> None: warnings.warn( "Filter.MaxProject is being deprecated in favor of Filter.Reduce(func='max')", DeprecationWarning, ) self.dims = set(Axes(dim) for dim in dims)