changeset 4:a3e8abcf78f3 draft

"planemo upload for repository https://github.com/bgruening/galaxytools/tree/master/tools commit 35da2dcd86747c9bff138e100dbe08c6106f3780"
author bgruening
date Sat, 06 Feb 2021 09:38:45 +0000
parents 1ce038635829
children 37e109e6560b
files color_to_gray.py cp_common_functions.py image_math.py overlay_outlines.py starting_modules.py test-data/color_to_gray.cppipe test-data/color_to_gray_combine_channels.cppipe test-data/color_to_gray_split_channels.cppipe test-data/color_to_gray_split_hsv.cppipe test-data/color_to_gray_split_rgb.cppipe test-data/overlay_outlines.cppipe test-data/overlay_outlines_blank_color.cppipe test-data/overlay_outlines_blank_grayscale.cppipe test-data/overlay_outlines_non_blank_color.cppipe test-data/overlay_outlines_non_blank_grayscale.cppipe test-data/tile.cppipe test-data/tile_across_cycles.cppipe test-data/tile_across_cyles.cppipe test-data/track_object.cppipe test-data/track_object_distance_no_filter_min.cppipe test-data/track_object_follow_neighbors.cppipe test-data/track_object_lap_velocity.cppipe test-data/track_object_measurement_intensity.cppipe test-data/track_object_overlap_no_filter_max.cppipe tile.py track_objects.py
diffstat 26 files changed, 2031 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/color_to_gray.py	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+
+import argparse
+import json
+
+from cp_common_functions import get_json_value
+from cp_common_functions import get_pipeline_lines
+from cp_common_functions import get_total_number_of_modules
+from cp_common_functions import INDENTATION
+from cp_common_functions import update_module_count
+from cp_common_functions import write_pipeline
+
+MODULE_NAME = "ColorToGray"
+OUTPUT_FILENAME = "output.cppipe"
+
+
+def build_ctg_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:True",
+                       "notes:\\x5B\\'Convert the color image to grayscale.\\'\\x5D",
+                       "batch_state:array(\\x5B\\x5D, dtype=uint8)",
+                       "enabled:True",
+                       "wants_pause:False]\n"])
+    return result
+
+
+def build_main_block(input_params):
+    """Creates the main block of the CP pipeline with the parameters that don't depend on conditional choices"""
+    result = INDENTATION.join([f"{INDENTATION}Select the input image:{get_json_value(input_params,'name_input_image')}\n",
+                               f"Conversion method:{get_json_value(input_params,'con_conversion_method.conversion_method')}\n",
+                               f"Image type:{get_json_value(input_params,'con_conversion_method.con_image_type.image_type')}\n",
+                               ])
+
+    conversion_method = get_json_value(input_params, 'con_conversion_method.conversion_method')
+
+    image_type = get_json_value(input_params, 'con_conversion_method.con_image_type.image_type')
+    rgb_comb_name_out = "OrigGray"
+    combine_w_red = 1.0
+    combine_w_green = 1.0
+    combine_w_blue = 1.0
+
+    split_red = "Yes"
+    split_green = "Yes"
+    split_blue = "Yes"
+    red_output_name = "OrigRed"
+    green_output_name = "OrigGreen"
+    blue_output_name = "OrigBlue"
+
+    split_hue = "Yes"
+    split_saturation = "Yes"
+    split_value = "Yes"
+    hue_output_name = "OrigHue"
+    saturation_output_name = "OrigSaturation"
+    value_output_name = "OrigValue"
+
+    channel_count = 1
+    if conversion_method == "Combine":
+        if image_type == "RGB" or image_type == "HSV":
+            rgb_comb_name_out = get_json_value(input_params, 'con_conversion_method.name_output_image')
+            combine_w_red = get_json_value(input_params, 'con_conversion_method.con_image_type.weight_red_channel')
+            combine_w_green = get_json_value(input_params, 'con_conversion_method.con_image_type.weight_green_channel')
+            combine_w_blue = get_json_value(input_params, 'con_conversion_method.con_image_type.weight_blue_channel')
+    elif conversion_method == "Split":
+        if image_type == "RGB":
+            split_red = get_json_value(input_params, 'con_conversion_method.con_image_type.con_convert_red.yes_no')
+            red_output_name = get_json_value(input_params, 'con_conversion_method.con_image_type.con_convert_red.name_output_image')
+            split_green = get_json_value(input_params, 'con_conversion_method.con_image_type.con_convert_green.yes_no')
+            green_output_name = get_json_value(input_params, 'con_conversion_method.con_image_type.con_convert_green.name_output_image')
+            split_blue = get_json_value(input_params, 'con_conversion_method.con_image_type.con_convert_blue.yes_no')
+            blue_output_name = get_json_value(input_params, 'con_conversion_method.con_image_type.con_convert_blue.name_output_image')
+        elif image_type == "HSV":
+            split_hue = get_json_value(input_params, 'con_conversion_method.con_image_type.con_convert_hue.yes_no')
+            hue_output_name = get_json_value(input_params, 'con_conversion_method.con_image_type.con_convert_hue.name_output_image')
+            split_saturation = get_json_value(input_params, 'con_conversion_method.con_image_type.con_convert_saturation.yes_no')
+            saturation_output_name = get_json_value(input_params, 'con_conversion_method.con_image_type.con_convert_saturation.name_output_image')
+            split_value = get_json_value(input_params, 'con_conversion_method.con_image_type.con_convert_value.yes_no')
+            value_output_name = get_json_value(input_params, 'con_conversion_method.con_image_type.con_convert_value.name_output_image')
+
+    result += INDENTATION.join(
+        [f"{INDENTATION}Name the output image:{rgb_comb_name_out}\n",
+         f"Relative weight of the red channel:{str(combine_w_red)}\n",
+         f"Relative weight of the green channel:{str(combine_w_green)}\n",
+         f"Relative weight of the blue channel:{str(combine_w_blue)}\n",
+
+         f"Convert red to gray?:{split_red}\n",
+         f"Name the output image:{red_output_name}\n",
+         f"Convert green to gray?:{split_green}\n",
+         f"Name the output image:{green_output_name}\n",
+         f"Convert blue to gray?:{split_blue}\n",
+         f"Name the output image:{blue_output_name}\n",
+
+         f"Convert hue to gray?:{split_hue}\n",
+         f"Name the output image:{hue_output_name}\n",
+         f"Convert saturation to gray?:{split_saturation}\n",
+         f"Name the output image:{saturation_output_name}\n",
+         f"Convert value to gray?:{split_value}\n",
+         f"Name the output image:{value_output_name}\n"
+         ])
+
+    channel_count = 1
+    if image_type == "Channels":
+        channels = input_params['con_conversion_method']['con_image_type']['rpt_channel']
+        channel_count = len(channels)
+        result += INDENTATION.join(
+            [f"{INDENTATION}Channel count:{channel_count}\n"
+             ])
+
+        for ch in channels:
+            rel_weight_ch = 1.0
+            image_name = "Channel1"
+            if conversion_method == "Combine":
+                rel_weight_ch = get_json_value(ch, 'weight_of_channel')
+            else:
+                image_name = get_json_value(ch, 'image_name')
+            result += INDENTATION.join(
+                [f"{INDENTATION}Channel number:{get_json_value(ch,'channel_no')}\n",
+                 f"Relative weight of the channel:{str(rel_weight_ch)}\n",
+                 f"Image name:{image_name}\n"
+                 ])
+    else:
+        result += INDENTATION.join(
+            [f"{INDENTATION}Channel count:{channel_count}\n",
+             "Channel number:Red\\x3A 1\n",
+             "Relative weight of the channel:1.0\n",
+             "Image name:Channel1\n"
+             ])
+
+    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_ctg_header(MODULE_NAME, current_module_num)
+    main_block = build_main_block(inputs_galaxy)
+
+    module_pipeline = f"\n{header_block}{main_block}\n"
+    pipeline_lines.append(module_pipeline)
+
+    write_pipeline(OUTPUT_FILENAME, pipeline_lines)
--- a/cp_common_functions.py	Mon May 11 11:37:52 2020 +0000
+++ b/cp_common_functions.py	Sat Feb 06 09:38:45 2021 +0000
@@ -1,6 +1,7 @@
 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):
