SeriesFilelist getSeriesFileNames(const std::string &inputDir, unsigned int minSlices) { NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New(); nameGenerator->SetUseSeriesDetails( true ); nameGenerator->SetDirectory( inputDir ); SeriesFilelist slist; typedef std::vector< std::string > SeriesIdContainer; const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs(); SeriesIdContainer::const_iterator seriesItr = seriesUID.begin(); SeriesIdContainer::const_iterator seriesEnd = seriesUID.end(); while( seriesItr != seriesEnd ) { FileNamesContainer fileNames = nameGenerator->GetFileNames(seriesItr->c_str()); if (fileNames.size() >= minSlices) slist.push_back( fileNames ); seriesItr++; } return slist; }
void QtDcmConvert::convert() { if (QtDcmPreferences::instance()->useDcm2nii()) { QString program = QtDcmPreferences::instance()->getDcm2niiPath(); QStringList arguments; arguments << "-x" << "N"; arguments << "-r" << "N"; arguments << "-g" << "N"; arguments << "-o" << d->outputDirectory << d->inputDirectory; QProcess * process = new QProcess(this); process->setStandardOutputFile(d->tempDirectory + QDir::separator() + "logs" + QDir::separator() + d->serieUID + ".txt"); process->start(program, arguments); process->waitForFinished(); delete process; } else { typedef signed short PixelType; const unsigned int Dimension = 3; typedef itk::Image< PixelType, Dimension > ImageType; typedef itk::ImageSeriesReader< ImageType > ReaderType; typedef itk::ImageFileWriter<ImageType> WriterType; typedef itk::GDCMImageIO ImageIOType; typedef itk::GDCMSeriesFileNames NamesGeneratorType; typedef std::vector< std::string > FileNamesContainer; typedef std::vector< std::string > SeriesIdContainer; // ImageType::Pointer image = 0; ReaderType::Pointer reader = ReaderType::New(); ImageIOType::Pointer dicomIO = ImageIOType::New(); NamesGeneratorType::Pointer inputNames = NamesGeneratorType::New(); inputNames->SetUseSeriesDetails ( true ); inputNames->AddSeriesRestriction ( "0008|0021" ); inputNames->AddSeriesRestriction ( "0020,0037" ); inputNames->LoadSequencesOn(); inputNames->LoadPrivateTagsOn(); inputNames->SetInputDirectory ( d->inputDirectory.toStdString() ); try { const SeriesIdContainer & seriesUID = inputNames->GetSeriesUIDs(); std::string seriesIdentifier = seriesUID.begin()->c_str(); FileNamesContainer filenames = inputNames->GetFileNames ( seriesIdentifier ); dicomIO->SetFileName ( filenames.begin()->c_str() ); try { dicomIO->ReadImageInformation(); } catch ( itk::ExceptionObject &e ) { qDebug() << e.GetDescription(); return; } reader->UseStreamingOn(); reader->SetFileNames ( filenames ); reader->SetImageIO ( dicomIO ); try { reader->Update(); } catch ( itk::ExceptionObject &excp ) { std::cerr << excp << std::endl; return; } // IteratorType itOut; // // image = reader->GetOutput(); // // RegionType region; // region.SetSize ( 0, image->GetLargestPossibleRegion().GetSize() [0] ); // region.SetSize ( 1, image->GetLargestPossibleRegion().GetSize() [1] ); // region.SetSize ( 2, image->GetLargestPossibleRegion().GetSize() [2] ); // image->SetRegions ( region ); // image->Allocate(); // SpacingType spacing; // spacing[0] = image->GetSpacing() [0]; // spacing[1] = image->GetSpacing() [1]; // spacing[2] = image->GetSpacing() [2]; // spacing[3] = 1; // image->SetSpacing ( spacing ); // PointType origin; // origin[0] = image->GetOrigin() [0]; // origin[1] = image->GetOrigin() [1]; // origin[2] = image->GetOrigin() [2]; // origin[3] = 0; // image->SetOrigin ( origin ); // DirectionType direction; // for ( unsigned int i=0; i<4; i++ ) // for ( unsigned int j=0; j<4; j++ ) // { // if ( ( i < 3 ) && ( j < 3 ) ) // direction[i][j] = image->GetDirection() [i][j]; // else // direction[i][j] = ( i == j ) ? 1 : 0; // } // image->SetDirection ( direction ); // itOut = IteratorType ( image, region ); // // image->SetMetaDataDictionary ( dicomIO->GetMetaDataDictionary() ); // // // itk::ImageRegionIterator<ImageType> itIn ( image, image->GetLargestPossibleRegion() ); // while ( !itIn.IsAtEnd() ) // { // itOut.Set ( itIn.Get() ); // ++itIn; // ++itOut; // } WriterType::Pointer writer = WriterType::New(); QString completeFilename = d->outputDirectory + QDir::separator() + d->outputFilename; writer->SetFileName ( completeFilename.toStdString() ); writer->SetInput ( reader->GetOutput() ); // writer->SetInput ( image ); try { writer->Update(); } catch ( itk::ExceptionObject &ex ) { std::cout << ex << std::endl; return; } } catch ( itk::ExceptionObject &ex ) { std::cout << ex << std::endl; return; } } }
int main(int argc, char *argv[]) { //print help if( argc == 1 ) //argv[0] { PrintHelp(argv); return 1; } if( argc == 2 ) //argv[0] -h { if( argv[1] == string("-h") || argv[1] == string("-H") || argv[1] == string("-help") ) { PrintHelp(argv); return 1; } else { cerr<< "For help: "<< argv[0] << " -h" <<endl; return 0; } } //tags used to name the converted 3d filename: PatientID_StudyID_StudyDate_Access#_Series#_SeriesDescription.mha vector<string> tags; tags.push_back("0010|0020");//patientID tags.push_back("0020|0010");//studyID tags.push_back("0008|0020");//studyDate tags.push_back("0008|0050");//access# tags.push_back("0020|0011");//series# tags.push_back("0008|103e");//series description //illegal filename chracters: \ / : * ? " < > | , which will be removed from tag value. string illegalChars = "\\/:?\"<>|"; //accept output format, specified by -f vector<string> acceptFormat; acceptFormat.push_back("mha"); acceptFormat.push_back("nii"); acceptFormat.push_back("mhd"); acceptFormat.push_back("nrrd"); acceptFormat.push_back("hdr"); //timer start const clock_t begin_time = clock(); //parse arguments string dicomDirectory; // -i string outputDirectory;// -o bool write3D = false; //will be set to true, if outputDirectory is good bool writeAllSeries = true; // default, if without -k string outputFormat = "mha"; //default, if without -f vector<string> seriesKeywords; //record series keywords specified by -f string convertedList; //-l bool writeConvertedList = false; for (int ac = 1; ac < argc; ac++) { //-i if( argv[ac] == string("-i") || argv[ac] == string("-I")) { if ( ++ac >= argc ) { cerr<< "missing argument for -i" <<endl; return 1; } dicomDirectory = argv[ac]; } //-o if( argv[ac] == string("-o") || argv[ac] == string("-O") ) { if ( ++ac >= argc ) { cerr<< "missing argument for -o" <<endl; return 1; } outputDirectory = argv[ac]; } //-f if( argv[ac] == string("-f") || argv[ac] == string("-F") ) { if ( ++ac >= argc ) { cerr<< "missing argument for -f" <<endl; return 1; } outputFormat = argv[ac]; transform(outputFormat.begin(), outputFormat.end(),outputFormat.begin(), tolower); //to lower case } //-k if ( argv[ac] == string("-k") || argv[ac] == string("-K") ) { if ( ++ac >= argc ) { cerr<< "missing argument for -k" <<endl; return 1; } //add elements after -f to vector serieskeywords string seriesKeyword; for( int i=ac; i<argc; i++ ) { seriesKeyword=argv[i]; //push_back until next option if( seriesKeyword == string("-l") || seriesKeyword == string("-i") || seriesKeyword == string("-o") || seriesKeyword == string("-f") ) { break; } transform(seriesKeyword.begin(), seriesKeyword.end(), seriesKeyword.begin(), tolower);//to lower case seriesKeyword = std::regex_replace(seriesKeyword, regex("^ +| +$|( ) +"), "$1");//remove leading,trailing and extra white space seriesKeywords.push_back(seriesKeyword); } if( seriesKeywords.size() > 0 ) { writeAllSeries = false; } } //-l if( argv[ac] == string("-l") || argv[ac] == string("-L") ) { if ( ++ac >= argc ) { cerr<< "missing argument for -l" <<endl; return 1; } convertedList = argv[ac]; } } // Check if dicomDirectory is a directory and exist bool exist = itksys::SystemTools::FileExists(dicomDirectory.c_str()); bool isDir = itksys::SystemTools::FileIsDirectory(dicomDirectory.c_str()); if ( !(exist && isDir) ) { cerr << "ERROR: " << dicomDirectory << " does not exist or is no directory." << endl; return 1; } //check if outputDirectory is good if ( !(outputDirectory.empty()) ) { //check if outputDirectory is a file bool isFile = itksys::SystemTools::FileExists(outputDirectory.c_str(),true); if ( isFile ) { cerr << "ERROR: " << outputDirectory << " should be a directory!" << endl; return 1; } // Check if outputDirectory exist exist = itksys::SystemTools::FileExists( outputDirectory.c_str() ); if( !exist ) //create directory is not exist { try { itksys::SystemTools::MakeDirectory( outputDirectory.c_str() ); cout << outputDirectory << " created." << endl; } catch (itk::ExceptionObject &ex) { cout << ex << std::endl; return 1; } } //set write3D to ture when outputDirectory is good. write3D = true; } //check if ouput format is accept if ( !(find(acceptFormat.begin(), acceptFormat.end(), outputFormat) != acceptFormat.end()) ) { cerr<< "accepted output formats:mha, nii, mhd, nrrd, hdr" <<endl; return 1; } //open convertedList file specified by -l ofstream convertedListFile; if ( !convertedList.empty() ) { convertedListFile.exceptions ( ofstream::failbit | ofstream::badbit ); try { convertedListFile.open( outputDirectory + string(PATH_SEP) + convertedList, ios::out | ios::app); writeConvertedList = true; } catch (std::ofstream::failure e) { cerr << "Exception opening file."<<endl; return 1; } } cout<<"Analyzing "<<dicomDirectory<<endl; //image type to read 2d dicom image, used to get the dicom tags of patientID,studyId,etc... typedef itk::Image< signed short, 2 > ImageType2D; typedef itk::ImageFileReader< ImageType2D > ReaderType2D; ReaderType2D::Pointer reader2D = ReaderType2D::New(); //image type to write 3d mha image typedef signed short PixelType; const unsigned int Dimension = 3; typedef itk::Image< PixelType, Dimension > ImageType; typedef itk::ImageSeriesReader< ImageType > ReaderType; typedef itk::GDCMSeriesFileNames NamesGeneratorType; NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New(); ReaderType::Pointer reader = ReaderType::New(); typedef itk::GDCMImageIO ImageIOType; ImageIOType::Pointer dicomIO = ImageIOType::New(); nameGenerator->SetRecursive(true); nameGenerator->SetUseSeriesDetails(true); nameGenerator->AddSeriesRestriction("0008|0021"); nameGenerator->SetDirectory(dicomDirectory); //get all the series (by series UID) under the input folder typedef std::vector< std::string > SeriesIdContainer; const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs(); SeriesIdContainer::const_iterator seriesItr = seriesUID.begin(); SeriesIdContainer::const_iterator seriesEnd = seriesUID.end(); //get the correspondence between series UID and PatientID,studyId,studyDate,accessNumber,seriesNumber,seriesDescription //key is series UID, vector<string> is PatientID,studyID,studyDate,accessNumber,seriesNumber,seriesDescription map< string, vector<string> > seriesUidToOtherStuff; seriesItr = seriesUID.begin(); while (seriesItr != seriesUID.end()) { string seriesIdentifier = seriesItr->c_str(); //get file names belong to specific series vector< string > fileNames = nameGenerator->GetFileNames(seriesIdentifier); vector< string > otherStuff; //read tags(PatientID StudyID StudyDate Access# Series# SeriesDescription) value from the first file of each series if (!fileNames.empty()) { reader2D->SetFileName(fileNames[0]); reader2D->SetImageIO(dicomIO); try { reader2D->UpdateLargestPossibleRegion(); //do not use reader->Update(),since image size is different across series. } catch (itk::ExceptionObject &ex) { cout << ex << endl; return 1; } typedef itk::MetaDataDictionary DictionaryType; const DictionaryType & dictionary = dicomIO->GetMetaDataDictionary(); typedef itk::MetaDataObject< std::string > MetaDataStringType; DictionaryType::ConstIterator itr = dictionary.Begin(); DictionaryType::ConstIterator end = dictionary.End(); for (int i = 0; i < tags.size(); i++) { string entryId = tags[i]; DictionaryType::ConstIterator tagItr = dictionary.Find( entryId ); if( tagItr != end ) { MetaDataStringType::ConstPointer entryvalue =dynamic_cast<const MetaDataStringType *>(tagItr->second.GetPointer() ); if( entryvalue )//entry found { string tagvalue = entryvalue->GetMetaDataObjectValue(); tagvalue = regex_replace(tagvalue, regex("^ +| +$|( ) +"), "$1");//remove leading,trailing and extra white space otherStuff.push_back(tagvalue); } else { otherStuff.push_back("EntryNotFound"); } } }//end for }//end if (!fileNames.empty()) seriesUidToOtherStuff[seriesIdentifier] = otherStuff; seriesItr++; }//end while //list series number and description for each patient and access# /*patientID, access#, series#, series descrition hierarchy: patientid access# series#:series description series#:series description ... access# series#:series description series#:series description ... patientid ... ... */ //create 2d vector for sorting vector<string> vs; vector< vector<string> > vvs; for( map< string,vector<string> >::iterator ii=seriesUidToOtherStuff.begin(); ii!=seriesUidToOtherStuff.end(); ++ii) { vector<string> vsNew; vs = (*ii).second; vsNew.push_back(vs[0]);//patientID vsNew.push_back(vs[3]);//access# vsNew.push_back(vs[4]);//series# vsNew.push_back(vs[5]);//series description vvs.push_back(vsNew); } //sort: patientID and access# by string lexicographical order, series# by integer sort(vvs.begin(),vvs.end(),comparator); //print series number and description for each patient and access# string patientID; string accessNumber; vector<string> patientIDVector; vector<string> accessNumberVector; if ( vvs.size()>0 ) { cout <<dicomDirectory<<" contains the following DICOM Series:"<<endl; for( int i = 0; i < vvs.size(); i++) { patientID = vvs[i][0]; accessNumber = vvs[i][1]; if (find(patientIDVector.begin(), patientIDVector.end(), patientID) == patientIDVector.end() ) // a new patientID { patientIDVector.push_back(patientID); cout<<"patient ID: "<<patientID<<endl; } if (find(accessNumberVector.begin(), accessNumberVector.end(), accessNumber) == accessNumberVector.end() ) // a new accessNumber { accessNumberVector.push_back(accessNumber); cout<<" "<<"access#: "<<accessNumber<<endl; } cout<<" "<<vvs[i][2]<<": "<<vvs[i][3]<<endl; //list series#:series description } } else { cout << "The directory: "<<dicomDirectory<<" contains no DICOM Series! InputDirectory correct?"<<endl; return 0; } //write 3D volume if (write3D) { typedef std::vector< std::string > FileNamesContainer; FileNamesContainer fileNames; typedef itk::ImageFileWriter< ImageType > WriterType; WriterType::Pointer writer = WriterType::New(); string outFileName; seriesItr = seriesUID.begin(); while (seriesItr != seriesUID.end()) { string seriesIdentifier; if (writeAllSeries) //without -k option { seriesIdentifier = seriesItr->c_str(); } else //with -k option { //get sereisDescription according to seriesUID string seriesDescription = seriesUidToOtherStuff[*seriesItr][5]; transform(seriesDescription.begin(), seriesDescription.end(), seriesDescription.begin(), tolower);//to lower case //check if series Description contains the specified keyword (by -k) for( int i = 0; i < seriesKeywords.size(); i++) { if (seriesDescription.find(seriesKeywords[i]) != string::npos) { seriesIdentifier = seriesItr->c_str(); } } }//end if (writeAllSeries) if ( !seriesIdentifier.empty() ) { //get file names belong to specific series fileNames = nameGenerator->GetFileNames(seriesIdentifier); reader->SetImageIO(dicomIO); reader->SetFileNames(fileNames); //get output file name:PatientID_StudyID_StudyDate_Access#_Series#_SeriesDescription vector<string> vs = seriesUidToOtherStuff[seriesIdentifier]; string temp = vs[0]+"_"+vs[1]+"_"+vs[2]+"_"+vs[3]+"_"+vs[4]+"_"+vs[5]; string tempNew; //remove illegal characters for (string::iterator it = temp.begin(); it < temp.end(); ++it) { bool found = illegalChars.find(*it) != string::npos; if(!found){ tempNew=tempNew+(*it); } } //repace space with . . Many series descriptions come with spaces. But, filenames with spaces is not good. replace( tempNew.begin(), tempNew.end(), ' ', '.'); //get full path file name outFileName = outputDirectory + string(PATH_SEP) + tempNew + "."+outputFormat; //write writer->SetFileName(outFileName); writer->UseCompressionOn(); writer->SetInput(reader->GetOutput()); cout << "Writing: " << outFileName << endl; try { writer->Update(); } catch (itk::ExceptionObject &ex) { cout << ex << std::endl; continue; } //writing converted files full path to convertedList if ( writeConvertedList ) { try { convertedListFile << outFileName <<endl; } catch (std::ofstream::failure e) { cerr << "Exception writing file"<<endl; } } } seriesItr++; }//end while }//end if write3D //close convertedList file if (convertedListFile.is_open()) { try { convertedListFile.close(); } catch (std::ofstream::failure e) { cerr << "Exception closing file"<<endl; } } //print elasped time cout << "Elapsed time: "<<float( clock () - begin_time )/CLOCKS_PER_SEC<<" Seconds"; return 0; }
int main() { typedef unsigned short PixelType; const unsigned int Dimension = 3; typedef itk::Image< PixelType, Dimension > ImageType; typedef itk::VTKImageExport<ImageType> ImageExportType; typedef itk::ImageSeriesReader< ImageType > ReaderType; ReaderType::Pointer reader = ReaderType::New(); typedef itk::GDCMImageIO ImageIOType; ImageIOType::Pointer dicomIO = ImageIOType::New(); reader->SetImageIO( dicomIO ); typedef itk::GDCMSeriesFileNames NamesGeneratorType; NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New(); nameGenerator->SetUseSeriesDetails( true ); nameGenerator->AddSeriesRestriction("0008|0021" ); nameGenerator->SetDirectory( "/Users/mac/BIOMED/Subjects/testSubject"); typedef std::vector< std::string > SeriesIdContainer; const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs(); std::cout << seriesUID.size() << std::endl; SeriesIdContainer::const_iterator seriesItr = seriesUID.begin(); SeriesIdContainer::const_iterator seriesEnd = seriesUID.end(); while( seriesItr != seriesEnd ) { std::cout << seriesItr->c_str() << std::endl; seriesItr++; } std::string seriesIdentifier; seriesIdentifier = seriesUID.begin()->c_str(); std::cout << seriesIdentifier.c_str() << std::endl; typedef std::vector< std::string > FileNamesContainer; FileNamesContainer fileNames; fileNames = nameGenerator->GetFileNames( seriesIdentifier ); reader->SetFileNames( fileNames ); try { reader->Update(); } catch (itk::ExceptionObject &ex) { std::cout << ex << std::endl; } //------------------------------------------------------------------------ // ITK to VTK pipeline connection. //------------------------------------------------------------------------ // Create the itk::VTKImageExport instance and connect it to the // itk::CurvatureFlowImageFilter. ImageExportType::Pointer exporter = ImageExportType::New(); exporter->SetInput(reader->GetOutput()); exporter->Update(); // Create the vtkImageImport and connect it to the // itk::VTKImageExport instance. vtkImageImport* importer = vtkImageImport::New(); ConnectPipelines(exporter, importer); //------------------------------------------------------------------------ // VTK pipeline. //------------------------------------------------------------------------ //Demo Display DICOM Image /* string folder = "/Users/mac/BIOMED/Subjects/testSubject"; // Read all the DICOM files in the specified directory. vtkSmartPointer<vtkDICOMImageReader> reader2 = vtkSmartPointer<vtkDICOMImageReader>::New(); reader2->SetDirectoryName(folder.c_str()); reader2->Update(); */ vtkSmartPointer<vtkImageSliceMapper> imageSliceMapper = vtkSmartPointer<vtkImageSliceMapper>::New(); imageSliceMapper->SetInputConnection(importer->GetOutputPort()); //imageSliceMapper->SetInputData(importer->GetOutput()); imageSliceMapper->Update(); vtkSmartPointer<vtkImageSlice> imageSlice = vtkSmartPointer<vtkImageSlice>::New(); imageSlice->SetMapper(imageSliceMapper); vtkSmartPointer<vtkSmartVolumeMapper> volumeMapper = vtkSmartPointer<vtkSmartVolumeMapper>::New(); volumeMapper->SetBlendModeToComposite(); volumeMapper->SetInputConnection(importer->GetOutputPort()); vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New(); volumeProperty->ShadeOff(); volumeProperty->SetInterpolationType(VTK_LINEAR_INTERPOLATION); // Setup renderers vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New(); renderer->AddViewProp(imageSlice); renderer->ResetCamera(); renderer->SetBackground(0.1,0.4,0.2); // Setup render window vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->SetSize(500, 500); renderWindow->AddRenderer(renderer); vtkSmartPointer<vtkVolume> volume = vtkSmartPointer<vtkVolume>::New(); volume->SetMapper(volumeMapper); volume->SetProperty(volumeProperty); renderer->AddViewProp(volume); renderer->ResetCamera(); volumeMapper->SetRequestedRenderModeToRayCast(); volumeMapper->SetBlendModeToMinimumIntensity(); renderWindow->Render(); vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); // Render and start interaction renderWindowInteractor->SetRenderWindow(renderWindow); renderWindowInteractor->Initialize(); renderWindowInteractor->Start(); return 0; }