diff --git a/Applications/Diffusion/CMakeLists.txt b/Applications/Diffusion/CMakeLists.txt index 903b7d2193..fc47284c90 100644 --- a/Applications/Diffusion/CMakeLists.txt +++ b/Applications/Diffusion/CMakeLists.txt @@ -1,95 +1,96 @@ project(MitkDiffusion) set(DIFFUSIONAPP_NAME MitkDiffusion) set(_app_options) if(MITK_SHOW_CONSOLE_WINDOW) list(APPEND _app_options SHOW_CONSOLE) endif() # Create a cache entry for the provisioning file which is used to export # the file name in the MITKConfig.cmake file. This will keep external projects # which rely on this file happy. set(DIFFUSIONIMAGINGAPP_PROVISIONING_FILE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${DIFFUSIONAPP_NAME}.provisioning" CACHE INTERNAL "${DIFFUSIONAPP_NAME} provisioning file" FORCE) # should be identical to the list in /CMake/mitkBuildConfigurationmitkDiffusion.cmake # remember to set plugins which should be automatically toggled in target_libraries.cmake set(_plugins org.commontk.configadmin org.commontk.eventadmin org.blueberry.core.runtime org.blueberry.core.expressions org.blueberry.core.commands org.blueberry.ui.qt org.blueberry.ui.qt.log org.blueberry.ui.qt.help org.mitk.core.services org.mitk.gui.common org.mitk.planarfigure org.mitk.core.ext org.mitk.gui.qt.application org.mitk.gui.qt.ext org.mitk.gui.qt.diffusionimagingapp org.mitk.gui.qt.common org.mitk.gui.qt.stdmultiwidgeteditor org.mitk.gui.qt.common.legacy org.mitk.gui.qt.datamanager org.mitk.gui.qt.measurementtoolbox org.mitk.gui.qt.segmentation org.mitk.gui.qt.volumevisualization org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.diffusionimaging.connectomics org.mitk.gui.qt.diffusionimaging.fiberfox org.mitk.gui.qt.diffusionimaging.fiberprocessing org.mitk.gui.qt.diffusionimaging.ivim org.mitk.gui.qt.diffusionimaging.odfpeaks org.mitk.gui.qt.diffusionimaging.preprocessing org.mitk.gui.qt.diffusionimaging.reconstruction org.mitk.gui.qt.diffusionimaging.tractography org.mitk.gui.qt.matchpoint.algorithm.browser org.mitk.gui.qt.matchpoint.algorithm.control + org.mitk.gui.qt.matchpoint.mapper org.mitk.gui.qt.imagenavigator org.mitk.gui.qt.moviemaker org.mitk.gui.qt.basicimageprocessing org.mitk.gui.qt.properties org.mitk.gui.qt.viewnavigator ) # Plug-ins listed below will not be # - added as a build-time dependency to the executable # - listed in the provisioning file for the executable # - installed if they are external plug-ins set(_exclude_plugins org.blueberry.test org.blueberry.uitest org.mitk.gui.qt.coreapplication org.mitk.gui.qt.extapplication ) set(_src_files MitkDiffusion.cpp ) qt5_add_resources(_src_files splashscreen.qrc) mitkFunctionCreateBlueBerryApplication( NAME ${DIFFUSIONAPP_NAME} DESCRIPTION "MITK Diffusion" PLUGINS ${_plugins} EXCLUDE_PLUGINS ${_exclude_plugins} SOURCES ${_src_files} ${_app_options} ) mitk_use_modules(TARGET ${DIFFUSIONAPP_NAME} MODULES MitkAppUtil) # Add meta dependencies (e.g. on auto-load modules from depending modules) if(TARGET ${CMAKE_PROJECT_NAME}-autoload) add_dependencies(${DIFFUSIONAPP_NAME} ${CMAKE_PROJECT_NAME}-autoload) endif() # Add a build time dependency to legacy BlueBerry bundles. if(MITK_MODULES_ENABLED_PLUGINS) add_dependencies(${DIFFUSIONAPP_NAME} ${MITK_MODULES_ENABLED_PLUGINS}) endif() diff --git a/Applications/Diffusion/target_libraries.cmake b/Applications/Diffusion/target_libraries.cmake index a6496917be..347d5fbc04 100644 --- a/Applications/Diffusion/target_libraries.cmake +++ b/Applications/Diffusion/target_libraries.cmake @@ -1,29 +1,32 @@ # A list of plug-in targets which should be automatically enabled -# (or be available in external projects) for this application. +# (or be available in external projects) for this application set(target_libraries org_blueberry_ui_qt org_blueberry_ui_qt_help org_mitk_planarfigure org_mitk_gui_qt_diffusionimagingapp org_mitk_gui_qt_common_legacy org_mitk_gui_qt_ext org_mitk_gui_qt_datamanager org_mitk_gui_qt_segmentation org_mitk_gui_qt_volumevisualization org_mitk_gui_qt_diffusionimaging org_mitk_gui_qt_diffusionimaging_connectomics org_mitk_gui_qt_diffusionimaging_fiberfox org_mitk_gui_qt_diffusionimaging_fiberprocessing org_mitk_gui_qt_diffusionimaging_ivim org_mitk_gui_qt_diffusionimaging_odfpeaks org_mitk_gui_qt_diffusionimaging_preprocessing org_mitk_gui_qt_diffusionimaging_reconstruction org_mitk_gui_qt_diffusionimaging_tractography + org_mitk_gui_qt_matchpoint_algorithm_browser + org_mitk_gui_qt_matchpoint_algorithm_control + org_mitk_gui_qt_matchpoint_mapper org_mitk_gui_qt_imagenavigator org_mitk_gui_qt_moviemaker org_mitk_gui_qt_measurementtoolbox org_mitk_gui_qt_basicimageprocessing org_mitk_gui_qt_viewnavigator ) diff --git a/CMake/BuildConfigurations/mitkDiffusion.cmake b/CMake/BuildConfigurations/DiffusionAll.cmake similarity index 94% rename from CMake/BuildConfigurations/mitkDiffusion.cmake rename to CMake/BuildConfigurations/DiffusionAll.cmake index 5e00e6b54b..26f661e2c9 100644 --- a/CMake/BuildConfigurations/mitkDiffusion.cmake +++ b/CMake/BuildConfigurations/DiffusionAll.cmake @@ -1,35 +1,34 @@ -message(STATUS "Configuring MITK Diffusion Release Build") +message(STATUS "Configuring MITK Diffusion with all Plugins") # Enable non-optional external dependencies set(MITK_USE_Vigra ON CACHE BOOL "MITK Use Vigra Library" FORCE) set(MITK_USE_HDF5 ON CACHE BOOL "MITK Use HDF5 Library" FORCE) set(MITK_USE_DCMQI ON CACHE BOOL "" FORCE) set(MITK_USE_MatchPoint ON CACHE BOOL "" FORCE) # Disable all apps but MITK Diffusion set(MITK_BUILD_ALL_APPS OFF CACHE BOOL "Build all MITK applications" FORCE) set(MITK_BUILD_APP_CoreApp OFF CACHE BOOL "Build the MITK CoreApp" FORCE) -set(MITK_BUILD_APP_Workbench OFF CACHE BOOL "Build the MITK Workbench" FORCE) set(MITK_BUILD_APP_Diffusion ON CACHE BOOL "Build MITK Diffusion" FORCE) # Activate Diffusion Mini Apps set(BUILD_DiffusionCoreCmdApps ON CACHE BOOL "Build commandline tools for diffusion" FORCE) set(BUILD_DiffusionFiberProcessingCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber processing" FORCE) set(BUILD_DiffusionFiberfoxCmdApps ON CACHE BOOL "Build commandline tools for diffusion data simulation (Fiberfox)" FORCE) set(BUILD_DiffusionMiscCmdApps ON CACHE BOOL "Build miscellaneous commandline tools for diffusion" FORCE) set(BUILD_DiffusionQuantificationCmdApps ON CACHE BOOL "Build commandline tools for diffusion quantification (IVIM, ADC, ...)" FORCE) set(BUILD_DiffusionTractographyCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber tractography" FORCE) set(BUILD_DiffusionTractographyEvaluationCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber tractography evaluation" FORCE) set(BUILD_DiffusionConnectomicsCmdApps ON CACHE BOOL "Build commandline tools for diffusion connectomics" FORCE) # Build neither all plugins nor examples set(MITK_BUILD_ALL_PLUGINS OFF CACHE BOOL "Build all MITK plugins" FORCE) set(MITK_BUILD_EXAMPLES OFF CACHE BOOL "Build the MITK examples" FORCE) set(BUILD_TESTING ON CACHE BOOL "Build the MITK tests" FORCE) # Activate in-application help generation set(MITK_DOXYGEN_GENERATE_QCH_FILES ON CACHE BOOL "Use doxygen to generate Qt compressed help files for MITK docs" FORCE) set(BLUEBERRY_USE_QT_HELP ON CACHE BOOL "Enable support for integrating bundle documentation into Qt Help" FORCE) # Disable console window set(MITK_SHOW_CONSOLE_WINDOW ON CACHE BOOL "Use this to enable or disable the console window when starting MITK GUI Applications" FORCE) diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTckReader.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTckReader.cpp index 1c5d1ddca6..cc326c9b2c 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTckReader.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTckReader.cpp @@ -1,166 +1,164 @@ /*=================================================================== 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 "mitkFiberBundleTckReader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkDiffusionIOMimeTypes.h" #include #include mitk::FiberBundleTckReader::FiberBundleTckReader() - : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_TCK_MIMETYPE_NAME(), "tck Fiber Bundle Reader (MRtrix format)" ) + : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_TCK_MIMETYPE_NAME(), "tck Fiber Bundle Reader (MRtrix format)" ) { - m_ServiceReg = this->RegisterService(); + m_ServiceReg = this->RegisterService(); } mitk::FiberBundleTckReader::FiberBundleTckReader(const FiberBundleTckReader &other) - :mitk::AbstractFileReader(other) + :mitk::AbstractFileReader(other) { } mitk::FiberBundleTckReader * mitk::FiberBundleTckReader::Clone() const { - return new FiberBundleTckReader(*this); + return new FiberBundleTckReader(*this); } std::vector > mitk::FiberBundleTckReader::Read() { - std::vector > result; - try - { - const std::string& locale = "C"; - const std::string& currLocale = setlocale( LC_ALL, nullptr ); - setlocale(LC_ALL, locale.c_str()); + std::vector > result; + try + { + const std::string& locale = "C"; + const std::string& currLocale = setlocale( LC_ALL, nullptr ); + setlocale(LC_ALL, locale.c_str()); - std::string filename = this->GetInputLocation(); + std::string filename = this->GetInputLocation(); - std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename); - ext = itksys::SystemTools::LowerCase(ext); + std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename); + ext = itksys::SystemTools::LowerCase(ext); - if (ext==".tck") + if (ext==".tck") + { + MITK_INFO << "Loading tractogram (MRtrix format): " << itksys::SystemTools::GetFilenameName(filename); + std::FILE* filePointer = std::fopen(filename.c_str(),"r+b"); + std::string header = ""; + + bool header_end = false; + int count = 0; + while (!header_end) + { + char c; + count += std::fread(&c, 1, 1, filePointer); + header += c; + if (header.size() >= 3 && header.compare(header.size() - 3, 3, "END") == 0) + header_end = true; + } + MITK_INFO << "TCK Header:"; + MITK_INFO << header; + + int header_size = -1; + try + { + std::string delimiter = "file: . "; + size_t pos = 0; + pos = header.find(delimiter); + header.erase(0, pos + delimiter.length()); + pos = header.find("\n"); + header_size = boost::lexical_cast(header.substr(0, pos)); + } + catch(...) + { + + } + + if (header_size==-1) + mitkThrow() << "Could not parse header size from " << filename; + std::fseek ( filePointer , header_size , SEEK_SET ); + + vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); + vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); + vtkSmartPointer container = vtkSmartPointer::New(); + + float tmp[3]; + count = 1; + int fiber_length = 0; + while (std::fread((char*)tmp, 1, 12, filePointer)==12) + { + if (std::isinf(tmp[0]) || std::isinf(tmp[1]) || std::isinf(tmp[1])) + break; + else if (std::isnan(tmp[0]) || std::isnan(tmp[1]) || std::isnan(tmp[2])) { - std::FILE* filePointer = std::fopen(filename.c_str(),"r+b"); - std::string header = ""; - - bool header_end = false; - int count = 0; - while (!header_end) - { - char c; - count += std::fread(&c, 1, 1, filePointer); - header += c; - if (header.size() >= 3 && header.compare(header.size() - 3, 3, "END") == 0) - header_end = true; - } - MITK_INFO << "TCK Header:"; - MITK_INFO << header; - - int header_size = -1; - try - { - std::string delimiter = "file: . "; - size_t pos = 0; - pos = header.find(delimiter); - header.erase(0, pos + delimiter.length()); - pos = header.find("\n"); - header_size = boost::lexical_cast(header.substr(0, pos)); - } - catch(...) - { - - } - - if (header_size==-1) - mitkThrow() << "Could not parse header size from " << filename; - std::fseek ( filePointer , header_size , SEEK_SET ); - - MITK_INFO << "Reading TCK file"; - - - vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); - vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); - vtkSmartPointer container = vtkSmartPointer::New(); - - float tmp[3]; - count = 1; - int fiber_length = 0; - while (std::fread((char*)tmp, 1, 12, filePointer)==12) - { - if (std::isinf(tmp[0]) || std::isinf(tmp[1]) || std::isinf(tmp[1])) - break; - else if (std::isnan(tmp[0]) || std::isnan(tmp[1]) || std::isnan(tmp[2])) - { - count++; - fiber_length = 0; - vtkNewCells->InsertNextCell(container); - container = vtkSmartPointer::New(); - } - else - { - fiber_length++; - vtkIdType id = vtkNewPoints->InsertNextPoint(tmp); - container->GetPointIds()->InsertNextId(id); - } - } - - vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); - fiberPolyData->SetPoints(vtkNewPoints); - fiberPolyData->SetLines(vtkNewCells); - - // transform polydata from RAS (MRtrix) to LPS (MITK) - mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); - vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New(); - matrix->Identity(); - matrix->SetElement(0,0,-matrix->GetElement(0,0)); - matrix->SetElement(1,1,-matrix->GetElement(1,1)); - geometry->SetIndexToWorldTransformByVtkMatrix(matrix); - - vtkSmartPointer transformFilter = vtkSmartPointer::New(); - transformFilter->SetInputData(fiberPolyData); - transformFilter->SetTransform(geometry->GetVtkTransform()); - transformFilter->Update(); - - FiberBundle::Pointer fib = FiberBundle::New(transformFilter->GetOutput()); - result.push_back(fib.GetPointer()); + count++; + fiber_length = 0; + vtkNewCells->InsertNextCell(container); + container = vtkSmartPointer::New(); } - - setlocale(LC_ALL, currLocale.c_str()); - MITK_INFO << "Fiber bundle read"; - return result; - } - catch(...) - { - throw; + else + { + fiber_length++; + vtkIdType id = vtkNewPoints->InsertNextPoint(tmp); + container->GetPointIds()->InsertNextId(id); + } + } + + vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); + fiberPolyData->SetPoints(vtkNewPoints); + fiberPolyData->SetLines(vtkNewCells); + + // transform polydata from RAS (MRtrix) to LPS (MITK) + mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); + vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New(); + matrix->Identity(); + matrix->SetElement(0,0,-matrix->GetElement(0,0)); + matrix->SetElement(1,1,-matrix->GetElement(1,1)); + geometry->SetIndexToWorldTransformByVtkMatrix(matrix); + + vtkSmartPointer transformFilter = vtkSmartPointer::New(); + transformFilter->SetInputData(fiberPolyData); + transformFilter->SetTransform(geometry->GetVtkTransform()); + transformFilter->Update(); + + FiberBundle::Pointer fib = FiberBundle::New(transformFilter->GetOutput()); + result.push_back(fib.GetPointer()); } + + setlocale(LC_ALL, currLocale.c_str()); + MITK_INFO << "Fiber bundle read"; return result; + } + catch(...) + { + throw; + } + return result; } diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTrackVisReader.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTrackVisReader.cpp index 0d02e09733..beac4c8317 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTrackVisReader.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTrackVisReader.cpp @@ -1,86 +1,87 @@ /*=================================================================== 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 "mitkFiberBundleTrackVisReader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkDiffusionIOMimeTypes.h" mitk::FiberBundleTrackVisReader::FiberBundleTrackVisReader() - : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_TRK_MIMETYPE_NAME(), "TrackVis Fiber Bundle Reader" ) + : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_TRK_MIMETYPE_NAME(), "TrackVis Fiber Bundle Reader" ) { - m_ServiceReg = this->RegisterService(); + m_ServiceReg = this->RegisterService(); } mitk::FiberBundleTrackVisReader::FiberBundleTrackVisReader(const FiberBundleTrackVisReader &other) - :mitk::AbstractFileReader(other) + :mitk::AbstractFileReader(other) { } mitk::FiberBundleTrackVisReader * mitk::FiberBundleTrackVisReader::Clone() const { - return new FiberBundleTrackVisReader(*this); + return new FiberBundleTrackVisReader(*this); } std::vector > mitk::FiberBundleTrackVisReader::Read() { - std::vector > result; - try - { - const std::string& locale = "C"; - const std::string& currLocale = setlocale( LC_ALL, nullptr ); - setlocale(LC_ALL, locale.c_str()); - - std::string filename = this->GetInputLocation(); - - std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename); - ext = itksys::SystemTools::LowerCase(ext); - - if (ext==".trk") - { - FiberBundle::Pointer mitk_fib = FiberBundle::New(); - TrackVisFiberReader reader; - reader.open(this->GetInputLocation().c_str()); - reader.read(mitk_fib.GetPointer()); - result.push_back(mitk_fib.GetPointer()); - return result; - } - - setlocale(LC_ALL, currLocale.c_str()); - MITK_INFO << "Fiber bundle read"; - } - catch(...) + std::vector > result; + try + { + const std::string& locale = "C"; + const std::string& currLocale = setlocale( LC_ALL, nullptr ); + setlocale(LC_ALL, locale.c_str()); + + std::string filename = this->GetInputLocation(); + MITK_INFO << "Loading tractogram (TrackVis format): " << itksys::SystemTools::GetFilenameName(filename); + + std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename); + ext = itksys::SystemTools::LowerCase(ext); + + if (ext==".trk") { - throw; + FiberBundle::Pointer mitk_fib = FiberBundle::New(); + TrackVisFiberReader reader; + reader.open(this->GetInputLocation().c_str()); + reader.read(mitk_fib.GetPointer()); + result.push_back(mitk_fib.GetPointer()); + return result; } - return result; + + setlocale(LC_ALL, currLocale.c_str()); + MITK_INFO << "Fiber bundle read"; + } + catch(...) + { + throw; + } + return result; } diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleVtkReader.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleVtkReader.cpp index 81da34bea2..0b98c2ebb2 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleVtkReader.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleVtkReader.cpp @@ -1,284 +1,284 @@ /*=================================================================== 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 "mitkFiberBundleVtkReader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkDiffusionIOMimeTypes.h" mitk::FiberBundleVtkReader::FiberBundleVtkReader() - : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_VTK_MIMETYPE_NAME(), "VTK Fiber Bundle Reader" ) + : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_VTK_MIMETYPE_NAME(), "VTK Fiber Bundle Reader" ) { - m_ServiceReg = this->RegisterService(); + m_ServiceReg = this->RegisterService(); } mitk::FiberBundleVtkReader::FiberBundleVtkReader(const FiberBundleVtkReader &other) - :mitk::AbstractFileReader(other) + :mitk::AbstractFileReader(other) { } mitk::FiberBundleVtkReader * mitk::FiberBundleVtkReader::Clone() const { - return new FiberBundleVtkReader(*this); + return new FiberBundleVtkReader(*this); } std::vector > mitk::FiberBundleVtkReader::Read() { - std::vector > result; + std::vector > result; - const std::string& locale = "C"; - const std::string& currLocale = setlocale( LC_ALL, nullptr ); - setlocale(LC_ALL, locale.c_str()); + const std::string& locale = "C"; + const std::string& currLocale = setlocale( LC_ALL, nullptr ); + setlocale(LC_ALL, locale.c_str()); - std::string filename = this->GetInputLocation(); + std::string filename = this->GetInputLocation(); - std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename); - ext = itksys::SystemTools::LowerCase(ext); + std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename); + ext = itksys::SystemTools::LowerCase(ext); - try + try + { + MITK_INFO << "Loading tractogram (VTK format): " << itksys::SystemTools::GetFilenameName(filename); + vtkSmartPointer reader = vtkSmartPointer::New(); + reader->SetFileName( this->GetInputLocation().c_str() ); + + if (reader->IsFilePolyData()) { - MITK_INFO << "Trying to load fiber file as VTK format."; - vtkSmartPointer reader = vtkSmartPointer::New(); - reader->SetFileName( this->GetInputLocation().c_str() ); + reader->Update(); - if (reader->IsFilePolyData()) - { - reader->Update(); + if ( reader->GetOutput() != nullptr ) + { + vtkSmartPointer fiberPolyData = reader->GetOutput(); + FiberBundle::Pointer fiberBundle = FiberBundle::New(fiberPolyData); - if ( reader->GetOutput() != nullptr ) + vtkSmartPointer weights = vtkFloatArray::SafeDownCast(fiberPolyData->GetCellData()->GetArray("FIBER_WEIGHTS")); + if (weights!=nullptr) + { + // float weight=0; + for (int i=0; iGetNumberOfValues(); i++) + { + if (weights->GetValue(i)<0.0) { - vtkSmartPointer fiberPolyData = reader->GetOutput(); - FiberBundle::Pointer fiberBundle = FiberBundle::New(fiberPolyData); - - vtkSmartPointer weights = vtkFloatArray::SafeDownCast(fiberPolyData->GetCellData()->GetArray("FIBER_WEIGHTS")); - if (weights!=nullptr) - { -// float weight=0; - for (int i=0; iGetNumberOfValues(); i++) - { - if (weights->GetValue(i)<0.0) - { - MITK_ERROR << "Fiber weight<0 detected! Setting value to 0."; - weights->SetValue(i,0); - } - } -// if (!mitk::Equal(weights->GetValue(i),weight,0.00001)) -// { -// MITK_INFO << "Weight: " << weights->GetValue(i); -// weight = weights->GetValue(i); -// } - fiberBundle->SetFiberWeights(weights); - } - - vtkSmartPointer fiberColors = vtkUnsignedCharArray::SafeDownCast(fiberPolyData->GetPointData()->GetArray("FIBER_COLORS")); - if (fiberColors!=nullptr) - fiberBundle->SetFiberColors(fiberColors); - - result.push_back(fiberBundle.GetPointer()); - return result; + MITK_ERROR << "Fiber weight<0 detected! Setting value to 0."; + weights->SetValue(i,0); } + } + // if (!mitk::Equal(weights->GetValue(i),weight,0.00001)) + // { + // MITK_INFO << "Weight: " << weights->GetValue(i); + // weight = weights->GetValue(i); + // } + fiberBundle->SetFiberWeights(weights); } - else - MITK_INFO << "File is not VTK format."; + + vtkSmartPointer fiberColors = vtkUnsignedCharArray::SafeDownCast(fiberPolyData->GetPointData()->GetArray("FIBER_COLORS")); + if (fiberColors!=nullptr) + fiberBundle->SetFiberColors(fiberColors); + + result.push_back(fiberBundle.GetPointer()); + return result; + } } - catch(...) + else + MITK_INFO << "File is not VTK format."; + } + catch(...) + { + throw; + } + + try + { + MITK_INFO << "Trying to load fiber file as VTP format."; + vtkSmartPointer reader = vtkSmartPointer::New(); + reader->SetFileName( this->GetInputLocation().c_str() ); + + if ( reader->CanReadFile(this->GetInputLocation().c_str()) ) { - throw; - } + reader->Update(); - try - { - MITK_INFO << "Trying to load fiber file as VTP format."; - vtkSmartPointer reader = vtkSmartPointer::New(); - reader->SetFileName( this->GetInputLocation().c_str() ); + if ( reader->GetOutput() != nullptr ) + { + vtkSmartPointer fiberPolyData = reader->GetOutput(); + FiberBundle::Pointer fiberBundle = FiberBundle::New(fiberPolyData); - if ( reader->CanReadFile(this->GetInputLocation().c_str()) ) - { - reader->Update(); + vtkSmartPointer weights = vtkFloatArray::SafeDownCast(fiberPolyData->GetCellData()->GetArray("FIBER_WEIGHTS")); - if ( reader->GetOutput() != nullptr ) - { - vtkSmartPointer fiberPolyData = reader->GetOutput(); - FiberBundle::Pointer fiberBundle = FiberBundle::New(fiberPolyData); - - vtkSmartPointer weights = vtkFloatArray::SafeDownCast(fiberPolyData->GetCellData()->GetArray("FIBER_WEIGHTS")); - - if (weights!=nullptr) - { -// float weight=0; -// for (int i=0; iGetSize(); i++) -// if (!mitk::Equal(weights->GetValue(i),weight,0.00001)) -// { -// MITK_INFO << "Weight: " << weights->GetValue(i); -// weight = weights->GetValue(i); -// } - fiberBundle->SetFiberWeights(weights); - } - - vtkSmartPointer fiberColors = vtkUnsignedCharArray::SafeDownCast(fiberPolyData->GetPointData()->GetArray("FIBER_COLORS")); - if (fiberColors!=nullptr) - fiberBundle->SetFiberColors(fiberColors); - - result.push_back(fiberBundle.GetPointer()); - return result; - } + if (weights!=nullptr) + { + // float weight=0; + // for (int i=0; iGetSize(); i++) + // if (!mitk::Equal(weights->GetValue(i),weight,0.00001)) + // { + // MITK_INFO << "Weight: " << weights->GetValue(i); + // weight = weights->GetValue(i); + // } + fiberBundle->SetFiberWeights(weights); } - else - MITK_INFO << "File is not VTP format."; - } - catch(...) - { - throw; - } - try + vtkSmartPointer fiberColors = vtkUnsignedCharArray::SafeDownCast(fiberPolyData->GetPointData()->GetArray("FIBER_COLORS")); + if (fiberColors!=nullptr) + fiberBundle->SetFiberColors(fiberColors); + + result.push_back(fiberBundle.GetPointer()); + return result; + } + } + else + MITK_INFO << "File is not VTP format."; + } + catch(...) + { + throw; + } + + try + { + MITK_INFO << "Trying to load fiber file as deprecated XML format."; + vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); + vtkSmartPointer cellArray = vtkSmartPointer::New(); + vtkSmartPointer points = vtkSmartPointer::New(); + TiXmlDocument doc( this->GetInputLocation().c_str() ); + if(doc.LoadFile()) { - MITK_INFO << "Trying to load fiber file as deprecated XML format."; - vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); - vtkSmartPointer cellArray = vtkSmartPointer::New(); - vtkSmartPointer points = vtkSmartPointer::New(); - TiXmlDocument doc( this->GetInputLocation().c_str() ); - if(doc.LoadFile()) + TiXmlHandle hDoc(&doc); + TiXmlElement* pElem; + TiXmlHandle hRoot(0); + pElem = hDoc.FirstChildElement().Element(); + // save this for later + hRoot = TiXmlHandle(pElem); + pElem = hRoot.FirstChildElement("geometry").Element(); + // read geometry + mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); + // read origin + mitk::Point3D origin; + double temp = 0; + pElem->Attribute("origin_x", &temp); + origin[0] = temp; + pElem->Attribute("origin_y", &temp); + origin[1] = temp; + pElem->Attribute("origin_z", &temp); + origin[2] = temp; + geometry->SetOrigin(origin); + // read spacing + ScalarType spacing[3]; + pElem->Attribute("spacing_x", &temp); + spacing[0] = temp; + pElem->Attribute("spacing_y", &temp); + spacing[1] = temp; + pElem->Attribute("spacing_z", &temp); + spacing[2] = temp; + geometry->SetSpacing(spacing); + // read transform + vtkMatrix4x4* m = vtkMatrix4x4::New(); + pElem->Attribute("xx", &temp); + m->SetElement(0,0,temp); + pElem->Attribute("xy", &temp); + m->SetElement(1,0,temp); + pElem->Attribute("xz", &temp); + m->SetElement(2,0,temp); + pElem->Attribute("yx", &temp); + m->SetElement(0,1,temp); + pElem->Attribute("yy", &temp); + m->SetElement(1,1,temp); + pElem->Attribute("yz", &temp); + m->SetElement(2,1,temp); + pElem->Attribute("zx", &temp); + m->SetElement(0,2,temp); + pElem->Attribute("zy", &temp); + m->SetElement(1,2,temp); + pElem->Attribute("zz", &temp); + m->SetElement(2,2,temp); + m->SetElement(0,3,origin[0]); + m->SetElement(1,3,origin[1]); + m->SetElement(2,3,origin[2]); + m->SetElement(3,3,1); + geometry->SetIndexToWorldTransformByVtkMatrix(m); + // read bounds + float bounds[] = {0, 0, 0, 0, 0, 0}; + pElem->Attribute("size_x", &temp); + bounds[1] = temp; + pElem->Attribute("size_y", &temp); + bounds[3] = temp; + pElem->Attribute("size_z", &temp); + bounds[5] = temp; + geometry->SetFloatBounds(bounds); + geometry->SetImageGeometry(true); + pElem = hRoot.FirstChildElement("fiber_bundle").FirstChild().Element(); + for( ; pElem ; pElem=pElem->NextSiblingElement()) + { + TiXmlElement* pElem2 = pElem->FirstChildElement(); + vtkSmartPointer container = vtkSmartPointer::New(); + for( ; pElem2; pElem2=pElem2->NextSiblingElement()) { - TiXmlHandle hDoc(&doc); - TiXmlElement* pElem; - TiXmlHandle hRoot(0); - pElem = hDoc.FirstChildElement().Element(); - // save this for later - hRoot = TiXmlHandle(pElem); - pElem = hRoot.FirstChildElement("geometry").Element(); - // read geometry - mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); - // read origin - mitk::Point3D origin; - double temp = 0; - pElem->Attribute("origin_x", &temp); - origin[0] = temp; - pElem->Attribute("origin_y", &temp); - origin[1] = temp; - pElem->Attribute("origin_z", &temp); - origin[2] = temp; - geometry->SetOrigin(origin); - // read spacing - ScalarType spacing[3]; - pElem->Attribute("spacing_x", &temp); - spacing[0] = temp; - pElem->Attribute("spacing_y", &temp); - spacing[1] = temp; - pElem->Attribute("spacing_z", &temp); - spacing[2] = temp; - geometry->SetSpacing(spacing); - // read transform - vtkMatrix4x4* m = vtkMatrix4x4::New(); - pElem->Attribute("xx", &temp); - m->SetElement(0,0,temp); - pElem->Attribute("xy", &temp); - m->SetElement(1,0,temp); - pElem->Attribute("xz", &temp); - m->SetElement(2,0,temp); - pElem->Attribute("yx", &temp); - m->SetElement(0,1,temp); - pElem->Attribute("yy", &temp); - m->SetElement(1,1,temp); - pElem->Attribute("yz", &temp); - m->SetElement(2,1,temp); - pElem->Attribute("zx", &temp); - m->SetElement(0,2,temp); - pElem->Attribute("zy", &temp); - m->SetElement(1,2,temp); - pElem->Attribute("zz", &temp); - m->SetElement(2,2,temp); - m->SetElement(0,3,origin[0]); - m->SetElement(1,3,origin[1]); - m->SetElement(2,3,origin[2]); - m->SetElement(3,3,1); - geometry->SetIndexToWorldTransformByVtkMatrix(m); - // read bounds - float bounds[] = {0, 0, 0, 0, 0, 0}; - pElem->Attribute("size_x", &temp); - bounds[1] = temp; - pElem->Attribute("size_y", &temp); - bounds[3] = temp; - pElem->Attribute("size_z", &temp); - bounds[5] = temp; - geometry->SetFloatBounds(bounds); - geometry->SetImageGeometry(true); - pElem = hRoot.FirstChildElement("fiber_bundle").FirstChild().Element(); - for( ; pElem ; pElem=pElem->NextSiblingElement()) - { - TiXmlElement* pElem2 = pElem->FirstChildElement(); - vtkSmartPointer container = vtkSmartPointer::New(); - for( ; pElem2; pElem2=pElem2->NextSiblingElement()) - { - Point3D point; - pElem2->Attribute("pos_x", &temp); - point[0] = temp; - pElem2->Attribute("pos_y", &temp); - point[1] = temp; - pElem2->Attribute("pos_z", &temp); - point[2] = temp; - geometry->IndexToWorld(point, point); - vtkIdType id = points->InsertNextPoint(point.GetDataPointer()); - container->GetPointIds()->InsertNextId(id); - } - cellArray->InsertNextCell(container); - } - fiberPolyData->SetPoints(points); - fiberPolyData->SetLines(cellArray); - vtkSmartPointer cleaner = vtkSmartPointer::New(); - cleaner->SetInputData(fiberPolyData); - cleaner->Update(); - fiberPolyData = cleaner->GetOutput(); - FiberBundle::Pointer image = FiberBundle::New(fiberPolyData); - result.push_back(image.GetPointer()); - return result; - } - else - { - MITK_INFO << "File is not deprectaed XML format."; + Point3D point; + pElem2->Attribute("pos_x", &temp); + point[0] = temp; + pElem2->Attribute("pos_y", &temp); + point[1] = temp; + pElem2->Attribute("pos_z", &temp); + point[2] = temp; + geometry->IndexToWorld(point, point); + vtkIdType id = points->InsertNextPoint(point.GetDataPointer()); + container->GetPointIds()->InsertNextId(id); } - - setlocale(LC_ALL, currLocale.c_str()); - MITK_INFO << "Fiber bundle read"; + cellArray->InsertNextCell(container); + } + fiberPolyData->SetPoints(points); + fiberPolyData->SetLines(cellArray); + vtkSmartPointer cleaner = vtkSmartPointer::New(); + cleaner->SetInputData(fiberPolyData); + cleaner->Update(); + fiberPolyData = cleaner->GetOutput(); + FiberBundle::Pointer image = FiberBundle::New(fiberPolyData); + result.push_back(image.GetPointer()); + return result; } - catch(...) + else { - throw; + MITK_INFO << "File is not deprectaed XML format."; } - throw "Selected file is no vtk readable fiber format (binary or ascii vtk or vtp file)."; + setlocale(LC_ALL, currLocale.c_str()); + MITK_INFO << "Fiber bundle read"; + } + catch(...) + { + throw; + } + + throw "Selected file is no vtk readable fiber format (binary or ascii vtk or vtp file)."; - return result; + return result; } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberCurvatureFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberCurvatureFilter.h index a6b0c5cfa6..3101de522d 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberCurvatureFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberCurvatureFilter.h @@ -1,83 +1,83 @@ /*=================================================================== 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 itkFiberCurvatureFilter_h #define itkFiberCurvatureFilter_h // MITK #include #include #include // ITK #include // VTK #include #include #include #include #include using namespace std; namespace itk{ /** -* \brief Generates artificial fibers distributed in and interpolated between the input planar figures. */ +* \brief */ class FiberCurvatureFilter : public ProcessObject { public: typedef FiberCurvatureFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( FiberCurvatureFilter, ProcessObject ) virtual void Update() override{ this->GenerateData(); } itkSetMacro( Distance, double ) itkSetMacro( AngularDeviation, double ) itkSetMacro( RemoveFibers, bool ) itkSetMacro( InputFiberBundle, FiberBundle::Pointer ) itkGetMacro( OutputFiberBundle, FiberBundle::Pointer ) protected: void GenerateData() override; FiberCurvatureFilter(); virtual ~FiberCurvatureFilter(); FiberBundle::Pointer m_InputFiberBundle; FiberBundle::Pointer m_OutputFiberBundle; double m_AngularDeviation; double m_Distance; bool m_RemoveFibers; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkFiberCurvatureFilter.cpp" #endif #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp index d9a719ec3d..0e143d3a09 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp @@ -1,437 +1,459 @@ #include "itkFitFibersToImageFilter.h" #include namespace itk{ FitFibersToImageFilter::FitFibersToImageFilter() : m_PeakImage(nullptr) , m_MaskImage(nullptr) , m_FitIndividualFibers(true) , m_GradientTolerance(1e-5) , m_Lambda(0.1) , m_MaxIterations(20) , m_FiberSampling(10) , m_Coverage(0) , m_Overshoot(0) + , m_RMSE(0.0) , m_FilterOutliers(true) , m_MeanWeight(1.0) , m_MedianWeight(1.0) , m_MinWeight(1.0) , m_MaxWeight(1.0) , m_Verbose(true) , m_DeepCopy(true) + , m_ResampleFibers(true) , m_NumUnknowns(0) , m_NumResiduals(0) , m_NumCoveredDirections(0) { this->SetNumberOfRequiredOutputs(3); } FitFibersToImageFilter::~FitFibersToImageFilter() { } void FitFibersToImageFilter::GenerateData() { int sz_x = m_PeakImage->GetLargestPossibleRegion().GetSize(0); int sz_y = m_PeakImage->GetLargestPossibleRegion().GetSize(1); int sz_z = m_PeakImage->GetLargestPossibleRegion().GetSize(2); int sz_peaks = m_PeakImage->GetLargestPossibleRegion().GetSize(3)/3 + 1; // +1 for zero - peak int num_voxels = sz_x*sz_y*sz_z; float minSpacing = 1; if(m_PeakImage->GetSpacing()[0]GetSpacing()[1] && m_PeakImage->GetSpacing()[0]GetSpacing()[2]) minSpacing = m_PeakImage->GetSpacing()[0]; else if (m_PeakImage->GetSpacing()[1] < m_PeakImage->GetSpacing()[2]) minSpacing = m_PeakImage->GetSpacing()[1]; else minSpacing = m_PeakImage->GetSpacing()[2]; m_NumUnknowns = m_Tractograms.size(); if (m_FitIndividualFibers) { m_NumUnknowns = 0; for (unsigned int bundle=0; bundleGetNumFibers(); } - for (unsigned int bundle=0; bundleGetDeepCopy(); - m_Tractograms.at(bundle)->ResampleLinear(minSpacing/m_FiberSampling); - } + if (m_ResampleFibers) + for (unsigned int bundle=0; bundleGetDeepCopy(); + m_Tractograms.at(bundle)->ResampleLinear(minSpacing/m_FiberSampling); + std::cout.rdbuf (old); + } m_NumResiduals = num_voxels * sz_peaks; MITK_INFO << "Num. unknowns: " << m_NumUnknowns; MITK_INFO << "Num. residuals: " << m_NumResiduals; MITK_INFO << "Creating system ..."; vnl_sparse_matrix A; vnl_vector b; A.set_size(m_NumResiduals, m_NumUnknowns); b.set_size(m_NumResiduals); b.fill(0.0); double TD = 0; double FD = 0; m_NumCoveredDirections = 0; unsigned int fiber_count = 0; for (unsigned int bundle=0; bundle polydata = m_Tractograms.at(bundle)->GetFiberPolyData(); for (int i=0; iGetNumFibers(); ++i) { vtkCell* cell = polydata->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints<2) MITK_INFO << "FIBER WITH ONLY ONE POINT ENCOUNTERED!"; for (int j=0; jGetPoint(j); PointType4 p; p[0]=p1[0]; p[1]=p1[1]; p[2]=p1[2]; p[3]=0; itk::Index<4> idx4; m_PeakImage->TransformPhysicalPointToIndex(p, idx4); itk::Index<3> idx3; idx3[0] = idx4[0]; idx3[1] = idx4[1]; idx3[2] = idx4[2]; if (!m_PeakImage->GetLargestPossibleRegion().IsInside(idx4) || (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(idx3)==0)) continue; double* p2 = points->GetPoint(j+1); vnl_vector_fixed fiber_dir; fiber_dir[0] = p[0]-p2[0]; fiber_dir[1] = p[1]-p2[1]; fiber_dir[2] = p[2]-p2[2]; fiber_dir.normalize(); double w = 1; int peak_id = sz_peaks-1; vnl_vector_fixed odf_peak = GetClosestPeak(idx4, m_PeakImage, fiber_dir, peak_id, w); float peak_mag = odf_peak.magnitude(); int x = idx4[0]; int y = idx4[1]; int z = idx4[2]; unsigned int linear_index = x + sz_x*y + sz_x*sz_y*z + sz_x*sz_y*sz_z*peak_id; if (b[linear_index] == 0 && peak_id<3) { m_NumCoveredDirections++; FD += peak_mag; } TD += w; if (m_FitIndividualFibers) { b[linear_index] = peak_mag; A.put(linear_index, fiber_count, A.get(linear_index, fiber_count) + w); } else { b[linear_index] = peak_mag; A.put(linear_index, bundle, A.get(linear_index, bundle) + w); } } ++fiber_count; } } TD /= (m_NumCoveredDirections*fiber_count); FD /= m_NumCoveredDirections; A /= TD; b *= 100.0/FD; // times 100 because we want to avoid too small values for computational reasons double init_lambda = fiber_count; // initialization for lambda estimation itk::TimeProbe clock; clock.Start(); VnlCostFunction cost(m_NumUnknowns); cost.SetProblem(A, b, init_lambda); m_Weights.set_size(m_NumUnknowns); // m_Weights.fill( TD/100.0 * FD/2.0 ); m_Weights.fill( 0.0 ); vnl_lbfgsb minimizer(cost); vnl_vector l; l.set_size(m_NumUnknowns); l.fill(0); vnl_vector bound_selection; bound_selection.set_size(m_NumUnknowns); bound_selection.fill(1); minimizer.set_bound_selection(bound_selection); minimizer.set_lower_bound(l); minimizer.set_projected_gradient_tolerance(m_GradientTolerance); MITK_INFO << "Estimating regularization"; minimizer.set_trace(false); minimizer.set_max_function_evals(2); minimizer.minimize(m_Weights); vnl_vector dx; dx.set_size(m_NumUnknowns); dx.fill(0.0); cost.grad_regu_localMSE(m_Weights, dx); double r = dx.magnitude()/m_Weights.magnitude(); cost.m_Lambda *= m_Lambda*55.0/r; MITK_INFO << r << " - " << m_Lambda*55.0/r; if (cost.m_Lambda>10e7) { MITK_INFO << "Regularization estimation failed. Using default value."; cost.m_Lambda = fiber_count; } MITK_INFO << "Using regularization factor of " << cost.m_Lambda << " (λ: " << m_Lambda << ")"; MITK_INFO << "Fitting fibers"; minimizer.set_trace(m_Verbose); minimizer.set_max_function_evals(m_MaxIterations); minimizer.minimize(m_Weights); std::vector< double > weights; if (m_FilterOutliers) { for (auto w : m_Weights) weights.push_back(w); std::sort(weights.begin(), weights.end()); MITK_INFO << "Setting upper weight bound to " << weights.at(m_NumUnknowns*0.99); vnl_vector u; u.set_size(m_NumUnknowns); u.fill(weights.at(m_NumUnknowns*0.99)); minimizer.set_upper_bound(u); bound_selection.fill(2); minimizer.set_bound_selection(bound_selection); minimizer.minimize(m_Weights); weights.clear(); } for (auto w : m_Weights) weights.push_back(w); std::sort(weights.begin(), weights.end()); m_MeanWeight = m_Weights.mean(); m_MedianWeight = weights.at(m_NumUnknowns*0.5); m_MinWeight = weights.at(0); m_MaxWeight = weights.at(m_NumUnknowns-1); MITK_INFO << "*************************"; MITK_INFO << "Weight statistics"; MITK_INFO << "Mean: " << m_MeanWeight; MITK_INFO << "Median: " << m_MedianWeight; MITK_INFO << "75% quantile: " << weights.at(m_NumUnknowns*0.75); MITK_INFO << "95% quantile: " << weights.at(m_NumUnknowns*0.95); MITK_INFO << "99% quantile: " << weights.at(m_NumUnknowns*0.99); MITK_INFO << "Min: " << m_MinWeight; MITK_INFO << "Max: " << m_MaxWeight; MITK_INFO << "*************************"; MITK_INFO << "NumEvals: " << minimizer.get_num_evaluations(); MITK_INFO << "NumIterations: " << minimizer.get_num_iterations(); MITK_INFO << "Residual cost: " << minimizer.get_end_error(); - MITK_INFO << "Final RMS: " << cost.S->get_rms_error(m_Weights); + m_RMSE = cost.S->get_rms_error(m_Weights); + MITK_INFO << "Final RMS: " << m_RMSE; clock.Stop(); int h = clock.GetTotal()/3600; int m = ((int)clock.GetTotal()%3600)/60; int s = (int)clock.GetTotal()%60; MITK_INFO << "Optimization took " << h << "h, " << m << "m and " << s << "s"; - // transform back for peak image creation - A *= FD/100.0; - b *= FD/100.0; - MITK_INFO << "Weighting fibers"; + m_RmsDiffPerFiber.set_size(m_Weights.size()); + m_RmsDiffPerBundle.set_size(m_Tractograms.size()); + std::streambuf *old = cout.rdbuf(); // <-- save + std::stringstream ss; + std::cout.rdbuf (ss.rdbuf()); if (m_FitIndividualFibers) { unsigned int fiber_count = 0; for (unsigned int bundle=0; bundle temp_weights; + temp_weights.set_size(m_Weights.size()); + temp_weights.copy_in(m_Weights.data_block()); + for (int i=0; iGetNumFibers(); i++) { m_Tractograms.at(bundle)->SetFiberWeight(i, m_Weights[fiber_count]); + temp_weights[fiber_count] = 0; + ++fiber_count; } + double d_rms = cost.S->get_rms_error(temp_weights) - m_RMSE; + m_RmsDiffPerBundle[bundle] = d_rms; m_Tractograms.at(bundle)->Compress(0.1); m_Tractograms.at(bundle)->ColorFibersByFiberWeights(false, true); } } else { for (unsigned int i=0; iSetFiberWeights(m_Weights[i]); m_Tractograms.at(i)->Compress(0.1); m_Tractograms.at(i)->ColorFibersByFiberWeights(false, true); } } + std::cout.rdbuf (old); + + // transform back for peak image creation + A *= FD/100.0; + b *= FD/100.0; MITK_INFO << "Generating output images ..."; itk::ImageDuplicator< PeakImgType >::Pointer duplicator = itk::ImageDuplicator< PeakImgType >::New(); duplicator->SetInputImage(m_PeakImage); duplicator->Update(); m_UnderexplainedImage = duplicator->GetOutput(); m_UnderexplainedImage->FillBuffer(0.0); duplicator->SetInputImage(m_UnderexplainedImage); duplicator->Update(); m_OverexplainedImage = duplicator->GetOutput(); m_OverexplainedImage->FillBuffer(0.0); duplicator->SetInputImage(m_OverexplainedImage); duplicator->Update(); m_ResidualImage = duplicator->GetOutput(); m_ResidualImage->FillBuffer(0.0); duplicator->SetInputImage(m_ResidualImage); duplicator->Update(); m_FittedImage = duplicator->GetOutput(); m_FittedImage->FillBuffer(0.0); vnl_vector fitted_b; fitted_b.set_size(b.size()); cost.S->multiply(m_Weights, fitted_b); for (unsigned int r=0; r idx4; unsigned int linear_index = r; idx4[0] = linear_index % sz_x; linear_index /= sz_x; idx4[1] = linear_index % sz_y; linear_index /= sz_y; idx4[2] = linear_index % sz_z; linear_index /= sz_z; int peak_id = linear_index % sz_peaks; if (peak_id peak_dir; idx4[3] = peak_id*3; peak_dir[0] = m_PeakImage->GetPixel(idx4); idx4[3] += 1; peak_dir[1] = m_PeakImage->GetPixel(idx4); idx4[3] += 1; peak_dir[2] = m_PeakImage->GetPixel(idx4); peak_dir.normalize(); peak_dir *= fitted_b[r]; idx4[3] = peak_id*3; m_FittedImage->SetPixel(idx4, peak_dir[0]); idx4[3] += 1; m_FittedImage->SetPixel(idx4, peak_dir[1]); idx4[3] += 1; m_FittedImage->SetPixel(idx4, peak_dir[2]); } } FD = 0; m_Coverage = 0; m_Overshoot = 0; itk::Index<4> idx4; for (idx4[0]=0; idx4[0] idx3; idx3[0] = idx4[0]; idx3[1] = idx4[1]; idx3[2] = idx4[2]; if (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(idx3)==0) continue; vnl_vector_fixed peak_dir; vnl_vector_fixed fitted_dir; vnl_vector_fixed overshoot_dir; for (idx4[3]=0; idx4[3]<(itk::IndexValueType)m_PeakImage->GetLargestPossibleRegion().GetSize(3); ++idx4[3]) { peak_dir[idx4[3]%3] = m_PeakImage->GetPixel(idx4); fitted_dir[idx4[3]%3] = m_FittedImage->GetPixel(idx4); m_ResidualImage->SetPixel(idx4, m_PeakImage->GetPixel(idx4) - m_FittedImage->GetPixel(idx4)); if (idx4[3]%3==2) { FD += peak_dir.magnitude(); itk::Index<4> tidx= idx4; if (peak_dir.magnitude()>fitted_dir.magnitude()) { m_Coverage += fitted_dir.magnitude(); m_UnderexplainedImage->SetPixel(tidx, peak_dir[2]-fitted_dir[2]); tidx[3]--; m_UnderexplainedImage->SetPixel(tidx, peak_dir[1]-fitted_dir[1]); tidx[3]--; m_UnderexplainedImage->SetPixel(tidx, peak_dir[0]-fitted_dir[0]); } else { overshoot_dir[0] = fitted_dir[0]-peak_dir[0]; overshoot_dir[1] = fitted_dir[1]-peak_dir[1]; overshoot_dir[2] = fitted_dir[2]-peak_dir[2]; m_Coverage += peak_dir.magnitude(); m_Overshoot += overshoot_dir.magnitude(); m_OverexplainedImage->SetPixel(tidx, overshoot_dir[2]); tidx[3]--; m_OverexplainedImage->SetPixel(tidx, overshoot_dir[1]); tidx[3]--; m_OverexplainedImage->SetPixel(tidx, overshoot_dir[0]); } } } } m_Coverage = m_Coverage/FD; m_Overshoot = m_Overshoot/FD; - MITK_INFO << std::fixed << "Coverage: " << setprecision(1) << 100.0*m_Coverage << "%"; - MITK_INFO << std::fixed << "Overshoot: " << setprecision(1) << 100.0*m_Overshoot << "%"; + MITK_INFO << std::fixed << "Coverage: " << setprecision(2) << 100.0*m_Coverage << "%"; + MITK_INFO << std::fixed << "Overshoot: " << setprecision(2) << 100.0*m_Overshoot << "%"; } vnl_vector_fixed FitFibersToImageFilter::GetClosestPeak(itk::Index<4> idx, PeakImgType::Pointer peak_image , vnl_vector_fixed fiber_dir, int& id, double& w ) { int m_NumDirs = peak_image->GetLargestPossibleRegion().GetSize()[3]/3; vnl_vector_fixed out_dir; out_dir.fill(0); - float angle = 0.8; + float angle = 0.9; for (int i=0; i dir; idx[3] = i*3; dir[0] = peak_image->GetPixel(idx); idx[3] += 1; dir[1] = peak_image->GetPixel(idx); idx[3] += 1; dir[2] = peak_image->GetPixel(idx); float mag = dir.magnitude(); if (magangle) { angle = fabs(a); w = angle; if (a<0) out_dir = -dir; else out_dir = dir; out_dir *= mag; id = i; } } return out_dir; } std::vector FitFibersToImageFilter::GetTractograms() const { return m_Tractograms; } void FitFibersToImageFilter::SetTractograms(const std::vector &tractograms) { m_Tractograms = tractograms; } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h index 119d39e57d..5907d9e874 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h @@ -1,262 +1,271 @@ #ifndef __itkFitFibersToImageFilter_h__ #define __itkFitFibersToImageFilter_h__ // MITK #include #include #include #include #include #include #include #include #include namespace itk{ /** * \brief Fits the tractogram to the input peak image by assigning a weight to each fiber (similar to https://doi.org/10.1016/j.neuroimage.2015.06.092). */ class FitFibersToImageFilter : public ImageSource< mitk::PeakImage::ItkPeakImageType > { public: typedef FitFibersToImageFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef itk::Point PointType4; typedef mitk::PeakImage::ItkPeakImageType PeakImgType; typedef itk::Image UcharImgType; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( FitFibersToImageFilter, ImageSource ) itkSetMacro( PeakImage, PeakImgType::Pointer) itkGetMacro( PeakImage, PeakImgType::Pointer) itkSetMacro( MaskImage, UcharImgType::Pointer) itkGetMacro( MaskImage, UcharImgType::Pointer) itkSetMacro( FitIndividualFibers, bool) itkGetMacro( FitIndividualFibers, bool) itkSetMacro( GradientTolerance, double) itkGetMacro( GradientTolerance, double) itkSetMacro( Lambda, double) itkGetMacro( Lambda, double) itkSetMacro( MaxIterations, int) itkGetMacro( MaxIterations, int) itkSetMacro( FiberSampling, float) itkGetMacro( FiberSampling, float) itkSetMacro( FilterOutliers, bool) itkGetMacro( FilterOutliers, bool) itkSetMacro( Verbose, bool) itkGetMacro( Verbose, bool) itkSetMacro( DeepCopy, bool) itkGetMacro( DeepCopy, bool) + itkSetMacro( ResampleFibers, bool) + itkGetMacro( ResampleFibers, bool) itkGetMacro( Weights, vnl_vector) + itkGetMacro( RmsDiffPerBundle, vnl_vector) + itkGetMacro( RmsDiffPerFiber, vnl_vector) itkGetMacro( FittedImage, PeakImgType::Pointer) itkGetMacro( ResidualImage, PeakImgType::Pointer) itkGetMacro( OverexplainedImage, PeakImgType::Pointer) itkGetMacro( UnderexplainedImage, PeakImgType::Pointer) itkGetMacro( Coverage, double) itkGetMacro( Overshoot, double) + itkGetMacro( RMSE, double) itkGetMacro( MeanWeight, double) itkGetMacro( MedianWeight, double) itkGetMacro( MinWeight, double) itkGetMacro( MaxWeight, double) itkGetMacro( NumUnknowns, unsigned int) itkGetMacro( NumResiduals, unsigned int) itkGetMacro( NumCoveredDirections, unsigned int) void SetTractograms(const std::vector &tractograms); void GenerateData() override; std::vector GetTractograms() const; protected: FitFibersToImageFilter(); virtual ~FitFibersToImageFilter(); vnl_vector_fixed GetClosestPeak(itk::Index<4> idx, PeakImgType::Pointer m_PeakImage , vnl_vector_fixed fiber_dir, int& id, double& w ); std::vector< mitk::FiberBundle::Pointer > m_Tractograms; PeakImgType::Pointer m_PeakImage; UcharImgType::Pointer m_MaskImage; bool m_FitIndividualFibers; double m_GradientTolerance; double m_Lambda; int m_MaxIterations; float m_FiberSampling; double m_Coverage; double m_Overshoot; + double m_RMSE; bool m_FilterOutliers; double m_MeanWeight; double m_MedianWeight; double m_MinWeight; double m_MaxWeight; bool m_Verbose; bool m_DeepCopy; + bool m_ResampleFibers; unsigned int m_NumUnknowns; unsigned int m_NumResiduals; unsigned int m_NumCoveredDirections; // output + vnl_vector m_RmsDiffPerBundle; vnl_vector m_Weights; + vnl_vector m_RmsDiffPerFiber; PeakImgType::Pointer m_UnderexplainedImage; PeakImgType::Pointer m_OverexplainedImage; PeakImgType::Pointer m_ResidualImage; PeakImgType::Pointer m_FittedImage; }; } class VnlCostFunction : public vnl_cost_function { public: vnl_sparse_matrix_linear_system< double >* S; vnl_sparse_matrix< double > m_A; vnl_sparse_matrix< double > m_A_Ones; // matrix indicating active weights with 1 vnl_vector< double > m_b; double m_Lambda; // regularization factor vnl_vector row_sums; // number of active weights per row vnl_vector local_weight_means; // mean weight of each row void SetProblem(vnl_sparse_matrix< double >& A, vnl_vector& b, double lambda) { S = new vnl_sparse_matrix_linear_system(A, b); m_A = A; m_b = b; m_Lambda = lambda; m_A_Ones.set_size(m_A.rows(), m_A.cols()); m_A.reset(); while (m_A.next()) m_A_Ones.put(m_A.getrow(), m_A.getcolumn(), 1); unsigned int N = m_b.size(); vnl_vector ones; ones.set_size(dim); ones.fill(1.0); row_sums.set_size(N); m_A_Ones.mult(ones, row_sums); local_weight_means.set_size(N); } VnlCostFunction(const int NumVars) : vnl_cost_function(NumVars) { } void regu_MSE(vnl_vector const &x, double& cost) { double mean = x.mean(); vnl_vector tx = x-mean; cost += m_Lambda*1e8*tx.squared_magnitude()/x.size(); } void regu_MSM(vnl_vector const &x, double& cost) { cost += m_Lambda*1e8*x.squared_magnitude()/x.size(); } void regu_localMSE(vnl_vector const &x, double& cost) { m_A_Ones.mult(x, local_weight_means); local_weight_means = element_quotient(local_weight_means, row_sums); m_A_Ones.reset(); double regu = 0; while (m_A_Ones.next()) { double d = 0; if (x[m_A_Ones.getcolumn()]>local_weight_means[m_A_Ones.getrow()]) d = std::exp(x[m_A_Ones.getcolumn()]) - std::exp(local_weight_means[m_A_Ones.getrow()]); else d = x[m_A_Ones.getcolumn()] - local_weight_means[m_A_Ones.getrow()]; regu += d*d; } cost += m_Lambda*regu/dim; } void grad_regu_MSE(vnl_vector const &x, vnl_vector &dx) { double mean = x.mean(); vnl_vector tx = x-mean; vnl_vector tx2(dim, 0.0); vnl_vector h(dim, 1.0); for (int c=0; c const &x, vnl_vector &dx) { dx += m_Lambda*1e8*2.0*x/dim; } void grad_regu_localMSE(vnl_vector const &x, vnl_vector &dx) { m_A_Ones.mult(x, local_weight_means); local_weight_means = element_quotient(local_weight_means, row_sums); vnl_vector exp_x = x.apply(std::exp); vnl_vector exp_means = local_weight_means.apply(std::exp); vnl_vector tdx(dim, 0); m_A_Ones.reset(); while (m_A_Ones.next()) { int c = m_A_Ones.getcolumn(); int r = m_A_Ones.getrow(); if (x[c]>local_weight_means[r]) tdx[c] += exp_x[c] * ( exp_x[c] - exp_means[r] ); else tdx[c] += x[c] - local_weight_means[r]; } dx += tdx*2.0*m_Lambda/dim; } double f(vnl_vector const &x) { double cost = S->get_rms_error(x); cost *= cost; regu_localMSE(x, cost); return cost; } void gradf(vnl_vector const &x, vnl_vector &dx) { dx.fill(0.0); unsigned int N = m_b.size(); vnl_vector d; d.set_size(N); S->multiply(x,d); d -= m_b; S->transpose_multiply(d, dx); dx *= 2.0/N; grad_regu_localMSE(x,dx); } }; #ifndef ITK_MANUAL_INSTANTIATION #include "itkFitFibersToImageFilter.cpp" #endif #endif // __itkFitFibersToImageFilter_h__ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp index 43076fa0b3..4aa60074cd 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp @@ -1,251 +1,273 @@ /*=================================================================== 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_UpsamplingFactor(1) - , m_InvertImage(false) - , m_BinaryOutput(false) - , m_UseImageGeometry(false) - , m_OutputAbsoluteValues(false) - , m_UseTrilinearInterpolation(false) - , m_DoFiberResampling(true) - , m_WorkOnFiberCopy(true) - , m_MaxDensity(0) + : m_UpsamplingFactor(1) + , m_InvertImage(false) + , m_BinaryOutput(false) + , m_UseImageGeometry(false) + , m_OutputAbsoluteValues(false) + , m_UseTrilinearInterpolation(false) + , m_DoFiberResampling(true) + , m_WorkOnFiberCopy(true) + , m_MaxDensity(0) + , m_NumCoveredVoxels(0) { } 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; + 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()) + // 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->ResampleLinear(minSpacing/10); + } + + MITK_INFO << "TractDensityImageFilter: starting image generation"; + + vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); + + int numFibers = m_FiberBundle->GetNumFibers(); + boost::progress_display disp(numFibers); + for( int i=0; iGetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + + float weight = m_FiberBundle->GetFiberWeight(i); + + // fill output image + for( int j=0; jGetSpacing()/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(); + itk::Point vertex = GetItkPoint(points->GetPoint(j)); + itk::Index<3> index; + itk::ContinuousIndex contIndex; + outImage->TransformPhysicalPointToIndex(vertex, index); + outImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex); + + if (!m_UseTrilinearInterpolation && outImage->GetLargestPossibleRegion().IsInside(index)) + { + if (outImage->GetPixel(index)==0) + m_NumCoveredVoxels++; + + if (m_BinaryOutput) + outImage->SetPixel(index, 1); + else + outImage->SetPixel(index, outImage->GetPixel(index)+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 (outImageBufferPointer[( index[0] + w*(index[1] + h*index[2] ))]==0) + m_NumCoveredVoxels++; + if (outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2] ))]==0) + m_NumCoveredVoxels++; + if (outImageBufferPointer[( index[0] + w*(index[1] + h*index[2]+h))]==0) + m_NumCoveredVoxels++; + if (outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2]+h))]==0) + m_NumCoveredVoxels++; + if (outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2] ))]==0) + m_NumCoveredVoxels++; + if (outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2]+h))]==0) + m_NumCoveredVoxels++; + if (outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2] ))]==0) + m_NumCoveredVoxels++; + if (outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))]==0) + m_NumCoveredVoxels++; + + 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); + } } - 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->ResampleLinear(minSpacing/10); - } - - MITK_INFO << "TractDensityImageFilter: starting image generation"; - - vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); - - int numFibers = m_FiberBundle->GetNumFibers(); - boost::progress_display disp(numFibers); - for( int i=0; iGetCell(i); - int numPoints = cell->GetNumberOfPoints(); - vtkPoints* points = cell->GetPoints(); - - float weight = m_FiberBundle->GetFiberWeight(i); - - // fill output image - for( int j=0; j vertex = GetItkPoint(points->GetPoint(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)+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); - } - } - } - - m_MaxDensity = 0; + } + + m_MaxDensity = 0; + for (int i=0; i0) + 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 ) itkGetMacro( MaxDensity, OutPixelType) + itkGetMacro( NumCoveredVoxels, unsigned int) 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 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; OutPixelType m_MaxDensity; + unsigned int m_NumCoveredVoxels; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkTractDensityImageFilter.cpp" #endif #endif // __itkTractDensityImageFilter_h__ diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp index d33bf2cf32..fedc54a446 100755 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp @@ -1,2335 +1,2588 @@ /*=================================================================== 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 #include +#include const char* mitk::FiberBundle::FIBER_ID_ARRAY = "Fiber_IDs"; using namespace std; mitk::FiberBundle::FiberBundle( vtkPolyData* fiberPolyData ) : m_NumFibers(0) { m_FiberWeights = vtkSmartPointer::New(); m_FiberWeights->SetName("FIBER_WEIGHTS"); m_FiberPolyData = vtkSmartPointer::New(); if (fiberPolyData != nullptr) m_FiberPolyData = fiberPolyData; + else + { + this->m_FiberPolyData->SetPoints(vtkSmartPointer::New()); + this->m_FiberPolyData->SetLines(vtkSmartPointer::New()); + } this->UpdateFiberGeometry(); this->GenerateFiberIds(); this->ColorFibersByOrientation(); } 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 mitk::FiberBundle::GeneratePolyDataByIds(std::vector fiberIds, vtkSmartPointer weights) { vtkSmartPointer newFiberPolyData = vtkSmartPointer::New(); vtkSmartPointer newLineSet = vtkSmartPointer::New(); vtkSmartPointer newPointSet = vtkSmartPointer::New(); + weights->SetNumberOfValues(fiberIds.size()); + int counter = 0; 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]); } + weights->InsertValue(counter, this->GetFiberWeight(*finIt)); newLineSet->InsertNextCell(newFiber); ++finIt; + ++counter; } newFiberPolyData->SetPoints(newPointSet); newFiberPolyData->SetLines(newLineSet); return newFiberPolyData; } // merge two fiber bundles -mitk::FiberBundle::Pointer mitk::FiberBundle::AddBundle(mitk::FiberBundle* fib) +mitk::FiberBundle::Pointer mitk::FiberBundle::AddBundles(std::vector< mitk::FiberBundle::Pointer > fibs) { - if (fib==nullptr) + vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); + vtkSmartPointer vNewLines = vtkSmartPointer::New(); + vtkSmartPointer vNewPoints = vtkSmartPointer::New(); + + // add current fiber bundle + vtkSmartPointer weights = vtkSmartPointer::New(); + + int num_weights = this->GetNumFibers(); + for (auto fib : fibs) + num_weights += fib->GetNumFibers(); + weights->SetNumberOfValues(num_weights); + + unsigned int counter = 0; + for (int i=0; iGetNumberOfCells(); i++) { - MITK_WARN << "trying to call AddBundle with nullptr argument"; - return nullptr; + 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++; } + + for (auto fib : fibs) + { + // 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; +} + +// merge two fiber bundles +mitk::FiberBundle::Pointer mitk::FiberBundle::AddBundle(mitk::FiberBundle* fib) +{ + if (fib==nullptr) + return this->GetDeepCopy(); + 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; } +// Only retain fibers with a weight larger than the specified threshold +mitk::FiberBundle::Pointer mitk::FiberBundle::FilterByWeights(float weight_thr, bool invert) +{ + vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); + vtkSmartPointer vNewLines = vtkSmartPointer::New(); + vtkSmartPointer vNewPoints = vtkSmartPointer::New(); + + std::vector weights; + + for (int i=0; iGetNumFibers(); i++) + { + if ( (invert && this->GetFiberWeight(i)>weight_thr) || (!invert && this->GetFiberWeight(i)<=weight_thr)) + continue; + + 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); + } + vNewLines->InsertNextCell(container); + weights.push_back(this->GetFiberWeight(i)); + } + + // initialize PolyData + vNewPolyData->SetPoints(vNewPoints); + vNewPolyData->SetLines(vNewLines); + + // initialize fiber bundle + mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); + for (unsigned int i=0; iSetFiberWeight(i, weights.at(i)); + return newFib; +} + +// Only retain a subsample of the fibers +mitk::FiberBundle::Pointer mitk::FiberBundle::SubsampleFibers(float factor) +{ + vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); + vtkSmartPointer vNewLines = vtkSmartPointer::New(); + vtkSmartPointer vNewPoints = vtkSmartPointer::New(); + + int new_num_fibs = this->GetNumFibers()*factor; + MITK_INFO << "Subsampling fibers with factor " << factor << "(" << new_num_fibs << "/" << this->GetNumFibers() << ")"; + + // add current fiber bundle + vtkSmartPointer weights = vtkSmartPointer::New(); + weights->SetNumberOfValues(new_num_fibs); + + std::vector< int > ids; + for (int i=0; iGetNumFibers(); i++) + ids.push_back(i); + std::random_shuffle(ids.begin(), ids.end()); + + unsigned int counter = 0; + for (int i=0; iGetCell(ids.at(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(ids.at(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"; + if (fib==nullptr) + return this->GetDeepCopy(); + MITK_INFO << "Subtracting fibers"; vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); 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; itk::Point 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; +// int progress = 0; std::vector< int > ids; #pragma omp parallel for for (int i=0; i<(int)points1.size(); i++) { -#pragma omp critical - { - progress++; - std::cout << (int)(100*(float)progress/points1.size()) << "%" << '\r'; - cout.flush(); - } +//#pragma omp critical +// { +// progress++; +// std::cout << (int)(100*(float)progress/points1.size()) << "%" << '\r'; +// cout.flush(); +// } bool match = false; for (unsigned int j=0; jGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (points==nullptr || numPoints<=0) continue; vtkSmartPointer container = vtkSmartPointer::New(); for( int j=0; jInsertNextPoint(points->GetPoint(j)); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } if(vNewLines->GetNumberOfCells()==0) - return nullptr; + return mitk::FiberBundle::New(); // 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); m_NumFibers = m_FiberPolyData->GetNumberOfLines(); if (updateGeometry) UpdateFiberGeometry(); GenerateFiberIds(); ColorFibersByOrientation(); } /* * 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->InsertTypedTuple(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, bool normalize) { 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; j1) dev = 1; lookupTable->GetColor(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->InsertTypedTuple(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, bool normalize) { mitkPixelTypeMultiplex3( ColorFibersByScalarMap, FAimage->GetPixelType(), FAimage, opacity, normalize ); m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } template void mitk::FiberBundle::ColorFibersByScalarMap(const mitk::PixelType, mitk::Image::Pointer image, bool opacity, bool normalize) { 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); double min = 9999999; double max = -9999999; 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); if (pixelValue>max) max = pixelValue; if (pixelValueGetNumberOfPoints(); ++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); if (normalize) pixelValue = (pixelValue-min)/(max-min); else if (pixelValue>1) pixelValue = 1; 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->InsertTypedTuple(i, rgba); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByFiberWeights(bool opacity, bool normalize) { m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); m_FiberColors->SetNumberOfComponents(4); 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); unsigned char rgba[4] = {0,0,0,0}; unsigned int counter = 0; float max = -999999; float min = 999999; for (int i=0; iGetFiberWeight(i); if (weight>max) max = weight; if (weightGetCell(i); int numPoints = cell->GetNumberOfPoints(); double weight = this->GetFiberWeight(i); for (int j=0; j1) v = 1; double color[3]; lookupTable->GetColor(1-v, 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 * v); else rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTypedTuple(counter, rgba); counter++; } } 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->InsertTypedTuple(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(); } +float mitk::FiberBundle::GetOverlap(ItkUcharImgType* mask, bool do_resampling) +{ + vtkSmartPointer PolyData = m_FiberPolyData; + mitk::FiberBundle::Pointer fibCopy = this; + if (do_resampling) + { + 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]; + + fibCopy = this->GetDeepCopy(); + fibCopy->ResampleLinear(minSpacing/5); + PolyData = fibCopy->GetFiberPolyData(); + } + + MITK_INFO << "Calculating overlap"; + int inside = 0; + int outside = 0; + 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); + 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->GetLargestPossibleRegion().IsInside(idx) && mask->GetPixel(idx) != 0 ) + inside++; + else + outside++; + } + } + + if (inside+outside==0) + outside = 1; + return (float)inside/(inside+outside); +} + mitk::FiberBundle::Pointer mitk::FiberBundle::ExtractFiberSubset(ItkUcharImgType* mask, bool anyPoint, bool invert, bool bothEnds, float fraction, bool do_resampling) { + if (m_NumFibers==0 || mask==nullptr) + return mitk::FiberBundle::New(nullptr); + vtkSmartPointer PolyData = m_FiberPolyData; mitk::FiberBundle::Pointer fibCopy = this; if (anyPoint && do_resampling) { 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]; fibCopy = this->GetDeepCopy(); fibCopy->ResampleLinear(minSpacing/5); PolyData = fibCopy->GetFiberPolyData(); } vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); std::vector< float > new_weights; MITK_INFO << "Extracting fibers with mask image"; 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->GetLargestPossibleRegion().IsInside(idx) && mask->GetPixel(idx) != 0 ) { 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); 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); } } } } } if (container->GetNumberOfPoints()>0) { new_weights.push_back(fibCopy->GetFiberWeight(i)); vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()<=0) - return nullptr; + return mitk::FiberBundle::New(nullptr); vtkSmartPointer newPolyData = vtkSmartPointer::New(); newPolyData->SetPoints(vtkNewPoints); newPolyData->SetLines(vtkNewCells); + mitk::FiberBundle::Pointer newfib = mitk::FiberBundle::New(newPolyData); for (unsigned int i=0; iSetFiberWeight(i, new_weights.at(i)); return newfib; } 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->ResampleLinear(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); + vtkSmartPointer weights = vtkSmartPointer::New(); + vtkSmartPointer pTmp = GeneratePolyDataByIds(tmp, weights); + mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(pTmp); + fib->SetFiberWeights(weights); + return fib; } 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 (unsigned int 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->GetNumberOfValues()!=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) const { return m_FiberWeights->GetValue(fiber); } void mitk::FiberBundle::SetFiberWeights(float newWeight) { for (int i=0; iGetNumberOfValues(); i++) m_FiberWeights->SetValue(i, newWeight); } void mitk::FiberBundle::SetFiberWeights(vtkSmartPointer weights) { if (m_NumFibers!=weights->GetNumberOfValues()) { MITK_INFO << "Weights array not equal to number of fibers! " << weights->GetNumberOfValues() << " vs " << m_NumFibers; return; } for (int i=0; iGetNumberOfValues(); 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->GetTypedTuple(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->InsertTypedTuple(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"; vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); boost::progress_display disp(m_NumFibers); #pragma omp parallel for for (int i=0; i newPoints = vtkSmartPointer::New(); float length = 0; float weight = 1; #pragma omp critical { length = m_FiberLengths.at(i); weight = m_FiberWeights->GetValue(i); ++disp; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jInsertNextPoint(points->GetPoint(j)); } 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()); #pragma omp critical { for (int j=0; jGetNumberOfPoints(); j++) { smoothLine->GetPointIds()->SetId(j, j+pointHelperCnt); vtkSmoothPoints->InsertNextPoint(tmpSmoothPnts->GetPoint(j)); } newFiberWeights->SetValue(vtkSmoothCells->GetNumberOfCells(), weight); vtkSmoothCells->InsertNextCell(smoothLine); pointHelperCnt += tmpSmoothPnts->GetNumberOfPoints(); } } SetFiberWeights(newFiberWeights); m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkSmoothPoints); m_FiberPolyData->SetLines(vtkSmoothCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::ResampleSpline(float pointDistance) { ResampleSpline(pointDistance, 0, 0, 0 ); } unsigned long mitk::FiberBundle::GetNumberOfPoints() const { 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()); vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); #pragma omp parallel for for (int i=0; iGetNumberOfCells(); i++) { std::vector< vnl_vector_fixed< double, 3 > > vertices; float weight = 1; #pragma omp critical { ++disp; weight = m_FiberWeights->GetValue(i); 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 (unsigned int j=0; j 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) { pred = vertices.at(k); validP = k; break; } int validS = -1; vnl_vector_fixed< double, 3 > succ; for (int k=j+1; k=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 (hcInsertNextPoint(vertices.at(j).data_block()); container->GetPointIds()->InsertNextId(id); } } } #pragma omp critical { newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), weight); numRemovedPoints += remCounter; vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()>0) { MITK_INFO << "Removed points: " << numRemovedPoints; SetFiberWeights(newFiberWeights); m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } } void mitk::FiberBundle::ResampleLinear(double pointDistance) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Resampling fibers (linear)"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); #pragma omp parallel for for (int i=0; iGetNumberOfCells(); i++) { std::vector< vnl_vector_fixed< double, 3 > > vertices; float weight = 1; #pragma omp critical { ++disp; weight = m_FiberWeights->GetValue(i); 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); } } vtkSmartPointer container = vtkSmartPointer::New(); vnl_vector_fixed< double, 3 > lastV = vertices.at(0); #pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(lastV.data_block()); container->GetPointIds()->InsertNextId(id); } for (unsigned int j=1; j vec = vertices.at(j) - lastV; double new_dist = vec.magnitude(); if (new_dist >= pointDistance) { vnl_vector_fixed< double, 3 > newV = lastV; if ( new_dist-pointDistance <= mitk::eps ) { vec.normalize(); newV += vec * pointDistance; } else { // intersection between sphere (radius 'pointDistance', center 'lastV') and line (direction 'd' and point 'p') vnl_vector_fixed< double, 3 > p = vertices.at(j-1); vnl_vector_fixed< double, 3 > d = vertices.at(j) - p; double a = d[0]*d[0] + d[1]*d[1] + d[2]*d[2]; double b = 2 * (d[0] * (p[0] - lastV[0]) + d[1] * (p[1] - lastV[1]) + d[2] * (p[2] - lastV[2])); double c = (p[0] - lastV[0])*(p[0] - lastV[0]) + (p[1] - lastV[1])*(p[1] - lastV[1]) + (p[2] - lastV[2])*(p[2] - lastV[2]) - pointDistance*pointDistance; double v1 =(-b + std::sqrt(b*b-4*a*c))/(2*a); double v2 =(-b - std::sqrt(b*b-4*a*c))/(2*a); if (v1>0) newV = p + d * v1; else if (v2>0) newV = p + d * v2; else MITK_INFO << "ERROR1 - linear resampling"; j--; } #pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(newV.data_block()); container->GetPointIds()->InsertNextId(id); } lastV = newV; } else if (j==vertices.size()-1 && new_dist>0.0001) { #pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(vertices.at(j).data_block()); container->GetPointIds()->InsertNextId(id); } } } #pragma omp critical { newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), weight); vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()>0) { SetFiberWeights(newFiberWeights); 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 nullptr!"; 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; } void mitk::FiberBundle::PrintSelf(std::ostream &os, itk::Indent indent) const { os << indent << this->GetNameOfClass() << ":\n"; os << indent << "Number of fibers: " << this->GetNumFibers() << std::endl; os << indent << "Min. fiber length: " << this->GetMinFiberLength() << std::endl; os << indent << "Max. fiber length: " << this->GetMaxFiberLength() << std::endl; os << indent << "Mean fiber length: " << this->GetMeanFiberLength() << std::endl; os << indent << "Median fiber length: " << this->GetMedianFiberLength() << std::endl; os << indent << "STDEV fiber length: " << this->GetLengthStDev() << std::endl; os << indent << "Number of points: " << this->GetNumberOfPoints() << std::endl; Superclass::PrintSelf(os, indent); } /* 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 a49a44e2dd..863c50b64d 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h @@ -1,179 +1,179 @@ /*=================================================================== 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 ColorFibersByFiberWeights(bool opacity, bool normalize); void ColorFibersByCurvature(bool opacity, bool normalize); void ColorFibersByScalarMap(mitk::Image::Pointer, bool opacity, bool normalize); template void ColorFibersByScalarMap(const mitk::PixelType pixelType, mitk::Image::Pointer, bool opacity, bool normalize); 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 ); void ResampleLinear(double pointDistance=1); + mitk::FiberBundle::Pointer FilterByWeights(float weight_thr, bool invert=false); 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); + mitk::FiberBundle::Pointer AddBundles(std::vector< mitk::FiberBundle::Pointer > fibs); 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, float fraction=0.0, bool do_resampling=true); FiberBundle::Pointer RemoveFibersOutside(ItkUcharImgType* mask, bool invert=false); - - vtkSmartPointer GeneratePolyDataByIds( std::vector ); // TODO: make protected - void GenerateFiberIds(); // TODO: make protected + float GetOverlap(ItkUcharImgType* mask, bool do_resampling); + mitk::FiberBundle::Pointer SubsampleFibers(float factor); // get/set data vtkSmartPointer GetFiberWeights() const { return m_FiberWeights; } float GetFiberWeight(unsigned int fiber) const; void SetFiberWeights(float newWeight); void SetFiberWeight(unsigned int fiber, float weight); void SetFiberWeights(vtkSmartPointer weights); void SetFiberPolyData(vtkSmartPointer, bool updateGeometry = true); vtkSmartPointer GetFiberPolyData() const; itkGetConstMacro( NumFibers, int) //itkGetMacro( FiberSampling, int) itkGetConstMacro( MinFiberLength, float ) itkGetConstMacro( MaxFiberLength, float ) itkGetConstMacro( MeanFiberLength, float ) itkGetConstMacro( MedianFiberLength, float ) itkGetConstMacro( LengthStDev, float ) itkGetConstMacro( UpdateTime2D, itk::TimeStamp ) itkGetConstMacro( UpdateTime3D, itk::TimeStamp ) void RequestUpdate2D(){ m_UpdateTime2D.Modified(); } void RequestUpdate3D(){ m_UpdateTime3D.Modified(); } void RequestUpdate(){ m_UpdateTime2D.Modified(); m_UpdateTime3D.Modified(); } unsigned long GetNumberOfPoints() const; // copy fiber bundle mitk::FiberBundle::Pointer GetDeepCopy(); // compare fiber bundles bool Equals(FiberBundle* fib, double eps=0.01); 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(); - - virtual void PrintSelf(std::ostream &os, itk::Indent indent) const override; + vtkSmartPointer GeneratePolyDataByIds(std::vector fiberIds, vtkSmartPointer weights); + void GenerateFiberIds(); + itk::Point GetItkPoint(double point[3]); + void UpdateFiberGeometry(); + virtual void PrintSelf(std::ostream &os, itk::Indent indent) const override; 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; 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/IODataStructures/FiberBundle/mitkTrackvis.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkTrackvis.cpp index e501575e58..ce5b004615 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkTrackvis.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkTrackvis.cpp @@ -1,240 +1,241 @@ #include #include TrackVisFiberReader::TrackVisFiberReader() { m_Filename = ""; m_FilePointer = nullptr; } TrackVisFiberReader::~TrackVisFiberReader() { if (m_FilePointer) fclose( m_FilePointer ); } // Create a TrackVis file and store standard metadata. The file is ready to append fibers. // --------------------------------------------------------------------------------------- short TrackVisFiberReader::create(string filename , const mitk::FiberBundle *fib, bool lps) { - // prepare the header - for(int i=0; i<3 ;i++) + // prepare the header + for(int i=0; i<3 ;i++) + { + if (fib->GetReferenceGeometry().IsNotNull()) { - if (fib->GetReferenceGeometry().IsNotNull()) - { - m_Header.dim[i] = fib->GetReferenceGeometry()->GetExtent(i); - m_Header.voxel_size[i] = fib->GetReferenceGeometry()->GetSpacing()[i]; - m_Header.origin[i] = fib->GetReferenceGeometry()->GetOrigin()[i]; - } - else - { - m_Header.dim[i] = fib->GetGeometry()->GetExtent(i); - m_Header.voxel_size[i] = fib->GetGeometry()->GetSpacing()[i]; - m_Header.origin[i] = fib->GetGeometry()->GetOrigin()[i]; - } + m_Header.dim[i] = fib->GetReferenceGeometry()->GetExtent(i); + m_Header.voxel_size[i] = fib->GetReferenceGeometry()->GetSpacing()[i]; + m_Header.origin[i] = fib->GetReferenceGeometry()->GetOrigin()[i]; } - m_Header.n_scalars = 0; - m_Header.n_properties = 0; - if (lps) - sprintf(m_Header.voxel_order,"LPS"); else - sprintf(m_Header.voxel_order,"RAS"); - m_Header.image_orientation_patient[0] = 1.0; - m_Header.image_orientation_patient[1] = 0.0; - m_Header.image_orientation_patient[2] = 0.0; - m_Header.image_orientation_patient[3] = 0.0; - m_Header.image_orientation_patient[4] = 1.0; - m_Header.image_orientation_patient[5] = 0.0; - m_Header.pad1[0] = 0; - m_Header.pad1[1] = 0; - m_Header.pad2[0] = 0; - m_Header.pad2[1] = 0; - m_Header.invert_x = 0; - m_Header.invert_y = 0; - m_Header.invert_z = 0; - m_Header.swap_xy = 0; - m_Header.swap_yz = 0; - m_Header.swap_zx = 0; - m_Header.n_count = 0; - m_Header.version = 1; - m_Header.hdr_size = 1000; - - // write the header to the file - m_FilePointer = fopen(filename.c_str(),"w+b"); - if (m_FilePointer == nullptr) { - printf("[ERROR] Unable to create file '%s'\n",filename.c_str()); - return 0; + m_Header.dim[i] = fib->GetGeometry()->GetExtent(i); + m_Header.voxel_size[i] = fib->GetGeometry()->GetSpacing()[i]; + m_Header.origin[i] = fib->GetGeometry()->GetOrigin()[i]; } - sprintf(m_Header.id_string,"TRACK"); - if (fwrite((char*)&m_Header, 1, 1000, m_FilePointer) != 1000) - MITK_ERROR << "TrackVis::create : Error occurding during writing fiber."; + } + m_Header.n_scalars = 0; + m_Header.n_properties = 0; + if (lps) + sprintf(m_Header.voxel_order,"LPS"); + else + sprintf(m_Header.voxel_order,"RAS"); + m_Header.image_orientation_patient[0] = 1.0; + m_Header.image_orientation_patient[1] = 0.0; + m_Header.image_orientation_patient[2] = 0.0; + m_Header.image_orientation_patient[3] = 0.0; + m_Header.image_orientation_patient[4] = 1.0; + m_Header.image_orientation_patient[5] = 0.0; + m_Header.pad1[0] = 0; + m_Header.pad1[1] = 0; + m_Header.pad2[0] = 0; + m_Header.pad2[1] = 0; + m_Header.invert_x = 0; + m_Header.invert_y = 0; + m_Header.invert_z = 0; + m_Header.swap_xy = 0; + m_Header.swap_yz = 0; + m_Header.swap_zx = 0; + m_Header.n_count = 0; + m_Header.version = 1; + m_Header.hdr_size = 1000; + + // write the header to the file + m_FilePointer = fopen(filename.c_str(),"w+b"); + if (m_FilePointer == nullptr) + { + printf("[ERROR] Unable to create file '%s'\n",filename.c_str()); + return 0; + } + sprintf(m_Header.id_string,"TRACK"); + if (fwrite((char*)&m_Header, 1, 1000, m_FilePointer) != 1000) + MITK_ERROR << "TrackVis::create : Error occurding during writing fiber."; - this->m_Filename = filename; + this->m_Filename = filename; - return 1; + return 1; } // Open an existing TrackVis file and read metadata information. // The file pointer is positiond at the beginning of fibers data // ------------------------------------------------------------- short TrackVisFiberReader::open( string filename ) { - m_FilePointer = fopen(filename.c_str(), "rb"); - if (m_FilePointer == nullptr) - { - printf("[ERROR] Unable to open file '%s'\n",filename.c_str()); - return 0; - } - this->m_Filename = filename; + m_FilePointer = fopen(filename.c_str(), "rb"); + if (m_FilePointer == nullptr) + { + printf("[ERROR] Unable to open file '%s'\n",filename.c_str()); + return 0; + } + this->m_Filename = filename; - return fread((char*)(&m_Header), 1, 1000, m_FilePointer); + return fread((char*)(&m_Header), 1, 1000, m_FilePointer); } // Append a fiber to the file // -------------------------- short TrackVisFiberReader::append(const mitk::FiberBundle *fib) { - vtkPolyData* poly = fib->GetFiberPolyData(); - for (int i=0; iGetNumFibers(); i++) + vtkPolyData* poly = fib->GetFiberPolyData(); + for (int i=0; iGetNumFibers(); i++) + { + vtkCell* cell = poly->GetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + + unsigned int numSaved, pos = 0; + //float* tmp = new float[3*maxSteps]; + std::vector< float > tmp; + tmp.reserve(3*numPoints); + + numSaved = numPoints; + for(unsigned int i=0; iGetCell(i); - int numPoints = cell->GetNumberOfPoints(); - vtkPoints* points = cell->GetPoints(); - - unsigned int numSaved, pos = 0; - //float* tmp = new float[3*maxSteps]; - std::vector< float > tmp; - tmp.reserve(3*numPoints); - - numSaved = numPoints; - for(unsigned int i=0; iGetPoint(i); - - tmp[pos++] = p[0]; - tmp[pos++] = p[1]; - tmp[pos++] = p[2]; - } - - // write the coordinates to the file - if ( fwrite((char*)&numSaved, 1, 4, m_FilePointer) != 4 ) - { - printf( "[ERROR] Problems saving the fiber!\n" ); - return 1; - } - if ( fwrite((char*)&(tmp.front()), 1, 4*pos, m_FilePointer) != 4*pos ) - { - printf( "[ERROR] Problems saving the fiber!\n" ); - return 1; - } + double* p = points->GetPoint(i); + + tmp[pos++] = p[0]; + tmp[pos++] = p[1]; + tmp[pos++] = p[2]; } - return 0; + // write the coordinates to the file + if ( fwrite((char*)&numSaved, 1, 4, m_FilePointer) != 4 ) + { + printf( "[ERROR] Problems saving the fiber!\n" ); + return 1; + } + if ( fwrite((char*)&(tmp.front()), 1, 4*pos, m_FilePointer) != 4*pos ) + { + printf( "[ERROR] Problems saving the fiber!\n" ); + return 1; + } + } + + return 0; } //// Read one fiber from the file //// ---------------------------- short TrackVisFiberReader::read( mitk::FiberBundle* fib ) { - int numPoints; - vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); - vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); + int numPoints; + vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); + vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); - while (fread((char*)&numPoints, 1, 4, m_FilePointer)==4) + while (fread((char*)&numPoints, 1, 4, m_FilePointer)==4) + { + if ( numPoints <= 0 ) { - if ( numPoints <= 0 ) - { - printf( "[ERROR] Trying to read a fiber with %d points!\n", numPoints ); - return -1; - } - vtkSmartPointer container = vtkSmartPointer::New(); - - float tmp[3]; - for(int i=0; iInsertNextPoint(tmp); - container->GetPointIds()->InsertNextId(id); - } - vtkNewCells->InsertNextCell(container); + printf( "[ERROR] Trying to read a fiber with %d points!\n", numPoints ); + return -1; } + vtkSmartPointer container = vtkSmartPointer::New(); - vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); - fiberPolyData->SetPoints(vtkNewPoints); - fiberPolyData->SetLines(vtkNewCells); - - MITK_INFO << "Coordinate convention: " << m_Header.voxel_order; - - mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); - vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New(); - matrix->Identity(); - - if (m_Header.voxel_order[0]=='R') - matrix->SetElement(0,0,-matrix->GetElement(0,0)); - if (m_Header.voxel_order[1]=='A') - matrix->SetElement(1,1,-matrix->GetElement(1,1)); - if (m_Header.voxel_order[2]=='I') - matrix->SetElement(2,2,-matrix->GetElement(2,2)); - - geometry->SetIndexToWorldTransformByVtkMatrix(matrix); - - vtkSmartPointer transformFilter = vtkSmartPointer::New(); - transformFilter->SetInputData(fiberPolyData); - transformFilter->SetTransform(geometry->GetVtkTransform()); - transformFilter->Update(); - fib->SetFiberPolyData(transformFilter->GetOutput()); - - mitk::Point3D origin; - origin[0]=m_Header.origin[0]; - origin[1]=m_Header.origin[1]; - origin[2]=m_Header.origin[2]; - geometry->SetOrigin(origin); - - mitk::Vector3D spacing; - spacing[0]=m_Header.voxel_size[0]; - spacing[1]=m_Header.voxel_size[1]; - spacing[2]=m_Header.voxel_size[2]; - geometry->SetSpacing(spacing); + float tmp[3]; + for(int i=0; iInsertNextPoint(tmp); + container->GetPointIds()->InsertNextId(id); + } + vtkNewCells->InsertNextCell(container); + } + + vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); + fiberPolyData->SetPoints(vtkNewPoints); + fiberPolyData->SetLines(vtkNewCells); + + // MITK_INFO << "Coordinate convention: " << m_Header.voxel_order; + + mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); + vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New(); + matrix->Identity(); + + if (m_Header.voxel_order[0]=='R') + matrix->SetElement(0,0,-matrix->GetElement(0,0)); + if (m_Header.voxel_order[1]=='A') + matrix->SetElement(1,1,-matrix->GetElement(1,1)); + if (m_Header.voxel_order[2]=='I') + matrix->SetElement(2,2,-matrix->GetElement(2,2)); + + geometry->SetIndexToWorldTransformByVtkMatrix(matrix); + + vtkSmartPointer transformFilter = vtkSmartPointer::New(); + transformFilter->SetInputData(fiberPolyData); + transformFilter->SetTransform(geometry->GetVtkTransform()); + transformFilter->Update(); + fib->SetFiberPolyData(transformFilter->GetOutput()); + + mitk::Point3D origin; + origin[0]=m_Header.origin[0]; + origin[1]=m_Header.origin[1]; + origin[2]=m_Header.origin[2]; + geometry->SetOrigin(origin); + + mitk::Vector3D spacing; + spacing[0]=m_Header.voxel_size[0]; + spacing[1]=m_Header.voxel_size[1]; + spacing[2]=m_Header.voxel_size[2]; + + if (spacing[0]>0 && spacing[1]>0 && spacing[2]>0 && m_Header.dim[0]>0 && m_Header.dim[1]>0 && m_Header.dim[2]>0) + { + geometry->SetSpacing(spacing); geometry->SetExtentInMM(0, m_Header.voxel_size[0]*m_Header.dim[0]); geometry->SetExtentInMM(1, m_Header.voxel_size[1]*m_Header.dim[1]); geometry->SetExtentInMM(2, m_Header.voxel_size[2]*m_Header.dim[2]); - fib->SetReferenceGeometry(dynamic_cast(geometry.GetPointer())); - - return numPoints; + } + return numPoints; } // Update the field in the header to the new FIBER TOTAL. // ------------------------------------------------------ void TrackVisFiberReader::updateTotal( int totFibers ) { - fseek(m_FilePointer, 1000-12, SEEK_SET); - if (fwrite((char*)&totFibers, 1, 4, m_FilePointer) != 4) - MITK_ERROR << "[ERROR] Problems saving the fiber!"; + fseek(m_FilePointer, 1000-12, SEEK_SET); + if (fwrite((char*)&totFibers, 1, 4, m_FilePointer) != 4) + MITK_ERROR << "[ERROR] Problems saving the fiber!"; } void TrackVisFiberReader::writeHdr() { - fseek(m_FilePointer, 0, SEEK_SET); - if (fwrite((char*)&m_Header, 1, 1000, m_FilePointer) != 1000) - MITK_ERROR << "[ERROR] Problems saving the fiber!"; + fseek(m_FilePointer, 0, SEEK_SET); + if (fwrite((char*)&m_Header, 1, 1000, m_FilePointer) != 1000) + MITK_ERROR << "[ERROR] Problems saving the fiber!"; } // Close the TrackVis file, but keep the metadata in the header. // ------------------------------------------------------------- void TrackVisFiberReader::close() { - fclose(m_FilePointer); - m_FilePointer = nullptr; + fclose(m_FilePointer); + m_FilePointer = nullptr; } bool TrackVisFiberReader::IsTransformValid() { - if (fabs(m_Header.image_orientation_patient[0])<=0.001 || fabs(m_Header.image_orientation_patient[3])<=0.001 || fabs(m_Header.image_orientation_patient[5])<=0.001) - return false; - return true; + if (fabs(m_Header.image_orientation_patient[0])<=0.001 || fabs(m_Header.image_orientation_patient[3])<=0.001 || fabs(m_Header.image_orientation_patient[5])<=0.001) + return false; + return true; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp index e58629356e..421f49ffea 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp @@ -1,203 +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 #include #include #include #include #include #include #include #include #include #include using namespace std; typedef itksys::SystemTools ist; typedef itk::Point PointType4; typedef itk::Image< float, 4 > PeakImgType; std::vector< string > get_file_list(const std::string& path) { std::vector< string > file_list; itk::Directory::Pointer dir = itk::Directory::New(); if (dir->Load(path.c_str())) { int n = dir->GetNumberOfFiles(); for (int r = 0; r < n; r++) { const char *filename = dir->GetFile(r); std::string ext = ist::GetFilenameExtension(filename); if (ext==".fib" || ext==".trk") file_list.push_back(path + '/' + filename); } } return file_list; } /*! \brief Fits the tractogram to the input peak image by assigning a weight to each fiber (similar to https://doi.org/10.1016/j.neuroimage.2015.06.092). */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Fit Fibers To Image"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setDescription("Assigns a weight to each fiber in order to optimally explain the input peak image"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("", "i1", mitkCommandLineParser::StringList, "Input tractograms:", "input tractograms (.fib, vtk ascii file format)", us::Any(), false); parser.addArgument("", "i2", mitkCommandLineParser::InputFile, "Input peaks:", "input peak image", us::Any(), false); parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false); parser.addArgument("max_iter", "", mitkCommandLineParser::Int, "Max. iterations:", "maximum number of optimizer iterations", 20); parser.addArgument("bundle_based", "", mitkCommandLineParser::Bool, "Bundle based fit:", "fit one weight per input tractogram/bundle, not for each fiber", false); parser.addArgument("min_g", "", mitkCommandLineParser::Float, "Min. g:", "lower termination threshold for gradient magnitude", 1e-5); parser.addArgument("lambda", "", mitkCommandLineParser::Float, "Lambda:", "modifier for regularization", 0.1); - parser.addArgument("save_res", "", mitkCommandLineParser::Bool, "Residuals:", "save residual images", false); + parser.addArgument("save_res", "", mitkCommandLineParser::Bool, "Save Residuals:", "save residual images", false); + parser.addArgument("save_weights", "", mitkCommandLineParser::Bool, "Save Weights:", "save fiber weights in a separate text file", false); parser.addArgument("dont_filter_outliers", "", mitkCommandLineParser::Bool, "Don't filter outliers:", "don't perform second optimization run with an upper weight bound based on the first weight estimation (95% quantile)", false); map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; mitkCommandLineParser::StringContainerType fib_files = us::any_cast(parsedArgs["i1"]); string peak_file_name = us::any_cast(parsedArgs["i2"]); string outRoot = us::any_cast(parsedArgs["o"]); bool single_fib = true; if (parsedArgs.count("bundle_based")) single_fib = !us::any_cast(parsedArgs["bundle_based"]); bool save_residuals = false; if (parsedArgs.count("save_res")) save_residuals = us::any_cast(parsedArgs["save_res"]); + bool save_weights = false; + if (parsedArgs.count("save_weights")) + save_weights = us::any_cast(parsedArgs["save_weights"]); + int max_iter = 20; if (parsedArgs.count("max_iter")) max_iter = us::any_cast(parsedArgs["max_iter"]); float g_tol = 1e-5; if (parsedArgs.count("min_g")) g_tol = us::any_cast(parsedArgs["min_g"]); float lambda = 0.1; if (parsedArgs.count("lambda")) lambda = us::any_cast(parsedArgs["lambda"]); bool filter_outliers = true; if (parsedArgs.count("dont_filter_outliers")) filter_outliers = !us::any_cast(parsedArgs["dont_filter_outliers"]); try { std::vector< mitk::FiberBundle::Pointer > input_tracts; mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Peak Image", "Fiberbundles"}, {}); mitk::Image::Pointer inputImage = dynamic_cast(mitk::IOUtil::Load(peak_file_name, &functor)[0].GetPointer()); typedef mitk::ImageToItk< PeakImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(inputImage); caster->Update(); PeakImgType::Pointer peak_image = caster->GetOutput(); std::vector< std::string > fib_names; for (auto item : fib_files) { if ( ist::FileIsDirectory(item) ) { for ( auto fibFile : get_file_list(item) ) { mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::Load(fibFile)[0].GetPointer()); if (inputTractogram.IsNull()) continue; input_tracts.push_back(inputTractogram); fib_names.push_back(fibFile); } } else { mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::Load(item)[0].GetPointer()); if (inputTractogram.IsNull()) continue; input_tracts.push_back(inputTractogram); fib_names.push_back(item); } } itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); fitter->SetPeakImage(peak_image); fitter->SetTractograms(input_tracts); fitter->SetFitIndividualFibers(single_fib); fitter->SetMaxIterations(max_iter); fitter->SetGradientTolerance(g_tol); fitter->SetLambda(lambda); fitter->SetFilterOutliers(filter_outliers); fitter->Update(); if (save_residuals) { itk::ImageFileWriter< PeakImgType >::Pointer writer = itk::ImageFileWriter< PeakImgType >::New(); writer->SetInput(fitter->GetFittedImage()); writer->SetFileName(outRoot + "fitted_image.nrrd"); writer->Update(); writer->SetInput(fitter->GetResidualImage()); writer->SetFileName(outRoot + "residual_image.nrrd"); writer->Update(); writer->SetInput(fitter->GetOverexplainedImage()); writer->SetFileName(outRoot + "overexplained_image.nrrd"); writer->Update(); writer->SetInput(fitter->GetUnderexplainedImage()); writer->SetFileName(outRoot + "underexplained_image.nrrd"); writer->Update(); } std::vector< mitk::FiberBundle::Pointer > output_tracts = fitter->GetTractograms(); for (unsigned int bundle=0; bundleGetNumFibers(); ++f) + logfile << output_tracts.at(bundle)->GetFiberWeight(f) << "\n"; + logfile.close(); + } } } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorBasedScoring.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorBasedScoring.cpp new file mode 100755 index 0000000000..16e127144f --- /dev/null +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorBasedScoring.cpp @@ -0,0 +1,444 @@ +/*=================================================================== + +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 + +using namespace std; +typedef itksys::SystemTools ist; +typedef itk::Point PointType4; +typedef itk::Image< float, 4 > PeakImgType; +typedef itk::Image< unsigned char, 3 > ItkUcharImageType; + +std::vector< string > get_file_list(const std::string& path, std::vector< string > extensions={".fib", ".trk"}) +{ + std::vector< string > file_list; + itk::Directory::Pointer dir = itk::Directory::New(); + + if (dir->Load(path.c_str())) + { + int n = dir->GetNumberOfFiles(); + for (int r = 0; r < n; r++) + { + const char *filename = dir->GetFile(r); + std::string ext = ist::GetFilenameExtension(filename); + for (auto e : extensions) + { + if (ext==e) + { + file_list.push_back(path + '/' + filename); + break; + } + } + } + } + return file_list; +} + +std::vector< mitk::FiberBundle::Pointer > CombineTractograms(std::vector< mitk::FiberBundle::Pointer > reference, std::vector< mitk::FiberBundle::Pointer > candidates, int skip=-1) +{ + std::vector< mitk::FiberBundle::Pointer > fib; + for (auto f : reference) + fib.push_back(f); + + int c = 0; + for (auto f : candidates) + { + if (c!=skip) + fib.push_back(f); + ++c; + } + + return fib; +} + +/*! +\brief Fits the tractogram to the input peak image by assigning a weight to each fiber (similar to https://doi.org/10.1016/j.neuroimage.2015.06.092). +*/ +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + + parser.setTitle("Anchor Based Scoring"); + parser.setCategory("Fiber Tracking Evaluation"); + parser.setDescription(""); + parser.setContributor("MIC"); + + parser.setArgumentPrefix("--", "-"); + parser.addArgument("", "i1", mitkCommandLineParser::InputFile, "Anchor tractogram:", "anchor tracts in one tractogram file", us::Any(), false); + parser.addArgument("", "i2", mitkCommandLineParser::InputFile, "Input peaks:", "input peak image", us::Any(), false); + parser.addArgument("", "i3", mitkCommandLineParser::InputFile, "Candidate folder:", "folder containing all candidate tracts (separate files)", us::Any(), false); + parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output folder:", "output folder", us::Any(), false); + + parser.addArgument("reference_mask_folder", "", mitkCommandLineParser::String, "Reference Mask Folder:", "reference tract masks for accuracy evaluation"); + parser.addArgument("mask", "", mitkCommandLineParser::InputFile, "Mask image:", "scoring is only performed inside the mask image"); + parser.addArgument("greedy_add", "", mitkCommandLineParser::Bool, "Greedy:", "if enabled, the candidate tracts are not jointly fitted to the residual image but one after the other employing a greedy scheme", false); + parser.addArgument("lambda", "", mitkCommandLineParser::Float, "Lambda:", "modifier for regularization", 0.1); + parser.addArgument("dont_filter_outliers", "", mitkCommandLineParser::Bool, "Don't filter outliers:", "don't perform second optimization run with an upper weight bound based on the first weight estimation (95% quantile)", false); + + map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + string anchors_file = us::any_cast(parsedArgs["i1"]); + string peak_file_name = us::any_cast(parsedArgs["i2"]); + string candidate_folder = us::any_cast(parsedArgs["i3"]); + string out_folder = us::any_cast(parsedArgs["o"]); + + bool greedy_add = false; + if (parsedArgs.count("greedy_add")) + greedy_add = us::any_cast(parsedArgs["greedy_add"]); + + float lambda = 0.1; + if (parsedArgs.count("lambda")) + lambda = us::any_cast(parsedArgs["lambda"]); + + bool filter_outliers = true; + if (parsedArgs.count("dont_filter_outliers")) + filter_outliers = !us::any_cast(parsedArgs["dont_filter_outliers"]); + + string mask_file = ""; + if (parsedArgs.count("mask")) + mask_file = us::any_cast(parsedArgs["mask"]); + + string reference_mask_folder = ""; + if (parsedArgs.count("reference_mask_folder")) + reference_mask_folder = us::any_cast(parsedArgs["reference_mask_folder"]); + + try + { + itk::TimeProbe clock; + clock.Start(); + + MITK_INFO << "Creating directory structure"; + if (ist::PathExists(out_folder)) + ist::RemoveADirectory(out_folder); + ist::MakeDirectory(out_folder); + + MITK_INFO << "Loading data"; + + streambuf *old = cout.rdbuf(); // <-- save + stringstream ss; + std::cout.rdbuf (ss.rdbuf()); // <-- redirect + + ofstream logfile; + logfile.open (out_folder + "log.txt"); + + itk::ImageFileWriter< PeakImgType >::Pointer peak_image_writer = itk::ImageFileWriter< PeakImgType >::New(); + mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Peak Image", "Fiberbundles"}, {}); + mitk::Image::Pointer inputImage = dynamic_cast(mitk::IOUtil::Load(peak_file_name, &functor)[0].GetPointer()); + + float minSpacing = 1; + if(inputImage->GetGeometry()->GetSpacing()[0]GetGeometry()->GetSpacing()[1] && inputImage->GetGeometry()->GetSpacing()[0]GetGeometry()->GetSpacing()[2]) + minSpacing = inputImage->GetGeometry()->GetSpacing()[0]; + else if (inputImage->GetGeometry()->GetSpacing()[1] < inputImage->GetGeometry()->GetSpacing()[2]) + minSpacing = inputImage->GetGeometry()->GetSpacing()[1]; + else + minSpacing = inputImage->GetGeometry()->GetSpacing()[2]; + + // Load mask file. Fit is only performed inside the mask + itk::FitFibersToImageFilter::UcharImgType::Pointer mask = nullptr; + if (mask_file.compare("")!=0) + { + mitk::Image::Pointer mitk_mask = dynamic_cast(mitk::IOUtil::Load(mask_file)[0].GetPointer()); + mitk::CastToItkImage(mitk_mask, mask); + } + + // Load masks covering the true positives for evaluation purposes + std::vector< string > reference_mask_filenames; + std::vector< itk::FitFibersToImageFilter::UcharImgType::Pointer > reference_masks; + if (reference_mask_folder.compare("")!=0) + { + reference_mask_filenames = get_file_list(reference_mask_folder, {".nii", ".nii.gz", ".nrrd"}); + for (auto filename : reference_mask_filenames) + { + itk::FitFibersToImageFilter::UcharImgType::Pointer ref_mask = nullptr; + mitk::Image::Pointer ref_mitk_mask = dynamic_cast(mitk::IOUtil::Load(filename)[0].GetPointer()); + mitk::CastToItkImage(ref_mitk_mask, ref_mask); + reference_masks.push_back(ref_mask); + } + } + + // Load peak image + typedef mitk::ImageToItk< PeakImgType > CasterType; + CasterType::Pointer caster = CasterType::New(); + caster->SetInput(inputImage); + caster->Update(); + PeakImgType::Pointer peak_image = caster->GetOutput(); + + // Load all candidate tracts + std::vector< mitk::FiberBundle::Pointer > input_candidates; + std::vector< string > candidate_tract_files = get_file_list(candidate_folder); + for (string f : candidate_tract_files) + { + mitk::FiberBundle::Pointer fib = dynamic_cast(mitk::IOUtil::Load(f)[0].GetPointer()); + if (fib.IsNull()) + continue; + if (fib->GetNumFibers()<=0) + return 0; + fib->ResampleLinear(minSpacing/10.0); + input_candidates.push_back(fib); + } + std::cout.rdbuf (old); // <-- restore + + double rmse = 0.0; + int iteration = 0; + std::string name = "NOANCHOR"; + // Load reference tractogram consisting of all known tracts + std::vector< mitk::FiberBundle::Pointer > input_reference; + mitk::FiberBundle::Pointer anchor_tractogram = dynamic_cast(mitk::IOUtil::Load(anchors_file)[0].GetPointer()); + if ( !(anchor_tractogram.IsNull() || anchor_tractogram->GetNumFibers()==0) ) + { + streambuf *old = cout.rdbuf(); // <-- save + stringstream ss; + std::cout.rdbuf (ss.rdbuf()); // <-- redirect + anchor_tractogram->ResampleLinear(minSpacing/10.0); + std::cout.rdbuf (old); // <-- restore + input_reference.push_back(anchor_tractogram); + + // Fit known tracts to peak image to obtain underexplained image + MITK_INFO << "Fit anchor tracts"; + itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); + fitter->SetTractograms(input_reference); + fitter->SetLambda(lambda); + fitter->SetFilterOutliers(filter_outliers); + fitter->SetPeakImage(peak_image); + fitter->SetVerbose(true); + fitter->SetResampleFibers(false); + fitter->SetMaskImage(mask); + fitter->Update(); + rmse = fitter->GetRMSE(); + + name = ist::GetFilenameWithoutExtension(anchors_file); + mitk::FiberBundle::Pointer anchor_tracts = fitter->GetTractograms().at(0); + anchor_tracts->SetFiberColors(255,255,255); + mitk::IOUtil::Save(anchor_tracts, out_folder + "0_" + name + ".fib"); + + peak_image = fitter->GetUnderexplainedImage(); + peak_image_writer->SetInput(peak_image); + peak_image_writer->SetFileName(out_folder + boost::lexical_cast(iteration) + "_" + name + ".nrrd"); + peak_image_writer->Update(); + } + + if (!greedy_add) + { + MITK_INFO << "Fit candidate tracts"; + itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); + fitter->SetLambda(lambda); + fitter->SetFilterOutliers(filter_outliers); + fitter->SetVerbose(true); + fitter->SetPeakImage(peak_image); + fitter->SetResampleFibers(false); + fitter->SetMaskImage(mask); + fitter->SetTractograms(input_candidates); + fitter->Update(); + vnl_vector rms_diff = fitter->GetRmsDiffPerBundle(); + + vnl_vector log_rms_diff = rms_diff-rms_diff.min_value() + 1; + log_rms_diff = log_rms_diff.apply(std::log); + log_rms_diff /= log_rms_diff.max_value(); + int c = 0; + for (auto fib : input_candidates) + { + fib->SetFiberWeights( log_rms_diff[c] ); + fib->ColorFibersByFiberWeights(false, true); + + string bundle_name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(c)); + + streambuf *old = cout.rdbuf(); // <-- save + stringstream ss; + std::cout.rdbuf (ss.rdbuf()); // <-- redirect + mitk::IOUtil::Save(fib, out_folder + boost::lexical_cast((int)(10000*rms_diff[c])) + "_" + bundle_name + ".fib"); + + float best_overlap = 0; + int best_overlap_index = -1; + int m_idx = 0; + for (auto ref_mask : reference_masks) + { + float overlap = fib->GetOverlap(ref_mask, false); + if (overlap>best_overlap) + { + best_overlap = overlap; + best_overlap_index = m_idx; + } + ++m_idx; + } + + unsigned int num_voxels = 0; + { + itk::TractDensityImageFilter< ItkUcharImageType >::Pointer masks_filter = itk::TractDensityImageFilter< ItkUcharImageType >::New(); + masks_filter->SetInputImage(mask); + masks_filter->SetBinaryOutput(true); + masks_filter->SetFiberBundle(fib); + masks_filter->SetUseImageGeometry(true); + masks_filter->Update(); + num_voxels = masks_filter->GetNumCoveredVoxels(); + } + + std::cout.rdbuf (old); // <-- restore + + logfile << "RMS_DIFF: " << setprecision(5) << rms_diff[c] << " " << bundle_name << " " << num_voxels << "\n"; + if (best_overlap_index>=0) + logfile << "Best_overlap: " << setprecision(5) << best_overlap << " " << ist::GetFilenameWithoutExtension(reference_mask_filenames.at(best_overlap_index)) << "\n"; + else + logfile << "No_overlap\n"; + + ++c; + } + + mitk::FiberBundle::Pointer out_fib = mitk::FiberBundle::New(); + out_fib = out_fib->AddBundles(input_candidates); + out_fib->ColorFibersByFiberWeights(false, true); + mitk::IOUtil::Save(out_fib, out_folder + "AllCandidates.fib"); + } + else + { + MITK_INFO << "RMSE: " << setprecision(5) << rmse; + // fitter->SetPeakImage(peak_image); + + // Iteratively add candidate bundles in a greedy manner + while (!input_candidates.empty()) + { + double next_rmse = rmse; + double num_peaks = 0; + mitk::FiberBundle::Pointer best_candidate = nullptr; + PeakImgType::Pointer best_candidate_peak_image = nullptr; + + for (int i=0; i<(int)input_candidates.size(); ++i) + { + // WHY NECESSARY AGAIN?? + itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); + fitter->SetLambda(lambda); + fitter->SetFilterOutliers(filter_outliers); + fitter->SetVerbose(false); + fitter->SetPeakImage(peak_image); + fitter->SetResampleFibers(false); + fitter->SetMaskImage(mask); + // ****************************** + fitter->SetTractograms({input_candidates.at(i)}); + + streambuf *old = cout.rdbuf(); // <-- save + stringstream ss; + std::cout.rdbuf (ss.rdbuf()); // <-- redirect + fitter->Update(); + std::cout.rdbuf (old); // <-- restore + + double candidate_rmse = fitter->GetRMSE(); + + if (candidate_rmseGetNumCoveredDirections(); + best_candidate = fitter->GetTractograms().at(0); + best_candidate_peak_image = fitter->GetUnderexplainedImage(); + } + } + + if (best_candidate.IsNull()) + break; + + // fitter->SetPeakImage(peak_image); + peak_image = best_candidate_peak_image; + + int i=0; + std::vector< mitk::FiberBundle::Pointer > remaining_candidates; + std::vector< string > remaining_candidate_files; + for (auto fib : input_candidates) + { + if (fib!=best_candidate) + { + remaining_candidates.push_back(fib); + remaining_candidate_files.push_back(candidate_tract_files.at(i)); + } + else + name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(i)); + ++i; + } + input_candidates = remaining_candidates; + candidate_tract_files = remaining_candidate_files; + + iteration++; + streambuf *old = cout.rdbuf(); // <-- save + stringstream ss; + std::cout.rdbuf (ss.rdbuf()); // <-- redirect + // Save winning candidate + mitk::IOUtil::Save(best_candidate, out_folder + boost::lexical_cast(iteration) + "_" + name + ".fib"); + peak_image_writer->SetInput(peak_image); + peak_image_writer->SetFileName(out_folder + boost::lexical_cast(iteration) + "_" + name + ".nrrd"); + peak_image_writer->Update(); + + // Calculate best overlap with reference masks for evaluation purposes + float best_overlap = 0; + int best_overlap_index = -1; + i = 0; + for (auto ref_mask : reference_masks) + { + float overlap = best_candidate->GetOverlap(ref_mask, false); + if (overlap>best_overlap) + { + best_overlap = overlap; + best_overlap_index = i; + } + ++i; + } + std::cout.rdbuf (old); // <-- restore + + logfile << "RMSE: " << setprecision(5) << rmse << " " << name << " " << num_peaks << "\n"; + if (best_overlap_index>=0) + logfile << "Best_overlap: " << setprecision(5) << best_overlap << " " << ist::GetFilenameWithoutExtension(reference_mask_filenames.at(best_overlap_index)) << "\n"; + else + logfile << "No_overlap\n"; + } + } + + clock.Stop(); + int h = clock.GetTotal()/3600; + int m = ((int)clock.GetTotal()%3600)/60; + int s = (int)clock.GetTotal()%60; + MITK_INFO << "Plausibility estimation took " << h << "h, " << m << "m and " << s << "s"; + logfile.close(); + } + catch (itk::ExceptionObject e) + { + std::cout << e; + return EXIT_FAILURE; + } + catch (std::exception e) + { + std::cout << e.what(); + return EXIT_FAILURE; + } + catch (...) + { + std::cout << "ERROR!?!"; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/CMakeLists.txt b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/CMakeLists.txt index 9e7cf2c5a7..a72860b7ab 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/CMakeLists.txt +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/CMakeLists.txt @@ -1,42 +1,44 @@ option(BUILD_DiffusionTractographyEvaluationCmdApps "Build commandline tools for diffusion fiber tractography evaluation" OFF) if(BUILD_DiffusionTractographyEvaluationCmdApps OR MITK_BUILD_ALL_APPS) # needed include directories include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of diffusion cmdapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( diffusionTractographyEvaluationcmdapps PeaksAngularError^^MitkFiberTracking TractometerMetrics^^MitkFiberTracking - TractPlausibility^^MitkFiberTracking - TractPlausibilityFit^^MitkFiberTracking + MergeOverlappingTracts^^MitkFiberTracking + ExtractAnchorTracts^^MitkFiberTracking + AnchorBasedScoring^^MitkFiberTracking + EvaluateLiFE^^MitkFiberTracking # LocalDirectionalFiberPlausibility^^MitkFiberTracking # HAS TO USE NEW PEAK IMAGE FORMAT ) foreach(diffusionTractographyEvaluationcmdapp ${diffusionTractographyEvaluationcmdapps}) # extract cmd app name and dependencies string(REPLACE "^^" "\\;" cmdapp_info ${diffusionTractographyEvaluationcmdapp}) set(cmdapp_info_list ${cmdapp_info}) list(GET cmdapp_info_list 0 appname) list(GET cmdapp_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() if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/EvaluateLiFE.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/EvaluateLiFE.cpp new file mode 100755 index 0000000000..80e65bf60a --- /dev/null +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/EvaluateLiFE.cpp @@ -0,0 +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +typedef itksys::SystemTools ist; +typedef itk::Image ItkUcharImgType; +typedef std::tuple< ItkUcharImgType::Pointer, std::string > MaskType; + +ItkUcharImgType::Pointer LoadItkMaskImage(const std::string& filename) +{ + mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::Load(filename)[0].GetPointer()); + ItkUcharImgType::Pointer itkMask = ItkUcharImgType::New(); + mitk::CastToItkImage(img, itkMask); + return itkMask; +} + +std::vector< MaskType > get_file_list(const std::string& path) +{ + std::chrono::milliseconds ms = std::chrono::duration_cast< std::chrono::milliseconds >(std::chrono::system_clock::now().time_since_epoch()); + std::srand(ms.count()); + + std::vector< MaskType > mask_list; + + itk::Directory::Pointer dir = itk::Directory::New(); + + if (dir->Load(path.c_str())) + { + int n = dir->GetNumberOfFiles(); + int num_images = 0; + + std::vector< int > im_indices; + for (int r = 0; r < n; r++) + { + const char *filename = dir->GetFile(r); + std::string ext = ist::GetFilenameExtension(filename); + if (ext==".nii" || ext==".nii.gz" || ext==".nrrd") + { + ++num_images; + im_indices.push_back(r); + } + } + + int c = -1; + for (int r : im_indices) + { + c++; + const char *filename = dir->GetFile(r); + + MITK_INFO << "Loading " << ist::GetFilenameWithoutExtension(filename); + streambuf *old = cout.rdbuf(); // <-- save + stringstream ss; + std::cout.rdbuf (ss.rdbuf()); // <-- redirect + MaskType m(LoadItkMaskImage(path + '/' + filename), ist::GetFilenameName(filename)); + mask_list.push_back(m); + std::cout.rdbuf (old); // <-- restore + } + } + + return mask_list; +} + +/*! +\brief +*/ +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + + parser.setTitle("Evaluate LiFE results"); + parser.setCategory("Fiber Tracking Evaluation"); + parser.setDescription(""); + parser.setContributor("MIC"); + + parser.setArgumentPrefix("--", "-"); + parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input tractogram (.fib, vtk ascii file format)", us::Any(), false); + parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output folder", us::Any(), false); + parser.addArgument("reference_mask_folder", "m", mitkCommandLineParser::String, "Reference Mask Folder:", "reference masks of known bundles", false); + parser.addArgument("overlap", "", mitkCommandLineParser::Float, "Overlap threshold:", "Overlap threshold used to identify true positives", 0.8); + parser.addArgument("steps", "", mitkCommandLineParser::Int, "Threshold steps:", "number of weight thresholds used to calculate the ROC curve", 100); + parser.addArgument("pre_filter_zeros", "", mitkCommandLineParser::Bool, "Remove zero weights:", "remove fibers with zero weights before starting the evaluation"); + + map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + string fibFile = us::any_cast(parsedArgs["input"]); + string reference_mask_folder = us::any_cast(parsedArgs["reference_mask_folder"]); + string out_folder = us::any_cast(parsedArgs["out"]); + + float overlap = 0.8; + if (parsedArgs.count("overlap")) + overlap = us::any_cast(parsedArgs["overlap"]); + + int steps = 10; + if (parsedArgs.count("steps")) + steps = us::any_cast(parsedArgs["steps"]); + + bool pre_filter_zeros = false; + if (parsedArgs.count("pre_filter_zeros")) + pre_filter_zeros = us::any_cast(parsedArgs["pre_filter_zeros"]); + + try + { + std::vector< MaskType > known_tract_masks = get_file_list(reference_mask_folder); + if (known_tract_masks.empty()) + return EXIT_FAILURE; + + mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::Load(fibFile)[0].GetPointer()); + + // resample fibers + float minSpacing = 1; + if(std::get<0>(known_tract_masks.at(0))->GetSpacing()[0](known_tract_masks.at(0))->GetSpacing()[1] && std::get<0>(known_tract_masks.at(0))->GetSpacing()[0](known_tract_masks.at(0))->GetSpacing()[2]) + minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[0]; + else if (std::get<0>(known_tract_masks.at(0))->GetSpacing()[1] < std::get<0>(known_tract_masks.at(0))->GetSpacing()[2]) + minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[1]; + else + minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[2]; + inputTractogram->ResampleLinear(minSpacing/5); + + std::vector< float > weights; + for (int i=0; iGetNumFibers(); ++i) + weights.push_back(inputTractogram->GetFiberWeight(i)); + std::sort(weights.begin(), weights.end()); + + if (pre_filter_zeros) + inputTractogram = inputTractogram->FilterByWeights(0.0); + mitk::FiberBundle::Pointer pred_positives = inputTractogram->GetDeepCopy(); + mitk::FiberBundle::Pointer pred_negatives = mitk::FiberBundle::New(nullptr); + + ofstream logfile; + logfile.open (out_folder + "LiFE_ROC.txt"); + + float fpr = 1.0; + float tpr = 1.0; + float step = weights.back()/steps; + float w = 0; + if (!pre_filter_zeros) + w -= step; + while (pred_positives->GetNumFibers()>0 && fpr>0.001 && tpr>0.001) + { + w += step; + + streambuf *old = cout.rdbuf(); // <-- save + stringstream ss; + std::cout.rdbuf (ss.rdbuf()); // <-- redirect + + mitk::FiberBundle::Pointer tp_tracts = mitk::FiberBundle::New(nullptr); + mitk::FiberBundle::Pointer fn_tracts = mitk::FiberBundle::New(nullptr); + for ( MaskType mask : known_tract_masks ) + { + ItkUcharImgType::Pointer mask_image = std::get<0>(mask); + + mitk::FiberBundle::Pointer a = pred_positives->ExtractFiberSubset(mask_image, true, false, false, overlap, false); + tp_tracts = tp_tracts->AddBundle(a); + + mitk::FiberBundle::Pointer b = pred_negatives->ExtractFiberSubset(mask_image, true, false, false, overlap, false); + fn_tracts = fn_tracts->AddBundle(b); + } + mitk::FiberBundle::Pointer fp_tracts = pred_positives->SubtractBundle(tp_tracts); + mitk::FiberBundle::Pointer tn_tracts = pred_negatives->SubtractBundle(fn_tracts); + + std::cout.rdbuf (old); // <-- restore + + float positives = tp_tracts->GetNumFibers() + fn_tracts->GetNumFibers(); + float negatives = tn_tracts->GetNumFibers() + fp_tracts->GetNumFibers(); + fpr = (float)fp_tracts->GetNumFibers() / negatives; + tpr = (float)tp_tracts->GetNumFibers() / positives; + + float accuracy = 1.0; + if (pred_positives->GetNumFibers()>0) + accuracy = (float)tp_tracts->GetNumFibers()/pred_positives->GetNumFibers(); + logfile << w << " " << fpr << " " << tpr << " " << accuracy << " \n"; + MITK_INFO << "#Fibers: " << pred_positives->GetNumFibers(); + MITK_INFO << "FPR/TPR: " << fpr << "/" << tpr; + MITK_INFO << "Acc: " << accuracy; + + pred_positives = inputTractogram->FilterByWeights(w); + pred_negatives = inputTractogram->FilterByWeights(w, true); + } + logfile.close(); + } + catch (itk::ExceptionObject e) + { + std::cout << e; + return EXIT_FAILURE; + } + catch (std::exception e) + { + std::cout << e.what(); + return EXIT_FAILURE; + } + catch (...) + { + std::cout << "ERROR!?!"; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractAnchorTracts.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractAnchorTracts.cpp new file mode 100755 index 0000000000..8479b8344a --- /dev/null +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractAnchorTracts.cpp @@ -0,0 +1,269 @@ +/*=================================================================== + +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 + +using namespace std; +typedef itksys::SystemTools ist; +typedef itk::Image ItkUcharImgType; +typedef std::tuple< ItkUcharImgType::Pointer, std::string > MaskType; + +void CreateFolderStructure(const std::string& path) +{ + if (ist::PathExists(path)) + ist::RemoveADirectory(path); + + ist::MakeDirectory(path); + ist::MakeDirectory(path + "/anchor_tracts/"); + ist::MakeDirectory(path + "/candidate_tracts/"); + ist::MakeDirectory(path + "/implausible_tracts/"); + ist::MakeDirectory(path + "/skipped_masks/"); +} + +ItkUcharImgType::Pointer LoadItkMaskImage(const std::string& filename) +{ + mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::Load(filename)[0].GetPointer()); + ItkUcharImgType::Pointer itkMask = ItkUcharImgType::New(); + mitk::CastToItkImage(img, itkMask); + return itkMask; +} + +std::vector< MaskType > get_file_list(const std::string& path, float anchor_fraction, const std::string& skipped_path) +{ + if (anchor_fraction<0) + anchor_fraction = 0; + else if (anchor_fraction>1.0) + anchor_fraction = 1.0; + + std::chrono::milliseconds ms = std::chrono::duration_cast< std::chrono::milliseconds >(std::chrono::system_clock::now().time_since_epoch()); + std::srand(ms.count()); + + std::vector< MaskType > mask_list; + + itk::Directory::Pointer dir = itk::Directory::New(); + + int skipped = 0; + if (dir->Load(path.c_str())) + { + int n = dir->GetNumberOfFiles(); + int num_images = 0; + + std::vector< int > im_indices; + for (int r = 0; r < n; r++) + { + const char *filename = dir->GetFile(r); + std::string ext = ist::GetFilenameExtension(filename); + if (ext==".nii" || ext==".nii.gz" || ext==".nrrd") + { + ++num_images; + im_indices.push_back(r); + } + } + + int skipping_num = num_images * (1.0 - anchor_fraction); + std::random_shuffle(im_indices.begin(), im_indices.end()); + MITK_INFO << "Skipping " << skipping_num << " images"; + MITK_INFO << "Number of anchors: " << num_images-skipping_num; + + int c = -1; + for (int r : im_indices) + { + c++; + const char *filename = dir->GetFile(r); + + if (c matrix = vtkSmartPointer< vtkMatrix4x4 >::New(); + matrix->Identity(); + matrix->SetElement(0,0,-matrix->GetElement(0,0)); + matrix->SetElement(1,1,-matrix->GetElement(1,1)); + geometry->SetIndexToWorldTransformByVtkMatrix(matrix); + + vtkSmartPointer transformFilter = vtkSmartPointer::New(); + transformFilter->SetInputData(fib->GetFiberPolyData()); + transformFilter->SetTransform(geometry->GetVtkTransform()); + transformFilter->Update(); + mitk::FiberBundle::Pointer transformed_fib = mitk::FiberBundle::New(transformFilter->GetOutput()); + return transformed_fib; +} + +/*! +\brief +*/ +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + + parser.setTitle("Extract Anchor Tracts"); + parser.setCategory("Fiber Tracking Evaluation"); + parser.setDescription(""); + parser.setContributor("MIC"); + + parser.setArgumentPrefix("--", "-"); + parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input tractogram (.fib, vtk ascii file format)", us::Any(), false); + parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output folder", us::Any(), false); + parser.addArgument("reference_mask_folder", "m", mitkCommandLineParser::String, "Reference Mask Folder:", "reference masks of known bundles", us::Any(), false); + parser.addArgument("gray_matter_mask", "gm", mitkCommandLineParser::String, "GM mask:", "remove fibers not ending in the gray matter"); + parser.addArgument("anchor_fraction", "", mitkCommandLineParser::Float, "Anchor fraction:", "Fraction of tracts used as anchors", 0.5); + parser.addArgument("overlap", "", mitkCommandLineParser::Float, "Overlap threshold:", "Overlap threshold used to identify the anchor tracts", 0.8); + parser.addArgument("subsample", "", mitkCommandLineParser::Float, "Subsampling factor:", "Only use specified fraction of input fibers for the analysis", 1.0); + + map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + string fibFile = us::any_cast(parsedArgs["input"]); + string reference_mask_folder = us::any_cast(parsedArgs["reference_mask_folder"]); + string out_folder = us::any_cast(parsedArgs["out"]); + + string gray_matter_mask = ""; + if (parsedArgs.count("gray_matter_mask")) + gray_matter_mask = us::any_cast(parsedArgs["gray_matter_mask"]); + + float anchor_fraction = 0.5; + if (parsedArgs.count("anchor_fraction")) + anchor_fraction = us::any_cast(parsedArgs["anchor_fraction"]); + + float overlap = 0.8; + if (parsedArgs.count("overlap")) + overlap = us::any_cast(parsedArgs["overlap"]); + + float subsample = 1.0; + if (parsedArgs.count("subsample")) + subsample = us::any_cast(parsedArgs["subsample"]); + + try + { + CreateFolderStructure(out_folder); + std::vector< MaskType > known_tract_masks = get_file_list(reference_mask_folder, anchor_fraction, out_folder + "/skipped_masks/"); + mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::Load(fibFile)[0].GetPointer()); + + MITK_INFO << "Removing fibers not ending inside of GM"; + if (gray_matter_mask.compare("")!=0) + { + streambuf *old = cout.rdbuf(); // <-- save + stringstream ss; + std::cout.rdbuf (ss.rdbuf()); // <-- redirect + ItkUcharImgType::Pointer gm_image = LoadItkMaskImage(gray_matter_mask); + std::cout.rdbuf (old); // <-- restore + + mitk::FiberBundle::Pointer not_gm_fibers = inputTractogram->ExtractFiberSubset(gm_image, false, true, true); + + old = cout.rdbuf(); // <-- save + std::cout.rdbuf (ss.rdbuf()); // <-- redirect + mitk::IOUtil::Save(not_gm_fibers, out_folder + "/implausible_tracts/no_gm_endings.trk"); + inputTractogram = inputTractogram->ExtractFiberSubset(gm_image, false, false, true); + std::cout.rdbuf (old); // <-- restore + } + + if (subsample<1.0) + inputTractogram = inputTractogram->SubsampleFibers(subsample); + + + // resample fibers + float minSpacing = 1; + if (!known_tract_masks.empty()) + { + if(std::get<0>(known_tract_masks.at(0))->GetSpacing()[0](known_tract_masks.at(0))->GetSpacing()[1] && std::get<0>(known_tract_masks.at(0))->GetSpacing()[0](known_tract_masks.at(0))->GetSpacing()[2]) + minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[0]; + else if (std::get<0>(known_tract_masks.at(0))->GetSpacing()[1] < std::get<0>(known_tract_masks.at(0))->GetSpacing()[2]) + minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[1]; + else + minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[2]; + } + inputTractogram->ResampleLinear(minSpacing/5); + + mitk::FiberBundle::Pointer all_anchor_tracts = mitk::FiberBundle::New(nullptr); + if (!known_tract_masks.empty()) + { + MITK_INFO << "Find known tracts via overlap match"; + boost::progress_display disp(known_tract_masks.size()); + for ( MaskType mask : known_tract_masks ) + { + ++disp; + streambuf *old = cout.rdbuf(); // <-- save + stringstream ss; + std::cout.rdbuf (ss.rdbuf()); // <-- redirect + + ItkUcharImgType::Pointer mask_image = std::get<0>(mask); + std::string mask_name = std::get<1>(mask); + mitk::FiberBundle::Pointer known_tract = inputTractogram->ExtractFiberSubset(mask_image, true, false, false, overlap, false); + mitk::IOUtil::Save(known_tract, out_folder + "/anchor_tracts/" + mask_name + ".trk"); + + all_anchor_tracts = all_anchor_tracts->AddBundle(known_tract); + + std::cout.rdbuf (old); // <-- restore + } + } + + mitk::IOUtil::Save(all_anchor_tracts, out_folder + "/anchor_tracts/anchor_tractogram.trk"); + mitk::FiberBundle::Pointer remaining_tracts = inputTractogram->SubtractBundle(all_anchor_tracts); + mitk::IOUtil::Save(remaining_tracts, out_folder + "/candidate_tracts/candidate_tractogram.trk"); + mitk::IOUtil::Save(inputTractogram, out_folder + "/filtered_tractogram.trk"); + } + catch (itk::ExceptionObject e) + { + std::cout << e; + return EXIT_FAILURE; + } + catch (std::exception e) + { + std::cout << e.what(); + return EXIT_FAILURE; + } + catch (...) + { + std::cout << "ERROR!?!"; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/MergeOverlappingTracts.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/MergeOverlappingTracts.cpp new file mode 100755 index 0000000000..673202ff03 --- /dev/null +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/MergeOverlappingTracts.cpp @@ -0,0 +1,252 @@ +/*=================================================================== + +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 + +using namespace std; +typedef itksys::SystemTools ist; +typedef itk::Image ItkUcharImgType; +typedef itk::Image ItkUIntImgType; + +std::vector< string > get_file_list(const std::string& path, std::vector< string > extensions={".fib", ".trk"}) +{ + std::vector< string > file_list; + itk::Directory::Pointer dir = itk::Directory::New(); + + if (dir->Load(path.c_str())) + { + int n = dir->GetNumberOfFiles(); + for (int r = 0; r < n; r++) + { + const char *filename = dir->GetFile(r); + std::string ext = ist::GetFilenameExtension(filename); + for (auto e : extensions) + { + if (ext==e) + { + file_list.push_back(path + '/' + filename); + break; + } + } + } + } + return file_list; +} + +/*! +\brief +*/ +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + + parser.setTitle("Merge Overlapping Tracts"); + parser.setCategory("Fiber Tracking Evaluation"); + parser.setDescription(""); + parser.setContributor("MIC"); + + parser.setArgumentPrefix("--", "-"); + parser.addArgument("in", "i", mitkCommandLineParser::InputFile, "Input Folder:", "input folder", us::Any(), false); + parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output Folder:", "output folder", us::Any(), false); + parser.addArgument("overlap", "", mitkCommandLineParser::Float, "Overlap threshold:", "Tracts with overlap larger than this threshold are merged", false, 0.8); + + map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + string input_folder = us::any_cast(parsedArgs["in"]); + string out_folder = us::any_cast(parsedArgs["out"]); + + float overlap = 0.8; + if (parsedArgs.count("overlap")) + overlap = us::any_cast(parsedArgs["overlap"]); + + try + { + if (ist::PathExists(out_folder)) + ist::RemoveADirectory(out_folder); + ist::MakeDirectory(out_folder); + + std::vector< string > fib_files = get_file_list(input_folder, {".fib", ".trk", ".tck"}); + if (fib_files.empty()) + return EXIT_FAILURE; + + streambuf *old = cout.rdbuf(); // <-- save + stringstream ss; + std::cout.rdbuf (ss.rdbuf()); // <-- redirect + + std::vector< mitk::FiberBundle::Pointer > fibs; + for (string f : fib_files) + { + mitk::FiberBundle::Pointer fib = dynamic_cast(mitk::IOUtil::Load(f)[0].GetPointer()); + fibs.push_back(fib); + } + + mitk::FiberBundle::Pointer combined = mitk::FiberBundle::New(); + combined = combined->AddBundles(fibs); + + itk::TractsToFiberEndingsImageFilter< ItkUcharImgType >::Pointer endings = itk::TractsToFiberEndingsImageFilter< ItkUcharImgType >::New(); + endings->SetFiberBundle(combined); + endings->SetUpsamplingFactor(0.25); + endings->Update(); + ItkUcharImgType::Pointer ref_image = endings->GetOutput(); + + std::cout.rdbuf (old); // <-- restore + + for (int its = 0; its<3; its++) + { + streambuf *old = cout.rdbuf(); // <-- save + stringstream ss; + std::cout.rdbuf (ss.rdbuf()); // <-- redirect + + std::vector< ItkUcharImgType::Pointer > mask_images; + for (auto fib : fibs) + { + itk::TractDensityImageFilter< ItkUcharImgType >::Pointer masks = itk::TractDensityImageFilter< ItkUcharImgType >::New(); + masks->SetInputImage(ref_image); + masks->SetBinaryOutput(true); + masks->SetFiberBundle(fib); + masks->SetUseImageGeometry(true); + masks->Update(); + mask_images.push_back(masks->GetOutput()); + } + + int r=0; + vnl_matrix< int > mat; mat.set_size(mask_images.size(), mask_images.size()); mat.fill(0); + for (auto m1 : mask_images) + { + float max_overlap = overlap; + int c = 0; + for (auto m2 : mask_images) + { + if (c<=r) + { + ++c; + continue; + } + + itk::ImageRegionConstIterator it1(m1, m1->GetLargestPossibleRegion()); + itk::ImageRegionConstIterator it2(m2, m2->GetLargestPossibleRegion()); + + unsigned int c1 = 0; + unsigned int c2 = 0; + unsigned int intersect = 0; + while( !it1.IsAtEnd() ) + { + if( it1.Get()>0 && it2.Get()>0) + ++intersect; + if(it1.Get()>0) + ++c1; + if(it2.Get()>0) + ++c2; + ++it1; + ++it2; + } + + if ( (float)intersect/c1>max_overlap ) + { + max_overlap = (float)intersect/c1; + mat.put(r,c, 1); + } + if ( (float)intersect/c2>max_overlap ) + { + max_overlap = (float)intersect/c2; + mat.put(r,c, 1); + } + ++c; + } + + ++r; + } + + std::vector< mitk::FiberBundle::Pointer > out_fibs; + std::vector< bool > used; + for (unsigned int i=0; i0) + { + fib = fib->AddBundle(fibs.at(c)); + MITK_INFO << c; + used[c] = true; + } + } + + out_fibs.push_back(fib); + } + std::cout.rdbuf (old); // <-- restore + + MITK_INFO << fibs.size() << " --> " << out_fibs.size(); + + if (fibs.size()==out_fibs.size()) + break; + fibs = out_fibs; + } + + int c = 0; + for (auto fib : fibs) + { + streambuf *old = cout.rdbuf(); // <-- save + stringstream ss; + std::cout.rdbuf (ss.rdbuf()); // <-- redirect + mitk::IOUtil::Save(fib, out_folder + "/bundle_" + boost::lexical_cast(c) + ".trk"); + std::cout.rdbuf (old); // <-- restore + + ++c; + } + } + catch (itk::ExceptionObject e) + { + std::cout << e; + return EXIT_FAILURE; + } + catch (std::exception e) + { + std::cout << e.what(); + return EXIT_FAILURE; + } + catch (...) + { + std::cout << "ERROR!?!"; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractPlausibility.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractPlausibility.cpp deleted file mode 100755 index ecf520ae8f..0000000000 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractPlausibility.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; -typedef itksys::SystemTools ist; -typedef itk::Image ItkUcharImgType; -typedef std::tuple< ItkUcharImgType::Pointer, std::string > MaskType; - -void CreateFolderStructure(const std::string& path) -{ - if (ist::PathExists(path)) - ist::RemoveADirectory(path); - - ist::MakeDirectory(path); - ist::MakeDirectory(path + "/known_tracts/"); - ist::MakeDirectory(path + "/plausible_tracts/"); - ist::MakeDirectory(path + "/implausible_tracts/"); -} - -ItkUcharImgType::Pointer LoadItkMaskImage(const std::string& filename) -{ - mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::Load(filename)[0].GetPointer()); - ItkUcharImgType::Pointer itkMask = ItkUcharImgType::New(); - mitk::CastToItkImage(img, itkMask); - return itkMask; -} - -std::vector< MaskType > get_file_list(const std::string& path, const std::string& skipped) -{ - std::srand(std::time(0)); - - std::vector< MaskType > mask_list; - - itk::Directory::Pointer dir = itk::Directory::New(); - - ofstream myfile; - myfile.open (skipped); - if (dir->Load(path.c_str())) - { - int n = dir->GetNumberOfFiles(); - for (int r = 0; r < n; r++) - { - const char *filename = dir->GetFile(r); - - if (std::rand()%3==0 && ist::GetFilenameWithoutExtension(filename)!="CC") - { - MITK_INFO << "Dismissing " << ist::GetFilenameWithoutExtension(filename); - myfile << ist::GetFilenameName(filename) << "\n"; - continue; - } - - std::string ext = ist::GetFilenameExtension(filename); - if (ext==".nii" || ext==".nii.gz" || ext==".nrrd") - { - MITK_INFO << "Loading " << ist::GetFilenameWithoutExtension(filename); - streambuf *old = cout.rdbuf(); // <-- save - stringstream ss; - std::cout.rdbuf (ss.rdbuf()); // <-- redirect - - MaskType m(LoadItkMaskImage(path + '/' + filename), ist::GetFilenameWithoutExtension(filename)); - mask_list.push_back(m); - - std::cout.rdbuf (old); // <-- restore - } - } - } - myfile.close(); - - return mask_list; -} - -mitk::FiberBundle::Pointer TransformToMRtrixSpace(mitk::FiberBundle::Pointer fib) -{ - mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); - vtkSmartPointer< vtkMatrix4x4 > matrix = vtkSmartPointer< vtkMatrix4x4 >::New(); - matrix->Identity(); - matrix->SetElement(0,0,-matrix->GetElement(0,0)); - matrix->SetElement(1,1,-matrix->GetElement(1,1)); - geometry->SetIndexToWorldTransformByVtkMatrix(matrix); - - vtkSmartPointer transformFilter = vtkSmartPointer::New(); - transformFilter->SetInputData(fib->GetFiberPolyData()); - transformFilter->SetTransform(geometry->GetVtkTransform()); - transformFilter->Update(); - mitk::FiberBundle::Pointer transformed_fib = mitk::FiberBundle::New(transformFilter->GetOutput()); - return transformed_fib; -} - -/*! -\brief -*/ -int main(int argc, char* argv[]) -{ - mitkCommandLineParser parser; - - parser.setTitle("Tract Plausibility"); - parser.setCategory("Fiber Tracking Evaluation"); - parser.setDescription(""); - parser.setContributor("MIC"); - - parser.setArgumentPrefix("--", "-"); - parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input tractogram (.fib, vtk ascii file format)", us::Any(), false); - parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output folder", us::Any(), false); - parser.addArgument("reference_mask_folder", "m", mitkCommandLineParser::String, "Reference Mask Folder:", "reference masks of known bundles", false); - parser.addArgument("gray_matter_mask", "gm", mitkCommandLineParser::String, "", "", false); - - map parsedArgs = parser.parseArguments(argc, argv); - if (parsedArgs.size()==0) - return EXIT_FAILURE; - - string fibFile = us::any_cast(parsedArgs["input"]); - string gray_matter_mask = us::any_cast(parsedArgs["gray_matter_mask"]); - string reference_mask_folder = us::any_cast(parsedArgs["reference_mask_folder"]); - string out_folder = us::any_cast(parsedArgs["out"]); - - try - { - CreateFolderStructure(out_folder); - - std::vector< MaskType > known_tract_masks = get_file_list(reference_mask_folder, out_folder + "skipped_masks.txt"); - if (known_tract_masks.empty()) - return EXIT_FAILURE; - - ItkUcharImgType::Pointer gm_image = LoadItkMaskImage(gray_matter_mask); - - mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::Load(fibFile)[0].GetPointer()); - - // filter gray matter fibers - mitk::FiberBundle::Pointer not_gm_fibers = inputTractogram->ExtractFiberSubset(gm_image, false, true, true); - mitk::IOUtil::Save(not_gm_fibers, out_folder + "/implausible_tracts/no_gm_endings.trk"); - inputTractogram = inputTractogram->ExtractFiberSubset(gm_image, false, false, true); - - // resample fibers - float minSpacing = 1; - if(std::get<0>(known_tract_masks.at(0))->GetSpacing()[0](known_tract_masks.at(0))->GetSpacing()[1] && std::get<0>(known_tract_masks.at(0))->GetSpacing()[0](known_tract_masks.at(0))->GetSpacing()[2]) - minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[0]; - else if (std::get<0>(known_tract_masks.at(0))->GetSpacing()[1] < std::get<0>(known_tract_masks.at(0))->GetSpacing()[2]) - minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[1]; - else - minSpacing = std::get<0>(known_tract_masks.at(0))->GetSpacing()[2]; - inputTractogram->ResampleLinear(minSpacing/5); - - // find known tracts via overlap match - mitk::FiberBundle::Pointer all_known_tracts = nullptr; - for ( MaskType mask : known_tract_masks ) - { - ItkUcharImgType::Pointer mask_image = std::get<0>(mask); - std::string mask_name = std::get<1>(mask); - mitk::FiberBundle::Pointer known_tract = inputTractogram->ExtractFiberSubset(mask_image, true, false, false, 0.7, false); - mitk::IOUtil::Save(known_tract, out_folder + "/known_tracts/" + mask_name + ".trk"); - - if (all_known_tracts.IsNull()) - all_known_tracts = mitk::FiberBundle::New(known_tract->GetFiberPolyData()); - else - all_known_tracts = all_known_tracts->AddBundle(known_tract); - } - mitk::IOUtil::Save(all_known_tracts, out_folder + "/known_tracts/all_known_tracts.trk"); - mitk::IOUtil::Save(TransformToMRtrixSpace(all_known_tracts), out_folder + "/known_tracts/all_known_tracts_mrtrixspace.fib"); - - mitk::FiberBundle::Pointer remaining_tracts = inputTractogram->SubtractBundle(all_known_tracts); - mitk::IOUtil::Save(remaining_tracts, out_folder + "/plausible_tracts/remaining_tracts.trk"); - mitk::IOUtil::Save(TransformToMRtrixSpace(remaining_tracts), out_folder + "/plausible_tracts/remaining_tracts_mrtrixspace.fib"); - MITK_INFO << "step_size: " << minSpacing/5; - } - catch (itk::ExceptionObject e) - { - std::cout << e; - return EXIT_FAILURE; - } - catch (std::exception e) - { - std::cout << e.what(); - return EXIT_FAILURE; - } - catch (...) - { - std::cout << "ERROR!?!"; - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractPlausibilityFit.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractPlausibilityFit.cpp deleted file mode 100755 index 6b1f1240c0..0000000000 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractPlausibilityFit.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; -typedef itksys::SystemTools ist; -typedef itk::Point PointType4; -typedef itk::Image< float, 4 > PeakImgType; - -std::vector< string > get_file_list(const std::string& path) -{ - std::vector< string > file_list; - itk::Directory::Pointer dir = itk::Directory::New(); - - if (dir->Load(path.c_str())) - { - int n = dir->GetNumberOfFiles(); - for (int r = 0; r < n; r++) - { - const char *filename = dir->GetFile(r); - std::string ext = ist::GetFilenameExtension(filename); - if (ext==".fib" || ext==".trk") - file_list.push_back(path + '/' + filename); - } - } - return file_list; -} - -/*! -\brief Fits the tractogram to the input peak image by assigning a weight to each fiber (similar to https://doi.org/10.1016/j.neuroimage.2015.06.092). -*/ -int main(int argc, char* argv[]) -{ - mitkCommandLineParser parser; - - parser.setTitle(""); - parser.setCategory("Fiber Tracking Evaluation"); - parser.setDescription(""); - parser.setContributor("MIC"); - - parser.setArgumentPrefix("--", "-"); - parser.addArgument("", "i1", mitkCommandLineParser::InputFile, "Input tractogram:", "input tractogram (.fib, vtk ascii file format)", us::Any(), false); - parser.addArgument("", "i2", mitkCommandLineParser::InputFile, "Input peaks:", "input peak image", us::Any(), false); - parser.addArgument("", "i3", mitkCommandLineParser::InputFile, "", "", us::Any(), false); - parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any()); - - parser.addArgument("mask", "", mitkCommandLineParser::InputFile, "", "", us::Any(), false); - parser.addArgument("min_gain", "", mitkCommandLineParser::Float, "Min. gain:", "process stops if remaining bundles don't contribute enough", 0.05); - - - parser.addArgument("max_iter", "", mitkCommandLineParser::Int, "Max. iterations:", "maximum number of optimizer iterations", 20); - parser.addArgument("bundle_based", "", mitkCommandLineParser::Bool, "Bundle based fit:", "fit one weight per input tractogram/bundle, not for each fiber", false); - parser.addArgument("min_g", "", mitkCommandLineParser::Float, "Min. gradient:", "lower termination threshold for gradient magnitude", 1e-5); - parser.addArgument("lambda", "", mitkCommandLineParser::Float, "Lambda:", "modifier for regularization", 0.1); - parser.addArgument("dont_filter_outliers", "", mitkCommandLineParser::Bool, "Don't filter outliers:", "don't perform second optimization run with an upper weight bound based on the first weight estimation (95% quantile)", false); - - map parsedArgs = parser.parseArguments(argc, argv); - if (parsedArgs.size()==0) - return EXIT_FAILURE; - - string fib_file = us::any_cast(parsedArgs["i1"]); - string peak_file_name = us::any_cast(parsedArgs["i2"]); - string candidate_folder = us::any_cast(parsedArgs["i3"]); - string outRoot = us::any_cast(parsedArgs["o"]); - - bool single_fib = true; - if (parsedArgs.count("bundle_based")) - single_fib = !us::any_cast(parsedArgs["bundle_based"]); - - int max_iter = 20; - if (parsedArgs.count("max_iter")) - max_iter = us::any_cast(parsedArgs["max_iter"]); - - float g_tol = 1e-5; - if (parsedArgs.count("min_g")) - g_tol = us::any_cast(parsedArgs["min_g"]); - - float min_gain = 0.05; - if (parsedArgs.count("min_gain")) - min_gain = us::any_cast(parsedArgs["min_gain"]); - - float lambda = 0.1; - if (parsedArgs.count("lambda")) - lambda = us::any_cast(parsedArgs["lambda"]); - - bool filter_outliers = true; - if (parsedArgs.count("dont_filter_outliers")) - filter_outliers = !us::any_cast(parsedArgs["dont_filter_outliers"]); - - string mask_file = ""; - if (parsedArgs.count("mask")) - mask_file = us::any_cast(parsedArgs["mask"]); - - try - { - itk::TimeProbe clock; - clock.Start(); - - mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Peak Image", "Fiberbundles"}, {}); - mitk::Image::Pointer inputImage = dynamic_cast(mitk::IOUtil::Load(peak_file_name, &functor)[0].GetPointer()); - - itk::FitFibersToImageFilter::UcharImgType::Pointer mask = nullptr; - if (mask_file.compare("")!=0) - { - mitk::Image::Pointer mitk_mask = dynamic_cast(mitk::IOUtil::Load(mask_file)[0].GetPointer()); - mitk::CastToItkImage(mitk_mask, mask); - } - - typedef mitk::ImageToItk< PeakImgType > CasterType; - CasterType::Pointer caster = CasterType::New(); - caster->SetInput(inputImage); - caster->Update(); - PeakImgType::Pointer peak_image = caster->GetOutput(); - - std::vector< mitk::FiberBundle::Pointer > input_reference; - mitk::FiberBundle::Pointer fib = dynamic_cast(mitk::IOUtil::Load(fib_file)[0].GetPointer()); - if (fib.IsNull()) - return EXIT_FAILURE; - input_reference.push_back(fib); - - std::vector< mitk::FiberBundle::Pointer > input_candidates; - std::vector< string > candidate_tract_files = get_file_list(candidate_folder); - for (string f : candidate_tract_files) - { - mitk::FiberBundle::Pointer fib = dynamic_cast(mitk::IOUtil::Load(f)[0].GetPointer()); - if (fib.IsNull()) - continue; - input_candidates.push_back(fib); - } - - int iteration = 0; - std::string name = ist::GetFilenameWithoutExtension(fib_file); - - itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); - fitter->SetTractograms(input_reference); - fitter->SetFitIndividualFibers(single_fib); - fitter->SetMaxIterations(max_iter); - fitter->SetGradientTolerance(g_tol); - fitter->SetLambda(lambda); - fitter->SetFilterOutliers(filter_outliers); - fitter->SetPeakImage(peak_image); - fitter->SetVerbose(true); - fitter->SetDeepCopy(false); - fitter->SetMaskImage(mask); - fitter->Update(); - -// fitter->GetTractograms().at(0)->SetFiberWeights(fitter->GetCoverage()); -// fitter->GetTractograms().at(0)->ColorFibersByFiberWeights(false, false); - - mitk::IOUtil::Save(fitter->GetTractograms().at(0), outRoot + "0_" + name + ".fib"); - peak_image = fitter->GetUnderexplainedImage(); - - itk::ImageFileWriter< PeakImgType >::Pointer writer = itk::ImageFileWriter< PeakImgType >::New(); - writer->SetInput(peak_image); - writer->SetFileName(outRoot + boost::lexical_cast(iteration) + "_" + name + ".nrrd"); - writer->Update(); - - double coverage = fitter->GetCoverage(); - MITK_INFO << "Iteration: " << iteration; - MITK_INFO << std::fixed << "Coverage: " << setprecision(2) << 100.0*coverage << "%"; -// fitter->SetPeakImage(peak_image); - - while (!input_candidates.empty()) - { - streambuf *old = cout.rdbuf(); // <-- save - stringstream ss; - std::cout.rdbuf (ss.rdbuf()); // <-- redirect - - double next_coverage = 0; - mitk::FiberBundle::Pointer best_candidate = nullptr; - for (auto fib : input_candidates) - { - - // WHY NECESSARY AGAIN?? - itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); - fitter->SetFitIndividualFibers(single_fib); - fitter->SetMaxIterations(max_iter); - fitter->SetGradientTolerance(g_tol); - fitter->SetLambda(lambda); - fitter->SetFilterOutliers(filter_outliers); - fitter->SetVerbose(false); - fitter->SetPeakImage(peak_image); - fitter->SetDeepCopy(false); - fitter->SetMaskImage(mask); - // ****************************** - fitter->SetTractograms({fib}); - fitter->Update(); - - double candidate_coverage = fitter->GetCoverage(); - - if (candidate_coverage>next_coverage) - { - next_coverage = candidate_coverage; - if ((1.0-coverage) * next_coverage >= min_gain) - { - best_candidate = fitter->GetTractograms().at(0); - peak_image = fitter->GetUnderexplainedImage(); - } - } - } - - if (best_candidate.IsNull()) - { - std::cout.rdbuf (old); // <-- restore - break; - } - -// fitter->SetPeakImage(peak_image); -// best_candidate->SetFiberWeights((1.0-coverage) * next_coverage); -// best_candidate->ColorFibersByFiberWeights(false, false); - - coverage += (1.0-coverage) * next_coverage; - - int i=0; - std::vector< mitk::FiberBundle::Pointer > remaining_candidates; - std::vector< string > remaining_candidate_files; - for (auto fib : input_candidates) - { - if (fib!=best_candidate) - { - remaining_candidates.push_back(fib); - remaining_candidate_files.push_back(candidate_tract_files.at(i)); - } - else - name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(i)); - ++i; - } - input_candidates = remaining_candidates; - candidate_tract_files = remaining_candidate_files; - - iteration++; - mitk::IOUtil::Save(best_candidate, outRoot + boost::lexical_cast(iteration) + "_" + name + ".fib"); - writer->SetInput(peak_image); - writer->SetFileName(outRoot + boost::lexical_cast(iteration) + "_" + name + ".nrrd"); - writer->Update(); - std::cout.rdbuf (old); // <-- restore - - MITK_INFO << "Iteration: " << iteration; - MITK_INFO << std::fixed << "Coverage: " << setprecision(2) << 100.0*coverage << "% (+" << 100*(1.0-coverage) * next_coverage << "%)"; - } - - clock.Stop(); - int h = clock.GetTotal()/3600; - int m = ((int)clock.GetTotal()%3600)/60; - int s = (int)clock.GetTotal()%60; - MITK_INFO << "Plausibility estimation took " << h << "h, " << m << "m and " << s << "s"; - } - catch (itk::ExceptionObject e) - { - std::cout << e; - return EXIT_FAILURE; - } - catch (std::exception e) - { - std::cout << e.what(); - return EXIT_FAILURE; - } - catch (...) - { - std::cout << "ERROR!?!"; - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/documentation/UserManual/QmitkFiberProcessingViewUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/documentation/UserManual/QmitkFiberProcessingViewUserManual.dox index 586d5dd171..46f70c978c 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/documentation/UserManual/QmitkFiberProcessingViewUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/documentation/UserManual/QmitkFiberProcessingViewUserManual.dox @@ -1,9 +1,9 @@ /** \page org_mitk_views_fiberprocessing Fiber Processing -This view provides tools to extract subbundles from a given fiber bundle, to remove unwanted fibers (e.g. via length, curvature and directional constraints) and to modify the properties of a fiber bundles such as coloring or fiber sampling. +This view provides tools to extract subbundles from a given fiber bundle, to remove unwanted fibers (e.g. via length, curvature, directional and fiber weight constraints) and to modify the properties of a fiber bundles such as coloring or fiber sampling. Fiber Extraction: Place ROIs in the 2D render widgets (cricles or polygons) and extract fibers from the bundle that pass through these ROIs by selecting the according ROI and fiber bundle in the datamanger and starting the extraction. The ROIs can be combined via logical operations. All fibers that pass through the thus generated composite ROI are extracted. The extraction can also be performed using 3D ROIs represented as binary mask images. In this extraction method, the logical operations are not implemented at the moment. */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.cpp index 3e3cee250e..e313b9abb3 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.cpp @@ -1,1546 +1,1577 @@ /*=================================================================== 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 #include // Qmitk #include "QmitkFiberProcessingView.h" // 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() : QmitkAbstractView() , m_Controls( 0 ) , m_CircleCounter(0) , m_PolygonCounter(0) , m_UpsamplingFactor(1) { } // Destructor QmitkFiberProcessingView::~QmitkFiberProcessingView() { RemoveObservers(); } 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 isOdf = mitk::NodePredicateDataType::New("OdfImage"); mitk::NodePredicateOr::Pointer isDiffusionImage = mitk::NodePredicateOr::New(isDwi, isDti); isDiffusionImage = mitk::NodePredicateOr::New(isDiffusionImage, isOdf); mitk::NodePredicateNot::Pointer noDiffusionImage = mitk::NodePredicateNot::New(isDiffusionImage); mitk::NodePredicateAnd::Pointer 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::SetFocus() { m_Controls->toolBoxx->setFocus(); } void QmitkFiberProcessingView::Modify() { switch (m_Controls->m_ModificationMethodBox->currentIndex()) { case 0: { ResampleSelectedBundlesSpline(); break; } case 1: { ResampleSelectedBundlesLinear(); break; } case 2: { CompressSelectedBundles(); break; } case 3: { DoImageColorCoding(); break; } case 4: { MirrorFibers(); break; } case 5: { WeightFibers(); break; } case 6: { DoCurvatureColorCoding(); break; } case 7: { DoWeightColorCoding(); 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; } + case 5: + { + ApplyWeightThreshold(); + 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(nullptr, "No output generated:", "The resulting fiber bundle contains no fibers."); else if (!fib->RemoveLongFibers(maxLength)) QMessageBox::information(nullptr, "No output generated:", "The resulting fiber bundle contains no fibers."); } RenderingManager::GetInstance()->RequestUpdateAll(); } +void QmitkFiberProcessingView::ApplyWeightThreshold() +{ + float thr = this->m_Controls->m_WeightThresholdBox->value(); + std::vector< DataNode::Pointer > nodes = m_SelectedFB; + for (auto node : nodes) + { + mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); + + mitk::FiberBundle::Pointer newFib = fib->FilterByWeights(thr); + if (newFib->GetNumFibers()>0) + { + newFib->ColorFibersByFiberWeights(false, true); + node->SetData(newFib); + } + else + QMessageBox::information(nullptr, "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(nullptr, "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()); itkUCharImageType::Pointer mask = itkUCharImageType::New(); mitk::CastToItkImage(mitkMask, mask); mitk::FiberBundle::Pointer newFib = fib->RemoveFibersOutside(mask, removeInside); if (newFib->GetNumFibers()<=0) { QMessageBox::information(nullptr, "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(), m_Controls->m_FiberExtractionFractionBox->value()); if (newFib->GetNumFibers()<=0) { QMessageBox::information(nullptr, "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()); GetDataStorage()->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->GetDataStorage()->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(unsigned 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::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_RemoveByWeightFrame->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); m_Controls->m_ColorMapBox->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; + case 5: + m_Controls->m_RemoveByWeightFrame->setVisible(true); + if ( fibSelected ) + m_Controls->m_RemoveButton->setEnabled(true); + break; } switch ( m_Controls->m_ModificationMethodBox->currentIndex() ) { case 0: m_Controls->m_SmoothFibersFrame->setVisible(true); break; case 1: m_Controls->m_SmoothFibersFrame->setVisible(true); break; case 2: m_Controls->m_CompressFibersFrame->setVisible(true); break; case 3: m_Controls->m_ColorFibersFrame->setVisible(true); m_Controls->m_ColorMapBox->setVisible(true); break; case 4: m_Controls->m_MirrorFibersFrame->setVisible(true); if (m_SelectedSurfaces.size()>0) m_Controls->m_ModifyButton->setEnabled(true); break; case 5: m_Controls->m_BundleWeightFrame->setVisible(true); break; case 6: m_Controls->m_ColorFibersFrame->setVisible(true); break; case 7: m_Controls->m_ColorFibersFrame->setVisible(true); break; } // 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 ) { for (auto fnode: m_SelectedFB) if (node == fnode) { m_SelectedFB.clear(); break; } berry::IWorkbenchPart::Pointer nullPart; QList nodes; OnSelectionChanged(nullPart, nodes); } void QmitkFiberProcessingView::NodeAdded(const mitk::DataNode* ) { if (!m_Controls->m_InteractiveBox->isChecked()) { berry::IWorkbenchPart::Pointer nullPart; QList nodes; OnSelectionChanged(nullPart, nodes); } } void QmitkFiberProcessingView::OnEndInteraction() { if (m_Controls->m_InteractiveBox->isChecked()) ExtractWithPlanarFigure(true); } void QmitkFiberProcessingView::AddObservers() { typedef itk::SimpleMemberCommand< QmitkFiberProcessingView > SimpleCommandType; for (auto node : m_SelectedPF) { mitk::PlanarFigure* figure = dynamic_cast(node->GetData()); if (figure!=nullptr) { figure->RemoveAllObservers(); // add observer for event when interaction with figure starts SimpleCommandType::Pointer endInteractionCommand = SimpleCommandType::New(); endInteractionCommand->SetCallbackFunction( this, &QmitkFiberProcessingView::OnEndInteraction); m_EndInteractionObserverTag = figure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), endInteractionCommand ); } } } void QmitkFiberProcessingView::RemoveObservers() { for (auto node : m_SelectedPF) { mitk::PlanarFigure* figure = dynamic_cast(node->GetData()); if (figure!=nullptr) figure->RemoveAllObservers(); } } void QmitkFiberProcessingView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { RemoveObservers(); //reset existing Vectors containing FiberBundles and PlanarFigures from a previous selection std::vector lastSelectedFB = m_SelectedFB; m_SelectedFB.clear(); m_SelectedPF.clear(); m_SelectedSurfaces.clear(); m_SelectedImage = nullptr; m_MaskImageNode = nullptr; for (auto node: nodes) { 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 we perform interactive fiber extraction, we want to avoid auto-selection of the extracted bundle if (m_SelectedFB.empty() && m_Controls->m_InteractiveBox->isChecked()) m_SelectedFB = lastSelectedFB; // if no fibers or surfaces are selected, select topmost if (m_SelectedFB.empty() && m_SelectedSurfaces.empty()) { int maxLayer = 0; itk::VectorContainer::ConstPointer nodes = this->GetDataStorage()->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 no plar figure is selected, select topmost if (m_SelectedPF.empty()) { int maxLayer = 0; itk::VectorContainer::ConstPointer nodes = this->GetDataStorage()->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)); } } } AddObservers(); 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::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 ); RemoveObservers(); 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); AddObservers(); UpdateGui(); } void QmitkFiberProcessingView::ExtractWithPlanarFigure(bool interactive) { if ( m_SelectedFB.empty() || m_SelectedPF.empty() ){ QMessageBox::information( nullptr, "Warning", "No fibe bundle selected!"); return; } try { 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 (interactive && m_Controls->m_InteractiveBox->isChecked()) { if (m_InteractiveNode.IsNull()) { m_InteractiveNode = mitk::DataNode::New(); QString name("Interactive"); m_InteractiveNode->SetName(name.toStdString()); GetDataStorage()->Add(m_InteractiveNode); } float op = 5.0/sqrt(fib->GetNumFibers()); float currentOp = 0; fiberBundles.at(i)->GetFloatProperty("opacity", currentOp); if (currentOp!=op) { fib->SetFiberColors(255, 255, 255); fiberBundles.at(i)->SetFloatProperty("opacity", op); fiberBundles.at(i)->SetBoolProperty("Fiber2DfadeEFX", false); } m_InteractiveNode->SetData(extFB); } else { if (extFB->GetNumFibers()<=0) { QMessageBox::information(nullptr, "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 += "*"; node->SetName(name.toStdString()); fiberBundles.at(i)->SetVisibility(false); GetDataStorage()->Add(node); } } } catch(const std::out_of_range& ) { QMessageBox::warning( nullptr, "Fiber extraction failed", "Did you only create the planar figure, using the circle or polygon button, but forgot to actually place it in the image afterwards? \nAfter creating a planar figure, simply left-click at the desired position in the image or on the tractogram to place it."); } } 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); RemoveObservers(); m_SelectedPF.clear(); m_SelectedPF.push_back(newPFCNode); AddObservers(); 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); RemoveObservers(); 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); RemoveObservers(); AddCompositeToDatastorage(newPFCNode, m_SelectedPF); m_SelectedPF.clear(); m_SelectedPF.push_back(newPFCNode); AddObservers(); 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( nullptr, "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( nullptr, "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( nullptr, "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(nullptr, "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::ResampleSelectedBundlesSpline() { 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::ResampleSelectedBundlesLinear() { double factor = this->m_Controls->m_SmoothFibersBox->value(); for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); fib->ResampleLinear(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(nullptr, "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(), m_Controls->m_NormalizeColorValues->isChecked()); } if (auto renderWindowPart = this->GetRenderWindowPart()) { renderWindowPart->RequestUpdate(); } } void QmitkFiberProcessingView::DoCurvatureColorCoding() { for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); fib->ColorFibersByCurvature(m_Controls->m_FiberOpacityBox->isChecked(), m_Controls->m_NormalizeColorValues->isChecked()); } if (auto renderWindowPart = this->GetRenderWindowPart()) { renderWindowPart->RequestUpdate(); } } void QmitkFiberProcessingView::DoWeightColorCoding() { for (auto node : m_SelectedFB) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); fib->ColorFibersByFiberWeights(m_Controls->m_FiberOpacityBox->isChecked(), m_Controls->m_NormalizeColorValues->isChecked()); } if (auto renderWindowPart = this->GetRenderWindowPart()) { renderWindowPart->RequestUpdate(); } } 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(); } if (auto renderWindowPart = this->GetRenderWindowPart()) { renderWindowPart->RequestUpdate(); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.h index 522d304afe..4651a3f7ed 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingView.h @@ -1,199 +1,200 @@ /*=================================================================== 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. */ class QmitkFiberProcessingView : 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: typedef itk::Image< unsigned char, 3 > itkUCharImageType; static const std::string VIEW_ID; QmitkFiberProcessingView(); virtual ~QmitkFiberProcessingView(); virtual void CreateQtPartControl(QWidget *parent) override; /// /// Sets the focus to an internal widget. /// virtual void SetFocus() 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 = nullptr, mitk::BaseProperty *property = nullptr ); protected: void MirrorFibers(); ///< mirror bundle on the specified plane void ResampleSelectedBundlesSpline(); ///< void ResampleSelectedBundlesLinear(); ///< void DoImageColorCoding(); ///< color fibers by selected scalar image void DoWeightColorCoding(); ///< color fibers by their respective weights void DoCurvatureColorCoding(); ///< color fibers by curvature void CompressSelectedBundles(); ///< remove points below certain error threshold void WeightFibers(); + void ApplyWeightThreshold(); 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(bool interactive=false); void OnEndInteraction(); /// \brief called by QmitkAbstractView when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; Ui::QmitkFiberProcessingViewControls* m_Controls; /** 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; unsigned int m_StartInteractionObserverTag; unsigned int m_EndInteractionObserverTag; mitk::DataNode::Pointer m_InteractiveNode; void AddCompositeToDatastorage(mitk::DataNode::Pointer pfc, std::vector children, mitk::DataNode::Pointer parentNode=nullptr); 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; void RemoveObservers(); void AddObservers(); }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui index d49bc8afea..3df18fd8fc 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui @@ -1,1450 +1,1502 @@ QmitkFiberProcessingViewControls 0 0 385 - 564 + 684 Form 0 5 0 0 - 353 + 367 382 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 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 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 Interactive Extraction 0 0 Extract using planar figures Extract using binary ROI image QFrame::NoFrame QFrame::Raised 0 0 0 0 Both ends true 1.000000000000000 0.100000000000000 Extract fibers: 0 0 Ending in mask Not ending in mask Passing mask Not passing mask Min. overlap: 0 0 - 353 - 371 + 367 + 408 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 + If unchecked, the fiber exceeding the threshold will be split in two instead of removed. - - - - - Max. Length: + Remove Fiber - - - - - - Min. Length: + + false - - - - Maximum fiber length in mm - - - 0 - - - 999999999 + + + + QFrame::NoFrame - - 300 + + 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 + + + 10.000000000000000 + + + + 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 - - + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + - If unchecked, the fiber exceeding the threshold will be split in two instead of removed. + Minimum fiber length in mm + + + 0 + + + 999999999 + + 20 + + + + + - Remove Fiber + Max. Length: - - false + + + + + + Min. Length: - - - - QFrame::NoFrame + + + + Maximum fiber length in mm - - QFrame::Raised + + 0 + + + 999999999 + + + 300 - - - 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 - - - 10.000000000000000 - - - - - + false 0 0 200 16777215 11 Remove - + Qt::Vertical 20 40 + + + + + 0 + 0 + + + + + Remove fibers in direction + + + + + Remove fibers by length + + + + + Remove fibers by curvature + + + + + Remove fiber parts outside mask + + + + + Remove fiber parts inside mask + + + + + Remove fibers by weight + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Weight threshold: + + + + + + + Only fibers with weight larger than this threshold are kept. + + + 5 + + + 0.100000000000000 + + + + + + 0 0 - 353 - 364 + 367 + 408 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 If checked, the image values are not only used to color the fibers but are also used as opaxity values. Values as opacity false Scalar map: The values used to color the fibers are min-max normalized. If not checked, the values should be between 0 and 1. Normalize values true 0 0 Resample fibers (spline) Resample fibers (linear) Compress fibers Color fibers by scalar map (e.g. FA) Mirror fibers Weight bundle Color fibers by curvature Color fibers by fiber weights 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 367 - 152 + 165 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