@@ -21,7 +22,7 @@
     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]
--- a/image_math.py	Mon May 11 11:37:52 2020 +0000
+++ b/image_math.py	Sat Feb 06 09:38:45 2021 +0000
@@ -1,10 +1,16 @@
 #!/usr/bin/env python
 
+import argparse
 import json
-import sys
-import os
-import argparse
-from cp_common_functions import *
+
+from cp_common_functions import build_header
+from cp_common_functions import concat_conditional
+from cp_common_functions import get_json_value
+from cp_common_functions import get_pipeline_lines
+from cp_common_functions import get_total_number_of_modules
+from cp_common_functions import INDENTATION
+from cp_common_functions import update_module_count
+from cp_common_functions import write_pipeline
 
 MODULE_NAME = "ImageMath"
 OUTPUT_FILENAME = "output.cppipe"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/overlay_outlines.py	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+
+import argparse
+import json
+
+from cp_common_functions import get_json_value
+from cp_common_functions import get_pipeline_lines
+from cp_common_functions import get_total_number_of_modules
+from cp_common_functions import INDENTATION
+from cp_common_functions import update_module_count
+from cp_common_functions import write_pipeline
+
+MODULE_NAME = "OverlayOutlines"
+OUTPUT_FILENAME = "output.cppipe"
+
+
+def build_ctg_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:True",
+                       "notes:\\x5B\\'Overlay the embryo outlines on the grayscale image.\\'\\x5D",
+                       "batch_state:array(\\x5B\\x5D, dtype=uint8)",
+                       "enabled:True",
+                       "wants_pause:False]\n"])
+    return result
+
+
+def build_main_block(input_params):
+    result = f"{INDENTATION}Display outlines on a blank image?:{get_json_value(input_params,'con_blank_img.blank_img')}\n"
+
+    on_blank = get_json_value(input_params, 'con_blank_img.blank_img')
+    # defaults
+    img_to_display = "None"
+    display_mode = get_json_value(input_params, 'con_blank_img.con_display_mode.display_mode')
+    method_brightness = "Max of image"
+    howto = get_json_value(input_params, 'howto_outline')
+    outline_color = "#FF0000"
+    obj_to_display = "None"
+
+    name_output_img = get_json_value(input_params, 'name_output_image')
+
+    if on_blank == "No":
+        img_to_display = get_json_value(input_params, 'con_blank_img.image_to_outline')
+
+    result += INDENTATION.join(
+        [f"{INDENTATION}Select image on which to display outlines:{img_to_display}\n",
+         f"Name the output image:{name_output_img}\n",
+         f"Outline display mode:{display_mode}\n"
+         ])
+
+    if on_blank == "No" and display_mode == "Grayscale":
+        method_brightness = get_json_value(input_params, 'con_blank_img.con_display_mode.method_brightness')
+
+    result += INDENTATION.join(
+        [f"{INDENTATION}Select method to determine brightness of outlines:{method_brightness}\n",
+         f"How to outline:{howto}\n"
+         ])
+
+    obj_outline_str = ""
+
+    if display_mode == "Color":
+        for obj in input_params['con_blank_img']['con_display_mode']['rpt_obj_to_display']:
+            outline_color = get_json_value(obj, 'outline_color')
+            obj_to_display = get_json_value(obj, 'obj_to_display')
+            obj_outline_str += INDENTATION.join(
+                [f"{INDENTATION}Select outline color:{outline_color}\n",
+                 f"Select objects to display:{obj_to_display}\n"
+                 ])
+    else:  # grayscale
+        for obj in input_params['con_blank_img']['con_display_mode']['rpt_obj_to_display']:
+            obj_to_display = get_json_value(obj, 'obj_to_display')
+            obj_outline_str += INDENTATION.join(
+                [f"{INDENTATION}Select outline color:{outline_color}\n",
+                 f"Select objects to display:{obj_to_display}\n"
+                 ])
+    obj_outline_str = obj_outline_str.rstrip("\n")
+    result += f"{obj_outline_str}"
+
+    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_ctg_header(MODULE_NAME, current_module_num)
+    main_block = build_main_block(inputs_galaxy)
+
+    module_pipeline = f"\n{header_block}{main_block}\n"
+    pipeline_lines.append(module_pipeline)
+
+    write_pipeline(OUTPUT_FILENAME, pipeline_lines)
--- a/starting_modules.py	Mon May 11 11:37:52 2020 +0000
+++ b/starting_modules.py	Sat Feb 06 09:38:45 2021 +0000
@@ -1,6 +1,5 @@
 import json
 import sys
