changeset 0:66d9e595dff2 draft

planemo upload commit 98c34e070343a117019ffd25a3af117808159bf5-dirty
author iuc
date Tue, 04 Aug 2015 13:20:29 -0400
parents
children d26f11339f08
files imagej2_base_utils.py imagej2_macros.xml imagej2_make_binary.py imagej2_make_binary.xml jython_script.py jython_utils.py test-data/clown.jpg test-data/clown_binary.jpg tool_dependencies.xml
diffstat 9 files changed, 516 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagej2_base_utils.py	Tue Aug 04 13:20:29 2015 -0400
@@ -0,0 +1,178 @@
+import os
+import shutil
+import sys
+import tempfile
+
+FIJI_JAR_DIR = os.environ.get( 'FIJI_JAR_DIR', None )
+FIJI_OSX_JAVA3D_DIR = os.environ.get( 'FIJI_OSX_JAVA3D_DIR', None )
+FIJI_PLUGIN_DIR = os.environ.get( 'FIJI_PLUGIN_DIR', None )
+FIJI_ROOT_DIR = os.environ.get( 'FIJI_ROOT_DIR', None )
+
+BUFF_SIZE = 1048576
+
+def cleanup_before_exit( tmp_dir ):
+    """
+    Remove temporary files and directories prior to tool exit.
+    """
+    if tmp_dir and os.path.exists( tmp_dir ):
+        shutil.rmtree( tmp_dir )
+
+def get_base_cmd_bunwarpj( jvm_memory ):
+    if FIJI_JAR_DIR is not None and FIJI_PLUGIN_DIR is not None:
+        if jvm_memory in [ None, 'None' ]:
+            jvm_memory_str = ''
+        else:
+            jvm_memory_str = '-Xmx%s' % jvm_memory
+        bunwarpj_base_cmd = "java %s -cp %s/ij-1.49k.jar:%s/bUnwarpJ_-2.6.1.jar bunwarpj.bUnwarpJ_" % \
+            ( jvm_memory_str, FIJI_JAR_DIR, FIJI_PLUGIN_DIR )
+        return bunwarpj_base_cmd
+    return None
+
+def get_base_command_imagej2( memory_size=None, macro=None, jython_script=None ):
+    imagej2_executable = get_imagej2_executable()
+    if imagej2_executable is None:
+        return None
+    cmd = '%s --ij2 --headless --debug' % imagej2_executable
+    if memory_size is not None:
+        memory_size_cmd = ' -DXms=%s -DXmx=%s' % ( memory_size, memory_size )
+        cmd += memory_size_cmd
+    if macro is not None:
+        cmd += ' --macro %s' % os.path.abspath( macro )
+    if jython_script is not None:
+        cmd += ' --jython %s' % os.path.abspath( jython_script )
+    return cmd
+
+def get_file_extension( image_format ):
+    """
+    Return a valid bioformats file extension based on the received
+    value of image_format( e.g., "gif" is returned as ".gif".
+    """
+    return '.%s' % image_format
+
+def get_file_name_without_extension( file_path ):
+    """
+    Eliminate the .ext from the received file name, assuming that
+    the file name consists of only a single '.'.
+    """
+    if os.path.exists( file_path ):
+        path, name = os.path.split( file_path )
+        name_items = name.split( '.' )
+        return name_items[ 0 ]
+    return None
+
+def get_imagej2_executable():
+    """
+    Fiji names the ImageJ executable different names for different
+    architectures, so figure out which name we need.
+    """
+    platform_dict = get_platform_info_dict()
+    if platform_dict.get( 'architecture', None ) in [ 'x86_64' ]:
+        if platform_dict.get( 'os', None ) in [ 'darwin' ]:
+            return 'ImageJ-macosx'
+        if platform_dict.get( 'os', None ) in [ 'linux' ]:
+            return 'ImageJ-linux64'
+    return None
+    
+def get_input_image_path( tmp_dir, input_file, image_format ):
+    """
+    Bioformats uses file extensions (e.g., .job, .gif, etc)
+    when reading and writing image files, so the Galaxy dataset
+    naming convention of setting all file extensions as .dat
+    must be handled.
+    """
+    image_path = get_temporary_image_path( tmp_dir, image_format )
+    # Remove the file so we can create a symlink.
+    os.remove( image_path )
+    os.symlink( input_file, image_path )
+    return image_path
+
+def get_max_heap_size_value( max_heap_size_type, max_heap_size ):
+    """
+    Return a string that can be used by the javabridge to set the size
+    of the memory allocation pool used by the JVM.  The value must be
+    determined to be a multiple of 1024 or it will be ignored.
+    """
+    if max_heap_size_type == 'default':
+        return None
+    if max_heap_size_type == 'megabytes':
+        if int( max_heap_size ) % 1024 not in [ 0, 256, 512 ]:
+            return None
+        return '%sm' % str( max_heap_size )
+    if max_heap_size_type == 'gigabytes':
+        return '%sg' % str( max_heap_size )
+
+def get_platform_info_dict():
+    '''Return a dict with information about the current platform.'''
+    platform_dict = {}
+    sysname, nodename, release, version, machine = os.uname()
+    platform_dict[ 'os' ] = sysname.lower()
+    platform_dict[ 'architecture' ] = machine.lower()
+    return platform_dict
+
+def get_stderr_exception( tmp_err, tmp_stderr, tmp_out, tmp_stdout, include_stdout=False ):
+    tmp_stderr.close()
+    """
+    Return a stderr string of reasonable size.
+    """
+    # Get stderr, allowing for case where it's very large.
+    tmp_stderr = open( tmp_err, 'rb' )
+    stderr_str = ''
+    buffsize = BUFF_SIZE
+    try:
+        while True:
+            stderr_str += tmp_stderr.read( buffsize )
+            if not stderr_str or len( stderr_str ) % buffsize != 0:
+                break
+    except OverflowError:
+        pass
+    tmp_stderr.close()
+    if include_stdout:
+        tmp_stdout = open( tmp_out, 'rb' )
+        stdout_str = ''
+        buffsize = BUFF_SIZE
+        try:
+            while True:
+                stdout_str += tmp_stdout.read( buffsize )
+                if not stdout_str or len( stdout_str ) % buffsize != 0:
+                    break
+        except OverflowError:
+            pass
+    tmp_stdout.close()
+    if include_stdout:
+        return 'STDOUT\n%s\n\nSTDERR\n%s\n' % ( stdout_str, stderr_str )
+    return stderr_str
+
+def get_temp_dir( prefix='tmp-imagej-', dir=None ):
+    """
+    Return a temporary directory.
+    """
+    return tempfile.mkdtemp( prefix=prefix, dir=dir )
+
+def get_tempfilename( dir=None, suffix=None ):
+    """
+    Return a temporary file name.
+    """
+    fd, name = tempfile.mkstemp( suffix=suffix, dir=dir )
+    os.close( fd )
+    return name
+
+def get_temporary_image_path( tmp_dir, image_format ):
+    """
+    Return the path to a temporary file with a valid image format
+    file extension that can be used with bioformats.
+    """
+    file_extension = get_file_extension( image_format )
+    return get_tempfilename( tmp_dir, file_extension )
+
+def handle_none_type( val, val_type='float' ):
+    if val is None:
+        return ' None'
+    else:
+        if val_type == 'float':
+            return ' %.1f' % val
+        elif val_type == 'int':
+            return ' %d' % val
+
+def stop_err( msg ):
+    sys.stderr.write( msg )
+    sys.exit( 1 )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagej2_macros.xml	Tue Aug 04 13:20:29 2015 -0400
@@ -0,0 +1,126 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<macros>
+    <xml name="fiji_20141125_requirements">
+        <requirements>
+            <requirement type="package" version="20141125">fiji</requirement>
+        </requirements>
+    </xml>
+    <xml name="python_bioformats_104_requirements">
+        <requirements>
+            <requirement type="package" version="20141125">fiji</requirement>
+            <requirement type="package" version="1.0.11">javabridge</requirement>
+            <requirement type="package" version="1.9">numpy</requirement>
+            <requirement type="package" version="1.0.4">python_bioformats</requirement>
+        </requirements>
+    </xml>
+    <xml name="stdio">
+        <stdio>
+            <exit_code range="1:"/>
+            <exit_code range=":-1"/>
+            <regex match="Error:"/>
+            <regex match="Exception:"/>
+        </stdio>
+    </xml>
+    <xml name="image_type">
+        <param name="image_type" type="select" label="Image type">
+            <option value="8-bit_white" selected="True">8-bit white</option>
+            <option value="8-bit_black">8-bit black</option>
+            <option value="8-bit_random">8-bit random</option>
+            <option value="8-bit_ramp">8-bit ramp</option>
+            <option value="16-bit_white">16-bit white</option>
+            <option value="16-bit_black">16-bit black</option>
+            <option value="16-bit_random">16-bit random</option>
+            <option value="16-bit_ramp">16-bit ramp</option>
+            <option value="32-bit_white">32-bit white</option>
+            <option value="32-bit_black">32-bit black</option>
+            <option value="32-bit_random">32-bit random</option>
+            <option value="32-bit_ramp">32-bit ramp</option>
+            <option value="RGB_white">RGB white</option>
+            <option value="RGB_black">RGB black</option>
+            <option value="RGB_random">RGB random</option>
+            <option value="RGB_ramp">RGB ramp</option>
+        </param>
+    </xml>
+    <xml name="make_binary_params">
+        <param name="iterations" type="integer" value="1" min="1" max="100" label="Iterations" help="The number of times (1-100) erosion, dilation, opening, and closing are performed."/>
+        <param name="count" type="integer" value="1" min="1" max="8" label="Count" help="The number of adjacent background pixels necessary (1-8) for erosion or dilation."/>
+        <param name="black_background" type="select" label="Black background" help="If Yes, the background is black and the foreground is white (no implies the opposite).">
+            <option value="no" selected="True">No</option>
+            <option value="yes">Yes</option>
+        </param>
+        <param name="pad_edges_when_eroding" type="select" label="Pad edges when eroding" help="If Yes, eroding does not erode from the edges of the image.">
+            <option value="no" selected="True">No</option>
+            <option value="yes">Yes</option>
+        </param>
+    </xml>
+    <token name="@make_binary_args@">
+        --iterations $iterations
+        --count $count
+        --black_background $black_background
+        --pad_edges_when_eroding $pad_edges_when_eroding
+    </token>
+    <xml name="max_heap_size_type_conditional">
+        <conditional name="set_max_heap_size">
+            <param name="max_heap_size_type" type="select" label="Maximum size of the memory allocation pool used by the JVM" help="This value must be a multiple of 1024 or it will be ignored and the system default will be used.">
+                <option value="default" selected="True">Do not set</option>
+                <option value="megabytes">Set in megabytes</option>
+                <option value="gigabytes">Set in gigabytes</option>
+            </param>
+            <when value="default" >
+                <param name="max_heap_size" type="integer" value="0" hidden="true" label="Do not set" help="Use system default"/>
+            </when>
+            <when value="megabytes">
+                <param name="max_heap_size" type="integer" value="512" min="256" label="Maximum size, in megabytes, of the memory allocation pool" help="Examples: 256, 512, etc."/>
+            </when>
+            <when value="gigabytes">
+                <param name="max_heap_size" type="integer" value="1" min="1" label="Maximum size, in gigabytes, of the memory allocation pool" help="Examples: 1, 2, etc."/>
+            </when>
+        </conditional>
+    </xml>
+    <token name="@max_heap_size_args@">
+        --max_heap_size_type $set_max_heap_size.max_heap_size_type
+        --max_heap_size $set_max_heap_size.max_heap_size
+    </token>
+    <xml name="image_datatypes">
+        <option value="bmp">bmp</option>
+        <option value="gif">gif</option>
+        <option value="jpg">jpg</option>
+        <option value="png" selected="true">png</option>
+        <option value="tiff">tiff</option>
+    </xml>
+    <xml name="bunwarpj_citations">
+        <citations>
+            <citation type="bibtex">
+                @InProceedings(Arganda-Carreras2006,
+                    author =     "Ignacio Arganda-Carreras and
+                                        Carlos Oscar S{\'a}nchez Sorzano and
+                                        Roberto Marabini and
+                                        Jos{\'e} Mar\'{\i}a Carazo and
+                                        Carlos Ortiz-de-Solorzano and
+                                        Jan Kybic",
+                    title =          "Consistent and Elastic Registration of Histological Sections Using Vector-Spline Regularization",    
+                    publisher =  "Springer Berlin / Heidelberg",    
+                    booktitle =   "Computer Vision Approaches to Medical Image Analysis",
+                    series =       "Lecture Notes in Computer Science",
+                    year =          "2006",
+                    volume =      "4241",
+                    pages =       "85-95",
+                    month =       "May",
+                    city =            "Graz, Austria")
+            </citation>
+            <citation type="doi">10.1038/nmeth.2019</citation>
+        </citations>
+    </xml>
+    <xml name="fiji_headless_citations">
+        <citations>
+            <citation type="doi">10.1038/nmeth.2102</citation>
+        </citations>
+    </xml>
+    <xml name="bioformats_fiji_javabridge_citations">
+        <citations>
+            <citation type="doi">10.1038/nmeth.2102</citation>
+            <citation type="doi">10.1038/nmeth.2019</citation>
+            <citation type="doi">10.1083/jcb.201004104</citation>
+        </citations>
+    </xml>
+</macros>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagej2_make_binary.py	Tue Aug 04 13:20:29 2015 -0400
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+import argparse
+import os
+import shutil
+import subprocess
+import tempfile
+import imagej2_base_utils
+
+parser = argparse.ArgumentParser()
+parser.add_argument( '--input', dest='input', help='Path to the input file' )
+parser.add_argument( '--input_datatype', dest='input_datatype', help='Datatype of the input image' )
+parser.add_argument( '--iterations', dest='iterations', type=int, help='Iterations' )
+parser.add_argument( '--count', dest='count', type=int, help='Count' )
+parser.add_argument( '--black_background', dest='black_background', help='Black background' )
+parser.add_argument( '--pad_edges_when_eroding', dest='pad_edges_when_eroding', help='Pad edges when eroding' )
+parser.add_argument( '--jython_script', dest='jython_script', help='Path to the Jython script' )
+parser.add_argument( '--max_heap_size_type', dest='max_heap_size_type', help='Type (default or megabytes) of max_heap_size value' )
+parser.add_argument( '--max_heap_size', dest='max_heap_size', help='Maximum size of the memory allocation pool used by the JVM.' )
+parser.add_argument( '--output', dest='output', help='Path to the output file' )
+parser.add_argument( '--output_datatype', dest='output_datatype', help='Datatype of the output image' )
+args = parser.parse_args()
+
+tmp_dir = imagej2_base_utils.get_temp_dir()
+# ImageJ expects valid image file extensions, so the Galaxy .dat extension does not
+# work for some features.  The following creates a symlink with an appropriate file
+# extension that points to the Galaxy dataset.  This symlink is used by ImageJ.
+tmp_input_path = imagej2_base_utils.get_input_image_path( tmp_dir, args.input, args.input_datatype )
+tmp_output_path = imagej2_base_utils.get_temporary_image_path( tmp_dir, args.output_datatype )
+# Set the size of the memory allocation pool used by the JVM.
+memory_size = imagej2_base_utils.get_max_heap_size_value( args.max_heap_size_type, args.max_heap_size )
+# Define command response buffers.
+tmp_out = tempfile.NamedTemporaryFile().name
+tmp_stdout = open( tmp_out, 'wb' )
+tmp_err = tempfile.NamedTemporaryFile().name
+tmp_stderr = open( tmp_err, 'wb' )
+# Java writes a lot of stuff to stderr, so we'll specify a file for handling actual errors.
+error_log = tempfile.NamedTemporaryFile( delete=False ).name
+# Build the command line.
+cmd = imagej2_base_utils.get_base_command_imagej2( memory_size, jython_script=args.jython_script )
+if cmd is None:
+    imagej2_base_utils.stop_err( "ImageJ not found!" )
+cmd += ' %s' % error_log
+cmd += ' %s' % tmp_input_path
+cmd += ' %d' % args.iterations
+cmd += ' %d' % args.count
+cmd += ' %s' % args.black_background
+cmd += ' %s' % args.pad_edges_when_eroding
+cmd += ' %s' % tmp_output_path
+cmd += ' %s' % args.output_datatype
+# Run the command.
+proc = subprocess.Popen( args=cmd, stderr=tmp_stderr, stdout=tmp_stdout, shell=True )
+rc = proc.wait()
+# Handle execution errors.
+if rc != 0:
+    error_message = imagej2_base_utils.get_stderr_exception( tmp_err, tmp_stderr, tmp_out, tmp_stdout )
+    imagej2_base_utils.stop_err( error_message )
+# Handle processing errors.
+if os.path.getsize( error_log ) > 0:
+    error_message = open( error_log, 'r' ).read()
+    imagej2_base_utils.stop_err( error_message )
+# Save the output image.
+shutil.move( tmp_output_path, args.output )
+imagej2_base_utils.cleanup_before_exit( tmp_dir )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagej2_make_binary.xml	Tue Aug 04 13:20:29 2015 -0400
@@ -0,0 +1,65 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<tool id="imagej2_make_binary" name="Convert to binary" version="1.0.0">
+    <description>(black and white) with ImageJ2</description>
+    <macros>
+        <import>imagej2_macros.xml</import>
+    </macros>
+    <expand macro="fiji_20141125_requirements" />
+    <command>
+<![CDATA[
+    python $__tool_directory__/imagej2_make_binary.py
+    --input "$input"
+    --input_datatype $input.ext
+    @make_binary_args@
+    @max_heap_size_args@
+    --jython_script $__tool_directory__/jython_script.py
+    --output_datatype $output_datatype
+    --output "$output"
+]]>
+    </command>
+    <inputs>
+        <param format="bmp,eps,gif,jpg,pcx,pgm,png,psd,tiff" name="input" type="data" label="Select image"/>
+        <expand macro="make_binary_params" />
+        <param name="output_datatype" type="select" label="Save as format">
+            <expand macro="image_datatypes" />
+        </param>
+        <expand macro="max_heap_size_type_conditional" />
+    </inputs>
+    <outputs>
+        <data name="output" format_source="input" label="${tool.name} on ${on_string}">
+            <actions>
+                <action type="format">
+                    <option type="from_param" name="output_datatype" />
+                 </action>
+           </actions>
+       </data>
+    </outputs>
+    <tests>
+        <test>
+            <param name="input" value="clown.jpg" />
+            <param name="input_datatype" value="jpg" />
+            <param name="iterations" value="1" />
+            <param name="count" value="1" />
+            <param name="black_background" value="no" />
+            <param name="pad_edges_when_eroding" value="no" />
+            <param name="output_datatype" value="jpg" />
+            <output name="output" file="clown_binary.jpg" compare="sim_size" />
+        </test>
+    </tests>
+    <help>
+**What it does**
+
+<![CDATA[
+Converts an image into a binary (black and white) image by analyzing the histogram of
+the  entire image and setting an automatic threshold level to create the binary image.
+
+- **Iterations** - Specifies the number of times erosion, dilation, opening, and closing are performed.
+- **Count** - Specifies the number of adjacent background pixels necessary before a pixel is removed from the edge of an object during erosion and the number of adjacent foreground pixels necessary before a pixel is added to the edge of an object during dilation.
+- **Black background** - If **Yes**, binary images will be created without using an inverted LUT and an assumption that the input image contains white objects on a black background will be made.
+- **Pad edges when eroding** - If **Yes**, eroding does not erode from the edges of the image.
+
+]]>
+
+    </help>
+    <expand macro="fiji_headless_citations" />
+</tool>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jython_script.py	Tue Aug 04 13:20:29 2015 -0400
@@ -0,0 +1,41 @@
+import jython_utils
+import sys
+from ij import IJ
+from ij import ImagePlus
+
+# Fiji Jython interpreter implements Python 2.5 which does not
+# provide support for argparse.
+error_log = sys.argv[ -8 ]
+input = sys.argv[ -7 ]
+iterations = sys.argv[ -6 ]
+count = sys.argv[ -5 ]
+black_background = sys.argv[ -4 ]
+pad_edges_when_eroding = sys.argv[ -3 ]
+tmp_output_path = sys.argv[ -2 ]
+output_datatype = sys.argv[ -1 ]
+
+# Open the input image file.
+input_image_plus = IJ.openImage( input )
+bit_depth = input_image_plus.getBitDepth()
+image_type = input_image_plus.getType()
+
+# Create a copy of the image.
+input_image_plus_copy = input_image_plus.createImagePlus()
+image_processor_copy = input_image_plus.getProcessor().duplicate()
+input_image_plus_copy.setProcessor( "iCopy", image_processor_copy )
+
+try:
+    options = [ "iterations=&iterations" "count=&count" ]
+    if black_background == "yes":
+        options.append( "black" )
+    if pad_edges_when_eroding == "yes":
+        options.append( "pad" )
+    # The following have no affect within this tool, but are necessary.
+    options.append( "edm=Overwrite" )
+    options.append( "do=Nothing" )
+    # Run the command.
+    IJ.run( input_image_plus_copy, "Make Binary", " ".join( options ) )
+    # Save the ImagePlus object as a new image.
+    IJ.saveAs( input_image_plus_copy, output_datatype, tmp_output_path )
+except Exception, e:
+    jython_utils.handle_error( error_log, str( e ) )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jython_utils.py	Tue Aug 04 13:20:29 2015 -0400
@@ -0,0 +1,37 @@
+import imagej2_base_utils
+from ij import IJ
+
+IMAGE_PLUS_IMAGE_TYPE_FIELD_VALUES = { '0':'GRAY8', '1':'GRAY16', '2':'GRAY32',
+                                       '3':'COLOR_256', '4':'COLOR_RGB' }
+
+def convert_before_saving_as_tiff( image_plus ):
+    # The bUnwarpJ plug-in produces TIFF image stacks consisting of 3
+    # slices which can be viewed in ImageJ.  The 3 slices are: 1) the
+    # registered image, 2) the target image and 3) the black/white warp
+    # image.  When running bUnwarpJ from the command line (as these
+    # Galaxy wrappers do) the initial call to IJ.openImage() (to open the
+    # registered source and target images produced by bUnwarpJ) in the
+    # tool's jython_script.py returns an ImagePlus object with a single
+    # slice which is the "generally undesired" slice 3 discussed above.
+    # However, a call to IJ.saveAs() will convert the single-slice TIFF
+    # into a 3-slice TIFF image stack (as described above) if the selected
+    # format for saving is TIFF.  Galaxy supports only single-layered
+    # images, so to work around this behavior, we have to convert the
+    # image to something other than TIFF so that slices are eliminated.
+    # We can then convert back to TIFF for saving.  There might be a way
+    # to do this without converting twice, but I spent a lot of time looking
+    # and I have yet to discover it.
+    tmp_dir = imagej2_base_utils.get_temp_dir()
+    tmp_out_png_path = imagej2_base_utils.get_temporary_image_path( tmp_dir, 'png' )
+    IJ.saveAs( image_plus, 'png', tmp_out_png_path )
+    return IJ.openImage( tmp_out_png_path )
+
+def get_display_image_type( image_type ):
+    return IMAGE_PLUS_IMAGE_TYPE_FIELD_VALUES.get( str( image_type ), None )
+
+def handle_error( error_log, msg ):
+    # Java writes a lot of stuff to stderr, so the received error_log 
+    # will log actual errors.
+    elh = open( error_log, 'wb' )
+    elh.write( msg )
+    elh.close()
Binary file test-data/clown.jpg has changed
Binary file test-data/clown_binary.jpg has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tool_dependencies.xml	Tue Aug 04 13:20:29 2015 -0400
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<tool_dependency>
+    <package name="fiji" version="20141125">
+        <repository changeset_revision="9dbe89105a25" name="package_fiji_20141125" owner="iuc" toolshed="https://testtoolshed.g2.bx.psu.edu" />
+    </package>
+</tool_dependency>