[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;
}