changeset 1:db20f09300bd draft

planemo upload for repository https://github.com/labsyspharm/basic-illumination commit d62977a02ee6e0e5100479d6d7b19eb4a8cf9761
author goeckslab
date Thu, 01 Sep 2022 22:46:21 +0000
parents fd8dfd64f25e
children acc6f509968c
files basic_illumination.xml imagej_basic_ashlar.py imagej_basic_ashlar_filepattern.py macros.xml test-data/test.tiff
diffstat 5 files changed, 49 insertions(+), 346 deletions(-) [+]
line wrap: on
line diff
--- a/basic_illumination.xml	Fri Mar 12 00:13:46 2021 +0000
+++ b/basic_illumination.xml	Thu Sep 01 22:46:21 2022 +0000
@@ -1,16 +1,16 @@
-<tool id="basic_illumination" name="BaSiC Illumination" version="@VERSION@.3" profile="17.09">
+<tool id="basic_illumination" name="BaSiC Illumination" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@" profile="@PROFILE@">
     <description>ImageJ BaSiC shading correction for use with Ashlar</description>
     <macros>
         <import>macros.xml</import>
     </macros>
  
     <expand macro="requirements"/>
-    @VERSION_CMD@
+    <expand macro="version_cmd"/>
 
     <command detect_errors="exit_code"><![CDATA[
-    ln -s $in_files "${in_files.name}" &&
+    ln -s '$in_files' '${in_files.name}' &&
 
-    #set $outname = str($in_files.name).replace('.ome.tiff','')
+    #set $outname = str('$in_files.name').replace('.ome.tiff','')
 
     @CMD_BEGIN@
 
@@ -26,25 +26,30 @@
        <data format="tiff" name="output_dfp" label="${tool.name} on ${on_string}: DFP" from_work_dir="output-dfp.tif"/>
        <data format="tiff" name="output_ffp" label="${tool.name} on ${on_string}: FFP" from_work_dir="output-ffp.tif"/>
     </outputs>
-
+    <tests>
+        <test>
+            <param name="in_files" value="test.tiff" />
+            <output name="output_dfp" ftype="tiff">
+                <assert_contents>
+                    <has_size value="350000" delta="50000" />
+                </assert_contents>
+            </output>
+            <output name="output_ffp" ftype="tiff">
+                <assert_contents>
+                    <has_size value="350000" delta="50000" />
+                </assert_contents>
+            </output>
+        </test>
+    </tests>
     <help><![CDATA[
+-------------------        
 basic-illumination
-ImageJ BaSiC shading correction for use with Ashlar
-
-Running as a Docker container
-Create a container:
+-------------------
 
-docker run -it -v /path/to/data:/data labsyspharm/basic-illumination bash
-(where /path/to/data is the data directory on your local machine. Your data will be mapped to /data inside the container)
-
-Once inside the container, do ls /data to ensure your data is there, followed by
-
-ImageJ-linux64 --ij2 --headless --run imagej_basic_ashlar.py \
-  "filename='/data/input.ome.tiff',output_dir='/data/',experiment_name='my_experiment'"
-for each input.ome.tiff in your data directory.
-
-OHSU Wrapper Repo: https://github.com/ohsu-comp-bio/basic-illumination
-Conda Package Available From: https://anaconda.org/ohsu-comp-bio/basic-illumination
+**ImageJ BaSiC shading correction for use with Ashlar**
+**basic-illumination** can read image data directly from BioFormats-supported microscope
+vendor file formats as well as a directory of plain TIFF files. Output includes a flat field and
+dark field image per input file.
     ]]></help>
     <expand macro="citations" />
 </tool>
--- a/imagej_basic_ashlar.py	Fri Mar 12 00:13:46 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-# @File(label="Select a slide to process") filename
-# @File(label="Select the output location", style="directory") output_dir
-# @String(label="Experiment name (base name for output files)") experiment_name
-# @Float(label="Flat field smoothing parameter (0 for automatic)", value=0.1) lambda_flat
-# @Float(label="Dark field smoothing parameter (0 for automatic)", value=0.01) lambda_dark
-
-# Takes a slide (or other multi-series BioFormats-compatible file set) and
-# generates flat- and dark-field correction profile images with BaSiC. The
-# output format is two multi-series TIFF files (one for flat and one for dark)
-# which is the input format used by Ashlar.
-
-# Invocation for running from the commandline:
-#
-# ImageJ --ij2 --headless --run imagej_basic_ashlar.py "filename='input.ext',output_dir='output',experiment_name='my_experiment'"
-
-import sys
-from ij import IJ, WindowManager, Prefs
-from ij.macro import Interpreter
-from loci.plugins import BF
-from loci.plugins.in import ImporterOptions
-from loci.formats import ImageReader
-from loci.formats.in import DynamicMetadataOptions
-import BaSiC_ as Basic
-
-import pdb
-
-
-def main():
-
-    Interpreter.batchMode = True
-
-    if (lambda_flat == 0) ^ (lambda_dark == 0):
-        print ("ERROR: Both of lambda_flat and lambda_dark must be zero,"
-               " or both non-zero.")
-        return
-    lambda_estimate = "Automatic" if lambda_flat == 0 else "Manual"
-
-    print "Loading images..."
-
-    # For multi-scene .CZI files, we need raw tiles instead of the
-    # auto-stitched mosaic and we don't want labels or overview images.  This
-    # only affects BF.openImagePlus, not direct use of the BioFormats reader
-    # classes which we also do (see below)
-    Prefs.set("bioformats.zeissczi.allow.autostitch",  "false")
-    Prefs.set("bioformats.zeissczi.include.attachments", "false")
-
-    # Use BioFormats reader directly to determine dataset dimensions without
-    # reading every single image. The series count (num_images) is the one value
-    # we can't easily get any other way, but we might as well grab the others
-    # while we have the reader available.
-    dyn_options = DynamicMetadataOptions()
-    # Directly calling a BioFormats reader will not use the IJ Prefs settings
-    # so we need to pass these options explicitly.
-    dyn_options.setBoolean("zeissczi.autostitch", False)
-    dyn_options.setBoolean("zeissczi.attachments", False)
-    bfreader = ImageReader()
-    bfreader.setMetadataOptions(dyn_options)
-    bfreader.id = str(filename)
-    num_images = bfreader.seriesCount
-    num_channels = bfreader.sizeC
-    width = bfreader.sizeX
-    height = bfreader.sizeY
-    bfreader.close()
-
-    # The internal initialization of the BaSiC code fails when we invoke it via
-    # scripting, unless we explicitly set a the private 'noOfSlices' field.
-    # Since it's private, we need to use Java reflection to access it.
-    Basic_noOfSlices = Basic.getDeclaredField('noOfSlices')
-    Basic_noOfSlices.setAccessible(True)
-    basic = Basic()
-    Basic_noOfSlices.setInt(basic, num_images)
-
-    # Pre-allocate the output profile images, since we have all the dimensions.
-    ff_image = IJ.createImage("Flat-field", width, height, num_channels, 32);
-    df_image = IJ.createImage("Dark-field", width, height, num_channels, 32);
-
-    print("\n\n")
-
-    # BaSiC works on one channel at a time, so we only read the images from one
-    # channel at a time to limit memory usage.
-    for channel in range(num_channels):
-        print "Processing channel %d/%d..." % (channel + 1, num_channels)
-        print "==========================="
-
-        options = ImporterOptions()
-        options.id = str(filename)
-        options.setOpenAllSeries(True)
-        # concatenate=True gives us a single stack rather than a list of
-        # separate images.
-        options.setConcatenate(True)
-        # Limit the reader to the channel we're currently working on. This loop
-        # is mainly why we need to know num_images before opening anything.
-        for i in range(num_images):
-            options.setCBegin(i, channel)
-            options.setCEnd(i, channel)
-        # openImagePlus returns a list of images, but we expect just one (a
-        # stack).
-        input_image = BF.openImagePlus(options)[0]
-
-        # BaSiC seems to require the input image is actually the ImageJ
-        # "current" image, otherwise it prints an error and aborts.
-        WindowManager.setTempCurrentImage(input_image)
-        basic.exec(
-            input_image, None, None,
-            "Estimate shading profiles", "Estimate both flat-field and dark-field",
-            lambda_estimate, lambda_flat, lambda_dark,
-            "Ignore", "Compute shading only"
-        )
-        input_image.close()
-
-        # Copy the pixels from the BaSiC-generated profile images to the
-        # corresponding channel of our output images.
-        ff_channel = WindowManager.getImage("Flat-field:%s" % input_image.title)
-        ff_image.slice = channel + 1
-        ff_image.getProcessor().insert(ff_channel.getProcessor(), 0, 0)
-        ff_channel.close()
-        df_channel = WindowManager.getImage("Dark-field:%s" % input_image.title)
-        df_image.slice = channel + 1
-        df_image.getProcessor().insert(df_channel.getProcessor(), 0, 0)
-        df_channel.close()
-
-        print("\n\n")
-
-    template = '%s/%s-%%s.tif' % (output_dir, experiment_name)
-    ff_filename = template % 'ffp'
-    IJ.saveAsTiff(ff_image, ff_filename)
-    ff_image.close()
-    df_filename = template % 'dfp'
-    IJ.saveAsTiff(df_image, df_filename)
-    df_image.close()
-
-    print "Done!"
-
-
-main()
--- a/imagej_basic_ashlar_filepattern.py	Fri Mar 12 00:13:46 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,186 +0,0 @@
-# @String(label="Enter a filename pattern describing the TIFFs to process") pattern
-# @File(label="Select the output location", style="directory") output_dir
-# @String(label="Experiment name (base name for output files)") experiment_name
-# @Float(label="Flat field smoothing parameter (0 for automatic)", value=0.1) lambda_flat
-# @Float(label="Dark field smoothing parameter (0 for automatic)", value=0.01) lambda_dark
-
-# Takes a filename pattern describing a list of image files and generates flat-
-# and dark-field correction profile images with BaSiC. The pattern must contain
-# a "*" wildcard to indicate the part of the filename that varies with the image
-# series number. If the images are stored with one channel per file then the
-# pattern must also contain the placeholder {channel} in place of the channel
-# name or number. If the image files are multi-channel then the {channel}
-# placeholder must be omitted. The output format is two multi-channel TIFF files
-# (one for flat and one for dark) which is the input format used by Ashlar.
-
-# Invocation for running from the commandline:
-# (to match files like "s001_c1.tif", "s001_c2.tif", "s002_c1.tif", etc.)
-#
-# ImageJ --ij2 --headless --run imagej_basic_ashlar_filepattern.py "pattern='input/s*_c{channel}.tif',output_dir='output',experiment_name='my_experiment'"
-
-import sys
-import os
-import re
-import collections
-from ij import IJ, WindowManager, ImagePlus, ImageStack
-from ij.io import Opener
-from ij.macro import Interpreter
-import BaSiC_ as Basic
-
-
-def enumerate_filenames(pattern):
-    """Return filenames matching pattern (a glob pattern containing an optional
-    {channel} placeholder).
-
-    Returns a list of lists, where the top level is indexed by sorted channel
-    name/number and the bottom level is filenames for that channel.
-
-    """
-    (base, pattern) = os.path.split(pattern)
-    regex = re.sub(r'{([^:}]+)(?:[^}]*)}', r'(?P<\1>.*?)',
-                   pattern.replace('.', '\.').replace('*', '.*?'))
-    channels = set()
-    num_images = 0
-    # Dict[Union[int, str, None], List[str]]
-    filenames = collections.defaultdict(list)
-    for f in os.listdir(base):
-        match = re.match(regex, f)
-        if match:
-            gd = match.groupdict()
-            channel = gd.get('channel', None)
-            try:
-                channel = int(channel)
-            except (ValueError, TypeError):
-                pass
-            channels.add(channel)
-            filenames[channel].append(os.path.join(base, f))
-            num_images += 1
-    if num_images % len(channels) != 0:
-        print (
-            "ERROR: Some image files seem to be missing --"
-            " image count (%d) is not a multiple of channel count (%d)"
-            % (num_images, len(channels))
-        )
-        return []
-    channels = sorted(channels)
-    if len(channels) > 1:
-        print("Detected the following channel names/numbers from filenames:")
-        for channel in channels:
-            print("    %s" % channel)
-    filenames = [filenames[channel] for channel in channels]
-    return filenames
-
-
-def main():
-
-    Interpreter.batchMode = True
-
-    if (lambda_flat == 0) ^ (lambda_dark == 0):
-        print ("ERROR: Both of lambda_flat and lambda_dark must be zero,"
-               " or both non-zero.")
-        return
-    lambda_estimate = "Automatic" if lambda_flat == 0 else "Manual"
-
-    print "Loading images..."
-    filenames = enumerate_filenames(pattern)
-    if len(filenames) == 0:
-        return
-    # This is the number of channels inferred from the filenames. The number
-    # of channels in an individual image file will be determined below.
-    num_channels = len(filenames)
-    num_images = len(filenames[0])
-    image = Opener().openImage(filenames[0][0])
-    if image.getNDimensions() > 3:
-        print "ERROR: Can't handle images with more than 3 dimensions."
-    (width, height, channels, slices, frames) = image.getDimensions()
-    # The third dimension could be any of these three, but the other two are
-    # guaranteed to be equal to 1 since we know NDimensions is <= 3.
-    image_channels = max((channels, slices, frames))
-    image.close()
-    if num_channels > 1 and image_channels > 1:
-        print (
-            "ERROR: Can only handle single-channel images with {channel} in"
-            " the pattern, or multi-channel images without {channel}. The"
-            " filename patterns imply %d channels and the images themselves"
-            " have %d channels." % (num_channels, image_channels)
-        )
-        return
-    if image_channels == 1:
-        multi_channel = False
-    else:
-        print (
-            "Detected multi-channel image files with %d channels"
-            % image_channels
-        )
-        multi_channel = True
-        num_channels = image_channels
-        # Clone the filename list across all channels. We will handle reading
-        # the individual image planes for each channel below.
-        filenames = filenames * num_channels
-
-    # The internal initialization of the BaSiC code fails when we invoke it via
-    # scripting, unless we explicitly set a the private 'noOfSlices' field.
-    # Since it's private, we need to use Java reflection to access it.
-    Basic_noOfSlices = Basic.getDeclaredField('noOfSlices')
-    Basic_noOfSlices.setAccessible(True)
-    basic = Basic()
-    Basic_noOfSlices.setInt(basic, num_images)
-
-    # Pre-allocate the output profile images, since we have all the dimensions.
-    ff_image = IJ.createImage("Flat-field", width, height, num_channels, 32);
-    df_image = IJ.createImage("Dark-field", width, height, num_channels, 32);
-
-    print("\n\n")
-
-    # BaSiC works on one channel at a time, so we only read the images from one
-    # channel at a time to limit memory usage.
-    for channel in range(num_channels):
-        print "Processing channel %d/%d..." % (channel + 1, num_channels)
-        print "==========================="
-
-        stack = ImageStack(width, height, num_images)
-        opener = Opener()
-        for i, filename in enumerate(filenames[channel]):
-            print "Loading image %d/%d" % (i + 1, num_images)
-            # For multi-channel images the channel determines the plane to read.
-            args = [channel + 1] if multi_channel else []
-            image = opener.openImage(filename, *args)
-            stack.setProcessor(image.getProcessor(), i + 1)
-        input_image = ImagePlus("input", stack)
-
-        # BaSiC seems to require the input image is actually the ImageJ
-        # "current" image, otherwise it prints an error and aborts.
-        WindowManager.setTempCurrentImage(input_image)
-        basic.exec(
-            input_image, None, None,
-            "Estimate shading profiles", "Estimate both flat-field and dark-field",
-            lambda_estimate, lambda_flat, lambda_dark,
-            "Ignore", "Compute shading only"
-        )
-        input_image.close()
-
-        # Copy the pixels from the BaSiC-generated profile images to the
-        # corresponding channel of our output images.
-        ff_channel = WindowManager.getImage("Flat-field:%s" % input_image.title)
-        ff_image.slice = channel + 1
-        ff_image.getProcessor().insert(ff_channel.getProcessor(), 0, 0)
-        ff_channel.close()
-        df_channel = WindowManager.getImage("Dark-field:%s" % input_image.title)
-        df_image.slice = channel + 1
-        df_image.getProcessor().insert(df_channel.getProcessor(), 0, 0)
-        df_channel.close()
-
-        print("\n\n")
-
-    template = '%s/%s-%%s.tif' % (output_dir, experiment_name)
-    ff_filename = template % 'ffp'
-    IJ.saveAsTiff(ff_image, ff_filename)
-    ff_image.close()
-    df_filename = template % 'dfp'
-    IJ.saveAsTiff(df_image, df_filename)
-    df_image.close()
-
-    print "Done!"
-
-
-main()
--- a/macros.xml	Fri Mar 12 00:13:46 2021 +0000
+++ b/macros.xml	Thu Sep 01 22:46:21 2022 +0000
@@ -2,19 +2,38 @@
 <macros>
     <xml name="requirements">
         <requirements>
-            <requirement type="package" version="3.8">python</requirement>
-            <requirement type="package" version="1.0.2">basic-illumination</requirement>
+            <container type="docker">labsyspharm/basic-illumination:@TOOL_VERSION@</container>
         </requirements>
     </xml>
 
     <xml name="version_cmd">
-        <version_command>echo @VERSION@</version_command>
+        <version_command>echo @TOOL_VERSION@</version_command>
     </xml>
     <xml name="citations">
         <citations>
+            <citation type="doi">10.1038/ncomms14836</citation>
         </citations>
     </xml>
 
-    <token name="@VERSION@">1.0.2</token>
-    <token name="@CMD_BEGIN@">ImageJ --ij2 --headless --run ${__tool_directory__}/imagej_basic_ashlar.py</token>
+    <token name="@TOOL_VERSION@">1.0.3</token>
+    <token name="@VERSION_SUFFIX@">0</token>
+    <token name="@PROFILE@">19.01</token>
+    <token name="@CMD_BEGIN@"><![CDATA[
+        ## if ImageJ isn't already present, this is the docker-dependency version
+        ## as such, ImageJ needs to be registered as a global executable on $PATH
+
+        if ! [ -x "\$(which ImageJ)" ]; then
+	    ln -sf "\$(which ImageJ-linux64)" "ImageJ";
+            export PATH="\$PATH:\$(pwd)/";
+        fi &&
+
+        BASIC_SCRIPT="" &&
+        if [ -f "/opt/fiji/imagej_basic_ashlar.py" ]; then
+            export BASIC_SCRIPT="/opt/fiji/imagej_basic_ashlar.py";
+        else
+            export BASIC_SCRIPT="${__tool_directory__}/imagej_basic_ashlar.py";
+        fi &&
+
+        ImageJ --ij2 --headless --run \$BASIC_SCRIPT
+    ]]></token>
 </macros>
Binary file test-data/test.tiff has changed