[vtkusers] A combination between ITK and VTK, read a series of the medical CT images and incorrect run of the vtkRenderWindowInteractor

paulus joo paulusjoo at hotmail.com
Mon Jun 14 09:58:24 EDT 2004


Dear vtk users

Forgive me for just asking you without giving any contribution yet, since I am still newbie in this field.  Hope you can still enough time to help me to answer my questions. 

I want to read a series of CT medical images (Dicom) format, apply image processing methods to obtain the desired quality of images and render the volume using volume rendering or surface rendering. For these purposes I  will combine VTK and ITK since as far as I know these two brother is suitable for these tasks. Below are the steps I will do:
1. Read Dicom files (using ITK)
2. Apply image processing methods on each images (using ITK)
3. Apply segmentation process for surface rendering (using ITK)
4. Use the itkImageToVTKImageFilter to convert the images to the format recognized by VTK.
5. Apply volume rendering or surface rendering.
6. Make a render window that contains 4 different renderers, one renderer to display volume or surface rendering result, and the rest (3 renderers) are used to display the 3 desired slices.  

Here are the list of what I've done: 
1. Try to open image file by ITK function and convert it to VTK format and display it with VTK. I tried this and succeed to open one image file as illustrated in the code below. 
2. Convert medical3.cxx example to MFC based so I can add control button (slider, spinner, checkbox,etc). I succeed to do this although the speed is slower than its original version. The code I mentioned in my previous mail.
3. Modify the result where there are 4 vtkRenderer instead of one, so the 3D is displayed in one vtkRenderer, and the rest will displays the slices in axial, sagittal, coronal plane. The code of this module is illustrated below. The result is not like I expect since the 3 renderer display the same image. I also add two button to navigate from one slice to another.

Here  are my questions and the problems I have:
1. Is the step mention above are correct to achieve the goal I need?
2. Is it correct to apply image processing methods before it is feed in into the VTK or do with VTK functions is enough? 
3. Based on the book, milist and the result of the trial I made, I make an assumption that to display the resliced images from a volume, it is used vtkImageActor instead of vtkImgeViewer. Is this correct?
4. I have a difficulties to find a good way how to reslice the volume and display it in 3 renderer, since these 3 renderers produce the same images, and I cannot navigate from one slice to another slice in each direction (sagittal,axial,coronal). Please show me what the mistakes I've done in the code?  
5. As I mentioned above I have 4 renderer, lets say ren1,ren2,ren3,ren4. The ren1 is used for the 3D visualization, and the other are used to display the 3 resliced images. I want to change the default interaction mode of the vtkRenderWindowInteractor in ren2,ren3 and ren4 by issuing ren2->interactiveOff(). This function run incorrectly since when I click the mouse on ren2 area it influence ren1 so the 3D object in ren1 is moving. How to avoid this problem so 3D object is moving just by the interaction in ren1. 


Thank you in advance. 
Paulus



// THE CODE TO READ IMAGE AND CONVERT ITK TO  VTK

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileReader.h"
#include "vtkImageViewer.h"
#include "vtkRenderWindowInteractor.h"
#include "itkImageToVTKImageFilter.h"


int main( int argc, char ** argv )
{
  typedef unsigned short      PixelType;
  const   unsigned int        Dimension = 2;

  typedef itk::Image< PixelType, Dimension >   ImageType;
  typedef itk::ImageFileReader< ImageType >    ReaderType;
  typedef itk::ImageToVTKImageFilter< ImageType > ConnectorType;

  ReaderType::Pointer reader = ReaderType::New();
  ConnectorType::Pointer connector = ConnectorType::New();
  reader->SetFileName( argv[1] );
  //reader->Update();

  connector->SetInput(reader->GetOutput());    

  vtkImageViewer *viewer=vtkImageViewer::New();
  vtkRenderWindowInteractor *renderWindowInteractor=vtkRenderWindowInteractor ::New();
  viewer->SetupInteractor(renderWindowInteractor);
  viewer->SetInput(connector->GetOutput());
  viewer->Render();
  viewer->SetColorWindow(255);
  viewer->SetColorLevel(128);
  //renderWindowInteractor->Start();

  return 0;
}

