Mercurial > repos > lldelisle > omero_hyperstack_to_gastruloid_measurements
changeset 2:45375dc5dd8d draft default tip
planemo upload for repository https://github.com/lldelisle/tools-lldelisle/tree/master/tools/omero_hyperstack_to_gastruloid_measurements commit 5e181f51312e53a72d354584439fa9359cd16723-dirty
author | lldelisle |
---|---|
date | Thu, 15 Feb 2024 12:28:09 +0000 |
parents | bd5771ff6aa3 |
children | |
files | 1-omero_timelapse_image_to_measurements_phase.groovy README.md omero_hyperstack_to_gastruloid_measurements.xml |
diffstat | 3 files changed, 263 insertions(+), 77 deletions(-) [+] |
line wrap: on
line diff
--- a/1-omero_timelapse_image_to_measurements_phase.groovy Wed Dec 20 20:07:13 2023 +0000 +++ b/1-omero_timelapse_image_to_measurements_phase.groovy Thu Feb 15 12:28:09 2024 +0000 @@ -5,11 +5,11 @@ // merge the analysis script with templates available at // https://github.com/BIOP/OMERO-scripts/tree/025047955b5c1265e1a93b259c1de4600d00f107/Fiji -// Last modification: 2023-12-20 +// Last modification: 2024-02-14 /* * = COPYRIGHT = - * © All rights reserved. ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, BioImaging And Optics Platform (BIOP), 2023 + * © All rights reserved. ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, BioImaging And Optics Platform (BIOP), 2024 * * Licensed under the BSD-3-Clause License: * Redistribution and use in source and binary forms, with or without modification, are permitted provided @@ -45,19 +45,22 @@ // The option 'rescue' allows to only process images without ROIs and // tables and generate the final table -// Without this option, the job will fail if a ROI or a table exists +// The option 'replace_at_runtime' allows to remove tables at start +// and ROIs on each image just before processing. -// If a final table exists it will fail in both modes +// The option 'use_existing' allows to +// Recompute only spine -// The option use_existing allows to -// Recompute only spine +// Without 'use_existing' or 'replace_at_runtime', the job will fail if a final table exists + +// Without 'use_existing' or 'replace_at_runtime' or 'rescue', the job will fail if ROI exists // This macro works both in headless // or GUI // In both modes, -// The result table and the result ROI are sent to omero -// The measures are: Area,Perim.,Circ.,Feret,FeretX,FeretY,FeretAngle,MinFeret,AR,Round,Solidity,Unit,Date,Version,IlastikProject,ProbabilityThreshold,MinSizeParticle,MinDiameter,ClosenessTolerance,MinSimilarity,RadiusMedian,BaseImage,ROI,Time,ROI_type,XCentroid,YCentroid,LargestRadius,SpineLength,ElongationIndex[,Date_rerun_spine,Version_rerun_spine] +// The result table and the result ROIs are sent to omero +// The measures are: Area,Perim.,Circ.,Feret,FeretX,FeretY,FeretAngle,MinFeret,AR,Round,Solidity,Unit,Date,Version,IlastikProject,ProbabilityThreshold,ThresholdingMethod,OptionsDo,OptionsIterations,OptionsCount,FillHolesBefore,RadiusMedian,MinSizeParticle,MinDiameter,ClosenessTolerance,MinSimilarity,BaseImage,ROI,Time,ROI_type,XCentroid,YCentroid,LargestRadius,SpineLength,ElongationIndex[,Date_rerun_spine,Version_rerun_spine] // LargestRadius and SpineLength are set to 0 if no circle was found. // ElongationIndex is set to 0 if a gastruloid was found and to -1 if no gastruloid was found. @@ -397,26 +400,39 @@ File ilastik_project, String ilastik_project_type, Integer ilastik_label_OI, Double probability_threshold, Double radius_median, - Integer min_size_particle, Boolean get_spine, - Integer minimum_diameter, Integer closeness_tolerance, Double min_similarity, + Double min_size_particle, Boolean get_spine, + Double minimum_diameter_um, Double closeness_tolerance_um, Double min_similarity, String ilastik_project_short_name, File output_directory, Boolean headless_mode, Boolean debug, String tool_version, Boolean use_existing, String final_object, Boolean rescue, Integer ilastik_label_BG, Double probability_threshold_BG, - Boolean keep_only_largest, String segmentation_method) { + Boolean keep_only_largest, String segmentation_method, + Boolean replace_at_runtime, + String thresholding_method, String options_do, + Integer options_iteration, Integer options_count, + Boolean fill_holes_before_median) { robustlyGetAll(dataset_wrp, "image", user_client).each{ ImageWrapper img_wrp -> + if (replace_at_runtime) { + List<ROIWrapper> rois = robustlyGetROIs(image_wrp, user_client) + if (!rois.isEmpty()) { + robustlyDeleteROIs(image_wrp, user_client, rois) + } + } processImage(user_client, img_wrp, ilastik_project, ilastik_project_type, ilastik_label_OI, probability_threshold, radius_median, min_size_particle, get_spine, - minimum_diameter, closeness_tolerance, min_similarity, + minimum_diameter_um, closeness_tolerance_um, min_similarity, ilastik_project_short_name, output_directory, headless_mode, debug, tool_version, use_existing, final_object, rescue, ilastik_label_BG, probability_threshold_BG, - keep_only_largest, segmentation_method) + keep_only_largest, segmentation_method, + thresholding_method, options_do, + options_iteration, options_count, + fill_holes_before_median) } } @@ -424,26 +440,34 @@ File ilastik_project, String ilastik_project_type, Integer ilastik_label_OI, Double probability_threshold, Double radius_median, - Integer min_size_particle, Boolean get_spine, - Integer minimum_diameter, Integer closeness_tolerance, Double min_similarity, + Double min_size_particle, Boolean get_spine, + Double minimum_diameter_um, Double closeness_tolerance_um, Double min_similarity, String ilastik_project_short_name, File output_directory, Boolean headless_mode, Boolean debug, String tool_version, Boolean use_existing, String final_object, Boolean rescue, Integer ilastik_label_BG, Double probability_threshold_BG, - Boolean keep_only_largest, String segmentation_method) { + Boolean keep_only_largest, String segmentation_method, + Boolean replace_at_runtime, + String thresholding_method, String options_do, + Integer options_iteration, Integer options_count, + Boolean fill_holes_before_median) { robustlyGetAll(plate_wrp, "well", user_client).each{ well_wrp -> processSingleWell(user_client, well_wrp, ilastik_project, ilastik_project_type, ilastik_label_OI, probability_threshold, radius_median, min_size_particle, get_spine, - minimum_diameter, closeness_tolerance, min_similarity, + minimum_diameter_um, closeness_tolerance_um, min_similarity, ilastik_project_short_name, output_directory, headless_mode, debug, tool_version, use_existing, final_object, rescue, ilastik_label_BG, probability_threshold_BG, - keep_only_largest, segmentation_method) + keep_only_largest, segmentation_method, + replace_at_runtime, + thresholding_method, options_do, + options_iteration, options_count, + fill_holes_before_median) } } @@ -451,41 +475,58 @@ File ilastik_project, String ilastik_project_type, Integer ilastik_label_OI, Double probability_threshold, Double radius_median, - Integer min_size_particle, Boolean get_spine, - Integer minimum_diameter, Integer closeness_tolerance, Double min_similarity, + Double min_size_particle, Boolean get_spine, + Double minimum_diameter_um, Double closeness_tolerance_um, Double min_similarity, String ilastik_project_short_name, File output_directory, Boolean headless_mode, Boolean debug, String tool_version, Boolean use_existing, String final_object, Boolean rescue, Integer ilastik_label_BG, Double probability_threshold_BG, - Boolean keep_only_largest, String segmentation_method) { + Boolean keep_only_largest, String segmentation_method, + Boolean replace_at_runtime, + String thresholding_method, String options_do, + Integer options_iteration, Integer options_count, + Boolean fill_holes_before_median) { well_wrp.getWellSamples().each{ - processImage(user_client, it.getImage(), + ImageWrapper img_wrp = it.getImage() + if (replace_at_runtime) { + List<ROIWrapper> rois = robustlyGetROIs(img_wrp, user_client) + if (!rois.isEmpty()) { + robustlyDeleteROIs(img_wrp, user_client, rois) + } + } + processImage(user_client, img_wrp, ilastik_project, ilastik_project_type, ilastik_label_OI, probability_threshold, radius_median, min_size_particle, get_spine, - minimum_diameter, closeness_tolerance, min_similarity, + minimum_diameter_um, closeness_tolerance_um, min_similarity, ilastik_project_short_name, output_directory, headless_mode, debug, tool_version, use_existing, final_object, rescue, ilastik_label_BG, probability_threshold_BG, - keep_only_largest, segmentation_method) + keep_only_largest, segmentation_method, + thresholding_method, options_do, + options_iteration, options_count, + fill_holes_before_median) } } def processImage(Client user_client, ImageWrapper image_wrp, File ilastik_project, String ilastik_project_type, // String ilastik_strategy, Integer ilastik_label_OI, - Double probability_threshold, Double radius_median, Integer min_size_particle, + Double probability_threshold, Double radius_median, Double min_size_particle, Boolean get_spine, - Integer minimum_diameter, Integer closeness_tolerance, Double min_similarity, + Double minimum_diameter_um, Double closeness_tolerance_um, Double min_similarity, String ilastik_project_short_name, File output_directory, Boolean headless_mode, Boolean debug, String tool_version, Boolean use_existing, String final_object, Boolean rescue, Integer ilastik_label_BG, Double probability_threshold_BG, - Boolean keep_only_largest, String segmentation_method) { + Boolean keep_only_largest, String segmentation_method, + String thresholding_method, String options_do, + Integer options_iteration, Integer options_count, + Boolean fill_holes_before_median) { IJ.run("Close All", "") IJ.run("Clear Results") @@ -584,7 +625,7 @@ use_existing = false rescue = false rois = robustlyGetROIs(image_wrp, user_client) - if (rois.size() > 0) { + if (!rois.isEmpty()) { // Clean existing ROIs robustlyDeleteROIs(image_wrp, user_client, rois) } @@ -693,17 +734,19 @@ // Get only the channel with bright field mask_imp = new Duplicator().run(imp, ilastik_input_ch, ilastik_input_ch, 1, 1, 1, nT); // Run convert to mask - (new Thresholder()).convertStackToBinary(mask_imp); + Thresholder my_thresholder = new Thresholder() + my_thresholder.setMethod(thresholding_method) + my_thresholder.setBackground("Light") + Prefs.blackBackground = true + my_thresholder.convertStackToBinary(mask_imp) } // This title will appear in the result table mask_imp.setTitle(image_basename) if (!headless_mode) { mask_imp.show() } - - // clean the mask a bit - // Before we were doing: - // IJ.run(mask_ilastik_imp, "Options...", "iterations=10 count=3 black do=Open") - // Now: - // (Romain proposed 5 as radius_median) + IJ.run(mask_imp, "Options...", "iterations=" + options_iteration + " count=" + options_count + " black do=" + options_do + " stack") + if (fill_holes_before_median) { + IJ.run(mask_imp, "Fill Holes", "stack") + } println "Smoothing mask" // Here I need to check if we first fill holes or first do the median @@ -714,7 +757,8 @@ // find gastruloids and measure them IJ.run("Set Measurements...", "area feret's perimeter shape display redirect=None decimal=3") - IJ.run("Set Scale...", "distance=1 known=" + scale + " unit=micron") + + IJ.run(mask_imp, "Set Scale...", "distance=1 known=" + scale + " unit=micron") pixelWidth = mask_imp.getCalibration().pixelWidth println "pixelWidth is " + pixelWidth // Exclude the edge @@ -732,6 +776,13 @@ for (int t=1;t<=nT;t++) { // Don't ask me why we need to refer to Z pos and not T/Frame ArrayList<Roi> all_rois_inT = ov.findAll{ roi -> roi.getZPosition() == t} + // When there is a single time the ROI has ZPosition to 0: + if (nT == 1) { + all_rois_inT = (ov as List) + if (all_rois_inT == null) { + all_rois_inT = [] + } + } println "There are " + all_rois_inT.size() + " in time " + t if (all_rois_inT.size() > 0) { largest_roi_inT = Collections.max(all_rois_inT, Comparator.comparing((roi) -> roi.getStatistics().area )) @@ -744,6 +795,9 @@ // Update the position before adding to the clean_overlay largest_roi_inT.setPosition( ilastik_input_ch, 1, t) clean_overlay.add(largest_roi_inT) + if (!headless_mode) { + rm.addRoi(largest_roi_inT) + } } } else { // We keep all @@ -752,6 +806,10 @@ ov.each{ Roi roi -> // Don't ask me why we need to refer to Z pos and not T/Frame t = roi.getZPosition() + // When there is a single time the ROI has ZPosition to 0: + if (nT == 1) { + t = 1 + } id = lastID[t - 1] + 1 roi.setName("Gastruloid_t" + t + "_id" + id) // Increase lastID: @@ -759,6 +817,9 @@ // Update the position before adding to the clean_overlay roi.setPosition( ilastik_input_ch, 1, t) clean_overlay.add(roi) + if (!headless_mode) { + rm.addRoi(roi) + } } // Fill timepoints with no ROI with notfound: Roi roi @@ -789,15 +850,21 @@ if (segmentation_method == "ilastik") { rt.setValue("IlastikProject", row, ilastik_project_short_name) rt.setValue("ProbabilityThreshold", row, probability_threshold) + rt.setValue("ThresholdingMethod", row, "NA") } else { rt.setValue("IlastikProject", row, "NA") rt.setValue("ProbabilityThreshold", row, "NA") + rt.setValue("ThresholdingMethod", row, thresholding_method) } + rt.setValue("OptionsDo", row, options_do) + rt.setValue("OptionsIterations", row, options_iteration) + rt.setValue("OptionsCount", row, options_count) + rt.setValue("FillHolesBefore", row, "" + fill_holes_before_median) + rt.setValue("RadiusMedian", row, radius_median) rt.setValue("MinSizeParticle", row, min_size_particle) - rt.setValue("MinDiameter", row, minimum_diameter) - rt.setValue("ClosenessTolerance", row, closeness_tolerance) + rt.setValue("MinDiameter", row, minimum_diameter_um) + rt.setValue("ClosenessTolerance", row, closeness_tolerance_um) rt.setValue("MinSimilarity", row, min_similarity) - rt.setValue("RadiusMedian", row, radius_median) String label = rt.getLabel(row) rt.setValue("BaseImage", row, label.split(":")[0]) rt.setValue("ROI", row, label.split(":")[1]) @@ -852,8 +919,8 @@ for ( int row = 0;row<rt.size();row++) { rt.setValue("Date_rerun_spine", row, now) rt.setValue("Version_rerun_spine", row, tool_version) - rt.setValue("MinDiameter", row, minimum_diameter) - rt.setValue("ClosenessTolerance", row, closeness_tolerance) + rt.setValue("MinDiameter", row, minimum_diameter_um) + rt.setValue("ClosenessTolerance", row, closeness_tolerance_um) rt.setValue("MinSimilarity", row, min_similarity) } // Remove any roi which is not gastruloid: @@ -896,7 +963,7 @@ mask_imp.setT(t) t_ov.fill(mask_imp, Color.white, Color.black) } - IJ.run("Set Scale...", "distance=1 known=" + scale + " unit=micron") + IJ.run(mask_imp, "Set Scale...", "distance=1 known=" + scale + " unit=micron") pixelWidth = mask_imp.getCalibration().pixelWidth println "pixelWidth is " + pixelWidth @@ -955,10 +1022,10 @@ isGetSpine = true appendPositionToName = false MaxInscribedCircles mic = MaxInscribedCircles.builder(mask_imp_single) - .minimumDiameter(minimum_diameter) + .minimumDiameter((int)(minimum_diameter_um / pixelWidth)) .useSelectionOnly(isSelectionOnly) .getSpine(isGetSpine) - .spineClosenessTolerance(closeness_tolerance) + .spineClosenessTolerance((int)(closeness_tolerance_um / pixelWidth)) .spineMinimumSimilarity(min_similarity) .appendPositionToName(appendPositionToName) .build() @@ -1096,7 +1163,7 @@ // In simple-omero-client // Strings that can be converted to double are stored in double // In order to build the super_table, tool_version should stay String -String tool_version = "White_v20231220" +String tool_version = "White_v20240214" // User set variables @@ -1111,16 +1178,26 @@ #@ String(visibility=MESSAGE, value="Parameters for segmentation/ROI", required=false) msg2 #@ Boolean(label="Use existing segmentation (values below in the section will be ignored)") use_existing +#@ Boolean(label="Replace ROIs and Tables") replace_at_runtime #@ String(label="Segmentation Method", choices={"convert_to_mask","ilastik"}) segmentation_method #@ Boolean(label="<html>Run in rescue mode<br/>(only segment images without tables)</html>", value=false) rescue +#@ String(label="Options do", choices={"Nothing", "Erode", "Dilate", "Open", "Close", "Outline", "Fill Holes", "Skeletonize"}) options_do +#@ Integer(label="Options iteration", min=1, value=1) options_iteration +#@ Integer(label="Options count", min=1, max=8, value=1) options_count +#@ Boolean(label="Fill holes before Median", value=false) fill_holes_before_median +#@ Double(label="Radius for median (=smooth the mask)", min=1, value=10) radius_median +#@ Double(label="Minimum surface for Analyze Particle", value=20000) min_size_particle +#@ Boolean(label="Keep only one gastruloid per timepoint", value=true) keep_only_largest + +#@ String(visibility=MESSAGE, value="Parameters for ilastik (ignore if you choose convert_to_mask)", required=false) msg2_1 #@ File(label="Ilastik project") ilastik_project #@ String(label="Ilastik project short name") ilastik_project_short_name #@ String(label="Ilastik project type", choices={"Regular", "Auto-context"}, value="Regular") ilastik_project_type #@ Integer(label="Ilastik label of interest", min=1, value=1) ilastik_label_OI #@ Double(label="Probability threshold for ilastik", min=0, max=1, value=0.65) probability_threshold -#@ Double(label="Radius for median (=smooth the mask)", min=1, value=20) radius_median -#@ Integer(label="Minimum surface for Analyze Particle", value=5000) min_size_particle -#@ Boolean(label="Keep only one gastruloid per timepoint", value=true) keep_only_largest + +#@ String(visibility=MESSAGE, value="Parameters for convert_to_mask (ignore if you choose ilastik)", required=false) msg2_2 +#@ String(label="Thresholding method", choices={"Default", "Huang", "Intermodes", "IsoData", "IJ_IsoData", "Li", "MaxEntropy", "Mean", "MinError", "Minimum", "Moments", "Otsu", "Percentile", "RenyiEntropy", "Shanbhag", "Triangle", "Yen"}) thresholding_method #@ String(visibility=MESSAGE, value="Parameters for segmentation/ROI of background", required=false) msg3 #@ Integer(label="Ilastik label of background (put 0 if not present)", min=0, value=1) ilastik_label_BG @@ -1128,8 +1205,8 @@ #@ String(visibility=MESSAGE, value="Parameters for elongation index", required=false) msg4 #@ Boolean(label="Compute spine", value=true) get_spine -#@ Integer(label="Minimum diameter of inscribed circles", min=0, value=20) minimum_diameter -#@ Integer(label="Closeness Tolerance (Spine)", min=0, value=50) closeness_tolerance +#@ Double(label="Minimum diameter of inscribed circles (um)", min=0, value=40) minimum_diameter_um +#@ Double(label="Closeness Tolerance (Spine) (um)", min=0, value=50) closeness_tolerance_um #@ Double(label="Min similarity (Spine)", min=-1, max=1, value=0.1) min_similarity #@ String(visibility=MESSAGE, value="Parameters for output", required=false) msg5 @@ -1140,6 +1217,9 @@ if (rescue && use_existing) { throw new Exception("rescue and use_existing modes are incompatible") } +if (replace_at_runtime && use_existing) { + throw new Exception("replace_at_runtime and use_existing modes are incompatible") +} if (use_existing && !get_spine) { throw new Exception("use_existing mode requires get_spine") } @@ -1204,12 +1284,20 @@ if (!use_existing) { List<TableWrapper> tables = robustlyGetTables(image_wrp, user_client) if (!tables.isEmpty()) { - throw new Exception("There should be no table associated to the image before segmentation. Please clean the image.") + if (replace_at_runtime) { + robustlyDeleteTables(image_wrp, user_client) + } else { + throw new Exception("There should be no table associated to the image before segmentation. Please clean the image.") + } } if (!rescue) { List<ROIWrapper> rois = robustlyGetROIs(image_wrp, user_client) if (!rois.isEmpty()) { - throw new Exception("There should be no ROIs associated to the image before segmentation. Please clean the image.") + if (replace_at_runtime) { + robustlyDeleteROIs(image_wrp, user_client, rois) + } else { + throw new Exception("There should be no ROIs associated to the image before segmentation. Please clean the image.") + } } } } @@ -1217,17 +1305,20 @@ ilastik_project, ilastik_project_type, ilastik_label_OI, probability_threshold, radius_median, min_size_particle, - get_spine, minimum_diameter, closeness_tolerance, min_similarity, + get_spine, minimum_diameter_um, closeness_tolerance_um, min_similarity, ilastik_project_short_name, output_directory, headless_mode, debug, tool_version, use_existing, "image", rescue, ilastik_label_BG, probability_threshold_BG, - keep_only_largest, segmentation_method) + keep_only_largest, segmentation_method, + thresholding_method, options_do, + options_iteration, options_count, + fill_holes_before_median) break case "dataset": DatasetWrapper dataset_wrp = robustlyGetOne(id, "dataset", user_client) - if (use_existing) { + if (use_existing || replace_at_runtime) { // Remove the tables associated to the dataset robustlyDeleteTables(dataset_wrp, user_client) } else if (rescue) { @@ -1244,20 +1335,24 @@ ilastik_project, ilastik_project_type, ilastik_label_OI, probability_threshold, radius_median, min_size_particle, - get_spine, minimum_diameter, closeness_tolerance, min_similarity, + get_spine, minimum_diameter_um, closeness_tolerance_um, min_similarity, ilastik_project_short_name, output_directory, headless_mode, debug, tool_version, use_existing, "dataset", rescue, ilastik_label_BG, probability_threshold_BG, - keep_only_largest, segmentation_method) + keep_only_largest, segmentation_method, + replace_at_runtime, + thresholding_method, options_do, + options_iteration, options_count, + fill_holes_before_median) // upload the table on OMERO super_table.setName(table_name + "_global") robustlyAddAndReplaceTable(dataset_wrp, user_client, super_table) break case "well": WellWrapper well_wrp = robustlyGetOne(id, "well", user_client) - if (use_existing) { + if (use_existing || replace_at_runtime) { // Remove the tables associated to the well robustlyDeleteTables(well_wrp, user_client) } else if (rescue) { @@ -1274,20 +1369,24 @@ ilastik_project, ilastik_project_type, ilastik_label_OI, probability_threshold, radius_median, min_size_particle, - get_spine, minimum_diameter, closeness_tolerance, min_similarity, + get_spine, minimum_diameter_um, closeness_tolerance_um, min_similarity, ilastik_project_short_name, output_directory, headless_mode, debug, tool_version, use_existing, "well", rescue, ilastik_label_BG, probability_threshold_BG, - keep_only_largest, segmentation_method) + keep_only_largest, segmentation_method, + replace_at_runtime, + thresholding_method, options_do, + options_iteration, options_count, + fill_holes_before_median) // upload the table on OMERO super_table.setName(table_name + "_global") robustlyAddAndReplaceTable(well_wrp, user_client, super_table) break case "plate": PlateWrapper plate_wrp = robustlyGetOne(id, "plate", user_client) - if (use_existing) { + if (use_existing || replace_at_runtime) { // Remove the tables associated to the plate robustlyDeleteTables(plate_wrp, user_client) } else if (rescue) { @@ -1304,13 +1403,17 @@ ilastik_project, ilastik_project_type, ilastik_label_OI, probability_threshold, radius_median, min_size_particle, - get_spine, minimum_diameter, closeness_tolerance, min_similarity, + get_spine, minimum_diameter_um, closeness_tolerance_um, min_similarity, ilastik_project_short_name, output_directory, headless_mode, debug, tool_version, use_existing, "plate", rescue, ilastik_label_BG, probability_threshold_BG, - keep_only_largest, segmentation_method) + keep_only_largest, segmentation_method, + replace_at_runtime, + thresholding_method, options_do, + options_iteration, options_count, + fill_holes_before_median) // upload the table on OMERO super_table.setName(table_name + "_global") robustlyAddAndReplaceTable(plate_wrp, user_client, super_table)
--- a/README.md Wed Dec 20 20:07:13 2023 +0000 +++ b/README.md Thu Feb 15 12:28:09 2024 +0000 @@ -1,7 +1,44 @@ # OMERO hyperstack to gastruloid measurements +## Set up user credentials on Galaxy to connect to other omero instance + +To enable users to set their credentials for this tool, +make sure the file `config/user_preferences_extra.yml` has the following section: + +``` + omero_account: + description: Your OMERO instance connection credentials + inputs: + - name: username + label: Username + type: text + required: False + - name: password + label: Password + type: password + required: False +``` + +## Dependencies + +This tool requires the channels: `--channel conda-forge --channel bioconda --channel defaults --channel pytorch --channel ilastik-forge`. + + ## CHANGELOG +### 20240214 + +- Update fiji, max_inscribed_circles, omero_ij, simple_omero_client +- Allow to do 'Replace at runtime' where it deletes the ROIs of the image before running the analysis on the image and remove all tables linked to the object on which the script is run. +- Add a parameter for the thresholding method when using 'convert_to_mask'. +- Allow to run 'Options...' and 'Fill Holes' between the mask and the median step. +- As a consequence the tables have more columns than before. +- Use um as unit for minimum_diameter and closeness_tolerance. +- Use Double for minimum_diameter_um, closeness_tolerance_um and min_size_particle +- Change the default of min_size_particle from 5000 to 20000. +- Change the default of minimume_diameter from 20 to 40. +- Change the default of radius_median from 20 to 10. + ### 20231220 - Add a new parameter: segmentation_method which can be 'ilastik' or 'convert_to_mask'. If 'convert_to_mask' is chosen, it does an autothreshold.
--- a/omero_hyperstack_to_gastruloid_measurements.xml Wed Dec 20 20:07:13 2023 +0000 +++ b/omero_hyperstack_to_gastruloid_measurements.xml Thu Feb 15 12:28:09 2024 +0000 @@ -1,6 +1,6 @@ <tool id="omero_hyperstack_to_gastruloid_measurements" name="Omero hyperstack to Gastruloid measurements" profile="20.01" version="@TOOL_VERSION@+galaxy0"> <macros> - <token name="@TOOL_VERSION@">20231220</token> + <token name="@TOOL_VERSION@">20240214</token> <xml name="segmentation"> <conditional name="use_ilastik"> <param name="segmentation_method" type="select" label="Segmentation method"> @@ -29,8 +29,28 @@ <param name="probability_threshold_BG" type="hidden" value="0"/> </when> </conditional> + <param name="thresholding_method" type="hidden" value="Default"/> </when> <when value="convert_to_mask"> + <param name="thresholding_method" type="select" label="Thresholding method" help="Method to use in the convert to mask"> + <option value="Default">Default</option> + <option value="Huang">Huang</option> + <option value="Intermodes">Intermodes</option> + <option value="IsoData">IsoData</option> + <option value="IJ_IsoData">IJ_IsoData</option> + <option value="Li">Li</option> + <option value="MaxEntropy">MaxEntropy</option> + <option value="Mean">Mean</option> + <option value="MinError">MinError</option> + <option value="Minimum">Minimum</option> + <option value="Moments">Moments</option> + <option value="Otsu">Otsu</option> + <option value="Percentile">Percentile</option> + <option value="RenyiEntropy">RenyiEntropy</option> + <option value="Shanbhag">Shanbhag</option> + <option value="Triangle">Triangle</option> + <option value="Yen">Yen</option> + </param> <param name="ilastik_project_type" type="hidden" value="Regular" /> <param name="ilastik_label_OI" type="hidden" value="3" /> <param name="probability_threshold" type="hidden" value="0" /> @@ -40,18 +60,34 @@ </section> </when> </conditional> - <param name="radius_median" type="float" value="20" label="Radius for median (=smooth the mask)" /> - <param name="min_size_particle" type="integer" min="0" value="5000" label="Minimum surface for Analyze Particle" /> + <section name="options" title="Options..." expanded="false" > + <param name="options_do" type="select" label="In Options... do=" help="Operation to perform after thresholding"> + <option value="Nothing">Nothing</option> + <option value="Erode">Erode</option> + <option value="Dilate">Dilate</option> + <option value="Open">Open</option> + <option value="Close">Close</option> + <option value="Outline">Outline</option> + <option value="Fill">Fill</option> + <option value="Holes">Holes</option> + <option value="Skeletonize">Skeletonize</option> + </param> + <param name="options_iteration" type="integer" min="1" value="1" label="In Options... iteration=" /> + <param name="options_count" type="integer" min="1" max="8" value="1" label="In Options... count=" /> + </section> + <param name="fill_holes_before_median" type="boolean" truevalue="true" falsevalue="false" checked="false" label="Fill holes before the Median..." /> + <param name="radius_median" type="float" value="10" label="Radius for median (=smooth the mask)" /> + <param name="min_size_particle" type="float" min="0" value="20000" label="Minimum surface for Analyze Particle" /> <param name="keep_only_largest" type="boolean" truevalue="true" falsevalue="false" checked="true" label="Keep only one gastruloid per timepoint" /> </xml> </macros> <requirements> - <requirement type="package" version="20220414">fiji</requirement> + <requirement type="package" version="20231211">fiji</requirement> <requirement type="package" version="3.7">python</requirement> - <requirement type="package" version="2.0.0">fiji-max_inscribed_circles</requirement> + <requirement type="package" version="2.1.0">fiji-max_inscribed_circles</requirement> <requirement type="package" version="1.8.2">fiji-ilastik</requirement> - <requirement type="package" version="5.8.0">fiji-omero_ij</requirement> - <requirement type="package" version="5.12.2">fiji-simple_omero_client</requirement> + <requirement type="package" version="5.8.3">fiji-omero_ij</requirement> + <requirement type="package" version="5.16.0">fiji-simple_omero_client</requirement> </requirements> <command detect_errors="exit_code"><![CDATA[ ## the user wants to use a non-public OMERO instance @@ -75,7 +111,7 @@ ## Because ilastik wants to write to ${HOME}/.cache and ${HOME}/.config export HOME=`pwd` && ImageJ-ilastik --ij2 --headless --console --run '$__tool_directory__/'1-omero_timelapse_image_to_measurements_phase.groovy - 'USERNAME="",PASSWORD="",credentials="${credentials}",host="${omero_host}",port="${omero_port}",object_type="${omero_object.object_type}",id="${omero_object.omero_id}",segmentation_method="${mode.use_ilastik.segmentation_method}",use_existing="${mode.use_existing}",ilastik_project="$ilastik_project_file",ilastik_project_short_name="$ilastik_project_name",ilastik_project_type="${mode.use_ilastik.ilastik_project_type}",ilastik_label_OI="${mode.use_ilastik.ilastik_label_OI}",probability_threshold="${mode.use_ilastik.probability_threshold}",radius_median="${mode.radius_median}",min_size_particle="${mode.min_size_particle}",get_spine="true",minimum_diameter="${minimum_diameter}",closeness_tolerance="${closeness_tolerance}",min_similarity="${min_similarity}",output_directory="output",debug="${debug}",rescue="${mode.rescue}",ilastik_label_BG="${mode.use_ilastik.background.ilastik_label_BG}",probability_threshold_BG="${mode.use_ilastik.background.probability_threshold_BG}",keep_only_largest="${mode.keep_only_largest}"' > output.log + 'USERNAME="",PASSWORD="",credentials="${credentials}",host="${omero_host}",port="${omero_port}",object_type="${omero_object.object_type}",id="${omero_object.omero_id}",segmentation_method="${mode.use_ilastik.segmentation_method}",use_existing="${mode.use_existing}",ilastik_project="$ilastik_project_file",ilastik_project_short_name="$ilastik_project_name",ilastik_project_type="${mode.use_ilastik.ilastik_project_type}",ilastik_label_OI="${mode.use_ilastik.ilastik_label_OI}",probability_threshold="${mode.use_ilastik.probability_threshold}",radius_median="${mode.radius_median}",min_size_particle="${mode.min_size_particle}",get_spine="true",minimum_diameter_um="${minimum_diameter_um}",closeness_tolerance_um="${closeness_tolerance_um}",min_similarity="${min_similarity}",output_directory="output",debug="${debug}",rescue="${mode.rescue}",ilastik_label_BG="${mode.use_ilastik.background.ilastik_label_BG}",probability_threshold_BG="${mode.use_ilastik.background.probability_threshold_BG}",keep_only_largest="${mode.keep_only_largest}",replace_at_runtime="${mode.replace_at_runtime}",thresholding_method="${mode.use_ilastik.thresholding_method}",options_do="${mode.options.options_do}",options_iteration="${mode.options.options_iteration}",options_count="${mode.options.options_count}",fill_holes_before_median="${mode.fill_holes_before_median}"' > output.log ]]> </command> <configfiles> @@ -113,17 +149,26 @@ </conditional> <conditional name="mode"> <param name="mode_select" type="select" label="Which mode do you want to use?" > + <option value="replace_existing">Replace existing (not recommanded with Ilastik)</option> + <option value="spine_only">Recompute only spine</option> <option value="regular">Regular (from scratch)</option> - <option value="spine_only">Recompute only spine</option> <option value="rescue">Rescue (if Regular did not go to the end)</option> </param> + <when value="replace_existing"> + <expand macro="segmentation"/> + <param name="replace_at_runtime" type="hidden" value="true"/> + <param name="rescue" type="hidden" value="false"/> + <param name="use_existing" type="hidden" value="false"/> + </when> <when value="regular"> <expand macro="segmentation"/> + <param name="replace_at_runtime" type="hidden" value="false"/> <param name="rescue" type="hidden" value="false"/> <param name="use_existing" type="hidden" value="false"/> </when> <when value="rescue"> <expand macro="segmentation"/> + <param name="replace_at_runtime" type="hidden" value="false"/> <param name="rescue" type="hidden" value="true"/> <param name="use_existing" type="hidden" value="false"/> </when> @@ -138,15 +183,16 @@ <param name="probability_threshold_BG" type="hidden" value="0"/> </section> </section> - <param name="radius_median" type="hidden" value="20" /> - <param name="min_size_particle" type="hidden" value="5000" /> + <param name="replace_at_runtime" type="hidden" value="false"/> + <param name="radius_median" type="hidden" value="10" /> + <param name="min_size_particle" type="hidden" value="20000" /> <param name="keep_only_largest" type="hidden" value="true"/> <param name="rescue" type="hidden" value="false"/> <param name="use_existing" type="hidden" value="true"/> </when> </conditional> - <param name="minimum_diameter" type="integer" min="0" value="20" label="Minimum diameter of inscribed circles" /> - <param name="closeness_tolerance" type="integer" min="0" value="50" label="Closeness Tolerance for the spine" help="Maximum distance between circles along the spine"/> + <param name="minimum_diameter_um" type="float" min="0" value="40" label="Minimum diameter of inscribed circles (in um)" /> + <param name="closeness_tolerance_um" type="float" min="0" value="50" label="Closeness Tolerance for the spine (in um)" help="Maximum distance between circles along the spine"/> <param name="min_similarity" type="float" min="-1" max="1" value="0.1" label="Min similarity for the spine" help="Close to 0 values allow more U shapes while close to 1 values only allows I shapes" /> <param name="debug" type="boolean" truevalue="true" falsevalue="false" checked="false" label="Debug the elongation index" help="This will output all inscribed circles" /> <param name="keep_intermediate" type="boolean" checked="false" label="Keep intermediate results (ilastik prediction + tables)" /> @@ -188,7 +234,7 @@ /* * = COPYRIGHT = - * © All rights reserved. ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, BioImaging And Optics Platform (BIOP), 2023 + * © All rights reserved. ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE, Switzerland, BioImaging And Optics Platform (BIOP), 2024 * * Licensed under the BSD-3-Clause License: * Redistribution and use in source and binary forms, with or without modification, are permitted provided