[Insight-users] meta image viewed upside down

Luis Ibanez luis.ibanez at kitware.com
Sat, 13 Mar 2004 14:30:17 -0500


This is a multi-part message in MIME format.
--------------090902030109050302080704
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit



Hi Gisses,


About question (1):

Note that the ImageViewer application allows you to flip the
images along the axis just by hitting the 'x' and 'y' keys.
This is of course just a rapid solution for viewing your image,
and not the real long term solution for displaying the data in
the correct orientation.

DICOM provides extra information regarding image orientation,
that is not normally used by the MetaImage reader.
The Iowa group has recently added functionality for extracting
orientation information from DICOM files and pass it through
the MetaDictionary.


You may want lot look at the classes:

MetaDictionary
http://www.itk.org/Insight/Doxygen/html/classitk_1_1MetaDataDictionary.html

OrientImageFilter
http://www.itk.org/Insight/Doxygen/html/classitk_1_1OrientImageFilter.html


Note also that you can read directly your DICOM image
by using the ImageSeriesReader.  Examples on how to do
this are available at


                  Insight/Examples/IO


---

About question (2):

The attached code will help you to implement this visualization
using ITK, VTK and FLTK. This is taken from the preliminary version
of IGSTK (The Image Guided Surgery Toolkit) which is built on top
of ITK and VTK.



Regards,


     Luis




----------------
b gises wrote:

> Hi all,
>  
> i have 2 questions here, thanks for helping
>  
> 1) i read a dicom image using the Image Viewer found in the ITK 
> Application package, but the image viewed is upside down (suppose we'r 
> looking at the top side of a piece of paper with the height(y-axis), 
> width(x-axis), normal to the paper(z-axis)....in this case, the paper is 
> rotated 180 degrees along the x-axis such that we are now viewing the 
> underside of the paper, and the content is upside down also)
> i also tried creating a meta image header (.mhd file) for my dicom image 
> and viewed it in SNAP, the same thing happened.  Can anyone tell me what 
> is wrong and how to deal with this problem, thanks.
>  
>  
> 2) i want to create 3 windows and embed them in my FLTK GUI, such that 
> when i load a volume of slices into the application, the first window 
> will display the top view of the slices(planar view), and the 2nd window 
> will display the front or side view of the slices (can see the slices 
> stack up in the z-axis), the 3rd window will be the volume of slices in 
> 3D space so that one can rotate it in 3D space. The main goal is to 
> segment the image slices, and that the user can select and process each 
> slice in one of the window, and see the results in all the 3 windows.  
> Have anyone any idea what are the classes i should use and how can i 
> deal with this
>  
>  
> Thank you
> Best Regards
> gises
> 
-------------------------------


--------------090902030109050302080704
Content-Type: text/plain;
 name="ImageSliceViewer.cxx"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="ImageSliceViewer.cxx"

#include "ImageSliceViewer.h"

#include "vtkImageData.h"
#include "vtkInteractorStyleImage.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"

#include "InteractorObserver.h"

#include "itkPoint.h"

#include "ClickedPointEvent.h"

