changeset 3:7fd8dba15bd3 draft

planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/superdsm/ commit fea6c8161c4b3e6394fe035b12b69b73e6fa7d75
author imgteam
date Thu, 16 Nov 2023 12:29:41 +0000
parents 244f67290d28
children dc5f72f6b1e9
files run-superdsm.py superdsm.xml test-data/cfg.tsv
diffstat 3 files changed, 158 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/run-superdsm.py	Mon Nov 13 22:12:35 2023 +0000
+++ b/run-superdsm.py	Thu Nov 16 12:29:41 2023 +0000
@@ -7,6 +7,7 @@
 """
 
 import argparse
+import csv
 import imghdr
 import os
 import pathlib
@@ -45,14 +46,25 @@
     return cfg
 
 
+def flatten_dict(d, sep='/'):
+    result = {}
+    for key, val in d.items():
+        if isinstance(val, dict):
+            for sub_key, sub_val in flatten_dict(val, sep=sep).items():
+                result[f'{key}{sep}{sub_key}'] = sub_val
+        else:
+            result[key] = val
+    return result
+
+
 if __name__ == "__main__":
     parser = argparse.ArgumentParser(description='Segmentation of cell nuclei in 2-D fluorescence microscopy images')
-    parser.add_argument('image', help='Path to the input image')
-    parser.add_argument('cfg', help='Path to the file containing the configuration')
-    parser.add_argument('masks', help='Path to the file containing the segmentation masks')
-    parser.add_argument('overlay', help='Path to the file containing the overlay of the segmentation results')
-    parser.add_argument('seg_border', type=int)
+    parser.add_argument('image', type=str, help='Path to the input image')
     parser.add_argument('slots', type=int)
+    parser.add_argument('--do-masks', type=str, default=None, help='Path to the file containing the segmentation masks')
+    parser.add_argument('--do-cfg', type=str, default=None, help='Path to the file containing the configuration')
+    parser.add_argument('--do-overlay', type=str, default=None, help='Path to the file containing the overlay of the segmentation results')
+    parser.add_argument('--do-overlay-border', type=int)
     for key, ptype in hyperparameters:
         parser.add_argument('--' + get_param_name(key), type=ptype, default=None)
     args = parser.parse_args()
@@ -83,13 +95,26 @@
         pipeline = superdsm.pipeline.create_default_pipeline()
         cfg = create_config(args)
         img = superdsm.io.imread(img_filepath)
-        data, cfg, _ = superdsm.automation.process_image(pipeline, cfg, img)
 
-        with open(args.cfg, 'w') as fp:
-            cfg.dump_json(fp)
+        if args.do_cfg:
+            print(f'Writing config to: {args.do_cfg}')
+            cfg, _ = superdsm.automation.create_config(pipeline, cfg, img)
+            with open(args.do_cfg, 'w') as fp:
+                tsv_out = csv.writer(fp, delimiter='\t')
+                tsv_out.writerow(['Hyperparameter', 'Value'])
+                for key, value in flatten_dict(cfg.entries).items():
+                    tsv_out.writerow([key, value])
 
-        overlay = superdsm.render.render_result_over_image(data, border_width=args.seg_border, normalize_img=False)
-        superdsm.io.imwrite(args.overlay, overlay)
+        if args.do_overlay or args.do_masks:
+            print('Performing segmentation')
+            data, cfg, _ = pipeline.process_image(img, cfg)
 
-        masks = superdsm.render.rasterize_labels(data)
-        superdsm.io.imwrite(args.masks, masks)
+        if args.do_overlay:
+            print(f'Writing overlay to: {args.do_overlay}')
+            overlay = superdsm.render.render_result_over_image(data, border_width=args.do_overlay_border, normalize_img=False)
+            superdsm.io.imwrite(args.do_overlay, overlay)
+
+        if args.do_masks:
+            print(f'Writing masks to: {args.do_masks}')
+            masks = superdsm.render.rasterize_labels(data)
+            superdsm.io.imwrite(args.do_masks, masks)
--- a/superdsm.xml	Mon Nov 13 22:12:35 2023 +0000
+++ b/superdsm.xml	Thu Nov 16 12:29:41 2023 +0000
@@ -1,5 +1,9 @@
-<tool id="ip_superdsm" name="Perform segmentation using deformable shape models" version="0.1.3+galaxy2" profile="20.05">
+<tool id="ip_superdsm" name="Perform segmentation using deformable shape models" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@" profile="20.05">
     <description>with SuperDSM</description>
+    <macros>
+        <token name="@TOOL_VERSION@">0.1.3</token>
+        <token name="@VERSION_SUFFIX@">3</token>
+    </macros>
     <edam_operations>
         <edam_operation>operation_3443</edam_operation>
     </edam_operations>
@@ -18,11 +22,22 @@
     <![CDATA[
     python '$__tool_directory__/run-superdsm.py'
     '${dataset}'
-    'cfg.json'
-    'masks.png'
-    'overlay.png'
-    $seg_border
     \${GALAXY_SLOTS:-4}
+    #if 'masks' in $outputs:
+        --do-masks 'masks.png'
+    #end if
+    #if 'cfg' in $outputs:
+        --do-cfg 'cfg.tsv'
+    #end if
+    #if 'overlay' in $outputs:
+        --do-overlay 'overlay.png'
+        #if $seg_border.value % 2 == 1:
+            #set $seg_border = "%d" % ($seg_border.value + 1)
+            --do-overlay-border $seg_border
+        #else:
+            --do-overlay-border $seg_border
+        #end if
+    #end if
     #if str($config.AF_scale) != '':
         --AF_scale '${config.AF_scale}'
     #end if
@@ -72,7 +87,12 @@
     </environment_variables>
     <inputs>
         <param name="dataset" type="data" format="tiff,png" label="Dataset" />
-        <param name="seg_border" type="integer" min="1" value="8" label="Width of the outlines (in pixels) of the segmentation results (overlays)" />
+        <param name="outputs" type="select" label="Outputs" multiple="true" optional="false">
+            <option value="overlay" selected="true">Create a segmentation overlay</option>
+            <option value="masks">Create a label map (e.g., for further processing)</option>
+            <option value="cfg">Report all hyperparameters (manually set and automatically determined values)</option>
+        </param>
+        <param name="seg_border" type="integer" min="1" value="8" label="Width of the outlines (in pixels)" help="This parameter is only used for segmentation overlays (see above)." />
         <section name="config" title="Hyperparameters" expanded="false">
             <param argument="--AF_scale" optional="true" type="float" value="" min="0" label="scale σ" help="The scale of the objects to be segmented. Leave empty to use the automatically determined value." />
             <param argument="--c2f_region_analysis_min_atom_radius" optional="true" type="float" value="" min="0" label="min_atom_radius" help="No region determined by the Coarse-to-fine region analysis scheme is smaller than a circle of this radius (in terms of the surface area). Leave empty to use the automatically determined value." />
@@ -91,14 +111,27 @@
         </section>
     </inputs>
     <outputs>
-        <data format="json" name="cfg" from_work_dir="cfg.json" label="${tool.name} on ${on_string}: cfg" />
-        <data format="png" name="masks" from_work_dir="masks.png" label="${tool.name} on ${on_string}: masks" />
-        <data format="png" name="overlay" from_work_dir="overlay.png" label="${tool.name} on ${on_string}: overlay" />
+        <data format="png" name="masks" from_work_dir="masks.png" label="${tool.name} on ${on_string}: masks">
+            <filter>'masks' in outputs</filter>
+        </data>
+        <data format="tsv" name="cfg" from_work_dir="cfg.tsv" label="${tool.name} on ${on_string}: cfg">
+            <filter>'cfg' in outputs</filter>
+        </data>
+        <data format="png" name="overlay" from_work_dir="overlay.png" label="${tool.name} on ${on_string}: overlay">
+            <filter>'overlay' in outputs</filter>
+        </data>
     </outputs>
     <tests>
-        <test>
+        <test expect_num_outputs="3">
             <param name="dataset" value="BBBC033_C2_z28.png" />
+            <param name="outputs" value="overlay,masks,cfg" />
             <output name="overlay" value="overlay.png" ftype="png" compare="sim_size" />
+            <output name="cfg" value="cfg.tsv" ftype="tsv" compare="sim_size" />
+        </test>
+        <test expect_num_outputs="1">
+            <param name="dataset" value="BBBC033_C2_z28.png" />
+            <param name="outputs" value="cfg" />
+            <output name="cfg" value="cfg.tsv" ftype="tsv" compare="sim_size" />
         </test>
     </tests>
     <help>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/cfg.tsv	Thu Nov 16 12:29:41 2023 +0000
@@ -0,0 +1,78 @@
+Hyperparameter	Value
+c2f_region_analysis_min_norm_energy_improvement	0.1
+c2f_region_analysis_max_atom_norm_energy	0.05
+c2f_region_analysis_max_cluster_marker_irregularity	0.2
+dsm_AF_alpha	0.0005
+global_energy_minimization_AF_beta	0.66
+postprocess_mask_max_distance	1
+postprocess_mask_stdamp	2.0
+postprocess_max_norm_energy	0.2
+postprocess_min_contrast	1.35
+postprocess_min_object_radius	0.0
+AF_scale	
+preprocess/AF_sigma2	1.0
+preprocess/sigma2	65.05382386916237
+preprocess/enabled	True
+preprocess/sigma1	1.4142135623730951
+preprocess/offset_clip	3
+preprocess/lower_clip_mean	False
+dsm/AF_alpha	0.0005
+dsm/alpha	2.116
+dsm/AF_smooth_amount	0.2
+dsm/smooth_amount	13
+dsm/AF_smooth_subsample	0.4
+dsm/smooth_subsample	26
+dsm/AF_background_margin	0.4
+dsm/background_margin	26
+dsm/enabled	True
+dsm/cachesize	1
+dsm/cachetest	
+dsm/sparsity_tol	0
+dsm/init	elliptical
+dsm/epsilon	1.0
+dsm/scale	1000
+dsm/gaussian_shape_multiplier	2
+dsm/smooth_mat_dtype	float32
+dsm/smooth_mat_max_allocations	inf
+dsm/cp_timeout	300
+c2f-region-analysis/AF_min_atom_radius	0.33
+c2f-region-analysis/min_atom_radius	30
+c2f-region-analysis/enabled	True
+c2f-region-analysis/seed_connectivity	8
+c2f-region-analysis/max_atom_norm_energy	0.05
+c2f-region-analysis/min_norm_energy_improvement	0.1
+c2f-region-analysis/max_cluster_marker_irregularity	0.2
+global-energy-minimization/AF_beta	0.66
+global-energy-minimization/beta	2793.1200000000003
+global-energy-minimization/AF_max_seed_distance	inf
+global-energy-minimization/max_seed_distance	inf
+global-energy-minimization/enabled	True
+global-energy-minimization/strict	True
+global-energy-minimization/max_iter	5
+global-energy-minimization/gamma	0.8
+global-energy-minimization/max_work_amount	1000000
+postprocess/AF_min_object_radius	0.0
+postprocess/min_object_radius	0.0
+postprocess/AF_max_object_radius	inf
+postprocess/max_object_radius	inf
+postprocess/AF_min_glare_radius	inf
+postprocess/min_glare_radius	inf
+postprocess/enabled	True
+postprocess/max_norm_energy	0.2
+postprocess/discard_image_boundary	False
+postprocess/min_boundary_obj_radius	0
+postprocess/max_eccentricity	0.99
+postprocess/max_boundary_eccentricity	inf
+postprocess/exterior_scale	5
+postprocess/exterior_offset	5
+postprocess/min_contrast	1.35
+postprocess/contrast_epsilon	0.0001
+postprocess/mask_stdamp	2
+postprocess/mask_max_distance	1
+postprocess/mask_smoothness	3
+postprocess/fill_holes	True
+postprocess/glare_detection_smoothness	3
+postprocess/glare_detection_num_layers	5
+postprocess/glare_detection_min_layer	0.5
+postprocess/min_boundary_glare_radius	inf
+histological	False