diff --git a/Modules/FiberDissection/CMakeLists.txt b/Modules/FiberDissection/CMakeLists.txt new file mode 100644 index 0000000..14605b9 --- /dev/null +++ b/Modules/FiberDissection/CMakeLists.txt @@ -0,0 +1,5 @@ +MITK_CREATE_MODULE( + SUBPROJECTS MITK-Diffusion + INCLUDE_DIRS Interactor ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS MitkDiffusionCore +) diff --git a/Modules/FiberDissection/Interactor/mitkStreamlineInteractor.cpp b/Modules/FiberDissection/Interactor/mitkStreamlineInteractor.cpp new file mode 100644 index 0000000..abc7696 --- /dev/null +++ b/Modules/FiberDissection/Interactor/mitkStreamlineInteractor.cpp @@ -0,0 +1,344 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "mitkStreamlineInteractor.h" +//#include "mitkStreamlineMapper2D.h" + +// MITK includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// VTK includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +mitk::StreamlineInteractor::StreamlineInteractor() +{ + m_ColorForHighlight[0] = 1.0; + m_ColorForHighlight[1] = 0.5; + m_ColorForHighlight[2] = 0.0; + m_ColorForHighlight[3] = 1.0; + + // TODO if we want to get this configurable, the this is the recipe: + // - make the 2D mapper add corresponding properties to control "enabled" and "color" + // - make the interactor evaluate those properties + // - in an ideal world, modify the state machine on the fly and skip mouse move handling +} + +mitk::StreamlineInteractor::~StreamlineInteractor() +{ +} + +void mitk::StreamlineInteractor::ConnectActionsAndFunctions() +{ +// CONNECT_CONDITION("isoverstreamline", HasPickedHandle); + CONNECT_FUNCTION("addnegstreamline", AddStreamlineNegBundle); + CONNECT_FUNCTION("addposstreamline", AddStreamlinePosBundle); +// CONNECT_FUNCTION("FeedUndoStack", FeedUndoStack); +} + +void mitk::StreamlineInteractor::SetNegativeNode(DataNode *node) +{ + + DataInteractor::SetDataNode(node); + m_NegStreamline= dynamic_cast(node->GetData()); + + MITK_INFO << "Negative Node added"; +} + +void mitk::StreamlineInteractor::SetToLabelNode(DataNode *node) +{ + DataInteractor::SetDataNode(node); + + if (node && node->GetData()) + { + m_manStreamline = dynamic_cast(node->GetData()); + MITK_INFO << "Label node added"; + } +} + +void mitk::StreamlineInteractor::SetPositiveNode(DataNode *node) +{ + + DataInteractor::SetDataNode(node); + m_PosStreamline= dynamic_cast(node->GetData()); + + + MITK_INFO << "Positive Node added"; + } + +void mitk::StreamlineInteractor::AddStreamlinePosBundle(StateMachineAction *, InteractionEvent *interactionEvent) +{ + MITK_INFO << "PositiveBundle clicked"; +// auto positionEvent = dynamic_cast(interactionEvent); +// if (positionEvent == nullptr) +// { +// return; +// } +// return true; + auto positionEvent = dynamic_cast(interactionEvent); + if (positionEvent == nullptr) + { + MITK_INFO << "no position"; + } + + if (interactionEvent->GetSender()->GetMapperID() == BaseRenderer::Standard2D) + { +// m_PickedHandle = PickFrom2D(positionEvent); + MITK_INFO << "2D"; + } + else + { + BaseRenderer *renderer = positionEvent->GetSender(); + + auto &picker = m_Picker[renderer]; + if (picker == nullptr) + { + + + picker = vtkSmartPointer::New(); + picker->SetTolerance(0.01); + auto mapper = GetDataNode()->GetMapper(BaseRenderer::Standard3D); + + + auto vtk_mapper = dynamic_cast(mapper); + if (vtk_mapper) + { // doing this each time is bizarre + picker->AddPickList(vtk_mapper->GetVtkProp(renderer)); + picker->PickFromListOn(); + } + } + + auto displayPosition = positionEvent->GetPointerPositionOnScreen(); +// MITK_INFO << displayPosition; + picker->Pick(displayPosition[0], displayPosition[1], 0, positionEvent->GetSender()->GetVtkRenderer()); + + vtkIdType pickedCellID = picker->GetCellId(); + + MITK_INFO << picker->GetCellId(); + MITK_INFO << "Number of Cells"; +// MITK_INFO << m_PosStreamline->GetFiberPolyData()->GetNumberOfCells(); + + + + if (picker->GetCellId()==-1) + { + MITK_INFO << "Nothing picked"; + } + else { + + + vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); + MITK_INFO << vNewPolyData->GetNumberOfLines (); + vtkSmartPointer vNewLines = vtkSmartPointer::New(); + vtkSmartPointer vNewPoints = vtkSmartPointer::New(); + + unsigned int counter = 0; + for ( int i=0; iGetFiberPolyData()->GetNumberOfCells(); i++) + { + vtkCell* cell = m_PosStreamline->GetFiberPolyData()->GetCell(i); + auto numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + + vtkSmartPointer container = vtkSmartPointer::New(); + for (unsigned 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++; + + } + + + + vtkCell* cell = m_manStreamline->GetFiberPolyData()->GetCell(pickedCellID); + auto numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + + vtkSmartPointer container = vtkSmartPointer::New(); + for (unsigned int j=0; jGetPoint(j, p); + + vtkIdType id = vNewPoints->InsertNextPoint(p); + container->GetPointIds()->InsertNextId(id); + } + vNewLines->InsertNextCell(container); + + vNewPolyData->SetPoints(vNewPoints); + vNewPolyData->SetLines(vNewLines); + + // m_PosStreamline = mitk::FiberBundle::New(vNewPolyData); + m_PosStreamline->GetFiberPolyData()->SetPoints(vNewPoints); + m_PosStreamline->GetFiberPolyData()->SetLines(vNewLines); + m_PosStreamline->SetFiberColors(0, 255, 0); + + m_manStreamline->GetFiberPolyData()->DeleteCell(pickedCellID); + m_manStreamline->GetFiberPolyData()->RemoveDeletedCells(); + + MITK_INFO << m_manStreamline->GetFiberPolyData()->GetNumberOfCells(); + MITK_INFO << m_PosStreamline->GetFiberPolyData()->GetNumberOfCells(); + } + } + } + +void mitk::StreamlineInteractor::AddStreamlineNegBundle(StateMachineAction *, InteractionEvent *interactionEvent) +{ + MITK_INFO << "NegativeBundle clicked"; +// auto positionEvent = dynamic_cast(interactionEvent); +// if (positionEvent == nullptr) +// { +// return; +// } +// return true; + auto positionEvent = dynamic_cast(interactionEvent); + if (positionEvent == nullptr) + { + MITK_INFO << "no position"; + } + + if (interactionEvent->GetSender()->GetMapperID() == BaseRenderer::Standard2D) + { +// m_PickedHandle = PickFrom2D(positionEvent); + MITK_INFO << "2D"; + } + else + { + BaseRenderer *renderer = positionEvent->GetSender(); + + auto &picker = m_Picker[renderer]; + if (picker == nullptr) + { + + + picker = vtkSmartPointer::New(); + picker->SetTolerance(0.01); + auto mapper = GetDataNode()->GetMapper(BaseRenderer::Standard3D); + + + auto vtk_mapper = dynamic_cast(mapper); + if (vtk_mapper) + { // doing this each time is bizarre + picker->AddPickList(vtk_mapper->GetVtkProp(renderer)); + picker->PickFromListOn(); + } + } + + auto displayPosition = positionEvent->GetPointerPositionOnScreen(); +// MITK_INFO << displayPosition; + picker->Pick(displayPosition[0], displayPosition[1], 0, positionEvent->GetSender()->GetVtkRenderer()); + + vtkIdType pickedCellID = picker->GetCellId(); + + MITK_INFO << picker->GetCellId(); + + if (picker->GetCellId()==-1) + { + MITK_INFO << "Nothing picked"; + } + else + { + vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); + MITK_INFO << vNewPolyData->GetNumberOfLines (); + vtkSmartPointer vNewLines = vtkSmartPointer::New(); + vtkSmartPointer vNewPoints = vtkSmartPointer::New(); + + unsigned int counter = 0; + for ( int i=0; iGetFiberPolyData()->GetNumberOfCells(); i++) + { + vtkCell* cell = m_NegStreamline->GetFiberPolyData()->GetCell(i); + auto numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + + vtkSmartPointer container = vtkSmartPointer::New(); + for (unsigned 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++; + + } + + + + vtkCell* cell = m_manStreamline->GetFiberPolyData()->GetCell(pickedCellID); + auto numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); + + vtkSmartPointer container = vtkSmartPointer::New(); + for (unsigned int j=0; jGetPoint(j, p); + + vtkIdType id = vNewPoints->InsertNextPoint(p); + container->GetPointIds()->InsertNextId(id); + } + vNewLines->InsertNextCell(container); + + vNewPolyData->SetPoints(vNewPoints); + vNewPolyData->SetLines(vNewLines); + + // m_NegStreamline = mitk::FiberBundle::New(vNewPolyData); + m_NegStreamline->GetFiberPolyData()->SetPoints(vNewPoints); + m_NegStreamline->GetFiberPolyData()->SetLines(vNewLines); + m_NegStreamline->SetFiberColors(255, 0, 0); + + m_manStreamline->GetFiberPolyData()->DeleteCell(pickedCellID); + m_manStreamline->GetFiberPolyData()->RemoveDeletedCells(); + + MITK_INFO << m_manStreamline->GetFiberPolyData()->GetNumberOfCells(); + MITK_INFO << m_NegStreamline->GetFiberPolyData()->GetNumberOfCells(); + } + + + + + + + + + + } + + + + } diff --git a/Modules/FiberDissection/Interactor/mitkStreamlineInteractor.h b/Modules/FiberDissection/Interactor/mitkStreamlineInteractor.h new file mode 100644 index 0000000..ce9f4fd --- /dev/null +++ b/Modules/FiberDissection/Interactor/mitkStreamlineInteractor.h @@ -0,0 +1,105 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#ifndef mitkStreamlineInteractor_h +#define mitkStreamlineInteractor_h + + +// MITK includes +#include +#include +#include +#include + +// VTK includes +#include +#include + +// System includes +#include + +#include "MitkFiberDissectionExports.h" + +namespace mitk +{ + class InteractionPositionEvent; + + //! Data interactor to pick streamlines via interaction + //! with a mitk::Streamline. + //! + //! + //! To determine what parts of the object are clicked during interaction, + //! the mappers (2D: custom mapper, 3D: regular surface mapper) are asked + //! for their VTK objects, picking is performed, and the picked point is + //! forwarded to the Streamline object for interpretation. + //! + //! The interactor fills the undo/redo stack with operations on the modified geometry. + //! + //! \sa Streamline + class MITKFIBERDISSECTION_EXPORT StreamlineInteractor : public DataInteractor + { + public: + mitkClassMacro(StreamlineInteractor, DataInteractor); + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + + //! The node holding the Fiberbundle for visual feedback. + //! This is the node that the interactor is primarily working on + //! (calls DataInteractor::SetDataNode). + + void SetNegativeNode(DataNode *node); + void SetToLabelNode(DataNode *node); + void SetPositiveNode(DataNode *node); + + protected: + + void AddStreamlineNegBundle(StateMachineAction *, InteractionEvent *interactionEvent); + + void AddStreamlinePosBundle(StateMachineAction *, InteractionEvent *interactionEvent); + + + std::map> m_Picker; + + private: + StreamlineInteractor(); + ~StreamlineInteractor() override; + + //! Setup the relation between the XML state machine and this object's methods. + void ConnectActionsAndFunctions() override; + + //! State machine condition: successful Streamline picking + //! \return true when any part of the Streamline has been picked. +// bool HasPickedHandle(const InteractionEvent *); + +// void DecideInteraction(StateMachineAction *, InteractionEvent *interactionEvent); + +// //! Pick a Streamline handle from a 2D event (passing by the 2D mapper) +// Streamline::HandleType PickFrom2D(const InteractionPositionEvent *positionEvent); + +// //! Pick a Streamline handle from a 3D event +// //! (passing by the general surface mapper and the Streamline object) +// Streamline::HandleType PickFrom3D(const InteractionPositionEvent *positionEvent); + +// void UpdateHandleHighlight(); + + //! the Streamline used for visual feedback and picking + mitk::FiberBundle::Pointer m_NegStreamline; + mitk::FiberBundle::Pointer m_PosStreamline; + mitk::FiberBundle::Pointer m_manStreamline; + + vtkSmartPointer m_extracted_streamline; + + double m_ColorForHighlight[4]; + + }; +} +#endif diff --git a/Modules/FiberDissection/MachineLearning/mitkStreamlineFeatureExtractor.cpp b/Modules/FiberDissection/MachineLearning/mitkStreamlineFeatureExtractor.cpp new file mode 100644 index 0000000..4420b63 --- /dev/null +++ b/Modules/FiberDissection/MachineLearning/mitkStreamlineFeatureExtractor.cpp @@ -0,0 +1,176 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center. + +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ +#include "mitkStreamlineFeatureExtractor.h" + +#define _USE_MATH_DEFINES +#include +#include +#include +#include + +namespace mitk{ + +StreamlineFeatureExtractor::StreamlineFeatureExtractor() + : m_NumPoints(12) +{ + +} + + +void TractClusteringFilter::SetTractogram(const mitk::FiberBundle::Pointer &Tractogram) +{ + m_Tractogram = Tractogram; +} + + + +void StreamlineFeatureExtractor::GenerateData() +{ + m_OutTractograms.clear(); + + mitk::FiberBundle::Pointer inputPrototypes = mitk::IOUtil::Load("/home/r948e/E132-Projekte/Projects/2022_Peretzke_Interactive_Fiber_Dissection/mitk_diff/prototypes_599671.trk"); + + T_prototypes = ResampleFibers(inputPrototypes); + + + +// if (m_Metrics.empty()) +// { +// mitkThrow() << "No metric selected!"; +// return; +// } + +// T = ResampleFibers(m_Tractogram); +// if (T.empty()) +// { +// MITK_INFO << "No fibers in tractogram!"; +// return; +// } + +// std::vector< unsigned int > f_indices; +// for (unsigned int i=0; i clusters; +// if (m_InCentroids.IsNull()) +// { +// MITK_INFO << "Clustering fibers"; +// clusters = ClusterStep(f_indices, m_Distances); +// MITK_INFO << "Number of clusters: " << clusters.size(); +// clusters = MergeDuplicateClusters2(clusters); +// std::sort(clusters.begin(),clusters.end()); +// } +// else +// { +// std::vector > centroids = ResampleFibers(m_InCentroids); +// if (centroids.empty()) +// { +// MITK_INFO << "No fibers in centroid tractogram!"; +// return; +// } +// MITK_INFO << "Clustering with input centroids"; +// clusters = AddToKnownClusters(f_indices, centroids); +// no_match = clusters.back(); +// clusters.pop_back(); +// MITK_INFO << "Number of clusters: " << clusters.size(); +// clusters = MergeDuplicateClusters2(clusters); +// } + +// MITK_INFO << "Clustering finished"; +// int max = clusters.size()-1; +// if (m_MaxClusters>0 && clusters.size()-1>m_MaxClusters) +// max = m_MaxClusters; +// m_DiscardedClusters = 0; +// for (int i=clusters.size()-1; i>=0; --i) +// { +// Cluster c = clusters.at(i); +// if ( c.n>=(int)m_MinClusterSize && !(m_MaxClusters>0 && clusters.size()-i>m_MaxClusters) ) +// { +// m_OutClusters.push_back(c); + +// vtkSmartPointer weights = vtkSmartPointer::New(); +// vtkSmartPointer pTmp = m_Tractogram->GeneratePolyDataByIds(c.I, weights); +// mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(pTmp); +// if (max>0) +// fib->SetFiberWeights((float)i/max); +// m_OutTractograms.push_back(fib); +// m_OutFiberIndices.push_back(c.I); + +// // create centroid +// vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); +// vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); +// vtkSmartPointer polyData = vtkSmartPointer::New(); +// vtkSmartPointer container = vtkSmartPointer::New(); +// vnl_matrix centroid_points = c.h / c.n; +// for (unsigned int j=0; jInsertNextPoint(p); +// container->GetPointIds()->InsertNextId(id); +// } +// vtkNewCells->InsertNextCell(container); +// polyData->SetPoints(vtkNewPoints); +// polyData->SetLines(vtkNewCells); +// mitk::FiberBundle::Pointer centroid = mitk::FiberBundle::New(polyData); +// centroid->SetFiberColors(255, 255, 255); +// m_OutCentroids.push_back(centroid); +// } +// else +// { +// m_DiscardedClusters++; +// } +// } +// MITK_INFO << "Final number of clusters: " << m_OutTractograms.size() << " (discarded " << m_DiscardedClusters << " clusters)"; + +// int w = 0; +// for (auto fib : m_OutTractograms) +// { +// if (m_OutTractograms.size()>1) +// { +// fib->SetFiberWeights((float)w/(m_OutTractograms.size()-1)); +// m_OutCentroids.at(w)->SetFiberWeights((float)w/(m_OutTractograms.size()-1)); +// } +// else +// { +// fib->SetFiberWeights(1); +// m_OutCentroids.at(w)->SetFiberWeights(1); +// } +// fib->ColorFibersByFiberWeights(false, mitk::LookupTable::JET); +// ++w; +// } + +// if (no_match.n>0) +// { +// vtkSmartPointer weights = vtkSmartPointer::New(); +// vtkSmartPointer pTmp = m_Tractogram->GeneratePolyDataByIds(no_match.I, weights); +// mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(pTmp); +// fib->SetFiberColors(0, 0, 0); +// m_OutFiberIndices.push_back(no_match.I); +// m_OutTractograms.push_back(fib); +// } +//} + +} + + + + diff --git a/Modules/FiberDissection/MachineLearning/mitkStreamlineFeatureExtractor.h b/Modules/FiberDissection/MachineLearning/mitkStreamlineFeatureExtractor.h new file mode 100644 index 0000000..f10e744 --- /dev/null +++ b/Modules/FiberDissection/MachineLearning/mitkStreamlineFeatureExtractor.h @@ -0,0 +1,72 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center. + +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ +#ifndef StreamlineFeatureExtractor_h +#define StreamlineFeatureExtractor_h + +// MITK +#include +#include +#include +#include + +// ITK +#include + +// VTK +#include +#include +#include +#include +#include + +namespace mitk{ + +/** +* \brief */ + +class MITKFIBERDISSECTION_EXPORT StreamlineFeatureExtractor +{ +public: + + + StreamlineFeatureExtractor(); + ~StreamlineFeatureExtractor(); + + typedef itk::Image< float, 3 > FloatImageType; + typedef itk::Image< unsigned char, 3 > UcharImageType; + + void Update(){ + this->GenerateData(); + } + + + +protected: + + void GenerateData(); + std::vector< vnl_matrix > ResampleFibers(FiberBundle::Pointer tractogram); + + + + unsigned int m_NumPoints; + mitk::FiberBundle::Pointer m_Tractogram; + std::vector > T_prototypes; + std::vector > T_Tractogram; + +}; +} + +#endif diff --git a/Modules/FiberDissection/files.cmake b/Modules/FiberDissection/files.cmake new file mode 100644 index 0000000..ee910a5 --- /dev/null +++ b/Modules/FiberDissection/files.cmake @@ -0,0 +1,13 @@ +set(H_FILES + Interactor/mitkStreamlineInteractor.h +) + +set(CPP_FILES + Interactor/mitkStreamlineInteractor.cpp +) + +set(RESOURCE_FILES + # "Interactions" prefix forced by mitk::StateMachine + Interactions/Streamline3DStates.xml + Interactions/Streamline3DConfig.xml +) diff --git a/Modules/FiberDissection/resource/Interactions/Streamline3DConfig.xml b/Modules/FiberDissection/resource/Interactions/Streamline3DConfig.xml new file mode 100644 index 0000000..3377f69 --- /dev/null +++ b/Modules/FiberDissection/resource/Interactions/Streamline3DConfig.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Modules/FiberDissection/resource/Interactions/Streamline3DStates.xml b/Modules/FiberDissection/resource/Interactions/Streamline3DStates.xml new file mode 100644 index 0000000..76dcdf1 --- /dev/null +++ b/Modules/FiberDissection/resource/Interactions/Streamline3DStates.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Modules/ModuleList.cmake b/Modules/ModuleList.cmake index ac97051..926de49 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,8 +1,9 @@ set(MITK_MODULES DiffusionCore FiberTracking Connectomics MriSimulation DiffusionIO DiffusionCmdApps + FiberDissection )