SimpleITK/Advisory Review Board/Prototype Code Discussions: Difference between revisions
From KitwarePublic
Jump to navigationJump to search
m (moved ITK/Release 4/SimpleITK/Advisory Review Board/Prototype Code Discussions to SimpleITK/Advisory Review Board/Prototype Code Discussions) |
|||
(11 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
== General Design Questions == | == General Design Questions == | ||
==== Procedural -vs- Pipelined ==== | |||
* The '''procedural''' model sees each filter as an independent function that takes a set of inputs and produces an output. | |||
** Could either be purely functional (static functions, no need to instantiate a filter) or set up with blocks of code for each filter | |||
** Generally easier to learn than the pipelined model (similar to Matlab's style) | |||
* The '''pipelined''' model sees each filter as a step along an algorithm pipeline that can take the output of a previous filter, modify it, and pass it off to the next filter in line. | |||
** Largely a mirror of the current ITK implementation with the templates hidden | |||
** Can be used to stream large images | |||
==== Enums -vs- Parameter methods ==== | |||
* This refers to the convention for setting filter parameters | |||
* '''enums''' => filter.SetParameter("name", val); | |||
** Single method or a set of type specific methods used throughout toolkit | |||
* '''parameter methods''' => filter.Set''Name''(val); | |||
** This is how it's currently done in ITK | |||
==== Registration granularity ==== | |||
* Should transform, metric, optimizer, interpolation be modular like in ITK? | |||
== Gaussian Blur == | ==== Streaming ==== | ||
* An open question is how Filter Blocks / Procedural paradigm might support streaming. Based on Jim Miller's suggestion, we could build machinery to stream blocks through a list of filters. This assumes the readers and writers support random access to images on disk. | |||
== Simple Examples == | |||
=== Gaussian Blur === | |||
* Open an image | * Open an image | ||
* Filter the image with a Gaussian blur using sigma = 2 | * Filter the image with a Gaussian blur using sigma = 2 | ||
Line 34: | Line 39: | ||
<pre style="display: inline-block;"> | <pre style="display: inline-block;"> | ||
// Read the image | // Read the image | ||
Image::Pointer im = ImageFileReader | Image::Pointer im = ImageFileReader ("sample/path/to/image.jpg"); | ||
// Apply Gaussian with sigma = 2 | // Apply Gaussian with sigma = 2 | ||
im = GaussianFilter | im = GaussianFilter (im, 2); | ||
// Write out the image | // Write out the image | ||
ImageFileWriter | ImageFileWriter (im, "sample/path/to/output.png"); | ||
</pre> | </pre> | ||
Line 46: | Line 51: | ||
<pre style="display: inline-block;"> | <pre style="display: inline-block;"> | ||
// Read the image | // Read the image | ||
Image::Pointer im = ImageFileReader | Image::Pointer im = ImageFileReader ("sample/path/to/image.jpg"); | ||
// Apply Gaussian with sigma = 2 | // Apply Gaussian with sigma = 2 | ||
im = GaussianFilter | im = GaussianFilter (im, 2); | ||
// Write out the image | // Write out the image | ||
ImageFileWriter | ImageFileWriter ("sample/path/to/output.png", im); | ||
</pre> | </pre> | ||
Line 72: | Line 77: | ||
ImageFileReader reader; | ImageFileReader reader; | ||
reader.SetFilename( "sample/path/to/image.jpg" ); | reader.SetFilename( "sample/path/to/image.jpg" ); | ||
Image::Pointer im = reader. | Image::Pointer im = reader.Execute(); | ||
// Anonymous reader object | |||
Image::Pointer im = ImageFileReader().SetFilename ( "path/image.nrrd" ).Execute(); | |||
// Apply Gaussian with sigma = 2 | // Apply Gaussian with sigma = 2 | ||
Gaussian filter; | Gaussian filter; | ||
filter.SetSigma( 2 ); | filter.SetSigma( 2 ); | ||
im = filter. | im = filter.Execute( im ); | ||
// Write out the image | // Write out the image | ||
ImageFileWriter writer; | ImageFileWriter writer; | ||
writer.SetFilename( "sample/path/to/output.png" ); | writer.SetFilename( "sample/path/to/output.png" ); | ||
writer. | writer.Execute( im ); | ||
</pre> | </pre> | ||
Line 133: | Line 142: | ||
</pre> | </pre> | ||
== Image Registration == | === Image Registration === | ||
* Open two images (one fixed, one moving) | * Open two images (one fixed, one moving) | ||
* Register the moving image to the fixed image using affine registration | * Register the moving image to the fixed image using affine registration | ||
Line 271: | Line 280: | ||
</pre> | </pre> | ||
==== | ==== Strategy pattern ==== | ||
[http://en.wikipedia.org/wiki/Strategy_pattern http://en.wikipedia.org/wiki/Strategy_pattern] | |||
* Notes: | * Notes: | ||
** 2 independent issues here ( | ** 2 independent issues here (strategy and parameter access) | ||
** Uses enums for parameter setting so all parameter setting is done through an X.SetParameter[TYPE]("name", val) function | ** Uses enums for parameter setting so all parameter setting is done through an X.SetParameter[TYPE]("name", val) function | ||
** Maintains registration granularity so that transform, interpolator, optimizer, and metric can be interchanged | ** Maintains registration granularity so that transform, interpolator, optimizer, and metric can be interchanged | ||
Line 312: | Line 322: | ||
</pre> | </pre> | ||
== Level Set == | === Level Set === | ||
== Region Growing == | === Region Growing === | ||
* Open an image | * Open an image | ||
* Set up a set of seed points | * Set up a set of seed points | ||
Line 348: | Line 358: | ||
</pre> | </pre> | ||
=====Jim's recommendation===== | |||
<pre style="display: inline-block;"> | |||
// Open an image | |||
Image::Pointer im = ImageFileReader::Read("sample/path/to/image.jpg"); | |||
// Set up seeds | |||
std::vector<Point> points; | |||
Point p1, p2; | |||
p1[0] = 25; | |||
p1[1] = 25; | |||
p2[0] = 35; | |||
p2[1] = 5; | |||
points.push_back(p1); | |||
points.push_back(p2); | |||
// Run the region growing algorithm | |||
seg = RegionGrowingConnectedThresholdFilter::Filter(im, points, 128, 200); // Segment()? | |||
// Write out the resulting segmentation | |||
ImageFileWriter::Write( "sample/path/to/output.png", seg); | |||
</pre> | |||
==== Pipieline ==== | ==== Pipieline ==== | ||
Line 388: | Line 419: | ||
</pre> | </pre> | ||
== Watershed == | === Watershed === | ||
=== QuadEdgeMesh === | |||
== User Domain Examples == | |||
This section provides a set of examples for simple applications from a number of target user groups. The goal is to present the ARB with targeted examples that show non-trivial applications specific to each target community. | |||
=== Microscopy === | |||
=== Orfeo Toolbox === | |||
== | === Education === |
Latest revision as of 17:51, 13 February 2013
General Design Questions
Procedural -vs- Pipelined
- The procedural model sees each filter as an independent function that takes a set of inputs and produces an output.
- Could either be purely functional (static functions, no need to instantiate a filter) or set up with blocks of code for each filter
- Generally easier to learn than the pipelined model (similar to Matlab's style)
- The pipelined model sees each filter as a step along an algorithm pipeline that can take the output of a previous filter, modify it, and pass it off to the next filter in line.
- Largely a mirror of the current ITK implementation with the templates hidden
- Can be used to stream large images
Enums -vs- Parameter methods
- This refers to the convention for setting filter parameters
- enums => filter.SetParameter("name", val);
- Single method or a set of type specific methods used throughout toolkit
- parameter methods => filter.SetName(val);
- This is how it's currently done in ITK
Registration granularity
- Should transform, metric, optimizer, interpolation be modular like in ITK?
Streaming
- An open question is how Filter Blocks / Procedural paradigm might support streaming. Based on Jim Miller's suggestion, we could build machinery to stream blocks through a list of filters. This assumes the readers and writers support random access to images on disk.
Simple Examples
Gaussian Blur
- Open an image
- Filter the image with a Gaussian blur using sigma = 2
- Write the image back out
Procedural
- Pros:
- Fewest lines of code to get a job done
- Easy to learn/use ("Matlab-like")
- Cons:
- Biggest diversion from traditional ITK style
- Potentially long list of parameters for a given function
// Read the image Image::Pointer im = ImageFileReader ("sample/path/to/image.jpg"); // Apply Gaussian with sigma = 2 im = GaussianFilter (im, 2); // Write out the image ImageFileWriter (im, "sample/path/to/output.png");
Jim's recommendation
// Read the image Image::Pointer im = ImageFileReader ("sample/path/to/image.jpg"); // Apply Gaussian with sigma = 2 im = GaussianFilter (im, 2); // Write out the image ImageFileWriter ("sample/path/to/output.png", im);
Filter Blocks
- Pros:
- Each filter processes an image directly
- Default parameters make provide good guess for algorithm prototyping
- Parameters can be changed individually as needed
- Cons:
- Image is fully processed between each filter (No easy streaming implementation)
- Other Notes:
- No pipeline
- Uses object-oriented paradigm so filters must be instantiated
// Read the image ImageFileReader reader; reader.SetFilename( "sample/path/to/image.jpg" ); Image::Pointer im = reader.Execute(); // Anonymous reader object Image::Pointer im = ImageFileReader().SetFilename ( "path/image.nrrd" ).Execute(); // Apply Gaussian with sigma = 2 Gaussian filter; filter.SetSigma( 2 ); im = filter.Execute( im ); // Write out the image ImageFileWriter writer; writer.SetFilename( "sample/path/to/output.png" ); writer.Execute( im );
Jim's recommendation
// Read the image ImageFileReader reader; reader.SetFilename( "sample/path/to/image.jpg" ); Image::Pointer im = reader.Read(); // Apply Gaussian with sigma = 2 Gaussian filter; filter.SetSigma( 2 ); im = filter.Filter( im ); // Write out the image ImageFileWriter writer; writer.SetFilename( "sample/path/to/output.png" ); writer.Write( im );
Pipelined
- Pros:
- Can easily implement streaming for large images
- Default parameter list is good for prototyping
- Can set individual parameters as needed
- Cons:
- Pipeline paradigm may be steeper on-ramp for new users
- Other Notes:
- Closest to full ITK implementation with templates removed
// Read the image ImageFileReader reader; reader.SetFilename( "sample/path/to/image.jpg" ); // Apply Gaussian with sigma = 2 Gaussian filter; filter.SetSigma( 2 ); filter.SetInput( reader.getOutput() ); // Write out the image ImageFileWriter writer; writer.SetFilename( "sample/path/to/output.png" ); writer.SetInput( filter->GetOutput() ); // Execute the pipieline writer.Update();
Image Registration
- Open two images (one fixed, one moving)
- Register the moving image to the fixed image using affine registration
- Resample the moving image using the computed transform
- Write the resampled image out
Procedural
- Pros:
- Fewest lines of code
- Cons:
- Long argument lists for functions
- Not easily extensible w.r.t. transform type, optimization type, interpolation type, etc...
- Other Notees:
- Most "Matlab-like"
// Open the fixed and moving images Image::Pointer fixedImage = ImageFileReader::Execute( "path/to/fixed.jpg" ); Image::Pointer movingImage = ImageFileReader::Execute( "path/to/moving.jpg" ); // Register the moving image to the fixed image AffineTransform::Pointer transform AffineRegistrator::Execute( fixedImage, movingImage ); // Resample the moving image movingImage = ImageResampler::Execute( movingImage, transform ); // Write out the resampled image ImageFileWriter::Ececute( movingImage, "path/to/output.png" );
Jim's recommendation
// Open the fixed and moving images Image::Pointer fixedImage = ImageFileReader::Read( "path/to/fixed.jpg" ); Image::Pointer movingImage = ImageFileReader::Read( "path/to/moving.jpg" ); // Register the moving image to the fixed image AffineTransform::Pointer transform AffineRegistrator::Register( fixedImage, movingImage ); // Resample the moving image movingImage = ImageResampler::Resample( movingImage, transform ); // Write out the resampled image ImageFileWriter::Write( "path/to/output.png", movingImage );
Filter blocks
- Pros:
- Default parameters make provide good guess for algorithm prototyping
- Parameters can be changed individually as needed
- Cons:
- Image is fully processed when execute is called (No easy streaming implementation)
- Other Notes:
- No pipeline
- Uses object-oriented paradigm
// Open the fixed and moving images ImageFileReader reader; reader.SetFilename( "path/to/fixed.jpg" ); Image::Pointer fixedImage = reader.execute(); reader.SetFilename( "path/to/moving.jpg" ); Image::Pointer movingImage = reader.execute(); // Register the moving image to the fixed image AffineRegistrator registrator; registrator.SetFixedImage( fixedImage ); registrator.SetMovingImage( movingImage ); AffineTransform transform; transform = registrator.execute(); // Resample the moving image Resampler resampler; resampler.SetTransform( transform ); movingImage = resampler.execute( movingImage ); // Write out the resampled image ImageFileWriter writer; writer.SetFilename( "path/to/output.png" ); writer.ececute( movingImage );
Jim's recommendation
// Open the fixed and moving images ImageFileReader reader; reader.SetFilename( "path/to/fixed.jpg" ); Image::Pointer fixedImage = reader.Read(); reader.SetFilename( "path/to/moving.jpg" ); Image::Pointer movingImage = reader.Read(); // Register the moving image to the fixed image AffineRegistrator registrator; registrator.SetFixedImage( fixedImage ); registrator.SetMovingImage( movingImage ); AffineTransform transform; transform = registrator.Register(); // Resample the moving image Resampler resampler; resampler.SetTransform( transform ); movingImage = resampler.Resample( movingImage ); // Write out the resampled image ImageFileWriter writer; writer.SetFilename( "path/to/output.png" ); writer.Write( movingImage );
Pipeline
// Open the fixed and moving images ImageFileReader reader1; ImageFileReader reader2; reader1.SetFilename( "path/to/fixed.jpg" ); reader2.SetFilename( "path/to/moving.jpg" ); // Register the moving image to the fixed image AffineRegistrator registrator; registrator.SetFixedImage( reader1.GetOutput() ); registrator.SetMovingImage( reader2.GetOutput() ); // Resample the moving image Resampler resampler; resampler.SetInput( reader2.GetOutput() ); resampler.SetTransform( registrator.GetOutput() ); // Write out the resampled image ImageFileWriter writer; writer.SetFilename( "path/to/output.png" ); writer.SetInput( movingImage ); // Execute the pipeline writer.Update();
Strategy pattern
http://en.wikipedia.org/wiki/Strategy_pattern
- Notes:
- 2 independent issues here (strategy and parameter access)
- Uses enums for parameter setting so all parameter setting is done through an X.SetParameter[TYPE]("name", val) function
- Maintains registration granularity so that transform, interpolator, optimizer, and metric can be interchanged
// NOTE: Language = C# // Create metric itk::simple::simpleMetric metric; metric.setType( itk::simple::MattesMutualInformation ); metric.setParameterInt( "NumberOfHistogramBins", 30 ); metric.setParameterInt( "NumberOfSpatialSamples", 1000 ); // Create interpolator itk::simple::simpleInterpolator interpolator; interpolator.setType( itk::simple::LanczosWindowedSincInterpolation ); // Create transform itk::simple::simpleTransform transform; transform.setType( itk::simple::AffineTransform ); // Create optimizer itk::simple::simpleOptimizer optimizer; optimizer.setType( itk::simple::RegularStepGradientDescentOptimizer ); optimizer.setParameterInt( "NumberOfIterations", 100 ); optimizer.setParameterDouble( "MinimumStepLength", 0.005 ); optimizer.setParameterDouble( "MaximumStepLength", 1.0 ); optimizer.setParameterBoolean( "Maximize", true ); // Registration itk::simple::simpleRegistration registration; registration.setMetric( metric ); registration.setInterpolator( interpolator ); registration.setTransform( transform ); registration.setOptimizer( optimizer ); registration.setFixedImage( fixedImage ); registration.setMovingImage( movingImage );
Level Set
Region Growing
- Open an image
- Set up a set of seed points
- Run an connected threshold region growing segmentation
- Write out the resulting segmentation mask
Procedural
- Pros:
- Fewest lines of code
- Cons:
- Not modular
- More complex argument lists needed for different comparison types
// Open an image Image::Pointer im = ImageFileReader::Execute("sample/path/to/image.jpg"); // Set up seeds std::vector<Point> points; Point p1, p2; p1[0] = 25; p1[1] = 25; p2[0] = 35; p2[1] = 5; points.push_back(p1); points.push_back(p2); // Run the region growing algorithm seg = RegionGrowingConnectedThresholdFilter::Execute(im, points, 128, 200); // Write out the resulting segmentation ImageFileWriter::Execute(seg, "sample/path/to/output.png");
Jim's recommendation
// Open an image Image::Pointer im = ImageFileReader::Read("sample/path/to/image.jpg"); // Set up seeds std::vector<Point> points; Point p1, p2; p1[0] = 25; p1[1] = 25; p2[0] = 35; p2[1] = 5; points.push_back(p1); points.push_back(p2); // Run the region growing algorithm seg = RegionGrowingConnectedThresholdFilter::Filter(im, points, 128, 200); // Segment()? // Write out the resulting segmentation ImageFileWriter::Write( "sample/path/to/output.png", seg);
Pipieline
- Pros:
- Can implement streaming for large images
- More efficient
- Cons:
- Harder to learn that procedural
// Open an image ImageFileReader reader; reader.SetFilename( "sample/path/to/image.jpg" ); // Set up seeds std::vector<Point> points; Point p1, p2; p1[0] = 25; p1[1] = 25; p2[0] = 35; p2[1] = 5; points.push_back(p1); points.push_back(p2); // Set up the region growing algorithm RegionGrowingConnectedThresholdFilter filter; filter->SetInput(reader->GetOutput()); filter->SetSeedPoints(points); filter->SetLower(128); filter->SetUpper(200); // Write out the image ImageFileWriter writer; writer.SetFilename( "sample/path/to/output.png" ); writer.SetInput( filter->GetOutput() ); // Update the pipieline writer.Update();
Watershed
QuadEdgeMesh
User Domain Examples
This section provides a set of examples for simple applications from a number of target user groups. The goal is to present the ARB with targeted examples that show non-trivial applications specific to each target community.