[Insight-users] why vtkImagePlaneWidget run extremely slow after itk::BinaryThresholdImageFilter excuted several times

kdsfinger at gmail.com kdsfinger at gmail.com
Mon Aug 21 15:48:58 EDT 2006


hi, all
I found the myITKgui runs extremely slow after
itk::BinaryThresholdImageFilter excuted several times. The myITKgui is
a little demo of itk-fltk and here is the link:
http://www.eecs.berkeley.edu/~eklund/teaching/cs294/software/Software/myITKgui-cs294v1.0.zip

Here is major part of the code.

/*=========================================================================

  Program:   My ITK GUI - A Foundation for Pipeline Visualization in ITK
  Module:    $RCSfile: migAppBase.h,v $
  Language:  C++
  Date:      $Date: 2006/02/06 06:35:36 $
  Version:   $Revision: 1.1 $

  Copyright (c) 2003-5 Damion Shelton

  All rights reserved.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#ifndef _migAppBase_h
#define _migAppBase_h

#include <stdio.h>

#include <itkSize.h>
#include <itkIndex.h>
#include <itkImage.h>
#include <itkBinaryThresholdImageFilter.h>
#include <itkImageFileReader.h>
#include <itkVTKImageExport.h>

#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkImageImport.h>
#include <vtkImagePlaneWidget.h>

#include "vtkFlRenderWindowInteractor.h"

class migAppBase
{
public:

  /** Typedefs used in myITKgui */
  typedef itk::Image<unsigned char, 3> InputImageType;
  typedef itk::ImageFileReader<InputImageType> ImageFileReaderType;
  typedef itk::Image<unsigned char, 3> OutputImageType;
  typedef itk::VTKImageExport<InputImageType> itkVTKImageExportType;
  typedef itkVTKImageExportType::Pointer itkVTKImageExportPointerType;

  /** The type of filter the demo uses... YOU WILL NEED TO CHANGE THIS
FILTER IN YOUR HOMEWORK */
  typedef itk::BinaryThresholdImageFilter<InputImageType,
InputImageType> ThresholdType;

  /** Read a META format image from disk */
  void ReadImage();

  /** Hook together an ITK pipeline, EDIT THIS FUNCTION TO CHANGE ITK
BEHAVIOR! */
  void CreateITKPipeline();

  /** Callback for making the ITK pipeline do something */
  void UpdatePipelineCallback();

  /** Window creation */
  void CreateInputImageWindow();
  void CreateOutputImageWindow();

  /** Create a FLTK window with a VTK interator */
  void CreateWindowWithRWI(vtkFlRenderWindowInteractor *&flrwi,
Fl_Window *&flw, char *title);

  /** Create input and output pipelines */
  void CreateInputImageVTKPipeline(vtkFlRenderWindowInteractor *flrwi);
  void CreateOutputImageVTKPipeline(vtkFlRenderWindowInteractor *flrwi);

  /** Reset the image planes to the center of the image */
  void ResetInputImagePlaneWidgets();
  void ResetOutputImagePlaneWidgets();

  /** Constructor - not much to see */
  migAppBase();

  /** Destructor - not much to see */
  virtual ~migAppBase();

protected:

  /** Input image file name */
  char* m_InputImageFilename;

  /** The image reader */
  ImageFileReaderType::Pointer m_ImageReader;

  /** The image we loaded from the file */
  InputImageType::Pointer m_InputImage;

  /** The image that results from running the pipeline */
  OutputImageType::Pointer m_OutputImage;

  /** Tracks whether this is the first time we've pressed "update" */
  bool m_IsFirstUpdate;

  /** The _EXAMPLE_ filter used here... YOU SHOULD CHANGE THIS */
  ThresholdType::Pointer m_ThresholdFilter;

  /** Example filter parameters... should also be changed in your code */
  double m_LowerThreshold;
  double m_UpperThreshold;
  double m_InsideThresholdValue;
  double m_OutsideThresholdValue;

  /** Input window FLTK stuff */
  vtkFlRenderWindowInteractor* m_InputInteractor;
  Fl_Window* m_InputWindow;

  /** Converter from ITK to VTK for input image */
  itk::VTKImageExport<InputImageType>::Pointer m_InputImageITKtoVTKexporter;
  vtkImageImport* m_InputImageVTKimporter;

  /** VTK rendering architecture for input image */
  vtkRenderWindow * m_InputRenderWindow;
  vtkRenderer     * m_InputRenderer;

  /** Slices through the input image */
  vtkImagePlaneWidget* m_InputImagePlaneX;
  vtkImagePlaneWidget* m_InputImagePlaneY;
  vtkImagePlaneWidget* m_InputImagePlaneZ;

  /** Output window FLTK stuff */
  vtkFlRenderWindowInteractor* m_OutputInteractor;
  Fl_Window* m_OutputWindow;

  /** VTK rendering architecture for output image */
  vtkRenderWindow * m_OutputRenderWindow;
  vtkRenderer     * m_OutputRenderer;

  /** Converter from ITK to VTK for output image */
  itk::VTKImageExport<OutputImageType>::Pointer m_OutputImageITKtoVTKexporter;
  vtkImageImport* m_OutputImageVTKimporter;

  /** Slices through the output image */
  vtkImagePlaneWidget* m_OutputImagePlaneX;
  vtkImagePlaneWidget* m_OutputImagePlaneY;
  vtkImagePlaneWidget* m_OutputImagePlaneZ;
};

