|
|
Line 1: |
Line 1: |
| === Abstract === | | === Abstract === |
| | | |
− | The purpose of this proposal is to facilitate a "run-everywhere" philosophy for algorithm writers. If NAMIC adopts a standard for algorithm "self-description" that is followed when command line executables are written, Slicer, the grid, clusters, etc... should be able to use the executables directly in their environment. | + | The purpose of the Slicer3 Execution Model is to facilitate a "run-everywhere" philosophy for algorithm writers. NAMIC has adopted a standard for algorithm "self-description" that is followed when command line executables are written. Slicer, the grid, clusters, etc... will be able to use the executables directly in their environment. |
| | | |
− | === Execution model for stand-alone executables === | + | === Status === |
| | | |
− | For Slicer3 to interact with stand-alone executables, a communications protocol must be created and implemented on both sides. This implies that the executable must be able to describe itself in sufficient detail for Slicer3 to run it and retrieve the results of the algorithm.
| + | The Slicer3 execution model contains three components: |
| | | |
− | === Initial Standard ===
| + | # Module Description Parser - This is a C++ library that parses an xml description of a module and creates C++ classes that can be accessed in applications. |
| + | # Command Line Processing - This is a C++ program that uses the Module Description Parser to generate C++ code that parses the command line arguments specified in the xml module description. This code can be included in the command line module to access the command line arguments at run-time. |
| + | # Slicer3 GUI - This GUI and related MRML and Logic classes uses the Module Description Parser to create GUI, MRML and Logic classes for each module "discovered" at run-time. |
| | | |
− | This sample describes the initial standard. The current best implementation is to write your XML algorithm description by hand, then have your executable respond to the --xml flag by producing the XML description to standard output.
| + | Currently, an initial implementation of all three components is complete. |
| | | |
− | Some notes about the sample below.
| + | === Documentation === |
| | | |
− | # The <category> tag corresponds to where the executable should show up in a menu on the calling Application
| + | Look at the [[Slicer3:Execution_Model_Documentation|Slicer3:Execution Model Documentation]] for details. |
− | # <parameters> tags are grouped together by name in the GUI, in the example "Registration Parameters" and "IO"
| |
− | # The currently described parameters are
| |
− | ## <integer> for simple integers
| |
− | ## <double> for floating point numbers
| |
− | ## <string> for string arguments
| |
− | ## <boolean> for boolean switches
| |
− | ## <image> for images. The current standard is 3d images, but may be agumented in the future
| |
− | ## <file> for files.
| |
− | ## <integer-vector> for a comma separated list of integers
| |
− | ## <float-vector> for a comma separated list of floats
| |
− | ## <double-vector> for a comma separated list of doubles
| |
− | # Most parameters share some common attributes
| |
− | ## <flag> the short flag for this parameter, ''i.e.'' <flag>f</flag>
| |
− | ## <longflag> the long flag for this parameter, ''i.e.'' <longflag>foo</longflag>
| |
− | ## <label> the text to display next to the parameter
| |
− | ## <default> default value
| |
− | ## <description> a useful description of the parameter, suitable for tool tips, ''etc...''
| |
− | ## <constraints> currently <minimum>, <maximum>, and <step> for <integer> and <double>
| |
− | # For positional arguments, an index is required, in this case Fixed and Moving images are indices 0 and 1
| |
− | # For images, there is a <channel> tag. <channel>input</channel> indicates that this file is read by the executable, <channel>output</channel> indicates the executale writes the image
| |
| | | |
− | ==== To Do ==== | + | === Background === |
| | | |
− | * Add radiobutton like choices
| + | The initial implementation of the Slicer3 Execution Model followed a Wiki discusion of requirements and implementation options. Refer to the [[Slicer3:Execution_Model_Discussion|Slicer3:Execution_Model_Discussion]] for background and motivation. |
− | * Add image format discription, ''i.e.'' does this algorithm handle 2D images, need DICOM files, ''etc...''
| |
− | * Establish convention for progress indications
| |
− | * XSD
| |
− | | |
− | <br />
| |
− | | |
− | ==== This is the example from the NAMIC Sandbox. ====
| |
− | | |
− |
| |
− | {practical:CommandLineAPI-Linux}1356:./CLRegistration --xml
| |
− | <?xml version="1.0" encoding="utf-8"?>
| |
− | <executable>
| |
− | <category>registration</category>
| |
− | <title>NAMIC sample registration</title>
| |
− | <description>Registers two images together using a rigid transform and MI</description>
| |
− | <version>1.0</version>
| |
− | <documentationurl></documentationurl>
| |
− | <license></license>
| |
− | <contributor>Daniel Blezek</contributor>
| |
− |
| |
− | <parameters>
| |
− | <label>Registration Parameters</label>
| |
− | <description>Parameters used for registration</description>
| |
− | <integer>
| |
− | <flag>b</flag>
| |
− | <longflag>histogrambins</longflag>
| |
− | <description>Number of histogram bins to use for Mattes Mutual Information</description>
| |
− | <label>Histogram Bins</label>
| |
− | <default>30</default>
| |
− | <constraints>
| |
− | <minimum>1</minimum>
| |
− | <maximum>500</maximum>
| |
− | <step>5</step>
| |
− | </constraints>
| |
− | </integer>
| |
− |
| |
− | <integer>
| |
− | <flag>s</flag>
| |
− | <longflag>spatialsamples</longflag>
| |
− | <description>Number of spatial samples to use in estimating Mattes Mutual Information</description>
| |
− | <label>Spatial Samples</label>
| |
− | <default>10000</default>
| |
− | <constraints>
| |
− | <minimum>1000</minimum>
| |
− | <maximum>50000</maximum>
| |
− | <step>1000</step>
| |
− | </constraints>
| |
− | </integer>
| |
− |
| |
− | <string>
| |
− | <flag>i</flag>
| |
− | <longflag>iterations</longflag>
| |
− | <description>Comma separated list of iterations must have the same number of elements as learning rate</description>
| |
− | <label>Iterations</label>
| |
− | <default>200,100</default>
| |
− | </string>
| |
− |
| |
− | <string>
| |
− | <flag>l</flag>
| |
− | <longflag>learningrate</longflag>
| |
− | <description>Comma separated list of learning rates must have the same number of elements as iterations</description>
| |
− | <label>Learning Rates</label>
| |
− | <default>0.05,0.005</default>
| |
− | </string>
| |
− |
| |
− | <double>
| |
− | <longflag>translationscale</longflag>
| |
− | <flag>t</flag>
| |
− | <description>Relative scale of translations to rotations, i.e. a value of 100 means 10mm = 1 degree</description>
| |
− | <label>Translation scaling</label>
| |
− | <default>100.0</default>
| |
− | <constraints>
| |
− | <minimum>10.0</minimum>
| |
− | <maximum>500.0</maximum>
| |
− | <step>50.0</step>
| |
− | </constraints>
| |
− | </double>
| |
− | </parameters>
| |
− |
| |
− | <parameters>
| |
− | <label>IO</label>
| |
− | <description>Input/output parameters</description>
| |
− | <image>
| |
− | <name>Fixed</name>
| |
− | <label>Fixed Image</label>
| |
− | <channel>input</channel>
| |
− | <index>0</index>
| |
− | <description>Fixed image to register to</description>
| |
− | </image>
| |
− | <image>
| |
− | <name>Moving</name>
| |
− | <label>Moving Image</label>
| |
− | <channel>input</channel>
| |
− | <index>1</index>
| |
− | <description>Moving image</description>
| |
− | </image>
| |
− | <image>
| |
− | <name>Output</name>
| |
− | <label>Output Volume</label>
| |
− | <channel>output</channel>
| |
− | <index>2</index>
| |
− | <description>Resampled Moving Image</description>
| |
− | </image>
| |
− | </parameters>
| |
− |
| |
− | </executable>
| |
− |
| |
− |
| |
− | | |
− | ==== Sample screenshots ====
| |
− | | |
− | {|
| |
− | |- valign="top"
| |
− | !
| |
− | <div class="thumb tright"><div style="width: 182px">[[Image:NAMICSampleRegistrationMenu.png|[[Image:180px-NAMICSampleRegistrationMenu.png|Sample GUI generated from XML above ]]]]<div class="thumbcaption"><div class="magnify" style="float: right">[[Image:NAMICSampleRegistrationMenu.png|[[Image:magnify-clip.png|Enlarge]]]]</div>Sample GUI generated from XML above </div></div></div>
| |
− | |}
| |
− | | |
− | ==== Open questions ====
| |
− | | |
− | # What classes of algorithms should Slicer3 be aware of?
| |
− | ## Registration, classification, segmentation, filtering?
| |
− | # How should Slicer3 communicate with the executables?
| |
− | ## Special FileIO objects (for ITK) has been suggested.
| |
− | ## MMapped files for efficient IO.
| |
− | ## Shared memory.
| |
− | ## Standard files.
| |
− | # Does Slicer3 need to communicate with the executing process?
| |
− | ## For status, "Cancel" operations, ''etc''...
| |
− | | |
− | === Proposal ===
| |
− | | |
− | If we adopt a standard XML description of the parameters to the algorithm, any application should be able to parse the XML and construct a GUI suitable for interaction with the software.
| |
− | | |
− | Below are potential ideas for an XML file format:
| |
− | | |
− | ==== Initial JSON output from sample registration package ====
| |
− | | |
− |
| |
− | /* JSON version 1.0 */
| |
− | {
| |
− | "class" : "registration",
| |
− | "name" : "CLRegistration",
| |
− | "info" : "Register two volumes",
| |
− | "executable" : "CLRegistration",
| |
− | "requiredparameters": {
| |
− | "fixed" : {
| |
− | "type" : "file",
| |
− | "index" : "0",
| |
− | "channel" : "input",
| |
− | /* what about image dimension: 2, 3, ... */
| |
− | },
| |
− | "moving" : {
| |
− | },
| |
− | "output" : {
| |
− | }
| |
− | "parameters" : {
| |
− | "histogrambins" : {
| |
− | "flag" : "b",
| |
− | "name" : "histogrambins",
| |
− | "displayname" : "Number of histogram bins",
| |
− | "description" : "Number of histogram bins",
| |
− | "type" : "integer",
| |
− | "guihints" : "slider",
| |
− | "range" : "[5-200]",
| |
− | "default" : "100"
| |
− | },
| |
− | "randomseed" : {
| |
− | "flag" : "d",
| |
− | "name" : "randomseed",
| |
− | },
| |
− | "gradtolerance" : {
| |
− | "flag" : "g",
| |
− | "name" : "gradtolerance",
| |
− | },
| |
− | "iterations" : {
| |
− | "flag" : "i",
| |
− | "name" : "iterations",
| |
− | },
| |
− | "learningrate" : {
| |
− | "flag" : "l",
| |
− | "name" : "learningrate",
| |
− | },
| |
− | "spatialsamples" : {
| |
− | "flag" : "s",
| |
− | "name" : "spatialsamples",
| |
− | },
| |
− | "translationscale" : {
| |
− | "flag" : "t",
| |
− | "name" : "translationscale",
| |
− | },
| |
− | "noinitializetransform" : {
| |
− | "flag" : "u",
| |
− | "name" : "noinitializetransform",
| |
− | },
| |
− | "help" : {
| |
− | "flag" : "h",
| |
− | "name" : "help",
| |
− | },
| |
− | "json" : {
| |
− | "flag" : "j",
| |
− | "name" : "json",
| |
− | },
| |
− | }
| |
− | }
| |
− | | |
− | XML Version of the same description
| |
− | | |
− | <sl
| |
− | class = "registration"
| |
− | name = "CLRegistration"
| |
− | info = "Register two volumes"
| |
− | executable = "CLRegistration">
| |
− | <requiredparameters>
| |
− | <requirement name="fixed">
| |
− | type = "file"
| |
− | index = "0"
| |
− | channel = "input"
| |
− | <!-- what about image dimension: 2 3 ... -->
| |
− | </requirement>
| |
− | <requirement name="moving" />
| |
− | <requirement name="output" />
| |
− | </requiredparameters>
| |
− | <parameters>
| |
− | <parameter name="histogrambins"
| |
− | flag = "b"
| |
− | name = "histogrambins"
| |
− | displayname = "Number of histogram bins"
| |
− | description = "Number of histogram bins"
| |
− | type = "integer"
| |
− | guihints = "slider"
| |
− | range = "[5-200]"
| |
− | default = "100"
| |
− | />
| |
− | <parameter name="randomseed"
| |
− | flag = "d"
| |
− | name = "randomseed"
| |
− | />
| |
− | <parameter name="gradtolerance"
| |
− | flag = "g"
| |
− | name = "gradtolerance"
| |
− | />
| |
− | <parameter name="iterations"
| |
− | flag = "i"
| |
− | name = "iterations"
| |
− | />
| |
− | <parameter name="learningrate"
| |
− | flag = "l"
| |
− | name = "learningrate"
| |
− | />
| |
− | <parameter name="spatialsamples"
| |
− | flag = "s"
| |
− | name = "spatialsamples"
| |
− | />
| |
− | <parameter name="translationscale"
| |
− | flag = "t"
| |
− | name = "translationscale"
| |
− | />
| |
− | <parameter name="noinitializetransform"
| |
− | flag = "u"
| |
− | name = "noinitializetransform"
| |
− | />
| |
− | <parameter name="help"
| |
− | flag = "h"
| |
− | name = "help"
| |
− | />
| |
− | <parameter name="json"
| |
− | flag = "j"
| |
− | name = "json"
| |
− | />
| |
− | </parameters>
| |
− | </sl>
| |
− | | |
− | ==== Data-centric proposal ====
| |
− | | |
− |
| |
− | <?xml version="1.0" encoding="utf-8"?>
| |
− | <executable class="registration">
| |
− | <Name>CLRegistration</name>
| |
− | <Description>Registers two images, writes the resampled moving image</description>
| |
− | <Parameters>
| |
− | <Parameter required="false" flag="t" name="threshold">
| |
− | <Description>Threshold</Description>
| |
− | <Type>integer</Type>
| |
− | <Constraints>
| |
− | <Range minimum="0" maximum="100"/>
| |
− | </Constraints>
| |
− | </Parameter>
| |
− | <Parameter required="true">
| |
− | </Parameter>
| |
− | </Parameters>
| |
− | </executable>
| |
− |
| |
− | | |
− | ==== GUI-centric proposal ====
| |
− | | |
− |
| |
− | <?xml version="1.0" encoding="utf-8"?>
| |
− | <executable class="register">
| |
− | <name>Register3d</name>
| |
− | <version>1.0</version>
| |
− | <description>This registers and resamples two images</description>
| |
− |
| |
− | <parameters>
| |
− | <!-- a switch is a boolean flag, likely a checkbox.
| |
− | on the command line, name is the long version, flag is the
| |
− | one character version of the argument
| |
− | -->
| |
− | <switch name="interpolate" flag="i" default="true" required="false">
| |
− | <description></description>
| |
− | </switch>
| |
− |
| |
− | <!-- a value takes a single argument, may be required to be present
| |
− | and has a type. In this case, the "metric" value is constrained to be
| |
− | one of the listed options below. This should be represented by a
| |
− | group of radio buttons or drop down menu.
| |
− | -->
| |
− | <value name="metric" flag="m" default="mattes" required="false" type="string">
| |
− | <description></description>
| |
− | <constraints>
| |
− | <list>
| |
− | <constraint>mattes</constraint>
| |
− | <constraint>mi</constraint>
| |
− | <constraint>normalizedcorrelation</constraint>
| |
− | </list>
| |
− | </constraints>
| |
− | </value>
| |
− |
| |
− | <!-- an integer value with a range -->
| |
− | <value name="threshold" flag="t" type="integer">
| |
− | <constraints>
| |
− | <range minimum="0" maximum="100"/>
| |
− | <increment>.1</increment>
| |
− | </constraints>
| |
− | </value>
| |
− |
| |
− | <!-- a value argument that allow several instances of the argument to be specified.
| |
− | The values are appended to each other and returned in a vector.
| |
− | In the GUI, this could be a list of numbers in a string, or a
| |
− | dynamic list constructed by the user.
| |
− | -->
| |
− | <value name="iterations" flag="e" type="iteration" allowrepeats="true">
| |
− | <constraints>
| |
− | <range minimum="1"/>
| |
− | </constraints>
| |
− | </value>
| |
− |
| |
− | <!-- xor specifies that only one of it's contained parameters
| |
− | be specified. In this case, we want a file or url, but not
| |
− | both -->
| |
− | <xor>
| |
− | <value name="file" flag="f" type="filename"/>
| |
− | <value name="url" flag="u"/>
| |
− | </xor>
| |
− |
| |
− | <!-- unlabeledvalue do not have a flag associated with them, and are positional.
| |
− | In this case, we are looking for 3 filenames.
| |
− | -->
| |
− | <unlabeledvalue name="fixedimage" position="0" type="filename"/>
| |
− | <unlabeledvalue name="movingimage" position="1" type="filename"/>
| |
− | <unlabeledvalue name="outputimage" position="2" type="filename"/>
| |
− | </parameters>
| |
− | </executable>
| |
− | | |
− | ==== JSON description ====
| |
− | | |
− |
| |
− | /* JSON version 1.0
| |
− | January 11, 2005 */
| |
− | {
| |
− | "class" : "registration",
| |
− | "name" : "CLRegistration",
| |
− | "info" : "Registers two images, writes the resampled moving image",
| |
− | "executable" : "CLRegistration",
| |
− | "parameters" :
| |
− | "threshold" : {
| |
− | "info" : "threshold"
| |
− | "flag" : "t",
| |
− | "required" : "true",
| |
− | "type" : "integer",
| |
− | "default" : "50",
| |
− | "contraints" : {
| |
− | "range" : {
| |
− | "minimum" : "0",
| |
− | "maximum" : "100" } },
| |
− | "guihints" : {
| |
− | "control" : "slider",
| |
− | "group" : "preprocessing" } },
| |
− | "xsigma" : {
| |
− | "info" : "X Direction in sigma",
| |
− | "flag" : "x",
| |
− | "required" : "false",
| |
− | "type" : "float",
| |
− | "default" : "1.0",
| |
− | "contraints" : {
| |
− | "range" : {
| |
− | "minimum" : "0",
| |
− | "maximum" : "5.0" } },
| |
− | "guihints" : {
| |
− | "control" : "slider",
| |
− | "group" : "preprocessing" } },
| |
− | "fixedfile" : {
| |
− | "info" : "Fixed Image",
| |
− | "order" : "0",
| |
− | "required" : "true",
| |
− | "type" : "file",
| |
− | "contraints" : {
| |
− | "filetypes" : [
| |
− | "ITK",
| |
− | "Slicerd",
| |
− | "MRML" ] },
| |
− | "guihints" : {
| |
− | "control" : "fileselection",
| |
− | "group" : "io" } },
| |
− |
| |
− | }
| |
− | | |
− | === Related Work ===
| |
− | | |
− | ==== MetaCommand ====
| |
− | | |
− | Julien Jomier and Stephen Aylward have added support for command line parsing to itk with the MetaCommand class (Utilities/MetaIO/metaCommand.{h,cxx}). It supports a -xml flag to output args in an xml syntax.
| |
− | | |
− | ==== Qt Designer XML Format ====
| |
− | | |
− | Qt has an xml syntax for representing their GUI layouts. It's unclear if this tool could be used to design layouts used by other GUI packages.
| |
− | | |
− | ==== ParaView Server ====
| |
− | | |
− | ParaView has a syntax to extend the GUI described [http://www.paraview.org/Wiki/ParaView:Extend on their wiki here].
| |
− | | |
− | ==== LONI Pipeline ====
| |
− | | |
− | Parameters to executables are described in an XML file as part of the process of wrapping them for the pipeline. These XML descriptions are quite similar to the example given above. Some example pipelines are available at the [http://www.loni.ucla.edu/twiki/bin/view/Pipeline/PipelineModules Pipeline Wiki]. A working draft of the language description is found also on the [http://www.loni.ucla.edu/twiki/bin/view/Pipeline/DeveloperDocumentation Wiki].
| |
− | | |
− | ==== JSON ====
| |
− | | |
− | Mike Halle suggested looking a JSON to describe the command line arguments to the parser, then to fill in the values from the command line. With this description, a GUI could build an interface for your code and/or communicate with your executable using JSON. Requires a standard set of elements.
| |
− | | |
− | [http://www.json.org/ JSON (JavaScript Object Notation)] is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.</pre>
| |
− | | |
− | ==== DICOM Working Group 23 ====
| |
− | | |
− | Dave Channin suggests this group be aware of the efforts of [http://medical.nema.org/DICOM/minutes/WG-23/ DICOM Working Group 23] along these lines. Although termed ''application hosting'' the work group is defining a DICOM standard mechanism by which a workstation can ''invoke'' an algorithm, send it (DICOM) data and receive from it (DICOM) results (as well as statuses, etc.) Although still in draft form they are thinking about using web services and in particular, [http://www.globus.org/ogsa/ OGSA (Open Grid Services Architecture)]. This has the interesting repercussion of allowing invoked algorihtms to be run locally or over the grid. This effort may be of interest to this group along two lines: 1) IMNSHO, Slicer should support the DICOM WG23 plug so as to be able to invoke compliant algorithms, and 2) Algorithm developers need to decide whether to add their specific functionality to ''base Slicer'' or as a DICOM WG23. In th elatter case it would then be possible to run these (presumably VTK and iTK based) algorithms not only on Slicer but on other (potentially commercial workstations) that support DICOM WG23. (I hope this is the right group to consider this).
| |