-import os
 
 FOURSPACES = "    "
 
@@ -13,7 +12,7 @@
     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 + ":\n"
     _str += FOURSPACES + "Filter images?:%s\n" % filter_images
     _str += FOURSPACES + "Select the rule criteria:and (extension does isimage) (directory doesnot startwith \".\")\n"
 
@@ -45,7 +44,7 @@
         _str += FOURSPACES + "Match file and image metadata:\x5B\x5D\n"
         _str += FOURSPACES + "Use case insensitive matching?:No\n"
     else:
-        _str += FOURSPACES + "Metadata data type:Text\n"  #default Text,not possible to select in Galaxy
+        _str += FOURSPACES + "Metadata data type:Text\n"  # default Text,not possible to select in Galaxy
         _str += FOURSPACES + "Metadata types:{}\n"
         _str += FOURSPACES + "Extraction method count:%d\n" % method_count
 
@@ -70,19 +69,18 @@
             _str += FOURSPACES + "Extract metadata from:%s\n" % methods["con_metadata_extract_from"]["extract_metadata_from"]
 
             if methods["con_metadata_extract_from"]["extract_metadata_from"] == "Images matching a rule":
-                rule_str =""
+                rule_str = ""
                 for r in methods["con_metadata_extract_from"]["r_match"]:
                     if r["con_match"]["rule_type"] == "extension":
                         rule_str += " (" + r["con_match"]["rule_type"] + " " + r["con_match"]["operator"] + " " + \
-                                    r["con_match"]["match_type"]+")"
+                                    r["con_match"]["match_type"] + ")"
                     else:
-                        rule_str +=" (" + r["con_match"]["rule_type"] + " " + r["con_match"]["operator"] + " " +\
-                                   r["con_match"]["contain"] + " \"" + r["con_match"]["match_value"] +"\")"
+                        rule_str += " (" + r["con_match"]["rule_type"] + " " + r["con_match"]["operator"] + " " +\
+                            r["con_match"]["contain"] + " \"" + r["con_match"]["match_value"] + "\")"
 
-
-                _str += FOURSPACES + "Select the filtering criteria:" + methods["con_metadata_extract_from"]["match_all_any"] + rule_str +"\n"
+                _str += FOURSPACES + "Select the filtering criteria:" + methods["con_metadata_extract_from"]["match_all_any"] + rule_str + "\n"
             else:
-                _str += FOURSPACES + "Select the filtering criteria:and (file does contain \"\")\n" #this line is required even if it's not used
+                _str += FOURSPACES + "Select the filtering criteria:and (file does contain \"\")\n"  # this line is required even if it's not used
 
             _str += FOURSPACES + "Metadata file location:\n"
             _str += FOURSPACES + "Match file and image metadata:\x5B\x5D\n"
@@ -127,7 +125,7 @@
         _str += FOURSPACES + "Process as 3D?:%s\n" % process_3d
 
     else:
-        #the below lines are not relevant to "images matching rules", but needed in pipeline file
+        # the below lines are not relevant to "images matching rules", but needed in pipeline file
         _str += FOURSPACES + "Select the image type:Grayscale image\n"
         _str += FOURSPACES + "Name to assign these images:DNA\n"
         _str += FOURSPACES + "Match metadata:[]\n"
@@ -147,18 +145,18 @@
         for rule in nameandtypes["con_assign_a_name_to"]["r_match_rule"]:
 
             rule_str = ""
-            if len(rule["r_match"]) >0 :
+            if len(rule["r_match"]) > 0:
                 for r in rule["r_match"]:
-                        if r["con_match"]["rule_type"] == "file" or r["con_match"]["rule_type"] == "directory":
-                            rule_str += " (" + r["con_match"]["rule_type"] + " "+r["con_match"]["operator"]+" "+\
-                                        r["con_match"]["contain"]+" \"" + r["con_match"]["match_value"] +"\")"
-                        else:
-                            rule_str += " ("+ r["con_match"]["rule_type"] + " " + r["con_match"]["operator"] + " " + \
-                                        r["con_match"]["match_type"] + ")"
+                    if r["con_match"]["rule_type"] == "file" or r["con_match"]["rule_type"] == "directory":
+                        rule_str += " (" + r["con_match"]["rule_type"] + " " + r["con_match"]["operator"] + " " + \
+                            r["con_match"]["contain"] + " \"" + r["con_match"]["match_value"] + "\")"
+                    else:
+                        rule_str += " (" + r["con_match"]["rule_type"] + " " + r["con_match"]["operator"] + " " + \
+                            r["con_match"]["match_type"] + ")"
             else:
-                rule_str = " (file does contain \"\")"  #need to have a value even if it is not used
+                rule_str = " (file does contain \"\")"  # need to have a value even if it is not used
 
-            _str += FOURSPACES + "Select the rule criteria:" + rule["match_all_any"] + rule_str +"\n"
+            _str += FOURSPACES + "Select the rule criteria:" + rule["match_all_any"] + rule_str + "\n"
 
             img_or_obj = rule["con_select_image_type"]["select_image_type"]
 
@@ -171,8 +169,7 @@
 
             _str += FOURSPACES + "Select the image type:%s\n" % img_or_obj
 
-
-            intensity_range="Image metadata" #default value
+            intensity_range = "Image metadata"  # default value
             if img_or_obj == "Grayscale image" or img_or_obj == "Color image":
                 intensity_range = rule["con_select_image_type"]["con_set_intensity"]["set_intensity_range_from"]
 
@@ -183,7 +180,6 @@
             else:
                 _str += FOURSPACES + "Maximum intensity:255.0\n"
 
-
     return _str
 
 
@@ -192,7 +188,7 @@
 
     _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"
 
