changeset 2:3c3cd68d6d5a draft

"planemo upload for repository https://github.com/bgruening/galaxytools/tree/master/tools commit 1907942bef43b20edfdbd1d1b5eb1cac3602848b"
author bgruening
date Thu, 16 Apr 2020 05:29:02 -0400
parents 0b7db679fff8
children 27396311a314
files common.xml cp_common_functions.py image_math.py macros.xml starting_modules.xml test-data/common_image_math.cppipe test-data/image_math_1.cppipe test-data/image_math_2.cppipe test-data/image_math_3.cppipe
diffstat 9 files changed, 1139 insertions(+), 481 deletions(-) [+]
line wrap: on
line diff
--- a/common.xml	Thu Apr 09 08:12:15 2020 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,458 +0,0 @@
-<tool id="cp_common" name="cellProfiler common start modules" version="@CP_VERSION@">
-    <description>load images and metadata into cellProfiler</description>
-    <macros>
-        <import>macros.xml</import>
-        <xml name="image_type_condition"> 
-            <conditional name="con_set_intensity">
-                <param name="set_intensity_range_from" type="select" label="Set intensity range from">
-                    <option value="Image metadata">Image metadata</option>
-                    <option value="Image bit-depth">Image bit-depth</option>
-                    <option value="Manual">Manual</option>
-                </param>
-                <when value="Manual">
-                    <param name="maximum_intensity" type="float" value="255.0" label="Maximum intensity"/>
-                </when>
-                <when value="Image metadata" />
-                <when value="Image bit-depth" />               
-            </conditional>
-        </xml>
-        <xml name="name_type_rule_matching_file">
-            <param name="operator" type="select">
-                <option value="does">Does</option>
-                <option value="doesnot">Does not</option>
-            </param>
-            <param name="contain" type="select">
-                <option value="contain">Contain</option>
-                <option value="Contain regular expression">Contain regular expression</option>
-                <option value="startwith">Start with</option>
-                <option value="endwith">End with</option>
-                <option value="Exactly match">Exactly match</option>
-            </param>
-            <param name="match_value" type="text"/>
-        </xml>
-        <xml name="image_matching_rules">
-            <repeat name="r_match_rule" title="Rules">
-                <param name="match_all_any" type="select" display="radio" label="Match the following rules">
-                    <option value="and">All</option>
-                    <option value="or">Any</option>
-                </param>
-                <conditional name="con_match">
-                      <param name="rule_type" type="select" label="Select rule criteria">
-                          <option value="file">File</option>
-                          <option value="directory">Directory</option>
-                          <option value="extension">Extension</option>
-                          <option value="image">Image</option>
-                          <option value="metadata">Metadata</option>
-                      </param>
-                      <when value="file">
-                          <expand macro="name_type_rule_matching_file"/>
-                      </when>
-                      <when value="directory">
-                          <expand macro="name_type_rule_matching_file"/>
-                      </when>
-                      <when value="extension" />
-                      <when value="image"/>
-                      <when value="metadata"/>
-                </conditional>
-                <param name="name_to_assign" label="Name to assign these images" type="text" />
-                <conditional name="con_select_image_type">
-                    <param name="select_image_type" type="select" label="Select the image type">
-                        <option value="Grayscale image">Grayscale image</option>
-                        <option value="Color image">Color image</option>
-                        <option value="Binary mask">Binary mask</option>
-                    </param>
-                    <when value ="Grayscale image">
-                        <expand macro="image_type_condition" />
-                    </when>
-                    <when value="Color image">
-                        <expand macro="image_type_condition" />
-                    </when>
-                    <when value="Binary mask">
-                    </when>
-                </conditional>
-            </repeat>
-        </xml>
-    </macros>
-    <expand macro="py_requirements"/>
-
-    <command detect_errors="aggressive"><![CDATA[
-        python '$script_file' '$inputs'
-    ]]></command>
-
-    <configfiles>
-        <inputs name="inputs"/>
-        <configfile name="script_file">
-import json
-import sys
-import os
-
-FOURSPACES = @SPACES@
-
-input_json_path = sys.argv[1]
-
-params = json.load(open(input_json_path, "r"))
-
-
-def write_images():
-    filter_images = params['images']['filter_images']
-
-    _str = "\nImages:[module_num:1|svn_version:\\'Unknown\\'|variable_revision_number:2|show_window:False|notes:\\x5B\\'To begin creating your project, use the Images module to compile a list of files and/or folders that you want to analyze. You can also specify a set of rules to include only the desired files in your selected folders.\\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]\n"
-    _str += FOURSPACES+":\n"
-    _str += FOURSPACES + "Filter images?:%s\n" % filter_images
-    _str += FOURSPACES + "Select the rule criteria:and (extension does isimage) (directory doesnot startwith \".\")\n"
-
-    return _str
-
-
-def write_metadata():
-    metadata_extraction = params['metadata']['con_metadata_extraction']
-    extract = metadata_extraction['extract']
-
-    if 'extraction_method' in metadata_extraction:
-        method_count = len(metadata_extraction['extraction_method'])
-    else:
-        method_count = 1
-
-    _str = "\nMetadata:[module_num:2|svn_version:\\'Unknown\\'|variable_revision_number:4|show_window:False|notes:\\x5B\\'The Metadata module optionally allows you to extract information describing your images (i.e, metadata) which will be stored along with your measurements. This information can be contained in the file name and/or location, or in an external file.\\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]\n"
-    _str += FOURSPACES + "Extract metadata?:%s\n" % extract
-
-    if extract == "No":
-        _str += FOURSPACES + "Metadata data type:Text\n"
-        _str += FOURSPACES + "Metadata types:{}\n"
-        _str += FOURSPACES + "Extraction method count:%d\n" % method_count
-        _str += FOURSPACES + "Metadata extraction method:Extract from file/folder names\n"
-        _str += FOURSPACES + "Regular expression to extract from file name:^(?P&lt;Plate>.*)_(?P&lt;Well>\x5BA-P\x5D\x5B0-9\x5D{2})_s(?P&lt;Site>\x5B0-9\x5D)_w(?P&lt;ChannelNumber>\x5B0-9\x5D)\n"
-        _str += FOURSPACES + "Regular expression to extract from folder name:(?P&lt;Date>\x5B0-9\x5D{4}_\x5B0-9\x5D{2}_\x5B0-9\x5D{2})$\n"
-        _str += FOURSPACES + "Extract metadata from:All images\n"
-        _str += FOURSPACES + "Select the filtering criteria:and (file does contain \"\")\n"
-        _str += FOURSPACES + "Metadata file location:\n"
-        _str += FOURSPACES + "Match file and image metadata:\x5B\x5D\n"
-        _str += FOURSPACES + "Use case insensitive matching?:No\n"
-    else:
-        _str += FOURSPACES + "Metadata data type:%s\n" % metadata_extraction['metadata_type']
-        _str += FOURSPACES + "Metadata types:{}\n"
-        _str += FOURSPACES + "Extraction method count:%d\n" % method_count
-
-        for methods in metadata_extraction["extraction_method"]:
-            _str += FOURSPACES + "Metadata extraction method:%s\n" % methods["metadata_extraction_method"]
-            _str += FOURSPACES + "Metadata source:%s\n" % methods["metadata_source"]
-            _str += FOURSPACES + "Regular expression to extract from file name:%s\n" % methods["file_name_regex"]
-            _str += FOURSPACES + "Regular expression to extract from folder name:%s\n" % methods["folder_name_regex"]
-            _str += FOURSPACES + "Extract metadata from:%s\n" % methods["extract_metadata_from"]
-            _str += FOURSPACES + "Select the filtering criteria:and (file does contain \"\")\n"
-            _str += FOURSPACES + "Metadata file location:\n"
-            _str += FOURSPACES + "Match file and image metadata:\x5B\x5D\n"
-            _str += FOURSPACES + "Use case insensitive matching?:No\n"
-
-    return _str
-
-
-def write_nameandtypes():
-    nameandtypes = params['nameandtypes']
-    assign_a_name = nameandtypes['con_assign_a_name_to']['assign_a_name_to']
-
-    if "con_select_image_type" in nameandtypes['con_assign_a_name_to']:
-        con_set_intensity = nameandtypes['con_assign_a_name_to']['con_select_image_type']['con_set_intensity']
-        max_intensity = con_set_intensity['maximum_intensity'] if "maximum_intensity" in con_set_intensity else 255.0
-    else:
-        max_intensity = 255.0
-
-    pixel_space = nameandtypes['pixel_space']
-
-    rule_count = len(nameandtypes['r_match_rule']) if "r_match_rule" in nameandtypes else 1
-
-    process_3d = nameandtypes['pixel_space']['process_3d']
-    x_spacing = 1.0 if "x_spacing" not in pixel_space else pixel_space["x_spacing"]
-    y_spacing = 1.0 if "y_spacing" not in pixel_space else pixel_space["y_spacing"]
-    z_spacing = 1.0 if "z_spacing" not in pixel_space else pixel_space["z_spacing"]
-
-    _str = "\nNamesAndTypes:[module_num:3|svn_version:\\'Unknown\\'|variable_revision_number:8|show_window:False|notes:\\x5B\\'The NamesAndTypes module allows you to assign a meaningful name to each image by which other modules will refer to it.\\'\\x5D|batch_state:array(\\x5B\\x5D, dtype=uint8)|enabled:True|wants_pause:False]\n"
-
-    _str += FOURSPACES + "Assign a name to:%s\n" % assign_a_name
-
-    if assign_a_name == "All images":
-        _str += FOURSPACES + "Select the image type:%s\n" % nameandtypes['con_assign_a_name_to']['con_select_image_type']['select_image_type']
-        _str += FOURSPACES + "Name to assign these images:%s\n" % nameandtypes['con_assign_a_name_to']['name_to_assign']
-        _str += FOURSPACES + "Match metadata:[]\n"
-
-        _str += FOURSPACES + "Image set matching method:Order\n"
-        _str += FOURSPACES + "Set intensity range from:%s\n" % con_set_intensity['set_intensity_range_from']
-        _str += FOURSPACES + "Assignments count:%s\n" % rule_count
-        _str += FOURSPACES + "Single images count:0\n"
-        _str += FOURSPACES + "Maximum intensity:%.1f\n" % max_intensity
-        _str += FOURSPACES + "Process as 3D?:%s\n" % process_3d
-
-        _str += FOURSPACES + "Relative pixel spacing in X:%.1f\n" % x_spacing
-        _str += FOURSPACES + "Relative pixel spacing in Y:%.1f\n" % y_spacing
-        _str += FOURSPACES + "Relative pixel spacing in Z:%.1f\n" % z_spacing
-    else:
-        _str += FOURSPACES + "Select the image type:Grayscale image\n"
-        _str += FOURSPACES + "Name to assign these images:DNA\n"
-        _str += FOURSPACES + "Match metadata:[]\n"
-
-        _str += FOURSPACES + "Image set matching method:%s\n" % nameandtypes['con_assign_a_name_to']['matching_method']
-        _str += FOURSPACES + "Set intensity range from:Image metadata\n"
-        _str += FOURSPACES + "Assignments count:%d\n" % rule_count
-        _str += FOURSPACES + "Single images count:0\n"
-        _str += FOURSPACES + "Maximum intensity:%.1f\n" % max_intensity
-        _str += FOURSPACES + "Process as 3D?:%s\n" % process_3d
-
-        _str += FOURSPACES + "Relative pixel spacing in X:1.0\n"
-        _str += FOURSPACES + "Relative pixel spacing in Y:1.0\n"
-        _str += FOURSPACES + "Relative pixel spacing in Z:1.0\n"
-
-        for rule in nameandtypes["con_assign_a_name_to"]["r_match_rule"]:
-            _str += FOURSPACES + "Select the rule criteria:%s%s%s%s%s%s%s%s%s%s\n" % (rule["match_all_any"], " (",rule["con_match"]["rule_type"], " ",rule["con_match"]["operator"]," ",rule["con_match"]["contain"]," \"",rule["con_match"]["match_value"],"\")")
-            _str += FOURSPACES + "Name to assign these images:%s\n" % rule["name_to_assign"]
-            _str += FOURSPACES + "Name to assign these objects:Cell\n"
-            _str += FOURSPACES + "Select the image type:%s\n" % rule["con_select_image_type"]["select_image_type"]
-
-            intensity_range = rule["con_select_image_type"]["con_set_intensity"]["set_intensity_range_from"]
-
-            _str += FOURSPACES + "Set intensity range from:%s\n" % intensity_range
-            _str += FOURSPACES + "Select the image type:%s\n" % rule["con_select_image_type"]["select_image_type"]
-
-            if intensity_range == "Manual":
-                _str += FOURSPACES + "Maximum intensity:%s\n" % rule["con_select_image_type"]["con_set_intensity"]["maximum_intensity"]
-            else:
-                _str += FOURSPACES + "Maximum intensity:255.0\n"
-
-            if process_3d == "Yes":
-                _str += FOURSPACES + "Relative pixel spacing in X:%.1f\n" % x_spacing
-                _str += FOURSPACES + "Relative pixel spacing in Y:%.1f\n" % y_spacing
-                _str += FOURSPACES + "Relative pixel spacing in Z:%.1f\n" % z_spacing
-
-    return _str
-
-
-def write_groups():
-    groups = params['groups']
-
-    _str = "\nGroups:[module_num:4|svn_version:\\'Unknown\\'|variable_revision_number:2|show_window:False|notes:\\x5B\\\'The Groups module optionally allows you to split your list of images into image subsets (groups) which will be processed independently of each other. Examples of groupings include screening batches, microtiter plates, time-lapse movies, etc.\\'\\x5D|batch_state:array(\\x5B\\x5D, dtype=uint8)|enabled:True|wants_pause:False]\n"
-
-    _str += FOURSPACES + "Do you want to group your images?:%s\n" % groups["con_groups"]["group_images"]
-    _str += FOURSPACES + "grouping metadata count:1\n"
-    _str += FOURSPACES + "Metadata category:%s\n" % groups["con_groups"]["group_category"]
-
-    return _str
-
-
-with open("output", "w") as f:
-    headers = ["CellProfiler Pipeline: http://www.cellprofiler.org\n",
-               "Version:3\n",
-               "DateRevision:319\n",
-               "GitHash:\n",
-               "ModuleCount:4\n",
-               "HasImagePlaneDetails:False",
-               "\n"]
-
-    f.writelines(headers)
-
-    img_str = write_images()
-    metadata_str = write_metadata()
-    nameandtypes_str = write_nameandtypes()
-    groups_str = write_groups()
-
-    output_str = img_str + metadata_str + nameandtypes_str + groups_str
-
-    f.write(output_str)
-f.close()
-
-        </configfile>
-    </configfiles>
-    <inputs>    
-        <!-- Images module-->
-        <section name="images" title="Images" expanded="false">
-            <param name="filter_images" type="select" label="Filer images?">
-              <option value="Images only">Images only</option>
-              <option value="No filtering">No filtering</option>
-            </param>
-        </section>
-        <!-- Metadata module-->
-        <section name="metadata" title="Metadata" expanded="false">
-            <conditional name="con_metadata_extraction">
-                <param name="extract" type="select" display="radio" label="Extract metadata?">
-                    <option value="No">No</option>
-                    <option value="Yes">Yes</option>
-                </param>
-                <when value="Yes">
-                    <repeat name="extraction_method" title="metadata">
-                        <param name="metadata_extraction_method" type="select" label="Metadata extraction method">
-                            <option value="Extract from file/folder names">Extract from file/folder names</option>
-                            <option value="Import from file">Import from file</option>
-                            <option value="Extract from image file headers">Extract from image file headers</option>
-                        </param>
-                        <param name="metadata_source" type="select" label="Metadata source">
-                            <option value="File name">File name</option>
-                            <option value="Folder name">Folder name</option>
-                        </param>
-                        <param name="file_name_regex" type="select" label="Select file name pattern to extract from file name" help="Image file names must comply with one of the patterns.For example, AS_09125_050116030001_D03f00d0.tif matches the pattern field1_filed2_field3_field4. If none of the patterns are suitable, please use other Galaxy tools to rename your files first.  ">
-                            <sanitizer sanitize="false"/>
-                            <option value="(?P&lt;field1>.*)">field1</option>
-                            <option value="(?P&lt;field1>.*)-(?P&lt;field2>[a-zA-Z0-9]+)">field1-field2</option>
-                            <option value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)">field1_field2</option>
-                            <option value="(?P&lt;field1>.*)__(?P&lt;field2>[a-zA-Z0-9]+)">field1__field2</option>
-                            <option value="(?P&lt;field1>.*)-(?P&lt;field2>[a-zA-Z0-9]+)-(?P&lt;field3>[a-zA-Z0-9]+)">field1-field2-field3</option>
-                            <option value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)_(?P&lt;field3>[a-zA-Z0-9]+)">field1_field2_field3</option>
-                            <option value="(?P&lt;field1>.*)__(?P&lt;field2>[a-zA-Z0-9]+)__(?P&lt;field3>[a-zA-Z0-9]+)">field1__field2__field3</option>
-                            <option value="(?P&lt;field1>.*)-(?P&lt;field2>[a-zA-Z0-9]+)-(?P&lt;field3>[a-zA-Z0-9]+)-(?P&lt;field4>[a-zA-Z0-9]+)">field1-field2-field3-field4</option>
-                            <option value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)_(?P&lt;field3>[a-zA-Z0-9]+)_(?P&lt;field4>[a-zA-Z0-9]+)">field1_field2_field3_field4</option>
-                            <option value="(?P&lt;field1>.*)__(?P&lt;field2>[a-zA-Z0-9]+)__(?P&lt;field3>[a-zA-Z0-9]+)__(?P&lt;field4>[a-zA-Z0-9]+)">field1__field2__field3__field4</option>
-                            <option value="(?P&lt;field1>.*)-(?P&lt;field2>[a-zA-Z0-9]+)-(?P&lt;field3>[a-zA-Z0-9]+)-(?P&lt;field4>[a-zA-Z0-9]+)-(?P&lt;field5>[a-zA-Z0-9]+)">field1-field2-field3-field4-field5</option>
-                            <option value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)_(?P&lt;field3>[a-zA-Z0-9]+)_(?P&lt;field4>[a-zA-Z0-9]+)_(?P&lt;field5>[a-zA-Z0-9]+)">field1_field2_field3_field4_field5</option>
-                            <option value="(?P&lt;field1>.*)__(?P&lt;field2>[a-zA-Z0-9]+)__(?P&lt;field3>[a-zA-Z0-9]+)__(?P&lt;field4>[a-zA-Z0-9]+)__(?P&lt;field5>[a-zA-Z0-9]+)">field1__field2__field3__field4__field5</option>
-                            <option value="(?P&lt;field1>.*)-(?P&lt;field2>[a-zA-Z0-9]+)-(?P&lt;field3>[a-zA-Z0-9]+)-(?P&lt;field4>[a-zA-Z0-9]+)-(?P&lt;field5>[a-zA-Z0-9]+)-(?P&lt;field6>[a-zA-Z0-9]+)">field1-field2-field3-field4-field5-field6</option>
-                            <option value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)_(?P&lt;field3>[a-zA-Z0-9]+)_(?P&lt;field4>[a-zA-Z0-9]+)_(?P&lt;field5>[a-zA-Z0-9]+)_(?P&lt;field6>[a-zA-Z0-9]+)">field1_field2_field3_field4_field5_field6</option>
-                            <option value="(?P&lt;field1>.*)__(?P&lt;field2>[a-zA-Z0-9]+)__(?P&lt;field3>[a-zA-Z0-9]+)__(?P&lt;field4>[a-zA-Z0-9]+)__(?P&lt;field5>[a-zA-Z0-9]+)__(?P&lt;field6>[a-zA-Z0-9]+)">field1__field2__field3__field4__field5__field6</option>
-                        </param>
-                        <param name="folder_name_regex" type="select" label="Select folder name pattern to extract from folder name" help="Folder names must comply with one of the patterns.For example, folder name images-exp1 matches the pattern field1-field2. If none of the patterns are suitable, please use other Galaxy tools to rename your folder first.  "> 
-                            <sanitizer sanitize="false"/>
-                            <option value="(?P&lt;field1>.*)">field1</option>
-                            <option value="(?P&lt;field1>.*)-(?P&lt;field2>[a-zA-Z0-9]+)">field1-field2</option>
-                            <option value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)">field1_field2</option>
-                        </param>
-                        <param name="extract_metadata_from" type="select" label="Extract metadata from">
-                            <option value="All images">All images</option>
-                            <option value="Images matching a rule">Images matching a rule</option>
-                        </param>
-                    </repeat>
-                    <param name="metadata_type" type="select" label="Metadata data type">      
-                        <option value="Text">Text</option>
-                    </param>
-                </when>
-                <when value="No">
-                </when>
-            </conditional>
-        </section>
-        <!-- NamesAndTypes-->
-        <section name="nameandtypes" title="NamesAndTypes" expanded="false">
-            <conditional name="pixel_space">
-                <param name="process_3d" type="select" display="radio" label="Process 3D">
-                    <option value="No">No</option>
-                    <option value="Yes">Yes</option>
-                </param>  
-                <when value="Yes">
-                    <param name="x_spacing" type="float" value="1.0" label="Relative pixel spacing in X"/>
-                    <param name="y_spacing" type="float" value="1.0" label="Relative pixel spacing in Y"/>
-                    <param name="z_spacing" type="float" value="1.0" label="Relative pixel spacing in Z"/>
-                </when>
-                <when value="No">
-                </when>
-            </conditional>
-            <conditional name="con_assign_a_name_to">
-                <param name="assign_a_name_to" type="select" label="Assign a name to">
-                    <option value="All images">All images</option>
-                    <option value="Images matching rules">Images matching rules</option>
-                </param>
-                <when value="All images">
-                    <param name="name_to_assign" type="text" value="DNA" label="Name to assign these images"/>
-                    <conditional name="con_select_image_type">
-                        <param name="select_image_type" type="select" label="Select the image type">
-                            <option value="Grayscale image">Grayscale image</option>
-                            <option value="Color image">Color image</option>
-                            <option value="Binary mask">Binary mask</option>
-                        </param>
-                        <when value ="Grayscale image">
-                            <expand macro="image_type_condition" />
-                        </when>
-                        <when value="Color image">
-                            <expand macro="image_type_condition" />
-                        </when>
-                        <when value="Binary mask">
-                        </when>
-                    </conditional>
-                </when>
-                <when value="Images matching rules">
-                    <expand macro="image_matching_rules"/>
-                    <param name="matching_method" type="select" label="Image set matching method">
-                        <option value="Order">Order</option>
-                        <option value="Metadata">Metadata</option>
-                    </param>
-                </when>
-            </conditional>
-        </section>
-        <!-- Groups -->
-        <section name="groups" title="Groups" expanded="false">
-            <conditional name="con_groups">
-                <param name="group_images" type="select" value="No" label="Do you want to group your images?" display="radio">
-                    <option value="Yes">Yes</option>
-                    <option value="No">No</option>
-                </param>
-                <when value="Yes">
-                    <param name="group_category" type="select" label="Metadata category">
-                        <option value="FileLocation">FileLocation</option>
-                        <option value="Frame">Frame</option>
-                        <option value="ImageId">ImageId</option>
-                        <option value="Screen">Screen</option>
-                        <option value="Series">Series</option>
-                    </param>
-                </when>
-                <when value="No">
-                </when>
-            </conditional>
-        </section>
-    </inputs>
-    <outputs>
-        <expand macro="output_pipeline_macro" />
-    </outputs>
-    <tests>
-        <test>
-            <param name="filter_images" value="Images only"/>
-            <conditional name="con_metadata_extraction">
-                <param name="extract" value="Yes"/>
-                <repeat name="extraction_method">
-                    <param name="metadata_extraction_method" value="Extract from file/folder names"/>
-                    <param name="metadata_source" value="File name" />
-                    <param name="file_name_regex" value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)_(?P&lt;field3>[a-zA-Z0-9]+)_(?P&lt;field4>[a-zA-Z0-9]+)" />
-                    <param name="extract_metadata_from" value="All images" />
-                </repeat>
-                <param name="metadata_type" value="Text" />
-            </conditional>
-            <conditional name="pixel_space">
-                <param name="process_3d" value="No"/>
-            </conditional>
-            <conditional name="con_assign_a_name_to">
-                <param name="assign_a_name_to" value="Images matching rules"/>
-                <repeat name="r_match_rule">
-                    <param name="match_all_any" value="and" />
-                    <conditional name="con_match">
-                        <param name="rule_type" value="file" />
-                        <param name="operator" value="does" />
-                        <param name="contain" value="startwith" />
-                        <param name="match_value" value="im" /> 
-                    </conditional>
-                    <param name="name_to_assign" value="DNA" />
-                    <conditional name="con_select_image_type">
-                        <param name="select_image_type" value="Grayscale image" />
-                        <conditional name="con_set_intensity">
-                            <param name="set_intensity_range_from" value="Image metadata" />
-                        </conditional>
-                    </conditional>
-                </repeat>
-                <param name="matching_method" value="Order" />
-            </conditional>
-            <conditional name="con_groups">
-                <param name="group_images" value="Yes" />
-                <param name="group_category" value="Screen" />
-            </conditional>
-            <expand macro="test_out_file" />
-        </test>
-    </tests>
-
-    <help>
-    This tool builds a cellProfiler pipeline file with headers and 4 compulsory modules, 'Images', 'Metadata', 'NamesAndTypes' and 'Groups'.
-
-    No input parameters are needed for this tool. The rest CP modules will build based on the output of this file.
-
- 
-    Images: use the Images module to compile a list of files that you want to analyze. 
-
-    Metadata: optionally allows you to extract information describing your images (i.e., metadata) which will be stored along with your measurements. 
-
-    NamesAndTypes: allows you to assign a meaningful name to each image by which other modules will refer to it.
-
-    Groups: optionally allows you to split your list of images into image subsets (groups) which will be processed independently of each other. Examples of groupings include screening batches, microtiter plates, time-lapse movies, etc.
-
-    </help>
-    <expand macro="citations" />
-</tool>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cp_common_functions.py	Thu Apr 16 05:29:02 2020 -0400
@@ -0,0 +1,61 @@
+INDENTATION = "    "
+LINE_NUM_MODULES = 4
+
+def get_json_value(json_input, keys_path):
+    """Returns the value specified in keys_path (using dot notation) or an empty string if the key doesn't exist"""
+    if not isinstance(json_input, dict):
+        return ""
+    keys = keys_path.split(".")
+    try:
+        value = json_input[keys[0]]
+        for key in keys[1:]:
+            value = value[key]
+        return value
+    except KeyError:
+        return ""
+
+
+def concat_conditional(a, b):
+    if a == "" or b == "":
+        return ""
+    else:
+        return f"{a}_{b}"
+
+        
+def get_total_number_of_modules(pipeline_lines):
+    """Gets the number of modules from the header of the previous pipeline"""
+    number_of_modules = pipeline_lines[LINE_NUM_MODULES].strip().split(':')[1]
+    return int(number_of_modules)
+
+
+def get_pipeline_lines(input_pipeline):
+    """Returns a list with the lines in the .cppipe file"""
+    with open(input_pipeline) as f:
+        lines = f.readlines()
+    return lines
+
+
+def update_module_count(pipeline_lines, count):
+    """Updates the number of modules in the .cppipe header"""
+    module_count_entry = pipeline_lines[LINE_NUM_MODULES].strip().split(':')[0]
+    pipeline_lines[4] = f"{module_count_entry}:{count}\n"
+    return pipeline_lines
+
+
+def write_pipeline(filename, lines_pipeline):
+    """Writes the lines composing the pipeline into a file"""
+    with open(filename, "w") as f:
+        f.writelines(lines_pipeline)
+
+
+def build_header(module_name, module_number):
+    """Creates the first line of a module given the name and module number"""
+    result = "|".join([f"{module_name}:[module_num:{module_number}",
+                       "svn_version:\\'Unknown\\'",
+                       "variable_revision_number:4",
+                       "show_window:False",
+                       "notes:\\x5B\\x5D",
+                       "batch_state:array(\\x5B\\x5D, dtype=uint8)",
+                       "enabled:True",
+                       "wants_pause:False]\n"])
+    return result
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/image_math.py	Thu Apr 16 05:29:02 2020 -0400
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+
+import json
+import sys
+import os
+import argparse
+from cp_common_functions import *
+
+MODULE_NAME = "ImageMath"
+OUTPUT_FILENAME = "output.cppipe"
+
+operator_map = {
+    "add": "Add",
+    "subtract": "Subtract",
+    "multiply": "Multiply",
+    "divide": "Divide",
+    "average": "Average",
+    "minimum": "Minimum",
+    "maximum": "Maximum",
+    "invert": "Invert",
+    "log_2": "Log transform (base 2)",
+    "log_legacy": "Log transform (legacy)",
+    "and": "And",
+    "or": "Or",
+    "not": "Not",
+    "equals": "Equals"
+}
+
+
+def build_main_block(input_params):
+    """Creates the main block of the CP pipeline with the parameters that don't depend on conditional choices"""
+    operation = operator_map[get_json_value(
+        input_params, 'operation.operation')]
+    result = INDENTATION.join([f"{INDENTATION}Operation:{operation}\n",
+                               f"Raise the power of the result by:{get_json_value(input_params,'operation.op_results.raise_the_power_of_the_result_by')}\n",
+                               f"Multiply the result by:{get_json_value(input_params,'operation.op_results.multiply_the_result_by')}\n",
+                               f"Add to result:{get_json_value(input_params,'operation.op_results.add_to_result')}\n",
+                               f"Set values less than 0 equal to 0?:{get_json_value(input_params,'operation.op_results.set_values_less_than_0_equal_to_0')}\n",
+                               f"Set values greater than 1 equal to 1?:{get_json_value(input_params,'operation.op_results.set_values_greater_than_1_equal_to_1')}\n",
+                               f"Ignore the image masks?:{get_json_value(input_params,'ignore_the_image_masks')}\n",
+                               f"Name the output image:{get_json_value(input_params,'name_output_image')}"
+                               ])
+    return result
+
+
+def build_variable_block(inputs_galaxy):
+    result = ""
+    first_image_block = build_first_image_block(
+        get_json_value(inputs_galaxy, 'operation.first_image'))
+    result += f"\n{first_image_block}"
+    second_image_block = build_second_image_block(
+        get_json_value(inputs_galaxy, 'operation.second_image'))
+    result += f"\n{second_image_block}"
+    return result
+
+
+def build_first_image_block(input_params):
+    """Creates the block of parameters for the first operator in operations"""
+
+    value_select = get_json_value(
+        input_params, 'image_or_measurement_first.image_or_measurement_first')
+    image_name = get_json_value(
+        input_params, 'image_or_measurement_first.select_the_first_image')
+    value_multiply = get_json_value(
+        input_params, 'multiply_the_first_image_by')
+    category = get_json_value(
+        input_params, 'image_or_measurement_first.category_first.category_first')
+    measurement = get_json_value(
+        input_params, 'image_or_measurement_first.category_first.measurement_first')
+
+    result = INDENTATION.join(
+        [f"{INDENTATION}Image or measurement?:{value_select}\n",
+         f"Select the first image:{image_name}\n",
+         f"Multiply the first image by:{value_multiply}\n",
+         f"Measurement:{concat_conditional(category, measurement)}"
+         ])
+    return result
+
+
+def build_second_image_block(input_params):
+    """Creates the block of parameters for the second operator in binary operations"""
+
+    value_select = get_json_value(
+        input_params, 'image_or_measurement_second.image_or_measurement_second')
+    image_name = get_json_value(
+        input_params, 'image_or_measurement_second.select_the_second_image')
+    value_multiply = get_json_value(
+        input_params, 'multiply_the_second_image_by')
+    category = get_json_value(
+        input_params, 'image_or_measurement_second.category_second.category_second')
+    measurement = get_json_value(
+        input_params, 'image_or_measurement_second.category_second.measurement_second')
+
+    result = INDENTATION.join(
+        [f"{INDENTATION}Image or measurement?:{value_select}\n",
+         f"Select the second image:{image_name}\n",
+         f"Multiply the second image by:{value_multiply}\n",
+         f"Measurement:{concat_conditional(category, measurement)}"
+         ])
+    return result
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        '-p', '--pipeline',
+        help='CellProfiler pipeline'
+    )
+    parser.add_argument(
+        '-i', '--inputs',
+        help='JSON inputs from Galaxy'
+    )
+    args = parser.parse_args()
+
+    pipeline_lines = get_pipeline_lines(args.pipeline)
+    inputs_galaxy = json.load(open(args.inputs, "r"))
+
+    current_module_num = get_total_number_of_modules(pipeline_lines)
+    current_module_num += 1
+    pipeline_lines = update_module_count(pipeline_lines, current_module_num)
+
+    header_block = build_header(MODULE_NAME, current_module_num)
+    main_block = build_main_block(inputs_galaxy)
+    variable_block = build_variable_block(inputs_galaxy)
+
+    module_pipeline = f"\n{header_block}{main_block}{variable_block}\n"
+    pipeline_lines.append(module_pipeline)
+
+    write_pipeline(OUTPUT_FILENAME, pipeline_lines)
--- a/macros.xml	Thu Apr 09 08:12:15 2020 -0400
+++ b/macros.xml	Thu Apr 16 05:29:02 2020 -0400
@@ -1,73 +1,105 @@
 <macros>
     <token name="@CP_VERSION@">3.1.9</token>