#endif


/*=========================================================================

  Program:   My ITK GUI - A Foundation for Pipeline Visualization in ITK
  Module:    $RCSfile: migAppBase.cxx,v $
  Language:  C++
  Date:      $Date: 2006/02/06 06:35:36 $
  Version:   $Revision: 1.1 $

  Copyright (c) 2003-5 Damion Shelton
  ...with thanks to Charl Botha who the FlRenderWindowInteractor example
     code on which part of this class is based

  All rights reserved.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "migAppBase.h"

#include <FL/Fl.H>
#include <FL/Fl_File_Chooser.H>

#include <itkMetaImageIOFactory.h>

/**
 * This function will connect the given itk::VTKImageExport filter to
 * the given vtkImageImport filter.
 */
template <typename ITK_Exporter, typename VTK_Importer>
void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer)
{
  importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback());
  importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback());
  importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback());
//  importer->SetSpacingCallback(exporter->GetSpacingCallback());
//  importer->SetOriginCallback(exporter->GetOriginCallback());
  importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback());
  importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback());
  importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback());
  importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback());
  importer->SetDataExtentCallback(exporter->GetDataExtentCallback());
  importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback());
  importer->SetCallbackUserData(exporter->GetCallbackUserData());
}

migAppBase
::migAppBase()
{
  // The file name of the image we're reading
  m_InputImageFilename = new char[256];

  // The first time update is called we need to do some extra stuff
  m_IsFirstUpdate = true;

  m_InputImage = 0;
  m_OutputImage = 0;
  m_ThresholdFilter = 0;

  m_LowerThreshold = 25;
  m_UpperThreshold = 100;
  m_InsideThresholdValue = 0;
  m_OutsideThresholdValue = 255;

  m_InputInteractor = 0;
  m_InputWindow = 0;
  m_InputImageITKtoVTKexporter = 0;
  m_InputImageVTKimporter = 0;
  m_InputRenderWindow = 0;
  m_InputRenderer = 0;
  m_InputImagePlaneX = 0;
  m_InputImagePlaneY = 0;
  m_InputImagePlaneZ = 0;

  m_OutputInteractor = 0;
  m_OutputWindow = 0;
  m_OutputImageITKtoVTKexporter = 0;
  m_OutputImageVTKimporter = 0;
  m_OutputRenderWindow = 0;
  m_OutputRenderer = 0;
  m_OutputImagePlaneX = 0;
  m_OutputImagePlaneY = 0;
  m_OutputImagePlaneZ = 0;
}

migAppBase
::~migAppBase()
{
  if( m_InputImageFilename )
    delete[] m_InputImageFilename;
}

void
migAppBase
::ReadImage()
{
  // Can only read an image once
#if 0 //FIXME
   if(m_InputImage != 0)
	  return;
#endif

  // Show a dialog box to let the user pick a file
  char* chooserName = fl_file_chooser("Pick a .mha file to load",
"*.mha", 0, 0);

  // Store the filename
  strcpy( m_InputImageFilename, chooserName );
  cout << "Opening file with name: " << m_InputImageFilename << endl;

  // Now we can read the file
  m_ImageReader = ImageFileReaderType::New();
  itk::MetaImageIOFactory::RegisterOneFactory();
  m_ImageReader->SetFileName( m_InputImageFilename );
  m_InputImage = m_ImageReader->GetOutput();
  m_InputImage->SetRequestedRegionToLargestPossibleRegion();
  m_ImageReader->Update();

  // Create the ITK pipeline (NB: pipeline not yet executed)
  this->CreateITKPipeline();

  // Create the input image VTK pipeline
  this->CreateInputImageWindow();
}

