#include "wxImageViewerInteractor.h" #include "wxVtkImageFlip.h" #include "wxVtkPageView.h" #include #include #include #include #include #include #include #include #include #include #include #include "vtkViewImage2DWithTracer.h" #include "vtkViewImage3D.h" #include #include #include #include "wxImageThumbnail.h" #include #include #include #include #include "GetPot.h" //#include #include wxImageViewerInteractor::wxImageViewerInteractor(wxWindow* parent, int id, const wxPoint& pos, const wxSize& size, long styl, const wxString& title) : wxImageViewer( parent, id, pos, size, styl, title ) { m_Thumbnail = new wxImageThumbnail ( this->m_MainNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, styl, wxT ("Preview") ); m_MainNotebook->AddPage ( m_Thumbnail, wxT ("Preview"), true ); m_InteractionStyle = vtkViewImage2D::SELECT_INTERACTION; itk::AnalyzeImageIOFactory::RegisterOneFactory(); itk::GDCMImageIOFactory::RegisterOneFactory(); } int wxImageViewerInteractor::SetCmdLine (int argc, char** argv) { GetPot cl(argc, argv); // argument parser if( cl.search(2, "--help", "-h") ) { std::cout << "Usage: " << argv[0] << " -mod imageviewer image1 image2 ... imageN\n" << " or: " << argv[0] << " -mod imageviewer -dicom -saveall -split" << std::endl; return -1; } const char* dicomRoot = cl.follow ("NoDicom", 2, "-dicom", "-DICOM"); const bool split = cl.search (2,"-split","-SPLIT"); const bool saveall = cl.search (2,"-saveall","-SAVEALL"); const char* directory = "./"; if( saveall ) { directory = cl.follow ("./", 2, "-saveall", "-SAVEALL"); } if( strcmp (dicomRoot, "NoDicom")!=0 ) { itk::GDCMImporter::Pointer myImporter = itk::GDCMImporter::New(); myImporter->RecursiveOn(); myImporter->SetInputDirectory (dicomRoot); if( saveall ) { try { myImporter->Scan(); if( split ) { myImporter->SplitVolumeByPositionConsistency ( myImporter->GetDICOMVolumeList()[0] ); } myImporter->SaveAll( directory ); } catch (itk::ExceptionObject &e) { std::cerr << e; return -1; } return -1; // one wants to exit now. } else { try { myImporter->Scan(); if( split ) { myImporter->SplitVolumeByPositionConsistency ( myImporter->GetDICOMVolumeList()[0] ); } myImporter->BuildAllVolumes(); } catch (itk::ExceptionObject &e) { std::cerr << e; return -1; } std::vector outputVolumes = myImporter->GetDICOMVolumeList(); for (unsigned int i=0; iGetImage().IsNull() ) { itk::ImageToVTKImageFilter::Pointer myConverter = itk::ImageToVTKImageFilter::New(); myConverter->SetInput( outputVolumes[i]->GetImage() ); try { myConverter->Update(); vtkImageData* input = vtkImageData::New(); input->DeepCopy ( myConverter->GetOutput() ); this->AddImage (input, outputVolumes[i]->GetDescription().c_str()); input->Delete(); } catch (itk::ExceptionObject &e) { std::cerr << e; } } } } } else { m_MainNotebook->Show(false); for( int i=1; iOpenImage (filename); } m_MainNotebook->SetSelection(0); m_MainNotebook->Show(true); } return 0; } void wxImageViewerInteractor::OnToolBarOpenVol(wxCommandEvent& event) { wxArrayString filenames = this->GetOpenFileNames(this, wxT("Choose an image"), wxSupportedImageExtensionsFilter); if( filenames.IsEmpty() ) { return; } m_MainNotebook->Show(false); // create a progress bar wxProgressDialog* dialog = new wxProgressDialog (wxT ("Opening images, please wait..."), wxT (""), 100, this, wxPD_APP_MODAL|wxPD_AUTO_HIDE|wxPD_SMOOTH|wxPD_CAN_ABORT); bool keepGoing = dialog->Update (0); unsigned int Nimages = filenames.Count(); double step = 100.0/(double)(Nimages); for( unsigned int i=0; iOpenImage (filenames[i].c_str()); keepGoing = dialog->Update ( (int)(step*(double)i) ); } m_MainNotebook->SetSelection(m_MainNotebook->GetPageCount()-1); m_MainNotebook->Show(true); dialog->Destroy(); } void wxImageViewerInteractor::OpenImage(const char* filename) { /* As their might be more than one volume in an image, we read 4D images, and then split them into 3D volumes if the 4th dimension is greater than 1. */ itk::ImageFileReader::Pointer reader = itk::ImageFileReader::New(); reader->SetFileName (filename); try { std::cout << "Reading: " << filename << std::endl; reader->Update(); } catch (itk::ExceptionObject & e) { std::cerr << e; return; } // here we look for the 4th dimension: Image4DType::Pointer image = reader->GetOutput(); Image4DType::SizeType size = image->GetLargestPossibleRegion().GetSize(); unsigned int nVolumes = size[3]; // split the 4D volume into 3D volumes Image4DType::RegionType regionToExtract = image->GetLargestPossibleRegion(); Image4DType::IndexType index; index[0] = 0; index[1] = 0; index[2] = 0; index[3] = 0; size[3] = 0; regionToExtract.SetSize (size); regionToExtract.SetIndex (index); if( nVolumes==0 ) { //throw itk::ExceptionObject (__FILE__,__LINE__,"Error: 4th dimension is zero, and should be at least one."); this->DisplayErrorMessage (this, wxT ("Error: No image present in this file") ); return; } for( unsigned int n=0; n ExtractImageType; regionToExtract.SetIndex (3,n); ExtractImageType::Pointer myExtractor = ExtractImageType::New(); myExtractor->SetExtractionRegion (regionToExtract); myExtractor->SetInput (image); try { myExtractor->Update(); } catch (itk::ExceptionObject &e) { std::cerr << e; throw itk::ExceptionObject (__FILE__,__LINE__,"Error while extracting a 3D volume from a 4D image."); } itk::ImageToVTKImageFilter::Pointer myConverter = itk::ImageToVTKImageFilter::New(); myConverter->SetInput( myExtractor->GetOutput() ); myConverter->Update(); vtkImageData* input = vtkImageData::New(); input->DeepCopy ( myConverter->GetOutput() ); wxString name = wxT(filename); wxString basename = this->GetNameFromFile( name ); this->AddImage ( input, basename.c_str() ); input->Delete(); } } wxVtkPageView* wxImageViewerInteractor::CreateNewVtkPage() { return new wxVtkPageView(m_MainNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize/*m_MainNotebook->GetPageBestSize()*/); } void wxImageViewerInteractor::OnPageChanged(wxAuiNotebookEvent& event) { } void wxImageViewerInteractor::OnDeletePage(wxAuiNotebookEvent& event) { if( m_MainNotebook->GetSelection()==0 ) { event.Veto(); return; } /* int res = wxMessageBox(wxT("Are you sure you want to close this tab?"), wxT("wxImageViewer"), wxYES_NO, this); if (res != wxYES) { event.Veto(); return; } else { m_Thumbnail->RemoveImage ( event.GetSelection()-1 ); } */ m_Thumbnail->RemoveImage ( event.GetSelection()-1 ); } void wxImageViewerInteractor::OnSelectInteractionEvent(wxCommandEvent& event) { m_InteractionStyle = vtkViewImage2D::SELECT_INTERACTION; int npages = m_MainNotebook->GetPageCount(); for( int i=0; i(m_MainNotebook->GetPage(i)); if( page ) { page->SetInteractionStyleToSelector(); } } m_Thumbnail->SetInteractionStyle (vtkViewImage2D::SELECT_INTERACTION); } void wxImageViewerInteractor::OnWindowLevelInteractionEvent(wxCommandEvent& event) { m_InteractionStyle = vtkViewImage2D::WINDOW_LEVEL_INTERACTION; int npages = m_MainNotebook->GetPageCount(); for( int i=0; i(m_MainNotebook->GetPage(i)); if( page ) { page->SetInteractionStyleToWindowLevel(); } } m_Thumbnail->SetInteractionStyle (vtkViewImage2D::WINDOW_LEVEL_INTERACTION); } void wxImageViewerInteractor::OnZoomInteractionEvent(wxCommandEvent& event) { m_InteractionStyle = vtkViewImage2D::ZOOM_INTERACTION; int npages =m_MainNotebook->GetPageCount(); for( int i=0; i(m_MainNotebook->GetPage(i)); if( page ) { page->SetInteractionStyleToZoom(); } } m_Thumbnail->SetInteractionStyle (vtkViewImage2D::ZOOM_INTERACTION); } void wxImageViewerInteractor::OnFullPageInteractionEvent(wxCommandEvent& event) { int npages = m_MainNotebook->GetPageCount(); for( int i=0; i(m_MainNotebook->GetPage(i)); if( page ) { page->SetInteractionStyleToFullPage(); } } } void wxImageViewerInteractor::On3DVolumeRendering(wxCommandEvent& event) { wxVtkPageView* page = dynamic_cast(m_MainNotebook->GetPage(m_MainNotebook->GetSelection())); if( !page ) return; vtkViewImage3D* view = page->GetView4(); if (!view) return; bool isVR = (view->GetRenderingMode() == vtkViewImage3D::VOLUME_RENDERING); if (isVR) view->SetRenderingMode(vtkViewImage3D::PLANAR_RENDERING); else view->SetRenderingMode(vtkViewImage3D::VOLUME_RENDERING); view->Render(); } void wxImageViewerInteractor::AddPreviewThumbnail ( wxVtkPageView* pageView, const char* filename) { if( !pageView ) { return; } m_Thumbnail->AddImage ( pageView->GetInput(), filename); m_Thumbnail->Render(); } void wxImageViewerInteractor::AddImage (vtkImageData* image, const char* filename) { wxVtkPageView* newPage = this->CreateNewVtkPage(); newPage->SetImageName (filename); wxString number; number.Printf ("%d-", (int)m_MainNotebook->GetPageCount()); wxString basename = number+wxT (filename); m_MainNotebook->AddPage( newPage, basename, true); newPage->SetInput( image ); newPage->SetInteractionStyle ( m_InteractionStyle ); #ifndef __WXMAC__ newPage->GetView4()->SetCubeVisibility (true); #endif this->AddPreviewThumbnail (newPage, basename.c_str()); } void wxImageViewerInteractor::OnToolBarOpenDICOM(wxCommandEvent& event) { wxVtkDICOMImporter* myimporter = new wxVtkDICOMImporter (this); if( myimporter->GetReturnCode()!=wxID_OK ) { myimporter->Destroy(); return; } m_MainNotebook->Show(false); // create a progress bar wxProgressDialog* dialog = new wxProgressDialog (wxT ("Please wait"), wxT ("Loading volumes..."), 100, this, wxPD_APP_MODAL|wxPD_AUTO_HIDE|wxPD_SMOOTH|wxPD_CAN_ABORT); bool keepGoing = dialog->Update (0); unsigned int Nimages = myimporter->GetOutputs().size(); double step = 100.0/(double)(Nimages); for (unsigned int i=0; iGetOutput(i)) { continue; } typedef itk::CastImageFilter CastFilterType; CastFilterType::Pointer myCast = CastFilterType::New(); myCast->SetInput (myimporter->GetOutput(i)); itk::ImageToVTKImageFilter::Pointer myConverter1 = itk::ImageToVTKImageFilter::New(); myConverter1->SetInput( myCast->GetOutput() ); myConverter1->Update(); vtkImageData* input = vtkImageData::New(); input->DeepCopy (myConverter1->GetOutput()); wxString basename = wxT (myimporter->GetDescription (i).c_str()); //wxString basename = wxT ("1"); this->AddImage ( input, basename.c_str()); input->Delete(); keepGoing = dialog->Update ( (int)(step*(double)i) ); } m_MainNotebook->SetSelection(0); m_MainNotebook->Show(true); // bug : to be removed : cannot destroy myimporter->Destroy(); dialog->Destroy(); } void wxImageViewerInteractor::OnToolBarSave(wxCommandEvent& event) { wxVtkPageView* page = dynamic_cast(m_MainNotebook->GetPage(m_MainNotebook->GetSelection())); if( !page ) return; wxString filename = this->GetSaveFileName(this, wxT("Choose an image"), wxSupportedImageExtensionsFilter); if( filename.IsEmpty() ) { return; } this->SaveImage (page, filename.c_str()); } void wxImageViewerInteractor::OnToolBarSaveAll(wxCommandEvent& event) { wxDirDialog* myDirDialog = new wxDirDialog(this, wxT ("Choose the DICOM directory"), wxT(""), wxDD_DIR_MUST_EXIST|wxDD_DEFAULT_STYLE|wxDD_CHANGE_DIR, wxDefaultPosition); int OK = myDirDialog->ShowModal(); if( OK!=wxID_OK ) { delete myDirDialog; return; } wxString directory = myDirDialog->GetPath(); std::string dir (directory.c_str()); #ifdef __WXMSW__ dir = dir+"\\"; #else dir = dir+"/"; #endif for (unsigned int id = 0; id < m_MainNotebook->GetPageCount(); id++) { wxVtkPageView* page = dynamic_cast(m_MainNotebook->GetPage(id)); if (!page) { continue; } std::string name = page->GetImageName(); bool validname=false; std::string::iterator last = name.end(); #ifndef __WXMSW__ last = std::remove (name.begin(), last, ' '); name.resize ( (size_t)(last-name.begin())); #endif std::replace (name.begin(), last, '/', '_'); std::replace (name.begin(), last, '\\', '_'); std::replace (name.begin(), last, ':', '_'); if (name.length() == 0) { name = "NotAValidFileName"; } std::string basename = dir+name; std::string filename = basename + ".hdr"; unsigned int iter = 1; while (itksys::SystemTools::FileExists (filename.c_str()) ) { // file exists char num[256]; sprintf (num, "(%d)", iter); filename = basename + num + ".hdr"; iter++; } this->SaveImage (page, filename.c_str()); } } void wxImageViewerInteractor::OnToolBarFlip(wxCommandEvent& event) { wxVtkImageFlip* myflipper = new wxVtkImageFlip (this, -1, wxT("Radiologic conventions"), wxDefaultPosition, wxSize(400,400)); int selection = m_MainNotebook->GetSelection(); wxVtkPageView* page = dynamic_cast(m_MainNotebook->GetPage( selection )); if( !page ) { return; } myflipper->SetImage (page->GetInput()); int OK = myflipper->ShowModal(); if (OK == wxID_OK ) { page->SetInput(myflipper->GetOutput(), false); // do not reset window/level/position page->Render(); m_Thumbnail->ChangeImage (selection-1, myflipper->GetOutput()); } myflipper->Destroy(); } void wxImageViewerInteractor::SaveImage (wxVtkPageView* page, const char* filename) { if (!page) { return; } // write the image itk::VTKImageToImageFilter::Pointer myConverter = itk::VTKImageToImageFilter::New(); vtkImageData* image = vtkImageData::New(); image->DeepCopy(page->GetInput() ); try { myConverter->SetInput( image ); myConverter->Update(); } catch (itk::ExceptionObject & e) { std::cerr << e; this->DisplayErrorMessage (this, wxT("Error while converting image.\n(check the log window for more details)")); return; } itk::Matrix cosines; cosines[0][0]= 1; cosines[0][1]= 0; cosines[0][2]= 0; cosines[1][0]= 0; cosines[1][1]=-1; cosines[1][2]= 0; cosines[2][0]= 0; cosines[2][1]= 0; cosines[2][2]= 1; ImageType::Pointer itkimage = const_cast(myConverter->GetOutput()); itkimage->SetDirection(cosines); itk::ImageFileWriter::Pointer writer = itk::ImageFileWriter::New(); writer->SetFileName (filename); writer->SetInput(itkimage); try { std::cout << "writing : " << filename << std::endl; writer->Update(); } catch (itk::ExceptionObject & e) { std::cerr << e; this->DisplayErrorMessage (this, wxT("Error while writing file.\n(check the log window for more details)")); return; } image->Delete(); } void wxImageViewerInteractor::OnFullScreenAxial(wxCommandEvent &event) { bool show = event.IsChecked(); wxVtkPageView* page = dynamic_cast(m_MainNotebook->GetPage(m_MainNotebook->GetSelection())); if( show ) { m_ToolBarView->ToggleTool (TOOLBAR_COR, false); m_ToolBarView->ToggleTool (TOOLBAR_SAG, false); m_ToolBarView->ToggleTool (TOOLBAR_3D, false); if (page) page->OnFullScreen(vtkViewImage::AXIAL_ID); } else { if (page) page->NoFullScreen(); } m_Thumbnail->ChangeOrientation (vtkViewImage::AXIAL_ID); } void wxImageViewerInteractor::OnFullScreenCoronal(wxCommandEvent &event) { bool show = event.IsChecked(); wxVtkPageView* page = dynamic_cast(m_MainNotebook->GetPage(m_MainNotebook->GetSelection())); if( show ) { m_ToolBarView->ToggleTool (TOOLBAR_AX, false); m_ToolBarView->ToggleTool (TOOLBAR_SAG, false); m_ToolBarView->ToggleTool (TOOLBAR_3D, false); if (page) page->OnFullScreen(vtkViewImage::CORONAL_ID); } else { if (page) page->NoFullScreen(); } m_Thumbnail->ChangeOrientation (vtkViewImage::CORONAL_ID); } void wxImageViewerInteractor::OnFullScreenSagittal(wxCommandEvent &event) { bool show = event.IsChecked(); wxVtkPageView* page = dynamic_cast(m_MainNotebook->GetPage(m_MainNotebook->GetSelection())); if( show ) { m_ToolBarView->ToggleTool (TOOLBAR_AX, false); m_ToolBarView->ToggleTool (TOOLBAR_COR, false); m_ToolBarView->ToggleTool (TOOLBAR_3D, false); if (page) page->OnFullScreen(vtkViewImage::SAGITTAL_ID); } else { if (page) page->NoFullScreen(); } m_Thumbnail->ChangeOrientation (vtkViewImage::SAGITTAL_ID); } void wxImageViewerInteractor::OnFullScreen3D(wxCommandEvent &event) { bool show = event.IsChecked(); wxVtkPageView* page = dynamic_cast(m_MainNotebook->GetPage(m_MainNotebook->GetSelection())); if( show ) { m_ToolBarView->ToggleTool (TOOLBAR_AX, false); m_ToolBarView->ToggleTool (TOOLBAR_COR, false); m_ToolBarView->ToggleTool (TOOLBAR_SAG, false); if (page) page->OnFullScreen(vtkViewImage::NB_PLAN_IDS); } else { if (page) page->NoFullScreen(); } } void wxImageViewerInteractor::OnToolBarLink(wxCommandEvent &event) { m_Thumbnail->LinkViews (event.IsChecked()); if (event.IsChecked()) m_Thumbnail->Render(); } void wxImageViewerInteractor::OnToolBarSnapShot(wxCommandEvent& event) { wxVtkPageView* page = dynamic_cast(m_MainNotebook->GetPage(m_MainNotebook->GetSelection())); if (!page) { this->DisplayWarningMessage( this, wxT("No snap shot in preview.")); return; } // find out which window is full screen wxVTKRenderWindowInteractor* viewToSnap = 0; viewToSnap = page->GetDisplayedView(); if( !viewToSnap ) { this->DisplayWarningMessage( this, wxT("Please set a window in full page first.")); return; } wxSnapshotTaker* sstaker = new wxSnapshotTaker (this); sstaker->SetRenderWindow (viewToSnap->GetRenderWindow()); sstaker->SetMagnification(2); sstaker->Snap(); delete sstaker; } void wxImageViewerInteractor::OnToolBarCLUT (wxCommandEvent& event) { int val = event.GetInt(); wxVtkPageView* page = dynamic_cast(m_MainNotebook->GetPage(m_MainNotebook->GetSelection())); vtkLookupTable* lut = vtkLookupTableManager::GetLookupTable(val-1); if( lut && page ) { page->SetLookupTable (lut); page->Render(); lut->Delete(); return; } wxImageThumbnail* thumbPage = dynamic_cast(m_MainNotebook->GetPage(m_MainNotebook->GetSelection())); if( lut && thumbPage ) { thumbPage->SetLookupTable (lut); thumbPage->Render(); lut->Delete(); return; } } void wxImageViewerInteractor::OnToolBarVRMode (wxCommandEvent& event) { int val = event.GetInt(); wxVtkPageView* page = dynamic_cast(m_MainNotebook->GetPage(m_MainNotebook->GetSelection())); if( !page ) { return; } switch(val) { case 1: page->GetView4()->SetVolumeMapperToTexture(); break; case 2: page->GetView4()->SetVolumeMapperToRayCast(); page->GetView4()->SetVolumeRayCastFunctionToMIP(); break; default: return; } page->GetView4()->Render(); } void wxImageViewerInteractor::OnToolBarShading (wxCommandEvent& event) { bool val = event.IsChecked(); wxVtkPageView* page = dynamic_cast(m_MainNotebook->GetPage(m_MainNotebook->GetSelection())); if( !page ) { return; } if( val ) { page->GetView4()->ShadeOn(); } else { page->GetView4()->ShadeOff(); } page->GetView4()->Render(); }