-    group_images =  groups["con_groups"]["group_images"]
+    group_images = groups["con_groups"]["group_images"]
 
     _str += FOURSPACES + "Do you want to group your images?:%s\n" % group_images
     _str += FOURSPACES + "grouping metadata count:1\n"
@@ -224,4 +220,4 @@
     output_str = img_str + metadata_str + nameandtypes_str + groups_str
 
     f.write(output_str)
-    f.close()
\ No newline at end of file
+    f.close()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/color_to_gray.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,79 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+ColorToGray:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:4|show_window:True|notes:\x5B\'Convert the color image to grayscale.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select the input image:OrigColor
+    Conversion method:Combine
+    Image type:RGB
+    Name the output image:OrigGray
+    Relative weight of the red channel:1.0
+    Relative weight of the green channel:1.0
+    Relative weight of the blue channel:1.0
+    Convert red to gray?:Yes
+    Name the output image:OrigRed
+    Convert green to gray?:Yes
+    Name the output image:OrigGreen
+    Convert blue to gray?:Yes
+    Name the output image:OrigBlue
+    Convert hue to gray?:Yes
+    Name the output image:OrigHue
+    Convert saturation to gray?:Yes
+    Name the output image:OrigSaturation
+    Convert value to gray?:Yes
+    Name the output image:OrigValue
+    Channel count:1
+    Channel number:Red\x3A 1
+    Relative weight of the channel:1.0
+    Image name:Channel1
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/color_to_gray_combine_channels.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,82 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+ColorToGray:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:4|show_window:True|notes:\x5B\'Convert the color image to grayscale.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select the input image:DNA
+    Conversion method:Combine
+    Image type:Channels
+    Name the output image:OrigGray
+    Relative weight of the red channel:1.0
+    Relative weight of the green channel:1.0
+    Relative weight of the blue channel:1.0
+    Convert red to gray?:Yes
+    Name the output image:OrigRed
+    Convert green to gray?:Yes
+    Name the output image:OrigGreen
+    Convert blue to gray?:Yes
+    Name the output image:OrigBlue
+    Convert hue to gray?:Yes
+    Name the output image:OrigHue
+    Convert saturation to gray?:Yes
+    Name the output image:OrigSaturation
+    Convert value to gray?:Yes
+    Name the output image:OrigValue
+    Channel count:2
+    Channel number:2
+    Relative weight of the channel:0.2
+    Image name:Channel1
+    Channel number:3
+    Relative weight of the channel:0.5
+    Image name:Channel1
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/color_to_gray_split_channels.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,82 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+ColorToGray:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:4|show_window:True|notes:\x5B\'Convert the color image to grayscale.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select the input image:DNA
+    Conversion method:Split
+    Image type:Channels
+    Name the output image:OrigGray
+    Relative weight of the red channel:1.0
+    Relative weight of the green channel:1.0
+    Relative weight of the blue channel:1.0
+    Convert red to gray?:Yes
+    Name the output image:OrigRed
+    Convert green to gray?:Yes
+    Name the output image:OrigGreen
+    Convert blue to gray?:Yes
+    Name the output image:OrigBlue
+    Convert hue to gray?:Yes
+    Name the output image:OrigHue
+    Convert saturation to gray?:Yes
+    Name the output image:OrigSaturation
+    Convert value to gray?:Yes
+    Name the output image:OrigValue
+    Channel count:2
+    Channel number:2
+    Relative weight of the channel:1.0
+    Image name:Image2
+    Channel number:3
+    Relative weight of the channel:1.0
+    Image name:Image3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/color_to_gray_split_hsv.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,79 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+ColorToGray:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:4|show_window:True|notes:\x5B\'Convert the color image to grayscale.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select the input image:DNA
+    Conversion method:Split
+    Image type:HSV
+    Name the output image:OrigGray
+    Relative weight of the red channel:1.0
+    Relative weight of the green channel:1.0
+    Relative weight of the blue channel:1.0
+    Convert red to gray?:Yes
+    Name the output image:OrigRed
+    Convert green to gray?:Yes
+    Name the output image:OrigGreen
+    Convert blue to gray?:Yes
+    Name the output image:OrigBlue
+    Convert hue to gray?:Yes
+    Name the output image:OutputHue
+    Convert saturation to gray?:No
+    Name the output image:
+    Convert value to gray?:Yes
+    Name the output image:OutputValue
+    Channel count:1
+    Channel number:Red\x3A 1
+    Relative weight of the channel:1.0
+    Image name:Channel1
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/color_to_gray_split_rgb.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,79 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+ColorToGray:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:4|show_window:True|notes:\x5B\'Convert the color image to grayscale.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select the input image:DNA
+    Conversion method:Split
+    Image type:RGB
+    Name the output image:OrigGray
+    Relative weight of the red channel:1.0
+    Relative weight of the green channel:1.0
+    Relative weight of the blue channel:1.0
+    Convert red to gray?:Yes
+    Name the output image:OutputRed
+    Convert green to gray?:Yes
+    Name the output image:OutputGreen
+    Convert blue to gray?:No
+    Name the output image:
+    Convert hue to gray?:Yes
+    Name the output image:OrigHue
+    Convert saturation to gray?:Yes
+    Name the output image:OrigSaturation
+    Convert value to gray?:Yes
+    Name the output image:OrigValue
+    Channel count:1
+    Channel number:Red\x3A 1
+    Relative weight of the channel:1.0
+    Image name:Channel1
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/overlay_outlines.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,63 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+OverlayOutlines:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:4|show_window:True|notes:\x5B\'Overlay the embryo outlines on the grayscale image.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Display outlines on a blank image?:No
+    Select image on which to display outlines:OrigGray
+    Name the output image:OutlineImage
+    Outline display mode:Color
+    Select method to determine brightness of outlines:Max of image
+    How to outline:Inner
+    Select outline color:#FF0000
+    Select objects to display:Embryos
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/overlay_outlines_blank_color.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,65 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+OverlayOutlines:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:4|show_window:True|notes:\x5B\'Overlay the embryo outlines on the grayscale image.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Display outlines on a blank image?:Yes
+    Select image on which to display outlines:None
+    Name the output image:OutputImage
+    Outline display mode:Color
+    Select method to determine brightness of outlines:Max of image
+    How to outline:Inner
+    Select outline color:#548dd4
+    Select objects to display:DNA1
+    Select outline color:#000000
+    Select objects to display:DNA3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/overlay_outlines_blank_grayscale.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,65 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+OverlayOutlines:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:4|show_window:True|notes:\x5B\'Overlay the embryo outlines on the grayscale image.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Display outlines on a blank image?:Yes
+    Select image on which to display outlines:None
+    Name the output image:OutputImage
+    Outline display mode:Grayscale
+    Select method to determine brightness of outlines:Max of image
+    How to outline:Outer
+    Select outline color:#FF0000
+    Select objects to display:DNA
+    Select outline color:#FF0000
+    Select objects to display:DNA1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/overlay_outlines_non_blank_color.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,63 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+OverlayOutlines:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:4|show_window:True|notes:\x5B\'Overlay the embryo outlines on the grayscale image.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Display outlines on a blank image?:No
+    Select image on which to display outlines:OrigGray
+    Name the output image:OutlineImage
+    Outline display mode:Color
+    Select method to determine brightness of outlines:Max of image
+    How to outline:Inner
+    Select outline color:#FF0000
+    Select objects to display:Embryos
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/overlay_outlines_non_blank_grayscale.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,65 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+OverlayOutlines:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:4|show_window:True|notes:\x5B\'Overlay the embryo outlines on the grayscale image.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Display outlines on a blank image?:No
+    Select image on which to display outlines:DNA1
+    Name the output image:OutputImage
+    Outline display mode:Grayscale
+    Select method to determine brightness of outlines:Max possible
+    How to outline:Thick
+    Select outline color:#FF0000
+    Select objects to display:Object1
+    Select outline color:#FF0000
+    Select objects to display:Object2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/tile.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,68 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+Tile:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:1|show_window:True|notes:\x5B\'Tile the original color image, the outlined image and the image of tracked labels together.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select an input image:OrigColor
+    Name the output image:AdjacentImage
+    Tile assembly method:Within cycles
+    Final number of rows:1
+    Final number of columns:12
+    Image corner to begin tiling:top left
+    Direction to begin tiling:row
+    Use meander mode?:No
+    Automatically calculate number of rows?:No
+    Automatically calculate number of columns?:Yes
+    Select an additional image to tile:OutlineImage
+    Select an additional image to tile:TrackedCells
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/tile_across_cycles.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,66 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+Tile:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:1|show_window:True|notes:\x5B\'Tile the original color image, the outlined image and the image of tracked labels together.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select an input image:DNA
+    Name the output image:TiledImage
+    Tile assembly method:Across cycles
+    Final number of rows:8
+    Final number of columns:5
+    Image corner to begin tiling:top right
+    Direction to begin tiling:column
+    Use meander mode?:No
+    Automatically calculate number of rows?:Yes
+    Automatically calculate number of columns?:No
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/tile_across_cyles.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,65 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+Tile:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:1|show_window:True|notes:\x5B\'Tile the original color image, the outlined image and the image of tracked labels together.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Select an input image:DNA
+    Name the output image:TiledImage
+    Tile assembly method:Across cycles
+    Final number of rows:8
+    Final number of columns:5
+    Image corner to begin tiling:top right
+    Direction to begin tiling:column
+    Use meander mode?:No
+    Automatically calculate number of rows?:Yes
+    Automatically calculate number of columns?:No
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/track_object.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,85 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+TrackObjects:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:7|show_window:True|notes:\x5B\'Track the embryos across images using the Overlap method\x3A tracked objects are identified by the amount of frame-to-frame overlap. Save an image of embryos labeled with a unique number across time.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Choose a tracking method:Overlap
+    Select the objects to track:Embryos
+    Select object measurement to use for tracking:None
+    Maximum pixel distance to consider matches:50
+    Select display option:Color and Number
+    Save color-coded image?:Yes
+    Name the output image:TrackedCells
+    Select the movement model:Both
+    Number of standard deviations for search radius:3.0
+    Search radius limit, in pixel units (Min,Max):2.0,10.0
+    Run the second phase of the LAP algorithm?:Yes
+    Gap closing cost:40
+    Split alternative cost:40
+    Merge alternative cost:40
+    Maximum gap displacement, in pixel units:5
+    Maximum split score:50
+    Maximum merge score:50
+    Maximum temporal gap, in frames:5
+    Filter objects by lifetime?:No
+    Filter using a minimum lifetime?:Yes
+    Minimum lifetime:1
+    Filter using a maximum lifetime?:No
+    Maximum lifetime:100
+    Mitosis alternative cost:80
+    Maximum mitosis distance, in pixel units:40
+    Average cell diameter in pixels:35.0
+    Use advanced configuration parameters:No
+    Cost of cell to empty matching:15.0
+    Weight of area difference in function matching cost:25.0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/track_object_distance_no_filter_min.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,85 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+TrackObjects:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:7|show_window:True|notes:\x5B\'Track the embryos across images using the Overlap method\x3A tracked objects are identified by the amount of frame-to-frame overlap. Save an image of embryos labeled with a unique number across time.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Choose a tracking method:Distance
+    Select the objects to track:DNA
+    Select object measurement to use for tracking:None
+    Maximum pixel distance to consider matches:50
+    Select display option:Color and Number
+    Save color-coded image?:Yes
+    Name the output image:OutputImage
+    Select the movement model:Both
+    Number of standard deviations for search radius:3.0
+    Search radius limit, in pixel units (Min,Max):2.0,10.0
+    Run the second phase of the LAP algorithm?:Yes
+    Gap closing cost:40
+    Split alternative cost:40
+    Merge alternative cost:40
+    Maximum gap displacement, in pixel units:5
+    Maximum split score:50
+    Maximum merge score:50
+    Maximum temporal gap, in frames:5
+    Filter objects by lifetime?:Yes
+    Filter using a minimum lifetime?:No
+    Minimum lifetime:1
+    Filter using a maximum lifetime?:Yes
+    Maximum lifetime:80
+    Mitosis alternative cost:80
+    Maximum mitosis distance, in pixel units:40
+    Average cell diameter in pixels:35.0
+    Use advanced configuration parameters:No
+    Cost of cell to empty matching:15.0
+    Weight of area difference in function matching cost:25.0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/track_object_follow_neighbors.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,85 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+TrackObjects:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:7|show_window:True|notes:\x5B\'Track the embryos across images using the Overlap method\x3A tracked objects are identified by the amount of frame-to-frame overlap. Save an image of embryos labeled with a unique number across time.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Choose a tracking method:Follow Neighbors
+    Select the objects to track:DNA
+    Select object measurement to use for tracking:None
+    Maximum pixel distance to consider matches:60
+    Select display option:Color only
+    Save color-coded image?:Yes
+    Name the output image:OutputImage
+    Select the movement model:Both
+    Number of standard deviations for search radius:3.0
+    Search radius limit, in pixel units (Min,Max):2.0,10.0
+    Run the second phase of the LAP algorithm?:Yes
+    Gap closing cost:40
+    Split alternative cost:40
+    Merge alternative cost:40
+    Maximum gap displacement, in pixel units:5
+    Maximum split score:50
+    Maximum merge score:50
+    Maximum temporal gap, in frames:5
+    Filter objects by lifetime?:Yes
+    Filter using a minimum lifetime?:No
+    Minimum lifetime:1
+    Filter using a maximum lifetime?:No
+    Maximum lifetime:100
+    Mitosis alternative cost:80
+    Maximum mitosis distance, in pixel units:40
+    Average cell diameter in pixels:36.0
+    Use advanced configuration parameters:Yes
+    Cost of cell to empty matching:11.0
+    Weight of area difference in function matching cost:20.0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/track_object_lap_velocity.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,85 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+TrackObjects:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:7|show_window:True|notes:\x5B\'Track the embryos across images using the Overlap method\x3A tracked objects are identified by the amount of frame-to-frame overlap. Save an image of embryos labeled with a unique number across time.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Choose a tracking method:LAP
+    Select the objects to track:DNA
+    Select object measurement to use for tracking:None
+    Maximum pixel distance to consider matches:50
+    Select display option:Color and Number
+    Save color-coded image?:Yes
+    Name the output image:OutputImage
+    Select the movement model:Velocity
+    Number of standard deviations for search radius:4.0
+    Search radius limit, in pixel units (Min,Max):5.0,11.0
+    Run the second phase of the LAP algorithm?:Yes
+    Gap closing cost:6
+    Split alternative cost:6
+    Merge alternative cost:6
+    Maximum gap displacement, in pixel units:6
+    Maximum split score:6
+    Maximum merge score:6
+    Maximum temporal gap, in frames:6
+    Filter objects by lifetime?:Yes
+    Filter using a minimum lifetime?:Yes
+    Minimum lifetime:1
+    Filter using a maximum lifetime?:Yes
+    Maximum lifetime:100
+    Mitosis alternative cost:6
+    Maximum mitosis distance, in pixel units:6
+    Average cell diameter in pixels:35.0
+    Use advanced configuration parameters:No
+    Cost of cell to empty matching:15.0
+    Weight of area difference in function matching cost:25.0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/track_object_measurement_intensity.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,85 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+TrackObjects:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:7|show_window:True|notes:\x5B\'Track the embryos across images using the Overlap method\x3A tracked objects are identified by the amount of frame-to-frame overlap. Save an image of embryos labeled with a unique number across time.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Choose a tracking method:Measurements
+    Select the objects to track:DNA
+    Select object measurement to use for tracking:Intensity_MADIntensity_Image1
+    Maximum pixel distance to consider matches:40
+    Select display option:Color only
+    Save color-coded image?:No
+    Name the output image:TrackedCells
+    Select the movement model:Both
+    Number of standard deviations for search radius:3.0
+    Search radius limit, in pixel units (Min,Max):2.0,10.0
+    Run the second phase of the LAP algorithm?:Yes
+    Gap closing cost:40
+    Split alternative cost:40
+    Merge alternative cost:40
+    Maximum gap displacement, in pixel units:5
+    Maximum split score:50
+    Maximum merge score:50
+    Maximum temporal gap, in frames:5
+    Filter objects by lifetime?:Yes
+    Filter using a minimum lifetime?:No
+    Minimum lifetime:1
+    Filter using a maximum lifetime?:Yes
+    Maximum lifetime:120
+    Mitosis alternative cost:80
+    Maximum mitosis distance, in pixel units:40
+    Average cell diameter in pixels:35.0
+    Use advanced configuration parameters:No
+    Cost of cell to empty matching:15.0
+    Weight of area difference in function matching cost:25.0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/track_object_overlap_no_filter_max.cppipe	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,85 @@
+CellProfiler Pipeline: http://www.cellprofiler.org
+Version:3
+DateRevision:319
+GitHash:
+ModuleCount:5
+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<folderField1>.*)
+    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:field1
+
+TrackObjects:[module_num:5|svn_version:\'Unknown\'|variable_revision_number:7|show_window:True|notes:\x5B\'Track the embryos across images using the Overlap method\x3A tracked objects are identified by the amount of frame-to-frame overlap. Save an image of embryos labeled with a unique number across time.\'\x5D|batch_state:array(\x5B\x5D, dtype=uint8)|enabled:True|wants_pause:False]
+    Choose a tracking method:Overlap
+    Select the objects to track:DNA
+    Select object measurement to use for tracking:None
+    Maximum pixel distance to consider matches:40
+    Select display option:Color only
+    Save color-coded image?:Yes
+    Name the output image:ColorCodedImage
+    Select the movement model:Both
+    Number of standard deviations for search radius:3.0
+    Search radius limit, in pixel units (Min,Max):2.0,10.0
+    Run the second phase of the LAP algorithm?:Yes
+    Gap closing cost:40
+    Split alternative cost:40
+    Merge alternative cost:40
+    Maximum gap displacement, in pixel units:5
+    Maximum split score:50
+    Maximum merge score:50
+    Maximum temporal gap, in frames:5
+    Filter objects by lifetime?:Yes
+    Filter using a minimum lifetime?:Yes
+    Minimum lifetime:2
+    Filter using a maximum lifetime?:No
+    Maximum lifetime:100
+    Mitosis alternative cost:80
+    Maximum mitosis distance, in pixel units:40
+    Average cell diameter in pixels:35.0
+    Use advanced configuration parameters:No
+    Cost of cell to empty matching:15.0
+    Weight of area difference in function matching cost:25.0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tile.py	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+
+import argparse
+import json
+
+from cp_common_functions import get_json_value
+from cp_common_functions import get_pipeline_lines
+from cp_common_functions import get_total_number_of_modules
+from cp_common_functions import INDENTATION
+from cp_common_functions import update_module_count
+from cp_common_functions import write_pipeline
+
+
+MODULE_NAME = "Tile"
+OUTPUT_FILENAME = "output.cppipe"
+
+
+def build_header(module_name, module_number):
+    result = "|".join([f"{module_name}:[module_num:{module_number}",
+                       "svn_version:\\'Unknown\\'",
+                       "variable_revision_number:1",
+                       "show_window:True",
+                       "notes:\\x5B\\'Tile the original color image, the outlined image and the image of tracked labels together.\\'\\x5D",
+                       "batch_state:array(\\x5B\\x5D, dtype=uint8)",
+                       "enabled:True",
+                       "wants_pause:False]\n"])
+    return result
+
+
+def build_main_block(input_params):
+    result = INDENTATION.join([f"{INDENTATION}Select an input image:{get_json_value(input_params,'input_image')}\n",
+                               f"Name the output image:{get_json_value(input_params,'output_image_name')}\n",
+                               f"Tile assembly method:{get_json_value(input_params,'con_assembly_method.assembly_method')}\n"
+                               ])
+
+    calc_rows = get_json_value(input_params, 'con_assembly_method.con_calc_no_row.calc_no_row')
+    no_of_rows = 8
+
+    calc_cols = get_json_value(input_params, 'con_assembly_method.con_calc_no_cols.calc_no_cols')
+    no_of_cols = 12
+
+    if calc_rows == "No":
+        no_of_rows = get_json_value(input_params, 'con_assembly_method.con_calc_no_row.no_of_row')
+
+    if calc_cols == "No":
+        no_of_cols = get_json_value(input_params, 'con_assembly_method.con_calc_no_cols.no_of_cols')
+
+    corner_to_begin = get_json_value(input_params, 'con_assembly_method.corner_to_begin')
+    direction_tiling = get_json_value(input_params, 'con_assembly_method.direction')
+    meander = get_json_value(input_params, 'con_assembly_method.meander_mode')
+
+    assembly_method = get_json_value(input_params, 'con_assembly_method.assembly_method')
+
+    result += INDENTATION.join(
+        [f"{INDENTATION}Final number of rows:{str(no_of_rows)}\n",
+         f"Final number of columns:{str(no_of_cols)}\n",
+         f"Image corner to begin tiling:{corner_to_begin}\n",
+         f"Direction to begin tiling:{direction_tiling}\n",
+         f"Use meander mode?:{meander}\n",
+         f"Automatically calculate number of rows?:{calc_rows}\n",
+         f"Automatically calculate number of columns?:{calc_cols}\n"
+         ])
+
+    if assembly_method == "Within cycles":
+        additionals = input_params['con_assembly_method']['rpt_additional_image']
+
+        for img in additionals:
+            result += INDENTATION.join(
+                [f"{INDENTATION}Select an additional image to tile:{get_json_value(img, 'additional_img')}\n"
+                 ])
+
+    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)
+
+    module_pipeline = f"\n{header_block}{main_block}\n"
+    pipeline_lines.append(module_pipeline)
+
+    write_pipeline(OUTPUT_FILENAME, pipeline_lines)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/track_objects.py	Sat Feb 06 09:38:45 2021 +0000
@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+
+import argparse
+import json
+
+from cp_common_functions import get_json_value
+from cp_common_functions import get_pipeline_lines
+from cp_common_functions import get_total_number_of_modules
+from cp_common_functions import INDENTATION
+from cp_common_functions import update_module_count
+from cp_common_functions import write_pipeline
+
+MODULE_NAME = "TrackObjects"
+OUTPUT_FILENAME = "output.cppipe"
+
+
+def build_header(module_name, module_number):
+    result = "|".join([f"{module_name}:[module_num:{module_number}",
+                       "svn_version:\\'Unknown\\'",
+                       "variable_revision_number:7",
+                       "show_window:True",
+                       "notes:\\x5B\\'Track the embryos across images using the Overlap method\\x3A tracked objects are identified by the amount of frame-to-frame overlap. Save an image of embryos labeled with a unique number across time.\\'\\x5D",
+                       "batch_state:array(\\x5B\\x5D, dtype=uint8)",
+                       "enabled:True",
+                       "wants_pause:False]\n"])
+    return result
+
+
+def build_main_block(input_params):
+    result = INDENTATION.join([f"{INDENTATION}Choose a tracking method:{get_json_value(input_params,'con_tracking_method.tracking_method')}\n",
+                               f"Select the objects to track:{get_json_value(input_params,'object_to_track')}\n"
+                               ])
+
+    tracking_method = get_json_value(input_params, 'con_tracking_method.tracking_method')
+
+    obj_measurement = "None"  # default value
+    if tracking_method == "Measurements":
+        measurement_category = get_json_value(input_params, 'con_tracking_method.con_measurement_category.measurement_category')
+        measurement = get_json_value(input_params, 'con_tracking_method.con_measurement_category.measurement')
+
+        if measurement_category == "Intensity" or measurement_category == "Location":
+            img_measure = get_json_value(input_params, 'con_tracking_method.con_measurement_category.img_measure')
+            obj_measurement = f"{measurement_category}_{measurement}_{img_measure}"
+        else:
+            obj_measurement = f"{measurement_category}_{measurement}"
+
+    result += INDENTATION.join([f"{INDENTATION}Select object measurement to use for tracking:{obj_measurement}\n"])
+
+    if tracking_method == "LAP":  # no max distance required, set default for pipeline
+        max_distance = 50
+    else:
+        max_distance = get_json_value(input_params, 'con_tracking_method.max_distance')
+
+    result += INDENTATION.join([f"{INDENTATION}Maximum pixel distance to consider matches:{max_distance}\n"])
+
+    display_option = get_json_value(input_params, 'con_tracking_method.display_option')
+
+    output_img_name = "TrackedCells"  # default value, required by cppipe regardless of its presence in UI
+    save = get_json_value(input_params, 'con_tracking_method.con_save_coded_img.save_coded_img')
+    if save == "Yes":
+        output_img_name = get_json_value(input_params, 'con_tracking_method.con_save_coded_img.name_output_img')
+
+    result += INDENTATION.join(
+        [f"{INDENTATION}Select display option:{display_option}\n",
+         f"Save color-coded image?:{save}\n",
+         f"Name the output image:{output_img_name}\n"
+         ])
+
+    # LAP method default values
+    movement_model = "Both"
+    no_std = 3.0
+    radius_limit_max = 10.0
+    radius_limit_min = 2.0
+    radius = "2.0,10.0"
+    run_second = "Yes"
+    gap_closing = 40
+    split_alt = 40
+    merge_alt = 40
+    max_gap_displacement = 5
+    max_split = 50
+    max_merge = 50
+    max_temporal = 5
+    max_mitosis_dist = 40
+    mitosis_alt = 80
+
+    # LAP method
+    if tracking_method == "LAP":
+        movement_model = get_json_value(input_params, 'con_tracking_method.movement_method')
+        no_std = get_json_value(input_params, 'con_tracking_method.no_std_radius')
+        radius_limit_max = get_json_value(input_params, 'con_tracking_method.max_radius')
+        radius_limit_min = get_json_value(input_params, 'con_tracking_method.min_radius')
+        radius = f"{radius_limit_min},{radius_limit_max}"
+
+        run_second = get_json_value(input_params, 'con_tracking_method.con_second_lap.second_lap')
+        if run_second == "Yes":
+            gap_closing = get_json_value(input_params, 'con_tracking_method.con_second_lap.gap_closing')
+            split_alt = get_json_value(input_params, 'con_tracking_method.con_second_lap.split_alt')
+            merge_alt = get_json_value(input_params, 'con_tracking_method.con_second_lap.merge_alt')
+            max_gap_displacement = get_json_value(input_params, 'con_tracking_method.con_second_lap.max_gap_displacement')
+            max_split = get_json_value(input_params, 'con_tracking_method.con_second_lap.max_split')
+            max_merge = get_json_value(input_params, 'con_tracking_method.con_second_lap.max_merge')
+            max_temporal = get_json_value(input_params, 'con_tracking_method.con_second_lap.max_temporal')
+            max_mitosis_dist = get_json_value(input_params, 'con_tracking_method.con_second_lap.max_mitosis_distance')
+            mitosis_alt = get_json_value(input_params, 'con_tracking_method.con_second_lap.mitosis_alt')
+
+    result += INDENTATION.join(
+        [f"{INDENTATION}Select the movement model:{movement_model}\n",
+         f"Number of standard deviations for search radius:{no_std}\n",
+         f"Search radius limit, in pixel units (Min,Max):{radius}\n",
+         f"Run the second phase of the LAP algorithm?:{run_second}\n",
+         f"Gap closing cost:{gap_closing}\n",
+         f"Split alternative cost:{split_alt}\n",
+         f"Merge alternative cost:{merge_alt}\n",
+         f"Maximum gap displacement, in pixel units:{max_gap_displacement}\n",
+         f"Maximum split score:{max_split}\n",
+         f"Maximum merge score:{max_merge}\n",
+         f"Maximum temporal gap, in frames:{max_temporal}\n"
+         ])
+
+    # common section
+    filter_by_lifetime = get_json_value(input_params, 'con_tracking_method.con_filter_by_lifetime.filter_by_lifetime')
+    use_min = "Yes"  # default
+    min_life = 1  # default
+    use_max = "No"  # default
+    max_life = 100  # default
+
+    if filter_by_lifetime == "Yes":
+        use_min = get_json_value(input_params, 'con_tracking_method.con_filter_by_lifetime.con_use_min.use_min')
+        if use_min == "Yes":
+            min_life = get_json_value(input_params, 'con_tracking_method.con_filter_by_lifetime.con_use_min.min_lifetime')
+
+        use_max = get_json_value(input_params, 'con_tracking_method.con_filter_by_lifetime.con_use_max.use_max')
+        if use_max == "Yes":
+            max_life = get_json_value(input_params, 'con_tracking_method.con_filter_by_lifetime.con_use_max.max_lifetime')
+
+    result += INDENTATION.join(
+        [f"{INDENTATION}Filter objects by lifetime?:{filter_by_lifetime}\n",
+         f"Filter using a minimum lifetime?:{use_min}\n",
+         f"Minimum lifetime:{min_life}\n",
+         f"Filter using a maximum lifetime?:{use_max}\n",
+         f"Maximum lifetime:{max_life}\n"
+         ])
+
+    # print 2 leftover from LAP
+    result += INDENTATION.join(
+        [f"{INDENTATION}Mitosis alternative cost:{mitosis_alt}\n",
+         f"Maximum mitosis distance, in pixel units:{max_mitosis_dist}\n"
+         ])
+
+    # Follow Neighbors
+    # defaults
+    avg_cell_diameter = 35.0
+    use_adv = "No"
+    cost_of_cell = 15.0
+    weight_of_area_diff = 25.0
+
+    if tracking_method == "Follow Neighbors":
+        avg_cell_diameter = get_json_value(input_params, 'con_tracking_method.avg_diameter')
+        use_adv = get_json_value(input_params, 'con_tracking_method.con_adv_parameter.adv_parameter')
+        if use_adv == "Yes":
+            cost_of_cell = get_json_value(input_params, 'con_tracking_method.con_adv_parameter.cost')
+            weight_of_area_diff = get_json_value(input_params, 'con_tracking_method.con_adv_parameter.weight')
+
+    result += INDENTATION.join(
+        [f"{INDENTATION}Average cell diameter in pixels:{avg_cell_diameter}\n",
+         f"Use advanced configuration parameters:{use_adv}\n",
+         f"Cost of cell to empty matching:{cost_of_cell}\n",
+         f"Weight of area difference in function matching cost:{weight_of_area_diff}\n"
+         ])
+
+    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)
+
+    module_pipeline = f"\n{header_block}{main_block}\n"
+    pipeline_lines.append(module_pipeline)
+
+    write_pipeline(OUTPUT_FILENAME, pipeline_lines)