diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000000000000000000000000000000000000..189142338a69ebcf1caaf58431539600a21b5154
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,45 @@
+# file GENERATED by distutils, do NOT edit
+setup.py
+ih/__init__.py
+ih/conf.py
+ih/imgproc.py
+ih/statistics.py
+ih/validator.py
+ih/workflow.py
+scripts/ih-adaptive-threshold
+scripts/ih-bitwise-and
+scripts/ih-bitwise-not
+scripts/ih-bitwise-or
+scripts/ih-bitwise-xor
+scripts/ih-blur
+scripts/ih-color-filter
+scripts/ih-contour-cut
+scripts/ih-convert-color
+scripts/ih-crawl
+scripts/ih-crop
+scripts/ih-data
+scripts/ih-edges
+scripts/ih-error-log
+scripts/ih-extract
+scripts/ih-extract-all
+scripts/ih-extract-multi
+scripts/ih-gaussian-blur
+scripts/ih-meanshift
+scripts/ih-median-blur
+scripts/ih-morphology
+scripts/ih-normalize-intensity
+scripts/ih-resize
+scripts/ih-run
+scripts/ih-setup
+scripts/ih-sql-aggregate
+scripts/ih-stats-anova
+scripts/ih-stats-correlate
+scripts/ih-stats-export
+scripts/ih-stats-histogram-bin
+scripts/ih-stats-normalize
+scripts/ih-stats-shoot-area
+scripts/ih-stats-threshold
+scripts/ih-stats-treatment-comp
+scripts/ih-stats-ttest
+scripts/ih-threshold
+scripts/osg-wrapper.sh
diff --git a/build/lib/ih/__init__.py b/build/lib/ih/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/build/lib/ih/conf.py b/build/lib/ih/conf.py
new file mode 100644
index 0000000000000000000000000000000000000000..f86eec3e47289c83717d8262b9ae0e571e414ba0
--- /dev/null
+++ b/build/lib/ih/conf.py
@@ -0,0 +1,1343 @@
+"""
+This file is part of Image Harvest.
+
+Image Harvest is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Image Harvest is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Image Harvest.  If not, see <http://www.gnu.org/licenses/>.
+"""
+
+import cv2
+
+"""
+A dictionary used to map input-output types to a cv2 color code
+"""
+colors = {
+    "bgr": {
+        "gray": [cv2.COLOR_BGR2GRAY],
+        "hsv": [cv2.COLOR_BGR2HSV],
+        "lab": [cv2.COLOR_BGR2LAB],
+        "ycrcb": [cv2.COLOR_BGR2YCR_CB]
+    },
+    "gray": {
+        "bgr": [cv2.COLOR_GRAY2BGR],
+        "hsv": [cv2.COLOR_GRAY2BGR, cv2.COLOR_BGR2HSV],
+        "lab": [cv2.COLOR_GRAY2BGR, cv2.COLOR_BGR2LAB],
+        "ycrcb": [cv2.COLOR_GRAY2BGR, cv2.COLOR_BGR2YCR_CB]
+    },
+    "hsv": {
+        "bgr": [cv2.COLOR_HSV2BGR],
+        "gray": [cv2.COLOR_HSV2BGR, cv2.COLOR_BGR2GRAY],
+        "lab": [cv2.COLOR_YCR_CB2BGR, cv2.COLOR_BGR2LAB],
+        "ycrcb": [cv2.COLOR_YCR_CB2BGR, cv2.COLOR_BGR2YCR_CB]
+    },
+    "lab": {
+        "bgr": [cv2.COLOR_LAB2BGR],
+        "gray": [cv2.COLOR_LAB2BGR, cv2.COLOR_BGR2GRAY],
+        "hsv": [cv2.COLOR_LAB2BGR, cv2.COLOR_BGR2HSV],
+        "ycrcb": [cv2.COLOR_LAB2BGR, cv2.COLOR_BGR2YCR_CB]
+    },
+    "ycrcb": {
+        "bgr": [cv2.COLOR_YCR_CB2BGR],
+        "gray": [cv2.COLOR_YCR_CB2BGR, cv2.COLOR_BGR2GRAY],
+        "hsv": [cv2.COLOR_YCR_CB2BGR, cv2.COLOR_BGR2HSV],
+        "lab": [cv2.COLOR_YCR_CB2BGR, cv2.COLOR_BGR2LAB]
+    }
+}
+
+"""
+A dicitonary used to map threshold-types to cv2 threshold codes
+"""
+thresholds = {
+    "binary": cv2.THRESH_BINARY,
+    "inverse": cv2.THRESH_BINARY_INV,
+    "truncate": cv2.THRESH_TRUNC,
+    "tozero": cv2.THRESH_TOZERO,
+    "otsu": cv2.THRESH_BINARY + cv2.THRESH_OTSU
+}
+
+"""
+A dictionary used to map adaptive-types to cv2 adaptive codes
+"""
+adaptives = {
+    "mean": cv2.ADAPTIVE_THRESH_MEAN_C,
+    "gauss": cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
+    "gaussian": cv2.ADAPTIVE_THRESH_GAUSSIAN_C
+}
+
+"""
+A dictionary used to map border-types to cv2 border codes
+"""
+borders = {
+    "default": cv2.BORDER_DEFAULT,
+    "constant": cv2.BORDER_CONSTANT,
+    "reflect": cv2.BORDER_REFLECT,
+    "replicate": cv2.BORDER_REPLICATE,
+    "transparent": cv2.BORDER_TRANSPARENT,
+    "wrap": cv2.BORDER_WRAP
+}
+
+"""
+A dictionary used to map morphology types to cv2 morphology codes
+"""
+morph = {
+    "dilate": cv2.MORPH_DILATE,
+    "erode": cv2.MORPH_ERODE,
+    "open": cv2.MORPH_OPEN,
+    "close": cv2.MORPH_CLOSE,
+    "gradient": cv2.MORPH_GRADIENT,
+    "tophat": cv2.MORPH_TOPHAT,
+    "blackhat": cv2.MORPH_BLACKHAT
+}
+
+"""
+A dictionary used to map kernel types to cv2 kernel codes
+"""
+kernels = {
+    "rect": cv2.MORPH_RECT,
+    "ellipse": cv2.MORPH_ELLIPSE,
+    "cross": cv2.MORPH_CROSS
+}
+
+"""
+A dictionary used to map center types to cv2 center codes
+"""
+centers = {
+    "random": cv2.KMEANS_RANDOM_CENTERS,
+    "pp": cv2.KMEANS_PP_CENTERS
+}
+
+"""
+A dictionary used to map termination types to cv2 termination codes
+"""
+ktermination = {
+    "accuracy": cv2.TERM_CRITERIA_EPS,
+    "iteration": cv2.TERM_CRITERIA_MAX_ITER,
+    "either": cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER
+}
+
+"""
+Defines the maximum size of a displayed image in total pixels.
+"""
+maxArea = 360000
+
+"""
+Defines imtype mapping
+"""
+typeMap = {
+    "rgbsv": "rgb",
+    "rgbtv": "rgb",
+    "fluosv": "fluo",
+    "fluotv": "fluo"
+}
+
+"""
+Defines all optional / required keys for all templates.
+"""
+
+templateKeys = {
+    "loading": {
+        "required": ["path", "base", "data", "order"],
+        "optional": ["translations", "filetype"],
+        "data": {
+            "required": ["type"],
+            "type": ["value", "file", "date"],
+            "value": {
+                "required": ["value", "type"],
+                "optional": ["translate"]
+            },
+            "file": {
+                "required": ["type", "value", "key", "keyColumn", "valueColumn"],
+                "optional": ["translate", "separator"]
+            },
+            "date": {
+                "required": ["type", "value", "format"],
+                "optional": []
+            }
+        },
+        "translations": {
+            
+        }
+    },
+    "config": {
+        "required": ["version", "installdir", "profile"],
+        "optional": ["cluster", "notify", "maxwalltime", "osg"],
+        "maxwalltime": {
+            "optional": ["images", "stats"]
+        },
+        "notify": {
+            "required": ["email", "pegasus_home"]
+        },
+        "osg": {
+            "required": ["tarball", "ssh"]
+        }
+    },
+    "imgproc": {
+        "required": ["workflows", "extract"],
+        "optional": ["options"],
+        "job": {
+            "required": ["executable", "inputs", "outputs", "arguments", "name"],
+            "optional": ["depends"]
+        },
+        "options": {
+            "required": [],
+            "optional": ["save-steps"]
+        },
+        "extract": {
+            "required": ["workflows"],
+            "optional": ["histogram-bin"],
+            "workflows": {
+                "required": [], # imtype are required, handled at run time.
+                "optional": []
+            },
+            "histogram-bin": {
+                "required": ["chunks", "group", "channels"],
+                "optional": []
+            }
+        }
+    },
+    "stats": {
+        "required": ["workflows"],
+        "optional": ["options"],
+        "job": {
+            "required": ["executable", "inputs", "outputs", "arguments", "name"],
+            "optional": ["depends"]
+        }
+    }
+}
+
+"""
+Defines valid date format character
+"""
+dateFormat = ["Y", "y", "M", "m", "d", "B", "b"]
+dateSep = ["/", "-", "_", " "]
+
+"""
+Defines required headers for output
+"""
+outHeaders = ["pegasusid", "experiment", "id", "genotype", "date", "treatment", "imgname", "imtype", "path"]
+
+"""
+Defines ALL possible output headers
+"""
+allHeaders = outHeaders + ["error", "rowNum", "colNum"]
+
+"""
+Defines required files for job checking
+"""
+jobFiles = ["crawl.json", "config.json", "imgproc.json", "stats.json", "images.db"]
+imgprocFiles = ["config.json", "imgproc.json", "images.db"]
+statisticsFiles = ["config.json", "stats.json"]
+
+workflowFile = "imgproc.json"
+configFile = "config.json"
+dbFile = "images.db"
+statsFile = "stats.json"
+outputdb = "output.db"
+
+
+"""
+Defines two things for stats functions.
+'Required' columns are the metadata columns a function needs to execute properly.
+'Exclude' columns are the metadata columns that become uninteresting after execution.
+"""
+statsColumns = {
+    "histogramBins": {
+        "ref": False,
+        "add": ["name", "minr", "ming", "minb", "maxr", "maxg", "maxb"],
+        "required": ["pegasusid", "experiment", "id", "date", "imtype", "imgname", "outputPath"],
+        "exclude": ["all"],
+        "overwrite": []
+    },
+    "ttest": {
+        "ref": True,
+        "add": [],
+        "required": ["pegasusid", "date", "imtype"],
+        "exclude": ["pegasusid", "path", "outputPath", "error", "id", "genotype", "treatment"],
+        "overwrite": []
+    },
+    "treatmentComp": {
+        "ref": True,
+        "add": [],
+        "required": ["pegasusid", "id", "genotype", "date", "treatment", "imtype"],
+        "exclude": ["pegasusid", "id", "path", "outputPath", "error"],
+        "overwrite": ["treatment"]
+    },
+    "shootArea": {
+        "ref": True,
+        "add": [],
+        "required": ["pegasusid", "id", "genotype", "date", "treatment", "imtype"],
+        "exclude": ["pegasusid", "imgname", "path", "outputPath", "error", "rowNum", "colNum"],
+        "overwrite": ["imtype"]
+    },
+    "normalize": {
+        "ref": True,
+        "add": [],
+        "required": ["pegasusid"],
+        "exclude": ["pegasusid", "path", "outputPath", "error"],
+        "overwrite": []
+    },
+    "correlation": {
+        "ref": True,
+        "add": [],
+        "required": ["pegasusid", "id", "date"],
+        "exclude": ["pegasusid", "path", "outputPath", "error", "rowNum", "colNum", "date", "imgname"],
+        "overwrite": []
+    },
+    "threshold": {
+        "ref": True,
+        "add": [],
+        "required": ["pegasusid"],
+        "exclude": ["pegasusid", "path", "outputPath", "error"],
+        "overwrite": []
+    },
+    "anova": {
+        "ref": False,
+        "add": ["factors"],
+        "required": ["pegasusid", "treatment", "date", "imtype"],
+        "exclude": ["pegasusid", "experiment", "id", "genotype", "date", "treatment", "imgname", "path", "outputPath", "error"],
+        "overwrite": ["imtype"]
+    }
+}
+
+"""
+Defines allowed image extensions, png is preferred.
+"""
+imageExtensions = [".png", ".jpg", ".jpeg", ".gif"]
+
+"""
+Defines allowed file extensions
+"""
+fileExtensions = {
+    "image": ".png",
+    "roi": ".json",
+    "binfile": ".json",
+    "csv": ".csv",
+}
+    
+
+"""
+Defines valid arguments for stats and image processing
+functions.
+"""
+valid = {
+    "ih-resize": {
+        "type": "imgproc",
+        "inputs": ["image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--scale": {
+                "type": "numeric"
+            },
+            "--width": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(1, 5001)
+            },
+            "--height": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(1, 5001)
+            }
+        }
+    },          
+    "ih-color-filter": {
+        "type": "imgproc",
+        "inputs": ["image", "roi"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--roi": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 1
+            },
+            "--logic": {
+                "type": "string",
+                "required": "true",
+                "complex": "true"
+            }
+        }
+    },
+    "ih-edges": {
+        "type": "imgproc",
+        "inputs": ["image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--threshold1": {
+                "type": "numeric",
+                "required": "true"
+            },
+            "--threshold2": {
+                "type": "numeric",
+                "required": "true"
+            },
+            "--apertureSize": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(1, 50)
+            },
+            "--L2gradient": {
+                "type": "exist"
+            }
+        }
+    },
+    "ih-contour-cut": {
+        "type": "imgproc",
+        "inputs": ["image", "image"],
+        "outputs": ["image", "roi"],
+        "arguments": {
+           "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--binary": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 1,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--basemin": {
+                "type": "numeric"
+            },
+            "--padminx": {
+                "type": "numeric"
+            },
+            "--padmaxx": {
+                "type": "numeric"
+            },
+            "--padminy": {
+                "type": "numeric"
+            },
+            "--padmaxy": {
+                "type": "numeric"
+            },
+            "--resize": {
+                "type": "exist"
+            },
+            "--returnBound": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 1,
+                "value": ""
+            },
+            "--roiwrite": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 1
+            }
+        }
+    },
+    "ih-crop": {
+        "type": "imgproc",
+        "inputs": ["image", "roi"],
+        "outputs": ["image"],
+        "arguments": {
+           "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--roi": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 1,
+                "required": "true"
+            },
+            "--resize": {
+                "type": "exist"
+            }
+        }
+    },
+    "ih-morphology": {
+        "type": "imgproc",
+        "inputs": ["image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--morphType": {
+                "type": "string",
+                "validation": "dictionary",
+                "value": morph,
+                "required": "true"
+            },
+            "--ktype": {
+                "type": "string",
+                "validation": "dictionary",
+                "value": kernels,
+                "required": "true"
+            },
+            "--kwidth": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(1, 256, 2),
+                "required": "true"
+            },
+            "--kheight": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(1, 256, 2),
+                "required": "true"
+            },
+            "--anchorx": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(-255, 256),
+            },
+            "--anchory": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(-255, 256),
+            },
+            "--iterations": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(1, 100)
+            },
+            "--border": {
+                "type": "string",
+                "validation": "dictionary",
+                "value": borders
+            }
+        }
+    },
+    "ih-normalize-intensity": {
+        "type": "imgproc",
+        "inputs": ["image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            }
+        }
+    },
+    "ih-gaussian-blur": {
+        "type": "imgproc",
+        "inputs": ["image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--kwidth": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(1, 256, 2),
+                "required": "true"
+            },
+            "--kheight": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(1, 256, 2),
+                "required": "true"
+            },
+            "--sigmax": {
+                "type": "numeric"
+            },
+            "--sigmay": {
+                "type": "numeric"
+            },
+            "--border": {
+                "type": "string",
+                "validation": "dictionary",
+                "value": borders
+            }
+        }
+    },
+    "ih-median-blur": {
+        "type": "imgproc",
+        "inputs": ["image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--ksize": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(1, 256, 2),
+                "required": "true"
+            }
+        }
+    },
+    "ih-blur": {
+        "type": "imgproc",
+        "inputs": ["image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--kwidth": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(1, 256, 2),
+                "required": "true"
+            },
+            "--kheight": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(1, 256, 2),
+                "required": "true"
+            },
+            "--anchorx": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(-255, 256),
+            },
+            "--anchory": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(-255, 256),
+            },
+            "--border": {
+                "type": "string",
+                "validation": "dictionary",
+                "value": borders
+            }
+        }
+    },
+    "ih-adaptive-threshold": {
+        "type": "imgproc",
+        "inputs": ["image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--value": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(0, 256),
+                "required": "true"
+            },
+            "--adaptiveType": {
+                "type": "string",
+                "validation": "dictionary",
+                "value": adaptives,
+                "required": "true"
+            },
+            "--thresholdType": {
+                "type": "string",
+                "validation": "dictionary",
+                "value": {"binary": "", "inverse": ""},
+                "required": "true"
+            },
+            "--blockSize": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(1, 256, 2),
+                "required": "true"
+            },
+            "--C": {
+                "type": "numeric",
+                "required": "true",
+            }
+        }
+    },
+    "ih-meanshift": {
+        "type": "imgproc",
+        "inputs": ["image"],
+        "outputs": ["image"],
+        "weight": .3,
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--spatial_radius": {
+                "type": "numeric",
+                "required": "true"
+            },
+            "--range_radius": {
+                "type": "numeric",
+                "required": "true"
+            },
+            "--min_density": {
+                "type": "numeric",
+                "required": "true"
+            }
+        }
+    },
+    "ih-convert-color": {
+        "type": "imgproc",
+        "inputs": ["image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--intype": {
+                "type": "string",
+                "validation": "dictionary",
+                "value": colors,
+                "required": "true"
+            },
+            "--outtype": {
+                "type": "string",
+                "validation": "dictionary",
+                "key": "--intype",
+                "value": colors,
+                "required": "true"
+            }
+        }
+    },
+    "ih-threshold": {
+        "type": "imgproc",
+        "inputs": ["image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--thresh": {
+                "type": "numeric"
+            },
+            "--max": {
+                "type": "numeric",
+                "validation": "list",
+                "value": range(0, 256)
+            },
+            "--type": {
+                "type": "string",
+                "validation": "list",
+                "value": ["binary", "trunc", "otsu", "tozero"]
+            }
+        }
+    },
+    "ih-bitwise-or": {
+        "type": "imgproc",
+        "inputs": ["image", "image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input1": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--input2": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 1,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            }
+        }
+    },
+    "ih-bitwise-xor": {
+        "type": "imgproc",
+        "inputs": ["image", "image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input1": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--input2": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 1,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            }
+        }
+    },    
+    "ih-bitwise-not": {
+        "type": "imgproc",
+        "inputs": ["image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            }
+        }
+    },       
+    "ih-bitwise-and": {
+        "type": "imgproc",
+        "inputs": ["image", "image"],
+        "outputs": ["image"],
+        "arguments": {
+            "--input1": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--input2": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 1,
+                "required": "true"
+            },
+            "--output": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outputdir": {
+                "type": "overwrite",
+                "value": "."
+            },
+            "--mask": {
+                "type": "exist"
+            }
+        }
+    },
+    "ih-extract": {
+        "type": "system",
+        "inputs": ["image", "binfile"],
+        "outputs": ["none"],
+        "arguments": {
+            "--input": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--dimensions": {
+                "type": "exist"
+            },
+            "--pixels": {
+                "type": "exist"
+            },
+            "--moments": {
+                "type": "exist"
+            },
+            "--bins": {
+                "type": "string"
+            },
+            "--channels": {
+                "type": "exist"
+            },
+            "--hull": {
+                "type": "exist"
+            },
+            "--circle": {
+                "type": "exist"
+            }
+        }
+    },
+    "ih-error-log": {
+         "type": "imgproc"   
+    },
+    
+    
+    
+    "ih-extract-all": {
+        "type": "system"
+    },
+    "ih-extract-multi": {
+        "type": "system"
+    },
+    "ih-sql-aggregate": {
+        "type": "system"
+    },
+    "osg-wrapper.sh": {
+        "type": "system"
+    },
+    
+    
+    
+    "ih-stats-export": {
+        "type": "statistics",
+        "inputs": ["table"],
+        "outputs": ["csv"],
+        "arguments": {
+            "--table": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--fname": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            }
+        }
+    },  
+    "ih-stats-histogram-bin": {
+        "type": "system",
+        "inputs": ["table"],
+        "outputs": ["table"],
+        "arguments": {
+            "--intable": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outtable": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--channels": {
+                "type": "dict",
+                "required": "true"
+            },
+            "--group": {
+                "type": "dict",
+                "required": "true"
+            },
+            "--chunks": {
+                "type": "dict",
+                "required": "true"
+            }
+        }
+    },
+    "ih-stats-ttest": {
+        "type": "statistics",
+        "inputs": ["table"],
+        "outputs": ["table"],
+        "arguments": {
+            "--intable": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outtable": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--comp": {
+                "type": "string",
+                "validation": "list",
+                "value": ["imtype", "imgname"],
+                "required": "true"
+            },
+            "--overwrite": {
+                "type": "overwrite",
+                "value": "",
+                "required": "true"
+            }
+        }
+    },
+    "ih-stats-treatment-comp": {
+        "type": "statistics",
+        "inputs": ["table"],
+        "outputs": ["table"],
+        "arguments": {
+            "--intable": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outtable": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--type": {
+                "type": "string",
+                "validation": "list",
+                "value": ["ratio", "difference"],
+                "required": "true"
+            },
+            "--direction": {
+                "type": "string",
+                "validation": "list",
+                "value": ["Control", "Stress"],
+                "required": "true"
+            },
+            "--comp": {
+                "type": "string",
+                "validation": "list",
+                "value": ["imtype", "imgname"],
+                "required": "true"
+            },
+            "--overwrite": {
+                "type": "overwrite",
+                "value": "",
+                "required": "true"
+            }
+        }
+    },
+    "ih-stats-anova": {
+        "type": "statistics",
+        "inputs": ["table"],
+        "outputs": ["table"],
+        "arguments": {
+            "--group": {
+                "type": "list",
+                "required": "true",
+                "join": " "
+            },
+            "--intable": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outtable": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--overwrite": {
+                "type": "overwrite",
+                "value": "",
+                "required": "true"
+            }
+        }
+    },
+    "ih-stats-shoot-area": {
+        "type": "statistics",
+        "inputs": ["table"],
+        "outputs": ["table"],
+        "arguments": {
+            "--group": {
+                "type": "list",
+                "required": "true",
+                "join": " "
+            },
+            "--intable": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outtable": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--overwrite": {
+                "type": "overwrite",
+                "value": "",
+                "required": "true"
+            }
+        }
+    },
+    "ih-stats-threshold": {
+        "type": "statistics",
+        "inputs": ["table"],
+        "outputs": ["table"],
+        "arguments": {
+            "--thresh": {
+                "type": "numeric",
+                "required": "true"
+            },
+            "--intable": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outtable": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--overwrite": {
+                "type": "overwrite",
+                "value": "",
+                "required": "true"
+            }
+        }
+    },
+    "ih-stats-normalize": {
+        "type": "statistics",
+        "inputs": ["table"],
+        "outputs": ["table"],
+        "arguments": {
+            "--column": {
+                "type": "string"
+            },
+            "--intable": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outtable": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--overwrite": {
+                "type": "overwrite",
+                "value": "",
+                "required": "true"
+            }
+        }
+    },
+    "ih-stats-correlate": {
+        "type": "statistics",
+        "inputs": ["table", "csv", "csv"],
+        "outputs": ["table"],
+        "arguments": {
+            "--intable": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--outtable": {
+                "type": "derived",
+                "key": "outputs",
+                "index": 0,
+                "required": "true"
+            },
+            "--datafile": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 1,
+                "required": "true"
+            },
+            "--dataheaders": {
+                "type": "derived",
+                "key": "inputs",
+                "index": 2,
+                "required": "true"
+            },
+            "--overwrite": {
+                "type": "overwrite",
+                "value": "",
+                "required": "true"
+            }
+        }
+    }
+}
diff --git a/build/lib/ih/imgproc.py b/build/lib/ih/imgproc.py
new file mode 100644
index 0000000000000000000000000000000000000000..78f6af66a2bb827e533e59394f93bf52d1d2971d
--- /dev/null
+++ b/build/lib/ih/imgproc.py
@@ -0,0 +1,1217 @@
+"""
+This file is part of Image Harvest.
+
+Image Harvest is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Image Harvest is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Image Harvest.  If not, see <http://www.gnu.org/licenses/>.
+
+.. module:: imgproc
+    :platform: Mac, Linux
+    :synopsis: Image processing function wrappers to opencv.
+
+.. moduleauthor:: Avi Knecht <avi@kurtknecht.com>
+
+"""
+
+import os
+import cv2
+import numpy as np
+import math
+import conf
+import sqlite3
+import pymeanshift as pms
+import traceback
+import json
+
+class ColorFilter(object):
+    
+    """
+    Color Filtration logic container.
+    """
+    def __init__(self, filter):
+        self.tokens = {
+            "True": True,
+            "False": False,
+            "and": lambda left, right: np.logical_and(left, right),
+            "or": lambda left, right: np.logical_or(left, right),
+            ">": lambda left, right: left > right,
+            "<": lambda left, right: left < right,
+            ">=": lambda left, right: left >= right,
+            "<=": lambda left, right: left <= right,
+            "=": lambda left, right: left == right,
+            "+": lambda left, right: left + right,
+            "-": lambda left, right: left - right,
+            "*": lambda left, right: left * right,
+            "/": lambda left, right: left / right,
+            "max": lambda left, right: np.maximum(left, right),
+            "min": lambda left, right: np.minimum(left, right),
+            "not": lambda left, right: np.invert(left),
+            "(": "(",
+            ")": ")",
+        }
+        self.filterString = filter
+        self.emptyRes = True
+        return
+    
+    def _createArgList(self):
+        s = self.filterString.replace("(", " ( ")
+        s = s.replace(")", " ) ")
+        self.filter = []
+        for item in s.split():
+            if item in self.tokens:
+                self.filter.append(self.tokens[item])
+            else:
+                try:
+                    val = int(item)
+                    self.filter.append(val)
+                except:
+                    raise Exception("Invalid logic string.")
+        #self.filter = [self.tokens[x] if x in self.tokens else int(x) for x in s.split()]
+        return
+    
+    def _find(self, what, start = 0):
+        return [i for i,x in enumerate(self.filter) if x == what and i >= start]
+    
+    def _parens(self):
+        left_1st = self._find("(")
+        if not left_1st:
+            return False, -1, -1
+        left = left_1st[-1]
+        right = self._find(")", left + 2)[0]
+        return True, left, right
+    
+    def _eval(self, filter):
+        return filter[1](filter[0], filter[2])
+    
+    def _formattedEval(self, filter):
+        if not filter:
+            return self.emptyRes
+        if len(filter) == 1:
+            return filter[0]
+        
+        has_parens, l_paren, r_paren = self._parens()
+        
+        if not has_parens:
+            return self._eval(filter)
+        
+        filter[l_paren:r_paren + 1] = [self._eval(filter[l_paren+1:r_paren])]
+        self.emptyRes = self._eval
+        return self._formattedEval(filter)
+    
+    def apply(self, image, roi):
+        self.tokens["r"] = image[:,:,2].astype(float)
+        self.tokens["g"] = image[:,:,1].astype(float)
+        self.tokens["b"] = image[:,:,0].astype(float)
+        self._createArgList()
+        result = cv2.cvtColor(np.where(self._formattedEval(self.filter), 255, 0).astype(np.uint8), cv2.COLOR_GRAY2BGR)
+        image[roi[0]:roi[1], roi[2]:roi[3]] = cv2.bitwise_and(image[roi[0]:roi[1], roi[2]:roi[3]], result[roi[0]:roi[1], roi[2]:roi[3]])
+        return image
+    
+    
+
+class Image(object):
+    
+    """
+    An individual image.  Each image is loaded in as its own instance of the Image class for processing.
+    """
+    def __init__(self, input, outputdir = ".", writename = None, dev = False, db = None, dbid = None):
+        """
+        :param input: The input resource, either a path to an image or a raw numpy array.
+        :type resource: numpy.ndarray or str
+        :param outputdir: The directory to write output files
+        :type outputdir: str
+        :param writename: The name to write the output file as, should include extension.
+        :type writename: str
+        :param dev: Dev mode will do something...
+        :type dev: bool
+        """
+        if os.path.isdir(outputdir):
+            self.states = {}
+            self._loadDb(db, dbid)
+            self.input = input
+            self.fname, self.image = self._loadResource(input)
+            self.y = self.image.shape[0]
+            self.x = self.image.shape[1]
+            self.outputdir = os.path.abspath(outputdir)
+            if writename:
+                self.writename = writename
+            elif isinstance(input, np.ndarray):
+                self.writename = "out.png"
+            else:
+                self.writename = os.path.basename(input)
+            self.dev = dev
+            self.window = 1
+        else:
+            raise Exception("Invalid output!")
+        return
+    
+    def _closeDb(self):
+        if self.conn:
+            self.conn.close()
+        return
+    
+    def _loadDb(self, db, dbid):
+        if db:
+            if os.path.isfile(db):
+                if dbid:
+                    self.dbid = dbid
+                    self.conn = sqlite3.connect(db, check_same_thread = False)
+                    self.conn.row_factory = sqlite3.Row
+                    result = self.conn.execute("select pegasusid from images where pegasusid=?", (self.dbid,))
+                    if not result.fetchone():
+                        raise Exception("Invalid pegasusid given!")
+                    self._addColumn("error")
+                else:
+                    raise Exception("A database id must be provided if you give a database.")
+            else:
+                raise Exception("Invalid database given!")
+        else:
+            self.conn = False
+        return
+
+    def _addColumn(self, column, tablename = "images"):
+        if self.conn:
+            if column not in [row["name"] for row in self.conn.execute("PRAGMA table_info(" + tablename + ");")]:
+                self.conn.execute("alter table " + tablename + " add column " + column + ";")
+                self.conn.commit()
+        return
+    
+    def _loadROIArg(self, arg, i):
+        vals = {
+            0: 0,
+            1: self.y,
+            2: 0,
+            3: self.x
+        }
+        arg = str(arg)
+        if arg == "-1":
+            return vals[i]
+        arg = arg.replace("x", str(self.x)).replace("y", str(self.y)).replace(" ","")
+        if "-" in arg:
+            try:
+                left, right = arg.split("-")
+                return int(left) - int(right)
+            except:
+                raise Exception("Could not load roi arg '%s'" % (arg,))
+        elif "+" in arg:
+            try:
+                left, right = arg.split("+")
+                return int(left) + int(right)
+            except:
+                raise Exception("Could not load roi arg '%s'" % (arg,))
+        elif "/" in arg:
+            try:
+                left, right = arg.split("/")
+                return int(left) / int(right)
+            except:
+                raise Exception("Could not load roi arg '%s'" % (arg,))
+        else:
+            return int(arg)
+    
+    def _loadROI(self, roi):
+        """
+        :param roi: The region of interest to load.
+        :type roi: list or file
+        :return: The region of interest of form [ystart, yend, xstart, xend]
+        :rtype: list
+        :raises OSError: if the input path does not exist.
+        
+        Loads a region of interest, either a path to an roi or a raw list.
+        """
+        if not roi:
+            roi = [-1, -1, -1, -1]
+        if isinstance(roi, list):
+            return [self._loadROIArg(z, i) for i,z in enumerate(roi)]
+        else:
+            if os.path.isfile(roi):
+                try:
+                    with open(roi, "r") as rh:
+                        r = json.load(rh)
+                        if all(x in r for x in ["xstart", "xend", "ystart", "yend"]):
+                            return [self._loadROIArg(r["ystart"], 0), self._loadROIArg(r["yend"], 1), self._loadROIArg(r["xstart"], 2), self._loadROIArg(r["xend"], 3)]
+                        else:
+                            raise Exception("Input roi file '%s' needs xstart, xend, ystart, and yend definitions!" % (roi,))
+                except Exception as e:
+                    print traceback.format_exc()
+                    raise Exception("Input roi file '%s' is not valid json!" % (roi,))
+            else:
+                raise Exception("Input path to roi file '%s' does not exist!" % (roi,))
+        return
+    
+    def _writeROI(self, roi, output):
+        """
+        :param roi: The region of interest to write.
+        :type roi: list
+        """
+        try:
+            with open(self.outputdir + "/" + output, "w") as wh:
+                wh.write(json.dumps({"ystart": roi[0], "yend": roi[1], "xstart": roi[2], "xend": roi[3]}, indent = 4))
+        except:
+            raise Exception("Could not write roi.")
+        return
+    
+    def _loadBins(self, binlist):
+        """
+        :param bin: The bin to load
+        :type bin: list or file
+        """
+        
+        if isinstance(binlist, list):
+            return binlist
+        else:
+            if os.path.isfile(binlist):
+                try:
+                    with open(binlist, "r") as rh:
+                        return json.load(rh)
+                except:
+                    raise Exception("Bin list not valid json!")
+            else:
+                raise Exception("Bin file does not exist.")
+        return
+    
+    def _loadResource(self, resource):
+        """
+        :param resource: The resource to load.
+        :type resource: numpy.ndarray or file
+        :return: The image
+        :rtype: numpy.ndarray
+        :raises OSError: if the input path does not exist.
+            
+        Loads a resource, either a path to an image or a raw numpy array.
+        """
+        if isinstance(resource, np.ndarray):
+            return ("unknown", resource.copy())
+        else:
+            if resource in self.states:
+                return (resource, self.states[resource].copy())
+            elif os.path.isfile(resource):
+                image = cv2.imread(resource)
+                if image is not None:
+                    return (os.path.basename(resource), image)
+                else:
+                    if self.conn:
+                        self.conn.execute("update images set error =? where pegasusid = ?", ("Load Error, input is not an image.", self.dbid))
+                        self.conn.commit()
+                    raise Exception("Input is not an image.")
+            else:
+                if self.conn:
+                    self.conn.execute("update images set error = ? where pegasusid = ?", ("Load Error, input path doesn't exist or specified resource is not a saved state.", self.dbid))
+                    self.conn.commit()
+                raise Exception("Input path to resource does not exist.")
+        return
+    
+    def _getMergedContour(self):
+        """
+        Assumes that image is already binary
+        """
+        if self._isColor():
+            binary = cv2.inRange(self.image.copy(), np.array([1, 1, 1], np.uint8), np.array([255, 255, 255], np.uint8))
+        else:
+            binary = self.image.copy()
+        contours,hierarchy = cv2.findContours(binary, 1, 2)
+        merged = []
+        for cnt in contours:
+            for point in cnt:
+                merged.append([point[0][0], point[0][1]])
+        return np.array(merged, dtype=np.int32)
+    
+    def _colorHistogram(self):
+        """
+        :return: A list of histograms, corresponding to R, G, B.
+        :rtype: List of numpy arrays.
+        
+        Calculates a normalized colorHistogram of the current image.  
+        The intensity is normalized between 0 and 255.
+        """
+        returnhist = []    
+    
+        for ch in range(0, 3):
+            hist_item = cv2.calcHist([self.image], [ch], None, [256], [1,255])
+            cv2.normalize(hist_item, hist_item, 0, 255, cv2.NORM_MINMAX)
+            hist = np.int32(np.around(hist_item))
+            returnhist.append(hist)
+        return returnhist
+    
+    def _isColor(self, image = None):
+        image = self.image if image is None else image
+        return len(image.shape) == 3
+    
+    def save(self, name):
+        """
+        :param name: The name to save the image under.
+        :type name: str OR any hashable type.
+        
+        This function saves the current image in the 'states' variable under
+        the specified name.  It can then be reloaded using the :py:meth:`~ih.imgproc.Image.restore`
+        method.
+        """
+        self.states[name] = self.image.copy()
+        return
+    
+    def restore(self, name):
+        """
+        :param name: The name the image is saved under.
+        :type name: str OR any hashable type.
+        
+        Reloads a previously saved image from the 'states' variable.
+        """
+        if name in self.states:
+            self.image = self.states[name].copy()
+            self.y = self.image.shape[0]
+            self.x = self.image.shape[1]
+        else:
+            print "Invalid state specified."
+        return
+    
+    def list(self):
+        """
+        Lists all saved states.
+        """
+        for state in self.states:
+            print state
+        return
+    
+    def destroy(self):
+        """
+        Destroys all currently open windows.
+        """
+        cv2.destroyAllWindows()
+        return
+    
+    def wait(self):
+        """
+        Waits until a key is pressed, then destroys all windows and
+        continues program execution.
+        """
+        cv2.waitKey(0)
+        self.destroy()
+        return
+    
+    def show(self, title = None, state = None):
+        """ 
+            :param title: The title to give the display window, if left blank one will be created.
+            :type title: str
+            :return: None
+            
+            Displays the image in a window.  Utilizes the :py:meth:`~ih.imgproc.Image.resize` function.
+            If a title is not specified, the window will be named 'windowX' where X is the number of times
+            show has been called.
+            
+        """
+        cv2.imshow(title if title else "window " + str(self.window), self.resize(state))
+        self.window += 1
+        return
+    
+    def resizeSelf(self, scale = None, width = None, height = None):
+        """
+        :param scale: Value to scale image by.
+        :type scale: float
+        :param width: Target width of image.
+        :type width: int
+        :param height: Target height of image.
+        :type height: int
+        
+        Resizes the current image.  If scale is set, it simply resizes the
+        width and height of the image based on the scale.  If only one of width
+        or height is set, it scales the other accordingly.  If both width
+        and height are set, it scales the image to the exact size specified.
+        """
+        if scale or width or height:
+            if scale:
+                self.image = cv2.resize(self.image, (int(self.x * scale), int(self.y * scale)))
+            elif width and height:
+                self.image = cv2.resize(self.image, height, width)
+            elif width:
+                scale = float(width) / float(self.x)
+                self.image = cv2.resize(self.image, (int(self.x * scale), int(self.y * scale)))
+            elif height:
+                scale = float(height) / float(self.y)
+                self.image = cv2.resize(self.image, (int(self.x * scale), int(self.y * scale)))
+            self.y = self.image.shape[0]
+            self.x = self.image.shape[1]
+        return
+    
+    def resize(self, state = None):
+        """
+        If the image is large than conf.maxArea, resize its total area down to conf.maxArea.
+        This function is primarily used for viewing purposes, and as such, it does not resize
+        the base image, but creates a copy to resize instead.
+        """
+        if (state):
+          im = self.states[state].copy()
+          if (im.shape[0] * im.shape[1] > conf.maxArea):
+              scale = 1 / math.sqrt((im.shape[1] * im.shape[0]) / conf.maxArea)
+              return cv2.resize(im, (int(im.shape[1] * scale), int(im.shape[0] * scale)))
+        elif (self.image.shape[0] * self.image.shape[1] > conf.maxArea):
+            scale = 1 / math.sqrt((self.image.shape[1] * self.image.shape[0]) / conf.maxArea)
+            return cv2.resize(self.image.copy(), (int(self.x*scale), int(self.y*scale)))
+        else:
+            return self.image
+    
+    def write(self, name = None):
+        """
+        Writes the current image to the given output directory, with the given name.
+        """
+        writename = self.writename if not name else name
+        cv2.imwrite(self.outputdir + "/" + writename, self.image)
+        return
+    
+    def convertColor(self, intype, outtype):
+        """ 
+        :param intype: The input image type
+        :type intype: str
+        :param outtype: The output image type
+        :type outtype: str
+        :return: The converted image.
+        :rtype: numpy.ndarray
+        :raises: KeyError
+        
+        Converts the given image between color spaces, based on the given types.
+        Supported types are: bgr, gray, hsv, lab, and ycrcb.  Note, you cannot
+        restore color to a gray image with this function, for that you must use
+        bitwise_and with an appropriate mask + image.  
+        """
+        if intype in conf.colors:
+            if outtype in conf.colors[intype]:
+                for code in conf.colors[intype][outtype]:
+                    self.image = cv2.cvtColor(self.image, code)
+            else:
+                raise KeyError(outtype + " is not a valid output type for the input type: " + intype)
+        else:
+            raise KeyError(intype + " is not a valid image type.")
+        return
+    
+    def threshold(self, thresh, max = 255, type = "binary"):
+        """
+        :param thresh: Threshold value.
+        :type thresh: int
+        :param max: Write value for binary threshold.
+        :type max: int
+        :param type: Threhsold type.
+        :type type: str
+        :return: The thresholded image.
+        :rtype: numpy.ndarray
+        :raises KeyError: if the specified threshold type doesn't exist.
+            
+        Thresholds the image based on the given type.  The image must be 
+        grayscale to be thresholded.  If the image is of type 'bgr' it is
+        automatically converted to grayscale before thresholding.
+        Supported types are: binary, truncate, tozero, and otsu.
+        """
+        if self._isColor():
+            self.convertColor("bgr", "gray")
+        if type in conf.thresholds:
+            self.image = cv2.threshold(self.image, thresh, max, conf.thresholds[type])[1]
+        else:
+            raise KeyError(type + " is not a valid threshold type.")
+        return
+    
+    def knn(self, k, labels, remove = []):
+        """
+        :param k: Number of nearest neighbors to use
+        :type k: int
+        :param labels: Path to label file.  More info below
+        :type labels: file
+        :param remove: Labels to remove from final image.
+        :type remove: list
+        
+        This function is a wrapper to the OpenCV function `KNearest <http://docs.opencv.org/modules/ml/doc/k_nearest_neighbors.html>`_.
+        The label file should contain training data in json format, using the label name of keys, and all 
+        the colors matching that label as an array value.  Each color should be a list of 3 values, in BGR order.  That is:
+	
+	.. code-block:: python
+
+		{
+		    "plant": [
+			[234, 125, 100],
+			[100, 100, 100]
+		    ],
+		    "pot": [
+		    ...
+		}
+
+        When creating your label file, make sure to use helpful names.  Calling each set of colors "label1", "label2" e.t.c
+        provides no meaningful information.  The remove list is the list of matched labels to remove from the final image.
+        The names to remove should match the names in your label file exactly. For example, let's say you have the labels
+	"plant", "pot", "track", and "background" defined, and you only want to keep pixels that match the "plant" label.
+	Your remove list should be specified as ["pot", "track", "background"].
+        """
+        if (os.path.isfile(labels)):
+            with open(labels, "r") as rh:
+                data = json.load(rh)
+                labelMap = []
+                trainData = []
+                response = []
+                for index,key in enumerate(data.keys()):
+                     labelMap.append(key)
+                     for color in data[key]:
+                         trainData.append(color)
+                         response.append(index)
+                trainData = np.array(trainData, dtype = np.float32)
+                response = np.array(response)
+                knn = cv2.KNearest()
+                knn.train(trainData, response)
+                fim = self.image.copy().reshape((-1, 3)).astype(np.float32)
+                ret, results, neighbors, dist = knn.find_nearest(fim, k)
+                ires = np.in1d(results.ravel(), [i for i,x in enumerate(labelMap) if x not in remove])
+                final = cv2.cvtColor(np.where(ires, 255, 0).astype(np.uint8).reshape((self.y, self.x)).astype(np.uint8), cv2.COLOR_GRAY2BGR)
+                self.bitwise_and(final)
+        else:
+            print "Cannot find label file."
+        return
+                                
+    
+    def kmeans(self, k, criteria, maxiter = 10, accuracy = 1.0, attempts = 10, flags = "random", labels = None):
+        """
+        :param k: Number of colors in final image.
+        :type k: int
+        :param criteria: Determination of how the algorithm stops execution.  Should be one of 'accuracy', 'iteration', or 'either'.
+        :type criteria: str
+        :param maxiter: Maximum number of iterations of the algorithm.
+        :type maxiter: int
+        :param accuracy: Minimum accuracy before algorithm finishes executing.
+        :type accuracy: float
+        :param attempts: Number of times the algorithm is executed using different initial guesses.
+        :type attempts: int
+        :param flags: How to determine initial centers should be either 'random' or 'pp'.
+        :type flags: str
+        
+        This function is a wrapper to the OpenCV function `kmeans <http://docs.opencv.org/modules/core/doc/clustering.html>`_
+        Adjusts the colors in the image to find the most compact 'central' colors.  The amount of colors
+        in the resulting image is the specified value 'k'.  The colors are chosen based upon the minimum
+        amount of adjustment in the image necessary.  The criteria parameter determines when the algorithm
+        stops.  If 'accuracy' is specified, the algorithm runs until the specified accuracy is reached.  If 'iteration'
+        is specified, the algorithm runs the specified number of iterations.  If 'either' is specified, the algorithm
+        runs until one of the conditions is satisfied.  The flags parameter determines the initial central colors,
+        and should be either 'random' -- to generate a random initial guess -- or 'pp' to use center initialization by Arthur and Vassilvitskii.
+        """ 
+        if flags in conf.centers:
+            if criteria in conf.ktermination:
+                reshaped = self.image.reshape((-1,3))
+                reshaped = np.float32(reshaped)
+                ret, label, center = cv2.kmeans(reshaped, k, (conf.ktermination[criteria], maxiter, accuracy), attempts, conf.centers[flags], bestLabels = labels)
+                center = np.uint8(center)
+                res = center[label.flatten()]
+                self.image = res.reshape((self.image.shape))
+            else:
+                raise KeyError(criteria + " is not a valid termination type.  Should be one of 'accuracy', 'iteration', or 'either'")
+        else:
+            raise KeyError(flags + " is not a valid center type.  Should be either 'random' or 'pp'.")
+        return
+
+    
+    def meanshift(self, spatial_radius, range_radius, min_density):
+        """
+        :param spatial_radius: Spatial Radius
+        :type spatial_radius: int
+        :param range_radius: Range Radius.
+        :type range_radius: int
+        :param min_density: Minimum Density.
+        :type min_density: int
+        :return: The mean-shifted image.
+        :rtype: numpy.ndarray
+        
+        Segments the image into clusters based on nearest neighbors.  This function
+        is a wrapper to the `pymeanshift <https://code.google.com/p/pymeanshift/>`_
+        module.  For details on the algorithm itself: `Mean shift: A robust approach toward feature space analysis <http://dx.doi.org/10.1109/34.1000236>`_.
+        """
+        (self.image, labels_image, number_regions) = pms.segment(self.image, spatial_radius = spatial_radius, range_radius = range_radius, min_density = min_density)
+        return
+    
+    def adaptiveThreshold(self, value, adaptiveType, thresholdType, blockSize, C):
+        """
+        :param value: Intensity value for the pixels based on the thresholding conditions.
+        :type param: int
+        :param adaptiveType: Adaptive algorithm to use, should be either 'mean' or 'gaussian'.
+        :type adaptiveType: str
+        :param thresholdType: Threshold type, should be either 'binary' or 'inverse'.
+        :type thresholdType: str
+        :param blockSize: The window size to consider while thresholding, should only be an odd number.
+        :type blockSize: int
+        :param C: A constant subtracted from the calculated mean in each window.
+        :type C: int
+        
+        Thresholds an image by considering the image in several different windows instead of the image
+        as a whole.  This function is a wrapper to the OpenCV function `adaptiveThreshold <http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html#adaptivethreshold>`_.
+        Specifying 'mean' for adaptiveType calculates a simple mean of the area, wheras specifying 'gaussian' calculates a weighted sum
+        based upon a `Gaussian Kernel <http://docs.opencv.org/modules/imgproc/doc/filtering.html#Mat getGaussianKernel(int ksize, double sigma, int ktype)>`_.
+        Specifying 'binary' for thresholdType means that a particular intensity value must beat the threshold to be kept, whereas
+        specifying 'inverse' means that a particular intensity value must lose to the threshold to be kept.
+        Similar to a normal thresholding function, the image must be converted to grayscale first.  This can be done using the
+        :meth:`~ih.imgproc.Image.convertColor` function, however, if your image is of type 'bgr', this is handled automatically.
+        """
+        if self._isColor():
+            self.convertColor("bgr", "gray")
+        if adaptiveType in conf.adaptives:
+            if thresholdType == "binary" or thresholdType == "inverse":
+                self.image = cv2.adaptiveThreshold(self.image, value, conf.adaptives[adaptiveType], conf.thresholds[thresholdType], blockSize, C)
+            else:
+                raise Exception("Threshold type: " + thresholdType + " must be either binary or inverse.")
+        else:
+            raise Exception("Adaptive type: " + adaptiveType + " is not a valid adaptive threshold type, should be either 'mean' or 'gaussian'")
+        return
+    
+    def blur(self, ksize, anchor = (-1, -1), borderType = "default"):
+        """
+        :param ksize: The size of the kernel represented by a tuple (width, height).  Both numbers should be odd and positive.
+        :type ksize: tuple
+        :param anchor: The anchor point for filtering.  Default is (-1, -1) which is the center of the kernel.
+        :type anchor: tuple
+        :param borderType: The type of border mode used to extrapolate pixels outside the image.
+        :type borderType: str
+        
+        Smoothes an image using the normalized box filter.  This function is a wrapper to the OpenCV function
+        `blur <http://docs.opencv.org/modules/imgproc/doc/filtering.html#blur>`_.  Increasing the kernel size increase
+        the window considered when applying a blur.  The anchor by default is the center of the kernel,
+        however you can alter the anchor to consider different areas of the kernel.  When blurring on the edge
+        of the image, values for pixels that would be outside of the image are extrapolated.  The method
+        of extrapolation depends on the specified 'borderType', and can be one of 'default', 'constant',
+        'reflect', or 'replicate'.
+        """
+        if borderType in conf.borders:
+            self.image = cv2.blur(self.image, ksize, anchor = anchor, borderType = conf.borders[borderType])
+        else:
+            raise Exception("Invalid border type, should be one of: " + ",".join(conf.borders.keys()) + ".")
+        return
+    
+    def medianBlur(self, ksize):
+        """
+        :param ksize: The size of the kernel (ksize x ksize).  Should be odd and positive.
+        :type ksize: int
+    
+        This function smoothes an image using the median filter.  The kernel is set to size (ksize, ksize).
+        The anchor position is assumed to be the center.
+        REFERENCE OPENCV MEDIAN BLUR
+        """
+        self.image = cv2.medianBlur(self.image, ksize)
+        return
+    
+    def gaussianBlur(self, ksize, sigmaX = 0, sigmaY = 0, borderType = "default"):
+        """
+        :param ksize: The size of the kernel represented by a tuple (width, height).  Both numers should be odd and positive.
+        :type ksize: tuple
+        :param sigmaX: The standard deviation in the x direction.  If 0, the value is calculated based on the kernel size.
+        :type sigmaX: float
+        :param sigmaY: The standard deviation in the y direction.  If 0, the value is equal to sigmaX.
+        :type sigmaY: float
+        :param borderType: The type of border mode used to extrapolate pixels outside the image.
+        :type borderType: str
+        
+        This function blurs an image based on a Gaussian kernel.  When blurring on the edge
+        of the image, values for pixels that would be outside of the image are extrapolated.  The method
+        of extrapolation depends on the specified 'borderType', and can be one of 'default', 'constant',
+        'reflect', or 'replicate'.  This function is a wrapper to the OpenCV function `GaussianBlur <http://docs.opencv.org/modules/imgproc/doc/filtering.html#gaussianblur>`_.
+        """
+        if borderType in conf.borders:
+            sigmaY = sigmaX if sigmaY == 0 else sigmaY
+            self.image = cv2.GaussianBlur(self.image, ksize, sigmaX, sigmaY, borderType = conf.borders[borderType])
+        else:
+            raise Exception("Invalid border type, should be one of: " + ",".join(conf.borders.keys()) + ".")
+        return
+    
+    def normalizeByIntensity(self):
+        """
+        Normalizes each channel of the pixel by its intensity.  For each pixel, the intensity is defined as
+        :math:`I = R + G + B`, where :math:`R,G,B` are the color values for that pixel.  We calculate new color values by 
+        multiplying the original number by 255, and dividing by the intensity, that is, :math:`r = \\frac{255 \\cdot R}{I}
+        , g = \\frac{255 \\cdot G}{I}, b = \\frac{255 \\cdot B}{I}`.
+        """
+        f = self.image.astype(float)
+        combined = np.add(np.add(f[:,:,0], f[:,:,1]), f[:,:,2])
+        scaled = np.multiply(f, [255])
+        self.image = np.divide(scaled, combined[:,:,None]).astype(np.uint8)
+        return
+    
+    def morphology(self, morphType, ktype, ksize, anchor = (-1, -1), iterations = 1, borderType = "default"):
+        """
+        :param morphType: The type of morphology to perform.  Should be dilate, erode, open, close, gradient, tophat, or blackhat.
+        :type morphType: str
+        :param ktype: the type of the kernel, should be rect, ellipse, or cross.
+        :type ktype: str
+        :param ksize: The size of the kernel represented by a tuple (width, height).  Both numbers should be odd and positive.
+        :type ksize: tuple
+        :param anchor: The anchor point for filtering.  Default is (-1, -1) which is the center of the kernel.
+        :type anchor: tuple
+        :param iterations: The number of times to perform the specified morphology.
+        :type iterations: int
+        :param borderType: The type of border mode used to extrapolate pixels outside the image.
+        :type borderType: str
+        
+        This function performs morphological operations based on the inputted values. This function is
+        a wrapper to the OpenCv function `morphologyEx <http://docs.opencv.org/modules/imgproc/doc/filtering.html#morphologyex>`_. When performing the morphology on the edges
+        of the image, values for pixels that would be outside of the image are extrapolated.  The method
+        of extrapolation depends on the specified 'borderType', and can be one of 'default', 'constant',
+        'reflect', or 'replicate'.
+        """
+        if morphType in conf.morph:
+            if ktype in conf.kernels:
+                if borderType in conf.borders:
+                    kernel = cv2.getStructuringElement(conf.kernels[ktype], ksize, anchor)
+                    self.image = cv2.morphologyEx(self.image, conf.morph[morphType], kernel, anchor = anchor, iterations = iterations, borderType = conf.borders[borderType])
+                else:
+                    raise Exception("Invalid border type, should be one of: " + ",".join(conf.borders.keys()) + ".")
+            else:
+                raise Exception("Invalid kernel type, should be one of: " + ",".join(conf.kernels.keys()) + ".")
+        else:
+            raise Exception("Invalid morphology type, should be one of: " + ",".join(conf.morph.keys()) + ".")
+        
+    def crop(self, roi, resize = False):
+        """
+        :param roi: A list corresponding to the area of the image you want.  List should be of the form [ystart, yend, xstart, xend]
+        :type roi: list or roi file
+        :param resize: If True, actually adjusts the size of the image, otherwise just draws over the part of the image not in the roi.
+        :type resize: bool
+        
+        This function crops the image based on the given roi [ystart, yend, xstart, xend].  There are two crop options,
+        by default, the function doesn't actually resize the image.  Instead, it sets each pixel not in the roi to black.
+        If resize is set to True, the function will actually crop the image down to the roi.
+        """
+        roi = self._loadROI(roi)
+        ystart, yend, xstart, xend = roi
+        if (resize):
+            self.image = self.image[ystart: yend, xstart: xend]
+            self.x = self.image.shape[1]
+            self.y = self.image.shape[0]
+        else: 
+            maxx = self.x
+            maxy = self.y
+            off = [0, 0, 0] if self._isColor() else [0]
+            self.image[0:ystart, 0:maxx] = off
+            self.image[yend:maxy, 0:maxx] = off
+            self.image[0:maxy, 0:xstart] = off
+            self.image[0:maxy, xend:maxx] = off
+        return
+    
+    def mask(self):
+        """
+        This function convers the image to a color mask by performing the following operations:
+        * :py:meth:`~ih.imgproc.Image.convertColor("bgr", "gray")`
+        * :py:meth:`~ih.imgproc.Image.threshold(0)
+        * :py:meth:`~ih.imgproc.Image.convertColor("gray", "bgr")
+        """
+        self.convertColor("bgr", "gray")
+        self.threshold(0)
+        self.convertColor("gray", "bgr")
+        return
+            
+    
+    def contourCut(self, binary, basemin = 100, padding = [0, 0, 0, 0], resize = False, returnBound = False, roiwrite = "roi.json"):
+        """
+        :param binary: The binary image to find contours of.
+        :type binary: str or np.ndarray
+        :param basemin: The minimum area a contour must have to be consider part of the foreground.
+        :type basemin: int
+        :param padding: Padding add to all sides of the final roi.
+        :type padding: int
+        :param returnBound: If set, instead of cropping the image, simply write the detected roi.
+        :type returnBound: bool
+        :param resize: Whether or not to resize the image.
+        :type resize: bool
+        
+        This function crops an image based on the size of detected contours in the image --
+        clusters of pixels in the image.  The image is cropped such that all contours
+        that are greater than the specified area are included in the final output image.
+        image is cropped such that all contours that are greater than the specified area are
+        included in the final output image.  If returnBound is set, instead of actually
+        cropping the image, the detected roi is written to a file instead.  Otherwise,
+        the detected roi is passed into the :py:meth:`~ih.imgproc.Image.crop` function,
+        with the given resize value.  This function is useful for getting accurate 
+        height and width of a specific plant, as well as removing outlying clusters
+        of non-important pixels.
+        """
+        bname, binary = self._loadResource(binary)
+        if self._isColor(binary):
+            binary = cv2.cvtColor(binary, cv2.COLOR_BGR2GRAY)
+        contours = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]
+        minx = binary.shape[1]
+        miny = binary.shape[0]
+        maxx = 0
+        maxy = 0
+        for cnt in contours:
+            x,y,w,h = cv2.boundingRect(cnt)
+            if (basemin < cv2.contourArea(cnt)):
+                if (x < minx):
+                    minx = x
+                if (y < miny):
+                    miny = y
+                if (x + w > maxx):
+                    maxx = x + w
+                if (y + h > maxy):
+                    maxy = y + h
+        roi = [0 if miny - padding[0] < 0 else miny - padding[0], binary.shape[0] if maxy + padding[1] > binary.shape[0] else maxy + padding[1], 0 if minx - padding[2] < 0 else minx - padding[2], binary.shape[1] if maxx + padding[3] > binary.shape[1] else maxx + padding[3]]
+        if returnBound:
+            self._writeROI(roi, roiwrite)
+        self.crop(roi, resize)
+        return
+    
+    def edges(self, threshold1, threshold2, apertureSize = 3, L2gradient = False):
+        """
+        :param threshold1: First threshold for the hysteresis procedure.
+        :type threshold1: int
+        :param threshold2: Second threshold for the hysteresis procedure.
+        :type threshold2: int
+        :param apertureSize: aperture size used for the Sobel algorithm.  Must be odd, postive, and less than 8.
+        :type apertureSize: int
+        :L2gradient: Used to calculate Image gradient magnitude, if true then :math:`L = \sqrt{(dI/dx)^2 + (dI/dy)^2}`, if false then :math:`L = dI/dx + dI/dy`.
+        :type L2gradient: bool
+        
+        This function calculates the edges of an image using the Canny edge detection algorithm, which is built upon the Sobel
+        algorithm.  This function is a wrapper to the OpenCV function `Canny <http://docs.opencv.org/modules/imgproc/doc/feature_detection.html#canny>`_.
+        """
+        self.image = cv2.Canny(self.image, threshold1, threshold2, apertureSize = apertureSize, L2gradient = L2gradient)
+        return
+    
+    def colorFilter(self, logic, roi = None):
+        """
+        :param logic: The logic you want to run on the image.
+        :type logic: str
+        :param roi: The roi you want to apply the filter to
+        :type roi: list or roi file
+        
+        This function applies a color filter defined by the input logic, to a
+        targeted region defined by the input roi. The logic string itself is fairly complicated.
+        The string supports the following characters: '+', '-', '*', '/', '>', '>=',
+        '==', '<', '<=', 'and', 'or', '(', ')', 'r', 'g', 'b', 'max', and 'min' as well as any numeric
+        value.  The logic string itself must be well formed -- each 
+        operation, arg1 operator arg2, must be surrounded by parenthesis, and the entire statement
+        must be surrounded by parenthesis.  For example,
+        if you want to check the intensity of the pixel, your logic string would be:
+        '(((r + g) + b) < 100)'.  This string in particular will only keep pixels whose
+        intensity is less than 100.  Similar rules apply for 'and' and 'or' operators.
+        Let's say we only want to keep pixels whose intensity is less than 100, OR both
+        the red and blue channels are greater than 150, the logic string would be: 
+        '((((r + g) + b) < 100) or ((r > 150) and (b > 150)))'.  The more complex
+        your logic is the harder it is to read, so you may want to consider breaking
+        up complex filtering into multiple steps for readability.  Finally, despite
+        the fact this function solves arbitrary logic, it is very fast.
+        """
+        filter = ColorFilter(logic)
+        roi = self._loadROI(roi)
+        self.image = filter.apply(self.image, roi)
+        return
+    
+    def bitwise_not(self):
+        """
+            Inverts the image.  If the given image has multiple channels (i.e. is a color image) each channel is processed independently.
+        """
+        self.image = cv2.bitwise_not(self.image)
+        return
+    
+    def bitwise_and(self, comp):
+        """
+        :param comp: The comparison image.
+        :type comp: str or np.ndarray
+        :return: The resulting mask.
+        :rtype: numpy.ndarray
+            
+        Performs logical AND between the input image and the comp image.
+        The comp input is very versatile, and can be one of three input types,
+        an image, a path, or a saved state.  An image input is a raw numpy array,
+        and this input type will be passed through to the function without modification.  
+        If a path is specified, ih attempts to load the file as an image, and pass it
+        to the function.  Finally, the input is checked against the currently saved
+        image states.  If it matches, the corresponding state is passed to the function.
+        The function assumes that the two input images are of matching type --
+        if they are not an error will be thrown.  By default, images loaded from a
+        path are loaded as 'bgr' type images.
+        For more information on states, see :py:meth:`~ih.imgproc.Image.save`.
+        """  
+        self.image = cv2.bitwise_and(self.image, self._loadResource(comp)[1])
+        return
+        
+    def bitwise_or(self, comp):
+        """
+        :param comp: The comparison image.
+        :type comp: str or np.ndarray
+        :return: The resulting mask.
+        :rtype: numpy.ndarray
+            
+        Performs logical OR between the input image and the comp image.
+        The comp input is very versatile, and can be one of three input types,
+        an image, a path, or a saved state.  An image input is a raw numpy array,
+        and this input type will be passed through to the function without modification.  
+        If a path is specified, ih attempts to load the file as an image, and pass it
+        to the function.  Finally, the input is checked against the currently saved
+        image states.  If it matches, the corresponding state is passed to the function.
+        The function assumes that the two input images are of matching type --
+        if they are not an error will be thrown.  By default, images loaded from a
+        path are loaded as 'bgr' type images.
+        For more information on states, see :py:meth:`~ih.imgproc.Image.save`.
+        """
+        self.image = cv2.bitwise_or(self.image, self._loadResource(comp)[1])
+        return
+        
+    def bitwise_xor(self, comp):
+        """
+        :param comp: The comparison image.
+        :type comp: str or np.ndarray
+        :return: The resulting mask.
+        :rtype: numpy.ndarray
+            
+        Performs exclusive logical OR between the input image and the comp image.
+        The comp input is very versatile, and can be one of three input types,
+        an image, a path, or a saved state.  An image input is a raw numpy array,
+        and this input type will be passed through to the function without modification.  
+        If a path is specified, ih attempts to load the file as an image, and pass it
+        to the function.  Finally, the input is checked against the currently saved
+        image states.  If it matches, the corresponding state is passed to the function.
+        The function assumes that the two input images are of matching type --
+        if they are not an error will be thrown.  By default, images loaded from a
+        path are loaded as 'bgr' type images.
+        For more information on states, see :py:meth:`~ih.imgproc.Image.save`.
+        """
+        self.image = cv2.bitwise_xor(self.image, self._loadResource(comp)[1])
+        return
+    
+    def extractFinalPath(self):
+        """
+        This function writes the absolute path of the output file to the database.
+        """
+        if self.conn:
+             finalpath = "/".join(os.path.abspath(self.input).split("/")[-6:])
+             self._addColumn("outputPath")
+             self.conn.execute("update images set outputPath=? where pegasusid=?", (finalpath, self.dbid))
+             self.conn.commit()
+        return
+    
+    def extractMoments(self):
+        """
+        :return: A dictionary corresponding to the different moments of the image.
+        :rtype: dict
+        
+        Calculates the moments of the image, and returns a dicitonary based on them.
+        Spatial moments are prefixed with 'm', central moments are prefixed with 'mu',
+        and central normalized moments are prefixed with 'nu'.  This function
+        is a wrapper to the OpenCV function `moments <http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#moments>`_.
+        """
+        moments = cv2.moments(cv2.inRange(self.image, np.array([1, 1, 1], np.uint8), np.array([255, 255, 255], np.uint8)))
+        if self.conn:
+            for id in moments:
+                self._addColumn(id)
+                self.conn.execute("update images set " + id + "=? where pegasusid=?", (moments[id], self.dbid))
+            self.conn.commit()
+            return
+        else:
+            return moments
+    
+    def extractDimensions(self):
+        """
+        :return: A list corresponding to the height and width of the image.
+        :rtype: list
+        
+        Returns a list with the following form: [height, width]
+        """
+        if self.conn:
+            self._addColumn("height")
+            self._addColumn("width")
+            self.conn.execute("update images set height=?,width=? where pegasusid=?", (self.y, self.x, self.dbid))
+            self.conn.commit()
+            return
+        else:
+            return [self.y, self.x]
+        
+    def extractMinEnclosingCircle(self):
+        """
+        :return: The center, and radius of the minimum enclosing circle.
+        :rtype: int
+        
+        Returns the center and radius of the minimum enclosing circle of all
+        non-black pixels in the image.  The point of this function
+        is not to threshold, so the contours are generated from
+        all the pixels that fall into the range [1, 1, 1], [255, 255, 255].
+        """
+        circle = cv2.minEnclosingCircle(self._getMergedContour())
+        if self.conn:
+            self._addColumn("circle_centerx")
+            self._addColumn("circle_centery")
+            self._addColumn("circle_radius")
+            self.conn.execute("update images set circle_centerx=?, circle_centery=?, circle_radius=? where pegasusid=?", (circle[0][0], circle[0][1], circle[1], self.dbid))
+            self.conn.commit()
+        else:
+            return circle
+        
+    def extractConvexHull(self):
+        """
+        :return: The area of the convex hull.
+        :rtype: int
+        
+        Returns the area of the convex hull around all non black pixels in the image.
+        The point of this function is not to threshold, so the contours are generate from
+        all the pixels that fall into the range [1, 1, 1], [255, 255, 255]
+        """
+        hull = cv2.contourArea(
+                 cv2.approxPolyDP(
+                    cv2.convexHull(
+                        self._getMergedContour()
+                    ), 0.001, True
+                ))
+        if self.conn:
+            self._addColumn("convex_hull_area")
+            self.conn.execute("update images set convex_hull_area=? where pegasusid=?", (hull, self.dbid)) 
+            self.conn.commit()
+        else:
+            return hull
+    
+    def extractPixels(self):
+        """
+        :return: The number of non-black pixels in the image.
+        :rtype: int
+        
+        Returns the number of non-black pixels in the image.  Creates
+        a temporary binary image to do this.  The point of this function
+        is not to threshold, so the binary image is created by all
+        pixels that fall into the range [1, 1, 1], [255, 255, 255].
+        """
+        pixelCount = cv2.countNonZero(cv2.inRange(self.image, np.array([1, 1, 1], np.uint8), np.array([255, 255, 255], np.uint8)))
+        if self.conn:
+            self._addColumn("pixels")
+            self.conn.execute("update images set pixels=? where pegasusid=?", (pixelCount, self.dbid))
+            self.conn.commit()
+            return
+        else:
+            return pixelCount
+    
+    def extractColorData(self, nonzero = True, returnhist = False):
+        """
+        :param nonzero: Whether or not to look at only nonzero pixels.  Default true.
+        :type nonzero: bool
+        :return: Mean & median for each channel.
+        :rtype: list
+        
+        This function calculates a normalized histogram of each individual color channel of 
+        the image, and returns the mean & median of the histograms for the channels
+        specified.  Because images are imported with the channels ordered as B,G,R,
+        the output list is returned the same way.  The returned list always looks like
+        this: [ [BlueMean, BlueMedian], [GreenMean, GreenMedian], [RedMean, RedMedian] ].
+        Mean values always come before median values.  If nonzero is set to true (default)
+        the function will only calculate mediapytn and means based on the non-black pixels.
+	If you are connected to a database, the entire histogram is saved to the database,
+	not just the mean and median.
+        """
+        hist = self._colorHistogram()
+        if returnhist:
+            return hist
+        colors = [    [np.mean(np.nonzero(hist[0]) if nonzero else hist[0]), np.median(np.nonzero(hist[0]) if nonzero else hist[0])],
+                    [np.mean(np.nonzero(hist[1]) if nonzero else hist[1]), np.median(np.nonzero(hist[1]) if nonzero else hist[1])],
+                    [np.mean(np.nonzero(hist[2]) if nonzero else hist[2]), np.median(np.nonzero(hist[2]) if nonzero else hist[2])]
+                ]
+        if self.conn:
+            self._addColumn("rmean")
+            self._addColumn("rmed")
+            self._addColumn("gmean")
+            self._addColumn("gmed")
+            self._addColumn("bmean")
+            self._addColumn("bmed")
+            query = "update images set rmean=?,rmed=?,gmean=?,gmed=?,bmean=?,bmed=?"
+            values = [colors[2][0], colors[2][1], colors[1][0], colors[1][1], colors[0][0], colors[0][1]]
+            for x,c in enumerate(["bhist", "ghist", "rhist"]):
+                for i in range(0, 256):
+                    self._addColumn(c + str(i))
+                    query += "," + c + str(i) + "=?"
+                    values.append(int(hist[x][i]))
+            query += " where pegasusid=?"
+            values.append(self.dbid)
+            self.conn.execute(query, tuple(values))
+            self.conn.commit()
+            return
+        else:
+            return colors
+        
+    def extractColorChannels(self):
+	"""
+	This function is similar to the 
+	"""
+        b, g, r = cv2.split(self.image)
+        bdata, gdata, rdata = [], [], []
+        for i in range(0, 256):
+            bdata.append(np.count_nonzero(np.where(b == i, True, False)))
+            gdata.append(np.count_nonzero(np.where(g == i, True, False)))
+            rdata.append(np.count_nonzero(np.where(r == i, True, False)))
+        data = [bdata, gdata, rdata]
+        if self.conn:
+            query = "update images set "
+            values = []
+            for x,c in enumerate(["b", "g", "r"]):
+                for i in range(0, 256):
+                    self._addColumn(c + str(i))
+                    if i == 0:
+                        query += c + str(i) + "=?"
+                    else:
+                        query += "," + c + str(i) + "=?"
+                    values.append(data[x][i])
+            query += " where pegasusid=?"
+            values.append(self.dbid)
+            self.conn.execute(query, tuple(values))
+            self.conn.commit()
+            return
+        else:
+            return (bdata, gdata, rdata)
+        
+    def extractBins(self, binlist):
+        """
+        :param binlist: The specified bins (color ranges) to count.
+        :type binlist: list
+        :return: The number of pixels that fall in each bin.
+        :rtype: list
+        
+        This function counts the number of pixels that fall into the range as
+        specified by each bin.  This function expects the input to be a list of 
+        dictionaries as follows:
+    
+        .. code-block:: python
+        
+             binlist = [
+                {"name": "bin1",
+                 "min": [B, G, R],
+                 "max": [B, G, R]
+                },
+                {"name": "bin2",
+                ...
+            ]
+            
+        Each range is defined by 6 values.  A minimum and maximum blue,
+        green, and red value. The returned list is very similar to the 
+        input list, except a 'count' key is added to each dictionary:
+        
+        .. code-block:: python
+        
+            returnlist = [
+                {"name": "bin1",
+                "min": [B, G, R],
+                "max": [B, G, R],
+                "count": VALUE
+                },
+                ...
+            ]
+            
+        Where 'VALUE' is the number of pixels that fall into the
+        corresponding range.
+        A list is used instead of a dictionary as the base structure
+        to maintain order for writing to the output database.  When
+        using this function within a workflow, the order you specify
+        your bins is the order in which they will show up in the
+        database, and the name you specify for you bin will be
+        the column name in the database.
+        """
+        binlist = self._loadBins(binlist)
+        for i in range(0, len(binlist)):
+            binlist[i]["count"] = cv2.countNonZero(cv2.inRange(self.image, np.array(binlist[i]["min"], np.uint8), np.array(binlist[i]["max"], np.uint8)))
+        if self.conn:
+            for bin in binlist:
+                self._addColumn(bin["name"])
+                self.conn.execute("update images set " + bin["name"] + "=? where pegasusid=?", (bin["count"], self.dbid))
+            self.conn.commit()
+            return
+        else:
+            return binlist
+      
+    
diff --git a/build/lib/ih/statistics.py b/build/lib/ih/statistics.py
new file mode 100644
index 0000000000000000000000000000000000000000..2d276c8feb45acc2350447b4537bb1385da335d3
--- /dev/null
+++ b/build/lib/ih/statistics.py
@@ -0,0 +1,804 @@
+"""
+This file is part of Image Harvest.
+
+Image Harvest is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Image Harvest is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Image Harvest.  If not, see <http://www.gnu.org/licenses/>.
+"""
+import math
+import os
+import sqlite3
+import conf
+import datetime
+import numpy as np
+import pandas
+import ih.imgproc
+import cv2
+import json
+import traceback
+import shutil
+import subprocess
+from scipy import stats
+
+class Stats:
+    
+    def __init__(self, db):
+        self.db = db
+        self.conn = self._openConnection()
+        return
+    
+    def _openConnection(self, db = None):
+        db = self.db if not db else db
+        if os.path.isfile(db):
+            conn = sqlite3.connect(db, check_same_thread = False)
+            conn.row_factory = sqlite3.Row
+            result = conn.execute("select pegasusid from images limit 0,1")
+            if not result.fetchone():
+                raise Exception("Database '%s' has no entries!" % (db,))
+            # Have to enable foreign keys EVERY time.
+            conn.execute("PRAGMA foreign_keys = ON")
+            conn.commit()
+        else:
+            raise Exception("Database file '%s' does not exist." % (db,))
+        return conn
+        
+    def _closeConnection(self, conn = None):
+        conn = self.conn if not conn else conn
+        conn.close()
+        return
+    
+    def _tableExists(self, tablename, conn = None):
+        conn = self.conn if not conn else conn
+        result = conn.execute("select name from sqlite_master where type='table' and name=?", (tablename,))
+        if not result.fetchone():
+            return False
+        else:
+            return True
+    
+    def _validate(self, funcname, intable, outtable, overwrite, conn = None):
+        conn = self.conn if not conn else conn
+        if funcname in conf.statsColumns:
+            if self._tableExists(intable):
+                cols = [x[1] for x in conn.execute("PRAGMA table_info('" + intable + "')")]
+                if set(conf.statsColumns[funcname]["required"]) <= set(cols):
+                    if self._tableExists(outtable, conn) and not overwrite:
+                        raise Exception("Output table '" + outtable + "' already exists.")
+                else:
+                    raise Exception("Table '" + intable + "' doesn't have all the required columns: '" + str(conf.statsColumns[funcname]["required"]) + "'.")
+            else:
+                raise Exception("Table '" + intable + "' doesn't exist.")
+        else:
+            raise Exception("Function '" + funcname + "' doesn't exist.")
+        return
+    
+    def _massage(self, table, headers, imtypes = None, conn = None):
+        conn = self.conn if not conn else conn
+        if not imtypes:
+            imtypes = self._getImageTypes(table, conn)
+        elif not isinstance(imtypes, list):
+            imtypes = [imtypes]
+            
+        for header in headers:
+            self.conn.execute("update " + table + " set " + header + "=? where " + header + " is null and (" + "or".join(["imtype=?" for x in imtypes]) + ")", (0,) + tuple(imtypes))
+        self.conn.commit()
+        return
+    
+    def _columnExists(self, column, tablename, conn = None):
+        conn = self.conn if not conn else conn
+        if column in [row["name"] for row in self.conn.execute("PRAGMA table_info('" + tablename + "')")]:
+            return True
+        else:
+            return False
+    
+    def _addColumn(self, column, tablename = "images", conn = None):
+        conn = self.conn if not conn else conn
+        if not self._columnExists(column, tablename, conn):
+            conn.execute("alter table '" + tablename + "' add column " + column + ";")
+            conn.commit()
+        return
+    
+    def _addKeyColumn(self, parent, parentCol, child, childCol, conn = None):
+        conn = self.conn if not conn else conn
+        if parentCol not in [row["name"] for row in conn.execute("PRAGMA table_info('" + parent + "');")] and childCol in [row["name"] for row in conn.execute("PRAGMA table_info('" + child + "');")]:
+            conn.execute("alter table '" + parent + "' add column '" + parentCol + "' REFERENCES '" + child + "'('" + childCol + "');")
+            conn.commit()
+        return
+    
+    def _createTable(self, funcname, intable, outtable, overwrite, conn = None):
+        conn = self.conn if not conn else conn
+        tablestr = "(pegasusid INTEGER PRIMARY KEY"
+        cols = [x[1] for x in conn.execute("pragma table_info('" + intable + "')")]
+        if "all" not in conf.statsColumns[funcname]["exclude"]:
+            for col in cols:
+                if col not in conf.statsColumns[funcname]["exclude"] and col[:3] != "ref":
+                    tablestr += "," + str(col)
+        for col in conf.statsColumns[funcname]["add"]:
+            tablestr += "," + str(col)
+        tablestr += ")"
+        if overwrite:
+            if conf.statsColumns[funcname]["ref"]:
+                if self._columnExists("ref_" + outtable, intable, conn):
+                    conn.execute("update " + intable + " set ref_" + outtable + "=? where ref_" + outtable + " is not null", (None,))
+                    conn.commit()
+            conn.execute("DROP TABLE IF EXISTS " + outtable)
+            conn.commit()
+        conn.execute("CREATE TABLE " + outtable + " " + tablestr)
+        conn.commit()
+        if conf.statsColumns[funcname]["ref"]:
+            self._addKeyColumn(intable, "ref_" + outtable, outtable, "pegasusid", conn)
+        return
+    
+    def _getHeaders(self, table, conn = None):
+        conn = self.conn if not conn else conn
+        return [str(x[1]) for x in conn.execute("pragma table_info(" + table + ")") if x[1] != "pegasusid"]
+    
+    def _getIds(self, table, conn = None):
+        conn = self.conn if not conn else conn
+        return [str(x[0]) for x in conn.execute("select distinct id from " + table)]
+    
+    def _getImageTypes(self, table, conn = None):
+        conn = self.conn if not conn else conn
+        return [str(x[0]) for x in conn.execute("select distinct imtype from " + table)]
+    
+    def _getDates(self, table, conn = None):
+        conn = self.conn if not conn else conn
+        return [str(x[0]) for x in conn.execute("select distinct date from " + table)]
+    
+    def _checkNull(self, value):
+        return True if value is None or str(value).lower() == "none" else False
+    
+    def _listToSql(self, l):
+        return str(l).replace("[", "(").replace("]", ")")
+    
+    def _loadLemnaData(self, dataFile, dataHeaders):
+        """
+        :param dataFile: The input dataFile
+        :type dataFile: str
+        :param dataHeaders: The input data headers
+        :type dataHeaders: dict
+        
+        dataHeaders should be:
+        { 
+            "id": "Snapshot ID Tag",
+            "date": "Snapshot Time Stamp",
+            "dateFormat": "%m/%d/%y",
+            "metric": "Projected Shoot Area [pixels]"
+        }
+        """
+        if os.path.isfile(dataFile):
+            if all(key in dataHeaders for key in ["id", "date", "dateFormat", "metric"]):
+                with open(dataFile) as rh:
+                    lines = rh.readlines()
+                    firstline = lines[0].strip().split(",")
+                    if dataHeaders["id"] in firstline:
+                        if dataHeaders["date"] in firstline:
+                            if dataHeaders["metric"] in firstline:
+                                idIndex = firstline.index(dataHeaders["id"])
+                                dateIndex = firstline.index(dataHeaders["date"])
+                                metricIndex = firstline.index(dataHeaders["metric"])
+                                lemnaData = {}
+                                for line in lines[1:]:
+                                    info = line.strip().split(",")
+                                    if (info[metricIndex] != "NA"):
+                                        id = info[idIndex][-8:]
+                                        date = datetime.datetime.strptime(info[dateIndex].split()[0], dataHeaders["dateFormat"]).strftime("%Y-%m-%d")
+                                        try:
+                                            metric = float(info[metricIndex])
+                                            if id not in lemnaData:
+                                                lemnaData[id] = {}
+                                            if date not in lemnaData[id]:
+                                                lemnaData[id][date] = {}
+                                            lemnaData[id][date]["metric"] = metric
+                                        except:
+                                            pass
+                                return lemnaData
+                            else:
+                                raise Exception("Metric Column: ",dataHeaders["metric"]," does not exist.")
+                        else:
+                            raise Exception("Date Column: ",dataHeaders["date"]," does not exist.")
+                    else:
+                        raise Exception("Id Column: ",dataHeaders["id"]," does not exist.")
+            else:
+                raise Exception("Data Dictionary does not have all required keys ['id', 'date', 'dateFormat', 'metric']")
+        else:
+            raise Exception("Data File: " + dataFile + " does not exist!")
+        return
+    
+    def loadSql(self, dblist):
+        for i,f in enumerate(dblist):
+            if os.path.isfile(f):
+                conn = self._openConnection(f)
+                cols = self._getHeaders("images", conn)
+                for col in cols:
+                    self._addColumn(col, "images")
+                result = conn.execute("select pegasusid," + ",".join(cols) + " from images")
+                query = "update images set " + ",".join([col + "=?" for col in cols]) + " where pegasusid=?"
+                values = [tuple([row[col] for col in cols] + [row["pegasusid"]]) for row in result]
+                self.conn.executemany(query, values)
+                self.conn.commit()
+                self._closeConnection(conn)
+            else:
+                print "DB File: '%s' does not exist." % (f,)
+        return
+        
+    def logErrors(self, logfile, table = "images"):
+        """
+        :param logfile: The logfile to write errors to
+        :type logfile: str
+        :param table: The table to load errors from
+        :type table: str
+        
+        This function writes all errors from a given table to a log file,
+        usually used at the end of image processing to write all images that
+        did not process correctly.
+        """
+        with open(logfile, "w") as wh:
+            wh.write("Image processing error log\n")
+            wh.write("==========================\n")
+            result = self.conn.execute("select pegasusid,path,error from '" + table + "' where error is not null")
+            firstrow = result.fetchone()
+            if firstrow:
+                wh.write("Image with id '%s' loaded from input path '%s' was not processed successfully.\n" % (firstrow["pegasusid"], firstrow["path"]))
+                for row in result:
+                    wh.write("Image with id '%s' loaded from input path '%s' was not processed successfully.\n" % (row["pegasusid"], row["path"]))
+            else:
+                wh.write("All images processed successfully!  Nice job!\n")
+        return
+    
+    def makePublic(self, targetFolder, process = False):
+        imtypes = ["rgbsv", "rgbtv", "fluosv"]
+        query = "select path from images where imtype in " + self._listToSql(imtypes)
+        print query
+        result = self.conn.execute(query)
+        for row in result:
+            target = "/iplant/home/shared/walia_rice_salt/" + targetFolder + "/" + "/".join(row["path"].split("/")[5:-1]) + "/0_0.png"
+            print target
+            if process:
+                for utype in ["anonymous", "public"]:
+                    subprocess.call(["ichmod","read", utype, target])
+        return
+        
+    def dataToPlantcv(self, folder, ids = None, imtypes = None, dates = None):
+        if not os.path.isdir(folder):
+            ids = ids if ids else self._getIds("images")
+            imtypes = imtypes if imtypes else self._getImageTypes("images")
+            dates = dates if dates else self._getDates("images")
+            query = "select id,date,imgname,imtype,path from images where id in " + self._listToSql(ids) + " and imtype in " + self._listToSql(imtypes) + " and date in " + self._listToSql(dates)
+            print query
+            result = self.conn.execute(query)
+            os.makedirs(folder)
+            for row in result:
+                id = row["id"].split("-")[0] if "-" in row["id"] else row["id"]
+                date_time = row["date"] + " 000"
+                imtype = {
+                    "rgbsv": "vis_sv_z700",
+                    "rgbtv": "vis_tv_z300"
+                }[row["imtype"]]
+                fname = "%s-%s-%s-%s.png" % (id, date_time, row["imgname"], imtype)
+                shutil.copyfile(row["path"], folder + "/" + fname)
+        else:
+            print "Folder already exists."
+        return
+    
+    def dataToIAP(self, folder, ids = None, imtypes = None, dates = None):
+        if not os.path.isdir(folder):
+            ids = ids if ids else self._getIds("images")
+            imtypes = imtypes if imtypes else self._getImageTypes("images")
+            dates = dates if dates else self._getDates("images")
+            query = "select id,date,imgname,imtype,path from images where id in " + self._listToSql(ids) + " and imtype in " + self._listToSql(imtypes) + " and date in " + self._listToSql(dates)
+            print query
+            result = self.conn.execute(query)
+            os.makedirs(folder)
+            for row in result:
+                if not os.path.isdir(folder + "/" + row["imtype"][:-2]):
+                    os.makedirs(folder + "/" + row["imtype"][:-2])
+                writeim = "side" if "sv" in row["imtype"] else "top"
+                dirname = folder + "/" + row["imtype"][:-2] + "/" + writeim
+                if not os.path.isdir(dirname):
+                    os.makedirs(dirname)
+                fname = "%s_%s_%s_%s.png" % (row["imgname"], writeim, row["id"], row["date"])
+                shutil.copyfile(row["path"], dirname + "/" + fname)
+        else:
+            print "Folder already exists."
+        return
+    
+    def shootArea(self, intable, outtable, grouping, overwrite = False):
+        """
+        :param intable: The input table to load information from
+        :type intable: str
+        :param outtable: The output table to write information to.
+        :type outtable: str
+        :param grouping: Which imtypes to group
+        :type grouping: list
+        
+        This function adds the numeric values of multiple image types together.
+        In general, it is used to combine side view + top view images of the same spectrum.
+        If you plan on correlating your data to lemnaTec's data, lemnaTec uses SV1 + SV2 + TV,
+        so you should aggregate your data likewise.
+        """
+        self._validate("shootArea", intable, outtable, overwrite)
+        self._createTable("shootArea", intable, outtable, overwrite)
+        headers = self._getHeaders(outtable)
+        dataHeaders = [header for header in headers if header not in conf.allHeaders and "ref" not in header]
+        start = len(headers) - len(dataHeaders)
+        """
+        map = {
+            "genotype": {
+                "date": {
+                    "treatment": {
+                        "writeback": [],
+                        "values": ()
+                    }
+                }
+            }
+        }
+        """
+        dataMap = {}
+        result = self.conn.execute("select pegasusid," + ",".join(headers) + " from " + intable + " where " + " or ".join(["imtype=?" for x in grouping]), tuple([x for x in grouping]))
+        for row in result:
+            if row["genotype"] not in dataMap:
+                dataMap[row["genotype"]] = {}
+            if row["date"] not in dataMap[row["genotype"]]:
+                dataMap[row["genotype"]][row["date"]] = {}
+            if row["treatment"] not in dataMap[row["genotype"]][row["date"]]:
+                dataMap[row["genotype"]][row["date"]][row["treatment"]] = {"writeback": [row["pegasusid"]], "values": tuple([row[x] for x in headers])}
+            else:
+                dataMap[row["genotype"]][row["date"]][row["treatment"]]["writeback"].append(row["pegasusid"])
+                values = []
+                for i,(x,y) in enumerate(zip(dataMap[row["genotype"]][row["date"]][row["treatment"]]["values"], tuple([row[x] for x in headers]))):
+                    if i < start:
+                        values.append(x)
+                    else:
+                        try:
+                            values.append(x + y)
+                        except:
+                            values.append(None)
+                dataMap[row["genotype"]][row["date"]][row["treatment"]]["values"] = tuple(values)
+            
+        #Loop through dataMap, insert values and writeback accordingly
+        for genotype in dataMap:
+            for date in dataMap[genotype]:
+                for treatment in dataMap[genotype][date]:
+                    lastid = self.conn.execute("insert into " + outtable + " (" + ",".join(headers) + ") values (" + ",".join(["?"] * len(headers)) + ")", dataMap[genotype][date][treatment]["values"]).lastrowid
+                    self.conn.executemany("update " + intable + " set ref_" + outtable + "=? where pegasusid=?", tuple([(lastid, x) for x in dataMap[row["genotype"]][row["date"]][row["treatment"]]["writeback"]]))
+        self.conn.commit()
+        return
+    
+    def normalize(self, intable, outtable, column = "pixels", overwrite = False):
+        """
+        :param intable: The input table to load information from
+        :type intable: str
+        :param outtable: The output table to write information to.
+        :type outtable: str
+        :param column: The column to normalize information to
+        :type column: str
+        
+        Normalizes all numerical information to the specific column.  This
+        function is usually used with 'pixels' as the specified column, which
+        expresses all numeric information as a percentage of the total pixels 
+        in the image.
+        """
+        self._validate("normalize", intable, outtable, overwrite)
+        if self._columnExists(column, intable):
+            conf.statsColumns["normalize"]["exclude"] += [column]
+            self._createTable("normalize", intable, outtable, overwrite)
+            headers = self._getHeaders(outtable)
+            dataHeaders = [header for header in headers if header not in conf.allHeaders and "ref" not in header]
+            result = self.conn.execute("select pegasusid," + column + "," + ",".join(headers) + " from " + intable)
+            vals = ()
+            for row in result:
+                vals = []
+                for x in headers:
+                    if x in conf.allHeaders:
+                        vals.append(row[x])
+                    else:
+                        if not self._checkNull(row[x]):
+                            if not self._checkNull(row[column]) and row[column]:
+                                vals.append(float(row[x]) / float(row[column]))
+                            else:
+                                vals.append(None)
+                        else:
+                            vals.append(None)
+                lastid = self.conn.execute("insert into " + outtable + " (" + ",".join(headers) + ") values (" + ",".join(["?"] * len(headers)) + ")", tuple(vals)).lastrowid
+                self.conn.execute("update " + intable + " set ref_" + outtable + "=? where pegasusid=?", (lastid, row["pegasusid"]))
+            self.conn.commit()
+        return
+    
+    def extractAll(self, options):
+        basepath = os.path.dirname(os.path.dirname(os.path.abspath(self.db) + "/"))
+        if "workflows" in options:
+            for type in options["workflows"]:
+                self._openConnection()
+                tmp = self.conn.execute("select pegasusid,experiment,id,date,imtype,imgname from images where imtype=?", (type,))
+                result = tmp.fetchall()
+                for row in result:
+                    finalpath = row["experiment"].replace(" ","") + "/" + row["id"].replace(" ","") + "/" + row["date"].replace(" ","") + "/" + row["imtype"].replace(" ","") + "/" + row["imgname"].replace(" ","") + "/" + row["pegasusid"] + "_" + options["workflows"][type]["inputs"][0] + ".png"
+                    #finalpath = row["pegasusid"] + "_" + options["workflows"][type]["inputs"][0] + ".png"
+                    self._closeConnection()
+                    if os.path.isfile(finalpath):
+                        try:
+                            plant = ih.imgproc.Image(finalpath, db = self.db, dbid = row["pegasusid"])
+                            plant.extractFinalPath()
+                            if "--dimensions" in options["workflows"][type]["arguments"]:
+                                plant.extractDimensions()
+                            if "--pixels" in options["workflows"][type]["arguments"]:
+                                plant.extractPixels()
+                            if "--moments" in options["workflows"][type]["arguments"]:
+                                plant.extractMoments()
+                            if "--colors" in options["workflows"][type]["arguments"]:
+                                plant.extractColorData()
+                            if "--channels" in options["workflows"][type]["arguments"]:
+                                plant.extractColorChannels()
+                            if "--bins" in options["workflows"][type]["arguments"]:
+                                plant.extractBins(options["workflows"][type]["arguments"]["--bins"])
+                        except Exception as e:
+                            print traceback.format_exc()
+                    else:
+                        print "PATH DOES NOT EXIST: %s." % (finalpath,)
+        if "histogram-bin" in options:
+            self._openConnection()
+            self.histogramBinning("images", "histogramBins", dict((type,options["workflows"][type]["inputs"][0]) for type in options["workflows"]), options["histogram-bin"]["--group"], options["histogram-bin"]["--chunks"], options["histogram-bin"]["--channels"], True)
+        return
+    
+    def histogramBinning(self, intable, outtable, grouping, chunks, channels, jsonwrite = False, overwrite = False):
+        color_vector = {}
+        for name in grouping:
+            self._validate("histogramBins", intable, name + "_" + outtable, overwrite)
+        for name in grouping:
+            self._createTable("histogramBins", intable, name + "_" + outtable, overwrite)
+            color_vector[name] = [0, 0, 0]
+        map = dict((type, name) for name in grouping for type in grouping[name])
+        basequery = "select "
+        for x,c in enumerate(["bhist", "ghist", "rhist"]):
+            for i in range(0, 256):
+                if i == 0 and x == 0:
+                    basequery += "SUM(" + c + str(i) + ")"
+                else:
+                    basequery += ",SUM(" + c + str(i) + ")"
+        basequery += " from images where "
+        for name in grouping:
+            query = basequery + " or ".join(["imtype=?" for x in grouping[name]])
+            result = self.conn.execute(query, tuple(grouping[name]))
+            data = list(result.fetchone())
+            for i in range(0, 3):
+                color_vector[name][i] = data[i*256:(i + 1)*256]
+        bins = {}
+        for name in grouping:
+            bins[name] = self._generateBins(self._splitHist(color_vector[name], chunks[name], channels[name]), name)
+            self.conn.executemany("insert into " + name + "_" + outtable + " (name, minr, ming, minb, maxr, maxg, maxb) values (?, ?, ?, ?, ?, ?, ?)", [(bin["name"], int(bin["min"][2]), int(bin["min"][1]), int(bin["min"][0]), int(bin["max"][2]), int(bin["max"][1]), int(bin["max"][0])) for bin in bins[name]])
+#             for bin in bins[name]:
+#                 self.conn.execute("insert into " + name + "_" + outtable + " (name, minr, ming, minb, maxr, maxg, maxb) values (?, ?, ?, ?, ?, ?, ?)", (name + bin["name"], int(bin["min"][2]), int(bin["min"][1]), int(bin["min"][0]), int(bin["max"][2]), int(bin["max"][1]), int(bin["max"][0])))
+#                 self.conn.commit()
+            self.conn.commit()
+        if jsonwrite:
+            for name in grouping:
+                with open(name + "_hist_bins.json", "w") as wh:
+                    json.dump(bins[name], wh)
+        return
+        
+    
+    def _splitHist(self, hist, chunks, channels):
+        returnlist = [ [1], [1], [1] ]
+        s = [sum(x) for x in hist]
+        #s = [int(x) for x in np.sum(hist, axis = 1)]
+        for i in channels:
+            tmp = 0
+            integral = s[i] / chunks
+            for j,item in enumerate(hist[i]):
+                tmp += item
+                if (tmp > integral):
+                    returnlist[i].append(j)
+                    tmp = 0 
+        returnlist[0].append(255)
+        returnlist[1].append(255)
+        returnlist[2].append(255)
+        return returnlist
+    
+    def _generateBins(self, vector, type):
+        bins = []
+        num = 1
+        for i in range (0, len(vector[0]) - 1):
+            for j in range(0, len(vector[1]) - 1):
+                for k in range(0, len(vector[2]) - 1):
+                    bins.append({
+                        "name": type + "_bin" + str(num),
+                        "min": np.array([vector[0][i],vector[1][j],vector[2][k]], dtype=np.uint8).tolist(),
+                        "max": np.array([vector[0][i+1],vector[1][j+1],vector[2][k+1]], dtype=np.uint8).tolist()
+                    })
+                    num += 1
+        return bins    
+    
+    
+    def correlation(self, intable, outtable, dataFile, dataHeaders, overwrite = False):
+        """
+        :param intable: The input table to load information from
+        :type intable: str
+        :param outtable: The output table to write information to.
+        :type outtable: str
+        :param dataFile: The csv data file to load
+        :type dataFile: str
+        :param dataHeaders: Column names for relevant table headers.
+        :type dataHeaders: str
+        
+        This function correlates all numeric values with values in the given file.
+        The input data file is assumed to be in csv format.  In dataHeaders, you must
+        specify four keys, 'id', 'date', 'dateFormat', and 'metric'.  Each of these should
+        be column names.  Id corresponds to the lemnaTec style identifier ex: '023535-S'.
+        All dates are converted into Y-m-d form, you must provide a valid format in 'dateFormat',
+        that way the dates can be converted correctly.  The 'metric' column is the actual value you
+        want to correlate to.
+        """
+        self._validate("correlation", intable, outtable, overwrite)
+        lemnaData = self._loadLemnaData(dataFile, dataHeaders)
+        self._createTable("correlation", intable, outtable, overwrite)
+        headers = self._getHeaders(outtable)
+        numeric = [h for h in headers if h not in conf.allHeaders]
+        for id in lemnaData:
+            for imtype in self._getImageTypes(intable):
+                x = {}
+                y = []
+                corr = {}
+                result = self.conn.execute("select pegasusid," + ",".join(headers + ["date"]) + " from " + intable + " where id=? and imtype=? order by date", (id,imtype))
+                if result.fetchone():
+                    for row in result:
+                        if row["date"] in lemnaData[id]:
+                            y.append(lemnaData[id][row["date"]]["metric"])
+                            for header in numeric:
+                                if header not in x:
+                                    x[header] = []
+                                try:
+                                    x[header].append(float(row[header]))
+                                except:
+                                    pass
+                    if any([x[header] for header in numeric]):
+                        for header in numeric:
+                            if len(x[header]) == len(y):
+                                corr[header] = np.corrcoef(x[header], y)[0][1]
+                            else:
+                                corr[header] = None
+                        lastid = self.conn.execute("insert into " + outtable + " (" + ",".join(headers) + ") values (" + ",".join(["?"] * len(headers)) + ")", tuple([row[header] if header in conf.allHeaders else corr[header] for header in headers])).lastrowid
+                        self.conn.execute("update " + intable + " set ref_" + outtable + "=? where id=? and imtype=?", (lastid, id, imtype))
+        self.conn.commit()
+        return
+    
+    def anova(self, intable, outtable, grouping, overwrite = False):
+        """ 
+        :param intable: The input table to load information from
+        :type intable: str
+        :param outtable: The output table to write information to.
+        :type outtable: str
+        :param grouping: The list of image types to group by.
+        :type grouping: list
+        
+        Computes the analysis of variation of all numeric information based on 3 factors,
+        treatment, date, and the interaction between the two.  Analysis of variation is
+        different than the rest of the stats functions, in that a lot of information is 
+        lost after running it.  The results themselves correspond to columns (pixels, rmed, binx...)
+        instead of actual images.  
+        """
+        self._validate("anova", intable, outtable, overwrite)
+        headers = self._getHeaders(intable)
+        numeric = [h for h in headers if h not in conf.allHeaders]
+        self._createTable("anova", intable, outtable, overwrite)
+        outHeaders = self._getHeaders(outtable)
+        result = self.conn.execute("select * from images")
+        rowdata = []
+        for row in result:
+            rowdata.append(dict(row))
+        data = pandas.DataFrame(rowdata).dropna()
+        anova = {}
+        for col in numeric:
+            anova[col] = {}
+            dateT = []
+            treatmentT = []
+            date_treatmentT = []
+            for date in self._getDates(intable):
+                dateT.append(data[data["date"] == date][col])
+                for treatment in ["Control", "Stress"]:
+                    treatmentT.append(data[data["treatment"] == treatment][col])
+                    date_treatmentT.append(data[np.where(np.logical_and(data["treatment"] == treatment,data["date"] == date), True, False)][col])
+            f_val, d_pval = stats.f_oneway(*dateT)  
+            f_val, t_pval = stats.f_oneway(*treatmentT)
+            f_val, dt_pval = stats.f_oneway(*date_treatmentT)
+            anova[col]["date"] = d_pval
+            anova[col]["treatment"] = t_pval
+            anova[col]["date_treatment"] = dt_pval
+        for type in ["date", "treatment", "date_treatment"]:
+            vals = [group] + [anova[x][type] for x in numeric] + [type]
+            self.conn.execute("insert into " + outtable + " (" + ",".join(outHeaders) + ") values (" + ",".join(["?"] * len(outHeaders)) + ")", tuple(vals))
+        self.conn.commit()
+        return
+        
+    def tTest(self, intable, outtable, comp = "imtype", overwrite = False):
+        """
+        :param intable: The input table to perform the T test on.
+        :type intable: str
+        :param outtable: The output table to write the results to.
+        :type outtable: str
+        :param comp: Whether to compare image types or image names.
+        :type comp: str
+        :param overwrite: Whether or not to overwrite the output database
+        :type overwrite: bool
+        
+        This function computes a ttest of the input table for all numeric headers.
+        The comparison is either done based on image types or image names.  Default
+        functionality is a comparison between image types, specify comp = 'imgname'
+        to compare image names.
+        """
+        
+        self._validate("ttest", intable, outtable, overwrite)
+        self._createTable("ttest", intable, outtable, overwrite)
+        comp = "imtype" if comp == "imtype" else "imgname"
+        headers = self._getHeaders(outtable)
+        numeric = [h for h in headers if h not in conf.allHeaders]
+        meta = [h for h in headers if h not in numeric]
+        data = {}
+        result = self.conn.execute("select pegasusid,treatment," + ",".join(headers) + " from " + intable)
+        for row in result:
+            if row[comp] not in data:
+                data[row[comp]] = {}
+            if row["date"] not in data[row[comp]]:
+                data[row[comp]][row["date"]] = {"meta": dict(row), "id": [], "values": {}}
+            data[row[comp]][row["date"]]["id"].append(row["pegasusid"])
+            if row["treatment"] not in data[row[comp]][row["date"]]["values"]:
+                data[row[comp]][row["date"]]["values"][row["treatment"]] = [[row[h]] for h in numeric]
+            else:
+                for i,h in enumerate(numeric):
+                    data[row[comp]][row["date"]]["values"][row["treatment"]][i].append(row[h])
+        for comp in data:
+            for date in data[comp]:
+                vals = [data[comp][date]["meta"][x] for x in meta]
+                for a,b in zip(data[comp][date]["values"]["Control"], data[comp][date]["values"]["Stress"]):
+                    try:
+                        res = stats.ttest_ind(a, b)[1]
+                    except:
+                        res = None
+                    vals += [res]
+                lastid = self.conn.execute("insert into " + outtable + " (" + ",".join(headers) + ") values (" + ",".join(["?"] * len(headers)) + ")", vals).lastrowid
+                updateVals = (lastid,) + tuple(data[comp][date]["id"])
+                self.conn.execute("update " + intable + " set ref_" + outtable + "=? where id in (" + ",".join(["?"] * len(data[comp][date]["id"])) + ")", updateVals)
+        self.conn.commit()
+        return
+    
+    def treatmentComp(self, intable, outtable, type = "ratio", direction = "Control", comp = "imtype", overwrite = False):
+        """
+        :param intable: The input table to load information from
+        :type intable: str
+        :param outtable: The output table to write information to.
+        :type outtable: str
+        :param type: The type of calculation to do between treatments.  Should be ratio or difference.
+        :type type: str
+        :param direction: Whether to compute C ~ S, or S ~ C, default is Control first.
+        :type direction: str
+        :param comp: Whether to compare by imtype or imgname
+        :type comp: str
+        
+        This function compares information between treatments -- It finds plants that are identical
+        except for treatment, and computes either a ratio or difference between them.  Direction
+        is specified as the column you want first, so direction = "Control" will compute C ~ S, and 
+        direction = "Stress" will compute S ~ C.  If you have already normalized your table, difference
+        will provide better information than ratio.
+        """
+        t1 = "Stress" if direction == "Stress" else "Control"
+        t2 = "Stress" if direction == "Control" else "Control"
+        if type == "ratio":
+            op = lambda left, right: (left / right)
+        else:
+            op = lambda left, right: (left - right)
+        comp = "imtype" if comp == "imtype" else "imgname"
+        self._validate("treatmentComp", intable, outtable, overwrite)
+        self._createTable("treatmentComp", intable, outtable, overwrite)
+        headers = self._getHeaders(outtable)
+        numeric = [h for h in headers if h not in conf.allHeaders]
+        meta = [h for h in headers if h not in numeric]
+        data = {}
+        result = self.conn.execute("select pegasusid," + ",".join(headers) + " from " + intable)
+        for row in result:
+            if row["genotype"] not in data:
+                data[row["genotype"]] = {"id": [], "values": {}, "meta": {}}
+            data[row["genotype"]]["meta"][row[comp]] = dict(row)
+            data[row["genotype"]]["id"].append(row["pegasusid"])
+            if row[comp] not in data[row["genotype"]]["values"]:
+                data[row["genotype"]]["values"][row[comp]] = {}
+            if row["date"] not in data[row["genotype"]]["values"][row[comp]]:
+                data[row["genotype"]]["values"][row[comp]][row["date"]] = {}
+            if row["treatment"] not in data[row["genotype"]]["values"][row[comp]][row["date"]]:
+                data[row["genotype"]]["values"][row[comp]][row["date"]][row["treatment"]] = [row[h] for h in numeric]
+        for genotype in data:
+            for comp in data[genotype]["values"]:
+                for date in data[genotype]["values"][comp]:
+                    vals = [data[genotype]["meta"][comp][x] for x in meta]
+                    for a,b in zip(data[genotype]["values"][comp][date][t1], data[genotype]["values"][comp][date][t2]):
+                        try:
+                            res = op(float(a), float(b))
+                        except:
+                            res = None
+                        vals.append(res)
+                    lastid = self.conn.execute("insert into " + outtable + " (" + ",".join(headers) + ") values (" + ",".join(["?"] * len(headers)) + ")", vals).lastrowid
+                    updateVals = (lastid,) + tuple(data[genotype]["id"])
+                    self.conn.execute("update " + intable + " set ref_" + outtable + "=? where id in (" + ",".join(["?"] * len(data[genotype]["id"])) + ")", updateVals)
+        self.conn.commit()
+        return
+    
+    def threshold(self, intable, outtable, thresh = 0.01, overwrite = False):
+        """
+        :param intable: The input table to load information from
+        :type intable: str
+        :param outtable: The output table to write information to.
+        :type outtable: str
+        :param thresh: The threshold value.
+        :type thresh: float
+        
+        This function thresholds the table based on the given value.  All values
+        that fall below the threhsold are 'updated' in place with 'null'.  Normalize
+        is often called before thresholding.
+        """
+        self._validate("threshold", intable, outtable, overwrite)
+        self._createTable("threshold", intable, outtable, overwrite)
+        headers = self._getHeaders(outtable)
+        numeric = [h for h in headers if h not in conf.allHeaders]
+        result = self.conn.execute("select pegasusid," + ",".join(headers) + " from " + intable)
+        for row in result:
+            vals = []
+            for x in headers:
+                if x in conf.allHeaders:
+                    vals.append(row[x])
+                else:
+                    if not self._checkNull(row[x]):
+                        if float(row[x]) > thresh:
+                            vals.append(row[x])
+                        else:
+                            vals.append(None)
+                    else:
+                        vals.append(None)
+            lastid = self.conn.execute("insert into " + outtable + " (" + ",".join(headers) + ") values (" + ",".join(["?"] * len(headers)) + ")", tuple(vals)).lastrowid
+            self.conn.execute("update " + intable + " set ref_" + outtable + "=? where pegasusid=?", (lastid, row["pegasusid"]))
+        self.conn.commit()
+        return
+    
+    def SOMANYGRAPHINGFUNCTIONS(self):
+        
+        return
+    
+    def export(self, table, processed = True, group = None, fname = None):
+        """
+        :param table: The table to write to csv
+        :type table: str
+        :param processed: Whether or not to extract processed data
+        :type processed: bool
+        :param group: Which image types to extract from the database.
+        :type group: list
+        :param fname: The file name to write to.
+        :type fname: str
+        
+        This function simply extracts data from a database and writes it to csv format.
+        Default functionality is to extract only data that has been processed.  This is
+        checked by finding if an outputPath has been set.  Additionally,
+        you can specify a list of image types to extract, if not, the default list contains
+        all rgb and fluo images.  Finally, if no file name is specified, the name
+        of the table is used as the filename.
+        """
+        group = group if isinstance(group, list) else self._getImageTypes(table)
+        fname = fname if fname else table + ".csv"
+        query = "select * from " + table
+        values = tuple()
+        if processed:
+            query += " where outputPath is not null"
+            if group:
+                query += " and (" + " or ".join(["imtype=?" for x in group]) + ")"
+                values = tuple([x for x in group])
+        elif group:
+            query += " where " + " or ".join(["imtype=?" for x in group])
+            values = tuple([x for x in group])
+        table = pandas.io.sql.read_sql(sql = query, params = values, con = self.conn)
+        table.to_csv(fname)
+        return
diff --git a/build/lib/ih/validator.py b/build/lib/ih/validator.py
new file mode 100644
index 0000000000000000000000000000000000000000..23c5bb563de8b7c61f6d440fb45251d838ec5465
--- /dev/null
+++ b/build/lib/ih/validator.py
@@ -0,0 +1,714 @@
+"""
+This file is part of Image Harvest.
+
+Image Harvest is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Image Harvest is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Image Harvest.  If not, see <http://www.gnu.org/licenses/>.
+"""
+import os
+import conf
+import sys
+import json
+import re
+import csv
+import datetime
+import sqlite3
+import textwrap
+import shutil
+import errno
+import copy
+import traceback
+from Pegasus.DAX3 import *
+
+class Validator(object):
+    """
+    A very, very generic validator.
+    """
+    def __init__(self, f, type):
+        self.err = ""
+        if not os.path.isfile(f):
+            self.err += "Path Error: Input '%s' doesn't exist.\n" % (f,)
+        if not self.err:
+            if type == "file":
+                with open(f, "r") as rh:
+                    try:
+                        self.data = json.load(rh)
+                    except Exception as e:
+                        self.err += "Json Error: File '%s', %s\n" % (f, str(e))
+            elif type == "db":
+                self.conn = sqlite3.connect(f)
+                self.conn.row_factory = sqlite3.Row
+                try:
+                    result = self.conn.execute("select * from images")
+                    if not result.fetchone():
+                        self.err += "Database Error: No information in images table\n"
+                except Exception as e:
+                    self.err += "Database Error: %s\n" % (str(e), )
+            else:
+                self.err += "Validator Error: Invalid type, must be either 'file' or 'db'\n"
+            self.rawFiles = {}
+            self.type = type
+            self.validate()
+        return
+    
+    def printErrors(self):
+        """
+            Prints out errors from validation and then exits.
+        """
+        if self.err:
+            print self.err.strip()
+        else:
+            print "No Validation Errors."
+        return
+    
+    def isValid(self):
+        """
+            A convenience function.  If validation ran successfully,
+            return True, else return False.
+        """
+        if not self.err:
+            return True
+        else:
+            return False
+        
+    def validate(self):
+        """
+            This function should be overloaded
+        """
+        return
+        
+class Workflow(object):
+    
+    def __init__(self, template, config, database):
+        self.workflow = Validator(template, "file")
+        self.config = Validator(config, "file")
+        self.db = Validator(database, "db")
+        self.err = ""
+        if self.workflow.isValid() and self.db.isValid() and self.config.isValid():
+            self.validate()
+        else:
+            self.err += "Workflow components did not validate individually. \n"
+            self.err += self.workflow.err
+            self.err += self.config.err
+            self.err += self.db.err
+        return
+    
+    def isValid(self):
+        """
+        A convenience function.
+        """
+        if not self.err:
+            return True
+        else:
+            return False
+        
+    def printErrors(self):
+        if self.err:
+            print self.err.strip()
+        else:
+            print "No Validation Errors"
+        return
+    
+    def _loadOverwriteArgument(self, job, arg):
+        job["arguments"][arg] = conf.valid[job["executable"]]["arguments"][arg]["value"]
+        return
+    
+    def _loadDerivedArgument(self, job, arg, jtype):
+        key = conf.valid[job["executable"]]["arguments"][arg]["key"]
+        index = conf.valid[job["executable"]]["arguments"][arg]["index"]
+        if key in job:
+            if isinstance(job[key], list):
+                if index <= len(job[key]) - 1:
+                    if "value" in conf.valid[job["executable"]]["arguments"][arg]:
+                        job["arguments"][arg] = conf.valid[job["executable"]]["arguments"][arg]["value"]
+                    else:
+                        job["arguments"][arg] = job[key][index]
+                else:
+                    if "required" in conf.valid[job["executable"]]["arguments"][arg]:
+                        self.err += "Workflow, Argument Error: Type '%s' job '%s', derived argument '%s' requires index '%s' for definition '%s', no such index. \n" % (jtype, job["name"], arg, index, key)
+            else:
+                if "required" in conf.valid[job["executable"]]["arguments"][arg]:
+                    self.err += "Workflow, Argument Error: Type '%s' job '%s', derived argument '%s' requires definition for '%s' to be of type list, definition is of type '%s'. \n" % (jtype, job["name"], arg, key, type(job[key]).__name__)
+        else:
+            if "required" in conf.valid[job["executable"]]["arguments"][arg]:
+                self.err += "Workflow, Argument Error: Type '%s' job '%s', derived argument '%s' requires job definition for '%s', no such definition. \n" % (jtype, job["name"], arg, key)
+        return
+    
+    def _validateArgumentType(self, job, arg, type):
+        if arg in job["arguments"]:
+            if not isinstance(job["arguments"][arg], {
+                "list": list,
+                "string": (str, unicode),
+                "dict": dict,
+                "numeric": (int, long, float),
+                "exist": object,
+                "derived": object
+            }[conf.valid[job["executable"]]["arguments"][arg]["type"]]):
+                self.err += "Workflow, Argument Error: Type '%s' job '%s', argument '%s' given value '%s', should be of type '%s'. \n" % (type, job["name"], arg, job["arguments"][arg], conf.valid[job["executable"]]["arguments"][arg]["type"])
+            else:
+                if isinstance(job["arguments"][arg], list) and "join" in conf.valid[job["executable"]]["arguments"][arg]:
+                    job["arguments"][arg] = conf.valid[job["executable"]]["arguments"][arg]["join"].join(job["arguments"][arg])
+                elif (isinstance(job["arguments"][arg], dict) or isinstance(job["arguments"][arg], list)):
+                    job["arguments"][arg] = str(job["arguments"][arg])
+                elif (isinstance(job["arguments"][arg], (str, unicode)) and conf.valid[job["executable"]]["arguments"][arg]["type"] and "complex" in conf.valid[job["executable"]]["arguments"][arg]):
+                    job["arguments"][arg] = '"' + job["arguments"][arg] + '"'
+        return
+    
+    def _validateArgumentRequired(self, job, arg, type):
+        if "required" in conf.valid[job["executable"]]["arguments"][arg]:
+            if arg in job["arguments"]:
+                if not job["arguments"][arg]:
+                    self.err += "Workflow, Argument Error: Type '%s' job '%s', has empty required argument '%s' \n" % (type, job["name"], arg)
+            else:
+                self.err += "Workflow, Argument Error: Type '%s' job '%s', requires argument '%s', no such argument found. \n" % (type, job["name"], arg)
+        return
+    
+    def _validateArgumentDictionary(self, job, arg, type):
+        arglist = job["arguments"][arg] if isinstance(job["arguments"][arg], list) else [job["arguments"][arg]]
+        if conf.valid[job["executable"]]["arguments"][arg]["validation"] == "dictionary":
+            d = conf.valid[job["executable"]]["arguments"][arg]["value"] if "key" not in conf.valid[job["executable"]]["arguments"][arg] else conf.valid[job["executable"]]["arguments"][arg]["value"].get(job["arguments"][conf.valid[job["executable"]]["arguments"][arg]["key"]])
+            for val in arglist:
+                if val not in d:
+                    self.err += "Workflow, Argument Error: Type '%s' job '%s', has invalid value '%s' for argument '%s'. \n" % (type, job["name"], val, arg)
+        return
+    
+    def _validateArgumentList(self, job, arg, type):
+        arglist = job["arguments"][arg] if isinstance(job["arguments"][arg], list) else [job["arguments"][arg]]
+        l = conf.valid[job["executable"]]["arguments"][arg]["value"]
+        for val in arglist:
+            if val not in l:
+                self.err += "Workflow, Argument Error: Type '%s' job '%s', has invalid value '%s' for argument '%s'. \n" % (type, job["name"], val, arg)
+        return
+    
+    def _validateArguments(self, job, type):
+        if not job["arguments"]:
+            job["arguments"] = {}
+        for arg in conf.valid[job["executable"]]["arguments"]:
+            if conf.valid[job["executable"]]["arguments"][arg]["type"] == "derived":
+                self._loadDerivedArgument(job, arg, type)
+            if "required" in conf.valid[job["executable"]]["arguments"][arg] or arg in job["arguments"]:
+                if conf.valid[job["executable"]]["arguments"][arg]["type"] == "overwrite":
+                    self._loadOverwriteArgument(job, arg)
+                else:
+                    self._validateArgumentRequired(job, arg, type)
+                    self._validateArgumentType(job, arg, type)
+                
+                if "validation" in conf.valid[job["executable"]]["arguments"][arg]:
+                    if arg in job["arguments"]:
+                        validate = {
+                            "dictionary": self._validateArgumentDictionary,
+                            "list": self._validateArgumentList
+                        }[conf.valid[job["executable"]]["arguments"][arg]["validation"]](job, arg, type)
+                
+        for arg in job["arguments"]:
+            if arg not in conf.valid[job["executable"]]["arguments"]:
+                self.err += "Workflow, Argument Error: Type '%s' job '%s', has invalid argument '%s'. \n" % (type, job["name"], arg)
+        return
+    
+    def _validateDependencies(self, job, type):
+        try:
+            names = [x["name"] for x in self.workflow.data["workflows"][type]]
+            unres = copy.deepcopy(job["inputs"])
+            for input in job["inputs"]:
+                if os.path.isfile(input):
+                    unres.remove(input)
+                    self.workflow.rawFiles[type].append(input)
+                elif input in self.workflow.data["workflows"][type][0]["inputs"]:
+                    unres.remove(input)
+            if "depends" in job:
+                for dependency in job["depends"]:
+                    if dependency in names:
+                        i = names.index(dependency)
+                        for output in self.workflow.data["workflows"][type][i]["outputs"]:
+                            if output in unres:
+                                unres = [x for x in unres if x != output]
+                    else:
+                        self.err += "Workflow, Dependency Error: Type '%s' job '%s' depends on job '%s', no such job exists. \n" % (type, job["name"], dependency)
+            for val in set(unres):
+                self.err += "Workflow, Input Error: Type '%s' job '%s' depends on input '%s'.  Cannot find matching output, or raw file. \n" % (type, job["name"], val)
+            for x,input in enumerate(job["inputs"]):
+                if "depends" in job:
+                    for dependency in job["depends"]:
+                        if dependency in names:
+                            i = names.index(dependency)
+                            if input in self.workflow.data["workflows"][type][i]["outputs"]:
+                                j = self.workflow.data["workflows"][type][i]["outputs"].index(input)
+                                if conf.valid[job["executable"]]["inputs"][x] != conf.valid[self.workflow.data["workflows"][type][i]["executable"]]["outputs"][j]:
+                                    self.err += "Workflow, Dependency Error: Type '%s' job '%s' input '%s' in position '%s' should be of type '%s', however, output '%s' in position '%s' of job '%s' is of type '%s'. \n" %  (type, job["name"], input, x, conf.valid[job["executable"]]["inputs"][x], self.workflow.data["workflows"][type][i]["outputs"][j], j, self.workflow.data["workflows"][type][i]["name"], conf.valid[self.workflow.data["workflows"][type][i]["executable"]]["outputs"][j])
+        except:
+            self.printErrors()
+            print "Validation halted at type '%s' job '%s'.  Fix errors before re-running. \n" % (type, job)
+            sys.exit()
+        return
+    
+    def _validateDB(self):
+        """
+        Valides the input database file.
+        DIFFERENT FOR WORKFLOWS
+        OVERLOAD THIS
+        """
+        
+        return
+    
+    def _validateConfig(self):
+        """
+        Validates the input configuration template.
+        SAME FOR BOTH TYPES OF WORKFLOWS
+        """
+        if self.config.data:
+            if set(conf.templateKeys["config"]["required"]) < set(self.config.data.keys()):
+                if not os.path.isdir(self.config.data["installdir"]):
+                    self.err += "Config, Path Error: Path '%s' specified for 'installdir' does not exist. \n" % (self.config.data["installdir"],)
+                for key in self.config.data:
+                    if key not in conf.templateKeys["config"]["required"] and key not in conf.templateKeys["config"]["optional"]:
+                        self.err += "Config, Key Error: Invalid key '%s' specified.  Allowed keys are '%s'. \n" % (key, conf.templateKeys["config"]["required"] + conf.templateKeys["config"]["optional"])
+                if "maxwalltime" in self.config.data:
+                    for key in self.config.data["maxwalltime"]:
+                        if key not in conf.templateKeys["config"]["maxwalltime"]["optional"]:
+                            self.err += "Config, Key Error: Invalid key '%s' specified for 'maxwalltime'.  Allowed keys are '%s'. \n" % (key, conf.templateKeys["config"]["maxwalltime"]["optional"])
+                if "notify" in self.config.data:
+                    for key in conf.templateKeys["config"]["notify"]["required"]:
+                        if key not in self.config.data["notify"]:
+                            self.err += "Config, Key Error: Required key '%s' not specified for 'notify'.  \n" % (key,)
+                        elif key == "pegasus_home":
+                            if not os.path.isfile(self.config.data["notify"]["pegasus_home"] + "/notification/email"):
+                                self.err += "Config, Path Error: Required key '%s' has invalid value.  Path '%s' does not exist." % (key, self.config.data["notify"]["pegasus_home"] + "/notification/email")
+                for namespace in self.config.data["profile"]:
+                    for key in self.config.data["profile"][namespace]:
+                        if "path" in key.lower():
+                            if not isinstance(self.config.data["profile"][namespace][key], list):
+                                self.config.data["profile"][namespace][key] = [self.config.data["profile"][namespace][key]]
+                            if "osg" in self.config.data and namespace == "env" and key in conf.osgenv:
+                                self.config.data["profile"][namespace][key] = list(set(conf.osgenv[key] + self.config.data["profile"][namespace][key]))
+                            for path in self.config.data["profile"][namespace][key]:
+                                if not os.path.isdir(path):
+                                    self.err += "Config, Path Error: Path '%s' specified for namespace '%s', key '%s' does not exist. \n" % (path, namespace, key)
+                if "osg" in self.config.data:
+                    if "profile" not in self.config.data:
+                        self.config.data["profile"] = {}
+                    if "env" not in self.config.data["profile"]:
+                        self.config.data["profile"]["env"] = {}
+                    for key in conf.templateKeys["config"]["osg"]["required"]:
+                        if key not in self.config.data["osg"]:
+                            self.err += "Config, OSG Key Error: Specifying 'osg' requires the key '%s' to be defined." % (key,)
+                        elif not os.path.isfile(self.config.data["osg"][key]):
+                            self.err += "Config, OSG Path Error: Path '%s' specified for key '%s' does not exist. \n" % (self.config.data["osg"][key], key)
+            else:
+                self.err += "Config, Template Error: Config file does not have all the required keys:" + str(conf.templateKeys["config"]["required"]) + " \n"
+        else:
+            self.err += "Config, Load Error: Could not load configuration info. \n"
+        return
+    
+    def _getImageTypes(self):
+        return [x["imtype"] for x in self.db.conn.execute("select distinct imtype from images")]
+    
+    def validate(self):
+        """
+        This should be overloaded again.
+        """
+        return 
+    
+    
+class ImageProcessor(Workflow):
+    
+    def __init__(self, template, config, database):
+        super(ImageProcessor, self).__init__(template, config, database)
+        return
+        
+    def validate(self):
+        """
+            Validates all inputted files.  Because the workflow is
+            dependenet on the config and metadata, workflow validation
+            is only done if config and metadata validate successfully.
+        """
+        if not self.err:
+            self._validateConfig()
+            self._validateDB()
+            if not self.err:
+                self._validateWorkflow()
+        return
+    
+    def _validateWorkflowJobs(self):
+        types = self._getImageTypes()
+        for type in self.workflow.data["workflows"]:
+            if type not in types:
+                self.err += "Imgproc, Type Error: Workflow definition exists for type '%s', no images have been loaded for that type. \n" % (type,)
+            self.workflow.rawFiles[type] = []
+            names = [x["name"] for x in self.workflow.data["workflows"][type]]
+            if len(names) == len(set(names)):
+                for job in self.workflow.data["workflows"][type]:
+                    if set(conf.templateKeys["imgproc"]["job"]["required"]) <= set(job.keys()):
+                        for key in job.keys():
+                            if key not in conf.templateKeys["imgproc"]["job"]["required"] and key not in conf.templateKeys["imgproc"]["job"]["optional"]:
+                                self.err += "Imgproc, Key Error: Job '%s' has invalid key '%s' specified.  Allowed keys are '%s'. \n" % (job["name"], key, conf.templateKeys["imgproc"]["job"]["required"] + conf.templateKeys["imgproc"]["job"]["optional"])
+                        if job["executable"] in conf.valid:
+                            if not os.path.isfile(self.config.data["installdir"] + "/" + job["executable"]):
+                                self.err += "Imgproc, Path Error: Job '%s' executable '%s' does not exist. \n" % (job["name"], self.config.data["installdir"] + "/" + job["executable"])
+                            if conf.valid[job["executable"]]["type"] == "imgproc":
+                                self._validateArguments(job, type)
+                                self._validateDependencies(job, type)
+                            else:
+                                self.err += "Imgproc, Executable Error: Job '%s' has invalid executable '%s' specified.  Only image processing scripts are allowed. \n" % (job["name"], job["executable"])
+                        else:
+                            self.err += "Imgproc, Executable Error: Job '%s' has non-existant executable '%s' specified. \n" % (job["name"], job["executable"])
+                    else:
+                        self.err += "Imgproc, Key Error: Job '%s' doesn't have all required keys: '%s'.  \n" % (job["name"], conf.templateKeys["imgproc"]["job"]["required"])
+            else:
+                self.err += "Imgproc, Name Error: Cannot parse ambiguous workflow.  Workflow defined for type '%s' contains multiple jobs with the same name. \n" % (type,)
+        return
+    
+    def _validateWorkflowOptions(self):
+        if set(conf.templateKeys["imgproc"]["options"]["required"]) <= set(self.workflow.data["options"].keys()):
+            for key in self.workflow.data["options"]:
+                if key not in conf.templateKeys["imgproc"]["options"]["required"] and key not in conf.templateKeys["imgproc"]["options"]["optional"]:
+                    self.err += "Imgproc, Option Error: Invalid option '%s' specified. \n " % (key,)
+        else:
+            self.err += "Imgproc, Option Error: Option specification doesn't have all required keys: '%s'. \n " % (conf.templateKeys["imgproc"]["options"]["required"],)
+        return
+    
+    def _validateWorkflowExtract(self):
+        if set(conf.templateKeys["imgproc"]["extract"]["required"]) <= set(self.workflow.data["extract"].keys()):
+            for key in self.workflow.data["extract"]:
+                if key not in conf.templateKeys["imgproc"]["extract"]["required"] and key not in conf.templateKeys["imgproc"]["extract"]["optional"]:
+                    self.err += "Imgproc, Extract Error: Invalid option '%s' specified. \n " % (key,)
+            
+            ## Manual hist-bin validation ##
+            if "histogram-bin" in self.workflow.data["extract"]:
+                hist = {}
+                hist["executable"] = "ih-stats-histogram-bin"
+                hist["inputs"] = ["images"]
+                hist["outputs"] = ["none"]
+                hist["name"] = "histogramBin"
+                hist["arguments"] = self.workflow.data["extract"]["histogram-bin"].copy()
+                self._validateArguments(hist, "extract")
+                if not self.err:
+                    if set(self.workflow.data["extract"]["histogram-bin"]["--group"].keys()) != set(self.workflow.data["extract"]["histogram-bin"]["--channels"].keys()):
+                        self.err += "Imgproc, Extract Error: Histogram bin group names don't match between '--group' and '--channels'. \n"
+                else:
+                    pass       
+                    
+            if not self.err:
+                for type in self.workflow.data["extract"]["workflows"]:
+                    if type in self.workflow.data["workflows"]:
+                        job = self.workflow.data["extract"]["workflows"][type]
+                        job["executable"] = "ih-extract"
+                        job["outputs"] = ["none"]
+                        job["name"] = type + "_extract"
+                        self._validateArguments(job, type)
+                        self._validateDependencies(job, type)
+                    else:
+                        self.err += "Imgproc, Extract Error: Extraction specified for type '%s'.  No processing workflow defined for that type." % (type,)
+            else:
+                pass
+        else:
+            self.err += "Imgproc, Extract Error: Extract specification doesn't have all required keys: '%s'. \n" % (conf.templateKeys["imgproc"]["extract"]["required"],)
+        return
+        
+    
+    def _validateWorkflow(self):
+        """
+            Validates the input workflow template, making sure all required
+            keys are inputted, and all names resolve
+        """
+        if set(conf.templateKeys["imgproc"]["required"]) <= set(self.workflow.data.keys()):
+            for key in self.workflow.data.keys():
+                if key not in conf.templateKeys["imgproc"]["required"] and key not in conf.templateKeys["imgproc"]["optional"]:
+                    self.err += "Imgproc, Key error: Invalid key '%s' specified.  Allowed keys are '%s'. \n" % (key, conf.templateKeys["imgproc"]["required"] + conf.templateKeys["imgproc"]["optional"])
+            try:
+                self._validateWorkflowJobs()
+                self._validateWorkflowOptions()
+                self._validateWorkflowExtract()
+            except Exception as e:
+                print traceback.format_exc()
+                self.err += "Validation halted.  Fix current issues before re-running. \n"
+                self.printErrors()
+        else:
+            self.err += "Imgproc, Template Error: Workflow file does not have all the required keys: '%s'. \n" % (conf.templateKeys["imgproc"]["required"],)
+        return
+    
+    def _validateDB(self):
+        """
+            Validates the inputted metadata db, ensuring the appropriate
+            column names are in the database.
+        """
+        if self.db:
+            cols = [row[1] for row in self.db.conn.execute("PRAGMA table_info(images)")]
+            if set(conf.outHeaders) <= set(cols):
+                testpath = self.db.conn.execute("select path from images limit 0,1").next()[0]
+                if not os.path.isfile(testpath):
+                    self.err += "DB, Path Error: Test file: '%s' could not be found. \n" % (testpath,)
+            else:
+                 self.err += "DB, Key Error: Meta-data file does not have all the required headers: %s \n" % (str(conf.outHeaders),)
+        else:
+            self.err += "DB, Load Error: Could not connect to meta-data db. \n"
+        return
+        
+        
+    
+class Statistics(Workflow):
+    
+    def __init__(self, template, config, database):
+        super(Statistics, self).__init__(template, config, database)
+        
+        return
+    
+    def validate(self):
+        """
+            Validates all inputted files.  Because the workflow is
+            dependenet on the config and metadata, workflow validation
+            is only done if config and metadata validate successfully.
+        """
+        if not self.err:
+            self._validateConfig()
+            self._validateDB()
+            if not self.err:
+                self._validateWorkflow()
+        return
+    
+    def _validateDB(self):
+        try:
+            result = self.db.conn.execute("select * from images")
+            cols = [row[1] for row in self.db.conn.execute("PRAGMA table_info(images)")]
+            if not set(cols) > set(conf.outHeaders):
+                self.err += "Stats, Database Error: Database specified does not contain any numeric columns, process images first. \n"
+            if not set(conf.outHeaders) <= set(cols):
+                self.err += "Stats, Database Error: Database specified does not contain all the required column names: '%s'. \n " % (conf.outHeaders,)
+            if not result.fetchone():
+                self.err += "Stats, Database Error: Database specified does not contain an image table with any entries. \n"
+        except sqlite3.DatabaseError:
+            self.err += "Stats, Database Error: File specified is not a valid database file. \n"
+        return
+ 
+    def _validateWorkflow(self):
+        if self.workflow.data:
+            for key in self.workflow.data.keys():
+                if key not in conf.templateKeys["stats"]["required"] and key not in conf.templateKeys["stats"]["optional"]:
+                    self.err += "Stats, Key error: Invalid key '%s' specified.  Allowed keys are '%s'. \n" % (key, conf.templateKeys["stats"]["required"] + conf.templateKeys["stats"]["optional"])
+            for type in self.workflow.data["workflows"]:
+                self.workflow.rawFiles[type] = []
+                names = [x["name"] for x in self.workflow.data["workflows"][type]]
+                if len(names) == len(set(names)):
+                    for job in self.workflow.data["workflows"][type]:
+                        if set(conf.templateKeys["stats"]["job"]["required"]) <= set(job.keys()):
+                            for key in job.keys():
+                                if key not in conf.templateKeys["stats"]["job"]["required"] and key not in conf.templateKeys["stats"]["job"]["optional"]:
+                                    self.err += "Stats, Key Error: Job '%s' has invalid key '%s' specified.  Allowed keys are '%s'. \n" % (job["name"], key, conf.templateKeys["stats"]["job"]["required"] + conf.templateKeys["stats"]["job"]["optional"])
+                            if job["executable"] in conf.valid:
+                                if conf.valid[job["executable"]]["type"] == "statistics":
+                                    if os.path.isfile(self.config.data["installdir"] + "/" + job["executable"]):
+                                        self._validateArguments(job, type)
+                                        self._validateDependencies(job, type)
+                                    else:
+                                        self.err += "Stats, Path Error: Job '%s' executable '%s' does not exist. \n" % (job["name"], self.config["installdir"] + "/" + job["executable"])
+                                else:
+                                    self.err += "Stats, Executable Error: Job '%s' has invalid executable '%s' specified.  Only statistics scripts are allowed. \n" % (job["name"], job["executable"])
+                            else:
+                                self.err += "Stats, Executable Error: Job '%s' executable '%s' is not a valid executable. \n" % (job["name"], job["executable"])
+                        else:
+                            self.err += "Stats, Key Error: Job '%s' doesn't have all required keys: '%s'. \n" % (job["name"], conf.templateKeys["stats"]["job"]["required"])
+                else:
+                    self.err += "Stats, Name Error: Cannot parse ambiguous workflow.  Workflow defined for type '%s' contains multiple jobs with the same name. \n" % (type,)
+        else:
+            self.err += "Stats, Load Error: Could not load stats file. \n"
+        return
+    
+class ImageLoader(Validator):
+    
+    def __init__(self, f):
+        super(ImageLoader, self).__init__(f, "file")
+        return
+    
+    def validate(self):
+        """
+            Validates the given template.
+        """
+        if self.isValid():
+            if set(conf.templateKeys["loading"]["required"]) <= set(self.data.keys()):
+                for key in self.data:
+                    if key not in conf.templateKeys["loading"]["required"] and key not in conf.templateKeys["loading"]["optional"]:
+                        self.err += "Loader, Key Error: Invalid key '%s' specified. \\n" % (key,)
+                        
+                if not self.err:
+                    for key in self.data:
+                        d = {
+                            "path": self._validatePath,
+                            "base": self._validateBase,
+                            "data": self._validateData,
+                            "translations": self._validateTranslations,
+                            "order": self._validateOrder,
+                            "filetype": self._validateFtype,
+                        }[key]()
+            else:
+                self.err += "Loader, Key Error: Not all required keys specified: '%s' \n" % (conf.templateKeys["loading"]["required"])
+        return
+    
+    def _validateFtype(self):
+        if self.data["filetype"]:
+            if self.data["filetype"] not in conf.imageExtensions:
+                self.err += "Loader, File Error: Value '%s' specified for 'filetype' is invalid.  Must be on of '%s'. \n" % (self.data["filetype"], conf.imageExtensions)
+        else:
+            self.err += "Loader, File Error: No value specified for 'filetype'. \n"
+    
+    def _validatePath(self):
+        """
+            Validates the path.  Because the path contains potential references, path existence
+            cannot be checked at this stage.
+        """
+        if not self.data["path"]:
+            self.err += "Loader, Path Error: No value specified for 'path'.\n"
+        return
+    
+    def _validateBase(self):
+        """
+            Validates the base walk path.  Checks existence of a value, if the value
+            is a subset of path, and if the path exists.
+        """ 
+        if self.data["base"]:
+            if self.data["base"] in self.data["path"]:
+                if not os.path.exists(self.data["base"]):
+                    self.err += "Loader, Base Error: Value for 'base' is not a valid path. \n"
+            else:
+                self.err += "Loader, Base Error: Value for 'base' is not a subset of 'path'. \n"
+        else:
+            self.err += "Loader, Base Error: No value specified for 'base'.\n"
+        pass
+    
+    def _validateData(self):
+        """
+            Validates the data!  Uses a seperate function for each data type.
+        """
+        if self.data["data"]:
+            for key in self.data["data"]:
+                if "type" in self.data["data"][key]:
+                    if self.data["data"][key]["type"] in conf.templateKeys["loading"]["data"]["type"]:
+                        if key in self.data["order"]:
+                            d = {
+                                "value": self._validateDataValue,
+                                "file": self._validateDataFile,
+                                "date": self._validateDataDate
+                            }[self.data["data"][key]["type"]](key)
+                        else:
+                            self.err += "Loader, Data Error: Definition for data key '%s', no corresponding definition in 'order'. \n" % (key,)
+                    else:
+                        self.err += "Loader, Data Error: Invalid type '%s' specified for data key '%s', must be one of '%s'. \n" % (self.data["data"][key]["type"], key, conf.templateKeys["loading"]["data"]["type"])
+                else:
+                    self.err += "Loader, Data Error: No value specified for 'type' of data key '%s'. \n" % (key,)
+        else:
+            self.err += "Loader, Value Error: No value specified for 'data'. \n"
+        pass
+    
+    def _validateDataValue(self, key):
+        """
+            Validates type 'value'.  Values can be combinations of hard-coded text
+            as well as references to path identifiers  Checks existence of a value,
+            if all the references are valid, and if translation is specified, that
+            translations exist.
+        """
+        if self.data["data"][key]["value"]:
+            if set(conf.templateKeys["loading"]["data"]["value"]["required"]) <= set(self.data["data"][key].keys()):
+                
+                for subkey in self.data["data"][key]:
+                    if subkey not in conf.templateKeys["loading"]["data"]["value"]["required"] and subkey not in conf.templateKeys["loading"]["data"]["value"]["optional"]:
+                        self.err += "Loader, Data Value Error: Invalid key '%s' specified for data key '%s'. \n" % (subkey,key)
+                
+                m = re.findall(r"%(\w+)%", self.data["data"][key]["value"])
+                for val in m:
+                    if "%" + val + "%" not in self.data["path"]:
+                        self.err += "Loader, Data Value Reference Error: Could not reference identifier '%s' for data key '%s'. \n" % (val, key)
+                if "translate" in self.data["data"][key]:
+                    if key not in self.data["translations"]:
+                        self.err += "Loader, Data Value Translation Error: Can't translate data key '%s', no translation specified. \n" % (key,)
+            else:
+                print set(conf.templateKeys["loading"]["data"]["value"]["required"])
+                print set(self.data["data"][key].keys())
+                self.err += "Loader, Data Value Error: Data key '%s' does not have all required keys '%s'. \n" % (key, conf.templateKeys["loading"]["data"]["value"]["required"])
+        else:
+            self.err += "Loader, Data Value Error: No value specified for data key '%s'. \n " % (key,)
+        return
+    
+    def _validateDataFile(self, key):
+        """
+            Validates type 'file'.  Checks to ensure that a file is specified,
+            that file exists, and that a value is specified for key, keyColumn,
+            and valueColumn.  Assumes the file is of csv format.
+        """
+        if set(conf.templateKeys["loading"]["data"]["file"]["required"]) <= set(self.data["data"][key].keys()):
+            
+            for subkey in self.data["data"][key]:
+                if subkey not in conf.templateKeys["loading"]["data"]["file"]["required"] and subkey not in conf.templateKeys["loading"]["data"]["file"]["optional"]:
+                    self.err += "Loader, Data File Error: Invalid key '%s' specified for data key '%s'. \n" % (subkey, key)
+            
+            if os.path.exists(self.data["data"][key]["value"]):
+                with open(self.data["data"][key]["value"], "r") as rh:
+                    firstline = rh.readline()
+                    sep = self.data["data"][key]["separator"] if "separator" in self.data["data"][key] else ","
+                    maxlength = len(firstline.split(sep))
+                    if maxlength <= self.data["data"][key]["keyColumn"]:
+                        self.err += "Loader, Data File Error: Key column for data key '%s' out of range. \n" % (key,)
+                    if maxlength <= self.data["data"][key]["valueColumn"]:
+                        self.err += "Loader, Data File Error: Value column for data key '%s' out of range. \n" % (key,)
+            else:
+                self.err += "Loader, Data Filer Error: File '%s' specified for data key '%s' does not exist. \n" % (self.data["data"][key]["value"], key)
+                
+            m = re.findall(r"%(\w+)%", self.data["data"][key]["key"])
+            for val in m:
+                if "%" + val + "%" not in self.data["path"]:
+                    self.err += "Loader, Data Value Reference Error: Could not reference identifier '%s' for data key '%s'. \n" % (val, key)
+        else:
+            self.err += "Loader, Data File Error: Data key '%s' does not have all required keys '%s'. \n" % (key, conf.templateKeys["loading"]["data"]["file"]["required"])
+        return
+            
+    def _validateDataDate(self, key):
+        """
+            Validates type 'date'.  Checks to ensure that a value exists, a format
+            exists, and that the format is semi-valid.  True validity of format is
+            checked when values are given in the crawling step.
+        """
+        if set(conf.templateKeys["loading"]["data"]["date"]["required"]) <= set(self.data["data"][key].keys()):
+            
+            for subkey in self.data["data"][key]:
+                if subkey not in conf.templateKeys["loading"]["data"]["date"]["required"] and subkey not in conf.templateKeys["loading"]["data"]["date"]["optional"]:
+                    self.err += "Loader, Data Date Error: Invalid key '%s' specified for data key '%s'. \n" % (subkey, key)
+             
+            if not set(self.data["data"][key]["format"]) <= set(conf.dateFormat + conf.dateSep):
+                self.err += "Loader, Data Date Error: Invalid values in data key '%s', format only supports '%s'. \n" % (key, conf.dateFormat + conf.dateSep)
+                
+            m = re.findall(r"%(\w+)%", self.data["data"][key]["value"])
+            for val in m:
+                if "%" + val + "%" not in self.data["path"]:
+                    self.err += "Loader, Data Value Reference Error: Could not reference identifier '%s' for data key '%s'. \n" % (val, key)
+        else:
+            self.err += "Loader, Data Date Error: Data key '%s' does not have all required keys '%s'. \n" % (key, conf.templateKeys["loading"]["data"]["date"]["required"])
+        return
+    
+    def _validateTranslations(self):
+        """
+            Nothing to see here, move along.
+        """
+        for key in self.data["translations"]:
+            if key not in self.data["data"]:
+                self.err += "Loader, Translation Error: Translation defined for '%s', however, no such data value exists. \n" % (key,)
+        return
+    
+    def _validateOrder(self):
+        """
+            Validates the order -- the order you want to write values to the csv.
+            Checks existence of a value, as well as ensuring all values specified
+            have corresponding data values.
+        """
+        if self.data["order"]:
+            if not set(self.data["order"]) == set(self.data["data"].keys() + ["path"]):
+                self.err += "Loader, Order Error: Order must contain ALL data keys AND 'path'. \n"
+        else:
+            self.err += "Loader, Order Error: No value specified for order. \n"
+        return
+        
diff --git a/build/lib/ih/workflow.py b/build/lib/ih/workflow.py
new file mode 100644
index 0000000000000000000000000000000000000000..1ce3947f44d5badcf280b2c4d38068b8675a5627
--- /dev/null
+++ b/build/lib/ih/workflow.py
@@ -0,0 +1,1128 @@
+"""
+This file is part of Image Harvest.
+
+Image Harvest is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Image Harvest is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Image Harvest.  If not, see <http://www.gnu.org/licenses/>.
+"""
+
+import os
+import conf
+import sys
+import json
+import re
+import csv
+import datetime
+import sqlite3
+import shutil
+import errno
+import textwrap
+import copy
+import ih.validator
+import getpass
+import xml.dom.minidom
+from Pegasus.DAX3 import *
+        
+
+class Workflow(object):
+    
+    """
+        Generic workflow creation class.
+    """
+    
+    def __init__(self, jobhome, basename = None):
+        """
+            :param jobhome: The base directory for job submission.
+            :type jobhome: str
+            
+            Creates a Workflow class based on the input directory.  Only loads and 
+            validates the config file by default.
+        """
+        self.err = ""
+        self.jobhome = os.path.abspath(jobhome)
+        self.jobname = os.path.basename(os.path.dirname(self.jobhome + "/"))
+        self.basename = basename
+        self.dax = ADAG(self.jobname)
+        self.executables = {}
+        self.files = {self.dax: {}}
+        self.jobs = {self.dax: {}}
+        self.deps = {}
+        return
+    
+    def _loadInputFiles(self):
+        """
+            Loads the input files into the appropriate variables
+            This should be overloaded.
+        """
+        return
+
+    def _isFile(self, name, dax, imtype, inout):
+        """
+            Convenience function to check if a given file exists.
+        """
+        if name in self.files[dax][imtype][inout]:
+            return True
+        return False
+    
+    def _isJob(self, name, dax):
+        """
+            Convenience function to check if a given job exists.
+        """
+        if name in self.jobs[dax]:
+            return True
+        return False
+    
+    def _isExecutable(self, name):
+        """
+            Convenience function to check if a given executable exists.
+        """
+        if name in self.executables:
+            return True
+        return False
+    
+    def _createSetup(self):
+        """
+            Creates the base structure for job submission.  Everything is contained 
+            within a folder based on the current timestamp.
+        """
+        self.basepath = self.jobhome + "/" + self.basename if self.basename else self.jobhome + "/" + datetime.datetime.now().strftime("%Y-%m-%d_%H%M%S")
+        if not os.path.exists(self.basepath):
+            os.makedirs(self.basepath)
+        if not os.path.exists(self.basepath + "/input"):
+            os.makedirs(self.basepath + "/input")
+        if not os.path.exists(self.basepath + "/output"):
+            os.makedirs(self.basepath + "/output")
+        if not os.path.exists(self.basepath + "input/templates"):
+            os.makedirs(self.basepath + "/input/templates")
+        if not os.path.exists(self.basepath + "/input/rawfiles"):
+            os.makedirs(self.basepath + "/input/rawfiles")
+        if "osg" in self.config:
+            if not os.path.exists(self.basepath + "/staging"):
+                os.makedirs(self.basepath + "/staging")
+        return
+    
+    def _addFile(self, name, imtype, inout, path = None, dax = None, derivedPath = None):
+        """
+            Adds the inputted file to the dax, as well as the internal variable self.files
+        """
+        dax = dax if dax else self.dax
+        if not self._isFile(name, dax, imtype, inout):
+            self.files[dax][imtype][inout][name] = {"file": File(name), "path": ""}
+            if inout == "input":
+                self.files[dax][imtype][inout][name]["path"] = path if path else name
+                self.files[dax][imtype][inout][name]["file"].addPFN(PFN("file://" + path.replace(" ","%20"), "local"))
+                if derivedPath:
+                    self.files[dax][imtype][inout][name]["derivedPath"] = derivedPath
+                dax.addFile(self.files[dax][imtype][inout][name]["file"])
+        return
+    
+    def _addJob(self, jobname, executable, inputs, outputs, arguments, dependencies = None, dax = None, label = None, walltime = None):
+        dax = dax if dax else self.dax
+        if not self._isJob(jobname, dax):
+            if "osg" in self.config:
+                self.jobs[dax][jobname] = Job("osg-wrapper.sh")
+            else:
+                self.jobs[dax][jobname] = Job(executable)
+            dax.addJob(self.jobs[dax][jobname])
+            if "osg" in self.config:
+                self.jobs[dax][jobname].uses("ih.tar.gz", link = Link.INPUT)
+            for key in inputs:
+                self.jobs[dax][jobname].uses(inputs[key]["file"], link = Link.INPUT)
+            for key in outputs:
+                self.jobs[dax][jobname].uses(outputs[key]["file"], link = Link.OUTPUT, transfer = outputs[key]["transfer"])
+            arglist = []
+            if "osg" in self.config:
+                arglist.append("./ih-" + self.config["version"] + "/scripts/" + executable)
+            for arg in arguments:
+                arglist.append(arg)
+                if str(arguments[arg]) in inputs:
+                    arglist.append(inputs[str(arguments[arg])]["file"])
+                elif str(arguments[arg]) in outputs:
+                    arglist.append(outputs[str(arguments[arg])]["file"])
+                else:
+                    if "osg" in self.config:
+                        arglist.append("'" + str(arguments[arg]) + "'")
+                    else:
+                        arglist.append(str(arguments[arg]))
+            self.jobs[dax][jobname].addArguments(*arglist)
+            if dependencies:
+                for depend in dependencies:
+                    dax.depends(child = self.jobs[dax][jobname], parent = self.jobs[dax][depend])
+            if label:
+                self.jobs[dax][jobname].profile(Namespace.PEGASUS, "label", label)
+            if walltime:
+                self.jobs[dax][jobname].profile(Namespace.GLOBUS, "maxwalltime", walltime)
+        return
+                
+    def create(self):
+        """
+            Creates a new pegasus submission directory based on the current timestamp,
+            and populates it with all required information to submit a pegasus job.
+            This function should be overloaded.
+        """
+        return  
+
+
+class Statistics(Workflow):
+    
+    """
+        A class specifically for statistics workflow
+        validation and submission.
+    """
+    
+    def __init__(self, jobhome, basename, validOnly = False):
+        super(Statistics, self).__init__(jobhome, basename)
+        self.configfile = jobhome + "/input/" + conf.configFile
+        self.statsfile = jobhome + "/input/" + conf.statsFile
+        self.dbfile = jobhome + "/" + basename + "/output/" + conf.outputdb
+        self.validOnly = validOnly
+        self.rawFiles = {}
+        self._loadInputFiles()
+        return
+    
+    def _getImageTypes(self):
+        return [x[0] for x in self.db.execute("select distinct imtype from images")]
+        
+        
+    def _loadInputFiles(self):
+        self.validator = ih.validator.Statistics(self.statsfile, self.configfile, self.dbfile)
+        if not self.validator.isValid() or self.validOnly:
+            self.validator.printErrors()
+            sys.exit()
+        else:
+            self.stats = self.validator.workflow.data
+            self.db = self.validator.db.conn
+            self.config = self.validator.config.data
+            self.rawFiles = self.validator.workflow.rawFiles
+        return
+    
+    def _copyFiles(self):
+        """
+            Copies all input files to the correct location.
+        """
+        if not os.path.exists(self.basepath + "/input/stats"):
+            os.makedirs(self.basepath + "/input/stats")
+        shutil.copyfile(self.statsfile, self.basepath + "/input/templates/" + os.path.basename(self.statsfile))
+        return
+    
+    def _loadFiles(self, loc):
+        """
+            Loads all files (input and output) into the dax and the self.files variable
+        """
+        self.files[self.dax] = {}
+        self.files[self.dax]["raw"] = {"input": {}, "output": {}}
+        self._addFile("output.db", "raw", "input", self.basepath + "/output/output.db")
+        for type in self.stats["workflows"]:
+            self.files[self.dax][type] = {"input": {}, "output": {}}
+            for f in self.rawFiles[type]:
+                shutil.copyfile(f, self.basepath + "/input/rawfiles/" + os.path.basename(f))
+                self._addFile(os.path.basename(f), type, "input", self.basepath + "/input/rawfiles/" + os.path.basename(f))
+        return
+    
+    def _loadExecutables(self, os="linux", arch="x86_64"):
+        """
+            Loads all executables (as specified in the conf) into
+            the dax, as well as the internal self.executables variable
+        """
+        for ex in conf.valid:
+            if "osg" in self.config:
+                self.executables[ex] = Executable(name=ex, os=os, arch=arch, installed=False)
+            else:
+                self.executables[ex] = Executable(name=ex, os=os, arch=arch)
+            self.executables[ex].addPFN(PFN("file://" + self.config["installdir"] + "/" + ex, "local"))
+            #if "cluster" in self.config:
+            #     self.executables[ex].addProfile(Profile(Namespace.PEGASUS, "clusters.size", self.config["cluster"]))
+            self.dax.addExecutable(self.executables[ex])
+        return
+    
+    def _loadNotify(self):
+        if "notify" in self.config:
+            self.dax.invoke(When.AT_END, self.basepath + "/input/stats/notify.sh")
+            with open(self.basepath + "/input/stats/notify.sh", "w") as wh:
+                notify = textwrap.dedent("""\
+                        #!/bin/bash
+                        %s/notification/email -t %s --report=pegasus-analyzer
+                """ % (self.config["notify"]["pegasus_home"], self.config["notify"]["email"]))
+                wh.write(notify)
+            os.chmod(self.basepath + "/input/stats/notify.sh", 0755)
+        return
+    
+    def _loadJobInputs(self, job, type, basename, extension, save = False):
+        inputs = {}
+        for i,input in enumerate(job["inputs"]):
+            ftype = conf.valid[job["executable"]]["inputs"][i]
+            if input in self.rawFiles[type]:
+                inputs[input] = {"file": os.path.basename(input), "transfer": save}
+            else:
+                ex = extension if job["name"] == self.workflow["workflows"][type][0]["name"] else conf.fileExtensions[ftype]
+                inputs[input] = {"file": basename + "_" + input + ex, "transfer": save}
+        return inputs
+    
+    def _loadJobInputs(self, job, type, save = False):
+        inputs = {"output.db": {"file": "output.db", "transfer": True}}
+        for i,input in enumerate(job["inputs"]):
+            ftype = conf.valid[job["executable"]]["inputs"][i]
+            if input in self.rawFiles[type]:
+                inputs[input] = {"file": os.path.basename(input), "transfer": save}
+        return inputs
+    
+    def _createDax(self, loc):
+        """
+            Loads all jobs into the dax, and then writes the dax
+            to input/loc/stats.dax
+        """
+        serial = []
+        if "maxwalltime" in self.config:
+            if "stats" in self.config["maxwalltime"]:
+                maxwalltime = self.config["maxwalltime"]["stats"]
+            else:
+                maxwalltime = None
+        else:
+            maxwalltime = None
+        for type in self.stats["workflows"]:
+            for job in self.stats["workflows"][type]:
+                jobname = type + "_" + job["name"]
+                job["arguments"]["--intable"] = type + "_" + job["arguments"]["--intable"] if job["arguments"]["--intable"] != "images" else job["arguments"]["--intable"]
+                job["arguments"]["--outtable"] = type + "_" + job["arguments"]["--outtable"]
+                job["arguments"]["--db"] = "output.db"
+                inputs = self._loadJobInputs(job, type)
+                outputs = {}
+                depends = [type + "_" + depend for depend in job["depends"]] if "depends" in job else serial
+                if self.stats["workflows"][type].index(job) == len(self.stats["workflows"][type]) - 1:
+                    serial = [jobname]
+                else:
+                    serial = []
+                self._addJob(jobname, job["executable"], inputs, outputs, job["arguments"], depends, walltime = maxwalltime)
+        with open(self.basepath + "/" + loc + "/stats.dax", "w") as wh:
+            self.dax.writeXML(wh)
+        return
+    
+    def _createReplica(self, loc):
+        """
+            Creates the pegasus configuration replica catalog.  input/conf.rc
+        """
+        with open(self.basepath + "/" + loc + "/conf.rc", "w") as wh:
+            pegasusrc = textwrap.dedent("""\
+                        pegasus.catalog.site = XML
+                        pegasus.catalog.site.file = %s/sites.xml
+                        
+                        pegasus.condor.logs.symlink = false
+                        
+                        pegasus.transfer.links = true
+                        
+                        pegasus.data.configuration = %s
+                        
+                        """ % (self.basepath + "/" + loc))
+            wh.write(pegasusrc)
+        return
+    
+    def _createSites(self, loc):
+        """
+            Creates the pegasus site catalog.  input/sites.xml
+        """
+        with open(self.basepath + "/" + loc + "/sites.xml", "w") as wh:
+            if "osg" in self.config:
+                sites = """\
+                <sitecatalog version="3.0" xmlns="http://pegasus.isi.edu/schema/sitecatalog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pegasus.isi.edu/schema/sitecatalog http://pegasus.isi.edu/schema/sc-3.0.xsd">
+                    <site handle="local" arch="x86_64" os="LINUX">
+                            <head-fs>
+                                <scratch>
+                                        <shared>
+                                            <file-server protocol="file" url="file://" mount-point="%s"/>
+                                            <internal-mount-point mount-point="%s"/>
+                                        </shared>
+                                    </scratch>
+                                <storage>
+                                        <shared>
+                                            <file-server protocol="file" url="file://" mount-point="%s"/>
+                                            <internal-mount-point mount-point="%s"/>
+                                        </shared>
+                                    </storage>
+                            </head-fs>
+                    """ % (self.basepath + "/work/stats/", self.basepath + "/work/stats/", self.basepath + "/output/", self.basepath + "/output/", self.basepath)
+                sites += """\
+                    </site>
+                    <site handle="condorpool" arch="x86_64" os="LINUX">
+                            <head-fs>
+                                    <scratch />
+                                    <storage />
+                            </head-fs>
+                """
+            else:
+                sites = """\
+                 <sitecatalog xmlns="http://pegasus.isi.edu/schema/sitecatalog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pegasus.isi.edu/schema/sitecatalog http://pegasus.isi.edu/schema/sc-4.0.xsd" version="4.0">
+        
+                            <site  handle="local" arch="x86_64" os="LINUX">
+                                <directory type="shared-scratch" path="%s">
+                                    <file-server operation="all" url="file://%s" />
+                                </directory>
+                                <directory type="local-storage" path="%s">
+                                    <file-server operation="all" url="file://%s" />
+                                </directory>
+                            """ % (self.basepath + "/work/stats/", self.basepath + "/work/stats/", self.basepath + "/output/", self.basepath + "/output/")
+            for namespace in self.config["profile"]:
+                for key in self.config["profile"][namespace]:
+                    val = ":".join(self.config["profile"][namespace][key]) if "path" in key.lower() else self.config["profile"][namespace][key]
+                    sites += """\n\t<profile namespace="%s" key="%s">%s</profile> """ % (namespace, key, val)
+            sites += "</site></sitecatalog>"
+            sites = sites.replace("\n","")
+            wh.write("\n".join([line for line in xml.dom.minidom.parseString(sites).toprettyxml().split('\n') if line.strip()]))
+        return
+    
+    def _createSubmit(self, loc):
+        """
+            Creates the pegasus submit script.  submit.sh
+        """
+        with open(self.basepath + "/" + loc + "/submit.sh", "w") as wh:
+            submit = textwrap.dedent("""\
+                    #!/bin/bash
+                    
+                    plan=`pegasus-plan \\
+                    --conf "%s" \\
+                    --sites "%s" \\
+                    --dir "%s" \\
+                    --output-site local \\
+                    --dax "%s" \\
+                    --randomdir \\""" % (self.basepath + "/" + loc + "/conf.rc", "condorpool" if "osg" in self.config else "local", self.basepath + "/work/stats", self.basepath + "/" + loc + "/stats.dax"))
+            if "cluster" in self.config:
+                submit += """--cluster horizontal \\\n"""
+            submit += textwrap.dedent("""\
+                    --submit`
+                    
+                    status=`echo "$plan" | grep pegasus-status | tr -s ' '| cut -d ' ' -f 6`
+                    echo -e "#!/bin/bash
+                    pegasus-status -l $status" > status.sh
+                    chmod 744 status.sh
+                    
+                    remove=`echo "$plan" | grep pegasus-remove | tr -s ' '| cut -d ' ' -f 5`
+                    echo -e "#!/bin/bash
+                    pegasus-remove $remove" > remove.sh 
+                    chmod 744 remove.sh
+                    
+                    echo "$plan"
+                    echo "Alternatively, you can use the status & remove scripts in the current directory!"
+                    
+                    """)
+            wh.write(submit)
+            os.chmod(self.basepath + "/" + loc + "/submit.sh", 0755)
+        return
+        
+    def create(self):
+        """
+            Creates a new pegasus submission directory based on the current timestamp,
+            and populates it with all required information to submit a pegasus job.
+        """
+        loc = "/input/stats/"
+        self._createSetup()
+        self._copyFiles()
+        self._loadFiles(loc)
+        self._loadExecutables()
+        self._loadNotify()
+        self._createDax(loc)
+        self._createReplica(loc)
+        self._createSites(loc)
+        self._createSubmit(loc)
+        return 
+    
+    
+    
+    
+        
+class ImageProcessor(Workflow):
+    
+    """
+        A class specifically for image processing workflow
+        validation and submission.
+    """
+    
+    def __init__(self, jobhome, basename = None, validOnly = False):
+        """
+            :param jobhome: The base directory for job submission.
+            :type jobhome: str
+            
+            Creates a Workflow class based on the input directory.  Loads and validates all input files,
+            and quits out if something doesn't exist or is defined innapropriately.
+        """
+        super(ImageProcessor, self).__init__(jobhome, basename)
+        self.validOnly = validOnly
+        self.workfile = jobhome + "/input/" + conf.workflowFile
+        self.metafile = jobhome + "/input/" + conf.dbFile
+        self.configfile = jobhome + "/input/" + conf.configFile
+        self._loadInputFiles()
+        self.exdax = ADAG("extract-" + self.jobname)
+        self.jobs[self.exdax] = {}
+        self.files[self.exdax] = {}
+        return
+    
+    def _loadInputFiles(self):
+        """
+            Loads the input files into the appropriate variables
+        """
+        self.validator = ih.validator.ImageProcessor(self.workfile, self.configfile, self.metafile)
+        if not self.validator.isValid() or self.validOnly:
+            self.validator.printErrors()
+            sys.exit()
+        else:
+            self.workflow = self.validator.workflow.data
+            self.metadata = self.validator.db.conn
+            self.config = self.validator.config.data
+            self.rawFiles = self.validator.workflow.rawFiles
+        return
+    
+    def _getImageTypes(self):
+        """
+            Convenience function to get all image types from the database.
+        """
+        return [x[0] for x in self.metadata.execute("select distinct imtype from images")]
+        
+    def _copyFiles(self):
+        """
+            Copies all input files to the correct location.
+        """
+        if not os.path.exists(self.basepath + "/input/imgproc"):
+            os.makedirs(self.basepath + "/input/imgproc")
+        shutil.copyfile(self.workfile, self.basepath + "/input/templates/" + os.path.basename(self.workfile))
+        shutil.copyfile(self.configfile, self.basepath + "/input/templates/" + os.path.basename(self.configfile))
+        shutil.copyfile(self.metafile, self.basepath + "/output/output.db")
+        for type in self.rawFiles:
+            for input in self.rawFiles[type]:
+                shutil.copyfile(input, self.basepath + "/input/rawfiles/" + os.path.basename(input))
+        if "osg" in self.config:
+            shutil.copyfile(self.config["osg"]["tarball"], self.basepath + "/input/rawfiles/" + os.path.basename(self.config["osg"]["tarball"]))
+        return
+    
+    def _loadFiles(self, loc):
+        """
+            Loads all files (input and output) into the dax and the self.files variable
+        """
+        with open(self.basepath + "/input/rawfiles/extract.json", "w") as wh:
+            json.dump(self.workflow["extract"], wh)
+        with open(self.basepath + "/" + loc + "/map.rc", "w") as wh:
+            self.exInput = {"db": "img.db", "extract.json": "extract.json"}
+            self.files[self.dax] = {}
+            self.files[self.exdax] = {}
+            self.files[self.exdax]["all"] = {"input": {}, "output": {}}
+            self.files[self.dax]["raw"] = {"input": {}, "output": {}}
+            self.files[self.exdax]["raw"] = {"input": {}, "output": {}}
+            if "osg" in self.config:
+                self._addFile("ih.tar.gz", "raw", "input", self.basepath + "/input/rawfiles/ih-" + self.config["version"] + ".tar.gz")
+                self._addFile("ih.tar.gz", "raw", "input", self.basepath + "/input/rawfiles/ih-" + self.config["version"] + ".tar.gz", dax = self.exdax)
+            self._addFile("img.db", "raw", "input", self.basepath + "/output/output.db")
+            self._addFile("img.db", "all", "input", self.basepath + "/output/output.db", dax = self.exdax)
+            self._addFile("img2.db", "raw", "output", self.basepath + "/output/img2.db")
+            self._addFile("img2.db", "raw", "output", self.basepath + "/output/img2.db", dax = self.exdax)
+            self._addFile("img3.db", "raw", "output", self.basepath + "/output/img3.db")
+            self._addFile("img3.db", "raw", "output", self.basepath + "/output/img3.db", dax = self.exdax)
+            self._addFile("img.log", "raw", "output", self.basepath + "/output/imgproc.log")
+            self._addFile("extract.json", "raw", "input", self.basepath + "/input/rawfiles/extract.json")
+            self._addFile("extract.json", "all", "input", self.basepath + "/input/rawfiles/extract.json", dax = self.exdax)
+            for type in self.workflow["workflows"]:
+                self.files[self.dax][type] = {"input": {}, "output": {}}
+                for input in self.rawFiles[type]:
+                    self._addFile(os.path.basename(input), type, "input", self.basepath + "/input/rawfiles/" + os.path.basename(input))
+                wh.write("img.log file://" + self.basepath + "/output/imgproc.log pool=\"local\"\n")
+                wh.write("img3.db file://" + self.basepath + "/output/img3.db pool=\"local\"\n")
+                inputImages = [self.workflow["workflows"][type][0]["inputs"][i] for i,x in enumerate(conf.valid[self.workflow["workflows"][type][0]["executable"]]["inputs"]) if x == "image"]
+                outputImages = [self.workflow["workflows"][type][z]["outputs"][i] for z in range(0, len(self.workflow["workflows"][type])) for i,x in enumerate(conf.valid[self.workflow["workflows"][type][z]["executable"]]["outputs"]) if x == "image"]
+                outputFiles = dict((self.workflow["workflows"][type][z]["outputs"][i], conf.fileExtensions[conf.valid[self.workflow["workflows"][type][z]["executable"]]["outputs"][i]]) for z in range(0, len(self.workflow["workflows"][type])) for i,x in enumerate(conf.valid[self.workflow["workflows"][type][z]["executable"]]["outputs"]) if x != "image" and x != "none" and len(self.workflow["workflows"][type][z]["outputs"]) > i)
+                for row in self.metadata.execute("select pegasusid, experiment, id, date, imgname, path from images where imtype=?", (type,)):
+                    realname = row["path"].split("/")[-1].split(".")[0]
+                    #derivedPath = row["experiment"].replace(" ","%20") + "/" + row["id"].replace(" ","%20") + "/" + row["date"].replace(" ","%20") + "/" + type + "/" + row["imgname"].replace(" ","%20") + "/"
+                    derivedPath = row["experiment"].replace(" ","") + "/" + row["id"].replace(" ","") + "/" + row["date"].replace(" ","") + "/" + type + "/" + row["imgname"].replace(" ","") + "/"
+                    for input in inputImages:
+                        if "osg" in self.config:
+                            self._addFile(row["pegasusid"] + "_" + input + "." + row["path"].split(".")[1], type, "input", row["path"], derivedPath = derivedPath + row["pegasusid"])
+                        else:
+                            self._addFile(derivedPath + row["pegasusid"] + "_" + input + "." + row["path"].split(".")[1], type, "input", row["path"], derivedPath = derivedPath + row["pegasusid"])
+                    for output in outputImages:
+                        if output in self.workflow["extract"]["workflows"][type]["inputs"]:
+                            self.exInput[derivedPath + row["pegasusid"] + "_" + output + ".png"] = derivedPath + row["pegasusid"] + "_" + output + ".png"
+                            self._addFile(derivedPath + row["pegasusid"] + "_" + output + ".png", "all", "input", self.basepath + "/output/" + derivedPath + row["pegasusid"] + "_" + output + ".png", dax = self.exdax)
+                        self._addFile(derivedPath + row["pegasusid"] + "_" + output + ".png", type, "output")
+                        wh.write(derivedPath + row["pegasusid"] + "_" + output + ".png file://" + self.basepath + "/output/" + derivedPath + row["pegasusid"].replace(" ","%20") + "_" + output + ".png pool=\"local\"\n") 
+                    for output in outputFiles:
+                        outname = output + outputFiles[output]
+                        self._addFile(derivedPath + row["pegasusid"] + "_" + outname, type, "output")
+                        wh.write(derivedPath + row["pegasusid"] + "_" + outname + " file://" + self.basepath + "/output/" + derivedPath.replace("_","%20") + outname + " pool=\"local\"\n")
+        return
+    
+    def _loadNotify(self):
+        if "notify" in self.config:
+            self.dax.invoke(When.AT_END, self.basepath + "/input/imgproc/notify.sh")
+            self.exdax.invoke(When.AT_END, self.basepath + "/input/imgproc/notify.sh")
+            with open(self.basepath + "/input/imgproc/notify.sh", "w") as wh:
+                notify = textwrap.dedent("""\
+                        #!/bin/bash
+                        %s/notification/email -t %s --report=pegasus-analyzer
+                """ % (self.config["notify"]["pegasus_home"], self.config["notify"]["email"]))
+                wh.write(notify)
+            os.chmod(self.basepath + "/input/imgproc/notify.sh", 0755)
+        return
+    
+    def _loadExecutables(self, os="linux", arch="x86_64"):
+        """
+            Loads all executables (as specified in the conf) into
+            the dax, as well as the internal self.executables variable
+        """
+        for ex in conf.valid:
+            if "osg" in self.config:
+                self.executables[ex] = Executable(name=ex, os=os, arch=arch, installed = False)
+            else:
+                self.executables[ex] = Executable(name=ex, os=os, arch=arch)
+            self.executables[ex].addPFN(PFN("file://" + self.config["installdir"] + "/" + ex, "local"))
+            #if "cluster" in self.config:
+            #    val = int(self.config["cluster"] * conf.valid[ex]["weight"]) if "weight" in conf.valid[ex] else self.config["cluster"]
+            #    self.executables[ex].addProfile(Profile(Namespace.PEGASUS, "clusters.size", val))
+            self.dax.addExecutable(self.executables[ex])
+            self.exdax.addExecutable(self.executables[ex])
+        return
+    
+    def _loadJobInputs(self, job, type, basename, extension, save = False):
+        inputs = {}
+        for i,input in enumerate(job["inputs"]):
+            ftype = conf.valid[job["executable"]]["inputs"][i]
+            if input in self.rawFiles[type]:
+                inputs[input] = {"file": os.path.basename(input), "transfer": save}
+            else:
+                ex = extension if job["name"] == self.workflow["workflows"][type][0]["name"] else conf.fileExtensions[ftype]
+                if "osg" in self.config:
+                    if input == "base":
+                        inputs[input] = {"file": os.path.basename(basename) + "_" + input + ex, "transfer": save}
+                    else:
+                        inputs[input] = {"file": basename + "_" + input + ex, "transfer": save}
+                else:
+                    inputs[input] = {"file": basename + "_" + input + ex, "transfer": save}
+        return inputs
+    
+    def _loadJobOutputs(self, job, type, basename, save):
+        outputs = {}
+        for i,output in enumerate(job["outputs"]):
+            if output != "none":
+                outputs[output] = {"file": basename + "_" + output + conf.fileExtensions[conf.valid[job["executable"]]["outputs"][i]], "transfer": save}
+        return outputs
+    
+    #def _loadJobOutputs(self, job, type, basename):
+    #    return dict((output, basename + "_" + output + conf.fileExtensions[conf.valid[job["executable"]]["outputs"][i]]) for i,output in enumerate(job["outputs"]) if output != "none")
+    
+    def _createDax(self, loc):
+        """
+            Loads all jobs into the dax, and then writes the dax
+            to input/workflow.dax
+        """
+        exDep = {}
+        exInput = {}
+        clusternum = {}
+        meancluster = {}
+        
+        if "maxwalltime" in self.config:
+            if "images" in self.config["maxwalltime"]:
+                maxwalltime = self.config["maxwalltime"]["images"]
+            else:
+                maxwalltime = None
+        else:
+            maxwalltime = None
+        
+        save = True if "save-steps" in self.workflow["options"] else False
+        for type in self.workflow["workflows"]:
+            exDep[type] = [[]]
+            exInput[type] = [{}]
+            jobnum = -1
+            clusternum[type] = 0
+            meancluster[type] = 0
+            exNames = self.workflow["extract"]["workflows"][type]["depends"]
+            for infile in [x for x in self.files[self.dax][type]["input"] if "." + x.split(".")[1] in conf.imageExtensions]:
+                if "cluster" in self.config:
+                    jobnum += 1
+                    if jobnum == self.config["cluster"]:
+                        jobnum = 0
+                        clusternum[type] += 1
+                        exDep[type].append([])
+                        exInput[type].append({})
+                    elif ((clusternum[type] * 100 + jobnum) % int(self.config["cluster"] * 0.3)) == 0:
+                        meancluster[type] += 1
+                extension = "." + infile.split(".")[1]
+                realname = self.files[self.dax][type]["input"][infile]["path"].split("/")[-1].split(".")[0]
+                derivedPath = self.files[self.dax][type]["input"][infile]["derivedPath"]
+                for stepnum,job in enumerate(self.workflow["workflows"][type]):
+                    jobname = derivedPath + "_" + job["name"]
+                    inputs = self._loadJobInputs(job, type, derivedPath, extension)
+                    if job["name"] in exNames:
+                        outputs = self._loadJobOutputs(job, type, derivedPath, True)
+                        exDep[type][clusternum[type]].append(jobname)
+                        reqFile = derivedPath + "_" + self.workflow["extract"]["workflows"][type]["inputs"][0] + ".png"
+                        exInput[type][clusternum[type]][reqFile] = {"file": reqFile, "transfer": save}
+                    else:
+                        outputs = self._loadJobOutputs(job, type, derivedPath, save)
+                    depends = [derivedPath + "_" + depend for depend in job["depends"]] if "depends" in job else []
+                    if job["executable"] == "ih-meanshift":
+                        self._addJob(jobname, job["executable"], inputs, outputs, job["arguments"], depends, label = type + "_step" + str(stepnum) + "_cluster" + str(meancluster[type]) if "cluster" in self.config else None, walltime = maxwalltime)
+                    else:    
+                        self._addJob(jobname, job["executable"], inputs, outputs, job["arguments"], depends, label = type + "_step" + str(stepnum) + "_cluster" + str(clusternum[type]) if "cluster" in self.config else None, walltime = maxwalltime)
+        
+        
+        maprc = open(self.basepath + "/" + loc + "/map.rc", "a")
+        binDep = []
+        aggIn = {}
+        for type in self.workflow["workflows"]:
+            for q in range(0, clusternum[type] + 1):
+                arguments = self.workflow["extract"]["workflows"][type]["arguments"]
+                if "--input" in arguments:
+                    del arguments["--input"]
+                if "histogram-bin" in self.workflow["extract"]:
+                    if type in [imtype for key in self.workflow["extract"]["histogram-bin"]["--group"] for imtype in self.workflow["extract"]["histogram-bin"]["--group"][key]]:
+                        arguments["--colors"] = ""
+                arguments["--db"] = "db"
+                arguments["--createdb"] = ""
+                arguments["--inputs"] = " ".join(exInput[type][q].keys())
+                self._addFile(type + str(q) + ".db", type, "output")
+                self._addJob(type + "_extract" + str(q), "ih-extract-multi", exInput[type][q], {"db": {"file": type + str(q) + ".db", "transfer": False}}, arguments, exDep[type][q])
+                self._addJob(type + "_extract" + str(q), "ih-extract-multi", exInput[type][q], {"db": {"file": type + str(q) + ".db", "transfer": False}}, arguments, [], dax = self.exdax)
+                maprc.write(type + str(q) + ".db" + " file://" + self.basepath + "/output/" + type + str(q) + ".db" + " pool=\"local\"\n")
+                binDep.append(type + "_extract" + str(q))
+                aggIn[type + str(q) + ".db"] = {"file": type + str(q) + ".db", "transfer": False}
+        aggIn["db"] = {"file": "img.db", "transfer": False}
+        self._addJob("sql_aggregate1", "ih-sql-aggregate", aggIn, {"img2.db": {"file": "img2.db", "transfer": False}}, {"--db": "db", "--output": "img2.db", "--inputs": " ".join([aggIn[x]["file"] for x in aggIn if x != "db"])}, binDep)
+        self._addJob("sql_aggregate1", "ih-sql-aggregate", aggIn, {"img2.db": {"file": "img2.db", "transfer": False}}, {"--db": "db", "--output": "img2.db", "--inputs": " ".join([aggIn[x]["file"] for x in aggIn if x != "db"])}, binDep, dax = self.exdax)
+        
+        if "histogram-bin" in self.workflow["extract"]:
+            outputs = {}
+            for name in self.workflow["extract"]["histogram-bin"]["--group"]:
+                self._addFile(name + "_hist_bins.json", "raw", "output")
+                maprc.write(name + "_hist_bins.json" + " file://" + self.basepath + "/output/" + name + "_hist_bins.json" + " pool=\"local\"\n")
+                outputs[name + "_hist_bins.json"] = {"file": name + "_hist_bins.json", "transfer": True}
+            self._addJob("bin_creation", "ih-stats-histogram-bin", {"db": {"file": "img2.db", "transfer": True}, "extract.json": {"file": "extract.json", "transfer": False}}, outputs, {"--db": "db", "--options": "extract.json", "--intable": "images", "--outtable": "histogramBins", "--jsonwrite": "", "--overwrite": ""}, ["sql_aggregate1"])
+            self._addJob("bin_creation", "ih-stats-histogram-bin", {"db": {"file": "img2.db", "transfer": True}, "extract.json": {"file": "extract.json", "transfer": False}}, outputs, {"--db": "db", "--options": "extract.json", "--intable": "images", "--outtable": "histogramBins", "--jsonwrite": "", "--overwrite": ""}, ["sql_aggregate1"], dax = self.exdax)
+            
+            binDep = []
+            map = {}
+            
+            for group in self.workflow["extract"]["histogram-bin"]["--group"]:
+                for type in self.workflow["extract"]["histogram-bin"]["--group"][group]:
+                    map[type] = group
+            
+            for type in self.workflow["workflows"]:
+                for q in range(0, clusternum[type] + 1):
+                    arguments = {}
+                    arguments["--db"] = "db"
+                    arguments["--inputs"] = " ".join(exInput[type][q].keys())
+                    exInput[type][q]["db"] = {"file": type + str(q) + ".db", "transfer": False}
+                    exInput[type][q]["binfile"] = {"file": map[type] + "_hist_bins.json", "transfer": False}
+                    arguments["--bins"] = "binfile"
+                    self._addJob(type + "_extractBins" + str(q), "ih-extract-multi", exInput[type][q], {}, arguments, ["bin_creation"])
+                    self._addJob(type + "_extractBins" + str(q), "ih-extract-multi", exInput[type][q], {}, arguments, ["bin_creation"], dax = self.exdax)
+                    binDep.append(type + "_extractBins" + str(q))
+            aggIn["db"] = {"file": "img2.db", "transfer": False}
+            self._addJob("sql_aggregate2", "ih-sql-aggregate", aggIn, {"img3.db": {"file": "img3.db", "transfer": True}}, {"--db": "db", "--output": "img3.db", "--inputs": " ".join([aggIn[x]["file"] for x in aggIn if x != "db"])}, binDep)
+            self._addJob("sql_aggregate2", "ih-sql-aggregate", aggIn, {"img3.db": {"file": "img3.db", "transfer": True}}, {"--db": "db", "--output": "img3.db", "--inputs": " ".join([aggIn[x]["file"] for x in aggIn if x != "db"])}, binDep, dax = self.exdax)
+        
+        z = 2 if "histogram-bin" in self.workflow["extract"] else 1
+        indb = "img3.db" if "histogram-bin" in self.workflow["extract"] else "img.db"
+        self._addJob("error-log", "ih-error-log", {"db": {"file": indb, "transfer": True}}, {"output": {"file": "img.log", "transfer": True}}, {"--db": "db", "--output": "output"}, ["sql_aggregate" + str(z)])
+        with open(self.basepath + "/" + loc + "/workflow.dax", "w") as wh:
+            self.dax.writeXML(wh)
+        return
+    
+    def _createExtract(self, loc):
+        """
+            Creates the extraction step only dax!
+        """
+        #self._addJob("extractOnly", "ih-extract-all", self.exInput, {}, {"--db": "db", "--options": "extract.json"}, dax = self.exdax)
+        with open(self.basepath + "/" + loc + "/extract.dax", "w") as wh:
+            self.exdax.writeXML(wh)
+        return
+    
+    def _createReplica(self, loc):
+        """
+            Creates the pegasus configuration replica catalog.  input/conf.rc
+        """
+        with open(self.basepath + "/" + loc + "/conf.rc", "w") as wh:
+            pegasusrc = textwrap.dedent("""\
+                        pegasus.catalog.site = XML
+                        pegasus.catalog.site.file = %s/sites.xml
+                        
+                        pegasus.condor.logs.symlink = false
+                        
+                        pegasus.transfer.links = true
+                        
+                        pegasus.data.configuration = %s
+                        
+                        pegasus.dir.storage.mapper = Replica
+                        pegasus.dir.storage.mapper.replica = File
+                        pegasus.dir.storage.mapper.replica.file = %s/map.rc
+                        """ % (self.basepath + "/" + loc, "nonsharedfs" if "osg" in self.config else "sharedfs", self.basepath + "/" + loc))
+            wh.write(pegasusrc)
+        return
+    
+    def _createSites(self, loc):
+        """
+            Creates the pegasus site catalog.  input/sites.xml
+        """
+        with open(self.basepath + "/" + loc + "/sites.xml", "w") as wh:
+            if "osg" in self.config:
+                sites = """\
+                <sitecatalog version="4.0" xmlns="http://pegasus.isi.edu/schema/sitecatalog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pegasus.isi.edu/schema/sitecatalog http://pegasus.isi.edu/schema/sc-4.0.xsd">
+                    <site handle="local" arch="x86_64" os="LINUX">
+                        <directory type="shared-scratch" path="%s">
+                            <file-server operation="all" url="file://%s" />
+                        </directory>
+                        <directory type="local-storage" path="%s">
+                            <file-server operation="all" url="file://%s" />
+                        </directory>
+                        <profile namespace="pegasus" key="SSH_PRIVATE_KEY">%s</profile>
+                    </site>
+                    <site handle="stash" arch="x86_64" os="LINUX">
+                        <directory type="shared-scratch" path="%s">
+                            <file-server operation="get" url="stash://%s"/>
+                            <file-server operation="put" url="scp://%s@login02.osgconnect.net/%s"/>
+                        </directory>
+                    </site>
+                    <site handle="condorpool" arch="x86_64" os="LINUX">
+                        
+                    """ % (self.basepath + "/work/imgproc/", self.basepath + "/work/imgproc/", self.basepath + "/output/", self.basepath + "/output/", self.config["osg"]["ssh"], self.basepath + "/staging/", "/".join((self.basepath + "/staging/").split("/")[2:]), getpass.getuser(), self.basepath + "/staging/")
+            else:
+                sites = """\
+                 <sitecatalog xmlns="http://pegasus.isi.edu/schema/sitecatalog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pegasus.isi.edu/schema/sitecatalog http://pegasus.isi.edu/schema/sc-4.0.xsd" version="4.0">
+        
+                            <site  handle="local" arch="x86_64" os="LINUX">
+                                <directory type="shared-scratch" path="%s">
+                                    <file-server operation="all" url="file://%s" />
+                                </directory>
+                                <directory type="local-storage" path="%s">
+                                    <file-server operation="all" url="file://%s" />
+                                </directory>
+                            """ % (self.basepath + "/work/imgproc/", self.basepath + "/work/imgproc/", self.basepath + "/output/", self.basepath + "/output/")
+            for namespace in self.config["profile"]:
+                for key in self.config["profile"][namespace]:
+                    val = ":".join(self.config["profile"][namespace][key]) if "path" in key.lower() else self.config["profile"][namespace][key]
+                    sites += """\n\t<profile namespace="%s" key="%s">%s</profile> """ % (namespace, key, val)
+            sites += "</site></sitecatalog>"
+            sites = sites.replace("\n","")
+            wh.write("\n".join([line for line in xml.dom.minidom.parseString(sites).toprettyxml().split('\n') if line.strip()]))
+        return
+    
+    def _createSubmit(self, loc):
+        """
+            Creates the pegasus submit script.  submit.sh
+        """
+        with open(self.basepath + "/" + loc + "/submit.sh", "w") as wh:
+            submit = textwrap.dedent("""\
+                    #!/bin/bash
+                    if [ "$1" = "--extract-only" ] || [ "$1" = "--extract" ] || [ "$1" = "-e" ]; then
+                        DAX="%s"
+                    else
+                        DAX="%s"
+                    fi
+                    plan=`pegasus-plan \\
+                    --conf "%s" \\
+                    --sites "%s" \\
+                    --dir "%s" \\
+                    --output-site local \\
+                    --dax "$DAX" \\
+                    --randomdir \\
+                    """ % (self.basepath + "/" + loc + "/extract.dax", self.basepath + "/" + loc + "/workflow.dax", self.basepath + "/" + loc + "/conf.rc", "condorpool" if "osg" in self.config else "local", self.basepath + "/work/imgproc"))
+            if "cluster" in self.config:
+                submit += """--cluster label \\\n"""
+            if "osg" in self.config:
+                submit += """--staging-site stash \\\n"""
+            submit += textwrap.dedent("""\
+                    --submit`
+                    
+                    status=`echo "$plan" | grep pegasus-status | tr -s ' '| cut -d ' ' -f 6`
+                    echo -e "#!/bin/bash
+                    pegasus-status -l $status" > status.sh
+                    chmod 744 status.sh
+                    
+                    remove=`echo "$plan" | grep pegasus-remove | tr -s ' '| cut -d ' ' -f 5`
+                    echo -e "#!/bin/bash
+                    pegasus-remove $remove" > remove.sh 
+                    chmod 744 remove.sh
+                    
+                    echo "$plan"
+                    echo "Alternatively, you can use the status & remove scripts in the current directory!"
+                    
+                    """)
+            wh.write(submit)
+            os.chmod(self.basepath + "/" + loc + "/submit.sh", 0755)
+        return
+                
+    def create(self):
+        """
+            Creates a new pegasus submission directory based on the current timestamp,
+            and populates it with all required information to submit a pegasus job.
+        """
+        print "Generating workflow.  Please wait."
+        loc = "/input/imgproc/"
+        self._createSetup()
+        self._copyFiles()
+        self._loadFiles(loc)
+        self._loadExecutables()
+        self._loadNotify()
+        self._createDax(loc)
+        self._createExtract(loc)
+        self._createReplica(loc)
+        self._createSites(loc)
+        self._createSubmit(loc)
+        return  
+
+
+class ImageLoader:
+    """
+        This should handle all meta-data definitions
+    """
+    
+    def __init__(self, template, output, validOnly = False, overwrite = False):
+        """
+            :param template: Path to input template file, should be valid json.
+            :type template: str
+        """
+        self.templatePath = os.path.abspath(template)
+        self.err = ""
+        self.output = output + "/input/"
+        try:
+            open(self.output + "/images.db")
+        except IOError:
+            self.err += "Path Error: Cannot open output db file. \n"
+        self.validator = ih.validator.ImageLoader(self.templatePath)
+        if not self.validator.isValid() or validOnly:
+            self.validator.printErrors()
+            sys.exit()
+        self.overwrite = overwrite
+        self.template = self.validator.data
+        self.template["order"].insert(0, "pegasusid")
+        self.count = {}
+        self.depth = len(self.template["path"].split("/")) - 1
+        self.structure = self._dictTemplate()
+        self.data = []
+        return
+    
+    def _success(self):
+        if self.overwrite:
+            print "Directory re-crawled!"
+            print "Use ih-run to submit your jobs."
+        else:
+            print "Directory setup successful!"
+            print "Define the required templates in " + self.output + "."
+            print "Then use ih-run to submit your jobs."
+        return
+    
+    def _dictTemplate(self):
+        """
+            Creates the first of two intermediary dictionaries for crawling.  This relates
+            identifiers in the path, to a specified depth, as well as operators to split
+            the value at that depth.
+        """
+        m = [x for x in re.findall(r"%(\w+)%", self.template["path"]) if x != "null"]
+        sp = self.template["path"].split("/")
+        d = {}
+        for key in m:
+            d[key] = {}
+            d[key]["depth"] = [n for n,x in enumerate(sp) if key in x][0]
+            d[key]["split"] = []
+            val = sp[d[key]["depth"]]
+            for operator in [" ", "_", "-"]:
+                if operator in val:
+                    b = val.split(operator)
+                    x = [n for n,x in enumerate(b) if key in x][0]
+                    d[key]["split"].append({"operator": operator, "index": x})
+                    val = b[x]
+        return d
+    
+    def _loadStructure(self, splitPath):
+        """
+            Creates the second of two intermediary dictionaries for crawling.
+            This utilizes the template created in _dictTemplate, and creates
+            a dictionary with actual values instead of structure.
+        """
+        d ={}
+        for key in self.structure:
+            val = splitPath[self.structure[key]["depth"]]
+            for operator in self.structure[key]["split"]:
+                val = val.split(operator["operator"])[operator["index"]]
+            d[key] = val
+        return d
+    
+    def _loadDataFile(self, dict, structure, key):
+        """
+            Loads data from a data file.  If the specified key isn't in the file,
+            write 'UNKNOWN' instead.
+        """
+        keyVal = self._convertReferences(structure, self.template["data"][key]["key"])
+        if keyVal in self.filedata[self.template["data"][key]["value"]]:
+            dict[key] = self.filedata[self.template["data"][key]["value"]][keyVal]
+        else:
+            dict[key] = "UNKNOWN"
+        return
+    
+    def _loadDataValue(self, dict, structure, key):
+        """
+            Loads a data value.
+        """
+        val = self._convertReferences(structure, self.template["data"][key]["value"])
+        if "translate" in self.template["data"][key]:
+            if val in self.template["translations"][key]:
+                val = self.template["translations"][key][val]
+        dict[key] = val
+        return
+    
+    def _loadDataDate(self, dict, structure, key):
+        """
+            Loads a date.
+        """
+        val = self._convertReferences(structure, self.template["data"][key]["value"])
+        format = "".join([x.replace(x, "%" + x) if x in conf.dateFormat else x for x in self.template["data"][key]["format"]])
+        val = datetime.datetime.strptime(val, format).strftime("%Y-%m-%d")
+        dict[key] = val
+        return
+                
+    def _convertReferences(self, structure, val):
+        """
+            Replaces all references ('%%') to actual values.
+        """
+        idList = [x for x in re.findall(r"%(\w+)%", val) if x != "null"]
+        for identifier in idList:
+            if identifier in structure:
+                val = val.replace("%" + identifier + "%", structure[identifier])
+        return val
+    
+    def _loadData(self, path):
+        """
+            Loads all data for a particular path.
+        """
+        temp = {}
+        final = {}
+        splitPath = path.split("/")
+        structure = self._loadStructure(splitPath)
+        for key in self.template["data"]:
+            d = {
+                "value": self._loadDataValue,
+                "file": self._loadDataFile,
+                "date": self._loadDataDate
+            }[self.template["data"][key]["type"]](final, structure, key)
+        final["path"] = path
+        if final["imtype"] not in self.count:
+            self.count[final["imtype"]] = 1
+        else:
+            self.count[final["imtype"]] += 1
+        final["pegasusid"] = final["imtype"] + str(self.count[final["imtype"]])
+        return final
+    
+    def _loadFiles(self):
+        """
+            Reads all data from all specified files.
+        """
+        self.filedata = {}
+        for key in self.template["data"]:
+            if self.template["data"][key]["type"] == "file":
+                if self.template["data"][key]["value"] not in self.filedata:
+                    self.filedata[self.template["data"][key]["value"]] = {}
+                    with open(self.template["data"][key]["value"], "r") as rh:
+                        for line in rh.readlines():
+                            info = line.strip().split(",")
+                            self.filedata[self.template["data"][key]["value"]][info[self.template["data"][key]["keyColumn"]]] = info[self.template["data"][key]["valueColumn"]]
+        return
+    
+    def crawl(self):
+        """
+            Recursively walks through directories in base, and loads
+            the appropriate data.
+        """
+        self._loadFiles()
+        for root, dirs, files in os.walk(self.template["base"]):
+            arr = root.split("/")
+            depth = len(arr)
+            if (depth == self.depth):
+                for file in files:
+                    if file[-len(self.template["filetype"]):] == self.template["filetype"] and file[0] != ".":
+                        d = self._loadData(root + "/" + file)
+                        self.data.append(d)
+        return
+    
+    def write(self):
+        """
+            Writes the data loaded from crawl into csv format based on 'order'
+        """
+        if self.data:
+            conn = sqlite3.connect(self.output + "/images.db")
+            tablestr = "(pegasusid PRIMARY KEY"
+            for x in self.template["order"]:
+                if x != "pegasusid":
+                    tablestr += "," + str(x)
+            tablestr += ")"
+            if self.overwrite:
+                conn.execute("DROP TABLE IF EXISTS images")
+                conn.commit()
+            conn.execute("CREATE TABLE images " + tablestr)
+            writedata = []
+            for row in self.data:
+                writedata.append(tuple([str(row[x]) for x in self.template["order"]]))
+            query = "insert into images " + str(tuple([str(x) for x in self.template["order"]])) + " values (" + ("?," * len(self.template["order"]))[:-1] + ")"
+            conn.executemany(query, writedata)
+            conn.commit()
+            if not self.overwrite:
+                shutil.copyfile(self.templatePath, self.output + "/crawl.json")
+        else:
+            print "Call crawl first!"
+        return
+    
+class DirectorySetup:
+    
+    def __init__(self, jobhome):
+        """
+            :param jobhome: The base directory to setup a job.
+            :type jobhome: str
+        """
+        if not os.path.isdir(os.path.dirname(os.path.dirname(os.path.abspath(jobhome) + "/"))):
+            print "Can't create job folder, path doesn't exist!"
+            sys.exit()
+        self.jobhome = jobhome
+        return
+    
+    def _makeDir(self, dirpath):
+        """
+            Makes a directory if it doesn't exist.  Catches and
+            prints out common errors.
+        """
+        try:
+            os.makedirs(dirpath)
+        except OSError as e:
+            raise Exception({
+                errno.EEXIST: "Directory " + dirpath + " already exists!",
+                errno.EACCES: "You don't have permission to create directory "  + dirpath + ".",
+            }.get(e.errno, "Error for directory " + dirpath + " error:" + str(e)))
+        return
+    
+    def _makeFile(self, filepath):
+        """
+            Opens a file to create it, uses append mode
+            so it doesn't overwrite any existing files.
+        """
+        try:
+            open(filepath, "a")
+        except OSError as e:
+            raise Exception({
+                
+            }.get(e, "Unsepcified error for file " + filepath))
+        return
+    
+    def setup(self):
+        """
+            Creates the directory structure needed to submit jobs,
+            and creates empty template files needed for job submission.
+        """
+        self._makeDir(self.jobhome)
+        self._makeDir(self.jobhome + "/input/")
+        for fname in conf.jobFiles:
+            self._makeFile(self.jobhome + "/input/" + fname)
+        return
+        
+       
+        
diff --git a/build/scripts-2.7/ih-adaptive-threshold b/build/scripts-2.7/ih-adaptive-threshold
new file mode 100755
index 0000000000000000000000000000000000000000..cd9078d5a97707b7f3096a89c6f01ecd1b32d025
--- /dev/null
+++ b/build/scripts-2.7/ih-adaptive-threshold
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Thresholds an image based on windows.")
+parser.add_argument("--input", dest="input", help="Path to input image.", required = True)
+parser.add_argument("--value", dest="value", type=int, help="Value to write to pixels.  Usually 255 or 0.", required = True)
+parser.add_argument("--adaptiveType", dest="adaptiveType", help="Adaptive type to use.  Either 'mean' or 'gaussian'.", required = True)
+parser.add_argument("--thresholdType", dest="thresholdType", help="Threshold type to use.  Either 'binary' or 'inverse'.", required = True)
+parser.add_argument("--blockSize", dest="blockSize", type=int, help="Window size to consider.  Should be an odd number.", required = True)
+parser.add_argument("--C", dest="C", type=int, help="Constant to subtract from window mean.", required = True)
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    plant.adaptiveThreshold(args.value, args.adaptiveType, args.thresholdType, args.blockSize, args.C)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-bitwise-and b/build/scripts-2.7/ih-bitwise-and
new file mode 100755
index 0000000000000000000000000000000000000000..f1ce6343da978c7188b4ba3dc97adc935cb780e1
--- /dev/null
+++ b/build/scripts-2.7/ih-bitwise-and
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Converts an image between color spectrums.")
+parser.add_argument("--input1", dest="input1", help="Path to first input image.", required = True)
+parser.add_argument("--input2", dest="input2", help="Path to second input image.", required = True)
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+parser.add_argument("--mask", default=False, dest="mask", action="store_true", help="Convert the first input image to a mask.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input1, args.outputdir, args.output, False)
+    if args.mask:
+    	plant.mask()
+    plant.bitwise_and(args.input2)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-bitwise-not b/build/scripts-2.7/ih-bitwise-not
new file mode 100755
index 0000000000000000000000000000000000000000..43b38cbaf76caf3c12faa4ff09646854fc02bfdb
--- /dev/null
+++ b/build/scripts-2.7/ih-bitwise-not
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Converts an image between color spectrums.")
+parser.add_argument("--input", dest="input", help="Path to first input image.", required = True)
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    plant.bitwise_not()
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-bitwise-or b/build/scripts-2.7/ih-bitwise-or
new file mode 100755
index 0000000000000000000000000000000000000000..087db32be33abc12658c2f4f1e3bb5853f28a390
--- /dev/null
+++ b/build/scripts-2.7/ih-bitwise-or
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Converts an image between color spectrums.")
+parser.add_argument("--input1", dest="input1", help="Path to first input image.", required = True)
+parser.add_argument("--input2", dest="input2", help="Path to second input image.", required = True)
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input1, args.outputdir, args.output, False)
+    plant.bitwise_or(args.input2)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-bitwise-xor b/build/scripts-2.7/ih-bitwise-xor
new file mode 100755
index 0000000000000000000000000000000000000000..f2141f6b4e35288f1b07174d72ec7784816c9fab
--- /dev/null
+++ b/build/scripts-2.7/ih-bitwise-xor
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Converts an image between color spectrums.")
+parser.add_argument("--input1", dest="input1", help="Path to first input image.", required = True)
+parser.add_argument("--input2", dest="input2", help="Path to second input image.", required = True)
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input1, args.outputdir, args.output, False)
+    plant.bitwise_xor(args.input2)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-blur b/build/scripts-2.7/ih-blur
new file mode 100755
index 0000000000000000000000000000000000000000..344ff9b73561ceea899e47061e73d5079d45c774
--- /dev/null
+++ b/build/scripts-2.7/ih-blur
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Smoothes an image based on a evenly distributed kernel.")
+parser.add_argument("--input", dest="input", help="Path to input image.", required = True)
+parser.add_argument("--kwidth", dest="kwidth", type=int, help="Width of the kernel", required = True)
+parser.add_argument("--kheight", dest="kheight", type=int, help="Height of the kernel", required = True)
+parser.add_argument("--anchorx", default=-1, dest="anchorx", type=int, help="X position of the anchor")
+parser.add_argument("--anchory", default=-1, dest="anchory", type=int, help="Y position of the anchor")
+parser.add_argument("--border", default="default", dest="border", help="Border type for extrapolation.")
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    plant.blur((args.kwidth, args.kheight), (args.anchorx, args.anchory), args.border)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-color-filter b/build/scripts-2.7/ih-color-filter
new file mode 100755
index 0000000000000000000000000000000000000000..85cde83ac6824ec63fce7276398350700e241807
--- /dev/null
+++ b/build/scripts-2.7/ih-color-filter
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Smoothes an image based on a evenly distributed kernel.")
+parser.add_argument("--input", dest="input", help="Path to input image.", required = True)
+parser.add_argument("--logic", dest="logic", help="Logic string to compute.", required = True)
+parser.add_argument("--roi", dest="roi", help="roi file")
+parser.add_argument("--ystart", dest="ystart", default=-1, help="Minimum Y of the roi.")
+parser.add_argument("--yend", dest="yend", default=-1, help="Maximum Y of the roi.")
+parser.add_argument("--xstart", dest="xstart", default=-1, help="Minimum X of the roi.")
+parser.add_argument("--xend", dest="xend", default=-1, help="Maximum X of the roi.")
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    if args.roi:
+        plant.colorFilter(args.logic, args.roi)
+    else:
+        plant.colorFilter(args.logic, [args.ystart, args.yend, args.xstart, args.xend])
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-contour-cut b/build/scripts-2.7/ih-contour-cut
new file mode 100755
index 0000000000000000000000000000000000000000..e315eb70243800668d33a96476077d47770bc8a0
--- /dev/null
+++ b/build/scripts-2.7/ih-contour-cut
@@ -0,0 +1,26 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Smoothes an image based on a evenly distributed kernel.")
+parser.add_argument("--input", dest="input", help="Path to input image.", required = True)
+parser.add_argument("--binary", dest="binary", help="Binary image to calculate contours from", required = True)
+parser.add_argument("--basemin", default=100, dest="basemin", type=int, help="Minimum area of contour required to keep in final image.")
+parser.add_argument("--padminx", default=0, dest="padminx", type=int, help="Padding added to left.")
+parser.add_argument("--padmaxx", default=0, dest="padmaxx", type=int, help="Padding added to right.")
+parser.add_argument("--padminy", default=0, dest="padminy", type=int, help="Padding added to top.")
+parser.add_argument("--padmaxy", default=0, dest="padmaxy", type=int, help="Padding added to bottom.")
+parser.add_argument("--resize", default=False, dest="resize", action="store_true", help="Whether or not to resize the actual image.")
+parser.add_argument("--returnBound", default=False, dest="returnBound", action="store_true", help="Whether or not to write the bound.")
+parser.add_argument("--roiwrite", default="roi.json", dest="roiwrite", help="The name of the roi file to write.")
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    plant.contourCut(args.binary, args.basemin, [args.padminy, args.padmaxy, args.padminx, args.padmaxx], args.resize, args.returnBound, args.roiwrite)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-convert-color b/build/scripts-2.7/ih-convert-color
new file mode 100755
index 0000000000000000000000000000000000000000..f61261b461920774ae611fdcfbab33222289c056
--- /dev/null
+++ b/build/scripts-2.7/ih-convert-color
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Converts an image between color spectrums.")
+parser.add_argument("--input", dest="input", help="Path to input image.", required = True)
+parser.add_argument("--intype", dest="intype", help="Type of input image, one of [bgr, gray, hsv, lab, ycrcb]", required = True)
+parser.add_argument("--outtype", dest="outtype", help="Type of output image, one of [bgr, gray, hsv, lab, ycrcb]", required = True)
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    plant.convertColor(args.intype, args.outtype)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-crawl b/build/scripts-2.7/ih-crawl
new file mode 100755
index 0000000000000000000000000000000000000000..2ec8a80c7e796bfd0ffea705c0ff4d28a85b146e
--- /dev/null
+++ b/build/scripts-2.7/ih-crawl
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.workflow
+
+parser = argparse.ArgumentParser(description = "Initial setup for job submission")
+parser.add_argument("--dir", dest="dir", default=".", help="Base directory name.")
+parser.add_argument("--template", default="input/crawl.json", dest="template", help="Name of template file to use for directory crawling.")
+parser.add_argument("--validate", dest="validate", action="store_true", help="If specified only validates the workflow.  Does not generate submission.")
+args = parser.parse_args()
+
+try:
+    loader = ih.workflow.ImageLoader(args.template, args.dir, args.validate, True)
+    loader.crawl()
+    loader.write()
+    loader._success()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-crop b/build/scripts-2.7/ih-crop
new file mode 100755
index 0000000000000000000000000000000000000000..47fca988253cd64fb28c1d4c4d62e0146f6bcf83
--- /dev/null
+++ b/build/scripts-2.7/ih-crop
@@ -0,0 +1,26 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Smoothes an image based on a evenly distributed kernel.")
+parser.add_argument("--input", dest="input", help="Path to input image.", required = True)
+parser.add_argument("--roi", dest="roi", help="roi file")
+parser.add_argument("--ystart", dest="ystart", help="Minimum Y of the roi.")
+parser.add_argument("--yend", dest="yend", help="Maximum Y of the roi.")
+parser.add_argument("--xstart", dest="xstart", help="Minimum X of the roi.")
+parser.add_argument("--xend", dest="xend", help="Maximum X of the roi.")
+parser.add_argument("--resize", default=False, dest="resize", action="store_true", help="Whether or not to actually resize the image.")
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    if args.roi:
+        plant.crop(args.roi, args.resize)
+    else:
+        plant.crop([args.ystart, args.yend, args.xtart, args.xend], args.resize)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-data b/build/scripts-2.7/ih-data
new file mode 100755
index 0000000000000000000000000000000000000000..e06f7856956891562307ac16ef9a0404ac0692e7
--- /dev/null
+++ b/build/scripts-2.7/ih-data
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.statistics
+import os
+import json
+
+parser = argparse.ArgumentParser(description = "Change input data format.")
+parser.add_argument("--db", dest="db", help="Database to run statistics on.", required = True)
+parser.add_argument("--dir", dest="dir", required = True, help="Folder to move files to.")
+parser.add_argument("--type", dest="type", required = True, help="Type of translation.  Should be one of [pcv, iap]")
+parser.add_argument("--ids", dest="ids", nargs="+", default=None, help="List of ids to extract from db.")
+parser.add_argument("--idfile", dest="idfile", default=None, help="Path to file containing list of ids.")
+parser.add_argument("--imtypes", dest="imtypes", nargs="+", default=None, help="List of imtypes to extract from db.")
+parser.add_argument("--imtypefile", dest="imtypefile", default=None, help="Path to file containing list of imtypes.")
+parser.add_argument("--dates", dest="dates", nargs="+", default=None, help="List of dates to extract from db.")
+parser.add_argument("--datefile", dest="datefile", default=None, help="Path to file containing list of dates.")
+args = parser.parse_args()
+
+try:
+    if args.idfile:
+        with open(args.idfile, "r") as rh:
+            ids = []
+            for line in rh.readlines():
+                ids.append(line.strip())
+    else:
+        ids = args.ids
+        
+    if args.imtypefile:
+        with open(args.idfile, "r") as rh:
+            imtypes = []
+            for line in rh.readlines():
+                imtypes.append(line.strip())
+    else:
+        imtypes = args.imtypes
+        
+    if args.datefile:
+        with open(args.datefile, "r") as rh:
+            dates = []
+            for line in rh.readlines():
+                dates.append(line.strip())
+    else:
+        dates = args.dates
+            
+    stats = ih.statistics.Stats(args.db)
+    if args.type == "pcv":
+        stats.dataToPlantcv(args.dir, ids, imtypes, dates)
+    elif args.type == "iap":
+        stats.dataToIAP(args.dir, ids, imtypes, dates)
+    stats._closeConnection()
+except Exception as e:
+    print traceback.format_exc()
\ No newline at end of file
diff --git a/build/scripts-2.7/ih-edges b/build/scripts-2.7/ih-edges
new file mode 100755
index 0000000000000000000000000000000000000000..3dbe0c9a0bb0beb012e2aecb7117fa138a05113e
--- /dev/null
+++ b/build/scripts-2.7/ih-edges
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Smoothes an image based on a evenly distributed kernel.")
+parser.add_argument("--input", dest="input", help="Path to input image.", required = True)
+parser.add_argument("--threshold1", dest="threshold1", type=int, help="Minimum threshold value.", required = True)
+parser.add_argument("--threshold2", dest="threshold2", type=int, help="Maximum threshold value.", required = True)
+parser.add_argument("--apertureSize", default = 3, dest="apertureSize", type=int, help="Aperture size for Sobel algorithm.")
+parser.add_argument("--L2gradient", default = False, dest="L2gradient", action="store_true", help="Determines method to calculate gradient magnitutde.")
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    plant.edges(args.threshold1, args.threshold2, args.apertureSize, args.L2gradient)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-error-log b/build/scripts-2.7/ih-error-log
new file mode 100755
index 0000000000000000000000000000000000000000..13ab4f56b2d3d42577729421dba793e098191fcb
--- /dev/null
+++ b/build/scripts-2.7/ih-error-log
@@ -0,0 +1,15 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.statistics
+
+parser = argparse.ArgumentParser(description = "Extracts numerical information from an image.")
+parser.add_argument("--db", dest="db", help="Path to database to write", required = True)
+parser.add_argument("--output", dest="output", help="Path to output log file.", required = True)
+args = parser.parse_args()
+
+try:
+    stats = ih.statistics.Stats(args.db)
+    stats.logErrors(args.output)
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-extract b/build/scripts-2.7/ih-extract
new file mode 100755
index 0000000000000000000000000000000000000000..84cd6880a89d0b5632588fb1fdb8a05072f2497d
--- /dev/null
+++ b/build/scripts-2.7/ih-extract
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+import os
+import sqlite3
+
+parser = argparse.ArgumentParser(description = "Extracts numerical information from an image.")
+parser.add_argument("--input", dest="input", help="Path to processed image.", required = True)
+parser.add_argument("--dbid", dest="dbid", help="Image Id, used for database writing", required = True)
+parser.add_argument("--db", dest="db", help="Path to database to write", required = True)
+parser.add_argument("--dimensions", dest="dimensions", default=False, action="store_true", help="Extract dimensions.")
+parser.add_argument("--pixels", dest="pixels", default=False, action="store_true", help="Extract pixels.")
+parser.add_argument("--colors", dest="colors", default=False, action="store_true", help="Extract color data.")
+parser.add_argument("--channels", dest="channels", default=False, action="store_true", help="Extract channel data.")
+parser.add_argument("--bins", dest="bins", default=None, help="Path to bin file.")
+parser.add_argument("--moments", dest="moments", default=False, action="store_true", help="Extract moment data.")
+parser.add_argument("--hull", dest="hull", default=False, action="store_true", help="Extract area of convex hull of entire image.")
+parser.add_argument("--circle", dest="circle", default=False, action="store_true", help="Extract area of min enclosing circle of entire image.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, ".", db = args.db, dbid = args.dbid)
+    
+    plant.extractFinalPath()
+    
+    if args.dimensions:
+        plant.extractDimensions()
+        
+    if args.pixels:
+        plant.extractPixels()
+        
+    if args.moments:
+        plant.extractMoments()
+        
+    if args.colors:
+        plant.extractColorData()
+    
+    if args.channels:
+        plant.extractColorChannels()
+        
+    if args.bins:
+        plant.extractBins(args.bins)
+        
+    if args.hull:
+        plant.extractConvexHull()
+        
+    if args.circle:
+        plant.extractMinEnclosingCircle()
+        
+    
+    
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-extract-all b/build/scripts-2.7/ih-extract-all
new file mode 100755
index 0000000000000000000000000000000000000000..20f12464514e44ae53f6150e3fea371558cac5e5
--- /dev/null
+++ b/build/scripts-2.7/ih-extract-all
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+import ih.statistics
+import os
+import sqlite3
+import json
+
+parser = argparse.ArgumentParser(description = "Extracts numerical information from all images in a database.")
+parser.add_argument("--db", dest="db", help="Database to load processed images from.", required = True)
+parser.add_argument("--options", dest="options", help="Path to options json file.", required = True)
+args = parser.parse_args()
+
+try:
+    with open (args.options, "r") as rh:
+        options = json.load(rh)
+    stats = ih.statistics.Stats(args.db)
+    stats.extractAll(options)
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-extract-multi b/build/scripts-2.7/ih-extract-multi
new file mode 100755
index 0000000000000000000000000000000000000000..22283161f8eaebefefaa88c2176be8132dcdb1a5
--- /dev/null
+++ b/build/scripts-2.7/ih-extract-multi
@@ -0,0 +1,69 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+import os
+import sqlite3
+
+parser = argparse.ArgumentParser(description = "Extracts numerical information from multiple images.")
+parser.add_argument("--inputs", dest="inputs", nargs="+", help="Path to processed image.", required = True)
+parser.add_argument("--db", dest="db", help="Path to database to write", required = True)
+parser.add_argument("--createdb", dest="createdb", default=False, action="store_true", help = "Create database file specified by db")
+parser.add_argument("--dimensions", dest="dimensions", default=False, action="store_true", help="Extract dimensions.")
+parser.add_argument("--pixels", dest="pixels", default=False, action="store_true", help="Extract pixels.")
+parser.add_argument("--colors", dest="colors", default=False, action="store_true", help="Extract color data.")
+parser.add_argument("--channels", dest="channels", default=False, action="store_true", help="Extract channel data.")
+parser.add_argument("--bins", dest="bins", default=None, help="Path to bin file.")
+parser.add_argument("--moments", dest="moments", default=False, action="store_true", help="Extract moment data.")
+parser.add_argument("--hull", dest="hull", default=False, action="store_true", help="Extract convexHull data.")
+parser.add_argument("--circle", dest="circle", default=False, action="store_true", help="Extract minEnclosingCircle data.")
+args = parser.parse_args()
+
+try:
+    if args.createdb:
+        conn = sqlite3.connect(args.db)
+        conn.execute("drop table if exists images")
+        conn.commit()
+        conn.execute("create table images (pegasusid PRIMARY KEY)")
+        conn.commit()
+        conn.executemany("insert into images (pegasusid) values (?)", [(os.path.basename(x).split("_")[0],) for x in args.inputs])
+        conn.commit()
+        conn.close()
+    for input in args.inputs:
+    	try:
+            dbid = "_".join(os.path.basename(input).split("_")[:-1])
+            plant = ih.imgproc.Image(input, ".", db = args.db, dbid = dbid)
+            
+            plant.extractFinalPath()
+	        
+            if args.dimensions:
+                plant.extractDimensions()
+            
+            if args.pixels:
+                plant.extractPixels()
+            
+            if args.moments:
+                plant.extractMoments()
+            
+            if args.colors:
+                plant.extractColorData()
+            
+            if args.channels:
+                plant.extractColorChannels()
+            
+            if args.bins:
+                plant.extractBins(args.bins)
+                
+            if args.hull:
+                plant.extractConvexHull()
+                
+            if args.circle:
+                plant.extractMinEnclosingCircle()
+            
+            plant._closeDb()
+            
+        except:
+            print traceback.format_exc()
+    
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-gaussian-blur b/build/scripts-2.7/ih-gaussian-blur
new file mode 100755
index 0000000000000000000000000000000000000000..00eb1930c553ac2d4c0c3724baa970c8d18c11d8
--- /dev/null
+++ b/build/scripts-2.7/ih-gaussian-blur
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Smooths an image based on a Gaussian kernel.")
+parser.add_argument("--input", dest="input", help="Path to input image.", required = True)
+parser.add_argument("--kwidth", dest="kwidth", type=int, help="Width of the kernel", required = True)
+parser.add_argument("--kheight", dest="kheight", type=int, help="Height of the kernel", required = True)
+parser.add_argument("--sigmax", default=0, dest="sigmax", type=int, help="Standard deviation in the x direction.")
+parser.add_argument("--sigmay", default=0, dest="sigmay", type=int, help="Standard deviation in the y direction.")
+parser.add_argument("--border", default="default", dest="border", help="Border type for extrapolation.")
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    plant.gaussianBlur((args.kwidth, args.kheight), args.sigmax, args.sigmay, args.border)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-meanshift b/build/scripts-2.7/ih-meanshift
new file mode 100755
index 0000000000000000000000000000000000000000..0368cc5447f848cff1059932ed5991210bab8ef9
--- /dev/null
+++ b/build/scripts-2.7/ih-meanshift
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Shifts colors in an image based on nearest neighbors.")
+parser.add_argument("--input", dest="input", help="Path to input image.", required = True)
+parser.add_argument("--spatial_radius", dest="spatial_radius", type=int, help="Spatial Radius.", required = True)
+parser.add_argument("--range_radius", dest="range_radius", type=int, help="Range Radius.", required = True)
+parser.add_argument("--min_density", dest="min_density", type=int, help="Minimum Density.", required = True)
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    plant.meanshift(args.spatial_radius, args.range_radius, args.min_density)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-median-blur b/build/scripts-2.7/ih-median-blur
new file mode 100755
index 0000000000000000000000000000000000000000..aa4e9ab4439a9b8596e648b66dc375cc688ca55a
--- /dev/null
+++ b/build/scripts-2.7/ih-median-blur
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Thresholds an image based on windows.")
+parser.add_argument("--input", dest="input", help="Path to input image.")
+parser.add_argument("--ksize", dest="ksize", type=int, help="Size of the kernel.  Should be odd and positive.", required = True)
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    plant.medianBlur(args.ksize)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-morphology b/build/scripts-2.7/ih-morphology
new file mode 100755
index 0000000000000000000000000000000000000000..6936cafbbe39e8fb7c816279055d6c51bd801153
--- /dev/null
+++ b/build/scripts-2.7/ih-morphology
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Converts an image between color spectrums.")
+parser.add_argument("--input", dest="input", help="Path to input image.", required = True)
+parser.add_argument("--morphType", dest="morphType", help="Type of morphology to perform.", required = True)
+parser.add_argument("--ktype", dest="ktype", help="Type of kernel to generate.", required = True)
+parser.add_argument("--kwidth", dest="kwidth", type=int, help="Width of the kernel.", required = True)
+parser.add_argument("--kheight", dest="kheight", type=int, help="Height of the kernel.", required = True)
+parser.add_argument("--anchorx", default=-1, dest="anchorx", type=int, help="X position of the anchor")
+parser.add_argument("--anchory", default=-1, dest="anchory", type=int, help="Y position of the anchor")
+parser.add_argument("--iterations", default=1, dest="iterations", type=int, help="Number of times to perform the morphology.")
+parser.add_argument("--border", default="default", dest="border", help="Border type for extrapolation.")
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    plant.morphology(args.morphType, args.ktype, (args.kwidth, args.kheight), (args.anchorx, args.anchory), args.iterations, args.border)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-normalize-intensity b/build/scripts-2.7/ih-normalize-intensity
new file mode 100755
index 0000000000000000000000000000000000000000..1df0ef02e4c7deb062e9be6fdaa180f0093f28fb
--- /dev/null
+++ b/build/scripts-2.7/ih-normalize-intensity
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Normalizes an image by per-pixel intensity.")
+parser.add_argument("--input", dest="input", help="Path to first input image.", required = True)
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    plant.normalizeByIntensity()
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-resize b/build/scripts-2.7/ih-resize
new file mode 100755
index 0000000000000000000000000000000000000000..2704315015bcbbf9ab14dfb2625b7848dd24ef64
--- /dev/null
+++ b/build/scripts-2.7/ih-resize
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Smoothes an image based on a evenly distributed kernel.")
+parser.add_argument("--input", dest="input", help="Path to input image.", required = True)
+parser.add_argument("--scale", dest="scale", default=None, type=float, help="Scaling factor.")
+parser.add_argument("--width", dest="width", default=None, type=int, help="Target width.")
+parser.add_argument("--height", dest="height", default=None, type=int, help="Target height.")
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", default=None, dest="output", help="Name of output image to write, if not specified, use input image name.")
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    plant.resizeSelf(args.scale, args.width, args.height)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-run b/build/scripts-2.7/ih-run
new file mode 100755
index 0000000000000000000000000000000000000000..8b8ecce8435c12395efd3650cd34c3880bf83261
--- /dev/null
+++ b/build/scripts-2.7/ih-run
@@ -0,0 +1,26 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.workflow
+import datetime
+
+parser = argparse.ArgumentParser(description = "Initial setup for job submission")
+parser.add_argument("--jobhome", dest="jobhome", default=".", help="Job root.  Should be the output directory from ih-setup. If left blank, will use current directory.")
+parser.add_argument("--basename", dest="basename", default=None, help="Base submission directory name.  If left blank, this will generate a timestamped directory.")
+parser.add_argument("--stats", dest="stats", action="store_true", default=False, help="Write the statistics workflow instead of imgproc workflow.  Requires --basename.")
+parser.add_argument("--validate", dest="validate", action="store_true", default=False, help="If specified only validates the workflow.  Does not generate submission.")
+args = parser.parse_args()
+
+try:
+        basename = datetime.datetime.now().strftime("%Y-%m-%d_%H%M%S") if not args.basename else args.basename
+        if args.stats:
+            if args.basename:
+                stats = ih.workflow.Statistics(args.jobhome, basename, args.validate)
+                stats.create()
+            else:
+                print "Stats requires an already processed folder.  Specify --basename."
+        else:
+            workflow = ih.workflow.ImageProcessor(args.jobhome, basename, args.validate)
+            workflow.create()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-setup b/build/scripts-2.7/ih-setup
new file mode 100755
index 0000000000000000000000000000000000000000..121ff7b70218651b76b73da8321b4309a9a26bca
--- /dev/null
+++ b/build/scripts-2.7/ih-setup
@@ -0,0 +1,14 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.workflow
+
+parser = argparse.ArgumentParser(description = "Initial setup for job submission")
+parser.add_argument("--dir", dest="dir", help="Base directory name.")
+args = parser.parse_args()
+
+try:
+    setup = ih.workflow.DirectorySetup(args.dir)
+    setup.setup()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-sql-aggregate b/build/scripts-2.7/ih-sql-aggregate
new file mode 100755
index 0000000000000000000000000000000000000000..17d768c8147de803eadb39862aff6db440a94b72
--- /dev/null
+++ b/build/scripts-2.7/ih-sql-aggregate
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.statistics
+import shutil
+
+parser = argparse.ArgumentParser(description = "Writes data from many small sql files to main db.")
+parser.add_argument("--db", dest="db", help="Main database to load data into.", required = True)
+parser.add_argument("--output", dest="output", help="Output file to copy to.")
+parser.add_argument("--inputs", dest="inputs", nargs="+", help="Small db's to load into main one.", required = True)
+args = parser.parse_args()
+
+try:
+    stats = ih.statistics.Stats(args.db)
+    stats.loadSql(args.inputs)
+    if (args.output):
+    	shutil.copyfile(args.db, args.output)
+    
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-stats-anova b/build/scripts-2.7/ih-stats-anova
new file mode 100755
index 0000000000000000000000000000000000000000..786d8c60bf6614d49d5672e2b11d7ed1423612cd
--- /dev/null
+++ b/build/scripts-2.7/ih-stats-anova
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.statistics
+import json
+
+parser = argparse.ArgumentParser(description = "Gathers shoot area information based on specified groupings.")
+parser.add_argument("--db", dest="db", help="Database to run statistics on.", required = True)
+parser.add_argument("--intable", dest="intable", help="Input table to gather data from.", required = True)
+parser.add_argument("--outtable", dest="outtable", help="Output table to write data to.", required = True)
+parser.add_argument("--group", dest="group", nargs="+", help="Image types to group by. Should be in json format.", required = True)
+parser.add_argument("--overwrite", dest="overwrite", action="store_true", help="If specified, will overwrite the output table.")
+args = parser.parse_args()
+
+stats = ih.statistics.Stats(args.db)
+stats.anova(args.intable, args.outtable, args.group, args.overwrite)
+stats._closeConnection()
diff --git a/build/scripts-2.7/ih-stats-correlate b/build/scripts-2.7/ih-stats-correlate
new file mode 100755
index 0000000000000000000000000000000000000000..6f7e5c9eba687e93e3b3d4744a7bac9b50a80b23
--- /dev/null
+++ b/build/scripts-2.7/ih-stats-correlate
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.statistics
+import json
+
+parser = argparse.ArgumentParser(description = "Gathers shoot area information based on specified groupings.")
+parser.add_argument("--db", dest="db", help="Database to run statistics on.", required = True)
+parser.add_argument("--intable", dest="intable", help="Input table to gather data from.", required = True)
+parser.add_argument("--outtable", dest="outtable", help="Output table to write data to.", required = True)
+parser.add_argument("--datafile", dest="datafile", help="LemanTec data file to correlate to.", required = True)
+parser.add_argument("--dataheaders", dest="dataheaders", help="Json header file.", required = True)
+parser.add_argument("--overwrite", dest="overwrite", action="store_true", help="If specified, will overwrite the output table.")
+args = parser.parse_args()
+
+with open(args.dataheaders, "r") as rh:
+    dataHeaders = json.load(rh)
+stats = ih.statistics.Stats(args.db)
+stats.correlation(args.intable, args.outtable, args.datafile, dataHeaders, args.overwrite)
+stats._closeConnection()
diff --git a/build/scripts-2.7/ih-stats-export b/build/scripts-2.7/ih-stats-export
new file mode 100755
index 0000000000000000000000000000000000000000..942bfc7448264311451f1325f6c563a325fe67b5
--- /dev/null
+++ b/build/scripts-2.7/ih-stats-export
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.statistics
+import json
+
+parser = argparse.ArgumentParser(description = "Export sqlite tables to csv.")
+parser.add_argument("--db", dest="db", help="Database to run statistics on.", required = True)
+parser.add_argument("--table", dest="table", help="Input table to write to a file.", required = True)
+parser.add_argument("--group", dest="group", nargs="+", help="Image types to extract.")
+parser.add_argument("--fname", dest="fname", help="File to write to, if unspecified, file will be written in the current directory with the specified table name.")
+args = parser.parse_args()
+
+try:
+    stats = ih.statistics.Stats(args.db)
+    stats.export(args.table, args.fname, group = args.group)
+    stats._closeConnection()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/ih-stats-histogram-bin b/build/scripts-2.7/ih-stats-histogram-bin
new file mode 100755
index 0000000000000000000000000000000000000000..b6c38e344d6a0f9508ff664eb5f24723d77b48e3
--- /dev/null
+++ b/build/scripts-2.7/ih-stats-histogram-bin
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.statistics
+import json
+
+parser = argparse.ArgumentParser(description = "Gathers shoot area information based on specified groupings.")
+parser.add_argument("--db", dest="db", help="Database to run statistics on.", required = True)
+parser.add_argument("--options", dest="options", help="Path to options json file.", required = True)
+parser.add_argument("--intable", dest="intable", help="Input table to gather data from.", required = True)
+parser.add_argument("--outtable", dest="outtable", help="Output table to write data to.", required = True)
+parser.add_argument("--jsonwrite", dest="jsonwrite", default = False, action="store_true", help="If specified, writes json output.")
+parser.add_argument("--overwrite", dest="overwrite", default = False, action="store_true", help="If specified, will overwrite the output table.")
+args = parser.parse_args()
+
+with open(args.options, "r") as rh:
+    options = json.load(rh)
+if "histogram-bin" in options:
+    stats = ih.statistics.Stats(args.db)
+    stats.histogramBinning(args.intable, args.outtable, options["histogram-bin"]["--group"], options["histogram-bin"]["--chunks"], options["histogram-bin"]["--channels"], args.jsonwrite, args.overwrite)
+    stats._closeConnection()
+else:
+    print "Key Error: key 'histogram-bin' must be in options file!"
diff --git a/build/scripts-2.7/ih-stats-normalize b/build/scripts-2.7/ih-stats-normalize
new file mode 100755
index 0000000000000000000000000000000000000000..d33ebe5ae0312f0ed06df9b05b7e1125b12cc0db
--- /dev/null
+++ b/build/scripts-2.7/ih-stats-normalize
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.statistics
+import json
+
+parser = argparse.ArgumentParser(description = "Gathers shoot area information based on specified groupings.")
+parser.add_argument("--db", dest="db", help="Database to run statistics on.", required = True)
+parser.add_argument("--intable", dest="intable", help="Input table to gather data from.", required = True)
+parser.add_argument("--outtable", dest="outtable", help="Output table to write data to.", required = True)
+parser.add_argument("--column", dest="column", help="Column to normalize numeric values to.", required = True)
+parser.add_argument("--overwrite", dest="overwrite", action="store_true", help="If specified, will overwrite the output table.")
+args = parser.parse_args()
+
+stats = ih.statistics.Stats(args.db)
+stats.normalize(args.intable, args.outtable, args.column, args.overwrite)
+stats._closeConnection()
\ No newline at end of file
diff --git a/build/scripts-2.7/ih-stats-shoot-area b/build/scripts-2.7/ih-stats-shoot-area
new file mode 100755
index 0000000000000000000000000000000000000000..8dacec95d7b2952375b82844576bf6d920037eef
--- /dev/null
+++ b/build/scripts-2.7/ih-stats-shoot-area
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.statistics
+import json
+
+parser = argparse.ArgumentParser(description = "Gathers shoot area information based on specified groupings.")
+parser.add_argument("--db", dest="db", help="Database to run statistics on.", required = True)
+parser.add_argument("--intable", dest="intable", help="Input table to gather data from.", required = True)
+parser.add_argument("--outtable", dest="outtable", help="Output table to write data to.", required = True)
+parser.add_argument("--group", dest="group", nargs="+", help="Image types to group by. Should be in json format.", required = True)
+parser.add_argument("--overwrite", dest="overwrite", action="store_true", help="If specified, will overwrite the output table.")
+args = parser.parse_args()
+
+stats = ih.statistics.Stats(args.db)
+stats.shootArea(args.intable, args.outtable, args.group, args.overwrite)
+stats._closeConnection()
diff --git a/build/scripts-2.7/ih-stats-threshold b/build/scripts-2.7/ih-stats-threshold
new file mode 100755
index 0000000000000000000000000000000000000000..4399cfb45370998cf192509297085e8f6307d77e
--- /dev/null
+++ b/build/scripts-2.7/ih-stats-threshold
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.statistics
+import json
+
+parser = argparse.ArgumentParser(description = "Gathers shoot area information based on specified groupings.")
+parser.add_argument("--db", dest="db", help="Database to run statistics on.", required = True)
+parser.add_argument("--intable", dest="intable", help="Input table to gather data from.", required = True)
+parser.add_argument("--outtable", dest="outtable", help="Output table to write data to.", required = True)
+parser.add_argument("--thresh", dest="thresh", type=float, help="Threhsold value.", required = True)
+parser.add_argument("--overwrite", dest="overwrite", action="store_true", help="If specified, will overwrite the output table.")
+args = parser.parse_args()
+
+stats = ih.statistics.Stats(args.db)
+stats.threshold(args.intable, args.outtable, args.thresh, args.overwrite)
+stats._closeConnection()
diff --git a/build/scripts-2.7/ih-stats-treatment-comp b/build/scripts-2.7/ih-stats-treatment-comp
new file mode 100755
index 0000000000000000000000000000000000000000..207d7e89496a0d2e660e4f32099860f40e1d33a0
--- /dev/null
+++ b/build/scripts-2.7/ih-stats-treatment-comp
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.statistics
+import json
+
+parser = argparse.ArgumentParser(description = "Gathers shoot area information based on specified groupings.")
+parser.add_argument("--db", dest="db", help="Database to run statistics on.", required = True)
+parser.add_argument("--intable", dest="intable", help="Input table to gather data from.", required = True)
+parser.add_argument("--outtable", dest="outtable", help="Output table to write data to.", required = True)
+parser.add_argument("--type", dest="type", default="ratio", help="Whether to perform division or subtraction between treatments.")
+paresr.add_argument("--direction", dest="direction", default="Control", help="Whether to perform C ~ S, or S ~ C.")
+parser.add_argument("--comp", dest="comp", default="imtype", help="Whether or not to use imtype or imgname as the primary comparison.")
+parser.add_argument("--overwrite", dest="overwrite", action="store_true", help="If specified, will overwrite the output table.")
+
+args = parser.parse_args()
+
+stats = ih.statistics.Stats(args.db)
+stats.treatmentComp(args.intable, args.outtable, args.type, args.direction, args.comp, args.overwrite)
+stats._closeConnection()
diff --git a/build/scripts-2.7/ih-stats-ttest b/build/scripts-2.7/ih-stats-ttest
new file mode 100755
index 0000000000000000000000000000000000000000..8120d5e583d02aaa184105b5175c1d8d11217cde
--- /dev/null
+++ b/build/scripts-2.7/ih-stats-ttest
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.statistics
+import json
+
+parser = argparse.ArgumentParser(description = "Gathers shoot area information based on specified groupings.")
+parser.add_argument("--db", dest="db", help="Database to run statistics on.", required = True)
+parser.add_argument("--intable", dest="intable", help="Input table to gather data from.", required = True)
+parser.add_argument("--outtable", dest="outtable", help="Output table to write data to.", required = True)
+parser.add_argument("--comp", dest="comp", default="imtype", help="Whether or not to use imtype or imgname as the primary comparison.")
+parser.add_argument("--overwrite", dest="overwrite", action="store_true", help="If specified, will overwrite the output table.")
+
+args = parser.parse_args()
+
+stats = ih.statistics.Stats(args.db)
+stats.ttest(args.intable, args.outtable, args.comp)
+stats.treatmentComp(args.intable, args.outtable, args.type, args.direction, args.comp, args.overwrite)
+stats._closeConnection()
\ No newline at end of file
diff --git a/build/scripts-2.7/ih-threshold b/build/scripts-2.7/ih-threshold
new file mode 100755
index 0000000000000000000000000000000000000000..64efb49e6223f71bb5c604fb6ea9211bc23e91c7
--- /dev/null
+++ b/build/scripts-2.7/ih-threshold
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+import argparse
+import traceback
+import ih.imgproc
+
+parser = argparse.ArgumentParser(description = "Converts an image between color spectrums.")
+parser.add_argument("--input", dest="input", help="Path to input image.", required = True)
+parser.add_argument("--thresh", dest="thresh", default=127, type=int, help="Threshold cutoff value.")
+parser.add_argument("--max", dest="max", default=255, type=int, help="Write value for binary threhsold")
+parser.add_argument("--type", dest="type", default="binary", help="Threshold type, one of: binary, trunc, tozero, otsu.")
+parser.add_argument("--outputdir", dest="outputdir", default=".", help="Path to write output files, if not specified use current directory.")
+parser.add_argument("--output", dest="output", default=None, help="Name of output image to write, if not specified, use input image name.")
+
+args = parser.parse_args()
+
+try:
+    plant = ih.imgproc.Image(args.input, args.outputdir, args.output, False)
+    plant.threshold(args.thresh, args.max, args.type)
+    plant.write()
+except Exception as e:
+    print traceback.format_exc()
diff --git a/build/scripts-2.7/osg-wrapper.sh b/build/scripts-2.7/osg-wrapper.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7de83c52bb1e06a7d00b0a18d68f8b3481d6170f
--- /dev/null
+++ b/build/scripts-2.7/osg-wrapper.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+source /cvmfs/oasis.opensciencegrid.org/osg/modules/lmod/5.6.2/init/bash
+
+module load python/2.7
+module load libgfortran
+module load lapack
+module load atlas
+module load hdf5/1.8.13
+module load netcdf/4.2.0
+module load gnome_libs
+module load ffmpeg/0.10.15
+module load opencv/2.4.10
+module load image_modules
+
+export PYTHONPATH=./ih-1.0/:$PYTHONPATH
+tar -zxf ih.tar.gz
+EXECUTABLE="$1"
+COMMAND="$@"
+### STAND BACK, BASH SCRIPTING ###
+while [[ $# > 1 ]]
+do
+key="$1"
+case $key in
+    --output)
+    OUTPUT="$2"
+    shift
+    ;;
+    *)
+            # unknown option
+    ;;
+esac
+shift
+done
+### Its safe now ###
+
+echo "Executable: $EXECUTABLE, Command: $COMMAND, Output: $OUTPUT"
+mkdir -p `dirname "$OUTPUT"`
+chmod 755 $EXECUTABLE
+eval $COMMAND
\ No newline at end of file
diff --git a/dist/ih-1.0.tar.gz b/dist/ih-1.0.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..3863ace6127ab481e59ad596dbf3028c451ac7cd
Binary files /dev/null and b/dist/ih-1.0.tar.gz differ
diff --git a/docs/build/doctrees/arkansas_workshop_july_2015.doctree b/docs/build/doctrees/arkansas_workshop_july_2015.doctree
new file mode 100644
index 0000000000000000000000000000000000000000..e3baa55d02069d28d031489afae525af145f3569
Binary files /dev/null and b/docs/build/doctrees/arkansas_workshop_july_2015.doctree differ
diff --git a/docs/build/doctrees/environment.pickle b/docs/build/doctrees/environment.pickle
index 6ba25b342d1e5e3ae96dd725d8e14a303af26d3e..c5d318c41ac5d99677f0c4397dfca9046e7c513c 100644
Binary files a/docs/build/doctrees/environment.pickle and b/docs/build/doctrees/environment.pickle differ
diff --git a/docs/build/doctrees/ex_workflow_1.doctree b/docs/build/doctrees/ex_workflow_1.doctree
index 79190f7bb13557f51d3e5fe609270d9e7718d6ed..6f311869411d1ba9ac3fcd8ebb342be0ca0191f5 100644
Binary files a/docs/build/doctrees/ex_workflow_1.doctree and b/docs/build/doctrees/ex_workflow_1.doctree differ
diff --git a/docs/build/doctrees/ex_workflow_2.doctree b/docs/build/doctrees/ex_workflow_2.doctree
new file mode 100644
index 0000000000000000000000000000000000000000..5f27cb48c373f00386fb755c6ac398b56e297c2b
Binary files /dev/null and b/docs/build/doctrees/ex_workflow_2.doctree differ
diff --git a/docs/build/doctrees/examples.doctree b/docs/build/doctrees/examples.doctree
index 1642d7c2efc872a6668f02012438beae48cc8354..cfd9ad89d9a389245819623da8f3b0d661b47b3d 100644
Binary files a/docs/build/doctrees/examples.doctree and b/docs/build/doctrees/examples.doctree differ
diff --git a/docs/build/doctrees/index.doctree b/docs/build/doctrees/index.doctree
index 93442fcd913282b843aed5b9ba2f9e337b62a41e..7412f3740eca77c73fc13b2f4dac8b2d3f2e3872 100644
Binary files a/docs/build/doctrees/index.doctree and b/docs/build/doctrees/index.doctree differ
diff --git a/docs/build/doctrees/installation.doctree b/docs/build/doctrees/installation.doctree
index 44a696cc91a07656994efe05460c9eb1a19ff5f8..4c988f0cd219bc4345865caa4751462c148a7391 100644
Binary files a/docs/build/doctrees/installation.doctree and b/docs/build/doctrees/installation.doctree differ
diff --git a/docs/build/doctrees/processing.doctree b/docs/build/doctrees/processing.doctree
index 7b412e6ac5a6d17ba3629c641c192ec4603addae..581b5dc2be5dec3be8f249b6fccff9ea3d27578d 100644
Binary files a/docs/build/doctrees/processing.doctree and b/docs/build/doctrees/processing.doctree differ
diff --git a/docs/build/doctrees/statistics.doctree b/docs/build/doctrees/statistics.doctree
index 989d58e52e355065ae6d3dad7f8104bdd4f76d19..3c50a55ece5a8de8f06a2f7ed4ee9604ac26de30 100644
Binary files a/docs/build/doctrees/statistics.doctree and b/docs/build/doctrees/statistics.doctree differ
diff --git a/docs/build/doctrees/viewer.doctree b/docs/build/doctrees/viewer.doctree
index a1e5dfd18750299b39743c43216159d08199c48b..c61ce75e3183a11d83407f04bd2f83d78a34cc1b 100644
Binary files a/docs/build/doctrees/viewer.doctree and b/docs/build/doctrees/viewer.doctree differ
diff --git a/docs/build/doctrees/workshops.doctree b/docs/build/doctrees/workshops.doctree
new file mode 100644
index 0000000000000000000000000000000000000000..cb690dae11d1c61d7bfc83564d85d97a7aced24d
Binary files /dev/null and b/docs/build/doctrees/workshops.doctree differ
diff --git a/docs/build/html/_downloads/0_0_2.png b/docs/build/html/_downloads/0_0_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..c1dda2e0e13c1d0a0400a492069185e1d9ec5663
Binary files /dev/null and b/docs/build/html/_downloads/0_0_2.png differ
diff --git a/docs/build/html/_downloads/config.json b/docs/build/html/_downloads/config.json
index 2dcae475e689e8863562757904203f1057eef1ff..aadc6ade8c38527b5f79f46bd8398d128df30b4a 100644
--- a/docs/build/html/_downloads/config.json
+++ b/docs/build/html/_downloads/config.json
@@ -1,25 +1,26 @@
 {
-        "installdir": "/work/walia/common/ih/pymodules/bin/",
-        "profile": {
-                "pegasus": {
-                        "style": "glite"
-                },
-                "condor": {
-                        "grid_resource": "pbs",
-                        "universe": "vanilla"
-                },
-                "env": {
-                        "PATH": "/work/walia/common/ih/pymodules/bin/",
-                        "LD_LIBRARY_PATH": "/work/walia/common/ih/pymodules/opencv_lib/"
-                }
+    "installdir": "/work/walia/common/ih/pymodules/bin/",
+    "profile": {
+        "pegasus": {
+            "style": "glite"
         },
-        "cluster": 100,
-        "maxwalltime": {
+        "condor": {
+          "grid_resource": "pbs",
+          "universe": "vanilla"
+        },
+        "env": {
+            "PATH": "/work/walia/common/ih/pymodules/bin/",
+            "PYTHONPATH": "/work/walia/common/ih/pymodules/lib/python2.6/site-packages",
+            "LD_LIBRARY_PATH": "/work/walia/common/ih/pymodules/opencv_lib/"
+        }
+      },
+      "cluster": 100,
+      "maxwalltime": {
         	"images": 2,
         	"stats": 300
-        },
-        "notify": {
+      },
+      "notify": {
         	"email": "avi@kurtknecht.com",
         	"pegasus_home": "/usr/share/pegasus/"
-        }
+      }
 }
diff --git a/docs/build/html/_downloads/config1.json b/docs/build/html/_downloads/config1.json
new file mode 100644
index 0000000000000000000000000000000000000000..faaa1c37349864e20c5d13f4d2ee2e531a0e7d65
--- /dev/null
+++ b/docs/build/html/_downloads/config1.json
@@ -0,0 +1,28 @@
+{
+        "version": "1.0",
+        "installdir": "/home/aknecht/stash/walia/ih/ih/build/scripts-2.7/",
+        "profile": {
+                "pegasus": {
+                        "style": "condor"
+                },
+                "condor": {
+                        "universe": "vanilla",
+                        "requirements": "OSGVO_OS_STRING == \"RHEL 6\" &amp;&amp; HAS_FILE_usr_lib64_libstdc___so_6 &amp;&amp; CVMFS_oasis_opensciencegrid_org_REVISION >= 3590",
+                        "+WantsStashCache": "True",
+                        "+ProjectName": "RicePhenomics"
+                }
+        },
+        "osg": {
+                "tarball": "/home/aknecht/stash/walia/ih/ih/dist/ih-1.0.tar.gz",
+                "ssh": "/home/aknecht/.ssh/workflow"
+        },
+        "cluster": 80,
+        "maxwalltime": {
+                "stats": 300,
+                "images": 2
+        },
+        "notify": {
+                "email": "avi@kurtknecht.com",
+                "pegasus_home": "/usr/share/pegasus/"
+        }
+}
diff --git a/docs/build/html/_downloads/firstimage.py b/docs/build/html/_downloads/firstimage.py
new file mode 100644
index 0000000000000000000000000000000000000000..1856ad6e22c07480c3d8fdab42b471a307e5d603
--- /dev/null
+++ b/docs/build/html/_downloads/firstimage.py
@@ -0,0 +1,31 @@
+# Load the library & image
+import ih.imgproc
+plant = ih.imgproc.Image("/path/to/your/image")
+# Save & show the base image
+plant.save("base")
+plant.show("Base")
+# Convert to gray, save the image
+plant.convertColor("bgr", "gray")
+plant.save("gray")
+plant.show("Grayscale")
+# Threshold the image incorrectly AND correctly
+plant.threshold(255)
+plant.show("Threshold 255")
+plant.restore("gray")
+plant.threshold(190)
+plant.save("binary")
+plant.show("Threshold 190")
+# Recolor the image
+plant.bitwise_not()
+plant.convertColor("gray", "bgr")
+plant.bitwise_and("base")
+plant.save("recolor")
+plant.show("Recolored Image")
+# Crop the image, produce the final output
+plant.crop([300, 2150, 0, "x"])
+plant.save("cropped")
+plant.show("Cropped")
+plant.contourCut("cropped", resize = True)
+plant.show("Final")
+plant.write("final.png")
+plant.wait()
diff --git a/docs/build/html/_downloads/pipeline.py b/docs/build/html/_downloads/pipeline.py
new file mode 100644
index 0000000000000000000000000000000000000000..bf20c7f5fbb136b78eac73e7896cf42805e8d19a
--- /dev/null
+++ b/docs/build/html/_downloads/pipeline.py
@@ -0,0 +1,40 @@
+import ih.imgproc
+
+# base plant
+plant = ih.imgproc.Image("0_0_2.png")
+plant.save("base")
+plant.show("base")
+
+# blur
+plant.blur((5, 5))
+plant.save("blur")
+plant.show("Blur")
+
+# meanshift
+plant.meanshift(4, 4, 40)
+plant.save("shift")
+plant.show("Meanshift")
+
+# colorFilter
+plant.colorFilter("(((g > r) and (g > b)) and (((r + g) + b) < 400))")
+plant.colorFilter("(((r max g) max b) - ((r min g) min b)) > 12)")
+plant.save("cf")
+plant.show("Color filter")
+
+# contourCut
+plant.contourCut("cf", basemin = 3000, resize = True)
+plant.save("cut")
+plant.show("Contour Cut")
+
+# recolor
+plant.convertColor("bgr", "gray")
+plant.threshold(0)
+plant.convertColor("gray", "bgr")
+plant.bitwise_and("base")
+plant.write("final.png")
+plant.show("Final")
+
+print plant.extractPixels()
+print plant.extractConvexHull()
+
+plant.wait()
diff --git a/docs/build/html/_downloads/rgbsv1.png b/docs/build/html/_downloads/rgbsv1.png
new file mode 100644
index 0000000000000000000000000000000000000000..7238c6a4f41bcfd565b8e22c0deedab91d9902b7
Binary files /dev/null and b/docs/build/html/_downloads/rgbsv1.png differ
diff --git a/docs/build/html/_images/cropped.png b/docs/build/html/_images/cropped.png
new file mode 100644
index 0000000000000000000000000000000000000000..d8b7770a6153a85df92d04e4316a0e7c4c1cdf1a
Binary files /dev/null and b/docs/build/html/_images/cropped.png differ
diff --git a/docs/build/html/_images/final1.png b/docs/build/html/_images/final1.png
new file mode 100644
index 0000000000000000000000000000000000000000..76481ef73a77a8dc9350d41a517ced606f7950dd
Binary files /dev/null and b/docs/build/html/_images/final1.png differ
diff --git a/docs/build/html/_images/inverted.png b/docs/build/html/_images/inverted.png
new file mode 100644
index 0000000000000000000000000000000000000000..081e5ca8d7659300ba52801ce2d26e6ae57670b8
Binary files /dev/null and b/docs/build/html/_images/inverted.png differ
diff --git a/docs/build/html/_images/recolored.png b/docs/build/html/_images/recolored.png
new file mode 100644
index 0000000000000000000000000000000000000000..c84f5e8fdd760163a14fed531826b8a4e0749f1c
Binary files /dev/null and b/docs/build/html/_images/recolored.png differ
diff --git a/docs/build/html/_images/shifted.png b/docs/build/html/_images/shifted.png
new file mode 100644
index 0000000000000000000000000000000000000000..37362bd7d4e7435d0348d01ecd76c7fbd8e27f51
Binary files /dev/null and b/docs/build/html/_images/shifted.png differ
diff --git a/docs/build/html/_modules/htpia/imgproc.html b/docs/build/html/_modules/htpia/imgproc.html
index d5444314aa73af074e12918a0abdfb2c549e4a1b..8dd87e24bc9be4b6523c2e8bd250208737b420b4 100644
--- a/docs/build/html/_modules/htpia/imgproc.html
+++ b/docs/build/html/_modules/htpia/imgproc.html
@@ -74,6 +74,8 @@
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/_modules/htpia/statistics.html b/docs/build/html/_modules/htpia/statistics.html
index 86db4c82a4feb725b2c190874e3a52c63a912192..6bb239251d68824ef2fd7cede3d3514fcc73a2a2 100644
--- a/docs/build/html/_modules/htpia/statistics.html
+++ b/docs/build/html/_modules/htpia/statistics.html
@@ -74,6 +74,8 @@
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/_modules/htpia/workflow.html b/docs/build/html/_modules/htpia/workflow.html
index 013ce59fdc1d89743c2c5e3d9df9d2f331b23c1f..aceeacaeb920664f9788a6aa5c0a7ae4b989a6e1 100644
--- a/docs/build/html/_modules/htpia/workflow.html
+++ b/docs/build/html/_modules/htpia/workflow.html
@@ -74,6 +74,8 @@
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/_modules/ih/imgproc.html b/docs/build/html/_modules/ih/imgproc.html
index f4f4fe5971afe6f0ac56ff1d660011a446dfdf93..18b3ba831c82dc7e3190b11e1142e06ea43636fd 100644
--- a/docs/build/html/_modules/ih/imgproc.html
+++ b/docs/build/html/_modules/ih/imgproc.html
@@ -74,6 +74,8 @@
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../viewer.html">Image Processing Viewer</a></li>
@@ -338,6 +340,12 @@
                 <span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">left</span><span class="p">)</span> <span class="o">+</span> <span class="nb">int</span><span class="p">(</span><span class="n">right</span><span class="p">)</span>
             <span class="k">except</span><span class="p">:</span>
                 <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s">&quot;Could not load roi arg &#39;</span><span class="si">%s</span><span class="s">&#39;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">arg</span><span class="p">,))</span>
+        <span class="k">elif</span> <span class="s">&quot;/&quot;</span> <span class="ow">in</span> <span class="n">arg</span><span class="p">:</span>
+            <span class="k">try</span><span class="p">:</span>
+                <span class="n">left</span><span class="p">,</span> <span class="n">right</span> <span class="o">=</span> <span class="n">arg</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">)</span>
+                <span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">left</span><span class="p">)</span> <span class="o">/</span> <span class="nb">int</span><span class="p">(</span><span class="n">right</span><span class="p">)</span>
+            <span class="k">except</span><span class="p">:</span>
+                <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s">&quot;Could not load roi arg &#39;</span><span class="si">%s</span><span class="s">&#39;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">arg</span><span class="p">,))</span>
         <span class="k">else</span><span class="p">:</span>
             <span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
     
@@ -433,6 +441,21 @@
                 <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s">&quot;Input path to resource does not exist.&quot;</span><span class="p">)</span>
         <span class="k">return</span>
     
+    <span class="k">def</span> <span class="nf">_getMergedContour</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+        <span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">        Assumes that image is already binary</span>
+<span class="sd">        &quot;&quot;&quot;</span>
+        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_isColor</span><span class="p">():</span>
+            <span class="n">binary</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">inRange</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">copy</span><span class="p">(),</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">np</span><span class="o">.</span><span class="n">uint8</span><span class="p">),</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">],</span> <span class="n">np</span><span class="o">.</span><span class="n">uint8</span><span class="p">))</span>
+        <span class="k">else</span><span class="p">:</span>
+            <span class="n">binary</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
+        <span class="n">contours</span><span class="p">,</span><span class="n">hierarchy</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">findContours</span><span class="p">(</span><span class="n">binary</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
+        <span class="n">merged</span> <span class="o">=</span> <span class="p">[]</span>
+        <span class="k">for</span> <span class="n">cnt</span> <span class="ow">in</span> <span class="n">contours</span><span class="p">:</span>
+            <span class="k">for</span> <span class="n">point</span> <span class="ow">in</span> <span class="n">cnt</span><span class="p">:</span>
+                <span class="n">merged</span><span class="o">.</span><span class="n">append</span><span class="p">([</span><span class="n">point</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span> <span class="n">point</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">1</span><span class="p">]])</span>
+        <span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">merged</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">np</span><span class="o">.</span><span class="n">int32</span><span class="p">)</span>
+    
     <span class="k">def</span> <span class="nf">_colorHistogram</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
         <span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">        :return: A list of histograms, corresponding to R, G, B.</span>
@@ -505,7 +528,7 @@
         <span class="bp">self</span><span class="o">.</span><span class="n">destroy</span><span class="p">()</span>
         <span class="k">return</span>
     </div>
-<div class="viewcode-block" id="Image.show"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.show">[docs]</a>    <span class="k">def</span> <span class="nf">show</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">title</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
+<div class="viewcode-block" id="Image.show"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.show">[docs]</a>    <span class="k">def</span> <span class="nf">show</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">title</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">state</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
         <span class="sd">&quot;&quot;&quot; </span>
 <span class="sd">            :param title: The title to give the display window, if left blank one will be created.</span>
 <span class="sd">            :type title: str</span>
@@ -516,7 +539,7 @@
 <span class="sd">            show has been called.</span>
 <span class="sd">            </span>
 <span class="sd">        &quot;&quot;&quot;</span>
-        <span class="n">cv2</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">title</span> <span class="k">if</span> <span class="n">title</span> <span class="k">else</span> <span class="s">&quot;window &quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">window</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">resize</span><span class="p">())</span>
+        <span class="n">cv2</span><span class="o">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">title</span> <span class="k">if</span> <span class="n">title</span> <span class="k">else</span> <span class="s">&quot;window &quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">window</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">resize</span><span class="p">(</span><span class="n">state</span><span class="p">))</span>
         <span class="bp">self</span><span class="o">.</span><span class="n">window</span> <span class="o">+=</span> <span class="mi">1</span>
         <span class="k">return</span>
     </div>
@@ -549,13 +572,18 @@
             <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
         <span class="k">return</span>
     </div>
-<div class="viewcode-block" id="Image.resize"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.resize">[docs]</a>    <span class="k">def</span> <span class="nf">resize</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+<div class="viewcode-block" id="Image.resize"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.resize">[docs]</a>    <span class="k">def</span> <span class="nf">resize</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
         <span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">        If the image is large than conf.maxArea, resize its total area down to conf.maxArea.</span>
 <span class="sd">        This function is primarily used for viewing purposes, and as such, it does not resize</span>
 <span class="sd">        the base image, but creates a copy to resize instead.</span>
 <span class="sd">        &quot;&quot;&quot;</span>
-        <span class="k">if</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">conf</span><span class="o">.</span><span class="n">maxArea</span><span class="p">):</span>
+        <span class="k">if</span> <span class="p">(</span><span class="n">state</span><span class="p">):</span>
+          <span class="n">im</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">states</span><span class="p">[</span><span class="n">state</span><span class="p">]</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
+          <span class="k">if</span> <span class="p">(</span><span class="n">im</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">im</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">conf</span><span class="o">.</span><span class="n">maxArea</span><span class="p">):</span>
+              <span class="n">scale</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">((</span><span class="n">im</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">im</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">/</span> <span class="n">conf</span><span class="o">.</span><span class="n">maxArea</span><span class="p">)</span>
+              <span class="k">return</span> <span class="n">cv2</span><span class="o">.</span><span class="n">resize</span><span class="p">(</span><span class="n">im</span><span class="p">,</span> <span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">im</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">scale</span><span class="p">),</span> <span class="nb">int</span><span class="p">(</span><span class="n">im</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">scale</span><span class="p">)))</span>
+        <span class="k">elif</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">conf</span><span class="o">.</span><span class="n">maxArea</span><span class="p">):</span>
             <span class="n">scale</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="n">math</span><span class="o">.</span><span class="n">sqrt</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">/</span> <span class="n">conf</span><span class="o">.</span><span class="n">maxArea</span><span class="p">)</span>
             <span class="k">return</span> <span class="n">cv2</span><span class="o">.</span><span class="n">resize</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">copy</span><span class="p">(),</span> <span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="o">*</span><span class="n">scale</span><span class="p">),</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">y</span><span class="o">*</span><span class="n">scale</span><span class="p">)))</span>
         <span class="k">else</span><span class="p">:</span>
@@ -619,7 +647,62 @@
             <span class="k">raise</span> <span class="ne">KeyError</span><span class="p">(</span><span class="nb">type</span> <span class="o">+</span> <span class="s">&quot; is not a valid threshold type.&quot;</span><span class="p">)</span>
         <span class="k">return</span>
     </div>
-<div class="viewcode-block" id="Image.kmeans"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.kmeans">[docs]</a>    <span class="k">def</span> <span class="nf">kmeans</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">criteria</span><span class="p">,</span> <span class="n">maxiter</span> <span class="o">=</span> <span class="mi">10</span><span class="p">,</span> <span class="n">accuracy</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="n">attempts</span> <span class="o">=</span> <span class="mi">10</span><span class="p">,</span> <span class="n">flags</span> <span class="o">=</span> <span class="s">&quot;random&quot;</span><span class="p">):</span>
+<div class="viewcode-block" id="Image.knn"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.knn">[docs]</a>    <span class="k">def</span> <span class="nf">knn</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">labels</span><span class="p">,</span> <span class="n">remove</span> <span class="o">=</span> <span class="p">[]):</span>
+        <span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">        :param k: Number of nearest neighbors to use</span>
+<span class="sd">        :type k: int</span>
+<span class="sd">        :param labels: Path to label file.  More info below</span>
+<span class="sd">        :type labels: file</span>
+<span class="sd">        :param remove: Labels to remove from final image.</span>
+<span class="sd">        :type remove: list</span>
+<span class="sd">        </span>
+<span class="sd">        This function is a wrapper to the OpenCV function `KNearest &lt;http://docs.opencv.org/modules/ml/doc/k_nearest_neighbors.html&gt;`_.</span>
+<span class="sd">        The label file should contain training data in json format, using the label name of keys, and all </span>
+<span class="sd">        the colors matching that label as an array value.  Each color should be a list of 3 values, in BGR order.  That is:</span>
+<span class="sd">	</span>
+<span class="sd">	.. code-block:: python</span>
+
+<span class="sd">		{</span>
+<span class="sd">		    &quot;plant&quot;: [</span>
+<span class="sd">			[234, 125, 100],</span>
+<span class="sd">			[100, 100, 100]</span>
+<span class="sd">		    ],</span>
+<span class="sd">		    &quot;pot&quot;: [</span>
+<span class="sd">		    ...</span>
+<span class="sd">		}</span>
+
+<span class="sd">        When creating your label file, make sure to use helpful names.  Calling each set of colors &quot;label1&quot;, &quot;label2&quot; e.t.c</span>
+<span class="sd">        provides no meaningful information.  The remove list is the list of matched labels to remove from the final image.</span>
+<span class="sd">        The names to remove should match the names in your label file exactly. For example, let&#39;s say you have the labels</span>
+<span class="sd">	&quot;plant&quot;, &quot;pot&quot;, &quot;track&quot;, and &quot;background&quot; defined, and you only want to keep pixels that match the &quot;plant&quot; label.</span>
+<span class="sd">	Your remove list should be specified as [&quot;pot&quot;, &quot;track&quot;, &quot;background&quot;].</span>
+<span class="sd">        &quot;&quot;&quot;</span>
+        <span class="k">if</span> <span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">labels</span><span class="p">)):</span>
+            <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">labels</span><span class="p">,</span> <span class="s">&quot;r&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">rh</span><span class="p">:</span>
+                <span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">rh</span><span class="p">)</span>
+                <span class="n">labelMap</span> <span class="o">=</span> <span class="p">[]</span>
+                <span class="n">trainData</span> <span class="o">=</span> <span class="p">[]</span>
+                <span class="n">response</span> <span class="o">=</span> <span class="p">[]</span>
+                <span class="k">for</span> <span class="n">index</span><span class="p">,</span><span class="n">key</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">keys</span><span class="p">()):</span>
+                     <span class="n">labelMap</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
+                     <span class="k">for</span> <span class="n">color</span> <span class="ow">in</span> <span class="n">data</span><span class="p">[</span><span class="n">key</span><span class="p">]:</span>
+                         <span class="n">trainData</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">color</span><span class="p">)</span>
+                         <span class="n">response</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">index</span><span class="p">)</span>
+                <span class="n">trainData</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">trainData</span><span class="p">,</span> <span class="n">dtype</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">float32</span><span class="p">)</span>
+                <span class="n">response</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>
+                <span class="n">knn</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">KNearest</span><span class="p">()</span>
+                <span class="n">knn</span><span class="o">.</span><span class="n">train</span><span class="p">(</span><span class="n">trainData</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span>
+                <span class="n">fim</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span><span class="o">.</span><span class="n">reshape</span><span class="p">((</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span><span class="o">.</span><span class="n">astype</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">float32</span><span class="p">)</span>
+                <span class="n">ret</span><span class="p">,</span> <span class="n">results</span><span class="p">,</span> <span class="n">neighbors</span><span class="p">,</span> <span class="n">dist</span> <span class="o">=</span> <span class="n">knn</span><span class="o">.</span><span class="n">find_nearest</span><span class="p">(</span><span class="n">fim</span><span class="p">,</span> <span class="n">k</span><span class="p">)</span>
+                <span class="n">ires</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">in1d</span><span class="p">(</span><span class="n">results</span><span class="o">.</span><span class="n">ravel</span><span class="p">(),</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span><span class="n">x</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">labelMap</span><span class="p">)</span> <span class="k">if</span> <span class="n">x</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">remove</span><span class="p">])</span>
+                <span class="n">final</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">cvtColor</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">ires</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">astype</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">uint8</span><span class="p">)</span><span class="o">.</span><span class="n">reshape</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">))</span><span class="o">.</span><span class="n">astype</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">uint8</span><span class="p">),</span> <span class="n">cv2</span><span class="o">.</span><span class="n">COLOR_GRAY2BGR</span><span class="p">)</span>
+                <span class="bp">self</span><span class="o">.</span><span class="n">bitwise_and</span><span class="p">(</span><span class="n">final</span><span class="p">)</span>
+        <span class="k">else</span><span class="p">:</span>
+            <span class="k">print</span> <span class="s">&quot;Cannot find label file.&quot;</span>
+        <span class="k">return</span>
+                                
+    </div>
+<div class="viewcode-block" id="Image.kmeans"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.kmeans">[docs]</a>    <span class="k">def</span> <span class="nf">kmeans</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">criteria</span><span class="p">,</span> <span class="n">maxiter</span> <span class="o">=</span> <span class="mi">10</span><span class="p">,</span> <span class="n">accuracy</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">,</span> <span class="n">attempts</span> <span class="o">=</span> <span class="mi">10</span><span class="p">,</span> <span class="n">flags</span> <span class="o">=</span> <span class="s">&quot;random&quot;</span><span class="p">,</span> <span class="n">labels</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
         <span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">        :param k: Number of colors in final image.</span>
 <span class="sd">        :type k: int</span>
@@ -647,7 +730,7 @@
             <span class="k">if</span> <span class="n">criteria</span> <span class="ow">in</span> <span class="n">conf</span><span class="o">.</span><span class="n">ktermination</span><span class="p">:</span>
                 <span class="n">reshaped</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">reshape</span><span class="p">((</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="mi">3</span><span class="p">))</span>
                 <span class="n">reshaped</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">float32</span><span class="p">(</span><span class="n">reshaped</span><span class="p">)</span>
-                <span class="n">ret</span><span class="p">,</span> <span class="n">label</span><span class="p">,</span> <span class="n">center</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">kmeans</span><span class="p">(</span><span class="n">reshaped</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="p">(</span><span class="n">conf</span><span class="o">.</span><span class="n">ktermination</span><span class="p">[</span><span class="n">criteria</span><span class="p">],</span> <span class="n">maxiter</span><span class="p">,</span> <span class="n">accuracy</span><span class="p">),</span> <span class="n">attempts</span><span class="p">,</span> <span class="n">conf</span><span class="o">.</span><span class="n">centers</span><span class="p">[</span><span class="n">flags</span><span class="p">])</span>
+                <span class="n">ret</span><span class="p">,</span> <span class="n">label</span><span class="p">,</span> <span class="n">center</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">kmeans</span><span class="p">(</span><span class="n">reshaped</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="p">(</span><span class="n">conf</span><span class="o">.</span><span class="n">ktermination</span><span class="p">[</span><span class="n">criteria</span><span class="p">],</span> <span class="n">maxiter</span><span class="p">,</span> <span class="n">accuracy</span><span class="p">),</span> <span class="n">attempts</span><span class="p">,</span> <span class="n">conf</span><span class="o">.</span><span class="n">centers</span><span class="p">[</span><span class="n">flags</span><span class="p">],</span> <span class="n">bestLabels</span> <span class="o">=</span> <span class="n">labels</span><span class="p">)</span>
                 <span class="n">center</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">uint8</span><span class="p">(</span><span class="n">center</span><span class="p">)</span>
                 <span class="n">res</span> <span class="o">=</span> <span class="n">center</span><span class="p">[</span><span class="n">label</span><span class="o">.</span><span class="n">flatten</span><span class="p">()]</span>
                 <span class="bp">self</span><span class="o">.</span><span class="n">image</span> <span class="o">=</span> <span class="n">res</span><span class="o">.</span><span class="n">reshape</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">shape</span><span class="p">))</span>
@@ -661,9 +744,9 @@
 <div class="viewcode-block" id="Image.meanshift"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.meanshift">[docs]</a>    <span class="k">def</span> <span class="nf">meanshift</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">spatial_radius</span><span class="p">,</span> <span class="n">range_radius</span><span class="p">,</span> <span class="n">min_density</span><span class="p">):</span>
         <span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">        :param spatial_radius: Spatial Radius</span>
-<span class="sd">        :type spatial_radius: float</span>
+<span class="sd">        :type spatial_radius: int</span>
 <span class="sd">        :param range_radius: Range Radius.</span>
-<span class="sd">        :type range_radius: float</span>
+<span class="sd">        :type range_radius: int</span>
 <span class="sd">        :param min_density: Minimum Density.</span>
 <span class="sd">        :type min_density: int</span>
 <span class="sd">        :return: The mean-shifted image.</span>
@@ -840,6 +923,19 @@
             <span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="n">maxy</span><span class="p">,</span> <span class="n">xend</span><span class="p">:</span><span class="n">maxx</span><span class="p">]</span> <span class="o">=</span> <span class="n">off</span>
         <span class="k">return</span>
     </div>
+<div class="viewcode-block" id="Image.mask"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.mask">[docs]</a>    <span class="k">def</span> <span class="nf">mask</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+        <span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">        This function convers the image to a color mask by performing the following operations:</span>
+<span class="sd">        * :py:meth:`~ih.imgproc.Image.convertColor(&quot;bgr&quot;, &quot;gray&quot;)`</span>
+<span class="sd">        * :py:meth:`~ih.imgproc.Image.threshold(0)</span>
+<span class="sd">        * :py:meth:`~ih.imgproc.Image.convertColor(&quot;gray&quot;, &quot;bgr&quot;)</span>
+<span class="sd">        &quot;&quot;&quot;</span>
+        <span class="bp">self</span><span class="o">.</span><span class="n">convertColor</span><span class="p">(</span><span class="s">&quot;bgr&quot;</span><span class="p">,</span> <span class="s">&quot;gray&quot;</span><span class="p">)</span>
+        <span class="bp">self</span><span class="o">.</span><span class="n">threshold</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+        <span class="bp">self</span><span class="o">.</span><span class="n">convertColor</span><span class="p">(</span><span class="s">&quot;gray&quot;</span><span class="p">,</span> <span class="s">&quot;bgr&quot;</span><span class="p">)</span>
+        <span class="k">return</span>
+            
+    </div>
 <div class="viewcode-block" id="Image.contourCut"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.contourCut">[docs]</a>    <span class="k">def</span> <span class="nf">contourCut</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">binary</span><span class="p">,</span> <span class="n">basemin</span> <span class="o">=</span> <span class="mi">100</span><span class="p">,</span> <span class="n">padding</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">resize</span> <span class="o">=</span> <span class="bp">False</span><span class="p">,</span> <span class="n">returnBound</span> <span class="o">=</span> <span class="bp">False</span><span class="p">,</span> <span class="n">roiwrite</span> <span class="o">=</span> <span class="s">&quot;roi.json&quot;</span><span class="p">):</span>
         <span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">        :param binary: The binary image to find contours of.</span>
@@ -914,8 +1010,7 @@
 <span class="sd">        :type roi: list or roi file</span>
 <span class="sd">        </span>
 <span class="sd">        This function applies a color filter defined by the input logic, to a</span>
-<span class="sd">        targeted region defined by the input roi.  The roi is defined the same,</span>
-<span class="sd">        [ystart, yend, xstart, xend].  The logic string itself is fairly complicated.</span>
+<span class="sd">        targeted region defined by the input roi. The logic string itself is fairly complicated.</span>
 <span class="sd">        The string supports the following characters: &#39;+&#39;, &#39;-&#39;, &#39;*&#39;, &#39;/&#39;, &#39;&gt;&#39;, &#39;&gt;=&#39;,</span>
 <span class="sd">        &#39;==&#39;, &#39;&lt;&#39;, &#39;&lt;=&#39;, &#39;and&#39;, &#39;or&#39;, &#39;(&#39;, &#39;)&#39;, &#39;r&#39;, &#39;g&#39;, &#39;b&#39;, &#39;max&#39;, and &#39;min&#39; as well as any numeric</span>
 <span class="sd">        value.  The logic string itself must be well formed -- each </span>
@@ -1055,6 +1150,48 @@
             <span class="k">return</span>
         <span class="k">else</span><span class="p">:</span>
             <span class="k">return</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">]</span>
+        </div>
+<div class="viewcode-block" id="Image.extractMinEnclosingCircle"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.extractMinEnclosingCircle">[docs]</a>    <span class="k">def</span> <span class="nf">extractMinEnclosingCircle</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+        <span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">        :return: The center, and radius of the minimum enclosing circle.</span>
+<span class="sd">        :rtype: int</span>
+<span class="sd">        </span>
+<span class="sd">        Returns the center and radius of the minimum enclosing circle of all</span>
+<span class="sd">        non-black pixels in the image.  The point of this function</span>
+<span class="sd">        is not to threshold, so the contours are generated from</span>
+<span class="sd">        all the pixels that fall into the range [1, 1, 1], [255, 255, 255].</span>
+<span class="sd">        &quot;&quot;&quot;</span>
+        <span class="n">circle</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">minEnclosingCircle</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_getMergedContour</span><span class="p">())</span>
+        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">conn</span><span class="p">:</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">_addColumn</span><span class="p">(</span><span class="s">&quot;circle_centerx&quot;</span><span class="p">)</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">_addColumn</span><span class="p">(</span><span class="s">&quot;circle_centery&quot;</span><span class="p">)</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">_addColumn</span><span class="p">(</span><span class="s">&quot;circle_radius&quot;</span><span class="p">)</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;update images set circle_centerx=?, circle_centery=?, circle_radius=? where pegasusid=?&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">circle</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span> <span class="n">circle</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">1</span><span class="p">],</span> <span class="n">circle</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">dbid</span><span class="p">))</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
+        <span class="k">else</span><span class="p">:</span>
+            <span class="k">return</span> <span class="n">circle</span>
+        </div>
+<div class="viewcode-block" id="Image.extractConvexHull"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.extractConvexHull">[docs]</a>    <span class="k">def</span> <span class="nf">extractConvexHull</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+        <span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">        :return: The area of the convex hull.</span>
+<span class="sd">        :rtype: int</span>
+<span class="sd">        </span>
+<span class="sd">        Returns the area of the convex hull around all non black pixels in the image.</span>
+<span class="sd">        The point of this function is not to threshold, so the contours are generate from</span>
+<span class="sd">        all the pixels that fall into the range [1, 1, 1], [255, 255, 255]</span>
+<span class="sd">        &quot;&quot;&quot;</span>
+        <span class="n">hull</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">contourArea</span><span class="p">(</span>
+                 <span class="n">cv2</span><span class="o">.</span><span class="n">approxPolyDP</span><span class="p">(</span>
+                    <span class="n">cv2</span><span class="o">.</span><span class="n">convexHull</span><span class="p">(</span>
+                        <span class="bp">self</span><span class="o">.</span><span class="n">_getMergedContour</span><span class="p">()</span>
+                    <span class="p">),</span> <span class="mf">0.001</span><span class="p">,</span> <span class="bp">True</span>
+                <span class="p">))</span>
+        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">conn</span><span class="p">:</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">_addColumn</span><span class="p">(</span><span class="s">&quot;convex_hull_area&quot;</span><span class="p">)</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;update images set convex_hull_area=? where pegasusid=?&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">hull</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">dbid</span><span class="p">))</span> 
+            <span class="bp">self</span><span class="o">.</span><span class="n">conn</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
+        <span class="k">else</span><span class="p">:</span>
+            <span class="k">return</span> <span class="n">hull</span>
     </div>
 <div class="viewcode-block" id="Image.extractPixels"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.extractPixels">[docs]</a>    <span class="k">def</span> <span class="nf">extractPixels</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
         <span class="sd">&quot;&quot;&quot;</span>
@@ -1089,6 +1226,8 @@
 <span class="sd">        this: [ [BlueMean, BlueMedian], [GreenMean, GreenMedian], [RedMean, RedMedian] ].</span>
 <span class="sd">        Mean values always come before median values.  If nonzero is set to true (default)</span>
 <span class="sd">        the function will only calculate mediapytn and means based on the non-black pixels.</span>
+<span class="sd">	If you are connected to a database, the entire histogram is saved to the database,</span>
+<span class="sd">	not just the mean and median.</span>
 <span class="sd">        &quot;&quot;&quot;</span>
         <span class="n">hist</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_colorHistogram</span><span class="p">()</span>
         <span class="k">if</span> <span class="n">returnhist</span><span class="p">:</span>
@@ -1119,7 +1258,10 @@
         <span class="k">else</span><span class="p">:</span>
             <span class="k">return</span> <span class="n">colors</span>
         </div>
-    <span class="k">def</span> <span class="nf">extractColorChannels</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+<div class="viewcode-block" id="Image.extractColorChannels"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.extractColorChannels">[docs]</a>    <span class="k">def</span> <span class="nf">extractColorChannels</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+	<span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">	This function is similar to the </span>
+<span class="sd">	&quot;&quot;&quot;</span>
         <span class="n">b</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">image</span><span class="p">)</span>
         <span class="n">bdata</span><span class="p">,</span> <span class="n">gdata</span><span class="p">,</span> <span class="n">rdata</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[],</span> <span class="p">[]</span>
         <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">256</span><span class="p">):</span>
@@ -1145,7 +1287,7 @@
             <span class="k">return</span>
         <span class="k">else</span><span class="p">:</span>
             <span class="k">return</span> <span class="p">(</span><span class="n">bdata</span><span class="p">,</span> <span class="n">gdata</span><span class="p">,</span> <span class="n">rdata</span><span class="p">)</span>
-        
+        </div>
 <div class="viewcode-block" id="Image.extractBins"><a class="viewcode-back" href="../../processing.html#ih.imgproc.Image.extractBins">[docs]</a>    <span class="k">def</span> <span class="nf">extractBins</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">binlist</span><span class="p">):</span>
         <span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">        :param binlist: The specified bins (color ranges) to count.</span>
diff --git a/docs/build/html/_modules/ih/statistics.html b/docs/build/html/_modules/ih/statistics.html
index 7e3beec6cb913f916b90f6c37f8a2c2dc1b326fa..e742cebae5a1b5894b620d79f290f54cad2d7a20 100644
--- a/docs/build/html/_modules/ih/statistics.html
+++ b/docs/build/html/_modules/ih/statistics.html
@@ -74,6 +74,8 @@
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../viewer.html">Image Processing Viewer</a></li>
@@ -128,6 +130,22 @@
     <div class="col-md-12">
       
   <h1>Source code for ih.statistics</h1><div class="highlight"><pre>
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">This file is part of Image Harvest.</span>
+
+<span class="sd">Image Harvest is free software: you can redistribute it and/or modify</span>
+<span class="sd">it under the terms of the GNU General Public License as published by</span>
+<span class="sd">the Free Software Foundation, either version 3 of the License, or</span>
+<span class="sd">(at your option) any later version.</span>
+
+<span class="sd">Image Harvest is distributed in the hope that it will be useful,</span>
+<span class="sd">but WITHOUT ANY WARRANTY; without even the implied warranty of</span>
+<span class="sd">MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span>
+<span class="sd">GNU General Public License for more details.</span>
+
+<span class="sd">You should have received a copy of the GNU General Public License</span>
+<span class="sd">along with Image Harvest.  If not, see &lt;http://www.gnu.org/licenses/&gt;.</span>
+<span class="sd">&quot;&quot;&quot;</span>
 <span class="kn">import</span> <span class="nn">math</span>
 <span class="kn">import</span> <span class="nn">os</span>
 <span class="kn">import</span> <span class="nn">sqlite3</span>
@@ -139,6 +157,8 @@
 <span class="kn">import</span> <span class="nn">cv2</span>
 <span class="kn">import</span> <span class="nn">json</span>
 <span class="kn">import</span> <span class="nn">traceback</span>
+<span class="kn">import</span> <span class="nn">shutil</span>
+<span class="kn">import</span> <span class="nn">subprocess</span>
 <span class="kn">from</span> <span class="nn">scipy</span> <span class="kn">import</span> <span class="n">stats</span>
 
 <div class="viewcode-block" id="Stats"><a class="viewcode-back" href="../../statistics.html#ih.statistics.Stats">[docs]</a><span class="k">class</span> <span class="nc">Stats</span><span class="p">:</span>
@@ -253,6 +273,10 @@
         <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">conn</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">conn</span> <span class="k">else</span> <span class="n">conn</span>
         <span class="k">return</span> <span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;pragma table_info(&quot;</span> <span class="o">+</span> <span class="n">table</span> <span class="o">+</span> <span class="s">&quot;)&quot;</span><span class="p">)</span> <span class="k">if</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="s">&quot;pegasusid&quot;</span><span class="p">]</span>
     
+    <span class="k">def</span> <span class="nf">_getIds</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">table</span><span class="p">,</span> <span class="n">conn</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
+        <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">conn</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">conn</span> <span class="k">else</span> <span class="n">conn</span>
+        <span class="k">return</span> <span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select distinct id from &quot;</span> <span class="o">+</span> <span class="n">table</span><span class="p">)]</span>
+    
     <span class="k">def</span> <span class="nf">_getImageTypes</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">table</span><span class="p">,</span> <span class="n">conn</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
         <span class="n">conn</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">conn</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">conn</span> <span class="k">else</span> <span class="n">conn</span>
         <span class="k">return</span> <span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select distinct imtype from &quot;</span> <span class="o">+</span> <span class="n">table</span><span class="p">)]</span>
@@ -264,6 +288,9 @@
     <span class="k">def</span> <span class="nf">_checkNull</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
         <span class="k">return</span> <span class="bp">True</span> <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="bp">None</span> <span class="ow">or</span> <span class="nb">str</span><span class="p">(</span><span class="n">value</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s">&quot;none&quot;</span> <span class="k">else</span> <span class="bp">False</span>
     
+    <span class="k">def</span> <span class="nf">_listToSql</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">l</span><span class="p">):</span>
+        <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">l</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&quot;[&quot;</span><span class="p">,</span> <span class="s">&quot;(&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&quot;]&quot;</span><span class="p">,</span> <span class="s">&quot;)&quot;</span><span class="p">)</span>
+    
     <span class="k">def</span> <span class="nf">_loadLemnaData</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dataFile</span><span class="p">,</span> <span class="n">dataHeaders</span><span class="p">):</span>
         <span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">        :param dataFile: The input dataFile</span>
@@ -335,8 +362,6 @@
                 <span class="k">print</span> <span class="s">&quot;DB File: &#39;</span><span class="si">%s</span><span class="s">&#39; does not exist.&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">f</span><span class="p">,)</span>
         <span class="k">return</span>
         
-        
-        
 <div class="viewcode-block" id="Stats.logErrors"><a class="viewcode-back" href="../../statistics.html#ih.statistics.Stats.logErrors">[docs]</a>    <span class="k">def</span> <span class="nf">logErrors</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">logfile</span><span class="p">,</span> <span class="n">table</span> <span class="o">=</span> <span class="s">&quot;images&quot;</span><span class="p">):</span>
         <span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">        :param logfile: The logfile to write errors to</span>
@@ -361,6 +386,63 @@
                 <span class="n">wh</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot;All images processed successfully!  Nice job!</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">)</span>
         <span class="k">return</span>
     </div>
+    <span class="k">def</span> <span class="nf">makePublic</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">targetFolder</span><span class="p">,</span> <span class="n">process</span> <span class="o">=</span> <span class="bp">False</span><span class="p">):</span>
+        <span class="n">imtypes</span> <span class="o">=</span> <span class="p">[</span><span class="s">&quot;rgbsv&quot;</span><span class="p">,</span> <span class="s">&quot;rgbtv&quot;</span><span class="p">,</span> <span class="s">&quot;fluosv&quot;</span><span class="p">]</span>
+        <span class="n">query</span> <span class="o">=</span> <span class="s">&quot;select path from images where imtype in &quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">_listToSql</span><span class="p">(</span><span class="n">imtypes</span><span class="p">)</span>
+        <span class="k">print</span> <span class="n">query</span>
+        <span class="n">result</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
+        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+            <span class="n">target</span> <span class="o">=</span> <span class="s">&quot;/iplant/home/shared/walia_rice_salt/&quot;</span> <span class="o">+</span> <span class="n">targetFolder</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s">&quot;path&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">)[</span><span class="mi">5</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="s">&quot;/0_0.png&quot;</span>
+            <span class="k">print</span> <span class="n">target</span>
+            <span class="k">if</span> <span class="n">process</span><span class="p">:</span>
+                <span class="k">for</span> <span class="n">utype</span> <span class="ow">in</span> <span class="p">[</span><span class="s">&quot;anonymous&quot;</span><span class="p">,</span> <span class="s">&quot;public&quot;</span><span class="p">]:</span>
+                    <span class="n">subprocess</span><span class="o">.</span><span class="n">call</span><span class="p">([</span><span class="s">&quot;ichmod&quot;</span><span class="p">,</span><span class="s">&quot;read&quot;</span><span class="p">,</span> <span class="n">utype</span><span class="p">,</span> <span class="n">target</span><span class="p">])</span>
+        <span class="k">return</span>
+        
+    <span class="k">def</span> <span class="nf">dataToPlantcv</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">folder</span><span class="p">,</span> <span class="n">ids</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">imtypes</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">dates</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
+        <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="n">folder</span><span class="p">):</span>
+            <span class="n">ids</span> <span class="o">=</span> <span class="n">ids</span> <span class="k">if</span> <span class="n">ids</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">_getIds</span><span class="p">(</span><span class="s">&quot;images&quot;</span><span class="p">)</span>
+            <span class="n">imtypes</span> <span class="o">=</span> <span class="n">imtypes</span> <span class="k">if</span> <span class="n">imtypes</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">_getImageTypes</span><span class="p">(</span><span class="s">&quot;images&quot;</span><span class="p">)</span>
+            <span class="n">dates</span> <span class="o">=</span> <span class="n">dates</span> <span class="k">if</span> <span class="n">dates</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">_getDates</span><span class="p">(</span><span class="s">&quot;images&quot;</span><span class="p">)</span>
+            <span class="n">query</span> <span class="o">=</span> <span class="s">&quot;select id,date,imgname,imtype,path from images where id in &quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">_listToSql</span><span class="p">(</span><span class="n">ids</span><span class="p">)</span> <span class="o">+</span> <span class="s">&quot; and imtype in &quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">_listToSql</span><span class="p">(</span><span class="n">imtypes</span><span class="p">)</span> <span class="o">+</span> <span class="s">&quot; and date in &quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">_listToSql</span><span class="p">(</span><span class="n">dates</span><span class="p">)</span>
+            <span class="k">print</span> <span class="n">query</span>
+            <span class="n">result</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
+            <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">folder</span><span class="p">)</span>
+            <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+                <span class="nb">id</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;id&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;-&quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="s">&quot;-&quot;</span> <span class="ow">in</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;id&quot;</span><span class="p">]</span> <span class="k">else</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;id&quot;</span><span class="p">]</span>
+                <span class="n">date_time</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;date&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="s">&quot; 000&quot;</span>
+                <span class="n">imtype</span> <span class="o">=</span> <span class="p">{</span>
+                    <span class="s">&quot;rgbsv&quot;</span><span class="p">:</span> <span class="s">&quot;vis_sv_z700&quot;</span><span class="p">,</span>
+                    <span class="s">&quot;rgbtv&quot;</span><span class="p">:</span> <span class="s">&quot;vis_tv_z300&quot;</span>
+                <span class="p">}[</span><span class="n">row</span><span class="p">[</span><span class="s">&quot;imtype&quot;</span><span class="p">]]</span>
+                <span class="n">fname</span> <span class="o">=</span> <span class="s">&quot;</span><span class="si">%s</span><span class="s">-</span><span class="si">%s</span><span class="s">-</span><span class="si">%s</span><span class="s">-</span><span class="si">%s</span><span class="s">.png&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">date_time</span><span class="p">,</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;imgname&quot;</span><span class="p">],</span> <span class="n">imtype</span><span class="p">)</span>
+                <span class="n">shutil</span><span class="o">.</span><span class="n">copyfile</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s">&quot;path&quot;</span><span class="p">],</span> <span class="n">folder</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">fname</span><span class="p">)</span>
+        <span class="k">else</span><span class="p">:</span>
+            <span class="k">print</span> <span class="s">&quot;Folder already exists.&quot;</span>
+        <span class="k">return</span>
+    
+    <span class="k">def</span> <span class="nf">dataToIAP</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">folder</span><span class="p">,</span> <span class="n">ids</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">imtypes</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">dates</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
+        <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="n">folder</span><span class="p">):</span>
+            <span class="n">ids</span> <span class="o">=</span> <span class="n">ids</span> <span class="k">if</span> <span class="n">ids</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">_getIds</span><span class="p">(</span><span class="s">&quot;images&quot;</span><span class="p">)</span>
+            <span class="n">imtypes</span> <span class="o">=</span> <span class="n">imtypes</span> <span class="k">if</span> <span class="n">imtypes</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">_getImageTypes</span><span class="p">(</span><span class="s">&quot;images&quot;</span><span class="p">)</span>
+            <span class="n">dates</span> <span class="o">=</span> <span class="n">dates</span> <span class="k">if</span> <span class="n">dates</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">_getDates</span><span class="p">(</span><span class="s">&quot;images&quot;</span><span class="p">)</span>
+            <span class="n">query</span> <span class="o">=</span> <span class="s">&quot;select id,date,imgname,imtype,path from images where id in &quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">_listToSql</span><span class="p">(</span><span class="n">ids</span><span class="p">)</span> <span class="o">+</span> <span class="s">&quot; and imtype in &quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">_listToSql</span><span class="p">(</span><span class="n">imtypes</span><span class="p">)</span> <span class="o">+</span> <span class="s">&quot; and date in &quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">_listToSql</span><span class="p">(</span><span class="n">dates</span><span class="p">)</span>
+            <span class="k">print</span> <span class="n">query</span>
+            <span class="n">result</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">conn</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
+            <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">folder</span><span class="p">)</span>
+            <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
+                <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="n">folder</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;imtype&quot;</span><span class="p">][:</span><span class="o">-</span><span class="mi">2</span><span class="p">]):</span>
+                    <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">folder</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;imtype&quot;</span><span class="p">][:</span><span class="o">-</span><span class="mi">2</span><span class="p">])</span>
+                <span class="n">writeim</span> <span class="o">=</span> <span class="s">&quot;side&quot;</span> <span class="k">if</span> <span class="s">&quot;sv&quot;</span> <span class="ow">in</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;imtype&quot;</span><span class="p">]</span> <span class="k">else</span> <span class="s">&quot;top&quot;</span>
+                <span class="n">dirname</span> <span class="o">=</span> <span class="n">folder</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;imtype&quot;</span><span class="p">][:</span><span class="o">-</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">writeim</span>
+                <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="n">dirname</span><span class="p">):</span>
+                    <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">dirname</span><span class="p">)</span>
+                <span class="n">fname</span> <span class="o">=</span> <span class="s">&quot;</span><span class="si">%s</span><span class="s">_</span><span class="si">%s</span><span class="s">_</span><span class="si">%s</span><span class="s">_</span><span class="si">%s</span><span class="s">.png&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s">&quot;imgname&quot;</span><span class="p">],</span> <span class="n">writeim</span><span class="p">,</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;id&quot;</span><span class="p">],</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;date&quot;</span><span class="p">])</span>
+                <span class="n">shutil</span><span class="o">.</span><span class="n">copyfile</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s">&quot;path&quot;</span><span class="p">],</span> <span class="n">dirname</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">fname</span><span class="p">)</span>
+        <span class="k">else</span><span class="p">:</span>
+            <span class="k">print</span> <span class="s">&quot;Folder already exists.&quot;</span>
+        <span class="k">return</span>
+    
 <div class="viewcode-block" id="Stats.shootArea"><a class="viewcode-back" href="../../statistics.html#ih.statistics.Stats.shootArea">[docs]</a>    <span class="k">def</span> <span class="nf">shootArea</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">intable</span><span class="p">,</span> <span class="n">outtable</span><span class="p">,</span> <span class="n">grouping</span><span class="p">,</span> <span class="n">overwrite</span> <span class="o">=</span> <span class="bp">False</span><span class="p">):</span>
         <span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">        :param intable: The input table to load information from</span>
@@ -844,7 +926,7 @@
         <span class="k">if</span> <span class="n">processed</span><span class="p">:</span>
             <span class="n">query</span> <span class="o">+=</span> <span class="s">&quot; where outputPath is not null&quot;</span>
             <span class="k">if</span> <span class="n">group</span><span class="p">:</span>
-                <span class="n">query</span> <span class="o">+=</span> <span class="s">&quot; and (&quot;</span> <span class="o">+</span> <span class="s">&quot; or &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s">&quot;imtype=?&quot;</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">group</span><span class="p">])</span>
+                <span class="n">query</span> <span class="o">+=</span> <span class="s">&quot; and (&quot;</span> <span class="o">+</span> <span class="s">&quot; or &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s">&quot;imtype=?&quot;</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">group</span><span class="p">])</span> <span class="o">+</span> <span class="s">&quot;)&quot;</span>
                 <span class="n">values</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">([</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">group</span><span class="p">])</span>
         <span class="k">elif</span> <span class="n">group</span><span class="p">:</span>
             <span class="n">query</span> <span class="o">+=</span> <span class="s">&quot; where &quot;</span> <span class="o">+</span> <span class="s">&quot; or &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s">&quot;imtype=?&quot;</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">group</span><span class="p">])</span>
diff --git a/docs/build/html/_modules/ih/workflow.html b/docs/build/html/_modules/ih/workflow.html
index 86c18cb785b0ae4b0e2a3052e05ffa063ac4c305..e23170e6b4d9221602aebf3d0521ab4be366b1e8 100644
--- a/docs/build/html/_modules/ih/workflow.html
+++ b/docs/build/html/_modules/ih/workflow.html
@@ -74,6 +74,8 @@
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../viewer.html">Image Processing Viewer</a></li>
@@ -158,6 +160,7 @@
 <span class="kn">import</span> <span class="nn">textwrap</span>
 <span class="kn">import</span> <span class="nn">copy</span>
 <span class="kn">import</span> <span class="nn">ih.validator</span>
+<span class="kn">import</span> <span class="nn">getpass</span>
 <span class="kn">import</span> <span class="nn">xml.dom.minidom</span>
 <span class="kn">from</span> <span class="nn">Pegasus.DAX3</span> <span class="kn">import</span> <span class="o">*</span>
         
@@ -234,9 +237,12 @@
             <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/templates&quot;</span><span class="p">)</span>
         <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/rawfiles&quot;</span><span class="p">):</span>
             <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/rawfiles&quot;</span><span class="p">)</span>
+        <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+            <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/staging&quot;</span><span class="p">):</span>
+                <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/staging&quot;</span><span class="p">)</span>
         <span class="k">return</span>
     
-    <span class="k">def</span> <span class="nf">_addFile</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">imtype</span><span class="p">,</span> <span class="n">inout</span><span class="p">,</span> <span class="n">path</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
+    <span class="k">def</span> <span class="nf">_addFile</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">imtype</span><span class="p">,</span> <span class="n">inout</span><span class="p">,</span> <span class="n">path</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">derivedPath</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
         <span class="sd">&quot;&quot;&quot;</span>
 <span class="sd">            Adds the inputted file to the dax, as well as the internal variable self.files</span>
 <span class="sd">        &quot;&quot;&quot;</span>
@@ -246,19 +252,28 @@
             <span class="k">if</span> <span class="n">inout</span> <span class="o">==</span> <span class="s">&quot;input&quot;</span><span class="p">:</span>
                 <span class="bp">self</span><span class="o">.</span><span class="n">files</span><span class="p">[</span><span class="n">dax</span><span class="p">][</span><span class="n">imtype</span><span class="p">][</span><span class="n">inout</span><span class="p">][</span><span class="n">name</span><span class="p">][</span><span class="s">&quot;path&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">path</span> <span class="k">if</span> <span class="n">path</span> <span class="k">else</span> <span class="n">name</span>
                 <span class="bp">self</span><span class="o">.</span><span class="n">files</span><span class="p">[</span><span class="n">dax</span><span class="p">][</span><span class="n">imtype</span><span class="p">][</span><span class="n">inout</span><span class="p">][</span><span class="n">name</span><span class="p">][</span><span class="s">&quot;file&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">addPFN</span><span class="p">(</span><span class="n">PFN</span><span class="p">(</span><span class="s">&quot;file://&quot;</span> <span class="o">+</span> <span class="n">path</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">,</span><span class="s">&quot;%20&quot;</span><span class="p">),</span> <span class="s">&quot;local&quot;</span><span class="p">))</span>
+                <span class="k">if</span> <span class="n">derivedPath</span><span class="p">:</span>
+                    <span class="bp">self</span><span class="o">.</span><span class="n">files</span><span class="p">[</span><span class="n">dax</span><span class="p">][</span><span class="n">imtype</span><span class="p">][</span><span class="n">inout</span><span class="p">][</span><span class="n">name</span><span class="p">][</span><span class="s">&quot;derivedPath&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">derivedPath</span>
                 <span class="n">dax</span><span class="o">.</span><span class="n">addFile</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">files</span><span class="p">[</span><span class="n">dax</span><span class="p">][</span><span class="n">imtype</span><span class="p">][</span><span class="n">inout</span><span class="p">][</span><span class="n">name</span><span class="p">][</span><span class="s">&quot;file&quot;</span><span class="p">])</span>
         <span class="k">return</span>
     
     <span class="k">def</span> <span class="nf">_addJob</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">jobname</span><span class="p">,</span> <span class="n">executable</span><span class="p">,</span> <span class="n">inputs</span><span class="p">,</span> <span class="n">outputs</span><span class="p">,</span> <span class="n">arguments</span><span class="p">,</span> <span class="n">dependencies</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">label</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">walltime</span> <span class="o">=</span> <span class="bp">None</span><span class="p">):</span>
         <span class="n">dax</span> <span class="o">=</span> <span class="n">dax</span> <span class="k">if</span> <span class="n">dax</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">dax</span>
         <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_isJob</span><span class="p">(</span><span class="n">jobname</span><span class="p">,</span> <span class="n">dax</span><span class="p">):</span>
-            <span class="bp">self</span><span class="o">.</span><span class="n">jobs</span><span class="p">[</span><span class="n">dax</span><span class="p">][</span><span class="n">jobname</span><span class="p">]</span> <span class="o">=</span> <span class="n">Job</span><span class="p">(</span><span class="n">executable</span><span class="p">)</span>
+            <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+                <span class="bp">self</span><span class="o">.</span><span class="n">jobs</span><span class="p">[</span><span class="n">dax</span><span class="p">][</span><span class="n">jobname</span><span class="p">]</span> <span class="o">=</span> <span class="n">Job</span><span class="p">(</span><span class="s">&quot;osg-wrapper.sh&quot;</span><span class="p">)</span>
+            <span class="k">else</span><span class="p">:</span>
+                <span class="bp">self</span><span class="o">.</span><span class="n">jobs</span><span class="p">[</span><span class="n">dax</span><span class="p">][</span><span class="n">jobname</span><span class="p">]</span> <span class="o">=</span> <span class="n">Job</span><span class="p">(</span><span class="n">executable</span><span class="p">)</span>
             <span class="n">dax</span><span class="o">.</span><span class="n">addJob</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">jobs</span><span class="p">[</span><span class="n">dax</span><span class="p">][</span><span class="n">jobname</span><span class="p">])</span>
+            <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+                <span class="bp">self</span><span class="o">.</span><span class="n">jobs</span><span class="p">[</span><span class="n">dax</span><span class="p">][</span><span class="n">jobname</span><span class="p">]</span><span class="o">.</span><span class="n">uses</span><span class="p">(</span><span class="s">&quot;ih.tar.gz&quot;</span><span class="p">,</span> <span class="n">link</span> <span class="o">=</span> <span class="n">Link</span><span class="o">.</span><span class="n">INPUT</span><span class="p">)</span>
             <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">inputs</span><span class="p">:</span>
                 <span class="bp">self</span><span class="o">.</span><span class="n">jobs</span><span class="p">[</span><span class="n">dax</span><span class="p">][</span><span class="n">jobname</span><span class="p">]</span><span class="o">.</span><span class="n">uses</span><span class="p">(</span><span class="n">inputs</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s">&quot;file&quot;</span><span class="p">],</span> <span class="n">link</span> <span class="o">=</span> <span class="n">Link</span><span class="o">.</span><span class="n">INPUT</span><span class="p">)</span>
             <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">outputs</span><span class="p">:</span>
                 <span class="bp">self</span><span class="o">.</span><span class="n">jobs</span><span class="p">[</span><span class="n">dax</span><span class="p">][</span><span class="n">jobname</span><span class="p">]</span><span class="o">.</span><span class="n">uses</span><span class="p">(</span><span class="n">outputs</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s">&quot;file&quot;</span><span class="p">],</span> <span class="n">link</span> <span class="o">=</span> <span class="n">Link</span><span class="o">.</span><span class="n">OUTPUT</span><span class="p">,</span> <span class="n">transfer</span> <span class="o">=</span> <span class="n">outputs</span><span class="p">[</span><span class="n">key</span><span class="p">][</span><span class="s">&quot;transfer&quot;</span><span class="p">])</span>
             <span class="n">arglist</span> <span class="o">=</span> <span class="p">[]</span>
+            <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+                <span class="n">arglist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">&quot;./ih-&quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;version&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="s">&quot;/scripts/&quot;</span> <span class="o">+</span> <span class="n">executable</span><span class="p">)</span>
             <span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">arguments</span><span class="p">:</span>
                 <span class="n">arglist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
                 <span class="k">if</span> <span class="nb">str</span><span class="p">(</span><span class="n">arguments</span><span class="p">[</span><span class="n">arg</span><span class="p">])</span> <span class="ow">in</span> <span class="n">inputs</span><span class="p">:</span>
@@ -266,7 +281,10 @@
                 <span class="k">elif</span> <span class="nb">str</span><span class="p">(</span><span class="n">arguments</span><span class="p">[</span><span class="n">arg</span><span class="p">])</span> <span class="ow">in</span> <span class="n">outputs</span><span class="p">:</span>
                     <span class="n">arglist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">outputs</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">arguments</span><span class="p">[</span><span class="n">arg</span><span class="p">])][</span><span class="s">&quot;file&quot;</span><span class="p">])</span>
                 <span class="k">else</span><span class="p">:</span>
-                    <span class="n">arglist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">arguments</span><span class="p">[</span><span class="n">arg</span><span class="p">]))</span>
+                    <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+                        <span class="n">arglist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">&quot;&#39;&quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">arguments</span><span class="p">[</span><span class="n">arg</span><span class="p">])</span> <span class="o">+</span> <span class="s">&quot;&#39;&quot;</span><span class="p">)</span>
+                    <span class="k">else</span><span class="p">:</span>
+                        <span class="n">arglist</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">arguments</span><span class="p">[</span><span class="n">arg</span><span class="p">]))</span>
             <span class="bp">self</span><span class="o">.</span><span class="n">jobs</span><span class="p">[</span><span class="n">dax</span><span class="p">][</span><span class="n">jobname</span><span class="p">]</span><span class="o">.</span><span class="n">addArguments</span><span class="p">(</span><span class="o">*</span><span class="n">arglist</span><span class="p">)</span>
             <span class="k">if</span> <span class="n">dependencies</span><span class="p">:</span>
                 <span class="k">for</span> <span class="n">depend</span> <span class="ow">in</span> <span class="n">dependencies</span><span class="p">:</span>
@@ -348,7 +366,10 @@
 <span class="sd">            the dax, as well as the internal self.executables variable</span>
 <span class="sd">        &quot;&quot;&quot;</span>
         <span class="k">for</span> <span class="n">ex</span> <span class="ow">in</span> <span class="n">conf</span><span class="o">.</span><span class="n">valid</span><span class="p">:</span>
-            <span class="bp">self</span><span class="o">.</span><span class="n">executables</span><span class="p">[</span><span class="n">ex</span><span class="p">]</span> <span class="o">=</span> <span class="n">Executable</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">ex</span><span class="p">,</span> <span class="n">os</span><span class="o">=</span><span class="n">os</span><span class="p">,</span> <span class="n">arch</span><span class="o">=</span><span class="n">arch</span><span class="p">)</span>
+            <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+                <span class="bp">self</span><span class="o">.</span><span class="n">executables</span><span class="p">[</span><span class="n">ex</span><span class="p">]</span> <span class="o">=</span> <span class="n">Executable</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">ex</span><span class="p">,</span> <span class="n">os</span><span class="o">=</span><span class="n">os</span><span class="p">,</span> <span class="n">arch</span><span class="o">=</span><span class="n">arch</span><span class="p">,</span> <span class="n">installed</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
+            <span class="k">else</span><span class="p">:</span>
+                <span class="bp">self</span><span class="o">.</span><span class="n">executables</span><span class="p">[</span><span class="n">ex</span><span class="p">]</span> <span class="o">=</span> <span class="n">Executable</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">ex</span><span class="p">,</span> <span class="n">os</span><span class="o">=</span><span class="n">os</span><span class="p">,</span> <span class="n">arch</span><span class="o">=</span><span class="n">arch</span><span class="p">)</span>
             <span class="bp">self</span><span class="o">.</span><span class="n">executables</span><span class="p">[</span><span class="n">ex</span><span class="p">]</span><span class="o">.</span><span class="n">addPFN</span><span class="p">(</span><span class="n">PFN</span><span class="p">(</span><span class="s">&quot;file://&quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;installdir&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">ex</span><span class="p">,</span> <span class="s">&quot;local&quot;</span><span class="p">))</span>
             <span class="c">#if &quot;cluster&quot; in self.config:</span>
             <span class="c">#     self.executables[ex].addProfile(Profile(Namespace.PEGASUS, &quot;clusters.size&quot;, self.config[&quot;cluster&quot;]))</span>
@@ -361,7 +382,7 @@
             <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/stats/notify.sh&quot;</span><span class="p">,</span> <span class="s">&quot;w&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">wh</span><span class="p">:</span>
                 <span class="n">notify</span> <span class="o">=</span> <span class="n">textwrap</span><span class="o">.</span><span class="n">dedent</span><span class="p">(</span><span class="s">&quot;&quot;&quot;</span><span class="se">\</span>
 <span class="s">                        #!/bin/bash</span>
-<span class="s">                        </span><span class="si">%s</span><span class="s">/email -t </span><span class="si">%s</span><span class="s"> --report=pegasus-analyzer</span>
+<span class="s">                        </span><span class="si">%s</span><span class="s">/notification/email -t </span><span class="si">%s</span><span class="s"> --report=pegasus-analyzer</span>
 <span class="s">                &quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;notify&quot;</span><span class="p">][</span><span class="s">&quot;pegasus_home&quot;</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;notify&quot;</span><span class="p">][</span><span class="s">&quot;email&quot;</span><span class="p">]))</span>
                 <span class="n">wh</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">notify</span><span class="p">)</span>
             <span class="n">os</span><span class="o">.</span><span class="n">chmod</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/stats/notify.sh&quot;</span><span class="p">,</span> <span class="mo">0755</span><span class="p">)</span>
@@ -430,7 +451,7 @@
 <span class="s">                        </span>
 <span class="s">                        pegasus.transfer.links = true</span>
 <span class="s">                        </span>
-<span class="s">                        pegasus.data.configuration = sharedfs</span>
+<span class="s">                        pegasus.data.configuration = </span><span class="si">%s</span><span class="s"></span>
 <span class="s">                        </span>
 <span class="s">                        &quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span><span class="p">))</span>
             <span class="n">wh</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">pegasusrc</span><span class="p">)</span>
@@ -441,17 +462,45 @@
 <span class="sd">            Creates the pegasus site catalog.  input/sites.xml</span>
 <span class="sd">        &quot;&quot;&quot;</span>
         <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span> <span class="o">+</span> <span class="s">&quot;/sites.xml&quot;</span><span class="p">,</span> <span class="s">&quot;w&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">wh</span><span class="p">:</span>
-            <span class="n">sites</span> <span class="o">=</span> <span class="s">&quot;&quot;&quot;</span><span class="se">\</span>
-<span class="s">             &lt;sitecatalog xmlns=&quot;http://pegasus.isi.edu/schema/sitecatalog&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://pegasus.isi.edu/schema/sitecatalog http://pegasus.isi.edu/schema/sc-4.0.xsd&quot; version=&quot;4.0&quot;&gt;</span>
-<span class="s">    </span>
-<span class="s">                        &lt;site  handle=&quot;local&quot; arch=&quot;x86_64&quot; os=&quot;LINUX&quot;&gt;</span>
-<span class="s">                            &lt;directory type=&quot;shared-scratch&quot; path=&quot;</span><span class="si">%s</span><span class="s">&quot;&gt;</span>
-<span class="s">                                &lt;file-server operation=&quot;all&quot; url=&quot;file://</span><span class="si">%s</span><span class="s">&quot; /&gt;</span>
-<span class="s">                            &lt;/directory&gt;</span>
-<span class="s">                            &lt;directory type=&quot;local-storage&quot; path=&quot;</span><span class="si">%s</span><span class="s">&quot;&gt;</span>
-<span class="s">                                &lt;file-server operation=&quot;all&quot; url=&quot;file://</span><span class="si">%s</span><span class="s">&quot; /&gt;</span>
-<span class="s">                            &lt;/directory&gt;</span>
-<span class="s">                        &quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/stats/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/stats/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/&quot;</span><span class="p">)</span>
+            <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+                <span class="n">sites</span> <span class="o">=</span> <span class="s">&quot;&quot;&quot;</span><span class="se">\</span>
+<span class="s">                &lt;sitecatalog version=&quot;3.0&quot; xmlns=&quot;http://pegasus.isi.edu/schema/sitecatalog&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://pegasus.isi.edu/schema/sitecatalog http://pegasus.isi.edu/schema/sc-3.0.xsd&quot;&gt;</span>
+<span class="s">                    &lt;site handle=&quot;local&quot; arch=&quot;x86_64&quot; os=&quot;LINUX&quot;&gt;</span>
+<span class="s">                            &lt;head-fs&gt;</span>
+<span class="s">                                &lt;scratch&gt;</span>
+<span class="s">                                        &lt;shared&gt;</span>
+<span class="s">                                            &lt;file-server protocol=&quot;file&quot; url=&quot;file://&quot; mount-point=&quot;</span><span class="si">%s</span><span class="s">&quot;/&gt;</span>
+<span class="s">                                            &lt;internal-mount-point mount-point=&quot;</span><span class="si">%s</span><span class="s">&quot;/&gt;</span>
+<span class="s">                                        &lt;/shared&gt;</span>
+<span class="s">                                    &lt;/scratch&gt;</span>
+<span class="s">                                &lt;storage&gt;</span>
+<span class="s">                                        &lt;shared&gt;</span>
+<span class="s">                                            &lt;file-server protocol=&quot;file&quot; url=&quot;file://&quot; mount-point=&quot;</span><span class="si">%s</span><span class="s">&quot;/&gt;</span>
+<span class="s">                                            &lt;internal-mount-point mount-point=&quot;</span><span class="si">%s</span><span class="s">&quot;/&gt;</span>
+<span class="s">                                        &lt;/shared&gt;</span>
+<span class="s">                                    &lt;/storage&gt;</span>
+<span class="s">                            &lt;/head-fs&gt;</span>
+<span class="s">                    &quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/stats/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/stats/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span><span class="p">)</span>
+                <span class="n">sites</span> <span class="o">+=</span> <span class="s">&quot;&quot;&quot;</span><span class="se">\</span>
+<span class="s">                    &lt;/site&gt;</span>
+<span class="s">                    &lt;site handle=&quot;condorpool&quot; arch=&quot;x86_64&quot; os=&quot;LINUX&quot;&gt;</span>
+<span class="s">                            &lt;head-fs&gt;</span>
+<span class="s">                                    &lt;scratch /&gt;</span>
+<span class="s">                                    &lt;storage /&gt;</span>
+<span class="s">                            &lt;/head-fs&gt;</span>
+<span class="s">                &quot;&quot;&quot;</span>
+            <span class="k">else</span><span class="p">:</span>
+                <span class="n">sites</span> <span class="o">=</span> <span class="s">&quot;&quot;&quot;</span><span class="se">\</span>
+<span class="s">                 &lt;sitecatalog xmlns=&quot;http://pegasus.isi.edu/schema/sitecatalog&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://pegasus.isi.edu/schema/sitecatalog http://pegasus.isi.edu/schema/sc-4.0.xsd&quot; version=&quot;4.0&quot;&gt;</span>
+<span class="s">        </span>
+<span class="s">                            &lt;site  handle=&quot;local&quot; arch=&quot;x86_64&quot; os=&quot;LINUX&quot;&gt;</span>
+<span class="s">                                &lt;directory type=&quot;shared-scratch&quot; path=&quot;</span><span class="si">%s</span><span class="s">&quot;&gt;</span>
+<span class="s">                                    &lt;file-server operation=&quot;all&quot; url=&quot;file://</span><span class="si">%s</span><span class="s">&quot; /&gt;</span>
+<span class="s">                                &lt;/directory&gt;</span>
+<span class="s">                                &lt;directory type=&quot;local-storage&quot; path=&quot;</span><span class="si">%s</span><span class="s">&quot;&gt;</span>
+<span class="s">                                    &lt;file-server operation=&quot;all&quot; url=&quot;file://</span><span class="si">%s</span><span class="s">&quot; /&gt;</span>
+<span class="s">                                &lt;/directory&gt;</span>
+<span class="s">                            &quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/stats/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/stats/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/&quot;</span><span class="p">)</span>
             <span class="k">for</span> <span class="n">namespace</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;profile&quot;</span><span class="p">]:</span>
                 <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;profile&quot;</span><span class="p">][</span><span class="n">namespace</span><span class="p">]:</span>
                     <span class="n">val</span> <span class="o">=</span> <span class="s">&quot;:&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;profile&quot;</span><span class="p">][</span><span class="n">namespace</span><span class="p">][</span><span class="n">key</span><span class="p">])</span> <span class="k">if</span> <span class="s">&quot;path&quot;</span> <span class="ow">in</span> <span class="n">key</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;profile&quot;</span><span class="p">][</span><span class="n">namespace</span><span class="p">][</span><span class="n">key</span><span class="p">]</span>
@@ -471,11 +520,11 @@
 <span class="s">                    </span>
 <span class="s">                    plan=`pegasus-plan </span><span class="se">\\</span><span class="s"></span>
 <span class="s">                    --conf &quot;</span><span class="si">%s</span><span class="s">&quot; </span><span class="se">\\</span><span class="s"></span>
-<span class="s">                    --sites local </span><span class="se">\\</span><span class="s"></span>
+<span class="s">                    --sites &quot;</span><span class="si">%s</span><span class="s">&quot; </span><span class="se">\\</span><span class="s"></span>
 <span class="s">                    --dir &quot;</span><span class="si">%s</span><span class="s">&quot; </span><span class="se">\\</span><span class="s"></span>
 <span class="s">                    --output-site local </span><span class="se">\\</span><span class="s"></span>
 <span class="s">                    --dax &quot;</span><span class="si">%s</span><span class="s">&quot; </span><span class="se">\\</span><span class="s"></span>
-<span class="s">                    --randomdir </span><span class="se">\\</span><span class="s">&quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span> <span class="o">+</span> <span class="s">&quot;/conf.rc&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/stats&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span> <span class="o">+</span> <span class="s">&quot;/stats.dax&quot;</span><span class="p">))</span>
+<span class="s">                    --randomdir </span><span class="se">\\</span><span class="s">&quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span> <span class="o">+</span> <span class="s">&quot;/conf.rc&quot;</span><span class="p">,</span> <span class="s">&quot;condorpool&quot;</span> <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span> <span class="k">else</span> <span class="s">&quot;local&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/stats&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span> <span class="o">+</span> <span class="s">&quot;/stats.dax&quot;</span><span class="p">))</span>
             <span class="k">if</span> <span class="s">&quot;cluster&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
                 <span class="n">submit</span> <span class="o">+=</span> <span class="s">&quot;&quot;&quot;--cluster horizontal </span><span class="se">\\\n</span><span class="s">&quot;&quot;&quot;</span>
             <span class="n">submit</span> <span class="o">+=</span> <span class="n">textwrap</span><span class="o">.</span><span class="n">dedent</span><span class="p">(</span><span class="s">&quot;&quot;&quot;</span><span class="se">\</span>
@@ -579,6 +628,8 @@
         <span class="k">for</span> <span class="nb">type</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">rawFiles</span><span class="p">:</span>
             <span class="k">for</span> <span class="nb">input</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">rawFiles</span><span class="p">[</span><span class="nb">type</span><span class="p">]:</span>
                 <span class="n">shutil</span><span class="o">.</span><span class="n">copyfile</span><span class="p">(</span><span class="nb">input</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/rawfiles/&quot;</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="nb">input</span><span class="p">))</span>
+        <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+            <span class="n">shutil</span><span class="o">.</span><span class="n">copyfile</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;osg&quot;</span><span class="p">][</span><span class="s">&quot;tarball&quot;</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/rawfiles/&quot;</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;osg&quot;</span><span class="p">][</span><span class="s">&quot;tarball&quot;</span><span class="p">]))</span>
         <span class="k">return</span>
     
     <span class="k">def</span> <span class="nf">_loadFiles</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">loc</span><span class="p">):</span>
@@ -593,8 +644,16 @@
             <span class="bp">self</span><span class="o">.</span><span class="n">files</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
             <span class="bp">self</span><span class="o">.</span><span class="n">files</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">][</span><span class="s">&quot;all&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">&quot;input&quot;</span><span class="p">:</span> <span class="p">{},</span> <span class="s">&quot;output&quot;</span><span class="p">:</span> <span class="p">{}}</span>
             <span class="bp">self</span><span class="o">.</span><span class="n">files</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">dax</span><span class="p">][</span><span class="s">&quot;raw&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">&quot;input&quot;</span><span class="p">:</span> <span class="p">{},</span> <span class="s">&quot;output&quot;</span><span class="p">:</span> <span class="p">{}}</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">files</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">][</span><span class="s">&quot;raw&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">&quot;input&quot;</span><span class="p">:</span> <span class="p">{},</span> <span class="s">&quot;output&quot;</span><span class="p">:</span> <span class="p">{}}</span>
+            <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+                <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="s">&quot;ih.tar.gz&quot;</span><span class="p">,</span> <span class="s">&quot;raw&quot;</span><span class="p">,</span> <span class="s">&quot;input&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/rawfiles/ih-&quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;version&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="s">&quot;.tar.gz&quot;</span><span class="p">)</span>
+                <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="s">&quot;ih.tar.gz&quot;</span><span class="p">,</span> <span class="s">&quot;raw&quot;</span><span class="p">,</span> <span class="s">&quot;input&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/rawfiles/ih-&quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;version&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="s">&quot;.tar.gz&quot;</span><span class="p">,</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">)</span>
             <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="s">&quot;img.db&quot;</span><span class="p">,</span> <span class="s">&quot;raw&quot;</span><span class="p">,</span> <span class="s">&quot;input&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/output.db&quot;</span><span class="p">)</span>
             <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="s">&quot;img.db&quot;</span><span class="p">,</span> <span class="s">&quot;all&quot;</span><span class="p">,</span> <span class="s">&quot;input&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/output.db&quot;</span><span class="p">,</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">)</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="s">&quot;img2.db&quot;</span><span class="p">,</span> <span class="s">&quot;raw&quot;</span><span class="p">,</span> <span class="s">&quot;output&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/img2.db&quot;</span><span class="p">)</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="s">&quot;img2.db&quot;</span><span class="p">,</span> <span class="s">&quot;raw&quot;</span><span class="p">,</span> <span class="s">&quot;output&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/img2.db&quot;</span><span class="p">,</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">)</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="s">&quot;img3.db&quot;</span><span class="p">,</span> <span class="s">&quot;raw&quot;</span><span class="p">,</span> <span class="s">&quot;output&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/img3.db&quot;</span><span class="p">)</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="s">&quot;img3.db&quot;</span><span class="p">,</span> <span class="s">&quot;raw&quot;</span><span class="p">,</span> <span class="s">&quot;output&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/img3.db&quot;</span><span class="p">,</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">)</span>
             <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="s">&quot;img.log&quot;</span><span class="p">,</span> <span class="s">&quot;raw&quot;</span><span class="p">,</span> <span class="s">&quot;output&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/imgproc.log&quot;</span><span class="p">)</span>
             <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="s">&quot;extract.json&quot;</span><span class="p">,</span> <span class="s">&quot;raw&quot;</span><span class="p">,</span> <span class="s">&quot;input&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/rawfiles/extract.json&quot;</span><span class="p">)</span>
             <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="s">&quot;extract.json&quot;</span><span class="p">,</span> <span class="s">&quot;all&quot;</span><span class="p">,</span> <span class="s">&quot;input&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/rawfiles/extract.json&quot;</span><span class="p">,</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">)</span>
@@ -603,6 +662,7 @@
                 <span class="k">for</span> <span class="nb">input</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">rawFiles</span><span class="p">[</span><span class="nb">type</span><span class="p">]:</span>
                     <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="nb">input</span><span class="p">),</span> <span class="nb">type</span><span class="p">,</span> <span class="s">&quot;input&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/rawfiles/&quot;</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="nb">input</span><span class="p">))</span>
                 <span class="n">wh</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot;img.log file://&quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/imgproc.log pool=</span><span class="se">\&quot;</span><span class="s">local</span><span class="se">\&quot;\n</span><span class="s">&quot;</span><span class="p">)</span>
+                <span class="n">wh</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot;img3.db file://&quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/img3.db pool=</span><span class="se">\&quot;</span><span class="s">local</span><span class="se">\&quot;\n</span><span class="s">&quot;</span><span class="p">)</span>
                 <span class="n">inputImages</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;workflows&quot;</span><span class="p">][</span><span class="nb">type</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s">&quot;inputs&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span><span class="n">x</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">conf</span><span class="o">.</span><span class="n">valid</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;workflows&quot;</span><span class="p">][</span><span class="nb">type</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s">&quot;executable&quot;</span><span class="p">]][</span><span class="s">&quot;inputs&quot;</span><span class="p">])</span> <span class="k">if</span> <span class="n">x</span> <span class="o">==</span> <span class="s">&quot;image&quot;</span><span class="p">]</span>
                 <span class="n">outputImages</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;workflows&quot;</span><span class="p">][</span><span class="nb">type</span><span class="p">][</span><span class="n">z</span><span class="p">][</span><span class="s">&quot;outputs&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;workflows&quot;</span><span class="p">][</span><span class="nb">type</span><span class="p">]))</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span><span class="n">x</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">conf</span><span class="o">.</span><span class="n">valid</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;workflows&quot;</span><span class="p">][</span><span class="nb">type</span><span class="p">][</span><span class="n">z</span><span class="p">][</span><span class="s">&quot;executable&quot;</span><span class="p">]][</span><span class="s">&quot;outputs&quot;</span><span class="p">])</span> <span class="k">if</span> <span class="n">x</span> <span class="o">==</span> <span class="s">&quot;image&quot;</span><span class="p">]</span>
                 <span class="n">outputFiles</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;workflows&quot;</span><span class="p">][</span><span class="nb">type</span><span class="p">][</span><span class="n">z</span><span class="p">][</span><span class="s">&quot;outputs&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">],</span> <span class="n">conf</span><span class="o">.</span><span class="n">fileExtensions</span><span class="p">[</span><span class="n">conf</span><span class="o">.</span><span class="n">valid</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;workflows&quot;</span><span class="p">][</span><span class="nb">type</span><span class="p">][</span><span class="n">z</span><span class="p">][</span><span class="s">&quot;executable&quot;</span><span class="p">]][</span><span class="s">&quot;outputs&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">]])</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;workflows&quot;</span><span class="p">][</span><span class="nb">type</span><span class="p">]))</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span><span class="n">x</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">conf</span><span class="o">.</span><span class="n">valid</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;workflows&quot;</span><span class="p">][</span><span class="nb">type</span><span class="p">][</span><span class="n">z</span><span class="p">][</span><span class="s">&quot;executable&quot;</span><span class="p">]][</span><span class="s">&quot;outputs&quot;</span><span class="p">])</span> <span class="k">if</span> <span class="n">x</span> <span class="o">!=</span> <span class="s">&quot;image&quot;</span> <span class="ow">and</span> <span class="n">x</span> <span class="o">!=</span> <span class="s">&quot;none&quot;</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;workflows&quot;</span><span class="p">][</span><span class="nb">type</span><span class="p">][</span><span class="n">z</span><span class="p">][</span><span class="s">&quot;outputs&quot;</span><span class="p">])</span> <span class="o">&gt;</span> <span class="n">i</span><span class="p">)</span>
@@ -611,7 +671,10 @@
                     <span class="c">#derivedPath = row[&quot;experiment&quot;].replace(&quot; &quot;,&quot;%20&quot;) + &quot;/&quot; + row[&quot;id&quot;].replace(&quot; &quot;,&quot;%20&quot;) + &quot;/&quot; + row[&quot;date&quot;].replace(&quot; &quot;,&quot;%20&quot;) + &quot;/&quot; + type + &quot;/&quot; + row[&quot;imgname&quot;].replace(&quot; &quot;,&quot;%20&quot;) + &quot;/&quot;</span>
                     <span class="n">derivedPath</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;experiment&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">,</span><span class="s">&quot;&quot;</span><span class="p">)</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;id&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">,</span><span class="s">&quot;&quot;</span><span class="p">)</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;date&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">,</span><span class="s">&quot;&quot;</span><span class="p">)</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="nb">type</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;imgname&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&quot; &quot;</span><span class="p">,</span><span class="s">&quot;&quot;</span><span class="p">)</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span>
                     <span class="k">for</span> <span class="nb">input</span> <span class="ow">in</span> <span class="n">inputImages</span><span class="p">:</span>
-                        <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="n">derivedPath</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;pegasusid&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="nb">input</span> <span class="o">+</span> <span class="s">&quot;.&quot;</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;path&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;.&quot;</span><span class="p">)[</span><span class="mi">1</span><span class="p">],</span> <span class="nb">type</span><span class="p">,</span> <span class="s">&quot;input&quot;</span><span class="p">,</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;path&quot;</span><span class="p">])</span>
+                        <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+                            <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s">&quot;pegasusid&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="nb">input</span> <span class="o">+</span> <span class="s">&quot;.&quot;</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;path&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;.&quot;</span><span class="p">)[</span><span class="mi">1</span><span class="p">],</span> <span class="nb">type</span><span class="p">,</span> <span class="s">&quot;input&quot;</span><span class="p">,</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;path&quot;</span><span class="p">],</span> <span class="n">derivedPath</span> <span class="o">=</span> <span class="n">derivedPath</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;pegasusid&quot;</span><span class="p">])</span>
+                        <span class="k">else</span><span class="p">:</span>
+                            <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="n">derivedPath</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;pegasusid&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="nb">input</span> <span class="o">+</span> <span class="s">&quot;.&quot;</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;path&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;.&quot;</span><span class="p">)[</span><span class="mi">1</span><span class="p">],</span> <span class="nb">type</span><span class="p">,</span> <span class="s">&quot;input&quot;</span><span class="p">,</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;path&quot;</span><span class="p">],</span> <span class="n">derivedPath</span> <span class="o">=</span> <span class="n">derivedPath</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;pegasusid&quot;</span><span class="p">])</span>
                     <span class="k">for</span> <span class="n">output</span> <span class="ow">in</span> <span class="n">outputImages</span><span class="p">:</span>
                         <span class="k">if</span> <span class="n">output</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;extract&quot;</span><span class="p">][</span><span class="s">&quot;workflows&quot;</span><span class="p">][</span><span class="nb">type</span><span class="p">][</span><span class="s">&quot;inputs&quot;</span><span class="p">]:</span>
                             <span class="bp">self</span><span class="o">.</span><span class="n">exInput</span><span class="p">[</span><span class="n">derivedPath</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;pegasusid&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="n">output</span> <span class="o">+</span> <span class="s">&quot;.png&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">derivedPath</span> <span class="o">+</span> <span class="n">row</span><span class="p">[</span><span class="s">&quot;pegasusid&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="n">output</span> <span class="o">+</span> <span class="s">&quot;.png&quot;</span>
@@ -631,7 +694,7 @@
             <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/imgproc/notify.sh&quot;</span><span class="p">,</span> <span class="s">&quot;w&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">wh</span><span class="p">:</span>
                 <span class="n">notify</span> <span class="o">=</span> <span class="n">textwrap</span><span class="o">.</span><span class="n">dedent</span><span class="p">(</span><span class="s">&quot;&quot;&quot;</span><span class="se">\</span>
 <span class="s">                        #!/bin/bash</span>
-<span class="s">                        </span><span class="si">%s</span><span class="s">/email -t </span><span class="si">%s</span><span class="s"> --report=pegasus-analyzer</span>
+<span class="s">                        </span><span class="si">%s</span><span class="s">/notification/email -t </span><span class="si">%s</span><span class="s"> --report=pegasus-analyzer</span>
 <span class="s">                &quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;notify&quot;</span><span class="p">][</span><span class="s">&quot;pegasus_home&quot;</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;notify&quot;</span><span class="p">][</span><span class="s">&quot;email&quot;</span><span class="p">]))</span>
                 <span class="n">wh</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">notify</span><span class="p">)</span>
             <span class="n">os</span><span class="o">.</span><span class="n">chmod</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/input/imgproc/notify.sh&quot;</span><span class="p">,</span> <span class="mo">0755</span><span class="p">)</span>
@@ -643,7 +706,10 @@
 <span class="sd">            the dax, as well as the internal self.executables variable</span>
 <span class="sd">        &quot;&quot;&quot;</span>
         <span class="k">for</span> <span class="n">ex</span> <span class="ow">in</span> <span class="n">conf</span><span class="o">.</span><span class="n">valid</span><span class="p">:</span>
-            <span class="bp">self</span><span class="o">.</span><span class="n">executables</span><span class="p">[</span><span class="n">ex</span><span class="p">]</span> <span class="o">=</span> <span class="n">Executable</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">ex</span><span class="p">,</span> <span class="n">os</span><span class="o">=</span><span class="n">os</span><span class="p">,</span> <span class="n">arch</span><span class="o">=</span><span class="n">arch</span><span class="p">)</span>
+            <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+                <span class="bp">self</span><span class="o">.</span><span class="n">executables</span><span class="p">[</span><span class="n">ex</span><span class="p">]</span> <span class="o">=</span> <span class="n">Executable</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">ex</span><span class="p">,</span> <span class="n">os</span><span class="o">=</span><span class="n">os</span><span class="p">,</span> <span class="n">arch</span><span class="o">=</span><span class="n">arch</span><span class="p">,</span> <span class="n">installed</span> <span class="o">=</span> <span class="bp">False</span><span class="p">)</span>
+            <span class="k">else</span><span class="p">:</span>
+                <span class="bp">self</span><span class="o">.</span><span class="n">executables</span><span class="p">[</span><span class="n">ex</span><span class="p">]</span> <span class="o">=</span> <span class="n">Executable</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">ex</span><span class="p">,</span> <span class="n">os</span><span class="o">=</span><span class="n">os</span><span class="p">,</span> <span class="n">arch</span><span class="o">=</span><span class="n">arch</span><span class="p">)</span>
             <span class="bp">self</span><span class="o">.</span><span class="n">executables</span><span class="p">[</span><span class="n">ex</span><span class="p">]</span><span class="o">.</span><span class="n">addPFN</span><span class="p">(</span><span class="n">PFN</span><span class="p">(</span><span class="s">&quot;file://&quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;installdir&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">ex</span><span class="p">,</span> <span class="s">&quot;local&quot;</span><span class="p">))</span>
             <span class="c">#if &quot;cluster&quot; in self.config:</span>
             <span class="c">#    val = int(self.config[&quot;cluster&quot;] * conf.valid[ex][&quot;weight&quot;]) if &quot;weight&quot; in conf.valid[ex] else self.config[&quot;cluster&quot;]</span>
@@ -660,7 +726,13 @@
                 <span class="n">inputs</span><span class="p">[</span><span class="nb">input</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="nb">input</span><span class="p">),</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="n">save</span><span class="p">}</span>
             <span class="k">else</span><span class="p">:</span>
                 <span class="n">ex</span> <span class="o">=</span> <span class="n">extension</span> <span class="k">if</span> <span class="n">job</span><span class="p">[</span><span class="s">&quot;name&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;workflows&quot;</span><span class="p">][</span><span class="nb">type</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s">&quot;name&quot;</span><span class="p">]</span> <span class="k">else</span> <span class="n">conf</span><span class="o">.</span><span class="n">fileExtensions</span><span class="p">[</span><span class="n">ftype</span><span class="p">]</span>
-                <span class="n">inputs</span><span class="p">[</span><span class="nb">input</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="n">basename</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="nb">input</span> <span class="o">+</span> <span class="n">ex</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="n">save</span><span class="p">}</span>
+                <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+                    <span class="k">if</span> <span class="nb">input</span> <span class="o">==</span> <span class="s">&quot;base&quot;</span><span class="p">:</span>
+                        <span class="n">inputs</span><span class="p">[</span><span class="nb">input</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">basename</span><span class="p">)</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="nb">input</span> <span class="o">+</span> <span class="n">ex</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="n">save</span><span class="p">}</span>
+                    <span class="k">else</span><span class="p">:</span>
+                        <span class="n">inputs</span><span class="p">[</span><span class="nb">input</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="n">basename</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="nb">input</span> <span class="o">+</span> <span class="n">ex</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="n">save</span><span class="p">}</span>
+                <span class="k">else</span><span class="p">:</span>
+                    <span class="n">inputs</span><span class="p">[</span><span class="nb">input</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="n">basename</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="nb">input</span> <span class="o">+</span> <span class="n">ex</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="n">save</span><span class="p">}</span>
         <span class="k">return</span> <span class="n">inputs</span>
     
     <span class="k">def</span> <span class="nf">_loadJobOutputs</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">job</span><span class="p">,</span> <span class="nb">type</span><span class="p">,</span> <span class="n">basename</span><span class="p">,</span> <span class="n">save</span><span class="p">):</span>
@@ -710,8 +782,8 @@
                     <span class="k">elif</span> <span class="p">((</span><span class="n">clusternum</span><span class="p">[</span><span class="nb">type</span><span class="p">]</span> <span class="o">*</span> <span class="mi">100</span> <span class="o">+</span> <span class="n">jobnum</span><span class="p">)</span> <span class="o">%</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;cluster&quot;</span><span class="p">]</span> <span class="o">*</span> <span class="mf">0.3</span><span class="p">))</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                         <span class="n">meancluster</span><span class="p">[</span><span class="nb">type</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
                 <span class="n">extension</span> <span class="o">=</span> <span class="s">&quot;.&quot;</span> <span class="o">+</span> <span class="n">infile</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;.&quot;</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
-                <span class="n">derivedPath</span> <span class="o">=</span> <span class="n">infile</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;_&quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
                 <span class="n">realname</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">files</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">dax</span><span class="p">][</span><span class="nb">type</span><span class="p">][</span><span class="s">&quot;input&quot;</span><span class="p">][</span><span class="n">infile</span><span class="p">][</span><span class="s">&quot;path&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;.&quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+                <span class="n">derivedPath</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">files</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">dax</span><span class="p">][</span><span class="nb">type</span><span class="p">][</span><span class="s">&quot;input&quot;</span><span class="p">][</span><span class="n">infile</span><span class="p">][</span><span class="s">&quot;derivedPath&quot;</span><span class="p">]</span>
                 <span class="k">for</span> <span class="n">stepnum</span><span class="p">,</span><span class="n">job</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;workflows&quot;</span><span class="p">][</span><span class="nb">type</span><span class="p">]):</span>
                     <span class="n">jobname</span> <span class="o">=</span> <span class="n">derivedPath</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="n">job</span><span class="p">[</span><span class="s">&quot;name&quot;</span><span class="p">]</span>
                     <span class="n">inputs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_loadJobInputs</span><span class="p">(</span><span class="n">job</span><span class="p">,</span> <span class="nb">type</span><span class="p">,</span> <span class="n">derivedPath</span><span class="p">,</span> <span class="n">extension</span><span class="p">)</span>
@@ -750,8 +822,8 @@
                 <span class="n">binDep</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">type</span> <span class="o">+</span> <span class="s">&quot;_extract&quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">q</span><span class="p">))</span>
                 <span class="n">aggIn</span><span class="p">[</span><span class="nb">type</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">q</span><span class="p">)</span> <span class="o">+</span> <span class="s">&quot;.db&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="nb">type</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">q</span><span class="p">)</span> <span class="o">+</span> <span class="s">&quot;.db&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">False</span><span class="p">}</span>
         <span class="n">aggIn</span><span class="p">[</span><span class="s">&quot;db&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img.db&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">False</span><span class="p">}</span>
-        <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;sql_aggregate1&quot;</span><span class="p">,</span> <span class="s">&quot;ih-sql-aggregate&quot;</span><span class="p">,</span> <span class="n">aggIn</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--inputs&quot;</span><span class="p">:</span> <span class="s">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">aggIn</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="s">&quot;file&quot;</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">aggIn</span> <span class="k">if</span> <span class="n">x</span> <span class="o">!=</span> <span class="s">&quot;db&quot;</span><span class="p">])},</span> <span class="n">binDep</span><span class="p">)</span>
-        <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;sql_aggregate1&quot;</span><span class="p">,</span> <span class="s">&quot;ih-sql-aggregate&quot;</span><span class="p">,</span> <span class="n">aggIn</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--inputs&quot;</span><span class="p">:</span> <span class="s">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">aggIn</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="s">&quot;file&quot;</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">aggIn</span> <span class="k">if</span> <span class="n">x</span> <span class="o">!=</span> <span class="s">&quot;db&quot;</span><span class="p">])},</span> <span class="n">binDep</span><span class="p">,</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">)</span>
+        <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;sql_aggregate1&quot;</span><span class="p">,</span> <span class="s">&quot;ih-sql-aggregate&quot;</span><span class="p">,</span> <span class="n">aggIn</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;img2.db&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img2.db&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">False</span><span class="p">}},</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--output&quot;</span><span class="p">:</span> <span class="s">&quot;img2.db&quot;</span><span class="p">,</span> <span class="s">&quot;--inputs&quot;</span><span class="p">:</span> <span class="s">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">aggIn</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="s">&quot;file&quot;</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">aggIn</span> <span class="k">if</span> <span class="n">x</span> <span class="o">!=</span> <span class="s">&quot;db&quot;</span><span class="p">])},</span> <span class="n">binDep</span><span class="p">)</span>
+        <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;sql_aggregate1&quot;</span><span class="p">,</span> <span class="s">&quot;ih-sql-aggregate&quot;</span><span class="p">,</span> <span class="n">aggIn</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;img2.db&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img2.db&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">False</span><span class="p">}},</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--output&quot;</span><span class="p">:</span> <span class="s">&quot;img2.db&quot;</span><span class="p">,</span> <span class="s">&quot;--inputs&quot;</span><span class="p">:</span> <span class="s">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">aggIn</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="s">&quot;file&quot;</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">aggIn</span> <span class="k">if</span> <span class="n">x</span> <span class="o">!=</span> <span class="s">&quot;db&quot;</span><span class="p">])},</span> <span class="n">binDep</span><span class="p">,</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">)</span>
         
         <span class="k">if</span> <span class="s">&quot;histogram-bin&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;extract&quot;</span><span class="p">]:</span>
             <span class="n">outputs</span> <span class="o">=</span> <span class="p">{}</span>
@@ -759,8 +831,8 @@
                 <span class="bp">self</span><span class="o">.</span><span class="n">_addFile</span><span class="p">(</span><span class="n">name</span> <span class="o">+</span> <span class="s">&quot;_hist_bins.json&quot;</span><span class="p">,</span> <span class="s">&quot;raw&quot;</span><span class="p">,</span> <span class="s">&quot;output&quot;</span><span class="p">)</span>
                 <span class="n">maprc</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">name</span> <span class="o">+</span> <span class="s">&quot;_hist_bins.json&quot;</span> <span class="o">+</span> <span class="s">&quot; file://&quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/&quot;</span> <span class="o">+</span> <span class="n">name</span> <span class="o">+</span> <span class="s">&quot;_hist_bins.json&quot;</span> <span class="o">+</span> <span class="s">&quot; pool=</span><span class="se">\&quot;</span><span class="s">local</span><span class="se">\&quot;\n</span><span class="s">&quot;</span><span class="p">)</span>
                 <span class="n">outputs</span><span class="p">[</span><span class="n">name</span> <span class="o">+</span> <span class="s">&quot;_hist_bins.json&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="n">name</span> <span class="o">+</span> <span class="s">&quot;_hist_bins.json&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">True</span><span class="p">}</span>
-            <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;bin_creation&quot;</span><span class="p">,</span> <span class="s">&quot;ih-stats-histogram-bin&quot;</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;db&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img.db&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">True</span><span class="p">},</span> <span class="s">&quot;extract.json&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;extract.json&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">False</span><span class="p">}},</span> <span class="n">outputs</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--options&quot;</span><span class="p">:</span> <span class="s">&quot;extract.json&quot;</span><span class="p">,</span> <span class="s">&quot;--intable&quot;</span><span class="p">:</span> <span class="s">&quot;images&quot;</span><span class="p">,</span> <span class="s">&quot;--outtable&quot;</span><span class="p">:</span> <span class="s">&quot;histogramBins&quot;</span><span class="p">,</span> <span class="s">&quot;--jsonwrite&quot;</span><span class="p">:</span> <span class="s">&quot;&quot;</span><span class="p">,</span> <span class="s">&quot;--overwrite&quot;</span><span class="p">:</span> <span class="s">&quot;&quot;</span><span class="p">},</span> <span class="p">[</span><span class="s">&quot;sql_aggregate1&quot;</span><span class="p">])</span>
-            <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;bin_creation&quot;</span><span class="p">,</span> <span class="s">&quot;ih-stats-histogram-bin&quot;</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;db&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img.db&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">True</span><span class="p">},</span> <span class="s">&quot;extract.json&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;extract.json&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">False</span><span class="p">}},</span> <span class="n">outputs</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--options&quot;</span><span class="p">:</span> <span class="s">&quot;extract.json&quot;</span><span class="p">,</span> <span class="s">&quot;--intable&quot;</span><span class="p">:</span> <span class="s">&quot;images&quot;</span><span class="p">,</span> <span class="s">&quot;--outtable&quot;</span><span class="p">:</span> <span class="s">&quot;histogramBins&quot;</span><span class="p">,</span> <span class="s">&quot;--jsonwrite&quot;</span><span class="p">:</span> <span class="s">&quot;&quot;</span><span class="p">,</span> <span class="s">&quot;--overwrite&quot;</span><span class="p">:</span> <span class="s">&quot;&quot;</span><span class="p">},</span> <span class="p">[</span><span class="s">&quot;sql_aggregate1&quot;</span><span class="p">],</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">)</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;bin_creation&quot;</span><span class="p">,</span> <span class="s">&quot;ih-stats-histogram-bin&quot;</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;db&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img2.db&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">True</span><span class="p">},</span> <span class="s">&quot;extract.json&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;extract.json&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">False</span><span class="p">}},</span> <span class="n">outputs</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--options&quot;</span><span class="p">:</span> <span class="s">&quot;extract.json&quot;</span><span class="p">,</span> <span class="s">&quot;--intable&quot;</span><span class="p">:</span> <span class="s">&quot;images&quot;</span><span class="p">,</span> <span class="s">&quot;--outtable&quot;</span><span class="p">:</span> <span class="s">&quot;histogramBins&quot;</span><span class="p">,</span> <span class="s">&quot;--jsonwrite&quot;</span><span class="p">:</span> <span class="s">&quot;&quot;</span><span class="p">,</span> <span class="s">&quot;--overwrite&quot;</span><span class="p">:</span> <span class="s">&quot;&quot;</span><span class="p">},</span> <span class="p">[</span><span class="s">&quot;sql_aggregate1&quot;</span><span class="p">])</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;bin_creation&quot;</span><span class="p">,</span> <span class="s">&quot;ih-stats-histogram-bin&quot;</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;db&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img2.db&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">True</span><span class="p">},</span> <span class="s">&quot;extract.json&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;extract.json&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">False</span><span class="p">}},</span> <span class="n">outputs</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--options&quot;</span><span class="p">:</span> <span class="s">&quot;extract.json&quot;</span><span class="p">,</span> <span class="s">&quot;--intable&quot;</span><span class="p">:</span> <span class="s">&quot;images&quot;</span><span class="p">,</span> <span class="s">&quot;--outtable&quot;</span><span class="p">:</span> <span class="s">&quot;histogramBins&quot;</span><span class="p">,</span> <span class="s">&quot;--jsonwrite&quot;</span><span class="p">:</span> <span class="s">&quot;&quot;</span><span class="p">,</span> <span class="s">&quot;--overwrite&quot;</span><span class="p">:</span> <span class="s">&quot;&quot;</span><span class="p">},</span> <span class="p">[</span><span class="s">&quot;sql_aggregate1&quot;</span><span class="p">],</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">)</span>
             
             <span class="n">binDep</span> <span class="o">=</span> <span class="p">[]</span>
             <span class="nb">map</span> <span class="o">=</span> <span class="p">{}</span>
@@ -780,11 +852,12 @@
                     <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="nb">type</span> <span class="o">+</span> <span class="s">&quot;_extractBins&quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">q</span><span class="p">),</span> <span class="s">&quot;ih-extract-multi&quot;</span><span class="p">,</span> <span class="n">exInput</span><span class="p">[</span><span class="nb">type</span><span class="p">][</span><span class="n">q</span><span class="p">],</span> <span class="p">{},</span> <span class="n">arguments</span><span class="p">,</span> <span class="p">[</span><span class="s">&quot;bin_creation&quot;</span><span class="p">])</span>
                     <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="nb">type</span> <span class="o">+</span> <span class="s">&quot;_extractBins&quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">q</span><span class="p">),</span> <span class="s">&quot;ih-extract-multi&quot;</span><span class="p">,</span> <span class="n">exInput</span><span class="p">[</span><span class="nb">type</span><span class="p">][</span><span class="n">q</span><span class="p">],</span> <span class="p">{},</span> <span class="n">arguments</span><span class="p">,</span> <span class="p">[</span><span class="s">&quot;bin_creation&quot;</span><span class="p">],</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">)</span>
                     <span class="n">binDep</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">type</span> <span class="o">+</span> <span class="s">&quot;_extractBins&quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">q</span><span class="p">))</span>
-            <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;sql_aggregate2&quot;</span><span class="p">,</span> <span class="s">&quot;ih-sql-aggregate&quot;</span><span class="p">,</span> <span class="n">aggIn</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--inputs&quot;</span><span class="p">:</span> <span class="s">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">aggIn</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="s">&quot;file&quot;</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">aggIn</span> <span class="k">if</span> <span class="n">x</span> <span class="o">!=</span> <span class="s">&quot;db&quot;</span><span class="p">])},</span> <span class="n">binDep</span><span class="p">)</span>
-            <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;sql_aggregate2&quot;</span><span class="p">,</span> <span class="s">&quot;ih-sql-aggregate&quot;</span><span class="p">,</span> <span class="n">aggIn</span><span class="p">,</span> <span class="p">{},</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--inputs&quot;</span><span class="p">:</span> <span class="s">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">aggIn</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="s">&quot;file&quot;</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">aggIn</span> <span class="k">if</span> <span class="n">x</span> <span class="o">!=</span> <span class="s">&quot;db&quot;</span><span class="p">])},</span> <span class="n">binDep</span><span class="p">,</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">)</span>
+            <span class="n">aggIn</span><span class="p">[</span><span class="s">&quot;db&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img2.db&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">False</span><span class="p">}</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;sql_aggregate2&quot;</span><span class="p">,</span> <span class="s">&quot;ih-sql-aggregate&quot;</span><span class="p">,</span> <span class="n">aggIn</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;img3.db&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img3.db&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">True</span><span class="p">}},</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--output&quot;</span><span class="p">:</span> <span class="s">&quot;img3.db&quot;</span><span class="p">,</span> <span class="s">&quot;--inputs&quot;</span><span class="p">:</span> <span class="s">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">aggIn</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="s">&quot;file&quot;</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">aggIn</span> <span class="k">if</span> <span class="n">x</span> <span class="o">!=</span> <span class="s">&quot;db&quot;</span><span class="p">])},</span> <span class="n">binDep</span><span class="p">)</span>
+            <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;sql_aggregate2&quot;</span><span class="p">,</span> <span class="s">&quot;ih-sql-aggregate&quot;</span><span class="p">,</span> <span class="n">aggIn</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;img3.db&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img3.db&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">True</span><span class="p">}},</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--output&quot;</span><span class="p">:</span> <span class="s">&quot;img3.db&quot;</span><span class="p">,</span> <span class="s">&quot;--inputs&quot;</span><span class="p">:</span> <span class="s">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">aggIn</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="s">&quot;file&quot;</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">aggIn</span> <span class="k">if</span> <span class="n">x</span> <span class="o">!=</span> <span class="s">&quot;db&quot;</span><span class="p">])},</span> <span class="n">binDep</span><span class="p">,</span> <span class="n">dax</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">exdax</span><span class="p">)</span>
         
         <span class="n">z</span> <span class="o">=</span> <span class="mi">2</span> <span class="k">if</span> <span class="s">&quot;histogram-bin&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">workflow</span><span class="p">[</span><span class="s">&quot;extract&quot;</span><span class="p">]</span> <span class="k">else</span> <span class="mi">1</span>
-        <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;error-log&quot;</span><span class="p">,</span> <span class="s">&quot;ih-error-log&quot;</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;db&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img.db&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">False</span><span class="p">}},</span> <span class="p">{</span><span class="s">&quot;output&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img.log&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">True</span><span class="p">}},</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--output&quot;</span><span class="p">:</span> <span class="s">&quot;output&quot;</span><span class="p">},</span> <span class="p">[</span><span class="s">&quot;sql_aggregate&quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)])</span>
+        <span class="bp">self</span><span class="o">.</span><span class="n">_addJob</span><span class="p">(</span><span class="s">&quot;error-log&quot;</span><span class="p">,</span> <span class="s">&quot;ih-error-log&quot;</span><span class="p">,</span> <span class="p">{</span><span class="s">&quot;db&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img3.db&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">False</span><span class="p">}},</span> <span class="p">{</span><span class="s">&quot;output&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s">&quot;file&quot;</span><span class="p">:</span> <span class="s">&quot;img.log&quot;</span><span class="p">,</span> <span class="s">&quot;transfer&quot;</span><span class="p">:</span> <span class="bp">True</span><span class="p">}},</span> <span class="p">{</span><span class="s">&quot;--db&quot;</span><span class="p">:</span> <span class="s">&quot;db&quot;</span><span class="p">,</span> <span class="s">&quot;--output&quot;</span><span class="p">:</span> <span class="s">&quot;output&quot;</span><span class="p">},</span> <span class="p">[</span><span class="s">&quot;sql_aggregate&quot;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">z</span><span class="p">)])</span>
         <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span> <span class="o">+</span> <span class="s">&quot;/workflow.dax&quot;</span><span class="p">,</span> <span class="s">&quot;w&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">wh</span><span class="p">:</span>
             <span class="bp">self</span><span class="o">.</span><span class="n">dax</span><span class="o">.</span><span class="n">writeXML</span><span class="p">(</span><span class="n">wh</span><span class="p">)</span>
         <span class="k">return</span>
@@ -811,12 +884,12 @@
 <span class="s">                        </span>
 <span class="s">                        pegasus.transfer.links = true</span>
 <span class="s">                        </span>
-<span class="s">                        pegasus.data.configuration = sharedfs</span>
+<span class="s">                        pegasus.data.configuration = </span><span class="si">%s</span><span class="s"></span>
 <span class="s">                        </span>
 <span class="s">                        pegasus.dir.storage.mapper = Replica</span>
 <span class="s">                        pegasus.dir.storage.mapper.replica = File</span>
 <span class="s">                        pegasus.dir.storage.mapper.replica.file = </span><span class="si">%s</span><span class="s">/map.rc</span>
-<span class="s">                        &quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span><span class="p">))</span>
+<span class="s">                        &quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span><span class="p">,</span> <span class="s">&quot;nonsharedfs&quot;</span> <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span> <span class="k">else</span> <span class="s">&quot;sharedfs&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span><span class="p">))</span>
             <span class="n">wh</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">pegasusrc</span><span class="p">)</span>
         <span class="k">return</span>
     
@@ -825,17 +898,39 @@
 <span class="sd">            Creates the pegasus site catalog.  input/sites.xml</span>
 <span class="sd">        &quot;&quot;&quot;</span>
         <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span> <span class="o">+</span> <span class="s">&quot;/sites.xml&quot;</span><span class="p">,</span> <span class="s">&quot;w&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">wh</span><span class="p">:</span>
-            <span class="n">sites</span> <span class="o">=</span> <span class="s">&quot;&quot;&quot;</span><span class="se">\</span>
-<span class="s">             &lt;sitecatalog xmlns=&quot;http://pegasus.isi.edu/schema/sitecatalog&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://pegasus.isi.edu/schema/sitecatalog http://pegasus.isi.edu/schema/sc-4.0.xsd&quot; version=&quot;4.0&quot;&gt;</span>
-<span class="s">    </span>
-<span class="s">                        &lt;site  handle=&quot;local&quot; arch=&quot;x86_64&quot; os=&quot;LINUX&quot;&gt;</span>
-<span class="s">                            &lt;directory type=&quot;shared-scratch&quot; path=&quot;</span><span class="si">%s</span><span class="s">&quot;&gt;</span>
-<span class="s">                                &lt;file-server operation=&quot;all&quot; url=&quot;file://</span><span class="si">%s</span><span class="s">&quot; /&gt;</span>
-<span class="s">                            &lt;/directory&gt;</span>
-<span class="s">                            &lt;directory type=&quot;local-storage&quot; path=&quot;</span><span class="si">%s</span><span class="s">&quot;&gt;</span>
-<span class="s">                                &lt;file-server operation=&quot;all&quot; url=&quot;file://</span><span class="si">%s</span><span class="s">&quot; /&gt;</span>
-<span class="s">                            &lt;/directory&gt;</span>
-<span class="s">                        &quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/imgproc/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/imgproc/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/&quot;</span><span class="p">)</span>
+            <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+                <span class="n">sites</span> <span class="o">=</span> <span class="s">&quot;&quot;&quot;</span><span class="se">\</span>
+<span class="s">                &lt;sitecatalog version=&quot;4.0&quot; xmlns=&quot;http://pegasus.isi.edu/schema/sitecatalog&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://pegasus.isi.edu/schema/sitecatalog http://pegasus.isi.edu/schema/sc-4.0.xsd&quot;&gt;</span>
+<span class="s">                    &lt;site handle=&quot;local&quot; arch=&quot;x86_64&quot; os=&quot;LINUX&quot;&gt;</span>
+<span class="s">                        &lt;directory type=&quot;shared-scratch&quot; path=&quot;</span><span class="si">%s</span><span class="s">&quot;&gt;</span>
+<span class="s">                            &lt;file-server operation=&quot;all&quot; url=&quot;file://</span><span class="si">%s</span><span class="s">&quot; /&gt;</span>
+<span class="s">                        &lt;/directory&gt;</span>
+<span class="s">                        &lt;directory type=&quot;local-storage&quot; path=&quot;</span><span class="si">%s</span><span class="s">&quot;&gt;</span>
+<span class="s">                            &lt;file-server operation=&quot;all&quot; url=&quot;file://</span><span class="si">%s</span><span class="s">&quot; /&gt;</span>
+<span class="s">                        &lt;/directory&gt;</span>
+<span class="s">                        &lt;profile namespace=&quot;pegasus&quot; key=&quot;SSH_PRIVATE_KEY&quot;&gt;</span><span class="si">%s</span><span class="s">&lt;/profile&gt;</span>
+<span class="s">                    &lt;/site&gt;</span>
+<span class="s">                    &lt;site handle=&quot;stash&quot; arch=&quot;x86_64&quot; os=&quot;LINUX&quot;&gt;</span>
+<span class="s">                        &lt;directory type=&quot;shared-scratch&quot; path=&quot;</span><span class="si">%s</span><span class="s">&quot;&gt;</span>
+<span class="s">                            &lt;file-server operation=&quot;get&quot; url=&quot;stash://</span><span class="si">%s</span><span class="s">&quot;/&gt;</span>
+<span class="s">                            &lt;file-server operation=&quot;put&quot; url=&quot;scp://</span><span class="si">%s</span><span class="s">@login02.osgconnect.net/</span><span class="si">%s</span><span class="s">&quot;/&gt;</span>
+<span class="s">                        &lt;/directory&gt;</span>
+<span class="s">                    &lt;/site&gt;</span>
+<span class="s">                    &lt;site handle=&quot;condorpool&quot; arch=&quot;x86_64&quot; os=&quot;LINUX&quot;&gt;</span>
+<span class="s">                        </span>
+<span class="s">                    &quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/imgproc/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/imgproc/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;osg&quot;</span><span class="p">][</span><span class="s">&quot;ssh&quot;</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/staging/&quot;</span><span class="p">,</span> <span class="s">&quot;/&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/staging/&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">)[</span><span class="mi">2</span><span class="p">:]),</span> <span class="n">getpass</span><span class="o">.</span><span class="n">getuser</span><span class="p">(),</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/staging/&quot;</span><span class="p">)</span>
+            <span class="k">else</span><span class="p">:</span>
+                <span class="n">sites</span> <span class="o">=</span> <span class="s">&quot;&quot;&quot;</span><span class="se">\</span>
+<span class="s">                 &lt;sitecatalog xmlns=&quot;http://pegasus.isi.edu/schema/sitecatalog&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot;http://pegasus.isi.edu/schema/sitecatalog http://pegasus.isi.edu/schema/sc-4.0.xsd&quot; version=&quot;4.0&quot;&gt;</span>
+<span class="s">        </span>
+<span class="s">                            &lt;site  handle=&quot;local&quot; arch=&quot;x86_64&quot; os=&quot;LINUX&quot;&gt;</span>
+<span class="s">                                &lt;directory type=&quot;shared-scratch&quot; path=&quot;</span><span class="si">%s</span><span class="s">&quot;&gt;</span>
+<span class="s">                                    &lt;file-server operation=&quot;all&quot; url=&quot;file://</span><span class="si">%s</span><span class="s">&quot; /&gt;</span>
+<span class="s">                                &lt;/directory&gt;</span>
+<span class="s">                                &lt;directory type=&quot;local-storage&quot; path=&quot;</span><span class="si">%s</span><span class="s">&quot;&gt;</span>
+<span class="s">                                    &lt;file-server operation=&quot;all&quot; url=&quot;file://</span><span class="si">%s</span><span class="s">&quot; /&gt;</span>
+<span class="s">                                &lt;/directory&gt;</span>
+<span class="s">                            &quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/imgproc/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/imgproc/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/output/&quot;</span><span class="p">)</span>
             <span class="k">for</span> <span class="n">namespace</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;profile&quot;</span><span class="p">]:</span>
                 <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;profile&quot;</span><span class="p">][</span><span class="n">namespace</span><span class="p">]:</span>
                     <span class="n">val</span> <span class="o">=</span> <span class="s">&quot;:&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;profile&quot;</span><span class="p">][</span><span class="n">namespace</span><span class="p">][</span><span class="n">key</span><span class="p">])</span> <span class="k">if</span> <span class="s">&quot;path&quot;</span> <span class="ow">in</span> <span class="n">key</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">&quot;profile&quot;</span><span class="p">][</span><span class="n">namespace</span><span class="p">][</span><span class="n">key</span><span class="p">]</span>
@@ -859,14 +954,16 @@
 <span class="s">                    fi</span>
 <span class="s">                    plan=`pegasus-plan </span><span class="se">\\</span><span class="s"></span>
 <span class="s">                    --conf &quot;</span><span class="si">%s</span><span class="s">&quot; </span><span class="se">\\</span><span class="s"></span>
-<span class="s">                    --sites local </span><span class="se">\\</span><span class="s"></span>
+<span class="s">                    --sites &quot;</span><span class="si">%s</span><span class="s">&quot; </span><span class="se">\\</span><span class="s"></span>
 <span class="s">                    --dir &quot;</span><span class="si">%s</span><span class="s">&quot; </span><span class="se">\\</span><span class="s"></span>
 <span class="s">                    --output-site local </span><span class="se">\\</span><span class="s"></span>
 <span class="s">                    --dax &quot;$DAX&quot; </span><span class="se">\\</span><span class="s"></span>
 <span class="s">                    --randomdir </span><span class="se">\\</span><span class="s"></span>
-<span class="s">                    &quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span> <span class="o">+</span> <span class="s">&quot;/extract.dax&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span> <span class="o">+</span> <span class="s">&quot;/workflow.dax&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span> <span class="o">+</span> <span class="s">&quot;/conf.rc&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/imgproc&quot;</span><span class="p">))</span>
+<span class="s">                    &quot;&quot;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span> <span class="o">+</span> <span class="s">&quot;/extract.dax&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span> <span class="o">+</span> <span class="s">&quot;/workflow.dax&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">loc</span> <span class="o">+</span> <span class="s">&quot;/conf.rc&quot;</span><span class="p">,</span> <span class="s">&quot;condorpool&quot;</span> <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span> <span class="k">else</span> <span class="s">&quot;local&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">basepath</span> <span class="o">+</span> <span class="s">&quot;/work/imgproc&quot;</span><span class="p">))</span>
             <span class="k">if</span> <span class="s">&quot;cluster&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
                 <span class="n">submit</span> <span class="o">+=</span> <span class="s">&quot;&quot;&quot;--cluster label </span><span class="se">\\\n</span><span class="s">&quot;&quot;&quot;</span>
+            <span class="k">if</span> <span class="s">&quot;osg&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
+                <span class="n">submit</span> <span class="o">+=</span> <span class="s">&quot;&quot;&quot;--staging-site stash </span><span class="se">\\\n</span><span class="s">&quot;&quot;&quot;</span>
             <span class="n">submit</span> <span class="o">+=</span> <span class="n">textwrap</span><span class="o">.</span><span class="n">dedent</span><span class="p">(</span><span class="s">&quot;&quot;&quot;</span><span class="se">\</span>
 <span class="s">                    --submit`</span>
 <span class="s">                    </span>
diff --git a/docs/build/html/_modules/index.html b/docs/build/html/_modules/index.html
index 32ababe99bd774195a65949f91c28ac4480af48b..99221b90a5c8d17839b5a30941c59abb3ff33cce 100644
--- a/docs/build/html/_modules/index.html
+++ b/docs/build/html/_modules/index.html
@@ -73,6 +73,8 @@
 <li class="toctree-l1"><a class="reference internal" href="../ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/_modules/plantcv/imgproc.html b/docs/build/html/_modules/plantcv/imgproc.html
index 750778867323855a8ead882328883dca13a7ad7d..effe4983a6ac7f9c9892560886695ceecbdcc51c 100644
--- a/docs/build/html/_modules/plantcv/imgproc.html
+++ b/docs/build/html/_modules/plantcv/imgproc.html
@@ -74,6 +74,8 @@
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/_modules/plantcv/statistics.html b/docs/build/html/_modules/plantcv/statistics.html
index 8da0a4c2d44a559451d884600801f9fb67ed8c6f..ecab13322c53f08a10d732355ce6aaa39bd528f4 100644
--- a/docs/build/html/_modules/plantcv/statistics.html
+++ b/docs/build/html/_modules/plantcv/statistics.html
@@ -74,6 +74,8 @@
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/_modules/plantcv/workflow.html b/docs/build/html/_modules/plantcv/workflow.html
index b4d1731aa6cbcf3b9b75339f0a90fc00d4656cf7..4a9c5a7169ce84247fbd56f69201a63c1b6c3ab2 100644
--- a/docs/build/html/_modules/plantcv/workflow.html
+++ b/docs/build/html/_modules/plantcv/workflow.html
@@ -74,6 +74,8 @@
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="../../viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/_sources/arkansas_workshop_july_2015.txt b/docs/build/html/_sources/arkansas_workshop_july_2015.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c60e9092c33955588d20fa74bda5115be87d28c4
--- /dev/null
+++ b/docs/build/html/_sources/arkansas_workshop_july_2015.txt
@@ -0,0 +1,383 @@
+.. |br| raw:: html
+
+	<br />
+
+Arkansas Workshop July 2015
+============================
+
+Hello Arkansas State!  This workshop covers basic command line instructions and local processing of an image from LemnaTec.  Either look at the corresponding part of the  installation page for your computer (`Mac OS X <installation.html#mac-osx>`_, `Windows <installation.html#windows>`_) or head to the next section. 
+
+Command Line Crash Course
+-------------------------
+If you are unfamiliar with the command line, or have never opened the Terminal or Command Prompt app before, this section is for you.  There are several useful features available while using Image Harvest through a Python interpreter, which requires a small amount of command line knowledge -- namely the ability to navigate through directories.  For all operating systems, files are structured hierarchically in directories.  A directory almost always has a parent (represented by ".."), and it may contain files or more sub-directories.  The only directory not that doesn't have a parent is the root directory which is "/" for Mac OS X and Linux, and "C:\\" for Windows users.  Since all directories are children of the root directory, you can write the path to any file all the way from the root.  These types of paths are absolute paths.  "/Users/username/Downloads/file.txt" and "C:\\Users\\username\\Downlaods\\file.txt" are both examples of absolute paths.  The counterpart to absolute paths is relative paths, which is a path to any file written from where you are currently located.  If you are currently located in your Downloads folder, the relative path "file.txt" is the same as the absolute path "/Users/username/Downloads/file.txt".  These concepts apply to all operating systems, however, each uses different commands for achieving directory navigation.
+ 
+Mac OS X
+#########
+First and foremost, the terminal app is located at /Applications/Utilities/Terminal.app.  There are only 3 important commands:
+
+* cd -- Which stands for "change directory".  This command allows you to move your current location to a new directory as specified by an argument.  It can be either an absolute or a relative path.
+* ls -- Which stands for "list".  This command lists all the files and folders in the current directory.
+* pwd -- Which stands for "print working directory", and prints your current directory's absolute path. 
+
+Examples:
+
+.. code-block:: bash
+
+    # Move to your home folder.
+    cd /Users/username/
+    # Move to your downloads folder from your home folder.
+    cd Downloads
+    # Move up a folder -- back to your home folder.
+    cd ..
+    # List files in your home folder
+    ls
+    # List files in your home folder as a list
+    ls -al
+    # List files in your home folder as a list with coloring
+    ls -alG
+    # Print the absolute path to your home folder.
+    pwd
+
+
+Windows
+########
+The Command Prompt app can be opened by typing cmd into the windows search bar.  There are only 2 important commands:
+
+* cd -- Which stands for "change directory".  This command allows you to move your current location to a new directory as specified by an argument.  It can be either an absolute or a relative path.
+* dir -- Which stands for "directory".  This command both prints your current location, and prints files and directories in your current location.
+
+Examples:
+
+.. code-block:: bash
+    
+    # Move to your home folder
+    cd C:\\Users\\username
+    # Move to your downloads folder from your home folder.
+    cd Downloads
+    # Move up a folder -- back to your home folder.
+    cd ..
+    # List the path to your home folder, and the files in your home folder.
+    dir
+
+First Image
+------------
+If you have not already, look at the corresponding part of the installation page for your computer (`Mac OS X <installation.html#mac-osx>`_, `Windows <installation.html#windows>`_).  Once you've got Image Harvest installed, download the following image:
+
+:download:`First Image <../images/sample/rgbsv1.png>`
+
+Once it's saved, navigate to it from the command line -- By default either /Users/username/Downloads/ or C:\\Users\\username\\Downloads.  From there open up a python interpreter by typing the following command:
+
+.. code-block:: bash
+
+    python
+
+You should see something like:
+
+.. code-block:: bash
+
+    Python 2.7.6 (default, Sep  9 2014, 15:04:36)
+    [GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
+    Type "help", "copyright", "credits" or "license" for more information.
+    >>>
+
+The 3 right angle brackets are where you type your input.  Within the python interpreter
+command line tools won't work, so when loading a file you need to already know it's path
+or it will be difficult to find.  Execute the following lines from the python interpreter:
+
+.. code-block:: python
+
+    # Import the Image Harvest library
+    import ih.imgproc
+    # Load your downloaded image!
+    plant = ih.imgproc.Image("rgbsv1.png") 
+    # Show your plant!
+    plant.show()
+    # Wait for user input, then destroy the window
+    plant.wait()
+
+You should see a window named "window 1" pop up with a smaller version of your image in it!
+By calling the :py:meth:`~ih.imgproc.Image.wait` method, the window will be displayed until you press any key, and control is taken away from the python interpreter.  Every processing script begins by loading the library, and loading the image, and all Image Harvest functions are performed on a loaded image.  Using the python interpreter provides some powerful tools to adjust your analysis on the fly and test out function parameters through the use of "states".  
+
+.. code-block:: python
+    
+    # Save the current state under the name "base"
+    plant.save("base")
+    # Convert the plant to grayscale
+    plant.convertColor("bgr", "gray")
+    # Save the current state under the name "gray"
+    plant.save("gray")
+    # Threshold with a questionable value!
+    plant.threshold(255)
+    plant.show()
+    plant.wait()
+
+If done correctly, you should see a window named "window 2" that's completely black.  The threshold function thresholds by pixel intensity, which is an integer from 0 to 255, so thresholding by 255 means no pixels should make it through.
+Since we saved states ("base" and "gray"), we can restore a previous state and try the thresholding operation again with adjusted parameters:
+
+.. code-block:: python
+
+    # Restore the gray state
+    plant.restore("gray")
+    # Threshold round 2
+    plant.threshold(190)
+    plant.show()
+    plant.wait()
+
+You should see a window name "window 3" that's only black and white, and you should be able to see the outline of the plant in black.  We can utilize states for more than just restoring a previous image:
+
+.. code-block:: python
+
+    # Save the black & white state!
+    plant.save("binary")
+    # Invert the color, display with name
+    plant.bitwise_not()
+    plant.show("Inverted Mask")
+    # Convert the mask to bgr, combine it with the "base" state
+    plant.convertColor("gray", "bgr")
+    plant.bitwise_and("base")
+    # Save the image and display it
+    plant.save("recolored")
+    plant.show("Recolored Image")
+    plant.wait()
+
+.. image:: ../../examples/workshops/arkansas_july_2015/inverted.png
+    :align: left
+
+.. image:: ../../examples/workshops/arkansas_july_2015/recolored.png
+    :align: right
+
+.. raw:: html
+
+    <div class="row" style="clear:both;"></div><br />
+
+This time, you should see two windows pop up, one named "Inverted Mask" and the other named "Recolored Image".  The inverted mask window shows our inverted thresholded image, and the recolored image window shows the final output of combining our mask with our base image.  We keep all the pixels that are in the mask, but we use the colors of the base image.  Utilizing a few more functions, we can finish the processing of our first image:
+
+.. code-block:: python
+
+    # Crop the pot out of the image.
+    # ROI is of the form [ystart, yend, xstart, xend]
+    plant.crop([300, 2150, 0, "x"])
+    plant.save("cropped")
+    plant.show("Cropped Image")
+    # Resize the image to just the plant
+    # See following paragraph for more info on contourCut
+    plant.contourCut("cropped", resize = True)
+    plant.show("Final Image")
+    plant.write("final.png")
+    plant.wait()
+
+
+.. image:: ../../examples/workshops/arkansas_july_2015/cropped.png
+    :align: left
+
+.. image:: ../../examples/workshops/arkansas_july_2015/final.png
+    :align: right
+
+
+.. raw:: html
+
+    <div class="row" style="clear:both;"></div><br />
+
+You should see your final displayed image!  The :py:meth:`~ih.imgproc.Image.contourCut` function crops an image based on contours, or grouped areas of pixels, and only keeps contours in the image that have a minimum required area.  Since the plant is completely connected (unless processing has removed some pixels), it should have a large contour area, and thus is kept within the image.  Finally, we write our image with the name "final.png".
+
+Python Script
+-------------
+
+:download:`Download Script <../../examples/workshops/arkansas_july_2015/firstimage.py>`
+
+:download:`Download Image <../images/sample/rgbsv1.png>` (same as above)
+
+This script performs exactly the process we worked through only as a standalone python script.  Update the image path accordingly, and run it to see the same results, as well as windows for each step.
+
+
+.. code-block:: python
+
+    # Load the library & image
+    import ih.imgproc
+    plant = ih.imgproc.Image("/path/to/your/image")
+    # Save & show the base image
+    plant.save("base")
+    plant.show("Base")
+    # Convert to gray, save the image
+    plant.convertColor("bgr", "gray")
+    plant.save("gray")
+    plant.show("Grayscale")
+    # Threshold the image incorrectly AND correctly 
+    plant.threshold(255)
+    plant.show("Threshold 255")
+    plant.restore("gray")
+    plant.threshold(190)
+    plant.save("binary")
+    plant.show("Threshold 190")
+    # Recolor the image
+    plant.bitwise_not()
+    plant.convertColor("gray", "bgr")
+    plant.bitwise_and("base")
+    plant.save("recolor")
+    plant.show("Recolored Image")
+    # Crop the image, produce the final output
+    plant.crop([300, 2150, 0, "x"])
+    plant.save("cropped")
+    plant.show("Cropped")
+    plant.contourCut("cropped", resize = True)
+    plant.show("Final")
+    plant.write("final.png")
+    plant.wait()
+
+
+Day 2
+------
+Now that we have everything installed, we'll work through a pipeline for an image, extract some data, and compare to LemnaTec.
+
+:download:`Team 1 Rice 0_0_2 <../../examples/workshops/arkansas_july_2015/0_0_2.png>`
+
+:download:`The Pipeline <../../examples/workshops/arkansas_july_2015/pipeline.py>`
+
+The pipline:
+
+.. code-block:: python
+
+    import ih.imgproc
+
+    # base plant
+    plant = ih.imgproc.Image("0_0_2.png")
+    plant.save("base")
+    plant.show("base")
+
+    # blur
+    plant.blur((5, 5))
+    plant.save("blur")
+    plant.show("Blur")
+
+    # meanshift
+    plant.meanshift(4, 4, 40)
+    plant.save("shift")
+    plant.show("Meanshift")
+
+    # colorFilter
+    plant.colorFilter("(((g > r) and (g > b)) and (((r + g) + b) < 400))")
+    plant.colorFilter("(((r max g) max b) - ((r min g) min b)) > 12)")
+    plant.save("cf")
+    plant.show("Color filter")
+
+    # contourCut
+    plant.contourCut("cf", basemin = 3000, resize = True)
+    plant.save("cut")
+    plant.show("Contour Cut")
+
+    # recolor
+    plant.convertColor("bgr", "gray")
+    plant.threshold(0)
+    plant.convertColor("gray", "bgr")
+    plant.bitwise_and("base")
+    plant.write("final.png")
+    plant.show("Final")
+
+    print plant.extractPixels()
+    print plant.extractConvexHull()
+
+    plant.wait()
+
+That's a lot of code.  Let's break it down piece by piece:
+
+Loading
+#######
+
+.. code-block:: python
+
+    import ih.imgproc
+
+    # base plant
+    plant = ih.imgproc.Image("0_0_2.png")
+    plant.save("base")
+    plant.show("base")
+
+This part should be fairly familiar -- we load the Image Harvest library with import ih.imgproc, we load our image "0_0_2.png", and we save & display it under the name "base".  
+
+Blur
+#####
+
+.. code-block:: python
+
+    # blur
+    plant.blur((5, 5))
+    plant.save("blur")
+    plant.show("Blur") 
+
+Here we call the :py:meth:`~ih.imgproc.Image.blur` function -- which does exactly that.  Blur can take a few arguments, but the most important and only required argument is the first which specifies the kernel size -- a larger kernel means a more blurry output image.  The kernel size is represented as two numbers: (width, height), and both the width and height must be odd and positive.  Try blurring with a kernel size of (15, 15) instead of (5, 5).
+
+Why blur?  Blurring greatly reduces the noise in an image, which is random variations of pixel colors.  Reducing these variations helps us to more easily define a region in an image.  Look at the inside of the pot for example -- the edges between individual rocks have become much less distinct as a result of the blurring, which makes it easier to percieve as a single continuous region.  The next step continues to reduce variation and separate regions from each other.
+
+Meanshift
+#########
+
+.. code-block:: python
+
+    # meanshift
+    plant.meanshift(4, 4, 40)
+    plant.save("shift")
+    plant.show("Meanshift")
+
+Here we call the :py:meth:`~ih.imgproc.Image.meanshift` function, which performs mean shift segmentation of the image.  Mean shift segmentation groups regions in an image that are geographically close AND close in color.  The first two arguments define the geographically distance, and the third argument defines the color variation allowed. 
+
+Why meanshift?  Meanshift makes the next step in grouping an image into regions.  In this case, we have some very easily defined regions that are close both geographically and close in color.  The plant itself is completely connected and a similar shade of green.  The interior of the pot is contained within a single circle in the image, and is made of similarly colored rocks.  Both of these regions become much more uniform, and thus much easier to process as a result of this step.
+
+Color Filter
+############
+
+.. code-block:: python
+    
+    # colorFilter
+    plant.colorFilter("(((g > r) and (g > b)) and (((r + g) + b) < 400))")
+    plant.colorFilter("(((r max g) max b) - ((r min g) min b)) > 12)")
+    plant.save("cf")
+    plant.show("Color filter")
+
+Here we call the :py:meth:`~ih.imgproc.Image.colorFilter` function, which solves arbitrary color logic and then applies it to the image.  What does that mean?  Effectively, we create a color pattern, and we look for all pixels that match this color pattern.  So this pattern: "((g > r) and (g > b))", reads as: "Pixels whose green value is greater than their red value AND whose green value is greater than their blue value."  In natural language: "Pixels that are predominantely green."  The next pattern: "(((r + g) + b) < 400))", reads as: "Pixels whose red value plus green value plus blue value is less than 400."  In natural language: "Pixels that aren't too bright."  Finally we have the pattern: "(((r max g) max b) - ((r min g) min b)) > 12)", which reads as: "Pixels whose maximum value of r,g,b minus mimim value of r,g,b is greater than 12".  In natural language: "Pixels that aren't white, gray, or black."
+
+Why colorFilter?  Processing power.  The colorFilter function is very fast, and can evaluate and apply complex logic in less than a second.  Additionally, since the function evalutes logic on a per-pixel basis, it can adapt to brightness changes or noise in images that a definite color range might miss.
+
+Contour Cut
+###########
+
+.. code-block:: python
+
+    # contourCut
+    plant.contourCut("cf", basemin = 3000, resize = True)
+    plant.save("cut")
+    plant.show("Contour Cut")
+
+Here we call the :py:meth:`~ih.imgproc.Image.contourCut` function, which crops an image based on contours in an image, which are connected regions of pixels.  The function searches for all contours in the image that are greater than the size of the basemin parameter, and crops the image to fit those contours.
+
+Why contourCut?  Removal of edge noise.  The plant itself is completely connected, and thus will have the largest contour in the image by far.  Utilizing this, we can find a value that will keep our plant in the image, while removing a lot of edge noise from it.
+
+Recoloring
+##########
+
+.. code-block:: python
+
+    # recolor
+    plant.convertColor("bgr", "gray")
+    plant.threshold(0)
+    plant.convertColor("gray", "bgr")
+    plant.bitwise_and("base")
+    plant.write("final.png")
+    plant.show("Final") 
+
+What's really happening here, is we are creating a mask of our current image, and then overlaying it on our base image to extract our original color.  Blurring and segmenting our image changed its original color, and we want to restore that.  The first 3 lines create the mask.  We first convert the image to grayscale with :py:meth:`~ih.imgproc.Image.convertColor`, and then :py:meth:`~ih.imgproc.Image.threhsold` with a value of 0.  By thresholding the image with a value of 0, we keep every pixel from our grayscale image that has an intensity of at least 1.  This means we keep every non-black pixel from our grayscale image.  We then convert the image back to "bgr" from "gray", however, this does NOT restore color to the image.  Our binary image only has a single channel (intensity), but our color image has 3 channels (b, g, r).  We can't overlay our mask while it only has a single channel, so we convert it to "bgr" to give it 3 channels.  We then use :py:meth:`ih.imgproc.Image.bitwise_and` to overaly our mask on our base image.
+
+Extraction
+##########
+
+.. code-block:: python
+
+    print plant.extractPixels()
+    print plant.extractConvexHull()
+
+The print function is native to python and simply outputs information to the screen.  The :py:meth:`~ih.imgproc.Image.extractPixels` function returns the total number of non-zero pixels in the image, and the :py:meth:`~ih.imgproc.Image.extractConvexHull` function returns the area of the convexHull surrounding all non-black pixels in the image.
+
+Extras
+------
+
+.. image:: ../../examples/workshops/arkansas_july_2015/shifted.png
+    :align: center
diff --git a/docs/build/html/_sources/ex_workflow_1.txt b/docs/build/html/_sources/ex_workflow_1.txt
index 5e754eb48e5ac8422779ab6c84b82705fd64d53c..3c2c79518f0d64ab05a6781e2dfc9a5695934aca 100644
--- a/docs/build/html/_sources/ex_workflow_1.txt
+++ b/docs/build/html/_sources/ex_workflow_1.txt
@@ -1,7 +1,7 @@
 .. raw:: html
 
 	<style> .red {color:red} .blue {color:blue} .green {color:green} .orange {color:orange} </style>
-	
+
 .. role:: red
 
 .. role:: blue
@@ -19,7 +19,7 @@ Workflow generation is designed specifically for high throughput
 data sets -- this example uses a data set of ~80,000 images.  Additionally,
 this tutorial serves to show how to setup and run a workflow, not
 explaining the analysis choices made when designing a workflow.  This workflow
-was created using experiment '0184 Uni Nebraska Rice 1' data, on 
+was created using experiment '0184 Uni Nebraska Rice 1' data, on
 Tusker at the Holland Computing Center.
 
 Final Templates
@@ -45,8 +45,8 @@ Here are several examples of paths to images:
 | /work/walia/common/ih/rawdata/0184 Uni Nebraska Rice 1/strain3/0184 Uni Nebraska Rice 1_023542-C_2013-09-05_05-18-33_455640/RGB SV1/0_0.png
 | /work/walia/common/ih/rawdata/0184 Uni Nebraska Rice 1/strain5/0184 Uni Nebraska Rice 1_023546-C_2013-08-21_05-22-52_432942/FLUO SV1/0_0.png
 | /work/walia/common/ih/rawdata/0184 Uni Nebraska Rice 1/strain93/0184 Uni Nebraska Rice 1_023722-S_2013-09-09_10-56-45_462980/RGB TV/0_0.png
-	
-There are a total of 436 strain folders, 36 sub folders in each strain folder, and 12 additional image-type folders.  For 
+
+There are a total of 436 strain folders, 36 sub folders in each strain folder, and 12 additional image-type folders.  For
 this experiment, we will be processing RGB SV1, RGB SV2, FLUO SV1, FLUO SV2, and RGB TV images for a total of 436 * 36 * 5 ~= 80,000 images.
 The image loading step takes care of two key problems posed by having large data sets (assuming correctly written template files).  First,
 it tracks all images, and loads them into a single database, making it very easy to find and process files in the future.  Second,
@@ -129,8 +129,8 @@ behind crawling.
 
 	"path": "/work/walia/common/ih/rawdata/0184 Uni Nebraska Rice 1/%null%/%null%_%idnum%-%idchar%_%date%/%imgname%/0_0.png",
 	"base": "/work/walia/common/ih/rawdata/0184 Uni Nebraska Rice 1/",
-    
-The first two definitions map our way through the rest of the template.  Above, we noted several important 
+
+The first two definitions map our way through the rest of the template.  Above, we noted several important
 pieces of information in the name of the directories.  We are doing exactly that here, except in a way that
 is more understandable to the computer.  We mark important places in the directory structure by using % signs,
 along with names.  The names themselves are not strictly checked, so use names that are easy to remember.
@@ -153,9 +153,9 @@ is simply where crawling should start.  It should be a subset of the "path" defi
 
 	"filetype": ".png",
 	"order": ["experiment", "id", "genotype", "date", "treatment", "imgname", "imtype", "path"],
-	
+
 The "filetype" definition is exactly that.  It searches for all files in the final path that end in the specified filetype.
-The "order" definition is the order in which values are stored in to the database.  It serves two purposes.  Thematically, 
+The "order" definition is the order in which values are stored in to the database.  It serves two purposes.  Thematically,
 you can organize your columns the same way you would data.  More importantly, it specifies which values are saved to the database.
 You can define any value in the "order" definition, however, there are **required** definitions as well.  In addition,
 although there are some optional column names, many of the statistics function expect a given format for data.
@@ -178,7 +178,7 @@ our "path" definition, to the names used in our "order" definition.  Let's look
 				"type": "value",
 				"value": "0184"
 			},
-			
+
 The first line simply shows how to start the data section.  Specifying '"data": {' shows that all further entries
 are specifically related to data-mapping.  Each value specified in the data section corresponds to a specific
 value in the "order" entry.  The values defined in the data section are NOT order dependent, but we include
@@ -186,7 +186,7 @@ them in the same order for ease of access.  Finally, remember that each of these
 Our first example is defining a value for "experiment".  It's important
 to note that "experiment" occurs in order.  The names of entries in the data section must match the value
 in the "order" entry exactly.  First we define the type of "experiment".  Type's of data keys can be defined
-as "value", "file", or "date".  Here, we define the type of experiment as a value.  This means that the value of 
+as "value", "file", or "date".  Here, we define the type of experiment as a value.  This means that the value of
 experiment will be saved as some combination of hard-coded characters, and identifiers, based on the "value" definition.
 In this case, we do not use identifiers in our "value" definition.  We simply save the value for experiment for every image
 as 0184.
@@ -197,7 +197,7 @@ as 0184.
 		"type": "value",
 		"value": "%idnum%-%idchar%"
 	},
-	
+
 Here, we define the "id" for each plant.  We also define it as type "value", but this time we use identifiers in
 the value.  This will load the identifiers from the path directly into the value for id.  Looking at our path definition and test path again:
 
@@ -218,11 +218,11 @@ into the output value.
 				"keyColumn": 0,
 				"valueColumn": 1
 			},
-			
+
 Here, we define the "genotype" for each plant.  This time, the type is "file".  This type of data key searches through the rows of a file,
 assuming that there is a mapping of key -> value in your row. If you look at the :download:`Genotype Key File <../../examples/workflows/current/GenKey.csv>`,
 you can see that it is a csv file with two columns.  We can see that the first column contains values that look like our "id" value.  The second column
-contains our genotype string -- our target value. The "file" type always assumes your input is some sort of value separated file.  It doesn't necessarily have to be 
+contains our genotype string -- our target value. The "file" type always assumes your input is some sort of value separated file.  It doesn't necessarily have to be
 separated by commas, but that is the default functionality.  If your file is separated by something other than commas, specify the "separator" option.  There are three
 other required definitions for "file" type data keys.  You need to define "key", "keyColumn", and "valueColumn".  The columns themselves are 0-indexed.  In this case, our "keyColumn" is 0, because
 our key is located in the 0th column.  "valueColumn" is 1, because our key is located in the 1st column.  Finally, our "key" value is the same as our "id".  This
@@ -241,15 +241,15 @@ located in the same row, namely UNL032
 				"value": "%date%",
 				"format": "Y-m-d"
 			},
-			
+
 Here, we define the "date" for each plant.  We use our final type, "date".  The only additional argument to the date type
 is "format", which specifies the input format of the date.  The date type loads in values based on a combination of identifiers and hard-coded values again,
 but afterwards, it converts the date to Y-m-d format.  In this case, because the input type is defined as "Y-m-d" using a date type
 isn't strictly required, we use it as an example though.  The date input string can contain "Y", "y", "M", "m", "d", "B", "b" as format characters,
 and uses "-", "/", " ", and "_" as separators.
- 
+
  .. code-block:: javascript
- 
+
  	"treatment": {
 				"type": "value",
 				"translate": "true",
@@ -264,7 +264,7 @@ and uses "-", "/", " ", and "_" as separators.
 				"translate": "true",
 				"value": "%imgname%"
 			}
-			
+
 We include the last three together, because they are all of type "value", and simply use one of the identifiers from the base path in their value.
 However, it is important to note that two of these values have an additional option, namely "translate": "true".  This specifies that the input value
 should be mapped to a different output value.  This functions very similar to a file mapping, except the mapping is defined inside the template.
@@ -307,15 +307,44 @@ Here, the "treatment" translation takes a single character, and maps it to a wor
 In this case, our idchar is 'C', this means that the "treatment" data key, will get mapped to "Control".  We also have a translation defined for "imtype".  Looking at our test path,
 our imgname is "RGB SV1".  This means that the "imtype" data key will get mapped to "rgbsv".  Remember, the key difference between defining translations, and using file mapping is size.
 
-With our template written, we can now load the images.  We do this using the 'ih-setup' command as follows:
+With our template written, we can now load the images using 2 ih commands.  First,
+run the ih-setup command with the name of the folder you want to create:
 
 .. code-block:: bash
 
-	ih-setup --dir "DIR_NAME" --template "crawl.json"
-	
-This will setup a workflow submission directory with the name "DIR_NAME".  It will create an input folder,
-and populate that input folder with the images database, the crawl.json template file, and empty template files required for job submission.
-Next we will look at defining the configuration file!
+	ih-setup --dir awesome_project
+
+This command will create a folder with the name you specify, and will create a two
+deep directory structure, with a couple empty files at the bottom:
+
+.. code-block:: bash
+
+	awesome_project/
+	  input/
+	    -config.json
+			-crawl.json
+			-images.db
+			-imgproc.json
+			-stats.json
+
+The ih commands assume by default that you are in the top level awesome_project/
+directory, using the above naming conventions for your input files.  The naming
+of the input files can be changed by using optional arguments.  Now that the
+project folder is setup, create your crawl.json file.  The above example is
+specific to our input data, so you must adjust the crawl file to match your
+input data.  Once your crawl.json is created, run the ih-crawl command from the
+awesome_project folder:
+
+.. code-block:: bash
+
+	ih-crawl
+
+This command may take a while to run depending on how many images need to be indexed.
+Once it is finished, it should populate the images.db file with an sqlite3 database.
+The database will contain all of the metadata information it parsed from your path
+names, as well as paths to your images.  Using the images.db file, and two additional
+files, a configuration file (config.json) and an workflow definition file (imgproc.json)
+we can submit jobs.
 
 Configuration
 -------------
@@ -326,37 +355,61 @@ variables, and job clustering.  Let's take a look.
 .. code-block:: javascript
 
 	{
-    	"installdir": "/work/walia/common/ih/pymodules/bin/",
-    	"profile": {
-              	"pegasus": {
-                        "style": "glite"
-                },
-                "condor": {
-                        "grid_resource": "pbs",
-                        "universe": "vanilla"
-                },
-                "env": {
-                        "PATH": "/work/walia/common/ih/pymodules/bin/",
-                        "LD_LIBRARY_PATH": "/work/walia/common/ih/pymodules/opencv_lib/"
-                }
-        },
-        "cluster": 100,
-        "email": "avi@kurtknecht.com"
+	        "installdir": "/work/walia/common/ih/pymodules/bin/",
+	        "profile": {
+	                "pegasus": {
+	                        "style": "glite"
+	                },
+	                "condor": {
+	                        "grid_resource": "pbs",
+	                        "universe": "vanilla"
+	                },
+	                "env": {
+	                        "PATH": "/work/walia/common/ih/pymodules/bin/",
+													"PYTHONPATH": "/work/walia/common/ih/pymodules/lib/python2.6/site-packages
+	                        "LD_LIBRARY_PATH": "/work/walia/common/ih/pymodules/opencv_lib/"
+	                }
+	        },
+	        "cluster": 100,
+	        "maxwalltime": {
+	        	"images": 2,
+	        	"stats": 300
+	        },
+	        "notify": {
+	        	"email": "avi@kurtknecht.com",
+	        	"pegasus_home": "/usr/share/pegasus/"
+	        }
 	}
-	
-The "installdir" definition is the location where all of ih's scripts are installed.  It may seem
-unnecessary to include this as well as a path, but it is important for pegasus to know the exact location
-of executable files.  The "profile" defintion supports inclusion of any-possible profile variable for 
-the sites.xml.  This is taken directly from the pegasus docs.  To run the workflow on HCC & OSG,
-we specify "pegasus"->"style"->"glite", and "condor"->"grid_resource"->"pbs".  The "env" definition
-passes environment variables through to the script.  In this case, we pass in two different path variables.
-One is the location of other executable scripts, in this case our custom python install.  The LD_LIBRARY_PATH
-is for the location of the required libraries for opencv.  It should be noted, that multiple path variables can be included
-by specifying the value as a list i.e. If you specify "PATH": ["/test/path/1/", "/test/path/2/"], both paths will
-be loaded into the sites.xml.  "cluster" specifies how many jobs you want to clump together.  Most jobs take
-seconds to run, so running-the entire workflow unclustered is very-inefficient.  A cluster size of 100 is used here,
-which means that jobs will be run in batches of 100.  The "email" option defines which email to send the results to upon
-completion of the workflow.
+
+Most of these definitions are fairly straightforward, but some, such as the pegasus
+style and condor universe will be specific to the cluster you use.  Make sure
+you use appropriate pegasus configuration for your system.
+
+1. "installdir" - This is simply the location to the ih-commands.
+
+2. "profile" - This definition populates the workflows sites.xml file
+(`sites.xml pegasus docs <http://pegasus.isi.edu/wms/docs/latest/site.php>`).
+The variables defined in here will be very specific for your system.  Make
+sure you use the correct pegasus & condor environment variables.  The "env"
+definition passes environment variables through to the processing scripts.
+Make sure that "PATH" points to necessary executables, "PYTHONPATH" points to
+necessary python modules, and "LD_LIBRARY_PATH" points to the required opencv
+libraries.
+
+3.  "cluster" - This argument sets the horizontal cluster size for job execution.
+Because individual image processing steps are fast and don't require many resources,
+it is advantageous to cluster them.  The number of clusters depends on how many
+input images you have.
+
+4. "maxwalltime" - This argument defines the maximum wall time for image processing
+jobs, and statitistics workflows.  Cummulative wall time for a single cluster is
+the size of the cluster times the value in the "images" definition.  For the
+example above, this means that each cluster of 100 images will request 200 mintues
+of wall time.
+
+5. "notify" - This argument defines the information needed for email notifications
+on workflow completion.  Simply provide an email address, and the path to pegasus_home,
+which contains a notification directory.
 
 Processing
 ----------
@@ -654,7 +707,7 @@ are defined for each image type -- as a result the template is quite long.  Here
 			]
 		},
 		"options": {
-		
+
 		},
 		"extract": {
 			"histogram-bin": {
@@ -717,11 +770,11 @@ For each job you may optionally define dependent jobs.  Let's look at the first
 				"--logic": "(((((((r - g) < 30) and (((r + g) + b) < 110)) or ((((r + g) + b) > 110) and ((r - g) < 50))) or (((r - g) < 25) and ((g - r) < 25))) or (g > 60)) not 1)"
 			}
 		},
-		
+
 Here, we define the name as "pot_filter_1".  Names are used to apply a more meaningful label
 to each job for the user, as well as used for dependencies in later processing steps.
 We define the executable we want to use as "ih-color-filter" -- This executable is used for
-processing user defined color logic, and will not be talked about in depth here.  We define two inputs 
+processing user defined color logic, and will not be talked about in depth here.  We define two inputs
 for our function.  The first is "base" -- which serves as a placeholder for raw images.  You can use
 this input in any step and it will load in the starting image.  This is important for steps such
 as reconstiuting the color of the image.  The second argument we feed is a path to a roi file.
@@ -729,13 +782,13 @@ Here are the contents of the file:
 
 .. code-block:: javascript
 
-	{	
+	{
 	    "ystart": 1110,
 	    "yend": "y",
 	    "xstart": 369,
 	    "xend": 669
 	}
-	
+
 The roi file simply defines the region we want to apply our color-filter to.
 The roi file will automatically convert "y" to the maximum height, and "x" to the maximum
 width.  Additionally it supports simply arithmetic, thus you could enter "y - 300" for
@@ -758,10 +811,10 @@ We now look at the second job for fluosv:
 					},
 					"depends": ["pot_filter_1"]
 			},
-			
+
 Note that the input image is now "pot1" instead of "base".  This chains the output
 of the previous step into the input of this step.  To fully accomplish this, we must define
-dependency.  Our first job was named "pot_filter_1", and we can see this name in our 
+dependency.  Our first job was named "pot_filter_1", and we can see this name in our
 dependency list.  A job can have multiple dependencies, you simply separate the names with
 commas i.e. "depends": ["job1", "job2", "job3"].  Whenever you use the output of a previous
 job, you must include it in the dependency list.  Some functions output roi files instead of,
@@ -777,7 +830,7 @@ the only supported option is "save-steps".  If you specify:
 	"options": {
 		"save-step": "true"
 	},
-	
+
 Each intermediary step (including roi files) will be saved to the final output folder.  Otherwise,
 only the final processed image will be saved.  Lastly, "extract" is required, and here you specify
 all the numeric information you want to extract from your final images.  Let's take a look:
@@ -820,7 +873,7 @@ all the numeric information you want to extract from your final images.  Let's t
 			}
 		}
 	}
-	
+
 There is an optional special key you can define -- "histogram-bin" -- in the
 extract section.  Specifying this key allows you to perform an experiment-wise histogram
 calculation of color-channel information to generate relevant bins.  It performs the
@@ -829,10 +882,10 @@ the histograms to get a histogram for the entire data set.  3. Segment the histo
 into equal area pieces as based on the inputs. 4. Generate complete permutation
 of bins based on the divided histogram. In the "histogram-bin" section we
 first define "--group".  This allows us to group one or more imtypes from separate
-workflows together.  In this case, we group "rgbsv" and "rgbtv" together.  This 
+workflows together.  In this case, we group "rgbsv" and "rgbtv" together.  This
 allows us to consider color information from the RGB spectrum as a whole.
 We name this group "rgb" -- group names are important for future "histogram-bin"
-definitions.  Next is "--chunks".  For each group, you simply define how many 
+definitions.  Next is "--chunks".  For each group, you simply define how many
 pieces you want the total calculated histogram to be broken up into.  Remember
 that color-space is 3 dimensional -- this means that specifying chunks = 5
 will generate :math:`5^{3} = 125` bins.  Finally, we define what channels to
@@ -845,52 +898,56 @@ for every generated bin.
 The definitions in each individual "workflow" extract information from each individual
 image.  You must define "inputs" and "depends" so that the extraction script
 can locate the image you want to extract data from (it does not necessarily have to be the
-final image, though it generally is).  In the arguments section, you define a list of the 
+final image, though it generally is).  In the arguments section, you define a list of the
 numeric information you want to extract.  For an example of all arguments you can specify,
 look at the ih-extract script.  If you specify "histogram-bin" for a particular
 imtype, the "--colors" options is added automatically.
 
-Finally, to actually generate your workflow, use the ih-run command.
-You should have setup a directory from the crawling step when you executed
+Finally, to actually generate your workflow, use the ih-run command.  Run this
+command from your top level folder that was generated by the ih-setup command.
 
 .. code-block:: bash
 
-	ih-setup --dir "DIR_NAME" --template "crawl.json"
-	
-The easiest way to run ih-run is to change directories to "DIR_NAME", then
-simply run:
-
-.. code-block:: bash
-	
 	ih-run
-	
-with no arguments!  Run with the -h option to see options.  Additionally, the validator
-for processing workflows is very powerful.  Use --validate to run in validate only mode
-to help debug your workflow as you create it.  Depending on how many input images,
-it may take a while to write the necessary submission files (sometimes 10-20 minutes).
+
+This will combine the information in your configuration file, workflow definition file,
+and image database to create the necessary files for a pegasus workflow.  Additionally,
+before creating the workflow, it validates arguments and dependencies in your workflow.
+Use --validate to run in validate only mode to help debug your workflow as you create it.
+Depending on how many input images, it may take a while for ih-run to write the necessary submission files.
 
 Submission
 -----------
 Upon sucessful completion of ih-run, a date and timestamped folder should be created
-with the following structure:
+in your top level folder.  Your setup should now look like this:
 
 .. code-block:: bash
 
-	date-timestamp/
-	  input/
-	    imgproc/
-		-sites.xml
-		-conf.rc
-		-map.rc
-		-extract.dax
-		-workflow.dax
-		-notify.sh
-		-submit.sh
-	    rawfiles/
-	    templates/
-	  output/
-	    -output.db
-	  work/
+	awesome_project/
+		date-timestamp/
+		  input/
+		    imgproc/
+			-conf.rc
+			-extract.dax
+			-map.rc
+			-notify.sh
+			-remove.sh
+			-sites.xml
+			-status.sh
+			-submit.sh
+			-workflow.dax
+		    rawfiles/
+		    templates/
+		  output/
+		    -output.db
+		  work/
+		input/
+			-config.json
+			-crawl.json
+			-images.db
+			-imgproc.json
+			-stats.json
+
 
 The work directory is where actual processing is done -- but initially starts empty.  The output
 folder starts only with the output database, but contains no images to start with.  The input folder
@@ -898,9 +955,4 @@ contains a copy of your submitted templates in the templates folder, and a copy
 in the rawfiles folder.  Finally, within the imgproc folder are the actual files required to submit
 a pegasus workflow.  All you need to do to submit is execute the submit.sh script.  This will launch your
 workflow, as well as creating a status.sh script for easy monitoring, and a remove.sh script if you
-want to remove your workflow.
-
-
-
-	
-	
+want to remove your workflow.  If there are other pegasus errors you may need to adjust your configuration.
diff --git a/docs/build/html/_sources/ex_workflow_2.txt b/docs/build/html/_sources/ex_workflow_2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..57d8ae1d00661d9d06618f2da1d6b91e558e52c6
--- /dev/null
+++ b/docs/build/html/_sources/ex_workflow_2.txt
@@ -0,0 +1,92 @@
+.. raw:: html
+
+	<style> .red {color:red} .blue {color:blue} .green {color:green} .orange {color:orange} </style>
+
+.. role:: red
+
+.. role:: blue
+
+.. role:: green
+
+.. role:: orange
+
+OSG Workflows
+==============
+This section details the modifications necessary to submit your pegasus
+workflows on the `OSG <http://www.opensciencegrid.org/>`_.  Their team has
+set up an environment specifically for our software, so the only changes that
+need to occur are some configuration changes, and creating a tarred version
+of this library.
+
+Final Templates
+----------------
+
+:download:`Configuration <../../examples/workflows/osg/config.json>`
+
+Configuration
+-------------
+Here is the adjusted configuration file:
+
+.. code-block:: javascript
+
+		{
+		    "installdir": "/work/walia/common/ih/pymodules/bin/",
+		    "profile": {
+		        "pegasus": {
+		            "style": "glite"
+		        },
+		        "condor": {
+		          "grid_resource": "pbs",
+		          "universe": "vanilla"
+		        },
+		        "env": {
+		            "PATH": "/work/walia/common/ih/pymodules/bin/",
+		            "PYTHONPATH": "/work/walia/common/ih/pymodules/lib/python2.6/site-packages",
+		            "LD_LIBRARY_PATH": "/work/walia/common/ih/pymodules/opencv_lib/"
+		        }
+		      },
+		      "cluster": 100,
+		      "maxwalltime": {
+		        	"images": 2,
+		        	"stats": 300
+		      },
+		      "notify": {
+		        	"email": "avi@kurtknecht.com",
+		        	"pegasus_home": "/usr/share/pegasus/"
+		      }
+		}
+
+
+Most of the information is the same as the configuration file from the previous
+workflow example, but there are a few differences.  First, the condor configuration
+should have the "requirements" and "+WantsStashCache" definitions, and they should
+match as above.  The "+ProjectName" definition is if you have a group on the OSG.
+Next, there is a version definition, which should match the version of your ih
+tar.  To create a tarball distribution, navigate to your ih install, and run:
+
+.. code-block:: python
+
+	python setup.py sdist
+
+This will create a dist folder, as well as an ih-1.0.tar.gz file.  Pass the
+full path to this file into the "tarball" definition.  Finally, for data staging
+and transferring to work successfully, you need to create an ssh key pair
+for your workflow.  Run the following:
+
+
+.. code-block:: bash
+
+	ssh-keygen -t rsa -b 2048
+
+This while generate an ssh key pair.  You will be prompted for a name and a
+password.  When prompted for the password, hit enter to leave the password blank.
+After this finishes, there should be two files created in your ~/.ssh/ folder,
+a private key file and public key file with the name that you gave.  Append the
+contents of the public key file to your authorized_keys files (create it if
+necessary).
+
+.. code-block:: bash
+
+	cat ~/.ssh/KEY_NAME.pub >> ~/.ssh/authorized_key
+
+Finally provide the full path to the private key for the "ssh" definition.
diff --git a/docs/build/html/_sources/examples.txt b/docs/build/html/_sources/examples.txt
index f33a32b58e2adfc04e2c317cfcf94afccc6088da..6a1a69871dd44d22d05afcb4b0f4b849331727e8 100644
--- a/docs/build/html/_sources/examples.txt
+++ b/docs/build/html/_sources/examples.txt
@@ -1,14 +1,16 @@
 ..
-	REMEMBER TO UPDATE THE HIDDEN TOC TREE 
+	REMEMBER TO UPDATE THE HIDDEN TOC TREE
 	AS SCRIPTS ARE ADDED TO THE EXAMPLES PAGE!!!
 
 .. toctree::
-	:hidden:
-	
-	ex_script_core1
-	ex_script_core2
-	ex_script_color1
-	ex_workflow_1.rst
+    :hidden:
+
+    ex_script_core1
+    ex_script_core2
+    ex_script_color1
+    ex_workflow_1
+    ex_workflow_2
+    arkansas_workshop_july_2015
 
 Examples
 ========
@@ -47,3 +49,11 @@ Workflow Examples
 -----------------
 
 :doc:`Workflow #1 <ex_workflow_1>`, difficulty = complex.
+
+:doc:`OSG Workflows <ex_workflow_2>`
+
+Workshops
+---------
+Start to finish tutorials for specific events.
+
+:doc:`Arkansas Workshop July 2015 <arkansas_workshop_july_2015>`
diff --git a/docs/build/html/_sources/installation.txt b/docs/build/html/_sources/installation.txt
index e905cfcfc3fe72f823602d40299f64dfcb595b68..27c50e31c62acbd8a62f4b993070cad4169388fe 100644
--- a/docs/build/html/_sources/installation.txt
+++ b/docs/build/html/_sources/installation.txt
@@ -150,7 +150,7 @@ Mac OSX
 Installation for local testing is a breeze with `brew <http://brew.sh>`_.  Installing
 brew simply requires copying a line into a terminal.  The only two packages
 you need to manual download will be PyMeanShift and Image Harvest.
-NOTE: You will have to install XCode, and the XCode Command Line Tools if you have not already. It's a free download 
+You will have to install `XCode <https://developer.apple.com/xcode/>`_, and the XCode Command Line Tools if you have not already. It's a free download 
 from the App Store.
 After you have downloaded the packages and installed brew, run the following:
 
@@ -186,7 +186,7 @@ install several packages before `pip <https://pypi.python.org/pypi/pip>`_ can pu
 in work.  First, install `python2.7 <https://www.python.org/downloads/>`_.  Next,
 you have to add python to your PATH environment variable. 
 
-* Windows 7: Right click on Computer > properties > Advanced system settings > Advanced Tab > Enviornment Variables
+* Windows 7: Right click on Computer > Properties > Advanced system settings > Advanced Tab > Enviornment Variables
 * Windows 8: Control Panel > System > Advanced system settings > Advanced Tab > Environment Variables
 
 You should see two boxes.  One that says "User variables for <user>", and the other that says
@@ -201,7 +201,7 @@ simply be a giant script you copy to a local file, and execute with python.
 
 Now, you can install all the dependent python packages by finding the correct version for your os,
 and downloading them from this `link <http://www.lfd.uci.edu/~gohlke/pythonlibs/>`_.  You will need the same
-list as above that is, numpy, scipy, pandas, matplotlib, and opencv. 
+list as above that is, `numpy <http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy>`_, `scipy <http://www.lfd.uci.edu/~gohlke/pythonlibs/#scipy>`_, `pandas <http://www.lfd.uci.edu/~gohlke/pythonlibs/#pandas>`_, `matplotlib <http://www.lfd.uci.edu/~gohlke/pythonlibs/#matplotlib>`_, and `opencv <http://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv>`_. 
 
 .. code-block:: bash
 
diff --git a/docs/build/html/_sources/processing.txt b/docs/build/html/_sources/processing.txt
index 66b618cea25e0a0d0ac4d0c63b74935391c9d615..2f617cc8601c514cb5f966bc49c97f41e01d78f7 100644
--- a/docs/build/html/_sources/processing.txt
+++ b/docs/build/html/_sources/processing.txt
@@ -4,7 +4,112 @@ Image Processing
 This page contains specific implementation details of image processing functions.
 Additionally, the next page contains an interactive image processing function viewer.
 It allows for adjusting inputs and seeing results of many different functions
-on several different sample input images.
+on several different sample input images.  Before talking about processing functions,
+we are first going to talk about inputting resources.
 
+.. _resource-image:
+
+.. raw:: html
+	
+	<h3>Images</h3>
+
+Images are mostly input at the beginning of processing,
+but there area few functions such as :meth:`~ih.imgproc.Image.bitwise_and`
+that take additional images as inputs.  When first loading the image,
+it can be constructed with either a path to the image or a raw numpy array.
+When loading an additional image into a function, it can be a path, a numpy array,
+or a state.  Loading an image from a path simply requires a string of an absolute or relative path
+to the image. 
+
+.. code-block:: python
+
+	plant = ih.imgproc.Image("/path/to/your/image.png")
+
+Most of the time other methods of input are not required, but they can
+be useful in certain circumstances.  OpenCV represnts images as numpy arrays --
+effectively, a large matrix that has a blue, green, and red value at each of the indices.
+By allowing images to be loaded in as a numpy array directly, Image Harvest can be used in
+conjunction with any other image tool that also uses OpenCV or represents images as numpy arrays.
+
+.. code-block:: python
+
+	im = cv2.imread("/path/to/your/image.png")
+	plant = ih.imgproc.Image(im)
+
+Finally, you can pass in a state to a function to use a previously saved image.
+Because states require you to save something first, you cannot instantiate an
+image with a state.  This is particularly useful when recoloring a thresholded image:
+
+.. code-block:: python
+
+	plant = ih.imgproc.Image("/path/to/your/image.png")
+	plant.save("base")
+	plant.convertColor("bgr", "gray")
+	plant.threshold(127)
+	plant.bitwise_and("base")
+
+.. raw:: html
+
+	<h3>ROI's</h3>
+
+Regions Of Interest can also be input as either a list, or a json file.  If a region of interest is input as a list it should be of the form:
+
+.. code-block:: python
+
+    [ystart, yend, xstart, xend] 
+
+If a ROI is input as a json file, it should look like the following:
+
+.. code-block:: python
+
+    {
+        "ystart": YOUR_VALUE,
+        "yend": YOUR_VALUE,
+        "xstart": YOUR_VALUE,
+        "xend": YOUR_VALUE
+    }
+
+Each individual ROI argument has some special options.  Each argument can be auto-filled by using a value of -1.  For "xstart" and "ystart" this simply assigns a value of 0, but for "xend" and "yend" this fills the width and height of the image respectively. This isn't as necessary for the starting values, but can be useful for the ending values.  For example, let's say we want an roi that skips the first 400 pixels from the left / top side of our image:
+
+.. code-block:: python
+
+    # List style
+    [400, -1, 400, -1]
+    # Json style
+    {
+        "ystart": 400,
+        "yend": -1,
+        "xstart": 400,
+        "xend": -1
+    }
+
+Instead of using -1 you can also use "x" and "y" to represent the full width and height respectively.
+Adjusting the previous example:
+
+.. code-block:: python
+
+    # List style
+    [400, "y", 400, "x"]
+    # Json style
+    {
+        "ystart": 400,
+        "yend": "y",
+        "xstart": 400,
+        "xend": "x"
+    }
+
+Finally, each individual argument can have a single arithmetic operation in it (except for multiplication).  Utilizing this, we can create fairly complex ROI's without too much effort.  For example, here is an ROI that targets only the bottom half of your image, and ignores 300 pixels on both the left and right sides:
+
+.. code-block:: python
+    # List style
+    ["y / 2", "y", 300, "x - 300"]
+    # Json style
+    {
+        "ystart": "y / 2",
+        "yend": "y",
+        "xstart": 300,
+        "xend": "x - 300"
+    }
+	
 .. autoclass:: ih.imgproc.Image
 	:members:
diff --git a/docs/build/html/_sources/viewer.txt b/docs/build/html/_sources/viewer.txt
index 48a696db71d433f6bfc08ad50bfab53de8390c3c..89ab648f93d0be21aac29616979e1ea56543137c 100644
--- a/docs/build/html/_sources/viewer.txt
+++ b/docs/build/html/_sources/viewer.txt
@@ -3,10 +3,11 @@ Image Processing Viewer
 
 .. raw:: html
 
-	<script type="text/javascript" src="/Users/aknecht/git/ih/docs/images/viewer.json"></script>
+	<!-- <script type="text/javascript" src="/data/viewerim/viewer.json"></script> -->
+    <script type="text/javascript" src="/Users/aknecht/git/ih/docs/images/viewer.json"></script>
 	<script type="text/javascript">
-		base = "/Users/aknecht/git/ih/docs/images/"
-		// base = "/cropstressgenomics.org/data/viewerim/"
+		var base = "/Users/aknecht/git/ih/docs/images/";
+        // var base = "/data/viewerim/"
 		$(function() {
 			$("#function").on("change", function() {
 				optstr = ""
@@ -101,4 +102,4 @@ Image Processing Viewer
 	<div class="row">
 		<br />
 	</div> 
-	
\ No newline at end of file
+	
diff --git a/docs/build/html/_sources/workshops.txt b/docs/build/html/_sources/workshops.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e5fd8b2c690d5d6ff83231e2d9932758d0830ee1
--- /dev/null
+++ b/docs/build/html/_sources/workshops.txt
@@ -0,0 +1,15 @@
+..
+	REMEMBER TO UPDATE THE HIDDEN TOC TREE 
+	AS WORKSHOPS ARE ADDED TO THE PAGE!!!
+
+.. toctree::
+    :hidden:
+
+    arkansas_workshop_july_2015
+	
+Workshops
+=========
+
+Some text here
+
+:doc:`Arkansas Workshop July 2015 <arkansas_workshop_july_2015>`
diff --git a/docs/build/html/arkansas_workshop_july_2015.html b/docs/build/html/arkansas_workshop_july_2015.html
new file mode 100644
index 0000000000000000000000000000000000000000..f35a538d625b90a2ff98db9eb81bf85add85dbaa
--- /dev/null
+++ b/docs/build/html/arkansas_workshop_july_2015.html
@@ -0,0 +1,499 @@
+<!DOCTYPE html>
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Arkansas Workshop July 2015 &mdash; Image Harvest 1.0.1 documentation</title>
+    
+    <link rel="stylesheet" href="_static/basic.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/bootstrap-3.2.0/css/bootstrap.min.css" type="text/css" />
+    <link rel="stylesheet" href="_static/bootstrap-3.2.0/css/bootstrap-theme.min.css" type="text/css" />
+    <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '1.0.1',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
+    <script type="text/javascript" src="_static/js/jquery-1.11.0.min.js"></script>
+    <script type="text/javascript" src="_static/js/jquery-fix.js"></script>
+    <script type="text/javascript" src="_static/bootstrap-3.2.0/js/bootstrap.min.js"></script>
+    <script type="text/javascript" src="_static/bootstrap-sphinx.js"></script>
+    <link rel="top" title="Image Harvest 1.0.1 documentation" href="index.html" />
+    <link rel="up" title="Examples" href="examples.html" />
+    <link rel="next" title="Image Processing" href="processing.html" />
+    <link rel="prev" title="OSG Workflows" href="ex_workflow_2.html" />
+<meta charset='utf-8'>
+<meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
+<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1'>
+<meta name="apple-mobile-web-app-capable" content="yes">
+
+  </head>
+  <body role="document">
+
+  <div id="navbar" class="navbar navbar-default navbar-fixed-top">
+    <div class="container">
+      <div class="navbar-header">
+        <!-- .btn-navbar is used as the toggle for collapsed navbar content -->
+        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".nav-collapse">
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+        </button>
+        <a class="navbar-brand" href="index.html">
+          Image Harvest</a>
+        <span class="navbar-text navbar-version pull-left"><b>1.0</b></span>
+      </div>
+
+        <div class="collapse navbar-collapse nav-collapse">
+          <ul class="nav navbar-nav">
+            
+            
+              <li class="dropdown globaltoc-container">
+  <a role="button"
+     id="dLabelGlobalToc"
+     data-toggle="dropdown"
+     data-target="#"
+     href="index.html">Site <b class="caret"></b></a>
+  <ul class="dropdown-menu globaltoc"
+      role="menu"
+      aria-labelledby="dLabelGlobalToc"><ul class="current">
+<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li>
+<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="start.html">Getting Started</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_script_core1.html">Core Processing Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1 current"><a class="current reference internal" href="">Arkansas Workshop July 2015</a></li>
+<li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
+<li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
+<li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
+<li class="toctree-l1"><a class="reference internal" href="statistics.html">Statistics</a></li>
+<li class="toctree-l1"><a class="reference internal" href="indexing.html">Image Loading</a></li>
+<li class="toctree-l1"><a class="reference internal" href="workflowimage.html">Image Processing Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="workflowstats.html">Statistics Workflows</a></li>
+</ul>
+</ul>
+</li>
+              
+                <li class="dropdown">
+  <a role="button"
+     id="dLabelLocalToc"
+     data-toggle="dropdown"
+     data-target="#"
+     href="#">Page <b class="caret"></b></a>
+  <ul class="dropdown-menu localtoc"
+      role="menu"
+      aria-labelledby="dLabelLocalToc"><ul>
+<li><a class="reference internal" href="#">Arkansas Workshop July 2015</a><ul>
+<li><a class="reference internal" href="#command-line-crash-course">Command Line Crash Course</a><ul>
+<li><a class="reference internal" href="#id1">Mac OS X</a></li>
+<li><a class="reference internal" href="#id2">Windows</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#first-image">First Image</a></li>
+<li><a class="reference internal" href="#python-script">Python Script</a></li>
+<li><a class="reference internal" href="#day-2">Day 2</a><ul>
+<li><a class="reference internal" href="#loading">Loading</a></li>
+<li><a class="reference internal" href="#blur">Blur</a></li>
+<li><a class="reference internal" href="#meanshift">Meanshift</a></li>
+<li><a class="reference internal" href="#color-filter">Color Filter</a></li>
+<li><a class="reference internal" href="#contour-cut">Contour Cut</a></li>
+<li><a class="reference internal" href="#recoloring">Recoloring</a></li>
+<li><a class="reference internal" href="#extraction">Extraction</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#extras">Extras</a></li>
+</ul>
+</li>
+</ul>
+</ul>
+</li>
+              
+            
+            
+              
+                
+  <li>
+    <a href="ex_workflow_2.html" title="Previous Chapter: OSG Workflows"><span class="glyphicon glyphicon-chevron-left visible-sm"></span><span class="hidden-sm hidden-tablet">&laquo; OSG Workflows</span>
+    </a>
+  </li>
+  <li>
+    <a href="processing.html" title="Next Chapter: Image Processing"><span class="glyphicon glyphicon-chevron-right visible-sm"></span><span class="hidden-sm hidden-tablet">Image Processing &raquo;</span>
+    </a>
+  </li>
+              
+            
+            
+            
+            
+              <li class="hidden-sm">
+<div id="sourcelink">
+  <a href="_sources/arkansas_workshop_july_2015.txt"
+     rel="nofollow">Source</a>
+</div></li>
+            
+          </ul>
+
+          
+            
+<form class="navbar-form navbar-right" action="search.html" method="get">
+ <div class="form-group">
+  <input type="text" name="q" class="form-control" placeholder="Search" />
+ </div>
+  <input type="hidden" name="check_keywords" value="yes" />
+  <input type="hidden" name="area" value="default" />
+</form>
+          
+        </div>
+    </div>
+  </div>
+
+<div class="container">
+  <div class="row">
+    <div class="col-md-12">
+      
+  <div class="section" id="arkansas-workshop-july-2015">
+<h1>Arkansas Workshop July 2015<a class="headerlink" href="#arkansas-workshop-july-2015" title="Permalink to this headline">ΒΆ</a></h1>
+<p>Hello Arkansas State!  This workshop covers basic command line instructions and local processing of an image from LemnaTec.  Either look at the corresponding part of the  installation page for your computer (<a class="reference external" href="installation.html#mac-osx">Mac OS X</a>, <a class="reference external" href="installation.html#windows">Windows</a>) or head to the next section.</p>
+<div class="section" id="command-line-crash-course">
+<h2>Command Line Crash Course<a class="headerlink" href="#command-line-crash-course" title="Permalink to this headline">ΒΆ</a></h2>
+<p>If you are unfamiliar with the command line, or have never opened the Terminal or Command Prompt app before, this section is for you.  There are several useful features available while using Image Harvest through a Python interpreter, which requires a small amount of command line knowledge &#8211; namely the ability to navigate through directories.  For all operating systems, files are structured hierarchically in directories.  A directory almost always has a parent (represented by &#8221;..&#8221;), and it may contain files or more sub-directories.  The only directory not that doesn&#8217;t have a parent is the root directory which is &#8220;/&#8221; for Mac OS X and Linux, and &#8220;C:\&#8221; for Windows users.  Since all directories are children of the root directory, you can write the path to any file all the way from the root.  These types of paths are absolute paths.  &#8220;/Users/username/Downloads/file.txt&#8221; and &#8220;C:\Users\username\Downlaods\file.txt&#8221; are both examples of absolute paths.  The counterpart to absolute paths is relative paths, which is a path to any file written from where you are currently located.  If you are currently located in your Downloads folder, the relative path &#8220;file.txt&#8221; is the same as the absolute path &#8220;/Users/username/Downloads/file.txt&#8221;.  These concepts apply to all operating systems, however, each uses different commands for achieving directory navigation.</p>
+<div class="section" id="id1">
+<h3>Mac OS X<a class="headerlink" href="#id1" title="Permalink to this headline">ΒΆ</a></h3>
+<p>First and foremost, the terminal app is located at /Applications/Utilities/Terminal.app.  There are only 3 important commands:</p>
+<ul class="simple">
+<li>cd &#8211; Which stands for &#8220;change directory&#8221;.  This command allows you to move your current location to a new directory as specified by an argument.  It can be either an absolute or a relative path.</li>
+<li>ls &#8211; Which stands for &#8220;list&#8221;.  This command lists all the files and folders in the current directory.</li>
+<li>pwd &#8211; Which stands for &#8220;print working directory&#8221;, and prints your current directory&#8217;s absolute path.</li>
+</ul>
+<p>Examples:</p>
+<div class="highlight-bash"><div class="highlight"><pre><span class="c"># Move to your home folder.</span>
+<span class="nb">cd</span> /Users/username/
+<span class="c"># Move to your downloads folder from your home folder.</span>
+<span class="nb">cd </span>Downloads
+<span class="c"># Move up a folder -- back to your home folder.</span>
+<span class="nb">cd</span> ..
+<span class="c"># List files in your home folder</span>
+ls
+<span class="c"># List files in your home folder as a list</span>
+ls -al
+<span class="c"># List files in your home folder as a list with coloring</span>
+ls -alG
+<span class="c"># Print the absolute path to your home folder.</span>
+<span class="nb">pwd</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="id2">
+<h3>Windows<a class="headerlink" href="#id2" title="Permalink to this headline">ΒΆ</a></h3>
+<p>The Command Prompt app can be opened by typing cmd into the windows search bar.  There are only 2 important commands:</p>
+<ul class="simple">
+<li>cd &#8211; Which stands for &#8220;change directory&#8221;.  This command allows you to move your current location to a new directory as specified by an argument.  It can be either an absolute or a relative path.</li>
+<li>dir &#8211; Which stands for &#8220;directory&#8221;.  This command both prints your current location, and prints files and directories in your current location.</li>
+</ul>
+<p>Examples:</p>
+<div class="highlight-bash"><div class="highlight"><pre><span class="c"># Move to your home folder</span>
+<span class="nb">cd </span>C:<span class="se">\\</span>Users<span class="se">\\</span>username
+<span class="c"># Move to your downloads folder from your home folder.</span>
+<span class="nb">cd </span>Downloads
+<span class="c"># Move up a folder -- back to your home folder.</span>
+<span class="nb">cd</span> ..
+<span class="c"># List the path to your home folder, and the files in your home folder.</span>
+dir
+</pre></div>
+</div>
+</div>
+</div>
+<div class="section" id="first-image">
+<h2>First Image<a class="headerlink" href="#first-image" title="Permalink to this headline">ΒΆ</a></h2>
+<p>If you have not already, look at the corresponding part of the installation page for your computer (<a class="reference external" href="installation.html#mac-osx">Mac OS X</a>, <a class="reference external" href="installation.html#windows">Windows</a>).  Once you&#8217;ve got Image Harvest installed, download the following image:</p>
+<p><a class="reference download internal" href="_downloads/rgbsv1.png"><code class="xref download docutils literal"><span class="pre">First</span> <span class="pre">Image</span></code></a></p>
+<p>Once it&#8217;s saved, navigate to it from the command line &#8211; By default either /Users/username/Downloads/ or C:\Users\username\Downloads.  From there open up a python interpreter by typing the following command:</p>
+<div class="highlight-bash"><div class="highlight"><pre>python
+</pre></div>
+</div>
+<p>You should see something like:</p>
+<div class="highlight-bash"><div class="highlight"><pre>Python 2.7.6 <span class="o">(</span>default, Sep  <span class="m">9</span> 2014, 15:04:36<span class="o">)</span>
+<span class="o">[</span>GCC 4.2.1 Compatible Apple LLVM 6.0 <span class="o">(</span>clang-600.0.39<span class="o">)]</span> on darwin
+Type <span class="s2">&quot;help&quot;</span>, <span class="s2">&quot;copyright&quot;</span>, <span class="s2">&quot;credits&quot;</span> or <span class="s2">&quot;license&quot;</span> <span class="k">for</span> more information.
+&gt;&gt;&gt;
+</pre></div>
+</div>
+<p>The 3 right angle brackets are where you type your input.  Within the python interpreter
+command line tools won&#8217;t work, so when loading a file you need to already know it&#8217;s path
+or it will be difficult to find.  Execute the following lines from the python interpreter:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># Import the Image Harvest library</span>
+<span class="kn">import</span> <span class="nn">ih.imgproc</span>
+<span class="c"># Load your downloaded image!</span>
+<span class="n">plant</span> <span class="o">=</span> <span class="n">ih</span><span class="o">.</span><span class="n">imgproc</span><span class="o">.</span><span class="n">Image</span><span class="p">(</span><span class="s">&quot;rgbsv1.png&quot;</span><span class="p">)</span>
+<span class="c"># Show your plant!</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">()</span>
+<span class="c"># Wait for user input, then destroy the window</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>You should see a window named &#8220;window 1&#8221; pop up with a smaller version of your image in it!
+By calling the <a class="reference internal" href="processing.html#ih.imgproc.Image.wait" title="ih.imgproc.Image.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a> method, the window will be displayed until you press any key, and control is taken away from the python interpreter.  Every processing script begins by loading the library, and loading the image, and all Image Harvest functions are performed on a loaded image.  Using the python interpreter provides some powerful tools to adjust your analysis on the fly and test out function parameters through the use of &#8220;states&#8221;.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># Save the current state under the name &quot;base&quot;</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;base&quot;</span><span class="p">)</span>
+<span class="c"># Convert the plant to grayscale</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">convertColor</span><span class="p">(</span><span class="s">&quot;bgr&quot;</span><span class="p">,</span> <span class="s">&quot;gray&quot;</span><span class="p">)</span>
+<span class="c"># Save the current state under the name &quot;gray&quot;</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;gray&quot;</span><span class="p">)</span>
+<span class="c"># Threshold with a questionable value!</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">threshold</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">()</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>If done correctly, you should see a window named &#8220;window 2&#8221; that&#8217;s completely black.  The threshold function thresholds by pixel intensity, which is an integer from 0 to 255, so thresholding by 255 means no pixels should make it through.
+Since we saved states (&#8220;base&#8221; and &#8220;gray&#8221;), we can restore a previous state and try the thresholding operation again with adjusted parameters:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># Restore the gray state</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">restore</span><span class="p">(</span><span class="s">&quot;gray&quot;</span><span class="p">)</span>
+<span class="c"># Threshold round 2</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">threshold</span><span class="p">(</span><span class="mi">190</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">()</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>You should see a window name &#8220;window 3&#8221; that&#8217;s only black and white, and you should be able to see the outline of the plant in black.  We can utilize states for more than just restoring a previous image:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># Save the black &amp; white state!</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;binary&quot;</span><span class="p">)</span>
+<span class="c"># Invert the color, display with name</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">bitwise_not</span><span class="p">()</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Inverted Mask&quot;</span><span class="p">)</span>
+<span class="c"># Convert the mask to bgr, combine it with the &quot;base&quot; state</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">convertColor</span><span class="p">(</span><span class="s">&quot;gray&quot;</span><span class="p">,</span> <span class="s">&quot;bgr&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">bitwise_and</span><span class="p">(</span><span class="s">&quot;base&quot;</span><span class="p">)</span>
+<span class="c"># Save the image and display it</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;recolored&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Recolored Image&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
+</pre></div>
+</div>
+<img alt="_images/inverted.png" class="align-left" src="_images/inverted.png" />
+<img alt="_images/recolored.png" class="align-right" src="_images/recolored.png" />
+<div class="row" style="clear:both;"></div><br /><p>This time, you should see two windows pop up, one named &#8220;Inverted Mask&#8221; and the other named &#8220;Recolored Image&#8221;.  The inverted mask window shows our inverted thresholded image, and the recolored image window shows the final output of combining our mask with our base image.  We keep all the pixels that are in the mask, but we use the colors of the base image.  Utilizing a few more functions, we can finish the processing of our first image:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># Crop the pot out of the image.</span>
+<span class="c"># ROI is of the form [ystart, yend, xstart, xend]</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">crop</span><span class="p">([</span><span class="mi">300</span><span class="p">,</span> <span class="mi">2150</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">&quot;x&quot;</span><span class="p">])</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;cropped&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Cropped Image&quot;</span><span class="p">)</span>
+<span class="c"># Resize the image to just the plant</span>
+<span class="c"># See following paragraph for more info on contourCut</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">contourCut</span><span class="p">(</span><span class="s">&quot;cropped&quot;</span><span class="p">,</span> <span class="n">resize</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Final Image&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot;final.png&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
+</pre></div>
+</div>
+<img alt="_images/cropped.png" class="align-left" src="_images/cropped.png" />
+<img alt="_images/final1.png" class="align-right" src="_images/final1.png" />
+<div class="row" style="clear:both;"></div><br /><p>You should see your final displayed image!  The <a class="reference internal" href="processing.html#ih.imgproc.Image.contourCut" title="ih.imgproc.Image.contourCut"><code class="xref py py-meth docutils literal"><span class="pre">contourCut()</span></code></a> function crops an image based on contours, or grouped areas of pixels, and only keeps contours in the image that have a minimum required area.  Since the plant is completely connected (unless processing has removed some pixels), it should have a large contour area, and thus is kept within the image.  Finally, we write our image with the name &#8220;final.png&#8221;.</p>
+</div>
+<div class="section" id="python-script">
+<h2>Python Script<a class="headerlink" href="#python-script" title="Permalink to this headline">ΒΆ</a></h2>
+<p><a class="reference download internal" href="_downloads/firstimage.py"><code class="xref download docutils literal"><span class="pre">Download</span> <span class="pre">Script</span></code></a></p>
+<p><a class="reference download internal" href="_downloads/rgbsv1.png"><code class="xref download docutils literal"><span class="pre">Download</span> <span class="pre">Image</span></code></a> (same as above)</p>
+<p>This script performs exactly the process we worked through only as a standalone python script.  Update the image path accordingly, and run it to see the same results, as well as windows for each step.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># Load the library &amp; image</span>
+<span class="kn">import</span> <span class="nn">ih.imgproc</span>
+<span class="n">plant</span> <span class="o">=</span> <span class="n">ih</span><span class="o">.</span><span class="n">imgproc</span><span class="o">.</span><span class="n">Image</span><span class="p">(</span><span class="s">&quot;/path/to/your/image&quot;</span><span class="p">)</span>
+<span class="c"># Save &amp; show the base image</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;base&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Base&quot;</span><span class="p">)</span>
+<span class="c"># Convert to gray, save the image</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">convertColor</span><span class="p">(</span><span class="s">&quot;bgr&quot;</span><span class="p">,</span> <span class="s">&quot;gray&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;gray&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Grayscale&quot;</span><span class="p">)</span>
+<span class="c"># Threshold the image incorrectly AND correctly</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">threshold</span><span class="p">(</span><span class="mi">255</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Threshold 255&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">restore</span><span class="p">(</span><span class="s">&quot;gray&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">threshold</span><span class="p">(</span><span class="mi">190</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;binary&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Threshold 190&quot;</span><span class="p">)</span>
+<span class="c"># Recolor the image</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">bitwise_not</span><span class="p">()</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">convertColor</span><span class="p">(</span><span class="s">&quot;gray&quot;</span><span class="p">,</span> <span class="s">&quot;bgr&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">bitwise_and</span><span class="p">(</span><span class="s">&quot;base&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;recolor&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Recolored Image&quot;</span><span class="p">)</span>
+<span class="c"># Crop the image, produce the final output</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">crop</span><span class="p">([</span><span class="mi">300</span><span class="p">,</span> <span class="mi">2150</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">&quot;x&quot;</span><span class="p">])</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;cropped&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Cropped&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">contourCut</span><span class="p">(</span><span class="s">&quot;cropped&quot;</span><span class="p">,</span> <span class="n">resize</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Final&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot;final.png&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="day-2">
+<h2>Day 2<a class="headerlink" href="#day-2" title="Permalink to this headline">ΒΆ</a></h2>
+<p>Now that we have everything installed, we&#8217;ll work through a pipeline for an image, extract some data, and compare to LemnaTec.</p>
+<p><a class="reference download internal" href="_downloads/0_0_2.png"><code class="xref download docutils literal"><span class="pre">Team</span> <span class="pre">1</span> <span class="pre">Rice</span> <span class="pre">0_0_2</span></code></a></p>
+<p><a class="reference download internal" href="_downloads/pipeline.py"><code class="xref download docutils literal"><span class="pre">The</span> <span class="pre">Pipeline</span></code></a></p>
+<p>The pipline:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">ih.imgproc</span>
+
+<span class="c"># base plant</span>
+<span class="n">plant</span> <span class="o">=</span> <span class="n">ih</span><span class="o">.</span><span class="n">imgproc</span><span class="o">.</span><span class="n">Image</span><span class="p">(</span><span class="s">&quot;0_0_2.png&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;base&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;base&quot;</span><span class="p">)</span>
+
+<span class="c"># blur</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">blur</span><span class="p">((</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;blur&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Blur&quot;</span><span class="p">)</span>
+
+<span class="c"># meanshift</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">meanshift</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">40</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;shift&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Meanshift&quot;</span><span class="p">)</span>
+
+<span class="c"># colorFilter</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">colorFilter</span><span class="p">(</span><span class="s">&quot;(((g &gt; r) and (g &gt; b)) and (((r + g) + b) &lt; 400))&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">colorFilter</span><span class="p">(</span><span class="s">&quot;(((r max g) max b) - ((r min g) min b)) &gt; 12)&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;cf&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Color filter&quot;</span><span class="p">)</span>
+
+<span class="c"># contourCut</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">contourCut</span><span class="p">(</span><span class="s">&quot;cf&quot;</span><span class="p">,</span> <span class="n">basemin</span> <span class="o">=</span> <span class="mi">3000</span><span class="p">,</span> <span class="n">resize</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;cut&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Contour Cut&quot;</span><span class="p">)</span>
+
+<span class="c"># recolor</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">convertColor</span><span class="p">(</span><span class="s">&quot;bgr&quot;</span><span class="p">,</span> <span class="s">&quot;gray&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">threshold</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">convertColor</span><span class="p">(</span><span class="s">&quot;gray&quot;</span><span class="p">,</span> <span class="s">&quot;bgr&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">bitwise_and</span><span class="p">(</span><span class="s">&quot;base&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot;final.png&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Final&quot;</span><span class="p">)</span>
+
+<span class="k">print</span> <span class="n">plant</span><span class="o">.</span><span class="n">extractPixels</span><span class="p">()</span>
+<span class="k">print</span> <span class="n">plant</span><span class="o">.</span><span class="n">extractConvexHull</span><span class="p">()</span>
+
+<span class="n">plant</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>That&#8217;s a lot of code.  Let&#8217;s break it down piece by piece:</p>
+<div class="section" id="loading">
+<h3>Loading<a class="headerlink" href="#loading" title="Permalink to this headline">ΒΆ</a></h3>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">ih.imgproc</span>
+
+<span class="c"># base plant</span>
+<span class="n">plant</span> <span class="o">=</span> <span class="n">ih</span><span class="o">.</span><span class="n">imgproc</span><span class="o">.</span><span class="n">Image</span><span class="p">(</span><span class="s">&quot;0_0_2.png&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;base&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;base&quot;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>This part should be fairly familiar &#8211; we load the Image Harvest library with import ih.imgproc, we load our image &#8220;0_0_2.png&#8221;, and we save &amp; display it under the name &#8220;base&#8221;.</p>
+</div>
+<div class="section" id="blur">
+<h3>Blur<a class="headerlink" href="#blur" title="Permalink to this headline">ΒΆ</a></h3>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># blur</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">blur</span><span class="p">((</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;blur&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Blur&quot;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Here we call the <a class="reference internal" href="processing.html#ih.imgproc.Image.blur" title="ih.imgproc.Image.blur"><code class="xref py py-meth docutils literal"><span class="pre">blur()</span></code></a> function &#8211; which does exactly that.  Blur can take a few arguments, but the most important and only required argument is the first which specifies the kernel size &#8211; a larger kernel means a more blurry output image.  The kernel size is represented as two numbers: (width, height), and both the width and height must be odd and positive.  Try blurring with a kernel size of (15, 15) instead of (5, 5).</p>
+<p>Why blur?  Blurring greatly reduces the noise in an image, which is random variations of pixel colors.  Reducing these variations helps us to more easily define a region in an image.  Look at the inside of the pot for example &#8211; the edges between individual rocks have become much less distinct as a result of the blurring, which makes it easier to percieve as a single continuous region.  The next step continues to reduce variation and separate regions from each other.</p>
+</div>
+<div class="section" id="meanshift">
+<h3>Meanshift<a class="headerlink" href="#meanshift" title="Permalink to this headline">ΒΆ</a></h3>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># meanshift</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">meanshift</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">40</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;shift&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Meanshift&quot;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Here we call the <a class="reference internal" href="processing.html#ih.imgproc.Image.meanshift" title="ih.imgproc.Image.meanshift"><code class="xref py py-meth docutils literal"><span class="pre">meanshift()</span></code></a> function, which performs mean shift segmentation of the image.  Mean shift segmentation groups regions in an image that are geographically close AND close in color.  The first two arguments define the geographically distance, and the third argument defines the color variation allowed.</p>
+<p>Why meanshift?  Meanshift makes the next step in grouping an image into regions.  In this case, we have some very easily defined regions that are close both geographically and close in color.  The plant itself is completely connected and a similar shade of green.  The interior of the pot is contained within a single circle in the image, and is made of similarly colored rocks.  Both of these regions become much more uniform, and thus much easier to process as a result of this step.</p>
+</div>
+<div class="section" id="color-filter">
+<h3>Color Filter<a class="headerlink" href="#color-filter" title="Permalink to this headline">ΒΆ</a></h3>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># colorFilter</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">colorFilter</span><span class="p">(</span><span class="s">&quot;(((g &gt; r) and (g &gt; b)) and (((r + g) + b) &lt; 400))&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">colorFilter</span><span class="p">(</span><span class="s">&quot;(((r max g) max b) - ((r min g) min b)) &gt; 12)&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;cf&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Color filter&quot;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Here we call the <a class="reference internal" href="processing.html#ih.imgproc.Image.colorFilter" title="ih.imgproc.Image.colorFilter"><code class="xref py py-meth docutils literal"><span class="pre">colorFilter()</span></code></a> function, which solves arbitrary color logic and then applies it to the image.  What does that mean?  Effectively, we create a color pattern, and we look for all pixels that match this color pattern.  So this pattern: &#8220;((g &gt; r) and (g &gt; b))&#8221;, reads as: &#8220;Pixels whose green value is greater than their red value AND whose green value is greater than their blue value.&#8221;  In natural language: &#8220;Pixels that are predominantely green.&#8221;  The next pattern: &#8220;(((r + g) + b) &lt; 400))&#8221;, reads as: &#8220;Pixels whose red value plus green value plus blue value is less than 400.&#8221;  In natural language: &#8220;Pixels that aren&#8217;t too bright.&#8221;  Finally we have the pattern: &#8220;(((r max g) max b) - ((r min g) min b)) &gt; 12)&#8221;, which reads as: &#8220;Pixels whose maximum value of r,g,b minus mimim value of r,g,b is greater than 12&#8221;.  In natural language: &#8220;Pixels that aren&#8217;t white, gray, or black.&#8221;</p>
+<p>Why colorFilter?  Processing power.  The colorFilter function is very fast, and can evaluate and apply complex logic in less than a second.  Additionally, since the function evalutes logic on a per-pixel basis, it can adapt to brightness changes or noise in images that a definite color range might miss.</p>
+</div>
+<div class="section" id="contour-cut">
+<h3>Contour Cut<a class="headerlink" href="#contour-cut" title="Permalink to this headline">ΒΆ</a></h3>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># contourCut</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">contourCut</span><span class="p">(</span><span class="s">&quot;cf&quot;</span><span class="p">,</span> <span class="n">basemin</span> <span class="o">=</span> <span class="mi">3000</span><span class="p">,</span> <span class="n">resize</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;cut&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Contour Cut&quot;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Here we call the <a class="reference internal" href="processing.html#ih.imgproc.Image.contourCut" title="ih.imgproc.Image.contourCut"><code class="xref py py-meth docutils literal"><span class="pre">contourCut()</span></code></a> function, which crops an image based on contours in an image, which are connected regions of pixels.  The function searches for all contours in the image that are greater than the size of the basemin parameter, and crops the image to fit those contours.</p>
+<p>Why contourCut?  Removal of edge noise.  The plant itself is completely connected, and thus will have the largest contour in the image by far.  Utilizing this, we can find a value that will keep our plant in the image, while removing a lot of edge noise from it.</p>
+</div>
+<div class="section" id="recoloring">
+<h3>Recoloring<a class="headerlink" href="#recoloring" title="Permalink to this headline">ΒΆ</a></h3>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># recolor</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">convertColor</span><span class="p">(</span><span class="s">&quot;bgr&quot;</span><span class="p">,</span> <span class="s">&quot;gray&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">threshold</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">convertColor</span><span class="p">(</span><span class="s">&quot;gray&quot;</span><span class="p">,</span> <span class="s">&quot;bgr&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">bitwise_and</span><span class="p">(</span><span class="s">&quot;base&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot;final.png&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">show</span><span class="p">(</span><span class="s">&quot;Final&quot;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>What&#8217;s really happening here, is we are creating a mask of our current image, and then overlaying it on our base image to extract our original color.  Blurring and segmenting our image changed its original color, and we want to restore that.  The first 3 lines create the mask.  We first convert the image to grayscale with <a class="reference internal" href="processing.html#ih.imgproc.Image.convertColor" title="ih.imgproc.Image.convertColor"><code class="xref py py-meth docutils literal"><span class="pre">convertColor()</span></code></a>, and then <code class="xref py py-meth docutils literal"><span class="pre">threhsold()</span></code> with a value of 0.  By thresholding the image with a value of 0, we keep every pixel from our grayscale image that has an intensity of at least 1.  This means we keep every non-black pixel from our grayscale image.  We then convert the image back to &#8220;bgr&#8221; from &#8220;gray&#8221;, however, this does NOT restore color to the image.  Our binary image only has a single channel (intensity), but our color image has 3 channels (b, g, r).  We can&#8217;t overlay our mask while it only has a single channel, so we convert it to &#8220;bgr&#8221; to give it 3 channels.  We then use <a class="reference internal" href="processing.html#ih.imgproc.Image.bitwise_and" title="ih.imgproc.Image.bitwise_and"><code class="xref py py-meth docutils literal"><span class="pre">ih.imgproc.Image.bitwise_and()</span></code></a> to overaly our mask on our base image.</p>
+</div>
+<div class="section" id="extraction">
+<h3>Extraction<a class="headerlink" href="#extraction" title="Permalink to this headline">ΒΆ</a></h3>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">print</span> <span class="n">plant</span><span class="o">.</span><span class="n">extractPixels</span><span class="p">()</span>
+<span class="k">print</span> <span class="n">plant</span><span class="o">.</span><span class="n">extractConvexHull</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>The print function is native to python and simply outputs information to the screen.  The <a class="reference internal" href="processing.html#ih.imgproc.Image.extractPixels" title="ih.imgproc.Image.extractPixels"><code class="xref py py-meth docutils literal"><span class="pre">extractPixels()</span></code></a> function returns the total number of non-zero pixels in the image, and the <a class="reference internal" href="processing.html#ih.imgproc.Image.extractConvexHull" title="ih.imgproc.Image.extractConvexHull"><code class="xref py py-meth docutils literal"><span class="pre">extractConvexHull()</span></code></a> function returns the area of the convexHull surrounding all non-black pixels in the image.</p>
+</div>
+</div>
+<div class="section" id="extras">
+<h2>Extras<a class="headerlink" href="#extras" title="Permalink to this headline">ΒΆ</a></h2>
+<img alt="_images/shifted.png" class="align-center" src="_images/shifted.png" />
+</div>
+</div>
+
+
+    </div>
+      
+  </div>
+</div>
+<footer class="footer">
+  <div class="container">
+    <p class="pull-right">
+      <a href="#">Back to top</a>
+      
+    </p>
+    <p>
+        &copy; Copyright 2015, Avi Knecht.<br/>
+      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.3a0.<br/>
+    </p>
+  </div>
+</footer>
+  </body>
+</html>
\ No newline at end of file
diff --git a/docs/build/html/ex_script_color1.html b/docs/build/html/ex_script_color1.html
index a5e9f23773f3d46564b068a192d7bc23893d0e9f..7526f40cbba0c60fd38960b1949832e9290e1aca 100644
--- a/docs/build/html/ex_script_color1.html
+++ b/docs/build/html/ex_script_color1.html
@@ -76,6 +76,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1 current"><a class="current reference internal" href="">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/ex_script_core1.html b/docs/build/html/ex_script_core1.html
index c36fd174afdd3fd32b636fabb3ff78130db50aa7..93c2e8b0e2b073a4456fb2d4c77fd08ca167e1dc 100644
--- a/docs/build/html/ex_script_core1.html
+++ b/docs/build/html/ex_script_core1.html
@@ -76,6 +76,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/ex_script_core2.html b/docs/build/html/ex_script_core2.html
index 5e95f8a389ff30089f76cdb90fb127eedb5027e0..056c5fa3e9840d0ef02c9e3f2d14789c2a06e84a 100644
--- a/docs/build/html/ex_script_core2.html
+++ b/docs/build/html/ex_script_core2.html
@@ -76,6 +76,8 @@
 <li class="toctree-l1 current"><a class="current reference internal" href="">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/ex_workflow_1.html b/docs/build/html/ex_workflow_1.html
index e6b1b5f984bc4b57a34a4fa89b429e2af098c748..27a56f2d80e73f73c3efeedbc79259e2c85524e8 100644
--- a/docs/build/html/ex_workflow_1.html
+++ b/docs/build/html/ex_workflow_1.html
@@ -32,7 +32,7 @@
     <script type="text/javascript" src="_static/bootstrap-sphinx.js"></script>
     <link rel="top" title="Image Harvest 1.0.1 documentation" href="index.html" />
     <link rel="up" title="Examples" href="examples.html" />
-    <link rel="next" title="Image Processing" href="processing.html" />
+    <link rel="next" title="OSG Workflows" href="ex_workflow_2.html" />
     <link rel="prev" title="Color Filter In Depth #1" href="ex_script_color1.html" />
 <meta charset='utf-8'>
 <meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
@@ -76,6 +76,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1 current"><a class="current reference internal" href="">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
@@ -117,7 +119,7 @@
     </a>
   </li>
   <li>
-    <a href="processing.html" title="Next Chapter: Image Processing"><span class="glyphicon glyphicon-chevron-right visible-sm"></span><span class="hidden-sm hidden-tablet">Image Processing &raquo;</span>
+    <a href="ex_workflow_2.html" title="Next Chapter: OSG Workflows"><span class="glyphicon glyphicon-chevron-right visible-sm"></span><span class="hidden-sm hidden-tablet">OSG Workflows &raquo;</span>
     </a>
   </li>
               
@@ -426,51 +428,97 @@ Here, the &#8220;treatment&#8221; translation takes a single character, and maps
 </div>
 <p>In this case, our idchar is &#8216;C&#8217;, this means that the &#8220;treatment&#8221; data key, will get mapped to &#8220;Control&#8221;.  We also have a translation defined for &#8220;imtype&#8221;.  Looking at our test path,
 our imgname is &#8220;RGB SV1&#8221;.  This means that the &#8220;imtype&#8221; data key will get mapped to &#8220;rgbsv&#8221;.  Remember, the key difference between defining translations, and using file mapping is size.</p>
-<p>With our template written, we can now load the images.  We do this using the &#8216;ih-setup&#8217; command as follows:</p>
-<div class="highlight-bash"><div class="highlight"><pre>ih-setup --dir <span class="s2">&quot;DIR_NAME&quot;</span> --template <span class="s2">&quot;crawl.json&quot;</span>
+<p>With our template written, we can now load the images using 2 ih commands.  First,
+run the ih-setup command with the name of the folder you want to create:</p>
+<div class="highlight-bash"><div class="highlight"><pre>ih-setup --dir awesome_project
 </pre></div>
 </div>
-<p>This will setup a workflow submission directory with the name &#8220;DIR_NAME&#8221;.  It will create an input folder,
-and populate that input folder with the images database, the crawl.json template file, and empty template files required for job submission.
-Next we will look at defining the configuration file!</p>
+<p>This command will create a folder with the name you specify, and will create a two
+deep directory structure, with a couple empty files at the bottom:</p>
+<div class="highlight-bash"><div class="highlight"><pre>awesome_project/
+  input/
+    -config.json
+                -crawl.json
+                -images.db
+                -imgproc.json
+                -stats.json
+</pre></div>
+</div>
+<p>The ih commands assume by default that you are in the top level awesome_project/
+directory, using the above naming conventions for your input files.  The naming
+of the input files can be changed by using optional arguments.  Now that the
+project folder is setup, create your crawl.json file.  The above example is
+specific to our input data, so you must adjust the crawl file to match your
+input data.  Once your crawl.json is created, run the ih-crawl command from the
+awesome_project folder:</p>
+<div class="highlight-bash"><div class="highlight"><pre>ih-crawl
+</pre></div>
+</div>
+<p>This command may take a while to run depending on how many images need to be indexed.
+Once it is finished, it should populate the images.db file with an sqlite3 database.
+The database will contain all of the metadata information it parsed from your path
+names, as well as paths to your images.  Using the images.db file, and two additional
+files, a configuration file (config.json) and an workflow definition file (imgproc.json)
+we can submit jobs.</p>
 </div>
 <div class="section" id="configuration">
 <h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">ΒΆ</a></h2>
 <p>The config file contains information that shouldn&#8217;t really change from run to run.  It contains things like installation directories, environment
 variables, and job clustering.  Let&#8217;s take a look.</p>
-<div class="highlight-javascript"><div class="highlight"><pre><span class="p">{</span>
-<span class="s2">&quot;installdir&quot;</span><span class="o">:</span> <span class="s2">&quot;/work/walia/common/ih/pymodules/bin/&quot;</span><span class="p">,</span>
-<span class="s2">&quot;profile&quot;</span><span class="o">:</span> <span class="p">{</span>
-        <span class="s2">&quot;pegasus&quot;</span><span class="o">:</span> <span class="p">{</span>
-                <span class="s2">&quot;style&quot;</span><span class="o">:</span> <span class="s2">&quot;glite&quot;</span>
-        <span class="p">},</span>
-        <span class="s2">&quot;condor&quot;</span><span class="o">:</span> <span class="p">{</span>
-                <span class="s2">&quot;grid_resource&quot;</span><span class="o">:</span> <span class="s2">&quot;pbs&quot;</span><span class="p">,</span>
-                <span class="s2">&quot;universe&quot;</span><span class="o">:</span> <span class="s2">&quot;vanilla&quot;</span>
-        <span class="p">},</span>
-        <span class="s2">&quot;env&quot;</span><span class="o">:</span> <span class="p">{</span>
-                <span class="s2">&quot;PATH&quot;</span><span class="o">:</span> <span class="s2">&quot;/work/walia/common/ih/pymodules/bin/&quot;</span><span class="p">,</span>
-                <span class="s2">&quot;LD_LIBRARY_PATH&quot;</span><span class="o">:</span> <span class="s2">&quot;/work/walia/common/ih/pymodules/opencv_lib/&quot;</span>
-        <span class="p">}</span>
-<span class="p">},</span>
-<span class="s2">&quot;cluster&quot;</span><span class="o">:</span> <span class="mi">100</span><span class="p">,</span>
-<span class="s2">&quot;email&quot;</span><span class="o">:</span> <span class="s2">&quot;avi@kurtknecht.com&quot;</span>
-<span class="p">}</span>
+<div class="highlight-javascript"><div class="highlight"><pre>{
+        &quot;installdir&quot;: &quot;/work/walia/common/ih/pymodules/bin/&quot;,
+        &quot;profile&quot;: {
+                &quot;pegasus&quot;: {
+                        &quot;style&quot;: &quot;glite&quot;
+                },
+                &quot;condor&quot;: {
+                        &quot;grid_resource&quot;: &quot;pbs&quot;,
+                        &quot;universe&quot;: &quot;vanilla&quot;
+                },
+                &quot;env&quot;: {
+                        &quot;PATH&quot;: &quot;/work/walia/common/ih/pymodules/bin/&quot;,
+                                                                                                &quot;PYTHONPATH&quot;: &quot;/work/walia/common/ih/pymodules/lib/python2.6/site-packages
+                        &quot;LD_LIBRARY_PATH&quot;: &quot;/work/walia/common/ih/pymodules/opencv_lib/&quot;
+                }
+        },
+        &quot;cluster&quot;: 100,
+        &quot;maxwalltime&quot;: {
+                &quot;images&quot;: 2,
+                &quot;stats&quot;: 300
+        },
+        &quot;notify&quot;: {
+                &quot;email&quot;: &quot;avi@kurtknecht.com&quot;,
+                &quot;pegasus_home&quot;: &quot;/usr/share/pegasus/&quot;
+        }
+}
 </pre></div>
 </div>
-<p>The &#8220;installdir&#8221; definition is the location where all of ih&#8217;s scripts are installed.  It may seem
-unnecessary to include this as well as a path, but it is important for pegasus to know the exact location
-of executable files.  The &#8220;profile&#8221; defintion supports inclusion of any-possible profile variable for
-the sites.xml.  This is taken directly from the pegasus docs.  To run the workflow on HCC &amp; OSG,
-we specify &#8220;pegasus&#8221;-&gt;&#8221;style&#8221;-&gt;&#8221;glite&#8221;, and &#8220;condor&#8221;-&gt;&#8221;grid_resource&#8221;-&gt;&#8221;pbs&#8221;.  The &#8220;env&#8221; definition
-passes environment variables through to the script.  In this case, we pass in two different path variables.
-One is the location of other executable scripts, in this case our custom python install.  The LD_LIBRARY_PATH
-is for the location of the required libraries for opencv.  It should be noted, that multiple path variables can be included
-by specifying the value as a list i.e. If you specify &#8220;PATH&#8221;: [&#8220;/test/path/1/&#8221;, &#8220;/test/path/2/&#8221;], both paths will
-be loaded into the sites.xml.  &#8220;cluster&#8221; specifies how many jobs you want to clump together.  Most jobs take
-seconds to run, so running-the entire workflow unclustered is very-inefficient.  A cluster size of 100 is used here,
-which means that jobs will be run in batches of 100.  The &#8220;email&#8221; option defines which email to send the results to upon
-completion of the workflow.</p>
+<p>Most of these definitions are fairly straightforward, but some, such as the pegasus
+style and condor universe will be specific to the cluster you use.  Make sure
+you use appropriate pegasus configuration for your system.</p>
+<ol class="arabic simple">
+<li>&#8220;installdir&#8221; - This is simply the location to the ih-commands.</li>
+</ol>
+<p>2. &#8220;profile&#8221; - This definition populates the workflows sites.xml file
+(<cite>sites.xml pegasus docs &lt;http://pegasus.isi.edu/wms/docs/latest/site.php&gt;</cite>).
+The variables defined in here will be very specific for your system.  Make
+sure you use the correct pegasus &amp; condor environment variables.  The &#8220;env&#8221;
+definition passes environment variables through to the processing scripts.
+Make sure that &#8220;PATH&#8221; points to necessary executables, &#8220;PYTHONPATH&#8221; points to
+necessary python modules, and &#8220;LD_LIBRARY_PATH&#8221; points to the required opencv
+libraries.</p>
+<p>3.  &#8220;cluster&#8221; - This argument sets the horizontal cluster size for job execution.
+Because individual image processing steps are fast and don&#8217;t require many resources,
+it is advantageous to cluster them.  The number of clusters depends on how many
+input images you have.</p>
+<p>4. &#8220;maxwalltime&#8221; - This argument defines the maximum wall time for image processing
+jobs, and statitistics workflows.  Cummulative wall time for a single cluster is
+the size of the cluster times the value in the &#8220;images&#8221; definition.  For the
+example above, this means that each cluster of 100 images will request 200 mintues
+of wall time.</p>
+<p>5. &#8220;notify&#8221; - This argument defines the information needed for email notifications
+on workflow completion.  Simply provide an email address, and the path to pegasus_home,
+which contains a notification directory.</p>
 </div>
 <div class="section" id="processing">
 <h2>Processing<a class="headerlink" href="#processing" title="Permalink to this headline">ΒΆ</a></h2>
@@ -948,40 +996,45 @@ final image, though it generally is).  In the arguments section, you define a li
 numeric information you want to extract.  For an example of all arguments you can specify,
 look at the ih-extract script.  If you specify &#8220;histogram-bin&#8221; for a particular
 imtype, the &#8220;&#8211;colors&#8221; options is added automatically.</p>
-<p>Finally, to actually generate your workflow, use the ih-run command.
-You should have setup a directory from the crawling step when you executed</p>
-<div class="highlight-bash"><div class="highlight"><pre>ih-setup --dir <span class="s2">&quot;DIR_NAME&quot;</span> --template <span class="s2">&quot;crawl.json&quot;</span>
-</pre></div>
-</div>
-<p>The easiest way to run ih-run is to change directories to &#8220;DIR_NAME&#8221;, then
-simply run:</p>
+<p>Finally, to actually generate your workflow, use the ih-run command.  Run this
+command from your top level folder that was generated by the ih-setup command.</p>
 <div class="highlight-bash"><div class="highlight"><pre>ih-run
 </pre></div>
 </div>
-<p>with no arguments!  Run with the -h option to see options.  Additionally, the validator
-for processing workflows is very powerful.  Use &#8211;validate to run in validate only mode
-to help debug your workflow as you create it.  Depending on how many input images,
-it may take a while to write the necessary submission files (sometimes 10-20 minutes).</p>
+<p>This will combine the information in your configuration file, workflow definition file,
+and image database to create the necessary files for a pegasus workflow.  Additionally,
+before creating the workflow, it validates arguments and dependencies in your workflow.
+Use &#8211;validate to run in validate only mode to help debug your workflow as you create it.
+Depending on how many input images, it may take a while for ih-run to write the necessary submission files.</p>
 </div>
 <div class="section" id="submission">
 <h2>Submission<a class="headerlink" href="#submission" title="Permalink to this headline">ΒΆ</a></h2>
 <p>Upon sucessful completion of ih-run, a date and timestamped folder should be created
-with the following structure:</p>
-<div class="highlight-bash"><div class="highlight"><pre>date-timestamp/
-  input/
-    imgproc/
-        -sites.xml
-        -conf.rc
-        -map.rc
-        -extract.dax
-        -workflow.dax
-        -notify.sh
-        -submit.sh
-    rawfiles/
-    templates/
-  output/
-    -output.db
-  work/
+in your top level folder.  Your setup should now look like this:</p>
+<div class="highlight-bash"><div class="highlight"><pre>awesome_project/
+        date-timestamp/
+          input/
+            imgproc/
+                -conf.rc
+                -extract.dax
+                -map.rc
+                -notify.sh
+                -remove.sh
+                -sites.xml
+                -status.sh
+                -submit.sh
+                -workflow.dax
+            rawfiles/
+            templates/
+          output/
+            -output.db
+          work/
+        input/
+                -config.json
+                -crawl.json
+                -images.db
+                -imgproc.json
+                -stats.json
 </pre></div>
 </div>
 <p>The work directory is where actual processing is done &#8211; but initially starts empty.  The output
@@ -990,7 +1043,7 @@ contains a copy of your submitted templates in the templates folder, and a copy
 in the rawfiles folder.  Finally, within the imgproc folder are the actual files required to submit
 a pegasus workflow.  All you need to do to submit is execute the submit.sh script.  This will launch your
 workflow, as well as creating a status.sh script for easy monitoring, and a remove.sh script if you
-want to remove your workflow.</p>
+want to remove your workflow.  If there are other pegasus errors you may need to adjust your configuration.</p>
 </div>
 </div>
 
diff --git a/docs/build/html/ex_workflow_2.html b/docs/build/html/ex_workflow_2.html
new file mode 100644
index 0000000000000000000000000000000000000000..3b5bbb4c58368cab4ff325325f12c9dc4eb53c76
--- /dev/null
+++ b/docs/build/html/ex_workflow_2.html
@@ -0,0 +1,242 @@
+<!DOCTYPE html>
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>OSG Workflows &mdash; Image Harvest 1.0.1 documentation</title>
+    
+    <link rel="stylesheet" href="_static/basic.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/bootstrap-3.2.0/css/bootstrap.min.css" type="text/css" />
+    <link rel="stylesheet" href="_static/bootstrap-3.2.0/css/bootstrap-theme.min.css" type="text/css" />
+    <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '1.0.1',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
+    <script type="text/javascript" src="_static/js/jquery-1.11.0.min.js"></script>
+    <script type="text/javascript" src="_static/js/jquery-fix.js"></script>
+    <script type="text/javascript" src="_static/bootstrap-3.2.0/js/bootstrap.min.js"></script>
+    <script type="text/javascript" src="_static/bootstrap-sphinx.js"></script>
+    <link rel="top" title="Image Harvest 1.0.1 documentation" href="index.html" />
+    <link rel="up" title="Examples" href="examples.html" />
+    <link rel="next" title="Arkansas Workshop July 2015" href="arkansas_workshop_july_2015.html" />
+    <link rel="prev" title="Workflow Example #1" href="ex_workflow_1.html" />
+<meta charset='utf-8'>
+<meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
+<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1'>
+<meta name="apple-mobile-web-app-capable" content="yes">
+
+  </head>
+  <body role="document">
+
+  <div id="navbar" class="navbar navbar-default navbar-fixed-top">
+    <div class="container">
+      <div class="navbar-header">
+        <!-- .btn-navbar is used as the toggle for collapsed navbar content -->
+        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".nav-collapse">
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+        </button>
+        <a class="navbar-brand" href="index.html">
+          Image Harvest</a>
+        <span class="navbar-text navbar-version pull-left"><b>1.0</b></span>
+      </div>
+
+        <div class="collapse navbar-collapse nav-collapse">
+          <ul class="nav navbar-nav">
+            
+            
+              <li class="dropdown globaltoc-container">
+  <a role="button"
+     id="dLabelGlobalToc"
+     data-toggle="dropdown"
+     data-target="#"
+     href="index.html">Site <b class="caret"></b></a>
+  <ul class="dropdown-menu globaltoc"
+      role="menu"
+      aria-labelledby="dLabelGlobalToc"><ul class="current">
+<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li>
+<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="start.html">Getting Started</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_script_core1.html">Core Processing Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1 current"><a class="current reference internal" href="">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
+<li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
+<li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
+<li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
+<li class="toctree-l1"><a class="reference internal" href="statistics.html">Statistics</a></li>
+<li class="toctree-l1"><a class="reference internal" href="indexing.html">Image Loading</a></li>
+<li class="toctree-l1"><a class="reference internal" href="workflowimage.html">Image Processing Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="workflowstats.html">Statistics Workflows</a></li>
+</ul>
+</ul>
+</li>
+              
+                <li class="dropdown">
+  <a role="button"
+     id="dLabelLocalToc"
+     data-toggle="dropdown"
+     data-target="#"
+     href="#">Page <b class="caret"></b></a>
+  <ul class="dropdown-menu localtoc"
+      role="menu"
+      aria-labelledby="dLabelLocalToc"><ul>
+<li><a class="reference internal" href="#">OSG Workflows</a><ul>
+<li><a class="reference internal" href="#final-templates">Final Templates</a></li>
+<li><a class="reference internal" href="#configuration">Configuration</a></li>
+</ul>
+</li>
+</ul>
+</ul>
+</li>
+              
+            
+            
+              
+                
+  <li>
+    <a href="ex_workflow_1.html" title="Previous Chapter: Workflow Example #1"><span class="glyphicon glyphicon-chevron-left visible-sm"></span><span class="hidden-sm hidden-tablet">&laquo; Workflow Example...</span>
+    </a>
+  </li>
+  <li>
+    <a href="arkansas_workshop_july_2015.html" title="Next Chapter: Arkansas Workshop July 2015"><span class="glyphicon glyphicon-chevron-right visible-sm"></span><span class="hidden-sm hidden-tablet">Arkansas Worksho... &raquo;</span>
+    </a>
+  </li>
+              
+            
+            
+            
+            
+              <li class="hidden-sm">
+<div id="sourcelink">
+  <a href="_sources/ex_workflow_2.txt"
+     rel="nofollow">Source</a>
+</div></li>
+            
+          </ul>
+
+          
+            
+<form class="navbar-form navbar-right" action="search.html" method="get">
+ <div class="form-group">
+  <input type="text" name="q" class="form-control" placeholder="Search" />
+ </div>
+  <input type="hidden" name="check_keywords" value="yes" />
+  <input type="hidden" name="area" value="default" />
+</form>
+          
+        </div>
+    </div>
+  </div>
+
+<div class="container">
+  <div class="row">
+    <div class="col-md-12">
+      
+  <style> .red {color:red} .blue {color:blue} .green {color:green} .orange {color:orange} </style><div class="section" id="osg-workflows">
+<h1>OSG Workflows<a class="headerlink" href="#osg-workflows" title="Permalink to this headline">ΒΆ</a></h1>
+<p>This section details the modifications necessary to submit your pegasus
+workflows on the <a class="reference external" href="http://www.opensciencegrid.org/">OSG</a>.  Their team has
+set up an environment specifically for our software, so the only changes that
+need to occur are some configuration changes, and creating a tarred version
+of this library.</p>
+<div class="section" id="final-templates">
+<h2>Final Templates<a class="headerlink" href="#final-templates" title="Permalink to this headline">ΒΆ</a></h2>
+<p><a class="reference download internal" href="_downloads/config1.json"><code class="xref download docutils literal"><span class="pre">Configuration</span></code></a></p>
+</div>
+<div class="section" id="configuration">
+<h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline">ΒΆ</a></h2>
+<p>Here is the adjusted configuration file:</p>
+<div class="highlight-javascript"><div class="highlight"><pre><span class="p">{</span>
+    <span class="s2">&quot;installdir&quot;</span><span class="o">:</span> <span class="s2">&quot;/work/walia/common/ih/pymodules/bin/&quot;</span><span class="p">,</span>
+    <span class="s2">&quot;profile&quot;</span><span class="o">:</span> <span class="p">{</span>
+        <span class="s2">&quot;pegasus&quot;</span><span class="o">:</span> <span class="p">{</span>
+            <span class="s2">&quot;style&quot;</span><span class="o">:</span> <span class="s2">&quot;glite&quot;</span>
+        <span class="p">},</span>
+        <span class="s2">&quot;condor&quot;</span><span class="o">:</span> <span class="p">{</span>
+          <span class="s2">&quot;grid_resource&quot;</span><span class="o">:</span> <span class="s2">&quot;pbs&quot;</span><span class="p">,</span>
+          <span class="s2">&quot;universe&quot;</span><span class="o">:</span> <span class="s2">&quot;vanilla&quot;</span>
+        <span class="p">},</span>
+        <span class="s2">&quot;env&quot;</span><span class="o">:</span> <span class="p">{</span>
+            <span class="s2">&quot;PATH&quot;</span><span class="o">:</span> <span class="s2">&quot;/work/walia/common/ih/pymodules/bin/&quot;</span><span class="p">,</span>
+            <span class="s2">&quot;PYTHONPATH&quot;</span><span class="o">:</span> <span class="s2">&quot;/work/walia/common/ih/pymodules/lib/python2.6/site-packages&quot;</span><span class="p">,</span>
+            <span class="s2">&quot;LD_LIBRARY_PATH&quot;</span><span class="o">:</span> <span class="s2">&quot;/work/walia/common/ih/pymodules/opencv_lib/&quot;</span>
+        <span class="p">}</span>
+      <span class="p">},</span>
+      <span class="s2">&quot;cluster&quot;</span><span class="o">:</span> <span class="mi">100</span><span class="p">,</span>
+      <span class="s2">&quot;maxwalltime&quot;</span><span class="o">:</span> <span class="p">{</span>
+                <span class="s2">&quot;images&quot;</span><span class="o">:</span> <span class="mi">2</span><span class="p">,</span>
+                <span class="s2">&quot;stats&quot;</span><span class="o">:</span> <span class="mi">300</span>
+      <span class="p">},</span>
+      <span class="s2">&quot;notify&quot;</span><span class="o">:</span> <span class="p">{</span>
+                <span class="s2">&quot;email&quot;</span><span class="o">:</span> <span class="s2">&quot;avi@kurtknecht.com&quot;</span><span class="p">,</span>
+                <span class="s2">&quot;pegasus_home&quot;</span><span class="o">:</span> <span class="s2">&quot;/usr/share/pegasus/&quot;</span>
+      <span class="p">}</span>
+<span class="p">}</span>
+</pre></div>
+</div>
+<p>Most of the information is the same as the configuration file from the previous
+workflow example, but there are a few differences.  First, the condor configuration
+should have the &#8220;requirements&#8221; and &#8220;+WantsStashCache&#8221; definitions, and they should
+match as above.  The &#8220;+ProjectName&#8221; definition is if you have a group on the OSG.
+Next, there is a version definition, which should match the version of your ih
+tar.  To create a tarball distribution, navigate to your ih install, and run:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">python</span> <span class="n">setup</span><span class="o">.</span><span class="n">py</span> <span class="n">sdist</span>
+</pre></div>
+</div>
+<p>This will create a dist folder, as well as an ih-1.0.tar.gz file.  Pass the
+full path to this file into the &#8220;tarball&#8221; definition.  Finally, for data staging
+and transferring to work successfully, you need to create an ssh key pair
+for your workflow.  Run the following:</p>
+<div class="highlight-bash"><div class="highlight"><pre>ssh-keygen -t rsa -b 2048
+</pre></div>
+</div>
+<p>This while generate an ssh key pair.  You will be prompted for a name and a
+password.  When prompted for the password, hit enter to leave the password blank.
+After this finishes, there should be two files created in your ~/.ssh/ folder,
+a private key file and public key file with the name that you gave.  Append the
+contents of the public key file to your authorized_keys files (create it if
+necessary).</p>
+<div class="highlight-bash"><div class="highlight"><pre>cat ~/.ssh/KEY_NAME.pub &gt;&gt; ~/.ssh/authorized_key
+</pre></div>
+</div>
+<p>Finally provide the full path to the private key for the &#8220;ssh&#8221; definition.</p>
+</div>
+</div>
+
+
+    </div>
+      
+  </div>
+</div>
+<footer class="footer">
+  <div class="container">
+    <p class="pull-right">
+      <a href="#">Back to top</a>
+      
+    </p>
+    <p>
+        &copy; Copyright 2015, Avi Knecht.<br/>
+      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.3a0.<br/>
+    </p>
+  </div>
+</footer>
+  </body>
+</html>
\ No newline at end of file
diff --git a/docs/build/html/examples.html b/docs/build/html/examples.html
index 99f434559b1195a4455dcf8c693b0a29c7839d0d..06fb31dc5996de2f6c0d6c7e0b73e829d4b38193 100644
--- a/docs/build/html/examples.html
+++ b/docs/build/html/examples.html
@@ -75,6 +75,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1 current"><a class="current reference internal" href="">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
@@ -102,6 +104,7 @@
 </ul>
 </li>
 <li><a class="reference internal" href="#workflow-examples">Workflow Examples</a></li>
+<li><a class="reference internal" href="#workshops">Workshops</a></li>
 </ul>
 </li>
 </ul>
@@ -186,6 +189,12 @@ to explain some basic terms.</p>
 <div class="section" id="workflow-examples">
 <h2>Workflow Examples<a class="headerlink" href="#workflow-examples" title="Permalink to this headline">ΒΆ</a></h2>
 <p><a class="reference internal" href="ex_workflow_1.html"><em>Workflow #1</em></a>, difficulty = complex.</p>
+<p><a class="reference internal" href="ex_workflow_2.html"><em>OSG Workflows</em></a></p>
+</div>
+<div class="section" id="workshops">
+<h2>Workshops<a class="headerlink" href="#workshops" title="Permalink to this headline">ΒΆ</a></h2>
+<p>Start to finish tutorials for specific events.</p>
+<p><a class="reference internal" href="arkansas_workshop_july_2015.html"><em>Arkansas Workshop July 2015</em></a></p>
 </div>
 </div>
 
diff --git a/docs/build/html/genindex.html b/docs/build/html/genindex.html
index fe57c3570f82718972a6c87b433f12a9704dba26..5b9e0fdfe63acb7f6ddeb2dea94b3b65c6cc9dfd 100644
--- a/docs/build/html/genindex.html
+++ b/docs/build/html/genindex.html
@@ -74,6 +74,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
@@ -260,9 +262,17 @@
   </dt>
 
       
+  <dt><a href="processing.html#ih.imgproc.Image.extractColorChannels">extractColorChannels() (ih.imgproc.Image method)</a>
+  </dt>
+
+      
   <dt><a href="processing.html#ih.imgproc.Image.extractColorData">extractColorData() (ih.imgproc.Image method)</a>
   </dt>
 
+      
+  <dt><a href="processing.html#ih.imgproc.Image.extractConvexHull">extractConvexHull() (ih.imgproc.Image method)</a>
+  </dt>
+
   </dl></td>
   <td style="width: 33%" valign="top"><dl>
       
@@ -274,6 +284,10 @@
   </dt>
 
       
+  <dt><a href="processing.html#ih.imgproc.Image.extractMinEnclosingCircle">extractMinEnclosingCircle() (ih.imgproc.Image method)</a>
+  </dt>
+
+      
   <dt><a href="processing.html#ih.imgproc.Image.extractMoments">extractMoments() (ih.imgproc.Image method)</a>
   </dt>
 
@@ -321,6 +335,12 @@
   <dt><a href="processing.html#ih.imgproc.Image.kmeans">kmeans() (ih.imgproc.Image method)</a>
   </dt>
 
+  </dl></td>
+  <td style="width: 33%" valign="top"><dl>
+      
+  <dt><a href="processing.html#ih.imgproc.Image.knn">knn() (ih.imgproc.Image method)</a>
+  </dt>
+
   </dl></td>
 </tr></table>
 
@@ -344,16 +364,20 @@
 <table style="width: 100%" class="indextable genindextable"><tr>
   <td style="width: 33%" valign="top"><dl>
       
-  <dt><a href="processing.html#ih.imgproc.Image.meanshift">meanshift() (ih.imgproc.Image method)</a>
+  <dt><a href="processing.html#ih.imgproc.Image.mask">mask() (ih.imgproc.Image method)</a>
   </dt>
 
       
-  <dt><a href="processing.html#ih.imgproc.Image.medianBlur">medianBlur() (ih.imgproc.Image method)</a>
+  <dt><a href="processing.html#ih.imgproc.Image.meanshift">meanshift() (ih.imgproc.Image method)</a>
   </dt>
 
   </dl></td>
   <td style="width: 33%" valign="top"><dl>
       
+  <dt><a href="processing.html#ih.imgproc.Image.medianBlur">medianBlur() (ih.imgproc.Image method)</a>
+  </dt>
+
+      
   <dt><a href="processing.html#ih.imgproc.Image.morphology">morphology() (ih.imgproc.Image method)</a>
   </dt>
 
diff --git a/docs/build/html/index.html b/docs/build/html/index.html
index b02b99cf48190c2356283d18075ef2ecd7d9ad44..5f2af6d3eefc0faab624559900e723e7ff4ba9d9 100644
--- a/docs/build/html/index.html
+++ b/docs/build/html/index.html
@@ -74,6 +74,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
@@ -158,6 +160,7 @@
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a><ul>
 <li class="toctree-l2"><a class="reference internal" href="examples.html#script-examples">Script Examples</a></li>
 <li class="toctree-l2"><a class="reference internal" href="examples.html#workflow-examples">Workflow Examples</a></li>
+<li class="toctree-l2"><a class="reference internal" href="examples.html#workshops">Workshops</a></li>
 </ul>
 </li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
diff --git a/docs/build/html/indexing.html b/docs/build/html/indexing.html
index e6b89964cdc1dfd804103b53f7e180e20ddb2471..aabf672f41b91cfffbadfa69761f2f406899ac46 100644
--- a/docs/build/html/indexing.html
+++ b/docs/build/html/indexing.html
@@ -75,6 +75,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/installation.html b/docs/build/html/installation.html
index 66441b68a193bb40441850ab2c2f05f077e3fcb6..3424a0563e17ab480c8ddeb2eb734e4a594387f2 100644
--- a/docs/build/html/installation.html
+++ b/docs/build/html/installation.html
@@ -75,6 +75,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
@@ -323,7 +325,7 @@ cp pegasus-4.4.0/bin/* /usr/bin/
 <p>Installation for local testing is a breeze with <a class="reference external" href="http://brew.sh">brew</a>.  Installing
 brew simply requires copying a line into a terminal.  The only two packages
 you need to manual download will be PyMeanShift and Image Harvest.
-NOTE: You will have to install XCode, and the XCode Command Line Tools if you have not already. It&#8217;s a free download
+You will have to install <a class="reference external" href="https://developer.apple.com/xcode/">XCode</a>, and the XCode Command Line Tools if you have not already. It&#8217;s a free download
 from the App Store.
 After you have downloaded the packages and installed brew, run the following:</p>
 <div class="highlight-bash"><div class="highlight"><pre><span class="c"># Install *almost* everything in one line</span>
@@ -357,7 +359,7 @@ install several packages before <a class="reference external" href="https://pypi
 in work.  First, install <a class="reference external" href="https://www.python.org/downloads/">python2.7</a>.  Next,
 you have to add python to your PATH environment variable.</p>
 <ul class="simple">
-<li>Windows 7: Right click on Computer &gt; properties &gt; Advanced system settings &gt; Advanced Tab &gt; Enviornment Variables</li>
+<li>Windows 7: Right click on Computer &gt; Properties &gt; Advanced system settings &gt; Advanced Tab &gt; Enviornment Variables</li>
 <li>Windows 8: Control Panel &gt; System &gt; Advanced system settings &gt; Advanced Tab &gt; Environment Variables</li>
 </ul>
 <p>You should see two boxes.  One that says &#8220;User variables for &lt;user&gt;&#8221;, and the other that says
@@ -370,7 +372,7 @@ Finally, download and install <a class="reference external" href="https://pypi.p
 simply be a giant script you copy to a local file, and execute with python.</p>
 <p>Now, you can install all the dependent python packages by finding the correct version for your os,
 and downloading them from this <a class="reference external" href="http://www.lfd.uci.edu/~gohlke/pythonlibs/">link</a>.  You will need the same
-list as above that is, numpy, scipy, pandas, matplotlib, and opencv.</p>
+list as above that is, <a class="reference external" href="http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy">numpy</a>, <a class="reference external" href="http://www.lfd.uci.edu/~gohlke/pythonlibs/#scipy">scipy</a>, <a class="reference external" href="http://www.lfd.uci.edu/~gohlke/pythonlibs/#pandas">pandas</a>, <a class="reference external" href="http://www.lfd.uci.edu/~gohlke/pythonlibs/#matplotlib">matplotlib</a>, and <a class="reference external" href="http://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv">opencv</a>.</p>
 <div class="highlight-bash"><div class="highlight"><pre><span class="c"># For each downloaded wheel file, you will</span>
 <span class="c"># need to run the following from a command prompt</span>
 pip install name.whl
diff --git a/docs/build/html/introduction.html b/docs/build/html/introduction.html
index 505750aa72a4113f5dc46322f6cd210f17f58c6e..6220b3c78b80b42b59ff62d8c1cff2d10689cedf 100644
--- a/docs/build/html/introduction.html
+++ b/docs/build/html/introduction.html
@@ -75,6 +75,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/objects.inv b/docs/build/html/objects.inv
index 4b5be9fecf69be96c26b994f17d247848b6519e7..d649d6255d540c464387fa9018a8b22b58dbc728 100644
Binary files a/docs/build/html/objects.inv and b/docs/build/html/objects.inv differ
diff --git a/docs/build/html/processing.html b/docs/build/html/processing.html
index 909b946a18a67e671b3ee4f20d1cc2cf844da414..f715bb263a1f9b81a5b82cb5b7ab0dd7da169753 100644
--- a/docs/build/html/processing.html
+++ b/docs/build/html/processing.html
@@ -32,7 +32,7 @@
     <script type="text/javascript" src="_static/bootstrap-sphinx.js"></script>
     <link rel="top" title="Image Harvest 1.0.1 documentation" href="index.html" />
     <link rel="next" title="Image Processing Viewer" href="viewer.html" />
-    <link rel="prev" title="Workflow Example #1" href="ex_workflow_1.html" />
+    <link rel="prev" title="Arkansas Workshop July 2015" href="arkansas_workshop_july_2015.html" />
 <meta charset='utf-8'>
 <meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
 <meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1'>
@@ -75,6 +75,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1 current"><a class="current reference internal" href="">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
@@ -105,7 +107,7 @@
               
                 
   <li>
-    <a href="ex_workflow_1.html" title="Previous Chapter: Workflow Example #1"><span class="glyphicon glyphicon-chevron-left visible-sm"></span><span class="hidden-sm hidden-tablet">&laquo; Workflow Example...</span>
+    <a href="arkansas_workshop_july_2015.html" title="Previous Chapter: Arkansas Workshop July 2015"><span class="glyphicon glyphicon-chevron-left visible-sm"></span><span class="hidden-sm hidden-tablet">&laquo; Arkansas Worksho...</span>
     </a>
   </li>
   <li>
@@ -148,7 +150,76 @@
 <p>This page contains specific implementation details of image processing functions.
 Additionally, the next page contains an interactive image processing function viewer.
 It allows for adjusting inputs and seeing results of many different functions
-on several different sample input images.</p>
+on several different sample input images.  Before talking about processing functions,
+we are first going to talk about inputting resources.</p>
+<h3>Images</h3><p>Images are mostly input at the beginning of processing,
+but there area few functions such as <a class="reference internal" href="#ih.imgproc.Image.bitwise_and" title="ih.imgproc.Image.bitwise_and"><code class="xref py py-meth docutils literal"><span class="pre">bitwise_and()</span></code></a>
+that take additional images as inputs.  When first loading the image,
+it can be constructed with either a path to the image or a raw numpy array.
+When loading an additional image into a function, it can be a path, a numpy array,
+or a state.  Loading an image from a path simply requires a string of an absolute or relative path
+to the image.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">plant</span> <span class="o">=</span> <span class="n">ih</span><span class="o">.</span><span class="n">imgproc</span><span class="o">.</span><span class="n">Image</span><span class="p">(</span><span class="s">&quot;/path/to/your/image.png&quot;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Most of the time other methods of input are not required, but they can
+be useful in certain circumstances.  OpenCV represnts images as numpy arrays &#8211;
+effectively, a large matrix that has a blue, green, and red value at each of the indices.
+By allowing images to be loaded in as a numpy array directly, Image Harvest can be used in
+conjunction with any other image tool that also uses OpenCV or represents images as numpy arrays.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">im</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">imread</span><span class="p">(</span><span class="s">&quot;/path/to/your/image.png&quot;</span><span class="p">)</span>
+<span class="n">plant</span> <span class="o">=</span> <span class="n">ih</span><span class="o">.</span><span class="n">imgproc</span><span class="o">.</span><span class="n">Image</span><span class="p">(</span><span class="n">im</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Finally, you can pass in a state to a function to use a previously saved image.
+Because states require you to save something first, you cannot instantiate an
+image with a state.  This is particularly useful when recoloring a thresholded image:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">plant</span> <span class="o">=</span> <span class="n">ih</span><span class="o">.</span><span class="n">imgproc</span><span class="o">.</span><span class="n">Image</span><span class="p">(</span><span class="s">&quot;/path/to/your/image.png&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">&quot;base&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">convertColor</span><span class="p">(</span><span class="s">&quot;bgr&quot;</span><span class="p">,</span> <span class="s">&quot;gray&quot;</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">threshold</span><span class="p">(</span><span class="mi">127</span><span class="p">)</span>
+<span class="n">plant</span><span class="o">.</span><span class="n">bitwise_and</span><span class="p">(</span><span class="s">&quot;base&quot;</span><span class="p">)</span>
+</pre></div>
+</div>
+<h3>ROI's</h3><p>Regions Of Interest can also be input as either a list, or a json file.  If a region of interest is input as a list it should be of the form:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="p">[</span><span class="n">ystart</span><span class="p">,</span> <span class="n">yend</span><span class="p">,</span> <span class="n">xstart</span><span class="p">,</span> <span class="n">xend</span><span class="p">]</span>
+</pre></div>
+</div>
+<p>If a ROI is input as a json file, it should look like the following:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="p">{</span>
+    <span class="s">&quot;ystart&quot;</span><span class="p">:</span> <span class="n">YOUR_VALUE</span><span class="p">,</span>
+    <span class="s">&quot;yend&quot;</span><span class="p">:</span> <span class="n">YOUR_VALUE</span><span class="p">,</span>
+    <span class="s">&quot;xstart&quot;</span><span class="p">:</span> <span class="n">YOUR_VALUE</span><span class="p">,</span>
+    <span class="s">&quot;xend&quot;</span><span class="p">:</span> <span class="n">YOUR_VALUE</span>
+<span class="p">}</span>
+</pre></div>
+</div>
+<p>Each individual ROI argument has some special options.  Each argument can be auto-filled by using a value of -1.  For &#8220;xstart&#8221; and &#8220;ystart&#8221; this simply assigns a value of 0, but for &#8220;xend&#8221; and &#8220;yend&#8221; this fills the width and height of the image respectively. This isn&#8217;t as necessary for the starting values, but can be useful for the ending values.  For example, let&#8217;s say we want an roi that skips the first 400 pixels from the left / top side of our image:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># List style</span>
+<span class="p">[</span><span class="mi">400</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">400</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">]</span>
+<span class="c"># Json style</span>
+<span class="p">{</span>
+    <span class="s">&quot;ystart&quot;</span><span class="p">:</span> <span class="mi">400</span><span class="p">,</span>
+    <span class="s">&quot;yend&quot;</span><span class="p">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
+    <span class="s">&quot;xstart&quot;</span><span class="p">:</span> <span class="mi">400</span><span class="p">,</span>
+    <span class="s">&quot;xend&quot;</span><span class="p">:</span> <span class="o">-</span><span class="mi">1</span>
+<span class="p">}</span>
+</pre></div>
+</div>
+<p>Instead of using -1 you can also use &#8220;x&#8221; and &#8220;y&#8221; to represent the full width and height respectively.
+Adjusting the previous example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># List style</span>
+<span class="p">[</span><span class="mi">400</span><span class="p">,</span> <span class="s">&quot;y&quot;</span><span class="p">,</span> <span class="mi">400</span><span class="p">,</span> <span class="s">&quot;x&quot;</span><span class="p">]</span>
+<span class="c"># Json style</span>
+<span class="p">{</span>
+    <span class="s">&quot;ystart&quot;</span><span class="p">:</span> <span class="mi">400</span><span class="p">,</span>
+    <span class="s">&quot;yend&quot;</span><span class="p">:</span> <span class="s">&quot;y&quot;</span><span class="p">,</span>
+    <span class="s">&quot;xstart&quot;</span><span class="p">:</span> <span class="mi">400</span><span class="p">,</span>
+    <span class="s">&quot;xend&quot;</span><span class="p">:</span> <span class="s">&quot;x&quot;</span>
+<span class="p">}</span>
+</pre></div>
+</div>
+<p>Finally, each individual argument can have a single arithmetic operation in it (except for multiplication).  Utilizing this, we can create fairly complex ROI&#8217;s without too much effort.  For example, here is an ROI that targets only the bottom half of your image, and ignores 300 pixels on both the left and right sides:</p>
 <dl class="class">
 <dt id="ih.imgproc.Image">
 <em class="property">class </em><code class="descclassname">ih.imgproc.</code><code class="descname">Image</code><span class="sig-paren">(</span><em>input</em>, <em>outputdir='.'</em>, <em>writename=None</em>, <em>dev=False</em>, <em>db=None</em>, <em>dbid=None</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image" title="Permalink to this definition">ΒΆ</a></dt>
@@ -312,8 +383,7 @@ of extrapolation depends on the specified &#8216;borderType&#8217;, and can be o
 </tbody>
 </table>
 <p>This function applies a color filter defined by the input logic, to a
-targeted region defined by the input roi.  The roi is defined the same,
-[ystart, yend, xstart, xend].  The logic string itself is fairly complicated.
+targeted region defined by the input roi. The logic string itself is fairly complicated.
 The string supports the following characters: &#8216;+&#8217;, &#8216;-&#8216;, &#8216;*&#8217;, &#8216;/&#8217;, &#8216;&gt;&#8217;, &#8216;&gt;=&#8217;,
 &#8216;==&#8217;, &#8216;&lt;&#8217;, &#8216;&lt;=&#8217;, &#8216;and&#8217;, &#8216;or&#8217;, &#8216;(&#8216;, &#8216;)&#8217;, &#8216;r&#8217;, &#8216;g&#8217;, &#8216;b&#8217;, &#8216;max&#8217;, and &#8216;min&#8217; as well as any numeric
 value.  The logic string itself must be well formed &#8211; each 
@@ -490,6 +560,12 @@ database, and the name you specify for you bin will be
 the column name in the database.</p>
 </dd></dl>
 
+<dl class="method">
+<dt id="ih.imgproc.Image.extractColorChannels">
+<code class="descname">extractColorChannels</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.extractColorChannels"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.extractColorChannels" title="Permalink to this definition">ΒΆ</a></dt>
+<dd><p>This function is similar to the</p>
+</dd></dl>
+
 <dl class="method">
 <dt id="ih.imgproc.Image.extractColorData">
 <code class="descname">extractColorData</code><span class="sig-paren">(</span><em>nonzero=True</em>, <em>returnhist=False</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.extractColorData"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.extractColorData" title="Permalink to this definition">ΒΆ</a></dt>
@@ -511,7 +587,27 @@ specified.  Because images are imported with the channels ordered as B,G,R,
 the output list is returned the same way.  The returned list always looks like
 this: [ [BlueMean, BlueMedian], [GreenMean, GreenMedian], [RedMean, RedMedian] ].
 Mean values always come before median values.  If nonzero is set to true (default)
-the function will only calculate mediapytn and means based on the non-black pixels.</p>
+the function will only calculate mediapytn and means based on the non-black pixels.
+If you are connected to a database, the entire histogram is saved to the database,
+not just the mean and median.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="ih.imgproc.Image.extractConvexHull">
+<code class="descname">extractConvexHull</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.extractConvexHull"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.extractConvexHull" title="Permalink to this definition">ΒΆ</a></dt>
+<dd><table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Returns:</th><td class="field-body">The area of the convex hull.</td>
+</tr>
+<tr class="field-even field"><th class="field-name">Return type:</th><td class="field-body">int</td>
+</tr>
+</tbody>
+</table>
+<p>Returns the area of the convex hull around all non black pixels in the image.
+The point of this function is not to threshold, so the contours are generate from
+all the pixels that fall into the range [1, 1, 1], [255, 255, 255]</p>
 </dd></dl>
 
 <dl class="method">
@@ -536,6 +632,25 @@ the function will only calculate mediapytn and means based on the non-black pixe
 <dd><p>This function writes the absolute path of the output file to the database.</p>
 </dd></dl>
 
+<dl class="method">
+<dt id="ih.imgproc.Image.extractMinEnclosingCircle">
+<code class="descname">extractMinEnclosingCircle</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.extractMinEnclosingCircle"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.extractMinEnclosingCircle" title="Permalink to this definition">ΒΆ</a></dt>
+<dd><table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Returns:</th><td class="field-body">The center, and radius of the minimum enclosing circle.</td>
+</tr>
+<tr class="field-even field"><th class="field-name">Return type:</th><td class="field-body">int</td>
+</tr>
+</tbody>
+</table>
+<p>Returns the center and radius of the minimum enclosing circle of all
+non-black pixels in the image.  The point of this function
+is not to threshold, so the contours are generated from
+all the pixels that fall into the range [1, 1, 1], [255, 255, 255].</p>
+</dd></dl>
+
 <dl class="method">
 <dt id="ih.imgproc.Image.extractMoments">
 <code class="descname">extractMoments</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.extractMoments"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.extractMoments" title="Permalink to this definition">ΒΆ</a></dt>
@@ -599,7 +714,7 @@ of extrapolation depends on the specified &#8216;borderType&#8217;, and can be o
 
 <dl class="method">
 <dt id="ih.imgproc.Image.kmeans">
-<code class="descname">kmeans</code><span class="sig-paren">(</span><em>k</em>, <em>criteria</em>, <em>maxiter=10</em>, <em>accuracy=1.0</em>, <em>attempts=10</em>, <em>flags='random'</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.kmeans"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.kmeans" title="Permalink to this definition">ΒΆ</a></dt>
+<code class="descname">kmeans</code><span class="sig-paren">(</span><em>k</em>, <em>criteria</em>, <em>maxiter=10</em>, <em>accuracy=1.0</em>, <em>attempts=10</em>, <em>flags='random'</em>, <em>labels=None</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.kmeans"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.kmeans" title="Permalink to this definition">ΒΆ</a></dt>
 <dd><table class="docutils field-list" frame="void" rules="none">
 <col class="field-name" />
 <col class="field-body" />
@@ -626,12 +741,57 @@ runs until one of the conditions is satisfied.  The flags parameter determines t
 and should be either &#8216;random&#8217; &#8211; to generate a random initial guess &#8211; or &#8216;pp&#8217; to use center initialization by Arthur and Vassilvitskii.</p>
 </dd></dl>
 
+<dl class="method">
+<dt id="ih.imgproc.Image.knn">
+<code class="descname">knn</code><span class="sig-paren">(</span><em>k</em>, <em>labels</em>, <em>remove=[]</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.knn"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.knn" title="Permalink to this definition">ΒΆ</a></dt>
+<dd><table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
+<li><strong>k</strong> (<a class="reference external" href="http://docs.python.org/library/functions.html#int" title="(in Python v2.7)"><em>int</em></a>) &#8211; Number of nearest neighbors to use</li>
+<li><strong>labels</strong> (<a class="reference external" href="http://docs.python.org/library/functions.html#file" title="(in Python v2.7)"><em>file</em></a>) &#8211; Path to label file.  More info below</li>
+<li><strong>remove</strong> (<a class="reference external" href="http://docs.python.org/library/functions.html#list" title="(in Python v2.7)"><em>list</em></a>) &#8211; Labels to remove from final image.</li>
+</ul>
+</td>
+</tr>
+</tbody>
+</table>
+<p>This function is a wrapper to the OpenCV function <a class="reference external" href="http://docs.opencv.org/modules/ml/doc/k_nearest_neighbors.html">KNearest</a>.
+The label file should contain training data in json format, using the label name of keys, and all 
+the colors matching that label as an array value.  Each color should be a list of 3 values, in BGR order.  That is:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="p">{</span>
+    <span class="s">&quot;plant&quot;</span><span class="p">:</span> <span class="p">[</span>
+        <span class="p">[</span><span class="mi">234</span><span class="p">,</span> <span class="mi">125</span><span class="p">,</span> <span class="mi">100</span><span class="p">],</span>
+        <span class="p">[</span><span class="mi">100</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">100</span><span class="p">]</span>
+    <span class="p">],</span>
+    <span class="s">&quot;pot&quot;</span><span class="p">:</span> <span class="p">[</span>
+    <span class="o">...</span>
+<span class="p">}</span>
+</pre></div>
+</div>
+<p>When creating your label file, make sure to use helpful names.  Calling each set of colors &#8220;label1&#8221;, &#8220;label2&#8221; e.t.c
+provides no meaningful information.  The remove list is the list of matched labels to remove from the final image.
+The names to remove should match the names in your label file exactly. For example, let&#8217;s say you have the labels
+&#8220;plant&#8221;, &#8220;pot&#8221;, &#8220;track&#8221;, and &#8220;background&#8221; defined, and you only want to keep pixels that match the &#8220;plant&#8221; label.
+Your remove list should be specified as [&#8220;pot&#8221;, &#8220;track&#8221;, &#8220;background&#8221;].</p>
+</dd></dl>
+
 <dl class="method">
 <dt id="ih.imgproc.Image.list">
 <code class="descname">list</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.list"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.list" title="Permalink to this definition">ΒΆ</a></dt>
 <dd><p>Lists all saved states.</p>
 </dd></dl>
 
+<dl class="method">
+<dt id="ih.imgproc.Image.mask">
+<code class="descname">mask</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.mask"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.mask" title="Permalink to this definition">ΒΆ</a></dt>
+<dd><p>This function convers the image to a color mask by performing the following operations:
+* <code class="xref py py-meth docutils literal"><span class="pre">convertColor(&quot;bgr&quot;,</span> <span class="pre">&quot;gray&quot;)()</span></code>
+* :py:meth:<a href="#id1"><span class="problematic" id="id2">`</span></a>~ih.imgproc.Image.threshold(0)
+* :py:meth:<a href="#id3"><span class="problematic" id="id4">`</span></a>~ih.imgproc.Image.convertColor(&#8220;gray&#8221;, &#8220;bgr&#8221;)</p>
+</dd></dl>
+
 <dl class="method">
 <dt id="ih.imgproc.Image.meanshift">
 <code class="descname">meanshift</code><span class="sig-paren">(</span><em>spatial_radius</em>, <em>range_radius</em>, <em>min_density</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.meanshift"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.meanshift" title="Permalink to this definition">ΒΆ</a></dt>
@@ -640,8 +800,8 @@ and should be either &#8216;random&#8217; &#8211; to generate a random initial g
 <col class="field-body" />
 <tbody valign="top">
 <tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
-<li><strong>spatial_radius</strong> (<a class="reference external" href="http://docs.python.org/library/functions.html#float" title="(in Python v2.7)"><em>float</em></a>) &#8211; Spatial Radius</li>
-<li><strong>range_radius</strong> (<a class="reference external" href="http://docs.python.org/library/functions.html#float" title="(in Python v2.7)"><em>float</em></a>) &#8211; Range Radius.</li>
+<li><strong>spatial_radius</strong> (<a class="reference external" href="http://docs.python.org/library/functions.html#int" title="(in Python v2.7)"><em>int</em></a>) &#8211; Spatial Radius</li>
+<li><strong>range_radius</strong> (<a class="reference external" href="http://docs.python.org/library/functions.html#int" title="(in Python v2.7)"><em>int</em></a>) &#8211; Range Radius.</li>
 <li><strong>min_density</strong> (<a class="reference external" href="http://docs.python.org/library/functions.html#int" title="(in Python v2.7)"><em>int</em></a>) &#8211; Minimum Density.</li>
 </ul>
 </td>
@@ -712,7 +872,7 @@ multiplying the original number by 255, and dividing by the intensity, that is,
 
 <dl class="method">
 <dt id="ih.imgproc.Image.resize">
-<code class="descname">resize</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.resize"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.resize" title="Permalink to this definition">ΒΆ</a></dt>
+<code class="descname">resize</code><span class="sig-paren">(</span><em>state=None</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.resize"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.resize" title="Permalink to this definition">ΒΆ</a></dt>
 <dd><p>If the image is large than conf.maxArea, resize its total area down to conf.maxArea.
 This function is primarily used for viewing purposes, and as such, it does not resize
 the base image, but creates a copy to resize instead.</p>
@@ -772,7 +932,7 @@ method.</p>
 
 <dl class="method">
 <dt id="ih.imgproc.Image.show">
-<code class="descname">show</code><span class="sig-paren">(</span><em>title=None</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.show"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.show" title="Permalink to this definition">ΒΆ</a></dt>
+<code class="descname">show</code><span class="sig-paren">(</span><em>title=None</em>, <em>state=None</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/ih/imgproc.html#Image.show"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#ih.imgproc.Image.show" title="Permalink to this definition">ΒΆ</a></dt>
 <dd><table class="docutils field-list" frame="void" rules="none">
 <col class="field-name" />
 <col class="field-body" />
diff --git a/docs/build/html/search.html b/docs/build/html/search.html
index 58b3f620027e3068a9c58279f5b830682ba18531..7fa362f6181b724a9df9e56cd6dbf839a9bd5816 100644
--- a/docs/build/html/search.html
+++ b/docs/build/html/search.html
@@ -81,6 +81,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/searchindex.js b/docs/build/html/searchindex.js
index 70bd9486732221dc01bb59beb07a7f069fb79e1b..a715eeed1d16e33a0b57a42535014cc45a591dcd 100644
--- a/docs/build/html/searchindex.js
+++ b/docs/build/html/searchindex.js
@@ -1 +1 @@
-Search.setIndex({envversion:42,terms:{roi:[14,4,2],all:[13,1,2,7,5,4,8,9,12,3,14],code:[14,5],edg:[10,14,4,2],chain:[9,14],osx:[],perl:3,focus:[12,2],binlist:4,secondli:14,prefix:[4,3],concept:5,abil:6,edu:3,follow:[2,5,4,9,12,3,14],basemin:[14,4,2],either:[1,14,4],"0_0":14,row:14,compact:4,cython:3,object:[9,2,5],accur:[4,2],depend:[],extractpixel:[4,2],pydata:[],readabl:4,specif:[13,1,3,7,5,4,9,11,12,14],send:14,fitler:2,program:[4,2,5],those:[14,11],under:[12,14,4,2,5],leav:[14,3],filetyp:14,introduc:5,rpmfusion:[],datafil:1,filtrat:2,everi:14,string:[12,14,4,2],dateformat:1,outtabl:1,pymeanshift:[4,3],unfamiliar:11,logiclist:12,util:4,verb:5,volum:[],enviorn:3,fall:[1,11,4],veri:[12,14,4,2,11],appar:14,imageprocessor:7,exact:[12,14,4,2,5],relev:[1,14],four:1,"09c8d0b2229f813c1b93":3,level:[],did:1,bla:3,list:[14,3,1,2,4],bright:2,iter:4,logic0:12,adjust:[9,4,2,3],red:[12,4,14,5],small:[14,2],div:[],refer:[4,2],prepar:2,dir:14,pleas:6,pase:5,impli:2,smaller:12,fortran:3,difficulti:11,natur:11,seper:[2,5],direct:[1,2,4],crop:[10,14,4,2],sign:14,jump:[9,11],greatli:[9,2],zero:2,possibl:14,design:14,aggreg:1,fluosv_pot2:14,pass:[4,14,5],download:[12,3,2,11,5],further:[9,14],medianblur:4,odd:4,outputdir:[9,4,2],bluemean:4,blue:[12,14,4,2,5],index:[0,14],what:[12,9,14,2,5],hide:2,sub:14,convertcolor:[9,4,2,5],section:[9,14,2,5],advanc:3,bmed:2,fluosv1:10,fluosv2:10,current:[13,1,2,7,5,4,14],version:3,osg:[14,11],blur:[10,14,4,2],"new":[13,7,3,4,5],net:[],method:[9,4,2,5],metadata:9,tusker:14,involv:14,full:14,themselv:[12,9,1,14],deriv:[],whose:[12,4],variat:1,gener:[1,3,6,4,9,14],like:[14,3,4,2,5],giant:3,here:[12,3,14,2,5],satisfi:4,modular:6,shouldn:14,let:[12,14,4,2,5],ubuntu:[],path:[3,5,4,12,2,14],along:14,ineffici:14,resizeself:4,sinc:[12,14],valu:[1,2,5,4,12,14],cf1:3,box:[14,4,3],convert:[1,2,5,10,4,9,12,14],pretti:2,howev:[12,4,14,11],shift:[10,4,14,5],larger:[12,2],step:[2,5,4,9,11,14],localinstal:[],amount:4,writenam:4,throughput:[],within:[9,4,14],action:5,chang:[14,2,5],magnitud:4,control:[14,1,3],batch:14,repositori:3,extra:[14,2],appli:[12,4,14],modul:[0,4,2,5],imgproc:[2,5,4,9,12,14],apt:3,"05_05":14,filenam:1,unix:[],bitwise_and:[4,2],ystart:[14,4,2],"1st":14,instal:[],total:[14,1,2,4],installdir:14,select:12,highli:[3,11],extrapol:4,fed:2,from:[1,2,5,4,8,9,12,3,14],zip:3,distinct:6,subtract:[4,2],univers:14,upgrad:3,noarch:[],few:[9,14],htcondor:3,call:[1,3,5,4,12,2],bash:[12,9,2,3,5],criteria:4,taken:[9,14],black:[12,4],panel:3,type:[14,1,2,4,5],until:[14,4,3,5],thresh75:5,more:[14,3,4,2],sort:14,wrapper:[4,2],relat:[12,14,5],hurt:2,flag:4,oop:5,particular:[12,4,14,11],actual:[1,2,5,4,12,14],hold:12,easiest:14,starter:9,must:[1,2,4,9,12,14],placehold:[14,2],rawfil:14,none:[14,1,4,7],word:[14,2,5],sometim:[14,3],restor:[12,4,2,5],local:[9,3,11],setup:[3,14,2,5],work:[1,3,6,9,11,14],unused_2:14,unused_1:14,remain:2,nebraska:14,dev:4,learn:11,meet:2,deb:3,purpos:[14,4,2,5],avi:[6,14],input2:2,nearest:4,input1:2,prompt:3,tab:3,tar:3,give:[4,2],c95ac804525aac4b6dba79b00b39d1d3:3,sudo:3,calcul:[14,1,2,4],topic:[],sourc:[13,1,3,7,6,4,8,9],pegasus_4:3,want:[1,2,5,4,12,14],aknecht2:[],kurtknecht:[6,14],occur:[12,14],kwidth:[14,2],alwai:[4,14],"09_10":14,multipl:[12,1,14,4,5],divid:[4,14],rather:9,anoth:3,comfort:14,write:[1,2,5,4,8,9,12,14],how:[2,5,4,9,11,14],extractbin:4,confin:[],env:14,holland:14,instead:[14,1,2,4,5],csv:[14,1,8],config:[9,14],bin2:4,map:14,plant:[],express:1,resourc:3,outsid:[4,2],rgbtv:14,max:[12,14,4,2],clone:[],after:[12,3,1,2,5],blackhat:4,lab:[4,2],reflect:4,befor:[1,2,4,9,11,12,3,14],mac:[],gtk2:3,echo:3,mai:[14,3,4,2],end:[14,1,2,5],underscor:14,varianc:2,data:[1,2,8,9,11,14],averag:2,rhel6:3,stress:[1,14],github:0,noun:5,save:[12,14,4,2,5],tutori:[9,14,3],contourcut:[4,2],strict:14,reconstiut:14,correspond:[1,14,4],exclud:[12,2],ycrcb:[4,2],inform:[13,1,2,7,4,9,14],maintain:[4,2],green:[12,14,4,2,5],binx:1,allow:[4,14],enter:14,exclus:4,order:[2,4,8,9,12,14],talk:[12,14,2,5],includ:[14,3,4,2,11],old_script:14,origin:[4,2],help:[6,9,14,2],wut:[],erod:[4,2],over:[4,2],move:3,becaus:[14,9,4,2,5],cross:4,i386:[],paper:[],through:[14,3,4,8,11],workflow1:[],libav:3,still:[9,14,2],returnlist:4,rgbtv_edg:14,paramet:[1,4],style:[1,14],group:[1,14,5],monitor:14,binari:[14,4,2],chosen:4,pcv:[],better:[1,11],window:[],complex:[4,14,11],whole:[4,14],mediapytn:4,main:[12,9],pixel:[1,2,5,4,12,14],split:14,them:[1,2,5,4,9,3,14],good:[9,2],"return":[12,14,4,2],greater:[12,4,2,5],thei:[12,14,4,3,11],handl:[9,4,8],timestamp:[13,7,14],colorfilt:[12,4,2],initi:[4,14,5],devel:[],"break":[14,4,2],now:[3,14,2,5],dax:14,introduct:[],choic:14,term:11,cutoff:5,name:[],logic2:12,edit:3,simpl:[9,4,2],revers:2,separ:[12,3,14,2,5],micro:9,submit:[6,13,14,7,3],mode:[4,14],each:[1,2,5,4,9,11,12,3,14],debug:14,found:9,updat:[1,3],side:[1,14,4],truncat:4,mean:[2,5,10,4,9,12,14],subset:14,manag:[14,3],notabl:5,just:[14,4,2,5],keycolumn:14,resum:5,chunk:14,hard:[14,5],continu:[12,4,2],procedur:4,realli:14,contrib:3,meta:[14,8],connect:2,operand:2,our:[12,14,2,5],happen:2,extractfinalpath:4,orient:5,special:[12,14],out:[9,14,2,3],variabl:[14,9,4,3],accomplish:[14,5],join:12,space:[4,14],gradient:4,dbid:4,idnum:14,research:3,categori:[12,11],hcc:14,fairli:[14,4,2],adapt:[6,10,14,4,2],range_radiu:[4,14],print:2,lib64:3,size:[14,9,4,2],bordertyp:4,correct:3,math:[],common:[14,3],foreground:4,linear:5,insid:14,workflow:[],spectrum:[14,1,2,5],differ:[1,2,5,6,4,9,11,12,14],free:3,parenthesi:[12,4,2],whera:4,reason:5,base:[13,1,2,7,5,4,8,9,12,14],clean:2,dictionari:4,latest:3,releas:3,r79:3,rmed:[1,2],afterward:14,rect:[4,2],care:14,thrown:4,returnbound:[4,14],wai:[1,5,4,9,11,12,14],launch:14,could:14,area:[14,4,2],put:3,moment:[4,14],keep:[2,5,4,9,12,3,14],counterpart:14,thing:14,isi:3,min_dens:[4,14],place:[1,14],isn:[9,14],s_2013:14,use_mirror:[],box_filt:14,clump:14,assign:[14,2],first:[1,2,5,4,9,11,12,3,14],oper:[12,4,2],dimens:14,major:[9,14,2,5],notifi:14,sobel:4,x86_64:3,onc:[2,5],arrai:4,independ:4,number:[12,14,4,2],gfilter1:14,yourself:9,meanshift:[4,14],minimum:[12,4,2],instruct:11,alreadi:[6,14,1,3],done:[12,9,1,14,4],"long":[14,2],blank:[12,4,14],stabl:3,custom:[6,14],open:[6,4,2,11,5],lemnatec:[9,1,14],adaptivetyp:[14,4,2],avail:[3,11],given:[12,1,14,4],width:[14,4,2],top:1,gpg:3,mkdir:[],system:[9,14,3],least:12,feed:[14,2],necessarili:14,demonstr:14,statement:4,similarli:14,termin:3,locat:14,easier:14,store:[14,3],too:2,pare:14,option:[10,4,14],download1:[],tool:[6,3],copi:[14,4,3],bitwise_or:4,gaussianblur:[4,2],specifi:[1,2,5,4,12,14],replic:4,logic3:12,part:[14,4,2],thresh:[1,2,5,4,9,14],submiss:[],essenti:3,rmean:2,crawl:[14,8],than:[1,2,5,4,9,11,12,14],png:[12,9,14,2,5],serv:14,outputpath:1,liter:12,simplist:5,ffmpeg:3,morph:[14,2],provid:[1,2,5,9,11,14],remov:[12,14,4,2],yend:[14,4,2],second:[12,14,4,2,5],structur:[14,9,4,2],"final":[],prependen:[2,5],reus:5,logic6:12,str:[1,4],were:2,posit:[4,2],minut:14,walia:14,outtyp:[14,9,4,2,5],maxarea:4,fluosv_pot1:14,analysi:[],sai:[12,4,3],"33_455640":14,rac:[],viewer:[],gfilter2:14,mind:14,argument:[12,9,14,2,5],"1_023542":14,raw:[12,4,14],"1_023546":14,have:[1,3,5,4,12,2,14],need:[3,14,2],been:[14,9,1,2,4],seem:14,"null":[1,14],border:[4,2],minu:2,pot_filter_1:14,dozen:9,caus:2,bitwis:[10,14,2],date:[1,14],built:4,equival:2,min:[12,14,4,2],check:[14,1,2,4,5],destroi:[4,5],click:3,note:[14,3,4,2,5],also:[9,14,2],high:[],without:[],take:[12,9,14,2],fname:1,environ:[9,14,3],channel:[12,14,4,2,5],even:[3,14,2],begin:[2,11,5],sure:[12,14,3],importantli:14,distribut:[6,9,11],padmaxx:14,normal:[10,14,1,2,4],usernam:3,"52_432942":14,previou:[9,14,5],oracl:3,most:[14,3,4,2,5],attempt:[4,11],plan:1,padmaxi:14,xor:10,htpia:[],segment:[10,4,14],"class":[8,1,4,7,13],focu:12,gray_filtered2:14,greenmedian:4,doi:[],renam:5,compar:[12,1,5],bug:6,dens:12,doc:[14,2],later:[14,2],cover:11,doe:[14,9,4,2,3],appropri:[4,8],valuecolumn:14,yum:3,determin:[4,2,5],add:[3,1,2,4],brew:3,pars:12,xstart:[14,4,2],usual:1,sum:[12,4,14],fact:[4,3],job2:14,shot:14,show:[12,14,4,2,5],text:12,xcode:3,random:4,radiu:4,syntax:12,grid_resourc:14,session:9,threshold:[1,2,5,10,4,9,14],gmean:2,"21_05":14,find:[14,3,1,2,4],paus:2,xml:14,despit:4,onli:[1,3,5,4,12,2,14],exactli:[12,9,14,2,5],ratio:1,acquir:14,datahead:1,strain3:14,"1_023722":14,condor:[14,3],explain:[14,11],tozero:4,behind:[14,3],should:[1,2,5,4,8,3,14],dict:4,analyz:6,factor:1,folder:[14,3],rice:14,rgbtv3:10,rgbtv2:10,rgbtv1:10,info:[],sigmai:4,get:[],beat:[4,2,5],familiar:[9,5],pegasu:[6,13,14,7,3],stop:[4,2],imgnam:[1,14],autom:9,repo:3,next:[2,4,9,12,3,14],cannot:[4,5],sigmax:4,wheezi:3,"import":[2,5,4,9,12,3,14],increas:4,logic4:12,requir:[13,2,7,9,3,14],target:[14,4,2],pymodul:14,bmean:2,organ:14,grayscal:[14,9,4,2],postiv:4,whenev:14,median:[4,2],shootarea:1,grai:[14,9,4,2,5],stuff:[],statist:[],though:[14,2],contain:[1,14,4,5],thresholdtyp:[14,4,2],comma:14,act:[12,2],where:[12,9,4,14],wrote:5,view:[1,2,4],fewer:12,set:[1,3,4,9,11,2,14],job3:14,groupinstal:[],job1:14,"float":[1,4],redmean:4,pot2:14,see:[14,3,4,2,5],result:[1,2,5,4,12,14],transpar:[],close:[14,4,2,5],charact:[12,4,14],contour:[14,4,2],dateutil:3,project:[],statu:14,detect:[4,14],recolor2:14,correctli:[9,1,14],intyp:[14,9,4,2,5],databas:[9,1,14,4],someth:[14,2],imtyp:[1,14],aknecht:14,label:14,"_05":14,state:[12,4],won:2,strain5:14,progress:[6,9],experi:14,approach:4,email:14,direciton:[],whl:3,recolor1:14,kei:[1,3,5,4,2,14],padminx:14,comp:[1,4],filter:[],sole:12,intabl:1,newg:[],popul:[13,7,14],job:[14,9,7,3,13],entir:[12,14,4,2],conda:3,matplotlib:3,solv:[12,4],homebrew:3,sucess:14,come:[14,9,4,3],tophat:4,addit:14,both:[12,9,14,4,2],toward:4,last:[14,5],easi:[12,14,11],hashabl:4,region:[12,14,4,2],alon:6,roiwrit:4,against:4,nogpgcheck:[],etc:3,instanc:4,equat:12,pot_filt:14,logic:[12,14,4,2],bool:[1,4],mani:[3,6,4,11,2,14],com:[6,14,3],ld_library_path:14,ellips:[4,14],fluoresc:14,pose:14,can:[1,2,5,6,4,9,12,3,14],instanti:[],pot:[14,2],address:[],pop:3,walk:8,arbitrarili:12,newr:[],written:[14,4,2],littl:3,padmini:14,respect:12,rpm:3,asdf:[],returnhist:4,becom:[14,3],java:3,semicolon:3,idchar:14,addition:[1,2,5,4,9,11,3,14],invert:[4,2],numpi:[4,3],due:[2,11],defint:14,ttest:1,compon:6,json:[9,4,14],much:[3,2,11],besid:[6,9],interpret:12,interest:[12,2],modif:4,wait:[12,4,2,5],nois:2,redmedian:4,quickli:3,histogram:[14,4,2],unl032:14,tap:3,theorem:[],worker:3,search:[0,14],ani:[6,12,14,4,2],unzip:[],recolor:[14,2],understand:[14,5],togeth:[12,1,14],rang:[5,4,9,11,12,14],standard:[4,2],"case":[9,14,2,5],dash:[14,2,5],multi:11,ident:[12,9,1,2,5],look:[3,5,4,12,2,14],packag:3,vanilla:14,properti:[3,5],harder:4,sourceforg:[],alter:[4,14],cluster:[14,9,4,2],defin:[14,9,4,2,5],"while":[12,14,4,2],displai:[12,4,2,5],invers:4,abov:[12,3,14,2,5],error:[1,4],rgbsv_edg:14,exist:[6,4,14],git:[14,3],anchor:4,imageload:8,dir_nam:14,scipi:[6,3],arg2:4,almost:3,"7script":[],metric:1,non:[14,4,2,5],jpg:3,equal:[12,4,14],strain:14,extractmo:4,itself:[4,14],motiv:14,breez:3,conf:[4,14],outli:4,wherea:[4,2,5],normalizebyintens:4,sever:[2,5,4,9,3,14],scienc:[3,11],bitwise_xor:4,develop:3,webupd8team:3,perform:[1,2,5,6,4,12,14],make:[6,12,14,3,5],format:[1,2,5,8,9,14],intermediari:14,same:[1,3,5,4,12,2,14],pot_filter_2:14,shorter:5,thresh50:5,when:[14,3,4,2,5],html:[],pad:4,ksize:4,featur:[6,4,2],genkei:14,subunit:14,dilat:4,complet:[6,9,14],wheel:3,threshold2:4,http:3,pot1:14,plantcv:[],absorb:12,upon:[4,14],effect:14,hand:9,main_filt:14,feature_detect:[],rais:4,temporari:4,user:[9,14,3],uni:14,nir:14,robust:4,nirtv:14,stack:3,recent:3,lib:3,lower:[2,5],deb7_amd64:3,off:2,center:[4,14],c_2013:14,"45_462980":14,unl:[],thu:[12,14],well:[2,4,9,11,12,3,14],kept:[4,2],versatil:[12,4],col:[],thought:14,likewis:[1,2],contact:6,morphtyp:[14,4,2],rawdata:14,thi:[1,2,5,4,8,9,12,3,14],conflict:3,waia:[],everyth:3,dimension:14,left:[12,4,14],load:[],identifi:[1,14],kheight:[14,2],execut:[2,5,4,9,3,14],less:[12,4,2],entri:14,cento:[],obtain:14,rest:[1,14,5],detail:[2,5,4,9,11,14],shape:2,aspect:9,simpli:[1,3,5,4,12,2,14],comput:[1,2,6,9,11,3,14],accuraci:[4,2],yet:2,languag:2,previous:[4,2,5],"243rd":14,cut:[14,2],directli:[9,14],kernel:[4,2],spatial_radiu:[4,14],lapack:3,mark:14,point:[3,4,2,5],except:[9,1,14,4,5],anova:1,opencv:[6,3,14,4,2],color:[],rgb:[1,14],spread:2,treatment:[1,14],densiti:4,bloo:[],input:[1,2,5,6,4,9,12,14],tell:[2,5],xend:[14,4,2],app:3,match:[9,4,14,5],build:3,bin:[2,5,4,9,12,3,14],inputimag:[],around:2,mayb:[],read:[4,14,11],piec:[12,9,14,2],halt:5,grid:[14,3,11],functino:14,combin:[1,14],press:[4,2,5],height:[14,4,2],recurs:8,you:[1,2,5,4,9,11,12,3,14],licens:3,python2:3,box_roi:14,bitwise_not:[4,2],lost:1,fluo:[1,14],header:[1,3],cdot:[],opencv_lib:14,arbitrari:4,manual:[14,3],background:2,arthur:4,permut:14,necessari:[14,4,3],rgbsv1:10,rgbsv2:10,rgbsv3:10,output:[1,2,5,4,8,9,12,14],resiz:[14,4,2],sv1:[1,14],readi:2,page:[0,4],vassilvitskii:4,draw:4,right:3,bluemedian:4,often:1,deal:[11,5],strain93:14,linux:3,some:[12,3,14,2,11],back:[3,2],percentag:1,pot_roi:14,intern:2,greenmean:4,maxit:4,nirsv:14,ktype:[14,4,2],proper:14,extractcolordata:[4,2],guess:4,constitut:2,titl:[4,2,5],librari:[2,5,6,9,11,14],pandaseq:3,cmake_install_prefix:[],basic:11,scale:[9,4,2,5],implement:[9,4,11],newb:[],fourth:5,assum:[14,3,1,2,4],condens:5,definit:[14,8],canni:4,larg:[12,9,14,4,2],slash:3,condit:[4,2],compil:3,three:[2,5,4,9,12,14],complic:[9,4,11],symbol:[12,2],blocksiz:[14,4,2],maxim:2,who:[12,14],run:[14,9,1,3,4],power:[12,14,2],quit:14,threshold1:4,reach:4,lose:4,usag:11,fluosv:14,broken:[12,9,14],sift:14,unclust:14,hsv:[4,2],nonfre:[],although:[14,2,5],otsu:4,wget:3,bin1:4,"super":[6,9,14,3],between:[1,2,5,4,12,14],fulli:14,simpler:3,comparison:[12,1,4],about:[12,14,2,5],central:4,would:[14,9,4,2],column:[1,14,4],slightli:[9,14,2],surround:[12,4,14],unnecessari:[14,5],bgr:[2,5,4,9,12,14],carrier:2,reconstitute2:14,stand:6,neighbor:4,reconstitute1:14,fals:[13,1,2,7,4,8,12,14],softwar:[6,9,3],other:[12,14,4,3,11],block:[2,5],deviat:4,ppa:3,own:4,treatmentcomp:1,absolut:[4,3],primarili:4,pythonpath:3,basenam:[13,7],lastli:14,rgbsv:14,automat:[14,4,2],two:[1,2,5,4,9,11,3,14],down:[12,9,14,4,2],l2gradient:4,empti:14,thresh100:5,strip:2,wrap:[],hysteresi:4,your:[1,2,5,4,9,12,3,14],genotyp:14,accordingli:[4,5],fast:4,log:1,suffici:2,pictur:9,aren:14,gray_filtered1:14,support:[12,14,4,2],themat:14,question:[6,12],kmean:[10,4],overwrit:[1,8,5],agrement:3,fluosv_edg:14,start:[],singl:[14,5],zxvf:3,arithmet:[12,14],nbsp:[],lot:[12,3,14,1,2],arg1:4,forward:[12,3],panda:3,strictli:14,stai:2,machin:3,individu:[12,9,14,4,2],usr:3,"function":[1,2,5,6,4,9,10,11,12,3,14],head:[],medium:11,form:[12,1,2,4,5],enough:9,tupl:[4,2],glite:14,recommend:[9,14,3,11],keyerror:4,weight:4,gaussian:[10,14,4,2],content:[0,14],windowx:4,link:[0,3],translat:[12,14,5],don:2,eas:14,outputimag:[],"true":[12,14,1,2,4],java8:3,longer:2,count:4,logic1:12,wisc:3,made:14,wise:14,logic5:12,consist:9,reload:4,whether:[1,14,4],wish:3,access:[6,9,14,2,5],smooth:[4,2],maximum:[12,14,4,2],rgbsv_gray2:14,morpholog:[10,14,4,2],below:[1,3,11],ensur:[9,2],rgbsv_gray1:14,which:[1,2,5,4,9,3,14],site:[14,3],otherwis:[12,4,14],problem:14,similar:[4,14],opencvlibrari:[],expect:[12,14,4,3],logfil:1,multipli:4,logerror:1,creat:[13,4,2,5,6,7,9,11,14],"int":4,certain:5,irsv:14,sampl:4,interact:[1,4],doesn:[14,3,4,2],repres:[4,2],rackcdn:3,replica:2,dicitonari:4,file:[1,3,5,4,9,11,12,14],home:9,pip:3,extractdimens:[4,2],meth:2,integr:6,hit:5,again:[12,14,2],password:[],cmake:3,googl:[],know:14,gmed:2,extract:[14,9,1,2],adaptivethreshold:[4,2],percent:14,x86_64_rhel_6:3,"default":[14,1,2,4],finish:4,valid:[13,1,14,7],inclus:[6,14],futur:[14,2,5],rememb:[12,14,2],spatial:4,test:[14,9,1,3,11],threhsold:[1,4],reconstitut:14,sv2:[1,14],imag:[],intermedi:14,irtv:14,correl:1,nonzero:[4,2],stat:1,validonli:[13,7,8],"0th":14,org:[],time:[12,4,14],cmake_build_typ:[],ndarrai:4,morphologyex:4,meaning:14,intens:[2,5,10,4,12,14],track:[14,2],consid:[12,14,4,2],numer:[9,1,14,4],unless:2,debian:3,apertur:4,reduc:2,constant:[4,2],faster:3,algorithm:4,jobhom:[13,7],directori:[13,4,2,7,8,9,3,14],apertures:4,bottom:2,mask:4,rule:[4,2],depth:[],broad:11,far:2,"export":[1,3],profil:[14,3],fluotv:14,scroll:3},objtypes:{"0":"py:method","1":"py:class"},objnames:{"0":["py","method","Python method"],"1":["py","class","Python class"]},filenames:["index","statistics","ex_script_core2","installation","processing","ex_script_core1","introduction","workflowimage","indexing","start","viewer","examples","ex_script_color1","workflowstats","ex_workflow_1"],titles:["Welcome to Image Harvest documentation!","Statistics","Core Processing Example #2","Installation","Image Processing","Core Processing Example #1","Introduction","Image Processing Workflows","Image Loading","Getting Started","Image Processing Viewer","Examples","Color Filter In Depth #1","Statistics Workflows","Workflow Example #1"],objects:{"ih.imgproc.Image":{restore:[4,0,1,""],extractDimensions:[4,0,1,""],show:[4,0,1,""],adaptiveThreshold:[4,0,1,""],kmeans:[4,0,1,""],crop:[4,0,1,""],medianBlur:[4,0,1,""],meanshift:[4,0,1,""],bitwise_or:[4,0,1,""],bitwise_and:[4,0,1,""],morphology:[4,0,1,""],bitwise_xor:[4,0,1,""],extractBins:[4,0,1,""],extractPixels:[4,0,1,""],write:[4,0,1,""],threshold:[4,0,1,""],blur:[4,0,1,""],destroy:[4,0,1,""],save:[4,0,1,""],resizeSelf:[4,0,1,""],gaussianBlur:[4,0,1,""],extractColorData:[4,0,1,""],convertColor:[4,0,1,""],contourCut:[4,0,1,""],edges:[4,0,1,""],extractFinalPath:[4,0,1,""],resize:[4,0,1,""],wait:[4,0,1,""],bitwise_not:[4,0,1,""],normalizeByIntensity:[4,0,1,""],list:[4,0,1,""],colorFilter:[4,0,1,""],extractMoments:[4,0,1,""]},"ih.workflow":{ImageProcessor:[7,1,1,""],Statistics:[13,1,1,""],ImageLoader:[8,1,1,""]},"ih.workflow.ImageProcessor":{create:[7,0,1,""]},"ih.workflow.ImageLoader":{write:[8,0,1,""],crawl:[8,0,1,""]},"ih.workflow.Statistics":{create:[13,0,1,""]},"ih.statistics":{Stats:[1,1,1,""]},"ih.imgproc":{Image:[4,1,1,""]},"ih.statistics.Stats":{normalize:[1,0,1,""],treatmentComp:[1,0,1,""],anova:[1,0,1,""],shootArea:[1,0,1,""],"export":[1,0,1,""],correlation:[1,0,1,""],threshold:[1,0,1,""],tTest:[1,0,1,""],logErrors:[1,0,1,""]}},titleterms:{load:[14,8],osx:3,process:[4,2,5,10,7,11,14],anaconda:3,templat:14,high:[],cento:3,tabl:0,instal:3,depend:3,welcom:0,script:[12,2,11,5],configur:14,start:9,window:3,exampl:[14,2,11,5],submiss:14,get:9,document:0,"final":14,analysi:[],core:[2,11,5],plant:[],workflow:[13,7,14,11],python:[12,2,5],imag:[0,4,10,7,8,14],viewer:10,indic:0,ubuntu:3,line:[12,2,5],htpia:[],harvest:0,color:[12,11],introduct:6,name:[],mac:3,filter:[12,11],depth:12,without:[],command:[12,2,5],statist:[13,1],throughput:[]}})
\ No newline at end of file
+Search.setIndex({envversion:42,terms:{four:1,secondli:15,prefix:[4,3],"0_0":15,whose:[12,4,14],accur:[4,2],fitler:2,deviat:4,under:[2,5,4,12,15,14],everi:[15,14],outtabl:1,appar:15,"09c8d0b2229f813c1b93":3,cmd:14,red:[12,4,15,14,5],apertur:4,x86_64:3,seper:[2,5],direct:[1,2,4],outputpath:1,second:[2,5,4,12,15,14],aggreg:1,panda:3,even:[3,15,2],hide:2,convertcolor:[9,4,2,14,5],bmed:2,fluosv1:10,fluosv2:10,blur:[],mintu:15,"new":[13,4,3,5,7,14],net:[],metadata:[9,15],never:14,here:[3,5,4,12,2,14,15,16],path:[3,5,4,12,2,14,15,16],ttest:1,interpret:[12,14],credit:14,functino:15,unix:[],total:[15,1,2,4,14],highli:[3,11],extrapol:4,would:[15,9,4,2],noarch:[],call:[1,3,5,4,12,2,14],recommend:[9,15,3,11],type:[1,2,5,4,15,14],until:[15,4,3,14,5],notif:15,hurt:2,hold:12,must:[1,2,4,9,12,15,14],rawfil:15,join:12,restor:[12,4,2,14,5],setup:[15,3,16,2,5],work:[1,3,6,9,11,14,15,16],root:14,give:[4,2,14],c95ac804525aac4b6dba79b00b39d1d3:3,liter:12,want:[1,2,5,4,12,15,14],"09_10":15,end:[15,1,2,4,5],how:[2,5,4,9,11,15],confin:[],env:[15,16],yum:3,config:[9,15],updat:[1,3,14],outsid:[4,2],after:[1,3,5,12,2,16],lab:[4,2],befor:[1,2,4,9,11,12,3,15,14],demonstr:15,rhel6:3,attempt:[4,11],third:14,reconstiut:15,exclud:[12,2],maintain:[4,2],environ:[9,15,3,16],enter:[15,16],exclus:4,order:[2,4,8,9,12,15],ricephenom:[],origin:[4,2,14],wut:[],over:[4,2],becaus:[15,9,4,2,5],workflow1:[],returnlist:4,fit:14,better:[1,11],mediapytn:4,easier:[15,14],them:[1,2,5,4,9,3,15],thei:[3,4,11,12,15,16],colorfilt:[12,4,2,14],"break":[15,4,2,14],choic:15,each:[1,2,5,4,9,11,12,3,15,14],debug:15,side:[1,15,4],mean:[2,5,10,4,9,12,15,14],resum:5,extract:[],pegasus_hom:[15,16],gradient:4,morpholog:[10,15,4,2],adapt:[2,6,4,10,15,14],knearest:4,got:14,lib64:3,bordertyp:4,linear:5,navig:[14,16],free:3,standard:[4,2],r79:3,returnbound:[4,15],angl:14,filter:[],isi:[15,3],isn:[9,4,15],use_mirror:[],rang:[5,4,9,11,12,15,14],sobel:4,independ:4,instruct:[11,14],alreadi:[6,15,1,3,14],top:[1,15,4],sometim:3,too:[4,2,14],similarli:[15,14],tool:[6,4,3,14],crawl:[15,8],target:[15,4,2],provid:[1,2,5,4,9,11,14,15,16],intyp:[15,9,4,2,5],project:15,minut:[],rac:[],mind:15,spectrum:[15,1,2,5],"1_023542":15,raw:[12,4,15],"1_023546":15,seem:15,minu:[2,14],dozen:9,ktype:[15,4,2],fname:1,blue:[2,5,4,12,15,14],though:[15,2],usernam:[3,14],object:[9,2,5],doi:[],don:[15,2],doc:[15,2],doe:[2,4,9,3,15,14],bracket:14,sum:[12,4,15],job2:15,box_roi:15,random:[4,14],radiu:4,syntax:12,involv:15,despit:4,submit:[13,3,6,7,15,16],acquir:15,"1_023722":15,explain:[15,11],folder:[15,14,3,16],rice:[15,14],label1:4,label2:4,likewis:[1,2],stop:[4,2],foremost:14,bar:14,"public":16,reload:4,groupinstal:[],cvmfs_oasis_opensciencegrid_org_revis:[],result:[1,2,5,4,12,15,14],databas:[9,1,15,4],aknecht:15,awai:14,approach:4,recolor1:15,recolor2:15,newb:[],newg:[],newr:[],hashabl:4,howev:[12,4,15,11,14],roiwrit:4,against:4,logic:[12,15,4,2,14],uni:15,com:[6,15,3,16],ld_library_path:[15,16],height:[15,4,2,14],permut:15,assum:[15,3,1,2,4],fortran:3,numpi:[4,3],three:[2,5,4,9,12,15],been:[15,9,1,2,4],much:[3,4,2,11,14],interest:[12,4,2],basic:[11,14],evalut:14,rgbsv_gray2:15,rgbsv_gray1:15,quickli:3,unl032:15,worker:3,argument:[2,5,4,9,12,15,14],jobhom:[13,7],ident:[12,9,1,2,5],properti:[3,5],sourceforg:[],calcul:[15,1,2,4],anchor:4,imgproc:[2,5,4,9,12,15,14],genkei:15,extractmo:4,conf:[4,15],sever:[2,5,4,9,3,15,14],incorrectli:14,perform:[1,2,5,6,4,12,15,14],make:[3,5,6,4,12,15,14],transpar:[],complex:[4,15,11,14],split:15,complet:[6,9,15,14],wheel:3,hand:9,fairli:[15,4,2,14],rais:4,nir:15,gaussianblur:[4,2],kept:[4,2,14],thu:[12,15,14],contact:6,thi:[1,2,5,4,8,9,12,3,14,15,16],everyth:[3,14],left:[12,4,15],identifi:[1,15],kheight:[15,2],just:[15,4,2,14,5],yet:2,languag:[2,14],previous:[4,2,5],easi:[12,15,11],opencv:[6,3,15,4,2],spread:2,save:[2,5,4,12,15,14],gave:16,applic:14,mayb:[],background:[4,2],ineffici:15,specif:[13,1,3,7,5,4,9,11,12,15,16],arbitrari:[4,14],manual:[15,3],unnecessari:[15,5],right:[4,3,14],deal:[11,5],maxim:2,percentag:1,intern:2,maxit:4,nirsv:15,successfulli:16,txt:14,bottom:[15,4,2],canni:4,condit:[4,2],plu:14,convexhul:14,pose:15,sift:15,hsv:[4,2],repositori:3,"super":[6,9,15,3],slightli:[9,15,2],surround:[12,4,15,14],nonfre:[],produc:14,zxvf:3,ppa:3,usersusernam:[],treatmentcomp:1,basenam:[13,7],"float":[1,4],down:[2,4,9,12,15,14],wrap:[],genotyp:15,accordingli:[4,14,5],represnt:4,suffici:2,support:[12,15,4,2],bmean:2,"class":[8,1,4,7,13],avail:[3,11,14],width:[15,4,2,14],direciton:[],head:14,medium:11,form:[1,2,5,4,12,14],authorized_kei:16,greenmedian:4,"true":[1,2,4,12,15,14],java8:3,autoclass:[],maximum:[12,15,4,2,14],"0_0_2":14,thresh75:5,featur:[6,4,2,14],logerror:1,semicolon:3,irsv:15,exist:[6,4,15],check:[15,1,2,4,5],cummul:15,when:[3,5,4,2,14,15,16],piplin:14,test:[1,3,9,11,15,14],threhsold:[1,4,14],relat:[12,15,5],intens:[2,5,10,4,12,15,14],consid:[12,15,4,2],faster:3,ignor:4,time:[12,4,15,14],roi:[15,4,2,14],imageload:8,concept:[14,5],chain:[9,15],skip:4,has_file_usr_lib64_libstdc___so_6:[],focus:[12,2],osg:[],row:15,hierarch:14,depend:[],extractpixel:[4,2,14],readabl:4,sourc:[13,1,3,7,6,4,8,9],string:[12,15,4,2],unfamiliar:[11,14],enviorn:3,word:[15,2,5],imageprocessor:7,exact:[12,4,2,5],level:15,did:1,iter:4,team:[14,16],div:[],round:14,dir:[15,14],sign:15,uniform:14,current:[13,1,2,7,5,4,15,14],paragraph:14,tusker:15,deriv:[],gener:[1,3,6,4,9,15,16],satisfi:4,modif:[4,16],address:15,along:15,resizeself:4,wait:[12,4,2,14,5],box:[15,4,3],shift:[10,4,15,14,5],throughput:[],extra:[],modul:[15,0,4,2,5],bitwise_and:[4,2,14],"1st":15,instal:[],installdir:[15,16],univers:[15,16],perl:3,criteria:4,black:[12,4,14],awesome_project:15,oop:5,effort:4,easiest:[],fly:14,prepar:2,focu:12,unused_1:15,cat:16,can:[1,2,5,6,4,9,12,3,15,14],purpos:[15,4,2,5],input2:2,nearest:4,input1:2,topic:[],plantcv:[],pegasus_4:3,occur:[12,15,16],kwidth:[15,2],alwai:[4,15,14],multipl:[12,1,15,4,5],write:[1,2,5,4,8,9,12,15,14],fourth:5,overali:14,rmean:2,map:15,rgbtv:15,max:[12,15,4,2,14],clone:[],mac:[],mai:[15,3,4,2,14],underscor:15,data:[1,2,4,8,9,11,14,15,16],stress:[1,15],noun:5,inform:[13,1,2,7,4,9,14,15,16],combin:[1,15,14],talk:[12,15,4,2,5],nbsp:[],still:[9,15,2],conjunct:4,group:[1,15,16,14,5],monitor:15,returnhist:4,window:[],main:[12,9],non:[15,4,2,14,5],outli:4,halt:5,threshold1:4,threshold2:4,initi:[4,15,5],half:4,now:[3,15,2,14,5],introduct:[],term:11,name:[],revers:2,separ:[3,5,12,2,15,14],rock:14,compil:3,keycolumn:15,arg1:4,individu:[2,4,9,12,15,14],continu:[12,4,2,14],contrib:3,operand:2,happen:[2,14],accomplish:[15,5],space:[4,15],idnum:15,profil:[15,3,16],hcc:[],bla:3,correct:[15,3],hull:4,whera:4,git:[15,3],org:[],care:15,wai:[1,5,4,9,11,12,15,14],thing:15,place:[1,15],first:[],oper:[12,4,2,14],osgvo_os_str:[],directli:[9,4,15],onc:[15,14,2,5],arrai:4,yourself:9,extractminenclosingcircl:4,fast:[4,15,14],open:[2,5,6,4,11,14],size:[15,9,4,2,14],adaptivetyp:[15,4,2],given:[12,1,15,4],convent:15,necessarili:15,breez:3,circl:[4,14],white:14,walia:[15,16],copi:[15,4,3],specifi:[1,2,5,4,12,15,14],enclos:4,mostli:4,than:[1,2,5,4,9,11,12,15,14],png:[2,5,4,9,12,15,14],serv:15,were:2,posit:[4,2,14],tophat:4,analysi:[],sai:[12,4,3],"33_455640":15,ani:[2,6,4,12,15,14],perciev:14,dash:[15,2,5],bitwis:[10,15,2],destroi:[4,14,5],note:[15,3,4,2,5],take:[2,4,9,12,15,14],interior:14,green:[2,5,4,12,15,14],channel:[2,5,4,12,15,14],begin:[4,2,11,14,5],sure:[12,15,4,3],importantli:15,padmaxx:15,normal:[10,15,1,2,4],multipli:4,padmaxi:15,pair:16,renam:5,later:[15,2],shot:15,show:[2,5,4,12,15,14],bright:[2,14],threshold:[1,2,5,10,4,9,15,14],"21_05":15,xml:15,onli:[1,3,5,4,12,2,14,15,16],ratio:1,datahead:1,strain3:15,tozero:4,written:[15,4,2,14],dict:4,analyz:6,aknecht2:[],get:[],pegasu:[13,3,6,7,15,16],clang:14,repo:3,cannot:[4,5],ssh:16,wheezi:3,requir:[13,4,2,7,9,3,14,15,16],median:[4,2],webupd8team:3,thresholdtyp:[15,4,2],where:[12,9,4,15,14],kernel:[4,2,14],job3:15,old_script:15,job1:15,"0_0_0":[],detect:[4,15],label:[4,15],behind:[15,3],between:[1,2,5,4,12,15,14],"import":[2,5,4,9,12,3,15,14],parent:14,comp:[1,4],screen:14,intabl:1,come:[15,9,4,3],region:[12,15,4,2,14],nogpgcheck:[],tutori:[9,15,3,11],mani:[3,6,4,11,2,15],color:[],pot:[15,4,2,14],pop:[3,14],coupl:15,invert:[4,2,14],invers:4,mark:15,workshop:[],recolor:[],those:[15,11,14],"case":[9,15,2,14,5],keygen:16,rgbsv_edg:15,advantag:15,download1:[],metric:1,strain:15,scipi:[6,3],develop:3,intermediari:15,same:[1,3,5,4,12,2,14,15,16],binari:[15,4,2,14],html:[],pad:4,subunit:15,finish:[4,15,11,14,16],feature_detect:[],nirtv:15,appropri:[15,4,8],without:[],dimension:15,execut:[2,5,4,9,3,15,14],key_nam:16,rest:[1,15,5],aspect:9,lapack:3,pymeanshift:[4,3],except:[9,1,15,4,5],littl:3,treatment:[1,15],bloo:[],xend:[15,4,2,14],around:[4,2],read:[4,15,11,14],grid:[15,3,11],amp:[],strain93:15,rpmfusion:[],cdot:[],integ:14,either:[1,15,4,14],output:[1,2,5,4,8,9,12,15,14],sv1:[1,15],manag:[15,3],vassilvitskii:4,pot_roi:15,constitut:2,cmake_install_prefix:[],easili:14,definit:[15,14,8,16],complic:[9,4,11],blocksiz:[15,4,2],power:[12,2,14],broken:[12,9,15],fulli:15,comparison:[12,1,4],central:4,greatli:[9,2,14],stand:[6,14],neighbor:4,act:[12,2],lastli:15,morphtyp:[15,4,2],thresh100:5,strip:2,your:[1,2,5,4,9,12,3,14,15,16],log:1,area:[15,4,2,14],aren:[15,14],overwrit:[1,8,5],agrement:3,strict:15,lot:[1,3,12,2,15,14],submiss:[],strictli:15,enough:9,tupl:[4,2],longer:2,logic0:12,logic1:12,logic2:12,logic3:12,logic4:12,logic5:12,logic6:12,possibl:15,"default":[15,1,2,4,14],expect:[12,15,4,3],creat:[13,4,2,5,6,7,9,11,14,15,16],certain:[4,5],deep:15,file:[1,3,5,4,9,11,12,14,15,16],fill:4,rect:[4,2],again:[12,15,2,14],googl:[],adaptivethreshold:[4,2],event:11,valid:[13,1,15,7],spatial:4,you:[1,2,5,4,9,11,12,3,14,15,16],pandaseq:3,"0th":15,symbol:[12,2],track:[15,4,2],reduc:[2,14],directori:[13,4,2,7,8,9,3,15,14],mask:[4,14],hello:14,mimim:14,all:[13,1,2,7,5,4,8,9,12,3,15,14],dist:16,osx:[],alg:14,correl:1,abil:[6,14],follow:[2,5,4,9,12,3,14,15,16],basemin:[15,4,2,14],children:14,content:[0,15,16],program:[4,2,5],introduc:5,filtrat:2,straightforward:15,dateformat:1,fals:[13,1,2,7,4,8,12,15],util:[4,14],verb:5,fall:[1,11,4],veri:[2,4,11,12,15,14],list:[1,3,4,2,15,14],adjust:[2,4,9,3,14,15,16],small:[15,2,14],extractcolorchannel:4,dimens:15,pase:5,difficulti:11,zero:[2,14],design:15,pass:[4,15,16,5],further:[9,15],medianblur:4,bluemean:4,what:[2,5,9,12,15,14],xor:10,sub:[15,14],section:[2,5,9,14,15,16],abl:14,version:[14,3,16],method:[9,4,2,14,5],full:[4,15,16],themselv:[12,9,1,15],variat:[1,14],modular:6,shouldn:15,parenthesi:[12,4,2],valu:[1,2,5,4,12,15,14],search:[0,15,14],amount:[4,14],writenam:4,action:5,magnitud:4,intermedi:15,filenam:1,ystart:[15,4,2,14],select:12,distinct:[6,14],two:[1,2,5,4,9,11,3,14,15,16],rhel:[],taken:[9,14],statitist:15,more:[15,3,4,2,14],flag:4,particular:[12,4,15,11],none:[15,1,4,7],cluster:[15,9,4,2,16],outlin:14,dev:4,remain:2,nebraska:15,learn:11,deb:3,prompt:[14,3,16],share:[15,16],minimum:[12,4,2,14],explor:[],divid:[4,15],rather:9,anoth:3,comfort:15,extractbin:4,csv:[15,1,8],simpl:[9,4,2],plant:[],resourc:[15,4,3],reflect:4,imtyp:[1,15],varianc:2,circumst:4,github:0,stash:[],wantsstashcach:16,caus:2,shade:14,help:[2,6,4,9,15,14],erod:[4,2],i386:[],paper:[],through:[3,4,8,11,15,14],rgbtv_edg:15,paramet:[1,4,14],style:[1,15,4,16],pcv:[],might:14,alter:[4,15],good:[9,2],"return":[12,15,4,2,14],timestamp:[13,7,15],gfilter2:15,micro:9,achiev:14,found:9,truncat:4,weight:4,hard:[15,5],procedur:4,realli:[15,14],connect:[4,2,14],orient:5,reconstitut:15,research:3,range_radiu:[4,15],print:[2,14],foreground:4,advanc:3,guess:4,pub:16,reason:5,base:[13,1,2,7,5,4,8,9,12,15,14],put:3,rmed:[1,2],bash:[12,9,2,3,5],basi:14,thrown:4,launch:15,min_dens:[4,15],clump:[],assign:[15,4,2],feed:[15,2],major:[9,15,2,5],notifi:[15,16],number:[12,15,4,2,14],gfilter1:15,placehold:[15,2],done:[1,4,9,12,15,14],construct:4,blank:[12,4,15,16],stabl:3,miss:14,stage:16,lemnatec:[9,1,15,14],differ:[1,2,5,6,4,9,11,12,14,15,16],projectnam:16,interact:[1,4],gpg:3,least:[12,14],extractconvexhul:[4,14],statement:4,store:[15,3],pare:15,option:[10,4,15],part:[15,4,2,14],pars:[12,15],simplist:5,ffmpeg:3,whenev:15,remov:[12,15,4,2,14],horizont:15,reus:5,str:[1,4],toward:4,outtyp:[15,9,4,2,5],maxarea:4,comput:[1,2,6,9,11,3,15,14],packag:[15,3,16],"null":[1,15],built:4,equival:2,click:3,also:[15,9,4,2],build:3,pipelin:14,extractcolordata:[4,2],distribut:[6,9,11,16],pot_filt:15,previou:[5,4,9,14,15,16],reach:4,most:[3,5,4,2,14,15,16],plan:1,htpia:[],gray_filtered1:15,gray_filtered2:15,maxwalltim:[15,16],windowx:4,cover:[11,14],clean:2,xstart:[15,4,2,14],latest:[15,3],xcode:3,session:9,particularli:4,gmean:2,find:[1,3,4,2,15,14],giant:3,copyright:14,condor:[15,3,16],factor:1,darwin:14,rgbtv3:10,rgbtv2:10,rgbtv1:10,sigmai:4,express:1,nativ:14,sigmax:4,statist:[],wrote:5,set:[1,3,4,9,11,2,15,16],sep:14,see:[3,5,4,2,15,14],close:[15,4,2,14,5],contour:[],dateutil:3,someth:[15,4,2,14],won:[2,14],experi:15,waia:[],numer:[9,1,15,4],sole:12,conda:3,solv:[12,4,14],padmini:15,rackcdn:3,popul:[13,7,15],both:[12,9,4,2,14],last:[15,5],alon:6,spatial_radiu:[4,15],whole:[4,15],load:[],simpli:[1,3,5,4,12,2,15,14],point:[15,3,4,2,5],instanti:4,arbitrarili:12,header:[1,3],linux:[3,14],averag:2,asdf:[],unclust:[],java:3,due:[2,11],empti:15,redmedian:4,imag:[],understand:[15,5],look:[3,5,4,12,2,15,14],batch:[],"while":[2,4,12,16,15,14],abov:[3,5,12,2,14,15,16],error:[1,15,4],localinstal:[],readi:2,"7script":[],jpg:3,itself:[4,15,14],cento:[],normalizebyintens:4,shorter:5,thresh50:5,ksize:4,sqlite3:15,conflict:3,wherea:[4,2,5],moment:[4,15],temporari:4,user:[9,15,3,14],robust:4,stack:3,recent:3,knn:4,lower:[2,5],lib:[15,3,16],"45_462980":15,entri:15,shape:2,glite:[15,16],cut:[],anova:1,rgb:[1,15],theorem:[],input:[1,2,5,6,4,9,12,15,14],tell:[2,5],finder:[],bin:[2,5,4,9,12,3,15,16],format:[1,2,5,4,8,9,15],bitwise_not:[4,2,14],fluo:[1,15],arthur:4,often:1,some:[3,4,11,12,2,14,15,16],back:[3,2,14],greenmean:4,sampl:4,scale:[9,4,2,5],per:14,larg:[2,4,9,12,15,14],slash:3,machin:3,run:[1,3,4,9,14,15,16],lose:4,step:[2,5,4,9,11,15,14],wget:3,subtract:[4,2],bgr:[2,5,4,9,12,15,14],reconstitute2:15,reconstitute1:15,block:[2,5],cutoff:5,primarili:4,pythonpath:[15,3,16],within:[9,4,15,14],usersusernamedownlaodsfil:[],ensur:[9,2],inclus:6,question:[6,12,14],kmean:[10,4],"long":[15,2],custom:6,arithmet:[12,4,15],includ:[15,3,4,2,11],forward:[12,3],pwd:14,link:[0,3],translat:[12,15,5],outputimag:[],info:[4,14],consist:9,similar:[4,15,14],constant:[4,2],fluotv:15,doesn:[15,3,4,2,14],repres:[4,2,14],dicitonari:4,cmake:3,titl:[4,2,5],sv2:[1,15],irtv:15,nonzero:[4,2],draw:4,llvm:14,meaning:[4,15],algorithm:4,depth:[],far:[2,14],scroll:3,code:[14,15,5],edg:[10,15,4,2,14],binlist:4,ellips:[4,15],edu:[15,3],compact:4,cython:3,privat:16,pydata:[],send:[],htcondor:3,datafil:1,unzip:[],gtk2:3,logiclist:12,volum:[],relev:[1,15],notabl:5,geograph:14,fewer:12,"try":14,refer:[4,2],pleas:6,impli:2,smaller:[12,14],natur:[11,14],crop:[10,15,4,2,14],unused_2:15,jump:[9,11],fluosv_pot1:15,fluosv_pot2:15,download:[3,5,11,12,2,14],odd:[4,14],outputdir:[9,4,2],append:16,compat:14,index:[0,15],compar:[12,1,14,5],access:[6,9,15,2,5],absolut:[4,3,14],matplotlib:3,your_valu:4,let:[2,5,4,12,15,14],ubuntu:[],becom:[15,3,14],sinc:[12,15,14],cf1:3,convert:[1,2,5,10,4,9,12,15,14],pretti:2,dilat:4,larger:[12,2,14],main_filt:15,chang:[15,16,2,14,5],appli:[12,4,15,14],app:[3,14],apt:3,"05_05":15,fed:2,from:[1,2,5,4,8,9,12,3,14,15,16],zip:3,upgrad:3,next:[2,4,9,12,3,14,15,16],few:[9,4,15,14,16],usr:[15,3,16],simpler:3,sort:15,train:4,starter:9,meet:2,control:[15,1,3,14],tap:3,tar:[3,16],sdist:16,sudo:3,high:[],rgbsv:15,tab:3,tarbal:16,hit:[16,5],kurtknecht:[6,15,16],gcc:14,instead:[1,2,5,4,15,14],sucess:15,bin2:4,blackhat:4,essenti:3,contourcut:[4,2,14],correspond:[1,15,4,14],ycrcb:[4,2],binx:1,allow:[4,15,14],move:[3,14],comma:15,libav:3,chosen:4,pixel:[1,2,5,4,12,15,14],greater:[12,4,2,14,5],handl:[9,4,8],auto:4,devel:[],dax:15,edit:3,bin1:4,mode:[4,15],subset:15,chunk:15,meta:[15,8],our:[2,5,4,12,14,15,16],meth:[4,2],shootarea:1,extractfinalpath:4,special:[12,4,15],out:[9,15,2,3,14],variabl:[15,9,4,3],matrix:4,dbid:4,categori:[12,11],rel:[4,14],math:[],common:[15,3,16],insid:[15,14],workflow:[],standalon:14,dictionari:4,releas:3,afterward:15,could:15,keep:[2,5,4,9,12,3,15,14],counterpart:[15,14],s_2013:15,softwar:[6,9,3,16],echo:3,meanshift:[],date:[1,15],fluoresc:15,padminx:15,start:[],licens:[3,14],mkdir:[],system:[9,15,3,14],wrapper:[4,2],termin:[3,14],"final":[],rsa:16,thresh:[1,2,5,4,9,15],exactli:[2,5,4,9,12,15,14],holland:15,morph:[15,2],l2gradient:4,yend:[15,4,2,14],pot2:15,pot1:15,charact:[12,4,15],prependen:[2,5],viewer:[],have:[1,3,5,4,12,2,14,15,16],need:[3,15,2,14,16],border:[4,2],pot_filter_2:15,pot_filter_1:15,min:[12,15,4,2,14],accuraci:[4,2],which:[1,2,5,4,9,3,14,15,16],singl:[4,15,14,5],unless:[2,14],whl:3,who:[12,15],oracl:3,histogram:[15,4,2],segment:[10,4,15,14],why:14,dens:12,request:15,valuecolumn:15,determin:[4,2,5],brew:3,fact:[4,3],text:12,filetyp:15,grid_resourc:[15,16],locat:[15,14],nois:[2,14],should:[1,2,5,4,8,3,14,15,16],local:[9,3,11,14],beat:[4,2,5],familiar:[9,14,5],imgnam:[1,15],autom:9,increas:4,organ:15,grayscal:[15,9,4,2,14],postiv:4,grai:[2,5,4,9,15,14],stuff:[],integr:6,contain:[14,1,15,4,5],view:[1,2,4],redmean:4,knowledg:14,imread:4,statu:15,"243rd":15,correctli:[9,1,15,14],pattern:14,"_05":15,state:[12,4,14],strain5:15,progress:[6,9],email:[15,16],kei:[1,3,5,4,2,14,15,16],job:[15,9,7,3,13],entir:[12,15,4,2],homebrew:3,addit:[4,15],rtype:[],equal:[12,4,15],etc:3,instanc:4,equat:12,wall:15,walk:8,bitwise_or:4,respect:[12,4],rpm:3,quit:15,addition:[1,2,5,4,9,11,3,15,14],cv2:4,defint:[],compon:6,json:[9,4,15],besid:[6,9],morphologyex:4,togeth:[12,1,15],replic:4,multi:11,vanilla:[15,16],harder:4,defin:[2,5,4,9,15,14],dir_nam:[],almost:[3,14],site:[15,3,16],motiv:15,avi:[6,15,16],scienc:[3,11],bitwise_xor:4,cross:4,member:[],largest:14,difficult:14,http:[15,3],structur:[15,9,4,2,14],absorb:12,upon:[4,15],effect:[4,15,14],logfil:1,php:15,deb7_amd64:3,off:2,center:[4,15],c_2013:15,unl:[],well:[2,4,9,11,12,3,14,15,16],versatil:[12,4],col:[],thought:15,rawdata:15,usual:1,distanc:14,paus:2,less:[12,4,2,14],obtain:15,x86_64_rhel_6:3,opencv_lib:[15,16],idchar:15,add:[3,1,2,4],densiti:4,match:[5,4,9,14,15,16],inputimag:[],piec:[12,9,15,2,14],know:14,press:[4,2,14,5],password:16,recurs:8,python2:[15,3,16],like:[3,5,4,2,15,14],lost:1,necessari:[15,4,3,16],rgbsv1:[10,14],rgbsv2:10,rgbsv3:10,otsu:4,resiz:[15,4,2,14],page:[0,4,14],bluemedian:4,"export":[1,3],convex:4,proper:15,home:[9,14],conver:4,librari:[2,5,6,9,11,14,15,16],broad:11,condens:5,blurri:14,leav:[15,3,16],overlai:14,usag:11,fluosv:15,although:[15,2,5],panel:3,about:[12,15,4,2,5],actual:[1,2,5,4,12,15],column:[1,15,4],carrier:2,box_filt:15,own:4,automat:[15,4,2],hysteresi:4,pictur:9,transfer:16,themat:15,fluosv_edg:15,appl:14,arg2:4,pymodul:[15,16],"function":[1,2,5,6,4,9,10,11,12,3,15,14],"52_432942":15,keyerror:4,gaussian:[10,15,4,2],eas:15,bug:6,count:4,wisc:3,made:[15,14],wise:15,whether:[1,15,4],wish:3,smooth:[4,2],displai:[12,4,2,14,5],below:[1,3,11,4],otherwis:[12,4,15],problem:15,opencvlibrari:[],evalu:14,"int":4,replica:2,implement:[9,4,11],pip:3,extractdimens:[4,2],gmed:2,percent:15,detail:[2,5,4,9,11,15,16],other:[3,4,11,12,15,14],bool:[1,4],futur:[15,2,5],rememb:[12,15,2],downlaod:14,predominant:14,stat:[1,15,16],validonli:[13,7,8],cmake_build_typ:[],ndarrai:4,debian:3,stai:2,apertures:4,rule:[4,2]},objtypes:{"0":"py:method","1":"py:class"},objnames:{"0":["py","method","Python method"],"1":["py","class","Python class"]},filenames:["index","statistics","ex_script_core2","installation","processing","ex_script_core1","introduction","workflowimage","indexing","start","viewer","examples","ex_script_color1","workflowstats","arkansas_workshop_july_2015","ex_workflow_1","ex_workflow_2"],titles:["Welcome to Image Harvest documentation!","Statistics","Core Processing Example #2","Installation","Image Processing","Core Processing Example #1","Introduction","Image Processing Workflows","Image Loading","Getting Started","Image Processing Viewer","Examples","Color Filter In Depth #1","Statistics Workflows","Arkansas Workshop July 2015","Workflow Example #1","OSG Workflows"],objects:{"ih.imgproc.Image":{restore:[4,0,1,""],extractDimensions:[4,0,1,""],show:[4,0,1,""],mask:[4,0,1,""],adaptiveThreshold:[4,0,1,""],kmeans:[4,0,1,""],crop:[4,0,1,""],medianBlur:[4,0,1,""],meanshift:[4,0,1,""],bitwise_or:[4,0,1,""],bitwise_and:[4,0,1,""],morphology:[4,0,1,""],extractConvexHull:[4,0,1,""],bitwise_xor:[4,0,1,""],extractBins:[4,0,1,""],extractPixels:[4,0,1,""],write:[4,0,1,""],threshold:[4,0,1,""],blur:[4,0,1,""],destroy:[4,0,1,""],save:[4,0,1,""],resizeSelf:[4,0,1,""],knn:[4,0,1,""],gaussianBlur:[4,0,1,""],extractColorData:[4,0,1,""],convertColor:[4,0,1,""],contourCut:[4,0,1,""],edges:[4,0,1,""],extractFinalPath:[4,0,1,""],resize:[4,0,1,""],wait:[4,0,1,""],extractColorChannels:[4,0,1,""],bitwise_not:[4,0,1,""],normalizeByIntensity:[4,0,1,""],list:[4,0,1,""],colorFilter:[4,0,1,""],extractMoments:[4,0,1,""],extractMinEnclosingCircle:[4,0,1,""]},"ih.workflow":{ImageProcessor:[7,1,1,""],Statistics:[13,1,1,""],ImageLoader:[8,1,1,""]},"ih.workflow.ImageProcessor":{create:[7,0,1,""]},"ih.workflow.ImageLoader":{write:[8,0,1,""],crawl:[8,0,1,""]},"ih.workflow.Statistics":{create:[13,0,1,""]},"ih.statistics":{Stats:[1,1,1,""]},"ih.imgproc":{Image:[4,1,1,""]},"ih.statistics.Stats":{normalize:[1,0,1,""],treatmentComp:[1,0,1,""],anova:[1,0,1,""],shootArea:[1,0,1,""],"export":[1,0,1,""],correlation:[1,0,1,""],threshold:[1,0,1,""],tTest:[1,0,1,""],logErrors:[1,0,1,""]}},titleterms:{load:[15,8,14],osx:3,arkansa:14,extra:14,process:[4,2,5,10,7,11,15],anaconda:3,templat:[15,16],high:[],cento:3,tabl:0,instal:3,extract:14,contour:14,osg:16,cours:14,depend:3,welcom:0,script:[12,14,2,11,5],harvest:0,configur:[15,16],workflow:[13,7,15,11,16],start:9,window:[3,14],workshop:[11,14],blur:14,submiss:15,document:0,"final":[15,16],analysi:[],core:[2,11,5],plant:[],crash:14,get:9,python:[12,14,2,5],juli:14,dai:14,cut:14,viewer:10,recolor:14,indic:0,ubuntu:3,line:[12,14,2,5],htpia:[],imag:[0,4,10,7,8,15,14],color:[12,11,14],introduct:6,meanshift:14,name:[],mac:[3,14],exampl:[15,2,11,5],filter:[12,11,14],depth:12,without:[],command:[12,14,2,5],statist:[13,1],throughput:[],first:14}})
\ No newline at end of file
diff --git a/docs/build/html/start.html b/docs/build/html/start.html
index b5f5cbdd4252e3b549d30e373e2d5cc8836c8165..7316c1b68ed370b038acb7efede52791a5adb711 100644
--- a/docs/build/html/start.html
+++ b/docs/build/html/start.html
@@ -75,6 +75,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/statistics.html b/docs/build/html/statistics.html
index 360717852c0dea25f3ba237997210f6e0014fc1d..088a0e1c199c5ce3d33bc8a29226d9bf92715331 100644
--- a/docs/build/html/statistics.html
+++ b/docs/build/html/statistics.html
@@ -75,6 +75,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/viewer.html b/docs/build/html/viewer.html
index cb601ce549de2eedcf3e92d6296998aee4549b34..d7823f2a908fe51268d6a9bd5a59949d0175f42a 100644
--- a/docs/build/html/viewer.html
+++ b/docs/build/html/viewer.html
@@ -75,6 +75,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1 current"><a class="current reference internal" href="">Image Processing Viewer</a></li>
@@ -145,104 +147,105 @@
       
   <div class="section" id="image-processing-viewer">
 <h1>Image Processing Viewer<a class="headerlink" href="#image-processing-viewer" title="Permalink to this headline">ΒΆ</a></h1>
+    <!-- <script type="text/javascript" src="/data/viewerim/viewer.json"></script> -->
 <script type="text/javascript" src="/Users/aknecht/git/ih/docs/images/viewer.json"></script>
-<script type="text/javascript">
-        base = "/Users/aknecht/git/ih/docs/images/"
-        // base = "/cropstressgenomics.org/data/viewerim/"
-        $(function() {
-                $("#function").on("change", function() {
-                        optstr = ""
-                        if ($("#function").val() == "bitwise_not" || $("#function").val() == "normalizeByIntensity") {
-                                optstr += "<input type='hidden' class='imload' />";
-                        }
-                        for (var ordernum in data[$("#function").val()]["order"]) {
-                                option = data[$("#function").val()]["order"][ordernum]
-                                optstr += "<div class='form-group'>";
-                                optstr += "<label for='" + option + "'>" + option + "</label>";
-                                optstr += "<select class='form-control imload' name='" + option + "' id='load_" + ordernum + "'>";
-                                for (var arg in data[$("#function").val()][option]) {
-                                        optstr += "<option value='" + data[$("#function").val()][option][arg] + "'>" + data[$("#function").val()][option][arg] + "</option>";
-                                }
-                                optstr += "</select>"
-                                optstr += "</div>";
-                        }
-                        $("#options").html(optstr);
-                        $("#options .imload").trigger("change");
-                });
-                $("#image").on("change", function() {
-                        $("#inputImage").html("<img src='" + base + "sample/" + $("#image").val() + "' />");
-                        $("#options .imload").trigger("change");
-                });
-                $("#options").on("change", ".imload", function() {
-                        var l = $("#options > div").length;
-                        var impath = base + "/" + $("#function").val() + "/"
-                        for (var i = 0; i < l; i++) {
-                                impath += $("#load_" + i).attr("name");
-                                impath += $("#load_" + i).val()
-                        }
-                        impath += $("#image").val();
-                        $("#outputImage").html("<img src='" + escape(impath) + "' />");
-                });
-                $("#function").trigger("change");
-                $("#image").trigger("change");
-        });
-</script>
-<div class="row">
-        <div style="height:613px;" class="col-md-2">
-                <form>
-                        <div class="form-group">
-                                <label for="function">Function</label>
-                                <select class="form-control" id="function">
-                                        <option value="adaptiveThreshold">Adaptive Threshold</option>
-                                        <option value="bitwise_and">Bitwise And</option>
-                                        <option value="bitwise_not">Bitwise Not</option>
-                                        <option value="bitwise_or">Bitwise Or</option>
-                                        <option value="bitwise_xor">Bitwise XOr</option>
-                                        <option value="blur">Blur</option>
-                                        <option value="colorFilter">Color Filter</option>
-                                        <option value="convertColor">Convert Color</option>
-                                        <option value="crop">Crop</option>
-                                        <option value="edges">Edges</option>
-                                        <option value="gaussianBlur">Gaussian Blur</option>
-                                        <option value="kmeans">Kmeans</option>
-                                        <option value="meanshift">Mean Shift Segmentation</option>
-                                        <option value="morphology">Morphology</option>
-                                        <option value="normalizeByIntensity">Normalize By Intensity</option>
-                                        <option value="threshold">Threshold</option>
-                                </select>
-                        </div>
-                        <div class="form-group">
-                                <label for="image">Images</label>
-                                <select class="form-control" id="image">
-                                        <option value="rgbsv1.png">rgbsv1</option>
-                                        <option value="rgbsv2.png">rgbsv2</option>
-                                        <option value="rgbsv3.png">rgbsv3</option>
-                                        <option value="rgbtv1.png">rgbtv1</option>
-                                        <option value="rgbtv2.png">rgbtv2</option>
-                                        <option value="rgbtv3.png">rgbtv3</option>
-                                        <option value="fluosv1.png">fluosv1</option>
-                                        <option value="fluosv2.png">fluosv2</option>
-                                </select>
-                        </div>
-                        <div class="form-group">
-                                <label for="options">Options</label>
-                                <hr style="margin-top:0px;margin-bottom:5px;">
-                        </div>
-                        <div id="options">
+    <script type="text/javascript">
+            var base = "/Users/aknecht/git/ih/docs/images/";
+    // var base = "/data/viewerim/"
+            $(function() {
+                    $("#function").on("change", function() {
+                            optstr = ""
+                            if ($("#function").val() == "bitwise_not" || $("#function").val() == "normalizeByIntensity") {
+                                    optstr += "<input type='hidden' class='imload' />";
+                            }
+                            for (var ordernum in data[$("#function").val()]["order"]) {
+                                    option = data[$("#function").val()]["order"][ordernum]
+                                    optstr += "<div class='form-group'>";
+                                    optstr += "<label for='" + option + "'>" + option + "</label>";
+                                    optstr += "<select class='form-control imload' name='" + option + "' id='load_" + ordernum + "'>";
+                                    for (var arg in data[$("#function").val()][option]) {
+                                            optstr += "<option value='" + data[$("#function").val()][option][arg] + "'>" + data[$("#function").val()][option][arg] + "</option>";
+                                    }
+                                    optstr += "</select>"
+                                    optstr += "</div>";
+                            }
+                            $("#options").html(optstr);
+                            $("#options .imload").trigger("change");
+                    });
+                    $("#image").on("change", function() {
+                            $("#inputImage").html("<img src='" + base + "sample/" + $("#image").val() + "' />");
+                            $("#options .imload").trigger("change");
+                    });
+                    $("#options").on("change", ".imload", function() {
+                            var l = $("#options > div").length;
+                            var impath = base + "/" + $("#function").val() + "/"
+                            for (var i = 0; i < l; i++) {
+                                    impath += $("#load_" + i).attr("name");
+                                    impath += $("#load_" + i).val()
+                            }
+                            impath += $("#image").val();
+                            $("#outputImage").html("<img src='" + escape(impath) + "' />");
+                    });
+                    $("#function").trigger("change");
+                    $("#image").trigger("change");
+            });
+    </script>
+    <div class="row">
+            <div style="height:613px;" class="col-md-2">
+                    <form>
+                            <div class="form-group">
+                                    <label for="function">Function</label>
+                                    <select class="form-control" id="function">
+                                            <option value="adaptiveThreshold">Adaptive Threshold</option>
+                                            <option value="bitwise_and">Bitwise And</option>
+                                            <option value="bitwise_not">Bitwise Not</option>
+                                            <option value="bitwise_or">Bitwise Or</option>
+                                            <option value="bitwise_xor">Bitwise XOr</option>
+                                            <option value="blur">Blur</option>
+                                            <option value="colorFilter">Color Filter</option>
+                                            <option value="convertColor">Convert Color</option>
+                                            <option value="crop">Crop</option>
+                                            <option value="edges">Edges</option>
+                                            <option value="gaussianBlur">Gaussian Blur</option>
+                                            <option value="kmeans">Kmeans</option>
+                                            <option value="meanshift">Mean Shift Segmentation</option>
+                                            <option value="morphology">Morphology</option>
+                                            <option value="normalizeByIntensity">Normalize By Intensity</option>
+                                            <option value="threshold">Threshold</option>
+                                    </select>
+                            </div>
+                            <div class="form-group">
+                                    <label for="image">Images</label>
+                                    <select class="form-control" id="image">
+                                            <option value="rgbsv1.png">rgbsv1</option>
+                                            <option value="rgbsv2.png">rgbsv2</option>
+                                            <option value="rgbsv3.png">rgbsv3</option>
+                                            <option value="rgbtv1.png">rgbtv1</option>
+                                            <option value="rgbtv2.png">rgbtv2</option>
+                                            <option value="rgbtv3.png">rgbtv3</option>
+                                            <option value="fluosv1.png">fluosv1</option>
+                                            <option value="fluosv2.png">fluosv2</option>
+                                    </select>
+                            </div>
+                            <div class="form-group">
+                                    <label for="options">Options</label>
+                                    <hr style="margin-top:0px;margin-bottom:5px;">
+                            </div>
+                            <div id="options">
 
-                        </div>
-                </form>
-        </div>
-        <div id="inputImage" style="height:613px;" class="col-md-5">
+                            </div>
+                    </form>
+            </div>
+            <div id="inputImage" style="height:613px;" class="col-md-5">
 
-        </div>
-        <div id="outputImage" style="height:613px;" class="col-md-5">
+            </div>
+            <div id="outputImage" style="height:613px;" class="col-md-5">
 
-        </div>
-</div>
-<div class="row">
-        <br />
-</div></div>
+            </div>
+    </div>
+    <div class="row">
+            <br />
+    </div></div>
 
 
     </div>
diff --git a/docs/build/html/workflowimage.html b/docs/build/html/workflowimage.html
index 60f6275b50031bba52914e138d49b609010f4731..1cdbbc06860c6d7b198b7cec862620d5952d7d9f 100644
--- a/docs/build/html/workflowimage.html
+++ b/docs/build/html/workflowimage.html
@@ -75,6 +75,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/workflowstats.html b/docs/build/html/workflowstats.html
index 4e739bfea4d9a5ed3c31d7a16f17f9b6717594ad..4fbc994b2fe766453162dc39593db053a865ec8e 100644
--- a/docs/build/html/workflowstats.html
+++ b/docs/build/html/workflowstats.html
@@ -74,6 +74,8 @@
 <li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
 <li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_2.html">OSG Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
 <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
 <li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
 <li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
diff --git a/docs/build/html/workshops.html b/docs/build/html/workshops.html
new file mode 100644
index 0000000000000000000000000000000000000000..e006146d9e4722c2099c8e4286569a1c215f9ea5
--- /dev/null
+++ b/docs/build/html/workshops.html
@@ -0,0 +1,174 @@
+<!DOCTYPE html>
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    
+    <title>Workshops &mdash; Image Harvest 1.0.1 documentation</title>
+    
+    <link rel="stylesheet" href="_static/basic.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <link rel="stylesheet" href="_static/bootstrap-3.2.0/css/bootstrap.min.css" type="text/css" />
+    <link rel="stylesheet" href="_static/bootstrap-3.2.0/css/bootstrap-theme.min.css" type="text/css" />
+    <link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
+    
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    './',
+        VERSION:     '1.0.1',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/underscore.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
+    <script type="text/javascript" src="_static/js/jquery-1.11.0.min.js"></script>
+    <script type="text/javascript" src="_static/js/jquery-fix.js"></script>
+    <script type="text/javascript" src="_static/bootstrap-3.2.0/js/bootstrap.min.js"></script>
+    <script type="text/javascript" src="_static/bootstrap-sphinx.js"></script>
+    <link rel="top" title="Image Harvest 1.0.1 documentation" href="index.html" />
+    <link rel="next" title="Arkansas Workshop July 2015" href="arkansas_workshop_july_2015.html" />
+    <link rel="prev" title="Workflow Example #1" href="ex_workflow_1.html" />
+<meta charset='utf-8'>
+<meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
+<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1'>
+<meta name="apple-mobile-web-app-capable" content="yes">
+
+  </head>
+  <body role="document">
+
+  <div id="navbar" class="navbar navbar-default navbar-fixed-top">
+    <div class="container">
+      <div class="navbar-header">
+        <!-- .btn-navbar is used as the toggle for collapsed navbar content -->
+        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".nav-collapse">
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+        </button>
+        <a class="navbar-brand" href="index.html">
+          Image Harvest</a>
+        <span class="navbar-text navbar-version pull-left"><b>1.0</b></span>
+      </div>
+
+        <div class="collapse navbar-collapse nav-collapse">
+          <ul class="nav navbar-nav">
+            
+            
+              <li class="dropdown globaltoc-container">
+  <a role="button"
+     id="dLabelGlobalToc"
+     data-toggle="dropdown"
+     data-target="#"
+     href="index.html">Site <b class="caret"></b></a>
+  <ul class="dropdown-menu globaltoc"
+      role="menu"
+      aria-labelledby="dLabelGlobalToc"><ul class="current">
+<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li>
+<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="start.html">Getting Started</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_script_core1.html">Core Processing Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_script_core2.html">Core Processing Example #2</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_script_color1.html">Color Filter In Depth #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="ex_workflow_1.html">Workflow Example #1</a></li>
+<li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
+<li class="toctree-l1"><a class="reference internal" href="arkansas_workshop_july_2015.html">Arkansas Workshop July 2015</a></li>
+<li class="toctree-l1 current"><a class="current reference internal" href="">Workshops</a></li>
+<li class="toctree-l1"><a class="reference internal" href="processing.html">Image Processing</a></li>
+<li class="toctree-l1"><a class="reference internal" href="viewer.html">Image Processing Viewer</a></li>
+<li class="toctree-l1"><a class="reference internal" href="statistics.html">Statistics</a></li>
+<li class="toctree-l1"><a class="reference internal" href="indexing.html">Image Loading</a></li>
+<li class="toctree-l1"><a class="reference internal" href="workflowimage.html">Image Processing Workflows</a></li>
+<li class="toctree-l1"><a class="reference internal" href="workflowstats.html">Statistics Workflows</a></li>
+</ul>
+</ul>
+</li>
+              
+                <li class="dropdown">
+  <a role="button"
+     id="dLabelLocalToc"
+     data-toggle="dropdown"
+     data-target="#"
+     href="#">Page <b class="caret"></b></a>
+  <ul class="dropdown-menu localtoc"
+      role="menu"
+      aria-labelledby="dLabelLocalToc"><ul>
+<li><a class="reference internal" href="#">Workshops</a></li>
+</ul>
+</ul>
+</li>
+              
+            
+            
+              
+                
+  <li>
+    <a href="ex_workflow_1.html" title="Previous Chapter: Workflow Example #1"><span class="glyphicon glyphicon-chevron-left visible-sm"></span><span class="hidden-sm hidden-tablet">&laquo; Workflow Example...</span>
+    </a>
+  </li>
+  <li>
+    <a href="arkansas_workshop_july_2015.html" title="Next Chapter: Arkansas Workshop July 2015"><span class="glyphicon glyphicon-chevron-right visible-sm"></span><span class="hidden-sm hidden-tablet">Arkansas Worksho... &raquo;</span>
+    </a>
+  </li>
+              
+            
+            
+            
+            
+              <li class="hidden-sm">
+<div id="sourcelink">
+  <a href="_sources/workshops.txt"
+     rel="nofollow">Source</a>
+</div></li>
+            
+          </ul>
+
+          
+            
+<form class="navbar-form navbar-right" action="search.html" method="get">
+ <div class="form-group">
+  <input type="text" name="q" class="form-control" placeholder="Search" />
+ </div>
+  <input type="hidden" name="check_keywords" value="yes" />
+  <input type="hidden" name="area" value="default" />
+</form>
+          
+        </div>
+    </div>
+  </div>
+
+<div class="container">
+  <div class="row">
+    <div class="col-md-12">
+      
+  <div class="toctree-wrapper compound">
+</div>
+<div class="section" id="workshops">
+<h1>Workshops<a class="headerlink" href="#workshops" title="Permalink to this headline">ΒΆ</a></h1>
+<p>Some text here</p>
+<p><a class="reference internal" href="arkansas_workshop_july_2015.html"><em>Arkansas Workshop July 2015</em></a></p>
+</div>
+
+
+    </div>
+      
+  </div>
+</div>
+<footer class="footer">
+  <div class="container">
+    <p class="pull-right">
+      <a href="#">Back to top</a>
+      
+    </p>
+    <p>
+        &copy; Copyright 2015, Avi Knecht.<br/>
+      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.3a0.<br/>
+    </p>
+  </div>
+</footer>
+  </body>
+</html>
\ No newline at end of file
diff --git a/docs/source/.viewer.rst.swp b/docs/source/.viewer.rst.swp
deleted file mode 100644
index 05f91489217d0f38757eb816b08d9b2f832394ab..0000000000000000000000000000000000000000
Binary files a/docs/source/.viewer.rst.swp and /dev/null differ
diff --git a/docs/source/arkansas_workshop_july_2015.rst b/docs/source/arkansas_workshop_july_2015.rst
index 810881efd7969648f9c1d3ecb7fc12f11f560e5f..c60e9092c33955588d20fa74bda5115be87d28c4 100644
--- a/docs/source/arkansas_workshop_july_2015.rst
+++ b/docs/source/arkansas_workshop_july_2015.rst
@@ -223,3 +223,161 @@ This script performs exactly the process we worked through only as a standalone
     plant.show("Final")
     plant.write("final.png")
     plant.wait()
+
+
+Day 2
+------
+Now that we have everything installed, we'll work through a pipeline for an image, extract some data, and compare to LemnaTec.
+
+:download:`Team 1 Rice 0_0_2 <../../examples/workshops/arkansas_july_2015/0_0_2.png>`
+
+:download:`The Pipeline <../../examples/workshops/arkansas_july_2015/pipeline.py>`
+
+The pipline:
+
+.. code-block:: python
+
+    import ih.imgproc
+
+    # base plant
+    plant = ih.imgproc.Image("0_0_2.png")
+    plant.save("base")
+    plant.show("base")
+
+    # blur
+    plant.blur((5, 5))
+    plant.save("blur")
+    plant.show("Blur")
+
+    # meanshift
+    plant.meanshift(4, 4, 40)
+    plant.save("shift")
+    plant.show("Meanshift")
+
+    # colorFilter
+    plant.colorFilter("(((g > r) and (g > b)) and (((r + g) + b) < 400))")
+    plant.colorFilter("(((r max g) max b) - ((r min g) min b)) > 12)")
+    plant.save("cf")
+    plant.show("Color filter")
+
+    # contourCut
+    plant.contourCut("cf", basemin = 3000, resize = True)
+    plant.save("cut")
+    plant.show("Contour Cut")
+
+    # recolor
+    plant.convertColor("bgr", "gray")
+    plant.threshold(0)
+    plant.convertColor("gray", "bgr")
+    plant.bitwise_and("base")
+    plant.write("final.png")
+    plant.show("Final")
+
+    print plant.extractPixels()
+    print plant.extractConvexHull()
+
+    plant.wait()
+
+That's a lot of code.  Let's break it down piece by piece:
+
+Loading
+#######
+
+.. code-block:: python
+
+    import ih.imgproc
+
+    # base plant
+    plant = ih.imgproc.Image("0_0_2.png")
+    plant.save("base")
+    plant.show("base")
+
+This part should be fairly familiar -- we load the Image Harvest library with import ih.imgproc, we load our image "0_0_2.png", and we save & display it under the name "base".  
+
+Blur
+#####
+
+.. code-block:: python
+
+    # blur
+    plant.blur((5, 5))
+    plant.save("blur")
+    plant.show("Blur") 
+
+Here we call the :py:meth:`~ih.imgproc.Image.blur` function -- which does exactly that.  Blur can take a few arguments, but the most important and only required argument is the first which specifies the kernel size -- a larger kernel means a more blurry output image.  The kernel size is represented as two numbers: (width, height), and both the width and height must be odd and positive.  Try blurring with a kernel size of (15, 15) instead of (5, 5).
+
+Why blur?  Blurring greatly reduces the noise in an image, which is random variations of pixel colors.  Reducing these variations helps us to more easily define a region in an image.  Look at the inside of the pot for example -- the edges between individual rocks have become much less distinct as a result of the blurring, which makes it easier to percieve as a single continuous region.  The next step continues to reduce variation and separate regions from each other.
+
+Meanshift
+#########
+
+.. code-block:: python
+
+    # meanshift
+    plant.meanshift(4, 4, 40)
+    plant.save("shift")
+    plant.show("Meanshift")
+
+Here we call the :py:meth:`~ih.imgproc.Image.meanshift` function, which performs mean shift segmentation of the image.  Mean shift segmentation groups regions in an image that are geographically close AND close in color.  The first two arguments define the geographically distance, and the third argument defines the color variation allowed. 
+
+Why meanshift?  Meanshift makes the next step in grouping an image into regions.  In this case, we have some very easily defined regions that are close both geographically and close in color.  The plant itself is completely connected and a similar shade of green.  The interior of the pot is contained within a single circle in the image, and is made of similarly colored rocks.  Both of these regions become much more uniform, and thus much easier to process as a result of this step.
+
+Color Filter
+############
+
+.. code-block:: python
+    
+    # colorFilter
+    plant.colorFilter("(((g > r) and (g > b)) and (((r + g) + b) < 400))")
+    plant.colorFilter("(((r max g) max b) - ((r min g) min b)) > 12)")
+    plant.save("cf")
+    plant.show("Color filter")
+
+Here we call the :py:meth:`~ih.imgproc.Image.colorFilter` function, which solves arbitrary color logic and then applies it to the image.  What does that mean?  Effectively, we create a color pattern, and we look for all pixels that match this color pattern.  So this pattern: "((g > r) and (g > b))", reads as: "Pixels whose green value is greater than their red value AND whose green value is greater than their blue value."  In natural language: "Pixels that are predominantely green."  The next pattern: "(((r + g) + b) < 400))", reads as: "Pixels whose red value plus green value plus blue value is less than 400."  In natural language: "Pixels that aren't too bright."  Finally we have the pattern: "(((r max g) max b) - ((r min g) min b)) > 12)", which reads as: "Pixels whose maximum value of r,g,b minus mimim value of r,g,b is greater than 12".  In natural language: "Pixels that aren't white, gray, or black."
+
+Why colorFilter?  Processing power.  The colorFilter function is very fast, and can evaluate and apply complex logic in less than a second.  Additionally, since the function evalutes logic on a per-pixel basis, it can adapt to brightness changes or noise in images that a definite color range might miss.
+
+Contour Cut
+###########
+
+.. code-block:: python
+
+    # contourCut
+    plant.contourCut("cf", basemin = 3000, resize = True)
+    plant.save("cut")
+    plant.show("Contour Cut")
+
+Here we call the :py:meth:`~ih.imgproc.Image.contourCut` function, which crops an image based on contours in an image, which are connected regions of pixels.  The function searches for all contours in the image that are greater than the size of the basemin parameter, and crops the image to fit those contours.
+
+Why contourCut?  Removal of edge noise.  The plant itself is completely connected, and thus will have the largest contour in the image by far.  Utilizing this, we can find a value that will keep our plant in the image, while removing a lot of edge noise from it.
+
+Recoloring
+##########
+
+.. code-block:: python
+
+    # recolor
+    plant.convertColor("bgr", "gray")
+    plant.threshold(0)
+    plant.convertColor("gray", "bgr")
+    plant.bitwise_and("base")
+    plant.write("final.png")
+    plant.show("Final") 
+
+What's really happening here, is we are creating a mask of our current image, and then overlaying it on our base image to extract our original color.  Blurring and segmenting our image changed its original color, and we want to restore that.  The first 3 lines create the mask.  We first convert the image to grayscale with :py:meth:`~ih.imgproc.Image.convertColor`, and then :py:meth:`~ih.imgproc.Image.threhsold` with a value of 0.  By thresholding the image with a value of 0, we keep every pixel from our grayscale image that has an intensity of at least 1.  This means we keep every non-black pixel from our grayscale image.  We then convert the image back to "bgr" from "gray", however, this does NOT restore color to the image.  Our binary image only has a single channel (intensity), but our color image has 3 channels (b, g, r).  We can't overlay our mask while it only has a single channel, so we convert it to "bgr" to give it 3 channels.  We then use :py:meth:`ih.imgproc.Image.bitwise_and` to overaly our mask on our base image.
+
+Extraction
+##########
+
+.. code-block:: python
+
+    print plant.extractPixels()
+    print plant.extractConvexHull()
+
+The print function is native to python and simply outputs information to the screen.  The :py:meth:`~ih.imgproc.Image.extractPixels` function returns the total number of non-zero pixels in the image, and the :py:meth:`~ih.imgproc.Image.extractConvexHull` function returns the area of the convexHull surrounding all non-black pixels in the image.
+
+Extras
+------
+
+.. image:: ../../examples/workshops/arkansas_july_2015/shifted.png
+    :align: center
diff --git a/docs/source/ex_workflow_1.rst b/docs/source/ex_workflow_1.rst
index 5e754eb48e5ac8422779ab6c84b82705fd64d53c..3c2c79518f0d64ab05a6781e2dfc9a5695934aca 100644
--- a/docs/source/ex_workflow_1.rst
+++ b/docs/source/ex_workflow_1.rst
@@ -1,7 +1,7 @@
 .. raw:: html
 
 	<style> .red {color:red} .blue {color:blue} .green {color:green} .orange {color:orange} </style>
-	
+
 .. role:: red
 
 .. role:: blue
@@ -19,7 +19,7 @@ Workflow generation is designed specifically for high throughput
 data sets -- this example uses a data set of ~80,000 images.  Additionally,
 this tutorial serves to show how to setup and run a workflow, not
 explaining the analysis choices made when designing a workflow.  This workflow
-was created using experiment '0184 Uni Nebraska Rice 1' data, on 
+was created using experiment '0184 Uni Nebraska Rice 1' data, on
 Tusker at the Holland Computing Center.
 
 Final Templates
@@ -45,8 +45,8 @@ Here are several examples of paths to images:
 | /work/walia/common/ih/rawdata/0184 Uni Nebraska Rice 1/strain3/0184 Uni Nebraska Rice 1_023542-C_2013-09-05_05-18-33_455640/RGB SV1/0_0.png
 | /work/walia/common/ih/rawdata/0184 Uni Nebraska Rice 1/strain5/0184 Uni Nebraska Rice 1_023546-C_2013-08-21_05-22-52_432942/FLUO SV1/0_0.png
 | /work/walia/common/ih/rawdata/0184 Uni Nebraska Rice 1/strain93/0184 Uni Nebraska Rice 1_023722-S_2013-09-09_10-56-45_462980/RGB TV/0_0.png
-	
-There are a total of 436 strain folders, 36 sub folders in each strain folder, and 12 additional image-type folders.  For 
+
+There are a total of 436 strain folders, 36 sub folders in each strain folder, and 12 additional image-type folders.  For
 this experiment, we will be processing RGB SV1, RGB SV2, FLUO SV1, FLUO SV2, and RGB TV images for a total of 436 * 36 * 5 ~= 80,000 images.
 The image loading step takes care of two key problems posed by having large data sets (assuming correctly written template files).  First,
 it tracks all images, and loads them into a single database, making it very easy to find and process files in the future.  Second,
@@ -129,8 +129,8 @@ behind crawling.
 
 	"path": "/work/walia/common/ih/rawdata/0184 Uni Nebraska Rice 1/%null%/%null%_%idnum%-%idchar%_%date%/%imgname%/0_0.png",
 	"base": "/work/walia/common/ih/rawdata/0184 Uni Nebraska Rice 1/",
-    
-The first two definitions map our way through the rest of the template.  Above, we noted several important 
+
+The first two definitions map our way through the rest of the template.  Above, we noted several important
 pieces of information in the name of the directories.  We are doing exactly that here, except in a way that
 is more understandable to the computer.  We mark important places in the directory structure by using % signs,
 along with names.  The names themselves are not strictly checked, so use names that are easy to remember.
@@ -153,9 +153,9 @@ is simply where crawling should start.  It should be a subset of the "path" defi
 
 	"filetype": ".png",
 	"order": ["experiment", "id", "genotype", "date", "treatment", "imgname", "imtype", "path"],
-	
+
 The "filetype" definition is exactly that.  It searches for all files in the final path that end in the specified filetype.
-The "order" definition is the order in which values are stored in to the database.  It serves two purposes.  Thematically, 
+The "order" definition is the order in which values are stored in to the database.  It serves two purposes.  Thematically,
 you can organize your columns the same way you would data.  More importantly, it specifies which values are saved to the database.
 You can define any value in the "order" definition, however, there are **required** definitions as well.  In addition,
 although there are some optional column names, many of the statistics function expect a given format for data.
@@ -178,7 +178,7 @@ our "path" definition, to the names used in our "order" definition.  Let's look
 				"type": "value",
 				"value": "0184"
 			},
-			
+
 The first line simply shows how to start the data section.  Specifying '"data": {' shows that all further entries
 are specifically related to data-mapping.  Each value specified in the data section corresponds to a specific
 value in the "order" entry.  The values defined in the data section are NOT order dependent, but we include
@@ -186,7 +186,7 @@ them in the same order for ease of access.  Finally, remember that each of these
 Our first example is defining a value for "experiment".  It's important
 to note that "experiment" occurs in order.  The names of entries in the data section must match the value
 in the "order" entry exactly.  First we define the type of "experiment".  Type's of data keys can be defined
-as "value", "file", or "date".  Here, we define the type of experiment as a value.  This means that the value of 
+as "value", "file", or "date".  Here, we define the type of experiment as a value.  This means that the value of
 experiment will be saved as some combination of hard-coded characters, and identifiers, based on the "value" definition.
 In this case, we do not use identifiers in our "value" definition.  We simply save the value for experiment for every image
 as 0184.
@@ -197,7 +197,7 @@ as 0184.
 		"type": "value",
 		"value": "%idnum%-%idchar%"
 	},
-	
+
 Here, we define the "id" for each plant.  We also define it as type "value", but this time we use identifiers in
 the value.  This will load the identifiers from the path directly into the value for id.  Looking at our path definition and test path again:
 
@@ -218,11 +218,11 @@ into the output value.
 				"keyColumn": 0,
 				"valueColumn": 1
 			},
-			
+
 Here, we define the "genotype" for each plant.  This time, the type is "file".  This type of data key searches through the rows of a file,
 assuming that there is a mapping of key -> value in your row. If you look at the :download:`Genotype Key File <../../examples/workflows/current/GenKey.csv>`,
 you can see that it is a csv file with two columns.  We can see that the first column contains values that look like our "id" value.  The second column
-contains our genotype string -- our target value. The "file" type always assumes your input is some sort of value separated file.  It doesn't necessarily have to be 
+contains our genotype string -- our target value. The "file" type always assumes your input is some sort of value separated file.  It doesn't necessarily have to be
 separated by commas, but that is the default functionality.  If your file is separated by something other than commas, specify the "separator" option.  There are three
 other required definitions for "file" type data keys.  You need to define "key", "keyColumn", and "valueColumn".  The columns themselves are 0-indexed.  In this case, our "keyColumn" is 0, because
 our key is located in the 0th column.  "valueColumn" is 1, because our key is located in the 1st column.  Finally, our "key" value is the same as our "id".  This
@@ -241,15 +241,15 @@ located in the same row, namely UNL032
 				"value": "%date%",
 				"format": "Y-m-d"
 			},
-			
+
 Here, we define the "date" for each plant.  We use our final type, "date".  The only additional argument to the date type
 is "format", which specifies the input format of the date.  The date type loads in values based on a combination of identifiers and hard-coded values again,
 but afterwards, it converts the date to Y-m-d format.  In this case, because the input type is defined as "Y-m-d" using a date type
 isn't strictly required, we use it as an example though.  The date input string can contain "Y", "y", "M", "m", "d", "B", "b" as format characters,
 and uses "-", "/", " ", and "_" as separators.
- 
+
  .. code-block:: javascript
- 
+
  	"treatment": {
 				"type": "value",
 				"translate": "true",
@@ -264,7 +264,7 @@ and uses "-", "/", " ", and "_" as separators.
 				"translate": "true",
 				"value": "%imgname%"
 			}
-			
+
 We include the last three together, because they are all of type "value", and simply use one of the identifiers from the base path in their value.
 However, it is important to note that two of these values have an additional option, namely "translate": "true".  This specifies that the input value
 should be mapped to a different output value.  This functions very similar to a file mapping, except the mapping is defined inside the template.
@@ -307,15 +307,44 @@ Here, the "treatment" translation takes a single character, and maps it to a wor
 In this case, our idchar is 'C', this means that the "treatment" data key, will get mapped to "Control".  We also have a translation defined for "imtype".  Looking at our test path,
 our imgname is "RGB SV1".  This means that the "imtype" data key will get mapped to "rgbsv".  Remember, the key difference between defining translations, and using file mapping is size.
 
-With our template written, we can now load the images.  We do this using the 'ih-setup' command as follows:
+With our template written, we can now load the images using 2 ih commands.  First,
+run the ih-setup command with the name of the folder you want to create:
 
 .. code-block:: bash
 
-	ih-setup --dir "DIR_NAME" --template "crawl.json"
-	
-This will setup a workflow submission directory with the name "DIR_NAME".  It will create an input folder,
-and populate that input folder with the images database, the crawl.json template file, and empty template files required for job submission.
-Next we will look at defining the configuration file!
+	ih-setup --dir awesome_project
+
+This command will create a folder with the name you specify, and will create a two
+deep directory structure, with a couple empty files at the bottom:
+
+.. code-block:: bash
+
+	awesome_project/
+	  input/
+	    -config.json
+			-crawl.json
+			-images.db
+			-imgproc.json
+			-stats.json
+
+The ih commands assume by default that you are in the top level awesome_project/
+directory, using the above naming conventions for your input files.  The naming
+of the input files can be changed by using optional arguments.  Now that the
+project folder is setup, create your crawl.json file.  The above example is
+specific to our input data, so you must adjust the crawl file to match your
+input data.  Once your crawl.json is created, run the ih-crawl command from the
+awesome_project folder:
+
+.. code-block:: bash
+
+	ih-crawl
+
+This command may take a while to run depending on how many images need to be indexed.
+Once it is finished, it should populate the images.db file with an sqlite3 database.
+The database will contain all of the metadata information it parsed from your path
+names, as well as paths to your images.  Using the images.db file, and two additional
+files, a configuration file (config.json) and an workflow definition file (imgproc.json)
+we can submit jobs.
 
 Configuration
 -------------
@@ -326,37 +355,61 @@ variables, and job clustering.  Let's take a look.
 .. code-block:: javascript
 
 	{
-    	"installdir": "/work/walia/common/ih/pymodules/bin/",
-    	"profile": {
-              	"pegasus": {
-                        "style": "glite"
-                },
-                "condor": {
-                        "grid_resource": "pbs",
-                        "universe": "vanilla"
-                },
-                "env": {
-                        "PATH": "/work/walia/common/ih/pymodules/bin/",
-                        "LD_LIBRARY_PATH": "/work/walia/common/ih/pymodules/opencv_lib/"
-                }
-        },
-        "cluster": 100,
-        "email": "avi@kurtknecht.com"
+	        "installdir": "/work/walia/common/ih/pymodules/bin/",
+	        "profile": {
+	                "pegasus": {
+	                        "style": "glite"
+	                },
+	                "condor": {
+	                        "grid_resource": "pbs",
+	                        "universe": "vanilla"
+	                },
+	                "env": {
+	                        "PATH": "/work/walia/common/ih/pymodules/bin/",
+													"PYTHONPATH": "/work/walia/common/ih/pymodules/lib/python2.6/site-packages
+	                        "LD_LIBRARY_PATH": "/work/walia/common/ih/pymodules/opencv_lib/"
+	                }
+	        },
+	        "cluster": 100,
+	        "maxwalltime": {
+	        	"images": 2,
+	        	"stats": 300
+	        },
+	        "notify": {
+	        	"email": "avi@kurtknecht.com",
+	        	"pegasus_home": "/usr/share/pegasus/"
+	        }
 	}
-	
-The "installdir" definition is the location where all of ih's scripts are installed.  It may seem
-unnecessary to include this as well as a path, but it is important for pegasus to know the exact location
-of executable files.  The "profile" defintion supports inclusion of any-possible profile variable for 
-the sites.xml.  This is taken directly from the pegasus docs.  To run the workflow on HCC & OSG,
-we specify "pegasus"->"style"->"glite", and "condor"->"grid_resource"->"pbs".  The "env" definition
-passes environment variables through to the script.  In this case, we pass in two different path variables.
-One is the location of other executable scripts, in this case our custom python install.  The LD_LIBRARY_PATH
-is for the location of the required libraries for opencv.  It should be noted, that multiple path variables can be included
-by specifying the value as a list i.e. If you specify "PATH": ["/test/path/1/", "/test/path/2/"], both paths will
-be loaded into the sites.xml.  "cluster" specifies how many jobs you want to clump together.  Most jobs take
-seconds to run, so running-the entire workflow unclustered is very-inefficient.  A cluster size of 100 is used here,
-which means that jobs will be run in batches of 100.  The "email" option defines which email to send the results to upon
-completion of the workflow.
+
+Most of these definitions are fairly straightforward, but some, such as the pegasus
+style and condor universe will be specific to the cluster you use.  Make sure
+you use appropriate pegasus configuration for your system.
+
+1. "installdir" - This is simply the location to the ih-commands.
+
+2. "profile" - This definition populates the workflows sites.xml file
+(`sites.xml pegasus docs <http://pegasus.isi.edu/wms/docs/latest/site.php>`).
+The variables defined in here will be very specific for your system.  Make
+sure you use the correct pegasus & condor environment variables.  The "env"
+definition passes environment variables through to the processing scripts.
+Make sure that "PATH" points to necessary executables, "PYTHONPATH" points to
+necessary python modules, and "LD_LIBRARY_PATH" points to the required opencv
+libraries.
+
+3.  "cluster" - This argument sets the horizontal cluster size for job execution.
+Because individual image processing steps are fast and don't require many resources,
+it is advantageous to cluster them.  The number of clusters depends on how many
+input images you have.
+
+4. "maxwalltime" - This argument defines the maximum wall time for image processing
+jobs, and statitistics workflows.  Cummulative wall time for a single cluster is
+the size of the cluster times the value in the "images" definition.  For the
+example above, this means that each cluster of 100 images will request 200 mintues
+of wall time.
+
+5. "notify" - This argument defines the information needed for email notifications
+on workflow completion.  Simply provide an email address, and the path to pegasus_home,
+which contains a notification directory.
 
 Processing
 ----------
@@ -654,7 +707,7 @@ are defined for each image type -- as a result the template is quite long.  Here
 			]
 		},
 		"options": {
-		
+
 		},
 		"extract": {
 			"histogram-bin": {
@@ -717,11 +770,11 @@ For each job you may optionally define dependent jobs.  Let's look at the first
 				"--logic": "(((((((r - g) < 30) and (((r + g) + b) < 110)) or ((((r + g) + b) > 110) and ((r - g) < 50))) or (((r - g) < 25) and ((g - r) < 25))) or (g > 60)) not 1)"
 			}
 		},
-		
+
 Here, we define the name as "pot_filter_1".  Names are used to apply a more meaningful label
 to each job for the user, as well as used for dependencies in later processing steps.
 We define the executable we want to use as "ih-color-filter" -- This executable is used for
-processing user defined color logic, and will not be talked about in depth here.  We define two inputs 
+processing user defined color logic, and will not be talked about in depth here.  We define two inputs
 for our function.  The first is "base" -- which serves as a placeholder for raw images.  You can use
 this input in any step and it will load in the starting image.  This is important for steps such
 as reconstiuting the color of the image.  The second argument we feed is a path to a roi file.
@@ -729,13 +782,13 @@ Here are the contents of the file:
 
 .. code-block:: javascript
 
-	{	
+	{
 	    "ystart": 1110,
 	    "yend": "y",
 	    "xstart": 369,
 	    "xend": 669
 	}
-	
+
 The roi file simply defines the region we want to apply our color-filter to.
 The roi file will automatically convert "y" to the maximum height, and "x" to the maximum
 width.  Additionally it supports simply arithmetic, thus you could enter "y - 300" for
@@ -758,10 +811,10 @@ We now look at the second job for fluosv:
 					},
 					"depends": ["pot_filter_1"]
 			},
-			
+
 Note that the input image is now "pot1" instead of "base".  This chains the output
 of the previous step into the input of this step.  To fully accomplish this, we must define
-dependency.  Our first job was named "pot_filter_1", and we can see this name in our 
+dependency.  Our first job was named "pot_filter_1", and we can see this name in our
 dependency list.  A job can have multiple dependencies, you simply separate the names with
 commas i.e. "depends": ["job1", "job2", "job3"].  Whenever you use the output of a previous
 job, you must include it in the dependency list.  Some functions output roi files instead of,
@@ -777,7 +830,7 @@ the only supported option is "save-steps".  If you specify:
 	"options": {
 		"save-step": "true"
 	},
-	
+
 Each intermediary step (including roi files) will be saved to the final output folder.  Otherwise,
 only the final processed image will be saved.  Lastly, "extract" is required, and here you specify
 all the numeric information you want to extract from your final images.  Let's take a look:
@@ -820,7 +873,7 @@ all the numeric information you want to extract from your final images.  Let's t
 			}
 		}
 	}
-	
+
 There is an optional special key you can define -- "histogram-bin" -- in the
 extract section.  Specifying this key allows you to perform an experiment-wise histogram
 calculation of color-channel information to generate relevant bins.  It performs the
@@ -829,10 +882,10 @@ the histograms to get a histogram for the entire data set.  3. Segment the histo
 into equal area pieces as based on the inputs. 4. Generate complete permutation
 of bins based on the divided histogram. In the "histogram-bin" section we
 first define "--group".  This allows us to group one or more imtypes from separate
-workflows together.  In this case, we group "rgbsv" and "rgbtv" together.  This 
+workflows together.  In this case, we group "rgbsv" and "rgbtv" together.  This
 allows us to consider color information from the RGB spectrum as a whole.
 We name this group "rgb" -- group names are important for future "histogram-bin"
-definitions.  Next is "--chunks".  For each group, you simply define how many 
+definitions.  Next is "--chunks".  For each group, you simply define how many
 pieces you want the total calculated histogram to be broken up into.  Remember
 that color-space is 3 dimensional -- this means that specifying chunks = 5
 will generate :math:`5^{3} = 125` bins.  Finally, we define what channels to
@@ -845,52 +898,56 @@ for every generated bin.
 The definitions in each individual "workflow" extract information from each individual
 image.  You must define "inputs" and "depends" so that the extraction script
 can locate the image you want to extract data from (it does not necessarily have to be the
-final image, though it generally is).  In the arguments section, you define a list of the 
+final image, though it generally is).  In the arguments section, you define a list of the
 numeric information you want to extract.  For an example of all arguments you can specify,
 look at the ih-extract script.  If you specify "histogram-bin" for a particular
 imtype, the "--colors" options is added automatically.
 
-Finally, to actually generate your workflow, use the ih-run command.
-You should have setup a directory from the crawling step when you executed
+Finally, to actually generate your workflow, use the ih-run command.  Run this
+command from your top level folder that was generated by the ih-setup command.
 
 .. code-block:: bash
 
-	ih-setup --dir "DIR_NAME" --template "crawl.json"
-	
-The easiest way to run ih-run is to change directories to "DIR_NAME", then
-simply run:
-
-.. code-block:: bash
-	
 	ih-run
-	
-with no arguments!  Run with the -h option to see options.  Additionally, the validator
-for processing workflows is very powerful.  Use --validate to run in validate only mode
-to help debug your workflow as you create it.  Depending on how many input images,
-it may take a while to write the necessary submission files (sometimes 10-20 minutes).
+
+This will combine the information in your configuration file, workflow definition file,
+and image database to create the necessary files for a pegasus workflow.  Additionally,
+before creating the workflow, it validates arguments and dependencies in your workflow.
+Use --validate to run in validate only mode to help debug your workflow as you create it.
+Depending on how many input images, it may take a while for ih-run to write the necessary submission files.
 
 Submission
 -----------
 Upon sucessful completion of ih-run, a date and timestamped folder should be created
-with the following structure:
+in your top level folder.  Your setup should now look like this:
 
 .. code-block:: bash
 
-	date-timestamp/
-	  input/
-	    imgproc/
-		-sites.xml
-		-conf.rc
-		-map.rc
-		-extract.dax
-		-workflow.dax
-		-notify.sh
-		-submit.sh
-	    rawfiles/
-	    templates/
-	  output/
-	    -output.db
-	  work/
+	awesome_project/
+		date-timestamp/
+		  input/
+		    imgproc/
+			-conf.rc
+			-extract.dax
+			-map.rc
+			-notify.sh
+			-remove.sh
+			-sites.xml
+			-status.sh
+			-submit.sh
+			-workflow.dax
+		    rawfiles/
+		    templates/
+		  output/
+		    -output.db
+		  work/
+		input/
+			-config.json
+			-crawl.json
+			-images.db
+			-imgproc.json
+			-stats.json
+
 
 The work directory is where actual processing is done -- but initially starts empty.  The output
 folder starts only with the output database, but contains no images to start with.  The input folder
@@ -898,9 +955,4 @@ contains a copy of your submitted templates in the templates folder, and a copy
 in the rawfiles folder.  Finally, within the imgproc folder are the actual files required to submit
 a pegasus workflow.  All you need to do to submit is execute the submit.sh script.  This will launch your
 workflow, as well as creating a status.sh script for easy monitoring, and a remove.sh script if you
-want to remove your workflow.
-
-
-
-	
-	
+want to remove your workflow.  If there are other pegasus errors you may need to adjust your configuration.
diff --git a/docs/source/ex_workflow_2.rst b/docs/source/ex_workflow_2.rst
new file mode 100644
index 0000000000000000000000000000000000000000..57d8ae1d00661d9d06618f2da1d6b91e558e52c6
--- /dev/null
+++ b/docs/source/ex_workflow_2.rst
@@ -0,0 +1,92 @@
+.. raw:: html
+
+	<style> .red {color:red} .blue {color:blue} .green {color:green} .orange {color:orange} </style>
+
+.. role:: red
+
+.. role:: blue
+
+.. role:: green
+
+.. role:: orange
+
+OSG Workflows
+==============
+This section details the modifications necessary to submit your pegasus
+workflows on the `OSG <http://www.opensciencegrid.org/>`_.  Their team has
+set up an environment specifically for our software, so the only changes that
+need to occur are some configuration changes, and creating a tarred version
+of this library.
+
+Final Templates
+----------------
+
+:download:`Configuration <../../examples/workflows/osg/config.json>`
+
+Configuration
+-------------
+Here is the adjusted configuration file:
+
+.. code-block:: javascript
+
+		{
+		    "installdir": "/work/walia/common/ih/pymodules/bin/",
+		    "profile": {
+		        "pegasus": {
+		            "style": "glite"
+		        },
+		        "condor": {
+		          "grid_resource": "pbs",
+		          "universe": "vanilla"
+		        },
+		        "env": {
+		            "PATH": "/work/walia/common/ih/pymodules/bin/",
+		            "PYTHONPATH": "/work/walia/common/ih/pymodules/lib/python2.6/site-packages",
+		            "LD_LIBRARY_PATH": "/work/walia/common/ih/pymodules/opencv_lib/"
+		        }
+		      },
+		      "cluster": 100,
+		      "maxwalltime": {
+		        	"images": 2,
+		        	"stats": 300
+		      },
+		      "notify": {
+		        	"email": "avi@kurtknecht.com",
+		        	"pegasus_home": "/usr/share/pegasus/"
+		      }
+		}
+
+
+Most of the information is the same as the configuration file from the previous
+workflow example, but there are a few differences.  First, the condor configuration
+should have the "requirements" and "+WantsStashCache" definitions, and they should
+match as above.  The "+ProjectName" definition is if you have a group on the OSG.
+Next, there is a version definition, which should match the version of your ih
+tar.  To create a tarball distribution, navigate to your ih install, and run:
+
+.. code-block:: python
+
+	python setup.py sdist
+
+This will create a dist folder, as well as an ih-1.0.tar.gz file.  Pass the
+full path to this file into the "tarball" definition.  Finally, for data staging
+and transferring to work successfully, you need to create an ssh key pair
+for your workflow.  Run the following:
+
+
+.. code-block:: bash
+
+	ssh-keygen -t rsa -b 2048
+
+This while generate an ssh key pair.  You will be prompted for a name and a
+password.  When prompted for the password, hit enter to leave the password blank.
+After this finishes, there should be two files created in your ~/.ssh/ folder,
+a private key file and public key file with the name that you gave.  Append the
+contents of the public key file to your authorized_keys files (create it if
+necessary).
+
+.. code-block:: bash
+
+	cat ~/.ssh/KEY_NAME.pub >> ~/.ssh/authorized_key
+
+Finally provide the full path to the private key for the "ssh" definition.
diff --git a/docs/source/examples.rst b/docs/source/examples.rst
index 2d6a66ba23e1172fd8e85bfd356ad5fdc738f8e4..6a1a69871dd44d22d05afcb4b0f4b849331727e8 100644
--- a/docs/source/examples.rst
+++ b/docs/source/examples.rst
@@ -1,14 +1,15 @@
 ..
-	REMEMBER TO UPDATE THE HIDDEN TOC TREE 
+	REMEMBER TO UPDATE THE HIDDEN TOC TREE
 	AS SCRIPTS ARE ADDED TO THE EXAMPLES PAGE!!!
 
 .. toctree::
     :hidden:
-	
+
     ex_script_core1
     ex_script_core2
     ex_script_color1
     ex_workflow_1
+    ex_workflow_2
     arkansas_workshop_july_2015
 
 Examples
@@ -49,6 +50,8 @@ Workflow Examples
 
 :doc:`Workflow #1 <ex_workflow_1>`, difficulty = complex.
 
+:doc:`OSG Workflows <ex_workflow_2>`
+
 Workshops
 ---------
 Start to finish tutorials for specific events.
diff --git a/examples/workflows/current/config.json b/examples/workflows/current/config.json
index 2dcae475e689e8863562757904203f1057eef1ff..aadc6ade8c38527b5f79f46bd8398d128df30b4a 100644
--- a/examples/workflows/current/config.json
+++ b/examples/workflows/current/config.json
@@ -1,25 +1,26 @@
 {
-        "installdir": "/work/walia/common/ih/pymodules/bin/",
-        "profile": {
-                "pegasus": {
-                        "style": "glite"
-                },
-                "condor": {
-                        "grid_resource": "pbs",
-                        "universe": "vanilla"
-                },
-                "env": {
-                        "PATH": "/work/walia/common/ih/pymodules/bin/",
-                        "LD_LIBRARY_PATH": "/work/walia/common/ih/pymodules/opencv_lib/"
-                }
+    "installdir": "/work/walia/common/ih/pymodules/bin/",
+    "profile": {
+        "pegasus": {
+            "style": "glite"
         },
-        "cluster": 100,
-        "maxwalltime": {
+        "condor": {
+          "grid_resource": "pbs",
+          "universe": "vanilla"
+        },
+        "env": {
+            "PATH": "/work/walia/common/ih/pymodules/bin/",
+            "PYTHONPATH": "/work/walia/common/ih/pymodules/lib/python2.6/site-packages",
+            "LD_LIBRARY_PATH": "/work/walia/common/ih/pymodules/opencv_lib/"
+        }
+      },
+      "cluster": 100,
+      "maxwalltime": {
         	"images": 2,
         	"stats": 300
-        },
-        "notify": {
+      },
+      "notify": {
         	"email": "avi@kurtknecht.com",
         	"pegasus_home": "/usr/share/pegasus/"
-        }
+      }
 }
diff --git a/examples/workflows/osg/config.json b/examples/workflows/osg/config.json
index 8a288ca55c6c24930da025b6bb7a348499ab01b1..faaa1c37349864e20c5d13f4d2ee2e531a0e7d65 100644
--- a/examples/workflows/osg/config.json
+++ b/examples/workflows/osg/config.json
@@ -1,4 +1,4 @@
-{	
+{
         "version": "1.0",
         "installdir": "/home/aknecht/stash/walia/ih/ih/build/scripts-2.7/",
         "profile": {
@@ -7,14 +7,15 @@
                 },
                 "condor": {
                         "universe": "vanilla",
-                        "requirements": "CVMFS_oasis_opensciencegrid_org_REVISION &gt;= 3590",
-                        "+WantsStashCache": "True"
+                        "requirements": "OSGVO_OS_STRING == \"RHEL 6\" &amp;&amp; HAS_FILE_usr_lib64_libstdc___so_6 &amp;&amp; CVMFS_oasis_opensciencegrid_org_REVISION >= 3590",
+                        "+WantsStashCache": "True",
+                        "+ProjectName": "RicePhenomics"
                 }
         },
         "osg": {
-        	"tarball": "/home/aknecht/stash/walia/ih/ih/dist/ih-1.0.tar.gz",
-        	"ssh": "/home/aknecht/.ssh/workflow"
-		},
+                "tarball": "/home/aknecht/stash/walia/ih/ih/dist/ih-1.0.tar.gz",
+                "ssh": "/home/aknecht/.ssh/workflow"
+        },
         "cluster": 80,
         "maxwalltime": {
                 "stats": 300,
@@ -24,4 +25,4 @@
                 "email": "avi@kurtknecht.com",
                 "pegasus_home": "/usr/share/pegasus/"
         }
-}
\ No newline at end of file
+}
diff --git a/examples/workflows/osg/imgproc.json b/examples/workflows/osg/imgproc.json
index 4a278268c91ae237f8c4cbe9d4da11fccfc2f6d7..be970e4b7f117f26fc105f73113ae2b0e9d7a758 100644
--- a/examples/workflows/osg/imgproc.json
+++ b/examples/workflows/osg/imgproc.json
@@ -4,7 +4,7 @@
 			{
 				"name": "pot_filter_1",
 				"executable": "ih-color-filter",
-				"inputs": ["base", "/Volumes/BLOO/Work/hcc/plantcv/new/workflow1/input/fluosv_pot1.json"],
+				"inputs": ["base", "/home/aknecht/stash/walia/ih/workflows/tinySet/input/fluosv_pot1.json"],
 				"outputs": ["pot1"],
 				"arguments": {
 					"--logic": "(((((((r - g) < 30) and (((r + g) + b) < 110)) or ((((r + g) + b) > 110) and ((r - g) < 50))) or (((r - g) < 25) and ((g - r) < 25))) or (g > 60)) not 1)"
@@ -13,7 +13,7 @@
 			{
 				"name": "pot_filter_2",
 				"executable": "ih-color-filter",
-				"inputs": ["pot1", "/Volumes/BLOO/Work/hcc/plantcv/new/workflow1/input/fluosv_pot2.json"],
+				"inputs": ["pot1", "/home/aknecht/stash/walia/ih/workflows/tinySet/input/fluosv_pot2.json"],
 				"outputs": ["pot2"],
 				"arguments": {
 					"--logic": "(((r + g) + b) > 120)"
@@ -33,7 +33,7 @@
 			{
 				"name": "crop",
 				"executable": "ih-crop",
-				"inputs": ["filter", "/Volumes/BLOO/Work/hcc/plantcv/new/workflow1/input/fluosv_edge.json"],
+				"inputs": ["filter", "/home/aknecht/stash/walia/ih/workflows/tinySet/input/fluosv_edge.json"],
 				"outputs": ["edged"],
 				"arguments": {},
 				"depends": ["main_filter"]
@@ -96,7 +96,7 @@
 			{
 				"name": "crop",
 				"executable": "ih-crop",
-				"inputs": ["morphed", "/Volumes/BLOO/Work/hcc/plantcv/new/workflow1/input/rgbtv_edge.json"],
+				"inputs": ["morphed", "/home/aknecht/stash/walia/ih/workflows/tinySet/input/rgbtv_edge.json"],
 				"outputs": ["edged"],
 				"arguments": {},
 				"depends": ["closing"]
@@ -188,8 +188,8 @@
 				"inputs": ["blurred"],
 				"outputs": ["thresh"],
 				"arguments": {
-					"--value": 255,
-					"--thresholdType": "binary",
+					"--value": 200,
+					"--thresholdType": "inverse",
 					"--adaptiveType": "mean",
 					"--blockSize": 15,
 					"--C": 3
@@ -239,7 +239,7 @@
 			{
 				"name": "gfilter1",
 				"executable": "ih-color-filter",
-				"inputs": ["box_filtered", "/Volumes/BLOO/Work/hcc/plantcv/new/workflow1/input/rgbsv_gray1.json"],
+				"inputs": ["box_filtered", "/home/aknecht/stash/walia/ih/workflows/tinySet/input/rgbsv_gray1.json"],
 				"outputs": ["gray_filtered1"],
 				"arguments": {
 					"--logic": "((((b max g) max r) - ((b min g) min r)) > 50)"
@@ -249,7 +249,7 @@
 			{
 				"name": "gfilter2",
 				"executable": "ih-color-filter",
-				"inputs": ["gray_filtered1", "/Volumes/BLOO/Work/hcc/plantcv/new/workflow1/input/rgbsv_gray2.json"],
+				"inputs": ["gray_filtered1", "/home/aknecht/stash/walia/ih/workflows/tinySet/input/rgbsv_gray2.json"],
 				"outputs": ["gray_filtered2"],
 				"arguments": {
 					"--logic": "((((b max g) max r) - ((b min g) min r)) > 100)"
@@ -259,7 +259,7 @@
 			{
 				"name": "crop",
 				"executable": "ih-crop",
-				"inputs": ["gray_filtered2", "/Volumes/BLOO/Work/hcc/plantcv/new/workflow1/input/rgbsv_edge.json"],
+				"inputs": ["gray_filtered2", "/home/aknecht/stash/walia/ih/workflows/tinySet/input/rgbsv_edge.json"],
 				"outputs": ["edged"],
 				"arguments": {},
 				"depends": ["gfilter2"]
@@ -286,7 +286,7 @@
 		]
 	},
 	"options": {
-	
+		"save-steps": "true"
 	},
 	"extract": {
 		"histogram-bin": {
diff --git a/examples/workshops/.DS_Store b/examples/workshops/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..a8802747e279cd430aacbeab11a160383fa8fcf9
Binary files /dev/null and b/examples/workshops/.DS_Store differ
diff --git a/examples/workshops/arkansas_july_2015/0_0_2.png b/examples/workshops/arkansas_july_2015/0_0_2.png
new file mode 100755
index 0000000000000000000000000000000000000000..c1dda2e0e13c1d0a0400a492069185e1d9ec5663
Binary files /dev/null and b/examples/workshops/arkansas_july_2015/0_0_2.png differ
diff --git a/examples/workshops/arkansas_july_2015/cat.jpeg b/examples/workshops/arkansas_july_2015/cat.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..1cf2705fbfe260e29c86a2c747e79d3082986f6b
Binary files /dev/null and b/examples/workshops/arkansas_july_2015/cat.jpeg differ
diff --git a/examples/workshops/arkansas_july_2015/cat.png b/examples/workshops/arkansas_july_2015/cat.png
new file mode 100644
index 0000000000000000000000000000000000000000..611b9742d475a39421aecd62159dbc5638e8ae69
Binary files /dev/null and b/examples/workshops/arkansas_july_2015/cat.png differ
diff --git a/examples/workshops/arkansas_july_2015/pipeline.py b/examples/workshops/arkansas_july_2015/pipeline.py
new file mode 100644
index 0000000000000000000000000000000000000000..bf20c7f5fbb136b78eac73e7896cf42805e8d19a
--- /dev/null
+++ b/examples/workshops/arkansas_july_2015/pipeline.py
@@ -0,0 +1,40 @@
+import ih.imgproc
+
+# base plant
+plant = ih.imgproc.Image("0_0_2.png")
+plant.save("base")
+plant.show("base")
+
+# blur
+plant.blur((5, 5))
+plant.save("blur")
+plant.show("Blur")
+
+# meanshift
+plant.meanshift(4, 4, 40)
+plant.save("shift")
+plant.show("Meanshift")
+
+# colorFilter
+plant.colorFilter("(((g > r) and (g > b)) and (((r + g) + b) < 400))")
+plant.colorFilter("(((r max g) max b) - ((r min g) min b)) > 12)")
+plant.save("cf")
+plant.show("Color filter")
+
+# contourCut
+plant.contourCut("cf", basemin = 3000, resize = True)
+plant.save("cut")
+plant.show("Contour Cut")
+
+# recolor
+plant.convertColor("bgr", "gray")
+plant.threshold(0)
+plant.convertColor("gray", "bgr")
+plant.bitwise_and("base")
+plant.write("final.png")
+plant.show("Final")
+
+print plant.extractPixels()
+print plant.extractConvexHull()
+
+plant.wait()
diff --git a/examples/workshops/arkansas_july_2015/rainbow.png b/examples/workshops/arkansas_july_2015/rainbow.png
new file mode 100644
index 0000000000000000000000000000000000000000..7645d5371b3b3a49c52bda29094975cb37500fb4
Binary files /dev/null and b/examples/workshops/arkansas_july_2015/rainbow.png differ
diff --git a/examples/workshops/arkansas_july_2015/rainbow_final.png b/examples/workshops/arkansas_july_2015/rainbow_final.png
new file mode 100644
index 0000000000000000000000000000000000000000..8ee38ff64c86c561435009bbe1874327dcf4a0a1
Binary files /dev/null and b/examples/workshops/arkansas_july_2015/rainbow_final.png differ
diff --git a/examples/workshops/arkansas_july_2015/shifted.png b/examples/workshops/arkansas_july_2015/shifted.png
new file mode 100644
index 0000000000000000000000000000000000000000..37362bd7d4e7435d0348d01ecd76c7fbd8e27f51
Binary files /dev/null and b/examples/workshops/arkansas_july_2015/shifted.png differ
diff --git a/ih/__init__.pyc b/ih/__init__.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..647b7cc9a3f861ae6dcd0b21bcf11c0c8b200607
Binary files /dev/null and b/ih/__init__.pyc differ
diff --git a/ih/conf.pyc b/ih/conf.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a2640b2b00313f8c47c7592e5327f2dfd85b33fd
Binary files /dev/null and b/ih/conf.pyc differ
diff --git a/ih/imgproc.pyc b/ih/imgproc.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6c693c43ec5866d4bdef335817c5b2edab88565e
Binary files /dev/null and b/ih/imgproc.pyc differ