diff --git a/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.cpp b/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.cpp index 119db6a..d2c8b59 100644 --- a/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.cpp +++ b/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.cpp @@ -1,615 +1,624 @@ /*=================================================================== 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) { // 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::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) { 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); 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); 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); 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); 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(mitk::Image* source, mitk::Image* target, bool ignore_original_gradients) +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) { return dynamic_cast(image->GetProperty(ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer())->GetGradientDirectionsContainer(); } mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer 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::Pointer g_cont) { image->GetPropertyList()->ReplaceProperty(ORIGINALGRADIENTCONTAINERPROPERTYNAME.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 db0d97d..7504226 100644 --- a/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.h +++ b/Modules/DiffusionCore/IODataStructures/Properties/mitkDiffusionPropertyHelper.h @@ -1,126 +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. ===================================================================*/ #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::Image* source, mitk::Image* target, bool ignore_original_gradients=false); + 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 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::Pointer 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 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/mitkDiffusionFunctionCollection.cpp b/Modules/DiffusionCore/mitkDiffusionFunctionCollection.cpp index 932aafb..a5dbca7 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 #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::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; } void mitk::gradients::WriteBvalsBvecs(std::string bvals_file, std::string bvecs_file, GradientDirectionContainerType::Pointer 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 ) { 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/DiffusionIO/ReaderWriter/mitkFiberBundleDicomReader.cpp b/Modules/DiffusionIO/ReaderWriter/mitkFiberBundleDicomReader.cpp index 3661330..c5e2fb5 100644 --- a/Modules/DiffusionIO/ReaderWriter/mitkFiberBundleDicomReader.cpp +++ b/Modules/DiffusionIO/ReaderWriter/mitkFiberBundleDicomReader.cpp @@ -1,180 +1,166 @@ /*=================================================================== 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 "mitkFiberBundleDicomReader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkDiffusionIOMimeTypes.h" #include #include #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/dcmtract/trctractographyresults.h" #include "dcmtk/dcmtract/trctrack.h" mitk::FiberBundleDicomReader::FiberBundleDicomReader() : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_DICOM_MIMETYPE_NAME(), "DICOM Fiber Bundle Reader" ) { m_ServiceReg = this->RegisterService(); } mitk::FiberBundleDicomReader::FiberBundleDicomReader(const FiberBundleDicomReader &other) :mitk::AbstractFileReader(other) { } mitk::FiberBundleDicomReader * mitk::FiberBundleDicomReader::Clone() const { return new FiberBundleDicomReader(*this); } std::vector > mitk::FiberBundleDicomReader::Read() { std::vector > output_fibs; try { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, nullptr ); setlocale(LC_ALL, locale.c_str()); std::string filename = this->GetInputLocation(); OFCondition result; TrcTractographyResults *trc = nullptr; result = TrcTractographyResults::loadFile(filename.c_str(), trc); if (result.bad()) mitkThrow() << "Unable to load tractography dicom file: " << result.text(); OFString val = "-"; trc->getPatient().getPatientName(val); MITK_INFO << "Patient Name: " << val; val = "-"; trc->getStudy().getStudyInstanceUID(val); MITK_INFO << "Study : " << val; val = "-"; trc->getSeries().getSeriesInstanceUID(val); MITK_INFO << "Series : " << val; val = "-"; trc->getSOPCommon().getSOPInstanceUID(val); MITK_INFO << "Instance : " << val; val = "-"; MITK_INFO << "-------------------------------------------------------------------------"; size_t numTrackSets = trc->getNumberOfTrackSets(); OFVector& sets = trc->getTrackSets(); for (size_t ts = 0; ts < numTrackSets; ts++) { size_t numTracks = sets[ts]->getNumberOfTracks(); MITK_INFO << " Track Set #" << ts << ": " << numTracks << " Tracks, " << sets[ts]->getNumberOfTrackSetStatistics() << " Track Set Statistics, " << sets[ts]->getNumberOfTrackStatistics() << " Track Statistics, " << sets[ts]->getNumberOfMeasurements() << " Measurements "; vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (size_t t = 0; t < numTracks; t++) { vtkSmartPointer container = vtkSmartPointer::New(); TrcTrack* track = sets[ts]->getTracks()[t]; const Float32* vals = nullptr; size_t numPoints = track->getTrackData(vals); for (size_t v = 0; v < numPoints; ++v) { vtkIdType id = vtkNewPoints->InsertNextPoint(vals[v*3],vals[v*3+1],vals[v*3+2]); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); fiberPolyData->SetPoints(vtkNewPoints); fiberPolyData->SetLines(vtkNewCells); - -// // transform polydata from RAS (MRtrix) to LPS (MITK) -// mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); -// vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New(); -// matrix->Identity(); -// matrix->SetElement(0,0,-matrix->GetElement(0,0)); -// matrix->SetElement(1,1,-matrix->GetElement(1,1)); -// geometry->SetIndexToWorldTransformByVtkMatrix(matrix); - -// vtkSmartPointer transformFilter = vtkSmartPointer::New(); -// transformFilter->SetInputData(fiberPolyData); -// transformFilter->SetTransform(geometry->GetVtkTransform()); -// transformFilter->Update(); - FiberBundle::Pointer fib = FiberBundle::New(fiberPolyData); - CodeSequenceMacro algoCode = sets[ts]->getTrackingAlgorithmIdentification().at(0)->getAlgorithmNameCode(); - val = "-"; algoCode.getCodeValue(val); - fib->GetPropertyList()->SetStringProperty("DICOM.algo_code.value",val.c_str()); - val = "-"; algoCode.getCodeMeaning(val); - fib->GetPropertyList()->SetStringProperty("DICOM.algo_code.meaning",val.c_str()); + CodeSequenceMacro algoCode = sets[ts]->getTrackingAlgorithmIdentification().at(0)->getAlgorithmFamilyCode(); + val = "0"; algoCode.getCodeValue(val); + fib->GetPropertyList()->SetStringProperty("DICOM.algo_family_code.value",val.c_str()); + val = "0"; algoCode.getCodeMeaning(val); + fib->GetPropertyList()->SetStringProperty("DICOM.algo_family_code.meaning",val.c_str()); CodeSequenceMacro modelCode = sets[ts]->getDiffusionModelCode(); - val = "-"; modelCode.getCodeValue(val); + val = "0"; modelCode.getCodeValue(val); fib->GetPropertyList()->SetStringProperty("DICOM.model_code.value",val.c_str()); - val = "-"; modelCode.getCodeMeaning(val); + val = "0"; modelCode.getCodeMeaning(val); fib->GetPropertyList()->SetStringProperty("DICOM.model_code.meaning",val.c_str()); CodeWithModifiers anatomy = sets[ts]->getTrackSetAnatomy(); - val = "-"; anatomy.getCodeValue(val); + val = "0"; anatomy.getCodeValue(val); fib->GetPropertyList()->SetStringProperty("DICOM.anatomy.value",val.c_str()); - val = "-"; anatomy.getCodeMeaning(val); + val = "0"; anatomy.getCodeMeaning(val); fib->GetPropertyList()->SetStringProperty("DICOM.anatomy.meaning",val.c_str()); - val = "-"; trc->getPatient().getPatientID(val); + val = "0"; trc->getPatient().getPatientID(val); fib->GetPropertyList()->SetStringProperty("DICOM.patient_id",val.c_str()); - val = "-"; trc->getPatient().getPatientName(val); + val = "0"; trc->getPatient().getPatientName(val); fib->GetPropertyList()->SetStringProperty("DICOM.patient_name",val.c_str()); - val = "-"; trc->getStudy().getStudyInstanceUID(val); + val = "0"; trc->getStudy().getStudyInstanceUID(val); fib->GetPropertyList()->SetStringProperty("DICOM.study_instance_uid",val.c_str()); - val = "-"; trc->getSeries().getSeriesInstanceUID(val); + val = "0"; trc->getSeries().getSeriesInstanceUID(val); fib->GetPropertyList()->SetStringProperty("DICOM.series_instance_uid",val.c_str()); - val = "-"; trc->getSOPCommon().getSOPInstanceUID(val); + val = "0"; trc->getSOPCommon().getSOPInstanceUID(val); fib->GetPropertyList()->SetStringProperty("DICOM.sop_instance_uid",val.c_str()); - val = "-"; trc->getSOPCommon().getSOPClassUID(val); + val = "0"; trc->getSOPCommon().getSOPClassUID(val); fib->GetPropertyList()->SetStringProperty("DICOM.sop_class_uid",val.c_str()); - val = "-"; trc->getFrameOfReference().getFrameOfReferenceUID(val); + val = "0"; trc->getFrameOfReference().getFrameOfReferenceUID(val); fib->GetPropertyList()->SetStringProperty("DICOM.frame_of_reference_uid",val.c_str()); output_fibs.push_back(fib.GetPointer()); MITK_INFO << "Fiber bundle read"; } delete trc; setlocale(LC_ALL, currLocale.c_str()); return output_fibs; } catch(...) { throw; } return output_fibs; } diff --git a/Modules/DiffusionIO/ReaderWriter/mitkFiberBundleDicomWriter.cpp b/Modules/DiffusionIO/ReaderWriter/mitkFiberBundleDicomWriter.cpp index 6dbeeaf..2915431 100644 --- a/Modules/DiffusionIO/ReaderWriter/mitkFiberBundleDicomWriter.cpp +++ b/Modules/DiffusionIO/ReaderWriter/mitkFiberBundleDicomWriter.cpp @@ -1,191 +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 "mitkFiberBundleDicomWriter.h" #include #include #include #include #include #include #include #include #include "mitkDiffusionIOMimeTypes.h" #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/dcmtract/trctractographyresults.h" mitk::FiberBundleDicomWriter::FiberBundleDicomWriter() : mitk::AbstractFileWriter(mitk::FiberBundle::GetStaticNameOfClass(), mitk::DiffusionIOMimeTypes::FIBERBUNDLE_DICOM_MIMETYPE_NAME(), "DICOM Fiber Bundle Writer") { RegisterService(); } mitk::FiberBundleDicomWriter::FiberBundleDicomWriter(const mitk::FiberBundleDicomWriter & other) :mitk::AbstractFileWriter(other) {} mitk::FiberBundleDicomWriter::~FiberBundleDicomWriter() {} mitk::FiberBundleDicomWriter * mitk::FiberBundleDicomWriter::Clone() const { return new mitk::FiberBundleDicomWriter(*this); } void mitk::FiberBundleDicomWriter::Write() { try { mitk::FiberBundle::ConstPointer fib = dynamic_cast(this->GetInput()); vtkPolyData* poly = fib->GetFiberPolyData(); mitk::PropertyList* p_list = fib->GetPropertyList(); std::string patient_id = ""; if (!p_list->GetStringProperty("DICOM.patient_id", patient_id)) - patient_id = "-"; + patient_id = "0"; std::string patient_name = ""; if (!p_list->GetStringProperty("DICOM.patient_name", patient_name)) - patient_name = "-"; + patient_name = "0"; std::string study_instance_uid = ""; if (!p_list->GetStringProperty("DICOM.study_instance_uid", study_instance_uid)) - study_instance_uid = "-"; + study_instance_uid = "0"; std::string series_instance_uid = ""; if (!p_list->GetStringProperty("DICOM.series_instance_uid", series_instance_uid)) - series_instance_uid = "-"; + series_instance_uid = "0"; std::string sop_instance_uid = ""; if (!p_list->GetStringProperty("DICOM.sop_instance_uid", sop_instance_uid)) - sop_instance_uid = "-"; + sop_instance_uid = "0"; + std::string sop_class_uid = ""; + if (!p_list->GetStringProperty("DICOM.sop_class_uid", sop_instance_uid)) + sop_class_uid = "0"; std::string frame_of_reference_uid = ""; if (!p_list->GetStringProperty("DICOM.frame_of_reference_uid", frame_of_reference_uid)) - frame_of_reference_uid = "-"; + frame_of_reference_uid = "0"; std::string algo_code_value = ""; - if (!p_list->GetStringProperty("DICOM.algo_code.value", algo_code_value)) - algo_code_value = "-"; + if (!p_list->GetStringProperty("DICOM.algo_family_code.value", algo_code_value)) + algo_code_value = "0"; std::string algo_code_meaning = ""; - if (!p_list->GetStringProperty("DICOM.algo_code.meaning", algo_code_meaning)) - algo_code_meaning = "-"; + if (!p_list->GetStringProperty("DICOM.algo_family_code.meaning", algo_code_meaning)) + algo_code_meaning = "0"; std::string model_code_value = ""; if (!p_list->GetStringProperty("DICOM.model_code.value", model_code_value)) - model_code_value = "-"; + model_code_value = "0"; std::string model_code_meaning = ""; if (!p_list->GetStringProperty("DICOM.model_code.meaning", model_code_meaning)) - model_code_meaning = "-"; + model_code_meaning = "0"; std::string anatomy_value = ""; if (!p_list->GetStringProperty("DICOM.anatomy.value", anatomy_value)) - anatomy_value = "-"; + anatomy_value = "0"; std::string anatomy_meaning = ""; if (!p_list->GetStringProperty("DICOM.anatomy.meaning", anatomy_meaning)) - anatomy_meaning = "-"; + anatomy_meaning = "0"; const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, nullptr ); setlocale(LC_ALL, locale.c_str()); // Instance Number, Label, Description, Creator's Name ContentIdentificationMacro id("1", "TRACTOGRAM", "Tractogram processed with MITK Diffusion", "MIC@DKFZ"); // Manufacturer, model name, serial number, software version(s) IODEnhGeneralEquipmentModule::EquipmentInfo equipment("MIC@DKFZ", "dcmtract library", "0815", OFFIS_DCMTK_VERSION_STRING); IODReferences refs; // We need at least one image reference this Tractography Results object is based on. // We provide: Patient ID, Study Instance UID, Series Instance UID, SOP Instance UID, SOP Class UID IODImageReference* ref = new IODImageReference(patient_id.c_str(), study_instance_uid.c_str(), series_instance_uid.c_str(), sop_instance_uid.c_str(), UID_MRImageStorage); refs.add(ref); std::time_t t = std::time(nullptr); char date_buffer[20]; std::strftime(date_buffer, sizeof(date_buffer), "%Y%m%d", std::gmtime(&t)); char time_buffer[20]; std::strftime(time_buffer, sizeof(time_buffer), "%H%M%S", std::gmtime(&t)); OFString contentDate(date_buffer); OFString contentTime(time_buffer); OFString val = "-"; TrcTractographyResults *trc = nullptr; TrcTractographyResults::create(id, contentDate, contentTime, equipment, refs, trc); trc->getStudy().setStudyInstanceUID(study_instance_uid.c_str()); trc->getSeries().setSeriesInstanceUID(series_instance_uid.c_str()); trc->getSOPCommon().setSOPInstanceUID(sop_instance_uid.c_str()); trc->getSeries().getSeriesInstanceUID(val); + trc->getPatient().setPatientID(patient_id.c_str()); + trc->getPatient().setPatientName(patient_name.c_str()); + trc->getSeries().setSeriesDescription("Tractogram processed with MITK Diffusion"); + + // Frame of Reference is required; could be the same as from related MR series + trc->getFrameOfReference().setFrameOfReferenceUID(frame_of_reference_uid.c_str()); + + DcmItem item; + item.putAndInsertOFStringArray(DCM_PatientID, patient_id); + item.putAndInsertOFStringArray(DCM_StudyInstanceUID, study_instance_uid); + item.putAndInsertOFStringArray(DCM_SeriesInstanceUID, series_instance_uid); + item.putAndInsertOFStringArray(DCM_SOPClassUID, sop_class_uid); + item.putAndInsertOFStringArray(DCM_SOPInstanceUID, sop_instance_uid); + IODReference* ref2 = new IODReference(); + ref2->readFromItem(item); + trc->getReferencedInstances().add(ref2); + + // GET STUFF FROM DICOM FILE (disbled since file probably not available) +// trc->importHierarchy("/media/neher/Rumpelkammer/Demo/Tumor/KOPF_UNTERSUCHUNG_20170419_164344_842000/T1_FL2D_TRA_5MM_0013/WISSING_MARISKA.MR.KOPF_UNTERSUCHUNG.0013.0022.2017.07.31.14.09.57.918625.254331277.IMA", +// true, +// true, +// true, +// true); + +// trc->getReferencedInstances().addFromFiles({"/media/neher/Rumpelkammer/Demo/Tumor/KOPF_UNTERSUCHUNG_20170419_164344_842000/T1_FL2D_TRA_5MM_0013/WISSING_MARISKA.MR.KOPF_UNTERSUCHUNG.0013.0022.2017.07.31.14.09.57.918625.254331277.IMA"}); + // Create track set CodeWithModifiers anatomy(""); anatomy.set(anatomy_value.c_str(), "SRT", anatomy_meaning.c_str()); // Every CodeSequenceMacro has: Code Value, Coding Scheme Designator, Code Meaning CodeSequenceMacro diffusionModel(model_code_value.c_str(), "DCM", model_code_meaning.c_str()); -// CodeSequenceMacro algorithmId(algo_code_value.c_str(), "DCM", algo_code_meaning.c_str()); AlgorithmIdentificationMacro algorithmId; - algorithmId.setAlgorithmName(algo_code_meaning); + algorithmId.getAlgorithmFamilyCode().set(algo_code_value, "DCM", algo_code_meaning); + algorithmId.setAlgorithmName("-"); + algorithmId.setAlgorithmVersion("-"); + algorithmId.setAlgorithmParameters("-"); + algorithmId.setAlgorithmSource("-"); TrcTrackSet *set = nullptr; trc->addTrackSet("TRACTOGRAM", "Tractogram processed with MITK Diffusion", anatomy, diffusionModel, algorithmId, set); // Create trackset Uint16 cieLabColor[3]; // color the whole track with this color; we use some blue cieLabColor[0] = 30000; // L cieLabColor[1] = 0 ; // a cieLabColor[2] = 0 ; // b std::vector< Float32* > tracts; for (unsigned int i=0; iGetNumFibers(); i++) { vtkCell* cell = poly->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); Float32* pointData = new Float32[numPoints*3]; for(int i=0; iGetPoint(i); pointData[i*3] = p[0]; pointData[i*3+1] = p[1]; pointData[i*3+2] = p[2]; } tracts.push_back(pointData); TrcTrack* track = nullptr; set->addTrack(pointData, numPoints, cieLabColor, 1 /* numColors */, track); } - // Frame of Reference is required; could be the same as from related MR series - trc->getFrameOfReference().setFrameOfReferenceUID(frame_of_reference_uid.c_str()); - - // Set some optional data - trc->getPatient().setPatientID(patient_id.c_str()); - trc->getPatient().setPatientName(patient_name.c_str()); - trc->getSeries().setSeriesDescription("Tractogram processed with MITK Diffusion"); - // Save file OFCondition result = trc->saveFile(this->GetOutputLocation().c_str()); delete trc; if (result.bad()) mitkThrow() << "Unable to save tractography as DICOM file: " << result.text(); for (Float32* tract : tracts) delete [] tract; setlocale(LC_ALL, currLocale.c_str()); MITK_INFO << "DICOM Fiber bundle written to " << this->GetOutputLocation(); } catch(...) { throw; } } diff --git a/Modules/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp b/Modules/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp index 7ac296a..fb642db 100644 --- a/Modules/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp +++ b/Modules/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp @@ -1,515 +1,515 @@ /*=================================================================== 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 "itkGibbsTrackingFilter.h" // MITK #include #include #include #include #include //#include #include #include // ITK #include #include #include // MISC #include // #include #include #include #include #include namespace itk{ template< class ItkOdfImageType > GibbsTrackingFilter< ItkOdfImageType >::GibbsTrackingFilter(): m_StartTemperature(0.1), m_EndTemperature(0.001), m_Iterations(1e9), m_CurrentIteration(0.0), m_CurrentStep(0), m_ParticleWeight(0), m_ParticleWidth(0), m_ParticleLength(0), m_ConnectionPotential(10), m_InexBalance(0), m_ParticlePotential(0.2), m_MinFiberLength(10), m_AbortTracking(false), m_NumAcceptedFibers(0), m_BuildFibers(false), m_ProposalAcceptance(0), m_CurvatureThreshold(0.7), m_DuplicateImage(true), m_NumParticles(0), m_NumConnections(0), m_RandomSeed(-1), m_LoadParameterFile(""), m_LutPath(""), m_IsInValidState(true) { } template< class ItkOdfImageType > GibbsTrackingFilter< ItkOdfImageType >::~GibbsTrackingFilter() { } // fill output fiber bundle datastructure template< class ItkOdfImageType > typename GibbsTrackingFilter< ItkOdfImageType >::FiberPolyDataType GibbsTrackingFilter< ItkOdfImageType >::GetFiberBundle() { if (!m_AbortTracking) { m_BuildFibers = true; while (m_BuildFibers){} } return m_FiberPolyData; } template< class ItkOdfImageType > void GibbsTrackingFilter< ItkOdfImageType > ::EstimateParticleWeight() { MITK_INFO << "GibbsTrackingFilter: estimating particle weight"; float minSpacing; if(m_OdfImage->GetSpacing()[0]GetSpacing()[1] && m_OdfImage->GetSpacing()[0]GetSpacing()[2]) minSpacing = m_OdfImage->GetSpacing()[0]; else if (m_OdfImage->GetSpacing()[1] < m_OdfImage->GetSpacing()[2]) minSpacing = m_OdfImage->GetSpacing()[1]; else minSpacing = m_OdfImage->GetSpacing()[2]; float m_ParticleLength = 1.5*minSpacing; float m_ParticleWidth = 0.5*minSpacing; // seed random generators Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); if (m_RandomSeed>-1) randGen->SetSeed(m_RandomSeed); else randGen->SetSeed(); // instantiate all necessary components SphereInterpolator* interpolator = new SphereInterpolator(m_LutPath); // handle lookup table not found cases if( !interpolator->IsInValidState() ) { m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; mitkThrow() << "Unable to load lookup tables."; } ParticleGrid* particleGrid = new ParticleGrid(m_MaskImage, m_ParticleLength, m_ParticleGridCellCapacity); GibbsEnergyComputer* encomp = new GibbsEnergyComputer(m_OdfImage, m_MaskImage, particleGrid, interpolator, randGen); // EnergyComputer* encomp = new EnergyComputer(m_OdfImage, m_MaskImage, particleGrid, interpolator, randGen); MetropolisHastingsSampler* sampler = new MetropolisHastingsSampler(particleGrid, encomp, randGen, m_CurvatureThreshold); float alpha = log(m_EndTemperature/m_StartTemperature); m_ParticleWeight = 0.01; int ppv = 0; // main loop int neededParts = 3000; while (ppvSetParameters(m_ParticleWeight,m_ParticleWidth,m_ConnectionPotential*m_ParticleLength*m_ParticleLength,m_CurvatureThreshold,m_InexBalance,m_ParticlePotential); for( int step = 0; step < 10; step++ ) { // update temperatur for simulated annealing process float temperature = m_StartTemperature * exp(alpha*(((1.0)*step)/((1.0)*10))); sampler->SetTemperature(temperature); for (unsigned long i=0; i<10000; i++) sampler->MakeProposal(); } ppv = particleGrid->m_NumParticles; particleGrid->ResetGrid(); } delete sampler; delete encomp; delete particleGrid; delete interpolator; MITK_INFO << "GibbsTrackingFilter: finished estimating particle weight"; } // perform global tracking template< class ItkOdfImageType > void GibbsTrackingFilter< ItkOdfImageType >::GenerateData() { TimeProbe preClock; preClock.Start(); // check if input is Odf or tensor image and generate Odf if necessary if (m_OdfImage.IsNull() && m_TensorImage.IsNotNull()) { TensorImageToOdfImageFilter::Pointer filter = TensorImageToOdfImageFilter::New(); filter->SetInput( m_TensorImage ); filter->Update(); m_OdfImage = filter->GetOutput(); } else if (m_DuplicateImage) // generate local working copy of Odf image (if not disabled) { typedef itk::ImageDuplicator< ItkOdfImageType > DuplicateFilterType; typename DuplicateFilterType::Pointer duplicator = DuplicateFilterType::New(); duplicator->SetInputImage( m_OdfImage ); duplicator->Update(); m_OdfImage = duplicator->GetOutput(); } // perform mean subtraction on odfs typedef ImageRegionIterator< ItkOdfImageType > InputIteratorType; InputIteratorType it(m_OdfImage, m_OdfImage->GetLargestPossibleRegion() ); it.GoToBegin(); while (!it.IsAtEnd()) { itk::OrientationDistributionFunction odf(it.Get().GetDataPointer()); float mean = odf.GetMeanValue(); odf -= mean; it.Set(odf.GetDataPointer()); ++it; } // check if mask image is given if it needs resampling PrepareMaskImage(); // load parameter file LoadParameters(); // prepare parameters float minSpacing; if(m_OdfImage->GetSpacing()[0]GetSpacing()[1] && m_OdfImage->GetSpacing()[0]GetSpacing()[2]) minSpacing = m_OdfImage->GetSpacing()[0]; else if (m_OdfImage->GetSpacing()[1] < m_OdfImage->GetSpacing()[2]) minSpacing = m_OdfImage->GetSpacing()[1]; else minSpacing = m_OdfImage->GetSpacing()[2]; if(m_ParticleLength == 0) m_ParticleLength = 1.5*minSpacing; if(m_ParticleWidth == 0) m_ParticleWidth = 0.5*minSpacing; if(m_ParticleWeight == 0) EstimateParticleWeight(); float alpha = log(m_EndTemperature/m_StartTemperature); if (m_CurvatureThreshold < mitk::eps) m_CurvatureThreshold = 0; // seed random generators Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); if (m_RandomSeed>-1) randGen->SetSeed(m_RandomSeed); else randGen->SetSeed(); // load sphere interpolator to evaluate the ODFs SphereInterpolator* interpolator = new SphereInterpolator(m_LutPath); // handle lookup table not found cases if( !interpolator->IsInValidState() ) { m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; mitkThrow() << "Unable to load lookup tables."; } // initialize the actual tracking components (ParticleGrid, Metropolis Hastings Sampler and Energy Computer) ParticleGrid* particleGrid; GibbsEnergyComputer* encomp; MetropolisHastingsSampler* sampler; try{ particleGrid = new ParticleGrid(m_MaskImage, m_ParticleLength, m_ParticleGridCellCapacity); encomp = new GibbsEnergyComputer(m_OdfImage, m_MaskImage, particleGrid, interpolator, randGen); encomp->SetParameters(m_ParticleWeight,m_ParticleWidth,m_ConnectionPotential*m_ParticleLength*m_ParticleLength,m_CurvatureThreshold,m_InexBalance,m_ParticlePotential); sampler = new MetropolisHastingsSampler(particleGrid, encomp, randGen, m_CurvatureThreshold); } catch(...) { MITK_ERROR << "Particle grid allocation failed. Not enough memory? Try to increase the particle length."; m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; return; } MITK_INFO << "----------------------------------------"; MITK_INFO << "Iterations: " << m_Iterations; MITK_INFO << "Particle length: " << m_ParticleLength; MITK_INFO << "Particle width: " << m_ParticleWidth; MITK_INFO << "Particle weight: " << m_ParticleWeight; MITK_INFO << "Start temperature: " << m_StartTemperature; MITK_INFO << "End temperature: " << m_EndTemperature; MITK_INFO << "In/Ex balance: " << m_InexBalance; MITK_INFO << "Min. fiber length: " << m_MinFiberLength; MITK_INFO << "Curvature threshold: " << m_CurvatureThreshold; MITK_INFO << "Random seed: " << m_RandomSeed; MITK_INFO << "----------------------------------------"; // main loop preClock.Stop(); TimeProbe clock; clock.Start(); m_NumAcceptedFibers = 0; m_CurrentIteration = 0; bool just_built_fibers = false; boost::progress_display disp(m_Iterations); if (!m_AbortTracking) while (m_CurrentIterationSetTemperature(temperature); sampler->MakeProposal(); m_ProposalAcceptance = (float)sampler->GetNumAcceptedProposals()/m_CurrentIteration; m_NumParticles = particleGrid->m_NumParticles; m_NumConnections = particleGrid->m_NumConnections; if (m_AbortTracking) break; if (m_BuildFibers) { FiberBuilder fiberBuilder(particleGrid, m_MaskImage); m_FiberPolyData = fiberBuilder.iterate(m_MinFiberLength); m_NumAcceptedFibers = m_FiberPolyData->GetNumberOfLines(); m_BuildFibers = false; just_built_fibers = true; } } if (!just_built_fibers) { FiberBuilder fiberBuilder(particleGrid, m_MaskImage); m_FiberPolyData = fiberBuilder.iterate(m_MinFiberLength); m_NumAcceptedFibers = m_FiberPolyData->GetNumberOfLines(); } clock.Stop(); delete sampler; delete encomp; delete interpolator; delete particleGrid; m_AbortTracking = true; m_BuildFibers = false; int h = clock.GetTotal()/3600; int m = ((int)clock.GetTotal()%3600)/60; int s = (int)clock.GetTotal()%60; MITK_INFO << "GibbsTrackingFilter: finished gibbs tracking in " << h << "h, " << m << "m and " << s << "s"; m = (int)preClock.GetTotal()/60; s = (int)preClock.GetTotal()%60; MITK_INFO << "GibbsTrackingFilter: preparation of the data took " << m << "m and " << s << "s"; MITK_INFO << "GibbsTrackingFilter: " << m_NumAcceptedFibers << " fibers accepted"; // sampler->PrintProposalTimes(); SaveParameters(); } template< class ItkOdfImageType > void GibbsTrackingFilter< ItkOdfImageType >::PrepareMaskImage() { if(m_MaskImage.IsNull()) { MITK_INFO << "GibbsTrackingFilter: generating default mask image"; m_MaskImage = ItkFloatImageType::New(); m_MaskImage->SetSpacing( m_OdfImage->GetSpacing() ); m_MaskImage->SetOrigin( m_OdfImage->GetOrigin() ); m_MaskImage->SetDirection( m_OdfImage->GetDirection() ); m_MaskImage->SetRegions( m_OdfImage->GetLargestPossibleRegion() ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1.0); } else if ( m_MaskImage->GetLargestPossibleRegion().GetSize()[0]!=m_OdfImage->GetLargestPossibleRegion().GetSize()[0] || m_MaskImage->GetLargestPossibleRegion().GetSize()[1]!=m_OdfImage->GetLargestPossibleRegion().GetSize()[1] || m_MaskImage->GetLargestPossibleRegion().GetSize()[2]!=m_OdfImage->GetLargestPossibleRegion().GetSize()[2] || m_MaskImage->GetSpacing()[0]!=m_OdfImage->GetSpacing()[0] || m_MaskImage->GetSpacing()[1]!=m_OdfImage->GetSpacing()[1] || m_MaskImage->GetSpacing()[2]!=m_OdfImage->GetSpacing()[2] ) { MITK_INFO << "GibbsTrackingFilter: resampling mask image"; typedef itk::ResampleImageFilter< ItkFloatImageType, ItkFloatImageType, float > ResamplerType; ResamplerType::Pointer resampler = ResamplerType::New(); resampler->SetOutputSpacing( m_OdfImage->GetSpacing() ); resampler->SetOutputOrigin( m_OdfImage->GetOrigin() ); resampler->SetOutputDirection( m_OdfImage->GetDirection() ); resampler->SetSize( m_OdfImage->GetLargestPossibleRegion().GetSize() ); resampler->SetInput( m_MaskImage ); resampler->SetDefaultPixelValue(0.0); resampler->Update(); m_MaskImage = resampler->GetOutput(); MITK_INFO << "GibbsTrackingFilter: resampling finished"; } } // load tracking paramters from xml file (.gtp) template< class ItkOdfImageType > bool GibbsTrackingFilter< ItkOdfImageType >::LoadParameters() { m_AbortTracking = true; try { if( m_LoadParameterFile.length()==0 ) { m_AbortTracking = false; return true; } MITK_INFO << "GibbsTrackingFilter: loading parameter file " << m_LoadParameterFile; TiXmlDocument doc( m_LoadParameterFile ); doc.LoadFile(); TiXmlHandle hDoc(&doc); TiXmlElement* pElem; TiXmlHandle hRoot(nullptr); pElem = hDoc.FirstChildElement().Element(); hRoot = TiXmlHandle(pElem); pElem = hRoot.FirstChildElement("parameter_set").Element(); std::string iterations(pElem->Attribute("iterations")); m_Iterations = boost::lexical_cast(iterations); std::string particleLength(pElem->Attribute("particle_length")); m_ParticleLength = boost::lexical_cast(particleLength); std::string particleWidth(pElem->Attribute("particle_width")); m_ParticleWidth = boost::lexical_cast(particleWidth); std::string partWeight(pElem->Attribute("particle_weight")); m_ParticleWeight = boost::lexical_cast(partWeight); std::string startTemp(pElem->Attribute("temp_start")); m_StartTemperature = boost::lexical_cast(startTemp); std::string endTemp(pElem->Attribute("temp_end")); m_EndTemperature = boost::lexical_cast(endTemp); std::string inExBalance(pElem->Attribute("inexbalance")); m_InexBalance = boost::lexical_cast(inExBalance); std::string fiberLength(pElem->Attribute("fiber_length")); m_MinFiberLength = boost::lexical_cast(fiberLength); std::string curvThres(pElem->Attribute("curvature_threshold")); m_CurvatureThreshold = cos(boost::lexical_cast(curvThres)*itk::Math::pi/180); m_AbortTracking = false; MITK_INFO << "GibbsTrackingFilter: parameter file loaded successfully"; return true; } catch(...) { MITK_INFO << "GibbsTrackingFilter: could not load parameter file"; return false; } } // save current tracking paramters to xml file (.gtp) template< class ItkOdfImageType > bool GibbsTrackingFilter< ItkOdfImageType >::SaveParameters() { try { if( m_SaveParameterFile.length()==0 ) { MITK_INFO << "GibbsTrackingFilter: no filename specified to save parameters"; return true; } MITK_INFO << "GibbsTrackingFilter: saving parameter file " << m_SaveParameterFile; TiXmlDocument documentXML; TiXmlDeclaration* declXML = new TiXmlDeclaration( "1.0", "", "" ); documentXML.LinkEndChild( declXML ); TiXmlElement* mainXML = new TiXmlElement("global_tracking_parameter_file"); mainXML->SetAttribute("file_version", "0.1"); documentXML.LinkEndChild(mainXML); TiXmlElement* paramXML = new TiXmlElement("parameter_set"); paramXML->SetAttribute("iterations", boost::lexical_cast(m_Iterations)); paramXML->SetAttribute("particle_length", boost::lexical_cast(m_ParticleLength)); paramXML->SetAttribute("particle_width", boost::lexical_cast(m_ParticleWidth)); paramXML->SetAttribute("particle_weight", boost::lexical_cast(m_ParticleWeight)); paramXML->SetAttribute("temp_start", boost::lexical_cast(m_StartTemperature)); paramXML->SetAttribute("temp_end", boost::lexical_cast(m_EndTemperature)); paramXML->SetAttribute("inexbalance", boost::lexical_cast(m_InexBalance)); paramXML->SetAttribute("fiber_length", boost::lexical_cast(m_MinFiberLength)); paramXML->SetAttribute("curvature_threshold", boost::lexical_cast(m_CurvatureThreshold)); mainXML->LinkEndChild(paramXML); if(!boost::algorithm::ends_with(m_SaveParameterFile, ".gtp")) m_SaveParameterFile.append(".gtp"); documentXML.SaveFile( m_SaveParameterFile ); MITK_INFO << "GibbsTrackingFilter: parameter file saved successfully"; return true; } catch(...) { MITK_INFO << "GibbsTrackingFilter: could not save parameter file"; return false; } } template< class ItkOdfImageType > void GibbsTrackingFilter< ItkOdfImageType >::SetDicomProperties(mitk::FiberBundle::Pointer fib) { std::string model_code_value = "-"; std::string model_code_meaning = "-"; std::string algo_code_value = "sup181_ee03"; std::string algo_code_meaning = "Global"; fib->SetProperty("DICOM.anatomy.value", mitk::StringProperty::New("T-A0095")); fib->SetProperty("DICOM.anatomy.meaning", mitk::StringProperty::New("White matter of brain and spinal cord")); - fib->SetProperty("DICOM.algo_code.value", mitk::StringProperty::New(algo_code_value)); - fib->SetProperty("DICOM.algo_code.meaning", mitk::StringProperty::New(algo_code_meaning)); + fib->SetProperty("DICOM.algo_family_code.value", mitk::StringProperty::New(algo_code_value)); + fib->SetProperty("DICOM.algo_family_code.meaning", mitk::StringProperty::New(algo_code_meaning)); fib->SetProperty("DICOM.model_code.value", mitk::StringProperty::New(model_code_value)); fib->SetProperty("DICOM.model_code.meaning", mitk::StringProperty::New(model_code_meaning)); } } diff --git a/Modules/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp b/Modules/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp index ec64f08..6bd9546 100644 --- a/Modules/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp +++ b/Modules/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp @@ -1,980 +1,999 @@ /*=================================================================== 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 "itkStreamlineTrackingFilter.h" #include #include #include #include "itkPointShell.h" #include #include #include #include #include #include #include #include namespace itk { StreamlineTrackingFilter ::StreamlineTrackingFilter() : m_PauseTracking(false) , m_AbortTracking(false) , m_BuildFibersFinished(false) , m_BuildFibersReady(0) , m_FiberPolyData(nullptr) , m_Points(nullptr) , m_Cells(nullptr) , m_StoppingRegions(nullptr) , m_TargetRegions(nullptr) , m_SeedImage(nullptr) , m_MaskImage(nullptr) , m_ExclusionRegions(nullptr) , m_OutputProbabilityMap(nullptr) , m_Verbose(true) , m_DemoMode(false) , m_CurrentTracts(0) , m_Progress(0) , m_StopTracking(false) , m_TrackingPriorHandler(nullptr) { this->SetNumberOfRequiredInputs(0); } std::string StreamlineTrackingFilter::GetStatusText() { std::string status = "Seedpoints processed: " + boost::lexical_cast(m_Progress) + "/" + boost::lexical_cast(m_SeedPoints.size()); if (m_SeedPoints.size()>0) status += " (" + boost::lexical_cast(100*m_Progress/m_SeedPoints.size()) + "%)"; if (m_Parameters->m_MaxNumFibers>0) status += "\nFibers accepted: " + boost::lexical_cast(m_CurrentTracts) + "/" + boost::lexical_cast(m_Parameters->m_MaxNumFibers); else status += "\nFibers accepted: " + boost::lexical_cast(m_CurrentTracts); return status; } void StreamlineTrackingFilter::BeforeTracking() { m_StopTracking = false; m_TrackingHandler->SetParameters(m_Parameters); m_TrackingHandler->InitForTracking(); m_FiberPolyData = PolyDataType::New(); m_Points = vtkSmartPointer< vtkPoints >::New(); m_Cells = vtkSmartPointer< vtkCellArray >::New(); if (m_TrackingPriorHandler!=nullptr) { m_TrackingPriorHandler->InitForTracking(); } m_PolyDataContainer.clear(); for (unsigned int i=0; iGetNumberOfThreads(); i++) { PolyDataType poly = PolyDataType::New(); m_PolyDataContainer.push_back(poly); } auto imageSpacing = m_TrackingHandler->GetSpacing(); if (m_Parameters->m_OutputProbMap) { m_OutputProbabilityMap = ItkDoubleImgType::New(); m_OutputProbabilityMap->SetSpacing(imageSpacing); m_OutputProbabilityMap->SetOrigin(m_TrackingHandler->GetOrigin()); m_OutputProbabilityMap->SetDirection(m_TrackingHandler->GetDirection()); m_OutputProbabilityMap->SetRegions(m_TrackingHandler->GetLargestPossibleRegion()); m_OutputProbabilityMap->Allocate(); m_OutputProbabilityMap->FillBuffer(0); } m_MaskInterpolator = itk::LinearInterpolateImageFunction< ItkFloatImgType, float >::New(); m_StopInterpolator = itk::LinearInterpolateImageFunction< ItkFloatImgType, float >::New(); m_SeedInterpolator = itk::LinearInterpolateImageFunction< ItkFloatImgType, float >::New(); m_TargetInterpolator = itk::LinearInterpolateImageFunction< ItkFloatImgType, float >::New(); m_ExclusionInterpolator = itk::LinearInterpolateImageFunction< ItkFloatImgType, float >::New(); if (m_StoppingRegions.IsNull()) { m_StoppingRegions = ItkFloatImgType::New(); m_StoppingRegions->SetSpacing( imageSpacing ); m_StoppingRegions->SetOrigin( m_TrackingHandler->GetOrigin() ); m_StoppingRegions->SetDirection( m_TrackingHandler->GetDirection() ); m_StoppingRegions->SetRegions( m_TrackingHandler->GetLargestPossibleRegion() ); m_StoppingRegions->Allocate(); m_StoppingRegions->FillBuffer(0); } else std::cout << "StreamlineTracking - Using stopping region image" << std::endl; m_StopInterpolator->SetInputImage(m_StoppingRegions); if (m_ExclusionRegions.IsNotNull()) { std::cout << "StreamlineTracking - Using exclusion region image" << std::endl; m_ExclusionInterpolator->SetInputImage(m_ExclusionRegions); } if (m_TargetRegions.IsNull()) { m_TargetImageSet = false; m_TargetRegions = ItkFloatImgType::New(); m_TargetRegions->SetSpacing( imageSpacing ); m_TargetRegions->SetOrigin( m_TrackingHandler->GetOrigin() ); m_TargetRegions->SetDirection( m_TrackingHandler->GetDirection() ); m_TargetRegions->SetRegions( m_TrackingHandler->GetLargestPossibleRegion() ); m_TargetRegions->Allocate(); m_TargetRegions->FillBuffer(1); } else { m_TargetImageSet = true; m_TargetInterpolator->SetInputImage(m_TargetRegions); std::cout << "StreamlineTracking - Using target region image" << std::endl; } if (m_SeedImage.IsNull()) { m_SeedImageSet = false; m_SeedImage = ItkFloatImgType::New(); m_SeedImage->SetSpacing( imageSpacing ); m_SeedImage->SetOrigin( m_TrackingHandler->GetOrigin() ); m_SeedImage->SetDirection( m_TrackingHandler->GetDirection() ); m_SeedImage->SetRegions( m_TrackingHandler->GetLargestPossibleRegion() ); m_SeedImage->Allocate(); m_SeedImage->FillBuffer(1); } else { m_SeedImageSet = true; std::cout << "StreamlineTracking - Using seed image" << std::endl; } m_SeedInterpolator->SetInputImage(m_SeedImage); if (m_MaskImage.IsNull()) { // initialize mask image m_MaskImage = ItkFloatImgType::New(); m_MaskImage->SetSpacing( imageSpacing ); m_MaskImage->SetOrigin( m_TrackingHandler->GetOrigin() ); m_MaskImage->SetDirection( m_TrackingHandler->GetDirection() ); m_MaskImage->SetRegions( m_TrackingHandler->GetLargestPossibleRegion() ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } else std::cout << "StreamlineTracking - Using mask image" << std::endl; m_MaskInterpolator->SetInputImage(m_MaskImage); // Autosettings for endpoint constraints if (m_Parameters->m_EpConstraints==EndpointConstraints::NONE && m_TargetImageSet && m_SeedImageSet) { MITK_INFO << "No endpoint constraint chosen but seed and target image set --> setting constraint to EPS_IN_SEED_AND_TARGET"; m_Parameters->m_EpConstraints = EndpointConstraints::EPS_IN_SEED_AND_TARGET; } else if (m_Parameters->m_EpConstraints==EndpointConstraints::NONE && m_TargetImageSet) { MITK_INFO << "No endpoint constraint chosen but target image set --> setting constraint to EPS_IN_TARGET"; m_Parameters->m_EpConstraints = EndpointConstraints::EPS_IN_TARGET; } // Check if endpoint constraints are valid FiberType test_fib; itk::Point p; p.Fill(0); test_fib.push_back(p); test_fib.push_back(p); IsValidFiber(&test_fib); if (m_SeedPoints.empty()) GetSeedPointsFromSeedImage(); m_BuildFibersReady = 0; m_BuildFibersFinished = false; m_Tractogram.clear(); m_SamplingPointset = mitk::PointSet::New(); m_AlternativePointset = mitk::PointSet::New(); m_StopVotePointset = mitk::PointSet::New(); m_StartTime = std::chrono::system_clock::now(); if (m_DemoMode) omp_set_num_threads(1); if (m_Parameters->m_Mode==mitk::TrackingDataHandler::MODE::DETERMINISTIC) std::cout << "StreamlineTracking - Mode: deterministic" << std::endl; else if(m_Parameters->m_Mode==mitk::TrackingDataHandler::MODE::PROBABILISTIC) { std::cout << "StreamlineTracking - Mode: probabilistic" << std::endl; std::cout << "StreamlineTracking - Trials per seed: " << m_Parameters->m_TrialsPerSeed << std::endl; } else std::cout << "StreamlineTracking - Mode: ???" << std::endl; if (m_Parameters->m_EpConstraints==EndpointConstraints::NONE) std::cout << "StreamlineTracking - Endpoint constraint: NONE" << std::endl; else if (m_Parameters->m_EpConstraints==EndpointConstraints::EPS_IN_TARGET) std::cout << "StreamlineTracking - Endpoint constraint: EPS_IN_TARGET" << std::endl; else if (m_Parameters->m_EpConstraints==EndpointConstraints::EPS_IN_TARGET_LABELDIFF) std::cout << "StreamlineTracking - Endpoint constraint: EPS_IN_TARGET_LABELDIFF" << std::endl; else if (m_Parameters->m_EpConstraints==EndpointConstraints::EPS_IN_SEED_AND_TARGET) std::cout << "StreamlineTracking - Endpoint constraint: EPS_IN_SEED_AND_TARGET" << std::endl; else if (m_Parameters->m_EpConstraints==EndpointConstraints::MIN_ONE_EP_IN_TARGET) std::cout << "StreamlineTracking - Endpoint constraint: MIN_ONE_EP_IN_TARGET" << std::endl; else if (m_Parameters->m_EpConstraints==EndpointConstraints::ONE_EP_IN_TARGET) std::cout << "StreamlineTracking - Endpoint constraint: ONE_EP_IN_TARGET" << std::endl; else if (m_Parameters->m_EpConstraints==EndpointConstraints::NO_EP_IN_TARGET) std::cout << "StreamlineTracking - Endpoint constraint: NO_EP_IN_TARGET" << std::endl; std::cout << "StreamlineTracking - Angular threshold: " << m_Parameters->GetAngularThresholdDot() << "°" << std::endl; std::cout << "StreamlineTracking - Stepsize: " << m_Parameters->GetStepSizeMm() << "mm (" << m_Parameters->GetStepSizeMm()/m_Parameters->GetMinVoxelSizeMm() << "*vox)" << std::endl; std::cout << "StreamlineTracking - Seeds per voxel: " << m_Parameters->m_SeedsPerVoxel << std::endl; std::cout << "StreamlineTracking - Max. tract length: " << m_Parameters->m_MaxTractLengthMm << "mm" << std::endl; std::cout << "StreamlineTracking - Min. tract length: " << m_Parameters->m_MinTractLengthMm << "mm" << std::endl; std::cout << "StreamlineTracking - Max. num. tracts: " << m_Parameters->m_MaxNumFibers << std::endl; std::cout << "StreamlineTracking - Loop check: " << m_Parameters->GetLoopCheckDeg() << "°" << std::endl; std::cout << "StreamlineTracking - Num. neighborhood samples: " << m_Parameters->m_NumSamples << std::endl; std::cout << "StreamlineTracking - Max. sampling distance: " << m_Parameters->GetSamplingDistanceMm() << "mm (" << m_Parameters->GetSamplingDistanceMm()/m_Parameters->GetMinVoxelSizeMm() << "*vox)" << std::endl; std::cout << "StreamlineTracking - Deflection modifier: " << m_Parameters->m_DeflectionMod << std::endl; std::cout << "StreamlineTracking - Use stop votes: " << m_Parameters->m_StopVotes << std::endl; std::cout << "StreamlineTracking - Only frontal samples: " << m_Parameters->m_OnlyForwardSamples << std::endl; if (m_TrackingPriorHandler!=nullptr) std::cout << "StreamlineTracking - Using directional prior for tractography (w=" << m_Parameters->m_Weight << ")" << std::endl; if (m_DemoMode) { std::cout << "StreamlineTracking - Running in demo mode"; std::cout << "StreamlineTracking - Starting streamline tracking using 1 thread" << std::endl; } else std::cout << "StreamlineTracking - Starting streamline tracking using " << omp_get_max_threads() << " threads" << std::endl; } void StreamlineTrackingFilter::CalculateNewPosition(itk::Point& pos, vnl_vector_fixed& dir) { pos[0] += dir[0]*m_Parameters->GetStepSizeMm(); pos[1] += dir[1]*m_Parameters->GetStepSizeMm(); pos[2] += dir[2]*m_Parameters->GetStepSizeMm(); } std::vector< vnl_vector_fixed > StreamlineTrackingFilter::CreateDirections(unsigned int NPoints) { std::vector< vnl_vector_fixed > pointshell; if (NPoints<2) return pointshell; std::vector< double > theta; theta.resize(NPoints); std::vector< double > phi; phi.resize(NPoints); auto C = sqrt(4*itk::Math::pi); phi[0] = 0.0; phi[NPoints-1] = 0.0; for(unsigned int i=0; i0 && i d; d[0] = static_cast(cos(theta[i]) * cos(phi[i])); d[1] = static_cast(cos(theta[i]) * sin(phi[i])); d[2] = static_cast(sin(theta[i])); pointshell.push_back(d); } return pointshell; } vnl_vector_fixed StreamlineTrackingFilter::GetNewDirection(const itk::Point &pos, std::deque >& olddirs, itk::Index<3> &oldIndex) { if (m_DemoMode) { m_SamplingPointset->Clear(); m_AlternativePointset->Clear(); m_StopVotePointset->Clear(); } vnl_vector_fixed direction; direction.fill(0); if (mitk::imv::IsInsideMask(pos, m_Parameters->m_InterpolateRoiImages, m_MaskInterpolator) && !mitk::imv::IsInsideMask(pos, m_Parameters->m_InterpolateRoiImages, m_StopInterpolator)) direction = m_TrackingHandler->ProposeDirection(pos, olddirs, oldIndex); // get direction proposal at current streamline position else return direction; int stop_votes = 0; int possible_stop_votes = 0; if (!olddirs.empty()) { vnl_vector_fixed olddir = olddirs.back(); std::vector< vnl_vector_fixed > probeVecs = CreateDirections(m_Parameters->m_NumSamples); itk::Point sample_pos; unsigned int alternatives = 1; for (unsigned int i=0; i d; bool is_stop_voter = false; if (!m_Parameters->m_FixRandomSeed && m_Parameters->m_RandomSampling) { d[0] = static_cast(m_TrackingHandler->GetRandDouble(-0.5, 0.5)); d[1] = static_cast(m_TrackingHandler->GetRandDouble(-0.5, 0.5)); d[2] = static_cast(m_TrackingHandler->GetRandDouble(-0.5, 0.5)); d.normalize(); d *= static_cast(m_TrackingHandler->GetRandDouble(0, static_cast(m_Parameters->GetSamplingDistanceMm()))); } else { d = probeVecs.at(i); float dot = dot_product(d, olddir); if (m_Parameters->m_StopVotes && dot>0.7f) { is_stop_voter = true; possible_stop_votes++; } else if (m_Parameters->m_OnlyForwardSamples && dot<0) continue; d *= m_Parameters->GetSamplingDistanceMm(); } sample_pos[0] = pos[0] + d[0]; sample_pos[1] = pos[1] + d[1]; sample_pos[2] = pos[2] + d[2]; vnl_vector_fixed tempDir; tempDir.fill(0.0); if (mitk::imv::IsInsideMask(sample_pos, m_Parameters->m_InterpolateRoiImages, m_MaskInterpolator)) tempDir = m_TrackingHandler->ProposeDirection(sample_pos, olddirs, oldIndex); // sample neighborhood if (tempDir.magnitude()>static_cast(mitk::eps)) { direction += tempDir; if(m_DemoMode) m_SamplingPointset->InsertPoint(i, sample_pos); } else if (m_Parameters->m_AvoidStop && olddir.magnitude()>0.5f) // out of white matter { if (is_stop_voter) stop_votes++; if (m_DemoMode) m_StopVotePointset->InsertPoint(i, sample_pos); float dot = dot_product(d, olddir); if (dot >= 0.0f) // in front of plane defined by pos and olddir d = -d + 2*dot*olddir; // reflect else d = -d; // invert // look a bit further into the other direction sample_pos[0] = pos[0] + d[0]; sample_pos[1] = pos[1] + d[1]; sample_pos[2] = pos[2] + d[2]; alternatives++; vnl_vector_fixed tempDir; tempDir.fill(0.0); if (mitk::imv::IsInsideMask(sample_pos, m_Parameters->m_InterpolateRoiImages, m_MaskInterpolator)) tempDir = m_TrackingHandler->ProposeDirection(sample_pos, olddirs, oldIndex); // sample neighborhood if (tempDir.magnitude()>static_cast(mitk::eps)) // are we back in the white matter? { direction += d * m_Parameters->m_DeflectionMod; // go into the direction of the white matter direction += tempDir; // go into the direction of the white matter direction at this location if(m_DemoMode) m_AlternativePointset->InsertPoint(alternatives, sample_pos); } else { if (m_DemoMode) m_StopVotePointset->InsertPoint(i, sample_pos); } } else { if (m_DemoMode) m_StopVotePointset->InsertPoint(i, sample_pos); if (is_stop_voter) stop_votes++; } } } bool valid = false; if (direction.magnitude()>0.001f && (possible_stop_votes==0 || static_cast(stop_votes)/possible_stop_votes<0.5f) ) { direction.normalize(); valid = true; } else direction.fill(0); if (m_TrackingPriorHandler!=nullptr && (m_Parameters->m_NewDirectionsFromPrior || valid)) { vnl_vector_fixed prior = m_TrackingPriorHandler->ProposeDirection(pos, olddirs, oldIndex); if (prior.magnitude()>0.001f) { prior.normalize(); if (dot_product(prior,direction)<0) prior *= -1; direction = (1.0f-m_Parameters->m_Weight) * direction + m_Parameters->m_Weight * prior; direction.normalize(); } else if (m_Parameters->m_RestrictToPrior) direction.fill(0.0); } return direction; } float StreamlineTrackingFilter::FollowStreamline(itk::Point pos, vnl_vector_fixed dir, FiberType* fib, DirectionContainer* container, float tractLength, bool front, bool &exclude) { vnl_vector_fixed zero_dir; zero_dir.fill(0.0); std::deque< vnl_vector_fixed > last_dirs; for (unsigned int i=0; im_NumPreviousDirections-1; i++) last_dirs.push_back(zero_dir); for (int step=0; step< 5000; step++) { itk::Index<3> oldIndex; m_TrackingHandler->WorldToIndex(pos, oldIndex); // get new position CalculateNewPosition(pos, dir); if (m_ExclusionRegions.IsNotNull() && mitk::imv::IsInsideMask(pos, m_Parameters->m_InterpolateRoiImages, m_ExclusionInterpolator)) { exclude = true; return tractLength; } if (m_AbortTracking) return tractLength; // if yes, add new point to streamline dir.normalize(); if (front) { fib->push_front(pos); container->push_front(dir); } else { fib->push_back(pos); container->push_back(dir); } tractLength += m_Parameters->GetStepSizeMm(); if (m_Parameters->GetLoopCheckDeg()>=0 && CheckCurvature(container, front)>m_Parameters->GetLoopCheckDeg()) return tractLength; if (tractLength>m_Parameters->m_MaxTractLengthMm) return tractLength; if (m_DemoMode && !m_Parameters->m_OutputProbMap) // CHECK: warum sind die samplingpunkte der streamline in der visualisierung immer einen schritt voras? { #pragma omp critical { m_BuildFibersReady++; m_Tractogram.push_back(*fib); BuildFibers(true); m_Stop = true; while (m_Stop){ } } } last_dirs.push_back(dir); if (last_dirs.size()>m_Parameters->m_NumPreviousDirections) last_dirs.pop_front(); dir = GetNewDirection(pos, last_dirs, oldIndex); while (m_PauseTracking){} if (dir.magnitude()<0.0001f) return tractLength; } return tractLength; } float StreamlineTrackingFilter::CheckCurvature(DirectionContainer* fib, bool front) { if (fib->size()<8) return 0; float m_Distance = std::max(m_Parameters->GetMinVoxelSizeMm()*4, m_Parameters->GetStepSizeMm()*8); float dist = 0; std::vector< vnl_vector_fixed< float, 3 > > vectors; vnl_vector_fixed< float, 3 > meanV; meanV.fill(0); float dev = 0; if (front) { int c = 0; while(dist(fib->size())-1) { dist += m_Parameters->GetStepSizeMm(); vnl_vector_fixed< float, 3 > v = fib->at(static_cast(c)); if (dot_product(v,meanV)<0) v = -v; vectors.push_back(v); meanV += v; c++; } } else { int c = static_cast(fib->size())-1; while(dist=0) { dist += m_Parameters->GetStepSizeMm(); vnl_vector_fixed< float, 3 > v = fib->at(static_cast(c)); if (dot_product(v,meanV)<0) v = -v; vectors.push_back(v); meanV += v; c--; } } meanV.normalize(); for (unsigned int c=0; c1.0f) angle = 1.0; dev += acos(angle)*180.0f/static_cast(itk::Math::pi); } if (vectors.size()>0) dev /= vectors.size(); return dev; } std::shared_ptr StreamlineTrackingFilter::GetParameters() const { return m_Parameters; } void StreamlineTrackingFilter::SetParameters(std::shared_ptr< mitk::StreamlineTractographyParameters > Parameters) { m_Parameters = Parameters; } void StreamlineTrackingFilter::SetTrackingPriorHandler(mitk::TrackingDataHandler *TrackingPriorHandler) { m_TrackingPriorHandler = TrackingPriorHandler; } void StreamlineTrackingFilter::GetSeedPointsFromSeedImage() { MITK_INFO << "StreamlineTracking - Calculating seed points."; m_SeedPoints.clear(); typedef ImageRegionConstIterator< ItkFloatImgType > MaskIteratorType; MaskIteratorType sit(m_SeedImage, m_SeedImage->GetLargestPossibleRegion()); sit.GoToBegin(); while (!sit.IsAtEnd()) { if (sit.Value()>0) { ItkFloatImgType::IndexType index = sit.GetIndex(); itk::ContinuousIndex start; start[0] = index[0]; start[1] = index[1]; start[2] = index[2]; itk::Point worldPos; m_SeedImage->TransformContinuousIndexToPhysicalPoint(start, worldPos); if ( mitk::imv::IsInsideMask(worldPos, m_Parameters->m_InterpolateRoiImages, m_MaskInterpolator) ) { m_SeedPoints.push_back(worldPos); for (unsigned int s = 1; s < m_Parameters->m_SeedsPerVoxel; s++) { start[0] = index[0] + static_cast(m_TrackingHandler->GetRandDouble(-0.5, 0.5)); start[1] = index[1] + static_cast(m_TrackingHandler->GetRandDouble(-0.5, 0.5)); start[2] = index[2] + static_cast(m_TrackingHandler->GetRandDouble(-0.5, 0.5)); itk::Point worldPos; m_SeedImage->TransformContinuousIndexToPhysicalPoint(start, worldPos); m_SeedPoints.push_back(worldPos); } } } ++sit; } if (m_SeedPoints.empty()) mitkThrow() << "No valid seed point in seed image! Is your seed image registered with the image you are tracking on?"; } void StreamlineTrackingFilter::GenerateData() { this->BeforeTracking(); if (!m_Parameters->m_FixRandomSeed) std::random_shuffle(m_SeedPoints.begin(), m_SeedPoints.end()); m_CurrentTracts = 0; int num_seeds = static_cast(m_SeedPoints.size()); itk::Index<3> zeroIndex; zeroIndex.Fill(0); m_Progress = 0; int i = 0; int print_interval = num_seeds/100; if (print_interval<100) m_Verbose=false; unsigned int trials_per_seed = 1; if(m_Parameters->m_Mode==mitk::TrackingDataHandler::MODE::PROBABILISTIC) trials_per_seed = m_Parameters->m_TrialsPerSeed; #pragma omp parallel while (i=num_seeds || m_StopTracking) continue; else if (m_Verbose && i%print_interval==0) #pragma omp critical { m_Progress += static_cast(print_interval); std::cout << " \r"; if (m_Parameters->m_MaxNumFibers>0) std::cout << "Tried: " << m_Progress << "/" << num_seeds << " | Accepted: " << m_CurrentTracts << "/" << m_Parameters->m_MaxNumFibers << '\r'; else std::cout << "Tried: " << m_Progress << "/" << num_seeds << " | Accepted: " << m_CurrentTracts << '\r'; cout.flush(); } const itk::Point worldPos = m_SeedPoints.at(static_cast(temp_i)); for (unsigned int trials=0; trials dir; dir.fill(0.0); std::deque< vnl_vector_fixed > olddirs; dir = GetNewDirection(worldPos, olddirs, zeroIndex) * 0.5f; bool exclude = false; if (m_ExclusionRegions.IsNotNull() && mitk::imv::IsInsideMask(worldPos, m_Parameters->m_InterpolateRoiImages, m_ExclusionInterpolator)) exclude = true; bool success = false; if (dir.magnitude()>0.0001f && !exclude) { // forward tracking tractLength = FollowStreamline(worldPos, dir, &fib, &direction_container, 0, false, exclude); fib.push_front(worldPos); // backward tracking if (!exclude) tractLength = FollowStreamline(worldPos, -dir, &fib, &direction_container, tractLength, true, exclude); counter = fib.size(); if (tractLength>=m_Parameters->m_MinTractLengthMm && counter>=2 && !exclude) { #pragma omp critical if ( IsValidFiber(&fib) ) { if (!m_StopTracking) { if (!m_Parameters->m_OutputProbMap) m_Tractogram.push_back(fib); else FiberToProbmap(&fib); m_CurrentTracts++; success = true; } if (m_Parameters->m_MaxNumFibers > 0 && m_CurrentTracts>=static_cast(m_Parameters->m_MaxNumFibers)) { if (!m_StopTracking) { std::cout << " \r"; MITK_INFO << "Reconstructed maximum number of tracts (" << m_CurrentTracts << "). Stopping tractography."; } m_StopTracking = true; } } } } if (success || m_Parameters->m_Mode!=MODE::PROBABILISTIC) break; // we only try one seed point multiple times if we use a probabilistic tracker and have not found a valid streamline yet }// trials per seed }// seed points this->AfterTracking(); } bool StreamlineTrackingFilter::IsValidFiber(FiberType* fib) { if (m_Parameters->m_EpConstraints==EndpointConstraints::NONE) { return true; } else if (m_Parameters->m_EpConstraints==EndpointConstraints::EPS_IN_TARGET) { if (m_TargetImageSet) { if ( mitk::imv::IsInsideMask(fib->front(), m_Parameters->m_InterpolateRoiImages, m_TargetInterpolator) && mitk::imv::IsInsideMask(fib->back(), m_Parameters->m_InterpolateRoiImages, m_TargetInterpolator) ) return true; return false; } else mitkThrow() << "No target image set but endpoint constraint EPS_IN_TARGET chosen!"; } else if (m_Parameters->m_EpConstraints==EndpointConstraints::EPS_IN_TARGET_LABELDIFF) { if (m_TargetImageSet) { float v1 = mitk::imv::GetImageValue(fib->front(), false, m_TargetInterpolator); float v2 = mitk::imv::GetImageValue(fib->back(), false, m_TargetInterpolator); if ( v1>0.0f && v2>0.0f && v1!=v2 ) return true; return false; } else mitkThrow() << "No target image set but endpoint constraint EPS_IN_TARGET_LABELDIFF chosen!"; } else if (m_Parameters->m_EpConstraints==EndpointConstraints::EPS_IN_SEED_AND_TARGET) { if (m_TargetImageSet && m_SeedImageSet) { if ( mitk::imv::IsInsideMask(fib->front(), m_Parameters->m_InterpolateRoiImages, m_SeedInterpolator) && mitk::imv::IsInsideMask(fib->back(), m_Parameters->m_InterpolateRoiImages, m_TargetInterpolator) ) return true; if ( mitk::imv::IsInsideMask(fib->back(), m_Parameters->m_InterpolateRoiImages, m_SeedInterpolator) && mitk::imv::IsInsideMask(fib->front(), m_Parameters->m_InterpolateRoiImages, m_TargetInterpolator) ) return true; return false; } else mitkThrow() << "No target or seed image set but endpoint constraint EPS_IN_SEED_AND_TARGET chosen!"; } else if (m_Parameters->m_EpConstraints==EndpointConstraints::MIN_ONE_EP_IN_TARGET) { if (m_TargetImageSet) { if ( mitk::imv::IsInsideMask(fib->front(), m_Parameters->m_InterpolateRoiImages, m_TargetInterpolator) || mitk::imv::IsInsideMask(fib->back(), m_Parameters->m_InterpolateRoiImages, m_TargetInterpolator) ) return true; return false; } else mitkThrow() << "No target image set but endpoint constraint MIN_ONE_EP_IN_TARGET chosen!"; } else if (m_Parameters->m_EpConstraints==EndpointConstraints::ONE_EP_IN_TARGET) { if (m_TargetImageSet) { if ( mitk::imv::IsInsideMask(fib->front(), m_Parameters->m_InterpolateRoiImages, m_TargetInterpolator) && !mitk::imv::IsInsideMask(fib->back(), m_Parameters->m_InterpolateRoiImages, m_TargetInterpolator) ) return true; if ( !mitk::imv::IsInsideMask(fib->back(), m_Parameters->m_InterpolateRoiImages, m_TargetInterpolator) && mitk::imv::IsInsideMask(fib->front(), m_Parameters->m_InterpolateRoiImages, m_TargetInterpolator) ) return true; return false; } else mitkThrow() << "No target image set but endpoint constraint ONE_EP_IN_TARGET chosen!"; } else if (m_Parameters->m_EpConstraints==EndpointConstraints::NO_EP_IN_TARGET) { if (m_TargetImageSet) { if ( mitk::imv::IsInsideMask(fib->front(), m_Parameters->m_InterpolateRoiImages, m_TargetInterpolator) || mitk::imv::IsInsideMask(fib->back(), m_Parameters->m_InterpolateRoiImages, m_TargetInterpolator) ) return false; return true; } else mitkThrow() << "No target image set but endpoint constraint NO_EP_IN_TARGET chosen!"; } return true; } void StreamlineTrackingFilter::FiberToProbmap(FiberType* fib) { ItkDoubleImgType::IndexType last_idx; last_idx.Fill(0); for (auto p : *fib) { ItkDoubleImgType::IndexType idx; m_OutputProbabilityMap->TransformPhysicalPointToIndex(p, idx); if (idx != last_idx) { if (m_OutputProbabilityMap->GetLargestPossibleRegion().IsInside(idx)) m_OutputProbabilityMap->SetPixel(idx, m_OutputProbabilityMap->GetPixel(idx)+1); last_idx = idx; } } } void StreamlineTrackingFilter::BuildFibers(bool check) { if (m_BuildFibersReady::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); for (unsigned int i=0; i container = vtkSmartPointer::New(); FiberType fib = m_Tractogram.at(i); for (FiberType::iterator it = fib.begin(); it!=fib.end(); ++it) { vtkIdType id = vNewPoints->InsertNextPoint((*it).GetDataPointer()); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } if (check) for (int i=0; iSetPoints(vNewPoints); m_FiberPolyData->SetLines(vNewLines); m_BuildFibersFinished = true; } void StreamlineTrackingFilter::AfterTracking() { if (m_Verbose) std::cout << " \r"; if (!m_Parameters->m_OutputProbMap) { MITK_INFO << "Reconstructed " << m_Tractogram.size() << " fibers."; MITK_INFO << "Generating polydata "; BuildFibers(false); } else { itk::RescaleIntensityImageFilter< ItkDoubleImgType, ItkDoubleImgType >::Pointer filter = itk::RescaleIntensityImageFilter< ItkDoubleImgType, ItkDoubleImgType >::New(); filter->SetInput(m_OutputProbabilityMap); filter->SetOutputMaximum(1.0); filter->SetOutputMinimum(0.0); filter->Update(); m_OutputProbabilityMap = filter->GetOutput(); } MITK_INFO << "done"; m_EndTime = std::chrono::system_clock::now(); std::chrono::hours hh = std::chrono::duration_cast(m_EndTime - m_StartTime); std::chrono::minutes mm = std::chrono::duration_cast(m_EndTime - m_StartTime); std::chrono::seconds ss = std::chrono::duration_cast(m_EndTime - m_StartTime); mm %= 60; ss %= 60; MITK_INFO << "Tracking took " << hh.count() << "h, " << mm.count() << "m and " << ss.count() << "s"; m_SeedPoints.clear(); } void StreamlineTrackingFilter::SetDicomProperties(mitk::FiberBundle::Pointer fib) { std::string model_code_value = "-"; std::string model_code_meaning = "-"; std::string algo_code_value = "-"; std::string algo_code_meaning = "-"; - if ( m_Parameters->m_Mode==MODE::DETERMINISTIC && dynamic_cast(m_TrackingHandler) && !m_Parameters->m_InterpolateTractographyData) + if ( m_Parameters->m_Mode==MODE::DETERMINISTIC && dynamic_cast(m_TrackingHandler)) { - algo_code_value = "sup181_ee04"; - algo_code_meaning = "FACT"; + algo_code_value = "sup181_ee01"; + algo_code_meaning = "Deterministic"; + + if (m_Parameters->m_F > 0.99 && m_Parameters->m_G < 0.01) + { + if (m_Parameters->m_InterpolateTractographyData) + { + algo_code_value = "sup181_ee08"; + algo_code_meaning = "Euler"; + } + else + { + algo_code_value = "sup181_ee04"; + algo_code_meaning = "FACT"; + } + } + else if (m_Parameters->m_G > 0.99 && m_Parameters->m_F < 0.01) + { + algo_code_value = "sup181_ee06"; + algo_code_meaning = "TEND"; + } } else if (m_Parameters->m_Mode==MODE::DETERMINISTIC) { algo_code_value = "sup181_ee01"; algo_code_meaning = "Deterministic"; } else if (m_Parameters->m_Mode==MODE::PROBABILISTIC) { algo_code_value = "sup181_ee02"; algo_code_meaning = "Probabilistic"; } if (dynamic_cast(m_TrackingHandler) || (dynamic_cast(m_TrackingHandler) && dynamic_cast(m_TrackingHandler)->GetIsOdfFromTensor() ) ) { if ( dynamic_cast(m_TrackingHandler) && dynamic_cast(m_TrackingHandler)->GetNumTensorImages()>1 ) { model_code_value = "sup181_bb02"; model_code_meaning = "Multi Tensor"; } else { model_code_value = "sup181_bb01"; model_code_meaning = "Single Tensor"; } } else if (dynamic_cast*>(m_TrackingHandler) || dynamic_cast*>(m_TrackingHandler)) { model_code_value = "sup181_bb03"; model_code_meaning = "Model Free"; } else if (dynamic_cast(m_TrackingHandler)) { model_code_value = "-"; model_code_meaning = "ODF"; } else if (dynamic_cast(m_TrackingHandler)) { model_code_value = "-"; model_code_meaning = "Peaks"; } fib->SetProperty("DICOM.anatomy.value", mitk::StringProperty::New("T-A0095")); fib->SetProperty("DICOM.anatomy.meaning", mitk::StringProperty::New("White matter of brain and spinal cord")); - fib->SetProperty("DICOM.algo_code.value", mitk::StringProperty::New(algo_code_value)); - fib->SetProperty("DICOM.algo_code.meaning", mitk::StringProperty::New(algo_code_meaning)); + fib->SetProperty("DICOM.algo_family_code.value", mitk::StringProperty::New(algo_code_value)); + fib->SetProperty("DICOM.algo_family_code.meaning", mitk::StringProperty::New(algo_code_meaning)); fib->SetProperty("DICOM.model_code.value", mitk::StringProperty::New(model_code_value)); fib->SetProperty("DICOM.model_code.meaning", mitk::StringProperty::New(model_code_meaning)); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionView.cpp index 4a8c699..3402b12 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionView.cpp @@ -1,382 +1,387 @@ /*=================================================================== 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. ===================================================================*/ //misc #include // Blueberry #include #include // Qmitk #include "QmitkOdfMaximaExtractionView.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Qt #include const std::string QmitkOdfMaximaExtractionView::VIEW_ID = "org.mitk.views.odfmaximaextractionview"; using namespace mitk; QmitkOdfMaximaExtractionView::QmitkOdfMaximaExtractionView() : m_Controls(nullptr) { } // Destructor QmitkOdfMaximaExtractionView::~QmitkOdfMaximaExtractionView() { } void QmitkOdfMaximaExtractionView::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::QmitkOdfMaximaExtractionViewControls; m_Controls->setupUi(parent); connect((QObject*)m_Controls->m_StartPeakExtractionButton, SIGNAL(clicked()), (QObject*) this, SLOT(StartPeakExtraction())); connect((QObject*)m_Controls->m_ImportShCoeffs, SIGNAL(clicked()), (QObject*) this, SLOT(ConvertShCoeffs())); m_Controls->m_MaskBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isShImage = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isTensorImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateNot::Pointer isDwi = mitk::NodePredicateNot::New(mitk::NodePredicateIsDWI::New()); mitk::NodePredicateNot::Pointer isOdf = mitk::NodePredicateNot::New(mitk::NodePredicateDataType::New("OdfImage")); mitk::NodePredicateAnd::Pointer unwanted = mitk::NodePredicateAnd::New(isOdf, isDwi); mitk::NodePredicateDimension::Pointer dim3 = mitk::NodePredicateDimension::New(3); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); m_Controls->m_MaskBox->SetPredicate(mitk::NodePredicateAnd::New(mitk::NodePredicateAnd::New(unwanted, dim3), isBinaryPredicate)); m_Controls->m_ImageBox->SetPredicate(mitk::NodePredicateOr::New(isTensorImage, isShImage)); m_Controls->m_MaskBox->SetZeroEntryText("--"); connect( (QObject*)(m_Controls->m_ImageBox), SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnImageSelectionChanged()) ); m_Controls->m_StartPeakExtractionButton->setVisible(false); m_Controls->m_ImportShCoeffs->setVisible(false); } } void QmitkOdfMaximaExtractionView::SetFocus() { } void QmitkOdfMaximaExtractionView::StartPeakExtraction() { if (dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData()) != nullptr) { StartTensorPeakExtraction(dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData())); } else { StartMaximaExtraction(dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData())); } } template void QmitkOdfMaximaExtractionView::TemplatedConvertShCoeffs(mitk::Image* mitkImg) { typedef itk::ShCoefficientImageImporter< float, shOrder > FilterType; typedef mitk::ImageToItk< itk::Image< float, 4 > > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkImg); caster->Update(); typename FilterType::Pointer filter = FilterType::New(); filter->SetInputImage(caster->GetOutput()); filter->GenerateData(); typename FilterType::CoefficientImageType::Pointer itkCi = filter->GetCoefficientImage(); { mitk::Image::Pointer img = dynamic_cast(mitk::ShImage::New().GetPointer()); img->InitializeByItk(itkCi.GetPointer()); img->SetVolume(itkCi->GetBufferPointer()); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(mitkImg, img); + DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_ShImage_Imported"; node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node, m_Controls->m_ImageBox->GetSelectedNode()); } } void QmitkOdfMaximaExtractionView::ConvertShCoeffs() { if (m_Controls->m_ImageBox->GetSelectedNode().IsNull()) return; Image::Pointer mitkImg = dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData()); if (mitkImg->GetDimension() != 4 && mitkImg->GetLargestPossibleRegion().GetSize()[3]<6) { MITK_INFO << "wrong image type (need 4 dimensions)"; return; } int nrCoeffs = mitkImg->GetLargestPossibleRegion().GetSize()[3]; switch (nrCoeffs) { case 6: TemplatedConvertShCoeffs<2>(mitkImg); break; case 15: TemplatedConvertShCoeffs<4>(mitkImg); break; case 28: TemplatedConvertShCoeffs<6>(mitkImg); break; case 45: TemplatedConvertShCoeffs<8>(mitkImg); break; case 66: TemplatedConvertShCoeffs<10>(mitkImg); break; case 91: TemplatedConvertShCoeffs<12>(mitkImg); break; default : QMessageBox::warning(nullptr, "Error", "Only spherical harmonics orders 2-12 are supported.", QMessageBox::Ok); } } void QmitkOdfMaximaExtractionView::StartTensorPeakExtraction(mitk::TensorImage* img) { typedef itk::DiffusionTensorPrincipalDirectionImageFilter< float > MaximaExtractionFilterType; MaximaExtractionFilterType::Pointer filter = MaximaExtractionFilterType::New(); filter->SetUsePolarCoordinates(false); mitk::BaseGeometry::Pointer geometry; try{ ItkTensorImage::Pointer itkImage = ItkTensorImage::New(); CastToItkImage(img, itkImage); filter->SetInput(itkImage); geometry = img->GetGeometry(); } catch (itk::ExceptionObject &e) { MITK_INFO << "wrong image type: " << e.what(); QMessageBox::warning(nullptr, "Wrong pixel type", "Could not perform Tensor Principal Direction Extraction due to Image has wrong pixel type.", QMessageBox::Ok); return; } if (m_Controls->m_MaskBox->GetSelectedNode().IsNotNull()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); Image::Pointer mitkMaskImg = dynamic_cast(m_Controls->m_MaskBox->GetSelectedNode()->GetData()); CastToItkImage(mitkMaskImg, itkMaskImage); filter->SetMaskImage(itkMaskImage); } if (m_Controls->m_NormalizationBox->currentIndex() == 0) filter->SetNormalizeVectors(false); filter->SetFaThreshold(m_Controls->m_AbsoluteThresholdBox->value()); filter->Update(); MaximaExtractionFilterType::PeakImageType::Pointer itkImg = filter->GetPeakImage(); mitk::Image::Pointer mitkPeakImage = dynamic_cast(PeakImage::New().GetPointer()); CastToMitkImage(itkImg, mitkPeakImage); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(img, mitkPeakImage); + DataNode::Pointer node = DataNode::New(); node->SetData(mitkPeakImage); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_PrincipalDirection"; node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node, m_Controls->m_ImageBox->GetSelectedNode()); if (m_Controls->m_OutputNumDirectionsBox->isChecked()) { ItkUcharImgType::Pointer numDirImage = filter->GetOutput(); mitk::Image::Pointer image2 = mitk::Image::New(); image2->InitializeByItk(numDirImage.GetPointer()); image2->SetVolume(numDirImage->GetBufferPointer()); DataNode::Pointer node2 = DataNode::New(); node2->SetData(image2); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_NumDirections"; node2->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node2, m_Controls->m_ImageBox->GetSelectedNode()); } } template void QmitkOdfMaximaExtractionView::StartMaximaExtraction(Image *image) { typedef itk::OdfMaximaExtractionFilter< float, shOrder, ODF_SAMPLING_SIZE > MaximaExtractionFilterType; typename MaximaExtractionFilterType::Pointer filter = MaximaExtractionFilterType::New(); switch (m_Controls->m_ToolkitBox->currentIndex()) { case 0: filter->SetToolkit(MaximaExtractionFilterType::MRTRIX); break; case 1: filter->SetToolkit(MaximaExtractionFilterType::FSL); break; default: filter->SetToolkit(MaximaExtractionFilterType::MRTRIX); } mitk::BaseGeometry::Pointer geometry; try{ typedef ImageToItk< typename MaximaExtractionFilterType::CoefficientImageType > CasterType; typename CasterType::Pointer caster = CasterType::New(); caster->SetInput(image); caster->Update(); filter->SetInput(caster->GetOutput()); geometry = image->GetGeometry(); } catch (itk::ExceptionObject &e) { MITK_INFO << "wrong image type: " << e.what(); QMessageBox::warning(nullptr, "Wrong pixel type", "Could not perform Finite Differences Extraction due to Image has wrong pixel type.", QMessageBox::Ok); return; } filter->SetAngularThreshold(cos((float)m_Controls->m_AngularThreshold->value()*itk::Math::pi / 180)); filter->SetMaxNumPeaks(m_Controls->m_MaxNumPeaksBox->value()); filter->SetRelativePeakThreshold(m_Controls->m_PeakThresholdBox->value()); filter->SetAbsolutePeakThreshold(m_Controls->m_AbsoluteThresholdBox->value()); filter->SetScaleByGfa(m_Controls->m_ScaleByGfaBox->isChecked()); if (m_Controls->m_MaskBox->GetSelectedNode().IsNotNull()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); Image::Pointer mitkMaskImg = dynamic_cast(m_Controls->m_MaskBox->GetSelectedNode()->GetData()); CastToItkImage(mitkMaskImg, itkMaskImage); filter->SetMaskImage(itkMaskImage); } switch (m_Controls->m_NormalizationBox->currentIndex()) { case 0: filter->SetNormalizationMethod(MaximaExtractionFilterType::NO_NORM); break; case 1: filter->SetNormalizationMethod(MaximaExtractionFilterType::MAX_VEC_NORM); break; case 2: filter->SetNormalizationMethod(MaximaExtractionFilterType::SINGLE_VEC_NORM); break; } filter->Update(); typename MaximaExtractionFilterType::PeakImageType::Pointer itkImg = filter->GetPeakImage(); mitk::Image::Pointer img = dynamic_cast(PeakImage::New().GetPointer()); CastToMitkImage(itkImg, img); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(image, img); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_PEAKS"; node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node, m_Controls->m_ImageBox->GetSelectedNode()); if (m_Controls->m_OutputNumDirectionsBox->isChecked()) { ItkUcharImgType::Pointer numDirImage = filter->GetNumDirectionsImage(); mitk::Image::Pointer image2 = mitk::Image::New(); CastToMitkImage(numDirImage, image2); DataNode::Pointer node2 = DataNode::New(); node2->SetData(image2); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_NUM_DIRECTIONS"; node2->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node2, m_Controls->m_ImageBox->GetSelectedNode()); } } void QmitkOdfMaximaExtractionView::StartMaximaExtraction(Image* img) { mitk::PixelType pixT = img->GetPixelType(); switch (pixT.GetNumberOfComponents()) { case 6: StartMaximaExtraction<2>(img); break; case 15: StartMaximaExtraction<4>(img); break; case 28: StartMaximaExtraction<6>(img); break; case 45: StartMaximaExtraction<8>(img); break; case 66: StartMaximaExtraction<10>(img); break; case 91: StartMaximaExtraction<12>(img); break; default : QMessageBox::warning(nullptr, "Error", "Only spherical harmonics orders 2-12 are supported.", QMessageBox::Ok); } } void QmitkOdfMaximaExtractionView::OnSelectionChanged(berry::IWorkbenchPart::Pointer , const QList& nodes) { (void) nodes; this->OnImageSelectionChanged(); } void QmitkOdfMaximaExtractionView::OnImageSelectionChanged() { m_Controls->m_StartPeakExtractionButton->setVisible(false); m_Controls->m_ImportShCoeffs->setVisible(false); mitk::DataNode::Pointer node = m_Controls->m_ImageBox->GetSelectedNode(); if (node.IsNull()) return; Image::Pointer img = dynamic_cast(node->GetData()); if (img->GetDimension()==4) m_Controls->m_ImportShCoeffs->setVisible(true); else m_Controls->m_StartPeakExtractionButton->setVisible(true); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionView.cpp index 38859e1..f9c8067 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionView.cpp @@ -1,808 +1,817 @@ /*=================================================================== 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 "QmitkQBallReconstructionView.h" // qt includes #include // itk includes #include "itkTimeProbe.h" // mitk includes #include "mitkProgressBar.h" #include "mitkStatusBar.h" #include "mitkNodePredicateDataType.h" #include "QmitkDataStorageComboBox.h" #include "itkDiffusionQballReconstructionImageFilter.h" #include "itkAnalyticalDiffusionQballReconstructionImageFilter.h" #include "itkDiffusionMultiShellQballReconstructionImageFilter.h" #include "itkVectorContainer.h" #include "itkB0ImageExtractionImageFilter.h" #include #include "mitkOdfImage.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 "mitkDiffusionImagingConfigure.h" #include #include "berryIStructuredSelection.h" #include "berryIWorkbenchWindow.h" #include "berryISelectionService.h" #include #include #include #include #include const std::string QmitkQBallReconstructionView::VIEW_ID = "org.mitk.views.qballreconstruction"; typedef float TTensorPixelType; const int QmitkQBallReconstructionView::nrconvkernels = 252; struct QbrShellSelection { typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientDirectionContainerType; typedef mitk::DiffusionPropertyHelper::BValueMapType BValueMapType; typedef itk::VectorImage< DiffusionPixelType, 3 > ITKDiffusionImageType; QmitkQBallReconstructionView* m_View; mitk::DataNode * m_Node; std::string m_NodeName; std::vector m_CheckBoxes; QLabel * m_Label; mitk::Image * m_Image; QbrShellSelection(QmitkQBallReconstructionView* view, mitk::DataNode * node) : m_View(view), m_Node(node), m_NodeName(node->GetName()) { m_Image = dynamic_cast (node->GetData()); if(!m_Image) { MITK_ERROR << "QmitkQBallReconstructionView::QbrShellSelection : no image selected"; return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_Node->GetData())) ); if( !isDiffusionImage ) { MITK_ERROR << "QmitkQBallReconstructionView::QbrShellSelection : selected image contains no diffusion information"; return; } GenerateCheckboxes(); } void GenerateCheckboxes() { BValueMapType origMap = mitk::DiffusionPropertyHelper::GetBValueMap(m_Image); BValueMapType::iterator itStart = origMap.begin(); itStart++; BValueMapType::iterator itEnd = origMap.end(); m_Label = new QLabel(m_NodeName.c_str()); m_Label->setVisible(true); m_View->m_Controls->m_QBallSelectionBox->layout()->addWidget(m_Label); for(BValueMapType::iterator it = itStart ; it!= itEnd; it++) { QCheckBox * box = new QCheckBox(QString::number(it->first)); m_View->m_Controls->m_QBallSelectionBox->layout()->addWidget(box); box->setChecked(true); box->setCheckable(true); // box->setVisible(true); m_CheckBoxes.push_back(box); } } void SetVisible(bool vis) { foreach(QCheckBox * box, m_CheckBoxes) { box->setVisible(vis); } } BValueMapType GetBValueSelctionMap() { BValueMapType inputMap = mitk::DiffusionPropertyHelper::GetBValueMap(m_Image); BValueMapType outputMap; unsigned int val = 0; if(inputMap.find(0) == inputMap.end()){ return outputMap; }else{ outputMap[val] = inputMap[val]; } foreach(QCheckBox * box, m_CheckBoxes) { if(box->isChecked()){ val = box->text().toUInt(); outputMap[val] = inputMap[val]; MITK_INFO << val; } } return outputMap; } ~QbrShellSelection() { m_View->m_Controls->m_QBallSelectionBox->layout()->removeWidget(m_Label); delete m_Label; for(std::vector::iterator it = m_CheckBoxes.begin() ; it!= m_CheckBoxes.end(); it++) { m_View->m_Controls->m_QBallSelectionBox->layout()->removeWidget((*it)); delete (*it); } m_CheckBoxes.clear(); } }; QmitkQBallReconstructionView::QmitkQBallReconstructionView() : QmitkAbstractView(), m_Controls(nullptr) { } QmitkQBallReconstructionView::~QmitkQBallReconstructionView() { } void QmitkQBallReconstructionView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkQBallReconstructionViewControls; m_Controls->setupUi(parent); this->CreateConnections(); QStringList items; items << "2" << "4" << "6" << "8" << "10" << "12"; m_Controls->m_QBallReconstructionMaxLLevelComboBox->addItems(items); m_Controls->m_QBallReconstructionMaxLLevelComboBox->setCurrentIndex(1); MethodChoosen(m_Controls->m_QBallReconstructionMethodComboBox->currentIndex()); } } void QmitkQBallReconstructionView::SetFocus() { } void QmitkQBallReconstructionView::CreateConnections() { if ( m_Controls ) { connect( static_cast(m_Controls->m_ButtonStandard), SIGNAL(clicked()), this, SLOT(ReconstructStandard()) ); connect( static_cast(m_Controls->m_QBallReconstructionMethodComboBox), SIGNAL(currentIndexChanged(int)), this, SLOT(MethodChoosen(int)) ); connect( static_cast(m_Controls->m_QBallReconstructionThreasholdEdit), SIGNAL(valueChanged(int)), this, SLOT(PreviewThreshold(int)) ); connect( static_cast(m_Controls->m_ConvertButton), SIGNAL(clicked()), this, SLOT(ConvertShImage()) ); m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); mitk::NodePredicateIsDWI::Pointer isDwi = mitk::NodePredicateIsDWI::New(); m_Controls->m_ImageBox->SetPredicate( isDwi ); m_Controls->m_ShImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isSh = mitk::TNodePredicateDataType::New(); m_Controls->m_ShImageBox->SetPredicate( isSh ); connect( static_cast(m_Controls->m_ImageBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); connect( static_cast(m_Controls->m_ShImageBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); UpdateGui(); } } void QmitkQBallReconstructionView::ConvertShImage() { if (m_Controls->m_ShImageBox->GetSelectedNode().IsNotNull()) { mitk::Image::Pointer mitkImg = dynamic_cast(m_Controls->m_ShImageBox->GetSelectedNode()->GetData()); auto img = mitk::convert::GetOdfFromShImage(mitkImg); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(mitkImg, img); mitk::DataNode::Pointer node= mitk::DataNode::New(); node->SetData( img ); node->SetName(m_Controls->m_ShImageBox->GetSelectedNode()->GetName()); GetDataStorage()->Add(node, m_Controls->m_ShImageBox->GetSelectedNode()); } } void QmitkQBallReconstructionView::UpdateGui() { m_Controls->m_ButtonStandard->setEnabled(false); if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) { m_Controls->m_ButtonStandard->setEnabled(true); GenerateShellSelectionUI(m_Controls->m_ImageBox->GetSelectedNode()); } m_Controls->m_ConvertButton->setEnabled(m_Controls->m_ShImageBox->GetSelectedNode().IsNotNull()); } void QmitkQBallReconstructionView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& /*nodes*/) { UpdateGui(); } void QmitkQBallReconstructionView::Activated() { } void QmitkQBallReconstructionView::Deactivated() { } void QmitkQBallReconstructionView::Visible() { } void QmitkQBallReconstructionView::Hidden() { } void QmitkQBallReconstructionView::ReconstructStandard() { int index = m_Controls->m_QBallReconstructionMethodComboBox->currentIndex(); switch(index) { case 0: { // Numerical Reconstruct(0,0); break; } case 1: { // Standard Reconstruct(1,0); break; } case 2: { // Solid Angle Reconstruct(1,6); break; } case 3: { // ADC Reconstruct(1,4); break; } case 4: { // Raw Signal Reconstruct(1,5); break; } case 5: { // Q-Ball reconstruction Reconstruct(2,0); break; } } } void QmitkQBallReconstructionView::MethodChoosen(int method) { m_Controls->m_QBallSelectionBox->setHidden(true); m_Controls->m_OutputOdfImage->setHidden(true); if (method==0) m_Controls->m_ShFrame->setVisible(false); else m_Controls->m_ShFrame->setVisible(true); switch(method) { case 0: m_Controls->m_Description->setText("Numerical recon. (Tuch 2004)"); break; case 1: m_Controls->m_Description->setText("Spherical harmonics recon. (Descoteaux 2007)"); m_Controls->m_OutputOdfImage->setHidden(false); break; case 2: m_Controls->m_Description->setText("SH recon. with solid angle consideration (Aganj 2009)"); m_Controls->m_OutputOdfImage->setHidden(false); break; case 3: m_Controls->m_Description->setText("SH solid angle with non-neg. constraint (Goh 2009)"); m_Controls->m_OutputOdfImage->setHidden(false); break; case 4: m_Controls->m_Description->setText("SH recon. of the plain ADC-profiles"); m_Controls->m_OutputOdfImage->setHidden(false); break; case 5: m_Controls->m_Description->setText("SH recon. of the raw diffusion signal"); m_Controls->m_OutputOdfImage->setHidden(false); break; case 6: m_Controls->m_Description->setText("SH recon. of the multi shell diffusion signal (Aganj 2010)"); m_Controls->m_QBallSelectionBox->setHidden(false); m_Controls->m_OutputOdfImage->setHidden(false); break; } } void QmitkQBallReconstructionView::Reconstruct(int method, int normalization) { if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) { if(method == 0) { NumericalQBallReconstruction(m_Controls->m_ImageBox->GetSelectedNode(), normalization); } else if(method == 1) { AnalyticalQBallReconstruction(m_Controls->m_ImageBox->GetSelectedNode(), normalization); } else if(method == 2) { MultiQBallReconstruction(m_Controls->m_ImageBox->GetSelectedNode()); } } } void QmitkQBallReconstructionView::NumericalQBallReconstruction(mitk::DataNode::Pointer node, int normalization) { try { mitk::Image* vols = static_cast(node->GetData()); std::string nodename = node->GetName(); typedef itk::DiffusionQballReconstructionImageFilter QballReconstructionImageFilterType; ITKDiffusionImageType::Pointer itkVectorImagePointer = ITKDiffusionImageType::New(); mitk::CastToItkImage(vols, itkVectorImagePointer); QballReconstructionImageFilterType::Pointer filter = QballReconstructionImageFilterType::New(); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(vols)); filter->SetGradientImage(mitk::DiffusionPropertyHelper::GetGradientContainer(vols), itkVectorImagePointer); filter->SetThreshold( static_cast(m_Controls->m_QBallReconstructionThreasholdEdit->value()) ); std::string nodePostfix; switch(normalization) { case 0: { filter->SetNormalizationMethod(QballReconstructionImageFilterType::QBR_STANDARD); nodePostfix = "_Numerical_Qball"; break; } case 1: { filter->SetNormalizationMethod(QballReconstructionImageFilterType::QBR_B_ZERO_B_VALUE); nodePostfix = "_Numerical_ZeroBvalueNormalization_Qball"; break; } case 2: { filter->SetNormalizationMethod(QballReconstructionImageFilterType::QBR_B_ZERO); nodePostfix = "_NumericalQball_ZeroNormalization_Qball"; break; } case 3: { filter->SetNormalizationMethod(QballReconstructionImageFilterType::QBR_NONE); nodePostfix = "_NumericalQball_NoNormalization_Qball"; break; } default: { filter->SetNormalizationMethod(QballReconstructionImageFilterType::QBR_STANDARD); nodePostfix = "_NumericalQball_Qball"; } } filter->Update(); // ODFs TO DATATREE mitk::OdfImage::Pointer image = mitk::OdfImage::New(); image->InitializeByItk( filter->GetOutput() ); image->SetVolume( filter->GetOutput()->GetBufferPointer() ); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(vols, image); + mitk::DataNode::Pointer new_node = mitk::DataNode::New(); new_node->SetData( image ); new_node->SetName(nodename+nodePostfix); mitk::ProgressBar::GetInstance()->Progress(); GetDataStorage()->Add(new_node, node); this->GetRenderWindowPart()->RequestUpdate(); } catch (itk::ExceptionObject &ex) { MITK_INFO << ex ; QMessageBox::information(nullptr, "Reconstruction not possible:", ex.GetDescription()); return ; } } void QmitkQBallReconstructionView::AnalyticalQBallReconstruction( mitk::DataNode::Pointer node, int normalization) { try { auto lambda = m_Controls->m_QBallReconstructionLambdaLineEdit->value(); switch(m_Controls->m_QBallReconstructionMaxLLevelComboBox->currentIndex()) { case 0: { TemplatedAnalyticalQBallReconstruction<2>(node, lambda, normalization); break; } case 1: { TemplatedAnalyticalQBallReconstruction<4>(node, lambda, normalization); break; } case 2: { TemplatedAnalyticalQBallReconstruction<6>(node, lambda, normalization); break; } case 3: { TemplatedAnalyticalQBallReconstruction<8>(node, lambda, normalization); break; } case 4: { TemplatedAnalyticalQBallReconstruction<10>(node, lambda, normalization); break; } case 5: { TemplatedAnalyticalQBallReconstruction<12>(node, lambda, normalization); break; } } this->GetRenderWindowPart()->RequestUpdate(); } catch (itk::ExceptionObject &ex) { MITK_INFO << ex; QMessageBox::information(nullptr, "Reconstruction not possible:", ex.GetDescription()); return; } } template void QmitkQBallReconstructionView::TemplatedAnalyticalQBallReconstruction(mitk::DataNode* dataNodePointer, double lambda, int normalization) { typedef itk::AnalyticalDiffusionQballReconstructionImageFilter FilterType; typename FilterType::Pointer filter = FilterType::New(); mitk::Image* vols = dynamic_cast(dataNodePointer->GetData()); ITKDiffusionImageType::Pointer itkVectorImagePointer = ITKDiffusionImageType::New(); mitk::CastToItkImage(vols, itkVectorImagePointer); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(vols)); filter->SetGradientImage(mitk::DiffusionPropertyHelper::GetGradientContainer(vols), itkVectorImagePointer); filter->SetThreshold( static_cast(m_Controls->m_QBallReconstructionThreasholdEdit->value()) ); filter->SetLambda(lambda); std::string nodePostfix; switch(normalization) { case 0: { filter->SetNormalizationMethod(FilterType::QBAR_STANDARD); nodePostfix = "_Qball"; break; } case 1: { filter->SetNormalizationMethod(FilterType::QBAR_B_ZERO_B_VALUE); nodePostfix = "_1_Qball"; break; } case 2: { filter->SetNormalizationMethod(FilterType::QBAR_B_ZERO); nodePostfix = "_2_Qball"; break; } case 3: { filter->SetNormalizationMethod(FilterType::QBAR_NONE); nodePostfix = "_3_Qball"; break; } case 4: { filter->SetNormalizationMethod(FilterType::QBAR_ADC_ONLY); nodePostfix = "_AdcProfile"; break; } case 5: { filter->SetNormalizationMethod(FilterType::QBAR_RAW_SIGNAL); nodePostfix = "_RawSignal"; break; } case 6: { filter->SetNormalizationMethod(FilterType::QBAR_SOLID_ANGLE); nodePostfix = "_CSA_Qball"; break; } case 7: { filter->SetNormalizationMethod(FilterType::QBAR_NONNEG_SOLID_ANGLE); nodePostfix = "_NonNegCSA_Qball"; break; } default: { filter->SetNormalizationMethod(FilterType::QBAR_STANDARD); } } filter->Update(); mitk::Image::Pointer coeffsImage = dynamic_cast(mitk::ShImage::New().GetPointer()); coeffsImage->InitializeByItk( filter->GetCoefficientImage().GetPointer() ); coeffsImage->SetVolume( filter->GetCoefficientImage()->GetBufferPointer() ); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(vols, coeffsImage); mitk::DataNode::Pointer coeffsNode = mitk::DataNode::New(); coeffsNode->SetData( coeffsImage ); coeffsNode->SetProperty( "name", mitk::StringProperty::New(dataNodePointer->GetName() + nodePostfix + "_SH") ); GetDataStorage()->Add(coeffsNode, dataNodePointer); // ODFs TO DATATREE if(m_Controls->m_OutputOdfImage->isChecked()) { mitk::OdfImage::Pointer image = mitk::OdfImage::New(); image->InitializeByItk( filter->GetOutput() ); image->SetVolume( filter->GetOutput()->GetBufferPointer() ); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(vols, image); + mitk::DataNode::Pointer node=mitk::DataNode::New(); node->SetData( image ); node->SetName(dataNodePointer->GetName() + nodePostfix + "_Sampeld"); GetDataStorage()->Add(node, coeffsNode); } } void QmitkQBallReconstructionView::MultiQBallReconstruction(mitk::DataNode::Pointer node) { try { auto lambda = m_Controls->m_QBallReconstructionLambdaLineEdit->value(); switch(m_Controls->m_QBallReconstructionMaxLLevelComboBox->currentIndex()) { case 0: { TemplatedMultiQBallReconstruction<2>(lambda, node); break; } case 1: { TemplatedMultiQBallReconstruction<4>(lambda, node); break; } case 2: { TemplatedMultiQBallReconstruction<6>(lambda, node); break; } case 3: { TemplatedMultiQBallReconstruction<8>(lambda, node); break; } case 4: { TemplatedMultiQBallReconstruction<10>(lambda, node); break; } case 5: { TemplatedMultiQBallReconstruction<12>(lambda, node); break; } } } catch (itk::ExceptionObject &ex) { MITK_INFO << ex ; QMessageBox::information(nullptr, "Reconstruction not possible:", ex.GetDescription()); return ; } } template void QmitkQBallReconstructionView::TemplatedMultiQBallReconstruction(double lambda, mitk::DataNode* dataNodePointer) { typedef itk::DiffusionMultiShellQballReconstructionImageFilter FilterType; typename FilterType::Pointer filter = FilterType::New(); std::string nodename; dataNodePointer->GetStringProperty("name",nodename); mitk::Image* dwi = dynamic_cast(dataNodePointer->GetData()); BValueMapType currSelectionMap = m_ShellSelectorMap[dataNodePointer]->GetBValueSelctionMap(); if(currSelectionMap.size() != 4)// || currSelectionMap.find(0) != currSelectionMap.end()) { QMessageBox::information(nullptr, "Reconstruction not possible:" ,QString("Only three equidistant shells are supported. (ImageName: " + QString(nodename.c_str()) + ")")); return; } BValueMapType::reverse_iterator it1 = currSelectionMap.rbegin(); BValueMapType::reverse_iterator it2 = currSelectionMap.rbegin(); ++it2; // Get average distance int avdistance = 0; for(; it2 != currSelectionMap.rend(); ++it1,++it2) avdistance += static_cast(it1->first - it2->first); avdistance /= currSelectionMap.size()-1; // Check if all shells are using the same averae distance it1 = currSelectionMap.rbegin(); it2 = currSelectionMap.rbegin(); ++it2; for(; it2 != currSelectionMap.rend(); ++it1,++it2) { if(avdistance != static_cast(it1->first - it2->first)) { QMessageBox::information(nullptr, "Reconstruction not possible:" ,QString("Selected Shells are not in a equidistant configuration. (ImageName: " + QString(nodename.c_str()) + ")")); return; } } ITKDiffusionImageType::Pointer itkVectorImagePointer = ITKDiffusionImageType::New(); mitk::CastToItkImage(dwi, itkVectorImagePointer); filter->SetBValueMap(m_ShellSelectorMap[dataNodePointer]->GetBValueSelctionMap()); filter->SetGradientImage(mitk::DiffusionPropertyHelper::GetGradientContainer(dwi), itkVectorImagePointer, mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi)); filter->SetThreshold( static_cast(m_Controls->m_QBallReconstructionThreasholdEdit->value()) ); filter->SetLambda(lambda); filter->Update(); mitk::Image::Pointer coeffsImage = dynamic_cast(mitk::ShImage::New().GetPointer()); coeffsImage->InitializeByItk( filter->GetCoefficientImage().GetPointer() ); coeffsImage->SetVolume( filter->GetCoefficientImage()->GetBufferPointer() ); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(dwi, coeffsImage); mitk::DataNode::Pointer coeffsNode=mitk::DataNode::New(); coeffsNode->SetData( coeffsImage ); coeffsNode->SetProperty( "name", mitk::StringProperty::New(dataNodePointer->GetName() + "_SH_MultiShell_Qball_SH") ); GetDataStorage()->Add(coeffsNode, dataNodePointer); if(m_Controls->m_OutputOdfImage->isChecked()) { // ODFs TO DATATREE mitk::OdfImage::Pointer image = mitk::OdfImage::New(); image->InitializeByItk( filter->GetOutput() ); image->SetVolume( filter->GetOutput()->GetBufferPointer() ); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(dwi, image); + mitk::DataNode::Pointer node=mitk::DataNode::New(); node->SetData( image ); node->SetName(dataNodePointer->GetName() + "_SH_MultiShell_Qball_Sampled"); GetDataStorage()->Add(node, coeffsNode); } } void QmitkQBallReconstructionView::GenerateShellSelectionUI(mitk::DataNode::Pointer node) { std::map tempMap; if(m_ShellSelectorMap.find( node.GetPointer() ) != m_ShellSelectorMap.end()) { tempMap[node.GetPointer()] = m_ShellSelectorMap[node.GetPointer()]; m_ShellSelectorMap.erase(node.GetPointer()); } else { tempMap[node.GetPointer()] = new QbrShellSelection(this, node ); tempMap[node.GetPointer()]->SetVisible(true); } for(std::map::iterator it = m_ShellSelectorMap.begin(); it != m_ShellSelectorMap.end();it ++) { delete it->second; } m_ShellSelectorMap.clear(); m_ShellSelectorMap = tempMap; } void QmitkQBallReconstructionView::PreviewThreshold(short threshold) { if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) { mitk::Image* vols = static_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData()); // Extract b0 image ITKDiffusionImageType::Pointer itkVectorImagePointer = ITKDiffusionImageType::New(); mitk::CastToItkImage(vols, itkVectorImagePointer); 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_ImageBox->GetSelectedNode())) { node = this->GetDataStorage()->GetNamedDerivedNode("ThresholdOverlay", m_Controls->m_ImageBox->GetSelectedNode()); } else { // create a new node, to show thresholded values node = mitk::DataNode::New(); GetDataStorage()->Add( node, m_Controls->m_ImageBox->GetSelectedNode() ); node->SetProperty( "name", mitk::StringProperty::New("ThresholdOverlay")); node->SetBoolProperty("helper object", true); } node->SetData( mitkImage ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } 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 5952e52..7dbae03 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,931 +1,933 @@ /*=================================================================== 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); 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; GradientDirectionContainerType* 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(); - - // TENSORS TO DATATREE 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->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(); 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(); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionView.cpp index e6c577c..d2f9aaf 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionView.cpp @@ -1,124 +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. ===================================================================*/ //misc #define _USE_MATH_DEFINES #include // Blueberry #include #include // Qmitk #include "QmitkHeadMotionCorrectionView.h" // MITK #include #include // Qt #include #include #include #include #include #include #define _USE_MATH_DEFINES #include const std::string QmitkHeadMotionCorrectionView::VIEW_ID = "org.mitk.views.headmotioncorrectionview"; QmitkHeadMotionCorrectionView::QmitkHeadMotionCorrectionView() : QmitkAbstractView() , m_Controls( 0 ) , m_DiffusionImage( nullptr ) { } // Destructor QmitkHeadMotionCorrectionView::~QmitkHeadMotionCorrectionView() { } void QmitkHeadMotionCorrectionView::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::QmitkHeadMotionCorrectionViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_ImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGUI()) ); connect( m_Controls->m_RegistrationStartButton, SIGNAL(clicked()), this, SLOT(StartCorrection()) ); this->m_Parent = parent; m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); m_Controls->m_ImageBox->SetPredicate(isImagePredicate); UpdateGUI(); } } void QmitkHeadMotionCorrectionView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& ) { } void QmitkHeadMotionCorrectionView::UpdateGUI() { if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) { m_Controls->m_RegistrationStartButton->setEnabled(true); m_Controls->m_RegistrationStartButton->setToolTip("Start Registration"); } else { m_Controls->m_RegistrationStartButton->setEnabled(false); m_Controls->m_RegistrationStartButton->setToolTip("No Diffusion image selected."); } } void QmitkHeadMotionCorrectionView::SetFocus() { UpdateGUI(); m_Controls->m_RegistrationStartButton->setFocus(); } void QmitkHeadMotionCorrectionView::StartCorrection() { mitk::DataNode::Pointer node = m_Controls->m_ImageBox->GetSelectedNode(); mitk::Image::Pointer inImage = dynamic_cast(node->GetData()); if (!mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(inImage)) { QMessageBox::warning(nullptr, "Image not processed", "Input is not a diffusion-weighted image!"); return; } mitk::DWIHeadMotionCorrectionFilter::Pointer registerer = mitk::DWIHeadMotionCorrectionFilter::New(); registerer->SetInput(inImage); registerer->Update(); mitk::Image::Pointer image = registerer->GetCorrectedImage(); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(inImage, image); + mitk::DataNode::Pointer corrected_node = mitk::DataNode::New(); corrected_node->SetData( image ); QString name(node->GetName().c_str()); name += "_Corrected"; corrected_node->SetName(name.toStdString()); GetDataStorage()->Add(corrected_node, node); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationView.cpp index da87097..faad923 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationView.cpp @@ -1,403 +1,405 @@ /*=================================================================== 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. ===================================================================*/ //misc #define _USE_MATH_DEFINES #include // Blueberry #include #include // Qmitk #include "QmitkSimpleRegistrationView.h" // MITK #include #include #include #include #include #include #include #include #include #include #include #include // Qt #include #define _USE_MATH_DEFINES #include const std::string QmitkSimpleRegistrationView::VIEW_ID = "org.mitk.views.simpleregistrationview"; QmitkSimpleRegistrationView::QmitkSimpleRegistrationView() : QmitkAbstractView() , m_Controls( 0 ) , m_RegistrationType(0) { } // Destructor QmitkSimpleRegistrationView::~QmitkSimpleRegistrationView() { } void QmitkSimpleRegistrationView::StartRegistration() { QmitkRegistrationJob* pJob; if (m_Controls->m_RegBox->currentIndex()==0) { mitk::MultiModalRigidDefaultRegistrationAlgorithm< ItkFloatImageType >::Pointer algo = mitk::MultiModalRigidDefaultRegistrationAlgorithm< ItkFloatImageType >::New(); pJob = new QmitkRegistrationJob(algo); m_RegistrationType = 0; } else { mitk::MultiModalAffineDefaultRegistrationAlgorithm< ItkFloatImageType >::Pointer algo = mitk::MultiModalAffineDefaultRegistrationAlgorithm< ItkFloatImageType >::New(); pJob = new QmitkRegistrationJob(algo); m_RegistrationType = 1; } pJob->setAutoDelete(true); m_MovingImageNode = m_Controls->m_MovingImageBox->GetSelectedNode(); mitk::Image::Pointer movingImage = dynamic_cast(m_MovingImageNode->GetData()); if (mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(movingImage)) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(movingImage, itkVectorImagePointer); itk::ExtractDwiChannelFilter< short >::Pointer filter = itk::ExtractDwiChannelFilter< short >::New(); filter->SetInput( itkVectorImagePointer); filter->SetChannelIndex(m_Controls->m_MovingChannelBox->value()); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( filter->GetOutput() ); newImage->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); pJob->m_spMovingData = newImage; } else pJob->m_spMovingData = movingImage; mitk::Image::Pointer fixedImage = dynamic_cast(m_Controls->m_FixedImageBox->GetSelectedNode()->GetData()); if (mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(fixedImage)) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(fixedImage, itkVectorImagePointer); itk::ExtractDwiChannelFilter< short >::Pointer filter = itk::ExtractDwiChannelFilter< short >::New(); filter->SetInput( itkVectorImagePointer); filter->SetChannelIndex(m_Controls->m_MovingChannelBox->value()); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( filter->GetOutput() ); newImage->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); pJob->m_spTargetData = newImage; } else pJob->m_spTargetData = fixedImage; pJob->m_TargetDataUID = mitk::EnsureUID(m_Controls->m_FixedImageBox->GetSelectedNode()->GetData()); pJob->m_MovingDataUID = mitk::EnsureUID(m_Controls->m_MovingImageBox->GetSelectedNode()->GetData()); connect(pJob, SIGNAL(RegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer, const QmitkRegistrationJob*)), this, SLOT(OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer, const QmitkRegistrationJob*)), Qt::BlockingQueuedConnection); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); m_Controls->m_RegistrationStartButton->setEnabled(false); m_Controls->m_RegistrationStartButton->setText("Registration in progress ..."); } void QmitkSimpleRegistrationView::OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer spResultRegistration, const QmitkRegistrationJob* job) { mitk::Image::Pointer movingImage = dynamic_cast(m_MovingImageNode->GetData()); mitk::Image::Pointer image; if (m_RegistrationType==0 && !m_Controls->m_ResampleBox->isChecked()) { image = mitk::ImageMappingHelper::refineGeometry(movingImage, spResultRegistration, true); mitk::DiffusionPropertyHelper::CopyProperties(movingImage, image, true); auto reg = spResultRegistration->GetRegistration(); typedef mitk::DiffusionImageCorrectionFilter CorrectionFilterType; CorrectionFilterType::Pointer corrector = CorrectionFilterType::New(); corrector->SetImage( image ); corrector->CorrectDirections( mitk::MITKRegistrationHelper::getAffineMatrix(reg, false)->GetMatrix().GetVnlMatrix() ); } else { if (!mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(movingImage)) { image = mitk::ImageMappingHelper::map(movingImage, spResultRegistration, false, 0, job->m_spTargetData->GetGeometry(), false, 0, mitk::ImageMappingInterpolator::BSpline_3); } else { typedef itk::ComposeImageFilter < ITKDiffusionVolumeType > ComposeFilterType; ComposeFilterType::Pointer composer = ComposeFilterType::New(); ItkDwiType::Pointer itkVectorImagePointer = mitk::DiffusionPropertyHelper::GetItkVectorImage(movingImage); for (unsigned int i=0; iGetVectorLength(); ++i) { itk::ExtractDwiChannelFilter< short >::Pointer filter = itk::ExtractDwiChannelFilter< short >::New(); filter->SetInput( itkVectorImagePointer); filter->SetChannelIndex(i); filter->Update(); mitk::Image::Pointer gradientVolume = mitk::Image::New(); gradientVolume->InitializeByItk( filter->GetOutput() ); gradientVolume->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); mitk::Image::Pointer registered_mitk_image = mitk::ImageMappingHelper::map(gradientVolume, spResultRegistration, false, 0, job->m_spTargetData->GetGeometry(), false, 0, mitk::ImageMappingInterpolator::BSpline_3); ITKDiffusionVolumeType::Pointer registered_itk_image = ITKDiffusionVolumeType::New(); mitk::CastToItkImage(registered_mitk_image, registered_itk_image); composer->SetInput(i, registered_itk_image); } composer->Update(); image = mitk::GrabItkImageMemory( composer->GetOutput() ); mitk::DiffusionPropertyHelper::CopyProperties(movingImage, image, true); auto reg = spResultRegistration->GetRegistration(); typedef mitk::DiffusionImageCorrectionFilter CorrectionFilterType; CorrectionFilterType::Pointer corrector = CorrectionFilterType::New(); corrector->SetImage( image ); corrector->CorrectDirections( mitk::MITKRegistrationHelper::getAffineMatrix(reg, false)->GetMatrix().GetVnlMatrix() ); } } if (mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image)) mitk::DiffusionPropertyHelper::InitializeImage( image ); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(movingImage, image); mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); resultNode->SetData(image); if (m_MovingImageNode.IsNotNull()) { m_MovingImageNode->SetVisibility(false); QString name = m_MovingImageNode->GetName().c_str(); if (m_RegistrationType==0) resultNode->SetName((name+"_registered (rigid)").toStdString().c_str()); else resultNode->SetName((name+"_registered (affine)").toStdString().c_str()); } else { if (m_RegistrationType==0) resultNode->SetName("Registered (rigid)"); else resultNode->SetName("Registered (affine)"); } // resultNode->SetOpacity(0.6); // resultNode->SetColor(0.0, 0.0, 1.0); GetDataStorage()->Add(resultNode); mitk::RenderingManager::GetInstance()->InitializeViews( resultNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); if (m_Controls->m_RegOutputBox->isChecked()) { mitk::DataNode::Pointer registration_node = mitk::DataNode::New(); registration_node->SetData(spResultRegistration); if (m_RegistrationType==0) registration_node->SetName("Registration Object (rigid)"); else registration_node->SetName("Registration Object (affine)"); GetDataStorage()->Add(registration_node, resultNode); } this->GetRenderWindowPart()->RequestUpdate(); m_Controls->m_RegistrationStartButton->setEnabled(true); m_Controls->m_RegistrationStartButton->setText("Start Registration"); m_MovingImageNode = nullptr; TractoChanged(); } void QmitkSimpleRegistrationView::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::QmitkSimpleRegistrationViewControls; m_Controls->setupUi( parent ); m_Controls->m_FixedImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MovingImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); m_Controls->m_FixedImageBox->SetPredicate(isImagePredicate); m_Controls->m_MovingImageBox->SetPredicate(isImagePredicate); mitk::TNodePredicateDataType::Pointer isFib = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isReg = mitk::TNodePredicateDataType::New(); m_Controls->m_TractoBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_RegObjectBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_TractoBox->SetPredicate(isFib); m_Controls->m_RegObjectBox->SetPredicate(isReg); connect( m_Controls->m_FixedImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(FixedImageChanged()) ); connect( m_Controls->m_MovingImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(MovingImageChanged()) ); connect( m_Controls->m_TractoBox, SIGNAL(currentIndexChanged(int)), this, SLOT(TractoChanged()) ); connect( m_Controls->m_RegObjectBox, SIGNAL(currentIndexChanged(int)), this, SLOT(TractoChanged()) ); connect( m_Controls->m_RegistrationStartButton, SIGNAL(clicked()), this, SLOT(StartRegistration()) ); connect( m_Controls->m_TractoRegistrationStartButton, SIGNAL(clicked()), this, SLOT(StartTractoRegistration()) ); FixedImageChanged(); MovingImageChanged(); TractoChanged(); } } void QmitkSimpleRegistrationView::StartTractoRegistration() { mitk::FiberBundle::Pointer fib = dynamic_cast(m_Controls->m_TractoBox->GetSelectedNode()->GetData()); mitk::MAPRegistrationWrapper::Pointer reg = dynamic_cast(m_Controls->m_RegObjectBox->GetSelectedNode()->GetData()); mitk::MITKRegistrationHelper::Affine3DTransformType::Pointer affine = mitk::MITKRegistrationHelper::getAffineMatrix(reg, false); mitk::FiberBundle::Pointer fib_copy = fib->GetDeepCopy(); fib_copy->TransformFibers(affine); + mitk::DiffusionPropertyHelper::CopyProperties(fib, fib_copy); mitk::DataNode::Pointer registration_node = mitk::DataNode::New(); registration_node->SetData(fib_copy); QString name = m_Controls->m_TractoBox->GetSelectedNode()->GetName().c_str(); registration_node->SetName((name+"_registered").toStdString().c_str()); GetDataStorage()->Add(registration_node, m_Controls->m_TractoBox->GetSelectedNode()); } void QmitkSimpleRegistrationView::TractoChanged() { if (m_Controls->m_RegObjectBox->GetSelectedNode().IsNotNull() && m_Controls->m_TractoBox->GetSelectedNode().IsNotNull()) m_Controls->m_TractoRegistrationStartButton->setEnabled(true); else m_Controls->m_TractoRegistrationStartButton->setEnabled(false); } void QmitkSimpleRegistrationView::FixedImageChanged() { if (m_Controls->m_FixedImageBox->GetSelectedNode().IsNotNull()) { mitk::Image::Pointer image = dynamic_cast(m_Controls->m_FixedImageBox->GetSelectedNode()->GetData()); int channels = image->GetNumberOfChannels(); int dims = image->GetDimension(); int fourth_dim_size = image->GetTimeSteps(); bool isdiff = mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image); if (dims==4 || channels>1) { m_Controls->m_FixedChannelBox->setEnabled(false); m_Controls->m_RegistrationStartButton->setEnabled(false); } if (isdiff) { m_Controls->m_FixedChannelBox->setEnabled(true); if (fourth_dim_size>1) m_Controls->m_FixedChannelBox->setMaximum(fourth_dim_size-1); else if (isdiff) m_Controls->m_FixedChannelBox->setMaximum(mitk::DiffusionPropertyHelper::GetGradientContainer(image)->Size()-1); } else { m_Controls->m_FixedChannelBox->setEnabled(false); } m_Controls->m_RegistrationStartButton->setEnabled(true); } else { m_Controls->m_FixedChannelBox->setEnabled(false); m_Controls->m_RegistrationStartButton->setEnabled(false); } } void QmitkSimpleRegistrationView::MovingImageChanged() { if (m_Controls->m_MovingImageBox->GetSelectedNode().IsNotNull()) { mitk::Image::Pointer image = dynamic_cast(m_Controls->m_MovingImageBox->GetSelectedNode()->GetData()); int channels = image->GetNumberOfChannels(); int dims = image->GetDimension(); int fourth_dim_size = image->GetTimeSteps(); bool isdiff = mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image); if (dims==4 || channels>1) { m_Controls->m_MovingChannelBox->setEnabled(false); m_Controls->m_RegistrationStartButton->setEnabled(false); } if (isdiff) { m_Controls->m_MovingChannelBox->setEnabled(true); if (fourth_dim_size>1) m_Controls->m_MovingChannelBox->setMaximum(fourth_dim_size-1); else if (isdiff) m_Controls->m_MovingChannelBox->setMaximum(mitk::DiffusionPropertyHelper::GetGradientContainer(image)->Size()-1); } else { m_Controls->m_MovingChannelBox->setEnabled(false); } m_Controls->m_RegistrationStartButton->setEnabled(true); } else { m_Controls->m_MovingChannelBox->setEnabled(false); m_Controls->m_RegistrationStartButton->setEnabled(false); } } void QmitkSimpleRegistrationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& ) { FixedImageChanged(); MovingImageChanged(); TractoChanged(); } void QmitkSimpleRegistrationView::SetFocus() { m_Controls->m_RegistrationStartButton->setFocus(); FixedImageChanged(); MovingImageChanged(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingView.cpp index 150ddb3..227276e 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingView.cpp @@ -1,608 +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. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkGibbsTrackingView.h" // Qt #include #include #include #include // MITK #include #include #include #include #include #include #include #include #include #include // ITK #include #include #include // MISC #include QmitkTrackingWorker::QmitkTrackingWorker(QmitkGibbsTrackingView* view) : m_View(view) { } void QmitkTrackingWorker::run() { m_View->m_GlobalTracker = QmitkGibbsTrackingView::GibbsTrackingFilterType::New(); m_View->m_GlobalTracker->SetOdfImage(m_View->m_ItkOdfImage); m_View->m_GlobalTracker->SetTensorImage(m_View->m_ItkTensorImage); m_View->m_GlobalTracker->SetMaskImage(m_View->m_MaskImage); m_View->m_GlobalTracker->SetStartTemperature((float)m_View->m_Controls->m_StartTempSlider->value()/100); m_View->m_GlobalTracker->SetEndTemperature((float)m_View->m_Controls->m_EndTempSlider->value()/10000); m_View->m_GlobalTracker->SetIterations(m_View->m_Controls->m_IterationsBox->text().toDouble()); m_View->m_GlobalTracker->SetParticleWeight((float)m_View->m_Controls->m_ParticleWeightSlider->value()/10000); m_View->m_GlobalTracker->SetParticleWidth((float)(m_View->m_Controls->m_ParticleWidthSlider->value())/10); m_View->m_GlobalTracker->SetParticleLength((float)(m_View->m_Controls->m_ParticleLengthSlider->value())/10); m_View->m_GlobalTracker->SetInexBalance((float)m_View->m_Controls->m_InExBalanceSlider->value()/10); m_View->m_GlobalTracker->SetMinFiberLength(m_View->m_Controls->m_FiberLengthSlider->value()); m_View->m_GlobalTracker->SetCurvatureThreshold(cos((float)m_View->m_Controls->m_CurvatureThresholdSlider->value()*itk::Math::pi/180)); m_View->m_GlobalTracker->SetRandomSeed(m_View->m_Controls->m_RandomSeedSlider->value()); try{ m_View->m_GlobalTracker->Update(); } catch( mitk::Exception& e ) { MITK_ERROR << "Internal error occured: " << e.what() << "\nAborting"; } m_View->m_TrackingThread.quit(); } const std::string QmitkGibbsTrackingView::VIEW_ID = "org.mitk.views.gibbstracking"; QmitkGibbsTrackingView::QmitkGibbsTrackingView() : QmitkAbstractView() , m_Controls( 0 ) , m_TrackingNode(nullptr) , m_FiberBundle(nullptr) , m_MaskImage(nullptr) , m_TensorImage(nullptr) , m_OdfImage(nullptr) , m_ItkOdfImage(nullptr) , m_ItkTensorImage(nullptr) , m_ImageNode(nullptr) , m_MaskImageNode(nullptr) , m_FiberBundleNode(nullptr) , m_ThreadIsRunning(false) , m_ElapsedTime(0) , m_GlobalTracker(nullptr) , m_TrackingWorker(this) { m_TrackingWorker.moveToThread(&m_TrackingThread); connect(&m_TrackingThread, SIGNAL(started()), this, SLOT(BeforeThread())); connect(&m_TrackingThread, SIGNAL(started()), &m_TrackingWorker, SLOT(run())); connect(&m_TrackingThread, SIGNAL(finished()), this, SLOT(AfterThread())); m_TrackingTimer = new QTimer(this); } QmitkGibbsTrackingView::~QmitkGibbsTrackingView() { if (m_GlobalTracker.IsNull()) return; m_GlobalTracker->SetAbortTracking(true); m_TrackingThread.wait(); } // update tracking status and generate fiber bundle void QmitkGibbsTrackingView::TimerUpdate() { UpdateTrackingStatus(); GenerateFiberBundle(); } // tell global tractography filter to stop after current step void QmitkGibbsTrackingView::StopGibbsTracking() { if (m_GlobalTracker.IsNull()) return; m_GlobalTracker->SetAbortTracking(true); m_Controls->m_TrackingStop->setEnabled(false); m_Controls->m_TrackingStop->setText("Stopping Tractography ..."); m_TrackingNode = nullptr; } // update gui elements and generate fiber bundle after tracking is finished void QmitkGibbsTrackingView::AfterThread() { m_ThreadIsRunning = false; m_TrackingTimer->stop(); UpdateGUI(); if( !m_GlobalTracker->GetIsInValidState() ) { QMessageBox::critical( nullptr, "Gibbs Tracking", "An internal error occured. Tracking aborted.\n Please check the log for details." ); m_FiberBundleNode = nullptr; return; } UpdateTrackingStatus(); if(m_Controls->m_ParticleWeightSlider->value()==0) { m_Controls->m_ParticleWeightLabel->setText(QString::number(m_GlobalTracker->GetParticleWeight())); m_Controls->m_ParticleWeightSlider->setValue(m_GlobalTracker->GetParticleWeight()*10000); } if(m_Controls->m_ParticleWidthSlider->value()==0) { m_Controls->m_ParticleWidthLabel->setText(QString::number(m_GlobalTracker->GetParticleWidth())); m_Controls->m_ParticleWidthSlider->setValue(m_GlobalTracker->GetParticleWidth()*10); } if(m_Controls->m_ParticleLengthSlider->value()==0) { m_Controls->m_ParticleLengthLabel->setText(QString::number(m_GlobalTracker->GetParticleLength())); m_Controls->m_ParticleLengthSlider->setValue(m_GlobalTracker->GetParticleLength()*10); } GenerateFiberBundle(); m_FiberBundleNode = 0; m_GlobalTracker = 0; // images not needed anymore ( relevant only for computation ) // we need to release them to remove the memory access block created through CastToItk<> calls this->m_ItkOdfImage = 0; this->m_ItkTensorImage = 0; } // start tracking timer and update gui elements before tracking is started void QmitkGibbsTrackingView::BeforeThread() { m_ThreadIsRunning = true; m_TrackingTime = QTime::currentTime(); m_ElapsedTime = 0; m_TrackingTimer->start(1000); UpdateGUI(); } // setup gui elements and signal/slot connections void QmitkGibbsTrackingView::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::QmitkGibbsTrackingViewControls; m_Controls->setupUi( parent ); AdvancedSettings(); connect( m_TrackingTimer, SIGNAL(timeout()), this, SLOT(TimerUpdate()) ); connect( m_Controls->m_TrackingStop, SIGNAL(clicked()), this, SLOT(StopGibbsTracking()) ); connect( m_Controls->m_TrackingStart, SIGNAL(clicked()), this, SLOT(StartGibbsTracking()) ); connect( m_Controls->m_AdvancedSettingsCheckbox, SIGNAL(clicked()), this, SLOT(AdvancedSettings()) ); connect( m_Controls->m_SaveTrackingParameters, SIGNAL(clicked()), this, SLOT(SaveTrackingParameters()) ); connect( m_Controls->m_LoadTrackingParameters, SIGNAL(clicked()), this, SLOT(LoadTrackingParameters()) ); connect( m_Controls->m_ParticleWidthSlider, SIGNAL(valueChanged(int)), this, SLOT(SetParticleWidth(int)) ); connect( m_Controls->m_ParticleLengthSlider, SIGNAL(valueChanged(int)), this, SLOT(SetParticleLength(int)) ); connect( m_Controls->m_InExBalanceSlider, SIGNAL(valueChanged(int)), this, SLOT(SetInExBalance(int)) ); connect( m_Controls->m_FiberLengthSlider, SIGNAL(valueChanged(int)), this, SLOT(SetFiberLength(int)) ); connect( m_Controls->m_ParticleWeightSlider, SIGNAL(valueChanged(int)), this, SLOT(SetParticleWeight(int)) ); connect( m_Controls->m_StartTempSlider, SIGNAL(valueChanged(int)), this, SLOT(SetStartTemp(int)) ); connect( m_Controls->m_EndTempSlider, SIGNAL(valueChanged(int)), this, SLOT(SetEndTemp(int)) ); connect( m_Controls->m_CurvatureThresholdSlider, SIGNAL(valueChanged(int)), this, SLOT(SetCurvatureThreshold(int)) ); connect( m_Controls->m_RandomSeedSlider, SIGNAL(valueChanged(int)), this, SLOT(SetRandomSeed(int)) ); connect( m_Controls->m_OutputFileButton, SIGNAL(clicked()), this, SLOT(SetOutputFile()) ); m_Controls->m_InputImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isOdfImagePredicate = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isTensorImagePredicate = mitk::TNodePredicateDataType::New(); m_Controls->m_InputImageBox->SetPredicate( mitk::NodePredicateOr::New(isOdfImagePredicate, isTensorImagePredicate) ); m_Controls->m_MaskImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MaskImageBox->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_MaskImageBox->SetPredicate( mitk::NodePredicateAnd::New(isBinaryPredicate, mitk::NodePredicateAnd::New(isImagePredicate, is3D)) ); connect( (QObject*)(m_Controls->m_MaskImageBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGUI())); connect( (QObject*)(m_Controls->m_InputImageBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGUI())); } } void QmitkGibbsTrackingView::SetFocus() { m_Controls->m_TrackingStart->setFocus(); } void QmitkGibbsTrackingView::SetInExBalance(int value) { m_Controls->m_InExBalanceLabel->setText(QString::number((float)value/10)); } void QmitkGibbsTrackingView::SetFiberLength(int value) { m_Controls->m_FiberLengthLabel->setText(QString::number(value)+"mm"); } void QmitkGibbsTrackingView::SetRandomSeed(int value) { if (value>=0) m_Controls->m_RandomSeedLabel->setText(QString::number(value)); else m_Controls->m_RandomSeedLabel->setText("auto"); } void QmitkGibbsTrackingView::SetParticleWeight(int value) { if (value>0) m_Controls->m_ParticleWeightLabel->setText(QString::number((float)value/10000)); else m_Controls->m_ParticleWeightLabel->setText("auto"); } void QmitkGibbsTrackingView::SetStartTemp(int value) { m_Controls->m_StartTempLabel->setText(QString::number((float)value/100)); } void QmitkGibbsTrackingView::SetEndTemp(int value) { m_Controls->m_EndTempLabel->setText(QString::number((float)value/10000)); } void QmitkGibbsTrackingView::SetParticleWidth(int value) { if (value>0) m_Controls->m_ParticleWidthLabel->setText(QString::number((float)value/10)+" mm"); else m_Controls->m_ParticleWidthLabel->setText("auto"); } void QmitkGibbsTrackingView::SetParticleLength(int value) { if (value>0) m_Controls->m_ParticleLengthLabel->setText(QString::number((float)value/10)+" mm"); else m_Controls->m_ParticleLengthLabel->setText("auto"); } void QmitkGibbsTrackingView::SetCurvatureThreshold(int value) { m_Controls->m_CurvatureThresholdLabel->setText(QString::number(value)+"°"); } // called if datamanager selection changes void QmitkGibbsTrackingView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& ) { UpdateGUI(); } void QmitkGibbsTrackingView::NodeRemoved(const mitk::DataNode * node) { if (m_ThreadIsRunning) { if (node==m_TrackingNode.GetPointer()) { StopGibbsTracking(); } } } // update gui elements displaying trackings status void QmitkGibbsTrackingView::UpdateTrackingStatus() { if (m_GlobalTracker.IsNull()) return; m_ElapsedTime += m_TrackingTime.elapsed()/1000; m_TrackingTime.restart(); unsigned long hours = m_ElapsedTime/3600; unsigned long minutes = (m_ElapsedTime%3600)/60; unsigned long seconds = m_ElapsedTime%60; m_Controls->m_ProposalAcceptance->setText(QString::number(m_GlobalTracker->GetProposalAcceptance()*100)+"%"); m_Controls->m_TrackingTimeLabel->setText( QString::number(hours)+QString("h ")+QString::number(minutes)+QString("m ")+QString::number(seconds)+QString("s") ); m_Controls->m_NumConnectionsLabel->setText( QString::number(m_GlobalTracker->GetNumConnections()) ); m_Controls->m_NumParticlesLabel->setText( QString::number(m_GlobalTracker->GetNumParticles()) ); m_Controls->m_CurrentStepLabel->setText( QString::number(100*m_GlobalTracker->GetCurrentIteration()/m_GlobalTracker->GetIterations())+"%" ); m_Controls->m_AcceptedFibersLabel->setText( QString::number(m_GlobalTracker->GetNumAcceptedFibers()) ); } // update gui elements (enable/disable elements and set tooltips) void QmitkGibbsTrackingView::UpdateGUI() { if (!m_ThreadIsRunning && m_Controls->m_InputImageBox->GetSelectedNode().IsNotNull()) { m_Controls->m_TrackingStop->setEnabled(false); m_Controls->m_TrackingStart->setEnabled(true); m_Controls->m_LoadTrackingParameters->setEnabled(true); m_Controls->m_IterationsBox->setEnabled(true); m_Controls->m_AdvancedFrame->setEnabled(true); m_Controls->m_TrackingStop->setText("Stop Tractography"); m_Controls->m_TrackingStart->setToolTip("Start tractography. No further change of parameters possible."); m_Controls->m_TrackingStop->setToolTip(""); m_Controls->m_MaskImageBox->setEnabled(true); m_Controls->m_InputImageBox->setEnabled(true); } else if (!m_ThreadIsRunning) { m_Controls->m_TrackingStop->setEnabled(false); m_Controls->m_TrackingStart->setEnabled(false); m_Controls->m_LoadTrackingParameters->setEnabled(true); m_Controls->m_IterationsBox->setEnabled(true); m_Controls->m_AdvancedFrame->setEnabled(true); m_Controls->m_TrackingStop->setText("Stop Tractography"); m_Controls->m_TrackingStart->setToolTip("No ODF image selected."); m_Controls->m_TrackingStop->setToolTip(""); m_Controls->m_MaskImageBox->setEnabled(true); m_Controls->m_InputImageBox->setEnabled(true); } else { m_Controls->m_TrackingStop->setEnabled(true); m_Controls->m_TrackingStart->setEnabled(false); m_Controls->m_LoadTrackingParameters->setEnabled(false); m_Controls->m_IterationsBox->setEnabled(false); m_Controls->m_AdvancedFrame->setEnabled(false); m_Controls->m_AdvancedFrame->setVisible(false); m_Controls->m_AdvancedSettingsCheckbox->setChecked(false); m_Controls->m_TrackingStart->setToolTip("Tracking in progress."); m_Controls->m_TrackingStop->setToolTip("Stop tracking and display results."); m_Controls->m_MaskImageBox->setEnabled(false); m_Controls->m_InputImageBox->setEnabled(false); } } // show/hide advanced settings frame void QmitkGibbsTrackingView::AdvancedSettings() { m_Controls->m_AdvancedFrame->setVisible(m_Controls->m_AdvancedSettingsCheckbox->isChecked()); } // check for mask and odf and start tracking thread void QmitkGibbsTrackingView::StartGibbsTracking() { if(m_ThreadIsRunning) { MITK_WARN("QmitkGibbsTrackingView")<<"Thread already running!"; return; } m_GlobalTracker = nullptr; if (m_Controls->m_InputImageBox->GetSelectedNode().IsNull()) { QMessageBox::information( nullptr, "Warning", "Please load and select a Odf image before starting image processing."); return; } m_ImageNode = m_Controls->m_InputImageBox->GetSelectedNode(); if (dynamic_cast(m_ImageNode->GetData())) m_OdfImage = dynamic_cast(m_ImageNode->GetData()); else if (dynamic_cast(m_ImageNode->GetData())) m_TensorImage = dynamic_cast(m_ImageNode->GetData()); if (m_OdfImage.IsNull() && m_TensorImage.IsNull()) return; // cast odf to itk m_TrackingNode = m_ImageNode; m_ItkTensorImage = nullptr; m_ItkOdfImage = nullptr; m_MaskImage = nullptr; if (m_OdfImage.IsNotNull()) { m_ItkOdfImage = ItkOdfImgType::New(); mitk::CastToItkImage(m_OdfImage, m_ItkOdfImage); } else { m_ItkTensorImage = ItkTensorImage::New(); mitk::CastToItkImage(m_TensorImage, m_ItkTensorImage); } // mask image found? // catch exceptions thrown by the itkAccess macros try{ if(m_Controls->m_MaskImageBox->GetSelectedNode().IsNotNull()) { m_MaskImageNode = m_Controls->m_MaskImageBox->GetSelectedNode(); if (dynamic_cast(m_MaskImageNode->GetData())) mitk::CastToItkImage(dynamic_cast(m_MaskImageNode->GetData()), m_MaskImage); } } catch(...){}; // start worker thread m_TrackingThread.start(QThread::LowestPriority); } // generate mitkFiberBundle from tracking filter output void QmitkGibbsTrackingView::GenerateFiberBundle() { if (m_GlobalTracker.IsNull() || (!(m_Controls->m_VisualizationCheckbox->isChecked() || m_Controls->m_VisualizeOnceButton->isChecked()) && m_ThreadIsRunning)) return; if (m_Controls->m_VisualizeOnceButton->isChecked()) m_Controls->m_VisualizeOnceButton->setChecked(false); vtkSmartPointer fiberBundle = m_GlobalTracker->GetFiberBundle(); if ( m_GlobalTracker->GetNumAcceptedFibers()==0 ) return; m_FiberBundle = mitk::FiberBundle::New(fiberBundle); m_FiberBundle->SetTrackVisHeader(dynamic_cast(m_ImageNode->GetData())->GetGeometry()); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(m_ImageNode->GetData(), m_FiberBundle); if (m_FiberBundleNode.IsNotNull()){ GetDataStorage()->Remove(m_FiberBundleNode); m_FiberBundleNode = 0; } m_GlobalTracker->SetDicomProperties(m_FiberBundle); m_FiberBundleNode = mitk::DataNode::New(); m_FiberBundleNode->SetData(m_FiberBundle); QString name("FiberBundle_"); name += m_ImageNode->GetName().c_str(); name += "_Gibbs"; m_FiberBundleNode->SetName(name.toStdString()); m_FiberBundleNode->SetVisibility(true); if (!m_OutputFileName.isEmpty() && !m_ThreadIsRunning) { try { mitk::IOUtil::Save(m_FiberBundle.GetPointer(),m_OutputFileName.toStdString()); QMessageBox::information(nullptr, "Fiber bundle saved to", m_OutputFileName); } catch (itk::ExceptionObject &ex) { QMessageBox::information(nullptr, "Fiber bundle could not be saved", QString("%1\n%2\n%3\n%4\n%5\n%6").arg(ex.GetNameOfClass()).arg(ex.GetFile()).arg(ex.GetLine()).arg(ex.GetLocation()).arg(ex.what()).arg(ex.GetDescription())); } } - if(m_ImageNode.IsNull()) - GetDataStorage()->Add(m_FiberBundleNode); - else - GetDataStorage()->Add(m_FiberBundleNode, m_ImageNode); + GetDataStorage()->Add(m_FiberBundleNode, m_ImageNode); } void QmitkGibbsTrackingView::SetOutputFile() { // SELECT FOLDER DIALOG m_OutputFileName = QFileDialog::getSaveFileName(0, tr("Set file name"), QDir::currentPath()+"/FiberBundle.fib", tr("Fiber Bundle (*.fib)") ); if (m_OutputFileName.isEmpty()) m_Controls->m_OutputFileLabel->setText("N/A"); else m_Controls->m_OutputFileLabel->setText(m_OutputFileName); } // save current tracking paramters as xml file (.gtp) void QmitkGibbsTrackingView::SaveTrackingParameters() { TiXmlDocument documentXML; TiXmlDeclaration* declXML = new TiXmlDeclaration( "1.0", "", "" ); documentXML.LinkEndChild( declXML ); TiXmlElement* mainXML = new TiXmlElement("global_tracking_parameter_file"); mainXML->SetAttribute("file_version", "0.1"); documentXML.LinkEndChild(mainXML); TiXmlElement* paramXML = new TiXmlElement("parameter_set"); paramXML->SetAttribute("iterations", m_Controls->m_IterationsBox->text().toStdString()); paramXML->SetAttribute("particle_length", QString::number((float)m_Controls->m_ParticleLengthSlider->value()/10).toStdString()); paramXML->SetAttribute("particle_width", QString::number((float)m_Controls->m_ParticleWidthSlider->value()/10).toStdString()); paramXML->SetAttribute("particle_weight", QString::number((float)m_Controls->m_ParticleWeightSlider->value()/10000).toStdString()); paramXML->SetAttribute("temp_start", QString::number((float)m_Controls->m_StartTempSlider->value()/100).toStdString()); paramXML->SetAttribute("temp_end", QString::number((float)m_Controls->m_EndTempSlider->value()/10000).toStdString()); paramXML->SetAttribute("inexbalance", QString::number((float)m_Controls->m_InExBalanceSlider->value()/10).toStdString()); paramXML->SetAttribute("fiber_length", QString::number(m_Controls->m_FiberLengthSlider->value()).toStdString()); paramXML->SetAttribute("curvature_threshold", QString::number(m_Controls->m_CurvatureThresholdSlider->value()).toStdString()); mainXML->LinkEndChild(paramXML); QString filename = QFileDialog::getSaveFileName( 0, tr("Save Parameters"), QDir::currentPath()+"/param.gtp", tr("Global Tracking Parameters (*.gtp)") ); if(filename.isEmpty() || filename.isNull()) return; if(!filename.endsWith(".gtp")) filename += ".gtp"; documentXML.SaveFile( filename.toStdString() ); } // load current tracking paramters from xml file (.gtp) void QmitkGibbsTrackingView::LoadTrackingParameters() { QString filename = QFileDialog::getOpenFileName(0, tr("Load Parameters"), QDir::currentPath(), tr("Global Tracking Parameters (*.gtp)") ); if(filename.isEmpty() || filename.isNull()) return; TiXmlDocument doc( filename.toStdString() ); doc.LoadFile(); TiXmlHandle hDoc(&doc); TiXmlElement* pElem; TiXmlHandle hRoot(0); pElem = hDoc.FirstChildElement().Element(); hRoot = TiXmlHandle(pElem); pElem = hRoot.FirstChildElement("parameter_set").Element(); QString iterations(pElem->Attribute("iterations")); m_Controls->m_IterationsBox->setText(iterations); QString particleLength(pElem->Attribute("particle_length")); float pLength = particleLength.toFloat(); QString particleWidth(pElem->Attribute("particle_width")); float pWidth = particleWidth.toFloat(); if (pLength==0) m_Controls->m_ParticleLengthLabel->setText("auto"); else m_Controls->m_ParticleLengthLabel->setText(particleLength+" mm"); if (pWidth==0) m_Controls->m_ParticleWidthLabel->setText("auto"); else m_Controls->m_ParticleWidthLabel->setText(particleWidth+" mm"); m_Controls->m_ParticleWidthSlider->setValue(pWidth*10); m_Controls->m_ParticleLengthSlider->setValue(pLength*10); QString partWeight(pElem->Attribute("particle_weight")); m_Controls->m_ParticleWeightSlider->setValue(partWeight.toFloat()*10000); m_Controls->m_ParticleWeightLabel->setText(partWeight); QString startTemp(pElem->Attribute("temp_start")); m_Controls->m_StartTempSlider->setValue(startTemp.toFloat()*100); m_Controls->m_StartTempLabel->setText(startTemp); QString endTemp(pElem->Attribute("temp_end")); m_Controls->m_EndTempSlider->setValue(endTemp.toFloat()*10000); m_Controls->m_EndTempLabel->setText(endTemp); QString inExBalance(pElem->Attribute("inexbalance")); m_Controls->m_InExBalanceSlider->setValue(inExBalance.toFloat()*10); m_Controls->m_InExBalanceLabel->setText(inExBalance); QString fiberLength(pElem->Attribute("fiber_length")); m_Controls->m_FiberLengthSlider->setValue(fiberLength.toInt()); m_Controls->m_FiberLengthLabel->setText(fiberLength+"mm"); QString curvThres(pElem->Attribute("curvature_threshold")); m_Controls->m_CurvatureThresholdSlider->setValue(curvThres.toInt()); m_Controls->m_CurvatureThresholdLabel->setText(curvThres+"°"); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp index d9633cb..cadd6c8 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp @@ -1,1159 +1,1161 @@ /*=================================================================== 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 #include // Qmitk #include "QmitkStreamlineTrackingView.h" #include "QmitkStdMultiWidget.h" // Qt #include #include // MITK #include #include #include #include #include #include #include #include #include #include #include #include #include #include // VTK #include #include #include #include #include #include #include #include #include #include const std::string QmitkStreamlineTrackingView::VIEW_ID = "org.mitk.views.streamlinetracking"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace berry; QmitkStreamlineTrackingWorker::QmitkStreamlineTrackingWorker(QmitkStreamlineTrackingView* view) : m_View(view) { } void QmitkStreamlineTrackingWorker::run() { m_View->m_Tracker->Update(); m_View->m_TrackingThread.quit(); } QmitkStreamlineTrackingView::QmitkStreamlineTrackingView() : m_TrackingWorker(this) , m_Controls(nullptr) , m_FirstTensorProbRun(true) , m_FirstInteractiveRun(true) , m_TrackingHandler(nullptr) , m_ThreadIsRunning(false) , m_DeleteTrackingHandler(false) , m_Visible(false) , m_LastPrior(nullptr) , m_TrackingPriorHandler(nullptr) { m_TrackingWorker.moveToThread(&m_TrackingThread); connect(&m_TrackingThread, SIGNAL(started()), this, SLOT(BeforeThread())); connect(&m_TrackingThread, SIGNAL(started()), &m_TrackingWorker, SLOT(run())); connect(&m_TrackingThread, SIGNAL(finished()), this, SLOT(AfterThread())); m_TrackingTimer = new QTimer(this); } // Destructor QmitkStreamlineTrackingView::~QmitkStreamlineTrackingView() { if (m_Tracker.IsNull()) return; m_Tracker->SetStopTracking(true); m_TrackingThread.wait(); } void QmitkStreamlineTrackingView::CreateQtPartControl( QWidget *parent ) { if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkStreamlineTrackingViewControls; m_Controls->setupUi( parent ); m_Controls->m_FaImageSelectionWidget->SetDataStorage(this->GetDataStorage()); m_Controls->m_SeedImageSelectionWidget->SetDataStorage(this->GetDataStorage()); m_Controls->m_MaskImageSelectionWidget->SetDataStorage(this->GetDataStorage()); m_Controls->m_TargetImageSelectionWidget->SetDataStorage(this->GetDataStorage()); m_Controls->m_PriorImageSelectionWidget->SetDataStorage(this->GetDataStorage()); m_Controls->m_StopImageSelectionWidget->SetDataStorage(this->GetDataStorage()); m_Controls->m_ForestSelectionWidget->SetDataStorage(this->GetDataStorage()); m_Controls->m_ExclusionImageSelectionWidget->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isPeakImagePredicate = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isTractographyForest = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinaryPredicate = mitk::NodePredicateNot::New( isBinaryPredicate ); mitk::NodePredicateAnd::Pointer isNotABinaryImagePredicate = mitk::NodePredicateAnd::New( isImagePredicate, isNotBinaryPredicate ); mitk::NodePredicateDimension::Pointer dimensionPredicate = mitk::NodePredicateDimension::New(3); m_Controls->m_ForestSelectionWidget->SetNodePredicate(isTractographyForest); m_Controls->m_FaImageSelectionWidget->SetNodePredicate( mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, dimensionPredicate) ); m_Controls->m_FaImageSelectionWidget->SetEmptyInfo("--"); m_Controls->m_FaImageSelectionWidget->SetSelectionIsOptional(true); m_Controls->m_SeedImageSelectionWidget->SetNodePredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_SeedImageSelectionWidget->SetEmptyInfo("--"); m_Controls->m_SeedImageSelectionWidget->SetSelectionIsOptional(true); m_Controls->m_MaskImageSelectionWidget->SetNodePredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_MaskImageSelectionWidget->SetEmptyInfo("--"); m_Controls->m_MaskImageSelectionWidget->SetSelectionIsOptional(true); m_Controls->m_StopImageSelectionWidget->SetNodePredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_StopImageSelectionWidget->SetEmptyInfo("--"); m_Controls->m_StopImageSelectionWidget->SetSelectionIsOptional(true); m_Controls->m_TargetImageSelectionWidget->SetNodePredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_TargetImageSelectionWidget->SetEmptyInfo("--"); m_Controls->m_TargetImageSelectionWidget->SetSelectionIsOptional(true); m_Controls->m_PriorImageSelectionWidget->SetNodePredicate( isPeakImagePredicate ); m_Controls->m_PriorImageSelectionWidget->SetEmptyInfo("--"); m_Controls->m_PriorImageSelectionWidget->SetSelectionIsOptional(true); m_Controls->m_ExclusionImageSelectionWidget->SetNodePredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_ExclusionImageSelectionWidget->SetEmptyInfo("--"); m_Controls->m_ExclusionImageSelectionWidget->SetSelectionIsOptional(true); connect( m_TrackingTimer, SIGNAL(timeout()), this, SLOT(TimerUpdate()) ); connect( m_Controls->m_SaveParametersButton, SIGNAL(clicked()), this, SLOT(SaveParameters()) ); connect( m_Controls->m_LoadParametersButton, SIGNAL(clicked()), this, SLOT(LoadParameters()) ); connect( m_Controls->commandLinkButton_2, SIGNAL(clicked()), this, SLOT(StopTractography()) ); connect( m_Controls->commandLinkButton, SIGNAL(clicked()), this, SLOT(DoFiberTracking()) ); connect( m_Controls->m_InteractiveBox, SIGNAL(stateChanged(int)), this, SLOT(ToggleInteractive()) ); connect( m_Controls->m_ModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui()) ); connect( m_Controls->m_FaImageSelectionWidget, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(DeleteTrackingHandler()) ); connect( m_Controls->m_ModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(DeleteTrackingHandler()) ); connect( m_Controls->m_OutputProbMap, SIGNAL(stateChanged(int)), this, SLOT(OutputStyleSwitched()) ); connect( m_Controls->m_SeedImageSelectionWidget, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_ModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_StopImageSelectionWidget, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_TargetImageSelectionWidget, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_PriorImageSelectionWidget, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_ExclusionImageSelectionWidget, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_MaskImageSelectionWidget, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FaImageSelectionWidget, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_ForestSelectionWidget, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(ForestSwitched()) ); connect( m_Controls->m_ForestSelectionWidget, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SeedsPerVoxelBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_NumFibersBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_ScalarThresholdBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_OdfCutoffBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_StepSizeBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SamplingDistanceBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_AngularThresholdBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_MinTractLengthBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_MaxTractLengthBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_fBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_gBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_NumSamplesBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SeedRadiusBox, SIGNAL(editingFinished()), this, SLOT(InteractiveSeedChanged()) ); connect( m_Controls->m_NumSeedsBox, SIGNAL(editingFinished()), this, SLOT(InteractiveSeedChanged()) ); connect( m_Controls->m_OutputProbMap, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SharpenOdfsBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_InterpolationBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_MaskInterpolationBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FlipXBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FlipYBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FlipZBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_PriorFlipXBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_PriorFlipYBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_PriorFlipZBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FrontalSamplesBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_StopVotesBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_LoopCheckBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_TrialsPerSeedBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_EpConstraintsBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_PeakJitterBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); m_Controls->m_SeedsPerVoxelBox->editingFinished(); m_Controls->m_NumFibersBox->editingFinished(); m_Controls->m_ScalarThresholdBox->editingFinished(); m_Controls->m_OdfCutoffBox->editingFinished(); m_Controls->m_StepSizeBox->editingFinished(); m_Controls->m_SamplingDistanceBox->editingFinished(); m_Controls->m_AngularThresholdBox->editingFinished(); m_Controls->m_MinTractLengthBox->editingFinished(); m_Controls->m_MaxTractLengthBox->editingFinished(); m_Controls->m_fBox->editingFinished(); m_Controls->m_gBox->editingFinished(); m_Controls->m_NumSamplesBox->editingFinished(); m_Controls->m_SeedRadiusBox->editingFinished(); m_Controls->m_NumSeedsBox->editingFinished(); m_Controls->m_LoopCheckBox->editingFinished(); m_Controls->m_TrialsPerSeedBox->editingFinished(); m_Controls->m_PeakJitterBox->editingFinished(); StartStopTrackingGui(false); } m_ParameterFile = QDir::currentPath()+"/param.stp"; UpdateGui(); } void QmitkStreamlineTrackingView::ParametersToGui(mitk::StreamlineTractographyParameters& params) { m_Controls->m_SeedRadiusBox->setValue(params.m_InteractiveRadiusMm); m_Controls->m_NumSeedsBox->setValue(params.m_NumInteractiveSeeds); m_Controls->m_InteractiveBox->setChecked(params.m_EnableInteractive); m_Controls->m_FiberErrorBox->setValue(params.m_Compression); m_Controls->m_ResampleFibersBox->setChecked(params.m_CompressFibers); m_Controls->m_SeedRadiusBox->setValue(params.m_InteractiveRadiusMm); m_Controls->m_NumFibersBox->setValue(params.m_MaxNumFibers); m_Controls->m_ScalarThresholdBox->setValue(params.m_Cutoff); m_Controls->m_fBox->setValue(params.m_F); m_Controls->m_gBox->setValue(params.m_G); m_Controls->m_OdfCutoffBox->setValue(params.m_OdfCutoff); m_Controls->m_SharpenOdfsBox->setChecked(params.m_SharpenOdfs); m_Controls->m_PriorWeightBox->setValue(params.m_Weight); m_Controls->m_PriorAsMaskBox->setChecked(params.m_RestrictToPrior); m_Controls->m_NewDirectionsFromPriorBox->setChecked(params.m_NewDirectionsFromPrior); m_Controls->m_PriorFlipXBox->setChecked(params.m_PriorFlipX); m_Controls->m_PriorFlipYBox->setChecked(params.m_PriorFlipY); m_Controls->m_PriorFlipZBox->setChecked(params.m_PriorFlipZ); m_Controls->m_FlipXBox->setChecked(params.m_FlipX); m_Controls->m_FlipYBox->setChecked(params.m_FlipY); m_Controls->m_FlipZBox->setChecked(params.m_FlipZ); m_Controls->m_InterpolationBox->setChecked(params.m_InterpolateTractographyData); m_Controls->m_MaskInterpolationBox->setChecked(params.m_InterpolateRoiImages); m_Controls->m_SeedsPerVoxelBox->setValue(params.m_SeedsPerVoxel); m_Controls->m_StepSizeBox->setValue(params.GetStepSizeVox()); m_Controls->m_SamplingDistanceBox->setValue(params.GetSamplingDistanceVox()); m_Controls->m_StopVotesBox->setChecked(params.m_StopVotes); m_Controls->m_FrontalSamplesBox->setChecked(params.m_OnlyForwardSamples); m_Controls->m_TrialsPerSeedBox->setValue(params.m_TrialsPerSeed); m_Controls->m_NumSamplesBox->setValue(params.m_NumSamples); m_Controls->m_LoopCheckBox->setValue(params.GetLoopCheckDeg()); m_Controls->m_AngularThresholdBox->setValue(params.GetAngularThresholdDeg()); m_Controls->m_MinTractLengthBox->setValue(params.m_MinTractLengthMm); m_Controls->m_MaxTractLengthBox->setValue(params.m_MaxTractLengthMm); m_Controls->m_OutputProbMap->setChecked(params.m_OutputProbMap); m_Controls->m_FixSeedBox->setChecked(params.m_FixRandomSeed); m_Controls->m_PeakJitterBox->setValue(params.m_PeakJitter); switch (params.m_Mode) { case mitk::TrackingDataHandler::MODE::DETERMINISTIC: m_Controls->m_ModeBox->setCurrentIndex(0); break; case mitk::TrackingDataHandler::MODE::PROBABILISTIC: m_Controls->m_ModeBox->setCurrentIndex(1); break; } switch (params.m_EpConstraints) { case itk::StreamlineTrackingFilter::EndpointConstraints::NONE: m_Controls->m_EpConstraintsBox->setCurrentIndex(0); break; case itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_TARGET: m_Controls->m_EpConstraintsBox->setCurrentIndex(1); break; case itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_TARGET_LABELDIFF: m_Controls->m_EpConstraintsBox->setCurrentIndex(2); break; case itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_SEED_AND_TARGET: m_Controls->m_EpConstraintsBox->setCurrentIndex(3); break; case itk::StreamlineTrackingFilter::EndpointConstraints::MIN_ONE_EP_IN_TARGET: m_Controls->m_EpConstraintsBox->setCurrentIndex(4); break; case itk::StreamlineTrackingFilter::EndpointConstraints::ONE_EP_IN_TARGET: m_Controls->m_EpConstraintsBox->setCurrentIndex(5); break; case itk::StreamlineTrackingFilter::EndpointConstraints::NO_EP_IN_TARGET: m_Controls->m_EpConstraintsBox->setCurrentIndex(6); break; } } std::shared_ptr QmitkStreamlineTrackingView::GetParametersFromGui() { // NOT IN GUI // unsigned int m_NumPreviousDirections = 1; // bool m_AvoidStop = true; // bool m_RandomSampling = false; // float m_DeflectionMod = 1.0; // bool m_ApplyDirectionMatrix = false; std::shared_ptr params = std::make_shared(); params->m_InteractiveRadiusMm = m_Controls->m_SeedRadiusBox->value(); params->m_NumInteractiveSeeds = m_Controls->m_NumSeedsBox->value(); params->m_EnableInteractive = m_Controls->m_InteractiveBox->isChecked(); params->m_Compression = m_Controls->m_FiberErrorBox->value(); params->m_CompressFibers = m_Controls->m_ResampleFibersBox->isChecked(); params->m_InteractiveRadiusMm = m_Controls->m_SeedRadiusBox->value(); params->m_MaxNumFibers = m_Controls->m_NumFibersBox->value(); params->m_Cutoff = static_cast(m_Controls->m_ScalarThresholdBox->value()); params->m_F = static_cast(m_Controls->m_fBox->value()); params->m_G = static_cast(m_Controls->m_gBox->value()); params->m_OdfCutoff = static_cast(m_Controls->m_OdfCutoffBox->value()); params->m_SharpenOdfs = m_Controls->m_SharpenOdfsBox->isChecked(); params->m_Weight = static_cast(m_Controls->m_PriorWeightBox->value()); params->m_RestrictToPrior = m_Controls->m_PriorAsMaskBox->isChecked(); params->m_NewDirectionsFromPrior = m_Controls->m_NewDirectionsFromPriorBox->isChecked(); params->m_PriorFlipX = m_Controls->m_PriorFlipXBox->isChecked(); params->m_PriorFlipY = m_Controls->m_PriorFlipYBox->isChecked(); params->m_PriorFlipZ = m_Controls->m_PriorFlipZBox->isChecked(); params->m_FlipX = m_Controls->m_FlipXBox->isChecked(); params->m_FlipY = m_Controls->m_FlipYBox->isChecked(); params->m_FlipZ = m_Controls->m_FlipZBox->isChecked(); params->m_InterpolateTractographyData = m_Controls->m_InterpolationBox->isChecked(); params->m_InterpolateRoiImages = m_Controls->m_MaskInterpolationBox->isChecked(); params->m_SeedsPerVoxel = m_Controls->m_SeedsPerVoxelBox->value(); params->SetStepSizeVox(m_Controls->m_StepSizeBox->value()); params->SetSamplingDistanceVox(m_Controls->m_SamplingDistanceBox->value()); params->m_StopVotes = m_Controls->m_StopVotesBox->isChecked(); params->m_OnlyForwardSamples = m_Controls->m_FrontalSamplesBox->isChecked(); params->m_TrialsPerSeed = m_Controls->m_TrialsPerSeedBox->value(); params->m_NumSamples = m_Controls->m_NumSamplesBox->value(); params->SetLoopCheckDeg(m_Controls->m_LoopCheckBox->value()); params->SetAngularThresholdDeg(m_Controls->m_AngularThresholdBox->value()); params->m_MinTractLengthMm = m_Controls->m_MinTractLengthBox->value(); params->m_MaxTractLengthMm = m_Controls->m_MaxTractLengthBox->value(); params->m_OutputProbMap = m_Controls->m_OutputProbMap->isChecked(); params->m_FixRandomSeed = m_Controls->m_FixSeedBox->isChecked(); params->m_PeakJitter = static_cast(m_Controls->m_PeakJitterBox->value()); switch (m_Controls->m_ModeBox->currentIndex()) { case 0: params->m_Mode = mitk::TrackingDataHandler::MODE::DETERMINISTIC; break; case 1: params->m_Mode = mitk::TrackingDataHandler::MODE::PROBABILISTIC; break; default: params->m_Mode = mitk::TrackingDataHandler::MODE::DETERMINISTIC; } switch (m_Controls->m_EpConstraintsBox->currentIndex()) { case 0: params->m_EpConstraints = itk::StreamlineTrackingFilter::EndpointConstraints::NONE; break; case 1: params->m_EpConstraints = itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_TARGET; break; case 2: params->m_EpConstraints = itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_TARGET_LABELDIFF; break; case 3: params->m_EpConstraints = itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_SEED_AND_TARGET; break; case 4: params->m_EpConstraints = itk::StreamlineTrackingFilter::EndpointConstraints::MIN_ONE_EP_IN_TARGET; break; case 5: params->m_EpConstraints = itk::StreamlineTrackingFilter::EndpointConstraints::ONE_EP_IN_TARGET; break; case 6: params->m_EpConstraints = itk::StreamlineTrackingFilter::EndpointConstraints::NO_EP_IN_TARGET; break; } return params; } void QmitkStreamlineTrackingView::SaveParameters() { QString filename = QFileDialog::getSaveFileName( 0, tr("Save Tractography Parameters"), m_ParameterFile, tr("Streamline Tractography Parameters (*.stp)") ); if(filename.isEmpty() || filename.isNull()) return; m_ParameterFile = filename; auto params = GetParametersFromGui(); params->SaveParameters(m_ParameterFile.toStdString()); } void QmitkStreamlineTrackingView::LoadParameters() { QString filename = QFileDialog::getOpenFileName( 0, tr("Load Tractography Parameters"), m_ParameterFile, tr("Streamline Tractography Parameters (*.stp)") ); if(filename.isEmpty() || filename.isNull()) return; m_ParameterFile = filename; mitk::StreamlineTractographyParameters params; params.LoadParameters(m_ParameterFile.toStdString()); ParametersToGui(params); } void QmitkStreamlineTrackingView::StopTractography() { if (m_Tracker.IsNull()) return; m_Tracker->SetStopTracking(true); } void QmitkStreamlineTrackingView::TimerUpdate() { if (m_Tracker.IsNull()) return; QString status_text(m_Tracker->GetStatusText().c_str()); m_Controls->m_StatusTextBox->setText(status_text); } void QmitkStreamlineTrackingView::BeforeThread() { m_TrackingTimer->start(1000); } void QmitkStreamlineTrackingView::AfterThread() { auto params = m_Tracker->GetParameters(); m_TrackingTimer->stop(); if (!params->m_OutputProbMap) { vtkSmartPointer fiberBundle = m_Tracker->GetFiberPolyData(); if (!m_Controls->m_InteractiveBox->isChecked() && fiberBundle->GetNumberOfLines() == 0) { QMessageBox warnBox; warnBox.setWindowTitle("Warning"); warnBox.setText("No fiberbundle was generated!"); warnBox.setDetailedText("No fibers were generated using the chosen parameters. Typical reasons are:\n\n- Cutoff too high. Some images feature very low FA/GFA/peak size. Try to lower this parameter.\n- Angular threshold too strict. Try to increase this parameter.\n- A small step sizes also means many steps to go wrong. Especially in the case of probabilistic tractography. Try to adjust the angular threshold."); warnBox.setIcon(QMessageBox::Warning); warnBox.exec(); if (m_InteractivePointSetNode.IsNotNull()) m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); StartStopTrackingGui(false); if (m_DeleteTrackingHandler) DeleteTrackingHandler(); UpdateGui(); return; } mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(fiberBundle); fib->SetTrackVisHeader(dynamic_cast(m_ParentNode->GetData())->GetGeometry()); if (m_Controls->m_ResampleFibersBox->isChecked() && fiberBundle->GetNumberOfLines()>0) fib->Compress(m_Controls->m_FiberErrorBox->value()); fib->ColorFibersByOrientation(); - m_Tracker->SetDicomProperties(fib); + m_Tracker->SetDicomProperties(fib); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(m_ParentNode->GetData(), fib); if (m_Controls->m_InteractiveBox->isChecked()) { if (m_InteractiveNode.IsNull()) { m_InteractiveNode = mitk::DataNode::New(); QString name("Interactive"); m_InteractiveNode->SetName(name.toStdString()); GetDataStorage()->Add(m_InteractiveNode); } m_InteractiveNode->SetData(fib); m_InteractiveNode->SetFloatProperty("Fiber2DSliceThickness", params->GetMinVoxelSizeMm()/2); if (auto renderWindowPart = this->GetRenderWindowPart()) renderWindowPart->RequestUpdate(); } else { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(fib); QString name("FiberBundle_"); name += m_ParentNode->GetName().c_str(); name += "_Streamline"; node->SetName(name.toStdString()); node->SetFloatProperty("Fiber2DSliceThickness", params->GetMinVoxelSizeMm()/2); GetDataStorage()->Add(node, m_ParentNode); } } else { TrackerType::ItkDoubleImgType::Pointer outImg = m_Tracker->GetOutputProbabilityMap(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); + mitk::DiffusionPropertyHelper::CopyDICOMProperties(m_ParentNode->GetData(), img); if (m_Controls->m_InteractiveBox->isChecked()) { if (m_InteractiveNode.IsNull()) { m_InteractiveNode = mitk::DataNode::New(); QString name("Interactive"); m_InteractiveNode->SetName(name.toStdString()); GetDataStorage()->Add(m_InteractiveNode); } m_InteractiveNode->SetData(img); 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); m_InteractiveNode->SetProperty("LookupTable", lut_prop); m_InteractiveNode->SetProperty("opacity", mitk::FloatProperty::New(0.5)); m_InteractiveNode->SetFloatProperty("Fiber2DSliceThickness", params->GetMinVoxelSizeMm()/2); if (auto renderWindowPart = this->GetRenderWindowPart()) renderWindowPart->RequestUpdate(); } else { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); QString name("ProbabilityMap_"); name += m_ParentNode->GetName().c_str(); node->SetName(name.toStdString()); 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); node->SetProperty("LookupTable", lut_prop); node->SetProperty("opacity", mitk::FloatProperty::New(0.5)); GetDataStorage()->Add(node, m_ParentNode); } } if (m_InteractivePointSetNode.IsNotNull()) m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); StartStopTrackingGui(false); if (m_DeleteTrackingHandler) DeleteTrackingHandler(); UpdateGui(); } void QmitkStreamlineTrackingView::InteractiveSeedChanged(bool posChanged) { if(!CheckAndStoreLastParams(sender()) && !posChanged) return; if (m_ThreadIsRunning || !m_Visible) return; if (!posChanged && (!m_Controls->m_InteractiveBox->isChecked() || !m_Controls->m_ParamUpdateBox->isChecked()) ) return; std::srand(std::time(0)); m_SeedPoints.clear(); itk::Point world_pos = this->GetRenderWindowPart()->GetSelectedPosition(); m_SeedPoints.push_back(world_pos); float radius = m_Controls->m_SeedRadiusBox->value(); int num = m_Controls->m_NumSeedsBox->value(); mitk::PointSet::Pointer pointset = mitk::PointSet::New(); pointset->InsertPoint(0, world_pos); m_InteractivePointSetNode->SetProperty("pointsize", mitk::FloatProperty::New(radius*2)); m_InteractivePointSetNode->SetProperty("point 2D size", mitk::FloatProperty::New(radius*2)); m_InteractivePointSetNode->SetData(pointset); for (int i=1; i p; p[0] = rand()%1000-500; p[1] = rand()%1000-500; p[2] = rand()%1000-500; p.Normalize(); p *= radius; m_SeedPoints.push_back(world_pos+p); } m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,0,0)); DoFiberTracking(); } bool QmitkStreamlineTrackingView::CheckAndStoreLastParams(QObject* obj) { if (obj!=nullptr) { std::string new_val = ""; if(qobject_cast(obj)!=nullptr) new_val = boost::lexical_cast(qobject_cast(obj)->value()); else if (qobject_cast(obj)!=nullptr) new_val = boost::lexical_cast(qobject_cast(obj)->value()); else return true; if (m_LastTractoParams.find(obj->objectName())==m_LastTractoParams.end()) { m_LastTractoParams[obj->objectName()] = new_val; return false; } else if (m_LastTractoParams.at(obj->objectName()) != new_val) { m_LastTractoParams[obj->objectName()] = new_val; return true; } else if (m_LastTractoParams.at(obj->objectName()) == new_val) return false; } return true; } void QmitkStreamlineTrackingView::OnParameterChanged() { UpdateGui(); if(!CheckAndStoreLastParams(sender())) return; if (m_Controls->m_InteractiveBox->isChecked() && m_Controls->m_ParamUpdateBox->isChecked()) DoFiberTracking(); } void QmitkStreamlineTrackingView::ToggleInteractive() { UpdateGui(); m_Controls->m_SeedsPerVoxelBox->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->m_SeedsPerVoxelLabel->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->m_SeedImageSelectionWidget->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->label_6->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); if ( m_Controls->m_InteractiveBox->isChecked() ) { if (m_FirstInteractiveRun) { QMessageBox::information(nullptr, "Information", "Place and move a spherical seed region anywhere in the image by left-clicking and dragging. If the seed region is colored red, tracking is in progress. If the seed region is colored white, tracking is finished.\nPlacing the seed region for the first time in a newly selected dataset might cause a short delay, since the tracker needs to be initialized."); m_FirstInteractiveRun = false; } QApplication::setOverrideCursor(Qt::PointingHandCursor); QApplication::processEvents(); m_InteractivePointSetNode = mitk::DataNode::New(); m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); m_InteractivePointSetNode->SetName("InteractiveSeedRegion"); mitk::PointSetShapeProperty::Pointer shape_prop = mitk::PointSetShapeProperty::New(); shape_prop->SetValue(mitk::PointSetShapeProperty::PointSetShape::CIRCLE); m_InteractivePointSetNode->SetProperty("Pointset.2D.shape", shape_prop); GetDataStorage()->Add(m_InteractivePointSetNode); m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } else { QApplication::restoreOverrideCursor(); QApplication::processEvents(); m_InteractiveNode = nullptr; m_InteractivePointSetNode = nullptr; m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); disconnect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } } void QmitkStreamlineTrackingView::Activated() { } void QmitkStreamlineTrackingView::Deactivated() { } void QmitkStreamlineTrackingView::Visible() { m_Visible = true; } void QmitkStreamlineTrackingView::Hidden() { m_Visible = false; m_Controls->m_InteractiveBox->setChecked(false); ToggleInteractive(); } void QmitkStreamlineTrackingView::OnSliceChanged() { InteractiveSeedChanged(true); } void QmitkStreamlineTrackingView::SetFocus() { } void QmitkStreamlineTrackingView::DeleteTrackingHandler() { if (!m_ThreadIsRunning && m_TrackingHandler != nullptr) { if (m_TrackingPriorHandler != nullptr) { delete m_TrackingPriorHandler; m_TrackingPriorHandler = nullptr; } delete m_TrackingHandler; m_TrackingHandler = nullptr; m_DeleteTrackingHandler = false; m_LastPrior = nullptr; } else if (m_ThreadIsRunning) { m_DeleteTrackingHandler = true; } } void QmitkStreamlineTrackingView::ForestSwitched() { DeleteTrackingHandler(); } void QmitkStreamlineTrackingView::OutputStyleSwitched() { if (m_InteractiveNode.IsNotNull()) GetDataStorage()->Remove(m_InteractiveNode); m_InteractiveNode = nullptr; } void QmitkStreamlineTrackingView::OnSelectionChanged( berry::IWorkbenchPart::Pointer , const QList& nodes ) { std::vector< mitk::DataNode::Pointer > last_nodes = m_InputImageNodes; m_InputImageNodes.clear(); m_AdditionalInputImages.clear(); bool retrack = false; for( auto node : nodes ) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { if( dynamic_cast(node->GetData()) || dynamic_cast(node->GetData()) || dynamic_cast(node->GetData()) || dynamic_cast(node->GetData()) || mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(node->GetData()))) { m_InputImageNodes.push_back(node); retrack = true; } else { mitk::Image* img = dynamic_cast(node->GetData()); if (img!=nullptr && img->GetDimension()==3) m_AdditionalInputImages.push_back(dynamic_cast(node->GetData())); } } } // sometimes the OnSelectionChanged event is sent twice and actually no selection has changed for the first event. We need to catch that. if (last_nodes.size() == m_InputImageNodes.size()) { bool same_nodes = true; for (unsigned int i=0; im_TensorImageLabel->setText("select in data-manager"); m_Controls->m_fBox->setEnabled(false); m_Controls->m_fLabel->setEnabled(false); m_Controls->m_gBox->setEnabled(false); m_Controls->m_gLabel->setEnabled(false); m_Controls->m_FaImageSelectionWidget->setEnabled(true); m_Controls->mFaImageLabel->setEnabled(true); m_Controls->m_OdfCutoffBox->setEnabled(false); m_Controls->m_OdfCutoffLabel->setEnabled(false); m_Controls->m_SharpenOdfsBox->setEnabled(false); m_Controls->m_ForestSelectionWidget->setVisible(false); m_Controls->m_ForestLabel->setVisible(false); m_Controls->commandLinkButton->setEnabled(false); m_Controls->m_TrialsPerSeedBox->setEnabled(false); m_Controls->m_TrialsPerSeedLabel->setEnabled(false); m_Controls->m_TargetImageSelectionWidget->setEnabled(false); m_Controls->m_TargetImageLabel->setEnabled(false); m_Controls->m_PeakJitterBox->setEnabled(false); if (m_Controls->m_InteractiveBox->isChecked()) { m_Controls->m_InteractiveSeedingFrame->setVisible(true); m_Controls->m_StaticSeedingFrame->setVisible(false); m_Controls->commandLinkButton_2->setVisible(false); m_Controls->commandLinkButton->setVisible(false); } else { m_Controls->m_InteractiveSeedingFrame->setVisible(false); m_Controls->m_StaticSeedingFrame->setVisible(true); m_Controls->commandLinkButton_2->setVisible(m_ThreadIsRunning); m_Controls->commandLinkButton->setVisible(!m_ThreadIsRunning); } if (m_Controls->m_EpConstraintsBox->currentIndex()>0) { m_Controls->m_TargetImageSelectionWidget->setEnabled(true); m_Controls->m_TargetImageLabel->setEnabled(true); } // stuff that is only important for probabilistic tractography if (m_Controls->m_ModeBox->currentIndex()==1) { m_Controls->m_TrialsPerSeedBox->setEnabled(true); m_Controls->m_TrialsPerSeedLabel->setEnabled(true); m_Controls->m_PeakJitterBox->setEnabled(true); } if(!m_InputImageNodes.empty()) { if (m_InputImageNodes.size()>1) m_Controls->m_TensorImageLabel->setText( ( std::to_string(m_InputImageNodes.size()) + " images selected").c_str() ); else m_Controls->m_TensorImageLabel->setText(m_InputImageNodes.at(0)->GetName().c_str()); m_Controls->commandLinkButton->setEnabled(!m_Controls->m_InteractiveBox->isChecked() && !m_ThreadIsRunning); m_Controls->m_ScalarThresholdBox->setEnabled(true); m_Controls->m_FaThresholdLabel->setEnabled(true); if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { m_Controls->m_fBox->setEnabled(true); m_Controls->m_fLabel->setEnabled(true); m_Controls->m_gBox->setEnabled(true); m_Controls->m_gLabel->setEnabled(true); } else if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) || dynamic_cast(m_InputImageNodes.at(0)->GetData())) { m_Controls->m_OdfCutoffBox->setEnabled(true); m_Controls->m_OdfCutoffLabel->setEnabled(true); m_Controls->m_SharpenOdfsBox->setEnabled(true); } else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_InputImageNodes.at(0)->GetData())) ) { m_Controls->m_ForestSelectionWidget->setVisible(true); m_Controls->m_ForestLabel->setVisible(true); m_Controls->m_ScalarThresholdBox->setEnabled(false); m_Controls->m_FaThresholdLabel->setEnabled(false); } } } void QmitkStreamlineTrackingView::StartStopTrackingGui(bool start) { m_ThreadIsRunning = start; if (!m_Controls->m_InteractiveBox->isChecked()) { m_Controls->commandLinkButton_2->setVisible(start); m_Controls->commandLinkButton->setVisible(!start); m_Controls->m_InteractiveBox->setEnabled(!start); m_Controls->m_StatusTextBox->setVisible(start); } } void QmitkStreamlineTrackingView::DoFiberTracking() { auto params = GetParametersFromGui(); if (m_InputImageNodes.empty()) { QMessageBox::information(nullptr, "Information", "Please select an input image in the datamaneger (tensor, ODF, peak or dMRI image)!"); return; } if (m_ThreadIsRunning || !m_Visible) return; if (m_Controls->m_InteractiveBox->isChecked() && m_SeedPoints.empty()) return; StartStopTrackingGui(true); m_Tracker = TrackerType::New(); if (params->m_EpConstraints == itk::StreamlineTrackingFilter::EndpointConstraints::NONE) m_Tracker->SetTargetRegions(nullptr); if( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { if (m_Controls->m_ModeBox->currentIndex()==1) { if (m_InputImageNodes.size()>1) { QMessageBox::information(nullptr, "Information", "Probabilistic tensor tractography is only implemented for single-tensor mode!"); StartStopTrackingGui(false); return; } if (m_TrackingHandler==nullptr) { m_TrackingHandler = new mitk::TrackingHandlerOdf(); typedef itk::TensorImageToOdfImageFilter< float, float > FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput( mitk::convert::GetItkTensorFromTensorImage(dynamic_cast(m_InputImageNodes.at(0)->GetData())) ); filter->Update(); dynamic_cast(m_TrackingHandler)->SetOdfImage(filter->GetOutput()); if (m_Controls->m_FaImageSelectionWidget->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageSelectionWidget->GetSelectedNode()->GetData()), itkImg); dynamic_cast(m_TrackingHandler)->SetGfaImage(itkImg); } } dynamic_cast(m_TrackingHandler)->SetIsOdfFromTensor(true); } else { if (m_TrackingHandler==nullptr) { m_TrackingHandler = new mitk::TrackingHandlerTensor(); for (unsigned int i=0; i(m_TrackingHandler)->AddTensorImage(mitk::convert::GetItkTensorFromTensorImage(dynamic_cast(m_InputImageNodes.at(i)->GetData())).GetPointer()); if (m_Controls->m_FaImageSelectionWidget->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageSelectionWidget->GetSelectedNode()->GetData()), itkImg); dynamic_cast(m_TrackingHandler)->SetFaImage(itkImg); } } } } else if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) || dynamic_cast(m_InputImageNodes.at(0)->GetData())) { if (m_TrackingHandler==nullptr) { m_TrackingHandler = new mitk::TrackingHandlerOdf(); if (dynamic_cast(m_InputImageNodes.at(0)->GetData())) dynamic_cast(m_TrackingHandler)->SetOdfImage(mitk::convert::GetItkOdfFromShImage(dynamic_cast(m_InputImageNodes.at(0)->GetData()))); else dynamic_cast(m_TrackingHandler)->SetOdfImage(mitk::convert::GetItkOdfFromOdfImage(dynamic_cast(m_InputImageNodes.at(0)->GetData()))); if (m_Controls->m_FaImageSelectionWidget->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageSelectionWidget->GetSelectedNode()->GetData()), itkImg); dynamic_cast(m_TrackingHandler)->SetGfaImage(itkImg); } } } else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_InputImageNodes.at(0)->GetData())) ) { if ( m_Controls->m_ForestSelectionWidget->GetSelectedNode().IsNull() ) { QMessageBox::information(nullptr, "Information", "Not random forest for machine learning based tractography (raw dMRI tractography) selected. Did you accidentally select the raw diffusion-weighted image in the datamanager?"); StartStopTrackingGui(false); return; } if (m_TrackingHandler==nullptr) { mitk::TractographyForest::Pointer forest = dynamic_cast(m_Controls->m_ForestSelectionWidget->GetSelectedNode()->GetData()); mitk::Image::Pointer dwi = dynamic_cast(m_InputImageNodes.at(0)->GetData()); std::vector< std::vector< ItkFloatImageType::Pointer > > additionalFeatureImages; additionalFeatureImages.push_back(std::vector< ItkFloatImageType::Pointer >()); for (auto img : m_AdditionalInputImages) { ItkFloatImageType::Pointer itkimg = ItkFloatImageType::New(); mitk::CastToItkImage(img, itkimg); additionalFeatureImages.at(0).push_back(itkimg); } bool forest_valid = false; if (forest->GetNumFeatures()>=100) { params->m_NumPreviousDirections = static_cast((forest->GetNumFeatures() - (100 + additionalFeatureImages.at(0).size()))/3); m_TrackingHandler = new mitk::TrackingHandlerRandomForest<6, 100>(); dynamic_cast*>(m_TrackingHandler)->AddDwi(dwi); dynamic_cast*>(m_TrackingHandler)->SetAdditionalFeatureImages(additionalFeatureImages); dynamic_cast*>(m_TrackingHandler)->SetForest(forest); forest_valid = dynamic_cast*>(m_TrackingHandler)->IsForestValid(); } else { params->m_NumPreviousDirections = static_cast((forest->GetNumFeatures() - (28 + additionalFeatureImages.at(0).size()))/3); m_TrackingHandler = new mitk::TrackingHandlerRandomForest<6, 28>(); dynamic_cast*>(m_TrackingHandler)->AddDwi(dwi); dynamic_cast*>(m_TrackingHandler)->SetAdditionalFeatureImages(additionalFeatureImages); dynamic_cast*>(m_TrackingHandler)->SetForest(forest); forest_valid = dynamic_cast*>(m_TrackingHandler)->IsForestValid(); } if (!forest_valid) { QMessageBox::information(nullptr, "Information", "Random forest is invalid. The forest signatue does not match the parameters of TrackingHandlerRandomForest."); StartStopTrackingGui(false); return; } } } else { if (m_TrackingHandler==nullptr) { m_TrackingHandler = new mitk::TrackingHandlerPeaks(); dynamic_cast(m_TrackingHandler)->SetPeakImage(mitk::convert::GetItkPeakFromPeakImage(dynamic_cast(m_InputImageNodes.at(0)->GetData()))); } } if (m_Controls->m_InteractiveBox->isChecked()) { m_Tracker->SetSeedPoints(m_SeedPoints); } else if (m_Controls->m_SeedImageSelectionWidget->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_SeedImageSelectionWidget->GetSelectedNode()->GetData()), mask); m_Tracker->SetSeedImage(mask); } if (m_Controls->m_MaskImageSelectionWidget->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_MaskImageSelectionWidget->GetSelectedNode()->GetData()), mask); m_Tracker->SetMaskImage(mask); } if (m_Controls->m_StopImageSelectionWidget->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_StopImageSelectionWidget->GetSelectedNode()->GetData()), mask); m_Tracker->SetStoppingRegions(mask); } if (m_Controls->m_TargetImageSelectionWidget->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_TargetImageSelectionWidget->GetSelectedNode()->GetData()), mask); m_Tracker->SetTargetRegions(mask); } if (m_Controls->m_PriorImageSelectionWidget->GetSelectedNode().IsNotNull()) { auto prior_params = GetParametersFromGui(); if (m_LastPrior!=m_Controls->m_PriorImageSelectionWidget->GetSelectedNode() || m_TrackingPriorHandler==nullptr) { typedef mitk::ImageToItk< mitk::TrackingHandlerPeaks::PeakImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(dynamic_cast(m_Controls->m_PriorImageSelectionWidget->GetSelectedNode()->GetData())); caster->SetCopyMemFlag(true); caster->Update(); mitk::TrackingHandlerPeaks::PeakImgType::Pointer itkImg = caster->GetOutput(); m_TrackingPriorHandler = new mitk::TrackingHandlerPeaks(); dynamic_cast(m_TrackingPriorHandler)->SetPeakImage(itkImg); m_LastPrior = m_Controls->m_PriorImageSelectionWidget->GetSelectedNode(); } prior_params->m_FlipX = m_Controls->m_PriorFlipXBox->isChecked(); prior_params->m_FlipY = m_Controls->m_PriorFlipYBox->isChecked(); prior_params->m_FlipZ = m_Controls->m_PriorFlipZBox->isChecked(); m_TrackingPriorHandler->SetParameters(prior_params); m_Tracker->SetTrackingPriorHandler(m_TrackingPriorHandler); } else if (m_Controls->m_PriorImageSelectionWidget->GetSelectedNode().IsNull()) m_Tracker->SetTrackingPriorHandler(nullptr); if (m_Controls->m_ExclusionImageSelectionWidget->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_ExclusionImageSelectionWidget->GetSelectedNode()->GetData()), mask); m_Tracker->SetExclusionRegions(mask); } if (params->m_EpConstraints!=itk::StreamlineTrackingFilter::EndpointConstraints::NONE && m_Controls->m_TargetImageSelectionWidget->GetSelectedNode().IsNull()) { QMessageBox::information(nullptr, "Error", "Endpoint constraints are used but no target image is set!"); StartStopTrackingGui(false); return; } else if (params->m_EpConstraints==itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_SEED_AND_TARGET && (m_Controls->m_SeedImageSelectionWidget->GetSelectedNode().IsNull()|| m_Controls->m_TargetImageSelectionWidget->GetSelectedNode().IsNull()) ) { QMessageBox::information(nullptr, "Error", "Endpoint constraint EPS_IN_SEED_AND_TARGET is used but no target or no seed image is set!"); StartStopTrackingGui(false); return; } m_Tracker->SetParameters(params); m_Tracker->SetTrackingHandler(m_TrackingHandler); m_Tracker->SetVerbose(!m_Controls->m_InteractiveBox->isChecked()); m_ParentNode = m_InputImageNodes.at(0); m_TrackingThread.start(QThread::LowestPriority); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorView.cpp index c4d8dba..d1180fd 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorView.cpp @@ -1,201 +1,201 @@ /*=================================================================== 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 #include // Qmitk #include "QmitkDicomTractogramTagEditorView.h" #include "QmitkStdMultiWidget.h" // Qt #include // MITK #include #include #include #include const std::string QmitkDicomTractogramTagEditorView::VIEW_ID = "org.mitk.views.dicomtractogramtageditor"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace berry; QmitkDicomTractogramTagEditorView::QmitkDicomTractogramTagEditorView() : m_Controls(nullptr) { m_TagList = {"DICOM.patient_id", "DICOM.patient_name", "DICOM.study_instance_uid", "DICOM.series_instance_uid", "DICOM.sop_instance_uid", "DICOM.frame_of_reference_uid", - "DICOM.algo_code.value", - "DICOM.algo_code.meaning", + "DICOM.algo_family_code.value", + "DICOM.algo_family_code.meaning", "DICOM.model_code.value", "DICOM.model_code.meaning", "DICOM.anatomy.value", "DICOM.anatomy.meaning"}; m_ImageTagList = {"DICOM.patient_id", "DICOM.patient_name", "DICOM.study_instance_uid", "DICOM.series_instance_uid", "DICOM.sop_instance_uid", "DICOM.frame_of_reference_uid"}; } // Destructor QmitkDicomTractogramTagEditorView::~QmitkDicomTractogramTagEditorView() { } void QmitkDicomTractogramTagEditorView::CreateQtPartControl( QWidget *parent ) { if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkDicomTractogramTagEditorViewControls; m_Controls->setupUi( parent ); m_Controls->m_TractogramBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isFibPredicate = mitk::TNodePredicateDataType::New(); m_Controls->m_TractogramBox->SetPredicate( isFibPredicate ); m_Controls->m_TractogramBox->SetZeroEntryText("--"); m_Controls->m_TagTable->setColumnCount(2); m_Controls->m_TagTable->setRowCount(m_TagList.size()); m_Controls->m_TagTable->verticalHeader()->setVisible(false); m_Controls->m_TagTable->setSelectionMode(QAbstractItemView::SingleSelection); QStringList tableHeader; tableHeader <<"Tag"<<"Value"; m_Controls->m_TagTable->setHorizontalHeaderLabels(tableHeader); m_Controls->m_TagTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); m_Controls->m_CopyPropsButton->setEnabled(false); connect( (QObject*)(m_Controls->m_TractogramBox), SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnTractSelectionChanged()) ); connect( (QObject*)(m_Controls->m_TagTable), SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(OnItemChanged(QTableWidgetItem*)) ); connect( m_Controls->m_CopyPropsButton, SIGNAL(clicked()), this, SLOT(CopyProperties())); UpdateGui(); } } void QmitkDicomTractogramTagEditorView::CopyProperties() { if (m_Controls->m_TractogramBox->GetSelectedNode()==nullptr) return; mitk::FiberBundle::Pointer fib = dynamic_cast(m_Controls->m_TractogramBox->GetSelectedNode()->GetData()); if (fib.IsNull()) return; if (m_Image.IsNull()) return; mitk::PropertyList* source_p_list = m_Image->GetPropertyList(); mitk::PropertyList* target_p_list = fib->GetPropertyList(); for (std::string tag : m_ImageTagList) { - std::string val = "-"; + std::string val = "0"; source_p_list->GetStringProperty(tag.c_str(), val); target_p_list->SetStringProperty(tag.c_str(), val.c_str()); } UpdateGui(); } void QmitkDicomTractogramTagEditorView::OnItemChanged(QTableWidgetItem* item) { if (m_Controls->m_TractogramBox->GetSelectedNode()==nullptr) { UpdateGui(); return; } int col = item->column(); if (col==1) { std::string tag = m_TagList.at(item->row()); mitk::FiberBundle::Pointer fib = dynamic_cast(m_Controls->m_TractogramBox->GetSelectedNode()->GetData()); mitk::PropertyList* p_list = fib->GetPropertyList(); p_list->SetStringProperty(tag.c_str(), item->text().toStdString().c_str()); } UpdateGui(); } void QmitkDicomTractogramTagEditorView::OnTractSelectionChanged() { UpdateGui(); } void QmitkDicomTractogramTagEditorView::UpdateGui() { m_Controls->m_CopyPropsButton->setEnabled(false); m_Controls->m_TagTable->blockSignals(true); if (m_Controls->m_TractogramBox->GetSelectedNode()==nullptr) { int row = 0; for (std::string tag : m_TagList) { m_Controls->m_TagTable->setItem(row, 0, new QTableWidgetItem(tag.c_str())); - m_Controls->m_TagTable->setItem(row, 1, new QTableWidgetItem("-")); + m_Controls->m_TagTable->setItem(row, 1, new QTableWidgetItem("0")); ++row; } m_Controls->m_TagTable->blockSignals(false); return; } mitk::FiberBundle::Pointer fib = dynamic_cast(m_Controls->m_TractogramBox->GetSelectedNode()->GetData()); mitk::PropertyList* p_list = fib->GetPropertyList(); int row = 0; for (std::string tag : m_TagList) { - std::string val = "-"; + std::string val = "0"; p_list->GetStringProperty(tag.c_str(), val); m_Controls->m_TagTable->setItem(row, 0, new QTableWidgetItem(tag.c_str())); m_Controls->m_TagTable->setItem(row, 1, new QTableWidgetItem(val.c_str())); ++row; } if (m_Image.IsNotNull()) m_Controls->m_CopyPropsButton->setEnabled(true); m_Controls->m_TagTable->blockSignals(false); } void QmitkDicomTractogramTagEditorView::OnSelectionChanged( berry::IWorkbenchPart::Pointer , const QList& nodes) { m_Image = nullptr; for (auto node : nodes) { mitk::Image::Pointer img = dynamic_cast(node->GetData()); if (img.IsNotNull()) { m_Image = img; } } UpdateGui(); } void QmitkDicomTractogramTagEditorView::SetFocus() { }