// THE CODE TO READ QUARTER IMAGES, CREATE THE VOLUME AND DISPLAY THE 3 RESLICE OF IT IN 3 DIFFERENT RENDERER
// MedicalSDIView.cpp : implementation of the CMedicalSDIView class
//

#include "stdafx.h"
#include "MedicalSDI.h"

#include "MedicalSDIDoc.h"
#include "MedicalSDIView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMedicalSDIView

IMPLEMENT_DYNCREATE(CMedicalSDIView, CFormView)

BEGIN_MESSAGE_MAP(CMedicalSDIView, CFormView)
 //{{AFX_MSG_MAP(CMedicalSDIView)
 ON_WM_CREATE()
 ON_BN_CLICKED(IDC_BTNDOWN, OnBtndown)
 ON_BN_CLICKED(IDC_BTNUP, OnBtnup)
    //ON_WM_ERASEBKGND() 
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMedicalSDIView construction/destruction

CMedicalSDIView::CMedicalSDIView()
 : CFormView(CMedicalSDIView::IDD)
{
 //{{AFX_DATA_INIT(CMedicalSDIView)
  // NOTE: the ClassWizard will add member initialization here
 //}}AFX_DATA_INIT
 // TODO: add construction code here
  this->volumeRenderer   = vtkRenderer::New();

  this->renWin = vtkRenderWindow::New();
  this->iren = vtkRenderWindowInteractor::New();
  this->v16 = vtkVolume16Reader::New();
  this->skinExtractor = vtkContourFilter::New();
  this->skinNormals = vtkPolyDataNormals::New();
  this->skinStripper = vtkStripper::New();
  this->skinMapper = vtkPolyDataMapper::New();
  this->skin = vtkActor::New();
  this->boneExtractor = vtkContourFilter::New();
  this->boneNormals = vtkPolyDataNormals::New();
  this->boneStripper = vtkStripper::New();
  this->boneMapper = vtkPolyDataMapper::New();
  this->bone = vtkActor::New();
  this->outlineData = vtkOutlineFilter::New();
  this->mapOutline = vtkPolyDataMapper::New();
  this->outline = vtkActor::New();
  this->bwLut = vtkLookupTable::New();
  this->hueLut = vtkLookupTable::New();
  this->satLut = vtkLookupTable::New();
  this->saggitalColors = vtkImageMapToColors::New();
  this->saggital = vtkImageActor::New();
  this->axialColors = vtkImageMapToColors::New();
  this->axial = vtkImageActor::New();
  this->coronalColors = vtkImageMapToColors::New();
  this->coronal = vtkImageActor::New();
  this->aCamera = vtkCamera::New();

  this->coronalShiftScale=vtkImageShiftScale::New(); 
  this->coronalRenderer  = vtkRenderer::New();
  this->coronalImgActor = vtkImageActor::New();
  this->coronalTransform = vtkTransform::New();
  this->coronalSlice = vtkImageReslice::New();

  this->sagittalShiftScale=vtkImageShiftScale::New(); 
  this->sagittalRenderer = vtkRenderer::New();
  this->sagittalImgActor = vtkImageActor::New();
  this->sagittalTransform = vtkTransform::New();
  this->sagittalSlice = vtkImageReslice::New();

  this->axialShiftScale=vtkImageShiftScale::New(); 
  this->axialRenderer    = vtkRenderer::New();
  this->axialImgActor = vtkImageActor::New();
  this->axialTransform = vtkTransform::New();
  this->axialSlice = vtkImageReslice::New();

  this->shiftScale=vtkImageShiftScale::New(); 
  coronalDisp  = 0.0;
  sagittalDisp = 0.0;
  axialDisp    = 0.0;
}

