-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pipeline Components: LearnTransform and ApplyTransform #1083
Changes from 14 commits
cbb88e0
a2b9ff7
25e1d4b
96f0ec3
f1e1f30
eba779f
393f2b9
1357c66
c3de8de
b08f0b3
27dcc5c
fe17786
0071ea9
9ee5eec
b2373f7
8ba1c7e
776bd19
1820bdd
0afd305
45fc168
6f75782
0bfd00e
d071c8d
17d581e
53c278c
fb0657a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,7 +59,6 @@ To see the code or report a bug, please visit the `github repository | |
<div class="col-md-3"> | ||
<h2>Features</h2> | ||
|
||
* Registration: :ref:`API <registration>` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to link to the newly created docs for learning and applying transformations? |
||
* Filtering: :ref:`API <filtering>` | ||
* Spot-Finding: :ref:`API <detection>` | ||
* Decoding: :ref:`API <decoding>` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -482,4 +482,4 @@ | |
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
from ._apply_transform import ApplyTransform | ||
from ._filter import Filter | ||
from ._registration import Registration | ||
from ._learn_transform import LearnTransform | ||
from ._segmentation import Segmentation |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,8 @@ | ||
from typing import Optional | ||
|
||
from starfish.imagestack.imagestack import ImageStack | ||
from starfish.pipeline.algorithmbase import AlgorithmBase | ||
|
||
|
||
class RegistrationAlgorithmBase(AlgorithmBase): | ||
def run(self, stack) -> Optional[ImageStack]: | ||
class ApplyTransformBase(AlgorithmBase): | ||
def run(self, stack) -> ImageStack: | ||
"""Performs registration on the stack provided.""" | ||
raise NotImplementedError() |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,106 @@ | ||||||
from copy import deepcopy | ||||||
from typing import Union | ||||||
|
||||||
import numpy as np | ||||||
import xarray as xr | ||||||
from skimage import transform | ||||||
from skimage.transform._geometric import GeometricTransform | ||||||
from tqdm import tqdm | ||||||
|
||||||
from starfish.config import StarfishConfig | ||||||
from starfish.image._apply_transform._base import ApplyTransformBase | ||||||
from starfish.image._learn_transform.transforms_list import TransformsList | ||||||
from starfish.imagestack.imagestack import ImageStack | ||||||
from starfish.types import Axes | ||||||
from starfish.util import click | ||||||
|
||||||
|
||||||
class Warp(ApplyTransformBase): | ||||||
"""Class that applies a list of arbitrary skimage GeometricTransforms to an ImageStack | ||||||
using skimage.transform.warp""" | ||||||
|
||||||
def __init__(self, transforms_list: Union[str, TransformsList]): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. things that can be loaded from a file should be passed into |
||||||
""" | ||||||
Parameters | ||||||
---------- | ||||||
transforms_list: TransformsList | ||||||
A list of tuples that describe a subset of an ImageStack axis and a GeometricTransform | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
to apply to it. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
""" | ||||||
if isinstance(transforms_list, TransformsList): | ||||||
self.transforms_list = transforms_list | ||||||
else: | ||||||
self.transforms_list = TransformsList.from_json(filename=transforms_list) | ||||||
|
||||||
def run( | ||||||
self, stack: ImageStack, | ||||||
in_place: bool=False, verbose: bool=False, **kwargs) -> ImageStack: | ||||||
"""Applies a list of transformations to an ImageStack | ||||||
|
||||||
Parameters | ||||||
---------- | ||||||
stack : ImageStack | ||||||
Stack to be transformed. | ||||||
in_place : bool | ||||||
if True, process ImageStack in-place, otherwise return a new stack | ||||||
verbose : bool | ||||||
if True, report on filtering progress (default = False) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
Returns | ||||||
------- | ||||||
ImageStack : | ||||||
If in-place is False, return the results of the transforms as a new stack. | ||||||
Otherwise return the original stack. | ||||||
""" | ||||||
if not in_place: | ||||||
# create a copy of the ImageStack, call apply on that stack with in_place=True | ||||||
image_stack = deepcopy(stack) | ||||||
return self.run( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: you could probably unwrap |
||||||
image_stack, | ||||||
in_place=True, | ||||||
**kwargs | ||||||
) | ||||||
if verbose and StarfishConfig().verbose: | ||||||
self.transforms_list.transforms = tqdm(self.transforms_list.transforms) | ||||||
all_axes = {Axes.ROUND, Axes.CH, Axes.ZPLANE} | ||||||
for selector, transformation_object in self.transforms_list.transforms: | ||||||
other_axes = all_axes - set(selector.keys()) | ||||||
# iterate through remaining axes | ||||||
for axes in stack._iter_axes(other_axes): | ||||||
# combine all axes data to select one tile | ||||||
selector.update(axes) # type: ignore | ||||||
selected_image, _ = stack.get_slice(selector) | ||||||
warped_image = warp(selected_image, transformation_object, **kwargs | ||||||
).astype(np.float32) | ||||||
stack.set_slice(selector, warped_image) | ||||||
return stack | ||||||
|
||||||
@staticmethod | ||||||
@click.command("Warp") | ||||||
@click.option("--transformation-list", required=True, type=click.Path(exists=True), | ||||||
help="The list of transformations to apply to the ImageStack.") | ||||||
@click.pass_context | ||||||
def _cli(ctx, transformation_list): | ||||||
ctx.obj["component"]._cli_run(ctx, Warp(transformation_list)) | ||||||
|
||||||
|
||||||
def warp(image: Union[xr.DataArray, np.ndarray], | ||||||
transformation_object: GeometricTransform, | ||||||
**kwargs | ||||||
) -> np.ndarray: | ||||||
""" Wrapper around skimage.transform.warp. Warps an image according to a | ||||||
given coordinate transformation. | ||||||
|
||||||
Parameters | ||||||
---------- | ||||||
image: np.ndarray | ||||||
The image to be transformed | ||||||
transformation_object: skimage.transform.GeometricTransform | ||||||
The transformation object to apply. | ||||||
|
||||||
Returns | ||||||
------- | ||||||
np.ndarray: | ||||||
the warped image. | ||||||
""" | ||||||
return transform.warp(image, transformation_object, **kwargs) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from typing import Type | ||
|
||
from starfish.imagestack.imagestack import ImageStack | ||
from starfish.pipeline import AlgorithmBase, import_all_submodules, PipelineComponent | ||
from starfish.util import click | ||
from . import _base | ||
import_all_submodules(__file__, __package__) | ||
|
||
|
||
class LearnTransform(PipelineComponent): | ||
|
||
@classmethod | ||
def _get_algorithm_base_class(cls) -> Type[AlgorithmBase]: | ||
return _base.LearnTransformBase | ||
|
||
@classmethod | ||
def _cli_run(cls, ctx, instance, *args, **kwargs): | ||
output = ctx.obj["output"] | ||
stack = ctx.obj["stack"] | ||
transformation_list = instance.run(stack) | ||
transformation_list.to_json(output) | ||
|
||
@staticmethod | ||
@click.group("learn_transform") | ||
@click.option("-i", "--input", type=click.Path(exists=True)) | ||
@click.option("-o", "--output", required=True) | ||
@click.pass_context | ||
def _cli(ctx, input, output): | ||
"""learn a set of transforms for an ImageStack.""" | ||
print("Learning Transforms for images...") | ||
ctx.obj = dict( | ||
component=LearnTransform, | ||
input=input, | ||
output=output, | ||
stack=ImageStack.from_path_or_url(input), | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from starfish.image._learn_transform.transforms_list import TransformsList | ||
from starfish.pipeline.algorithmbase import AlgorithmBase | ||
|
||
|
||
class LearnTransformBase(AlgorithmBase): | ||
def run(self, stack) -> TransformsList: | ||
"""Learns Transforms for a given stack.""" | ||
raise NotImplementedError() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably need a new doc sections for LearnTransform and ApplyTransform.