ReadDICOMSeries
VTKExamples/Cxx/IO/ReadDICOMSeries
Description¶
This example demonstates how to read a series of DICOM images and how to scroll with the mousewheel or the up/down keys through all slices. Sample data are available as a zipped file (977 kB, 40 slices): DicomTestImages
Seealso
Code¶
ReadDICOMSeries.cxx
// // This example demonstrates how to read a series of dicom images // and how to scroll with the mousewheel or the up/down keys // through all slices // // some standard vtk headers #include <vtkSmartPointer.h> #include <vtkObjectFactory.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkRenderer.h> #include <vtkActor.h> // headers needed for this example #include <vtkImageViewer2.h> #include <vtkDICOMImageReader.h> #include <vtkInteractorStyleImage.h> #include <vtkActor2D.h> #include <vtkTextProperty.h> #include <vtkTextMapper.h> // needed to easily convert int to std::string #include <sstream> // helper class to format slice status message class StatusMessage { public: static std::string Format(int slice, int maxSlice) { std::stringstream tmp; tmp << "Slice Number " << slice + 1 << "/" << maxSlice + 1; return tmp.str(); } }; // Define own interaction style class myVtkInteractorStyleImage : public vtkInteractorStyleImage { public: static myVtkInteractorStyleImage* New(); vtkTypeMacro(myVtkInteractorStyleImage, vtkInteractorStyleImage); protected: vtkImageViewer2* _ImageViewer; vtkTextMapper* _StatusMapper; int _Slice; int _MinSlice; int _MaxSlice; public: void SetImageViewer(vtkImageViewer2* imageViewer) { _ImageViewer = imageViewer; _MinSlice = imageViewer->GetSliceMin(); _MaxSlice = imageViewer->GetSliceMax(); _Slice = _MinSlice; cout << "Slicer: Min = " << _MinSlice << ", Max = " << _MaxSlice << std::endl; } void SetStatusMapper(vtkTextMapper* statusMapper) { _StatusMapper = statusMapper; } protected: void MoveSliceForward() { if(_Slice < _MaxSlice) { _Slice += 1; cout << "MoveSliceForward::Slice = " << _Slice << std::endl; _ImageViewer->SetSlice(_Slice); std::string msg = StatusMessage::Format(_Slice, _MaxSlice); _StatusMapper->SetInput(msg.c_str()); _ImageViewer->Render(); } } void MoveSliceBackward() { if(_Slice > _MinSlice) { _Slice -= 1; cout << "MoveSliceBackward::Slice = " << _Slice << std::endl; _ImageViewer->SetSlice(_Slice); std::string msg = StatusMessage::Format(_Slice, _MaxSlice); _StatusMapper->SetInput(msg.c_str()); _ImageViewer->Render(); } } virtual void OnKeyDown() { std::string key = this->GetInteractor()->GetKeySym(); if(key.compare("Up") == 0) { //cout << "Up arrow key was pressed." << endl; MoveSliceForward(); } else if(key.compare("Down") == 0) { //cout << "Down arrow key was pressed." << endl; MoveSliceBackward(); } // forward event vtkInteractorStyleImage::OnKeyDown(); } virtual void OnMouseWheelForward() { //std::cout << "Scrolled mouse wheel forward." << std::endl; MoveSliceForward(); // don't forward events, otherwise the image will be zoomed // in case another interactorstyle is used (e.g. trackballstyle, ...) // vtkInteractorStyleImage::OnMouseWheelForward(); } virtual void OnMouseWheelBackward() { //std::cout << "Scrolled mouse wheel backward." << std::endl; if(_Slice > _MinSlice) { MoveSliceBackward(); } // don't forward events, otherwise the image will be zoomed // in case another interactorstyle is used (e.g. trackballstyle, ...) // vtkInteractorStyleImage::OnMouseWheelBackward(); } }; vtkStandardNewMacro(myVtkInteractorStyleImage); int main(int argc, char* argv[]) { // Verify input arguments if ( argc != 2 ) { std::cout << "Usage: " << argv[0] << " FolderName" << std::endl; return EXIT_FAILURE; } std::string folder = argv[1]; //std::string folder = "C:\\VTK\\vtkdata-5.8.0\\Data\\DicomTestImages"; // Read all the DICOM files in the specified directory. vtkSmartPointer<vtkDICOMImageReader> reader = vtkSmartPointer<vtkDICOMImageReader>::New(); reader->SetDirectoryName(folder.c_str()); reader->Update(); // Visualize vtkSmartPointer<vtkImageViewer2> imageViewer = vtkSmartPointer<vtkImageViewer2>::New(); imageViewer->SetInputConnection(reader->GetOutputPort()); // slice status message vtkSmartPointer<vtkTextProperty> sliceTextProp = vtkSmartPointer<vtkTextProperty>::New(); sliceTextProp->SetFontFamilyToCourier(); sliceTextProp->SetFontSize(20); sliceTextProp->SetVerticalJustificationToBottom(); sliceTextProp->SetJustificationToLeft(); vtkSmartPointer<vtkTextMapper> sliceTextMapper = vtkSmartPointer<vtkTextMapper>::New(); std::string msg = StatusMessage::Format(imageViewer->GetSliceMin(), imageViewer->GetSliceMax()); sliceTextMapper->SetInput(msg.c_str()); sliceTextMapper->SetTextProperty(sliceTextProp); vtkSmartPointer<vtkActor2D> sliceTextActor = vtkSmartPointer<vtkActor2D>::New(); sliceTextActor->SetMapper(sliceTextMapper); sliceTextActor->SetPosition(15, 10); // usage hint message vtkSmartPointer<vtkTextProperty> usageTextProp = vtkSmartPointer<vtkTextProperty>::New(); usageTextProp->SetFontFamilyToCourier(); usageTextProp->SetFontSize(14); usageTextProp->SetVerticalJustificationToTop(); usageTextProp->SetJustificationToLeft(); vtkSmartPointer<vtkTextMapper> usageTextMapper = vtkSmartPointer<vtkTextMapper>::New(); usageTextMapper->SetInput("- Slice with mouse wheel\n or Up/Down-Key\n- Zoom with pressed right\n mouse button while dragging"); usageTextMapper->SetTextProperty(usageTextProp); vtkSmartPointer<vtkActor2D> usageTextActor = vtkSmartPointer<vtkActor2D>::New(); usageTextActor->SetMapper(usageTextMapper); usageTextActor->GetPositionCoordinate()->SetCoordinateSystemToNormalizedDisplay(); usageTextActor->GetPositionCoordinate()->SetValue( 0.05, 0.95); // create an interactor with our own style (inherit from vtkInteractorStyleImage) // in order to catch mousewheel and key events vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); vtkSmartPointer<myVtkInteractorStyleImage> myInteractorStyle = vtkSmartPointer<myVtkInteractorStyleImage>::New(); // make imageviewer2 and sliceTextMapper visible to our interactorstyle // to enable slice status message updates when scrolling through the slices myInteractorStyle->SetImageViewer(imageViewer); myInteractorStyle->SetStatusMapper(sliceTextMapper); imageViewer->SetupInteractor(renderWindowInteractor); // make the interactor use our own interactorstyle // cause SetupInteractor() is defining it's own default interatorstyle // this must be called after SetupInteractor() renderWindowInteractor->SetInteractorStyle(myInteractorStyle); // add slice status message and usage hint message to the renderer imageViewer->GetRenderer()->AddActor2D(sliceTextActor); imageViewer->GetRenderer()->AddActor2D(usageTextActor); // initialize rendering and interaction //imageViewer->GetRenderWindow()->SetSize(400, 300); //imageViewer->GetRenderer()->SetBackground(0.2, 0.3, 0.4); imageViewer->Render(); imageViewer->GetRenderer()->ResetCamera(); imageViewer->Render(); renderWindowInteractor->Start(); return EXIT_SUCCESS; }
CMakeLists.txt¶
cmake_minimum_required(VERSION 2.8) PROJECT(ReadDICOMSeries) find_package(VTK REQUIRED) include(${VTK_USE_FILE}) add_executable(ReadDICOMSeries MACOSX_BUNDLE ReadDICOMSeries.cxx) target_link_libraries(ReadDICOMSeries ${VTK_LIBRARIES})
Download and Build ReadDICOMSeries¶
Danger
The generation of tar files has not been ported to the new VTKExamples. Some tarballs may be missing or out-of-date.
Click here to download ReadDICOMSeries and its CMakeLists.txt file. Once the tarball ReadDICOMSeries.tar has been downloaded and extracted,
cd ReadDICOMSeries/build
If VTK is installed:
cmake ..
If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:
cmake -DVTK_DIR:PATH=/home/me/vtk_build ..
Build the project:
make
and run it:
./ReadDICOMSeries
WINDOWS USERS PLEASE NOTE: Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.