namespace ISIS
{


ImageSliceViewer
::ImageSliceViewer()
{
  m_Actor         = vtkImageActor::New();
  m_Renderer      = vtkRenderer::New();
  m_RenderWindow  = vtkRenderWindow::New();

  m_Renderer->AddActor( m_Actor );

  m_Actor->Delete();

  m_Camera = m_Renderer->GetActiveCamera();
  m_Camera->ParallelProjectionOn();

  m_RenderWindow->AddRenderer( m_Renderer );

  m_Renderer->Delete();

  this->SetOrientation( Axial );

  InteractorObserver * observer = InteractorObserver::New();
  observer->SetImageSliceViewer( this );
  m_InteractorObserver = observer;

  m_Notifier      = itk::Object::New();

  m_NearPlane = 0.1;
  m_FarPlane  = 1000.0;

  m_ZoomFactor = 1.0;

  m_Renderer->SetBackground( 0, 0, 0 );
}



ImageSliceViewer
::~ImageSliceViewer()
{
  if( m_RenderWindow )
    {
    m_RenderWindow->Delete();
    }   

  if( m_InteractorObserver )
    {
    m_InteractorObserver->Delete();
    }
}



void
ImageSliceViewer
::Render()
{
  m_Camera->SetClippingRange( 0.1, 100000 );
  m_RenderWindow->Render();
}



vtkRenderer *
ImageSliceViewer
::GetRenderer()
{
  return m_Renderer;
}


void
ImageSliceViewer
::SetInput( vtkImageData * image )
{

  m_Actor->SetInput( image );
  this->SetupCamera();

}



void
ImageSliceViewer
::SetupCamera()
{

  vtkImageData * image = m_Actor->GetInput();

  if ( !image )
    {
    return;
    }

  float spacing[3];
  float origin[3];
  int   dimensions[3];

  image->GetSpacing(spacing);
  image->GetOrigin(origin);
  image->GetDimensions(dimensions);

  double focalPoint[3];
  double position[3];

  for ( unsigned int cc = 0; cc < 3; cc++)
    {
    focalPoint[cc] = origin[cc] + ( spacing[cc] * dimensions[cc] ) / 2.0;
    position[cc]   = focalPoint[cc];
    }

  int idx = 0;
  switch( m_Orientation )
    {
  case Saggital:
      {
      idx = 0;
      m_Camera->SetViewUp (     0,  0,  -1 );
      break;
      }
  case Coronal:
      {
      idx = 1;
      m_Camera->SetViewUp (     0,  0,  -1 );
      break;
      }
  case Axial:
      {
      idx = 2;
      m_Camera->SetViewUp (     0,  -1,  0 );
      break;
      }
    }

  const double distanceToFocalPoint = 1000;
  position[idx] += distanceToFocalPoint;

  m_Camera->SetPosition (   position );
  m_Camera->SetFocalPoint ( focalPoint );

#define myMAX(x,y) (((x)>(y))?(x):(y))  

   int d1 = (idx + 1) % 3;
   int d2 = (idx + 2) % 3;
 
  double max = myMAX( 
    spacing[d1] * dimensions[d1],
    spacing[d2] * dimensions[d2]);


  m_Camera->SetParallelScale( max / 2  * m_ZoomFactor );

}


void
  ImageSliceViewer
::SetZoomFactor( double factor )
{
  m_ZoomFactor = factor;
}



void
  ImageSliceViewer
::SetInteractor( vtkRenderWindowInteractor * interactor )
{
  m_RenderWindow->SetInteractor( interactor );

  vtkInteractorStyleImage * interactorStyle = vtkInteractorStyleImage::New();
  interactor->SetInteractorStyle( interactorStyle );
  interactorStyle->Delete();
  interactor->AddObserver( ::vtkCommand::LeftButtonPressEvent, m_InteractorObserver );
  interactor->AddObserver( ::vtkCommand::LeftButtonReleaseEvent, m_InteractorObserver );
  interactor->AddObserver( ::vtkCommand::MouseMoveEvent, m_InteractorObserver );
}





void
  ImageSliceViewer
::SetOrientation( OrientationType orientation )
{
  m_Orientation = orientation;
  this->SetupCamera();
}




void
  ImageSliceViewer
::SelectSlice( int slice )
{
  if (!m_Actor->GetInput()) 
    {
    return;     // return, if no image is loaded yet.
    }

  int ext[6];
  m_Actor->GetInput()->GetExtent( ext );

  switch( m_Orientation )
    {
  case Saggital:
      if ((slice>=ext[0]) && (slice<=ext[1]))
      {
        ext[0] = slice;
        ext[1] = slice;
        m_SliceNum = slice;
      }
      break;
  case Coronal:
      if ((slice>=ext[2]) && (slice<=ext[3]))
      {
        ext[2] = slice;
        ext[3] = slice;
        m_SliceNum = slice;
      }
      break;
  case Axial:
      if ((slice>=ext[4]) && (slice<=ext[5]))
      {
        ext[4] = slice;
        ext[5] = slice;
        m_SliceNum = slice;
      }
      break;
    }

  m_Actor->SetDisplayExtent( ext );
}


void
ImageSliceViewer
::SelectPoint( int x, int y )
{
  if (!m_Actor->GetInput()) 
    {
    return;     // return, if no image is loaded yet.
    }

  // Invert the y coordinate (vtk uses opposite y as FLTK)
  int* winsize = m_RenderWindow->GetSize();
  y = winsize[1] - y;

  // Convert display point to world point
  double wpoint[4];
  const double z = m_SliceNum / ( m_FarPlane - m_NearPlane );
  m_Renderer->SetDisplayPoint( x, y, 0 );
  m_Renderer->DisplayToWorld();
  m_Renderer->GetWorldPoint( wpoint );

  // Fix camera Z coorinate to match the current slice
  float spacing[3]={1,1,1};
  float origin[3] ={0,0,0};

  int dimensions[3] = { 100, 100, 100 };
  if ( m_Actor->GetInput() )
    {
    m_Actor->GetInput()->GetSpacing(spacing);
    m_Actor->GetInput()->GetOrigin(origin);
    m_Actor->GetInput()->GetDimensions(dimensions);
    }

  int idx = 0;
  switch( m_Orientation )
    {
  case Saggital:
      {
      idx = 0;
      break;
      }
  case Coronal:
      {
      idx = 1;
      break;
      }
  case Axial:
      {
      idx = 2;
      break;
      }
    }
  double realz = m_SliceNum * spacing[idx] + origin[idx];
  wpoint[idx] = realz;

  // At this point we have 3D position in the variable wpoint
  this->SelectPoint(wpoint[0], wpoint[1], wpoint[2]);

  m_Notifier->InvokeEvent( ClickedPointEvent() );
}

void  
ImageSliceViewer::SelectPoint( double x, double y, double z )
{
  m_SelectPoint[0] = x;
  m_SelectPoint[1] = y;
  m_SelectPoint[2] = z;
}

void 
ImageSliceViewer::GetSelectPoint(double data[3])
{
  for(int i=0; i<3; i++)
  {
    data[i] = m_SelectPoint[i];
  }
}




unsigned long 
ImageSliceViewer::AddObserver( const itk::EventObject & event, itk::Command * command)
{
  return m_Notifier->AddObserver( event, command );
}


}