/**
 *
 *
 * EDIT THE FOLLOWING FUNCTION TO CHANGE THE BEHAVIOR OF THE FILTERS
 *
 *
 **/

void
migAppBase
::CreateITKPipeline()
{
  // Set up our example filter
  m_ThresholdFilter = ThresholdType::New();
  m_ThresholdFilter->SetInput(m_InputImage);

  m_ThresholdFilter->SetOutsideValue( m_OutsideThresholdValue );
  m_ThresholdFilter->SetInsideValue( m_InsideThresholdValue );
  m_ThresholdFilter->SetLowerThreshold( m_LowerThreshold );
  m_ThresholdFilter->SetUpperThreshold( m_UpperThreshold );

  // Get the final pipeline output... be sure to do this in your revisions!
  m_OutputImage = m_ThresholdFilter->GetOutput();
}

void
migAppBase
::UpdatePipelineCallback()
{
  // Transfer the most recent filter parameters to the filter
  m_ThresholdFilter->SetOutsideValue( m_OutsideThresholdValue );
  m_ThresholdFilter->SetInsideValue( m_InsideThresholdValue );
  m_ThresholdFilter->SetLowerThreshold( m_LowerThreshold );
  m_ThresholdFilter->SetUpperThreshold( m_UpperThreshold );

  // Update the pipeline
  m_ThresholdFilter->Update();

  // If this is the first time we've hit update there's other stuff
  // that needs to happen
  if(m_IsFirstUpdate)
  {
    // Display the output image
    this->CreateOutputImageWindow();

    // No longer the first update
    m_IsFirstUpdate = false;
  }
  else
  {
    // Refresh the output window if not the first update
    // NB: doing this on the first update on Windows causes a new
    // renderwindow to spawn (not sure why)
	  m_OutputRenderWindow->Render();
  }
}

void
migAppBase
::CreateInputImageWindow()
{
  CreateWindowWithRWI(m_InputInteractor, m_InputWindow, "Input Image");

  // these two steps are VERY IMPORTANT, you have to show() the fltk window
  // containing the vtkFlRenderWindowInteractor, and then the
  // vtkFlRenderWindowInteractor itself
  m_InputWindow->show();
  m_InputInteractor->show();

  // now we get to setup our VTK rendering pipeline
  CreateInputImageVTKPipeline(m_InputInteractor);
}

void
migAppBase
::CreateOutputImageWindow()
{
  CreateWindowWithRWI(m_OutputInteractor, m_OutputWindow, "Output Image");

  // these two steps are VERY IMPORTANT, you have to show() the fltk window
  // containing the vtkFlRenderWindowInteractor, and then the
  // vtkFlRenderWindowInteractor itself
  m_OutputWindow->show();
  m_OutputInteractor->show();

  // now we get to setup our VTK rendering pipeline
  this->CreateOutputImageVTKPipeline(m_OutputInteractor);
}

void
migAppBase
::CreateWindowWithRWI(vtkFlRenderWindowInteractor *&flrwi, Fl_Window
*&flw, char *title)
{
   // set up main FLTK window
   flw = new Fl_Window(300,330,title);

   // and instantiate vtkFlRenderWindowInteractor (here it acts like a
   // FLTK window, i.e. you could also instantiate it as child of a
   // Fl_Group in a window)
   flrwi = new vtkFlRenderWindowInteractor(5,5,290,260,NULL);

   // this will result in a little message under the rendering
   Fl_Box* box = new Fl_Box(5,261,290,34,
                             "3 = stereo, j = joystick, t = trackball, "
                            "w = wireframe, s = surface, p = pick; "
                            "you can also resize the window");
   box->labelsize(10);
   box->align(FL_ALIGN_WRAP);

   // we're done populating the flw
   flw->end();

   // if the main window gets resized, the vtk window should resize with it
   flw->resizable(flrwi);
}

