diff --git a/Modules/DiffusionImaging/DiffusionCore/Testing/mitkDiffusionDICOMFileReaderTest.cpp b/Modules/DiffusionImaging/DiffusionCore/Testing/mitkDiffusionDICOMFileReaderTest.cpp index 442d2b82fa..f9512c8183 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Testing/mitkDiffusionDICOMFileReaderTest.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/Testing/mitkDiffusionDICOMFileReaderTest.cpp @@ -1,119 +1,120 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDiffusionDICOMFileReader.h" #include "mitkDiffusionDICOMFileReaderTestHelper.h" #include "mitkDICOMTagBasedSorter.h" #include "mitkDICOMSortByTag.h" #include "mitkNrrdDiffusionImageWriter.h" #include "mitkTestingMacros.h" using mitk::DICOMTag; int mitkDiffusionDICOMFileReaderTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkDiffusionDICOMFileReaderTest"); mitk::DiffusionDICOMFileReader::Pointer gdcmReader = mitk::DiffusionDICOMFileReader::New(); MITK_TEST_CONDITION_REQUIRED(gdcmReader.IsNotNull(), "DICOMITKSeriesGDCMReader can be instantiated."); std::string output_filename = "/tmp/dicom_out.dwi"; if( argc > 3) { mitk::DICOMFileReaderTestHelper::SetTestInputFilenames( argc-1,argv ); output_filename = std::string( argv[argc-1] ); } else { mitk::DICOMFileReaderTestHelper::SetTestInputFilenames( argc,argv ); } // check the Set/GetInput function mitk::DICOMFileReaderTestHelper::TestInputFilenames( gdcmReader ); MITK_INFO << "Test input filenanems"; // check that output is a good reproduction of input (no duplicates, no new elements) mitk::DICOMFileReaderTestHelper::TestOutputsContainInputs( gdcmReader ); MITK_INFO << "Test output"; // repeat test with some more realistic sorting gdcmReader = mitk::DiffusionDICOMFileReader::New(); // this also tests destruction mitk::DICOMTagBasedSorter::Pointer tagSorter = mitk::DICOMTagBasedSorter::New(); // Use tags as in Qmitk // all the things that split by tag in DicomSeriesReader tagSorter->AddDistinguishingTag( DICOMTag(0x0028, 0x0010) ); // Number of Rows tagSorter->AddDistinguishingTag( DICOMTag(0x0028, 0x0011) ); // Number of Columns tagSorter->AddDistinguishingTag( DICOMTag(0x0028, 0x0030) ); // Pixel Spacing tagSorter->AddDistinguishingTag( DICOMTag(0x0018, 0x1164) ); // Imager Pixel Spacing tagSorter->AddDistinguishingTag( DICOMTag(0x0020, 0x0037) ); // Image Orientation (Patient) // TODO add tolerance parameter (l. 1572 of original code) // TODO handle as real vectors! cluster with configurable errors! - tagSorter->AddDistinguishingTag( DICOMTag(0x0020, 0x000e) ); // Series Instance UID + //tagSorter->AddDistinguishingTag( DICOMTag(0x0020, 0x000e) ); // Series Instance UID + //tagSorter->AddDistinguishingTag( DICOMTag(0x0020, 0x0010) ); tagSorter->AddDistinguishingTag( DICOMTag(0x0018, 0x0050) ); // Slice Thickness tagSorter->AddDistinguishingTag( DICOMTag(0x0028, 0x0008) ); // Number of Frames tagSorter->AddDistinguishingTag( DICOMTag(0x0020, 0x0052) ); // Frame of Reference UID // gdcmReader->AddSortingElement( tagSorter ); //mitk::DICOMFileReaderTestHelper::TestOutputsContainInputs( gdcmReader ); mitk::DICOMSortCriterion::ConstPointer sorting = mitk::DICOMSortByTag::New( DICOMTag(0x0020, 0x0013), // instance number mitk::DICOMSortByTag::New( DICOMTag(0x0020, 0x0012), // aqcuisition number mitk::DICOMSortByTag::New( DICOMTag(0x0008, 0x0032), // aqcuisition time mitk::DICOMSortByTag::New( DICOMTag(0x0018, 0x1060), // trigger time mitk::DICOMSortByTag::New( DICOMTag(0x0008, 0x0018) // SOP instance UID (last resort, not really meaningful but decides clearly) ).GetPointer() ).GetPointer() ).GetPointer() ).GetPointer() ).GetPointer(); tagSorter->SetSortCriterion( sorting ); MITK_INFO << "Created sort"; gdcmReader->AddSortingElement( tagSorter ); mitk::DICOMFileReaderTestHelper::TestOutputsContainInputs( gdcmReader ); MITK_INFO << "Created sort"; //gdcmReader->PrintOutputs(std::cout, true); // really load images //mitk::DICOMFileReaderTestHelper::TestMitkImagesAreLoaded( gdcmReader ); gdcmReader->LoadImages(); mitk::Image::Pointer loaded_image = gdcmReader->GetOutput(0).GetMitkImage(); mitk::DiffusionImage::Pointer d_img = static_cast*>( loaded_image.GetPointer() ); mitk::NrrdDiffusionImageWriter::Pointer writer = mitk::NrrdDiffusionImageWriter::New(); writer->SetFileName( output_filename.c_str() ); writer->SetInput(d_img ); try { writer->Update(); } catch( const itk::ExceptionObject& e) { MITK_TEST_FAILED_MSG( << "Writer failed : " << e.what() ); } MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/MiniApps/DICOMLoader.cpp b/Modules/DiffusionImaging/MiniApps/DICOMLoader.cpp new file mode 100644 index 0000000000..f6abc06557 --- /dev/null +++ b/Modules/DiffusionImaging/MiniApps/DICOMLoader.cpp @@ -0,0 +1,291 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "MiniAppManager.h" +#include "mitkBaseDataIOFactory.h" +#include "mitkDiffusionImage.h" +#include "mitkBaseData.h" + +#include +#include +#include "ctkCommandLineParser.h" +#include +#include + +#include "mitkNrrdDiffusionImageWriter.h" +#include "mitkDiffusionDICOMFileReader.h" +#include "mitkDICOMTagBasedSorter.h" +#include "mitkDICOMSortByTag.h" + +#include "itkMergeDiffusionImagesFilter.h" + +static mitk::StringList& GetInputFilenames() +{ + static mitk::StringList inputs; + return inputs; +} + +void SetInputFileNames( std::string input_directory ) +{ + // I. Get all files in directory + itksys::Directory input; + input.Load( input_directory.c_str() ); + + // II. Push back files + mitk::StringList inputlist;//, mergedlist; + for( unsigned long idx=0; idx::Pointer ReadInDICOMFiles( mitk::StringList& input_files, std::string output_file ) +{ + // repeat test with some more realistic sorting + mitk::DiffusionDICOMFileReader::Pointer gdcmReader = mitk::DiffusionDICOMFileReader::New(); // this also tests destruction + mitk::DICOMTagBasedSorter::Pointer tagSorter = mitk::DICOMTagBasedSorter::New(); + + // Use tags as in Qmitk + // all the things that split by tag in DicomSeriesReader + tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0028, 0x0010) ); // Number of Rows + tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0028, 0x0011) ); // Number of Columns + tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0028, 0x0030) ); // Pixel Spacing + tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0018, 0x1164) ); // Imager Pixel Spacing + tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0020, 0x0037) ); // Image Orientation (Patient) // TODO add tolerance parameter (l. 1572 of original code) + tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0018, 0x0050) ); // Slice Thickness + tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0028, 0x0008) ); // Number of Frames + tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0020, 0x0052) ); // Frame of Reference UID + + mitk::DICOMSortCriterion::ConstPointer sorting = + mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0020, 0x0013), // instance number + mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0020, 0x0012)/*, // aqcuisition number + mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0008, 0x0032), // aqcuisition time + mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0018, 0x1060)//, // trigger time + /* mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0008, 0x0018) // SOP instance UID (last resort, not really meaningful but decides clearly) + ).GetPointer() + ).GetPointer() + ).GetPointer() + */ ).GetPointer() + ).GetPointer(); + tagSorter->SetSortCriterion( sorting ); + + MITK_INFO("dicom.loader.read.init") << "[]" ; + MITK_INFO("dicom.loader.read.inputs") << " " << input_files.size(); + + gdcmReader->SetInputFiles( input_files ); + gdcmReader->AddSortingElement( tagSorter ); + gdcmReader->AnalyzeInputFiles(); + gdcmReader->LoadImages(); + + mitk::Image::Pointer loaded_image = gdcmReader->GetOutput(0).GetMitkImage(); + + mitk::DiffusionImage::Pointer d_img = static_cast*>( loaded_image.GetPointer() ); + + return d_img; +} + +typedef short DiffusionPixelType; +typedef itk::VectorImage DwiImageType; +typedef DwiImageType::PixelType DwiPixelType; +typedef DwiImageType::RegionType DwiRegionType; +typedef std::vector< DwiImageType::Pointer > DwiImageContainerType; + +typedef mitk::DiffusionImage DiffusionImageType; +typedef DiffusionImageType::GradientDirectionContainerType GradientContainerType; +typedef std::vector< GradientContainerType::Pointer > GradientListContainerType; + +void SearchForInputInSubdirs( std::string root_directory, std::string subdir_prefix , std::vector& output_container) +{ + // I. Get all dirs in directory + itksys::Directory rootdir; + rootdir.Load( root_directory.c_str() ); + + MITK_INFO("dicom.loader.setinputdirs.start") << "Prefix = " << subdir_prefix; + + for( unsigned int idx=0; idx parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size()==0) + { + MITK_ERROR << "No input arguments were specified. Please provide all non-optional arguments. "; + return 0; + } + + std::string inputDirectory = us::any_cast( parsedArgs["inputdir"] ); + MITK_INFO << "Loading data from directory: " << inputDirectory; + + // retrieve the prefix flag (if set) + bool search_for_subdirs = false; + std::string subdir_prefix; + if( parsedArgs.count("dwprefix")) + { + MITK_INFO << "Prefix specified, will search for subdirs in the input directory!"; + subdir_prefix = us::any_cast( parsedArgs["dwprefix"] ); + search_for_subdirs = true; + } + + // retrieve the output + std::string outputFile = us::any_cast< std::string >( parsedArgs["output"] ); + + // if the executable is called with a single directory, just parse the given folder for files and read them into a diffusion image + if( !search_for_subdirs ) + { + SetInputFileNames( inputDirectory ); + + MITK_INFO << "Got " << GetInputFilenames().size() << " input files."; + mitk::DiffusionImage::Pointer d_img = ReadInDICOMFiles( GetInputFilenames(), outputFile ); + + mitk::NrrdDiffusionImageWriter::Pointer writer = + mitk::NrrdDiffusionImageWriter::New(); + writer->SetFileName( outputFile.c_str() ); + writer->SetInput(d_img ); + + try + { + writer->Update(); + } + catch( const itk::ExceptionObject& e) + { + MITK_ERROR << "Failed to write out the output file. \n\t Reason : ITK Exception " << e.what(); + } + + } + // if the --dwprefix flag is set, then we have to look for the directories, load each of them separately and afterwards merge the images + else + { + std::vector::Pointer> output_container; + + SearchForInputInSubdirs( inputDirectory, subdir_prefix, output_container ); + + // final output image + mitk::DiffusionImage::Pointer image = mitk::DiffusionImage::New(); + if( output_container.size() > 1 ) + { + DwiImageContainerType imageContainer; + GradientListContainerType gradientListContainer; + std::vector< double > bValueContainer; + + for ( std::vector< mitk::DiffusionImage::Pointer >::iterator dwi = output_container.begin(); + dwi != output_container.end(); ++dwi ) + { + imageContainer.push_back((*dwi)->GetVectorImage()); + gradientListContainer.push_back((*dwi)->GetDirections()); + bValueContainer.push_back((*dwi)->GetB_Value()); + } + + typedef itk::MergeDiffusionImagesFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + filter->SetImageVolumes(imageContainer); + filter->SetGradientLists(gradientListContainer); + filter->SetBValues(bValueContainer); + filter->Update(); + + vnl_matrix_fixed< double, 3, 3 > mf; mf.set_identity(); + + image->SetVectorImage( filter->GetOutput() ); + image->SetB_Value(filter->GetB_Value()); + image->SetDirections(filter->GetOutputGradients()); + image->SetMeasurementFrame(mf); + image->InitializeFromVectorImage(); + } + // just output the image if there was only one folder found + else + { + image = output_container.at(0); + } + + mitk::NrrdDiffusionImageWriter::Pointer writer = + mitk::NrrdDiffusionImageWriter::New(); + writer->SetFileName( outputFile.c_str() ); + writer->SetInput( image ); + + MITK_INFO("dicom.import.writeout") << " [OutputFile] " << outputFile.c_str(); + + try + { + writer->Update(); + } + catch( const itk::ExceptionObject& e) + { + MITK_ERROR << "Failed to write out the output file. \n\t Reason : ITK Exception " << e.what(); + } + + } + + return 1; +} +RegisterDiffusionMiniApp(DICOMLoader); diff --git a/Modules/DiffusionImaging/MiniApps/files.cmake b/Modules/DiffusionImaging/MiniApps/files.cmake index 30c2fb70da..679293a774 100644 --- a/Modules/DiffusionImaging/MiniApps/files.cmake +++ b/Modules/DiffusionImaging/MiniApps/files.cmake @@ -1,22 +1,23 @@ set(CPP_FILES mitkDiffusionMiniApps.cpp MiniAppManager.cpp FileFormatConverter.cpp TensorReconstruction.cpp QballReconstruction.cpp DiffusionIndices.cpp CopyGeometry.cpp GibbsTracking.cpp StreamlineTracking.cpp FiberProcessing.cpp LocalDirectionalFiberPlausibility.cpp #TractogramAngularError.cpp FiberDirectionExtraction.cpp PeakExtraction.cpp PeaksAngularError.cpp MultishellMethods.cpp #FiberFoxProcessing.cpp ExportShImage.cpp NetworkCreation.cpp NetworkStatistics.cpp + DICOMLoader.cpp )