diff --git a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/files.cmake b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/files.cmake index 72798e5e8e..c003d57737 100644 --- a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/files.cmake +++ b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/files.cmake @@ -1,23 +1,24 @@ set(CPP_FILES mitkDiffusionCoreIOActivator.cpp + mitkPeakImageReader.cpp mitkNrrdTensorImageReader.cpp mitkNrrdTensorImageWriter.cpp mitkTensorImageSerializer.cpp mitkTensorImageSource.cpp mitkDiffusionCoreObjectFactory.cpp mitkDiffusionCoreIOMimeTypes.cpp mitkDiffusionImageDicomReaderService.cpp mitkDiffusionImageNrrdReaderService.cpp mitkDiffusionImageNrrdWriterService.cpp mitkDiffusionImageNiftiReaderService.cpp mitkDiffusionImageNiftiWriterService.cpp mitkNrrdOdfImageReader.cpp mitkNrrdOdfImageWriter.cpp mitkOdfImageSerializer.cpp mitkCompositeMapper.cpp ) diff --git a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOActivator.cpp b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOActivator.cpp index 88a67ccc10..2c2a187d37 100644 --- a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOActivator.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOActivator.cpp @@ -1,136 +1,140 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include "mitkDiffusionCoreIOMimeTypes.h" namespace mitk { /** \brief Registers services for segmentation module. */ class DiffusionCoreIOActivator : public us::ModuleActivator { public: void Load(us::ModuleContext* context) override { us::ServiceProperties props; props[ us::ServiceConstants::SERVICE_RANKING() ] = 10; m_MimeTypes = mitk::DiffusionCoreIOMimeTypes::Get(); for (std::vector::const_iterator mimeTypeIter = m_MimeTypes.begin(), iterEnd = m_MimeTypes.end(); mimeTypeIter != iterEnd; ++mimeTypeIter) { context->RegisterService(*mimeTypeIter, props); } m_DiffusionImageNrrdReaderService = new DiffusionImageNrrdReaderService(); m_DiffusionImageNiftiReaderService = new DiffusionImageNiftiReaderService( CustomMimeType( mitk::DiffusionCoreIOMimeTypes::DWI_NIFTI_MIMETYPE() ), mitk::DiffusionCoreIOMimeTypes::DWI_NIFTI_MIMETYPE_DESCRIPTION() ); m_DiffusionImageFslNiftiReaderService = new DiffusionImageNiftiReaderService( CustomMimeType( mitk::DiffusionCoreIOMimeTypes::DWI_FSL_MIMETYPE() ), mitk::DiffusionCoreIOMimeTypes::DWI_FSL_MIMETYPE_DESCRIPTION() ); m_DiffusionImageDicomReaderService = new DiffusionImageDicomReaderService(); m_NrrdTensorImageReader = new NrrdTensorImageReader(); m_NrrdOdfImageReader = new NrrdOdfImageReader(); + m_PeakImageReader = new PeakImageReader(); m_DiffusionImageNrrdWriterService = new DiffusionImageNrrdWriterService(); m_DiffusionImageNiftiWriterService = new DiffusionImageNiftiWriterService(); m_NrrdTensorImageWriter = new NrrdTensorImageWriter(); m_NrrdOdfImageWriter = new NrrdOdfImageWriter(); //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); } void Unload(us::ModuleContext*) override { for (unsigned int loop(0); loop < m_MimeTypes.size(); ++loop) { delete m_MimeTypes.at(loop); } delete m_DiffusionImageNrrdReaderService; delete m_DiffusionImageNiftiReaderService; delete m_DiffusionImageFslNiftiReaderService; delete m_DiffusionImageDicomReaderService; delete m_NrrdTensorImageReader; delete m_NrrdOdfImageReader; + delete m_PeakImageReader; delete m_DiffusionImageNrrdWriterService; delete m_DiffusionImageNiftiWriterService; delete m_NrrdTensorImageWriter; delete m_NrrdOdfImageWriter; } private: DiffusionImageNrrdReaderService * m_DiffusionImageNrrdReaderService; DiffusionImageNiftiReaderService * m_DiffusionImageNiftiReaderService; DiffusionImageNiftiReaderService * m_DiffusionImageFslNiftiReaderService; DiffusionImageDicomReaderService * m_DiffusionImageDicomReaderService; NrrdTensorImageReader * m_NrrdTensorImageReader; NrrdOdfImageReader * m_NrrdOdfImageReader; + PeakImageReader * m_PeakImageReader; DiffusionImageNrrdWriterService * m_DiffusionImageNrrdWriterService; DiffusionImageNiftiWriterService * m_DiffusionImageNiftiWriterService; NrrdTensorImageWriter * m_NrrdTensorImageWriter; NrrdOdfImageWriter * m_NrrdOdfImageWriter; std::vector m_MimeTypes; }; } US_EXPORT_MODULE_ACTIVATOR(mitk::DiffusionCoreIOActivator) diff --git a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOMimeTypes.cpp b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOMimeTypes.cpp index 5e197c95a6..b05a53cc8d 100644 --- a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOMimeTypes.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOMimeTypes.cpp @@ -1,454 +1,515 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDiffusionCoreIOMimeTypes.h" #include "mitkIOMimeTypes.h" #include #include #include #include #include #include #include #include +#include namespace mitk { std::vector DiffusionCoreIOMimeTypes::Get() { std::vector mimeTypes; // order matters here (descending rank for mime types) mimeTypes.push_back(DWI_NRRD_MIMETYPE().Clone()); mimeTypes.push_back(DWI_NIFTI_MIMETYPE().Clone()); mimeTypes.push_back(DWI_FSL_MIMETYPE().Clone()); mimeTypes.push_back(DWI_DICOM_MIMETYPE().Clone()); mimeTypes.push_back(DTI_MIMETYPE().Clone()); mimeTypes.push_back(ODF_MIMETYPE().Clone()); + mimeTypes.push_back(PEAK_MIMETYPE().Clone()); return mimeTypes; } // Mime Types DiffusionCoreIOMimeTypes::DiffusionImageNrrdMimeType::DiffusionImageNrrdMimeType() : CustomMimeType(DWI_NRRD_MIMETYPE_NAME()) { std::string category = "Diffusion Weighted Images"; this->SetCategory(category); this->SetComment("Diffusion Weighted Images"); this->AddExtension("dwi"); //this->AddExtension("hdwi"); // saving with detached header does not work out of the box this->AddExtension("nrrd"); } bool DiffusionCoreIOMimeTypes::DiffusionImageNrrdMimeType::AppliesTo(const std::string &path) const { bool canRead( CustomMimeType::AppliesTo(path) ); // fix for bug 18572 // Currently this function is called for writing as well as reading, in that case // the image information can of course not be read // This is a bug, this function should only be called for reading. if( ! itksys::SystemTools::FileExists( path.c_str() ) ) { return canRead; } //end fix for bug 18572 std::string ext = this->GetExtension( path ); ext = itksys::SystemTools::LowerCase( ext ); // Simple NRRD files should only be considered for this mime type if they contain // corresponding tags if( ext == ".nrrd" ) { itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); io->SetFileName(path); try { io->ReadImageInformation(); itk::MetaDataDictionary imgMetaDictionary = io->GetMetaDataDictionary(); std::vector imgMetaKeys = imgMetaDictionary.GetKeys(); std::vector::const_iterator itKey = imgMetaKeys.begin(); std::string metaString; for (; itKey != imgMetaKeys.end(); itKey ++) { itk::ExposeMetaData (imgMetaDictionary, *itKey, metaString); if (itKey->find("modality") != std::string::npos) { if (metaString.find("DWMRI") != std::string::npos) { return canRead; } } } } catch( const itk::ExceptionObject &e ) { MITK_ERROR << "ITK Exception: " << e.what(); } canRead = false; } return canRead; } DiffusionCoreIOMimeTypes::DiffusionImageNrrdMimeType* DiffusionCoreIOMimeTypes::DiffusionImageNrrdMimeType::Clone() const { return new DiffusionImageNrrdMimeType(*this); } DiffusionCoreIOMimeTypes::DiffusionImageNrrdMimeType DiffusionCoreIOMimeTypes::DWI_NRRD_MIMETYPE() { return DiffusionImageNrrdMimeType(); } DiffusionCoreIOMimeTypes::DiffusionImageNiftiMimeType::DiffusionImageNiftiMimeType() : CustomMimeType(DWI_NIFTI_MIMETYPE_NAME()) { std::string category = "Diffusion Weighted Images"; this->SetCategory(category); this->SetComment("Diffusion Weighted Images"); this->AddExtension("nii.gz"); this->AddExtension("nii"); } bool DiffusionCoreIOMimeTypes::DiffusionImageNiftiMimeType::AppliesTo(const std::string &path) const { bool canRead(CustomMimeType::AppliesTo(path)); // fix for bug 18572 // Currently this function is called for writing as well as reading, in that case // the image information can of course not be read // This is a bug, this function should only be called for reading. if (!itksys::SystemTools::FileExists(path.c_str())) { return canRead; } //end fix for bug 18572 std::string ext = this->GetExtension(path); ext = itksys::SystemTools::LowerCase(ext); // Nifti files should only be considered for this mime type if they are // accompanied by bvecs and bvals files defining the diffusion information if (ext == ".nii" || ext == ".nii.gz") { std::string base_path = itksys::SystemTools::GetFilenamePath(path); std::string base = this->GetFilenameWithoutExtension(path); std::string filename = base; if (!base_path.empty()) { base = base_path + "/" + base; base_path += "/"; } if (itksys::SystemTools::FileExists(std::string(base + ".bvec").c_str()) && itksys::SystemTools::FileExists(std::string(base + ".bval").c_str()) ) { return canRead; } if (itksys::SystemTools::FileExists(std::string(base + ".bvecs").c_str()) && itksys::SystemTools::FileExists(std::string(base + ".bvals").c_str()) ) { return canRead; } // hack for HCP data if ( filename=="data" && itksys::SystemTools::FileExists(std::string(base_path + "bvec").c_str()) && itksys::SystemTools::FileExists(std::string(base_path + "bval").c_str()) ) { return canRead; } if ( filename=="data" && itksys::SystemTools::FileExists(std::string(base_path + "bvecs").c_str()) && itksys::SystemTools::FileExists(std::string(base_path + "bvals").c_str()) ) { return canRead; } canRead = false; } return canRead; } DiffusionCoreIOMimeTypes::DiffusionImageNiftiMimeType* DiffusionCoreIOMimeTypes::DiffusionImageNiftiMimeType::Clone() const { return new DiffusionImageNiftiMimeType(*this); } DiffusionCoreIOMimeTypes::DiffusionImageNiftiMimeType DiffusionCoreIOMimeTypes::DWI_NIFTI_MIMETYPE() { return DiffusionImageNiftiMimeType(); } DiffusionCoreIOMimeTypes::DiffusionImageFslMimeType::DiffusionImageFslMimeType() : CustomMimeType(DWI_FSL_MIMETYPE_NAME()) { std::string category = "Diffusion Weighted Image"; this->SetCategory(category); this->SetComment("Diffusion Weighted Images"); this->AddExtension("fslgz"); this->AddExtension("fsl"); } bool DiffusionCoreIOMimeTypes::DiffusionImageFslMimeType::AppliesTo(const std::string &path) const { bool canRead(CustomMimeType::AppliesTo(path)); // fix for bug 18572 // Currently this function is called for writing as well as reading, in that case // the image information can of course not be read // This is a bug, this function should only be called for reading. if (!itksys::SystemTools::FileExists(path.c_str())) { return canRead; } //end fix for bug 18572 std::string ext = this->GetExtension(path); ext = itksys::SystemTools::LowerCase(ext); // Nifti files should only be considered for this mime type if they are // accompanied by bvecs and bvals files defining the diffusion information if (ext == ".fsl" || ext == ".fslgz") { std::string base_path = itksys::SystemTools::GetFilenamePath(path); std::string base = this->GetFilenameWithoutExtension(path); if (!base_path.empty()) base = base_path + "/" + base; if (itksys::SystemTools::FileExists(std::string(base + ".bvec").c_str()) && itksys::SystemTools::FileExists(std::string(base + ".bval").c_str()) ) { return canRead; } if (itksys::SystemTools::FileExists(std::string(base + ".bvecs").c_str()) && itksys::SystemTools::FileExists(std::string(base + ".bvals").c_str()) ) { return canRead; } if (itksys::SystemTools::FileExists(std::string(base + ext + ".bvec").c_str()) && itksys::SystemTools::FileExists(std::string(base + ext + ".bval").c_str()) ) { return canRead; } if (itksys::SystemTools::FileExists(std::string(base + ext + ".bvecs").c_str()) && itksys::SystemTools::FileExists(std::string(base + ext + ".bvals").c_str()) ) { return canRead; } canRead = false; } return canRead; } DiffusionCoreIOMimeTypes::DiffusionImageFslMimeType* DiffusionCoreIOMimeTypes::DiffusionImageFslMimeType::Clone() const { return new DiffusionImageFslMimeType(*this); } DiffusionCoreIOMimeTypes::DiffusionImageFslMimeType DiffusionCoreIOMimeTypes::DWI_FSL_MIMETYPE() { return DiffusionImageFslMimeType(); } DiffusionCoreIOMimeTypes::DiffusionImageDicomMimeType::DiffusionImageDicomMimeType() : CustomMimeType(DWI_DICOM_MIMETYPE_NAME()) { std::string category = "Diffusion Weighted Images"; this->SetCategory(category); this->SetComment("Diffusion Weighted Images"); this->AddExtension("gdcm"); this->AddExtension("dcm"); this->AddExtension("DCM"); this->AddExtension("dc3"); this->AddExtension("DC3"); this->AddExtension("ima"); this->AddExtension("img"); } bool DiffusionCoreIOMimeTypes::DiffusionImageDicomMimeType::AppliesTo(const std::string &path) const { itk::GDCMImageIO::Pointer gdcmIO = itk::GDCMImageIO::New(); bool canRead = gdcmIO->CanReadFile(path.c_str()); if (!canRead) return canRead; mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New(); mitk::DICOMTag ImageTypeTag(0x0008, 0x0008); mitk::StringList relevantFiles; relevantFiles.push_back(path); scanner->AddTag(ImageTypeTag); scanner->SetInputFiles(relevantFiles); scanner->Scan(); mitk::DICOMTagCache::Pointer tagCache = scanner->GetScanCache(); mitk::DICOMImageFrameList imageFrameList = mitk::ConvertToDICOMImageFrameList(tagCache->GetFrameInfoList()); mitk::DICOMImageFrameInfo *firstFrame = imageFrameList.begin()->GetPointer(); std::string byteString = tagCache->GetTagValue(firstFrame, ImageTypeTag).value; if (byteString.empty()) { return false; } std::size_t found = byteString.find("DIFFUSION"); if (found==std::string::npos) return false; found = byteString.find("NONE"); if (found==std::string::npos) return false; return canRead; } DiffusionCoreIOMimeTypes::DiffusionImageDicomMimeType* DiffusionCoreIOMimeTypes::DiffusionImageDicomMimeType::Clone() const { return new DiffusionImageDicomMimeType(*this); } DiffusionCoreIOMimeTypes::DiffusionImageDicomMimeType DiffusionCoreIOMimeTypes::DWI_DICOM_MIMETYPE() { return DiffusionImageDicomMimeType(); } +DiffusionCoreIOMimeTypes::PeakImageMimeType::PeakImageMimeType() : CustomMimeType(PEAK_MIMETYPE_NAME()) +{ + std::string category = "Peak Image"; + this->SetCategory(category); + this->SetComment("Peak Image"); + + this->AddExtension("nrrd"); + this->AddExtension("nii"); + this->AddExtension("nii.gz"); +} + +bool DiffusionCoreIOMimeTypes::PeakImageMimeType::AppliesTo(const std::string &path) const +{ + { + itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); + if ( io->CanReadFile( path.c_str() ) ) + { + io->SetFileName( path.c_str() ); + io->ReadImageInformation(); + if ( io->GetPixelType() == itk::ImageIOBase::SCALAR && io->GetNumberOfDimensions()==4 && io->GetDimensions(3)%3==0) + return true; + } + } + { + itk::NiftiImageIO::Pointer io = itk::NiftiImageIO::New(); + if ( io->CanReadFile( path.c_str() ) ) + { + io->SetFileName( path.c_str() ); + io->ReadImageInformation(); + if ( io->GetPixelType() == itk::ImageIOBase::SCALAR && io->GetNumberOfDimensions()==4 && io->GetDimensions(3)%3==0) + return true; + } + } + + return false; +} + +DiffusionCoreIOMimeTypes::PeakImageMimeType* DiffusionCoreIOMimeTypes::PeakImageMimeType::Clone() const +{ + return new PeakImageMimeType(*this); +} + + +DiffusionCoreIOMimeTypes::PeakImageMimeType DiffusionCoreIOMimeTypes::PEAK_MIMETYPE() +{ + return PeakImageMimeType(); +} + + CustomMimeType DiffusionCoreIOMimeTypes::DTI_MIMETYPE() { CustomMimeType mimeType(DTI_MIMETYPE_NAME()); std::string category = "Tensor Images"; mimeType.SetComment("Diffusion Tensor Images"); mimeType.SetCategory(category); mimeType.AddExtension("dti"); - //mimeType.AddExtension("hdti"); // saving with detached header does not work out of the box return mimeType; } CustomMimeType DiffusionCoreIOMimeTypes::ODF_MIMETYPE() { CustomMimeType mimeType(ODF_MIMETYPE_NAME()); std::string category = "ODF Images"; mimeType.SetComment("Diffusion ODF Images"); mimeType.SetCategory(category); mimeType.AddExtension("odf"); mimeType.AddExtension("qbi"); // legacy support return mimeType; } // Names +std::string DiffusionCoreIOMimeTypes::PEAK_MIMETYPE_NAME() +{ + static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".nrrd"; + return name; +} + std::string DiffusionCoreIOMimeTypes::DWI_NRRD_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".dwi"; return name; } std::string DiffusionCoreIOMimeTypes::DWI_NIFTI_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".nii.gz"; return name; } std::string DiffusionCoreIOMimeTypes::DWI_FSL_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".fslgz"; return name; } std::string DiffusionCoreIOMimeTypes::DWI_DICOM_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".IMA"; return name; } std::string DiffusionCoreIOMimeTypes::DTI_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".dti"; return name; } std::string DiffusionCoreIOMimeTypes::ODF_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".odf"; return name; } // Descriptions +std::string DiffusionCoreIOMimeTypes::PEAK_MIMETYPE_DESCRIPTION() +{ + static std::string description = "Peak Image"; + return description; +} std::string DiffusionCoreIOMimeTypes::DWI_NRRD_MIMETYPE_DESCRIPTION() { static std::string description = "Diffusion Weighted Images"; return description; } std::string DiffusionCoreIOMimeTypes::DWI_NIFTI_MIMETYPE_DESCRIPTION() { static std::string description = "Diffusion Weighted Images"; return description; } std::string DiffusionCoreIOMimeTypes::DWI_FSL_MIMETYPE_DESCRIPTION() { static std::string description = "Diffusion Weighted Images"; return description; } std::string DiffusionCoreIOMimeTypes::DWI_DICOM_MIMETYPE_DESCRIPTION() { static std::string description = "Diffusion Weighted Images"; return description; } std::string DiffusionCoreIOMimeTypes::DTI_MIMETYPE_DESCRIPTION() { static std::string description = "Diffusion Tensor Images"; return description; } std::string DiffusionCoreIOMimeTypes::ODF_MIMETYPE_DESCRIPTION() { static std::string description = "ODF Images"; return description; } } diff --git a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOMimeTypes.h b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOMimeTypes.h index e6821c6208..01876a94fd 100644 --- a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOMimeTypes.h +++ b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOMimeTypes.h @@ -1,97 +1,108 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKDiffusionCoreIOMimeTypes_H #define MITKDiffusionCoreIOMimeTypes_H #include "mitkCustomMimeType.h" #include namespace mitk { class DiffusionCoreIOMimeTypes { public: class DiffusionImageNrrdMimeType : public CustomMimeType { public: DiffusionImageNrrdMimeType(); virtual bool AppliesTo(const std::string &path) const override; virtual DiffusionImageNrrdMimeType* Clone() const override; }; class DiffusionImageNiftiMimeType : public CustomMimeType { public: DiffusionImageNiftiMimeType(); virtual bool AppliesTo(const std::string &path) const override; virtual DiffusionImageNiftiMimeType* Clone() const override; }; class DiffusionImageFslMimeType : public CustomMimeType { public: DiffusionImageFslMimeType(); virtual bool AppliesTo(const std::string &path) const override; virtual DiffusionImageFslMimeType* Clone() const override; }; class DiffusionImageDicomMimeType : public CustomMimeType { public: DiffusionImageDicomMimeType(); virtual bool AppliesTo(const std::string &path) const override; virtual DiffusionImageDicomMimeType* Clone() const override; }; + class PeakImageMimeType : public CustomMimeType + { + public: + PeakImageMimeType(); + virtual bool AppliesTo(const std::string &path) const override; + virtual PeakImageMimeType* Clone() const override; + }; + // Get all Diffusion Mime Types static std::vector Get(); // ------------------------- Image formats (ITK based) -------------------------- static DiffusionImageNrrdMimeType DWI_NRRD_MIMETYPE(); static DiffusionImageNiftiMimeType DWI_NIFTI_MIMETYPE(); static DiffusionImageFslMimeType DWI_FSL_MIMETYPE(); static DiffusionImageDicomMimeType DWI_DICOM_MIMETYPE(); - static CustomMimeType DTI_MIMETYPE(); // dti, hdti + static PeakImageMimeType PEAK_MIMETYPE(); + static CustomMimeType DTI_MIMETYPE(); // dti static CustomMimeType ODF_MIMETYPE(); // odf, qbi + static std::string PEAK_MIMETYPE_NAME(); static std::string DWI_NRRD_MIMETYPE_NAME(); static std::string DWI_NIFTI_MIMETYPE_NAME(); static std::string DWI_FSL_MIMETYPE_NAME(); static std::string DWI_DICOM_MIMETYPE_NAME(); static std::string DTI_MIMETYPE_NAME(); static std::string ODF_MIMETYPE_NAME(); + static std::string PEAK_MIMETYPE_DESCRIPTION(); static std::string DWI_NRRD_MIMETYPE_DESCRIPTION(); static std::string DWI_NIFTI_MIMETYPE_DESCRIPTION(); static std::string DWI_FSL_MIMETYPE_DESCRIPTION(); static std::string DWI_DICOM_MIMETYPE_DESCRIPTION(); static std::string DTI_MIMETYPE_DESCRIPTION(); static std::string ODF_MIMETYPE_DESCRIPTION(); private: // purposely not implemented DiffusionCoreIOMimeTypes(); DiffusionCoreIOMimeTypes(const DiffusionCoreIOMimeTypes&); }; } #endif // MITKDiffusionCoreIOMimeTypes_H diff --git a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkPeakImageReader.cpp b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkPeakImageReader.cpp new file mode 100644 index 0000000000..1fd94331b0 --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkPeakImageReader.cpp @@ -0,0 +1,76 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkPeakImageReader.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mitk +{ + + PeakImageReader::PeakImageReader(const PeakImageReader& other) + : mitk::AbstractFileReader(other) + { + } + + PeakImageReader::PeakImageReader() + : mitk::AbstractFileReader( CustomMimeType( mitk::DiffusionCoreIOMimeTypes::PEAK_MIMETYPE() ), mitk::DiffusionCoreIOMimeTypes::PEAK_MIMETYPE_DESCRIPTION() ) + { + m_ServiceReg = this->RegisterService(); + } + + PeakImageReader::~PeakImageReader() + { + } + + std::vector > PeakImageReader::Read() + { + std::vector > result; + + typedef itk::ImageFileReader FileReaderType; + FileReaderType::Pointer reader = FileReaderType::New(); + reader->SetFileName(GetInputLocation()); + reader->Update(); + + Image::Pointer resultImage = dynamic_cast(PeakImage::New().GetPointer()); + mitk::CastToMitkImage(reader->GetOutput(), resultImage); + resultImage->SetVolume(reader->GetOutput()->GetBufferPointer()); + + StringProperty::Pointer nameProp; + nameProp = StringProperty::New(itksys::SystemTools::GetFilenameWithoutExtension(GetInputLocation())); + resultImage->SetProperty("name", nameProp); + dynamic_cast(resultImage.GetPointer())->ConstructPolydata(); + + result.push_back( resultImage.GetPointer() ); + + return result; + } + +} //namespace MITK + +mitk::PeakImageReader* mitk::PeakImageReader::Clone() const +{ + return new PeakImageReader(*this); +} diff --git a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkPeakImageReader.h b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkPeakImageReader.h new file mode 100644 index 0000000000..eddb20956e --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkPeakImageReader.h @@ -0,0 +1,53 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef __mitkPeakImageReader_h +#define __mitkPeakImageReader_h + +#include "mitkCommon.h" +#include +#include +#include + +namespace mitk +{ + + /** \brief + */ + + class PeakImageReader : public mitk::AbstractFileReader + { + public: + + PeakImageReader(const PeakImageReader& other); + PeakImageReader(); + virtual ~PeakImageReader(); + + using AbstractFileReader::Read; + virtual std::vector > Read() override; + + protected: + + + private: + PeakImageReader* Clone() const override; + + us::ServiceRegistration m_ServiceReg; + }; + +} //namespace MITK + +#endif // __mitkPeakImageReader_h diff --git a/Modules/DiffusionImaging/DiffusionCore/files.cmake b/Modules/DiffusionImaging/DiffusionCore/files.cmake index 7ffe8e1bca..b45035cfef 100644 --- a/Modules/DiffusionImaging/DiffusionCore/files.cmake +++ b/Modules/DiffusionImaging/DiffusionCore/files.cmake @@ -1,157 +1,160 @@ set(CPP_FILES # DicomImport # DicomImport/mitkGroupDiffusionHeadersFilter.cpp DicomImport/mitkDicomDiffusionImageHeaderReader.cpp DicomImport/mitkGEDicomDiffusionImageHeaderReader.cpp DicomImport/mitkPhilipsDicomDiffusionImageHeaderReader.cpp DicomImport/mitkSiemensDicomDiffusionImageHeaderReader.cpp DicomImport/mitkSiemensMosaicDicomDiffusionImageHeaderReader.cpp DicomImport/mitkDiffusionDICOMFileReader.cpp DicomImport/mitkDiffusionHeaderDICOMFileReader.cpp DicomImport/mitkDiffusionHeaderSiemensDICOMFileReader.cpp DicomImport/mitkDiffusionHeaderSiemensDICOMFileHelper.cpp DicomImport/mitkDiffusionHeaderSiemensMosaicDICOMFileReader.cpp DicomImport/mitkDiffusionHeaderGEDICOMFileReader.cpp DicomImport/mitkDiffusionHeaderPhilipsDICOMFileReader.cpp - # DataStructures -> DWI IODataStructures/DiffusionWeightedImages/mitkDiffusionImageHeaderInformation.cpp IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCorrectionFilter.cpp IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.cpp # Properties IODataStructures/Properties/mitkBValueMapProperty.cpp IODataStructures/Properties/mitkGradientDirectionsProperty.cpp IODataStructures/Properties/mitkMeasurementFrameProperty.cpp IODataStructures/Properties/mitkDiffusionPropertyHelper.cpp IODataStructures/Properties/mitkNodePredicateIsDWI.cpp # Serializer IODataStructures/Properties/mitkBValueMapPropertySerializer.cpp IODataStructures/Properties/mitkGradientDirectionsPropertySerializer.cpp IODataStructures/Properties/mitkMeasurementFramePropertySerializer.cpp # DataStructures -> Odf IODataStructures/OdfImages/mitkOdfImageSource.cpp IODataStructures/OdfImages/mitkOdfImage.cpp # DataStructures -> Tensor IODataStructures/TensorImages/mitkTensorImage.cpp + # DataStructures -> Peaks + IODataStructures/mitkPeakImage.cpp + Rendering/vtkMaskedProgrammableGlyphFilter.cpp Rendering/mitkVectorImageVtkGlyphMapper3D.cpp Rendering/vtkOdfSource.cxx Rendering/vtkThickPlane.cxx Rendering/mitkOdfNormalizationMethodProperty.cpp Rendering/mitkOdfScaleByProperty.cpp # Algorithms Algorithms/mitkPartialVolumeAnalysisHistogramCalculator.cpp Algorithms/mitkPartialVolumeAnalysisClusteringCalculator.cpp Algorithms/itkDwiGradientLengthCorrectionFilter.cpp # Registration Algorithms & Co. Algorithms/Registration/mitkRegistrationWrapper.cpp Algorithms/Registration/mitkPyramidImageRegistrationMethod.cpp # Algorithms/Registration/mitkRegistrationMethodITK4.cpp Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.cpp # MultishellProcessing Algorithms/Reconstruction/MultishellProcessing/itkADCAverageFunctor.cpp Algorithms/Reconstruction/MultishellProcessing/itkADCFitFunctor.cpp Algorithms/Reconstruction/MultishellProcessing/itkKurtosisFitFunctor.cpp Algorithms/Reconstruction/MultishellProcessing/itkBiExpFitFunctor.cpp # Function Collection mitkDiffusionFunctionCollection.cpp ) set(H_FILES # function Collection include/mitkDiffusionFunctionCollection.h # Rendering include/Rendering/mitkOdfVtkMapper2D.h # Reconstruction include/Algorithms/Reconstruction/itkDiffusionQballReconstructionImageFilter.h include/Algorithms/Reconstruction/mitkTeemDiffusionTensor3DReconstructionImageFilter.h include/Algorithms/Reconstruction/itkAnalyticalDiffusionQballReconstructionImageFilter.h include/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.h include/Algorithms/Reconstruction/itkPointShell.h include/Algorithms/Reconstruction/itkOrientationDistributionFunction.h include/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h include/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.h include/Algorithms/Reconstruction/itkBallAndSticksImageFilter.h include/Algorithms/Reconstruction/itkMultiTensorImageFilter.h # Fitting functions include/Algorithms/Reconstruction/FittingFunctions/mitkAbstractFitter.h include/Algorithms/Reconstruction/FittingFunctions/mitkMultiTensorFitter.h include/Algorithms/Reconstruction/FittingFunctions/mitkBallStickFitter.h # MultishellProcessing include/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.h include/Algorithms/Reconstruction/MultishellProcessing/itkDWIVoxelFunctor.h include/Algorithms/Reconstruction/MultishellProcessing/itkADCAverageFunctor.h include/Algorithms/Reconstruction/MultishellProcessing/itkKurtosisFitFunctor.h include/Algorithms/Reconstruction/MultishellProcessing/itkBiExpFitFunctor.h include/Algorithms/Reconstruction/MultishellProcessing/itkADCFitFunctor.h # Properties include/IODataStructures/Properties/mitkBValueMapProperty.h include/IODataStructures/Properties/mitkGradientDirectionsProperty.h include/IODataStructures/Properties/mitkMeasurementFrameProperty.h include/IODataStructures/Properties/mitkDiffusionPropertyHelper.h include/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageTransformedCreationFilter.h # Algorithms include/Algorithms/itkDiffusionOdfGeneralizedFaImageFilter.h include/Algorithms/itkDiffusionOdfPrepareVisualizationImageFilter.h include/Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.h include/Algorithms/itkTensorDerivedMeasurementsFilter.h include/Algorithms/itkBrainMaskExtractionImageFilter.h include/Algorithms/itkB0ImageExtractionImageFilter.h include/Algorithms/itkB0ImageExtractionToSeparateImageFilter.h include/Algorithms/itkTensorImageToDiffusionImageFilter.h include/Algorithms/itkTensorToL2NormImageFilter.h include/Algorithms/itkGaussianInterpolateImageFunction.h include/Algorithms/mitkPartialVolumeAnalysisHistogramCalculator.h include/Algorithms/mitkPartialVolumeAnalysisClusteringCalculator.h include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h include/Algorithms/itkCartesianToPolarVectorImageFilter.h include/Algorithms/itkPolarToCartesianVectorImageFilter.h include/Algorithms/itkDistanceMapFilter.h include/Algorithms/itkProjectionFilter.h include/Algorithms/itkResidualImageFilter.h include/Algorithms/itkExtractChannelFromRgbaImageFilter.h include/Algorithms/itkTensorReconstructionWithEigenvalueCorrectionFilter.h include/Algorithms/itkMergeDiffusionImagesFilter.h include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h include/Algorithms/itkShCoefficientImageImporter.h include/Algorithms/itkShCoefficientImageExporter.h include/Algorithms/itkOdfMaximaExtractionFilter.h include/Algorithms/itkResampleDwiImageFilter.h include/Algorithms/itkDwiGradientLengthCorrectionFilter.h include/Algorithms/itkAdcImageFilter.h include/Algorithms/itkDwiNormilzationFilter.h include/Algorithms/itkSplitDWImageFilter.h include/Algorithms/itkRemoveDwiChannelFilter.h include/Algorithms/itkExtractDwiChannelFilter.h + include/Algorithms/itkFlipPeaksFilter.h include/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.h include/Algorithms/itkNonLocalMeansDenoisingFilter.h include/Algorithms/itkVectorImageToImageFilter.h ) set( TOOL_FILES ) diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h index 32305432cd..761f6e5a6d 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h @@ -1,104 +1,102 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkDiffusionTensorPrincipalDirectionImageFilter_h_ #define __itkDiffusionTensorPrincipalDirectionImageFilter_h_ #include #include #include #include #include #include #include #include #include namespace itk{ /** \brief Extracts principal eigenvectors of the input tensors */ template< class TTensorPixelType> class DiffusionTensorPrincipalDirectionImageFilter : public ImageToImageFilter< Image< DiffusionTensor3D, 3 >, Image< unsigned char, 3 > > { public: typedef DiffusionTensorPrincipalDirectionImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< DiffusionTensor3D, 3 >, Image< unsigned char, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DiffusionTensorPrincipalDirectionImageFilter, ImageToImageFilter) typedef TTensorPixelType TensorComponentType; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef itk::Image ItkUcharImgType; typedef vnl_vector_fixed< double, 3 > DirectionType; typedef Image< float, 4 > PeakImageType; void SetImage( const InputImageType *image ); // input itkSetMacro( MaskImage, ItkUcharImgType::Pointer) itkSetMacro( NormalizeVectors, bool) itkSetMacro( UsePolarCoordinates, bool) itkSetMacro( FaThreshold, float) // output - itkGetMacro( OutputFiberBundle, mitk::FiberBundle::Pointer) itkGetMacro( PeakImage, PeakImageType::Pointer) protected: DiffusionTensorPrincipalDirectionImageFilter(); ~DiffusionTensorPrincipalDirectionImageFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType ); void AfterThreadedGenerateData(); private: bool m_NormalizeVectors; ///< Normalizes the output vector to length 1 - mitk::FiberBundle::Pointer m_OutputFiberBundle; ///< Vector field representation of the output vectors ItkUcharImgType::Pointer m_MaskImage; ///< Extraction is only performed inside of the binary mask PeakImageType::Pointer m_PeakImage; bool m_UsePolarCoordinates; float m_FaThreshold; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDiffusionTensorPrincipalDirectionImageFilter.txx" #endif #endif //__itkDiffusionTensorPrincipalDirectionImageFilter_h_ diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.txx b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.txx index bf99d959fb..37e4344f4f 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.txx +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.txx @@ -1,280 +1,218 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkDiffusionTensorPrincipalDirectionImageFilter_txx #define __itkDiffusionTensorPrincipalDirectionImageFilter_txx #include #include #include #include "itkDiffusionTensorPrincipalDirectionImageFilter.h" #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" #include "itkArray.h" #include "vnl/vnl_vector.h" #include #include #include #include #include #include #define _USE_MATH_DEFINES #include namespace itk { template< class TTensorPixelType> DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType>::DiffusionTensorPrincipalDirectionImageFilter() : m_NormalizeVectors(true) , m_UsePolarCoordinates(false) , m_FaThreshold(0.2) { this->SetNumberOfRequiredInputs( 1 ); } template< class TTensorPixelType> void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType>::BeforeThreadedGenerateData() { typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); Vector spacing3 = inputImagePointer->GetSpacing(); mitk::Point3D origin3 = inputImagePointer->GetOrigin(); itk::Matrix direction3 = inputImagePointer->GetDirection(); ImageRegion<3> imageRegion3 = inputImagePointer->GetLargestPossibleRegion(); if (m_MaskImage.IsNull()) { m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( spacing3 ); m_MaskImage->SetOrigin( origin3 ); m_MaskImage->SetDirection( direction3 ); m_MaskImage->SetRegions( imageRegion3 ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } typename OutputImageType::Pointer outputImage = OutputImageType::New(); outputImage->SetSpacing( spacing3 ); outputImage->SetOrigin( origin3 ); outputImage->SetDirection( direction3 ); outputImage->SetRegions( imageRegion3 ); outputImage->Allocate(); outputImage->FillBuffer(0); this->SetNthOutput(0, outputImage); itk::Vector spacing4; itk::Point origin4; itk::Matrix direction4; itk::ImageRegion<4> imageRegion4; spacing4[0] = spacing3[0]; spacing4[1] = spacing3[1]; spacing4[2] = spacing3[2]; spacing4[3] = 1; origin4[0] = origin3[0]; origin4[1] = origin3[1]; origin4[2] = origin3[2]; origin3[3] = 0; for (int r=0; r<3; r++) for (int c=0; c<3; c++) direction4[r][c] = direction3[r][c]; direction4[3][3] = 1; imageRegion4.SetSize(0, imageRegion3.GetSize()[0]); imageRegion4.SetSize(1, imageRegion3.GetSize()[1]); imageRegion4.SetSize(2, imageRegion3.GetSize()[2]); imageRegion4.SetSize(3, 3); m_PeakImage = PeakImageType::New(); m_PeakImage->SetSpacing( spacing4 ); m_PeakImage->SetOrigin( origin4 ); m_PeakImage->SetDirection( direction4 ); m_PeakImage->SetRegions( imageRegion4 ); m_PeakImage->Allocate(); m_PeakImage->FillBuffer(0.0); } template< class TTensorPixelType> void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType> ::AfterThreadedGenerateData() { - vtkSmartPointer m_VtkCellArray = vtkSmartPointer::New(); - vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); - typename OutputImageType::Pointer numDirImage = static_cast< OutputImageType* >( this->ProcessObject::GetPrimaryOutput() ); - ImageRegionConstIterator< OutputImageType > it(numDirImage, numDirImage->GetLargestPossibleRegion() ); - - mitk::Vector3D spacing = numDirImage->GetSpacing(); - double minSpacing = spacing[0]; - if (spacing[1]GetPixel(index)==0) - { - ++it; - continue; - } - - typename PeakImageType::IndexType peakIndex; - peakIndex[0] = it.GetIndex()[0]; - peakIndex[1] = it.GetIndex()[1]; - peakIndex[2] = it.GetIndex()[2]; - DirectionType dir; - peakIndex[3] = 0; - dir[0] = m_PeakImage->GetPixel(peakIndex); - peakIndex[3] = 1; - dir[1] = m_PeakImage->GetPixel(peakIndex); - peakIndex[3] = 2; - dir[2] = m_PeakImage->GetPixel(peakIndex); - - vtkSmartPointer container = vtkSmartPointer::New(); - itk::ContinuousIndex center; - center[0] = index[0]; - center[1] = index[1]; - center[2] = index[2]; - itk::Point worldCenter; - numDirImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); - - itk::Point worldStart; - worldStart[0] = worldCenter[0]-dir[0]/2 * minSpacing; - worldStart[1] = worldCenter[1]-dir[1]/2 * minSpacing; - worldStart[2] = worldCenter[2]-dir[2]/2 * minSpacing; - vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); - container->GetPointIds()->InsertNextId(id); - itk::Point worldEnd; - worldEnd[0] = worldCenter[0]+dir[0]/2 * minSpacing; - worldEnd[1] = worldCenter[1]+dir[1]/2 * minSpacing; - worldEnd[2] = worldCenter[2]+dir[2]/2 * minSpacing; - id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); - container->GetPointIds()->InsertNextId(id); - m_VtkCellArray->InsertNextCell(container); - - ++it; - } - - vtkSmartPointer directionsPolyData = vtkSmartPointer::New(); - directionsPolyData->SetPoints(m_VtkPoints); - directionsPolyData->SetLines(m_VtkCellArray); - m_OutputFiberBundle = mitk::FiberBundle::New(directionsPolyData); } template< class TTensorPixelType> void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType> ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) { typedef itk::DiffusionTensor3D TensorType; typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); ImageRegionIterator< OutputImageType > numDirectionsIterator(outputImage, outputRegionForThread); InputIteratorType tensorIterator(inputImagePointer, outputRegionForThread ); while( !tensorIterator.IsAtEnd() ) { typename InputImageType::IndexType index = tensorIterator.GetIndex(); if (m_MaskImage->GetPixel(index)==0) { ++tensorIterator; ++numDirectionsIterator; continue; } typename InputImageType::PixelType b = tensorIterator.Get(); TensorType tensor = b.GetDataPointer(); typename PeakImageType::IndexType peakIndex; peakIndex[0] = tensorIterator.GetIndex()[0]; peakIndex[1] = tensorIterator.GetIndex()[1]; peakIndex[2] = tensorIterator.GetIndex()[2]; typename TensorType::EigenValuesArrayType eigenvalues; typename TensorType::EigenVectorsMatrixType eigenvectors; if(tensor.GetTrace()!=0) { tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); vnl_vector_fixed vec; vec[0] = eigenvectors(2,0); vec[1] = eigenvectors(2,1); vec[2] = eigenvectors(2,2); vec.normalize(); vnl_vector_fixed out; out.fill(0); float fa = tensor.GetFractionalAnisotropy(); if (faM_PI) { out[1] = out[1] - M_PI; } } else { out[0] = 0; out[1] = 0; out[2] = 0; } } else { out = vec; } } peakIndex[3] = 0; m_PeakImage->SetPixel(peakIndex, out[0]); peakIndex[3] = 1; m_PeakImage->SetPixel(peakIndex, out[1]); peakIndex[3] = 2; m_PeakImage->SetPixel(peakIndex, out[2]); numDirectionsIterator.Set( 1 ); } ++numDirectionsIterator; ++tensorIterator; } std::cout << "One Thread finished extraction" << std::endl; } template< class TTensorPixelType> void DiffusionTensorPrincipalDirectionImageFilter< TTensorPixelType> ::PrintSelf(std::ostream& , Indent ) const { } } #endif diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.cpp b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.cpp index 369f691042..0b0fe5064c 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.cpp @@ -1,548 +1,480 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkFiniteDiffOdfMaximaExtractionFilter_cpp #define __itkFiniteDiffOdfMaximaExtractionFilter_cpp #include "itkFiniteDiffOdfMaximaExtractionFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace boost::math; namespace itk { static bool CompareVectors(const vnl_vector_fixed< double, 3 >& v1, const vnl_vector_fixed< double, 3 >& v2) { return (v1.magnitude()>v2.magnitude()); } template< class PixelType, int ShOrder, int NrOdfDirections > FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::FiniteDiffOdfMaximaExtractionFilter() : m_NormalizationMethod(MAX_VEC_NORM) , m_MaxNumPeaks(2) , m_PeakThreshold(0.4) , m_AbsolutePeakThreshold(0) , m_ClusteringThreshold(0.9) , m_AngularThreshold(0.7) , m_NumCoeffs((ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder) , m_Toolkit(FSL) , m_ApplyDirectionMatrix(false) { this->SetNumberOfRequiredInputs(1); } template< class PixelType, int ShOrder, int NrOdfDirections > void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::FindCandidatePeaks(OdfType& odf, double thr, std::vector< DirectionType >& container) { double gfa = odf.GetGeneralizedFractionalAnisotropy(); //Find the peaks using a finite difference method bool flag = true; vnl_vector_fixed< bool, NrOdfDirections > used; used.fill(false); //Find the peaks for (int i=0; ithr && val*gfa>m_AbsolutePeakThreshold) // limit to one hemisphere ??? { flag = true; std::vector< int > neighbours = odf.GetNeighbors(i); for (unsigned int j=0; j std::vector< vnl_vector_fixed< double, 3 > > FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections>::MeanShiftClustering(std::vector< DirectionType >& inDirs) { std::vector< DirectionType > outDirs; if (inDirs.empty()) return inDirs; DirectionType oldMean, currentMean, workingMean; std::vector< int > touched; // initialize touched.resize(inDirs.size(), 0); bool free = true; currentMean = inDirs[0]; // initialize first seed while (free) { oldMean.fill(0.0); // start mean-shift clustering float angle = 0.0; int counter = 0; while ((currentMean-oldMean).magnitude()>0.0001) { counter = 0; oldMean = currentMean; workingMean = oldMean; workingMean.normalize(); currentMean.fill(0.0); for (unsigned int i=0; i=m_ClusteringThreshold) { currentMean += inDirs[i]; touched[i] = 1; counter++; } else if (-angle>=m_ClusteringThreshold) { currentMean -= inDirs[i]; touched[i] = 1; counter++; } } } // found stable mean if (counter>0) { float mag = currentMean.magnitude(); if (mag>0) { currentMean /= mag; outDirs.push_back(currentMean); } } // find next unused seed free = false; for (unsigned int i=0; i void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::BeforeThreadedGenerateData() { typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) ); itk::Vector spacing = ShCoeffImage->GetSpacing(); double minSpacing = spacing[0]; if (spacing[1]GetOrigin(); itk::Matrix direction = ShCoeffImage->GetDirection(); ImageRegion<3> imageRegion = ShCoeffImage->GetLargestPossibleRegion(); if (m_MaskImage.IsNotNull()) { origin = m_MaskImage->GetOrigin(); direction = m_MaskImage->GetDirection(); imageRegion = m_MaskImage->GetLargestPossibleRegion(); } itk::Vector spacing3 = ShCoeffImage->GetSpacing(); itk::Point origin3 = ShCoeffImage->GetOrigin(); itk::Matrix direction3 = ShCoeffImage->GetDirection(); itk::ImageRegion<3> imageRegion3 = ShCoeffImage->GetLargestPossibleRegion(); itk::Vector spacing4; itk::Point origin4; itk::Matrix direction4; itk::ImageRegion<4> imageRegion4; spacing4[0] = spacing3[0]; spacing4[1] = spacing3[1]; spacing4[2] = spacing3[2]; spacing4[3] = 1; origin4[0] = origin3[0]; origin4[1] = origin3[1]; origin4[2] = origin3[2]; origin4[3] = 0; for (int r=0; r<3; r++) for (int c=0; c<3; c++) direction4[r][c] = direction3[r][c]; direction4[3][3] = 1; imageRegion4.SetSize(0, imageRegion3.GetSize()[0]); imageRegion4.SetSize(1, imageRegion3.GetSize()[1]); imageRegion4.SetSize(2, imageRegion3.GetSize()[2]); imageRegion4.SetSize(3, m_MaxNumPeaks*3); m_PeakImage = PeakImageType::New(); m_PeakImage->SetSpacing( spacing4 ); m_PeakImage->SetOrigin( origin4 ); m_PeakImage->SetDirection( direction4 ); m_PeakImage->SetRegions( imageRegion4 ); m_PeakImage->Allocate(); m_PeakImage->FillBuffer(0.0); if (m_MaskImage.IsNull()) { m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( spacing ); m_MaskImage->SetOrigin( origin ); m_MaskImage->SetDirection( direction ); m_MaskImage->SetRegions( imageRegion ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } m_NumDirectionsImage = ItkUcharImgType::New(); m_NumDirectionsImage->SetSpacing( spacing ); m_NumDirectionsImage->SetOrigin( origin ); m_NumDirectionsImage->SetDirection( direction ); m_NumDirectionsImage->SetRegions( imageRegion ); m_NumDirectionsImage->Allocate(); m_NumDirectionsImage->FillBuffer(0); // calculate SH basis OdfType odf; vnl_matrix< double > sphCoords; std::vector< DirectionType > dirs; for (int i=0; i void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::AfterThreadedGenerateData() { - MITK_INFO << "Generating vector field"; - vtkSmartPointer m_VtkCellArray = vtkSmartPointer::New(); - vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); - typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) ); - ImageRegionConstIterator< CoefficientImageType > cit(ShCoeffImage, ShCoeffImage->GetLargestPossibleRegion() ); - - mitk::Vector3D spacing = ShCoeffImage->GetSpacing(); - double minSpacing = spacing[0]; - if (spacing[1]GetLargestPossibleRegion().GetSize()[0]*ShCoeffImage->GetLargestPossibleRegion().GetSize()[1]*ShCoeffImage->GetLargestPossibleRegion().GetSize()[2]; - boost::progress_display disp(maxProgress); - - while( !cit.IsAtEnd() ) - { - ++disp; - - typename CoefficientImageType::IndexType idx3 = cit.GetIndex(); - if (m_MaskImage->GetPixel(idx3)==0) - { - ++cit; - continue; - } - - itk::Index<4> idx4; idx4[0] = idx3[0]; idx4[1] = idx3[1]; idx4[2] = idx3[2]; - - for (unsigned int i=0; iGetPixel(idx4); - idx4[3] = i*3 + 1; - dir[1] = m_PeakImage->GetPixel(idx4); - idx4[3] = i*3 + 2; - dir[2] = m_PeakImage->GetPixel(idx4); - - vtkSmartPointer container = vtkSmartPointer::New(); - itk::ContinuousIndex center; - center[0] = idx3[0]; - center[1] = idx3[1]; - center[2] = idx3[2]; - itk::Point worldCenter; - m_MaskImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); - - itk::Point worldStart; - worldStart[0] = worldCenter[0]-dir[0]/2 * minSpacing; - worldStart[1] = worldCenter[1]-dir[1]/2 * minSpacing; - worldStart[2] = worldCenter[2]-dir[2]/2 * minSpacing; - vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); - container->GetPointIds()->InsertNextId(id); - itk::Point worldEnd; - worldEnd[0] = worldCenter[0]+dir[0]/2 * minSpacing; - worldEnd[1] = worldCenter[1]+dir[1]/2 * minSpacing; - worldEnd[2] = worldCenter[2]+dir[2]/2 * minSpacing; - id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); - container->GetPointIds()->InsertNextId(id); - m_VtkCellArray->InsertNextCell(container); - } - ++cit; - } - - vtkSmartPointer directionsPolyData = vtkSmartPointer::New(); - directionsPolyData->SetPoints(m_VtkPoints); - directionsPolyData->SetLines(m_VtkCellArray); - m_OutputFiberBundle = mitk::FiberBundle::New(directionsPolyData); } template< class PixelType, int ShOrder, int NrOdfDirections > void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, ThreadIdType threadID ) { typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) ); ImageRegionConstIterator< CoefficientImageType > cit(ShCoeffImage, outputRegionForThread ); OdfType odf; while( !cit.IsAtEnd() ) { typename CoefficientImageType::IndexType idx3 = cit.GetIndex(); if (m_MaskImage->GetPixel(idx3)==0) { ++cit; continue; } CoefficientPixelType c = cit.Get(); // calculate ODF double max = 0; odf.Fill(0.0); for (int i=0; imax) max = odf[i]; } if (max<0.0001) { ++cit; continue; } std::vector< DirectionType > candidates, peaks, temp; peaks.clear(); max *= m_PeakThreshold; // relative threshold FindCandidatePeaks(odf, max, candidates); // find all local maxima candidates = MeanShiftClustering(candidates); // cluster maxima vnl_matrix< double > shBasis, sphCoords; Cart2Sph(candidates, sphCoords); // convert candidate peaks to spherical angles shBasis = CalcShBasis(sphCoords); // evaluate spherical harmonics at each peak max = 0.0; for (unsigned int i=0; imax) max = val; peaks.push_back(candidates[i]*val); } std::sort( peaks.begin(), peaks.end(), CompareVectors ); // sort peaks // kick out directions to close to a larger direction (too far away to cluster but too close to keep) unsigned int m = peaks.size(); if ( m>m_MaxNumPeaks ) m = m_MaxNumPeaks; for (unsigned int i=0; im_AngularThreshold && val idx4; idx4[0] = idx3[0]; idx4[1] = idx3[1]; idx4[2] = idx3[2]; // fill output image unsigned int num = peaks.size(); if ( num>m_MaxNumPeaks ) num = m_MaxNumPeaks; for (unsigned int i=0; iGetDirection()*dir; if (m_FlipX) dir[0] = -dir[0]; if (m_FlipY) dir[1] = -dir[1]; if (m_FlipZ) dir[2] = -dir[2]; for (unsigned int j = 0; j<3; j++) { idx4[3] = i*3 + j; m_PeakImage->SetPixel(idx4, dir[j]); } } m_NumDirectionsImage->SetPixel(idx3, num); ++cit; } MITK_INFO << "Thread " << threadID << " finished extraction"; } // convert cartesian to spherical coordinates template< class PixelType, int ShOrder, int NrOdfDirections > void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::Cart2Sph(const std::vector< DirectionType >& dir, vnl_matrix& sphCoords) { sphCoords.set_size(dir.size(), 2); for (unsigned int i=0; i vnl_matrix FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::CalcShBasis(vnl_matrix& sphCoords) { int M = sphCoords.rows(); int j, m; double mag, plm; vnl_matrix shBasis; shBasis.set_size(M, m_NumCoeffs); for (int p=0; p(l,abs(m),cos(sphCoords(p,0))); mag = sqrt((double)(2*l+1)/(4.0*M_PI)*factorial(l-abs(m))/factorial(l+abs(m)))*plm; if (m<0) shBasis(p,j) = sqrt(2.0)*mag*cos(fabs((double)m)*sphCoords(p,1)); else if (m==0) shBasis(p,j) = mag; else shBasis(p,j) = pow(-1.0, m)*sqrt(2.0)*mag*sin(m*sphCoords(p,1)); break; case MRTRIX: plm = legendre_p(l,abs(m),-cos(sphCoords(p,0))); mag = sqrt((double)(2*l+1)/(4.0*M_PI)*factorial(l-abs(m))/factorial(l+abs(m)))*plm; if (m>0) shBasis(p,j) = mag*cos(m*sphCoords(p,1)); else if (m==0) shBasis(p,j) = mag; else shBasis(p,j) = mag*sin(-m*sphCoords(p,1)); break; } j++; } } return shBasis; } } #endif // __itkFiniteDiffOdfMaximaExtractionFilter_cpp diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h index 6c52c16b05..a11ed68a6b 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h @@ -1,151 +1,149 @@ /*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkDiffusionTensor3DReconstructionImageFilter.h,v $ Language: C++ Date: $Date: 2006-03-27 17:01:06 $ Version: $Revision: 1.12 $ Copyright (c) Insight Software Consortium. All rights reserved. See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef __itkFiniteDiffOdfMaximaExtractionFilter_h_ #define __itkFiniteDiffOdfMaximaExtractionFilter_h_ #include "itkImageToImageFilter.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_svd.h" #include "itkVectorContainer.h" #include "itkVectorImage.h" #include #include namespace itk{ /** * \brief Extract ODF peaks by searching all local maxima on a densely sampled ODF und clustering these maxima to get the underlying fiber direction. * NrOdfDirections: number of sampling points on the ODF surface (about 20000 is a good value) */ template< class PixelType, int ShOrder, int NrOdfDirections > class FiniteDiffOdfMaximaExtractionFilter : public ImageToImageFilter< Image< Vector< PixelType, (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder >, 3 >, Image< unsigned char, 3 > > { public: enum Toolkit { ///< SH coefficient convention (depends on toolkit) FSL, MRTRIX }; enum NormalizationMethods { NO_NORM, ///< no length normalization of the output peaks SINGLE_VEC_NORM, ///< normalize the single peaks to length 1 - MAX_VEC_NORM ///< normalize all peaks according to their length in comparison to the largest peak (0-1) + MAX_VEC_NORM ///< normalize all peaks according to their length in comparison to the largest peak in the respective voxel (0-1) }; typedef FiniteDiffOdfMaximaExtractionFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< Vector< PixelType, (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder >, 3 >, Image< unsigned char, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(FiniteDiffOdfMaximaExtractionFilter, ImageToImageFilter) typedef typename Superclass::InputImageType CoefficientImageType; typedef typename CoefficientImageType::RegionType CoefficientImageRegionType; typedef typename CoefficientImageType::PixelType CoefficientPixelType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef typename Superclass::InputImageRegionType InputImageRegionType; typedef Image< float, 4 > PeakImageType; typedef OrientationDistributionFunction OdfType; typedef itk::Image ItkUcharImgType; typedef vnl_vector_fixed< double, 3 > DirectionType; // input itkSetMacro( MaxNumPeaks, unsigned int) ///< maximum number of peaks per voxel. if more peaks are detected, only the largest are kept. itkSetMacro( PeakThreshold, double) ///< threshold on the peak length relative to the largest peak inside the current voxel itkSetMacro( AbsolutePeakThreshold, double) ///< hard threshold on the peak length of all local maxima itkSetMacro( ClusteringThreshold, double) ///< directions closer together than the specified angular threshold will be clustered (in rad) itkSetMacro( AngularThreshold, double) ///< directions closer together than the specified threshold that remain after clustering are discarded (largest is kept) (in rad) itkSetMacro( MaskImage, ItkUcharImgType::Pointer) ///< only voxels inside the binary mask are processed itkSetMacro( NormalizationMethod, NormalizationMethods) ///< normalization method of ODF peaks itkSetMacro( FlipX, bool) ///< flip peaks in x direction itkSetMacro( FlipY, bool) ///< flip peaks in y direction itkSetMacro( FlipZ, bool) ///< flip peaks in z direction itkSetMacro( ApplyDirectionMatrix, bool) // output itkGetMacro( NumDirectionsImage, ItkUcharImgType::Pointer ) itkGetMacro( PeakImage, PeakImageType::Pointer ) - itkGetMacro( OutputFiberBundle, mitk::FiberBundle::Pointer) ///< vector field (peak sizes rescaled for visualization purposes) itkSetMacro( Toolkit, Toolkit) ///< define SH coefficient convention (depends on toolkit) itkGetMacro( Toolkit, Toolkit) ///< SH coefficient convention (depends on toolkit) protected: FiniteDiffOdfMaximaExtractionFilter(); ~FiniteDiffOdfMaximaExtractionFilter(){} void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadID ); void AfterThreadedGenerateData(); /** Extract all local maxima from the densely sampled ODF surface. Thresholding possible. **/ void FindCandidatePeaks(OdfType& odf, double odfMax, std::vector< DirectionType >& inDirs); /** Cluster input directions within a certain angular threshold **/ std::vector< DirectionType > MeanShiftClustering(std::vector< DirectionType >& inDirs); /** Convert cartesian to spherical coordinates **/ void Cart2Sph(const std::vector< DirectionType >& dir, vnl_matrix& sphCoords); /** Calculate spherical harmonic basis of the defined order **/ vnl_matrix CalcShBasis(vnl_matrix& sphCoords); private: NormalizationMethods m_NormalizationMethod; ///< normalization method of ODF peaks unsigned int m_MaxNumPeaks; ///< maximum number of peaks per voxel. if more peaks are detected, only the largest are kept. double m_PeakThreshold; ///< threshold on the peak length relative to the largest peak inside the current voxel double m_AbsolutePeakThreshold;///< hard threshold on the peak length of all local maxima vnl_matrix< double > m_ShBasis; ///< container for evaluated SH base functions double m_ClusteringThreshold; ///< directions closer together than the specified angular threshold will be clustered (in rad) double m_AngularThreshold; ///< directions closer together than the specified threshold that remain after clustering are discarded (largest is kept) (in rad) const int m_NumCoeffs; ///< number of spherical harmonics coefficients - mitk::FiberBundle::Pointer m_OutputFiberBundle; ///< vector field (peak sizes rescaled for visualization purposes) PeakImageType::Pointer m_PeakImage; ItkUcharImgType::Pointer m_NumDirectionsImage; ///< number of peaks per voxel ItkUcharImgType::Pointer m_MaskImage; ///< only voxels inside the binary mask are processed Toolkit m_Toolkit; bool m_FlipX; bool m_FlipY; bool m_FlipZ; bool m_ApplyDirectionMatrix; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkFiniteDiffOdfMaximaExtractionFilter.cpp" #endif #endif //__itkFiniteDiffOdfMaximaExtractionFilter_h_ diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFlipPeaksFilter.cpp b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFlipPeaksFilter.cpp new file mode 100644 index 0000000000..0e1fc33aa9 --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFlipPeaksFilter.cpp @@ -0,0 +1,99 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ +#ifndef __itkFlipPeaksFilter_cpp +#define __itkFlipPeaksFilter_cpp + +#include "itkFlipPeaksFilter.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +using namespace boost::math; + +namespace itk { + +template< class PixelType > +FlipPeaksFilter< PixelType>::FlipPeaksFilter() +{ + this->SetNumberOfRequiredInputs(1); +} + + +template< class PixelType > +void FlipPeaksFilter< PixelType> +::BeforeThreadedGenerateData() +{ + typename InputImageType::Pointer input = static_cast< InputImageType* >( this->ProcessObject::GetInput(0) ); + +// typename OutputImageType::Pointer output = OutputImageType::New(); +// output->SetSpacing( input->GetSpacing() ); +// output->SetOrigin( input->GetOrigin() ); +// output->SetDirection( input->GetDirection() ); +// output->SetRegions( input->GetLargestPossibleRegion() ); +// output->Allocate(); +// output->FillBuffer(0.0); +} + +template< class PixelType > +void FlipPeaksFilter< PixelType> +::AfterThreadedGenerateData() +{ + +} + +template< class PixelType > +void FlipPeaksFilter< PixelType> +::ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, ThreadIdType ) +{ + typename InputImageType::Pointer input_image = static_cast< InputImageType* >( this->ProcessObject::GetInput(0) ); + typename OutputImageType::Pointer output_image = static_cast< OutputImageType* >( this->ProcessObject::GetOutput(0) ); + + ImageRegionIterator< InputImageType > iit(input_image, outputRegionForThread ); + ImageRegionIterator< OutputImageType > oit(output_image, outputRegionForThread ); + + while( !iit.IsAtEnd() ) + { + typename InputImageType::IndexType idx = iit.GetIndex(); + + oit.Set(iit.Get()); + if (m_FlipX && idx[3]%3==0) + oit.Set(-1*iit.Get()); + if (m_FlipY && idx[3]%3==1) + oit.Set(-1*iit.Get()); + if (m_FlipZ && idx[3]%3==2) + oit.Set(-1*iit.Get()); + + ++iit; + ++oit; + } +} + +} + +#endif // __itkFlipPeaksFilter_cpp diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFlipPeaksFilter.h b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFlipPeaksFilter.h new file mode 100644 index 0000000000..64ca3625d8 --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFlipPeaksFilter.h @@ -0,0 +1,84 @@ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkDiffusionTensor3DReconstructionImageFilter.h,v $ + Language: C++ + Date: $Date: 2006-03-27 17:01:06 $ + Version: $Revision: 1.12 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __itkFlipPeaksFilter_h_ +#define __itkFlipPeaksFilter_h_ + +#include "itkImageToImageFilter.h" +#include "vnl/vnl_vector_fixed.h" +#include "vnl/vnl_matrix.h" +#include "vnl/algo/vnl_svd.h" +#include "itkVectorContainer.h" +#include "itkVectorImage.h" +#include +#include +#include + +namespace itk{ + +/** +* \brief Flip peaks along specified axes +*/ + +template< class PixelType > +class FlipPeaksFilter : public ImageToImageFilter< mitk::PeakImage::ItkPeakImageType, mitk::PeakImage::ItkPeakImageType > +{ + + public: + + typedef FlipPeaksFilter Self; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + typedef ImageToImageFilter< mitk::PeakImage::ItkPeakImageType, mitk::PeakImage::ItkPeakImageType > Superclass; + + /** Method for creation through the object factory. */ + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /** Runtime information support. */ + itkTypeMacro(FlipPeaksFilter, ImageToImageFilter) + + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::OutputImageType OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + itkSetMacro( FlipX, bool) ///< flip peaks in x direction + itkSetMacro( FlipY, bool) ///< flip peaks in y direction + itkSetMacro( FlipZ, bool) ///< flip peaks in z direction + + protected: + FlipPeaksFilter(); + ~FlipPeaksFilter(){} + + void BeforeThreadedGenerateData(); + void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadID ); + void AfterThreadedGenerateData(); + + private: + + bool m_FlipX; + bool m_FlipY; + bool m_FlipZ; +}; + +} + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkFlipPeaksFilter.cpp" +#endif + +#endif //__itkFlipPeaksFilter_h_ + diff --git a/Modules/DiffusionImaging/DiffusionCore/include/IODataStructures/mitkPeakImage.h b/Modules/DiffusionImaging/DiffusionCore/include/IODataStructures/mitkPeakImage.h new file mode 100644 index 0000000000..0904e739d6 --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionCore/include/IODataStructures/mitkPeakImage.h @@ -0,0 +1,65 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef __mitkPeakImage__h +#define __mitkPeakImage__h + +#include "mitkImage.h" +#include +#include + +#include + +namespace mitk +{ + + /** + * \brief this class encapsulates tensor images + */ + class MITKDIFFUSIONCORE_EXPORT PeakImage : public Image + { + + public: + typedef itk::Image ItkPeakImageType; + + mitkClassMacro( PeakImage, Image ) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + void ConstructPolydata(); + + vtkSmartPointer< vtkPolyData > GetPolyData() + { + if (m_PolyData==nullptr) + this->ConstructPolydata(); + return m_PolyData; + } + + void SetCustomColor(float r, float g, float b); + void ColorByOrientation(); + + protected: + PeakImage(); + virtual ~PeakImage(); + + mutable vtkSmartPointer< vtkPolyData > m_PolyData; + + }; + +} // namespace mitk + +#endif /* __mitkPeakImage__h */ diff --git a/Modules/DiffusionImaging/DiffusionCore/src/Algorithms/itkDwiPhantomGenerationFilter.cpp b/Modules/DiffusionImaging/DiffusionCore/src/Algorithms/itkDwiPhantomGenerationFilter.cpp deleted file mode 100644 index 07c21396b4..0000000000 --- a/Modules/DiffusionImaging/DiffusionCore/src/Algorithms/itkDwiPhantomGenerationFilter.cpp +++ /dev/null @@ -1,401 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ -#ifndef __itkDwiPhantomGenerationFilter_cpp -#define __itkDwiPhantomGenerationFilter_cpp - -#include -#include -#include - -#include "itkDwiPhantomGenerationFilter.h" -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -namespace itk { - - - template< class TOutputScalarType > - DwiPhantomGenerationFilter< TOutputScalarType > - ::DwiPhantomGenerationFilter() - : m_BValue(1000) - , m_SignalScale(1000) - , m_BaselineImages(0) - , m_MaxBaseline(0) - , m_MeanBaseline(0) - , m_NoiseVariance(0.004) - , m_AddNoiseFlag(true) // parameters.m_Misc.m_CheckAddNoiseBox - , m_GreyMatterAdc(0.01) - , m_SimulateBaseline(true) - , m_DefaultBaseline(1000) - { - this->SetNumberOfRequiredOutputs (1); - m_Spacing.Fill(2.5); m_Origin.Fill(0.0); - m_DirectionMatrix.SetIdentity(); - m_ImageRegion.SetSize(0, 10); - m_ImageRegion.SetSize(1, 10); - m_ImageRegion.SetSize(2, 10); - - typename OutputImageType::Pointer outImage = OutputImageType::New(); - - outImage->SetSpacing( m_Spacing ); // Set the image spacing - outImage->SetOrigin( m_Origin ); // Set the image origin - outImage->SetDirection( m_DirectionMatrix ); // Set the image direction - outImage->SetLargestPossibleRegion( m_ImageRegion ); - outImage->SetBufferedRegion( m_ImageRegion ); - outImage->SetRequestedRegion( m_ImageRegion ); - outImage->SetVectorLength(ODF_SAMPLING_SIZE); - outImage->Allocate(); - // ITKv4 migration fix : removing OutputImageType::PixelType(0.0) - // the conversion is handled internally by the itk::Image - typename OutputImageType::PixelType fillValue(0.0); - outImage->FillBuffer( fillValue ); - - this->SetNthOutput (0, outImage); - - - } - - template< class TOutputScalarType > - void DwiPhantomGenerationFilter< TOutputScalarType > - ::GenerateTensors() - { - MITK_INFO << "Generating tensors"; - - for (int i=0; i kernel; - kernel.Fill(0); - float e1=ADC*(1+2*FA/sqrt(3-2*FA*FA)); - float e2=ADC*(1-FA/sqrt(3-2*FA*FA)); - float e3=e2; - kernel.SetElement(0,e1); - kernel.SetElement(3,e2); - kernel.SetElement(5,e3); - - if (m_SimulateBaseline) - { - double l2 = GetTensorL2Norm(kernel); - if (l2>m_MaxBaseline) - m_MaxBaseline = l2; - } - - MITK_INFO << "Kernel FA: " << kernel.GetFractionalAnisotropy(); - vnl_vector_fixed kernelDir; kernelDir[0]=1; kernelDir[1]=0; kernelDir[2]=0; - - itk::DiffusionTensor3D tensor; - vnl_vector_fixed dir = m_TensorDirection.at(i); - MITK_INFO << "Tensor direction: " << dir; - - dir.normalize(); - - vnl_vector_fixed axis = vnl_cross_3d(kernelDir, dir); axis.normalize(); - vnl_quaternion rotation(axis, acos(dot_product(kernelDir, dir))); - rotation.normalize(); - vnl_matrix_fixed matrix = rotation.rotation_matrix_transpose(); - - vnl_matrix_fixed tensorMatrix; - tensorMatrix[0][0] = kernel[0]; tensorMatrix[0][1] = kernel[1]; tensorMatrix[0][2] = kernel[2]; - tensorMatrix[1][0] = kernel[1]; tensorMatrix[1][1] = kernel[3]; tensorMatrix[1][2] = kernel[4]; - tensorMatrix[2][0] = kernel[2]; tensorMatrix[2][1] = kernel[4]; tensorMatrix[2][2] = kernel[5]; - - tensorMatrix = matrix.transpose()*tensorMatrix*matrix; - tensor[0] = tensorMatrix[0][0]; tensor[1] = tensorMatrix[0][1]; tensor[2] = tensorMatrix[0][2]; - tensor[3] = tensorMatrix[1][1]; tensor[4] = tensorMatrix[1][2]; tensor[5] = tensorMatrix[2][2]; - - m_TensorList.push_back(tensor); - } - } - - template< class TOutputScalarType > - void DwiPhantomGenerationFilter< TOutputScalarType >::AddNoise(typename OutputImageType::PixelType& pix) - { - for( unsigned int i=0; iGetNormalVariate(0.0, m_NoiseVariance), 2) + pow(m_SignalScale*m_RandGen->GetNormalVariate(0.0, m_NoiseVariance),2)); - pix[i] += val; - } - } - - template< class TOutputScalarType > - typename DwiPhantomGenerationFilter< TOutputScalarType >::OutputImageType::PixelType - DwiPhantomGenerationFilter< TOutputScalarType >::SimulateMeasurement(itk::DiffusionTensor3D& T, float weight) - { - typename OutputImageType::PixelType out; - out.SetSize(m_GradientList.size()); - out.Fill(0); - - TOutputScalarType s0 = m_DefaultBaseline; - if (m_SimulateBaseline) - s0 = (GetTensorL2Norm(T)/m_MaxBaseline)*m_SignalScale; - - for( unsigned int i=0; i0.0001) - { - itk::DiffusionTensor3D S; - S[0] = g[0]*g[0]; - S[1] = g[1]*g[0]; - S[2] = g[2]*g[0]; - S[3] = g[1]*g[1]; - S[4] = g[2]*g[1]; - S[5] = g[2]*g[2]; - - double D = T[0]*S[0] + T[1]*S[1] + T[2]*S[2] + - T[1]*S[1] + T[3]*S[3] + T[4]*S[4] + - T[2]*S[2] + T[4]*S[4] + T[5]*S[5]; - - // check for corrupted tensor and generate signal - if (D>=0) - { - D = weight*s0*exp ( -m_BValue * D ); - out[i] = static_cast( D ); - } - } - else - out[i] = s0; - } - - return out; - } - - template< class TOutputScalarType > - void DwiPhantomGenerationFilter< TOutputScalarType > - ::GenerateData() - { - if (m_NoiseVariance < 0 && m_AddNoiseFlag) - { - m_NoiseVariance = 0.001; - } - - if (!m_SimulateBaseline) - { - MITK_INFO << "Baseline image values are set to default. Noise variance value is treated as SNR!"; - if (m_NoiseVariance <= 0 && m_AddNoiseFlag) - { - m_NoiseVariance = 0.0001; - } - else if (m_NoiseVariance>99 && m_AddNoiseFlag) - { - m_NoiseVariance = 0; - } - else - { - m_NoiseVariance = m_DefaultBaseline/(m_NoiseVariance*m_SignalScale); - m_NoiseVariance *= m_NoiseVariance; - } - } - - m_RandGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); - m_RandGen->SetSeed(); - - typename OutputImageType::Pointer outImage = OutputImageType::New(); - outImage->SetSpacing( m_Spacing ); - outImage->SetOrigin( m_Origin ); - outImage->SetDirection( m_DirectionMatrix ); - outImage->SetLargestPossibleRegion( m_ImageRegion ); - outImage->SetBufferedRegion( m_ImageRegion ); - outImage->SetRequestedRegion( m_ImageRegion ); - outImage->SetVectorLength(m_GradientList.size()); - outImage->Allocate(); - typename OutputImageType::PixelType pix; - pix.SetSize(m_GradientList.size()); - pix.Fill(0.0); - outImage->FillBuffer(pix); - this->SetNthOutput (0, outImage); - - double minSpacing = m_Spacing[0]; - if (m_Spacing[1] nullVec; nullVec.Fill(0.0); - ItkDirectionImage::Pointer img = ItkDirectionImage::New(); - img->SetSpacing( m_Spacing ); - img->SetOrigin( m_Origin ); - img->SetDirection( m_DirectionMatrix ); - img->SetRegions( m_ImageRegion ); - img->Allocate(); - img->FillBuffer(nullVec); - m_DirectionImageContainer->InsertElement(m_DirectionImageContainer->Size(), img); - } - m_NumDirectionsImage = ItkUcharImgType::New(); - m_NumDirectionsImage->SetSpacing( m_Spacing ); - m_NumDirectionsImage->SetOrigin( m_Origin ); - m_NumDirectionsImage->SetDirection( m_DirectionMatrix ); - m_NumDirectionsImage->SetRegions( m_ImageRegion ); - m_NumDirectionsImage->Allocate(); - m_NumDirectionsImage->FillBuffer(0); - - m_SNRImage = ItkFloatImgType::New(); - m_SNRImage->SetSpacing( m_Spacing ); - m_SNRImage->SetOrigin( m_Origin ); - m_SNRImage->SetDirection( m_DirectionMatrix ); - m_SNRImage->SetRegions( m_ImageRegion ); - m_SNRImage->Allocate(); - m_SNRImage->FillBuffer(0); - - vtkSmartPointer m_VtkCellArray = vtkSmartPointer::New(); - vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); - - m_BaselineImages = 0; - for( unsigned int i=0; i IteratorOutputType; - IteratorOutputType it (outImage, m_ImageRegion); - - // isotropic tensor - itk::DiffusionTensor3D isoTensor; - isoTensor.Fill(0); - float e1 = m_GreyMatterAdc; - float e2 = m_GreyMatterAdc; - float e3 = m_GreyMatterAdc; - isoTensor.SetElement(0,e1); - isoTensor.SetElement(3,e2); - isoTensor.SetElement(5,e3); - m_MaxBaseline = GetTensorL2Norm(isoTensor); - - GenerateTensors(); - - // simulate measurement - m_MeanBaseline = 0; - double noiseStdev = sqrt(m_NoiseVariance); - while(!it.IsAtEnd()) - { - pix = it.Get(); - typename OutputImageType::IndexType index = it.GetIndex(); - - int numDirs = 0; - for (int i=0; iGetPixel(index)!=0) - { - numDirs++; - pix += SimulateMeasurement(m_TensorList[i], m_TensorWeight[i]); - - // set direction image pixel - ItkDirectionImage::Pointer img = m_DirectionImageContainer->GetElement(i); - itk::Vector< float, 3 > pixel = img->GetPixel(index); - vnl_vector_fixed dir = m_TensorDirection.at(i); - dir.normalize(); - dir *= m_TensorWeight.at(i); - pixel.SetElement(0, dir[0]); - pixel.SetElement(1, dir[1]); - pixel.SetElement(2, dir[2]); - img->SetPixel(index, pixel); - - vtkSmartPointer container = vtkSmartPointer::New(); - itk::ContinuousIndex center; - center[0] = index[0]; - center[1] = index[1]; - center[2] = index[2]; - itk::Point worldCenter; - outImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); - itk::Point worldStart; - worldStart[0] = worldCenter[0]-dir[0]/2 * minSpacing; - worldStart[1] = worldCenter[1]-dir[1]/2 * minSpacing; - worldStart[2] = worldCenter[2]-dir[2]/2 * minSpacing; - vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); - container->GetPointIds()->InsertNextId(id); - itk::Point worldEnd; - worldEnd[0] = worldCenter[0]+dir[0]/2 * minSpacing; - worldEnd[1] = worldCenter[1]+dir[1]/2 * minSpacing; - worldEnd[2] = worldCenter[2]+dir[2]/2 * minSpacing; - id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); - container->GetPointIds()->InsertNextId(id); - m_VtkCellArray->InsertNextCell(container); - } - } - - if (numDirs>1) - { - for (int i=0; iSetPixel(index, numDirs); - if (m_NoiseVariance>0 && m_AddNoiseFlag) - { - m_SNRImage->SetPixel(index, pix[0]/(noiseStdev*m_SignalScale)); - } - ++it; - } - m_MeanBaseline /= m_ImageRegion.GetNumberOfPixels(); - if (m_NoiseVariance>0 && m_AddNoiseFlag) - { - MITK_INFO << "Mean SNR: " << m_MeanBaseline/(noiseStdev*m_SignalScale); - } - else - { - MITK_INFO << "No noise added"; - } - - // add rician noise - it.GoToBegin(); - while(!it.IsAtEnd()) - { - pix = it.Get(); - AddNoise(pix); - it.Set(pix); - ++it; - } - - // generate fiber bundle - vtkSmartPointer directionsPolyData = vtkSmartPointer::New(); - directionsPolyData->SetPoints(m_VtkPoints); - directionsPolyData->SetLines(m_VtkCellArray); - m_OutputFiberBundle = mitk::FiberBundle::New(directionsPolyData); - } - template< class TOutputScalarType > - double DwiPhantomGenerationFilter< TOutputScalarType >::GetTensorL2Norm(itk::DiffusionTensor3D& T) - { - return sqrt(T[0]*T[0] + T[3]*T[3] + T[5]*T[5] + T[1]*T[2]*2.0 + T[2]*T[4]*2.0 + T[1]*T[4]*2.0); - } - -} - -#endif // __itkDwiPhantomGenerationFilter_cpp diff --git a/Modules/DiffusionImaging/DiffusionCore/src/IODataStructures/mitkPeakImage.cpp b/Modules/DiffusionImaging/DiffusionCore/src/IODataStructures/mitkPeakImage.cpp new file mode 100644 index 0000000000..ce9d1938ee --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionCore/src/IODataStructures/mitkPeakImage.cpp @@ -0,0 +1,221 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkPeakImage.h" +#include "mitkImageDataItem.h" +#include "mitkImageCast.h" +#include +#include +#include +#include +#include + +mitk::PeakImage::PeakImage() : Image() +{ + m_PolyData = nullptr; +} + +mitk::PeakImage::~PeakImage() +{ + +} + +void mitk::PeakImage::ConstructPolydata() +{ + MITK_INFO << "PeakImage constructing polydata"; + if (this->GetDimensions()[3]%3!=0) + mitkThrow() << "Fourth dimension needs to be a multiple of 3"; + + typedef mitk::ImageToItk< ItkPeakImageType > CasterType; + CasterType::Pointer caster = CasterType::New(); + caster->SetInput(this); + caster->Update(); + ItkPeakImageType::ConstPointer itkImg = caster->GetOutput(); + + int sz_x = this->GetDimensions()[0]; + int sz_y = this->GetDimensions()[1]; + int sz_z = this->GetDimensions()[2]; + unsigned int num_dirs = this->GetDimensions()[3]/3; + + double minSpacing = 1; + ItkPeakImageType::SpacingType spacing = itkImg->GetSpacing(); + if(spacing[0] m_VtkCellArray = vtkSmartPointer::New(); + vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); + +#ifdef WIN32 +#pragma omp parallel for +#else +#pragma omp parallel for collapse(3) +#endif + for (int x=0; x idx4; idx4[0] = x; idx4[1] = y; idx4[2] = z; + + for (unsigned int i=0; i center; + center[0] = idx4[0]; + center[1] = idx4[1]; + center[2] = idx4[2]; + center[3] = 0; + + itk::Point worldCenter; + itkImg->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); + + idx4[3] = 0; + vnl_vector_fixed< float, 3 > dir; + idx4[3] = i*3; + dir[0] = itkImg->GetPixel(idx4); + idx4[3] += 1; + dir[1] = itkImg->GetPixel(idx4); + idx4[3] += 1; + dir[2] = itkImg->GetPixel(idx4); + + if (dir.magnitude()<0.001) + continue; + +#pragma omp critical + { + vtkSmartPointer container = vtkSmartPointer::New(); + // add direction to vector field (with spacing compensation) + itk::Point worldStart; + worldStart[0] = worldCenter[0]-dir[0]/2*minSpacing; + worldStart[1] = worldCenter[1]-dir[1]/2*minSpacing; + worldStart[2] = worldCenter[2]-dir[2]/2*minSpacing; + vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); + container->GetPointIds()->InsertNextId(id); + itk::Point worldEnd; + worldEnd[0] = worldCenter[0]+dir[0]/2*minSpacing; + worldEnd[1] = worldCenter[1]+dir[1]/2*minSpacing; + worldEnd[2] = worldCenter[2]+dir[2]/2*minSpacing; + id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); + container->GetPointIds()->InsertNextId(id); + m_VtkCellArray->InsertNextCell(container); + } + } + } + + m_PolyData = vtkSmartPointer::New(); + m_PolyData->SetPoints(m_VtkPoints); + m_PolyData->SetLines(m_VtkCellArray); + MITK_INFO << "PeakImage finished constructing polydata"; + + ColorByOrientation(); + + this->Modified(); +} + +void mitk::PeakImage::SetCustomColor(float r, float g, float b) +{ + vtkPoints* extrPoints = nullptr; + extrPoints = m_PolyData->GetPoints(); + int numOfPoints = 0; + if (extrPoints!=nullptr) + numOfPoints = extrPoints->GetNumberOfPoints(); + + int componentSize = 4; + + vtkSmartPointer colors = vtkSmartPointer::New(); + colors->Allocate(numOfPoints * componentSize); + colors->SetNumberOfComponents(componentSize); + colors->SetName("FIBER_COLORS"); + + unsigned char rgba[4] = {0,0,0,0}; + for(long i=0; iGetNumberOfPoints(); ++i) + { + rgba[0] = (unsigned char) r; + rgba[1] = (unsigned char) g; + rgba[2] = (unsigned char) b; + rgba[3] = (unsigned char) 255; + colors->InsertTypedTuple(i, rgba); + } + + m_PolyData->GetPointData()->AddArray(colors); + this->Modified(); +} + +void mitk::PeakImage::ColorByOrientation() +{ + //===== FOR WRITING A TEST ======================== + // colorT size == tupelComponents * tupelElements + // compare color results + // to cover this code 100% also PolyData needed, where colorarray already exists + // + one fiber with exactly 1 point + // + one fiber with 0 points + //================================================= + + vtkPoints* extrPoints = nullptr; + extrPoints = m_PolyData->GetPoints(); + int numOfPoints = 0; + if (extrPoints!=nullptr) + numOfPoints = extrPoints->GetNumberOfPoints(); + + //colors and alpha value for each single point, RGBA = 4 components + unsigned char rgba[4] = {0,0,0,0}; + int componentSize = 4; + + vtkSmartPointer colors = vtkSmartPointer::New(); + colors->Allocate(numOfPoints * componentSize); + colors->SetNumberOfComponents(componentSize); + colors->SetName("FIBER_COLORS"); + + int num_peaks = m_PolyData->GetNumberOfLines(); + if (num_peaks < 1) + return; + + vtkCellArray* fiberList = m_PolyData->GetLines(); + fiberList->InitTraversal(); + for (int fi=0; fiGetNextCell(num_points, idList); + + if (num_points == 2) + { + vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[0])[0], extrPoints->GetPoint(idList[0])[1],extrPoints->GetPoint(idList[0])[2]); + vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[1])[0], extrPoints->GetPoint(idList[1])[1], extrPoints->GetPoint(idList[1])[2]); + + vnl_vector_fixed< double, 3 > diff1; + diff1 = currentPntvtk - nextPntvtk; + diff1.normalize(); + + rgba[0] = (unsigned char) (255.0 * std::fabs(diff1[0])); + rgba[1] = (unsigned char) (255.0 * std::fabs(diff1[1])); + rgba[2] = (unsigned char) (255.0 * std::fabs(diff1[2])); + rgba[3] = (unsigned char) (255.0); + colors->InsertTypedTuple(idList[0], rgba); + colors->InsertTypedTuple(idList[1], rgba); + } + else + { + MITK_INFO << "Peak with point number!=2 detected!" ; + continue; + } + } + + m_PolyData->GetPointData()->AddArray(colors); + this->Modified(); +} diff --git a/Modules/DiffusionImaging/DiffusionIO/files.cmake b/Modules/DiffusionImaging/DiffusionIO/files.cmake index 419593c7e3..ccf7e79422 100644 --- a/Modules/DiffusionImaging/DiffusionIO/files.cmake +++ b/Modules/DiffusionImaging/DiffusionIO/files.cmake @@ -1,40 +1,41 @@ set(CPP_FILES mitkDiffusionModuleActivator.cpp mitkNrrdTbssImageWriterFactory.cpp #mitkFiberBundleIOFactory.cpp mitkConnectomicsNetworkReader.cpp mitkConnectomicsNetworkWriter.cpp mitkConnectomicsNetworkCSVWriter.cpp mitkConnectomicsNetworkMatrixWriter.cpp mitkConnectomicsNetworkSerializer.cpp mitkConnectomicsNetworkDefinitions.cpp mitkNrrdTbssRoiImageIOFactory.cpp #mitkFiberBundleWriterFactory.cpp mitkNrrdTbssRoiImageWriterFactory.cpp mitkFiberTrackingObjectFactory.cpp mitkConnectomicsObjectFactory.cpp mitkQuantificationObjectFactory.cpp mitkNrrdTbssImageIOFactory.cpp mitkDiffusionIOMimeTypes.cpp mitkFiberBundleDicomReader.cpp mitkFiberBundleDicomWriter.cpp mitkFiberBundleTckReader.cpp mitkFiberBundleTrackVisReader.cpp mitkFiberBundleTrackVisWriter.cpp mitkFiberBundleVtkReader.cpp mitkFiberBundleVtkWriter.cpp mitkFiberBundleSerializer.cpp mitkFiberBundleMapper2D.cpp mitkFiberBundleMapper3D.cpp + mitkPeakImageMapper2D.cpp mitkTractographyForestReader.cpp mitkTractographyForestWriter.cpp mitkTractographyForestSerializer.cpp mitkPlanarFigureCompositeWriter.cpp mitkPlanarFigureCompositeReader.cpp mitkPlanarFigureCompositeSerializer.cpp ) diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkDiffusionIOMimeTypes.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkDiffusionIOMimeTypes.cpp index d23a1a97b4..bdfe381bad 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkDiffusionIOMimeTypes.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkDiffusionIOMimeTypes.cpp @@ -1,250 +1,278 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDiffusionIOMimeTypes.h" #include "mitkIOMimeTypes.h" #include #include #include #include #include - -#include "dcmtk/dcmtract/trctractographyresults.h" +#include +#include +#include namespace mitk { std::vector DiffusionIOMimeTypes::Get() { std::vector mimeTypes; // order matters here (descending rank for mime types) mimeTypes.push_back(FIBERBUNDLE_VTK_MIMETYPE().Clone()); mimeTypes.push_back(FIBERBUNDLE_TRK_MIMETYPE().Clone()); mimeTypes.push_back(FIBERBUNDLE_TCK_MIMETYPE().Clone()); mimeTypes.push_back(FIBERBUNDLE_DICOM_MIMETYPE().Clone()); mimeTypes.push_back(CONNECTOMICS_MIMETYPE().Clone()); mimeTypes.push_back(TRACTOGRAPHYFOREST_MIMETYPE().Clone()); mimeTypes.push_back(PLANARFIGURECOMPOSITE_MIMETYPE().Clone()); return mimeTypes; } // Mime Types CustomMimeType DiffusionIOMimeTypes::PLANARFIGURECOMPOSITE_MIMETYPE() { CustomMimeType mimeType(PLANARFIGURECOMPOSITE_MIMETYPE_NAME()); std::string category = "Planar Figure Composite"; mimeType.SetComment("Planar Figure Composite"); mimeType.SetCategory(category); mimeType.AddExtension("pfc"); return mimeType; } CustomMimeType DiffusionIOMimeTypes::TRACTOGRAPHYFOREST_MIMETYPE() { CustomMimeType mimeType(TRACTOGRAPHYFOREST_MIMETYPE_NAME()); std::string category = "Tractography Forest"; mimeType.SetComment("Tractography Forest"); mimeType.SetCategory(category); mimeType.AddExtension("rf"); return mimeType; } CustomMimeType DiffusionIOMimeTypes::FIBERBUNDLE_VTK_MIMETYPE() { CustomMimeType mimeType(FIBERBUNDLE_VTK_MIMETYPE_NAME()); std::string category = "VTK Fibers"; mimeType.SetComment("VTK Fibers"); mimeType.SetCategory(category); mimeType.AddExtension("fib"); mimeType.AddExtension("vtk"); return mimeType; } CustomMimeType DiffusionIOMimeTypes::FIBERBUNDLE_TCK_MIMETYPE() { CustomMimeType mimeType(FIBERBUNDLE_TCK_MIMETYPE_NAME()); std::string category = "MRtrix Fibers"; mimeType.SetComment("MRtrix Fibers"); mimeType.SetCategory(category); mimeType.AddExtension("tck"); return mimeType; } CustomMimeType DiffusionIOMimeTypes::FIBERBUNDLE_TRK_MIMETYPE() { CustomMimeType mimeType(FIBERBUNDLE_TRK_MIMETYPE_NAME()); std::string category = "TrackVis Fibers"; mimeType.SetComment("TrackVis Fibers"); mimeType.SetCategory(category); mimeType.AddExtension("trk"); return mimeType; } DiffusionIOMimeTypes::FiberBundleDicomMimeType::FiberBundleDicomMimeType() : CustomMimeType(FIBERBUNDLE_DICOM_MIMETYPE_NAME()) { std::string category = "DICOM Fibers"; this->SetCategory(category); this->SetComment("DICOM Fibers"); this->AddExtension("dcm"); this->AddExtension("DCM"); this->AddExtension("gdcm"); this->AddExtension("dc3"); this->AddExtension("DC3"); this->AddExtension("ima"); this->AddExtension("img"); } bool DiffusionIOMimeTypes::FiberBundleDicomMimeType::AppliesTo(const std::string &path) const { - OFCondition result; - TrcTractographyResults *trc = NULL; - result = TrcTractographyResults::loadFile(path.c_str(), trc); - if (result.bad()) - return false; - - return true; + try + { + mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New(); + mitk::DICOMTag SOPInstanceUID(0x0008, 0x0016); + + mitk::StringList relevantFiles; + relevantFiles.push_back(path); + + scanner->AddTag(SOPInstanceUID); + scanner->SetInputFiles(relevantFiles); + scanner->Scan(); + mitk::DICOMTagCache::Pointer tagCache = scanner->GetScanCache(); + + mitk::DICOMImageFrameList imageFrameList = mitk::ConvertToDICOMImageFrameList(tagCache->GetFrameInfoList()); + if (imageFrameList.empty()) + return false; + + mitk::DICOMImageFrameInfo *firstFrame = imageFrameList.begin()->GetPointer(); + + std::string tag_value = tagCache->GetTagValue(firstFrame, SOPInstanceUID).value; + if (tag_value.empty()) { + return false; + } + + if (tag_value.compare(UID_TractographyResultsStorage)!=0) + return false; + + return true; + } + catch (std::exception& e) + { + MITK_INFO << e.what(); + } + return false; } DiffusionIOMimeTypes::FiberBundleDicomMimeType* DiffusionIOMimeTypes::FiberBundleDicomMimeType::Clone() const { return new FiberBundleDicomMimeType(*this); } DiffusionIOMimeTypes::FiberBundleDicomMimeType DiffusionIOMimeTypes::FIBERBUNDLE_DICOM_MIMETYPE() { return FiberBundleDicomMimeType(); } CustomMimeType DiffusionIOMimeTypes::CONNECTOMICS_MIMETYPE() { CustomMimeType mimeType(CONNECTOMICS_MIMETYPE_NAME()); std::string category = "Connectomics Networks"; mimeType.SetComment("Connectomics Networks Files"); mimeType.SetCategory(category); mimeType.AddExtension("cnf"); return mimeType; } CustomMimeType DiffusionIOMimeTypes::CONNECTOMICS_MATRIX_MIMETYPE() { CustomMimeType mimeType(CONNECTOMICS_MATRIX_MIMETYPE_NAME()); std::string category = "Connectomics Networks export"; mimeType.SetComment("Connectomics Matrix Files"); mimeType.SetCategory(category); mimeType.AddExtension("mat"); return mimeType; } CustomMimeType DiffusionIOMimeTypes::CONNECTOMICS_LIST_MIMETYPE() { CustomMimeType mimeType(CONNECTOMICS_LIST_MIMETYPE_NAME()); std::string category = "Connectomics Networks export"; mimeType.SetComment("Connectomics Connection Lists"); mimeType.SetCategory(category); mimeType.AddExtension("txt"); return mimeType; } // Names std::string DiffusionIOMimeTypes::FIBERBUNDLE_VTK_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".FiberBundle.vtk"; return name; } std::string DiffusionIOMimeTypes::FIBERBUNDLE_TCK_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".FiberBundle.tck"; return name; } std::string DiffusionIOMimeTypes::FIBERBUNDLE_TRK_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".FiberBundle.trk"; return name; } std::string DiffusionIOMimeTypes::FIBERBUNDLE_DICOM_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".FiberBundle.dcm"; return name; } std::string DiffusionIOMimeTypes::CONNECTOMICS_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".cnf"; return name; } std::string DiffusionIOMimeTypes::CONNECTOMICS_MATRIX_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".mat"; return name; } std::string DiffusionIOMimeTypes::CONNECTOMICS_LIST_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".txt"; return name; } std::string DiffusionIOMimeTypes::PLANARFIGURECOMPOSITE_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".pfc"; return name; } std::string DiffusionIOMimeTypes::TRACTOGRAPHYFOREST_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".rf"; return name; } // Descriptions std::string DiffusionIOMimeTypes::FIBERBUNDLE_MIMETYPE_DESCRIPTION() { static std::string description = "Fiberbundles"; return description; } std::string DiffusionIOMimeTypes::CONNECTOMICS_MIMETYPE_DESCRIPTION() { static std::string description = "Connectomics Networks"; return description; } std::string DiffusionIOMimeTypes::PLANARFIGURECOMPOSITE_MIMETYPE_DESCRIPTION() { static std::string description = "Planar Figure Composite"; return description; } std::string DiffusionIOMimeTypes::TRACTOGRAPHYFOREST_MIMETYPE_DESCRIPTION() { static std::string description = "Tractography Forest"; return description; } } diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.cpp index e29a9e7d54..093d65304a 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.cpp @@ -1,114 +1,123 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkFiberTrackingObjectFactory.h" mitk::FiberTrackingObjectFactory::FiberTrackingObjectFactory() : CoreObjectFactoryBase() { } mitk::FiberTrackingObjectFactory::~FiberTrackingObjectFactory() { } mitk::Mapper::Pointer mitk::FiberTrackingObjectFactory::CreateMapper(mitk::DataNode* node, MapperSlotId id) { mitk::Mapper::Pointer newMapper=nullptr; if ( id == mitk::BaseRenderer::Standard2D ) { std::string classname("FiberBundle"); if(node->GetData() && classname.compare(node->GetData()->GetNameOfClass())==0) { newMapper = mitk::FiberBundleMapper2D::New(); newMapper->SetDataNode(node); } + else if(node->GetData() && std::string("PeakImage").compare(node->GetData()->GetNameOfClass())==0) + { + newMapper = mitk::PeakImageMapper2D::New(); + newMapper->SetDataNode(node); + } } else if ( id == mitk::BaseRenderer::Standard3D ) { std::string classname("FiberBundle"); if(node->GetData() && classname.compare(node->GetData()->GetNameOfClass())==0) { newMapper = mitk::FiberBundleMapper3D::New(); newMapper->SetDataNode(node); } } return newMapper; } void mitk::FiberTrackingObjectFactory::SetDefaultProperties(mitk::DataNode* node) { std::string classname("FiberBundle"); if(node->GetData() && classname.compare(node->GetData()->GetNameOfClass())==0) { mitk::FiberBundleMapper3D::SetDefaultProperties(node); mitk::FiberBundleMapper2D::SetDefaultProperties(node); } + else if (node->GetData() && std::string("PeakImage").compare(node->GetData()->GetNameOfClass())==0) + { + mitk::PeakImageMapper2D::SetDefaultProperties(node); + } } const char* mitk::FiberTrackingObjectFactory::GetFileExtensions() { std::string fileExtension; this->CreateFileExtensions(m_FileExtensionsMap, fileExtension); return fileExtension.c_str(); } mitk::CoreObjectFactoryBase::MultimapType mitk::FiberTrackingObjectFactory::GetFileExtensionsMap() { return m_FileExtensionsMap; } const char* mitk::FiberTrackingObjectFactory::GetSaveFileExtensions() { std::string fileExtension; this->CreateFileExtensions(m_SaveFileExtensionsMap, fileExtension); return fileExtension.c_str(); } mitk::CoreObjectFactoryBase::MultimapType mitk::FiberTrackingObjectFactory::GetSaveFileExtensionsMap() { return m_SaveFileExtensionsMap; } void mitk::FiberTrackingObjectFactory::CreateFileExtensionsMap() { } void mitk::FiberTrackingObjectFactory::RegisterIOFactories() { } struct RegisterFiberTrackingObjectFactory{ RegisterFiberTrackingObjectFactory() : m_Factory( mitk::FiberTrackingObjectFactory::New() ) { mitk::CoreObjectFactory::GetInstance()->RegisterExtraFactory( m_Factory ); } ~RegisterFiberTrackingObjectFactory() { mitk::CoreObjectFactory::GetInstance()->UnRegisterExtraFactory( m_Factory ); } mitk::FiberTrackingObjectFactory::Pointer m_Factory; }; static RegisterFiberTrackingObjectFactory registerFiberTrackingObjectFactory; diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.h b/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.h index 3fb7527295..cee2f7d300 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.h +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberTrackingObjectFactory.h @@ -1,70 +1,71 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKFIBERTRACKINGOBJECTFACTORY_H #define MITKFIBERTRACKINGOBJECTFACTORY_H #include "mitkCoreObjectFactory.h" //modernized fiberbundle datastrucutre #include "mitkFiberBundle.h" #include "mitkFiberBundleMapper3D.h" #include "mitkFiberBundleMapper2D.h" +#include //#include "mitkFiberBundleThreadMonitorMapper3D.h" //#include "mitkFiberBundleThreadMonitor.h" namespace mitk { class FiberTrackingObjectFactory : public CoreObjectFactoryBase { public: mitkClassMacro(FiberTrackingObjectFactory,CoreObjectFactoryBase) itkFactorylessNewMacro(Self) itkCloneMacro(Self) ~FiberTrackingObjectFactory(); virtual Mapper::Pointer CreateMapper(mitk::DataNode* node, MapperSlotId slotId) override; virtual void SetDefaultProperties(mitk::DataNode* node) override; virtual const char* GetFileExtensions() override; virtual mitk::CoreObjectFactoryBase::MultimapType GetFileExtensionsMap() override; virtual const char* GetSaveFileExtensions() override; virtual mitk::CoreObjectFactoryBase::MultimapType GetSaveFileExtensionsMap() override; void RegisterIOFactories(); protected: FiberTrackingObjectFactory(); private: void CreateFileExtensionsMap(); std::string m_ExternalFileExtensions; std::string m_InternalFileExtensions; std::string m_SaveFileExtensions; MultimapType m_FileExtensionsMap; MultimapType m_SaveFileExtensionsMap; }; } #endif // MITKFIBERTRACKINGOBJECTFACTORY_H diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.cpp new file mode 100644 index 0000000000..d8209d1276 --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.cpp @@ -0,0 +1,239 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkPeakImageMapper2D.h" +#include "mitkBaseRenderer.h" +#include "mitkDataNode.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class vtkPeakShaderCallback : public vtkCommand +{ +public: + static vtkPeakShaderCallback *New() + { + return new vtkPeakShaderCallback; + } + mitk::BaseRenderer *renderer; + mitk::DataNode *node; + + virtual void Execute(vtkObject *, unsigned long, void*cbo) + { + vtkOpenGLHelper *cellBO = reinterpret_cast(cbo); + + + mitk::Image* image = dynamic_cast(node->GetData()); + mitk::Vector3D spacing = image->GetGeometry()->GetSpacing(); + + float minSpacing = 1; + if(spacing[0]GetOpacity(peakOpacity, nullptr); + + cellBO->Program->SetUniformf("peakOpacity", peakOpacity); + cellBO->Program->SetUniformf("clippingPlaneThickness", minSpacing/2); + + if (this->renderer) + { + //get information about current position of views + mitk::SliceNavigationController::Pointer sliceContr = renderer->GetSliceNavigationController(); + mitk::PlaneGeometry::ConstPointer planeGeo = sliceContr->GetCurrentPlaneGeometry(); + + //generate according cutting planes based on the view position + float planeNormal[3]; + planeNormal[0] = planeGeo->GetNormal()[0]; + planeNormal[1] = planeGeo->GetNormal()[1]; + planeNormal[2] = planeGeo->GetNormal()[2]; + + float tmp1 = planeGeo->GetOrigin()[0] * planeNormal[0]; + float tmp2 = planeGeo->GetOrigin()[1] * planeNormal[1]; + float tmp3 = planeGeo->GetOrigin()[2] * planeNormal[2]; + float thickness = tmp1 + tmp2 + tmp3; //attention, correct normalvector + + float* a = new float[4]; + for (int i = 0; i < 3; ++i) + a[i] = planeNormal[i]; + + a[3] = thickness; + cellBO->Program->SetUniform4f("slicingPlane", a); + } + } + + vtkPeakShaderCallback() { this->renderer = 0; } +}; + + + +mitk::PeakImageMapper2D::PeakImageMapper2D() +{ + m_lut = vtkLookupTable::New(); + m_lut->Build(); +} + +mitk::PeakImageMapper2D::~PeakImageMapper2D() +{ +} + + +mitk::PeakImage* mitk::PeakImageMapper2D::GetInput() +{ + return dynamic_cast< mitk::PeakImage * > ( GetDataNode()->GetData() ); +} + +void mitk::PeakImageMapper2D::UpdateVtkTransform(mitk::BaseRenderer *) +{ + // don't apply transform since the peak polydata is already in world coordinates. + return; +} + +void mitk::PeakImageMapper2D::Update(mitk::BaseRenderer * renderer) +{ + mitk::DataNode* node = this->GetDataNode(); + if (node == nullptr) + return; + + bool visible = true; + node->GetVisibility(visible, renderer, "visible"); + if ( !visible ) + return; + + this->GenerateDataForRenderer( renderer ); +} + +void mitk::PeakImageMapper2D::UpdateShaderParameter(mitk::BaseRenderer *) +{ + // see new vtkPeakShaderCallback +} + +// vtkActors and Mappers are feeded here +void mitk::PeakImageMapper2D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) +{ + mitk::PeakImage* peakImage = this->GetInput(); + + //the handler of local storage gets feeded in this method with requested data for related renderwindow + FBXLocalStorage *localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); + + vtkSmartPointer polyData = peakImage->GetPolyData(); + if (polyData == nullptr) + return; + + localStorage->m_Mapper->ScalarVisibilityOn(); + localStorage->m_Mapper->SetScalarModeToUsePointFieldData(); + localStorage->m_Mapper->SetLookupTable(m_lut); //apply the properties after the slice was set +// localStorage->m_PointActor->GetProperty()->SetOpacity(0.999); + localStorage->m_Mapper->SelectColorArray("FIBER_COLORS"); + + localStorage->m_Mapper->SetInputData(polyData); + localStorage->m_Mapper->SetVertexShaderCode( + "//VTK::System::Dec\n" + "attribute vec4 vertexMC;\n" + + "//VTK::Normal::Dec\n" + "uniform mat4 MCDCMatrix;\n" + + "//VTK::Color::Dec\n" + + "varying vec4 positionWorld;\n" + "varying vec4 colorVertex;\n" + + "void main(void)\n" + "{\n" + " colorVertex = scalarColor;\n" + " positionWorld = vertexMC;\n" + " gl_Position = MCDCMatrix * vertexMC;\n" + "}\n" + ); + localStorage->m_Mapper->SetFragmentShaderCode( + "//VTK::System::Dec\n" // always start with this line + "//VTK::Output::Dec\n" // always have this line in your FS + "uniform vec4 slicingPlane;\n" + "uniform float clippingPlaneThickness;\n" + "uniform float peakOpacity;\n" + "varying vec4 positionWorld;\n" + "varying vec4 colorVertex;\n" + + "void main(void)\n" + "{\n" + " float r1 = dot(positionWorld.xyz, slicingPlane.xyz) - slicingPlane.w;\n" + + " if (abs(r1) >= clippingPlaneThickness)\n" + " discard;\n" + " gl_FragColor = vec4(colorVertex.xyz,peakOpacity);\n" + "}\n" + ); + + vtkSmartPointer myCallback = vtkSmartPointer::New(); + myCallback->renderer = renderer; + myCallback->node = this->GetDataNode(); + localStorage->m_Mapper->AddObserver(vtkCommand::UpdateShaderEvent,myCallback); + + localStorage->m_PointActor->SetMapper(localStorage->m_Mapper); + localStorage->m_PointActor->GetProperty()->ShadingOn(); + + float linewidth = 1.0; + this->GetDataNode()->GetFloatProperty("shape.linewidth",linewidth); + localStorage->m_PointActor->GetProperty()->SetLineWidth(linewidth); + + // We have been modified => save this for next Update() + localStorage->m_LastUpdateTime.Modified(); +} + + +vtkProp* mitk::PeakImageMapper2D::GetVtkProp(mitk::BaseRenderer *renderer) +{ + this->Update(renderer); + return m_LocalStorageHandler.GetLocalStorage(renderer)->m_PointActor; +} + + +void mitk::PeakImageMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) +{ + Superclass::SetDefaultProperties(node, renderer, overwrite); + + //add other parameters to propertylist + node->AddProperty( "color", mitk::ColorProperty::New(1.0,1.0,1.0), renderer, overwrite); + node->AddProperty( "shape.linewidth", mitk::FloatProperty::New(1.0), renderer, overwrite); +} + + +mitk::PeakImageMapper2D::FBXLocalStorage::FBXLocalStorage() +{ + m_PointActor = vtkSmartPointer::New(); + m_Mapper = vtkSmartPointer::New(); +} diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.h b/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.h new file mode 100644 index 0000000000..3153d7c22c --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionIO/mitkPeakImageMapper2D.h @@ -0,0 +1,106 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef PeakImageMapper2D_H_HEADER_INCLUDED +#define PeakImageMapper2D_H_HEADER_INCLUDED + +//MITK Rendering +#include +#include +#include +#include +#include + +#define MITKPeakImageMapper2D_POLYDATAMAPPER vtkOpenGLPolyDataMapper + +class vtkActor; +class mitkBaseRenderer; +class MITKPeakImageMapper2D_POLYDATAMAPPER; +class vtkCutter; +class vtkPlane; +class vtkPolyData; + + + +namespace mitk { + +struct IShaderRepository; + +class PeakImageMapper2D : public VtkMapper +{ + +public: + mitkClassMacro(PeakImageMapper2D, VtkMapper) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + mitk::PeakImage* GetInput(); + + + /** \brief Checks whether this mapper needs to update itself and generate data. */ + virtual void Update(mitk::BaseRenderer * renderer) override; + + + static void SetDefaultProperties(DataNode* node, BaseRenderer* renderer = nullptr, bool overwrite = false ); + + virtual void UpdateVtkTransform(mitk::BaseRenderer *renderer) override; + + //### methods of MITK-VTK rendering pipeline + virtual vtkProp* GetVtkProp(mitk::BaseRenderer* renderer) override; + //### end of methods of MITK-VTK rendering pipeline + + + class FBXLocalStorage : public mitk::Mapper::BaseLocalStorage + { + public: + /** \brief Point Actor of a 2D render window. */ + vtkSmartPointer m_PointActor; + /** \brief Point Mapper of a 2D render window. */ + vtkSmartPointer m_Mapper; + vtkSmartPointer m_SlicingPlane; //needed later when optimized 2D mapper + vtkSmartPointer m_SlicedResult; //might be depricated in optimized 2D mapper + + /** \brief Timestamp of last update of stored data. */ + itk::TimeStamp m_LastUpdateTime; + /** \brief Constructor of the local storage. Do as much actions as possible in here to avoid double executions. */ + FBXLocalStorage(); //if u copy&paste from this 2Dmapper, be aware that the implementation of this constructor is in the cpp file + + ~FBXLocalStorage() + { + } + }; + + /** \brief This member holds all three LocalStorages for the three 2D render windows. */ + mitk::LocalStorageHandler m_LocalStorageHandler; + + + +protected: + PeakImageMapper2D(); + virtual ~PeakImageMapper2D(); + + /** Does the actual resampling, without rendering. */ + virtual void GenerateDataForRenderer(mitk::BaseRenderer*) override; + + void UpdateShaderParameter(mitk::BaseRenderer*); + +private: + vtkSmartPointer m_lut; +}; + + +}//end namespace + +#endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp index ab570096a5..962cb70c17 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.cpp @@ -1,414 +1,412 @@ #include "itkTractsToVectorImageFilter.h" // VTK #include #include #include // ITK #include #include // misc #define _USE_MATH_DEFINES #include #include namespace itk{ static inline bool CompareVectorLengths(const vnl_vector_fixed< double, 3 >& v1, const vnl_vector_fixed< double, 3 >& v2) { - return (v1.magnitude()>v2.magnitude()); + return (v1.magnitude()>v2.magnitude()); } template< class PixelType > TractsToVectorImageFilter< PixelType >::TractsToVectorImageFilter(): - m_AngularThreshold(0.7), - m_Epsilon(0.999), - m_NormalizeVectors(false), - m_UseWorkingCopy(true), - m_MaxNumDirections(3), - m_SizeThreshold(0.3), - m_CreateDirectionImages(true) + m_NormalizationMethod(GLOBAL_MAX), + m_AngularThreshold(0.7), + m_Epsilon(0.999), + m_UseWorkingCopy(true), + m_MaxNumDirections(3), + m_SizeThreshold(0.3) { - this->SetNumberOfRequiredOutputs(1); + this->SetNumberOfRequiredOutputs(1); } template< class PixelType > TractsToVectorImageFilter< PixelType >::~TractsToVectorImageFilter() { } template< class PixelType > vnl_vector_fixed TractsToVectorImageFilter< PixelType >::GetVnlVector(double point[]) { - vnl_vector_fixed vnlVector; - vnlVector[0] = point[0]; - vnlVector[1] = point[1]; - vnlVector[2] = point[2]; - return vnlVector; + vnl_vector_fixed vnlVector; + vnlVector[0] = point[0]; + vnlVector[1] = point[1]; + vnlVector[2] = point[2]; + return vnlVector; } template< class PixelType > itk::Point TractsToVectorImageFilter< PixelType >::GetItkPoint(double point[]) { - itk::Point itkPoint; - itkPoint[0] = point[0]; - itkPoint[1] = point[1]; - itkPoint[2] = point[2]; - return itkPoint; + itk::Point itkPoint; + itkPoint[0] = point[0]; + itkPoint[1] = point[1]; + itkPoint[2] = point[2]; + return itkPoint; } template< class PixelType > void TractsToVectorImageFilter< PixelType >::GenerateData() { - mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry(); - - // calculate new image parameters - itk::Vector spacing3; - itk::Point origin3; - itk::Matrix direction3; - ImageRegion<3> imageRegion3; - if (!m_MaskImage.IsNull()) + mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry(); + + // calculate new image parameters + itk::Vector spacing3; + itk::Point origin3; + itk::Matrix direction3; + ImageRegion<3> imageRegion3; + if (!m_MaskImage.IsNull()) + { + spacing3 = m_MaskImage->GetSpacing(); + imageRegion3 = m_MaskImage->GetLargestPossibleRegion(); + origin3 = m_MaskImage->GetOrigin(); + direction3 = m_MaskImage->GetDirection(); + } + else + { + spacing3 = geometry->GetSpacing(); + origin3 = geometry->GetOrigin(); + mitk::BaseGeometry::BoundsArrayType bounds = geometry->GetBounds(); + origin3[0] += bounds.GetElement(0); + origin3[1] += bounds.GetElement(2); + origin3[2] += bounds.GetElement(4); + + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + direction3[j][i] = geometry->GetMatrixColumn(i)[j]; + imageRegion3.SetSize(0, geometry->GetExtent(0)+1); + imageRegion3.SetSize(1, geometry->GetExtent(1)+1); + imageRegion3.SetSize(2, geometry->GetExtent(2)+1); + + + m_MaskImage = ItkUcharImgType::New(); + m_MaskImage->SetSpacing( spacing3 ); + m_MaskImage->SetOrigin( origin3 ); + m_MaskImage->SetDirection( direction3 ); + m_MaskImage->SetRegions( imageRegion3 ); + m_MaskImage->Allocate(); + m_MaskImage->FillBuffer(1); + } + OutputImageType::RegionType::SizeType outImageSize = imageRegion3.GetSize(); + m_OutImageSpacing = m_MaskImage->GetSpacing(); + m_ClusteredDirectionsContainer = ContainerType::New(); + + // initialize num directions image + m_NumDirectionsImage = ItkUcharImgType::New(); + m_NumDirectionsImage->SetSpacing( spacing3 ); + m_NumDirectionsImage->SetOrigin( origin3 ); + m_NumDirectionsImage->SetDirection( direction3 ); + m_NumDirectionsImage->SetRegions( imageRegion3 ); + m_NumDirectionsImage->Allocate(); + m_NumDirectionsImage->FillBuffer(0); + + itk::Vector spacing4; + itk::Point origin4; + itk::Matrix direction4; + itk::ImageRegion<4> imageRegion4; + + spacing4[0] = spacing3[0]; spacing4[1] = spacing3[1]; spacing4[2] = spacing3[2]; spacing4[3] = 1; + origin4[0] = origin3[0]; origin4[1] = origin3[1]; origin4[2] = origin3[2]; origin3[3] = 0; + for (int r=0; r<3; r++) + for (int c=0; c<3; c++) + direction4[r][c] = direction3[r][c]; + direction4[3][3] = 1; + imageRegion4.SetSize(0, imageRegion3.GetSize()[0]); + imageRegion4.SetSize(1, imageRegion3.GetSize()[1]); + imageRegion4.SetSize(2, imageRegion3.GetSize()[2]); + imageRegion4.SetSize(3, m_MaxNumDirections*3); + + m_DirectionImage = ItkDirectionImageType::New(); + m_DirectionImage->SetSpacing( spacing4 ); + m_DirectionImage->SetOrigin( origin4 ); + m_DirectionImage->SetDirection( direction4 ); + m_DirectionImage->SetRegions( imageRegion4 ); + m_DirectionImage->Allocate(); + m_DirectionImage->FillBuffer(0.0); + + // resample fiber bundle + double minSpacing = 1; + if(m_OutImageSpacing[0]GetDeepCopy(); + + // resample fiber bundle for sufficient voxel coverage + m_FiberBundle->ResampleLinear(minSpacing/10); + + // iterate over all fibers + vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); + int numFibers = m_FiberBundle->GetNumFibers(); + m_DirectionsContainer = ContainerType::New(); + + VectorContainer< unsigned int, std::vector< double > >::Pointer peakLengths = VectorContainer< unsigned int, std::vector< double > >::New(); + + MITK_INFO << "Generating directions from tractogram"; + boost::progress_display disp(numFibers); + for( int i=0; iGetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + if (numPoints<2) + continue; + + vnl_vector_fixed dir; + itk::Point worldPos; + vnl_vector v; + + + float fiberWeight = m_FiberBundle->GetFiberWeight(i); + + for( int j=0; jGetSpacing(); - imageRegion3 = m_MaskImage->GetLargestPossibleRegion(); - origin3 = m_MaskImage->GetOrigin(); - direction3 = m_MaskImage->GetDirection(); - } - else - { - spacing3 = geometry->GetSpacing(); - origin3 = geometry->GetOrigin(); - mitk::BaseGeometry::BoundsArrayType bounds = geometry->GetBounds(); - origin3[0] += bounds.GetElement(0); - origin3[1] += bounds.GetElement(2); - origin3[2] += bounds.GetElement(4); - - for (int i=0; i<3; i++) - for (int j=0; j<3; j++) - direction3[j][i] = geometry->GetMatrixColumn(i)[j]; - imageRegion3.SetSize(0, geometry->GetExtent(0)+1); - imageRegion3.SetSize(1, geometry->GetExtent(1)+1); - imageRegion3.SetSize(2, geometry->GetExtent(2)+1); - - - m_MaskImage = ItkUcharImgType::New(); - m_MaskImage->SetSpacing( spacing3 ); - m_MaskImage->SetOrigin( origin3 ); - m_MaskImage->SetDirection( direction3 ); - m_MaskImage->SetRegions( imageRegion3 ); - m_MaskImage->Allocate(); - m_MaskImage->FillBuffer(1); + // get current position along fiber in world coordinates + double* temp = points->GetPoint(j); + worldPos = GetItkPoint(temp); + itk::Index<3> index; + m_MaskImage->TransformPhysicalPointToIndex(worldPos, index); + if (!m_MaskImage->GetLargestPossibleRegion().IsInside(index) || m_MaskImage->GetPixel(index)==0) + continue; + + // get fiber tangent direction at this position + v = GetVnlVector(temp); + dir = GetVnlVector(points->GetPoint(j+1))-v; + if (dir.is_zero()) + continue; + dir.normalize(); + + // add direction to container + unsigned int idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2]); + DirectionContainerType::Pointer dirCont; + if (m_DirectionsContainer->IndexExists(idx)) + { + peakLengths->ElementAt(idx).push_back(fiberWeight); + + dirCont = m_DirectionsContainer->GetElement(idx); + if (dirCont.IsNull()) + { + dirCont = DirectionContainerType::New(); + dirCont->push_back(dir); + m_DirectionsContainer->InsertElement(idx, dirCont); + } + else + dirCont->push_back(dir); + } + else + { + dirCont = DirectionContainerType::New(); + dirCont->push_back(dir); + m_DirectionsContainer->InsertElement(idx, dirCont); + + std::vector< double > lengths; lengths.push_back(fiberWeight); + peakLengths->InsertElement(idx, lengths); + } } - OutputImageType::RegionType::SizeType outImageSize = imageRegion3.GetSize(); - m_OutImageSpacing = m_MaskImage->GetSpacing(); - m_ClusteredDirectionsContainer = ContainerType::New(); - - // initialize num directions image - m_NumDirectionsImage = ItkUcharImgType::New(); - m_NumDirectionsImage->SetSpacing( spacing3 ); - m_NumDirectionsImage->SetOrigin( origin3 ); - m_NumDirectionsImage->SetDirection( direction3 ); - m_NumDirectionsImage->SetRegions( imageRegion3 ); - m_NumDirectionsImage->Allocate(); - m_NumDirectionsImage->FillBuffer(0); - - itk::Vector spacing4; - itk::Point origin4; - itk::Matrix direction4; - itk::ImageRegion<4> imageRegion4; - - spacing4[0] = spacing3[0]; spacing4[1] = spacing3[1]; spacing4[2] = spacing3[2]; spacing4[3] = 1; - origin4[0] = origin3[0]; origin4[1] = origin3[1]; origin4[2] = origin3[2]; origin3[3] = 0; - for (int r=0; r<3; r++) - for (int c=0; c<3; c++) - direction4[r][c] = direction3[r][c]; - direction4[3][3] = 1; - imageRegion4.SetSize(0, imageRegion3.GetSize()[0]); - imageRegion4.SetSize(1, imageRegion3.GetSize()[1]); - imageRegion4.SetSize(2, imageRegion3.GetSize()[2]); - imageRegion4.SetSize(3, m_MaxNumDirections*3); - - m_DirectionImage = ItkDirectionImageType::New(); - m_DirectionImage->SetSpacing( spacing4 ); - m_DirectionImage->SetOrigin( origin4 ); - m_DirectionImage->SetDirection( direction4 ); - m_DirectionImage->SetRegions( imageRegion4 ); - m_DirectionImage->Allocate(); - m_DirectionImage->FillBuffer(0.0); - - // resample fiber bundle - double minSpacing = 1; - if(m_OutImageSpacing[0]GetDeepCopy(); + } - // resample fiber bundle for sufficient voxel coverage - m_FiberBundle->ResampleLinear(minSpacing/10); + itk::ImageRegionIterator dirIt(m_NumDirectionsImage, m_NumDirectionsImage->GetLargestPossibleRegion()); - // iterate over all fibers - vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); - int numFibers = m_FiberBundle->GetNumFibers(); - m_DirectionsContainer = ContainerType::New(); + MITK_INFO << "Clustering directions"; + float max_dir_mag = 0; + boost::progress_display disp2(outImageSize[0]*outImageSize[1]*outImageSize[2]); + while(!dirIt.IsAtEnd()) + { + ++disp2; + OutputImageType::IndexType idx3 = dirIt.GetIndex(); + int idx_lin = idx3[0]+(idx3[1]+idx3[2]*outImageSize[1])*outImageSize[0]; - VectorContainer< unsigned int, std::vector< double > >::Pointer peakLengths = VectorContainer< unsigned int, std::vector< double > >::New(); + itk::Index<4> idx4; idx4[0] = idx3[0]; idx4[1] = idx3[1]; idx4[2] = idx3[2]; - MITK_INFO << "Generating directions from tractogram"; - boost::progress_display disp(numFibers); - for( int i=0; iIndexExists(idx_lin)) { - ++disp; - vtkCell* cell = fiberPolyData->GetCell(i); - int numPoints = cell->GetNumberOfPoints(); - vtkPoints* points = cell->GetPoints(); - if (numPoints<2) - continue; - - vnl_vector_fixed dir; - itk::Point worldPos; - vnl_vector v; - - - float fiberWeight = m_FiberBundle->GetFiberWeight(i); - - for( int j=0; jGetPoint(j); - worldPos = GetItkPoint(temp); - itk::Index<3> index; - m_MaskImage->TransformPhysicalPointToIndex(worldPos, index); - if (!m_MaskImage->GetLargestPossibleRegion().IsInside(index) || m_MaskImage->GetPixel(index)==0) - continue; - - // get fiber tangent direction at this position - v = GetVnlVector(temp); - dir = GetVnlVector(points->GetPoint(j+1))-v; - if (dir.is_zero()) - continue; - dir.normalize(); - - // add direction to container - unsigned int idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2]); - DirectionContainerType::Pointer dirCont; - if (m_DirectionsContainer->IndexExists(idx)) - { - peakLengths->ElementAt(idx).push_back(fiberWeight); - - dirCont = m_DirectionsContainer->GetElement(idx); - if (dirCont.IsNull()) - { - dirCont = DirectionContainerType::New(); - dirCont->push_back(dir); - m_DirectionsContainer->InsertElement(idx, dirCont); - } - else - dirCont->push_back(dir); - } - else - { - dirCont = DirectionContainerType::New(); - dirCont->push_back(dir); - m_DirectionsContainer->InsertElement(idx, dirCont); - - std::vector< double > lengths; lengths.push_back(fiberWeight); - peakLengths->InsertElement(idx, lengths); - } - } + ++dirIt; + continue; } - - vtkSmartPointer m_VtkCellArray = vtkSmartPointer::New(); - vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); - - itk::ImageRegionIterator dirIt(m_NumDirectionsImage, m_NumDirectionsImage->GetLargestPossibleRegion()); - - MITK_INFO << "Clustering directions"; - boost::progress_display disp2(outImageSize[0]*outImageSize[1]*outImageSize[2]); - while(!dirIt.IsAtEnd()) + DirectionContainerType::Pointer dirCont = m_DirectionsContainer->GetElement(idx_lin); + if (dirCont.IsNull() || dirCont->empty()) { - ++disp2; - OutputImageType::IndexType idx3 = dirIt.GetIndex(); - int idx_lin = idx3[0]+(idx3[1]+idx3[2]*outImageSize[1])*outImageSize[0]; - - itk::Index<4> idx4; idx4[0] = idx3[0]; idx4[1] = idx3[1]; idx4[2] = idx3[2]; + ++dirIt; + continue; + } - if (!m_DirectionsContainer->IndexExists(idx_lin)) - { - ++dirIt; - continue; - } - DirectionContainerType::Pointer dirCont = m_DirectionsContainer->GetElement(idx_lin); - if (dirCont.IsNull() || dirCont->empty()) - { - ++dirIt; - continue; - } + DirectionContainerType::Pointer directions; + if (m_MaxNumDirections>0) + { + directions = FastClustering(dirCont, peakLengths->GetElement(idx_lin)); + std::sort( directions->begin(), directions->end(), CompareVectorLengths ); + } + else + directions = dirCont; -// std::vector< double > lengths; lengths.resize(dirCont->size(), 1); // all peaks have size 1 - DirectionContainerType::Pointer directions; - if (m_MaxNumDirections>0) - { - directions = FastClustering(dirCont, peakLengths->GetElement(idx_lin)); - std::sort( directions->begin(), directions->end(), CompareVectorLengths ); - } - else - directions = dirCont; + unsigned int numDir = directions->size(); + if (m_MaxNumDirections>0 && numDir>m_MaxNumDirections) + numDir = m_MaxNumDirections; - unsigned int numDir = directions->size(); - if (m_MaxNumDirections>0 && numDir>m_MaxNumDirections) - numDir = m_MaxNumDirections; + float voxel_max_mag = 0; + for (unsigned int i=0; iat(i); + float mag = dir.magnitude(); - int count = 0; - for (unsigned int i=0; i container = vtkSmartPointer::New(); - itk::ContinuousIndex center; - center[0] = idx3[0]; - center[1] = idx3[1]; - center[2] = idx3[2]; - itk::Point worldCenter; - m_MaskImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); - DirectionType dir = directions->at(i); - - if (dir.magnitude()SetPixel(idx4, dir[j]); - } - - // add direction to vector field (with spacing compensation) - itk::Point worldStart; - worldStart[0] = worldCenter[0]-dir[0]/2*minSpacing; - worldStart[1] = worldCenter[1]-dir[1]/2*minSpacing; - worldStart[2] = worldCenter[2]-dir[2]/2*minSpacing; - vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); - container->GetPointIds()->InsertNextId(id); - itk::Point worldEnd; - worldEnd[0] = worldCenter[0]+dir[0]/2*minSpacing; - worldEnd[1] = worldCenter[1]+dir[1]/2*minSpacing; - worldEnd[2] = worldCenter[2]+dir[2]/2*minSpacing; - id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); - container->GetPointIds()->InsertNextId(id); - m_VtkCellArray->InsertNextCell(container); - } - dirIt.Set(count); - ++dirIt; + if (mag>voxel_max_mag) + voxel_max_mag = mag; + if (mag>max_dir_mag) + max_dir_mag = mag; } - vtkSmartPointer directionsPolyData = vtkSmartPointer::New(); - directionsPolyData->SetPoints(m_VtkPoints); - directionsPolyData->SetLines(m_VtkCellArray); - m_OutputFiberBundle = mitk::FiberBundle::New(directionsPolyData); + int count = 0; + for (unsigned int i=0; iat(i); + count++; + + float mag = dir.magnitude(); + if (m_NormalizationMethod==MAX_VEC_NORM && voxel_max_mag>mitk::eps) + dir /= voxel_max_mag; + else if (m_NormalizationMethod==SINGLE_VEC_NORM && mag>mitk::eps) + dir.normalize(); + + for (unsigned int j = 0; j<3; j++) + { + idx4[3] = i*3 + j; + m_DirectionImage->SetPixel(idx4, dir[j]); + } + } + dirIt.Set(count); + ++dirIt; + } + + if (m_NormalizationMethod==GLOBAL_MAX && max_dir_mag>0) + { + itk::ImageRegionIterator dirImgIt(m_DirectionImage, m_DirectionImage->GetLargestPossibleRegion()); + while(!dirImgIt.IsAtEnd()) + { + dirImgIt.Set(dirImgIt.Get()/max_dir_mag); + ++dirImgIt; + } + } } template< class PixelType > TractsToVectorImageFilter< PixelType >::DirectionContainerType::Pointer TractsToVectorImageFilter< PixelType >::FastClustering(DirectionContainerType::Pointer inDirs, std::vector< double > lengths) { - DirectionContainerType::Pointer outDirs = DirectionContainerType::New(); - if (inDirs->size()<2) - return inDirs; - - DirectionType oldMean, currentMean; - std::vector< int > touched; - - // initialize - touched.resize(inDirs->size(), 0); - bool free = true; - currentMean = inDirs->at(0); // initialize first seed - currentMean.normalize(); - double length = lengths.at(0); - touched[0] = 1; - std::vector< double > newLengths; - bool meanChanged = false; - - double max = 0; - while (free) + DirectionContainerType::Pointer outDirs = DirectionContainerType::New(); + if (inDirs->size()<2) + { + if (inDirs->size()==1) + inDirs->SetElement(0, inDirs->at(0)*lengths.at(0)); + return inDirs; + } + + DirectionType oldMean, currentMean; + std::vector< int > touched; + + // initialize + touched.resize(inDirs->size(), 0); + bool free = true; + currentMean = inDirs->at(0); // initialize first seed + currentMean.normalize(); + double length = lengths.at(0); + touched[0] = 1; + std::vector< double > newLengths; + bool meanChanged = false; + + double max = 0; + while (free) + { + oldMean.fill(0.0); + + // start mean-shift clustering + double angle = 0; + + while (fabs(dot_product(currentMean, oldMean))<0.99) { - oldMean.fill(0.0); - - // start mean-shift clustering - double angle = 0; - - while (fabs(dot_product(currentMean, oldMean))<0.99) + oldMean = currentMean; + currentMean.fill(0.0); + for (unsigned int i=0; isize(); i++) + { + angle = dot_product(oldMean, inDirs->at(i)); + if (angle>=m_AngularThreshold) { - oldMean = currentMean; - currentMean.fill(0.0); - for (unsigned int i=0; isize(); i++) - { - angle = dot_product(oldMean, inDirs->at(i)); - if (angle>=m_AngularThreshold) - { - currentMean += inDirs->at(i); - if (meanChanged) - length += lengths.at(i); - touched[i] = 1; - meanChanged = true; - } - else if (-angle>=m_AngularThreshold) - { - currentMean -= inDirs->at(i); - if (meanChanged) - length += lengths.at(i); - touched[i] = 1; - meanChanged = true; - } - } - if(!meanChanged) - currentMean = oldMean; - else - currentMean.normalize(); + currentMean += inDirs->at(i); + if (meanChanged) + length += lengths.at(i); + touched[i] = 1; + meanChanged = true; } - - // found stable mean - outDirs->push_back(currentMean); - newLengths.push_back(length); - if (length>max) - max = length; - - // find next unused seed - free = false; - for (unsigned int i=0; iat(i); - free = true; - meanChanged = false; - length = lengths.at(i); - touched[i] = 1; - break; - } + else if (-angle>=m_AngularThreshold) + { + currentMean -= inDirs->at(i); + if (meanChanged) + length += lengths.at(i); + touched[i] = 1; + meanChanged = true; + } + } + if(!meanChanged) + currentMean = oldMean; + else + currentMean.normalize(); } - if (inDirs->size()==outDirs->size()) + // found stable mean + outDirs->push_back(currentMean); + newLengths.push_back(length); + if (length>max) + max = length; + + // find next unused seed + free = false; + for (unsigned int i=0; iat(i); + free = true; + meanChanged = false; + length = lengths.at(i); + touched[i] = 1; + break; + } + } + + if (inDirs->size()==outDirs->size()) + { + if (max>0) { - if (max>0) - for (unsigned int i=0; isize(); i++) - outDirs->SetElement(i, outDirs->at(i)*newLengths.at(i)/max); - return outDirs; + for (unsigned int i=0; isize(); i++) + outDirs->SetElement(i, outDirs->at(i)*newLengths.at(i)); } - else - return FastClustering(outDirs, newLengths); + return outDirs; + } + else + return FastClustering(outDirs, newLengths); } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h index fcef17847e..e4ed2d9fab 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h @@ -1,104 +1,106 @@ #ifndef __itkTractsToVectorImageFilter_h__ #define __itkTractsToVectorImageFilter_h__ // MITK #include // ITK #include #include // VTK #include #include #include #include #include namespace itk{ /** * \brief Extracts the voxel-wise main directions of the input fiber bundle. */ template< class PixelType > class TractsToVectorImageFilter : public ImageSource< Image< PixelType, 4 > > { public: - typedef TractsToVectorImageFilter Self; - typedef ProcessObject Superclass; - typedef SmartPointer< Self > Pointer; - typedef SmartPointer< const Self > ConstPointer; - - typedef itk::Vector OutputVectorType; - typedef itk::Image OutputImageType; - typedef std::vector< OutputImageType::Pointer > OutputImageContainerType; - - typedef vnl_vector_fixed< double, 3 > DirectionType; - typedef VectorContainer< unsigned int, DirectionType > DirectionContainerType; - typedef VectorContainer< unsigned int, DirectionContainerType::Pointer > ContainerType; - typedef Image< PixelType, 4 > ItkDirectionImageType; - typedef itk::Image ItkUcharImgType; - typedef itk::Image ItkDoubleImgType; - - itkFactorylessNewMacro(Self) - itkCloneMacro(Self) - itkTypeMacro( TractsToVectorImageFilter, ImageSource ) - - itkSetMacro( SizeThreshold, float) - itkGetMacro( SizeThreshold, float) - itkSetMacro( AngularThreshold, float) ///< cluster directions that are closer together than the specified threshold - itkGetMacro( AngularThreshold, float) ///< cluster directions that are closer together than the specified threshold - itkSetMacro( NormalizeVectors, bool) ///< Normalize vectors to length 1 - itkGetMacro( NormalizeVectors, bool) ///< Normalize vectors to length 1 - itkSetMacro( UseWorkingCopy, bool) ///< Do not modify input fiber bundle. Use a copy. - itkGetMacro( UseWorkingCopy, bool) ///< Do not modify input fiber bundle. Use a copy. - itkSetMacro( MaxNumDirections, unsigned long) ///< If more directions are extracted, only the largest are kept. - itkGetMacro( MaxNumDirections, unsigned long) ///< If more directions are extracted, only the largest are kept. - itkSetMacro( MaskImage, ItkUcharImgType::Pointer) ///< only process voxels inside mask - itkSetMacro( FiberBundle, mitk::FiberBundle::Pointer) ///< input fiber bundle - itkGetMacro( ClusteredDirectionsContainer, ContainerType::Pointer) ///< output directions - itkGetMacro( NumDirectionsImage, ItkUcharImgType::Pointer) ///< number of directions per voxel - itkGetMacro( OutputFiberBundle, mitk::FiberBundle::Pointer) ///< vector field for visualization purposes - itkGetMacro( DirectionImage, typename ItkDirectionImageType::Pointer) ///< output directions - itkSetMacro( CreateDirectionImages, bool) - - void GenerateData() override; + + enum NormalizationMethods { + GLOBAL_MAX, ///< global maximum normalization + SINGLE_VEC_NORM, ///< normalize the single peaks to length 1 + MAX_VEC_NORM ///< normalize all peaks according to their length in comparison to the largest peak in the voxel (0-1) + }; + + typedef TractsToVectorImageFilter Self; + typedef ProcessObject Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + typedef itk::Vector OutputVectorType; + typedef itk::Image OutputImageType; + typedef std::vector< OutputImageType::Pointer > OutputImageContainerType; + + typedef vnl_vector_fixed< double, 3 > DirectionType; + typedef VectorContainer< unsigned int, DirectionType > DirectionContainerType; + typedef VectorContainer< unsigned int, DirectionContainerType::Pointer > ContainerType; + typedef Image< PixelType, 4 > ItkDirectionImageType; + typedef itk::Image ItkUcharImgType; + typedef itk::Image ItkDoubleImgType; + + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + itkTypeMacro( TractsToVectorImageFilter, ImageSource ) + + itkSetMacro( SizeThreshold, float) + itkGetMacro( SizeThreshold, float) + itkSetMacro( AngularThreshold, float) ///< cluster directions that are closer together than the specified threshold + itkGetMacro( AngularThreshold, float) ///< cluster directions that are closer together than the specified threshold + itkSetMacro( NormalizationMethod, NormalizationMethods) ///< normalization method of peaks + itkSetMacro( UseWorkingCopy, bool) ///< Do not modify input fiber bundle. Use a copy. + itkGetMacro( UseWorkingCopy, bool) ///< Do not modify input fiber bundle. Use a copy. + itkSetMacro( MaxNumDirections, unsigned long) ///< If more directions are extracted, only the largest are kept. + itkGetMacro( MaxNumDirections, unsigned long) ///< If more directions are extracted, only the largest are kept. + itkSetMacro( MaskImage, ItkUcharImgType::Pointer) ///< only process voxels inside mask + itkSetMacro( FiberBundle, mitk::FiberBundle::Pointer) ///< input fiber bundle + itkGetMacro( ClusteredDirectionsContainer, ContainerType::Pointer) ///< output directions + itkGetMacro( NumDirectionsImage, ItkUcharImgType::Pointer) ///< number of directions per voxel + itkGetMacro( DirectionImage, typename ItkDirectionImageType::Pointer) ///< output directions + + void GenerateData() override; protected: - DirectionContainerType::Pointer FastClustering(DirectionContainerType::Pointer inDirs, std::vector< double > lengths); ///< cluster fiber directions + DirectionContainerType::Pointer FastClustering(DirectionContainerType::Pointer inDirs, std::vector< double > lengths); ///< cluster fiber directions - vnl_vector_fixed GetVnlVector(double point[3]); - itk::Point GetItkPoint(double point[3]); + vnl_vector_fixed GetVnlVector(double point[3]); + itk::Point GetItkPoint(double point[3]); - TractsToVectorImageFilter(); - virtual ~TractsToVectorImageFilter(); + TractsToVectorImageFilter(); + virtual ~TractsToVectorImageFilter(); - mitk::FiberBundle::Pointer m_FiberBundle; ///< input fiber bundle - float m_AngularThreshold; ///< cluster directions that are closer together than the specified threshold - float m_Epsilon; ///< epsilon for vector equality check - ItkUcharImgType::Pointer m_MaskImage; ///< only voxels inside the binary mask are processed - bool m_NormalizeVectors; ///< normalize vectors to length 1 - itk::Vector m_OutImageSpacing; ///< spacing of output image - ContainerType::Pointer m_DirectionsContainer; ///< container for fiber directions - bool m_UseWorkingCopy; ///< do not modify input fiber bundle but work on copy - unsigned long m_MaxNumDirections; ///< if more directions per voxel are extracted, only the largest are kept - float m_SizeThreshold; - bool m_CreateDirectionImages; + NormalizationMethods m_NormalizationMethod; ///< normalization method of peaks + mitk::FiberBundle::Pointer m_FiberBundle; ///< input fiber bundle + float m_AngularThreshold; ///< cluster directions that are closer together than the specified threshold + float m_Epsilon; ///< epsilon for vector equality check + ItkUcharImgType::Pointer m_MaskImage; ///< only voxels inside the binary mask are processed + itk::Vector m_OutImageSpacing; ///< spacing of output image + ContainerType::Pointer m_DirectionsContainer; ///< container for fiber directions + bool m_UseWorkingCopy; ///< do not modify input fiber bundle but work on copy + unsigned long m_MaxNumDirections; ///< if more directions per voxel are extracted, only the largest are kept + float m_SizeThreshold; - // output datastructures - typename ItkDirectionImageType::Pointer m_DirectionImage; - ContainerType::Pointer m_ClusteredDirectionsContainer; ///< contains direction vectors for each voxel - ItkUcharImgType::Pointer m_NumDirectionsImage; ///< shows number of fibers per voxel - mitk::FiberBundle::Pointer m_OutputFiberBundle; ///< vector field for visualization purposes + // output datastructures + typename ItkDirectionImageType::Pointer m_DirectionImage; + ContainerType::Pointer m_ClusteredDirectionsContainer; ///< contains direction vectors for each voxel + ItkUcharImgType::Pointer m_NumDirectionsImage; ///< shows number of fibers per voxel }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkTractsToVectorImageFilter.cpp" #endif #endif // __itkTractsToVectorImageFilter_h__ diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt b/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt index c9c558e4f2..b4aa62b258 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt +++ b/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt @@ -1,21 +1,18 @@ MITK_CREATE_MODULE_TESTS() if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") mitkAddCustomModuleTest(mitkFiberBundleReaderWriterTest mitkFiberBundleReaderWriterTest) # Temporarily disabled. Since method relies on random numbers, the behaviour is not consistent across different systems. Solution? #mitkAddCustomModuleTest(mitkGibbsTrackingTest mitkGibbsTrackingTest ${MITK_DATA_DIR}/DiffusionImaging/qBallImage.qbi ${MITK_DATA_DIR}/DiffusionImaging/diffusionImageMask.nrrd ${MITK_DATA_DIR}/DiffusionImaging/gibbsTrackingParameters.gtp ${MITK_DATA_DIR}/DiffusionImaging/gibbsTractogram.fib) - -# mitkLocalFiberPlausibilityTest needs to use new direction image -# mitkAddCustomModuleTest(mitkLocalFiberPlausibilityTest mitkLocalFiberPlausibilityTest ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX.fib ${MITK_DATA_DIR}/DiffusionImaging/LDFP_GT_DIRECTION_0.nrrd ${MITK_DATA_DIR}/DiffusionImaging/LDFP_GT_DIRECTION_1.nrrd ${MITK_DATA_DIR}/DiffusionImaging/LDFP_ERROR_IMAGE.nrrd ${MITK_DATA_DIR}/DiffusionImaging/LDFP_NUM_DIRECTIONS.nrrd ${MITK_DATA_DIR}/DiffusionImaging/LDFP_VECTOR_FIELD.fib ${MITK_DATA_DIR}/DiffusionImaging/LDFP_ERROR_IMAGE_IGNORE.nrrd) mitkAddCustomModuleTest(mitkFiberTransformationTest mitkFiberTransformationTest ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_transformed.fib) mitkAddCustomModuleTest(mitkFiberExtractionTest mitkFiberExtractionTest ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_extracted.fib ${MITK_DATA_DIR}/DiffusionImaging/ROI1.pf ${MITK_DATA_DIR}/DiffusionImaging/ROI2.pf ${MITK_DATA_DIR}/DiffusionImaging/ROI3.pf ${MITK_DATA_DIR}/DiffusionImaging/ROIIMAGE.nrrd ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_inside.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_outside.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_passing-mask.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_ending-in-mask.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_subtracted.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_added.fib) mitkAddCustomModuleTest(mitkFiberGenerationTest mitkFiberGenerationTest ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/Fiducial_0.pf ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/Fiducial_1.pf ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/Fiducial_2.pf ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/uniform.fib ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/gaussian.fib) mitkAddCustomModuleTest(mitkFiberfoxSignalGenerationTest mitkFiberfoxSignalGenerationTest) mitkAddCustomModuleTest(mitkMachineLearningTrackingTest mitkMachineLearningTrackingTest) mitkAddCustomModuleTest(mitkStreamlineTractographyTest mitkStreamlineTractographyTest) mitkAddCustomModuleTest(mitkFiberProcessingTest mitkFiberProcessingTest) ENDIF() diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/files.cmake b/Modules/DiffusionImaging/FiberTracking/Testing/files.cmake index f760eddcd6..7190a886e0 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/files.cmake +++ b/Modules/DiffusionImaging/FiberTracking/Testing/files.cmake @@ -1,15 +1,14 @@ SET(MODULE_CUSTOM_TESTS mitkFiberBundleReaderWriterTest.cpp mitkGibbsTrackingTest.cpp mitkStreamlineTractographyTest.cpp - mitkPeakExtractionTest.cpp mitkLocalFiberPlausibilityTest.cpp mitkFiberTransformationTest.cpp mitkFiberExtractionTest.cpp mitkFiberGenerationTest.cpp mitkFiberfoxSignalGenerationTest.cpp mitkMachineLearningTrackingTest.cpp mitkFiberProcessingTest.cpp ) diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp index da55d9400b..0dd0aa5f74 100755 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp @@ -1,161 +1,161 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include using namespace std; int mitkLocalFiberPlausibilityTest(int argc, char* argv[]) { omp_set_num_threads(1); MITK_TEST_BEGIN("mitkLocalFiberPlausibilityTest"); MITK_TEST_CONDITION_REQUIRED(argc==8,"check for input data") string fibFile = argv[1]; vector< string > referenceImages; referenceImages.push_back(argv[2]); referenceImages.push_back(argv[3]); string LDFP_ERROR_IMAGE = argv[4]; string LDFP_NUM_DIRECTIONS = argv[5]; string LDFP_VECTOR_FIELD = argv[6]; string LDFP_ERROR_IMAGE_IGNORE = argv[7]; float angularThreshold = 30; try { typedef itk::Image ItkUcharImgType; typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType; typedef itk::VectorContainer< unsigned int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; typedef itk::EvaluateDirectionImagesFilter< float > EvaluationFilterType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::Load(fibFile)[0].GetPointer()); // load reference directions ItkDirectionImageContainerType::Pointer referenceImageContainer = ItkDirectionImageContainerType::New(); for (unsigned int i=0; i(mitk::IOUtil::Load(referenceImages.at(i))[0].GetPointer()); typedef mitk::ImageToItk< ItkDirectionImage3DType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); ItkDirectionImage3DType::Pointer itkImg = caster->GetOutput(); referenceImageContainer->InsertElement(referenceImageContainer->Size(),itkImg); } catch(...){ MITK_INFO << "could not load: " << referenceImages.at(i); } } ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); ItkDirectionImage3DType::Pointer dirImg = referenceImageContainer->GetElement(0); itkMaskImage->SetSpacing( dirImg->GetSpacing() ); itkMaskImage->SetOrigin( dirImg->GetOrigin() ); itkMaskImage->SetDirection( dirImg->GetDirection() ); itkMaskImage->SetLargestPossibleRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetBufferedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetRequestedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->Allocate(); itkMaskImage->FillBuffer(1); // extract directions from fiber bundle itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetMaskImage(itkMaskImage); fOdfFilter->SetAngularThreshold(cos(angularThreshold*M_PI/180)); - fOdfFilter->SetNormalizeVectors(true); + fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::SINGLE_VEC_NORM); fOdfFilter->SetMaxNumDirections(3); fOdfFilter->SetSizeThreshold(0.3); fOdfFilter->SetUseWorkingCopy(false); fOdfFilter->SetNumberOfThreads(1); fOdfFilter->Update(); itk::TractsToVectorImageFilter::ItkDirectionImageType::Pointer direction_image = fOdfFilter->GetDirectionImage(); // Get directions and num directions image ItkUcharImgType::Pointer numDirImage = fOdfFilter->GetNumDirectionsImage(); mitk::Image::Pointer mitkNumDirImage = mitk::Image::New(); mitkNumDirImage->InitializeByItk( numDirImage.GetPointer() ); mitkNumDirImage->SetVolume( numDirImage->GetBufferPointer() ); // mitk::FiberBundle::Pointer testDirections = fOdfFilter->GetOutputFiberBundle(); // evaluate directions with missing directions EvaluationFilterType::Pointer evaluationFilter = EvaluationFilterType::New(); // evaluationFilter->SetImageSet(directionImageContainer); evaluationFilter->SetReferenceImageSet(referenceImageContainer); evaluationFilter->SetMaskImage(itkMaskImage); evaluationFilter->SetIgnoreMissingDirections(false); evaluationFilter->Update(); EvaluationFilterType::OutputImageType::Pointer angularErrorImage = evaluationFilter->GetOutput(0); mitk::Image::Pointer mitkAngularErrorImage = mitk::Image::New(); mitkAngularErrorImage->InitializeByItk( angularErrorImage.GetPointer() ); mitkAngularErrorImage->SetVolume( angularErrorImage->GetBufferPointer() ); // evaluate directions without missing directions evaluationFilter->SetIgnoreMissingDirections(true); evaluationFilter->Update(); EvaluationFilterType::OutputImageType::Pointer angularErrorImageIgnore = evaluationFilter->GetOutput(0); mitk::Image::Pointer mitkAngularErrorImageIgnore = mitk::Image::New(); mitkAngularErrorImageIgnore->InitializeByItk( angularErrorImageIgnore.GetPointer() ); mitkAngularErrorImageIgnore->SetVolume( angularErrorImageIgnore->GetBufferPointer() ); mitk::Image::Pointer gtAngularErrorImageIgnore = dynamic_cast(mitk::IOUtil::Load(LDFP_ERROR_IMAGE_IGNORE)[0].GetPointer()); mitk::Image::Pointer gtAngularErrorImage = dynamic_cast(mitk::IOUtil::Load(LDFP_ERROR_IMAGE)[0].GetPointer()); mitk::Image::Pointer gtNumTestDirImage = dynamic_cast(mitk::IOUtil::Load(LDFP_NUM_DIRECTIONS)[0].GetPointer()); MITK_ASSERT_EQUAL(gtAngularErrorImageIgnore, mitkAngularErrorImageIgnore, "Check if error images are equal (ignored missing directions)."); MITK_ASSERT_EQUAL(gtAngularErrorImage, mitkAngularErrorImage, "Check if error images are equal."); MITK_ASSERT_EQUAL(gtNumTestDirImage, mitkNumDirImage, "Check if num direction images are equal."); } catch (itk::ExceptionObject e) { MITK_INFO << e; return EXIT_FAILURE; } catch (std::exception e) { MITK_INFO << e.what(); return EXIT_FAILURE; } catch (...) { MITK_INFO << "ERROR!?!"; return EXIT_FAILURE; } MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkPeakExtractionTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkPeakExtractionTest.cpp deleted file mode 100755 index 69e785ac66..0000000000 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkPeakExtractionTest.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -int mitkPeakExtractionTest(int argc, char* argv[]) -{ - MITK_TEST_BEGIN("mitkStreamlineTrackingTest"); - - MITK_TEST_CONDITION_REQUIRED(argc>3,"check for input data") - - string shCoeffFileName = argv[1]; - string maskFileName = argv[2]; - string referenceFileName = argv[3]; - - MITK_INFO << "SH-coefficient file: " << shCoeffFileName; - MITK_INFO << "Mask file: " << maskFileName; - MITK_INFO << "Reference fiber file: " << referenceFileName; - - try - { - mitk::CoreObjectFactory::GetInstance(); - - mitk::Image::Pointer image = dynamic_cast(mitk::IOUtil::Load(shCoeffFileName)[0].GetPointer()); - mitk::Image::Pointer mitkMaskImage = dynamic_cast(mitk::IOUtil::Load(maskFileName)[0].GetPointer()); - - typedef itk::Image ItkUcharImgType; - typedef itk::FiniteDiffOdfMaximaExtractionFilter< float, 4, 20242 > MaximaExtractionFilterType; - MaximaExtractionFilterType::Pointer filter = MaximaExtractionFilterType::New(); - - MITK_INFO << "Casting mask image ..."; - ItkUcharImgType::Pointer itkMask = ItkUcharImgType::New(); - mitk::CastToItkImage(mitkMaskImage, itkMask); - filter->SetMaskImage(itkMask); - - MITK_INFO << "Casting SH image ..."; - typedef mitk::ImageToItk< MaximaExtractionFilterType::CoefficientImageType > CasterType; - CasterType::Pointer caster = CasterType::New(); - caster->SetInput(image); - caster->Update(); - filter->SetInput(caster->GetOutput()); - filter->SetMaxNumPeaks(2); - filter->SetPeakThreshold(0.4); - filter->SetAbsolutePeakThreshold(0.01); - filter->SetAngularThreshold(25); - filter->SetNormalizationMethod(MaximaExtractionFilterType::MAX_VEC_NORM); - filter->SetNumberOfThreads(1); - MITK_INFO << "Starting extraction ..."; - filter->Update(); - mitk::FiberBundle::Pointer fib1 = filter->GetOutputFiberBundle(); - - MITK_INFO << "Loading reference ..."; - std::vector infile = mitk::IOUtil::Load( referenceFileName ); - mitk::FiberBundle::Pointer fib2 = dynamic_cast(infile.at(0).GetPointer()); - - // TODO: reduce epsilon. strange issues with differing values between windows and linux. - MITK_TEST_CONDITION_REQUIRED(fib1->Equals(fib2), "Check if tractograms are equal."); - } - catch (itk::ExceptionObject e) - { - MITK_INFO << e; - return EXIT_FAILURE; - } - catch (std::exception e) - { - MITK_INFO << e.what(); - return EXIT_FAILURE; - } - catch (...) - { - MITK_INFO << "ERROR!?!"; - return EXIT_FAILURE; - } - - MITK_TEST_END(); -} diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp index 4632dff611..9867591755 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp @@ -1,179 +1,180 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include "mitkCommandLineParser.h" #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include using namespace std; /*! \brief Extract principal fiber directions from a tractogram */ int main(int argc, char* argv[]) { - mitkCommandLineParser parser; + mitkCommandLineParser parser; - parser.setTitle("Fiber Direction Extraction"); - parser.setCategory("Fiber Tracking and Processing Methods"); - parser.setDescription("Extract principal fiber directions from a tractogram"); - parser.setContributor("MIC"); + parser.setTitle("Fiber Direction Extraction"); + parser.setCategory("Fiber Tracking and Processing Methods"); + parser.setDescription("Extract principal fiber directions from a tractogram"); + parser.setContributor("MIC"); - parser.setArgumentPrefix("--", "-"); - parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input tractogram (.fib/.trk)", us::Any(), false); - parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false); - parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask:", "mask image"); - parser.addArgument("athresh", "a", mitkCommandLineParser::Float, "Angular threshold:", "angular threshold in degrees. closer fiber directions are regarded as one direction and clustered together.", 25, true); - parser.addArgument("peakthresh", "t", mitkCommandLineParser::Float, "Peak size threshold:", "peak size threshold relative to largest peak in voxel", 0.2, true); - parser.addArgument("verbose", "v", mitkCommandLineParser::Bool, "Verbose:", "output optional and intermediate calculation results"); - parser.addArgument("numdirs", "d", mitkCommandLineParser::Int, "Max. num. directions:", "maximum number of fibers per voxel", 3, true); - parser.addArgument("normalize", "n", mitkCommandLineParser::Bool, "Normalize:", "normalize vectors"); - parser.addArgument("file_ending", "f", mitkCommandLineParser::String, "Image type:", ".nrrd, .nii, .nii.gz"); + parser.setArgumentPrefix("--", "-"); + parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input tractogram (.fib/.trk)", us::Any(), false); + parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false); + parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask:", "mask image"); + parser.addArgument("athresh", "a", mitkCommandLineParser::Float, "Angular threshold:", "angular threshold in degrees. closer fiber directions are regarded as one direction and clustered together.", 25, true); + parser.addArgument("peakthresh", "t", mitkCommandLineParser::Float, "Peak size threshold:", "peak size threshold relative to largest peak in voxel", 0.2, true); + parser.addArgument("verbose", "v", mitkCommandLineParser::Bool, "Verbose:", "output optional and intermediate calculation results"); + parser.addArgument("numdirs", "d", mitkCommandLineParser::Int, "Max. num. directions:", "maximum number of fibers per voxel", 3, true); + parser.addArgument("normalization", "n", mitkCommandLineParser::Int, "Normalization method:", "1=global maximum, 2=single vector, 3=voxel-wise maximum", 1); + parser.addArgument("file_ending", "f", mitkCommandLineParser::String, "Image type:", ".nrrd, .nii, .nii.gz"); - map parsedArgs = parser.parseArguments(argc, argv); - if (parsedArgs.size()==0) - return EXIT_FAILURE; + map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size()==0) + return EXIT_FAILURE; - string fibFile = us::any_cast(parsedArgs["input"]); + string fibFile = us::any_cast(parsedArgs["input"]); - string maskImage(""); - if (parsedArgs.count("mask")) - maskImage = us::any_cast(parsedArgs["mask"]); + string maskImage(""); + if (parsedArgs.count("mask")) + maskImage = us::any_cast(parsedArgs["mask"]); - float peakThreshold = 0.2; - if (parsedArgs.count("peakthresh")) - peakThreshold = us::any_cast(parsedArgs["peakthresh"]); + float peakThreshold = 0.2; + if (parsedArgs.count("peakthresh")) + peakThreshold = us::any_cast(parsedArgs["peakthresh"]); - float angularThreshold = 25; - if (parsedArgs.count("athresh")) - angularThreshold = us::any_cast(parsedArgs["athresh"]); + float angularThreshold = 25; + if (parsedArgs.count("athresh")) + angularThreshold = us::any_cast(parsedArgs["athresh"]); - string outRoot = us::any_cast(parsedArgs["out"]); + string outRoot = us::any_cast(parsedArgs["out"]); - bool verbose = false; - if (parsedArgs.count("verbose")) - verbose = us::any_cast(parsedArgs["verbose"]); + bool verbose = false; + if (parsedArgs.count("verbose")) + verbose = us::any_cast(parsedArgs["verbose"]); - int maxNumDirs = 3; - if (parsedArgs.count("numdirs")) - maxNumDirs = us::any_cast(parsedArgs["numdirs"]); + int maxNumDirs = 3; + if (parsedArgs.count("numdirs")) + maxNumDirs = us::any_cast(parsedArgs["numdirs"]); - bool normalize = false; - if (parsedArgs.count("normalize")) - normalize = us::any_cast(parsedArgs["normalize"]); + int normalization = 1; + if (parsedArgs.count("normalization")) + normalization = us::any_cast(parsedArgs["normalization"]); - std::string file_ending = ".nrrd"; - if (parsedArgs.count("file_ending")) - file_ending = us::any_cast(parsedArgs["file_ending"]); + std::string file_ending = ".nrrd"; + if (parsedArgs.count("file_ending")) + file_ending = us::any_cast(parsedArgs["file_ending"]); - try + try + { + typedef itk::Image ItkUcharImgType; + + // load fiber bundle + mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::Load(fibFile)[0].GetPointer()); + + // load/create mask image + ItkUcharImgType::Pointer itkMaskImage = nullptr; + if (maskImage.compare("")!=0) { - typedef itk::Image ItkUcharImgType; - - // load fiber bundle - mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::Load(fibFile)[0].GetPointer()); - - // load/create mask image - ItkUcharImgType::Pointer itkMaskImage = nullptr; - if (maskImage.compare("")!=0) - { - std::cout << "Using mask image"; - itkMaskImage = ItkUcharImgType::New(); - mitk::Image::Pointer mitkMaskImage = dynamic_cast(mitk::IOUtil::Load(maskImage)[0].GetPointer()); - mitk::CastToItkImage(mitkMaskImage, itkMaskImage); - } - - // extract directions from fiber bundle - itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); - fOdfFilter->SetFiberBundle(inputTractogram); - fOdfFilter->SetMaskImage(itkMaskImage); - fOdfFilter->SetAngularThreshold(cos(angularThreshold*M_PI/180)); - fOdfFilter->SetNormalizeVectors(normalize); - fOdfFilter->SetUseWorkingCopy(false); - fOdfFilter->SetSizeThreshold(peakThreshold); - fOdfFilter->SetMaxNumDirections(maxNumDirs); - fOdfFilter->Update(); - - { - itk::TractsToVectorImageFilter::ItkDirectionImageType::Pointer itkImg = fOdfFilter->GetDirectionImage(); - typedef itk::ImageFileWriter< itk::TractsToVectorImageFilter::ItkDirectionImageType > WriterType; - WriterType::Pointer writer = WriterType::New(); - - string outfilename = outRoot; - outfilename.append("_DIRECTIONS"); - outfilename.append(file_ending); - - writer->SetFileName(outfilename.c_str()); - writer->SetInput(itkImg); - writer->Update(); - } - - if (verbose) - { - // write vector field - mitk::FiberBundle::Pointer directions = fOdfFilter->GetOutputFiberBundle(); - - string outfilename = outRoot; - outfilename.append("_VECTOR_FIELD.fib"); - - mitk::IOUtil::Save(directions.GetPointer(), outfilename ); - - // write num direction image - { - ItkUcharImgType::Pointer numDirImage = fOdfFilter->GetNumDirectionsImage(); - typedef itk::ImageFileWriter< ItkUcharImgType > WriterType; - WriterType::Pointer writer = WriterType::New(); - - string outfilename = outRoot; - outfilename.append("_NUM_DIRECTIONS"); - outfilename.append(file_ending); - - writer->SetFileName(outfilename.c_str()); - writer->SetInput(numDirImage); - writer->Update(); - } - } + std::cout << "Using mask image"; + itkMaskImage = ItkUcharImgType::New(); + mitk::Image::Pointer mitkMaskImage = dynamic_cast(mitk::IOUtil::Load(maskImage)[0].GetPointer()); + mitk::CastToItkImage(mitkMaskImage, itkMaskImage); } - catch (itk::ExceptionObject e) + + // extract directions from fiber bundle + itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); + fOdfFilter->SetFiberBundle(inputTractogram); + fOdfFilter->SetMaskImage(itkMaskImage); + fOdfFilter->SetAngularThreshold(cos(angularThreshold*M_PI/180)); + switch (normalization) { - std::cout << e; - return EXIT_FAILURE; + case 1: + fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::GLOBAL_MAX); + break; + case 2: + fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::SINGLE_VEC_NORM); + break; + case 3: + fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::MAX_VEC_NORM); + break; } - catch (std::exception e) + fOdfFilter->SetUseWorkingCopy(false); + fOdfFilter->SetSizeThreshold(peakThreshold); + fOdfFilter->SetMaxNumDirections(maxNumDirs); + fOdfFilter->Update(); + { - std::cout << e.what(); - return EXIT_FAILURE; + itk::TractsToVectorImageFilter::ItkDirectionImageType::Pointer itkImg = fOdfFilter->GetDirectionImage(); + typedef itk::ImageFileWriter< itk::TractsToVectorImageFilter::ItkDirectionImageType > WriterType; + WriterType::Pointer writer = WriterType::New(); + + string outfilename = outRoot; + outfilename.append("_DIRECTIONS"); + outfilename.append(file_ending); + + writer->SetFileName(outfilename.c_str()); + writer->SetInput(itkImg); + writer->Update(); } - catch (...) + + if (verbose) { - std::cout << "ERROR!?!"; - return EXIT_FAILURE; + // write num direction image + ItkUcharImgType::Pointer numDirImage = fOdfFilter->GetNumDirectionsImage(); + typedef itk::ImageFileWriter< ItkUcharImgType > WriterType; + WriterType::Pointer writer = WriterType::New(); + + string outfilename = outRoot; + outfilename.append("_NUM_DIRECTIONS"); + outfilename.append(file_ending); + + writer->SetFileName(outfilename.c_str()); + writer->SetInput(numDirImage); + writer->Update(); } - return EXIT_SUCCESS; + } + catch (itk::ExceptionObject e) + { + std::cout << e; + return EXIT_FAILURE; + } + catch (std::exception e) + { + std::cout << e.what(); + return EXIT_FAILURE; + } + catch (...) + { + std::cout << "ERROR!?!"; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/Misc/PeakExtraction.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/Misc/PeakExtraction.cpp index 22d588e5c1..f0009f4a7b 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/Misc/PeakExtraction.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/Misc/PeakExtraction.cpp @@ -1,371 +1,362 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include "mitkCommandLineParser.h" #include #include #include #include #include using namespace std; template int StartPeakExtraction(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("image", "i", mitkCommandLineParser::InputFile, "Input image", "sh coefficient image", us::Any(), false); parser.addArgument("outroot", "o", mitkCommandLineParser::OutputDirectory, "Output directory", "output root", us::Any(), false); parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask", "mask image"); parser.addArgument("normalization", "n", mitkCommandLineParser::Int, "Normalization", "0=no norm, 1=max norm, 2=single vec norm", 1, true); parser.addArgument("numpeaks", "p", mitkCommandLineParser::Int, "Max. number of peaks", "maximum number of extracted peaks", 2, true); parser.addArgument("peakthres", "r", mitkCommandLineParser::Float, "Peak threshold", "peak threshold relative to largest peak", 0.4, true); parser.addArgument("abspeakthres", "a", mitkCommandLineParser::Float, "Absolute peak threshold", "absolute peak threshold weighted with local GFA value", 0.06, true); parser.addArgument("shConvention", "s", mitkCommandLineParser::String, "Use specified SH-basis", "use specified SH-basis (MITK, FSL, MRtrix)", string("MITK"), true); parser.addArgument("noFlip", "f", mitkCommandLineParser::Bool, "No flip", "do not flip input image to match MITK coordinate convention"); parser.addArgument("clusterThres", "c", mitkCommandLineParser::Float, "Clustering threshold", "directions closer together than the specified angular threshold will be clustered (in rad)", 0.9); parser.addArgument("flipX", "fx", mitkCommandLineParser::Bool, "Flip X", "Flip peaks in x direction"); parser.addArgument("flipY", "fy", mitkCommandLineParser::Bool, "Flip Y", "Flip peaks in y direction"); parser.addArgument("flipZ", "fz", mitkCommandLineParser::Bool, "Flip Z", "Flip peaks in z direction"); parser.setCategory("Preprocessing Tools"); parser.setTitle("Peak Extraction"); parser.setDescription(""); parser.setContributor("MIC"); map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; // mandatory arguments string imageName = us::any_cast(parsedArgs["image"]); string outRoot = us::any_cast(parsedArgs["outroot"]); // optional arguments string maskImageName(""); if (parsedArgs.count("mask")) maskImageName = us::any_cast(parsedArgs["mask"]); int normalization = 1; if (parsedArgs.count("normalization")) normalization = us::any_cast(parsedArgs["normalization"]); int numPeaks = 2; if (parsedArgs.count("numpeaks")) numPeaks = us::any_cast(parsedArgs["numpeaks"]); float peakThres = 0.4; if (parsedArgs.count("peakthres")) peakThres = us::any_cast(parsedArgs["peakthres"]); float absPeakThres = 0.06; if (parsedArgs.count("abspeakthres")) absPeakThres = us::any_cast(parsedArgs["abspeakthres"]); float clusterThres = 0.9; if (parsedArgs.count("clusterThres")) clusterThres = us::any_cast(parsedArgs["clusterThres"]); bool noFlip = false; if (parsedArgs.count("noFlip")) noFlip = us::any_cast(parsedArgs["noFlip"]); bool flipX = false; if (parsedArgs.count("flipX")) flipX = us::any_cast(parsedArgs["flipX"]); bool flipY = false; if (parsedArgs.count("flipY")) flipY = us::any_cast(parsedArgs["flipY"]); bool flipZ = false; if (parsedArgs.count("flipZ")) flipZ = us::any_cast(parsedArgs["flipZ"]); std::cout << "image: " << imageName; std::cout << "outroot: " << outRoot; if (!maskImageName.empty()) std::cout << "mask: " << maskImageName; else std::cout << "no mask image selected"; std::cout << "numpeaks: " << numPeaks; std::cout << "peakthres: " << peakThres; std::cout << "abspeakthres: " << absPeakThres; std::cout << "shOrder: " << shOrder; try { mitk::Image::Pointer image = dynamic_cast(mitk::IOUtil::Load(imageName)[0].GetPointer()); mitk::Image::Pointer mask = dynamic_cast(mitk::IOUtil::Load(maskImageName)[0].GetPointer()); typedef itk::Image ItkUcharImgType; typedef itk::FiniteDiffOdfMaximaExtractionFilter< float, shOrder, 20242 > MaximaExtractionFilterType; typename MaximaExtractionFilterType::Pointer filter = MaximaExtractionFilterType::New(); int toolkitConvention = 0; if (parsedArgs.count("shConvention")) { string convention = us::any_cast(parsedArgs["shConvention"]).c_str(); if ( boost::algorithm::equals(convention, "FSL") ) { toolkitConvention = 1; std::cout << "Using FSL SH-basis"; } else if ( boost::algorithm::equals(convention, "MRtrix") ) { toolkitConvention = 2; std::cout << "Using MRtrix SH-basis"; } else std::cout << "Using MITK SH-basis"; } else std::cout << "Using MITK SH-basis"; ItkUcharImgType::Pointer itkMaskImage = nullptr; if (mask.IsNotNull()) { try{ itkMaskImage = ItkUcharImgType::New(); mitk::CastToItkImage(mask, itkMaskImage); filter->SetMaskImage(itkMaskImage); } catch(...) { } } if (toolkitConvention>0) { std::cout << "Converting coefficient image to MITK format"; typedef itk::ShCoefficientImageImporter< float, shOrder > ConverterType; typedef mitk::ImageToItk< itk::Image< float, 4 > > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(image); caster->Update(); itk::Image< float, 4 >::Pointer itkImage = caster->GetOutput(); typename ConverterType::Pointer converter = ConverterType::New(); if (noFlip) { converter->SetInputImage(itkImage); } else { std::cout << "Flipping image"; itk::FixedArray flipAxes; flipAxes[0] = true; flipAxes[1] = true; flipAxes[2] = false; flipAxes[3] = false; itk::FlipImageFilter< itk::Image< float, 4 > >::Pointer flipper = itk::FlipImageFilter< itk::Image< float, 4 > >::New(); flipper->SetInput(itkImage); flipper->SetFlipAxes(flipAxes); flipper->Update(); itk::Image< float, 4 >::Pointer flipped = flipper->GetOutput(); itk::Matrix< double,4,4 > m = itkImage->GetDirection(); m[0][0] *= -1; m[1][1] *= -1; flipped->SetDirection(m); itk::Point< float, 4 > o = itkImage->GetOrigin(); o[0] -= (flipped->GetLargestPossibleRegion().GetSize(0)-1); o[1] -= (flipped->GetLargestPossibleRegion().GetSize(1)-1); flipped->SetOrigin(o); converter->SetInputImage(flipped); } std::cout << "Starting conversion"; switch (toolkitConvention) { case 1: converter->SetToolkit(ConverterType::FSL); filter->SetToolkit(MaximaExtractionFilterType::FSL); break; case 2: converter->SetToolkit(ConverterType::MRTRIX); filter->SetToolkit(MaximaExtractionFilterType::MRTRIX); break; default: converter->SetToolkit(ConverterType::FSL); filter->SetToolkit(MaximaExtractionFilterType::FSL); break; } converter->GenerateData(); filter->SetInput(converter->GetCoefficientImage()); } else { try{ typedef mitk::ImageToItk< typename MaximaExtractionFilterType::CoefficientImageType > CasterType; typename CasterType::Pointer caster = CasterType::New(); caster->SetInput(image); caster->Update(); filter->SetInput(caster->GetOutput()); } catch(...) { std::cout << "wrong image type"; return EXIT_FAILURE; } } filter->SetMaxNumPeaks(numPeaks); filter->SetPeakThreshold(peakThres); filter->SetAbsolutePeakThreshold(absPeakThres); filter->SetAngularThreshold(1); filter->SetClusteringThreshold(clusterThres); filter->SetFlipX(flipX); filter->SetFlipY(flipY); filter->SetFlipZ(flipZ); switch (normalization) { 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; } std::cout << "Starting extraction"; filter->Update(); // write direction image { typename MaximaExtractionFilterType::PeakImageType::Pointer itkImg = filter->GetPeakImage(); string outfilename = outRoot; outfilename.append("_PEAKS.nrrd"); typedef itk::ImageFileWriter< typename MaximaExtractionFilterType::PeakImageType > WriterType; typename WriterType::Pointer writer = WriterType::New(); writer->SetFileName(outfilename); writer->SetInput(itkImg); writer->Update(); } // write num directions image { ItkUcharImgType::Pointer numDirImage = filter->GetNumDirectionsImage(); if (itkMaskImage.IsNotNull()) { numDirImage->SetDirection(itkMaskImage->GetDirection()); numDirImage->SetOrigin(itkMaskImage->GetOrigin()); } string outfilename = outRoot.c_str(); outfilename.append("_NUM_PEAKS.nrrd"); typedef itk::ImageFileWriter< ItkUcharImgType > WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetFileName(outfilename); writer->SetInput(numDirImage); writer->Update(); } - - // write vector field - { - mitk::FiberBundle::Pointer directions = filter->GetOutputFiberBundle(); - - string outfilename = outRoot.c_str(); - outfilename.append("_VECTOR_FIELD.fib"); - mitk::IOUtil::Save(directions.GetPointer(),outfilename.c_str()); - } } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } /*! \brief Extract maxima in the input spherical harmonics image. */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("image", "i", mitkCommandLineParser::InputFile, "Input image", "sh coefficient image", us::Any(), false); parser.addArgument("shOrder", "sh", mitkCommandLineParser::Int, "Spherical harmonics order", "spherical harmonics order"); parser.addArgument("outroot", "o", mitkCommandLineParser::OutputDirectory, "Output directory", "output root", us::Any(), false); parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask", "mask image"); parser.addArgument("normalization", "n", mitkCommandLineParser::Int, "Normalization", "0=no norm, 1=max norm, 2=single vec norm", 1, true); parser.addArgument("numpeaks", "p", mitkCommandLineParser::Int, "Max. number of peaks", "maximum number of extracted peaks", 2, true); parser.addArgument("peakthres", "r", mitkCommandLineParser::Float, "Peak threshold", "peak threshold relative to largest peak", 0.4, true); parser.addArgument("abspeakthres", "a", mitkCommandLineParser::Float, "Absolute peak threshold", "absolute peak threshold weighted with local GFA value", 0.06, true); parser.addArgument("shConvention", "s", mitkCommandLineParser::String, "Use specified SH-basis", "use specified SH-basis (MITK, FSL, MRtrix)", string("MITK"), true); parser.addArgument("noFlip", "f", mitkCommandLineParser::Bool, "No flip", "do not flip input image to match MITK coordinate convention"); parser.setCategory("Preprocessing Tools"); parser.setTitle("Peak Extraction"); parser.setDescription("Extract maxima in the input spherical harmonics image."); parser.setContributor("MIC"); map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; int shOrder = -1; if (parsedArgs.count("shOrder")) shOrder = us::any_cast(parsedArgs["shOrder"]); switch (shOrder) { case 4: return StartPeakExtraction<4>(argc, argv); case 6: return StartPeakExtraction<6>(argc, argv); case 8: return StartPeakExtraction<8>(argc, argv); case 10: return StartPeakExtraction<10>(argc, argv); case 12: return StartPeakExtraction<12>(argc, argv); } return EXIT_FAILURE; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/FitFibersToImage.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/FitFibersToImage.cpp index c49dd60fb1..24917a8991 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/FitFibersToImage.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/FitFibersToImage.cpp @@ -1,450 +1,554 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef itksys::SystemTools ist; typedef itk::Image ItkUcharImgType; typedef std::tuple< ItkUcharImgType::Pointer, std::string > MaskType; typedef mitk::DiffusionPropertyHelper DPH; typedef itk::Point PointType; +typedef itk::Point PointType4; typedef mitk::StickModel<> ModelType; typedef mitk::BallModel<> BallModelType; +typedef itk::Image< float, 4 > PeakImgType; -std::vector SolveLinear(mitk::FiberBundle* inputTractogram, mitk::Image::Pointer inputImage, ModelType signalModel, BallModelType ) +vnl_vector_fixed GetCLosestPeak(itk::Index<4> idx, PeakImgType::Pointer peak_image , vnl_vector_fixed fiber_dir, bool flip_x, bool flip_y, bool flip_z ) { - unsigned int num_gradients = signalModel.GetGradientList().size(); - DPH::ImageType::Pointer itkImage = DPH::GetItkVectorImage(inputImage); + int m_NumDirs = peak_image->GetLargestPossibleRegion().GetSize()[3]/3; + vnl_vector_fixed out_dir; out_dir.fill(0); + float angle = 0.8; + + for (int i=0; i dir; + idx[3] = i*3; + dir[0] = peak_image->GetPixel(idx); + idx[3] += 1; + dir[1] = peak_image->GetPixel(idx); + idx[3] += 1; + dir[2] = peak_image->GetPixel(idx); + + float mag = dir.magnitude(); + if (magangle) + { + angle = fabs(a); + if (a<0) + out_dir = -dir; + else + out_dir = dir; + out_dir *= mag; + out_dir *= 1000; + } + } + + return out_dir; +} + +std::vector SolveLinear( std::string , std::vector< mitk::FiberBundle::Pointer > inputTractogram, mitk::Image::Pointer inputImage, bool flip_x=false, bool flip_y=false, bool flip_z=false ) +{ + typedef mitk::ImageToItk< PeakImgType > CasterType; + CasterType::Pointer caster = CasterType::New(); + caster->SetInput(inputImage); + caster->Update(); + PeakImgType::Pointer itkImage = caster->GetOutput(); unsigned int* image_size = inputImage->GetDimensions(); int sz_x = image_size[0]; int sz_y = image_size[1]; int sz_z = image_size[2]; int num_voxels = sz_x*sz_y*sz_z; - unsigned int num_unknowns = inputTractogram->GetNumFibers(); - unsigned int number_of_residuals = num_voxels * num_gradients; - + unsigned int num_unknowns = inputTractogram.size(); //inputTractogram->GetNumFibers(); + unsigned int number_of_residuals = num_voxels * 3; // create linear system MITK_INFO << "Num. unknowns: " << num_unknowns; MITK_INFO << "Num. residuals: " << number_of_residuals; - MITK_INFO << "Creating matrices ..."; - // Eigen::MatrixXf A = Eigen::MatrixXf::Constant(number_of_residuals, num_unknowns, 0); - // Eigen::VectorXf b = Eigen::VectorXf::Constant(number_of_residuals, 0); + vigra::MultiArray<2, double> test_m(vigra::Shape2(number_of_residuals, 1000000), 0.0); + MITK_INFO << test_m.height(); + MITK_INFO << "Creating matrices ..."; vigra::MultiArray<2, double> A(vigra::Shape2(number_of_residuals, num_unknowns), 0.0); vigra::MultiArray<2, double> b(vigra::Shape2(number_of_residuals, 1), 0.0); vigra::MultiArray<2, double> x(vigra::Shape2(num_unknowns, 1), 1.0); - - itk::Image< double, 3>::Pointer temp_img1 = itk::Image< double, 3>::New(); - temp_img1->SetSpacing( itkImage->GetSpacing() ); - temp_img1->SetOrigin( itkImage->GetOrigin() ); - temp_img1->SetDirection( itkImage->GetDirection() ); - temp_img1->SetLargestPossibleRegion( itkImage->GetLargestPossibleRegion() ); - temp_img1->SetBufferedRegion( itkImage->GetBufferedRegion() ); - temp_img1->SetRequestedRegion( itkImage->GetRequestedRegion() ); - temp_img1->Allocate(); - temp_img1->FillBuffer(0.0); - - itk::Image< double, 3>::Pointer temp_img2 = itk::Image< double, 3>::New(); - temp_img2->SetSpacing( itkImage->GetSpacing() ); - temp_img2->SetOrigin( itkImage->GetOrigin() ); - temp_img2->SetDirection( itkImage->GetDirection() ); - temp_img2->SetLargestPossibleRegion( itkImage->GetLargestPossibleRegion() ); - temp_img2->SetBufferedRegion( itkImage->GetBufferedRegion() ); - temp_img2->SetRequestedRegion( itkImage->GetRequestedRegion() ); - temp_img2->Allocate(); - temp_img2->FillBuffer(0.0); - MITK_INFO << "Filling matrices ..."; - unsigned int point_counter = 0; - vtkSmartPointer polydata = inputTractogram->GetFiberPolyData(); - for (int i=0; iGetNumFibers(); ++i) + for (unsigned int bundle=0; bundleGetCell(i); - int numPoints = cell->GetNumberOfPoints(); - vtkPoints* points = cell->GetPoints(); - - if (numPoints<2) - MITK_INFO << "FIBER WITH ONLY ONE POINT ENCOUNTERED!"; + vtkSmartPointer polydata = inputTractogram.at(bundle)->GetFiberPolyData(); - for (int j=0; jGetNumFibers(); ++i) { - double* p1 = points->GetPoint(j); - PointType p; - p[0]=p1[0]; - p[1]=p1[1]; - p[2]=p1[2]; + vtkCell* cell = polydata->GetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); - DPH::ImageType::IndexType idx; - itkImage->TransformPhysicalPointToIndex(p, idx); - if (!itkImage->GetLargestPossibleRegion().IsInside(idx)) - continue; - - double* p2 = points->GetPoint(j+1); - ModelType::GradientType d; - d[0] = p[0]-p2[0]; - d[1] = p[1]-p2[1]; - d[2] = p[2]-p2[2]; - signalModel.SetFiberDirection(d); - ModelType::PixelType model_signal = signalModel.SimulateMeasurement(); - DPH::ImageType::PixelType measured_signal = itkImage->GetPixel(idx); - - int x = idx[0]; - int y = idx[1]; - int z = idx[2]; + if (numPoints<2) + MITK_INFO << "FIBER WITH ONLY ONE POINT ENCOUNTERED!"; - unsigned int linear_index = x + sz_x*y + sz_x*sz_y*z; - - for (unsigned int k=0; kSetPixel(idx, temp_img1->GetPixel(idx) + (double)model_signal[k]); - A(num_gradients*linear_index + k, i) = temp_img1->GetPixel(idx); + double* p1 = points->GetPoint(j); + PointType4 p; + p[0]=p1[0]; + p[1]=p1[1]; + p[2]=p1[2]; + p[3]=0; + + itk::Index<4> idx4; + itkImage->TransformPhysicalPointToIndex(p, idx4); + if (!itkImage->GetLargestPossibleRegion().IsInside(idx4)) + continue; + + double* p2 = points->GetPoint(j+1); + vnl_vector_fixed fiber_dir; + fiber_dir[0] = p[0]-p2[0]; + fiber_dir[1] = p[1]-p2[1]; + fiber_dir[2] = p[2]-p2[2]; + fiber_dir.normalize(); + + vnl_vector_fixed odf_peak = GetCLosestPeak(idx4, itkImage, fiber_dir, flip_x, flip_y, flip_z); + if (odf_peak.magnitude()<0.001) + continue; + + int x = idx4[0]; + int y = idx4[1]; + int z = idx4[2]; + + unsigned int linear_index = x + sz_x*y + sz_x*sz_y*z; + + for (unsigned int k=0; k<3; ++k) + { + b(3*linear_index + k, 0) = (double)odf_peak[k]; + A(3*linear_index + k, bundle) = A(3*linear_index + k, bundle) + (double)fiber_dir[k]; + } -// temp_img2->SetPixel(idx, A(num_gradients*linear_index + k, i) ); } - - point_counter++; } } -// typedef itk::ImageFileWriter< itk::Image< double, 3> > WriterType; -// WriterType::Pointer writer = WriterType::New(); -// writer->SetFileName("/home/neher/Projects/TractPlausibility/model_signal.nrrd"); -// writer->SetInput(temp_img2); -// writer->Update(); - -// writer->SetFileName("/home/neher/Projects/TractPlausibility/measured_signal.nrrd"); -// writer->SetInput(temp_img1); -// writer->Update(); - MITK_INFO << "Solving linear system"; vigra::linalg::nonnegativeLeastSquares(A, b, x); std::vector weights; for (unsigned int i=0; i SolveEvo(mitk::FiberBundle* inputTractogram, mitk::Image::Pointer inputImage, ModelType signalModel, BallModelType ballModel, int num_iterations=1000, double step=0.1) +std::vector SolveEvo(mitk::FiberBundle* inputTractogram, mitk::Image::Pointer inputImage, ModelType signalModel, BallModelType ballModel, float start_weight, int num_iterations=1000) { std::vector out_weights; DPH::ImageType::Pointer itkImage = DPH::GetItkVectorImage(inputImage); itk::VectorImage< double, 3>::Pointer simulatedImage = itk::VectorImage< double, 3>::New(); simulatedImage->SetSpacing(itkImage->GetSpacing()); simulatedImage->SetOrigin(itkImage->GetOrigin()); simulatedImage->SetDirection(itkImage->GetDirection()); simulatedImage->SetRegions(itkImage->GetLargestPossibleRegion()); simulatedImage->SetVectorLength(itkImage->GetVectorLength()); simulatedImage->Allocate(); DPH::ImageType::PixelType zero_signal; zero_signal.SetSize(itkImage->GetVectorLength()); zero_signal.Fill(0); simulatedImage->FillBuffer(zero_signal); + MITK_INFO << "start_weight: " << start_weight; + double step = start_weight/10; + vtkSmartPointer polydata = inputTractogram->GetFiberPolyData(); + unsigned int* image_size = inputImage->GetDimensions(); + int sz_x = image_size[0]; + int sz_y = image_size[1]; + MITK_INFO << "INITIALIZING"; std::vector< std::vector< ModelType::PixelType > > fiber_model_signals; std::vector< std::vector< DPH::ImageType::IndexType > > fiber_image_indices; + std::map< unsigned int, std::vector > image_index_to_fiber_indices; std::vector< int > fiber_indices; int f = 0; for (int i=0; iGetNumFibers(); ++i) { vtkCell* cell = polydata->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // if (numPoints<2) // continue; std::vector< ModelType::PixelType > model_signals; std::vector< DPH::ImageType::IndexType > image_indices; for (int j=0; jGetPoint(j); PointType p; p[0]=p1[0]; p[1]=p1[1]; p[2]=p1[2]; DPH::ImageType::IndexType idx; itkImage->TransformPhysicalPointToIndex(p, idx); if (!itkImage->GetLargestPossibleRegion().IsInside(idx)) continue; double* p2 = points->GetPoint(j+1); ModelType::GradientType d; d[0] = p[0]-p2[0]; d[1] = p[1]-p2[1]; d[2] = p[2]-p2[2]; signalModel.SetFiberDirection(d); - model_signals.push_back(step*signalModel.SimulateMeasurement()); + ModelType::PixelType sig = signalModel.SimulateMeasurement(); + simulatedImage->SetPixel(idx, simulatedImage->GetPixel(idx) + start_weight * sig); + + model_signals.push_back(step*sig); image_indices.push_back(idx); + unsigned int linear_index = idx[0] + sz_x*idx[1] + sz_x*sz_y*idx[2]; + + if (image_index_to_fiber_indices.count(linear_index)==0) + { + image_index_to_fiber_indices[linear_index] = {i}; + } + else + { + std::vector< int > index_fiber_indices = image_index_to_fiber_indices[linear_index]; + if(std::find(index_fiber_indices.begin(), index_fiber_indices.end(), i) == index_fiber_indices.end()) + { + image_index_to_fiber_indices[linear_index].push_back(i); + } + } } fiber_model_signals.push_back(model_signals); fiber_image_indices.push_back(image_indices); fiber_indices.push_back(f); - out_weights.push_back(0); + out_weights.push_back(start_weight); ++f; } - BallModelType::PixelType ballSignal = step/10*ballModel.SimulateMeasurement(); + BallModelType::PixelType ballSignal = step*ballModel.SimulateMeasurement(); + + // SINGLE WEIGHT ONLY ANISO FIT + + + // FILL WITH ISO - double T_start = 0.0001; - double T_end = 0.000001; + // ACTUAL WEIGHT ADAPTATION + + double T_start = 0.01; + double T_end = 0.001; double alpha = log(T_end/T_start); unsigned int num_gradients = signalModel.GetGradientList().size(); for (int i=0; i model_signals = fiber_model_signals.at(f); std::vector< DPH::ImageType::IndexType > image_indices = fiber_image_indices.at(f); - double E_old = 0; - double E_new = 0; + double E_ext_old = 0; + double E_ext_new = 0; + double E_int_old = 0; + double E_int_new = 0; int add = std::rand()%2; // add = 1; int use_ball = std::rand()%2; + use_ball = 0; if (add==0 && use_ball==0 && out_weights[f]GetPixel(idx); - ModelType::PixelType sVal = simulatedImage->GetPixel(idx); - ModelType::PixelType dVal = model_signals.at(c); + DPH::ImageType::PixelType measured_val = itkImage->GetPixel(idx); + ModelType::PixelType simulated_val = simulatedImage->GetPixel(idx); + ModelType::PixelType model_val = model_signals.at(c); // value of fiber model at currnet fiber position if (use_ball==1) - dVal = ballSignal; + model_val = ballSignal; + // EXTERNAL ENERGY for (unsigned int g=0; g index_fiber_indices = image_index_to_fiber_indices[linear_index]; + + if (index_fiber_indices.size()>1) + { + float mean_weight = 0; + for (auto neighbor_index : index_fiber_indices) + { + if (neighbor_index!=f) + mean_weight += out_weights[neighbor_index]; + } + mean_weight /= (index_fiber_indices.size()-1); + + E_int_old += fabs(mean_weight-old_weight); + E_int_new += fabs(mean_weight-new_weight); + } } - E_old /= image_indices.size(); - E_new /= image_indices.size(); - double R = exp( (E_old-E_new)/T ); + E_ext_old /= image_indices.size(); + E_ext_new /= image_indices.size(); + E_int_old /= image_indices.size(); + E_int_new /= image_indices.size(); + +// MITK_INFO << "EXT: " << E_ext_old << " --> " << E_ext_new; +// MITK_INFO << "INT: " << E_int_old-E_int_new; + + double R = exp( (E_ext_old-E_ext_new)/T + 0*(E_int_old-E_int_new)/T ); +// MITK_INFO << R; -// if (E_new < E_old) float p = static_cast (rand()) / static_cast (RAND_MAX); + + p = E_ext_new; + R = E_ext_old; + + MITK_INFO << add << " - " << i; if (pGetPixel(idx); ModelType::PixelType dVal = model_signals.at(c); if (use_ball==1) dVal = ballSignal; if (add==1) + { sVal += dVal; + } else + { sVal -= dVal; + } simulatedImage->SetPixel(idx, sVal); - ++c; } - if (add==1 && use_ball==0) - out_weights[f] += step; - else if (use_ball==0) - out_weights[f] -= step; - + out_weights[f] = new_weight; } } - MITK_INFO << "Accepted: " << (float)accepted/fiber_indices.size(); +// MITK_INFO << "Accepted: " << (float)accepted/fiber_indices.size(); } typedef itk::ImageFileWriter< itk::VectorImage< double, 3> > WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetFileName("/home/neher/Projects/TractPlausibility/model_signal.nrrd"); writer->SetInput(simulatedImage); writer->Update(); return out_weights; } -/*! -\brief -*/ +std::vector< string > get_file_list(const std::string& path) +{ + std::vector< string > file_list; + + itk::Directory::Pointer dir = itk::Directory::New(); + + if (dir->Load(path.c_str())) + { + int n = dir->GetNumberOfFiles(); + for (int r = 0; r < n; r++) + { + const char *filename = dir->GetFile(r); + std::string ext = ist::GetFilenameExtension(filename); + if (ext==".fib" || ext==".trk") + file_list.push_back(path + '/' + filename); + } + } + + return file_list; +} + int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Fit Fibers To Image"); parser.setCategory("Fiber Tracking Evaluation"); parser.setDescription(""); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); - parser.addArgument("input_tractogram", "i1", mitkCommandLineParser::InputFile, "Input Tractogram:", "input tractogram (.fib, vtk ascii file format)", us::Any(), false); - parser.addArgument("input_dMRI", "i2", mitkCommandLineParser::InputFile, "Input dMRI:", "input diffusion-weighted image", us::Any(), false); + parser.addArgument("input_tractograms", "i1", mitkCommandLineParser::StringList, "Input tractograms:", "input tractograms (.fib, vtk ascii file format)", us::Any(), false); + parser.addArgument("input_peaks", "i2", mitkCommandLineParser::InputFile, "Input peaks:", "input peak image", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false); - parser.addArgument("step", "", mitkCommandLineParser::Float, "", "", us::Any()); - parser.addArgument("it", "", mitkCommandLineParser::Int, "", "", us::Any()); map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; - string fibFile = us::any_cast(parsedArgs["input_tractogram"]); - string dwiFile = us::any_cast(parsedArgs["input_dMRI"]); + mitkCommandLineParser::StringContainerType fib_files = us::any_cast(parsedArgs["input_tractograms"]); + string dwiFile = us::any_cast(parsedArgs["input_peaks"]); string outRoot = us::any_cast(parsedArgs["out"]); - int it = 1000; - if (parsedArgs.count("it")) - it = us::any_cast(parsedArgs["it"]); - - float step = 0.1; - if (parsedArgs.count("step")) - step = us::any_cast(parsedArgs["step"]); - - - - typedef DPH::GradientDirectionsContainerType GradientContainerType; - try { - mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::Load(fibFile)[0].GetPointer()); + std::vector< mitk::FiberBundle::Pointer > bundles; mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Diffusion Weighted Images", "Fiberbundles"}, {}); mitk::Image::Pointer inputImage = dynamic_cast(mitk::IOUtil::Load(dwiFile, &functor)[0].GetPointer()); - if (!DPH::IsDiffusionWeightedImage(inputImage)) - return EXIT_FAILURE; - // resample fibers float minSpacing = 1; if(inputImage->GetGeometry()->GetSpacing()[0]GetGeometry()->GetSpacing()[1] && inputImage->GetGeometry()->GetSpacing()[0]GetGeometry()->GetSpacing()[2]) minSpacing = inputImage->GetGeometry()->GetSpacing()[0]; else if (inputImage->GetGeometry()->GetSpacing()[1] < inputImage->GetGeometry()->GetSpacing()[2]) minSpacing = inputImage->GetGeometry()->GetSpacing()[1]; else minSpacing = inputImage->GetGeometry()->GetSpacing()[2]; - inputTractogram->ResampleLinear(minSpacing/10); - - // set up signal model - GradientContainerType* gradients = static_cast( inputImage->GetProperty(DPH::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(); - - float b_value = 0; - inputImage->GetPropertyList()->GetFloatProperty(DPH::REFERENCEBVALUEPROPERTYNAME.c_str(), b_value); - ModelType signalModel; - signalModel.SetDiffusivity(0.001); - signalModel.SetBvalue(b_value); - signalModel.SetGradientList(gradients); - - BallModelType ballModel; - ballModel.SetDiffusivity(0.001); - ballModel.SetBvalue(b_value); - ballModel.SetGradientList(gradients); + std::vector< std::string > fib_names; + for (auto item : fib_files) + { + if ( ist::FileIsDirectory(item) ) + { + for ( auto fibFile : get_file_list(item) ) + { + mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::Load(fibFile)[0].GetPointer()); + if (inputTractogram.IsNull()) + continue; + inputTractogram->ResampleLinear(minSpacing/4); + bundles.push_back(inputTractogram); + fib_names.push_back(fibFile); + } + } + else + { + mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::Load(item)[0].GetPointer()); + if (inputTractogram.IsNull()) + continue; + inputTractogram->ResampleLinear(minSpacing/4); + bundles.push_back(inputTractogram); + fib_names.push_back(item); + } + } -// MITK_INFO << it << " " << step; -// std::vector weights = SolveLinear(inputTractogram, inputImage, signalModel, ballModel); - std::vector weights = SolveEvo(inputTractogram, inputImage, signalModel, ballModel, it, step); + std::vector weights = SolveLinear(outRoot, bundles, inputImage); - for (unsigned int i=0; iSetFiberWeight(i, weights.at(i)); + std::string name = fib_names.at(i); + name = ist::GetFilenameWithoutExtension(name); + MITK_INFO << name << ": " << weights.at(i); + mitk::FiberBundle::Pointer bundle = bundles.at(i); +// inputTractogram->SetFiberWeight(i, weights.at(i)); + bundle->SetFiberWeights(weights.at(i)); + mitk::IOUtil::Save(bundle, outRoot + name + "_fitted.fib"); } - - mitk::IOUtil::Save(inputTractogram, outRoot + "fitted.fib"); } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp index 7a1cb9b24d..4e5689337f 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp @@ -1,1197 +1,1206 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkDataManagerView.h" //# Own Includes //## mitk #include "mitkDataStorageEditorInput.h" #include "mitkIDataStorageReference.h" #include "mitkNodePredicateDataType.h" #include "mitkCoreObjectFactory.h" #include "mitkColorProperty.h" #include "mitkCommon.h" #include "mitkNodePredicateData.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateOr.h" #include "mitkNodePredicateProperty.h" #include "mitkEnumerationProperty.h" #include "mitkLookupTableProperty.h" #include "mitkProperties.h" #include #include #include #include #include //## Qmitk #include #include #include #include #include #include #include #include "src/internal/QmitkNodeTableViewKeyFilter.h" #include "src/internal/QmitkInfoDialog.h" #include "src/internal/QmitkDataManagerItemDelegate.h" //## Berry #include #include #include #include #include #include #include #include //# Toolkit Includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkDataNodeObject.h" #include "mitkIContextMenuAction.h" #include "berryIExtensionRegistry.h" #include "mitkRenderingModeProperty.h" const QString QmitkDataManagerView::VIEW_ID = "org.mitk.views.datamanager"; QmitkDataManagerView::QmitkDataManagerView() : m_GlobalReinitOnNodeDelete(true), m_ItemDelegate(nullptr) { } QmitkDataManagerView::~QmitkDataManagerView() { //Remove all registered actions from each descriptor for (std::vector< std::pair< QmitkNodeDescriptor*, QAction* > >::iterator it = m_DescriptorActionList.begin();it != m_DescriptorActionList.end(); it++) { // first== the NodeDescriptor; second== the registered QAction (it->first)->RemoveAction(it->second); } } void QmitkDataManagerView::CreateQtPartControl(QWidget* parent) { m_CurrentRowCount = 0; m_Parent = parent; //# Preferences berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node(VIEW_ID)) .Cast(); assert( prefs ); prefs->OnChanged.AddListener( berry::MessageDelegate1( this , &QmitkDataManagerView::OnPreferencesChanged ) ); //# GUI m_NodeTreeModel = new QmitkDataStorageTreeModel(this->GetDataStorage()); m_NodeTreeModel->setParent( parent ); m_NodeTreeModel->SetPlaceNewNodesOnTop( prefs->GetBool("Place new nodes on top", true) ); m_NodeTreeModel->SetAllowHierarchyChange( prefs->GetBool("Allow changing of parent node", false)); m_SurfaceDecimation = prefs->GetBool("Use surface decimation", false); // Prepare filters m_HelperObjectFilterPredicate = mitk::NodePredicateOr::New( mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)), mitk::NodePredicateProperty::New("hidden object", mitk::BoolProperty::New(true))); m_NodeWithNoDataFilterPredicate = mitk::NodePredicateData::New(0); m_FilterModel = new QmitkDataStorageFilterProxyModel(); m_FilterModel->setSourceModel(m_NodeTreeModel); m_FilterModel->AddFilterPredicate(m_HelperObjectFilterPredicate); m_FilterModel->AddFilterPredicate(m_NodeWithNoDataFilterPredicate); //# Tree View (experimental) m_NodeTreeView = new QTreeView; m_NodeTreeView->setHeaderHidden(true); m_NodeTreeView->setSelectionMode( QAbstractItemView::ExtendedSelection ); m_NodeTreeView->setSelectionBehavior( QAbstractItemView::SelectRows ); m_NodeTreeView->setAlternatingRowColors(true); m_NodeTreeView->setDragEnabled(true); m_NodeTreeView->setDropIndicatorShown(true); m_NodeTreeView->setAcceptDrops(true); m_NodeTreeView->setContextMenuPolicy(Qt::CustomContextMenu); m_NodeTreeView->setModel(m_FilterModel); m_NodeTreeView->setTextElideMode(Qt::ElideMiddle); m_NodeTreeView->installEventFilter(new QmitkNodeTableViewKeyFilter(this)); m_ItemDelegate = new QmitkDataManagerItemDelegate(m_NodeTreeView); m_NodeTreeView->setItemDelegate(m_ItemDelegate); QObject::connect( m_NodeTreeView, SIGNAL(customContextMenuRequested(const QPoint&)) , this, SLOT(NodeTableViewContextMenuRequested(const QPoint&)) ); QObject::connect( m_NodeTreeModel, SIGNAL(rowsInserted (const QModelIndex&, int, int)) , this, SLOT(NodeTreeViewRowsInserted ( const QModelIndex&, int, int )) ); QObject::connect( m_NodeTreeModel, SIGNAL(rowsRemoved (const QModelIndex&, int, int)) , this, SLOT(NodeTreeViewRowsRemoved( const QModelIndex&, int, int )) ); QObject::connect( m_NodeTreeView->selectionModel() , SIGNAL( selectionChanged ( const QItemSelection &, const QItemSelection & ) ) , this , SLOT( NodeSelectionChanged ( const QItemSelection &, const QItemSelection & ) ) ); //# m_NodeMenu m_NodeMenu = new QMenu(m_NodeTreeView); // # Actions berry::IEditorRegistry* editorRegistry = berry::PlatformUI::GetWorkbench()->GetEditorRegistry(); QList editors = editorRegistry->GetEditors("*.mitk"); if (editors.size() > 1) { m_ShowInMapper = new QSignalMapper(this); foreach(berry::IEditorDescriptor::Pointer descriptor, editors) { QAction* action = new QAction(descriptor->GetLabel(), this); m_ShowInActions << action; m_ShowInMapper->connect(action, SIGNAL(triggered()), m_ShowInMapper, SLOT(map())); m_ShowInMapper->setMapping(action, descriptor->GetId()); } connect(m_ShowInMapper, SIGNAL(mapped(QString)), this, SLOT(ShowIn(QString))); } auto unknownDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetUnknownDataNodeDescriptor(); auto imageDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("Image"); auto multiComponentImageDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("MultiComponentImage"); auto diffusionImageDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("DiffusionImage"); auto fiberBundleDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("FiberBundle"); + auto peakImageDataNodeDescriptor = + QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PeakImage"); + auto surfaceDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("Surface"); auto pointSetNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PointSet"); auto planarLineNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarLine"); auto planarCircleNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarCircle"); auto planarEllipseNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarEllipse"); auto planarAngleNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarAngle"); auto planarFourPointAngleNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarFourPointAngle"); auto planarRectangleNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarRectangle"); auto planarPolygonNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarPolygon"); auto planarPathNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarPath"); auto planarDoubleEllipseNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarDoubleEllipse"); auto planarBezierCurveNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarBezierCurve"); auto planarSubdivisionPolygonNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("PlanarSubdivisionPolygon"); QAction* globalReinitAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Refresh_48.png"), tr("Global Reinit"), this); QObject::connect( globalReinitAction, SIGNAL( triggered(bool) ) , this, SLOT( GlobalReinit(bool) ) ); unknownDataNodeDescriptor->AddAction(globalReinitAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor, globalReinitAction)); QAction* saveAction = new QmitkFileSaveAction(QIcon(":/org.mitk.gui.qt.datamanager/Save_48.png"), this->GetSite()->GetWorkbenchWindow()); unknownDataNodeDescriptor->AddAction(saveAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,saveAction)); QAction* removeAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Remove_48.png"), tr("Remove"), this); QObject::connect( removeAction, SIGNAL( triggered(bool) ) , this, SLOT( RemoveSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(removeAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,removeAction)); QAction* reinitAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Refresh_48.png"), tr("Reinit"), this); QObject::connect( reinitAction, SIGNAL( triggered(bool) ) , this, SLOT( ReinitSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(reinitAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,reinitAction)); // find contextMenuAction extension points and add them to the node descriptor berry::IExtensionRegistry* extensionPointService = berry::Platform::GetExtensionRegistry(); QList customMenuConfigs = extensionPointService->GetConfigurationElementsFor("org.mitk.gui.qt.datamanager.contextMenuActions"); // Prepare all custom QActions m_ConfElements.clear(); DescriptorActionListType customMenuEntries; for (auto& customMenuConfig : customMenuConfigs) { QString actionNodeDescriptorName = customMenuConfig->GetAttribute("nodeDescriptorName"); QString actionLabel = customMenuConfig->GetAttribute("label"); QString actionClass = customMenuConfig->GetAttribute("class"); if (actionNodeDescriptorName.isEmpty() || actionLabel.isEmpty() || actionClass.isEmpty()) { continue; } QString actionIconName = customMenuConfig->GetAttribute("icon"); // Find matching descriptor auto nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(actionNodeDescriptorName); if ( nodeDescriptor == nullptr) { MITK_WARN << "Cannot add action \"" << actionLabel << "\" because descriptor " << actionNodeDescriptorName << " does not exist."; continue; } // Create action with or without icon QAction* contextMenuAction; if ( !actionIconName.isEmpty() ) { QIcon actionIcon; if ( QFile::exists(actionIconName) ) { actionIcon = QIcon(actionIconName); } else { actionIcon = berry::AbstractUICTKPlugin::ImageDescriptorFromPlugin( customMenuConfig->GetContributor()->GetName(), actionIconName); } contextMenuAction = new QAction(actionIcon, actionLabel, parent); } else { contextMenuAction = new QAction(actionLabel, parent); } // Define menu handler to trigger on click connect(contextMenuAction, static_cast(&QAction::triggered), this, &QmitkDataManagerView::ContextMenuActionTriggered); // Mark configuration element into lookup list for context menu handler m_ConfElements[contextMenuAction] = customMenuConfig; // Mark new action in sortable list for addition to descriptor customMenuEntries.emplace_back(nodeDescriptor, contextMenuAction); } // Sort all custom QActions by their texts { using ListEntryType = std::pair; std::sort(customMenuEntries.begin(), customMenuEntries.end(), [](const ListEntryType& left, const ListEntryType& right) -> bool { assert (left.second != nullptr && right.second != nullptr); // unless we messed up above return left.second->text() < right.second->text(); }); } // Add custom QActions in sorted order int globalAddedMenuIndex=1; for (auto& menuEntryToAdd : customMenuEntries) { auto& nodeDescriptor = menuEntryToAdd.first; auto& contextMenuAction = menuEntryToAdd.second; // TODO is the action "data" used by anything? Otherwise remove! contextMenuAction->setData(static_cast(globalAddedMenuIndex)); ++globalAddedMenuIndex; // Really add this action to that descriptor (in pre-defined order) nodeDescriptor->AddAction(contextMenuAction); // Mark new action into list of descriptors to remove in d'tor m_DescriptorActionList.push_back(menuEntryToAdd); } m_OpacitySlider = new QSlider; m_OpacitySlider->setMinimum(0); m_OpacitySlider->setMaximum(100); m_OpacitySlider->setOrientation(Qt::Horizontal); QObject::connect( m_OpacitySlider, SIGNAL( valueChanged(int) ) , this, SLOT( OpacityChanged(int) ) ); QLabel* _OpacityLabel = new QLabel(tr("Opacity: ")); QHBoxLayout* _OpacityWidgetLayout = new QHBoxLayout; _OpacityWidgetLayout->setContentsMargins(4,4,4,4); _OpacityWidgetLayout->addWidget(_OpacityLabel); _OpacityWidgetLayout->addWidget(m_OpacitySlider); QWidget* _OpacityWidget = new QWidget; _OpacityWidget->setLayout(_OpacityWidgetLayout); QWidgetAction* opacityAction = new QWidgetAction(this); opacityAction ->setDefaultWidget(_OpacityWidget); QObject::connect( opacityAction , SIGNAL( changed() ) , this, SLOT( OpacityActionChanged() ) ); unknownDataNodeDescriptor->AddAction(opacityAction , false); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,opacityAction)); m_ColorButton = new QPushButton; m_ColorButton->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Minimum); //m_ColorButton->setText("Change color"); QObject::connect( m_ColorButton, SIGNAL( clicked() ) , this, SLOT( ColorChanged() ) ); QLabel* _ColorLabel = new QLabel(tr("Color: ")); _ColorLabel->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum); QHBoxLayout* _ColorWidgetLayout = new QHBoxLayout; _ColorWidgetLayout->setContentsMargins(4,4,4,4); _ColorWidgetLayout->addWidget(_ColorLabel); _ColorWidgetLayout->addWidget(m_ColorButton); QWidget* _ColorWidget = new QWidget; _ColorWidget->setLayout(_ColorWidgetLayout); QWidgetAction* colorAction = new QWidgetAction(this); colorAction->setDefaultWidget(_ColorWidget); QObject::connect( colorAction, SIGNAL( changed() ) , this, SLOT( ColorActionChanged() ) ); { // only give the color context menu option where appropriate bool colorActionCanBatch = true; if (imageDataNodeDescriptor != nullptr) { imageDataNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(imageDataNodeDescriptor, colorAction)); } if (multiComponentImageDataNodeDescriptor != nullptr) { multiComponentImageDataNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(multiComponentImageDataNodeDescriptor, colorAction)); } if (diffusionImageDataNodeDescriptor != nullptr) { diffusionImageDataNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(diffusionImageDataNodeDescriptor, colorAction)); } if (fiberBundleDataNodeDescriptor != nullptr) { fiberBundleDataNodeDescriptor->AddAction(colorAction, false); m_DescriptorActionList.push_back( std::pair(fiberBundleDataNodeDescriptor, colorAction)); } + if (peakImageDataNodeDescriptor != nullptr) + { + peakImageDataNodeDescriptor->AddAction(colorAction, false); + m_DescriptorActionList.push_back( + std::pair(peakImageDataNodeDescriptor, colorAction)); + } if (surfaceDataNodeDescriptor != nullptr) { surfaceDataNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(surfaceDataNodeDescriptor, colorAction)); } if (pointSetNodeDescriptor != nullptr) { pointSetNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(pointSetNodeDescriptor, colorAction)); } if (planarLineNodeDescriptor != nullptr) { planarLineNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(planarLineNodeDescriptor, colorAction)); } if (planarCircleNodeDescriptor != nullptr) { planarCircleNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(planarCircleNodeDescriptor, colorAction)); } if (planarEllipseNodeDescriptor != nullptr) { planarEllipseNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(planarEllipseNodeDescriptor, colorAction)); } if (planarAngleNodeDescriptor != nullptr) { planarAngleNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(planarAngleNodeDescriptor, colorAction)); } if (planarFourPointAngleNodeDescriptor != nullptr) { planarFourPointAngleNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(planarFourPointAngleNodeDescriptor, colorAction)); } if (planarRectangleNodeDescriptor != nullptr) { planarRectangleNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(planarRectangleNodeDescriptor, colorAction)); } if (planarPolygonNodeDescriptor != nullptr) { planarPolygonNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(planarPolygonNodeDescriptor, colorAction)); } if (planarPathNodeDescriptor != nullptr) { planarPathNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(planarPathNodeDescriptor, colorAction)); } if (planarDoubleEllipseNodeDescriptor != nullptr) { planarDoubleEllipseNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(planarDoubleEllipseNodeDescriptor, colorAction)); } if (planarBezierCurveNodeDescriptor != nullptr) { planarBezierCurveNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(planarBezierCurveNodeDescriptor, colorAction)); } if (planarSubdivisionPolygonNodeDescriptor != nullptr) { planarSubdivisionPolygonNodeDescriptor->AddAction(colorAction, colorActionCanBatch); m_DescriptorActionList.push_back( std::pair(planarSubdivisionPolygonNodeDescriptor, colorAction)); } } m_ComponentSlider = new QmitkNumberPropertySlider; m_ComponentSlider->setOrientation(Qt::Horizontal); //QObject::connect( m_OpacitySlider, SIGNAL( valueChanged(int) ) // , this, SLOT( OpacityChanged(int) ) ); QLabel* _ComponentLabel = new QLabel(tr("Component: ")); QHBoxLayout* _ComponentWidgetLayout = new QHBoxLayout; _ComponentWidgetLayout->setContentsMargins(4,4,4,4); _ComponentWidgetLayout->addWidget(_ComponentLabel); _ComponentWidgetLayout->addWidget(m_ComponentSlider); QLabel* _ComponentValueLabel = new QLabel(); _ComponentWidgetLayout->addWidget(_ComponentValueLabel); connect(m_ComponentSlider, SIGNAL(valueChanged(int)), _ComponentValueLabel, SLOT(setNum(int))); QWidget* _ComponentWidget = new QWidget; _ComponentWidget->setLayout(_ComponentWidgetLayout); QWidgetAction* componentAction = new QWidgetAction(this); componentAction->setDefaultWidget(_ComponentWidget); QObject::connect( componentAction , SIGNAL( changed() ) , this, SLOT( ComponentActionChanged() ) ); multiComponentImageDataNodeDescriptor->AddAction(componentAction, false); m_DescriptorActionList.push_back(std::pair(multiComponentImageDataNodeDescriptor,componentAction)); if (diffusionImageDataNodeDescriptor!=nullptr) { diffusionImageDataNodeDescriptor->AddAction(componentAction, false); m_DescriptorActionList.push_back(std::pair(diffusionImageDataNodeDescriptor,componentAction)); } m_TextureInterpolation = new QAction(tr("Texture Interpolation"), this); m_TextureInterpolation->setCheckable ( true ); QObject::connect( m_TextureInterpolation, SIGNAL( changed() ) , this, SLOT( TextureInterpolationChanged() ) ); QObject::connect( m_TextureInterpolation, SIGNAL( toggled(bool) ) , this, SLOT( TextureInterpolationToggled(bool) ) ); imageDataNodeDescriptor->AddAction(m_TextureInterpolation, false); m_DescriptorActionList.push_back(std::pair(imageDataNodeDescriptor,m_TextureInterpolation)); if (diffusionImageDataNodeDescriptor!=nullptr) { diffusionImageDataNodeDescriptor->AddAction(m_TextureInterpolation, false); m_DescriptorActionList.push_back(std::pair(diffusionImageDataNodeDescriptor,m_TextureInterpolation)); } m_ColormapAction = new QAction(tr("Colormap"), this); m_ColormapAction->setMenu(new QMenu); QObject::connect( m_ColormapAction->menu(), SIGNAL( aboutToShow() ) , this, SLOT( ColormapMenuAboutToShow() ) ); imageDataNodeDescriptor->AddAction(m_ColormapAction, false); m_DescriptorActionList.push_back(std::pair(imageDataNodeDescriptor, m_ColormapAction)); if (diffusionImageDataNodeDescriptor!=nullptr) { diffusionImageDataNodeDescriptor->AddAction(m_ColormapAction, false); m_DescriptorActionList.push_back(std::pair(diffusionImageDataNodeDescriptor, m_ColormapAction)); } m_SurfaceRepresentation = new QAction(tr("Surface Representation"), this); m_SurfaceRepresentation->setMenu(new QMenu(m_NodeTreeView)); QObject::connect( m_SurfaceRepresentation->menu(), SIGNAL( aboutToShow() ) , this, SLOT( SurfaceRepresentationMenuAboutToShow() ) ); surfaceDataNodeDescriptor->AddAction(m_SurfaceRepresentation, false); m_DescriptorActionList.push_back(std::pair(surfaceDataNodeDescriptor, m_SurfaceRepresentation)); QAction* showOnlySelectedNodes = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/ShowSelectedNode_48.png") , tr("Show only selected nodes"), this); QObject::connect( showOnlySelectedNodes, SIGNAL( triggered(bool) ) , this, SLOT( ShowOnlySelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(showOnlySelectedNodes); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor, showOnlySelectedNodes)); QAction* toggleSelectedVisibility = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/InvertShowSelectedNode_48.png") , tr("Toggle visibility"), this); QObject::connect( toggleSelectedVisibility, SIGNAL( triggered(bool) ) , this, SLOT( ToggleVisibilityOfSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(toggleSelectedVisibility); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,toggleSelectedVisibility)); QAction* actionShowInfoDialog = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/ShowDataInfo_48.png") , tr("Details..."), this); QObject::connect( actionShowInfoDialog, SIGNAL( triggered(bool) ) , this, SLOT( ShowInfoDialogForSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(actionShowInfoDialog); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,actionShowInfoDialog)); QGridLayout* _DndFrameWidgetLayout = new QGridLayout; _DndFrameWidgetLayout->addWidget(m_NodeTreeView, 0, 0); _DndFrameWidgetLayout->setContentsMargins(0,0,0,0); m_DndFrameWidget = new QmitkDnDFrameWidget(m_Parent); m_DndFrameWidget->setLayout(_DndFrameWidgetLayout); QVBoxLayout* layout = new QVBoxLayout(parent); layout->addWidget(m_DndFrameWidget); layout->setContentsMargins(0,0,0,0); m_Parent->setLayout(layout); } void QmitkDataManagerView::SetFocus() { } void QmitkDataManagerView::ContextMenuActionTriggered( bool ) { QAction* action = qobject_cast ( sender() ); std::map::iterator it = m_ConfElements.find( action ); if( it == m_ConfElements.end() ) { MITK_WARN << "associated conf element for action " << action->text().toStdString() << " not found"; return; } berry::IConfigurationElement::Pointer confElem = it->second; mitk::IContextMenuAction* contextMenuAction = confElem->CreateExecutableExtension("class"); QString className = confElem->GetAttribute("class"); QString smoothed = confElem->GetAttribute("smoothed"); contextMenuAction->SetDataStorage(this->GetDataStorage()); if(className == "QmitkCreatePolygonModelAction") { if(smoothed == "false") { contextMenuAction->SetSmoothed(false); } else { contextMenuAction->SetSmoothed(true); } contextMenuAction->SetDecimated(m_SurfaceDecimation); } else if(className == "QmitkStatisticsAction") { contextMenuAction->SetFunctionality(this); } contextMenuAction->Run( this->GetCurrentSelection() ); // run the action } void QmitkDataManagerView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if( m_NodeTreeModel->GetPlaceNewNodesOnTopFlag() != prefs->GetBool("Place new nodes on top", true) ) m_NodeTreeModel->SetPlaceNewNodesOnTop( !m_NodeTreeModel->GetPlaceNewNodesOnTopFlag() ); bool hideHelperObjects = !prefs->GetBool("Show helper objects", false); if (m_FilterModel->HasFilterPredicate(m_HelperObjectFilterPredicate) != hideHelperObjects) { if (hideHelperObjects) { m_FilterModel->AddFilterPredicate(m_HelperObjectFilterPredicate); } else { m_FilterModel->RemoveFilterPredicate(m_HelperObjectFilterPredicate); } } bool hideNodesWithNoData = !prefs->GetBool("Show nodes containing no data", false); if (m_FilterModel->HasFilterPredicate(m_NodeWithNoDataFilterPredicate) != hideNodesWithNoData) { if (hideNodesWithNoData) { m_FilterModel->AddFilterPredicate(m_NodeWithNoDataFilterPredicate); } else { m_FilterModel->RemoveFilterPredicate(m_NodeWithNoDataFilterPredicate); } } m_GlobalReinitOnNodeDelete = prefs->GetBool("Call global reinit if node is deleted", true); m_NodeTreeView->expandAll(); m_SurfaceDecimation = prefs->GetBool("Use surface decimation", false); m_NodeTreeModel->SetAllowHierarchyChange( prefs->GetBool("Allow changing of parent node", false)); this->GlobalReinit(); } void QmitkDataManagerView::NodeTableViewContextMenuRequested( const QPoint & pos ) { QModelIndex selectedProxy = m_NodeTreeView->indexAt ( pos ); QModelIndex selected = m_FilterModel->mapToSource(selectedProxy); mitk::DataNode::Pointer node = m_NodeTreeModel->GetNode(selected); QList selectedNodes = this->GetCurrentSelection(); if(!selectedNodes.isEmpty()) { ColorActionChanged(); // update color button m_NodeMenu->clear(); QList actions; if(selectedNodes.size() == 1 ) { actions = QmitkNodeDescriptorManager::GetInstance()->GetActions(node); for(QList::iterator it = actions.begin(); it != actions.end(); ++it) { (*it)->setData(QVariant::fromValue(node.GetPointer())); } } else actions = QmitkNodeDescriptorManager::GetInstance()->GetActions(selectedNodes); if (!m_ShowInActions.isEmpty()) { QMenu* showInMenu = m_NodeMenu->addMenu(tr("Show In")); showInMenu->addActions(m_ShowInActions); } m_NodeMenu->addActions(actions); m_NodeMenu->popup(QCursor::pos()); } } void QmitkDataManagerView::OpacityChanged(int value) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(node) { float opacity = static_cast(value)/100.0f; node->SetFloatProperty("opacity", opacity); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkDataManagerView::OpacityActionChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(node) { float opacity = 0.0; if(node->GetFloatProperty("opacity", opacity)) { m_OpacitySlider->setValue(static_cast(opacity*100)); } } } void QmitkDataManagerView::ComponentActionChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); mitk::IntProperty* componentProperty = nullptr; int numComponents = 0; if(node) { componentProperty = dynamic_cast(node->GetProperty("Image.Displayed Component")); mitk::Image* img = dynamic_cast(node->GetData()); if (img != nullptr) { numComponents = img->GetPixelType().GetNumberOfComponents(); } } if (componentProperty && numComponents > 1) { m_ComponentSlider->SetProperty(componentProperty); m_ComponentSlider->setMinValue(0); m_ComponentSlider->setMaxValue(numComponents-1); } else { m_ComponentSlider->SetProperty(static_cast(nullptr)); } } void QmitkDataManagerView::ColorChanged() { bool color_selected = false; QColor newColor; auto selected_indices = m_NodeTreeView->selectionModel()->selectedIndexes(); for (auto& selected_index : selected_indices) { auto node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(selected_index)); if(node) { float rgb[3]; if (node->GetColor(rgb)) { if (!color_selected) { QColor initial(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255); newColor = QColorDialog::getColor(initial, 0, QString(tr("Change color"))); if ( newColor.isValid() ) { color_selected = true; } else { return; } } node->SetProperty("color", mitk::ColorProperty::New(newColor.redF(), newColor.greenF(), newColor.blueF())); if ( node->GetProperty("binaryimage.selectedcolor") ) { node->SetProperty("binaryimage.selectedcolor", mitk::ColorProperty::New(newColor.redF(), newColor.greenF(), newColor.blueF())); } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ColorActionChanged() { // Adapts color displayed in context menu item auto selected_indices = m_NodeTreeView->selectionModel()->selectedIndexes(); if (selected_indices.isEmpty()) return; mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(selected_indices.front())); if(node) { float rgb[3]; if (node->GetColor(rgb)) { QColor color(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255); QString styleSheet = QString("background-color: ") + color.name(QColor::HexRgb); m_ColorButton->setAutoFillBackground(true); m_ColorButton->setStyleSheet(styleSheet); } } } void QmitkDataManagerView::TextureInterpolationChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(node) { bool textureInterpolation = false; node->GetBoolProperty("texture interpolation", textureInterpolation); m_TextureInterpolation->setChecked(textureInterpolation); } } void QmitkDataManagerView::TextureInterpolationToggled( bool checked ) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(node) { node->SetBoolProperty("texture interpolation", checked); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkDataManagerView::ColormapActionToggled( bool /*checked*/ ) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(!node) return; mitk::LookupTableProperty::Pointer lookupTableProperty = dynamic_cast(node->GetProperty("LookupTable")); if (!lookupTableProperty) return; QAction* senderAction = qobject_cast(QObject::sender()); if(!senderAction) return; std::string activatedItem = senderAction->text().toStdString(); mitk::LookupTable::Pointer lookupTable = lookupTableProperty->GetValue(); if (!lookupTable) return; lookupTable->SetType(activatedItem); lookupTableProperty->SetValue(lookupTable); mitk::RenderingModeProperty::Pointer renderingMode = dynamic_cast(node->GetProperty("Image Rendering.Mode")); renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ColormapMenuAboutToShow() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(!node) return; mitk::LookupTableProperty::Pointer lookupTableProperty = dynamic_cast(node->GetProperty("LookupTable")); if (!lookupTableProperty) { mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); lookupTableProperty = mitk::LookupTableProperty::New(); lookupTableProperty->SetLookupTable(mitkLut); node->SetProperty("LookupTable", lookupTableProperty); } mitk::LookupTable::Pointer lookupTable = lookupTableProperty->GetValue(); if (!lookupTable) return; m_ColormapAction->menu()->clear(); QAction* tmp; int i = 0; std::string lutType = lookupTable->typenameList[i]; while (lutType != "END_OF_ARRAY") { tmp = m_ColormapAction->menu()->addAction(QString::fromStdString(lutType)); tmp->setCheckable(true); if (lutType == lookupTable->GetActiveTypeAsString()) { tmp->setChecked(true); } QObject::connect(tmp, SIGNAL(triggered(bool)), this, SLOT(ColormapActionToggled(bool))); lutType = lookupTable->typenameList[++i]; } } void QmitkDataManagerView::SurfaceRepresentationMenuAboutToShow() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(!node) return; mitk::EnumerationProperty* representationProp = dynamic_cast (node->GetProperty("material.representation")); if(!representationProp) return; // clear menu m_SurfaceRepresentation->menu()->clear(); QAction* tmp; // create menu entries for(mitk::EnumerationProperty::EnumConstIterator it=representationProp->Begin(); it!=representationProp->End() ; it++) { tmp = m_SurfaceRepresentation->menu()->addAction(QString::fromStdString(it->second)); tmp->setCheckable(true); if(it->second == representationProp->GetValueAsString()) { tmp->setChecked(true); } QObject::connect( tmp, SIGNAL( triggered(bool) ) , this, SLOT( SurfaceRepresentationActionToggled(bool) ) ); } } void QmitkDataManagerView::SurfaceRepresentationActionToggled( bool /*checked*/ ) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_FilterModel->mapToSource(m_NodeTreeView->selectionModel()->currentIndex())); if(!node) return; mitk::EnumerationProperty* representationProp = dynamic_cast (node->GetProperty("material.representation")); if(!representationProp) return; QAction* senderAction = qobject_cast ( QObject::sender() ); if(!senderAction) return; std::string activatedItem = senderAction->text().toStdString(); if ( activatedItem != representationProp->GetValueAsString() ) { if ( representationProp->IsValidEnumerationValue( activatedItem ) ) { representationProp->SetValue( activatedItem ); representationProp->InvokeEvent( itk::ModifiedEvent() ); representationProp->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } void QmitkDataManagerView::ReinitSelectedNodes( bool ) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow == nullptr) renderWindow = this->OpenRenderWindowPart(false); QList selectedNodes = this->GetCurrentSelection(); foreach(mitk::DataNode::Pointer node, selectedNodes) { mitk::BaseData::Pointer basedata = node->GetData(); if ( basedata.IsNotNull() && basedata->GetTimeGeometry()->IsValid() ) { renderWindow->GetRenderingManager()->InitializeViews( basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); } } } void QmitkDataManagerView::RemoveSelectedNodes( bool ) { QModelIndexList indexesOfSelectedRowsFiltered = m_NodeTreeView->selectionModel()->selectedRows(); QModelIndexList indexesOfSelectedRows; for (int i = 0; i < indexesOfSelectedRowsFiltered.size(); ++i) { indexesOfSelectedRows.push_back(m_FilterModel->mapToSource(indexesOfSelectedRowsFiltered[i])); } if(indexesOfSelectedRows.size() < 1) { return; } std::vector selectedNodes; mitk::DataNode::Pointer node = 0; QString question = tr("Do you really want to remove "); for (QModelIndexList::iterator it = indexesOfSelectedRows.begin() ; it != indexesOfSelectedRows.end(); it++) { node = m_NodeTreeModel->GetNode(*it); // if node is not defined or if the node contains geometry data do not remove it if ( node.IsNotNull() /*& strcmp(node->GetData()->GetNameOfClass(), "PlaneGeometryData") != 0*/ ) { selectedNodes.push_back(node); question.append(QString::fromStdString(node->GetName())); question.append(", "); } } // remove the last two characters = ", " question = question.remove(question.size()-2, 2); question.append(tr(" from data storage?")); QMessageBox::StandardButton answerButton = QMessageBox::question( m_Parent , tr("DataManager") , question , QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if(answerButton == QMessageBox::Yes) { for (std::vector::iterator it = selectedNodes.begin() ; it != selectedNodes.end(); it++) { node = *it; this->GetDataStorage()->Remove(node); if (m_GlobalReinitOnNodeDelete) this->GlobalReinit(false); } } } void QmitkDataManagerView::MakeAllNodesInvisible( bool ) { QList nodes = m_NodeTreeModel->GetNodeSet(); foreach(mitk::DataNode::Pointer node, nodes) { node->SetVisibility(false); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ShowOnlySelectedNodes( bool ) { QList selectedNodes = this->GetCurrentSelection(); QList allNodes = m_NodeTreeModel->GetNodeSet(); foreach(mitk::DataNode::Pointer node, allNodes) { node->SetVisibility(selectedNodes.contains(node)); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ToggleVisibilityOfSelectedNodes( bool ) { QList selectedNodes = this->GetCurrentSelection(); bool isVisible = false; foreach(mitk::DataNode::Pointer node, selectedNodes) { isVisible = false; node->GetBoolProperty("visible", isVisible); node->SetVisibility(!isVisible); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ShowInfoDialogForSelectedNodes( bool ) { QList selectedNodes = this->GetCurrentSelection(); QmitkInfoDialog _QmitkInfoDialog(selectedNodes, this->m_Parent); _QmitkInfoDialog.exec(); } void QmitkDataManagerView::NodeChanged(const mitk::DataNode* /*node*/) { // m_FilterModel->invalidate(); // fix as proposed by R. Khlebnikov in the mitk-users mail from 02.09.2014 QMetaObject::invokeMethod( m_FilterModel, "invalidate", Qt::QueuedConnection ); } QItemSelectionModel *QmitkDataManagerView::GetDataNodeSelectionModel() const { return m_NodeTreeView->selectionModel(); } void QmitkDataManagerView::GlobalReinit( bool ) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow == nullptr) renderWindow = this->OpenRenderWindowPart(false); // no render window available if (renderWindow == nullptr) return; mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); } void QmitkDataManagerView::NodeTreeViewRowsRemoved ( const QModelIndex & /*parent*/, int /*start*/, int /*end*/ ) { m_CurrentRowCount = m_NodeTreeModel->rowCount(); } void QmitkDataManagerView::NodeTreeViewRowsInserted( const QModelIndex & parent, int, int ) { QModelIndex viewIndex = m_FilterModel->mapFromSource(parent); m_NodeTreeView->setExpanded(viewIndex, true); // a new row was inserted if( m_CurrentRowCount == 0 && m_NodeTreeModel->rowCount() == 1 ) { this->OpenRenderWindowPart(); m_CurrentRowCount = m_NodeTreeModel->rowCount(); } } void QmitkDataManagerView::NodeSelectionChanged( const QItemSelection & /*selected*/, const QItemSelection & /*deselected*/ ) { QList nodes = m_NodeTreeModel->GetNodeSet(); foreach(mitk::DataNode::Pointer node, nodes) { if ( node.IsNotNull() ) node->SetBoolProperty("selected", false); } nodes.clear(); nodes = this->GetCurrentSelection(); foreach(mitk::DataNode::Pointer node, nodes) { if ( node.IsNotNull() ) node->SetBoolProperty("selected", true); } //changing the selection does NOT require any rendering processes! //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ShowIn(const QString &editorId) { berry::IWorkbenchPage::Pointer page = this->GetSite()->GetPage(); berry::IEditorInput::Pointer input(new mitk::DataStorageEditorInput(this->GetDataStorageReference())); page->OpenEditor(input, editorId, false, berry::IWorkbenchPage::MATCH_ID); } mitk::IRenderWindowPart* QmitkDataManagerView::OpenRenderWindowPart(bool activatedEditor) { if (activatedEditor) { return this->GetRenderWindowPart(QmitkAbstractView::ACTIVATE | QmitkAbstractView::OPEN); } else { return this->GetRenderWindowPart(QmitkAbstractView::BRING_TO_FRONT | QmitkAbstractView::OPEN); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp index 75891c28d5..4ff98294ba 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp @@ -1,473 +1,450 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkFiberQuantificationView.h" // Qt #include // MITK #include #include #include #include #include #include #include #include #include #include +#include // ITK #include #include #include #include #include #include #include #include #include #include const std::string QmitkFiberQuantificationView::VIEW_ID = "org.mitk.views.fiberquantification"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace mitk; QmitkFiberQuantificationView::QmitkFiberQuantificationView() : QmitkAbstractView() , m_Controls( 0 ) , m_UpsamplingFactor(5) { } // Destructor QmitkFiberQuantificationView::~QmitkFiberQuantificationView() { } void QmitkFiberQuantificationView::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::QmitkFiberQuantificationViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_ProcessFiberBundleButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedBundles()) ); connect( m_Controls->m_ExtractFiberPeaks, SIGNAL(clicked()), this, SLOT(CalculateFiberDirections()) ); } } void QmitkFiberQuantificationView::SetFocus() { m_Controls->m_ProcessFiberBundleButton->setFocus(); } void QmitkFiberQuantificationView::CalculateFiberDirections() { typedef itk::Image ItkUcharImgType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(m_SelectedFB.back()->GetData()); itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); if (m_SelectedImage.IsNotNull()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); mitk::CastToItkImage(m_SelectedImage, itkMaskImage); fOdfFilter->SetMaskImage(itkMaskImage); } // extract directions from fiber bundle fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetAngularThreshold(cos(m_Controls->m_AngularThreshold->value()*M_PI/180)); - fOdfFilter->SetNormalizeVectors(m_Controls->m_NormalizeDirectionsBox->isChecked()); + switch (m_Controls->m_FiberDirNormBox->currentIndex()) + { + case 0: + fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::GLOBAL_MAX); + break; + case 1: + fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::SINGLE_VEC_NORM); + break; + case 2: + fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::MAX_VEC_NORM); + break; + } fOdfFilter->SetUseWorkingCopy(true); - fOdfFilter->SetCreateDirectionImages(m_Controls->m_DirectionImagesBox->isChecked()); fOdfFilter->SetSizeThreshold(m_Controls->m_PeakThreshold->value()); fOdfFilter->SetMaxNumDirections(m_Controls->m_MaxNumDirections->value()); fOdfFilter->Update(); QString name = m_SelectedFB.back()->GetName().c_str(); - if (m_Controls->m_VectorFieldBox->isChecked()) - { - float minSpacing = 1; - if (m_SelectedImage.IsNotNull()) - { - mitk::Vector3D outImageSpacing = m_SelectedImage->GetGeometry()->GetSpacing(); - - if(outImageSpacing[0]GetOutputFiberBundle(); - mitk::DataNode::Pointer node = mitk::DataNode::New(); - node->SetData(directions); - node->SetName((name+"_VECTOR_FIELD").toStdString().c_str()); - node->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(minSpacing)); - node->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); - node->SetProperty("color", mitk::ColorProperty::New(1.0f, 1.0f, 1.0f)); - - GetDataStorage()->Add(node, m_SelectedFB.back()); - } - if (m_Controls->m_NumDirectionsBox->isChecked()) { mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( fOdfFilter->GetNumDirectionsImage().GetPointer() ); mitkImage->SetVolume( fOdfFilter->GetNumDirectionsImage()->GetBufferPointer() ); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitkImage); node->SetName((name+"_NUM_DIRECTIONS").toStdString().c_str()); GetDataStorage()->Add(node, m_SelectedFB.back()); } - if (m_Controls->m_DirectionImagesBox->isChecked()) - { - itk::TractsToVectorImageFilter::ItkDirectionImageType::Pointer itkImg = fOdfFilter->GetDirectionImage(); - - if (itkImg.IsNull()) - return; - - mitk::Image::Pointer mitkImage = mitk::Image::New(); - mitkImage->InitializeByItk( itkImg.GetPointer() ); - mitkImage->SetVolume( itkImg->GetBufferPointer() ); + Image::Pointer mitkImage = dynamic_cast(PeakImage::New().GetPointer()); + mitk::CastToMitkImage(fOdfFilter->GetDirectionImage(), mitkImage); + mitkImage->SetVolume(fOdfFilter->GetDirectionImage()->GetBufferPointer()); - mitk::DataNode::Pointer node = mitk::DataNode::New(); - node->SetData(mitkImage); - node->SetName( (name+"_DIRECTIONS").toStdString().c_str()); - GetDataStorage()->Add(node, m_SelectedFB.back()); - } + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(mitkImage); + node->SetName( (name+"_DIRECTIONS").toStdString().c_str()); + GetDataStorage()->Add(node, m_SelectedFB.back()); } void QmitkFiberQuantificationView::UpdateGui() { m_Controls->m_ProcessFiberBundleButton->setEnabled(!m_SelectedFB.empty()); m_Controls->m_ExtractFiberPeaks->setEnabled(!m_SelectedFB.empty()); } void QmitkFiberQuantificationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { //reset existing Vectors containing FiberBundles and PlanarFigures from a previous selection m_SelectedFB.clear(); m_SelectedSurfaces.clear(); m_SelectedImage = nullptr; for (mitk::DataNode::Pointer node: nodes) { if ( dynamic_cast(node->GetData()) ) { m_SelectedFB.push_back(node); } else if (dynamic_cast(node->GetData())) m_SelectedImage = dynamic_cast(node->GetData()); else if (dynamic_cast(node->GetData())) { m_SelectedSurfaces.push_back(dynamic_cast(node->GetData())); } } UpdateGui(); GenerateStats(); } void QmitkFiberQuantificationView::GenerateStats() { if ( m_SelectedFB.empty() ) return; QString stats(""); for( unsigned int i=0; i(node->GetData())) { if (i>0) stats += "\n-----------------------------\n"; stats += QString(node->GetName().c_str()) + "\n"; mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); stats += "Number of fibers: "+ QString::number(fib->GetNumFibers()) + "\n"; stats += "Number of points: "+ QString::number(fib->GetNumberOfPoints()) + "\n"; stats += "Min. length: "+ QString::number(fib->GetMinFiberLength(),'f',1) + " mm\n"; stats += "Max. length: "+ QString::number(fib->GetMaxFiberLength(),'f',1) + " mm\n"; stats += "Mean length: "+ QString::number(fib->GetMeanFiberLength(),'f',1) + " mm\n"; stats += "Median length: "+ QString::number(fib->GetMedianFiberLength(),'f',1) + " mm\n"; stats += "Standard deviation: "+ QString::number(fib->GetLengthStDev(),'f',1) + " mm\n"; vtkSmartPointer weights = fib->GetFiberWeights(); if (weights!=nullptr) { float weight = -1; int c = 0; for (int i=0; iGetSize(); i++) if (!mitk::Equal(weights->GetValue(i),weight,0.0001)) { weight = weights->GetValue(i); c++; if (c>1) break; } if (c>1) stats += "Detected fiber weights. Fibers are not weighted uniformly.\n"; else stats += "Fibers are weighted equally.\n"; } else stats += "No fiber weight array found.\n"; } } this->m_Controls->m_StatsTextEdit->setText(stats); } void QmitkFiberQuantificationView::ProcessSelectedBundles() { if ( m_SelectedFB.empty() ){ QMessageBox::information( nullptr, "Warning", "No fibe bundle selected!"); MITK_WARN("QmitkFiberQuantificationView") << "no fibe bundle selected"; return; } int generationMethod = m_Controls->m_GenerationBox->currentIndex(); for( unsigned int i=0; i(node->GetData())) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); QString name(node->GetName().c_str()); DataNode::Pointer newNode = nullptr; switch(generationMethod){ case 0: newNode = GenerateTractDensityImage(fib, false, true); name += "_TDI"; break; case 1: newNode = GenerateTractDensityImage(fib, false, false); name += "_TDI"; break; case 2: newNode = GenerateTractDensityImage(fib, true, false); name += "_envelope"; break; case 3: newNode = GenerateColorHeatmap(fib); break; case 4: newNode = GenerateFiberEndingsImage(fib); name += "_fiber_endings"; break; case 5: newNode = GenerateFiberEndingsPointSet(fib); name += "_fiber_endings"; break; } if (newNode.IsNotNull()) { newNode->SetName(name.toStdString()); GetDataStorage()->Add(newNode); } } } } // generate pointset displaying the fiber endings mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateFiberEndingsPointSet(mitk::FiberBundle::Pointer fib) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); vtkSmartPointer fiberPolyData = fib->GetFiberPolyData(); int count = 0; int numFibers = fib->GetNumFibers(); for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints>0) { double* point = points->GetPoint(0); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } if (numPoints>2) { double* point = points->GetPoint(numPoints-1); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } } mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( pointSet ); return node; } // generate image displaying the fiber endings mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateFiberEndingsImage(mitk::FiberBundle::Pointer fib) { typedef unsigned int OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToFiberEndingsImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image OutImageType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate rgba heatmap from fiber bundle mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateColorHeatmap(mitk::FiberBundle::Pointer fib) { typedef itk::RGBAPixel OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToRgbaImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { itk::Image::Pointer itkImage = itk::Image::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate tract density image from fiber bundle mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateTractDensityImage(mitk::FiberBundle::Pointer fib, bool binary, bool absolute) { mitk::DataNode::Pointer node = mitk::DataNode::New(); if (binary) { typedef unsigned char OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node node->SetData(img); } else { typedef float OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } //generator->SetDoFiberResampling(false); generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node node->SetData(img); } return node; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui index 5dda3fdfd1..399ba8db30 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui @@ -1,367 +1,357 @@ QmitkFiberQuantificationViewControls 0 0 484 - 558 + 574 Form Qt::Vertical 20 40 Fiber-derived images QFormLayout::AllNonFixedFieldsGrow false 0 0 200 16777215 11 Perform selected operation on all selected fiber bundles. Generate Image 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 0 Tract Density Image (TDI) Normalized TDI Binary Envelope Fiber Bundle Image Fiber Endings Image Fiber Endings Pointset 0 0 Upsampling factor 1 0.100000000000000 10.000000000000000 0.100000000000000 1.000000000000000 Fiber Statistics Courier 10 Pitch false true Principal Fiber Directions - - - - Angular Threshold: + + + + Maximum number of fiber directions per voxel. + + + 100 + + + 3 - - + + + + Image containing the number of distinct fiber clusters per voxel. + - Size Threshold: + Output #Directions per Voxel + + + true - + false 0 0 200 16777215 11 Start - - + + - Output Vector Field + Max. clusters: - - true + + + + + + Size Threshold: + + + + + + + Angular Threshold: <html><head/><body><p>Directions shorter than the defined threshold are discarded.</p></body></html> 3 1.000000000000000 0.100000000000000 0.300000000000000 - - - - Max. clusters: - - - - - - - Maximum number of fiber directions per voxel. - - - 100 - - - 3 - - - Fiber directions with an angle smaller than the defined threshold are clustered. 2 0.000000000000000 90.000000000000000 1.000000000000000 30.000000000000000 - - - - 4D image containing the principal fiber directions. - - - Output Direction image - - - true - - - - - - - Image containing the number of distinct fiber clusters per voxel. - + + - Output #Directions per Voxel - - - true + Normalization: - - - - <html><head/><body><p>Normalize output directions to length 1 otherwise directions are max normalized (voxel-wise).</p></body></html> - - - Normalize directions - - - true - + + + + + Global maximum + + + + + Single vector + + + + + Voxel-wise maximum + + 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 62f8b6d726..ace95e55ae 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,478 +1,424 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //misc #define _USE_MATH_DEFINES #include #include // Blueberry #include #include // Qmitk #include "QmitkOdfMaximaExtractionView.h" -// MITK #include #include #include #include #include - -// ITK #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 isMitkImage = 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::NodePredicateAnd::New(mitk::NodePredicateAnd::New(unwanted, isMitkImage), mitk::NodePredicateNot::New(isBinaryPredicate))); m_Controls->m_MaskBox->SetZeroEntryText("--"); m_Controls->m_ImageBox->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())); - } + 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(); switch (m_Controls->m_ToolkitBox->currentIndex()) { case 0: filter->SetToolkit(FilterType::FSL); break; case 1: filter->SetToolkit(FilterType::MRTRIX); break; default: filter->SetToolkit(FilterType::FSL); } filter->SetInputImage(caster->GetOutput()); filter->GenerateData(); typename FilterType::OdfImageType::Pointer itkodf = filter->GetOdfImage(); typename FilterType::CoefficientImageType::Pointer itkCi = filter->GetCoefficientImage(); { mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(itkCi.GetPointer()); img->SetVolume(itkCi->GetBufferPointer()); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); name += "_ShCoefficientImage_Imported"; node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node, m_Controls->m_ImageBox->GetSelectedNode()); } - { - mitk::OdfImage::Pointer img = mitk::OdfImage::New(); - img->InitializeByItk(itkodf.GetPointer()); - img->SetVolume(itkodf->GetBufferPointer()); - DataNode::Pointer node = DataNode::New(); - node->SetData(img); + { + mitk::OdfImage::Pointer img = mitk::OdfImage::New(); + img->InitializeByItk(itkodf.GetPointer()); + img->SetVolume(itkodf->GetBufferPointer()); + DataNode::Pointer node = DataNode::New(); + node->SetData(img); - QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); - name += "_OdfImage_Imported"; - node->SetName(name.toStdString().c_str()); + QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); + name += "_OdfImage_Imported"; + node->SetName(name.toStdString().c_str()); - GetDataStorage()->Add(node, m_Controls->m_ImageBox->GetSelectedNode()); - } + 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]; -// // solve bx² + cx + d = 0 = shOrder² + 2*shOrder + 2-2*neededCoeffs; -// int c = 3, d = 2 - 2 * nrCoeffs; -// double D = c*c - 4 * d; -// int shOrder; -// if (D>0) -// { -// shOrder = (-c + sqrt(D)) / 2.0; -// if (shOrder<0) -// shOrder = (-c - sqrt(D)) / 2.0; -// } -// else if (D == 0) -// shOrder = -c / 2.0; + // // solve bx² + cx + d = 0 = shOrder² + 2*shOrder + 2-2*neededCoeffs; + // int c = 3, d = 2 - 2 * nrCoeffs; + // double D = c*c - 4 * d; + // int shOrder; + // if (D>0) + // { + // shOrder = (-c + sqrt(D)) / 2.0; + // if (shOrder<0) + // shOrder = (-c - sqrt(D)) / 2.0; + // } + // else if (D == 0) + // shOrder = -c / 2.0; 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); + 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(); - if (m_Controls->m_OutputDirectionImagesBox->isChecked()) - { - MaximaExtractionFilterType::PeakImageType::Pointer itkImg = filter->GetPeakImage(); - mitk::Image::Pointer img = mitk::Image::New(); - CastToMitkImage(itkImg, img); + MaximaExtractionFilterType::PeakImageType::Pointer itkImg = filter->GetPeakImage(); + mitk::Image::Pointer mitkPeakImage = dynamic_cast(PeakImage::New().GetPointer()); + CastToMitkImage(itkImg, mitkPeakImage); - DataNode::Pointer node = DataNode::New(); - node->SetData(img); - 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()); - } + 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()); } - - if (m_Controls->m_OutputVectorFieldBox->isChecked()) - { - mitk::Vector3D outImageSpacing = geometry->GetSpacing(); - float minSpacing = 1; - if (outImageSpacing[0]GetOutputFiberBundle(); - // directions->SetGeometry(geometry); - DataNode::Pointer node = DataNode::New(); - node->SetData(directions); - QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); - name += "_VectorField"; - node->SetName(name.toStdString().c_str()); - node->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(minSpacing)); - node->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); - GetDataStorage()->Add(node, m_Controls->m_ImageBox->GetSelectedNode()); - } } template void QmitkOdfMaximaExtractionView::StartMaximaExtraction(Image *image) { typedef itk::FiniteDiffOdfMaximaExtractionFilter< float, shOrder, 20242 > MaximaExtractionFilterType; typename MaximaExtractionFilterType::Pointer filter = MaximaExtractionFilterType::New(); switch (m_Controls->m_ToolkitBox->currentIndex()) { case 0: filter->SetToolkit(MaximaExtractionFilterType::FSL); break; case 1: filter->SetToolkit(MaximaExtractionFilterType::MRTRIX); break; default: filter->SetToolkit(MaximaExtractionFilterType::FSL); } 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()*M_PI / 180)); filter->SetClusteringThreshold(cos((float)m_Controls->m_ClusteringAngleBox->value()*M_PI / 180)); filter->SetMaxNumPeaks(m_Controls->m_MaxNumPeaksBox->value()); filter->SetPeakThreshold(m_Controls->m_PeakThresholdBox->value()); filter->SetAbsolutePeakThreshold(m_Controls->m_AbsoluteThresholdBox->value()); 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(); - if (m_Controls->m_OutputDirectionImagesBox->isChecked()) - { - typename MaximaExtractionFilterType::PeakImageType::Pointer itkImg = filter->GetPeakImage(); - mitk::Image::Pointer img = mitk::Image::New(); - CastToMitkImage(itkImg, img); + typename MaximaExtractionFilterType::PeakImageType::Pointer itkImg = filter->GetPeakImage(); + mitk::Image::Pointer img = dynamic_cast(PeakImage::New().GetPointer()); + CastToMitkImage(itkImg, 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()); - } + 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()); } - - if (m_Controls->m_OutputVectorFieldBox->isChecked()) - { - mitk::Vector3D outImageSpacing = geometry->GetSpacing(); - float minSpacing = 1; - if (outImageSpacing[0]GetOutputFiberBundle(); - // directions->SetGeometry(geometry); - DataNode::Pointer node = DataNode::New(); - node->SetData(directions); - QString name(m_Controls->m_ImageBox->GetSelectedNode()->GetName().c_str()); - name += "_VECTOR_FIELD"; - node->SetName(name.toStdString().c_str()); - node->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(minSpacing)); - node->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); - GetDataStorage()->Add(node, 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); + 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); + 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; + 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); + 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.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui index b2f0f1245e..9d4c7b0bf6 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui @@ -1,413 +1,387 @@ QmitkOdfMaximaExtractionViewControls 0 0 397 848 Form true Generate ODF image and MITK compatible SH coefficient from other toolkits. Start SH Coefficient Import Qt::Vertical 20 259 - Output + Additional Output QFormLayout::AllNonFixedFieldsGrow - - - Only for visualization purposes! The vectors are automatically corrected for image spacing and for the largest eigenvalue in case of the tensor peak extraction. - - - Vector Field - - - true - - - - Output unsigned char image containing the number of directions per voxel. #Peaks per Voxel false - - - - 4D image cotaining peak information - - - Peak Image - - - true - - - Parameters QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Vector Normalization: <html><head/><body><p>The vector fields are always coorected for image spacing and using the lagest eigenvalue in case of the tensor peak extraction. This is done for visualizytion purposes. The output direction images are not affected.</p></body></html> 1 No Normalization MAX Normalize Single Vec Normalization true QFrame::NoFrame QFrame::Raised 0 0 0 0 6 true Max. Peaks: Relative Threshold: true Peak threshold relative to the largest peak per voxel. 3 0.000000000000000 1.000000000000000 0.100000000000000 0.500000000000000 true Absolute peak threshold (only used for the finite differences method). The value is additionally scaled by 1/GFA. 3 0.000000000000000 1.000000000000000 0.010000000000000 0.030000000000000 true Maximum number of peaks to extract. 1 1000 3 Clustering Angle: Cluster close directions. Define "close" here. 90 30 Absolute Threshold: Angular Threshold: Discard smaller peaks in the defined angle around the maximum peaks that were too far away to be clustered. 0 90 0 Please Select Input Data Select a tensor image or a SH coefficient image (generate using Q-Ball reconstruction view). ShCoeff/DTI: Mask Image: true Extract ODF peaks using finite differences on the densely sampled ODF surface. Start Peak Extraction Spherical Harmonic Convention Define SH coefficient convention (depends on toolkit) 0 MITK/FSL MRtrix QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake index 3649eafc3f..624eea1730 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake @@ -1,61 +1,62 @@ set(SRC_CPP_FILES ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkDiffusionDicomImportView.cpp QmitkControlVisualizationPropertiesView.cpp QmitkDicomTractogramTagEditorView.cpp Perspectives/QmitkDiffusionDefaultPerspective.cpp ) set(UI_FILES src/internal/QmitkDiffusionDicomImportViewControls.ui src/internal/QmitkControlVisualizationPropertiesViewControls.ui src/internal/QmitkDicomTractogramTagEditorViewControls.ui ) set(MOC_H_FILES src/internal/mitkPluginActivator.h src/internal/QmitkDiffusionDicomImportView.h src/internal/QmitkControlVisualizationPropertiesView.h src/internal/QmitkDicomTractogramTagEditorView.h src/internal/Perspectives/QmitkDiffusionDefaultPerspective.h ) set(CACHED_RESOURCE_FILES # list of resource files which can be used by the plug-in # system without loading the plug-ins shared library, # for example the icon used in the menu and tabs for the # plug-in views in the workbench plugin.xml resources/dwiimport.png resources/vizControls.png resources/arrow.png resources/dwi.png resources/odf.png resources/tensor.png resources/tractogram.png + resources/odf_peaks.png resources/ml_tractogram.png resources/refresh.xpm ) set(QRC_FILES # uncomment the following line if you want to use Qt resources resources/QmitkDiffusionImaging.qrc #resources/QmitkTractbasedSpatialStatisticsView.qrc ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/resources/QmitkDiffusionImaging.qrc b/Plugins/org.mitk.gui.qt.diffusionimaging/resources/QmitkDiffusionImaging.qrc index 8eeca44476..cd94502f0b 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/resources/QmitkDiffusionImaging.qrc +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/resources/QmitkDiffusionImaging.qrc @@ -1,30 +1,31 @@ dwi.png dwiimport.png texIntONIcon.png texIntOFFIcon.png vizControls.png Refresh_48.png glyphsoff_C.png glyphsoff_S.png glyphsoff_T.png glyphson_C.png glyphson_S.png glyphson_T.png color24.gif color48.gif color64.gif crosshair.png paint2.png reset.png MapperEfx2D.png refresh.xpm tensor.png tractogram.png ml_tractogram.png ConnectomicsNetwork.png odf.png DiffData24.png + odf_peaks.png diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/resources/odf_peaks.png b/Plugins/org.mitk.gui.qt.diffusionimaging/resources/odf_peaks.png new file mode 100644 index 0000000000..5ea20f6af9 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.diffusionimaging/resources/odf_peaks.png differ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp index d904081ddb..d82d42da44 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.cpp @@ -1,1363 +1,1403 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkControlVisualizationPropertiesView.h" #include "mitkNodePredicateDataType.h" #include "mitkDataNodeObject.h" #include "mitkOdfNormalizationMethodProperty.h" #include "mitkOdfScaleByProperty.h" #include "mitkResliceMethodProperty.h" #include "mitkRenderingManager.h" #include "mitkTbssImage.h" #include "mitkPlanarFigure.h" #include "mitkFiberBundle.h" #include "QmitkDataStorageComboBox.h" #include "mitkPlanarFigureInteractor.h" #include #include #include #include #include #include "usModuleRegistry.h" - +#include #include #include "mitkPlaneGeometry.h" #include +#include +#include #include "berryIWorkbenchWindow.h" #include "berryIWorkbenchPage.h" #include "berryISelectionService.h" #include "berryConstants.h" #include "berryPlatformUI.h" #include "itkRGBAPixel.h" #include #include "qwidgetaction.h" #include "qcolordialog.h" #include #include #include #define ROUND(a) ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a))) const std::string QmitkControlVisualizationPropertiesView::VIEW_ID = "org.mitk.views.controlvisualizationpropertiesview"; using namespace berry; QmitkControlVisualizationPropertiesView::QmitkControlVisualizationPropertiesView() : QmitkAbstractView(), m_Controls(nullptr), m_CurrentSelection(0), m_IconTexOFF(new QIcon(":/QmitkDiffusionImaging/texIntOFFIcon.png")), m_IconTexON(new QIcon(":/QmitkDiffusionImaging/texIntONIcon.png")), m_IconGlyOFF_T(new QIcon(":/QmitkDiffusionImaging/glyphsoff_T.png")), m_IconGlyON_T(new QIcon(":/QmitkDiffusionImaging/glyphson_T.png")), m_IconGlyOFF_C(new QIcon(":/QmitkDiffusionImaging/glyphsoff_C.png")), m_IconGlyON_C(new QIcon(":/QmitkDiffusionImaging/glyphson_C.png")), m_IconGlyOFF_S(new QIcon(":/QmitkDiffusionImaging/glyphsoff_S.png")), m_IconGlyON_S(new QIcon(":/QmitkDiffusionImaging/glyphson_S.png")), m_GlyIsOn_T(false), m_GlyIsOn_C(false), m_GlyIsOn_S(false), m_CurrentPickingNode(0), - m_FiberBundleObserverTag(0), - m_FiberBundleObserveOpacityTag(0) + m_ColorPropertyObserverTag(0), + m_OpacityPropertyObserverTag(0) { currentThickSlicesMode = 1; m_MyMenu = nullptr; int numThread = itk::MultiThreader::GetGlobalMaximumNumberOfThreads(); if (numThread > 12) numThread = 12; itk::MultiThreader::SetGlobalDefaultNumberOfThreads(numThread); } QmitkControlVisualizationPropertiesView::~QmitkControlVisualizationPropertiesView() { + mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); + + if (renderWindow) + { + mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("axial"))->GetSliceNavigationController(); + slicer->RemoveObserver(m_SliceObserverTag1); + slicer = renderWindow->GetQmitkRenderWindow(QString("sagittal"))->GetSliceNavigationController(); + slicer->RemoveObserver(m_SliceObserverTag2); + slicer = renderWindow->GetQmitkRenderWindow(QString("coronal"))->GetSliceNavigationController(); + slicer->RemoveObserver(m_SliceObserverTag3); + } + this->GetSite()->GetWorkbenchWindow()->GetSelectionService()->RemovePostSelectionListener(/*"org.mitk.views.datamanager",*/ m_SelListener.data()); } void QmitkControlVisualizationPropertiesView::OnThickSlicesModeSelected( QAction* action ) { currentThickSlicesMode = action->data().toInt(); switch( currentThickSlicesMode ) { case 0: // toInt() returns 0 'otherwise'. return; // dummy code/todo: implement stuff. case 1: this->m_Controls->m_TSMenu->setText("MIP"); break; case 2: this->m_Controls->m_TSMenu->setText("SUM"); break; case 3: this->m_Controls->m_TSMenu->setText("WEIGH"); break; default: return; // dummy code/todo: implement stuff. } if (auto renderWindowPart = this->GetRenderWindowPart(OPEN)) { /// TODO There is no way to access the individual crosshair planes through the render window part API. /// There could be a new 'mitk::DataNode* mitk::ILinkedRenderWindowPart::GetSlicingPlane(const std::string& name) const' /// function for this purpose. For the time being, I comment out the lines below, but they are valid /// and they have to be re-enabled after the crosshair planes can be accessed again. // mitk::DataNode* n; // n = renderWindowPart->GetSlicingPlane("axial"); // if (n) { n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); } // n = renderWindowPart->GetSlicingPlane("sagittal"); // if (n) { n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); } // n = renderWindowPart->GetSlicingPlane("coronal"); // if (n) { n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); } mitk::BaseRenderer::Pointer renderer; renderer = renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer(); if (renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = renderWindowPart->GetQmitkRenderWindow("sagittal")->GetRenderer(); if (renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = renderWindowPart->GetQmitkRenderWindow("coronal")->GetRenderer(); if (renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer->GetRenderingManager()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::OnTSNumChanged( int num ) { if (auto renderWindowPart = this->GetRenderWindowPart(OPEN)) { /// TODO There is no way to access the individual crosshair planes through the render window part API. /// There could be a new 'mitk::DataNode* mitk::ILinkedRenderWindowPart::GetSlicingPlane(const std::string& name) const' /// function for this purpose. For the time being, I comment out the lines below, but they are valid /// and they have to be re-enabled after the crosshair planes can be accessed again. // if(num==0) // { // mitk::DataNode* n; // n = renderWindowPart->GetSlicingPlane("axial"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 0 ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( false ) ); // // n = renderWindowPart->GetSlicingPlane("sagittal"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 0 ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( false ) ); // // n = renderWindowPart->GetSlicingPlane("coronal"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( 0 ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( false ) ); // } // else // { // mitk::DataNode* n; // n = renderWindowPart->GetSlicingPlane("axial"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( (num>0) ) ); // // n = renderWindowPart->GetSlicingPlane("sagittal"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( (num>0) ) ); // // n = renderWindowPart->GetSlicingPlane("coronal"); // if(n) n->SetProperty( "reslice.thickslices", mitk::ResliceMethodProperty::New( currentThickSlicesMode ) ); // if(n) n->SetProperty( "reslice.thickslices.num", mitk::IntProperty::New( num ) ); // if(n) n->SetProperty( "reslice.thickslices.showarea", mitk::BoolProperty::New( (num>0) ) ); // } m_TSLabel->setText(QString::number( num*2 + 1 )); mitk::BaseRenderer::Pointer renderer; renderer = renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = nullptr; renderer = renderWindowPart->GetQmitkRenderWindow("sagittal")->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer = nullptr; renderer = renderWindowPart->GetQmitkRenderWindow("coronal")->GetRenderer(); if(renderer.IsNotNull()) { renderer->SendUpdateSlice(); } renderer->GetRenderingManager()->RequestUpdateAll(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); } } void QmitkControlVisualizationPropertiesView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkControlVisualizationPropertiesViewControls; m_Controls->setupUi(parent); this->CreateConnections(); // hide warning (ODFs in rotated planes) m_Controls->m_lblRotatedPlanesWarning->hide(); m_MyMenu = new QMenu(parent); m_Controls->m_TSMenu->setMenu( m_MyMenu ); QIcon iconFiberFade(":/QmitkDiffusionImaging/MapperEfx2D.png"); m_Controls->m_FiberFading2D->setIcon(iconFiberFade); #ifndef DIFFUSION_IMAGING_EXTENDED int size = m_Controls->m_AdditionalScaling->count(); for(int t=0; tm_AdditionalScaling->itemText(t).toStdString() == "Scale by ASR") { m_Controls->m_AdditionalScaling->removeItem(t); } } #endif m_Controls->m_ScalingFrame->setVisible(false); m_Controls->m_NormalizationFrame->setVisible(false); m_Controls->m_Crosshair->setVisible(false); + + mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); + + if (renderWindow) + { + { + mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("axial"))->GetSliceNavigationController(); + itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); + command->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::OnAxialChanged ); + m_SliceObserverTag1 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), command ); + } + + { + mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("sagittal"))->GetSliceNavigationController(); + itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); + command->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::OnSagittalChanged ); + m_SliceObserverTag2 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), command ); + } + + { + mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("coronal"))->GetSliceNavigationController(); + itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); + command->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::OnCoronalChanged ); + m_SliceObserverTag3 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), command ); + } + } } } void QmitkControlVisualizationPropertiesView::SetFocus() { m_Controls->m_TSMenu->setFocus(); } void QmitkControlVisualizationPropertiesView::SliceRotation(const itk::EventObject&) { // test if plane rotated if( m_GlyIsOn_T || m_GlyIsOn_C || m_GlyIsOn_S ) { if( this->IsPlaneRotated() ) { // show label m_Controls->m_lblRotatedPlanesWarning->show(); } else { //hide label m_Controls->m_lblRotatedPlanesWarning->hide(); } } } void QmitkControlVisualizationPropertiesView::NodeRemoved(const mitk::DataNode* /*node*/) { } #include void QmitkControlVisualizationPropertiesView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_VisibleOdfsON_T), SIGNAL(clicked()), this, SLOT(VisibleOdfsON_T()) ); connect( (QObject*)(m_Controls->m_VisibleOdfsON_S), SIGNAL(clicked()), this, SLOT(VisibleOdfsON_S()) ); connect( (QObject*)(m_Controls->m_VisibleOdfsON_C), SIGNAL(clicked()), this, SLOT(VisibleOdfsON_C()) ); connect( (QObject*)(m_Controls->m_ShowMaxNumber), SIGNAL(editingFinished()), this, SLOT(ShowMaxNumberChanged()) ); connect( (QObject*)(m_Controls->m_NormalizationDropdown), SIGNAL(currentIndexChanged(int)), this, SLOT(NormalizationDropdownChanged(int)) ); connect( (QObject*)(m_Controls->m_ScalingFactor), SIGNAL(valueChanged(double)), this, SLOT(ScalingFactorChanged(double)) ); connect( (QObject*)(m_Controls->m_AdditionalScaling), SIGNAL(currentIndexChanged(int)), this, SLOT(AdditionalScaling(int)) ); connect( (QObject*)(m_Controls->m_ScalingCheckbox), SIGNAL(clicked()), this, SLOT(ScalingCheckbox()) ); - connect((QObject*) m_Controls->m_ResetColoring, SIGNAL(clicked()), (QObject*) this, SLOT(BundleRepresentationResetColoring())); + connect((QObject*) m_Controls->m_ResetColoring, SIGNAL(clicked()), (QObject*) this, SLOT(ResetColoring())); + connect((QObject*) m_Controls->m_ResetColoring2, SIGNAL(clicked()), (QObject*) this, SLOT(ResetColoring())); connect((QObject*) m_Controls->m_FiberFading2D, SIGNAL(clicked()), (QObject*) this, SLOT( Fiber2DfadingEFX() ) ); connect((QObject*) m_Controls->m_FiberThicknessSlider, SIGNAL(sliderReleased()), (QObject*) this, SLOT( FiberSlicingThickness2D() ) ); connect((QObject*) m_Controls->m_FiberThicknessSlider, SIGNAL(valueChanged(int)), (QObject*) this, SLOT( FiberSlicingUpdateLabel(int) )); connect((QObject*) m_Controls->m_Crosshair, SIGNAL(clicked()), (QObject*) this, SLOT(SetInteractor())); connect((QObject*) m_Controls->m_LineWidth, SIGNAL(editingFinished()), (QObject*) this, SLOT(LineWidthChanged())); connect((QObject*) m_Controls->m_TubeWidth, SIGNAL(editingFinished()), (QObject*) this, SLOT(TubeRadiusChanged())); connect( (QObject*) m_Controls->m_EllipsoidViewRadioButton, SIGNAL(toggled(bool)), (QObject*) this, SLOT(OnTensorViewChanged() ) ); connect( (QObject*) m_Controls->m_colouriseRainbowRadioButton, SIGNAL(toggled(bool)), (QObject*) this, SLOT(OnColourisationModeChanged() ) ); connect( (QObject*) m_Controls->m_randomModeRadioButton, SIGNAL(toggled(bool)), (QObject*) this, SLOT(OnRandomModeChanged() ) ); connect((QObject*) m_Controls->m_Clip0, SIGNAL(toggled(bool)), (QObject*) this, SLOT(Toggle3DClipping(bool))); connect((QObject*) m_Controls->m_Clip1, SIGNAL(toggled(bool)), (QObject*) this, SLOT(Toggle3DClipping(bool))); connect((QObject*) m_Controls->m_Clip2, SIGNAL(toggled(bool)), (QObject*) this, SLOT(Toggle3DClipping(bool))); connect((QObject*) m_Controls->m_Clip3, SIGNAL(toggled(bool)), (QObject*) this, SLOT(Toggle3DClipping(bool))); connect((QObject*) m_Controls->m_FlipClipBox, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(Toggle3DClipping())); + + connect((QObject*) m_Controls->m_FlipPeaksButton, SIGNAL(clicked()), (QObject*) this, SLOT(FlipPeaks())); } } // set diffusion image channel to b0 volume void QmitkControlVisualizationPropertiesView::NodeAdded(const mitk::DataNode *node) { mitk::DataNode* notConst = const_cast(node); bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(node->GetData())) ); if (isDiffusionImage) { mitk::Image::Pointer dimg = dynamic_cast(notConst->GetData()); // if there is no b0 image in the dataset, the GetB0Indices() returns a vector of size 0 // and hence we cannot set the Property directly to .front() int displayChannelPropertyValue = 0; mitk::BValueMapProperty* bmapproperty = static_cast (dimg->GetProperty(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ); mitk::DiffusionPropertyHelper::BValueMapType map = bmapproperty->GetBValueMap(); if( map[0].size() > 0) { displayChannelPropertyValue = map[0].front(); } notConst->SetIntProperty("DisplayChannel", displayChannelPropertyValue ); } } /* OnSelectionChanged is registered to SelectionService, therefore no need to implement SelectionService Listener explicitly */ void QmitkControlVisualizationPropertiesView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { m_Controls->m_BundleControlsFrame->setVisible(false); m_Controls->m_ImageControlsFrame->setVisible(false); + m_Controls->m_PeakImageFrame->setVisible(false); if (nodes.size()>1) // only do stuff if one node is selected return; m_Controls->m_NumberGlyphsFrame->setVisible(false); m_Controls->m_GlyphFrame->setVisible(false); m_Controls->m_TSMenu->setVisible(false); m_SelectedNode = nullptr; int numOdfImages = 0; for (mitk::DataNode::Pointer node: nodes) { if(node.IsNull()) continue; mitk::BaseData* nodeData = node->GetData(); if(nodeData == nullptr) continue; m_SelectedNode = node; - if (dynamic_cast(nodeData)) + if (dynamic_cast(nodeData)) + { + m_Controls->m_PeakImageFrame->setVisible(true); + + if (m_Color.IsNotNull()) + m_Color->RemoveObserver(m_ColorPropertyObserverTag); + + itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); + command->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::SetCustomColor ); + m_Color = dynamic_cast(node->GetProperty("color", nullptr)); + if (m_Color.IsNotNull()) + m_ColorPropertyObserverTag = m_Color->AddObserver( itk::ModifiedEvent(), command ); + } + else if (dynamic_cast(nodeData)) { int Fiber3DClippingPlaneId = -1; m_SelectedNode->GetPropertyValue("Fiber3DClippingPlaneId",Fiber3DClippingPlaneId); switch(Fiber3DClippingPlaneId) { case 0: m_Controls->m_Clip0->setChecked(1); break; case 1: m_Controls->m_Clip1->setChecked(1); break; case 2: m_Controls->m_Clip2->setChecked(1); break; case 3: m_Controls->m_Clip3->setChecked(1); break; default : m_Controls->m_Clip0->setChecked(1); } - // handle fiber bundle property observers - if (m_Color.IsNotNull()) { m_Color->RemoveObserver(m_FiberBundleObserverTag); } + // handle fiber property observers + if (m_Color.IsNotNull()) + m_Color->RemoveObserver(m_ColorPropertyObserverTag); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::SetFiberBundleCustomColor ); + command->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::SetCustomColor ); m_Color = dynamic_cast(node->GetProperty("color", nullptr)); if (m_Color.IsNotNull()) - m_FiberBundleObserverTag = m_Color->AddObserver( itk::ModifiedEvent(), command ); + m_ColorPropertyObserverTag = m_Color->AddObserver( itk::ModifiedEvent(), command ); - if (m_Opacity.IsNotNull()) - { - m_Opacity->RemoveObserver(m_FiberBundleObserveOpacityTag); - } - itk::ReceptorMemberCommand::Pointer command2 - = itk::ReceptorMemberCommand::New(); - command2->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::SetFiberBundleOpacity ); - m_Opacity = dynamic_cast(node->GetProperty("opacity", nullptr)); - - if (m_Opacity.IsNotNull()) - { - m_FiberBundleObserveOpacityTag = m_Opacity->AddObserver( itk::ModifiedEvent(), command2 ); - } m_Controls->m_BundleControlsFrame->setVisible(true); if(m_CurrentPickingNode != 0 && node.GetPointer() != m_CurrentPickingNode) { m_Controls->m_Crosshair->setEnabled(false); } else { m_Controls->m_Crosshair->setEnabled(true); } int width; node->GetIntProperty("shape.linewidth", width); m_Controls->m_LineWidth->setValue(width); float radius; node->GetFloatProperty("shape.tuberadius", radius); m_Controls->m_TubeWidth->setValue(radius); float range; node->GetFloatProperty("Fiber2DSliceThickness",range); mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); mitk::BaseGeometry::Pointer geo = fib->GetGeometry(); mitk::ScalarType max = geo->GetExtentInMM(0); max = std::max(max, geo->GetExtentInMM(1)); max = std::max(max, geo->GetExtentInMM(2)); m_Controls->m_FiberThicknessSlider->setMaximum(max * 10); m_Controls->m_FiberThicknessSlider->setValue(range * 10); } else if(dynamic_cast(nodeData) || dynamic_cast(nodeData)) { m_Controls->m_ImageControlsFrame->setVisible(true); m_Controls->m_NumberGlyphsFrame->setVisible(true); m_Controls->m_GlyphFrame->setVisible(true); m_Controls->m_NormalizationFrame->setVisible(true); if(m_NodeUsedForOdfVisualization.IsNotNull()) { m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_S", false); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_C", false); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_T", false); } m_NodeUsedForOdfVisualization = node; m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_S", m_GlyIsOn_S); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_C", m_GlyIsOn_C); m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_T", m_GlyIsOn_T); int val; node->GetIntProperty("ShowMaxNumber", val); m_Controls->m_ShowMaxNumber->setValue(val); m_Controls->m_NormalizationDropdown ->setCurrentIndex(dynamic_cast(node->GetProperty("Normalization")) ->GetValueAsId()); float fval; node->GetFloatProperty("Scaling",fval); m_Controls->m_ScalingFactor->setValue(fval); m_Controls->m_AdditionalScaling ->setCurrentIndex(dynamic_cast(node->GetProperty("ScaleBy"))->GetValueAsId()); bool switchTensorViewValue = false; node->GetBoolProperty( "DiffusionCore.Rendering.OdfVtkMapper.SwitchTensorView", switchTensorViewValue ); if( dynamic_cast(nodeData) ) { m_Controls-> m_EllipsoidViewRadioButton-> setEnabled( true ); m_Controls-> m_EllipsoidViewRadioButton-> setChecked( switchTensorViewValue ); } else { m_Controls-> m_EllipsoidViewRadioButton-> setEnabled( false ); m_Controls-> m_EllipsoidViewRadioButton-> setChecked( false ); } bool colourisationModeBit = false; node-> GetBoolProperty( "DiffusionCore.Rendering.OdfVtkMapper.ColourisationModeBit", colourisationModeBit ); m_Controls-> m_colouriseSimpleRadioButton-> setChecked( colourisationModeBit ); bool randomModeBit = false; node-> GetBoolProperty( "DiffusionCore.Rendering.OdfVtkMapper.RandomModeBit", randomModeBit ); m_Controls-> m_randomModeRadioButton-> setChecked( randomModeBit ); numOdfImages++; } else if(dynamic_cast(nodeData)) { PlanarFigureFocus(); } else if( dynamic_cast(nodeData) ) { m_Controls->m_ImageControlsFrame->setVisible(true); m_Controls->m_TSMenu->setVisible(true); } } if( nodes.empty() ) { return; } mitk::DataNode::Pointer node = nodes.at(0); if( node.IsNull() ) { return; } QMenu *myMenu = m_MyMenu; myMenu->clear(); QActionGroup* thickSlicesActionGroup = new QActionGroup(myMenu); thickSlicesActionGroup->setExclusive(true); int currentTSMode = 0; { mitk::ResliceMethodProperty::Pointer m = dynamic_cast(node->GetProperty( "reslice.thickslices" )); if( m.IsNotNull() ) currentTSMode = m->GetValueAsId(); } int maxTS = 30; for (auto node: nodes) { mitk::Image* image = dynamic_cast(node->GetData()); if (image) { int size = std::max(image->GetDimension(0), std::max(image->GetDimension(1), image->GetDimension(2))); if (size>maxTS) { maxTS=size; } } } maxTS /= 2; int currentNum = 0; { mitk::IntProperty::Pointer m = dynamic_cast(node->GetProperty( "reslice.thickslices.num" )); if( m.IsNotNull() ) { currentNum = m->GetValue(); if(currentNum < 0) { currentNum = 0; } if(currentNum > maxTS) { currentNum = maxTS; } } } if(currentTSMode==0) { currentNum=0; } QSlider *m_TSSlider = new QSlider(myMenu); m_TSSlider->setMinimum(0); m_TSSlider->setMaximum(maxTS-1); m_TSSlider->setValue(currentNum); m_TSSlider->setOrientation(Qt::Horizontal); connect( m_TSSlider, SIGNAL( valueChanged(int) ), this, SLOT( OnTSNumChanged(int) ) ); QHBoxLayout* _TSLayout = new QHBoxLayout; _TSLayout->setContentsMargins(4,4,4,4); _TSLayout->addWidget(m_TSSlider); _TSLayout->addWidget(m_TSLabel=new QLabel(QString::number(currentNum*2+1),myMenu)); QWidget* _TSWidget = new QWidget; _TSWidget->setLayout(_TSLayout); QActionGroup* thickSliceModeActionGroup = new QActionGroup(myMenu); thickSliceModeActionGroup->setExclusive(true); QWidgetAction *m_TSSliderAction = new QWidgetAction(myMenu); m_TSSliderAction->setDefaultWidget(_TSWidget); myMenu->addAction(m_TSSliderAction); QAction* mipThickSlicesAction = new QAction(myMenu); mipThickSlicesAction->setActionGroup(thickSliceModeActionGroup); mipThickSlicesAction->setText("MIP (max. intensity proj.)"); mipThickSlicesAction->setCheckable(true); mipThickSlicesAction->setChecked(currentThickSlicesMode==1); mipThickSlicesAction->setData(1); myMenu->addAction( mipThickSlicesAction ); QAction* sumThickSlicesAction = new QAction(myMenu); sumThickSlicesAction->setActionGroup(thickSliceModeActionGroup); sumThickSlicesAction->setText("SUM (sum intensity proj.)"); sumThickSlicesAction->setCheckable(true); sumThickSlicesAction->setChecked(currentThickSlicesMode==2); sumThickSlicesAction->setData(2); myMenu->addAction( sumThickSlicesAction ); QAction* weightedThickSlicesAction = new QAction(myMenu); weightedThickSlicesAction->setActionGroup(thickSliceModeActionGroup); weightedThickSlicesAction->setText("WEIGHTED (gaussian proj.)"); weightedThickSlicesAction->setCheckable(true); weightedThickSlicesAction->setChecked(currentThickSlicesMode==3); weightedThickSlicesAction->setData(3); myMenu->addAction( weightedThickSlicesAction ); connect( thickSliceModeActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(OnThickSlicesModeSelected(QAction*)) ); } void QmitkControlVisualizationPropertiesView::VisibleOdfsON_S() { m_GlyIsOn_S = m_Controls->m_VisibleOdfsON_S->isChecked(); if (m_NodeUsedForOdfVisualization.IsNull()) { MITK_WARN << "ODF visualization activated but m_NodeUsedForOdfVisualization is nullptr"; return; } m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_S", m_GlyIsOn_S); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::Visible() { - mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); - if (renderWindow) - { - { - mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("axial"))->GetSliceNavigationController(); - itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::OnAxialChanged ); - m_SliceObserverTag1 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), command ); - } - - { - mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("sagittal"))->GetSliceNavigationController(); - itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::OnSagittalChanged ); - m_SliceObserverTag2 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), command ); - } - - { - mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("coronal"))->GetSliceNavigationController(); - itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); - command->SetCallbackFunction( this, &QmitkControlVisualizationPropertiesView::OnCoronalChanged ); - m_SliceObserverTag3 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), command ); - } - } } void QmitkControlVisualizationPropertiesView::Hidden() { - mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); - if (renderWindow) - { - mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("axial"))->GetSliceNavigationController(); - slicer->RemoveObserver(m_SliceObserverTag1); - slicer = renderWindow->GetQmitkRenderWindow(QString("sagittal"))->GetSliceNavigationController(); - slicer->RemoveObserver(m_SliceObserverTag2); - slicer = renderWindow->GetQmitkRenderWindow(QString("coronal"))->GetSliceNavigationController(); - slicer->RemoveObserver(m_SliceObserverTag3); - } } void QmitkControlVisualizationPropertiesView::Activated() { } void QmitkControlVisualizationPropertiesView::Deactivated() { } +void QmitkControlVisualizationPropertiesView::FlipPeaks() +{ + if (m_SelectedNode.IsNull() || dynamic_cast(m_SelectedNode->GetData())==nullptr) + return; + + mitk::Image::Pointer image = dynamic_cast(m_SelectedNode->GetData()); + + typedef mitk::ImageToItk< mitk::PeakImage::ItkPeakImageType > CasterType; + CasterType::Pointer caster = CasterType::New(); + caster->SetInput(image); + caster->Update(); + mitk::PeakImage::ItkPeakImageType::Pointer itkImg = caster->GetOutput(); + + itk::FlipPeaksFilter< float >::Pointer flipper = itk::FlipPeaksFilter< float >::New(); + flipper->SetInput(itkImg); + flipper->SetFlipX(m_Controls->m_FlipPeaksX->isChecked()); + flipper->SetFlipY(m_Controls->m_FlipPeaksY->isChecked()); + flipper->SetFlipZ(m_Controls->m_FlipPeaksZ->isChecked()); + flipper->Update(); + + mitk::Image::Pointer resultImage = dynamic_cast(mitk::PeakImage::New().GetPointer()); + mitk::CastToMitkImage(flipper->GetOutput(), resultImage); + resultImage->SetVolume(flipper->GetOutput()->GetBufferPointer()); + m_SelectedNode->SetData(resultImage); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + void QmitkControlVisualizationPropertiesView::Toggle3DClipping(bool enabled) { if (!enabled || m_SelectedNode.IsNull() || dynamic_cast(m_SelectedNode->GetData())==nullptr) return; m_SelectedNode->SetBoolProperty( "Fiber3DClippingPlaneFlip", m_Controls->m_FlipClipBox->isChecked() ); if (m_Controls->m_Clip0->isChecked()) { m_SelectedNode->SetIntProperty( "Fiber3DClippingPlaneId", 0 ); Set3DClippingPlane(true, m_SelectedNode, ""); } else if (m_Controls->m_Clip1->isChecked()) { m_SelectedNode->SetIntProperty( "Fiber3DClippingPlaneId", 1 ); Set3DClippingPlane(false, m_SelectedNode, "axial"); } else if (m_Controls->m_Clip2->isChecked()) { m_SelectedNode->SetIntProperty( "Fiber3DClippingPlaneId", 2 ); Set3DClippingPlane(false, m_SelectedNode, "sagittal"); } else if (m_Controls->m_Clip3->isChecked()) { m_SelectedNode->SetIntProperty( "Fiber3DClippingPlaneId", 3 ); Set3DClippingPlane(false, m_SelectedNode, "coronal"); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::OnAxialChanged(const itk::EventObject& ) { mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetDataStorage()->GetAll(); for (unsigned int i=0; iSize(); ++i) { mitk::DataNode::Pointer node = nodes->GetElement(i); int plane_id = -1; node->GetIntProperty("Fiber3DClippingPlaneId", plane_id); if (plane_id==1) Set3DClippingPlane(false, node, "axial"); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::OnCoronalChanged(const itk::EventObject& ) { mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetDataStorage()->GetAll(); for (unsigned int i=0; iSize(); ++i) { mitk::DataNode::Pointer node = nodes->GetElement(i); int plane_id = -1; node->GetIntProperty("Fiber3DClippingPlaneId", plane_id); if (plane_id==3) Set3DClippingPlane(false, node, "coronal"); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::OnSagittalChanged(const itk::EventObject& ) { mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetDataStorage()->GetAll(); for (unsigned int i=0; iSize(); ++i) { mitk::DataNode::Pointer node = nodes->GetElement(i); int plane_id = -1; node->GetIntProperty("Fiber3DClippingPlaneId", plane_id); if (plane_id==2) Set3DClippingPlane(false, node, "sagittal"); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::Set3DClippingPlane(bool disable, mitk::DataNode* node, std::string plane) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow && node && dynamic_cast(node->GetData())) { mitk::Vector3D planeNormal; planeNormal.Fill(0.0); if (!disable) { mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString(plane.c_str()))->GetSliceNavigationController(); mitk::PlaneGeometry::ConstPointer planeGeo = slicer->GetCurrentPlaneGeometry(); //generate according cutting planes based on the view position planeNormal = planeGeo->GetNormal(); float tmp1 = planeGeo->GetOrigin()[0] * planeNormal[0]; float tmp2 = planeGeo->GetOrigin()[1] * planeNormal[1]; float tmp3 = planeGeo->GetOrigin()[2] * planeNormal[2]; float distance = tmp1 + tmp2 + tmp3; //attention, correct normalvector planeNormal *= distance; if (distance<0) node->SetBoolProperty( "Fiber3DClippingPlaneSecondFlip", true ); else node->SetBoolProperty( "Fiber3DClippingPlaneSecondFlip", false ); } node->SetProperty( "Fiber3DClippingPlane", mitk::Vector3DProperty::New( planeNormal ) ); dynamic_cast(node->GetData())->RequestUpdate(); } } void QmitkControlVisualizationPropertiesView::VisibleOdfsON_T() { m_GlyIsOn_T = m_Controls->m_VisibleOdfsON_T->isChecked(); if (m_NodeUsedForOdfVisualization.IsNull()) { MITK_WARN << "ODF visualization activated but m_NodeUsedForOdfVisualization is nullptr"; return; } m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_T", m_GlyIsOn_T); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::VisibleOdfsON_C() { m_GlyIsOn_C = m_Controls->m_VisibleOdfsON_C->isChecked(); if (m_NodeUsedForOdfVisualization.IsNull()) { MITK_WARN << "ODF visualization activated but m_NodeUsedForOdfVisualization is nullptr"; return; } m_NodeUsedForOdfVisualization->SetBoolProperty("VisibleOdfs_C", m_GlyIsOn_C); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } bool QmitkControlVisualizationPropertiesView::IsPlaneRotated() { mitk::Image* currentImage = dynamic_cast( m_NodeUsedForOdfVisualization->GetData() ); if( currentImage == nullptr ) { MITK_ERROR << " Casting problems. Returning false"; return false; } mitk::Vector3D imageNormal0 = currentImage->GetSlicedGeometry()->GetAxisVector(0); mitk::Vector3D imageNormal1 = currentImage->GetSlicedGeometry()->GetAxisVector(1); mitk::Vector3D imageNormal2 = currentImage->GetSlicedGeometry()->GetAxisVector(2); imageNormal0.Normalize(); imageNormal1.Normalize(); imageNormal2.Normalize(); auto renderWindowPart = this->GetRenderWindowPart(); double eps = 0.000001; // for all 2D renderwindows of the render window part check alignment { mitk::PlaneGeometry::ConstPointer displayPlane = dynamic_cast ( renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()->GetCurrentWorldPlaneGeometry() ); if (displayPlane.IsNull()) { return false; } mitk::Vector3D normal = displayPlane->GetNormal(); normal.Normalize(); int test = 0; if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal0.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal1.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal2.GetVnlVector()))-1) > eps ) { test++; } if (test==3) { return true; } } { mitk::PlaneGeometry::ConstPointer displayPlane = dynamic_cast ( renderWindowPart->GetQmitkRenderWindow("sagittal")->GetRenderer()->GetCurrentWorldPlaneGeometry() ); if (displayPlane.IsNull()) { return false; } mitk::Vector3D normal = displayPlane->GetNormal(); normal.Normalize(); int test = 0; if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal0.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal1.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal2.GetVnlVector()))-1) > eps ) { test++; } if (test==3) { return true; } } { mitk::PlaneGeometry::ConstPointer displayPlane = dynamic_cast ( renderWindowPart->GetQmitkRenderWindow("coronal")->GetRenderer()->GetCurrentWorldPlaneGeometry() ); if (displayPlane.IsNull()) { return false; } mitk::Vector3D normal = displayPlane->GetNormal(); normal.Normalize(); int test = 0; if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal0.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal1.GetVnlVector()))-1) > eps ) { test++; } if( fabs(fabs(dot_product(normal.GetVnlVector(),imageNormal2.GetVnlVector()))-1) > eps ) { test++; } if (test==3) { return true; } } return false; } void QmitkControlVisualizationPropertiesView::ShowMaxNumberChanged() { int maxNr = m_Controls->m_ShowMaxNumber->value(); if ( maxNr < 1 ) { m_Controls->m_ShowMaxNumber->setValue( 1 ); maxNr = 1; } if ( dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) ) { m_SelectedNode->SetIntProperty("ShowMaxNumber", maxNr); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::NormalizationDropdownChanged(int normDropdown) { typedef mitk::OdfNormalizationMethodProperty PropType; PropType::Pointer normMeth = PropType::New(); switch(normDropdown) { case 0: normMeth->SetNormalizationToMinMax(); break; case 1: normMeth->SetNormalizationToMax(); break; case 2: normMeth->SetNormalizationToNone(); break; case 3: normMeth->SetNormalizationToGlobalMax(); break; default: normMeth->SetNormalizationToMinMax(); } if ( dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) ) { m_SelectedNode->SetProperty("Normalization", normMeth.GetPointer()); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::ScalingFactorChanged(double scalingFactor) { if ( dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) ) { m_SelectedNode->SetFloatProperty("Scaling", scalingFactor); } if (auto renderWindowPart = this->GetRenderWindowPart()) { renderWindowPart->RequestUpdate(); } } void QmitkControlVisualizationPropertiesView::AdditionalScaling(int additionalScaling) { typedef mitk::OdfScaleByProperty PropType; PropType::Pointer scaleBy = PropType::New(); switch(additionalScaling) { case 0: scaleBy->SetScaleByNothing(); break; case 1: scaleBy->SetScaleByGFA(); //m_Controls->params_frame->setVisible(true); break; #ifdef DIFFUSION_IMAGING_EXTENDED case 2: scaleBy->SetScaleByPrincipalCurvature(); // commented in for SPIE paper, Principle curvature scaling //m_Controls->params_frame->setVisible(true); break; #endif default: scaleBy->SetScaleByNothing(); } if ( dynamic_cast(m_SelectedNode->GetData()) || dynamic_cast(m_SelectedNode->GetData()) ) { m_SelectedNode->SetProperty("Normalization", scaleBy.GetPointer()); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkControlVisualizationPropertiesView::ScalingCheckbox() { m_Controls->m_ScalingFrame->setVisible( m_Controls->m_ScalingCheckbox->isChecked() ); if( ! m_Controls->m_ScalingCheckbox->isChecked() ) { m_Controls->m_AdditionalScaling->setCurrentIndex(0); m_Controls->m_ScalingFactor->setValue(1.0); } } void QmitkControlVisualizationPropertiesView::Fiber2DfadingEFX() { if (m_SelectedNode && dynamic_cast(m_SelectedNode->GetData()) ) { bool currentMode; m_SelectedNode->GetBoolProperty("Fiber2DfadeEFX", currentMode); m_SelectedNode->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(!currentMode)); dynamic_cast(m_SelectedNode->GetData())->RequestUpdate2D(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::FiberSlicingThickness2D() { if (m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { float fibThickness = m_Controls->m_FiberThicknessSlider->value() * 0.1; float currentThickness = 0; m_SelectedNode->GetFloatProperty("Fiber2DSliceThickness", currentThickness); if ( fabs(fibThickness-currentThickness) < 0.001 ) { return; } m_SelectedNode->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(fibThickness)); dynamic_cast(m_SelectedNode->GetData())->RequestUpdate2D(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::FiberSlicingUpdateLabel(int value) { QString label = "Range %1 mm"; label = label.arg(value * 0.1); m_Controls->label_range->setText(label); FiberSlicingThickness2D(); } - -void QmitkControlVisualizationPropertiesView::SetFiberBundleOpacity(const itk::EventObject& /*e*/) +void QmitkControlVisualizationPropertiesView::SetCustomColor(const itk::EventObject& /*e*/) { - if(m_SelectedNode) + if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { + float color[3]; + m_SelectedNode->GetColor(color); mitk::FiberBundle::Pointer fib = dynamic_cast(m_SelectedNode->GetData()); - fib->RequestUpdate(); + fib->SetFiberColors(color[0]*255, color[1]*255, color[2]*255); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } -} - - -void QmitkControlVisualizationPropertiesView::SetFiberBundleCustomColor(const itk::EventObject& /*e*/) -{ - if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) + else if (m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { float color[3]; m_SelectedNode->GetColor(color); - mitk::FiberBundle::Pointer fib = dynamic_cast(m_SelectedNode->GetData()); - fib->SetFiberColors(color[0]*255, color[1]*255, color[2]*255); + mitk::PeakImage::Pointer img = dynamic_cast(m_SelectedNode->GetData()); + img->SetCustomColor(color[0]*255, color[1]*255, color[2]*255); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } -void QmitkControlVisualizationPropertiesView::BundleRepresentationResetColoring() +void QmitkControlVisualizationPropertiesView::ResetColoring() { if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { mitk::FiberBundle::Pointer fib = dynamic_cast(m_SelectedNode->GetData()); fib->ColorFibersByOrientation(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } + else if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) + { + mitk::PeakImage::Pointer fib = dynamic_cast(m_SelectedNode->GetData()); + fib->ColorByOrientation(); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } } void QmitkControlVisualizationPropertiesView::PlanarFigureFocus() { if(m_SelectedNode) { mitk::PlanarFigure* _PlanarFigure = 0; _PlanarFigure = dynamic_cast (m_SelectedNode->GetData()); if (_PlanarFigure && _PlanarFigure->GetPlaneGeometry()) { QmitkRenderWindow* selectedRenderWindow = 0; bool PlanarFigureInitializedWindow = false; auto renderWindowPart = this->GetRenderWindowPart(OPEN); QmitkRenderWindow* axialRenderWindow = renderWindowPart->GetQmitkRenderWindow("axial"); if (m_SelectedNode->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, axialRenderWindow->GetRenderer())) { selectedRenderWindow = axialRenderWindow; } QmitkRenderWindow* sagittalRenderWindow = renderWindowPart->GetQmitkRenderWindow("sagittal"); if (!selectedRenderWindow && m_SelectedNode->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, sagittalRenderWindow->GetRenderer())) { selectedRenderWindow = sagittalRenderWindow; } QmitkRenderWindow* coronalRenderWindow = renderWindowPart->GetQmitkRenderWindow("coronal"); if (!selectedRenderWindow && m_SelectedNode->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, coronalRenderWindow->GetRenderer())) { selectedRenderWindow = coronalRenderWindow; } QmitkRenderWindow* _3DRenderWindow = renderWindowPart->GetQmitkRenderWindow("3d"); if (!selectedRenderWindow && m_SelectedNode->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, _3DRenderWindow->GetRenderer())) { selectedRenderWindow = _3DRenderWindow; } const mitk::PlaneGeometry* _PlaneGeometry = _PlanarFigure->GetPlaneGeometry(); mitk::VnlVector normal = _PlaneGeometry->GetNormalVnl(); mitk::PlaneGeometry::ConstPointer worldGeometry1 = axialRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); mitk::PlaneGeometry::ConstPointer _Plane1 = dynamic_cast( worldGeometry1.GetPointer() ); mitk::VnlVector normal1 = _Plane1->GetNormalVnl(); mitk::PlaneGeometry::ConstPointer worldGeometry2 = sagittalRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); mitk::PlaneGeometry::ConstPointer _Plane2 = dynamic_cast( worldGeometry2.GetPointer() ); mitk::VnlVector normal2 = _Plane2->GetNormalVnl(); mitk::PlaneGeometry::ConstPointer worldGeometry3 = coronalRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); mitk::PlaneGeometry::ConstPointer _Plane3 = dynamic_cast( worldGeometry3.GetPointer() ); mitk::VnlVector normal3 = _Plane3->GetNormalVnl(); normal[0] = fabs(normal[0]); normal[1] = fabs(normal[1]); normal[2] = fabs(normal[2]); normal1[0] = fabs(normal1[0]); normal1[1] = fabs(normal1[1]); normal1[2] = fabs(normal1[2]); normal2[0] = fabs(normal2[0]); normal2[1] = fabs(normal2[1]); normal2[2] = fabs(normal2[2]); normal3[0] = fabs(normal3[0]); normal3[1] = fabs(normal3[1]); normal3[2] = fabs(normal3[2]); double ang1 = angle(normal, normal1); double ang2 = angle(normal, normal2); double ang3 = angle(normal, normal3); if(ang1 < ang2 && ang1 < ang3) { selectedRenderWindow = axialRenderWindow; } else { if(ang2 < ang3) { selectedRenderWindow = sagittalRenderWindow; } else { selectedRenderWindow = coronalRenderWindow; } } // make node visible if (selectedRenderWindow) { const mitk::Point3D& centerP = _PlaneGeometry->GetOrigin(); selectedRenderWindow->GetSliceNavigationController()->ReorientSlices( centerP, _PlaneGeometry->GetNormal()); } } // set interactor for new node (if not already set) mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(m_SelectedNode->GetDataInteractor().GetPointer()); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New(); us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" ); figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule ); figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule ); figureInteractor->SetDataNode( m_SelectedNode ); } m_SelectedNode->SetProperty("planarfigure.iseditable",mitk::BoolProperty::New(true)); } } void QmitkControlVisualizationPropertiesView::SetInteractor() { // BUG 19179 // typedef std::vector Container; // Container _NodeSet = this->GetDataManagerSelection(); // mitk::DataNode* node = 0; // mitk::FiberBundle* bundle = 0; // mitk::FiberBundleInteractor::Pointer bundleInteractor = 0; // // finally add all nodes to the model // for(Container::const_iterator it=_NodeSet.begin(); it!=_NodeSet.end() // ; it++) // { // node = const_cast(*it); // bundle = dynamic_cast(node->GetData()); // if(bundle) // { // bundleInteractor = dynamic_cast(node->GetInteractor()); // if(bundleInteractor.IsNotNull()) // mitk::GlobalInteraction::GetInstance()->RemoveInteractor(bundleInteractor); // if(!m_Controls->m_Crosshair->isChecked()) // { // m_Controls->m_Crosshair->setChecked(false); // this->GetActiveStdMultiWidget()->GetRenderWindow4()->setCursor(Qt::ArrowCursor); // m_CurrentPickingNode = 0; // } // else // { // m_Controls->m_Crosshair->setChecked(true); // bundleInteractor = mitk::FiberBundleInteractor::New("FiberBundleInteractor", node); // mitk::GlobalInteraction::GetInstance()->AddInteractor(bundleInteractor); // this->GetActiveStdMultiWidget()->GetRenderWindow4()->setCursor(Qt::CrossCursor); // m_CurrentPickingNode = node; // } // } // } } void QmitkControlVisualizationPropertiesView::TubeRadiusChanged() { if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { float newRadius = m_Controls->m_TubeWidth->value(); if (newRadius>0) m_SelectedNode->SetBoolProperty( "light.enable_light", true); else m_SelectedNode->SetBoolProperty( "light.enable_light", false); m_SelectedNode->SetFloatProperty("shape.tuberadius", newRadius); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::LineWidthChanged() { if(m_SelectedNode && dynamic_cast(m_SelectedNode->GetData())) { int newWidth = m_Controls->m_LineWidth->value(); int currentWidth = 0; m_SelectedNode->GetIntProperty("shape.linewidth", currentWidth); if (currentWidth==newWidth) return; m_SelectedNode->SetIntProperty("shape.linewidth", newWidth); dynamic_cast(m_SelectedNode->GetData())->RequestUpdate(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkControlVisualizationPropertiesView::Welcome() { berry::PlatformUI::GetWorkbench()->GetIntroManager() ->ShowIntro(GetSite()->GetWorkbenchWindow(), false); } void QmitkControlVisualizationPropertiesView::OnTensorViewChanged() { if( m_NodeUsedForOdfVisualization.IsNotNull() ) { if( m_Controls-> m_EllipsoidViewRadioButton-> isChecked() ) { if ( m_SelectedNode and dynamic_cast( m_SelectedNode->GetData() ) ) { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.SwitchTensorView", mitk::BoolProperty::New( true ) ); mitk::OdfNormalizationMethodProperty::Pointer normalizationProperty = mitk::OdfNormalizationMethodProperty::New( mitk::ODFN_MAX ); m_SelectedNode-> SetProperty( "Normalization", normalizationProperty ); // type OdfNormalizationMethodProperty m_Controls-> m_NormalizationDropdown->setCurrentIndex ( dynamic_cast( m_SelectedNode->GetProperty("Normalization") )->GetValueAsId() ); } else { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.SwitchTensorView", mitk::BoolProperty::New( false ) ); m_Controls-> m_OdfViewRadioButton-> setChecked(true); m_Controls-> m_EllipsoidViewRadioButton-> setEnabled(false); } } else if( m_Controls-> m_OdfViewRadioButton-> isChecked() ) { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.SwitchTensorView", mitk::BoolProperty::New( false ) ); } mitk::RenderingManager::GetInstance()-> RequestUpdateAll(); } else { MITK_DEBUG << "QmitkControlVisualizationPropertiesView::OnTensorViewChanged()" " was called but m_NodeUsedForOdfVisualization was Null."; } } void QmitkControlVisualizationPropertiesView::OnColourisationModeChanged() { if( m_SelectedNode and m_NodeUsedForOdfVisualization.IsNotNull() ) { if( m_Controls-> m_colouriseRainbowRadioButton-> isChecked() ) { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.ColourisationModeBit", mitk::BoolProperty::New( false ) ); } else if ( m_Controls-> m_colouriseSimpleRadioButton-> isChecked() ) { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.ColourisationModeBit", mitk::BoolProperty::New( true ) ); } mitk::RenderingManager::GetInstance()-> RequestUpdateAll(); } else { MITK_DEBUG << "QmitkControlVisualizationPropertiesView::OnColourisationModeChanged()" " was called but m_NodeUsedForOdfVisualization was Null."; } } void QmitkControlVisualizationPropertiesView::OnRandomModeChanged() { if( m_SelectedNode and m_NodeUsedForOdfVisualization.IsNotNull() ) { if( m_Controls-> m_randomModeRadioButton-> isChecked() ) { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.RandomModeBit", mitk::BoolProperty::New( true ) ); } else if ( m_Controls-> m_orderedModeRadioButton-> isChecked() ) { m_SelectedNode-> SetProperty( "DiffusionCore.Rendering.OdfVtkMapper.RandomModeBit", mitk::BoolProperty::New( false ) ); } mitk::RenderingManager::GetInstance()-> RequestUpdateAll(); } else { MITK_DEBUG << "QmitkControlVisualizationPropertiesView::OnRandomModeChanged()" " was called but m_NodeUsedForOdfVisualization was Null."; } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.h index b3871b9d68..d03f11eed5 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesView.h @@ -1,167 +1,162 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _QMITKControlVisualizationPropertiesView_H_INCLUDED #define _QMITKControlVisualizationPropertiesView_H_INCLUDED #include #include #include "berryISelectionListener.h" #include "berryIStructuredSelection.h" #include "berryISizeProvider.h" #include "ui_QmitkControlVisualizationPropertiesViewControls.h" #include "mitkEnumerationProperty.h" #include /*! * \ingroup org_mitk_gui_qt_diffusionquantification_internal * * \brief QmitkControlVisualizationPropertiesView * * Document your class here. */ class QmitkControlVisualizationPropertiesView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { friend struct CvpSelListener; // this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) Q_OBJECT public: static const std::string VIEW_ID; QmitkControlVisualizationPropertiesView(); virtual ~QmitkControlVisualizationPropertiesView(); virtual void CreateQtPartControl(QWidget *parent) override; /// \brief Creation of the connections of main and control widget virtual void CreateConnections(); protected slots: void VisibleOdfsON_S(); void VisibleOdfsON_T(); void VisibleOdfsON_C(); - void ShowMaxNumberChanged(); void NormalizationDropdownChanged(int); void ScalingFactorChanged(double); void AdditionalScaling(int); void ScalingCheckbox(); - void OnThickSlicesModeSelected( QAction* action ); void OnTSNumChanged(int num); - - void BundleRepresentationResetColoring(); + void ResetColoring(); void PlanarFigureFocus(); void Fiber2DfadingEFX(); void FiberSlicingThickness2D(); void FiberSlicingUpdateLabel(int); void LineWidthChanged(); void TubeRadiusChanged(); - void SetInteractor(); void Toggle3DClipping(bool enabled=true); - + void FlipPeaks(); void Welcome(); /// \brief Slot function for switching tensor view between ODF and ellipsoids from tensors. void OnTensorViewChanged(); /// \brief Slot function for switching colourisation mode of glyphs. void OnColourisationModeChanged(); /// \brief Slot function for switching glyph placement mode. void OnRandomModeChanged(); protected: virtual void SetFocus() override; virtual void Activated() override; virtual void Deactivated() override; virtual void Visible() override; virtual void Hidden() override; virtual void NodeRemoved(const mitk::DataNode* node) override; /// \brief called by QmitkAbstractView when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; virtual void NodeAdded(const mitk::DataNode *node) override; - void SetFiberBundleCustomColor(const itk::EventObject& /*e*/); - void SetFiberBundleOpacity(const itk::EventObject& /*e*/); + void SetCustomColor(const itk::EventObject& /*e*/); bool IsPlaneRotated(); void SliceRotation(const itk::EventObject&); void OnAxialChanged(const itk::EventObject& e); void OnCoronalChanged(const itk::EventObject& e); void OnSagittalChanged(const itk::EventObject& e); void Set3DClippingPlane(bool disable, mitk::DataNode *node, std::string plane); Ui::QmitkControlVisualizationPropertiesViewControls* m_Controls; QScopedPointer m_SelListener; berry::IStructuredSelection::ConstPointer m_CurrentSelection; mitk::DataNode::Pointer m_NodeUsedForOdfVisualization; QIcon* m_IconTexOFF; QIcon* m_IconTexON; QIcon* m_IconGlyOFF_T; QIcon* m_IconGlyON_T; QIcon* m_IconGlyOFF_C; QIcon* m_IconGlyON_C; QIcon* m_IconGlyOFF_S; QIcon* m_IconGlyON_S; bool m_TexIsOn; bool m_GlyIsOn_T; bool m_GlyIsOn_C; bool m_GlyIsOn_S; int currentThickSlicesMode; QLabel* m_TSLabel; QMenu* m_MyMenu; // for planarfigure and bundle handling: mitk::DataNode::Pointer m_SelectedNode; mitk::DataNode* m_CurrentPickingNode; - unsigned long m_FiberBundleObserverTag; - unsigned long m_FiberBundleObserveOpacityTag; + unsigned long m_ColorPropertyObserverTag; + unsigned long m_OpacityPropertyObserverTag; mitk::ColorProperty::Pointer m_Color; mitk::FloatProperty::Pointer m_Opacity; int m_SliceObserverTag1; int m_SliceObserverTag2; int m_SliceObserverTag3; }; #endif // _QMITKControlVisualizationPropertiesView_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui index 4840495a9e..b06fcea149 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui @@ -1,861 +1,946 @@ QmitkControlVisualizationPropertiesViewControls 0 0 567 619 0 100 0 0 QmitkTemplate 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Multislice Projection MIP QToolButton::MenuButtonPopup Qt::NoArrow QFrame::NoFrame QFrame::Plain 0 0 0 0 Toggle visibility of ODF glyphs (axial) :/QmitkDiffusionImaging/glyphsoff_T.png :/QmitkDiffusionImaging/glyphson_T.png:/QmitkDiffusionImaging/glyphsoff_T.png true false Toggle visibility of ODF glyphs (sagittal) :/QmitkDiffusionImaging/glyphsoff_S.png :/QmitkDiffusionImaging/glyphson_S.png:/QmitkDiffusionImaging/glyphsoff_S.png true false Toggle visibility of ODF glyphs (coronal) :/QmitkDiffusionImaging/glyphsoff_C.png :/QmitkDiffusionImaging/glyphson_C.png:/QmitkDiffusionImaging/glyphsoff_C.png true false #Glyphs 9999 Qt::Horizontal 20 20 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Scaling QFrame::NoFrame QFrame::Plain 0 0 0 0 false None By GFA By ASR * Additional scaling factor 3 999999999.000000000000000 0.100000000000000 1.000000000000000 QFrame::NoFrame QFrame::Plain 0 0 0 0 &ODF View true buttonGroup_2 true &Rainbow colorization true buttonGroup true E&llipsoid View buttonGroup_2 false &Simple colorization buttonGroup ODF normalization false Min-Max Max None true Random Placement true buttonGroup_3 true Orderer Placement buttonGroup_3 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Reset to Default Coloring :/QmitkDiffusionImaging/reset.png:/QmitkDiffusionImaging/reset.png Position Crosshair by 3D-Click :/QmitkDiffusionImaging/crosshair.png:/QmitkDiffusionImaging/crosshair.png true false 2D Fiberfading on/off Qt::Horizontal 40 20 QFrame::NoFrame QFrame::Raised 0 0 0 0 2D Clipping 100 10 10 10 Qt::Horizontal 90 0 10000 16777215 Range QFrame::NoFrame QFrame::Raised 0 0 0 0 1 10 Tube Radius Line Width 4 0.100000000000000 3D Fiber Clipping 0 0 0 0 0 Sagittal No clipping true Coronal Axial Flipp Clipping Direction 50 false false <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#ff0000;">One or more slices are rotated. ODF Visualisation is not possible in rotated planes. Use 'Reinit' on the image node to reset. </span></p></body></html> Qt::AutoText true + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + z + + + + + + + x + + + + + + + + 0 + 0 + + + + Flip Peaks + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + y + + + + + + + Reset to Default Coloring + + + + + + + :/QmitkDiffusionImaging/reset.png:/QmitkDiffusionImaging/reset.png + + + + + + Qt::Vertical 20 40 QmitkDataStorageComboBox.h - + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp index b4a266281a..5c1b930cb7 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/mitkPluginActivator.cpp @@ -1,69 +1,73 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPluginActivator.h" #include "src/internal/Perspectives/QmitkDiffusionDefaultPerspective.h" #include "src/internal/QmitkDiffusionDicomImportView.h" #include "src/internal/QmitkDicomTractogramTagEditorView.h" #include "src/internal/QmitkControlVisualizationPropertiesView.h" #include "QmitkNodeDescriptorManager.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateProperty.h" #include "mitkNodePredicateIsDWI.h" #include namespace mitk { void PluginActivator::start(ctkPluginContext* context) { BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionDefaultPerspective, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkDiffusionDicomImport, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkDicomTractogramTagEditorView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkControlVisualizationPropertiesView, context) // Q_UNUSED(context) QmitkNodeDescriptorManager* manager = QmitkNodeDescriptorManager::GetInstance(); mitk::NodePredicateIsDWI::Pointer isDiffusionImage = mitk::NodePredicateIsDWI::New(); QmitkNodeDescriptor* desc = new QmitkNodeDescriptor(QObject::tr("DiffusionImage"), QString(":/QmitkDiffusionImaging/DiffData24.png"), isDiffusionImage, manager); manager->AddDescriptor(desc); mitk::NodePredicateDataType::Pointer isTensorImage = mitk::NodePredicateDataType::New("TensorImage"); manager->AddDescriptor(new QmitkNodeDescriptor(QObject::tr("TensorImage"), QString(":/QmitkDiffusionImaging/tensor.png"), isTensorImage, manager)); mitk::NodePredicateDataType::Pointer isOdfImage = mitk::NodePredicateDataType::New("OdfImage"); manager->AddDescriptor(new QmitkNodeDescriptor(QObject::tr("OdfImage"), QString(":/QmitkDiffusionImaging/odf.png"), isOdfImage, manager)); mitk::NodePredicateDataType::Pointer isFiberBundle = mitk::NodePredicateDataType::New("FiberBundle"); manager->AddDescriptor(new QmitkNodeDescriptor(QObject::tr("FiberBundle"), QString(":/QmitkDiffusionImaging/tractogram.png"), isFiberBundle, manager)); + mitk::NodePredicateDataType::Pointer isPeakImage = mitk::NodePredicateDataType::New("PeakImage"); + manager->AddDescriptor(new QmitkNodeDescriptor(QObject::tr("PeakImage"), QString(":/QmitkDiffusionImaging/odf_peaks.png"), isPeakImage, manager)); + + mitk::NodePredicateDataType::Pointer isConnectomicsNetwork = mitk::NodePredicateDataType::New("ConnectomicsNetwork"); manager->AddDescriptor(new QmitkNodeDescriptor(QObject::tr("ConnectomicsNetwork"), QString(":/QmitkDiffusionImaging/ConnectomicsNetwork.png"), isConnectomicsNetwork, manager)); mitk::NodePredicateDataType::Pointer isTractographyForestNetwork = mitk::NodePredicateDataType::New("TractographyForest"); manager->AddDescriptor(new QmitkNodeDescriptor(QObject::tr("TractographyForest"), QString(":/QmitkDiffusionImaging/ml_tractogram.png"), isTractographyForestNetwork, manager)); } void PluginActivator::stop(ctkPluginContext* context) { Q_UNUSED(context) } }