void
migAppBase
::CreateInputImageVTKPipeline(vtkFlRenderWindowInteractor *flrwi)
{
  // Abort if the user is being stupid
#if 0 //FIXME
   if(m_InputImage==0)
    return;
#endif

  // create a rendering window and renderer
  m_InputRenderer = vtkRenderer::New();
  m_InputRenderer->SetBackground(0.0, 0.0, 0.0);

  m_InputRenderWindow = vtkRenderWindow::New();
  m_InputRenderWindow->AddRenderer(m_InputRenderer);

  // NB: here we treat the vtkFlRenderWindowInteractor just like any other
  // old vtkRenderWindowInteractor
  flrwi->SetRenderWindow(m_InputRenderWindow);

  // Hook the VTK pipeline up to the ITK pipeline
  m_InputImageITKtoVTKexporter = itk::VTKImageExport<InputImageType>::New();
  m_InputImageVTKimporter = vtkImageImport::New();
  m_InputImageITKtoVTKexporter->SetInput( m_InputImage );
  ConnectPipelines(m_InputImageITKtoVTKexporter, m_InputImageVTKimporter);

  // Need to update prior to creating the cutting planes
  m_InputImageITKtoVTKexporter->Update();
  m_InputImageVTKimporter->Update();

  // Create the image cutting planes
  m_InputImagePlaneX = vtkImagePlaneWidget::New();
  m_InputImagePlaneX->RestrictPlaneToVolumeOn();
  m_InputImagePlaneX->SetResliceInterpolateToCubic();
  m_InputImagePlaneX->SetInput( (vtkDataSet*)
m_InputImageVTKimporter->GetOutput() );
  m_InputImagePlaneX->SetPlaneOrientationToXAxes();
  m_InputImagePlaneX->SetSliceIndex( 0 );

  m_InputImagePlaneY = vtkImagePlaneWidget::New();
  m_InputImagePlaneY->RestrictPlaneToVolumeOn();
  m_InputImagePlaneY->SetResliceInterpolateToCubic();
  m_InputImagePlaneY->SetInput( (vtkDataSet*)
m_InputImageVTKimporter->GetOutput() );
  m_InputImagePlaneY->SetPlaneOrientationToYAxes();
  m_InputImagePlaneY->SetSliceIndex( 0 );

  m_InputImagePlaneZ = vtkImagePlaneWidget::New();
  m_InputImagePlaneZ->RestrictPlaneToVolumeOn();
  m_InputImagePlaneZ->SetResliceInterpolateToCubic();
  m_InputImagePlaneZ->SetInput( (vtkDataSet*)
m_InputImageVTKimporter->GetOutput() );
  m_InputImagePlaneZ->SetPlaneOrientationToZAxes();
  m_InputImagePlaneZ->SetSliceIndex( 0 );

  // Set the position of the image planes to the center of the volume
  this->ResetInputImagePlaneWidgets();

  // Link the image planes to the interactor
  m_InputImagePlaneX->SetInteractor( flrwi );
  m_InputImagePlaneY->SetInteractor( flrwi );
  m_InputImagePlaneZ->SetInteractor( flrwi );

  // Turn on the image plane so they display
  m_InputImagePlaneX->On();
  m_InputImagePlaneY->On();
  m_InputImagePlaneZ->On();

  // just like with any other vtkRenderWindowInteractor(), you HAVE to call
  // Initialize() before the interactor will function.  See the docs in
  // vtkRenderWindowInteractor.h
  // This must occur AFTER the image planes have been added to the interactor
  flrwi->Initialize();

  // Clean up memory allocation (NB: not actually deleted until program returns)
  m_InputRenderer->Delete();
  m_InputRenderWindow->Delete();
}

