Thursday, 4 July 2013

ITK reader- VTK Viewer - Qt GUI

We are using itkImageSeriesReader which support different formats DICOM, JPEG, TIFF, PNG to read in a series but size of images should be same. Then itkImageToVTKImageFilter will convert data from itk to vtk image format that we will visualize through VTK+Qt pipeline. In VTK you can try both viewers just by uncomment two lines of vtkImageViewer2 and comment lines of vtkResliceImageViewer.
Application have :
1. main.cpp
2. mainwindow.h
3. mainwindow.cpp
4. mainwindow.ui
5. CmakeLists.txt
Step 1. Copy XML code of ui form into a text editor and save it as mainwindow.ui format. It will create ui.
Step 2. Create headers, cpp and cmake files.
Step 3. Cmake to generate project file, build and run.
Here is code

mainwindow.ui 

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>419</width>
    <height>350</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <widget class="QVTKWidget" name="qVTK1">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>10</y>
      <width>381</width>
      <height>291</height>
     </rect>
    </property>
    <property name="sizePolicy">
     <sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
      <horstretch>0</horstretch>
      <verstretch>0</verstretch>
     </sizepolicy>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>419</width>
     <height>21</height>
    </rect>
   </property>
   <widget class="QMenu" name="menu_File">
    <property name="title">
     <string>&amp;File</string>
    </property>
    <widget class="QMenu" name="menu_Open">
     <property name="title">
      <string>&amp;Open</string>
     </property>
     <addaction name="actionDICOM_Sequence"/>
    </widget>
    <addaction name="menu_Open"/>
    <addaction name="separator"/>
    <addaction name="actionExit"/>
   </widget>
   <addaction name="menu_File"/>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
  <action name="actionJPEG">
   <property name="text">
    <string>JPEG</string>
   </property>
  </action>
  <action name="actionDICOM">
   <property name="text">
    <string>DICOM</string>
   </property>
  </action>
  <action name="actionDICOM_Sequence">
   <property name="text">
    <string>DICOM Sequence</string>
   </property>
  </action>
  <action name="actionExit">
   <property name="text">
    <string>Exit</string>
   </property>
  </action>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <customwidgets>
  <customwidget>
   <class>QVTKWidget</class>
   <extends>QWidget</extends>
   <header>QVTKWidget.h</header>
   <container>1</container>
   <slots>
    <slot>sopenimage()</slot>
   </slots>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>


mainwindow.h


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "vtkSmartPointer.h"

class vtkImageViewer2;
class vtkResliceImageViewer;

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
   
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
   
private slots:
    int DICOMseq();
private:

      //vtkImageViewer2 *image_view;
    vtkSmartPointer<vtkResliceImageViewer> image_view;
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp
//Qt
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QFileDialog>
#include<QFileInfoList>
#include<QDir>
#include<iostream>
//ITK
#include "itkImage.h"
#include "itkImageSeriesReader.h"
#include "itkImageToVTKImageFilter.h"
//VTK
#include "vtkImageViewer2.h"
#include "vtkResliceImageViewer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"

using namespace std;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
  
      //image_view = vtkImageViewer2::New();
      image_view = vtkSmartPointer<vtkResliceImageViewer>::New();
     
   //Qt Signal slot    
      connect(ui->actionDICOM_Sequence,SIGNAL(triggered()),this, SLOT(DICOMseq()));
      connect(ui->actionExit,SIGNAL(triggered()),this, SLOT(close()));
}

MainWindow::~MainWindow()
{
    delete ui;
}


int MainWindow::DICOMseq()
{
      typedef signed short InputPixelType;//Pixel Type
      const unsigned int InputDimension = 3;//Dimension of image
      typedef itk::Image< InputPixelType, InputDimension > InputImageType;//Image Type

      typedef itk::ImageSeriesReader< InputImageType > ReaderType;//Reader of Image Type
      ReaderType::Pointer reader = ReaderType::New();

      //Replacement of name generator of ITK
      QDir dir("Dir");
      dir=QFileDialog::getExistingDirectory(0,"Select Folder: ");
      QFileInfoList list = dir.entryInfoList(QDir::Dirs| QDir::Files | QDir::NoDotAndDotDot);

            std::vector<std::string> names;
         foreach(QFileInfo finfo, list)
                  {
                        std::string str=dir.path().toStdString().c_str();
                        str=str+"/";
                        names.push_back(str+finfo.fileName().toStdString().c_str());
                  }

      reader->SetFileNames( names );
      //Exceptional handling
      try
      {
            reader->Update();
      }
      catch (itk::ExceptionObject & e)
      {
            std::cerr << "exception in file reader " << std::endl;
            std::cerr << e << std::endl;
            return EXIT_FAILURE;
      }

    /*
     
      You can impliment your Filter here and connect its output to connector below.
     
      */

      //connector to convert ITK image data to VTK image data
      typedef itk::ImageToVTKImageFilter<InputImageType> ConnectorType;
      ConnectorType::Pointer connector= ConnectorType::New();
      connector->SetInput( reader->GetOutput() );//Set ITK reader Output to connector you can replace it with filter
     
      //Exceptional handling
      try
      {
            connector->Update();
      }
      catch (itk::ExceptionObject & e)
      {
            std::cerr << "exception in file reader " << std::endl;
            std::cerr << e << std::endl;
            return EXIT_FAILURE;
      }
      //deep copy connector's output to an image else connector will go out of scope
      //and vanish it will cause error while changing slice
      vtkImageData * image = vtkImageData::New();
      image->DeepCopy(connector->GetOutput());
     
      //set VTK Viewer to QVTKWidget in Qt's UI
      ui->qVTK1->SetRenderWindow(image_view->GetRenderWindow());
      image_view->SetupInteractor(ui->qVTK1->GetRenderWindow()->GetInteractor());
      //Set input image to VTK viewer
      image_view->SetInput(image);
      image_view->SetSlice(image_view->GetSliceMax()/2);
      image_view->GetRenderer()->ResetCamera();
      image_view->Render();


    ui->qVTK1->update();
      return EXIT_SUCCESS;
}

