Skip to content
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

Update "Threshold image" tool #109

Merged
merged 1 commit into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 21 additions & 19 deletions tools/2d_auto_threshold/auto_threshold.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,49 @@
"""
Copyright 2017-2022 Biomedical Computer Vision Group, Heidelberg University.
Copyright 2017-2024 Biomedical Computer Vision Group, Heidelberg University.

Distributed under the MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT

"""

import argparse

import numpy as np
import skimage.filters
import skimage.io
import skimage.util
import tifffile

thOptions = {
'otsu': lambda img_raw, bz: skimage.filters.threshold_otsu(img_raw),
'li': lambda img_raw, bz: skimage.filters.threshold_li(img_raw),
'yen': lambda img_raw, bz: skimage.filters.threshold_yen(img_raw),
'isodata': lambda img_raw, bz: skimage.filters.threshold_isodata(img_raw),
th_methods = {
'manual': lambda thres, **kwargs: thres,

'otsu': lambda img_raw, **kwargs: skimage.filters.threshold_otsu(img_raw),
'li': lambda img_raw, **kwargs: skimage.filters.threshold_li(img_raw),
'yen': lambda img_raw, **kwargs: skimage.filters.threshold_yen(img_raw),
'isodata': lambda img_raw, **kwargs: skimage.filters.threshold_isodata(img_raw),

'loc_gaussian': lambda img_raw, bz: skimage.filters.threshold_local(img_raw, bz, method='gaussian'),
'loc_median': lambda img_raw, bz: skimage.filters.threshold_local(img_raw, bz, method='median'),
'loc_mean': lambda img_raw, bz: skimage.filters.threshold_local(img_raw, bz, method='mean')
'loc_gaussian': lambda img_raw, bz, **kwargs: skimage.filters.threshold_local(img_raw, bz, method='gaussian'),
'loc_median': lambda img_raw, bz, **kwargs: skimage.filters.threshold_local(img_raw, bz, method='median'),
'loc_mean': lambda img_raw, bz, **kwargs: skimage.filters.threshold_local(img_raw, bz, method='mean')
}


def auto_thresholding(in_fn, out_fn, th_method, block_size=5, dark_bg=True):
def do_thresholding(in_fn, out_fn, th_method, block_size=5, threshold=0, invert_output=False):
img = skimage.io.imread(in_fn)
th = thOptions[th_method](img, block_size)
if dark_bg:
res = img > th
else:
res = img <= th
th = th_methods[th_method](img_raw=img, bz=block_size, thres=threshold)
res = img > th
if invert_output:
res = np.logical_not(res)
tifffile.imwrite(out_fn, skimage.util.img_as_ubyte(res))


if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Automatic Image Thresholding')
parser.add_argument('im_in', help='Path to the input image')
parser.add_argument('im_out', help='Path to the output image (TIFF)')
parser.add_argument('th_method', choices=thOptions.keys(), help='Thresholding method')
parser.add_argument('th_method', choices=th_methods.keys(), help='Thresholding method')
parser.add_argument('block_size', type=int, default=5, help='Odd size of pixel neighborhood for calculating the threshold')
parser.add_argument('dark_bg', default=True, type=bool, help='True if background is dark')
parser.add_argument('threshold', type=float, default=0, help='Manual thresholding value')
parser.add_argument('invert_output', default=False, type=bool, help='Values below/above the threshold are labeled with 0/255 if False, and with 255/0 otherwise')
args = parser.parse_args()

auto_thresholding(args.im_in, args.im_out, args.th_method, args.block_size, args.dark_bg)
do_thresholding(args.im_in, args.im_out, args.th_method, args.block_size, args.threshold, args.invert_output)
94 changes: 73 additions & 21 deletions tools/2d_auto_threshold/auto_threshold.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<tool id="ip_threshold" name="Threshold image" version="0.0.5-2" profile="20.05">
<tool id="ip_threshold" name="Threshold image" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@" profile="20.05">
<description>with scikit-image</description>
<macros>
<token name="@TOOL_VERSION@">0.18.1</token>
<token name="@VERSION_SUFFIX@">0</token>
</macros>
<edam_operations>
<edam_operation>operation_3443</edam_operation>
</edam_operations>
Expand All @@ -16,46 +20,94 @@
python '$__tool_directory__/auto_threshold.py'
'$input'
./out.tif
'$th_method'
'$block_size'
'$dark_bg'
'$th_method.method_id'
'$th_method.block_size'
'$th_method.threshold'
'$invert_output'
]]>
</command>
<inputs>
<param name="input" type="data" format="tiff,png" label="Input image" />
<param name="th_method" type="select" label="Thresholding method">
<option value="otsu" selected="True">Otsu</option>
<option value="li">Li's Minimum Cross Entropy</option>
<option value="isodata">Isodata</option>
<option value="yen">Yen</option>
<option value="loc_gaussian">Adaptive (Gaussian)</option>
<option value="loc_median">Adaptive (Median)</option>
<option value="loc_mean">Adaptive (Mean)</option>
</param>
<param name="block_size" type="integer" value="5" label="Odd size of pixel neighborhood for determining the threshold (only valid for adaptive thresholding methods)" />
<param name="dark_bg" type="boolean" checked="true" truevalue="True" falsevalue="False" label="Dark Background" />
<conditional name="th_method">
<param name="method_id" type="select" label="Thresholding method">
<option value="manual">Manual</option>
<option value="otsu" selected="True">Globally adaptive / Otsu</option>
<option value="li">Globally adaptive / Li's Minimum Cross Entropy</option>
<option value="isodata">Globally adaptive / Isodata</option>
<option value="yen">Globally adaptive / Yen</option>
<option value="loc_gaussian">Locally adaptive / Gaussian</option>
<option value="loc_median">Locally adaptive / Median</option>
<option value="loc_mean">Locally adaptive / Mean</option>
</param>
<when value="manual">
<param name="threshold" type="float" value="0" label="Threshold value" />
<param name="block_size" type="hidden" value="0" />
</when>
<when value="otsu">
<param name="threshold" type="hidden" value="0" />
<param name="block_size" type="hidden" value="0" />
</when>
<when value="li">
<param name="threshold" type="hidden" value="0" />
<param name="block_size" type="hidden" value="0" />
</when>
<when value="isodata">
<param name="threshold" type="hidden" value="0" />
<param name="block_size" type="hidden" value="0" />
</when>
<when value="yen">
<param name="threshold" type="hidden" value="0" />
<param name="block_size" type="hidden" value="0" />
</when>
<when value="loc_gaussian">
<param name="threshold" type="hidden" value="0" />
<param name="block_size" type="integer" value="5" label="Odd size of pixel neighborhood for determining the threshold" />
</when>
<when value="loc_median">
<param name="threshold" type="hidden" value="0" />
<param name="block_size" type="integer" value="5" label="Odd size of pixel neighborhood for determining the threshold" />
</when>
<when value="loc_mean">
<param name="threshold" type="hidden" value="0" />
<param name="block_size" type="integer" value="5" label="Odd size of pixel neighborhood for determining the threshold" />
</when>
</conditional>
<param name="invert_output" type="boolean" checked="false" truevalue="True" falsevalue="False" label="Invert output labels" help="Pixels are usually assigned the label 0 if the pixel value is below (or equal to) the threshold, and 255 if it is above the threshold. If this option is activated, pixels are assigned the label 255 if the pixel value is below (or equal to) the threshold, and 0 if it is above the threshold." />
</inputs>
<outputs>
<data format="tiff" name="output" from_work_dir="out.tif" />
</outputs>
<tests>
<test>
<param name="input" value="sample.tif"/>
<output name="output" value="out.tif" ftype="tiff" compare="sim_size"/>
<param name="th_method" value="loc_gaussian"/>
<output name="output" value="out.tif" ftype="tiff" compare="sim_size" delta="10"/>
<param name="method_id" value="loc_gaussian"/>
<param name="block_size" value="3"/>
<param name="dark_bg" value="True"/>
<param name="invert_output" value="False"/>
</test>
<test>
<param name="input" value="sample.tif"/>
<output name="output" value="out2.tif" ftype="tiff" compare="sim_size"/>
<param name="th_method" value="otsu"/>
<output name="output" value="out2.tif" ftype="tiff" compare="sim_size" delta="10"/>
<param name="method_id" value="otsu"/>
<param name="block_size" value="5"/>
<param name="dark_bg" value="True"/>
<param name="invert_output" value="False"/>
</test>
<test>
<param name="input" value="sample.tif"/>
<output name="output" value="out3.tif" ftype="tiff" compare="sim_size" delta="10"/>
<param name="method_id" value="manual"/>
<param name="threshold" value="64"/>
<param name="invert_output" value="True"/>
</test>
</tests>
<help>
Applies a standard thresholding algorithm to an image.

The thresholding algorithm automatically determines a threshold value (unless manual thresholding is used).
The input image is then thresholded, by assigning white (pixel value 255) to image regions above the determined threshold,
and black (pixel value 0) to image regions below or equal to the determined threshold.

The assignment of black and white to image regions below and above the threshold is inverted, if the corresponding option is set.
</help>
<citations>
<citation type="doi">10.1016/j.jbiotec.2017.07.019</citation>
Expand Down
Binary file added tools/2d_auto_threshold/test-data/out3.tif
Binary file not shown.