void
migAppBase
::CreateOutputImageVTKPipeline(vtkFlRenderWindowInteractor *flrwi)
{
  // Abort if the user is being stupid
#if 0 //FIXME
   if(m_OutputImage==0)
    return;
#endif

  // create a rendering window and renderer
  m_OutputRenderer = vtkRenderer::New();
  m_OutputRenderer->SetBackground(0.0, 0.0, 0.0);

  m_OutputRenderWindow = vtkRenderWindow::New();
  m_OutputRenderWindow->AddRenderer(m_OutputRenderer);

  // NB: here we treat the vtkFlRenderWindowInteractor just like any other
  // old vtkRenderWindowInteractor
  flrwi->SetRenderWindow(m_OutputRenderWindow);

  // Hook the VTK pipeline up to the ITK pipeline
  m_OutputImageITKtoVTKexporter = itk::VTKImageExport<OutputImageType>::New();
  m_OutputImageVTKimporter = vtkImageImport::New();
  m_OutputImageITKtoVTKexporter->SetInput( m_OutputImage );
  ConnectPipelines(m_OutputImageITKtoVTKexporter, m_OutputImageVTKimporter);

  // Need to update prior to creating the cutting planes
  m_OutputImageITKtoVTKexporter->Update();
  m_OutputImageVTKimporter->Update();

  // Create the image cutting planes
  m_OutputImagePlaneX = vtkImagePlaneWidget::New();
  m_OutputImagePlaneX->RestrictPlaneToVolumeOn();
  m_OutputImagePlaneX->SetResliceInterpolateToCubic();
  m_OutputImagePlaneX->SetInput( (vtkDataSet*)
m_OutputImageVTKimporter->GetOutput() );
  m_OutputImagePlaneX->SetPlaneOrientationToXAxes();
  m_OutputImagePlaneX->SetSliceIndex( 0 );

  m_OutputImagePlaneY = vtkImagePlaneWidget::New();
  m_OutputImagePlaneY->RestrictPlaneToVolumeOn();
  m_OutputImagePlaneY->SetResliceInterpolateToCubic();
  m_OutputImagePlaneY->SetInput( (vtkDataSet*)
m_OutputImageVTKimporter->GetOutput() );
  m_OutputImagePlaneY->SetPlaneOrientationToYAxes();
  m_OutputImagePlaneY->SetSliceIndex( 0 );

  m_OutputImagePlaneZ = vtkImagePlaneWidget::New();
  m_OutputImagePlaneZ->RestrictPlaneToVolumeOn();
  m_OutputImagePlaneZ->SetResliceInterpolateToCubic();
  m_OutputImagePlaneZ->SetInput( (vtkDataSet*)
m_OutputImageVTKimporter->GetOutput() );
  m_OutputImagePlaneZ->SetPlaneOrientationToZAxes();
  m_OutputImagePlaneZ->SetSliceIndex( 0 );

  // Set the position of the image planes to the center of the volume
  this->ResetOutputImagePlaneWidgets();

  // Link the image planes to the interactor
  m_OutputImagePlaneX->SetInteractor( flrwi );
  m_OutputImagePlaneY->SetInteractor( flrwi );
  m_OutputImagePlaneZ->SetInteractor( flrwi );

  // Turn on the image plane so they display
  m_OutputImagePlaneX->On();
  m_OutputImagePlaneY->On();
  m_OutputImagePlaneZ->On();

  // just like with any other vtkRenderWindowInteractor(), you HAVE to call
  // Initialize() before the interactor will function.  See the docs in
  // vtkRenderWindowInteractor.h
  // This must occur AFTER the image planes have been added to the interactor
  flrwi->Initialize();

  // Clean up memory allocation (NB: not actually deleted until program returns)
  m_OutputRenderer->Delete();
  m_OutputRenderWindow->Delete();
}

void
migAppBase
::ResetInputImagePlaneWidgets()
{
  // Sanity check
  if(m_InputInteractor == 0)
    return;

  // Reset plane orientations
  m_InputImagePlaneZ->SetPlaneOrientationToZAxes();
  m_InputImagePlaneY->SetPlaneOrientationToYAxes();
  m_InputImagePlaneX->SetPlaneOrientationToXAxes();

  // Figure out how big the image is
  itk::Size<3> imageSize = m_InputImage->GetLargestPossibleRegion().GetSize();

  int xmax = imageSize[0];
  int ymax = imageSize[1];
  int zmax = imageSize[2];

  // Set the image planes to the center of the image
  m_InputImagePlaneX->SetSlicePosition( xmax/2 );
  m_InputImagePlaneY->SetSlicePosition( ymax/2 );
  m_InputImagePlaneZ->SetSlicePosition( zmax/2 );
}

void
migAppBase
::ResetOutputImagePlaneWidgets()
{
  // Sanity check
  if(m_OutputInteractor == 0)
    return;

  // Reset plane orientations
  m_OutputImagePlaneZ->SetPlaneOrientationToZAxes();
  m_OutputImagePlaneY->SetPlaneOrientationToYAxes();
  m_OutputImagePlaneX->SetPlaneOrientationToXAxes();

  // Figure out how big the image is
  itk::Size<3> imageSize = m_OutputImage->GetLargestPossibleRegion().GetSize();

  int xmax = imageSize[0];
  int ymax = imageSize[1];
  int zmax = imageSize[2];

  // Set the image planes to the center of the image
  m_OutputImagePlaneX->SetSlicePosition( xmax/2 );
  m_OutputImagePlaneY->SetSlicePosition( ymax/2 );
  m_OutputImagePlaneZ->SetSlicePosition( zmax/2 );
}

Thanks for comments.

zl2k


More information about the Insight-users mailing list