Skip to content

Commit

Permalink
feat(math): task and widget for image pair operations
Browse files Browse the repository at this point in the history
  • Loading branch information
qin-yu committed Dec 3, 2024
1 parent 8493d90 commit 4d141c8
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 2 deletions.
2 changes: 2 additions & 0 deletions plantseg/functionals/dataprocessing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
remove_false_positives_by_foreground_probability,
)
from plantseg.functionals.dataprocessing.dataprocessing import (
ImagePairOperation,
add_images,
compute_scaling_factor,
compute_scaling_voxelsize,
Expand Down Expand Up @@ -52,6 +53,7 @@
"fix_layout_to_YX",
"fix_layout",
# simple image operations
"ImagePairOperation",
"process_images",
"max_images",
"add_images",
Expand Down
5 changes: 4 additions & 1 deletion plantseg/functionals/dataprocessing/dataprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,10 +355,13 @@ def normalize_01_channel_wise(data: np.ndarray, channel_axis: int = 0, eps=1e-12
return np.moveaxis(normalized_channels, 0, channel_axis)


ImagePairOperation = Literal["add", "multiply", "subtract", "divide", "max"]


def process_images(
image1: np.ndarray,
image2: np.ndarray,
operation: str,
operation: ImagePairOperation,
normalize_input: bool = False,
clip_output: bool = False,
normalize_output: bool = True,
Expand Down
34 changes: 34 additions & 0 deletions plantseg/tasks/dataprocessing_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

from plantseg.core.image import ImageDimensionality, ImageLayout, PlantSegImage, SemanticType
from plantseg.functionals.dataprocessing import (
ImagePairOperation,
fix_over_under_segmentation_from_nuclei,
image_gaussian_smoothing,
image_rescale,
process_images,
relabel_segmentation,
remove_false_positives_by_foreground_probability,
set_biggest_instance_to_zero,
Expand Down Expand Up @@ -306,3 +308,35 @@ def relabel_segmentation_task(image: PlantSegImage, background: int | None = Non
new_data = relabel_segmentation(data, background=background)
new_image = image.derive_new(new_data, name=f"{image.name}_relabeled")
return new_image


@task_tracker
def image_pair_operation_task(
image1: PlantSegImage,
image2: PlantSegImage,
operation: ImagePairOperation,
normalize_input: bool = False,
clip_output: bool = False,
normalize_output: bool = False,
) -> PlantSegImage:
"""
Task to perform an operation on two images.
Args:
image1 (PlantSegImage): First image to process.
Image2 (PlantSegImage): Second image to process.
operation (str): Operation to perform on the images.
Returns:
PlantSegImage: New image resulting from the operation.
"""
result = process_images(

Check warning on line 333 in plantseg/tasks/dataprocessing_tasks.py

View check run for this annotation

Codecov / codecov/patch

plantseg/tasks/dataprocessing_tasks.py#L333

Added line #L333 was not covered by tests
image1.get_data(),
image2.get_data(),
operation=operation,
normalize_input=normalize_input,
clip_output=clip_output,
normalize_output=normalize_output,
)
new_image = image1.derive_new(result, name=f"{image1.name}_{operation}_{image2.name}")
return new_image

Check warning on line 342 in plantseg/tasks/dataprocessing_tasks.py

View check run for this annotation

Codecov / codecov/patch

plantseg/tasks/dataprocessing_tasks.py#L341-L342

Added lines #L341 - L342 were not covered by tests
2 changes: 2 additions & 0 deletions plantseg/viewer_napari/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
widget_filter_segmentation,
widget_fix_over_under_segmentation_from_nuclei,
widget_gaussian_smoothing,
widget_image_pair_operations,
widget_infos,
widget_open_file,
widget_proofreading_initialisation,
Expand Down Expand Up @@ -55,6 +56,7 @@ def get_preprocessing_tab():
widget_gaussian_smoothing,
widget_rescaling,
widget_cropping,
widget_image_pair_operations,
],
labels=False,
)
Expand Down
2 changes: 2 additions & 0 deletions plantseg/viewer_napari/widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
widget_cropping,
widget_fix_over_under_segmentation_from_nuclei,
widget_gaussian_smoothing,
widget_image_pair_operations,
widget_relabel,
widget_remove_false_positives_by_foreground,
widget_rescaling,
Expand Down Expand Up @@ -40,6 +41,7 @@
"widget_gaussian_smoothing",
"widget_rescaling",
"widget_cropping",
"widget_image_pair_operations",
# IO
"widget_open_file",
"widget_export_image",
Expand Down
65 changes: 64 additions & 1 deletion plantseg/viewer_napari/widgets/dataprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
from plantseg.core.zoo import model_zoo
from plantseg.io.voxelsize import VoxelSize
from plantseg.tasks.dataprocessing_tasks import (
ImagePairOperation,
fix_over_under_segmentation_from_nuclei_task,
gaussian_smoothing_task,
image_cropping_task,
image_pair_operation_task,
image_rescale_to_shape_task,
image_rescale_to_voxel_size_task,
relabel_segmentation_task,
Expand Down Expand Up @@ -114,7 +116,7 @@ def widget_cropping(

ps_image = PlantSegImage.from_napari_layer(image)

widgets_to_update = []
widgets_to_update = None

Check warning on line 119 in plantseg/viewer_napari/widgets/dataprocessing.py

View check run for this annotation

Codecov / codecov/patch

plantseg/viewer_napari/widgets/dataprocessing.py#L119

Added line #L119 was not covered by tests

return schedule_task(
image_cropping_task,
Expand Down Expand Up @@ -632,3 +634,64 @@ def widget_set_biggest_instance_to_zero(
},
widgets_to_update=widgets_to_update,
)


########################################################################################################################
# #
# Image Pair Operation Widget #
# #
########################################################################################################################


@magicgui(
call_button="Run Operation",
image1={
"label": "Image 1",
"tooltip": "First image to apply the operation.",
},
image2={
"label": "Image 2",
"tooltip": "Second image to apply the operation.",
},
operation={
"label": "Operation",
"choices": ImagePairOperation,
},
normalize_input={
"label": "Normalize input",
"tooltip": "Normalize the input images to the range [0, 1].",
},
clip_output={
"label": "Clip output",
"tooltip": "Clip the output to the range [0, 1].",
},
normalize_output={
"label": "Normalize output",
"tooltip": "Normalize the output image to the range [0, 1].",
},
)
def widget_image_pair_operations(
image1: Image,
image2: Image,
operation: ImagePairOperation = "add",
normalize_input: bool = False,
clip_output: bool = False,
normalize_output: bool = False,
) -> None:
"""Apply an operation to two image layers."""

ps_image1 = PlantSegImage.from_napari_layer(image1)
ps_image2 = PlantSegImage.from_napari_layer(image2)

Check warning on line 684 in plantseg/viewer_napari/widgets/dataprocessing.py

View check run for this annotation

Codecov / codecov/patch

plantseg/viewer_napari/widgets/dataprocessing.py#L683-L684

Added lines #L683 - L684 were not covered by tests

return schedule_task(

Check warning on line 686 in plantseg/viewer_napari/widgets/dataprocessing.py

View check run for this annotation

Codecov / codecov/patch

plantseg/viewer_napari/widgets/dataprocessing.py#L686

Added line #L686 was not covered by tests
image_pair_operation_task,
task_kwargs={
"image1": ps_image1,
"image2": ps_image2,
"operation": operation,
"normalize_input": normalize_input,
"clip_output": clip_output,
"normalize_output": normalize_output,
},
widgets_to_update=[],
)

0 comments on commit 4d141c8

Please sign in to comment.