-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR adds a Binarizer that effectively wraps skimage's watershed implementation. Test plan: used in subsequent PR.
- Loading branch information
Tony Tung
authored
Dec 17, 2019
1 parent
e08c260
commit 44b518b
Showing
2 changed files
with
83 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
from typing import Mapping, Optional | ||
|
||
import numpy as np | ||
from skimage.morphology import watershed | ||
|
||
from starfish.core.imagestack.imagestack import ImageStack | ||
from starfish.core.morphology.binary_mask import BinaryMaskCollection | ||
from starfish.core.morphology.util import _get_axes_names | ||
from starfish.core.types import ArrayLike, Axes, Coordinates, Number | ||
from ._base import BinarizeAlgorithm | ||
|
||
|
||
class WatershedBinarize(BinarizeAlgorithm): | ||
"""Binarizes an image using a watershed algorithm. This wraps scikit-image's watershed | ||
algorithm. | ||
The image being binarized must be an ImageStack with num_rounds == 1 and num_chs == 1. | ||
Any parameters besides image, markers, and mask should be set in the constructor and will be | ||
passed to scikit-image's watershed. | ||
See Also | ||
-------- | ||
skimage.morphology.watershed | ||
""" | ||
def __init__(self, **watershed_kwargs): | ||
self.watershed_kwargs = watershed_kwargs | ||
|
||
def run( | ||
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"{WatershedBinarize.__name__} given an image with more than one round " | ||
f"{image.num_rounds}") | ||
if image.num_chs != 1: | ||
raise ValueError( | ||
f"{WatershedBinarize.__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"{WatershedBinarize.__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"{WatershedBinarize.__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. | ||
) |