CMedicalSDIView::~CMedicalSDIView()
{
  v16->Delete();
  skinExtractor->Delete();
  skinNormals->Delete();
  skinStripper->Delete();
  skinMapper->Delete();
  skin->Delete();
  boneExtractor->Delete();
  boneNormals->Delete();
  boneStripper->Delete();
  boneMapper->Delete();
  bone->Delete();
  outlineData->Delete();
  mapOutline->Delete();
  outline->Delete();
  bwLut->Delete();
  hueLut->Delete();
  satLut->Delete();
  saggitalColors->Delete();
  saggital->Delete();
  axialColors->Delete();
  axial->Delete();
  coronalColors->Delete();
  coronal->Delete();
  aCamera->Delete();
  renWin->Delete();
  iren->Delete();

  volumeRenderer->Delete();

  coronalRenderer->Delete();
  coronalSlice->Delete();
  coronalTransform->Delete();
  coronalImgActor->Delete();

  sagittalRenderer->Delete();
  sagittalSlice->Delete();
  sagittalTransform->Delete();
  sagittalImgActor->Delete();

  axialRenderer->Delete();
  axialSlice->Delete();
  axialTransform->Delete();
  axialImgActor->Delete();

}

void CMedicalSDIView::DoDataExchange(CDataExchange* pDX)
{
 CFormView::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CMedicalSDIView)
  // NOTE: the ClassWizard will add DDX and DDV calls here
 //}}AFX_DATA_MAP
}

BOOL CMedicalSDIView::PreCreateWindow(CREATESTRUCT& cs)
{
 // TODO: Modify the Window class or styles here by modifying
 //  the CREATESTRUCT cs

 return CFormView::PreCreateWindow(cs);
}

void CMedicalSDIView::OnInitialUpdate()
{
 CFormView::OnInitialUpdate();
 GetParentFrame()->RecalcLayout();
 ResizeParentToFit();

}

/////////////////////////////////////////////////////////////////////////////
// CMedicalSDIView diagnostics

#ifdef _DEBUG
void CMedicalSDIView::AssertValid() const
{
 CFormView::AssertValid();
}

void CMedicalSDIView::Dump(CDumpContext& dc) const
{
 CFormView::Dump(dc);
}

