diff --git a/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake index 127c37a4a2..24e5461c37 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake @@ -1,38 +1,39 @@ #----------------------------------------------------------------------------- # MITK Data #----------------------------------------------------------------------------- # Sanity checks if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") endif() set(proj MITK-Data) set(proj_DEPENDENCIES) set(MITK-Data_DEPENDS ${proj}) if(BUILD_TESTING) - set(revision_tag 826b368f) # first 8 characters of hash-tag + + set(revision_tag f81328b8) # first 8 characters of hash-tag # ^^^^^^^^ these are just to check correct length of hash part ExternalProject_Add(${proj} SOURCE_DIR ${proj} # GIT_REPOSITORY https://phabricator.mitk.org/diffusion/MD/mitk-data.git # GIT_TAG ${revision_tag} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/mitk-data_${revision_tag}.tar.gz UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS ${proj_DEPENDENCIES} ) set(MITK_DATA_DIR ${CMAKE_CURRENT_BINARY_DIR}/${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif(BUILD_TESTING) diff --git a/Modules/Classification/DataCollection/CMakeLists.txt b/Modules/Classification/DataCollection/CMakeLists.txt index e9c1cf6c69..bf410b0207 100644 --- a/Modules/Classification/DataCollection/CMakeLists.txt +++ b/Modules/Classification/DataCollection/CMakeLists.txt @@ -1,12 +1,12 @@ MITK_CREATE_MODULE(DataCollection #<-- module name SUBPROJECTS INCLUDE_DIRS DataHolder ReaderWriter Iterators Utilities#<-- sub-folders of module INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} - DEPENDS MitkDiffusionCore MitkDiffusionIO MitkFiberTracking MitkLegacyIO #<-- modules on which your module depends on + DEPENDS MitkCore # MitkLegacyIO #<-- modules on which your module depends on PACKAGE_DEPENDS Qt5|Core Eigen # WARNINGS_AS_ERRORS ) if(BUILD_TESTING) ADD_SUBDIRECTORY(Testing) endif() diff --git a/Modules/Classification/DataCollection/DataHolder/mitkDataCollection.h b/Modules/Classification/DataCollection/DataHolder/mitkDataCollection.h index d512d79bf8..491eb69dd2 100644 --- a/Modules/Classification/DataCollection/DataHolder/mitkDataCollection.h +++ b/Modules/Classification/DataCollection/DataHolder/mitkDataCollection.h @@ -1,288 +1,288 @@ /*=================================================================== 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. ===================================================================*/ #pragma warning (disable : 4996) #ifndef mitkDataCollection_H_ #define mitkDataCollection_H_ -#include -#include -#include "itkObjectFactory.h" -#include "mitkCommon.h" +//#include +//#include +//#include "itkObjectFactory.h" +//#include "mitkCommon.h" #include #include #include #include /** * \brief DataCollection - Class to facilitate loading/accessing structured data * * Data is grouped into a collection that may contain further (sub) collections or images. * * Exemplary structure * * Collection (e.g. Patient) * | * |-- Sub-Collection1 (e.g. follow-up 1) * | | * | |-- DataItem (e.g. T1) * | |-- DataItem (e.g. T2) * | * |-- Sub-Collection2 (e.g. follow-up 2) * | | * | |-- DataItem (e.g. T1) * | |-- DataItem (e.g. T2) * */ namespace mitk { class MITKDATACOLLECTION_EXPORT DataCollection : public BaseData { public: mitkClassMacro(DataCollection, BaseData) itkFactorylessNewMacro(Self) itkCloneMacro(Self) // Needed methods from Basedata virtual void UpdateOutputInformation(); virtual void SetRequestedRegionToLargestPossibleRegion(); virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); virtual bool VerifyRequestedRegion(); virtual void SetRequestedRegion(const itk::DataObject *); void Init(std::string name); /** * @brief AddData Add a data item * @param data Images/Fibers/DataCollections * @param name name that allows identifying this data (e.g. a category T2, Segmentation , etc ...) * @param description * @return */ size_t AddData(DataObject::Pointer data, std::string name, std::string filePath = ""); /** * @brief SetName - Sets name of DataCollection * @param name */ void SetName(std::string name); std::string GetName() const; std::string GetDataFilePath(size_t index) const; /** * @brief NameToIndex - Get index from data item name * @param name * @return */ size_t NameToIndex(std::string name); /** * @brief IndexToName - Get name from index * @param index * @return */ std::string IndexToName(size_t index) const; /** * @brief HasElement - check if element with this name exists in collection * @param name * @return */ bool HasElement(std::string name); /** * @brief HasElement - check if element with this index exists in collection * @param index * @return */ bool HasElement(size_t index); /** * @brief Size - number of data items in collection * @return */ size_t Size() const; /** * @brief SetData - set/update data item by index * @param data * @param index */ void SetData(itk::DataObject::Pointer data, size_t index); /** * @brief SetData - set/update data item by name * @param data * @param name */ void SetData(itk::DataObject::Pointer data, std::string name); /** * @brief GetData Get original data by index * * To ensure a mitk::Image is returned use \ref mitk::GetMitkImage * * @param index * @return */ itk::DataObject::Pointer GetData(size_t index); /** * @brief GetData Get original data by name * * To ensure a mitk::Image is returned use \ref mitk::GetMitkImage * * @param name * @return */ itk::DataObject::Pointer GetData(std::string name); /** * @brief GetMitkImage - casts data to mitk::Image and returns it * * \note returns NULL is object is no mitk::Image or itk::Image * * @param index * @return */ mitk::Image::Pointer GetMitkImage(size_t index); /** * @brief GetMitkImage - casts data to mitk::Image and returns it * * \note returns NULL is object is no mitk::Image or itk::Image * * @param name * @return */ mitk::Image::Pointer GetMitkImage(std::string name); /** * @brief GetMitkImage - casts data to privided itk::Image pointer */ template ImageType GetItkImage(size_t index, ImageType* itkImage); /** * @brief GetMitkImage - casts data to privided itk::Image pointer */ template ImageType GetItkImage(std::string name, ImageType* itkImage); itk::DataObject::Pointer& operator[](size_t index); itk::DataObject::Pointer& operator[](std::string &name); /** * @brief SetNameForIndex - sets name for given data item by index * @param index * @param name */ void SetNameForIndex(size_t index, std::string &name); /** * @brief SetXMLFile - sets xml file to which data collection is saved */ void SetXMLFile(std::string absoluteXMlFile); /** * @brief SetXMLFile - gets xml file to which data collection is supposed to be saved */ std::string GetXMLFile(); /** * @brief SetParent - sets the parent collection * @param parent */ void SetParent(mitk::DataCollection* parent); /** * @brief GetParent - returns the parent collection if available else null is returned * @return */ mitk::DataCollection* GetParent(); /** * @brief RemoveIndex - removes element at index * @param index * @return */ bool RemoveIndex(size_t index); /** * @brief RemoveElement - removes element with name * @param name * @return */ bool RemoveElement(std::string& name); /** * @brief Clear - clears the data collection */ void Clear(); /** * @brief GetDataNode - returns data node containing data at index * @param index * @return */ mitk::DataNode::Pointer GetDataNode(size_t index); /** * @brief GetDataNode - returns data node containing data with name * @param name * @return */ mitk::DataNode::Pointer GetDataNode(std::string name); /** * @brief GetProbabilityMap - returns vectorimage generated out of images with names in the probabilityNamesVector * @param probabilityNamesVector * @return */ mitk::Image::Pointer GetProbabilityMap(std::vector probabilityNamesVector); protected: DataCollection(); virtual ~DataCollection(); private: // DATA std::string m_Name; std::vector m_DataVector; std::vector m_NameVector; std::vector m_FilePathVector; std::map m_DataNames; mitk::DataCollection * m_Parent; std::string m_XMLFile; // is only filled for the hightest layer when loading a data collection }; } // end namespace #endif diff --git a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionReader.cpp b/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionReader.cpp index 5b92ec8dd6..c6ea2945ae 100644 --- a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionReader.cpp +++ b/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionReader.cpp @@ -1,423 +1,390 @@ /*=================================================================== 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. ===================================================================*/ #pragma warning (disable : 4996) #include "mitkCollectionReader.h" #include #include -#include -#include -#include +//#include #include //XML StateMachine Tags // Objects const std::string COLLECTION = "col"; const std::string SUBCOLLECTION = "subcol"; const std::string DATA = "data"; const std::string ITEM = "item"; // Properties const std::string NAME = "name"; const std::string ID = "id"; const std::string FILEPATH = "description"; const std::string LINK = "link"; static std::string GetName(std::string fileName,std::string suffix) { fileName = QFileInfo(QString::fromStdString(fileName)).fileName().toStdString(); return fileName.substr(0,fileName.length() -suffix.length()-9); // 8 = date length } static std::string GetDate(std::string fileName,std::string suffix) { fileName = QFileInfo(QString::fromStdString(fileName)).fileName().toStdString(); fileName = fileName.substr(fileName.length() - suffix.length()-8,8); // 8 = date length fileName.insert(6,"-"); fileName.insert(4,"-"); return fileName; } mitk::CollectionReader::CollectionReader() : m_Collection(NULL), m_SubCollection(NULL), m_DataItemCollection(NULL), m_ColIgnore(false), m_ItemIgnore(false) { } mitk::CollectionReader::~CollectionReader() { this->Clear(); } /** * @brief Loads the xml file filename and generates the necessary instances. **/ mitk::DataCollection::Pointer mitk::CollectionReader::LoadCollection(const std::string& xmlFileName) { QDir fileName = QFileInfo(xmlFileName.c_str()).absoluteDir(); m_BaseDir = fileName.path().toStdString() + QDir::separator().toLatin1(); this->SetFileName(xmlFileName.c_str()); this->Parse(); if (m_Collection.IsNotNull()) m_Collection->SetXMLFile(xmlFileName); return m_Collection; } void mitk::CollectionReader::AddDataElementIds(std::vector dataElemetIds) { m_SelectedDataItemIds.insert( m_SelectedDataItemIds.end(), dataElemetIds.begin(), dataElemetIds.end() ); } void mitk::CollectionReader::AddSubColIds(std::vector subColIds) { m_SelectedSubColIds.insert( m_SelectedSubColIds.end(), subColIds.begin(), subColIds.end() ); } void mitk::CollectionReader::SetDataItemNames(std::vector itemNames) { m_SelectedDataItemNames = itemNames; } void mitk::CollectionReader::ClearDataElementIds() { m_SelectedDataItemIds.clear(); } void mitk::CollectionReader::ClearSubColIds() { m_SelectedSubColIds.clear(); } void mitk::CollectionReader::Clear() { m_DataItemCollection = NULL; m_SubCollection = NULL; m_Collection = NULL; } mitk::DataCollection::Pointer mitk::CollectionReader::FolderToCollection(std::string folder, std::vector suffixes,std::vector seriesNames, bool allowGaps) { // Parse folder and look up all data, // after sanitation only fully available groups are included (that is all suffixes are found) FileListType fileList = SanitizeFileList(GenerateFileLists(folder, suffixes, allowGaps)); if (fileList.size() <= 0) return NULL; DataCollection::Pointer collection = DataCollection::New(); collection->SetName(GetName(fileList.at(0).at(0),suffixes.at(0))); for (unsigned int k=0; k < fileList.at(0).size(); ++k) // all groups have the same amount of items, so looking at 0 is ok. { DataCollection::Pointer subCollection = DataCollection::New(); for (unsigned int i=0; i< suffixes.size(); ++i) { - std::string fileName = fileList.at(i).at(k); - if (fileName.find(".fib") >= fileName.length()) - { - Image::Pointer image = IOUtil::LoadImage(fileList.at(i).at(k)); - subCollection->AddData(image.GetPointer(),seriesNames.at(i), fileList.at(i).at(k)); - } - else - { - const std::string s1="", s2=""; - - std::vector fiber_infile = mitk::BaseDataIO::LoadBaseDataFromFile( fileName, s1, s2, false ); - if( fiber_infile.empty() ) - { - MITK_INFO << "Fiber bundle could not be read " << fileName ; - } - mitk::BaseData* fiber_baseData = fiber_infile.at(0); - subCollection->AddData(fiber_baseData,seriesNames.at(i), fileList.at(i).at(k)); - } + Image::Pointer image = IOUtil::LoadImage(fileList.at(i).at(k)); + subCollection->AddData(image.GetPointer(),seriesNames.at(i), fileList.at(i).at(k)); } std::string sDate = GetDate(fileList.at(0).at(k),suffixes.at(0)); collection->AddData(subCollection.GetPointer(),sDate,"--"); } return collection; } void mitk::CollectionReader::StartElement(const char* elementName, const char **atts) { std::string name(elementName); if (name == COLLECTION) { m_Collection = DataCollection::New(); std::string colName = ReadXMLStringAttribut(NAME, atts); m_Collection->SetName(colName); } else if (name == SUBCOLLECTION) { m_ColIgnore = false; m_ItemIgnore = false; std::string subColName = ReadXMLStringAttribut(NAME, atts); std::string subColId = ReadXMLStringAttribut(ID, atts); if (m_SelectedSubColIds.size() > 0 && std::find(m_SelectedSubColIds.begin(), m_SelectedSubColIds.end(), subColId) == m_SelectedSubColIds.end() ) { // a) a selection list is provided AND b) the item is not in the list m_ColIgnore = true; return; } // Create subcollection m_SubCollection = DataCollection::New(); m_SubCollection->Init(subColName); } else if (name == DATA) { if (m_ColIgnore) return; std::string dataId = ReadXMLStringAttribut(ID, atts); if (m_SelectedDataItemIds.size() > 0 && std::find(m_SelectedDataItemIds.begin(), m_SelectedDataItemIds.end(), dataId) == m_SelectedDataItemIds.end() ) { // a) a selection list is provided AND b) the item is not in the list m_ItemIgnore = true; return; } m_ItemIgnore = false; std::string dataName = ReadXMLStringAttribut(NAME, atts); m_DataItemCollection = DataCollection::New(); m_DataItemCollection->Init(dataName); } else if (name == ITEM) { if (m_ColIgnore || m_ItemIgnore) return; std::string relativeItemLink = ReadXMLStringAttribut(LINK, atts); std::string itemLink = m_BaseDir + relativeItemLink; std::string itemName = ReadXMLStringAttribut(NAME, atts); // if item names are provided and name is not in list, do not load it if (m_SelectedDataItemNames.size() != 0 && std::find(m_SelectedDataItemNames.begin(), m_SelectedDataItemNames.end(), itemName) == m_SelectedDataItemNames.end() ) return; // Populate Sub-Collection - if (itemLink.find(".fib") >= itemLink.length()) - { - Image::Pointer image = IOUtil::LoadImage(itemLink); - if (image.IsNotNull()) - m_DataItemCollection->AddData(image.GetPointer(),itemName,relativeItemLink); - else - MITK_ERROR << "File could not be loaded: " << itemLink << ". Wihtin Sub-Collection " << m_SubCollection->GetName() << ", within " << m_DataItemCollection->GetName() ; - } + Image::Pointer image = IOUtil::LoadImage(itemLink); + if (image.IsNotNull()) + m_DataItemCollection->AddData(image.GetPointer(),itemName,relativeItemLink); else - { - const std::string s1="", s2=""; - - std::vector fiber_infile = mitk::BaseDataIO::LoadBaseDataFromFile( itemLink, s1, s2, false ); - if( fiber_infile.empty() ) - { - MITK_INFO << "Fiber bundle could not be read " << itemLink ; - } - mitk::BaseData* fiber_baseData = fiber_infile.at(0); - m_DataItemCollection->AddData(fiber_baseData,itemName, relativeItemLink); - } + MITK_ERROR << "File could not be loaded: " << itemLink << ". Wihtin Sub-Collection " << m_SubCollection->GetName() << ", within " << m_DataItemCollection->GetName() ; } else MITK_WARN<< "Malformed description ? -- unknown tag: " << name; } void mitk::CollectionReader::EndElement(const char* elementName) { std::string name(elementName); if (name == SUBCOLLECTION) { if (m_SubCollection.IsNull()) return; if (m_ColIgnore || m_SubCollection->Size() == 0) return; m_Collection->AddData(m_SubCollection.GetPointer(),m_SubCollection->GetName()); m_SubCollection = DataCollection::New(); } if (name == DATA) { if (m_DataItemCollection.IsNull()) return; if (m_DataItemCollection->Size() == 0) return; m_SubCollection->AddData(m_DataItemCollection.GetPointer(),m_DataItemCollection->GetName()); m_DataItemCollection = DataCollection::New(); } } std::string mitk::CollectionReader::ReadXMLStringAttribut(std::string name, const char** atts) { if (atts) { const char** attsIter = atts; while (*attsIter) { if (name == *attsIter) { attsIter++; return *attsIter; } attsIter++; attsIter++; } } return std::string(); } bool mitk::CollectionReader::ReadXMLBooleanAttribut(std::string name, const char** atts) { std::string s = ReadXMLStringAttribut(name, atts); std::transform(s.begin(), s.end(), s.begin(), ::toupper); if (s == "TRUE") return true; else return false; } int mitk::CollectionReader::ReadXMLIntegerAttribut(std::string name, const char** atts) { std::string s = ReadXMLStringAttribut(name, atts); return atoi(s.c_str()); } mitk::CollectionReader::FileListType mitk::CollectionReader::GenerateFileLists(std::string folder, std::vector suffixes, bool allowGaps) { FileListType fileList; QString qFolder = QString::fromStdString(folder); if (!QFileInfo(qFolder).isDir()) { MITK_ERROR << "Folder does not exist."; return fileList; } // Add vector for each suffix for (unsigned int i=0; i< suffixes.size(); ++i) { std::vector list; fileList.push_back(list); } // if gaps are allowed, file names are build up from reference file (first suffix) // else all lists a file, file by file with regular sorting of the files, // if one suffix has more/less images than the others loading is aborted if (allowGaps) { QDir parseDir; parseDir.setFilter(QDir::Files); parseDir.setPath(qFolder); QStringList filterMorph; filterMorph << "*" + QString::fromStdString( suffixes.at(0) ); parseDir.setNameFilters( filterMorph ); QFileInfoList qFileList = parseDir.entryInfoList(); // now populate lists with files names, non-existing files will be marked with an empty string for (int i = 0; i < qFileList.size(); ++i) { std::string baseFileName = qFileList.at(i).absoluteFilePath().toStdString(); fileList.at(0).push_back( baseFileName ); //check for different suffixes for (unsigned int suffNo=1; suffNo < suffixes.size(); ++suffNo) { std::string derivedFileName = baseFileName.substr(0,baseFileName.length() -suffixes.at(0).length()) + suffixes.at(suffNo); // checking if file exists if (QFileInfo(QString::fromStdString(derivedFileName)).isFile()) fileList.at(suffNo).push_back(derivedFileName); else fileList.at(suffNo).push_back(""); } } } else { int numberOfFiles=-1; for (unsigned int i=0; i< suffixes.size(); ++i) { QDir parseDir; parseDir.setFilter(QDir::Files); parseDir.setPath(qFolder); QStringList filterMorph; filterMorph << "*" + QString::fromStdString( suffixes.at(i) ); parseDir.setNameFilters( filterMorph ); QFileInfoList qFileList = parseDir.entryInfoList(); if (numberOfFiles == -1) numberOfFiles = qFileList.size(); if (numberOfFiles != qFileList.size() ) { MITK_ERROR << "Series contain different number of images. Loading aborting."; fileList.clear(); break; } for (int fileNo=0; fileNo indexRemoval; // Parse through all items and check for empty strings, if one occurs mark this index // for removal. int modalities = list.size(); int timeSteps = list.at(0).size(); MITK_INFO << "Modalities " << modalities; MITK_INFO << "TimeSteps " << timeSteps; if (timeSteps == 0) MITK_ERROR << "No files found. Fatal."; for (int listIndex = 0 ; listIndex < timeSteps; listIndex++) { for (int modalityIndex = 0 ; modalityIndex < modalities; modalityIndex++) { if (list.at(modalityIndex).at(listIndex) == "") { MITK_INFO << "Marked Index " << listIndex << " for removal."; indexRemoval.push_back(listIndex); break; } } } for (int listIndex = indexRemoval.size()-1 ; listIndex >= 0; --listIndex) { for (int i = 0 ; i < modalities; i++) { list.at(i).erase(list.at(i).begin()+indexRemoval.at(listIndex)) ; } } MITK_INFO << "Time Steps after sanitizing: " << list.at(0).size(); return list; } diff --git a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.cpp b/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.cpp index 6c23a872a5..1a9420d5ae 100755 --- a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.cpp +++ b/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.cpp @@ -1,508 +1,418 @@ /*=================================================================== 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. ===================================================================*/ #pragma warning (disable : 4996) #include "mitkCollectionWriter.h" #include -#include -#include #include "mitkImageCast.h" -#include "mitkTensorImage.h" #include "itkNrrdImageIO.h" #include "itkImageFileWriter.h" #include "mitkCoreObjectFactory.h" #include #include #include //XML StateMachine Tags // Objects const std::string COLLECTION = "col"; const std::string SUBCOLLECTION = "subcol"; const std::string DATA = "data"; const std::string ITEM = "item"; // Properties const std::string NAME = "name"; const std::string ID = "id"; const std::string FILEPATH = "filepath"; const std::string LINK = "link"; static std::string GetName(std::string fileName,std::string suffix, bool longName = false) { fileName = QFileInfo(QString::fromStdString(fileName)).fileName().toStdString(); if (longName) return fileName.substr(0,fileName.length() -suffix.length()-11); // 10 = date length else return fileName.substr(0,fileName.length() -suffix.length()-9); // 8 = date length } static std::string GetDate(std::string fileName,std::string suffix, bool longName = false) { fileName = QFileInfo(QString::fromStdString(fileName)).fileName().toStdString(); if (longName) fileName = fileName.substr(fileName.length() - suffix.length()-10,10); // 8 = date length else fileName = fileName.substr(fileName.length() - suffix.length()-8,8); // 8 = date length if (!longName) { fileName.insert(6,"-"); fileName.insert(4,"-"); } return fileName; } bool mitk::CollectionWriter::ExportCollectionToFolder(DataCollection *dataCollection, std::string xmlFile, std::vector filter) { // Quick and Dirty: Assumes three level DataCollection QDir fileName = QFileInfo(xmlFile.c_str()).absoluteDir(); std::string outputFolder = fileName.path().toStdString() + QDir::separator().toLatin1(); QDir baseFolder(outputFolder.c_str()); baseFolder.mkpath(outputFolder.c_str()); std::ofstream xmlFileStream; xmlFileStream.open (xmlFile.c_str()); xmlFileStream << " \n"; xmlFileStream << "<" << COLLECTION << " " << NAME << "=\"" << dataCollection->GetName() << "\" >\n"; unsigned int subColId = 0; unsigned int dataId = 0; QDir dir(QString::fromStdString(outputFolder)); for (size_t i = 0 ; i < dataCollection->Size(); ++i) { // Write Subcollection tag xmlFileStream << " <" << SUBCOLLECTION << " " << NAME << "=\"" << dataCollection->IndexToName(i) << "\" " << FILEPATH << "=\"" << dataCollection->GetDataFilePath(i) << "\" id=\"Col" << subColId << "\" >\n"; // Create Sub-Folder dir.mkpath(QString::fromStdString(dataCollection->IndexToName(i))); // Herein create data folders DataCollection* subCollections = dynamic_cast (dataCollection->GetData(i).GetPointer()); if (subCollections == NULL) { MITK_ERROR<< "mitk::CollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; return false; } for (size_t d = 0; d < subCollections->Size(); d++ ) { // Create Sub Paths QString subPath = QString::fromStdString(dataCollection->IndexToName(i))+"/"+QString::fromStdString(subCollections->IndexToName(d)); dir.mkpath(subPath); xmlFileStream << " <" << DATA << " " << NAME << "=\"" << subCollections->IndexToName(d) << "\" " << FILEPATH << "=\"" << subCollections->GetDataFilePath(d) << "\" id=\"Data" << dataId << "\" >\n"; DataCollection* itemCollections = dynamic_cast (subCollections->GetData(d).GetPointer()); if (itemCollections == NULL) { MITK_ERROR<< "mitk::CollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; return false; } for (size_t s = 0; s < itemCollections->Size(); s++) { if (filter.size() > 0) { bool isSelected = false; for (size_t f = 0; f < filter.size(); f++) { if (filter.at(f) == itemCollections->IndexToName(s) ) { isSelected = true; break; } } if (isSelected == false) continue; } Image* image = dynamic_cast (itemCollections->GetData(s).GetPointer()); QString fileName = dir.path() + dir.separator() + subPath + dir.separator() + QString::fromStdString(dataCollection->IndexToName(i)) + "_" + QString::fromStdString(subCollections->IndexToName(d)) + "_" + QString::fromStdString(itemCollections->IndexToName(s)); try { - if (itemCollections->IndexToName(s) == "DTI" || itemCollections->IndexToName(s) == "DTIFWE") - { - fileName += ".dti"; - itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); - io->SetFileType( itk::ImageIOBase::Binary ); - io->UseCompressionOn(); - TensorImage* tensorImage = dynamic_cast (image); - MITK_INFO << "Pixeltype Tensor Image: " << tensorImage->GetPixelType().GetPixelTypeAsString(); - typedef itk::Image,3> ImageType; - typedef itk::ImageFileWriter WriterType; - WriterType::Pointer nrrdWriter = WriterType::New(); - ImageType::Pointer outimage = ImageType::New(); - CastToItkImage(tensorImage, outimage); - nrrdWriter->SetInput( outimage ); - nrrdWriter->SetImageIO(io); - nrrdWriter->SetFileName(fileName.toStdString()); - nrrdWriter->UseCompressionOn(); - nrrdWriter->Update(); - } - else if (itemCollections->IndexToName(s) == "FIB") - { - fileName += ".fib"; - FiberBundle* fib = dynamic_cast (itemCollections->GetData(s).GetPointer()); - CoreObjectFactory::FileWriterList fileWriters = CoreObjectFactory::GetInstance()->GetFileWriters(); - for (CoreObjectFactory::FileWriterList::iterator it = fileWriters.begin() ; it != fileWriters.end() ; ++it) - { - if ( (*it)->CanWriteBaseDataType(fib) ) { - (*it)->SetFileName( fileName.toStdString().c_str() ); - (*it)->DoWrite( fib ); - } - } - } - else if (itemCollections->IndexToName(s) == "DWI") - { - fileName += ".dwi"; -// NrrdDiffusionImageWriter dwiwriter; -// dwiwriter.SetInput( dynamic_cast* > (image)); -// dwiwriter.SetOutputLocation( fileName.toStdString() ); - - IOUtil::SaveImage(image,fileName.toStdString()); - } - else - { - fileName += ".nrrd"; - Image::Pointer image = itemCollections->GetMitkImage(s).GetPointer(); - IOUtil::SaveImage(image,fileName.toStdString()); - } + fileName += ".nrrd"; + Image::Pointer image = itemCollections->GetMitkImage(s).GetPointer(); + IOUtil::SaveImage(image,fileName.toStdString()); } catch( const std::exception& e) { MITK_ERROR << "Caught exception: " << e.what(); } std::string relativeFilename = baseFolder.relativeFilePath(fileName).toStdString(); xmlFileStream << " <" << ITEM << " " << NAME << "=\"" <IndexToName(s) << "\" " << FILEPATH << "=\"" << "\" " << LINK << "=\"" << relativeFilename << "\" />\n"; } xmlFileStream << " \n"; dataId++; } xmlFileStream << " \n"; subColId++; } xmlFileStream << "\n"; xmlFileStream.flush(); xmlFileStream.close(); return true; } bool mitk::CollectionWriter::ExportCollectionToFolder(mitk::DataCollection *dataCollection, std::string xmlFile) { std::vector mods; return ExportCollectionToFolder(dataCollection,xmlFile, mods); } bool mitk::CollectionWriter::SaveCollection(mitk::DataCollection *dataCollection, std::vector filter, std::string xmlFile) { QDir origFilename = QFileInfo(dataCollection->GetXMLFile().c_str()).absoluteDir(); QString originalFolder = origFilename.path() + QDir::separator(); if (xmlFile == "") xmlFile = dataCollection->GetXMLFile(); QDir fileName = QFileInfo(xmlFile.c_str()).absoluteDir(); std::string outputFolder = fileName.path().toStdString() + QDir::separator().toLatin1(); QDir baseFolder(outputFolder.c_str()); std::ofstream xmlFileStream; xmlFileStream.open (xmlFile.c_str()); xmlFileStream << " \n"; xmlFileStream << "<" << COLLECTION << " " << NAME << "=\"" << dataCollection->GetName() << "\" >\n"; unsigned int subColId = 0; unsigned int dataId = 0; QDir dir(QString::fromStdString(outputFolder)); for (size_t i = 0 ; i < dataCollection->Size(); ++i) { // Write Subcollection tag xmlFileStream << " <" << SUBCOLLECTION << " " << NAME << "=\"" << dataCollection->IndexToName(i) << "\" " << FILEPATH << "=\"" << dataCollection->GetDataFilePath(i) << "\" id=\"Col" << subColId << "\" >\n"; // Create Sub-Folder dir.mkpath(QString::fromStdString(dataCollection->IndexToName(i))); // Herein create data folders DataCollection* subCollections = dynamic_cast (dataCollection->GetData(i).GetPointer()); if (subCollections == NULL) { MITK_ERROR<< "mitk::CollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; return false; } for (size_t d = 0; d < subCollections->Size(); d++ ) { // Create Sub Paths QString subPath = QString::fromStdString(dataCollection->IndexToName(i))+"/"+QString::fromStdString(subCollections->IndexToName(d)); dir.mkpath(subPath); xmlFileStream << " <" << DATA << " " << NAME << "=\"" << subCollections->IndexToName(d) << "\" " << FILEPATH << "=\"" << subCollections->GetDataFilePath(d) << "\" id=\"Data" << dataId << "\" >\n"; DataCollection* itemCollections = dynamic_cast (subCollections->GetData(d).GetPointer()); if (itemCollections == NULL) { MITK_ERROR<< "mitk::CollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; return false; } for (size_t s = 0; s < itemCollections->Size(); s++) { if (filter.size() > 0) { bool isSelected = false; for (size_t f = 0; f < filter.size(); f++) { if (filter.at(f) == itemCollections->IndexToName(s) ) { isSelected = true; break; } } if (isSelected == false) continue; } Image* image = dynamic_cast (itemCollections->GetData(s).GetPointer()); QString fileName; bool fullName = false; if (itemCollections->GetDataFilePath(s) != "") { fileName = originalFolder + QString::fromStdString(itemCollections->GetDataFilePath(s)); fullName = true; MITK_INFO << "original path: " << itemCollections->GetDataFilePath(s) ; } else fileName = dir.path() + dir.separator() + subPath + dir.separator() + QString::fromStdString(dataCollection->IndexToName(i)) + "_" + QString::fromStdString(subCollections->IndexToName(d)) + "_" + QString::fromStdString(itemCollections->IndexToName(s)); try { - if (itemCollections->IndexToName(s) == "DTI" || itemCollections->IndexToName(s) == "DTIFWE") - { - if (!fullName) - fileName += ".dti"; - itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); - io->SetFileType( itk::ImageIOBase::Binary ); - io->UseCompressionOn(); - TensorImage* tensorImage = dynamic_cast (image); - MITK_INFO << "Pixeltype Tensor Image: " << tensorImage->GetPixelType().GetPixelTypeAsString(); - typedef itk::Image,3> ImageType; - typedef itk::ImageFileWriter WriterType; - WriterType::Pointer nrrdWriter = WriterType::New(); - ImageType::Pointer outimage = ImageType::New(); - CastToItkImage(tensorImage, outimage); - nrrdWriter->SetInput( outimage ); - nrrdWriter->SetImageIO(io); - nrrdWriter->SetFileName(fileName.toStdString()); - nrrdWriter->UseCompressionOn(); - nrrdWriter->Update(); - } - else if (itemCollections->IndexToName(s) == "FIB") - { - if (!fullName) - fileName += ".fib"; - FiberBundle* fib = dynamic_cast (itemCollections->GetData(s).GetPointer()); - CoreObjectFactory::FileWriterList fileWriters = CoreObjectFactory::GetInstance()->GetFileWriters(); - for (CoreObjectFactory::FileWriterList::iterator it = fileWriters.begin() ; it != fileWriters.end() ; ++it) - { - if ( (*it)->CanWriteBaseDataType(fib) ) { - (*it)->SetFileName( fileName.toStdString().c_str() ); - (*it)->DoWrite( fib ); - } - } - } - else if (itemCollections->IndexToName(s) == "DWI") - { - if (!fullName) - fileName += ".dwi"; - IOUtil::SaveImage(image,fileName.toStdString()); - } - else - { - if (!fullName) - fileName += ".nrrd"; - Image::Pointer image = itemCollections->GetMitkImage(s).GetPointer(); - IOUtil::SaveImage(image,fileName.toStdString()); - } + if (!fullName) + fileName += ".nrrd"; + Image::Pointer image = itemCollections->GetMitkImage(s).GetPointer(); + IOUtil::SaveImage(image,fileName.toStdString()); } catch( const std::exception& e) { MITK_ERROR << "Caught exception: " << e.what(); } std::string relativeFilename =baseFolder.relativeFilePath(fileName).toStdString(); xmlFileStream << " <" << ITEM << " " << NAME << "=\"" <IndexToName(s) << "\" " << FILEPATH << "=\"" << "\" " << LINK << "=\"" << relativeFilename << "\" />\n"; } xmlFileStream << " \n"; dataId++; } xmlFileStream << " \n"; subColId++; } xmlFileStream << "\n"; xmlFileStream.flush(); xmlFileStream.close(); return true; } bool mitk::CollectionWriter::FolderToXml(std::string folder, std::string collectionType, std::string xmlFile, std::vector filter, std::vector seriesNames) { // 1) Parse for folders QDir parseDir; parseDir.setFilter( QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot); parseDir.setPath(QString::fromStdString(folder)); QFileInfoList qFileList = parseDir.entryInfoList(); std::ofstream xmlFileStream; xmlFileStream.open (xmlFile.c_str()); xmlFileStream << " \n"; xmlFileStream << "<" << COLLECTION << " " << NAME << "=\"" << "GEN" << "\" >\n"; unsigned int dataId = 0; // now populate lists with files names, non-existing files will be marked with an empty string for (int i = 0; i < qFileList.size(); ++i) { // 2) For Each sub folder construct collectionType sub-folder std::string baseFolder = qFileList.at(i).absoluteFilePath().toStdString() + QDir::separator().toLatin1() + collectionType; MITK_INFO << "Processing : " << baseFolder; if (!QFileInfo(QString::fromStdString(baseFolder)).isDir()) { MITK_WARN << "Not a valid folder, skipping."; continue; } // 3) Parse each sub folder and extend XML file // Parse folder and look up all data, // after sanitation only fully available groups are included (that is all suffixes are found) CollectionReader::FileListType fileList = CollectionReader::SanitizeFileList(CollectionReader::GenerateFileLists(baseFolder, filter,true)); if (fileList.size() <= 0 || fileList.at(0).size() <= 0) continue; // Write Subcollection tag // try to extract date out of filename std::string name = GetName(fileList.at(0).at(0),filter.at(0)); xmlFileStream << " <" << SUBCOLLECTION << " " << NAME << "=\"" << name << "\" " << FILEPATH << "=\"\" id=\"Col" << i << "\" >\n"; for (unsigned int k=0; k < fileList.at(0).size(); ++k) // all groups have the same amount of items, so looking at 0 is ok. { std::string strDate = GetDate(fileList.at(0).at(k),filter.at(0)); xmlFileStream << " <" << DATA << " " << NAME << "=\"" << strDate << "\" " << " id=\"Data" << dataId << "\" >\n"; dataId++; for (unsigned int i=0; i< filter.size(); ++i) { std::string fileName = fileList.at(i).at(k); xmlFileStream << " <" << ITEM << " " << NAME << "=\"" << seriesNames.at(i) << "\" " << LINK << "=\"" << fileName << "\" />\n"; } xmlFileStream << " \n" ; } xmlFileStream << " \n"; } xmlFileStream << "\n"; xmlFileStream.flush(); xmlFileStream.close(); return true; } bool mitk::CollectionWriter::SingleFolderToXml(std::string folder, std::string xmlFile, std::vector filter, std::vector seriesNames, bool longDate, int skipUntil, float months) { std::ofstream xmlFileStream; xmlFileStream.open (xmlFile.c_str()); xmlFileStream << " \n"; xmlFileStream << "<" << COLLECTION << " " << NAME << "=\"" << "GEN" << "\" >\n"; unsigned int dataId = 0; // 1) // Parse folder and look up all data, // after sanitation only fully available groups are included (that is all suffixes are found) CollectionReader::FileListType fileList = CollectionReader::SanitizeFileList(CollectionReader::GenerateFileLists(folder, filter,true)); // Write Subcollection tag // try to extract date out of filename std::string name = GetName(fileList.at(0).at(0),filter.at(0),longDate); xmlFileStream << " <" << SUBCOLLECTION << " " << NAME << "=\"" << name << "\" " << FILEPATH << "=\"\" id=\"Col" << 0 << "\" >\n"; for (unsigned int k=skipUntil; k < fileList.at(0).size(); ++k) // all groups have the same amount of items, so looking at 0 is ok. { std::string strDate = GetDate(fileList.at(0).at(k),filter.at(0),true); xmlFileStream << " <" << DATA << " " << NAME << "=\"" << strDate << "\" " << " id=\"Data" << dataId << "\" >\n"; dataId++; for (unsigned int i=0; i< filter.size(); ++i) { std::string fileName = fileList.at(i).at(k); xmlFileStream << " <" << ITEM << " " << NAME << "=\"" << seriesNames.at(i) << "\" " << LINK << "=\"" << fileName << "\" />\n"; } // size_t ind = GetIndexForinXMonths(fileList,months,k,filter); // xmlFileStream << " <" << ITEM << " " << NAME << "=\"TARGET\" " << LINK << "=\"" << fileList.at(filter.size()-1).at(ind) << "\" />\n"; xmlFileStream << " \n" ; // check if target still exists for next step if (GetIndexForinXMonths(fileList,months,k+1,filter)== 0) break; } xmlFileStream << " \n"; xmlFileStream << "\n"; xmlFileStream.flush(); xmlFileStream.close(); return true; } size_t mitk::CollectionWriter::GetIndexForinXMonths(mitk::CollectionReader::FileListType fileList,float months, size_t curIndex,std::vector filter) { std::string strDate0 = GetDate(fileList.at(0).at(curIndex),filter.at(0),true); int year0 =std::atoi(strDate0.substr(0,4).c_str()); int month0 =std::atoi(strDate0.substr(5,2).c_str()); int day0 = std::atoi(strDate0.substr(8,2).c_str()); size_t bestIndex = 0; int bestFit = 1e5; for (size_t i=curIndex+1; i < fileList.at(0).size(); ++i) { std::string strDate = GetDate(fileList.at(0).at(i),filter.at(0),true); int year =std::atoi(strDate.substr(0,4).c_str()); int month =std::atoi(strDate.substr(5,2).c_str()); int day = std::atoi(strDate.substr(8,2).c_str()); int fit = std::fabs((months * 30 ) - (((year-year0)*360) +((month-month0)*30) + (day-day0))); // days difference from x months if (fit < bestFit) { bestFit = fit; bestIndex = i; } } return bestIndex; } diff --git a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.h b/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.h index a366057d6e..046320df27 100755 --- a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.h +++ b/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.h @@ -1,81 +1,81 @@ /*=================================================================== 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 MITK_COLLECTION_WRITER_H #define MITK_COLLECTION_WRITER_H -#include "mitkCommon.h" +//#include "mitkCommon.h" #include "mitkDataCollection.h" #include "mitkCollectionReader.h" #include namespace mitk { class MITKDATACOLLECTION_EXPORT CollectionWriter { public: typedef float TensorScalar; /** * @brief ExportCollectionToFolder * * Creates an XML file and stores all data in the same folder as the xml file (creating sub-folders for sub-collections) * * * Naming Conventions (Neccessary for proper saving of these images): * DWI - Diffusion Weighted Images * DTI - Diffusion Tensor Images * FIB - Fiber Bundles * * @param dataCollection * @param xmlFile * @param filter - (optional) only items with names contained in this list are written, if list is empty all items are written * @return */ static bool ExportCollectionToFolder(DataCollection* dataCollection, std::string xmlFile , std::vector filter); static bool ExportCollectionToFolder(DataCollection* dataCollection, std::string xmlFile); /** * @brief SaveCollection - Stores data collection at original location * * Writes the collection back to the files given in the original XML file. * New data items are stored into the default location, which is relative to the XML file. * * If a XML file is provided the files are stored as stated above with the differences that a new XML file is generated and new files are saved * relative to the newly generated xml. * * @param dataCollection * @param filter * @param xmlFile * @return */ static bool SaveCollection(DataCollection* dataCollection, std::vector filter, std::string xmlFile = ""); static bool FolderToXml(std::string folder, std::string collectionType, std::string xmlFile, std::vector filter, std::vector seriesNames); // GTV last entry in filter list, this item will be made to TARGET static bool SingleFolderToXml(std::string folder, std::string xmlFile, std::vector filter, std::vector seriesNames, bool longDate = true, int skipUntil = 0, float months = 0); protected: private: static size_t GetIndexForinXMonths(CollectionReader::FileListType fileList, float months, size_t curIndex, std::vector filter); }; } // namespace mitk #endif /* MITK_COLLECTION_WRITER_H */ diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDwiNormilzationFilter.h b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDwiNormilzationFilter.h index c268bb5e40..d614feb423 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDwiNormilzationFilter.h +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDwiNormilzationFilter.h @@ -1,100 +1,101 @@ /*=================================================================== 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 __itkDwiNormilzationFilter_h_ #define __itkDwiNormilzationFilter_h_ #include "itkImageToImageFilter.h" #include "itkVectorImage.h" #include #include #include #include namespace itk{ /** \class DwiNormilzationFilter * \brief Normalizes the data vectors either using the specified reference value or the voxelwise baseline value. */ template< class TInPixelType > class DwiNormilzationFilter : public ImageToImageFilter< VectorImage< TInPixelType, 3 >, VectorImage< TInPixelType, 3 > > { public: typedef DwiNormilzationFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< TInPixelType, 3 >, VectorImage< TInPixelType, 3 > > Superclass; + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::OutputImageType OutputImageType; + typedef typename Superclass::OutputImageRegionType OutputImageRegionType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DwiNormilzationFilter, ImageToImageFilter) typedef itk::Image< double, 3 > DoubleImageType; typedef itk::Image< unsigned char, 3 > UcharImageType; typedef itk::Image< unsigned short, 3 > BinImageType; typedef itk::Image< TInPixelType, 3 > TInPixelImageType; - typedef typename Superclass::InputImageType InputImageType; - typedef typename Superclass::OutputImageType OutputImageType; - typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer GradientContainerType; - typedef itk::LabelStatisticsImageFilter< TInPixelImageType,BinImageType > StatisticsFilterType; - typedef itk::Statistics::Histogram< typename TInPixelImageType::PixelType > HistogramType; - typedef typename HistogramType::MeasurementType MeasurementType; - typedef itk::ShiftScaleImageFilter ShiftScaleImageFilterType; + + typedef ImageRegionConstIterator< InputImageType > InputIteratorType; + typedef ImageRegionConstIterator< UcharImageType > MaskIteratorType; + itkSetMacro( GradientDirections, GradientContainerType ) itkSetMacro( ScalingFactor, TInPixelType ) - itkSetMacro( UseGlobalReference, bool ) itkSetMacro( MaskImage, UcharImageType::Pointer ) - itkSetMacro( Reference, double ) + itkSetMacro( NewMean, double ) + itkSetMacro( NewStdev, double ) protected: DwiNormilzationFilter(); ~DwiNormilzationFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType); UcharImageType::Pointer m_MaskImage; GradientContainerType m_GradientDirections; int m_B0Index; TInPixelType m_ScalingFactor; - bool m_UseGlobalReference; - double m_Reference; - + double m_Mean; + double m_Stdev; + double m_NewMean; + double m_NewStdev; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDwiNormilzationFilter.txx" #endif #endif //__itkDwiNormilzationFilter_h_ diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDwiNormilzationFilter.txx b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDwiNormilzationFilter.txx index 59faf8479b..dfbb15d407 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDwiNormilzationFilter.txx +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkDwiNormilzationFilter.txx @@ -1,127 +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. ===================================================================*/ #ifndef __itkDwiNormilzationFilter_txx #define __itkDwiNormilzationFilter_txx #include #include #include #define _USE_MATH_DEFINES #include #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" #include namespace itk { template< class TInPixelType > DwiNormilzationFilter< TInPixelType>::DwiNormilzationFilter() - :m_B0Index(-1) - ,m_ScalingFactor(1000) - ,m_UseGlobalReference(false) + : m_B0Index(-1) + , m_NewMean(1000) + , m_NewStdev(500) { this->SetNumberOfRequiredInputs( 1 ); } template< class TInPixelType > void DwiNormilzationFilter< TInPixelType>::BeforeThreadedGenerateData() { typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); m_B0Index = -1; for (unsigned int i=0; iGetVectorLength(); i++) { GradientDirectionType g = m_GradientDirections->GetElement(i); if (g.magnitude()<0.001) m_B0Index = i; } if (m_B0Index==-1) itkExceptionMacro(<< "DwiNormilzationFilter: No b-Zero indecies found!"); - if (m_UseGlobalReference) - MITK_INFO << "Using global reference value: " << m_Reference; + if (m_MaskImage.IsNull()) + { + // initialize mask image + m_MaskImage = UcharImageType::New(); + m_MaskImage->SetSpacing( inputImagePointer->GetSpacing() ); + m_MaskImage->SetOrigin( inputImagePointer->GetOrigin() ); + m_MaskImage->SetDirection( inputImagePointer->GetDirection() ); + m_MaskImage->SetRegions( inputImagePointer->GetLargestPossibleRegion() ); + m_MaskImage->Allocate(); + m_MaskImage->FillBuffer(1); + } + else + std::cout << "DwiNormilzationFilter: using mask image" << std::endl; + + InputIteratorType git( inputImagePointer, inputImagePointer->GetLargestPossibleRegion() ); + MaskIteratorType mit( m_MaskImage, m_MaskImage->GetLargestPossibleRegion() ); + git.GoToBegin(); + mit.GoToBegin(); + + int n = 0; + m_Mean = 0; + m_Stdev = 0; + while( !git.IsAtEnd() ) + { + if (mit.Get()>0) + { + for (unsigned int i=0; iGetVectorLength(); i++) + { + if (i==m_B0Index) + continue; + m_Mean += git.Get()[i]; + n++; + } + } + ++git; + ++mit; + } + m_Mean /= n; + + git.GoToBegin(); + mit.GoToBegin(); + + while( !git.IsAtEnd() ) + { + if (mit.Get()>0) + { + for (unsigned int i=0; iGetVectorLength(); i++) + { + if (i==m_B0Index) + continue; + double diff = (double)(git.Get()[i]) - m_Mean; + m_Stdev += diff*diff; + } + } + ++git; + ++mit; + } + + m_Stdev = std::sqrt(m_Stdev/(n-1)); + + MITK_INFO << "Mean: " << m_Mean; + MITK_INFO << "Stdev: " << m_Stdev; } template< class TInPixelType > void DwiNormilzationFilter< TInPixelType>::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); oit.GoToBegin(); - typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typename InputImageType::Pointer inputImagePointer = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); - typename OutputImageType::PixelType nullPix; - nullPix.SetSize(inputImagePointer->GetVectorLength()); - nullPix.Fill(0); - + MaskIteratorType mit( m_MaskImage, outputRegionForThread ); + mit.GoToBegin(); InputIteratorType git( inputImagePointer, outputRegionForThread ); git.GoToBegin(); + while( !git.IsAtEnd() ) { typename InputImageType::PixelType pix = git.Get(); typename OutputImageType::PixelType outPix; outPix.SetSize(inputImagePointer->GetVectorLength()); - double S0 = pix[m_B0Index]; - if (m_UseGlobalReference) - S0 = m_Reference; - - if (S0>0.1 && pix[m_B0Index]>0) - { +// if (mit.Get()>0) +// { for (unsigned int i=0; iGetVectorLength(); i++) { - double val = (double)pix[i]; - - if (val!=val || val<0) - val = 0; - else - { - val /= S0; - val *= (double)m_ScalingFactor; - } + double val = (double)pix[i] - m_Mean; + val /= m_Stdev; + val *= m_NewStdev; + val += m_NewMean; + if (val<0) + val = 0; outPix[i] = (TInPixelType)val; } - oit.Set(outPix); - } - else - oit.Set(nullPix); +// } +// else +// outPix.Fill(0); + + oit.Set(outPix); + ++mit; ++oit; ++git; } std::cout << "One Thread finished calculation" << std::endl; } template< class TInPixelType > void DwiNormilzationFilter< TInPixelType> ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); } } #endif // __itkDwiNormilzationFilter_txx diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFslPeakImageConverter.cpp b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFslPeakImageConverter.cpp index e582ffefc5..57b1ddc32b 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFslPeakImageConverter.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFslPeakImageConverter.cpp @@ -1,171 +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. ===================================================================*/ #ifndef __itkFslPeakImageConverter_cpp #define __itkFslPeakImageConverter_cpp #include #include #include #include "itkFslPeakImageConverter.h" #include #include #include #include #include #include #include #include #include namespace itk { template< class PixelType > FslPeakImageConverter< PixelType >::FslPeakImageConverter(): m_NormalizationMethod(NO_NORM) + , m_InvertX(false) + , m_InvertY(false) + , m_InvertZ(false) { } template< class PixelType > void FslPeakImageConverter< PixelType > ::GenerateData() { // output vector field vtkSmartPointer m_VtkCellArray = vtkSmartPointer::New(); vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); Vector spacing4 = m_InputImages->GetElement(0)->GetSpacing(); Point origin4 = m_InputImages->GetElement(0)->GetOrigin(); Matrix direction4 = m_InputImages->GetElement(0)->GetDirection(); ImageRegion<4> imageRegion4 = m_InputImages->GetElement(0)->GetLargestPossibleRegion(); itk::Vector spacing3; Point origin3; Matrix direction3; ImageRegion<3> imageRegion3; spacing3[0] = spacing4[0]; spacing3[1] = spacing4[1]; spacing3[2] = spacing4[2]; origin3[0] = origin4[0]; origin3[1] = origin4[1]; origin3[2] = origin4[2]; for (int r=0; r<3; r++) for (int c=0; c<3; c++) direction3[r][c] = direction4[r][c]; imageRegion3.SetSize(0, imageRegion4.GetSize()[0]); imageRegion3.SetSize(1, imageRegion4.GetSize()[1]); imageRegion3.SetSize(2, imageRegion4.GetSize()[2]); double minSpacing = spacing3[0]; if (spacing3[1] InputIteratorType; for (int i=0; iSize(); i++) { InputImageType::Pointer img = m_InputImages->GetElement(i); int x = img->GetLargestPossibleRegion().GetSize(0); int y = img->GetLargestPossibleRegion().GetSize(1); int z = img->GetLargestPossibleRegion().GetSize(2); ItkDirectionImageType::Pointer directionImage = ItkDirectionImageType::New(); directionImage->SetSpacing( spacing3 ); directionImage->SetOrigin( origin3 ); directionImage->SetDirection( direction3 ); directionImage->SetRegions( imageRegion3 ); directionImage->Allocate(); Vector< PixelType, 3 > nullVec; nullVec.Fill(0.0); directionImage->FillBuffer(nullVec); for (int a=0; a dirVec; dirVec.set_size(4); for (int k=0; k<3; k++) { index.SetElement(3,k); dirVec[k] = img->GetPixel(index); } dirVec[3] = 0; vtkSmartPointer container = vtkSmartPointer::New(); itk::ContinuousIndex center; center[0] = index[0]; center[1] = index[1]; center[2] = index[2]; center[3] = 0; itk::Point worldCenter; img->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); switch (m_NormalizationMethod) { case NO_NORM: break; case SINGLE_VEC_NORM: dirVec.normalize(); break; } dirVec.normalize(); dirVec = img->GetDirection()*dirVec; + if (m_InvertX) + dirVec[0] *= -1; + if (m_InvertY) + dirVec[1] *= -1; + if (m_InvertZ) + dirVec[2] *= -1; itk::Point worldStart; worldStart[0] = worldCenter[0]-dirVec[0]/2 * minSpacing; worldStart[1] = worldCenter[1]-dirVec[1]/2 * minSpacing; worldStart[2] = worldCenter[2]-dirVec[2]/2 * minSpacing; vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); container->GetPointIds()->InsertNextId(id); itk::Point worldEnd; worldEnd[0] = worldCenter[0]+dirVec[0]/2 * minSpacing; worldEnd[1] = worldCenter[1]+dirVec[1]/2 * minSpacing; worldEnd[2] = worldCenter[2]+dirVec[2]/2 * minSpacing; id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); container->GetPointIds()->InsertNextId(id); m_VtkCellArray->InsertNextCell(container); // generate direction image typename ItkDirectionImageType::IndexType index2; index2[0] = index[0]; index2[1] = index[1]; index2[2] = index[2]; Vector< PixelType, 3 > pixel; pixel.SetElement(0, dirVec[0]); pixel.SetElement(1, dirVec[1]); pixel.SetElement(2, dirVec[2]); directionImage->SetPixel(index2, pixel); } m_DirectionImageContainer->InsertElement(m_DirectionImageContainer->Size(), directionImage); } vtkSmartPointer directionsPolyData = vtkSmartPointer::New(); directionsPolyData->SetPoints(m_VtkPoints); directionsPolyData->SetLines(m_VtkCellArray); m_OutputFiberBundle = mitk::FiberBundle::New(directionsPolyData); } } #endif // __itkFslPeakImageConverter_cpp diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFslPeakImageConverter.h b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFslPeakImageConverter.h index d63133ba43..0503316246 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFslPeakImageConverter.h +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkFslPeakImageConverter.h @@ -1,89 +1,96 @@ /*========================================================================= 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 __itkFslPeakImageConverter_h_ #define __itkFslPeakImageConverter_h_ #include #include #include #include namespace itk{ /** \class FslPeakImageConverter Converts a series of 4D images containing directional (3D vector) information into a vector field stored as mitkFiberBundle. These 4D files are for example generated by the FSL qboot command. */ template< class PixelType > class FslPeakImageConverter : public ProcessObject { public: enum NormalizationMethods { NO_NORM, ///< don't normalize peaks SINGLE_VEC_NORM ///< normalize peaks to length 1 }; typedef FslPeakImageConverter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ProcessObject Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(FslPeakImageConverter, ImageToImageFilter) typedef vnl_vector_fixed< double, 3 > DirectionType; typedef VectorContainer< int, DirectionType > DirectionContainerType; typedef VectorContainer< int, DirectionContainerType::Pointer > ContainerType; typedef Image< float, 4 > InputImageType; typedef VectorContainer< int, InputImageType::Pointer > InputType; typedef Image< Vector< float, 3 >, 3> ItkDirectionImageType; typedef VectorContainer< int, ItkDirectionImageType::Pointer > DirectionImageContainerType; itkSetMacro( NormalizationMethod, NormalizationMethods) ///< normalization method of ODF peaks itkSetMacro( InputImages, InputType::Pointer) ///< MRtrix peak image of type itk::Image< float, 4 > itkGetMacro( OutputFiberBundle, mitk::FiberBundle::Pointer) ///< vector field (peak sizes rescaled for visualization purposes) itkGetMacro( DirectionImageContainer, DirectionImageContainerType::Pointer) ///< container for output peaks + itkSetMacro( InvertX, bool ) + itkSetMacro( InvertY, bool ) + itkSetMacro( InvertZ, bool ) + void GenerateData() override; protected: FslPeakImageConverter(); ~FslPeakImageConverter(){} NormalizationMethods m_NormalizationMethod; ///< normalization method of ODF peaks mitk::FiberBundle::Pointer m_OutputFiberBundle; ///< vector field (peak sizes rescaled for visualization purposes) InputType::Pointer m_InputImages; ///< MRtrix peak image of type itk::Image< float, 4 > DirectionImageContainerType::Pointer m_DirectionImageContainer; ///< container for output peaks + bool m_InvertX; + bool m_InvertY; + bool m_InvertZ; private: }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkFslPeakImageConverter.cpp" #endif #endif //__itkFslPeakImageConverter_h_ diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkMrtrixPeakImageConverter.cpp b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkMrtrixPeakImageConverter.cpp index 9dc2978402..9004e8bd5b 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkMrtrixPeakImageConverter.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkMrtrixPeakImageConverter.cpp @@ -1,211 +1,220 @@ /*=================================================================== 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 __itkMrtrixPeakImageConverter_cpp #define __itkMrtrixPeakImageConverter_cpp #include #include #include #include "itkMrtrixPeakImageConverter.h" #include #include #include #include #include #include #include #include #include namespace itk { template< class PixelType > MrtrixPeakImageConverter< PixelType >::MrtrixPeakImageConverter(): m_NormalizationMethod(NO_NORM) + , m_InvertX(false) + , m_InvertY(false) + , m_InvertZ(false) { } template< class PixelType > void MrtrixPeakImageConverter< PixelType > ::GenerateData() { // output vector field vtkSmartPointer m_VtkCellArray = vtkSmartPointer::New(); vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); Vector spacing4 = m_InputImage->GetSpacing(); Point origin4 = m_InputImage->GetOrigin(); Matrix direction4 = m_InputImage->GetDirection(); ImageRegion<4> imageRegion4 = m_InputImage->GetLargestPossibleRegion(); Vector spacing3; Point origin3; Matrix direction3; ImageRegion<3> imageRegion3; spacing3[0] = spacing4[0]; spacing3[1] = spacing4[1]; spacing3[2] = spacing4[2]; origin3[0] = origin4[0]; origin3[1] = origin4[1]; origin3[2] = origin4[2]; for (int r=0; r<3; r++) for (int c=0; c<3; c++) direction3[r][c] = direction4[r][c]; imageRegion3.SetSize(0, imageRegion4.GetSize()[0]); imageRegion3.SetSize(1, imageRegion4.GetSize()[1]); imageRegion3.SetSize(2, imageRegion4.GetSize()[2]); double minSpacing = spacing3[0]; if (spacing3[1] InputIteratorType; int x = m_InputImage->GetLargestPossibleRegion().GetSize(0); int y = m_InputImage->GetLargestPossibleRegion().GetSize(1); int z = m_InputImage->GetLargestPossibleRegion().GetSize(2); int numDirs = m_InputImage->GetLargestPossibleRegion().GetSize(3)/3; 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); for (int i=0; iSetSpacing( spacing3 ); directionImage->SetOrigin( origin3 ); directionImage->SetDirection( direction3 ); directionImage->SetRegions( imageRegion3 ); directionImage->Allocate(); Vector< PixelType, 3 > nullVec; nullVec.Fill(0.0); directionImage->FillBuffer(nullVec); m_DirectionImageContainer->InsertElement(m_DirectionImageContainer->Size(), directionImage); } double minangle = 0; for (int i=0; i dirVec; dirVec.set_size(4); for (int k=0; k<3; k++) { index.SetElement(3,k+i*3); dirVec[k] = m_InputImage->GetPixel(index); } dirVec[3] = 0; if (dirVec.magnitude()<0.0001) continue; vtkSmartPointer container = vtkSmartPointer::New(); itk::ContinuousIndex center; center[0] = index[0]; center[1] = index[1]; center[2] = index[2]; center[3] = 0; itk::Point worldCenter; m_InputImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); switch (m_NormalizationMethod) { case NO_NORM: break; case SINGLE_VEC_NORM: dirVec.normalize(); break; } dirVec.normalize(); dirVec = m_InputImage->GetDirection()*dirVec; + if (m_InvertX) + dirVec[0] *= -1; + if (m_InvertY) + dirVec[1] *= -1; + if (m_InvertZ) + dirVec[2] *= -1; itk::Point worldStart; worldStart[0] = worldCenter[0]-dirVec[0]/2 * minSpacing; worldStart[1] = worldCenter[1]-dirVec[1]/2 * minSpacing; worldStart[2] = worldCenter[2]-dirVec[2]/2 * minSpacing; vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); container->GetPointIds()->InsertNextId(id); itk::Point worldEnd; worldEnd[0] = worldCenter[0]+dirVec[0]/2 * minSpacing; worldEnd[1] = worldCenter[1]+dirVec[1]/2 * minSpacing; worldEnd[2] = worldCenter[2]+dirVec[2]/2 * minSpacing; id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); container->GetPointIds()->InsertNextId(id); m_VtkCellArray->InsertNextCell(container); // generate direction image typename ItkDirectionImageType::IndexType index2; index2[0] = a; index2[1] = b; index2[2] = c; // workaround ********************************************* dirVec = m_InputImage->GetDirection()*dirVec; dirVec.normalize(); // workaround ********************************************* Vector< PixelType, 3 > pixel; pixel.SetElement(0, dirVec[0]); pixel.SetElement(1, dirVec[1]); pixel.SetElement(2, dirVec[2]); for (int j=0; jElementAt(j); Vector< PixelType, 3 > tempPix = directionImage->GetPixel(index2); if (tempPix.GetNorm()<0.01) { directionImage->SetPixel(index2, pixel); break; } else { if ( fabs(dot_product(tempPix.GetVnlVector(), pixel.GetVnlVector()))>minangle ) { minangle = fabs(dot_product(tempPix.GetVnlVector(), pixel.GetVnlVector())); MITK_INFO << "Minimum angle: " << acos(minangle)*180.0/M_PI; } } } m_NumDirectionsImage->SetPixel(index2, m_NumDirectionsImage->GetPixel(index2)+1); } } vtkSmartPointer directionsPolyData = vtkSmartPointer::New(); directionsPolyData->SetPoints(m_VtkPoints); directionsPolyData->SetLines(m_VtkCellArray); m_OutputFiberBundle = mitk::FiberBundle::New(directionsPolyData); } } #endif // __itkMrtrixPeakImageConverter_cpp diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkMrtrixPeakImageConverter.h b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkMrtrixPeakImageConverter.h index b71034f5f5..1b45e5da6c 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkMrtrixPeakImageConverter.h +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/itkMrtrixPeakImageConverter.h @@ -1,91 +1,98 @@ /*========================================================================= 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 __itkMrtrixPeakImageConverter_h_ #define __itkMrtrixPeakImageConverter_h_ #include #include #include #include namespace itk{ /** \class MrtrixPeakImageConverter Converts a series of 4D images containing directional (3D vector) information into a vector field stored as mitkFiberBundle. These 4D files are for example generated by the FSL qboot command. */ template< class PixelType > class MrtrixPeakImageConverter : public ProcessObject { public: enum NormalizationMethods { NO_NORM, ///< don't normalize peaks SINGLE_VEC_NORM ///< normalize peaks to length 1 }; typedef MrtrixPeakImageConverter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ProcessObject Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(MrtrixPeakImageConverter, ImageToImageFilter) typedef vnl_vector_fixed< double, 3 > DirectionType; typedef VectorContainer< int, DirectionType > DirectionContainerType; typedef VectorContainer< int, DirectionContainerType::Pointer > ContainerType; typedef Image< float, 4 > InputImageType; typedef Image< Vector< float, 3 >, 3> ItkDirectionImageType; typedef VectorContainer< int, ItkDirectionImageType::Pointer > DirectionImageContainerType; typedef itk::Image ItkUcharImgType; itkSetMacro( NormalizationMethod, NormalizationMethods) ///< normalization method of ODF peaks itkSetMacro( InputImage, InputImageType::Pointer) ///< MRtrix direction image of type itk::Image< float, 4 > itkGetMacro( OutputFiberBundle, mitk::FiberBundle::Pointer) ///< vector field (peak sizes rescaled for visualization purposes) itkGetMacro( DirectionImageContainer, DirectionImageContainerType::Pointer) ///< container for output peaks itkGetMacro( NumDirectionsImage, ItkUcharImgType::Pointer) ///< number of peaks per voxel + itkSetMacro( InvertX, bool ) + itkSetMacro( InvertY, bool ) + itkSetMacro( InvertZ, bool ) + void GenerateData() override; protected: MrtrixPeakImageConverter(); ~MrtrixPeakImageConverter(){} NormalizationMethods m_NormalizationMethod; ///< normalization method of ODF peaks mitk::FiberBundle::Pointer m_OutputFiberBundle; ///< vector field (peak sizes rescaled for visualization purposes) InputImageType::Pointer m_InputImage; ///< MRtrix direction image of type itk::Image< float, 4 > DirectionImageContainerType::Pointer m_DirectionImageContainer; ///< container for output peaks ItkUcharImgType::Pointer m_NumDirectionsImage; ///< number of peaks per voxel + bool m_InvertX; + bool m_InvertY; + bool m_InvertZ; private: }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkMrtrixPeakImageConverter.cpp" #endif #endif //__itkMrtrixPeakImageConverter_h_ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/itkMLBSTrackingFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/itkMLBSTrackingFilter.cpp index 112d08a3de..e426ff3dd4 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/itkMLBSTrackingFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/itkMLBSTrackingFilter.cpp @@ -1,594 +1,831 @@ /*=================================================================== 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 __itkMLBSTrackingFilter_txx #define __itkMLBSTrackingFilter_txx #include #include #include +#include #include "itkMLBSTrackingFilter.h" #include #include #include #include +#include "itkPointShell.h" #define _USE_MATH_DEFINES #include namespace itk { template< int ShOrder, int NumImageFeatures > MLBSTrackingFilter< ShOrder, NumImageFeatures > ::MLBSTrackingFilter() - : m_PauseTracking(false) - , m_AbortTracking(false) - , m_FiberPolyData(NULL) - , m_Points(NULL) - , m_Cells(NULL) - , m_AngularThreshold(0.7) - , m_StepSize(0) - , m_MaxLength(10000) - , m_MinTractLength(20.0) - , m_MaxTractLength(400.0) - , m_SeedsPerVoxel(1) - , m_RandomSampling(false) - , m_SamplingDistance(-1) - , m_NumberOfSamples(50) - , m_StoppingRegions(NULL) - , m_SeedImage(NULL) - , m_MaskImage(NULL) - , m_AposterioriCurvCheck(false) - , m_RemoveWmEndFibers(false) - , m_AvoidStop(true) - , m_DemoMode(false) + : m_PauseTracking(false) + , m_AbortTracking(false) + , m_FiberPolyData(NULL) + , m_Points(NULL) + , m_Cells(NULL) + , m_AngularThreshold(0.7) + , m_StepSize(0) + , m_MaxLength(10000) + , m_MinTractLength(20.0) + , m_MaxTractLength(400.0) + , m_SeedsPerVoxel(1) + , m_RandomSampling(false) + , m_SamplingDistance(-1) + , m_DeflectionMod(1.0) + , m_OnlyForwardSamples(true) + , m_UseStopVotes(true) + , m_NumberOfSamples(30) + , m_NumPreviousDirections(1) + , m_StoppingRegions(NULL) + , m_SeedImage(NULL) + , m_MaskImage(NULL) + , m_AposterioriCurvCheck(false) + , m_AvoidStop(true) + , m_DemoMode(false) + , m_SeedOnlyGm(false) + , m_WmLabel(3) // mrtrix 5ttseg labels + , m_GmLabel(1) // mrtrix 5ttseg labels { - this->SetNumberOfRequiredInputs(1); + this->SetNumberOfRequiredInputs(1); } template< int ShOrder, int NumImageFeatures > -double MLBSTrackingFilter< ShOrder, NumImageFeatures > -::RoundToNearest(double num) { - return (num > 0.0) ? floor(num + 0.5) : ceil(num - 0.5); +void MLBSTrackingFilter< ShOrder, NumImageFeatures >::BeforeThreadedGenerateData() +{ + m_InputImage = const_cast(this->GetInput(0)); + m_ForestHandler.InitForTracking(); + + m_FiberPolyData = PolyDataType::New(); + m_Points = vtkSmartPointer< vtkPoints >::New(); + m_Cells = vtkSmartPointer< vtkCellArray >::New(); + + std::vector< double > m_ImageSpacing; m_ImageSpacing.resize(3); + m_ImageSpacing[0] = m_InputImage->GetSpacing()[0]; + m_ImageSpacing[1] = m_InputImage->GetSpacing()[1]; + m_ImageSpacing[2] = m_InputImage->GetSpacing()[2]; + + double minSpacing; + if(m_ImageSpacing[0]GetNumberOfThreads(); i++) + { + PolyDataType poly = PolyDataType::New(); + m_PolyDataContainer.push_back(poly); + } + + if (m_StoppingRegions.IsNull()) + { + m_StoppingRegions = ItkUcharImgType::New(); + m_StoppingRegions->SetSpacing( m_InputImage->GetSpacing() ); + m_StoppingRegions->SetOrigin( m_InputImage->GetOrigin() ); + m_StoppingRegions->SetDirection( m_InputImage->GetDirection() ); + m_StoppingRegions->SetRegions( m_InputImage->GetLargestPossibleRegion() ); + m_StoppingRegions->Allocate(); + m_StoppingRegions->FillBuffer(0); + } + + if (m_SeedImage.IsNull()) + { + m_SeedImage = ItkUcharImgType::New(); + m_SeedImage->SetSpacing( m_InputImage->GetSpacing() ); + m_SeedImage->SetOrigin( m_InputImage->GetOrigin() ); + m_SeedImage->SetDirection( m_InputImage->GetDirection() ); + m_SeedImage->SetRegions( m_InputImage->GetLargestPossibleRegion() ); + m_SeedImage->Allocate(); + m_SeedImage->FillBuffer(1); + } + + if (m_MaskImage.IsNull()) + { + // initialize mask image + m_MaskImage = ItkUcharImgType::New(); + m_MaskImage->SetSpacing( m_InputImage->GetSpacing() ); + m_MaskImage->SetOrigin( m_InputImage->GetOrigin() ); + m_MaskImage->SetDirection( m_InputImage->GetDirection() ); + m_MaskImage->SetRegions( m_InputImage->GetLargestPossibleRegion() ); + m_MaskImage->Allocate(); + m_MaskImage->FillBuffer(1); + } + else + std::cout << "MLBSTrackingFilter: using mask image" << std::endl; + + if (m_AngularThreshold<0.0) + m_AngularThreshold = 0.5*minSpacing; + m_BuildFibersReady = 0; + m_BuildFibersFinished = false; + m_Tractogram.clear(); + m_SamplingPointset = mitk::PointSet::New(); + m_AlternativePointset = mitk::PointSet::New(); + m_StartTime = std::chrono::system_clock::now(); + + if (m_SeedOnlyGm) + InitGrayMatterEndings(); + + if (m_DemoMode) + { + omp_set_num_threads(1); + this->SetNumberOfThreads(1); + } + std::cout << "MLBSTrackingFilter: Angular threshold: " << m_AngularThreshold << std::endl; + std::cout << "MLBSTrackingFilter: Stepsize: " << m_StepSize << " mm" << std::endl; + std::cout << "MLBSTrackingFilter: Seeds per voxel: " << m_SeedsPerVoxel << std::endl; + std::cout << "MLBSTrackingFilter: Max. sampling distance: " << m_SamplingDistance << " mm" << std::endl; + std::cout << "MLBSTrackingFilter: Deflection modifier: " << m_DeflectionMod << std::endl; + std::cout << "MLBSTrackingFilter: Max. tract length: " << m_MaxTractLength << " mm" << std::endl; + std::cout << "MLBSTrackingFilter: Min. tract length: " << m_MinTractLength << " mm" << std::endl; + std::cout << "MLBSTrackingFilter: Use stop votes: " << m_UseStopVotes << std::endl; + std::cout << "MLBSTrackingFilter: Only frontal samples: " << m_OnlyForwardSamples << std::endl; + std::cout << "MLBSTrackingFilter: Starting streamline tracking using " << this->GetNumberOfThreads() << " threads." << std::endl; + this->SetNumberOfThreads(1); } template< int ShOrder, int NumImageFeatures > -void MLBSTrackingFilter< ShOrder, NumImageFeatures >::BeforeThreadedGenerateData() +void MLBSTrackingFilter< ShOrder, NumImageFeatures >::InitGrayMatterEndings() { - m_InputImage = const_cast(this->GetInput(0)); - m_ForestHandler.InitForTracking(); - - m_FiberPolyData = PolyDataType::New(); - m_Points = vtkSmartPointer< vtkPoints >::New(); - m_Cells = vtkSmartPointer< vtkCellArray >::New(); - - std::vector< double > m_ImageSpacing; m_ImageSpacing.resize(3); - m_ImageSpacing[0] = m_InputImage->GetSpacing()[0]; - m_ImageSpacing[1] = m_InputImage->GetSpacing()[1]; - m_ImageSpacing[2] = m_InputImage->GetSpacing()[2]; - - double minSpacing; - if(m_ImageSpacing[0] it(m_FourTTImage, m_FourTTImage->GetLargestPossibleRegion() ); + it.GoToBegin(); + + int candidates = 0; + double prob = 0; + vnl_vector_fixed d1; d1.fill(0.0); + std::deque< vnl_vector_fixed > olddirs; + while (olddirs.size() start; + m_FourTTImage->TransformIndexToPhysicalPoint(s_idx, start); + itk::Point wm_p; + double max = -1; + FiberType fib; + + for (int x : {-1,0,1}) + for (int y : {-1,0,1}) + for (int z : {-1,0,1}) + { + if (x==y && y==z) + continue; - m_SamplingDistance *= minSpacing; - if (m_SamplingDistanceGetNumberOfThreads(); i++) - { - PolyDataType poly = PolyDataType::New(); - m_PolyDataContainer.push_back(poly); - } + if ( !m_FourTTImage->GetLargestPossibleRegion().IsInside(e_idx) || m_FourTTImage->GetPixel(e_idx)!=m_WmLabel ) + continue; - if (m_StoppingRegions.IsNull()) - { - m_StoppingRegions = ItkUcharImgType::New(); - m_StoppingRegions->SetSpacing( m_InputImage->GetSpacing() ); - m_StoppingRegions->SetOrigin( m_InputImage->GetOrigin() ); - m_StoppingRegions->SetDirection( m_InputImage->GetDirection() ); - m_StoppingRegions->SetRegions( m_InputImage->GetLargestPossibleRegion() ); - m_StoppingRegions->Allocate(); - m_StoppingRegions->FillBuffer(0); - } + itk::ContinuousIndex end; + m_FourTTImage->TransformIndexToPhysicalPoint(e_idx, end); - if (m_SeedImage.IsNull()) - { - m_SeedImage = ItkUcharImgType::New(); - m_SeedImage->SetSpacing( m_InputImage->GetSpacing() ); - m_SeedImage->SetOrigin( m_InputImage->GetOrigin() ); - m_SeedImage->SetDirection( m_InputImage->GetDirection() ); - m_SeedImage->SetRegions( m_InputImage->GetLargestPossibleRegion() ); - m_SeedImage->Allocate(); - m_SeedImage->FillBuffer(1); - } + d1 = m_ForestHandler.Classify(end, candidates, olddirs, 0, prob, m_MaskImage); + if (d1.magnitude()<0.0001) + continue; + d1.normalize(); + + vnl_vector_fixed< double, 3 > d2; + d2[0] = end[0] - start[0]; + d2[1] = end[1] - start[1]; + d2[2] = end[2] - start[2]; + d2.normalize(); + double a = fabs(dot_product(d1,d2)); + if (a>max) + { + max = a; + wm_p = end; + } + } - if (m_MaskImage.IsNull()) - { - // initialize mask image - m_MaskImage = ItkUcharImgType::New(); - m_MaskImage->SetSpacing( m_InputImage->GetSpacing() ); - m_MaskImage->SetOrigin( m_InputImage->GetOrigin() ); - m_MaskImage->SetDirection( m_InputImage->GetDirection() ); - m_MaskImage->SetRegions( m_InputImage->GetLargestPossibleRegion() ); - m_MaskImage->Allocate(); - m_MaskImage->FillBuffer(1); + if (max>=0) + { + fib.push_back(start); + fib.push_back(wm_p); + m_GmStubs.push_back(fib); + } + } + ++it; } - else - std::cout << "MLBSTrackingFilter: using mask image" << std::endl; - - if (m_AngularThreshold<0.0) - m_AngularThreshold = 0.5*minSpacing; - m_BuildFibersReady = 0; - m_BuildFibersFinished = false; - m_Threads = 0; - m_Tractogram.clear(); - m_SamplingPointset = mitk::PointSet::New(); - m_AlternativePointset = mitk::PointSet::New(); - m_StartTime = std::chrono::system_clock::now(); - - std::cout << "MLBSTrackingFilter: Angular threshold: " << m_AngularThreshold << std::endl; - std::cout << "MLBSTrackingFilter: Stepsize: " << m_StepSize << " mm" << std::endl; - std::cout << "MLBSTrackingFilter: Seeds per voxel: " << m_SeedsPerVoxel << std::endl; - std::cout << "MLBSTrackingFilter: Max. sampling distance: " << m_SamplingDistance << " mm" << std::endl; - std::cout << "MLBSTrackingFilter: Number of samples: " << m_NumberOfSamples << std::endl; - std::cout << "MLBSTrackingFilter: Max. tract length: " << m_MaxTractLength << " mm" << std::endl; - std::cout << "MLBSTrackingFilter: Min. tract length: " << m_MinTractLength << " mm" << std::endl; - std::cout << "MLBSTrackingFilter: Starting streamline tracking using " << this->GetNumberOfThreads() << " threads." << std::endl; + } } template< int ShOrder, int NumImageFeatures > void MLBSTrackingFilter< ShOrder, NumImageFeatures >::CalculateNewPosition(itk::Point& pos, vnl_vector_fixed& dir) { - // vnl_matrix_fixed< double, 3, 3 > rot = m_FeatureImage->GetDirection().GetTranspose(); - // dir = rot*dir; - - dir *= m_StepSize; - pos[0] += dir[0]; - pos[1] += dir[1]; - pos[2] += dir[2]; + pos[0] += dir[0]*m_StepSize; + pos[1] += dir[1]*m_StepSize; + pos[2] += dir[2]*m_StepSize; } template< int ShOrder, int NumImageFeatures > bool MLBSTrackingFilter< ShOrder, NumImageFeatures > ::IsValidPosition(itk::Point &pos) { - typename FeatureImageType::IndexType idx; - m_InputImage->TransformPhysicalPointToIndex(pos, idx); - if (!m_InputImage->GetLargestPossibleRegion().IsInside(idx) || m_MaskImage->GetPixel(idx)==0) - return false; + typename FeatureImageType::IndexType idx; + m_InputImage->TransformPhysicalPointToIndex(pos, idx); + if (!m_InputImage->GetLargestPossibleRegion().IsInside(idx) || m_MaskImage->GetPixel(idx)==0) + return false; - return true; + return true; } template< int ShOrder, int NumImageFeatures > double MLBSTrackingFilter< ShOrder, NumImageFeatures >::GetRandDouble(double min, double max) { - return (double)(rand()%((int)(10000*(max-min))) + 10000*min)/10000; + return (double)(rand()%((int)(10000*(max-min))) + 10000*min)/10000; } template< int ShOrder, int NumImageFeatures > -vnl_vector_fixed MLBSTrackingFilter< ShOrder, NumImageFeatures >::GetNewDirection(itk::Point &pos, vnl_vector_fixed& olddir) +std::vector< vnl_vector_fixed > MLBSTrackingFilter< ShOrder, NumImageFeatures >::CreateDirections(int NPoints) { - if (m_DemoMode) - { - m_SamplingPointset->Clear(); - m_AlternativePointset->Clear(); - } - vnl_vector_fixed direction; direction.fill(0); - ItkUcharImgType::IndexType idx; - m_StoppingRegions->TransformPhysicalPointToIndex(pos, idx); - if (m_StoppingRegions->GetLargestPossibleRegion().IsInside(idx) && m_StoppingRegions->GetPixel(idx)>0) - return direction; + std::vector< double > theta; theta.resize(NPoints); - if (m_MaskImage.IsNotNull() && ((m_MaskImage->GetLargestPossibleRegion().IsInside(idx) && m_MaskImage->GetPixel(idx)<=0) || !m_MaskImage->GetLargestPossibleRegion().IsInside(idx)) ) - return direction; + std::vector< double > phi; phi.resize(NPoints); - if (olddir.magnitude()>0) - olddir.normalize(); + double C = sqrt(4*M_PI); - int candidates = 0; // number of directions with probability > 0 - double w = 0; // weight of the direction predicted at each sampling point - if (IsValidPosition(pos)) + phi[0] = 0.0; + phi[NPoints-1] = 0.0; + + for(int i=0; i0 && i probeVecs; - itk::Point sample_pos; - int alternatives = 1; - for (int i=0; i d; + std::vector< vnl_vector_fixed > pointshell; - if (m_RandomSampling) - { - d[0] = GetRandDouble(); - d[1] = GetRandDouble(); - d[2] = GetRandDouble(); - d.normalize(); - d *= GetRandDouble(0,m_SamplingDistance); - } - else - { - d = probeVecs.GetDirection(i)*m_SamplingDistance; - } + for(int i=0; i d; + d[0] = cos(theta[i]) * cos(phi[i]); + d[1] = cos(theta[i]) * sin(phi[i]); + d[2] = sin(theta[i]); + pointshell.push_back(d); + } - sample_pos[0] = pos[0] + d[0]; - sample_pos[1] = pos[1] + d[1]; - sample_pos[2] = pos[2] + d[2]; - if(m_DemoMode) - m_SamplingPointset->InsertPoint(i, sample_pos); - - candidates = 0; - vnl_vector_fixed tempDir; tempDir.fill(0.0); - if (IsValidPosition(sample_pos)) - tempDir = m_ForestHandler.Classify(sample_pos, candidates, olddir, m_AngularThreshold, w, m_MaskImage); // sample neighborhood - if (candidates>0 && tempDir.magnitude()>0.001) - { - direction += tempDir*w; - } - else if (m_AvoidStop && candidates==0 && olddir.magnitude()>0) // out of white matter - { - double dot = dot_product(d, olddir); - if (dot >= 0.0) // in front of plane defined by pos and olddir - d = -d + 2*dot*olddir; // reflect - else - d = -d; // invert - - // look a bit further into the other direction - sample_pos[0] = pos[0] + d[0]; - sample_pos[1] = pos[1] + d[1]; - sample_pos[2] = pos[2] + d[2]; - if(m_DemoMode) - m_AlternativePointset->InsertPoint(alternatives, sample_pos); - alternatives++; - candidates = 0; - vnl_vector_fixed tempDir; tempDir.fill(0.0); - if (IsValidPosition(sample_pos)) - tempDir = m_ForestHandler.Classify(sample_pos, candidates, olddir, m_AngularThreshold, w, m_MaskImage); // sample neighborhood - - if (candidates>0 && tempDir.magnitude()>0.001) // are we back in the white matter? - { - direction += d; // go into the direction of the white matter - direction += tempDir*w; // go into the direction of the white matter direction at this location - } - } - } + return pointshell; +} - if (direction.magnitude()>0.001) +template< int ShOrder, int NumImageFeatures > +vnl_vector_fixed MLBSTrackingFilter< ShOrder, NumImageFeatures >::GetNewDirection(itk::Point &pos, std::deque >& olddirs) +{ + if (m_DemoMode) + { + m_SamplingPointset->Clear(); + m_AlternativePointset->Clear(); + } + vnl_vector_fixed direction; direction.fill(0); + + ItkUcharImgType::IndexType idx; + m_StoppingRegions->TransformPhysicalPointToIndex(pos, idx); + if (m_StoppingRegions->GetLargestPossibleRegion().IsInside(idx) && m_StoppingRegions->GetPixel(idx)>0) + return direction; + + if (m_MaskImage.IsNotNull() && ((m_MaskImage->GetLargestPossibleRegion().IsInside(idx) && m_MaskImage->GetPixel(idx)<=0) || !m_MaskImage->GetLargestPossibleRegion().IsInside(idx)) ) + return direction; + + int candidates = 0; // number of directions with probability > 0 + double w = 0; // weight of the direction predicted at each sampling point + if (IsValidPosition(pos)) + { + direction = m_ForestHandler.Classify(pos, candidates, olddirs, m_AngularThreshold, w, m_MaskImage); // get direction proposal at current streamline position + direction *= w; // HERE WE ARE WEIGHTING AGAIN EVEN THOUGH THE OUTPUT DIRECTIONS ARE ALREADY WEIGHTED!!! THE EFFECT OF THIS HAS YET TO BE EVALUATED. + } + + vnl_vector_fixed olddir = olddirs.back(); + std::vector< vnl_vector_fixed > probeVecs = CreateDirections(m_NumberOfSamples); + itk::Point sample_pos; + int alternatives = 1; + int stop_votes = 0; + int possible_stop_votes = 0; + for (int i=0; i d; + bool is_stop_voter = false; + if (m_RandomSampling) { - direction.normalize(); - olddir[0] = direction[0]; - olddir[1] = direction[1]; - olddir[2] = direction[2]; + d[0] = GetRandDouble(); + d[1] = GetRandDouble(); + d[2] = GetRandDouble(); + d.normalize(); + d *= GetRandDouble(0,m_SamplingDistance); } else - direction.fill(0); + { + d = probeVecs.at(i); + double dot = dot_product(d, olddir); + if (m_UseStopVotes && dot>0.7) + { + is_stop_voter = true; + possible_stop_votes++; + } + else if (m_OnlyForwardSamples && dot<0) + continue; + d *= m_SamplingDistance; + } - return direction; + sample_pos[0] = pos[0] + d[0]; + sample_pos[1] = pos[1] + d[1]; + sample_pos[2] = pos[2] + d[2]; + if(m_DemoMode) + m_SamplingPointset->InsertPoint(i, sample_pos); + + candidates = 0; + vnl_vector_fixed tempDir; tempDir.fill(0.0); + if (IsValidPosition(sample_pos)) + tempDir = m_ForestHandler.Classify(sample_pos, candidates, olddirs, m_AngularThreshold, w, m_MaskImage); // sample neighborhood + if (candidates>0 && tempDir.magnitude()>0.001) + { + direction += tempDir*w; + } + else if (m_AvoidStop && candidates==0 && olddir.magnitude()>0) // out of white matter + { + if (is_stop_voter) + stop_votes++; + + double dot = dot_product(d, olddir); + if (dot >= 0.0) // in front of plane defined by pos and olddir + d = -d + 2*dot*olddir; // reflect + else + d = -d; // invert + + // look a bit further into the other direction + sample_pos[0] = pos[0] + d[0]; + sample_pos[1] = pos[1] + d[1]; + sample_pos[2] = pos[2] + d[2]; + if(m_DemoMode) + m_AlternativePointset->InsertPoint(alternatives, sample_pos); + alternatives++; + candidates = 0; + vnl_vector_fixed tempDir; tempDir.fill(0.0); + if (IsValidPosition(sample_pos)) + tempDir = m_ForestHandler.Classify(sample_pos, candidates, olddirs, m_AngularThreshold, w, m_MaskImage); // sample neighborhood + + if (candidates>0 && tempDir.magnitude()>0.001) // are we back in the white matter? + { + direction += d * m_DeflectionMod; // go into the direction of the white matter + direction += tempDir*w; // go into the direction of the white matter direction at this location + } + } + else if (is_stop_voter) + stop_votes++; + } + + if (direction.magnitude()>0.001 && (possible_stop_votes==0 || (float)stop_votes/possible_stop_votes<0.5) ) + direction.normalize(); + else + direction.fill(0); + + return direction; } template< int ShOrder, int NumImageFeatures > double MLBSTrackingFilter< ShOrder, NumImageFeatures >::FollowStreamline(itk::Point pos, vnl_vector_fixed dir, FiberType* fib, double tractLength, bool front) { - vnl_vector_fixed dirOld = dir; - dirOld = dir; - - for (int step=0; step< m_MaxLength/2; step++) + vnl_vector_fixed zero_dir; zero_dir.fill(0.0); + std::deque< vnl_vector_fixed > last_dirs; + for (int i=0; ipush_front(pos); + else + fib->push_back(pos); + + if (m_AposterioriCurvCheck) + { + int curv = CheckCurvature(fib, front); // TODO: Move into classification ??? + if (curv>0) { - tractLength += m_StepSize; + tractLength -= m_StepSize*curv; + while (curv>0) + { if (front) - fib->push_front(pos); + fib->pop_front(); else - fib->push_back(pos); - - if (m_AposterioriCurvCheck) - { - int curv = CheckCurvature(fib, front); // TODO: Move into classification ??? - if (curv>0) - { - tractLength -= m_StepSize*curv; - while (curv>0) - { - if (front) - fib->pop_front(); - else - fib->pop_back(); - curv--; - } - return tractLength; - } - } - - if (tractLength>m_MaxTractLength) - return tractLength; - } - if (m_DemoMode) // CHECK: warum sind die samplingpunkte der streamline in der visualisierung immer einen schritt voras? - { - m_Mutex.Lock(); - m_BuildFibersReady++; - m_Tractogram.push_back(*fib); - BuildFibers(true); - m_Stop = true; - m_Mutex.Unlock(); - - while (m_Stop){ - } + fib->pop_back(); + curv--; + } + return tractLength; } - dir = GetNewDirection(pos, dirOld); + } - while (m_PauseTracking){} + if (tractLength>m_MaxTractLength) + return tractLength; + } - if (dir.magnitude()<0.0001) - return tractLength; +#pragma omp critical + if (m_DemoMode) // CHECK: warum sind die samplingpunkte der streamline in der visualisierung immer einen schritt voras? + { + m_BuildFibersReady++; + m_Tractogram.push_back(*fib); + BuildFibers(true); + m_Stop = true; + + while (m_Stop){ + } } - return tractLength; + + dir.normalize(); + last_dirs.push_back(dir); + if (last_dirs.size()>m_NumPreviousDirections) + last_dirs.pop_front(); + dir = GetNewDirection(pos, last_dirs); + + while (m_PauseTracking){} + + if (dir.magnitude()<0.0001) + return tractLength; + } + return tractLength; } template< int ShOrder, int NumImageFeatures > int MLBSTrackingFilter< ShOrder, NumImageFeatures >::CheckCurvature(FiberType* fib, bool front) { - double m_Distance = 5; - if (fib->size()<3) - return 0; - - double dist = 0; - std::vector< vnl_vector_fixed< float, 3 > > vectors; - vnl_vector_fixed< float, 3 > meanV; meanV.fill(0); - double dev = 0; - - if (front) + double m_Distance = 5; + if (fib->size()<3) + return 0; + + double dist = 0; + std::vector< vnl_vector_fixed< float, 3 > > vectors; + vnl_vector_fixed< float, 3 > meanV; meanV.fill(0); + double dev = 0; + + if (front) + { + int c=0; + while(distsize()-1) { - int c=0; - while(distsize()-1) - { - itk::Point p1 = fib->at(c); - itk::Point p2 = fib->at(c+1); - - vnl_vector_fixed< float, 3 > v; - v[0] = p2[0]-p1[0]; - v[1] = p2[1]-p1[1]; - v[2] = p2[2]-p1[2]; - dist += v.magnitude(); - v.normalize(); - vectors.push_back(v); - if (c==0) - meanV += v; - c++; - } - } - else - { - int c=fib->size()-1; - while(dist0) - { - itk::Point p1 = fib->at(c); - itk::Point p2 = fib->at(c-1); - - vnl_vector_fixed< float, 3 > v; - v[0] = p2[0]-p1[0]; - v[1] = p2[1]-p1[1]; - v[2] = p2[2]-p1[2]; - dist += v.magnitude(); - v.normalize(); - vectors.push_back(v); - if (c==fib->size()-1) - meanV += v; - c--; - } + itk::Point p1 = fib->at(c); + itk::Point p2 = fib->at(c+1); + + vnl_vector_fixed< float, 3 > v; + v[0] = p2[0]-p1[0]; + v[1] = p2[1]-p1[1]; + v[2] = p2[2]-p1[2]; + dist += v.magnitude(); + v.normalize(); + vectors.push_back(v); + if (c==0) + meanV += v; + c++; } - meanV.normalize(); - - for (int c=0; csize()-1; + while(dist0) { - double angle = dot_product(meanV, vectors.at(c)); - if (angle>1.0) - angle = 1.0; - if (angle<-1.0) - angle = -1.0; - dev += acos(angle)*180/M_PI; + itk::Point p1 = fib->at(c); + itk::Point p2 = fib->at(c-1); + + vnl_vector_fixed< float, 3 > v; + v[0] = p2[0]-p1[0]; + v[1] = p2[1]-p1[1]; + v[2] = p2[2]-p1[2]; + dist += v.magnitude(); + v.normalize(); + vectors.push_back(v); + if (c==fib->size()-1) + meanV += v; + c--; } - if (vectors.size()>0) - dev /= vectors.size(); - - if (dev<30) - return 0; - else - return vectors.size(); + } + meanV.normalize(); + + for (int c=0; c1.0) + angle = 1.0; + if (angle<-1.0) + angle = -1.0; + dev += acos(angle)*180/M_PI; + } + if (vectors.size()>0) + dev /= vectors.size(); + + if (dev<30) + return 0; + else + return vectors.size(); } template< int ShOrder, int NumImageFeatures > -void MLBSTrackingFilter< ShOrder, NumImageFeatures >::ThreadedGenerateData(const InputImageRegionType ®ionForThread, ThreadIdType threadId) +void MLBSTrackingFilter< ShOrder, NumImageFeatures >::ThreadedGenerateData(const InputImageRegionType ®ionForThread, ThreadIdType ) { - m_Mutex.Lock(); - m_Threads++; - m_Mutex.Unlock(); + std::vector< itk::Point > seedpoints; + + if (m_GmStubs.empty()) + { typedef ImageRegionConstIterator< ItkUcharImgType > MaskIteratorType; MaskIteratorType sit(m_SeedImage, regionForThread ); MaskIteratorType mit(m_MaskImage, regionForThread ); - sit.GoToBegin(); mit.GoToBegin(); - itk::Point worldPos; + while( !sit.IsAtEnd() ) { - if (sit.Value()==0 || mit.Value()==0) + if (sit.Value()==0 || mit.Value()==0) + { + ++sit; + ++mit; + continue; + } + + for (int s=0; s start; + + if (m_SeedsPerVoxel>1) { - ++sit; - ++mit; - continue; + start[0] = index[0]+GetRandDouble(-0.5, 0.5); + start[1] = index[1]+GetRandDouble(-0.5, 0.5); + start[2] = index[2]+GetRandDouble(-0.5, 0.5); } - - for (int s=0; s start; - unsigned int counter = 0; - - if (m_SeedsPerVoxel>1) - { - start[0] = index[0]+GetRandDouble(-0.5, 0.5); - start[1] = index[1]+GetRandDouble(-0.5, 0.5); - start[2] = index[2]+GetRandDouble(-0.5, 0.5); - } - else - { - start[0] = index[0]; - start[1] = index[1]; - start[2] = index[2]; - } + start[0] = index[0]; + start[1] = index[1]; + start[2] = index[2]; + } - // get staring position - m_SeedImage->TransformContinuousIndexToPhysicalPoint( start, worldPos ); - - // get starting direction - int candidates = 0; - double prob = 0; - vnl_vector_fixed dirOld; dirOld.fill(0.0); - vnl_vector_fixed dir; dir.fill(0.0); - if (IsValidPosition(worldPos)) - dir = m_ForestHandler.Classify(worldPos, candidates, dirOld, 0, prob, m_MaskImage); - if (dir.magnitude()<0.0001) - continue; + itk::Point worldPos; + m_SeedImage->TransformContinuousIndexToPhysicalPoint( start, worldPos ); + seedpoints.push_back(worldPos); + } + ++sit; + ++mit; + } + } + else + { + for (auto s : m_GmStubs) + seedpoints.push_back(s[1]); + } + + int progress = 0; +#pragma omp parallel for + for (unsigned int i=0; i worldPos = seedpoints.at(i); + FiberType fib; + double tractLength = 0; + unsigned int counter = 0; + + // get starting direction + int candidates = 0; + double prob = 0; + vnl_vector_fixed dir; dir.fill(0.0); + std::deque< vnl_vector_fixed > olddirs; + while (olddirs.size() gm_start_dir; + if (!m_GmStubs.empty()) + { + gm_start_dir[0] = m_GmStubs[i][1][0] - m_GmStubs[i][0][0]; + gm_start_dir[1] = m_GmStubs[i][1][1] - m_GmStubs[i][0][1]; + gm_start_dir[2] = m_GmStubs[i][1][2] - m_GmStubs[i][0][2]; + gm_start_dir.normalize(); + olddirs.pop_back(); + olddirs.push_back(gm_start_dir); + } - // forward tracking - tractLength = FollowStreamline(worldPos, dir, &fib, 0, false); - fib.push_front(worldPos); + if (IsValidPosition(worldPos)) + dir = m_ForestHandler.Classify(worldPos, candidates, olddirs, 0, prob, m_MaskImage); + if (dir.magnitude()<0.0001) + continue; - if (m_RemoveWmEndFibers) - { - itk::Point check = fib.back(); - dirOld.fill(0.0); - vnl_vector_fixed check2 = GetNewDirection(check, dirOld); - if (check2.magnitude()>0.001) - { - MITK_INFO << "Detected WM ending. Discarding fiber."; - continue; - } - } + if (!m_GmStubs.empty()) + { + double a = dot_product(gm_start_dir, dir); + if (a<0) + dir = -dir; + } - // backward tracking - tractLength = FollowStreamline(worldPos, -dir, &fib, tractLength, true); - counter = fib.size(); + // forward tracking + tractLength = FollowStreamline(worldPos, dir, &fib, 0, false); + fib.push_front(worldPos); - if (m_RemoveWmEndFibers) - { - itk::Point check = fib.front(); - dirOld.fill(0.0); - vnl_vector_fixed check2 = GetNewDirection(check, dirOld); - if (check2.magnitude()>0.001) - { - MITK_INFO << "Detected WM ending. Discarding fiber."; - continue; - } - } + if (!m_GmStubs.empty()) + { + fib.push_front(m_GmStubs[i][0]); + CheckFiberForGmEnding(&fib); + } + else + { + // backward tracking (only if we don't explicitely start in the GM) + tractLength = FollowStreamline(worldPos, -dir, &fib, tractLength, true); + if (m_FourTTImage.IsNotNull()) + { + CheckFiberForGmEnding(&fib); + std::reverse(fib.begin(),fib.end()); + CheckFiberForGmEnding(&fib); + } + } - if (tractLength -void MLBSTrackingFilter< ShOrder, NumImageFeatures >::BuildFibers(bool check) +void MLBSTrackingFilter< ShOrder, NumImageFeatures >::CheckFiberForGmEnding(FiberType* fib) { - if (m_BuildFibersReadysize()>2) + { + typename ItkUcharImgType::IndexType idx; + m_FourTTImage->TransformPhysicalPointToIndex(fib->back(), idx); + if (m_FourTTImage->GetPixel(idx)==m_WmLabel) + in_wm = true; + else + fib->pop_back(); + } + if (fib->size()<3 || !in_wm) + { + fib->clear(); + return; + } + + // get fiber direction at end point + vnl_vector_fixed< double, 3 > d1; + d1[0] = fib->back()[0] - fib->at(fib->size()-2)[0]; + d1[1] = fib->back()[1] - fib->at(fib->size()-2)[1]; + d1[2] = fib->back()[2] - fib->at(fib->size()-2)[2]; + d1.normalize(); + + // find closest gray matter voxel + typename ItkUcharImgType::IndexType s_idx; + m_FourTTImage->TransformPhysicalPointToIndex(fib->back(), s_idx); + itk::Point gm_endp; + double max = -1; + + for (int x : {-1,0,1}) + for (int y : {-1,0,1}) + for (int z : {-1,0,1}) + { + if (x==y && y==z) + continue; + + typename ItkUcharImgType::IndexType e_idx; + e_idx[0] = s_idx[0] + x; + e_idx[1] = s_idx[1] + y; + e_idx[2] = s_idx[2] + z; + + if ( !m_FourTTImage->GetLargestPossibleRegion().IsInside(e_idx) || m_FourTTImage->GetPixel(e_idx)!=m_GmLabel ) + continue; + + itk::ContinuousIndex end; + m_FourTTImage->TransformIndexToPhysicalPoint(e_idx, end); + vnl_vector_fixed< double, 3 > d2; + d2[0] = end[0] - fib->back()[0]; + d2[1] = end[1] - fib->back()[1]; + d2[2] = end[2] - fib->back()[2]; + d2.normalize(); + double a = dot_product(d1,d2); + if (a>max) + { + max = a; + gm_endp = end; + } + } - m_FiberPolyData = vtkSmartPointer::New(); - vtkSmartPointer vNewLines = vtkSmartPointer::New(); - vtkSmartPointer vNewPoints = vtkSmartPointer::New(); + if (max>=0) + fib->push_back(gm_endp); + else // no gray matter enpoint found -> delete fiber + fib->clear(); +} - for (int i=0; i +void MLBSTrackingFilter< ShOrder, NumImageFeatures >::BuildFibers(bool check) +{ + if (m_BuildFibersReady::New(); + vtkSmartPointer vNewLines = vtkSmartPointer::New(); + vtkSmartPointer vNewPoints = vtkSmartPointer::New(); + + for (int i=0; i container = vtkSmartPointer::New(); + FiberType fib = m_Tractogram.at(i); + for (FiberType::iterator it = fib.begin(); it!=fib.end(); ++it) { - vtkSmartPointer container = vtkSmartPointer::New(); - FiberType fib = m_Tractogram.at(i); - for (FiberType::iterator it = fib.begin(); it!=fib.end(); ++it) - { - vtkIdType id = vNewPoints->InsertNextPoint((*it).GetDataPointer()); - container->GetPointIds()->InsertNextId(id); - } - vNewLines->InsertNextCell(container); + vtkIdType id = vNewPoints->InsertNextPoint((*it).GetDataPointer()); + container->GetPointIds()->InsertNextId(id); } + vNewLines->InsertNextCell(container); + } - if (check) - for (int i=0; iSetPoints(vNewPoints); - m_FiberPolyData->SetLines(vNewLines); - m_BuildFibersFinished = true; + m_FiberPolyData->SetPoints(vNewPoints); + m_FiberPolyData->SetLines(vNewLines); + m_BuildFibersFinished = true; } template< int ShOrder, int NumImageFeatures > void MLBSTrackingFilter< ShOrder, NumImageFeatures >::AfterThreadedGenerateData() { - MITK_INFO << "Generating polydata "; - BuildFibers(false); - MITK_INFO << "done"; - - m_EndTime = std::chrono::system_clock::now(); - std::chrono::hours hh = std::chrono::duration_cast(m_EndTime - m_StartTime); - std::chrono::minutes mm = std::chrono::duration_cast(m_EndTime - m_StartTime); - std::chrono::seconds ss = std::chrono::duration_cast(m_EndTime - m_StartTime); - mm %= 60; - ss %= 60; - MITK_INFO << "Tracking took " << hh.count() << "h, " << mm.count() << "m and " << ss.count() << "s"; + MITK_INFO << "Generating polydata "; + BuildFibers(false); + MITK_INFO << "done"; + + m_EndTime = std::chrono::system_clock::now(); + std::chrono::hours hh = std::chrono::duration_cast(m_EndTime - m_StartTime); + std::chrono::minutes mm = std::chrono::duration_cast(m_EndTime - m_StartTime); + std::chrono::seconds ss = std::chrono::duration_cast(m_EndTime - m_StartTime); + mm %= 60; + ss %= 60; + MITK_INFO << "Tracking took " << hh.count() << "h, " << mm.count() << "m and " << ss.count() << "s"; } } #endif // __itkDiffusionQballPrincipleDirectionsImageFilter_txx diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/itkMLBSTrackingFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/itkMLBSTrackingFilter.h index b7986bd18b..9713f7a15d 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/itkMLBSTrackingFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/itkMLBSTrackingFilter.h @@ -1,178 +1,187 @@ /*=================================================================== 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 __itkMLBSTrackingFilter_h_ #define __itkMLBSTrackingFilter_h_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // classification includes #include #include #include namespace itk{ /** * \brief Performes deterministic streamline tracking on the input tensor image. */ -template< int ShOrder=6, int NumImageFeatures=100 > +template< int ShOrder, int NumImageFeatures > class MLBSTrackingFilter : public ImageToImageFilter< VectorImage< short, 3 >, Image< double, 3 > > { public: typedef MLBSTrackingFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< VectorImage< short, 3 >, Image< double, 3 > > Superclass; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::InputImageRegionType InputImageRegionType; typedef Image< Vector< float, NumImageFeatures > , 3 > FeatureImageType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(MLBSTrackingFilter, ImageToImageFilter) typedef itk::Image ItkUcharImgType; typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkFloatImgType; typedef vtkSmartPointer< vtkPolyData > PolyDataType; typedef std::deque< itk::Point > FiberType; typedef std::vector< FiberType > BundleType; volatile bool m_PauseTracking; bool m_AbortTracking; bool m_BuildFibersFinished; int m_BuildFibersReady; volatile bool m_Stop; mitk::PointSet::Pointer m_SamplingPointset; mitk::PointSet::Pointer m_AlternativePointset; itkGetMacro( FiberPolyData, PolyDataType ) ///< Output fibers itkSetMacro( SeedImage, ItkUcharImgType::Pointer) ///< Seeds are only placed inside of this mask. itkSetMacro( MaskImage, ItkUcharImgType::Pointer) ///< Tracking is only performed inside of this mask image. + itkSetMacro( FourTTImage, ItkUcharImgType::Pointer) ///< itkSetMacro( SeedsPerVoxel, int) ///< One seed placed in the center of each voxel or multiple seeds randomly placed inside each voxel. itkSetMacro( StepSize, double) ///< Integration step size in mm itkSetMacro( MinTractLength, double ) ///< Shorter tracts are discarded. itkSetMacro( MaxTractLength, double ) ///< Streamline progression stops if tract is longer than specified. itkSetMacro( AngularThreshold, double ) ///< Probabilities for directions with larger angular deviation from previous direction is set to 0 itkSetMacro( SamplingDistance, double ) ///< Maximum distance of sampling points in mm - itkSetMacro( NumberOfSamples, int ) ///< Number of sampling points + itkSetMacro( UseStopVotes, bool ) ///< Frontal sampling points can vote for stopping the streamline even if the remaining sampling points keep pushing + itkSetMacro( OnlyForwardSamples, bool ) ///< Don't use sampling points behind the current position in progression direction + itkSetMacro( DeflectionMod, double ) ///< Deflection distance modifier itkSetMacro( StoppingRegions, ItkUcharImgType::Pointer) ///< Streamlines entering a stopping region will stop immediately itkSetMacro( DemoMode, bool ) - itkSetMacro( RemoveWmEndFibers, bool ) ///< Checks if fiber ending is located in the white matter. If this is the case, the streamline is discarded. + itkSetMacro( SeedOnlyGm, bool ) + itkSetMacro( NumberOfSamples, unsigned int ) ///< Number of neighborhood sampling points itkSetMacro( AposterioriCurvCheck, bool ) ///< Checks fiber curvature (angular deviation across 5mm) is larger than 30°. If yes, the streamline progression is stopped. itkSetMacro( AvoidStop, bool ) ///< Use additional sampling points to avoid premature streamline termination itkSetMacro( RandomSampling, bool ) ///< If true, the sampling points are distributed randomly around the current position, not sphericall in the specified sampling distance. + itkSetMacro( NumPreviousDirections, unsigned int ) ///< How many "old" steps do we want to consider in our decision where to go next? - void SetForestHandler( mitk::TrackingForestHandler fh ) ///< Stores random forest classifier and performs actual classification + void SetForestHandler( mitk::TrackingForestHandler fh ) ///< Stores random forest classifier and performs actual classification { m_ForestHandler = fh; } protected: MLBSTrackingFilter(); ~MLBSTrackingFilter() {} + void InitGrayMatterEndings(); + void CheckFiberForGmEnding(FiberType* fib); + void CalculateNewPosition(itk::Point& pos, vnl_vector_fixed& dir); ///< Calculate next integration step. double FollowStreamline(itk::Point pos, vnl_vector_fixed dir, FiberType* fib, double tractLength, bool front); ///< Start streamline in one direction. bool IsValidPosition(itk::Point& pos); ///< Are we outside of the mask image? - vnl_vector_fixed GetNewDirection(itk::Point& pos, vnl_vector_fixed& olddir); ///< Determine new direction by sample voting at the current position taking the last progression direction into account. + vnl_vector_fixed GetNewDirection(itk::Point& pos, std::deque< vnl_vector_fixed >& olddirs); ///< Determine new direction by sample voting at the current position taking the last progression direction into account. double GetRandDouble(double min=-1, double max=1); - double RoundToNearest(double num); + std::vector< vnl_vector_fixed > CreateDirections(int NPoints); void BeforeThreadedGenerateData() override; void ThreadedGenerateData( const InputImageRegionType &outputRegionForThread, ThreadIdType threadId) override; void AfterThreadedGenerateData() override; PolyDataType m_FiberPolyData; vtkSmartPointer m_Points; vtkSmartPointer m_Cells; BundleType m_Tractogram; + BundleType m_GmStubs; double m_AngularThreshold; double m_StepSize; int m_MaxLength; double m_MinTractLength; double m_MaxTractLength; int m_SeedsPerVoxel; bool m_RandomSampling; double m_SamplingDistance; - int m_NumberOfSamples; + double m_DeflectionMod; + bool m_OnlyForwardSamples; + bool m_UseStopVotes; + unsigned int m_NumberOfSamples; + unsigned int m_NumPreviousDirections; + int m_WmLabel; + int m_GmLabel; + bool m_SeedOnlyGm; - SimpleFastMutexLock m_Mutex; ItkUcharImgType::Pointer m_StoppingRegions; ItkUcharImgType::Pointer m_SeedImage; ItkUcharImgType::Pointer m_MaskImage; + ItkUcharImgType::Pointer m_FourTTImage; bool m_AposterioriCurvCheck; - bool m_RemoveWmEndFibers; bool m_AvoidStop; - int m_Threads; bool m_DemoMode; void BuildFibers(bool check); int CheckCurvature(FiberType* fib, bool front); // decision forest - mitk::TrackingForestHandler m_ForestHandler; + mitk::TrackingForestHandler m_ForestHandler; typename InputImageType::Pointer m_InputImage; std::vector< PolyDataType > m_PolyDataContainer; std::chrono::time_point m_StartTime; std::chrono::time_point m_EndTime; private: }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkMLBSTrackingFilter.cpp" #endif #endif //__itkMLBSTrackingFilter_h_ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/mitkTrackingForestHandler.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/mitkTrackingForestHandler.cpp index 92a034581c..b024b599ec 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/mitkTrackingForestHandler.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/mitkTrackingForestHandler.cpp @@ -1,704 +1,935 @@ /*=================================================================== 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 _TrackingForestHandler_cpp #define _TrackingForestHandler_cpp #include "mitkTrackingForestHandler.h" #include #include namespace mitk { - template< int ShOrder, int NumberOfSignalFeatures > - TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::TrackingForestHandler() - : m_WmSampleDistance(-1) - , m_NumTrees(30) - , m_MaxTreeDepth(50) - , m_SampleFraction(1.0) - , m_NumberOfSamples(0) - , m_GmSamplesPerVoxel(50) +template< int ShOrder, int NumberOfSignalFeatures > +TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::TrackingForestHandler() + : m_WmSampleDistance(-1) + , m_NumTrees(30) + , m_MaxTreeDepth(50) + , m_SampleFraction(1.0) + , m_NumberOfSamples(0) + , m_GmSamplesPerVoxel(50) + , m_NumPreviousDirections(1) + , m_ZeroDirWmFeatures(true) + , m_BidirectionalFiberSampling(false) + , m_MaxNumWmSamples(-1) +{ + vnl_vector_fixed ref; ref.fill(0); ref[0]=1; + + itk::OrientationDistributionFunction< double, 200 > odf; + m_DirectionContainer.clear(); + for (unsigned int i = 0; i0) // only used directions on one hemisphere + m_DirectionContainer.push_back(odf.GetDirection(i)); // store indices for later mapping the classifier output to the actual direction } +} + +template< int ShOrder, int NumberOfSignalFeatures > +TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::~TrackingForestHandler() +{ +} + +template< int ShOrder, int NumberOfSignalFeatures > +typename TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::DwiFeatureImageType::PixelType TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::GetDwiFeaturesAtPosition(itk::Point itkP, typename DwiFeatureImageType::Pointer image) +{ + // transform physical point to index coordinates + itk::Index<3> idx; + itk::ContinuousIndex< double, 3> cIdx; + image->TransformPhysicalPointToIndex(itkP, idx); + image->TransformPhysicalPointToContinuousIndex(itkP, cIdx); + + typename DwiFeatureImageType::PixelType pix; pix.Fill(0.0); + if ( image->GetLargestPossibleRegion().IsInside(idx) ) + pix = image->GetPixel(idx); + else + return pix; - template< int ShOrder, int NumberOfSignalFeatures > - TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::~TrackingForestHandler() + double frac_x = cIdx[0] - idx[0]; + double frac_y = cIdx[1] - idx[1]; + double frac_z = cIdx[2] - idx[2]; + if (frac_x<0) { + idx[0] -= 1; + frac_x += 1; } - - template< int ShOrder, int NumberOfSignalFeatures > - typename TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::InterpolatedRawImageType::PixelType TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::GetImageValues(itk::Point itkP, typename InterpolatedRawImageType::Pointer image) + if (frac_y<0) { - // transform physical point to index coordinates - itk::Index<3> idx; - itk::ContinuousIndex< double, 3> cIdx; - image->TransformPhysicalPointToIndex(itkP, idx); - image->TransformPhysicalPointToContinuousIndex(itkP, cIdx); - - typename InterpolatedRawImageType::PixelType pix; pix.Fill(0.0); - if ( image->GetLargestPossibleRegion().IsInside(idx) ) - pix = image->GetPixel(idx); - else - return pix; - - double frac_x = cIdx[0] - idx[0]; - double frac_y = cIdx[1] - idx[1]; - double frac_z = cIdx[2] - idx[2]; - if (frac_x<0) - { - idx[0] -= 1; - frac_x += 1; - } - if (frac_y<0) - { - idx[1] -= 1; - frac_y += 1; - } - if (frac_z<0) - { - idx[2] -= 1; - frac_z += 1; - } - frac_x = 1-frac_x; - frac_y = 1-frac_y; - frac_z = 1-frac_z; + idx[1] -= 1; + frac_y += 1; + } + if (frac_z<0) + { + idx[2] -= 1; + frac_z += 1; + } + frac_x = 1-frac_x; + frac_y = 1-frac_y; + frac_z = 1-frac_z; - // int coordinates inside image? - if (idx[0] >= 0 && idx[0] < image->GetLargestPossibleRegion().GetSize(0)-1 && + // int coordinates inside image? + if (idx[0] >= 0 && idx[0] < image->GetLargestPossibleRegion().GetSize(0)-1 && idx[1] >= 0 && idx[1] < image->GetLargestPossibleRegion().GetSize(1)-1 && idx[2] >= 0 && idx[2] < image->GetLargestPossibleRegion().GetSize(2)-1) + { + // trilinear interpolation + vnl_vector_fixed interpWeights; + interpWeights[0] = ( frac_x)*( frac_y)*( frac_z); + interpWeights[1] = (1-frac_x)*( frac_y)*( frac_z); + interpWeights[2] = ( frac_x)*(1-frac_y)*( frac_z); + interpWeights[3] = ( frac_x)*( frac_y)*(1-frac_z); + interpWeights[4] = (1-frac_x)*(1-frac_y)*( frac_z); + interpWeights[5] = ( frac_x)*(1-frac_y)*(1-frac_z); + interpWeights[6] = (1-frac_x)*( frac_y)*(1-frac_z); + interpWeights[7] = (1-frac_x)*(1-frac_y)*(1-frac_z); + + pix = image->GetPixel(idx) * interpWeights[0]; + typename DwiFeatureImageType::IndexType tmpIdx = idx; tmpIdx[0]++; + pix += image->GetPixel(tmpIdx) * interpWeights[1]; + tmpIdx = idx; tmpIdx[1]++; + pix += image->GetPixel(tmpIdx) * interpWeights[2]; + tmpIdx = idx; tmpIdx[2]++; + pix += image->GetPixel(tmpIdx) * interpWeights[3]; + tmpIdx = idx; tmpIdx[0]++; tmpIdx[1]++; + pix += image->GetPixel(tmpIdx) * interpWeights[4]; + tmpIdx = idx; tmpIdx[1]++; tmpIdx[2]++; + pix += image->GetPixel(tmpIdx) * interpWeights[5]; + tmpIdx = idx; tmpIdx[2]++; tmpIdx[0]++; + pix += image->GetPixel(tmpIdx) * interpWeights[6]; + tmpIdx = idx; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++; + pix += image->GetPixel(tmpIdx) * interpWeights[7]; + } + + return pix; +} + +template< int ShOrder, int NumberOfSignalFeatures > +void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::InputDataValidForTracking() +{ + if (m_InputDwis.empty()) + mitkThrow() << "No diffusion-weighted images set!"; + if (!IsForestValid()) + mitkThrow() << "No or invalid random forest detected!"; +} + +template< int ShOrder, int NumberOfSignalFeatures> +template +typename std::enable_if< NumberOfSignalFeatures <=99, T >::type TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::InitDwiImageFeatures(mitk::Image::Pointer mitk_dwi) +{ + MITK_INFO << "Calculating spherical harmonics features"; + typedef itk::AnalyticalDiffusionQballReconstructionImageFilter InterpolationFilterType; + + typename InterpolationFilterType::Pointer filter = InterpolationFilterType::New(); + filter->SetGradientImage( mitk::DiffusionPropertyHelper::GetGradientContainer(mitk_dwi), mitk::DiffusionPropertyHelper::GetItkVectorImage(mitk_dwi) ); + filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(mitk_dwi)); + filter->SetLambda(0.006); + filter->SetNormalizationMethod(InterpolationFilterType::QBAR_RAW_SIGNAL); + filter->Update(); + + m_DwiFeatureImages.push_back(filter->GetCoefficientImage()); +} + +template< int ShOrder, int NumberOfSignalFeatures> +template +typename std::enable_if< NumberOfSignalFeatures >=100, T >::type TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::InitDwiImageFeatures(mitk::Image::Pointer mitk_dwi) +{ + MITK_INFO << "Interpolating raw dwi signal features"; + typedef itk::AnalyticalDiffusionQballReconstructionImageFilter InterpolationFilterType; + + typename InterpolationFilterType::Pointer filter = InterpolationFilterType::New(); + filter->SetGradientImage( mitk::DiffusionPropertyHelper::GetGradientContainer(mitk_dwi), mitk::DiffusionPropertyHelper::GetItkVectorImage(mitk_dwi) ); + filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(mitk_dwi)); + filter->SetLambda(0.006); + filter->SetNormalizationMethod(InterpolationFilterType::QBAR_RAW_SIGNAL); + filter->Update(); + + typename DwiFeatureImageType::Pointer dwiFeatureImage = DwiFeatureImageType::New(); + dwiFeatureImage->SetSpacing(filter->GetOutput()->GetSpacing()); + dwiFeatureImage->SetOrigin(filter->GetOutput()->GetOrigin()); + dwiFeatureImage->SetDirection(filter->GetOutput()->GetDirection()); + dwiFeatureImage->SetLargestPossibleRegion(filter->GetOutput()->GetLargestPossibleRegion()); + dwiFeatureImage->SetBufferedRegion(filter->GetOutput()->GetLargestPossibleRegion()); + dwiFeatureImage->SetRequestedRegion(filter->GetOutput()->GetLargestPossibleRegion()); + dwiFeatureImage->Allocate(); + + // get signal values and store them in the feature image + vnl_vector_fixed ref; ref.fill(0); ref[0]=1; + itk::OrientationDistributionFunction< double, 2*NumberOfSignalFeatures > odf; + itk::ImageRegionIterator< typename InterpolationFilterType::OutputImageType > it(filter->GetOutput(), filter->GetOutput()->GetLargestPossibleRegion()); + while(!it.IsAtEnd()) + { + typename DwiFeatureImageType::PixelType pix; + int f = 0; + for (unsigned int i = 0; i interpWeights; - interpWeights[0] = ( frac_x)*( frac_y)*( frac_z); - interpWeights[1] = (1-frac_x)*( frac_y)*( frac_z); - interpWeights[2] = ( frac_x)*(1-frac_y)*( frac_z); - interpWeights[3] = ( frac_x)*( frac_y)*(1-frac_z); - interpWeights[4] = (1-frac_x)*(1-frac_y)*( frac_z); - interpWeights[5] = ( frac_x)*(1-frac_y)*(1-frac_z); - interpWeights[6] = (1-frac_x)*( frac_y)*(1-frac_z); - interpWeights[7] = (1-frac_x)*(1-frac_y)*(1-frac_z); - - pix = image->GetPixel(idx) * interpWeights[0]; - typename InterpolatedRawImageType::IndexType tmpIdx = idx; tmpIdx[0]++; - pix += image->GetPixel(tmpIdx) * interpWeights[1]; - tmpIdx = idx; tmpIdx[1]++; - pix += image->GetPixel(tmpIdx) * interpWeights[2]; - tmpIdx = idx; tmpIdx[2]++; - pix += image->GetPixel(tmpIdx) * interpWeights[3]; - tmpIdx = idx; tmpIdx[0]++; tmpIdx[1]++; - pix += image->GetPixel(tmpIdx) * interpWeights[4]; - tmpIdx = idx; tmpIdx[1]++; tmpIdx[2]++; - pix += image->GetPixel(tmpIdx) * interpWeights[5]; - tmpIdx = idx; tmpIdx[2]++; tmpIdx[0]++; - pix += image->GetPixel(tmpIdx) * interpWeights[6]; - tmpIdx = idx; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++; - pix += image->GetPixel(tmpIdx) * interpWeights[7]; + if (dot_product(ref, odf.GetDirection(i))>0) // only used directions on one hemisphere + { + pix[f] = it.Get()[i]; + f++; + } } + dwiFeatureImage->SetPixel(it.GetIndex(), pix); + ++it; + } + m_DwiFeatureImages.push_back(dwiFeatureImage); +} - return pix; +template< int ShOrder, int NumberOfSignalFeatures > +void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::InitForTracking() +{ + InputDataValidForTracking(); + m_DwiFeatureImages.clear(); + InitDwiImageFeatures<>(m_InputDwis.at(0)); +} + +template< int ShOrder, int NumberOfSignalFeatures > +template< class TPixelType > +TPixelType TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::GetImageValue(itk::Point itkP, itk::Image* image, bool interpolate) +{ + // transform physical point to index coordinates + itk::Index<3> idx; + itk::ContinuousIndex< double, 3> cIdx; + image->TransformPhysicalPointToIndex(itkP, idx); + image->TransformPhysicalPointToContinuousIndex(itkP, cIdx); + + TPixelType pix = 0.0; + if ( image->GetLargestPossibleRegion().IsInside(idx) ) + { + pix = image->GetPixel(idx); + if (!interpolate) + return pix; } + else + return pix; - template< int ShOrder, int NumberOfSignalFeatures > - void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::InputDataValidForTracking() + double frac_x = cIdx[0] - idx[0]; + double frac_y = cIdx[1] - idx[1]; + double frac_z = cIdx[2] - idx[2]; + if (frac_x<0) + { + idx[0] -= 1; + frac_x += 1; + } + if (frac_y<0) { - if (m_RawData.empty()) - mitkThrow() << "No diffusion-weighted images set!"; - if (!IsForestValid()) - mitkThrow() << "No or invalid random forest detected!"; + idx[1] -= 1; + frac_y += 1; } + if (frac_z<0) + { + idx[2] -= 1; + frac_z += 1; + } + frac_x = 1-frac_x; + frac_y = 1-frac_y; + frac_z = 1-frac_z; - template< int ShOrder, int NumberOfSignalFeatures > - void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::InitForTracking() + // int coordinates inside image? + if (idx[0] >= 0 && idx[0] < image->GetLargestPossibleRegion().GetSize(0)-1 && + idx[1] >= 0 && idx[1] < image->GetLargestPossibleRegion().GetSize(1)-1 && + idx[2] >= 0 && idx[2] < image->GetLargestPossibleRegion().GetSize(2)-1) { - InputDataValidForTracking(); - - MITK_INFO << "Spherically interpolating raw data and creating feature image ..."; - typedef itk::AnalyticalDiffusionQballReconstructionImageFilter InterpolationFilterType; - - typename InterpolationFilterType::Pointer filter = InterpolationFilterType::New(); - filter->SetGradientImage( mitk::DiffusionPropertyHelper::GetGradientContainer(m_RawData.at(0)), mitk::DiffusionPropertyHelper::GetItkVectorImage(m_RawData.at(0)) ); - filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(m_RawData.at(0))); - filter->SetLambda(0.006); - filter->SetNormalizationMethod(InterpolationFilterType::QBAR_RAW_SIGNAL); - filter->Update(); - - vnl_vector_fixed ref; ref.fill(0); ref[0]=1; - itk::OrientationDistributionFunction< double, NumberOfSignalFeatures*2 > odf; - m_DirectionIndices.clear(); - for (unsigned int f=0; f0) // only used directions on one hemisphere - m_DirectionIndices.push_back(f); // store indices for later mapping the classifier output to the actual direction - } + // trilinear interpolation + vnl_vector_fixed interpWeights; + interpWeights[0] = ( frac_x)*( frac_y)*( frac_z); + interpWeights[1] = (1-frac_x)*( frac_y)*( frac_z); + interpWeights[2] = ( frac_x)*(1-frac_y)*( frac_z); + interpWeights[3] = ( frac_x)*( frac_y)*(1-frac_z); + interpWeights[4] = (1-frac_x)*(1-frac_y)*( frac_z); + interpWeights[5] = ( frac_x)*(1-frac_y)*(1-frac_z); + interpWeights[6] = (1-frac_x)*( frac_y)*(1-frac_z); + interpWeights[7] = (1-frac_x)*(1-frac_y)*(1-frac_z); - m_FeatureImage = FeatureImageType::New(); - m_FeatureImage->SetSpacing(filter->GetOutput()->GetSpacing()); - m_FeatureImage->SetOrigin(filter->GetOutput()->GetOrigin()); - m_FeatureImage->SetDirection(filter->GetOutput()->GetDirection()); - m_FeatureImage->SetLargestPossibleRegion(filter->GetOutput()->GetLargestPossibleRegion()); - m_FeatureImage->SetBufferedRegion(filter->GetOutput()->GetLargestPossibleRegion()); - m_FeatureImage->SetRequestedRegion(filter->GetOutput()->GetLargestPossibleRegion()); - m_FeatureImage->Allocate(); - - // get signal values and store them in the feature image - itk::ImageRegionIterator< typename InterpolationFilterType::OutputImageType > it(filter->GetOutput(), filter->GetOutput()->GetLargestPossibleRegion()); - while(!it.IsAtEnd()) - { - typename FeatureImageType::PixelType pix; - for (unsigned int f=0; fSetPixel(it.GetIndex(), pix); - ++it; - } + pix = image->GetPixel(idx) * interpWeights[0]; - //m_Forest->multithreadPrediction = false; - } + typename itk::Image::IndexType tmpIdx = idx; tmpIdx[0]++; + pix += image->GetPixel(tmpIdx) * interpWeights[1]; - template< int ShOrder, int NumberOfSignalFeatures > - typename TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::FeatureImageType::PixelType TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::GetFeatureValues(itk::Point itkP) - { - // transform physical point to index coordinates - itk::Index<3> idx; - itk::ContinuousIndex< double, 3> cIdx; - m_FeatureImage->TransformPhysicalPointToIndex(itkP, idx); - m_FeatureImage->TransformPhysicalPointToContinuousIndex(itkP, cIdx); - - typename FeatureImageType::PixelType pix; pix.Fill(0.0); - if ( m_FeatureImage->GetLargestPossibleRegion().IsInside(idx) ) - pix = m_FeatureImage->GetPixel(idx); - else - return pix; + tmpIdx = idx; tmpIdx[1]++; + pix += image->GetPixel(tmpIdx) * interpWeights[2]; - double frac_x = cIdx[0] - idx[0]; - double frac_y = cIdx[1] - idx[1]; - double frac_z = cIdx[2] - idx[2]; - if (frac_x<0) - { - idx[0] -= 1; - frac_x += 1; - } - if (frac_y<0) - { - idx[1] -= 1; - frac_y += 1; - } - if (frac_z<0) - { - idx[2] -= 1; - frac_z += 1; - } - frac_x = 1-frac_x; - frac_y = 1-frac_y; - frac_z = 1-frac_z; - - // int coordinates inside image? - if (idx[0] >= 0 && idx[0] < m_FeatureImage->GetLargestPossibleRegion().GetSize(0)-1 && - idx[1] >= 0 && idx[1] < m_FeatureImage->GetLargestPossibleRegion().GetSize(1)-1 && - idx[2] >= 0 && idx[2] < m_FeatureImage->GetLargestPossibleRegion().GetSize(2)-1) - { - // trilinear interpolation - vnl_vector_fixed interpWeights; - interpWeights[0] = ( frac_x)*( frac_y)*( frac_z); - interpWeights[1] = (1-frac_x)*( frac_y)*( frac_z); - interpWeights[2] = ( frac_x)*(1-frac_y)*( frac_z); - interpWeights[3] = ( frac_x)*( frac_y)*(1-frac_z); - interpWeights[4] = (1-frac_x)*(1-frac_y)*( frac_z); - interpWeights[5] = ( frac_x)*(1-frac_y)*(1-frac_z); - interpWeights[6] = (1-frac_x)*( frac_y)*(1-frac_z); - interpWeights[7] = (1-frac_x)*(1-frac_y)*(1-frac_z); - - pix = m_FeatureImage->GetPixel(idx) * interpWeights[0]; - typename FeatureImageType::IndexType tmpIdx = idx; tmpIdx[0]++; - pix += m_FeatureImage->GetPixel(tmpIdx) * interpWeights[1]; - tmpIdx = idx; tmpIdx[1]++; - pix += m_FeatureImage->GetPixel(tmpIdx) * interpWeights[2]; - tmpIdx = idx; tmpIdx[2]++; - pix += m_FeatureImage->GetPixel(tmpIdx) * interpWeights[3]; - tmpIdx = idx; tmpIdx[0]++; tmpIdx[1]++; - pix += m_FeatureImage->GetPixel(tmpIdx) * interpWeights[4]; - tmpIdx = idx; tmpIdx[1]++; tmpIdx[2]++; - pix += m_FeatureImage->GetPixel(tmpIdx) * interpWeights[5]; - tmpIdx = idx; tmpIdx[2]++; tmpIdx[0]++; - pix += m_FeatureImage->GetPixel(tmpIdx) * interpWeights[6]; - tmpIdx = idx; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++; - pix += m_FeatureImage->GetPixel(tmpIdx) * interpWeights[7]; - } + tmpIdx = idx; tmpIdx[2]++; + pix += image->GetPixel(tmpIdx) * interpWeights[3]; - return pix; + tmpIdx = idx; tmpIdx[0]++; tmpIdx[1]++; + pix += image->GetPixel(tmpIdx) * interpWeights[4]; + + tmpIdx = idx; tmpIdx[1]++; tmpIdx[2]++; + pix += image->GetPixel(tmpIdx) * interpWeights[5]; + + tmpIdx = idx; tmpIdx[2]++; tmpIdx[0]++; + pix += image->GetPixel(tmpIdx) * interpWeights[6]; + + tmpIdx = idx; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++; + pix += image->GetPixel(tmpIdx) * interpWeights[7]; } - template< int ShOrder, int NumberOfSignalFeatures > - vnl_vector_fixed TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::Classify(itk::Point& pos, int& candidates, vnl_vector_fixed& olddir, double angularThreshold, double& w, ItkUcharImgType::Pointer mask) - { - vnl_vector_fixed direction; direction.fill(0); + if (pix!=pix) + mitkThrow() << "nan values in volume modification image!"; + + return pix; +} - itk::Index<3> idx; - m_FeatureImage->TransformPhysicalPointToIndex(pos, idx); - if (mask.IsNotNull() && ((mask->GetLargestPossibleRegion().IsInside(idx) && mask->GetPixel(idx)<=0) || !mask->GetLargestPossibleRegion().IsInside(idx)) ) - return direction; +template< int ShOrder, int NumberOfSignalFeatures > +vnl_vector_fixed TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::Classify(itk::Point& pos, int& candidates, std::deque >& olddirs, double angularThreshold, double& w, ItkUcharImgType::Pointer mask) +{ + + vnl_vector_fixed output_direction; output_direction.fill(0); - // store feature pixel values in a vigra data type - vigra::MultiArray<2, double> featureData = vigra::MultiArray<2, double>( vigra::Shape2(1,NumberOfSignalFeatures+3) ); - typename FeatureImageType::PixelType featurePixel = GetFeatureValues(pos); - for (unsigned int f=0; f idx; + m_DwiFeatureImages.at(0)->TransformPhysicalPointToIndex(pos, idx); + if (mask.IsNotNull() && ((mask->GetLargestPossibleRegion().IsInside(idx) && mask->GetPixel(idx)<=0) || !mask->GetLargestPossibleRegion().IsInside(idx)) ) + return output_direction; - // append normalized previous direction to feature vector + // store feature pixel values in a vigra data type + vigra::MultiArray<2, double> featureData = vigra::MultiArray<2, double>( vigra::Shape2(1,m_Forest->feature_count()) ); + typename DwiFeatureImageType::PixelType dwiFeaturePixel = GetDwiFeaturesAtPosition(pos, m_DwiFeatureImages.at(0)); + for (unsigned int f=0; f ref; ref.fill(0); ref[0]=1; + for (auto d : olddirs) + { int c = 0; - vnl_vector_fixed ref; ref.fill(0); ref[0]=1; - for (unsigned int f=NumberOfSignalFeatures; f0) + { + int c = 0; + for (auto img : m_AdditionalFeatureImages.at(0)) + { + float v = GetImageValue(pos, img, false); + featureData(0,NumberOfSignalFeatures+m_NumPreviousDirections*3+c) = v; + c++; + } + } - // perform classification - vigra::MultiArray<2, double> probs(vigra::Shape2(1, m_Forest->class_count())); - m_Forest->predictProbabilities(featureData, probs); + // perform classification + vigra::MultiArray<2, double> probs(vigra::Shape2(1, m_Forest->class_count())); + m_Forest->predictProbabilities(featureData, probs); - double pNonFib = 0; // probability that we left the white matter - w = 0; // weight of the predicted direction - candidates = 0; // directions with probability > 0 - for (int i=0; iclass_count(); i++) // for each class (number of possible directions + out-of-wm class) + vnl_vector_fixed last_dir; + if (!olddirs.empty()) + last_dir = olddirs.back(); + + + double pNonFib = 0; // probability that we left the white matter + w = 0; // weight of the predicted direction + candidates = 0; // directions with probability > 0 + for (int i=0; iclass_count(); i++) // for each class (number of possible directions + out-of-wm class) + { + if (probs(0,i)>0) // if probability of respective class is 0, do nothing { - if (probs(0,i)>0) // if probability of respective class is 0, do nothing + // get label of class (does not correspond to the loop variable i) + int classLabel = 0; + m_Forest->ext_param_.to_classlabel(i, classLabel); + + if (classLabelext_param_.to_classlabel(i, classLabel); + candidates++; // now we have one direction more with probability > 0 (DO WE NEED THIS???) + vnl_vector_fixed d = m_DirectionContainer.at(classLabel); // get direction vector assiciated with the respective direction index - if (classLabel0) // do we have a previous streamline direction or did we just start? { - candidates++; // now we have one direction more with probability > 0 (DO WE NEED THIS???) - vnl_vector_fixed d = m_DirContainer.GetDirection(m_DirectionIndices.at(classLabel)); // get direction vector assiciated with the respective direction index + // TODO: check if hard curvature threshold is necessary. + // alternatively try square of dot pruduct as weight. + // TODO: check if additional weighting with dot product as directional prior is necessary. are there alternatives on the classification level? - if (olddir.magnitude()>0) // do we have a previous streamline direction or did we just start? - { - // TODO: check if hard curvature threshold is necessary. - // alternatively try square of dot pruduct as weight. - // TODO: check if additional weighting with dot product as directional prior is necessary. are there alternatives on the classification level? - - double dot = dot_product(d, olddir); // claculate angle between the candidate direction vector and the previous streamline direction - if (fabs(dot)>angularThreshold) // is angle between the directions smaller than our hard threshold? - { - if (dot<0) // make sure we don't walk backwards - d *= -1; - double w_i = probs(0,i)*fabs(dot); - direction += w_i*d; // weight contribution to output direction with its probability and the angular deviation from the previous direction - w += w_i; // increase output weight of the final direction - } - } - else + double dot = dot_product(d, last_dir); // claculate angle between the candidate direction vector and the previous streamline direction + if (fabs(dot)>angularThreshold) // is angle between the directions smaller than our hard threshold? { - direction += probs(0,i)*d; - w += probs(0,i); + if (dot<0) // make sure we don't walk backwards + d *= -1; + double w_i = probs(0,i)*fabs(dot); + output_direction += w_i*d; // weight contribution to output direction with its probability and the angular deviation from the previous direction + w += w_i; // increase output weight of the final direction } } else - pNonFib += probs(0,i); // probability that we are not in the whte matter anymore + { + output_direction += probs(0,i)*d; + w += probs(0,i); + } } + else + pNonFib += probs(0,i); // probability that we are not in the white matter anymore } - - // if we did not find a suitable direction, make sure that we return (0,0,0) - if (pNonFib>w && w>0) - { - candidates = 0; - w = 0; - direction.fill(0.0); - } - - return direction; } - template< int ShOrder, int NumberOfSignalFeatures > - void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::StartTraining() + // if we did not find a suitable direction, make sure that we return (0,0,0) + if (pNonFib>w && w>0) { - m_StartTime = std::chrono::system_clock::now(); - InputDataValidForTraining(); - PreprocessInputDataForTraining(); - CalculateFeaturesForTraining(); - TrainForest(); - m_EndTime = std::chrono::system_clock::now(); - std::chrono::hours hh = std::chrono::duration_cast(m_EndTime - m_StartTime); - std::chrono::minutes mm = std::chrono::duration_cast(m_EndTime - m_StartTime); - mm %= 60; - MITK_INFO << "Training took " << hh.count() << "h and " << mm.count() << "m"; + candidates = 0; + w = 0; + output_direction.fill(0.0); } - template< int ShOrder, int NumberOfSignalFeatures > - void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::InputDataValidForTraining() - { - if (m_RawData.empty()) - mitkThrow() << "No diffusion-weighted images set!"; - if (m_Tractograms.empty()) - mitkThrow() << "No tractograms set!"; - if (m_RawData.size()!=m_Tractograms.size()) - mitkThrow() << "Unequal number of diffusion-weighted images and tractograms detected!"; - } + return output_direction; +} - template< int ShOrder, int NumberOfSignalFeatures > - bool TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::IsForestValid() +template< int ShOrder, int NumberOfSignalFeatures > +void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::StartTraining() +{ + m_StartTime = std::chrono::system_clock::now(); + InputDataValidForTraining(); + InitForTraining(); + CalculateTrainingSamples(); + + MITK_INFO << "Maximum tree depths: " << m_MaxTreeDepth; + MITK_INFO << "Sample fraction per tree: " << m_SampleFraction; + MITK_INFO << "Number of trees: " << m_NumTrees; + + DefaultSplitType splitter; + splitter.UsePointBasedWeights(true); + splitter.SetWeights(m_Weights); + splitter.UseRandomSplit(false); + splitter.SetPrecision(mitk::eps); + splitter.SetMaximumTreeDepth(m_MaxTreeDepth); + + std::vector< std::shared_ptr< vigra::RandomForest > > trees; + int count = 0; +#pragma omp parallel for + for (int i = 0; i < m_NumTrees; ++i) { - if(m_Forest && m_Forest->tree_count()>0 && m_Forest->feature_count()==(NumberOfSignalFeatures+3)) - return true; - return false; + std::shared_ptr< vigra::RandomForest > lrf = std::make_shared< vigra::RandomForest >(); + lrf->set_options().use_stratification(vigra::RF_NONE); // How the data should be made equal + lrf->set_options().sample_with_replacement(true); // if sampled with replacement or not + lrf->set_options().samples_per_tree(m_SampleFraction); // Fraction of samples that are used to train a tree + lrf->set_options().tree_count(1); // Number of trees that are calculated; + lrf->set_options().min_split_node_size(5); // Minimum number of datapoints that must be in a node + lrf->ext_param_.max_tree_depth = m_MaxTreeDepth; + + lrf->learn(m_FeatureData, m_LabelData,vigra::rf::visitors::VisitorBase(),splitter); +#pragma omp critical + { + count++; + MITK_INFO << "Tree " << count << " finished training."; + trees.push_back(lrf); + } } - template< int ShOrder, int NumberOfSignalFeatures > - void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::PreprocessInputDataForTraining() + for (int i = 1; i < m_NumTrees; ++i) + trees.at(0)->trees_.push_back(trees.at(i)->trees_[0]); + + m_Forest = trees.at(0); + m_Forest->options_.tree_count_ = m_NumTrees; + MITK_INFO << "Training finsihed"; + + m_EndTime = std::chrono::system_clock::now(); + std::chrono::hours hh = std::chrono::duration_cast(m_EndTime - m_StartTime); + std::chrono::minutes mm = std::chrono::duration_cast(m_EndTime - m_StartTime); + mm %= 60; + MITK_INFO << "Training took " << hh.count() << "h and " << mm.count() << "m"; +} + +template< int ShOrder, int NumberOfSignalFeatures > +void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::InputDataValidForTraining() +{ + if (m_InputDwis.empty()) + mitkThrow() << "No diffusion-weighted images set!"; + if (m_Tractograms.empty()) + mitkThrow() << "No tractograms set!"; + if (m_InputDwis.size()!=m_Tractograms.size()) + mitkThrow() << "Unequal number of diffusion-weighted images and tractograms detected!"; +} + +template< int ShOrder, int NumberOfSignalFeatures > +bool TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::IsForestValid() +{ + int additional_features = 0; + if (m_AdditionalFeatureImages.size()>0) + additional_features = m_AdditionalFeatureImages.at(0).size(); + if(m_Forest && m_Forest->tree_count()>0 && m_Forest->feature_count()==(NumberOfSignalFeatures+3*m_NumPreviousDirections+additional_features)) + return true; + return false; +} + +template< int ShOrder, int NumberOfSignalFeatures > +void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::InitForTraining() +{ + typedef itk::AnalyticalDiffusionQballReconstructionImageFilter InterpolationFilterType; + + MITK_INFO << "Spherical signal interpolation and sampling ..."; + for (unsigned int i=0; i InterpolationFilterType; + InitDwiImageFeatures<>(m_InputDwis.at(i)); - MITK_INFO << "Spherical signal interpolation and sampling ..."; - for (unsigned int i=0; i=m_AdditionalFeatureImages.size()) { - typename InterpolationFilterType::Pointer qballfilter = InterpolationFilterType::New(); - qballfilter->SetGradientImage( mitk::DiffusionPropertyHelper::GetGradientContainer(m_RawData.at(i)), mitk::DiffusionPropertyHelper::GetItkVectorImage(m_RawData.at(i)) ); - qballfilter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(m_RawData.at(i))); - qballfilter->SetLambda(0.006); - qballfilter->SetNormalizationMethod(InterpolationFilterType::QBAR_RAW_SIGNAL); - qballfilter->Update(); - // FeatureImageType::Pointer itkFeatureImage = qballfilter->GetCoefficientImage(); - m_InterpolatedRawImages.push_back(qballfilter->GetOutput()); - - if (i>=m_MaskImages.size()) - { - ItkUcharImgType::Pointer newMask = ItkUcharImgType::New(); - newMask->SetSpacing( m_InterpolatedRawImages.at(i)->GetSpacing() ); - newMask->SetOrigin( m_InterpolatedRawImages.at(i)->GetOrigin() ); - newMask->SetDirection( m_InterpolatedRawImages.at(i)->GetDirection() ); - newMask->SetLargestPossibleRegion( m_InterpolatedRawImages.at(i)->GetLargestPossibleRegion() ); - newMask->SetBufferedRegion( m_InterpolatedRawImages.at(i)->GetLargestPossibleRegion() ); - newMask->SetRequestedRegion( m_InterpolatedRawImages.at(i)->GetLargestPossibleRegion() ); - newMask->Allocate(); - newMask->FillBuffer(1); - m_MaskImages.push_back(newMask); - } + m_AdditionalFeatureImages.push_back(std::vector< ItkFloatImgType::Pointer >()); + } - if (m_MaskImages.at(i)==nullptr) - { - m_MaskImages.at(i) = ItkUcharImgType::New(); - m_MaskImages.at(i)->SetSpacing( m_InterpolatedRawImages.at(i)->GetSpacing() ); - m_MaskImages.at(i)->SetOrigin( m_InterpolatedRawImages.at(i)->GetOrigin() ); - m_MaskImages.at(i)->SetDirection( m_InterpolatedRawImages.at(i)->GetDirection() ); - m_MaskImages.at(i)->SetLargestPossibleRegion( m_InterpolatedRawImages.at(i)->GetLargestPossibleRegion() ); - m_MaskImages.at(i)->SetBufferedRegion( m_InterpolatedRawImages.at(i)->GetLargestPossibleRegion() ); - m_MaskImages.at(i)->SetRequestedRegion( m_InterpolatedRawImages.at(i)->GetLargestPossibleRegion() ); - m_MaskImages.at(i)->Allocate(); - m_MaskImages.at(i)->FillBuffer(1); - } + if (i>=m_FiberVolumeModImages.size()) + { + ItkFloatImgType::Pointer img = ItkFloatImgType::New(); + img->SetSpacing( m_DwiFeatureImages.at(i)->GetSpacing() ); + img->SetOrigin( m_DwiFeatureImages.at(i)->GetOrigin() ); + img->SetDirection( m_DwiFeatureImages.at(i)->GetDirection() ); + img->SetLargestPossibleRegion( m_DwiFeatureImages.at(i)->GetLargestPossibleRegion() ); + img->SetBufferedRegion( m_DwiFeatureImages.at(i)->GetLargestPossibleRegion() ); + img->SetRequestedRegion( m_DwiFeatureImages.at(i)->GetLargestPossibleRegion() ); + img->Allocate(); + img->FillBuffer(1); + m_FiberVolumeModImages.push_back(img); } - MITK_INFO << "Resampling fibers and calculating number of samples ..."; - m_NumberOfSamples = 0; - for (unsigned int t=0; tSetSpacing( m_DwiFeatureImages.at(i)->GetSpacing() ); + m_FiberVolumeModImages.at(i)->SetOrigin( m_DwiFeatureImages.at(i)->GetOrigin() ); + m_FiberVolumeModImages.at(i)->SetDirection( m_DwiFeatureImages.at(i)->GetDirection() ); + m_FiberVolumeModImages.at(i)->SetLargestPossibleRegion( m_DwiFeatureImages.at(i)->GetLargestPossibleRegion() ); + m_FiberVolumeModImages.at(i)->SetBufferedRegion( m_DwiFeatureImages.at(i)->GetLargestPossibleRegion() ); + m_FiberVolumeModImages.at(i)->SetRequestedRegion( m_DwiFeatureImages.at(i)->GetLargestPossibleRegion() ); + m_FiberVolumeModImages.at(i)->Allocate(); + m_FiberVolumeModImages.at(i)->FillBuffer(1); + } + + if (i>=m_MaskImages.size()) + { + ItkUcharImgType::Pointer newMask = ItkUcharImgType::New(); + newMask->SetSpacing( m_DwiFeatureImages.at(i)->GetSpacing() ); + newMask->SetOrigin( m_DwiFeatureImages.at(i)->GetOrigin() ); + newMask->SetDirection( m_DwiFeatureImages.at(i)->GetDirection() ); + newMask->SetLargestPossibleRegion( m_DwiFeatureImages.at(i)->GetLargestPossibleRegion() ); + newMask->SetBufferedRegion( m_DwiFeatureImages.at(i)->GetLargestPossibleRegion() ); + newMask->SetRequestedRegion( m_DwiFeatureImages.at(i)->GetLargestPossibleRegion() ); + newMask->Allocate(); + newMask->FillBuffer(1); + m_MaskImages.push_back(newMask); + } + + if (m_MaskImages.at(i)==nullptr) + { + m_MaskImages.at(i) = ItkUcharImgType::New(); + m_MaskImages.at(i)->SetSpacing( m_DwiFeatureImages.at(i)->GetSpacing() ); + m_MaskImages.at(i)->SetOrigin( m_DwiFeatureImages.at(i)->GetOrigin() ); + m_MaskImages.at(i)->SetDirection( m_DwiFeatureImages.at(i)->GetDirection() ); + m_MaskImages.at(i)->SetLargestPossibleRegion( m_DwiFeatureImages.at(i)->GetLargestPossibleRegion() ); + m_MaskImages.at(i)->SetBufferedRegion( m_DwiFeatureImages.at(i)->GetLargestPossibleRegion() ); + m_MaskImages.at(i)->SetRequestedRegion( m_DwiFeatureImages.at(i)->GetLargestPossibleRegion() ); + m_MaskImages.at(i)->Allocate(); + m_MaskImages.at(i)->FillBuffer(1); + } + } + + MITK_INFO << "Resampling fibers and calculating number of samples ..."; + m_NumberOfSamples = 0; + m_SampleUsage.clear(); + for (unsigned int t=0; t::Pointer env = itk::TractDensityImageFilter< ItkUcharImgType >::New(); + env->SetFiberBundle(m_Tractograms.at(t)); + env->SetInputImage(mask); + env->SetBinaryOutput(true); + env->SetUseImageGeometry(true); + env->Update(); + wmmask = env->GetOutput(); + if (t>=m_WhiteMatterImages.size()) + m_WhiteMatterImages.push_back(wmmask); else - { - MITK_INFO << "No white-matter mask found. Using fiber envelope."; - itk::TractDensityImageFilter< ItkUcharImgType >::Pointer env = itk::TractDensityImageFilter< ItkUcharImgType >::New(); - env->SetFiberBundle(m_Tractograms.at(t)); - env->SetInputImage(mask); - env->SetBinaryOutput(true); - env->SetUseImageGeometry(true); - env->Update(); - wmmask = env->GetOutput(); - if (t>=m_WhiteMatterImages.size()) - m_WhiteMatterImages.push_back(wmmask); - else - m_WhiteMatterImages.at(t) = wmmask; - } + m_WhiteMatterImages.at(t) = wmmask; + } - // Calculate white-matter samples - if (m_WmSampleDistance<0) - { - typename InterpolatedRawImageType::Pointer image = m_InterpolatedRawImages.at(t); - float minSpacing = 1; - if(image->GetSpacing()[0]GetSpacing()[1] && image->GetSpacing()[0]GetSpacing()[2]) - minSpacing = image->GetSpacing()[0]; - else if (image->GetSpacing()[1] < image->GetSpacing()[2]) - minSpacing = image->GetSpacing()[1]; - else - minSpacing = image->GetSpacing()[2]; - m_WmSampleDistance = minSpacing*0.5; - } + // Calculate white-matter samples + if (m_WmSampleDistance<0) + { + typename DwiFeatureImageType::Pointer image = m_DwiFeatureImages.at(t); + float minSpacing = 1; + if(image->GetSpacing()[0]GetSpacing()[1] && image->GetSpacing()[0]GetSpacing()[2]) + minSpacing = image->GetSpacing()[0]; + else if (image->GetSpacing()[1] < image->GetSpacing()[2]) + minSpacing = image->GetSpacing()[1]; + else + minSpacing = image->GetSpacing()[2]; + m_WmSampleDistance = minSpacing*0.5; + } - m_Tractograms.at(t)->ResampleSpline(m_WmSampleDistance); - unsigned int wmSamples = m_Tractograms.at(t)->GetNumberOfPoints()-2*m_Tractograms.at(t)->GetNumFibers(); - m_NumberOfSamples += wmSamples; - MITK_INFO << "Samples inside of WM: " << wmSamples; + m_Tractograms.at(t)->ResampleSpline(m_WmSampleDistance); - // calculate gray-matter samples - itk::ImageRegionConstIterator it(wmmask, wmmask->GetLargestPossibleRegion()); - int OUTOFWM = 0; - while(!it.IsAtEnd()) - { - if (it.Get()==0 && mask->GetPixel(it.GetIndex())>0) - OUTOFWM++; - ++it; - } - MITK_INFO << "Non-white matter voxels: " << OUTOFWM; + unsigned int wmSamples = m_Tractograms.at(t)->GetNumberOfPoints()-2*m_Tractograms.at(t)->GetNumFibers(); + if (m_BidirectionalFiberSampling) + wmSamples *= 2; + if (m_ZeroDirWmFeatures) + wmSamples *= (m_NumPreviousDirections+1); - if (m_GmSamplesPerVoxel>0) - { - m_GmSamples.push_back(m_GmSamplesPerVoxel); - m_NumberOfSamples += m_GmSamplesPerVoxel*OUTOFWM; - } - else if (OUTOFWM>0) + MITK_INFO << "White matter samples available: " << wmSamples; + + // upper limit for samples + if (m_MaxNumWmSamples>0 && wmSamples>m_MaxNumWmSamples) + { + if ((double)m_MaxNumWmSamples/wmSamples > 0.8) { - m_GmSamples.push_back(0.5+(double)wmSamples/(double)OUTOFWM); - m_NumberOfSamples += m_GmSamples.back()*OUTOFWM; - MITK_INFO << "Non-white matter samples per voxel: " << m_GmSamples.back(); + m_SampleUsage.push_back(std::vector(wmSamples, true)); + m_NumberOfSamples += wmSamples; } else { - m_GmSamples.push_back(0); + m_SampleUsage.push_back(std::vector(wmSamples, false)); + m_NumberOfSamples += m_MaxNumWmSamples; + wmSamples = m_MaxNumWmSamples; + MITK_INFO << "Limiting white matter samples to: " << m_MaxNumWmSamples; + + itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer randgen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); + randgen->SetSeed(); + unsigned int c = 0; + while (cGetIntegerVariate(m_MaxNumWmSamples-1); + if (m_SampleUsage[t][idx]==false) + { + m_SampleUsage[t][idx]=true; + c++; + } + } } - MITK_INFO << "Samples outside of WM: " << m_GmSamples.back()*OUTOFWM; } - MITK_INFO << "Number of samples: " << m_NumberOfSamples; - } - - template< int ShOrder, int NumberOfSignalFeatures > - void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::CalculateFeaturesForTraining() - { - vnl_vector_fixed ref; ref.fill(0); ref[0]=1; - itk::OrientationDistributionFunction< double, 2*NumberOfSignalFeatures > directions; - std::vector< int > directionIndices; - for (unsigned int f=0; f<2*NumberOfSignalFeatures; f++) + else { - if (dot_product(ref, directions.GetDirection(f))>0) - directionIndices.push_back(f); + m_SampleUsage.push_back(std::vector(wmSamples, true)); + m_NumberOfSamples += wmSamples; } - int numDirectionFeatures = 3; + // calculate gray-matter samples + itk::ImageRegionConstIterator it(wmmask, wmmask->GetLargestPossibleRegion()); + int OUTOFWM = 0; + while(!it.IsAtEnd()) + { + if (it.Get()==0 && mask->GetPixel(it.GetIndex())>0) + OUTOFWM++; + ++it; + } + MITK_INFO << "Non-white matter voxels: " << OUTOFWM; - m_FeatureData.reshape( vigra::Shape2(m_NumberOfSamples, NumberOfSignalFeatures+numDirectionFeatures) ); - m_LabelData.reshape( vigra::Shape2(m_NumberOfSamples,1) ); - MITK_INFO << "Number of features: " << m_FeatureData.shape(1); + if (m_GmSamplesPerVoxel>0) + { + m_GmSamples.push_back(m_GmSamplesPerVoxel); + m_NumberOfSamples += m_GmSamplesPerVoxel*OUTOFWM; + } + else if (OUTOFWM>0) + { + int gm_per_voxel = 0.5+(double)wmSamples/(double)OUTOFWM; + if (gm_per_voxel<=0) + gm_per_voxel = 1; + m_GmSamples.push_back(gm_per_voxel); + m_NumberOfSamples += m_GmSamples.back()*OUTOFWM; + MITK_INFO << "Non-white matter samples per voxel: " << m_GmSamples.back(); + } + else + { + m_GmSamples.push_back(0); + } + MITK_INFO << "Non-white matter samples: " << m_GmSamples.back()*OUTOFWM; + } + MITK_INFO << "Number of samples: " << m_NumberOfSamples; +} - itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer m_RandGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); - m_RandGen->SetSeed(); - MITK_INFO << "Creating training data ..."; - int sampleCounter = 0; - for (unsigned int t=0; t +void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::CalculateTrainingSamples() +{ + vnl_vector_fixed ref; ref.fill(0); ref[0]=1; + + m_FeatureData.reshape( vigra::Shape2(m_NumberOfSamples, NumberOfSignalFeatures+m_NumPreviousDirections*3+m_AdditionalFeatureImages.at(0).size()) ); + m_LabelData.reshape( vigra::Shape2(m_NumberOfSamples,1) ); + m_Weights.reshape( vigra::Shape2(m_NumberOfSamples,1) ); + MITK_INFO << "Number of features: " << m_FeatureData.shape(1); + + itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer m_RandGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); + m_RandGen->SetSeed(); + MITK_INFO << "Creating training data ..."; + unsigned int sampleCounter = 0; + for (unsigned int t=0; t it(wmMask, wmMask->GetLargestPossibleRegion()); + while(!it.IsAtEnd()) { - typename InterpolatedRawImageType::Pointer image = m_InterpolatedRawImages.at(t); - ItkUcharImgType::Pointer wmMask = m_WhiteMatterImages.at(t); - ItkUcharImgType::Pointer mask; - if (t it(wmMask, wmMask->GetLargestPossibleRegion()); - while(!it.IsAtEnd()) + if (it.Get()==0 && (mask.IsNull() || (mask.IsNotNull() && mask->GetPixel(it.GetIndex())>0))) { - if (it.Get()==0 && (mask.IsNull() || (mask.IsNotNull() && mask->GetPixel(it.GetIndex())>0))) - { - typename InterpolatedRawImageType::PixelType pix = image->GetPixel(it.GetIndex()); + typename DwiFeatureImageType::PixelType pix = image->GetPixel(it.GetIndex()); - // null direction + // random directions + for (unsigned int i=0; iGetIntegerVariate(m_NumPreviousDirections); // how many directions should be zero? + for (unsigned int i=0; i probe; - probe[0] = m_RandGen->GetVariate()*2-1; - probe[1] = m_RandGen->GetVariate()*2-1; - probe[2] = m_RandGen->GetVariate()*2-1; - probe.normalize(); - if (dot_product(ref, probe)<0) - probe *= -1; - for (unsigned int f=NumberOfSignalFeatures; fGetVariate()*2-1; + probe[1] = m_RandGen->GetVariate()*2-1; + probe[2] = m_RandGen->GetVariate()*2-1; + probe.normalize(); + if (dot_product(ref, probe)<0) + probe *= -1; + } + for (unsigned int f=NumberOfSignalFeatures+3*i; f itkP; + image->TransformIndexToPhysicalPoint(it.GetIndex(), itkP); + float v = GetImageValue(itkP, img, false); + m_FeatureData(sampleCounter,NumberOfSignalFeatures+m_NumPreviousDirections*3+add_feat_c) = v; + add_feat_c++; + } + + // label and sample weight + m_LabelData(sampleCounter,0) = m_DirectionContainer.size(); + m_Weights(sampleCounter,0) = 1.0; + sampleCounter++; } - ++it; } + ++it; + } - // white matter samples - mitk::FiberBundle::Pointer fib = m_Tractograms.at(t); - vtkSmartPointer< vtkPolyData > polyData = fib->GetFiberPolyData(); - for (int i=0; iGetNumFibers(); i++) - { - vtkCell* cell = polyData->GetCell(i); - int numPoints = cell->GetNumberOfPoints(); - vtkPoints* points = cell->GetPoints(); - - vnl_vector_fixed dirOld; dirOld.fill(0.0); + unsigned int num_gm_samples = sampleCounter; + MITK_INFO << "WM samples..."; + // white matter samples + mitk::FiberBundle::Pointer fib = m_Tractograms.at(t); + vtkSmartPointer< vtkPolyData > polyData = fib->GetFiberPolyData(); + vnl_vector_fixed zero_dir; zero_dir.fill(0.0); + for (int i=0; iGetNumFibers(); i++) + { + vtkCell* cell = polyData->GetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + double fiber_weight = fib->GetFiberWeight(i); - for (int j=0; jGetPoint(j); - itk::Point itkP1; - itkP1[0] = p1[0]; itkP1[1] = p1[1]; itkP1[2] = p1[2]; + for (int j=1; j dir; dir.fill(0.0); + itk::Point itkP1, itkP2; - itk::Point itkP2; - double* p2 = points->GetPoint(j+1); - itkP2[0] = p2[0]; itkP2[1] = p2[1]; itkP2[2] = p2[2]; - dir[0]=itkP2[0]-itkP1[0]; - dir[1]=itkP2[1]-itkP1[1]; - dir[2]=itkP2[2]-itkP1[2]; + int num_nonzero_dirs = m_NumPreviousDirections; + if (!reverse) + num_nonzero_dirs = std::min(n, j); + else + num_nonzero_dirs = std::min(n, numPoints-j-1); - if (dir.magnitude()<0.0001) - { - MITK_INFO << "streamline error!"; - continue; - } - dir.normalize(); - if (dir[0]!=dir[0] || dir[1]!=dir[1] || dir[2]!=dir[2]) - { - MITK_INFO << "ERROR: NaN direction!"; - continue; - } + vnl_vector_fixed dir; + // zero directions + for (unsigned int k=0; kGetPoint(j-n_idx); + itkP1[0] = p[0]; itkP1[1] = p[1]; itkP1[2] = p[2]; + p = points->GetPoint(j-n_idx+1); + itkP2[0] = p[0]; itkP2[1] = p[1]; itkP2[2] = p[2]; + } + else + { + p = points->GetPoint(j+n_idx); + itkP1[0] = p[0]; itkP1[1] = p[1]; itkP1[2] = p[2]; + p = points->GetPoint(j+n_idx-1); + itkP2[0] = p[0]; itkP2[1] = p[1]; itkP2[2] = p[2]; + } - // get voxel values - typename InterpolatedRawImageType::PixelType pix = GetImageValues(itkP1, image); - for (unsigned int f=0; f0.0001) - { + int c = 0; + for (unsigned int f=NumberOfSignalFeatures+3*(k+m_NumPreviousDirections-num_nonzero_dirs); fGetPoint(j); + itkP1[0] = p[0]; itkP1[1] = p[1]; itkP1[2] = p[2]; + if (reverse) + { + p = points->GetPoint(j-1); + itkP2[0] = p[0]; itkP2[1] = p[1]; itkP2[2] = p[2]; + } + else + { + p = points->GetPoint(j+1); + itkP2[0] = p[0]; itkP2[1] = p[1]; itkP2[2] = p[2]; + } + dir[0]=itkP2[0]-itkP1[0]; + dir[1]=itkP2[1]-itkP1[1]; + dir[2]=itkP2[2]-itkP1[2]; + + if (dir.magnitude()<0.0001) + mitkThrow() << "streamline error!"; + dir.normalize(); + if (dir[0]!=dir[0] || dir[1]!=dir[1] || dir[2]!=dir[2]) + mitkThrow() << "ERROR: NaN direction!"; + if (dot_product(ref, dir)<0) + dir *= -1; + + // image features + float volume_mod = GetImageValue(itkP1, fiber_folume, false); + + // diffusion signal features + typename DwiFeatureImageType::PixelType pix = GetDwiFeaturesAtPosition(itkP1, image); for (unsigned int f=0; f(itkP1, img, false); + add_feat_c++; + m_FeatureData(sampleCounter,NumberOfSignalFeatures+2+add_feat_c) = v; + } + + // set label values + double angle = 0; + double m = dir.magnitude(); + if (m>0.0001) { - double a = fabs(dot_product(dir, directions.GetDirection(directionIndices[f]))); - if (a>angle) + int l = 0; + for (auto d : m_DirectionContainer) { - m_LabelData(sampleCounter,0) = f; - angle = a; + double a = fabs(dot_product(dir, d)); + if (a>angle) + { + m_LabelData(sampleCounter,0) = l; + m_Weights(sampleCounter,0) = fiber_weight*volume_mod; + angle = a; + } + l++; } } - } - dirOld = dir; - sampleCounter++; + sampleCounter++; + } + if (!m_BidirectionalFiberSampling) // don't sample fibers backward + break; } } } } + m_Tractograms.clear(); +} - template< int ShOrder, int NumberOfSignalFeatures > - void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::TrainForest() - { - MITK_INFO << "Maximum tree depths: " << m_MaxTreeDepth; - MITK_INFO << "Sample fraction per tree: " << m_SampleFraction; - MITK_INFO << "Number of trees: " << m_NumTrees; - - std::vector< std::shared_ptr< vigra::RandomForest > > trees; - int count = 0; -#pragma omp parallel for - for (int i = 0; i < m_NumTrees; ++i) - { - std::shared_ptr< vigra::RandomForest > lrf = std::make_shared< vigra::RandomForest >(); - lrf->set_options().use_stratification(vigra::RF_NONE); // How the data should be made equal - lrf->set_options().sample_with_replacement(true); // if sampled with replacement or not - lrf->set_options().samples_per_tree(m_SampleFraction); // Fraction of samples that are used to train a tree - lrf->set_options().tree_count(1); // Number of trees that are calculated; - lrf->set_options().min_split_node_size(5); // Minimum number of datapoints that must be in a node - lrf->ext_param_.max_tree_depth = m_MaxTreeDepth; - - lrf->learn(m_FeatureData, m_LabelData); -#pragma omp critical - { - count++; - MITK_INFO << "Tree " << count << " finished training."; - trees.push_back(lrf); - } - } - - for (int i = 1; i < m_NumTrees; ++i) - trees.at(0)->trees_.push_back(trees.at(i)->trees_[0]); - - m_Forest = trees.at(0); - m_Forest->options_.tree_count_ = m_NumTrees; - MITK_INFO << "Training finsihed"; - } - - template< int ShOrder, int NumberOfSignalFeatures > - void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::SaveForest(std::string forestFile) +template< int ShOrder, int NumberOfSignalFeatures > +void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::SaveForest(std::string forestFile) +{ + MITK_INFO << "Saving forest to " << forestFile; + if (IsForestValid()) { - MITK_INFO << "Saving forest to " << forestFile; - if (IsForestValid()) - vigra::rf_export_HDF5( *m_Forest, forestFile, "" ); - else - MITK_INFO << "Forest invalid! Could not be saved."; + vigra::rf_export_HDF5( *m_Forest, forestFile, "" ); MITK_INFO << "Forest saved successfully."; } + else + MITK_INFO << "Forest invalid! Could not be saved."; +} - template< int ShOrder, int NumberOfSignalFeatures > - void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::LoadForest(std::string forestFile) - { - MITK_INFO << "Loading forest from " << forestFile; - m_Forest = std::make_shared< vigra::RandomForest >(); - vigra::rf_import_HDF5( *m_Forest, forestFile); - } +template< int ShOrder, int NumberOfSignalFeatures > +void TrackingForestHandler< ShOrder, NumberOfSignalFeatures >::LoadForest(std::string forestFile) +{ + MITK_INFO << "Loading forest from " << forestFile; + m_Forest = std::make_shared< vigra::RandomForest >(); + vigra::rf_import_HDF5( *m_Forest, forestFile); +} } -#endif \ No newline at end of file +#endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/mitkTrackingForestHandler.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/mitkTrackingForestHandler.h index ebcc190e78..03657b94ea 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/mitkTrackingForestHandler.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/MLTracking/mitkTrackingForestHandler.h @@ -1,132 +1,156 @@ /*=================================================================== 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 _TrackingForestHandler #define _TrackingForestHandler #include "mitkBaseData.h" #include #include #include #include #include #include #undef DIFFERENCE #define VIGRA_STATIC_LIB #include #include #include +//#include +#include +#include +#include + #define _USE_MATH_DEFINES #include namespace mitk { /** * \brief Manages random forests for fiber tractography. The preparation of the features from the inputa data and the training process are handled here. The data preprocessing and actual prediction for the tracking process is also performed here. The tracking itself is performed in MLBSTrackingFilter. */ -template< int ShOrder=6, int NumberOfSignalFeatures=100 > +template< int ShOrder, int NumberOfSignalFeatures > class TrackingForestHandler { public: TrackingForestHandler(); ~TrackingForestHandler(); + typedef itk::Image ItkShortImgType; + typedef itk::Image ItkFloatImgType; typedef itk::Image ItkUcharImgType; - typedef itk::Image< itk::Vector< float, NumberOfSignalFeatures*2 > , 3 > InterpolatedRawImageType; - typedef itk::Image< Vector< float, NumberOfSignalFeatures > , 3 > FeatureImageType; + typedef itk::Image< itk::Vector< float, NumberOfSignalFeatures > , 3 > DwiFeatureImageType; + + typedef mitk::ThresholdSplit >,int,vigra::ClassificationTag> DefaultSplitType; - void SetRawData( std::vector< Image::Pointer > images ){ m_RawData = images; } - void AddRawData( Image::Pointer img ){ m_RawData.push_back(img); } + void SetDwis( std::vector< Image::Pointer > images ){ m_InputDwis = images; } + void AddDwi( Image::Pointer img ){ m_InputDwis.push_back(img); } void SetTractograms( std::vector< FiberBundle::Pointer > tractograms ) { m_Tractograms.clear(); for (auto fib : tractograms) - { - m_Tractograms.push_back(fib->GetDeepCopy()); - } + m_Tractograms.push_back(fib); } void SetMaskImages( std::vector< ItkUcharImgType::Pointer > images ){ m_MaskImages = images; } void SetWhiteMatterImages( std::vector< ItkUcharImgType::Pointer > images ){ m_WhiteMatterImages = images; } + void SetFiberVolumeModImages( std::vector< ItkFloatImgType::Pointer > images ){ m_FiberVolumeModImages = images; } + void SetAdditionalFeatureImages( std::vector< std::vector< ItkFloatImgType::Pointer > > images ){ m_AdditionalFeatureImages = images; } void StartTraining(); void SaveForest(std::string forestFile); void LoadForest(std::string forestFile); - // training parameters - + void SetMaxNumWmSamples(int num){ m_MaxNumWmSamples=num; } + void SetNumPreviousDirections( int num ){ m_NumPreviousDirections=num; } void SetNumTrees(int num){ m_NumTrees = num; } void SetMaxTreeDepth(int depth){ m_MaxTreeDepth = depth; } void SetStepSize(double step){ m_WmSampleDistance = step; } void SetGrayMatterSamplesPerVoxel(int samples){ m_GmSamplesPerVoxel = samples; } void SetSampleFraction(double fraction){ m_SampleFraction = fraction; } + void SetBidirectionalFiberSampling(bool val) { m_BidirectionalFiberSampling = val; } + void SetZeroDirWmFeatures(bool val) { m_ZeroDirWmFeatures = val; } std::shared_ptr< vigra::RandomForest > GetForest(){ return m_Forest; } - void InitForTracking(); ///< calls InputDataValidForTracking() and creates feature images from the war input DWI - vnl_vector_fixed Classify(itk::Point& pos, int& candidates, vnl_vector_fixed& olddir, double angularThreshold, double& w, ItkUcharImgType::Pointer mask=nullptr); ///< predicts next progression direction at the given position + void InitForTracking(); ///< calls InputDataValidForTracking() and creates feature images + vnl_vector_fixed Classify(itk::Point& pos, int& candidates, std::deque< vnl_vector_fixed >& olddirs, double angularThreshold, double& w, ItkUcharImgType::Pointer mask=nullptr); ///< predicts next progression direction at the given position bool IsForestValid(); ///< true is forest is not null, has more than 0 trees and the correct number of features (NumberOfSignalFeatures + 3) protected: - // tracking void InputDataValidForTracking(); ///< check if raw data is set and tracking forest is valid - typename FeatureImageType::PixelType GetFeatureValues(itk::Point itkP); ///< get trilinearly interpolated feature values at given world position - // training + template< class TPixelType > + TPixelType GetImageValue(itk::Point itkP, itk::Image* image, bool interpolate); + + template + typename std::enable_if::type InitDwiImageFeatures(mitk::Image::Pointer mitk_dwi); + + template + typename std::enable_if= 100, T>::type InitDwiImageFeatures(mitk::Image::Pointer mitk_dwi); + void InputDataValidForTraining(); ///< Check if everything is tehere for training (raw datasets, fiber tracts) - void PreprocessInputDataForTraining(); ///< Generate masks if necessary, resample fibers, spherically interpolate raw DWIs - void CalculateFeaturesForTraining(); ///< Calculate GM and WM features using the interpolated raw data, the WM masks and the fibers - void TrainForest(); ///< start training process - typename InterpolatedRawImageType::PixelType GetImageValues(itk::Point itkP, typename InterpolatedRawImageType::Pointer image); ///< get trilinearly interpolated raw image values at given world position + void InitForTraining(); ///< Generate masks if necessary, resample fibers, spherically interpolate raw DWIs + void CalculateTrainingSamples(); ///< Calculate GM and WM features using the interpolated raw data, the WM masks and the fibers + typename DwiFeatureImageType::PixelType GetDwiFeaturesAtPosition(itk::Point itkP, typename DwiFeatureImageType::Pointer image); ///< get trilinearly interpolated raw image values at given world position + + std::vector< Image::Pointer > m_InputDwis; ///< original input DWI data + std::shared_ptr< vigra::RandomForest > m_Forest; ///< random forest classifier + std::chrono::time_point m_StartTime; + std::chrono::time_point m_EndTime; - std::vector< Image::Pointer > m_RawData; ///< original input DWI data - std::shared_ptr< vigra::RandomForest > m_Forest; ///< random forest classifier - std::chrono::time_point m_StartTime; - std::chrono::time_point m_EndTime; - // only for training + std::vector< typename DwiFeatureImageType::Pointer > m_DwiFeatureImages; + std::vector< std::vector< ItkFloatImgType::Pointer > > m_AdditionalFeatureImages; + + std::vector< ItkFloatImgType::Pointer > m_FiberVolumeModImages; ///< used to correct the fiber density std::vector< FiberBundle::Pointer > m_Tractograms; ///< training tractograms std::vector< ItkUcharImgType::Pointer > m_MaskImages; ///< binary mask images to constrain training to a certain area (e.g. brain mask) std::vector< ItkUcharImgType::Pointer > m_WhiteMatterImages; ///< defines white matter voxels. if not set, theses mask images are automatically generated from the input tractograms - std::vector< typename InterpolatedRawImageType::Pointer > m_InterpolatedRawImages; ///< spherically interpolated and resampled raw datasets + double m_WmSampleDistance; ///< deterines the number of white matter samples (distance of sampling points on each fiber). int m_NumTrees; ///< number of trees in random forest int m_MaxTreeDepth; ///< limits the tree depth double m_SampleFraction; ///< fraction of samples used to train each tree unsigned int m_NumberOfSamples; ///< stores overall number of samples used for training std::vector< unsigned int > m_GmSamples; ///< number of gray matter samples int m_GmSamplesPerVoxel; ///< number of gray matter samplees per voxel. if -1, then the number is automatically chosen to gain an overall number of GM samples close to the number of WM samples. vigra::MultiArray<2, double> m_FeatureData; ///< vigra container for training features + unsigned int m_NumPreviousDirections; ///< How many "old" directions should be used as classification features? // only for tracking - typename FeatureImageType::Pointer m_FeatureImage; ///< feature image used for tracking - vigra::MultiArray<2, double> m_LabelData; ///< vigra container for training labels - std::vector< int > m_DirectionIndices; ///< maps each of the NumberOfSignalFeatures possible output directions to one of the 2*NumberOfSignalFeatures ODF directions. - itk::OrientationDistributionFunction< double, NumberOfSignalFeatures*2 > m_DirContainer; ///< direction container + vigra::MultiArray<2, double> m_LabelData; ///< vigra container for training labels + vigra::MultiArray<2, double> m_Weights; ///< vigra container for training sample weights + std::vector< vnl_vector_fixed > m_DirectionContainer; + + bool m_BidirectionalFiberSampling; + bool m_ZeroDirWmFeatures; + int m_MaxNumWmSamples; + std::vector< std::vector< bool > > m_SampleUsage; }; } #include "mitkTrackingForestHandler.cpp" #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberCurvatureFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberCurvatureFilter.cpp index a2ebc7e7f1..dfdaf409cb 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberCurvatureFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberCurvatureFilter.cpp @@ -1,149 +1,163 @@ /*=================================================================== 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 "itkFiberCurvatureFilter.h" #define _USE_MATH_DEFINES #include #include #include #include namespace itk{ FiberCurvatureFilter::FiberCurvatureFilter() : m_AngularDeviation(30) , m_Distance(5.0) , m_RemoveFibers(false) { } FiberCurvatureFilter::~FiberCurvatureFilter() { } void FiberCurvatureFilter::GenerateData() { vtkSmartPointer inputPoly = m_InputFiberBundle->GetFiberPolyData(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Applying curvature threshold"; boost::progress_display disp(inputPoly->GetNumberOfCells()); +#pragma omp parallel for for (int i=0; iGetNumberOfCells(); i++) { - ++disp; - vtkCell* cell = inputPoly->GetCell(i); - int numPoints = cell->GetNumberOfPoints(); - vtkPoints* points = cell->GetPoints(); + std::vector< vnl_vector_fixed< double, 3 > > vertices; + +#pragma omp critical + { + ++disp; + vtkCell* cell = inputPoly->GetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + + for (int j=0; jGetPoint(j, p); + vnl_vector_fixed< double, 3 > p_vec; + p_vec[0]=p[0]; p_vec[1]=p[1]; p_vec[2]=p[2]; + vertices.push_back(p_vec); + } + } // calculate curvatures + int numPoints = vertices.size(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; j > vectors; - vnl_vector_fixed< float, 3 > meanV; meanV.fill(0.0); + std::vector< vnl_vector_fixed< double, 3 > > vectors; + vnl_vector_fixed< double, 3 > meanV; meanV.fill(0.0); while(dist1) { - double p1[3]; - points->GetPoint(c-1, p1); - double p2[3]; - points->GetPoint(c, p2); - - vnl_vector_fixed< float, 3 > v; - v[0] = p2[0]-p1[0]; - v[1] = p2[1]-p1[1]; - v[2] = p2[2]-p1[2]; + vnl_vector_fixed< double, 3 > p1 = vertices.at(c-1); + vnl_vector_fixed< double, 3 > p2 = vertices.at(c); + + vnl_vector_fixed< double, 3 > v = p2-p1; dist += v.magnitude(); v.normalize(); vectors.push_back(v); if (c==j) meanV += v; c--; } c = j; dist = 0; while(distGetPoint(c, p1); - double p2[3]; - points->GetPoint(c+1, p2); - - vnl_vector_fixed< float, 3 > v; - v[0] = p2[0]-p1[0]; - v[1] = p2[1]-p1[1]; - v[2] = p2[2]-p1[2]; + vnl_vector_fixed< double, 3 > p1 = vertices.at(c); + vnl_vector_fixed< double, 3 > p2 = vertices.at(c+1); + + vnl_vector_fixed< double, 3 > v = p2-p1; dist += v.magnitude(); v.normalize(); vectors.push_back(v); if (c==j) meanV += v; c++; } meanV.normalize(); double dev = 0; for (auto vec : vectors) { double angle = dot_product(meanV, vec); if (angle>1.0) angle = 1.0; if (angle<-1.0) angle = -1.0; dev += acos(angle)*180/M_PI; } if (vectors.size()>0) dev /= vectors.size(); if (devGetPoint(j, p); - vtkIdType id = vtkNewPoints->InsertNextPoint(p); +#pragma omp critical + { + vtkIdType id = vtkNewPoints->InsertNextPoint(vertices.at(j).data_block()); container->GetPointIds()->InsertNextId(id); + } } else { if (m_RemoveFibers) { container = vtkSmartPointer::New(); break; } if (container->GetNumberOfPoints()>0) + { +#pragma omp critical vtkNewCells->InsertNextCell(container); + } container = vtkSmartPointer::New(); } } - if (container->GetNumberOfPoints()>0) - vtkNewCells->InsertNextCell(container); + +#pragma omp critical + { + if (container->GetNumberOfPoints()>0) + vtkNewCells->InsertNextCell(container); + } } vtkSmartPointer outputPoly = vtkSmartPointer::New(); outputPoly->SetPoints(vtkNewPoints); outputPoly->SetLines(vtkNewCells); m_OutputFiberBundle = FiberBundle::New(outputPoly); } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp index dc860353fc..565642074f 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp @@ -1,251 +1,253 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Coindex[1]right (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 "itkTractDensityImageFilter.h" // VTK #include #include #include #include // misc #include #include namespace itk{ template< class OutputImageType > TractDensityImageFilter< OutputImageType >::TractDensityImageFilter() : m_InvertImage(false) , m_FiberBundle(NULL) , m_UpsamplingFactor(1) , m_InputImage(NULL) , m_BinaryOutput(false) , m_UseImageGeometry(false) , m_OutputAbsoluteValues(false) , m_UseTrilinearInterpolation(false) , m_DoFiberResampling(true) + , m_WorkOnFiberCopy(true) { } template< class OutputImageType > TractDensityImageFilter< OutputImageType >::~TractDensityImageFilter() { } template< class OutputImageType > itk::Point TractDensityImageFilter< OutputImageType >::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } template< class OutputImageType > void TractDensityImageFilter< OutputImageType >::GenerateData() { // generate upsampled image mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry(); typename OutputImageType::Pointer outImage = this->GetOutput(); // calculate new image parameters itk::Vector newSpacing; mitk::Point3D newOrigin; itk::Matrix newDirection; ImageRegion<3> upsampledRegion; if (m_UseImageGeometry && !m_InputImage.IsNull()) { MITK_INFO << "TractDensityImageFilter: using image geometry"; newSpacing = m_InputImage->GetSpacing()/m_UpsamplingFactor; upsampledRegion = m_InputImage->GetLargestPossibleRegion(); newOrigin = m_InputImage->GetOrigin(); typename OutputImageType::RegionType::SizeType size = upsampledRegion.GetSize(); size[0] *= m_UpsamplingFactor; size[1] *= m_UpsamplingFactor; size[2] *= m_UpsamplingFactor; upsampledRegion.SetSize(size); newDirection = m_InputImage->GetDirection(); } else { MITK_INFO << "TractDensityImageFilter: using fiber bundle geometry"; newSpacing = geometry->GetSpacing()/m_UpsamplingFactor; newOrigin = geometry->GetOrigin(); mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); // we retrieve the origin from a vtk-polydata (corner-based) and hance have to translate it to an image geometry // i.e. center-based newOrigin[0] += bounds.GetElement(0) + 0.5 * newSpacing[0]; newOrigin[1] += bounds.GetElement(2) + 0.5 * newSpacing[1]; newOrigin[2] += bounds.GetElement(4) + 0.5 * newSpacing[2]; for (int i=0; i<3; i++) for (int j=0; j<3; j++) newDirection[j][i] = geometry->GetMatrixColumn(i)[j]; upsampledRegion.SetSize(0, ceil( geometry->GetExtent(0)*m_UpsamplingFactor ) ); upsampledRegion.SetSize(1, ceil( geometry->GetExtent(1)*m_UpsamplingFactor ) ); upsampledRegion.SetSize(2, ceil( geometry->GetExtent(2)*m_UpsamplingFactor ) ); } typename OutputImageType::RegionType::SizeType upsampledSize = upsampledRegion.GetSize(); // apply new image parameters outImage->SetSpacing( newSpacing ); outImage->SetOrigin( newOrigin ); outImage->SetDirection( newDirection ); outImage->SetLargestPossibleRegion( upsampledRegion ); outImage->SetBufferedRegion( upsampledRegion ); outImage->SetRequestedRegion( upsampledRegion ); outImage->Allocate(); outImage->FillBuffer(0.0); int w = upsampledSize[0]; int h = upsampledSize[1]; int d = upsampledSize[2]; // set/initialize output OutPixelType* outImageBufferPointer = (OutPixelType*)outImage->GetBufferPointer(); // resample fiber bundle float minSpacing = 1; if(newSpacing[0]GetDeepCopy(); - m_FiberBundle->ResampleSpline(minSpacing/10); + m_FiberBundle->ResampleSpline(minSpacing/10); } MITK_INFO << "TractDensityImageFilter: starting image generation"; vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); vtkSmartPointer vLines = fiberPolyData->GetLines(); vLines->InitTraversal(); int numFibers = m_FiberBundle->GetNumFibers(); boost::progress_display disp(numFibers); for( int i=0; iGetNextCell ( numPoints, points ); float weight = m_FiberBundle->GetFiberWeight(i); // fill output image for( int j=0; j vertex = GetItkPoint(fiberPolyData->GetPoint(points[j])); itk::Index<3> index; itk::ContinuousIndex contIndex; outImage->TransformPhysicalPointToIndex(vertex, index); outImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex); if (!m_UseTrilinearInterpolation && outImage->GetLargestPossibleRegion().IsInside(index)) { if (m_BinaryOutput) outImage->SetPixel(index, 1); else outImage->SetPixel(index, outImage->GetPixel(index)+0.01*weight); continue; } float frac_x = contIndex[0] - index[0]; float frac_y = contIndex[1] - index[1]; float frac_z = contIndex[2] - index[2]; if (frac_x<0) { index[0] -= 1; frac_x += 1; } if (frac_y<0) { index[1] -= 1; frac_y += 1; } if (frac_z<0) { index[2] -= 1; frac_z += 1; } frac_x = 1-frac_x; frac_y = 1-frac_y; frac_z = 1-frac_z; // int coordinates inside image? if (index[0] < 0 || index[0] >= w-1) continue; if (index[1] < 0 || index[1] >= h-1) continue; if (index[2] < 0 || index[2] >= d-1) continue; if (m_BinaryOutput) { outImageBufferPointer[( index[0] + w*(index[1] + h*index[2] ))] = 1; outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2] ))] = 1; outImageBufferPointer[( index[0] + w*(index[1] + h*index[2]+h))] = 1; outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2]+h))] = 1; outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2] ))] = 1; outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2]+h))] = 1; outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2] ))] = 1; outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))] = 1; } else { outImageBufferPointer[( index[0] + w*(index[1] + h*index[2] ))] += ( frac_x)*( frac_y)*( frac_z); outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2] ))] += ( frac_x)*(1-frac_y)*( frac_z); outImageBufferPointer[( index[0] + w*(index[1] + h*index[2]+h))] += ( frac_x)*( frac_y)*(1-frac_z); outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2]+h))] += ( frac_x)*(1-frac_y)*(1-frac_z); outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2] ))] += (1-frac_x)*( frac_y)*( frac_z); outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2]+h))] += (1-frac_x)*( frac_y)*(1-frac_z); outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2] ))] += (1-frac_x)*(1-frac_y)*( frac_z); outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))] += (1-frac_x)*(1-frac_y)*(1-frac_z); } } } if (!m_OutputAbsoluteValues && !m_BinaryOutput) { MITK_INFO << "TractDensityImageFilter: max-normalizing output image"; OutPixelType max = 0; for (int i=0; i0) for (int i=0; i #include #include #include #include namespace itk{ /** * \brief Generates tract density images from input fiberbundles (Calamante 2010). */ template< class OutputImageType > class TractDensityImageFilter : public ImageSource< OutputImageType > { public: typedef TractDensityImageFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef typename OutputImageType::PixelType OutPixelType; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( TractDensityImageFilter, ImageSource ) itkSetMacro( UpsamplingFactor, float) ///< use higher resolution for ouput image itkGetMacro( UpsamplingFactor, float) ///< use higher resolution for ouput image itkSetMacro( InvertImage, bool) ///< voxelvalue = 1-voxelvalue itkGetMacro( InvertImage, bool) ///< voxelvalue = 1-voxelvalue itkSetMacro( BinaryOutput, bool) ///< generate binary fiber envelope itkGetMacro( BinaryOutput, bool) ///< generate binary fiber envelope itkSetMacro( OutputAbsoluteValues, bool) ///< output absolute values of the number of fibers per voxel itkGetMacro( OutputAbsoluteValues, bool) ///< output absolute values of the number of fibers per voxel itkSetMacro( UseImageGeometry, bool) ///< use input image geometry to initialize output image itkGetMacro( UseImageGeometry, bool) ///< use input image geometry to initialize output image itkSetMacro( FiberBundle, mitk::FiberBundle::Pointer) ///< input fiber bundle itkSetMacro( InputImage, typename OutputImageType::Pointer) ///< use input image geometry to initialize output image itkSetMacro( UseTrilinearInterpolation, bool ) itkSetMacro( DoFiberResampling, bool ) + itkSetMacro( WorkOnFiberCopy, bool ) void GenerateData(); protected: itk::Point GetItkPoint(double point[3]); TractDensityImageFilter(); virtual ~TractDensityImageFilter(); typename OutputImageType::Pointer m_InputImage; ///< use input image geometry to initialize output image - mitk::FiberBundle::Pointer m_FiberBundle; ///< input fiber bundle + mitk::FiberBundle::Pointer m_FiberBundle; ///< input fiber bundle float m_UpsamplingFactor; ///< use higher resolution for ouput image bool m_InvertImage; ///< voxelvalue = 1-voxelvalue bool m_BinaryOutput; ///< generate binary fiber envelope bool m_UseImageGeometry; ///< use input image geometry to initialize output image bool m_OutputAbsoluteValues; ///< do not normalize image values to 0-1 bool m_UseTrilinearInterpolation; bool m_DoFiberResampling; + bool m_WorkOnFiberCopy; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkTractDensityImageFilter.cpp" #endif #endif // __itkTractDensityImageFilter_h__ diff --git a/Modules/DiffusionImaging/FiberTracking/CMakeLists.txt b/Modules/DiffusionImaging/FiberTracking/CMakeLists.txt index 3dda9a1b59..1bbcc5c444 100644 --- a/Modules/DiffusionImaging/FiberTracking/CMakeLists.txt +++ b/Modules/DiffusionImaging/FiberTracking/CMakeLists.txt @@ -1,54 +1,54 @@ -set(_module_deps MitkDiffusionCore MitkGraphAlgorithms) +set(_module_deps MitkDiffusionCore MitkGraphAlgorithms MitkCLVigraRandomForest) mitk_check_module_dependencies( MODULES ${_module_deps} MISSING_DEPENDENCIES_VAR _missing_deps ) if(NOT _missing_deps) set(lut_url http://mitk.org/download/data/FibertrackingLUT.tar.gz) set(lut_tarball ${CMAKE_CURRENT_BINARY_DIR}/FibertrackingLUT.tar.gz) message("Downloading FiberTracking LUT ${lut_url}...") file(DOWNLOAD ${lut_url} ${lut_tarball} EXPECTED_MD5 38ecb6d4a826c9ebb0f4965eb9aeee44 TIMEOUT 60 STATUS status SHOW_PROGRESS ) list(GET status 0 status_code) list(GET status 1 status_msg) if(NOT status_code EQUAL 0) message(SEND_ERROR "${status_msg} (error code ${status_code})") else() message("done.") endif() file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Resources) message("Unpacking FiberTracking LUT tarball...") execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ../FibertrackingLUT.tar.gz WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Resources RESULT_VARIABLE result ERROR_VARIABLE err_msg) if(result) message(SEND_ERROR "Unpacking FibertrackingLUT.tar.gz failed: ${err_msg}") else() message("done.") endif() endif() MITK_CREATE_MODULE( SUBPROJECTS MITK-DTI INCLUDE_DIRS Fiberfox Fiberfox/SignalModels Fiberfox/Sequences Algorithms Algorithms/MLTracking Algorithms/GibbsTracking Algorithms/StochasticTracking IODataStructures IODataStructures/FiberBundle IODataStructures/PlanarFigureComposite Rendering ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${_module_deps} PACKAGE_DEPENDS PUBLIC ITK|ITKFFT ITK|ITKDiffusionTensorImage Vigra HDF5 #WARNINGS_AS_ERRORS ) if(MODULE_IS_ENABLED) add_subdirectory(Testing) endif() diff --git a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp index 1c5a62fcf8..4816e1b8af 100755 --- a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp @@ -1,1677 +1,1679 @@ /*=================================================================== 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 "itkTractsToDWIImageFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace itk { template< class PixelType > TractsToDWIImageFilter< PixelType >::TractsToDWIImageFilter() : m_FiberBundle(NULL) , m_StatusText("") , m_UseConstantRandSeed(false) , m_RandGen(itk::Statistics::MersenneTwisterRandomVariateGenerator::New()) { m_RandGen->SetSeed(); } template< class PixelType > TractsToDWIImageFilter< PixelType >::~TractsToDWIImageFilter() { } template< class PixelType > TractsToDWIImageFilter< PixelType >::DoubleDwiType::Pointer TractsToDWIImageFilter< PixelType >:: SimulateKspaceAcquisition( std::vector< DoubleDwiType::Pointer >& images ) { int numFiberCompartments = m_Parameters.m_FiberModelList.size(); // create slice object ImageRegion<2> sliceRegion; sliceRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]); sliceRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]); Vector< double, 2 > sliceSpacing; sliceSpacing[0] = m_WorkingSpacing[0]; sliceSpacing[1] = m_WorkingSpacing[1]; DoubleDwiType::PixelType nullPix; nullPix.SetSize(images.at(0)->GetVectorLength()); nullPix.Fill(0.0); auto magnitudeDwiImage = DoubleDwiType::New(); magnitudeDwiImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); magnitudeDwiImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); magnitudeDwiImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); magnitudeDwiImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetVectorLength( images.at(0)->GetVectorLength() ); magnitudeDwiImage->Allocate(); magnitudeDwiImage->FillBuffer(nullPix); m_PhaseImage = DoubleDwiType::New(); m_PhaseImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_PhaseImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); m_PhaseImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_PhaseImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetVectorLength( images.at(0)->GetVectorLength() ); m_PhaseImage->Allocate(); m_PhaseImage->FillBuffer(nullPix); m_KspaceImage = DoubleDwiType::New(); m_KspaceImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_KspaceImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); m_KspaceImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_KspaceImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetVectorLength( m_Parameters.m_SignalGen.m_NumberOfCoils ); m_KspaceImage->Allocate(); m_KspaceImage->FillBuffer(nullPix); std::vector< unsigned int > spikeVolume; for (unsigned int i=0; iGetIntegerVariate()%(images.at(0)->GetVectorLength())); std::sort (spikeVolume.begin(), spikeVolume.end()); std::reverse (spikeVolume.begin(), spikeVolume.end()); // calculate coil positions double a = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(0)*m_Parameters.m_SignalGen.m_ImageSpacing[0]; double b = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1)*m_Parameters.m_SignalGen.m_ImageSpacing[1]; double c = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(2)*m_Parameters.m_SignalGen.m_ImageSpacing[2]; double diagonal = sqrt(a*a+b*b)/1000; // image diagonal in m m_CoilPointset = mitk::PointSet::New(); std::vector< itk::Vector > coilPositions; itk::Vector pos; pos.Fill(0.0); pos[1] = -diagonal/2; itk::Vector center; center[0] = a/2-m_Parameters.m_SignalGen.m_ImageSpacing[0]/2; center[1] = b/2-m_Parameters.m_SignalGen.m_ImageSpacing[2]/2; center[2] = c/2-m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; for (int c=0; cInsertPoint(c, pos*1000 + m_Parameters.m_SignalGen.m_ImageOrigin.GetVectorFromOrigin() + center ); double rz = 360.0/m_Parameters.m_SignalGen.m_NumberOfCoils * M_PI/180; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; pos.SetVnlVector(rotZ*pos.GetVnlVector()); } PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); unsigned long lastTick = 0; boost::progress_display disp(images.at(0)->GetVectorLength()*images.at(0)->GetLargestPossibleRegion().GetSize(2)); for (unsigned int g=0; gGetVectorLength(); g++) { std::vector< unsigned int > spikeSlice; while (!spikeVolume.empty() && spikeVolume.back()==g) { spikeSlice.push_back(m_RandGen->GetIntegerVariate()%images.at(0)->GetLargestPossibleRegion().GetSize(2)); spikeVolume.pop_back(); } std::sort (spikeSlice.begin(), spikeSlice.end()); std::reverse (spikeSlice.begin(), spikeSlice.end()); for (unsigned int z=0; zGetLargestPossibleRegion().GetSize(2); z++) { std::vector< SliceType::Pointer > compartmentSlices; std::vector< double > t2Vector; std::vector< double > t1Vector; for (unsigned int i=0; i* signalModel; if (iSetLargestPossibleRegion( sliceRegion ); slice->SetBufferedRegion( sliceRegion ); slice->SetRequestedRegion( sliceRegion ); slice->SetSpacing(sliceSpacing); slice->Allocate(); slice->FillBuffer(0.0); // extract slice from channel g for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; slice->SetPixel(index2D, images.at(i)->GetPixel(index3D)[g]); } compartmentSlices.push_back(slice); t2Vector.push_back(signalModel->GetT2()); t1Vector.push_back(signalModel->GetT1()); } int numSpikes = 0; while (!spikeSlice.empty() && spikeSlice.back()==z) { numSpikes++; spikeSlice.pop_back(); } int spikeCoil = m_RandGen->GetIntegerVariate()%m_Parameters.m_SignalGen.m_NumberOfCoils; if (this->GetAbortGenerateData()) return NULL; #pragma omp parallel for for (int c=0; c::New(); idft->SetCompartmentImages(compartmentSlices); idft->SetT2(t2Vector); idft->SetT1(t1Vector); idft->SetUseConstantRandSeed(m_UseConstantRandSeed); idft->SetParameters(&m_Parameters); idft->SetZ((double)z-(double)( images.at(0)->GetLargestPossibleRegion().GetSize(2) -images.at(0)->GetLargestPossibleRegion().GetSize(2)%2 ) / 2.0); idft->SetZidx(z); idft->SetCoilPosition(coilPositions.at(c)); idft->SetFiberBundle(m_FiberBundleWorkingCopy); idft->SetTranslation(m_Translations.at(g)); idft->SetRotation(m_Rotations.at(g)); idft->SetDiffusionGradientDirection(m_Parameters.m_SignalGen.GetGradientDirection(g)); if (c==spikeCoil) idft->SetSpikesPerSlice(numSpikes); idft->Update(); #pragma omp critical if (c==spikeCoil && numSpikes>0) { m_SpikeLog += "Volume " + boost::lexical_cast(g) + " Coil " + boost::lexical_cast(c) + "\n"; m_SpikeLog += idft->GetSpikeLog(); } ComplexSliceType::Pointer fSlice; fSlice = idft->GetOutput(); // fourier transform slice ComplexSliceType::Pointer newSlice; auto dft = itk::DftImageFilter< SliceType::PixelType >::New(); dft->SetInput(fSlice); dft->SetParameters(m_Parameters); dft->Update(); newSlice = dft->GetOutput(); // put slice back into channel g for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; ComplexSliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; ComplexSliceType::PixelType cPix = newSlice->GetPixel(index2D); double magn = sqrt(cPix.real()*cPix.real()+cPix.imag()*cPix.imag()); double phase = 0; if (cPix.real()!=0) phase = atan( cPix.imag()/cPix.real() ); DoubleDwiType::PixelType dwiPix = magnitudeDwiImage->GetPixel(index3D); DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D); if (m_Parameters.m_SignalGen.m_NumberOfCoils>1) { dwiPix[g] += magn*magn; phasePix[g] += phase*phase; } else { dwiPix[g] = magn; phasePix[g] = phase; } #pragma omp critical { magnitudeDwiImage->SetPixel(index3D, dwiPix); m_PhaseImage->SetPixel(index3D, phasePix); // k-space image if (g==0) { DoubleDwiType::PixelType kspacePix = m_KspaceImage->GetPixel(index3D); kspacePix[c] = idft->GetKSpaceImage()->GetPixel(index2D); m_KspaceImage->SetPixel(index3D, kspacePix); } } } } if (m_Parameters.m_SignalGen.m_NumberOfCoils>1) { #ifdef WIN32 #pragma omp parallel for #else #pragma omp parallel for collapse(2) #endif for (int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; DoubleDwiType::PixelType magPix = magnitudeDwiImage->GetPixel(index3D); magPix[g] = sqrt(magPix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils); DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D); phasePix[g] = sqrt(phasePix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils); #pragma omp critical { magnitudeDwiImage->SetPixel(index3D, magPix); m_PhaseImage->SetPixel(index3D, phasePix); } } } ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned long tick = 0; tick<(newTick-lastTick); tick++) PrintToLog("*", false, false, false); lastTick = newTick; } } PrintToLog("\n", false); return magnitudeDwiImage; } template< class PixelType > TractsToDWIImageFilter< PixelType >::ItkDoubleImgType::Pointer TractsToDWIImageFilter< PixelType >:: NormalizeInsideMask(ItkDoubleImgType::Pointer image) { double max = itk::NumericTraits< double >::min(); double min = itk::NumericTraits< double >::max(); itk::ImageRegionIterator< ItkDoubleImgType > it(image, image->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { if (m_Parameters.m_SignalGen.m_MaskImage.IsNotNull() && m_Parameters.m_SignalGen.m_MaskImage->GetPixel(it.GetIndex())<=0) { it.Set(0.0); ++it; continue; } // if (it.Get()>900) // it.Set(900); if (it.Get()>max) max = it.Get(); if (it.Get()::New(); scaler->SetInput(image); scaler->SetShift(-min); scaler->SetScale(1.0/(max-min)); scaler->Update(); return scaler->GetOutput(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::CheckVolumeFractionImages() { m_UseRelativeNonFiberVolumeFractions = false; // check for fiber volume fraction maps int fibVolImages = 0; for (int i=0; iGetVolumeFractionImage().IsNotNull()) { PrintToLog("Using volume fraction map for fiber compartment " + boost::lexical_cast(i+1)); fibVolImages++; } } // check for non-fiber volume fraction maps int nonfibVolImages = 0; for (int i=0; iGetVolumeFractionImage().IsNotNull()) { PrintToLog("Using volume fraction map for non-fiber compartment " + boost::lexical_cast(i+1)); nonfibVolImages++; } } // not all fiber compartments are using volume fraction maps // --> non-fiber volume fractions are assumed to be relative to the // non-fiber volume and not absolute voxel-volume fractions. // this means if two non-fiber compartments are used but only one of them // has an associated volume fraction map, the repesctive other volume fraction map // can be determined as inverse (1-val) of the present volume fraction map- if ( fibVolImages::New(); inverter->SetMaximum(1.0); if ( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNull() && m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNotNull() ) { // m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage( // NormalizeInsideMask( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() ) ); inverter->SetInput( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() ); inverter->Update(); m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage(inverter->GetOutput()); } else if ( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNull() && m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNotNull() ) { // m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage( // NormalizeInsideMask( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() ) ); inverter->SetInput( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() ); inverter->Update(); m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage(inverter->GetOutput()); } else { itkExceptionMacro("Something went wrong in automatically calculating the missing non-fiber volume fraction image!" " Did you use two non fiber compartments but only one volume fraction image?" " Then it should work and this error is really strange."); } m_UseRelativeNonFiberVolumeFractions = true; nonfibVolImages++; } // Up to two fiber compartments are allowed without volume fraction maps since the volume fractions can then be determined automatically if (m_Parameters.m_FiberModelList.size()>2 && fibVolImages!=m_Parameters.m_FiberModelList.size()) itkExceptionMacro("More than two fiber compartment selected but no corresponding volume fraction maps set!"); // One non-fiber compartment is allowed without volume fraction map since the volume fraction can then be determined automatically if (m_Parameters.m_NonFiberModelList.size()>1 && nonfibVolImages!=m_Parameters.m_NonFiberModelList.size()) itkExceptionMacro("More than one non-fiber compartment selected but no volume fraction maps set!"); if (fibVolImages0) { PrintToLog("Not all fiber compartments are using an associated volume fraction image.\n" "Assuming non-fiber volume fraction images to contain values relative to the" " remaining non-fiber volume, not absolute values."); m_UseRelativeNonFiberVolumeFractions = true; // itk::ImageFileWriter::Pointer wr = itk::ImageFileWriter::New(); // wr->SetInput(m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage()); // wr->SetFileName("/local/volumefraction.nrrd"); // wr->Update(); } // initialize the images that store the output volume fraction of each compartment m_VolumeFractions.clear(); for (int i=0; iSetSpacing( m_WorkingSpacing ); doubleImg->SetOrigin( m_WorkingOrigin ); doubleImg->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); doubleImg->SetLargestPossibleRegion( m_WorkingImageRegion ); doubleImg->SetBufferedRegion( m_WorkingImageRegion ); doubleImg->SetRequestedRegion( m_WorkingImageRegion ); doubleImg->Allocate(); doubleImg->FillBuffer(0); m_VolumeFractions.push_back(doubleImg); } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::InitializeData() { m_Rotations.clear(); m_Translations.clear(); m_MotionLog = ""; m_SpikeLog = ""; // initialize output dwi image m_Parameters.m_SignalGen.m_CroppedRegion = m_Parameters.m_SignalGen.m_ImageRegion; m_Parameters.m_SignalGen.m_CroppedRegion.SetSize( 1, m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(1) *m_Parameters.m_SignalGen.m_CroppingFactor); itk::Point shiftedOrigin = m_Parameters.m_SignalGen.m_ImageOrigin; shiftedOrigin[1] += (m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1) -m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(1))*m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; m_OutputImage = OutputImageType::New(); m_OutputImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_OutputImage->SetOrigin( shiftedOrigin ); m_OutputImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_OutputImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); m_OutputImage->Allocate(); typename OutputImageType::PixelType temp; temp.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); temp.Fill(0.0); m_OutputImage->FillBuffer(temp); // Apply in-plane upsampling for Gibbs ringing artifact double upsampling = 1; if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) upsampling = 2; m_WorkingSpacing = m_Parameters.m_SignalGen.m_ImageSpacing; m_WorkingSpacing[0] /= upsampling; m_WorkingSpacing[1] /= upsampling; m_WorkingImageRegion = m_Parameters.m_SignalGen.m_ImageRegion; m_WorkingImageRegion.SetSize(0, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[0]*upsampling); m_WorkingImageRegion.SetSize(1, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[1]*upsampling); m_WorkingOrigin = m_Parameters.m_SignalGen.m_ImageOrigin; m_WorkingOrigin[0] -= m_Parameters.m_SignalGen.m_ImageSpacing[0]/2; m_WorkingOrigin[0] += m_WorkingSpacing[0]/2; m_WorkingOrigin[1] -= m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; m_WorkingOrigin[1] += m_WorkingSpacing[1]/2; m_WorkingOrigin[2] -= m_Parameters.m_SignalGen.m_ImageSpacing[2]/2; m_WorkingOrigin[2] += m_WorkingSpacing[2]/2; m_VoxelVolume = m_WorkingSpacing[0]*m_WorkingSpacing[1]*m_WorkingSpacing[2]; // generate double images to store the individual compartment signals m_CompartmentImages.clear(); int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); for (int i=0; iSetSpacing( m_WorkingSpacing ); doubleDwi->SetOrigin( m_WorkingOrigin ); doubleDwi->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); doubleDwi->SetLargestPossibleRegion( m_WorkingImageRegion ); doubleDwi->SetBufferedRegion( m_WorkingImageRegion ); doubleDwi->SetRequestedRegion( m_WorkingImageRegion ); doubleDwi->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); doubleDwi->Allocate(); DoubleDwiType::PixelType pix; pix.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); pix.Fill(0.0); doubleDwi->FillBuffer(pix); m_CompartmentImages.push_back(doubleDwi); } if (m_FiberBundle.IsNull() && m_InputImage.IsNotNull()) { m_CompartmentImages.clear(); m_Parameters.m_SignalGen.m_DoAddMotion = false; m_Parameters.m_SignalGen.m_DoSimulateRelaxation = false; PrintToLog("Simulating acquisition for input diffusion-weighted image.", false); auto caster = itk::CastImageFilter< OutputImageType, DoubleDwiType >::New(); caster->SetInput(m_InputImage); caster->Update(); if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) { PrintToLog("Upsampling input diffusion-weighted image for Gibbs ringing simulation.", false); auto resampler = itk::ResampleDwiImageFilter< double >::New(); resampler->SetInput(caster->GetOutput()); itk::Vector< double, 3 > samplingFactor; samplingFactor[0] = upsampling; samplingFactor[1] = upsampling; samplingFactor[2] = 1; resampler->SetSamplingFactor(samplingFactor); resampler->SetInterpolation(itk::ResampleDwiImageFilter< double >::Interpolate_WindowedSinc); resampler->Update(); m_CompartmentImages.push_back(resampler->GetOutput()); } else m_CompartmentImages.push_back(caster->GetOutput()); for (unsigned int g=0; g::New(); rescaler->SetInput(0,m_Parameters.m_SignalGen.m_MaskImage); rescaler->SetOutputMaximum(100); rescaler->SetOutputMinimum(0); rescaler->Update(); // resample mask image auto resampler = itk::ResampleImageFilter::New(); resampler->SetInput(rescaler->GetOutput()); resampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_MaskImage); resampler->SetSize(m_WorkingImageRegion.GetSize()); resampler->SetOutputSpacing(m_WorkingSpacing); resampler->SetOutputOrigin(m_WorkingOrigin); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); m_Parameters.m_SignalGen.m_MaskImage = resampler->GetOutput(); } // resample frequency map if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) { auto resampler = itk::ResampleImageFilter::New(); resampler->SetInput(m_Parameters.m_SignalGen.m_FrequencyMap); resampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_FrequencyMap); resampler->SetSize(m_WorkingImageRegion.GetSize()); resampler->SetOutputSpacing(m_WorkingSpacing); resampler->SetOutputOrigin(m_WorkingOrigin); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); m_Parameters.m_SignalGen.m_FrequencyMap = resampler->GetOutput(); } } m_MaskImageSet = true; if (m_Parameters.m_SignalGen.m_MaskImage.IsNull()) { // no input tissue mask is set -> create default PrintToLog("No tissue mask set", false); m_Parameters.m_SignalGen.m_MaskImage = ItkUcharImgType::New(); m_Parameters.m_SignalGen.m_MaskImage->SetSpacing( m_WorkingSpacing ); m_Parameters.m_SignalGen.m_MaskImage->SetOrigin( m_WorkingOrigin ); m_Parameters.m_SignalGen.m_MaskImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_Parameters.m_SignalGen.m_MaskImage->SetLargestPossibleRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->SetBufferedRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->SetRequestedRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->Allocate(); m_Parameters.m_SignalGen.m_MaskImage->FillBuffer(100); m_MaskImageSet = false; } else { if (m_Parameters.m_SignalGen.m_MaskImage->GetLargestPossibleRegion()!=m_WorkingImageRegion) { itkExceptionMacro("Mask image and specified DWI geometry are not matching!"); } PrintToLog("Using tissue mask", false); } if (m_Parameters.m_SignalGen.m_DoAddMotion) { if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { PrintToLog("Random motion artifacts:", false); PrintToLog("Maximum rotation: +/-" + boost::lexical_cast(m_Parameters.m_SignalGen.m_Rotation) + "°", false); PrintToLog("Maximum translation: +/-" + boost::lexical_cast(m_Parameters.m_SignalGen.m_Translation) + "mm", false); } else { PrintToLog("Linear motion artifacts:", false); PrintToLog("Maximum rotation: " + boost::lexical_cast(m_Parameters.m_SignalGen.m_Rotation) + "°", false); PrintToLog("Maximum translation: " + boost::lexical_cast(m_Parameters.m_SignalGen.m_Translation) + "mm", false); } } if ( m_Parameters.m_SignalGen.m_MotionVolumes.empty() ) { // no motion in first volume m_Parameters.m_SignalGen.m_MotionVolumes.push_back(false); // motion in all other volumes while ( m_Parameters.m_SignalGen.m_MotionVolumes.size() < m_Parameters.m_SignalGen.GetNumVolumes() ) { m_Parameters.m_SignalGen.m_MotionVolumes.push_back(true); } } // we need to know for every volume if there is motion. if this information is missing, then set corresponding fal to false while ( m_Parameters.m_SignalGen.m_MotionVolumes.size()::New(); duplicator->SetInputImage(m_Parameters.m_SignalGen.m_MaskImage); duplicator->Update(); m_TransformedMaskImage = duplicator->GetOutput(); // second upsampling needed for motion artifacts ImageRegion<3> upsampledImageRegion = m_WorkingImageRegion; DoubleVectorType upsampledSpacing = m_WorkingSpacing; upsampledSpacing[0] /= 4; upsampledSpacing[1] /= 4; upsampledSpacing[2] /= 4; upsampledImageRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]*4); upsampledImageRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]*4); upsampledImageRegion.SetSize(2, m_WorkingImageRegion.GetSize()[2]*4); itk::Point upsampledOrigin = m_WorkingOrigin; upsampledOrigin[0] -= m_WorkingSpacing[0]/2; upsampledOrigin[0] += upsampledSpacing[0]/2; upsampledOrigin[1] -= m_WorkingSpacing[1]/2; upsampledOrigin[1] += upsampledSpacing[1]/2; upsampledOrigin[2] -= m_WorkingSpacing[2]/2; upsampledOrigin[2] += upsampledSpacing[2]/2; m_UpsampledMaskImage = ItkUcharImgType::New(); auto upsampler = itk::ResampleImageFilter::New(); upsampler->SetInput(m_Parameters.m_SignalGen.m_MaskImage); upsampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_MaskImage); upsampler->SetSize(upsampledImageRegion.GetSize()); upsampler->SetOutputSpacing(upsampledSpacing); upsampler->SetOutputOrigin(upsampledOrigin); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); upsampler->SetInterpolator(nn_interpolator); upsampler->Update(); m_UpsampledMaskImage = upsampler->GetOutput(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::InitializeFiberData() { // resample fiber bundle for sufficient voxel coverage PrintToLog("Resampling fibers ..."); m_SegmentVolume = 0.0001; float minSpacing = 1; if( m_WorkingSpacing[0]GetDeepCopy(); double volumeAccuracy = 10; m_FiberBundleWorkingCopy->ResampleSpline(minSpacing/volumeAccuracy); m_mmRadius = m_Parameters.m_SignalGen.m_AxonRadius/1000; if (m_mmRadius>0) { m_SegmentVolume = M_PI*m_mmRadius*m_mmRadius*minSpacing/volumeAccuracy; } // a second fiber bundle is needed to store the transformed version of the m_FiberBundleWorkingCopy m_FiberBundleTransformed = m_FiberBundleWorkingCopy; } template< class PixelType > bool TractsToDWIImageFilter< PixelType >::PrepareLogFile() { assert( ! m_Logfile.is_open() ); std::string filePath; std::string fileName; // Get directory name: if (m_Parameters.m_Misc.m_OutputPath.size() > 0) { filePath = m_Parameters.m_Misc.m_OutputPath; if( *(--(filePath.cend())) != '/') { filePath.push_back('/'); } } else { filePath = mitk::IOUtil::GetTempPath() + '/'; } // check if directory exists, else use /tmp/: if( itksys::SystemTools::FileIsDirectory( filePath ) ) { while( *(--(filePath.cend())) == '/') { filePath.pop_back(); } filePath = filePath + '/'; } else { filePath = mitk::IOUtil::GetTempPath() + '/'; } // Get file name: if( ! m_Parameters.m_Misc.m_ResultNode->GetName().empty() ) { fileName = m_Parameters.m_Misc.m_ResultNode->GetName(); } else { fileName = ""; } if( ! m_Parameters.m_Misc.m_OutputPrefix.empty() ) { fileName = m_Parameters.m_Misc.m_OutputPrefix + fileName; } else { fileName = "fiberfox"; } // check if file already exists and DO NOT overwrite existing files: std::string NameTest = fileName; int c = 0; while( itksys::SystemTools::FileExists( filePath + '/' + fileName + ".log" ) && c <= std::numeric_limits::max() ) { fileName = NameTest + "_" + boost::lexical_cast(c); ++c; } try { m_Logfile.open( ( filePath + '/' + fileName + ".log" ).c_str() ); } catch (const std::ios_base::failure &fail) { MITK_ERROR << "itkTractsToDWIImageFilter.cpp: Exception " << fail.what() << " while trying to open file" << filePath << '/' << fileName << ".log"; return false; } if ( m_Logfile.is_open() ) { PrintToLog( "Logfile: " + filePath + '/' + fileName + ".log", false ); return true; } else { m_StatusText += "Logfile could not be opened!\n"; MITK_ERROR << "itkTractsToDWIImageFilter.cpp: Logfile could not be opened!"; return false; } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::GenerateData() { // prepare logfile if ( ! PrepareLogFile() ) { this->SetAbortGenerateData( true ); return; } m_TimeProbe.Start(); // check input data if (m_FiberBundle.IsNull() && m_InputImage.IsNull()) itkExceptionMacro("Input fiber bundle and input diffusion-weighted image is NULL!"); if (m_Parameters.m_FiberModelList.empty() && m_InputImage.IsNull()) itkExceptionMacro("No diffusion model for fiber compartments defined and input diffusion-weighted" " image is NULL! At least one fiber compartment is necessary to simulate diffusion."); if (m_Parameters.m_NonFiberModelList.empty() && m_InputImage.IsNull()) itkExceptionMacro("No diffusion model for non-fiber compartments defined and input diffusion-weighted" " image is NULL! At least one non-fiber compartment is necessary to simulate diffusion."); int baselineIndex = m_Parameters.m_SignalGen.GetFirstBaselineIndex(); if (baselineIndex<0) { itkExceptionMacro("No baseline index found!"); } if (!m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition) // No upsampling of input image needed if no k-space simulation is performed { m_Parameters.m_SignalGen.m_DoAddGibbsRinging = false; } if (m_UseConstantRandSeed) // always generate the same random numbers? { m_RandGen->SetSeed(0); } else { m_RandGen->SetSeed(); } InitializeData(); if ( m_FiberBundle.IsNotNull() ) // if no fiber bundle is found, we directly proceed to the k-space acquisition simulation { CheckVolumeFractionImages(); InitializeFiberData(); int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); double maxVolume = 0; unsigned long lastTick = 0; int signalModelSeed = m_RandGen->GetIntegerVariate(); PrintToLog("\n", false, false); PrintToLog("Generating " + boost::lexical_cast(numFiberCompartments+numNonFiberCompartments) + "-compartment diffusion-weighted signal."); int numFibers = m_FiberBundleWorkingCopy->GetNumFibers(); boost::progress_display disp(numFibers*m_Parameters.m_SignalGen.GetNumVolumes()); PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); for (unsigned int g=0; gSetSeed(signalModelSeed); for (int i=0; iSetSeed(signalModelSeed); // storing voxel-wise intra-axonal volume in mm³ auto intraAxonalVolumeImage = ItkDoubleImgType::New(); intraAxonalVolumeImage->SetSpacing( m_WorkingSpacing ); intraAxonalVolumeImage->SetOrigin( m_WorkingOrigin ); intraAxonalVolumeImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); intraAxonalVolumeImage->SetLargestPossibleRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetBufferedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetRequestedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->Allocate(); intraAxonalVolumeImage->FillBuffer(0); maxVolume = 0; vtkPolyData* fiberPolyData = m_FiberBundleTransformed->GetFiberPolyData(); // generate fiber signal (if there are any fiber models present) if (!m_Parameters.m_FiberModelList.empty()) for( int i=0; iGetFiberWeight(i); vtkCell* cell = fiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints<2) continue; for( int j=0; jGetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } double* temp = points->GetPoint(j); itk::Point vertex = GetItkPoint(temp); itk::Vector v = GetItkVector(temp); itk::Vector dir(3); if (jGetPoint(j+1))-v; } else { dir = v-GetItkVector(points->GetPoint(j-1)); } if ( dir.GetSquaredNorm()<0.0001 || dir[0]!=dir[0] || dir[1]!=dir[1] || dir[2]!=dir[2] ) { continue; } itk::Index<3> idx; itk::ContinuousIndex contIndex; m_TransformedMaskImage->TransformPhysicalPointToIndex(vertex, idx); m_TransformedMaskImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex); if (!m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(idx) || m_TransformedMaskImage->GetPixel(idx)<=0) { continue; } // generate signal for each fiber compartment for (int k=0; kSetFiberDirection(dir); DoubleDwiType::PixelType pix = m_CompartmentImages.at(k)->GetPixel(idx); pix[g] += fiberWeight*m_SegmentVolume*m_Parameters.m_FiberModelList[k]->SimulateMeasurement(g); m_CompartmentImages.at(k)->SetPixel(idx, pix); } // update fiber volume image double vol = intraAxonalVolumeImage->GetPixel(idx) + m_SegmentVolume*fiberWeight; intraAxonalVolumeImage->SetPixel(idx, vol); // we assume that the first volume is always unweighted! if (vol>maxVolume) { maxVolume = vol; } } // progress report ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned int tick = 0; tick<(newTick-lastTick); tick++) { PrintToLog("*", false, false, false); } lastTick = newTick; } // generate non-fiber signal ImageRegionIterator it3(m_TransformedMaskImage, m_TransformedMaskImage->GetLargestPossibleRegion()); double fact = 1; // density correction factor in mm³ if (m_Parameters.m_SignalGen.m_AxonRadius<0.0001 || maxVolume>m_VoxelVolume) // the fullest voxel is always completely full fact = m_VoxelVolume/maxVolume; while(!it3.IsAtEnd()) { if (it3.Get()>0) { DoubleDwiType::IndexType index = it3.GetIndex(); itk::Point point; m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, point); if ( m_Parameters.m_SignalGen.m_DoAddMotion && g>=0 && m_Parameters.m_SignalGen.m_MotionVolumes[g] ) { if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { point = m_FiberBundleWorkingCopy->TransformPoint( point.GetVnlVector(), -m_Rotation[0], -m_Rotation[1], -m_Rotation[2], -m_Translation[0], -m_Translation[1], -m_Translation[2] ); } else { point = m_FiberBundleWorkingCopy->TransformPoint( point.GetVnlVector(), -m_Rotation[0]*m_MotionCounter, -m_Rotation[1]*m_MotionCounter, -m_Rotation[2]*m_MotionCounter, -m_Translation[0]*m_MotionCounter, -m_Translation[1]*m_MotionCounter, -m_Translation[2]*m_MotionCounter ); } } double iAxVolume = intraAxonalVolumeImage->GetPixel(index); // if volume fraction image is set use it, otherwise use scaling factor to obtain one full fiber voxel double fact2 = fact; if ( m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()!=nullptr && iAxVolume>0.0001 ) { double val = InterpolateValue(point, m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()); if (val>=0) { fact2 = m_VoxelVolume*val/iAxVolume; } } // adjust intra-axonal image value for (int i=0; iGetPixel(index); pix[g] *= fact2; m_CompartmentImages.at(i)->SetPixel(index, pix); } // simulate other compartments SimulateExtraAxonalSignal(index, iAxVolume*fact2, g); } ++it3; } } PrintToLog("\n", false); if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } } DoubleDwiType::Pointer doubleOutImage; double signalScale = m_Parameters.m_SignalGen.m_SignalScale; if ( m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition ) // do k-space stuff { PrintToLog("\n", false, false); PrintToLog("Simulating k-space acquisition using " +boost::lexical_cast(m_Parameters.m_SignalGen.m_NumberOfCoils) +" coil(s)"); switch (m_Parameters.m_SignalGen.m_AcquisitionType) { case SignalGenerationParameters::SingleShotEpi: { PrintToLog("Acquisition type: single shot EPI", false); break; } case SignalGenerationParameters::SpinEcho: { PrintToLog("Acquisition type: classic spin echo with cartesian k-space trajectory", false); break; } default: { PrintToLog("Acquisition type: single shot EPI", false); break; } } if (m_Parameters.m_SignalGen.m_NoiseVariance>0) PrintToLog("Simulating complex Gaussian noise", false); if (m_Parameters.m_SignalGen.m_DoSimulateRelaxation) PrintToLog("Simulating signal relaxation", false); if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) PrintToLog("Simulating distortions", false); if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) PrintToLog("Simulating ringing artifacts", false); if (m_Parameters.m_SignalGen.m_EddyStrength>0) PrintToLog("Simulating eddy currents", false); if (m_Parameters.m_SignalGen.m_Spikes>0) PrintToLog("Simulating spikes", false); if (m_Parameters.m_SignalGen.m_CroppingFactor<1.0) PrintToLog("Simulating aliasing artifacts", false); if (m_Parameters.m_SignalGen.m_KspaceLineOffset>0) PrintToLog("Simulating ghosts", false); doubleOutImage = SimulateKspaceAcquisition(m_CompartmentImages); signalScale = 1; // already scaled in SimulateKspaceAcquisition() } else // don't do k-space stuff, just sum compartments { PrintToLog("Summing compartments"); doubleOutImage = m_CompartmentImages.at(0); for (unsigned int i=1; i::New(); adder->SetInput1(doubleOutImage); adder->SetInput2(m_CompartmentImages.at(i)); adder->Update(); doubleOutImage = adder->GetOutput(); } } if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } PrintToLog("Finalizing image"); if (signalScale>1) PrintToLog(" Scaling signal", false); if (m_Parameters.m_NoiseModel) PrintToLog(" Adding noise", false); unsigned int window = 0; unsigned int min = itk::NumericTraits::max(); ImageRegionIterator it4 (m_OutputImage, m_OutputImage->GetLargestPossibleRegion()); DoubleDwiType::PixelType signal; signal.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); boost::progress_display disp2(m_OutputImage->GetLargestPossibleRegion().GetNumberOfPixels()); PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); int lastTick = 0; while(!it4.IsAtEnd()) { if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } ++disp2; unsigned long newTick = 50*disp2.count()/disp2.expected_count(); for (unsigned long tick = 0; tick<(newTick-lastTick); tick++) PrintToLog("*", false, false, false); lastTick = newTick; typename OutputImageType::IndexType index = it4.GetIndex(); signal = doubleOutImage->GetPixel(index)*signalScale; if (m_Parameters.m_NoiseModel) m_Parameters.m_NoiseModel->AddNoise(signal); for (unsigned int i=0; i0) signal[i] = floor(signal[i]+0.5); else signal[i] = ceil(signal[i]-0.5); if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]>window) window = signal[i]; if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]SetNthOutput(0, m_OutputImage); PrintToLog("\n", false); PrintToLog("Finished simulation"); m_TimeProbe.Stop(); if (m_Parameters.m_SignalGen.m_DoAddMotion) { PrintToLog("\nHead motion log:", false); PrintToLog(m_MotionLog, false, false); } if (m_Parameters.m_SignalGen.m_Spikes>0) { PrintToLog("\nSpike log:", false); PrintToLog(m_SpikeLog, false, false); } if (m_Logfile.is_open()) m_Logfile.close(); } // Heilliger Spaghetti-Code, Batman! todo/mdh template< class PixelType > void TractsToDWIImageFilter< PixelType >::PrintToLog(string m, bool addTime, bool linebreak, bool stdOut) { // timestamp if (addTime) { m_Logfile << this->GetTime() << " > "; m_StatusText += this->GetTime() + " > "; if (stdOut) std::cout << this->GetTime() << " > "; } // message if (m_Logfile.is_open()) m_Logfile << m; m_StatusText += m; if (stdOut) std::cout << m; // new line if (linebreak) { if (m_Logfile.is_open()) m_Logfile << "\n"; m_StatusText += "\n"; if (stdOut) std::cout << "\n"; } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::SimulateMotion(int g) { // is motion artifact enabled? // is the current volume g affected by motion? if ( m_Parameters.m_SignalGen.m_DoAddMotion && m_Parameters.m_SignalGen.m_MotionVolumes[g] && gGetDeepCopy(); m_Rotation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[0]*2) -m_Parameters.m_SignalGen.m_Rotation[0]; m_Rotation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[1]*2) -m_Parameters.m_SignalGen.m_Rotation[1]; m_Rotation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[2]*2) -m_Parameters.m_SignalGen.m_Rotation[2]; m_Translation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[0]*2) -m_Parameters.m_SignalGen.m_Translation[0]; m_Translation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[1]*2) -m_Parameters.m_SignalGen.m_Translation[1]; m_Translation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[2]*2) -m_Parameters.m_SignalGen.m_Translation[2]; } else { m_Rotation = m_Parameters.m_SignalGen.m_Rotation / m_NumMotionVolumes; m_Translation = m_Parameters.m_SignalGen.m_Translation / m_NumMotionVolumes; m_MotionCounter++; } // move mask image if (m_MaskImageSet) { ImageRegionIterator maskIt(m_UpsampledMaskImage, m_UpsampledMaskImage->GetLargestPossibleRegion()); m_TransformedMaskImage->FillBuffer(0); while(!maskIt.IsAtEnd()) { if (maskIt.Get()<=0) { ++maskIt; continue; } DoubleDwiType::IndexType index = maskIt.GetIndex(); itk::Point point; m_UpsampledMaskImage->TransformIndexToPhysicalPoint(index, point); if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(), m_Rotation[0],m_Rotation[1],m_Rotation[2], m_Translation[0],m_Translation[1],m_Translation[2]); } else { point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(), m_Rotation[0]*m_MotionCounter,m_Rotation[1]*m_MotionCounter,m_Rotation[2]*m_MotionCounter, m_Translation[0]*m_MotionCounter,m_Translation[1]*m_MotionCounter,m_Translation[2]*m_MotionCounter); } m_TransformedMaskImage->TransformPhysicalPointToIndex(point, index); if (m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(index)) { m_TransformedMaskImage->SetPixel(index,100); } ++maskIt; } } if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { m_Rotations.push_back(m_Rotation); m_Translations.push_back(m_Translation); m_MotionLog += boost::lexical_cast(g) + " rotation: " + boost::lexical_cast(m_Rotation[0]) + "," + boost::lexical_cast(m_Rotation[1]) + "," + boost::lexical_cast(m_Rotation[2]) + ";"; m_MotionLog += " translation: " + boost::lexical_cast(m_Translation[0]) + "," + boost::lexical_cast(m_Translation[1]) + "," + boost::lexical_cast(m_Translation[2]) + "\n"; } else { m_Rotations.push_back(m_Rotation*m_MotionCounter); m_Translations.push_back(m_Translation*m_MotionCounter); m_MotionLog += boost::lexical_cast(g) + " rotation: " + boost::lexical_cast(m_Rotation[0]*m_MotionCounter) + "," + boost::lexical_cast(m_Rotation[1]*m_MotionCounter) + "," + boost::lexical_cast(m_Rotation[2]*m_MotionCounter) + ";"; m_MotionLog += " translation: " + boost::lexical_cast(m_Translation[0]*m_MotionCounter) + "," + boost::lexical_cast(m_Translation[1]*m_MotionCounter) + "," + boost::lexical_cast(m_Translation[2]*m_MotionCounter) + "\n"; } m_FiberBundleTransformed->TransformFibers(m_Rotation[0],m_Rotation[1],m_Rotation[2],m_Translation[0],m_Translation[1],m_Translation[2]); } else { m_Rotation.Fill(0.0); m_Translation.Fill(0.0); m_Rotations.push_back(m_Rotation); m_Translations.push_back(m_Translation); m_MotionLog += boost::lexical_cast(g) + " rotation: " + boost::lexical_cast(m_Rotation[0]) + "," + boost::lexical_cast(m_Rotation[1]) + "," + boost::lexical_cast(m_Rotation[2]) + ";"; m_MotionLog += " translation: " + boost::lexical_cast(m_Translation[0]) + "," + boost::lexical_cast(m_Translation[1]) + "," + boost::lexical_cast(m_Translation[2]) + "\n"; } } template< class PixelType > void TractsToDWIImageFilter< PixelType >:: SimulateExtraAxonalSignal(ItkUcharImgType::IndexType index, double intraAxonalVolume, int g) { int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); if (intraAxonalVolume>0.0001 && m_Parameters.m_SignalGen.m_DoDisablePartialVolume) // only fiber in voxel { DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); if (g>=0) pix[g] *= m_VoxelVolume/intraAxonalVolume; else pix *= m_VoxelVolume/intraAxonalVolume; m_CompartmentImages.at(0)->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(0)->SetPixel(index, 1); for (int i=1; iGetPixel(index); if (g>=0) pix[g] = 0.0; else pix.Fill(0.0); m_CompartmentImages.at(i)->SetPixel(index, pix); } } else { if (g==0) { m_VolumeFractions.at(0)->SetPixel(index, intraAxonalVolume/m_VoxelVolume); } // get non-transformed point (remove headmotion tranformation) // this point can then be transformed to each of the original images, regardless of their geometry itk::Point point; m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, point); if ( m_Parameters.m_SignalGen.m_DoAddMotion && g>=0 && m_Parameters.m_SignalGen.m_MotionVolumes[g] ) { if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(), -m_Rotation[0],-m_Rotation[1],-m_Rotation[2], -m_Translation[0],-m_Translation[1],-m_Translation[2]); } else { point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(), -m_Rotation[0]*m_MotionCounter,-m_Rotation[1]*m_MotionCounter,-m_Rotation[2]*m_MotionCounter, -m_Translation[0]*m_MotionCounter,-m_Translation[1]*m_MotionCounter,-m_Translation[2]*m_MotionCounter); } } if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) { int maxVolumeIndex = 0; double maxWeight = 0; for (int i=0; i1) { double val = InterpolateValue(point, m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()); if (val<0) continue; else weight = val; } if (weight>maxWeight) { maxWeight = weight; maxVolumeIndex = i; } } DoubleDwiType::Pointer doubleDwi = m_CompartmentImages.at(maxVolumeIndex+numFiberCompartments); DoubleDwiType::PixelType pix = doubleDwi->GetPixel(index); if (g>=0) pix[g] += m_Parameters.m_NonFiberModelList[maxVolumeIndex]->SimulateMeasurement(g)*m_VoxelVolume; else pix += m_Parameters.m_NonFiberModelList[maxVolumeIndex]->SimulateMeasurement()*m_VoxelVolume; doubleDwi->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(maxVolumeIndex+numFiberCompartments)->SetPixel(index, 1); } else { double extraAxonalVolume = m_VoxelVolume-intraAxonalVolume; // non-fiber volume if (extraAxonalVolume<0) { - MITK_ERROR << "Corrupted intra-axonal signal voxel detected. Fiber volume larger voxel volume!"; + if (extraAxonalVolume<-0.001) + MITK_ERROR << "Corrupted intra-axonal signal voxel detected. Fiber volume larger voxel volume! " << m_VoxelVolume << "<" << intraAxonalVolume; extraAxonalVolume = 0; } double interAxonalVolume = 0; if (numFiberCompartments>1) interAxonalVolume = extraAxonalVolume * intraAxonalVolume/m_VoxelVolume; // inter-axonal fraction of non fiber compartment double other = extraAxonalVolume - interAxonalVolume; // rest of compartment if (other<0) { - MITK_ERROR << "Corrupted signal voxel detected. Fiber volume larger voxel volume!"; + if (other<-0.001) + MITK_ERROR << "Corrupted signal voxel detected. Fiber volume larger voxel volume!"; other = 0; } // adjust non-fiber and intra-axonal signal for (int i=1; iGetPixel(index); if (intraAxonalVolume>0) // remove scaling by intra-axonal volume from inter-axonal compartment { if (g>=0) pix[g] /= intraAxonalVolume; else pix /= intraAxonalVolume; } if (m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage()!=nullptr) { double val = InterpolateValue(point, m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage()); if (val<0) continue; else weight = val*m_VoxelVolume; } if (g>=0) pix[g] *= weight; else pix *= weight; m_CompartmentImages.at(i)->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(i)->SetPixel(index, weight/m_VoxelVolume); } for (int i=0; iGetPixel(index); if (m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()!=nullptr) { double val = InterpolateValue(point, m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()); if (val<0) continue; else weight = val*m_VoxelVolume; if (m_UseRelativeNonFiberVolumeFractions) weight *= other/m_VoxelVolume; } if (g>=0) pix[g] += m_Parameters.m_NonFiberModelList[i]->SimulateMeasurement(g)*weight; else pix += m_Parameters.m_NonFiberModelList[i]->SimulateMeasurement()*weight; m_CompartmentImages.at(i+numFiberCompartments)->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(i+numFiberCompartments)->SetPixel(index, weight/m_VoxelVolume); } } } } template< class PixelType > double TractsToDWIImageFilter< PixelType >:: InterpolateValue(itk::Point itkP, ItkDoubleImgType::Pointer img) { itk::Index<3> idx; itk::ContinuousIndex< double, 3> cIdx; img->TransformPhysicalPointToIndex(itkP, idx); img->TransformPhysicalPointToContinuousIndex(itkP, cIdx); double pix = -1; if ( img->GetLargestPossibleRegion().IsInside(idx) ) pix = img->GetPixel(idx); else return pix; double frac_x = cIdx[0] - idx[0]; double frac_y = cIdx[1] - idx[1]; double frac_z = cIdx[2] - idx[2]; if (frac_x<0) { idx[0] -= 1; frac_x += 1; } if (frac_y<0) { idx[1] -= 1; frac_y += 1; } if (frac_z<0) { idx[2] -= 1; frac_z += 1; } frac_x = 1-frac_x; frac_y = 1-frac_y; frac_z = 1-frac_z; // int coordinates inside image? if (idx[0] >= 0 && idx[0] < img->GetLargestPossibleRegion().GetSize(0)-1 && idx[1] >= 0 && idx[1] < img->GetLargestPossibleRegion().GetSize(1)-1 && idx[2] >= 0 && idx[2] < img->GetLargestPossibleRegion().GetSize(2)-1) { vnl_vector_fixed interpWeights; interpWeights[0] = ( frac_x)*( frac_y)*( frac_z); interpWeights[1] = (1-frac_x)*( frac_y)*( frac_z); interpWeights[2] = ( frac_x)*(1-frac_y)*( frac_z); interpWeights[3] = ( frac_x)*( frac_y)*(1-frac_z); interpWeights[4] = (1-frac_x)*(1-frac_y)*( frac_z); interpWeights[5] = ( frac_x)*(1-frac_y)*(1-frac_z); interpWeights[6] = (1-frac_x)*( frac_y)*(1-frac_z); interpWeights[7] = (1-frac_x)*(1-frac_y)*(1-frac_z); pix = img->GetPixel(idx) * interpWeights[0]; ItkDoubleImgType::IndexType tmpIdx = idx; tmpIdx[0]++; pix += img->GetPixel(tmpIdx) * interpWeights[1]; tmpIdx = idx; tmpIdx[1]++; pix += img->GetPixel(tmpIdx) * interpWeights[2]; tmpIdx = idx; tmpIdx[2]++; pix += img->GetPixel(tmpIdx) * interpWeights[3]; tmpIdx = idx; tmpIdx[0]++; tmpIdx[1]++; pix += img->GetPixel(tmpIdx) * interpWeights[4]; tmpIdx = idx; tmpIdx[1]++; tmpIdx[2]++; pix += img->GetPixel(tmpIdx) * interpWeights[5]; tmpIdx = idx; tmpIdx[2]++; tmpIdx[0]++; pix += img->GetPixel(tmpIdx) * interpWeights[6]; tmpIdx = idx; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++; pix += img->GetPixel(tmpIdx) * interpWeights[7]; } return pix; } template< class PixelType > itk::Point TractsToDWIImageFilter< PixelType >::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } template< class PixelType > itk::Vector TractsToDWIImageFilter< PixelType >::GetItkVector(double point[3]) { itk::Vector itkVector; itkVector[0] = point[0]; itkVector[1] = point[1]; itkVector[2] = point[2]; return itkVector; } template< class PixelType > vnl_vector_fixed TractsToDWIImageFilter< PixelType >::GetVnlVector(double point[3]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } template< class PixelType > vnl_vector_fixed TractsToDWIImageFilter< PixelType >::GetVnlVector(Vector& vector) { vnl_vector_fixed vnlVector; vnlVector[0] = vector[0]; vnlVector[1] = vector[1]; vnlVector[2] = vector[2]; return vnlVector; } template< class PixelType > double TractsToDWIImageFilter< PixelType >::RoundToNearest(double num) { return (num > 0.0) ? floor(num + 0.5) : ceil(num - 0.5); } template< class PixelType > std::string TractsToDWIImageFilter< PixelType >::GetTime() { m_TimeProbe.Stop(); unsigned long total = RoundToNearest(m_TimeProbe.GetTotal()); unsigned long hours = total/3600; unsigned long minutes = (total%3600)/60; unsigned long seconds = total%60; std::string out = ""; out.append(boost::lexical_cast(hours)); out.append(":"); out.append(boost::lexical_cast(minutes)); out.append(":"); out.append(boost::lexical_cast(seconds)); m_TimeProbe.Start(); return out; } } diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp index 5ead665866..5b25f8f59b 100755 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp @@ -1,2023 +1,2100 @@ /*=================================================================== 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. ===================================================================*/ #define _USE_MATH_DEFINES #include "mitkFiberBundle.h" #include #include #include #include "mitkImagePixelReadAccessor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const char* mitk::FiberBundle::FIBER_ID_ARRAY = "Fiber_IDs"; using namespace std; mitk::FiberBundle::FiberBundle( vtkPolyData* fiberPolyData ) : m_NumFibers(0) , m_FiberSampling(0) { m_FiberWeights = vtkSmartPointer::New(); m_FiberWeights->SetName("FIBER_WEIGHTS"); m_FiberPolyData = vtkSmartPointer::New(); if (fiberPolyData != nullptr) { m_FiberPolyData = fiberPolyData; this->ColorFibersByOrientation(); } this->UpdateFiberGeometry(); this->GenerateFiberIds(); } mitk::FiberBundle::~FiberBundle() { } mitk::FiberBundle::Pointer mitk::FiberBundle::GetDeepCopy() { mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(m_FiberPolyData); newFib->SetFiberColors(this->m_FiberColors); newFib->SetFiberWeights(this->m_FiberWeights); return newFib; } vtkSmartPointer mitk::FiberBundle::GeneratePolyDataByIds(std::vector fiberIds) { vtkSmartPointer newFiberPolyData = vtkSmartPointer::New(); vtkSmartPointer newLineSet = vtkSmartPointer::New(); vtkSmartPointer newPointSet = vtkSmartPointer::New(); auto finIt = fiberIds.begin(); while ( finIt != fiberIds.end() ) { if (*finIt < 0 || *finIt>GetNumFibers()){ MITK_INFO << "FiberID can not be negative or >NumFibers!!! check id Extraction!" << *finIt; break; } vtkSmartPointer fiber = m_FiberIdDataSet->GetCell(*finIt);//->DeepCopy(fiber); vtkSmartPointer fibPoints = fiber->GetPoints(); vtkSmartPointer newFiber = vtkSmartPointer::New(); newFiber->GetPointIds()->SetNumberOfIds( fibPoints->GetNumberOfPoints() ); for(int i=0; iGetNumberOfPoints(); i++) { newFiber->GetPointIds()->SetId(i, newPointSet->GetNumberOfPoints()); newPointSet->InsertNextPoint(fibPoints->GetPoint(i)[0], fibPoints->GetPoint(i)[1], fibPoints->GetPoint(i)[2]); } newLineSet->InsertNextCell(newFiber); ++finIt; } newFiberPolyData->SetPoints(newPointSet); newFiberPolyData->SetLines(newLineSet); return newFiberPolyData; } // merge two fiber bundles mitk::FiberBundle::Pointer mitk::FiberBundle::AddBundle(mitk::FiberBundle* fib) { if (fib==nullptr) { MITK_WARN << "trying to call AddBundle with NULL argument"; return nullptr; } MITK_INFO << "Adding fibers"; vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); // add current fiber bundle vtkSmartPointer weights = vtkSmartPointer::New(); weights->SetNumberOfValues(this->GetNumFibers()+fib->GetNumFibers()); unsigned int counter = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, this->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } // add new fiber bundle for (int i=0; iGetFiberPolyData()->GetNumberOfCells(); i++) { vtkCell* cell = fib->GetFiberPolyData()->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, fib->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } // initialize polydata vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); newFib->SetFiberWeights(weights); return newFib; } // subtract two fiber bundles mitk::FiberBundle::Pointer mitk::FiberBundle::SubtractBundle(mitk::FiberBundle* fib) { MITK_INFO << "Subtracting fibers"; vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); - // iterate over current fibers - boost::progress_display disp(m_NumFibers); + std::vector< std::vector< itk::Point > > points1; for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (points==nullptr || numPoints<=0) continue; - int numFibers2 = fib->GetNumFibers(); - bool contained = false; - for( int i2=0; i2 start = GetItkPoint(points->GetPoint(0)); + itk::Point end = GetItkPoint(points->GetPoint(numPoints-1)); + + points1.push_back( {start, end} ); + } + + std::vector< std::vector< itk::Point > > points2; + for( int i=0; iGetNumFibers(); i++ ) + { + vtkCell* cell = fib->GetFiberPolyData()->GetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + + if (points==nullptr || numPoints<=0) + continue; + + itk::Point start = GetItkPoint(points->GetPoint(0)); + itk::Point end = GetItkPoint(points->GetPoint(numPoints-1)); + + points2.push_back( {start, end} ); + } + + int progress = 0; + std::vector< int > ids; +#pragma omp parallel for + for (unsigned int i=0; iGetFiberPolyData()->GetCell(i2); - int numPoints2 = cell2->GetNumberOfPoints(); - vtkPoints* points2 = cell2->GetPoints(); + progress++; + std::cout << (int)(100*(float)progress/points1.size()) << "%" << '\r'; + cout.flush(); + } - if (points2==nullptr)// || numPoints2<=0) - continue; + bool match = false; + for (unsigned int j=0; j point_start = GetItkPoint(points->GetPoint(0)); - itk::Point point_end = GetItkPoint(points->GetPoint(numPoints-1)); - itk::Point point2_start = GetItkPoint(points2->GetPoint(0)); - itk::Point point2_end = GetItkPoint(points2->GetPoint(numPoints2-1)); + if (v1[c].SquaredEuclideanDistanceTo(v2[c])GetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + + if (points==nullptr || numPoints<=0) + continue; + + vtkSmartPointer container = vtkSmartPointer::New(); + for( int j=0; j container = vtkSmartPointer::New(); - for( int j=0; jInsertNextPoint(points->GetPoint(j)); - container->GetPointIds()->InsertNextId(id); - } - vNewLines->InsertNextCell(container); + vtkIdType id = vNewPoints->InsertNextPoint(points->GetPoint(j)); + container->GetPointIds()->InsertNextId(id); } + vNewLines->InsertNextCell(container); } if(vNewLines->GetNumberOfCells()==0) return nullptr; // initialize polydata vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle return mitk::FiberBundle::New(vNewPolyData); } itk::Point mitk::FiberBundle::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } /* * set polydata (additional flag to recompute fiber geometry, default = true) */ void mitk::FiberBundle::SetFiberPolyData(vtkSmartPointer fiberPD, bool updateGeometry) { if (fiberPD == nullptr) this->m_FiberPolyData = vtkSmartPointer::New(); else { m_FiberPolyData->DeepCopy(fiberPD); ColorFibersByOrientation(); } m_NumFibers = m_FiberPolyData->GetNumberOfLines(); if (updateGeometry) UpdateFiberGeometry(); GenerateFiberIds(); } /* * return vtkPolyData */ vtkSmartPointer mitk::FiberBundle::GetFiberPolyData() const { return m_FiberPolyData; } void mitk::FiberBundle::ColorFibersByOrientation() { //===== 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_FiberPolyData->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; m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(numOfPoints * componentSize); m_FiberColors->SetNumberOfComponents(componentSize); m_FiberColors->SetName("FIBER_COLORS"); int numOfFibers = m_FiberPolyData->GetNumberOfLines(); if (numOfFibers < 1) return; /* extract single fibers of fiberBundle */ vtkCellArray* fiberList = m_FiberPolyData->GetLines(); fiberList->InitTraversal(); for (int fi=0; fiGetNextCell(pointsPerFiber, idList); /* single fiber checkpoints: is number of points valid */ if (pointsPerFiber > 1) { /* operate on points of single fiber */ for (int i=0; i 0) { /* The color value of the current point is influenced by the previous point and next point. */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; vnl_vector_fixed< double, 3 > diff; diff = (diff1 - diff2) / 2.0; diff.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff[2])); rgba[3] = (unsigned char) (255.0); } else if (i==0) { /* First point has no previous point, therefore only diff1 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+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); } else if (i==pointsPerFiber-1) { /* Last point has no next point, therefore only diff2 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; diff2.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff2[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff2[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff2[2])); rgba[3] = (unsigned char) (255.0); } m_FiberColors->InsertTupleValue(idList[i], rgba); } } else if (pointsPerFiber == 1) { /* a single point does not define a fiber (use vertex mechanisms instead */ continue; } else { MITK_DEBUG << "Fiber with 0 points detected... please check your tractography algorithm!" ; continue; } } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByCurvature(bool minMaxNorm) { double window = 5; //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; int componentSize = 4; m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * componentSize); m_FiberColors->SetNumberOfComponents(componentSize); m_FiberColors->SetName("FIBER_COLORS"); mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 0.8); lookupTable->Build(); mitkLookup->SetVtkLookupTable(lookupTable); mitkLookup->SetType(mitk::LookupTable::JET); vector< double > values; double min = 1; double max = 0; MITK_INFO << "Coloring fibers by curvature"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // calculate curvatures for (int j=0; j > vectors; vnl_vector_fixed< float, 3 > meanV; meanV.fill(0.0); while(dist1) { double p1[3]; points->GetPoint(c-1, p1); double p2[3]; points->GetPoint(c, p2); vnl_vector_fixed< float, 3 > v; v[0] = p2[0]-p1[0]; v[1] = p2[1]-p1[1]; v[2] = p2[2]-p1[2]; dist += v.magnitude(); v.normalize(); vectors.push_back(v); if (c==j) meanV += v; c--; } c = j; dist = 0; while(distGetPoint(c, p1); double p2[3]; points->GetPoint(c+1, p2); vnl_vector_fixed< float, 3 > v; v[0] = p2[0]-p1[0]; v[1] = p2[1]-p1[1]; v[2] = p2[2]-p1[2]; dist += v.magnitude(); v.normalize(); vectors.push_back(v); if (c==j) meanV += v; c++; } meanV.normalize(); double dev = 0; for (unsigned int c=0; c1.0) angle = 1.0; if (angle<-1.0) angle = -1.0; dev += acos(angle)*180/M_PI; } if (vectors.size()>0) dev /= vectors.size(); dev = 1.0-dev/180.0; values.push_back(dev); if (devmax) max = dev; } } unsigned int count = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); for (int j=0; jGetColor(dev, color); rgba[0] = (unsigned char) (255.0 * color[0]); rgba[1] = (unsigned char) (255.0 * color[1]); rgba[2] = (unsigned char) (255.0 * color[2]); rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTupleValue(cell->GetPointId(j), rgba); count++; } } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::SetFiberOpacity(vtkDoubleArray* FAValArray) { for(long i=0; iGetNumberOfTuples(); i++) { double faValue = FAValArray->GetValue(i); faValue = faValue * 255.0; m_FiberColors->SetComponent(i,3, (unsigned char) faValue ); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ResetFiberOpacity() { for(long i=0; iGetNumberOfTuples(); i++) m_FiberColors->SetComponent(i,3, 255.0 ); m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByScalarMap(mitk::Image::Pointer FAimage, bool opacity) { mitkPixelTypeMultiplex2( ColorFibersByScalarMap, FAimage->GetPixelType(), FAimage, opacity ); m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } template void mitk::FiberBundle::ColorFibersByScalarMap(const mitk::PixelType, mitk::Image::Pointer image, bool opacity) { m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); m_FiberColors->SetNumberOfComponents(4); m_FiberColors->SetName("FIBER_COLORS"); mitk::ImagePixelReadAccessor readimage(image, image->GetVolumeData(0)); unsigned char rgba[4] = {0,0,0,0}; vtkPoints* pointSet = m_FiberPolyData->GetPoints(); mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 0.8); lookupTable->Build(); mitkLookup->SetVtkLookupTable(lookupTable); mitkLookup->SetType(mitk::LookupTable::JET); for(long i=0; iGetNumberOfPoints(); ++i) { Point3D px; px[0] = pointSet->GetPoint(i)[0]; px[1] = pointSet->GetPoint(i)[1]; px[2] = pointSet->GetPoint(i)[2]; double pixelValue = readimage.GetPixelByWorldCoordinates(px); double color[3]; lookupTable->GetColor(1-pixelValue, color); rgba[0] = (unsigned char) (255.0 * color[0]); rgba[1] = (unsigned char) (255.0 * color[1]); rgba[2] = (unsigned char) (255.0 * color[2]); if (opacity) rgba[3] = (unsigned char) (255.0 * pixelValue); else rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTupleValue(i, rgba); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::SetFiberColors(float r, float g, float b, float alpha) { m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); m_FiberColors->SetNumberOfComponents(4); m_FiberColors->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) alpha; m_FiberColors->InsertTupleValue(i, rgba); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::GenerateFiberIds() { if (m_FiberPolyData == nullptr) return; vtkSmartPointer idFiberFilter = vtkSmartPointer::New(); idFiberFilter->SetInputData(m_FiberPolyData); idFiberFilter->CellIdsOn(); // idFiberFilter->PointIdsOn(); // point id's are not needed idFiberFilter->SetIdsArrayName(FIBER_ID_ARRAY); idFiberFilter->FieldDataOn(); idFiberFilter->Update(); m_FiberIdDataSet = idFiberFilter->GetOutput(); } -mitk::FiberBundle::Pointer mitk::FiberBundle::ExtractFiberSubset(ItkUcharImgType* mask, bool anyPoint, bool invert, bool bothEnds) +mitk::FiberBundle::Pointer mitk::FiberBundle::ExtractFiberSubset(ItkUcharImgType* mask, bool anyPoint, bool invert, bool bothEnds, float fraction) { vtkSmartPointer polyData = m_FiberPolyData; if (anyPoint) { float minSpacing = 1; if(mask->GetSpacing()[0]GetSpacing()[1] && mask->GetSpacing()[0]GetSpacing()[2]) minSpacing = mask->GetSpacing()[0]; else if (mask->GetSpacing()[1] < mask->GetSpacing()[2]) minSpacing = mask->GetSpacing()[1]; else minSpacing = mask->GetSpacing()[2]; mitk::FiberBundle::Pointer fibCopy = this->GetDeepCopy(); fibCopy->ResampleSpline(minSpacing/5); polyData = fibCopy->GetFiberPolyData(); } vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Extracting fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkCell* cellOriginal = m_FiberPolyData->GetCell(i); int numPointsOriginal = cellOriginal->GetNumberOfPoints(); vtkPoints* pointsOriginal = cellOriginal->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); if (numPoints>1 && numPointsOriginal) { if (anyPoint) { + int inside = 0; + int outside = 0; if (!invert) { for (int j=0; jGetPoint(j); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; itk::Index<3> idx; mask->TransformPhysicalPointToIndex(itkP, idx); - if ( mask->GetPixel(idx)>0 && mask->GetLargestPossibleRegion().IsInside(idx) ) + if ( mask->GetLargestPossibleRegion().IsInside(idx) && mask->GetPixel(idx)>0 ) { - for (int k=0; kGetPoint(k); - vtkIdType id = vtkNewPoints->InsertNextPoint(p); - container->GetPointIds()->InsertNextId(id); - } - break; + inside++; + if (fraction==0) + break; + } + else + outside++; + } + + float current_fraction = 0.0; + if (inside+outside>0) + current_fraction = (float)inside/(inside+outside); + + if (current_fraction>fraction) + { + for (int k=0; kGetPoint(k); + vtkIdType id = vtkNewPoints->InsertNextPoint(p); + container->GetPointIds()->InsertNextId(id); } } } else { bool includeFiber = true; for (int j=0; jGetPoint(j); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; itk::Index<3> idx; mask->TransformPhysicalPointToIndex(itkP, idx); if ( mask->GetPixel(idx)>0 && mask->GetLargestPossibleRegion().IsInside(idx) ) { + inside++; includeFiber = false; break; } + else + outside++; } if (includeFiber) { - for (int k=0; kGetPoint(k); + double* p = points->GetPoint(k); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } } } } else { double* start = pointsOriginal->GetPoint(0); itk::Point itkStart; itkStart[0] = start[0]; itkStart[1] = start[1]; itkStart[2] = start[2]; itk::Index<3> idxStart; mask->TransformPhysicalPointToIndex(itkStart, idxStart); double* end = pointsOriginal->GetPoint(numPointsOriginal-1); itk::Point itkEnd; itkEnd[0] = end[0]; itkEnd[1] = end[1]; itkEnd[2] = end[2]; itk::Index<3> idxEnd; mask->TransformPhysicalPointToIndex(itkEnd, idxEnd); if (invert) { if (bothEnds) { if ( !mask->GetPixel(idxStart)>0 && !mask->GetPixel(idxEnd)>0 ) { for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } } } else if ( !mask->GetPixel(idxStart)>0 || !mask->GetPixel(idxEnd)>0 ) { for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } } } else { if (bothEnds) { if ( mask->GetPixel(idxStart)>0 && mask->GetPixel(idxEnd)>0 && mask->GetLargestPossibleRegion().IsInside(idxStart) && mask->GetLargestPossibleRegion().IsInside(idxEnd) ) { for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } } } else if ( (mask->GetPixel(idxStart)>0 && mask->GetLargestPossibleRegion().IsInside(idxStart)) || (mask->GetPixel(idxEnd)>0 && mask->GetLargestPossibleRegion().IsInside(idxEnd)) ) { for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } } } } } vtkNewCells->InsertNextCell(container); } if (vtkNewCells->GetNumberOfCells()<=0) return nullptr; vtkSmartPointer newPolyData = vtkSmartPointer::New(); newPolyData->SetPoints(vtkNewPoints); newPolyData->SetLines(vtkNewCells); return mitk::FiberBundle::New(newPolyData); } mitk::FiberBundle::Pointer mitk::FiberBundle::RemoveFibersOutside(ItkUcharImgType* mask, bool invert) { float minSpacing = 1; if(mask->GetSpacing()[0]GetSpacing()[1] && mask->GetSpacing()[0]GetSpacing()[2]) minSpacing = mask->GetSpacing()[0]; else if (mask->GetSpacing()[1] < mask->GetSpacing()[2]) minSpacing = mask->GetSpacing()[1]; else minSpacing = mask->GetSpacing()[2]; mitk::FiberBundle::Pointer fibCopy = this->GetDeepCopy(); fibCopy->ResampleSpline(minSpacing/10); vtkSmartPointer polyData =fibCopy->GetFiberPolyData(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Cutting fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); if (numPoints>1) { int newNumPoints = 0; for (int j=0; jGetPoint(j); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; itk::Index<3> idx; mask->TransformPhysicalPointToIndex(itkP, idx); if ( mask->GetPixel(idx)>0 && mask->GetLargestPossibleRegion().IsInside(idx) && !invert ) { vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); newNumPoints++; } else if ( (mask->GetPixel(idx)<=0 || !mask->GetLargestPossibleRegion().IsInside(idx)) && invert ) { vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); newNumPoints++; } else if (newNumPoints>0) { vtkNewCells->InsertNextCell(container); newNumPoints = 0; container = vtkSmartPointer::New(); } } if (newNumPoints>0) vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()<=0) return nullptr; vtkSmartPointer newPolyData = vtkSmartPointer::New(); newPolyData->SetPoints(vtkNewPoints); newPolyData->SetLines(vtkNewCells); mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(newPolyData); newFib->Compress(0.1); return newFib; } mitk::FiberBundle::Pointer mitk::FiberBundle::ExtractFiberSubset(DataNode* roi, DataStorage* storage) { if (roi==nullptr || !(dynamic_cast(roi->GetData()) || dynamic_cast(roi->GetData())) ) return nullptr; std::vector tmp = ExtractFiberIdSubset(roi, storage); if (tmp.size()<=0) return mitk::FiberBundle::New(); vtkSmartPointer pTmp = GeneratePolyDataByIds(tmp); return mitk::FiberBundle::New(pTmp); } std::vector mitk::FiberBundle::ExtractFiberIdSubset(DataNode *roi, DataStorage* storage) { std::vector result; if (roi==nullptr || roi->GetData()==nullptr) return result; mitk::PlanarFigureComposite::Pointer pfc = dynamic_cast(roi->GetData()); if (!pfc.IsNull()) // handle composite { DataStorage::SetOfObjects::ConstPointer children = storage->GetDerivations(roi); if (children->size()==0) return result; switch (pfc->getOperationType()) { case 0: // AND { MITK_INFO << "AND"; result = this->ExtractFiberIdSubset(children->ElementAt(0), storage); std::vector::iterator it; for (unsigned int i=1; iSize(); ++i) { std::vector inRoi = this->ExtractFiberIdSubset(children->ElementAt(i), storage); std::vector rest(std::min(result.size(),inRoi.size())); it = std::set_intersection(result.begin(), result.end(), inRoi.begin(), inRoi.end(), rest.begin() ); rest.resize( it - rest.begin() ); result = rest; } break; } case 1: // OR { MITK_INFO << "OR"; result = ExtractFiberIdSubset(children->ElementAt(0), storage); std::vector::iterator it; for (unsigned int i=1; iSize(); ++i) { it = result.end(); std::vector inRoi = ExtractFiberIdSubset(children->ElementAt(i), storage); result.insert(it, inRoi.begin(), inRoi.end()); } // remove duplicates sort(result.begin(), result.end()); it = unique(result.begin(), result.end()); result.resize( it - result.begin() ); break; } case 2: // NOT { MITK_INFO << "NOT"; for(long i=0; iGetNumFibers(); i++) result.push_back(i); std::vector::iterator it; for (long i=0; iSize(); ++i) { std::vector inRoi = ExtractFiberIdSubset(children->ElementAt(i), storage); std::vector rest(result.size()-inRoi.size()); it = std::set_difference(result.begin(), result.end(), inRoi.begin(), inRoi.end(), rest.begin() ); rest.resize( it - rest.begin() ); result = rest; } break; } } } else if ( dynamic_cast(roi->GetData()) ) // actual extraction { if ( dynamic_cast(roi->GetData()) ) { mitk::PlanarFigure::Pointer planarPoly = dynamic_cast(roi->GetData()); //create vtkPolygon using controlpoints from planarFigure polygon vtkSmartPointer polygonVtk = vtkSmartPointer::New(); for (unsigned int i=0; iGetNumberOfControlPoints(); ++i) { itk::Point p = planarPoly->GetWorldControlPoint(i); vtkIdType id = polygonVtk->GetPoints()->InsertNextPoint(p[0], p[1], p[2] ); polygonVtk->GetPointIds()->InsertNextId(id); } MITK_INFO << "Extracting with polygon"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, p1); double p2[3] = {0,0,0}; points->GetPoint(j+1, p2); double tolerance = 0.001; // Outputs double t = 0; // Parametric coordinate of intersection (0 (corresponding to p1) to 1 (corresponding to p2)) double x[3] = {0,0,0}; // The coordinate of the intersection double pcoords[3] = {0,0,0}; int subId = 0; int iD = polygonVtk->IntersectWithLine(p1, p2, tolerance, t, x, pcoords, subId); if (iD!=0) { result.push_back(i); break; } } } } else if ( dynamic_cast(roi->GetData()) ) { mitk::PlanarFigure::Pointer planarFigure = dynamic_cast(roi->GetData()); Vector3D planeNormal = planarFigure->GetPlaneGeometry()->GetNormal(); planeNormal.Normalize(); //calculate circle radius mitk::Point3D V1w = planarFigure->GetWorldControlPoint(0); //centerPoint mitk::Point3D V2w = planarFigure->GetWorldControlPoint(1); //radiusPoint double radius = V1w.EuclideanDistanceTo(V2w); radius *= radius; MITK_INFO << "Extracting with circle"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, p1); double p2[3] = {0,0,0}; points->GetPoint(j+1, p2); // Outputs double t = 0; // Parametric coordinate of intersection (0 (corresponding to p1) to 1 (corresponding to p2)) double x[3] = {0,0,0}; // The coordinate of the intersection int iD = vtkPlane::IntersectWithLine(p1,p2,planeNormal.GetDataPointer(),V1w.GetDataPointer(),t,x); if (iD!=0) { double dist = (x[0]-V1w[0])*(x[0]-V1w[0])+(x[1]-V1w[1])*(x[1]-V1w[1])+(x[2]-V1w[2])*(x[2]-V1w[2]); if( dist <= radius) { result.push_back(i); break; } } } } } return result; } return result; } void mitk::FiberBundle::UpdateFiberGeometry() { vtkSmartPointer cleaner = vtkSmartPointer::New(); cleaner->SetInputData(m_FiberPolyData); cleaner->PointMergingOff(); cleaner->Update(); m_FiberPolyData = cleaner->GetOutput(); m_FiberLengths.clear(); m_MeanFiberLength = 0; m_MedianFiberLength = 0; m_LengthStDev = 0; m_NumFibers = m_FiberPolyData->GetNumberOfCells(); if (m_FiberColors==nullptr || m_FiberColors->GetNumberOfTuples()!=m_FiberPolyData->GetNumberOfPoints()) this->ColorFibersByOrientation(); if (m_FiberWeights->GetSize()!=m_NumFibers) { m_FiberWeights = vtkSmartPointer::New(); m_FiberWeights->SetName("FIBER_WEIGHTS"); m_FiberWeights->SetNumberOfValues(m_NumFibers); this->SetFiberWeights(1); } if (m_NumFibers<=0) // no fibers present; apply default geometry { m_MinFiberLength = 0; m_MaxFiberLength = 0; mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetImageGeometry(false); float b[] = {0, 1, 0, 1, 0, 1}; geometry->SetFloatBounds(b); SetGeometry(geometry); return; } double b[6]; m_FiberPolyData->GetBounds(b); // calculate statistics for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int p = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); float length = 0; for (int j=0; jGetPoint(j, p1); double p2[3]; points->GetPoint(j+1, p2); float dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); length += dist; } m_FiberLengths.push_back(length); m_MeanFiberLength += length; if (i==0) { m_MinFiberLength = length; m_MaxFiberLength = length; } else { if (lengthm_MaxFiberLength) m_MaxFiberLength = length; } } m_MeanFiberLength /= m_NumFibers; std::vector< float > sortedLengths = m_FiberLengths; std::sort(sortedLengths.begin(), sortedLengths.end()); for (int i=0; i1) m_LengthStDev /= (m_NumFibers-1); else m_LengthStDev = 0; m_LengthStDev = std::sqrt(m_LengthStDev); m_MedianFiberLength = sortedLengths.at(m_NumFibers/2); mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetFloatBounds(b); this->SetGeometry(geometry); m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } float mitk::FiberBundle::GetFiberWeight(unsigned int fiber) { return m_FiberWeights->GetValue(fiber); } void mitk::FiberBundle::SetFiberWeights(float newWeight) { for (int i=0; iGetSize(); i++) m_FiberWeights->SetValue(i, newWeight); } void mitk::FiberBundle::SetFiberWeights(vtkSmartPointer weights) { if (m_NumFibers!=weights->GetSize()) { MITK_INFO << "Weights array not equal to number of fibers!"; return; } for (int i=0; iGetSize(); i++) m_FiberWeights->SetValue(i, weights->GetValue(i)); m_FiberWeights->SetName("FIBER_WEIGHTS"); } void mitk::FiberBundle::SetFiberWeight(unsigned int fiber, float weight) { m_FiberWeights->SetValue(fiber, weight); } void mitk::FiberBundle::SetFiberColors(vtkSmartPointer fiberColors) { for(long i=0; iGetNumberOfPoints(); ++i) { unsigned char source[4] = {0,0,0,0}; fiberColors->GetTupleValue(i, source); unsigned char target[4] = {0,0,0,0}; target[0] = source[0]; target[1] = source[1]; target[2] = source[2]; target[3] = source[3]; m_FiberColors->InsertTupleValue(i, target); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } itk::Matrix< double, 3, 3 > mitk::FiberBundle::TransformMatrix(itk::Matrix< double, 3, 3 > m, double rx, double ry, double rz) { rx = rx*M_PI/180; ry = ry*M_PI/180; rz = rz*M_PI/180; itk::Matrix< double, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; itk::Matrix< double, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; itk::Matrix< double, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< double, 3, 3 > rot = rotZ*rotY*rotX; m = rot*m; return m; } itk::Point mitk::FiberBundle::TransformPoint(vnl_vector_fixed< double, 3 > point, double rx, double ry, double rz, double tx, double ty, double tz) { rx = rx*M_PI/180; ry = ry*M_PI/180; rz = rz*M_PI/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; vnl_matrix_fixed< double, 3, 3 > rot = rotZ*rotY*rotX; mitk::BaseGeometry::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); point[0] -= center[0]; point[1] -= center[1]; point[2] -= center[2]; point = rot*point; point[0] += center[0]+tx; point[1] += center[1]+ty; point[2] += center[2]+tz; itk::Point out; out[0] = point[0]; out[1] = point[1]; out[2] = point[2]; return out; } void mitk::FiberBundle::TransformFibers(double rx, double ry, double rz, double tx, double ty, double tz) { rx = rx*M_PI/180; ry = ry*M_PI/180; rz = rz*M_PI/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; vnl_matrix_fixed< double, 3, 3 > rot = rotZ*rotY*rotX; mitk::BaseGeometry::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vnl_vector_fixed< double, 3 > dir; dir[0] = p[0]-center[0]; dir[1] = p[1]-center[1]; dir[2] = p[2]-center[2]; dir = rot*dir; dir[0] += center[0]+tx; dir[1] += center[1]+ty; dir[2] += center[2]+tz; vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::RotateAroundAxis(double x, double y, double z) { x = x*M_PI/180; y = y*M_PI/180; z = z*M_PI/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; mitk::BaseGeometry::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vnl_vector_fixed< double, 3 > dir; dir[0] = p[0]-center[0]; dir[1] = p[1]-center[1]; dir[2] = p[2]-center[2]; dir = rotZ*rotY*rotX*dir; dir[0] += center[0]; dir[1] += center[1]; dir[2] += center[2]; vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::ScaleFibers(double x, double y, double z, bool subtractCenter) { MITK_INFO << "Scaling fibers"; boost::progress_display disp(m_NumFibers); mitk::BaseGeometry* geom = this->GetGeometry(); mitk::Point3D c = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); if (subtractCenter) { p[0] -= c[0]; p[1] -= c[1]; p[2] -= c[2]; } p[0] *= x; p[1] *= y; p[2] *= z; if (subtractCenter) { p[0] += c[0]; p[1] += c[1]; p[2] += c[2]; } vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::TranslateFibers(double x, double y, double z) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); p[0] += x; p[1] += y; p[2] += z; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::MirrorFibers(unsigned int axis) { if (axis>2) return; MITK_INFO << "Mirroring fibers"; boost::progress_display disp(m_NumFibers); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); p[axis] = -p[axis]; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::RemoveDir(vnl_vector_fixed dir, double threshold) { dir.normalize(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp ; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // calculate curvatures vtkSmartPointer container = vtkSmartPointer::New(); bool discard = false; for (int j=0; jGetPoint(j, p1); double p2[3]; points->GetPoint(j+1, p2); vnl_vector_fixed< double, 3 > v1; v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; if (v1.magnitude()>0.001) { v1.normalize(); if (fabs(dot_product(v1,dir))>threshold) { discard = true; break; } } } if (!discard) { for (int j=0; jGetPoint(j, p1); vtkIdType id = vtkNewPoints->InsertNextPoint(p1); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); // UpdateColorCoding(); // UpdateFiberGeometry(); } bool mitk::FiberBundle::ApplyCurvatureThreshold(float minRadius, bool deleteFibers) { if (minRadius<0) return true; vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Applying curvature threshold"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp ; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // calculate curvatures vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p1); double p2[3]; points->GetPoint(j+1, p2); double p3[3]; points->GetPoint(j+2, p3); vnl_vector_fixed< float, 3 > v1, v2, v3; v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; v2[0] = p3[0]-p2[0]; v2[1] = p3[1]-p2[1]; v2[2] = p3[2]-p2[2]; v3[0] = p1[0]-p3[0]; v3[1] = p1[1]-p3[1]; v3[2] = p1[2]-p3[2]; float a = v1.magnitude(); float b = v2.magnitude(); float c = v3.magnitude(); float r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle) vtkIdType id = vtkNewPoints->InsertNextPoint(p1); container->GetPointIds()->InsertNextId(id); if (deleteFibers && rInsertNextCell(container); container = vtkSmartPointer::New(); } else if (j==numPoints-3) { id = vtkNewPoints->InsertNextPoint(p2); container->GetPointIds()->InsertNextId(id); id = vtkNewPoints->InsertNextPoint(p3); container->GetPointIds()->InsertNextId(id); vtkNewCells->InsertNextCell(container); } } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); return true; } bool mitk::FiberBundle::RemoveShortFibers(float lengthInMM) { MITK_INFO << "Removing short fibers"; if (lengthInMM<=0 || lengthInMMm_MaxFiberLength) // can't remove all fibers { MITK_WARN << "Process aborted. No fibers would be left!"; return false; } vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); float min = m_MaxFiberLength; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (m_FiberLengths.at(i)>=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); if (m_FiberLengths.at(i)GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); return true; } bool mitk::FiberBundle::RemoveLongFibers(float lengthInMM) { if (lengthInMM<=0 || lengthInMM>m_MaxFiberLength) return true; if (lengthInMM vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Removing long fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (m_FiberLengths.at(i)<=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); return true; } void mitk::FiberBundle::ResampleSpline(float pointDistance, double tension, double continuity, double bias ) { if (pointDistance<=0) return; vtkSmartPointer vtkSmoothPoints = vtkSmartPointer::New(); //in smoothpoints the interpolated points representing a fiber are stored. //in vtkcells all polylines are stored, actually all id's of them are stored vtkSmartPointer vtkSmoothCells = vtkSmartPointer::New(); //cellcontainer for smoothed lines vtkIdType pointHelperCnt = 0; MITK_INFO << "Smoothing fibers"; boost::progress_display disp(m_NumFibers); +#pragma omp parallel for for (int i=0; iGetCell(i); - int numPoints = cell->GetNumberOfPoints(); - vtkPoints* points = cell->GetPoints(); - vtkSmartPointer newPoints = vtkSmartPointer::New(); - for (int j=0; jInsertNextPoint(points->GetPoint(j)); + float length = 0; +#pragma omp critical + { + length = m_FiberLengths.at(i); + ++disp; + vtkCell* cell = m_FiberPolyData->GetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + for (int j=0; jInsertNextPoint(points->GetPoint(j)); + } - float length = m_FiberLengths.at(i); int sampling = std::ceil(length/pointDistance); vtkSmartPointer xSpline = vtkSmartPointer::New(); vtkSmartPointer ySpline = vtkSmartPointer::New(); vtkSmartPointer zSpline = vtkSmartPointer::New(); xSpline->SetDefaultBias(bias); xSpline->SetDefaultTension(tension); xSpline->SetDefaultContinuity(continuity); ySpline->SetDefaultBias(bias); ySpline->SetDefaultTension(tension); ySpline->SetDefaultContinuity(continuity); zSpline->SetDefaultBias(bias); zSpline->SetDefaultTension(tension); zSpline->SetDefaultContinuity(continuity); vtkSmartPointer spline = vtkSmartPointer::New(); spline->SetXSpline(xSpline); spline->SetYSpline(ySpline); spline->SetZSpline(zSpline); spline->SetPoints(newPoints); vtkSmartPointer functionSource = vtkSmartPointer::New(); functionSource->SetParametricFunction(spline); functionSource->SetUResolution(sampling); functionSource->SetVResolution(sampling); functionSource->SetWResolution(sampling); functionSource->Update(); vtkPolyData* outputFunction = functionSource->GetOutput(); vtkPoints* tmpSmoothPnts = outputFunction->GetPoints(); //smoothPoints of current fiber vtkSmartPointer smoothLine = vtkSmartPointer::New(); smoothLine->GetPointIds()->SetNumberOfIds(tmpSmoothPnts->GetNumberOfPoints()); - for (int j=0; jGetNumberOfPoints(); j++) +#pragma omp critical { - smoothLine->GetPointIds()->SetId(j, j+pointHelperCnt); - vtkSmoothPoints->InsertNextPoint(tmpSmoothPnts->GetPoint(j)); + for (int j=0; jGetNumberOfPoints(); j++) + { + smoothLine->GetPointIds()->SetId(j, j+pointHelperCnt); + vtkSmoothPoints->InsertNextPoint(tmpSmoothPnts->GetPoint(j)); + } + + vtkSmoothCells->InsertNextCell(smoothLine); + pointHelperCnt += tmpSmoothPnts->GetNumberOfPoints(); } - vtkSmoothCells->InsertNextCell(smoothLine); - pointHelperCnt += tmpSmoothPnts->GetNumberOfPoints(); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkSmoothPoints); m_FiberPolyData->SetLines(vtkSmoothCells); this->SetFiberPolyData(m_FiberPolyData, true); m_FiberSampling = 10/pointDistance; } void mitk::FiberBundle::ResampleSpline(float pointDistance) { ResampleSpline(pointDistance, 0, 0, 0 ); } unsigned long mitk::FiberBundle::GetNumberOfPoints() { unsigned long points = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); points += cell->GetNumberOfPoints(); } return points; } void mitk::FiberBundle::Compress(float error) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Compressing fibers"; unsigned long numRemovedPoints = 0; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); +#pragma omp parallel for for (int i=0; iGetNumberOfCells(); i++) { - ++disp; - vtkCell* cell = m_FiberPolyData->GetCell(i); - int numPoints = cell->GetNumberOfPoints(); - vtkPoints* points = cell->GetPoints(); + + std::vector< vnl_vector_fixed< double, 3 > > vertices; + +#pragma omp critical + { + ++disp; + vtkCell* cell = m_FiberPolyData->GetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + + for (int j=0; jGetPoint(j, cand); + vnl_vector_fixed< double, 3 > candV; + candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2]; + vertices.push_back(candV); + } + } // calculate curvatures + int numPoints = vertices.size(); std::vector< int > removedPoints; removedPoints.resize(numPoints, 0); removedPoints[0]=-1; removedPoints[numPoints-1]=-1; vtkSmartPointer container = vtkSmartPointer::New(); + int remCounter = 0; bool pointFound = true; while (pointFound) { pointFound = false; double minError = error; int removeIndex = -1; - for (int j=0; jGetPoint(j, cand); - vnl_vector_fixed< double, 3 > candV; - candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2]; + vnl_vector_fixed< double, 3 > candV = vertices.at(j); int validP = -1; vnl_vector_fixed< double, 3 > pred; for (int k=j-1; k>=0; k--) if (removedPoints[k]<=0) { - double ref[3]; - points->GetPoint(k, ref); - pred[0]=ref[0]; pred[1]=ref[1]; pred[2]=ref[2]; + pred = vertices.at(k); validP = k; break; } int validS = -1; vnl_vector_fixed< double, 3 > succ; for (int k=j+1; kGetPoint(k, ref); - succ[0]=ref[0]; succ[1]=ref[1]; succ[2]=ref[2]; + succ = vertices.at(k); validS = k; break; } if (validP>=0 && validS>=0) { double a = (candV-pred).magnitude(); double b = (candV-succ).magnitude(); double c = (pred-succ).magnitude(); double s=0.5*(a+b+c); double hc=(2.0/c)*sqrt(fabs(s*(s-a)*(s-b)*(s-c))); if (hcGetPoint(j, cand); - vtkIdType id = vtkNewPoints->InsertNextPoint(cand); - container->GetPointIds()->InsertNextId(id); +#pragma omp critical + { + vtkIdType id = vtkNewPoints->InsertNextPoint(vertices.at(j).data_block()); + container->GetPointIds()->InsertNextId(id); + } } } - vtkNewCells->InsertNextCell(container); +#pragma omp critical + { + numRemovedPoints += remCounter; + vtkNewCells->InsertNextCell(container); + } } if (vtkNewCells->GetNumberOfCells()>0) { MITK_INFO << "Removed points: " << numRemovedPoints; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } } // reapply selected colorcoding in case polydata structure has changed bool mitk::FiberBundle::Equals(mitk::FiberBundle* fib, double eps) { if (fib==nullptr) { MITK_INFO << "Reference bundle is NULL!"; return false; } if (m_NumFibers!=fib->GetNumFibers()) { MITK_INFO << "Unequal number of fibers!"; MITK_INFO << m_NumFibers << " vs. " << fib->GetNumFibers(); return false; } for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkCell* cell2 = fib->GetFiberPolyData()->GetCell(i); int numPoints2 = cell2->GetNumberOfPoints(); vtkPoints* points2 = cell2->GetPoints(); if (numPoints2!=numPoints) { MITK_INFO << "Unequal number of points in fiber " << i << "!"; MITK_INFO << numPoints2 << " vs. " << numPoints; return false; } for (int j=0; jGetPoint(j); double* p2 = points2->GetPoint(j); if (fabs(p1[0]-p2[0])>eps || fabs(p1[1]-p2[1])>eps || fabs(p1[2]-p2[2])>eps) { MITK_INFO << "Unequal points in fiber " << i << " at position " << j << "!"; MITK_INFO << "p1: " << p1[0] << ", " << p1[1] << ", " << p1[2]; MITK_INFO << "p2: " << p2[0] << ", " << p2[1] << ", " << p2[2]; return false; } } } return true; } /* ESSENTIAL IMPLEMENTATION OF SUPERCLASS METHODS */ void mitk::FiberBundle::UpdateOutputInformation() { } void mitk::FiberBundle::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::FiberBundle::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::FiberBundle::VerifyRequestedRegion() { return true; } void mitk::FiberBundle::SetRequestedRegion(const itk::DataObject* ) { } diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h index 2df33a97ee..c6e7054718 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h @@ -1,177 +1,177 @@ /*=================================================================== 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 _MITK_FiberBundle_H #define _MITK_FiberBundle_H //includes for MITK datastructure #include #include #include #include #include #include #include //includes storing fiberdata #include #include #include #include #include #include namespace mitk { /** * \brief Base Class for Fiber Bundles; */ class MITKFIBERTRACKING_EXPORT FiberBundle : public BaseData { public: typedef itk::Image ItkUcharImgType; // fiber colorcodings static const char* FIBER_ID_ARRAY; virtual void UpdateOutputInformation() override; virtual void SetRequestedRegionToLargestPossibleRegion() override; virtual bool RequestedRegionIsOutsideOfTheBufferedRegion() override; virtual bool VerifyRequestedRegion() override; virtual void SetRequestedRegion(const itk::DataObject*) override; mitkClassMacro( FiberBundle, BaseData ) itkFactorylessNewMacro(Self) itkCloneMacro(Self) mitkNewMacro1Param(Self, vtkSmartPointer) // custom constructor // colorcoding related methods void ColorFibersByCurvature(bool minMaxNorm=true); void ColorFibersByScalarMap(mitk::Image::Pointer, bool opacity); template void ColorFibersByScalarMap(const mitk::PixelType pixelType, mitk::Image::Pointer, bool opacity); void ColorFibersByOrientation(); void SetFiberOpacity(vtkDoubleArray *FAValArray); void ResetFiberOpacity(); void SetFiberColors(vtkSmartPointer fiberColors); void SetFiberColors(float r, float g, float b, float alpha=255); vtkSmartPointer GetFiberColors() const { return m_FiberColors; } // fiber compression void Compress(float error = 0.0); // fiber resampling void ResampleSpline(float pointDistance=1); void ResampleSpline(float pointDistance, double tension, double continuity, double bias ); bool RemoveShortFibers(float lengthInMM); bool RemoveLongFibers(float lengthInMM); bool ApplyCurvatureThreshold(float minRadius, bool deleteFibers); void MirrorFibers(unsigned int axis); void RotateAroundAxis(double x, double y, double z); void TranslateFibers(double x, double y, double z); void ScaleFibers(double x, double y, double z, bool subtractCenter=true); void TransformFibers(double rx, double ry, double rz, double tx, double ty, double tz); void RemoveDir(vnl_vector_fixed dir, double threshold); itk::Point TransformPoint(vnl_vector_fixed< double, 3 > point, double rx, double ry, double rz, double tx, double ty, double tz); itk::Matrix< double, 3, 3 > TransformMatrix(itk::Matrix< double, 3, 3 > m, double rx, double ry, double rz); // add/subtract fibers FiberBundle::Pointer AddBundle(FiberBundle* fib); FiberBundle::Pointer SubtractBundle(FiberBundle* fib); // fiber subset extraction FiberBundle::Pointer ExtractFiberSubset(DataNode *roi, DataStorage* storage); std::vector ExtractFiberIdSubset(DataNode* roi, DataStorage* storage); - FiberBundle::Pointer ExtractFiberSubset(ItkUcharImgType* mask, bool anyPoint, bool invert=false, bool bothEnds=true); + FiberBundle::Pointer ExtractFiberSubset(ItkUcharImgType* mask, bool anyPoint, bool invert=false, bool bothEnds=true, float fraction=0.0); FiberBundle::Pointer RemoveFibersOutside(ItkUcharImgType* mask, bool invert=false); vtkSmartPointer GeneratePolyDataByIds( std::vector ); // TODO: make protected void GenerateFiberIds(); // TODO: make protected // get/set data vtkSmartPointer GetFiberWeights() const { return m_FiberWeights; } float GetFiberWeight(unsigned int fiber); void SetFiberWeights(float newWeight); void SetFiberWeight(unsigned int fiber, float weight); void SetFiberWeights(vtkSmartPointer weights); void SetFiberPolyData(vtkSmartPointer, bool updateGeometry = true); vtkSmartPointer GetFiberPolyData() const; itkGetMacro( NumFibers, int) //itkGetMacro( FiberSampling, int) int GetNumFibers() const {return m_NumFibers;} itkGetMacro( MinFiberLength, float ) itkGetMacro( MaxFiberLength, float ) itkGetMacro( MeanFiberLength, float ) itkGetMacro( MedianFiberLength, float ) itkGetMacro( LengthStDev, float ) itkGetMacro( UpdateTime2D, itk::TimeStamp ) itkGetMacro( UpdateTime3D, itk::TimeStamp ) void RequestUpdate2D(){ m_UpdateTime2D.Modified(); } void RequestUpdate3D(){ m_UpdateTime3D.Modified(); } void RequestUpdate(){ m_UpdateTime2D.Modified(); m_UpdateTime3D.Modified(); } unsigned long GetNumberOfPoints(); // copy fiber bundle mitk::FiberBundle::Pointer GetDeepCopy(); // compare fiber bundles bool Equals(FiberBundle* fib, double eps=0.0001); itkSetMacro( ReferenceGeometry, mitk::BaseGeometry::Pointer ) itkGetConstMacro( ReferenceGeometry, mitk::BaseGeometry::Pointer ) protected: FiberBundle( vtkPolyData* fiberPolyData = nullptr ); virtual ~FiberBundle(); itk::Point GetItkPoint(double point[3]); // calculate geometry from fiber extent void UpdateFiberGeometry(); private: // actual fiber container vtkSmartPointer m_FiberPolyData; // contains fiber ids vtkSmartPointer m_FiberIdDataSet; int m_NumFibers; vtkSmartPointer m_FiberColors; vtkSmartPointer m_FiberWeights; std::vector< float > m_FiberLengths; float m_MinFiberLength; float m_MaxFiberLength; float m_MeanFiberLength; float m_MedianFiberLength; float m_LengthStDev; int m_FiberSampling; itk::TimeStamp m_UpdateTime2D; itk::TimeStamp m_UpdateTime3D; mitk::BaseGeometry::Pointer m_ReferenceGeometry; }; } // namespace mitk #endif /* _MITK_FiberBundle_H */ diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt b/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt index 354cfe3d2c..db310e0ecc 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt +++ b/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt @@ -1,18 +1,19 @@ 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) mitkAddCustomModuleTest(mitkStreamlineTrackingTest mitkStreamlineTrackingTest ${MITK_DATA_DIR}/DiffusionImaging/tensorImage.dti ${MITK_DATA_DIR}/DiffusionImaging/diffusionImageMask.nrrd ${MITK_DATA_DIR}/DiffusionImaging/streamlineTractogramInterpolated.fib) 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 ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/Signalgen.fib ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/params/param3 ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/params/param4 ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/params/param5 ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/params/param6 ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/params/param8) + +mitkAddCustomModuleTest(mitkFiberfoxSignalGenerationTest mitkFiberfoxSignalGenerationTest) mitkAddCustomModuleTest(mitkMachineLearningTrackingTest mitkMachineLearningTrackingTest) mitkAddCustomModuleTest(mitkFiberProcessingTest mitkFiberProcessingTest) ENDIF() diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberExtractionTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberExtractionTest.cpp index a9295023c1..a7c5c5a155 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberExtractionTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberExtractionTest.cpp @@ -1,121 +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 #include #include #include #include #include #include #include +#include /**Documentation * Test if fiber transfortaiom methods work correctly */ int mitkFiberExtractionTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkFiberExtractionTest"); /// \todo Fix VTK memory leaks. Bug 18097. vtkDebugLeaks::SetExitError(0); MITK_INFO << "argc: " << argc; MITK_TEST_CONDITION_REQUIRED(argc==13,"check for input data"); - try{ + omp_set_num_threads(1); + try{ mitk::FiberBundle::Pointer groundTruthFibs = dynamic_cast( mitk::IOUtil::Load(argv[1]).front().GetPointer() ); mitk::FiberBundle::Pointer testFibs = dynamic_cast( mitk::IOUtil::Load(argv[2]).front().GetPointer() ); // test planar figure based extraction mitk::DataNode::Pointer pf1 = mitk::IOUtil::LoadDataNode(argv[3]); mitk::DataNode::Pointer pf2 = mitk::IOUtil::LoadDataNode(argv[4]); mitk::DataNode::Pointer pf3 = mitk::IOUtil::LoadDataNode(argv[5]); mitk::StandaloneDataStorage::Pointer storage = mitk::StandaloneDataStorage::New(); mitk::PlanarFigureComposite::Pointer pfc2 = mitk::PlanarFigureComposite::New(); pfc2->setOperationType(mitk::PlanarFigureComposite::OR); mitk::DataNode::Pointer pfcNode2 = mitk::DataNode::New(); pfcNode2->SetData(pfc2); mitk::DataStorage::SetOfObjects::Pointer set2 = mitk::DataStorage::SetOfObjects::New(); set2->push_back(pfcNode2); mitk::PlanarFigureComposite::Pointer pfc1 = mitk::PlanarFigureComposite::New(); pfc1->setOperationType(mitk::PlanarFigureComposite::AND); mitk::DataNode::Pointer pfcNode1 = mitk::DataNode::New(); pfcNode1->SetData(pfc1); mitk::DataStorage::SetOfObjects::Pointer set1 = mitk::DataStorage::SetOfObjects::New(); set1->push_back(pfcNode1); storage->Add(pfcNode2); storage->Add(pf1, set2); storage->Add(pfcNode1, set2); storage->Add(pf2, set1); storage->Add(pf3, set1); MITK_INFO << "TEST1"; mitk::FiberBundle::Pointer extractedFibs = groundTruthFibs->ExtractFiberSubset(pfcNode2, storage); MITK_INFO << "TEST2"; MITK_TEST_CONDITION_REQUIRED(extractedFibs->Equals(testFibs),"check planar figure extraction"); MITK_INFO << "TEST3"; // test subtraction and addition mitk::FiberBundle::Pointer notExtractedFibs = groundTruthFibs->SubtractBundle(extractedFibs); MITK_INFO << argv[11]; testFibs = dynamic_cast(mitk::IOUtil::Load(argv[11]).front().GetPointer()); MITK_TEST_CONDITION_REQUIRED(notExtractedFibs->Equals(testFibs),"check bundle subtraction"); mitk::FiberBundle::Pointer joinded = extractedFibs->AddBundle(notExtractedFibs); testFibs = dynamic_cast(mitk::IOUtil::Load(argv[12]).front().GetPointer()); MITK_TEST_CONDITION_REQUIRED(joinded->Equals(testFibs),"check bundle addition"); // test binary image based extraction mitk::Image::Pointer mitkRoiImage = dynamic_cast(mitk::IOUtil::Load(argv[6]).front().GetPointer()); typedef itk::Image< unsigned char, 3 > itkUCharImageType; itkUCharImageType::Pointer itkRoiImage = itkUCharImageType::New(); mitk::CastToItkImage(mitkRoiImage, itkRoiImage); -// mitk::FiberBundle::Pointer inside = groundTruthFibs->RemoveFibersOutside(itkRoiImage, false); -// mitk::IOUtil::SaveBaseData(inside, mitk::IOUtil::GetTempPath()+"inside.fib"); -// mitk::FiberBundle::Pointer outside = groundTruthFibs->RemoveFibersOutside(itkRoiImage, true); -// mitk::IOUtil::SaveBaseData(outside, mitk::IOUtil::GetTempPath()+"outside.fib"); + // mitk::FiberBundle::Pointer inside = groundTruthFibs->RemoveFibersOutside(itkRoiImage, false); + // mitk::IOUtil::SaveBaseData(inside, mitk::IOUtil::GetTempPath()+"inside.fib"); + // mitk::FiberBundle::Pointer outside = groundTruthFibs->RemoveFibersOutside(itkRoiImage, true); + // mitk::IOUtil::SaveBaseData(outside, mitk::IOUtil::GetTempPath()+"outside.fib"); mitk::FiberBundle::Pointer passing = groundTruthFibs->ExtractFiberSubset(itkRoiImage, true); -// mitk::IOUtil::SaveBaseData(passing, mitk::IOUtil::GetTempPath()+"passing.fib"); + mitk::IOUtil::SaveBaseData(passing, mitk::IOUtil::GetTempPath()+"passing.fib"); mitk::FiberBundle::Pointer ending = groundTruthFibs->ExtractFiberSubset(itkRoiImage, false); -// mitk::IOUtil::SaveBaseData(ending, mitk::IOUtil::GetTempPath()+"ending.fib"); + // mitk::IOUtil::SaveBaseData(ending, mitk::IOUtil::GetTempPath()+"ending.fib"); -// testFibs = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[7])->GetData()); -// MITK_TEST_CONDITION_REQUIRED(inside->Equals(testFibs),"check inside mask extraction") + // testFibs = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[7])->GetData()); + // MITK_TEST_CONDITION_REQUIRED(inside->Equals(testFibs),"check inside mask extraction") -// testFibs = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[8])->GetData()); -// MITK_TEST_CONDITION_REQUIRED(outside->Equals(testFibs),"check outside mask extraction") + // testFibs = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[8])->GetData()); + // MITK_TEST_CONDITION_REQUIRED(outside->Equals(testFibs),"check outside mask extraction") testFibs = dynamic_cast(mitk::IOUtil::Load(argv[9]).front().GetPointer()); MITK_TEST_CONDITION_REQUIRED(passing->Equals(testFibs),"check passing mask extraction"); testFibs = dynamic_cast(mitk::IOUtil::Load(argv[10]).front().GetPointer()); MITK_TEST_CONDITION_REQUIRED(ending->Equals(testFibs),"check ending in mask extraction"); } catch(...) { return EXIT_FAILURE; } // always end with this! MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberGenerationTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberGenerationTest.cpp index c4f2d01f28..56892c43d7 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberGenerationTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberGenerationTest.cpp @@ -1,78 +1,80 @@ /*=================================================================== 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 /**Documentation * Test if fiber transfortaiom methods work correctly */ int mitkFiberGenerationTest(int argc, char* argv[]) { + omp_set_num_threads(1); MITK_TEST_BEGIN("mitkFiberGenerationTest"); MITK_TEST_CONDITION_REQUIRED(argc==6,"check for input data") try{ mitk::PlanarEllipse::Pointer pf1 = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[1])->GetData()); mitk::PlanarEllipse::Pointer pf2 = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[2])->GetData()); mitk::PlanarEllipse::Pointer pf3 = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[3])->GetData()); mitk::FiberBundle::Pointer uniform = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[4])->GetData()); mitk::FiberBundle::Pointer gaussian = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[5])->GetData()); FiberGenerationParameters parameters; vector< mitk::PlanarEllipse::Pointer > fid; fid.push_back(pf1); fid.push_back(pf2); fid.push_back(pf3); vector< unsigned int > flip; flip.push_back(0); flip.push_back(0); flip.push_back(0); parameters.m_Fiducials.push_back(fid); parameters.m_FlipList.push_back(flip); parameters.m_Density = 50; parameters.m_Tension = 0; parameters.m_Continuity = 0; parameters.m_Bias = 0; parameters.m_Sampling = 1; parameters.m_Variance = 0.1; // check uniform fiber distribution { itk::FibersFromPlanarFiguresFilter::Pointer filter = itk::FibersFromPlanarFiguresFilter::New(); parameters.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; filter->SetParameters(parameters); filter->Update(); vector< mitk::FiberBundle::Pointer > fiberBundles = filter->GetFiberBundles(); MITK_TEST_CONDITION_REQUIRED(uniform->Equals(fiberBundles.at(0)),"check uniform bundle") } // check gaussian fiber distribution { itk::FibersFromPlanarFiguresFilter::Pointer filter = itk::FibersFromPlanarFiguresFilter::New(); parameters.m_Distribution = FiberGenerationParameters::DISTRIBUTE_GAUSSIAN; filter->SetParameters(parameters); filter->SetParameters(parameters); filter->Update(); vector< mitk::FiberBundle::Pointer > fiberBundles = filter->GetFiberBundles(); MITK_TEST_CONDITION_REQUIRED(gaussian->Equals(fiberBundles.at(0)),"check gaussian bundle") } } catch(...) { return EXIT_FAILURE; } // always end with this! MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberProcessingTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberProcessingTest.cpp index 228e94d72c..5d6733898f 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberProcessingTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberProcessingTest.cpp @@ -1,288 +1,289 @@ /*=================================================================== 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 "mitkTestingMacros.h" #include #include #include #include #include #include - +#include #include "mitkTestFixture.h" class mitkFiberProcessingTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkFiberProcessingTestSuite); MITK_TEST(Test1); MITK_TEST(Test2); MITK_TEST(Test3); MITK_TEST(Test4); // MITK_TEST(Test5); - disabled as a temporary fix for bug 19770, should be fixed properly MITK_TEST(Test6); MITK_TEST(Test7); MITK_TEST(Test8); MITK_TEST(Test9); MITK_TEST(Test10); MITK_TEST(Test11); MITK_TEST(Test12); MITK_TEST(Test13); MITK_TEST(Test14); MITK_TEST(Test15); MITK_TEST(Test16); MITK_TEST(Test17); CPPUNIT_TEST_SUITE_END(); typedef itk::Image ItkUcharImgType; private: /** Members used inside the different (sub-)tests. All members are initialized via setUp().*/ mitk::FiberBundle::Pointer original; ItkUcharImgType::Pointer mask; public: void setUp() override { + omp_set_num_threads(1); original = NULL; original = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/original.fib")).front().GetPointer()); mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::LoadImage(GetTestDataFilePath("DiffusionImaging/FiberProcessing/MASK.nrrd")).GetPointer()); mask = ItkUcharImgType::New(); mitk::CastToItkImage(img, mask); } void tearDown() override { original = NULL; } void Test1() { MITK_INFO << "TEST 1: Remove by direction"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); vnl_vector_fixed dir; dir[0] = 0; dir[1] = 1; dir[2] = 0; fib->RemoveDir(dir,cos(5.0*M_PI/180)); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/remove_direction.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } void Test2() { MITK_INFO << "TEST 2: Remove by length"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); fib->RemoveShortFibers(30); fib->RemoveLongFibers(40); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/remove_length.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } void Test3() { MITK_INFO << "TEST 3: Remove by curvature 1"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); auto filter = itk::FiberCurvatureFilter::New(); filter->SetInputFiberBundle(fib); filter->SetAngularDeviation(30); filter->SetDistance(5); filter->SetRemoveFibers(false); filter->Update(); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/remove_curvature1.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(filter->GetOutputFiberBundle())); } void Test4() { MITK_INFO << "TEST 4: Remove by curvature 2"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); auto filter = itk::FiberCurvatureFilter::New(); filter->SetInputFiberBundle(fib); filter->SetAngularDeviation(30); filter->SetDistance(5); filter->SetRemoveFibers(true); filter->Update(); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/remove_curvature2.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(filter->GetOutputFiberBundle())); } void Test5() { MITK_INFO << "TEST 5: Remove outside mask"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); fib = fib->RemoveFibersOutside(mask); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/remove_outside.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } void Test6() { MITK_INFO << "TEST 6: Remove inside mask"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); fib = fib->RemoveFibersOutside(mask, true); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/remove_inside.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } void Test7() { MITK_INFO << "TEST 7: Modify resample"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); fib->ResampleSpline(5); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/modify_resample.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } void Test8() { MITK_INFO << "TEST 8: Modify compress"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); fib->Compress(0.1); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/modify_compress.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } void Test9() { MITK_INFO << "TEST 9: Modify sagittal mirror"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); fib->MirrorFibers(0); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/modify_sagittal_mirror.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } void Test10() { MITK_INFO << "TEST 10: Modify coronal mirror"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); fib->MirrorFibers(1); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/modify_coronal_mirror.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } void Test11() { MITK_INFO << "TEST 11: Modify axial mirror"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); fib->MirrorFibers(2); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/modify_axial_mirror.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } void Test12() { MITK_INFO << "TEST 12: Weight and join"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); fib->SetFiberWeights(0.1); mitk::FiberBundle::Pointer fib2 = original->GetDeepCopy(); fib2->SetFiberWeight(3, 0.5); fib = fib->AddBundle(fib2); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/modify_weighted_joined.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Number of fibers", ref->GetNumFibers() == fib->GetNumFibers()); for (int i=0; iGetNumFibers(); i++) CPPUNIT_ASSERT_MESSAGE("Fiber weights", ref->GetFiberWeight(i) == fib->GetFiberWeight(i)); } void Test13() { MITK_INFO << "TEST 13: Subtract"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); mitk::FiberBundle::Pointer fib2 = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/remove_length.fib")).front().GetPointer()); fib = fib->SubtractBundle(fib2); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/subtracted.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } void Test14() { MITK_INFO << "TEST 14: rotate"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); fib->TransformFibers(1,2,3,0,0,0); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/transform_rotate.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } void Test15() { MITK_INFO << "TEST 15: translate"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); fib->TransformFibers(0,0,0,1,2,3); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/transform_translate.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } void Test16() { MITK_INFO << "TEST 16: scale 1"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); fib->ScaleFibers(0.1, 0.2, 0.3); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/transform_scale1.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } void Test17() { MITK_INFO << "TEST 17: scale 2"; mitk::FiberBundle::Pointer fib = original->GetDeepCopy(); fib->ScaleFibers(0.1, 0.2, 0.3, false); mitk::FiberBundle::Pointer ref = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/FiberProcessing/transform_scale2.fib")).front().GetPointer()); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(fib)); } }; MITK_TEST_SUITE_REGISTRATION(mitkFiberProcessing) diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberTransformationTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberTransformationTest.cpp index 9e48b3c7f1..ddd1da724e 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberTransformationTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberTransformationTest.cpp @@ -1,53 +1,55 @@ /*=================================================================== 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 /**Documentation * Test if fiber transfortaiom methods work correctly */ int mitkFiberTransformationTest(int argc, char* argv[]) { + omp_set_num_threads(1); MITK_TEST_BEGIN("mitkFiberTransformationTest"); MITK_TEST_CONDITION_REQUIRED(argc==3,"check for input data") try{ mitk::FiberBundle::Pointer groundTruthFibs = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[1])->GetData()); mitk::FiberBundle::Pointer transformedFibs = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[2])->GetData()); groundTruthFibs->RotateAroundAxis(90, 45, 10); groundTruthFibs->TranslateFibers(2, 3, 5); groundTruthFibs->ScaleFibers(1, 0.1, 1.3); groundTruthFibs->RemoveLongFibers(150); groundTruthFibs->RemoveShortFibers(20); groundTruthFibs->ResampleSpline(1.0); groundTruthFibs->ApplyCurvatureThreshold(3.0, true); groundTruthFibs->MirrorFibers(0); groundTruthFibs->MirrorFibers(1); groundTruthFibs->MirrorFibers(2); MITK_TEST_CONDITION_REQUIRED(groundTruthFibs->Equals(transformedFibs),"check transformation") } catch(...) { return EXIT_FAILURE; } // always end with this! MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberfoxSignalGenerationTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberfoxSignalGenerationTest.cpp index 83d0c416ea..8556d2c9e7 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberfoxSignalGenerationTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberfoxSignalGenerationTest.cpp @@ -1,129 +1,188 @@ /*=================================================================== 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 -typedef itk::VectorImage< short, 3> ItkDwiType; -/**Documentation - * Test the Fiberfox simulation functions (fiberBundle -> diffusion weighted image) - */ -bool CompareDwi(itk::VectorImage< short, 3 >* dwi1, itk::VectorImage< short, 3 >* dwi2) +#include "mitkTestFixture.h" + +class mitkFiberfoxSignalGenerationTestSuite : public mitk::TestFixture { - typedef itk::VectorImage< short, 3 > DwiImageType; - try{ - itk::ImageRegionIterator< DwiImageType > it1(dwi1, dwi1->GetLargestPossibleRegion()); - itk::ImageRegionIterator< DwiImageType > it2(dwi2, dwi2->GetLargestPossibleRegion()); - while(!it1.IsAtEnd()) - { - if (it1.Get()!=it2.Get()) + + CPPUNIT_TEST_SUITE(mitkFiberfoxSignalGenerationTestSuite); + MITK_TEST(Test0); + MITK_TEST(Test1); + MITK_TEST(Test2); + MITK_TEST(Test3); + MITK_TEST(Test4); + CPPUNIT_TEST_SUITE_END(); + + typedef itk::VectorImage< short, 3> ItkDwiType; + +private: + +public: + + /** Members used inside the different (sub-)tests. All members are initialized via setUp().*/ + FiberBundle::Pointer m_FiberBundle; + std::vector< FiberfoxParameters > m_Parameters; + std::vector< mitk::Image::Pointer > m_RefImages; + + void setUp() override + { + m_FiberBundle = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/Fiberfox/Signalgen.fib"))[0].GetPointer()); + + FiberfoxParameters parameters0; + parameters0.LoadParameters(GetTestDataFilePath("DiffusionImaging/Fiberfox/params/param3.ffp")); + m_Parameters.push_back(parameters0); + m_RefImages.push_back(mitk::IOUtil::LoadImage(GetTestDataFilePath("DiffusionImaging/Fiberfox/params/param3.dwi"))); + + FiberfoxParameters parameters1; + parameters1.LoadParameters(GetTestDataFilePath("DiffusionImaging/Fiberfox/params/param4.ffp")); + m_Parameters.push_back(parameters1); + m_RefImages.push_back(mitk::IOUtil::LoadImage(GetTestDataFilePath("DiffusionImaging/Fiberfox/params/param4.dwi"))); + + FiberfoxParameters parameters2; + parameters2.LoadParameters(GetTestDataFilePath("DiffusionImaging/Fiberfox/params/param5.ffp")); + m_Parameters.push_back(parameters2); + m_RefImages.push_back(mitk::IOUtil::LoadImage(GetTestDataFilePath("DiffusionImaging/Fiberfox/params/param5.dwi"))); + + FiberfoxParameters parameters3; + parameters3.LoadParameters(GetTestDataFilePath("DiffusionImaging/Fiberfox/params/param6.ffp")); + m_Parameters.push_back(parameters3); + m_RefImages.push_back(mitk::IOUtil::LoadImage(GetTestDataFilePath("DiffusionImaging/Fiberfox/params/param6.dwi"))); + + FiberfoxParameters parameters4; + parameters4.LoadParameters(GetTestDataFilePath("DiffusionImaging/Fiberfox/params/param8.ffp")); + m_Parameters.push_back(parameters4); + m_RefImages.push_back(mitk::IOUtil::LoadImage(GetTestDataFilePath("DiffusionImaging/Fiberfox/params/param8.dwi"))); + } + + void tearDown() override + { + + } + + bool CompareDwi(itk::VectorImage< short, 3 >* dwi1, itk::VectorImage< short, 3 >* dwi2) + { + typedef itk::VectorImage< short, 3 > DwiImageType; + try{ + itk::ImageRegionIterator< DwiImageType > it1(dwi1, dwi1->GetLargestPossibleRegion()); + itk::ImageRegionIterator< DwiImageType > it2(dwi2, dwi2->GetLargestPossibleRegion()); + while(!it1.IsAtEnd()) { - MITK_INFO << it1.GetIndex() << ":" << it1.Get(); - MITK_INFO << it2.GetIndex() << ":" << it2.Get(); - return false; + if (it1.Get()!=it2.Get()) + { + MITK_INFO << it1.GetIndex() << ":" << it1.Get(); + MITK_INFO << it2.GetIndex() << ":" << it2.Get(); + return false; + } + ++it1; + ++it2; } - ++it1; - ++it2; } + catch(...) + { + return false; + } + return true; } - catch(...) - { - return false; - } - return true; -} -void StartSimulation(FiberfoxParameters parameters, FiberBundle::Pointer fiberBundle, mitk::Image::Pointer refImage, string message) -{ - itk::TractsToDWIImageFilter< short >::Pointer tractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); - tractsToDwiFilter->SetUseConstantRandSeed(true); - tractsToDwiFilter->SetParameters(parameters); - tractsToDwiFilter->SetFiberBundle(fiberBundle); - tractsToDwiFilter->Update(); + void StartSimulation(FiberfoxParameters parameters, mitk::Image::Pointer refImage) + { + itk::TractsToDWIImageFilter< short >::Pointer tractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); + tractsToDwiFilter->SetUseConstantRandSeed(true); + tractsToDwiFilter->SetParameters(parameters); + tractsToDwiFilter->SetFiberBundle(m_FiberBundle); + tractsToDwiFilter->Update(); - mitk::Image::Pointer testImage = mitk::GrabItkImageMemory( tractsToDwiFilter->GetOutput() ); - testImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() ) ); - testImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.m_Bvalue ) ); + mitk::Image::Pointer testImage = mitk::GrabItkImageMemory( tractsToDwiFilter->GetOutput() ); + testImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() ) ); + testImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.m_Bvalue ) ); - mitk::DiffusionPropertyHelper propertyHelper( testImage ); - propertyHelper.InitializeImage(); + mitk::DiffusionPropertyHelper propertyHelper( testImage ); + propertyHelper.InitializeImage(); - if (refImage.IsNotNull()) - { - if( static_cast( refImage->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer().IsNotNull() ) + if (refImage.IsNotNull()) { - ItkDwiType::Pointer itkTestImagePointer = ItkDwiType::New(); - mitk::CastToItkImage(testImage, itkTestImagePointer); - ItkDwiType::Pointer itkRefImagePointer = ItkDwiType::New(); - mitk::CastToItkImage(refImage, itkRefImagePointer); - - bool cond = CompareDwi(itkTestImagePointer, itkRefImagePointer); - if (!cond) + if( static_cast( refImage->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer().IsNotNull() ) { - MITK_INFO << "Saving test and rference image to " << mitk::IOUtil::GetTempPath(); - mitk::IOUtil::SaveBaseData(testImage, mitk::IOUtil::GetTempPath()+"testImage.dwi"); - mitk::IOUtil::SaveBaseData(refImage, mitk::IOUtil::GetTempPath()+"refImage.dwi"); + ItkDwiType::Pointer itkTestImagePointer = ItkDwiType::New(); + mitk::CastToItkImage(testImage, itkTestImagePointer); + ItkDwiType::Pointer itkRefImagePointer = ItkDwiType::New(); + mitk::CastToItkImage(refImage, itkRefImagePointer); + + bool cond = CompareDwi(itkTestImagePointer, itkRefImagePointer); + if (!cond) + { + MITK_INFO << "Saving test and rference image to " << mitk::IOUtil::GetTempPath(); + mitk::IOUtil::SaveBaseData(testImage, mitk::IOUtil::GetTempPath()+"testImage.dwi"); + mitk::IOUtil::SaveBaseData(refImage, mitk::IOUtil::GetTempPath()+"refImage.dwi"); + } + CPPUNIT_ASSERT_MESSAGE("Simulated images should be equal", cond); } - MITK_TEST_CONDITION_REQUIRED(cond, message); } } -} -int mitkFiberfoxSignalGenerationTest(int argc, char* argv[]) -{ - MITK_TEST_BEGIN("mitkFiberfoxSignalGenerationTest"); + void Test0() + { + StartSimulation(m_Parameters.at(0), m_RefImages.at(0)); + } - // input fiber bundle - FiberBundle::Pointer fiberBundle = dynamic_cast(mitk::IOUtil::Load(argv[1])[0].GetPointer()); + void Test1() + { + StartSimulation(m_Parameters.at(1), m_RefImages.at(1)); + } - for (int i=2; i parameters; - string file = argv[i]; - MITK_INFO << "Starting test: " << file; - parameters.LoadParameters(file+".ffp"); + StartSimulation(m_Parameters.at(2), m_RefImages.at(2)); + } - // Load reference diffusion weighted image - mitk::Image::Pointer mitkRef = dynamic_cast(mitk::IOUtil::LoadDataNode(file+".dwi")->GetData()); + void Test3() + { + StartSimulation(m_Parameters.at(3), m_RefImages.at(3)); + } - StartSimulation(parameters, fiberBundle, mitkRef, file); + void Test4() + { + StartSimulation(m_Parameters.at(4), m_RefImages.at(4)); } - // always end with this! - MITK_TEST_END(); -} +}; + +MITK_TEST_SUITE_REGISTRATION(mitkFiberfoxSignalGeneration) diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp index 13be13ddac..82504a682e 100755 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp @@ -1,163 +1,165 @@ /*=================================================================== 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::LoadDataNode(fibFile)->GetData()); // load reference directions ItkDirectionImageContainerType::Pointer referenceImageContainer = ItkDirectionImageContainerType::New(); for (unsigned int i=0; i(mitk::IOUtil::LoadDataNode(referenceImages.at(i))->GetData()); 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->SetMaxNumDirections(3); fOdfFilter->SetSizeThreshold(0.3); fOdfFilter->SetUseWorkingCopy(false); fOdfFilter->SetNumberOfThreads(1); fOdfFilter->Update(); ItkDirectionImageContainerType::Pointer directionImageContainer = fOdfFilter->GetDirectionImageContainer(); // 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() ); //mitk::IOUtil::SaveImage(mitkAngularErrorImage, "/local/mitk/release-binary/MITK-superbuild/CMakeExternals/Source/MITK-Data/DiffusionImaging/LDFP_ERROR_IMAGE.nrrd"); // 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::IOUtil::SaveImage(mitkAngularErrorImageIgnore, "/local/mitk/release-binary/MITK-superbuild/CMakeExternals/Source/MITK-Data/DiffusionImaging/LDFP_ERROR_IMAGE_IGNORE.nrrd"); mitk::Image::Pointer gtAngularErrorImageIgnore = dynamic_cast(mitk::IOUtil::LoadDataNode(LDFP_ERROR_IMAGE_IGNORE)->GetData()); mitk::Image::Pointer gtAngularErrorImage = dynamic_cast(mitk::IOUtil::LoadDataNode(LDFP_ERROR_IMAGE)->GetData()); mitk::Image::Pointer gtNumTestDirImage = dynamic_cast(mitk::IOUtil::LoadDataNode(LDFP_NUM_DIRECTIONS)->GetData()); // mitk::FiberBundle::Pointer refDirections = dynamic_cast(mitk::IOUtil::LoadDataNode(LDFP_VECTOR_FIELD)->GetData()); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(gtAngularErrorImageIgnore, mitkAngularErrorImageIgnore, 0.5, true), "Check if error images are equal (ignored missing directions)."); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(gtAngularErrorImage, mitkAngularErrorImage, 0.01, true), "Check if error images are equal."); // MITK_TEST_CONDITION_REQUIRED(testDirections->Equals(refDirections, 0.001), "Check if vector fields are equal."); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(gtNumTestDirImage, mitkNumDirImage, 0.1, true), "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/mitkMachineLearningTrackingTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkMachineLearningTrackingTest.cpp index 85d39d2c4e..de58325c45 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkMachineLearningTrackingTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkMachineLearningTrackingTest.cpp @@ -1,102 +1,103 @@ /*=================================================================== 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 "mitkTestingMacros.h" #include #include #include #include #include #include #include #include #include +#include #include "mitkTestFixture.h" class mitkMachineLearningTrackingTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkMachineLearningTrackingTestSuite); MITK_TEST(Track1); CPPUNIT_TEST_SUITE_END(); typedef itk::Image ItkUcharImgType; private: /** Members used inside the different (sub-)tests. All members are initialized via setUp().*/ mitk::FiberBundle::Pointer ref; - mitk::TrackingForestHandler<> tfh; + mitk::TrackingForestHandler<6, 100> tfh; mitk::Image::Pointer dwi; ItkUcharImgType::Pointer seed; public: void setUp() override { ref = NULL; std::vector fibInfile = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/MachineLearningTracking/ReferenceTracts.fib")); mitk::BaseData::Pointer baseData = fibInfile.at(0); ref = dynamic_cast(baseData.GetPointer()); dwi = dynamic_cast(mitk::IOUtil::LoadImage(GetTestDataFilePath("DiffusionImaging/MachineLearningTracking/DiffusionImage.dwi")).GetPointer()); mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::LoadImage(GetTestDataFilePath("DiffusionImaging/MachineLearningTracking/seed.nrrd")).GetPointer()); seed = ItkUcharImgType::New(); mitk::CastToItkImage(img, seed); tfh.LoadForest(GetTestDataFilePath("DiffusionImaging/MachineLearningTracking/forest.rf")); - tfh.AddRawData(dwi); + tfh.AddDwi(dwi); } void tearDown() override { ref = NULL; } void Track1() { - typedef itk::MLBSTrackingFilter<> TrackerType; + omp_set_num_threads(1); + typedef itk::MLBSTrackingFilter<6,100> TrackerType; TrackerType::Pointer tracker = TrackerType::New(); tracker->SetInput(0, mitk::DiffusionPropertyHelper::GetItkVectorImage(dwi)); tracker->SetDemoMode(false); tracker->SetSeedImage(seed); tracker->SetSeedsPerVoxel(1); tracker->SetStepSize(-1); tracker->SetMinTractLength(20); tracker->SetMaxTractLength(400); tracker->SetForestHandler(tfh); - tracker->SetNumberOfSamples(30); tracker->SetAposterioriCurvCheck(false); - tracker->SetRemoveWmEndFibers(false); tracker->SetAvoidStop(true); tracker->SetSamplingDistance(0.5); tracker->SetRandomSampling(false); tracker->Update(); vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); -// mitk::IOUtil::Save(outFib, mitk::IOUtil::GetTempPath()+"RefFib.fib"); + //MITK_INFO << mitk::IOUtil::GetTempPath() << "ReferenceTracts.fib"; + //mitk::IOUtil::Save(outFib, mitk::IOUtil::GetTempPath()+"ReferenceTracts.fib"); CPPUNIT_ASSERT_MESSAGE("Should be equal", ref->Equals(outFib)); } }; MITK_TEST_SUITE_REGISTRATION(mitkMachineLearningTracking) diff --git a/Modules/DiffusionImaging/MiniApps/CMakeLists.txt b/Modules/DiffusionImaging/MiniApps/CMakeLists.txt index 742c5e1dc4..f4ff7b8979 100755 --- a/Modules/DiffusionImaging/MiniApps/CMakeLists.txt +++ b/Modules/DiffusionImaging/MiniApps/CMakeLists.txt @@ -1,58 +1,59 @@ if(BUILD_DiffusionMiniApps OR MITK_BUILD_ALL_APPS) # needed include directories include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of diffusion miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( diffusionminiapps NetworkCreation^^MitkFiberTracking_MitkConnectomics NetworkStatistics^^MitkConnectomics Fiberfox^^MitkFiberTracking MultishellMethods^^MitkFiberTracking PeaksAngularError^^MitkFiberTracking PeakExtraction^^MitkFiberTracking FiberExtraction^^MitkFiberTracking FiberProcessing^^MitkFiberTracking FiberDirectionExtraction^^MitkFiberTracking LocalDirectionalFiberPlausibility^^MitkFiberTracking StreamlineTracking^^MitkFiberTracking GibbsTracking^^MitkFiberTracking TractometerMetrics^^MitkFiberTracking FileFormatConverter^^MitkFiberTracking DFTraining^^MitkFiberTracking DFTracking^^MitkFiberTracking + TractDensity^^MitkFiberTracking ) foreach(diffusionminiapp ${diffusionminiapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${diffusionminiapp}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitkFunctionCreateCommandLineApp( NAME ${appname} DEPENDS MitkCore MitkDiffusionCore ${dependencies_list} PACKAGE_DEPENDS ITK ) endforeach() # This mini app does not depend on mitkDiffusionImaging at all mitkFunctionCreateCommandLineApp( NAME Dicom2Nrrd DEPENDS MitkCore ${dependencies_list} ) if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/DiffusionImaging/MiniApps/DFTracking.cpp b/Modules/DiffusionImaging/MiniApps/DFTracking.cpp index ec79d8ad56..10a5f3e027 100755 --- a/Modules/DiffusionImaging/MiniApps/DFTracking.cpp +++ b/Modules/DiffusionImaging/MiniApps/DFTracking.cpp @@ -1,161 +1,241 @@ /*=================================================================== 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 #define _USE_MATH_DEFINES #include using namespace std; const int numOdfSamples = 200; typedef itk::Image< itk::Vector< float, numOdfSamples > , 3 > SampledShImageType; /*! \brief Perform machine learning based streamline tractography */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Machine Learning Based Streamline Tractography"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setDescription("Perform machine learning based streamline tractography"); parser.setContributor("MBI"); parser.setArgumentPrefix("--", "-"); parser.addArgument("image", "i", mitkCommandLineParser::String, "DWI:", "input diffusion-weighted image", us::Any(), false); + parser.addArgument("addfeatures", "a", mitkCommandLineParser::StringList, "Additional feature images:", "specify a list of float images that hold additional features (float)", us::Any()); parser.addArgument("forest", "f", mitkCommandLineParser::String, "Forest:", "input random forest (HDF5 file)", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output fiberbundle", us::Any(), false); parser.addArgument("stop", "st", mitkCommandLineParser::String, "Stop image:", "streamlines entering the binary mask will stop immediately", us::Any()); parser.addArgument("mask", "m", mitkCommandLineParser::String, "Mask image:", "restrict tractography with a binary mask image", us::Any()); parser.addArgument("seed", "s", mitkCommandLineParser::String, "Seed image:", "binary mask image defining seed voxels", us::Any()); + parser.addArgument("tissue", "t", mitkCommandLineParser::String, "Tissue type image:", "image with tissue type labels (WM=3, GM=1)", us::Any()); parser.addArgument("stepsize", "se", mitkCommandLineParser::Float, "Stepsize:", "stepsize (in voxels)", us::Any()); - parser.addArgument("samples", "ns", mitkCommandLineParser::Int, "Samples:", "number of neighborhood samples", us::Any()); parser.addArgument("samplingdist", "sd", mitkCommandLineParser::Float, "Sampling distance:", "distance of neighborhood sampling points (in voxels)", us::Any()); parser.addArgument("seeds", "nse", mitkCommandLineParser::Int, "Seeds per voxel:", "number of seed points per voxel", us::Any()); + parser.addArgument("seed_gm", "sgm", mitkCommandLineParser::Int, "Seed only GM:", "Seed only in gray matter (requires tissue type image -t)", us::Any()); + + parser.addArgument("stopvotes", "sv", mitkCommandLineParser::Int, "Use stop votes:", "use stop votes", us::Any()); + parser.addArgument("forward", "fs", mitkCommandLineParser::Int, "Use only forward samples:", "use only forward samples", us::Any()); + + parser.addArgument("shfeatures", "shf", mitkCommandLineParser::Int, "Use SH features:", "use SH features", us::Any()); + map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; string imageFile = us::any_cast(parsedArgs["image"]); string forestFile = us::any_cast(parsedArgs["forest"]); string outFile = us::any_cast(parsedArgs["out"]); + bool shfeatures = false; + if (parsedArgs.count("shfeatures")) + shfeatures = us::any_cast(parsedArgs["shfeatures"]); + + bool seed_gm = false; + if (parsedArgs.count("seed_gm")) + seed_gm = us::any_cast(parsedArgs["seed_gm"]); + + bool stopvotes = true; + if (parsedArgs.count("stopvotes")) + stopvotes = us::any_cast(parsedArgs["stopvotes"]); + + bool forward = true; + if (parsedArgs.count("forward")) + forward = us::any_cast(parsedArgs["forward"]); + string maskFile = ""; if (parsedArgs.count("mask")) maskFile = us::any_cast(parsedArgs["mask"]); string seedFile = ""; if (parsedArgs.count("seed")) seedFile = us::any_cast(parsedArgs["seed"]); string stopFile = ""; if (parsedArgs.count("stop")) stopFile = us::any_cast(parsedArgs["stop"]); + string tissueFile = ""; + if (parsedArgs.count("tissue")) + tissueFile = us::any_cast(parsedArgs["tissue"]); + float stepsize = -1; if (parsedArgs.count("stepsize")) stepsize = us::any_cast(parsedArgs["stepsize"]); float samplingdist = 0.25; if (parsedArgs.count("samplingdist")) samplingdist = us::any_cast(parsedArgs["samplingdist"]); - int samples = 30; - if (parsedArgs.count("samples")) - samples = us::any_cast(parsedArgs["samples"]); - int seeds = 1; if (parsedArgs.count("seeds")) seeds = us::any_cast(parsedArgs["seeds"]); + mitkCommandLineParser::StringContainerType addFeatFiles; + if (parsedArgs.count("addfeatures")) + addFeatFiles = us::any_cast(parsedArgs["addfeatures"]); + typedef itk::Image ItkUcharImgType; MITK_INFO << "loading diffusion-weighted image"; mitk::Image::Pointer dwi = dynamic_cast(mitk::IOUtil::LoadImage(imageFile).GetPointer()); ItkUcharImgType::Pointer mask; if (!maskFile.empty()) { MITK_INFO << "loading mask image"; mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::LoadImage(maskFile).GetPointer()); mask = ItkUcharImgType::New(); mitk::CastToItkImage(img, mask); } ItkUcharImgType::Pointer seed; if (!seedFile.empty()) { MITK_INFO << "loading seed image"; mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::LoadImage(seedFile).GetPointer()); seed = ItkUcharImgType::New(); mitk::CastToItkImage(img, seed); } ItkUcharImgType::Pointer stop; if (!stopFile.empty()) { MITK_INFO << "loading stop image"; mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::LoadImage(stopFile).GetPointer()); stop = ItkUcharImgType::New(); mitk::CastToItkImage(img, stop); } - mitk::TrackingForestHandler<> tfh; - tfh.LoadForest(forestFile); - tfh.AddRawData(dwi); - - typedef itk::MLBSTrackingFilter<> TrackerType; - TrackerType::Pointer tracker = TrackerType::New(); - tracker->SetInput(0, mitk::DiffusionPropertyHelper::GetItkVectorImage(dwi)); - tracker->SetMaskImage(mask); - tracker->SetSeedImage(seed); - tracker->SetStoppingRegions(stop); - tracker->SetSeedsPerVoxel(seeds); - tracker->SetStepSize(stepsize); - tracker->SetForestHandler(tfh); - tracker->SetSamplingDistance(samplingdist); - tracker->SetNumberOfSamples(samples); - //tracker->SetAvoidStop(false); - tracker->SetAposterioriCurvCheck(false); - tracker->SetRemoveWmEndFibers(false); - tracker->Update(); - vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); - mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); - - mitk::IOUtil::Save(outFib, outFile); + + ItkUcharImgType::Pointer tissue; + if (!tissueFile.empty()) + { + MITK_INFO << "loading tissue image"; + mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::LoadImage(tissueFile).GetPointer()); + tissue = ItkUcharImgType::New(); + mitk::CastToItkImage(img, tissue); + } + + MITK_INFO << "loading additional feature images"; + typedef itk::Image ItkFloatImgType; + std::vector< std::vector< ItkFloatImgType::Pointer > > addFeatImages; + addFeatImages.push_back(std::vector< ItkFloatImgType::Pointer >()); + for (auto file : addFeatFiles) + { + mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::LoadImage(file).GetPointer()); + ItkFloatImgType::Pointer itkimg = ItkFloatImgType::New(); + mitk::CastToItkImage(img, itkimg); + addFeatImages.at(0).push_back(itkimg); + } + + if (shfeatures) + { + mitk::TrackingForestHandler<6,28> tfh; + tfh.LoadForest(forestFile); + tfh.AddDwi(dwi); + tfh.SetAdditionalFeatureImages(addFeatImages); + typedef itk::MLBSTrackingFilter<6,28> TrackerType; + TrackerType::Pointer tracker = TrackerType::New(); + tracker->SetInput(0, mitk::DiffusionPropertyHelper::GetItkVectorImage(dwi)); + tracker->SetMaskImage(mask); + tracker->SetSeedImage(seed); + tracker->SetStoppingRegions(stop); + tracker->SetSeedsPerVoxel(seeds); + tracker->SetStepSize(stepsize); + tracker->SetForestHandler(tfh); + tracker->SetSamplingDistance(samplingdist); + tracker->SetUseStopVotes(stopvotes); + tracker->SetOnlyForwardSamples(forward); + tracker->SetAposterioriCurvCheck(false); + tracker->SetFourTTImage(tissue); + tracker->SetSeedOnlyGm(seed_gm); + tracker->Update(); + vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); + mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); + mitk::IOUtil::Save(outFib, outFile); + } + else + { + mitk::TrackingForestHandler<6,100> tfh; + tfh.LoadForest(forestFile); + tfh.AddDwi(dwi); + tfh.SetAdditionalFeatureImages(addFeatImages); + + typedef itk::MLBSTrackingFilter<6,100> TrackerType; + TrackerType::Pointer tracker = TrackerType::New(); + tracker->SetInput(0, mitk::DiffusionPropertyHelper::GetItkVectorImage(dwi)); + tracker->SetMaskImage(mask); + tracker->SetSeedImage(seed); + tracker->SetStoppingRegions(stop); + tracker->SetSeedsPerVoxel(seeds); + tracker->SetStepSize(stepsize); + tracker->SetForestHandler(tfh); + tracker->SetSamplingDistance(samplingdist); + tracker->SetUseStopVotes(stopvotes); + tracker->SetOnlyForwardSamples(forward); + tracker->SetAposterioriCurvCheck(false); + tracker->SetFourTTImage(tissue); + tracker->SetSeedOnlyGm(seed_gm); + tracker->Update(); + vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); + mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); + mitk::IOUtil::Save(outFib, outFile); + } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/MiniApps/DFTraining.cpp b/Modules/DiffusionImaging/MiniApps/DFTraining.cpp index 7ea6c1d8d2..149d6f55f0 100755 --- a/Modules/DiffusionImaging/MiniApps/DFTraining.cpp +++ b/Modules/DiffusionImaging/MiniApps/DFTraining.cpp @@ -1,156 +1,227 @@ /*=================================================================== 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 #include #include #define _USE_MATH_DEFINES #include using namespace std; /*! \brief Train random forest classifier for machine learning based streamline tractography */ int main(int argc, char* argv[]) { MITK_INFO << "DFTraining"; mitkCommandLineParser parser; parser.setTitle("Training for Machine Learning Based Streamline Tractography"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setDescription("Train random forest classifier for machine learning based streamline tractography"); parser.setContributor("MBI"); parser.setArgumentPrefix("--", "-"); parser.addArgument("images", "i", mitkCommandLineParser::StringList, "DWIs:", "input diffusion-weighted images", us::Any(), false); parser.addArgument("tractograms", "t", mitkCommandLineParser::StringList, "Tractograms:", "input training tractograms (.fib, vtk ascii file format)", us::Any(), false); parser.addArgument("forest", "f", mitkCommandLineParser::OutputFile, "Forest:", "output random forest (HDF5)", us::Any(), false); parser.addArgument("masks", "m", mitkCommandLineParser::StringList, "Masks:", "restrict trining using a binary mask image", us::Any()); parser.addArgument("wmmasks", "w", mitkCommandLineParser::StringList, "WM-Masks:", "if no binary white matter mask is specified, the envelope of the input tractogram is used", us::Any()); + parser.addArgument("volmod", "v", mitkCommandLineParser::StringList, "Volume modification images:", "specify a list of float images that modify the fiber density", us::Any()); + parser.addArgument("addfeatures", "a", mitkCommandLineParser::StringList, "Additional feature images:", "specify a list of float images that hold additional features (float)", us::Any()); parser.addArgument("stepsize", "s", mitkCommandLineParser::Float, "Stepsize:", "resampling parameter for the input tractogram in mm (determines number of white-matter samples)", us::Any()); parser.addArgument("gmsamples", "g", mitkCommandLineParser::Int, "Number of gray matter samples per voxel:", "Number of gray matter samples per voxel", us::Any()); parser.addArgument("numtrees", "n", mitkCommandLineParser::Int, "Number of trees:", "number of trees", us::Any()); parser.addArgument("max_tree_depth", "d", mitkCommandLineParser::Int, "Max. tree depth:", "maximum tree depth", us::Any()); parser.addArgument("sample_fraction", "sf", mitkCommandLineParser::Float, "Sample fraction:", "fraction of samples used per tree", us::Any()); + parser.addArgument("shfeatures", "shf", mitkCommandLineParser::Int, "Use SH features:", "use SH features", us::Any()); + parser.addArgument("max_wm_samples", "mws", mitkCommandLineParser::Int, "Max. num. WM samples:", "upper limit for the number of WM samples", us::Any()); + map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; + bool shfeatures = false; + if (parsedArgs.count("shfeatures")) + shfeatures = us::any_cast(parsedArgs["shfeatures"]); + mitkCommandLineParser::StringContainerType imageFiles = us::any_cast(parsedArgs["images"]); mitkCommandLineParser::StringContainerType wmMaskFiles; if (parsedArgs.count("wmmasks")) wmMaskFiles = us::any_cast(parsedArgs["wmmasks"]); + mitkCommandLineParser::StringContainerType volModFiles; + if (parsedArgs.count("volmod")) + volModFiles = us::any_cast(parsedArgs["volmod"]); + + mitkCommandLineParser::StringContainerType addFeatFiles; + if (parsedArgs.count("addfeatures")) + addFeatFiles = us::any_cast(parsedArgs["addfeatures"]); + mitkCommandLineParser::StringContainerType maskFiles; if (parsedArgs.count("masks")) maskFiles = us::any_cast(parsedArgs["masks"]); string forestFile = us::any_cast(parsedArgs["forest"]); mitkCommandLineParser::StringContainerType tractogramFiles; if (parsedArgs.count("tractograms")) tractogramFiles = us::any_cast(parsedArgs["tractograms"]); int numTrees = 50; if (parsedArgs.count("numtrees")) numTrees = us::any_cast(parsedArgs["numtrees"]); int gmsamples = -1; if (parsedArgs.count("gmsamples")) gmsamples = us::any_cast(parsedArgs["gmsamples"]); float stepsize = -1; if (parsedArgs.count("stepsize")) stepsize = us::any_cast(parsedArgs["stepsize"]); int max_tree_depth = 25; if (parsedArgs.count("max_tree_depth")) max_tree_depth = us::any_cast(parsedArgs["max_tree_depth"]); double sample_fraction = 0.6; if (parsedArgs.count("sample_fraction")) sample_fraction = us::any_cast(parsedArgs["sample_fraction"]); + int maxWmSamples = -1; + if (parsedArgs.count("max_wm_samples")) + maxWmSamples = us::any_cast(parsedArgs["max_wm_samples"]); + MITK_INFO << "loading diffusion-weighted images"; std::vector< mitk::Image::Pointer > rawData; for (auto imgFile : imageFiles) { mitk::Image::Pointer dwi = dynamic_cast(mitk::IOUtil::LoadImage(imgFile).GetPointer()); rawData.push_back(dwi); } + typedef itk::Image ItkFloatImgType; typedef itk::Image ItkUcharImgType; MITK_INFO << "loading mask images"; std::vector< ItkUcharImgType::Pointer > maskImageVector; for (auto maskFile : maskFiles) { mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::LoadImage(maskFile).GetPointer()); ItkUcharImgType::Pointer mask = ItkUcharImgType::New(); mitk::CastToItkImage(img, mask); maskImageVector.push_back(mask); } MITK_INFO << "loading white matter mask images"; std::vector< ItkUcharImgType::Pointer > wmMaskImageVector; for (auto wmFile : wmMaskFiles) { mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::LoadImage(wmFile).GetPointer()); ItkUcharImgType::Pointer wmmask = ItkUcharImgType::New(); mitk::CastToItkImage(img, wmmask); wmMaskImageVector.push_back(wmmask); } MITK_INFO << "loading tractograms"; std::vector< mitk::FiberBundle::Pointer > tractograms; for (auto tractFile : tractogramFiles) { mitk::FiberBundle::Pointer fib = dynamic_cast(mitk::IOUtil::Load(tractFile).at(0).GetPointer()); tractograms.push_back(fib); } - mitk::TrackingForestHandler<> forestHandler; - forestHandler.SetRawData(rawData); - forestHandler.SetMaskImages(maskImageVector); - forestHandler.SetWhiteMatterImages(wmMaskImageVector); - forestHandler.SetTractograms(tractograms); - forestHandler.SetNumTrees(numTrees); - forestHandler.SetMaxTreeDepth(max_tree_depth); - forestHandler.SetGrayMatterSamplesPerVoxel(gmsamples); - forestHandler.SetSampleFraction(sample_fraction); - forestHandler.SetStepSize(stepsize); - forestHandler.StartTraining(); - forestHandler.SaveForest(forestFile); + MITK_INFO << "loading white volume modification images"; + std::vector< ItkFloatImgType::Pointer > volumeModImages; + for (auto file : volModFiles) + { + mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::LoadImage(file).GetPointer()); + ItkFloatImgType::Pointer itkimg = ItkFloatImgType::New(); + mitk::CastToItkImage(img, itkimg); + volumeModImages.push_back(itkimg); + } + + MITK_INFO << "loading additional feature images"; + std::vector< std::vector< ItkFloatImgType::Pointer > > addFeatImages; + for (int i=0; i()); + + int c = 0; + for (auto file : addFeatFiles) + { + mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::LoadImage(file).GetPointer()); + ItkFloatImgType::Pointer itkimg = ItkFloatImgType::New(); + mitk::CastToItkImage(img, itkimg); + addFeatImages.at(c%addFeatImages.size()).push_back(itkimg); + c++; + } + + if (shfeatures) + { + mitk::TrackingForestHandler<6,28> forestHandler; + forestHandler.SetDwis(rawData); + forestHandler.SetMaskImages(maskImageVector); + forestHandler.SetWhiteMatterImages(wmMaskImageVector); + forestHandler.SetFiberVolumeModImages(volumeModImages); + forestHandler.SetAdditionalFeatureImages(addFeatImages); + forestHandler.SetTractograms(tractograms); + forestHandler.SetNumTrees(numTrees); + forestHandler.SetMaxTreeDepth(max_tree_depth); + forestHandler.SetGrayMatterSamplesPerVoxel(gmsamples); + forestHandler.SetSampleFraction(sample_fraction); + forestHandler.SetStepSize(stepsize); + forestHandler.SetMaxNumWmSamples(maxWmSamples); + forestHandler.StartTraining(); + forestHandler.SaveForest(forestFile); + } + else + { + mitk::TrackingForestHandler<6,100> forestHandler; + forestHandler.SetDwis(rawData); + forestHandler.SetMaskImages(maskImageVector); + forestHandler.SetWhiteMatterImages(wmMaskImageVector); + forestHandler.SetFiberVolumeModImages(volumeModImages); + forestHandler.SetAdditionalFeatureImages(addFeatImages); + forestHandler.SetTractograms(tractograms); + forestHandler.SetNumTrees(numTrees); + forestHandler.SetMaxTreeDepth(max_tree_depth); + forestHandler.SetGrayMatterSamplesPerVoxel(gmsamples); + forestHandler.SetSampleFraction(sample_fraction); + forestHandler.SetStepSize(stepsize); + forestHandler.SetMaxNumWmSamples(maxWmSamples); + forestHandler.StartTraining(); + forestHandler.SaveForest(forestFile); + } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/MiniApps/FiberDirectionExtraction.cpp b/Modules/DiffusionImaging/MiniApps/FiberDirectionExtraction.cpp index b285e54242..9bfe98e249 100755 --- a/Modules/DiffusionImaging/MiniApps/FiberDirectionExtraction.cpp +++ b/Modules/DiffusionImaging/MiniApps/FiberDirectionExtraction.cpp @@ -1,178 +1,185 @@ /*=================================================================== 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; parser.setTitle("Fiber Direction Extraction"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setDescription("Extract principal fiber directions from a tractogram"); parser.setContributor("MBI"); 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"); map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; string fibFile = us::any_cast(parsedArgs["input"]); 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 angularThreshold = 25; if (parsedArgs.count("athresh")) angularThreshold = us::any_cast(parsedArgs["athresh"]); string outRoot = us::any_cast(parsedArgs["out"]); 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"]); bool normalize = false; if (parsedArgs.count("normalize")) normalize = us::any_cast(parsedArgs["normalize"]); + std::string file_ending = ".nrrd"; + if (parsedArgs.count("file_ending")) + file_ending = us::any_cast(parsedArgs["file_ending"]); + + try { typedef itk::Image ItkUcharImgType; typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType; typedef itk::VectorContainer< unsigned int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::LoadDataNode(fibFile)->GetData()); // load/create mask image ItkUcharImgType::Pointer itkMaskImage = NULL; if (maskImage.compare("")!=0) { std::cout << "Using mask image"; itkMaskImage = ItkUcharImgType::New(); mitk::Image::Pointer mitkMaskImage = dynamic_cast(mitk::IOUtil::LoadDataNode(maskImage)->GetData()); 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(); ItkDirectionImageContainerType::Pointer directionImageContainer = fOdfFilter->GetDirectionImageContainer(); // write direction images for (unsigned int i=0; iSize(); i++) { itk::TractsToVectorImageFilter::ItkDirectionImageType::Pointer itkImg = directionImageContainer->GetElement(i); typedef itk::ImageFileWriter< itk::TractsToVectorImageFilter::ItkDirectionImageType > WriterType; WriterType::Pointer writer = WriterType::New(); string outfilename = outRoot; - outfilename.append("_DIRECTION_"); + outfilename.append("_direction_"); outfilename.append(boost::lexical_cast(i)); - outfilename.append(".nrrd"); + 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"); + outfilename.append("_vectorfield.fib"); mitk::IOUtil::SaveBaseData(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.nrrd"); + outfilename.append("_numdirections"); + outfilename.append(file_ending); writer->SetFileName(outfilename.c_str()); writer->SetInput(numDirImage); writer->Update(); } } } 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/MiniApps/FiberProcessing.cpp b/Modules/DiffusionImaging/MiniApps/FiberProcessing.cpp index 658d753b41..c431ab571f 100644 --- a/Modules/DiffusionImaging/MiniApps/FiberProcessing.cpp +++ b/Modules/DiffusionImaging/MiniApps/FiberProcessing.cpp @@ -1,215 +1,220 @@ /*=================================================================== 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 "mitkCommandLineParser.h" #include #include #include #include mitk::FiberBundle::Pointer LoadFib(std::string filename) { std::vector fibInfile = mitk::IOUtil::Load(filename); if( fibInfile.empty() ) std::cout << "File " << filename << " could not be read!"; mitk::BaseData::Pointer baseData = fibInfile.at(0); return dynamic_cast(baseData.GetPointer()); } /*! \brief Modify input tractogram: fiber resampling, compression, pruning and transformation. */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Fiber Processing"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setDescription("Modify input tractogram: fiber resampling, compression, pruning and transformation."); parser.setContributor("MBI"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input fiber bundle (.fib)", us::Any(), false); parser.addArgument("outFile", "o", mitkCommandLineParser::OutputFile, "Output:", "output fiber bundle (.fib)", us::Any(), false); parser.addArgument("smooth", "s", mitkCommandLineParser::Float, "Spline resampling:", "Resample fiber using splines with the given point distance (in mm)"); parser.addArgument("compress", "c", mitkCommandLineParser::Float, "Compress:", "Compress fiber using the given error threshold (in mm)"); parser.addArgument("minLength", "l", mitkCommandLineParser::Float, "Minimum length:", "Minimum fiber length (in mm)"); parser.addArgument("maxLength", "m", mitkCommandLineParser::Float, "Maximum length:", "Maximum fiber length (in mm)"); parser.addArgument("maxAngle", "a", mitkCommandLineParser::Float, "Maximum angle:", "Maximum angular STDEV over 1cm (in degree)"); + parser.addArgument("remove", "rm", mitkCommandLineParser::Int, "Remove fibers exceeding curvature threshold:", "if 0, only the high curvature parts are removed"); parser.addArgument("mirror", "p", mitkCommandLineParser::Int, "Invert coordinates:", "Invert fiber coordinates XYZ (e.g. 010 to invert y-coordinate of each fiber point)"); - parser.addArgument("rotate-x", "rx", mitkCommandLineParser::Float, "Rotate x-axis:", "Rotate around x-axis (if copy is given the copy is rotated, in deg)"); - parser.addArgument("rotate-y", "ry", mitkCommandLineParser::Float, "Rotate y-axis:", "Rotate around y-axis (if copy is given the copy is rotated, in deg)"); - parser.addArgument("rotate-z", "rz", mitkCommandLineParser::Float, "Rotate z-axis:", "Rotate around z-axis (if copy is given the copy is rotated, in deg)"); + parser.addArgument("rotate-x", "rx", mitkCommandLineParser::Float, "Rotate x-axis:", "Rotate around x-axis (in deg)"); + parser.addArgument("rotate-y", "ry", mitkCommandLineParser::Float, "Rotate y-axis:", "Rotate around y-axis (in deg)"); + parser.addArgument("rotate-z", "rz", mitkCommandLineParser::Float, "Rotate z-axis:", "Rotate around z-axis (in deg)"); - parser.addArgument("scale-x", "sx", mitkCommandLineParser::Float, "Scale x-axis:", "Scale in direction of x-axis (if copy is given the copy is scaled)"); - parser.addArgument("scale-y", "sy", mitkCommandLineParser::Float, "Scale y-axis:", "Scale in direction of y-axis (if copy is given the copy is scaled)"); - parser.addArgument("scale-z", "sz", mitkCommandLineParser::Float, "Scale z-axis", "Scale in direction of z-axis (if copy is given the copy is scaled)"); + parser.addArgument("scale-x", "sx", mitkCommandLineParser::Float, "Scale x-axis:", "Scale in direction of x-axis"); + parser.addArgument("scale-y", "sy", mitkCommandLineParser::Float, "Scale y-axis:", "Scale in direction of y-axis"); + parser.addArgument("scale-z", "sz", mitkCommandLineParser::Float, "Scale z-axis", "Scale in direction of z-axis"); - parser.addArgument("translate-x", "tx", mitkCommandLineParser::Float, "Translate x-axis:", "Translate in direction of x-axis (if copy is given the copy is translated, in mm)"); - parser.addArgument("translate-y", "ty", mitkCommandLineParser::Float, "Translate y-axis:", "Translate in direction of y-axis (if copy is given the copy is translated, in mm)"); - parser.addArgument("translate-z", "tz", mitkCommandLineParser::Float, "Translate z-axis:", "Translate in direction of z-axis (if copy is given the copy is translated, in mm)"); + parser.addArgument("translate-x", "tx", mitkCommandLineParser::Float, "Translate x-axis:", "Translate in direction of x-axis (in mm)"); + parser.addArgument("translate-y", "ty", mitkCommandLineParser::Float, "Translate y-axis:", "Translate in direction of y-axis (in mm)"); + parser.addArgument("translate-z", "tz", mitkCommandLineParser::Float, "Translate z-axis:", "Translate in direction of z-axis (in mm)"); map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; + bool remove = true; + if (parsedArgs.count("remove")) + remove = us::any_cast(parsedArgs["remove"]); + float smoothDist = -1; if (parsedArgs.count("smooth")) smoothDist = us::any_cast(parsedArgs["smooth"]); float compress = -1; if (parsedArgs.count("compress")) compress = us::any_cast(parsedArgs["compress"]); float minFiberLength = -1; if (parsedArgs.count("minLength")) minFiberLength = us::any_cast(parsedArgs["minLength"]); float maxFiberLength = -1; if (parsedArgs.count("maxLength")) maxFiberLength = us::any_cast(parsedArgs["maxLength"]); float maxAngularDev = -1; if (parsedArgs.count("maxAngle")) maxAngularDev = us::any_cast(parsedArgs["maxAngle"]); int axis = 0; if (parsedArgs.count("mirror")) axis = us::any_cast(parsedArgs["mirror"]); float rotateX = 0; if (parsedArgs.count("rotate-x")) rotateX = us::any_cast(parsedArgs["rotate-x"]); float rotateY = 0; if (parsedArgs.count("rotate-y")) rotateY = us::any_cast(parsedArgs["rotate-y"]); float rotateZ = 0; if (parsedArgs.count("rotate-z")) rotateZ = us::any_cast(parsedArgs["rotate-z"]); float scaleX = 0; if (parsedArgs.count("scale-x")) scaleX = us::any_cast(parsedArgs["scale-x"]); float scaleY = 0; if (parsedArgs.count("scale-y")) scaleY = us::any_cast(parsedArgs["scale-y"]); float scaleZ = 0; if (parsedArgs.count("scale-z")) scaleZ = us::any_cast(parsedArgs["scale-z"]); float translateX = 0; if (parsedArgs.count("translate-x")) translateX = us::any_cast(parsedArgs["translate-x"]); float translateY = 0; if (parsedArgs.count("translate-y")) translateY = us::any_cast(parsedArgs["translate-y"]); float translateZ = 0; if (parsedArgs.count("translate-z")) translateZ = us::any_cast(parsedArgs["translate-z"]); string inFileName = us::any_cast(parsedArgs["input"]); string outFileName = us::any_cast(parsedArgs["outFile"]); try { mitk::FiberBundle::Pointer fib = LoadFib(inFileName); - if (minFiberLength>0) - fib->RemoveShortFibers(minFiberLength); - - if (maxFiberLength>0) - fib->RemoveLongFibers(maxFiberLength); - if (maxAngularDev>0) { auto filter = itk::FiberCurvatureFilter::New(); filter->SetInputFiberBundle(fib); filter->SetAngularDeviation(maxAngularDev); filter->SetDistance(10); - filter->SetRemoveFibers(true); + filter->SetRemoveFibers(remove); filter->Update(); fib = filter->GetOutputFiberBundle(); } + if (minFiberLength>0) + fib->RemoveShortFibers(minFiberLength); + + if (maxFiberLength>0) + fib->RemoveLongFibers(maxFiberLength); + if (smoothDist>0) fib->ResampleSpline(smoothDist); if (compress>0) fib->Compress(compress); if (axis/100==1) fib->MirrorFibers(0); if ((axis%100)/10==1) fib->MirrorFibers(1); if (axis%10==1) fib->MirrorFibers(2); if (rotateX > 0 || rotateY > 0 || rotateZ > 0){ std::cout << "Rotate " << rotateX << " " << rotateY << " " << rotateZ; fib->RotateAroundAxis(rotateX, rotateY, rotateZ); } if (translateX > 0 || translateY > 0 || translateZ > 0){ fib->TranslateFibers(translateX, translateY, translateZ); } if (scaleX > 0 || scaleY > 0 || scaleZ > 0) fib->ScaleFibers(scaleX, scaleY, scaleZ); mitk::IOUtil::SaveBaseData(fib.GetPointer(), outFileName ); } 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/MiniApps/TractDensity.cpp b/Modules/DiffusionImaging/MiniApps/TractDensity.cpp new file mode 100644 index 0000000000..581bb56fea --- /dev/null +++ b/Modules/DiffusionImaging/MiniApps/TractDensity.cpp @@ -0,0 +1,166 @@ +/*=================================================================== + +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 "mitkCommandLineParser.h" +#include +#include +#include +#include + + +mitk::FiberBundle::Pointer LoadFib(std::string filename) +{ + std::vector fibInfile = mitk::IOUtil::Load(filename); + if( fibInfile.empty() ) + std::cout << "File " << filename << " could not be read!"; + mitk::BaseData::Pointer baseData = fibInfile.at(0); + return dynamic_cast(baseData.GetPointer()); +} + +/*! +\brief Modify input tractogram: fiber resampling, compression, pruning and transformation. +*/ +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + + parser.setTitle("Tract Density"); + parser.setCategory("Fiber Tracking and Processing Methods"); + parser.setDescription("Generate tract density image or fiber envelope."); + parser.setContributor("MBI"); + + parser.setArgumentPrefix("--", "-"); + parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input fiber bundle (.fib)", us::Any(), false); + parser.addArgument("outFile", "o", mitkCommandLineParser::OutputFile, "Output:", "output image", us::Any(), false); + parser.addArgument("binary", "b", mitkCommandLineParser::Int, "Binary output:", "calculate binary tract envelope", us::Any()); + parser.addArgument("ref_image", "r", mitkCommandLineParser::StringList, "Reference image:", "output image will have geometry of this reference image", us::Any()); + + + std::map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + bool binary = false; + if (parsedArgs.count("binary")) + binary = us::any_cast(parsedArgs["binary"]); + + std::string ref_image = ""; + if (parsedArgs.count("ref_image")) + ref_image = us::any_cast(parsedArgs["ref_image"]); + + std::string inFileName = us::any_cast(parsedArgs["input"]); + std::string outFileName = us::any_cast(parsedArgs["outFile"]); + + try + { + mitk::FiberBundle::Pointer fib = LoadFib(inFileName); + + mitk::Image::Pointer ref_img; + if (!ref_image.empty()) + ref_img = dynamic_cast(mitk::IOUtil::LoadImage(ref_image).GetPointer()); + + 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(false); + generator->SetWorkOnFiberCopy(false); + + if (ref_img.IsNotNull()) + { + OutImageType::Pointer itkImage = OutImageType::New(); + CastToItkImage(ref_img, 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()); + + mitk::IOUtil::SaveBaseData(img, outFileName ); + } + 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(false); + generator->SetWorkOnFiberCopy(false); + + if (ref_img.IsNotNull()) + { + OutImageType::Pointer itkImage = OutImageType::New(); + CastToItkImage(ref_img, 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()); + + mitk::IOUtil::SaveBaseData(img, outFileName ); + } + + } + 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/ModuleList.cmake b/Modules/ModuleList.cmake index 6ee8f22a2b..b76d04f42e 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,83 +1,83 @@ # The entries in the mitk_modules list must be # ordered according to their dependencies. set(mitk_modules Core CommandLine AppUtil DCMTesting RDF LegacyIO DataTypesExt Annotation LegacyGL AlgorithmsExt MapperExt DICOMReader DICOMReaderServices DICOMTesting SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction LegacyAdaptors SceneSerialization Gizmo GraphAlgorithms Multilabel ImageStatistics ContourModel SurfaceInterpolation Segmentation PlanarFigureSegmentation OpenViewCore QtWidgets QtWidgetsExt C3js QmlItems SegmentationUI + Classification DiffusionImaging GPGPU OpenIGTLink IGTBase IGT CameraCalibration RigidRegistration RigidRegistrationUI DeformableRegistration DeformableRegistrationUI OpenCL OpenCVVideoSupport QtOverlays ToFHardware ToFProcessing ToFUI US USUI DicomUI Simulation Remeshing Python QtPython Persistence OpenIGTLinkUI IGTUI VtkShaders DicomRT RTUI IOExt XNAT TubeGraph BiophotonicsHardware - Classification TumorInvasionAnalysis MatchPointRegistration MatchPointRegistrationUI BoundingShape RenderWindowManager RenderWindowManagerUI ) if(MITK_ENABLE_PIC_READER) list(APPEND mitk_modules IpPicSupportIO) endif() diff --git a/Modules/TumorInvasionAnalysis/CMakeLists.txt b/Modules/TumorInvasionAnalysis/CMakeLists.txt index 1651e7b9d0..564099b74d 100644 --- a/Modules/TumorInvasionAnalysis/CMakeLists.txt +++ b/Modules/TumorInvasionAnalysis/CMakeLists.txt @@ -1,12 +1,12 @@ MITK_CREATE_MODULE( - INCLUDE_DIRS PRIVATE src/Classification src/ImageFilters - DEPENDS MitkCore MitkDiffusionCore MitkDataCollection MitkSegmentation MitkCLVigraRandomForest #<-- modules on which your module depends on - PACKAGE_DEPENDS PUBLIC ITK|ITKDiffusionTensorImage+ITKLevelSets + INCLUDE_DIRS PRIVATE src/Classification src/ImageFilters src/ReaderWriter + DEPENDS MitkCore MitkDiffusionCore MitkFiberTracking MitkDiffusionIO MitkDataCollection MitkSegmentation MitkCLVigraRandomForest #<-- modules on which your module depends + PACKAGE_DEPENDS PUBLIC ITK|ITKDiffusionTensorImage+ITKLevelSets Qt5|Core WARNINGS_AS_ERRORS ) -add_subdirectory(test) if (MODULE_IS_ENABLED) - ADD_SUBDIRECTORY(MiniApps) + add_subdirectory(test) + ADD_SUBDIRECTORY(MiniApps) endif() diff --git a/Modules/TumorInvasionAnalysis/MiniApps/TumorInvasionAnalysisTool.cpp b/Modules/TumorInvasionAnalysis/MiniApps/TumorInvasionAnalysisTool.cpp index d79009d471..e666ba8694 100644 --- a/Modules/TumorInvasionAnalysis/MiniApps/TumorInvasionAnalysisTool.cpp +++ b/Modules/TumorInvasionAnalysis/MiniApps/TumorInvasionAnalysisTool.cpp @@ -1,350 +1,350 @@ /*=================================================================== 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. ===================================================================*/ // MITK - DataCollection -#include -#include +#include +#include #include #include #include "mitkDataCollectionImageIterator.h" #include #include // CTK #include "mitkCommandLineParser.h" // ITK #include using namespace std; int main(int argc, char *argv[]) { // Setup CLI Module parsable interface mitkCommandLineParser parser; parser.setTitle("Tumor Invasion Analysis"); parser.setCategory("Tumor Analysis"); parser.setDescription("Learns and predicts Invasion behavior"); parser.setContributor("MBI"); parser.setArgumentPrefix("--", "-"); // Add command line argument names parser.addArgument("help", "h", mitkCommandLineParser::Bool, "Show options"); parser.addArgument("loadFile", "l", mitkCommandLineParser::InputFile, "DataCollection File"); parser.addArgument( "colIds", "c", mitkCommandLineParser::String, "Patient Identifiers from DataCollection used for training"); parser.addArgument( "testId", "t", mitkCommandLineParser::String, "Patient Identifier from DataCollection used for testing"); parser.addArgument("features", "b", mitkCommandLineParser::String, "Features"); parser.addArgument("stats", "s", mitkCommandLineParser::String, "Output file for stats"); parser.addArgument("ratio", "q", mitkCommandLineParser::Float, "ratio of tumor to healthy"); parser.addArgument("treeDepth", "d", mitkCommandLineParser::Int, "limits tree depth"); parser.addArgument("forestSize", "f", mitkCommandLineParser::Int, "number of trees"); parser.addArgument("samplingMode", "m", mitkCommandLineParser::Int, "mode of sample selection"); parser.addArgument("configName", "n", mitkCommandLineParser::String, "human readable name for configuration"); parser.addArgument("output", "o", mitkCommandLineParser::OutputDirectory, "output folder for results"); parser.addArgument("forest", "t", mitkCommandLineParser::OutputFile, "store trained forest to file"); map parsedArgs = parser.parseArguments(argc, argv); // Show a help message if (parsedArgs.size() == 0) return EXIT_SUCCESS; if (parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } // Default values float ratio = 1.0; bool useStatsFile = false; unsigned int forestSize = 250; unsigned int treeDepth = 0; unsigned int samplingMode = 1; std::string configName = ""; std::string outputFolder = ""; std::string forestFile = ""; std::vector features; std::vector trainingIds; std::vector testingIds; std::vector loadIds; // features + masks needed for training and evaluation std::string outputFile; std::string xmlFile; std::ofstream experimentFS; // Parse input parameters { if (parsedArgs.count("colIds") || parsedArgs.count("c")) { std::istringstream ss(us::any_cast(parsedArgs["colIds"])); std::string token; while (std::getline(ss, token, ',')) trainingIds.push_back(token); } if (parsedArgs.count("output") || parsedArgs.count("o")) { outputFolder = us::any_cast(parsedArgs["output"]); } if (parsedArgs.count("configName") || parsedArgs.count("n")) { configName = us::any_cast(parsedArgs["configName"]); } if (parsedArgs.count("features") || parsedArgs.count("b")) { std::istringstream ss(us::any_cast(parsedArgs["features"])); std::string token; while (std::getline(ss, token, ',')) features.push_back(token); } if (parsedArgs.count("treeDepth") || parsedArgs.count("d")) { treeDepth = us::any_cast(parsedArgs["treeDepth"]); } if (parsedArgs.count("ratio") || parsedArgs.count("q")) { ratio = us::any_cast(parsedArgs["ratio"]); } if (parsedArgs.count("forestSize") || parsedArgs.count("f")) { forestSize = us::any_cast(parsedArgs["forestSize"]); } if (parsedArgs.count("samplingMode") || parsedArgs.count("m")) { samplingMode = us::any_cast(parsedArgs["samplingMode"]); } if (parsedArgs.count("stats") || parsedArgs.count("s")) { useStatsFile = true; experimentFS.open(us::any_cast(parsedArgs["stats"]).c_str(), std::ios_base::app); } if (parsedArgs.count("forest") || parsedArgs.count("t")) { forestFile = us::any_cast(parsedArgs["stats"]); } if (parsedArgs.count("testId") || parsedArgs.count("t")) { std::istringstream ss(us::any_cast(parsedArgs["testId"])); std::string token; while (std::getline(ss, token, ',')) testingIds.push_back(token); } for (unsigned int i = 0; i < features.size(); i++) { loadIds.push_back(features.at(i)); } loadIds.push_back("GTV"); loadIds.push_back("BRAINMASK"); loadIds.push_back("TARGET"); if (parsedArgs.count("stats") || parsedArgs.count("s")) { outputFile = us::any_cast(parsedArgs["stats"]); } if (parsedArgs.count("loadFile") || parsedArgs.count("l")) { xmlFile = us::any_cast(parsedArgs["loadFile"]); } else { MITK_ERROR << parser.helpText(); return EXIT_FAILURE; } } mitk::DataCollection::Pointer trainCollection; mitk::DataCollection::Pointer testCollection; { - mitk::CollectionReader colReader; + mitk::DiffusionCollectionReader colReader; // Load only relevant images colReader.SetDataItemNames(loadIds); colReader.AddSubColIds(testingIds); testCollection = colReader.LoadCollection(xmlFile); colReader.ClearDataElementIds(); colReader.ClearSubColIds(); colReader.SetDataItemNames(loadIds); colReader.AddSubColIds(trainingIds); trainCollection = colReader.LoadCollection(xmlFile); } std::cout << "Setup Training" << std::endl; mitk::TumorInvasionClassification classifier; classifier.SetClassRatio(ratio); classifier.SetTrainMargin(7, 1); classifier.SamplesWeightingActivated(true); classifier.SelectTrainingSamples(trainCollection, samplingMode); // Learning stage std::cout << "Start Training" << std::endl; classifier.LearnProgressionFeatures(trainCollection, features, forestSize, treeDepth); if (forestFile != "") classifier.SaveRandomForest(forestFile); std::cout << "Start Predict" << std::endl; classifier.PredictInvasion(testCollection, features); if (false && outputFolder != "") { std::cout << "Saving files to " << outputFolder << std::endl; - mitk::CollectionWriter::ExportCollectionToFolder(trainCollection, "/tmp/dumple"); + mitk::DiffusionCollectionWriter::ExportCollectionToFolder(trainCollection, "/tmp/dumple"); } classifier.SanitizeResults(testCollection); { mitk::DataCollectionImageIterator gtvIt(testCollection, "GTV"); mitk::DataCollectionImageIterator result(testCollection, "RESULTOPEN"); while (!gtvIt.IsAtEnd()) { if (gtvIt.GetVoxel() != 0) { result.SetVoxel(2); } result++; gtvIt++; } } mitk::CollectionStatistic stat2; mitk::ProgressionValueToIndexMapper progressionValueToIndexMapper; mitk::BinaryValueToIndexMapper binaryValueToIndexMapper; stat2.SetCollection(testCollection); stat2.SetClassCount(2); stat2.SetGoldName("TARGET"); stat2.SetTestName("RESULTOPEN"); stat2.SetMaskName("BRAINMASK"); stat2.SetGroundTruthValueToIndexMapper(&binaryValueToIndexMapper); stat2.SetTestValueToIndexMapper(&progressionValueToIndexMapper); stat2.Update(); stat2.ComputeRMSD(); // FIXME: DICE value available after calling Print method std::ostringstream out2; stat2.Print(out2, std::cout, true); std::cout << std::endl << std::endl << out2.str() << std::endl; // Exclude GTV from Statistics by removing it from brain mask, // insert GTV as tumor region, since it is known before, in the result. { mitk::DataCollectionImageIterator gtvIt(testCollection, "GTV"); mitk::DataCollectionImageIterator brainMaskIter(testCollection, "BRAINMASK"); mitk::DataCollectionImageIterator result(testCollection, "RESULTOPEN"); while (!gtvIt.IsAtEnd()) { if (gtvIt.GetVoxel() != 0) { brainMaskIter.SetVoxel(0); result.SetVoxel(2); } result++; gtvIt++; brainMaskIter++; } } mitk::CollectionStatistic stat; stat.SetCollection(testCollection); stat.SetClassCount(2); stat.SetGoldName("TARGET"); stat.SetTestName("RESULTOPEN"); stat.SetMaskName("BRAINMASK"); stat.SetGroundTruthValueToIndexMapper(&binaryValueToIndexMapper); stat.SetTestValueToIndexMapper(&progressionValueToIndexMapper); stat.Update(); stat.ComputeRMSD(); // WARN: DICE value computed within Print method, so values are only available // after // calling Print() std::ostringstream out; stat.Print(out, std::cout, true); std::cout << std::endl << std::endl << out.str() << std::endl; // Statistics for original GTV excluded (Dice,Sensitivity) and for Gold // Standard vs prediction (RMSE) mitk::StatisticData statData = stat.GetStatisticData(1).at(0); mitk::StatisticData statData2 = stat2.GetStatisticData(1).at(0); std::cout << "Writing Stats to file" << std::endl; // one line output if (useStatsFile) { experimentFS << "Tree_Depth " << treeDepth << ','; experimentFS << "Forest_Size " << forestSize << ','; experimentFS << "Tumor/healthy_ratio " << ratio << ','; experimentFS << "Sample_Selection " << samplingMode << ','; experimentFS << "Trainined_on: " << ','; for (unsigned int i = 0; i < trainingIds.size(); i++) { experimentFS << trainingIds.at(i) << "/"; } experimentFS << ','; experimentFS << "Tested_on: " << ','; for (unsigned int i = 0; i < testingIds.size(); i++) { experimentFS << testingIds.at(i) << "/"; } experimentFS << ','; experimentFS << "Features_used: " << ','; if (configName == "") { for (unsigned int i = 0; i < features.size(); i++) { experimentFS << features.at(i) << "/"; } } else experimentFS << configName; experimentFS << ','; experimentFS << "---- STATS ---" << ','; experimentFS << " Sensitivity " << statData.m_Sensitivity << ','; experimentFS << " DICE " << statData.m_DICE << ','; experimentFS << " RMSE " << statData2.m_RMSD << ','; experimentFS << std::endl; } if (outputFolder != "") { std::cout << "Saving files to " << outputFolder << std::endl; - mitk::CollectionWriter::ExportCollectionToFolder(testCollection, outputFolder); + mitk::DiffusionCollectionWriter::ExportCollectionToFolder(testCollection, outputFolder); } return EXIT_SUCCESS; } diff --git a/Modules/TumorInvasionAnalysis/MiniApps/TumorResponseEvaluationTool.cpp b/Modules/TumorInvasionAnalysis/MiniApps/TumorResponseEvaluationTool.cpp index c9f5e6f640..6cb72895cf 100644 --- a/Modules/TumorInvasionAnalysis/MiniApps/TumorResponseEvaluationTool.cpp +++ b/Modules/TumorInvasionAnalysis/MiniApps/TumorResponseEvaluationTool.cpp @@ -1,266 +1,266 @@ /*=================================================================== 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. ===================================================================*/ // MITK - DataCollection -#include -#include +#include +#include #include #include #include "mitkDataCollectionImageIterator.h" #include #include // CTK #include "mitkCommandLineParser.h" // ITK #include using namespace std; int main(int argc, char *argv[]) { // Setup CLI Module parsable interface mitkCommandLineParser parser; parser.setTitle("Tumor Invasion Analysis"); parser.setCategory("Tumor Analysis"); parser.setDescription("Learns and predicts Invasion behavior"); parser.setContributor("MBI"); parser.setArgumentPrefix("--", "-"); // Add command line argument names parser.addArgument("help", "h", mitkCommandLineParser::Bool, "Show options"); parser.addArgument("loadFile", "l", mitkCommandLineParser::InputFile, "DataCollection File"); parser.addArgument( "colIds", "c", mitkCommandLineParser::String, "Patient Identifiers from DataCollection used for training"); parser.addArgument( "testId", "t", mitkCommandLineParser::String, "Patient Identifier from DataCollection used for testing"); parser.addArgument("features", "b", mitkCommandLineParser::String, "Features"); parser.addArgument("stats", "s", mitkCommandLineParser::String, "Output file for stats"); parser.addArgument("ratio", "q", mitkCommandLineParser::Float, "ratio of tumor to healthy"); parser.addArgument("treeDepth", "d", mitkCommandLineParser::Int, "limits tree depth"); parser.addArgument("forestSize", "f", mitkCommandLineParser::Int, "number of trees"); parser.addArgument("configName", "n", mitkCommandLineParser::String, "human readable name for configuration"); parser.addArgument("output", "o", mitkCommandLineParser::OutputDirectory, "output folder for results"); parser.addArgument("forest", "t", mitkCommandLineParser::OutputFile, "store trained forest to file"); map parsedArgs = parser.parseArguments(argc, argv); // Show a help message if (parsedArgs.size() == 0) return EXIT_SUCCESS; if (parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } // Default values float ratio = 1.0; bool useStatsFile = false; unsigned int forestSize = 250; unsigned int treeDepth = 0; std::string configName = ""; std::string outputFolder = ""; std::string forestFile = ""; std::vector features; std::vector trainingIds; std::vector testingIds; std::vector loadIds; // features + masks needed for training and evaluation std::string outputFile; std::string xmlFile; std::ofstream experimentFS; // Parse input parameters { if (parsedArgs.count("colIds") || parsedArgs.count("c")) { std::istringstream ss(us::any_cast(parsedArgs["colIds"])); std::string token; while (std::getline(ss, token, ',')) trainingIds.push_back(token); } if (parsedArgs.count("output") || parsedArgs.count("o")) { outputFolder = us::any_cast(parsedArgs["output"]); } if (parsedArgs.count("configName") || parsedArgs.count("n")) { configName = us::any_cast(parsedArgs["configName"]); } if (parsedArgs.count("features") || parsedArgs.count("b")) { std::istringstream ss(us::any_cast(parsedArgs["features"])); std::string token; while (std::getline(ss, token, ',')) features.push_back(token); } if (parsedArgs.count("treeDepth") || parsedArgs.count("d")) { treeDepth = us::any_cast(parsedArgs["treeDepth"]); } if (parsedArgs.count("ratio") || parsedArgs.count("q")) { ratio = us::any_cast(parsedArgs["ratio"]); } if (parsedArgs.count("forestSize") || parsedArgs.count("f")) { forestSize = us::any_cast(parsedArgs["forestSize"]); } if (parsedArgs.count("stats") || parsedArgs.count("s")) { useStatsFile = true; experimentFS.open(us::any_cast(parsedArgs["stats"]).c_str(), std::ios_base::app); } if (parsedArgs.count("forest") || parsedArgs.count("t")) { forestFile = us::any_cast(parsedArgs["stats"]); } if (parsedArgs.count("testId") || parsedArgs.count("t")) { std::istringstream ss(us::any_cast(parsedArgs["testId"])); std::string token; while (std::getline(ss, token, ',')) testingIds.push_back(token); } for (unsigned int i = 0; i < features.size(); i++) { loadIds.push_back(features.at(i)); } loadIds.push_back("GTV"); loadIds.push_back("BRAINMASK"); loadIds.push_back("TARGET"); if (parsedArgs.count("stats") || parsedArgs.count("s")) { outputFile = us::any_cast(parsedArgs["stats"]); } if (parsedArgs.count("loadFile") || parsedArgs.count("l")) { xmlFile = us::any_cast(parsedArgs["loadFile"]); } else { MITK_ERROR << parser.helpText(); return EXIT_FAILURE; } } mitk::DataCollection::Pointer trainCollection; mitk::DataCollection::Pointer testCollection; { - mitk::CollectionReader colReader; + mitk::DiffusionCollectionReader colReader; // Load only relevant images colReader.SetDataItemNames(loadIds); colReader.AddSubColIds(testingIds); testCollection = colReader.LoadCollection(xmlFile); colReader.ClearDataElementIds(); colReader.ClearSubColIds(); colReader.SetDataItemNames(loadIds); colReader.AddSubColIds(trainingIds); trainCollection = colReader.LoadCollection(xmlFile); } std::cout << "Setup Training" << std::endl; mitk::TumorInvasionClassification classifier; classifier.SetClassRatio(ratio); classifier.SamplesWeightingActivated(true); classifier.PrepareResponseSamples(trainCollection); // Learning stage std::cout << "Start Training" << std::endl; classifier.LearnProgressionFeatures(trainCollection, features, forestSize, treeDepth); if (forestFile != "") classifier.SaveRandomForest(forestFile); std::cout << "Start Predict" << std::endl; classifier.PredictInvasion(testCollection, features); if (outputFolder != "") { std::cout << "Saving files to " << outputFolder << std::endl; - mitk::CollectionWriter::ExportCollectionToFolder(trainCollection, "/tmp/dumple"); + mitk::DiffusionCollectionWriter::ExportCollectionToFolder(trainCollection, "/tmp/dumple"); } /* prepare target values to match training values: * 0 - excluded (e.g. out of brainmask) * 1 - no involvement (healthy all the time) * 2 - formerly healthy, now tumor (rezivid) * 3 - formerly tumor, now necroses (responsive) */ { mitk::DataCollectionImageIterator gtvIter(testCollection, "GTV"); mitk::DataCollectionImageIterator targetIt(testCollection, "TARGET"); while (!gtvIter.IsAtEnd()) { if (targetIt.GetVoxel() == 0 && gtvIter.GetVoxel() == 0) targetIt.SetVoxel(1); if (targetIt.GetVoxel() == 0 && gtvIter.GetVoxel() == 1) targetIt.SetVoxel(3); if (targetIt.GetVoxel() == 1 && gtvIter.GetVoxel() == 0) targetIt.SetVoxel(2); targetIt++; gtvIter++; } } mitk::CollectionStatistic stats; mitk::ProgressionValueToIndexMapper progressionValueToIndexMapper; mitk::BinaryValueToIndexMapper binaryValueToIndexMapper; stats.SetCollection(testCollection); stats.SetClassCount(4); stats.SetGoldName("TARGET"); stats.SetTestName("RESULT"); stats.SetMaskName("BRAINMASK"); stats.SetGroundTruthValueToIndexMapper(&binaryValueToIndexMapper); stats.SetTestValueToIndexMapper(&binaryValueToIndexMapper); stats.Update(); std::ostringstream outStr; stats.Print(outStr, std::cout, true); std::cout << std::endl << std::endl << outStr.str() << std::endl; if (useStatsFile) std::cout << "dummy" << std::endl; if (outputFolder != "") { std::cout << "Saving files to " << outputFolder << std::endl; - mitk::CollectionWriter::ExportCollectionToFolder(testCollection, outputFolder); + mitk::DiffusionCollectionWriter::ExportCollectionToFolder(testCollection, outputFolder); } return EXIT_SUCCESS; } diff --git a/Modules/TumorInvasionAnalysis/files.cmake b/Modules/TumorInvasionAnalysis/files.cmake index 5a3fd4f8ab..a757fcc18b 100644 --- a/Modules/TumorInvasionAnalysis/files.cmake +++ b/Modules/TumorInvasionAnalysis/files.cmake @@ -1,8 +1,9 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") SET(CPP_FILES + ReaderWriter/mitkDiffusionCollectionReader.cpp + ReaderWriter/mitkDiffusionCollectionWriter.cpp Classification/mitkTumorInvasionClassification.cpp ImageFilters/mitkCollectionDilatation.cpp ImageFilters/mitkCollectionGrayOpening.cpp ) - diff --git a/Modules/TumorInvasionAnalysis/include/mitkDiffusionCollectionReader.h b/Modules/TumorInvasionAnalysis/include/mitkDiffusionCollectionReader.h new file mode 100644 index 0000000000..1b29e1b0cc --- /dev/null +++ b/Modules/TumorInvasionAnalysis/include/mitkDiffusionCollectionReader.h @@ -0,0 +1,147 @@ +/*=================================================================== + +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 MITK_DIFFUSIONCOLLECTION_READER_H +#define MITK_DIFFUSIONCOLLECTION_READER_H + +#include "mitkCommon.h" +#include "mitkDataCollection.h" +#include + +// VTK +#include + +namespace mitk { + class MITKTUMORINVASIONANALYSIS_EXPORT DiffusionCollectionReader : public vtkXMLParser + { + public: + + typedef std::vector > FileListType; + + /** + * @brief Build up a mitk::DataCollection from a XML resource + * + **/ + DataCollection::Pointer LoadCollection(const std::string& xmlFileName); + + void AddDataElementIds(std::vector dataElemetIds); + void AddSubColIds(std::vector subColIds); + + void SetDataItemNames(std::vector itemNames); + + void ClearDataElementIds(); + void ClearSubColIds(); + + void Clear(); + + /** + * @brief Build up a mitk::DataCollection from a folder providing suffixes to group the files + * + **/ + static DataCollection::Pointer FolderToCollection(std::string folder, std::vector suffixes,std::vector seriesNames, bool allowGaps); + + /** + * @brief GenerateFileLists Returns a collection of lists with valid files names in a folder + * + * The first suffix entry in the vector is used for the reference images which are put in the first list, + * then the suffixes are interchanged and checked if the file exists; for each suffix a list is returned with filenames, + * if a file is expected but does not exist an empty string "" is added instead. + * + * @param folder + * @param suffixes + * @param allowGaps + * @return + */ + static FileListType GenerateFileLists(std::string folder, std::vector suffixes, bool allowGaps = false); + + /** + * @brief SanitizeFileList Removes all entries that are lacking at least one modality + * @param list - sanitized list + * @return + */ + + static FileListType SanitizeFileList(FileListType list); + + DiffusionCollectionReader(); + ~DiffusionCollectionReader(); + protected: + + /** + * @brief Derived from XMLReader + **/ + void StartElement (const char* elementName, const char **atts); + /** + * @brief Derived from XMLReader + **/ + void EndElement (const char* elementName); + + private: + /** + * @brief Derived from XMLReader + **/ + std::string ReadXMLStringAttribut( std::string name, const char** atts); + /** + * @brief Derived from XMLReader + **/ + bool ReadXMLBooleanAttribut( std::string name, const char** atts ); + /** + * @brief Derived from XMLReader + **/ + int ReadXMLIntegerAttribut( std::string name, const char** atts ); + + /** + * @brief m_DataCollection + * Stores a data collection during build of + */ + DataCollection::Pointer m_Collection; + DataCollection::Pointer m_SubCollection; + DataCollection::Pointer m_DataItemCollection; + + /** + * @brief m_SelectedIds + * + * Stores ids which are to be considered during loading, if this is provided all + * all data sets not matching an ID in this list are skipped. + */ + std::vector m_SelectedSubColIds; + + std::vector m_SelectedDataItemIds; + + /** + * @brief m_SelectedDataItemNames + * Lists names of items to be loaded, rest is ignored + */ + + std::vector m_SelectedDataItemNames; + + /** + * @brief m_Ignore + * + * Determines if current sub-collection is ignored + */ + bool m_ColIgnore; + bool m_ItemIgnore; + + /** + * @brief m_BaseDir + * + * Stores Base directory to allow XML links with relative paths + */ + std::string m_BaseDir; + }; +} // namespace mitk + +#endif /* MITK_COLLECTION_READER_H */ diff --git a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.h b/Modules/TumorInvasionAnalysis/include/mitkDiffusionCollectionWriter.h similarity index 90% copy from Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.h copy to Modules/TumorInvasionAnalysis/include/mitkDiffusionCollectionWriter.h index a366057d6e..1ea5345e12 100755 --- a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.h +++ b/Modules/TumorInvasionAnalysis/include/mitkDiffusionCollectionWriter.h @@ -1,81 +1,80 @@ /*=================================================================== 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 MITK_COLLECTION_WRITER_H -#define MITK_COLLECTION_WRITER_H +#ifndef MITK_DIFFUSIONCOLLECTION_WRITER_H +#define MITK_DIFFUSIONCOLLECTION_WRITER_H #include "mitkCommon.h" #include "mitkDataCollection.h" -#include "mitkCollectionReader.h" -#include +#include "mitkDiffusionCollectionReader.h" namespace mitk { - class MITKDATACOLLECTION_EXPORT CollectionWriter + class DiffusionCollectionWriter { public: typedef float TensorScalar; /** * @brief ExportCollectionToFolder * * Creates an XML file and stores all data in the same folder as the xml file (creating sub-folders for sub-collections) * * * Naming Conventions (Neccessary for proper saving of these images): * DWI - Diffusion Weighted Images * DTI - Diffusion Tensor Images * FIB - Fiber Bundles * * @param dataCollection * @param xmlFile * @param filter - (optional) only items with names contained in this list are written, if list is empty all items are written * @return */ static bool ExportCollectionToFolder(DataCollection* dataCollection, std::string xmlFile , std::vector filter); static bool ExportCollectionToFolder(DataCollection* dataCollection, std::string xmlFile); /** * @brief SaveCollection - Stores data collection at original location * * Writes the collection back to the files given in the original XML file. * New data items are stored into the default location, which is relative to the XML file. * * If a XML file is provided the files are stored as stated above with the differences that a new XML file is generated and new files are saved * relative to the newly generated xml. * * @param dataCollection * @param filter * @param xmlFile * @return */ static bool SaveCollection(DataCollection* dataCollection, std::vector filter, std::string xmlFile = ""); static bool FolderToXml(std::string folder, std::string collectionType, std::string xmlFile, std::vector filter, std::vector seriesNames); // GTV last entry in filter list, this item will be made to TARGET static bool SingleFolderToXml(std::string folder, std::string xmlFile, std::vector filter, std::vector seriesNames, bool longDate = true, int skipUntil = 0, float months = 0); protected: private: - static size_t GetIndexForinXMonths(CollectionReader::FileListType fileList, float months, size_t curIndex, std::vector filter); + static size_t GetIndexForinXMonths(DiffusionCollectionReader::FileListType fileList, float months, size_t curIndex, std::vector filter); }; } // namespace mitk #endif /* MITK_COLLECTION_WRITER_H */ diff --git a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionReader.cpp b/Modules/TumorInvasionAnalysis/src/ReaderWriter/mitkDiffusionCollectionReader.cpp similarity index 81% copy from Modules/Classification/DataCollection/ReaderWriter/mitkCollectionReader.cpp copy to Modules/TumorInvasionAnalysis/src/ReaderWriter/mitkDiffusionCollectionReader.cpp index 5b92ec8dd6..e0ce41bd21 100644 --- a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionReader.cpp +++ b/Modules/TumorInvasionAnalysis/src/ReaderWriter/mitkDiffusionCollectionReader.cpp @@ -1,423 +1,404 @@ /*=================================================================== 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. ===================================================================*/ #pragma warning (disable : 4996) -#include "mitkCollectionReader.h" +#include "mitkDiffusionCollectionReader.h" #include #include -#include #include #include #include //XML StateMachine Tags // Objects const std::string COLLECTION = "col"; const std::string SUBCOLLECTION = "subcol"; const std::string DATA = "data"; const std::string ITEM = "item"; // Properties const std::string NAME = "name"; const std::string ID = "id"; const std::string FILEPATH = "description"; const std::string LINK = "link"; static std::string GetName(std::string fileName,std::string suffix) { fileName = QFileInfo(QString::fromStdString(fileName)).fileName().toStdString(); return fileName.substr(0,fileName.length() -suffix.length()-9); // 8 = date length } static std::string GetDate(std::string fileName,std::string suffix) { fileName = QFileInfo(QString::fromStdString(fileName)).fileName().toStdString(); fileName = fileName.substr(fileName.length() - suffix.length()-8,8); // 8 = date length fileName.insert(6,"-"); fileName.insert(4,"-"); return fileName; } -mitk::CollectionReader::CollectionReader() +mitk::DiffusionCollectionReader::DiffusionCollectionReader() : m_Collection(NULL), m_SubCollection(NULL), m_DataItemCollection(NULL), m_ColIgnore(false), m_ItemIgnore(false) { } -mitk::CollectionReader::~CollectionReader() +mitk::DiffusionCollectionReader::~DiffusionCollectionReader() { this->Clear(); } /** * @brief Loads the xml file filename and generates the necessary instances. **/ -mitk::DataCollection::Pointer mitk::CollectionReader::LoadCollection(const std::string& xmlFileName) +mitk::DataCollection::Pointer mitk::DiffusionCollectionReader::LoadCollection(const std::string& xmlFileName) { QDir fileName = QFileInfo(xmlFileName.c_str()).absoluteDir(); m_BaseDir = fileName.path().toStdString() + QDir::separator().toLatin1(); this->SetFileName(xmlFileName.c_str()); this->Parse(); if (m_Collection.IsNotNull()) m_Collection->SetXMLFile(xmlFileName); return m_Collection; } -void mitk::CollectionReader::AddDataElementIds(std::vector dataElemetIds) +void mitk::DiffusionCollectionReader::AddDataElementIds(std::vector dataElemetIds) { m_SelectedDataItemIds.insert( m_SelectedDataItemIds.end(), dataElemetIds.begin(), dataElemetIds.end() ); } -void mitk::CollectionReader::AddSubColIds(std::vector subColIds) +void mitk::DiffusionCollectionReader::AddSubColIds(std::vector subColIds) { m_SelectedSubColIds.insert( m_SelectedSubColIds.end(), subColIds.begin(), subColIds.end() ); } -void mitk::CollectionReader::SetDataItemNames(std::vector itemNames) +void mitk::DiffusionCollectionReader::SetDataItemNames(std::vector itemNames) { m_SelectedDataItemNames = itemNames; } -void mitk::CollectionReader::ClearDataElementIds() +void mitk::DiffusionCollectionReader::ClearDataElementIds() { m_SelectedDataItemIds.clear(); } -void mitk::CollectionReader::ClearSubColIds() +void mitk::DiffusionCollectionReader::ClearSubColIds() { m_SelectedSubColIds.clear(); } -void mitk::CollectionReader::Clear() +void mitk::DiffusionCollectionReader::Clear() { m_DataItemCollection = NULL; m_SubCollection = NULL; m_Collection = NULL; } -mitk::DataCollection::Pointer mitk::CollectionReader::FolderToCollection(std::string folder, std::vector suffixes,std::vector seriesNames, bool allowGaps) +mitk::DataCollection::Pointer mitk::DiffusionCollectionReader::FolderToCollection(std::string folder, std::vector suffixes,std::vector seriesNames, bool allowGaps) { // Parse folder and look up all data, // after sanitation only fully available groups are included (that is all suffixes are found) FileListType fileList = SanitizeFileList(GenerateFileLists(folder, suffixes, allowGaps)); if (fileList.size() <= 0) return NULL; DataCollection::Pointer collection = DataCollection::New(); collection->SetName(GetName(fileList.at(0).at(0),suffixes.at(0))); for (unsigned int k=0; k < fileList.at(0).size(); ++k) // all groups have the same amount of items, so looking at 0 is ok. { DataCollection::Pointer subCollection = DataCollection::New(); for (unsigned int i=0; i< suffixes.size(); ++i) { std::string fileName = fileList.at(i).at(k); if (fileName.find(".fib") >= fileName.length()) { Image::Pointer image = IOUtil::LoadImage(fileList.at(i).at(k)); subCollection->AddData(image.GetPointer(),seriesNames.at(i), fileList.at(i).at(k)); } else { - const std::string s1="", s2=""; - - std::vector fiber_infile = mitk::BaseDataIO::LoadBaseDataFromFile( fileName, s1, s2, false ); - if( fiber_infile.empty() ) - { - MITK_INFO << "Fiber bundle could not be read " << fileName ; - } - mitk::BaseData* fiber_baseData = fiber_infile.at(0); - subCollection->AddData(fiber_baseData,seriesNames.at(i), fileList.at(i).at(k)); + subCollection->AddData(mitk::IOUtil::Load(fileName).at(0).GetPointer(),seriesNames.at(i), fileList.at(i).at(k)); } } std::string sDate = GetDate(fileList.at(0).at(k),suffixes.at(0)); collection->AddData(subCollection.GetPointer(),sDate,"--"); } return collection; } -void mitk::CollectionReader::StartElement(const char* elementName, const char **atts) +void mitk::DiffusionCollectionReader::StartElement(const char* elementName, const char **atts) { std::string name(elementName); if (name == COLLECTION) { m_Collection = DataCollection::New(); std::string colName = ReadXMLStringAttribut(NAME, atts); m_Collection->SetName(colName); } else if (name == SUBCOLLECTION) { m_ColIgnore = false; m_ItemIgnore = false; std::string subColName = ReadXMLStringAttribut(NAME, atts); std::string subColId = ReadXMLStringAttribut(ID, atts); if (m_SelectedSubColIds.size() > 0 && std::find(m_SelectedSubColIds.begin(), m_SelectedSubColIds.end(), subColId) == m_SelectedSubColIds.end() ) { // a) a selection list is provided AND b) the item is not in the list m_ColIgnore = true; return; } // Create subcollection m_SubCollection = DataCollection::New(); m_SubCollection->Init(subColName); } else if (name == DATA) { if (m_ColIgnore) return; std::string dataId = ReadXMLStringAttribut(ID, atts); if (m_SelectedDataItemIds.size() > 0 && std::find(m_SelectedDataItemIds.begin(), m_SelectedDataItemIds.end(), dataId) == m_SelectedDataItemIds.end() ) { // a) a selection list is provided AND b) the item is not in the list m_ItemIgnore = true; return; } m_ItemIgnore = false; std::string dataName = ReadXMLStringAttribut(NAME, atts); m_DataItemCollection = DataCollection::New(); m_DataItemCollection->Init(dataName); } else if (name == ITEM) { if (m_ColIgnore || m_ItemIgnore) return; std::string relativeItemLink = ReadXMLStringAttribut(LINK, atts); std::string itemLink = m_BaseDir + relativeItemLink; std::string itemName = ReadXMLStringAttribut(NAME, atts); // if item names are provided and name is not in list, do not load it if (m_SelectedDataItemNames.size() != 0 && std::find(m_SelectedDataItemNames.begin(), m_SelectedDataItemNames.end(), itemName) == m_SelectedDataItemNames.end() ) return; // Populate Sub-Collection if (itemLink.find(".fib") >= itemLink.length()) { Image::Pointer image = IOUtil::LoadImage(itemLink); if (image.IsNotNull()) m_DataItemCollection->AddData(image.GetPointer(),itemName,relativeItemLink); else MITK_ERROR << "File could not be loaded: " << itemLink << ". Wihtin Sub-Collection " << m_SubCollection->GetName() << ", within " << m_DataItemCollection->GetName() ; } else - { - const std::string s1="", s2=""; - - std::vector fiber_infile = mitk::BaseDataIO::LoadBaseDataFromFile( itemLink, s1, s2, false ); - if( fiber_infile.empty() ) - { - MITK_INFO << "Fiber bundle could not be read " << itemLink ; - } - mitk::BaseData* fiber_baseData = fiber_infile.at(0); - m_DataItemCollection->AddData(fiber_baseData,itemName, relativeItemLink); - } + m_DataItemCollection->AddData(mitk::IOUtil::Load(itemLink).at(0).GetPointer(),itemName, relativeItemLink); } else MITK_WARN<< "Malformed description ? -- unknown tag: " << name; } -void mitk::CollectionReader::EndElement(const char* elementName) +void mitk::DiffusionCollectionReader::EndElement(const char* elementName) { std::string name(elementName); if (name == SUBCOLLECTION) { if (m_SubCollection.IsNull()) return; if (m_ColIgnore || m_SubCollection->Size() == 0) return; m_Collection->AddData(m_SubCollection.GetPointer(),m_SubCollection->GetName()); m_SubCollection = DataCollection::New(); } if (name == DATA) { if (m_DataItemCollection.IsNull()) return; if (m_DataItemCollection->Size() == 0) return; m_SubCollection->AddData(m_DataItemCollection.GetPointer(),m_DataItemCollection->GetName()); m_DataItemCollection = DataCollection::New(); } } -std::string mitk::CollectionReader::ReadXMLStringAttribut(std::string name, const char** atts) +std::string mitk::DiffusionCollectionReader::ReadXMLStringAttribut(std::string name, const char** atts) { if (atts) { const char** attsIter = atts; while (*attsIter) { if (name == *attsIter) { attsIter++; return *attsIter; } attsIter++; attsIter++; } } return std::string(); } -bool mitk::CollectionReader::ReadXMLBooleanAttribut(std::string name, const char** atts) +bool mitk::DiffusionCollectionReader::ReadXMLBooleanAttribut(std::string name, const char** atts) { std::string s = ReadXMLStringAttribut(name, atts); std::transform(s.begin(), s.end(), s.begin(), ::toupper); if (s == "TRUE") return true; else return false; } -int mitk::CollectionReader::ReadXMLIntegerAttribut(std::string name, const char** atts) +int mitk::DiffusionCollectionReader::ReadXMLIntegerAttribut(std::string name, const char** atts) { std::string s = ReadXMLStringAttribut(name, atts); return atoi(s.c_str()); } -mitk::CollectionReader::FileListType mitk::CollectionReader::GenerateFileLists(std::string folder, std::vector suffixes, bool allowGaps) +mitk::DiffusionCollectionReader::FileListType mitk::DiffusionCollectionReader::GenerateFileLists(std::string folder, std::vector suffixes, bool allowGaps) { FileListType fileList; QString qFolder = QString::fromStdString(folder); if (!QFileInfo(qFolder).isDir()) { MITK_ERROR << "Folder does not exist."; return fileList; } // Add vector for each suffix for (unsigned int i=0; i< suffixes.size(); ++i) { std::vector list; fileList.push_back(list); } // if gaps are allowed, file names are build up from reference file (first suffix) // else all lists a file, file by file with regular sorting of the files, // if one suffix has more/less images than the others loading is aborted if (allowGaps) { QDir parseDir; parseDir.setFilter(QDir::Files); parseDir.setPath(qFolder); QStringList filterMorph; filterMorph << "*" + QString::fromStdString( suffixes.at(0) ); parseDir.setNameFilters( filterMorph ); QFileInfoList qFileList = parseDir.entryInfoList(); // now populate lists with files names, non-existing files will be marked with an empty string for (int i = 0; i < qFileList.size(); ++i) { std::string baseFileName = qFileList.at(i).absoluteFilePath().toStdString(); fileList.at(0).push_back( baseFileName ); //check for different suffixes for (unsigned int suffNo=1; suffNo < suffixes.size(); ++suffNo) { std::string derivedFileName = baseFileName.substr(0,baseFileName.length() -suffixes.at(0).length()) + suffixes.at(suffNo); // checking if file exists if (QFileInfo(QString::fromStdString(derivedFileName)).isFile()) fileList.at(suffNo).push_back(derivedFileName); else fileList.at(suffNo).push_back(""); } } } else { int numberOfFiles=-1; for (unsigned int i=0; i< suffixes.size(); ++i) { QDir parseDir; parseDir.setFilter(QDir::Files); parseDir.setPath(qFolder); QStringList filterMorph; filterMorph << "*" + QString::fromStdString( suffixes.at(i) ); parseDir.setNameFilters( filterMorph ); QFileInfoList qFileList = parseDir.entryInfoList(); if (numberOfFiles == -1) numberOfFiles = qFileList.size(); if (numberOfFiles != qFileList.size() ) { MITK_ERROR << "Series contain different number of images. Loading aborting."; fileList.clear(); break; } for (int fileNo=0; fileNo indexRemoval; // Parse through all items and check for empty strings, if one occurs mark this index // for removal. int modalities = list.size(); int timeSteps = list.at(0).size(); MITK_INFO << "Modalities " << modalities; MITK_INFO << "TimeSteps " << timeSteps; if (timeSteps == 0) MITK_ERROR << "No files found. Fatal."; for (int listIndex = 0 ; listIndex < timeSteps; listIndex++) { for (int modalityIndex = 0 ; modalityIndex < modalities; modalityIndex++) { if (list.at(modalityIndex).at(listIndex) == "") { MITK_INFO << "Marked Index " << listIndex << " for removal."; indexRemoval.push_back(listIndex); break; } } } for (int listIndex = indexRemoval.size()-1 ; listIndex >= 0; --listIndex) { for (int i = 0 ; i < modalities; i++) { list.at(i).erase(list.at(i).begin()+indexRemoval.at(listIndex)) ; } } MITK_INFO << "Time Steps after sanitizing: " << list.at(0).size(); return list; } diff --git a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.cpp b/Modules/TumorInvasionAnalysis/src/ReaderWriter/mitkDiffusionCollectionWriter.cpp similarity index 76% copy from Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.cpp copy to Modules/TumorInvasionAnalysis/src/ReaderWriter/mitkDiffusionCollectionWriter.cpp index 6c23a872a5..709534cbbc 100755 --- a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.cpp +++ b/Modules/TumorInvasionAnalysis/src/ReaderWriter/mitkDiffusionCollectionWriter.cpp @@ -1,508 +1,462 @@ /*=================================================================== 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. ===================================================================*/ #pragma warning (disable : 4996) -#include "mitkCollectionWriter.h" +#include "mitkDiffusionCollectionWriter.h" #include #include #include #include "mitkImageCast.h" #include "mitkTensorImage.h" #include "itkNrrdImageIO.h" #include "itkImageFileWriter.h" #include "mitkCoreObjectFactory.h" #include #include #include //XML StateMachine Tags // Objects const std::string COLLECTION = "col"; const std::string SUBCOLLECTION = "subcol"; const std::string DATA = "data"; const std::string ITEM = "item"; // Properties const std::string NAME = "name"; const std::string ID = "id"; const std::string FILEPATH = "filepath"; const std::string LINK = "link"; static std::string GetName(std::string fileName,std::string suffix, bool longName = false) { fileName = QFileInfo(QString::fromStdString(fileName)).fileName().toStdString(); if (longName) return fileName.substr(0,fileName.length() -suffix.length()-11); // 10 = date length else return fileName.substr(0,fileName.length() -suffix.length()-9); // 8 = date length } static std::string GetDate(std::string fileName,std::string suffix, bool longName = false) { fileName = QFileInfo(QString::fromStdString(fileName)).fileName().toStdString(); if (longName) fileName = fileName.substr(fileName.length() - suffix.length()-10,10); // 8 = date length else fileName = fileName.substr(fileName.length() - suffix.length()-8,8); // 8 = date length if (!longName) { fileName.insert(6,"-"); fileName.insert(4,"-"); } return fileName; } -bool mitk::CollectionWriter::ExportCollectionToFolder(DataCollection *dataCollection, std::string xmlFile, std::vector filter) +bool mitk::DiffusionCollectionWriter::ExportCollectionToFolder(DataCollection *dataCollection, std::string xmlFile, std::vector filter) { // Quick and Dirty: Assumes three level DataCollection QDir fileName = QFileInfo(xmlFile.c_str()).absoluteDir(); std::string outputFolder = fileName.path().toStdString() + QDir::separator().toLatin1(); QDir baseFolder(outputFolder.c_str()); baseFolder.mkpath(outputFolder.c_str()); std::ofstream xmlFileStream; xmlFileStream.open (xmlFile.c_str()); xmlFileStream << " \n"; xmlFileStream << "<" << COLLECTION << " " << NAME << "=\"" << dataCollection->GetName() << "\" >\n"; unsigned int subColId = 0; unsigned int dataId = 0; QDir dir(QString::fromStdString(outputFolder)); for (size_t i = 0 ; i < dataCollection->Size(); ++i) { // Write Subcollection tag xmlFileStream << " <" << SUBCOLLECTION << " " << NAME << "=\"" << dataCollection->IndexToName(i) << "\" " << FILEPATH << "=\"" << dataCollection->GetDataFilePath(i) << "\" id=\"Col" << subColId << "\" >\n"; // Create Sub-Folder dir.mkpath(QString::fromStdString(dataCollection->IndexToName(i))); // Herein create data folders DataCollection* subCollections = dynamic_cast (dataCollection->GetData(i).GetPointer()); if (subCollections == NULL) { - MITK_ERROR<< "mitk::CollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; + MITK_ERROR<< "mitk::DiffusionCollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; return false; } for (size_t d = 0; d < subCollections->Size(); d++ ) { // Create Sub Paths QString subPath = QString::fromStdString(dataCollection->IndexToName(i))+"/"+QString::fromStdString(subCollections->IndexToName(d)); dir.mkpath(subPath); xmlFileStream << " <" << DATA << " " << NAME << "=\"" << subCollections->IndexToName(d) << "\" " << FILEPATH << "=\"" << subCollections->GetDataFilePath(d) << "\" id=\"Data" << dataId << "\" >\n"; DataCollection* itemCollections = dynamic_cast (subCollections->GetData(d).GetPointer()); if (itemCollections == NULL) { - MITK_ERROR<< "mitk::CollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; + MITK_ERROR<< "mitk::DiffusionCollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; return false; } for (size_t s = 0; s < itemCollections->Size(); s++) { if (filter.size() > 0) { bool isSelected = false; for (size_t f = 0; f < filter.size(); f++) { if (filter.at(f) == itemCollections->IndexToName(s) ) { isSelected = true; break; } } if (isSelected == false) continue; } Image* image = dynamic_cast (itemCollections->GetData(s).GetPointer()); QString fileName = dir.path() + dir.separator() + subPath + dir.separator() + QString::fromStdString(dataCollection->IndexToName(i)) + "_" + QString::fromStdString(subCollections->IndexToName(d)) + "_" + QString::fromStdString(itemCollections->IndexToName(s)); try { if (itemCollections->IndexToName(s) == "DTI" || itemCollections->IndexToName(s) == "DTIFWE") { fileName += ".dti"; - itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); - io->SetFileType( itk::ImageIOBase::Binary ); - io->UseCompressionOn(); - TensorImage* tensorImage = dynamic_cast (image); - MITK_INFO << "Pixeltype Tensor Image: " << tensorImage->GetPixelType().GetPixelTypeAsString(); - typedef itk::Image,3> ImageType; - typedef itk::ImageFileWriter WriterType; - WriterType::Pointer nrrdWriter = WriterType::New(); - ImageType::Pointer outimage = ImageType::New(); - CastToItkImage(tensorImage, outimage); - nrrdWriter->SetInput( outimage ); - nrrdWriter->SetImageIO(io); - nrrdWriter->SetFileName(fileName.toStdString()); - nrrdWriter->UseCompressionOn(); - nrrdWriter->Update(); + IOUtil::Save(image,fileName.toStdString()); } else if (itemCollections->IndexToName(s) == "FIB") { fileName += ".fib"; FiberBundle* fib = dynamic_cast (itemCollections->GetData(s).GetPointer()); - CoreObjectFactory::FileWriterList fileWriters = CoreObjectFactory::GetInstance()->GetFileWriters(); - for (CoreObjectFactory::FileWriterList::iterator it = fileWriters.begin() ; it != fileWriters.end() ; ++it) - { - if ( (*it)->CanWriteBaseDataType(fib) ) { - (*it)->SetFileName( fileName.toStdString().c_str() ); - (*it)->DoWrite( fib ); - } - } + IOUtil::Save(fib, fileName.toStdString()); } else if (itemCollections->IndexToName(s) == "DWI") { fileName += ".dwi"; -// NrrdDiffusionImageWriter dwiwriter; -// dwiwriter.SetInput( dynamic_cast* > (image)); -// dwiwriter.SetOutputLocation( fileName.toStdString() ); - - IOUtil::SaveImage(image,fileName.toStdString()); + IOUtil::Save(image,fileName.toStdString()); } else { fileName += ".nrrd"; Image::Pointer image = itemCollections->GetMitkImage(s).GetPointer(); - IOUtil::SaveImage(image,fileName.toStdString()); + IOUtil::Save(image,fileName.toStdString()); } } catch( const std::exception& e) { MITK_ERROR << "Caught exception: " << e.what(); } std::string relativeFilename = baseFolder.relativeFilePath(fileName).toStdString(); xmlFileStream << " <" << ITEM << " " << NAME << "=\"" <IndexToName(s) << "\" " << FILEPATH << "=\"" << "\" " << LINK << "=\"" << relativeFilename << "\" />\n"; } xmlFileStream << " \n"; dataId++; } xmlFileStream << " \n"; subColId++; } xmlFileStream << "\n"; xmlFileStream.flush(); xmlFileStream.close(); return true; } -bool mitk::CollectionWriter::ExportCollectionToFolder(mitk::DataCollection *dataCollection, std::string xmlFile) +bool mitk::DiffusionCollectionWriter::ExportCollectionToFolder(mitk::DataCollection *dataCollection, std::string xmlFile) { std::vector mods; return ExportCollectionToFolder(dataCollection,xmlFile, mods); } -bool mitk::CollectionWriter::SaveCollection(mitk::DataCollection *dataCollection, std::vector filter, std::string xmlFile) +bool mitk::DiffusionCollectionWriter::SaveCollection(mitk::DataCollection *dataCollection, std::vector filter, std::string xmlFile) { QDir origFilename = QFileInfo(dataCollection->GetXMLFile().c_str()).absoluteDir(); QString originalFolder = origFilename.path() + QDir::separator(); if (xmlFile == "") xmlFile = dataCollection->GetXMLFile(); QDir fileName = QFileInfo(xmlFile.c_str()).absoluteDir(); std::string outputFolder = fileName.path().toStdString() + QDir::separator().toLatin1(); QDir baseFolder(outputFolder.c_str()); std::ofstream xmlFileStream; xmlFileStream.open (xmlFile.c_str()); xmlFileStream << " \n"; xmlFileStream << "<" << COLLECTION << " " << NAME << "=\"" << dataCollection->GetName() << "\" >\n"; unsigned int subColId = 0; unsigned int dataId = 0; QDir dir(QString::fromStdString(outputFolder)); for (size_t i = 0 ; i < dataCollection->Size(); ++i) { // Write Subcollection tag xmlFileStream << " <" << SUBCOLLECTION << " " << NAME << "=\"" << dataCollection->IndexToName(i) << "\" " << FILEPATH << "=\"" << dataCollection->GetDataFilePath(i) << "\" id=\"Col" << subColId << "\" >\n"; // Create Sub-Folder dir.mkpath(QString::fromStdString(dataCollection->IndexToName(i))); // Herein create data folders DataCollection* subCollections = dynamic_cast (dataCollection->GetData(i).GetPointer()); if (subCollections == NULL) { - MITK_ERROR<< "mitk::CollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; + MITK_ERROR<< "mitk::DiffusionCollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; return false; } for (size_t d = 0; d < subCollections->Size(); d++ ) { // Create Sub Paths QString subPath = QString::fromStdString(dataCollection->IndexToName(i))+"/"+QString::fromStdString(subCollections->IndexToName(d)); dir.mkpath(subPath); xmlFileStream << " <" << DATA << " " << NAME << "=\"" << subCollections->IndexToName(d) << "\" " << FILEPATH << "=\"" << subCollections->GetDataFilePath(d) << "\" id=\"Data" << dataId << "\" >\n"; DataCollection* itemCollections = dynamic_cast (subCollections->GetData(d).GetPointer()); if (itemCollections == NULL) { - MITK_ERROR<< "mitk::CollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; + MITK_ERROR<< "mitk::DiffusionCollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; return false; } for (size_t s = 0; s < itemCollections->Size(); s++) { if (filter.size() > 0) { bool isSelected = false; for (size_t f = 0; f < filter.size(); f++) { if (filter.at(f) == itemCollections->IndexToName(s) ) { isSelected = true; break; } } if (isSelected == false) continue; } Image* image = dynamic_cast (itemCollections->GetData(s).GetPointer()); QString fileName; bool fullName = false; if (itemCollections->GetDataFilePath(s) != "") { fileName = originalFolder + QString::fromStdString(itemCollections->GetDataFilePath(s)); fullName = true; MITK_INFO << "original path: " << itemCollections->GetDataFilePath(s) ; } else fileName = dir.path() + dir.separator() + subPath + dir.separator() + QString::fromStdString(dataCollection->IndexToName(i)) + "_" + QString::fromStdString(subCollections->IndexToName(d)) + "_" + QString::fromStdString(itemCollections->IndexToName(s)); try { if (itemCollections->IndexToName(s) == "DTI" || itemCollections->IndexToName(s) == "DTIFWE") { if (!fullName) fileName += ".dti"; - itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); - io->SetFileType( itk::ImageIOBase::Binary ); - io->UseCompressionOn(); - TensorImage* tensorImage = dynamic_cast (image); - MITK_INFO << "Pixeltype Tensor Image: " << tensorImage->GetPixelType().GetPixelTypeAsString(); - typedef itk::Image,3> ImageType; - typedef itk::ImageFileWriter WriterType; - WriterType::Pointer nrrdWriter = WriterType::New(); - ImageType::Pointer outimage = ImageType::New(); - CastToItkImage(tensorImage, outimage); - nrrdWriter->SetInput( outimage ); - nrrdWriter->SetImageIO(io); - nrrdWriter->SetFileName(fileName.toStdString()); - nrrdWriter->UseCompressionOn(); - nrrdWriter->Update(); + IOUtil::Save(image,fileName.toStdString()); } else if (itemCollections->IndexToName(s) == "FIB") { if (!fullName) fileName += ".fib"; FiberBundle* fib = dynamic_cast (itemCollections->GetData(s).GetPointer()); - CoreObjectFactory::FileWriterList fileWriters = CoreObjectFactory::GetInstance()->GetFileWriters(); - for (CoreObjectFactory::FileWriterList::iterator it = fileWriters.begin() ; it != fileWriters.end() ; ++it) - { - if ( (*it)->CanWriteBaseDataType(fib) ) { - (*it)->SetFileName( fileName.toStdString().c_str() ); - (*it)->DoWrite( fib ); - } - } + IOUtil::Save(fib, fileName.toStdString()); } else if (itemCollections->IndexToName(s) == "DWI") { if (!fullName) fileName += ".dwi"; - IOUtil::SaveImage(image,fileName.toStdString()); + IOUtil::Save(image,fileName.toStdString()); } else { if (!fullName) fileName += ".nrrd"; Image::Pointer image = itemCollections->GetMitkImage(s).GetPointer(); - IOUtil::SaveImage(image,fileName.toStdString()); + IOUtil::Save(image,fileName.toStdString()); } } catch( const std::exception& e) { MITK_ERROR << "Caught exception: " << e.what(); } std::string relativeFilename =baseFolder.relativeFilePath(fileName).toStdString(); xmlFileStream << " <" << ITEM << " " << NAME << "=\"" <IndexToName(s) << "\" " << FILEPATH << "=\"" << "\" " << LINK << "=\"" << relativeFilename << "\" />\n"; } xmlFileStream << " \n"; dataId++; } xmlFileStream << " \n"; subColId++; } xmlFileStream << "\n"; xmlFileStream.flush(); xmlFileStream.close(); return true; } -bool mitk::CollectionWriter::FolderToXml(std::string folder, std::string collectionType, std::string xmlFile, std::vector filter, std::vector seriesNames) +bool mitk::DiffusionCollectionWriter::FolderToXml(std::string folder, std::string collectionType, std::string xmlFile, std::vector filter, std::vector seriesNames) { // 1) Parse for folders QDir parseDir; parseDir.setFilter( QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot); parseDir.setPath(QString::fromStdString(folder)); QFileInfoList qFileList = parseDir.entryInfoList(); std::ofstream xmlFileStream; xmlFileStream.open (xmlFile.c_str()); xmlFileStream << " \n"; xmlFileStream << "<" << COLLECTION << " " << NAME << "=\"" << "GEN" << "\" >\n"; unsigned int dataId = 0; // now populate lists with files names, non-existing files will be marked with an empty string for (int i = 0; i < qFileList.size(); ++i) { // 2) For Each sub folder construct collectionType sub-folder std::string baseFolder = qFileList.at(i).absoluteFilePath().toStdString() + QDir::separator().toLatin1() + collectionType; MITK_INFO << "Processing : " << baseFolder; if (!QFileInfo(QString::fromStdString(baseFolder)).isDir()) { MITK_WARN << "Not a valid folder, skipping."; continue; } // 3) Parse each sub folder and extend XML file // Parse folder and look up all data, // after sanitation only fully available groups are included (that is all suffixes are found) - CollectionReader::FileListType fileList = CollectionReader::SanitizeFileList(CollectionReader::GenerateFileLists(baseFolder, filter,true)); + DiffusionCollectionReader::FileListType fileList = DiffusionCollectionReader::SanitizeFileList(DiffusionCollectionReader::GenerateFileLists(baseFolder, filter,true)); if (fileList.size() <= 0 || fileList.at(0).size() <= 0) continue; // Write Subcollection tag // try to extract date out of filename std::string name = GetName(fileList.at(0).at(0),filter.at(0)); xmlFileStream << " <" << SUBCOLLECTION << " " << NAME << "=\"" << name << "\" " << FILEPATH << "=\"\" id=\"Col" << i << "\" >\n"; for (unsigned int k=0; k < fileList.at(0).size(); ++k) // all groups have the same amount of items, so looking at 0 is ok. { std::string strDate = GetDate(fileList.at(0).at(k),filter.at(0)); xmlFileStream << " <" << DATA << " " << NAME << "=\"" << strDate << "\" " << " id=\"Data" << dataId << "\" >\n"; dataId++; for (unsigned int i=0; i< filter.size(); ++i) { std::string fileName = fileList.at(i).at(k); xmlFileStream << " <" << ITEM << " " << NAME << "=\"" << seriesNames.at(i) << "\" " << LINK << "=\"" << fileName << "\" />\n"; } xmlFileStream << " \n" ; } xmlFileStream << " \n"; } xmlFileStream << "\n"; xmlFileStream.flush(); xmlFileStream.close(); return true; } -bool mitk::CollectionWriter::SingleFolderToXml(std::string folder, std::string xmlFile, std::vector filter, std::vector seriesNames, bool longDate, int skipUntil, float months) +bool mitk::DiffusionCollectionWriter::SingleFolderToXml(std::string folder, std::string xmlFile, std::vector filter, std::vector seriesNames, bool longDate, int skipUntil, float months) { std::ofstream xmlFileStream; xmlFileStream.open (xmlFile.c_str()); xmlFileStream << " \n"; xmlFileStream << "<" << COLLECTION << " " << NAME << "=\"" << "GEN" << "\" >\n"; unsigned int dataId = 0; // 1) // Parse folder and look up all data, // after sanitation only fully available groups are included (that is all suffixes are found) - CollectionReader::FileListType fileList = CollectionReader::SanitizeFileList(CollectionReader::GenerateFileLists(folder, filter,true)); + DiffusionCollectionReader::FileListType fileList = DiffusionCollectionReader::SanitizeFileList(DiffusionCollectionReader::GenerateFileLists(folder, filter,true)); // Write Subcollection tag // try to extract date out of filename std::string name = GetName(fileList.at(0).at(0),filter.at(0),longDate); xmlFileStream << " <" << SUBCOLLECTION << " " << NAME << "=\"" << name << "\" " << FILEPATH << "=\"\" id=\"Col" << 0 << "\" >\n"; for (unsigned int k=skipUntil; k < fileList.at(0).size(); ++k) // all groups have the same amount of items, so looking at 0 is ok. { std::string strDate = GetDate(fileList.at(0).at(k),filter.at(0),true); xmlFileStream << " <" << DATA << " " << NAME << "=\"" << strDate << "\" " << " id=\"Data" << dataId << "\" >\n"; dataId++; for (unsigned int i=0; i< filter.size(); ++i) { std::string fileName = fileList.at(i).at(k); xmlFileStream << " <" << ITEM << " " << NAME << "=\"" << seriesNames.at(i) << "\" " << LINK << "=\"" << fileName << "\" />\n"; } // size_t ind = GetIndexForinXMonths(fileList,months,k,filter); // xmlFileStream << " <" << ITEM << " " << NAME << "=\"TARGET\" " << LINK << "=\"" << fileList.at(filter.size()-1).at(ind) << "\" />\n"; xmlFileStream << " \n" ; // check if target still exists for next step if (GetIndexForinXMonths(fileList,months,k+1,filter)== 0) break; } xmlFileStream << " \n"; xmlFileStream << "\n"; xmlFileStream.flush(); xmlFileStream.close(); return true; } -size_t mitk::CollectionWriter::GetIndexForinXMonths(mitk::CollectionReader::FileListType fileList,float months, size_t curIndex,std::vector filter) +size_t mitk::DiffusionCollectionWriter::GetIndexForinXMonths(mitk::DiffusionCollectionReader::FileListType fileList,float months, size_t curIndex,std::vector filter) { std::string strDate0 = GetDate(fileList.at(0).at(curIndex),filter.at(0),true); int year0 =std::atoi(strDate0.substr(0,4).c_str()); int month0 =std::atoi(strDate0.substr(5,2).c_str()); int day0 = std::atoi(strDate0.substr(8,2).c_str()); size_t bestIndex = 0; int bestFit = 1e5; for (size_t i=curIndex+1; i < fileList.at(0).size(); ++i) { std::string strDate = GetDate(fileList.at(0).at(i),filter.at(0),true); int year =std::atoi(strDate.substr(0,4).c_str()); int month =std::atoi(strDate.substr(5,2).c_str()); int day = std::atoi(strDate.substr(8,2).c_str()); int fit = std::fabs((months * 30 ) - (((year-year0)*360) +((month-month0)*30) + (day-day0))); // days difference from x months if (fit < bestFit) { bestFit = fit; bestIndex = i; } } return bestIndex; } diff --git a/Modules/TumorInvasionAnalysis/test/mitkClassificationTest.cpp b/Modules/TumorInvasionAnalysis/test/mitkClassificationTest.cpp index 077ce6b639..4fa06cebb0 100644 --- a/Modules/TumorInvasionAnalysis/test/mitkClassificationTest.cpp +++ b/Modules/TumorInvasionAnalysis/test/mitkClassificationTest.cpp @@ -1,107 +1,107 @@ /*=================================================================== 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. ===================================================================*/ #pragma warning(disable : 4996) #include "mitkTestFixture.h" #include "mitkTestingMacros.h" #include "mitkCompareImageDataFilter.h" #include "mitkIOUtil.h" -#include "mitkCollectionReader.h" -#include "mitkCollectionWriter.h" #include "mitkDataCollection.h" - #include "mitkTumorInvasionClassification.h" +#include "mitkDiffusionCollectionReader.h" +#include "mitkDiffusionCollectionWriter.h" + #include /** * @brief mitkClassificationTestSuite * - * Tests mitkDecisionForest, mitkClassifyProgression, mitkDataCollection, mitkCollectionReader + * Tests mitkDecisionForest, mitkClassifyProgression, mitkDataCollection, mitkDiffusionCollectionReader * \warn Reference is compared to results computed based on random forests, which might be a source of random test fails * such sporadic fails do represent total fails, as the result is no longer consitently under the provided margin. * */ class mitkClassificationTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkClassificationTestSuite); MITK_TEST(TestClassification); CPPUNIT_TEST_SUITE_END(); public: /** * @brief Setup - Always call this method before each Test-case to ensure correct and new intialization of the used * members for a new test case. (If the members are not used in a test, the method does not need to be called). */ void setUp() {} void tearDown() {} void TestClassification() { size_t forestSize = 10; size_t treeDepth = 2; std::string train = GetTestDataFilePath("DiffusionImaging/ProgressionAnalysis/Classification/Train.xml"); std::string eval = GetTestDataFilePath("DiffusionImaging/ProgressionAnalysis/Classification/Test.xml"); std::vector modalities; modalities.push_back("MOD0"); modalities.push_back("MOD1"); - mitk::CollectionReader colReader; + mitk::DiffusionCollectionReader colReader; mitk::DataCollection::Pointer collection = colReader.LoadCollection(train); colReader.Clear(); // read evaluation collection mitk::DataCollection::Pointer evaluation = colReader.LoadCollection(eval); mitk::TumorInvasionClassification progression; progression.SetClassRatio(1); progression.SetTrainMargin(4, 0); progression.SetMaskID("MASK"); progression.SelectTrainingSamples(collection); progression.LearnProgressionFeatures(collection, modalities, forestSize, treeDepth); progression.PredictInvasion(evaluation, modalities); mitk::Image::Pointer refImage = mitk::IOUtil::LoadImage( GetTestDataFilePath("DiffusionImaging/ProgressionAnalysis/Classification/TESTING_RESULT.nrrd")); mitk::DataCollection *patCol = dynamic_cast(evaluation->GetData(0).GetPointer()); mitk::DataCollection *subCol = dynamic_cast(patCol->GetData(0).GetPointer()); mitk::Image::Pointer resultImage = subCol->GetMitkImage("RESULT"); // Test result against fixed reference. // Require more than 90% to be correct. // 10% margin due to // 1) unsure classification in transitional regions and // 2) stochastic training procedure // Total number of voxels 2400 -> 10% err -> 240 voxels margin mitk::CompareImageDataFilter::Pointer compareFilter = mitk::CompareImageDataFilter::New(); compareFilter->SetInput(0, refImage.GetPointer()); compareFilter->SetInput(1, resultImage); compareFilter->SetTolerance(.1); compareFilter->Update(); MITK_TEST_CONDITION_REQUIRED(compareFilter->GetResult(240), "Compare prediction results to reference image.") } }; MITK_TEST_SUITE_REGISTRATION(mitkClassification) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkFreeSurferParcellationHandler.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkFreeSurferParcellationHandler.cpp index 35660b23c4..8431ef525c 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkFreeSurferParcellationHandler.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkFreeSurferParcellationHandler.cpp @@ -1,116 +1,126 @@ /*=================================================================== 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 "QmitkFreeSurferParcellationHandler.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace mitk; using namespace std; US_USE_NAMESPACE QmitkFreeSurferParcellationHandler::QmitkFreeSurferParcellationHandler() : m_LastPixelvalue( 0 ), m_Translator( mitk::FreeSurferParcellationTranslator::New() ) { us::ServiceProperties props; props["name"] = std::string("ParcellationHandler"); us::ModuleContext* context = us::ModuleRegistry::GetModule(1)->GetModuleContext(); m_ServiceRegistration = context->RegisterService( this, props); } QmitkFreeSurferParcellationHandler::~QmitkFreeSurferParcellationHandler() { m_ServiceRegistration.Unregister(); } void QmitkFreeSurferParcellationHandler::Notify(InteractionEvent *interactionEvent, bool isHandled) { Q_UNUSED( isHandled ) typedef itk::VectorContainer SetOfObjects; BaseRenderer* sender = interactionEvent->GetSender(); InteractionPositionEvent* positionEvent = static_cast(interactionEvent); TNodePredicateDataType::Pointer isImageData = TNodePredicateDataType::New(); DataStorage::SetOfObjects::ConstPointer nodes = sender->GetDataStorage()->GetSubset(isImageData).GetPointer(); if(nodes.IsNull() || nodes->size() <= 0) return; Point3D worldposition = positionEvent->GetPositionInWorld(); for (unsigned int x = 0; x < nodes->size(); x++) { DataNode::Pointer node = static_cast( nodes->at(x) ); if(node.IsNotNull()) { Image::Pointer image = dynamic_cast( node->GetData() ); if( image.IsNotNull() && image->GetGeometry()->IsInside(worldposition) ) { string typeStr = image->GetPixelType().GetComponentTypeAsString(); int value = 0; try { if( typeStr == "int" ) { ImagePixelReadAccessor readAccess( image ); value = static_cast( readAccess.GetPixelByWorldCoordinates( worldposition ) ); } else if( typeStr == "unsigned_char" ) { ImagePixelReadAccessor readAccess( image ); value = static_cast( readAccess.GetPixelByWorldCoordinates( worldposition ) ); } + else if( typeStr == "short" ) + { + ImagePixelReadAccessor readAccess( image ); + value = static_cast( readAccess.GetPixelByWorldCoordinates( worldposition ) ); + } + else if( typeStr == "float" ) + { + ImagePixelReadAccessor readAccess( image ); + value = static_cast( readAccess.GetPixelByWorldCoordinates( worldposition ) ); + } else { MITK_WARN("QmitkFreeSurferParcellationHandler") << "Pixeltype '" << typeStr << "' is not implemented yet."; return; } emit this->changed( value ); QString name( QString::fromStdString( this->m_Translator->GetName( value ) ) ); emit this->changed( name ); MousePressEvent::Pointer mouseEvent = dynamic_cast( interactionEvent ); MouseWheelEvent::Pointer wheelEvent = dynamic_cast( interactionEvent ); if(mouseEvent.IsNotNull()) { emit this->clicked( value ); emit this->clicked( name ); } if( wheelEvent.IsNotNull() ) { emit this->scrolled( value ); emit this->scrolled( name ); } return; // exit loop } catch( const Exception& ex ) { MITK_WARN("QmitkFreeSurferParcellationHandler") << "Could not access image for reading pixelvalue due to: " << ex.GetDescription(); } catch(...) { MITK_WARN("QmitkFreeSurferParcellationHandler") << "Could not access image for reading pixelvalue."; } } } } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp index ea0f98f081..0fc9b26c0e 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.cpp @@ -1,1383 +1,1408 @@ /*=================================================================== 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 "QmitkFiberProcessingView.h" #include // Qt #include // MITK #include #include #include #include #include #include #include #include #include #include #include "usModuleRegistry.h" #include #include "mitkNodePredicateDataType.h" #include #include #include #include // ITK #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include const std::string QmitkFiberProcessingView::VIEW_ID = "org.mitk.views.fiberprocessing"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace mitk; QmitkFiberProcessingView::QmitkFiberProcessingView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) , m_CircleCounter(0) , m_PolygonCounter(0) , m_UpsamplingFactor(1) { } // Destructor QmitkFiberProcessingView::~QmitkFiberProcessingView() { } void QmitkFiberProcessingView::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::QmitkFiberProcessingViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_CircleButton, SIGNAL( clicked() ), this, SLOT( OnDrawCircle() ) ); connect( m_Controls->m_PolygonButton, SIGNAL( clicked() ), this, SLOT( OnDrawPolygon() ) ); connect(m_Controls->PFCompoANDButton, SIGNAL(clicked()), this, SLOT(GenerateAndComposite()) ); connect(m_Controls->PFCompoORButton, SIGNAL(clicked()), this, SLOT(GenerateOrComposite()) ); connect(m_Controls->PFCompoNOTButton, SIGNAL(clicked()), this, SLOT(GenerateNotComposite()) ); connect(m_Controls->m_GenerateRoiImage, SIGNAL(clicked()), this, SLOT(GenerateRoiImage()) ); connect(m_Controls->m_JoinBundles, SIGNAL(clicked()), this, SLOT(JoinBundles()) ); connect(m_Controls->m_SubstractBundles, SIGNAL(clicked()), this, SLOT(SubstractBundles()) ); connect(m_Controls->m_CopyBundle, SIGNAL(clicked()), this, SLOT(CopyBundles()) ); connect(m_Controls->m_ExtractFibersButton, SIGNAL(clicked()), this, SLOT(Extract())); connect(m_Controls->m_RemoveButton, SIGNAL(clicked()), this, SLOT(Remove())); connect(m_Controls->m_ModifyButton, SIGNAL(clicked()), this, SLOT(Modify())); connect(m_Controls->m_ExtractionMethodBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); connect(m_Controls->m_RemovalMethodBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); connect(m_Controls->m_ModificationMethodBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); + connect(m_Controls->m_ExtractionBoxMask, SIGNAL(currentIndexChanged(int)), this, SLOT(OnMaskExtractionChanged())); m_Controls->m_ColorMapBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isMitkImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isQbi = mitk::NodePredicateDataType::New("QBallImage"); mitk::NodePredicateOr::Pointer isDiffusionImage = mitk::NodePredicateOr::New(isDwi, isDti); isDiffusionImage = mitk::NodePredicateOr::New(isDiffusionImage, isQbi); mitk::NodePredicateNot::Pointer noDiffusionImage = mitk::NodePredicateNot::New(isDiffusionImage); mitk::NodePredicateAnd::Pointer finalPredicate = mitk::NodePredicateAnd::New(isMitkImage, noDiffusionImage); m_Controls->m_ColorMapBox->SetPredicate(finalPredicate); + + m_Controls->label_17->setVisible(false); + m_Controls->m_FiberExtractionFractionBox->setVisible(false); } UpdateGui(); } +void QmitkFiberProcessingView::OnMaskExtractionChanged() +{ + if (m_Controls->m_ExtractionBoxMask->currentIndex() == 2) + { + m_Controls->label_17->setVisible(true); + m_Controls->m_FiberExtractionFractionBox->setVisible(true); + m_Controls->m_BothEnds->setVisible(false); + } + else + { + m_Controls->label_17->setVisible(false); + m_Controls->m_FiberExtractionFractionBox->setVisible(false); + if (m_Controls->m_ExtractionBoxMask->currentIndex() != 3) + m_Controls->m_BothEnds->setVisible(true); + } +} + void QmitkFiberProcessingView::Modify() { switch (m_Controls->m_ModificationMethodBox->currentIndex()) { case 0: { ResampleSelectedBundles(); break; } case 1: { CompressSelectedBundles(); break; } case 2: { DoImageColorCoding(); break; } case 3: { MirrorFibers(); break; } case 4: { WeightFibers(); break; } case 5: { DoCurvatureColorCoding(); break; } } } void QmitkFiberProcessingView::WeightFibers() { float weight = this->m_Controls->m_BundleWeightBox->value(); for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); fib->SetFiberWeights(weight); } } void QmitkFiberProcessingView::Remove() { switch (m_Controls->m_RemovalMethodBox->currentIndex()) { case 0: { RemoveDir(); break; } case 1: { PruneBundle(); break; } case 2: { ApplyCurvatureThreshold(); break; } case 3: { RemoveWithMask(false); break; } case 4: { RemoveWithMask(true); break; } } } void QmitkFiberProcessingView::Extract() { switch (m_Controls->m_ExtractionMethodBox->currentIndex()) { case 0: { ExtractWithPlanarFigure(); break; } case 1: { switch (m_Controls->m_ExtractionBoxMask->currentIndex()) { { case 0: ExtractWithMask(true, false); break; } { case 1: ExtractWithMask(true, true); break; } { case 2: ExtractWithMask(false, false); break; } { case 3: ExtractWithMask(false, true); break; } } break; } } } void QmitkFiberProcessingView::PruneBundle() { int minLength = this->m_Controls->m_PruneFibersMinBox->value(); int maxLength = this->m_Controls->m_PruneFibersMaxBox->value(); for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); if (!fib->RemoveShortFibers(minLength)) QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); else if (!fib->RemoveLongFibers(maxLength)) QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); } RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::ApplyCurvatureThreshold() { int angle = this->m_Controls->m_CurvSpinBox->value(); int dist = this->m_Controls->m_CurvDistanceSpinBox->value(); std::vector< DataNode::Pointer > nodes = m_SelectedFB; for (auto node : nodes) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); itk::FiberCurvatureFilter::Pointer filter = itk::FiberCurvatureFilter::New(); filter->SetInputFiberBundle(fib); filter->SetAngularDeviation(angle); filter->SetDistance(dist); filter->SetRemoveFibers(m_Controls->m_RemoveCurvedFibersBox->isChecked()); filter->Update(); mitk::FiberBundle::Pointer newFib = filter->GetOutputFiberBundle(); if (newFib->GetNumFibers()>0) + { + newFib->ColorFibersByOrientation(); node->SetData(newFib); + } else QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); } RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::RemoveDir() { for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); vnl_vector_fixed dir; dir[0] = m_Controls->m_ExtractDirX->value(); dir[1] = m_Controls->m_ExtractDirY->value(); dir[2] = m_Controls->m_ExtractDirZ->value(); fib->RemoveDir(dir,cos((float)m_Controls->m_ExtractAngle->value()*M_PI/180)); } RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::RemoveWithMask(bool removeInside) { if (m_MaskImageNode.IsNull()) return; mitk::Image::Pointer mitkMask = dynamic_cast(m_MaskImageNode->GetData()); for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); QString name(node->GetName().c_str()); itkUCharImageType::Pointer mask = itkUCharImageType::New(); mitk::CastToItkImage(mitkMask, mask); mitk::FiberBundle::Pointer newFib = fib->RemoveFibersOutside(mask, removeInside); if (newFib->GetNumFibers()<=0) { QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); continue; } node->SetData(newFib); } RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::ExtractWithMask(bool onlyEnds, bool invert) { if (m_MaskImageNode.IsNull()) return; mitk::Image::Pointer mitkMask = dynamic_cast(m_MaskImageNode->GetData()); for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); QString name(node->GetName().c_str()); itkUCharImageType::Pointer mask = itkUCharImageType::New(); mitk::CastToItkImage(mitkMask, mask); - mitk::FiberBundle::Pointer newFib = fib->ExtractFiberSubset(mask, !onlyEnds, invert, m_Controls->m_BothEnds->isChecked()); + mitk::FiberBundle::Pointer newFib = fib->ExtractFiberSubset(mask, !onlyEnds, invert, m_Controls->m_BothEnds->isChecked(), m_Controls->m_FiberExtractionFractionBox->value()); if (newFib->GetNumFibers()<=0) { QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); continue; } DataNode::Pointer newNode = DataNode::New(); newNode->SetData(newFib); if (invert) { name += "_not"; if (onlyEnds) name += "-ending-in-mask"; else name += "-passing-mask"; } else { if (onlyEnds) name += "_ending-in-mask"; else name += "_passing-mask"; } newNode->SetName(name.toStdString()); GetDefaultDataStorage()->Add(newNode); node->SetVisibility(false); } } void QmitkFiberProcessingView::GenerateRoiImage() { if (m_SelectedPF.empty()) return; mitk::BaseGeometry::Pointer geometry; if (!m_SelectedFB.empty()) { mitk::FiberBundle::Pointer fib = dynamic_cast(m_SelectedFB.front()->GetData()); geometry = fib->GetGeometry(); } else if (m_SelectedImage) geometry = m_SelectedImage->GetGeometry(); else return; itk::Vector spacing = geometry->GetSpacing(); spacing /= m_UpsamplingFactor; mitk::Point3D newOrigin = geometry->GetOrigin(); mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); newOrigin[0] += bounds.GetElement(0); newOrigin[1] += bounds.GetElement(2); newOrigin[2] += bounds.GetElement(4); itk::Matrix direction; itk::ImageRegion<3> imageRegion; for (int i=0; i<3; i++) for (int j=0; j<3; j++) direction[j][i] = geometry->GetMatrixColumn(i)[j]/spacing[j]; imageRegion.SetSize(0, geometry->GetExtent(0)*m_UpsamplingFactor); imageRegion.SetSize(1, geometry->GetExtent(1)*m_UpsamplingFactor); imageRegion.SetSize(2, geometry->GetExtent(2)*m_UpsamplingFactor); m_PlanarFigureImage = itkUCharImageType::New(); m_PlanarFigureImage->SetSpacing( spacing ); // Set the image spacing m_PlanarFigureImage->SetOrigin( newOrigin ); // Set the image origin m_PlanarFigureImage->SetDirection( direction ); // Set the image direction m_PlanarFigureImage->SetRegions( imageRegion ); m_PlanarFigureImage->Allocate(); m_PlanarFigureImage->FillBuffer( 0 ); Image::Pointer tmpImage = Image::New(); tmpImage->InitializeByItk(m_PlanarFigureImage.GetPointer()); tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer()); std::string name = m_SelectedPF.at(0)->GetName(); WritePfToImage(m_SelectedPF.at(0), tmpImage); for (unsigned int i=1; iGetName(); WritePfToImage(m_SelectedPF.at(i), tmpImage); } DataNode::Pointer node = DataNode::New(); tmpImage = Image::New(); tmpImage->InitializeByItk(m_PlanarFigureImage.GetPointer()); tmpImage->SetVolume(m_PlanarFigureImage->GetBufferPointer()); node->SetData(tmpImage); node->SetName(name); this->GetDefaultDataStorage()->Add(node); } void QmitkFiberProcessingView::WritePfToImage(mitk::DataNode::Pointer node, mitk::Image* image) { if (dynamic_cast(node->GetData())) { m_PlanarFigure = dynamic_cast(node->GetData()); AccessFixedDimensionByItk_2( image, InternalReorientImagePlane, 3, m_PlanarFigure->GetGeometry(), -1); AccessFixedDimensionByItk_2( m_InternalImage, InternalCalculateMaskFromPlanarFigure, 3, 2, node->GetName() ); } else if (dynamic_cast(node->GetData())) { DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(node); for (unsigned int i=0; iSize(); i++) { WritePfToImage(children->at(i), image); } } } template < typename TPixel, unsigned int VImageDimension > void QmitkFiberProcessingView::InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::BaseGeometry* planegeo3D, int additionalIndex ) { typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::Image< float, VImageDimension > FloatImageType; typedef itk::ResampleImageFilter ResamplerType; typename ResamplerType::Pointer resampler = ResamplerType::New(); mitk::PlaneGeometry* planegeo = dynamic_cast(planegeo3D); float upsamp = m_UpsamplingFactor; float gausssigma = 0.5; // Spacing typename ResamplerType::SpacingType spacing = planegeo->GetSpacing(); spacing[0] = image->GetSpacing()[0] / upsamp; spacing[1] = image->GetSpacing()[1] / upsamp; spacing[2] = image->GetSpacing()[2]; resampler->SetOutputSpacing( spacing ); // Size typename ResamplerType::SizeType size; size[0] = planegeo->GetExtentInMM(0) / spacing[0]; size[1] = planegeo->GetExtentInMM(1) / spacing[1]; size[2] = 1; resampler->SetSize( size ); // Origin typename mitk::Point3D orig = planegeo->GetOrigin(); typename mitk::Point3D corrorig; planegeo3D->WorldToIndex(orig,corrorig); corrorig[0] += 0.5/upsamp; corrorig[1] += 0.5/upsamp; corrorig[2] += 0; planegeo3D->IndexToWorld(corrorig,corrorig); resampler->SetOutputOrigin(corrorig ); // Direction typename ResamplerType::DirectionType direction; typename mitk::AffineTransform3D::MatrixType matrix = planegeo->GetIndexToWorldTransform()->GetMatrix(); for(int c=0; cSetOutputDirection( direction ); // Gaussian interpolation if(gausssigma != 0) { double sigma[3]; for( unsigned int d = 0; d < 3; d++ ) sigma[d] = gausssigma * image->GetSpacing()[d]; double alpha = 2.0; typedef itk::GaussianInterpolateImageFunction GaussianInterpolatorType; typename GaussianInterpolatorType::Pointer interpolator = GaussianInterpolatorType::New(); interpolator->SetInputImage( image ); interpolator->SetParameters( sigma, alpha ); resampler->SetInterpolator( interpolator ); } else { typedef typename itk::LinearInterpolateImageFunction InterpolatorType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); interpolator->SetInputImage( image ); resampler->SetInterpolator( interpolator ); } resampler->SetInput( image ); resampler->SetDefaultPixelValue(0); resampler->Update(); if(additionalIndex < 0) { this->m_InternalImage = mitk::Image::New(); this->m_InternalImage->InitializeByItk( resampler->GetOutput() ); this->m_InternalImage->SetVolume( resampler->GetOutput()->GetBufferPointer() ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkFiberProcessingView::InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string ) { typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::CastImageFilter< ImageType, itkUCharImageType > CastFilterType; // Generate mask image as new image with same header as input image and // initialize with "1". itkUCharImageType::Pointer newMaskImage = itkUCharImageType::New(); newMaskImage->SetSpacing( image->GetSpacing() ); // Set the image spacing newMaskImage->SetOrigin( image->GetOrigin() ); // Set the image origin newMaskImage->SetDirection( image->GetDirection() ); // Set the image direction newMaskImage->SetRegions( image->GetLargestPossibleRegion() ); newMaskImage->Allocate(); newMaskImage->FillBuffer( 1 ); // Generate VTK polygon from (closed) PlanarFigure polyline // (The polyline points are shifted by -0.5 in z-direction to make sure // that the extrusion filter, which afterwards elevates all points by +0.5 // in z-direction, creates a 3D object which is cut by the the plane z=0) const PlaneGeometry *planarFigurePlaneGeometry = m_PlanarFigure->GetPlaneGeometry(); const PlanarFigure::PolyLineType planarFigurePolyline = m_PlanarFigure->GetPolyLine( 0 ); const BaseGeometry *imageGeometry3D = m_InternalImage->GetGeometry( 0 ); vtkPolyData *polyline = vtkPolyData::New(); polyline->Allocate( 1, 1 ); // Determine x- and y-dimensions depending on principal axis int i0, i1; switch ( axis ) { case 0: i0 = 1; i1 = 2; break; case 1: i0 = 0; i1 = 2; break; case 2: default: i0 = 0; i1 = 1; break; } // Create VTK polydata object of polyline contour vtkPoints *points = vtkPoints::New(); PlanarFigure::PolyLineType::const_iterator it; unsigned int numberOfPoints = 0; for ( it = planarFigurePolyline.begin(); it != planarFigurePolyline.end(); ++it ) { Point3D point3D; // Convert 2D point back to the local index coordinates of the selected image Point2D point2D = *it; planarFigurePlaneGeometry->WorldToIndex(point2D, point2D); point2D[0] -= 0.5/m_UpsamplingFactor; point2D[1] -= 0.5/m_UpsamplingFactor; planarFigurePlaneGeometry->IndexToWorld(point2D, point2D); planarFigurePlaneGeometry->Map( point2D, point3D ); // Polygons (partially) outside of the image bounds can not be processed further due to a bug in vtkPolyDataToImageStencil if ( !imageGeometry3D->IsInside( point3D ) ) { float bounds[2] = {0,0}; bounds[0] = this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i0); bounds[1] = this->m_InternalImage->GetLargestPossibleRegion().GetSize().GetElement(i1); imageGeometry3D->WorldToIndex( point3D, point3D ); if (point3D[i0]<0) point3D[i0] = 0.0; else if (point3D[i0]>bounds[0]) point3D[i0] = bounds[0]-0.001; if (point3D[i1]<0) point3D[i1] = 0.0; else if (point3D[i1]>bounds[1]) point3D[i1] = bounds[1]-0.001; points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); numberOfPoints++; } else { imageGeometry3D->WorldToIndex( point3D, point3D ); // Add point to polyline array points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 ); numberOfPoints++; } } polyline->SetPoints( points ); points->Delete(); vtkIdType *ptIds = new vtkIdType[numberOfPoints]; for ( vtkIdType i = 0; i < numberOfPoints; ++i ) ptIds[i] = i; polyline->InsertNextCell( VTK_POLY_LINE, numberOfPoints, ptIds ); // Extrude the generated contour polygon vtkLinearExtrusionFilter *extrudeFilter = vtkLinearExtrusionFilter::New(); extrudeFilter->SetInputData( polyline ); extrudeFilter->SetScaleFactor( 1 ); extrudeFilter->SetExtrusionTypeToNormalExtrusion(); extrudeFilter->SetVector( 0.0, 0.0, 1.0 ); // Make a stencil from the extruded polygon vtkPolyDataToImageStencil *polyDataToImageStencil = vtkPolyDataToImageStencil::New(); polyDataToImageStencil->SetInputConnection( extrudeFilter->GetOutputPort() ); // Export from ITK to VTK (to use a VTK filter) typedef itk::VTKImageImport< itkUCharImageType > ImageImportType; typedef itk::VTKImageExport< itkUCharImageType > ImageExportType; typename ImageExportType::Pointer itkExporter = ImageExportType::New(); itkExporter->SetInput( newMaskImage ); vtkImageImport *vtkImporter = vtkImageImport::New(); this->ConnectPipelines( itkExporter, vtkImporter ); vtkImporter->Update(); // Apply the generated image stencil to the input image vtkImageStencil *imageStencilFilter = vtkImageStencil::New(); imageStencilFilter->SetInputConnection( vtkImporter->GetOutputPort() ); imageStencilFilter->SetStencilConnection(polyDataToImageStencil->GetOutputPort() ); imageStencilFilter->ReverseStencilOff(); imageStencilFilter->SetBackgroundValue( 0 ); imageStencilFilter->Update(); // Export from VTK back to ITK vtkImageExport *vtkExporter = vtkImageExport::New(); vtkExporter->SetInputConnection( imageStencilFilter->GetOutputPort() ); vtkExporter->Update(); typename ImageImportType::Pointer itkImporter = ImageImportType::New(); this->ConnectPipelines( vtkExporter, itkImporter ); itkImporter->Update(); // calculate cropping bounding box m_InternalImageMask3D = itkImporter->GetOutput(); m_InternalImageMask3D->SetDirection(image->GetDirection()); itk::ImageRegionConstIterator itmask(m_InternalImageMask3D, m_InternalImageMask3D->GetLargestPossibleRegion()); itk::ImageRegionIterator itimage(image, image->GetLargestPossibleRegion()); itmask.GoToBegin(); itimage.GoToBegin(); typename ImageType::SizeType lowersize = {{itk::NumericTraits::max(),itk::NumericTraits::max(),itk::NumericTraits::max()}}; typename ImageType::SizeType uppersize = {{0,0,0}}; while( !itmask.IsAtEnd() ) { if(itmask.Get() == 0) itimage.Set(0); else { typename ImageType::IndexType index = itimage.GetIndex(); typename ImageType::SizeType signedindex; signedindex[0] = index[0]; signedindex[1] = index[1]; signedindex[2] = index[2]; lowersize[0] = signedindex[0] < lowersize[0] ? signedindex[0] : lowersize[0]; lowersize[1] = signedindex[1] < lowersize[1] ? signedindex[1] : lowersize[1]; lowersize[2] = signedindex[2] < lowersize[2] ? signedindex[2] : lowersize[2]; uppersize[0] = signedindex[0] > uppersize[0] ? signedindex[0] : uppersize[0]; uppersize[1] = signedindex[1] > uppersize[1] ? signedindex[1] : uppersize[1]; uppersize[2] = signedindex[2] > uppersize[2] ? signedindex[2] : uppersize[2]; } ++itmask; ++itimage; } typename ImageType::IndexType index; index[0] = lowersize[0]; index[1] = lowersize[1]; index[2] = lowersize[2]; typename ImageType::SizeType size; size[0] = uppersize[0] - lowersize[0] + 1; size[1] = uppersize[1] - lowersize[1] + 1; size[2] = uppersize[2] - lowersize[2] + 1; itk::ImageRegion<3> cropRegion = itk::ImageRegion<3>(index, size); // crop internal mask typedef itk::RegionOfInterestImageFilter< itkUCharImageType, itkUCharImageType > ROIMaskFilterType; typename ROIMaskFilterType::Pointer roi2 = ROIMaskFilterType::New(); roi2->SetRegionOfInterest(cropRegion); roi2->SetInput(m_InternalImageMask3D); roi2->Update(); m_InternalImageMask3D = roi2->GetOutput(); Image::Pointer tmpImage = Image::New(); tmpImage->InitializeByItk(m_InternalImageMask3D.GetPointer()); tmpImage->SetVolume(m_InternalImageMask3D->GetBufferPointer()); Image::Pointer tmpImage2 = Image::New(); tmpImage2->InitializeByItk(m_PlanarFigureImage.GetPointer()); const BaseGeometry *pfImageGeometry3D = tmpImage2->GetGeometry( 0 ); const BaseGeometry *intImageGeometry3D = tmpImage->GetGeometry( 0 ); typedef itk::ImageRegionIteratorWithIndex IteratorType; IteratorType imageIterator (m_InternalImageMask3D, m_InternalImageMask3D->GetRequestedRegion()); imageIterator.GoToBegin(); while ( !imageIterator.IsAtEnd() ) { unsigned char val = imageIterator.Value(); if (val>0) { itk::Index<3> index = imageIterator.GetIndex(); Point3D point; point[0] = index[0]; point[1] = index[1]; point[2] = index[2]; intImageGeometry3D->IndexToWorld(point, point); pfImageGeometry3D->WorldToIndex(point, point); point[i0] += 0.5; point[i1] += 0.5; index[0] = point[0]; index[1] = point[1]; index[2] = point[2]; if (pfImageGeometry3D->IsIndexInside(index)) m_PlanarFigureImage->SetPixel(index, 1); } ++imageIterator; } // Clean up VTK objects polyline->Delete(); extrudeFilter->Delete(); polyDataToImageStencil->Delete(); vtkImporter->Delete(); imageStencilFilter->Delete(); //vtkExporter->Delete(); // TODO: crashes when outcommented; memory leak?? delete[] ptIds; } void QmitkFiberProcessingView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkFiberProcessingView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkFiberProcessingView::UpdateGui() { m_Controls->m_FibLabel->setText("mandatory"); m_Controls->m_PfLabel->setText("needed for extraction"); m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_RemoveButton->setEnabled(false); m_Controls->m_PlanarFigureButtonsFrame->setEnabled(false); m_Controls->PFCompoANDButton->setEnabled(false); m_Controls->PFCompoORButton->setEnabled(false); m_Controls->PFCompoNOTButton->setEnabled(false); m_Controls->m_GenerateRoiImage->setEnabled(false); m_Controls->m_ExtractFibersButton->setEnabled(false); m_Controls->m_ModifyButton->setEnabled(false); m_Controls->m_CopyBundle->setEnabled(false); m_Controls->m_JoinBundles->setEnabled(false); m_Controls->m_SubstractBundles->setEnabled(false); // disable alle frames m_Controls->m_BundleWeightFrame->setVisible(false); m_Controls->m_ExtactionFramePF->setVisible(false); m_Controls->m_RemoveDirectionFrame->setVisible(false); m_Controls->m_RemoveLengthFrame->setVisible(false); m_Controls->m_RemoveCurvatureFrame->setVisible(false); m_Controls->m_SmoothFibersFrame->setVisible(false); m_Controls->m_CompressFibersFrame->setVisible(false); m_Controls->m_ColorFibersFrame->setVisible(false); m_Controls->m_MirrorFibersFrame->setVisible(false); m_Controls->m_MaskExtractionFrame->setVisible(false); bool pfSelected = !m_SelectedPF.empty(); bool fibSelected = !m_SelectedFB.empty(); bool multipleFibsSelected = (m_SelectedFB.size()>1); bool maskSelected = m_MaskImageNode.IsNotNull(); bool imageSelected = m_SelectedImage.IsNotNull(); // toggle visibility of elements according to selected method switch ( m_Controls->m_ExtractionMethodBox->currentIndex() ) { case 0: m_Controls->m_ExtactionFramePF->setVisible(true); break; case 1: m_Controls->m_MaskExtractionFrame->setVisible(true); break; } switch ( m_Controls->m_RemovalMethodBox->currentIndex() ) { case 0: m_Controls->m_RemoveDirectionFrame->setVisible(true); if ( fibSelected ) m_Controls->m_RemoveButton->setEnabled(true); break; case 1: m_Controls->m_RemoveLengthFrame->setVisible(true); if ( fibSelected ) m_Controls->m_RemoveButton->setEnabled(true); break; case 2: m_Controls->m_RemoveCurvatureFrame->setVisible(true); if ( fibSelected ) m_Controls->m_RemoveButton->setEnabled(true); break; case 3: break; case 4: break; } switch ( m_Controls->m_ModificationMethodBox->currentIndex() ) { case 0: m_Controls->m_SmoothFibersFrame->setVisible(true); break; case 1: m_Controls->m_CompressFibersFrame->setVisible(true); break; case 2: m_Controls->m_ColorFibersFrame->setVisible(true); break; case 3: m_Controls->m_MirrorFibersFrame->setVisible(true); if (m_SelectedSurfaces.size()>0) m_Controls->m_ModifyButton->setEnabled(true); break; case 4: m_Controls->m_BundleWeightFrame->setVisible(true); } // are fiber bundles selected? if ( fibSelected ) { m_Controls->m_CopyBundle->setEnabled(true); m_Controls->m_ModifyButton->setEnabled(true); m_Controls->m_PlanarFigureButtonsFrame->setEnabled(true); m_Controls->m_FibLabel->setText(QString(m_SelectedFB.at(0)->GetName().c_str())); // one bundle and one planar figure needed to extract fibers if (pfSelected && m_Controls->m_ExtractionMethodBox->currentIndex()==0) { m_Controls->m_InputData->setTitle("Input Data"); m_Controls->m_PfLabel->setText(QString(m_SelectedPF.at(0)->GetName().c_str())); m_Controls->m_ExtractFibersButton->setEnabled(true); } // more than two bundles needed to join/subtract if (multipleFibsSelected) { m_Controls->m_FibLabel->setText("multiple bundles selected"); m_Controls->m_JoinBundles->setEnabled(true); m_Controls->m_SubstractBundles->setEnabled(true); } if (maskSelected && m_Controls->m_ExtractionMethodBox->currentIndex()==1) { m_Controls->m_InputData->setTitle("Input Data"); m_Controls->m_PfLabel->setText(QString(m_MaskImageNode->GetName().c_str())); m_Controls->m_ExtractFibersButton->setEnabled(true); } if (maskSelected && (m_Controls->m_RemovalMethodBox->currentIndex()==3 || m_Controls->m_RemovalMethodBox->currentIndex()==4) ) { m_Controls->m_InputData->setTitle("Input Data"); m_Controls->m_PfLabel->setText(QString(m_MaskImageNode->GetName().c_str())); m_Controls->m_RemoveButton->setEnabled(true); } } // are planar figures selected? if (pfSelected) { if ( fibSelected || m_SelectedImage.IsNotNull()) m_Controls->m_GenerateRoiImage->setEnabled(true); if (m_SelectedPF.size() > 1) { m_Controls->PFCompoANDButton->setEnabled(true); m_Controls->PFCompoORButton->setEnabled(true); } else m_Controls->PFCompoNOTButton->setEnabled(true); } // is image selected if (imageSelected || maskSelected) { m_Controls->m_PlanarFigureButtonsFrame->setEnabled(true); } } void QmitkFiberProcessingView::NodeRemoved(const mitk::DataNode* node) { std::vector nodes; OnSelectionChanged(nodes); } void QmitkFiberProcessingView::NodeAdded(const mitk::DataNode* node) { std::vector nodes; OnSelectionChanged(nodes); } void QmitkFiberProcessingView::OnSelectionChanged( std::vector nodes ) { //reset existing Vectors containing FiberBundles and PlanarFigures from a previous selection m_SelectedFB.clear(); m_SelectedPF.clear(); m_SelectedSurfaces.clear(); m_SelectedImage = NULL; m_MaskImageNode = NULL; for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( dynamic_cast(node->GetData()) ) m_SelectedFB.push_back(node); else if (dynamic_cast(node->GetData()) || dynamic_cast(node->GetData()) || dynamic_cast(node->GetData())) m_SelectedPF.push_back(node); else if (dynamic_cast(node->GetData())) { m_SelectedImage = dynamic_cast(node->GetData()); bool isBinary = false; node->GetPropertyValue("binary", isBinary); if (isBinary) m_MaskImageNode = node; } else if (dynamic_cast(node->GetData())) m_SelectedSurfaces.push_back(dynamic_cast(node->GetData())); } if (m_SelectedFB.empty() && m_SelectedSurfaces.empty()) { int maxLayer = 0; itk::VectorContainer::ConstPointer nodes = this->GetDefaultDataStorage()->GetAll(); for (unsigned int i=0; iSize(); i++) if (dynamic_cast(nodes->at(i)->GetData())) { mitk::DataStorage::SetOfObjects::ConstPointer sources = GetDataStorage()->GetSources(nodes->at(i)); if (sources->Size()>0) continue; int layer = 0; nodes->at(i)->GetPropertyValue("layer", layer); if (layer>=maxLayer) { maxLayer = layer; m_SelectedFB.clear(); m_SelectedFB.push_back(nodes->at(i)); } } } if (m_SelectedPF.empty()) { int maxLayer = 0; itk::VectorContainer::ConstPointer nodes = this->GetDefaultDataStorage()->GetAll(); for (unsigned int i=0; iSize(); i++) if (dynamic_cast(nodes->at(i)->GetData()) || dynamic_cast(nodes->at(i)->GetData()) || dynamic_cast(nodes->at(i)->GetData())) { mitk::DataStorage::SetOfObjects::ConstPointer sources = GetDataStorage()->GetSources(nodes->at(i)); if (sources->Size()>0) continue; int layer = 0; nodes->at(i)->GetPropertyValue("layer", layer); if (layer>=maxLayer) { maxLayer = layer; m_SelectedPF.clear(); m_SelectedPF.push_back(nodes->at(i)); } } } UpdateGui(); } void QmitkFiberProcessingView::OnDrawPolygon() { mitk::PlanarPolygon::Pointer figure = mitk::PlanarPolygon::New(); figure->ClosedOn(); this->AddFigureToDataStorage(figure, QString("Polygon%1").arg(++m_PolygonCounter)); } void QmitkFiberProcessingView::OnDrawCircle() { mitk::PlanarCircle::Pointer figure = mitk::PlanarCircle::New(); this->AddFigureToDataStorage(figure, QString("Circle%1").arg(++m_CircleCounter)); } void QmitkFiberProcessingView::Activated() { } void QmitkFiberProcessingView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *, mitk::BaseProperty* ) { // initialize figure's geometry with empty geometry mitk::PlaneGeometry::Pointer emptygeometry = mitk::PlaneGeometry::New(); figure->SetPlaneGeometry( emptygeometry ); //set desired data to DataNode where Planarfigure is stored mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); newNode->SetBoolProperty("planarfigure.3drendering", true); newNode->SetBoolProperty("planarfigure.3drendering.fill", true); mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(newNode->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(newNode); } // figure drawn on the topmost layer / image GetDataStorage()->Add(newNode ); for(unsigned int i = 0; i < m_SelectedPF.size(); i++) m_SelectedPF[i]->SetSelected(false); newNode->SetSelected(true); m_SelectedPF.clear(); m_SelectedPF.push_back(newNode); UpdateGui(); } void QmitkFiberProcessingView::ExtractWithPlanarFigure() { if ( m_SelectedFB.empty() || m_SelectedPF.empty() ){ QMessageBox::information( NULL, "Warning", "No fibe bundle selected!"); return; } std::vector fiberBundles = m_SelectedFB; mitk::DataNode::Pointer planarFigure = m_SelectedPF.at(0); for (unsigned int i=0; i(fiberBundles.at(i)->GetData()); mitk::FiberBundle::Pointer extFB = fib->ExtractFiberSubset(planarFigure, GetDataStorage()); if (extFB->GetNumFibers()<=0) { QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers."); continue; } mitk::DataNode::Pointer node; node = mitk::DataNode::New(); node->SetData(extFB); QString name(fiberBundles.at(i)->GetName().c_str()); name += "*"; //name += planarFigure->GetName().c_str(); node->SetName(name.toStdString()); fiberBundles.at(i)->SetVisibility(false); GetDataStorage()->Add(node); } } void QmitkFiberProcessingView::GenerateAndComposite() { mitk::PlanarFigureComposite::Pointer PFCAnd = mitk::PlanarFigureComposite::New(); PFCAnd->setOperationType(mitk::PlanarFigureComposite::AND); mitk::DataNode::Pointer newPFCNode; newPFCNode = mitk::DataNode::New(); newPFCNode->SetName("AND"); newPFCNode->SetData(PFCAnd); AddCompositeToDatastorage(newPFCNode, m_SelectedPF); m_SelectedPF.clear(); m_SelectedPF.push_back(newPFCNode); UpdateGui(); } void QmitkFiberProcessingView::GenerateOrComposite() { mitk::PlanarFigureComposite::Pointer PFCOr = mitk::PlanarFigureComposite::New(); PFCOr->setOperationType(mitk::PlanarFigureComposite::OR); mitk::DataNode::Pointer newPFCNode; newPFCNode = mitk::DataNode::New(); newPFCNode->SetName("OR"); newPFCNode->SetData(PFCOr); AddCompositeToDatastorage(newPFCNode, m_SelectedPF); m_SelectedPF.clear(); m_SelectedPF.push_back(newPFCNode); UpdateGui(); } void QmitkFiberProcessingView::GenerateNotComposite() { mitk::PlanarFigureComposite::Pointer PFCNot = mitk::PlanarFigureComposite::New(); PFCNot->setOperationType(mitk::PlanarFigureComposite::NOT); mitk::DataNode::Pointer newPFCNode; newPFCNode = mitk::DataNode::New(); newPFCNode->SetName("NOT"); newPFCNode->SetData(PFCNot); AddCompositeToDatastorage(newPFCNode, m_SelectedPF); m_SelectedPF.clear(); m_SelectedPF.push_back(newPFCNode); UpdateGui(); } void QmitkFiberProcessingView::AddCompositeToDatastorage(mitk::DataNode::Pointer pfc, std::vector children, mitk::DataNode::Pointer parentNode ) { pfc->SetSelected(true); if (parentNode.IsNotNull()) GetDataStorage()->Add(pfc, parentNode); else GetDataStorage()->Add(pfc); for (auto child : children) { if (dynamic_cast(child->GetData())) { mitk::DataNode::Pointer newChild; newChild = mitk::DataNode::New(); newChild->SetData(dynamic_cast(child->GetData())); newChild->SetName( child->GetName() ); newChild->SetBoolProperty("planarfigure.3drendering", true); newChild->SetBoolProperty("planarfigure.3drendering.fill", true); GetDataStorage()->Add(newChild, pfc); GetDataStorage()->Remove(child); } else if (dynamic_cast(child->GetData())) { mitk::DataNode::Pointer newChild; newChild = mitk::DataNode::New(); newChild->SetData(dynamic_cast(child->GetData())); newChild->SetName( child->GetName() ); std::vector< mitk::DataNode::Pointer > grandChildVector; mitk::DataStorage::SetOfObjects::ConstPointer grandchildren = GetDataStorage()->GetDerivations(child); for( mitk::DataStorage::SetOfObjects::const_iterator it = grandchildren->begin(); it != grandchildren->end(); ++it ) grandChildVector.push_back(*it); AddCompositeToDatastorage(newChild, grandChildVector, pfc); GetDataStorage()->Remove(child); } } UpdateGui(); } void QmitkFiberProcessingView::CopyBundles() { if ( m_SelectedFB.empty() ){ QMessageBox::information( NULL, "Warning", "Select at least one fiber bundle!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least one fiber bundle!"; return; } for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); mitk::FiberBundle::Pointer newFib = fib->GetDeepCopy(); node->SetVisibility(false); QString name(""); name += QString(m_SelectedFB.at(0)->GetName().c_str()); name += "_copy"; mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newFib); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); } UpdateGui(); } void QmitkFiberProcessingView::JoinBundles() { if ( m_SelectedFB.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; return; } mitk::FiberBundle::Pointer newBundle = dynamic_cast(m_SelectedFB.at(0)->GetData()); m_SelectedFB.at(0)->SetVisibility(false); QString name(""); name += QString(m_SelectedFB.at(0)->GetName().c_str()); for (unsigned int i=1; iAddBundle(dynamic_cast(m_SelectedFB.at(i)->GetData())); name += "+"+QString(m_SelectedFB.at(i)->GetName().c_str()); m_SelectedFB.at(i)->SetVisibility(false); } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); UpdateGui(); } void QmitkFiberProcessingView::SubstractBundles() { if ( m_SelectedFB.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; return; } mitk::FiberBundle::Pointer newBundle = dynamic_cast(m_SelectedFB.at(0)->GetData()); m_SelectedFB.at(0)->SetVisibility(false); QString name(""); name += QString(m_SelectedFB.at(0)->GetName().c_str()); for (unsigned int i=1; iSubtractBundle(dynamic_cast(m_SelectedFB.at(i)->GetData())); if (newBundle.IsNull()) break; name += "-"+QString(m_SelectedFB.at(i)->GetName().c_str()); m_SelectedFB.at(i)->SetVisibility(false); } if (newBundle.IsNull()) { QMessageBox::information(NULL, "No output generated:", "The resulting fiber bundle contains no fibers. Did you select the fiber bundles in the correct order? X-Y is not equal to Y-X!"); return; } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); UpdateGui(); } void QmitkFiberProcessingView::ResampleSelectedBundles() { double factor = this->m_Controls->m_SmoothFibersBox->value(); for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); fib->ResampleSpline(factor); } RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::CompressSelectedBundles() { double factor = this->m_Controls->m_ErrorThresholdBox->value(); for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); fib->Compress(factor); + fib->ColorFibersByOrientation(); } RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::DoImageColorCoding() { if (m_Controls->m_ColorMapBox->GetSelectedNode().IsNull()) { QMessageBox::information(NULL, "Bundle coloring aborted:", "No image providing the scalar values for coloring the selected bundle available."); return; } for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); fib->ColorFibersByScalarMap(dynamic_cast(m_Controls->m_ColorMapBox->GetSelectedNode()->GetData()), m_Controls->m_FiberOpacityBox->isChecked()); } RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::DoCurvatureColorCoding() { for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); fib->ColorFibersByCurvature(); } RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberProcessingView::MirrorFibers() { unsigned int axis = this->m_Controls->m_MirrorFibersBox->currentIndex(); for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); if (m_SelectedImage.IsNotNull()) fib->SetReferenceGeometry(m_SelectedImage->GetGeometry()); fib->MirrorFibers(axis); } for (auto surf : m_SelectedSurfaces) { vtkSmartPointer poly = surf->GetVtkPolyData(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); for (int i=0; iGetNumberOfPoints(); i++) { double* point = poly->GetPoint(i); point[axis] *= -1; vtkNewPoints->InsertNextPoint(point); } poly->SetPoints(vtkNewPoints); surf->CalculateBoundingBox(); } RenderingManager::GetInstance()->RequestUpdateAll(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h index 1bc6121983..5e794efc5f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h @@ -1,191 +1,192 @@ /*=================================================================== 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 QmitkFiberProcessingView_h #define QmitkFiberProcessingView_h #include #include "ui_QmitkFiberProcessingViewControls.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*! \brief View to process fiber bundles. Supplies methods to extract fibers from the bundle, fiber resampling, mirroring, join and subtract bundles and much more. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkFiberProcessingView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: typedef itk::Image< unsigned char, 3 > itkUCharImageType; static const std::string VIEW_ID; QmitkFiberProcessingView(); virtual ~QmitkFiberProcessingView(); virtual void CreateQtPartControl(QWidget *parent) override; virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) override; virtual void StdMultiWidgetNotAvailable() override; virtual void Activated() override; protected slots: void OnDrawCircle(); ///< add circle interactors etc. void OnDrawPolygon(); ///< add circle interactors etc. void GenerateAndComposite(); void GenerateOrComposite(); void GenerateNotComposite(); void CopyBundles(); ///< add copies of selected bundles to data storage void JoinBundles(); ///< merge selected fiber bundles void SubstractBundles(); ///< subtract bundle A from bundle B. Not commutative! Defined by order of selection. void GenerateRoiImage(); ///< generate binary image of selected planar figures. void Remove(); void Extract(); void Modify(); void UpdateGui(); ///< update button activity etc. dpending on current datamanager selection + void OnMaskExtractionChanged(); virtual void AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey = NULL, mitk::BaseProperty *property = NULL ); protected: void MirrorFibers(); ///< mirror bundle on the specified plane void ResampleSelectedBundles(); ///< smooth fiber bundle using the specified number of sampling points per cm. void DoImageColorCoding(); ///< color fibers by selected scalar image void DoCurvatureColorCoding(); ///< color fibers by curvature void CompressSelectedBundles(); ///< remove points below certain error threshold void WeightFibers(); void RemoveWithMask(bool removeInside); void RemoveDir(); void ApplyCurvatureThreshold(); ///< remove/split fibers with a too high curvature threshold void PruneBundle(); ///< remove too short/too long fibers void ExtractWithMask(bool onlyEnds, bool invert); void ExtractWithPlanarFigure(); /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ) override; Ui::QmitkFiberProcessingViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; /** Connection from VTK to ITK */ template void ConnectPipelines(VTK_Exporter* exporter, ITK_Importer importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template < typename TPixel, unsigned int VImageDimension > void InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ); template < typename TPixel, unsigned int VImageDimension > void InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::BaseGeometry* planegeo3D, int additionalIndex ); int m_CircleCounter; ///< used for data node naming int m_PolygonCounter; ///< used for data node naming std::vector m_SelectedFB; ///< selected fiber bundle nodes std::vector m_SelectedPF; ///< selected planar figure nodes std::vector m_SelectedSurfaces; mitk::Image::Pointer m_SelectedImage; mitk::Image::Pointer m_InternalImage; mitk::PlanarFigure::Pointer m_PlanarFigure; itkUCharImageType::Pointer m_InternalImageMask3D; itkUCharImageType::Pointer m_PlanarFigureImage; float m_UpsamplingFactor; ///< upsampling factor for all image generations mitk::DataNode::Pointer m_MaskImageNode; void AddCompositeToDatastorage(mitk::DataNode::Pointer pfc, std::vector children, mitk::DataNode::Pointer parentNode=NULL); void debugPFComposition(mitk::PlanarFigureComposite::Pointer , int ); void WritePfToImage(mitk::DataNode::Pointer node, mitk::Image* image); mitk::DataNode::Pointer GenerateTractDensityImage(mitk::FiberBundle::Pointer fib, bool binary, bool absolute); mitk::DataNode::Pointer GenerateColorHeatmap(mitk::FiberBundle::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsImage(mitk::FiberBundle::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsPointSet(mitk::FiberBundle::Pointer fib); void NodeAdded( const mitk::DataNode* node ) override; void NodeRemoved(const mitk::DataNode* node) override; }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui index 3e95e0f184..e75e7cf762 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingViewControls.ui @@ -1,1399 +1,1416 @@ QmitkFiberProcessingViewControls 0 0 386 540 Form 0 0 0 - 355 - 330 + 354 + 347 Fiber Extraction Extract a fiber subset from the selected fiber bundle using manually placed planar figures as waypoints or binary regions of interest. false 0 0 200 16777215 11 Extract fibers passing through selected ROI or composite ROI. Select ROI and fiber bundle to execute. Extract Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 9 9 9 9 0 false 0 0 16777215 16777215 11 Generate a binary image containing all selected ROIs. Select at least one ROI (planar figure) and a reference fiber bundle or image. Generate ROI Image 0 0 200 0 16777215 60 QFrame::NoFrame QFrame::Raised 0 0 0 0 false 60 16777215 Create OR composition with selected ROIs. OR Qt::Horizontal 40 20 false 60 16777215 Create NOT composition from selected ROI. NOT false 60 16777215 Create AND composition with selected ROIs. AND 0 0 200 0 16777215 60 QFrame::NoFrame QFrame::Raised 0 0 0 0 30 30 Draw circular ROI. Select reference fiber bundle to execute. :/QmitkDiffusionImaging/circle.png:/QmitkDiffusionImaging/circle.png 32 32 false true Qt::Horizontal 40 20 30 30 Draw polygonal ROI. Select reference fiber bundle to execute. :/QmitkDiffusionImaging/polygon.png:/QmitkDiffusionImaging/polygon.png 32 32 true true 0 0 Extract using planar figures Extract using binary ROI image QFrame::NoFrame QFrame::Raised 0 0 0 0 - + + + + Extract fibers: + + + + + + + Min. overlap: + + + + 0 0 Ending in mask Not ending in mask Passing mask Not passing mask - - - - Extract fibers: - - - - + Both ends true + + + + 1.000000000000000 + + + 0.100000000000000 + + + 0 0 - 355 - 380 + 354 + 342 Fiber Removal Remove fibers that satisfy certain criteria from the selected bundle. 0 0 Remove fibers in direction Remove fibers by length Remove fibers by curvature Remove fiber parts outside mask Remove fiber parts inside mask QFrame::NoFrame QFrame::Raised 0 0 0 0 Qt::Horizontal 40 20 Minimum fiber length in mm 0 999999999 20 Max. Length: Min. Length: Maximum fiber length in mm 0 999999999 300 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 X: Y: Z: Angle: Angular deviation threshold in degree 1 90.000000000000000 1.000000000000000 25.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 If unchecked, the fiber exceeding the threshold will be split in two instead of removed. Remove Fiber false QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Max. Angular Deviation: Qt::Horizontal 40 20 Maximum angular deviation in degree 180.000000000000000 0.100000000000000 30.000000000000000 Distance: Distance in mm 1 999.000000000000000 1.000000000000000 5.000000000000000 false 0 0 200 16777215 11 Remove Qt::Vertical 20 40 0 0 - 355 - 349 + 368 + 309 Bundle Modification Modify the selected bundle with operations such as fiber resampling, FA coloring, etc. QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Error threshold in mm: 999999999.000000000000000 0.100000000000000 0.100000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Sagittal Coronal Axial Select direction: QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Scalar map: If checked, the image values are not only used to color the fibers but are also used as opaxity values. Values as opacity true 0 0 Resample fibers Compress fibers Color fibers by scalar map (e.g. FA) Mirror fibers Weight Bundle Color fibers by curvature QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0.010000000000000 999999999.000000000000000 0.100000000000000 1.000000000000000 Point distance in mm: Qt::Vertical 20 40 false 0 0 200 16777215 11 Execute QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Weight: 7 999999999.000000000000000 0.100000000000000 1.000000000000000 0 0 368 152 Bundle Operations Join, subtract or copy bundles. false 0 0 200 16777215 11 Returns all fibers contained in bundle X that are not contained in bundle Y (not commutative!). Select at least two fiber bundles to execute. Substract Qt::Vertical 20 40 false 0 0 200 16777215 11 Merge selected fiber bundles. Select at least two fiber bundles to execute. Join false 0 0 200 16777215 11 Merge selected fiber bundles. Select at least two fiber bundles to execute. Copy Please Select Input Data <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> true <html><head/><body><p><span style=" color:#969696;">needed for extraction</span></p></body></html> true Input DTI Fiber Bundle: Binary seed ROI. If not specified, the whole image area is seeded. ROI: Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp index 471d7d5bb1..434620e3aa 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp @@ -1,2898 +1,2897 @@ /*=================================================================== 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 // Blueberry #include #include // Qmitk #include "QmitkFiberfoxView.h" // MITK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define RAPIDXML_NO_EXCEPTIONS #include #include #include #include #include "usModuleRegistry.h" #include #include #include #include #include #include #include #include #include #include "mitkNodePredicateDataType.h" #include #include #include #include #define _USE_MATH_DEFINES #include QmitkFiberfoxWorker::QmitkFiberfoxWorker(QmitkFiberfoxView* view) : m_View(view) { } void QmitkFiberfoxWorker::run() { try{ m_View->m_TractsToDwiFilter->Update(); } catch( ... ) { } m_View->m_Thread.quit(); } const std::string QmitkFiberfoxView::VIEW_ID = "org.mitk.views.fiberfoxview"; QmitkFiberfoxView::QmitkFiberfoxView() : QmitkAbstractView() , m_Controls( 0 ) , m_SelectedImageNode( NULL ) , m_Worker(this) , m_ThreadIsRunning(false) { m_Worker.moveToThread(&m_Thread); connect(&m_Thread, SIGNAL(started()), this, SLOT(BeforeThread())); connect(&m_Thread, SIGNAL(started()), &m_Worker, SLOT(run())); connect(&m_Thread, SIGNAL(finished()), this, SLOT(AfterThread())); // connect(&m_Thread, SIGNAL(terminated()), this, SLOT(AfterThread())); m_SimulationTimer = new QTimer(this); } void QmitkFiberfoxView::KillThread() { MITK_INFO << "Aborting DWI simulation."; m_TractsToDwiFilter->SetAbortGenerateData(true); m_Controls->m_AbortSimulationButton->setEnabled(false); m_Controls->m_AbortSimulationButton->setText("Aborting simulation ..."); } void QmitkFiberfoxView::BeforeThread() { m_SimulationTime = QTime::currentTime(); m_SimulationTimer->start(100); m_Controls->m_AbortSimulationButton->setVisible(true); m_Controls->m_GenerateImageButton->setVisible(false); m_Controls->m_SimulationStatusText->setVisible(true); m_ThreadIsRunning = true; } void QmitkFiberfoxView::AfterThread() { UpdateSimulationStatus(); m_SimulationTimer->stop(); m_Controls->m_AbortSimulationButton->setVisible(false); m_Controls->m_AbortSimulationButton->setEnabled(true); m_Controls->m_AbortSimulationButton->setText("Abort simulation"); m_Controls->m_GenerateImageButton->setVisible(true); m_ThreadIsRunning = false; QString statusText; FiberfoxParameters parameters; mitk::Image::Pointer mitkImage = mitk::Image::New(); statusText = QString(m_TractsToDwiFilter->GetStatusText().c_str()); if (m_TractsToDwiFilter->GetAbortGenerateData()) { MITK_INFO << "Simulation aborted."; return; } parameters = m_TractsToDwiFilter->GetParameters(); mitkImage = mitk::GrabItkImageMemory( m_TractsToDwiFilter->GetOutput() ); mitkImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() )); mitkImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.m_Bvalue )); mitk::DiffusionPropertyHelper propertyHelper( mitkImage ); propertyHelper.InitializeImage(); parameters.m_Misc.m_ResultNode->SetData( mitkImage ); GetDataStorage()->Add(parameters.m_Misc.m_ResultNode, parameters.m_Misc.m_ParentNode); parameters.m_Misc.m_ResultNode->SetProperty( "levelwindow", mitk::LevelWindowProperty::New(m_TractsToDwiFilter->GetLevelWindow()) ); if (m_Controls->m_VolumeFractionsBox->isChecked()) { std::vector< itk::TractsToDWIImageFilter< short >::ItkDoubleImgType::Pointer > volumeFractions = m_TractsToDwiFilter->GetVolumeFractions(); for (unsigned int k=0; kInitializeByItk(volumeFractions.at(k).GetPointer()); image->SetVolume(volumeFractions.at(k)->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("CompartmentVolume-"+QString::number(k).toStdString()); GetDataStorage()->Add(node, parameters.m_Misc.m_ResultNode); } if (m_TractsToDwiFilter->GetPhaseImage().IsNotNull()) { mitk::Image::Pointer phaseImage = mitk::Image::New(); itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer itkPhase = m_TractsToDwiFilter->GetPhaseImage(); phaseImage = mitk::GrabItkImageMemory( itkPhase.GetPointer() ); mitk::DataNode::Pointer phaseNode = mitk::DataNode::New(); phaseNode->SetData( phaseImage ); phaseNode->SetName("Phase Image"); GetDataStorage()->Add(phaseNode, parameters.m_Misc.m_ResultNode); } if (m_TractsToDwiFilter->GetKspaceImage().IsNotNull()) { mitk::Image::Pointer image = mitk::Image::New(); itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer itkImage = m_TractsToDwiFilter->GetKspaceImage(); image = mitk::GrabItkImageMemory( itkImage.GetPointer() ); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("k-Space"); GetDataStorage()->Add(node, parameters.m_Misc.m_ResultNode); } { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(m_TractsToDwiFilter->GetCoilPointset()); node->SetName("Coil Positions"); node->SetProperty("pointsize", mitk::FloatProperty::New(parameters.m_SignalGen.m_ImageSpacing[0]/4)); node->SetProperty("color", mitk::ColorProperty::New(0, 1, 0)); GetDataStorage()->Add(node, parameters.m_Misc.m_ResultNode); } } m_TractsToDwiFilter = NULL; if (parameters.m_Misc.m_AfterSimulationMessage.size()>0) QMessageBox::information( NULL, "Warning", parameters.m_Misc.m_AfterSimulationMessage.c_str()); mitk::BaseData::Pointer basedata = parameters.m_Misc.m_ResultNode->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } if (!parameters.m_Misc.m_OutputPath.empty()) { try{ QString outputFileName(parameters.m_Misc.m_OutputPath.c_str()); outputFileName += parameters.m_Misc.m_ResultNode->GetName().c_str(); outputFileName.replace(QString("."), QString("_")); SaveParameters(outputFileName+".ffp"); outputFileName += ".dwi"; QString status("Saving output image to "); status += outputFileName; m_Controls->m_SimulationStatusText->append(status); mitk::IOUtil::Save(mitkImage, outputFileName.toStdString()); m_Controls->m_SimulationStatusText->append("File saved successfully."); } catch (itk::ExceptionObject &e) { QString status("Exception during DWI writing: "); status += e.GetDescription(); m_Controls->m_SimulationStatusText->append(status); } catch (...) { m_Controls->m_SimulationStatusText->append("Unknown exception during DWI writing!"); } } parameters.m_SignalGen.m_FrequencyMap = NULL; } void QmitkFiberfoxView::UpdateSimulationStatus() { QString statusText = QString(m_TractsToDwiFilter->GetStatusText().c_str()); if (QString::compare(m_SimulationStatusText,statusText)!=0) { m_Controls->m_SimulationStatusText->clear(); m_Controls->m_SimulationStatusText->setText(statusText); QScrollBar *vScrollBar = m_Controls->m_SimulationStatusText->verticalScrollBar(); vScrollBar->triggerAction(QScrollBar::SliderToMaximum); } } // Destructor QmitkFiberfoxView::~QmitkFiberfoxView() { delete m_SimulationTimer; } void QmitkFiberfoxView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberfoxViewControls; m_Controls->setupUi( parent ); m_Controls->m_StickWidget1->setVisible(true); m_Controls->m_StickWidget2->setVisible(false); m_Controls->m_ZeppelinWidget1->setVisible(false); m_Controls->m_ZeppelinWidget2->setVisible(false); m_Controls->m_TensorWidget1->setVisible(false); m_Controls->m_TensorWidget2->setVisible(false); m_Controls->m_BallWidget1->setVisible(true); m_Controls->m_BallWidget2->setVisible(false); m_Controls->m_BallWidget2->SetT1(4500); m_Controls->m_AstrosticksWidget1->setVisible(false); m_Controls->m_AstrosticksWidget2->setVisible(false); m_Controls->m_AstrosticksWidget2->SetT1(4500); m_Controls->m_DotWidget1->setVisible(false); m_Controls->m_DotWidget2->setVisible(false); m_Controls->m_DotWidget2->SetT1(4500); m_Controls->m_PrototypeWidget1->setVisible(false); m_Controls->m_PrototypeWidget2->setVisible(false); m_Controls->m_PrototypeWidget3->setVisible(false); m_Controls->m_PrototypeWidget4->setVisible(false); m_Controls->m_PrototypeWidget3->SetMinFa(0.0); m_Controls->m_PrototypeWidget3->SetMaxFa(0.15); m_Controls->m_PrototypeWidget4->SetMinFa(0.0); m_Controls->m_PrototypeWidget4->SetMaxFa(0.15); m_Controls->m_PrototypeWidget3->SetMinAdc(0.0); m_Controls->m_PrototypeWidget3->SetMaxAdc(0.001); m_Controls->m_PrototypeWidget4->SetMinAdc(0.003); m_Controls->m_PrototypeWidget4->SetMaxAdc(0.004); m_Controls->m_Comp2FractionFrame->setVisible(false); m_Controls->m_Comp4FractionFrame->setVisible(false); m_Controls->m_DiffusionPropsMessage->setVisible(false); m_Controls->m_GeometryMessage->setVisible(false); m_Controls->m_AdvancedSignalOptionsFrame->setVisible(false); m_Controls->m_AdvancedFiberOptionsFrame->setVisible(false); m_Controls->m_VarianceBox->setVisible(false); m_Controls->m_NoiseFrame->setVisible(false); m_Controls->m_GhostFrame->setVisible(false); m_Controls->m_DistortionsFrame->setVisible(false); m_Controls->m_EddyFrame->setVisible(false); m_Controls->m_SpikeFrame->setVisible(false); m_Controls->m_AliasingFrame->setVisible(false); m_Controls->m_MotionArtifactFrame->setVisible(false); m_ParameterFile = QDir::currentPath()+"/param.ffp"; m_Controls->m_AbortSimulationButton->setVisible(false); m_Controls->m_SimulationStatusText->setVisible(false); m_Controls->m_FrequencyMapBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_Comp1VolumeFraction->SetDataStorage(this->GetDataStorage()); m_Controls->m_Comp2VolumeFraction->SetDataStorage(this->GetDataStorage()); m_Controls->m_Comp3VolumeFraction->SetDataStorage(this->GetDataStorage()); m_Controls->m_Comp4VolumeFraction->SetDataStorage(this->GetDataStorage()); m_Controls->m_MaskComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_TemplateComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_FiberBundleComboBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isFiberBundle = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isMitkImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateIsDWI::Pointer isDwi = mitk::NodePredicateIsDWI::New( ); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isQbi = mitk::NodePredicateDataType::New("QBallImage"); mitk::NodePredicateOr::Pointer isDiffusionImage = mitk::NodePredicateOr::New(isDwi, isDti); isDiffusionImage = mitk::NodePredicateOr::New(isDiffusionImage, isQbi); mitk::NodePredicateNot::Pointer noDiffusionImage = mitk::NodePredicateNot::New(isDiffusionImage); mitk::NodePredicateAnd::Pointer isNonDiffMitkImage = mitk::NodePredicateAnd::New(isMitkImage, noDiffusionImage); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isBinaryMitkImage = mitk::NodePredicateAnd::New( isNonDiffMitkImage, isBinaryPredicate ); m_Controls->m_FrequencyMapBox->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp1VolumeFraction->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp1VolumeFraction->SetZeroEntryText("--"); m_Controls->m_Comp2VolumeFraction->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp2VolumeFraction->SetZeroEntryText("--"); m_Controls->m_Comp3VolumeFraction->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp3VolumeFraction->SetZeroEntryText("--"); m_Controls->m_Comp4VolumeFraction->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp4VolumeFraction->SetZeroEntryText("--"); m_Controls->m_MaskComboBox->SetPredicate(isBinaryMitkImage); m_Controls->m_MaskComboBox->SetZeroEntryText("--"); m_Controls->m_TemplateComboBox->SetPredicate(isMitkImage); m_Controls->m_TemplateComboBox->SetZeroEntryText("--"); m_Controls->m_FiberBundleComboBox->SetPredicate(isFiberBundle); m_Controls->m_FiberBundleComboBox->SetZeroEntryText("--"); QFont font; font.setFamily("Courier"); font.setStyleHint(QFont::Monospace); font.setFixedPitch(true); font.setPointSize(8); m_Controls->m_SimulationStatusText->setFont(font); connect( m_SimulationTimer, SIGNAL(timeout()), this, SLOT(UpdateSimulationStatus()) ); connect((QObject*) m_Controls->m_AbortSimulationButton, SIGNAL(clicked()), (QObject*) this, SLOT(KillThread())); connect((QObject*) m_Controls->m_GenerateImageButton, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateImage())); connect((QObject*) m_Controls->m_GenerateFibersButton, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateFibers())); connect((QObject*) m_Controls->m_CircleButton, SIGNAL(clicked()), (QObject*) this, SLOT(OnDrawROI())); connect((QObject*) m_Controls->m_FlipButton, SIGNAL(clicked()), (QObject*) this, SLOT(OnFlipButton())); connect((QObject*) m_Controls->m_JoinBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(JoinBundles())); connect((QObject*) m_Controls->m_VarianceBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnVarianceChanged(double))); connect((QObject*) m_Controls->m_DistributionBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnDistributionChanged(int))); connect((QObject*) m_Controls->m_FiberDensityBox, SIGNAL(valueChanged(int)), (QObject*) this, SLOT(OnFiberDensityChanged(int))); connect((QObject*) m_Controls->m_FiberSamplingBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnFiberSamplingChanged(double))); connect((QObject*) m_Controls->m_TensionBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnTensionChanged(double))); connect((QObject*) m_Controls->m_ContinuityBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnContinuityChanged(double))); connect((QObject*) m_Controls->m_BiasBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnBiasChanged(double))); connect((QObject*) m_Controls->m_AddNoise, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddNoise(int))); connect((QObject*) m_Controls->m_AddGhosts, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddGhosts(int))); connect((QObject*) m_Controls->m_AddDistortions, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddDistortions(int))); connect((QObject*) m_Controls->m_AddEddy, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddEddy(int))); connect((QObject*) m_Controls->m_AddSpikes, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddSpikes(int))); connect((QObject*) m_Controls->m_AddAliasing, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddAliasing(int))); connect((QObject*) m_Controls->m_AddMotion, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddMotion(int))); connect((QObject*) m_Controls->m_ConstantRadiusBox, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnConstantRadius(int))); connect((QObject*) m_Controls->m_CopyBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(CopyBundles())); connect((QObject*) m_Controls->m_TransformBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(ApplyTransform())); connect((QObject*) m_Controls->m_AlignOnGrid, SIGNAL(clicked()), (QObject*) this, SLOT(AlignOnGrid())); connect((QObject*) m_Controls->m_Compartment1Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp1ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_Compartment2Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp2ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_Compartment3Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp3ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_Compartment4Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp4ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_AdvancedOptionsBox, SIGNAL( stateChanged(int)), (QObject*) this, SLOT(ShowAdvancedOptions(int))); connect((QObject*) m_Controls->m_AdvancedOptionsBox_2, SIGNAL( stateChanged(int)), (QObject*) this, SLOT(ShowAdvancedOptions(int))); connect((QObject*) m_Controls->m_SaveParametersButton, SIGNAL(clicked()), (QObject*) this, SLOT(SaveParameters())); connect((QObject*) m_Controls->m_LoadParametersButton, SIGNAL(clicked()), (QObject*) this, SLOT(LoadParameters())); connect((QObject*) m_Controls->m_OutputPathButton, SIGNAL(clicked()), (QObject*) this, SLOT(SetOutputPath())); connect((QObject*) m_Controls->m_MaskComboBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnMaskSelected(int))); connect((QObject*) m_Controls->m_TemplateComboBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnTemplateSelected(int))); connect((QObject*) m_Controls->m_FiberBundleComboBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnFibSelected(int))); } } void QmitkFiberfoxView::OnMaskSelected(int value) { UpdateGui(); } void QmitkFiberfoxView::OnTemplateSelected(int value) { UpdateGui(); } void QmitkFiberfoxView::OnFibSelected(int value) { UpdateGui(); } template< class ScalarType > -FiberfoxParameters< ScalarType > QmitkFiberfoxView::UpdateImageParameters(bool all) +FiberfoxParameters< ScalarType > QmitkFiberfoxView::UpdateImageParameters(bool all, bool save) { FiberfoxParameters< ScalarType > parameters; parameters.m_Misc.m_OutputPath = ""; parameters.m_Misc.m_CheckAdvancedFiberOptionsBox = m_Controls->m_AdvancedOptionsBox->isChecked(); parameters.m_Misc.m_CheckAdvancedSignalOptionsBox = m_Controls->m_AdvancedOptionsBox_2->isChecked(); parameters.m_Misc.m_CheckOutputVolumeFractionsBox = m_Controls->m_VolumeFractionsBox->isChecked(); parameters.m_Misc.m_AfterSimulationMessage = ""; string outputPath = m_Controls->m_SavePathEdit->text().toStdString(); if (outputPath.compare("-")!=0) { parameters.m_Misc.m_OutputPath = outputPath; parameters.m_Misc.m_OutputPath += "/"; } switch(m_Controls->m_DistributionBox->currentIndex()) { case 0: parameters.m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; break; case 1: parameters.m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_GAUSSIAN; break; default: parameters.m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; } parameters.m_FiberGen.m_Variance = m_Controls->m_VarianceBox->value(); parameters.m_FiberGen.m_Density = m_Controls->m_FiberDensityBox->value(); parameters.m_FiberGen.m_Sampling = m_Controls->m_FiberSamplingBox->value(); parameters.m_FiberGen.m_Tension = m_Controls->m_TensionBox->value(); parameters.m_FiberGen.m_Continuity = m_Controls->m_ContinuityBox->value(); parameters.m_FiberGen.m_Bias = m_Controls->m_BiasBox->value(); parameters.m_FiberGen.m_Rotation[0] = m_Controls->m_XrotBox->value(); parameters.m_FiberGen.m_Rotation[1] = m_Controls->m_YrotBox->value(); parameters.m_FiberGen.m_Rotation[2] = m_Controls->m_ZrotBox->value(); parameters.m_FiberGen.m_Translation[0] = m_Controls->m_XtransBox->value(); parameters.m_FiberGen.m_Translation[1] = m_Controls->m_YtransBox->value(); parameters.m_FiberGen.m_Translation[2] = m_Controls->m_ZtransBox->value(); parameters.m_FiberGen.m_Scale[0] = m_Controls->m_XscaleBox->value(); parameters.m_FiberGen.m_Scale[1] = m_Controls->m_YscaleBox->value(); parameters.m_FiberGen.m_Scale[2] = m_Controls->m_ZscaleBox->value(); if (!all) return parameters; if (m_Controls->m_MaskComboBox->GetSelectedNode().IsNotNull()) { mitk::Image::Pointer mitkMaskImage = dynamic_cast(m_Controls->m_MaskComboBox->GetSelectedNode()->GetData()); mitk::CastToItkImage(mitkMaskImage, parameters.m_SignalGen.m_MaskImage); itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage(parameters.m_SignalGen.m_MaskImage); duplicator->Update(); parameters.m_SignalGen.m_MaskImage = duplicator->GetOutput(); } if (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull() && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( m_Controls->m_TemplateComboBox->GetSelectedNode())) // use parameters of selected DWI { mitk::Image::Pointer dwi = dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(dwi, itkVectorImagePointer); parameters.m_SignalGen.m_ImageRegion = itkVectorImagePointer->GetLargestPossibleRegion(); parameters.m_SignalGen.m_ImageSpacing = itkVectorImagePointer->GetSpacing(); parameters.m_SignalGen.m_ImageOrigin = itkVectorImagePointer->GetOrigin(); parameters.m_SignalGen.m_ImageDirection = itkVectorImagePointer->GetDirection(); parameters.m_SignalGen.m_Bvalue = static_cast(dwi->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue(); parameters.m_SignalGen.SetGradienDirections(static_cast( dwi->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer()); } else if (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull()) // use geometry of selected image { mitk::Image::Pointer img = dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()); itk::Image< float, 3 >::Pointer itkImg = itk::Image< float, 3 >::New(); CastToItkImage< itk::Image< float, 3 > >(img, itkImg); parameters.m_SignalGen.m_ImageRegion = itkImg->GetLargestPossibleRegion(); parameters.m_SignalGen.m_ImageSpacing = itkImg->GetSpacing(); parameters.m_SignalGen.m_ImageOrigin = itkImg->GetOrigin(); parameters.m_SignalGen.m_ImageDirection = itkImg->GetDirection(); parameters.m_SignalGen.SetNumWeightedVolumes(m_Controls->m_NumGradientsBox->value()); parameters.m_SignalGen.m_Bvalue = m_Controls->m_BvalueBox->value(); } else if (parameters.m_SignalGen.m_MaskImage.IsNotNull()) // use geometry of mask image { ItkUcharImgType::Pointer itkImg = parameters.m_SignalGen.m_MaskImage; parameters.m_SignalGen.m_ImageRegion = itkImg->GetLargestPossibleRegion(); parameters.m_SignalGen.m_ImageSpacing = itkImg->GetSpacing(); parameters.m_SignalGen.m_ImageOrigin = itkImg->GetOrigin(); parameters.m_SignalGen.m_ImageDirection = itkImg->GetDirection(); parameters.m_SignalGen.SetNumWeightedVolumes(m_Controls->m_NumGradientsBox->value()); parameters.m_SignalGen.m_Bvalue = m_Controls->m_BvalueBox->value(); } else // use GUI parameters { parameters.m_SignalGen.m_ImageRegion.SetSize(0, m_Controls->m_SizeX->value()); parameters.m_SignalGen.m_ImageRegion.SetSize(1, m_Controls->m_SizeY->value()); parameters.m_SignalGen.m_ImageRegion.SetSize(2, m_Controls->m_SizeZ->value()); parameters.m_SignalGen.m_ImageSpacing[0] = m_Controls->m_SpacingX->value(); parameters.m_SignalGen.m_ImageSpacing[1] = m_Controls->m_SpacingY->value(); parameters.m_SignalGen.m_ImageSpacing[2] = m_Controls->m_SpacingZ->value(); parameters.m_SignalGen.m_ImageOrigin[0] = parameters.m_SignalGen.m_ImageSpacing[0]/2; parameters.m_SignalGen.m_ImageOrigin[1] = parameters.m_SignalGen.m_ImageSpacing[1]/2; parameters.m_SignalGen.m_ImageOrigin[2] = parameters.m_SignalGen.m_ImageSpacing[2]/2; parameters.m_SignalGen.m_ImageDirection.SetIdentity(); parameters.m_SignalGen.SetNumWeightedVolumes(m_Controls->m_NumGradientsBox->value()); parameters.m_SignalGen.m_Bvalue = m_Controls->m_BvalueBox->value(); parameters.m_SignalGen.GenerateGradientHalfShell(); } // signal relaxation parameters.m_SignalGen.m_DoSimulateRelaxation = false; - if (m_Controls->m_RelaxationBox->isChecked() && m_Controls->m_FiberBundleComboBox->GetSelectedNode().IsNotNull() ) + if (m_Controls->m_RelaxationBox->isChecked() && (m_Controls->m_FiberBundleComboBox->GetSelectedNode().IsNotNull() || save) ) { parameters.m_SignalGen.m_DoSimulateRelaxation = true; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Relaxation", BoolProperty::New(true)); parameters.m_Misc.m_ArtifactModelString += "_RELAX"; } parameters.m_SignalGen.m_SimulateKspaceAcquisition = parameters.m_SignalGen.m_DoSimulateRelaxation; // N/2 ghosts parameters.m_Misc.m_CheckAddGhostsBox = m_Controls->m_AddGhosts->isChecked(); if (m_Controls->m_AddGhosts->isChecked()) { parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; parameters.m_Misc.m_ArtifactModelString += "_GHOST"; parameters.m_SignalGen.m_KspaceLineOffset = m_Controls->m_kOffsetBox->value(); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Ghost", DoubleProperty::New(parameters.m_SignalGen.m_KspaceLineOffset)); } else parameters.m_SignalGen.m_KspaceLineOffset = 0; // Aliasing parameters.m_Misc.m_CheckAddAliasingBox = m_Controls->m_AddAliasing->isChecked(); if (m_Controls->m_AddAliasing->isChecked()) { parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; parameters.m_Misc.m_ArtifactModelString += "_ALIASING"; parameters.m_SignalGen.m_CroppingFactor = (100-m_Controls->m_WrapBox->value())/100; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Aliasing", DoubleProperty::New(m_Controls->m_WrapBox->value())); } // Spikes parameters.m_Misc.m_CheckAddSpikesBox = m_Controls->m_AddSpikes->isChecked(); if (m_Controls->m_AddSpikes->isChecked()) { parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; parameters.m_SignalGen.m_Spikes = m_Controls->m_SpikeNumBox->value(); parameters.m_SignalGen.m_SpikeAmplitude = m_Controls->m_SpikeScaleBox->value(); parameters.m_Misc.m_ArtifactModelString += "_SPIKES"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Spikes.Number", IntProperty::New(parameters.m_SignalGen.m_Spikes)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Spikes.Amplitude", DoubleProperty::New(parameters.m_SignalGen.m_SpikeAmplitude)); } // gibbs ringing parameters.m_SignalGen.m_DoAddGibbsRinging = m_Controls->m_AddGibbsRinging->isChecked(); if (m_Controls->m_AddGibbsRinging->isChecked()) { parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Ringing", BoolProperty::New(true)); parameters.m_Misc.m_ArtifactModelString += "_RINGING"; } // add distortions parameters.m_Misc.m_CheckAddDistortionsBox = m_Controls->m_AddDistortions->isChecked(); if (m_Controls->m_AddDistortions->isChecked() && m_Controls->m_FrequencyMapBox->GetSelectedNode().IsNotNull()) { mitk::DataNode::Pointer fMapNode = m_Controls->m_FrequencyMapBox->GetSelectedNode(); mitk::Image* img = dynamic_cast(fMapNode->GetData()); ItkDoubleImgType::Pointer itkImg = ItkDoubleImgType::New(); CastToItkImage< ItkDoubleImgType >(img, itkImg); if (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNull()) // use geometry of frequency map { parameters.m_SignalGen.m_ImageRegion = itkImg->GetLargestPossibleRegion(); parameters.m_SignalGen.m_ImageSpacing = itkImg->GetSpacing(); parameters.m_SignalGen.m_ImageOrigin = itkImg->GetOrigin(); parameters.m_SignalGen.m_ImageDirection = itkImg->GetDirection(); } if (parameters.m_SignalGen.m_ImageRegion.GetSize(0)==itkImg->GetLargestPossibleRegion().GetSize(0) && parameters.m_SignalGen.m_ImageRegion.GetSize(1)==itkImg->GetLargestPossibleRegion().GetSize(1) && parameters.m_SignalGen.m_ImageRegion.GetSize(2)==itkImg->GetLargestPossibleRegion().GetSize(2)) { parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage(itkImg); duplicator->Update(); parameters.m_SignalGen.m_FrequencyMap = duplicator->GetOutput(); parameters.m_Misc.m_ArtifactModelString += "_DISTORTED"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Distortions", BoolProperty::New(true)); } } parameters.m_SignalGen.m_EddyStrength = 0; parameters.m_Misc.m_CheckAddEddyCurrentsBox = m_Controls->m_AddEddy->isChecked(); if (m_Controls->m_AddEddy->isChecked()) { parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; parameters.m_SignalGen.m_EddyStrength = m_Controls->m_EddyGradientStrength->value(); parameters.m_Misc.m_ArtifactModelString += "_EDDY"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Eddy-strength", DoubleProperty::New(parameters.m_SignalGen.m_EddyStrength)); } // Motion parameters.m_SignalGen.m_DoAddMotion = false; parameters.m_SignalGen.m_DoRandomizeMotion = m_Controls->m_RandomMotion->isChecked(); parameters.m_SignalGen.m_Translation[0] = m_Controls->m_MaxTranslationBoxX->value(); parameters.m_SignalGen.m_Translation[1] = m_Controls->m_MaxTranslationBoxY->value(); parameters.m_SignalGen.m_Translation[2] = m_Controls->m_MaxTranslationBoxZ->value(); parameters.m_SignalGen.m_Rotation[0] = m_Controls->m_MaxRotationBoxX->value(); parameters.m_SignalGen.m_Rotation[1] = m_Controls->m_MaxRotationBoxY->value(); parameters.m_SignalGen.m_Rotation[2] = m_Controls->m_MaxRotationBoxZ->value(); parameters.m_SignalGen.m_MotionVolumes.clear(); parameters.m_Misc.m_MotionVolumesBox = m_Controls->m_MotionVolumesBox->text().toStdString(); - if ( m_Controls->m_AddMotion->isChecked() - && m_Controls->m_FiberBundleComboBox->GetSelectedNode().IsNotNull() ) + if ( m_Controls->m_AddMotion->isChecked() && (m_Controls->m_FiberBundleComboBox->GetSelectedNode().IsNotNull() || save) ) { parameters.m_SignalGen.m_DoAddMotion = true; parameters.m_Misc.m_ArtifactModelString += "_MOTION"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Random", BoolProperty::New(parameters.m_SignalGen.m_DoRandomizeMotion)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Translation-x", DoubleProperty::New(parameters.m_SignalGen.m_Translation[0])); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Translation-y", DoubleProperty::New(parameters.m_SignalGen.m_Translation[1])); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Translation-z", DoubleProperty::New(parameters.m_SignalGen.m_Translation[2])); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Rotation-x", DoubleProperty::New(parameters.m_SignalGen.m_Rotation[0])); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Rotation-y", DoubleProperty::New(parameters.m_SignalGen.m_Rotation[1])); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Rotation-z", DoubleProperty::New(parameters.m_SignalGen.m_Rotation[2])); if ( parameters.m_Misc.m_MotionVolumesBox == "random" ) { for ( size_t i=0; i < parameters.m_SignalGen.GetNumVolumes(); ++i ) { parameters.m_SignalGen.m_MotionVolumes.push_back( bool( rand()%2 ) ); } MITK_DEBUG << "QmitkFiberfoxView.cpp: Case m_Misc.m_MotionVolumesBox == \"random\"."; } else if ( ! parameters.m_Misc.m_MotionVolumesBox.empty() ) { stringstream stream( parameters.m_Misc.m_MotionVolumesBox ); std::vector numbers; int nummer = std::numeric_limits::max(); while( stream >> nummer ) { if( nummer < std::numeric_limits::max() ) { numbers.push_back( nummer ); } } // If a list of negative numbers is given: if( *(std::min_element( numbers.begin(), numbers.end() )) < 0 && *(std::max_element( numbers.begin(), numbers.end() )) <= 0 ) // cave: -0 == +0 { for ( size_t i=0; i < parameters.m_SignalGen.GetNumVolumes(); ++i ) { parameters.m_SignalGen.m_MotionVolumes.push_back( true ); } // set all true except those given. for( auto iter = std::begin( numbers ); iter != std::end( numbers ); ++iter ) { if ( -(*iter) < parameters.m_SignalGen.GetNumVolumes() && -(*iter) >= 0 ) { parameters.m_SignalGen.m_MotionVolumes.at( -(*iter) ) = false; } } MITK_DEBUG << "QmitkFiberfoxView.cpp: Case list of negative numbers."; } // If a list of positive numbers is given: else if( *(std::min_element( numbers.begin(), numbers.end() )) >= 0 && *(std::max_element( numbers.begin(), numbers.end() )) >= 0 ) { for ( size_t i=0; i < parameters.m_SignalGen.GetNumVolumes(); ++i ) { parameters.m_SignalGen.m_MotionVolumes.push_back( false ); } // set all false except those given. for( auto iter = std::begin( numbers ); iter != std::end( numbers ); ++iter ) { if ( *iter < parameters.m_SignalGen.GetNumVolumes() && *iter >= 0 ) { parameters.m_SignalGen.m_MotionVolumes.at( *iter ) = true; } } MITK_DEBUG << "QmitkFiberfoxView.cpp: Case list of positive numbers."; } else { MITK_ERROR << "QmitkFiberfoxView.cpp: Inconsistent list of numbers in m_MotionVolumesBox."; } } else { MITK_WARN << "QmitkFiberfoxView.cpp: Unrecognised parameters.m_Misc.m_MotionVolumesBox: " << parameters.m_Misc.m_MotionVolumesBox; parameters.m_Misc.m_MotionVolumesBox = "random"; // set default. for (int i=0; im_AcquisitionTypeBox->currentIndex(); parameters.m_SignalGen.m_CoilSensitivityProfile = (SignalGenerationParameters::CoilSensitivityProfile)m_Controls->m_CoilSensBox->currentIndex(); parameters.m_SignalGen.m_NumberOfCoils = m_Controls->m_NumCoilsBox->value(); parameters.m_SignalGen.m_PartialFourier = m_Controls->m_PartialFourier->value(); parameters.m_SignalGen.m_ReversePhase = m_Controls->m_ReversePhaseBox->isChecked(); parameters.m_SignalGen.m_tLine = m_Controls->m_LineReadoutTimeBox->value(); parameters.m_SignalGen.m_tInhom = m_Controls->m_T2starBox->value(); parameters.m_SignalGen.m_tEcho = m_Controls->m_TEbox->value(); parameters.m_SignalGen.m_tRep = m_Controls->m_TRbox->value(); parameters.m_SignalGen.m_DoDisablePartialVolume = m_Controls->m_EnforcePureFiberVoxelsBox->isChecked(); parameters.m_SignalGen.m_AxonRadius = m_Controls->m_FiberRadius->value(); parameters.m_SignalGen.m_SignalScale = m_Controls->m_SignalScaleBox->value(); double voxelVolume = parameters.m_SignalGen.m_ImageSpacing[0] * parameters.m_SignalGen.m_ImageSpacing[1] * parameters.m_SignalGen.m_ImageSpacing[2]; if ( parameters.m_SignalGen.m_SignalScale*voxelVolume > itk::NumericTraits::max()*0.75 ) { parameters.m_SignalGen.m_SignalScale = itk::NumericTraits::max()*0.75/voxelVolume; m_Controls->m_SignalScaleBox->setValue(parameters.m_SignalGen.m_SignalScale); QMessageBox::information( NULL, "Warning", "Maximum signal exceeding data type limits. Automatically adjusted to " + QString::number(parameters.m_SignalGen.m_SignalScale) + " to obtain a maximum signal of 75% of the data type maximum." " Relaxation and other effects that affect the signal intensities are not accounted for."); } // Noise parameters.m_Misc.m_CheckAddNoiseBox = m_Controls->m_AddNoise->isChecked(); parameters.m_SignalGen.m_NoiseVariance = 0; if (m_Controls->m_AddNoise->isChecked()) { double noiseVariance = m_Controls->m_NoiseLevel->value(); switch (m_Controls->m_NoiseDistributionBox->currentIndex()) { case 0: { if (noiseVariance>0) { parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; parameters.m_Misc.m_ArtifactModelString += "_COMPLEX-GAUSSIAN-"; parameters.m_SignalGen.m_NoiseVariance = m_Controls->m_NoiseLevel->value(); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Complex Gaussian")); } break; } case 1: { if (noiseVariance>0) { parameters.m_NoiseModel = std::make_shared< mitk::RicianNoiseModel >(); parameters.m_Misc.m_ArtifactModelString += "_RICIAN-"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Rician")); parameters.m_NoiseModel->SetNoiseVariance(noiseVariance); } break; } case 2: { if (noiseVariance>0) { parameters.m_NoiseModel = std::make_shared< mitk::ChiSquareNoiseModel >(); parameters.m_Misc.m_ArtifactModelString += "_CHISQUARED-"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Chi-squared")); parameters.m_NoiseModel->SetNoiseVariance(noiseVariance); } break; } default: { if (noiseVariance>0) { parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; parameters.m_Misc.m_ArtifactModelString += "_COMPLEX-GAUSSIAN-"; parameters.m_SignalGen.m_NoiseVariance = m_Controls->m_NoiseLevel->value(); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Complex Gaussian")); } break; } } if (noiseVariance>0) { parameters.m_Misc.m_ArtifactModelString += QString::number(noiseVariance).toStdString(); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Variance", DoubleProperty::New(noiseVariance)); } } // signal models { // compartment 1 switch (m_Controls->m_Compartment1Box->currentIndex()) { case 0: { mitk::StickModel* model = new mitk::StickModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity(m_Controls->m_StickWidget1->GetD()); model->SetT2(m_Controls->m_StickWidget1->GetT2()); model->SetT1(m_Controls->m_StickWidget1->GetT1()); model->m_CompartmentId = 1; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Stick"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Stick") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D", DoubleProperty::New(m_Controls->m_StickWidget1->GetD()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(model->GetT2()) ); break; } case 1: { mitk::TensorModel* model = new mitk::TensorModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity1(m_Controls->m_ZeppelinWidget1->GetD1()); model->SetDiffusivity2(m_Controls->m_ZeppelinWidget1->GetD2()); model->SetDiffusivity3(m_Controls->m_ZeppelinWidget1->GetD2()); model->SetT2(m_Controls->m_ZeppelinWidget1->GetT2()); model->SetT1(m_Controls->m_ZeppelinWidget1->GetT1()); model->m_CompartmentId = 1; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Zeppelin"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Zeppelin") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D1", DoubleProperty::New(m_Controls->m_ZeppelinWidget1->GetD1()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D2", DoubleProperty::New(m_Controls->m_ZeppelinWidget1->GetD2()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(model->GetT2()) ); break; } case 2: { mitk::TensorModel* model = new mitk::TensorModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity1(m_Controls->m_TensorWidget1->GetD1()); model->SetDiffusivity2(m_Controls->m_TensorWidget1->GetD2()); model->SetDiffusivity3(m_Controls->m_TensorWidget1->GetD3()); model->SetT2(m_Controls->m_TensorWidget1->GetT2()); model->SetT1(m_Controls->m_TensorWidget1->GetT1()); model->m_CompartmentId = 1; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Tensor"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Tensor") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D1", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD1()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D2", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD2()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D3", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD3()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(model->GetT2()) ); break; } case 3: { mitk::RawShModel* model = new mitk::RawShModel(); parameters.m_SignalGen.m_DoSimulateRelaxation = false; model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetMaxNumKernels(m_Controls->m_PrototypeWidget1->GetNumberOfSamples()); model->SetFaRange(m_Controls->m_PrototypeWidget1->GetMinFa(), m_Controls->m_PrototypeWidget1->GetMaxFa()); model->SetAdcRange(m_Controls->m_PrototypeWidget1->GetMinAdc(), m_Controls->m_PrototypeWidget1->GetMaxAdc()); model->m_CompartmentId = 1; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Prototype"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Prototype") ); break; } } if (m_Controls->m_Comp1VolumeFraction->GetSelectedNode().IsNotNull()) { mitk::DataNode::Pointer volumeNode = m_Controls->m_Comp1VolumeFraction->GetSelectedNode(); ItkDoubleImgType::Pointer comp1VolumeImage = ItkDoubleImgType::New(); mitk::Image* img = dynamic_cast(volumeNode->GetData()); CastToItkImage< ItkDoubleImgType >(img, comp1VolumeImage); parameters.m_FiberModelList.back()->SetVolumeFractionImage(comp1VolumeImage); } // compartment 2 switch (m_Controls->m_Compartment2Box->currentIndex()) { case 0: break; case 1: { mitk::StickModel* model = new mitk::StickModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity(m_Controls->m_StickWidget2->GetD()); model->SetT2(m_Controls->m_StickWidget2->GetT2()); model->SetT1(m_Controls->m_StickWidget2->GetT1()); model->m_CompartmentId = 2; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Stick"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Stick") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D", DoubleProperty::New(m_Controls->m_StickWidget2->GetD()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(model->GetT2()) ); break; } case 2: { mitk::TensorModel* model = new mitk::TensorModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity1(m_Controls->m_ZeppelinWidget2->GetD1()); model->SetDiffusivity2(m_Controls->m_ZeppelinWidget2->GetD2()); model->SetDiffusivity3(m_Controls->m_ZeppelinWidget2->GetD2()); model->SetT2(m_Controls->m_ZeppelinWidget2->GetT2()); model->SetT1(m_Controls->m_ZeppelinWidget2->GetT1()); model->m_CompartmentId = 2; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Zeppelin"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Zeppelin") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D1", DoubleProperty::New(m_Controls->m_ZeppelinWidget2->GetD1()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D2", DoubleProperty::New(m_Controls->m_ZeppelinWidget2->GetD2()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(model->GetT2()) ); break; } case 3: { mitk::TensorModel* model = new mitk::TensorModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity1(m_Controls->m_TensorWidget2->GetD1()); model->SetDiffusivity2(m_Controls->m_TensorWidget2->GetD2()); model->SetDiffusivity3(m_Controls->m_TensorWidget2->GetD3()); model->SetT2(m_Controls->m_TensorWidget2->GetT2()); model->SetT1(m_Controls->m_TensorWidget2->GetT1()); model->m_CompartmentId = 2; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Tensor"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Tensor") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D1", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD1()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D2", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD2()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D3", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD3()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(model->GetT2()) ); break; } } if (m_Controls->m_Comp2VolumeFraction->GetSelectedNode().IsNotNull() && parameters.m_FiberModelList.size()==2) { mitk::DataNode::Pointer volumeNode = m_Controls->m_Comp2VolumeFraction->GetSelectedNode(); ItkDoubleImgType::Pointer comp1VolumeImage = ItkDoubleImgType::New(); mitk::Image* img = dynamic_cast(volumeNode->GetData()); CastToItkImage< ItkDoubleImgType >(img, comp1VolumeImage); parameters.m_FiberModelList.back()->SetVolumeFractionImage(comp1VolumeImage); } // compartment 3 switch (m_Controls->m_Compartment3Box->currentIndex()) { case 0: { mitk::BallModel* model = new mitk::BallModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity(m_Controls->m_BallWidget1->GetD()); model->SetT2(m_Controls->m_BallWidget1->GetT2()); model->SetT1(m_Controls->m_BallWidget1->GetT1()); model->m_CompartmentId = 3; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Ball"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Ball") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.D", DoubleProperty::New(m_Controls->m_BallWidget1->GetD()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(model->GetT2()) ); break; } case 1: { mitk::AstroStickModel* model = new mitk::AstroStickModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity(m_Controls->m_AstrosticksWidget1->GetD()); model->SetT2(m_Controls->m_AstrosticksWidget1->GetT2()); model->SetT1(m_Controls->m_AstrosticksWidget1->GetT1()); model->SetRandomizeSticks(m_Controls->m_AstrosticksWidget1->GetRandomizeSticks()); model->m_CompartmentId = 3; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Astrosticks"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Astrosticks") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.D", DoubleProperty::New(m_Controls->m_AstrosticksWidget1->GetD()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(model->GetT2()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.RandomSticks", BoolProperty::New(m_Controls->m_AstrosticksWidget1->GetRandomizeSticks()) ); break; } case 2: { mitk::DotModel* model = new mitk::DotModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetT2(m_Controls->m_DotWidget1->GetT2()); model->SetT1(m_Controls->m_DotWidget1->GetT1()); model->m_CompartmentId = 3; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Dot"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Dot") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(model->GetT2()) ); break; } case 3: { mitk::RawShModel* model = new mitk::RawShModel(); parameters.m_SignalGen.m_DoSimulateRelaxation = false; model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetMaxNumKernels(m_Controls->m_PrototypeWidget3->GetNumberOfSamples()); model->SetFaRange(m_Controls->m_PrototypeWidget3->GetMinFa(), m_Controls->m_PrototypeWidget3->GetMaxFa()); model->SetAdcRange(m_Controls->m_PrototypeWidget3->GetMinAdc(), m_Controls->m_PrototypeWidget3->GetMaxAdc()); model->m_CompartmentId = 3; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Prototype"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Prototype") ); break; } } if (m_Controls->m_Comp3VolumeFraction->GetSelectedNode().IsNotNull()) { mitk::DataNode::Pointer volumeNode = m_Controls->m_Comp3VolumeFraction->GetSelectedNode(); ItkDoubleImgType::Pointer comp1VolumeImage = ItkDoubleImgType::New(); mitk::Image* img = dynamic_cast(volumeNode->GetData()); CastToItkImage< ItkDoubleImgType >(img, comp1VolumeImage); parameters.m_NonFiberModelList.back()->SetVolumeFractionImage(comp1VolumeImage); } switch (m_Controls->m_Compartment4Box->currentIndex()) { case 0: break; case 1: { mitk::BallModel* model = new mitk::BallModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity(m_Controls->m_BallWidget2->GetD()); model->SetT2(m_Controls->m_BallWidget2->GetT2()); model->SetT1(m_Controls->m_BallWidget2->GetT1()); model->m_CompartmentId = 4; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Ball"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Ball") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.D", DoubleProperty::New(m_Controls->m_BallWidget2->GetD()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(model->GetT2()) ); break; } case 2: { mitk::AstroStickModel* model = new mitk::AstroStickModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity(m_Controls->m_AstrosticksWidget2->GetD()); model->SetT2(m_Controls->m_AstrosticksWidget2->GetT2()); model->SetT1(m_Controls->m_AstrosticksWidget2->GetT1()); model->SetRandomizeSticks(m_Controls->m_AstrosticksWidget2->GetRandomizeSticks()); model->m_CompartmentId = 4; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Astrosticks"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Astrosticks") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.D", DoubleProperty::New(m_Controls->m_AstrosticksWidget2->GetD()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(model->GetT2()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.RandomSticks", BoolProperty::New(m_Controls->m_AstrosticksWidget2->GetRandomizeSticks()) ); break; } case 3: { mitk::DotModel* model = new mitk::DotModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetT2(m_Controls->m_DotWidget2->GetT2()); model->SetT1(m_Controls->m_DotWidget2->GetT1()); model->m_CompartmentId = 4; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Dot"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Dot") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(model->GetT2()) ); break; } case 4: { mitk::RawShModel* model = new mitk::RawShModel(); parameters.m_SignalGen.m_DoSimulateRelaxation = false; model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetMaxNumKernels(m_Controls->m_PrototypeWidget4->GetNumberOfSamples()); model->SetFaRange(m_Controls->m_PrototypeWidget4->GetMinFa(), m_Controls->m_PrototypeWidget4->GetMaxFa()); model->SetAdcRange(m_Controls->m_PrototypeWidget4->GetMinAdc(), m_Controls->m_PrototypeWidget4->GetMaxAdc()); model->m_CompartmentId = 4; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Prototype"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Prototype") ); break; } } if (m_Controls->m_Comp4VolumeFraction->GetSelectedNode().IsNotNull() && parameters.m_NonFiberModelList.size()==2) { mitk::DataNode::Pointer volumeNode = m_Controls->m_Comp4VolumeFraction->GetSelectedNode(); ItkDoubleImgType::Pointer compVolumeImage = ItkDoubleImgType::New(); mitk::Image* img = dynamic_cast(volumeNode->GetData()); CastToItkImage< ItkDoubleImgType >(img, compVolumeImage); parameters.m_NonFiberModelList.back()->SetVolumeFractionImage(compVolumeImage); } } parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.SignalScale", IntProperty::New(parameters.m_SignalGen.m_SignalScale)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.FiberRadius", IntProperty::New(parameters.m_SignalGen.m_AxonRadius)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Tinhom", DoubleProperty::New(parameters.m_SignalGen.m_tInhom)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Tline", DoubleProperty::New(parameters.m_SignalGen.m_tLine)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.TE", DoubleProperty::New(parameters.m_SignalGen.m_tEcho)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.b-value", DoubleProperty::New(parameters.m_SignalGen.m_Bvalue)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.NoPartialVolume", BoolProperty::New(parameters.m_SignalGen.m_DoDisablePartialVolume)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Relaxation", BoolProperty::New(parameters.m_SignalGen.m_DoSimulateRelaxation)); parameters.m_Misc.m_ResultNode->AddProperty("binary", BoolProperty::New(false)); parameters.m_Misc.m_CheckRealTimeFibersBox = m_Controls->m_RealTimeFibers->isChecked(); parameters.m_Misc.m_CheckAdvancedFiberOptionsBox = m_Controls->m_AdvancedOptionsBox->isChecked(); parameters.m_Misc.m_CheckIncludeFiducialsBox = m_Controls->m_IncludeFiducials->isChecked(); parameters.m_Misc.m_CheckConstantRadiusBox = m_Controls->m_ConstantRadiusBox->isChecked(); return parameters; } void QmitkFiberfoxView::SaveParameters(QString filename) { - FiberfoxParameters<> ffParamaters = UpdateImageParameters(); + FiberfoxParameters<> ffParamaters = UpdateImageParameters(true, true); bool ok = true; bool first = true; bool dosampling = false; mitk::Image::Pointer diffImg = NULL; itk::Image< itk::DiffusionTensor3D< double >, 3 >::Pointer tensorImage = NULL; const int shOrder = 2; typedef itk::AnalyticalDiffusionQballReconstructionImageFilter QballFilterType; QballFilterType::CoefficientImageType::Pointer itkFeatureImage = NULL; ItkDoubleImgType::Pointer adcImage = NULL; for (unsigned int i=0; i* model = nullptr; if (i* >(ffParamaters.m_FiberModelList.at(i)); } else { model = dynamic_cast< mitk::RawShModel<>* >(ffParamaters.m_NonFiberModelList.at(i-ffParamaters.m_FiberModelList.size())); } if ( model!=nullptr && model->GetNumberOfKernels() <= 0 ) { if (first==true) { if ( QMessageBox::question(NULL, "Prototype signal sampling", "Do you want to sample prototype signals from the selected diffusion-weighted imag and save them?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes ) dosampling = true; first = false; if ( dosampling && (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNull() || !mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()) ) ) ) { QMessageBox::information(NULL, "Parameter file not saved", "No diffusion-weighted image selected to sample signal from."); return; } else if (dosampling) { diffImg = dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()); typedef itk::DiffusionTensor3DReconstructionImageFilter< short, short, double > TensorReconstructionImageFilterType; TensorReconstructionImageFilterType::Pointer filter = TensorReconstructionImageFilterType::New(); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(diffImg, itkVectorImagePointer); filter->SetGradientImage( static_cast ( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(), itkVectorImagePointer ); filter->SetBValue( static_cast ( diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str() ).GetPointer() ) ->GetValue() ); filter->Update(); tensorImage = filter->GetOutput(); QballFilterType::Pointer qballfilter = QballFilterType::New(); qballfilter->SetGradientImage( static_cast ( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(), itkVectorImagePointer ); qballfilter->SetBValue( static_cast ( diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); qballfilter->SetLambda(0.006); qballfilter->SetNormalizationMethod(QballFilterType::QBAR_RAW_SIGNAL); qballfilter->Update(); itkFeatureImage = qballfilter->GetCoefficientImage(); itk::AdcImageFilter< short, double >::Pointer adcFilter = itk::AdcImageFilter< short, double >::New(); adcFilter->SetInput( itkVectorImagePointer ); adcFilter->SetGradientDirections( static_cast ( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); adcFilter->SetB_value( static_cast (diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); adcFilter->Update(); adcImage = adcFilter->GetOutput(); } } typedef itk::DiffusionTensor3DReconstructionImageFilter< short, short, double > TensorReconstructionImageFilterType; TensorReconstructionImageFilterType::Pointer filter = TensorReconstructionImageFilterType::New(); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(diffImg, itkVectorImagePointer); filter->SetGradientImage( static_cast ( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(), itkVectorImagePointer ); filter->SetBValue( static_cast (diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); filter->Update(); tensorImage = filter->GetOutput(); QballFilterType::Pointer qballfilter = QballFilterType::New(); qballfilter->SetGradientImage( static_cast ( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(), itkVectorImagePointer ); qballfilter->SetBValue( static_cast (diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); qballfilter->SetLambda(0.006); qballfilter->SetNormalizationMethod(QballFilterType::QBAR_RAW_SIGNAL); qballfilter->Update(); itkFeatureImage = qballfilter->GetCoefficientImage(); itk::AdcImageFilter< short, double >::Pointer adcFilter = itk::AdcImageFilter< short, double >::New(); adcFilter->SetInput( itkVectorImagePointer ); adcFilter->SetGradientDirections( static_cast ( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); adcFilter->SetB_value( static_cast (diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); adcFilter->Update(); adcImage = adcFilter->GetOutput(); if (dosampling && diffImg.IsNotNull()) { ok = model->SampleKernels(diffImg, ffParamaters.m_SignalGen.m_MaskImage, tensorImage, itkFeatureImage, adcImage); if (!ok) { QMessageBox::information( NULL, "Parameter file not saved", "No valid prototype signals could be sampled."); return; } } } } ffParamaters.SaveParameters(filename.toStdString()); m_ParameterFile = filename; } void QmitkFiberfoxView::SaveParameters() { QString filename = QFileDialog::getSaveFileName( 0, tr("Save Parameters"), m_ParameterFile, tr("Fiberfox Parameters (*.ffp)") ); SaveParameters(filename); } void QmitkFiberfoxView::LoadParameters() { QString filename = QFileDialog::getOpenFileName(0, tr("Load Parameters"), QString(itksys::SystemTools::GetFilenamePath(m_ParameterFile.toStdString()).c_str()), tr("Fiberfox Parameters (*.ffp)") ); if(filename.isEmpty() || filename.isNull()) return; m_ParameterFile = filename; FiberfoxParameters<> parameters = UpdateImageParameters(); parameters.LoadParameters(filename.toStdString()); if (parameters.m_MissingTags.size()>0) { QString missing("Parameter file might be corrupted. The following parameters could not be read: "); missing += QString(parameters.m_MissingTags.c_str()); missing += "\nDefault values have been assigned to the missing parameters."; QMessageBox::information( NULL, "Warning!", missing); } m_Controls->m_RealTimeFibers->setChecked(parameters.m_Misc.m_CheckRealTimeFibersBox); m_Controls->m_AdvancedOptionsBox->setChecked(parameters.m_Misc.m_CheckAdvancedFiberOptionsBox); m_Controls->m_IncludeFiducials->setChecked(parameters.m_Misc.m_CheckIncludeFiducialsBox); m_Controls->m_ConstantRadiusBox->setChecked(parameters.m_Misc.m_CheckConstantRadiusBox); m_Controls->m_DistributionBox->setCurrentIndex(parameters.m_FiberGen.m_Distribution); m_Controls->m_VarianceBox->setValue(parameters.m_FiberGen.m_Variance); m_Controls->m_FiberDensityBox->setValue(parameters.m_FiberGen.m_Density); m_Controls->m_FiberSamplingBox->setValue(parameters.m_FiberGen.m_Sampling); m_Controls->m_TensionBox->setValue(parameters.m_FiberGen.m_Tension); m_Controls->m_ContinuityBox->setValue(parameters.m_FiberGen.m_Continuity); m_Controls->m_BiasBox->setValue(parameters.m_FiberGen.m_Bias); m_Controls->m_XrotBox->setValue(parameters.m_FiberGen.m_Rotation[0]); m_Controls->m_YrotBox->setValue(parameters.m_FiberGen.m_Rotation[1]); m_Controls->m_ZrotBox->setValue(parameters.m_FiberGen.m_Rotation[2]); m_Controls->m_XtransBox->setValue(parameters.m_FiberGen.m_Translation[0]); m_Controls->m_YtransBox->setValue(parameters.m_FiberGen.m_Translation[1]); m_Controls->m_ZtransBox->setValue(parameters.m_FiberGen.m_Translation[2]); m_Controls->m_XscaleBox->setValue(parameters.m_FiberGen.m_Scale[0]); m_Controls->m_YscaleBox->setValue(parameters.m_FiberGen.m_Scale[1]); m_Controls->m_ZscaleBox->setValue(parameters.m_FiberGen.m_Scale[2]); // image generation parameters m_Controls->m_SizeX->setValue(parameters.m_SignalGen.m_ImageRegion.GetSize(0)); m_Controls->m_SizeY->setValue(parameters.m_SignalGen.m_ImageRegion.GetSize(1)); m_Controls->m_SizeZ->setValue(parameters.m_SignalGen.m_ImageRegion.GetSize(2)); m_Controls->m_SpacingX->setValue(parameters.m_SignalGen.m_ImageSpacing[0]); m_Controls->m_SpacingY->setValue(parameters.m_SignalGen.m_ImageSpacing[1]); m_Controls->m_SpacingZ->setValue(parameters.m_SignalGen.m_ImageSpacing[2]); m_Controls->m_NumGradientsBox->setValue(parameters.m_SignalGen.GetNumWeightedVolumes()); m_Controls->m_BvalueBox->setValue(parameters.m_SignalGen.m_Bvalue); m_Controls->m_SignalScaleBox->setValue(parameters.m_SignalGen.m_SignalScale); m_Controls->m_TEbox->setValue(parameters.m_SignalGen.m_tEcho); m_Controls->m_LineReadoutTimeBox->setValue(parameters.m_SignalGen.m_tLine); m_Controls->m_T2starBox->setValue(parameters.m_SignalGen.m_tInhom); m_Controls->m_FiberRadius->setValue(parameters.m_SignalGen.m_AxonRadius); m_Controls->m_RelaxationBox->setChecked(parameters.m_SignalGen.m_DoSimulateRelaxation); m_Controls->m_EnforcePureFiberVoxelsBox->setChecked(parameters.m_SignalGen.m_DoDisablePartialVolume); m_Controls->m_ReversePhaseBox->setChecked(parameters.m_SignalGen.m_ReversePhase); m_Controls->m_PartialFourier->setValue(parameters.m_SignalGen.m_PartialFourier); m_Controls->m_TRbox->setValue(parameters.m_SignalGen.m_tRep); m_Controls->m_NumCoilsBox->setValue(parameters.m_SignalGen.m_NumberOfCoils); m_Controls->m_CoilSensBox->setCurrentIndex(parameters.m_SignalGen.m_CoilSensitivityProfile); m_Controls->m_AcquisitionTypeBox->setCurrentIndex(parameters.m_SignalGen.m_AcquisitionType); if (parameters.m_NoiseModel!=NULL) { m_Controls->m_AddNoise->setChecked(parameters.m_Misc.m_CheckAddNoiseBox); if (dynamic_cast*>(parameters.m_NoiseModel.get())) { m_Controls->m_NoiseDistributionBox->setCurrentIndex(0); } else if (dynamic_cast*>(parameters.m_NoiseModel.get())) { m_Controls->m_NoiseDistributionBox->setCurrentIndex(1); } m_Controls->m_NoiseLevel->setValue(parameters.m_NoiseModel->GetNoiseVariance()); } else { m_Controls->m_AddNoise->setChecked(parameters.m_Misc.m_CheckAddNoiseBox); m_Controls->m_NoiseLevel->setValue(parameters.m_SignalGen.m_NoiseVariance); } m_Controls->m_VolumeFractionsBox->setChecked(parameters.m_Misc.m_CheckOutputVolumeFractionsBox); m_Controls->m_AdvancedOptionsBox_2->setChecked(parameters.m_Misc.m_CheckAdvancedSignalOptionsBox); m_Controls->m_AddGhosts->setChecked(parameters.m_Misc.m_CheckAddGhostsBox); m_Controls->m_AddAliasing->setChecked(parameters.m_Misc.m_CheckAddAliasingBox); m_Controls->m_AddDistortions->setChecked(parameters.m_Misc.m_CheckAddDistortionsBox); m_Controls->m_AddSpikes->setChecked(parameters.m_Misc.m_CheckAddSpikesBox); m_Controls->m_AddEddy->setChecked(parameters.m_Misc.m_CheckAddEddyCurrentsBox); m_Controls->m_kOffsetBox->setValue(parameters.m_SignalGen.m_KspaceLineOffset); m_Controls->m_WrapBox->setValue(100*(1-parameters.m_SignalGen.m_CroppingFactor)); m_Controls->m_SpikeNumBox->setValue(parameters.m_SignalGen.m_Spikes); m_Controls->m_SpikeScaleBox->setValue(parameters.m_SignalGen.m_SpikeAmplitude); m_Controls->m_EddyGradientStrength->setValue(parameters.m_SignalGen.m_EddyStrength); m_Controls->m_AddGibbsRinging->setChecked(parameters.m_SignalGen.m_DoAddGibbsRinging); m_Controls->m_AddMotion->setChecked(parameters.m_SignalGen.m_DoAddMotion); m_Controls->m_RandomMotion->setChecked(parameters.m_SignalGen.m_DoRandomizeMotion); m_Controls->m_MotionVolumesBox->setText(QString(parameters.m_Misc.m_MotionVolumesBox.c_str())); m_Controls->m_MaxTranslationBoxX->setValue(parameters.m_SignalGen.m_Translation[0]); m_Controls->m_MaxTranslationBoxY->setValue(parameters.m_SignalGen.m_Translation[1]); m_Controls->m_MaxTranslationBoxZ->setValue(parameters.m_SignalGen.m_Translation[2]); m_Controls->m_MaxRotationBoxX->setValue(parameters.m_SignalGen.m_Rotation[0]); m_Controls->m_MaxRotationBoxY->setValue(parameters.m_SignalGen.m_Rotation[1]); m_Controls->m_MaxRotationBoxZ->setValue(parameters.m_SignalGen.m_Rotation[2]); m_Controls->m_Compartment1Box->setCurrentIndex(0); m_Controls->m_Compartment2Box->setCurrentIndex(0); m_Controls->m_Compartment3Box->setCurrentIndex(0); m_Controls->m_Compartment4Box->setCurrentIndex(0); for (unsigned int i=0; i* signalModel = NULL; if (iGetVolumeFractionImage().IsNotNull() ) { compVolNode = mitk::DataNode::New(); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(signalModel->GetVolumeFractionImage().GetPointer()); image->SetVolume(signalModel->GetVolumeFractionImage()->GetBufferPointer()); compVolNode->SetData( image ); compVolNode->SetName("Compartment volume "+QString::number(signalModel->m_CompartmentId).toStdString()); GetDataStorage()->Add(compVolNode); } switch (signalModel->m_CompartmentId) { case 1: { if (compVolNode.IsNotNull()) m_Controls->m_Comp1VolumeFraction->SetSelectedNode(compVolNode); if (dynamic_cast*>(signalModel)) { mitk::StickModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_StickWidget1->SetT2(model->GetT2()); m_Controls->m_StickWidget1->SetT1(model->GetT1()); m_Controls->m_StickWidget1->SetD(model->GetDiffusivity()); m_Controls->m_Compartment1Box->setCurrentIndex(0); break; } else if (dynamic_cast*>(signalModel)) { mitk::TensorModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_TensorWidget1->SetT2(model->GetT2()); m_Controls->m_TensorWidget1->SetT1(model->GetT1()); m_Controls->m_TensorWidget1->SetD1(model->GetDiffusivity1()); m_Controls->m_TensorWidget1->SetD2(model->GetDiffusivity2()); m_Controls->m_TensorWidget1->SetD3(model->GetDiffusivity3()); m_Controls->m_Compartment1Box->setCurrentIndex(2); break; } else if (dynamic_cast*>(signalModel)) { mitk::RawShModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_PrototypeWidget1->SetNumberOfSamples(model->GetMaxNumKernels()); m_Controls->m_PrototypeWidget1->SetMinFa(model->GetFaRange().first); m_Controls->m_PrototypeWidget1->SetMaxFa(model->GetFaRange().second); m_Controls->m_PrototypeWidget1->SetMinAdc(model->GetAdcRange().first); m_Controls->m_PrototypeWidget1->SetMaxAdc(model->GetAdcRange().second); m_Controls->m_Compartment1Box->setCurrentIndex(3); break; } break; } case 2: { if (compVolNode.IsNotNull()) m_Controls->m_Comp2VolumeFraction->SetSelectedNode(compVolNode); if (dynamic_cast*>(signalModel)) { mitk::StickModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_StickWidget2->SetT2(model->GetT2()); m_Controls->m_StickWidget2->SetT1(model->GetT1()); m_Controls->m_StickWidget2->SetD(model->GetDiffusivity()); m_Controls->m_Compartment2Box->setCurrentIndex(1); break; } else if (dynamic_cast*>(signalModel)) { mitk::TensorModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_TensorWidget2->SetT2(model->GetT2()); m_Controls->m_TensorWidget2->SetT1(model->GetT1()); m_Controls->m_TensorWidget2->SetD1(model->GetDiffusivity1()); m_Controls->m_TensorWidget2->SetD2(model->GetDiffusivity2()); m_Controls->m_TensorWidget2->SetD3(model->GetDiffusivity3()); m_Controls->m_Compartment2Box->setCurrentIndex(3); break; } break; } case 3: { if (compVolNode.IsNotNull()) m_Controls->m_Comp3VolumeFraction->SetSelectedNode(compVolNode); if (dynamic_cast*>(signalModel)) { mitk::BallModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_BallWidget1->SetT2(model->GetT2()); m_Controls->m_BallWidget1->SetT1(model->GetT1()); m_Controls->m_BallWidget1->SetD(model->GetDiffusivity()); m_Controls->m_Compartment3Box->setCurrentIndex(0); break; } else if (dynamic_cast*>(signalModel)) { mitk::AstroStickModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_AstrosticksWidget1->SetT2(model->GetT2()); m_Controls->m_AstrosticksWidget1->SetT1(model->GetT1()); m_Controls->m_AstrosticksWidget1->SetD(model->GetDiffusivity()); m_Controls->m_AstrosticksWidget1->SetRandomizeSticks(model->GetRandomizeSticks()); m_Controls->m_Compartment3Box->setCurrentIndex(1); break; } else if (dynamic_cast*>(signalModel)) { mitk::DotModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_DotWidget1->SetT2(model->GetT2()); m_Controls->m_DotWidget1->SetT1(model->GetT1()); m_Controls->m_Compartment3Box->setCurrentIndex(2); break; } else if (dynamic_cast*>(signalModel)) { mitk::RawShModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_PrototypeWidget3->SetNumberOfSamples(model->GetMaxNumKernels()); m_Controls->m_PrototypeWidget3->SetMinFa(model->GetFaRange().first); m_Controls->m_PrototypeWidget3->SetMaxFa(model->GetFaRange().second); m_Controls->m_PrototypeWidget3->SetMinAdc(model->GetAdcRange().first); m_Controls->m_PrototypeWidget3->SetMaxAdc(model->GetAdcRange().second); m_Controls->m_Compartment3Box->setCurrentIndex(3); break; } break; } case 4: { if (compVolNode.IsNotNull()) m_Controls->m_Comp4VolumeFraction->SetSelectedNode(compVolNode); if (dynamic_cast*>(signalModel)) { mitk::BallModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_BallWidget2->SetT2(model->GetT2()); m_Controls->m_BallWidget2->SetT1(model->GetT1()); m_Controls->m_BallWidget2->SetD(model->GetDiffusivity()); m_Controls->m_Compartment4Box->setCurrentIndex(1); break; } else if (dynamic_cast*>(signalModel)) { mitk::AstroStickModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_AstrosticksWidget2->SetT2(model->GetT2()); m_Controls->m_AstrosticksWidget2->SetT1(model->GetT1()); m_Controls->m_AstrosticksWidget2->SetD(model->GetDiffusivity()); m_Controls->m_AstrosticksWidget2->SetRandomizeSticks(model->GetRandomizeSticks()); m_Controls->m_Compartment4Box->setCurrentIndex(2); break; } else if (dynamic_cast*>(signalModel)) { mitk::DotModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_DotWidget2->SetT2(model->GetT2()); m_Controls->m_DotWidget2->SetT1(model->GetT1()); m_Controls->m_Compartment4Box->setCurrentIndex(3); break; } else if (dynamic_cast*>(signalModel)) { mitk::RawShModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_PrototypeWidget4->SetNumberOfSamples(model->GetMaxNumKernels()); m_Controls->m_PrototypeWidget4->SetMinFa(model->GetFaRange().first); m_Controls->m_PrototypeWidget4->SetMaxFa(model->GetFaRange().second); m_Controls->m_PrototypeWidget4->SetMinAdc(model->GetAdcRange().first); m_Controls->m_PrototypeWidget4->SetMaxAdc(model->GetAdcRange().second); m_Controls->m_Compartment4Box->setCurrentIndex(4); break; } break; } } } if ( parameters.m_SignalGen.m_MaskImage ) { mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(parameters.m_SignalGen.m_MaskImage.GetPointer()); image->SetVolume(parameters.m_SignalGen.m_MaskImage->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("Tissue mask"); GetDataStorage()->Add(node); m_Controls->m_MaskComboBox->SetSelectedNode(node); } if ( parameters.m_SignalGen.m_FrequencyMap ) { mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(parameters.m_SignalGen.m_FrequencyMap.GetPointer()); image->SetVolume(parameters.m_SignalGen.m_FrequencyMap->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("Frequency map"); GetDataStorage()->Add(node); m_Controls->m_FrequencyMapBox->SetSelectedNode(node); } } void QmitkFiberfoxView::ShowAdvancedOptions(int state) { if (state) { m_Controls->m_AdvancedFiberOptionsFrame->setVisible(true); m_Controls->m_AdvancedSignalOptionsFrame->setVisible(true); m_Controls->m_AdvancedOptionsBox->setChecked(true); m_Controls->m_AdvancedOptionsBox_2->setChecked(true); } else { m_Controls->m_AdvancedFiberOptionsFrame->setVisible(false); m_Controls->m_AdvancedSignalOptionsFrame->setVisible(false); m_Controls->m_AdvancedOptionsBox->setChecked(false); m_Controls->m_AdvancedOptionsBox_2->setChecked(false); } } void QmitkFiberfoxView::Comp1ModelFrameVisibility(int index) { m_Controls->m_StickWidget1->setVisible(false); m_Controls->m_ZeppelinWidget1->setVisible(false); m_Controls->m_TensorWidget1->setVisible(false); m_Controls->m_PrototypeWidget1->setVisible(false); switch (index) { case 0: m_Controls->m_StickWidget1->setVisible(true); break; case 1: m_Controls->m_ZeppelinWidget1->setVisible(true); break; case 2: m_Controls->m_TensorWidget1->setVisible(true); break; case 3: m_Controls->m_PrototypeWidget1->setVisible(true); break; } } void QmitkFiberfoxView::Comp2ModelFrameVisibility(int index) { m_Controls->m_StickWidget2->setVisible(false); m_Controls->m_ZeppelinWidget2->setVisible(false); m_Controls->m_TensorWidget2->setVisible(false); m_Controls->m_Comp2FractionFrame->setVisible(false); switch (index) { case 0: break; case 1: m_Controls->m_StickWidget2->setVisible(true); m_Controls->m_Comp2FractionFrame->setVisible(true); break; case 2: m_Controls->m_ZeppelinWidget2->setVisible(true); m_Controls->m_Comp2FractionFrame->setVisible(true); break; case 3: m_Controls->m_TensorWidget2->setVisible(true); m_Controls->m_Comp2FractionFrame->setVisible(true); break; } } void QmitkFiberfoxView::Comp3ModelFrameVisibility(int index) { m_Controls->m_BallWidget1->setVisible(false); m_Controls->m_AstrosticksWidget1->setVisible(false); m_Controls->m_DotWidget1->setVisible(false); m_Controls->m_PrototypeWidget3->setVisible(false); switch (index) { case 0: m_Controls->m_BallWidget1->setVisible(true); break; case 1: m_Controls->m_AstrosticksWidget1->setVisible(true); break; case 2: m_Controls->m_DotWidget1->setVisible(true); break; case 3: m_Controls->m_PrototypeWidget3->setVisible(true); break; } } void QmitkFiberfoxView::Comp4ModelFrameVisibility(int index) { m_Controls->m_BallWidget2->setVisible(false); m_Controls->m_AstrosticksWidget2->setVisible(false); m_Controls->m_DotWidget2->setVisible(false); m_Controls->m_PrototypeWidget4->setVisible(false); m_Controls->m_Comp4FractionFrame->setVisible(false); switch (index) { case 0: break; case 1: m_Controls->m_BallWidget2->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; case 2: m_Controls->m_AstrosticksWidget2->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; case 3: m_Controls->m_DotWidget2->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; case 4: m_Controls->m_PrototypeWidget4->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; } } void QmitkFiberfoxView::OnConstantRadius(int value) { if (value>0 && m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnAddMotion(int value) { if (value>0) m_Controls->m_MotionArtifactFrame->setVisible(true); else m_Controls->m_MotionArtifactFrame->setVisible(false); } void QmitkFiberfoxView::OnAddAliasing(int value) { if (value>0) m_Controls->m_AliasingFrame->setVisible(true); else m_Controls->m_AliasingFrame->setVisible(false); } void QmitkFiberfoxView::OnAddSpikes(int value) { if (value>0) m_Controls->m_SpikeFrame->setVisible(true); else m_Controls->m_SpikeFrame->setVisible(false); } void QmitkFiberfoxView::OnAddEddy(int value) { if (value>0) m_Controls->m_EddyFrame->setVisible(true); else m_Controls->m_EddyFrame->setVisible(false); } void QmitkFiberfoxView::OnAddDistortions(int value) { if (value>0) m_Controls->m_DistortionsFrame->setVisible(true); else m_Controls->m_DistortionsFrame->setVisible(false); } void QmitkFiberfoxView::OnAddGhosts(int value) { if (value>0) m_Controls->m_GhostFrame->setVisible(true); else m_Controls->m_GhostFrame->setVisible(false); } void QmitkFiberfoxView::OnAddNoise(int value) { if (value>0) m_Controls->m_NoiseFrame->setVisible(true); else m_Controls->m_NoiseFrame->setVisible(false); } void QmitkFiberfoxView::OnDistributionChanged(int value) { if (value==1) m_Controls->m_VarianceBox->setVisible(true); else m_Controls->m_VarianceBox->setVisible(false); if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnVarianceChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFiberDensityChanged(int) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFiberSamplingChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnTensionChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnContinuityChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnBiasChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::AlignOnGrid() { for (unsigned int i=0; i(m_SelectedFiducials.at(i)->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::DataStorage::SetOfObjects::ConstPointer parentFibs = GetDataStorage()->GetSources(m_SelectedFiducials.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = parentFibs->begin(); it != parentFibs->end(); ++it ) { mitk::DataNode::Pointer pFibNode = *it; if ( pFibNode.IsNotNull() && dynamic_cast(pFibNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer parentImgs = GetDataStorage()->GetSources(pFibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = parentImgs->begin(); it2 != parentImgs->end(); ++it2 ) { mitk::DataNode::Pointer pImgNode = *it2; if ( pImgNode.IsNotNull() && dynamic_cast(pImgNode->GetData()) ) { mitk::Image::Pointer img = dynamic_cast(pImgNode->GetData()); mitk::BaseGeometry::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); break; } } break; } } } for(unsigned int i=0; iGetSources(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it = sources->begin(); it != sources->end(); ++it ) { mitk::DataNode::Pointer imgNode = *it; if ( imgNode.IsNotNull() && dynamic_cast(imgNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::Image::Pointer img = dynamic_cast(imgNode->GetData()); mitk::BaseGeometry::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); } } break; } } } for(unsigned int i=0; i(m_SelectedImages.at(i)->GetData()); mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(m_SelectedImages.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = derivations->begin(); it != derivations->end(); ++it ) { mitk::DataNode::Pointer fibNode = *it; if ( fibNode.IsNotNull() && dynamic_cast(fibNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer derivations2 = GetDataStorage()->GetDerivations(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations2->begin(); it2 != derivations2->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::BaseGeometry::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); } } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFlipButton() { if (m_SelectedFiducial.IsNull()) return; std::map::iterator it = m_DataNodeToPlanarFigureData.find(m_SelectedFiducial.GetPointer()); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; data.m_Flipped += 1; data.m_Flipped %= 2; } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } QmitkFiberfoxView::GradientListType QmitkFiberfoxView::GenerateHalfShell(int NPoints) { NPoints *= 2; GradientListType pointshell; int numB0 = NPoints/20; if (numB0==0) numB0=1; GradientType g; g.Fill(0.0); for (int i=0; i theta; theta.set_size(NPoints); vnl_vector phi; phi.set_size(NPoints); double C = sqrt(4*M_PI); phi(0) = 0.0; phi(NPoints-1) = 0.0; for(int i=0; i0 && i std::vector > QmitkFiberfoxView::MakeGradientList() { std::vector > retval; vnl_matrix_fixed* U = itk::PointShell >::DistributePointShell(); // Add 0 vector for B0 int numB0 = ndirs/10; if (numB0==0) numB0=1; itk::Vector v; v.Fill(0.0); for (int i=0; i v; v[0] = U->get(0,i); v[1] = U->get(1,i); v[2] = U->get(2,i); retval.push_back(v); } return retval; } void QmitkFiberfoxView::OnAddBundle() { if (m_SelectedImageNode.IsNull()) return; mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedImageNode); mitk::FiberBundle::Pointer bundle = mitk::FiberBundle::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( bundle ); QString name = QString("Bundle_%1").arg(children->size()); node->SetName(name.toStdString()); m_SelectedBundles.push_back(node); UpdateGui(); GetDataStorage()->Add(node, m_SelectedImageNode); } void QmitkFiberfoxView::OnDrawROI() { if (m_SelectedBundles.empty()) OnAddBundle(); if (m_SelectedBundles.empty()) return; mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedBundles.at(0)); mitk::PlanarEllipse::Pointer figure = mitk::PlanarEllipse::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( figure ); node->SetBoolProperty("planarfigure.3drendering", true); node->SetBoolProperty("planarfigure.3drendering.fill", true); QList nodes = this->GetDataManagerSelection(); for( int i=0; iSetSelected(false); m_SelectedFiducial = node; QString name = QString("Fiducial_%1").arg(children->size()); node->SetName(name.toStdString()); node->SetSelected(true); this->DisableCrosshairNavigation(); mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->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( node ); } UpdateGui(); GetDataStorage()->Add(node, m_SelectedBundles.at(0)); } bool CompareLayer(mitk::DataNode::Pointer i,mitk::DataNode::Pointer j) { int li = -1; i->GetPropertyValue("layer", li); int lj = -1; j->GetPropertyValue("layer", lj); return liGetSources(m_SelectedFiducial); for( mitk::DataStorage::SetOfObjects::const_iterator it = parents->begin(); it != parents->end(); ++it ) if(dynamic_cast((*it)->GetData())) m_SelectedBundles.push_back(*it); if (m_SelectedBundles.empty()) return; } FiberfoxParameters parameters = UpdateImageParameters(false); for (unsigned int i=0; iGetDerivations(m_SelectedBundles.at(i)); std::vector< mitk::DataNode::Pointer > childVector; for( mitk::DataStorage::SetOfObjects::const_iterator it = children->begin(); it != children->end(); ++it ) childVector.push_back(*it); sort(childVector.begin(), childVector.end(), CompareLayer); vector< mitk::PlanarEllipse::Pointer > fib; vector< unsigned int > flip; float radius = 1; int count = 0; for( std::vector< mitk::DataNode::Pointer >::const_iterator it = childVector.begin(); it != childVector.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { mitk::PlanarEllipse* ellipse = dynamic_cast(node->GetData()); if (m_Controls->m_ConstantRadiusBox->isChecked()) { ellipse->SetTreatAsCircle(true); mitk::Point2D c = ellipse->GetControlPoint(0); mitk::Point2D p = ellipse->GetControlPoint(1); mitk::Vector2D v = p-c; if (count==0) { radius = v.GetVnlVector().magnitude(); ellipse->SetControlPoint(1, p); ellipse->Modified(); } else { v.Normalize(); v *= radius; ellipse->SetControlPoint(1, c+v); ellipse->Modified(); } } fib.push_back(ellipse); std::map::iterator it = m_DataNodeToPlanarFigureData.find(node.GetPointer()); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; flip.push_back(data.m_Flipped); } else flip.push_back(0); } count++; } if (fib.size()>1) { parameters.m_FiberGen.m_Fiducials.push_back(fib); parameters.m_FiberGen.m_FlipList.push_back(flip); } else if (fib.size()>0) m_SelectedBundles.at(i)->SetData( mitk::FiberBundle::New() ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } itk::FibersFromPlanarFiguresFilter::Pointer filter = itk::FibersFromPlanarFiguresFilter::New(); filter->SetParameters(parameters.m_FiberGen); filter->Update(); vector< mitk::FiberBundle::Pointer > fiberBundles = filter->GetFiberBundles(); for (unsigned int i=0; iSetData( fiberBundles.at(i) ); if (fiberBundles.at(i)->GetNumFibers()>50000) m_SelectedBundles.at(i)->SetVisibility(false); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::GenerateImage() { if (m_Controls->m_FiberBundleComboBox->GetSelectedNode().IsNull() && !mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( m_Controls->m_TemplateComboBox->GetSelectedNode())) { mitk::Image::Pointer image = mitk::ImageGenerator::GenerateGradientImage( m_Controls->m_SizeX->value(), m_Controls->m_SizeY->value(), m_Controls->m_SizeZ->value(), m_Controls->m_SpacingX->value(), m_Controls->m_SpacingY->value(), m_Controls->m_SpacingZ->value()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("Dummy"); unsigned int window = m_Controls->m_SizeX->value()*m_Controls->m_SizeY->value()*m_Controls->m_SizeZ->value(); unsigned int level = window/2; mitk::LevelWindow lw; lw.SetLevelWindow(level, window); node->SetProperty( "levelwindow", mitk::LevelWindowProperty::New( lw ) ); GetDataStorage()->Add(node); m_SelectedImageNode = node; mitk::BaseData::Pointer basedata = node->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } UpdateGui(); QMessageBox::information(NULL, "Template image generated", "You have selected no fiber bundle or diffusion-weighted image, which can be used to simulate a new diffusion-weighted image. A template image with the specified geometry has been generated that can be used to draw artificial fibers (see tab 'Fiber Definition')."); } else if (m_Controls->m_FiberBundleComboBox->GetSelectedNode().IsNotNull()) SimulateImageFromFibers(m_Controls->m_FiberBundleComboBox->GetSelectedNode()); else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( m_Controls->m_TemplateComboBox->GetSelectedNode()) ) SimulateForExistingDwi(m_Controls->m_TemplateComboBox->GetSelectedNode()); else QMessageBox::information(NULL, "No image generated", "You have selected no fiber bundle or diffusion-weighted image, which can be used to simulate a new diffusion-weighted image."); } void QmitkFiberfoxView::SimulateForExistingDwi(mitk::DataNode* imageNode) { bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(imageNode->GetData())) ); if ( !isDiffusionImage ) { return; } FiberfoxParameters parameters = UpdateImageParameters(); mitk::Image::Pointer diffImg = dynamic_cast(imageNode->GetData()); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(diffImg, itkVectorImagePointer); m_TractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); parameters.m_Misc.m_ParentNode = imageNode; parameters.m_SignalGen.m_SignalScale = 1; parameters.m_Misc.m_ResultNode->SetName(parameters.m_Misc.m_ParentNode->GetName() +"_D"+QString::number(parameters.m_SignalGen.m_ImageRegion.GetSize(0)).toStdString() +"-"+QString::number(parameters.m_SignalGen.m_ImageRegion.GetSize(1)).toStdString() +"-"+QString::number(parameters.m_SignalGen.m_ImageRegion.GetSize(2)).toStdString() +"_S"+QString::number(parameters.m_SignalGen.m_ImageSpacing[0]).toStdString() +"-"+QString::number(parameters.m_SignalGen.m_ImageSpacing[1]).toStdString() +"-"+QString::number(parameters.m_SignalGen.m_ImageSpacing[2]).toStdString() +"_b"+QString::number(parameters.m_SignalGen.m_Bvalue).toStdString() +"_"+parameters.m_Misc.m_SignalModelString +parameters.m_Misc.m_ArtifactModelString); m_TractsToDwiFilter->SetParameters(parameters); m_TractsToDwiFilter->SetInputImage(itkVectorImagePointer); m_Thread.start(QThread::LowestPriority); } void QmitkFiberfoxView::SimulateImageFromFibers(mitk::DataNode* fiberNode) { mitk::FiberBundle::Pointer fiberBundle = dynamic_cast(fiberNode->GetData()); if (fiberBundle->GetNumFibers()<=0) { return; } FiberfoxParameters parameters = UpdateImageParameters(); m_TractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); parameters.m_Misc.m_ParentNode = fiberNode; parameters.m_Misc.m_ResultNode->SetName(parameters.m_Misc.m_ParentNode->GetName() +"_D"+QString::number(parameters.m_SignalGen.m_ImageRegion.GetSize(0)).toStdString() +"-"+QString::number(parameters.m_SignalGen.m_ImageRegion.GetSize(1)).toStdString() +"-"+QString::number(parameters.m_SignalGen.m_ImageRegion.GetSize(2)).toStdString() +"_S"+QString::number(parameters.m_SignalGen.m_ImageSpacing[0]).toStdString() +"-"+QString::number(parameters.m_SignalGen.m_ImageSpacing[1]).toStdString() +"-"+QString::number(parameters.m_SignalGen.m_ImageSpacing[2]).toStdString() +"_b"+QString::number(parameters.m_SignalGen.m_Bvalue).toStdString() +"_"+parameters.m_Misc.m_SignalModelString +parameters.m_Misc.m_ArtifactModelString); if ( m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull() && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast (m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()) ) ) { bool first = true; bool ok = true; mitk::Image::Pointer diffImg = dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()); itk::Image< itk::DiffusionTensor3D< double >, 3 >::Pointer tensorImage = NULL; const int shOrder = 2; typedef itk::AnalyticalDiffusionQballReconstructionImageFilter QballFilterType; QballFilterType::CoefficientImageType::Pointer itkFeatureImage = NULL; ItkDoubleImgType::Pointer adcImage = NULL; for (unsigned int i=0; i* model = NULL; if (i* >(parameters.m_FiberModelList.at(i)); else model = dynamic_cast< mitk::RawShModel<>* >(parameters.m_NonFiberModelList.at(i-parameters.m_FiberModelList.size())); if (model!=0 && model->GetNumberOfKernels()<=0) { if (first==true) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(diffImg, itkVectorImagePointer); typedef itk::DiffusionTensor3DReconstructionImageFilter< short, short, double > TensorReconstructionImageFilterType; TensorReconstructionImageFilterType::Pointer filter = TensorReconstructionImageFilterType::New(); filter->SetGradientImage( static_cast ( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(), itkVectorImagePointer ); filter->SetBValue( static_cast (diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); filter->Update(); tensorImage = filter->GetOutput(); QballFilterType::Pointer qballfilter = QballFilterType::New(); qballfilter->SetGradientImage( static_cast ( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(), itkVectorImagePointer ); qballfilter->SetBValue( static_cast (diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); qballfilter->SetLambda(0.006); qballfilter->SetNormalizationMethod(QballFilterType::QBAR_RAW_SIGNAL); qballfilter->Update(); itkFeatureImage = qballfilter->GetCoefficientImage(); itk::AdcImageFilter< short, double >::Pointer adcFilter = itk::AdcImageFilter< short, double >::New(); adcFilter->SetInput( itkVectorImagePointer ); adcFilter->SetGradientDirections( static_cast ( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); adcFilter->SetB_value( static_cast (diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); adcFilter->Update(); adcImage = adcFilter->GetOutput(); } ok = model->SampleKernels(diffImg, parameters.m_SignalGen.m_MaskImage, tensorImage, itkFeatureImage, adcImage); if (!ok) break; } } if (!ok) { QMessageBox::information( NULL, "Simulation cancelled", "No valid prototype signals could be sampled."); return; } } else if ( m_Controls->m_Compartment1Box->currentIndex()==3 || m_Controls->m_Compartment3Box->currentIndex()==3 || m_Controls->m_Compartment4Box->currentIndex()==4 ) { QMessageBox::information( NULL, "Simulation cancelled", "Prototype signal but no diffusion-weighted image selected to sample signal from."); return; } m_TractsToDwiFilter->SetParameters(parameters); m_TractsToDwiFilter->SetFiberBundle(fiberBundle); m_Thread.start(QThread::LowestPriority); } void QmitkFiberfoxView::ApplyTransform() { vector< mitk::DataNode::Pointer > selectedBundles; for(unsigned int i=0; iGetDerivations(m_SelectedImages.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = derivations->begin(); it != derivations->end(); ++it ) { mitk::DataNode::Pointer fibNode = *it; if ( fibNode.IsNotNull() && dynamic_cast(fibNode->GetData()) ) selectedBundles.push_back(fibNode); } } if (selectedBundles.empty()) selectedBundles = m_SelectedBundles2; if (!selectedBundles.empty()) { for (std::vector::const_iterator it = selectedBundles.begin(); it!=selectedBundles.end(); ++it) { mitk::FiberBundle::Pointer fib = dynamic_cast((*it)->GetData()); fib->RotateAroundAxis(m_Controls->m_XrotBox->value(), m_Controls->m_YrotBox->value(), m_Controls->m_ZrotBox->value()); fib->TranslateFibers(m_Controls->m_XtransBox->value(), m_Controls->m_YtransBox->value(), m_Controls->m_ZtransBox->value()); fib->ScaleFibers(m_Controls->m_XscaleBox->value(), m_Controls->m_YscaleBox->value(), m_Controls->m_ZscaleBox->value()); // handle child fiducials if (m_Controls->m_IncludeFiducials->isChecked()) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse* pe = dynamic_cast(fiducialNode->GetData()); mitk::BaseGeometry* geom = pe->GetGeometry(); // translate mitk::Vector3D world; world[0] = m_Controls->m_XtransBox->value(); world[1] = m_Controls->m_YtransBox->value(); world[2] = m_Controls->m_ZtransBox->value(); geom->Translate(world); // calculate rotation matrix double x = m_Controls->m_XrotBox->value()*M_PI/180; double y = m_Controls->m_YrotBox->value()*M_PI/180; double z = m_Controls->m_ZrotBox->value()*M_PI/180; itk::Matrix< double, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; itk::Matrix< double, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; itk::Matrix< double, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< double, 3, 3 > rot = rotZ*rotY*rotX; // transform control point coordinate into geometry translation geom->SetOrigin(pe->GetWorldControlPoint(0)); mitk::Point2D cp; cp.Fill(0.0); pe->SetControlPoint(0, cp); // rotate fiducial geom->GetIndexToWorldTransform()->SetMatrix(rot*geom->GetIndexToWorldTransform()->GetMatrix()); // implicit translation mitk::Vector3D trans; trans[0] = geom->GetOrigin()[0]-fib->GetGeometry()->GetCenter()[0]; trans[1] = geom->GetOrigin()[1]-fib->GetGeometry()->GetCenter()[1]; trans[2] = geom->GetOrigin()[2]-fib->GetGeometry()->GetCenter()[2]; mitk::Vector3D newWc = rot*trans; newWc = newWc-trans; geom->Translate(newWc); pe->Modified(); } } } } } else { for (unsigned int i=0; i(m_SelectedFiducials.at(i)->GetData()); mitk::BaseGeometry* geom = pe->GetGeometry(); // translate mitk::Vector3D world; world[0] = m_Controls->m_XtransBox->value(); world[1] = m_Controls->m_YtransBox->value(); world[2] = m_Controls->m_ZtransBox->value(); geom->Translate(world); // calculate rotation matrix double x = m_Controls->m_XrotBox->value()*M_PI/180; double y = m_Controls->m_YrotBox->value()*M_PI/180; double z = m_Controls->m_ZrotBox->value()*M_PI/180; itk::Matrix< double, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; itk::Matrix< double, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; itk::Matrix< double, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< double, 3, 3 > rot = rotZ*rotY*rotX; // transform control point coordinate into geometry translation geom->SetOrigin(pe->GetWorldControlPoint(0)); mitk::Point2D cp; cp.Fill(0.0); pe->SetControlPoint(0, cp); // rotate fiducial geom->GetIndexToWorldTransform()->SetMatrix(rot*geom->GetIndexToWorldTransform()->GetMatrix()); pe->Modified(); } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::CopyBundles() { if ( m_SelectedBundles.size()<1 ){ QMessageBox::information( NULL, "Warning", "Select at least one fiber bundle!"); MITK_WARN("QmitkFiberFoxView") << "Select at least one fiber bundle!"; return; } for (std::vector::const_iterator it = m_SelectedBundles.begin(); it!=m_SelectedBundles.end(); ++it) { // find parent image mitk::DataNode::Pointer parentNode; mitk::DataStorage::SetOfObjects::ConstPointer parentImgs = GetDataStorage()->GetSources(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = parentImgs->begin(); it2 != parentImgs->end(); ++it2 ) { mitk::DataNode::Pointer pImgNode = *it2; if ( pImgNode.IsNotNull() && dynamic_cast(pImgNode->GetData()) ) { parentNode = pImgNode; break; } } mitk::FiberBundle::Pointer fib = dynamic_cast((*it)->GetData()); mitk::FiberBundle::Pointer newBundle = fib->GetDeepCopy(); QString name((*it)->GetName().c_str()); name += "_copy"; mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); if (parentNode.IsNotNull()) GetDataStorage()->Add(fbNode, parentNode); else GetDataStorage()->Add(fbNode); // copy child fiducials if (m_Controls->m_IncludeFiducials->isChecked()) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData())->Clone(); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(pe); newNode->SetName(fiducialNode->GetName()); newNode->SetBoolProperty("planarfigure.3drendering", true); GetDataStorage()->Add(newNode, fbNode); } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::JoinBundles() { if ( m_SelectedBundles.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberFoxView") << "Select at least two fiber bundles!"; return; } std::vector::const_iterator it = m_SelectedBundles.begin(); mitk::FiberBundle::Pointer newBundle = dynamic_cast((*it)->GetData()); QString name(""); name += QString((*it)->GetName().c_str()); ++it; for (; it!=m_SelectedBundles.end(); ++it) { newBundle = newBundle->AddBundle(dynamic_cast((*it)->GetData())); name += "+"+QString((*it)->GetName().c_str()); } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::UpdateGui() { m_Controls->m_GeometryFrame->setEnabled(true); m_Controls->m_GeometryMessage->setVisible(false); m_Controls->m_DiffusionPropsMessage->setVisible(false); m_Controls->m_FiberGenMessage->setVisible(true); m_Controls->m_TransformBundlesButton->setEnabled(false); m_Controls->m_CopyBundlesButton->setEnabled(false); m_Controls->m_GenerateFibersButton->setEnabled(false); m_Controls->m_FlipButton->setEnabled(false); m_Controls->m_CircleButton->setEnabled(false); m_Controls->m_BvalueBox->setEnabled(true); m_Controls->m_NumGradientsBox->setEnabled(true); m_Controls->m_JoinBundlesButton->setEnabled(false); m_Controls->m_AlignOnGrid->setEnabled(false); // Fiber generation gui if (m_SelectedFiducial.IsNotNull()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_FlipButton->setEnabled(true); m_Controls->m_AlignOnGrid->setEnabled(true); } if (m_SelectedImageNode.IsNotNull() || !m_SelectedBundles.empty()) { m_Controls->m_CircleButton->setEnabled(true); m_Controls->m_FiberGenMessage->setVisible(false); } if (m_SelectedImageNode.IsNotNull() && !m_SelectedBundles.empty()) m_Controls->m_AlignOnGrid->setEnabled(true); if (!m_SelectedBundles.empty()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_CopyBundlesButton->setEnabled(true); m_Controls->m_GenerateFibersButton->setEnabled(true); if (m_SelectedBundles.size()>1) m_Controls->m_JoinBundlesButton->setEnabled(true); } // Signal generation gui if (m_Controls->m_MaskComboBox->GetSelectedNode().IsNotNull() || m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull()) { m_Controls->m_GeometryMessage->setVisible(true); m_Controls->m_GeometryFrame->setEnabled(false); } if ( m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull() && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()) ) ) { m_Controls->m_DiffusionPropsMessage->setVisible(true); m_Controls->m_BvalueBox->setEnabled(false); m_Controls->m_NumGradientsBox->setEnabled(false); m_Controls->m_GeometryMessage->setVisible(true); m_Controls->m_GeometryFrame->setEnabled(false); } } void QmitkFiberfoxView::OnSelectionChanged( berry::IWorkbenchPart::Pointer, const QList& nodes ) { m_SelectedBundles2.clear(); m_SelectedImages.clear(); m_SelectedFiducials.clear(); m_SelectedFiducial = NULL; m_SelectedBundles.clear(); m_SelectedImageNode = NULL; // iterate all selected objects, adjust warning visibility for( int i=0; i(node->GetData()) ) { m_SelectedImages.push_back(node); m_SelectedImageNode = node; } else if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedBundles2.push_back(node); if (m_Controls->m_RealTimeFibers->isChecked()) { m_SelectedBundles.push_back(node); mitk::FiberBundle::Pointer newFib = dynamic_cast(node->GetData()); if (newFib->GetNumFibers()!=m_Controls->m_FiberDensityBox->value()) GenerateFibers(); } else m_SelectedBundles.push_back(node); } else if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedFiducials.push_back(node); m_SelectedFiducial = node; m_SelectedBundles.clear(); mitk::DataStorage::SetOfObjects::ConstPointer parents = GetDataStorage()->GetSources(node); for( mitk::DataStorage::SetOfObjects::const_iterator it = parents->begin(); it != parents->end(); ++it ) { mitk::DataNode::Pointer pNode = *it; if ( pNode.IsNotNull() && dynamic_cast(pNode->GetData()) ) m_SelectedBundles.push_back(pNode); } } } UpdateGui(); } void QmitkFiberfoxView::EnableCrosshairNavigation() { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::DisableCrosshairNavigation() { } void QmitkFiberfoxView::NodeRemoved(const mitk::DataNode* node) { mitk::DataNode* nonConstNode = const_cast(node); std::map::iterator it = m_DataNodeToPlanarFigureData.find(nonConstNode); if (dynamic_cast(node->GetData())) { m_SelectedBundles.clear(); m_SelectedBundles2.clear(); } else if (dynamic_cast(node->GetData())) m_SelectedImages.clear(); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; // remove observers data.m_Figure->RemoveObserver( data.m_EndPlacementObserverTag ); data.m_Figure->RemoveObserver( data.m_SelectObserverTag ); data.m_Figure->RemoveObserver( data.m_StartInteractionObserverTag ); data.m_Figure->RemoveObserver( data.m_EndInteractionObserverTag ); m_DataNodeToPlanarFigureData.erase( it ); } } void QmitkFiberfoxView::NodeAdded( const mitk::DataNode* node ) { // add observer for selection in renderwindow mitk::PlanarFigure* figure = dynamic_cast(node->GetData()); bool isPositionMarker (false); node->GetBoolProperty("isContourMarker", isPositionMarker); if( figure && !isPositionMarker ) { MITK_DEBUG << "figure added. will add interactor if needed."; mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); mitk::DataNode* nonConstNode = const_cast( node ); 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( nonConstNode ); } MITK_DEBUG << "will now add observers for planarfigure"; QmitkPlanarFigureData data; data.m_Figure = figure; // // add observer for event when figure has been placed typedef itk::SimpleMemberCommand< QmitkFiberfoxView > SimpleCommandType; // SimpleCommandType::Pointer initializationCommand = SimpleCommandType::New(); // initializationCommand->SetCallbackFunction( this, &QmitkFiberfoxView::PlanarFigureInitialized ); // data.m_EndPlacementObserverTag = figure->AddObserver( mitk::EndPlacementPlanarFigureEvent(), initializationCommand ); // add observer for event when figure is picked (selected) typedef itk::MemberCommand< QmitkFiberfoxView > MemberCommandType; MemberCommandType::Pointer selectCommand = MemberCommandType::New(); selectCommand->SetCallbackFunction( this, &QmitkFiberfoxView::PlanarFigureSelected ); data.m_SelectObserverTag = figure->AddObserver( mitk::SelectPlanarFigureEvent(), selectCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer startInteractionCommand = SimpleCommandType::New(); startInteractionCommand->SetCallbackFunction( this, &QmitkFiberfoxView::DisableCrosshairNavigation); data.m_StartInteractionObserverTag = figure->AddObserver( mitk::StartInteractionPlanarFigureEvent(), startInteractionCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer endInteractionCommand = SimpleCommandType::New(); endInteractionCommand->SetCallbackFunction( this, &QmitkFiberfoxView::EnableCrosshairNavigation); data.m_EndInteractionObserverTag = figure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), endInteractionCommand ); m_DataNodeToPlanarFigureData[nonConstNode] = data; } } void QmitkFiberfoxView::PlanarFigureSelected( itk::Object* object, const itk::EventObject& ) { mitk::TNodePredicateDataType::Pointer isPf = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer allPfs = this->GetDataStorage()->GetSubset( isPf ); for ( mitk::DataStorage::SetOfObjects::const_iterator it = allPfs->begin(); it!=allPfs->end(); ++it) { mitk::DataNode* node = *it; if( node->GetData() == object ) { node->SetSelected(true); m_SelectedFiducial = node; } else node->SetSelected(false); } UpdateGui(); this->RequestRenderWindowUpdate(); } void QmitkFiberfoxView::SetFocus() { m_Controls->m_CircleButton->setFocus(); } void QmitkFiberfoxView::SetOutputPath() { // SELECT FOLDER DIALOG string outputPath = QFileDialog::getExistingDirectory(NULL, "Save images to...", QString(outputPath.c_str())).toStdString(); if (outputPath.empty()) m_Controls->m_SavePathEdit->setText("-"); else { outputPath += "/"; m_Controls->m_SavePathEdit->setText(QString(outputPath.c_str())); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h index fa3f2f52eb..94bcf65efb 100755 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h @@ -1,217 +1,217 @@ /*=================================================================== 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 "ui_QmitkFiberfoxViewControls.h" #include #include #include #ifndef Q_MOC_RUN #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif #include #include #include #include /*! \brief View for fiber based diffusion software phantoms (Fiberfox). See "Fiberfox: Facilitating the creation of realistic white matter software phantoms" (DOI: 10.1002/mrm.25045) for details. \sa QmitkFunctionality \ingroup Functionalities */ // Forward Qt class declarations using namespace std; class QmitkFiberfoxView; class QmitkFiberfoxWorker : public QObject { Q_OBJECT public: QmitkFiberfoxWorker(QmitkFiberfoxView* view); public slots: void run(); private: QmitkFiberfoxView* m_View; }; class QmitkFiberfoxView : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const string VIEW_ID; QmitkFiberfoxView(); virtual ~QmitkFiberfoxView(); virtual void CreateQtPartControl(QWidget *parent) override; void SetFocus() override; typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientDirectionContainerType; typedef itk::Vector GradientType; typedef vector GradientListType; typedef itk::VectorImage< short, 3 > ItkDwiType; typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkFloatImgType; typedef itk::Image ItkUcharImgType; template vector > MakeGradientList(); protected slots: void SetOutputPath(); ///< path where image is automatically saved to after the simulation is finished void LoadParameters(); ///< load fiberfox parameters void SaveParameters(); ///< save fiberfox parameters void BeforeThread(); void AfterThread(); void KillThread(); ///< abort simulation void UpdateSimulationStatus(); ///< print simulation progress and satus messages void OnDrawROI(); ///< adds new ROI, handles interactors etc. void OnAddBundle(); ///< adds new fiber bundle to datastorage void OnFlipButton(); ///< negate one coordinate of the fiber waypoints in the selcted planar figure. needed in case of unresolvable twists void GenerateFibers(); ///< generate fibers from the selected ROIs void GenerateImage(); ///< start image simulation void JoinBundles(); ///< merges selcted fiber bundles into one void CopyBundles(); ///< add copy of the selected bundle to the datamanager void ApplyTransform(); ///< rotate and shift selected bundles void AlignOnGrid(); ///< shift selected fiducials to nearest voxel center void Comp1ModelFrameVisibility(int index); ///< only show parameters of selected signal model for compartment 1 void Comp2ModelFrameVisibility(int index); ///< only show parameters of selected signal model for compartment 2 void Comp3ModelFrameVisibility(int index); ///< only show parameters of selected signal model for compartment 3 void Comp4ModelFrameVisibility(int index); ///< only show parameters of selected signal model for compartment 4 void ShowAdvancedOptions(int state); /** update fibers if any parameter changes */ void OnFiberDensityChanged(int value); void OnFiberSamplingChanged(double value); void OnTensionChanged(double value); void OnContinuityChanged(double value); void OnBiasChanged(double value); void OnVarianceChanged(double value); void OnDistributionChanged(int value); void OnConstantRadius(int value); /** update GUI elements */ void OnAddNoise(int value); void OnAddGhosts(int value); void OnAddDistortions(int value); void OnAddEddy(int value); void OnAddSpikes(int value); void OnAddAliasing(int value); void OnAddMotion(int value); void OnMaskSelected(int value); void OnFibSelected(int value); void OnTemplateSelected(int value); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList&) override; GradientListType GenerateHalfShell(int NPoints); ///< generate vectors distributed over the halfsphere Ui::QmitkFiberfoxViewControls* m_Controls; void SimulateForExistingDwi(mitk::DataNode* imageNode); ///< add artifacts to existing diffusion weighted image void SimulateImageFromFibers(mitk::DataNode* fiberNode); ///< simulate new diffusion weighted image - template< class ScalarType > FiberfoxParameters< ScalarType > UpdateImageParameters(bool all=true); ///< update fiberfox paramater object (template parameter defines noise model type) + template< class ScalarType > FiberfoxParameters< ScalarType > UpdateImageParameters(bool all=true, bool save=false); ///< update fiberfox paramater object (template parameter defines noise model type) void UpdateGui(); ///< enable/disbale buttons etc. according to current datamanager selection void PlanarFigureSelected( itk::Object* object, const itk::EventObject& ); void EnableCrosshairNavigation(); ///< enable crosshair navigation if planar figure interaction ends void DisableCrosshairNavigation(); ///< disable crosshair navigation if planar figure interaction starts void NodeAdded( const mitk::DataNode* node ) override; ///< add observers void NodeRemoved(const mitk::DataNode* node) override; ///< remove observers void SaveParameters(QString filename); /** structure to keep track of planar figures and observers */ struct QmitkPlanarFigureData { QmitkPlanarFigureData() : m_Figure(0) , m_EndPlacementObserverTag(0) , m_SelectObserverTag(0) , m_StartInteractionObserverTag(0) , m_EndInteractionObserverTag(0) , m_Flipped(0) { } mitk::PlanarFigure* m_Figure; unsigned int m_EndPlacementObserverTag; unsigned int m_SelectObserverTag; unsigned int m_StartInteractionObserverTag; unsigned int m_EndInteractionObserverTag; unsigned int m_Flipped; }; std::map m_DataNodeToPlanarFigureData; ///< map each planar figure uniquely to a QmitkPlanarFigureData mitk::DataNode::Pointer m_SelectedFiducial; ///< selected planar ellipse mitk::DataNode::Pointer m_SelectedImageNode; vector< mitk::DataNode::Pointer > m_SelectedBundles; vector< mitk::DataNode::Pointer > m_SelectedBundles2; vector< mitk::DataNode::Pointer > m_SelectedFiducials; vector< mitk::DataNode::Pointer > m_SelectedImages; QString m_ParameterFile; ///< parameter file name // GUI thread QmitkFiberfoxWorker m_Worker; ///< runs filter QThread m_Thread; ///< worker thread bool m_ThreadIsRunning; QTimer* m_SimulationTimer; QTime m_SimulationTime; QString m_SimulationStatusText; /** Image filters that do all the simulations. */ itk::TractsToDWIImageFilter< short >::Pointer m_TractsToDwiFilter; friend class QmitkFiberfoxWorker; }; diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkMLBTView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkMLBTView.cpp index 5c80118200..aeda305197 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkMLBTView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkMLBTView.cpp @@ -1,430 +1,448 @@ /*=================================================================== 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 "QmitkMLBTView.h" #include "QmitkStdMultiWidget.h" // Qt #include #include #include #include #include #include #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include const std::string QmitkMLBTView::VIEW_ID = "org.mitk.views.mlbtview"; using namespace berry; QmitkMLBTView::QmitkMLBTView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) { m_TrackingTimer = std::make_shared(this); m_LastLoadedForestName = "(none)"; } // Destructor QmitkMLBTView::~QmitkMLBTView() { } void QmitkMLBTView::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::QmitkMLBTViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_StartTrainingButton, SIGNAL ( clicked() ), this, SLOT( StartTrainingThread() ) ); connect( &m_TrainingWatcher, SIGNAL ( finished() ), this, SLOT( OnTrainingThreadStop() ) ); connect( m_Controls->m_StartTrackingButton, SIGNAL ( clicked() ), this, SLOT( StartTrackingThread() ) ); connect( &m_TrackingWatcher, SIGNAL ( finished() ), this, SLOT( OnTrackingThreadStop() ) ); connect( m_Controls->m_SaveForestButton, SIGNAL ( clicked() ), this, SLOT( SaveForest() ) ); connect( m_Controls->m_LoadForestButton, SIGNAL ( clicked() ), this, SLOT( LoadForest() ) ); connect( m_TrackingTimer.get(), SIGNAL(timeout()), this, SLOT(BuildFibers()) ); connect( m_Controls->m_TimerIntervalBox, SIGNAL(valueChanged(int)), this, SLOT( ChangeTimerInterval(int) )); connect( m_Controls->m_DemoModeBox, SIGNAL(stateChanged(int)), this, SLOT( ToggleDemoMode(int) )); connect( m_Controls->m_PauseTrackingButton, SIGNAL ( clicked() ), this, SLOT( PauseTracking() ) ); connect( m_Controls->m_AbortTrackingButton, SIGNAL ( clicked() ), this, SLOT( AbortTracking() ) ); connect( m_Controls->m_AddTwButton, SIGNAL ( clicked() ), this, SLOT( AddTrainingWidget() ) ); connect( m_Controls->m_RemoveTwButton, SIGNAL ( clicked() ), this, SLOT( RemoveTrainingWidget() ) ); m_Controls->m_TrackingMaskImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_TrackingSeedImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_TrackingStopImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_TrackingRawImageBox->SetDataStorage(this->GetDataStorage()); + m_Controls->m_FourTTImageBox->SetDataStorage(this->GetDataStorage()); mitk::NodePredicateIsDWI::Pointer isDiffusionImage = mitk::NodePredicateIsDWI::New(); mitk::TNodePredicateDataType::Pointer isMitkImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateNot::Pointer noDiffusionImage = mitk::NodePredicateNot::New(isDiffusionImage); mitk::NodePredicateAnd::Pointer finalPredicate = mitk::NodePredicateAnd::New(isMitkImage, noDiffusionImage); + m_Controls->m_FourTTImageBox->SetPredicate(finalPredicate); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); finalPredicate = mitk::NodePredicateAnd::New(finalPredicate, isBinaryPredicate); m_Controls->m_TrackingMaskImageBox->SetPredicate(finalPredicate); m_Controls->m_TrackingSeedImageBox->SetPredicate(finalPredicate); m_Controls->m_TrackingStopImageBox->SetPredicate(finalPredicate); m_Controls->m_TrackingRawImageBox->SetPredicate(isDiffusionImage); m_Controls->m_TrackingMaskImageBox->SetZeroEntryText("--"); m_Controls->m_TrackingSeedImageBox->SetZeroEntryText("--"); m_Controls->m_TrackingStopImageBox->SetZeroEntryText("--"); + m_Controls->m_FourTTImageBox->SetZeroEntryText("--"); AddTrainingWidget(); UpdateGui(); } } void QmitkMLBTView::AddTrainingWidget() { std::shared_ptr tw = std::make_shared(); tw->SetDataStorage(this->GetDataStorage()); m_Controls->m_TwFrame->layout()->addWidget(tw.get()); m_TrainingWidgets.push_back(tw); } void QmitkMLBTView::RemoveTrainingWidget() { if(m_TrainingWidgets.size()>1) { m_TrainingWidgets.back().reset(); m_TrainingWidgets.pop_back(); } } void QmitkMLBTView::UpdateGui() { if (m_ForestHandler.IsForestValid()) { std::string label_text="Random forest available: "+m_LastLoadedForestName; m_Controls->statusLabel->setText( QString(label_text.c_str()) ); m_Controls->m_SaveForestButton->setEnabled(true); m_Controls->m_StartTrackingButton->setEnabled(true); } else { m_Controls->statusLabel->setText("Please load or train random forest!"); m_Controls->m_SaveForestButton->setEnabled(false); m_Controls->m_StartTrackingButton->setEnabled(false); } } void QmitkMLBTView::AbortTracking() { if (tracker.IsNotNull()) { tracker->m_AbortTracking = true; } } void QmitkMLBTView::PauseTracking() { if (tracker.IsNotNull()) { tracker->m_PauseTracking = !tracker->m_PauseTracking; } } void QmitkMLBTView::ChangeTimerInterval(int value) { m_TrackingTimer->setInterval(value); } void QmitkMLBTView::ToggleDemoMode(int state) { if (tracker.IsNotNull()) { tracker->SetDemoMode(m_Controls->m_DemoModeBox->isChecked()); tracker->m_Stop = false; } } void QmitkMLBTView::BuildFibers() { if (m_Controls->m_DemoModeBox->isChecked() && tracker.IsNotNull() && tracker->m_BuildFibersFinished) { vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); outFib->SetFiberColors(255,255,255); m_TractogramNode->SetData(outFib); m_SamplingPointsNode->SetData(tracker->m_SamplingPointset); m_AlternativePointsNode->SetData(tracker->m_AlternativePointset); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); tracker->m_BuildFibersFinished = false; tracker->m_BuildFibersReady = 0; tracker->m_Stop = false; } } void QmitkMLBTView::LoadForest() { QString filename = QFileDialog::getOpenFileName(0, tr("Load Forest"), QDir::currentPath(), tr("HDF5 random forest file (*.rf)") ); if(filename.isEmpty() || filename.isNull()) return; m_ForestHandler.LoadForest( filename.toStdString() ); QFileInfo fi( filename ); m_LastLoadedForestName = QString( fi.baseName() + "." + fi.completeSuffix() ).toStdString(); UpdateGui(); } void QmitkMLBTView::StartTrackingThread() { m_TractogramNode = mitk::DataNode::New(); m_TractogramNode->SetName("MLBT Result"); - m_TractogramNode->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(20)); - m_TractogramNode->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); - m_TractogramNode->SetProperty("LineWidth", mitk::IntProperty::New(2)); - m_TractogramNode->SetProperty("color",mitk::ColorProperty::New(0, 1, 1)); + //m_TractogramNode->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(20)); + m_TractogramNode->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(true)); + m_TractogramNode->SetProperty("LineWidth", mitk::IntProperty::New(1)); + //m_TractogramNode->SetProperty("color",mitk::ColorProperty::New(0, 1, 1)); this->GetDataStorage()->Add(m_TractogramNode); m_SamplingPointsNode = mitk::DataNode::New(); m_SamplingPointsNode->SetName("SamplingPoints"); m_SamplingPointsNode->SetProperty("pointsize", mitk::FloatProperty::New(0.2)); m_SamplingPointsNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); mitk::PointSetShapeProperty::Pointer bla = mitk::PointSetShapeProperty::New(); bla->SetValue(8); m_SamplingPointsNode->SetProperty("Pointset.2D.shape", bla); m_SamplingPointsNode->SetProperty("Pointset.2D.distance to plane", mitk::FloatProperty::New(1.5)); m_SamplingPointsNode->SetProperty("point 2D size", mitk::FloatProperty::New(0.1)); m_SamplingPointsNode->SetProperty("Pointset.2D.fill shape", mitk::BoolProperty::New(true)); this->GetDataStorage()->Add(m_SamplingPointsNode); m_AlternativePointsNode = mitk::DataNode::New(); m_AlternativePointsNode->SetName("AlternativePoints"); m_AlternativePointsNode->SetProperty("pointsize", mitk::FloatProperty::New(0.2)); m_AlternativePointsNode->SetProperty("color", mitk::ColorProperty::New(1,0,0)); m_AlternativePointsNode->SetProperty("Pointset.2D.shape", bla); m_AlternativePointsNode->SetProperty("Pointset.2D.distance to plane", mitk::FloatProperty::New(1.5)); m_AlternativePointsNode->SetProperty("point 2D size", mitk::FloatProperty::New(0.1)); m_AlternativePointsNode->SetProperty("Pointset.2D.fill shape", mitk::BoolProperty::New(true)); this->GetDataStorage()->Add(m_AlternativePointsNode); QFuture future = QtConcurrent::run( this, &QmitkMLBTView::StartTracking ); m_TrackingWatcher.setFuture(future); m_TrackingThreadIsRunning = true; m_Controls->m_StartTrackingButton->setEnabled(false); m_TrackingTimer->start(m_Controls->m_TimerIntervalBox->value()); } void QmitkMLBTView::OnTrackingThreadStop() { m_TrackingThreadIsRunning = false; m_Controls->m_StartTrackingButton->setEnabled(true); vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); m_TractogramNode->SetData(outFib); m_TractogramNode->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(1)); if (m_Controls->m_DemoModeBox->isChecked()) { m_SamplingPointsNode->SetData(tracker->m_SamplingPointset); m_AlternativePointsNode->SetData(tracker->m_AlternativePointset); } tracker = NULL; m_TrackingTimer->stop(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkMLBTView::StartTracking() { if ( m_Controls->m_TrackingRawImageBox->GetSelectedNode().IsNull() || !m_ForestHandler.IsForestValid()) return; mitk::Image::Pointer dwi = dynamic_cast(m_Controls->m_TrackingRawImageBox->GetSelectedNode()->GetData()); - m_ForestHandler.AddRawData(dwi); + m_ForestHandler.AddDwi(dwi); // int numThread = itk::MultiThreader::GetGlobalDefaultNumberOfThreads(); tracker = TrackerType::New(); tracker->SetInput(0, mitk::DiffusionPropertyHelper::GetItkVectorImage(dwi) ); tracker->SetDemoMode(m_Controls->m_DemoModeBox->isChecked()); if (m_Controls->m_DemoModeBox->isChecked()) tracker->SetNumberOfThreads(1); if (m_Controls->m_TrackingMaskImageBox->GetSelectedNode().IsNotNull()) { mitk::Image::Pointer mask = dynamic_cast(m_Controls->m_TrackingMaskImageBox->GetSelectedNode()->GetData()); ItkUcharImgType::Pointer itkMask = ItkUcharImgType::New(); mitk::CastToItkImage(mask, itkMask); tracker->SetMaskImage(itkMask); } if (m_Controls->m_TrackingSeedImageBox->GetSelectedNode().IsNotNull()) { mitk::Image::Pointer img = dynamic_cast(m_Controls->m_TrackingSeedImageBox->GetSelectedNode()->GetData()); ItkUcharImgType::Pointer itkImg = ItkUcharImgType::New(); mitk::CastToItkImage(img, itkImg); tracker->SetSeedImage(itkImg); } if (m_Controls->m_TrackingStopImageBox->GetSelectedNode().IsNotNull()) { mitk::Image::Pointer img = dynamic_cast(m_Controls->m_TrackingStopImageBox->GetSelectedNode()->GetData()); ItkUcharImgType::Pointer itkImg = ItkUcharImgType::New(); mitk::CastToItkImage(img, itkImg); tracker->SetStoppingRegions(itkImg); } + if (m_Controls->m_FourTTImageBox->GetSelectedNode().IsNotNull()) + { + mitk::Image::Pointer img = dynamic_cast(m_Controls->m_FourTTImageBox->GetSelectedNode()->GetData()); + ItkUcharImgType::Pointer itkImg = ItkUcharImgType::New(); + mitk::CastToItkImage(img, itkImg); + tracker->SetFourTTImage(itkImg); + } + tracker->SetSeedsPerVoxel(m_Controls->m_NumberOfSeedsBox->value()); tracker->SetStepSize(m_Controls->m_TrackingStepSizeBox->value()); tracker->SetMinTractLength(m_Controls->m_MinLengthBox->value()); tracker->SetMaxTractLength(m_Controls->m_MaxLengthBox->value()); tracker->SetAposterioriCurvCheck(m_Controls->m_Curvcheck2->isChecked()); - tracker->SetRemoveWmEndFibers(false); + tracker->SetNumberOfSamples(m_Controls->m_NumSamplesBox->value()); tracker->SetAvoidStop(m_Controls->m_AvoidStop->isChecked()); tracker->SetForestHandler(m_ForestHandler); tracker->SetSamplingDistance(m_Controls->m_SamplingDistanceBox->value()); - tracker->SetNumberOfSamples(m_Controls->m_NumSamplesBox->value()); + tracker->SetDeflectionMod(m_Controls->m_DeflectionModBox->value()); tracker->SetRandomSampling(m_Controls->m_RandomSampling->isChecked()); + tracker->SetUseStopVotes(m_Controls->m_UseStopVotes->isChecked()); + tracker->SetOnlyForwardSamples(m_Controls->m_OnlyForwardSamples->isChecked()); + tracker->SetNumPreviousDirections(m_Controls->m_NumPrevDirs->value()); + tracker->SetSeedOnlyGm(m_Controls->m_SeedGm->isChecked()); tracker->Update(); } void QmitkMLBTView::SaveForest() { if (!m_ForestHandler.IsForestValid()) { UpdateGui(); return; } QString filename = QFileDialog::getSaveFileName(0, tr("Save Forest"), QDir::currentPath()+"/forest.rf", tr("HDF5 random forest file (*.rf)") ); if(filename.isEmpty() || filename.isNull()) return; if(!filename.endsWith(".rf")) filename += ".rf"; m_ForestHandler.SaveForest( filename.toStdString() ); } void QmitkMLBTView::StartTrainingThread() { if (!this->IsTrainingInputValid()) { QMessageBox::warning(nullptr, "Training aborted", "Training could not be started. Not all necessary datasets were selected."); return; } QFuture future = QtConcurrent::run( this, &QmitkMLBTView::StartTraining ); m_TrainingWatcher.setFuture(future); m_Controls->m_StartTrainingButton->setEnabled(false); m_Controls->m_SaveForestButton->setEnabled(false); m_Controls->m_LoadForestButton->setEnabled(false); } void QmitkMLBTView::OnTrainingThreadStop() { m_Controls->m_StartTrainingButton->setEnabled(true); m_Controls->m_SaveForestButton->setEnabled(true); m_Controls->m_LoadForestButton->setEnabled(true); UpdateGui(); } void QmitkMLBTView::StartTraining() { std::vector< mitk::Image::Pointer > m_SelectedDiffImages; std::vector< mitk::FiberBundle::Pointer > m_SelectedFB; std::vector< ItkUcharImgType::Pointer > m_MaskImages; std::vector< ItkUcharImgType::Pointer > m_WhiteMatterImages; for (auto w : m_TrainingWidgets) { m_SelectedDiffImages.push_back(dynamic_cast(w->GetImage()->GetData())); m_SelectedFB.push_back(dynamic_cast(w->GetFibers()->GetData())); if (w->GetMask().IsNotNull()) { mitk::Image::Pointer img = dynamic_cast(w->GetMask()->GetData()); ItkUcharImgType::Pointer itkMask = ItkUcharImgType::New(); mitk::CastToItkImage(img, itkMask); m_MaskImages.push_back(itkMask); } else m_MaskImages.push_back(nullptr); if (w->GetWhiteMatter().IsNotNull()) { mitk::Image::Pointer img = dynamic_cast(w->GetWhiteMatter()->GetData()); ItkUcharImgType::Pointer itkMask = ItkUcharImgType::New(); mitk::CastToItkImage(img, itkMask); m_WhiteMatterImages.push_back(itkMask); } else m_WhiteMatterImages.push_back(nullptr); } - m_ForestHandler.SetRawData(m_SelectedDiffImages); + m_ForestHandler.SetDwis(m_SelectedDiffImages); m_ForestHandler.SetTractograms(m_SelectedFB); m_ForestHandler.SetMaskImages(m_MaskImages); m_ForestHandler.SetWhiteMatterImages(m_WhiteMatterImages); m_ForestHandler.SetNumTrees(m_Controls->m_NumTreesBox->value()); m_ForestHandler.SetMaxTreeDepth(m_Controls->m_MaxDepthBox->value()); m_ForestHandler.SetGrayMatterSamplesPerVoxel(m_Controls->m_GmSamplingBox->value()); m_ForestHandler.SetSampleFraction(m_Controls->m_SampleFractionBox->value()); m_ForestHandler.SetStepSize(m_Controls->m_TrainingStepSizeBox->value()); + m_ForestHandler.SetNumPreviousDirections(m_Controls->m_NumPrevDirs->value()); + m_ForestHandler.SetBidirectionalFiberSampling(m_Controls->m_BidirectionalSampling->isChecked()); + m_ForestHandler.SetZeroDirWmFeatures(m_Controls->m_ZeroDirBox->isChecked()); m_ForestHandler.StartTraining(); } void QmitkMLBTView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkMLBTView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkMLBTView::Activated() { } bool QmitkMLBTView::IsTrainingInputValid(void) const { for (auto widget : m_TrainingWidgets) { if (widget->GetImage().IsNull() || widget->GetFibers().IsNull()) { return false; } } return true; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkMLBTView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkMLBTView.h index 4b34f9b68b..cf3d7690c0 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkMLBTView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkMLBTView.h @@ -1,112 +1,112 @@ /*=================================================================== 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 "ui_QmitkMLBTViewControls.h" #ifndef Q_MOC_RUN #include "mitkDataStorage.h" #include "mitkDataStorageSelection.h" #include #include #endif #include #include #include #include #include #include /*! \brief View to perform machine learning based fiber tractography. Includes training of the random forst classifier as well as the actual tractography. */ // Forward Qt class declarations class QmitkMLBTView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; typedef itk::Image ItkUcharImgType; - typedef itk::MLBSTrackingFilter<> TrackerType; + typedef itk::MLBSTrackingFilter<6,100> TrackerType; QmitkMLBTView(); virtual ~QmitkMLBTView(); virtual void CreateQtPartControl(QWidget *parent) override; virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) override; virtual void StdMultiWidgetNotAvailable() override; virtual void Activated() override; protected slots: void StartTrackingThread(); void OnTrackingThreadStop(); void StartTrainingThread(); void OnTrainingThreadStop(); void SaveForest(); void LoadForest(); void BuildFibers(); void ChangeTimerInterval(int value); void ToggleDemoMode(int state); void PauseTracking(); void AbortTracking(); void AddTrainingWidget(); void RemoveTrainingWidget(); protected: void StartTracking(); void StartTraining(); void UpdateGui(); Ui::QmitkMLBTViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; - mitk::TrackingForestHandler<> m_ForestHandler; + mitk::TrackingForestHandler<6,100> m_ForestHandler; QFutureWatcher m_TrainingWatcher; QFutureWatcher m_TrackingWatcher; bool m_TrackingThreadIsRunning; TrackerType::Pointer tracker; std::shared_ptr m_TrackingTimer; mitk::DataNode::Pointer m_TractogramNode; mitk::DataNode::Pointer m_SamplingPointsNode; mitk::DataNode::Pointer m_AlternativePointsNode; std::vector< std::shared_ptr > m_TrainingWidgets; private: bool IsTrainingInputValid(void) const; std::string m_LastLoadedForestName; }; diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkMLBTViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkMLBTViewControls.ui index 23a0ba0b40..44a2ae5e27 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkMLBTViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkMLBTViewControls.ui @@ -1,762 +1,905 @@ QmitkMLBTViewControls 0 0 - 696 - 907 + 503 + 672 Form - - - - Please load or train random forest! - - - Qt::AlignCenter - - - - + 1 0 0 - 678 - 804 + 485 + 517 Training - - - - Save Forest - - - QFrame::NoFrame QFrame::Raised 0 0 0 0 Add additional training data pair ... :/org_mitk_icons/icons/tango/scalable/actions/list-add.svg:/org_mitk_icons/icons/tango/scalable/actions/list-add.svg Remove training data pair ... :/org_mitk_icons/icons/tango/scalable/actions/list-remove.svg:/org_mitk_icons/icons/tango/scalable/actions/list-remove.svg QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Input DWI: Qt::AlignCenter Reference Tractogram: Qt::AlignCenter Mask: Qt::AlignCenter WM: Qt::AlignCenter + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Start Training + + + + + + + Use direction as well as zero-vector as directional training feature at each point. This enables to learn to predict the direction without a previous direction (e.g. at seed point). + + + Zero-direction features + + + true + + + QFrame::NoFrame QFrame::Raised 0 0 0 0 Maximum tree depth. 1 999999999 - 30 + 25 Non-WM Sampling Points: Fiber Sampling: Number of tress in the final random forest. 1 999999999 - 50 + 30 Fiber sampling in mm. Determines the number of white-matter samples (-1 = auto). 3 -1.000000000000000 999.000000000000000 0.100000000000000 -1.000000000000000 Num. Trees: Number of sampling points outside of the white-matter (-1 = automatic estimation). -1 999999999 -1 Max. Depth: Sample Fraction: Fraction of samples used to train each tree. 3 1.000000000000000 0.100000000000000 - 1.000000000000000 + 0.700000000000000 - - + + - Start Training + Save Forest - - - - Qt::Vertical + + + + Sample fibers in both directions. - - - 20 - 40 - + + Bidirectional sampling - + + true + + 0 0 - 678 - 804 + 471 + 657 Tractography - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Demo Mode - - - - - - - 1 - - - 1000 - - - 10 - - - - - - Random sampling false - - + + QFrame::NoFrame QFrame::Raised - + 0 0 0 0 - - - - - - - - + + - - - - Mask Image: + + + + 999999999.000000000000000 - - - - - - Seed Image: + + 1.000000000000000 + + + 400.000000000000000 - - + + - Stop Image: + Deflection distance modifier: - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - Number of seeds per voxel. 1 999 - - - - - + + - 999999999.000000000000000 + 1.000000000000000 - 1.000000000000000 + 0.100000000000000 - 400.000000000000000 + 1.000000000000000 - - - - 999999999.000000000000000 - - - 1.000000000000000 - - - 20.000000000000000 + + + + Num. Seeds: - - - - 999999999 + + + + 0.100000000000000 - 50 + 0.500000000000000 - - + + - Sampling Distance: + Step Size: - + - Min. Length + Num. Samples: - - - - Num. Seeds: + + + + 0.000000000000000 - - + + + + 999999999.000000000000000 + - 0.100000000000000 + 1.000000000000000 - 0.500000000000000 + 20.000000000000000 - - + + - Max. Length + Sampling Distance: - - + + - Step Size: + Input DWI: - - + + - Input DWI: + Max. Length - - + + - Num. Samples: + Min. Length - - + + + + Number of seeds per voxel. + + + 0 + + + 256 + - 0.500000000000000 + 30 - - + + - Avoid premature termination + Secondary curvature check - true + false - + + + + Load Forest + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Demo Mode + + + + + + + 1 + + + 1000 + + + 10 + + + + + + + QFrame::NoFrame QFrame::Raised 0 0 0 0 Pause tractography ... :/org_mitk_icons/icons/tango/scalable/actions/media-playback-pause.svg:/org_mitk_icons/icons/tango/scalable/actions/media-playback-pause.svg Start tractography ... :/org_mitk_icons/icons/tango/scalable/actions/media-playback-start.svg:/org_mitk_icons/icons/tango/scalable/actions/media-playback-start.svg Abort tractography ... :/org_mitk_icons/icons/tango/scalable/actions/media-playback-stop.svg:/org_mitk_icons/icons/tango/scalable/actions/media-playback-stop.svg - + Qt::Vertical 20 40 - - + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Mask Image: + + + + + + + Seed Image: + + + + + + + + + + Stop Image: + + + + + + + + + + 4TT Image: + + + + + + + + + + + - Secondary curvature check + Use stop votes true - - + + - Load Forest + Avoid premature termination + + + true + + + + + + + Only frontal samples + + + true + + + + + + + Seed only GM + + + false + + + + Please load or train random forest! + + + Qt::AlignCenter + + + + + + + Training and tractography + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Num. previous directions: + + + + + + + Number of seeds per voxel. + + + 0 + + + 50 + + + 1 + + + + + + + + + + Qt::Horizontal + + + QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkODFDetailsView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkODFDetailsView.cpp index 5732a7fb54..39d369fabc 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkODFDetailsView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkODFDetailsView.cpp @@ -1,377 +1,387 @@ /*=================================================================== 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 "QmitkODFDetailsView.h" #include #include #include #include #include #include #include #include #include #include #include #include const std::string QmitkODFDetailsView::VIEW_ID = "org.mitk.views.odfdetails"; QmitkODFDetailsView::QmitkODFDetailsView() : QmitkAbstractView() , m_Controls( 0 ) , m_OdfNormalization(0) , m_ImageNode(NULL) { m_VtkActor = vtkActor::New(); m_VtkMapper = vtkPolyDataMapper::New(); m_Renderer = vtkRenderer::New(); m_VtkRenderWindow = vtkRenderWindow::New(); m_RenderWindowInteractor = vtkRenderWindowInteractor::New(); m_Camera = vtkCamera::New(); m_VtkRenderWindow->SetSize(300,300); } QmitkODFDetailsView::~QmitkODFDetailsView() { if (m_ImageNode.IsNotNull()) m_ImageNode->RemoveObserver( m_PropertyObserverTag ); } void QmitkODFDetailsView::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, &QmitkODFDetailsView::OnSliceChanged ); m_SliceObserverTag1 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); } { mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("sagittal"))->GetSliceNavigationController(); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); m_SliceObserverTag2 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); } { mitk::SliceNavigationController* slicer = renderWindow->GetQmitkRenderWindow(QString("coronal"))->GetSliceNavigationController(); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); m_SliceObserverTag3 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); } } } void QmitkODFDetailsView::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 QmitkODFDetailsView::Activated() { } void QmitkODFDetailsView::Deactivated() { } void QmitkODFDetailsView::SetFocus() { this->m_Controls->m_ODFRenderWidget->setFocus(); } void QmitkODFDetailsView::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::QmitkODFDetailsViewControls; m_Controls->setupUi( parent ); m_Controls->m_OdfBox->setVisible(false); m_Controls->m_ODFRenderWidget->setVisible(false); } } void QmitkODFDetailsView::OnSelectionChanged( berry::IWorkbenchPart::Pointer source, const QList& nodes ) { if (m_ImageNode.IsNotNull()) m_ImageNode->RemoveObserver( m_PropertyObserverTag ); m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_InputImageLabel->setText("mandatory"); m_ImageNode = NULL; // iterate selection foreach( mitk::DataNode::Pointer node, nodes ) { if( node.IsNotNull() && (dynamic_cast(node->GetData()) || dynamic_cast(node->GetData())) ) { m_Controls->m_InputImageLabel->setText(node->GetName().c_str()); m_ImageNode = node; } } UpdateOdf(); if (m_ImageNode.IsNotNull()) { itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkODFDetailsView::OnSliceChanged ); m_PropertyObserverTag = m_ImageNode->AddObserver( itk::ModifiedEvent(), command ); m_Controls->m_InputData->setTitle("Input Data"); } } void QmitkODFDetailsView::UpdateOdf() { try { m_Controls->m_OverviewBox->setVisible(true); if (m_ImageNode.IsNull() || !this->GetRenderWindowPart()) { m_Controls->m_ODFRenderWidget->setVisible(false); m_Controls->m_OdfBox->setVisible(false); m_Controls->m_OverviewBox->setVisible(false); return; } // restore the input image label ( needed in case the last run resulted into an exception ) m_Controls->m_InputImageLabel->setText(m_ImageNode->GetName().c_str()); // ODF Normalization Property mitk::OdfNormalizationMethodProperty* nmp = dynamic_cast(m_ImageNode->GetProperty( "Normalization" )); if(nmp) m_OdfNormalization = nmp->GetNormalization(); m_TemplateOdf = itk::OrientationDistributionFunction::GetBaseMesh(); m_OdfTransform = vtkSmartPointer::New(); m_OdfTransform->Identity(); m_OdfVals = vtkSmartPointer::New(); m_OdfSource = vtkSmartPointer::New(); itk::OrientationDistributionFunction odf; mitk::Point3D world = this->GetRenderWindowPart()->GetSelectedPosition(); mitk::Point3D index; mitk::Image::Pointer img = dynamic_cast(m_ImageNode->GetData()); unsigned int *img_dimension = img->GetDimensions(); img->GetGeometry()->WorldToIndex(world, index); float sum = 0; float max = itk::NumericTraits::NonpositiveMin(); float min = itk::NumericTraits::max(); QString values; QString overviewText; // check if dynamic_cast successfull and if the crosshair position is inside of the geometry of the ODF data // otherwise possible crash for a scenario with multiple nodes if (dynamic_cast(m_ImageNode->GetData()) && ( m_ImageNode->GetData()->GetGeometry()->IsInside(world) ) ) { m_Controls->m_ODFRenderWidget->setVisible(true); m_Controls->m_OdfBox->setVisible(true); try { const mitk::QBallImage* qball_image = dynamic_cast< mitk::QBallImage* >( m_ImageNode->GetData() ); // get access to the qball image data with explicitely allowing exceptions if memory locked mitk::ImageReadAccessor readAccess( qball_image, qball_image->GetVolumeData(0), mitk::ImageAccessorBase::ExceptionIfLocked ); const float* qball_cPtr = static_cast< const float*>(readAccess.GetData()); OdfVectorImgType::IndexType ind; ind[0] = (int)(index[0]+0.5); ind[1] = (int)(index[1]+0.5); ind[2] = (int)(index[2]+0.5); // pixel size = QBALL_ODFSIZE // position offset = standard offset unsigned int offset_to_data = QBALL_ODFSIZE * (ind[2] * img_dimension[1] * img_dimension[0] + ind[1] * img_dimension[0] + ind[0]); const float *pixel_data = qball_cPtr + offset_to_data; for (int i=0; imax) max = val; if (val pd = odf.GetDirection(odf.GetPrincipleDiffusionDirection()); overviewText += "Main Diffusion:\n "+QString::number(pd[0])+"\n "+QString::number(pd[1])+"\n "+QString::number(pd[2])+"\n"; m_Controls->m_OdfValuesTextEdit->setText(values); m_Controls->m_OverviewTextEdit->setVisible(true); } catch( mitk::Exception &e ) { MITK_WARN << "LOCKED : " << e.what(); m_Controls->m_ODFRenderWidget->setVisible(false); m_Controls->m_OdfBox->setVisible(false); m_Controls->m_OverviewTextEdit->setVisible(false); // reset the selection m_Controls->m_InputImageLabel->setText("Click image to restore rendering!"); } } else if (dynamic_cast(m_ImageNode->GetData()) && ( m_ImageNode->GetData()->GetGeometry()->IsInside(world) ) ) { m_Controls->m_ODFRenderWidget->setVisible(true); m_Controls->m_OdfBox->setVisible(false); const mitk::TensorImage* qball_image = dynamic_cast< mitk::TensorImage*>(m_ImageNode->GetData()); // pixel access block try { // get access to the qball image data with explicitely allowing exceptions if memory locked mitk::ImageReadAccessor readAccess( qball_image, qball_image->GetVolumeData(0), mitk::ImageAccessorBase::ExceptionIfLocked ); const float* qball_cPtr = static_cast< const float*>(readAccess.GetData()); TensorImageType::IndexType ind; ind[0] = (int)(index[0]+0.5); ind[1] = (int)(index[1]+0.5); ind[2] = (int)(index[2]+0.5); // 6 - tensorsize // remaining computation - standard offset unsigned int offset_to_data = 6 * (ind[2] * img_dimension[1] * img_dimension[0] + ind[1] * img_dimension[0] + ind[0]); const float *pixel_data = qball_cPtr + offset_to_data; float tensorelems[6] = { *(pixel_data ), *(pixel_data + 1), *(pixel_data + 2), *(pixel_data + 3), *(pixel_data + 4), *(pixel_data + 5), }; itk::DiffusionTensor3D tensor(tensorelems); odf.InitFromTensor(tensor); /** Array of eigen-values. */ typedef itk::FixedArray EigenValuesArrayType; /** Matrix of eigen-vectors. */ typedef itk::Matrix MatrixType; typedef itk::Matrix EigenVectorsMatrixType; EigenValuesArrayType eigenValues; EigenVectorsMatrixType eigenvectors; QString pos = QString::number(ind[0])+", "+QString::number(ind[1])+", "+QString::number(ind[2]); overviewText += "Coordinates: "+pos+"\n"; overviewText += "FA: "+QString::number(tensor.GetFractionalAnisotropy())+"\n"; overviewText += "RA: "+QString::number(tensor.GetRelativeAnisotropy())+"\n"; overviewText += "Trace: "+QString::number(tensor.GetTrace())+"\n"; tensor.ComputeEigenAnalysis(eigenValues,eigenvectors); overviewText += "Eigenvalues:\n "+QString::number(eigenValues[2])+"\n "+QString::number(eigenValues[1])+"\n "+QString::number(eigenValues[0])+"\n"; overviewText += "Main Diffusion:\n "+QString::number(eigenvectors(2, 0))+"\n "+QString::number(eigenvectors(2, 1))+"\n "+QString::number(eigenvectors(2, 2))+"\n"; overviewText += "Values:\n "+QString::number(tensorelems[0])+"\n "+QString::number(tensorelems[1])+"\n "+QString::number(tensorelems[2])+"\n "+QString::number(tensorelems[3])+"\n "+QString::number(tensorelems[4])+"\n "+QString::number(tensorelems[5])+"\n "+"\n"; m_Controls->m_OverviewTextEdit->setVisible(true); } // end pixel access block catch(mitk::Exception &e ) { MITK_WARN << "LOCKED : " << e.what(); m_Controls->m_ODFRenderWidget->setVisible(false); m_Controls->m_OdfBox->setVisible(false); m_Controls->m_OverviewTextEdit->setVisible(false); // reset the selection m_Controls->m_InputImageLabel->setText("Click image to restore rendering!"); } } else { m_Controls->m_ODFRenderWidget->setVisible(false); m_Controls->m_OdfBox->setVisible(false); overviewText += "Please reinit image geometry.\n"; } // proceed only if the render widget is visible which indicates that the // predecessing computations were successfull if( m_Controls->m_ODFRenderWidget->isVisible() ) { m_Controls->m_ODFDetailsWidget->SetParameters(odf); switch(m_OdfNormalization) { case 0: odf = odf.MinMaxNormalize(); break; case 1: odf = odf.MaxNormalize(); break; case 2: odf = odf.MaxNormalize(); break; default: odf = odf.MinMaxNormalize(); } m_Controls->m_ODFRenderWidget->GenerateODF(odf); m_Controls->m_OverviewTextEdit->setText(overviewText.toStdString().c_str()); } } catch(...) { QMessageBox::critical(0, "Error", "Data could not be analyzed. The image might be corrupted."); } } void QmitkODFDetailsView::OnSliceChanged(const itk::EventObject& /*e*/) { UpdateOdf(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionView.cpp index 15fd3e614c..69c1b8c3cf 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionView.cpp @@ -1,778 +1,784 @@ /*=================================================================== 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 // Qt #include const std::string QmitkOdfMaximaExtractionView::VIEW_ID = "org.mitk.views.odfmaximaextractionview"; using namespace mitk; QmitkOdfMaximaExtractionView::QmitkOdfMaximaExtractionView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) { } // 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_StartTensor, SIGNAL(clicked()), (QObject*) this, SLOT(StartTensor())); connect((QObject*) m_Controls->m_StartFiniteDiff, SIGNAL(clicked()), (QObject*) this, SLOT(StartFiniteDiff())); connect((QObject*) m_Controls->m_GenerateImageButton, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateImage())); connect((QObject*) m_Controls->m_ImportPeaks, SIGNAL(clicked()), (QObject*) this, SLOT(ConvertPeaks())); connect((QObject*) m_Controls->m_ImportShCoeffs, SIGNAL(clicked()), (QObject*) this, SLOT(ConvertShCoeffs())); } } void QmitkOdfMaximaExtractionView::UpdateGui() { m_Controls->m_GenerateImageButton->setEnabled(false); m_Controls->m_StartFiniteDiff->setEnabled(false); m_Controls->m_StartTensor->setEnabled(false); m_Controls->m_CoeffImageFrame->setEnabled(false); if (!m_ImageNodes.empty() || !m_TensorImageNodes.empty()) { m_Controls->m_InputData->setTitle("Input Data"); if (!m_TensorImageNodes.empty()) { m_Controls->m_DwiFibLabel->setText(m_TensorImageNodes.front()->GetName().c_str()); m_Controls->m_StartTensor->setEnabled(true); } else { m_Controls->m_DwiFibLabel->setText(m_ImageNodes.front()->GetName().c_str()); m_Controls->m_StartFiniteDiff->setEnabled(true); m_Controls->m_GenerateImageButton->setEnabled(true); m_Controls->m_CoeffImageFrame->setEnabled(true); m_Controls->m_ShOrderBox->setEnabled(true); m_Controls->m_MaxNumPeaksBox->setEnabled(true); m_Controls->m_PeakThresholdBox->setEnabled(true); m_Controls->m_AbsoluteThresholdBox->setEnabled(true); } } else m_Controls->m_DwiFibLabel->setText("mandatory"); if (m_ImageNodes.empty()) { m_Controls->m_ImportPeaks->setEnabled(false); m_Controls->m_ImportShCoeffs->setEnabled(false); } else { m_Controls->m_ImportPeaks->setEnabled(true); m_Controls->m_ImportShCoeffs->setEnabled(true); } if (!m_BinaryImageNodes.empty()) { m_Controls->m_MaskLabel->setText(m_BinaryImageNodes.front()->GetName().c_str()); } else { m_Controls->m_MaskLabel->setText("optional"); } } 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::QballImageType::Pointer itkQbi = filter->GetQballImage(); 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); node->SetName("_ShCoefficientImage"); node->SetVisibility(false); GetDataStorage()->Add(node); } { mitk::QBallImage::Pointer img = mitk::QBallImage::New(); img->InitializeByItk( itkQbi.GetPointer() ); img->SetVolume( itkQbi->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(img); node->SetName("_QballImage"); GetDataStorage()->Add(node); } } void QmitkOdfMaximaExtractionView::ConvertShCoeffs() { if (m_ImageNodes.empty()) return; mitk::Image::Pointer mitkImg = dynamic_cast(m_ImageNodes.at(0)->GetData()); if (mitkImg->GetDimension()!=4) { 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; MITK_INFO << "using SH-order " << shOrder; switch (shOrder) { case 2: TemplatedConvertShCoeffs<2>(mitkImg); break; case 4: TemplatedConvertShCoeffs<4>(mitkImg); break; case 6: TemplatedConvertShCoeffs<6>(mitkImg); break; case 8: TemplatedConvertShCoeffs<8>(mitkImg); break; case 10: TemplatedConvertShCoeffs<10>(mitkImg); break; case 12: TemplatedConvertShCoeffs<12>(mitkImg); break; default: MITK_INFO << "SH-order " << shOrder << " not supported"; } } void QmitkOdfMaximaExtractionView::ConvertPeaks() { if (m_ImageNodes.empty()) return; switch (m_Controls->m_ToolkitBox->currentIndex()) { case 0: { typedef itk::Image< float, 4 > ItkImageType; typedef itk::FslPeakImageConverter< float > FilterType; FilterType::Pointer filter = FilterType::New(); FilterType::InputType::Pointer inputVec = FilterType::InputType::New(); mitk::BaseGeometry::Pointer geom; for (int i=0; i(m_ImageNodes.at(i)->GetData()); geom = mitkImg->GetGeometry(); typedef mitk::ImageToItk< FilterType::InputImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkImg); caster->Update(); FilterType::InputImageType::Pointer itkImg = caster->GetOutput(); inputVec->InsertElement(inputVec->Size(), itkImg); } filter->SetInputImages(inputVec); + filter->SetInvertX(m_Controls->m_InvertX->isChecked()); + filter->SetInvertY(m_Controls->m_InvertY->isChecked()); + filter->SetInvertZ(m_Controls->m_InvertZ->isChecked()); filter->GenerateData(); mitk::Vector3D outImageSpacing = geom->GetSpacing(); float maxSpacing = 1; if(outImageSpacing[0]>outImageSpacing[1] && outImageSpacing[0]>outImageSpacing[2]) maxSpacing = outImageSpacing[0]; else if (outImageSpacing[1] > outImageSpacing[2]) maxSpacing = outImageSpacing[1]; else maxSpacing = outImageSpacing[2]; mitk::FiberBundle::Pointer directions = filter->GetOutputFiberBundle(); // directions->SetGeometry(geom); DataNode::Pointer node = DataNode::New(); node->SetData(directions); node->SetName("_VectorField"); node->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(maxSpacing)); node->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); GetDataStorage()->Add(node); typedef FilterType::DirectionImageContainerType DirectionImageContainerType; DirectionImageContainerType::Pointer container = filter->GetDirectionImageContainer(); for (int i=0; iSize(); i++) { ItkDirectionImage3DType::Pointer itkImg = container->GetElement(i); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk( itkImg.GetPointer() ); img->SetVolume( itkImg->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_ImageNodes.at(i)->GetName().c_str()); name += "_Direction"; name += QString::number(i+1); node->SetName(name.toStdString().c_str()); node->SetVisibility(false); GetDataStorage()->Add(node); } break; } case 1: { typedef itk::Image< float, 4 > ItkImageType; typedef itk::MrtrixPeakImageConverter< float > FilterType; FilterType::Pointer filter = FilterType::New(); // cast to itk mitk::Image::Pointer mitkImg = dynamic_cast(m_ImageNodes.at(0)->GetData()); mitk::BaseGeometry::Pointer geom = mitkImg->GetGeometry(); typedef mitk::ImageToItk< FilterType::InputImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitkImg); caster->Update(); FilterType::InputImageType::Pointer itkImg = caster->GetOutput(); filter->SetInputImage(itkImg); + filter->SetInvertX(m_Controls->m_InvertX->isChecked()); + filter->SetInvertY(m_Controls->m_InvertY->isChecked()); + filter->SetInvertZ(m_Controls->m_InvertZ->isChecked()); filter->GenerateData(); mitk::Vector3D outImageSpacing = geom->GetSpacing(); float maxSpacing = 1; if(outImageSpacing[0]>outImageSpacing[1] && outImageSpacing[0]>outImageSpacing[2]) maxSpacing = outImageSpacing[0]; else if (outImageSpacing[1] > outImageSpacing[2]) maxSpacing = outImageSpacing[1]; else maxSpacing = outImageSpacing[2]; mitk::FiberBundle::Pointer directions = filter->GetOutputFiberBundle(); //directions->SetGeometry(geom); DataNode::Pointer node = DataNode::New(); node->SetData(directions); QString name(m_ImageNodes.at(0)->GetName().c_str()); name += "_VectorField"; node->SetName(name.toStdString().c_str()); node->SetProperty("Fiber2DSliceThickness", mitk::FloatProperty::New(maxSpacing)); node->SetProperty("Fiber2DfadeEFX", mitk::BoolProperty::New(false)); GetDataStorage()->Add(node); { ItkUcharImgType::Pointer numDirImage = filter->GetNumDirectionsImage(); 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_ImageNodes.at(0)->GetName().c_str()); name += "_NumDirections"; node2->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node2); } typedef FilterType::DirectionImageContainerType DirectionImageContainerType; DirectionImageContainerType::Pointer container = filter->GetDirectionImageContainer(); for (int i=0; iSize(); i++) { ItkDirectionImage3DType::Pointer itkImg = container->GetElement(i); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk( itkImg.GetPointer() ); img->SetVolume( itkImg->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_ImageNodes.at(0)->GetName().c_str()); name += "_Direction"; name += QString::number(i+1); node->SetName(name.toStdString().c_str()); node->SetVisibility(false); GetDataStorage()->Add(node); } break; } } } void QmitkOdfMaximaExtractionView::GenerateImage() { if (!m_ImageNodes.empty()) GenerateDataFromDwi(); } void QmitkOdfMaximaExtractionView::StartTensor() { if (m_TensorImageNodes.empty()) return; typedef itk::DiffusionTensorPrincipalDirectionImageFilter< float, float > MaximaExtractionFilterType; MaximaExtractionFilterType::Pointer filter = MaximaExtractionFilterType::New(); mitk::BaseGeometry::Pointer geometry; try{ TensorImage::Pointer img = dynamic_cast(m_TensorImageNodes.at(0)->GetData()); 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( NULL, "Wrong pixel type", "Could not perform Tensor Principal Direction Extraction due to Image has wrong pixel type.", QMessageBox::Ok ); return; //throw e; } if (!m_BinaryImageNodes.empty()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); Image::Pointer mitkMaskImg = dynamic_cast(m_BinaryImageNodes.at(0)->GetData()); CastToItkImage(mitkMaskImg, itkMaskImage); filter->SetMaskImage(itkMaskImage); } if (m_Controls->m_NormalizationBox->currentIndex()==0) filter->SetNormalizeVectors(false); filter->Update(); if (m_Controls->m_OutputDirectionImagesBox->isChecked()) { MaximaExtractionFilterType::OutputImageType::Pointer itkImg = filter->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk( itkImg.GetPointer() ); img->SetVolume( itkImg->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_TensorImageNodes.at(0)->GetName().c_str()); name += "_PrincipalDirection"; node->SetName(name.toStdString().c_str()); node->SetVisibility(false); GetDataStorage()->Add(node); } if (m_Controls->m_OutputNumDirectionsBox->isChecked()) { ItkUcharImgType::Pointer numDirImage = filter->GetNumDirectionsImage(); 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_TensorImageNodes.at(0)->GetName().c_str()); name += "_NumDirections"; node2->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node2); } 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_TensorImageNodes.at(0)->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); } } template void QmitkOdfMaximaExtractionView::StartMaximaExtraction() { 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{ Image::Pointer img = dynamic_cast(m_ImageNodes.at(0)->GetData()); typedef ImageToItk< typename MaximaExtractionFilterType::CoefficientImageType > CasterType; typename CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); filter->SetInput(caster->GetOutput()); geometry = img->GetGeometry(); } catch(itk::ExceptionObject &e) { MITK_INFO << "wrong image type: " << e.what(); QMessageBox::warning( NULL, "Wrong pixel type", "Could not perform Finite Differences Extraction due to Image has wrong pixel type.", QMessageBox::Ok ); return; //throw; } 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_BinaryImageNodes.empty()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); Image::Pointer mitkMaskImg = dynamic_cast(m_BinaryImageNodes.at(0)->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()) { typedef typename MaximaExtractionFilterType::ItkDirectionImageContainer ItkDirectionImageContainer; typename ItkDirectionImageContainer::Pointer container = filter->GetDirectionImageContainer(); for (int i=0; iSize(); i++) { typename MaximaExtractionFilterType::ItkDirectionImage::Pointer itkImg = container->GetElement(i); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk( itkImg.GetPointer() ); img->SetVolume( itkImg->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_ImageNodes.at(0)->GetName().c_str()); name += "_Direction"; name += QString::number(i+1); node->SetName(name.toStdString().c_str()); node->SetVisibility(false); GetDataStorage()->Add(node); } } if (m_Controls->m_OutputNumDirectionsBox->isChecked()) { ItkUcharImgType::Pointer numDirImage = filter->GetNumDirectionsImage(); 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_ImageNodes.at(0)->GetName().c_str()); name += "_NumDirections"; node2->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node2); } 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_ImageNodes.at(0)->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); } } void QmitkOdfMaximaExtractionView::StartFiniteDiff() { if (m_ImageNodes.empty()) return; switch (m_Controls->m_ShOrderBox->currentIndex()) { case 0: StartMaximaExtraction<2>(); break; case 1: StartMaximaExtraction<4>(); break; case 2: StartMaximaExtraction<6>(); break; case 3: StartMaximaExtraction<8>(); break; case 4: StartMaximaExtraction<10>(); break; case 5: StartMaximaExtraction<12>(); break; } } void QmitkOdfMaximaExtractionView::GenerateDataFromDwi() { typedef itk::OdfMaximaExtractionFilter< float > MaximaExtractionFilterType; MaximaExtractionFilterType::Pointer filter = MaximaExtractionFilterType::New(); mitk::BaseGeometry::Pointer geometry; if (!m_ImageNodes.empty()) { try{ Image::Pointer img = dynamic_cast(m_ImageNodes.at(0)->GetData()); typedef ImageToItk< MaximaExtractionFilterType::CoefficientImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); filter->SetShCoeffImage(caster->GetOutput()); geometry = img->GetGeometry(); } catch(itk::ExceptionObject &e) { MITK_INFO << "wrong image type: " << e.what(); return; } } else return; filter->SetMaxNumPeaks(m_Controls->m_MaxNumPeaksBox->value()); filter->SetPeakThreshold(m_Controls->m_PeakThresholdBox->value()); if (!m_BinaryImageNodes.empty()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); Image::Pointer mitkMaskImg = dynamic_cast(m_BinaryImageNodes.at(0)->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->GenerateData(); ItkUcharImgType::Pointer numDirImage = filter->GetNumDirectionsImage(); if (m_Controls->m_OutputDirectionImagesBox->isChecked()) { typedef MaximaExtractionFilterType::ItkDirectionImageContainer ItkDirectionImageContainer; ItkDirectionImageContainer::Pointer container = filter->GetDirectionImageContainer(); for (int i=0; iSize(); i++) { MaximaExtractionFilterType::ItkDirectionImage::Pointer itkImg = container->GetElement(i); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk( itkImg.GetPointer() ); img->SetVolume( itkImg->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(img); QString name(m_ImageNodes.at(0)->GetName().c_str()); name += "_Direction"; name += QString::number(i+1); node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node); } } if (m_Controls->m_OutputNumDirectionsBox->isChecked()) { mitk::Image::Pointer image2 = mitk::Image::New(); image2->InitializeByItk( numDirImage.GetPointer() ); image2->SetVolume( numDirImage->GetBufferPointer() ); DataNode::Pointer node = DataNode::New(); node->SetData(image2); QString name(m_ImageNodes.at(0)->GetName().c_str()); name += "_NumDirections"; node->SetName(name.toStdString().c_str()); GetDataStorage()->Add(node); } 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_ImageNodes.at(0)->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); } } void QmitkOdfMaximaExtractionView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkOdfMaximaExtractionView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkOdfMaximaExtractionView::OnSelectionChanged( std::vector nodes ) { m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_DwiFibLabel->setText("mandatory"); m_Controls->m_MaskLabel->setText("optional"); m_BinaryImageNodes.clear(); m_ImageNodes.clear(); m_TensorImageNodes.clear(); // iterate all selected objects, adjust warning visibility for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_TensorImageNodes.push_back(node); } else if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { bool isBinary = false; node->GetPropertyValue("binary", isBinary); if (isBinary) m_BinaryImageNodes.push_back(node); else m_ImageNodes.push_back(node); } } UpdateGui(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionView.h index 859d00b90f..f0d97ce7a1 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionView.h @@ -1,91 +1,92 @@ /*=================================================================== 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 "ui_QmitkOdfMaximaExtractionViewControls.h" #include #include #include /*! \brief View providing several methods to extract peaks from the spherical harmonic representation of ODFs or from tensors \sa QmitkFunctionality \ingroup Functionalities */ // Forward Qt class declarations class QmitkOdfMaximaExtractionView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; QmitkOdfMaximaExtractionView(); virtual ~QmitkOdfMaximaExtractionView(); virtual void CreateQtPartControl(QWidget *parent) override; virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) override; virtual void StdMultiWidgetNotAvailable() override; typedef itk::Image ItkUcharImgType; typedef itk::Image< itk::DiffusionTensor3D< float >, 3 > ItkTensorImage; typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType; ///< contains a 3D vector in each voxel protected slots: void ConvertShCoeffs(); ///< convert spherical harmonic coefficients to the according mitk datatype void ConvertPeaks(); ///< convert peak files from other toolkits to the according mitk datatype void GenerateImage(); ///< semicontinuous ODF maxima extraction void StartFiniteDiff(); ///< ODF maxima extraction using finite differences on the densely sampled sphere void StartTensor(); ///< extract principal eigenvectors from tensor image + protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ) override; Ui::QmitkOdfMaximaExtractionViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; std::vector< mitk::DataNode::Pointer > m_BinaryImageNodes; ///< mask images std::vector< mitk::DataNode::Pointer > m_ImageNodes; std::vector< mitk::DataNode::Pointer > m_TensorImageNodes; void UpdateGui(); ///< update button activity etc. dpending on current datamanager selection void GenerateDataFromDwi(); ///< semicontinuous ODF maxima extraction template void TemplatedConvertShCoeffs(mitk::Image* mitkImg); template void StartMaximaExtraction(); ///< ODF maxima extraction using finite differences on the densely sampled sphere private: }; diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionViewControls.ui index 16461ab945..d59a56a856 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkOdfMaximaExtractionViewControls.ui @@ -1,500 +1,539 @@ QmitkOdfMaximaExtractionViewControls 0 0 395 - 761 + 807 Form false Extract ODF peaks using a semicontinuous method (Aganj et al. 2010). EXPERIMENTAL! Start Analytical Extraction (only SH order 4) Please Select Input Data Select a tensor image or a SH coefficient image (generate using Q-Ball reconstruction view). ShCoeff/DTI: Mask Image: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> true <html><head/><body><p><span style=" color:#969696;">optional</span></p></body></html> 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 false QFrame::NoFrame QFrame::Raised 0 0 0 0 6 SH Order: Absolute threshold: false Absolute peak threshold (only used for the finite differences method). The value is additionally scaled by 1/GFA. 3 0.000000000000000 1.000000000000000 0.001000000000000 0.010000000000000 Max. Peaks: false Peak threshold relative to the largest peak per voxel. 0.000000000000000 1.000000000000000 0.050000000000000 0.400000000000000 false Maximum number of peaks to extract. 1 1000 3 Relative threshold: false 1 2 4 6 8 10 12 Clustering angle: Cluster close directions. Define "close" here. 90 30 Angular threshold: Discard smaller peaks in the defined angle around the maximum peaks. 0 90 0 Qt::Vertical 20 259 Import From Other Tools + + + Only for peak import! + + + Only for peak import! + + + invert y coordinate + + + + false Generate Q-Ball image and MITK compatible SH coefficient from other toolkits. Import SH - Coefficients Define SH coefficient convention (depends on toolkit) 1 FSL MRtrix - + false Generate vector field and direction images from the FSL qboot peak extraction output. Import Peak Image + + + + Only for peak import! + + + Only for peak import! + + + invert x coordinate + + + + + + + Only for peak import! + + + Only for peak import! + + + invert z coordinate + + + false Extract ODF peaks using finite differences on the densely sampled ODF surface. Start Finite Differences Extraction false Extract principal eigenvectors of input tensors. Start Tensor Principal Direction Extraction 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. #Directions per Voxel false Output one image per extracted direction containing the direction vecors as pixel values. Direction Images false diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingView.cpp index 6a199e95d4..338a41872f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingView.cpp @@ -1,2384 +1,2345 @@ /*=================================================================== 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. ===================================================================*/ //#define MBILOG_ENABLE_DEBUG #include "QmitkPreprocessingView.h" #include "mitkDiffusionImagingConfigure.h" // qt includes #include // itk includes #include "itkTimeProbe.h" #include "itkB0ImageExtractionImageFilter.h" #include "itkB0ImageExtractionToSeparateImageFilter.h" #include "itkBrainMaskExtractionImageFilter.h" #include "itkCastImageFilter.h" #include "itkVectorContainer.h" #include #include #include #include // Multishell includes #include // Multishell Functors #include #include #include #include // mitk includes #include "QmitkDataStorageComboBox.h" #include "QmitkStdMultiWidget.h" #include "mitkProgressBar.h" #include "mitkStatusBar.h" #include "mitkNodePredicateDataType.h" #include "mitkProperties.h" #include "mitkVtkResliceInterpolationProperty.h" #include "mitkLookupTable.h" #include "mitkLookupTableProperty.h" #include "mitkTransferFunction.h" #include "mitkTransferFunctionProperty.h" #include "mitkDataNodeObject.h" #include "mitkOdfNormalizationMethodProperty.h" #include "mitkOdfScaleByProperty.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const std::string QmitkPreprocessingView::VIEW_ID = "org.mitk.views.preprocessing"; #define DI_INFO MITK_INFO("DiffusionImaging") typedef float TTensorPixelType; QmitkPreprocessingView::QmitkPreprocessingView() : QmitkFunctionality(), m_Controls(NULL), m_MultiWidget(NULL) { } QmitkPreprocessingView::~QmitkPreprocessingView() { } void QmitkPreprocessingView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkPreprocessingViewControls; m_Controls->setupUi(parent); this->CreateConnections(); m_Controls->m_MeasurementFrameTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); m_Controls->m_MeasurementFrameTable->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); m_Controls->m_DirectionMatrixTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); m_Controls->m_DirectionMatrixTable->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch); } } void QmitkPreprocessingView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkPreprocessingView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkPreprocessingView::CreateConnections() { if ( m_Controls ) { m_Controls->m_NormalizationMaskBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_SelctedImageComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MergeDwiBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isMitkImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isQbi = mitk::NodePredicateDataType::New("QBallImage"); mitk::NodePredicateOr::Pointer isDiffusionImage = mitk::NodePredicateOr::New(isDwi, isDti); isDiffusionImage = mitk::NodePredicateOr::New(isDiffusionImage, isQbi); mitk::NodePredicateNot::Pointer noDiffusionImage = mitk::NodePredicateNot::New(isDiffusionImage); mitk::NodePredicateAnd::Pointer finalPredicate = mitk::NodePredicateAnd::New(isMitkImage, noDiffusionImage); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); finalPredicate = mitk::NodePredicateAnd::New(finalPredicate, isBinaryPredicate); m_Controls->m_NormalizationMaskBox->SetPredicate(finalPredicate); m_Controls->m_SelctedImageComboBox->SetPredicate(isMitkImage); m_Controls->m_MergeDwiBox->SetPredicate(isMitkImage); m_Controls->m_ExtractBrainMask->setVisible(false); m_Controls->m_BrainMaskIterationsBox->setVisible(false); m_Controls->m_ResampleIntFrame->setVisible(false); connect( (QObject*)(m_Controls->m_ButtonAverageGradients), SIGNAL(clicked()), this, SLOT(AverageGradients()) ); connect( (QObject*)(m_Controls->m_ButtonExtractB0), SIGNAL(clicked()), this, SLOT(ExtractB0()) ); connect( (QObject*)(m_Controls->m_ModifyMeasurementFrame), SIGNAL(clicked()), this, SLOT(DoApplyMesurementFrame()) ); connect( (QObject*)(m_Controls->m_ReduceGradientsButton), SIGNAL(clicked()), this, SLOT(DoReduceGradientDirections()) ); connect( (QObject*)(m_Controls->m_ShowGradientsButton), SIGNAL(clicked()), this, SLOT(DoShowGradientDirections()) ); connect( (QObject*)(m_Controls->m_MirrorGradientToHalfSphereButton), SIGNAL(clicked()), this, SLOT(DoHalfSphereGradientDirections()) ); connect( (QObject*)(m_Controls->m_MergeDwisButton), SIGNAL(clicked()), this, SLOT(MergeDwis()) ); connect( (QObject*)(m_Controls->m_ProjectSignalButton), SIGNAL(clicked()), this, SLOT(DoProjectSignal()) ); connect( (QObject*)(m_Controls->m_B_ValueMap_Rounder_SpinBox), SIGNAL(valueChanged(int)), this, SLOT(UpdateDwiBValueMapRounder(int))); connect( (QObject*)(m_Controls->m_CreateLengthCorrectedDwi), SIGNAL(clicked()), this, SLOT(DoLengthCorrection()) ); connect( (QObject*)(m_Controls->m_CalcAdcButton), SIGNAL(clicked()), this, SLOT(DoAdcCalculation()) ); connect( (QObject*)(m_Controls->m_NormalizeImageValuesButton), SIGNAL(clicked()), this, SLOT(DoDwiNormalization()) ); connect( (QObject*)(m_Controls->m_ModifyDirection), SIGNAL(clicked()), this, SLOT(DoApplyDirectionMatrix()) ); connect( (QObject*)(m_Controls->m_ModifySpacingButton), SIGNAL(clicked()), this, SLOT(DoApplySpacing()) ); connect( (QObject*)(m_Controls->m_ModifyOriginButton), SIGNAL(clicked()), this, SLOT(DoApplyOrigin()) ); connect( (QObject*)(m_Controls->m_ResampleImageButton), SIGNAL(clicked()), this, SLOT(DoResampleImage()) ); connect( (QObject*)(m_Controls->m_ResampleTypeBox), SIGNAL(currentIndexChanged(int)), this, SLOT(DoUpdateInterpolationGui(int)) ); connect( (QObject*)(m_Controls->m_CropImageButton), SIGNAL(clicked()), this, SLOT(DoCropImage()) ); connect( (QObject*)(m_Controls->m_RemoveGradientButton), SIGNAL(clicked()), this, SLOT(DoRemoveGradient()) ); connect( (QObject*)(m_Controls->m_ExtractGradientButton), SIGNAL(clicked()), this, SLOT(DoExtractGradient()) ); connect( (QObject*)(m_Controls->m_FlipAxis), SIGNAL(clicked()), this, SLOT(DoFlipAxis()) ); + connect( (QObject*)(m_Controls->m_FlipGradientsButton), SIGNAL(clicked()), this, SLOT(DoFlipGradientDirections()) ); connect( (QObject*)(m_Controls->m_SelctedImageComboBox), SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnImageSelectionChanged()) ); m_Controls->m_NormalizationMaskBox->SetZeroEntryText("--"); } } void QmitkPreprocessingView::DoFlipAxis() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(node) ); if (isDiffusionImage) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); itk::FixedArray flipAxes; flipAxes[0] = m_Controls->m_FlipX->isChecked(); flipAxes[1] = m_Controls->m_FlipY->isChecked(); flipAxes[2] = m_Controls->m_FlipZ->isChecked(); itk::FlipImageFilter< ItkDwiType >::Pointer flipper = itk::FlipImageFilter< ItkDwiType >::New(); flipper->SetInput(itkVectorImagePointer); flipper->SetFlipAxes(flipAxes); flipper->Update(); mitk::GradientDirectionsProperty::GradientDirectionsContainerType::Pointer oldGradients = static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); mitk::GradientDirectionsProperty::GradientDirectionsContainerType::Pointer newGradients = mitk::GradientDirectionsProperty::GradientDirectionsContainerType::New(); for (unsigned int i=0; iSize(); i++) { mitk::GradientDirectionsProperty::GradientDirectionType g = oldGradients->GetElement(i); mitk::GradientDirectionsProperty::GradientDirectionType newG = g; if (flipAxes[0]) { newG[0] *= -1; } if (flipAxes[1]) { newG[1] *= -1; } if (flipAxes[2]) { newG[2] *= -1; } newGradients->InsertElement(i, newG); } mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( flipper->GetOutput() ); newImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( newGradients ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer() ) ->GetMeasurementFrame() ) ); mitk::DiffusionPropertyHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); newImage->GetGeometry()->SetOrigin(image->GetGeometry()->GetOrigin()); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_flipped").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if( image->GetPixelType().GetNumberOfComponents() == 1 ) { AccessFixedDimensionByItk(image, TemplatedFlipAxis,3); } else { QMessageBox::warning(NULL,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedFlipAxis(itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } itk::FixedArray flipAxes; flipAxes[0] = m_Controls->m_FlipX->isChecked(); flipAxes[1] = m_Controls->m_FlipY->isChecked(); flipAxes[2] = m_Controls->m_FlipZ->isChecked(); typename itk::FlipImageFilter< itk::Image >::Pointer flipper = itk::FlipImageFilter< itk::Image >::New(); flipper->SetInput(itkImage); flipper->SetFlipAxes(flipAxes); flipper->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( flipper->GetOutput() ); newImage->GetGeometry()->SetOrigin(image->GetGeometry()->GetOrigin()); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_flipped").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoRemoveGradient() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } std::vector< unsigned int > channelsToRemove; channelsToRemove.push_back(m_Controls->m_RemoveGradientBox->value()); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); itk::RemoveDwiChannelFilter< short >::Pointer filter = itk::RemoveDwiChannelFilter< short >::New(); filter->SetInput(itkVectorImagePointer); filter->SetChannelIndices(channelsToRemove); filter->SetDirections( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( filter->GetOutput() ); newImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( filter->GetNewDirections() ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer() ) ->GetMeasurementFrame() ) ); mitk::DiffusionPropertyHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_removedgradients").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoExtractGradient() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); unsigned int channel = m_Controls->m_ExtractGradientBox->value(); itk::ExtractDwiChannelFilter< short >::Pointer filter = itk::ExtractDwiChannelFilter< short >::New(); filter->SetInput( itkVectorImagePointer); filter->SetChannelIndex(channel); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( filter->GetOutput() ); newImage->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName( (name+"_direction-"+QString::number(channel)).toStdString().c_str() ); GetDefaultDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } void QmitkPreprocessingView::DoCropImage() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( isDiffusionImage ) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); ItkDwiType::SizeType lower; ItkDwiType::SizeType upper; lower[0] = m_Controls->m_XstartBox->value(); lower[1] = m_Controls->m_YstartBox->value(); lower[2] = m_Controls->m_ZstartBox->value(); upper[0] = m_Controls->m_XendBox->value(); upper[1] = m_Controls->m_YendBox->value(); upper[2] = m_Controls->m_ZendBox->value(); itk::CropImageFilter< ItkDwiType, ItkDwiType >::Pointer cropper = itk::CropImageFilter< ItkDwiType, ItkDwiType >::New(); cropper->SetLowerBoundaryCropSize(lower); cropper->SetUpperBoundaryCropSize(upper); cropper->SetInput( itkVectorImagePointer ); cropper->Update(); ItkDwiType::Pointer itkOutImage = cropper->GetOutput(); + ItkDwiType::DirectionType dir = itkOutImage->GetDirection(); itk::Point origin = itkOutImage->GetOrigin(); - origin[0] += lower[0]*itkOutImage->GetSpacing()[0]; - origin[1] += lower[1]*itkOutImage->GetSpacing()[1]; - origin[2] += lower[2]*itkOutImage->GetSpacing()[2]; + origin[0] += lower[0]*itkOutImage->GetSpacing()[0]*dir[0][0]/std::fabs(dir[0][0]); + origin[1] += lower[1]*itkOutImage->GetSpacing()[1]*dir[1][1]/std::fabs(dir[1][1]); + origin[2] += lower[2]*itkOutImage->GetSpacing()[2]*dir[2][2]/std::fabs(dir[2][2]); itkOutImage->SetOrigin(origin); mitk::Image::Pointer newimage = mitk::GrabItkImageMemory( itkOutImage ); newimage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ) ); newimage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ) ); newimage->SetProperty( mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer() ) ->GetMeasurementFrame() ) ); mitk::DiffusionPropertyHelper propertyHelper( newimage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newimage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_cropped").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if( image->GetPixelType().GetNumberOfComponents() ) { AccessFixedDimensionByItk(image, TemplatedCropImage,3); } else { QMessageBox::warning(NULL,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedCropImage( itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } ItkDwiType::SizeType lower; ItkDwiType::SizeType upper; lower[0] = m_Controls->m_XstartBox->value(); lower[1] = m_Controls->m_YstartBox->value(); lower[2] = m_Controls->m_ZstartBox->value(); upper[0] = m_Controls->m_XendBox->value(); upper[1] = m_Controls->m_YendBox->value(); upper[2] = m_Controls->m_ZendBox->value(); typedef itk::Image ImageType; typename itk::CropImageFilter< ImageType, ImageType >::Pointer cropper = itk::CropImageFilter< ImageType, ImageType >::New(); cropper->SetLowerBoundaryCropSize(lower); cropper->SetUpperBoundaryCropSize(upper); cropper->SetInput(itkImage); cropper->Update(); typename ImageType::Pointer itkOutImage = cropper->GetOutput(); + typename ImageType::DirectionType dir = itkOutImage->GetDirection(); itk::Point origin = itkOutImage->GetOrigin(); - origin[0] += lower[0]*itkOutImage->GetSpacing()[0]; - origin[1] += lower[1]*itkOutImage->GetSpacing()[1]; - origin[2] += lower[2]*itkOutImage->GetSpacing()[2]; + origin[0] += lower[0]*itkOutImage->GetSpacing()[0]*dir[0][0]/std::fabs(dir[0][0]); + origin[1] += lower[1]*itkOutImage->GetSpacing()[1]*dir[1][1]/std::fabs(dir[1][1]); + origin[2] += lower[2]*itkOutImage->GetSpacing()[2]*dir[2][2]/std::fabs(dir[2][2]); + itkOutImage->SetOrigin(origin); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( itkOutImage.GetPointer() ); image->SetVolume( itkOutImage->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( image ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_cropped").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoApplySpacing() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( isDiffusionImage ) { mitk::Vector3D spacing; spacing[0] = m_Controls->m_HeaderSpacingX->value(); spacing[1] = m_Controls->m_HeaderSpacingY->value(); spacing[2] = m_Controls->m_HeaderSpacingZ->value(); mitk::Image::Pointer newImage = image->Clone(); newImage->GetGeometry()->SetSpacing( spacing ); mitk::DiffusionPropertyHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_newspacing").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if( image->GetPixelType().GetNumberOfComponents() ) { AccessFixedDimensionByItk(image, TemplatedSetImageSpacing,3); } else { QMessageBox::warning(NULL,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedSetImageSpacing( itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) return; mitk::Vector3D spacing; spacing[0] = m_Controls->m_HeaderSpacingX->value(); spacing[1] = m_Controls->m_HeaderSpacingY->value(); spacing[2] = m_Controls->m_HeaderSpacingZ->value(); typedef itk::ImageDuplicator< itk::Image > DuplicateFilterType; typename DuplicateFilterType::Pointer duplicator = DuplicateFilterType::New(); duplicator->SetInputImage( itkImage ); duplicator->Update(); typename itk::Image::Pointer newImage = duplicator->GetOutput(); newImage->SetSpacing(spacing); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( newImage.GetPointer() ); image->SetVolume( newImage->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( image ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_newspacing").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoApplyOrigin() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image)); if ( isDiffusionImage ) { mitk::Vector3D origin; origin[0] = m_Controls->m_HeaderOriginX->value(); origin[1] = m_Controls->m_HeaderOriginY->value(); origin[2] = m_Controls->m_HeaderOriginZ->value(); mitk::Image::Pointer newImage = image->Clone(); newImage->GetGeometry()->SetOrigin( origin ); mitk::DiffusionPropertyHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_neworigin").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if( image->GetPixelType().GetNumberOfComponents() ) { AccessFixedDimensionByItk(image, TemplatedSetImageOrigin,3); } else { QMessageBox::warning(NULL,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedSetImageOrigin( itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Vector3D origin; origin[0] = m_Controls->m_HeaderOriginX->value(); origin[1] = m_Controls->m_HeaderOriginY->value(); origin[2] = m_Controls->m_HeaderOriginZ->value(); typedef itk::ImageDuplicator< itk::Image > DuplicateFilterType; typename DuplicateFilterType::Pointer duplicator = DuplicateFilterType::New(); duplicator->SetInputImage( itkImage ); duplicator->Update(); typename itk::Image::Pointer newImage = duplicator->GetOutput(); newImage->SetOrigin(origin); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( newImage.GetPointer() ); image->SetVolume( newImage->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( image ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_neworigin").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoUpdateInterpolationGui(int i) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } switch (i) { case 0: { m_Controls->m_ResampleIntFrame->setVisible(false); m_Controls->m_ResampleDoubleFrame->setVisible(true); break; } case 1: { m_Controls->m_ResampleIntFrame->setVisible(false); m_Controls->m_ResampleDoubleFrame->setVisible(true); mitk::BaseGeometry* geom = image->GetGeometry(); m_Controls->m_ResampleDoubleX->setValue(geom->GetSpacing()[0]); m_Controls->m_ResampleDoubleY->setValue(geom->GetSpacing()[1]); m_Controls->m_ResampleDoubleZ->setValue(geom->GetSpacing()[2]); break; } case 2: { m_Controls->m_ResampleIntFrame->setVisible(true); m_Controls->m_ResampleDoubleFrame->setVisible(false); mitk::BaseGeometry* geom = image->GetGeometry(); m_Controls->m_ResampleIntX->setValue(geom->GetExtent(0)); m_Controls->m_ResampleIntY->setValue(geom->GetExtent(1)); m_Controls->m_ResampleIntZ->setValue(geom->GetExtent(2)); break; } default: { m_Controls->m_ResampleIntFrame->setVisible(false); m_Controls->m_ResampleDoubleFrame->setVisible(true); } } } void QmitkPreprocessingView::DoExtractBrainMask() { } void QmitkPreprocessingView::DoResampleImage() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( isDiffusionImage ) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); typedef itk::ResampleDwiImageFilter< short > ResampleFilter; ResampleFilter::Pointer resampler = ResampleFilter::New(); resampler->SetInput( itkVectorImagePointer ); switch (m_Controls->m_ResampleTypeBox->currentIndex()) { case 0: { itk::Vector< double, 3 > samplingFactor; samplingFactor[0] = m_Controls->m_ResampleDoubleX->value(); samplingFactor[1] = m_Controls->m_ResampleDoubleY->value(); samplingFactor[2] = m_Controls->m_ResampleDoubleZ->value(); resampler->SetSamplingFactor(samplingFactor); break; } case 1: { itk::Vector< double, 3 > newSpacing; newSpacing[0] = m_Controls->m_ResampleDoubleX->value(); newSpacing[1] = m_Controls->m_ResampleDoubleY->value(); newSpacing[2] = m_Controls->m_ResampleDoubleZ->value(); resampler->SetNewSpacing(newSpacing); break; } case 2: { itk::ImageRegion<3> newRegion; newRegion.SetSize(0, m_Controls->m_ResampleIntX->value()); newRegion.SetSize(1, m_Controls->m_ResampleIntY->value()); newRegion.SetSize(2, m_Controls->m_ResampleIntZ->value()); resampler->SetNewImageSize(newRegion); break; } default: { MITK_WARN << "Unknown resampling parameters!"; return; } } QString outAdd; switch (m_Controls->m_InterpolatorBox->currentIndex()) { case 0: { resampler->SetInterpolation(ResampleFilter::Interpolate_NearestNeighbour); outAdd = "NearestNeighbour"; break; } case 1: { resampler->SetInterpolation(ResampleFilter::Interpolate_Linear); outAdd = "Linear"; break; } case 2: { resampler->SetInterpolation(ResampleFilter::Interpolate_BSpline); outAdd = "BSpline"; break; } case 3: { resampler->SetInterpolation(ResampleFilter::Interpolate_WindowedSinc); outAdd = "WindowedSinc"; break; } default: { resampler->SetInterpolation(ResampleFilter::Interpolate_NearestNeighbour); outAdd = "NearestNeighbour"; } } resampler->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( resampler->GetOutput() ); newImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer() ) ->GetMeasurementFrame() ) ); mitk::DiffusionPropertyHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_resampled_"+outAdd).toStdString().c_str()); imageNode->SetVisibility(false); GetDefaultDataStorage()->Add(imageNode, node); } else if( image->GetPixelType().GetNumberOfComponents() ) { AccessFixedDimensionByItk(image, TemplatedResampleImage,3); } else { QMessageBox::warning(NULL,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedResampleImage( itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } itk::Vector< double, 3 > newSpacing; itk::ImageRegion<3> newRegion; switch (m_Controls->m_ResampleTypeBox->currentIndex()) { case 0: { itk::Vector< double, 3 > sampling; sampling[0] = m_Controls->m_ResampleDoubleX->value(); sampling[1] = m_Controls->m_ResampleDoubleY->value(); sampling[2] = m_Controls->m_ResampleDoubleZ->value(); newSpacing = itkImage->GetSpacing(); newSpacing[0] /= sampling[0]; newSpacing[1] /= sampling[1]; newSpacing[2] /= sampling[2]; newRegion = itkImage->GetLargestPossibleRegion(); newRegion.SetSize(0, newRegion.GetSize(0)*sampling[0]); newRegion.SetSize(1, newRegion.GetSize(1)*sampling[1]); newRegion.SetSize(2, newRegion.GetSize(2)*sampling[2]); break; } case 1: { newSpacing[0] = m_Controls->m_ResampleDoubleX->value(); newSpacing[1] = m_Controls->m_ResampleDoubleY->value(); newSpacing[2] = m_Controls->m_ResampleDoubleZ->value(); itk::Vector< double, 3 > oldSpacing = itkImage->GetSpacing(); itk::Vector< double, 3 > sampling; sampling[0] = oldSpacing[0]/newSpacing[0]; sampling[1] = oldSpacing[1]/newSpacing[1]; sampling[2] = oldSpacing[2]/newSpacing[2]; newRegion = itkImage->GetLargestPossibleRegion(); newRegion.SetSize(0, newRegion.GetSize(0)*sampling[0]); newRegion.SetSize(1, newRegion.GetSize(1)*sampling[1]); newRegion.SetSize(2, newRegion.GetSize(2)*sampling[2]); break; } case 2: { newRegion.SetSize(0, m_Controls->m_ResampleIntX->value()); newRegion.SetSize(1, m_Controls->m_ResampleIntY->value()); newRegion.SetSize(2, m_Controls->m_ResampleIntZ->value()); itk::ImageRegion<3> oldRegion = itkImage->GetLargestPossibleRegion(); itk::Vector< double, 3 > sampling; sampling[0] = (double)newRegion.GetSize(0)/oldRegion.GetSize(0); sampling[1] = (double)newRegion.GetSize(1)/oldRegion.GetSize(1); sampling[2] = (double)newRegion.GetSize(2)/oldRegion.GetSize(2); newSpacing = itkImage->GetSpacing(); newSpacing[0] /= sampling[0]; newSpacing[1] /= sampling[1]; newSpacing[2] /= sampling[2]; break; } default: { MITK_WARN << "Unknown resampling parameters!"; return; } } itk::Point origin = itkImage->GetOrigin(); origin[0] -= itkImage->GetSpacing()[0]/2; origin[1] -= itkImage->GetSpacing()[1]/2; origin[2] -= itkImage->GetSpacing()[2]/2; origin[0] += newSpacing[0]/2; origin[1] += newSpacing[1]/2; origin[2] += newSpacing[2]/2; typedef itk::Image ImageType; typename ImageType::Pointer outImage = ImageType::New(); outImage->SetSpacing( newSpacing ); outImage->SetOrigin( origin ); outImage->SetDirection( itkImage->GetDirection() ); outImage->SetLargestPossibleRegion( newRegion ); outImage->SetBufferedRegion( newRegion ); outImage->SetRequestedRegion( newRegion ); outImage->Allocate(); typedef itk::ResampleImageFilter ResampleFilter; typename ResampleFilter::Pointer resampler = ResampleFilter::New(); resampler->SetInput(itkImage); resampler->SetOutputParametersFromImage(outImage); QString outAdd; switch (m_Controls->m_InterpolatorBox->currentIndex()) { case 0: { typename itk::NearestNeighborInterpolateImageFunction::Pointer interp = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(interp); outAdd = "NearestNeighbour"; break; } case 1: { typename itk::LinearInterpolateImageFunction::Pointer interp = itk::LinearInterpolateImageFunction::New(); resampler->SetInterpolator(interp); outAdd = "Linear"; break; } case 2: { typename itk::BSplineInterpolateImageFunction::Pointer interp = itk::BSplineInterpolateImageFunction::New(); resampler->SetInterpolator(interp); outAdd = "BSpline"; break; } case 3: { typename itk::WindowedSincInterpolateImageFunction::Pointer interp = itk::WindowedSincInterpolateImageFunction::New(); resampler->SetInterpolator(interp); outAdd = "WindowedSinc"; break; } default: { typename itk::NearestNeighborInterpolateImageFunction::Pointer interp = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(interp); outAdd = "NearestNeighbour"; } } resampler->Update(); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( resampler->GetOutput() ); image->SetVolume( resampler->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( image ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_resampled_"+outAdd).toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); } void QmitkPreprocessingView::DoApplyDirectionMatrix() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( isDiffusionImage ) { ItkDwiType::DirectionType newDirection; for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item(r,c); if (!item) return; newDirection[r][c] = item->text().toDouble(); } } ItkDwiType::Pointer itkDwi = ItkDwiType::New(); mitk::CastToItkImage(image, itkDwi); itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage(itkDwi); duplicator->Update(); itkDwi = duplicator->GetOutput(); vnl_matrix_fixed< double,3,3 > oldInverseDirection = itkDwi->GetDirection().GetInverse(); mitk::GradientDirectionsProperty::GradientDirectionsContainerType::Pointer oldGradients = static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); mitk::GradientDirectionsProperty::GradientDirectionsContainerType::Pointer newGradients = mitk::GradientDirectionsProperty::GradientDirectionsContainerType::New(); for (unsigned int i=0; iSize(); i++) { mitk::GradientDirectionsProperty::GradientDirectionType g = oldGradients->GetElement(i); double mag = g.magnitude(); g.normalize(); mitk::GradientDirectionsProperty::GradientDirectionType newG = oldInverseDirection*g; newG = newDirection.GetVnlMatrix()*newG; newG.normalize(); newGradients->InsertElement(i, newG*mag); } itkDwi->SetDirection(newDirection); mitk::Image::Pointer newDwi2 = mitk::GrabItkImageMemory( itkDwi.GetPointer() ); newDwi2->SetProperty( mitk::DiffusionPropertyHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( newGradients ) ); newDwi2->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ) ); newDwi2->SetProperty( mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer() ) ->GetMeasurementFrame() ) ); mitk::DiffusionPropertyHelper propertyHelper( newDwi2 ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi2 ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_newdirection").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance() ->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if( image->GetPixelType().GetNumberOfComponents() ) { AccessFixedDimensionByItk(image, TemplatedApplyRotation,3); } else { QMessageBox::warning(NULL,"Warning", QString("Operation not supported in multi-component images") ); } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedApplyRotation( itk::Image* itkImage) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } ItkDwiType::DirectionType newDirection; for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item(r,c); if (!item) return; newDirection[r][c] = item->text().toDouble(); } } typedef itk::Image ImageType; typename ImageType::Pointer newImage = ImageType::New(); newImage->SetSpacing( itkImage->GetSpacing() ); newImage->SetOrigin( itkImage->GetOrigin() ); newImage->SetDirection( newDirection ); newImage->SetLargestPossibleRegion( itkImage->GetLargestPossibleRegion() ); newImage->SetBufferedRegion( itkImage->GetLargestPossibleRegion() ); newImage->SetRequestedRegion( itkImage->GetLargestPossibleRegion() ); newImage->Allocate(); newImage->FillBuffer(0); itk::ImageRegionIterator< itk::Image > it(itkImage, itkImage->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { newImage->SetPixel(it.GetIndex(), it.Get()); ++it; } mitk::Image::Pointer newMitkImage = mitk::Image::New(); newMitkImage->InitializeByItk(newImage.GetPointer()); newMitkImage->SetVolume(newImage->GetBufferPointer()); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newMitkImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_newdirection").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); mitk::RenderingManager::GetInstance()->InitializeViews( imageNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkPreprocessingView::DoProjectSignal() { switch(m_Controls->m_ProjectionMethodBox->currentIndex()) { case 0: DoADCAverage(); break; case 1: DoAKCFit(); break; case 2: DoBiExpFit(); break; default: DoADCAverage(); } } void QmitkPreprocessingView::DoDwiNormalization() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) { return; } GradientDirectionContainerType::Pointer gradientContainer = static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); int b0Index = -1; for (unsigned int i=0; isize(); i++) { GradientDirectionType g = gradientContainer->GetElement(i); if (g.magnitude()<0.001) { b0Index = i; break; } } if (b0Index==-1) { return; } typedef itk::DwiNormilzationFilter FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetGradientDirections( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); + filter->SetNewMean(m_Controls->m_NewMean->value()); + filter->SetNewStdev(m_Controls->m_NewStdev->value()); UcharImageType::Pointer itkImage = NULL; if (m_Controls->m_NormalizationMaskBox->GetSelectedNode().IsNotNull()) { itkImage = UcharImageType::New(); if ( dynamic_cast(m_Controls->m_NormalizationMaskBox->GetSelectedNode()->GetData()) != nullptr ) { mitk::CastToItkImage( dynamic_cast(m_Controls->m_NormalizationMaskBox->GetSelectedNode()->GetData()), itkImage ); } filter->SetMaskImage(itkImage); } - - // determin normalization reference - switch(m_Controls->m_NormalizationReferenceBox->currentIndex()) - { - case 0: // normalize relative to mean white matter signal intensity - { - typedef itk::DiffusionTensor3DReconstructionImageFilter< short, short, double > TensorReconstructionImageFilterType; - TensorReconstructionImageFilterType::Pointer dtFilter = TensorReconstructionImageFilterType::New(); - dtFilter->SetGradientImage( gradientContainer, itkVectorImagePointer ); - dtFilter->SetBValue( static_cast - (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) - ->GetValue() ); - dtFilter->Update(); - itk::Image< itk::DiffusionTensor3D< double >, 3 >::Pointer tensorImage = dtFilter->GetOutput(); - itk::ImageRegionIterator< itk::Image< itk::DiffusionTensor3D< double >, 3 > > inIt(tensorImage, tensorImage->GetLargestPossibleRegion()); - double ref = 0; - unsigned int count = 0; - while ( !inIt.IsAtEnd() ) - { - if (itkImage.IsNotNull() && itkImage->GetPixel(inIt.GetIndex())<=0) - { - ++inIt; - continue; - } - - double FA = inIt.Get().GetFractionalAnisotropy(); - if (FA>0.4 && FA<0.99) - { - ref += itkVectorImagePointer->GetPixel(inIt.GetIndex())[b0Index]; - count++; - } - ++inIt; - } - if (count>0) - { - ref /= count; - filter->SetUseGlobalReference(true); - filter->SetReference(ref); - } - break; - } - case 1: // normalize relative to mean CSF signal intensity - { - itk::AdcImageFilter< short, double >::Pointer adcFilter = itk::AdcImageFilter< short, double >::New(); - adcFilter->SetInput( itkVectorImagePointer ); - adcFilter->SetGradientDirections( gradientContainer); - adcFilter->SetB_value( static_cast - (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) - ->GetValue() ); - adcFilter->Update(); - ItkDoubleImageType::Pointer adcImage = adcFilter->GetOutput(); - itk::ImageRegionIterator inIt(adcImage, adcImage->GetLargestPossibleRegion()); - double max = 0.0030; - double ref = 0; - unsigned int count = 0; - while ( !inIt.IsAtEnd() ) - { - if (itkImage.IsNotNull() && itkImage->GetPixel(inIt.GetIndex())<=0) - { - ++inIt; - continue; - } - if (inIt.Get()>max && inIt.Get()<0.004) - { - ref += itkVectorImagePointer->GetPixel(inIt.GetIndex())[b0Index]; - count++; - } - ++inIt; - } - if (count>0) - { - ref /= count; - filter->SetUseGlobalReference(true); - filter->SetReference(ref); - } - break; - } - case 2: - { - filter->SetUseGlobalReference(false); - } - } filter->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( filter->GetOutput() ); newImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer() ) ->GetMeasurementFrame() ) ); mitk::DiffusionPropertyHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_normalized").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); } void QmitkPreprocessingView::DoLengthCorrection() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) { return; } typedef itk::DwiGradientLengthCorrectionFilter FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetRoundingValue( m_Controls->m_B_ValueMap_Rounder_SpinBox->value()); filter->SetReferenceBValue( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); filter->SetReferenceGradientDirectionContainer( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New();//mitk::ImportItkImage( itkVectorImagePointer ); newImage->InitializeByItk( itkVectorImagePointer.GetPointer() ); newImage->SetImportVolume( itkVectorImagePointer->GetBufferPointer(), 0, 0, mitk::Image::CopyMemory); itkVectorImagePointer->GetPixelContainer()->ContainerManageMemoryOff(); newImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( filter->GetOutputGradientDirectionContainer() ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( filter->GetNewBValue() ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( static_cast(image->GetProperty(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer() )->GetMeasurementFrame() ) ); mitk::DiffusionPropertyHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_rounded").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); } void QmitkPreprocessingView::UpdateDwiBValueMapRounder(int i) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(node) ); if ( ! isDiffusionImage ) { return; } UpdateBValueTableWidget(i); } void QmitkPreprocessingView:: CallMultishellToSingleShellFilter( itk::DWIVoxelFunctor * functor, mitk::Image::Pointer image, QString imageName, mitk::DataNode* parent ) { typedef itk::RadialMultishellToSingleshellImageFilter FilterType; // filter input parameter const mitk::BValueMapProperty::BValueMap& originalShellMap = static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); ItkDwiType* vectorImage = itkVectorImagePointer.GetPointer(); const mitk::GradientDirectionsProperty::GradientDirectionsContainerType::Pointer gradientContainer = static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); const unsigned int& bValue = static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue(); mitk::DataNode::Pointer imageNode = 0; // filter call FilterType::Pointer filter = FilterType::New(); filter->SetInput(vectorImage); filter->SetOriginalGradientDirections(gradientContainer); filter->SetOriginalBValueMap(originalShellMap); filter->SetOriginalBValue(bValue); filter->SetFunctor(functor); filter->Update(); // create new DWI image mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( filter->GetOutput() ); outImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( filter->GetTargetGradientDirections() ) ); outImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( m_Controls->m_targetBValueSpinBox->value() ) ); outImage->SetProperty( mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer() ) ->GetMeasurementFrame() ) ); mitk::DiffusionPropertyHelper propertyHelper( outImage ); propertyHelper.InitializeImage(); imageNode = mitk::DataNode::New(); imageNode->SetData( outImage ); imageNode->SetName(imageName.toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, parent); // if(m_Controls->m_OutputRMSErrorImage->isChecked()){ // // create new Error image // FilterType::ErrorImageType::Pointer errImage = filter->GetErrorImage(); // mitk::Image::Pointer mitkErrImage = mitk::Image::New(); // mitkErrImage->InitializeByItk(errImage); // mitkErrImage->SetVolume(errImage->GetBufferPointer()); // imageNode = mitk::DataNode::New(); // imageNode->SetData( mitkErrImage ); // imageNode->SetName((imageName+"_Error").toStdString().c_str()); // GetDefaultDataStorage()->Add(imageNode); // } } void QmitkPreprocessingView::DoBiExpFit() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) { return; } itk::BiExpFitFunctor::Pointer functor = itk::BiExpFitFunctor::New(); QString name(node->GetName().c_str()); const mitk::BValueMapProperty::BValueMap& originalShellMap = static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); mitk::BValueMapProperty::BValueMap::const_iterator it = originalShellMap.begin(); ++it;/* skip b=0*/ unsigned int s = 0; /*shell index */ vnl_vector bValueList(originalShellMap.size()-1); while( it != originalShellMap.end() ) { bValueList.put(s++,(it++)->first); } const double targetBValue = m_Controls->m_targetBValueSpinBox->value(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); CallMultishellToSingleShellFilter(functor,image,name + "_BiExp", node); } void QmitkPreprocessingView::DoAKCFit() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) { return; } itk::KurtosisFitFunctor::Pointer functor = itk::KurtosisFitFunctor::New(); QString name(node->GetName().c_str()); const mitk::BValueMapProperty::BValueMap& originalShellMap = static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); mitk::BValueMapProperty::BValueMap::const_iterator it = originalShellMap.begin(); ++it;/* skip b=0*/ unsigned int s = 0; /*shell index */ vnl_vector bValueList(originalShellMap.size()-1); while(it != originalShellMap.end()) bValueList.put(s++,(it++)->first); const double targetBValue = m_Controls->m_targetBValueSpinBox->value(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); CallMultishellToSingleShellFilter(functor,image,name + "_AKC", node); } void QmitkPreprocessingView::DoADCFit() { // later } void QmitkPreprocessingView::DoADCAverage() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) return; itk::ADCAverageFunctor::Pointer functor = itk::ADCAverageFunctor::New(); QString name(node->GetName().c_str()); const mitk::BValueMapProperty::BValueMap &originalShellMap = static_cast(image->GetProperty(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() )->GetBValueMap(); mitk::BValueMapProperty::BValueMap::const_iterator it = originalShellMap.begin(); ++it;/* skip b=0*/ unsigned int s = 0; /*shell index */ vnl_vector bValueList(originalShellMap.size()-1); while(it != originalShellMap.end()) bValueList.put(s++,(it++)->first); const double targetBValue = m_Controls->m_targetBValueSpinBox->value(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); CallMultishellToSingleShellFilter(functor,image,name + "_ADC", node); } void QmitkPreprocessingView::DoAdcCalculation() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( ! isDiffusionImage ) { return; } typedef itk::AdcImageFilter< DiffusionPixelType, double > FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetGradientDirections( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->SetB_value( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( filter->GetOutput() ); newImage->SetVolume( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_ADC").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); } void QmitkPreprocessingView::CleanBValueTableWidget() { m_Controls->m_B_ValueMap_TableWidget->clear(); m_Controls->m_B_ValueMap_TableWidget->setRowCount(1); QStringList headerList; headerList << "b-Value" << "Number of gradients"; m_Controls->m_B_ValueMap_TableWidget->setHorizontalHeaderLabels(headerList); m_Controls->m_B_ValueMap_TableWidget->setItem(0,0,new QTableWidgetItem("-")); m_Controls->m_B_ValueMap_TableWidget->setItem(0,1,new QTableWidgetItem("-")); } void QmitkPreprocessingView::UpdateBValueTableWidget(int) { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { CleanBValueTableWidget(); return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage(false); isDiffusionImage = mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image); if ( ! isDiffusionImage ) { CleanBValueTableWidget(); } else { typedef mitk::BValueMapProperty::BValueMap BValueMap; typedef mitk::BValueMapProperty::BValueMap::iterator BValueMapIterator; BValueMapIterator it; BValueMap roundedBValueMap = static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); m_Controls->m_B_ValueMap_TableWidget->clear(); m_Controls->m_B_ValueMap_TableWidget->setRowCount(roundedBValueMap.size() ); QStringList headerList; headerList << "b-Value" << "Number of gradients"; m_Controls->m_B_ValueMap_TableWidget->setHorizontalHeaderLabels(headerList); int i = 0 ; for(it = roundedBValueMap.begin() ;it != roundedBValueMap.end(); it++) { m_Controls->m_B_ValueMap_TableWidget->setItem(i,0,new QTableWidgetItem(QString::number(it->first))); QTableWidgetItem* item = m_Controls->m_B_ValueMap_TableWidget->item(i,0); item->setFlags(item->flags() & ~Qt::ItemIsEditable); m_Controls->m_B_ValueMap_TableWidget->setItem(i,1,new QTableWidgetItem(QString::number(it->second.size()))); i++; } } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedUpdateGui( itk::Image* itkImage) { for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item(r,c); delete item; item = new QTableWidgetItem(); item->setTextAlignment(Qt::AlignCenter | Qt::AlignVCenter); item->setText(QString::number(itkImage->GetDirection()[r][c])); m_Controls->m_DirectionMatrixTable->setItem(r,c,item); } } } template < typename TPixel, unsigned int VImageDimension > void QmitkPreprocessingView::TemplatedUpdateGui( itk::VectorImage* itkImage) { for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item(r,c); delete item; item = new QTableWidgetItem(); item->setTextAlignment(Qt::AlignCenter | Qt::AlignVCenter); item->setText(QString::number(itkImage->GetDirection()[r][c])); m_Controls->m_DirectionMatrixTable->setItem(r,c,item); } } } //todo/mdh void QmitkPreprocessingView::OnSelectionChanged( std::vector nodes ) { (void) nodes; //maybe? this->OnImageSelectionChanged(); }//todo/mdh/why not? void QmitkPreprocessingView::OnImageSelectionChanged() { bool foundImageVolume = true; mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } bool foundDwiVolume( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( node ) ); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool multiComponentVolume = (image->GetPixelType().GetNumberOfComponents() > 1); bool threeDplusTVolume = (image->GetTimeSteps() > 1); // we do not support multi-component and 3D+t images in the widget, check early to avoid access exception bool foundSingleImageVolume = foundDwiVolume || (foundImageVolume && (!multiComponentVolume) && (!threeDplusTVolume) ); m_Controls->m_ButtonAverageGradients->setEnabled(foundDwiVolume); m_Controls->m_ButtonExtractB0->setEnabled(foundDwiVolume); m_Controls->m_CheckExtractAll->setEnabled(foundDwiVolume); m_Controls->m_ModifyMeasurementFrame->setEnabled(foundDwiVolume); m_Controls->m_MeasurementFrameTable->setEnabled(foundDwiVolume); m_Controls->m_ReduceGradientsButton->setEnabled(foundDwiVolume); m_Controls->m_ShowGradientsButton->setEnabled(foundDwiVolume); m_Controls->m_MirrorGradientToHalfSphereButton->setEnabled(foundDwiVolume); m_Controls->m_MergeDwisButton->setEnabled(foundDwiVolume); m_Controls->m_B_ValueMap_Rounder_SpinBox->setEnabled(foundDwiVolume); m_Controls->m_ProjectSignalButton->setEnabled(foundDwiVolume); m_Controls->m_CreateLengthCorrectedDwi->setEnabled(foundDwiVolume); m_Controls->m_CalcAdcButton->setEnabled(foundDwiVolume); m_Controls->m_targetBValueSpinBox->setEnabled(foundDwiVolume); m_Controls->m_NormalizeImageValuesButton->setEnabled(foundDwiVolume); m_Controls->m_DirectionMatrixTable->setEnabled(foundSingleImageVolume); m_Controls->m_ModifyDirection->setEnabled(foundSingleImageVolume); m_Controls->m_ExtractBrainMask->setEnabled(foundSingleImageVolume); m_Controls->m_ResampleImageButton->setEnabled(foundSingleImageVolume); m_Controls->m_ModifySpacingButton->setEnabled(foundSingleImageVolume); m_Controls->m_ModifyOriginButton->setEnabled(foundSingleImageVolume); m_Controls->m_CropImageButton->setEnabled(foundSingleImageVolume); m_Controls->m_RemoveGradientButton->setEnabled(foundDwiVolume); m_Controls->m_ExtractGradientButton->setEnabled(foundDwiVolume); m_Controls->m_FlipAxis->setEnabled(foundSingleImageVolume); + m_Controls->m_FlipGradientsButton->setEnabled(foundSingleImageVolume); // reset sampling frame to 1 and update all ealted components m_Controls->m_B_ValueMap_Rounder_SpinBox->setValue(1); UpdateBValueTableWidget(m_Controls->m_B_ValueMap_Rounder_SpinBox->value()); DoUpdateInterpolationGui(m_Controls->m_ResampleTypeBox->currentIndex()); if (foundDwiVolume) { m_Controls->m_InputData->setTitle("Input Data"); vnl_matrix_fixed< double, 3, 3 > mf = static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer() ) ->GetMeasurementFrame(); for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { // Measurement frame { QTableWidgetItem* item = m_Controls->m_MeasurementFrameTable->item( r, c ); delete item; item = new QTableWidgetItem(); item->setTextAlignment(Qt::AlignCenter | Qt::AlignVCenter); item->setText(QString::number(mf.get(r,c))); m_Controls->m_MeasurementFrameTable->setItem( r, c, item ); } // Direction matrix { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item( r, c ); delete item; item = new QTableWidgetItem(); item->setTextAlignment(Qt::AlignCenter | Qt::AlignVCenter); item->setText(QString::number(itkVectorImagePointer->GetDirection()[r][c])); m_Controls->m_DirectionMatrixTable->setItem( r, c, item ); } } } //calculate target bValue for MultishellToSingleShellfilter const mitk::BValueMapProperty::BValueMap & bValMap = static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); mitk::BValueMapProperty::BValueMap::const_iterator it = bValMap.begin(); unsigned int targetBVal = 0; while(it != bValMap.end()) { targetBVal += (it++)->first; } targetBVal /= (float)bValMap.size()-1; m_Controls->m_targetBValueSpinBox->setValue(targetBVal); m_Controls->m_HeaderSpacingX->setValue(image->GetGeometry()->GetSpacing()[0]); m_Controls->m_HeaderSpacingY->setValue(image->GetGeometry()->GetSpacing()[1]); m_Controls->m_HeaderSpacingZ->setValue(image->GetGeometry()->GetSpacing()[2]); m_Controls->m_HeaderOriginX->setValue(image->GetGeometry()->GetOrigin()[0]); m_Controls->m_HeaderOriginY->setValue(image->GetGeometry()->GetOrigin()[1]); m_Controls->m_HeaderOriginZ->setValue(image->GetGeometry()->GetOrigin()[2]); m_Controls->m_XstartBox->setMaximum(image->GetGeometry()->GetExtent(0)-1); m_Controls->m_YstartBox->setMaximum(image->GetGeometry()->GetExtent(1)-1); m_Controls->m_ZstartBox->setMaximum(image->GetGeometry()->GetExtent(2)-1); m_Controls->m_XendBox->setMaximum(image->GetGeometry()->GetExtent(0)-1); m_Controls->m_YendBox->setMaximum(image->GetGeometry()->GetExtent(1)-1); m_Controls->m_ZendBox->setMaximum(image->GetGeometry()->GetExtent(2)-1); m_Controls->m_RemoveGradientBox->setMaximum(static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer()->Size()-1); m_Controls->m_ExtractGradientBox->setMaximum(static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer()->Size()-1); } else if (foundSingleImageVolume) { for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_MeasurementFrameTable->item(r,c); delete item; item = new QTableWidgetItem(); m_Controls->m_MeasurementFrameTable->setItem(r,c,item); } } m_Controls->m_HeaderSpacingX->setValue(image->GetGeometry()->GetSpacing()[0]); m_Controls->m_HeaderSpacingY->setValue(image->GetGeometry()->GetSpacing()[1]); m_Controls->m_HeaderSpacingZ->setValue(image->GetGeometry()->GetSpacing()[2]); m_Controls->m_HeaderOriginX->setValue(image->GetGeometry()->GetOrigin()[0]); m_Controls->m_HeaderOriginY->setValue(image->GetGeometry()->GetOrigin()[1]); m_Controls->m_HeaderOriginZ->setValue(image->GetGeometry()->GetOrigin()[2]); m_Controls->m_XstartBox->setMaximum(image->GetGeometry()->GetExtent(0)-1); m_Controls->m_YstartBox->setMaximum(image->GetGeometry()->GetExtent(1)-1); m_Controls->m_ZstartBox->setMaximum(image->GetGeometry()->GetExtent(2)-1); m_Controls->m_XendBox->setMaximum(image->GetGeometry()->GetExtent(0)-1); m_Controls->m_YendBox->setMaximum(image->GetGeometry()->GetExtent(1)-1); m_Controls->m_ZendBox->setMaximum(image->GetGeometry()->GetExtent(2)-1); AccessFixedDimensionByItk(image, TemplatedUpdateGui,3); } else { for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { { QTableWidgetItem* item = m_Controls->m_MeasurementFrameTable->item( r, c ); delete item; item = new QTableWidgetItem(); m_Controls->m_MeasurementFrameTable->setItem( r, c, item ); } { QTableWidgetItem* item = m_Controls->m_DirectionMatrixTable->item( r, c ); delete item; item = new QTableWidgetItem(); m_Controls->m_DirectionMatrixTable->setItem( r, c, item ); } } } } } void QmitkPreprocessingView::Visible() { QmitkFunctionality::Visible(); OnImageSelectionChanged(); } void QmitkPreprocessingView::Activated() { QmitkFunctionality::Activated(); } void QmitkPreprocessingView::Deactivated() { QmitkFunctionality::Deactivated(); } + +void QmitkPreprocessingView::DoFlipGradientDirections() +{ + mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); + if (node.IsNull()) { return; } + + mitk::Image::Pointer image = dynamic_cast(node->GetData()); + if ( image == nullptr ) { return; } + + mitk::Image::Pointer newDwi = image->Clone(); + GradientDirectionContainerType::Pointer gradientContainer = + static_cast + ( newDwi->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) + ->GetGradientDirectionsContainer(); + + for (unsigned int j=0; jSize(); j++) + { + if (m_Controls->m_FlipGradBoxX->isChecked()) { gradientContainer->at(j)[0] = -gradientContainer->at(j)[0]; } + if (m_Controls->m_FlipGradBoxY->isChecked()) { gradientContainer->at(j)[1] = -gradientContainer->at(j)[1]; } + if (m_Controls->m_FlipGradBoxZ->isChecked()) { gradientContainer->at(j)[2] = -gradientContainer->at(j)[2]; } + } + + newDwi->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), + mitk::GradientDirectionsProperty::New( gradientContainer ) ); + + mitk::DiffusionPropertyHelper propertyHelper( newDwi ); + propertyHelper.InitializeImage(); + + mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); + imageNode->SetData( newDwi ); + + QString name = node->GetName().c_str(); + imageNode->SetName( (name+"_GradientFlip").toStdString().c_str() ); + GetDefaultDataStorage()->Add( imageNode, node ); +} + void QmitkPreprocessingView::DoHalfSphereGradientDirections() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } mitk::Image::Pointer newDwi = image->Clone(); GradientDirectionContainerType::Pointer gradientContainer = static_cast ( newDwi->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); for (unsigned int j=0; jSize(); j++) { if (gradientContainer->at(j)[0]<0) { gradientContainer->at(j) = -gradientContainer->at(j); } } newDwi->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( gradientContainer ) ); mitk::DiffusionPropertyHelper propertyHelper( newDwi ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi ); QString name = node->GetName().c_str(); imageNode->SetName( (name+"_halfsphere").toStdString().c_str() ); GetDefaultDataStorage()->Add( imageNode, node ); } void QmitkPreprocessingView::DoApplyMesurementFrame() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) return; vnl_matrix_fixed< double, 3, 3 > mf; for (int r=0; r<3; r++) { for (int c=0; c<3; c++) { QTableWidgetItem* item = m_Controls->m_MeasurementFrameTable->item(r,c); if (!item) return; mf[r][c] = item->text().toDouble(); } } mitk::Image::Pointer newDwi = image->Clone(); newDwi->SetProperty( mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( mf ) ); mitk::DiffusionPropertyHelper propertyHelper( newDwi ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_new-MF").toStdString().c_str()); GetDefaultDataStorage()->Add( imageNode, node ); } void QmitkPreprocessingView::DoShowGradientDirections() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } int maxIndex = 0; unsigned int maxSize = image->GetDimension(0); if (maxSizeGetDimension(1)) { maxSize = image->GetDimension(1); maxIndex = 1; } if (maxSizeGetDimension(2)) { maxSize = image->GetDimension(2); maxIndex = 2; } mitk::Point3D origin = image->GetGeometry()->GetOrigin(); mitk::PointSet::Pointer originSet = mitk::PointSet::New(); typedef mitk::BValueMapProperty::BValueMap BValueMap; typedef mitk::BValueMapProperty::BValueMap::iterator BValueMapIterator; BValueMap bValMap = static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); GradientDirectionContainerType::Pointer gradientContainer = static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); mitk::BaseGeometry::Pointer geometry = image->GetGeometry(); int shellCount = 1; for(BValueMapIterator it = bValMap.begin(); it!=bValMap.end(); ++it) { mitk::PointSet::Pointer pointset = mitk::PointSet::New(); for (unsigned int j=0; jsecond.size(); j++) { mitk::Point3D ip; vnl_vector_fixed< double, 3 > v = gradientContainer->at(it->second[j]); if (v.magnitude()>mitk::eps) { ip[0] = v[0]*maxSize*geometry->GetSpacing()[maxIndex]/2 + origin[0]-0.5*geometry->GetSpacing()[0] + geometry->GetSpacing()[0]*image->GetDimension(0)/2; ip[1] = v[1]*maxSize*geometry->GetSpacing()[maxIndex]/2 + origin[1]-0.5*geometry->GetSpacing()[1] + geometry->GetSpacing()[1]*image->GetDimension(1)/2; ip[2] = v[2]*maxSize*geometry->GetSpacing()[maxIndex]/2 + origin[2]-0.5*geometry->GetSpacing()[2] + geometry->GetSpacing()[2]*image->GetDimension(2)/2; pointset->InsertPoint(j, ip); } else if (originSet->IsEmpty()) { ip[0] = v[0]*maxSize*geometry->GetSpacing()[maxIndex]/2 + origin[0]-0.5*geometry->GetSpacing()[0] + geometry->GetSpacing()[0]*image->GetDimension(0)/2; ip[1] = v[1]*maxSize*geometry->GetSpacing()[maxIndex]/2 + origin[1]-0.5*geometry->GetSpacing()[1] + geometry->GetSpacing()[1]*image->GetDimension(1)/2; ip[2] = v[2]*maxSize*geometry->GetSpacing()[maxIndex]/2 + origin[2]-0.5*geometry->GetSpacing()[2] + geometry->GetSpacing()[2]*image->GetDimension(2)/2; originSet->InsertPoint(j, ip); } } if ( it->first < mitk::eps ) { continue; } // add shell to datastorage mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(pointset); QString name = node->GetName().c_str(); name += "_Shell_"; name += QString::number( it->first ); newNode->SetName( name.toStdString().c_str() ); newNode->SetProperty( "pointsize", mitk::FloatProperty::New((float)maxSize / 50) ); int b0 = shellCount % 2; int b1 = 0; int b2 = 0; if (shellCount>4) { b2 = 1; } if (shellCount%4 >= 2) { b1 = 1; } newNode->SetProperty("color", mitk::ColorProperty::New( b2, b1, b0 )); GetDefaultDataStorage()->Add( newNode, node ); shellCount++; } // add origin to datastorage mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(originSet); QString name = node->GetName().c_str(); name += "_Origin"; newNode->SetName(name.toStdString().c_str()); newNode->SetProperty("pointsize", mitk::FloatProperty::New((float)maxSize/50)); newNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); GetDefaultDataStorage()->Add(newNode, node); } void QmitkPreprocessingView::DoReduceGradientDirections() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } typedef itk::ElectrostaticRepulsionDiffusionGradientReductionFilter FilterType; typedef mitk::BValueMapProperty::BValueMap BValueMap; // GetShellSelection from GUI BValueMap shellSlectionMap; BValueMap originalShellMap = static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); std::vector newNumGradientDirections; int shellCounter = 0; QString name = node->GetName().c_str(); for (int i=0; im_B_ValueMap_TableWidget->rowCount(); i++) { double BValue = m_Controls->m_B_ValueMap_TableWidget->item(i,0)->text().toDouble(); shellSlectionMap[BValue] = originalShellMap[BValue]; unsigned int num = m_Controls->m_B_ValueMap_TableWidget->item(i,1)->text().toUInt(); newNumGradientDirections.push_back(num); name += "_"; name += QString::number(num); shellCounter++; } if (newNumGradientDirections.empty()) { return; } GradientDirectionContainerType::Pointer gradientContainer = static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetOriginalGradientDirections(gradientContainer); filter->SetNumGradientDirections(newNumGradientDirections); filter->SetOriginalBValueMap(originalShellMap); filter->SetShellSelectionBValueMap(shellSlectionMap); filter->Update(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( filter->GetOutput() ); newImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( filter->GetGradientDirections() ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str()).GetPointer() ) ->GetMeasurementFrame() ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ) ); mitk::DiffusionPropertyHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); imageNode->SetName(name.toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); // update the b-value widget to remove the modified number of gradients used for extraction this->CleanBValueTableWidget(); this->UpdateBValueTableWidget(0); } void QmitkPreprocessingView::MergeDwis() { typedef mitk::GradientDirectionsProperty::GradientDirectionsContainerType GradientContainerType; mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } mitk::DataNode::Pointer node2 = m_Controls->m_MergeDwiBox->GetSelectedNode(); if (node2.IsNull()) { return; } mitk::Image::Pointer image2 = dynamic_cast(node2->GetData()); if ( image2 == nullptr ) { return; } typedef itk::VectorImage DwiImageType; typedef DwiImageType::PixelType DwiPixelType; typedef DwiImageType::RegionType DwiRegionType; typedef std::vector< DwiImageType::Pointer > DwiImageContainerType; typedef std::vector< GradientContainerType::Pointer > GradientListContainerType; DwiImageContainerType imageContainer; GradientListContainerType gradientListContainer; std::vector< double > bValueContainer; QString name = ""; { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); imageContainer.push_back( itkVectorImagePointer ); gradientListContainer.push_back( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); bValueContainer.push_back( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); name += node->GetName().c_str(); } { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image2, itkVectorImagePointer); imageContainer.push_back( itkVectorImagePointer ); gradientListContainer.push_back( static_cast ( image2->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); bValueContainer.push_back( static_cast (image2->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); name += "+"; name += node2->GetName().c_str(); } typedef itk::MergeDiffusionImagesFilter FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetImageVolumes(imageContainer); filter->SetGradientLists(gradientListContainer); filter->SetBValues(bValueContainer); filter->Update(); vnl_matrix_fixed< double, 3, 3 > mf; mf.set_identity(); mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( filter->GetOutput() ); newImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( filter->GetOutputGradients() ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( mf ) ); newImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( filter->GetB_Value() ) ); mitk::DiffusionPropertyHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); imageNode->SetName(name.toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode); } void QmitkPreprocessingView::ExtractB0() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } typedef mitk::GradientDirectionsProperty::GradientDirectionsContainerType GradientContainerType; // call the extraction withou averaging if the check-box is checked if( this->m_Controls->m_CheckExtractAll->isChecked() ) { DoExtractBOWithoutAveraging(); return; } ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); // Extract image using found index typedef itk::B0ImageExtractionImageFilter FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetDirections( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->Update(); mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( filter->GetOutput() ); mitkImage->SetVolume( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer newNode=mitk::DataNode::New(); newNode->SetData( mitkImage ); newNode->SetProperty( "name", mitk::StringProperty::New(node->GetName() + "_B0")); GetDefaultDataStorage()->Add(newNode, node); } void QmitkPreprocessingView::DoExtractBOWithoutAveraging() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { return; } // typedefs typedef mitk::GradientDirectionsProperty::GradientDirectionsContainerType GradientContainerType; typedef itk::B0ImageExtractionToSeparateImageFilter< short, short> FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); // Extract image using found index FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetDirections( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->Update(); mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( filter->GetOutput() ); mitkImage->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer newNode=mitk::DataNode::New(); newNode->SetData( mitkImage ); newNode->SetProperty( "name", mitk::StringProperty::New(node->GetName() + "_B0_ALL")); GetDefaultDataStorage()->Add(newNode, node); /*A reinitialization is needed to access the time channels via the ImageNavigationController The Global-Geometry can not recognize the time channel without a re-init. (for a new selection in datamanger a automatically updated of the Global-Geometry should be done - if it contains the time channel)*/ mitk::RenderingManager::GetInstance()->InitializeViews( newNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } void QmitkPreprocessingView::AverageGradients() { mitk::DataNode::Pointer node = m_Controls->m_SelctedImageComboBox->GetSelectedNode(); if (node.IsNull()) { return; } mitk::Image::Pointer image = dynamic_cast(node->GetData()); if ( image == nullptr ) { return; } bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) return; mitk::Image::Pointer newDwi = image->Clone(); newDwi->SetPropertyList( image->GetPropertyList()->Clone() ); mitk::DiffusionPropertyHelper propertyHelper(newDwi); propertyHelper.AverageRedundantGradients(m_Controls->m_Blur->value()); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newDwi ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_averaged").toStdString().c_str()); GetDefaultDataStorage()->Add(imageNode, node); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingView.h index a7444bafbf..9e7fc32804 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingView.h @@ -1,167 +1,168 @@ /*=================================================================== 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 _QMITKPREPROCESSINGVIEW_H_INCLUDED #define _QMITKPREPROCESSINGVIEW_H_INCLUDED #include #include "ui_QmitkPreprocessingViewControls.h" // st includes #include // itk includes #include #include // mitk includes #include #include "itkDWIVoxelFunctor.h" #include typedef short DiffusionPixelType; struct PrpSelListener; /*! * \ingroup org_mitk_gui_qt_preprocessing_internal * * \brief Viewing and modifying diffusion weighted images (gradient reduction, resampling, b-value projection, ...) * * \sa QmitkFunctionality */ class QmitkPreprocessingView : public QmitkFunctionality { friend struct PrpSelListener; // this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) Q_OBJECT public: static const std::string VIEW_ID; typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientDirectionContainerType; typedef itk::VectorImage< short, 3 > ItkDwiType; typedef itk::Image< unsigned char, 3 > UcharImageType; typedef itk::Image< double, 3 > ItkDoubleImageType; QmitkPreprocessingView(); virtual ~QmitkPreprocessingView(); virtual void CreateQtPartControl(QWidget *parent) override; /// \brief Creation of the connections of main and control widget virtual void CreateConnections(); /// \brief Called when the functionality is activated virtual void Activated() override; virtual void Deactivated() override; virtual void Visible() override; virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) override; virtual void StdMultiWidgetNotAvailable() override; static const int nrconvkernels; protected slots: void AverageGradients(); void ExtractB0(); void MergeDwis(); void DoApplySpacing(); void DoApplyOrigin(); void DoApplyDirectionMatrix(); void DoApplyMesurementFrame(); void DoReduceGradientDirections(); void DoShowGradientDirections(); void DoHalfSphereGradientDirections(); void UpdateDwiBValueMapRounder(int i); void DoLengthCorrection(); void DoAdcCalculation(); void DoDwiNormalization(); void DoProjectSignal(); void DoExtractBrainMask(); void DoResampleImage(); void DoCropImage(); void DoUpdateInterpolationGui(int i); void DoRemoveGradient(); void DoExtractGradient(); void DoFlipAxis(); void OnImageSelectionChanged(); + void DoFlipGradientDirections(); protected: void DoADCFit(); void DoAKCFit(); void DoBiExpFit(); void DoADCAverage(); template < typename TPixel, unsigned int VImageDimension > void TemplatedFlipAxis( itk::Image* itkImage); template < typename TPixel, unsigned int VImageDimension > void TemplatedCropImage( itk::Image* itkImage); template < typename TPixel, unsigned int VImageDimension > void TemplatedApplyRotation( itk::Image* itkImage); template < typename TPixel, unsigned int VImageDimension > void TemplatedUpdateGui( itk::Image* itkImage); template < typename TPixel, unsigned int VImageDimension > void TemplatedUpdateGui( itk::VectorImage* itkImage); template < typename TPixel, unsigned int VImageDimension > void TemplatedResampleImage( itk::Image* itkImage); template < typename TPixel, unsigned int VImageDimension > void TemplatedSetImageSpacing( itk::Image* itkImage); template < typename TPixel, unsigned int VImageDimension > void TemplatedSetImageOrigin( itk::Image* itkImage); /** Called by ExtractB0 if check-box activated, extracts all b0 images without averaging */ void DoExtractBOWithoutAveraging(); void UpdateBValueTableWidget(int); /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ) override; // why not? Ui::QmitkPreprocessingViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; void SetDefaultNodeProperties(mitk::DataNode::Pointer node, std::string name); void CallMultishellToSingleShellFilter( itk::DWIVoxelFunctor * functor, mitk::Image::Pointer ImPtr, QString imageName, mitk::DataNode* parent ); void CleanBValueTableWidget(); }; #endif // _QMITKPREPROCESSINGVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingViewControls.ui index 9c99bd30a3..6559c06955 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkPreprocessingViewControls.ui @@ -1,1650 +1,1730 @@ QmitkPreprocessingViewControls 0 0 523 1158 0 0 false QmitkPreprocessingViewControls true Please Select Input Data Image: QComboBox::AdjustToMinimumContentsLength 0 Gradients 0 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAlwaysOff true 100 true false true b-Value Number of gradients QFrame::NoFrame QFrame::Raised 0 0 0 0 6 - - - false - - - Sometimes the gradient directions are not located on one half sphere. - - - - - - - - - Mirror gradients to half sphere - - - - - - - false - - - Round b-values - - - - - + false - Retain only the specified number of gradient directions and according image volumes. The retained directions are spread equally over the half sphere using an iterative energy repulsion strategy. + Generate pointset displaying the gradient vectors (applied measurement frame). - Reduce number of gradients + Show gradients <html><head/><body><p>Define the sampling frame the b-Values are rounded with.</p></body></html> Sampling frame: false <html><head/><body><p>Round b-values to nearest multiple of this value (click &quot;Round b-value&quot; to create new image with these values).</p></body></html> QAbstractSpinBox::CorrectToNearestValue 1 10000 10 + + + + false + + + Retain only the specified number of gradient directions and according image volumes. The retained directions are spread equally over the half sphere using an iterative energy repulsion strategy. + + + + + + + + + Reduce number of gradients + + + + + + + false + + + Sometimes the gradient directions are not located on one half sphere. + + + + + + + + + Mirror gradients to half sphere + + + + + + + false + + + Round b-values + + + - + false Generate pointset displaying the gradient vectors (applied measurement frame). - Show gradients + Flip gradients + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + x + + + + + + + y + + + + + + + z + + + + + + Qt::Vertical 20 40 Image Values Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. 6 2.000000000000000 0.000100000000000 0.001000000000000 Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Merge radius false Merges selected DWIs of same dimension. If several b-values are present, the resulting image will contain multiple b-shells. Merge selected DWIs false Normalize image values QFrame::NoFrame QFrame::Raised 0 0 0 0 0 false Target b-value 100000 500 Select projection method. QComboBox::AdjustToMinimumContentsLength ADC Average AKC Bi-Exponential false Multiple acquistions of one gradient direction can be averaged. Due to rounding errors, similar gradients often differ in the last decimal positions. The Merge radius allows to average them by taking all directions within a certain radius into account. Average repetitions false Project image values onto one b-shell. Project onto shell QFrame::NoFrame QFrame::Raised 0 0 0 0 0 + + + true + + + New b-0 stdev + + + 100000 + + + 100 + + + 500 + + + + Select binary mask image. QComboBox::AdjustToMinimumContentsLength - + + + true + - Select normalization reference. + New mean b-0 value - - QComboBox::AdjustToMinimumContentsLength + + 100000 + + + 100 + + + 1000 - - - White matter - - - - - CSF - - - - - Voxel-wise baseline - - false Merges selected DWIs of same dimension. If several b-values are present, the resulting image will contain multiple b-shells. Flip axis QFrame::NoFrame QFrame::Raised 0 0 0 0 Y Qt::Horizontal 40 20 X Z Axis: QComboBox::AdjustToMinimumContentsLength Resample image QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0.010000000000000 2.000000000000000 0.010000000000000 2.000000000000000 0.010000000000000 2.000000000000000 Sampling factor New image spacing New image size QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Interpolator: Nearest neighbour Linear B-spline Windowed sinc false Resample image QFrame::NoFrame QFrame::Raised 0 0 0 0 0 1 10000 1 10000 1 10000 Header Image size 0 0 0 y: Number of pixels to remove on lower image bound. 999999999 Number of pixels to remove on upper image bound. 999999999 Number of pixels to remove on upper image bound. 999999999 Number of pixels to remove on lower image bound. 999999999 x: Number of pixels to remove on lower image bound. 999999999 Number of pixels to remove on upper image bound. 999999999 z: false Crop image Remove or extract gradient volumes false Generate pointset displaying the gradient vectors (applied measurement frame). Remove false Generate pointset displaying the gradient vectors (applied measurement frame). Extract Voxel size 0 0 0 4 4 4 0.000000000000000 99.989999999999995 false Set new voxel size Qt::Vertical 20 40 0 0 Measurment frame 0 0 0 Qt::Horizontal 40 20 false 0 0 0 0 IBeamCursor true Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true false false true true 0 false true true New Row New Row New Row New Column New Column New Column false Diffusion encoding gradient directions are rotated accordingly. Apply new measurement frame Direction matrix 0 9 0 0 false 0 0 0 0 IBeamCursor true Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true false false true true 0 false true true New Row New Row New Row New Column New Column New Column false Diffusion encoding gradient directions are rotated accordingly. Apply new direction Qt::Horizontal 40 20 Origin 0 0 0 4 -999999999.000000000000000 999999999.000000000000000 4 -999999999.000000000000000 999999999.000000000000000 4 -99999999.000000000000000 999999999.000000000000000 false Set new origin Other Create a 3D+t data set containing all b0 images as timesteps Disable averaging false If multiple baseline acquisitions are present, the default behaviour is to output an averaged image. Extract baseline image Qt::Vertical 20 40 false If multiple baseline acquisitions are present, the default behaviour is to output an averaged image. Calculate ADC map false If multiple baseline acquisitions are present, the default behaviour is to output an averaged image. Estimate binary brain mask Maximum number of iterations. 10000 10000 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
m_B_ValueMap_Rounder_SpinBox m_Blur m_targetBValueSpinBox m_ProjectionMethodBox m_ResampleTypeBox m_ResampleDoubleX m_ResampleDoubleY m_ResampleDoubleZ m_ResampleIntX m_ResampleIntY m_ResampleIntZ m_InterpolatorBox m_HeaderSpacingX m_HeaderSpacingY m_HeaderSpacingZ m_HeaderOriginX m_HeaderOriginY m_HeaderOriginZ m_DirectionMatrixTable m_MeasurementFrameTable m_CheckExtractAll m_BrainMaskIterationsBox tabWidget m_B_ValueMap_TableWidget m_CreateLengthCorrectedDwi m_ShowGradientsButton m_MirrorGradientToHalfSphereButton m_ReduceGradientsButton m_ButtonAverageGradients m_ProjectSignalButton m_NormalizeImageValuesButton m_MergeDwisButton m_ResampleImageButton m_ModifySpacingButton m_ModifyOriginButton m_ModifyDirection m_ModifyMeasurementFrame m_ButtonExtractB0 m_CalcAdcButton m_ExtractBrainMask