-    <token name="@PY_VERSION@">2.7.16</token>
+    <token name="@PY_VERSION@">3.7</token>
     <token name="@FORMATS@">jpg,png,tiff,bmp,gif,pcx,ppm,psd,pbm,pgm,eps</token>
+    <token name="@SPACES@">"    "</token>
+    <!-- four spaces needed for CP pipeline file -->
+    <token name="@COMMON_HELP@">
+        .. class:: infomark
 
-    <token name="@SPACES@">"    "</token> <!-- four spaces needed for CP pipeline file -->
+        **Input**
+
+        Existing CellProfiler pipeline file *(.cppipe)* or generated by linking CellProfiler tools.
+
+        .. class:: infomark
+
+        **Output**
+
+        The input CellProfiler pipeline file *(.cppipe)* in addition to the settings of this module.
+
+        .. class:: warningmark
+
+        **IMPORTANT**
+
+        The first tool in a CellProfiler workflow has to be **Starting modules** and the last one **CellProfiler**. You can also execute the entire pipeline with the final CellProfiler tool, in which you feed in the images you want to process as well.
+    </token>
+
 
     <xml name="output_pipeline_macro">
-        <data name="out_file" from_work_dir="output" format="txt" label="Output pipeline" />
+        <data name="out_file" from_work_dir="output" format="txt"/>
     </xml>
 
