[Insight-users] Application walk through
Neil Killeen
Neil.Killeen@atnf.csiro.au
Wed, 8 Jan 2003 17:21:51 +1100 (EST)
Luis
I have now written a small application (included below) that reads as
image, smooths it with a gaussian and displays it. Before I proceed
further, I'd like to make sure I understand some basic things. Could you
find the time to comment on the following questions pertaining to this
application ?
The application is based on the example code in
Insight/InsightDocuments/CourseWare/Training/GettingStarted-II.ppt
many thanks
Neil
1) I have created the Image typedef
typedef itk::Image<float, 2> ImageType;
I had to specify the dimensionality of the image (2) at this point.
Is this really necessary ? In my opinion, it is very inflexible to have to
specify it here. A generic display tool for example should be able
to read and display an image of arbitrary dimensionality.
2) I have used the class itk::ImageFileReader to read the image,.
This class appears to have the smarts to handle various different
file formats. It can handle at least dicom and meta images - great.
However, I would *never* have found this class if it wasn't used
in the example code. The (module) 'Groups' class listing
is the one that I find the most useful. However, this class does
not appear to exist in that structure. If I was to expect to find it anywhere,
it would be under
Groups
Data Processing Objects
Input and Output Filters
Here you find a funny list of classes:
ByteSwapper
ImageFileWriter
ImageViewer
ImageViewerWindow
ImageWriter
ImportImageContainer
ImportImageFilter
RawImageIO
RawImageWriter
VOLImageIO
VTKImageExport
VTKImageExportBase
VTKImageImport
Writer
- there is no ImageFileReader. I see RawImageIO there, I would have expected a similar
class for all of the supported file formats, e.g. MetaImageIO etc. Where is ImageFileReader
to be found ?
- I see the class VTKImageExport (and *Import) which says it is for use at the end of the ITK
pipeline chain to allow you to convert to VTK format. Question, what is the
relationship of this class to class ImageToVTKImageFilter which does exactly
that too (used in application below and subject of our discussion last week) ?
- The only place I could find ImageFileReader was in the alphabetical list.
The class documentation gives no clue as to what file format types are supported.
This class is templated according to
template <class TOutputImage, class ConvertPixelTraits=DefaultConvertPixelTraits<ITK_TYPENAME TOutputImage::PixelType> >
where the TOutputImage is the *output* Image type of the filter. The ConvertPixelTraits
is used to convert between the file pixel type and this output type.
I couldn't find any class ConvertPixelTraits in the alphabetical list although
DefaulConvertPixelTraits is there. As far as I can tell this is nothing to do
with file formats (e.g. meta/dicom etc) but purely pixel type (float, int etc).
I assume that DefaultConvertPixelTraits<ITK_TYPENAME TOutputImage::PixelType> >
works out to be the same pixel type as TOutputImage, which in my case was Float ?
3) The DiscreteGaussianImageFilter class does separable Gaussian convolution.
It's interface should be simple and clear. However, virtally every method
doc. says 'Standard Get/Set' macros for filter parameters.
I find that pretty frustrating, especially as nowhere can I find the
documentation for these 'Standard Get/Set' methods ! I think that
anything that says this should include a link to their location.
As a general statement about the class documentation, I am finding it
relatively poor.
The module, class and class member descriptions are often so poor as to
be useless. IMO, the module docs. are the most important as they give
you some high-level context about what does what and where it is.
As another trivial example, ImageFileReader::GenerateData describes its
functionality as 'Does the real work' which is singularly unhelpful !
Also the heavy typedef-ing and templating makes it very hard to figure
out just what the arguments in the interface are. I seem to spend a lot
of time going back to the Alphabetical class list becaus the DOxygen
docs. don't hyperlink me anywhere useful a lot of the time (because of
typedefs I think).
Clearly, your goal with a toolkit is to reuse code. This means
the documentation *must* be good enough to allow this easily.
It's always a problem to get people to write good documentation...
4) The basic approach is that of a pipeline, and I like the clarity that
this has, with common methods always being available for the pipeline
(e.g. SetInput, GetOutput)
smoother->SetInput(reader->GetOutput());
converter->SetInput(smoother->GetOutput());
viewer->SetInput(converter->GetOutput());
The GetOutput functions return pointers to the basic class Image of the
appropriate type that you are dealing with. However, these do not appear
to be Smart pointers, but raw pointers.
E.g.
template<class TOutputImage> OutputImageType* itk::ImageSource< TOutputImage >::GetOutput (void)
So I am a bit confused about whose responsibility it is to manage these
pointers. In the example code nothing deletes them. Who owns these
pointers - are they all clones of the same image ? I.e. it being a
pipeline, all I need is one Image which is continually updated.
I am assuming that what happens is that the data is read into an Image
class object (by ImageFileReader) which exists purely in memory (perhaps
you can get away with this because Medical imaging images are not very
big). This object is updated by each filter and responsibility for it
is transferred somehow to each successive filter. Does it get deleted
at the end when the last filter is destroyed ? Perhaps you could clarify
this for me ?
5) I don't know much about VTK yet, so perhaps I will allow myself just
one question. IN getting the example code running I had to use the class
vtkImageViewer2 rather than the given vtkImageViewer. I don't know what
the difference is.
The example code did
vtkImageViewer2* viewer = vtkImageViewer2::New();
which is just a raw pointer. Nothing deletes it. However if I try to
delete them the compiler complains. Should they be deleted (somehow)
or not ?
that's all for now
many thanks (again)
Neil
#include <iostream>
#include <itkImage.h>
#include <itkImageFileReader.h>
#include <itkImageToVTKImageFilter.h>
#include <vtkImageViewer2.h>
#include <vtkRenderWindowInteractor.h>
#include <itkDiscreteGaussianImageFilter.h>
int usage(void) {
std::cout << "metaImageViewer" << std::endl;
std::cout << std::endl;
std::cout << "metaImageViewer <Filename>" << std::endl;
std::cout << std::endl;
return 1;
}
int main(int argc, char **argv)
{
// Get file name
char* fName;
if(argc == 2) {
if(argv[1][0] != '-') {
fName = argv[argc-1];
} else {
return usage();
}
} else {
return usage();
}
// typedefs
typedef itk::Image<float, 2> ImageType;
typedef itk::ImageFileReader<ImageType> ReaderType;
typedef itk::ImageToVTKImageFilter<ImageType> ConverterType;
typedef itk::DiscreteGaussianImageFilter<ImageType, ImageType>
SmoothType;
// Create reader and filter
std::cout << "Create reader" << std::endl;
ReaderType::Pointer reader = ReaderType::New();
// Create itk -> vtk filter
std::cout << "Create itk->vtk filter" << std::endl;
ConverterType::Pointer converter = ConverterType::New();
// Create smoothing filter
std::cout << "Create smoothing filter" << std::endl;
SmoothType::Pointer smoother = SmoothType::New();
smoother->SetVariance (10.0);
// Create VTK viewer and renderer
vtkImageViewer2* viewer = vtkImageViewer2::New();
vtkRenderWindowInteractor* renderer = vtkRenderWindowInteractor::New();
viewer->SetupInteractor(renderer);
try {
// Set file name in reader
std::cout << "Set file " << fName << " in reader" << std::endl;
reader->SetFileName(fName);
// Set image in smoother
std::cout << "Set image in smoother" << std::endl;
smoother->SetInput(reader->GetOutput());
// Set image in itk->vtk converter
std::cout << "Set image in converter" << std::endl;
converter->SetInput(smoother->GetOutput());
// Set viewer input with filter output
std::cout << "Set filter in viewer" << std::endl;
viewer->SetInput(converter->GetOutput());
// Display
viewer->Render();
viewer->SetColorWindow(255);
viewer->SetColorLevel(128);
renderer->Start();
} catch( ... ) {
std::cout << "Problems with process" << std::endl;
return 1;
}
std::cout << "...Done" << std::endl;
//
return 0;
}