Post on 22-Jan-2016
1
ITK Lecture 7 - Writing Filters, Part 1
ITK Lecture 7 - Writing Filters, Part 1
Methods in Image AnalysisCMU Robotics Institute 16-725U. Pitt Bioengineering 2630
Spring Term, 2006
Methods in Image AnalysisCMU Robotics Institute 16-725U. Pitt Bioengineering 2630
Spring Term, 2006
Damion Shelton
2
Where we areWhere we are
You should understand What the pipeline is and how to connect filters together to perform sequential processing
How to move through images using iterators
How to access specific pixels based on their location in data space or physical space
You should understand What the pipeline is and how to connect filters together to perform sequential processing
How to move through images using iterators
How to access specific pixels based on their location in data space or physical space
3
What we’ll coverWhat we’ll cover
How to write your own filter that can fit into the pipeline
For reference, read Chapter 10 from the ITK Guide
How to write your own filter that can fit into the pipeline
For reference, read Chapter 10 from the ITK Guide
4
Is it hard or easy?Is it hard or easy?
Today: writing filters is really, really easy
Next lecture: well… it can be tricky at times
Remember, don’t panic!
Today: writing filters is really, really easy
Next lecture: well… it can be tricky at times
Remember, don’t panic!QuickTime™ and a
TIFF (Uncompressed) decompressorare needed to see this picture.
5
Cheat as much as possible!Cheat as much as possible! Never, ever, ever, write a filter from scratch
Unless you’re doing something really odd, find a filter close to what you want and work from there
Recycling the general framework will save you a lot of time and reduce errors
Never, ever, ever, write a filter from scratch
Unless you’re doing something really odd, find a filter close to what you want and work from there
Recycling the general framework will save you a lot of time and reduce errors
6
Much of the filter is already writtenMuch of the filter is already written
Most of the interface for an ImageToImageFilter is already coded by the base classes
For example, SetInput and GetOutput are not functions you have to write
You should never have to worry about particulars of the pipeline
Most of the interface for an ImageToImageFilter is already coded by the base classes
For example, SetInput and GetOutput are not functions you have to write
You should never have to worry about particulars of the pipeline
7
The simple caseThe simple case
You can write a filter with only one* function! (* well, sort of)
Overload GenerateData(void) to produce output given some input
We’ll look at ReflectImageFilter as an example (look in /Code/BasicFilters)
You can write a filter with only one* function! (* well, sort of)
Overload GenerateData(void) to produce output given some input
We’ll look at ReflectImageFilter as an example (look in /Code/BasicFilters)
8
The header - stuff that’s “always there”The header - stuff that’s “always there” itkNewMacro sets up the object factory (for reference counted smart pointers)
itkTypeMacro allows you to use run time type information
itkGetMacro and itkSetMacro are used to access private member variables
itkNewMacro sets up the object factory (for reference counted smart pointers)
itkTypeMacro allows you to use run time type information
itkGetMacro and itkSetMacro are used to access private member variables
9
The header cont.The header cont.
Prototypes for functions you will overload:
void PrintSelf(std::ostream& os, Indent indent) const;
void GenerateData(void);
Prototypes for functions you will overload:
void PrintSelf(std::ostream& os, Indent indent) const;
void GenerateData(void);
10
More header codeMore header code
You will also see: Many typedefs: Self, Superclass, Pointer, and ConstPointer are particularly important
Constructor and destructor prototypes
Member variables (in this example, only one)
You will also see: Many typedefs: Self, Superclass, Pointer, and ConstPointer are particularly important
Constructor and destructor prototypes
Member variables (in this example, only one)
11
Pay attention to...Pay attention to...
#ifdef, #define, #endif are used to enforce single inclusion of header code
Use of namespace itk The three lines starting with #ifndef ITK_MANUAL_INSTANTIATION control inclusion of the .txx file, since compilers don’t recognize the .txx as compilable source
#ifdef, #define, #endif are used to enforce single inclusion of header code
Use of namespace itk The three lines starting with #ifndef ITK_MANUAL_INSTANTIATION control inclusion of the .txx file, since compilers don’t recognize the .txx as compilable source
12
Does this seem complex?Does this seem complex? That’s why I suggested always starting with an existing class
You may want to use find and replace to change the class name and edit from there
Moving on to the .txx file...
That’s why I suggested always starting with an existing class
You may want to use find and replace to change the class name and edit from there
Moving on to the .txx file...
13
The constructorThe constructor
In ReflectImageFilter, the constructor doesn’t do much Tell the pipeline framework that we want one and only one input
Initialize the member variable
In ReflectImageFilter, the constructor doesn’t do much Tell the pipeline framework that we want one and only one input
Initialize the member variable
14
GenerateData()GenerateData()
This is where most of the action occurs
GenerateData() is called during the pipeline update process
It’s responsible for allocating the output image (though the pointer already exists) and filling the image with interesting data
This is where most of the action occurs
GenerateData() is called during the pipeline update process
It’s responsible for allocating the output image (though the pointer already exists) and filling the image with interesting data
15
Accessing the input and outputAccessing the input and output
First, we get the pointers to the input and ouput images
typename Superclass::InputImageConstPointer inputPtr = this->GetInput();
typename Superclass::OutputImagePointer outputPtr = this->GetOutput(0);
First, we get the pointers to the input and ouput images
typename Superclass::InputImageConstPointer inputPtr = this->GetInput();
typename Superclass::OutputImagePointer outputPtr = this->GetOutput(0);
Filters can have multiple outputs,in this case we only have one
16
Allocating the output imageAllocating the output imageoutputPtr->SetRequestedRegion( inputPtr->GetRequestedRegion() );
outputPtr->SetBufferedRegion( inputPtr->GetBufferedRegion() );
outputPtr->SetLargestPossibleRegion( inputPtr->GetLargestPossibleRegion() );
outputPtr->Allocate();
outputPtr->SetRequestedRegion( inputPtr->GetRequestedRegion() );
outputPtr->SetBufferedRegion( inputPtr->GetBufferedRegion() );
outputPtr->SetLargestPossibleRegion( inputPtr->GetLargestPossibleRegion() );
outputPtr->Allocate();
Question: How big is output image compared to the input?
17
The meat of GenerateData()The meat of GenerateData() Iterate “forwards” through input image and “backwards” through the output image
Set the output pixel equal to the input pixel
We can globally reverse the direction of iteration with m_Direction - i.e. forwards becomes backwards and vice-versa
Iterate “forwards” through input image and “backwards” through the output image
Set the output pixel equal to the input pixel
We can globally reverse the direction of iteration with m_Direction - i.e. forwards becomes backwards and vice-versa
18
PrintSelfPrintSelf
PrintSelf is a function present in all classes derived from itk::Object which permits easy display of the “state” of an object (i.e. all of its member variables)
The testing framework requires that you implement this function, otherwise it will fail the “PrintSelf test”
PrintSelf is a function present in all classes derived from itk::Object which permits easy display of the “state” of an object (i.e. all of its member variables)
The testing framework requires that you implement this function, otherwise it will fail the “PrintSelf test”
19
PrintSelf, cont.PrintSelf, cont.
First, we call the base class implementationSuperclass::PrintSelf(os,indent);
And second we print all of our member variables
os << indent << "Direction: " << m_Direction << std::endl;
First, we call the base class implementationSuperclass::PrintSelf(os,indent);
And second we print all of our member variables
os << indent << "Direction: " << m_Direction << std::endl;
20
What we’ve just doneWhat we’ve just done
We now have a filter that: Is single threaded (executes on one processor)
Produces an output image the same size as the input
Assumes a one-to-one mapping between input and output pixels
This works, but seems a bit limiting...
We now have a filter that: Is single threaded (executes on one processor)
Produces an output image the same size as the input
Assumes a one-to-one mapping between input and output pixels
This works, but seems a bit limiting...
21
Questions?Questions?
How can we make multithreaded filters?
What if the input and output images are not the same size? E.g., convolution edge effects, subsampling, etc.
What about requested regions?
How can we make multithreaded filters?
What if the input and output images are not the same size? E.g., convolution edge effects, subsampling, etc.
What about requested regions?