+
     <xml name="input_pipeline_macro">
-        <param name="input_pipeline" type="data" format="data" label="Pipeline to select"/>
+        <param name="input_pipeline" type="data" format="data" label="Select the input CellProfiler pipeline"/>
     </xml>
 
+
     <xml name="cp_requirements">
         <requirements>
             <requirement type="package" version="@CP_VERSION@">cellprofiler</requirement>
         </requirements>
     </xml>
 
+
     <xml name="py_requirements">
         <requirements>
             <requirement type="package" version="@PY_VERSION@">python</requirement>
         </requirements>
     </xml>
 
+
     <xml name="citations">
         <citations>
             <citation type="bibtex">
-            @misc{galaxytoolscellprofiler,
-            author = {Sun, Yi},
-            year = {2020},
-            title = {Cellprofiler Galaxy tools},
-            publisher = {Github},
-            journal = {Github repository},
-            url = {https://github.com/bgruening/galaxytools/tools/cellrprofiler},
-            }
+                @article{McQuin_2018,
+                title = {CellProfiler 3.0: Next-generation image processing for biology},
+                author = {McQuin C, Goodman A, Chernyshev V, Kamentsky L, Cimini BA, Karhohs KW, Doan M, Ding L, Rafelski SM, Thirstrup D, Wiegraebe W, Singh S, Becker T, Caicedo JC, Carpenter AE},
+                year = {2018},
+                volume = {16(7):e2005970},
+                DOI = {10.1371/journal.pbio.2005970},
+                journal = {PLoS Biol.},
+                url = {https://journals.plos.org/plosbiology/article?id=10.1371/journal.pbio.2005970},
+                }
             </citation>
         </citations>
     </xml>
 
+
     <xml name="cmd_modules">
-        <command detect_errors="aggressive"><![CDATA[
-            python '$script_file' '$inputs' '$input_pipeline'
-        ]]></command>
+        <command detect_errors="aggressive">
+            <![CDATA[
+                python '$script_file' '$inputs' '$input_pipeline'
+                ]]>
+        </command>
     </xml>
 
+
     <xml name="text_validator">
         <validator type="regex" message="Only numbers, letters, hyphen, underscore and spaces are allowed">^[A-Za-z0-9 _-]*$</validator>
     </xml>
 
+
     <xml name="test_input_pipeline_param">
         <param name="input_pipeline" value="common.txt" />
     </xml>
 
+
     <xml name="test_out_file" token_file="common.txt">
         <output name="out_file" ftype="txt" file="@FILE@" lines_diff="0"/>
     </xml>
-    
+
+
     <xml name="help" token_module="common">
-       <help>
-           This tool appends the inputs of the @MODULE@ module to an existing pipeline file (.cppipe)
+        <help>
+            This tool appends the inputs of the @MODULE@ module to an existing pipeline file (.cppipe)
 
-           Input: existing pipeline file
+            Input: existing pipeline file
 
-           Output: new pipeline file
+            Output: new pipeline file
 
-           Combine this tool with "Common" tool and "CellProfiler" tool together to run the current module alone.
-       </help>
-   </xml>
+            Combine this tool with "Common" tool and "CellProfiler" tool together to run the current module alone.
+        </help>
+    </xml>
 </macros>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/starting_modules.xml	Thu Apr 16 05:29:02 2020 -0400
@@ -0,0 +1,464 @@
+<tool id="cp_common" name="Starting modules" version="@CP_VERSION@">
+    <description>load images and metadata into CellProfiler (Images, Metadata, NamesAndTypes, Groups)</description>
+    <macros>
+        <import>macros.xml</import>
+        <xml name="image_type_condition"> 
+            <conditional name="con_set_intensity">
+                <param name="set_intensity_range_from" type="select" label="Set intensity range from">
+                    <option value="Image metadata">Image metadata</option>
+                    <option value="Image bit-depth">Image bit-depth</option>
+                    <option value="Manual">Manual</option>
+                </param>
+                <when value="Manual">
+                    <param name="maximum_intensity" type="float" value="255.0" label="Maximum intensity"/>
+                </when>
+                <when value="Image metadata" />
+                <when value="Image bit-depth" />               
+            </conditional>
+        </xml>
+        <xml name="name_type_rule_matching_file">
+            <param name="operator" type="select">
+                <option value="does">Does</option>
+                <option value="doesnot">Does not</option>
+            </param>
+            <param name="contain" type="select">
+                <option value="contain">Contain</option>
+                <option value="Contain regular expression">Contain regular expression</option>
+                <option value="startwith">Start with</option>
+                <option value="endwith">End with</option>
+                <option value="Exactly match">Exactly match</option>
+            </param>
+            <param name="match_value" type="text"/>
+        </xml>
+        <xml name="image_matching_rules">
+            <repeat name="r_match_rule" title="Rules">
+                <param name="match_all_any" type="select" display="radio" label="Match the following rules">
+                    <option value="and">All</option>
+                    <option value="or">Any</option>
+                </param>
+                <conditional name="con_match">
+                      <param name="rule_type" type="select" label="Select rule criteria">
+                          <option value="file">File</option>
+                          <option value="directory">Directory</option>
+                          <option value="extension">Extension</option>
+                          <option value="image">Image</option>
+                          <option value="metadata">Metadata</option>
+                      </param>
+                      <when value="file">
+                          <expand macro="name_type_rule_matching_file"/>
+                      </when>
+                      <when value="directory">
+                          <expand macro="name_type_rule_matching_file"/>
+                      </when>
+                      <when value="extension" />
+                      <when value="image"/>
+                      <when value="metadata"/>
+                </conditional>
+                <param name="name_to_assign" label="Name to assign these images" type="text" />
+                <conditional name="con_select_image_type">
+                    <param name="select_image_type" type="select" label="Select the image type">
+                        <option value="Grayscale image">Grayscale image</option>
+                        <option value="Color image">Color image</option>
+                        <option value="Binary mask">Binary mask</option>
+                    </param>
+                    <when value ="Grayscale image">
+                        <expand macro="image_type_condition" />
+                    </when>
+                    <when value="Color image">
+                        <expand macro="image_type_condition" />
+                    </when>
+                    <when value="Binary mask">
+                    </when>
+                </conditional>
+            </repeat>
+        </xml>
+    </macros>
+    <expand macro="py_requirements"/>
+
+    <command detect_errors="aggressive"><![CDATA[
+        python '$script_file' '$inputs'
+    ]]></command>
+
+    <configfiles>
+        <inputs name="inputs"/>
+        <configfile name="script_file">
+import json
+import sys
+import os
+
+FOURSPACES = @SPACES@
+
+input_json_path = sys.argv[1]
+
+params = json.load(open(input_json_path, "r"))
+
+
+def write_images():
+    filter_images = params['images']['filter_images']
+
+    _str = "\nImages:[module_num:1|svn_version:\\'Unknown\\'|variable_revision_number:2|show_window:False|notes:\\x5B\\'To begin creating your project, use the Images module to compile a list of files and/or folders that you want to analyze. You can also specify a set of rules to include only the desired files in your selected folders.\\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]\n"
+    _str += FOURSPACES+":\n"
+    _str += FOURSPACES + "Filter images?:%s\n" % filter_images
+    _str += FOURSPACES + "Select the rule criteria:and (extension does isimage) (directory doesnot startwith \".\")\n"
+
+    return _str
+
+
+def write_metadata():
+    metadata_extraction = params['metadata']['con_metadata_extraction']
+    extract = metadata_extraction['extract']
+
+    if 'extraction_method' in metadata_extraction:
+        method_count = len(metadata_extraction['extraction_method'])
+    else:
+        method_count = 1
+
+    _str = "\nMetadata:[module_num:2|svn_version:\\'Unknown\\'|variable_revision_number:4|show_window:False|notes:\\x5B\\'The Metadata module optionally allows you to extract information describing your images (i.e, metadata) which will be stored along with your measurements. This information can be contained in the file name and/or location, or in an external file.\\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]\n"
+    _str += FOURSPACES + "Extract metadata?:%s\n" % extract
+
+    if extract == "No":
+        _str += FOURSPACES + "Metadata data type:Text\n"
+        _str += FOURSPACES + "Metadata types:{}\n"
+        _str += FOURSPACES + "Extraction method count:%d\n" % method_count
+        _str += FOURSPACES + "Metadata extraction method:Extract from file/folder names\n"
+        _str += FOURSPACES + "Regular expression to extract from file name:^(?P&lt;Plate>.*)_(?P&lt;Well>\x5BA-P\x5D\x5B0-9\x5D{2})_s(?P&lt;Site>\x5B0-9\x5D)_w(?P&lt;ChannelNumber>\x5B0-9\x5D)\n"
+        _str += FOURSPACES + "Regular expression to extract from folder name:(?P&lt;Date>\x5B0-9\x5D{4}_\x5B0-9\x5D{2}_\x5B0-9\x5D{2})$\n"
+        _str += FOURSPACES + "Extract metadata from:All images\n"
+        _str += FOURSPACES + "Select the filtering criteria:and (file does contain \"\")\n"
+        _str += FOURSPACES + "Metadata file location:\n"
+        _str += FOURSPACES + "Match file and image metadata:\x5B\x5D\n"
+        _str += FOURSPACES + "Use case insensitive matching?:No\n"
+    else:
+        _str += FOURSPACES + "Metadata data type:%s\n" % metadata_extraction['metadata_type']
+        _str += FOURSPACES + "Metadata types:{}\n"
+        _str += FOURSPACES + "Extraction method count:%d\n" % method_count
+
+        for methods in metadata_extraction["extraction_method"]:
+            _str += FOURSPACES + "Metadata extraction method:%s\n" % methods["metadata_extraction_method"]
+            _str += FOURSPACES + "Metadata source:%s\n" % methods["metadata_source"]
+            _str += FOURSPACES + "Regular expression to extract from file name:%s\n" % methods["file_name_regex"]
+            _str += FOURSPACES + "Regular expression to extract from folder name:%s\n" % methods["folder_name_regex"]
+            _str += FOURSPACES + "Extract metadata from:%s\n" % methods["extract_metadata_from"]
+            _str += FOURSPACES + "Select the filtering criteria:and (file does contain \"\")\n"
+            _str += FOURSPACES + "Metadata file location:\n"
+            _str += FOURSPACES + "Match file and image metadata:\x5B\x5D\n"
+            _str += FOURSPACES + "Use case insensitive matching?:No\n"
+
+    return _str
+
+
+def write_nameandtypes():
+    nameandtypes = params['nameandtypes']
+    assign_a_name = nameandtypes['con_assign_a_name_to']['assign_a_name_to']
+
+    if "con_select_image_type" in nameandtypes['con_assign_a_name_to']:
+        con_set_intensity = nameandtypes['con_assign_a_name_to']['con_select_image_type']['con_set_intensity']
+        max_intensity = con_set_intensity['maximum_intensity'] if "maximum_intensity" in con_set_intensity else 255.0
+    else:
+        max_intensity = 255.0
+
+    pixel_space = nameandtypes['pixel_space']
+
+    rule_count = len(nameandtypes['r_match_rule']) if "r_match_rule" in nameandtypes else 1
+
+    process_3d = nameandtypes['pixel_space']['process_3d']
+    x_spacing = 1.0 if "x_spacing" not in pixel_space else pixel_space["x_spacing"]
+    y_spacing = 1.0 if "y_spacing" not in pixel_space else pixel_space["y_spacing"]
+    z_spacing = 1.0 if "z_spacing" not in pixel_space else pixel_space["z_spacing"]
+
+    _str = "\nNamesAndTypes:[module_num:3|svn_version:\\'Unknown\\'|variable_revision_number:8|show_window:False|notes:\\x5B\\'The NamesAndTypes module allows you to assign a meaningful name to each image by which other modules will refer to it.\\'\\x5D|batch_state:array(\\x5B\\x5D, dtype=uint8)|enabled:True|wants_pause:False]\n"
+
+    _str += FOURSPACES + "Assign a name to:%s\n" % assign_a_name
+
+    if assign_a_name == "All images":
+        _str += FOURSPACES + "Select the image type:%s\n" % nameandtypes['con_assign_a_name_to']['con_select_image_type']['select_image_type']
+        _str += FOURSPACES + "Name to assign these images:%s\n" % nameandtypes['con_assign_a_name_to']['name_to_assign']
+        _str += FOURSPACES + "Match metadata:[]\n"
+
+        _str += FOURSPACES + "Image set matching method:Order\n"
+        _str += FOURSPACES + "Set intensity range from:%s\n" % con_set_intensity['set_intensity_range_from']
+        _str += FOURSPACES + "Assignments count:%s\n" % rule_count
+        _str += FOURSPACES + "Single images count:0\n"
+        _str += FOURSPACES + "Maximum intensity:%.1f\n" % max_intensity
+        _str += FOURSPACES + "Process as 3D?:%s\n" % process_3d
+
+        _str += FOURSPACES + "Relative pixel spacing in X:%.1f\n" % x_spacing
+        _str += FOURSPACES + "Relative pixel spacing in Y:%.1f\n" % y_spacing
+        _str += FOURSPACES + "Relative pixel spacing in Z:%.1f\n" % z_spacing
+    else:
+        _str += FOURSPACES + "Select the image type:Grayscale image\n"
+        _str += FOURSPACES + "Name to assign these images:DNA\n"
+        _str += FOURSPACES + "Match metadata:[]\n"
+
+        _str += FOURSPACES + "Image set matching method:%s\n" % nameandtypes['con_assign_a_name_to']['matching_method']
+        _str += FOURSPACES + "Set intensity range from:Image metadata\n"
+        _str += FOURSPACES + "Assignments count:%d\n" % rule_count
+        _str += FOURSPACES + "Single images count:0\n"
+        _str += FOURSPACES + "Maximum intensity:%.1f\n" % max_intensity
+        _str += FOURSPACES + "Process as 3D?:%s\n" % process_3d
+
+        _str += FOURSPACES + "Relative pixel spacing in X:1.0\n"
+        _str += FOURSPACES + "Relative pixel spacing in Y:1.0\n"
+        _str += FOURSPACES + "Relative pixel spacing in Z:1.0\n"
+
+        for rule in nameandtypes["con_assign_a_name_to"]["r_match_rule"]:
+            _str += FOURSPACES + "Select the rule criteria:%s%s%s%s%s%s%s%s%s%s\n" % (rule["match_all_any"], " (",rule["con_match"]["rule_type"], " ",rule["con_match"]["operator"]," ",rule["con_match"]["contain"]," \"",rule["con_match"]["match_value"],"\")")
+            _str += FOURSPACES + "Name to assign these images:%s\n" % rule["name_to_assign"]
+            _str += FOURSPACES + "Name to assign these objects:Cell\n"
+            _str += FOURSPACES + "Select the image type:%s\n" % rule["con_select_image_type"]["select_image_type"]
+
+            intensity_range = rule["con_select_image_type"]["con_set_intensity"]["set_intensity_range_from"]
+
+            _str += FOURSPACES + "Set intensity range from:%s\n" % intensity_range
+            _str += FOURSPACES + "Select the image type:%s\n" % rule["con_select_image_type"]["select_image_type"]
+
+            if intensity_range == "Manual":
+                _str += FOURSPACES + "Maximum intensity:%s\n" % rule["con_select_image_type"]["con_set_intensity"]["maximum_intensity"]
+            else:
+                _str += FOURSPACES + "Maximum intensity:255.0\n"
+
+            if process_3d == "Yes":
+                _str += FOURSPACES + "Relative pixel spacing in X:%.1f\n" % x_spacing
+                _str += FOURSPACES + "Relative pixel spacing in Y:%.1f\n" % y_spacing
+                _str += FOURSPACES + "Relative pixel spacing in Z:%.1f\n" % z_spacing
+
+    return _str
+
+
+def write_groups():
+    groups = params['groups']
+
+    _str = "\nGroups:[module_num:4|svn_version:\\'Unknown\\'|variable_revision_number:2|show_window:False|notes:\\x5B\\\'The Groups module optionally allows you to split your list of images into image subsets (groups) which will be processed independently of each other. Examples of groupings include screening batches, microtiter plates, time-lapse movies, etc.\\'\\x5D|batch_state:array(\\x5B\\x5D, dtype=uint8)|enabled:True|wants_pause:False]\n"
+
+    _str += FOURSPACES + "Do you want to group your images?:%s\n" % groups["con_groups"]["group_images"]
+    _str += FOURSPACES + "grouping metadata count:1\n"
+    _str += FOURSPACES + "Metadata category:%s\n" % groups["con_groups"]["group_category"]
+
+    return _str
+
+
+with open("output", "w") as f:
+    headers = ["CellProfiler Pipeline: http://www.cellprofiler.org\n",
+               "Version:3\n",
+               "DateRevision:319\n",
+               "GitHash:\n",
+               "ModuleCount:4\n",
+               "HasImagePlaneDetails:False",
+               "\n"]
+
+    f.writelines(headers)
+
+    img_str = write_images()
+    metadata_str = write_metadata()
+    nameandtypes_str = write_nameandtypes()
+    groups_str = write_groups()
+
+    output_str = img_str + metadata_str + nameandtypes_str + groups_str
+
+    f.write(output_str)
+f.close()
+
+        </configfile>
+    </configfiles>
+    <inputs>    
+        <!-- Images module-->
+        <section name="images" title="Images" expanded="false">
+            <param name="filter_images" type="select" label="Filter images?">
+              <option value="Images only">Images only</option>
+              <option value="No filtering">No filtering</option>
+            </param>
+        </section>
+        <!-- Metadata module-->
+        <section name="metadata" title="Metadata" expanded="false">
+            <conditional name="con_metadata_extraction">
+                <param name="extract" type="select" display="radio" label="Extract metadata?">
+                    <option value="No">No</option>
+                    <option value="Yes">Yes</option>
+                </param>
+                <when value="Yes">
+                    <repeat name="extraction_method" title="metadata">
+                        <param name="metadata_extraction_method" type="select" label="Metadata extraction method">
+                            <option value="Extract from file/folder names">Extract from file/folder names</option>
+                            <option value="Import from file">Import from file</option>
+                            <option value="Extract from image file headers">Extract from image file headers</option>
+                        </param>
+                        <param name="metadata_source" type="select" label="Metadata source">
+                            <option value="File name">File name</option>
+                            <option value="Folder name">Folder name</option>
+                        </param>
+                        <param name="file_name_regex" type="select" label="Select file name pattern to extract from file name" help="Image file names must comply with one of the patterns.For example, AS_09125_050116030001_D03f00d0.tif matches the pattern field1_filed2_field3_field4. If none of the patterns are suitable, please use other Galaxy tools to rename your files first.  ">
+                            <sanitizer sanitize="false"/>
+                            <option value="(?P&lt;field1>.*)">field1</option>
+                            <option value="(?P&lt;field1>.*)-(?P&lt;field2>[a-zA-Z0-9]+)">field1-field2</option>
+                            <option value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)">field1_field2</option>
+                            <option value="(?P&lt;field1>.*)__(?P&lt;field2>[a-zA-Z0-9]+)">field1__field2</option>
+                            <option value="(?P&lt;field1>.*)-(?P&lt;field2>[a-zA-Z0-9]+)-(?P&lt;field3>[a-zA-Z0-9]+)">field1-field2-field3</option>
+                            <option value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)_(?P&lt;field3>[a-zA-Z0-9]+)">field1_field2_field3</option>
+                            <option value="(?P&lt;field1>.*)__(?P&lt;field2>[a-zA-Z0-9]+)__(?P&lt;field3>[a-zA-Z0-9]+)">field1__field2__field3</option>
+                            <option value="(?P&lt;field1>.*)-(?P&lt;field2>[a-zA-Z0-9]+)-(?P&lt;field3>[a-zA-Z0-9]+)-(?P&lt;field4>[a-zA-Z0-9]+)">field1-field2-field3-field4</option>
+                            <option value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)_(?P&lt;field3>[a-zA-Z0-9]+)_(?P&lt;field4>[a-zA-Z0-9]+)">field1_field2_field3_field4</option>
+                            <option value="(?P&lt;field1>.*)__(?P&lt;field2>[a-zA-Z0-9]+)__(?P&lt;field3>[a-zA-Z0-9]+)__(?P&lt;field4>[a-zA-Z0-9]+)">field1__field2__field3__field4</option>
+                            <option value="(?P&lt;field1>.*)-(?P&lt;field2>[a-zA-Z0-9]+)-(?P&lt;field3>[a-zA-Z0-9]+)-(?P&lt;field4>[a-zA-Z0-9]+)-(?P&lt;field5>[a-zA-Z0-9]+)">field1-field2-field3-field4-field5</option>
+                            <option value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)_(?P&lt;field3>[a-zA-Z0-9]+)_(?P&lt;field4>[a-zA-Z0-9]+)_(?P&lt;field5>[a-zA-Z0-9]+)">field1_field2_field3_field4_field5</option>
+                            <option value="(?P&lt;field1>.*)__(?P&lt;field2>[a-zA-Z0-9]+)__(?P&lt;field3>[a-zA-Z0-9]+)__(?P&lt;field4>[a-zA-Z0-9]+)__(?P&lt;field5>[a-zA-Z0-9]+)">field1__field2__field3__field4__field5</option>
+                            <option value="(?P&lt;field1>.*)-(?P&lt;field2>[a-zA-Z0-9]+)-(?P&lt;field3>[a-zA-Z0-9]+)-(?P&lt;field4>[a-zA-Z0-9]+)-(?P&lt;field5>[a-zA-Z0-9]+)-(?P&lt;field6>[a-zA-Z0-9]+)">field1-field2-field3-field4-field5-field6</option>
+                            <option value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)_(?P&lt;field3>[a-zA-Z0-9]+)_(?P&lt;field4>[a-zA-Z0-9]+)_(?P&lt;field5>[a-zA-Z0-9]+)_(?P&lt;field6>[a-zA-Z0-9]+)">field1_field2_field3_field4_field5_field6</option>
+                            <option value="(?P&lt;field1>.*)__(?P&lt;field2>[a-zA-Z0-9]+)__(?P&lt;field3>[a-zA-Z0-9]+)__(?P&lt;field4>[a-zA-Z0-9]+)__(?P&lt;field5>[a-zA-Z0-9]+)__(?P&lt;field6>[a-zA-Z0-9]+)">field1__field2__field3__field4__field5__field6</option>
+                        </param>
+                        <param name="folder_name_regex" type="select" label="Select folder name pattern to extract from folder name" help="Folder names must comply with one of the patterns.For example, folder name images-exp1 matches the pattern field1-field2. If none of the patterns are suitable, please use other Galaxy tools to rename your folder first.  "> 
+                            <sanitizer sanitize="false"/>
+                            <option value="(?P&lt;field1>.*)">field1</option>
+                            <option value="(?P&lt;field1>.*)-(?P&lt;field2>[a-zA-Z0-9]+)">field1-field2</option>
+                            <option value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)">field1_field2</option>
+                        </param>
+                        <param name="extract_metadata_from" type="select" label="Extract metadata from">
+                            <option value="All images">All images</option>
+                            <option value="Images matching a rule">Images matching a rule</option>
+                        </param>
+                    </repeat>
+                    <param name="metadata_type" type="select" label="Metadata data type">      
+                        <option value="Text">Text</option>
+                    </param>
+                </when>
+                <when value="No">
+                </when>
+            </conditional>
+        </section>
+        <!-- NamesAndTypes-->
+        <section name="nameandtypes" title="NamesAndTypes" expanded="false">
+            <conditional name="pixel_space">
+                <param name="process_3d" type="select" display="radio" label="Process 3D">
+                    <option value="No">No</option>
+                    <option value="Yes">Yes</option>
+                </param>  
+                <when value="Yes">
+                    <param name="x_spacing" type="float" value="1.0" label="Relative pixel spacing in X"/>
+                    <param name="y_spacing" type="float" value="1.0" label="Relative pixel spacing in Y"/>
+                    <param name="z_spacing" type="float" value="1.0" label="Relative pixel spacing in Z"/>
+                </when>
+                <when value="No">
+                </when>
+            </conditional>
+            <conditional name="con_assign_a_name_to">
+                <param name="assign_a_name_to" type="select" label="Assign a name to">
+                    <option value="All images">All images</option>
+                    <option value="Images matching rules">Images matching rules</option>
+                </param>
+                <when value="All images">
+                    <param name="name_to_assign" type="text" value="DNA" label="Name to assign these images"/>
+                    <conditional name="con_select_image_type">
+                        <param name="select_image_type" type="select" label="Select the image type">
+                            <option value="Grayscale image">Grayscale image</option>
+                            <option value="Color image">Color image</option>
+                            <option value="Binary mask">Binary mask</option>
+                        </param>
+                        <when value ="Grayscale image">
+                            <expand macro="image_type_condition" />
+                        </when>
+                        <when value="Color image">
+                            <expand macro="image_type_condition" />
+                        </when>
+                        <when value="Binary mask">
+                        </when>
+                    </conditional>
+                </when>
+                <when value="Images matching rules">
+                    <expand macro="image_matching_rules"/>
+                    <param name="matching_method" type="select" label="Image set matching method">
+                        <option value="Order">Order</option>
+                        <option value="Metadata">Metadata</option>
+                    </param>
+                </when>
+            </conditional>
+        </section>
+        <!-- Groups -->
+        <section name="groups" title="Groups" expanded="false">
+            <conditional name="con_groups">
+                <param name="group_images" type="select" value="No" label="Do you want to group your images?" display="radio">
+                    <option value="Yes">Yes</option>
+                    <option value="No">No</option>
+                </param>
+                <when value="Yes">
+                    <param name="group_category" type="select" label="Metadata category">
+                        <option value="FileLocation">FileLocation</option>
+                        <option value="Frame">Frame</option>
+                        <option value="ImageId">ImageId</option>
+                        <option value="Screen">Screen</option>
+                        <option value="Series">Series</option>
+                        <option value="field1">field1</option>
+                        <option value="field2">field2</option>
+                        <option value="field3">field3</option>
+                        <option value="field4">field4</option>
+                        <option value="field5">field5</option>
+                        <option value="field6">field6</option>
+                    </param>
+                </when>
+                <when value="No">
+                </when>
+            </conditional>
+        </section>
+    </inputs>
+    <outputs>
+        <expand macro="output_pipeline_macro" />
+    </outputs>
+    <tests>
+        <test>
+            <param name="filter_images" value="Images only"/>
+            <conditional name="con_metadata_extraction">
+                <param name="extract" value="Yes"/>
+                <repeat name="extraction_method">
+                    <param name="metadata_extraction_method" value="Extract from file/folder names"/>
+                    <param name="metadata_source" value="File name" />
+                    <param name="file_name_regex" value="(?P&lt;field1>.*)_(?P&lt;field2>[a-zA-Z0-9]+)_(?P&lt;field3>[a-zA-Z0-9]+)_(?P&lt;field4>[a-zA-Z0-9]+)" />
+                    <param name="extract_metadata_from" value="All images" />
+                </repeat>
+                <param name="metadata_type" value="Text" />
+            </conditional>
+            <conditional name="pixel_space">
+                <param name="process_3d" value="No"/>
+            </conditional>
+            <conditional name="con_assign_a_name_to">
+                <param name="assign_a_name_to" value="Images matching rules"/>
+                <repeat name="r_match_rule">
+                    <param name="match_all_any" value="and" />
+                    <conditional name="con_match">
+                        <param name="rule_type" value="file" />
+                        <param name="operator" value="does" />
+                        <param name="contain" value="startwith" />
+                        <param name="match_value" value="im" /> 
+                    </conditional>
+                    <param name="name_to_assign" value="DNA" />
+                    <conditional name="con_select_image_type">
+                        <param name="select_image_type" value="Grayscale image" />
+                        <conditional name="con_set_intensity">
+                            <param name="set_intensity_range_from" value="Image metadata" />
+                        </conditional>
+                    </conditional>
+                </repeat>
+                <param name="matching_method" value="Order" />
+            </conditional>
+            <conditional name="con_groups">
+                <param name="group_images" value="Yes" />
+                <param name="group_category" value="Screen" />
+            </conditional>
+            <expand macro="test_out_file" />
+        </test>
+    </tests>
+
+    <help>
+    This tool builds a CellProfiler pipeline file with headers and 4 compulsory modules, 'Images', 'Metadata', 'NamesAndTypes' and 'Groups'.
+
+    No input parameters are needed for this tool. The rest CP modules will build based on the output of this file.
+
+ 
+    Images: use the Images module to compile a list of files that you want to analyze. 
+
+    Metadata: optionally allows you to extract information describing your images (i.e., metadata) which will be stored along with your measurements. 
+
+    NamesAndTypes: allows you to assign a meaningful name to each image by which other modules will refer to it.
+
+    Groups: optionally allows you to split your list of images into image subsets (groups) which will be processed independently of each other. Examples of groupings include screening batches, microtiter plates, time-lapse movies, etc.
+
+    </help>
+    <expand macro="citations" />
+</tool>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/common_image_math.cppipe	Thu Apr 16 05:29:02 2020 -0400
@@ -0,0 +1,94 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:6
+HasImagePlaneDetails:False
+
+Images:[module_num:1|svn_version:\'Unknown\'|variable_revision_number:2|show_window:False|notes:\x5B\'To begin creating your project, use the Images module to compile a list of files and/or folders that you want to analyze. You can also specify a set of rules to include only the desired files in your selected folders.\']|batch_state:array([], dtype=uint8)|enabled:True|wants_pause:False]
+    :
+    Filter images?:Images only
+    Select the rule criteria:and (extension does isimage) (directory doesnot startwith ".")
+
+Metadata:[module_num:2|svn_version:\'Unknown\'|variable_revision_number:4|show_window:False|notes:\x5B\'The Metadata module optionally allows you to extract information describing your images (i.e, metadata) which will be stored along with your measurements. This information can be contained in the file name and/or location, or in an external file.\']|batch_state:array([], dtype=uint8)|enabled:True|wants_pause:False]
+    Extract metadata?:Yes
+    Metadata data type:Text
+    Metadata types:{}
+    Extraction method count:1
+    Metadata extraction method:Extract from file/folder names
+    Metadata source:File name
+    Regular expression to extract from file name:(?P<field1>.*)_(?P<field2>[a-zA-Z0-9]+)_(?P<field3>[a-zA-Z0-9]+)_(?P<field4>[a-zA-Z0-9]+)
+    Regular expression to extract from folder name:(?P<field1>.*)
+    Extract metadata from:All images
+    Select the filtering criteria:and (file does contain "")
+    Metadata file location:
+    Match file and image metadata:[]
+    Use case insensitive matching?:No
+
+NamesAndTypes:[module_num:3|svn_version:\'Unknown\'|variable_revision_number:8|show_window:False|notes:\x5B\'The NamesAndTypes module allows you to assign a meaningful name to each image by which other modules will refer to it.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Assign a name to:Images matching rules
+    Select the image type:Grayscale image
+    Name to assign these images:DNA
+    Match metadata:[]
+    Image set matching method:Order
+    Set intensity range from:Image metadata
+    Assignments count:1
+    Single images count:0
+    Maximum intensity:255.0
+    Process as 3D?:No
+    Relative pixel spacing in X:1.0
+    Relative pixel spacing in Y:1.0
+    Relative pixel spacing in Z:1.0
+    Select the rule criteria:and (file does startwith "im")
+    Name to assign these images:DNA
+    Name to assign these objects:Cell
+    Select the image type:Grayscale image
+    Set intensity range from:Image metadata
+    Select the image type:Grayscale image
+    Maximum intensity:255.0
+
+Groups:[module_num:4|svn_version:\'Unknown\'|variable_revision_number:2|show_window:False|notes:\x5B\'The Groups module optionally allows you to split your list of images into image subsets (groups) which will be processed independently of each other. Examples of groupings include screening batches, microtiter plates, time-lapse movies, etc.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Do you want to group your images?:Yes
+    grouping metadata count:1
+    Metadata category:Screen
+
+IdentifyPrimaryObjects:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:13|show_window:True|notes:\x5B\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select the input image:DNA
+    Name the primary objects to be identified:Nucleus
+    Typical diameter of objects, in pixel units (Min,Max):15,200
+    Discard objects outside the diameter range?:Yes
+    Discard objects touching the border of the image?:Yes
+    Method to distinguish clumped objects:Intensity
+    Method to draw dividing lines between clumped objects:Intensity
+    Size of smoothing filter:10
+    Suppress local maxima that are closer than this minimum allowed distance:7.0
+    Speed up by using lower-resolution image to find local maxima?:Yes
+    Fill holes in identified objects?:After both thresholding and declumping
+    Automatically calculate size of smoothing filter for declumping?:Yes
+    Automatically calculate minimum allowed distance between local maxima?:Yes
+    Handling of objects if excessive number of objects identified:Continue
+    Maximum number of objects:500
+    Use advanced settings?:No
+    Threshold setting version:10
+    Threshold strategy:Global
+    Thresholding method:Minimum cross entropy
+    Threshold smoothing scale:1.3488
+    Threshold correction factor:1.0
+    Lower and upper bounds on threshold:0.0,1.0
+    Manual threshold:0.0
+    Select the measurement to threshold with:None
+    Two-class or three-class thresholding?:Two classes
+    Assign pixels in the middle intensity class to the foreground or the background?:Foreground
+    Size of adaptive window:50
+    Lower outlier fraction:0.05
+    Upper outlier fraction:0.05
+    Averaging method:Mean
+    Variance method:Standard deviation
+    # of deviations:2.0
+    Thresholding method:Otsu
+
+ConvertObjectsToImage:[module_num:6|svn_version:\'Unknown\'|variable_revision_number:1|show_window:True|notes:\x5B\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select the input objects:Nucleus
+    Name the output image:CellImage
+    Select the color format:Binary (black & white)
+    Select the colormap:Default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/image_math_1.cppipe	Thu Apr 16 05:29:02 2020 -0400
@@ -0,0 +1,112 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:7
+HasImagePlaneDetails:False
+
+Images:[module_num:1|svn_version:\'Unknown\'|variable_revision_number:2|show_window:False|notes:\x5B\'To begin creating your project, use the Images module to compile a list of files and/or folders that you want to analyze. You can also specify a set of rules to include only the desired files in your selected folders.\']|batch_state:array([], dtype=uint8)|enabled:True|wants_pause:False]
+    :
+    Filter images?:Images only
+    Select the rule criteria:and (extension does isimage) (directory doesnot startwith ".")
+
+Metadata:[module_num:2|svn_version:\'Unknown\'|variable_revision_number:4|show_window:False|notes:\x5B\'The Metadata module optionally allows you to extract information describing your images (i.e, metadata) which will be stored along with your measurements. This information can be contained in the file name and/or location, or in an external file.\']|batch_state:array([], dtype=uint8)|enabled:True|wants_pause:False]
+    Extract metadata?:Yes
+    Metadata data type:Text
+    Metadata types:{}
+    Extraction method count:1
+    Metadata extraction method:Extract from file/folder names
+    Metadata source:File name
+    Regular expression to extract from file name:(?P<field1>.*)_(?P<field2>[a-zA-Z0-9]+)_(?P<field3>[a-zA-Z0-9]+)_(?P<field4>[a-zA-Z0-9]+)
+    Regular expression to extract from folder name:(?P<field1>.*)
+    Extract metadata from:All images
+    Select the filtering criteria:and (file does contain "")
+    Metadata file location:
+    Match file and image metadata:[]
+    Use case insensitive matching?:No
+
+NamesAndTypes:[module_num:3|svn_version:\'Unknown\'|variable_revision_number:8|show_window:False|notes:\x5B\'The NamesAndTypes module allows you to assign a meaningful name to each image by which other modules will refer to it.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Assign a name to:Images matching rules
+    Select the image type:Grayscale image
+    Name to assign these images:DNA
+    Match metadata:[]
+    Image set matching method:Order
+    Set intensity range from:Image metadata
+    Assignments count:1
+    Single images count:0
+    Maximum intensity:255.0
+    Process as 3D?:No
+    Relative pixel spacing in X:1.0
+    Relative pixel spacing in Y:1.0
+    Relative pixel spacing in Z:1.0
+    Select the rule criteria:and (file does startwith "im")
+    Name to assign these images:DNA
+    Name to assign these objects:Cell
+    Select the image type:Grayscale image
+    Set intensity range from:Image metadata
+    Select the image type:Grayscale image
+    Maximum intensity:255.0
+
+Groups:[module_num:4|svn_version:\'Unknown\'|variable_revision_number:2|show_window:False|notes:\x5B\'The Groups module optionally allows you to split your list of images into image subsets (groups) which will be processed independently of each other. Examples of groupings include screening batches, microtiter plates, time-lapse movies, etc.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Do you want to group your images?:Yes
+    grouping metadata count:1
+    Metadata category:Screen
+
+IdentifyPrimaryObjects:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:13|show_window:True|notes:\x5B\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select the input image:DNA
+    Name the primary objects to be identified:Nucleus
+    Typical diameter of objects, in pixel units (Min,Max):15,200
+    Discard objects outside the diameter range?:Yes
+    Discard objects touching the border of the image?:Yes
+    Method to distinguish clumped objects:Intensity
+    Method to draw dividing lines between clumped objects:Intensity
+    Size of smoothing filter:10
+    Suppress local maxima that are closer than this minimum allowed distance:7.0
+    Speed up by using lower-resolution image to find local maxima?:Yes
+    Fill holes in identified objects?:After both thresholding and declumping
+    Automatically calculate size of smoothing filter for declumping?:Yes
+    Automatically calculate minimum allowed distance between local maxima?:Yes
+    Handling of objects if excessive number of objects identified:Continue
+    Maximum number of objects:500
+    Use advanced settings?:No
+    Threshold setting version:10
+    Threshold strategy:Global
+    Thresholding method:Minimum cross entropy
+    Threshold smoothing scale:1.3488
+    Threshold correction factor:1.0
+    Lower and upper bounds on threshold:0.0,1.0
+    Manual threshold:0.0
+    Select the measurement to threshold with:None
+    Two-class or three-class thresholding?:Two classes
+    Assign pixels in the middle intensity class to the foreground or the background?:Foreground
+    Size of adaptive window:50
+    Lower outlier fraction:0.05
+    Upper outlier fraction:0.05
+    Averaging method:Mean
+    Variance method:Standard deviation
+    # of deviations:2.0
+    Thresholding method:Otsu
+
+ConvertObjectsToImage:[module_num:6|svn_version:\'Unknown\'|variable_revision_number:1|show_window:True|notes:\x5B\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select the input objects:Nucleus
+    Name the output image:CellImage
+    Select the color format:Binary (black & white)
+    Select the colormap:Default
+
+ImageMath:[module_num:7|svn_version:\'Unknown\'|variable_revision_number:4|show_window:False|notes:\x5B\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Operation:Add
+    Raise the power of the result by:1.0
+    Multiply the result by:1.0
+    Add to result:0.0
+    Set values less than 0 equal to 0?:Yes
+    Set values greater than 1 equal to 1?:Yes
+    Ignore the image masks?:No
+    Name the output image:ImageAfterMath
+    Image or measurement?:Image
+    Select the first image:DNA
+    Multiply the first image by:1.0
+    Measurement:
+    Image or measurement?:Image
+    Select the second image:CellImage
+    Multiply the second image by:2.0
+    Measurement:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/image_math_2.cppipe	Thu Apr 16 05:29:02 2020 -0400
@@ -0,0 +1,112 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:7
+HasImagePlaneDetails:False
+
+Images:[module_num:1|svn_version:\'Unknown\'|variable_revision_number:2|show_window:False|notes:\x5B\'To begin creating your project, use the Images module to compile a list of files and/or folders that you want to analyze. You can also specify a set of rules to include only the desired files in your selected folders.\']|batch_state:array([], dtype=uint8)|enabled:True|wants_pause:False]
+    :
+    Filter images?:Images only
+    Select the rule criteria:and (extension does isimage) (directory doesnot startwith ".")
+
+Metadata:[module_num:2|svn_version:\'Unknown\'|variable_revision_number:4|show_window:False|notes:\x5B\'The Metadata module optionally allows you to extract information describing your images (i.e, metadata) which will be stored along with your measurements. This information can be contained in the file name and/or location, or in an external file.\']|batch_state:array([], dtype=uint8)|enabled:True|wants_pause:False]
+    Extract metadata?:Yes
+    Metadata data type:Text
+    Metadata types:{}
+    Extraction method count:1
+    Metadata extraction method:Extract from file/folder names
+    Metadata source:File name
+    Regular expression to extract from file name:(?P<field1>.*)_(?P<field2>[a-zA-Z0-9]+)_(?P<field3>[a-zA-Z0-9]+)_(?P<field4>[a-zA-Z0-9]+)
+    Regular expression to extract from folder name:(?P<field1>.*)
+    Extract metadata from:All images
+    Select the filtering criteria:and (file does contain "")
+    Metadata file location:
+    Match file and image metadata:[]
+    Use case insensitive matching?:No
+
+NamesAndTypes:[module_num:3|svn_version:\'Unknown\'|variable_revision_number:8|show_window:False|notes:\x5B\'The NamesAndTypes module allows you to assign a meaningful name to each image by which other modules will refer to it.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Assign a name to:Images matching rules
+    Select the image type:Grayscale image
+    Name to assign these images:DNA
+    Match metadata:[]
+    Image set matching method:Order
+    Set intensity range from:Image metadata
+    Assignments count:1
+    Single images count:0
+    Maximum intensity:255.0
+    Process as 3D?:No
+    Relative pixel spacing in X:1.0
+    Relative pixel spacing in Y:1.0
+    Relative pixel spacing in Z:1.0
+    Select the rule criteria:and (file does startwith "im")
+    Name to assign these images:DNA
+    Name to assign these objects:Cell
+    Select the image type:Grayscale image
+    Set intensity range from:Image metadata
+    Select the image type:Grayscale image
+    Maximum intensity:255.0
+
+Groups:[module_num:4|svn_version:\'Unknown\'|variable_revision_number:2|show_window:False|notes:\x5B\'The Groups module optionally allows you to split your list of images into image subsets (groups) which will be processed independently of each other. Examples of groupings include screening batches, microtiter plates, time-lapse movies, etc.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Do you want to group your images?:Yes
+    grouping metadata count:1
+    Metadata category:Screen
+
+IdentifyPrimaryObjects:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:13|show_window:True|notes:\x5B\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select the input image:DNA
+    Name the primary objects to be identified:Nucleus
+    Typical diameter of objects, in pixel units (Min,Max):15,200
+    Discard objects outside the diameter range?:Yes
+    Discard objects touching the border of the image?:Yes
+    Method to distinguish clumped objects:Intensity
+    Method to draw dividing lines between clumped objects:Intensity
+    Size of smoothing filter:10
+    Suppress local maxima that are closer than this minimum allowed distance:7.0
+    Speed up by using lower-resolution image to find local maxima?:Yes
+    Fill holes in identified objects?:After both thresholding and declumping
+    Automatically calculate size of smoothing filter for declumping?:Yes
+    Automatically calculate minimum allowed distance between local maxima?:Yes
+    Handling of objects if excessive number of objects identified:Continue
+    Maximum number of objects:500
+    Use advanced settings?:No
+    Threshold setting version:10
+    Threshold strategy:Global
+    Thresholding method:Minimum cross entropy
+    Threshold smoothing scale:1.3488
+    Threshold correction factor:1.0
+    Lower and upper bounds on threshold:0.0,1.0
+    Manual threshold:0.0
+    Select the measurement to threshold with:None
+    Two-class or three-class thresholding?:Two classes
+    Assign pixels in the middle intensity class to the foreground or the background?:Foreground
+    Size of adaptive window:50
+    Lower outlier fraction:0.05
+    Upper outlier fraction:0.05
+    Averaging method:Mean
+    Variance method:Standard deviation
+    # of deviations:2.0
+    Thresholding method:Otsu
+
+ConvertObjectsToImage:[module_num:6|svn_version:\'Unknown\'|variable_revision_number:1|show_window:True|notes:\x5B\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select the input objects:Nucleus
+    Name the output image:CellImage
+    Select the color format:Binary (black & white)
+    Select the colormap:Default
+
+ImageMath:[module_num:7|svn_version:\'Unknown\'|variable_revision_number:4|show_window:False|notes:\x5B\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Operation:Subtract
+    Raise the power of the result by:1.0
+    Multiply the result by:1.0
+    Add to result:0.0
+    Set values less than 0 equal to 0?:Yes
+    Set values greater than 1 equal to 1?:No
+    Ignore the image masks?:No
+    Name the output image:ImageAfterMath
+    Image or measurement?:Image
+    Select the first image:DNA
+    Multiply the first image by:1.0
+    Measurement:
+    Image or measurement?:Measurement
+    Select the second image:
+    Multiply the second image by:5.0
+    Measurement:FileName_DNA
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/image_math_3.cppipe	Thu Apr 16 05:29:02 2020 -0400
@@ -0,0 +1,112 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:7
+HasImagePlaneDetails:False
+
+Images:[module_num:1|svn_version:\'Unknown\'|variable_revision_number:2|show_window:False|notes:\x5B\'To begin creating your project, use the Images module to compile a list of files and/or folders that you want to analyze. You can also specify a set of rules to include only the desired files in your selected folders.\']|batch_state:array([], dtype=uint8)|enabled:True|wants_pause:False]
+    :
+    Filter images?:Images only
+    Select the rule criteria:and (extension does isimage) (directory doesnot startwith ".")
+
+Metadata:[module_num:2|svn_version:\'Unknown\'|variable_revision_number:4|show_window:False|notes:\x5B\'The Metadata module optionally allows you to extract information describing your images (i.e, metadata) which will be stored along with your measurements. This information can be contained in the file name and/or location, or in an external file.\']|batch_state:array([], dtype=uint8)|enabled:True|wants_pause:False]
+    Extract metadata?:Yes
+    Metadata data type:Text
+    Metadata types:{}
+    Extraction method count:1
+    Metadata extraction method:Extract from file/folder names
+    Metadata source:File name
+    Regular expression to extract from file name:(?P<field1>.*)_(?P<field2>[a-zA-Z0-9]+)_(?P<field3>[a-zA-Z0-9]+)_(?P<field4>[a-zA-Z0-9]+)
+    Regular expression to extract from folder name:(?P<field1>.*)
+    Extract metadata from:All images
+    Select the filtering criteria:and (file does contain "")
+    Metadata file location:
+    Match file and image metadata:[]
+    Use case insensitive matching?:No
+
+NamesAndTypes:[module_num:3|svn_version:\'Unknown\'|variable_revision_number:8|show_window:False|notes:\x5B\'The NamesAndTypes module allows you to assign a meaningful name to each image by which other modules will refer to it.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Assign a name to:Images matching rules
+    Select the image type:Grayscale image
+    Name to assign these images:DNA
+    Match metadata:[]
+    Image set matching method:Order
+    Set intensity range from:Image metadata
+    Assignments count:1
+    Single images count:0
+    Maximum intensity:255.0
+    Process as 3D?:No
+    Relative pixel spacing in X:1.0
+    Relative pixel spacing in Y:1.0
+    Relative pixel spacing in Z:1.0
+    Select the rule criteria:and (file does startwith "im")
+    Name to assign these images:DNA
+    Name to assign these objects:Cell
+    Select the image type:Grayscale image
+    Set intensity range from:Image metadata
+    Select the image type:Grayscale image
+    Maximum intensity:255.0
+
+Groups:[module_num:4|svn_version:\'Unknown\'|variable_revision_number:2|show_window:False|notes:\x5B\'The Groups module optionally allows you to split your list of images into image subsets (groups) which will be processed independently of each other. Examples of groupings include screening batches, microtiter plates, time-lapse movies, etc.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Do you want to group your images?:Yes
+    grouping metadata count:1
+    Metadata category:Screen
+
+IdentifyPrimaryObjects:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:13|show_window:True|notes:\x5B\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select the input image:DNA
+    Name the primary objects to be identified:Nucleus
+    Typical diameter of objects, in pixel units (Min,Max):15,200
+    Discard objects outside the diameter range?:Yes
+    Discard objects touching the border of the image?:Yes
+    Method to distinguish clumped objects:Intensity
+    Method to draw dividing lines between clumped objects:Intensity
+    Size of smoothing filter:10
+    Suppress local maxima that are closer than this minimum allowed distance:7.0
+    Speed up by using lower-resolution image to find local maxima?:Yes
+    Fill holes in identified objects?:After both thresholding and declumping
+    Automatically calculate size of smoothing filter for declumping?:Yes
+    Automatically calculate minimum allowed distance between local maxima?:Yes
+    Handling of objects if excessive number of objects identified:Continue
+    Maximum number of objects:500
+    Use advanced settings?:No
+    Threshold setting version:10
+    Threshold strategy:Global
+    Thresholding method:Minimum cross entropy
+    Threshold smoothing scale:1.3488
+    Threshold correction factor:1.0
+    Lower and upper bounds on threshold:0.0,1.0
+    Manual threshold:0.0
+    Select the measurement to threshold with:None
+    Two-class or three-class thresholding?:Two classes
+    Assign pixels in the middle intensity class to the foreground or the background?:Foreground
+    Size of adaptive window:50
+    Lower outlier fraction:0.05
+    Upper outlier fraction:0.05
+    Averaging method:Mean
+    Variance method:Standard deviation
+    # of deviations:2.0
+    Thresholding method:Otsu
+
+ConvertObjectsToImage:[module_num:6|svn_version:\'Unknown\'|variable_revision_number:1|show_window:True|notes:\x5B\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select the input objects:Nucleus
+    Name the output image:CellImage
+    Select the color format:Binary (black & white)
+    Select the colormap:Default
+
+ImageMath:[module_num:7|svn_version:\'Unknown\'|variable_revision_number:4|show_window:False|notes:\x5B\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Operation:Not
+    Raise the power of the result by:
+    Multiply the result by:
+    Add to result:
+    Set values less than 0 equal to 0?:
+    Set values greater than 1 equal to 1?:
+    Ignore the image masks?:No
+    Name the output image:ImageAfterMath
+    Image or measurement?:Image
+    Select the first image:DNA
+    Multiply the first image by:
+    Measurement:
+    Image or measurement?:
+    Select the second image:
+    Multiply the second image by:
+    Measurement: