# HG changeset patch
# User greg
# Date 1563971437 14400
# Node ID 0729a4b20e67120c695962e5891de2cad91b642d
Uploaded
diff -r 000000000000 -r 0729a4b20e67 .shed.yml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.shed.yml	Wed Jul 24 08:30:37 2019 -0400
@@ -0,0 +1,19 @@
+name: imagej2_adjust_threshold_binary
+owner: greg
+homepage_url: http://fiji.sc
+long_description: |
+  ImageJ2 is a new version of ImageJ for the next generation of multidimensional
+  image data, with a focus on scientific imaging.  Its central goal is to broaden
+  the paradigm of ImageJ beyond the limitations of ImageJ 1.x, to support the next
+  generation of multidimensional scientific imaging.
+
+  ImageJ2 is also a collection of reusable software libraries built on the SciJava
+  software stack, using a powerful plugin framework to facilitate rapid development
+  and painless user customization.
+
+  The Fiji distribution of ImageJ has shipped with beta versions of ImageJ2 for
+  quite some time.
+remote_repository_url: https://github.com/bgruening/galaxytools/tree/master/tools/image_processing/imagej2
+type: unrestricted
+categories:
+  - Imaging
diff -r 000000000000 -r 0729a4b20e67 imagej2_adjust_threshold_binary.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagej2_adjust_threshold_binary.py	Wed Jul 24 08:30:37 2019 -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( '--threshold_min', dest='threshold_min', type=float, help='Minimum threshold value' )
+parser.add_argument( '--threshold_max', dest='threshold_max', type=float, help='Maximum threshold value' )
+parser.add_argument( '--method', dest='method', help='Threshold method' )
+parser.add_argument( '--display', dest='display', help='Display mode' )
+parser.add_argument( '--black_background', dest='black_background', help='Black background' )
+parser.add_argument( '--stack_histogram', dest='stack_histogram', help='Stack histogram' )
+parser.add_argument( '--jython_script', dest='jython_script', help='Path to the Jython script' )
+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 )
+# 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( None, 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 += ' %.3f' % args.threshold_min
+cmd += ' %.3f' % args.threshold_max
+cmd += ' %s' % args.method
+cmd += ' %s' % args.display
+cmd += ' %s' % args.black_background
+cmd += ' %s' % args.stack_histogram
+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 )
diff -r 000000000000 -r 0729a4b20e67 imagej2_adjust_threshold_binary.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagej2_adjust_threshold_binary.xml	Wed Jul 24 08:30:37 2019 -0400
@@ -0,0 +1,115 @@
+
+
+    of binary image
+    
+        imagej2_macros.xml
+    
+    
+    
+    
+        
+        
+        
+        
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+        
+        
+            
+            
+            
+        
+        
+            
+            
+        
+        
+            
+            
+        
+    
+    
+        
+    
+    
+        
+            
+            
+            
+            
+            
+            
+            
+            
+            
+        
+        
+            
+            
+            
+            
+            
+            
+            
+            
+            
+        
+        
+            
+            
+            
+            
+            
+            
+            
+            
+            
+        
+    
+    
+
+@requires_binary_input@
+
+**What it does**
+
+
+
+    
+    
+
diff -r 000000000000 -r 0729a4b20e67 imagej2_adjust_threshold_binary_jython_script.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagej2_adjust_threshold_binary_jython_script.py	Wed Jul 24 08:30:37 2019 -0400
@@ -0,0 +1,49 @@
+import jython_utils
+import sys
+from ij import IJ
+
+# Fiji Jython interpreter implements Python 2.5 which does not
+# provide support for argparse.
+error_log = sys.argv[ -10 ]
+input = sys.argv[ -9 ]
+threshold_min = float( sys.argv[ -8 ] )
+threshold_max = float( sys.argv[ -7 ] )
+method = sys.argv[ -6 ]
+display = sys.argv[ -5 ]
+black_background = jython_utils.asbool( sys.argv[ -4 ] )
+# TODO: this is not being used.
+stack_histogram = jython_utils.asbool( 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 )
+
+# Create a copy of the image.
+input_image_plus_copy = input_image_plus.duplicate()
+image_processor_copy = input_image_plus_copy.getProcessor()
+
+try:
+    # Convert image to binary if necessary.
+    if not image_processor_copy.isBinary():
+        # Convert the image to binary grayscale.
+        IJ.run( input_image_plus_copy, "Make Binary","iterations=1 count=1 edm=Overwrite do=Nothing" )
+    # Set the options.
+    if black_background:
+        method_str = "%s dark" % method
+    else:
+        method_str = method
+    IJ.setAutoThreshold( input_image_plus_copy, method_str )
+    if display == "red":
+        display_mode = "Red"
+    elif display == "bw":
+        display_mode = "Black & White"
+    elif display == "over_under":
+        display_mode = "Over/Under"
+    IJ.setThreshold( input_image_plus_copy, threshold_min, threshold_max, display_mode )
+    # Run the command.
+    IJ.run( input_image_plus_copy, "threshold", "" )
+    # 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 ) )
diff -r 000000000000 -r 0729a4b20e67 imagej2_base_utils.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagej2_base_utils.py	Wed Jul 24 08:30:37 2019 -0400
@@ -0,0 +1,169 @@
+import os
+import shutil
+import sys
+import tempfile
+
+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 jvm_memory in [None, 'None']:
+        jvm_memory_str = ''
+    else:
+        jvm_memory_str = '-Xmx%s' % jvm_memory
+    # The following bunwarpj_base_cmd string will look something like this:
+    # "java %s -cp $JAR_DIR/ij-1.49k.jar:$PLUGINS_DIR/bUnwarpJ_-2.6.1.jar \
+    # bunwarpj.bUnwarpJ_" % (jvm_memory_str)
+    # See the bunwarpj.sh script for the fiji 20151222
+    # bioconda recipe in github.
+    bunwarpj_base_cmd = "bunwarpj %s" % jvm_memory_str
+    return bunwarpj_base_cmd
+
+
+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, but our bioconda recipe allows us to do this.
+    """
+    return 'ImageJ'
+
+
+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_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 ' %.3f' % val
+        elif val_type == 'int':
+            return ' %d' % val
+    return ' %s' % val
+
+
+def stop_err(msg):
+    sys.stderr.write(msg)
+    sys.exit(1)
diff -r 000000000000 -r 0729a4b20e67 imagej2_base_utils.pyc
Binary file imagej2_base_utils.pyc has changed
diff -r 000000000000 -r 0729a4b20e67 imagej2_macros.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagej2_macros.xml	Wed Jul 24 08:30:37 2019 -0400
@@ -0,0 +1,106 @@
+
+
+    20170530
+    
+        
+            fiji
+        
+    
+    
+        
+            
+            
+            
+            
+        
+    
+    
+        
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+        
+    
+    
+        
+        
+        
+            
+            
+        
+        
+            
+            
+        
+    
+    
+        
+            
+            
+        
+    
+    
+        --iterations $iterations
+        --count $count
+        --black_background $black_background
+        --pad_edges_when_eroding $pad_edges_when_eroding
+    
+    
+.. class:: warningmark
+
+This tool works on binary images, so other image types will automatically be converted to binary
+before they are analyzed.  This step is performed using the ImageJ2 **Make Binary** command with
+the following settings: **Iterations:** 1, **Count:** 1, **Pad edges when eroding:** No.  The tool
+allows you to choose the **Black background** setting.  If these settings are not appropriate,
+first manually convert the image to binary using the **Convert to binary (black and white)**
+tool, which allows you to change them.
+    
+    
+        
+        
+        
+        
+        
+    
+    
+        
+            
+                @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")
+            
+            10.1038/nmeth.2019
+        
+    
+    
+        
+            10.1038/nmeth.2102
+        
+    
+
diff -r 000000000000 -r 0729a4b20e67 jython_utils.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jython_utils.py	Wed Jul 24 08:30:37 2019 -0400
@@ -0,0 +1,48 @@
+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 asbool( val ):
+    return str( val ).lower() in [ 'yes', 'true' ]
+
+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_binary_options( black_background, iterations=1, count=1, pad_edges_when_eroding='no' ):
+    options = [ 'edm=Overwrite', 'iterations=%d' % iterations, 'count=%d' % count ]
+    if asbool( pad_edges_when_eroding ):
+        options.append( 'pad' )
+    if asbool( black_background ):
+        options.append( "black" )
+    return " ".join( options )
+
+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()
diff -r 000000000000 -r 0729a4b20e67 test-data/blobs.gif
Binary file test-data/blobs.gif has changed
diff -r 000000000000 -r 0729a4b20e67 test-data/blobs_threshold_default.gif
Binary file test-data/blobs_threshold_default.gif has changed
diff -r 000000000000 -r 0729a4b20e67 test-data/blobs_threshold_huang_dark.gif
Binary file test-data/blobs_threshold_huang_dark.gif has changed
diff -r 000000000000 -r 0729a4b20e67 test-data/blobs_threshold_ijiso.gif
Binary file test-data/blobs_threshold_ijiso.gif has changed