main.cpp

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
   
    return a.exec();
}

CmakeLists.txt

cmake_minimum_required(VERSION 2.6)
PROJECT(main)

IF(NOT VTK_BINARY_DIR)
FIND_PACKAGE(VTK)
IF(NOT VTK_DIR)
  MESSAGE(FATAL_ERROR "Please set VTK_DIR.")
ENDIF(NOT VTK_DIR)
INCLUDE(${VTK_USE_FILE})
ENDIF(NOT VTK_BINARY_DIR)
FIND_PACKAGE ( ITK)
IF ( ITK_FOUND)
INCLUDE( ${USE_ITK_FILE} )
ENDIF( ITK_FOUND)

SET(QT_QMAKE_EXECUTABLE ${VTK_QT_QMAKE_EXECUTABLE} CACHE FILEPATH "")
SET(QT_MOC_EXECUTABLE ${VTK_QT_MOC_EXECUTABLE} CACHE FILEPATH "")
SET(QT_UIC_EXECUTABLE ${VTK_QT_UIC_EXECUTABLE} CACHE FILEPATH "")

FIND_PACKAGE(Qt4 REQUIRED)
INCLUDE(${QT_USE_FILE})
# Set your files and resources here
SET(Main main.cpp mainwindow.cpp)
SET(MainUI mainwindow.ui)
SET(MainH mainwindow.h)
INCLUDE_DIRECTORIES(
  ${QT_INCLUDE_DIR}
  ${CMAKE_CURRENT_BINARY_DIR}
  ${CMAKE_CURRENT_SOURCE_DIR}
)
QT4_WRAP_UI(UISrcs ${MainUI})
QT4_WRAP_CPP(MOCSrcs ${MainH} )
SOURCE_GROUP("Resources" FILES
  ${MainUI}
)
SOURCE_GROUP("Generated" FILES
  ${UISrcs}
  ${MOCSrcs}
  ${RCS_SOURCES}
)
ADD_EXECUTABLE( main ${Main} ${UISrcs} ${MOCSrcs})
TARGET_LINK_LIBRARIES( main QVTK ${ITK_LIBRARIES}  )

12 comments:

  1. Nice post on VTK Itk and qt .
    Can i comiple ITK-VTK application from Qt creater?

    ReplyDelete
    Replies
    1. Yes you can by providing ITK VTK libraries' path in .pro file to use creator.

      Delete
    2. Do you have example of .pro file. if You have please send me the file how to add these itk vtk libraries in . pro file.
      I create a simple vtk app add vtk libraries in .pro file it work . But when create a itk adding the header file it doesnot work. Please Help Me. I m new to itk vtk and Qt.
      Thanks for your Help .

      Delete
    3. HTH http://itk-insight-users.2283740.n2.nabble.com/Including-ITK-in-QT-Creator-Project-ld-error-OSX-tt7409758.html#a7580667

      Delete
  2. Hi That post is wonderful !
    Was wondering if you heard about GDCMIOFactory registered error ? Because I cannot read dicom image.

    ReplyDelete
  3. Thank you for this post !
    I got this error "‘class vtkResliceImageViewer’ has no member named ‘SetInput’"
    I use ITK 4.5 with VTK 6.1

    ReplyDelete
    Replies
    1. USE SetInputData

      Delete
    2. Great ! it works without changing 'setInput', but the image view is upside (tested for DICOM)
      I use ITK 4.5 VTK 6.1 QT 5.2.1

      Delete
    3. Hi have you changed in the CmakeLists.txt for Qt version?

      Delete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Nice post.
    Great Help.

    CmakeLists.txt

    it is INCLUDE(${ITK_USE_FILE}) not INCLUDE(${USE_ITK_FILE})

    ReplyDelete