From a0e1213d4d1fd054dc40a63849c152064b496731 Mon Sep 17 00:00:00 2001 From: Leonardo Florez-Valencia Date: Thu, 22 Oct 2015 19:15:27 -0500 Subject: [PATCH] Dicom series reader plugin added. --- appli/ImageMPR/ImageMPR.cxx | 10 + appli/ImageMPR/ImageMPR.h | 1 + appli/ImageMPR/ImageMPR.ui | 11 +- lib/cpPlugins/Interface/BaseMPRWindow.cxx | 53 ++++++ lib/cpPlugins/Interface/BaseMPRWindow.h | 2 + .../Plugins/IO/DicomSeriesReader.cxx | 179 ++++++++++++++++++ lib/cpPlugins/Plugins/IO/DicomSeriesReader.h | 61 ++++++ lib/cpPlugins/Plugins/IO/ImageReader.cxx | 13 +- 8 files changed, 319 insertions(+), 11 deletions(-) create mode 100644 lib/cpPlugins/Plugins/IO/DicomSeriesReader.cxx create mode 100644 lib/cpPlugins/Plugins/IO/DicomSeriesReader.h diff --git a/appli/ImageMPR/ImageMPR.cxx b/appli/ImageMPR/ImageMPR.cxx index ca29aaa..4b1a4c9 100644 --- a/appli/ImageMPR/ImageMPR.cxx +++ b/appli/ImageMPR/ImageMPR.cxx @@ -20,6 +20,7 @@ ImageMPR( QWidget* parent ) // Connect actions ImageMPR_ConnectAction( OpenImage ); + ImageMPR_ConnectAction( OpenDICOMSeries ); ImageMPR_ConnectAction( OpenSegmentation ); ImageMPR_ConnectAction( OpenPolyData ); ImageMPR_ConnectAction( SaveImage ); @@ -53,6 +54,15 @@ _aOpenImage( ) this->m_ImageLoaded = this->m_UI->MPR->LoadImage( ); } +// ------------------------------------------------------------------------- +void ImageMPR:: +_aOpenDICOMSeries( ) +{ + if( this->m_ImageLoaded != "" ) + this->m_UI->MPR->ClearAll( ); + this->m_ImageLoaded = this->m_UI->MPR->LoadDicomSeries( ); +} + // ------------------------------------------------------------------------- void ImageMPR:: _aOpenSegmentation( ) diff --git a/appli/ImageMPR/ImageMPR.h b/appli/ImageMPR/ImageMPR.h index dabf450..b1d43ff 100644 --- a/appli/ImageMPR/ImageMPR.h +++ b/appli/ImageMPR/ImageMPR.h @@ -150,6 +150,7 @@ public: private slots: void _aOpenImage( ); + void _aOpenDICOMSeries( ); void _aOpenSegmentation( ); void _aOpenPolyData( ); void _aSaveImage( ); diff --git a/appli/ImageMPR/ImageMPR.ui b/appli/ImageMPR/ImageMPR.ui index 7a292a2..d37cab6 100644 --- a/appli/ImageMPR/ImageMPR.ui +++ b/appli/ImageMPR/ImageMPR.ui @@ -32,7 +32,7 @@ 0 0 718 - 25 + 27 @@ -40,6 +40,7 @@ &File + @@ -169,6 +170,14 @@ Ctrl+Shift+M + + + Open DICOM series + + + Ctrl+D + + diff --git a/lib/cpPlugins/Interface/BaseMPRWindow.cxx b/lib/cpPlugins/Interface/BaseMPRWindow.cxx index 04bc870..5f64d36 100644 --- a/lib/cpPlugins/Interface/BaseMPRWindow.cxx +++ b/lib/cpPlugins/Interface/BaseMPRWindow.cxx @@ -207,6 +207,57 @@ LoadImage( ) return( ret ); } +// ------------------------------------------------------------------------- +std::string cpPlugins::Interface::BaseMPRWindow:: +LoadDicomSeries( ) +{ + std::string msg = ""; + std::string ret = ""; + if( this->m_DicomSeriesReader.IsNull( ) ) + msg = "No valid DICOM series reader. Please load a valid plugin file."; + + if( this->m_DicomSeriesReader->ExecConfigurationDialog( this ) ) + { + this->Block( ); + msg = this->m_DicomSeriesReader->Update( ); + if( msg == "" ) + { + TImage::Pointer image = + this->m_DicomSeriesReader->GetOutput< TImage >( "Output" ); + if( this->m_Images.size( ) == 0 ) + ret = image->GetName( ); + else + ret = "Segmentation"; + this->m_Images[ ret ] = image; + this->m_DicomSeriesReader->DisconnectOutputs( ); + this->m_DicomSeriesReader->GetParameters( )-> + ClearStringList( "FileNames" ); + vtkImageData* vtk_id = image->GetVTK< vtkImageData >( ); + if( vtk_id != NULL ) + { + this->m_MPRObjects->AddImage( vtk_id ); + /* + MementoState(m_state, this->m_Image); + this->m_state++; + */ + } + else + msg = "Read dicom series does not have a valid VTK converter."; + } + else + ret = ""; + + } // fi + + // Show errors and return + this->Unblock( ); + if( msg != "" ) + QMessageBox::critical( + this, tr( "Error reading dicom series." ), tr( msg.c_str( ) ) + ); + return( ret ); +} + // ------------------------------------------------------------------------- std::string cpPlugins::Interface::BaseMPRWindow:: LoadMesh( ) @@ -300,6 +351,8 @@ _UpdatePlugins( ) this->m_MeshReader = o; else if( category == "MeshWriter" ) this->m_MeshWriter = o; + else if( category == "DicomSeriesReader" ) + this->m_DicomSeriesReader = o; else this->m_Filters[ category ].insert( name ); diff --git a/lib/cpPlugins/Interface/BaseMPRWindow.h b/lib/cpPlugins/Interface/BaseMPRWindow.h index 6799abe..3395d21 100644 --- a/lib/cpPlugins/Interface/BaseMPRWindow.h +++ b/lib/cpPlugins/Interface/BaseMPRWindow.h @@ -80,6 +80,7 @@ namespace cpPlugins bool LoadPlugins( const std::string& fname ); void LoadPlugins( ); std::string LoadImage( ); + std::string LoadDicomSeries( ); std::string LoadMesh( ); void ExecuteFilter( @@ -133,6 +134,7 @@ namespace cpPlugins TProcessObject::Pointer m_ImageWriter; TProcessObject::Pointer m_MeshReader; TProcessObject::Pointer m_MeshWriter; + TProcessObject::Pointer m_DicomSeriesReader; TFilters m_Filters; TImages m_Images; diff --git a/lib/cpPlugins/Plugins/IO/DicomSeriesReader.cxx b/lib/cpPlugins/Plugins/IO/DicomSeriesReader.cxx new file mode 100644 index 0000000..99f19b0 --- /dev/null +++ b/lib/cpPlugins/Plugins/IO/DicomSeriesReader.cxx @@ -0,0 +1,179 @@ +#include "DicomSeriesReader.h" + +#ifdef cpPlugins_Interface_QT4 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#endif // cpPlugins_Interface_QT4 + +#include + +// ------------------------------------------------------------------------- +bool cpPlugins::IO::DicomSeriesReader:: +ExecConfigurationDialog( QWidget* parent ) +{ + bool r = false; + +#ifdef cpPlugins_Interface_QT4 + + // DICOM series analyzer + itk::GDCMSeriesFileNames::GlobalWarningDisplayOff( ); + itk::GDCMSeriesFileNames::Pointer series = + itk::GDCMSeriesFileNames::New( ); + + typedef std::map< std::string, TStringList > _TSeries; + typedef std::map< std::string, _TSeries > _TFilenames; + _TSeries found_series; + _TFilenames found_filenames; + + // Show dialog and check if it was accepted + QFileDialog dialog( parent ); + dialog.setFileMode( QFileDialog::DirectoryOnly ); + dialog.setDirectory( QFileDialog::tr( "." ) ); + if( dialog.exec( ) ) + { + std::string dir_name = dialog.selectedFiles( ).begin( )->toStdString( ); + std::queue< std::string > q; + q.push( dir_name ); + while( !( q.empty( ) ) ) + { + dir_name = q.front( ); + q.pop( ); + + // Get DICOM information + series->SetUseSeriesDetails( true ); + series->AddSeriesRestriction( "0008|0021" ); + series->SetDirectory( dir_name ); + const TStringList& seriesUID = series->GetSeriesUIDs( ); + if( seriesUID.size( ) > 0 ) + { + TStringList::const_iterator sIt = seriesUID.begin( ); + for( ; sIt != seriesUID.end( ); ++sIt ) + { + TStringList filenames = series->GetFileNames( *sIt ); + if( filenames.size( ) > 0 ) + { + found_series[ dir_name ].push_back( *sIt ); + found_filenames[ dir_name ][ *sIt ] = filenames; + + } // fi + + } // rof + + } // fi + + // Update queue + QDir dir( dir_name.c_str( ) ); + QFileInfoList contents = dir.entryInfoList( ); + QFileInfoList::const_iterator i = contents.begin( ); + for( ; i != contents.end( ); ++i ) + { + if( i->isDir( ) ) + { + std::string new_dir_name = i->absoluteFilePath( ).toStdString( ); + if( new_dir_name.size( ) > dir_name.size( ) ) + q.push( new_dir_name ); + + } // fi + + } // rof + + } // elihw + + } // fi + + // Show second dialog + if( found_series.size( ) > 0 ) + { + QDialog* tree_dialog = new QDialog( parent ); + + QLabel* title = new QLabel( tree_dialog ); + title->setText( "Choose a DICOM series" ); + QGridLayout* mainLayout = new QGridLayout( tree_dialog ); + QVBoxLayout* toolsLayout = new QVBoxLayout( ); + toolsLayout->addWidget( title ); + mainLayout->addLayout( toolsLayout, 0, 0, 1, 1 ); + + QTreeWidget* tree = new QTreeWidget( tree_dialog ); + QList< QTreeWidgetItem* > tree_items; + + _TSeries::const_iterator fsIt = found_series.begin( ); + for( ; fsIt != found_series.end( ); ++fsIt ) + { + QTreeWidgetItem* new_item = + new QTreeWidgetItem( + ( QTreeWidgetItem* )( NULL ), QStringList( fsIt->first.c_str( ) ) + ); + TStringList::const_iterator sId = fsIt->second.begin( ); + for( ; sId != fsIt->second.end( ); ++sId ) + { + QTreeWidgetItem* new_leaf = + new QTreeWidgetItem( new_item, QStringList( sId->c_str( ) ) ); + new_item->addChild( new_leaf ); + + } // rof + tree_items.append( new_item ); + + } // rof + tree->insertTopLevelItems( 0, tree_items ); + toolsLayout->addWidget( tree ); + + QDialogButtonBox* bb = new QDialogButtonBox( + QDialogButtonBox::Ok | QDialogButtonBox::Cancel + ); + tree_dialog->connect( bb, SIGNAL( accepted( ) ), tree_dialog, SLOT( accept( ) ) ); + tree_dialog->connect( bb, SIGNAL( rejected( ) ), tree_dialog, SLOT( reject( ) ) ); + toolsLayout->addWidget( bb ); + + if( tree_dialog->exec( ) == 1 ) + { + QTreeWidgetItem* item = tree->currentItem( ); + QTreeWidgetItem* parent = item->parent( ); + if( parent != NULL ) + { + std::string serie_dir = parent->text( 0 ).toStdString( ); + std::string serie_id = item->text( 0 ).toStdString( ); + + this->m_Parameters->ClearStringList( "FileNames" ); + const TStringList& filenames = found_filenames[ serie_dir ][ serie_id ]; + for( unsigned int f = 0; f < filenames.size( ); ++f ) + this->m_Parameters->AddToStringList( "FileNames", filenames[ f ] ); + + r = true; + + } // fi + + } // fi + + } // fi + + itk::GDCMSeriesFileNames::GlobalWarningDisplayOn( ); + +#endif // cpPlugins_Interface_QT4 + + return( r ); +} + +// ------------------------------------------------------------------------- +cpPlugins::IO::DicomSeriesReader:: +DicomSeriesReader( ) + : Superclass( ) +{ +} + +// ------------------------------------------------------------------------- +cpPlugins::IO::DicomSeriesReader:: +~DicomSeriesReader( ) +{ +} + +// eof - $RCSfile$ diff --git a/lib/cpPlugins/Plugins/IO/DicomSeriesReader.h b/lib/cpPlugins/Plugins/IO/DicomSeriesReader.h new file mode 100644 index 0000000..3bad459 --- /dev/null +++ b/lib/cpPlugins/Plugins/IO/DicomSeriesReader.h @@ -0,0 +1,61 @@ +#ifndef __CPPLUGINS__PLUGINS__DICOMSERIESREADER__H__ +#define __CPPLUGINS__PLUGINS__DICOMSERIESREADER__H__ + +#include + +#include +#include + +namespace itk +{ + class ImageIOBase; +} + +namespace cpPlugins +{ + namespace IO + { + /** + */ + class cpPluginsIO_EXPORT DicomSeriesReader + : public ImageReader + { + public: + typedef DicomSeriesReader Self; + typedef ImageReader Superclass; + typedef itk::SmartPointer< Self > Pointer; + typedef itk::SmartPointer< const Self > ConstPointer; + + typedef Superclass::TParameters TParameters; + typedef Superclass::TStringList TStringList; + + public: + itkNewMacro( Self ); + itkTypeMacro( DicomSeriesReader, ImageReader ); + cpPlugins_Id_Macro( + cpPlugins::IO::DicomSeriesReader, "DicomSeriesReader" + ); + + public: + virtual bool ExecConfigurationDialog( QWidget* parent ); + + protected: + DicomSeriesReader( ); + virtual ~DicomSeriesReader( ); + + private: + // Purposely not implemented + DicomSeriesReader( const Self& ); + Self& operator=( const Self& ); + }; + + // --------------------------------------------------------------------- + CPPLUGINS_INHERIT_PROVIDER( DicomSeriesReader ); + + } // ecapseman + +} // ecapseman + +#endif // __CPPLUGINS__PLUGINS__DICOMSERIESREADER__H__ + +// eof - $RCSfile$ diff --git a/lib/cpPlugins/Plugins/IO/ImageReader.cxx b/lib/cpPlugins/Plugins/IO/ImageReader.cxx index f544617..d28b129 100644 --- a/lib/cpPlugins/Plugins/IO/ImageReader.cxx +++ b/lib/cpPlugins/Plugins/IO/ImageReader.cxx @@ -1,8 +1,6 @@ #include "ImageReader.h" #include -#include - #include #include @@ -388,20 +386,15 @@ _RealGD( const TStringList& names ) else if( names.size( ) > 1 ) { // Read image series - std::set< std::string > ordered_names; - for( unsigned int i = 0; i < names.size( ); ++i ) - ordered_names.insert( names[ i ] ); - typedef itk::ImageSeriesReader< I > _MR; _MR* reader = this->_CreateITK< _MR >( ); - std::set< std::string >::const_iterator fnIt = ordered_names.begin( ); - for( ; fnIt != ordered_names.end( ); ++fnIt ) - reader->AddFileName( *fnIt ); + for( unsigned int i = 0; i < names.size( ); ++i ) + reader->AddFileName( names[ i ] ); try { reader->Update( ); out->SetITK< I >( reader->GetOutput( ) ); - out->SetName( *( ordered_names.begin( ) ) ); + out->SetName( names[ 0 ] ); } catch( itk::ExceptionObject& err ) { -- 2.47.1