CMedicalSDIDoc* CMedicalSDIView::GetDocument() // non-debug version is inline
{
 ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMedicalSDIDoc)));
 return (CMedicalSDIDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CMedicalSDIView message handlers

void CMedicalSDIView::Pipeline()
{
    renWin->AddRenderer(volumeRenderer);
    renWin->AddRenderer(coronalRenderer);
    renWin->AddRenderer(axialRenderer);
    renWin->AddRenderer(sagittalRenderer);
    iren  ->SetRenderWindow(renWin);

    v16->SetDataDimensions(64,64);
    v16->SetDataByteOrderToLittleEndian();
    v16->SetFilePrefix ("..\\data\\headsq\\quarter");
    v16->SetImageRange(1, 93);
    v16->SetDataSpacing (3.2, 3.2, 1.5);


 skinExtractor->SetInput( v16->GetOutput());
    skinExtractor->SetValue(0, 500);
    skinNormals->SetInput(skinExtractor->GetOutput());
    skinNormals->SetFeatureAngle(60.0);
    skinStripper->SetInput(skinNormals->GetOutput());
    skinMapper->SetInput(skinStripper->GetOutput());
    skinMapper->ScalarVisibilityOff();
    skin->SetMapper(skinMapper);

    skin->GetProperty()->SetDiffuseColor(1, .49, .25);
    skin->GetProperty()->SetSpecular(.3);
    skin->GetProperty()->SetSpecularPower(20);

    boneExtractor->SetInput((vtkDataSet *) v16->GetOutput());
    boneExtractor->SetValue(0, 1150);
    boneNormals->SetInput(boneExtractor->GetOutput());
    boneNormals->SetFeatureAngle(60.0);
    boneStripper->SetInput(boneNormals->GetOutput());
    boneMapper->SetInput(boneStripper->GetOutput());
    boneMapper->ScalarVisibilityOff();
    bone->SetMapper(boneMapper);
    bone->GetProperty()->SetDiffuseColor(1, 1, .9412);

    outlineData->SetInput((vtkDataSet *) v16->GetOutput());
    mapOutline->SetInput(outlineData->GetOutput());
    outline->SetMapper(mapOutline);
    outline->GetProperty()->SetColor(0,0,0);

    bwLut->SetTableRange (0, 2000);
    bwLut->SetSaturationRange (0, 0);
    bwLut->SetHueRange (0, 0);
    bwLut->SetValueRange (0, 1);

    hueLut->SetTableRange (0, 2000);
    hueLut->SetHueRange (0, 1);
    hueLut->SetSaturationRange (1, 1);
    hueLut->SetValueRange (1, 1);

    satLut->SetTableRange (0, 2000);
    satLut->SetHueRange (.6, .6);
    satLut->SetSaturationRange (0, 1);
    satLut->SetValueRange (1, 1);

    saggitalColors->SetInput(v16->GetOutput());
    saggitalColors->SetLookupTable(bwLut);
    saggital->SetInput(saggitalColors->GetOutput());
    saggital->SetDisplayExtent(32,32, 0,63, 0,92);

    axialColors->SetInput(v16->GetOutput());
    axialColors->SetLookupTable(hueLut);
    axial->SetInput(axialColors->GetOutput());
    axial->SetDisplayExtent(0,63, 0,63, 46,46);

    coronalColors->SetInput(v16->GetOutput());
    coronalColors->SetLookupTable(satLut);

    coronal->SetInput(coronalColors->GetOutput());
    coronal->SetDisplayExtent(0,63, 32,32, 0,92);

    aCamera->SetViewUp (0, 0, -1);
    aCamera->SetPosition (0, 1, 0);
    aCamera->SetFocalPoint (0, 0, 0);
    aCamera->ComputeViewPlaneNormal();

    volumeRenderer->AddActor(outline);
    volumeRenderer->AddActor(saggital);
    volumeRenderer->AddActor(axial);
    volumeRenderer->AddActor(coronal);
    volumeRenderer->AddActor(axial);
    volumeRenderer->AddActor(coronal);
    volumeRenderer->AddActor(skin);
    volumeRenderer->AddActor(bone);


  coronalTransform ->Translate(0,coronalDisp,0);
  sagittalTransform->Translate(sagittalDisp,0,0);
  axialTransform   ->Translate(0,0,axialDisp);
// coronal
  coronalSlice->SetInput(v16->GetOutput());
  coronalSlice->SetResliceTransform(coronalTransform);
  coronalSlice->InterpolateOn();
  coronalSlice->SetInterpolationModeToCubic();
  coronalSlice->SetBackgroundLevel(1023);

  coronalShiftScale->SetInput(coronalSlice->GetOutput());
  coronalShiftScale->SetShift(0);
  coronalShiftScale->SetScale(0.07);
  coronalShiftScale->SetOutputScalarTypeToUnsignedChar();

  coronalImgActor->SetInput(coronalShiftScale->GetOutput());
  coronalRenderer->AddActor(coronalImgActor);
  coronalRenderer->InteractiveOff();
// sagital
  sagittalSlice->SetInput(v16->GetOutput());
  sagittalSlice->SetResliceTransform(sagittalTransform);
  sagittalSlice->InterpolateOn();
  sagittalSlice->SetInterpolationModeToCubic();
  sagittalSlice->SetBackgroundLevel(1023);

  sagittalShiftScale->SetInput(sagittalSlice->GetOutput());
  sagittalShiftScale->SetShift(0);
  sagittalShiftScale->SetScale(0.07);
  sagittalShiftScale->SetOutputScalarTypeToUnsignedChar();

  sagittalImgActor->SetInput(sagittalShiftScale->GetOutput());
  sagittalRenderer->AddActor(sagittalImgActor);
  sagittalRenderer->InteractiveOff();
// axial
  axialSlice->SetInput(v16->GetOutput());
  axialSlice->SetResliceTransform(axialTransform);
  axialSlice->InterpolateOn();
  axialSlice->SetInterpolationModeToCubic();
  axialSlice->SetBackgroundLevel(1023);

  
  axialShiftScale->SetInput(axialSlice->GetOutput());
  axialShiftScale->SetShift(0);
  axialShiftScale->SetScale(0.07);
  axialShiftScale->SetOutputScalarTypeToUnsignedChar();

  axialImgActor->SetInput(axialShiftScale->GetOutput());
  axialRenderer->AddActor(axialImgActor);
  axialRenderer->InteractiveOff();
  // Turn off bone for this example.
  bone->VisibilityOff();

  // Set skin to semi-transparent.
  skin->GetProperty()->SetOpacity(0.5);

  // An initial camera view is created.  The Dolly() method moves 
  // the camera towards the FocalPoint, thereby enlarging the image.
  volumeRenderer->SetActiveCamera(aCamera);
  volumeRenderer->ResetCamera ();
  aCamera->Dolly(1.5);


  // Set a background color for the renderer and set the size of the
  // render window (expressed in pixels).
  volumeRenderer->SetBackground(1,1,1);
  //renWin->SetSize(512,512);

  // Note that when camera movement occurs (as it does in the Dolly()
  // method), the clipping planes often need adjusting. Clipping planes
  // consist of two planes: near and far along the view direction. The 
  // near plane clips out objects in front of the plane; the far plane
  // clips out objects behind the plane. This way only what is drawn
  // between the planes is actually rendered.
  volumeRenderer->ResetCameraClippingRange ();

  // interact with data
  //iren->Initialize();
  //iren->Start(); 

}

void CMedicalSDIView::OnDraw(CDC* pDC) 
{
  CPaintDC dc(this); // device context for painting
 
 // TODO: Add your message handler code here
 
  CMedicalSDIDoc* pDoc = GetDocument();
  ASSERT_VALID(pDoc);
 // TODO: Add your specialized code here and/or call the base class
  if ( !this->iren->GetInitialized() )
  {
    CRect rect;

    this->GetClientRect(&rect);
    this->iren->Initialize();
    this->renWin->SetPosition(250,0);
    //this->renWin->SetSize(rect.right-rect.left-100,rect.bottom-rect.top-100);
    this->renWin->SetSize(1024,1024);

    this->volumeRenderer->ResetCamera();
  }

  // Invoke the pipeline
  Pipeline();
  this->renWin->Render();

}

int CMedicalSDIView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
 if (CFormView::OnCreate(lpCreateStruct) == -1)
  return -1;
 
 // TODO: Add your specialized creation code here
  this->volumeRenderer->SetViewport(0.0,0.0,0.5,0.5);
  this->volumeRenderer->SetBackground(0.2,0.3,0.3); 
  this->renWin->AddRenderer(this->volumeRenderer);

  this->sagittalRenderer->SetViewport(0.5,0.0,1.0,0.5);
  this->sagittalRenderer->SetBackground(0.2,0.3,0.3); 
  this->renWin->AddRenderer(this->sagittalRenderer);

  this->axialRenderer->SetViewport(0.0,0.5,0.5,1.0);
  this->axialRenderer->SetBackground(0.2,0.3,0.3); 
  this->renWin->AddRenderer(this->axialRenderer);
  
  this->coronalRenderer->SetViewport(0.5,0.5,1.0,1.0);
  this->coronalRenderer->SetBackground(0.2,0.3,0.3); 
  this->renWin->AddRenderer(this->coronalRenderer);
  
  // setup the parent window
  this->renWin->SetParentId(this->m_hWnd);
  this->iren->SetRenderWindow(this->renWin);
  
  return 0;
}

void CMedicalSDIView::OnBtndown() 
{
 // TODO: Add your control notification handler code here
 coronalDisp  = coronalDisp  - 0.1;
 sagittalDisp = sagittalDisp - 0.1;
 axialDisp    = axialDisp    - 0.1;
 InvalidateRect(NULL,FALSE);
 
}

void CMedicalSDIView::OnBtnup() 
{
 // TODO: Add your control notification handler code here
 coronalDisp  = coronalDisp  + 0.1;
 sagittalDisp = sagittalDisp + 0.1;
 axialDisp    = axialDisp    + 0.1;
 InvalidateRect(NULL,FALSE);
 
}


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.vtk.org/pipermail/vtkusers/attachments/20040614/1a31e127/attachment.htm>


More information about the vtkusers mailing list