-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
morphological_operations
tool (#106)
* Add `morphological_operations` tool Squashed commit of the following: commit 0edf531 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 23:48:36 2024 +0100 Update test data commit cf17824 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 22:44:12 2024 +0000 Fix UI commit 9992a54 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 22:29:58 2024 +0000 Fix bug commit 5bb0d2c Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 23:26:35 2024 +0100 Update test output data commit d720124 Merge: 1408aab c57e084 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 22:22:47 2024 +0000 Merge branch 'add-morphology-tools' of https://github.com/kostrykin/galaxy-image-analysis into add-morphology-tools commit 1408aab Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 22:22:14 2024 +0000 Fix output type commit c57e084 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 23:16:53 2024 +0100 Add test results commit addf5c1 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 22:16:35 2024 +0000 Add more tests commit edf0dd5 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 22:07:40 2024 +0000 Fix bug commit 9094e30 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 21:44:13 2024 +0000 Fix tool commit 77bd875 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 21:40:00 2024 +0000 Fix tool commit 0884095 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 21:37:59 2024 +0000 Fix profile commit 3220ddb Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 21:37:05 2024 +0000 Add help commit 657018c Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 21:32:07 2024 +0000 Add citation commit 5df1d74 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 21:29:01 2024 +0000 Add tests for `morphological_operations` tool commit 59aa195 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 21:15:58 2024 +0000 Fix `morphological_operations` tool commit e048176 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 21:07:08 2024 +0000 Finish implementation of `morphological_operations` tool commit 106075c Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 18:56:08 2024 +0000 Continue implementation of `morphological_operations` tool commit 8057408 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 13:31:47 2024 +0000 Continue implementation of `morphological_operations` tool commit 442a459 Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 13:04:26 2024 +0000 Add `morphological_operations` tool commit 0ab2a2d Author: Leonid Kostrykin <[email protected]> Date: Thu Mar 7 12:58:35 2024 +0000 Add devcontainer.json with useful extensions * Delete .devcontainer/devcontainer.json * Update .gitignore with .devcontainer/ * Create styler.R --------- Co-authored-by: Björn Grüning <[email protected]>
- Loading branch information
Showing
17 changed files
with
271 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#!/usr/bin/env Rscript | ||
|
||
library("argparse") | ||
library("styler") | ||
|
||
parser <- ArgumentParser(description = "Call styler") | ||
parser$add_argument("dir", | ||
metavar = "DIR", type = "character", | ||
help = "File to parse" | ||
) | ||
parser$add_argument("--dry", | ||
choices = c("off", "on"), default = "on" | ||
) | ||
args <- parser$parse_args() | ||
|
||
file_info <- file.info(args$dir) | ||
is_directory <- file_info$isdir | ||
|
||
if (is_directory) { | ||
captured_output <- capture.output({ | ||
result <- style_dir(args$dir, indent_by = 4, dry = args$dry, recursive = TRUE) | ||
}) | ||
} else { | ||
captured_output <- capture.output({ | ||
result <- style_file(args$dir, indent_by = 4, dry = args$dry) | ||
}) | ||
} | ||
|
||
n <- nrow(subset(result, changed == TRUE)) | ||
if (n > 0) { | ||
if (args$dry == "off") { | ||
print(paste("Changed", n, "files")) | ||
} else { | ||
stop(paste("Linting failed for", n, "files")) | ||
} | ||
} |
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 |
---|---|---|
|
@@ -7,3 +7,4 @@ template_shed.yml | |
/create_csvs.py | ||
.DS_Store | ||
._* | ||
.devcontainer |
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,8 @@ | ||
categories: | ||
- Imaging | ||
description: Apply morphological operations to images | ||
long_description: Apply morphological operations to images. | ||
name: morphological_operations | ||
owner: imgteam | ||
homepage_url: https://github.com/bmcv | ||
remote_repository_url: https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/morphological_operations |
93 changes: 93 additions & 0 deletions
93
tools/morphological_operations/morphological_operations.py
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,93 @@ | ||
import argparse | ||
|
||
import numpy as np | ||
import scipy.ndimage as ndi | ||
import skimage.io | ||
import skimage.morphology as morph | ||
|
||
|
||
def create_selem(args): | ||
""" | ||
Creates structuring element based on commandline arguments. | ||
""" | ||
assert args.selem_shape in ( | ||
'square', | ||
'disk', | ||
) | ||
|
||
if args.selem_shape == 'square': | ||
return np.ones((args.selem_size, args.selem_size)) | ||
|
||
elif args.selem_shape == 'disk': | ||
return morph.disk(args.selem_size) | ||
|
||
|
||
def apply_operation(args, im): | ||
""" | ||
Applies morphological operation to a 2-D single-channel image. | ||
""" | ||
assert im.ndim == 2 | ||
selem = create_selem(args) | ||
values_count = len(np.unique(im)) | ||
if values_count <= 2: | ||
im_proxy = np.zeros(im.shape, bool) | ||
im_proxy[im == im.max()] = True | ||
result_proxy = apply_binary_operation(args, im_proxy, selem) | ||
result = np.full(im.shape, im.min(), im.dtype) | ||
result[result_proxy] = im.max() | ||
return result | ||
else: | ||
return apply_intensity_based_operation(args, im, selem) | ||
|
||
|
||
def apply_intensity_based_operation(args, im, selem): | ||
operations = { | ||
'erosion': ndi.grey_erosion, | ||
'dilation': ndi.grey_dilation, | ||
'opening': ndi.grey_opening, | ||
'closing': ndi.grey_closing, | ||
} | ||
if args.operation in operations: | ||
operation = operations[args.operation] | ||
return operation(input=im, structure=selem) | ||
else: | ||
raise ValueError(f'Operation "{args.operation}" not supported for this image type ({im.dtype}).') | ||
|
||
|
||
def apply_binary_operation(args, im, selem): | ||
operations = { | ||
'erosion': ndi.binary_erosion, | ||
'dilation': ndi.binary_dilation, | ||
'opening': ndi.binary_opening, | ||
'closing': ndi.binary_closing, | ||
'fill_holes': ndi.binary_fill_holes, | ||
} | ||
operation = operations[args.operation] | ||
return operation(input=im, structure=selem) | ||
|
||
|
||
if __name__ == '__main__': | ||
|
||
parser = argparse.ArgumentParser() | ||
parser.add_argument('--operation', type=str) | ||
parser.add_argument('--selem-shape', type=str) | ||
parser.add_argument('--selem-size', type=int) | ||
parser.add_argument('input', type=str) | ||
parser.add_argument('output', type=str) | ||
args = parser.parse_args() | ||
|
||
im = skimage.io.imread(args.input) | ||
assert im.ndim in (2, 3), 'Input image must be two-dimensional and either single-channel or multi-channel.' | ||
|
||
if im.ndim == 2: | ||
im_result = apply_operation(args, im) | ||
|
||
else: | ||
ch_result_list = [] | ||
for ch_idx in range(im.shape[2]): | ||
ch = im[:, :, ch_idx] | ||
ch_result = apply_operation(args, ch) | ||
ch_result_list.append(ch_result) | ||
im_result = np.dstack(ch_result_list) | ||
|
||
skimage.io.imsave(args.output, im_result) |
133 changes: 133 additions & 0 deletions
133
tools/morphological_operations/morphological_operations.xml
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,133 @@ | ||
<tool id="morphological_operations" name="Apply a morphological operation" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@" profile="23.0"> | ||
<description>with SciPy</description> | ||
<macros> | ||
<token name="@TOOL_VERSION@">1.12.0</token> | ||
<token name="@VERSION_SUFFIX@">0</token> | ||
</macros> | ||
<edam_operations> | ||
<edam_operation>operation_3443</edam_operation> | ||
</edam_operations> | ||
<xrefs> | ||
<xref type="biii">scipy</xref> | ||
</xrefs> | ||
<requirements> | ||
<requirement type="package" version="1.12.0">scipy</requirement> | ||
<requirement type="package" version="0.22.0">scikit-image</requirement> | ||
</requirements> | ||
<command><![CDATA[ | ||
## Inputs | ||
python '$__tool_directory__/morphological_operations.py' '$image' | ||
--operation $operation | ||
--selem-shape $selem_shape | ||
--selem-size $selem_size | ||
## Outputs | ||
./result.tiff | ||
]]> | ||
</command> | ||
<inputs> | ||
<param name="image" type="data" format="png,tiff" label="Input image" /> | ||
<param label="Morphological operation" argument="--operation" type="select"> | ||
<option value="erosion" selected="True">Erosion</option> | ||
<option value="dilation">Dilation</option> | ||
<option value="opening">Opening</option> | ||
<option value="closing">Closing</option> | ||
<option value="fill_holes">Fill holes</option> | ||
</param> | ||
<param label="Structuring element" argument="--selem-shape" type="select"> | ||
<option value="disk" selected="True">Disk</option> | ||
<option value="square">Square</option> | ||
</param> | ||
<param label="Structuring element size" argument="--selem-size" type="integer" min="1" max="256" value="1" help="The radius of the disk, or the width of the square, in pixels." /> | ||
</inputs> | ||
<outputs> | ||
<data format="tiff" name="result" from_work_dir="result.tiff" /> | ||
</outputs> | ||
<tests> | ||
<!-- Test binary operations (input images with two distinct values) --> | ||
<test> | ||
<param name="image" value="input1.tiff" /> | ||
<param name="operation" value="erosion" /> | ||
<param name="selem_shape" value="disk" /> | ||
<param name="selem_size" value="1" /> | ||
<output name="result" value="output1_erosion.tiff" ftype="tiff" compare="sim_size" delta="10" /> | ||
</test> | ||
<test> | ||
<param name="image" value="input1.tiff" /> | ||
<param name="operation" value="dilation" /> | ||
<param name="selem_shape" value="disk" /> | ||
<param name="selem_size" value="2" /> | ||
<output name="result" value="output1_dilation.tiff" ftype="tiff" compare="sim_size" delta="10" /> | ||
</test> | ||
<test> | ||
<param name="image" value="input1.tiff" /> | ||
<param name="operation" value="opening" /> | ||
<param name="selem_shape" value="square" /> | ||
<param name="selem_size" value="1" /> | ||
<output name="result" value="output1_opening.tiff" ftype="tiff" compare="sim_size" delta="10" /> | ||
</test> | ||
<test> | ||
<param name="image" value="input1.tiff" /> | ||
<param name="operation" value="closing" /> | ||
<param name="selem_shape" value="square" /> | ||
<param name="selem_size" value="2" /> | ||
<output name="result" value="output1_closing.tiff" ftype="tiff" compare="sim_size" delta="10" /> | ||
</test> | ||
<!-- Test intensity-based operations (more than two distinct values) --> | ||
<test> | ||
<param name="image" value="input3.png" /> | ||
<param name="operation" value="erosion" /> | ||
<param name="selem_shape" value="disk" /> | ||
<param name="selem_size" value="1" /> | ||
<output name="result" value="output3_erosion.tiff" ftype="tiff" compare="sim_size" delta="10" /> | ||
</test> | ||
<test> | ||
<param name="image" value="input3.png" /> | ||
<param name="operation" value="dilation" /> | ||
<param name="selem_shape" value="disk" /> | ||
<param name="selem_size" value="2" /> | ||
<output name="result" value="output3_dilation.tiff" ftype="tiff" compare="sim_size" delta="10" /> | ||
</test> | ||
<test> | ||
<param name="image" value="input3.png" /> | ||
<param name="operation" value="opening" /> | ||
<param name="selem_shape" value="square" /> | ||
<param name="selem_size" value="1" /> | ||
<output name="result" value="output3_opening.tiff" ftype="tiff" compare="sim_size" delta="10" /> | ||
</test> | ||
<test> | ||
<param name="image" value="input3.png" /> | ||
<param name="operation" value="closing" /> | ||
<param name="selem_shape" value="square" /> | ||
<param name="selem_size" value="2" /> | ||
<output name="result" value="output3_closing.tiff" ftype="tiff" compare="sim_size" delta="10" /> | ||
</test> | ||
<!-- Test multi-channel image (with two distinct values per channel) --> | ||
<test> | ||
<param name="image" value="input2.png" /> | ||
<param name="operation" value="fill_holes" /> | ||
<param name="selem_shape" value="disk" /> | ||
<param name="selem_size" value="1" /> | ||
<output name="result" value="output2_fill_holes.tiff" ftype="tiff" compare="sim_size" delta="10" /> | ||
</test> | ||
</tests> | ||
<help> | ||
Applies a morphological operation to a 2-D image. | ||
For multi-channel images, the operation is applied to each channel separately. | ||
|
||
The following operations are supported: | ||
|
||
- **Erosion:** Shrink bright areas. | ||
- **Dilation:** Grow bright areas. | ||
- **Opening:** Erosion followed by Dilation. Erases tiny bright spots. | ||
- **Closing:** Dilation followed by Erosion. Erases tiny dark holes. | ||
- **Fill holes:** Fills the holes (dark areas) in binary images. | ||
</help> | ||
<citations> | ||
<citation type="doi">10.1038/s41592-019-0686-2</citation> | ||
</citations> | ||
</tool> |
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.