diff --git a/Modules/Bundles/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.cpp b/Modules/Bundles/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.cpp index b298150f71..11c3851800 100644 --- a/Modules/Bundles/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.cpp +++ b/Modules/Bundles/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportView.cpp @@ -1,659 +1,663 @@ /*========================================================================= Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "QmitkDiffusionDicomImportView.h" // qt includes #include // itk includes #include "itkTimeProbesCollectorBase.h" #include "itkGDCMSeriesFileNames.h" #include "itksys/SystemTools.hxx" // mitk includes #include "mitkProgressBar.h" #include "mitkStatusBar.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkMemoryUtilities.h" // diffusion module includes #include "mitkDicomDiffusionImageHeaderReader.h" #include "mitkGroupDiffusionHeadersFilter.h" #include "mitkDicomDiffusionImageReader.h" #include "mitkDiffusionImage.h" #include "mitkNrrdDiffusionImageWriter.h" #include "gdcmDirectory.h" #include "gdcmScanner.h" #include "gdcmSorter.h" #include "gdcmIPPSorter.h" #include "gdcmAttribute.h" #include "gdcmVersion.h" +#include + const std::string QmitkDiffusionDicomImport::VIEW_ID = "org.mitk.views.diffusiondicomimport"; QmitkDiffusionDicomImport::QmitkDiffusionDicomImport(QObject* /*parent*/, const char* /*name*/) : QmitkFunctionality(), m_Controls(NULL), m_MultiWidget(NULL), m_OutputFolderName(""), m_OutputFolderNameSet(false) { } QmitkDiffusionDicomImport::QmitkDiffusionDicomImport(const QmitkDiffusionDicomImport& other) { Q_UNUSED(other) throw std::runtime_error("Copy constructor not implemented"); } QmitkDiffusionDicomImport::~QmitkDiffusionDicomImport() {} void QmitkDiffusionDicomImport::CreateQtPartControl(QWidget *parent) { m_Parent = parent; if (m_Controls == NULL) { m_Controls = new Ui::QmitkDiffusionDicomImportControls; m_Controls->setupUi(parent); this->CreateConnections(); m_Controls->m_DicomLoadRecursiveCheckbox->setChecked(true); m_Controls->m_DicomLoadAverageDuplicatesCheckbox->setChecked(false); m_Controls->m_DicomLoadRecursiveCheckbox->setVisible(false); AverageClicked(); } } void QmitkDiffusionDicomImport::CreateConnections() { if ( m_Controls ) { - connect( m_Controls->m_AddFoldersButton, SIGNAL(clicked()), - this, SLOT(DicomLoadAddFolderNames()) ); - connect( m_Controls->m_DeleteFoldersButton, SIGNAL(clicked()), - this, SLOT(DicomLoadDeleteFolderNames()) ); - connect( m_Controls->m_DicomLoadStartLoadButton, SIGNAL(clicked()), - this, SLOT(DicomLoadStartLoad()) ); - connect( m_Controls->m_DicomLoadAverageDuplicatesCheckbox, SIGNAL(clicked()), - this, SLOT(AverageClicked()) ); - connect( m_Controls->m_OutputSetButton, SIGNAL(clicked()), - this, SLOT(OutputSet()) ); - connect( m_Controls->m_OutputClearButton, SIGNAL(clicked()), - this, SLOT(OutputClear()) ); + connect( m_Controls->m_AddFoldersButton, SIGNAL(clicked()), this, SLOT(DicomLoadAddFolderNames()) ); + connect( m_Controls->m_DeleteFoldersButton, SIGNAL(clicked()), this, SLOT(DicomLoadDeleteFolderNames()) ); + connect( m_Controls->m_DicomLoadStartLoadButton, SIGNAL(clicked()), this, SLOT(DicomLoadStartLoad()) ); + connect( m_Controls->m_DicomLoadAverageDuplicatesCheckbox, SIGNAL(clicked()), this, SLOT(AverageClicked()) ); + connect( m_Controls->m_OutputSetButton, SIGNAL(clicked()), this, SLOT(OutputSet()) ); + connect( m_Controls->m_OutputClearButton, SIGNAL(clicked()), this, SLOT(OutputClear()) ); } } void QmitkDiffusionDicomImport::OutputSet() { // SELECT FOLDER DIALOG QFileDialog* w = new QFileDialog( m_Parent, QString("Select folders containing DWI data") ); w->setFileMode( QFileDialog::Directory ); // RETRIEVE SELECTION if ( w->exec() != QDialog::Accepted ) return; m_OutputFolderName = w->selectedFiles()[0]; m_OutputFolderNameSet = true; m_Controls->m_OutputLabel->setText(m_OutputFolderName); } void QmitkDiffusionDicomImport::OutputClear() { m_OutputFolderName = ""; m_OutputFolderNameSet = false; m_Controls->m_OutputLabel->setText("... optional out-folder ..."); } void QmitkDiffusionDicomImport::AverageClicked() { m_Controls->m_Blur->setEnabled(m_Controls->m_DicomLoadAverageDuplicatesCheckbox->isChecked()); } void QmitkDiffusionDicomImport::Activated() { QmitkFunctionality::Activated(); } void QmitkDiffusionDicomImport::DicomLoadDeleteFolderNames() { m_Controls->listWidget->clear(); } void QmitkDiffusionDicomImport::DicomLoadAddFolderNames() { // SELECT FOLDER DIALOG QFileDialog* w = new QFileDialog( m_Parent, QString("Select folders containing DWI data") ); w->setFileMode( QFileDialog::Directory ); // RETRIEVE SELECTION if ( w->exec() != QDialog::Accepted ) return; m_Controls->listWidget->addItems(w->selectedFiles()); } bool SortBySeriesUID(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) { gdcm::Attribute<0x0020,0x000e> at1; at1.Set( ds1 ); gdcm::Attribute<0x0020,0x000e> at2; at2.Set( ds2 ); return at1 < at2; } bool SortByAcquisitionNumber(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) { gdcm::Attribute<0x0020,0x0012> at1; at1.Set( ds1 ); gdcm::Attribute<0x0020,0x0012> at2; at2.Set( ds2 ); return at1 < at2; } bool SortBySeqName(gdcm::DataSet const & ds1, gdcm::DataSet const & ds2 ) { gdcm::Attribute<0x0018, 0x0024> at1; at1.Set( ds1 ); gdcm::Attribute<0x0018, 0x0024> at2; at2.Set( ds2 ); std::string str1 = at1.GetValue(0).Trim(); std::string str2 = at2.GetValue(0).Trim(); return std::lexicographical_compare(str1.begin(), str1.end(), str2.begin(), str2.end() ); } void QmitkDiffusionDicomImport::Status(QString status) { mitk::StatusBar::GetInstance()->DisplayText(status.toAscii()); MITK_INFO << status.toStdString().c_str(); } void QmitkDiffusionDicomImport::Status(std::string status) { mitk::StatusBar::GetInstance()->DisplayText(status.c_str()); MITK_INFO << status.c_str(); } void QmitkDiffusionDicomImport::Status(const char* status) { mitk::StatusBar::GetInstance()->DisplayText(status); MITK_INFO << status; } void QmitkDiffusionDicomImport::Error(QString status) { mitk::StatusBar::GetInstance()->DisplayErrorText(status.toAscii()); MITK_ERROR << status.toStdString().c_str(); } void QmitkDiffusionDicomImport::Error(std::string status) { mitk::StatusBar::GetInstance()->DisplayErrorText(status.c_str()); MITK_ERROR << status.c_str(); } void QmitkDiffusionDicomImport::Error(const char* status) { mitk::StatusBar::GetInstance()->DisplayErrorText(status); MITK_ERROR << status; } void QmitkDiffusionDicomImport::PrintMemoryUsage() { size_t processSize = mitk::MemoryUtilities::GetProcessMemoryUsage(); size_t totalSize = mitk::MemoryUtilities::GetTotalSizeOfPhysicalRam(); float percentage = ( (float) processSize / (float) totalSize ) * 100.0; MITK_INFO << "Current memory usage: " << GetMemoryDescription( processSize, percentage ); } std::string QmitkDiffusionDicomImport::FormatMemorySize( size_t size ) { double val = size; std::string descriptor("B"); if ( val >= 1000.0 ) { val /= 1024.0; descriptor = "KB"; } if ( val >= 1000.0 ) { val /= 1024.0; descriptor = "MB"; } if ( val >= 1000.0 ) { val /= 1024.0; descriptor = "GB"; } std::ostringstream str; str << std::fixed << std::setprecision(2) << val << " " << descriptor; return str.str(); } std::string QmitkDiffusionDicomImport::FormatPercentage( double val ) { std::ostringstream str; str << std::fixed << std::setprecision(2) << val << " " << "%"; return str.str(); } std::string QmitkDiffusionDicomImport::GetMemoryDescription( size_t processSize, float percentage ) { std::ostringstream str; str << FormatMemorySize(processSize) << " (" << FormatPercentage( percentage ) <<")" ; return str.str(); } void QmitkDiffusionDicomImport::DicomLoadStartLoad() { itk::TimeProbesCollectorBase clock; + bool imageSuccessfullySaved = true; try { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, NULL ); if ( locale.compare(currLocale)!=0 ) { try { MITK_INFO << " ** Changing locale from " << setlocale(LC_ALL, NULL) << " to '" << locale << "'"; setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } int nrFolders = m_Controls->listWidget->count(); if(!nrFolders) { Error(QString("No input folders were selected. ABORTING.")); return; } Status(QString("GDCM %1 used for DICOM parsing and sorting!").arg(gdcm::Version::GetVersion())); PrintMemoryUsage(); QString status; mitk::DataNode::Pointer node; mitk::ProgressBar::GetInstance()->AddStepsToDo(3*nrFolders); while(m_Controls->listWidget->count()) { - // RETREIVE FOLDERNAME QListWidgetItem * item = m_Controls->listWidget->takeItem(0); QString folderName = item->text(); // PARSING DIRECTORY PrintMemoryUsage(); clock.Start(folderName.toAscii()); std::vector seriesUIDs(0); std::vector > seriesFilenames(0); Status("== Initial Directory Scan =="); gdcm::Directory d; d.Load( folderName.toStdString().c_str(), true ); // recursive ! const gdcm::Directory::FilenamesType &l1 = d.GetFilenames(); const unsigned int ntotalfiles = l1.size(); Status(QString(" ... found %1 different files").arg(ntotalfiles)); Status("Scanning Headers"); gdcm::Scanner s; const gdcm::Tag t1(0x0020,0x000d); // Study Instance UID const gdcm::Tag t2(0x0020,0x000e); // Series Instance UID const gdcm::Tag t5(0x0028, 0x0010); // number rows const gdcm::Tag t6(0x0028, 0x0011); // number cols s.AddTag( t1 ); s.AddTag( t2 ); s.AddTag( t5 ); s.AddTag( t6 ); bool b = s.Scan( d.GetFilenames() ); if( !b ) { Error("Scanner failed"); continue; } // Only get the DICOM files: gdcm::Directory::FilenamesType l2 = s.GetKeys(); const int nfiles = l2.size(); if(nfiles < 1) { Error("No DICOM files found"); continue; } Status(QString(" ... successfully scanned %1 headers.").arg(nfiles)); Status("Sorting"); const gdcm::Scanner::ValuesType &values1 = s.GetValues(t1); int nvalues = values1.size(); if(nvalues>1) { Error("Multiple studies found. Please limit to 1 study per folder"); continue; } const gdcm::Scanner::ValuesType &values5 = s.GetValues(t5); const gdcm::Scanner::ValuesType &values6 = s.GetValues(t6); if(values5.size()>1 || values6.size()>1) { Error("Folder contains images of unequal dimensions that cannot be combined in one 3d volume. ABORTING."); continue; } const gdcm::Scanner::ValuesType &values2 = s.GetValues(t2); int nSeries = values2.size(); gdcm::Directory::FilenamesType files; if(nSeries > 1) { gdcm::Sorter sorter; sorter.SetSortFunction( SortBySeriesUID ); sorter.StableSort( l2 ); files = sorter.GetFilenames(); } else { files = l2; } unsigned int nTotalAcquis = 0; if(nfiles % nSeries != 0) { Error("Number of files in series not equal, ABORTING"); continue; } int filesPerSeries = nfiles / nSeries; gdcm::Scanner::ValuesType::const_iterator it2 = values2.begin(); for(int i=0; i & list = ippsorter.GetFilenames(); seriesFilenames.push_back(list); seriesUIDs.push_back(identifier.c_str()); } ++it2; } if(nfiles % nTotalAcquis != 0) { Error("Number of files per acquisition differs between series, ABORTING"); continue; } int slices = nfiles/nTotalAcquis; Status(QString("Series is composed of %1 different 3D volumes with %2 slices.").arg(nTotalAcquis).arg(slices)); // READING HEADER-INFOS PrintMemoryUsage(); Status(QString("Reading Headers %1").arg(folderName)); mitk::DicomDiffusionImageHeaderReader::Pointer headerReader; mitk::GroupDiffusionHeadersFilter::InputType inHeaders; unsigned int size2 = seriesUIDs.size(); for ( unsigned int i = 0 ; i < size2 ; ++i ) { Status(QString("Reading header image #%1/%2").arg(i+1).arg(size2)); headerReader = mitk::DicomDiffusionImageHeaderReader::New(); headerReader->SetSeriesDicomFilenames(seriesFilenames[i]); headerReader->Update(); inHeaders.push_back(headerReader->GetOutput()); //Status(std::endl; } mitk::ProgressBar::GetInstance()->Progress(); // // GROUP HEADERS // mitk::GroupDiffusionHeadersFilter::Pointer grouper // = mitk::GroupDiffusionHeadersFilter::New(); // mitk::GroupDiffusionHeadersFilter::OutputType outHeaders; // grouper->SetInput(inHeaders); // grouper->Update(); // outHeaders = grouper->GetOutput(); // READ VOLUMES PrintMemoryUsage(); Status(QString("Loading Volumes %1").arg(folderName)); typedef short PixelValueType; typedef mitk::DicomDiffusionImageReader< PixelValueType, 3 > VolumesReader; VolumesReader::Pointer vReader = VolumesReader::New(); VolumesReader::HeaderContainer hc = inHeaders; // hc.insert(hc.end(), outHeaders[1].begin(), outHeaders[1].end() ); // hc.insert(hc.end(), outHeaders[2].begin(), outHeaders[2].end() ); if(hc.size()>1) { vReader->SetHeaders(hc); vReader->Update(); VolumesReader::OutputImageType::Pointer vecImage; vecImage = vReader->GetOutput(); Status(QString("Volumes Loaded (%1)").arg(folderName)); // CONSTRUCT CONTAINER WITH DIRECTIONS typedef vnl_vector_fixed< double, 3 > GradientDirectionType; typedef itk::VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; GradientDirectionContainerType::Pointer directions = GradientDirectionContainerType::New(); std::vector b_vals; double maxb = 0; for(unsigned int i=0; ibValue; if(maxb vect = hc[i]->DiffusionVector; vect.normalize(); vect *= sqrt(b_vals[i]/maxb); directions->push_back(vect); } // DWI TO DATATREE PrintMemoryUsage(); Status(QString("Initializing Diffusion Image")); typedef mitk::DiffusionImage DiffVolumesType; DiffVolumesType::Pointer diffImage = DiffVolumesType::New(); diffImage->SetDirections(directions); diffImage->SetOriginalDirections(directions); if(m_Controls->m_DicomLoadDKFZ->isChecked()) { diffImage->CorrectDKFZBrokenGradientScheme(m_Controls->m_Blur->value()); } diffImage->SetVectorImage(vecImage); diffImage->SetB_Value(maxb); diffImage->InitializeFromVectorImage(); Status(QString("Diffusion Image initialized")); if(m_Controls->m_DicomLoadAverageDuplicatesCheckbox->isChecked()) { PrintMemoryUsage(); Status(QString("Averaging gradient directions")); diffImage->AverageRedundantGradients(m_Controls->m_Blur->value()); } //if(m_Controls->m_DicomLoadDuplicateIfSingleSliceCheckbox->isChecked()) // diffVolumes->DuplicateIfSingleSlice(); QString descr = QString("%1_%2_%3") .arg(((inHeaders)[0])->seriesDescription.c_str()) .arg(((inHeaders)[0])->seriesNumber) .arg(((inHeaders)[0])->patientName.c_str()); descr = descr.trimmed(); descr = descr.replace(" ", "_"); if(!m_OutputFolderNameSet) { node=mitk::DataNode::New(); node->SetData( diffImage ); GetDefaultDataStorage()->Add(node); SetDwiNodeProperties(node, descr.toStdString().c_str()); Status(QString("Image %1 added to datastorage").arg(descr)); } else { typedef mitk::NrrdDiffusionImageWriter WriterType; WriterType::Pointer writer = WriterType::New(); QString fullpath = QString("%1/%2.dwi") .arg(m_OutputFolderName) .arg(descr); std::string pathstring = itksys::SystemTools::ConvertToOutputPath(fullpath.toStdString().c_str()); writer->SetFileName(pathstring); writer->SetInput(diffImage); try { writer->Update(); } catch (itk::ExceptionObject &ex) { + imageSuccessfullySaved = false; Error(QString("%1\n%2\n%3\n%4\n%5\n%6").arg(ex.GetNameOfClass()).arg(ex.GetFile()).arg(ex.GetLine()).arg(ex.GetLocation()).arg(ex.what()).arg(ex.GetDescription())); + node=mitk::DataNode::New(); + node->SetData( diffImage ); + GetDefaultDataStorage()->Add(node); + SetDwiNodeProperties(node, descr.toStdString().c_str()); + Status(QString("Image %1 added to datastorage").arg(descr)); continue ; } Status(QString("Image %1 written to disc (%1)").arg(fullpath.toStdString().c_str())); } } else { Status(QString("No diffusion information found (%1)").arg(folderName)); } Status(QString("Finished processing %1 with memory:").arg(folderName)); PrintMemoryUsage(); clock.Stop(folderName.toAscii()); mitk::ProgressBar::GetInstance()->Progress(); } Status("Timing information"); clock.Report(); if(!m_OutputFolderNameSet && node.IsNotNull()) { mitk::BaseData::Pointer basedata = node->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); try { MITK_INFO << " ** Changing locale back from " << setlocale(LC_ALL, NULL) << " to '" << currLocale << "'"; setlocale(LC_ALL, currLocale.c_str()); } catch(...) { MITK_INFO << "Could not reset locale " << currLocale; } } catch (itk::ExceptionObject &ex) { Error(QString("%1\n%2\n%3\n%4\n%5\n%6").arg(ex.GetNameOfClass()).arg(ex.GetFile()).arg(ex.GetLine()).arg(ex.GetLocation()).arg(ex.what()).arg(ex.GetDescription())); return ; } + if (!imageSuccessfullySaved) + QMessageBox::warning(NULL,"WARNING","One or more files could not be saved! The according files where moved to the datastorage."); Status(QString("Finished import with memory:")); PrintMemoryUsage(); } void QmitkDiffusionDicomImport::SetDwiNodeProperties(mitk::DataNode::Pointer node, std::string name) { node->SetProperty( "IsDWIRawVolume", mitk::BoolProperty::New( true ) ); // set foldername as string property mitk::StringProperty::Pointer nameProp = mitk::StringProperty::New( name ); node->SetProperty( "name", nameProp ); } diff --git a/Modules/DiffusionImaging/IODataStructures/DiffusionWeightedImages/mitkNrrdDiffusionImageWriter.cpp b/Modules/DiffusionImaging/IODataStructures/DiffusionWeightedImages/mitkNrrdDiffusionImageWriter.cpp index 44ecb43c36..53d61fa9c2 100644 --- a/Modules/DiffusionImaging/IODataStructures/DiffusionWeightedImages/mitkNrrdDiffusionImageWriter.cpp +++ b/Modules/DiffusionImaging/IODataStructures/DiffusionWeightedImages/mitkNrrdDiffusionImageWriter.cpp @@ -1,326 +1,328 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2008-12-10 18:05:13 +0100 (Mi, 10 Dez 2008) $ Version: $Revision: 15922 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef __mitkNrrdDiffusionImageWriter__cpp #define __mitkNrrdDiffusionImageWriter__cpp #include "mitkNrrdDiffusionImageWriter.h" #include "itkMetaDataDictionary.h" #include "itkMetaDataObject.h" #include "itkNrrdImageIO.h" #include "itkNiftiImageIO.h" #include "itkImageFileWriter.h" #include "itksys/SystemTools.hxx" #include #include template mitk::NrrdDiffusionImageWriter::NrrdDiffusionImageWriter() : m_FileName(""), m_FilePrefix(""), m_FilePattern(""), m_Success(false) { this->SetNumberOfRequiredInputs( 1 ); } template mitk::NrrdDiffusionImageWriter::~NrrdDiffusionImageWriter() {} template void mitk::NrrdDiffusionImageWriter::GenerateData() { m_Success = false; InputType* input = this->GetInput(); if (input == NULL) { itkWarningMacro(<<"Sorry, input to NrrdDiffusionImageWriter is NULL!"); return; } if ( m_FileName == "" ) { itkWarningMacro( << "Sorry, filename has not been set!" ); return ; } const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, NULL ); if ( locale.compare(currLocale)!=0 ) { try { MITK_INFO << " ** Changing locale from " << setlocale(LC_ALL, NULL) << " to '" << locale << "'"; setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } char keybuffer[512]; char valbuffer[512]; std::string tmp; itk::VectorImage::Pointer img = input->GetVectorImage(); img->GetMetaDataDictionary(); //itk::MetaDataDictionary dic = input->GetImage()->GetMetaDataDictionary(); vnl_matrix_fixed measurementFrame = input->GetMeasurementFrame(); if (measurementFrame(0,0) || measurementFrame(0,1) || measurementFrame(0,2) || measurementFrame(1,0) || measurementFrame(1,1) || measurementFrame(1,2) || measurementFrame(2,0) || measurementFrame(2,1) || measurementFrame(2,2)) { sprintf( valbuffer, " ( %lf , %lf , %lf ) ( %lf , %lf , %lf ) ( %lf , %lf , %lf ) \n", measurementFrame(0,0), measurementFrame(0,1), measurementFrame(0,2), measurementFrame(1,0), measurementFrame(1,1), measurementFrame(1,2), measurementFrame(2,0), measurementFrame(2,1), measurementFrame(2,2)); itk::EncapsulateMetaData(input->GetVectorImage()->GetMetaDataDictionary(),std::string("measurement frame"),std::string(valbuffer)); } sprintf( valbuffer, "DWMRI"); itk::EncapsulateMetaData(input->GetVectorImage()->GetMetaDataDictionary(),std::string("modality"),std::string(valbuffer)); if(input->GetOriginalDirections()->Size()) { sprintf( valbuffer, "%1f", input->GetB_Value() ); itk::EncapsulateMetaData(input->GetVectorImage()->GetMetaDataDictionary(),std::string("DWMRI_b-value"),std::string(valbuffer)); } for(unsigned int i=0; iGetOriginalDirections()->Size(); i++) { sprintf( keybuffer, "DWMRI_gradient_%04d", i ); /*if(itk::ExposeMetaData(input->GetMetaDataDictionary(), std::string(keybuffer),tmp)) continue;*/ sprintf( valbuffer, "%1f %1f %1f", input->GetOriginalDirections()->ElementAt(i).get(0), input->GetOriginalDirections()->ElementAt(i).get(1), input->GetOriginalDirections()->ElementAt(i).get(2)); itk::EncapsulateMetaData(input->GetVectorImage()->GetMetaDataDictionary(),std::string(keybuffer),std::string(valbuffer)); } typedef itk::VectorImage ImageType; std::string ext = itksys::SystemTools::GetFilenameLastExtension(m_FileName); ext = itksys::SystemTools::LowerCase(ext); if (ext == ".hdwi" || ext == ".dwi") { itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); //io->SetNrrdVectorType( nrrdKindList ); io->SetFileType( itk::ImageIOBase::Binary ); io->UseCompressionOn(); typedef itk::ImageFileWriter WriterType; typename WriterType::Pointer nrrdWriter = WriterType::New(); nrrdWriter->UseInputMetaDataDictionaryOn(); nrrdWriter->SetInput( input->GetVectorImage() ); nrrdWriter->SetImageIO(io); nrrdWriter->SetFileName(m_FileName); nrrdWriter->UseCompressionOn(); nrrdWriter->SetImageIO(io); try { nrrdWriter->Update(); } catch (itk::ExceptionObject e) { std::cout << e << std::endl; + throw; } } else if (ext == ".fsl" || ext == ".fslgz") { MITK_INFO << "Writing Nifti-Image for FSL"; typename ImageType::Pointer vecimg = input->GetVectorImage(); typedef itk::Image ImageType4D; typename ImageType4D::Pointer img4 = ImageType4D::New(); typename ImageType::SpacingType spacing = vecimg->GetSpacing(); typename ImageType4D::SpacingType spacing4; for(int i=0; i<3; i++) spacing4[i] = spacing[i]; spacing4[3] = 1; img4->SetSpacing( spacing4 ); // Set the image spacing typename ImageType::PointType origin = vecimg->GetOrigin(); typename ImageType4D::PointType origin4; for(int i=0; i<3; i++) origin4[i] = origin[i]; origin4[3] = 0; img4->SetOrigin( origin4 ); // Set the image origin typename ImageType::DirectionType direction = vecimg->GetDirection(); typename ImageType4D::DirectionType direction4; for(int i=0; i<3; i++) for(int j=0; j<3; j++) direction4[i][j] = direction[i][j]; for(int i=0; i<4; i++) direction4[i][3] = 0; for(int i=0; i<4; i++) direction4[3][i] = 0; direction4[3][3] = 1; img4->SetDirection( direction4 ); // Set the image direction typename ImageType::RegionType region = vecimg->GetLargestPossibleRegion(); typename ImageType4D::RegionType region4; typename ImageType::RegionType::SizeType size = region.GetSize(); typename ImageType4D::RegionType::SizeType size4; for(int i=0; i<3; i++) size4[i] = size[i]; size4[3] = vecimg->GetVectorLength(); typename ImageType::RegionType::IndexType index = region.GetIndex(); typename ImageType4D::RegionType::IndexType index4; for(int i=0; i<3; i++) index4[i] = index[i]; index4[3] = 0; region4.SetSize(size4); region4.SetIndex(index4); img4->SetRegions( region4 ); img4->Allocate(); itk::ImageRegionIterator it (vecimg, vecimg->GetLargestPossibleRegion() ); typedef typename ImageType::PixelType VecPixType; for (it = it.Begin(); !it.IsAtEnd(); ++it) { VecPixType vec = it.Get(); typename ImageType::IndexType currentIndex = it.GetIndex(); for(unsigned int ind=0; indSetPixel(index4, vec[ind]); } } // create copy of file with correct ending for mitk std::string fname3 = m_FileName; std::string newext = ext == ".fsl" ? "nii" : "nii.gz"; std::string::iterator itend = fname3.end(); fname3.replace( itend-3, itend, newext); itk::NiftiImageIO::Pointer io4 = itk::NiftiImageIO::New(); typedef itk::VectorImage ImageType; typedef itk::ImageFileWriter WriterType4; typename WriterType4::Pointer nrrdWriter4 = WriterType4::New(); nrrdWriter4->UseInputMetaDataDictionaryOn(); nrrdWriter4->SetInput( img4 ); nrrdWriter4->SetFileName(fname3); nrrdWriter4->UseCompressionOn(); nrrdWriter4->SetImageIO(io4); try { nrrdWriter4->Update(); } catch (itk::ExceptionObject e) { std::cout << e << std::endl; + throw; } itksys::SystemTools::CopyAFile(fname3.c_str(), m_FileName.c_str()); if(input->GetDirections()->Size()) { std::ofstream myfile; std::string fname = m_FileName; fname += ".bvals"; myfile.open (fname.c_str()); for(unsigned int i=0; iGetDirections()->Size(); i++) { double twonorm = input->GetDirections()->ElementAt(i).two_norm(); myfile << input->GetB_Value()*twonorm*twonorm << " "; } myfile.close(); std::ofstream myfile2; std::string fname2 = m_FileName; fname2 += ".bvecs"; myfile2.open (fname2.c_str()); for(int j=0; j<3; j++) { for(unsigned int i=0; iGetDirections()->Size(); i++) { myfile2 << input->GetDirections()->ElementAt(i).get(j) << " "; } myfile2 << std::endl; } std::ofstream myfile3; std::string fname4 = m_FileName; fname4 += ".ttk"; myfile3.open (fname4.c_str()); for(unsigned int i=0; iGetDirections()->Size(); i++) { for(int j=0; j<3; j++) { myfile3 << input->GetDirections()->ElementAt(i).get(j) << " "; } myfile3 << std::endl; } } } try { MITK_INFO << " ** Changing locale back from " << setlocale(LC_ALL, NULL) << " to '" << currLocale << "'"; setlocale(LC_ALL, currLocale.c_str()); } catch(...) { MITK_INFO << "Could not reset locale " << currLocale; } m_Success = true; } template void mitk::NrrdDiffusionImageWriter::SetInput( InputType* diffVolumes ) { this->ProcessObject::SetNthInput( 0, diffVolumes ); } template mitk::DiffusionImage* mitk::NrrdDiffusionImageWriter::GetInput() { if ( this->GetNumberOfInputs() < 1 ) { return NULL; } else { return dynamic_cast ( this->ProcessObject::GetInput( 0 ) ); } } template std::vector mitk::NrrdDiffusionImageWriter::GetPossibleFileExtensions() { std::vector possibleFileExtensions; possibleFileExtensions.push_back(".dwi"); possibleFileExtensions.push_back(".hdwi"); possibleFileExtensions.push_back(".fsl"); possibleFileExtensions.push_back(".fslgz"); return possibleFileExtensions; } #endif //__mitkNrrdDiffusionImageWriter__cpp diff --git a/Modules/DiffusionImaging/Tractography/itkGibbsTrackingFilter.cpp b/Modules/DiffusionImaging/Tractography/itkGibbsTrackingFilter.cpp index 44d0c4ee47..b29b82bd2f 100644 --- a/Modules/DiffusionImaging/Tractography/itkGibbsTrackingFilter.cpp +++ b/Modules/DiffusionImaging/Tractography/itkGibbsTrackingFilter.cpp @@ -1,475 +1,484 @@ #include "itkGibbsTrackingFilter.h" #include #include #include "itkPointShell.h" #include "GibbsTracking/BuildFibres.cpp" #pragma GCC visibility push(default) #include #pragma GCC visibility pop #include #include #include #include #include #include #include "GibbsTracking/reparametrize_arclen2.cpp" #include struct LessDereference { template bool operator()(const T * lhs, const T * rhs) const { return *lhs < *rhs; } }; namespace itk{ template< class TInputOdfImage, class TInputROIImage > GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::GibbsTrackingFilter(): m_TempStart(0.1), m_TempEnd(0.001), m_NumIt(500000), m_ParticleWeight(0), m_ParticleWidth(0), m_ParticleLength(0), m_ChempotConnection(10), m_ChempotParticle(0), m_InexBalance(0), m_Chempot2(0.2), m_FiberLength(10), m_AbortTracking(false), m_NumConnections(0), m_NumParticles(0), m_NumAcceptedFibers(0), m_CurrentStep(0), m_SubtractMean(true), m_BuildFibers(false), m_Sampler(NULL), m_Steps(10), m_Memory(0), m_ProposalAcceptance(0) { //this->m_MeasurementFrame.set_identity(); this->SetNumberOfRequiredInputs(2); //Filter needs a DWI image + a Mask Image } template< class TInputOdfImage, class TInputROIImage > GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::~GibbsTrackingFilter(){ delete BESSEL_APPROXCOEFF; if (m_Sampler!=NULL) delete m_Sampler; } template< class TInputOdfImage, class TInputROIImage > void GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::ComputeFiberCorrelation(){ // float bD = 15; // vnl_matrix_fixed bDir = // *itk::PointShell >::DistributePointShell(); // const int N = QBALL_ODFSIZE; // vnl_matrix_fixed temp = bDir.transpose(); // vnl_matrix_fixed C = temp*bDir; // vnl_matrix_fixed Q = C; // vnl_vector_fixed mean; // for(int i=0; i repMean; // for (int i=0; i P = Q*Q; // std::vector pointer; // pointer.reserve(N*N); // double * start = C.data_block(); // double * end = start + N*N; // for (double * iter = start; iter != end; ++iter) // { // pointer.push_back(iter); // } // std::sort(pointer.begin(), pointer.end(), LessDereference()); // vnl_vector_fixed alpha; // vnl_vector_fixed beta; // for (int i=0; im_Meanval_sq = (sum*sum)/N; // vnl_vector_fixed alpha_0; // vnl_vector_fixed alpha_2; // vnl_vector_fixed alpha_4; // vnl_vector_fixed alpha_6; // for(int i=0; i T; // T.set_column(0,alpha_0); // T.set_column(1,alpha_2); // T.set_column(2,alpha_4); // T.set_column(3,alpha_6); // vnl_vector_fixed coeff = vnl_matrix_inverse(T).pinverse()*beta; // MITK_INFO << "Bessel oefficients: " << coeff; BESSEL_APPROXCOEFF = new float[4]; // BESSEL_APPROXCOEFF[0] = coeff(0); // BESSEL_APPROXCOEFF[1] = coeff(1); // BESSEL_APPROXCOEFF[2] = coeff(2); // BESSEL_APPROXCOEFF[3] = coeff(3); BESSEL_APPROXCOEFF[0] = -0.1714; BESSEL_APPROXCOEFF[1] = 0.5332; BESSEL_APPROXCOEFF[2] = -1.4889; BESSEL_APPROXCOEFF[3] = 2.0389; } // build fibers from tracking result template< class TInputOdfImage, class TInputROIImage > void GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::BuildFibers(float* points, int numPoints) { MITK_INFO << "Building fibers ..."; typename InputQBallImageType::Pointer odfImage = dynamic_cast(this->GetInput(0)); double spacing[3]; spacing[0] = odfImage->GetSpacing().GetElement(0); spacing[1] = odfImage->GetSpacing().GetElement(1); spacing[2] = odfImage->GetSpacing().GetElement(2); // initialize array of particles CCAnalysis ccana(points, numPoints, spacing); // label the particles according to fiber affiliation and return number of fibers int numFibers = ccana.iterate(m_FiberLength); if (numFibers<=0){ MITK_INFO << "0 fibers accepted"; return; } // fill output datastructure m_FiberBundle.clear(); for (int i = 0; i < numFibers; i++) { vector< Particle* >* particleContainer = ccana.m_FiberContainer->at(i); // resample fibers std::vector< Particle* >* pCon = ResampleFibers(particleContainer, 0.9*spacing[0]); FiberTractType tract; for (int j=0; jsize(); j++) { Particle* particle = pCon->at(j); pVector p = particle->R; itk::Point point; point[0] = p[0]-0.5; point[1] = p[1]-0.5; point[2] = p[2]-0.5; tract.push_back(point); delete(particle); } m_FiberBundle.push_back(tract); delete(pCon); } m_NumAcceptedFibers = numFibers; MITK_INFO << "itkGibbsTrackingFilter: " << numFibers << " fibers accepted"; } // fill output fiber bundle datastructure template< class TInputOdfImage, class TInputROIImage > typename GibbsTrackingFilter< TInputOdfImage, TInputROIImage >::FiberBundleType* GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::GetFiberBundle() { if (!m_AbortTracking) { m_BuildFibers = true; while (m_BuildFibers){} } return &m_FiberBundle; } // get memory allocated for particle grid template< class TInputOdfImage, class TInputROIImage > float GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::GetMemoryUsage() { if (m_Sampler!=NULL) return m_Sampler->m_ParticleGrid.GetMemoryUsage(); return 0; } // perform global tracking template< class TInputOdfImage, class TInputROIImage > void GibbsTrackingFilter< TInputOdfImage, TInputROIImage > ::GenerateData(){ // input qball image m_ItkQBallImage = dynamic_cast(this->GetInput(0)); // approximationscoeffizienten der // teilchenkorrelationen im orientierungsraum // 4er vektor ComputeFiberCorrelation(); // image sizes and spacing int qBallImageSize[4] = {QBALL_ODFSIZE, m_ItkQBallImage->GetLargestPossibleRegion().GetSize().GetElement(0), m_ItkQBallImage->GetLargestPossibleRegion().GetSize().GetElement(1), m_ItkQBallImage->GetLargestPossibleRegion().GetSize().GetElement(2)}; double qBallImageSpacing[3] = {m_ItkQBallImage->GetSpacing().GetElement(0),m_ItkQBallImage->GetSpacing().GetElement(1),m_ItkQBallImage->GetSpacing().GetElement(2)}; // make sure image has enough slices if (qBallImageSize[1]<3 || qBallImageSize[2]<3 || qBallImageSize[3]<3) { MITK_INFO << "image size < 3 not supported"; return; } // calculate rotation matrix vnl_matrix_fixed directionMatrix = m_ItkQBallImage->GetDirection().GetVnlMatrix(); vnl_vector_fixed d0 = directionMatrix.get_column(0); d0.normalize(); vnl_vector_fixed d1 = directionMatrix.get_column(1); d1.normalize(); vnl_vector_fixed d2 = directionMatrix.get_column(2); d2.normalize(); directionMatrix.set_column(0, d0); directionMatrix.set_column(1, d1); directionMatrix.set_column(2, d2); vnl_matrix_fixed I = directionMatrix*directionMatrix.transpose(); if(!I.is_identity(mitk::eps)){ MITK_INFO << "Image direction is not a rotation matrix. Tracking not possible!"; return; } // generate local working copy of image buffer int bufferSize = qBallImageSize[0]*qBallImageSize[1]*qBallImageSize[2]*qBallImageSize[3]; float* qBallImageBuffer = (float*) m_ItkQBallImage->GetBufferPointer(); float* workingQballImage = new float[bufferSize]; for (int i=0; i0 && i%qBallImageSize[0] == 0 && i>0) { sum /= qBallImageSize[0]; for (int j=i-qBallImageSize[0]; jGetBufferPointer(); maskImageSize[0] = m_MaskImage->GetLargestPossibleRegion().GetSize().GetElement(0); maskImageSize[1] = m_MaskImage->GetLargestPossibleRegion().GetSize().GetElement(1); maskImageSize[2] = m_MaskImage->GetLargestPossibleRegion().GetSize().GetElement(2); } else { mask = 0; maskImageSize[0] = qBallImageSize[1]; maskImageSize[1] = qBallImageSize[2]; maskImageSize[2] = qBallImageSize[3]; } int mask_oversamp_mult = maskImageSize[0]/qBallImageSize[1]; // load lookuptable ifstream BaryCoords; + +#ifdef CMAKE_INTDIR + BaryCoords.open("../FiberTrackingLUTBaryCoords.bin", ios::in | ios::binary); +#else BaryCoords.open("FiberTrackingLUTBaryCoords.bin", ios::in | ios::binary); +#endif float* coords; if (BaryCoords.is_open()) { float tmp; coords = new float [1630818]; BaryCoords.seekg (0, ios::beg); for (int i=0; i<1630818; i++) { BaryCoords.read((char *)&tmp, sizeof(tmp)); coords[i] = tmp; } BaryCoords.close(); } else { MITK_INFO << "Unable to open barycoords file"; return; } ifstream Indices; +#ifdef CMAKE_INTDIR + Indices.open("../FiberTrackingLUTIndices.bin", ios::in | ios::binary); +#else Indices.open("FiberTrackingLUTIndices.bin", ios::in | ios::binary); +#endif int* ind; if (Indices.is_open()) { int tmp; ind = new int [1630818]; Indices.seekg (0, ios::beg); for (int i=0; i<1630818; i++) { Indices.read((char *)&tmp, 4); ind[i] = tmp; } Indices.close(); } else { MITK_INFO << "Unable to open indices file"; return; } // initialize sphere interpolator with lookuptables SphereInterpolator *sinterp = new SphereInterpolator(coords, ind, QBALL_ODFSIZE, 301, 0.5); // get paramters float minSpacing; if(qBallImageSpacing[0]m_NumIt) { MITK_INFO << "not enough iterations!"; return; } unsigned long singleIts = (unsigned long)((1.0*m_NumIt) / (1.0*m_Steps)); // setup metropolis hastings sampler MITK_INFO << "itkGibbsTrackingFilter: setting up MH-sampler"; if (m_Sampler!=NULL) delete m_Sampler; m_Sampler = new RJMCMC(NULL, 0, workingQballImage, qBallImageSize, qBallImageSpacing, cellsize); // setup energy computer MITK_INFO << "itkGibbsTrackingFilter: setting up Energy-computer"; EnergyComputer encomp(workingQballImage,qBallImageSize,qBallImageSpacing,sinterp,&(m_Sampler->m_ParticleGrid),mask,mask_oversamp_mult, directionMatrix); encomp.setParameters(m_ParticleWeight,m_ParticleWidth,m_ChempotConnection*m_ParticleLength*m_ParticleLength,m_ParticleLength,curvatureHardThreshold,m_InexBalance,m_Chempot2); m_Sampler->SetEnergyComputer(&encomp); m_Sampler->SetParameters(m_TempStart,singleIts,m_ParticleLength,curvatureHardThreshold,m_ChempotParticle); // main loop for( int step = 0; step < m_Steps; step++ ) { if (m_AbortTracking) break; m_CurrentStep = step+1; float temperature = m_TempStart * exp(alpha*(((1.0)*step)/((1.0)*m_Steps))); MITK_INFO << "iterating step " << m_CurrentStep; m_Sampler->SetTemperature(temperature); m_Sampler->Iterate(&m_ProposalAcceptance, &m_NumConnections, &m_NumParticles, &m_AbortTracking); MITK_INFO << "proposal acceptance: " << 100*m_ProposalAcceptance << "%"; MITK_INFO << "particles: " << m_NumParticles; MITK_INFO << "connections: " << m_NumConnections; MITK_INFO << "progress: " << 100*(float)step/m_Steps << "%"; if (m_BuildFibers) { int numPoints = m_Sampler->m_ParticleGrid.pcnt; float* points = new float[numPoints*m_Sampler->m_NumAttributes]; m_Sampler->WriteOutParticles(points); BuildFibers(points, numPoints); delete points; m_BuildFibers = false; } } int numPoints = m_Sampler->m_ParticleGrid.pcnt; float* points = new float[numPoints*m_Sampler->m_NumAttributes]; m_Sampler->WriteOutParticles(points); BuildFibers(points, numPoints); delete points; delete sinterp; delete coords; delete ind; delete workingQballImage; m_AbortTracking = true; m_BuildFibers = false; MITK_INFO << "done generate data"; } }