|
|
(111 intermediate revisions by 12 users not shown) |
Line 1: |
Line 1: |
− | == Introduction ==
| + | <big>'''Note:''' We are migrating this content to the slicer.org domain - <font color="orange">The newer page is [https://www.slicer.org/wiki/Slicer3:Execution_Model_Documentation here]</font></big>a |
− | | |
− | The Slicer 3 Execution Model is designed to improve the acceptance and productivity of Slicer application developers. The Execution Model provides a simple mechanism for incorporating command line programs as Slicer modules. These command line modules are self-describing, emitting an XML description of its command line arguments. Slicer uses this XML description to construct a GUI for the module.
| |
− | | |
− | [[Image:ExecutionModelPlugins.png|[[Image:ExecutionModelPlugins.png|Image:ExecutionModelPlugins.png]]]]
| |
− | | |
− | [[Image:CommandLineModule.png|[[Image:CommandLineModule.png|Image:CommandLineModule.png]]]] [[Image:ModuleFactory.png|[[Image:400px-ModuleFactory.png]]]]
| |
− | | |
− | [[Image:Class_parser_state_coll_graph.png|[[Image:Class_parser_state_coll_graph.png|Image:Class_parser_state_coll_graph.png]]]]
| |
− | | |
− | == Module Description ==
| |
− | | |
− | Modules are described using XML. The XML is used to generate the C++ command line code and the GUI for the application.
| |
− | | |
− | === XML Schema ===
| |
− | | |
− | At a minimum, each module description must contain:
| |
− | | |
− | <?xml version="1.0" encoding="utf-8"?>
| |
− | <executable>
| |
− | <title>A title</title>
| |
− | <description>A description</description>
| |
− | <parameters>
| |
− | At least one parameter
| |
− | </parameters>
| |
− | </executable>
| |
− | | |
− | In the following descriptions of each XML tag, CLP means command line processing and GUI means graphical user interface. Unless otherwise specified, tags are optional.
| |
− | | |
− | ; <executable> (required)
| |
− | | |
− | : ;; <category>
| |
− | :: Classifies the executable (e.g. Filtering, Segmentation). Category can be a ''dot'' sepearted string.
| |
− | :: ''for CLP'', not used.
| |
− | :: ''for GUI'', used on the menu selector to group executables. ''Dot'' separated strings can be used to generate sub-menus.
| |
− | ;; </category>
| |
− | | |
− | : ;; <title> (required)
| |
− | :: A word or two describing the executable (e.g. Median Filter, Anisotropic Diffusion
| |
− | :: ''for CLP'', not used.
| |
− | :: ''for GUI'', used to label the frame containing the GUI for the executable. Also, GUI names for volumes use this label as a prefix.
| |
− | ;; </title>
| |
− | | |
− | : ;; <description> (required)
| |
− | :: A long description of the executable. Any double quotes will be converted to single quotes.
| |
− | :: ''for CLP'', appears at the end of the --help.
| |
− | :: ''for GUI'', appears in the help frame.
| |
− | ;; </description>
| |
− | | |
− | : ;; <version>
| |
− | :: The version of the command line executable. A suggested format is:
| |
− | ::: ''major''.''minor''.''patch''.''build''.''status''
| |
− | ::: where status is
| |
− | :::: vc: version controlled (pre-alpha), build can be a serial revision number, if any (like svn might have).
| |
− | :::: a: alpha
| |
− | :::: b: beta
| |
− | :::: rc: release candidate
| |
− | :::: fcs: first customer ship
| |
− | :: ''for CLP'', reported in response to --version.
| |
− | :: ''for GUI'', not used.
| |
− | ;; </version>
| |
− | | |
− | : ;; <documentation-url>
| |
− | :: The location of extended documentation for the executable, (e.g. http://www.na-mic.org/foo.html).
| |
− | ;; </documentation-url>
| |
− | | |
− | : ;; <license>
| |
− | :: The type of license or a url containing the license, (e.g. Berkeley, Apache, http://www.slicer.org/copyright/copyright.txt).
| |
− | :: ''for CLP'', not used.
| |
− | :: ''for GUI'', not used.
| |
− | ;; </license>
| |
− | | |
− | : ;; <contributor>
| |
− | :: The author(s) of the command line executable (e.g. Pieper, Jim Miller).
| |
− | :: for ''CLP'', not used
| |
− | :: for ''GUI'', not used.
| |
− | ;; </contributor>
| |
− | | |
− | : ;; <parameters> [advanced="true|''false''"] (required for each group of parameters)
| |
− | :: Starts a group of parameters.
| |
− | :: for ''CLP'', not used.
| |
− | :: for ''GUI'', defines a widget (in tk, a frame) that contains other widgets. If ''advanced'' is true, the frame will be closed initially.
| |
− | | |
− | : :: ;;; <label> (required)
| |
− | ::: A short string that summarizes a parameter group, (e.g. I/O, Diffusion)
| |
− | ::: for ''CLP'', not used.
| |
− | ::: for ''GUI'', used to label the frame.
| |
− | ;;; </label>
| |
− | | |
− | : :: ;;; <description> (required)
| |
− | ::: A short descriprion of the parameter group, (e.g. Input/Output Parameters, Anitostropic Diffusion Parameters). Any double quotes will be converted to single quotes.
| |
− | ::: ''for CLP'', not used.
| |
− | ::: ''for GUI'', used in balloon help for the frame containing the parameter group.
| |
− | ;;; </description>
| |
− | | |
− | : :: ;;; <integer> | <float> | <double> | <boolean> | <string> | <integer-vector> | <float-vector> | <double-vector> | <string-vector> | <integer-enumeration> | <float-enumeration> | <double-enumeration> | <string-enumeration> | <file> | <directory> | <image> | <geometry> | <point>[multiple="true|''false''"] [coordinateSystem="lps|ras|''ijk''"]
| |
− | ::: The type of the parameter. The scalar types ('''integer''', '''float''', etc.) correspond to the usual programmming language types. The '''-vector''' types are representaed by comma separated values of the scalar type. The '''-enumeration''' types use the '''<element>''' tag to enumerate choices of the scalar type. '''<image>''' is a special type that indicates that the parameter is a file name that specifies images. If the attribute multiple is "true", multiple arguments are allowed for '''scalar''', '''file''', '''directory''', '''image''', '''geometry''' and '''point''' parameters. The attribute coordinateSystem is allowed for the parameter '''point'''. If the parameter has a ''flag'' or ''longflag'', then the flag may be specified multiple times on the command line. The resulting C++ variable will be a std::vector of the scalar type. If the multiple parameter does not have a flag, then multiple arguments can appear on the command line. However, a multiple parameter with no flags must be the last parameter specified.
| |
− | | |
− | : :: ::: ;;;; <name> (required if longflag is not specified)
| |
− | :::: The name of a command line argument. If name is not specified, longflag will be used (e.g. conductance, numberOfIterations). The name must be usable as a C++ variable. For example, it CANNOT have spaces or special characters and must start with a letter.
| |
− | :::: ''for CLP'', the name of the C++ variable.
| |
− | :::: ''for GUI'', used internally.
| |
− | ;;;; </name>
| |
− | | |
− | : :: ::: ;;;; <description> (required)
| |
− | :::: A brief description of the parameter. Any double quotes will be converted to single quotes.
| |
− | :::: ''for CLP'', describes the parameter for --usage and --help.
| |
− | :::: ''for GUI'', describes the parameter when the cursor is placed over the widget for the parameter (balloon help).
| |
− | ;;;; </description>
| |
− | | |
− | : :: ::: ;;;; <label> (required)
| |
− | :::: A label for parameter (e.g. Dicom Directory, Conductance).
| |
− | :::: ''for'' CLP, not used.
| |
− | :::: ''for'' GUI, the label for the parameter widget.
| |
− | ;;;; </label>
| |
− | | |
− | : :: ::: ;;;; <default>
| |
− | :::: A default value for the parameter. The default must be a type that is compatible with the parameter type. The vector parameters are specified as comma separated values of the atomic parameter type.
| |
− | :::: ''for CLP'', contains the default for the parameter unless the parameter is a ''boolean''. The default for ''boolean'' parameters is always set to ''false''.
| |
− | :::: ''for GUI'', contains the default for the parameter.
| |
− | ;;;; </default>
| |
− | | |
− | : :: ::: ;;;; <flag> (not required if longflag is present)
| |
− | :::: A single character command line flag (e.g. s, W)
| |
− | :::: ''for CLP'', used as the short flag on the command line.
| |
− | :::: ''for GUI'', used when running the module.
| |
− | ;;;; </flag>
| |
− | | |
− | : :: ::: ;;;; <longflag> (not required if flag is present)
| |
− | :::: A command line flag (e.g. spacing, Watcher).
| |
− | :::: ''for CLP'', used as the long flag on the command line.
| |
− | :::: ''for GUI'', used when running the module.
| |
− | ;;;; </longflag>
| |
− | | |
− | : :: ::: ;;;; <constraints>
| |
− | :::: Encloses constraints on the value of a non-vector, non-enumerated parameter.
| |
− | :::: ''for CLP'', not used.
| |
− | :::: ''for GUI'', if present, a slider will be created using the minimum, maximum and step specified.
| |
− | | |
− | : :: ::: :::: ;;;;; <minimum>
| |
− | ::::: The minimum allowed value for the parameter. If not specified, the minimum is the smallest possible value for the parameter type.
| |
− | ;;;;; </minimum>
| |
− | | |
− | : :: ::: :::: ;;;;; <maximum>
| |
− | ::::: The maximum allowed value for the parameter. If not specified, the maximum is the largest possible value for the parameter type.
| |
− | ;;;;; </maximum>
| |
− | | |
− | : :: ::: :::: ;;;;; <step>
| |
− | ::::: The increment for the parameter.
| |
− | ;;;;; </step>
| |
− | | |
− | : :: ::: ;;;; </constraints>
| |
− | | |
− | : :: ::: ;;;; <channel> (required for file, directory and image parameters)
| |
− | :::: Specifies whether the parameter is an input or output parameter.
| |
− | :::: ''for CLP'', not used.
| |
− | :::: ''for GUI'', selects the proper widget for file handling.
| |
− | ;;;; </channel>
| |
− | | |
− | : :: ::: ;;;; <index> (required if there are no flags specified)
| |
− | :::: An integer starting at 0, that specifies a command line argument that has no flags.
| |
− | :::: ''for CLP'', specifies the order of an argument that has no flags.
| |
− | :::: ''for GUI'', used when running the module.
| |
− | ;;;; </index>
| |
− | | |
− | : :: ::: ;;;; <enumeration> (required for enumeration parameters)
| |
− | :::: Encloses elements for the parameter. The parameter is restricted one and only one element.
| |
− | :::: ''for CLP'', not used.
| |
− | :::: ''for GUI'', defines a radio button with choices.
| |
− | | |
− | : :: ::: :::: ;;;;; <element>
| |
− | ::::: Defines the choice. Must be of the proper type for a parameter.
| |
− | ::::: ''for CLP'', not used.
| |
− | ::::: ''for GUI'', used as the label for the raido button.
| |
− | ;;;;; </element>
| |
− | | |
− | : :: ::: ;;;; </enumeration>
| |
− | | |
− | : :: ;;; </integer> | </float> | </double> | </boolean> | </string> | </integer-vector> | </float-vector> | </double-vector> | </string-vector> | </integer-enumeration> | </float-enumeration> | </double-enumeration> | </string-enumeration> | </file> | </directory> | </image> | </geometry> | </point>
| |
− | ;; </parameters>
| |
− | | |
− | ; </executable>
| |
− | | |
− | == Slicer3 GUI Generation ==
| |
− | | |
− | Slicer 3 generates GUI's for each executable discovered during the startup process. Slicer 3 searches directories stored in the Slicer3 Module Path. This path is set from the Slicer3 application in View->Applicaton Settings->Module Settings. For Windows, the Module Path contains ";" separated directories while for Unix, the directories are spearated by ":"'s. Slicer3 attempts to run every executable in the prescribed directores and look for a valid XML file in response to a "--xml" command line.
| |
− | | |
− | Here are a few representative examples.
| |
− | | |
− | === A tour of the Execution Model XML ===
| |
− | | |
− | This example is a sampler of the parameters available in the Execution Model.
| |
− | | |
− | <div class="floatright"><span>[[Image:ExectionModelTourGUI.png|[[Image:ExectionModelTourGUI.png]]]]</span></div>
| |
− | | |
− | <?xml version="1.0" encoding="utf-8"?>
| |
− | <executable>
| |
− | <category>Tours</category>
| |
− | <title>Execution Model Tour</title>
| |
− | <description>
| |
− | Shows one of each type of parameter.
| |
− | </description>
| |
− | <version>1.0</version>
| |
− | <documentationurl></documentationurl>
| |
− | <license></license>
| |
− | <contributor>Daniel Blezek</contributor>
| |
− |
| |
− | <parameters>
| |
− | <label>Scalar Parameters</label>
| |
− | <description>
| |
− | Variations on scalar parameters
| |
− | </description>
| |
− | <integer>
| |
− | <name>integerVariable</name>
| |
− | <flag>i</flag>
| |
− | <longflag>integer</longflag>
| |
− | <description>
| |
− | An integer without constraints
| |
− | </description>
| |
− | <label>Integer Parameter</label>
| |
− | <default>30</default>
| |
− | </integer>
| |
− | <label>Scalar Parameters With Constraints</label>
| |
− | <description>Variations on scalar parameters</description>
| |
− | <double>
| |
− | <name>doubleVariable</name>
| |
− | <flag>d</flag>
| |
− | <longflag>double</longflag>
| |
− | <description>An double with constraints</description>
| |
− | <label>Double Parameter</label>
| |
− | <default>30</default>
| |
− | <constraints>
| |
− | <minimum>0</minimum>
| |
− | <maximum>1.e3</maximum>
| |
− | <step>0</step>
| |
− | </constraints>
| |
− | </double>
| |
− | </parameters>
| |
− |
| |
− | <parameters>
| |
− | <label>Vector Parameters</label>
| |
− | <description>Variations on vector parameters</description>
| |
− | <float-vector>
| |
− | <name>floatVector</name>
| |
− | <flag>f</flag>
| |
− | <description>A vector of floats</description>
| |
− | <label>Float Vector Parameter</label>
| |
− | <default>1.3,2,-14</default>
| |
− | </float-vector>
| |
− | <string-vector>
| |
− | <name>stringVector</name>
| |
− | <longflag>string_vector</longflag>
| |
− | <description>A vector of strings</description>
| |
− | <label>String Vector Parameter</label>
| |
− | <default>"foo",bar,"foobar"</default>
| |
− | </string-vector>
| |
− | </parameters>
| |
− |
| |
− | <parameters>
| |
− | <label>Enumeration Parameters</label>
| |
− | <description>Variations on enumeration parameters</description>
| |
− | <string-enumeration>
| |
− | <name>stringChoice</name>
| |
− | <flag>e</flag>
| |
− | <longflag>enumeration</longflag>
| |
− | <description>An enumeration of strings</description>
| |
− | <label>String Enumeration Parameter</label>
| |
− | <default>foo</default>
| |
− | <element>foo</element>
| |
− | <element>"foobar"</element>
| |
− | <element>foofoo</element>
| |
− | </string-enumeration>
| |
− | </parameters>
| |
− | </executable>
| |
− | | |
− | === Module with an integer-vector, one input image and one output image ===
| |
− | | |
− | Here is the XML that describes the MedianImageFilter. The image on the right shows the generated Slicer 3 GUI. The help frame has been expanded by the user.
| |
− | | |
− | <div class="floatright"><span>[[Image:MedianFilterGUI.png|[[Image:MedianFilterGUI.png]]]]</span></div>
| |
− | | |
− | <?xml version="1.0" encoding="utf-8"?>
| |
− | <executable>
| |
− | <category>Filtering</category>
| |
− | <title>Median Filter</title>
| |
− | <description>
| |
− | The MedianImageFilter is commonly
| |
− | used as a robust approach for
| |
− | noise reduction. This filter is
| |
− | particularly efficient against
| |
− | "salt-and-pepper" noise. In other
| |
− | words, it is robust to the presence
| |
− | of gray-level outliers. MedianImageFilter
| |
− | computes the value of each output
| |
− | pixel as the statistical median of
| |
− | the neighborhood of values around the
| |
− | corresponding input pixel.
| |
− | </description>
| |
− | <version>1.0</version>
| |
− | <documentationurl></documentationurl>
| |
− | <license></license>
| |
− | <contributor>Bill Lorensen</contributor>
| |
− |
| |
− | <parameters>
| |
− | <label>Median Filter Parameters</label>
| |
− | <description>
| |
− | Parameters for the median filter
| |
− | </description>
| |
− |
| |
− | <integer-vector>
| |
− | <name>neighborhood</name>
| |
− | <longflag>neighborhood</longflag>
| |
− | <description>
| |
− | The size of the neighborhood in each dimension. The sizes are comma separated.
| |
− | </description>
| |
− | <label>Neighborhood Size</label>
| |
− | <default>1,1,1</default>
| |
− | </integer-vector>
| |
− |
| |
− | </parameters>
| |
− |
| |
− | <parameters>
| |
− | <label>I/O</label>
| |
− | <description>Input/Output parameters</description>
| |
− | <image>
| |
− | <name>inputVolume</name>
| |
− | <label>Input Volume</label>
| |
− | <channel>input</channel>
| |
− | <index>0</index>
| |
− | <description>Input volume to be filtered</description>
| |
− | </image>
| |
− | <image>
| |
− | <name>outputVolume</name>
| |
− | <label>Output Volume</label>
| |
− | <channel>output</channel>
| |
− | <index>1</index>
| |
− | <description>Output filtered</description>
| |
− | </image>
| |
− | </parameters>
| |
− |
| |
− | </executable>
| |
− | | |
− | === Module with a multiple scalars, one Input image and one output image ===
| |
− | | |
− | A module with
| |
− | | |
− | <div class="floatright"><span>[[Image:AnisotropicDiffusionFilterGUI.png|[[Image:AnisotropicDiffusionFilterGUI.png]]]]</span></div>
| |
− | | |
− | <?xml version="1.0" encoding="utf-8"?>
| |
− | <executable>
| |
− | <category>filtering</category>
| |
− | <title>Anisotropic Diffusion</title>
| |
− | <description>
| |
− | Runs anisotropic diffusion on a volume
| |
− | </description>
| |
− | <version>1.0</version>
| |
− | <documentationurl></documentationurl>
| |
− | <license></license>
| |
− | <contributor>Bill Lorensen</contributor>
| |
− |
| |
− | <parameters>
| |
− | <label>
| |
− | Anisotropic Diffusion Parameters
| |
− | </label>
| |
− | <description>
| |
− | Parameters for the anisotropic
| |
− | diffusion algorithm
| |
− | </description>
| |
− |
| |
− | <double>
| |
− | <name>conductance</name>
| |
− | <longflag>conductance</longflag>
| |
− | <description>Conductance</description>
| |
− | <label>Conductance</label>
| |
− | <default>1</default>
| |
− | <constraints>
| |
− | <minimum>0</minimum>
| |
− | <maximum>10</maximum>
| |
− | <step>.01</step>
| |
− | </constraints>
| |
− | </double>
| |
− |
| |
− | <double>
| |
− | <name>timeStep</name>
| |
− | <longflag>timeStep</longflag>
| |
− | <description>Time Step</description>
| |
− | <label>Time Step</label>
| |
− | <default>0.0625</default>
| |
− | <constraints>
| |
− | <minimum>.001</minimum>
| |
− | <maximum>1</maximum>
| |
− | <step>.001</step>
| |
− | </constraints>
| |
− | </double>
| |
− |
| |
− | <integer>
| |
− | <name>numberOfIterations</name>
| |
− | <longflag>iterations</longflag>
| |
− | <description>Number of iterations</description>
| |
− | <label>Iterations</label>
| |
− | <default>1</default>
| |
− | <constraints>
| |
− | <minimum>1</minimum>
| |
− | <maximum>30</maximum>
| |
− | <step>1</step>
| |
− | </constraints>
| |
− | </integer>
| |
− |
| |
− | </parameters>
| |
− |
| |
− | <parameters>
| |
− | <label>IO</label>
| |
− | <description>Input/output parameters</description>
| |
− | <image>
| |
− | <name>inputVolume</name>
| |
− | <label>Input Volume</label>
| |
− | <channel>input</channel>
| |
− | <index>0</index>
| |
− | <description>Input volume to be filtered</description>
| |
− | </image>
| |
− | <image>
| |
− | <name>outputVolume</name>
| |
− | <label>Output Volume</label>
| |
− | <channel>output</channel>
| |
− | <index>1</index>
| |
− | <description>Output filtered</description>
| |
− | </image>
| |
− | </parameters>
| |
− |
| |
− | </executable>
| |
− | | |
− | == Command Line Parsing ==
| |
− | | |
− | The Slicer 3 Execution Model has support for parsing executable command lines. The C++ code to parse the command line arguments is generated automatically from the same XML description that generates the GUI. GenerateCLP, located in Slicer3/Libs/GenerateCLP reads the XML Module Description and creates an include file "Executable"CLP.h in the build tree. The executable includes this header file and accesses the code with the macro PARSE_ARGS.
| |
− | | |
− | GenerateCLP provides the following to the executable:
| |
− | | |
− | # A brief usage command if required arguments are missing
| |
− | # A full help command if -h or --help is specified on the command line
| |
− | # A copy of the xml description if --xml is specified on the command line
| |
− | # An echo of the command line parametrs and their values if --echo is specified
| |
− | | |
− | GenerateCLP provides the following source code:
| |
− | | |
− | # A C++ declaration of the proper type for each parameter assiging the default value if specified by the XML
| |
− | # For ''-vector'' parameters, a ''std::vector'' containing the proper C++ type fo the parameter. The generated code parses the comma separated strings to generate the ''std::vector''
| |
− | | |
− | === Using GenerateCLP ===
| |
− | | |
− | GenerateCLP is normally used via CMake where it is implemented as a CUSTOM_COMMAND. To use GenerateCLP from CMake include the following in your CMakeLists.txt file:
| |
− | | |
− | INCLUDE(${Slicer3_SOURCE_DIR}/Libs/GenerateCLP/UseGenerateCLP.cmake)
| |
− | | |
− | For each executable, include the following, replacing '''MyFilter''' with the name of your C++ source:
| |
− | | |
− | SET ( '''MyFilter'''_SOURCE '''MyFilter'''.cxx )
| |
− | GENERATECLP('''MyFilter'''_SOURCE '''MyFilter'''.xml)
| |
− | | |
− | To generate a stand-alone executable add the lines:
| |
− | | |
− | ADD_EXECUTABLE ( '''MyFilter''' ${'''MyFilter'''_SOURCE})
| |
− | TARGET_LINK_LIBRARIES ( '''MyFilter''' ITKIO ITKBasicFilters ITKCommon)
| |
− | | |
− | To generate a pluggable library add the lines:
| |
− | | |
− | ADD_LIBRARY('''MyFilter'''Lib SHARED ${'''MyFilter'''_SOURCE})
| |
− | SET_TARGET_PROPERTIES ('''MyFilter''' PROPERTIES COMPILE_FLAGS "-Dmain=SlicerModuleEntryPoint")
| |
− | TARGET_LINK_LIBRARIES ('''MyFilter'''Lib ITKIO ITKBasicFilters)
| |
− | | |
− | <br /> The ADD_EXECUTABLE target creates a stand-alone executable that can be run from a command line. The ADD_LIBRARY target creates a shared library that is discovered at Slicer 3 startup.
| |
− | | |
− | Although this example linked to ITK libraries, other libraries can be specified.
| |
− | | |
− | === Short Example ===
| |
− | | |
− | This example uses the XML for the [[Slicer3:Execution_Model_Documentation#Module_with_an_integer-vector.2C_one_input_image_and_one_output_image|Median Image Filter example]].
| |
− | | |
− | <nowiki>#include "MedianImageFilterCLP.h"
| |
− | int main (int argc, char * argv[])
| |
− | {
| |
− | PARSE_ARGS;
| |
− | std::cout << "The size of the neighborhood is: " << neighborhood.size()
| |
− | << " and the first element of the neighborhood is: " << neighborhood[0]
| |
− | << std::endl;
| |
− | std::cout << "The input volume is: " << inputVolume << std::endl;
| |
− | std::cout << "The output volume is: " << outputVolume << std::endl;
| |
− | return EXIT_SUCCESS;
| |
− | }
| |
− | </nowiki>
| |
− | | |
− | Here is the output --help:
| |
− | | |
− |
| |
− | USAGE:
| |
− |
| |
− | d:\lorensen\Projects\Slicer3-net\bin\RelWithDebInfo\MedianImageFilter.exe
| |
− | [--xml] [--echo] [--neighborhood
| |
− | <std::vector<int>>] [--]
| |
− | [--version] [-h] <std::string>
| |
− | <std::string>
| |
− |
| |
− |
| |
− | Where:
| |
− |
| |
− | --xml
| |
− | Produce xml description of command line arguments (default: 0)
| |
− |
| |
− | --echo
| |
− | Echo the command line arguments (default: 0)
| |
− |
| |
− | --neighborhood <std::vector<int>>
| |
− | The size of the neighborhood in each dimension (default: 1,1,1)
| |
− |
| |
− | --, --ignore_rest
| |
− | Ignores the rest of the labeled arguments following this flag.
| |
− |
| |
− | --version
| |
− | Displays version information and exits.
| |
− |
| |
− | -h, --help
| |
− | Displays usage information and exits.
| |
− |
| |
− | <std::string>
| |
− | (required) Input volume to be filtered
| |
− |
| |
− | <std::string>
| |
− | (required) Output filtered
| |
− |
| |
− |
| |
− | The MedianImageFilter is commonly used as a robust approach for noise
| |
− | reduction. This filter is particularly efficient against
| |
− | 'salt-and-pepper' noise. In other words, it is robust to the presence of
| |
− | gray-level outliers. MedianImageFilter computes the value of each output
| |
− | pixel as the statistical median of the neighborhood of values around the
| |
− | corresponding input pixel.
| |
− | | |
− | === Parameters and C++ code ===
| |
− | | |
− | This table shows how parameters are defined in the C++ code and how they are specified on the command line.
| |
− | | |
− | {| border="1"
| |
− | ! XML
| |
− | ! C++ Declaration
| |
− | ! Command Line
| |
− | |-
| |
− | |
| |
− | <integer><br /> <name>count</name><br /> <flag>c</flag> </integer>
| |
− | |
| |
− | int count;
| |
− | |
| |
− | ''prog'' -c 10
| |
− | |-
| |
− | |
| |
− | <float><br /> <name>stepSize</name><br /> <default>.0625</default><br /> <longflag>stepSize</longflag><br /> </float>
| |
− | |
| |
− | float stepSize=.0625;
| |
− | |
| |
− | ''prog'' --stepSize .003
| |
− | |-
| |
− | |
| |
− | <integer multiple="true"><br /> <name>iterations</name><br /> <flag>i</flag><br /> <default>100</default><br /> </integer>
| |
− | |
| |
− | std::vector<int> iterations;<br /> iterations.push_back(100);<br />
| |
− | |
| |
− | ''prog'' -i 20 -i 30 -i 100
| |
− | |-
| |
− | |
| |
− | <float-vector><br /> <name>variation</name><br /> <flag>v</flag><br /> <default>1,2,3</default><br /> </float-vector>
| |
− | |
| |
− | std::vector<float> variation; iterations.push_back(1);<br /> iterations.push_back(2);<br /> iterations.push_back(3);<br />
| |
− | |
| |
− | ''prog'' -v 10,20,3
| |
− | |-
| |
− | |
| |
− | <string-vector><br /> <name>sites</name><br /> <longflag>sites</longflag> </string-vector>
| |
− | |
| |
− | std::vector<std::string> sites;
| |
− | |
| |
− | ''prog'' --names BWH,GE,Kitware,UNC,MIT,UTAH,GT
| |
− | |-
| |
− | |
| |
− | <string-enumeration><br /> <name>leaders</name><br /> <default>Bill</default><br /> <element>Ron</element><br /> <element>Bill</element><br /> <element>Steve</element><br /> </string-enumeration>
| |
− | |
| |
− | std::string leaders = "Bill";
| |
− | |
| |
− | ''prog'' --leaders Ron
| |
− | |-
| |
− | |
| |
− | <boolean><br /> <name>debugSwitch</name><br /> <flag>d</flag> <default>true</default><br /> </boolean>
| |
− | |
| |
− | bool debugSwitch = false;
| |
− | |
| |
− | ''prog'' -d
| |
− | |-
| |
− | |
| |
− | <file><br /> <longflag>file1</longflag><br /> <file>
| |
− | |
| |
− | std::string file1;
| |
− | |
| |
− | ''prog'' --file1 mytext.txt
| |
− | |-
| |
− | |
| |
− | <image><br /> <name>image</name><br /> <index>0</index><br /> </image>
| |
− | |
| |
− | std::string image;
| |
− | |
| |
− | ''prog'' c:/lorensen/Data/ct.nrrd
| |
− | |-
| |
− | |
| |
− | <file multiple="true"><br /> <name>args</name><br /> <index>1</index><br /> </file>
| |
− | |
| |
− | std::vector<std::string> args;
| |
− | |
| |
− | ''prog'' --otherFlags file1 file2 ... filen
| |
− | |-
| |
− | |
| |
− | <point multiple="true" coordinateSystem="ras"><br /> <name>seed</name><br /> <longflag>--seed</longflag>
| |
− | |
| |
− | std::vector<std::vector<float> > seed;
| |
− | |
| |
− | ''prog'' --seed 10,100,23 --seed 5,240,17
| |
− | |}
| |
− | | |
− | == Error Handling ==
| |
− | | |
− | GenerateCLP attempts to do error checking so that the generated C++ code will compile. These errors will show up as custom command errors during the build process.
| |
− | | |
− | * XML Errors
| |
− | ** ''mismatched tag at line xx'' : The closing tag (a tag with </ >) does not have a matching opening tag.
| |
− | ** ''not well-formed (invalid token) at line xx'' : Probably a blank in the token name.
| |
− | * ModuleDescriptionParser Errors
| |
− | ** ''<executable> must be the outer most tag''
| |
− | ** ''<executable> was found inside another tag''
| |
− | ** ''<parameters> can only be inside <executable>''
| |
− | ** ''<xxx> can only be used inside <parameters>''
| |
− | ** ''<flag> can only contain one character''
| |
− | ** ''<longname> can only contain letters, numbers and underscores and must start with a _ or letter''
| |
− | ** ''<name> can only contain letters, numbers and underscores and must start with an _ or letter''
| |
− | | |
− | * ModuleDescriptionParser Warnings
| |
− | ** ''<xxx> is an unknown parameter tag'' : Probably a misspelled parameter type.
| |
− | | |
− | * Compiler Errors
| |
− | ** The generated C++ code may have syntax errors if invalid defaults are specified. These will show up during the C++ compilation.
| |
− | | |
− | == Interfacing Legacy Executables ==
| |
− | | |
− | GenerateCLP is only provided as a convenience. Users can use the same XML Module Description to interface C++, shell scripts, tcl programs and even Matlab!
| |
− | | |
− | * C++ Example
| |
− | * Tcl Example
| |
− | * Shell Script Example
| |
− | * Matlab Example
| |
− | * [[Slicer3:FiberTrackingIntegration|FiberTracking Integration Example]]
| |
− | | |
− | == Showing Progress in an Application ==
| |
− | | |
− | Programs can communicate progress to the user in two ways. If the program is running an a stand-alone executable, it communicates with a simple XML syntax. If the program is loaded at run-time as a plugin library, it communicates through a C structure.
| |
− | | |
− | The XML syntax is:
| |
− | | |
− | <filter-start>
| |
− | <filter-name>
| |
− | ''name of program section or algorithm''
| |
− | </filter-name>
| |
− | <filter-comment>
| |
− | ''description of program section or algrotihm''
| |
− | </filter-comment>
| |
− | </filter-start>
| |
− | | |
− | <filter-progress>
| |
− | ''floating number from 0 to 1''
| |
− | </filter-progress>
| |
− | | |
− | <filter-end>
| |
− | <filter-name>
| |
− | ''name of program section or algorithm''
| |
− | </filter-name>
| |
− | <filter-time>
| |
− | ''execution time''
| |
− | </filter-time>
| |
− | </filter-end>
| |
− | | |
− | The C structure that library plugins use is:
| |
− | | |
− | extern "C" {
| |
− | struct ModuleProcessInformation
| |
− | {
| |
− | /** Inputs from calling application to the module **/
| |
− | unsigned char Abort;
| |
− | /** Outputs from the module to the calling application **/
| |
− | float Progress;
| |
− | char ProgressMessage[1024];
| |
− | void (*ProgressCallbackFunction)(void *);
| |
− | void *ProgressCallbackClientData;
| |
− | double ElapsedTime;
| |
− | }
| |
− | }
| |
− | | |
− | Details on how to use this mechanism are illustrated in [http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FitkPluginFilterWatcher.h&rev=0&sc=0 itkPluginFilterWatcher.h].
| |
− | | |
− | For vtk and itk execution model programs, two classes are available that make it simple to add progress. The classes, ''vtkPluginFilterWatcher'' and ''itk::PluginFilterWatcher'' use the vtk and itk command/observer mechanism to report progress.
| |
− | | |
− | vtkPluginFilterWatcher (vtkAlgorithm *'''filter''', const char* '''comment''', ModuleProcessInformation *'''inf''', double '''fraction''', double '''start''') <br /> itk::PluginFilterWatcher (itk::ProcessObject '''filter''', const char* '''comment''', ModuleProcessInformation *'''inf''', double '''fraction''', double '''start''')
| |
− | | |
− | : where:
| |
− | ;; filter
| |
− | :: is the vtkAlgorithm or itk::ProcessObject to be watched.
| |
− | ;; comment
| |
− | :: is a string that describes the algorithm.
| |
− | ;; inf
| |
− | :: is an optional pointer to a structure that is used to communicate with the invoking program when the called program is used as a library plugin. If the pointer is 0, this prgram will not report progress if it is run as a library plugin. Default is 0.
| |
− | ;; fraction
| |
− | :: is the fraction (0-1) of progress that will be reported by this watcher. This is used when multiple filters are run and each filter represents a proportion of the total progress. Default is 1.
| |
− | ;; start
| |
− | :: is the offset (0-1) of the progress for this filter. This is added to the progress of the filter. The reported progress of the watched filter is ''start + fraction * filter_progress''.
| |
− | | |
− | <br /> The following example produces progress for a simple vtk program. The variable CLPProcessInformation is automatically declared and set in the program's ''program''CLP.h file.
| |
− | | |
− | <nowiki>#include "vtkPluginFilterWatcher.h"
| |
− | ...
| |
− | vtkMarchingCubes *cubes = vtkMarchingCubes::New();
| |
− | cubes->SetInput(reader->GetOutput());
| |
− | vtkPluginFilterWatcher watchCubes(cubes, "Generate Isosurface", CLPProcessInformation, .5, 0.0);
| |
− | vtkDecimatePro *decimate = vtkDecimatePro::New();
| |
− | decimate->SetInput(cubes->GetOutput());
| |
− | vtkPluginFilterWatcher watchDecimate(decimate, "Reduce Triangle Count", CLPProcessInformation, .5, 0.5);
| |
− | decimate->Update();
| |
− | </nowiki>
| |
− | | |
− | The following example produces progress for a simple itk program:
| |
− | | |
− | <nowiki>#include "itkPluginFilterWatcher.h
| |
− | ...
| |
− | typedef itk::MedianImageFilter<ImageType,ImageType> FilterType;
| |
− | FilterType::Pointer median = FilterType::New();
| |
− | itk::PluginFilterWatcher watchMedian(median, "Denoise Image", CLPProcessInformation);
| |
− | </nowiki>
| |
− | | |
− | == Using GenerateCLP Outside of Slicer3 ==
| |
− | | |
− | GenerateCLP can be built and used outside of the Slicer3 tree.
| |
− | | |
− | # First checkout the required directories from the Slicer3 repository.
| |
− | ## svn co http://www.na-mic.org:8000/svn/Slicer3/trunk/Libs/tclap
| |
− | ## svn co http://www.na-mic.org:8000/svn/Slicer3/trunk/Libs/ModuleDescriptionParser
| |
− | ## svn co http://www.na-mic.org:8000/svn/Slicer3/trunk/Libs/GenerateCLP
| |
− | # Run cmake on tclap
| |
− | # Run cmake on ModuleDescriptionParser
| |
− | # make ModuleDescriptionParser
| |
− | # Run cmake on GenerateCLP
| |
− | # make GenerateCLP
| |
− | | |
− | To use '''GenerateCLP''' from CMake include the following in your ''CMakeLists.txt'' file:
| |
− | | |
− | FIND_PACKAGE(GenerateCLP REQUIRED)
| |
− | INCLUDE(${GenerateCLP_SOURCE_DIR}/UseGenerateCLP.cmake)
| |
− | | |
− | To use '''GenerateCLP''' with an itk program, add the following to the ''CMakeLists.txt'' file for your project:
| |
− | | |
− | SET ( '''MyFilter'''_SOURCE '''MyFilter'''.cxx )
| |
− | GENERATECLP('''MyFilter'''_SOURCE '''MyFilter'''.xml)
| |
− | ADD_EXECUTABLE ( '''MyFilter''' ${'''MyFilter'''_SOURCE})
| |
− | TARGET_LINK_LIBRARIES ( '''MyFilter''' ITKIO ITKBasicFilters ITKCommon)
| |
− | | |
− | To use '''GenerateCLP''' with a vtk program, add the following to the ''CMakeLists.txt'' file for your project:
| |
− | | |
− | SET ( '''MyFilter'''_SOURCE '''MyFilter'''.cxx )
| |
− | GENERATECLP('''MyFilter'''_SOURCE '''MyFilter'''.xml)
| |
− | LINK_DIRECTORIES(${vtkITK_LIB_DIR})
| |
− | ADD_EXECUTABLE ( '''MyFilter''' ${'''MyFilter'''_SOURCE})
| |
− | TARGET_LINK_LIBRARIES ( '''MyFilter''' vtkITK vtkImaging vtkGraphics vtkIO)
| |
− | INCLUDE_DIRECTORIES(${vtkITK_SOURCE_DIR} ${vtkITK_BINARY_DIR})
| |
− | | |
− | <br />'''Windows Users Please Note:''' All packages that you use '''MUST''' be built with the same build type (Debug, Release or RelWithDebInfo).
| |
− | | |
− | == Accessing Module Information at Runtime ==
| |
− | | |
− | All of the information contained in the XML description of a module can be accessed at run-time by the command line program. The ''ModuleDescriptionParser'' class library can parse an XML module description and populate a ''ModuleDescription'' instance.
| |
− | <pre>
| |
− | // Module Description Parser Class Library
| |
− | #include "ModuleDescriptionParser.h"
| |
− | #include "ModuleDescription.h"
| |
− | #include "ModuleParameterGroup.h"
| |
− | #include "ModuleParameter.h"
| |
− | .
| |
− | .
| |
− | .
| |
− | // Create a module and a parser
| |
− | ModuleDescription module;
| |
− | ModuleDescriptionParser parser;
| |
− | // Parse the XML
| |
− | if (parser.Parse(GetXMLModuleDescription(), module))
| |
− | {
| |
− | std::cerr << argv[0] << ": One or more XML errors detected." << std::endl;
| |
− | return EXIT_FAILURE;
| |
− | }
| |
− | // Access the module description information
| |
− | std::cout << "Module Description Information" << std::endl;
| |
− | std::cout << "\tCategory is: " << module.GetCategory() << std::endl;
| |
− | std::cout << "\tTitle is: " << module.GetTitle() << std::endl;
| |
− | std::cout << "\tDescription is: " << module.GetDescription() << std::endl;
| |
− | std::cout << "\tVersion is: " << module.GetVersion() << std::endl;
| |
− | std::cout << "\tDocumentationURL is: " << module.GetDocumentationURL() << std::endl;
| |
− | std::cout << "\tLicense is: " << module.GetLicense() << std::endl;
| |
− | std::cout << "\tContributor is: " << module.GetContributor() << std::endl;
| |
− | </pre>
| |
− | | |
− | ''GetXMLModuleDescription'' is automatically generated by ''GenerateCLP''. Information about parameter groups and parametrs is also available.
| |
− | | |
− | The ''CMakeLists.txt'' file that creates the command line module should point to the ''ModuleDescriptionParser'' library.
| |
− | <pre>
| |
− | TARGET_LINK_LIBRARIES (${CLP}
| |
− | ModuleDescriptionParser
| |
− | )
| |
− | </pre>
| |
− | | |
− | == Building the Slicer3 Command Line Programs Outside of Slicer3 ==
| |
− | | |
− | The command line programs developed for Slicer3 can be built without building Slicer3.
| |
− | | |
− | # First follow the directions in [[Slicer3:Execution_Model_Documentation#Using_GenerateCLP_Outside_of_Slicer3|Using GenerateCLP Outside of Slicer3]]
| |
− | # Checkout the Slicer3 command line programs
| |
− | ## svn co http://www.na-mic.org:8000/svn/Slicer3/trunk/Applications/CLI
| |
− | # Some of the programs in CLI rely on vtkITK. If you will e using these command line programs, then checkout vtkITK.
| |
− | ## svn co http://www.na-mic.org:8000/svn/Slicer3/trunk/Libs/vtkITK
| |
− | ## Run cmake on vtkITK.
| |
− | # Run cmake on CLI.
| |
− | | |
− | CMake may ask you to locate the builds for packages that the CLI programs use.
| |
− | | |
− | '''Windows Users Please Note:''' All packages that you use '''MUST''' be built with the same build type (Debug, Release or RelWithDebInfo).
| |
− | | |
− | == Useful Examples ==
| |
− | | |
− | Slicer3 contains a growing list of command line programs. These reside in the [http://www.na-mic.org:8000/websvn/listing.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2F&rev=0&sc=0 Slicer3/Applications/CLI]directory. As with all command line programs, these can be run from the Slicer3 GUI or as independent executables. The command line programs fall into two general categories:
| |
− | | |
− | # ''Read/Single Filter/Write'' - These programs provide useful, single function operations. Examples include:
| |
− | ## [http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FCheckerBoard.cxx&rev=0&sc=0 CheckerBoard] ([http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FCheckerBoard.xml&rev=0&sc=0 xml]) - combines two volumes into a single volume with alternating images from each volume.
| |
− | ## [http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FGradientAnisotropicDiffusion.cxx&rev=0&sc=0 Gradient Anisotropic Diffusion] ([http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FGradientAnisotropicDiffusion.xml&rev=0&sc=0 xml]) - classic Perona-Malik, gradient magnitude based equation
| |
− | ## [http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FGrayscaleFillHoleImageFilter.cxx&rev=0&sc=0 Grayscale Fill Hole] ([http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FGrayscaleFillHoleImageFilter.xml&rev=0&sc=0 xml]) - smooth over local minima without affecting the values of local maxima.
| |
− | ## [http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FGrayscaleGrindPeakImageFilter.cxx&rev=0&sc=0 Grayscale Grind Peak] ([http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FGrayscaleGrindPeakImageFilter.xml&rev=0&sc=0 xml]) - smooth over local maxima without affecting the values of local minima.
| |
− | ## [http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FMedianImageFilter.cxx&rev=0&sc=0 Median Image Filter] ([http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FMedianImageFilter.xml&rev=0&sc=0 xml]) - classic non-linear median filter. This program is a modification of the Insight Example [http://www.itk.org/cgi-bin/viewcvs.cgi/Examples/Filtering/MedianImageFilter.cxx?rev=1.24&root=Insight&view=markup Median Image Filter].
| |
− | ## [http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FOtsuThresholdImageFilter.cxx&rev=0&sc=0 Otsu Threshold] ([http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FOtsuThresholdImageFilter.xml&rev=0&sc=0 xml]) - creates a binary thresholded image that separates an image into foreground and background components. This program is a modification of the Insight Example [http://www.itk.org/cgi-bin/viewcvs.cgi/Examples/Filtering/OtsuThresholdImageFilter.cxx?root=Insight&view=markup OtsuThresholdImageFilter].
| |
− | ## [http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FVotingBinaryHoleFillingImageFilter.cxx&rev=0&sc=0 Voting Binary Hole Filling] ([http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FVotingBinaryHoleFillingImageFilter.xml&rev=0&sc=0 xml]) - fills in holes and cavities by applying a voting operation on each pixel.
| |
− | ## [http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FResampleVolume.cxx&rev=0&sc=0 Resample Volume] ([http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FResampleVolume.cxx&rev=0&sc=0 xml]) - resample a volume.
| |
− | # ''Read/Multiple Filters/Write'' - These programs package a number of filters to accomplish a higher level task.
| |
− | ## [http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FModelMaker.cxx&rev=0&sc=0 Model Maker]([http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FModelMaker.xml&rev=0&sc=0 xml]) - creates polygonal models from segmented volumes. This program uses vtk filters to creae isosurfaces, decimate and smooth them.
| |
− | ## [http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FImageReadDicomWrite.cxx&rev=0&sc=0 Image Read DICOM Write] ([http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FImageReadDicomWrite.xml&rev=0&sc=0 xml]) - creates a DICOM series from a 3D volume.
| |
− | ## [http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FOtsuThresholdSegmentation.cxx&rev=0&sc=0 Otsu Threshold Segmentation] ([http://www.na-mic.org:8000/websvn/filedetails.php?repname=Slicer3&path=%2Ftrunk%2FApplications%2FCLI%2FOtsuThresholdSegmentation.xml&rev=0&sc=0 xml]) - finds a threshold to separate foreground and background, then runs a connected component algorithm and produces a segmented volume with independent components.
| |
− | | |
− | === Runtime specification of filter types ===
| |
− | | |
− | ITK filters are templated over the images they process. The following code snippet shows how an execution model program can select the image types for filters based on the input images.
| |
− | | |
− | First, include the utilites for plugin's:
| |
− | <pre>
| |
− | #include "itkPluginUtilities.h"
| |
− | </pre>
| |
− | | |
− | Then, turn your main program into a templated procedure called ''DoIt'':
| |
− | <pre>
| |
− | template<class T> int DoIt( int argc, char * argv[], T )
| |
− | {
| |
− | PARSE_ARGS;
| |
− | | |
− | typedef itk::Image< T, 3 > InputImageType;
| |
− | typedef itk::Image< T, 3 > OutputImageType;
| |
− | .
| |
− | .
| |
− | .
| |
− | }
| |
− | </pre>
| |
− | Then, create a main program that gets the native component type from one of the input file. Here that input file is ''inputVolume'':
| |
− | <pre>
| |
− | int main( int argc, char * argv[] )
| |
− | {
| |
− |
| |
− | PARSE_ARGS;
| |
− | | |
− | itk::ImageIOBase::IOPixelType pixelType;
| |
− | itk::ImageIOBase::IOComponentType componentType;
| |
− | | |
− | try
| |
− | {
| |
− | itk::GetImageType (inputVolume, pixelType, componentType);
| |
− | | |
− | // This filter handles all types
| |
− |
| |
− | switch (componentType)
| |
− | {
| |
− | case itk::ImageIOBase::UCHAR:
| |
− | return DoIt( argc, argv, static_cast<unsigned char>(0));
| |
− | break;
| |
− | case itk::ImageIOBase::CHAR:
| |
− | return DoIt( argc, argv, static_cast<char>(0));
| |
− | break;
| |
− | case itk::ImageIOBase::USHORT:
| |
− | return DoIt( argc, argv, static_cast<unsigned short>(0));
| |
− | break;
| |
− | case itk::ImageIOBase::SHORT:
| |
− | return DoIt( argc, argv, static_cast<short>(0));
| |
− | break;
| |
− | case itk::ImageIOBase::UINT:
| |
− | return DoIt( argc, argv, static_cast<unsigned int>(0));
| |
− | break;
| |
− | case itk::ImageIOBase::INT:
| |
− | return DoIt( argc, argv, static_cast<int>(0));
| |
− | break;
| |
− | case itk::ImageIOBase::ULONG:
| |
− | return DoIt( argc, argv, static_cast<unsigned long>(0));
| |
− | break;
| |
− | case itk::ImageIOBase::LONG:
| |
− | return DoIt( argc, argv, static_cast<long>(0));
| |
− | break;
| |
− | case itk::ImageIOBase::FLOAT:
| |
− | return DoIt( argc, argv, static_cast<float>(0));
| |
− | break;
| |
− | case itk::ImageIOBase::DOUBLE:
| |
− | return DoIt( argc, argv, static_cast<double>(0));
| |
− | break;
| |
− | case itk::ImageIOBase::UNKNOWNCOMPONENTTYPE:
| |
− | default:
| |
− | std::cout << "unknown component type" << std::endl;
| |
− | break;
| |
− | }
| |
− | }
| |
− | catch( itk::ExceptionObject &excep)
| |
− | {
| |
− | std::cerr << argv[0] << ": exception caught !" << std::endl;
| |
− | std::cerr << excep << std::endl;
| |
− | return EXIT_FAILURE;
| |
− | }
| |
− | return EXIT_SUCCESS;
| |
− | }
| |
− | | |
− | </pre>
| |
− | | |
− | == Behind the Scenes ==
| |
− | | |
− | A primary goal of the execution model is to relieve developers from developing GUI code and command line parsing code. This section descibes the major components of the execution model implementation.
| |
− | | |
− | === Command Line Processing ===
| |
− | | |
− | Command line processing parses command line arguments and populates internal program variables. Every Unix (and windows) program can receive an argument list through its main entry point. All C and C++ programmers are familiar with the ''int main (int argc, char *[] argv)'' entry point in their programs. Most computer languages including scripting languages provide a similar mechanism to retrieve command line arguments. Simple command line processing directly accesses the strings defined in argv.
| |
− | | |
− | This snippet shows simple commmand line processing:
| |
− | | |
− | int main (int argc, char *argv[]) | |
− | {
| |
− | if (argc < 2)
| |
− | {
| |
− | std::cout << "Usage: " << argv[0] << " filename" << std::endl;
| |
− | return -1;
| |
− | }
| |
− | std::cout << "The File is " << argv[1] << std::endl;
| |
− | return 0;
| |
− | }
| |
− | | |
− | The simple approach works great for a small number of arguments. But larger numbers of arguments of varying types quickly make the processing code more complex and subject to error, both in coding and usage.
| |
− | | |
− | int main (int argc, char *argv[])
| |
− | {
| |
− | if (argc < 5)
| |
− | {
| |
− | std::cout << "Usage: " << argv[0] << " iterations epsilon inputfile outputfile " << std::endl;
| |
− | return -1;
| |
− | }
| |
− | std::string inputfile(argv[3]);
| |
− | std::string outputfile(argv[4]);
| |
− | unsigned int iterations = atoi(argv[1]);
| |
− | float epsilon = atof(argv[2]);
| |
− | ...
| |
− | return 0;
| |
− | }
| |
− | | |
− | Adding flags (or options) to the command line makes the program easier to use but places a larger burden on the program developer. Each developer must ''invent'' a command line argument syntax and implement code to parse the command line. Even a simple example of this is too long to include in this description. This code snippet looks for just two command line arguments.
| |
− | | |
− | int main (int argc, char *argv[])
| |
− | {
| |
− | if (argc < 3)
| |
− | {
| |
− | std::cout << "Usage: " << argv[0] << " [-i iterations] [-e epsilon] inputfile outputfile " << std::endl;
| |
− | return -1;
| |
− | }
| |
− | std::string inputfile;
| |
− | std::string outputfile;
| |
− | unsigned int iterations = 10; /* a default */
| |
− | float epsilon = .001; /* a defualt */
| |
− | ++argc; /* skip program name */
| |
− | while (argc > 0)
| |
− | {
| |
− | if (strcmp(argv[argc], "-i")
| |
− | {
| |
− | iterations = atoi(argv[argc+1]);
| |
− | argc+=2;
| |
− | continue;
| |
− |
| |
− | else if (strcmp(argv[argc], "-e")
| |
− | {
| |
− | epsilon = atof(argv[argc+1]);
| |
− | argc+=2;
| |
− | continue;
| |
− | ...
| |
− | }
| |
− | | |
− | The code gets longer and longer as more options are added and must be rewritten every time a new programs is open.
| |
− | | |
− | To solve this complexity issue, people have developed command line argument libraries. There are dozens, if not hundreds, of command line processing tools. For Slicer3 we looked at argument processors in vxl, nrrd, meta, kwsys and tclap. Each has its strengths and weaknesses. We chose [http://tclap.sourceforge.net/ The Templatized C++ Command Line Parser Library], '''TCLAP'''. '''TCLAP''' is implemented in ''include'' files and does not require a separate library build. As you will see later, the particular command line processing tool is, for the most part, transparent to the Slicer3 developer or user.
| |
− | | |
− | But even these libraries require some work to use.
| |
− | | |
− | ==== TCLAP ====
| |
− | | |
− | This example uses '''TCLAP''' to process a command line with 10 possible entries:
| |
− | | |
− | int main ( int argc, char* argv[] ) {
| |
− | //
| |
− | // Define default values
| |
− | int HistogramBins = 30;
| |
− | int RandomSeed = 1234567;
| |
− | int SpatialSamples = 10000;
| |
− | float TranslationScale = 100.0;
| |
− | int Iterations = 200;
| |
− | int SplineOrder = 3;
| |
− | double MinimumStepSize = 0.00001;
| |
− | double MaximumStepSize = 0.005;
| |
− | bool PrintTransform = false;
| |
− | string fixedImageFileName;
| |
− | string movingImageFileName;
| |
− | string resampledImageFileName;
| |
− | //
| |
− | // Setup command line parsing
| |
− | try
| |
− | {
| |
− | TCLAP::CmdLine cl ( "Register2d", ' ', "$Revision: 1.1 $" );
| |
− | TCLAP::ValueArg<int> HistogramBinsArg ( "b", "histogrambins", "Number of histogram bins", false, 30, "integer", cl );
| |
− | TCLAP::ValueArg<int> IterationsArg ( "i", "iterations", "Number of Iterations", false, Iterations, "int", cl );
| |
− | TCLAP::ValueArg<double> MinimumStepSizeArg ( "m", "minstepsize", "Minimum Step Size", false, MinimumStepSize, "double", cl );
| |
− | TCLAP::ValueArg<double> MaximumStepSizeArg ( "x", "maxstepsize", "Maximum Step Size", false, MaximumStepSize, "double", cl );
| |
− | TCLAP::ValueArg<int> RandomSeedArg ( "r", "randomseed", "Random Seed", false, RandomSeed, "int", cl );
| |
− | TCLAP::ValueArg<int> SpatialSamplesArg ( "s", "spatialsamples", "Number of spatial samples", false, SpatialSamples, "int", cl );
| |
− | TCLAP::ValueArg<int> SplineOrderArg ( "o", "splineorder", "Order of spline for registration", false, SplineOrder, "int", cl );
| |
− | TCLAP::SwitchArg PrintTransformArg ( "p", "printtransform", "Print the final transform", PrintTransform, cl );
| |
− | TCLAP::ValueArg<float> TranslationScaleArg ( "t", "translationscale", "Translation scale", false, TranslationScale, "float", cl );
| |
− | TCLAP::UnlabeledValueArg<string> FixedImageArg ( "fixed", "Fixed image filename", "", "string", cl );
| |
− | TCLAP::UnlabeledValueArg<string> MovingImageArg ( "moving", "Moving image filename", "", "string", cl );
| |
− | TCLAP::UnlabeledValueArg<string> ResampledImageArg ( "resampled", "Resampled image filename", "", "string", cl );
| |
− | //
| |
− | // Parse the command line
| |
− | cl.parse ( argc, argv );
| |
− | //
| |
− | // Access the variables
| |
− | HistogramBins = HistogramBinsArg.getValue();
| |
− | Iterations = IterationsArg.getValue();
| |
− | MinimumStepSize = MinimumStepSizeArg.getValue();
| |
− | MaximumStepSize = MaximumStepSizeArg.getValue();
| |
− | RandomSeed = RandomSeedArg.getValue();
| |
− | SpatialSamples = SpatialSamplesArg.getValue();
| |
− | TranslationScale = TranslationScaleArg.getValue();
| |
− | PrintTransform = PrintTransformArg.getValue();
| |
− | fixedImageFileName = FixedImageArg.getValue();
| |
− | movingImageFileName = MovingImageArg.getValue();
| |
− | resampledImageFileName = ResampledImageArg.getValue();
| |
− | }
| |
− | catch ( ArgException e )
| |
− | {
| |
− | cerr << "error: " << e.error() << " for arg " << e.argId() << endl;
| |
− | exit ( EXIT_FAILURE );
| |
− | }
| |
− | | |
− | You do get a lot for your investment here. Good error handling and help.
| |
− | | |
− | === Module Description Parser ===
| |
− | The XML parsing is done by the ''ModuleDescriptionParser'' class library located in ''Slicer3/Libs/ModuleDescriptionParser''. ''GenerateCLP'' and Slicer3 use this class library to parse the module XML descriptions. The class ''ModuleDescrptionParser'' has one method, '''Parse''', that converts the XML description into an object model. The resulting object model has one ''ModuleDescription'', one or more ''ModuleParameterGroup'' each of which has one or more ''ModuleParameter''. Each instance has access methods to retrieve information from the XML.
| |
− | * '''ModuleDescriptionParser''' - parser for command line module XML description.
| |
− | *: ''Parse(std::string xml, ModuleDescription module)'' - parse an xml string and populate a ModuleDescription.
| |
− | * '''ModuleDescription''' - contains information about a module
| |
− | *: const std::string ''GetCategory()'' : returns the contents of '''<category>'''.
| |
− | *: const std::string ''GetTitle()'' : returns the contents of '''<title>'''.
| |
− | *: const std::string ''GetDescription()'' : returns the contents of '''<description>'''.
| |
− | *: const std::string ''GetVersion()'' : returns the contents of '''<version>'''.
| |
− | *: const std::string ''GetDocumentationURL()'' : returns the contents of '''<documentationURL>'''.
| |
− | *: const std::string ''GetLicense()'' : returns the contents of '''<license>'''.
| |
− | *: const std::string ''GetContributor()'' : returns the contents of '''<contributor>'''.
| |
− | *: const std::vector<ModuleParameterGroup>& ''GetParameterGroups()'' : returns a vector of parameter groups.
| |
− | * '''ModuleParameterGroup''' - contains ModuleParameters for each parameter group.
| |
− | *: const std::string ''GetLabel'' - returns the contents of '''<label>'''.
| |
− | *: const std::string ''GetDescription()'' - returns the contents of the parameter group's '''<description>'''.
| |
− | *: const std::string ''GetAdvanced()'' - returns advanced attribute. Either "true" of "false".
| |
− | * '''ModuleParameter''' - contains information for a parameter.
| |
− | *:GetTag() - returns the paarameter's tag, e.g. '''<integer>, <image>''', etc.
| |
− | *:GetName() - returns the parameter's '''<name>'''.
| |
− | *:GetLongFlag() - returns the parameter's '''<longflag>'''.
| |
− | *:GetLabel() - returns the parameter's '''<label>'''.
| |
− | *:GetMaximum() - returns the parameter's '''<maximum>''' constraint.
| |
− | *:GetMinimum() - returns the parameter's '''<minimum>''' constraint.
| |
− | *:GetStep() - returns the parameter's '''<step>'''.
| |
− | *:GetDescription() - returns the parameter's '''<description>'''.
| |
− | *:GetChannel() - returns the parameter's '''<channel>'''.
| |
− | *:GetIndex() - returns the parameter's '''<index>'''.
| |
− | *:GetDefault() - returns the parameter's '''<default>'''.
| |
− | *:GetFlag() - returns the parameter's '''<flag>'''.
| |
− | *:GetMultiple() - returns the parameter's multiple attribute, either "true" or "false".
| |
− | *:GetCoordinateSystem() - returns the parameter's coordinate system attribute, one of "lps", "ras", or "ijk".
| |