--------------090902030109050302080704
Content-Type: text/plain;
 name="ImageSliceViewer.h"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="ImageSliceViewer.h"


#ifndef __ISIS_ImageSliceViewer_h__
#define __ISIS_ImageSliceViewer_h__

#include "vtkCamera.h"
#include "vtkRenderer.h"
#include "vtkImageActor.h"
#include "vtkRenderWindow.h"
#include "vtkCommand.h"
#include "vtkInteractorStyleImage.h"

#include "itkEventObject.h"
#include "itkCommand.h"

namespace ISIS
{
	/** \class ImageSlicerViewer
	    \brief This class visualizes a volume
      \warning
	    \sa everyone needs to look at doxygen tags
  */

class ImageSliceViewer
{
public:

  typedef enum
    { 
    Saggital, 
    Coronal, 
    Axial 
    } 
    OrientationType;

  ImageSliceViewer( void );

  virtual ~ImageSliceViewer( void );

  void SetInput( vtkImageData * image );

  void SelectSlice( int slice );

  void SelectPoint( int x, int y);

  virtual void SetInteractor( vtkRenderWindowInteractor * interactor );

  void Render( void );

  void SetOrientation( OrientationType orientation );

  vtkRenderer *  GetRenderer( void );

  virtual void SelectPoint( double x, double y, double z );

  virtual void  GetSelectPoint(double data[3]); 
  
  unsigned long AddObserver( const itk::EventObject & event, itk::Command *);

  virtual void SetZoomFactor( double factor );

protected:

  void SetupCamera( void );


public:

  vtkImageActor     * m_Actor;

  vtkRenderer       * m_Renderer;

  vtkCamera         * m_Camera;

  vtkRenderWindow   * m_RenderWindow;

  OrientationType     m_Orientation;

  int                 m_SliceNum;

  vtkCommand        * m_InteractorObserver;

  itk::Object::Pointer   m_Notifier;

  double              m_NearPlane;

  double              m_FarPlane;

  double              m_ZoomFactor;

  double               m_SelectPoint[3];
};


}  // end namespace ISIS

#endif




--------------090902030109050302080704--