diff --git a/Modules/DiffusionCmdApps/Misc/DiffusionDICOMLoader.cpp b/Modules/DiffusionCmdApps/Misc/DiffusionDICOMLoader.cpp index 0abc985..5941bc4 100644 --- a/Modules/DiffusionCmdApps/Misc/DiffusionDICOMLoader.cpp +++ b/Modules/DiffusionCmdApps/Misc/DiffusionDICOMLoader.cpp @@ -1,315 +1,315 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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 "mitkImage.h" #include "mitkBaseData.h" #include #include #include #include "mitkDiffusionCommandLineParser.h" #include #include #include "mitkDiffusionDICOMFileReader.h" #include "mitkSortByImagePositionPatient.h" #include "mitkDICOMTagBasedSorter.h" #include "mitkDICOMSortByTag.h" #include "itkMergeDiffusionImagesFilter.h" #include static mitk::StringList& GetInputFilenames() { static mitk::StringList inputs; return inputs; } // FIXME slash at the end 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; idxAddDistinguishingTag( 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) // TODO handle as real vectors! cluster with configurable errors! tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0020, 0x000e) ); // Series Instance UID 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 // gdcmReader->AddSortingElement( tagSorter ); //mitk::DICOMFileReaderTestHelper::TestOutputsContainInputs( gdcmReader ); mitk::DICOMSortCriterion::ConstPointer sorting = mitk::SortByImagePositionPatient::New( // Image Position (Patient) //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() ).GetPointer(); tagSorter->SetSortCriterion( sorting ); // mosaic //gdcmReader->SetResolveMosaic( this->m_Controls->m_SplitMosaicCheckBox->isChecked() ); gdcmReader->AddSortingElement( tagSorter );*/ gdcmReader->SetInputFiles( input_files ); try { gdcmReader->AnalyzeInputFiles(); } catch( const itk::ExceptionObject &e) { MITK_ERROR << "Failed to analyze data. " << e.what(); } catch( const std::exception &se) { MITK_ERROR << "Std Exception " << se.what(); } gdcmReader->LoadImages(); mitk::Image::Pointer loaded_image = gdcmReader->GetOutput(0).GetMitkImage(); return loaded_image; } typedef short DiffusionPixelType; typedef itk::VectorImage DwiImageType; typedef DwiImageType::PixelType DwiPixelType; typedef DwiImageType::RegionType DwiRegionType; typedef std::vector< DwiImageType::Pointer > DwiImageContainerType; typedef mitk::Image DiffusionImageType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientContainerType; -typedef std::vector< GradientContainerType::Pointer > GradientListContainerType; +typedef std::vector< GradientContainerType::ConstPointer > 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) { return EXIT_FAILURE; } std::string inputDirectory = us::any_cast( parsedArgs["i"] ); 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")) { subdir_prefix = us::any_cast( parsedArgs["dwprefix"] ); if (subdir_prefix != "") { MITK_INFO << "Prefix specified, will search for subdirs in the input directory!"; search_for_subdirs = true; } } // retrieve the output std::string outputFile = us::any_cast< std::string >( parsedArgs["o"] ); // 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::Image::Pointer d_img = ReadInDICOMFiles( GetInputFilenames(), outputFile ); try { mitk::IOUtil::Save(d_img, outputFile.c_str()); } 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 output_container; SearchForInputInSubdirs( inputDirectory, subdir_prefix, output_container ); // final output image mitk::Image::Pointer image = mitk::Image::New(); if( output_container.size() > 1 ) { DwiImageContainerType imageContainer; GradientListContainerType gradientListContainer; std::vector< double > bValueContainer; for ( std::vector< mitk::Image::Pointer >::iterator dwi = output_container.begin(); dwi != output_container.end(); ++dwi ) { mitk::DiffusionPropertyHelper::ImageType::Pointer itkVectorImagePointer = mitk::DiffusionPropertyHelper::ImageType::New(); mitk::CastToItkImage(*dwi, itkVectorImagePointer); imageContainer.push_back(itkVectorImagePointer); gradientListContainer.push_back( mitk::DiffusionPropertyHelper::GetGradientContainer(*dwi)); bValueContainer.push_back( mitk::DiffusionPropertyHelper::GetReferenceBValue(*dwi)); } 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 = mitk::GrabItkImageMemory( filter->GetOutput() ); mitk::DiffusionPropertyHelper::SetGradientContainer(image, filter->GetOutputGradients()); mitk::DiffusionPropertyHelper::SetReferenceBValue(image, filter->GetB_Value()); mitk::DiffusionPropertyHelper::SetMeasurementFrame(image, mf); mitk::DiffusionPropertyHelper::InitializeImage( image ); } // just output the image if there was only one folder found else { image = output_container.at(0); } MITK_INFO("dicom.import.writeout") << " [OutputFile] " << outputFile.c_str(); try { mitk::IOUtil::Save(image, outputFile.c_str()); } catch( const itk::ExceptionObject& e) { MITK_ERROR << "Failed to write out the output file. \n\t Reason : ITK Exception " << e.what(); } } return 1; } diff --git a/Modules/DiffusionCmdApps/Quantification/MultishellMethods.cpp b/Modules/DiffusionCmdApps/Quantification/MultishellMethods.cpp index a8b2c33..6e5e7e2 100644 --- a/Modules/DiffusionCmdApps/Quantification/MultishellMethods.cpp +++ b/Modules/DiffusionCmdApps/Quantification/MultishellMethods.cpp @@ -1,215 +1,215 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkDiffusionCommandLineParser.h" #include #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char* argv[]) { mitkDiffusionCommandLineParser parser; parser.setTitle("Multishell Methods"); parser.setCategory("Preprocessing Tools"); parser.setDescription(""); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("", "i", mitkDiffusionCommandLineParser::String, "Input:", "input file", us::Any(), false, false, false, mitkDiffusionCommandLineParser::Input); parser.addArgument("", "o", mitkDiffusionCommandLineParser::String, "Output:", "output file", us::Any(), false, false, false, mitkDiffusionCommandLineParser::Output); parser.addArgument("adc", "D", mitkDiffusionCommandLineParser::Bool, "ADC:", "ADC Average", us::Any(), false); parser.addArgument("akc", "K", mitkDiffusionCommandLineParser::Bool, "Kurtosis fit:", "Kurtosis Fit", us::Any(), false); parser.addArgument("biexp", "B", mitkDiffusionCommandLineParser::Bool, "BiExp fit:", "BiExp fit", us::Any(), false); parser.addArgument("targetbvalue", "b", mitkDiffusionCommandLineParser::String, "b Value:", "target bValue (mean, min, max)", us::Any(), false); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; // mandatory arguments std::string inName = us::any_cast(parsedArgs["i"]); std::string outName = us::any_cast(parsedArgs["o"]); bool applyADC = us::any_cast(parsedArgs["adc"]); bool applyAKC = us::any_cast(parsedArgs["akc"]); bool applyBiExp = us::any_cast(parsedArgs["biexp"]); std::string targetType = us::any_cast(parsedArgs["targetbvalue"]); try { std::cout << "Loading " << inName; mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Diffusion Weighted Images"}, std::vector()); mitk::Image::Pointer dwi = mitk::IOUtil::Load(inName, &functor); if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dwi ) ) { typedef itk::RadialMultishellToSingleshellImageFilter FilterType; typedef itk::DwiGradientLengthCorrectionFilter CorrectionFilterType; CorrectionFilterType::Pointer roundfilter = CorrectionFilterType::New(); roundfilter->SetRoundingValue( 1000 ); roundfilter->SetReferenceBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue( dwi )); roundfilter->SetReferenceGradientDirectionContainer(mitk::DiffusionPropertyHelper::GetGradientContainer(dwi)); roundfilter->Update(); mitk::DiffusionPropertyHelper::SetReferenceBValue(dwi, roundfilter->GetNewBValue()); mitk::DiffusionPropertyHelper::SetGradientContainer(dwi, roundfilter->GetOutputGradientDirectionContainer()); // filter input parameter const mitk::DiffusionPropertyHelper::BValueMapType &originalShellMap = mitk::DiffusionPropertyHelper::GetBValueMap(dwi); mitk::DiffusionPropertyHelper::ImageType::Pointer vectorImage = mitk::DiffusionPropertyHelper::ImageType::New(); mitk::CastToItkImage(dwi, vectorImage); - const mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer + const mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer gradientContainer = mitk::DiffusionPropertyHelper::GetGradientContainer(dwi); const unsigned int &bValue = mitk::DiffusionPropertyHelper::GetReferenceBValue( dwi ); // filter call vnl_vector bValueList(originalShellMap.size()-1); double targetBValue = bValueList.mean(); mitk::DiffusionPropertyHelper::BValueMapType::const_iterator it = originalShellMap.begin(); ++it; int i = 0 ; for(; it != originalShellMap.end(); ++it) bValueList.put(i++,it->first); if( targetType == "mean" ) targetBValue = bValueList.mean(); else if( targetType == "min" ) targetBValue = bValueList.min_value(); else if( targetType == "max" ) targetBValue = bValueList.max_value(); if(applyADC) { FilterType::Pointer filter = FilterType::New(); filter->SetInput(vectorImage); filter->SetOriginalGradientDirections(gradientContainer); filter->SetOriginalBValueMap(originalShellMap); filter->SetOriginalBValue(bValue); itk::ADCAverageFunctor::Pointer functor = itk::ADCAverageFunctor::New(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); filter->SetFunctor(functor); filter->Update(); // create new DWI image mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( filter->GetOutput() ); mitk::DiffusionPropertyHelper::SetReferenceBValue(outImage, targetBValue); mitk::DiffusionPropertyHelper::SetGradientContainer(outImage, filter->GetTargetGradientDirections()); mitk::DiffusionPropertyHelper::InitializeImage( outImage ); mitk::IOUtil::Save(outImage, (outName + "_ADC.dwi").c_str()); } if(applyAKC) { FilterType::Pointer filter = FilterType::New(); filter->SetInput(vectorImage); filter->SetOriginalGradientDirections(gradientContainer); filter->SetOriginalBValueMap(originalShellMap); filter->SetOriginalBValue(bValue); itk::KurtosisFitFunctor::Pointer functor = itk::KurtosisFitFunctor::New(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); filter->SetFunctor(functor); filter->Update(); // create new DWI image mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( filter->GetOutput() ); mitk::DiffusionPropertyHelper::SetReferenceBValue(outImage, targetBValue); mitk::DiffusionPropertyHelper::SetGradientContainer(outImage, filter->GetTargetGradientDirections()); mitk::DiffusionPropertyHelper::InitializeImage( outImage ); mitk::IOUtil::Save(outImage, (std::string(outName) + "_AKC.dwi").c_str()); } if(applyBiExp) { FilterType::Pointer filter = FilterType::New(); filter->SetInput(vectorImage); filter->SetOriginalGradientDirections(gradientContainer); filter->SetOriginalBValueMap(originalShellMap); filter->SetOriginalBValue(bValue); itk::BiExpFitFunctor::Pointer functor = itk::BiExpFitFunctor::New(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); filter->SetFunctor(functor); filter->Update(); // create new DWI image mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( filter->GetOutput() ); mitk::DiffusionPropertyHelper::SetReferenceBValue(outImage, targetBValue); mitk::DiffusionPropertyHelper::SetGradientContainer(outImage, filter->GetTargetGradientDirections()); mitk::DiffusionPropertyHelper::InitializeImage( outImage ); mitk::IOUtil::Save(outImage, (std::string(outName) + "_BiExp.dwi").c_str()); } } } catch (const itk::ExceptionObject& e) { std::cout << e.what(); return EXIT_FAILURE; } catch (std::exception& e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionCmdApps/Quantification/TensorReconstruction.cpp b/Modules/DiffusionCmdApps/Quantification/TensorReconstruction.cpp index bd3df17..a497247 100644 --- a/Modules/DiffusionCmdApps/Quantification/TensorReconstruction.cpp +++ b/Modules/DiffusionCmdApps/Quantification/TensorReconstruction.cpp @@ -1,135 +1,135 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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 "mitkImage.h" #include #include "mitkBaseData.h" #include #include #include #include #include #include #include "mitkDiffusionCommandLineParser.h" #include #include #include /** * Convert files from one ending to the other */ int main(int argc, char* argv[]) { mitkDiffusionCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("", "i", mitkDiffusionCommandLineParser::String, "Input image", "input raw dwi", us::Any(), false, false, false, mitkDiffusionCommandLineParser::Input); parser.addArgument("", "o", mitkDiffusionCommandLineParser::String, "Output image", "output image", us::Any(), false, false, false, mitkDiffusionCommandLineParser::Output); parser.addArgument("b0_threshold", "", mitkDiffusionCommandLineParser::Int, "b0 threshold", "baseline image intensity threshold", 0); parser.addArgument("correct_negative_eigenv", "", mitkDiffusionCommandLineParser::Bool, "Correct negative eigenvalues", "correct negative eigenvalues", us::Any(false)); parser.setCategory("Signal Modelling"); parser.setTitle("Tensor Reconstruction"); parser.setDescription(""); parser.setContributor("MIC"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string inFileName = us::any_cast(parsedArgs["i"]); std::string outfilename = us::any_cast(parsedArgs["o"]); if (!itksys::SystemTools::GetFilenamePath(outfilename).empty()) outfilename = itksys::SystemTools::GetFilenamePath(outfilename)+"/"+itksys::SystemTools::GetFilenameWithoutExtension(outfilename); else outfilename = itksys::SystemTools::GetFilenameWithoutExtension(outfilename); outfilename += ".dti"; int threshold = 0; if (parsedArgs.count("b0_threshold")) threshold = us::any_cast(parsedArgs["b0_threshold"]); bool correct_negative_eigenv = false; if (parsedArgs.count("correct_negative_eigenv")) correct_negative_eigenv = us::any_cast(parsedArgs["correct_negative_eigenv"]); try { mitk::Image::Pointer dwi = mitk::IOUtil::Load(inFileName); mitk::DiffusionPropertyHelper::ImageType::Pointer itkVectorImagePointer = mitk::DiffusionPropertyHelper::ImageType::New(); mitk::CastToItkImage(dwi, itkVectorImagePointer); if (correct_negative_eigenv) { typedef itk::TensorReconstructionWithEigenvalueCorrectionFilter< short, float > TensorReconstructionImageFilterType; TensorReconstructionImageFilterType::Pointer filter = TensorReconstructionImageFilterType::New(); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi)); filter->SetGradientImage( mitk::DiffusionPropertyHelper::GetGradientContainer(dwi), itkVectorImagePointer); filter->SetB0Threshold(threshold); filter->Update(); // Save tensor image itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); io->SetFileType( itk::ImageIOBase::Binary ); io->UseCompressionOn(); mitk::LocaleSwitch localeSwitch("C"); itk::ImageFileWriter< itk::Image< itk::DiffusionTensor3D< float >, 3 > >::Pointer writer = itk::ImageFileWriter< itk::Image< itk::DiffusionTensor3D< float >, 3 > >::New(); writer->SetInput(filter->GetOutput()); writer->SetFileName(outfilename); writer->SetImageIO(io); writer->UseCompressionOn(); writer->Update(); } else { typedef itk::DiffusionTensor3DReconstructionImageFilter< short, short, float > TensorReconstructionImageFilterType; TensorReconstructionImageFilterType::Pointer filter = TensorReconstructionImageFilterType::New(); - filter->SetGradientImage( mitk::DiffusionPropertyHelper::GetGradientContainer(dwi), itkVectorImagePointer ); + filter->SetGradientImage( dynamic_cast(dwi->GetProperty(mitk::DiffusionPropertyHelper::GetGradientContainerPropertyName().c_str()).GetPointer())->GetGradientDirectionsContainerCopy(), itkVectorImagePointer ); filter->SetBValue( mitk::DiffusionPropertyHelper::GetReferenceBValue( dwi )); filter->SetThreshold(threshold); filter->Update(); // Save tensor image itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); io->SetFileType( itk::ImageIOBase::Binary ); io->UseCompressionOn(); mitk::LocaleSwitch localeSwitch("C"); itk::ImageFileWriter< itk::Image< itk::DiffusionTensor3D< float >, 3 > >::Pointer writer = itk::ImageFileWriter< itk::Image< itk::DiffusionTensor3D< float >, 3 > >::New(); writer->SetInput(filter->GetOutput()); writer->SetFileName(outfilename); writer->SetImageIO(io); writer->UseCompressionOn(); writer->Update(); } } catch ( itk::ExceptionObject &err) { std::cout << "Exception: " << err; } catch ( std::exception& err) { std::cout << "Exception: " << err.what(); } catch ( ... ) { std::cout << "Exception!"; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/FittingFunctions/mitkAbstractFitter.h b/Modules/DiffusionCore/Algorithms/Reconstruction/FittingFunctions/mitkAbstractFitter.h index 5bf4eb0..9d0b766 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/FittingFunctions/mitkAbstractFitter.h +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/FittingFunctions/mitkAbstractFitter.h @@ -1,125 +1,125 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef _MITK_AbstractFitter_H #define _MITK_AbstractFitter_H #include #include #include #include namespace mitk { class AbstractFitter: public vnl_least_squares_function { public: typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientContainerType; typedef itk::VectorImage< unsigned short, 3 > DiffusionImageType; typedef TensorImage::PixelType TensorType; AbstractFitter(unsigned int number_of_parameters, unsigned int number_of_measurements) : vnl_least_squares_function(number_of_parameters, number_of_measurements, no_gradient) { } GradientContainerType::Pointer gradientDirections; DiffusionImageType::PixelType measurements; std::vector bValues; double S0; std::vector weightedIndices; void set_S0(double val) { S0 = val; } void set_measurements(const DiffusionImageType::PixelType& m) { measurements = m; } void set_bvalues(std::vector& x) { bValues = x; } void set_weightedIndices(std::vector& x) { weightedIndices = x; } - void set_gradient_directions(const GradientContainerType::Pointer& directions) + void set_gradient_directions(const GradientContainerType::Pointer directions) { gradientDirections = directions; } static void Sph2Cart(vnl_vector_fixed& dir, const double &theta, const double &phi) { dir[0] = std::sin(theta)*std::cos(phi); dir[1] = std::sin(theta)*std::sin(phi); dir[2] = std::cos(theta); } static void Cart2Sph(const vnl_vector_fixed& dir, double &theta, double &phi) { theta = std::acos( dir[2] ); // phi goes from 0.0 (+x axis) and wraps at 2 * PI // theta goes from 0.0 (+z axis) and wraps at PI // if x and y are 0.0 or very close, return phi == 0 if (fabs(dir[0]) + fabs(dir[1]) < 1E-9) { phi = 0.0; } else { // ie, if ( x == 0 && y == 0 ) == false if (dir[1] == 0.0) { if (dir[0] > 0.0) phi = 0.0; else phi = itk::Math::pi; } else if (dir[0] == 0.0) { // avoid div by zero if (dir[1] > 0) { phi = itk::Math::pi / 2.0; } else { phi = 1.5 * itk::Math::pi; } } else if (dir[0] > 0.0 && dir[1] > 0.0) // first quadrant phi = atan(dir[1] / dir[0]); else if (dir[0] < 0.0 && dir[1] > 0.0) // second quadrant phi = itk::Math::pi + atan(dir[1] / dir[0]); else if (dir[0] < 0.0 && dir[1] < 0.0) // third quadrant phi = itk::Math::pi + atan(dir[1] / dir[0]); else // fourth quadrant phi = 2.0 * itk::Math::pi + atan(dir[1] / dir[0]); } } }; } #endif diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.h b/Modules/DiffusionCore/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.h index 42ed9ed..8d78833 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.h @@ -1,111 +1,111 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef _itk_RadialMultishellToSingleshellImageFilterr_h_ #define _itk_RadialMultishellToSingleshellImageFilterr_h_ #include #include #include "itkDWIVoxelFunctor.h" namespace itk { template class RadialMultishellToSingleshellImageFilter : public ImageToImageFilter, itk::VectorImage > { public: typedef RadialMultishellToSingleshellImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< itk::VectorImage, itk::VectorImage > Superclass; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(RadialMultishellToSingleshellImageFilter, ImageToImageFilter) typedef TInputScalarType InputScalarType; typedef itk::VectorImage InputImageType; typedef typename InputImageType::PixelType InputPixelType; typedef TOutputScalarType OutputScalarType; typedef itk::VectorImage OutputImageType; typedef typename OutputImageType::PixelType OutputPixelType; typedef OutputScalarType BaselineScalarType; typedef BaselineScalarType BaselinePixelType; typedef typename itk::Image BaselineImageType; typedef float ErrorScalarType; typedef ErrorScalarType ErrorPixelType; typedef typename itk::Image ErrorImageType; typedef vnl_vector_fixed< double, 3 > GradientDirectionType; typedef itk::VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; typedef std::vector IndicesVector; typedef std::map BValueMap; - void SetOriginalGradientDirections(GradientDirectionContainerType::Pointer ptr){m_OriginalGradientDirections = ptr;} + void SetOriginalGradientDirections(GradientDirectionContainerType::ConstPointer ptr){m_OriginalGradientDirections = ptr;} void SetOriginalBValue(const double & val){m_OriginalBValue = val;} void SetOriginalBValueMap(const BValueMap & inp){m_BValueMap = inp;} void SetFunctor(DWIVoxelFunctor * functor){m_Functor = functor;} GradientDirectionContainerType::Pointer GetTargetGradientDirections(){return m_TargetGradientDirections;} ErrorImageType::Pointer GetErrorImage(){return m_ErrorImage;} protected: RadialMultishellToSingleshellImageFilter(); ~RadialMultishellToSingleshellImageFilter() {} void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &, ThreadIdType); GradientDirectionContainerType::Pointer m_TargetGradientDirections; ///< container for the subsampled output gradient directions - GradientDirectionContainerType::Pointer m_OriginalGradientDirections; ///< input gradient directions + GradientDirectionContainerType::ConstPointer m_OriginalGradientDirections; ///< input gradient directions BValueMap m_BValueMap; double m_OriginalBValue; std::vector > m_ShellInterpolationMatrixVector; IndicesVector m_TargetDirectionsIndicies; unsigned int m_NumberTargetDirections; DWIVoxelFunctor * m_Functor; ErrorImageType::Pointer m_ErrorImage; }; } // end of namespace #ifndef ITK_MANUAL_INSTANTIATION #include "itkRadialMultishellToSingleshellImageFilter.cpp" #endif #endif diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp index 0ba0cc3..2917d13 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp @@ -1,718 +1,718 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_cpp #define __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_cpp #include "itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h" #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_symmetric_eigensystem.h" #include #include "itkRegularizedIVIMReconstructionFilter.h" #include #define IVIM_FOO -100000 namespace itk { template< class TIn, class TOut> DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::DiffusionIntravoxelIncoherentMotionReconstructionImageFilter() : m_GradientDirectionContainer(nullptr), m_Method(IVIM_DSTAR_FIX), m_FitDStar(true), m_Verbose(false) { this->SetNumberOfRequiredInputs( 1 ); this->SetNumberOfRequiredOutputs( 3 ); typename OutputImageType::Pointer outputPtr1 = OutputImageType::New(); this->SetNthOutput(0, outputPtr1.GetPointer()); typename OutputImageType::Pointer outputPtr2 = OutputImageType::New(); this->SetNthOutput(1, outputPtr2.GetPointer()); typename OutputImageType::Pointer outputPtr3 = OutputImageType::New(); this->SetNthOutput(2, outputPtr3.GetPointer()); } template< class TIn, class TOut> void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::BeforeThreadedGenerateData() { // Input must be an itk::VectorImage. std::string gradientImageClassName(this->ProcessObject::GetInput(0)->GetNameOfClass()); if ( strcmp(gradientImageClassName.c_str(),"VectorImage") != 0 ) { itkExceptionMacro( << "There is only one Gradient image. I expect that to be a VectorImage. " << "But its of type: " << gradientImageClassName ); } // Compute the indicies of the baseline images and gradient images // If no b=0 mm/s² gradients ar found, the next lowest b-value is used. GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin(); double minNorm = itk::NumericTraits::max(); while( gdcit != this->m_GradientDirectionContainer->End() ) { double norm = gdcit.Value().one_norm(); if (normm_GradientDirectionContainer->Begin(); while( gdcit != this->m_GradientDirectionContainer->End() ) { if(gdcit.Value().one_norm() <= minNorm) m_Snap.baselineind.push_back(gdcit.Index()); else m_Snap.gradientind.push_back(gdcit.Index()); ++gdcit; } if (m_Snap.gradientind.size()==0) itkExceptionMacro("Only one b-value supplied. At least two needed for IVIM fit."); // check sind die grad und base gleichlang? alle grad gerade und base ungerade? dann iterierende aufnahme!! m_Snap.iterated_sequence = false; if(m_Snap.baselineind.size() == m_Snap.gradientind.size()) { int size = m_Snap.baselineind.size(); int sum_b = 0, sum_g = 0; for(int i=0; iGetElement(m_Snap.gradientind[i]).two_norm(); m_Snap.bvalues[i] = m_BValue*twonorm*twonorm; } if(m_Verbose) { std::cout << "ref bval: " << m_BValue << "; b-values: "; for(int i=0; im_BThres) m_Snap.high_indices.push_back(i); } m_Snap.num_high = m_Snap.high_indices.size(); m_Snap.high_bvalues.set_size(m_Snap.num_high); m_Snap.high_meas.set_size(m_Snap.num_high); for(int i=0; i MeasAndBvals DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::ApplyS0Threshold(vnl_vector &meas, vnl_vector &bvals) { std::vector newmeas; std::vector newbvals; int N = meas.size(); for(int i=0; i void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); typename OutputImageType::Pointer dImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(1)); ImageRegionIterator< OutputImageType > oit1(dImage, outputRegionForThread); oit1.GoToBegin(); typename OutputImageType::Pointer dstarImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(2)); ImageRegionIterator< OutputImageType > oit2(dstarImage, outputRegionForThread); oit2.GoToBegin(); typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typedef typename InputImageType::PixelType InputVectorType; typename InputImageType::Pointer inputImagePointer = nullptr; // Would have liked a dynamic_cast here, but seems SGI doesn't like it // The enum will DiffusionIntravoxelIncoherentMotionReconstructionImageFilterensure that an inappropriate cast is not done inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); InputIteratorType iit(inputImagePointer, outputRegionForThread ); iit.GoToBegin(); // init internal vector image for regularized fit m_InternalVectorImage = VectorImageType::New(); m_InternalVectorImage->SetSpacing( inputImagePointer->GetSpacing() ); // Set the image spacing m_InternalVectorImage->SetOrigin( inputImagePointer->GetOrigin() ); // Set the image origin m_InternalVectorImage->SetDirection( inputImagePointer->GetDirection() ); // Set the image direction m_InternalVectorImage->SetRegions( inputImagePointer->GetLargestPossibleRegion() ); m_InitialFitImage = InitialFitImageType::New(); m_InitialFitImage->SetSpacing( inputImagePointer->GetSpacing() ); // Set the image spacing m_InitialFitImage->SetOrigin( inputImagePointer->GetOrigin() ); // Set the image origin m_InitialFitImage->SetDirection( inputImagePointer->GetDirection() ); // Set the image direction m_InitialFitImage->SetRegions( inputImagePointer->GetLargestPossibleRegion() ); if(m_Method == IVIM_REGULARIZED) { m_InternalVectorImage->SetVectorLength(m_Snap.num_high); m_InternalVectorImage->Allocate(); VectorImageType::PixelType varvec(m_Snap.num_high); for(int i=0; iFillBuffer(varvec); m_InitialFitImage->Allocate(); InitialFitImageType::PixelType vec; vec[0] = 0.5; vec[1] = 0.01; vec[2]=0.001; m_InitialFitImage->FillBuffer(vec); } typedef itk::ImageRegionIterator VectorIteratorType; VectorIteratorType vecit(m_InternalVectorImage, outputRegionForThread ); vecit.GoToBegin(); typedef itk::ImageRegionIterator InitIteratorType; InitIteratorType initit(m_InitialFitImage, outputRegionForThread ); initit.GoToBegin(); while( !iit.IsAtEnd() ) { InputVectorType measvec = iit.Get(); typename NumericTraits::AccumulateType b0 = NumericTraits::Zero; m_Snap.meas_for_threshold.set_size(m_Snap.num_weighted); m_Snap.allmeas.set_size(m_Snap.num_weighted); if(!m_Snap.iterated_sequence) { // Average the baseline image pixels for(unsigned int i = 0; i < m_Snap.baselineind.size(); ++i) b0 += measvec[m_Snap.baselineind[i]]; if(m_Snap.baselineind.size()) b0 /= m_Snap.baselineind.size(); // measurement vector for(int i = 0; i < m_Snap.num_weighted; ++i) { m_Snap.allmeas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); if(measvec[m_Snap.gradientind[i]] > m_S0Thres) m_Snap.meas_for_threshold[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); else m_Snap.meas_for_threshold[i] = IVIM_FOO; } } else { // measurement vector for(int i = 0; i < m_Snap.num_weighted; ++i) { b0 = measvec[m_Snap.baselineind[i]]; m_Snap.allmeas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); if(measvec[m_Snap.gradientind[i]] > m_S0Thres) m_Snap.meas_for_threshold[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); else m_Snap.meas_for_threshold[i] = IVIM_FOO; } } m_Snap.currentF = 0; m_Snap.currentD = 0; m_Snap.currentDStar = 0; switch(m_Method) { case IVIM_D_THEN_DSTAR: { for(int i=0; i x_donly(2); x_donly[0] = 0.001; x_donly[1] = 0.1; // f 0.1 Dstar 0.01 D 0.001 vnl_levenberg_marquardt lm_donly(f_donly); lm_donly.set_f_tolerance(0.0001); lm_donly.minimize(x_donly); m_Snap.currentD = x_donly[0]; m_Snap.currentF = x_donly[1]; if(m_FitDStar) { MeasAndBvals input2 = ApplyS0Threshold(m_Snap.meas_for_threshold, m_Snap.bvalues); m_Snap.bvals2 = input2.bvals; m_Snap.meas2 = input2.meas; if (input2.N < 2) break; IVIM_dstar_only f_dstar_only(input2.N,m_Snap.currentD,m_Snap.currentF); f_dstar_only.set_bvalues(input2.bvals); f_dstar_only.set_measurements(input2.meas); vnl_vector< double > x_dstar_only(1); vnl_vector< double > fx_dstar_only(input2.N); double opt = 1111111111111111.0; int opt_idx = -1; int num_its = 100; double min_val = .001; double max_val = .15; for(int i=0; i x(2); x[0] = 0.1; x[1] = 0.001; // f 0.1 Dstar 0.01 D 0.001 vnl_levenberg_marquardt lm(f_fixdstar); lm.set_f_tolerance(0.0001); lm.minimize(x); m_Snap.currentF = x[0]; m_Snap.currentD = x[1]; m_Snap.currentDStar = m_DStar; break; } case IVIM_FIT_ALL: { MeasAndBvals input = ApplyS0Threshold(m_Snap.meas_for_threshold, m_Snap.bvalues); m_Snap.bvals1 = input.bvals; m_Snap.meas1 = input.meas; if (input.N < 3) break; IVIM_3param f_3param(input.N); f_3param.set_bvalues(input.bvals); f_3param.set_measurements(input.meas); vnl_vector< double > x(3); x[0] = 0.1; x[1] = 0.001; x[2] = 0.01; // f 0.1 Dstar 0.01 D 0.001 vnl_levenberg_marquardt lm(f_3param); lm.set_f_tolerance(0.0001); lm.minimize(x); m_Snap.currentF = x[0]; m_Snap.currentD = x[1]; m_Snap.currentDStar = x[2]; break; } case IVIM_LINEAR_D_THEN_F: { for(int i=0; i X(input.N,2); bool nan_element = false; for(int i=0; i XX = X.transpose() * X; vnl_symmetric_eigensystem eigs(XX); vnl_vector eig; if(eigs.get_eigenvalue(0) > eigs.get_eigenvalue(1)) eig = eigs.get_eigenvector(0); else eig = eigs.get_eigenvector(1); m_Snap.currentF = 1 - exp( meas_m - bval_m*(eig(1)/eig(0)) ); m_Snap.currentD = -eig(1)/eig(0); if(m_FitDStar) { MeasAndBvals input2 = ApplyS0Threshold(m_Snap.meas_for_threshold, m_Snap.bvalues); m_Snap.bvals2 = input2.bvals; m_Snap.meas2 = input2.meas; if (input2.N < 2) break; IVIM_dstar_only f_dstar_only(input2.N,m_Snap.currentD,m_Snap.currentF); f_dstar_only.set_bvalues(input2.bvals); f_dstar_only.set_measurements(input2.meas); vnl_vector< double > x_dstar_only(1); vnl_vector< double > fx_dstar_only(input2.N); double opt = 1111111111111111.0; int opt_idx = -1; int num_its = 100; double min_val = .001; double max_val = .15; for(int i=0; i " << DStar; // x_dstar_only[0] = 0.01; // // f 0.1 Dstar 0.01 D 0.001 // vnl_levenberg_marquardt lm_dstar_only(f_dstar_only); // lm_dstar_only.set_f_tolerance(0.0001); // lm_dstar_only.minimize(x_dstar_only); // DStar = x_dstar_only[0]; break; } case IVIM_REGULARIZED: { //m_Snap.high_meas, m_Snap.high_bvalues; for(int i=0; i x_donly(2); x_donly[0] = 0.001; x_donly[1] = 0.1; if(input.N >= 2) { IVIM_d_and_f f_donly(input.N); f_donly.set_bvalues(input.bvals); f_donly.set_measurements(input.meas); //MITK_INFO << "initial fit N=" << input.N << ", min-b = " << input.bvals[0] << ", max-b = " << input.bvals[input.N-1]; vnl_levenberg_marquardt lm_donly(f_donly); lm_donly.set_f_tolerance(0.0001); lm_donly.minimize(x_donly); } typename InitialFitImageType::PixelType initvec; initvec[0] = x_donly[1]; initvec[1] = x_donly[0]; initit.Set(initvec); //MITK_INFO << "Init vox " << initit.GetIndex() << " with " << initvec[0] << "; " << initvec[1]; ++initit; int N = m_Snap.high_meas.size(); typename VectorImageType::PixelType vec(N); for(int i=0; i void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::AfterThreadedGenerateData() { if(m_Method == IVIM_REGULARIZED) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); ImageRegionIterator< OutputImageType > oit0(outputImage, outputImage->GetLargestPossibleRegion()); oit0.GoToBegin(); typename OutputImageType::Pointer dImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(1)); ImageRegionIterator< OutputImageType > oit1(dImage, dImage->GetLargestPossibleRegion()); oit1.GoToBegin(); typename OutputImageType::Pointer dstarImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(2)); ImageRegionIterator< OutputImageType > oit2(dstarImage, dstarImage->GetLargestPossibleRegion()); oit2.GoToBegin(); typedef itk::RegularizedIVIMReconstructionFilter RegFitType; RegFitType::Pointer filter = RegFitType::New(); filter->SetInput(m_InitialFitImage); filter->SetReferenceImage(m_InternalVectorImage); filter->SetBValues(m_Snap.high_bvalues); filter->SetNumberIterations(m_NumberIterations); filter->SetNumberOfThreads(1); filter->SetLambda(m_Lambda); filter->Update(); typename RegFitType::OutputImageType::Pointer outimg = filter->GetOutput(); ImageRegionConstIterator< RegFitType::OutputImageType > iit(outimg, outimg->GetLargestPossibleRegion()); iit.GoToBegin(); while( !iit.IsAtEnd() ) { double f = iit.Get()[0]; IVIM_CEIL( f, 0.0, 1.0 ); oit0.Set( myround(f) ); oit1.Set( myround(iit.Get()[1]) ); oit2.Set( myround(iit.Get()[2]) ); if(!m_Verbose) { // report the middle voxel if( iit.GetIndex()[0] == static_cast(outimg->GetLargestPossibleRegion().GetSize(0)-1)/2 && iit.GetIndex()[1] == static_cast(outimg->GetLargestPossibleRegion().GetSize(2)-1)/2 && iit.GetIndex()[2] == static_cast(outimg->GetLargestPossibleRegion().GetSize(1)-1)/2 ) { m_Snap.currentF = f; m_Snap.currentD = iit.Get()[1]; m_Snap.currentDStar = iit.Get()[2]; m_Snap.allmeas = m_tmp_allmeas; MITK_INFO << "setting " << f << ";" << iit.Get()[1] << ";" << iit.Get()[2]; } } ++oit0; ++oit1; ++oit2; ++iit; } } } template< class TIn, class TOut> double DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::myround(double number) { return number < 0.0 ? ceil(number - 0.5) : floor(number + 0.5); } template< class TIn, class TOut> void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter -::SetGradientDirections( GradientDirectionContainerType *gradientDirection ) +::SetGradientDirections( GradientDirectionContainerType::ConstPointer gradientDirection ) { this->m_GradientDirectionContainer = gradientDirection; this->m_NumberOfGradientDirections = gradientDirection->Size(); } template< class TIn, class TOut> void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); if ( m_GradientDirectionContainer ) { os << indent << "GradientDirectionContainer: " << m_GradientDirectionContainer << std::endl; } else { os << indent << "GradientDirectionContainer: (Gradient directions not set)" << std::endl; } } } #endif // __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_cpp diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h index b97a03c..9fdda7d 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h @@ -1,417 +1,417 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_h #define __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_h #include "itkImageToImageFilter.h" //#include "vnl/vnl_matrix.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_svd.h" #include "itkVectorContainer.h" #include "itkVectorImage.h" //#include "QuadProg.h" #include "itkVectorImage.h" #include "vnl/vnl_least_squares_function.h" #include "vnl/vnl_cost_function.h" #include "vnl/algo/vnl_levenberg_marquardt.h" #include "vnl/vnl_math.h" #define IVIM_CEIL(val,u,o) (val) = \ ( (val) < (u) ) ? ( (u) ) : ( ( (val)>(o) ) ? ( (o) ) : ( (val) ) ); namespace itk{ /** baseclass for IVIM fitting algorithms */ struct IVIM_base { void set_measurements(const vnl_vector& x) { measurements.set_size(x.size()); measurements.copy_in(x.data_block()); } void set_bvalues(const vnl_vector& x) { bvalues.set_size(x.size()); bvalues.copy_in(x.data_block()); } vnl_vector measurements; vnl_vector bvalues; int N; }; /** Fitt all three parameters */ struct IVIM_3param : public IVIM_base, vnl_least_squares_function { IVIM_3param(unsigned int number_of_measurements) : vnl_least_squares_function(3, number_of_measurements, no_gradient) { N = get_number_of_residuals(); } void f(const vnl_vector& x, vnl_vector& fx) override { double ef = x[0]; double D = x[1]; double Dstar = x[2]; for(int s=0; s0.003) fx[s] += D*100000; if (Dstar>0.3) fx[s] += Dstar*100000; } } }; /** fit by setting DStar to a fix value */ struct IVIM_fixdstar : public IVIM_base, vnl_least_squares_function { IVIM_fixdstar(unsigned int number_of_measurements, double DStar) : vnl_least_squares_function(2, number_of_measurements, no_gradient) { N = get_number_of_residuals(); fixDStar = DStar; } void f(const vnl_vector& x, vnl_vector& fx) override { double ef = x[0]; double D = x[1]; for(int s=0; s0.003) fx[s] += D*100000; } } double fixDStar; }; /** fit a monoexponential curve only estimating D and f */ struct IVIM_d_and_f : public IVIM_base, vnl_least_squares_function { IVIM_d_and_f(unsigned int number_of_measurements) : vnl_least_squares_function(2, number_of_measurements, no_gradient) { N = get_number_of_residuals(); } void f(const vnl_vector& x, vnl_vector& fx) override { double D = x[0]; double f = x[1]; for(int s=0; s0.003) fx[s] += D*100000; } } }; /** fiting DStar and f with fix value of D */ struct IVIM_fixd : public IVIM_base, vnl_least_squares_function { IVIM_fixd(unsigned int number_of_measurements, double D) : vnl_least_squares_function(2, number_of_measurements, no_gradient) { N = get_number_of_residuals(); fixD = D; } void f(const vnl_vector& x, vnl_vector& fx) override { double ef = x[0]; double Dstar = x[1]; for(int s=0; s0.3) fx[s] += Dstar*100000; } } double fixD; }; /** fiting DStar with given f and D */ struct IVIM_dstar_only : public IVIM_base, vnl_least_squares_function { IVIM_dstar_only(unsigned int number_of_measurements, double D, double f) : vnl_least_squares_function(1, number_of_measurements, no_gradient) { N = get_number_of_residuals(); fixD = D; fixF = f; } void f(const vnl_vector& x, vnl_vector& fx) override { double Dstar = x[0]; for(int s=0; s0.3) fx[s] += Dstar*100000; } } double fixD; double fixF; }; struct MeasAndBvals { vnl_vector meas; vnl_vector bvals; int N; }; /** \class DiffusionIntravoxelIncoherentMotionReconstructionImageFilter */ template< class TInputPixelType, class TOutputPixelType> class DiffusionIntravoxelIncoherentMotionReconstructionImageFilter : public ImageToImageFilter< VectorImage< TInputPixelType, 3 >, Image< TOutputPixelType, 3 > > { public: struct IVIMSnapshot { double currentF; double currentFunceiled; double currentD; double currentDStar; bool iterated_sequence; // wether each measurement has its own b0-acqu. std::vector baselineind; // baseline image indicies std::vector gradientind; // gradient image indicies vnl_vector bvalues; // bvalues != 0 int num_weighted; // total number of measurements vnl_vector meas_for_threshold; // all measurements, thresholded blanked out vnl_vector allmeas; // all measurements int num_high; // number of used measurements std::vector high_indices; // indices of used measurements vnl_vector high_bvalues; // bvals of used measurements vnl_vector high_meas; // used measurements // fit 1 vnl_vector meas1; vnl_vector bvals1; // fit 2 vnl_vector meas2; vnl_vector bvals2; }; enum IVIM_Method { IVIM_FIT_ALL, IVIM_DSTAR_FIX, IVIM_D_THEN_DSTAR, IVIM_LINEAR_D_THEN_F, IVIM_REGULARIZED }; typedef DiffusionIntravoxelIncoherentMotionReconstructionImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInputPixelType, 3>, Image< TOutputPixelType,3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DiffusionIntravoxelIncoherentMotionReconstructionImageFilter, ImageToImageFilter); typedef TOutputPixelType OutputPixelType; typedef TInputPixelType InputPixelType; /** Reference image data, This image is aquired in the absence * of a diffusion sensitizing field gradient */ typedef typename Superclass::InputImageType InputImageType; typedef Image< OutputPixelType, 3 > OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; /** Holds each magnetic field gradient used to acquire one DWImage */ typedef vnl_vector_fixed< double, 3 > GradientDirectionType; /** Container to hold gradient directions of the 'n' DW measurements */ typedef VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; // vector image typedefs for regularized fit typedef itk::VectorImage VectorImageType; typedef itk::Image, 3> InitialFitImageType; /** set method to add gradient directions and its corresponding * image. The image here is a VectorImage. The user is expected to pass the * gradient directions in a container. The ith element of the container * corresponds to the gradient direction of the ith component image the * VectorImage. For the baseline image, a vector of all zeros * should be set.*/ - void SetGradientDirections( GradientDirectionContainerType * ); + void SetGradientDirections( GradientDirectionContainerType::ConstPointer ); void SetBValue(double bval){m_BValue = bval;} void SetBThres(double bval){m_BThres = bval;} void SetS0Thres(double val){m_S0Thres = val;} void SetDStar(double dstar){m_DStar = dstar;} void SetFitDStar(bool fit){m_FitDStar = fit;} void SetVerbose(bool verbose){m_Verbose = verbose;} void SetNumberIterations(int num){m_NumberIterations = num;} void SetLambda(double lambda){m_Lambda = lambda;} void SetCrossPosition(typename InputImageType::IndexType crosspos){this->m_CrossPosition = crosspos;} void SetMethod(IVIM_Method method){m_Method = method;} IVIMSnapshot GetSnapshot(){return m_Snap;} /** Return the gradient direction. idx is 0 based */ virtual GradientDirectionType GetGradientDirection( unsigned int idx) const { if( idx >= m_NumberOfGradientDirections ) { itkExceptionMacro( << "Gradient direction " << idx << "does not exist" ); } return m_GradientDirectionContainer->ElementAt( idx+1 ); } protected: DiffusionIntravoxelIncoherentMotionReconstructionImageFilter(); ~DiffusionIntravoxelIncoherentMotionReconstructionImageFilter() {}; void PrintSelf(std::ostream& os, Indent indent) const; void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType); void AfterThreadedGenerateData(); MeasAndBvals ApplyS0Threshold(vnl_vector &meas, vnl_vector &bvals); private: double myround(double number); /** container to hold gradient directions */ - GradientDirectionContainerType::Pointer m_GradientDirectionContainer; + GradientDirectionContainerType::ConstPointer m_GradientDirectionContainer; /** Number of gradient measurements */ unsigned int m_NumberOfGradientDirections; double m_BValue; double m_BThres; double m_S0Thres; double m_DStar; IVIM_Method m_Method; typename OutputImageType::Pointer m_DMap; typename OutputImageType::Pointer m_DStarMap; bool m_FitDStar; IVIMSnapshot m_Snap; bool m_Verbose; typename VectorImageType::Pointer m_InternalVectorImage; typename InitialFitImageType::Pointer m_InitialFitImage; int m_NumberIterations; // for total variation vnl_vector m_tmp_allmeas; double m_Lambda; typename InputImageType::IndexType m_CrossPosition; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp" #endif #endif //__itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_h diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx index 8a26054..a816db8 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx @@ -1,493 +1,493 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_CXX #define DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_CXX #include "itkDiffusionKurtosisReconstructionImageFilter.h" #include #include #include #include #include #include #include template< class TInputPixelType> static void FitSingleVoxel( const itk::VariableLengthVector< TInputPixelType > &input, const vnl_vector& bvalues, vnl_vector& result, itk::KurtosisFitConfiguration kf_config) { // check for length assert( input.Size() == bvalues.size() ); // assembly data vectors for fitting auto bvalueIter = bvalues.begin(); unsigned int unused_values = 0; while( bvalueIter != bvalues.end() ) { if( *bvalueIter < vnl_math::eps && kf_config.omit_bzero ) { ++unused_values; } ++bvalueIter; } // initialize data vectors with the estimated size (after filtering) vnl_vector fit_measurements( input.Size() - unused_values, 0 ); vnl_vector fit_bvalues( input.Size() - unused_values, 0 ); bvalueIter = bvalues.begin(); unsigned int running_index = 0; unsigned int skip_count = 0; while( bvalueIter != bvalues.end() ) { // skip b=0 if the corresponding flag is set if( ( kf_config.omit_bzero && *bvalueIter < vnl_math::eps ) // skip bvalues higher than the limit provided, if the flag is activated || ( kf_config.exclude_high_b && *bvalueIter > kf_config.b_upper_threshold ) ) { ++skip_count; } else { fit_measurements[ running_index - skip_count ] = input.GetElement(running_index); fit_bvalues[ running_index - skip_count] = *bvalueIter; } ++running_index; ++bvalueIter; } MITK_DEBUG("KurtosisFilter.FitSingleVoxel.Meas") << fit_measurements; MITK_DEBUG("KurtosisFilter.FitSingleVoxel.Bval") << fit_bvalues; // perform fit on data vectors if( kf_config.omit_bzero ) { itk::kurtosis_fit_omit_unweighted kurtosis_cost_fn( fit_measurements.size() ); // configuration kurtosis_cost_fn.set_fit_logscale( static_cast(kf_config.fit_scale) ); kurtosis_cost_fn.initialize( fit_measurements, fit_bvalues ); if( kf_config.use_K_limits) { kurtosis_cost_fn.set_K_bounds( kf_config.K_limits ); } vnl_levenberg_marquardt nonlinear_fit( kurtosis_cost_fn ); nonlinear_fit.minimize( result ); } else { itk::kurtosis_fit_lsq_function kurtosis_cost_fn( fit_measurements.size() ); // configuration kurtosis_cost_fn.set_fit_logscale( static_cast(kf_config.fit_scale) ); kurtosis_cost_fn.initialize( fit_measurements, fit_bvalues ); if( kf_config.use_K_limits) { kurtosis_cost_fn.set_K_bounds( kf_config.K_limits ); } vnl_levenberg_marquardt nonlinear_fit( kurtosis_cost_fn ); nonlinear_fit.minimize(result); } MITK_DEBUG("KurtosisFilter.FitSingleVoxel.Rslt") << result; } template< class TInputPixelType, class TOutputPixelType> itk::DiffusionKurtosisReconstructionImageFilter ::DiffusionKurtosisReconstructionImageFilter() : m_ReferenceBValue(-1), m_OmitBZero(false), m_ApplyPriorSmoothing(false), m_SmoothingSigma(1.5), m_UseKBounds( false ), m_MaxFitBValue( 3000 ), m_ScaleForFitting( STRAIGHT ) { this->m_InitialPosition = vnl_vector(3, 0); this->m_InitialPosition[2] = 1000.0; // S_0 this->m_InitialPosition[0] = 0.001; // D this->m_InitialPosition[1] = 1; // K this->m_KurtosisBounds.fill(0); // single input image this->SetNumberOfRequiredInputs(1); // two output images (D, K) this->SetNumberOfRequiredOutputs(2); typename OutputImageType::Pointer outputPtr1 = OutputImageType::New(); typename OutputImageType::Pointer outputPtr2 = OutputImageType::New(); this->SetNthOutput(0, outputPtr1.GetPointer() ); this->SetNthOutput(1, outputPtr2.GetPointer() ); } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::GenerateOutputInformation() { // first call superclass Superclass::GenerateOutputInformation(); } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::SetImageMask(MaskImageType::Pointer mask) { this->m_MaskImage = mask; } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::BeforeThreadedGenerateData() { // if we have a region set, convert it to a mask image, which is to be used as default for telling // we need to set the image anyway, so by default the mask is overall 1 if( m_MaskImage.IsNull() ) { m_MaskImage = MaskImageType::New(); m_MaskImage->SetRegions( this->GetInput()->GetLargestPossibleRegion() ); m_MaskImage->CopyInformation( this->GetInput() ); m_MaskImage->Allocate(); if( this->m_MapOutputRegion.GetNumberOfPixels() > 0 ) { m_MaskImage->FillBuffer(0); typedef itk::ImageRegionIteratorWithIndex< MaskImageType > MaskIteratorType; MaskIteratorType maskIter( this->m_MaskImage, this->m_MapOutputRegion ); maskIter.GoToBegin(); while( !maskIter.IsAtEnd() ) { maskIter.Set( 1 ); ++maskIter; } } else { m_MaskImage->FillBuffer(1); } } // apply smoothing to the input image if( this->m_ApplyPriorSmoothing ) { // filter typedefs typedef itk::DiscreteGaussianImageFilter< itk::Image, itk::Image > GaussianFilterType; typedef itk::VectorIndexSelectionCastImageFilter< InputImageType, itk::Image > IndexSelectionType; typedef itk::ComposeImageFilter< itk::Image, InputImageType > ComposeFilterType; auto vectorImage = this->GetInput(); typename IndexSelectionType::Pointer indexSelectionFilter = IndexSelectionType::New(); indexSelectionFilter->SetInput( vectorImage ); typename ComposeFilterType::Pointer vec_composer = ComposeFilterType::New(); for( unsigned int i=0; iGetVectorLength(); ++i) { typename GaussianFilterType::Pointer gaussian_filter = GaussianFilterType::New(); indexSelectionFilter->SetIndex( i ); gaussian_filter->SetInput( indexSelectionFilter->GetOutput() ); gaussian_filter->SetVariance( m_SmoothingSigma ); vec_composer->SetInput(i, gaussian_filter->GetOutput() ); gaussian_filter->Update(); } try { vec_composer->Update(); } catch(const itk::ExceptionObject &e) { mitkThrow() << "[VectorImage.GaussianSmoothing] !! Failed with ITK Exception: " << e.what(); } this->m_ProcessedInputImage = vec_composer->GetOutput(); } else { this->m_ProcessedInputImage = const_cast( this->GetInput() ); } } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::AfterThreadedGenerateData() { /* // initialize buffer to zero overall, but don't forget the requested region pointer for( unsigned int i=0; iGetNumberOfOutputs(); ++i) { typename OutputImageType::Pointer output = this->GetOutput(i); // after generating, set the buffered region to max, we have taken care about filling it with valid data in // UpdateOutputInformation, if not set, a writer (or any filter using the LargestPossibleRegion() during update may // complain about not getting the requested region output->SetBufferedRegion( output->GetLargestPossibleRegion() ); std::cout << "[DiffusionKurtosisReconstructionImageFilter.After]" << output->GetLargestPossibleRegion() << std::endl; }*/ } template< class TInputPixelType, class TOutputPixelType> typename itk::DiffusionKurtosisReconstructionImageFilter::KurtosisSnapshot itk::DiffusionKurtosisReconstructionImageFilter -::GetSnapshot(const itk::VariableLengthVector &input, GradientDirectionContainerType::Pointer gradients, float bvalue, KurtosisFitConfiguration kf_conf) +::GetSnapshot(const itk::VariableLengthVector &input, GradientDirectionContainerType::ConstPointer gradients, float bvalue, KurtosisFitConfiguration kf_conf) { // initialize bvalues from reference value and the gradients provided on input this->SetReferenceBValue(bvalue); this->SetGradientDirections( gradients ); // call the other method return this->GetSnapshot( input, this->m_BValues, kf_conf ); } template< class TInputPixelType, class TOutputPixelType> typename itk::DiffusionKurtosisReconstructionImageFilter::KurtosisSnapshot itk::DiffusionKurtosisReconstructionImageFilter ::GetSnapshot(const itk::VariableLengthVector &input, vnl_vector bvalues, KurtosisFitConfiguration kf_conf) { // initialize vnl_vector initial_position; bool omit_bzero = kf_conf.omit_bzero; if( !omit_bzero ) { initial_position.set_size(2); initial_position[0] = this->m_InitialPosition[0]; initial_position[1] = this->m_InitialPosition[1]; } else { initial_position.set_size(3); initial_position = this->m_InitialPosition; } // fit FitSingleVoxel( input, bvalues, initial_position, kf_conf ); // assembly result snapshot KurtosisSnapshot result; result.m_D = initial_position[0]; result.m_K = initial_position[1]; if( omit_bzero ) { result.m_f = 1 - initial_position[2] / std::fmax(0.01, input.GetElement(0)); result.m_BzeroFit = initial_position[2]; } else result.m_f = 1; // assembly data vectors for fitting auto bvalueIter = bvalues.begin(); unsigned int unused_values = 0; while( bvalueIter != bvalues.end() ) { if( *bvalueIter < vnl_math::eps && omit_bzero ) { ++unused_values; } ++bvalueIter; } // initialize data vectors with the estimated size (after filtering) vnl_vector fit_measurements( input.Size() - unused_values, 0 ); vnl_vector fit_bvalues( input.Size() - unused_values, 0 ); // original data vnl_vector orig_measurements( input.Size(), 0 ); bvalueIter = bvalues.begin(); unsigned int running_index = 0; unsigned int skip_count = 0; unsigned int bzero_count = 0; result.m_Bzero = 0; while( bvalueIter != bvalues.end() ) { if( *bvalueIter < vnl_math::eps && omit_bzero ) { ++skip_count; } else { fit_measurements[ running_index - skip_count ] = input.GetElement(running_index); fit_bvalues[ running_index - skip_count ] = *bvalueIter; } if( *bvalueIter < vnl_math::eps ) { result.m_Bzero += input.GetElement(running_index); ++bzero_count; } orig_measurements[ running_index ] = input.GetElement(running_index); ++running_index; ++bvalueIter; } result.m_Bzero /= bzero_count; result.fit_bvalues = fit_bvalues; result.fit_measurements = fit_measurements; result.bvalues = bvalues; result.measurements = orig_measurements; result.m_fittedBZero = omit_bzero; return result; } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter -::SetGradientDirections(GradientDirectionContainerType::Pointer gradients) +::SetGradientDirections(GradientDirectionContainerType::ConstPointer gradients) { if( this->m_ReferenceBValue < 0) { itkExceptionMacro( << "Specify reference b-value prior to setting the gradient directions." ); } if( gradients->Size() == 0 ) { itkExceptionMacro( << "Empty gradient directions container retrieved" ); } vnl_vector vnl_bvalues( gradients->Size(), 0 ); // initialize the b-values auto grIter = gradients->Begin(); unsigned int index = 0; while( grIter != gradients->End() ) { const double twonorm = grIter.Value().two_norm(); vnl_bvalues( index++ ) = this->m_ReferenceBValue * twonorm * twonorm; ++grIter; } this->m_BValues = vnl_bvalues; } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::SetInitialSolution(const vnl_vector& x0 ) { assert( x0.size() == (2 + static_cast( this->m_OmitBZero )) ); this->m_InitialPosition = x0; } template< class TInputPixelType, class TOutputPixelType> void itk::DiffusionKurtosisReconstructionImageFilter ::ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType /*threadId*/) { typename OutputImageType::Pointer dImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); itk::ImageRegionIteratorWithIndex< OutputImageType > dImageIt(dImage, outputRegionForThread); dImageIt.GoToBegin(); typename OutputImageType::Pointer kImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(1)); itk::ImageRegionIteratorWithIndex< OutputImageType > kImageIt(kImage, outputRegionForThread); kImageIt.GoToBegin(); typedef itk::ImageRegionConstIteratorWithIndex< InputImageType > InputIteratorType; InputIteratorType inputIter( m_ProcessedInputImage, outputRegionForThread ); inputIter.GoToBegin(); typedef itk::ImageRegionConstIteratorWithIndex< MaskImageType > MaskIteratorType; MaskIteratorType maskIter( this->m_MaskImage, outputRegionForThread ); maskIter.GoToBegin(); KurtosisFitConfiguration fit_config; fit_config.omit_bzero = this->m_OmitBZero; fit_config.fit_scale = this->m_ScaleForFitting; fit_config.use_K_limits = this->m_UseKBounds; fit_config.K_limits = this->m_KurtosisBounds; vnl_vector initial_position; if( !this->m_OmitBZero ) { initial_position.set_size(2); initial_position[0] = this->m_InitialPosition[0]; initial_position[1] = this->m_InitialPosition[1]; } else { initial_position.set_size(3); initial_position = this->m_InitialPosition; } while( !inputIter.IsAtEnd() ) { // set (reset) each iteration vnl_vector result = initial_position; // fit single voxel (if inside mask ) if( maskIter.Get() > 0 ) { FitSingleVoxel( inputIter.Get(), this->m_BValues, result, fit_config ); } else { result.fill(0); } // regardless the fit type, the parameters are always in the first two position // of the results vector dImageIt.Set( result[0] ); kImageIt.Set( result[1] ); //std::cout << "[Kurtosis.Fit]" << inputIter.GetIndex() << " --> " << dImageIt.GetIndex() << " result: " << result << std::endl; ++maskIter; ++inputIter; ++dImageIt; ++kImageIt; } } #endif // guards diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.h b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.h index 8ea52d8..59a6b94 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.h @@ -1,443 +1,443 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_H #define DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_H #include "itkImageToImageFilter.h" #include "itkVectorImage.h" #include "mitkDiffusionPropertyHelper.h" // vnl includes #include #include namespace itk { // Fitting routines /** @struct Kurtosis_fit_lsq_function @brief A base least-squares function for the diffusion kurtosis fit (non-IVIM) The basic function fits the signal to S_0 = S * exp [ -b * D + -b^2 * D^2 * K^2 ] */ struct kurtosis_fit_lsq_function : public vnl_least_squares_function { public: /** full lsq_function constructor */ kurtosis_fit_lsq_function( unsigned int num_params, unsigned int num_measurements, UseGradient g=no_gradient) : vnl_least_squares_function( num_params, num_measurements, g), m_use_bounds(false), m_use_logscale(false), m_skip_fit(false) {} /** simplified constructor for the 2-parameters fit */ kurtosis_fit_lsq_function( unsigned int number_measurements) : kurtosis_fit_lsq_function( 2, number_measurements, no_gradient ) {} /** Initialize the function by setting measurements and the corresponding b-values */ void initialize( vnl_vector< double > const& _meas, vnl_vector< double> const& _bvals ) { meas = _meas; if( m_use_logscale ) { for( unsigned int i=0; i< meas.size(); ++i) { // would produce NaN values, skip the fit // using the virtual function from the superclass (sets a boolean flag) if( meas[i] < vnl_math::eps ) { m_skip_fit = true; throw_failure(); continue; } meas[i] = log( meas[i] ); } } bvalues = _bvals; } /** use penalty terms on fitting to force the parameters stay within the default bounds */ void use_bounds() { m_use_bounds = true; // initialize bounds double upper_bounds[2] = {4e-3, 4 }; kurtosis_upper_bounds = vnl_vector(2, 2, upper_bounds); kurtosis_lower_bounds = vnl_vector(2, 0); } void set_fit_logscale( bool flag ) { this->m_use_logscale = flag; } void set_K_bounds( const vnl_vector_fixed k_bounds ) { // init this->use_bounds(); // override K bounds kurtosis_lower_bounds[1] = k_bounds[0]; kurtosis_upper_bounds[1] = k_bounds[1]; } virtual void f(const vnl_vector &x, vnl_vector &fx) { for ( unsigned int s=0; s < fx.size(); s++ ) { const double factor = ( meas[s] - M(x, s) ); fx[s] = factor * factor + penalty_term(x); } MITK_DEBUG("Fit.x_and_f") << x << " | " << fx; } protected: /** Formula for diffusion term, use for internal computations */ double Diff( double x1, double x2, double b) { const double quotient = -1. * b * x1 + b*b * x1 * x1 * x2 / 6; if( m_use_logscale ) return quotient; else return exp(quotient); } /** The fitting measurement function, has to be reimplemented in the classes */ virtual double M( vnl_vector const& x, unsigned int idx ) { const double bvalue = bvalues[idx]; double result = Diff( x[0], x[1], bvalue); if( m_use_logscale ) return meas[0] + result; else return meas[0] * result ; } /** Penalty term on D and K during fitting, make sure the vector that is passed in contains (D, K) in this ordering */ virtual double penalty_term( vnl_vector const& x) { double penalty = 0; // skip when turned off if( !m_use_bounds ) return penalty; // we have bounds for D and K only (the first two params ) for( unsigned int i=0; i< 2; i++) { // 5% penalty boundary // use exponential function to scale the penalty (max when x[i] == bounds ) double penalty_boundary = 0.02 * (kurtosis_upper_bounds[i] - kurtosis_lower_bounds[i]); if( x[i] < kurtosis_lower_bounds[i] + penalty_boundary ) { penalty += 1e6 * exp( -1 * ( x[i] - kurtosis_lower_bounds[i]) / penalty_boundary ); } else if ( x[i] > kurtosis_upper_bounds[i] - penalty_boundary ) { penalty += 1e6 * exp( -1 * ( kurtosis_upper_bounds[i] - x[i]) / penalty_boundary ); } } MITK_DEBUG("Fit.Orig.Penalty") << x << " || penalty: " << penalty; return penalty; } bool m_use_bounds; bool m_use_logscale; bool m_skip_fit; vnl_vector kurtosis_upper_bounds; vnl_vector kurtosis_lower_bounds; vnl_vector meas; vnl_vector bvalues; }; /** @struct kurtosis_fit_omit_unweighted @brief A fitting function handling the unweighted signal b_0 as a fitted parameter */ struct kurtosis_fit_omit_unweighted : public kurtosis_fit_lsq_function { public: /** simplified constructor for the 3-parameters fit */ kurtosis_fit_omit_unweighted( unsigned int number_measurements) : kurtosis_fit_lsq_function( 3, number_measurements, no_gradient ) {} protected: virtual double M(const vnl_vector &x, unsigned int idx) override { const double bvalue = bvalues[idx]; double result = Diff( x[0], x[1], bvalue); if( m_use_logscale ) return log( x[2] ) + result; else return x[2] * result ; } }; enum FitScale { STRAIGHT = 0, LOGARITHMIC }; struct KurtosisFitConfiguration { KurtosisFitConfiguration() : omit_bzero(false) , use_K_limits(false) , exclude_high_b(false) , b_upper_threshold(10e9) {} bool omit_bzero; FitScale fit_scale; bool use_K_limits; vnl_vector_fixed K_limits; bool exclude_high_b; double b_upper_threshold; }; /** @class DiffusionKurtosisReconstructionImageFilter @brief This filter provides the fit of the kurtosis (non-IVIM) signal to the data It has two main modes of operation, either as an image filter to compute the D and K maps, i.e. fitting the values to each voxel or a computation on a single voxel or a voxel group (with mask) can be triggered by @sa GetSnapshot, GetCurrentSnapshot methods. */ template< class TInputPixelType, class TOutputPixelType > class DiffusionKurtosisReconstructionImageFilter : public ImageToImageFilter< VectorImage< TInputPixelType, 3>, Image > { public: /** @struct KurtosisSnapshot @brief Struct describing a result (and the data) of a Kurtosis model fit */ struct KurtosisSnapshot { KurtosisSnapshot() : m_f(1), m_BzeroFit(1), m_D(0.001), m_K(0) {} // input data structures //vnl_vector filtered_measurements; vnl_vector bvalues; vnl_vector measurements; vnl_vector fit_bvalues; vnl_vector fit_measurements; vnl_vector weighted_image_indices; bool m_fittedBZero; // variables holding the fitted values double m_f; double m_BzeroFit; double m_D; double m_K; double m_Bzero; // mean baseline signal }; //-- class typedefs typedef DiffusionKurtosisReconstructionImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInputPixelType, 3>, Image< TOutputPixelType,3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DiffusionKurtosisReconstructionImageFilter, ImageToImageFilter) typedef TOutputPixelType OutputPixelType; typedef TInputPixelType InputPixelType; typedef typename Superclass::InputImageType InputImageType; typedef Image< OutputPixelType, 3 > OutputImageType; typedef itk::Image< short , 3> MaskImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; /** Holds each magnetic field gradient used to acquire one DWImage */ typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientDirectionContainerType; // vector image typedefs for regularized fit typedef itk::VectorImage VectorImageType; typedef itk::Image, 3> InitialFitImageType; //-- input (Set) methods /** Set the initial solution for fitting, make sure the length and the values correspond to the parameters * x0 = ( S_0, ADC_0, AKC_0 ) when also the S_0 is estimated * x0 = ( ADC_0, AKC_0 ) when the S_0 is used in fitting */ void SetInitialSolution(const vnl_vector& x0 ); /** Set whether the S_0 value is fitted or used in fitting */ void SetOmitUnweightedValue( bool flag) { this->m_OmitBZero = flag; } /** Trigger a single computation of the Kurtosis values from the given input vector and the bvalues and returns the result as a KurtosisSnapshot object */ KurtosisSnapshot GetSnapshot( const itk::VariableLengthVector< TInputPixelType > &input, vnl_vector bvalues, KurtosisFitConfiguration kf_conf); /** Trigger a single computation of the kurtosis values, first the bvalues vector is computed internally but then also stored into the returend snapshot */ - KurtosisSnapshot GetSnapshot( const itk::VariableLengthVector< TInputPixelType > &input, GradientDirectionContainerType::Pointer, float bvalue, KurtosisFitConfiguration kf_conf); + KurtosisSnapshot GetSnapshot( const itk::VariableLengthVector< TInputPixelType > &input, GradientDirectionContainerType::ConstPointer, float bvalue, KurtosisFitConfiguration kf_conf); /** * Returns the value of the current data presented to the filter. If a mask is set, the voxels are first averaged before passed to the fitting procedure */ KurtosisSnapshot GetCurrentSnapshot(bool omit_bzero); /** Set the reference bvalue of the input DW image */ void SetReferenceBValue( double bvalue ) { this->m_ReferenceBValue = bvalue; } /** Set the gradient directions */ - void SetGradientDirections( GradientDirectionContainerType::Pointer gradients ); + void SetGradientDirections( GradientDirectionContainerType::ConstPointer gradients ); /** Restrict map generation to an image region */ void SetMapOutputRegion( OutputImageRegionType region ) { m_MapOutputRegion = region; this->m_ApplyPriorSmoothing = true; } void SetImageMask( MaskImageType::Pointer mask ); /** Set smoothing sigma (default = 1.5 ), automatically enables smoothing prior to fitting */ void SetSmoothingSigma( double sigma ) { this->m_SmoothingSigma = sigma; this->m_ApplyPriorSmoothing = true; } /** Activate/Deactivate the gaussian smoothing applied to the input prior to fitting ( default = off ) */ void SetUseSmoothingPriorToFitting( bool flag) { this->m_ApplyPriorSmoothing = flag; } /** Set boundaries enforced by penalty terms in the fitting procedure */ void SetBoundariesForKurtosis( double lower, double upper ) { m_UseKBounds = true; m_KurtosisBounds[0] = lower; m_KurtosisBounds[1] = upper; } /** Exclude measurements associated with b-values higher than max_bvalue from fitting */ void SetMaximalBValueUsedForFitting( double max_bvalue ) { m_MaxFitBValue = max_bvalue; } /** Select the method used in fitting of the data STRAIHT - fit the exponential signal equation S / S_0 = exp [ ... ] LOGARITHMIC - fit the logarithmic signal equation ln( S / S_0 ) = [] */ void SetFittingScale( FitScale scale ) { m_ScaleForFitting = scale; } protected: DiffusionKurtosisReconstructionImageFilter(); virtual ~DiffusionKurtosisReconstructionImageFilter() {} void GenerateOutputInformation() override; void AfterThreadedGenerateData() override; void BeforeThreadedGenerateData() override; void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId) override; double m_ReferenceBValue; vnl_vector m_BValues; vnl_vector m_InitialPosition; bool m_OmitBZero; OutputImageRegionType m_MapOutputRegion; MaskImageType::Pointer m_MaskImage; typename InputImageType::Pointer m_ProcessedInputImage; bool m_ApplyPriorSmoothing; double m_SmoothingSigma; bool m_UseKBounds; vnl_vector_fixed m_KurtosisBounds; double m_MaxFitBValue; FitScale m_ScaleForFitting; private: }; } //end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkDiffusionKurtosisReconstructionImageFilter.cxx" #endif #endif // DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_H diff --git a/Modules/DiffusionCore/Algorithms/itkAdcImageFilter.h b/Modules/DiffusionCore/Algorithms/itkAdcImageFilter.h index 9c6a05b..a5fd827 100644 --- a/Modules/DiffusionCore/Algorithms/itkAdcImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkAdcImageFilter.h @@ -1,136 +1,136 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkAdcImageFilter_h_ #define __itkAdcImageFilter_h_ #include "itkImageToImageFilter.h" #include "itkVectorImage.h" #include #include #include namespace itk{ /** \class AdcImageFilter */ template< class TInPixelType, class TOutPixelType > class AdcImageFilter : public ImageToImageFilter< VectorImage< TInPixelType, 3 >, Image< TOutPixelType, 3 > > { public: typedef AdcImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInPixelType, 3 >, Image< TOutPixelType, 3 > > Superclass; typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; - typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer GradientContainerType; + typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer GradientContainerType; typedef itk::Image< unsigned char, 3> ItkUcharImageType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(AdcImageFilter, ImageToImageFilter) typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; itkSetMacro( MaskImage, ItkUcharImageType::Pointer ) itkSetMacro( FitSignal, bool ) itkSetMacro( B_value, double ) itkSetMacro( GradientDirections, GradientContainerType ) /** * \brief The lestSquaresFunction struct for Non-Linear-Least-Squres fit of monoexponential model Si = S0*exp(-b*ADC) */ struct adcLeastSquaresFunction: public vnl_least_squares_function { void set_S0(double val) { S0 = val; } void set_measurements(const vnl_vector& m) { measurements.set_size(m.size()); measurements.copy_in(m.data_block()); } void set_bvalues(const vnl_vector& x) { bValues.set_size(x.size()); bValues.copy_in(x.data_block()); } vnl_vector measurements; vnl_vector bValues; double S0; adcLeastSquaresFunction(unsigned int number_of_measurements=1) : vnl_least_squares_function(1, number_of_measurements, no_gradient) { } void f(const vnl_vector& x, vnl_vector& fx) override { const double & ADC = x[0]; for(unsigned int s=0; s m_B_values; vnl_vector m_Nonzero_B_values; GradientContainerType m_GradientDirections; ItkUcharImageType::Pointer m_MaskImage; double FitSingleVoxel( const typename InputImageType::PixelType &input); }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkAdcImageFilter.txx" #endif #endif //__itkAdcImageFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkB0ImageExtractionImageFilter.h b/Modules/DiffusionCore/Algorithms/itkB0ImageExtractionImageFilter.h index a5d2848..9d9dc36 100644 --- a/Modules/DiffusionCore/Algorithms/itkB0ImageExtractionImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkB0ImageExtractionImageFilter.h @@ -1,90 +1,90 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef __itkB0ImageExtractionImageFilter_h_ #define __itkB0ImageExtractionImageFilter_h_ #include "itkImageToImageFilter.h" namespace itk{ /** \class B0ImageExtractionImageFilter * \brief This class takes as input a T2-weighted image and computes a brainmask. * */ template< class TInputImagePixelType, class TOutputImagePixelType > class B0ImageExtractionImageFilter : public ImageToImageFilter< VectorImage, Image< TOutputImagePixelType, 3 > > { public: typedef B0ImageExtractionImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInputImagePixelType, 3 >, Image< TOutputImagePixelType, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(B0ImageExtractionImageFilter, ImageToImageFilter); typedef TInputImagePixelType InputPixelType; typedef TOutputImagePixelType OutputPixelType; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef vnl_vector_fixed< double, 3 > GradientDirectionType; typedef itk::VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; - GradientDirectionContainerType::Pointer GetDirections() + GradientDirectionContainerType::ConstPointer GetDirections() { return m_Directions; } - void SetDirections( GradientDirectionContainerType::Pointer directions ) + void SetDirections( GradientDirectionContainerType::ConstPointer directions ) { this->m_Directions = directions; } protected: B0ImageExtractionImageFilter(); ~B0ImageExtractionImageFilter() override {}; void GenerateData() override; - GradientDirectionContainerType::Pointer m_Directions; + GradientDirectionContainerType::ConstPointer m_Directions; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkB0ImageExtractionImageFilter.txx" #endif #endif //__itkB0ImageExtractionImageFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkB0ImageExtractionImageFilter.txx b/Modules/DiffusionCore/Algorithms/itkB0ImageExtractionImageFilter.txx index f99b802..3d2f787 100644 --- a/Modules/DiffusionCore/Algorithms/itkB0ImageExtractionImageFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkB0ImageExtractionImageFilter.txx @@ -1,126 +1,126 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkB0ImageExtractionImageFilter_txx #define __itkB0ImageExtractionImageFilter_txx #include "itkB0ImageExtractionImageFilter.h" #include "itkImageRegionIterator.h" namespace itk { template< class TInputImagePixelType, class TOutputImagePixelType > B0ImageExtractionImageFilter< TInputImagePixelType, TOutputImagePixelType > ::B0ImageExtractionImageFilter() { // At least 1 inputs is necessary for a vector image. // For images added one at a time we need at least six this->SetNumberOfRequiredInputs( 1 ); } template< class TInputImagePixelType, class TOutputImagePixelType > void B0ImageExtractionImageFilter< TInputImagePixelType, TOutputImagePixelType > ::GenerateData() { - typename GradientDirectionContainerType::Iterator begin = m_Directions->Begin(); - typename GradientDirectionContainerType::Iterator end = m_Directions->End(); + typename GradientDirectionContainerType::ConstIterator begin = m_Directions->Begin(); + typename GradientDirectionContainerType::ConstIterator end = m_Directions->End(); // Find the index of the b0 image std::vector indices; int index = 0; while(begin!=end) { GradientDirectionType grad = begin->Value(); if(grad[0] == 0 && grad[1] == 0 && grad[2] == 0) { indices.push_back(index); } ++index; ++begin; } typedef itk::Image TempImageType; TempImageType::Pointer tmp = TempImageType::New(); typename TempImageType::RegionType region = this->GetInput()->GetLargestPossibleRegion(); tmp->SetSpacing(this->GetInput()->GetSpacing()); tmp->SetOrigin(this->GetInput()->GetOrigin()); tmp->SetDirection(this->GetInput()->GetDirection()); tmp->SetRegions(region); tmp->Allocate(); itk::ImageRegionIterator it(tmp.GetPointer(), tmp->GetLargestPossibleRegion() ); itk::ImageRegionConstIterator vectorIt(this->GetInput(), this->GetInput()->GetLargestPossibleRegion() ); it.GoToBegin(); while(!it.IsAtEnd()) { it.Set(0); ++it; } //Sum all images that have zero diffusion weighting (indices stored in vector index) for(std::vector::iterator indexIt = indices.begin(); indexIt != indices.end(); indexIt++) { it.GoToBegin(); vectorIt.GoToBegin(); while(!it.IsAtEnd() && !vectorIt.IsAtEnd()) { typename InputImageType::PixelType vec = vectorIt.Get(); it.Set((1.0 * it.Get()) + (1.0 * vec[*indexIt]) / (1.0 * indices.size())); ++it; ++vectorIt; } } typename OutputImageType::Pointer b0Image = static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); typename OutputImageType::RegionType outregion = this->GetInput()->GetLargestPossibleRegion(); b0Image->SetSpacing(this->GetInput()->GetSpacing()); b0Image->SetOrigin(this->GetInput()->GetOrigin()); b0Image->SetDirection(this->GetInput()->GetDirection()); b0Image->SetRegions(outregion); b0Image->Allocate(); itk::ImageRegionIterator itIn(tmp, tmp->GetLargestPossibleRegion() ); itk::ImageRegionIterator itOut(b0Image, b0Image->GetLargestPossibleRegion() ); itIn.GoToBegin(); itOut.GoToBegin(); while(!itIn.IsAtEnd()) { itOut.Set(itIn.Get()); ++itIn; ++itOut; } } } #endif // __itkB0ImageExtractionImageFilter_txx diff --git a/Modules/DiffusionCore/Algorithms/itkB0ImageExtractionToSeparateImageFilter.h b/Modules/DiffusionCore/Algorithms/itkB0ImageExtractionToSeparateImageFilter.h index 25cc6f5..29efaf1 100644 --- a/Modules/DiffusionCore/Algorithms/itkB0ImageExtractionToSeparateImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkB0ImageExtractionToSeparateImageFilter.h @@ -1,107 +1,107 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef ITKB0IMAGEEXTRACTIONTOSEPARATEIMAGEFILTER_H #define ITKB0IMAGEEXTRACTIONTOSEPARATEIMAGEFILTER_H #include "itkImageToImageFilter.h" namespace itk { /** \class B0ImageExtractionToSeparateImageFilter \brief This class has an advanced functionality to the B0ImageExtractionImageFilter, however the b0 images are stored in a 3D+t image with each b0 image beeing a separate timestep and not averaged to a single 3D volume */ template< class TInputImagePixelType, class TOutputImagePixelType > class B0ImageExtractionToSeparateImageFilter : public ImageToImageFilter< VectorImage, Image< TOutputImagePixelType, 4 > > { public: typedef B0ImageExtractionToSeparateImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef TInputImagePixelType InputPixelType; typedef TOutputImagePixelType OutputPixelType; typedef ImageToImageFilter< VectorImage, Image< TOutputImagePixelType, 4 > > Superclass; /** typedefs from superclass */ typedef typename Superclass::InputImageType InputImageType; //typedef typename Superclass::OutputImageType OutputImageType; typedef Image< TOutputImagePixelType, 4 > OutputImageType; typedef typename OutputImageType::RegionType OutputImageRegionType; typedef vnl_vector_fixed< double, 3 > GradientDirectionType; typedef itk::VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; - typedef typename GradientDirectionContainerType::Iterator GradContainerIteratorType; + typedef typename GradientDirectionContainerType::ConstIterator GradContainerIteratorType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(B0ImageExtractionToSeparateImageFilter, ImageToImageFilter); - GradientDirectionContainerType::Pointer GetDirections() + GradientDirectionContainerType::ConstPointer GetDirections() { return m_Directions; } - void SetDirections( GradientDirectionContainerType::Pointer directions ) + void SetDirections( GradientDirectionContainerType::ConstPointer directions ) { this->m_Directions = directions; } protected: B0ImageExtractionToSeparateImageFilter(); virtual ~B0ImageExtractionToSeparateImageFilter(){}; void GenerateData(); /** The dimension of the output does not match the dimension of the input hence we need to re-implement the CopyInformation method to avoid executing the default implementation which tries to copy the input information to the output */ virtual void CopyInformation( const DataObject *data); /** Override of the ProcessObject::GenerateOutputInformation() because of different dimensionality of the input and the output */ virtual void GenerateOutputInformation(); - GradientDirectionContainerType::Pointer m_Directions; + GradientDirectionContainerType::ConstPointer m_Directions; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkB0ImageExtractionToSeparateImageFilter.txx" #endif #endif // ITKB0IMAGEEXTRACTIONTOSEPARATEIMAGEFILTER_H diff --git a/Modules/DiffusionCore/Algorithms/itkDwiGradientLengthCorrectionFilter.h b/Modules/DiffusionCore/Algorithms/itkDwiGradientLengthCorrectionFilter.h index ad8e203..1e07cd0 100644 --- a/Modules/DiffusionCore/Algorithms/itkDwiGradientLengthCorrectionFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkDwiGradientLengthCorrectionFilter.h @@ -1,75 +1,75 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef _itk_DwiGradientLengthCorrectionFilter_h_ #define _itk_DwiGradientLengthCorrectionFilter_h_ #include #include #include #include namespace itk { class MITKDIFFUSIONCORE_EXPORT DwiGradientLengthCorrectionFilter : public ProcessObject { public: typedef DwiGradientLengthCorrectionFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ProcessObject Superclass; typedef vnl_vector_fixed< double, 3 > GradientDirectionType; typedef itk::VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro(DwiGradientLengthCorrectionFilter,ProcessObject) void GenerateData() override; void Update() override{ this->GenerateData(); } // input itkSetMacro(RoundingValue, int) itkSetMacro(ReferenceBValue, double) - itkSetMacro(ReferenceGradientDirectionContainer, GradientDirectionContainerType::Pointer) + itkSetMacro(ReferenceGradientDirectionContainer, GradientDirectionContainerType::ConstPointer) // output itkGetMacro(OutputGradientDirectionContainer, GradientDirectionContainerType::Pointer) itkGetMacro(NewBValue, double) protected: DwiGradientLengthCorrectionFilter(); ~DwiGradientLengthCorrectionFilter() override; double m_NewBValue; double m_ReferenceBValue; int m_RoundingValue; - GradientDirectionContainerType::Pointer m_ReferenceGradientDirectionContainer; + GradientDirectionContainerType::ConstPointer m_ReferenceGradientDirectionContainer; GradientDirectionContainerType::Pointer m_OutputGradientDirectionContainer; }; } // end of namespace #endif diff --git a/Modules/DiffusionCore/Algorithms/itkDwiNormilzationFilter.h b/Modules/DiffusionCore/Algorithms/itkDwiNormilzationFilter.h index 7de201f..4ffc8dd 100644 --- a/Modules/DiffusionCore/Algorithms/itkDwiNormilzationFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkDwiNormilzationFilter.h @@ -1,101 +1,101 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkDwiNormilzationFilter_h_ #define __itkDwiNormilzationFilter_h_ #include "itkImageToImageFilter.h" #include "itkVectorImage.h" #include #include #include #include namespace itk{ /** \class DwiNormilzationFilter * \brief Normalizes the data vectors either using the specified reference value or the voxelwise baseline value. */ template< class TInPixelType > class DwiNormilzationFilter : public ImageToImageFilter< VectorImage< TInPixelType, 3 >, VectorImage< TInPixelType, 3 > > { public: typedef DwiNormilzationFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInPixelType, 3 >, VectorImage< TInPixelType, 3 > > Superclass; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DwiNormilzationFilter, ImageToImageFilter) typedef itk::Image< double, 3 > DoubleImageType; typedef itk::Image< unsigned char, 3 > UcharImageType; typedef itk::Image< unsigned short, 3 > BinImageType; typedef itk::Image< TInPixelType, 3 > TInPixelImageType; typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; - typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer GradientContainerType; + typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer GradientContainerType; typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typedef ImageRegionConstIterator< UcharImageType > MaskIteratorType; itkSetMacro( GradientDirections, GradientContainerType ) itkSetMacro( ScalingFactor, TInPixelType ) itkSetMacro( MaskImage, UcharImageType::Pointer ) itkSetMacro( NewMean, double ) itkSetMacro( NewStdev, double ) protected: DwiNormilzationFilter(); ~DwiNormilzationFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType); UcharImageType::Pointer m_MaskImage; GradientContainerType m_GradientDirections; int m_B0Index; TInPixelType m_ScalingFactor; double m_Mean; double m_Stdev; double m_NewMean; double m_NewStdev; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDwiNormilzationFilter.txx" #endif #endif //__itkDwiNormilzationFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.h b/Modules/DiffusionCore/Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.h index 219d226..b684f1b 100644 --- a/Modules/DiffusionCore/Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.h @@ -1,128 +1,128 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ /*========================================================================= Program: Tensor ToolKit - TTK Module: $URL: svn://scm.gforge.inria.fr/svn/ttk/trunk/Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.h $ Language: C++ Date: $Date: 2010-06-07 13:39:13 +0200 (Mo, 07 Jun 2010) $ Version: $Revision: 68 $ Copyright (c) INRIA 2010. All rights reserved. See LICENSE.txt 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 _itk_ElectrostaticRepulsionDiffusionGradientReductionFilter_h_ #define _itk_ElectrostaticRepulsionDiffusionGradientReductionFilter_h_ #include #include #include namespace itk { /** * \brief Select subset of the input vectors equally distributed over the sphere using an iterative electrostatic repulsion strategy. */ template class ElectrostaticRepulsionDiffusionGradientReductionFilter : public ImageToImageFilter, itk::VectorImage > { public: typedef ElectrostaticRepulsionDiffusionGradientReductionFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< itk::VectorImage, itk::VectorImage > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(ElectrostaticRepulsionDiffusionGradientReductionFilter, ImageToImageFilter) typedef TInputScalarType InputScalarType; typedef itk::VectorImage InputImageType; typedef typename InputImageType::PixelType InputPixelType; typedef TOutputScalarType OutputScalarType; typedef itk::VectorImage OutputImageType; typedef typename OutputImageType::PixelType OutputPixelType; typedef OutputScalarType BaselineScalarType; typedef BaselineScalarType BaselinePixelType; typedef typename itk::Image BaselineImageType; typedef vnl_vector_fixed< double, 3 > GradientDirectionType; typedef itk::VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; typedef std::vector IndicesVector; typedef std::map BValueMap; - itkGetMacro(OriginalGradientDirections, GradientDirectionContainerType::Pointer) - itkSetMacro(OriginalGradientDirections, GradientDirectionContainerType::Pointer) + itkGetMacro(OriginalGradientDirections, GradientDirectionContainerType::ConstPointer) + itkSetMacro(OriginalGradientDirections, GradientDirectionContainerType::ConstPointer) - itkGetMacro(GradientDirections, GradientDirectionContainerType::Pointer) - itkSetMacro(GradientDirections, GradientDirectionContainerType::Pointer) + itkGetMacro(GradientDirections, GradientDirectionContainerType::ConstPointer) + itkSetMacro(GradientDirections, GradientDirectionContainerType::ConstPointer) itkSetMacro(UseFirstN, bool) IndicesVector GetUsedGradientIndices(){return m_UsedGradientIndices;} void SetOriginalBValueMap(BValueMap inp){m_OriginalBValueMap = inp;} void SetShellSelectionBValueMap(BValueMap inp){m_InputBValueMap = inp;} void SetNumGradientDirections(std::vector numDirs){m_NumGradientDirections = numDirs;} void UpdateOutputInformation() override; protected: ElectrostaticRepulsionDiffusionGradientReductionFilter(); ~ElectrostaticRepulsionDiffusionGradientReductionFilter() override {} void GenerateData() override; double Costs(); ///< calculates electrostatic energy of current direction set - GradientDirectionContainerType::Pointer m_GradientDirections; ///< container for the subsampled output gradient directions - GradientDirectionContainerType::Pointer m_OriginalGradientDirections; ///< input gradient directions + GradientDirectionContainerType::ConstPointer m_GradientDirections; ///< container for the subsampled output gradient directions + GradientDirectionContainerType::ConstPointer m_OriginalGradientDirections; ///< input gradient directions IndicesVector m_UsedGradientIndices; IndicesVector m_UnusedGradientIndices; IndicesVector m_BaselineImageIndices; BValueMap m_OriginalBValueMap; BValueMap m_InputBValueMap; bool m_UseFirstN; std::vector m_NumGradientDirections; }; } // end of namespace #ifndef ITK_MANUAL_INSTANTIATION #include "itkElectrostaticRepulsionDiffusionGradientReductionFilter.txx" #endif #endif diff --git a/Modules/DiffusionCore/Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.txx b/Modules/DiffusionCore/Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.txx index a802c81..e63da72 100644 --- a/Modules/DiffusionCore/Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.txx @@ -1,270 +1,272 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ /*========================================================================= Program: Tensor ToolKit - TTK Module: $URL: svn://scm.gforge.inria.fr/svn/ttk/trunk/Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.txx $ Language: C++ Date: $Date: 2010-06-07 13:39:13 +0200 (Mo, 07 Jun 2010) $ Version: $Revision: 68 $ Copyright (c) INRIA 2010. All rights reserved. See LICENSE.txt 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 _itk_ElectrostaticRepulsionDiffusionGradientReductionFilter_txx_ #define _itk_ElectrostaticRepulsionDiffusionGradientReductionFilter_txx_ #endif #include "itkElectrostaticRepulsionDiffusionGradientReductionFilter.h" #include #include #include #include namespace itk { template ElectrostaticRepulsionDiffusionGradientReductionFilter ::ElectrostaticRepulsionDiffusionGradientReductionFilter() : m_UseFirstN(false) { this->SetNumberOfRequiredInputs( 1 ); } template double ElectrostaticRepulsionDiffusionGradientReductionFilter ::Costs() { double costs = 2*itk::Math::pi; for (IndicesVector::iterator it = m_UsedGradientIndices.begin(); it!=m_UsedGradientIndices.end(); ++it) { for (IndicesVector::iterator it2 = m_UsedGradientIndices.begin(); it2!=m_UsedGradientIndices.end(); ++it2) if (it != it2) { vnl_vector_fixed v1 = m_OriginalGradientDirections->at(*it); vnl_vector_fixed v2 = m_OriginalGradientDirections->at(*it2); v1.normalize(); v2.normalize(); double temp = dot_product(v1,v2); if (temp>1) temp = 1; else if (temp<-1) temp = -1; double angle = acos(temp); if (angle1) temp = 1; else if (temp<-1) temp = -1; angle = acos(temp); if (angle void ElectrostaticRepulsionDiffusionGradientReductionFilter ::GenerateData() { itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer randgen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); if(m_InputBValueMap.empty() || m_NumGradientDirections.size()!=m_InputBValueMap.size()) mitkThrow() << "Vector of the number of desired gradient directions contains more elements than the specified target b-value map."; BValueMap manipulatedMap = m_InputBValueMap; IndicesVector final_gradient_indices; int shellCounter = 0; for(BValueMap::iterator it = m_InputBValueMap.begin(); it != m_InputBValueMap.end(); it++ ) { randgen->SetSeed(); m_UsedGradientIndices.clear(); m_UnusedGradientIndices.clear(); MITK_INFO << "Shell number: " << shellCounter; unsigned int c=0; for (unsigned int i=0; isecond.size(); i++) { if (csecond.at(i)); else m_UnusedGradientIndices.push_back(it->second.at(i)); c++; } if ( it->second.size() <= m_NumGradientDirections[shellCounter] ) { itkWarningMacro( << "current directions: " << it->second.size() << " wanted directions: " << m_NumGradientDirections[shellCounter]); m_NumGradientDirections[shellCounter] = it->second.size(); } else if (!m_UseFirstN) { double minAngle = Costs(); double newMinAngle = 0; MITK_INFO << "minimum angle: " << 180*minAngle/itk::Math::pi; int stagnationCount = 0; int rejectionCount = 0; int maxRejections = m_NumGradientDirections[shellCounter] * 1000; if (maxRejections<10000) maxRejections = 10000; int iUsed = 0; if (m_UsedGradientIndices.size()>0) { while ( stagnationCount<1000 && rejectionCountGetIntegerVariate() % m_UnusedGradientIndices.size(); int vUsed = m_UsedGradientIndices.at(iUsed); int vUnUsed = m_UnusedGradientIndices.at(iUnUsed); m_UsedGradientIndices.at(iUsed) = vUnUsed; m_UnusedGradientIndices.at(iUnUsed) = vUsed; newMinAngle = Costs(); // calculate costs of proposed configuration if (newMinAngle > minAngle) // accept or reject proposal { MITK_INFO << "minimum angle: " << 180*newMinAngle/itk::Math::pi; if ( (newMinAngle-minAngle)<0.01 ) stagnationCount++; else stagnationCount = 0; minAngle = newMinAngle; rejectionCount = 0; } else { rejectionCount++; m_UsedGradientIndices.at(iUsed) = vUsed; m_UnusedGradientIndices.at(iUnUsed) = vUnUsed; } iUsed++; iUsed = iUsed % m_UsedGradientIndices.size(); } } } manipulatedMap[it->first] = m_UsedGradientIndices; shellCounter++; for (auto gidx : m_UsedGradientIndices) final_gradient_indices.push_back(gidx); } std::sort(final_gradient_indices.begin(), final_gradient_indices.end()); int vecLength = 0 ; for(BValueMap::iterator it = manipulatedMap.begin(); it != manipulatedMap.end(); it++) vecLength += it->second.size(); // initialize output image typename OutputImageType::Pointer outImage = OutputImageType::New(); outImage->SetSpacing( this->GetInput()->GetSpacing() ); // Set the image spacing outImage->SetOrigin( this->GetInput()->GetOrigin() ); // Set the image origin outImage->SetDirection( this->GetInput()->GetDirection() ); // Set the image direction outImage->SetLargestPossibleRegion( this->GetInput()->GetLargestPossibleRegion()); outImage->SetBufferedRegion( this->GetInput()->GetLargestPossibleRegion() ); outImage->SetRequestedRegion( this->GetInput()->GetLargestPossibleRegion() ); outImage->SetVectorLength( final_gradient_indices.size() ); // Set the vector length outImage->Allocate(); itk::ImageRegionIterator< OutputImageType > newIt(outImage, outImage->GetLargestPossibleRegion()); newIt.GoToBegin(); typename InputImageType::Pointer inImage = const_cast(this->GetInput(0)); itk::ImageRegionIterator< InputImageType > oldIt(inImage, inImage->GetLargestPossibleRegion()); oldIt.GoToBegin(); // initial new value of voxel OutputPixelType newVec; newVec.SetSize( final_gradient_indices.size() ); newVec.AllocateElements( final_gradient_indices.size() ); // generate new pixel values while(!newIt.IsAtEnd()) { // init new vector with zeros newVec.Fill(0.0); InputPixelType oldVec = oldIt.Get(); for (unsigned int i=0; isecond.size(); j++) // { // newVec[index] = oldVec[it->second.at(j)]; // index++; // } newIt.Set(newVec); ++newIt; ++oldIt; } // set new gradient directions - m_GradientDirections = GradientDirectionContainerType::New(); + + GradientDirectionContainerType::Pointer temp = GradientDirectionContainerType::New(); for (unsigned int i=0; iInsertElement(i, m_OriginalGradientDirections->at(final_gradient_indices.at(i))); + temp->InsertElement(i, m_OriginalGradientDirections->at(final_gradient_indices.at(i))); + m_GradientDirections = temp; // int index = 0; // for(BValueMap::iterator it = manipulatedMap.begin(); it != manipulatedMap.end(); it++) // for(unsigned int j = 0; j < it->second.size(); j++) // { // m_GradientDirections->InsertElement(index, m_OriginalGradientDirections->at(it->second.at(j))); // index++; // } this->SetNumberOfRequiredOutputs (1); this->SetNthOutput (0, outImage); MITK_INFO << "...done"; } template void ElectrostaticRepulsionDiffusionGradientReductionFilter ::UpdateOutputInformation() { Superclass::UpdateOutputInformation(); int vecLength = 0 ; for(unsigned int index = 0; index < m_NumGradientDirections.size(); index++) { vecLength += m_NumGradientDirections[index]; } this->GetOutput()->SetVectorLength( vecLength ); } } // end of namespace diff --git a/Modules/DiffusionCore/Algorithms/itkMergeDiffusionImagesFilter.h b/Modules/DiffusionCore/Algorithms/itkMergeDiffusionImagesFilter.h index 30e6c48..2c9676c 100644 --- a/Modules/DiffusionCore/Algorithms/itkMergeDiffusionImagesFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkMergeDiffusionImagesFilter.h @@ -1,108 +1,108 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ /*========================================================================= Program: Tensor ToolKit - TTK Module: $URL: svn://scm.gforge.inria.fr/svn/ttk/trunk/Algorithms/itkMergeDiffusionImagesFilter.h $ Language: C++ Date: $Date: 2010-06-07 13:39:13 +0200 (Mo, 07 Jun 2010) $ Version: $Revision: 68 $ Copyright (c) INRIA 2010. All rights reserved. See LICENSE.txt 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 _itk_MergeDiffusionImagesFilter_h_ #define _itk_MergeDiffusionImagesFilter_h_ #include "itkImageToImageFilter.h" #include #include #include namespace itk { /** * \brief Merges diffusion weighted images, e.g. to generate one multishell volume from several single shell volumes. */ template class MergeDiffusionImagesFilter : public ImageSource > { public: typedef MergeDiffusionImagesFilter Self; typedef ImageSource< itk::VectorImage > Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(MergeDiffusionImagesFilter, ImageSource) typedef itk::VectorImage DwiImageType; typedef typename DwiImageType::PixelType DwiPixelType; typedef typename DwiImageType::RegionType DwiRegionType; typedef typename std::vector< typename DwiImageType::Pointer > DwiImageContainerType; typedef vnl_vector_fixed< double, 3 > GradientType; typedef itk::VectorContainer< unsigned int, GradientType > GradientListType; - typedef typename std::vector< GradientListType::Pointer > GradientListContainerType; + typedef typename std::vector< GradientListType::ConstPointer > GradientListContainerType; // input void SetImageVolumes(DwiImageContainerType cont); ///< input DWI image volume container void SetGradientLists(GradientListContainerType cont); ///< gradients of all input images void SetBValues(std::vector< double > bvals); ///< b-values of all input images // output GradientListType::Pointer GetOutputGradients(); ///< gradient list of the merged output image double GetB_Value(); ///< main b-value of the merged output image protected: MergeDiffusionImagesFilter(); ~MergeDiffusionImagesFilter(); void GenerateData() override; DwiImageContainerType m_ImageVolumes; ///< contains input images GradientListContainerType m_GradientLists; ///< contains gradients of all input images std::vector< double > m_BValues; ///< contains b-values of all input images int m_NumGradients; ///< number of gradients in the output image GradientListType::Pointer m_OutputGradients; ///< container for output gradients double m_BValue; ///< main output b-value }; } // end of namespace #ifndef ITK_MANUAL_INSTANTIATION #include "itkMergeDiffusionImagesFilter.txx" #endif #endif diff --git a/Modules/DiffusionCore/Algorithms/itkMergeDiffusionImagesFilter.txx b/Modules/DiffusionCore/Algorithms/itkMergeDiffusionImagesFilter.txx index 261f233..cbc48e9 100644 --- a/Modules/DiffusionCore/Algorithms/itkMergeDiffusionImagesFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkMergeDiffusionImagesFilter.txx @@ -1,179 +1,179 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ /*========================================================================= 2 3 Program: Tensor ToolKit - TTK 4 Module: $URL: svn://scm.gforge.inria.fr/svn/ttk/trunk/Algorithms/itkMergeDiffusionImagesFilter.txx $ 5 Language: C++ 6 Date: $Date: 2010-06-07 13:39:13 +0200 (Mo, 07 Jun 2010) $ 7 Version: $Revision: 68 $ 8 9 Copyright (c) INRIA 2010. All rights reserved. 10 See LICENSE.txt for details. 11 12 This software is distributed WITHOUT ANY WARRANTY; without even 13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 14 PURPOSE. See the above copyright notices for more information. 15 16 =========================================================================*/ #ifndef _itk_MergeDiffusionImagesFilter_txx_ #define _itk_MergeDiffusionImagesFilter_txx_ #endif #include "itkMergeDiffusionImagesFilter.h" #include "itkTensorToL2NormImageFilter.h" #include "itkRescaleIntensityImageFilter.h" #include #include #include namespace itk { template MergeDiffusionImagesFilter::MergeDiffusionImagesFilter() { } template MergeDiffusionImagesFilter::~MergeDiffusionImagesFilter() { } template void MergeDiffusionImagesFilter ::SetImageVolumes(DwiImageContainerType cont) { m_ImageVolumes=cont; } template void MergeDiffusionImagesFilter ::SetGradientLists(GradientListContainerType cont) { m_GradientLists=cont; } template void MergeDiffusionImagesFilter ::SetBValues(std::vector< double > bvals) { m_BValues=bvals; } template MergeDiffusionImagesFilter::GradientListType::Pointer MergeDiffusionImagesFilter ::GetOutputGradients() { return m_OutputGradients; } template double MergeDiffusionImagesFilter ::GetB_Value() { return m_BValue; } template void MergeDiffusionImagesFilter ::GenerateData () { if( m_ImageVolumes.size()<2 ) throw itk::ExceptionObject (__FILE__,__LINE__,"Error: cannot combine less than two DWIs."); if( m_GradientLists.size()!=m_ImageVolumes.size() || m_ImageVolumes.size()!=m_BValues.size() || m_BValues.size()!=m_GradientLists.size() ) throw itk::ExceptionObject (__FILE__,__LINE__,"Error: need same number of b-values, image volumes and gradient containers."); typename DwiImageType::Pointer img = m_ImageVolumes.at(0); m_NumGradients = 0; for (unsigned int i=0; iSize(); typename DwiImageType::Pointer tmp = m_ImageVolumes.at(i); if ( img->GetLargestPossibleRegion()!=tmp->GetLargestPossibleRegion() ) throw itk::ExceptionObject (__FILE__,__LINE__,"Error: images are not of same size."); } m_BValue = 0; for (auto bval : m_BValues) if (bval>m_BValue) m_BValue = bval; m_OutputGradients = GradientListType::New(); typename DwiImageType::Pointer outImage = DwiImageType::New(); outImage->SetSpacing( img->GetSpacing() ); // Set the image spacing outImage->SetOrigin( img->GetOrigin() ); // Set the image origin outImage->SetDirection( img->GetDirection() ); // Set the image direction outImage->SetLargestPossibleRegion( img->GetLargestPossibleRegion()); outImage->SetBufferedRegion( img->GetLargestPossibleRegion() ); outImage->SetRequestedRegion( img->GetLargestPossibleRegion() ); outImage->SetVectorLength(m_NumGradients); outImage->Allocate(); this->SetNumberOfRequiredOutputs(1); this->SetNthOutput (0, outImage); typedef ImageRegionIterator IteratorOutputType; IteratorOutputType itOut (this->GetOutput(), this->GetOutput()->GetLargestPossibleRegion()); MITK_INFO << "MergeDiffusionImagesFilter: merging images"; GradientType zeroG; zeroG.fill(0.0); boost::progress_display disp(this->GetOutput()->GetLargestPossibleRegion().GetNumberOfPixels()); while(!itOut.IsAtEnd()) { ++disp; DwiPixelType out; out.SetSize(m_NumGradients); out.Fill(0); int c=0; for (unsigned int i=0; iSize(); j++) { GradientType g = gradients->GetElement(j); double mag = g.two_norm(); if (mag>0.0001) { double frac = m_BValues.at(i)*mag*mag/m_BValue; g.normalize(); g *= sqrt(frac); } else g = zeroG; m_OutputGradients->InsertElement(c, g); out[c] = static_cast(img->GetPixel(itOut.GetIndex())[j]); c++; } } itOut.Set(out); ++itOut; } } } // end of namespace diff --git a/Modules/DiffusionCore/Algorithms/itkRemoveDwiChannelFilter.h b/Modules/DiffusionCore/Algorithms/itkRemoveDwiChannelFilter.h index d3bbed2..9079886 100644 --- a/Modules/DiffusionCore/Algorithms/itkRemoveDwiChannelFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkRemoveDwiChannelFilter.h @@ -1,84 +1,84 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkRemoveDwiChannelFilter_h_ #define __itkRemoveDwiChannelFilter_h_ #include "itkImageToImageFilter.h" #include "itkVectorImage.h" #include #include namespace itk{ /** \class RemoveDwiChannelFilter * \brief Remove spcified channels from diffusion-weighted image. */ template< class TInPixelType > class RemoveDwiChannelFilter : public ImageToImageFilter< VectorImage< TInPixelType, 3 >, VectorImage< TInPixelType, 3 > > { public: typedef RemoveDwiChannelFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInPixelType, 3 >, VectorImage< TInPixelType, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(RemoveDwiChannelFilter, ImageToImageFilter) typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef typename mitk::DiffusionPropertyHelper::GradientDirectionType DirectionType; typedef typename mitk::DiffusionPropertyHelper::GradientDirectionsContainerType DirectionContainerType; void SetChannelIndices( std::vector< unsigned int > indices ){ m_ChannelIndices = indices; } - void SetDirections( typename DirectionContainerType::Pointer directions ){ m_Directions = directions; } + void SetDirections( typename DirectionContainerType::ConstPointer directions ){ m_Directions = directions; } typename DirectionContainerType::Pointer GetNewDirections(){ return m_NewDirections; } protected: RemoveDwiChannelFilter(); ~RemoveDwiChannelFilter() {} void PrintSelf(std::ostream& os, Indent indent) const override; void BeforeThreadedGenerateData() override; void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType id ) override; std::vector< unsigned int > m_ChannelIndices; - typename DirectionContainerType::Pointer m_Directions; + typename DirectionContainerType::ConstPointer m_Directions; typename DirectionContainerType::Pointer m_NewDirections; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkRemoveDwiChannelFilter.txx" #endif #endif //__itkRemoveDwiChannelFilter_h_ diff --git a/Modules/DiffusionCore/Algorithms/itkResidualImageFilter.h b/Modules/DiffusionCore/Algorithms/itkResidualImageFilter.h index 1101ef5..8e32ee2 100644 --- a/Modules/DiffusionCore/Algorithms/itkResidualImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkResidualImageFilter.h @@ -1,177 +1,177 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ /*========================================================================= Program: Tensor ToolKit - TTK Module: $URL: svn://scm.gforge.inria.fr/svn/ttk/trunk/Algorithms/itkTensorImageToDiffusionImageFilter.h $ Language: C++ Date: $Date: 2010-06-07 13:39:13 +0200 (Mo, 07 Jun 2010) $ Version: $Revision: 68 $ Copyright (c) INRIA 2010. All rights reserved. See LICENSE.txt 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 _itk_ResidualImageFilter_h_ #define _itk_ResidualImageFilter_h_ #include "itkImageToImageFilter.h" #include namespace itk { template class ResidualImageFilter : public ImageToImageFilter, itk::Image > { public: typedef TInputScalarType InputScalarType; typedef itk::VectorImage InputImageType; typedef typename InputImageType::PixelType InputPixelType; typedef typename InputImageType::RegionType InputImageRegionType; typedef TOutputScalarType OutputScalarType; typedef itk::Image OutputImageType; typedef typename OutputImageType::PixelType OutputPixelType; typedef typename OutputImageType::RegionType OutputImageRegionType; typedef ResidualImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef vnl_vector_fixed< double, 3 > GradientDirectionType; typedef itk::VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; typedef itk::Image BaselineImageType; itkTypeMacro (ResidualImageFilter, ImageToImageFilter); itkStaticConstMacro (ImageDimension, unsigned int, OutputImageType::ImageDimension); itkFactorylessNewMacro(Self) itkCloneMacro(Self) void SetSecondDiffusionImage(typename InputImageType::Pointer diffImage) { m_SecondDiffusionImage = diffImage; } std::vector GetQ1() { return m_Q1; } std::vector GetQ3() { return m_Q3; } std::vector GetMeans() { return m_Means; } std::vector GetPercentagesOfOutliers() { return m_PercentagesOfOutliers; } std::vector< std::vector > GetOutliersPerSlice() { return m_OutliersPerSlice; } - void SetGradients(GradientDirectionContainerType* grads) + void SetGradients(GradientDirectionContainerType::ConstPointer grads) { m_Gradients = grads; } void SetBaseLineImage(BaselineImageType* baseline) { m_BaseLineImage = baseline; } void SetB0Threshold(InputScalarType threshold) { m_B0Threshold = threshold; } itkSetMacro(B0Index, int) protected: ResidualImageFilter() { m_B0Threshold = 30.0; // default value. allow user to redefine }; ~ResidualImageFilter(){}; void PrintSelf (std::ostream& os, Indent indent) const override { Superclass::PrintSelf (os, indent); } void GenerateData() override; private: ResidualImageFilter (const Self&); void operator=(const Self&); typename InputImageType::Pointer m_SecondDiffusionImage; std::vector m_Means, m_Q1, m_Q3, m_PercentagesOfOutliers; // 'Outer' vector: slices, 'Inner' volumes std::vector< std::vector > m_OutliersPerSlice; - GradientDirectionContainerType* m_Gradients; + GradientDirectionContainerType::ConstPointer m_Gradients; typename BaselineImageType::Pointer m_BaseLineImage; InputScalarType m_B0Threshold; int m_B0Index; }; } // end of namespace #ifndef ITK_MANUAL_INSTANTIATION #include "itkResidualImageFilter.txx" #endif #endif diff --git a/Modules/DiffusionCore/Algorithms/itkTensorImageToDiffusionImageFilter.h b/Modules/DiffusionCore/Algorithms/itkTensorImageToDiffusionImageFilter.h index 0bd32a8..b74a281 100644 --- a/Modules/DiffusionCore/Algorithms/itkTensorImageToDiffusionImageFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkTensorImageToDiffusionImageFilter.h @@ -1,170 +1,170 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ /*========================================================================= Program: Tensor ToolKit - TTK Module: $URL: svn://scm.gforge.inria.fr/svn/ttk/trunk/Algorithms/itkTensorImageToDiffusionImageFilter.h $ Language: C++ Date: $Date: 2010-06-07 13:39:13 +0200 (Mo, 07 Jun 2010) $ Version: $Revision: 68 $ Copyright (c) INRIA 2010. All rights reserved. See LICENSE.txt 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 _itk_TensorImageToDiffusionImageFilter_h_ #define _itk_TensorImageToDiffusionImageFilter_h_ #include "itkImageToImageFilter.h" #include #include namespace itk { template class TensorImageToDiffusionImageFilter : public ImageToImageFilter,3>, itk::VectorImage > { public: typedef TInputScalarType InputScalarType; typedef itk::DiffusionTensor3D InputPixelType; typedef itk::Image InputImageType; typedef typename InputImageType::RegionType InputImageRegionType; typedef TOutputScalarType OutputScalarType; typedef itk::VectorImage OutputImageType; typedef typename OutputImageType::PixelType OutputPixelType; typedef typename OutputImageType::RegionType OutputImageRegionType; typedef OutputScalarType BaselineScalarType; typedef BaselineScalarType BaselinePixelType; typedef typename itk::Image BaselineImageType; typedef typename BaselineImageType::RegionType BaselineImageRegionType; typedef itk::Image< short, 3> MaskImageType; typedef MaskImageType::RegionType MaskImageRegionType; typedef TensorImageToDiffusionImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; itkTypeMacro (TensorImageToDiffusionImageFilter, ImageToImageFilter); itkStaticConstMacro (ImageDimension, unsigned int, OutputImageType::ImageDimension); itkFactorylessNewMacro(Self) itkCloneMacro(Self) typedef vnl_vector_fixed GradientType; typedef VectorContainer GradientListType; - typedef GradientListType::Pointer GradientListPointerType; + typedef GradientListType::ConstPointer GradientListPointerType; /** Manually Set/Get a list of gradients */ void SetGradientList(const GradientListPointerType list) { m_GradientList = list; this->Modified(); } GradientListPointerType GetGradientList(void) const {return m_GradientList;} void SetBValue( const double& bval) { m_BValue = bval; } void SetMaskImage( MaskImageType::Pointer maskimage ) { m_MaskImage = maskimage; } /** * @brief Set an external baseline image for signal generation (optional) * * An option to enforce a specific baseline image. If none provided (default) the filter uses * the itk::TensorToL2NormImageFilter to generate the modelled baseline image. */ void SetExternalBaselineImage( typename BaselineImageType::Pointer bimage) { m_BaselineImage = bimage; } itkSetMacro(Min, OutputScalarType); itkSetMacro(Max, OutputScalarType); protected: TensorImageToDiffusionImageFilter() { m_BValue = 1.0; m_BaselineImage = 0; m_Min = 0.0; m_Max = 10000.0; } virtual ~TensorImageToDiffusionImageFilter(){} void PrintSelf (std::ostream& os, Indent indent) const override { Superclass::PrintSelf (os, indent); } virtual void BeforeThreadedGenerateData( void ) override; virtual void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType) override; //void GenerateData(); virtual void UpdateOutputInformation() override; private: TensorImageToDiffusionImageFilter (const Self&); void operator=(const Self&); - GradientListType::Pointer m_GradientList; + GradientListType::ConstPointer m_GradientList; double m_BValue; typename BaselineImageType::Pointer m_BaselineImage; OutputScalarType m_Min; OutputScalarType m_Max; MaskImageType::Pointer m_MaskImage; }; } // end of namespace #ifndef ITK_MANUAL_INSTANTIATION #include "itkTensorImageToDiffusionImageFilter.txx" #endif #endif diff --git a/Modules/DiffusionCore/Algorithms/itkTensorReconstructionWithEigenvalueCorrectionFilter.h b/Modules/DiffusionCore/Algorithms/itkTensorReconstructionWithEigenvalueCorrectionFilter.h index f6c9ded..318a58c 100644 --- a/Modules/DiffusionCore/Algorithms/itkTensorReconstructionWithEigenvalueCorrectionFilter.h +++ b/Modules/DiffusionCore/Algorithms/itkTensorReconstructionWithEigenvalueCorrectionFilter.h @@ -1,227 +1,227 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef _itk_TensorReconstructionWithEigenvalueCorrectionFilter_h_ #define _itk_TensorReconstructionWithEigenvalueCorrectionFilter_h_ #include "itkImageToImageFilter.h" #include #include #include #include namespace itk { template class TensorReconstructionWithEigenvalueCorrectionFilter : public ImageToImageFilter< itk::Image< TDiffusionPixelType, 3 >, itk::Image,3> > { public: typedef itk::VectorImage ImageType; typedef TensorReconstructionWithEigenvalueCorrectionFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< TDiffusionPixelType, 3>, Image< DiffusionTensor3D< TTensorPixelType >, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(TensorReconstructionWithEigenvalueCorrectionFilter, ImageToImageFilter) typedef typename itk::Image,3> OutputType; typedef TDiffusionPixelType GradientPixelType; typedef DiffusionTensor3D< TTensorPixelType > TensorPixelType; typedef Image< TensorPixelType, 3 > TensorImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; /** An alternative typedef defining one (of the many) gradient images. * It will be assumed that the vectorImage has the same dimension as the * Reference image and a vector length parameter of \c n (number of * gradient directions) */ typedef VectorImage< GradientPixelType, 3 > GradientImagesType; typedef typename GradientImagesType::PixelType GradientVectorType; /** Holds each magnetic field gradient used to acquire one DWImage */ typedef vnl_vector_fixed< double, 3 > GradientDirectionType; /** Container to hold gradient directions of the 'n' DW measurements */ typedef VectorContainer< unsigned int, GradientDirectionType > GradientDirectionContainerType; /** Another set method to add a gradient directions and its corresponding * image. The image here is a VectorImage. The user is expected to pass the * gradient directions in a container. The ith element of the container * corresponds to the gradient direction of the ith component image the * VectorImage. For the baseline image, a vector of all zeros * should be set. */ - void SetGradientImage( GradientDirectionContainerType *, + void SetGradientImage( GradientDirectionContainerType::ConstPointer, const GradientImagesType *image); itkSetMacro( BValue, TTensorPixelType) /** Set the b0 threshold */ itkSetMacro( B0Threshold, double) /** Get the pseudeInverse that was calculated in the process of tensor estimation */ itkGetMacro(PseudoInverse, vnl_matrix) /** FIXME: added by Sebastian Wirkert due to compile error otherwise. */ itkGetMacro(CorrectedDiffusionVolumes, ImageType::Pointer) /** Outputs the design matrix that was calculated in the process of tensor estimation */ itkGetMacro(H, vnl_matrix) /** Outputs the normalized b-vector */ itkGetMacro(BVec, vnl_vector) /** Outputs the mask created by thresholding the B0 weighted volume*/ itkGetMacro(B0Mask, vnl_vector) /** Returns the dwi image volumes with smoothed voxels on positions were there were negative eigenvalues in the tensir*/ ImageType::Pointer GetGradientImagePointer() { return m_GradientImagePointer; } /** Get the mask image*/ itk::Image::Pointer GetMask() { return m_MaskImage; } protected: TensorReconstructionWithEigenvalueCorrectionFilter(); ~TensorReconstructionWithEigenvalueCorrectionFilter() {} void GenerateData() override; typedef enum { GradientIsInASingleImage = 1, GradientIsInManyImages, Else } GradientImageTypeEnumeration; private: double CheckNeighbours(int x, int y, int z,int f, itk::Size<3> size, itk::Image ::Pointer mask,typename GradientImagesType::Pointer corrected_diffusion_temp); /** Calculates the attenuation for a voxel*/ void CalculateAttenuation(vnl_vector org_data, vnl_vector &atten,int nof,int numberb0); /** Correct the diffusion data set for voxels that contain negative eigenvalues in the tensor*/ void CorrectDiffusionImage(int nof,int numberb0,itk::Size<3> size,typename GradientImagesType::Pointer corrected_diffusion,itk::Image::Pointer mask,vnl_vector< double> pixel_max,vnl_vector< double> pixel_min); /** Calculte a tensor iamge from a diffusion data set*/ void GenerateTensorImage(int nof,int numberb0,itk::Size<3> size,itk::VectorImage::Pointer corrected_diffusion,itk::Image::Pointer mask,double what_mask, typename itk::Image< itk::DiffusionTensor3D, 3 >::Pointer tensorImg ); //void DeepCopyTensorImage(itk::Image< itk::DiffusionTensor3D, 3 >::Pointer tensorImg, itk::Image< itk::DiffusionTensor3D, 3 >::Pointer temp_tensorImg); //void DeepCopyDiffusionImage(itk::VectorImage::Pointer corrected_diffusion, itk::VectorImage::Pointer corrected_diffusion_temp,int nof); void TurnMask( itk::Size<3> size, itk::Image::Pointer mask, double previous_mask, double set_mask); double CheckNegatives ( itk::Size<3> size, itk::Image::Pointer mask, typename itk::Image< itk::DiffusionTensor3D, 3 >::Pointer tensorImg ); /** Gradient image was specified in a single image or in multiple images */ GradientImageTypeEnumeration m_GradientImageTypeEnumeration; /** Number of gradient measurements */ unsigned int m_NumberOfGradientDirections; /** container to hold gradient directions */ - GradientDirectionContainerType::Pointer m_GradientDirectionContainer; + GradientDirectionContainerType::ConstPointer m_GradientDirectionContainer; /** b-value */ TTensorPixelType m_BValue; /** Number of baseline images */ unsigned int m_NumberOfBaselineImages; ImageType::Pointer m_CorrectedDiffusionVolumes; double m_B0Threshold; /** decodes what is to be done with every single voxel */ itk::Image::Pointer m_MaskImage; /** Pseudoinverse calculated in the process of calculating a tensor */ vnl_matrix m_PseudoInverse; /** design matrix */ vnl_matrix m_H; /** normalized b-vector */ vnl_vector m_BVec; /** m_B0Mask indicates whether a volume identified by an index is B0-weighted or not */ vnl_vector m_B0Mask; /** volumes of the diffusion data set */ typename GradientImagesType::Pointer m_GradientImagePointer; }; } // end of namespace #ifndef ITK_MANUAL_INSTANTIATION #include "itkTensorReconstructionWithEigenvalueCorrectionFilter.txx" #endif #endif diff --git a/Modules/DiffusionCore/Algorithms/itkTensorReconstructionWithEigenvalueCorrectionFilter.txx b/Modules/DiffusionCore/Algorithms/itkTensorReconstructionWithEigenvalueCorrectionFilter.txx index 55ca97c..ac2a191 100644 --- a/Modules/DiffusionCore/Algorithms/itkTensorReconstructionWithEigenvalueCorrectionFilter.txx +++ b/Modules/DiffusionCore/Algorithms/itkTensorReconstructionWithEigenvalueCorrectionFilter.txx @@ -1,863 +1,863 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef _itk_TensorReconstructionWithEigenvalueCorrectionFilter_txx_ #define _itk_TensorReconstructionWithEigenvalueCorrectionFilter_txx_ #endif #include "itkImageRegionConstIterator.h" #include #include "itkImage.h" #include "itkImageRegionIterator.h" #include namespace itk { template TensorReconstructionWithEigenvalueCorrectionFilter ::TensorReconstructionWithEigenvalueCorrectionFilter() { m_B0Threshold = 50.0; } template void TensorReconstructionWithEigenvalueCorrectionFilter ::GenerateData () { typename GradientImagesType::Pointer input_image = static_cast< GradientImagesType * >( this->ProcessObject::GetInput(0) ); typename itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage(input_image); duplicator->Update(); m_GradientImagePointer = duplicator->GetOutput(); typename GradientImagesType::SizeType size = m_GradientImagePointer->GetLargestPossibleRegion().GetSize(); // number of volumes int nof = m_GradientDirectionContainer->Size(); // determine the number of b-zero values int numberb0=0; for(int i=0; i vec = m_GradientDirectionContainer->ElementAt(i); float bval = vec.magnitude(); bval = bval*bval*m_BValue; if(bval<100) numberb0++; } // Matrix to store all diffusion encoding gradients vnl_matrix directions(nof-numberb0,3); m_B0Mask.set_size(nof); int cnt=0; for(int i=0; i vec = m_GradientDirectionContainer->ElementAt(i); float bval = vec.magnitude(); bval = bval*bval*m_BValue; if(bval<100) { // the diffusion encoding gradient is approximately zero, wo we are dealing with a non-diffusion weighted volume m_B0Mask[i]=1; } else { // dealing with a diffusion weighted volume m_B0Mask[i]=0; // set the diffusion encoding gradient to the directions matrix directions[cnt][0] = vec[0]; directions[cnt][1] = vec[1]; directions[cnt][2] = vec[2]; cnt++; } } // looking for maximal norm among gradients. // The norm is calculated with use of spectral radius theorem- based on determination of eigenvalue. vnl_matrix dirsTimesDirsTrans = directions*directions.transpose(); vnl_vector< double> diagonal(nof-numberb0); vnl_vector< double> b_vec(nof-numberb0); vnl_vector< double> temporary(3); for (int i=0;i H(nof-numberb0, 6); vnl_matrix H_org(nof-numberb0, 6); vnl_vector pre_tensor(9); //H is matrix that contains covariances for directions. It is stored twice because its original value is needed later // while H is changed int etbt[6] = { 0, 4, 8, 1, 5, 2 };// tensor order for (int i = 0; i < nof-numberb0; i++) { for (int j = 0; j < 3; j++) { temporary[j] = -directions[i][j]; } for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { pre_tensor[k + 3 * j] = temporary[k] * directions[i][j]; } } for (int j = 0; j < 6; j++) { H[i][j] = pre_tensor[etbt[j]]; } for (int j = 0; j < 3; j++) { H[i][3 + j] *= 2.0; } } H_org=H; // calculation of inverse matrix by means of pseudoinverse vnl_matrix inputtopseudoinverse=H.transpose()*H; vnl_symmetric_eigensystem eig( inputtopseudoinverse); vnl_matrix pseudoInverse = eig.pinverse()*H.transpose(); typedef itk::Image MaskImageType; MaskImageType::Pointer mask = MaskImageType::New(); mask->SetRegions(m_GradientImagePointer->GetLargestPossibleRegion().GetSize()); mask->SetSpacing(m_GradientImagePointer->GetSpacing()); mask->SetOrigin(m_GradientImagePointer->GetOrigin()); mask->SetDirection( m_GradientImagePointer->GetDirection() ); // Set the image direction mask->SetLargestPossibleRegion( m_GradientImagePointer->GetLargestPossibleRegion() ); mask->SetBufferedRegion( m_GradientImagePointer->GetLargestPossibleRegion() ); mask->SetRequestedRegion( m_GradientImagePointer->GetLargestPossibleRegion() ); mask->Allocate(); // Image thresholding: For every voxel mean B0 image is calculated and then voxels of mean B0 less than the // treshold on the B0 image proviced by the userare excluded from the dataset with use of defined mask image. // 1 in mask voxel means that B0 > assumed treshold. int mask_cnt=0; #ifdef WIN32 #pragma omp parallel for #else #pragma omp parallel for collapse(3) #endif for(int x=0;x<(int)size[0];x++) for(int y=0;y<(int)size[1];y++) for(int z=0;z<(int)size[2];z++) { double mean_b=0.0; itk::Index<3> ix = {{(itk::IndexValueType)x,(itk::IndexValueType)y,(itk::IndexValueType)z}}; GradientVectorType pixel = m_GradientImagePointer->GetPixel(ix); for (int i=0;i m_B0Threshold) { #pragma omp critical { mask->SetPixel(ix, 1); mask_cnt++; } } else { #pragma omp critical mask->SetPixel(ix, 0); } } #ifdef WIN32 #pragma omp parallel for #else #pragma omp parallel for collapse(3) #endif for (int x=0;x<(int)size[0];x++) for (int y=0;y<(int)size[1];y++) for (int z=0;z<(int)size[2];z++) { vnl_vector org_vec(nof); itk::Index<3> ix = {{(itk::IndexValueType)x,(itk::IndexValueType)y,(itk::IndexValueType)z}}; double mask_val = mask->GetPixel(ix); GradientVectorType pixel2 = m_GradientImagePointer->GetPixel(ix); for (int i=0;i0) { for( int f=0;fSetPixel(ix, pixel2); } } typename TensorImageType::Pointer tensorImg; tensorImg = TensorImageType::New(); tensorImg->SetSpacing( m_GradientImagePointer->GetSpacing() ); // Set the image spacing tensorImg->SetOrigin( m_GradientImagePointer->GetOrigin() ); // Set the image origin tensorImg->SetDirection( m_GradientImagePointer->GetDirection() ); // Set the image direction tensorImg->SetLargestPossibleRegion( m_GradientImagePointer->GetLargestPossibleRegion() ); tensorImg->SetBufferedRegion( m_GradientImagePointer->GetLargestPossibleRegion() ); tensorImg->SetRequestedRegion( m_GradientImagePointer->GetLargestPossibleRegion() ); tensorImg->Allocate(); //Declaration of vectors that contains too high or too low atenuation for each gradient. Attenuation is only calculated for //non B0 images so nof-numberb0. vnl_vector< double> pixel_max(nof-numberb0); vnl_vector< double> pixel_min(nof-numberb0); // to high and to low attenuation is calculated with use of highest allowed =5 and lowest allowed =0.01 diffusion coefficient for (int i=0;i outputIterator(tensorImg, tensorImg->GetLargestPossibleRegion()); outputIterator.GoToBegin(); while(!outputIterator.IsAtEnd()) { TensorPixelType tens = outputIterator.Get(); tens/= 1000.0; outputIterator.Set(tens); ++outputIterator; } this->SetNthOutput(0, tensorImg); } template void TensorReconstructionWithEigenvalueCorrectionFilter -::SetGradientImage( GradientDirectionContainerType *gradientDirection, +::SetGradientImage( GradientDirectionContainerType::ConstPointer gradientDirection, const GradientImagesType *gradientImage ) { if( m_GradientImageTypeEnumeration == GradientIsInManyImages ) { itkExceptionMacro( << "Cannot call both methods:" << "AddGradientImage and SetGradientImage. Please call only one of them."); } this->m_GradientDirectionContainer = gradientDirection; unsigned int numImages = gradientDirection->Size(); this->m_NumberOfBaselineImages = 0; this->m_NumberOfGradientDirections = numImages - this->m_NumberOfBaselineImages; // ensure that the gradient image we received has as many components as // the number of gradient directions if( gradientImage->GetVectorLength() != this->m_NumberOfBaselineImages + this->m_NumberOfGradientDirections ) { itkExceptionMacro( << this->m_NumberOfGradientDirections << " gradients + " << this->m_NumberOfBaselineImages << "baselines = " << this->m_NumberOfGradientDirections + this->m_NumberOfBaselineImages << " directions specified but image has " << gradientImage->GetVectorLength() << " components."); } this->ProcessObject::SetNthInput( 0, const_cast< GradientImagesType* >(gradientImage) ); m_GradientImageTypeEnumeration = GradientIsInASingleImage; } template double TensorReconstructionWithEigenvalueCorrectionFilter ::CheckNeighbours(int x, int y, int z,int f, itk::Size<3> size, itk::Image::Pointer mask, typename GradientImagesType::Pointer corrected_diffusion_temp) { // method is used for finding a new value for the voxel with use of its 27 neighborhood. To perform such a smoothing correct voxels are // counted an arithmetical mean is calculated and stored as a new value for the voxel. If there is no proper neigborhood voxel is turned // to the value of 0. // Definition of neighbourhood avoiding crossing the image boundaries int x_max=size[0]-1; int y_max=size[1]-1; int z_max=size[2]-1; double back_x=std::max(0,x-1); double back_y=std::max(0,y-1); double back_z=std::max(0,z-1); double forth_x=std::min((x+1),x_max); double forth_y=std::min((y+1),y_max); double forth_z=std::min((z+1),z_max); double tempsum=0; double temp_number=0; for(int i=back_x; i<=forth_x; i++) { for (int j=back_y; j<=forth_y; j++) { for (int k=back_z; k<=forth_z; k++) { itk::Index<3> ix = {{i,j,k}}; GradientVectorType p = corrected_diffusion_temp->GetPixel(ix); if (p[f] > 0.0 )// taking only positive values and counting them { if(!(i==x && j==y && k== z)) { tempsum=tempsum+p[f]; temp_number++; } } } } } //getting back to the original position of the voxel itk::Index<3> ix = {{x,y,z}}; if (temp_number <= 0.0) { tempsum=0; #pragma omp critical mask->SetPixel(ix,0); } else { tempsum=tempsum/temp_number; } return tempsum;// smoothed value of voxel } template void TensorReconstructionWithEigenvalueCorrectionFilter ::CalculateAttenuation(vnl_vector org_data,vnl_vector &atten,int nof, int numberb0) { double mean_b=0.0; for (int i=0;i0) mean_b=mean_b+org_data[i]; mean_b=mean_b/numberb0; int cnt=0; for (int i=0;i double TensorReconstructionWithEigenvalueCorrectionFilter ::CheckNegatives ( itk::Size<3> size, itk::Image::Pointer mask, typename itk::Image< itk::DiffusionTensor3D, 3 >::Pointer tensorImg ) { // The method was created to simplif the flow of negative eigenvalue correction process. The method itself just return the number // of voxels (tensors) with negative eigenvalues. Then if the voxel was previously bad ( mask=2 ) but it is not bad anymore mask is //changed to 1. // declaration of important structures and variables double badvoxels=0; #ifdef WIN32 #pragma omp parallel for #else #pragma omp parallel for collapse(3) #endif for (int x=0;x<(int)size[0];x++) for (int y=0;y<(int)size[1];y++) for (int z=0;z<(int)size[2];z++) { double pixel=0; itk::Index<3> ix = {{(itk::IndexValueType)x,(itk::IndexValueType)y,(itk::IndexValueType)z}}; pixel = mask->GetPixel(ix); // but only if previously marked as bad one-negative eigen value if(pixel > 1) { #pragma omp critical { itk::DiffusionTensor3D::EigenValuesArrayType eigenvalues; itk::DiffusionTensor3D::EigenVectorsMatrixType eigenvectors; itk::DiffusionTensor3D ten = tensorImg->GetPixel(ix); ten.ComputeEigenAnalysis(eigenvalues, eigenvectors); //comparison to 0.01 instead of 0 was proposed by O.Pasternak if( eigenvalues[0]>0.01 && eigenvalues[1]>0.01 && eigenvalues[2]>0.01) mask->SetPixel(ix,1); else badvoxels++; } } } return badvoxels; } template void TensorReconstructionWithEigenvalueCorrectionFilter ::CorrectDiffusionImage(int nof, int numberb0, itk::Size<3> size, typename GradientImagesType::Pointer corrected_diffusion,itk::Image::Pointer mask,vnl_vector< double> pixel_max,vnl_vector< double> pixel_min) { // in this method the voxels that has tensor negative eigenvalues are smoothed. Smoothing is done on DWI image.For the voxel //detected as bad one, B0 image is smoothed obligatory. All other gradient images are smoothed only when value of attenuation //is out of declared bounds for too high or too low attenuation. // declaration of important variables #ifdef WIN32 #pragma omp parallel for #else #pragma omp parallel for collapse(3) #endif for (int z=0;z<(int)size[2];z++) for (int x=0;x<(int)size[0];x++) for (int y=0;y<(int)size[1];y++) { vnl_vector org_data(nof); vnl_vector atten(nof-numberb0); double cnt_atten=0; itk::Index<3> ix = {{(itk::IndexValueType)x, (itk::IndexValueType)y, (itk::IndexValueType)z}}; if(mask->GetPixel(ix) > 1.0) { GradientVectorType pt = corrected_diffusion->GetPixel(ix); for (int i=0;i0) { mean_b=mean_b+org_data[i]; } mean_b=mean_b/numberb0; int cnt=0; for (int i=0;i pixel_max[cnt_atten]) { int x_max=size[0]-1; int y_max=size[1]-1; int z_max=size[2]-1; double back_x=std::max(0,(int)x-1); double back_y=std::max(0,(int)y-1); double back_z=std::max(0,(int)z-1); double forth_x=std::min(((int)x+1),x_max); double forth_y=std::min(((int)y+1),y_max); double forth_z=std::min(((int)z+1),z_max); double tempsum=0; double temp_number=0; for(int i=back_x; i<=forth_x; i++) for (int j=back_y; j<=forth_y; j++) for (int k=back_z; k<=forth_z; k++) { itk::Index<3> ix = {{i,j,k}}; GradientVectorType p = corrected_diffusion->GetPixel(ix); if(p[f] > 0.0 && !(i==x && j==y && k== z)) { tempsum=tempsum+p[f]; temp_number++; } } //getting back to the original position of the voxel itk::Index<3> ix = {{(itk::IndexValueType)x,(itk::IndexValueType)y,(itk::IndexValueType)z}}; if (temp_number <= 0.0) { tempsum=0; #pragma omp critical mask->SetPixel(ix,0); } else tempsum=tempsum/temp_number; org_data[f] = tempsum; } cnt_atten++; } //smoothing B0 if(m_B0Mask[f]==1) { int x_max=size[0] - 1; int y_max=size[1] - 1; int z_max=size[2] - 1; double back_x=std::max(0,(int)x-1); double back_y=std::max(0,(int)y-1); double back_z=std::max(0,(int)z-1); double forth_x=std::min(((int)x+1),x_max); double forth_y=std::min(((int)y+1),y_max); double forth_z=std::min(((int)z+1),z_max); double tempsum=0; double temp_number=0; for(int i=back_x; i<=forth_x; i++) for (int j=back_y; j<=forth_y; j++) for (int k=back_z; k<=forth_z; k++) { itk::Index<3> ix = {{i,j,k}}; GradientVectorType p = corrected_diffusion->GetPixel(ix); //double test= p[f]; if (p[f] > 0.0 )// taking only positive values and counting them { if(!(i==x && j==y && k== z)) { tempsum=tempsum+p[f]; temp_number++; } } } //getting back to the original position of the voxel itk::Index<3> ix = {{(itk::IndexValueType)x,(itk::IndexValueType)y,(itk::IndexValueType)z}}; if (temp_number <= 0.0) { tempsum=0; #pragma omp critical mask->SetPixel(ix,0); } else { tempsum=tempsum/temp_number; } org_data[f] = tempsum; } } for (int i=0;iSetPixel(ix, pt); } else { GradientVectorType pt = corrected_diffusion->GetPixel(ix); #pragma omp critical corrected_diffusion->SetPixel(ix, pt); } } } template void TensorReconstructionWithEigenvalueCorrectionFilter ::GenerateTensorImage(int nof,int numberb0,itk::Size<3> size,itk::VectorImage::Pointer corrected_diffusion,itk::Image::Pointer mask,double , typename itk::Image< itk::DiffusionTensor3D, 3 >::Pointer tensorImg) { // in this method the whole tensor image is updated with a tensors for defined voxels ( defined by a value of mask); #ifdef WIN32 #pragma omp parallel for #else #pragma omp parallel for collapse(3) #endif for (int x=0;x<(int)size[0];x++) for (int y=0;y<(int)size[1];y++) for (int z=0;z<(int)size[2];z++) { itk::Index<3> ix; vnl_vector org_data(nof); vnl_vector atten(nof-numberb0); vnl_vector tensor(6); itk::DiffusionTensor3D ten; double mask_val=0; ix[0] = x; ix[1] = y; ix[2] = z; mask_val= mask->GetPixel(ix); //Tensors are calculated only for voxels above theshold for B0 image. if( mask_val > 0.0 ) { // calculation of attenuation with use of gradient image and and mean B0 image GradientVectorType pt = corrected_diffusion->GetPixel(ix); for (int i=0;i0) { mean_b=mean_b+org_data[i]; } } mean_b=mean_b/numberb0; int cnt=0; for (int i=0;iSetPixel(ix, ten); } // for voxels with mask value 0 - tensor is simply 0 ( outside brain value) else if (mask_val < 1.0) { ten(0,0) = 0; ten(0,1) = 0; ten(0,2) = 0; ten(1,1) = 0; ten(1,2) = 0; ten(2,2) = 0; #pragma omp critical tensorImg->SetPixel(ix, ten); } } }// end of Generate Tensor template void TensorReconstructionWithEigenvalueCorrectionFilter ::TurnMask( itk::Size<3> size, itk::Image::Pointer mask, double previous_mask, double set_mask) { // The method changes voxels in the mask that poses a certain value with other value. itk::Index<3> ix; double temp_mask_value=0; #ifdef WIN32 #pragma omp parallel for #else #pragma omp parallel for collapse(3) #endif for(int x=0;x<(int)size[0];x++) for(int y=0;y<(int)size[1];y++) for(int z=0;z<(int)size[2];z++) { ix[0] = x; ix[1] = y; ix[2] = z; temp_mask_value=mask->GetPixel(ix); if(temp_mask_value>previous_mask) { #pragma omp critical mask->SetPixel(ix,set_mask); } } } } // end of namespace diff --git a/Modules/DiffusionCore/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCorrectionFilter.cpp b/Modules/DiffusionCore/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCorrectionFilter.cpp index a3045dc..5652c32 100644 --- a/Modules/DiffusionCore/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCorrectionFilter.cpp +++ b/Modules/DiffusionCore/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCorrectionFilter.cpp @@ -1,117 +1,117 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef MITKDIFFUSIONIMAGECORRECTIONFILTER_CPP #define MITKDIFFUSIONIMAGECORRECTIONFILTER_CPP #include "mitkDiffusionImageCorrectionFilter.h" #include #include #include typedef mitk::DiffusionPropertyHelper DPH; mitk::DiffusionImageCorrectionFilter::DiffusionImageCorrectionFilter() { } mitk::DiffusionImageCorrectionFilter::TransformMatrixType mitk::DiffusionImageCorrectionFilter ::GetRotationComponent(const TransformMatrixType &A) { TransformMatrixType B; B = A * A.transpose(); // get the eigenvalues and eigenvectors typedef double MType; vnl_vector< MType > eigvals; vnl_matrix< MType > eigvecs; vnl_symmetric_eigensystem_compute< MType > ( B, eigvecs, eigvals ); vnl_matrix_fixed< MType, 3, 3 > eigvecs_fixed; eigvecs_fixed.set_columns(0, eigvecs ); TransformMatrixType C; C.set_identity(); vnl_vector_fixed< MType, 3 > eigvals_sqrt; for(unsigned int i=0; i<3; i++) { C(i,i) = std::sqrt( eigvals[i] ); } TransformMatrixType S = vnl_inverse( eigvecs_fixed * C * vnl_inverse( eigvecs_fixed )) * A; return S; } void mitk::DiffusionImageCorrectionFilter ::CorrectDirections( const TransformsVectorType& transformations) { if( m_SourceImage.IsNull() ) { mitkThrow() << " No diffusion image given! "; } - DPH::GradientDirectionsContainerType::Pointer directions = DPH::GetGradientContainer(m_SourceImage); + DPH::GradientDirectionsContainerType::ConstPointer directions = DPH::GetGradientContainer(m_SourceImage); DPH::GradientDirectionsContainerType::Pointer corrected_directions = DPH::GradientDirectionsContainerType::New(); mitk::BValueMapProperty::BValueMap bval_map = DPH::GetBValueMap(m_SourceImage); size_t first_unweighted_index = bval_map.begin()->second.front(); unsigned int transformed = 0; for(size_t i=0; i< directions->Size(); i++ ) { // skip b-zero images if(i==first_unweighted_index) { corrected_directions->push_back(directions->ElementAt(i)); continue; } auto corrected = GetRotationComponent(transformations.at(transformed)) * directions->ElementAt(i); // store the corrected direction corrected_directions->push_back(corrected); transformed++; } // replace the old directions with the corrected ones DPH::SetGradientContainer(m_SourceImage, corrected_directions); } void mitk::DiffusionImageCorrectionFilter::CorrectDirections( const TransformMatrixType& transformation) { if( m_SourceImage.IsNull() ) { mitkThrow() << " No diffusion image given! "; } TransformsVectorType transfVec; for (unsigned int i=0; i< DPH::GetGradientContainer(m_SourceImage)->Size();i++) { transfVec.push_back(transformation); } this->CorrectDirections(transfVec); } #endif diff --git a/Modules/DiffusionCore/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.cpp b/Modules/DiffusionCore/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.cpp index 38858f8..742570d 100644 --- a/Modules/DiffusionCore/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.cpp +++ b/Modules/DiffusionCore/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.cpp @@ -1,218 +1,218 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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 "mitkDiffusionImageCreationFilter.h" #include "mitkProperties.h" #include "mitkImageTimeSelector.h" #include "mitkImageCast.h" #include "mitkImageToItk.h" #include "mitkImageAccessByItk.h" #include "mitkITKImageImport.h" #include "mitkIOUtil.h" #include /** * @brief RemapIntoVectorImage Take a 3d+t image and reinterpret it as vector image * @return vectoriamge */ mitk::DiffusionImageCreationFilter::VectorImageType::Pointer mitk::DiffusionImageCreationFilter::RemapIntoVectorImage( mitk::Image::Pointer input) { typedef itk::Image ImageVolumeType; typedef itk::ComposeImageFilter< ImageVolumeType > ComposeFilterType; ComposeFilterType::Pointer vec_composer = ComposeFilterType::New(); mitk::ImageTimeSelector::Pointer t_selector = mitk::ImageTimeSelector::New(); t_selector->SetInput( input ); for( unsigned int i=0; i< input->GetTimeSteps(); i++) { t_selector->SetTimeNr(i); t_selector->Update(); ImageVolumeType::Pointer singleImageItk; mitk::CastToItkImage( t_selector->GetOutput(), singleImageItk ); vec_composer->SetInput( i, singleImageItk ); } try { vec_composer->Update(); } catch( const itk::ExceptionObject& e) { MITK_ERROR << "Caught exception while updating compose filter: " << e.what(); } mitk::DiffusionImageCreationFilter::VectorImageType::Pointer vector_image = vec_composer->GetOutput(); vector_image->GetPixelContainer()->ContainerManageMemoryOff(); return vector_image; } mitk::DiffusionImageCreationFilter::DiffusionImageCreationFilter() : m_ReferenceImage( nullptr ) { m_HeaderDescriptorSet = false; this->SetNumberOfRequiredInputs(1); this->SetNumberOfRequiredOutputs(1); } mitk::DiffusionImageCreationFilter::~DiffusionImageCreationFilter() { } void mitk::DiffusionImageCreationFilter::SetReferenceImage( mitk::Image::Pointer reference_image ) { if( reference_image.IsNull() ) { mitkThrow() << "Null-pointer image provided as reference. "; } if( ! DPH::IsDiffusionWeightedImage(reference_image) ) { mitkThrow() << "The image provided as reference is not a diffusion-weighted image. Cannot proceed. "; } this->m_ReferenceImage = reference_image; } void mitk::DiffusionImageCreationFilter::GenerateData() { const mitk::Image::Pointer input_image = this->GetInput(0); if( input_image.IsNull() ) { mitkThrow() << "No input specified. Cannot proceed "; } if( !( m_HeaderDescriptorSet ^ m_ReferenceImage.IsNotNull() ) ) { mitkThrow() << "Either a header descriptor or a reference diffusion-weighted image have to be provided. Terminating."; } mitk::Image::Pointer outputForCache = this->GetOutput(); if( input_image->GetTimeSteps() > 1 ) { mitk::Image::Pointer mitkvectorimage = mitk::GrabItkImageMemory( RemapIntoVectorImage( input_image )); outputForCache->Initialize( mitkvectorimage ); } // no need to remap, we expect to have a vector image directly else { outputForCache->Initialize( input_image ); } // header information - GradientDirectionContainerType::Pointer DiffusionVectors = this->InternalGetGradientDirections( ); + GradientDirectionContainerType::ConstPointer DiffusionVectors = this->InternalGetGradientDirections( ); MeasurementFrameType MeasurementFrame = this->InternalGetMeasurementFrame(); float BValue = this->InternalGetBValue(); // create BValueMap mitk::BValueMapProperty::BValueMap BValueMap = mitk::BValueMapProperty::CreateBValueMap( DiffusionVectors, BValue ); DPH::SetGradientContainer(outputForCache, DiffusionVectors); DPH::SetMeasurementFrame(outputForCache, MeasurementFrame); DPH::SetBValueMap(outputForCache, BValueMap); DPH::SetReferenceBValue(outputForCache, BValue); outputForCache->Modified(); } void mitk::DiffusionImageCreationFilter::SetHeaderDescriptor(DiffusionImageHeaderDescriptor header_descriptor) { this->m_HeaderDescriptor = header_descriptor; this->m_HeaderDescriptorSet = true; } mitk::DiffusionImageCreationFilter::MeasurementFrameType mitk::DiffusionImageCreationFilter::InternalGetMeasurementFrame() { MeasurementFrameType MeasurementFrame; if( m_ReferenceImage.IsNotNull() ) { MeasurementFrame = DPH::GetMeasurementFrame( m_ReferenceImage ); } else if ( m_HeaderDescriptorSet ) { MeasurementFrame = m_HeaderDescriptor.m_MeasurementFrame; } else { MeasurementFrame(0,0) = 1; MeasurementFrame(0,1) = 0; MeasurementFrame(0,2) = 0; MeasurementFrame(1,0) = 0; MeasurementFrame(1,1) = 1; MeasurementFrame(1,2) = 0; MeasurementFrame(2,0) = 0; MeasurementFrame(2,1) = 0; MeasurementFrame(2,2) = 1; MITK_WARN << "Created default measurement frame as non provided ( no reference image or header information provided)"; } return MeasurementFrame; } -mitk::DiffusionImageCreationFilter::GradientDirectionContainerType::Pointer +mitk::DiffusionImageCreationFilter::GradientDirectionContainerType::ConstPointer mitk::DiffusionImageCreationFilter::InternalGetGradientDirections() { - GradientDirectionContainerType::Pointer DiffusionVectors = GradientDirectionContainerType::New(); + GradientDirectionContainerType::ConstPointer DiffusionVectors; if( this->m_ReferenceImage ) { DiffusionVectors = DPH::GetGradientContainer( this->m_ReferenceImage ); } else if ( m_HeaderDescriptorSet ) { DiffusionVectors = m_HeaderDescriptor.m_GradientDirections; } return DiffusionVectors; } float mitk::DiffusionImageCreationFilter::InternalGetBValue() { float bvalue = -1; if( m_ReferenceImage.IsNotNull() ) { bvalue = DPH::GetReferenceBValue( m_ReferenceImage ); } else if ( m_HeaderDescriptorSet ) { bvalue = m_HeaderDescriptor.m_BValue; } else { MITK_ERROR << "No reference image and no header descriptor provided."; } return bvalue; } diff --git a/Modules/DiffusionCore/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.h b/Modules/DiffusionCore/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.h index 0881885..c4466ce 100644 --- a/Modules/DiffusionCore/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.h +++ b/Modules/DiffusionCore/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.h @@ -1,106 +1,106 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef DIFFUSIONIMAGECREATIONFILTER_H #define DIFFUSIONIMAGECREATIONFILTER_H #include "mitkImageToImageFilter.h" #include "mitkDiffusionPropertyHelper.h" #include namespace mitk { /** * @brief The DiffusionImageHeaderDescriptor struct bundles the necessary diffusion-weighted image header meta information. */ struct MITKDIFFUSIONCORE_EXPORT DiffusionImageHeaderDescriptor { DiffusionImageHeaderDescriptor() : m_GradientDirections(nullptr) { m_BValue = -1; } float m_BValue; mitk::DiffusionPropertyHelper::BValueMapType m_BValueMapType; mitk::DiffusionPropertyHelper::MeasurementFrameType m_MeasurementFrame; mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer m_GradientDirections; }; /** * @brief The DiffusionImageCreationFilter class creates a diffusion-weighted image out of a * given 3D+t regular image and sufficient additional information about gradient directions and b values * * For easier use, the filter supports the usage of reference images. Here a diffusion-weighted (dw) image is expected and the meta * information of this image will be used for the output dw image. The diffusion information can also be specified by setting the HeaderDescriptor * directly (SetHeaderDescriptor). * * At least one of reference image or descriptor must be used, otherwise an exception is thrown. */ class MITKDIFFUSIONCORE_EXPORT DiffusionImageCreationFilter : public ImageToImageFilter { public: /** class macros */ mitkClassMacro( DiffusionImageCreationFilter, ImageToImageFilter ) itkNewMacro(Self) typedef short DiffusionPixelType; typedef mitk::DiffusionPropertyHelper DPH; typedef mitk::Image OutputType; typedef mitk::DiffusionPropertyHelper::ImageType VectorImageType; typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::MeasurementFrameType MeasurementFrameType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientDirectionContainerType; /** * @brief SetReferenceImage Set a diffusion image as reference, i.e. the header information will be extracted from it * @param reference_image A reference diffusion-weigted image - will throw exception of the input is not DW image */ void SetReferenceImage( mitk::Image::Pointer reference_image ); /** * @brief SetHeaderDescriptor set the information to be used with the dw image * @param header_descriptor * * \sa DiffusionImageHeaderDescriptor */ void SetHeaderDescriptor( DiffusionImageHeaderDescriptor header_descriptor ); void GenerateData() override; protected: DiffusionImageCreationFilter(); ~DiffusionImageCreationFilter() override; - GradientDirectionContainerType::Pointer InternalGetGradientDirections( ); + GradientDirectionContainerType::ConstPointer InternalGetGradientDirections( ); MeasurementFrameType InternalGetMeasurementFrame(); float InternalGetBValue(); VectorImageType::Pointer RemapIntoVectorImage( mitk::Image::Pointer input); mitk::Image::Pointer m_ReferenceImage; DiffusionImageHeaderDescriptor m_HeaderDescriptor; bool m_HeaderDescriptorSet; }; } //end namespace mitk #endif // DIFFUSIONIMAGECREATIONFILTER_H diff --git a/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.cpp b/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.cpp index d2c8b59..e37a51a 100644 --- a/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.cpp +++ b/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.cpp @@ -1,624 +1,633 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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 "mitkDiffusionPropertyHelper.h" #include #include #include #include #include #include #include #include #include #include const std::string mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME = "DWMRI.GradientDirections"; const std::string mitk::DiffusionPropertyHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME = "DWMRI.OriginalGradientDirections"; const std::string mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME = "DWMRI.MeasurementFrame"; const std::string mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME = "DWMRI.ReferenceBValue"; const std::string mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME = "DWMRI.BValueMap"; const std::string mitk::DiffusionPropertyHelper::MODALITY = "DWMRI.Modality"; const std::string mitk::DiffusionPropertyHelper::APPLY_MATRIX_TO_GRADIENTS = "DWMRI.ApplyMatrixToGradients"; const std::string mitk::DiffusionPropertyHelper::APPLY_MF_TO_GRADIENTS = "DWMRI.ApplyMfToGradients"; mitk::DiffusionPropertyHelper::DiffusionPropertyHelper() { } mitk::DiffusionPropertyHelper::~DiffusionPropertyHelper() { } mitk::DiffusionPropertyHelper::ImageType::Pointer mitk::DiffusionPropertyHelper::GetItkVectorImage(mitk::Image* image) { ImageType::Pointer vectorImage = ImageType::New(); mitk::CastToItkImage(image, vectorImage); return vectorImage; } mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer -mitk::DiffusionPropertyHelper::CalcAveragedDirectionSet(double precision, GradientDirectionsContainerType::Pointer directions) +mitk::DiffusionPropertyHelper::CalcAveragedDirectionSet(double precision, GradientDirectionsContainerType::ConstPointer directions) { // save old and construct new direction container GradientDirectionsContainerType::Pointer newDirections = GradientDirectionsContainerType::New(); // fill new direction container for(GradientDirectionsContainerType::ConstIterator gdcitOld = directions->Begin(); gdcitOld != directions->End(); ++gdcitOld) { // already exists? bool found = false; for(GradientDirectionsContainerType::ConstIterator gdcitNew = newDirections->Begin(); gdcitNew != newDirections->End(); ++gdcitNew) { if(AreAlike(gdcitNew.Value(), gdcitOld.Value(), precision)) { found = true; break; } } // if not found, add it to new container if(!found) { newDirections->push_back(gdcitOld.Value()); } } return newDirections; } void mitk::DiffusionPropertyHelper::AverageRedundantGradients(mitk::Image* image, double precision) { - GradientDirectionsContainerType::Pointer oldDirs = GetOriginalGradientContainer(image); + GradientDirectionsContainerType::ConstPointer oldDirs = GetOriginalGradientContainer(image); GradientDirectionsContainerType::Pointer newDirs = CalcAveragedDirectionSet(precision, oldDirs); // if sizes equal, we do not need to do anything in this function if(oldDirs->size() == newDirs->size()) return; // new image ImageType::Pointer oldImage = ImageType::New(); mitk::CastToItkImage( image, oldImage); ImageType::Pointer newITKImage = ImageType::New(); newITKImage->SetSpacing( oldImage->GetSpacing() ); // Set the image spacing newITKImage->SetOrigin( oldImage->GetOrigin() ); // Set the image origin newITKImage->SetDirection( oldImage->GetDirection() ); // Set the image direction newITKImage->SetLargestPossibleRegion( oldImage->GetLargestPossibleRegion() ); newITKImage->SetVectorLength( newDirs->size() ); newITKImage->SetBufferedRegion( oldImage->GetLargestPossibleRegion() ); newITKImage->Allocate(); // average image data that corresponds to identical directions itk::ImageRegionIterator< ImageType > newIt(newITKImage, newITKImage->GetLargestPossibleRegion()); newIt.GoToBegin(); itk::ImageRegionIterator< ImageType > oldIt(oldImage, oldImage->GetLargestPossibleRegion()); oldIt.GoToBegin(); // initial new value of voxel ImageType::PixelType newVec; newVec.SetSize(newDirs->size()); newVec.AllocateElements(newDirs->size()); // find which gradients should be averaged - GradientDirectionsContainerType::Pointer oldDirections = oldDirs; std::vector > dirIndices; for(GradientDirectionsContainerType::ConstIterator gdcitNew = newDirs->Begin(); gdcitNew != newDirs->End(); ++gdcitNew) { dirIndices.push_back(std::vector(0)); for(GradientDirectionsContainerType::ConstIterator gdcitOld = oldDirs->Begin(); - gdcitOld != oldDirections->End(); ++gdcitOld) + gdcitOld != oldDirs->End(); ++gdcitOld) { if(AreAlike(gdcitNew.Value(), gdcitOld.Value(), precision)) { //MITK_INFO << gdcitNew.Value() << " " << gdcitOld.Value(); dirIndices[gdcitNew.Index()].push_back(gdcitOld.Index()); } } } //int ind1 = -1; while(!newIt.IsAtEnd()) { // init new vector with zeros newVec.Fill(0.0); // the old voxel value with duplicates ImageType::PixelType oldVec = oldIt.Get(); for(unsigned int i=0; iGetProperty(mitk::DiffusionPropertyHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str()).IsNull() ) { return; } - GradientDirectionsContainerType::Pointer originalDirections = GetOriginalGradientContainer(image); + GradientDirectionsContainerType::ConstPointer originalDirections = GetOriginalGradientContainer(image); MeasurementFrameType measurementFrame = GetMeasurementFrame(image); mitk::Vector3D s = image->GetGeometry()->GetSpacing(); mitk::VnlVector c0 = image->GetGeometry()->GetMatrixColumn(0)/s[0]; mitk::VnlVector c1 = image->GetGeometry()->GetMatrixColumn(1)/s[1]; mitk::VnlVector c2 = image->GetGeometry()->GetMatrixColumn(2)/s[2]; MeasurementFrameType imageRotationMatrix; imageRotationMatrix[0][0] = c0[0]; imageRotationMatrix[1][0] = c0[1]; imageRotationMatrix[2][0] = c0[2]; imageRotationMatrix[0][1] = c1[0]; imageRotationMatrix[1][1] = c1[1]; imageRotationMatrix[2][1] = c1[2]; imageRotationMatrix[0][2] = c2[0]; imageRotationMatrix[1][2] = c2[1]; imageRotationMatrix[2][2] = c2[2]; GradientDirectionsContainerType::Pointer directions = GradientDirectionsContainerType::New(); if( originalDirections.IsNull() || ( originalDirections->size() == 0 ) ) { // original direction container was not set return; } bool apply_matrix = true; image->GetPropertyList()->GetBoolProperty(mitk::DiffusionPropertyHelper::APPLY_MATRIX_TO_GRADIENTS.c_str(), apply_matrix); bool apply_mf = true; image->GetPropertyList()->GetBoolProperty(mitk::DiffusionPropertyHelper::APPLY_MF_TO_GRADIENTS.c_str(), apply_mf); if (apply_matrix) { MITK_INFO << "Applying image rotation to diffusion-gradient directions:"; std::cout << imageRotationMatrix << std::endl; } if (apply_mf) { MITK_INFO << "Applying measurement frame to diffusion-gradient directions:"; std::cout << measurementFrame << std::endl; } int c = 0; for(GradientDirectionsContainerType::ConstIterator gdcit = originalDirections->Begin(); gdcit != originalDirections->End(); ++gdcit) { vnl_vector vec = gdcit.Value(); if (apply_matrix) vec = vec.pre_multiply(measurementFrame); if (apply_mf) vec = vec.pre_multiply(imageRotationMatrix); directions->InsertElement(c, vec); c++; } SetGradientContainer(image, directions); } void mitk::DiffusionPropertyHelper::UnApplyMeasurementFrameAndRotationMatrix(mitk::Image* image) { if( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).IsNull() ) { return; } - GradientDirectionsContainerType::Pointer modifiedDirections = GetGradientContainer(image); + GradientDirectionsContainerType::ConstPointer modifiedDirections = GetGradientContainer(image); MeasurementFrameType measurementFrame = GetMeasurementFrame(image); measurementFrame = vnl_matrix_inverse(measurementFrame).pinverse(); mitk::Vector3D s = image->GetGeometry()->GetSpacing(); mitk::VnlVector c0 = image->GetGeometry()->GetMatrixColumn(0)/s[0]; mitk::VnlVector c1 = image->GetGeometry()->GetMatrixColumn(1)/s[1]; mitk::VnlVector c2 = image->GetGeometry()->GetMatrixColumn(2)/s[2]; MeasurementFrameType imageRotationMatrix; imageRotationMatrix[0][0] = c0[0]; imageRotationMatrix[1][0] = c0[1]; imageRotationMatrix[2][0] = c0[2]; imageRotationMatrix[0][1] = c1[0]; imageRotationMatrix[1][1] = c1[1]; imageRotationMatrix[2][1] = c1[2]; imageRotationMatrix[0][2] = c2[0]; imageRotationMatrix[1][2] = c2[1]; imageRotationMatrix[2][2] = c2[2]; imageRotationMatrix = vnl_matrix_inverse(imageRotationMatrix).pinverse(); GradientDirectionsContainerType::Pointer directions = GradientDirectionsContainerType::New(); if( modifiedDirections.IsNull() || ( modifiedDirections->size() == 0 ) ) { // original direction container was not set return; } bool apply_matrix = true; image->GetPropertyList()->GetBoolProperty(mitk::DiffusionPropertyHelper::APPLY_MATRIX_TO_GRADIENTS.c_str(), apply_matrix); bool apply_mf = true; image->GetPropertyList()->GetBoolProperty(mitk::DiffusionPropertyHelper::APPLY_MF_TO_GRADIENTS.c_str(), apply_mf); if (apply_matrix) { MITK_INFO << "Reverting image rotation to diffusion-gradient directions:"; std::cout << imageRotationMatrix << std::endl; } if (apply_mf) { MITK_INFO << "Reverting measurement frame to diffusion-gradient directions:"; std::cout << measurementFrame << std::endl; } int c = 0; for(GradientDirectionsContainerType::ConstIterator gdcit = modifiedDirections->Begin(); gdcit != modifiedDirections->End(); ++gdcit) { vnl_vector vec = gdcit.Value(); if (apply_matrix) vec = vec.pre_multiply(imageRotationMatrix); if (apply_mf) vec = vec.pre_multiply(measurementFrame); directions->InsertElement(c, vec); c++; } SetOriginalGradientContainer(image, directions); } void mitk::DiffusionPropertyHelper::SetApplyMatrixToGradients(mitk::Image* image, bool apply) { image->GetPropertyList()->SetProperty( mitk::DiffusionPropertyHelper::APPLY_MATRIX_TO_GRADIENTS.c_str(), mitk::BoolProperty::New(apply) ); } void mitk::DiffusionPropertyHelper::SetApplyMfToGradients(mitk::Image* image, bool apply) { image->GetPropertyList()->SetProperty( mitk::DiffusionPropertyHelper::APPLY_MF_TO_GRADIENTS.c_str(), mitk::BoolProperty::New(apply) ); } void mitk::DiffusionPropertyHelper::UpdateBValueMap(mitk::Image* image) { BValueMapType b_ValueMap; if(image->GetProperty(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str()).IsNotNull()) b_ValueMap = GetBValueMap(image); if(!b_ValueMap.empty()) b_ValueMap.clear(); if(GetGradientContainer(image).IsNotNull()) { - GradientDirectionsContainerType::Pointer directions = GetGradientContainer(image); + GradientDirectionsContainerType::ConstPointer directions = GetGradientContainer(image); for(auto gdcit = directions->Begin(); gdcit!=directions->End(); ++gdcit) { b_ValueMap[GetB_Value(image, gdcit.Index())].push_back(gdcit.Index()); } } SetBValueMap(image, b_ValueMap); } bool mitk::DiffusionPropertyHelper::AreAlike(GradientDirectionType g1, GradientDirectionType g2, double precision) { GradientDirectionType diff = g1 - g2; GradientDirectionType diff2 = g1 + g2; return diff.two_norm() < precision || diff2.two_norm() < precision; } float mitk::DiffusionPropertyHelper::GetB_Value(const mitk::Image* image, unsigned int i) { - GradientDirectionsContainerType::Pointer directions = GetGradientContainer(image); + GradientDirectionsContainerType::ConstPointer directions = GetGradientContainer(image); float b_value = GetReferenceBValue(image); if(i > directions->Size()-1) return -1; if(directions->ElementAt(i).one_norm() <= 0.0) { return 0; } else { double twonorm = directions->ElementAt(i).two_norm(); double bval = b_value*twonorm*twonorm; if (bval<0) bval = ceil(bval - 0.5); else bval = floor(bval + 0.5); return bval; } } void mitk::DiffusionPropertyHelper::CopyProperties(BaseData *source, BaseData *target, bool ignore_original_gradients) { mitk::PropertyList::Pointer props = source->GetPropertyList()->Clone(); if (ignore_original_gradients) props->RemoveProperty(mitk::DiffusionPropertyHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME); target->SetPropertyList(props); } void mitk::DiffusionPropertyHelper::CopyDICOMProperties(const mitk::BaseData* source, mitk::BaseData* target) { mitk::PropertyList::Pointer list = source->GetPropertyList(); for (auto key : list->GetPropertyKeys()) if (boost::algorithm::starts_with(key, "DICOM.")) target->GetPropertyList()->ReplaceProperty(key, list->GetProperty(key)); } void mitk::DiffusionPropertyHelper::InitializeImage(mitk::Image* image) { if ( image->GetProperty(mitk::DiffusionPropertyHelper::APPLY_MATRIX_TO_GRADIENTS.c_str()).IsNull() ) image->SetProperty( mitk::DiffusionPropertyHelper::APPLY_MATRIX_TO_GRADIENTS.c_str(), mitk::BoolProperty::New(true) ); if ( image->GetProperty(mitk::DiffusionPropertyHelper::APPLY_MF_TO_GRADIENTS.c_str()).IsNull() ) image->SetProperty( mitk::DiffusionPropertyHelper::APPLY_MF_TO_GRADIENTS.c_str(), mitk::BoolProperty::New(true) ); if( image->GetProperty(mitk::DiffusionPropertyHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str()).IsNull() ) { // we don't have the original gradient directions. Therefore use the modified directions and rotate them back. UnApplyMeasurementFrameAndRotationMatrix(image); } else ApplyMeasurementFrameAndRotationMatrix(image); UpdateBValueMap(image); // initialize missing properties mitk::MeasurementFrameProperty::Pointer mf = dynamic_cast( image->GetProperty(MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer()); if( mf.IsNull() ) { //no measurement frame present, identity is assumed MeasurementFrameType identity; identity.set_identity(); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( identity )); } } bool mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(const mitk::DataNode* node) { if ( node==nullptr ) return false; if ( node->GetData()==nullptr ) return false; return IsDiffusionWeightedImage(dynamic_cast(node->GetData())); } bool mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(const mitk::Image * image) { bool isDiffusionWeightedImage( true ); if( image == nullptr ) { isDiffusionWeightedImage = false; } if( isDiffusionWeightedImage ) { mitk::FloatProperty::Pointer referenceBValue = dynamic_cast(image->GetProperty(REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer()); if( referenceBValue.IsNull() ) { isDiffusionWeightedImage = false; } } unsigned int gradientDirections( 0 ); if( isDiffusionWeightedImage ) { mitk::GradientDirectionsProperty::Pointer gradientDirectionsProperty = dynamic_cast(image->GetProperty(GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer()); if( gradientDirectionsProperty.IsNull() ) { isDiffusionWeightedImage = false; } else { gradientDirections = gradientDirectionsProperty->GetGradientDirectionsContainer()->size(); } } if( isDiffusionWeightedImage ) { unsigned int components = image->GetPixelType().GetNumberOfComponents(); if( components != gradientDirections ) { isDiffusionWeightedImage = false; } } return isDiffusionWeightedImage; } const mitk::DiffusionPropertyHelper::BValueMapType & mitk::DiffusionPropertyHelper::GetBValueMap(const mitk::Image *image) { return dynamic_cast(image->GetProperty(BVALUEMAPPROPERTYNAME.c_str()).GetPointer())->GetBValueMap(); } std::vector< int > mitk::DiffusionPropertyHelper::GetBValueVector(const mitk::Image* image) { auto gcon = mitk::DiffusionPropertyHelper::GetGradientContainer(image); float b_value = mitk::DiffusionPropertyHelper::GetReferenceBValue(image); std::vector< int > bvalues; for (unsigned int i=0; iSize(); ++i) { double twonorm = gcon->ElementAt(i).two_norm(); double bval = b_value*twonorm*twonorm; if (bval<0) bval = ceil(bval - 0.5); else bval = floor(bval + 0.5); bvalues.push_back(bval); } return bvalues; } float mitk::DiffusionPropertyHelper::GetReferenceBValue(const mitk::Image *image) { return dynamic_cast(image->GetProperty(REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer())->GetValue(); } const mitk::DiffusionPropertyHelper::MeasurementFrameType & mitk::DiffusionPropertyHelper::GetMeasurementFrame(const mitk::Image *image) { mitk::MeasurementFrameProperty::Pointer mf = dynamic_cast( image->GetProperty(MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer()); if( mf.IsNull() ) { //no measurement frame present, identity is assumed MeasurementFrameType identity; identity.set_identity(); mf = mitk::MeasurementFrameProperty::New( identity ); } return mf->GetMeasurementFrame(); } -mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer mitk::DiffusionPropertyHelper::GetOriginalGradientContainer(const mitk::Image *image) +const mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer mitk::DiffusionPropertyHelper::GetOriginalGradientContainer(const mitk::Image *image) { return dynamic_cast(image->GetProperty(ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer())->GetGradientDirectionsContainer(); } -mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer mitk::DiffusionPropertyHelper::GetGradientContainer(const mitk::Image *image) +const mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer mitk::DiffusionPropertyHelper::GetGradientContainer(const mitk::Image *image) { return dynamic_cast(image->GetProperty(GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer())->GetGradientDirectionsContainer(); } void mitk::DiffusionPropertyHelper::SetReferenceBValue(mitk::Image* image, float b_value) { image->GetPropertyList()->ReplaceProperty(REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New(b_value)); } void mitk::DiffusionPropertyHelper::SetBValueMap(mitk::Image* image, BValueMapType map) { image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str(), mitk::BValueMapProperty::New(map)); } +void mitk::DiffusionPropertyHelper::SetOriginalGradientContainer(mitk::Image* image, GradientDirectionsContainerType::ConstPointer g_cont) +{ + image->GetPropertyList()->ReplaceProperty(ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New(g_cont)); +} + void mitk::DiffusionPropertyHelper::SetOriginalGradientContainer(mitk::Image* image, GradientDirectionsContainerType::Pointer g_cont) { image->GetPropertyList()->ReplaceProperty(ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New(g_cont)); } +void mitk::DiffusionPropertyHelper::SetGradientContainer(mitk::Image* image, GradientDirectionsContainerType::ConstPointer g_cont) +{ + image->GetPropertyList()->ReplaceProperty(GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New(g_cont)); +} + void mitk::DiffusionPropertyHelper::SetGradientContainer(mitk::Image* image, GradientDirectionsContainerType::Pointer g_cont) { image->GetPropertyList()->ReplaceProperty(GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New(g_cont)); } void mitk::DiffusionPropertyHelper::SetMeasurementFrame(mitk::Image* image, MeasurementFrameType mf) { image->GetPropertyList()->ReplaceProperty( MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( mf ) ); } void mitk::DiffusionPropertyHelper::RotateGradients(mitk::Image* image, vnl_matrix_fixed rotation_matrix, bool normalize_columns) { if (normalize_columns) rotation_matrix = rotation_matrix.normalize_columns(); int c = 0; auto new_gradients = GradientDirectionsContainerType::New(); auto old_gradients = GetGradientContainer(image); for(auto gdcit = old_gradients->Begin(); gdcit != old_gradients->End(); ++gdcit) { vnl_vector vec = gdcit.Value(); vec = vec.pre_multiply(rotation_matrix); new_gradients->InsertElement(c, vec); c++; } SetGradientContainer(image, new_gradients); } void mitk::DiffusionPropertyHelper::RotateOriginalGradients(mitk::Image* image, vnl_matrix_fixed rotation_matrix, bool normalize_columns) { if (normalize_columns) rotation_matrix = rotation_matrix.normalize_columns(); int c = 0; auto new_gradients = GradientDirectionsContainerType::New(); auto old_gradients = GetOriginalGradientContainer(image); for(auto gdcit = old_gradients->Begin(); gdcit != old_gradients->End(); ++gdcit) { vnl_vector vec = gdcit.Value(); vec = vec.pre_multiply(rotation_matrix); new_gradients->InsertElement(c, vec); c++; } SetOriginalGradientContainer(image, new_gradients); } void mitk::DiffusionPropertyHelper::SetupProperties() { //register relevant properties //non-persistent properties mitk::CoreServices::GetPropertyDescriptions()->AddDescription(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME, "This map stores which b values belong to which gradients."); mitk::CoreServices::GetPropertyDescriptions()->AddDescription(mitk::DiffusionPropertyHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME, "The original gradients used during acquisition. This property may be empty."); //persistent properties mitk::CoreServices::GetPropertyDescriptions()->AddDescription(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME, "The reference b value the gradients are normalized to."); mitk::CoreServices::GetPropertyDescriptions()->AddDescription(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME, "The measurment frame used during acquisition."); mitk::CoreServices::GetPropertyDescriptions()->AddDescription(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME, "The gradients after applying measurement frame and image matrix."); mitk::CoreServices::GetPropertyDescriptions()->AddDescription(mitk::DiffusionPropertyHelper::MODALITY, "Defines the modality used for acquisition. DWMRI signifies diffusion weighted images."); mitk::PropertyPersistenceInfo::Pointer PPI_referenceBValue = mitk::PropertyPersistenceInfo::New(); PPI_referenceBValue->SetNameAndKey(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME, "DWMRI_b-value"); mitk::PropertyPersistenceInfo::Pointer PPI_measurementFrame = mitk::PropertyPersistenceInfo::New(); PPI_measurementFrame->SetNameAndKey(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME, "measurement frame"); mitk::PropertyPersistenceInfo::Pointer PPI_gradientContainer = mitk::PropertyPersistenceInfo::New(); PPI_gradientContainer->SetNameAndKey(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME, "DWMRI_gradient"); mitk::PropertyPersistenceInfo::Pointer PPI_modality = mitk::PropertyPersistenceInfo::New(); PPI_modality->SetNameAndKey(mitk::DiffusionPropertyHelper::MODALITY, "modality"); mitk::CoreServices::GetPropertyPersistence()->AddInfo(PPI_referenceBValue.GetPointer() , true); mitk::CoreServices::GetPropertyPersistence()->AddInfo(PPI_measurementFrame.GetPointer(), true); mitk::CoreServices::GetPropertyPersistence()->AddInfo(PPI_gradientContainer.GetPointer(), true); mitk::CoreServices::GetPropertyPersistence()->AddInfo(PPI_modality.GetPointer(), true); } diff --git a/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.h b/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.h index 7504226..2d33296 100644 --- a/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.h +++ b/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.h @@ -1,128 +1,130 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef MITKDIFFUSIONPROPERTYHELPER_H #define MITKDIFFUSIONPROPERTYHELPER_H #include #include #include #include #include #include #include namespace mitk { /** \brief Helper class for mitk::Images containing diffusion weighted data * * This class takes a pointer to a mitk::Image containing diffusion weighted information and provides * functions to manipulate the diffusion meta-data. Will log an error if required information is * missing. */ class MITKDIFFUSIONCORE_EXPORT DiffusionPropertyHelper { public: typedef short DiffusionPixelType; typedef mitk::BValueMapProperty::BValueMap BValueMapType; typedef GradientDirectionsProperty::GradientDirectionType GradientDirectionType; typedef GradientDirectionsProperty::GradientDirectionsContainerType GradientDirectionsContainerType; typedef mitk::MeasurementFrameProperty::MeasurementFrameType MeasurementFrameType; typedef itk::VectorImage< DiffusionPixelType, 3> ImageType; static bool IsDiffusionWeightedImage(const mitk::Image *); static bool IsDiffusionWeightedImage(const mitk::DataNode* node); static void CopyProperties(mitk::BaseData* source, mitk::BaseData* target, bool ignore_original_gradients=false); static ImageType::Pointer GetItkVectorImage(Image *image); static const BValueMapType & GetBValueMap(const mitk::Image *); static float GetReferenceBValue(const mitk::Image *); static std::vector< int > GetBValueVector(const mitk::Image *); static const MeasurementFrameType & GetMeasurementFrame(const mitk::Image *); - static GradientDirectionsContainerType::Pointer GetOriginalGradientContainer(const mitk::Image *); - static GradientDirectionsContainerType::Pointer GetGradientContainer(const mitk::Image *); + static const GradientDirectionsContainerType::ConstPointer GetOriginalGradientContainer(const mitk::Image *); + static const GradientDirectionsContainerType::ConstPointer GetGradientContainer(const mitk::Image *); static void SetApplyMatrixToGradients(mitk::Image* image, bool apply); static void SetApplyMfToGradients(mitk::Image* image, bool apply); static void SetMeasurementFrame(mitk::Image* image, MeasurementFrameType mf); static void SetReferenceBValue(mitk::Image* image, float b_value); static void SetBValueMap(mitk::Image* image, BValueMapType map); + static void SetOriginalGradientContainer(mitk::Image* image, GradientDirectionsContainerType::ConstPointer g_cont); static void SetOriginalGradientContainer(mitk::Image* image, GradientDirectionsContainerType::Pointer g_cont); + static void SetGradientContainer(mitk::Image* image, GradientDirectionsContainerType::ConstPointer g_cont); static void SetGradientContainer(mitk::Image* image, GradientDirectionsContainerType::Pointer g_cont); static void RotateGradients(mitk::Image* image, vnl_matrix_fixed rotation_matrix, bool normalize_columns); static void RotateOriginalGradients(mitk::Image* image, vnl_matrix_fixed rotation_matrix, bool normalize_columns); static void AverageRedundantGradients(mitk::Image* image, double precision); static void InitializeImage(mitk::Image* image); - static GradientDirectionsContainerType::Pointer CalcAveragedDirectionSet(double precision, GradientDirectionsContainerType::Pointer directions); + static GradientDirectionsContainerType::Pointer CalcAveragedDirectionSet(double precision, GradientDirectionsContainerType::ConstPointer directions); static void SetupProperties(); // called in DiffusionCoreIOActivator static const std::string GetBvaluePropertyName() { return BVALUEMAPPROPERTYNAME; } static const std::string GetGradientContainerPropertyName() { return GRADIENTCONTAINERPROPERTYNAME; } static const std::string GetMeasurementFramePropertyName() { return MEASUREMENTFRAMEPROPERTYNAME; } static void CopyDICOMProperties(const BaseData *source, BaseData *target); protected: DiffusionPropertyHelper(); ~DiffusionPropertyHelper(); static const std::string GRADIENTCONTAINERPROPERTYNAME; static const std::string ORIGINALGRADIENTCONTAINERPROPERTYNAME; static const std::string MEASUREMENTFRAMEPROPERTYNAME; static const std::string REFERENCEBVALUEPROPERTYNAME; static const std::string BVALUEMAPPROPERTYNAME; static const std::string MODALITY; static const std::string APPLY_MATRIX_TO_GRADIENTS; static const std::string APPLY_MF_TO_GRADIENTS; /** * \brief Apply the previously set MeasurementFrame and the image rotation matrix to all gradients * * \warning first set the MeasurementFrame */ static void ApplyMeasurementFrameAndRotationMatrix(mitk::Image* image); /** * \brief Apply the inverse of the previously set MeasurementFrame and the image rotation matrix to all gradients * * \warning first set the MeasurementFrame */ static void UnApplyMeasurementFrameAndRotationMatrix(mitk::Image* image); /** * \brief Update the BValueMap (m_B_ValueMap) using the current gradient directions (m_Directions) * * \warning Have to be called after each manipulation on the GradientDirectionContainer * !especially after manipulation of the m_Directions (GetDirections()) container via pointer access! */ static void UpdateBValueMap(mitk::Image* image); /// Determines whether gradients can be considered to be equal static bool AreAlike(GradientDirectionType g1, GradientDirectionType g2, double precision); /// Get the b value belonging to an index static float GetB_Value(const mitk::Image* image, unsigned int i); }; } #endif diff --git a/Modules/DiffusionCore/IODataStructures/Properties/mitkGradientDirectionsProperty.cpp b/Modules/DiffusionCore/IODataStructures/Properties/mitkGradientDirectionsProperty.cpp index 43c0a03..eb3e0b6 100644 --- a/Modules/DiffusionCore/IODataStructures/Properties/mitkGradientDirectionsProperty.cpp +++ b/Modules/DiffusionCore/IODataStructures/Properties/mitkGradientDirectionsProperty.cpp @@ -1,83 +1,104 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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 "mitkGradientDirectionsProperty.h" mitk::GradientDirectionsProperty::GradientDirectionsProperty() { m_GradientDirectionsContainer = mitk::GradientDirectionsProperty::GradientDirectionsContainerType::New(); } mitk::GradientDirectionsProperty::GradientDirectionsProperty(const GradientDirectionsProperty& other) : mitk::BaseProperty(other) { m_GradientDirectionsContainer = other.GetGradientDirectionsContainer(); } +mitk::GradientDirectionsProperty::GradientDirectionsProperty(const GradientDirectionsContainerType::ConstPointer gradientDirectionsContainer) +{ + m_GradientDirectionsContainer = gradientDirectionsContainer; +} + mitk::GradientDirectionsProperty::GradientDirectionsProperty(const GradientDirectionsContainerType::Pointer gradientDirectionsContainer) { m_GradientDirectionsContainer = gradientDirectionsContainer; } mitk::GradientDirectionsProperty::GradientDirectionsProperty(const AlternativeGradientDirectionsContainerType gradientDirectionsContainer) { - m_GradientDirectionsContainer = mitk::GradientDirectionsProperty::GradientDirectionsContainerType::New(); + auto temp = mitk::GradientDirectionsProperty::GradientDirectionsContainerType::New(); for(unsigned int index(0); index < gradientDirectionsContainer.size(); index++) { GradientDirectionType newDirection = gradientDirectionsContainer.at(index).GetVnlVector(); - m_GradientDirectionsContainer->InsertElement( index, newDirection); + temp->InsertElement( index, newDirection); } + m_GradientDirectionsContainer = temp; } mitk::GradientDirectionsProperty::~GradientDirectionsProperty() { } -const mitk::GradientDirectionsProperty::GradientDirectionsContainerType::Pointer mitk::GradientDirectionsProperty::GetGradientDirectionsContainer() const +const mitk::GradientDirectionsProperty::GradientDirectionsContainerType::Pointer mitk::GradientDirectionsProperty::GetGradientDirectionsContainerCopy() const +{ + auto temp = mitk::GradientDirectionsProperty::GradientDirectionsContainerType::New(); + + for(unsigned int index = 0; index < m_GradientDirectionsContainer->Size(); ++index) + { + GradientDirectionType newDirection; + newDirection[0] = m_GradientDirectionsContainer->at(index)[0]; + newDirection[1] = m_GradientDirectionsContainer->at(index)[1]; + newDirection[2] = m_GradientDirectionsContainer->at(index)[2]; + temp->InsertElement( index, newDirection); + } + return temp; +} + +const mitk::GradientDirectionsProperty::GradientDirectionsContainerType::ConstPointer mitk::GradientDirectionsProperty::GetGradientDirectionsContainer() const { return m_GradientDirectionsContainer; } bool mitk::GradientDirectionsProperty::IsEqual(const BaseProperty& property) const { - GradientDirectionsContainerType::Pointer lhs = this->m_GradientDirectionsContainer; - GradientDirectionsContainerType::Pointer rhs = static_cast(property).m_GradientDirectionsContainer; + GradientDirectionsContainerType::ConstPointer lhs = this->m_GradientDirectionsContainer; + GradientDirectionsContainerType::ConstPointer rhs = static_cast(property).m_GradientDirectionsContainer; if(lhs->Size() != rhs->Size()) return false; - GradientDirectionsContainerType::Iterator lhsit = lhs->Begin(); - GradientDirectionsContainerType::Iterator rhsit = rhs->Begin(); + GradientDirectionsContainerType::ConstIterator lhsit = lhs->Begin(); + GradientDirectionsContainerType::ConstIterator rhsit = rhs->Begin(); bool equal = true; for(unsigned int i = 0 ; i < lhs->Size(); i++, ++lhsit, ++rhsit) equal |= lhsit.Value() == rhsit.Value(); return equal; } bool mitk::GradientDirectionsProperty::Assign(const BaseProperty& property) { this->m_GradientDirectionsContainer = static_cast(property).m_GradientDirectionsContainer; return true; } itk::LightObject::Pointer mitk::GradientDirectionsProperty::InternalClone() const { itk::LightObject::Pointer result(new Self(*this)); result->UnRegister(); return result; } diff --git a/Modules/DiffusionCore/IODataStructures/Properties/mitkGradientDirectionsProperty.h b/Modules/DiffusionCore/IODataStructures/Properties/mitkGradientDirectionsProperty.h index e23dbce..ef7cfab 100644 --- a/Modules/DiffusionCore/IODataStructures/Properties/mitkGradientDirectionsProperty.h +++ b/Modules/DiffusionCore/IODataStructures/Properties/mitkGradientDirectionsProperty.h @@ -1,68 +1,71 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef MITKGRADIENTDIRECTIONSPROPERTY_H #define MITKGRADIENTDIRECTIONSPROPERTY_H #include "mitkBaseProperty.h" #include #include #include #include namespace mitk { /** This property will store the gradients directions and the original gradient directions */ class MITKDIFFUSIONCORE_EXPORT GradientDirectionsProperty : public mitk::BaseProperty { public: typedef unsigned int IndexType; typedef vnl_vector_fixed< double, 3 > ValueType; typedef ValueType GradientDirectionType; typedef itk::VectorContainer< IndexType, GradientDirectionType > GradientDirectionsContainerType; typedef std::vector< itk::Vector > AlternativeGradientDirectionsContainerType; mitkClassMacro(GradientDirectionsProperty, BaseProperty) itkFactorylessNewMacro(Self) itkCloneMacro(Self) mitkNewMacro1Param(GradientDirectionsProperty, const GradientDirectionsProperty&); mitkNewMacro1Param(GradientDirectionsProperty, const GradientDirectionsContainerType::Pointer); + mitkNewMacro1Param(GradientDirectionsProperty, const GradientDirectionsContainerType::ConstPointer); mitkNewMacro1Param(GradientDirectionsProperty, const AlternativeGradientDirectionsContainerType ); - const GradientDirectionsContainerType::Pointer GetGradientDirectionsContainer() const; + const GradientDirectionsContainerType::ConstPointer GetGradientDirectionsContainer() const; + const GradientDirectionsContainerType::Pointer GetGradientDirectionsContainerCopy() const; protected: GradientDirectionsProperty(); ~GradientDirectionsProperty() override; GradientDirectionsProperty(const GradientDirectionsProperty& other); GradientDirectionsProperty(const GradientDirectionsContainerType::Pointer gradientDirectionsContainer); + GradientDirectionsProperty(const GradientDirectionsContainerType::ConstPointer gradientDirectionsContainer); GradientDirectionsProperty(const AlternativeGradientDirectionsContainerType gradientDirectionsContainer); bool IsEqual(const BaseProperty& property) const override; bool Assign(const BaseProperty & property) override; - GradientDirectionsContainerType::Pointer m_GradientDirectionsContainer; + GradientDirectionsContainerType::ConstPointer m_GradientDirectionsContainer; itk::LightObject::Pointer InternalClone() const override; }; } #endif diff --git a/Modules/DiffusionCore/IODataStructures/Properties/mitkGradientDirectionsPropertySerializer.cpp b/Modules/DiffusionCore/IODataStructures/Properties/mitkGradientDirectionsPropertySerializer.cpp index 8b68fe2..3c3b047 100644 --- a/Modules/DiffusionCore/IODataStructures/Properties/mitkGradientDirectionsPropertySerializer.cpp +++ b/Modules/DiffusionCore/IODataStructures/Properties/mitkGradientDirectionsPropertySerializer.cpp @@ -1,106 +1,106 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef mitkGradientDirectionPropertySerializer_h_included #define mitkGradientDirectionPropertySerializer_h_included #include "mitkBasePropertySerializer.h" #include "mitkGradientDirectionsProperty.h" #include "MitkDiffusionCoreExports.h" namespace mitk { class MITKDIFFUSIONCORE_EXPORT GradientDirectionsPropertySerializer : public BasePropertySerializer { public: mitkClassMacro( GradientDirectionsPropertySerializer, BasePropertySerializer ) itkFactorylessNewMacro(Self) itkCloneMacro(Self) TiXmlElement* Serialize() override { if (const GradientDirectionsProperty* prop = dynamic_cast(m_Property.GetPointer())) { typedef mitk::GradientDirectionsProperty::GradientDirectionsContainerType GradientDirectionsContainerType; - GradientDirectionsContainerType::Pointer gdc = prop->GetGradientDirectionsContainer().GetPointer(); + GradientDirectionsContainerType::ConstPointer gdc = prop->GetGradientDirectionsContainer().GetPointer(); if(gdc.IsNull() || gdc->Size() == 0) return nullptr; - GradientDirectionsContainerType::Iterator it = gdc->Begin(); - GradientDirectionsContainerType::Iterator end = gdc->End(); + GradientDirectionsContainerType::ConstIterator it = gdc->Begin(); + GradientDirectionsContainerType::ConstIterator end = gdc->End(); auto element = new TiXmlElement("gradientdirections"); while (it != end) { auto child = new TiXmlElement("entry"); std::stringstream ss; ss << it.Value(); child->SetAttribute("value", ss.str()); element->InsertEndChild(*child); ++it; } return element; } else return nullptr; } BaseProperty::Pointer Deserialize(TiXmlElement* element) override { if (!element) return nullptr; mitk::GradientDirectionsProperty::GradientDirectionsContainerType::Pointer gdc; gdc = mitk::GradientDirectionsProperty::GradientDirectionsContainerType::New(); TiXmlElement* entry = element->FirstChildElement( "entry" )->ToElement(); while(entry != nullptr){ std::stringstream ss; std::string value; entry->QueryStringAttribute("value",&value); ss << value; vnl_vector_fixed vector; vector.read_ascii(ss); gdc->push_back(vector); entry = entry->NextSiblingElement( "entry" ); } return GradientDirectionsProperty::New(gdc).GetPointer(); } protected: GradientDirectionsPropertySerializer() {} ~GradientDirectionsPropertySerializer() override {} }; } // namespace // important to put this into the GLOBAL namespace (because it starts with 'namespace mitk') MITK_REGISTER_SERIALIZER(GradientDirectionsPropertySerializer) #endif diff --git a/Modules/DiffusionCore/Testing/mitkDiffusionPropertySerializerTest.cpp b/Modules/DiffusionCore/Testing/mitkDiffusionPropertySerializerTest.cpp index 506f63c..935f41a 100644 --- a/Modules/DiffusionCore/Testing/mitkDiffusionPropertySerializerTest.cpp +++ b/Modules/DiffusionCore/Testing/mitkDiffusionPropertySerializerTest.cpp @@ -1,183 +1,183 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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 "mitkIOUtil.h" #include "mitkTestingMacros.h" #include "mitkTestFixture.h" #include #include #include #include #include class mitkDiffusionPropertySerializerTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkDiffusionPropertySerializerTestSuite); MITK_TEST(Equal_SerializeandDeserialize_ReturnsTrue); //MITK_TEST(Equal_DifferentChannels_ReturnFalse); CPPUNIT_TEST_SUITE_END(); private: /** Members used inside the different (sub-)tests. All members are initialized via setUp().*/ mitk::PropertyList::Pointer propList; //represet image propertylist mitk::BValueMapProperty::Pointer bvaluemap_prop; mitk::GradientDirectionsProperty::Pointer gradientdirection_prop; mitk::MeasurementFrameProperty::Pointer measurementframe_prop; public: /** * @brief Setup Always call this method before each Test-case to ensure correct and new intialization of the used members for a new test case. (If the members are not used in a test, the method does not need to be called). */ void setUp() override { propList = mitk::PropertyList::New(); mitk::BValueMapProperty::BValueMap map; std::vector indices1; indices1.push_back(1); indices1.push_back(2); indices1.push_back(3); indices1.push_back(4); map[0] = indices1; std::vector indices2; indices2.push_back(4); indices2.push_back(3); indices2.push_back(2); indices2.push_back(1); map[1000] = indices2; bvaluemap_prop = mitk::BValueMapProperty::New(map).GetPointer(); propList->SetProperty(mitk::DiffusionPropertyHelper::GetBvaluePropertyName().c_str(), bvaluemap_prop); mitk::GradientDirectionsProperty::GradientDirectionsContainerType::Pointer gdc; gdc = mitk::GradientDirectionsProperty::GradientDirectionsContainerType::New(); double a[3] = {3.0,4.0,1.4}; vnl_vector_fixed vec1; vec1.set(a); gdc->push_back(vec1); double b[3] = {1.0,5.0,123.4}; vnl_vector_fixed vec2; vec2.set(b); gdc->push_back(vec2); double c[3] = {13.0,84.02,13.4}; vnl_vector_fixed vec3; vec3.set(c); gdc->push_back(vec3); - gradientdirection_prop = mitk::GradientDirectionsProperty::New(gdc.GetPointer()).GetPointer(); + gradientdirection_prop = mitk::GradientDirectionsProperty::New(gdc).GetPointer(); propList->ReplaceProperty(mitk::DiffusionPropertyHelper::GetGradientContainerPropertyName().c_str(), gradientdirection_prop); mitk::MeasurementFrameProperty::MeasurementFrameType mft; double row0[3] = {1,0,0}; double row1[3] = {0,1,0}; double row2[3] = {0,0,1}; mft.set_row(0,row0); mft.set_row(1,row1); mft.set_row(2,row2); measurementframe_prop = mitk::MeasurementFrameProperty::New(mft).GetPointer(); propList->ReplaceProperty(mitk::DiffusionPropertyHelper::GetGradientContainerPropertyName().c_str(), measurementframe_prop); } void tearDown() override { } void Equal_SerializeandDeserialize_ReturnsTrue() { assert(propList); /* try to serialize each property in the list, then deserialize again and check for equality */ for (mitk::PropertyList::PropertyMap::const_iterator it = propList->GetMap()->begin(); it != propList->GetMap()->end(); ++it) { const mitk::BaseProperty* prop = it->second; // construct name of serializer class std::string serializername = std::string(prop->GetNameOfClass()) + "Serializer"; std::list allSerializers = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str()); MITK_TEST_CONDITION(allSerializers.size() > 0, std::string("Creating serializers for ") + serializername); if (allSerializers.size() == 0) { MITK_TEST_OUTPUT( << "serialization not possible, skipping " << prop->GetNameOfClass()); continue; } if (allSerializers.size() > 1) { MITK_TEST_OUTPUT (<< "Warning: " << allSerializers.size() << " serializers found for " << prop->GetNameOfClass() << "testing only the first one."); } mitk::BasePropertySerializer* serializer = dynamic_cast( allSerializers.begin()->GetPointer()); MITK_TEST_CONDITION(serializer != nullptr, serializername + std::string(" is valid")); if (serializer != nullptr) { serializer->SetProperty(prop); TiXmlElement* valueelement = nullptr; try { valueelement = serializer->Serialize(); // TiXmlPrinter p; // valueelement->Accept(&p); // MITK_INFO << p.CStr(); } catch (...) { } MITK_TEST_CONDITION(valueelement != nullptr, std::string("Serialize property with ") + serializername); if (valueelement == nullptr) { MITK_TEST_OUTPUT( << "serialization failed, skipping deserialization"); continue; } mitk::BaseProperty::Pointer deserializedProp = serializer->Deserialize( valueelement ); MITK_TEST_CONDITION(deserializedProp.IsNotNull(), "serializer created valid property"); if (deserializedProp.IsNotNull()) { MITK_TEST_CONDITION(*(deserializedProp.GetPointer()) == *prop, "deserialized property equals initial property for type " << prop->GetNameOfClass()); } } else { MITK_TEST_OUTPUT( << "created serializer object is of class " << allSerializers.begin()->GetPointer()->GetNameOfClass()) } } // for all properties } }; MITK_TEST_SUITE_REGISTRATION(mitkDiffusionPropertySerializer) diff --git a/Modules/DiffusionCore/Testing/mitkExtractSingleShellTest.cpp b/Modules/DiffusionCore/Testing/mitkExtractSingleShellTest.cpp index e90580d..3405e5f 100644 --- a/Modules/DiffusionCore/Testing/mitkExtractSingleShellTest.cpp +++ b/Modules/DiffusionCore/Testing/mitkExtractSingleShellTest.cpp @@ -1,97 +1,97 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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 "mitkTestingMacros.h" #include "mitkIOUtil.h" #include #include "mitkDWIHeadMotionCorrectionFilter.h" #include #include #include typedef short DiffusionPixelType; int mitkExtractSingleShellTest( int argc, char* argv[] ) { MITK_TEST_BEGIN("mitkExtractSingleShellTest"); MITK_TEST_CONDITION_REQUIRED( argc > 3, "Specify input and output and the shell to be extracted"); /* 1. Get input data */ mitk::Image::Pointer dwimage = mitk::IOUtil::Load( argv[1] ); unsigned int extract_value = 0; std::istringstream input(argv[3]); input >> extract_value; typedef itk::ElectrostaticRepulsionDiffusionGradientReductionFilter FilterType; typedef mitk::DiffusionPropertyHelper::BValueMapType BValueMap; // GetShellSelection from GUI BValueMap shellSelectionMap; BValueMap originalShellMap = mitk::DiffusionPropertyHelper::GetBValueMap(dwimage); std::vector newNumGradientDirections; shellSelectionMap[extract_value] = originalShellMap[extract_value]; newNumGradientDirections.push_back( originalShellMap[extract_value].size() ) ; itk::VectorImage< short, 3 >::Pointer itkVectorImagePointer = itk::VectorImage< short, 3 >::New(); mitk::CastToItkImage(dwimage, itkVectorImagePointer); itk::VectorImage< short, 3 > *vectorImage = itkVectorImagePointer.GetPointer(); - mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientContainer = mitk::DiffusionPropertyHelper::GetGradientContainer(dwimage); + mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer gradientContainer = mitk::DiffusionPropertyHelper::GetGradientContainer(dwimage); FilterType::Pointer filter = FilterType::New(); filter->SetInput(vectorImage); filter->SetOriginalGradientDirections(gradientContainer); filter->SetNumGradientDirections(newNumGradientDirections); filter->SetOriginalBValueMap(originalShellMap); filter->SetShellSelectionBValueMap(shellSelectionMap); try { filter->Update(); } catch( const itk::ExceptionObject& e) { MITK_TEST_FAILED_MSG( << "Failed due to ITK exception: " << e.what() ); } mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( filter->GetOutput() ); mitk::DiffusionPropertyHelper::CopyProperties(dwimage, outImage, true); mitk::DiffusionPropertyHelper::SetGradientContainer(outImage, filter->GetGradientDirections()); mitk::DiffusionPropertyHelper::InitializeImage( outImage ); /* * 3. Write output data **/ try { mitk::IOUtil::Save(outImage, argv[2]); } catch( const itk::ExceptionObject& e) { MITK_ERROR << "Catched exception: " << e.what(); mitkThrow() << "Failed with exception from subprocess!"; } MITK_TEST_END(); } diff --git a/Modules/DiffusionCore/Testing/mitkImageReconstructionTest.cpp b/Modules/DiffusionCore/Testing/mitkImageReconstructionTest.cpp index 67d95f1..3c948e0 100644 --- a/Modules/DiffusionCore/Testing/mitkImageReconstructionTest.cpp +++ b/Modules/DiffusionCore/Testing/mitkImageReconstructionTest.cpp @@ -1,155 +1,155 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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 #include #include #include #include #include #include #include #include #include #include #include int mitkImageReconstructionTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkImageReconstructionTest"); MITK_TEST_CONDITION_REQUIRED(argc>1,"check for input data") try { mitk::Image::Pointer dwi = mitk::IOUtil::Load(argv[1]); itk::VectorImage::Pointer itkVectorImagePointer = itk::VectorImage::New(); mitk::CastToItkImage(dwi, itkVectorImagePointer); float b_value = mitk::DiffusionPropertyHelper::GetReferenceBValue( dwi ); - mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradients = mitk::DiffusionPropertyHelper::GetGradientContainer(dwi); + mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer gradients = mitk::DiffusionPropertyHelper::GetGradientContainer(dwi); { MITK_INFO << "Tensor reconstruction " << argv[2]; mitk::TensorImage::Pointer tensorImage = mitk::IOUtil::Load(argv[2]); typedef itk::DiffusionTensor3DReconstructionImageFilter< short, short, float > TensorReconstructionImageFilterType; TensorReconstructionImageFilterType::Pointer filter = TensorReconstructionImageFilterType::New(); filter->SetBValue( b_value ); - filter->SetGradientImage( gradients, itkVectorImagePointer ); + filter->SetGradientImage( dynamic_cast(dwi->GetProperty(mitk::DiffusionPropertyHelper::GetGradientContainerPropertyName().c_str()).GetPointer())->GetGradientDirectionsContainerCopy(), itkVectorImagePointer ); filter->Update(); mitk::TensorImage::Pointer testImage = mitk::TensorImage::New(); testImage->InitializeByItk( filter->GetOutput() ); testImage->SetVolume( filter->GetOutput()->GetBufferPointer() ); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(*testImage, *tensorImage, 0.0001, true), "tensor reconstruction test."); } { MITK_INFO << "Numerical Q-ball reconstruction " << argv[3]; mitk::OdfImage::Pointer odfImage = mitk::IOUtil::Load(argv[3]); typedef itk::DiffusionQballReconstructionImageFilter QballReconstructionImageFilterType; QballReconstructionImageFilterType::Pointer filter = QballReconstructionImageFilterType::New(); filter->SetBValue( b_value ); filter->SetGradientImage( gradients, itkVectorImagePointer ); filter->SetNormalizationMethod(QballReconstructionImageFilterType::QBR_STANDARD); filter->Update(); mitk::OdfImage::Pointer testImage = mitk::OdfImage::New(); testImage->InitializeByItk( filter->GetOutput() ); testImage->SetVolume( filter->GetOutput()->GetBufferPointer() ); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(*testImage, *odfImage, 0.0001, true), "Numerical Q-ball reconstruction test."); } { MITK_INFO << "Standard Q-ball reconstruction " << argv[4]; mitk::OdfImage::Pointer odfImage = mitk::IOUtil::Load(argv[4]); typedef itk::AnalyticalDiffusionQballReconstructionImageFilter FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetBValue( b_value ); filter->SetGradientImage( gradients, itkVectorImagePointer ); filter->SetLambda(0.006); filter->SetNormalizationMethod(FilterType::QBAR_STANDARD); filter->Update(); mitk::OdfImage::Pointer testImage = mitk::OdfImage::New(); testImage->InitializeByItk( filter->GetOutput() ); testImage->SetVolume( filter->GetOutput()->GetBufferPointer() ); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(*testImage, *odfImage, 0.0001, true), "Standard Q-ball reconstruction test."); } { MITK_INFO << "CSA Q-ball reconstruction " << argv[5]; mitk::OdfImage::Pointer odfImage = mitk::IOUtil::Load(argv[5]); typedef itk::AnalyticalDiffusionQballReconstructionImageFilter FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetBValue( b_value ); filter->SetGradientImage( gradients, itkVectorImagePointer ); filter->SetLambda(0.006); filter->SetNormalizationMethod(FilterType::QBAR_SOLID_ANGLE); filter->Update(); mitk::OdfImage::Pointer testImage = mitk::OdfImage::New(); testImage->InitializeByItk( filter->GetOutput() ); testImage->SetVolume( filter->GetOutput()->GetBufferPointer() ); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(*testImage, *odfImage, 0.0001, true), "CSA Q-ball reconstruction test."); } { MITK_INFO << "ADC profile reconstruction " << argv[6]; mitk::OdfImage::Pointer odfImage = mitk::IOUtil::Load(argv[6]); typedef itk::AnalyticalDiffusionQballReconstructionImageFilter FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetBValue( b_value ); filter->SetGradientImage( gradients, itkVectorImagePointer ); filter->SetLambda(0.006); filter->SetNormalizationMethod(FilterType::QBAR_ADC_ONLY); filter->Update(); mitk::OdfImage::Pointer testImage = mitk::OdfImage::New(); testImage->InitializeByItk( filter->GetOutput() ); testImage->SetVolume( filter->GetOutput()->GetBufferPointer() ); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(*testImage, *odfImage, 0.0001, true), "ADC profile reconstruction test."); } { MITK_INFO << "Raw signal modeling " << argv[7]; mitk::OdfImage::Pointer odfImage = mitk::IOUtil::Load(argv[7]); typedef itk::AnalyticalDiffusionQballReconstructionImageFilter FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetBValue( b_value ); filter->SetGradientImage( gradients, itkVectorImagePointer ); filter->SetLambda(0.006); filter->SetNormalizationMethod(FilterType::QBAR_RAW_SIGNAL); filter->Update(); mitk::OdfImage::Pointer testImage = mitk::OdfImage::New(); testImage->InitializeByItk( filter->GetOutput() ); testImage->SetVolume( filter->GetOutput()->GetBufferPointer() ); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(*testImage, *odfImage, 0.1, true), "Raw signal modeling test."); } } catch (const itk::ExceptionObject& e) { MITK_INFO << e.what(); return EXIT_FAILURE; } catch (const std::exception& e) { MITK_INFO << e.what(); return EXIT_FAILURE; } catch (...) { MITK_INFO << "ERROR!?!"; return EXIT_FAILURE; } MITK_TEST_END(); } diff --git a/Modules/DiffusionCore/mitkDiffusionFunctionCollection.cpp b/Modules/DiffusionCore/mitkDiffusionFunctionCollection.cpp index a5dbca7..0308e98 100644 --- a/Modules/DiffusionCore/mitkDiffusionFunctionCollection.cpp +++ b/Modules/DiffusionCore/mitkDiffusionFunctionCollection.cpp @@ -1,713 +1,713 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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 "mitkDiffusionFunctionCollection.h" #include "mitkNumericTypes.h" #include #include #include #include #include #include "itkVectorContainer.h" #include "vnl/vnl_vector.h" #include #include #include #include #include // Intersect a finite line (with end points p0 and p1) with all of the // cells of a vtkImageData std::vector< std::pair< itk::Index<3>, double > > mitk::imv::IntersectImage(const itk::Vector& spacing, itk::Index<3>& si, itk::Index<3>& ei, itk::ContinuousIndex& sf, itk::ContinuousIndex& ef) { std::vector< std::pair< itk::Index<3>, double > > out; if (si == ei) { double d[3]; for (int i=0; i<3; ++i) d[i] = static_cast(sf[i]-ef[i])*spacing[i]; double len = std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); out.push_back( std::pair< itk::Index<3>, double >(si, len) ); return out; } double bounds[6]; double entrancePoint[3]; double exitPoint[3]; double startPoint[3]; double endPoint[3]; double t0, t1; for (unsigned int i=0; i<3; ++i) { startPoint[i] = static_cast(sf[i]); endPoint[i] = static_cast(ef[i]); if (si[i]>ei[i]) { auto t = si[i]; si[i] = ei[i]; ei[i] = t; } } for (auto x = si[0]; x<=ei[0]; ++x) for (auto y = si[1]; y<=ei[1]; ++y) for (auto z = si[2]; z<=ei[2]; ++z) { bounds[0] = static_cast(x) - 0.5; bounds[1] = static_cast(x) + 0.5; bounds[2] = static_cast(y) - 0.5; bounds[3] = static_cast(y) + 0.5; bounds[4] = static_cast(z) - 0.5; bounds[5] = static_cast(z) + 0.5; int entryPlane; int exitPlane; int hit = vtkBox::IntersectWithLine(bounds, startPoint, endPoint, t0, t1, entrancePoint, exitPoint, entryPlane, exitPlane); if (hit) { if (entryPlane>=0 && exitPlane>=0) { double d[3]; for (int i=0; i<3; ++i) d[i] = (exitPoint[i] - entrancePoint[i])*spacing[i]; double len = std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); itk::Index<3> idx; idx[0] = x; idx[1] = y; idx[2] = z; out.push_back( std::pair< itk::Index<3>, double >(idx, len) ); } else if (entryPlane>=0) { double d[3]; for (int i=0; i<3; ++i) d[i] = (static_cast(ef[i]) - entrancePoint[i])*spacing[i]; double len = std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); itk::Index<3> idx; idx[0] = x; idx[1] = y; idx[2] = z; out.push_back( std::pair< itk::Index<3>, double >(idx, len) ); } else if (exitPlane>=0) { double d[3]; for (int i=0; i<3; ++i) d[i] = (exitPoint[i]-static_cast(sf[i]))*spacing[i]; double len = std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); itk::Index<3> idx; idx[0] = x; idx[1] = y; idx[2] = z; out.push_back( std::pair< itk::Index<3>, double >(idx, len) ); } } } return out; } //------------------------- SH-function ------------------------------------ double mitk::sh::factorial(int number) { if(number <= 1) return 1; double result = 1.0; for(int i=1; i<=number; i++) result *= i; return result; } void mitk::sh::Cart2Sph(double x, double y, double z, double *spherical) { double phi, th, rad; rad = sqrt(x*x+y*y+z*z); if( rad < mitk::eps ) { th = itk::Math::pi/2; phi = itk::Math::pi/2; } else { th = acos(z/rad); phi = atan2(y, x); } spherical[0] = phi; spherical[1] = th; spherical[2] = rad; } vnl_vector_fixed mitk::sh::Sph2Cart(const double& theta, const double& phi, const double& rad) { vnl_vector_fixed dir; dir[0] = rad * sin(theta) * cos(phi); dir[1] = rad * sin(theta) * sin(phi); dir[2] = rad * cos(theta); return dir; } double mitk::sh::legendre0(int l) { if( l%2 != 0 ) { return 0; } else { double prod1 = 1.0; for(int i=1;i(::boost::math::spherical_harmonic_r(static_cast(k), -m, theta, phi)); else if (m==0) return static_cast(::boost::math::spherical_harmonic_r(static_cast(k), m, theta, phi)); else return pow(-1.0,m)*sqrt(2.0)*static_cast(::boost::math::spherical_harmonic_i(static_cast(k), m, theta, phi)); } else { double plm = static_cast(::boost::math::legendre_p(k,abs(m),-cos(theta))); double mag = sqrt((2.0*k+1.0)/(4.0*itk::Math::pi)*::boost::math::factorial(k-abs(m))/::boost::math::factorial(k+abs(m)))*plm; if (m>0) return mag*static_cast(cos(m*phi)); else if (m==0) return mag; else return mag*static_cast(sin(-m*phi)); } return 0; } mitk::OdfImage::ItkOdfImageType::Pointer mitk::convert::GetItkOdfFromShImage(mitk::Image::Pointer mitkImage) { mitk::ShImage::Pointer mitkShImage = dynamic_cast(mitkImage.GetPointer()); if (mitkShImage.IsNull()) mitkThrow() << "Input image is not a SH image!"; mitk::OdfImage::ItkOdfImageType::Pointer output; switch (mitkShImage->ShOrder()) { case 2: { typedef itk::ShToOdfImageFilter< float, 2 > ShConverterType; typename ShConverterType::InputImageType::Pointer itkvol = ShConverterType::InputImageType::New(); mitk::CastToItkImage(mitkImage, itkvol); typename ShConverterType::Pointer converter = ShConverterType::New(); converter->SetInput(itkvol); converter->SetToolkit(mitkShImage->GetShConvention()); converter->Update(); output = converter->GetOutput(); break; } case 4: { typedef itk::ShToOdfImageFilter< float, 4 > ShConverterType; typename ShConverterType::InputImageType::Pointer itkvol = ShConverterType::InputImageType::New(); mitk::CastToItkImage(mitkImage, itkvol); typename ShConverterType::Pointer converter = ShConverterType::New(); converter->SetInput(itkvol); converter->SetToolkit(mitkShImage->GetShConvention()); converter->Update(); output = converter->GetOutput(); break; } case 6: { typedef itk::ShToOdfImageFilter< float, 6 > ShConverterType; typename ShConverterType::InputImageType::Pointer itkvol = ShConverterType::InputImageType::New(); mitk::CastToItkImage(mitkImage, itkvol); typename ShConverterType::Pointer converter = ShConverterType::New(); converter->SetInput(itkvol); converter->SetToolkit(mitkShImage->GetShConvention()); converter->Update(); output = converter->GetOutput(); break; } case 8: { typedef itk::ShToOdfImageFilter< float, 8 > ShConverterType; typename ShConverterType::InputImageType::Pointer itkvol = ShConverterType::InputImageType::New(); mitk::CastToItkImage(mitkImage, itkvol); typename ShConverterType::Pointer converter = ShConverterType::New(); converter->SetInput(itkvol); converter->SetToolkit(mitkShImage->GetShConvention()); converter->Update(); output = converter->GetOutput(); break; } case 10: { typedef itk::ShToOdfImageFilter< float, 10 > ShConverterType; typename ShConverterType::InputImageType::Pointer itkvol = ShConverterType::InputImageType::New(); mitk::CastToItkImage(mitkImage, itkvol); typename ShConverterType::Pointer converter = ShConverterType::New(); converter->SetInput(itkvol); converter->SetToolkit(mitkShImage->GetShConvention()); converter->Update(); output = converter->GetOutput(); break; } case 12: { typedef itk::ShToOdfImageFilter< float, 12 > ShConverterType; typename ShConverterType::InputImageType::Pointer itkvol = ShConverterType::InputImageType::New(); mitk::CastToItkImage(mitkImage, itkvol); typename ShConverterType::Pointer converter = ShConverterType::New(); converter->SetInput(itkvol); converter->SetToolkit(mitkShImage->GetShConvention()); converter->Update(); output = converter->GetOutput(); break; } default: mitkThrow() << "SH orders higher than 12 are not supported!"; } return output; } mitk::OdfImage::Pointer mitk::convert::GetOdfFromShImage(mitk::Image::Pointer mitkImage) { mitk::OdfImage::Pointer image = mitk::OdfImage::New(); auto img = GetItkOdfFromShImage(mitkImage); image->InitializeByItk( img.GetPointer() ); image->SetVolume( img->GetBufferPointer() ); return image; } mitk::OdfImage::ItkOdfImageType::Pointer mitk::convert::GetItkOdfFromTensorImage(mitk::Image::Pointer mitkImage) { typedef itk::TensorImageToOdfImageFilter< float, float > FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput( GetItkTensorFromTensorImage(mitkImage) ); filter->Update(); return filter->GetOutput(); } mitk::TensorImage::ItkTensorImageType::Pointer mitk::convert::GetItkTensorFromTensorImage(mitk::Image::Pointer mitkImage) { typedef mitk::ImageToItk< mitk::TensorImage::ItkTensorImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkImage); caster->Update(); return caster->GetOutput(); } mitk::PeakImage::ItkPeakImageType::Pointer mitk::convert::GetItkPeakFromPeakImage(mitk::Image::Pointer mitkImage) { typedef mitk::ImageToItk< mitk::PeakImage::ItkPeakImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkImage); caster->SetCopyMemFlag(true); caster->Update(); return caster->GetOutput(); } mitk::OdfImage::Pointer mitk::convert::GetOdfFromTensorImage(mitk::Image::Pointer mitkImage) { mitk::OdfImage::Pointer image = mitk::OdfImage::New(); auto img = GetItkOdfFromTensorImage(mitkImage); image->InitializeByItk( img.GetPointer() ); image->SetVolume( img->GetBufferPointer() ); return image; } mitk::OdfImage::ItkOdfImageType::Pointer mitk::convert::GetItkOdfFromOdfImage(mitk::Image::Pointer mitkImage) { typedef mitk::ImageToItk< mitk::OdfImage::ItkOdfImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkImage); caster->Update(); return caster->GetOutput(); } vnl_matrix mitk::sh::CalcShBasisForDirections(unsigned int sh_order, vnl_matrix U, bool mrtrix) { vnl_matrix sh_basis = vnl_matrix(U.cols(), (sh_order*sh_order + sh_order + 2)/2 + sh_order ); for(unsigned int i=0; i(sh_order); k+=2) { for(int m=-k; m<=k; m++) { int j = (k*k + k + 2)/2 + m - 1; double phi = U(0,i); double th = U(1,i); sh_basis(i,j) = mitk::sh::Yj(m,k,th,phi, mrtrix); } } } return sh_basis; } unsigned int mitk::sh::ShOrder(int num_coeffs) { int c=3, d=2-2*num_coeffs; int D = c*c-4*d; if (D>0) { int s = (-c+static_cast(sqrt(D)))/2; if (s<0) s = (-c-static_cast(sqrt(D)))/2; return static_cast(s); } else if (D==0) return static_cast(-c/2); return 0; } float mitk::sh::GetValue(const vnl_vector &coefficients, const int &sh_order, const double theta, const double phi, const bool mrtrix) { float val = 0; for(int k=0; k<=sh_order; k+=2) { for(int m=-k; m<=k; m++) { unsigned int j = static_cast((k*k + k + 2)/2 + m - 1); val += coefficients[j] * mitk::sh::Yj(m, k, theta, phi, mrtrix); } } return val; } float mitk::sh::GetValue(const vnl_vector &coefficients, const int &sh_order, const vnl_vector_fixed &dir, const bool mrtrix) { double spherical[3]; mitk::sh::Cart2Sph(dir[0], dir[1], dir[2], spherical); float val = 0; for(int k=0; k<=sh_order; k+=2) { for(int m=-k; m<=k; m++) { int j = (k*k + k + 2)/2 + m - 1; val += coefficients[j] * mitk::sh::Yj(m, k, spherical[1], spherical[0], mrtrix); } } return val; } //------------------------- gradients-function ------------------------------------ -mitk::gradients::GradientDirectionContainerType::Pointer mitk::gradients::ReadBvalsBvecs(std::string bvals_file, std::string bvecs_file, double& reference_bval) +mitk::gradients::GradientDirectionContainerType::ConstPointer mitk::gradients::ReadBvalsBvecs(std::string bvals_file, std::string bvecs_file, double& reference_bval) { mitk::gradients::GradientDirectionContainerType::Pointer directioncontainer = mitk::gradients::GradientDirectionContainerType::New(); std::vector bvec_entries; if (!itksys::SystemTools::FileExists(bvecs_file)) mitkThrow() << "bvecs file not existing: " << bvecs_file; else { std::string line; std::ifstream myfile (bvecs_file.c_str()); if (myfile.is_open()) { while (std::getline(myfile, line)) { std::vector strs; boost::split(strs,line,boost::is_any_of("\t \n")); for (auto token : strs) { if (!token.empty()) { try { bvec_entries.push_back(boost::lexical_cast(token)); } catch(...) { mitkThrow() << "Encountered invalid bvecs file entry >" << token << "<"; } } } } myfile.close(); } else { mitkThrow() << "bvecs file could not be opened: " << bvals_file; } } reference_bval = -1; std::vector bval_entries; if (!itksys::SystemTools::FileExists(bvals_file)) mitkThrow() << "bvals file not existing: " << bvals_file; else { std::string line; std::ifstream myfile (bvals_file.c_str()); if (myfile.is_open()) { while (std::getline(myfile, line)) { std::vector strs; boost::split(strs,line,boost::is_any_of("\t \n")); for (auto token : strs) { if (!token.empty()) { try { bval_entries.push_back(boost::lexical_cast(token)); if (bval_entries.back()>reference_bval) reference_bval = bval_entries.back(); } catch(...) { mitkThrow() << "Encountered invalid bvals file entry >" << token << "<"; } } } } myfile.close(); } else { mitkThrow() << "bvals file could not be opened: " << bvals_file; } } for(unsigned int i=0; i0) { double factor = b_val/reference_bval; if(vec.magnitude() > 0) { vec.normalize(); vec[0] = sqrt(factor)*vec[0]; vec[1] = sqrt(factor)*vec[1]; vec[2] = sqrt(factor)*vec[2]; } } directioncontainer->InsertElement(i,vec); } - return directioncontainer; + return GradientDirectionContainerType::ConstPointer(directioncontainer); } -void mitk::gradients::WriteBvalsBvecs(std::string bvals_file, std::string bvecs_file, GradientDirectionContainerType::Pointer gradients, double reference_bval) +void mitk::gradients::WriteBvalsBvecs(std::string bvals_file, std::string bvecs_file, GradientDirectionContainerType::ConstPointer gradients, double reference_bval) { std::ofstream myfile; myfile.open (bvals_file.c_str()); for(unsigned int i=0; iSize(); i++) { double twonorm = gradients->ElementAt(i).two_norm(); myfile << std::round(reference_bval*twonorm*twonorm) << " "; } myfile.close(); std::ofstream myfile2; myfile2.open (bvecs_file.c_str()); for(int j=0; j<3; j++) { for(unsigned int i=0; iSize(); i++) { GradientDirectionType direction = gradients->ElementAt(i); direction.normalize(); myfile2 << direction.get(j) << " "; } myfile2 << std::endl; } } -std::vector mitk::gradients::GetAllUniqueDirections(const BValueMap & refBValueMap, GradientDirectionContainerType *refGradientsContainer ) +std::vector mitk::gradients::GetAllUniqueDirections(const BValueMap & refBValueMap, GradientDirectionContainerType::ConstPointer refGradientsContainer ) { IndiciesVector directioncontainer; auto mapIterator = refBValueMap.begin(); if(refBValueMap.find(0) != refBValueMap.end() && refBValueMap.size() > 1) mapIterator++; //skip bzero Values for( ; mapIterator != refBValueMap.end(); mapIterator++){ IndiciesVector currentShell = mapIterator->second; while(currentShell.size()>0) { unsigned int wntIndex = currentShell.back(); currentShell.pop_back(); auto containerIt = directioncontainer.begin(); bool directionExist = false; while(containerIt != directioncontainer.end()) { if (fabs(dot_product(refGradientsContainer->ElementAt(*containerIt), refGradientsContainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { directioncontainer.push_back(wntIndex); } } } return directioncontainer; } bool mitk::gradients::CheckForDifferingShellDirections(const BValueMap & refBValueMap, GradientDirectionContainerType::ConstPointer refGradientsContainer) { auto mapIterator = refBValueMap.begin(); if(refBValueMap.find(0) != refBValueMap.end() && refBValueMap.size() > 1) mapIterator++; //skip bzero Values for( ; mapIterator != refBValueMap.end(); mapIterator++){ auto mapIterator_2 = refBValueMap.begin(); if(refBValueMap.find(0) != refBValueMap.end() && refBValueMap.size() > 1) mapIterator_2++; //skip bzero Values for( ; mapIterator_2 != refBValueMap.end(); mapIterator_2++){ if(mapIterator_2 == mapIterator) continue; IndiciesVector currentShell = mapIterator->second; IndiciesVector testShell = mapIterator_2->second; for (unsigned int i = 0; i< currentShell.size(); i++) if (fabs(dot_product(refGradientsContainer->ElementAt(currentShell[i]), refGradientsContainer->ElementAt(testShell[i]))) <= 0.9998) { return true; } } } return false; } vnl_matrix mitk::gradients::ComputeSphericalFromCartesian(const IndiciesVector & refShell, const GradientDirectionContainerType * refGradientsContainer) { vnl_matrix Q(3, refShell.size()); Q.fill(0.0); for(unsigned int i = 0; i < refShell.size(); i++) { GradientDirectionType dir = refGradientsContainer->ElementAt(refShell[i]); double x = dir.normalize().get(0); double y = dir.normalize().get(1); double z = dir.normalize().get(2); double cart[3]; mitk::sh::Cart2Sph(x,y,z,cart); Q(0,i) = cart[0]; Q(1,i) = cart[1]; Q(2,i) = cart[2]; } return Q; } vnl_matrix mitk::gradients::ComputeSphericalHarmonicsBasis(const vnl_matrix & QBallReference, const unsigned int & LOrder) { vnl_matrix SHBasisOutput(QBallReference.cols(), (LOrder+1)*(LOrder+2)*0.5); SHBasisOutput.fill(0.0); for(unsigned int i=0; i 1){ mapIterator++; //skip bzero Values vnl_vector_fixed vec; vec.fill(0.0); directioncontainer->push_back(vec); } for( ; mapIterator != bValueMap.end(); mapIterator++){ IndiciesVector currentShell = mapIterator->second; while(currentShell.size()>0) { unsigned int wntIndex = currentShell.back(); currentShell.pop_back(); mitk::gradients::GradientDirectionContainerType::Iterator containerIt = directioncontainer->Begin(); bool directionExist = false; while(containerIt != directioncontainer->End()) { if (fabs(dot_product(containerIt.Value(), origninalGradentcontainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { GradientDirectionType dir(origninalGradentcontainer->ElementAt(wntIndex)); directioncontainer->push_back(dir.normalize()); } } } return directioncontainer; } diff --git a/Modules/DiffusionCore/mitkDiffusionFunctionCollection.h b/Modules/DiffusionCore/mitkDiffusionFunctionCollection.h index ed135c5..518da46 100644 --- a/Modules/DiffusionCore/mitkDiffusionFunctionCollection.h +++ b/Modules/DiffusionCore/mitkDiffusionFunctionCollection.h @@ -1,259 +1,259 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef __mitkDiffusionFunctionCollection_h_ #define __mitkDiffusionFunctionCollection_h_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mitk{ class MITKDIFFUSIONCORE_EXPORT imv { public: static std::vector< std::pair< itk::Index<3>, double > > IntersectImage(const itk::Vector& spacing, itk::Index<3>& si, itk::Index<3>& ei, itk::ContinuousIndex& sf, itk::ContinuousIndex& ef); static itk::Point GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = static_cast(point[0]); itkPoint[1] = static_cast(point[1]); itkPoint[2] = static_cast(point[2]); return itkPoint; } template< class TType > static itk::Point GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = static_cast(point[0]); itkPoint[1] = static_cast(point[1]); itkPoint[2] = static_cast(point[2]); return itkPoint; } template< class TType > static itk::Vector GetItkVector(double point[3]) { itk::Vector itkVector; itkVector[0] = static_cast(point[0]); itkVector[1] = static_cast(point[1]); itkVector[2] = static_cast(point[2]); return itkVector; } template< class TPixelType, class TOutPixelType=TPixelType > static TOutPixelType GetImageValue(const itk::Point& itkP, bool interpolate, typename itk::LinearInterpolateImageFunction< itk::Image< TPixelType, 3 >, float >::Pointer interpolator) { if (interpolator==nullptr) return 0.0; itk::ContinuousIndex< float, 3> cIdx; interpolator->ConvertPointToContinuousIndex(itkP, cIdx); if (interpolator->IsInsideBuffer(cIdx)) { if (interpolate) return interpolator->EvaluateAtContinuousIndex(cIdx); else { itk::Index<3> idx; interpolator->ConvertContinuousIndexToNearestIndex(cIdx, idx); return interpolator->EvaluateAtIndex(idx); } } else return 0.0; } template< class TPixelType=unsigned char > static bool IsInsideMask(const itk::Point& itkP, bool interpolate, typename itk::LinearInterpolateImageFunction< itk::Image< TPixelType, 3 >, float >::Pointer interpolator, float threshold=0.5) { if (interpolator==nullptr) return false; itk::ContinuousIndex< float, 3> cIdx; interpolator->ConvertPointToContinuousIndex(itkP, cIdx); if (interpolator->IsInsideBuffer(cIdx)) { float value = 0.0; if (interpolate) value = interpolator->EvaluateAtContinuousIndex(cIdx); else { itk::Index<3> idx; interpolator->ConvertContinuousIndexToNearestIndex(cIdx, idx); value = interpolator->EvaluateAtIndex(idx); } if (value>=threshold) return true; } return false; } template< class TType=float > static vnl_matrix_fixed< TType, 3, 3 > GetRotationMatrixVnl(TType rx, TType ry, TType rz) { rx = rx*itk::Math::pi/180; ry = ry*itk::Math::pi/180; rz = rz*itk::Math::pi/180; vnl_matrix_fixed< TType, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< TType, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< TType, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; vnl_matrix_fixed< TType, 3, 3 > rot = rotZ*rotY*rotX; return rot; } template< class TType=float > static itk::Matrix< TType, 3, 3 > GetRotationMatrixItk(TType rx, TType ry, TType rz) { rx = rx*itk::Math::pi/180; ry = ry*itk::Math::pi/180; rz = rz*itk::Math::pi/180; itk::Matrix< TType, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; itk::Matrix< TType, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; itk::Matrix< TType, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< TType, 3, 3 > rot = rotZ*rotY*rotX; return rot; } }; class MITKDIFFUSIONCORE_EXPORT convert { public: static mitk::OdfImage::ItkOdfImageType::Pointer GetItkOdfFromTensorImage(mitk::Image::Pointer mitkImage); static mitk::OdfImage::Pointer GetOdfFromTensorImage(mitk::Image::Pointer mitkImage); static mitk::TensorImage::ItkTensorImageType::Pointer GetItkTensorFromTensorImage(mitk::Image::Pointer mitkImage); static mitk::PeakImage::ItkPeakImageType::Pointer GetItkPeakFromPeakImage(mitk::Image::Pointer mitkImage); template static typename itk::Image< itk::Vector, 3>::Pointer GetItkShFromShImage(mitk::Image::Pointer mitkImage) { mitk::ShImage::Pointer mitkShImage = dynamic_cast(mitkImage.GetPointer()); if (mitkShImage.IsNull()) mitkThrow() << "Input image is not a SH image!"; typename itk::Image< itk::Vector, 3>::Pointer itkvol; mitk::CastToItkImage(mitkImage, itkvol); return itkvol; } static mitk::OdfImage::ItkOdfImageType::Pointer GetItkOdfFromShImage(mitk::Image::Pointer mitkImage); static mitk::OdfImage::Pointer GetOdfFromShImage(mitk::Image::Pointer mitkImage); static mitk::OdfImage::ItkOdfImageType::Pointer GetItkOdfFromOdfImage(mitk::Image::Pointer mitkImage); }; class MITKDIFFUSIONCORE_EXPORT sh { public: static double factorial(int number); static void Cart2Sph(double x, double y, double z, double* spherical); static vnl_vector_fixed Sph2Cart(const double& theta, const double& phi, const double& rad); static double legendre0(int l); static double spherical_harmonic(int m,int l,double theta,double phi, bool complexPart); static double Yj(int m, int k, float theta, float phi, bool mrtrix=true); static vnl_matrix CalcShBasisForDirections(unsigned int sh_order, vnl_matrix U, bool mrtrix=true); static float GetValue(const vnl_vector& coefficients, const int& sh_order, const vnl_vector_fixed& dir, const bool mrtrix); static float GetValue(const vnl_vector &coefficients, const int &sh_order, const double theta, const double phi, const bool mrtrix); static unsigned int ShOrder(int num_coeffs); template static void SampleOdf(const vnl_vector& coefficients, itk::OrientationDistributionFunction& odf) { auto dirs = odf.GetDirections(); auto basis = CalcShBasisForDirections(ShOrder(coefficients.size()), *dirs); auto odf_vals = basis * coefficients; for (unsigned int i=0; i IndiciesVector; typedef mitk::BValueMapProperty::BValueMap BValueMap; typedef DiffusionPropertyHelper::GradientDirectionsContainerType GradientDirectionContainerType; typedef DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; public: - static GradientDirectionContainerType::Pointer ReadBvalsBvecs(std::string bvals_file, std::string bvecs_file, double& reference_bval); - static void WriteBvalsBvecs(std::string bvals_file, std::string bvecs_file, GradientDirectionContainerType::Pointer gradients, double reference_bval); - static std::vector GetAllUniqueDirections(const BValueMap &bValueMap, GradientDirectionContainerType *refGradientsContainer ); + static GradientDirectionContainerType::ConstPointer ReadBvalsBvecs(std::string bvals_file, std::string bvecs_file, double& reference_bval); + static void WriteBvalsBvecs(std::string bvals_file, std::string bvecs_file, GradientDirectionContainerType::ConstPointer gradients, double reference_bval); + static std::vector GetAllUniqueDirections(const BValueMap &bValueMap, GradientDirectionContainerType::ConstPointer refGradientsContainer ); static bool CheckForDifferingShellDirections(const BValueMap &bValueMap, GradientDirectionContainerType::ConstPointer refGradientsContainer); static vnl_matrix ComputeSphericalHarmonicsBasis(const vnl_matrix & QBallReference, const unsigned int & LOrder); static vnl_matrix ComputeSphericalFromCartesian(const IndiciesVector & refShell, const GradientDirectionContainerType * refGradientsContainer); static GradientDirectionContainerType::Pointer CreateNormalizedUniqueGradientDirectionContainer(const BValueMap &bValueMap, const GradientDirectionContainerType * origninalGradentcontainer); }; } #endif //__mitkDiffusionFunctionCollection_h_ diff --git a/Modules/DiffusionIO/ReaderWriter/mitkDiffusionImageNiftiReader.cpp b/Modules/DiffusionIO/ReaderWriter/mitkDiffusionImageNiftiReader.cpp index 14cc39c..1ab2830 100644 --- a/Modules/DiffusionIO/ReaderWriter/mitkDiffusionImageNiftiReader.cpp +++ b/Modules/DiffusionIO/ReaderWriter/mitkDiffusionImageNiftiReader.cpp @@ -1,487 +1,489 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef __mitkDiffusionImageNiftiReader_cpp #define __mitkDiffusionImageNiftiReader_cpp #include "mitkDiffusionImageNiftiReader.h" #include #include // Diffusion properties #include #include #include #include // ITK includes #include #include #include "itksys/SystemTools.hxx" #include "itkImageFileReader.h" #include "itkMetaDataObject.h" #include "itkNiftiImageIO.h" #include #include #include #include "mitkCustomMimeType.h" #include "mitkDiffusionIOMimeTypes.h" #include #include #include #include #include "mitkIOUtil.h" #include #include #include #include namespace mitk { DiffusionImageNiftiReader:: DiffusionImageNiftiReader(const DiffusionImageNiftiReader & other) : AbstractFileReader(other) { } DiffusionImageNiftiReader* DiffusionImageNiftiReader::Clone() const { return new DiffusionImageNiftiReader(*this); } DiffusionImageNiftiReader:: ~DiffusionImageNiftiReader() {} DiffusionImageNiftiReader:: DiffusionImageNiftiReader() : mitk::AbstractFileReader( CustomMimeType( mitk::DiffusionIOMimeTypes::DWI_NIFTI_MIMETYPE() ), mitk::DiffusionIOMimeTypes::DWI_NIFTI_MIMETYPE_DESCRIPTION() ) { Options defaultOptions; defaultOptions["Apply image rotation to gradients"] = true; this->SetDefaultOptions(defaultOptions); m_ServiceReg = this->RegisterService(); } std::vector > DiffusionImageNiftiReader:: DoRead() { std::vector > result; // Since everything is completely read in GenerateOutputInformation() it is stored // in a cache variable. A timestamp is associated. // If the timestamp of the cache variable is newer than the MTime, we only need to // assign the cache variable to the DataObject. // Otherwise, the tree must be read again from the file and OuputInformation must // be updated! if(m_OutputCache.IsNull()) InternalRead(); result.push_back(m_OutputCache.GetPointer()); return result; } void DiffusionImageNiftiReader::InternalRead() { OutputType::Pointer outputForCache = OutputType::New(); if ( this->GetInputLocation() == "") { throw itk::ImageFileReaderException(__FILE__, __LINE__, "Sorry, the filename to be read is empty!"); } else { try { mitk::LocaleSwitch localeSwitch("C"); MITK_INFO << "DiffusionImageNiftiReader: reading image information"; VectorImageType::Pointer itkVectorImage; std::string ext = this->GetMimeType()->GetExtension( this->GetInputLocation() ); ext = itksys::SystemTools::LowerCase( ext ); itk::Bruker2dseqImageIO::Pointer bruker_io = itk::Bruker2dseqImageIO::New(); typedef itk::Image ImageType4D; ImageType4D::Pointer img4 = ImageType4D::New(); bool bruker = false; if(ext == ".nii" || ext == ".nii.gz") { // create reader and read file itk::NiftiImageIO::Pointer io2 = itk::NiftiImageIO::New(); if (io2->CanReadFile(this->GetInputLocation().c_str())) { typedef itk::ImageFileReader FileReaderType; FileReaderType::Pointer reader = FileReaderType::New(); reader->SetFileName( this->GetInputLocation() ); reader->SetImageIO(io2); reader->Update(); img4 = reader->GetOutput(); } else { vtkSmartPointer reader = vtkSmartPointer::New(); if (reader->CanReadFile(this->GetInputLocation().c_str())) { reader->SetFileName(this->GetInputLocation().c_str()); reader->SetTimeAsVector(true); reader->Update(); auto vtk_image = reader->GetOutput(); auto header = reader->GetNIFTIHeader(); auto dim = header->GetDim(0); auto matrix = reader->GetQFormMatrix(); if (matrix == nullptr) matrix = reader->GetSFormMatrix(); itk::Matrix direction; direction.SetIdentity(); itk::Matrix ras_lps; ras_lps.SetIdentity(); ras_lps[0][0] = -1; ras_lps[1][1] = -1; if (matrix != nullptr) { for (int r=0; rGetElement(r, c); } direction = direction*ras_lps; itk::Vector< double, 4 > spacing; spacing.Fill(1.0); vtk_image->GetSpacing(spacing.GetDataPointer()); itk::Point< double, 4 > origin; origin.Fill(0.0); vtk_image->GetOrigin(origin.GetDataPointer()); itk::ImageRegion< 4 > region; for (int i=0; i<4; ++i) if (iGetDim(i+1)); else region.SetSize(i, 1); img4->SetSpacing( spacing ); img4->SetOrigin( origin ); img4->SetDirection( direction ); img4->SetRegions( region ); img4->Allocate(); img4->FillBuffer(0); switch (header->GetDim(0)) { case 4: for (int g=0; gGetDim(4); g++) for (int z=0; zGetDim(3); z++) for (int y=0; yGetDim(2); y++) for (int x=0; xGetDim(1); x++) { double val = vtk_image->GetScalarComponentAsDouble(x, y, z, g); ImageType4D::IndexType idx; idx[0] = x; idx[1] = y; idx[2] = z; idx[3] = g; img4->SetPixel(idx, val); } break; default: mitkThrow() << "Image dimension " << header->GetDim(0) << " not supported!"; break; } } } } else if(bruker_io->CanReadFile(this->GetInputLocation().c_str())) { MITK_INFO << "Reading bruker 2dseq file"; typedef itk::ImageFileReader FileReaderType; FileReaderType::Pointer reader = FileReaderType::New(); reader->SetFileName( this->GetInputLocation() ); reader->SetImageIO(bruker_io); reader->Update(); img4 = reader->GetOutput(); bruker = true; } // convert 4D file to vector image itkVectorImage = VectorImageType::New(); VectorImageType::SpacingType spacing; ImageType4D::SpacingType spacing4 = img4->GetSpacing(); for(int i=0; i<3; i++) spacing[i] = spacing4[i]; itkVectorImage->SetSpacing( spacing ); // Set the image spacing VectorImageType::PointType origin; ImageType4D::PointType origin4 = img4->GetOrigin(); for(int i=0; i<3; i++) origin[i] = origin4[i]; itkVectorImage->SetOrigin( origin ); // Set the image origin VectorImageType::DirectionType direction; if (bruker) { MITK_INFO << "Setting image matrix to identity (bruker hack!!!)"; direction.SetIdentity(); } else { ImageType4D::DirectionType direction4 = img4->GetDirection(); for(int i=0; i<3; i++) for(int j=0; j<3; j++) direction[i][j] = direction4[i][j]; } itkVectorImage->SetDirection( direction ); // Set the image direction VectorImageType::RegionType region; ImageType4D::RegionType region4 = img4->GetLargestPossibleRegion(); VectorImageType::RegionType::SizeType size; ImageType4D::RegionType::SizeType size4 = region4.GetSize(); for(int i=0; i<3; i++) size[i] = size4[i]; VectorImageType::RegionType::IndexType index; ImageType4D::RegionType::IndexType index4 = region4.GetIndex(); for(int i=0; i<3; i++) index[i] = index4[i]; region.SetSize(size); region.SetIndex(index); itkVectorImage->SetRegions( region ); itkVectorImage->SetVectorLength(size4[3]); itkVectorImage->Allocate(); itk::ImageRegionIterator it ( itkVectorImage, itkVectorImage->GetLargestPossibleRegion() ); typedef VectorImageType::PixelType VecPixType; for (it.GoToBegin(); !it.IsAtEnd(); ++it) { VecPixType vec = it.Get(); VectorImageType::IndexType currentIndex = it.GetIndex(); for(int i=0; i<3; i++) index4[i] = currentIndex[i]; for(unsigned int ind=0; indGetPixel(index4); } it.Set(vec); } // Diffusion Image information START - GradientDirectionContainerType::Pointer DiffusionVectors = GradientDirectionContainerType::New(); + GradientDirectionContainerType::ConstPointer DiffusionVectors; MeasurementFrameType MeasurementFrame; MeasurementFrame.set_identity(); double BValue = -1; // Diffusion Image information END if(ext == ".nii" || ext == ".nii.gz") { std::string base_path = itksys::SystemTools::GetFilenamePath(this->GetInputLocation()); std::string base = this->GetMimeType()->GetFilenameWithoutExtension(this->GetInputLocation()); if (!base_path.empty()) { base = base_path + "/" + base; base_path += "/"; } // check for possible file names std::string bvals_file, bvecs_file; if (itksys::SystemTools::FileExists(base+".bvals")) bvals_file = base+".bvals"; else if (itksys::SystemTools::FileExists(base+".bval")) bvals_file = base+".bval"; else if (itksys::SystemTools::FileExists(base_path+"bvals")) bvals_file = base_path + "bvals"; else if (itksys::SystemTools::FileExists(base_path+"bval")) bvals_file = base_path + "bval"; if (itksys::SystemTools::FileExists(base+".bvecs")) bvecs_file = base+".bvecs"; else if (itksys::SystemTools::FileExists(base+".bvec")) bvals_file = base+".bvec"; else if (itksys::SystemTools::FileExists(base_path+"bvecs")) bvecs_file = base_path + "bvecs"; else if (itksys::SystemTools::FileExists(base_path+"bvec")) bvecs_file = base_path + "bvec"; DiffusionVectors = mitk::gradients::ReadBvalsBvecs(bvals_file, bvecs_file, BValue); } else { MITK_INFO << "Parsing bruker method file for gradient information."; std::string base_path = itksys::SystemTools::GetFilenamePath(this->GetInputLocation()); std::string base = this->GetMimeType()->GetFilenameWithoutExtension(this->GetInputLocation()); base_path += "/../../"; std::string method_file = base_path + "method"; int g_count = 0; int num_gradients = 0; int num_b = 0; std::vector grad_values; std::vector b_values; std::fstream newfile; newfile.open(method_file,ios::in); std::string line; while(getline(newfile, line)) { std::vector result; boost::split(result, line, boost::is_any_of("=")); // check if current section is b-value section if (result.size()==2 && result.at(0)=="##$PVM_DwEffBval") { std::vector vec_spec; boost::split(vec_spec, result.at(1), boost::is_any_of("( )"), boost::token_compress_on); for (auto a : vec_spec) if (!a.empty()) { num_b = boost::lexical_cast(a); MITK_INFO << "Found " << num_b << " b-values"; break; } continue; } // check if current section is gradient vector value section if (result.size()==2 && result.at(0)=="##$PVM_DwGradVec") { std::vector vec_spec; boost::split(vec_spec, result.at(1), boost::is_any_of("( ,)"), boost::token_compress_on); for (auto a : vec_spec) if (!a.empty()) { num_gradients = boost::lexical_cast(a); MITK_INFO << "Found " << num_gradients << " gradients"; break; } continue; } // get gradient vector values if (num_gradients>0) { std::vector grad_values_line; boost::split(grad_values_line, line, boost::is_any_of(" ")); for (auto a : grad_values_line) if (!a.empty()) { grad_values.push_back(boost::lexical_cast(a)); ++g_count; if (g_count%3==0) --num_gradients; } } // get b-values if (num_b>0) { std::vector b_values_line; boost::split(b_values_line, line, boost::is_any_of(" ")); for (auto a : b_values_line) if (!a.empty()) { b_values.push_back(boost::lexical_cast(a)); if (b_values.back()>BValue) BValue = b_values.back(); num_b--; } } } newfile.close(); + GradientDirectionContainerType::Pointer temp = GradientDirectionContainerType::New(); if (!b_values.empty() && grad_values.size()==b_values.size()*3) { // MITK_INFO << "Switching gradient vector x and y (bruker hack!!!)"; for(unsigned int i=0; i0) { double factor = b_val/BValue; if(vec.magnitude() > 0) { vec.normalize(); vec[0] = sqrt(factor)*vec[0]; vec[1] = sqrt(factor)*vec[1]; vec[2] = sqrt(factor)*vec[2]; } } - DiffusionVectors->InsertElement(i,vec); + temp->InsertElement(i,vec); } } else { mitkThrow() << "No valid gradient information found."; } + DiffusionVectors = temp; } outputForCache = mitk::GrabItkImageMemory( itkVectorImage); // create BValueMap mitk::BValueMapProperty::BValueMap BValueMap = mitk::BValueMapProperty::CreateBValueMap(DiffusionVectors,BValue); mitk::DiffusionPropertyHelper::SetOriginalGradientContainer(outputForCache, DiffusionVectors); mitk::DiffusionPropertyHelper::SetMeasurementFrame(outputForCache, MeasurementFrame); mitk::DiffusionPropertyHelper::SetBValueMap(outputForCache, BValueMap); mitk::DiffusionPropertyHelper::SetReferenceBValue(outputForCache, BValue); mitk::DiffusionPropertyHelper::SetApplyMatrixToGradients(outputForCache, us::any_cast(this->GetOptions()["Apply image rotation to gradients"])); mitk::DiffusionPropertyHelper::InitializeImage(outputForCache); // Since we have already read the tree, we can store it in a cache variable // so that it can be assigned to the DataObject in GenerateData(); m_OutputCache = outputForCache; m_CacheTime.Modified(); } catch(std::exception& e) { MITK_INFO << "Std::Exception while reading file!!"; MITK_INFO << e.what(); throw itk::ImageFileReaderException(__FILE__, __LINE__, e.what()); } catch(...) { MITK_INFO << "Exception while reading file!!"; throw itk::ImageFileReaderException(__FILE__, __LINE__, "Sorry, an error occurred while reading the requested file!"); } } } } //namespace MITK #endif diff --git a/Modules/MriSimulation/SignalModels/mitkDiffusionSignalModel.h b/Modules/MriSimulation/SignalModels/mitkDiffusionSignalModel.h index a08aaba..46cd860 100644 --- a/Modules/MriSimulation/SignalModels/mitkDiffusionSignalModel.h +++ b/Modules/MriSimulation/SignalModels/mitkDiffusionSignalModel.h @@ -1,112 +1,112 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef _MITK_DiffusionSignalModel_H #define _MITK_DiffusionSignalModel_H #include #include #include #include #include #include namespace mitk { /** * \brief Abstract class for diffusion signal models * */ template< class ScalarType = double > class DiffusionSignalModel { public: DiffusionSignalModel() : m_T2(100) , m_T1(0) , m_BValue(1000) {} ~DiffusionSignalModel(){} typedef itk::Image ItkDoubleImgType; typedef itk::VariableLengthVector< ScalarType > PixelType; typedef itk::Vector GradientType; typedef std::vector GradientListType; typedef itk::Statistics::MersenneTwisterRandomVariateGenerator ItkRandGenType; typedef mitk::DiffusionPropertyHelper DPH; /** Realizes actual signal generation. Has to be implemented in subclass. **/ virtual PixelType SimulateMeasurement(GradientType& fiberDirection) = 0; virtual ScalarType SimulateMeasurement(unsigned int dir, GradientType& fiberDirection) = 0; - void SetGradientList(DPH::GradientDirectionsContainerType* gradients) + void SetGradientList(DPH::GradientDirectionsContainerType::ConstPointer gradients) { m_GradientList.clear(); for ( unsigned int i=0; iSize(); ++i ) { DPH::GradientDirectionType g_vnl = gradients->GetElement(i); GradientType g_itk; g_itk[0] = g_vnl[0]; g_itk[1] = g_vnl[1]; g_itk[2] = g_vnl[2]; m_GradientList.push_back(g_itk); } } void SetGradientList(GradientListType gradientList) { this->m_GradientList = gradientList; } GradientListType GetGradientList(){ return m_GradientList; } GradientType GetGradientDirection(int i) { return m_GradientList.at(i); } void SetT2(double T2) { m_T2 = T2; } double GetT2() { return m_T2; } void SetT1(double T1) { m_T1 = T1; } double GetT1() { return m_T1; } void SetVolumeFractionImage(ItkDoubleImgType::Pointer img){ m_VolumeFractionImage = img; } ItkDoubleImgType::Pointer GetVolumeFractionImage(){ return m_VolumeFractionImage; } void SetRandomGenerator(ItkRandGenType::Pointer randgen){ m_RandGen = randgen; } ItkRandGenType::Pointer GetRandomGenerator(){ return m_RandGen; } void SetSeed(int s) ///< set seed for random generator { if (m_RandGen.IsNull()) m_RandGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); m_RandGen->SetSeed(s); } void SetBvalue(double bValue) { m_BValue = bValue; } ///< b-value used to generate the artificial signal double GetBvalue() { return m_BValue; } unsigned int m_CompartmentId; ///< GUI flag. Which compartment is this model assigned to? protected: GradientListType m_GradientList; ///< Diffusion gradient direction container double m_T2; ///< Tissue specific transversal relaxation time double m_T1; ///< Tissue specific longitudinal relaxation time ItkDoubleImgType::Pointer m_VolumeFractionImage; ///< Tissue specific volume fraction for each voxel (only relevant for non fiber compartments) ItkRandGenType::Pointer m_RandGen; ///< Random number generator double m_BValue; }; } #endif diff --git a/Modules/MriSimulation/SignalModels/mitkRawShModel.cpp b/Modules/MriSimulation/SignalModels/mitkRawShModel.cpp index ce830a0..575efa6 100644 --- a/Modules/MriSimulation/SignalModels/mitkRawShModel.cpp +++ b/Modules/MriSimulation/SignalModels/mitkRawShModel.cpp @@ -1,394 +1,394 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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 #include #include #include #include #include #include #include #include #include #include #include using namespace mitk; using namespace boost::math; template< class ScalarType > RawShModel< ScalarType >::RawShModel() : m_ShOrder(0) , m_ModelIndex(-1) , m_MaxNumKernels(1000) { this->m_RandGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); this->m_RandGen->SetSeed(); m_AdcRange.first = 0; m_AdcRange.second = 0.004; m_FaRange.first = 0; m_FaRange.second = 1; } template< class ScalarType > RawShModel< ScalarType >::~RawShModel() { } template< class ScalarType > void RawShModel< ScalarType >::Clear() { m_ShCoefficients.clear(); m_PrototypeMaxDirection.clear(); m_B0Signal.clear(); } template< class ScalarType > void RawShModel< ScalarType >::RandomModel() { m_ModelIndex = this->m_RandGen->GetIntegerVariate(m_B0Signal.size()-1); } template< class ScalarType > unsigned int RawShModel< ScalarType >::GetNumberOfKernels() { return m_B0Signal.size(); } template< class ScalarType > bool RawShModel< ScalarType >::SampleKernels(Image::Pointer diffImg, ItkUcharImageType::Pointer maskImage, TensorImageType::Pointer tensorImage, QballFilterType::CoefficientImageType::Pointer itkFeatureImage, ItkDoubleImageType::Pointer adcImage) { if (diffImg.IsNull()) return false; typedef itk::VectorImage ITKDiffusionImageType; ITKDiffusionImageType::Pointer itkVectorImagePointer = ITKDiffusionImageType::New(); mitk::CastToItkImage(diffImg, itkVectorImagePointer); const int shOrder = 2; if (tensorImage.IsNull()) { typedef itk::DiffusionTensor3DReconstructionImageFilter< short, short, double > TensorReconstructionImageFilterType; TensorReconstructionImageFilterType::Pointer filter = TensorReconstructionImageFilterType::New(); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(diffImg)); - filter->SetGradientImage(mitk::DiffusionPropertyHelper::GetGradientContainer(diffImg), itkVectorImagePointer ); + filter->SetGradientImage(dynamic_cast(diffImg->GetProperty(mitk::DiffusionPropertyHelper::GetGradientContainerPropertyName().c_str()).GetPointer())->GetGradientDirectionsContainerCopy(), itkVectorImagePointer ); filter->Update(); tensorImage = filter->GetOutput(); } const int NumCoeffs = (shOrder*shOrder + shOrder + 2)/2 + shOrder; if (itkFeatureImage.IsNull()) { QballFilterType::Pointer qballfilter = QballFilterType::New(); qballfilter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(diffImg)); qballfilter->SetGradientImage(mitk::DiffusionPropertyHelper::GetGradientContainer(diffImg), itkVectorImagePointer ); qballfilter->SetLambda(0.006); qballfilter->SetNormalizationMethod(QballFilterType::QBAR_RAW_SIGNAL); qballfilter->Update(); itkFeatureImage = qballfilter->GetCoefficientImage(); } if (adcImage.IsNull()) { itk::AdcImageFilter< short, double >::Pointer adcFilter = itk::AdcImageFilter< short, double >::New(); adcFilter->SetInput(itkVectorImagePointer); adcFilter->SetGradientDirections(mitk::DiffusionPropertyHelper::GetGradientContainer(diffImg)); adcFilter->SetB_value(mitk::DiffusionPropertyHelper::GetReferenceBValue(diffImg)); adcFilter->Update(); adcImage = adcFilter->GetOutput(); } int b0Index = 0; for (unsigned int i=0; iSize(); i++) if (mitk::DiffusionPropertyHelper::GetOriginalGradientContainer(diffImg)->GetElement(i).magnitude()<0.001 ) { b0Index = i; break; } double max = 0; { itk::ImageRegionIterator< itk::VectorImage< short, 3 > > it(itkVectorImagePointer, itkVectorImagePointer->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { if (maskImage.IsNotNull() && maskImage->GetPixel(it.GetIndex())<=0) { ++it; continue; } if (it.Get()[b0Index]>max) max = it.Get()[b0Index]; ++it; } } MITK_INFO << "Sampling signal kernels."; unsigned int count = 0; itk::ImageRegionIterator< itk::Image< itk::DiffusionTensor3D< double >, 3 > > it(tensorImage, tensorImage->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { bool skipPixel = false; if (maskImage.IsNotNull() && maskImage->GetPixel(it.GetIndex())<=0) { ++it; continue; } for (unsigned int i=0; iSize(); i++) { if (itkVectorImagePointer->GetPixel(it.GetIndex())[i]!=itkVectorImagePointer->GetPixel(it.GetIndex())[i] || itkVectorImagePointer->GetPixel(it.GetIndex())[i]<=0 || itkVectorImagePointer->GetPixel(it.GetIndex())[i]>itkVectorImagePointer->GetPixel(it.GetIndex())[b0Index]) { skipPixel = true; break; } } if (skipPixel) { ++it; continue; } typedef itk::DiffusionTensor3D TensorType; TensorType::EigenValuesArrayType eigenvalues; TensorType::EigenVectorsMatrixType eigenvectors; TensorType tensor = it.Get(); double FA = tensor.GetFractionalAnisotropy(); double ADC = adcImage->GetPixel(it.GetIndex()); QballFilterType::CoefficientImageType::PixelType itkv = itkFeatureImage->GetPixel(it.GetIndex()); vnl_vector_fixed< double, NumCoeffs > coeffs; for (unsigned int c=0; cGetMaxNumKernels()>this->GetNumberOfKernels() && FA>m_FaRange.first && FAm_AdcRange.first && ADCSetShCoefficients( coeffs, (double)itkVectorImagePointer->GetPixel(it.GetIndex())[b0Index]/max )) { tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); itk::Vector dir; dir[0] = eigenvectors(2, 0); dir[1] = eigenvectors(2, 1); dir[2] = eigenvectors(2, 2); m_PrototypeMaxDirection.push_back(dir); count++; MITK_INFO << "KERNEL: " << it.GetIndex() << " (" << count << ")"; } } ++it; } if (m_ShCoefficients.size()>0) return true; return false; } // convert cartesian to spherical coordinates template< class ScalarType > vnl_matrix RawShModel::Cart2Sph(GradientListType &gradients ) { vnl_matrix sphCoords; sphCoords.set_size(gradients.size(), 2); sphCoords.fill(0.0); for (unsigned int i=0; i 0.0001 ) { gradients[i].Normalize(); sphCoords(i,0) = acos(gradients[i][2]); // theta sphCoords(i,1) = atan2(gradients[i][1], gradients[i][0]); // phi } } return sphCoords; } template< class ScalarType > vnl_matrix RawShModel< ScalarType >::SetFiberDirection(GradientType& fiberDirection) { RandomModel(); GradientType axis = itk::CrossProduct(fiberDirection, m_PrototypeMaxDirection.at(m_ModelIndex)); axis.Normalize(); vnl_quaternion rotation(axis.GetVnlVector(), acos(dot_product(fiberDirection.GetVnlVector(), m_PrototypeMaxDirection.at(m_ModelIndex).GetVnlVector()))); rotation.normalize(); GradientListType gradients; for (unsigned int i=0; im_GradientList.size(); i++) { GradientType dir = this->m_GradientList.at(i); if( dir.GetNorm() > 0.0001 ) { dir.Normalize(); vnl_vector_fixed< double, 3 > vnlDir = rotation.rotate(dir.GetVnlVector()); dir[0] = vnlDir[0]; dir[1] = vnlDir[1]; dir[2] = vnlDir[2]; dir.Normalize(); } gradients.push_back(dir); } return Cart2Sph( gradients ); } template< class ScalarType > bool RawShModel< ScalarType >::SetShCoefficients(vnl_vector< double > shCoefficients, double b0 ) { m_ShOrder = 2; while ( (m_ShOrder*m_ShOrder + m_ShOrder + 2)/2 + m_ShOrder <= shCoefficients.size() ) m_ShOrder += 2; m_ShOrder -= 2; m_ModelIndex = m_B0Signal.size(); m_B0Signal.push_back(b0); m_ShCoefficients.push_back(shCoefficients); // itk::OrientationDistributionFunction odf; // GradientListType gradients; // for (unsigned int i=0; im_GradientList ); // PixelType signal = SimulateMeasurement(); // int minDirIdx = 0; // double min = itk::NumericTraits::max(); // for (unsigned int i=0; ib0 || signal[i]<0) // { // MITK_INFO << "Corrupted signal value detected. Kernel rejected."; // m_B0Signal.pop_back(); // m_ShCoefficients.pop_back(); // return false; // } // if (signal[i]m_GradientList.at(minDirIdx); // maxDir.Normalize(); // m_PrototypeMaxDirection.push_back(maxDir); Cart2Sph( this->m_GradientList ); m_ModelIndex = -1; return true; } template< class ScalarType > ScalarType RawShModel< ScalarType >::SimulateMeasurement(unsigned int dir, GradientType& fiberDirection) { ScalarType signal = 0; if (m_ModelIndex==-1) RandomModel(); vnl_matrix sphCoords = this->SetFiberDirection(fiberDirection); if (dir>=this->m_GradientList.size()) return signal; int j, m; double mag, plm; if (this->m_GradientList[dir].GetNorm()>0.001) { j=0; for (int l=0; l<=static_cast(m_ShOrder); l=l+2) for (m=-l; m<=l; m++) { plm = legendre_p(l,abs(m),cos(sphCoords(dir,0))); mag = sqrt((double)(2*l+1)/(4.0*itk::Math::pi)*factorial(l-abs(m))/factorial(l+abs(m)))*plm; double basis; if (m<0) basis = sqrt(2.0)*mag*cos(fabs((double)m)*sphCoords(dir,1)); else if (m==0) basis = mag; else basis = pow(-1.0, m)*sqrt(2.0)*mag*sin(m*sphCoords(dir,1)); signal += m_ShCoefficients.at(m_ModelIndex)[j]*basis; j++; } } else signal = m_B0Signal.at(m_ModelIndex); m_ModelIndex = -1; return signal; } template< class ScalarType > typename RawShModel< ScalarType >::PixelType RawShModel< ScalarType >::SimulateMeasurement(GradientType& fiberDirection) { if (m_ModelIndex==-1) RandomModel(); PixelType signal; signal.SetSize(this->m_GradientList.size()); int M = this->m_GradientList.size(); int j, m; double mag, plm; vnl_matrix< double > shBasis; shBasis.set_size(M, m_ShCoefficients.at(m_ModelIndex).size()); shBasis.fill(0.0); vnl_matrix sphCoords = this->SetFiberDirection(fiberDirection); for (int p=0; pm_GradientList[p].GetNorm()>0.001) { j=0; for (int l=0; l<=static_cast(m_ShOrder); l=l+2) for (m=-l; m<=l; m++) { plm = legendre_p(l,abs(m),cos(sphCoords(p,0))); mag = sqrt((double)(2*l+1)/(4.0*itk::Math::pi)*factorial(l-abs(m))/factorial(l+abs(m)))*plm; if (m<0) shBasis(p,j) = sqrt(2.0)*mag*cos(fabs((double)m)*sphCoords(p,1)); else if (m==0) shBasis(p,j) = mag; else shBasis(p,j) = pow(-1.0, m)*sqrt(2.0)*mag*sin(m*sphCoords(p,1)); j++; } double val = 0; for (unsigned int cidx=0; cidx #include #include #include #include #include #include #include #include mitk::FiberfoxParameters::FiberfoxParameters() : m_NoiseModel(nullptr) { mitk::StickModel* model_aniso = new mitk::StickModel(); model_aniso->m_CompartmentId = 1; m_FiberModelList.push_back(model_aniso); mitk::BallModel* model_iso = new mitk::BallModel(); model_iso->m_CompartmentId = 3; m_NonFiberModelList.push_back(model_iso); } mitk::FiberfoxParameters::FiberfoxParameters(const mitk::FiberfoxParameters& params) : m_NoiseModel(nullptr) { m_FiberGen = params.m_FiberGen; m_SignalGen = params.m_SignalGen; m_Misc = params.m_Misc; if (params.m_NoiseModel!=nullptr) { if (dynamic_cast*>(params.m_NoiseModel.get())) m_NoiseModel = std::make_shared< mitk::RicianNoiseModel<> >(); else if (dynamic_cast*>(params.m_NoiseModel.get())) m_NoiseModel = std::make_shared< mitk::ChiSquareNoiseModel<> >(); m_NoiseModel->SetNoiseVariance(params.m_NoiseModel->GetNoiseVariance()); } for (unsigned int i=0; i* outModel = nullptr; mitk::DiffusionSignalModel<>* signalModel = nullptr; if (i*>(signalModel)) outModel = new mitk::StickModel<>(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::TensorModel<>(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::RawShModel<>(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::BallModel<>(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::AstroStickModel<>(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::DotModel<>(dynamic_cast*>(signalModel)); if (i theta; theta.set_size(NPoints); vnl_vector phi; phi.set_size(NPoints); double C = sqrt(4*itk::Math::pi); phi(0) = 0.0; phi(NPoints-1) = 0.0; for(int i=0; i0 && i mitk::SignalGenerationParameters::GetBaselineIndices() { std::vector< int > result; for( unsigned int i=0; im_GradientDirections.size(); i++) if (m_GradientDirections.at(i).GetNorm()<0.0001) result.push_back(i); return result; } unsigned int mitk::SignalGenerationParameters::GetFirstBaselineIndex() { for( unsigned int i=0; im_GradientDirections.size(); i++) if (m_GradientDirections.at(i).GetNorm()<0.0001) return i; return -1; } bool mitk::SignalGenerationParameters::IsBaselineIndex(unsigned int idx) { if (m_GradientDirections.size()>idx && m_GradientDirections.at(idx).GetNorm()<0.0001) return true; return false; } unsigned int mitk::SignalGenerationParameters::GetNumWeightedVolumes() { return m_NumGradients; } unsigned int mitk::SignalGenerationParameters::GetNumBaselineVolumes() { return m_NumBaseline; } unsigned int mitk::SignalGenerationParameters::GetNumVolumes() { return m_GradientDirections.size(); } mitk::SignalGenerationParameters::GradientListType mitk::SignalGenerationParameters::GetGradientDirections() { return m_GradientDirections; } -mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer mitk::SignalGenerationParameters::GetItkGradientContainer() +mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer mitk::SignalGenerationParameters::GetItkGradientContainer() { int c = 0; mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer out = mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::New(); for (auto g : m_GradientDirections) { mitk::DiffusionPropertyHelper::GradientDirectionType vnl_dir; vnl_dir[0] = g[0]; vnl_dir[1] = g[1]; vnl_dir[2] = g[2]; out->InsertElement(c, vnl_dir); ++c; } - return out; + return mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer(out); } mitk::SignalGenerationParameters::GradientType mitk::SignalGenerationParameters::GetGradientDirection(unsigned int i) { return m_GradientDirections.at(i); } void mitk::SignalGenerationParameters::SetNumWeightedVolumes(int numGradients) { m_NumGradients = numGradients; GenerateGradientHalfShell(); } std::vector< int > mitk::SignalGenerationParameters::GetBvalues() { std::vector< int > bVals; for( GradientType g : m_GradientDirections) { float norm = g.GetNorm(); int bVal = std::round(norm*norm*m_Bvalue); if ( std::find(bVals.begin(), bVals.end(), bVal) == bVals.end() ) bVals.push_back(bVal); } return bVals; } double mitk::SignalGenerationParameters::GetBvalue() { return m_Bvalue; } void mitk::SignalGenerationParameters::SetGradienDirections(GradientListType gradientList) { m_GradientDirections = gradientList; m_NumGradients = 0; m_NumBaseline = 0; for( unsigned int i=0; im_GradientDirections.size(); i++) { float norm = m_GradientDirections.at(i).GetNorm(); if (norm>0.0001) m_NumGradients++; else m_NumBaseline++; } } -void mitk::SignalGenerationParameters::SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientList) +void mitk::SignalGenerationParameters::SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer gradientList) { m_NumGradients = 0; m_NumBaseline = 0; m_GradientDirections.clear(); for( unsigned int i=0; iSize(); i++) { GradientType g; g[0] = gradientList->at(i)[0]; g[1] = gradientList->at(i)[1]; g[2] = gradientList->at(i)[2]; m_GradientDirections.push_back(g); float norm = m_GradientDirections.at(i).GetNorm(); if (norm>0.0001) m_NumGradients++; else m_NumBaseline++; } } void mitk::SignalGenerationParameters::ApplyDirectionMatrix() { auto imageRotationMatrix = m_ImageDirection.GetVnlMatrix(); GradientListType rotated_gradients; for(auto g : m_GradientDirections) { vnl_vector vec = g.GetVnlVector(); vec = vec.pre_multiply(imageRotationMatrix); GradientType g2; g2[0] = vec[0]; g2[1] = vec[1]; g2[2] = vec[2]; rotated_gradients.push_back(g2); } m_GradientDirections = rotated_gradients; } void mitk::FiberfoxParameters::ApplyDirectionMatrix() { m_SignalGen.ApplyDirectionMatrix(); UpdateSignalModels(); } void mitk::FiberfoxParameters::SaveParameters(std::string filename) { if(filename.empty()) return; if(".ffp"!=filename.substr(filename.size()-4, 4)) filename += ".ffp"; const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, nullptr ); if ( locale.compare(currLocale)!=0 ) { try { setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } boost::property_tree::ptree parameters; // fiber generation parameters parameters.put("fiberfox.fibers.distribution", m_FiberGen.m_Distribution); parameters.put("fiberfox.fibers.variance", m_FiberGen.m_Variance); parameters.put("fiberfox.fibers.density", m_FiberGen.m_Density); parameters.put("fiberfox.fibers.spline.sampling", m_FiberGen.m_Sampling); parameters.put("fiberfox.fibers.spline.tension", m_FiberGen.m_Tension); parameters.put("fiberfox.fibers.spline.continuity", m_FiberGen.m_Continuity); parameters.put("fiberfox.fibers.spline.bias", m_FiberGen.m_Bias); parameters.put("fiberfox.fibers.rotation.x", m_FiberGen.m_Rotation[0]); parameters.put("fiberfox.fibers.rotation.y", m_FiberGen.m_Rotation[1]); parameters.put("fiberfox.fibers.rotation.z", m_FiberGen.m_Rotation[2]); parameters.put("fiberfox.fibers.translation.x", m_FiberGen.m_Translation[0]); parameters.put("fiberfox.fibers.translation.y", m_FiberGen.m_Translation[1]); parameters.put("fiberfox.fibers.translation.z", m_FiberGen.m_Translation[2]); parameters.put("fiberfox.fibers.scale.x", m_FiberGen.m_Scale[0]); parameters.put("fiberfox.fibers.scale.y", m_FiberGen.m_Scale[1]); parameters.put("fiberfox.fibers.scale.z", m_FiberGen.m_Scale[2]); // image generation parameters parameters.put("fiberfox.image.basic.size.x", m_SignalGen.m_ImageRegion.GetSize(0)); parameters.put("fiberfox.image.basic.size.y", m_SignalGen.m_ImageRegion.GetSize(1)); parameters.put("fiberfox.image.basic.size.z", m_SignalGen.m_ImageRegion.GetSize(2)); parameters.put("fiberfox.image.basic.spacing.x", m_SignalGen.m_ImageSpacing[0]); parameters.put("fiberfox.image.basic.spacing.y", m_SignalGen.m_ImageSpacing[1]); parameters.put("fiberfox.image.basic.spacing.z", m_SignalGen.m_ImageSpacing[2]); parameters.put("fiberfox.image.basic.origin.x", m_SignalGen.m_ImageOrigin[0]); parameters.put("fiberfox.image.basic.origin.y", m_SignalGen.m_ImageOrigin[1]); parameters.put("fiberfox.image.basic.origin.z", m_SignalGen.m_ImageOrigin[2]); parameters.put("fiberfox.image.basic.direction.d1", m_SignalGen.m_ImageDirection[0][0]); parameters.put("fiberfox.image.basic.direction.d2", m_SignalGen.m_ImageDirection[0][1]); parameters.put("fiberfox.image.basic.direction.d3", m_SignalGen.m_ImageDirection[0][2]); parameters.put("fiberfox.image.basic.direction.d4", m_SignalGen.m_ImageDirection[1][0]); parameters.put("fiberfox.image.basic.direction.d5", m_SignalGen.m_ImageDirection[1][1]); parameters.put("fiberfox.image.basic.direction.d6", m_SignalGen.m_ImageDirection[1][2]); parameters.put("fiberfox.image.basic.direction.d7", m_SignalGen.m_ImageDirection[2][0]); parameters.put("fiberfox.image.basic.direction.d8", m_SignalGen.m_ImageDirection[2][1]); parameters.put("fiberfox.image.basic.direction.d9", m_SignalGen.m_ImageDirection[2][2]); mitk::gradients::WriteBvalsBvecs(filename+".bvals", filename+".bvecs", m_SignalGen.GetItkGradientContainer(), m_SignalGen.m_Bvalue); parameters.put("fiberfox.image.acquisitiontype", m_SignalGen.m_AcquisitionType); parameters.put("fiberfox.image.coilsensitivityprofile", m_SignalGen.m_CoilSensitivityProfile); parameters.put("fiberfox.image.numberofcoils", m_SignalGen.m_NumberOfCoils); parameters.put("fiberfox.image.reversephase", m_SignalGen.m_ReversePhase); parameters.put("fiberfox.image.partialfourier", m_SignalGen.m_PartialFourier); parameters.put("fiberfox.image.noisevariance", m_SignalGen.m_NoiseVariance); parameters.put("fiberfox.image.trep", m_SignalGen.m_tRep); parameters.put("fiberfox.image.tinv", m_SignalGen.m_tInv); parameters.put("fiberfox.image.signalScale", m_SignalGen.m_SignalScale); parameters.put("fiberfox.image.tEcho", m_SignalGen.m_tEcho); parameters.put("fiberfox.image.tLine", m_SignalGen.m_tLine); parameters.put("fiberfox.image.tInhom", m_SignalGen.m_tInhom); parameters.put("fiberfox.image.echoTrainLength", m_SignalGen.m_EchoTrainLength); parameters.put("fiberfox.image.simulatekspace", m_SignalGen.m_SimulateKspaceAcquisition); parameters.put("fiberfox.image.axonRadius", m_SignalGen.m_AxonRadius); parameters.put("fiberfox.image.doSimulateRelaxation", m_SignalGen.m_DoSimulateRelaxation); parameters.put("fiberfox.image.doDisablePartialVolume", m_SignalGen.m_DoDisablePartialVolume); parameters.put("fiberfox.image.artifacts.spikesnum", m_SignalGen.m_Spikes); parameters.put("fiberfox.image.artifacts.spikesscale", m_SignalGen.m_SpikeAmplitude); parameters.put("fiberfox.image.artifacts.kspaceLineOffset", m_SignalGen.m_KspaceLineOffset); parameters.put("fiberfox.image.artifacts.eddyStrength", m_SignalGen.m_EddyStrength); parameters.put("fiberfox.image.artifacts.eddyTau", m_SignalGen.m_Tau); parameters.put("fiberfox.image.artifacts.aliasingfactor", m_SignalGen.m_CroppingFactor); parameters.put("fiberfox.image.artifacts.drift", m_SignalGen.m_Drift); parameters.put("fiberfox.image.artifacts.doAddMotion", m_SignalGen.m_DoAddMotion); parameters.put("fiberfox.image.artifacts.randomMotion", m_SignalGen.m_DoRandomizeMotion); parameters.put("fiberfox.image.artifacts.translation0", m_SignalGen.m_Translation[0]); parameters.put("fiberfox.image.artifacts.translation1", m_SignalGen.m_Translation[1]); parameters.put("fiberfox.image.artifacts.translation2", m_SignalGen.m_Translation[2]); parameters.put("fiberfox.image.artifacts.rotation0", m_SignalGen.m_Rotation[0]); parameters.put("fiberfox.image.artifacts.rotation1", m_SignalGen.m_Rotation[1]); parameters.put("fiberfox.image.artifacts.rotation2", m_SignalGen.m_Rotation[2]); parameters.put("fiberfox.image.artifacts.motionvolumes", m_Misc.m_MotionVolumesBox); parameters.put("fiberfox.image.artifacts.addringing", m_SignalGen.m_DoAddGibbsRinging); parameters.put("fiberfox.image.artifacts.zeroringing", m_SignalGen.m_ZeroRinging); parameters.put("fiberfox.image.artifacts.addnoise", m_Misc.m_DoAddNoise); parameters.put("fiberfox.image.artifacts.addghosts", m_Misc.m_DoAddGhosts); parameters.put("fiberfox.image.artifacts.addaliasing", m_Misc.m_DoAddAliasing); parameters.put("fiberfox.image.artifacts.addspikes", m_Misc.m_DoAddSpikes); parameters.put("fiberfox.image.artifacts.addeddycurrents", m_Misc.m_DoAddEddyCurrents); parameters.put("fiberfox.image.artifacts.doAddDistortions", m_Misc.m_DoAddDistortions); parameters.put("fiberfox.image.artifacts.doAddDrift", m_SignalGen.m_DoAddDrift); parameters.put("fiberfox.image.outputvolumefractions", m_Misc.m_OutputAdditionalImages); parameters.put("fiberfox.image.showadvanced", m_Misc.m_CheckAdvancedSignalOptionsBox); parameters.put("fiberfox.image.signalmodelstring", m_Misc.m_SignalModelString); parameters.put("fiberfox.image.artifactmodelstring", m_Misc.m_ArtifactModelString); parameters.put("fiberfox.image.outpath", m_Misc.m_OutputPath); parameters.put("fiberfox.fibers.realtime", m_Misc.m_CheckRealTimeFibersBox); parameters.put("fiberfox.fibers.showadvanced", m_Misc.m_CheckAdvancedFiberOptionsBox); parameters.put("fiberfox.fibers.constantradius", m_Misc.m_CheckConstantRadiusBox); parameters.put("fiberfox.fibers.includeFiducials", m_Misc.m_CheckIncludeFiducialsBox); if (m_NoiseModel!=nullptr) { parameters.put("fiberfox.image.artifacts.noisevariance", m_NoiseModel->GetNoiseVariance()); if (dynamic_cast*>(m_NoiseModel.get())) parameters.put("fiberfox.image.artifacts.noisetype", "rice"); else if (dynamic_cast*>(m_NoiseModel.get())) parameters.put("fiberfox.image.artifacts.noisetype", "chisquare"); } for (std::size_t i=0; i* signalModel = nullptr; if (i(i)+".type", "fiber"); } else { signalModel = m_NonFiberModelList.at(i-m_FiberModelList.size()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".type", "non-fiber"); } if (dynamic_cast*>(signalModel)) { mitk::StickModel<>* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".model", "stick"); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".d", model->GetDiffusivity()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".t2", model->GetT2()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".t1", model->GetT1()); } else if (dynamic_cast*>(signalModel)) { mitk::TensorModel<>* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".model", "tensor"); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".d1", model->GetDiffusivity1()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".d2", model->GetDiffusivity2()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".d3", model->GetDiffusivity3()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".t2", model->GetT2()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".t1", model->GetT1()); } else if (dynamic_cast*>(signalModel)) { mitk::RawShModel<>* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".model", "prototype"); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".minFA", model->GetFaRange().first); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".maxFA", model->GetFaRange().second); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".minADC", model->GetAdcRange().first); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".maxADC", model->GetAdcRange().second); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".maxNumSamples", model->GetMaxNumKernels()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".numSamples", model->GetNumberOfKernels()); int shOrder = model->GetShOrder(); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".numCoeffs", (shOrder*shOrder + shOrder + 2)/2 + shOrder); for (unsigned int j=0; jGetNumberOfKernels(); j++) { vnl_vector< double > coeffs = model->GetCoefficients(j); for (unsigned int k=0; k(i)+".kernels."+boost::lexical_cast(j)+".coeffs."+boost::lexical_cast(k), coeffs[k]); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".kernels."+boost::lexical_cast(j)+".B0", model->GetBaselineSignal(j)); } } else if (dynamic_cast*>(signalModel)) { mitk::BallModel<>* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".model", "ball"); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".d", model->GetDiffusivity()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".t2", model->GetT2()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".t1", model->GetT1()); } else if (dynamic_cast*>(signalModel)) { mitk::AstroStickModel<>* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".model", "astrosticks"); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".d", model->GetDiffusivity()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".t2", model->GetT2()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".t1", model->GetT1()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".randomize", model->GetRandomizeSticks()); } else if (dynamic_cast*>(signalModel)) { mitk::DotModel<>* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".model", "dot"); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".t2", model->GetT2()); parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".t1", model->GetT1()); } if (signalModel!=nullptr) { parameters.put("fiberfox.image.compartments.c"+boost::lexical_cast(i)+".ID", signalModel->m_CompartmentId); if (signalModel->GetVolumeFractionImage().IsNotNull()) { try{ itk::ImageFileWriter::Pointer writer = itk::ImageFileWriter::New(); writer->SetFileName(filename+"_VOLUME"+boost::lexical_cast(signalModel->m_CompartmentId)+".nii.gz"); writer->SetInput(signalModel->GetVolumeFractionImage()); writer->Update(); MITK_INFO << "Volume fraction image for compartment "+boost::lexical_cast(signalModel->m_CompartmentId)+" saved."; } catch(...) { } } } } boost::property_tree::xml_writer_settings writerSettings(' ', 2); boost::property_tree::xml_parser::write_xml(filename, parameters, std::locale(), writerSettings); try{ itk::ImageFileWriter::Pointer writer = itk::ImageFileWriter::New(); writer->SetFileName(filename+"_FMAP.nii.gz"); writer->SetInput(m_SignalGen.m_FrequencyMap); writer->Update(); } catch(...) { MITK_INFO << "No frequency map saved."; } try{ itk::ImageFileWriter::Pointer writer = itk::ImageFileWriter::New(); writer->SetFileName(filename+"_MASK.nii.gz"); writer->SetInput(m_SignalGen.m_MaskImage); writer->Update(); } catch(...) { MITK_INFO << "No mask image saved."; } setlocale(LC_ALL, currLocale.c_str()); } template< class ParameterType > ParameterType mitk::FiberfoxParameters::ReadVal(boost::property_tree::ptree::value_type const& v, std::string tag, ParameterType defaultValue, bool essential) { try { return v.second.get(tag); } catch (...) { if (essential) { mitkThrow() << "Parameter file corrupted. Essential tag is missing: '" << tag << "'"; } if (tag!="artifacts.noisetype") { MITK_INFO << "Tag '" << tag << "' not found. Using default value '" << defaultValue << "'."; m_MissingTags += "\n- "; m_MissingTags += tag; } return defaultValue; } } void mitk::FiberfoxParameters::UpdateSignalModels() { for (mitk::DiffusionSignalModel<>* m : m_FiberModelList) { m->SetGradientList(m_SignalGen.m_GradientDirections); m->SetBvalue(m_SignalGen.m_Bvalue); } for (mitk::DiffusionSignalModel<>* m : m_NonFiberModelList) { m->SetGradientList(m_SignalGen.m_GradientDirections); m->SetBvalue(m_SignalGen.m_Bvalue); } } void mitk::FiberfoxParameters::SetNumWeightedVolumes(int numGradients) { m_SignalGen.SetNumWeightedVolumes(numGradients); UpdateSignalModels(); } void mitk::FiberfoxParameters::SetGradienDirections(mitk::SignalGenerationParameters::GradientListType gradientList) { m_SignalGen.SetGradienDirections(gradientList); UpdateSignalModels(); } -void mitk::FiberfoxParameters::SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientList) +void mitk::FiberfoxParameters::SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer gradientList) { m_SignalGen.SetGradienDirections(gradientList); UpdateSignalModels(); } void mitk::FiberfoxParameters::SetBvalue(double Bvalue) { m_SignalGen.m_Bvalue = Bvalue; UpdateSignalModels(); } void mitk::FiberfoxParameters::GenerateGradientHalfShell() { m_SignalGen.GenerateGradientHalfShell(); UpdateSignalModels(); } void mitk::FiberfoxParameters::LoadParameters(std::string filename, bool fix_seed) { itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer randgen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); if (fix_seed) { srand(0); randgen->SetSeed(0); } else { srand(time(0)); randgen->SetSeed(); } m_MissingTags = ""; if(filename.empty()) { return; } const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, nullptr ); if ( locale.compare(currLocale)!=0 ) { try { setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } boost::property_tree::ptree parameterTree; boost::property_tree::xml_parser::read_xml( filename, parameterTree ); m_FiberModelList.clear(); m_NonFiberModelList.clear(); if (m_NoiseModel) { m_NoiseModel = nullptr; } BOOST_FOREACH( boost::property_tree::ptree::value_type const& v1, parameterTree.get_child("fiberfox") ) { if( v1.first == "fibers" ) { m_Misc.m_CheckRealTimeFibersBox = ReadVal(v1,"realtime", m_Misc.m_CheckRealTimeFibersBox); m_Misc.m_CheckAdvancedFiberOptionsBox = ReadVal(v1,"showadvanced", m_Misc.m_CheckAdvancedFiberOptionsBox); m_Misc.m_CheckConstantRadiusBox = ReadVal(v1,"constantradius", m_Misc.m_CheckConstantRadiusBox); m_Misc.m_CheckIncludeFiducialsBox = ReadVal(v1,"includeFiducials", m_Misc.m_CheckIncludeFiducialsBox); switch (ReadVal(v1,"distribution", 0)) { case 0: m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; break; case 1: m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_GAUSSIAN; break; default: m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; } m_FiberGen.m_Variance = ReadVal(v1,"variance", m_FiberGen.m_Variance); m_FiberGen.m_Density = ReadVal(v1,"density", m_FiberGen.m_Density); m_FiberGen.m_Sampling = ReadVal(v1,"spline.sampling", m_FiberGen.m_Sampling); m_FiberGen.m_Tension = ReadVal(v1,"spline.tension", m_FiberGen.m_Tension); m_FiberGen.m_Continuity = ReadVal(v1,"spline.continuity", m_FiberGen.m_Continuity); m_FiberGen.m_Bias = ReadVal(v1,"spline.bias", m_FiberGen.m_Bias); m_FiberGen.m_Rotation[0] = ReadVal(v1,"rotation.x", m_FiberGen.m_Rotation[0]); m_FiberGen.m_Rotation[1] = ReadVal(v1,"rotation.y", m_FiberGen.m_Rotation[1]); m_FiberGen.m_Rotation[2] = ReadVal(v1,"rotation.z", m_FiberGen.m_Rotation[2]); m_FiberGen.m_Translation[0] = ReadVal(v1,"translation.x", m_FiberGen.m_Translation[0]); m_FiberGen.m_Translation[1] = ReadVal(v1,"translation.y", m_FiberGen.m_Translation[1]); m_FiberGen.m_Translation[2] = ReadVal(v1,"translation.z", m_FiberGen.m_Translation[2]); m_FiberGen.m_Scale[0] = ReadVal(v1,"scale.x", m_FiberGen.m_Scale[0]); m_FiberGen.m_Scale[1] = ReadVal(v1,"scale.y", m_FiberGen.m_Scale[1]); m_FiberGen.m_Scale[2] = ReadVal(v1,"scale.z", m_FiberGen.m_Scale[2]); } else if ( v1.first == "image" ) { m_Misc.m_SignalModelString = ReadVal(v1,"signalmodelstring", m_Misc.m_SignalModelString); m_Misc.m_ArtifactModelString = ReadVal(v1,"artifactmodelstring", m_Misc.m_ArtifactModelString); m_Misc.m_OutputPath = ReadVal(v1,"outpath", m_Misc.m_OutputPath); m_Misc.m_OutputAdditionalImages = ReadVal(v1,"outputvolumefractions", m_Misc.m_OutputAdditionalImages); m_Misc.m_CheckAdvancedSignalOptionsBox = ReadVal(v1,"showadvanced", m_Misc.m_CheckAdvancedSignalOptionsBox); m_Misc.m_DoAddDistortions = ReadVal(v1,"artifacts.doAddDistortions", m_Misc.m_DoAddDistortions); m_Misc.m_DoAddNoise = ReadVal(v1,"artifacts.addnoise", m_Misc.m_DoAddNoise); m_Misc.m_DoAddGhosts = ReadVal(v1,"artifacts.addghosts", m_Misc.m_DoAddGhosts); m_Misc.m_DoAddAliasing = ReadVal(v1,"artifacts.addaliasing", m_Misc.m_DoAddAliasing); m_Misc.m_DoAddSpikes = ReadVal(v1,"artifacts.addspikes", m_Misc.m_DoAddSpikes); m_Misc.m_DoAddEddyCurrents = ReadVal(v1,"artifacts.addeddycurrents", m_Misc.m_DoAddEddyCurrents); m_SignalGen.m_ImageRegion.SetSize(0, ReadVal(v1,"basic.size.x",m_SignalGen.m_ImageRegion.GetSize(0))); m_SignalGen.m_ImageRegion.SetSize(1, ReadVal(v1,"basic.size.y",m_SignalGen.m_ImageRegion.GetSize(1))); m_SignalGen.m_ImageRegion.SetSize(2, ReadVal(v1,"basic.size.z",m_SignalGen.m_ImageRegion.GetSize(2))); m_SignalGen.m_ImageSpacing[0] = ReadVal(v1,"basic.spacing.x",m_SignalGen.m_ImageSpacing[0]); m_SignalGen.m_ImageSpacing[1] = ReadVal(v1,"basic.spacing.y",m_SignalGen.m_ImageSpacing[1]); m_SignalGen.m_ImageSpacing[2] = ReadVal(v1,"basic.spacing.z",m_SignalGen.m_ImageSpacing[2]); m_SignalGen.m_ImageOrigin[0] = ReadVal(v1,"basic.origin.x",m_SignalGen.m_ImageOrigin[0]); m_SignalGen.m_ImageOrigin[1] = ReadVal(v1,"basic.origin.y",m_SignalGen.m_ImageOrigin[1]); m_SignalGen.m_ImageOrigin[2] = ReadVal(v1,"basic.origin.z",m_SignalGen.m_ImageOrigin[2]); int i = 0; int j = 0; for(auto v : v1.second.get_child("basic.direction")) { m_SignalGen.m_ImageDirection[i][j] = boost::lexical_cast(v.second.data()); ++j; if (j==3) { j = 0; ++i; } } m_SignalGen.m_AcquisitionType = (SignalGenerationParameters::AcquisitionType)ReadVal(v1,"acquisitiontype", m_SignalGen.m_AcquisitionType); m_SignalGen.m_CoilSensitivityProfile = (SignalGenerationParameters::CoilSensitivityProfile)ReadVal(v1,"coilsensitivityprofile", m_SignalGen.m_CoilSensitivityProfile); m_SignalGen.m_NumberOfCoils = ReadVal(v1,"numberofcoils", m_SignalGen.m_NumberOfCoils); m_SignalGen.m_ReversePhase = ReadVal(v1,"reversephase", m_SignalGen.m_ReversePhase); m_SignalGen.m_PartialFourier = ReadVal(v1,"partialfourier", m_SignalGen.m_PartialFourier); m_SignalGen.m_NoiseVariance = ReadVal(v1,"noisevariance", m_SignalGen.m_NoiseVariance); m_SignalGen.m_tRep = ReadVal(v1,"trep", m_SignalGen.m_tRep); m_SignalGen.m_tInv = ReadVal(v1,"tinv", m_SignalGen.m_tInv); m_SignalGen.m_SignalScale = ReadVal(v1,"signalScale", m_SignalGen.m_SignalScale); m_SignalGen.m_tEcho = ReadVal(v1,"tEcho", m_SignalGen.m_tEcho); m_SignalGen.m_tLine = ReadVal(v1,"tLine", m_SignalGen.m_tLine); m_SignalGen.m_tInhom = ReadVal(v1,"tInhom", m_SignalGen.m_tInhom); m_SignalGen.m_EchoTrainLength = ReadVal(v1,"echoTrainLength", m_SignalGen.m_EchoTrainLength); m_SignalGen.m_SimulateKspaceAcquisition = ReadVal(v1,"simulatekspace", m_SignalGen.m_SimulateKspaceAcquisition); m_SignalGen.m_AxonRadius = ReadVal(v1,"axonRadius", m_SignalGen.m_AxonRadius); m_SignalGen.m_Spikes = ReadVal(v1,"artifacts.spikesnum", m_SignalGen.m_Spikes); m_SignalGen.m_SpikeAmplitude = ReadVal(v1,"artifacts.spikesscale", m_SignalGen.m_SpikeAmplitude); m_SignalGen.m_KspaceLineOffset = ReadVal(v1,"artifacts.kspaceLineOffset", m_SignalGen.m_KspaceLineOffset); m_SignalGen.m_EddyStrength = ReadVal(v1,"artifacts.eddyStrength", m_SignalGen.m_EddyStrength); m_SignalGen.m_Tau = ReadVal(v1,"artifacts.eddyTau", m_SignalGen.m_Tau); m_SignalGen.m_CroppingFactor = ReadVal(v1,"artifacts.aliasingfactor", m_SignalGen.m_CroppingFactor); m_SignalGen.m_Drift = ReadVal(v1,"artifacts.drift", m_SignalGen.m_Drift); m_SignalGen.m_DoAddGibbsRinging = ReadVal(v1,"artifacts.addringing", m_SignalGen.m_DoAddGibbsRinging); m_SignalGen.m_ZeroRinging = ReadVal(v1,"artifacts.zeroringing", m_SignalGen.m_ZeroRinging); m_SignalGen.m_DoSimulateRelaxation = ReadVal(v1,"doSimulateRelaxation", m_SignalGen.m_DoSimulateRelaxation); m_SignalGen.m_DoDisablePartialVolume = ReadVal(v1,"doDisablePartialVolume", m_SignalGen.m_DoDisablePartialVolume); m_SignalGen.m_DoAddMotion = ReadVal(v1,"artifacts.doAddMotion", m_SignalGen.m_DoAddMotion); m_SignalGen.m_DoRandomizeMotion = ReadVal(v1,"artifacts.randomMotion", m_SignalGen.m_DoRandomizeMotion); m_SignalGen.m_DoAddDrift = ReadVal(v1,"artifacts.doAddDrift", m_SignalGen.m_DoAddDrift); m_SignalGen.m_Translation[0] = ReadVal(v1,"artifacts.translation0", m_SignalGen.m_Translation[0]); m_SignalGen.m_Translation[1] = ReadVal(v1,"artifacts.translation1", m_SignalGen.m_Translation[1]); m_SignalGen.m_Translation[2] = ReadVal(v1,"artifacts.translation2", m_SignalGen.m_Translation[2]); m_SignalGen.m_Rotation[0] = ReadVal(v1,"artifacts.rotation0", m_SignalGen.m_Rotation[0]); m_SignalGen.m_Rotation[1] = ReadVal(v1,"artifacts.rotation1", m_SignalGen.m_Rotation[1]); m_SignalGen.m_Rotation[2] = ReadVal(v1,"artifacts.rotation2", m_SignalGen.m_Rotation[2]); if (itksys::SystemTools::FileExists(filename+".bvals") && itksys::SystemTools::FileExists(filename+".bvecs")) { m_Misc.m_BvalsFile = filename+".bvals"; m_Misc.m_BvecsFile = filename+".bvecs"; m_SignalGen.SetGradienDirections( mitk::gradients::ReadBvalsBvecs(m_Misc.m_BvalsFile, m_Misc.m_BvecsFile, m_SignalGen.m_Bvalue) ); } else { m_SignalGen.m_Bvalue = ReadVal(v1,"bvalue", m_SignalGen.m_Bvalue); SignalGenerationParameters::GradientListType gradients; try { BOOST_FOREACH( boost::property_tree::ptree::value_type const& v2, v1.second.get_child("gradients") ) { SignalGenerationParameters::GradientType g; g[0] = ReadVal(v2,"x",0); g[1] = ReadVal(v2,"y",0); g[2] = ReadVal(v2,"z",0); gradients.push_back(g); } } catch(...) { MITK_INFO << "WARNING: Fiberfox parameters without any gradient directions loaded."; } m_SignalGen.SetGradienDirections(gradients); } m_Misc.m_MotionVolumesBox = ReadVal(v1,"artifacts.motionvolumes", m_Misc.m_MotionVolumesBox); m_SignalGen.m_MotionVolumes.clear(); if ( m_Misc.m_MotionVolumesBox == "random" ) { m_SignalGen.m_MotionVolumes.push_back(0); for ( size_t i=1; i < m_SignalGen.GetNumVolumes(); ++i ) { m_SignalGen.m_MotionVolumes.push_back( bool( randgen->GetIntegerVariate()%2 ) ); } MITK_DEBUG << "mitkFiberfoxParameters.cpp: Case m_Misc.m_MotionVolumesBox == \"random\"."; } else if ( ! m_Misc.m_MotionVolumesBox.empty() ) { std::stringstream stream( m_Misc.m_MotionVolumesBox ); std::vector numbers; int nummer = std::numeric_limits::max(); while( stream >> nummer ) { if( nummer < std::numeric_limits::max() ) { numbers.push_back( nummer ); } } // If a list of negative numbers is given: if( *(std::min_element( numbers.begin(), numbers.end() )) < 0 && *(std::max_element( numbers.begin(), numbers.end() )) <= 0 ) // cave: -0 == +0 { for ( size_t i=0; i(m_SignalGen.GetNumVolumes()) && -number >= 0 ) m_SignalGen.m_MotionVolumes.at(-number) = false; } MITK_DEBUG << "mitkFiberfoxParameters.cpp: Case list of negative numbers."; } // If a list of positive numbers is given: else if( *(std::min_element( numbers.begin(), numbers.end() )) >= 0 && *(std::max_element( numbers.begin(), numbers.end() )) >= 0 ) { for ( size_t i=0; i(m_SignalGen.GetNumVolumes()) && number >= 0) m_SignalGen.m_MotionVolumes.at(number) = true; } MITK_DEBUG << "mitkFiberfoxParameters.cpp: Case list of positive numbers."; } else { MITK_WARN << "mitkFiberfoxParameters.cpp: Inconsistent list of numbers in m_MotionVolumesBox."; break; } } else { MITK_WARN << "mitkFiberfoxParameters.cpp: Cannot make sense of string in m_MotionVolumesBox."; break; } try { if (ReadVal(v1,"artifacts.noisetype","")=="rice") { m_NoiseModel = std::make_shared< mitk::RicianNoiseModel<> >(); m_NoiseModel->SetNoiseVariance(ReadVal(v1,"artifacts.noisevariance",m_NoiseModel->GetNoiseVariance())); } } catch(...) { MITK_DEBUG << "mitkFiberfoxParameters.cpp: caught some error while trying m_NoiseModel->SetNoiseVariance()"; // throw; } try { if (ReadVal(v1,"artifacts.noisetype","")=="chisquare") { m_NoiseModel = std::make_shared< mitk::ChiSquareNoiseModel<> >(); m_NoiseModel->SetNoiseVariance(ReadVal(v1,"artifacts.noisevariance",m_NoiseModel->GetNoiseVariance())); } } catch(...) { MITK_DEBUG << "mitkFiberfoxParameters.cpp: caught some error while trying m_NoiseModel->SetNoiseVariance()"; // throw; } BOOST_FOREACH( boost::property_tree::ptree::value_type const& v2, v1.second.get_child("compartments") ) { mitk::DiffusionSignalModel<>* signalModel = nullptr; std::string model = ReadVal(v2,"model","",true); if (model=="stick") { mitk::StickModel<>* model = new mitk::StickModel<>(); model->SetDiffusivity(ReadVal(v2,"d",model->GetDiffusivity())); model->SetT2(ReadVal(v2,"t2",model->GetT2())); model->SetT1(ReadVal(v2,"t1",model->GetT1())); model->SetBvalue(m_SignalGen.m_Bvalue); model->m_CompartmentId = ReadVal(v2,"ID",0,true); if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="tensor") { mitk::TensorModel<>* model = new mitk::TensorModel<>(); model->SetDiffusivity1(ReadVal(v2,"d1",model->GetDiffusivity1())); model->SetDiffusivity2(ReadVal(v2,"d2",model->GetDiffusivity2())); model->SetDiffusivity3(ReadVal(v2,"d3",model->GetDiffusivity3())); model->SetT2(ReadVal(v2,"t2",model->GetT2())); model->SetT1(ReadVal(v2,"t1",model->GetT1())); model->SetBvalue(m_SignalGen.m_Bvalue); model->m_CompartmentId = ReadVal(v2,"ID",0,true); if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="ball") { mitk::BallModel<>* model = new mitk::BallModel<>(); model->SetDiffusivity(ReadVal(v2,"d",model->GetDiffusivity())); model->SetT2(ReadVal(v2,"t2",model->GetT2())); model->SetT1(ReadVal(v2,"t1",model->GetT1())); model->SetBvalue(m_SignalGen.m_Bvalue); model->m_CompartmentId = ReadVal(v2,"ID",0,true); if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="astrosticks") { mitk::AstroStickModel<>* model = new AstroStickModel<>(); model->SetDiffusivity(ReadVal(v2,"d",model->GetDiffusivity())); model->SetT2(ReadVal(v2,"t2",model->GetT2())); model->SetT1(ReadVal(v2,"t1",model->GetT1())); model->SetBvalue(m_SignalGen.m_Bvalue); model->SetRandomizeSticks(ReadVal(v2,"randomize",model->GetRandomizeSticks())); model->m_CompartmentId = ReadVal(v2,"ID",0,true); if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="dot") { mitk::DotModel<>* model = new mitk::DotModel<>(); model->SetT2(ReadVal(v2,"t2",model->GetT2())); model->SetT1(ReadVal(v2,"t1",model->GetT1())); model->m_CompartmentId = ReadVal(v2,"ID",0,true); if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="prototype") { mitk::RawShModel<>* model = new mitk::RawShModel<>(); model->SetMaxNumKernels(ReadVal(v2,"maxNumSamples",model->GetMaxNumKernels())); model->SetFaRange(ReadVal(v2,"minFA",model->GetFaRange().first), ReadVal(v2,"maxFA",model->GetFaRange().second)); model->SetAdcRange(ReadVal(v2,"minADC",model->GetAdcRange().first), ReadVal(v2,"maxADC",model->GetAdcRange().second)); model->m_CompartmentId = ReadVal(v2,"ID",0,true); unsigned int numCoeffs = ReadVal(v2,"numCoeffs",0,true); unsigned int numSamples = ReadVal(v2,"numSamples",0,true); for (unsigned int j=0; j coeffs(numCoeffs); for (unsigned int k=0; k(v2,"kernels."+boost::lexical_cast(j)+".coeffs."+boost::lexical_cast(k),0,true); } model->SetShCoefficients( coeffs, ReadVal(v2,"kernels."+boost::lexical_cast(j)+".B0",0,true) ); } if (ReadVal(v2,"type","",true)=="fiber") { m_FiberModelList.push_back(model); } else if (ReadVal(v2,"type","",true)=="non-fiber") { m_NonFiberModelList.push_back(model); } // else ? signalModel = model; } if (signalModel!=nullptr) { try { itk::ImageFileReader::Pointer reader = itk::ImageFileReader::New(); if ( itksys::SystemTools::FileExists(filename+"_VOLUME"+ReadVal(v2,"ID","")+".nii.gz") ) reader->SetFileName(filename+"_VOLUME"+ReadVal(v2,"ID","")+".nii.gz"); else if ( itksys::SystemTools::FileExists(filename+"_VOLUME"+ReadVal(v2,"ID","")+".nii") ) reader->SetFileName(filename+"_VOLUME"+ReadVal(v2,"ID","")+".nii"); else reader->SetFileName(filename+"_VOLUME"+ReadVal(v2,"ID","")+".nrrd"); reader->Update(); signalModel->SetVolumeFractionImage(reader->GetOutput()); MITK_INFO << "Volume fraction image loaded for compartment " << signalModel->m_CompartmentId; } catch(...) { MITK_INFO << "No volume fraction image found for compartment " << signalModel->m_CompartmentId; } } } } else { } } UpdateSignalModels(); try { itk::ImageFileReader::Pointer reader = itk::ImageFileReader::New(); reader->SetFileName(filename+"_FMAP.nrrd"); if ( itksys::SystemTools::FileExists(filename+"_FMAP.nii.gz") ) reader->SetFileName(filename+"_FMAP.nii.gz"); else if ( itksys::SystemTools::FileExists(filename+"_FMAP.nii") ) reader->SetFileName(filename+"_FMAP.nii"); else reader->SetFileName(filename+"_FMAP.nrrd"); reader->Update(); m_SignalGen.m_FrequencyMap = reader->GetOutput(); MITK_INFO << "Frequency map loaded."; } catch(...) { MITK_INFO << "No frequency map found."; } try { itk::ImageFileReader::Pointer reader = itk::ImageFileReader::New(); if ( itksys::SystemTools::FileExists(filename+"_MASK.nii.gz") ) reader->SetFileName(filename+"_MASK.nii.gz"); else if ( itksys::SystemTools::FileExists(filename+"_MASK.nii") ) reader->SetFileName(filename+"_MASK.nii"); else reader->SetFileName(filename+"_MASK.nrrd"); reader->Update(); m_SignalGen.m_MaskImage = reader->GetOutput(); m_SignalGen.m_ImageRegion = m_SignalGen.m_MaskImage->GetLargestPossibleRegion(); m_SignalGen.m_ImageSpacing = m_SignalGen.m_MaskImage->GetSpacing(); m_SignalGen.m_ImageOrigin = m_SignalGen.m_MaskImage->GetOrigin(); m_SignalGen.m_ImageDirection = m_SignalGen.m_MaskImage->GetDirection(); MITK_INFO << "Mask image loaded."; } catch(...) { MITK_INFO << "No mask image found."; } setlocale(LC_ALL, currLocale.c_str()); } void mitk::FiberfoxParameters::PrintSelf() { MITK_INFO << "Not implemented :("; } diff --git a/Modules/MriSimulation/mitkFiberfoxParameters.h b/Modules/MriSimulation/mitkFiberfoxParameters.h index 055e2dd..9105306 100644 --- a/Modules/MriSimulation/mitkFiberfoxParameters.h +++ b/Modules/MriSimulation/mitkFiberfoxParameters.h @@ -1,339 +1,339 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef _MITK_FiberfoxParameters_H #define _MITK_FiberfoxParameters_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mitk { class MITKMRISIMULATION_EXPORT FiberfoxParameters; /** Signal generation */ class MITKMRISIMULATION_EXPORT SignalGenerationParameters { friend FiberfoxParameters; public: typedef itk::Image ItkFloatImgType; typedef itk::Image ItkUcharImgType; typedef itk::Vector GradientType; typedef std::vector GradientListType; enum CoilSensitivityProfile : int { COIL_CONSTANT, COIL_LINEAR, COIL_EXPONENTIAL }; enum AcquisitionType : int { SingleShotEpi, ConventionalSpinEcho, FastSpinEcho, }; SignalGenerationParameters() : m_AcquisitionType(SignalGenerationParameters::SingleShotEpi) , m_SignalScale(100) , m_tEcho(100) , m_tRep(4000) , m_tInv(0) , m_tLine(1) , m_tInhom(50) , m_EchoTrainLength(8) , m_ReversePhase(false) , m_PartialFourier(1.0) , m_NoiseVariance(0.001f) , m_NumberOfCoils(1) , m_CoilSensitivityProfile(SignalGenerationParameters::COIL_CONSTANT) , m_CoilSensitivity(0.3f) , m_SimulateKspaceAcquisition(false) , m_AxonRadius(0) , m_DoDisablePartialVolume(false) , m_Spikes(0) , m_SpikeAmplitude(1) , m_KspaceLineOffset(0) , m_EddyStrength(0.002f) , m_Tau(70) , m_CroppingFactor(1) , m_Drift(0.06) , m_DoAddGibbsRinging(false) , m_ZeroRinging(0) , m_DoSimulateRelaxation(true) , m_DoAddMotion(false) , m_DoRandomizeMotion(true) , m_DoAddDrift(false) , m_FrequencyMap(nullptr) , m_MaskImage(nullptr) , m_Bvalue(1000) { m_ImageRegion.SetSize(0, 12); m_ImageRegion.SetSize(1, 12); m_ImageRegion.SetSize(2, 3); m_ImageSpacing.Fill(2.0); m_ImageOrigin.Fill(0.0); m_ImageDirection.SetIdentity(); m_Translation.Fill(0.0); m_Rotation.Fill(0.0); SetNumWeightedVolumes(6); } /** input/output image specifications */ itk::ImageRegion<3> m_CroppedRegion; ///< Image size with reduced FOV. itk::ImageRegion<3> m_ImageRegion; ///< Image size. itk::Vector m_ImageSpacing; ///< Image voxel size. itk::Point m_ImageOrigin; ///< Image origin. itk::Matrix m_ImageDirection; ///< Image rotation matrix. /** Other acquisitions parameters */ AcquisitionType m_AcquisitionType; ///< determines k-space trajectory and maximum echo position(s) float m_SignalScale; ///< Scaling factor for output signal (before noise is added). float m_tEcho; ///< Echo time TE. float m_tRep; ///< Echo time TR. float m_tInv; ///< Inversion time float m_tLine; ///< k-space line readout time (dwell time). float m_tInhom; ///< T2' unsigned int m_EchoTrainLength; ///< Only relevant for Fast Spin Echo sequence (number of k-space lines acquired with one RF pulse) bool m_ReversePhase; ///< If true, the phase readout direction will be inverted (-y instead of y) float m_PartialFourier; ///< Partial fourier factor (0.5-1) float m_NoiseVariance; ///< Variance of complex gaussian noise unsigned int m_NumberOfCoils; ///< Number of coils in multi-coil acquisition CoilSensitivityProfile m_CoilSensitivityProfile; ///< Choose between constant, linear or exponential sensitivity profile of the used coils float m_CoilSensitivity; ///< signal remaining in slice center bool m_SimulateKspaceAcquisition;///< Flag to enable/disable k-space acquisition simulation double m_AxonRadius; ///< Determines compartment volume fractions (0 == automatic axon radius estimation) bool m_DoDisablePartialVolume; ///< Disable partial volume effects. Each voxel is either all fiber or all non-fiber. /** Artifacts and other effects */ unsigned int m_Spikes; ///< Number of spikes randomly appearing in the image float m_SpikeAmplitude; ///< amplitude of spikes relative to the largest signal intensity (magnitude of complex) float m_KspaceLineOffset; ///< Causes N/2 ghosts. Larger offset means stronger ghost. float m_EddyStrength; ///< Strength of eddy current induced gradients in mT/m. float m_Tau; ///< Eddy current decay constant (in ms) float m_CroppingFactor; ///< FOV size in y-direction is multiplied by this factor. Causes aliasing artifacts. float m_Drift; ///< Global signal decrease by the end of the acquisition. bool m_DoAddGibbsRinging; ///< Add Gibbs ringing artifact int m_ZeroRinging; ///< If > 0, ringing is simulated by by setting the defined percentage of higher frequencies to 0 in k-space. Otherwise, the input to the k-space simulation is generated with twice the resolution and cropped during k-space simulation (much slower). bool m_DoSimulateRelaxation; ///< Add T2 relaxation effects bool m_DoAddMotion; ///< Enable motion artifacts. bool m_DoRandomizeMotion; ///< Toggles between random and linear motion. bool m_DoAddDrift; ///< Add quadratic signal drift. std::vector< bool > m_MotionVolumes; ///< Indicates the image volumes that are affected by motion ///< with positive numbers, inverted logic with negative numbers. itk::Vector m_Translation; ///< Maximum translational motion. itk::Vector m_Rotation; ///< Maximum rotational motion. ItkFloatImgType::Pointer m_FrequencyMap; ///< If != nullptr, distortions are added to the image using this frequency map. ItkUcharImgType::Pointer m_MaskImage; ///< Signal is only genrated inside of the mask image. std::vector< int > GetBaselineIndices(); ///< Returns list of nun-diffusion-weighted image volume indices unsigned int GetFirstBaselineIndex(); ///< Returns index of first non-diffusion-weighted image volume bool IsBaselineIndex(unsigned int idx); ///< Checks if image volume with given index is non-diffusion-weighted volume or not. unsigned int GetNumWeightedVolumes(); ///< Get number of diffusion-weighted image volumes unsigned int GetNumBaselineVolumes(); ///< Get number of non-diffusion-weighted image volumes unsigned int GetNumVolumes(); ///< Get number of baseline and diffusion-weighted image volumes GradientListType GetGradientDirections(); ///< Return gradient direction container - mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer GetItkGradientContainer(); + mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer GetItkGradientContainer(); GradientType GetGradientDirection(unsigned int i); std::vector< int > GetBvalues(); ///< Returns a vector with all unique b-values (determined by the gradient magnitudes) double GetBvalue(); void ApplyDirectionMatrix(); protected: unsigned int m_NumGradients; ///< Number of diffusion-weighted image volumes. unsigned int m_NumBaseline; ///< Number of non-diffusion-weighted image volumes. GradientListType m_GradientDirections; ///< Total number of image volumes. double m_Bvalue; ///< Acquisition b-value void SetNumWeightedVolumes(int numGradients); ///< Automaticall calls GenerateGradientHalfShell() afterwards. void SetGradienDirections(GradientListType gradientList); - void SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientList); + void SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer gradientList); void GenerateGradientHalfShell(); ///< Generates half shell of gradient directions (with m_NumGradients non-zero directions) }; /** Fiber generation */ class MITKMRISIMULATION_EXPORT FiberGenerationParameters { public: enum FiberDistribution { DISTRIBUTE_UNIFORM, // distribute fibers uniformly in the ROIs DISTRIBUTE_GAUSSIAN // distribute fibers using a 2D gaussian }; typedef std::vector< std::vector< mitk::PlanarEllipse::Pointer > > FiducialListType; typedef std::vector< std::vector< unsigned int > > FlipListType; FiberGenerationParameters() : m_Distribution(DISTRIBUTE_UNIFORM) , m_Density(100) , m_Variance(100) , m_Sampling(1) , m_Tension(0) , m_Continuity(0) , m_Bias(0) { m_Rotation.Fill(0.0); m_Translation.Fill(0.0); m_Scale.Fill(1.0); } FiberDistribution m_Distribution; unsigned int m_Density; double m_Variance; double m_Sampling; double m_Tension; double m_Continuity; double m_Bias; mitk::Vector3D m_Rotation; mitk::Vector3D m_Translation; mitk::Vector3D m_Scale; FlipListType m_FlipList; ///< contains flags indicating a flip of the 2D fiber x-coordinates (needed to resolve some unwanted fiber twisting) FiducialListType m_Fiducials; ///< container of the planar ellipses used as fiducials for the fiber generation process }; /** GUI persistence, input, output, ... */ class MITKMRISIMULATION_EXPORT MiscFiberfoxParameters { public: MiscFiberfoxParameters() : m_ResultNode(DataNode::New()) , m_ParentNode(nullptr) , m_SignalModelString("") , m_ArtifactModelString("") , m_OutputPath("/tmp/") , m_OutputPrefix("fiberfox") , m_AfterSimulationMessage("") , m_BvalsFile("") , m_BvecsFile("") , m_OutputAdditionalImages(false) , m_CheckAdvancedSignalOptionsBox(false) , m_DoAddNoise(false) , m_DoAddGhosts(false) , m_DoAddAliasing(false) , m_DoAddSpikes(false) , m_DoAddEddyCurrents(false) , m_DoAddDistortions(false) , m_MotionVolumesBox("random") , m_CheckRealTimeFibersBox(true) , m_CheckAdvancedFiberOptionsBox(false) , m_CheckConstantRadiusBox(false) , m_CheckIncludeFiducialsBox(true) {} DataNode::Pointer m_ResultNode; ///< Stores resulting image. DataNode::Pointer m_ParentNode; ///< Parent node of result node. std::string m_SignalModelString; ///< Appendet to the name of the result node std::string m_ArtifactModelString; ///< Appendet to the name of the result node std::string m_OutputPath; ///< Image is automatically saved to the specified folder after simulation is finished. std::string m_OutputPrefix; /** Prefix for filename of output files and logfile. */ std::string m_AfterSimulationMessage; ///< Store messages that are displayed after the simulation has finished (e.g. warnings, automatic parameter adjustments etc.) std::string m_BvalsFile; std::string m_BvecsFile; /** member variables that store the check-state of GUI checkboxes */ // image generation bool m_OutputAdditionalImages; bool m_CheckAdvancedSignalOptionsBox; bool m_DoAddNoise; bool m_DoAddGhosts; bool m_DoAddAliasing; bool m_DoAddSpikes; bool m_DoAddEddyCurrents; bool m_DoAddDistortions; std::string m_MotionVolumesBox; // fiber generation bool m_CheckRealTimeFibersBox; bool m_CheckAdvancedFiberOptionsBox; bool m_CheckConstantRadiusBox; bool m_CheckIncludeFiducialsBox; }; /** * \brief Datastructure to manage the Fiberfox signal generation parameters. * */ class MITKMRISIMULATION_EXPORT FiberfoxParameters { public: typedef itk::Image ItkFloatImgType; typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkUcharImgType; typedef DiffusionSignalModel DiffusionModelType; typedef std::vector< DiffusionModelType* > DiffusionModelListType; typedef DiffusionNoiseModel NoiseModelType; FiberfoxParameters(); FiberfoxParameters(const FiberfoxParameters ¶ms); ~FiberfoxParameters(); /** Not templated parameters */ FiberGenerationParameters m_FiberGen; ///< Fiber generation parameters SignalGenerationParameters m_SignalGen; ///< Signal generation parameters MiscFiberfoxParameters m_Misc; ///< GUI realted and I/O parameters /** Templated parameters */ DiffusionModelListType m_FiberModelList; ///< Intra- and inter-axonal compartments. DiffusionModelListType m_NonFiberModelList; ///< Extra-axonal compartments. std::shared_ptr< NoiseModelType > m_NoiseModel; ///< If != nullptr, noise is added to the image. void GenerateGradientHalfShell(); void SetNumWeightedVolumes(int numGradients); ///< Automaticall calls GenerateGradientHalfShell() afterwards. void SetGradienDirections(mitk::SignalGenerationParameters::GradientListType gradientList); - void SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientList); + void SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer gradientList); void SetBvalue(double Bvalue); void UpdateSignalModels(); void ClearFiberParameters(); void ClearSignalParameters(); void ApplyDirectionMatrix(); void PrintSelf(); ///< Print parameters to stdout. void SaveParameters(std::string filename); ///< Save image generation parameters to .ffp file. void LoadParameters(std::string filename, bool fix_seed=false); ///< Load image generation parameters from .ffp file. template< class ParameterType > ParameterType ReadVal(boost::property_tree::ptree::value_type const& v, std::string tag, ParameterType defaultValue, bool essential=false); std::string m_MissingTags; }; } #endif diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxView.cpp index b6fc585..a30336b 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxView.cpp @@ -1,2181 +1,2181 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkFiberfoxView.h" // MITK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define RAPIDXML_NO_EXCEPTIONS #include #include #include #include #include "usModuleRegistry.h" #include #include #include #include #include #include #include #include #include #include "mitkNodePredicateDataType.h" #include #include #include #include QmitkFiberfoxWorker::QmitkFiberfoxWorker(QmitkFiberfoxView* view) : m_View(view) { } void QmitkFiberfoxWorker::run() { try{ m_View->m_TractsToDwiFilter->Update(); } catch( ... ) { } m_View->m_Thread.quit(); } const std::string QmitkFiberfoxView::VIEW_ID = "org.mitk.views.fiberfoxview"; QmitkFiberfoxView::QmitkFiberfoxView() : QmitkAbstractView() , m_Controls( 0 ) , m_SelectedImageNode( nullptr ) , m_Worker(this) , m_ThreadIsRunning(false) { m_Worker.moveToThread(&m_Thread); connect(&m_Thread, SIGNAL(started()), this, SLOT(BeforeThread())); connect(&m_Thread, SIGNAL(started()), &m_Worker, SLOT(run())); connect(&m_Thread, SIGNAL(finished()), this, SLOT(AfterThread())); // connect(&m_Thread, SIGNAL(terminated()), this, SLOT(AfterThread())); m_SimulationTimer = new QTimer(this); } void QmitkFiberfoxView::KillThread() { MITK_INFO << "Aborting DWI simulation."; m_TractsToDwiFilter->SetAbortGenerateData(true); m_Controls->m_AbortSimulationButton->setEnabled(false); m_Controls->m_AbortSimulationButton->setText("Aborting simulation ..."); } void QmitkFiberfoxView::BeforeThread() { m_SimulationTime = QTime::currentTime(); m_SimulationTimer->start(100); m_Controls->m_AbortSimulationButton->setVisible(true); m_Controls->m_GenerateImageButton->setVisible(false); m_Controls->m_SimulationStatusText->setVisible(true); m_ThreadIsRunning = true; } void QmitkFiberfoxView::AfterThread() { UpdateSimulationStatus(); m_SimulationTimer->stop(); m_Controls->m_AbortSimulationButton->setVisible(false); m_Controls->m_AbortSimulationButton->setEnabled(true); m_Controls->m_AbortSimulationButton->setText("Abort simulation"); m_Controls->m_GenerateImageButton->setVisible(true); m_ThreadIsRunning = false; QString statusText; FiberfoxParameters parameters; mitk::Image::Pointer mitkImage = mitk::Image::New(); statusText = QString(m_TractsToDwiFilter->GetStatusText().c_str()); if (m_TractsToDwiFilter->GetAbortGenerateData()) { MITK_INFO << "Simulation aborted."; return; } parameters = m_TractsToDwiFilter->GetParameters(); mitkImage = mitk::GrabItkImageMemory( m_TractsToDwiFilter->GetOutput() ); if (parameters.m_SignalGen.GetNumWeightedVolumes() > 0) { mitk::DiffusionPropertyHelper::SetGradientContainer(mitkImage, parameters.m_SignalGen.GetItkGradientContainer()); mitk::DiffusionPropertyHelper::SetReferenceBValue(mitkImage, parameters.m_SignalGen.GetBvalue()); mitk::DiffusionPropertyHelper::InitializeImage( mitkImage ); } parameters.m_Misc.m_ResultNode->SetData( mitkImage ); GetDataStorage()->Add(parameters.m_Misc.m_ResultNode, parameters.m_Misc.m_ParentNode); if (m_Controls->m_VolumeFractionsBox->isChecked()) { if (m_TractsToDwiFilter->GetTickImage().IsNotNull()) { mitk::Image::Pointer mitkImage = mitk::Image::New(); itk::TractsToDWIImageFilter< short >::Float2DImageType::Pointer itkImage = m_TractsToDwiFilter->GetTickImage(); mitkImage = mitk::GrabItkImageMemory( itkImage.GetPointer() ); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( mitkImage ); node->SetName("Tick Image"); GetDataStorage()->Add(node, parameters.m_Misc.m_ResultNode); } if (m_TractsToDwiFilter->GetRfImage().IsNotNull()) { mitk::Image::Pointer mitkImage = mitk::Image::New(); itk::TractsToDWIImageFilter< short >::Float2DImageType::Pointer itkImage = m_TractsToDwiFilter->GetRfImage(); mitkImage = mitk::GrabItkImageMemory( itkImage.GetPointer() ); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( mitkImage ); node->SetName("RF Image"); GetDataStorage()->Add(node, parameters.m_Misc.m_ResultNode); } if (m_TractsToDwiFilter->GetPhaseImage().IsNotNull()) { mitk::Image::Pointer phaseImage = mitk::Image::New(); itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer itkPhase = m_TractsToDwiFilter->GetPhaseImage(); phaseImage = mitk::GrabItkImageMemory( itkPhase.GetPointer() ); mitk::DataNode::Pointer phaseNode = mitk::DataNode::New(); phaseNode->SetData( phaseImage ); phaseNode->SetName("Phase Image"); GetDataStorage()->Add(phaseNode, parameters.m_Misc.m_ResultNode); } if (m_TractsToDwiFilter->GetKspaceImage().IsNotNull()) { mitk::Image::Pointer image = mitk::Image::New(); itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer itkImage = m_TractsToDwiFilter->GetKspaceImage(); image = mitk::GrabItkImageMemory( itkImage.GetPointer() ); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("k-Space"); GetDataStorage()->Add(node, parameters.m_Misc.m_ResultNode); } { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(m_TractsToDwiFilter->GetCoilPointset()); node->SetName("Coil Positions"); node->SetProperty("pointsize", mitk::FloatProperty::New(parameters.m_SignalGen.m_ImageSpacing[0]/4)); node->SetProperty("color", mitk::ColorProperty::New(0, 1, 0)); GetDataStorage()->Add(node, parameters.m_Misc.m_ResultNode); } int c = 1; std::vector< itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer > output_real = m_TractsToDwiFilter->GetOutputImagesReal(); for (auto real : output_real) { mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(real.GetPointer()); image->SetVolume(real->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("Coil-"+QString::number(c).toStdString()+"-real"); GetDataStorage()->Add(node, parameters.m_Misc.m_ResultNode); ++c; } c = 1; std::vector< itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer > output_imag = m_TractsToDwiFilter->GetOutputImagesImag(); for (auto imag : output_imag) { mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(imag.GetPointer()); image->SetVolume(imag->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("Coil-"+QString::number(c).toStdString()+"-imag"); GetDataStorage()->Add(node, parameters.m_Misc.m_ResultNode); ++c; } std::vector< itk::TractsToDWIImageFilter< short >::ItkDoubleImgType::Pointer > volumeFractions = m_TractsToDwiFilter->GetVolumeFractions(); for (unsigned int k=0; kInitializeByItk(volumeFractions.at(k).GetPointer()); image->SetVolume(volumeFractions.at(k)->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("CompartmentVolume-"+QString::number(k).toStdString()); GetDataStorage()->Add(node, parameters.m_Misc.m_ResultNode); } } m_TractsToDwiFilter = nullptr; if (parameters.m_Misc.m_AfterSimulationMessage.size()>0) QMessageBox::information( nullptr, "Warning", parameters.m_Misc.m_AfterSimulationMessage.c_str()); mitk::BaseData::Pointer basedata = parameters.m_Misc.m_ResultNode->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } if (!parameters.m_Misc.m_OutputPath.empty()) { try{ QString outputFileName(parameters.m_Misc.m_OutputPath.c_str()); outputFileName += parameters.m_Misc.m_ResultNode->GetName().c_str(); outputFileName.replace(QString("."), QString("_")); SaveParameters(outputFileName+".ffp"); outputFileName += ".dwi"; QString status("Saving output image to "); status += outputFileName; m_Controls->m_SimulationStatusText->append(status); mitk::IOUtil::Save(mitkImage, outputFileName.toStdString()); m_Controls->m_SimulationStatusText->append("File saved successfully."); } catch (itk::ExceptionObject &e) { QString status("Exception during DWI writing: "); status += e.GetDescription(); m_Controls->m_SimulationStatusText->append(status); } catch (...) { m_Controls->m_SimulationStatusText->append("Unknown exception during DWI writing!"); } } parameters.m_SignalGen.m_FrequencyMap = nullptr; } void QmitkFiberfoxView::UpdateSimulationStatus() { QString statusText = QString(m_TractsToDwiFilter->GetStatusText().c_str()); if (QString::compare(m_SimulationStatusText,statusText)!=0) { m_Controls->m_SimulationStatusText->clear(); m_Controls->m_SimulationStatusText->setText(statusText); QScrollBar *vScrollBar = m_Controls->m_SimulationStatusText->verticalScrollBar(); vScrollBar->triggerAction(QScrollBar::SliderToMaximum); } } // Destructor QmitkFiberfoxView::~QmitkFiberfoxView() { delete m_SimulationTimer; } void QmitkFiberfoxView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberfoxViewControls; m_Controls->setupUi( parent ); m_Controls->m_StickWidget1->setVisible(true); m_Controls->m_StickWidget2->setVisible(false); m_Controls->m_ZeppelinWidget1->setVisible(false); m_Controls->m_ZeppelinWidget2->setVisible(false); m_Controls->m_TensorWidget1->setVisible(false); m_Controls->m_TensorWidget2->setVisible(false); m_Controls->m_BallWidget1->setVisible(true); m_Controls->m_BallWidget2->setVisible(false); m_Controls->m_BallWidget2->SetT1(4658); m_Controls->m_BallWidget2->SetT2(2200); m_Controls->m_AstrosticksWidget1->setVisible(false); m_Controls->m_AstrosticksWidget2->setVisible(false); m_Controls->m_AstrosticksWidget2->SetT1(4658); m_Controls->m_AstrosticksWidget2->SetT2(2200); m_Controls->m_DotWidget1->setVisible(false); m_Controls->m_DotWidget2->setVisible(false); m_Controls->m_DotWidget2->SetT1(4658); m_Controls->m_DotWidget2->SetT2(2200); m_Controls->m_PrototypeWidget1->setVisible(false); m_Controls->m_PrototypeWidget2->setVisible(false); m_Controls->m_PrototypeWidget3->setVisible(false); m_Controls->m_PrototypeWidget4->setVisible(false); m_Controls->m_PrototypeWidget3->SetMinFa(0.0); m_Controls->m_PrototypeWidget3->SetMaxFa(0.15); m_Controls->m_PrototypeWidget4->SetMinFa(0.0); m_Controls->m_PrototypeWidget4->SetMaxFa(0.15); m_Controls->m_PrototypeWidget3->SetMinAdc(0.0); m_Controls->m_PrototypeWidget3->SetMaxAdc(0.001); m_Controls->m_PrototypeWidget4->SetMinAdc(0.003); m_Controls->m_PrototypeWidget4->SetMaxAdc(0.004); m_Controls->m_Comp2FractionFrame->setVisible(false); m_Controls->m_Comp4FractionFrame->setVisible(false); m_Controls->m_DiffusionPropsMessage->setVisible(false); m_Controls->m_GeometryMessage->setVisible(false); m_Controls->m_AdvancedSignalOptionsFrame->setVisible(false); m_Controls->m_NoiseFrame->setVisible(false); m_Controls->m_ZeroRinging->setVisible(false); m_Controls->m_GhostFrame->setVisible(false); m_Controls->m_DistortionsFrame->setVisible(false); m_Controls->m_EddyFrame->setVisible(false); m_Controls->m_SpikeFrame->setVisible(false); m_Controls->m_AliasingFrame->setVisible(false); m_Controls->m_MotionArtifactFrame->setVisible(false); m_Controls->m_DriftFrame->setVisible(false); m_ParameterFile = QDir::currentPath()+"/param.ffp"; m_Controls->m_AbortSimulationButton->setVisible(false); m_Controls->m_SimulationStatusText->setVisible(false); m_Controls->m_FrequencyMapBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_Comp1VolumeFraction->SetDataStorage(this->GetDataStorage()); m_Controls->m_Comp2VolumeFraction->SetDataStorage(this->GetDataStorage()); m_Controls->m_Comp3VolumeFraction->SetDataStorage(this->GetDataStorage()); m_Controls->m_Comp4VolumeFraction->SetDataStorage(this->GetDataStorage()); m_Controls->m_MaskComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_TemplateComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_FiberBundleComboBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isFiberBundle = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isMitkImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateIsDWI::Pointer isDwi = mitk::NodePredicateIsDWI::New( ); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isOdf = mitk::NodePredicateDataType::New("Odfmage"); mitk::NodePredicateOr::Pointer isDiffusionImage = mitk::NodePredicateOr::New(isDwi, isDti); isDiffusionImage = mitk::NodePredicateOr::New(isDiffusionImage, isOdf); mitk::NodePredicateNot::Pointer noDiffusionImage = mitk::NodePredicateNot::New(isDiffusionImage); mitk::NodePredicateAnd::Pointer isNonDiffMitkImage = mitk::NodePredicateAnd::New(isMitkImage, noDiffusionImage); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isBinaryMitkImage = mitk::NodePredicateAnd::New( isNonDiffMitkImage, isBinaryPredicate ); m_Controls->m_FrequencyMapBox->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp1VolumeFraction->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp1VolumeFraction->SetZeroEntryText("--"); m_Controls->m_Comp2VolumeFraction->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp2VolumeFraction->SetZeroEntryText("--"); m_Controls->m_Comp3VolumeFraction->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp3VolumeFraction->SetZeroEntryText("--"); m_Controls->m_Comp4VolumeFraction->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp4VolumeFraction->SetZeroEntryText("--"); m_Controls->m_MaskComboBox->SetPredicate(isBinaryMitkImage); m_Controls->m_MaskComboBox->SetZeroEntryText("--"); m_Controls->m_TemplateComboBox->SetPredicate(isMitkImage); m_Controls->m_TemplateComboBox->SetZeroEntryText("--"); m_Controls->m_FiberBundleComboBox->SetPredicate(isFiberBundle); m_Controls->m_FiberBundleComboBox->SetZeroEntryText("--"); QFont font; font.setFamily("Courier"); font.setStyleHint(QFont::Monospace); font.setFixedPitch(true); font.setPointSize(7); m_Controls->m_SimulationStatusText->setFont(font); connect( m_SimulationTimer, SIGNAL(timeout()), this, SLOT(UpdateSimulationStatus()) ); connect((QObject*) m_Controls->m_AbortSimulationButton, SIGNAL(clicked()), (QObject*) this, SLOT(KillThread())); connect((QObject*) m_Controls->m_GenerateImageButton, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateImage())); connect((QObject*) m_Controls->m_AddNoise, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddNoise(int))); connect((QObject*) m_Controls->m_AddGhosts, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddGhosts(int))); connect((QObject*) m_Controls->m_AddDistortions, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddDistortions(int))); connect((QObject*) m_Controls->m_AddEddy, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddEddy(int))); connect((QObject*) m_Controls->m_AddSpikes, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddSpikes(int))); connect((QObject*) m_Controls->m_AddAliasing, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddAliasing(int))); connect((QObject*) m_Controls->m_AddMotion, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddMotion(int))); connect((QObject*) m_Controls->m_AddDrift, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddDrift(int))); connect((QObject*) m_Controls->m_AddGibbsRinging, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddRinging(int))); connect((QObject*) m_Controls->m_Compartment1Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp1ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_Compartment2Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp2ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_Compartment3Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp3ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_Compartment4Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp4ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_AdvancedOptionsBox_2, SIGNAL( stateChanged(int)), (QObject*) this, SLOT(ShowAdvancedOptions(int))); connect((QObject*) m_Controls->m_UseBvalsBvecsBox, SIGNAL( stateChanged(int)), (QObject*) this, SLOT(OnBvalsBvecsCheck(int))); connect((QObject*) m_Controls->m_SaveParametersButton, SIGNAL(clicked()), (QObject*) this, SLOT(SaveParameters())); connect((QObject*) m_Controls->m_LoadParametersButton, SIGNAL(clicked()), (QObject*) this, SLOT(LoadParameters())); connect((QObject*) m_Controls->m_OutputPathButton, SIGNAL(clicked()), (QObject*) this, SLOT(SetOutputPath())); connect((QObject*) m_Controls->m_LoadBvalsButton, SIGNAL(clicked()), (QObject*) this, SLOT(SetBvalsEdit())); connect((QObject*) m_Controls->m_LoadBvecsButton, SIGNAL(clicked()), (QObject*) this, SLOT(SetBvecsEdit())); connect((QObject*) m_Controls->m_MaskComboBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnMaskSelected(int))); connect((QObject*) m_Controls->m_TemplateComboBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnTemplateSelected(int))); connect((QObject*) m_Controls->m_FiberBundleComboBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnFibSelected(int))); connect((QObject*) m_Controls->m_LineReadoutTimeBox, SIGNAL( valueChanged(double)), (QObject*) this, SLOT(OnTlineChanged())); connect((QObject*) m_Controls->m_SizeX, SIGNAL( valueChanged(int)), (QObject*) this, SLOT(OnTlineChanged())); } OnTlineChanged(); UpdateGui(); } void QmitkFiberfoxView::OnTlineChanged() { double num_pix_line = 0; if (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull()) // use geometry of selected image { mitk::Image::Pointer img = dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()); num_pix_line = img->GetDimension(0); } else if (m_Controls->m_MaskComboBox->GetSelectedNode().IsNotNull()) // use geometry of mask image { mitk::Image::Pointer img = dynamic_cast(m_Controls->m_MaskComboBox->GetSelectedNode()->GetData()); num_pix_line = img->GetDimension(0); } else { num_pix_line = m_Controls->m_SizeX->value(); } double value = static_cast(m_Controls->m_LineReadoutTimeBox->value())/1000.0; // line readout time in seconds double dweel_pp = value/num_pix_line; // pixel readout time in seconds double bw = 1/dweel_pp; double bw_pp = bw/num_pix_line; std::string tt = "Bandwidth:\n" + boost::lexical_cast(itk::Math::Round(bw)) + "Hz\n" + boost::lexical_cast(itk::Math::Round(bw_pp)) + "Hz/Px"; m_Controls->m_LineReadoutTimeBox->setToolTip(tt.c_str()); } void QmitkFiberfoxView::OnMaskSelected(int ) { UpdateGui(); } void QmitkFiberfoxView::OnTemplateSelected(int ) { UpdateGui(); } void QmitkFiberfoxView::OnFibSelected(int ) { UpdateGui(); } void QmitkFiberfoxView::OnBvalsBvecsCheck(int ) { UpdateGui(); } void QmitkFiberfoxView::UpdateParametersFromGui() { m_Parameters.ClearSignalParameters(); m_Parameters.m_Misc.m_CheckAdvancedSignalOptionsBox = m_Controls->m_AdvancedOptionsBox_2->isChecked(); m_Parameters.m_Misc.m_OutputAdditionalImages = m_Controls->m_VolumeFractionsBox->isChecked(); std::string outputPath = m_Controls->m_SavePathEdit->text().toStdString(); if (outputPath.compare("-")!=0) { m_Parameters.m_Misc.m_OutputPath = outputPath; m_Parameters.m_Misc.m_OutputPath += "/"; } else { m_Parameters.m_Misc.m_OutputPath = ""; } if (m_Controls->m_MaskComboBox->GetSelectedNode().IsNotNull()) { mitk::Image::Pointer mitkMaskImage = dynamic_cast(m_Controls->m_MaskComboBox->GetSelectedNode()->GetData()); mitk::CastToItkImage(mitkMaskImage, m_Parameters.m_SignalGen.m_MaskImage); itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage(m_Parameters.m_SignalGen.m_MaskImage); duplicator->Update(); m_Parameters.m_SignalGen.m_MaskImage = duplicator->GetOutput(); } if (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull() && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( m_Controls->m_TemplateComboBox->GetSelectedNode())) // use parameters of selected DWI { mitk::Image::Pointer dwi = dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(dwi, itkVectorImagePointer); m_Parameters.m_SignalGen.m_ImageRegion = itkVectorImagePointer->GetLargestPossibleRegion(); m_Parameters.m_SignalGen.m_ImageSpacing = itkVectorImagePointer->GetSpacing(); m_Parameters.m_SignalGen.m_ImageOrigin = itkVectorImagePointer->GetOrigin(); m_Parameters.m_SignalGen.m_ImageDirection = itkVectorImagePointer->GetDirection(); m_Parameters.SetBvalue(mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi)); m_Parameters.SetGradienDirections(mitk::DiffusionPropertyHelper::GetOriginalGradientContainer(dwi)); } else if (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull()) // use geometry of selected image { mitk::Image::Pointer img = dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()); itk::Image< float, 3 >::Pointer itkImg = itk::Image< float, 3 >::New(); CastToItkImage< itk::Image< float, 3 > >(img, itkImg); m_Parameters.m_SignalGen.m_ImageRegion = itkImg->GetLargestPossibleRegion(); m_Parameters.m_SignalGen.m_ImageSpacing = itkImg->GetSpacing(); m_Parameters.m_SignalGen.m_ImageOrigin = itkImg->GetOrigin(); m_Parameters.m_SignalGen.m_ImageDirection = itkImg->GetDirection(); if (m_Controls->m_UseBvalsBvecsBox->isChecked()) { double bval; m_Parameters.SetGradienDirections( mitk::gradients::ReadBvalsBvecs(m_Controls->m_LoadBvalsEdit->text().toStdString(), m_Controls->m_LoadBvecsEdit->text().toStdString(), bval) ); m_Parameters.SetBvalue(bval); } else { m_Parameters.SetNumWeightedVolumes(m_Controls->m_NumGradientsBox->value()); m_Parameters.SetBvalue(m_Controls->m_BvalueBox->value()); m_Parameters.GenerateGradientHalfShell(); } } else if (m_Parameters.m_SignalGen.m_MaskImage.IsNotNull()) // use geometry of mask image { ItkUcharImgType::Pointer itkImg = m_Parameters.m_SignalGen.m_MaskImage; m_Parameters.m_SignalGen.m_ImageRegion = itkImg->GetLargestPossibleRegion(); m_Parameters.m_SignalGen.m_ImageSpacing = itkImg->GetSpacing(); m_Parameters.m_SignalGen.m_ImageOrigin = itkImg->GetOrigin(); m_Parameters.m_SignalGen.m_ImageDirection = itkImg->GetDirection(); if (m_Controls->m_UseBvalsBvecsBox->isChecked()) { double bval; m_Parameters.SetGradienDirections( mitk::gradients::ReadBvalsBvecs(m_Controls->m_LoadBvalsEdit->text().toStdString(), m_Controls->m_LoadBvecsEdit->text().toStdString(), bval) ); m_Parameters.SetBvalue(bval); } else { m_Parameters.SetNumWeightedVolumes(m_Controls->m_NumGradientsBox->value()); m_Parameters.SetBvalue(m_Controls->m_BvalueBox->value()); m_Parameters.GenerateGradientHalfShell(); } } else // use GUI parameters { m_Parameters.m_SignalGen.m_ImageRegion.SetSize(0, m_Controls->m_SizeX->value()); m_Parameters.m_SignalGen.m_ImageRegion.SetSize(1, m_Controls->m_SizeY->value()); m_Parameters.m_SignalGen.m_ImageRegion.SetSize(2, m_Controls->m_SizeZ->value()); m_Parameters.m_SignalGen.m_ImageSpacing[0] = m_Controls->m_SpacingX->value(); m_Parameters.m_SignalGen.m_ImageSpacing[1] = m_Controls->m_SpacingY->value(); m_Parameters.m_SignalGen.m_ImageSpacing[2] = m_Controls->m_SpacingZ->value(); m_Parameters.m_SignalGen.m_ImageOrigin[0] = m_Parameters.m_SignalGen.m_ImageSpacing[0]/2; m_Parameters.m_SignalGen.m_ImageOrigin[1] = m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; m_Parameters.m_SignalGen.m_ImageOrigin[2] = m_Parameters.m_SignalGen.m_ImageSpacing[2]/2; m_Parameters.m_SignalGen.m_ImageDirection.SetIdentity(); if (m_Controls->m_UseBvalsBvecsBox->isChecked()) { double bval; m_Parameters.SetGradienDirections( mitk::gradients::ReadBvalsBvecs(m_Controls->m_LoadBvalsEdit->text().toStdString(), m_Controls->m_LoadBvecsEdit->text().toStdString(), bval) ); m_Parameters.SetBvalue(bval); } else { m_Parameters.SetNumWeightedVolumes(m_Controls->m_NumGradientsBox->value()); m_Parameters.SetBvalue(m_Controls->m_BvalueBox->value()); m_Parameters.GenerateGradientHalfShell(); } } // signal relaxation m_Parameters.m_SignalGen.m_DoSimulateRelaxation = false; if (m_Controls->m_RelaxationBox->isChecked()) { m_Parameters.m_SignalGen.m_DoSimulateRelaxation = true; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Relaxation", BoolProperty::New(true)); m_Parameters.m_Misc.m_ArtifactModelString += "_RELAX"; } m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition = m_Parameters.m_SignalGen.m_DoSimulateRelaxation; // N/2 ghosts m_Parameters.m_Misc.m_DoAddGhosts = m_Controls->m_AddGhosts->isChecked(); m_Parameters.m_SignalGen.m_KspaceLineOffset = m_Controls->m_kOffsetBox->value(); if (m_Controls->m_AddGhosts->isChecked()) { m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; m_Parameters.m_Misc.m_ArtifactModelString += "_GHOST"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Ghost", DoubleProperty::New(m_Parameters.m_SignalGen.m_KspaceLineOffset)); } // Aliasing m_Parameters.m_Misc.m_DoAddAliasing = m_Controls->m_AddAliasing->isChecked(); m_Parameters.m_SignalGen.m_CroppingFactor = (100-m_Controls->m_WrapBox->value())/100; if (m_Controls->m_AddAliasing->isChecked()) { m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; m_Parameters.m_Misc.m_ArtifactModelString += "_ALIASING"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Aliasing", DoubleProperty::New(m_Controls->m_WrapBox->value())); } // Spikes m_Parameters.m_Misc.m_DoAddSpikes = m_Controls->m_AddSpikes->isChecked(); m_Parameters.m_SignalGen.m_Spikes = m_Controls->m_SpikeNumBox->value(); m_Parameters.m_SignalGen.m_SpikeAmplitude = m_Controls->m_SpikeScaleBox->value(); if (m_Controls->m_AddSpikes->isChecked()) { m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; m_Parameters.m_Misc.m_ArtifactModelString += "_SPIKES"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Spikes.Number", IntProperty::New(m_Parameters.m_SignalGen.m_Spikes)); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Spikes.Amplitude", DoubleProperty::New(m_Parameters.m_SignalGen.m_SpikeAmplitude)); } // Drift m_Parameters.m_SignalGen.m_DoAddDrift = m_Controls->m_AddDrift->isChecked(); m_Parameters.m_SignalGen.m_Drift = static_cast(m_Controls->m_DriftFactor->value())/100; if (m_Controls->m_AddDrift->isChecked()) { m_Parameters.m_Misc.m_ArtifactModelString += "_DRIFT"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Drift", FloatProperty::New(m_Parameters.m_SignalGen.m_Drift)); } // gibbs ringing m_Parameters.m_SignalGen.m_DoAddGibbsRinging = m_Controls->m_AddGibbsRinging->isChecked(); m_Parameters.m_SignalGen.m_ZeroRinging = m_Controls->m_ZeroRinging->value(); if (m_Controls->m_AddGibbsRinging->isChecked()) { m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Ringing", BoolProperty::New(true)); m_Parameters.m_Misc.m_ArtifactModelString += "_RINGING"; } // add distortions m_Parameters.m_Misc.m_DoAddDistortions = m_Controls->m_AddDistortions->isChecked(); if (m_Controls->m_AddDistortions->isChecked() && m_Controls->m_FrequencyMapBox->GetSelectedNode().IsNotNull()) { mitk::DataNode::Pointer fMapNode = m_Controls->m_FrequencyMapBox->GetSelectedNode(); mitk::Image* img = dynamic_cast(fMapNode->GetData()); ItkFloatImgType::Pointer itkImg = ItkFloatImgType::New(); CastToItkImage< ItkFloatImgType >(img, itkImg); if (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNull()) // use geometry of frequency map { m_Parameters.m_SignalGen.m_ImageRegion = itkImg->GetLargestPossibleRegion(); m_Parameters.m_SignalGen.m_ImageSpacing = itkImg->GetSpacing(); m_Parameters.m_SignalGen.m_ImageOrigin = itkImg->GetOrigin(); m_Parameters.m_SignalGen.m_ImageDirection = itkImg->GetDirection(); } m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage(itkImg); duplicator->Update(); m_Parameters.m_SignalGen.m_FrequencyMap = duplicator->GetOutput(); m_Parameters.m_Misc.m_ArtifactModelString += "_DISTORTED"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Distortions", BoolProperty::New(true)); } m_Parameters.m_SignalGen.m_EddyStrength = m_Controls->m_EddyGradientStrength->value(); m_Parameters.m_Misc.m_DoAddEddyCurrents = m_Controls->m_AddEddy->isChecked(); if (m_Controls->m_AddEddy->isChecked()) { m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; m_Parameters.m_Misc.m_ArtifactModelString += "_EDDY"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Eddy-strength", DoubleProperty::New(m_Parameters.m_SignalGen.m_EddyStrength)); } // Motion m_Parameters.m_SignalGen.m_DoAddMotion = false; m_Parameters.m_SignalGen.m_DoRandomizeMotion = m_Controls->m_RandomMotion->isChecked(); m_Parameters.m_SignalGen.m_Translation[0] = m_Controls->m_MaxTranslationBoxX->value(); m_Parameters.m_SignalGen.m_Translation[1] = m_Controls->m_MaxTranslationBoxY->value(); m_Parameters.m_SignalGen.m_Translation[2] = m_Controls->m_MaxTranslationBoxZ->value(); m_Parameters.m_SignalGen.m_Rotation[0] = m_Controls->m_MaxRotationBoxX->value(); m_Parameters.m_SignalGen.m_Rotation[1] = m_Controls->m_MaxRotationBoxY->value(); m_Parameters.m_SignalGen.m_Rotation[2] = m_Controls->m_MaxRotationBoxZ->value(); m_Parameters.m_SignalGen.m_MotionVolumes.clear(); m_Parameters.m_Misc.m_MotionVolumesBox = m_Controls->m_MotionVolumesBox->text().toStdString(); if ( m_Controls->m_AddMotion->isChecked()) { m_Parameters.m_SignalGen.m_DoAddMotion = true; m_Parameters.m_Misc.m_ArtifactModelString += "_MOTION"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Random", BoolProperty::New(m_Parameters.m_SignalGen.m_DoRandomizeMotion)); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Translation-x", DoubleProperty::New(m_Parameters.m_SignalGen.m_Translation[0])); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Translation-y", DoubleProperty::New(m_Parameters.m_SignalGen.m_Translation[1])); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Translation-z", DoubleProperty::New(m_Parameters.m_SignalGen.m_Translation[2])); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Rotation-x", DoubleProperty::New(m_Parameters.m_SignalGen.m_Rotation[0])); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Rotation-y", DoubleProperty::New(m_Parameters.m_SignalGen.m_Rotation[1])); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Rotation-z", DoubleProperty::New(m_Parameters.m_SignalGen.m_Rotation[2])); if ( m_Parameters.m_Misc.m_MotionVolumesBox == "random" ) { for ( size_t i=0; i < m_Parameters.m_SignalGen.GetNumVolumes(); ++i ) { m_Parameters.m_SignalGen.m_MotionVolumes.push_back( bool( rand()%2 ) ); } MITK_DEBUG << "QmitkFiberfoxView.cpp: Case m_Misc.m_MotionVolumesBox == \"random\"."; } else if ( ! m_Parameters.m_Misc.m_MotionVolumesBox.empty() ) { std::stringstream stream( m_Parameters.m_Misc.m_MotionVolumesBox ); std::vector numbers; int number = std::numeric_limits::max(); while( stream >> number ) { if( number < std::numeric_limits::max() ) { numbers.push_back( number ); } } // If a list of negative numbers is given: if( *(std::min_element( numbers.begin(), numbers.end() )) < 0 && *(std::max_element( numbers.begin(), numbers.end() )) <= 0 ) // cave: -0 == +0 { for ( size_t i=0; i < m_Parameters.m_SignalGen.GetNumVolumes(); ++i ) { m_Parameters.m_SignalGen.m_MotionVolumes.push_back( true ); } // set all true except those given. for( auto iter = std::begin( numbers ); iter != std::end( numbers ); ++iter ) { if ( -(*iter) < (int)m_Parameters.m_SignalGen.GetNumVolumes() && -(*iter) >= 0 ) { m_Parameters.m_SignalGen.m_MotionVolumes.at( -(*iter) ) = false; } } MITK_DEBUG << "QmitkFiberfoxView.cpp: Case list of negative numbers."; } // If a list of positive numbers is given: else if( *(std::min_element( numbers.begin(), numbers.end() )) >= 0 && *(std::max_element( numbers.begin(), numbers.end() )) >= 0 ) { for ( size_t i=0; i < m_Parameters.m_SignalGen.GetNumVolumes(); ++i ) { m_Parameters.m_SignalGen.m_MotionVolumes.push_back( false ); } // set all false except those given. for( auto iter = std::begin( numbers ); iter != std::end( numbers ); ++iter ) { if ( *iter < (int)m_Parameters.m_SignalGen.GetNumVolumes() && *iter >= 0 ) { m_Parameters.m_SignalGen.m_MotionVolumes.at( *iter ) = true; } } MITK_DEBUG << "QmitkFiberfoxView.cpp: Case list of positive numbers."; } else { MITK_ERROR << "QmitkFiberfoxView.cpp: Inconsistent list of numbers in m_MotionVolumesBox."; } } else { m_Parameters.m_Misc.m_MotionVolumesBox = ""; // set empty. m_Controls->m_MotionVolumesBox->setText(""); for (unsigned int i=0; im_AcquisitionTypeBox->currentIndex(); m_Parameters.m_SignalGen.m_CoilSensitivityProfile = (SignalGenerationParameters::CoilSensitivityProfile)m_Controls->m_CoilSensBox->currentIndex(); m_Parameters.m_SignalGen.m_NumberOfCoils = m_Controls->m_NumCoilsBox->value(); m_Parameters.m_SignalGen.m_PartialFourier = m_Controls->m_PartialFourier->value(); m_Parameters.m_SignalGen.m_ReversePhase = m_Controls->m_ReversePhaseBox->isChecked(); m_Parameters.m_SignalGen.m_tLine = m_Controls->m_LineReadoutTimeBox->value(); m_Parameters.m_SignalGen.m_tInhom = m_Controls->m_T2starBox->value(); m_Parameters.m_SignalGen.m_EchoTrainLength = m_Controls->m_EtlBox->value(); m_Parameters.m_SignalGen.m_tEcho = m_Controls->m_TEbox->value(); m_Parameters.m_SignalGen.m_tRep = m_Controls->m_TRbox->value(); m_Parameters.m_SignalGen.m_tInv = m_Controls->m_TIbox->value(); m_Parameters.m_SignalGen.m_DoDisablePartialVolume = m_Controls->m_EnforcePureFiberVoxelsBox->isChecked(); m_Parameters.m_SignalGen.m_AxonRadius = m_Controls->m_FiberRadius->value(); m_Parameters.m_SignalGen.m_SignalScale = m_Controls->m_SignalScaleBox->value(); // double voxelVolume = m_Parameters.m_SignalGen.m_ImageSpacing[0] // * m_Parameters.m_SignalGen.m_ImageSpacing[1] // * m_Parameters.m_SignalGen.m_ImageSpacing[2]; // if ( m_Parameters.m_SignalGen.m_SignalScale*voxelVolume > itk::NumericTraits::max()*0.75 ) // { // m_Parameters.m_SignalGen.m_SignalScale = itk::NumericTraits::max()*0.75/voxelVolume; // m_Controls->m_SignalScaleBox->setValue(m_Parameters.m_SignalGen.m_SignalScale); // QMessageBox::information( nullptr, "Warning", // "Maximum signal exceeding data type limits. Automatically adjusted to " // + QString::number(m_Parameters.m_SignalGen.m_SignalScale) // + " to obtain a maximum signal of 75% of the data type maximum." // " Relaxation and other effects that affect the signal intensities are not accounted for."); // } // Noise m_Parameters.m_Misc.m_DoAddNoise = m_Controls->m_AddNoise->isChecked(); m_Parameters.m_SignalGen.m_NoiseVariance = m_Controls->m_NoiseLevel->value(); if (m_Controls->m_AddNoise->isChecked()) { switch (m_Controls->m_NoiseDistributionBox->currentIndex()) { case 0: { if (m_Parameters.m_SignalGen.m_NoiseVariance>0) { m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; m_Parameters.m_Misc.m_ArtifactModelString += "_COMPLEX-GAUSSIAN-"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Complex Gaussian")); } break; } case 1: { if (m_Parameters.m_SignalGen.m_NoiseVariance>0) { m_Parameters.m_NoiseModel = std::make_shared< mitk::RicianNoiseModel >(); m_Parameters.m_Misc.m_ArtifactModelString += "_RICIAN-"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Rician")); m_Parameters.m_NoiseModel->SetNoiseVariance(m_Parameters.m_SignalGen.m_NoiseVariance); } break; } case 2: { if (m_Parameters.m_SignalGen.m_NoiseVariance>0) { m_Parameters.m_NoiseModel = std::make_shared< mitk::ChiSquareNoiseModel >(); m_Parameters.m_Misc.m_ArtifactModelString += "_CHISQUARED-"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Chi-squared")); m_Parameters.m_NoiseModel->SetNoiseVariance(m_Parameters.m_SignalGen.m_NoiseVariance); } break; } default: { if (m_Parameters.m_SignalGen.m_NoiseVariance>0) { m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; m_Parameters.m_Misc.m_ArtifactModelString += "_COMPLEX-GAUSSIAN-"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Complex Gaussian")); } break; } } if (m_Parameters.m_SignalGen.m_NoiseVariance>0) { m_Parameters.m_Misc.m_ArtifactModelString += QString::number(m_Parameters.m_SignalGen.m_NoiseVariance).toStdString(); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Variance", DoubleProperty::New(m_Parameters.m_SignalGen.m_NoiseVariance)); } } // signal models { // compartment 1 switch (m_Controls->m_Compartment1Box->currentIndex()) { case 0: { mitk::StickModel* model = new mitk::StickModel(); model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(m_Parameters.m_SignalGen.GetBvalue()); model->SetDiffusivity(m_Controls->m_StickWidget1->GetD()); model->SetT2(m_Controls->m_StickWidget1->GetT2()); model->SetT1(m_Controls->m_StickWidget1->GetT1()); model->m_CompartmentId = 1; m_Parameters.m_FiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Stick"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Stick") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D", DoubleProperty::New(m_Controls->m_StickWidget1->GetD()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(model->GetT2()) ); break; } case 1: { mitk::TensorModel* model = new mitk::TensorModel(); model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(m_Parameters.m_SignalGen.GetBvalue()); model->SetDiffusivity1(m_Controls->m_ZeppelinWidget1->GetD1()); model->SetDiffusivity2(m_Controls->m_ZeppelinWidget1->GetD2()); model->SetDiffusivity3(m_Controls->m_ZeppelinWidget1->GetD2()); model->SetT2(m_Controls->m_ZeppelinWidget1->GetT2()); model->SetT1(m_Controls->m_ZeppelinWidget1->GetT1()); model->m_CompartmentId = 1; m_Parameters.m_FiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Zeppelin"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Zeppelin") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D1", DoubleProperty::New(m_Controls->m_ZeppelinWidget1->GetD1()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D2", DoubleProperty::New(m_Controls->m_ZeppelinWidget1->GetD2()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(model->GetT2()) ); break; } case 2: { mitk::TensorModel* model = new mitk::TensorModel(); model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(m_Parameters.m_SignalGen.GetBvalue()); model->SetDiffusivity1(m_Controls->m_TensorWidget1->GetD1()); model->SetDiffusivity2(m_Controls->m_TensorWidget1->GetD2()); model->SetDiffusivity3(m_Controls->m_TensorWidget1->GetD3()); model->SetT2(m_Controls->m_TensorWidget1->GetT2()); model->SetT1(m_Controls->m_TensorWidget1->GetT1()); model->m_CompartmentId = 1; m_Parameters.m_FiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Tensor"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Tensor") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D1", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD1()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D2", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD2()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D3", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD3()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(model->GetT2()) ); break; } case 3: { mitk::RawShModel* model = new mitk::RawShModel(); m_Parameters.m_SignalGen.m_DoSimulateRelaxation = false; model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetMaxNumKernels(m_Controls->m_PrototypeWidget1->GetNumberOfSamples()); model->SetFaRange(m_Controls->m_PrototypeWidget1->GetMinFa(), m_Controls->m_PrototypeWidget1->GetMaxFa()); model->SetAdcRange(m_Controls->m_PrototypeWidget1->GetMinAdc(), m_Controls->m_PrototypeWidget1->GetMaxAdc()); model->m_CompartmentId = 1; m_Parameters.m_FiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Prototype"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Prototype") ); break; } } if (m_Controls->m_Comp1VolumeFraction->GetSelectedNode().IsNotNull()) { mitk::DataNode::Pointer volumeNode = m_Controls->m_Comp1VolumeFraction->GetSelectedNode(); ItkDoubleImgType::Pointer comp1VolumeImage = ItkDoubleImgType::New(); mitk::Image* img = dynamic_cast(volumeNode->GetData()); CastToItkImage< ItkDoubleImgType >(img, comp1VolumeImage); m_Parameters.m_FiberModelList.back()->SetVolumeFractionImage(comp1VolumeImage); } // compartment 2 switch (m_Controls->m_Compartment2Box->currentIndex()) { case 0: break; case 1: { mitk::StickModel* model = new mitk::StickModel(); model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(m_Parameters.m_SignalGen.GetBvalue()); model->SetDiffusivity(m_Controls->m_StickWidget2->GetD()); model->SetT2(m_Controls->m_StickWidget2->GetT2()); model->SetT1(m_Controls->m_StickWidget2->GetT1()); model->m_CompartmentId = 2; m_Parameters.m_FiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Stick"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Stick") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D", DoubleProperty::New(m_Controls->m_StickWidget2->GetD()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(model->GetT2()) ); break; } case 2: { mitk::TensorModel* model = new mitk::TensorModel(); model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(m_Parameters.m_SignalGen.GetBvalue()); model->SetDiffusivity1(m_Controls->m_ZeppelinWidget2->GetD1()); model->SetDiffusivity2(m_Controls->m_ZeppelinWidget2->GetD2()); model->SetDiffusivity3(m_Controls->m_ZeppelinWidget2->GetD2()); model->SetT2(m_Controls->m_ZeppelinWidget2->GetT2()); model->SetT1(m_Controls->m_ZeppelinWidget2->GetT1()); model->m_CompartmentId = 2; m_Parameters.m_FiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Zeppelin"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Zeppelin") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D1", DoubleProperty::New(m_Controls->m_ZeppelinWidget2->GetD1()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D2", DoubleProperty::New(m_Controls->m_ZeppelinWidget2->GetD2()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(model->GetT2()) ); break; } case 3: { mitk::TensorModel* model = new mitk::TensorModel(); model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(m_Parameters.m_SignalGen.GetBvalue()); model->SetDiffusivity1(m_Controls->m_TensorWidget2->GetD1()); model->SetDiffusivity2(m_Controls->m_TensorWidget2->GetD2()); model->SetDiffusivity3(m_Controls->m_TensorWidget2->GetD3()); model->SetT2(m_Controls->m_TensorWidget2->GetT2()); model->SetT1(m_Controls->m_TensorWidget2->GetT1()); model->m_CompartmentId = 2; m_Parameters.m_FiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Tensor"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Tensor") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D1", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD1()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D2", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD2()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D3", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD3()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(model->GetT2()) ); break; } } if (m_Controls->m_Comp2VolumeFraction->GetSelectedNode().IsNotNull() && m_Parameters.m_FiberModelList.size()==2) { mitk::DataNode::Pointer volumeNode = m_Controls->m_Comp2VolumeFraction->GetSelectedNode(); ItkDoubleImgType::Pointer comp1VolumeImage = ItkDoubleImgType::New(); mitk::Image* img = dynamic_cast(volumeNode->GetData()); CastToItkImage< ItkDoubleImgType >(img, comp1VolumeImage); m_Parameters.m_FiberModelList.back()->SetVolumeFractionImage(comp1VolumeImage); } // compartment 3 switch (m_Controls->m_Compartment3Box->currentIndex()) { case 0: { mitk::BallModel* model = new mitk::BallModel(); model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(m_Parameters.m_SignalGen.GetBvalue()); model->SetDiffusivity(m_Controls->m_BallWidget1->GetD()); model->SetT2(m_Controls->m_BallWidget1->GetT2()); model->SetT1(m_Controls->m_BallWidget1->GetT1()); model->m_CompartmentId = 3; m_Parameters.m_NonFiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Ball"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Ball") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.D", DoubleProperty::New(m_Controls->m_BallWidget1->GetD()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(model->GetT2()) ); break; } case 1: { mitk::AstroStickModel* model = new mitk::AstroStickModel(); model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(m_Parameters.m_SignalGen.GetBvalue()); model->SetDiffusivity(m_Controls->m_AstrosticksWidget1->GetD()); model->SetT2(m_Controls->m_AstrosticksWidget1->GetT2()); model->SetT1(m_Controls->m_AstrosticksWidget1->GetT1()); model->SetRandomizeSticks(m_Controls->m_AstrosticksWidget1->GetRandomizeSticks()); model->m_CompartmentId = 3; m_Parameters.m_NonFiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Astrosticks"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Astrosticks") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.D", DoubleProperty::New(m_Controls->m_AstrosticksWidget1->GetD()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(model->GetT2()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.RandomSticks", BoolProperty::New(m_Controls->m_AstrosticksWidget1->GetRandomizeSticks()) ); break; } case 2: { mitk::DotModel* model = new mitk::DotModel(); model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetT2(m_Controls->m_DotWidget1->GetT2()); model->SetT1(m_Controls->m_DotWidget1->GetT1()); model->m_CompartmentId = 3; m_Parameters.m_NonFiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Dot"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Dot") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(model->GetT2()) ); break; } case 3: { mitk::RawShModel* model = new mitk::RawShModel(); m_Parameters.m_SignalGen.m_DoSimulateRelaxation = false; model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetMaxNumKernels(m_Controls->m_PrototypeWidget3->GetNumberOfSamples()); model->SetFaRange(m_Controls->m_PrototypeWidget3->GetMinFa(), m_Controls->m_PrototypeWidget3->GetMaxFa()); model->SetAdcRange(m_Controls->m_PrototypeWidget3->GetMinAdc(), m_Controls->m_PrototypeWidget3->GetMaxAdc()); model->m_CompartmentId = 3; m_Parameters.m_NonFiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Prototype"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Prototype") ); break; } } if (m_Controls->m_Comp3VolumeFraction->GetSelectedNode().IsNotNull()) { mitk::DataNode::Pointer volumeNode = m_Controls->m_Comp3VolumeFraction->GetSelectedNode(); ItkDoubleImgType::Pointer comp1VolumeImage = ItkDoubleImgType::New(); mitk::Image* img = dynamic_cast(volumeNode->GetData()); CastToItkImage< ItkDoubleImgType >(img, comp1VolumeImage); m_Parameters.m_NonFiberModelList.back()->SetVolumeFractionImage(comp1VolumeImage); } switch (m_Controls->m_Compartment4Box->currentIndex()) { case 0: break; case 1: { mitk::BallModel* model = new mitk::BallModel(); model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(m_Parameters.m_SignalGen.GetBvalue()); model->SetDiffusivity(m_Controls->m_BallWidget2->GetD()); model->SetT2(m_Controls->m_BallWidget2->GetT2()); model->SetT1(m_Controls->m_BallWidget2->GetT1()); model->m_CompartmentId = 4; m_Parameters.m_NonFiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Ball"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Ball") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.D", DoubleProperty::New(m_Controls->m_BallWidget2->GetD()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(model->GetT2()) ); break; } case 2: { mitk::AstroStickModel* model = new mitk::AstroStickModel(); model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(m_Parameters.m_SignalGen.GetBvalue()); model->SetDiffusivity(m_Controls->m_AstrosticksWidget2->GetD()); model->SetT2(m_Controls->m_AstrosticksWidget2->GetT2()); model->SetT1(m_Controls->m_AstrosticksWidget2->GetT1()); model->SetRandomizeSticks(m_Controls->m_AstrosticksWidget2->GetRandomizeSticks()); model->m_CompartmentId = 4; m_Parameters.m_NonFiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Astrosticks"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Astrosticks") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.D", DoubleProperty::New(m_Controls->m_AstrosticksWidget2->GetD()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(model->GetT2()) ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.RandomSticks", BoolProperty::New(m_Controls->m_AstrosticksWidget2->GetRandomizeSticks()) ); break; } case 3: { mitk::DotModel* model = new mitk::DotModel(); model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetT2(m_Controls->m_DotWidget2->GetT2()); model->SetT1(m_Controls->m_DotWidget2->GetT1()); model->m_CompartmentId = 4; m_Parameters.m_NonFiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Dot"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Dot") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(model->GetT2()) ); break; } case 4: { mitk::RawShModel* model = new mitk::RawShModel(); m_Parameters.m_SignalGen.m_DoSimulateRelaxation = false; model->SetGradientList(m_Parameters.m_SignalGen.GetGradientDirections()); model->SetMaxNumKernels(m_Controls->m_PrototypeWidget4->GetNumberOfSamples()); model->SetFaRange(m_Controls->m_PrototypeWidget4->GetMinFa(), m_Controls->m_PrototypeWidget4->GetMaxFa()); model->SetAdcRange(m_Controls->m_PrototypeWidget4->GetMinAdc(), m_Controls->m_PrototypeWidget4->GetMaxAdc()); model->m_CompartmentId = 4; m_Parameters.m_NonFiberModelList.push_back(model); m_Parameters.m_Misc.m_SignalModelString += "Prototype"; m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Prototype") ); break; } } if (m_Controls->m_Comp4VolumeFraction->GetSelectedNode().IsNotNull() && m_Parameters.m_NonFiberModelList.size()==2) { mitk::DataNode::Pointer volumeNode = m_Controls->m_Comp4VolumeFraction->GetSelectedNode(); ItkDoubleImgType::Pointer compVolumeImage = ItkDoubleImgType::New(); mitk::Image* img = dynamic_cast(volumeNode->GetData()); CastToItkImage< ItkDoubleImgType >(img, compVolumeImage); m_Parameters.m_NonFiberModelList.back()->SetVolumeFractionImage(compVolumeImage); } } m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.SignalScale", IntProperty::New(m_Parameters.m_SignalGen.m_SignalScale)); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.FiberRadius", IntProperty::New(m_Parameters.m_SignalGen.m_AxonRadius)); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Tinhom", DoubleProperty::New(m_Parameters.m_SignalGen.m_tInhom)); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.echoTrainLength", IntProperty::New(m_Parameters.m_SignalGen.m_EchoTrainLength)); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Tline", DoubleProperty::New(m_Parameters.m_SignalGen.m_tLine)); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.TE", DoubleProperty::New(m_Parameters.m_SignalGen.m_tEcho)); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.b-value", DoubleProperty::New(m_Parameters.m_SignalGen.GetBvalue())); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.NoPartialVolume", BoolProperty::New(m_Parameters.m_SignalGen.m_DoDisablePartialVolume)); m_Parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Relaxation", BoolProperty::New(m_Parameters.m_SignalGen.m_DoSimulateRelaxation)); m_Parameters.m_Misc.m_ResultNode->AddProperty("binary", BoolProperty::New(false)); } void QmitkFiberfoxView::SaveParameters(QString filename) { UpdateParametersFromGui(); std::vector< int > bVals = m_Parameters.m_SignalGen.GetBvalues(); std::cout << "b-values: "; for (auto v : bVals) std::cout << v << " "; std::cout << std::endl; bool ok = true; bool first = true; bool dosampling = false; mitk::Image::Pointer diffImg = nullptr; itk::Image< itk::DiffusionTensor3D< double >, 3 >::Pointer tensorImage = nullptr; const int shOrder = 2; typedef itk::AnalyticalDiffusionQballReconstructionImageFilter QballFilterType; QballFilterType::CoefficientImageType::Pointer itkFeatureImage = nullptr; ItkDoubleImgType::Pointer adcImage = nullptr; for (unsigned int i=0; i* model = nullptr; if (i* >(m_Parameters.m_FiberModelList.at(i)); } else { model = dynamic_cast< mitk::RawShModel<>* >(m_Parameters.m_NonFiberModelList.at(i-m_Parameters.m_FiberModelList.size())); } if ( model!=nullptr && model->GetNumberOfKernels() <= 0 ) { if (first==true) { if ( QMessageBox::question(nullptr, "Prototype signal sampling", "Do you want to sample prototype signals from the selected diffusion-weighted imag and save them?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes ) dosampling = true; first = false; if ( dosampling && (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNull() || !mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()) ) ) ) { QMessageBox::information(nullptr, "Parameter file not saved", "No diffusion-weighted image selected to sample signal from."); return; } else if (dosampling) { diffImg = dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()); typedef itk::DiffusionTensor3DReconstructionImageFilter< short, short, double > TensorReconstructionImageFilterType; TensorReconstructionImageFilterType::Pointer filter = TensorReconstructionImageFilterType::New(); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(diffImg, itkVectorImagePointer); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(diffImg)); - filter->SetGradientImage(mitk::DiffusionPropertyHelper::GetGradientContainer(diffImg), + filter->SetGradientImage(dynamic_cast(diffImg->GetProperty(mitk::DiffusionPropertyHelper::GetGradientContainerPropertyName().c_str()).GetPointer())->GetGradientDirectionsContainerCopy(), itkVectorImagePointer ); filter->Update(); tensorImage = filter->GetOutput(); QballFilterType::Pointer qballfilter = QballFilterType::New(); qballfilter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(diffImg)); qballfilter->SetGradientImage(mitk::DiffusionPropertyHelper::GetGradientContainer(diffImg), itkVectorImagePointer ); qballfilter->SetLambda(0.006); qballfilter->SetNormalizationMethod(QballFilterType::QBAR_RAW_SIGNAL); qballfilter->Update(); itkFeatureImage = qballfilter->GetCoefficientImage(); itk::AdcImageFilter< short, double >::Pointer adcFilter = itk::AdcImageFilter< short, double >::New(); adcFilter->SetInput( itkVectorImagePointer ); adcFilter->SetGradientDirections(mitk::DiffusionPropertyHelper::GetGradientContainer(diffImg)); adcFilter->SetB_value(mitk::DiffusionPropertyHelper::GetReferenceBValue(diffImg)); adcFilter->Update(); adcImage = adcFilter->GetOutput(); } } typedef itk::DiffusionTensor3DReconstructionImageFilter< short, short, double > TensorReconstructionImageFilterType; TensorReconstructionImageFilterType::Pointer filter = TensorReconstructionImageFilterType::New(); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(diffImg, itkVectorImagePointer); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(diffImg)); - filter->SetGradientImage(mitk::DiffusionPropertyHelper::GetGradientContainer(diffImg), itkVectorImagePointer ); + filter->SetGradientImage(dynamic_cast(diffImg->GetProperty(mitk::DiffusionPropertyHelper::GetGradientContainerPropertyName().c_str()).GetPointer())->GetGradientDirectionsContainerCopy(), itkVectorImagePointer ); filter->Update(); tensorImage = filter->GetOutput(); QballFilterType::Pointer qballfilter = QballFilterType::New(); qballfilter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(diffImg)); qballfilter->SetGradientImage(mitk::DiffusionPropertyHelper::GetGradientContainer(diffImg), itkVectorImagePointer ); qballfilter->SetLambda(0.006); qballfilter->SetNormalizationMethod(QballFilterType::QBAR_RAW_SIGNAL); qballfilter->Update(); itkFeatureImage = qballfilter->GetCoefficientImage(); itk::AdcImageFilter< short, double >::Pointer adcFilter = itk::AdcImageFilter< short, double >::New(); adcFilter->SetInput( itkVectorImagePointer ); adcFilter->SetGradientDirections(mitk::DiffusionPropertyHelper::GetGradientContainer(diffImg)); adcFilter->SetB_value(mitk::DiffusionPropertyHelper::GetReferenceBValue(diffImg)); adcFilter->Update(); adcImage = adcFilter->GetOutput(); if (dosampling && diffImg.IsNotNull()) { ok = model->SampleKernels(diffImg, m_Parameters.m_SignalGen.m_MaskImage, tensorImage, itkFeatureImage, adcImage); if (!ok) { QMessageBox::information( nullptr, "Parameter file not saved", "No valid prototype signals could be sampled."); return; } } } } m_Parameters.SaveParameters(filename.toStdString()); m_ParameterFile = filename; } void QmitkFiberfoxView::SaveParameters() { QString filename = QFileDialog::getSaveFileName( 0, tr("Save Parameters"), m_ParameterFile, tr("Fiberfox Parameters (*.ffp)") ); SaveParameters(filename); } void QmitkFiberfoxView::LoadParameters() { QString filename = QFileDialog::getOpenFileName(0, tr("Load Parameters"), QString(itksys::SystemTools::GetFilenamePath(m_ParameterFile.toStdString()).c_str()), tr("Fiberfox Parameters (*.ffp)") ); if(filename.isEmpty() || filename.isNull()) return; m_ParameterFile = filename; m_Parameters.LoadParameters(filename.toStdString()); if (m_Parameters.m_MissingTags.size()>0) { QString missing("Parameter file might be corrupted. The following parameters could not be read: "); missing += QString(m_Parameters.m_MissingTags.c_str()); missing += "\nDefault values have been assigned to the missing parameters."; QMessageBox::information( nullptr, "Warning!", missing); } // image generation parameters m_Controls->m_SizeX->setValue(m_Parameters.m_SignalGen.m_ImageRegion.GetSize(0)); m_Controls->m_SizeY->setValue(m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1)); m_Controls->m_SizeZ->setValue(m_Parameters.m_SignalGen.m_ImageRegion.GetSize(2)); m_Controls->m_SpacingX->setValue(m_Parameters.m_SignalGen.m_ImageSpacing[0]); m_Controls->m_SpacingY->setValue(m_Parameters.m_SignalGen.m_ImageSpacing[1]); m_Controls->m_SpacingZ->setValue(m_Parameters.m_SignalGen.m_ImageSpacing[2]); m_Controls->m_NumGradientsBox->setValue(m_Parameters.m_SignalGen.GetNumWeightedVolumes()); m_Controls->m_BvalueBox->setValue(m_Parameters.m_SignalGen.GetBvalue()); m_Controls->m_SignalScaleBox->setValue(m_Parameters.m_SignalGen.m_SignalScale); m_Controls->m_TEbox->setValue(m_Parameters.m_SignalGen.m_tEcho); m_Controls->m_LineReadoutTimeBox->setValue(m_Parameters.m_SignalGen.m_tLine); m_Controls->m_T2starBox->setValue(m_Parameters.m_SignalGen.m_tInhom); m_Controls->m_EtlBox->setValue(m_Parameters.m_SignalGen.m_EchoTrainLength); m_Controls->m_FiberRadius->setValue(m_Parameters.m_SignalGen.m_AxonRadius); m_Controls->m_RelaxationBox->setChecked(m_Parameters.m_SignalGen.m_DoSimulateRelaxation); m_Controls->m_EnforcePureFiberVoxelsBox->setChecked(m_Parameters.m_SignalGen.m_DoDisablePartialVolume); m_Controls->m_ReversePhaseBox->setChecked(m_Parameters.m_SignalGen.m_ReversePhase); m_Controls->m_PartialFourier->setValue(m_Parameters.m_SignalGen.m_PartialFourier); m_Controls->m_TRbox->setValue(m_Parameters.m_SignalGen.m_tRep); m_Controls->m_TIbox->setValue(m_Parameters.m_SignalGen.m_tInv); m_Controls->m_NumCoilsBox->setValue(m_Parameters.m_SignalGen.m_NumberOfCoils); m_Controls->m_CoilSensBox->setCurrentIndex(m_Parameters.m_SignalGen.m_CoilSensitivityProfile); m_Controls->m_AcquisitionTypeBox->setCurrentIndex(m_Parameters.m_SignalGen.m_AcquisitionType); if (!m_Parameters.m_Misc.m_BvalsFile.empty()) { m_Controls->m_UseBvalsBvecsBox->setChecked(true); m_Controls->m_LoadBvalsEdit->setText(QString(m_Parameters.m_Misc.m_BvalsFile.c_str())); } else m_Controls->m_LoadBvalsEdit->setText("-"); if (!m_Parameters.m_Misc.m_BvecsFile.empty()) { m_Controls->m_UseBvalsBvecsBox->setChecked(true); m_Controls->m_LoadBvecsEdit->setText(QString(m_Parameters.m_Misc.m_BvecsFile.c_str())); } else m_Controls->m_LoadBvecsEdit->setText("-"); if (m_Parameters.m_NoiseModel!=nullptr) { m_Controls->m_AddNoise->setChecked(m_Parameters.m_Misc.m_DoAddNoise); if (dynamic_cast*>(m_Parameters.m_NoiseModel.get())) { m_Controls->m_NoiseDistributionBox->setCurrentIndex(0); } else if (dynamic_cast*>(m_Parameters.m_NoiseModel.get())) { m_Controls->m_NoiseDistributionBox->setCurrentIndex(1); } m_Controls->m_NoiseLevel->setValue(m_Parameters.m_NoiseModel->GetNoiseVariance()); } else { m_Controls->m_AddNoise->setChecked(m_Parameters.m_Misc.m_DoAddNoise); m_Controls->m_NoiseLevel->setValue(m_Parameters.m_SignalGen.m_NoiseVariance); } m_Controls->m_VolumeFractionsBox->setChecked(m_Parameters.m_Misc.m_OutputAdditionalImages); m_Controls->m_AdvancedOptionsBox_2->setChecked(m_Parameters.m_Misc.m_CheckAdvancedSignalOptionsBox); m_Controls->m_AddGhosts->setChecked(m_Parameters.m_Misc.m_DoAddGhosts); m_Controls->m_AddAliasing->setChecked(m_Parameters.m_Misc.m_DoAddAliasing); m_Controls->m_AddDistortions->setChecked(m_Parameters.m_Misc.m_DoAddDistortions); m_Controls->m_AddSpikes->setChecked(m_Parameters.m_Misc.m_DoAddSpikes); m_Controls->m_AddEddy->setChecked(m_Parameters.m_Misc.m_DoAddEddyCurrents); m_Controls->m_AddDrift->setChecked(m_Parameters.m_SignalGen.m_DoAddDrift); m_Controls->m_kOffsetBox->setValue(m_Parameters.m_SignalGen.m_KspaceLineOffset); m_Controls->m_WrapBox->setValue(100*(1-m_Parameters.m_SignalGen.m_CroppingFactor)); m_Controls->m_DriftFactor->setValue(100*m_Parameters.m_SignalGen.m_Drift); m_Controls->m_SpikeNumBox->setValue(m_Parameters.m_SignalGen.m_Spikes); m_Controls->m_SpikeScaleBox->setValue(m_Parameters.m_SignalGen.m_SpikeAmplitude); m_Controls->m_EddyGradientStrength->setValue(m_Parameters.m_SignalGen.m_EddyStrength); m_Controls->m_AddGibbsRinging->setChecked(m_Parameters.m_SignalGen.m_DoAddGibbsRinging); m_Controls->m_ZeroRinging->setValue(m_Parameters.m_SignalGen.m_ZeroRinging); m_Controls->m_AddMotion->setChecked(m_Parameters.m_SignalGen.m_DoAddMotion); m_Controls->m_RandomMotion->setChecked(m_Parameters.m_SignalGen.m_DoRandomizeMotion); m_Controls->m_MotionVolumesBox->setText(QString(m_Parameters.m_Misc.m_MotionVolumesBox.c_str())); m_Controls->m_MaxTranslationBoxX->setValue(m_Parameters.m_SignalGen.m_Translation[0]); m_Controls->m_MaxTranslationBoxY->setValue(m_Parameters.m_SignalGen.m_Translation[1]); m_Controls->m_MaxTranslationBoxZ->setValue(m_Parameters.m_SignalGen.m_Translation[2]); m_Controls->m_MaxRotationBoxX->setValue(m_Parameters.m_SignalGen.m_Rotation[0]); m_Controls->m_MaxRotationBoxY->setValue(m_Parameters.m_SignalGen.m_Rotation[1]); m_Controls->m_MaxRotationBoxZ->setValue(m_Parameters.m_SignalGen.m_Rotation[2]); m_Controls->m_Compartment1Box->setCurrentIndex(0); m_Controls->m_Compartment2Box->setCurrentIndex(0); m_Controls->m_Compartment3Box->setCurrentIndex(0); m_Controls->m_Compartment4Box->setCurrentIndex(0); for (unsigned int i=0; i* signalModel = nullptr; if (iGetVolumeFractionImage().IsNotNull() ) { compVolNode = mitk::DataNode::New(); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(signalModel->GetVolumeFractionImage().GetPointer()); image->SetVolume(signalModel->GetVolumeFractionImage()->GetBufferPointer()); compVolNode->SetData( image ); compVolNode->SetName("Compartment volume "+QString::number(signalModel->m_CompartmentId).toStdString()); GetDataStorage()->Add(compVolNode); } switch (signalModel->m_CompartmentId) { case 1: { if (compVolNode.IsNotNull()) m_Controls->m_Comp1VolumeFraction->SetSelectedNode(compVolNode); if (dynamic_cast*>(signalModel)) { mitk::StickModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_StickWidget1->SetT2(model->GetT2()); m_Controls->m_StickWidget1->SetT1(model->GetT1()); m_Controls->m_StickWidget1->SetD(model->GetDiffusivity()); m_Controls->m_Compartment1Box->setCurrentIndex(0); break; } else if (dynamic_cast*>(signalModel)) { mitk::TensorModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_TensorWidget1->SetT2(model->GetT2()); m_Controls->m_TensorWidget1->SetT1(model->GetT1()); m_Controls->m_TensorWidget1->SetD1(model->GetDiffusivity1()); m_Controls->m_TensorWidget1->SetD2(model->GetDiffusivity2()); m_Controls->m_TensorWidget1->SetD3(model->GetDiffusivity3()); m_Controls->m_Compartment1Box->setCurrentIndex(2); break; } else if (dynamic_cast*>(signalModel)) { mitk::RawShModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_PrototypeWidget1->SetNumberOfSamples(model->GetMaxNumKernels()); m_Controls->m_PrototypeWidget1->SetMinFa(model->GetFaRange().first); m_Controls->m_PrototypeWidget1->SetMaxFa(model->GetFaRange().second); m_Controls->m_PrototypeWidget1->SetMinAdc(model->GetAdcRange().first); m_Controls->m_PrototypeWidget1->SetMaxAdc(model->GetAdcRange().second); m_Controls->m_Compartment1Box->setCurrentIndex(3); break; } break; } case 2: { if (compVolNode.IsNotNull()) m_Controls->m_Comp2VolumeFraction->SetSelectedNode(compVolNode); if (dynamic_cast*>(signalModel)) { mitk::StickModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_StickWidget2->SetT2(model->GetT2()); m_Controls->m_StickWidget2->SetT1(model->GetT1()); m_Controls->m_StickWidget2->SetD(model->GetDiffusivity()); m_Controls->m_Compartment2Box->setCurrentIndex(1); break; } else if (dynamic_cast*>(signalModel)) { mitk::TensorModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_TensorWidget2->SetT2(model->GetT2()); m_Controls->m_TensorWidget2->SetT1(model->GetT1()); m_Controls->m_TensorWidget2->SetD1(model->GetDiffusivity1()); m_Controls->m_TensorWidget2->SetD2(model->GetDiffusivity2()); m_Controls->m_TensorWidget2->SetD3(model->GetDiffusivity3()); m_Controls->m_Compartment2Box->setCurrentIndex(3); break; } break; } case 3: { if (compVolNode.IsNotNull()) m_Controls->m_Comp3VolumeFraction->SetSelectedNode(compVolNode); if (dynamic_cast*>(signalModel)) { mitk::BallModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_BallWidget1->SetT2(model->GetT2()); m_Controls->m_BallWidget1->SetT1(model->GetT1()); m_Controls->m_BallWidget1->SetD(model->GetDiffusivity()); m_Controls->m_Compartment3Box->setCurrentIndex(0); break; } else if (dynamic_cast*>(signalModel)) { mitk::AstroStickModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_AstrosticksWidget1->SetT2(model->GetT2()); m_Controls->m_AstrosticksWidget1->SetT1(model->GetT1()); m_Controls->m_AstrosticksWidget1->SetD(model->GetDiffusivity()); m_Controls->m_AstrosticksWidget1->SetRandomizeSticks(model->GetRandomizeSticks()); m_Controls->m_Compartment3Box->setCurrentIndex(1); break; } else if (dynamic_cast*>(signalModel)) { mitk::DotModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_DotWidget1->SetT2(model->GetT2()); m_Controls->m_DotWidget1->SetT1(model->GetT1()); m_Controls->m_Compartment3Box->setCurrentIndex(2); break; } else if (dynamic_cast*>(signalModel)) { mitk::RawShModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_PrototypeWidget3->SetNumberOfSamples(model->GetMaxNumKernels()); m_Controls->m_PrototypeWidget3->SetMinFa(model->GetFaRange().first); m_Controls->m_PrototypeWidget3->SetMaxFa(model->GetFaRange().second); m_Controls->m_PrototypeWidget3->SetMinAdc(model->GetAdcRange().first); m_Controls->m_PrototypeWidget3->SetMaxAdc(model->GetAdcRange().second); m_Controls->m_Compartment3Box->setCurrentIndex(3); break; } break; } case 4: { if (compVolNode.IsNotNull()) m_Controls->m_Comp4VolumeFraction->SetSelectedNode(compVolNode); if (dynamic_cast*>(signalModel)) { mitk::BallModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_BallWidget2->SetT2(model->GetT2()); m_Controls->m_BallWidget2->SetT1(model->GetT1()); m_Controls->m_BallWidget2->SetD(model->GetDiffusivity()); m_Controls->m_Compartment4Box->setCurrentIndex(1); break; } else if (dynamic_cast*>(signalModel)) { mitk::AstroStickModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_AstrosticksWidget2->SetT2(model->GetT2()); m_Controls->m_AstrosticksWidget2->SetT1(model->GetT1()); m_Controls->m_AstrosticksWidget2->SetD(model->GetDiffusivity()); m_Controls->m_AstrosticksWidget2->SetRandomizeSticks(model->GetRandomizeSticks()); m_Controls->m_Compartment4Box->setCurrentIndex(2); break; } else if (dynamic_cast*>(signalModel)) { mitk::DotModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_DotWidget2->SetT2(model->GetT2()); m_Controls->m_DotWidget2->SetT1(model->GetT1()); m_Controls->m_Compartment4Box->setCurrentIndex(3); break; } else if (dynamic_cast*>(signalModel)) { mitk::RawShModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_PrototypeWidget4->SetNumberOfSamples(model->GetMaxNumKernels()); m_Controls->m_PrototypeWidget4->SetMinFa(model->GetFaRange().first); m_Controls->m_PrototypeWidget4->SetMaxFa(model->GetFaRange().second); m_Controls->m_PrototypeWidget4->SetMinAdc(model->GetAdcRange().first); m_Controls->m_PrototypeWidget4->SetMaxAdc(model->GetAdcRange().second); m_Controls->m_Compartment4Box->setCurrentIndex(4); break; } break; } } } if ( m_Parameters.m_SignalGen.m_MaskImage ) { mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(m_Parameters.m_SignalGen.m_MaskImage.GetPointer()); image->SetVolume(m_Parameters.m_SignalGen.m_MaskImage->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("Tissue mask"); GetDataStorage()->Add(node); m_Controls->m_MaskComboBox->SetSelectedNode(node); } if ( m_Parameters.m_SignalGen.m_FrequencyMap ) { mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(m_Parameters.m_SignalGen.m_FrequencyMap.GetPointer()); image->SetVolume(m_Parameters.m_SignalGen.m_FrequencyMap->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("Frequency map"); GetDataStorage()->Add(node); m_Controls->m_FrequencyMapBox->SetSelectedNode(node); } } void QmitkFiberfoxView::ShowAdvancedOptions(int state) { if (state) { m_Controls->m_AdvancedSignalOptionsFrame->setVisible(true); m_Controls->m_AdvancedOptionsBox_2->setChecked(true); } else { m_Controls->m_AdvancedSignalOptionsFrame->setVisible(false); m_Controls->m_AdvancedOptionsBox_2->setChecked(false); } } void QmitkFiberfoxView::Comp1ModelFrameVisibility(int index) { m_Controls->m_StickWidget1->setVisible(false); m_Controls->m_ZeppelinWidget1->setVisible(false); m_Controls->m_TensorWidget1->setVisible(false); m_Controls->m_PrototypeWidget1->setVisible(false); switch (index) { case 0: m_Controls->m_StickWidget1->setVisible(true); break; case 1: m_Controls->m_ZeppelinWidget1->setVisible(true); break; case 2: m_Controls->m_TensorWidget1->setVisible(true); break; case 3: m_Controls->m_PrototypeWidget1->setVisible(true); break; } } void QmitkFiberfoxView::Comp2ModelFrameVisibility(int index) { m_Controls->m_StickWidget2->setVisible(false); m_Controls->m_ZeppelinWidget2->setVisible(false); m_Controls->m_TensorWidget2->setVisible(false); m_Controls->m_Comp2FractionFrame->setVisible(false); switch (index) { case 0: break; case 1: m_Controls->m_StickWidget2->setVisible(true); m_Controls->m_Comp2FractionFrame->setVisible(true); break; case 2: m_Controls->m_ZeppelinWidget2->setVisible(true); m_Controls->m_Comp2FractionFrame->setVisible(true); break; case 3: m_Controls->m_TensorWidget2->setVisible(true); m_Controls->m_Comp2FractionFrame->setVisible(true); break; } } void QmitkFiberfoxView::Comp3ModelFrameVisibility(int index) { m_Controls->m_BallWidget1->setVisible(false); m_Controls->m_AstrosticksWidget1->setVisible(false); m_Controls->m_DotWidget1->setVisible(false); m_Controls->m_PrototypeWidget3->setVisible(false); switch (index) { case 0: m_Controls->m_BallWidget1->setVisible(true); break; case 1: m_Controls->m_AstrosticksWidget1->setVisible(true); break; case 2: m_Controls->m_DotWidget1->setVisible(true); break; case 3: m_Controls->m_PrototypeWidget3->setVisible(true); break; } } void QmitkFiberfoxView::Comp4ModelFrameVisibility(int index) { m_Controls->m_BallWidget2->setVisible(false); m_Controls->m_AstrosticksWidget2->setVisible(false); m_Controls->m_DotWidget2->setVisible(false); m_Controls->m_PrototypeWidget4->setVisible(false); m_Controls->m_Comp4FractionFrame->setVisible(false); switch (index) { case 0: break; case 1: m_Controls->m_BallWidget2->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; case 2: m_Controls->m_AstrosticksWidget2->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; case 3: m_Controls->m_DotWidget2->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; case 4: m_Controls->m_PrototypeWidget4->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; } } void QmitkFiberfoxView::OnAddMotion(int value) { if (value>0) m_Controls->m_MotionArtifactFrame->setVisible(true); else m_Controls->m_MotionArtifactFrame->setVisible(false); } void QmitkFiberfoxView::OnAddDrift(int value) { if (value>0) m_Controls->m_DriftFrame->setVisible(true); else m_Controls->m_DriftFrame->setVisible(false); } void QmitkFiberfoxView::OnAddAliasing(int value) { if (value>0) m_Controls->m_AliasingFrame->setVisible(true); else m_Controls->m_AliasingFrame->setVisible(false); } void QmitkFiberfoxView::OnAddSpikes(int value) { if (value>0) m_Controls->m_SpikeFrame->setVisible(true); else m_Controls->m_SpikeFrame->setVisible(false); } void QmitkFiberfoxView::OnAddEddy(int value) { if (value>0) m_Controls->m_EddyFrame->setVisible(true); else m_Controls->m_EddyFrame->setVisible(false); } void QmitkFiberfoxView::OnAddDistortions(int value) { if (value>0) m_Controls->m_DistortionsFrame->setVisible(true); else m_Controls->m_DistortionsFrame->setVisible(false); } void QmitkFiberfoxView::OnAddGhosts(int value) { if (value>0) m_Controls->m_GhostFrame->setVisible(true); else m_Controls->m_GhostFrame->setVisible(false); } void QmitkFiberfoxView::OnAddNoise(int value) { if (value>0) m_Controls->m_NoiseFrame->setVisible(true); else m_Controls->m_NoiseFrame->setVisible(false); } void QmitkFiberfoxView::OnAddRinging(int value) { if (value>0) m_Controls->m_ZeroRinging->setVisible(true); else m_Controls->m_ZeroRinging->setVisible(false); } QmitkFiberfoxView::GradientListType QmitkFiberfoxView::GenerateHalfShell(int NPoints) { NPoints *= 2; GradientListType pointshell; int numB0 = NPoints/20; if (numB0==0) numB0=1; GradientType g; g.Fill(0.0); for (int i=0; i theta; theta.set_size(NPoints); vnl_vector phi; phi.set_size(NPoints); double C = sqrt(4*itk::Math::pi); phi(0) = 0.0; phi(NPoints-1) = 0.0; for(int i=0; i0 && i std::vector > QmitkFiberfoxView::MakeGradientList() { std::vector > retval; vnl_matrix_fixed* U = itk::PointShell >::DistributePointShell(); // Add 0 vector for B0 int numB0 = ndirs/10; if (numB0==0) numB0=1; itk::Vector v; v.Fill(0.0); for (int i=0; i v; v[0] = U->get(0,i); v[1] = U->get(1,i); v[2] = U->get(2,i); retval.push_back(v); } return retval; } void QmitkFiberfoxView::GenerateImage() { if (m_Controls->m_FiberBundleComboBox->GetSelectedNode().IsNull() && !mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( m_Controls->m_TemplateComboBox->GetSelectedNode())) { mitk::Image::Pointer image = mitk::ImageGenerator::GenerateGradientImage( m_Controls->m_SizeX->value(), m_Controls->m_SizeY->value(), m_Controls->m_SizeZ->value(), m_Controls->m_SpacingX->value(), m_Controls->m_SpacingY->value(), m_Controls->m_SpacingZ->value()); mitk::Point3D origin; origin[0] = m_Controls->m_SpacingX->value()/2; origin[1] = m_Controls->m_SpacingY->value()/2; origin[2] = m_Controls->m_SpacingZ->value()/2; image->SetOrigin(origin); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("Dummy"); GetDataStorage()->Add(node); m_SelectedImageNode = node; mitk::BaseData::Pointer basedata = node->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } UpdateGui(); QMessageBox::information(nullptr, "Template image generated", "You have selected no fiber bundle or diffusion-weighted image, which can be used to simulate a new diffusion-weighted image. A template image with the specified geometry has been generated that can be used to draw artificial fibers (see view 'Fiber Generator')."); } else if (m_Controls->m_FiberBundleComboBox->GetSelectedNode().IsNotNull()) SimulateImageFromFibers(m_Controls->m_FiberBundleComboBox->GetSelectedNode()); else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( m_Controls->m_TemplateComboBox->GetSelectedNode()) ) SimulateForExistingDwi(m_Controls->m_TemplateComboBox->GetSelectedNode()); else QMessageBox::information(nullptr, "No image generated", "You have selected no fiber bundle or diffusion-weighted image, which can be used to simulate a new diffusion-weighted image."); } void QmitkFiberfoxView::SetFocus() { } void QmitkFiberfoxView::SimulateForExistingDwi(mitk::DataNode* imageNode) { bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(imageNode->GetData())) ); if ( !isDiffusionImage ) { return; } UpdateParametersFromGui(); mitk::Image::Pointer diffImg = dynamic_cast(imageNode->GetData()); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(diffImg, itkVectorImagePointer); m_TractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); m_Parameters.m_Misc.m_ParentNode = imageNode; m_Parameters.m_SignalGen.m_SignalScale = 1; m_Parameters.m_Misc.m_ResultNode->SetName("b"+QString::number(m_Parameters.m_SignalGen.GetBvalue()).toStdString() +"_"+m_Parameters.m_Misc.m_SignalModelString +m_Parameters.m_Misc.m_ArtifactModelString); m_Parameters.ApplyDirectionMatrix(); m_TractsToDwiFilter->SetParameters(m_Parameters); m_TractsToDwiFilter->SetInputImage(itkVectorImagePointer); m_Thread.start(QThread::LowestPriority); } void QmitkFiberfoxView::SimulateImageFromFibers(mitk::DataNode* fiberNode) { mitk::FiberBundle::Pointer fiberBundle = dynamic_cast(fiberNode->GetData()); if (fiberBundle->GetNumFibers()<=0) { return; } UpdateParametersFromGui(); m_TractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); m_Parameters.m_Misc.m_ParentNode = fiberNode; m_Parameters.m_Misc.m_ResultNode->SetName("b"+QString::number(m_Parameters.m_SignalGen.GetBvalue()).toStdString() +"_"+m_Parameters.m_Misc.m_SignalModelString +m_Parameters.m_Misc.m_ArtifactModelString); if ( m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull() && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast (m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()) ) ) { bool first = true; bool ok = true; mitk::Image::Pointer diffImg = dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()); itk::Image< itk::DiffusionTensor3D< double >, 3 >::Pointer tensorImage = nullptr; const int shOrder = 2; typedef itk::AnalyticalDiffusionQballReconstructionImageFilter QballFilterType; QballFilterType::CoefficientImageType::Pointer itkFeatureImage = nullptr; ItkDoubleImgType::Pointer adcImage = nullptr; for (unsigned int i=0; i* model = nullptr; if (i* >(m_Parameters.m_FiberModelList.at(i)); else model = dynamic_cast< mitk::RawShModel<>* >(m_Parameters.m_NonFiberModelList.at(i-m_Parameters.m_FiberModelList.size())); if (model!=0 && model->GetNumberOfKernels()<=0) { if (first==true) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(diffImg, itkVectorImagePointer); typedef itk::DiffusionTensor3DReconstructionImageFilter< short, short, double > TensorReconstructionImageFilterType; TensorReconstructionImageFilterType::Pointer filter = TensorReconstructionImageFilterType::New(); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(diffImg)); - filter->SetGradientImage(mitk::DiffusionPropertyHelper::GetGradientContainer(diffImg), + filter->SetGradientImage(dynamic_cast(diffImg->GetProperty(mitk::DiffusionPropertyHelper::GetGradientContainerPropertyName().c_str()).GetPointer())->GetGradientDirectionsContainerCopy(), itkVectorImagePointer ); filter->Update(); tensorImage = filter->GetOutput(); QballFilterType::Pointer qballfilter = QballFilterType::New(); qballfilter->SetGradientImage(mitk::DiffusionPropertyHelper::GetGradientContainer(diffImg), itkVectorImagePointer ); qballfilter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(diffImg)); qballfilter->SetLambda(0.006); qballfilter->SetNormalizationMethod(QballFilterType::QBAR_RAW_SIGNAL); qballfilter->Update(); itkFeatureImage = qballfilter->GetCoefficientImage(); itk::AdcImageFilter< short, double >::Pointer adcFilter = itk::AdcImageFilter< short, double >::New(); adcFilter->SetInput( itkVectorImagePointer ); adcFilter->SetGradientDirections(mitk::DiffusionPropertyHelper::GetGradientContainer(diffImg)); adcFilter->SetB_value(mitk::DiffusionPropertyHelper::GetReferenceBValue(diffImg)); adcFilter->Update(); adcImage = adcFilter->GetOutput(); } ok = model->SampleKernels(diffImg, m_Parameters.m_SignalGen.m_MaskImage, tensorImage, itkFeatureImage, adcImage); if (!ok) break; } } if (!ok) { QMessageBox::information( nullptr, "Simulation cancelled", "No valid prototype signals could be sampled."); return; } } else if ( m_Controls->m_Compartment1Box->currentIndex()==3 || m_Controls->m_Compartment3Box->currentIndex()==3 || m_Controls->m_Compartment4Box->currentIndex()==4 ) { QMessageBox::information( nullptr, "Simulation cancelled", "Prototype signal but no diffusion-weighted image selected to sample signal from."); return; } m_Parameters.ApplyDirectionMatrix(); m_TractsToDwiFilter->SetParameters(m_Parameters); m_TractsToDwiFilter->SetFiberBundle(fiberBundle); m_Thread.start(QThread::LowestPriority); } void QmitkFiberfoxView::SetBvalsEdit() { // SELECT FOLDER DIALOG std::string filename; filename = QFileDialog::getOpenFileName(nullptr, "Select bvals file", QString(filename.c_str())).toStdString(); if (filename.empty()) m_Controls->m_LoadBvalsEdit->setText("-"); else m_Controls->m_LoadBvalsEdit->setText(QString(filename.c_str())); } void QmitkFiberfoxView::SetBvecsEdit() { // SELECT FOLDER DIALOG std::string filename; filename = QFileDialog::getOpenFileName(nullptr, "Select bvecs file", QString(filename.c_str())).toStdString(); if (filename.empty()) m_Controls->m_LoadBvecsEdit->setText("-"); else m_Controls->m_LoadBvecsEdit->setText(QString(filename.c_str())); } void QmitkFiberfoxView::SetOutputPath() { // SELECT FOLDER DIALOG std::string outputPath; outputPath = QFileDialog::getExistingDirectory(nullptr, "Save images to...", QString(outputPath.c_str())).toStdString(); if (outputPath.empty()) m_Controls->m_SavePathEdit->setText("-"); else { outputPath += "/"; m_Controls->m_SavePathEdit->setText(QString(outputPath.c_str())); } } void QmitkFiberfoxView::UpdateGui() { OnTlineChanged(); m_Controls->m_GeometryFrame->setEnabled(true); m_Controls->m_GeometryMessage->setVisible(false); m_Controls->m_DiffusionPropsMessage->setVisible(false); m_Controls->m_LoadGradientsFrame->setVisible(false); m_Controls->m_GenerateGradientsFrame->setVisible(false); if (m_Controls->m_UseBvalsBvecsBox->isChecked()) m_Controls->m_LoadGradientsFrame->setVisible(true); else m_Controls->m_GenerateGradientsFrame->setVisible(true); // Signal generation gui if (m_Controls->m_MaskComboBox->GetSelectedNode().IsNotNull() || m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull()) { m_Controls->m_GeometryMessage->setVisible(true); m_Controls->m_GeometryFrame->setEnabled(false); } if ( m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull() && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()) ) ) { m_Controls->m_DiffusionPropsMessage->setVisible(true); m_Controls->m_GeometryMessage->setVisible(true); m_Controls->m_GeometryFrame->setEnabled(false); m_Controls->m_LoadGradientsFrame->setVisible(false); m_Controls->m_GenerateGradientsFrame->setVisible(false); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.cpp index 1b13de9..283253f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.cpp @@ -1,1095 +1,1095 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkIVIMView.h" // qt #include "qmessagebox.h" #include "qclipboard.h" // mitk #include "mitkImage.h" #include "mitkImageCast.h" #include "mitkLookupTable.h" #include "mitkLookupTableProperty.h" #include #include // itk #include "itkScalarImageToHistogramGenerator.h" #include "itkRegionOfInterestImageFilter.h" #include "itkImageRegionConstIteratorWithIndex.h" // itk/mitk #include "itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h" #include "itkRegularizedIVIMReconstructionFilter.h" #include "mitkImageCast.h" #include #include #include #include #include #include #include const std::string QmitkIVIMView::VIEW_ID = "org.mitk.views.ivim"; QmitkIVIMView::QmitkIVIMView() : QmitkAbstractView() , m_Controls( 0 ) , m_Active(false) , m_Visible(false) , m_HoldUpdate(false) { } QmitkIVIMView::~QmitkIVIMView() { } void QmitkIVIMView::CreateQtPartControl( QWidget *parent ) { // hold update untill all elements are set this->m_HoldUpdate = true; // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkIVIMViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_ButtonStart, SIGNAL(clicked()), this, SLOT(FittIVIMStart()) ); connect( m_Controls->m_ButtonAutoThres, SIGNAL(clicked()), this, SLOT(AutoThreshold()) ); connect( m_Controls->m_MethodCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnIvimFitChanged(int)) ); connect( m_Controls->m_DStarSlider, SIGNAL(valueChanged(int)), this, SLOT(DStarSlider(int)) ); connect( m_Controls->m_BThreshSlider, SIGNAL(valueChanged(int)), this, SLOT(BThreshSlider(int)) ); connect( m_Controls->m_S0ThreshSlider, SIGNAL(valueChanged(int)), this, SLOT(S0ThreshSlider(int)) ); connect( m_Controls->m_NumItSlider, SIGNAL(valueChanged(int)), this, SLOT(NumItsSlider(int)) ); connect( m_Controls->m_LambdaSlider, SIGNAL(valueChanged(int)), this, SLOT(LambdaSlider(int)) ); connect( m_Controls->m_CheckDStar, SIGNAL(clicked()), this, SLOT(Checkbox()) ); connect( m_Controls->m_CheckD, SIGNAL(clicked()), this, SLOT(Checkbox()) ); connect( m_Controls->m_Checkf, SIGNAL(clicked()), this, SLOT(Checkbox()) ); connect( m_Controls->m_CurveClipboard, SIGNAL(clicked()), this, SLOT(ClipboardCurveButtonClicked()) ); connect( m_Controls->m_ValuesClipboard, SIGNAL(clicked()), this, SLOT(ClipboardStatisticsButtonClicked()) ); connect( m_Controls->m_SavePlot, SIGNAL(clicked()), this, SLOT(SavePlotButtonClicked()) ); // connect all kurtosis actions to a recompute connect( m_Controls->m_KurtosisRangeWidget, SIGNAL( rangeChanged(double, double)), this, SLOT(OnKurtosisParamsChanged() ) ); connect( m_Controls->m_OmitBZeroCB, SIGNAL( stateChanged(int) ), this, SLOT( OnKurtosisParamsChanged() ) ); connect( m_Controls->m_KurtosisFitScale, SIGNAL( currentIndexChanged(int)), this, SLOT( OnKurtosisParamsChanged() ) ); connect( m_Controls->m_UseKurtosisBoundsCB, SIGNAL(clicked() ), this, SLOT( OnKurtosisParamsChanged() ) ); m_Controls->m_DwiBox->SetDataStorage(this->GetDataStorage()); mitk::NodePredicateIsDWI::Pointer isDwi = mitk::NodePredicateIsDWI::New(); m_Controls->m_DwiBox->SetPredicate( isDwi ); connect( (QObject*)(m_Controls->m_DwiBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); m_Controls->m_MaskBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MaskBox->SetZeroEntryText("--"); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateDimension::Pointer is3D = mitk::NodePredicateDimension::New(3); m_Controls->m_MaskBox->SetPredicate( mitk::NodePredicateAnd::New(isBinaryPredicate, mitk::NodePredicateAnd::New(isImagePredicate, is3D)) ); connect( (QObject*)(m_Controls->m_MaskBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); connect( (QObject*)(m_Controls->m_ModelTabSelectionWidget), SIGNAL(currentChanged(int)), this, SLOT(OnModelTabChanged(int))); } QString dstar = QString::number(m_Controls->m_DStarSlider->value()/1000.0); m_Controls->m_DStarLabel->setText(dstar); QString bthresh = QString::number(m_Controls->m_BThreshSlider->value()*5.0); m_Controls->m_BThreshLabel->setText(bthresh); QString s0thresh = QString::number(m_Controls->m_S0ThreshSlider->value()*0.5); m_Controls->m_S0ThreshLabel->setText(s0thresh); QString numits = QString::number(m_Controls->m_NumItSlider->value()); m_Controls->m_NumItsLabel->setText(numits); QString lambda = QString::number(m_Controls->m_LambdaSlider->value()*.00001); m_Controls->m_LambdaLabel->setText(lambda); m_Controls->m_Warning->setVisible(false); OnIvimFitChanged(m_Controls->m_MethodCombo->currentIndex()); m_Controls->m_KurtosisRangeWidget->setSingleStep(0.1); m_Controls->m_KurtosisRangeWidget->setRange( 0.0, 10.0 ); m_Controls->m_KurtosisRangeWidget->setMaximumValue( 5.0 ); // LogScale not working yet, have to fix that first // m_Controls->m_KurtosisFitScale->setEnabled(false); //m_Controls->m_MaximalBValueWidget->setVisible( false ); // release update block after the UI-elements were all set this->m_HoldUpdate = false; QmitkIVIMView::InitChartIvim(); m_ListenerActive = false; if (this->GetRenderWindowPart()) { m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); m_ListenerActive = true; } } void QmitkIVIMView::OnModelTabChanged(int tab) { if (tab==0) InitChartIvim(); else if (tab==1) InitChartKurtosis(); UpdateGui(); } void QmitkIVIMView::AddSecondFitPlot() { if (m_Controls->m_ChartWidget->GetDataElementByLabel("signal values (used for second fit)") == nullptr) { std::vector< std::pair > init_data; m_Controls->m_ChartWidget->AddData2D(init_data, "signal values (used for second fit)", QmitkChartWidget::ChartType::scatter); m_Controls->m_ChartWidget->SetColor("signal values (used for second fit)", "white"); m_Controls->m_ChartWidget->SetMarkerSymbol("signal values (used for second fit)", QmitkChartWidget::MarkerSymbol::x_thin); m_Controls->m_ChartWidget->Show(true); m_Controls->m_ChartWidget->SetShowDataPoints(false); m_Controls->m_ChartWidget->SetShowSubchart(false); } } void QmitkIVIMView::RemoveSecondFitPlot() { if (m_Controls->m_ChartWidget->GetDataElementByLabel("signal values (used for second fit)") != nullptr) { m_Controls->m_ChartWidget->RemoveData("signal values (used for second fit)"); m_Controls->m_ChartWidget->Show(true); m_Controls->m_ChartWidget->SetShowDataPoints(false); m_Controls->m_ChartWidget->SetShowSubchart(false); } } void QmitkIVIMView::InitChartIvim() { m_Controls->m_ChartWidget->Clear(); std::vector< std::pair > init_data; m_Controls->m_ChartWidget->AddData2D(init_data, "D-part of fitted model", QmitkChartWidget::ChartType::line); m_Controls->m_ChartWidget->AddData2D(init_data, "fitted model", QmitkChartWidget::ChartType::line); m_Controls->m_ChartWidget->AddData2D(init_data, "signal values", QmitkChartWidget::ChartType::scatter); m_Controls->m_ChartWidget->SetColor("fitted model", "red"); m_Controls->m_ChartWidget->SetColor("signal values", "white"); m_Controls->m_ChartWidget->SetColor("D-part of fitted model", "cyan"); m_Controls->m_ChartWidget->SetYAxisScale(QmitkChartWidget::AxisScale::log); m_Controls->m_ChartWidget->SetYAxisLabel("S/S0"); m_Controls->m_ChartWidget->SetXAxisLabel("b-value"); m_Controls->m_ChartWidget->SetLineStyle("fitted model", QmitkChartWidget::LineStyle::solid); m_Controls->m_ChartWidget->SetLineStyle("D-part of fitted model", QmitkChartWidget::LineStyle::dashed); m_Controls->m_ChartWidget->SetMarkerSymbol("signal values", QmitkChartWidget::MarkerSymbol::diamond); m_Controls->m_ChartWidget->Show(true); m_Controls->m_ChartWidget->SetShowDataPoints(false); m_Controls->m_ChartWidget->SetShowSubchart(false); } void QmitkIVIMView::InitChartKurtosis() { m_Controls->m_ChartWidget->Clear(); std::vector< std::pair > init_data; m_Controls->m_ChartWidget->AddData2D(init_data, "D-part of fitted model", QmitkChartWidget::ChartType::line); m_Controls->m_ChartWidget->AddData2D(init_data, "fitted model", QmitkChartWidget::ChartType::line); m_Controls->m_ChartWidget->AddData2D(init_data, "signal values", QmitkChartWidget::ChartType::scatter); m_Controls->m_ChartWidget->SetColor("fitted model", "red"); m_Controls->m_ChartWidget->SetColor("signal values", "white"); m_Controls->m_ChartWidget->SetColor("D-part of fitted model", "cyan"); m_Controls->m_ChartWidget->SetYAxisScale(QmitkChartWidget::AxisScale::log); m_Controls->m_ChartWidget->SetYAxisLabel("S"); m_Controls->m_ChartWidget->SetXAxisLabel("b-value"); m_Controls->m_ChartWidget->SetLineStyle("fitted model", QmitkChartWidget::LineStyle::solid); m_Controls->m_ChartWidget->SetLineStyle("D-part of fitted model", QmitkChartWidget::LineStyle::dashed); m_Controls->m_ChartWidget->SetMarkerSymbol("signal values", QmitkChartWidget::MarkerSymbol::diamond); m_Controls->m_ChartWidget->Show(true); m_Controls->m_ChartWidget->SetShowDataPoints(false); m_Controls->m_ChartWidget->SetShowSubchart(false); } void QmitkIVIMView::SetFocus() { m_Controls->m_ButtonAutoThres->setFocus(); } void QmitkIVIMView::Checkbox() { OnSliceChanged(); } void QmitkIVIMView::OnIvimFitChanged(int val) { switch(val) { case 0: m_Controls->m_DstarFrame->setVisible(false); m_Controls->m_NeglSiFrame->setVisible(true); m_Controls->m_NeglBframe->setVisible(false); m_Controls->m_IterationsFrame->setVisible(false); m_Controls->m_LambdaFrame->setVisible(false); break; case 1: m_Controls->m_DstarFrame->setVisible(true); m_Controls->m_NeglSiFrame->setVisible(true); m_Controls->m_NeglBframe->setVisible(false); m_Controls->m_IterationsFrame->setVisible(false); m_Controls->m_LambdaFrame->setVisible(false); break; case 2: m_Controls->m_DstarFrame->setVisible(false); m_Controls->m_NeglSiFrame->setVisible(true); m_Controls->m_NeglBframe->setVisible(true); m_Controls->m_IterationsFrame->setVisible(false); m_Controls->m_LambdaFrame->setVisible(false); break; case 3: m_Controls->m_DstarFrame->setVisible(false); m_Controls->m_NeglSiFrame->setVisible(true); m_Controls->m_NeglBframe->setVisible(true); m_Controls->m_IterationsFrame->setVisible(false); m_Controls->m_LambdaFrame->setVisible(false); break; case 4: m_Controls->m_DstarFrame->setVisible(false); m_Controls->m_NeglSiFrame->setVisible(false); m_Controls->m_NeglBframe->setVisible(false); m_Controls->m_IterationsFrame->setVisible(false); m_Controls->m_LambdaFrame->setVisible(false); break; } OnSliceChanged(); } void QmitkIVIMView::DStarSlider (int val) { QString sval = QString::number(val/1000.0); m_Controls->m_DStarLabel->setText(sval); OnSliceChanged(); } void QmitkIVIMView::BThreshSlider (int val) { QString sval = QString::number(val*5.0); m_Controls->m_BThreshLabel->setText(sval); OnSliceChanged(); } void QmitkIVIMView::S0ThreshSlider (int val) { QString sval = QString::number(val*0.5); m_Controls->m_S0ThreshLabel->setText(sval); OnSliceChanged(); } void QmitkIVIMView::NumItsSlider (int val) { QString sval = QString::number(val); m_Controls->m_NumItsLabel->setText(sval); OnSliceChanged(); } void QmitkIVIMView::LambdaSlider (int val) { QString sval = QString::number(val*.00001); m_Controls->m_LambdaLabel->setText(sval); OnSliceChanged(); } void QmitkIVIMView::UpdateGui() { m_Controls->m_FittedParamsLabel->setText(""); if (m_Controls->m_DwiBox->GetSelectedNode().IsNotNull()) { m_Controls->m_ChartWidget->setVisible(true); m_HoldUpdate = false; } else { m_Controls->m_ChartWidget->setVisible(false); } m_Controls->m_ButtonStart->setEnabled( m_Controls->m_DwiBox->GetSelectedNode().IsNotNull() ); m_Controls->m_ButtonAutoThres->setEnabled( m_Controls->m_DwiBox->GetSelectedNode().IsNotNull() ); m_Controls->m_ControlsFrame->setEnabled( m_Controls->m_DwiBox->GetSelectedNode().IsNotNull() ); m_Controls->m_BottomControlsFrame->setEnabled( m_Controls->m_DwiBox->GetSelectedNode().IsNotNull() ); OnSliceChanged(); } void QmitkIVIMView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& ) { // UpdateGui(); } void QmitkIVIMView::AutoThreshold() { if (m_Controls->m_DwiBox->GetSelectedNode().IsNull()) { // Nothing selected. Inform the user and return QMessageBox::information( nullptr, "Template", "Please load and select a diffusion image before starting image processing."); return; } mitk::Image* dimg = dynamic_cast(m_Controls->m_DwiBox->GetSelectedNode()->GetData()); if (!dimg) { // Nothing selected. Inform the user and return QMessageBox::information( nullptr, "Template", "No valid diffusion image was found."); return; } // find bzero index int index = -1; auto directions = mitk::DiffusionPropertyHelper::GetGradientContainer(dimg); for(DirContainerType::ConstIterator it = directions->Begin(); it != directions->End(); ++it) { index++; GradientDirectionType g = it.Value(); if(g[0] == 0 && g[1] == 0 && g[2] == 0 ) break; } VecImgType::Pointer vecimg = VecImgType::New(); mitk::CastToItkImage(dimg, vecimg); int vecLength = vecimg->GetVectorLength(); index = index > vecLength-1 ? vecLength-1 : index; MITK_INFO << "Performing Histogram Analysis on Channel" << index; typedef itk::Image ImgType; ImgType::Pointer img = ImgType::New(); mitk::CastToItkImage(dimg, img); itk::ImageRegionIterator itw (img, img->GetLargestPossibleRegion() ); itw.GoToBegin(); itk::ImageRegionConstIterator itr (vecimg, vecimg->GetLargestPossibleRegion() ); itr.GoToBegin(); while(!itr.IsAtEnd()) { itw.Set(itr.Get().GetElement(index)); ++itr; ++itw; } typedef itk::Statistics::ScalarImageToHistogramGenerator< ImgType > HistogramGeneratorType; typedef HistogramGeneratorType::HistogramType HistogramType; HistogramGeneratorType::Pointer histogramGenerator = HistogramGeneratorType::New(); histogramGenerator->SetInput( img ); histogramGenerator->SetMarginalScale( 10 ); // Defines y-margin width of histogram histogramGenerator->SetNumberOfBins( 100 ); // CT range [-1024, +2048] --> bin size 4 values histogramGenerator->SetHistogramMin( dimg->GetStatistics()->GetScalarValueMin() ); histogramGenerator->SetHistogramMax( dimg->GetStatistics()->GetScalarValueMax() * .5 ); histogramGenerator->Compute(); HistogramType::ConstIterator iter = histogramGenerator->GetOutput()->Begin(); float maxFreq = 0; float maxValue = 0; while ( iter != histogramGenerator->GetOutput()->End() ) { if(iter.GetFrequency() > maxFreq) { maxFreq = iter.GetFrequency(); maxValue = iter.GetMeasurementVector()[0]; } ++iter; } maxValue *= 2; int sliderPos = maxValue * 2; m_Controls->m_S0ThreshSlider->setValue(sliderPos); S0ThreshSlider(sliderPos); } void QmitkIVIMView::FittIVIMStart() { if (m_Controls->m_DwiBox->GetSelectedNode().IsNull()) { QMessageBox::information( nullptr, "Template", "No valid diffusion-weighted image selected."); return; } mitk::Image* img = dynamic_cast(m_Controls->m_DwiBox->GetSelectedNode()->GetData()); VecImgType::Pointer vecimg = VecImgType::New(); mitk::CastToItkImage(img, vecimg); OutImgType::IndexType dummy; if( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) { // KURTOSIS KurtosisFilterType::Pointer filter = KurtosisFilterType::New(); filter->SetInput(vecimg); filter->SetReferenceBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(img)); filter->SetGradientDirections(mitk::DiffusionPropertyHelper::GetGradientContainer(img)); filter->SetSmoothingSigma( m_Controls->m_SigmaSpinBox->value() ); if( m_Controls->m_UseKurtosisBoundsCB->isChecked() ) filter->SetBoundariesForKurtosis( m_Controls->m_KurtosisRangeWidget->minimumValue(), m_Controls->m_KurtosisRangeWidget->maximumValue() ); filter->SetFittingScale( static_cast(m_Controls->m_KurtosisFitScale->currentIndex() ) ); if( m_Controls->m_MaskBox->GetSelectedNode().IsNotNull() ) { mitk::Image::Pointer maskImg = dynamic_cast(m_Controls->m_MaskBox->GetSelectedNode()->GetData()); typedef itk::Image MaskImgType; MaskImgType::Pointer maskItk; CastToItkImage( maskImg, maskItk ); filter->SetImageMask( maskItk ); } filter->Update(); mitk::LookupTable::Pointer kurt_map_lut = mitk::LookupTable::New(); kurt_map_lut->SetType( mitk::LookupTable::JET ); mitk::LookupTableProperty::Pointer kurt_lut_prop = mitk::LookupTableProperty::New(); kurt_lut_prop->SetLookupTable( kurt_map_lut ); mitk::Image::Pointer dimage = mitk::Image::New(); dimage->InitializeByItk( filter->GetOutput(0) ); dimage->SetVolume( filter->GetOutput(0)->GetBufferPointer()); mitk::Image::Pointer kimage = mitk::Image::New(); kimage->InitializeByItk( filter->GetOutput(1) ); kimage->SetVolume( filter->GetOutput(1)->GetBufferPointer()); QString new_dname = "Kurtosis_DMap"; new_dname.append("_Method-"+m_Controls->m_KurtosisFitScale->currentText()); QString new_kname = "Kurtosis_KMap"; new_kname.append("_Method-"+m_Controls->m_KurtosisFitScale->currentText()); if( m_Controls->m_CheckKurtD->isChecked() ) { mitk::DataNode::Pointer dnode = mitk::DataNode::New(); dnode->SetData( dimage ); dnode->SetName(new_dname.toLatin1()); dnode->SetProperty("LookupTable", kurt_lut_prop ); GetDataStorage()->Add(dnode, m_Controls->m_DwiBox->GetSelectedNode()); } if( m_Controls->m_CheckKurtK->isChecked() ) { mitk::DataNode::Pointer knode = mitk::DataNode::New(); knode->SetData( kimage ); knode->SetName(new_kname.toLatin1()); knode->SetProperty("LookupTable", kurt_lut_prop ); GetDataStorage()->Add(knode, m_Controls->m_DwiBox->GetSelectedNode()); } } else { FittIVIM(vecimg, mitk::DiffusionPropertyHelper::GetGradientContainer(img), mitk::DiffusionPropertyHelper::GetReferenceBValue(img), true, dummy); OutputToDatastorage(m_Controls->m_DwiBox->GetSelectedNode()); } } void QmitkIVIMView::OnKurtosisParamsChanged() { OnSliceChanged(); } void QmitkIVIMView::OnSliceChanged() { if(m_HoldUpdate || !m_Visible) return; m_Controls->m_Warning->setVisible(false); if(m_Controls->m_DwiBox->GetSelectedNode().IsNull()) return; mitk::Image::Pointer diffusionImg = dynamic_cast(m_Controls->m_DwiBox->GetSelectedNode()->GetData()); mitk::Image::Pointer maskImg = nullptr; if (m_Controls->m_MaskBox->GetSelectedNode().IsNotNull()) maskImg = dynamic_cast(m_Controls->m_MaskBox->GetSelectedNode()->GetData()); if (!this->GetRenderWindowPart()) return; if (!m_ListenerActive) { m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); m_ListenerActive = true; } VecImgType::Pointer vecimg = VecImgType::New(); mitk::CastToItkImage(diffusionImg, vecimg); VecImgType::Pointer roiImage = VecImgType::New(); if(maskImg.IsNull()) { int roisize = 0; if(m_Controls->m_MethodCombo->currentIndex() == 4) roisize = 3; mitk::Point3D pos = this->GetRenderWindowPart()->GetSelectedPosition(); VecImgType::IndexType crosspos; diffusionImg->GetGeometry()->WorldToIndex(pos, crosspos); if (!vecimg->GetLargestPossibleRegion().IsInside(crosspos)) { m_Controls->m_Warning->setText(QString("Crosshair position not inside of selected diffusion weighted image. Reinit needed!")); m_Controls->m_Warning->setVisible(true); return; } else m_Controls->m_Warning->setVisible(false); VecImgType::IndexType index; index[0] = crosspos[0] - roisize; index[0] = index[0] < 0 ? 0 : index[0]; index[1] = crosspos[1] - roisize; index[1] = index[1] < 0 ? 0 : index[1]; index[2] = crosspos[2] - roisize; index[2] = index[2] < 0 ? 0 : index[2]; VecImgType::SizeType size; size[0] = roisize*2+1; size[1] = roisize*2+1; size[2] = roisize*2+1; VecImgType::SizeType maxSize = vecimg->GetLargestPossibleRegion().GetSize(); size[0] = index[0]+size[0] > maxSize[0] ? maxSize[0]-index[0] : size[0]; size[1] = index[1]+size[1] > maxSize[1] ? maxSize[1]-index[1] : size[1]; size[2] = index[2]+size[2] > maxSize[2] ? maxSize[2]-index[2] : size[2]; VecImgType::RegionType region; region.SetSize( size ); region.SetIndex( index ); vecimg->SetRequestedRegion( region ); VecImgType::IndexType newstart; newstart.Fill(0); VecImgType::RegionType newregion; newregion.SetSize( size ); newregion.SetIndex( newstart ); roiImage->CopyInformation( vecimg ); roiImage->SetRegions( newregion ); roiImage->SetOrigin( pos ); roiImage->Allocate(); // roiImage->SetPixel(newstart, vecimg->GetPixel(index)); typedef itk::ImageRegionIterator VectorIteratorType; VectorIteratorType vecit(vecimg, vecimg->GetRequestedRegion() ); vecit.GoToBegin(); typedef itk::ImageRegionIterator VectorIteratorType; VectorIteratorType vecit2(roiImage, roiImage->GetLargestPossibleRegion() ); vecit2.GoToBegin(); while( !vecit.IsAtEnd() ) { vecit2.Set(vecit.Get()); ++vecit; ++vecit2; } if( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) { FitKurtosis(roiImage, mitk::DiffusionPropertyHelper::GetGradientContainer(diffusionImg), mitk::DiffusionPropertyHelper::GetReferenceBValue(diffusionImg), newstart); } else { FittIVIM(roiImage, mitk::DiffusionPropertyHelper::GetGradientContainer(diffusionImg), mitk::DiffusionPropertyHelper::GetReferenceBValue(diffusionImg), false, crosspos); } } else { typedef itk::Image MaskImgType; MaskImgType::Pointer maskItk; CastToItkImage( maskImg, maskItk ); mitk::Point3D pos; pos[0] = 0; pos[1] = 0; pos[2] = 0; VecImgType::IndexType index; index[0] = 0; index[1] = 0; index[2] = 0; VecImgType::SizeType size; size[0] = 1; size[1] = 1; size[2] = 1; VecImgType::RegionType region; region.SetSize( size ); region.SetIndex( index ); vecimg->SetRequestedRegion( region ); // iterators over output and input itk::ImageRegionConstIteratorWithIndex vecit(vecimg, vecimg->GetLargestPossibleRegion()); itk::VariableLengthVector avg(vecimg->GetVectorLength()); avg.Fill(0); float numPixels = 0; while ( ! vecit.IsAtEnd() ) { VecImgType::PointType point; vecimg->TransformIndexToPhysicalPoint(vecit.GetIndex(), point); MaskImgType::IndexType index; maskItk->TransformPhysicalPointToIndex(point, index); if(maskItk->GetPixel(index) != 0) { avg += vecit.Get(); numPixels += 1.0; } // update iterators ++vecit; } avg /= numPixels; m_Controls->m_Warning->setText(QString("Averaging ")+QString::number((int)numPixels)+QString(" voxels!")); m_Controls->m_Warning->setVisible(true); roiImage->CopyInformation( vecimg ); roiImage->SetRegions( region ); roiImage->SetOrigin( pos ); roiImage->Allocate(); roiImage->SetPixel(index, avg); if( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) { FitKurtosis(roiImage, mitk::DiffusionPropertyHelper::GetGradientContainer(diffusionImg), mitk::DiffusionPropertyHelper::GetReferenceBValue(diffusionImg), index); } else { FittIVIM(roiImage, mitk::DiffusionPropertyHelper::GetGradientContainer(diffusionImg), mitk::DiffusionPropertyHelper::GetReferenceBValue(diffusionImg), false, index); } // do not update until selection changed, the values will remain the same as long as the mask is selected! m_HoldUpdate = true; } vecimg->SetRegions( vecimg->GetLargestPossibleRegion() ); } -bool QmitkIVIMView::FitKurtosis( itk::VectorImage *vecimg, DirContainerType *dirs, float bval, OutImgType::IndexType &crosspos ) +bool QmitkIVIMView::FitKurtosis( itk::VectorImage *vecimg, DirContainerType::ConstPointer dirs, float bval, OutImgType::IndexType &crosspos ) { KurtosisFilterType::Pointer filter = KurtosisFilterType::New(); itk::KurtosisFitConfiguration fit_config; fit_config.omit_bzero = m_Controls->m_OmitBZeroCB->isChecked(); if( m_Controls->m_UseKurtosisBoundsCB->isChecked() ) { fit_config.use_K_limits = true; vnl_vector_fixed k_limits; k_limits[0] = m_Controls->m_KurtosisRangeWidget->minimumValue(); k_limits[1] = m_Controls->m_KurtosisRangeWidget->maximumValue(); fit_config.K_limits = k_limits; } fit_config.fit_scale = static_cast(m_Controls->m_KurtosisFitScale->currentIndex() ); m_KurtosisSnap = filter->GetSnapshot( vecimg->GetPixel( crosspos ), dirs, bval, fit_config ); QString param_label_text("K=%2, D=%1"); param_label_text = param_label_text.arg( m_KurtosisSnap.m_K, 4); param_label_text = param_label_text.arg( m_KurtosisSnap.m_D, 4); m_Controls->m_FittedParamsLabel->setText(param_label_text); const double maxb = m_KurtosisSnap.bvalues.max_value(); double S0 = m_KurtosisSnap.m_Bzero; if (m_KurtosisSnap.m_fittedBZero) S0 = m_KurtosisSnap.m_BzeroFit; std::vector< std::pair > d_line; d_line.emplace_back(0, S0); d_line.emplace_back(maxb, S0*exp(-maxb * m_KurtosisSnap.m_D)); m_Controls->m_ChartWidget->UpdateData2D(d_line, "D-part of fitted model"); const unsigned int num_samples = 50; std::vector< std::pair > y; for( unsigned int i=0; i<=num_samples; ++i) { double b = (((1.0)*i)/(1.0*num_samples))*maxb; y.emplace_back(b, S0 * exp( -b * m_KurtosisSnap.m_D + b*b * m_KurtosisSnap.m_D * m_KurtosisSnap.m_D * m_KurtosisSnap.m_K / 6.0 )); } m_Controls->m_ChartWidget->UpdateData2D(y, "fitted model"); std::vector< std::pair > y_meas; for (unsigned int i=0; im_OmitBZeroCB->isChecked() || m_KurtosisSnap.bvalues[i] > 0.01) y_meas.emplace_back(m_KurtosisSnap.bvalues[i], m_KurtosisSnap.measurements[i]); } m_Controls->m_ChartWidget->UpdateData2D(y_meas, "signal values"); return true; } -bool QmitkIVIMView::FittIVIM(itk::VectorImage* vecimg, DirContainerType* dirs, float bval, bool multivoxel, OutImgType::IndexType &crosspos) +bool QmitkIVIMView::FittIVIM(itk::VectorImage* vecimg, DirContainerType::ConstPointer dirs, float bval, bool multivoxel, OutImgType::IndexType &crosspos) { IVIMFilterType::Pointer filter = IVIMFilterType::New(); filter->SetInput(vecimg); filter->SetGradientDirections(dirs); filter->SetBValue(bval); switch(m_Controls->m_MethodCombo->currentIndex()) { case 0: filter->SetMethod(IVIMFilterType::IVIM_FIT_ALL); filter->SetS0Thres(m_Controls->m_S0ThreshLabel->text().toDouble()); break; case 1: filter->SetMethod(IVIMFilterType::IVIM_DSTAR_FIX); filter->SetDStar(m_Controls->m_DStarLabel->text().toDouble()); filter->SetS0Thres(m_Controls->m_S0ThreshLabel->text().toDouble()); break; case 2: filter->SetMethod(IVIMFilterType::IVIM_D_THEN_DSTAR); filter->SetBThres(m_Controls->m_BThreshLabel->text().toDouble()); filter->SetS0Thres(m_Controls->m_S0ThreshLabel->text().toDouble()); filter->SetFitDStar(m_Controls->m_CheckDStar->isChecked()); break; case 3: filter->SetMethod(IVIMFilterType::IVIM_LINEAR_D_THEN_F); filter->SetBThres(m_Controls->m_BThreshLabel->text().toDouble()); filter->SetS0Thres(m_Controls->m_S0ThreshLabel->text().toDouble()); filter->SetFitDStar(m_Controls->m_CheckDStar->isChecked()); break; case 4: filter->SetMethod(IVIMFilterType::IVIM_REGULARIZED); filter->SetBThres(m_Controls->m_BThreshLabel->text().toDouble()); filter->SetS0Thres(m_Controls->m_S0ThreshLabel->text().toDouble()); filter->SetNumberIterations(m_Controls->m_NumItsLabel->text().toInt()); filter->SetLambda(m_Controls->m_LambdaLabel->text().toDouble()); filter->SetFitDStar(m_Controls->m_CheckDStar->isChecked()); break; } if(!multivoxel) { filter->SetFitDStar(true); } filter->SetNumberOfThreads(1); filter->SetVerbose(false); filter->SetCrossPosition(crosspos); try{ filter->Update(); m_IvimSnap = filter->GetSnapshot(); m_DStarMap = filter->GetOutput(2); m_DMap = filter->GetOutput(1); m_fMap = filter->GetOutput(); QString param_label_text("f=%1, D=%2, D*=%3"); param_label_text = param_label_text.arg(m_IvimSnap.currentF,4); param_label_text = param_label_text.arg(m_IvimSnap.currentD,4); param_label_text = param_label_text.arg(m_IvimSnap.currentDStar,4); m_Controls->m_FittedParamsLabel->setText(param_label_text); double maxb = m_IvimSnap.bvalues.max_value(); std::vector< std::pair > d_line; d_line.emplace_back(0, 1-m_IvimSnap.currentFunceiled); d_line.emplace_back(maxb, d_line[0].second*exp(-maxb * m_IvimSnap.currentD)); m_Controls->m_ChartWidget->UpdateData2D(d_line, "D-part of fitted model"); std::vector< std::pair > y; int nsampling = 50; double f = 1-m_IvimSnap.currentFunceiled; for(int i=0; i<=nsampling; i++) { double x = (((1.0)*i)/(1.0*nsampling))*maxb; y.emplace_back(x, f*exp(- x * m_IvimSnap.currentD) + (1-f)*exp(- x * (m_IvimSnap.currentD+m_IvimSnap.currentDStar))); } m_Controls->m_ChartWidget->UpdateData2D(y, "fitted model"); std::vector< std::pair > y_meas; for (unsigned int i=0; im_ChartWidget->UpdateData2D(y_meas, "signal values"); if(m_IvimSnap.bvals2.size() > 0) { AddSecondFitPlot(); std::vector< std::pair > additonal_meas; for (int i=0; i(m_IvimSnap.bvals2.size()); ++i) additonal_meas.emplace_back(m_IvimSnap.bvals2[i], m_IvimSnap.meas2[i]); m_Controls->m_ChartWidget->UpdateData2D(additonal_meas, "signal values (used for second fit)"); } else { RemoveSecondFitPlot(); } } catch (itk::ExceptionObject &ex) { MITK_INFO << ex ; m_Controls->m_Warning->setText(QString("IVIM fit not possible: ")+ex.GetDescription()); m_Controls->m_Warning->setVisible(true); return false; } return true; } void QmitkIVIMView::OutputToDatastorage(mitk::DataNode::Pointer node) { mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType( mitk::LookupTable::JET ); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable( lut ); if(m_Controls->m_CheckDStar->isChecked()) { mitk::Image::Pointer dstarimage = mitk::Image::New(); dstarimage->InitializeByItk(m_DStarMap.GetPointer()); dstarimage->SetVolume(m_DStarMap->GetBufferPointer()); QString newname2 = ""; newname2 = newname2.append("D* Fit-%1").arg(m_Controls->m_MethodCombo->currentIndex()+1); mitk::DataNode::Pointer node2=mitk::DataNode::New(); node2->SetData( dstarimage ); node2->SetName(newname2.toLatin1()); node2->SetProperty("LookupTable", lut_prop ); mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetRangeMinMax(0, 0.2); levWinProp->SetLevelWindow(levelwindow); node2->SetProperty("levelwindow", levWinProp); GetDataStorage()->Add(node2, node); } if(m_Controls->m_CheckD->isChecked()) { mitk::Image::Pointer dimage = mitk::Image::New(); dimage->InitializeByItk(m_DMap.GetPointer()); dimage->SetVolume(m_DMap->GetBufferPointer()); QString newname1 = ""; newname1 = newname1.append("D Fit-%1").arg(m_Controls->m_MethodCombo->currentIndex()+1); mitk::DataNode::Pointer node1=mitk::DataNode::New(); node1->SetData( dimage ); node1->SetName(newname1.toLatin1()); node1->SetProperty("LookupTable", lut_prop ); mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetRangeMinMax(0, 0.003); levWinProp->SetLevelWindow(levelwindow); node1->SetProperty("levelwindow", levWinProp); GetDataStorage()->Add(node1, node); } if(m_Controls->m_Checkf->isChecked()) { mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(m_fMap.GetPointer()); image->SetVolume(m_fMap->GetBufferPointer()); QString newname0 = ""; newname0 = newname0.append("f Fit-%1").arg(m_Controls->m_MethodCombo->currentIndex()+1); mitk::DataNode::Pointer node3=mitk::DataNode::New(); node3->SetData( image ); node3->SetName(newname0.toLatin1()); node3->SetProperty("LookupTable", lut_prop ); mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetRangeMinMax(0, 1); levWinProp->SetLevelWindow(levelwindow); node3->SetProperty("levelwindow", levWinProp); GetDataStorage()->Add(node3, node); } this->GetRenderWindowPart()->RequestUpdate(); } void QmitkIVIMView::ClipboardCurveButtonClicked() { // Kurtosis if ( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) { std::stringstream ss; QString clipboard("Measurement Points\n"); ss << m_KurtosisSnap.bvalues << "\n" << m_KurtosisSnap.measurements << "\n\n"; ss << "Fitted Values ( D K [b_0] ) \n" << m_KurtosisSnap.m_D << " " << m_KurtosisSnap.m_K; if( m_KurtosisSnap.m_fittedBZero ) ss << " " << m_KurtosisSnap.m_BzeroFit; ss << "\n\n"; clipboard.append( QString( ss.str().c_str() )); ss.str( std::string() ); ss.clear(); QApplication::clipboard()->setText(clipboard, QClipboard::Clipboard ); } else { std::stringstream ss; QString clipboard("Normalized Measurement Points\n"); ss << m_IvimSnap.bvalues << "\n" << m_IvimSnap.allmeas << "\n\n"; ss << "Fitted Values ( f D D* ) \n" << m_IvimSnap.currentF << " " << m_IvimSnap.currentD << " " << m_IvimSnap.currentDStar; ss << "\n\n"; clipboard.append( QString( ss.str().c_str() )); ss.str( std::string() ); ss.clear(); QApplication::clipboard()->setText(clipboard, QClipboard::Clipboard ); } } void QmitkIVIMView::SavePlotButtonClicked() { m_Controls->m_ChartWidget->SavePlotAsImage(); } void QmitkIVIMView::ClipboardStatisticsButtonClicked() { // Kurtosis if ( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) { QString clipboard( "D \t K \n" ); clipboard = clipboard.append( "%L1 \t %L2" ) .arg( m_KurtosisSnap.m_D, 0, 'f', 10 ) .arg( m_KurtosisSnap.m_K, 0, 'f', 10 ) ; QApplication::clipboard()->setText(clipboard, QClipboard::Clipboard ); } else { QString clipboard( "f \t D \t D* \n" ); clipboard = clipboard.append( "%L1 \t %L2 \t %L3" ) .arg( m_IvimSnap.currentF, 0, 'f', 10 ) .arg( m_IvimSnap.currentD, 0, 'f', 10 ) .arg( m_IvimSnap.currentDStar, 0, 'f', 10 ) ; QApplication::clipboard()->setText(clipboard, QClipboard::Clipboard ); } } void QmitkIVIMView::Activated() { m_Active = true; } void QmitkIVIMView::Deactivated() { m_Active = false; } void QmitkIVIMView::Visible() { m_Visible = true; if (this->GetRenderWindowPart() && !m_ListenerActive) { m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); m_ListenerActive = true; } } void QmitkIVIMView::Hidden() { m_Visible = false; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.h index 63e87de..1123647 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.h @@ -1,136 +1,136 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef _QMITKIVIMVIEW_H_INCLUDED #define _QMITKIVIMVIEW_H_INCLUDED #include #include #include #include #include "ui_QmitkIVIMViewControls.h" #include "itkVectorImage.h" #include "itkImage.h" #include #include "itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h" #include "itkDiffusionKurtosisReconstructionImageFilter.h" #include #include /*! \brief QmitkIVIMView \warning This application module is not yet documented. Use "svn blame/praise/annotate" and ask the author to provide basic documentation. */ class QmitkIVIMView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; QmitkIVIMView(); virtual ~QmitkIVIMView(); typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType DirContainerType; typedef itk::DiffusionIntravoxelIncoherentMotionReconstructionImageFilter IVIMFilterType; typedef itk::DiffusionKurtosisReconstructionImageFilter KurtosisFilterType; typedef itk::VectorImage VecImgType; typedef itk::Image OutImgType; virtual void CreateQtPartControl(QWidget *parent) override; /// /// Sets the focus to an internal widget. /// virtual void SetFocus() override; void OutputToDatastorage(mitk::DataNode::Pointer node); - bool FittIVIM(itk::VectorImage* vecimg, DirContainerType* dirs, float bval, bool multivoxel, OutImgType::IndexType &crosspos); + bool FittIVIM(itk::VectorImage* vecimg, DirContainerType::ConstPointer dirs, float bval, bool multivoxel, OutImgType::IndexType &crosspos); void Activated() override; void Deactivated() override; void Visible() override; void Hidden() override; protected slots: void OnSliceChanged(); /// \brief Called when the user clicks the GUI button void FittIVIMStart(); void AutoThreshold(); void OnModelTabChanged(int tab); void OnIvimFitChanged(int val); void Checkbox(); void DStarSlider(int val); void BThreshSlider(int val); void S0ThreshSlider(int val); void NumItsSlider(int val); void LambdaSlider(int val); void ClipboardStatisticsButtonClicked(); void ClipboardCurveButtonClicked(); void SavePlotButtonClicked(); void OnKurtosisParamsChanged(); void UpdateGui(); protected: void InitChartIvim(); void InitChartKurtosis(); void AddSecondFitPlot(); void RemoveSecondFitPlot(); /// \brief called by QmitkAbstractView when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; - bool FitKurtosis( itk::VectorImage *vecimg, DirContainerType *dirs, float bval, OutImgType::IndexType &crosspos); + bool FitKurtosis( itk::VectorImage *vecimg, DirContainerType::ConstPointer dirs, float bval, OutImgType::IndexType &crosspos); Ui::QmitkIVIMViewControls* m_Controls; OutImgType::Pointer m_DStarMap; OutImgType::Pointer m_DMap; OutImgType::Pointer m_fMap; IVIMFilterType::IVIMSnapshot m_IvimSnap; KurtosisFilterType::KurtosisSnapshot m_KurtosisSnap; bool m_Active; bool m_Visible; bool m_ListenerActive; bool m_HoldUpdate; QmitkSliceNavigationListener m_SliceChangeListener; }; #endif // _QMITKIVIMVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingView.cpp index b865c30..9f3b391 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingView.cpp @@ -1,1951 +1,2024 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ //#define MBILOG_ENABLE_DEBUG #include "QmitkPreprocessingView.h" #include "mitkDiffusionImagingConfigure.h" // qt includes #include // itk includes #include "itkTimeProbe.h" #include "itkB0ImageExtractionImageFilter.h" #include "itkB0ImageExtractionToSeparateImageFilter.h" #include "itkBrainMaskExtractionImageFilter.h" #include "itkCastImageFilter.h" #include "itkVectorContainer.h" #include #include #include #include #include #include // Multishell includes #include // Multishell Functors #include #include #include #include // mitk includes #include "QmitkDataStorageComboBox.h" #include "mitkProgressBar.h" #include "mitkStatusBar.h" #include "mitkNodePredicateDataType.h" #include "mitkProperties.h" #include "mitkVtkResliceInterpolationProperty.h" #include "mitkLookupTable.h" #include "mitkLookupTableProperty.h" #include "mitkTransferFunction.h" #include "mitkTransferFunctionProperty.h" #include "mitkDataNodeObject.h" #include "mitkOdfNormalizationMethodProperty.h" #include "mitkOdfScaleByProperty.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include + const std::string QmitkPreprocessingView::VIEW_ID = "org.mitk.views.diffusionpreprocessing"; #define DI_INFO MITK_INFO("DiffusionImaging") typedef float TTensorPixelType; QmitkPreprocessingView::QmitkPreprocessingView() : QmitkAbstractView(), m_Controls(nullptr) { } QmitkPreprocessingView::~QmitkPreprocessingView() { } void QmitkPreprocessingView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkPreprocessingViewControls; m_Controls->setupUi(parent); this->CreateConnections(); m_Controls->m_MeasurementFrameTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); m_Controls->m_MeasurementFrameTable->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); m_Controls->m_DirectionMatrixTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); m_Controls->m_DirectionMatrixTable->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); } } void QmitkPreprocessingView::SetFocus() { m_Controls->m_MirrorGradientToHalfSphereButton->setFocus(); } void QmitkPreprocessingView::CreateConnections() { if ( m_Controls ) { m_Controls->m_NormalizationMaskBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_SelctedImageComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MergeDwiBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_AlignImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isMitkImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isOdf = mitk::NodePredicateDataType::New("OdfImage"); mitk::NodePredicateOr::Pointer isDiffusionImage = mitk::NodePredicateOr::New(isOdf, isDti); mitk::NodePredicateAnd::Pointer noDiffusionImage = mitk::NodePredicateAnd::New(isMitkImage, mitk::NodePredicateNot::New(isDiffusionImage)); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer binaryNoDiffusionImage = mitk::NodePredicateAnd::New(noDiffusionImage, isBinaryPredicate); m_Controls->m_NormalizationMaskBox->SetPredicate(binaryNoDiffusionImage); m_Controls->m_SelctedImageComboBox->SetPredicate(isMitkImage); m_Controls->m_MergeDwiBox->SetPredicate(isMitkImage); m_Controls->m_AlignImageBox->SetPredicate(isMitkImage); m_Controls->m_ExtractBrainMask->setVisible(false); m_Controls->m_BrainMaskIterationsBox->setVisible(false); m_Controls->m_ResampleIntFrame->setVisible(false); connect( (QObject*)(m_Controls->m_ButtonAverageGradients), SIGNAL(clicked()), this, SLOT(AverageGradients()) ); connect( (QObject*)(m_Controls->m_ButtonExtractB0), SIGNAL(clicked()), this, SLOT(ExtractB0()) ); connect( (QObject*)(m_Controls->m_ReduceGradientsButton), SIGNAL(clicked()), this, SLOT(DoReduceGradientDirections()) ); connect( (QObject*)(m_Controls->m_ShowGradientsButton), SIGNAL(clicked()), this, SLOT(DoShowGradientDirections()) ); connect( (QObject*)(m_Controls->m_MirrorGradientToHalfSphereButton), SIGNAL(clicked()), this, SLOT(DoHalfSphereGradientDirections()) ); + connect( (QObject*)(m_Controls->m_SwapGradientsButton), SIGNAL(clicked()), this, SLOT(DoSwapGradientDimensions()) ); connect( (QObject*)(m_Controls->m_MergeDwisButton), SIGNAL(clicked()), this, SLOT(MergeDwis()) ); connect( (QObject*)(m_Controls->m_ProjectSignalButton), SIGNAL(clicked()), this, SLOT(DoProjectSignal()) ); connect( (QObject*)(m_Controls->m_B_ValueMap_Rounder_SpinBox), SIGNAL(valueChanged(int)), this, SLOT(UpdateDwiBValueMapRounder(int))); connect( (QObject*)(m_Controls->m_CreateLengthCorrectedDwi), SIGNAL(clicked()), this, SLOT(DoLengthCorrection()) ); connect( (QObject*)(m_Controls->m_NormalizeImageValuesButton), SIGNAL(clicked()), this, SLOT(DoDwiNormalization()) ); connect( (QObject*)(m_Controls->m_ResampleImageButton), SIGNAL(clicked()), this, SLOT(DoResampleImage()) ); connect( (QObject*)(m_Controls->m_ResampleTypeBox), SIGNAL(currentIndexChanged(int)), this, SLOT(DoUpdateInterpolationGui(int)) ); connect( (QObject*)(m_Controls->m_CropImageButton), SIGNAL(clicked()), this, SLOT(DoCropImage()) ); connect( (QObject*)(m_Controls->m_RemoveGradientButton), SIGNAL(clicked()), this, SLOT(DoRemoveGradient()) ); connect( (QObject*)(m_Controls->m_ExtractGradientButton), SIGNAL(clicked()), this, SLOT(DoExtractGradient()) ); connect( (QObject*)(m_Controls->m_FlipAxis), SIGNAL(clicked()), this, SLOT(DoFlipAxis()) ); connect( (QObject*)(m_Controls->m_FlipGradientsButton), SIGNAL(clicked()), this, SLOT(DoFlipGradientDirections()) ); connect( (QObject*)(m_Controls->m_ClearRotationButton), SIGNAL(clicked()), this, SLOT(DoClearRotationOfGradients()) ); connect( (QObject*)(m_Controls->m_ModifyHeader), SIGNAL(clicked()), this, SLOT(DoApplyHeader()) ); connect( (QObject*)(m_Controls->m_AlignImageButton), SIGNAL(clicked()), this, SLOT(DoAlignImages()) ); connect( (QObject*)(m_Controls->m_SelctedImageComboBox), SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnImageSelectionChanged()) ); m_Controls->m_NormalizationMaskBox->SetZeroEntryText("--"); QFont f("monospace"); f.setStyleHint(QFont::Monospace); m_Controls->m_OriginalGradientsText->setFont(f); m_Controls->m_WorkingGradientsText->setFont(f); } } void QmitkPreprocessingView::DoAlignImages() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } mitk::DataNode::Pointer target_node = m_Controls->m_AlignImageBox->GetSelectedNode(); if (target_node.IsNull()) { return; } mitk::Image::Pointer target_image = dynamic_cast(target_node->GetData()); if ( target_image == nullptr ) { return; } image->SetOrigin(target_image->GetGeometry()->GetOrigin()); mitk::RenderingManager::GetInstance()->InitializeViews( image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoFlipAxis() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(node) ); if (isDiffusionImage) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); itk::FixedArray flipAxes; flipAxes[0] = m_Controls->m_FlipX->isChecked(); flipAxes[1] = m_Controls->m_FlipY->isChecked(); flipAxes[2] = m_Controls->m_FlipZ->isChecked(); itk::FlipImageFilter< ItkDwiType >::Pointer flipper = itk::FlipImageFilter< ItkDwiType >::New(); flipper->SetInput(itkVectorImagePointer); flipper->SetFlipAxes(flipAxes); flipper->Update(); auto oldGradients = PropHelper::GetGradientContainer(image); auto newGradients = GradProp::GradientDirectionsContainerType::New(); for (unsigned int i=0; iSize(); i++) { GradProp::GradientDirectionType g = oldGradients->GetElement(i); GradProp::GradientDirectionType newG = g; if (flipAxes[0]) { newG[0] *= -1; } if (flipAxes[1]) { newG[1] *= -1; } if (flipAxes[2]) { newG[2] *= -1; } newGradients->InsertElement(i, newG); } mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( flipper->GetOutput() ); PropHelper::CopyProperties(image, newImage, true); PropHelper::SetGradientContainer(newImage, newGradients); PropHelper::InitializeImage(newImage); newImage->GetGeometry()->SetOrigin(image->GetGeometry()->GetOrigin()); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_flipped").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if( image->GetPixelType().GetNumberOfComponents() == 1 ) { AccessFixedDimensionByItk(image, TemplatedFlipAxis,3); } else { QMessageBox::warning(nullptr,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedFlipAxis(itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } itk::FixedArray flipAxes; flipAxes[0] = m_Controls->m_FlipX->isChecked(); flipAxes[1] = m_Controls->m_FlipY->isChecked(); flipAxes[2] = m_Controls->m_FlipZ->isChecked(); typename itk::FlipImageFilter< itk::Image >::Pointer flipper = itk::FlipImageFilter< itk::Image >::New(); flipper->SetInput(itkImage); flipper->SetFlipAxes(flipAxes); flipper->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( flipper->GetOutput() ); newImage->GetGeometry()->SetOrigin(image->GetGeometry()->GetOrigin()); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_flipped").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoRemoveGradient() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } std::vector< unsigned int > channelsToRemove; channelsToRemove.push_back(m_Controls->m_RemoveGradientBox->value()); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); itk::RemoveDwiChannelFilter< short >::Pointer filter = itk::RemoveDwiChannelFilter< short >::New(); filter->SetInput(itkVectorImagePointer); filter->SetChannelIndices(channelsToRemove); filter->SetDirections(PropHelper::GetGradientContainer(image)); filter->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( filter->GetOutput() ); PropHelper::CopyProperties(image, newImage, true); PropHelper::SetGradientContainer(newImage, filter->GetNewDirections()); PropHelper::InitializeImage( newImage ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_removedgradients").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoExtractGradient() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); unsigned int channel = m_Controls->m_ExtractGradientBox->value(); itk::ExtractDwiChannelFilter< short >::Pointer filter = itk::ExtractDwiChannelFilter< short >::New(); filter->SetInput( itkVectorImagePointer); filter->SetChannelIndex(channel); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( filter->GetOutput() ); newImage->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName( (name+"_direction-"+QString::number(channel)).toStdString().c_str() ); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } void QmitkPreprocessingView::DoCropImage() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( isDiffusionImage ) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); ItkDwiType::SizeType lower; ItkDwiType::SizeType upper; lower[0] = m_Controls->m_XstartBox->value(); lower[1] = m_Controls->m_YstartBox->value(); lower[2] = m_Controls->m_ZstartBox->value(); upper[0] = m_Controls->m_XendBox->value(); upper[1] = m_Controls->m_YendBox->value(); upper[2] = m_Controls->m_ZendBox->value(); itk::CropImageFilter< ItkDwiType, ItkDwiType >::Pointer cropper = itk::CropImageFilter< ItkDwiType, ItkDwiType >::New(); cropper->SetLowerBoundaryCropSize(lower); cropper->SetUpperBoundaryCropSize(upper); cropper->SetInput( itkVectorImagePointer ); cropper->Update(); ItkDwiType::Pointer itkOutImage = cropper->GetOutput(); ItkDwiType::DirectionType dir = itkOutImage->GetDirection(); itk::Point origin = itkOutImage->GetOrigin(); itk::Point t; t[0] = lower[0]*itkOutImage->GetSpacing()[0]; t[1] = lower[1]*itkOutImage->GetSpacing()[1]; t[2] = lower[2]*itkOutImage->GetSpacing()[2]; t= dir*t; origin[0] += t[0]; origin[1] += t[1]; origin[2] += t[2]; itkOutImage->SetOrigin(origin); mitk::Image::Pointer newimage = mitk::GrabItkImageMemory( itkOutImage ); PropHelper::CopyProperties(image, newimage, false); PropHelper::InitializeImage( newimage ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newimage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_cropped").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if( image->GetPixelType().GetNumberOfComponents() ) { AccessFixedDimensionByItk(image, TemplatedCropImage,3); } else { QMessageBox::warning(nullptr,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedCropImage( itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } ItkDwiType::SizeType lower; ItkDwiType::SizeType upper; lower[0] = m_Controls->m_XstartBox->value(); lower[1] = m_Controls->m_YstartBox->value(); lower[2] = m_Controls->m_ZstartBox->value(); upper[0] = m_Controls->m_XendBox->value(); upper[1] = m_Controls->m_YendBox->value(); upper[2] = m_Controls->m_ZendBox->value(); typedef itk::Image ImageType; typename itk::CropImageFilter< ImageType, ImageType >::Pointer cropper = itk::CropImageFilter< ImageType, ImageType >::New(); cropper->SetLowerBoundaryCropSize(lower); cropper->SetUpperBoundaryCropSize(upper); cropper->SetInput(itkImage); cropper->Update(); typename ImageType::Pointer itkOutImage = cropper->GetOutput(); typename ImageType::DirectionType dir = itkOutImage->GetDirection(); itk::Point origin = itkOutImage->GetOrigin(); itk::Point t; t[0] = lower[0]*itkOutImage->GetSpacing()[0]; t[1] = lower[1]*itkOutImage->GetSpacing()[1]; t[2] = lower[2]*itkOutImage->GetSpacing()[2]; t= dir*t; origin[0] += t[0]; origin[1] += t[1]; origin[2] += t[2]; itkOutImage->SetOrigin(origin); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( itkOutImage.GetPointer() ); image->SetVolume( itkOutImage->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( image ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_cropped").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoUpdateInterpolationGui(int i) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } switch (i) { - case 0: - { - m_Controls->m_ResampleIntFrame->setVisible(false); - m_Controls->m_ResampleDoubleFrame->setVisible(true); - break; - } - case 1: - { - m_Controls->m_ResampleIntFrame->setVisible(false); - m_Controls->m_ResampleDoubleFrame->setVisible(true); + case 0: + { + m_Controls->m_ResampleIntFrame->setVisible(false); + m_Controls->m_ResampleDoubleFrame->setVisible(true); + break; + } + case 1: + { + m_Controls->m_ResampleIntFrame->setVisible(false); + m_Controls->m_ResampleDoubleFrame->setVisible(true); - mitk::BaseGeometry* geom = image->GetGeometry(); - m_Controls->m_ResampleDoubleX->setValue(geom->GetSpacing()[0]); - m_Controls->m_ResampleDoubleY->setValue(geom->GetSpacing()[1]); - m_Controls->m_ResampleDoubleZ->setValue(geom->GetSpacing()[2]); - break; - } - case 2: - { - m_Controls->m_ResampleIntFrame->setVisible(true); - m_Controls->m_ResampleDoubleFrame->setVisible(false); + mitk::BaseGeometry* geom = image->GetGeometry(); + m_Controls->m_ResampleDoubleX->setValue(geom->GetSpacing()[0]); + m_Controls->m_ResampleDoubleY->setValue(geom->GetSpacing()[1]); + m_Controls->m_ResampleDoubleZ->setValue(geom->GetSpacing()[2]); + break; + } + case 2: + { + m_Controls->m_ResampleIntFrame->setVisible(true); + m_Controls->m_ResampleDoubleFrame->setVisible(false); - mitk::BaseGeometry* geom = image->GetGeometry(); - m_Controls->m_ResampleIntX->setValue(geom->GetExtent(0)); - m_Controls->m_ResampleIntY->setValue(geom->GetExtent(1)); - m_Controls->m_ResampleIntZ->setValue(geom->GetExtent(2)); - break; - } - default: - { - m_Controls->m_ResampleIntFrame->setVisible(false); - m_Controls->m_ResampleDoubleFrame->setVisible(true); - } + mitk::BaseGeometry* geom = image->GetGeometry(); + m_Controls->m_ResampleIntX->setValue(geom->GetExtent(0)); + m_Controls->m_ResampleIntY->setValue(geom->GetExtent(1)); + m_Controls->m_ResampleIntZ->setValue(geom->GetExtent(2)); + break; + } + default: + { + m_Controls->m_ResampleIntFrame->setVisible(false); + m_Controls->m_ResampleDoubleFrame->setVisible(true); + } } } void QmitkPreprocessingView::DoExtractBrainMask() { } void QmitkPreprocessingView::DoResampleImage() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( isDiffusionImage ) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); typedef itk::ResampleDwiImageFilter< short > ResampleFilter; ResampleFilter::Pointer resampler = ResampleFilter::New(); resampler->SetInput( itkVectorImagePointer ); switch (m_Controls->m_ResampleTypeBox->currentIndex()) { - case 0: - { - itk::Vector< double, 3 > samplingFactor; - samplingFactor[0] = m_Controls->m_ResampleDoubleX->value(); - samplingFactor[1] = m_Controls->m_ResampleDoubleY->value(); - samplingFactor[2] = m_Controls->m_ResampleDoubleZ->value(); - resampler->SetSamplingFactor(samplingFactor); - break; - } - case 1: - { - itk::Vector< double, 3 > newSpacing; - newSpacing[0] = m_Controls->m_ResampleDoubleX->value(); - newSpacing[1] = m_Controls->m_ResampleDoubleY->value(); - newSpacing[2] = m_Controls->m_ResampleDoubleZ->value(); - resampler->SetNewSpacing(newSpacing); - break; - } - case 2: - { - itk::ImageRegion<3> newRegion; - newRegion.SetSize(0, m_Controls->m_ResampleIntX->value()); - newRegion.SetSize(1, m_Controls->m_ResampleIntY->value()); - newRegion.SetSize(2, m_Controls->m_ResampleIntZ->value()); - resampler->SetNewImageSize(newRegion); - break; - } - default: - { - MITK_WARN << "Unknown resampling parameters!"; - return; - } + case 0: + { + itk::Vector< double, 3 > samplingFactor; + samplingFactor[0] = m_Controls->m_ResampleDoubleX->value(); + samplingFactor[1] = m_Controls->m_ResampleDoubleY->value(); + samplingFactor[2] = m_Controls->m_ResampleDoubleZ->value(); + resampler->SetSamplingFactor(samplingFactor); + break; + } + case 1: + { + itk::Vector< double, 3 > newSpacing; + newSpacing[0] = m_Controls->m_ResampleDoubleX->value(); + newSpacing[1] = m_Controls->m_ResampleDoubleY->value(); + newSpacing[2] = m_Controls->m_ResampleDoubleZ->value(); + resampler->SetNewSpacing(newSpacing); + break; + } + case 2: + { + itk::ImageRegion<3> newRegion; + newRegion.SetSize(0, m_Controls->m_ResampleIntX->value()); + newRegion.SetSize(1, m_Controls->m_ResampleIntY->value()); + newRegion.SetSize(2, m_Controls->m_ResampleIntZ->value()); + resampler->SetNewImageSize(newRegion); + break; + } + default: + { + MITK_WARN << "Unknown resampling parameters!"; + return; + } } QString outAdd; switch (m_Controls->m_InterpolatorBox->currentIndex()) { - case 0: - { - resampler->SetInterpolation(ResampleFilter::Interpolate_NearestNeighbour); - outAdd = "NearestNeighbour"; - break; - } - case 1: - { - resampler->SetInterpolation(ResampleFilter::Interpolate_Linear); - outAdd = "Linear"; - break; - } - case 2: - { - resampler->SetInterpolation(ResampleFilter::Interpolate_BSpline); - outAdd = "BSpline"; - break; - } - case 3: - { - resampler->SetInterpolation(ResampleFilter::Interpolate_WindowedSinc); - outAdd = "WindowedSinc"; - break; - } - default: - { - resampler->SetInterpolation(ResampleFilter::Interpolate_NearestNeighbour); - outAdd = "NearestNeighbour"; - } + case 0: + { + resampler->SetInterpolation(ResampleFilter::Interpolate_NearestNeighbour); + outAdd = "NearestNeighbour"; + break; + } + case 1: + { + resampler->SetInterpolation(ResampleFilter::Interpolate_Linear); + outAdd = "Linear"; + break; + } + case 2: + { + resampler->SetInterpolation(ResampleFilter::Interpolate_BSpline); + outAdd = "BSpline"; + break; + } + case 3: + { + resampler->SetInterpolation(ResampleFilter::Interpolate_WindowedSinc); + outAdd = "WindowedSinc"; + break; + } + default: + { + resampler->SetInterpolation(ResampleFilter::Interpolate_NearestNeighbour); + outAdd = "NearestNeighbour"; + } } resampler->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( resampler->GetOutput() ); PropHelper::CopyProperties(image, newImage, false); PropHelper::InitializeImage( newImage ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_resampled_"+outAdd).toStdString().c_str()); imageNode->SetVisibility(false); GetDataStorage()->Add(imageNode, node); } else if( image->GetPixelType().GetNumberOfComponents() ) { AccessFixedDimensionByItk(image, TemplatedResampleImage,3); } else { QMessageBox::warning(nullptr,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedResampleImage( itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } itk::Vector< double, 3 > newSpacing; itk::ImageRegion<3> newRegion; switch (m_Controls->m_ResampleTypeBox->currentIndex()) { - case 0: - { - itk::Vector< double, 3 > sampling; - sampling[0] = m_Controls->m_ResampleDoubleX->value(); - sampling[1] = m_Controls->m_ResampleDoubleY->value(); - sampling[2] = m_Controls->m_ResampleDoubleZ->value(); - - newSpacing = itkImage->GetSpacing(); - newSpacing[0] /= sampling[0]; - newSpacing[1] /= sampling[1]; - newSpacing[2] /= sampling[2]; - newRegion = itkImage->GetLargestPossibleRegion(); - newRegion.SetSize(0, newRegion.GetSize(0)*sampling[0]); - newRegion.SetSize(1, newRegion.GetSize(1)*sampling[1]); - newRegion.SetSize(2, newRegion.GetSize(2)*sampling[2]); - - break; - } - case 1: - { - newSpacing[0] = m_Controls->m_ResampleDoubleX->value(); - newSpacing[1] = m_Controls->m_ResampleDoubleY->value(); - newSpacing[2] = m_Controls->m_ResampleDoubleZ->value(); - - itk::Vector< double, 3 > oldSpacing = itkImage->GetSpacing(); - itk::Vector< double, 3 > sampling; - sampling[0] = oldSpacing[0]/newSpacing[0]; - sampling[1] = oldSpacing[1]/newSpacing[1]; - sampling[2] = oldSpacing[2]/newSpacing[2]; - newRegion = itkImage->GetLargestPossibleRegion(); - newRegion.SetSize(0, newRegion.GetSize(0)*sampling[0]); - newRegion.SetSize(1, newRegion.GetSize(1)*sampling[1]); - newRegion.SetSize(2, newRegion.GetSize(2)*sampling[2]); - break; - } - case 2: - { - newRegion.SetSize(0, m_Controls->m_ResampleIntX->value()); - newRegion.SetSize(1, m_Controls->m_ResampleIntY->value()); - newRegion.SetSize(2, m_Controls->m_ResampleIntZ->value()); - - itk::ImageRegion<3> oldRegion = itkImage->GetLargestPossibleRegion(); - itk::Vector< double, 3 > sampling; - sampling[0] = (double)newRegion.GetSize(0)/oldRegion.GetSize(0); - sampling[1] = (double)newRegion.GetSize(1)/oldRegion.GetSize(1); - sampling[2] = (double)newRegion.GetSize(2)/oldRegion.GetSize(2); + case 0: + { + itk::Vector< double, 3 > sampling; + sampling[0] = m_Controls->m_ResampleDoubleX->value(); + sampling[1] = m_Controls->m_ResampleDoubleY->value(); + sampling[2] = m_Controls->m_ResampleDoubleZ->value(); + + newSpacing = itkImage->GetSpacing(); + newSpacing[0] /= sampling[0]; + newSpacing[1] /= sampling[1]; + newSpacing[2] /= sampling[2]; + newRegion = itkImage->GetLargestPossibleRegion(); + newRegion.SetSize(0, newRegion.GetSize(0)*sampling[0]); + newRegion.SetSize(1, newRegion.GetSize(1)*sampling[1]); + newRegion.SetSize(2, newRegion.GetSize(2)*sampling[2]); - newSpacing = itkImage->GetSpacing(); - newSpacing[0] /= sampling[0]; - newSpacing[1] /= sampling[1]; - newSpacing[2] /= sampling[2]; - break; - } - default: - { - MITK_WARN << "Unknown resampling parameters!"; - return; - } + break; + } + case 1: + { + newSpacing[0] = m_Controls->m_ResampleDoubleX->value(); + newSpacing[1] = m_Controls->m_ResampleDoubleY->value(); + newSpacing[2] = m_Controls->m_ResampleDoubleZ->value(); + + itk::Vector< double, 3 > oldSpacing = itkImage->GetSpacing(); + itk::Vector< double, 3 > sampling; + sampling[0] = oldSpacing[0]/newSpacing[0]; + sampling[1] = oldSpacing[1]/newSpacing[1]; + sampling[2] = oldSpacing[2]/newSpacing[2]; + newRegion = itkImage->GetLargestPossibleRegion(); + newRegion.SetSize(0, newRegion.GetSize(0)*sampling[0]); + newRegion.SetSize(1, newRegion.GetSize(1)*sampling[1]); + newRegion.SetSize(2, newRegion.GetSize(2)*sampling[2]); + break; + } + case 2: + { + newRegion.SetSize(0, m_Controls->m_ResampleIntX->value()); + newRegion.SetSize(1, m_Controls->m_ResampleIntY->value()); + newRegion.SetSize(2, m_Controls->m_ResampleIntZ->value()); + + itk::ImageRegion<3> oldRegion = itkImage->GetLargestPossibleRegion(); + itk::Vector< double, 3 > sampling; + sampling[0] = (double)newRegion.GetSize(0)/oldRegion.GetSize(0); + sampling[1] = (double)newRegion.GetSize(1)/oldRegion.GetSize(1); + sampling[2] = (double)newRegion.GetSize(2)/oldRegion.GetSize(2); + + newSpacing = itkImage->GetSpacing(); + newSpacing[0] /= sampling[0]; + newSpacing[1] /= sampling[1]; + newSpacing[2] /= sampling[2]; + break; + } + default: + { + MITK_WARN << "Unknown resampling parameters!"; + return; + } } itk::Point origin = itkImage->GetOrigin(); origin[0] -= itkImage->GetSpacing()[0]/2; origin[1] -= itkImage->GetSpacing()[1]/2; origin[2] -= itkImage->GetSpacing()[2]/2; origin[0] += newSpacing[0]/2; origin[1] += newSpacing[1]/2; origin[2] += newSpacing[2]/2; typedef itk::Image ImageType; typename ImageType::Pointer outImage = ImageType::New(); outImage->SetSpacing( newSpacing ); outImage->SetOrigin( origin ); outImage->SetDirection( itkImage->GetDirection() ); outImage->SetLargestPossibleRegion( newRegion ); outImage->SetBufferedRegion( newRegion ); outImage->SetRequestedRegion( newRegion ); outImage->Allocate(); typedef itk::ResampleImageFilter ResampleFilter; typename ResampleFilter::Pointer resampler = ResampleFilter::New(); resampler->SetInput(itkImage); resampler->SetOutputParametersFromImage(outImage); QString outAdd; switch (m_Controls->m_InterpolatorBox->currentIndex()) { - case 0: - { - typename itk::NearestNeighborInterpolateImageFunction::Pointer interp - = itk::NearestNeighborInterpolateImageFunction::New(); - resampler->SetInterpolator(interp); - outAdd = "NearestNeighbour"; - break; - } - case 1: - { - typename itk::LinearInterpolateImageFunction::Pointer interp - = itk::LinearInterpolateImageFunction::New(); - resampler->SetInterpolator(interp); - outAdd = "Linear"; - break; - } - case 2: - { - typename itk::BSplineInterpolateImageFunction::Pointer interp - = itk::BSplineInterpolateImageFunction::New(); - resampler->SetInterpolator(interp); - outAdd = "BSpline"; - break; - } - case 3: - { - typename itk::WindowedSincInterpolateImageFunction::Pointer interp - = itk::WindowedSincInterpolateImageFunction::New(); - resampler->SetInterpolator(interp); - outAdd = "WindowedSinc"; - break; - } - default: - { - typename itk::NearestNeighborInterpolateImageFunction::Pointer interp - = itk::NearestNeighborInterpolateImageFunction::New(); - resampler->SetInterpolator(interp); - outAdd = "NearestNeighbour"; - } + case 0: + { + typename itk::NearestNeighborInterpolateImageFunction::Pointer interp + = itk::NearestNeighborInterpolateImageFunction::New(); + resampler->SetInterpolator(interp); + outAdd = "NearestNeighbour"; + break; + } + case 1: + { + typename itk::LinearInterpolateImageFunction::Pointer interp + = itk::LinearInterpolateImageFunction::New(); + resampler->SetInterpolator(interp); + outAdd = "Linear"; + break; + } + case 2: + { + typename itk::BSplineInterpolateImageFunction::Pointer interp + = itk::BSplineInterpolateImageFunction::New(); + resampler->SetInterpolator(interp); + outAdd = "BSpline"; + break; + } + case 3: + { + typename itk::WindowedSincInterpolateImageFunction::Pointer interp + = itk::WindowedSincInterpolateImageFunction::New(); + resampler->SetInterpolator(interp); + outAdd = "WindowedSinc"; + break; + } + default: + { + typename itk::NearestNeighborInterpolateImageFunction::Pointer interp + = itk::NearestNeighborInterpolateImageFunction::New(); + resampler->SetInterpolator(interp); + outAdd = "NearestNeighbour"; + } } resampler->Update(); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( resampler->GetOutput() ); image->SetVolume( resampler->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( image ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_resampled_"+outAdd).toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } void QmitkPreprocessingView::DoApplyHeader() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); bool isDti = false; bool isOdf = false; bool isPeak = false; if (!isDiffusionImage) { if ( dynamic_cast(node->GetData()) ) isDti = true; else if ( dynamic_cast(node->GetData()) ) isOdf = true; else if ( dynamic_cast(node->GetData()) ) isPeak = true; } mitk::Image::Pointer newImage = image->Clone(); mitk::Vector3D spacing; spacing[0] = m_Controls->m_HeaderSpacingX->value(); spacing[1] = m_Controls->m_HeaderSpacingY->value(); spacing[2] = m_Controls->m_HeaderSpacingZ->value(); newImage->GetGeometry()->SetSpacing( spacing ); mitk::Point3D origin; origin[0] = m_Controls->m_HeaderOriginX->value(); origin[1] = m_Controls->m_HeaderOriginY->value(); origin[2] = m_Controls->m_HeaderOriginZ->value(); newImage->GetGeometry()->SetOrigin(origin); vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New(); matrix->SetElement(0,3,newImage->GetGeometry()->GetOrigin()[0]); matrix->SetElement(1,3,newImage->GetGeometry()->GetOrigin()[1]); matrix->SetElement(2,3,newImage->GetGeometry()->GetOrigin()[2]); for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item(r,c); if (!item) continue; matrix->SetElement(r,c,item->text().toDouble()); } } newImage->GetGeometry()->SetIndexToWorldTransformByVtkMatrixWithoutChangingSpacing(matrix); if ( isDiffusionImage ) { vnl_matrix_fixed< double, 3, 3 > mf; for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_MeasurementFrameTable->item(r,c); if (!item) continue; mf[r][c] = item->text().toDouble(); } } PropHelper::SetMeasurementFrame(newImage, mf); PropHelper::InitializeImage( newImage ); } mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); if (isOdf) { mitk::OdfImage::ItkOdfImageType::Pointer itk_img = mitk::OdfImage::ItkOdfImageType::New(); mitk::CastToItkImage(newImage, itk_img); mitk::Image::Pointer odfImage = dynamic_cast(mitk::OdfImage::New().GetPointer()); mitk::CastToMitkImage(itk_img, odfImage); odfImage->SetVolume(itk_img->GetBufferPointer()); imageNode->SetData( odfImage ); } else if (isDti) { mitk::TensorImage::ItkTensorImageType::Pointer itk_img = mitk::ImageToItkImage(newImage); mitk::Image::Pointer tensorImage = dynamic_cast(mitk::TensorImage::New().GetPointer()); mitk::CastToMitkImage(itk_img, tensorImage); tensorImage->SetVolume(itk_img->GetBufferPointer()); imageNode->SetData( tensorImage ); } else if (isPeak) { mitk::PeakImage::ItkPeakImageType::Pointer itk_img = mitk::ImageToItkImage(newImage); mitk::Image::Pointer peakImage = dynamic_cast(mitk::PeakImage::New().GetPointer()); mitk::CastToMitkImage(itk_img, peakImage); peakImage->SetVolume(itk_img->GetBufferPointer()); imageNode->SetData( peakImage ); } else imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_newheader").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoProjectSignal() { switch(m_Controls->m_ProjectionMethodBox->currentIndex()) { - case 0: - DoADCAverage(); + case 0: + DoADCAverage(); break; - case 1: - DoAKCFit(); + case 1: + DoAKCFit(); break; - case 2: - DoBiExpFit(); + case 2: + DoBiExpFit(); break; - default: - DoADCAverage(); + default: + DoADCAverage(); } } void QmitkPreprocessingView::DoDwiNormalization() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) { return; } auto gradientContainer = PropHelper::GetGradientContainer(image); int b0Index = -1; for (unsigned int i=0; isize(); i++) { GradientDirectionType g = gradientContainer->GetElement(i); if (g.magnitude()<0.001) { b0Index = i; break; } } if (b0Index==-1) { return; } typedef itk::DwiNormilzationFilter FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetGradientDirections(PropHelper::GetGradientContainer(image)); filter->SetNewMean(m_Controls->m_NewMean->value()); filter->SetNewStdev(m_Controls->m_NewStdev->value()); UcharImageType::Pointer itkImage = nullptr; if (m_Controls->m_NormalizationMaskBox->GetSelectedNode().IsNotNull()) { itkImage = UcharImageType::New(); if ( dynamic_cast(m_Controls->m_NormalizationMaskBox->GetSelectedNode()->GetData()) != nullptr ) { mitk::CastToItkImage( dynamic_cast(m_Controls->m_NormalizationMaskBox->GetSelectedNode()->GetData()), itkImage ); } filter->SetMaskImage(itkImage); } filter->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( filter->GetOutput() ); PropHelper::CopyProperties(image, newImage, false); PropHelper::InitializeImage( newImage ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_normalized").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } void QmitkPreprocessingView::DoLengthCorrection() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) return; mitk::Image::Pointer image = dynamic_cast(node->GetData()); if (image == nullptr ) return; if (!PropHelper::IsDiffusionWeightedImage(image)) return; typedef itk::DwiGradientLengthCorrectionFilter FilterType; ItkDwiType::Pointer itkVectorImagePointer = PropHelper::GetItkVectorImage(image); FilterType::Pointer filter = FilterType::New(); filter->SetRoundingValue( m_Controls->m_B_ValueMap_Rounder_SpinBox->value()); filter->SetReferenceBValue(PropHelper::GetReferenceBValue(image)); filter->SetReferenceGradientDirectionContainer(PropHelper::GetGradientContainer(image)); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( itkVectorImagePointer.GetPointer() ); newImage->SetImportVolume( itkVectorImagePointer->GetBufferPointer(), 0, 0, mitk::Image::CopyMemory); itkVectorImagePointer->GetPixelContainer()->ContainerManageMemoryOff(); PropHelper::CopyProperties(image, newImage, true); PropHelper::SetGradientContainer(newImage, filter->GetOutputGradientDirectionContainer()); PropHelper::SetReferenceBValue(newImage, filter->GetNewBValue()); PropHelper::InitializeImage( newImage ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_rounded").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } void QmitkPreprocessingView::UpdateDwiBValueMapRounder(int i) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(node) ); if ( ! isDiffusionImage ) { return; } UpdateBValueTableWidget(i); UpdateGradientDetails(); } void QmitkPreprocessingView:: CallMultishellToSingleShellFilter( itk::DWIVoxelFunctor * functor, mitk::Image::Pointer image, QString imageName, mitk::DataNode* parent ) { typedef itk::RadialMultishellToSingleshellImageFilter FilterType; // filter input parameter const mitk::BValueMapProperty::BValueMap& originalShellMap = PropHelper::GetBValueMap(image); ItkDwiType::Pointer itkVectorImagePointer = PropHelper::GetItkVectorImage(image); ItkDwiType* vectorImage = itkVectorImagePointer.GetPointer(); - const GradProp::GradientDirectionsContainerType::Pointer gradientContainer = PropHelper::GetGradientContainer(image); + const GradProp::GradientDirectionsContainerType::ConstPointer gradientContainer = PropHelper::GetGradientContainer(image); const unsigned int& bValue = PropHelper::GetReferenceBValue(image); mitk::DataNode::Pointer imageNode = 0; // filter call FilterType::Pointer filter = FilterType::New(); filter->SetInput(vectorImage); filter->SetOriginalGradientDirections(gradientContainer); filter->SetOriginalBValueMap(originalShellMap); filter->SetOriginalBValue(bValue); filter->SetFunctor(functor); filter->Update(); // create new DWI image mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( filter->GetOutput() ); PropHelper::CopyProperties(image, outImage, true); PropHelper::SetGradientContainer(outImage, filter->GetTargetGradientDirections()); PropHelper::SetReferenceBValue(outImage, m_Controls->m_targetBValueSpinBox->value()); PropHelper::InitializeImage( outImage ); imageNode = mitk::DataNode::New(); imageNode->SetData( outImage ); imageNode->SetName(imageName.toStdString().c_str()); GetDataStorage()->Add(imageNode, parent); } void QmitkPreprocessingView::DoBiExpFit() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) { return; } itk::BiExpFitFunctor::Pointer functor = itk::BiExpFitFunctor::New(); QString name(node->GetName().c_str()); const mitk::BValueMapProperty::BValueMap& originalShellMap = PropHelper::GetBValueMap(image); mitk::BValueMapProperty::BValueMap::const_iterator it = originalShellMap.begin(); ++it;/* skip b=0*/ unsigned int s = 0; /*shell index */ vnl_vector bValueList(originalShellMap.size()-1); while( it != originalShellMap.end() ) { bValueList.put(s++,(it++)->first); } const double targetBValue = m_Controls->m_targetBValueSpinBox->value(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); CallMultishellToSingleShellFilter(functor,image,name + "_BiExp", node); } void QmitkPreprocessingView::DoAKCFit() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) { return; } itk::KurtosisFitFunctor::Pointer functor = itk::KurtosisFitFunctor::New(); QString name(node->GetName().c_str()); const mitk::BValueMapProperty::BValueMap& originalShellMap = PropHelper::GetBValueMap(image); mitk::BValueMapProperty::BValueMap::const_iterator it = originalShellMap.begin(); ++it;/* skip b=0*/ unsigned int s = 0; /*shell index */ vnl_vector bValueList(originalShellMap.size()-1); while(it != originalShellMap.end()) bValueList.put(s++,(it++)->first); const double targetBValue = m_Controls->m_targetBValueSpinBox->value(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); CallMultishellToSingleShellFilter(functor,image,name + "_AKC", node); } void QmitkPreprocessingView::DoADCFit() { // later } void QmitkPreprocessingView::DoADCAverage() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) return; itk::ADCAverageFunctor::Pointer functor = itk::ADCAverageFunctor::New(); QString name(node->GetName().c_str()); const mitk::BValueMapProperty::BValueMap &originalShellMap = PropHelper::GetBValueMap(image); mitk::BValueMapProperty::BValueMap::const_iterator it = originalShellMap.begin(); ++it;/* skip b=0*/ unsigned int s = 0; /*shell index */ vnl_vector bValueList(originalShellMap.size()-1); while(it != originalShellMap.end()) bValueList.put(s++,(it++)->first); const double targetBValue = m_Controls->m_targetBValueSpinBox->value(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); CallMultishellToSingleShellFilter(functor,image,name + "_ADC", node); } void QmitkPreprocessingView::CleanBValueTableWidget() { m_Controls->m_B_ValueMap_TableWidget->clear(); m_Controls->m_B_ValueMap_TableWidget->setRowCount(1); QStringList headerList; headerList << "b-Value" << "Number of gradients"; m_Controls->m_B_ValueMap_TableWidget->setHorizontalHeaderLabels(headerList); m_Controls->m_B_ValueMap_TableWidget->setItem(0,0,new QTableWidgetItem("-")); m_Controls->m_B_ValueMap_TableWidget->setItem(0,1,new QTableWidgetItem("-")); } void QmitkPreprocessingView::UpdateGradientDetails() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage(false); isDiffusionImage = PropHelper::IsDiffusionWeightedImage(image); if ( ! isDiffusionImage ) { m_Controls->m_WorkingGradientsText->clear(); m_Controls->m_OriginalGradientsText->clear(); return; } auto gradientContainer = PropHelper::GetGradientContainer(image); QString text = ""; for (unsigned int j=0; jSize(); j++) { auto g = gradientContainer->at(j); g = g.normalize(); if (g[0]>=0) text += " "; text += QString::number(g[0]); if (jSize()-1) text += " "; else text += "\n"; } for (unsigned int j=0; jSize(); j++) { auto g = gradientContainer->at(j); g = g.normalize(); if (g[1]>=0) text += " "; text += QString::number(g[1]); if (jSize()-1) text += " "; else text += "\n"; } for (unsigned int j=0; jSize(); j++) { auto g = gradientContainer->at(j); g = g.normalize(); if (g[2]>=0) text += " "; text += QString::number(g[2]); if (jSize()-1) text += " "; else text += "\n"; } m_Controls->m_WorkingGradientsText->setPlainText(text); gradientContainer = PropHelper::GetOriginalGradientContainer(image); text = ""; for (unsigned int j=0; jSize(); j++) { auto g = gradientContainer->at(j); g = g.normalize(); if (g[0]>=0) text += " "; text += QString::number(g[0]); if (jSize()-1) text += " "; else text += "\n"; } for (unsigned int j=0; jSize(); j++) { auto g = gradientContainer->at(j); g = g.normalize(); if (g[1]>=0) text += " "; text += QString::number(g[1]); if (jSize()-1) text += " "; else text += "\n"; } for (unsigned int j=0; jSize(); j++) { auto g = gradientContainer->at(j); g = g.normalize(); if (g[2]>=0) text += " "; text += QString::number(g[2]); if (jSize()-1) text += " "; else text += "\n"; } m_Controls->m_OriginalGradientsText->setPlainText(text); } void QmitkPreprocessingView::UpdateBValueTableWidget(int) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { CleanBValueTableWidget(); return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage(false); isDiffusionImage = PropHelper::IsDiffusionWeightedImage(image); if ( ! isDiffusionImage ) { CleanBValueTableWidget(); } else { typedef mitk::BValueMapProperty::BValueMap BValueMap; typedef mitk::BValueMapProperty::BValueMap::iterator BValueMapIterator; BValueMapIterator it; BValueMap roundedBValueMap = PropHelper::GetBValueMap(image); m_Controls->m_B_ValueMap_TableWidget->clear(); m_Controls->m_B_ValueMap_TableWidget->setRowCount(roundedBValueMap.size() ); QStringList headerList; headerList << "b-Value" << "Number of gradients"; m_Controls->m_B_ValueMap_TableWidget->setHorizontalHeaderLabels(headerList); int i = 0 ; for(it = roundedBValueMap.begin() ;it != roundedBValueMap.end(); it++) { m_Controls->m_B_ValueMap_TableWidget->setItem(i,0,new QTableWidgetItem(QString::number(it->first))); QTableWidgetItem* item = m_Controls->m_B_ValueMap_TableWidget->item(i,0); item->setFlags(item->flags() & ~Qt::ItemIsEditable); m_Controls->m_B_ValueMap_TableWidget->setItem(i,1,new QTableWidgetItem(QString::number(it->second.size()))); i++; } } } void QmitkPreprocessingView::OnSelectionChanged(berry::IWorkbenchPart::Pointer , const QList& nodes) { (void) nodes; this->OnImageSelectionChanged(); } void QmitkPreprocessingView::OnImageSelectionChanged() { for (int r=0; r<3; r++) for (int c=0; c<3; c++) { { QTableWidgetItem* item = m_Controls->m_MeasurementFrameTable->item( r, c ); delete item; item = new QTableWidgetItem(); m_Controls->m_MeasurementFrameTable->setItem( r, c, item ); } { QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item( r, c ); delete item; item = new QTableWidgetItem(); m_Controls->m_DirectionMatrixTable->setItem( r, c, item ); } } bool foundImageVolume = true; mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } bool foundDwiVolume( PropHelper::IsDiffusionWeightedImage( node ) ); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool multiComponentVolume = (image->GetPixelType().GetNumberOfComponents() > 1); bool threeDplusTVolume = (image->GetTimeSteps() > 1); m_Controls->m_ButtonAverageGradients->setEnabled(foundDwiVolume); m_Controls->m_ButtonExtractB0->setEnabled(foundDwiVolume); m_Controls->m_CheckExtractAll->setEnabled(foundDwiVolume); m_Controls->m_MeasurementFrameTable->setEnabled(foundDwiVolume); m_Controls->m_ReduceGradientsButton->setEnabled(foundDwiVolume); m_Controls->m_ShowGradientsButton->setEnabled(foundDwiVolume); m_Controls->m_MirrorGradientToHalfSphereButton->setEnabled(foundDwiVolume); + m_Controls->m_SwapGradientsButton->setEnabled(foundDwiVolume); m_Controls->m_MergeDwisButton->setEnabled(foundDwiVolume); m_Controls->m_B_ValueMap_Rounder_SpinBox->setEnabled(foundDwiVolume); m_Controls->m_ProjectSignalButton->setEnabled(foundDwiVolume); m_Controls->m_CreateLengthCorrectedDwi->setEnabled(foundDwiVolume); m_Controls->m_targetBValueSpinBox->setEnabled(foundDwiVolume); m_Controls->m_NormalizeImageValuesButton->setEnabled(foundDwiVolume); m_Controls->m_RemoveGradientButton->setEnabled(foundDwiVolume); m_Controls->m_ExtractGradientButton->setEnabled(foundDwiVolume); m_Controls->m_FlipGradientsButton->setEnabled(foundDwiVolume); m_Controls->m_ClearRotationButton->setEnabled(foundDwiVolume); m_Controls->m_DirectionMatrixTable->setEnabled(foundImageVolume); m_Controls->m_ModifyHeader->setEnabled(foundImageVolume); m_Controls->m_AlignImageBox->setEnabled(foundImageVolume); // we do not support multi-component and 3D+t images for certain operations bool foundSingleImageVolume = foundDwiVolume || (foundImageVolume && !(multiComponentVolume || threeDplusTVolume)); m_Controls->m_FlipAxis->setEnabled(foundSingleImageVolume); m_Controls->m_CropImageButton->setEnabled(foundSingleImageVolume); m_Controls->m_ExtractBrainMask->setEnabled(foundSingleImageVolume); m_Controls->m_ResampleImageButton->setEnabled(foundSingleImageVolume); // reset sampling frame to 1 and update all ealted components m_Controls->m_B_ValueMap_Rounder_SpinBox->setValue(1); UpdateBValueTableWidget(m_Controls->m_B_ValueMap_Rounder_SpinBox->value()); DoUpdateInterpolationGui(m_Controls->m_ResampleTypeBox->currentIndex()); UpdateGradientDetails(); m_Controls->m_HeaderSpacingX->setValue(image->GetGeometry()->GetSpacing()[0]); m_Controls->m_HeaderSpacingY->setValue(image->GetGeometry()->GetSpacing()[1]); m_Controls->m_HeaderSpacingZ->setValue(image->GetGeometry()->GetSpacing()[2]); m_Controls->m_HeaderOriginX->setValue(image->GetGeometry()->GetOrigin()[0]); m_Controls->m_HeaderOriginY->setValue(image->GetGeometry()->GetOrigin()[1]); m_Controls->m_HeaderOriginZ->setValue(image->GetGeometry()->GetOrigin()[2]); m_Controls->m_XstartBox->setMaximum(image->GetGeometry()->GetExtent(0)-1); m_Controls->m_YstartBox->setMaximum(image->GetGeometry()->GetExtent(1)-1); m_Controls->m_ZstartBox->setMaximum(image->GetGeometry()->GetExtent(2)-1); m_Controls->m_XendBox->setMaximum(image->GetGeometry()->GetExtent(0)-1); m_Controls->m_YendBox->setMaximum(image->GetGeometry()->GetExtent(1)-1); m_Controls->m_ZendBox->setMaximum(image->GetGeometry()->GetExtent(2)-1); for (int r=0; r<3; r++) for (int c=0; c<3; c++) { // Direction matrix QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item( r, c ); delete item; item = new QTableWidgetItem(); item->setTextAlignment(Qt::AlignCenter | Qt::AlignVCenter); double val = image->GetGeometry()->GetVtkMatrix()->GetElement(r,c)/image->GetGeometry()->GetSpacing()[c]; item->setText(QString::number(val)); m_Controls->m_DirectionMatrixTable->setItem( r, c, item ); } if (foundDwiVolume) { m_Controls->m_InputData->setTitle("Input Data"); vnl_matrix_fixed< double, 3, 3 > mf = PropHelper::GetMeasurementFrame(image); for (int r=0; r<3; r++) for (int c=0; c<3; c++) { // Measurement frame QTableWidgetItem* item = m_Controls->m_MeasurementFrameTable->item( r, c ); delete item; item = new QTableWidgetItem(); item->setTextAlignment(Qt::AlignCenter | Qt::AlignVCenter); item->setText(QString::number(mf.get(r,c))); m_Controls->m_MeasurementFrameTable->setItem( r, c, item ); } //calculate target bValue for MultishellToSingleShellfilter const mitk::BValueMapProperty::BValueMap & bValMap = PropHelper::GetBValueMap(image); mitk::BValueMapProperty::BValueMap::const_iterator it = bValMap.begin(); unsigned int targetBVal = 0; while(it != bValMap.end()) { targetBVal += (it++)->first; } targetBVal /= (float)bValMap.size()-1; m_Controls->m_targetBValueSpinBox->setValue(targetBVal); m_Controls->m_RemoveGradientBox->setMaximum(PropHelper::GetGradientContainer(image)->Size()-1); m_Controls->m_ExtractGradientBox->setMaximum(PropHelper::GetGradientContainer(image)->Size()-1); } } void QmitkPreprocessingView::Activated() { } void QmitkPreprocessingView::Deactivated() { OnImageSelectionChanged(); } void QmitkPreprocessingView::Visible() { OnImageSelectionChanged(); } void QmitkPreprocessingView::Hidden() { } void QmitkPreprocessingView::DoClearRotationOfGradients() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) return; mitk::Image::Pointer image = dynamic_cast(node->GetData()); if (image == nullptr) return; if(!PropHelper::IsDiffusionWeightedImage(image)) return; mitk::Image::Pointer newDwi = image->Clone(); PropHelper::SetApplyMatrixToGradients(newDwi, false); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi ); QString name = node->GetName().c_str(); imageNode->SetName( (name+"_OriginalGradients").toStdString().c_str() ); GetDataStorage()->Add( imageNode, node ); } void QmitkPreprocessingView::DoFlipGradientDirections() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } mitk::Image::Pointer newDwi = image->Clone(); auto gradientContainer = PropHelper::GetGradientContainer(newDwi); + auto newGradientContainer = PropHelper::GradientDirectionsContainerType::New(); for (unsigned int j=0; jSize(); j++) { - if (m_Controls->m_FlipGradBoxX->isChecked()) { gradientContainer->at(j)[0] *= -1; } - if (m_Controls->m_FlipGradBoxY->isChecked()) { gradientContainer->at(j)[1] *= -1; } - if (m_Controls->m_FlipGradBoxZ->isChecked()) { gradientContainer->at(j)[2] *= -1; } + PropHelper::GradientDirectionType g; + g[0] = gradientContainer->at(j)[0]; + g[1] = gradientContainer->at(j)[1]; + g[2] = gradientContainer->at(j)[2]; + if (m_Controls->m_FlipGradBoxX->isChecked()) { g[0] *= -1; } + if (m_Controls->m_FlipGradBoxY->isChecked()) { g[1] *= -1; } + if (m_Controls->m_FlipGradBoxZ->isChecked()) { g[2] *= -1; } + newGradientContainer->push_back(g); } PropHelper::CopyProperties(image, newDwi, true); - PropHelper::SetGradientContainer(newDwi, gradientContainer); + PropHelper::SetGradientContainer(newDwi, newGradientContainer); PropHelper::InitializeImage( newDwi ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi ); QString name = node->GetName().c_str(); imageNode->SetName( (name+"_GradientFlip").toStdString().c_str() ); GetDataStorage()->Add( imageNode, node ); } + +void QmitkPreprocessingView::DoSwapGradientDimensions() +{ + mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); + if (node.IsNull()) { return; } + + mitk::Image::Pointer image = dynamic_cast(node->GetData()); + if ( image == nullptr ) { return; } + + mitk::Image::Pointer newDwi = image->Clone(); + + auto gradientContainer = PropHelper::GetGradientContainer(newDwi); + auto newGradientContainer = PropHelper::GradientDirectionsContainerType::New(); + + std::vector dims_split; + std::string swap_string = m_Controls->m_SwapGradientsEdit->text().toStdString(); + boost::split(dims_split, swap_string, boost::is_any_of(" "), boost::token_compress_on); + std::vector dims_split_clean; + for (auto s : dims_split) + { + if (s=="x") + dims_split_clean.push_back(0); + else if (s=="y") + dims_split_clean.push_back(1); + else if (s=="z") + dims_split_clean.push_back(2); + } + if (dims_split_clean.size()!=3) + { + QMessageBox::warning(nullptr,"Warning", QString("String should contain x, y and z in arbitrary order separated by a space.") ); + return; + } + + for (unsigned int j=0; jSize(); j++) + { + PropHelper::GradientDirectionType g; + g[0] = gradientContainer->at(j)[dims_split_clean.at(0)]; + g[1] = gradientContainer->at(j)[dims_split_clean.at(1)]; + g[2] = gradientContainer->at(j)[dims_split_clean.at(2)]; + + newGradientContainer->push_back(g); + } + + PropHelper::CopyProperties(image, newDwi, true); + PropHelper::SetGradientContainer(newDwi, newGradientContainer); + PropHelper::InitializeImage( newDwi ); + + mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); + imageNode->SetData( newDwi ); + + QString name = node->GetName().c_str(); + imageNode->SetName( (name+"_GradientDimSwapped").toStdString().c_str() ); + GetDataStorage()->Add( imageNode, node ); +} + void QmitkPreprocessingView::DoHalfSphereGradientDirections() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } mitk::Image::Pointer newDwi = image->Clone(); auto gradientContainer = PropHelper::GetGradientContainer(newDwi); + auto newGradientContainer = PropHelper::GradientDirectionsContainerType::New(); for (unsigned int j=0; jSize(); j++) { - if (gradientContainer->at(j)[0]<0) { gradientContainer->at(j) = -gradientContainer->at(j); } + PropHelper::GradientDirectionType g; + g[0] = gradientContainer->at(j)[0]; + g[1] = gradientContainer->at(j)[1]; + g[2] = gradientContainer->at(j)[2]; + + if (g[0]<0) { g = -g; } + + newGradientContainer->push_back(g); } PropHelper::CopyProperties(image, newDwi, true); - PropHelper::SetGradientContainer(newDwi, gradientContainer); + PropHelper::SetGradientContainer(newDwi, newGradientContainer); PropHelper::InitializeImage( newDwi ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi ); QString name = node->GetName().c_str(); imageNode->SetName( (name+"_halfsphere").toStdString().c_str() ); GetDataStorage()->Add( imageNode, node ); } void QmitkPreprocessingView::DoShowGradientDirections() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } int maxIndex = 0; unsigned int maxSize = image->GetDimension(0); if (maxSizeGetDimension(1)) { maxSize = image->GetDimension(1); maxIndex = 1; } if (maxSizeGetDimension(2)) { maxSize = image->GetDimension(2); maxIndex = 2; } mitk::Point3D origin = image->GetGeometry()->GetOrigin(); mitk::PointSet::Pointer originSet = mitk::PointSet::New(); typedef mitk::BValueMapProperty::BValueMap BValueMap; typedef mitk::BValueMapProperty::BValueMap::iterator BValueMapIterator; BValueMap bValMap = PropHelper::GetBValueMap(image); auto gradientContainer = PropHelper::GetGradientContainer(image); mitk::BaseGeometry::Pointer geometry = image->GetGeometry(); int shellCount = 1; for(BValueMapIterator it = bValMap.begin(); it!=bValMap.end(); ++it) { mitk::PointSet::Pointer pointset = mitk::PointSet::New(); for (unsigned int j=0; jsecond.size(); j++) { mitk::Point3D ip; vnl_vector_fixed< double, 3 > v = gradientContainer->at(it->second[j]); if (v.magnitude()>mitk::eps) { ip[0] = v[0]*maxSize*geometry->GetSpacing()[maxIndex]/2 - + origin[0]-0.5*geometry->GetSpacing()[0] - + geometry->GetSpacing()[0]*image->GetDimension(0)/2; + + origin[0]-0.5*geometry->GetSpacing()[0] + + geometry->GetSpacing()[0]*image->GetDimension(0)/2; ip[1] = v[1]*maxSize*geometry->GetSpacing()[maxIndex]/2 - + origin[1]-0.5*geometry->GetSpacing()[1] - + geometry->GetSpacing()[1]*image->GetDimension(1)/2; + + origin[1]-0.5*geometry->GetSpacing()[1] + + geometry->GetSpacing()[1]*image->GetDimension(1)/2; ip[2] = v[2]*maxSize*geometry->GetSpacing()[maxIndex]/2 - + origin[2]-0.5*geometry->GetSpacing()[2] - + geometry->GetSpacing()[2]*image->GetDimension(2)/2; + + origin[2]-0.5*geometry->GetSpacing()[2] + + geometry->GetSpacing()[2]*image->GetDimension(2)/2; pointset->InsertPoint(j, ip); } else if (originSet->IsEmpty()) { ip[0] = v[0]*maxSize*geometry->GetSpacing()[maxIndex]/2 - + origin[0]-0.5*geometry->GetSpacing()[0] - + geometry->GetSpacing()[0]*image->GetDimension(0)/2; + + origin[0]-0.5*geometry->GetSpacing()[0] + + geometry->GetSpacing()[0]*image->GetDimension(0)/2; ip[1] = v[1]*maxSize*geometry->GetSpacing()[maxIndex]/2 - + origin[1]-0.5*geometry->GetSpacing()[1] - + geometry->GetSpacing()[1]*image->GetDimension(1)/2; + + origin[1]-0.5*geometry->GetSpacing()[1] + + geometry->GetSpacing()[1]*image->GetDimension(1)/2; ip[2] = v[2]*maxSize*geometry->GetSpacing()[maxIndex]/2 - + origin[2]-0.5*geometry->GetSpacing()[2] - + geometry->GetSpacing()[2]*image->GetDimension(2)/2; + + origin[2]-0.5*geometry->GetSpacing()[2] + + geometry->GetSpacing()[2]*image->GetDimension(2)/2; originSet->InsertPoint(j, ip); } } if ( it->first < mitk::eps ) { continue; } // add shell to datastorage mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(pointset); QString name = node->GetName().c_str(); name += "_Shell_"; name += QString::number( it->first ); newNode->SetName( name.toStdString().c_str() ); newNode->SetProperty( "pointsize", mitk::FloatProperty::New((float)maxSize / 50) ); int b0 = shellCount % 2; int b1 = 0; int b2 = 0; if (shellCount>4) { b2 = 1; } if (shellCount%4 >= 2) { b1 = 1; } newNode->SetProperty("color", mitk::ColorProperty::New( b2, b1, b0 )); GetDataStorage()->Add( newNode, node ); shellCount++; } // add origin to datastorage mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(originSet); QString name = node->GetName().c_str(); name += "_Origin"; newNode->SetName(name.toStdString().c_str()); newNode->SetProperty("pointsize", mitk::FloatProperty::New((float)maxSize/50)); newNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); GetDataStorage()->Add(newNode, node); } void QmitkPreprocessingView::DoReduceGradientDirections() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } typedef itk::ElectrostaticRepulsionDiffusionGradientReductionFilter FilterType; typedef mitk::BValueMapProperty::BValueMap BValueMap; // GetShellSelection from GUI BValueMap shellSlectionMap; BValueMap originalShellMap = PropHelper::GetBValueMap(image); std::vector newNumGradientDirections; int shellCounter = 0; QString name = node->GetName().c_str(); for (int i=0; im_B_ValueMap_TableWidget->rowCount(); i++) { double BValue = m_Controls->m_B_ValueMap_TableWidget->item(i,0)->text().toDouble(); shellSlectionMap[BValue] = originalShellMap[BValue]; unsigned int num = m_Controls->m_B_ValueMap_TableWidget->item(i,1)->text().toUInt(); newNumGradientDirections.push_back(num); name += "_"; name += QString::number(num); shellCounter++; } if (newNumGradientDirections.empty()) { return; } auto gradientContainer = PropHelper::GetGradientContainer(image); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetOriginalGradientDirections(gradientContainer); filter->SetNumGradientDirections(newNumGradientDirections); filter->SetOriginalBValueMap(originalShellMap); filter->SetShellSelectionBValueMap(shellSlectionMap); filter->SetUseFirstN(m_Controls->m_KeepFirstNBox->isChecked()); filter->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( filter->GetOutput() ); PropHelper::CopyProperties(image, newImage, true); PropHelper::SetGradientContainer(newImage, filter->GetGradientDirections()); PropHelper::InitializeImage(newImage); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); imageNode->SetName(name.toStdString().c_str()); GetDataStorage()->Add(imageNode, node); // update the b-value widget to remove the modified number of gradients used for extraction this->CleanBValueTableWidget(); this->UpdateBValueTableWidget(0); this->UpdateGradientDetails(); } void QmitkPreprocessingView::MergeDwis() { typedef GradProp::GradientDirectionsContainerType GradientContainerType; mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } mitk::DataNode::Pointer node2 = m_Controls->m_MergeDwiBox->GetSelectedNode(); if (node2.IsNull()) { return; } mitk::Image::Pointer image2 = dynamic_cast(node2->GetData()); if ( image2 == nullptr ) { return; } typedef itk::VectorImage DwiImageType; typedef std::vector< DwiImageType::Pointer > DwiImageContainerType; - typedef std::vector< GradientContainerType::Pointer > GradientListContainerType; + typedef std::vector< GradientContainerType::ConstPointer > GradientListContainerType; DwiImageContainerType imageContainer; GradientListContainerType gradientListContainer; std::vector< double > bValueContainer; QString name = ""; { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); imageContainer.push_back( itkVectorImagePointer ); gradientListContainer.push_back(PropHelper::GetGradientContainer(image)); bValueContainer.push_back(PropHelper::GetReferenceBValue(image)); name += node->GetName().c_str(); } { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image2, itkVectorImagePointer); imageContainer.push_back( itkVectorImagePointer ); gradientListContainer.push_back(PropHelper::GetGradientContainer(image2)); bValueContainer.push_back(PropHelper::GetReferenceBValue(image2)); name += "+"; name += node2->GetName().c_str(); } 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(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( filter->GetOutput() ); PropHelper::SetGradientContainer(newImage, filter->GetOutputGradients()); PropHelper::SetMeasurementFrame(newImage, mf); PropHelper::SetReferenceBValue(newImage, filter->GetB_Value()); PropHelper::InitializeImage( newImage ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); imageNode->SetName(name.toStdString().c_str()); GetDataStorage()->Add(imageNode); } void QmitkPreprocessingView::ExtractB0() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } // call the extraction withou averaging if the check-box is checked if( this->m_Controls->m_CheckExtractAll->isChecked() ) { DoExtractBOWithoutAveraging(); return; } ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); // Extract image using found index typedef itk::B0ImageExtractionImageFilter FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetDirections(PropHelper::GetGradientContainer(image)); filter->Update(); mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( filter->GetOutput() ); mitkImage->SetVolume( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer newNode=mitk::DataNode::New(); newNode->SetData( mitkImage ); newNode->SetProperty( "name", mitk::StringProperty::New(node->GetName() + "_B0")); GetDataStorage()->Add(newNode, node); } void QmitkPreprocessingView::DoExtractBOWithoutAveraging() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } // typedefs typedef itk::B0ImageExtractionToSeparateImageFilter< short, short> FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); // Extract image using found index FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetDirections(PropHelper::GetGradientContainer(image)); filter->Update(); mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( filter->GetOutput() ); mitkImage->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer newNode=mitk::DataNode::New(); newNode->SetData( mitkImage ); newNode->SetProperty( "name", mitk::StringProperty::New(node->GetName() + "_B0_ALL")); GetDataStorage()->Add(newNode, node); /*A reinitialization is needed to access the time channels via the ImageNavigationController The Global-Geometry can not recognize the time channel without a re-init. (for a new selection in datamanger a automatically updated of the Global-Geometry should be done - if it contains the time channel)*/ mitk::RenderingManager::GetInstance()->InitializeViews( newNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } void QmitkPreprocessingView::AverageGradients() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( PropHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) return; mitk::Image::Pointer newDwi = image->Clone(); PropHelper::AverageRedundantGradients(newDwi, m_Controls->m_Blur->value()); PropHelper::InitializeImage(newDwi); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_averaged").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingView.h index 90f462f..30439da 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingView.h @@ -1,159 +1,160 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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. ===================================================================*/ #ifndef _QMITKPREPROCESSINGVIEW_H_INCLUDED #define _QMITKPREPROCESSINGVIEW_H_INCLUDED #include #include #include "ui_QmitkPreprocessingViewControls.h" // st includes #include // itk includes #include #include // mitk includes #include #include "itkDWIVoxelFunctor.h" #include #include #include #include #include typedef short DiffusionPixelType; struct PrpSelListener; /*! * \ingroup org_mitk_gui_qt_preprocessing_internal * * \brief Viewing and modifying diffusion weighted images (gradient reduction, resampling, b-value projection, ...) * */ class QmitkPreprocessingView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { friend struct PrpSelListener; // this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) Q_OBJECT public: static const std::string VIEW_ID; typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientDirectionContainerType; typedef itk::VectorImage< short, 3 > ItkDwiType; typedef itk::Image< unsigned char, 3 > UcharImageType; typedef itk::Image< double, 3 > ItkDoubleImageType; typedef mitk::DiffusionPropertyHelper PropHelper; typedef mitk::GradientDirectionsProperty GradProp; QmitkPreprocessingView(); virtual ~QmitkPreprocessingView(); virtual void CreateQtPartControl(QWidget *parent) override; /// \brief Creation of the connections of main and control widget virtual void CreateConnections(); virtual void Activated() override; virtual void Deactivated() override; virtual void Visible() override; virtual void Hidden() override; /// /// Sets the focus to an internal widget. /// virtual void SetFocus() override; static const int nrconvkernels; protected slots: void AverageGradients(); void ExtractB0(); void MergeDwis(); void DoApplyHeader(); void DoReduceGradientDirections(); void DoShowGradientDirections(); void DoHalfSphereGradientDirections(); void UpdateDwiBValueMapRounder(int i); void DoLengthCorrection(); void DoDwiNormalization(); void DoProjectSignal(); void DoExtractBrainMask(); void DoResampleImage(); void DoCropImage(); void DoUpdateInterpolationGui(int i); void DoRemoveGradient(); void DoExtractGradient(); void DoFlipAxis(); void OnImageSelectionChanged(); void DoFlipGradientDirections(); void DoClearRotationOfGradients(); void DoAlignImages(); + void DoSwapGradientDimensions(); protected: void DoADCFit(); void DoAKCFit(); void DoBiExpFit(); void DoADCAverage(); template < typename TPixel, unsigned int VImageDimension > void TemplatedFlipAxis( itk::Image* itkImage); template < typename TPixel, unsigned int VImageDimension > void TemplatedCropImage( itk::Image* itkImage); template < typename TPixel, unsigned int VImageDimension > void TemplatedResampleImage( itk::Image* itkImage); /** Called by ExtractB0 if check-box activated, extracts all b0 images without averaging */ void DoExtractBOWithoutAveraging(); void UpdateBValueTableWidget(int); void UpdateGradientDetails(); /// \brief called by QmitkAbstractView when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; Ui::QmitkPreprocessingViewControls* m_Controls; void SetDefaultNodeProperties(mitk::DataNode::Pointer node, std::string name); void CallMultishellToSingleShellFilter( itk::DWIVoxelFunctor * functor, mitk::Image::Pointer ImPtr, QString imageName, mitk::DataNode* parent ); void CleanBValueTableWidget(); }; #endif // _QMITKPREPROCESSINGVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui index dbcdfbf..25c96cc 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui @@ -1,1807 +1,1836 @@ QmitkPreprocessingViewControls 0 0 503 1001 0 0 false QmitkPreprocessingViewControls true QCommandLinkButton:disabled { border: none; } QGroupBox { background-color: transparent; } 25 Please Select Input Data 6 6 6 6 Image: QComboBox::AdjustToMinimumContentsLength 0 Gradients 25 Remove or extract gradient volumes 6 6 6 6 6 6 false Remove gradient volume false Extract gradient volume QFrame::NoFrame QFrame::Raised 0 0 0 0 6 + + + + false + + + Retain only the specified number of gradient directions and according image volumes. The retained directions are spread equally over the half sphere using an iterative energy repulsion strategy. + + + + + + + + + Reduce number of gradients + + + <html><head/><body><p>Define the sampling frame the b-Values are rounded with.</p></body></html> Sampling frame: false <html><head/><body><p>Round b-values to nearest multiple of this value (click &quot;Round b-value&quot; to create new image with these values).</p></body></html> QAbstractSpinBox::CorrectToNearestValue 1 10000 10 - + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + x + + + + + + + y + + + + + + + z + + + + + + + false Sometimes the gradient directions are not located on one half sphere. Mirror gradients to half sphere - - + + false Generate pointset displaying the gradient vectors (applied measurement frame). - Show gradients + Flip gradients - - + + false - - Generate pointset displaying the gradient vectors (applied measurement frame). - - - - - - - - Flip gradients + Round b-values - - + + false - Retain only the specified number of gradient directions and according image volumes. The retained directions are spread equally over the half sphere using an iterative energy repulsion strategy. + Generate pointset displaying the gradient vectors (applied measurement frame). - Reduce number of gradients + Show gradients - - - - QFrame::NoFrame + + + + Don't optimize gradients to retain, simply keep first n gradients per b-value. - - QFrame::Plain + + first n - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - x - - - - - - - y - - - - - - - z - - - - - - + + false + + By default, the image matrix is applied to the image gradients. This button removes this additional rotation. + + + + + + + - Round b-values + Clear rotation of gradients - - + + false - By default, the image matrix is applied to the image gradients. This button removes this additional rotation. + Generate pointset displaying the gradient vectors (applied measurement frame). - Clear rotation of gradients + Reorder gradient dimensions - - + + - Don't optimize gradients to retain, simply keep first n gradients per b-value. + New order of gradient vector components (e.g. swap x and y) - first n + y x z 0 Original Gradients Qt::ScrollBarAsNeeded Qt::ScrollBarAsNeeded QAbstractScrollArea::AdjustIgnored QPlainTextEdit::NoWrap true Working Gradients Qt::ScrollBarAsNeeded Qt::ScrollBarAsNeeded QAbstractScrollArea::AdjustIgnored QPlainTextEdit::NoWrap true Qt::Vertical 20 40 0 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAlwaysOff true 100 true false true b-Value Number of gradients Image Values 25 Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. 6 2.000000000000000 0.000100000000000 0.001000000000000 Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Merge radius false Merges selected DWIs of same dimension. If several b-values are present, the resulting image will contain multiple b-shells. Merge selected DWIs false Normalizes the diffusion-weighted image values across all weighted volumes to the given mean and standard deviation. Normalize image values QFrame::NoFrame QFrame::Raised 0 0 0 0 0 false Target b-value 100000 500 Select projection method. QComboBox::AdjustToMinimumContentsLength ADC Average AKC Bi-Exponential false Multiple acquistions of one gradient direction can be averaged. Due to rounding errors, similar gradients often differ in the last decimal positions. The Merge radius allows to average them by taking all directions within a certain radius into account. Average repetitions false Project image values onto one b-shell. Project onto shell QFrame::NoFrame QFrame::Raised 0 0 0 0 0 true New stdev 100000 100 500 Select binary mask image. The mask is used to calculate the old mean and standard deviation. QComboBox::AdjustToMinimumContentsLength true New mean value 100000 100 1000 false Merges selected DWIs of same dimension. If several b-values are present, the resulting image will contain multiple b-shells. Flip axis QFrame::NoFrame QFrame::Raised 0 0 0 0 Y Qt::Horizontal 40 20 X Z Axis: QComboBox::AdjustToMinimumContentsLength Resample image 6 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0.010000000000000 2.000000000000000 0.010000000000000 2.000000000000000 0.010000000000000 2.000000000000000 Sampling factor New image spacing New image size QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Interpolator: Nearest neighbour Linear B-spline Windowed sinc false Resample image QFrame::NoFrame QFrame::Raised 0 0 0 0 0 1 10000 1 10000 1 10000 Crop Image 6 6 6 6 6 x: y: z: Crop Image Header 25 Voxel size 6 6 6 6 4 0.000000000000000 99.989999999999995 4 4 false Apply new header information Direction matrix 6 6 6 6 false 0 0 0 0 IBeamCursor true Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true false false true - - true - 0 + + true + false true true New Row New Row New Row New Column New Column New Column Qt::Horizontal 40 20 0 0 Measurment frame 6 6 6 6 false 0 0 0 0 IBeamCursor true Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true false false true - - true - 0 + + true + false true true New Row New Row New Row New Column New Column New Column Qt::Horizontal 40 20 Qt::Vertical 20 40 Origin 6 6 6 6 4 -999999999.000000000000000 999999999.000000000000000 4 -99999999.000000000000000 999999999.000000000000000 4 -999999999.000000000000000 999999999.000000000000000 Align origins 6 6 6 6 QComboBox::AdjustToMinimumContentsLength Align to Other false If multiple baseline acquisitions are present, the default behaviour is to output an averaged image. Estimate binary brain mask Maximum number of iterations. 10000 10000 Qt::Vertical 20 40 false If multiple baseline acquisitions are present, the default behaviour is to output an averaged image. Extract baseline image Create a 3D+t data set containing all b0 images as timesteps Disable averaging QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
m_SelctedImageComboBox tabWidget m_B_ValueMap_TableWidget m_CreateLengthCorrectedDwi m_B_ValueMap_Rounder_SpinBox m_FlipGradientsButton m_FlipGradBoxX m_FlipGradBoxY m_FlipGradBoxZ m_ShowGradientsButton m_MirrorGradientToHalfSphereButton m_ReduceGradientsButton m_ClearRotationButton m_RemoveGradientButton m_RemoveGradientBox m_ExtractGradientButton m_ExtractGradientBox m_ButtonAverageGradients m_Blur m_ProjectSignalButton m_targetBValueSpinBox m_ProjectionMethodBox m_NormalizeImageValuesButton m_NewMean m_NewStdev m_NormalizationMaskBox m_FlipAxis m_FlipX m_FlipY m_FlipZ m_MergeDwisButton m_MergeDwiBox m_ResampleTypeBox m_ResampleDoubleX m_ResampleDoubleY m_ResampleDoubleZ m_ResampleIntX m_ResampleIntY m_ResampleIntZ m_InterpolatorBox m_ResampleImageButton m_XstartBox m_XendBox m_YstartBox m_YendBox m_ZstartBox m_ZendBox m_CropImageButton m_ModifyHeader m_HeaderOriginX m_HeaderOriginY m_HeaderOriginZ m_HeaderSpacingX m_HeaderSpacingY m_HeaderSpacingZ m_DirectionMatrixTable m_MeasurementFrameTable m_ButtonExtractB0 m_CheckExtractAll m_ExtractBrainMask m_BrainMaskIterationsBox
diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationView.cpp index 0eed5b0..bc23efc 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationView.cpp @@ -1,606 +1,606 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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 "QmitkDiffusionQuantificationView.h" #include "mitkDiffusionImagingConfigure.h" #include "itkTimeProbe.h" #include "itkImage.h" #include "mitkNodePredicateDataType.h" #include "mitkDataNodeObject.h" #include "mitkOdfImage.h" #include #include "mitkImageCast.h" #include "mitkStatusBar.h" #include "itkDiffusionOdfGeneralizedFaImageFilter.h" #include "itkShiftScaleImageFilter.h" #include "itkTensorFractionalAnisotropyImageFilter.h" #include "itkTensorRelativeAnisotropyImageFilter.h" #include "itkTensorDerivedMeasurementsFilter.h" #include "QmitkDataStorageComboBox.h" #include #include "berryIWorkbenchWindow.h" #include "berryISelectionService.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include const std::string QmitkDiffusionQuantificationView::VIEW_ID = "org.mitk.views.diffusionquantification"; QmitkDiffusionQuantificationView::QmitkDiffusionQuantificationView() : QmitkAbstractView(), m_Controls(nullptr) { } QmitkDiffusionQuantificationView::~QmitkDiffusionQuantificationView() { } void QmitkDiffusionQuantificationView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkDiffusionQuantificationViewControls; m_Controls->setupUi(parent); m_Controls->m_BallStickButton->setVisible(false); m_Controls->m_MultiTensorButton->setVisible(false); connect( static_cast(m_Controls->m_GFAButton), SIGNAL(clicked()), this, SLOT(GFA()) ); connect( static_cast(m_Controls->m_FAButton), SIGNAL(clicked()), this, SLOT(FA()) ); connect( static_cast(m_Controls->m_RAButton), SIGNAL(clicked()), this, SLOT(RA()) ); connect( static_cast(m_Controls->m_ADButton), SIGNAL(clicked()), this, SLOT(AD()) ); connect( static_cast(m_Controls->m_RDButton), SIGNAL(clicked()), this, SLOT(RD()) ); connect( static_cast(m_Controls->m_MDButton), SIGNAL(clicked()), this, SLOT(MD()) ); connect( static_cast(m_Controls->m_MdDwiButton), SIGNAL(clicked()), this, SLOT(MD_DWI()) ); connect( static_cast(m_Controls->m_AdcDwiButton), SIGNAL(clicked()), this, SLOT(ADC_DWI()) ); connect( static_cast(m_Controls->m_ClusteringAnisotropy), SIGNAL(clicked()), this, SLOT(ClusterAnisotropy()) ); connect( static_cast(m_Controls->m_BallStickButton), SIGNAL(clicked()), this, SLOT(DoBallStickCalculation()) ); connect( static_cast(m_Controls->m_MultiTensorButton), SIGNAL(clicked()), this, SLOT(DoMultiTensorCalculation()) ); m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isDti = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isOdf = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isSh = mitk::TNodePredicateDataType::New(); mitk::NodePredicateIsDWI::Pointer isDwi = mitk::NodePredicateIsDWI::New(); m_Controls->m_ImageBox->SetPredicate( mitk::NodePredicateOr::New(isSh, mitk::NodePredicateOr::New(isDti, mitk::NodePredicateOr::New(isOdf, isDwi))) ); connect( static_cast(m_Controls->m_ImageBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); } } void QmitkDiffusionQuantificationView::SetFocus() { m_Controls->m_ScaleImageValuesBox->setFocus(); } void QmitkDiffusionQuantificationView::UpdateGui() { bool foundOdfVolume = false; bool foundTensorVolume = false; bool foundDwVolume = false; mitk::DataNode::Pointer selNode = m_Controls->m_ImageBox->GetSelectedNode(); if( selNode.IsNotNull() && (dynamic_cast(selNode->GetData()) || dynamic_cast(selNode->GetData())) ) foundOdfVolume = true; else if( selNode.IsNotNull() && dynamic_cast(selNode->GetData()) ) foundTensorVolume = true; else if( selNode.IsNotNull()) foundDwVolume = true; m_Controls->m_GFAButton->setEnabled(foundOdfVolume); m_Controls->m_FAButton->setEnabled(foundTensorVolume); m_Controls->m_RAButton->setEnabled(foundTensorVolume); m_Controls->m_ADButton->setEnabled(foundTensorVolume); m_Controls->m_RDButton->setEnabled(foundTensorVolume); m_Controls->m_MDButton->setEnabled(foundTensorVolume); m_Controls->m_ClusteringAnisotropy->setEnabled(foundTensorVolume); m_Controls->m_AdcDwiButton->setEnabled(foundDwVolume); m_Controls->m_MdDwiButton->setEnabled(foundDwVolume); m_Controls->m_BallStickButton->setEnabled(foundDwVolume); m_Controls->m_MultiTensorButton->setEnabled(foundDwVolume); } void QmitkDiffusionQuantificationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& ) { UpdateGui(); } void QmitkDiffusionQuantificationView::ADC_DWI() { DoAdcCalculation(true); } void QmitkDiffusionQuantificationView::MD_DWI() { DoAdcCalculation(false); } void QmitkDiffusionQuantificationView::DoBallStickCalculation() { if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) { mitk::DataNode* node = m_Controls->m_ImageBox->GetSelectedNode(); mitk::Image::Pointer image = dynamic_cast(node->GetData()); typedef itk::BallAndSticksImageFilter< short, double > FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); - filter->SetGradientDirections(mitk::DiffusionPropertyHelper::GetGradientContainer(image)); + filter->SetGradientDirections(dynamic_cast(image->GetProperty(mitk::DiffusionPropertyHelper::GetGradientContainerPropertyName().c_str()).GetPointer())->GetGradientDirectionsContainerCopy()); filter->SetB_value(static_cast(mitk::DiffusionPropertyHelper::GetReferenceBValue(image))); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( filter->GetOutput() ); newImage->SetVolume( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_f").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); { FilterType::PeakImageType::Pointer itkImg = filter->GetPeakImage(); mitk::Image::Pointer newImage = mitk::Image::New(); CastToMitkImage(itkImg, newImage); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_Sticks").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } { mitk::Image::Pointer dOut = mitk::GrabItkImageMemory( filter->GetOutDwi().GetPointer() ); mitk::DiffusionPropertyHelper::SetGradientContainer(dOut, mitk::DiffusionPropertyHelper::GetGradientContainer(image) ); mitk::DiffusionPropertyHelper::SetReferenceBValue(dOut, mitk::DiffusionPropertyHelper::GetReferenceBValue(image) ); mitk::DiffusionPropertyHelper::InitializeImage(dOut); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData(dOut); QString name = node->GetName().c_str(); imageNode->SetName((name+"_Estimated-DWI").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } } } void QmitkDiffusionQuantificationView::DoMultiTensorCalculation() { if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) // for all items { mitk::DataNode* node = m_Controls->m_ImageBox->GetSelectedNode(); mitk::Image::Pointer image = dynamic_cast(node->GetData()); typedef itk::MultiTensorImageFilter< short, double > FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); - filter->SetGradientDirections(mitk::DiffusionPropertyHelper::GetGradientContainer(image)); + filter->SetGradientDirections(dynamic_cast(image->GetProperty(mitk::DiffusionPropertyHelper::GetGradientContainerPropertyName().c_str()).GetPointer())->GetGradientDirectionsContainerCopy()); filter->SetB_value(static_cast(mitk::DiffusionPropertyHelper::GetReferenceBValue(image))); filter->Update(); typedef mitk::TensorImage::ItkTensorImageType TensorImageType; for (unsigned int i=0; iGetTensorImages().at(i); mitk::TensorImage::Pointer image = mitk::TensorImage::New(); image->InitializeByItk( tensorImage.GetPointer() ); image->SetVolume( tensorImage->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( image ); QString name = node->GetName().c_str(); name.append("_Tensor"); name.append(boost::lexical_cast(i).c_str()); imageNode->SetName(name.toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } } } void QmitkDiffusionQuantificationView::DoAdcCalculation(bool fit) { if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) { mitk::DataNode* node = m_Controls->m_ImageBox->GetSelectedNode(); mitk::Image::Pointer image = dynamic_cast(node->GetData()); typedef itk::AdcImageFilter< short, double > FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetGradientDirections( mitk::DiffusionPropertyHelper::GetGradientContainer(image) ); filter->SetB_value( static_cast(mitk::DiffusionPropertyHelper::GetReferenceBValue(image)) ); filter->SetFitSignal(fit); filter->Update(); typedef itk::ShiftScaleImageFilter::OutputImageType, itk::AdcImageFilter< short, double >::OutputImageType> ShiftScaleFilterType; ShiftScaleFilterType::Pointer multi = ShiftScaleFilterType::New(); multi->SetShift(0.0); multi->SetScale(m_Controls->m_ScaleImageValuesBox->value()); multi->SetInput(filter->GetOutput()); multi->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( multi->GetOutput() ); newImage->SetVolume( multi->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType( mitk::LookupTable::JET_TRANSPARENT ); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable( lut ); imageNode->SetProperty("LookupTable", lut_prop ); if (fit) imageNode->SetName((name+"_ADC").toStdString().c_str()); else imageNode->SetName((name+"_MD").toStdString().c_str()); mitk::LevelWindow lw; lw.SetLevelWindow(0.0015, 0.003); imageNode->SetProperty( "levelwindow", mitk::LevelWindowProperty::New( lw ) ); GetDataStorage()->Add(imageNode, node); } } void QmitkDiffusionQuantificationView::GFA() { OdfQuantify(0); } void QmitkDiffusionQuantificationView::FA() { TensorQuantify(0); } void QmitkDiffusionQuantificationView::RA() { TensorQuantify(1); } void QmitkDiffusionQuantificationView::AD() { TensorQuantify(2); } void QmitkDiffusionQuantificationView::RD() { TensorQuantify(3); } void QmitkDiffusionQuantificationView::ClusterAnisotropy() { TensorQuantify(4); } void QmitkDiffusionQuantificationView::MD() { TensorQuantify(5); } void QmitkDiffusionQuantificationView::OdfQuantify(int method) { OdfQuantification(method); } void QmitkDiffusionQuantificationView::TensorQuantify(int method) { TensorQuantification(method); } void QmitkDiffusionQuantificationView::OdfQuantification(int method) { QString status; if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) { mitk::DataNode* node = m_Controls->m_ImageBox->GetSelectedNode(); typedef float TOdfPixelType; typedef itk::Vector OdfVectorType; typedef itk::Image OdfVectorImgType; mitk::Image::Pointer vol = dynamic_cast(node->GetData()); OdfVectorImgType::Pointer itkvol; if (dynamic_cast(vol.GetPointer())) itkvol = mitk::convert::GetItkOdfFromShImage(vol); else itkvol = mitk::convert::GetItkOdfFromOdfImage(vol); std::string nodename = node->GetName(); mitk::StatusBar::GetInstance()->DisplayText(status.sprintf("Computing GFA for %s", nodename.c_str()).toLatin1()); typedef itk::DiffusionOdfGeneralizedFaImageFilter GfaFilterType; GfaFilterType::Pointer gfaFilter = GfaFilterType::New(); gfaFilter->SetInput(itkvol); std::string newname; newname.append(nodename); switch(method) { case 0: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_STANDARD); newname.append("GFA"); break; } case 1: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_QUANTILES_HIGH_LOW); newname.append("01"); break; } case 2: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_QUANTILE_HIGH); newname.append("02"); break; } case 3: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_MAX_ODF_VALUE); newname.append("03"); break; } case 4: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_DECONVOLUTION_COEFFS); newname.append("04"); break; } case 5: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_MIN_MAX_NORMALIZED_STANDARD); newname.append("05"); break; } case 6: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_NORMALIZED_ENTROPY); newname.append("06"); break; } case 7: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_NEMATIC_ORDER_PARAMETER); newname.append("07"); break; } case 8: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_QUANTILES_LOW_HIGH); newname.append("08"); break; } case 9: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_QUANTILE_LOW); newname.append("09"); break; } case 10: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_MIN_ODF_VALUE); newname.append("10"); break; } case 11: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_STD_BY_MAX); newname.append("11"); break; } default: { newname.append("0"); gfaFilter->SetComputationMethod(GfaFilterType::GFA_STANDARD); } } gfaFilter->Update(); typedef itk::Image ImgType; ImgType::Pointer img = ImgType::New(); img->SetSpacing( gfaFilter->GetOutput()->GetSpacing() ); // Set the image spacing img->SetOrigin( gfaFilter->GetOutput()->GetOrigin() ); // Set the image origin img->SetDirection( gfaFilter->GetOutput()->GetDirection() ); // Set the image direction img->SetLargestPossibleRegion( gfaFilter->GetOutput()->GetLargestPossibleRegion()); img->SetBufferedRegion( gfaFilter->GetOutput()->GetLargestPossibleRegion() ); img->Allocate(); itk::ImageRegionIterator ot (img, img->GetLargestPossibleRegion() ); ot.GoToBegin(); itk::ImageRegionConstIterator it (gfaFilter->GetOutput(), gfaFilter->GetOutput()->GetLargestPossibleRegion() ); for (it.GoToBegin(); !it.IsAtEnd(); ++it) { GfaFilterType::OutputImageType::PixelType val = it.Get(); ot.Set(val * m_Controls->m_ScaleImageValuesBox->value()); ++ot; } // GFA TO DATATREE mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( img.GetPointer() ); image->SetVolume( img->GetBufferPointer() ); mitk::DataNode::Pointer new_node=mitk::DataNode::New(); new_node->SetData( image ); new_node->SetProperty( "name", mitk::StringProperty::New(newname) ); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType( mitk::LookupTable::JET_TRANSPARENT ); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable( lut ); new_node->SetProperty("LookupTable", lut_prop ); mitk::LevelWindow lw; lw.SetLevelWindow(0.5, 1.0); new_node->SetProperty( "levelwindow", mitk::LevelWindowProperty::New( lw ) ); GetDataStorage()->Add(new_node, node); mitk::StatusBar::GetInstance()->DisplayText("Computation complete."); } this->GetRenderWindowPart()->RequestUpdate(); } void QmitkDiffusionQuantificationView::TensorQuantification(int method) { QString status; if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) { mitk::DataNode* node = m_Controls->m_ImageBox->GetSelectedNode(); typedef mitk::TensorImage::ScalarPixelType TTensorPixelType; typedef mitk::TensorImage::ItkTensorImageType TensorImageType; mitk::Image* vol = static_cast(node->GetData()); TensorImageType::Pointer itkvol = TensorImageType::New(); mitk::CastToItkImage(vol, itkvol); std::string nodename = node->GetName(); mitk::StatusBar::GetInstance()->DisplayText(status.sprintf("Computing FA for %s", nodename.c_str()).toLatin1()); typedef itk::Image< TTensorPixelType, 3 > FAImageType; typedef itk::ShiftScaleImageFilter ShiftScaleFilterType; ShiftScaleFilterType::Pointer multi = ShiftScaleFilterType::New(); multi->SetShift(0.0); multi->SetScale(m_Controls->m_ScaleImageValuesBox->value()); typedef itk::TensorDerivedMeasurementsFilter MeasurementsType; mitk::LevelWindow lw; if(method == 0) //FA { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::FA); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_FA").toStdString(); lw.SetLevelWindow(0.5, 1.0); } else if(method == 1) //RA { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::RA); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_RA").toStdString(); lw.SetLevelWindow(0.015, 0.03); } else if(method == 2) // AD (Axial diffusivity) { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::AD); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_AD").toStdString(); lw.SetLevelWindow(0.0015, 0.003); } else if(method == 3) // RD (Radial diffusivity, (Lambda2+Lambda3)/2 { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::RD); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_RD").toStdString(); lw.SetLevelWindow(0.0015, 0.003); } else if(method == 4) // 1-(Lambda2+Lambda3)/(2*Lambda1) { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::CA); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_CA").toStdString(); lw.SetLevelWindow(0.5, 1.0); } else if(method == 5) // MD (Mean Diffusivity, (Lambda1+Lambda2+Lambda3)/3 ) { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::MD); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_MD").toStdString(); lw.SetLevelWindow(0.0015, 0.003); } multi->Update(); // FA TO DATATREE mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( multi->GetOutput() ); image->SetVolume( multi->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer new_node=mitk::DataNode::New(); new_node->SetData( image ); new_node->SetProperty( "name", mitk::StringProperty::New(nodename) ); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType( mitk::LookupTable::JET_TRANSPARENT ); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable( lut ); new_node->SetProperty("LookupTable", lut_prop ); new_node->SetProperty( "levelwindow", mitk::LevelWindowProperty::New( lw ) ); GetDataStorage()->Add(new_node, node); mitk::StatusBar::GetInstance()->DisplayText("Computation complete."); } this->GetRenderWindowPart()->RequestUpdate(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionView.cpp index 7dbae03..9fe1973 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionView.cpp @@ -1,933 +1,931 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. 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 "QmitkTensorReconstructionView.h" #include "mitkDiffusionImagingConfigure.h" // qt includes #include #include #include #include #include // itk includes #include "itkTimeProbe.h" //#include "itkTensor.h" // mitk includes #include "mitkProgressBar.h" #include "mitkStatusBar.h" #include "mitkNodePredicateDataType.h" #include "QmitkDataStorageComboBox.h" #include "mitkTeemDiffusionTensor3DReconstructionImageFilter.h" #include "itkDiffusionTensor3DReconstructionImageFilter.h" #include "itkTensorImageToDiffusionImageFilter.h" #include "itkPointShell.h" #include "itkVector.h" #include "itkB0ImageExtractionImageFilter.h" #include "itkTensorReconstructionWithEigenvalueCorrectionFilter.h" #include "mitkImageCast.h" #include "mitkImageAccessByItk.h" #include #include #include "mitkProperties.h" #include "mitkDataNodeObject.h" #include "mitkOdfNormalizationMethodProperty.h" #include "mitkOdfScaleByProperty.h" #include "mitkLookupTableProperty.h" #include "mitkLookupTable.h" #include "mitkImageStatisticsHolder.h" #include #include #include #include #include #include #include #include const std::string QmitkTensorReconstructionView::VIEW_ID = "org.mitk.views.tensorreconstruction"; typedef mitk::TensorImage::ScalarPixelType TTensorPixelType; typedef mitk::TensorImage::PixelType TensorPixelType; typedef mitk::TensorImage::ItkTensorImageType TensorImageType; using namespace berry; QmitkTensorReconstructionView::QmitkTensorReconstructionView() : QmitkAbstractView(), m_Controls(nullptr) { } QmitkTensorReconstructionView::~QmitkTensorReconstructionView() { } void QmitkTensorReconstructionView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkTensorReconstructionViewControls; m_Controls->setupUi(parent); this->CreateConnections(); Advanced1CheckboxClicked(); } } void QmitkTensorReconstructionView::SetFocus() { m_Controls->m_Advanced1->setFocus(); } void QmitkTensorReconstructionView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_StartReconstruction), SIGNAL(clicked()), this, SLOT(Reconstruct()) ); connect( (QObject*)(m_Controls->m_Advanced1), SIGNAL(clicked()), this, SLOT(Advanced1CheckboxClicked()) ); connect( (QObject*)(m_Controls->m_TensorsToDWIButton), SIGNAL(clicked()), this, SLOT(TensorsToDWI()) ); connect( (QObject*)(m_Controls->m_TensorsToOdfButton), SIGNAL(clicked()), this, SLOT(TensorsToOdf()) ); connect( (QObject*)(m_Controls->m_ResidualButton), SIGNAL(clicked()), this, SLOT(ResidualCalculation()) ); connect( (QObject*)(m_Controls->m_PerSliceView), SIGNAL(pointSelected(int, int)), this, SLOT(ResidualClicked(int, int)) ); connect( (QObject*)(m_Controls->m_TensorReconstructionThreshold), SIGNAL(valueChanged(int)), this, SLOT(PreviewThreshold(int)) ); m_Controls->m_ResidualTab->setVisible(false); m_Controls->m_PercentagesOfOutliers->setVisible(false); m_Controls->m_DwiBox->SetDataStorage(this->GetDataStorage()); mitk::NodePredicateIsDWI::Pointer isDwi = mitk::NodePredicateIsDWI::New(); m_Controls->m_DwiBox->SetPredicate( isDwi ); connect( (QObject*)(m_Controls->m_DwiBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); m_Controls->m_OdfBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isDti = mitk::TNodePredicateDataType::New(); m_Controls->m_OdfBox->SetPredicate( isDti ); connect( (QObject*)(m_Controls->m_OdfBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); m_Controls->m_DtiBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_DtiBox->SetPredicate( isDti ); connect( (QObject*)(m_Controls->m_DtiBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); m_Controls->m_ResBox1->SetDataStorage(this->GetDataStorage()); m_Controls->m_ResBox1->SetPredicate( isDwi ); connect( (QObject*)(m_Controls->m_ResBox1), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); m_Controls->m_ResBox2->SetDataStorage(this->GetDataStorage()); m_Controls->m_ResBox2->SetPredicate( isDti ); connect( (QObject*)(m_Controls->m_ResBox2), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); } } void QmitkTensorReconstructionView::ResidualClicked(int slice, int volume) { mitk::Image* diffImage; mitk::DataNode::Pointer correctNode; mitk::BaseGeometry* geometry; if (m_Controls->m_ResBox1->GetSelectedNode().IsNotNull()) { diffImage = static_cast(m_Controls->m_ResBox1->GetSelectedNode()->GetData()); geometry = m_Controls->m_ResBox1->GetSelectedNode()->GetData()->GetGeometry(); // Remember the node whose display index must be updated correctNode = mitk::DataNode::New(); correctNode = m_Controls->m_ResBox1->GetSelectedNode(); - GradientDirectionContainerType::Pointer dirs = mitk::DiffusionPropertyHelper::GetGradientContainer(diffImage); + GradientDirectionContainerType::ConstPointer dirs = mitk::DiffusionPropertyHelper::GetGradientContainer(diffImage); for(itk::SizeValueType i=0; iSize() && i<=(itk::SizeValueType)volume; i++) { GradientDirectionType grad = dirs->ElementAt(i); // check if image is b0 weighted if(fabs(grad[0]) < 0.001 && fabs(grad[1]) < 0.001 && fabs(grad[2]) < 0.001) { volume++; } } QString pos = "Volume: "; pos.append(QString::number(volume)); pos.append(", Slice: "); pos.append(QString::number(slice)); m_Controls->m_PositionLabel->setText(pos); if(correctNode) { int oldDisplayVal; correctNode->GetIntProperty("DisplayChannel", oldDisplayVal); QString oldVal = QString::number(oldDisplayVal); QString newVal = QString::number(volume); correctNode->SetIntProperty("DisplayChannel",volume); correctNode->SetSelected(true); this->FirePropertyChanged("DisplayChannel", oldVal, newVal); correctNode->UpdateOutputInformation(); mitk::Point3D p3 = this->GetRenderWindowPart()->GetSelectedPosition(); itk::Index<3> ix; geometry->WorldToIndex(p3, ix); // ix[2] = slice; mitk::Vector3D vec; vec[0] = ix[0]; vec[1] = ix[1]; vec[2] = slice; mitk::Vector3D v3New; geometry->IndexToWorld(vec, v3New); mitk::Point3D origin = geometry->GetOrigin(); mitk::Point3D p3New; p3New[0] = v3New[0] + origin[0]; p3New[1] = v3New[1] + origin[1]; p3New[2] = v3New[2] + origin[2]; this->GetRenderWindowPart()->SetSelectedPosition(p3New); this->GetRenderWindowPart()->RequestUpdate(); } } } void QmitkTensorReconstructionView::Advanced1CheckboxClicked() { bool check = m_Controls-> m_Advanced1->isChecked(); m_Controls->frame->setVisible(check); } void QmitkTensorReconstructionView::Activated() { } void QmitkTensorReconstructionView::Deactivated() { // Get all current nodes mitk::DataStorage::SetOfObjects::ConstPointer objects = this->GetDataStorage()->GetAll(); mitk::DataStorage::SetOfObjects::const_iterator itemiter( objects->begin() ); mitk::DataStorage::SetOfObjects::const_iterator itemiterend( objects->end() ); while ( itemiter != itemiterend ) // for all items { mitk::DataNode::Pointer node = *itemiter; if (node.IsNull()) continue; // only look at interesting types if( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(dynamic_cast(node->GetData()))) { if (this->GetDataStorage()->GetNamedDerivedNode("ThresholdOverlay", *itemiter)) { node = this->GetDataStorage()->GetNamedDerivedNode("ThresholdOverlay", *itemiter); this->GetDataStorage()->Remove(node); } } itemiter++; } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkTensorReconstructionView::Visible() { } void QmitkTensorReconstructionView::Hidden() { } void QmitkTensorReconstructionView::ResidualCalculation() { // Extract dwi and dti from current selection // In case of multiple selections, take the first one, since taking all combinations is not meaningful mitk::DataStorage::SetOfObjects::Pointer set = mitk::DataStorage::SetOfObjects::New(); mitk::Image::Pointer diffImage = mitk::Image::New(); TensorImageType::Pointer tensorImage; std::string nodename; if(m_Controls->m_ResBox1->GetSelectedNode()) { diffImage = static_cast(m_Controls->m_ResBox1->GetSelectedNode()->GetData()); } else return; if(m_Controls->m_ResBox2->GetSelectedNode().IsNotNull()) { mitk::TensorImage* mitkVol; mitkVol = static_cast(m_Controls->m_ResBox2->GetSelectedNode()->GetData()); mitk::CastToItkImage(mitkVol, tensorImage); m_Controls->m_ResBox2->GetSelectedNode()->GetStringProperty("name", nodename); } else return; - typedef itk::TensorImageToDiffusionImageFilter< - TTensorPixelType, DiffusionPixelType > FilterType; + typedef itk::TensorImageToDiffusionImageFilter FilterType; - GradientDirectionContainerType* gradients - = mitk::DiffusionPropertyHelper::GetGradientContainer(diffImage); + GradientDirectionContainerType::ConstPointer gradients = mitk::DiffusionPropertyHelper::GetGradientContainer(diffImage); // Find the min and the max values from a baseline image mitk::ImageStatisticsHolder *stats = diffImage->GetStatistics(); //Initialize filter that calculates the modeled diffusion weighted signals FilterType::Pointer filter = FilterType::New(); filter->SetInput( tensorImage ); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(diffImage)); filter->SetGradientList(gradients); filter->SetMin(stats->GetScalarValueMin()); filter->SetMax(stats->GetScalarValueMax()); filter->Update(); mitk::Image::Pointer image = mitk::GrabItkImageMemory( filter->GetOutput() ); mitk::DiffusionPropertyHelper::CopyProperties(diffImage, image, true); mitk::DiffusionPropertyHelper::SetGradientContainer(image, gradients); mitk::DiffusionPropertyHelper::InitializeImage( image ); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); mitk::ImageVtkMapper2D::SetDefaultProperties(node); QString newname; newname = newname.append(nodename.c_str()); newname = newname.append("_Estimated DWI"); node->SetName(newname.toLatin1()); GetDataStorage()->Add(node, m_Controls->m_ResBox2->GetSelectedNode()); BValueMapType map = mitk::DiffusionPropertyHelper::GetBValueMap(image); std::vector< unsigned int > b0Indices = map[0]; typedef itk::ResidualImageFilter ResidualImageFilterType; ITKDiffusionImageType::Pointer itkVectorImagePointer = ITKDiffusionImageType::New(); mitk::CastToItkImage(diffImage, itkVectorImagePointer); ITKDiffusionImageType::Pointer itkSecondVectorImagePointer = ITKDiffusionImageType::New(); mitk::CastToItkImage(image, itkSecondVectorImagePointer); ResidualImageFilterType::Pointer residualFilter = ResidualImageFilterType::New(); residualFilter->SetInput( itkVectorImagePointer ); residualFilter->SetSecondDiffusionImage( itkSecondVectorImagePointer ); residualFilter->SetGradients(gradients); residualFilter->SetB0Index(b0Indices[0]); residualFilter->SetB0Threshold(30); residualFilter->Update(); itk::Image::Pointer residualImage = itk::Image::New(); residualImage = residualFilter->GetOutput(); mitk::Image::Pointer mitkResImg = mitk::Image::New(); mitk::CastToMitkImage(residualImage, mitkResImg); stats = mitkResImg->GetStatistics(); float min = stats->GetScalarValueMin(); float max = stats->GetScalarValueMax(); mitk::LookupTableProperty::Pointer lutProp = mitk::LookupTableProperty::New(); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(min, max); // If you don't want to use the whole color range, you can use // SetValueRange, SetHueRange, and SetSaturationRange lookupTable->Build(); vtkSmartPointer reversedlookupTable = vtkSmartPointer::New(); reversedlookupTable->SetTableRange(min+1, max); reversedlookupTable->Build(); for(int i=0; i<256; i++) { double* rgba = reversedlookupTable->GetTableValue(255-i); lookupTable->SetTableValue(i, rgba[0], rgba[1], rgba[2], rgba[3]); } lut->SetVtkLookupTable(lookupTable); lutProp->SetLookupTable(lut); // Create lookuptable mitk::DataNode::Pointer resNode=mitk::DataNode::New(); resNode->SetData( mitkResImg ); resNode->SetName("Residuals"); resNode->SetProperty("LookupTable", lutProp); bool b; resNode->GetBoolProperty("use color", b); resNode->SetBoolProperty("use color", false); GetDataStorage()->Add(resNode, m_Controls->m_ResBox2->GetSelectedNode()); this->GetRenderWindowPart()->RequestUpdate(); // Draw Graph std::vector means = residualFilter->GetMeans(); std::vector q1s = residualFilter->GetQ1(); std::vector q3s = residualFilter->GetQ3(); std::vector percentagesOfOUtliers = residualFilter->GetPercentagesOfOutliers(); m_Controls->m_ResidualAnalysis->SetMeans(means); m_Controls->m_ResidualAnalysis->SetQ1(q1s); m_Controls->m_ResidualAnalysis->SetQ3(q3s); m_Controls->m_ResidualAnalysis->SetPercentagesOfOutliers(percentagesOfOUtliers); if(m_Controls->m_PercentagesOfOutliers->isChecked()) { m_Controls->m_ResidualAnalysis->DrawPercentagesOfOutliers(); } else { m_Controls->m_ResidualAnalysis->DrawMeans(); } // Draw Graph for volumes per slice in the QGraphicsView std::vector< std::vector > outliersPerSlice = residualFilter->GetOutliersPerSlice(); int xSize = outliersPerSlice.size(); if(xSize == 0) { return; } int ySize = outliersPerSlice[0].size(); // Find maximum in outliersPerSlice double maxOutlier= 0.0; for(int i=0; imaxOutlier) { maxOutlier = outliersPerSlice[i][j]; } } } // Create some QImage QImage qImage(xSize, ySize, QImage::Format_RGB32); QImage legend(1, 256, QImage::Format_RGB32); QRgb value; vtkSmartPointer lookup = vtkSmartPointer::New(); lookup->SetTableRange(0.0, maxOutlier); lookup->Build(); reversedlookupTable->SetTableRange(0, maxOutlier); reversedlookupTable->Build(); for(int i=0; i<256; i++) { double* rgba = reversedlookupTable->GetTableValue(255-i); lookup->SetTableValue(i, rgba[0], rgba[1], rgba[2], rgba[3]); } // Fill qImage for(int i=0; iMapValue(out); int r, g, b; r = _rgba[0]; g = _rgba[1]; b = _rgba[2]; value = qRgb(r, g, b); qImage.setPixel(i,j,value); } } for(int i=0; i<256; i++) { double* rgba = lookup->GetTableValue(i); int r, g, b; r = rgba[0]*255; g = rgba[1]*255; b = rgba[2]*255; value = qRgb(r, g, b); legend.setPixel(0,255-i,value); } QString upper = QString::number(maxOutlier, 'g', 3); upper.append(" %"); QString lower = QString::number(0.0); lower.append(" %"); m_Controls->m_UpperLabel->setText(upper); m_Controls->m_LowerLabel->setText(lower); QPixmap pixmap(QPixmap::fromImage(qImage)); QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap); item->setTransform(QTransform::fromScale(10.0, 3.0), true); QPixmap pixmap2(QPixmap::fromImage(legend)); QGraphicsPixmapItem *item2 = new QGraphicsPixmapItem(pixmap2); item2->setTransform(QTransform::fromScale(20.0, 1.0), true); m_Controls->m_PerSliceView->SetResidualPixmapItem(item); QGraphicsScene* scene = new QGraphicsScene; QGraphicsScene* scene2 = new QGraphicsScene; scene->addItem(item); scene2->addItem(item2); m_Controls->m_PerSliceView->setScene(scene); m_Controls->m_LegendView->setScene(scene2); m_Controls->m_PerSliceView->show(); m_Controls->m_PerSliceView->repaint(); m_Controls->m_LegendView->setHorizontalScrollBarPolicy ( Qt::ScrollBarAlwaysOff ); m_Controls->m_LegendView->setVerticalScrollBarPolicy ( Qt::ScrollBarAlwaysOff ); m_Controls->m_LegendView->show(); m_Controls->m_LegendView->repaint(); } void QmitkTensorReconstructionView::Reconstruct() { int method = m_Controls->m_ReconctructionMethodBox->currentIndex(); switch (method) { case 0: ItkTensorReconstruction(); break; case 1: TensorReconstructionWithCorr(); break; default: ItkTensorReconstruction(); } } void QmitkTensorReconstructionView::TensorReconstructionWithCorr() { try { if ( m_Controls->m_DwiBox->GetSelectedNode().IsNotNull() ) // for all items { mitk::Image* vols = static_cast(m_Controls->m_DwiBox->GetSelectedNode()->GetData()); std::string nodename = m_Controls->m_DwiBox->GetSelectedNode()->GetName(); typedef itk::TensorReconstructionWithEigenvalueCorrectionFilter< DiffusionPixelType, TTensorPixelType > ReconstructionFilter; float b0Threshold = m_Controls->m_TensorReconstructionThreshold->value(); mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientContainerCopy = mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::New(); for(auto it = mitk::DiffusionPropertyHelper::GetGradientContainer(vols)->Begin(); it != mitk::DiffusionPropertyHelper::GetGradientContainer(vols)->End(); it++) gradientContainerCopy->push_back(it.Value()); ITKDiffusionImageType::Pointer itkVectorImagePointer = ITKDiffusionImageType::New(); mitk::CastToItkImage(vols, itkVectorImagePointer); ReconstructionFilter::Pointer reconFilter = ReconstructionFilter::New(); reconFilter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(vols)); - reconFilter->SetGradientImage( gradientContainerCopy, itkVectorImagePointer); + reconFilter->SetGradientImage( mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::ConstPointer(gradientContainerCopy), itkVectorImagePointer); reconFilter->SetB0Threshold(b0Threshold); reconFilter->Update(); typedef mitk::TensorImage::ItkTensorImageType TensorImageType; TensorImageType::Pointer outputTensorImg = reconFilter->GetOutput(); typedef itk::ImageRegionIterator TensorImageIteratorType; TensorImageIteratorType tensorIt(outputTensorImg, outputTensorImg->GetRequestedRegion()); tensorIt.GoToBegin(); int negatives = 0; while(!tensorIt.IsAtEnd()) { typedef mitk::TensorImage::PixelType TensorType; TensorType tensor = tensorIt.Get(); TensorType::EigenValuesArrayType ev; tensor.ComputeEigenValues(ev); for(unsigned int i=0; iInitializeByItk( outputTensorImg.GetPointer() ); image->SetVolume( outputTensorImg->GetBufferPointer() ); mitk::DiffusionPropertyHelper::CopyDICOMProperties(vols, image); mitk::DataNode::Pointer node=mitk::DataNode::New(); node->SetData( image ); node->SetName(nodename+"_EigenvalueCorrected_DT"); GetDataStorage()->Add(node, m_Controls->m_DwiBox->GetSelectedNode()); } this->GetRenderWindowPart()->RequestUpdate(); } catch (itk::ExceptionObject &ex) { MITK_INFO << ex ; QMessageBox::information(0, "Reconstruction not possible:", ex.GetDescription()); } } void QmitkTensorReconstructionView::ItkTensorReconstruction() { try { if ( m_Controls->m_DwiBox->GetSelectedNode().IsNotNull() ) // for all items { mitk::Image* vols = static_cast(m_Controls->m_DwiBox->GetSelectedNode()->GetData()); std::string nodename = m_Controls->m_DwiBox->GetSelectedNode()->GetName(); typedef itk::DiffusionTensor3DReconstructionImageFilter TensorReconstructionImageFilterType; TensorReconstructionImageFilterType::Pointer tensorReconstructionFilter = TensorReconstructionImageFilterType::New(); GradientDirectionContainerType::Pointer gradientContainerCopy = GradientDirectionContainerType::New(); for(GradientDirectionContainerType::ConstIterator it = mitk::DiffusionPropertyHelper::GetGradientContainer(vols)->Begin(); it != mitk::DiffusionPropertyHelper::GetGradientContainer(vols)->End(); it++) { gradientContainerCopy->push_back(it.Value()); } ITKDiffusionImageType::Pointer itkVectorImagePointer = ITKDiffusionImageType::New(); mitk::CastToItkImage(vols, itkVectorImagePointer); tensorReconstructionFilter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(vols)); tensorReconstructionFilter->SetGradientImage( gradientContainerCopy, itkVectorImagePointer ); tensorReconstructionFilter->SetThreshold( m_Controls->m_TensorReconstructionThreshold->value() ); tensorReconstructionFilter->Update(); // TENSORS TO DATATREE mitk::TensorImage::Pointer image = mitk::TensorImage::New(); typedef mitk::TensorImage::ItkTensorImageType TensorImageType; TensorImageType::Pointer tensorImage; tensorImage = tensorReconstructionFilter->GetOutput(); // Check the tensor for negative eigenvalues if(m_Controls->m_CheckNegativeEigenvalues->isChecked()) { typedef itk::ImageRegionIterator TensorImageIteratorType; TensorImageIteratorType tensorIt(tensorImage, tensorImage->GetRequestedRegion()); tensorIt.GoToBegin(); while(!tensorIt.IsAtEnd()) { typedef mitk::TensorImage::PixelType TensorType; //typedef itk::Tensor TensorType2; TensorType tensor = tensorIt.Get(); TensorType::EigenValuesArrayType ev; tensor.ComputeEigenValues(ev); for(unsigned int i=0; iSetDirection( itkVectorImagePointer->GetDirection() ); image->InitializeByItk( tensorImage.GetPointer() ); image->SetVolume( tensorReconstructionFilter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer node=mitk::DataNode::New(); mitk::DiffusionPropertyHelper::CopyDICOMProperties(vols, image); node->SetData( image ); node->SetName(nodename+"_LinearLeastSquares_DT"); GetDataStorage()->Add(node, m_Controls->m_DwiBox->GetSelectedNode()); } this->GetRenderWindowPart()->RequestUpdate(); } catch (itk::ExceptionObject &ex) { MITK_INFO << ex ; QMessageBox::information(0, "Reconstruction not possible:", ex.GetDescription()); return; } } void QmitkTensorReconstructionView::TensorsToDWI() { DoTensorsToDWI(); } void QmitkTensorReconstructionView::TensorsToOdf() { if (m_Controls->m_OdfBox->GetSelectedNode().IsNotNull()) { mitk::DataNode::Pointer tensorImageNode = m_Controls->m_OdfBox->GetSelectedNode(); typedef mitk::TensorImage::ScalarPixelType TTensorPixelType; typedef mitk::TensorImage::ItkTensorImageType TensorImageType; TensorImageType::Pointer itkvol = TensorImageType::New(); mitk::CastToItkImage(dynamic_cast(tensorImageNode->GetData()), itkvol); typedef itk::TensorImageToOdfImageFilter< TTensorPixelType, TTensorPixelType > FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkvol ); filter->Update(); typedef itk::Vector OutputPixelType; typedef itk::Image OutputImageType; mitk::OdfImage::Pointer image = mitk::OdfImage::New(); OutputImageType::Pointer outimg = filter->GetOutput(); image->InitializeByItk( outimg.GetPointer() ); image->SetVolume( outimg->GetBufferPointer() ); mitk::DataNode::Pointer node = mitk::DataNode::New(); mitk::DiffusionPropertyHelper::CopyDICOMProperties(tensorImageNode->GetData(), image); node->SetData( image ); node->SetName(tensorImageNode->GetName()+"_Odf"); GetDataStorage()->Add(node, tensorImageNode); } } void QmitkTensorReconstructionView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& ) { UpdateGui(); } void QmitkTensorReconstructionView::UpdateGui() { m_Controls->m_StartReconstruction->setEnabled(m_Controls->m_DwiBox->GetSelectedNode().IsNotNull()); m_Controls->m_TensorsToDWIButton->setEnabled(m_Controls->m_DtiBox->GetSelectedNode().IsNotNull()); m_Controls->m_TensorsToOdfButton->setEnabled(m_Controls->m_OdfBox->GetSelectedNode().IsNotNull()); m_Controls->m_ResidualButton->setEnabled(m_Controls->m_ResBox1->GetSelectedNode().IsNotNull() && m_Controls->m_ResBox2->GetSelectedNode().IsNotNull()); m_Controls->m_PercentagesOfOutliers->setEnabled(m_Controls->m_ResBox1->GetSelectedNode().IsNotNull() && m_Controls->m_ResBox2->GetSelectedNode().IsNotNull()); m_Controls->m_PerSliceView->setEnabled(m_Controls->m_ResBox1->GetSelectedNode().IsNotNull() && m_Controls->m_ResBox2->GetSelectedNode().IsNotNull()); } template itk::VectorContainer >::Pointer QmitkTensorReconstructionView::MakeGradientList() { itk::VectorContainer >::Pointer retval = itk::VectorContainer >::New(); vnl_matrix_fixed* U = itk::PointShell >::DistributePointShell(); for(int i=0; i v; v[0] = U->get(0,i); v[1] = U->get(1,i); v[2] = U->get(2,i); retval->push_back(v); } // Add 0 vector for B0 vnl_vector_fixed v; v.fill(0.0); retval->push_back(v); return retval; } void QmitkTensorReconstructionView::DoTensorsToDWI() { try { if (m_Controls->m_DtiBox->GetSelectedNode().IsNotNull()) { std::string nodename = m_Controls->m_DtiBox->GetSelectedNode()->GetName(); mitk::TensorImage* vol = static_cast(m_Controls->m_DtiBox->GetSelectedNode()->GetData()); typedef mitk::TensorImage::ScalarPixelType TTensorPixelType; typedef mitk::TensorImage::ItkTensorImageType TensorImageType; TensorImageType::Pointer itkvol = TensorImageType::New(); mitk::CastToItkImage(vol, itkvol); typedef itk::TensorImageToDiffusionImageFilter< TTensorPixelType, DiffusionPixelType > FilterType; - FilterType::GradientListPointerType gradientList = FilterType::GradientListType::New(); + FilterType::GradientListPointerType gradientList; switch(m_Controls->m_TensorsToDWINumDirsSelect->currentIndex()) { case 0: gradientList = MakeGradientList<12>(); break; case 1: gradientList = MakeGradientList<42>(); break; case 2: gradientList = MakeGradientList<92>(); break; case 3: gradientList = MakeGradientList<162>(); break; case 4: gradientList = MakeGradientList<252>(); break; case 5: gradientList = MakeGradientList<362>(); break; case 6: gradientList = MakeGradientList<492>(); break; case 7: gradientList = MakeGradientList<642>(); break; case 8: gradientList = MakeGradientList<812>(); break; case 9: gradientList = MakeGradientList<1002>(); break; default: gradientList = MakeGradientList<92>(); } double bVal = m_Controls->m_TensorsToDWIBValueEdit->text().toDouble(); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkvol ); filter->SetBValue(bVal); filter->SetGradientList(gradientList); filter->Update(); mitk::Image::Pointer image = mitk::GrabItkImageMemory( filter->GetOutput() ); mitk::DiffusionPropertyHelper::SetGradientContainer(image, gradientList); mitk::DiffusionPropertyHelper::SetReferenceBValue(image, bVal); mitk::DiffusionPropertyHelper::InitializeImage( image ); mitk::DataNode::Pointer node=mitk::DataNode::New(); mitk::DiffusionPropertyHelper::CopyDICOMProperties(vol, image); node->SetData( image ); mitk::ImageVtkMapper2D::SetDefaultProperties(node); node->SetName(nodename+"_DWI"); GetDataStorage()->Add(node, m_Controls->m_DtiBox->GetSelectedNode()); } this->GetRenderWindowPart()->RequestUpdate(); } catch (itk::ExceptionObject &ex) { MITK_INFO << ex ; QMessageBox::information(0, "DWI estimation failed:", ex.GetDescription()); return ; } } void QmitkTensorReconstructionView::PreviewThreshold(int threshold) { if (m_Controls->m_DwiBox->GetSelectedNode().IsNotNull()) { mitk::Image* vols = static_cast(m_Controls->m_DwiBox->GetSelectedNode()->GetData()); ITKDiffusionImageType::Pointer itkVectorImagePointer = ITKDiffusionImageType::New(); mitk::CastToItkImage(vols, itkVectorImagePointer); // Extract b0 image typedef itk::B0ImageExtractionImageFilter FilterType; FilterType::Pointer filterB0 = FilterType::New(); filterB0->SetInput(itkVectorImagePointer); filterB0->SetDirections(mitk::DiffusionPropertyHelper::GetGradientContainer(vols)); filterB0->Update(); mitk::Image::Pointer mitkImage = mitk::Image::New(); typedef itk::Image ImageType; typedef itk::Image SegmentationType; typedef itk::BinaryThresholdImageFilter ThresholdFilterType; // apply threshold ThresholdFilterType::Pointer filterThreshold = ThresholdFilterType::New(); filterThreshold->SetInput(filterB0->GetOutput()); filterThreshold->SetLowerThreshold(threshold); filterThreshold->SetInsideValue(0); filterThreshold->SetOutsideValue(1); // mark cut off values red filterThreshold->Update(); mitkImage->InitializeByItk( filterThreshold->GetOutput() ); mitkImage->SetVolume( filterThreshold->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer node; if (this->GetDataStorage()->GetNamedDerivedNode("ThresholdOverlay", m_Controls->m_DwiBox->GetSelectedNode())) { node = this->GetDataStorage()->GetNamedDerivedNode("ThresholdOverlay", m_Controls->m_DwiBox->GetSelectedNode()); } else { // create a new node, to show thresholded values node = mitk::DataNode::New(); GetDataStorage()->Add( node, m_Controls->m_DwiBox->GetSelectedNode() ); node->SetProperty( "name", mitk::StringProperty::New("ThresholdOverlay")); node->SetBoolProperty("helper object", true); } node->SetData( mitkImage ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } }