diff --git a/Modules/FiberTracking/Algorithms/mitkTractClusteringFilter.cpp b/Modules/FiberTracking/Algorithms/mitkTractClusteringFilter.cpp index 89ab41b..cb1b076 100644 --- a/Modules/FiberTracking/Algorithms/mitkTractClusteringFilter.cpp +++ b/Modules/FiberTracking/Algorithms/mitkTractClusteringFilter.cpp @@ -1,603 +1,608 @@ /*=================================================================== 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 "mitkTractClusteringFilter.h" #define _USE_MATH_DEFINES #include #include #include namespace mitk{ TractClusteringFilter::TractClusteringFilter() : m_NumPoints(12) , m_InCentroids(nullptr) , m_MinClusterSize(1) , m_MaxClusters(0) , m_MergeDuplicateThreshold(-1) , m_DoResampling(true) , m_FilterMask(nullptr) , m_OverlapThreshold(0.0) { } TractClusteringFilter::~TractClusteringFilter() { for (auto m : m_Metrics) delete m; } std::vector > TractClusteringFilter::GetOutFiberIndices() const { return m_OutFiberIndices; } void TractClusteringFilter::SetMetrics(const std::vector &Metrics) { m_Metrics = Metrics; } std::vector TractClusteringFilter::GetOutClusters() const { return m_OutClusters; } std::vector TractClusteringFilter::GetOutCentroids() const { return m_OutCentroids; } std::vector TractClusteringFilter::GetOutTractograms() const { return m_OutTractograms; } void TractClusteringFilter::SetDistances(const std::vector &Distances) { m_Distances = Distances; } float TractClusteringFilter::CalcOverlap(vnl_matrix& t) { float overlap = 0; if (m_FilterMask.IsNotNull()) { for (unsigned int i=0; i p = t.get_column(i); itk::Point point; point[0] = p[0]; point[1] = p[1]; point[2] = p[2]; itk::Index<3> idx; m_FilterMask->TransformPhysicalPointToIndex(point, idx); if (m_FilterMask->GetLargestPossibleRegion().IsInside(idx) && m_FilterMask->GetPixel(idx)>0) overlap += 1; } overlap /= m_NumPoints; } else return 1.0; return overlap; } std::vector > TractClusteringFilter::ResampleFibers(mitk::FiberBundle::Pointer tractogram) { mitk::FiberBundle::Pointer temp_fib = tractogram->GetDeepCopy(); if (m_DoResampling) temp_fib->ResampleToNumPoints(m_NumPoints); std::vector< vnl_matrix > out_fib; for (int i=0; iGetFiberPolyData()->GetNumberOfCells(); i++) { vtkCell* cell = temp_fib->GetFiberPolyData()->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vnl_matrix streamline; streamline.set_size(3, m_NumPoints); streamline.fill(0.0); for (int j=0; jGetPoint(j, cand); vnl_vector_fixed< float, 3 > candV; candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2]; streamline.set_column(j, candV); } out_fib.push_back(streamline); } return out_fib; } std::vector< TractClusteringFilter::Cluster > TractClusteringFilter::ClusterStep(std::vector< unsigned int > f_indices, std::vector distances) { float dist_thres = distances.back(); distances.pop_back(); std::vector< Cluster > C; int N = f_indices.size(); Cluster c1; c1.I.push_back(f_indices.at(0)); c1.h = T[f_indices.at(0)]; c1.n = 1; C.push_back(c1); if (f_indices.size()==1) return C; for (int i=1; i t = T.at(f_indices.at(i)); int min_cluster_index = -1; float min_cluster_distance = 99999; bool flip = false; for (unsigned int k=0; k v = C.at(k).h / C.at(k).n; bool f = false; float d = 0; for (auto m : m_Metrics) d += m->CalculateDistance(t, v, f); d /= m_Metrics.size(); if (d=0 && min_cluster_distance outC; #pragma omp parallel for for (int c=0; c<(int)C.size(); c++) { std::vector< Cluster > tempC = ClusterStep(C.at(c).I, distances); #pragma omp critical AppendCluster(outC, tempC); } return outC; } else return C; } void TractClusteringFilter::AppendCluster(std::vector< Cluster >& a, std::vector< Cluster >&b) { for (auto c : b) a.push_back(c); } +unsigned int TractClusteringFilter::GetDiscardedClusters() const +{ + return m_DiscardedClusters; +} + void TractClusteringFilter::SetDoResampling(bool DoResampling) { m_DoResampling = DoResampling; } void TractClusteringFilter::SetOverlapThreshold(float OverlapThreshold) { m_OverlapThreshold = OverlapThreshold; } void TractClusteringFilter::SetFilterMask(const UcharImageType::Pointer &FilterMask) { m_FilterMask = FilterMask; } void TractClusteringFilter::SetMinClusterSize(unsigned int MinClusterSize) { m_MinClusterSize = MinClusterSize; } void TractClusteringFilter::SetMaxClusters(unsigned int MaxClusters) { m_MaxClusters = MaxClusters; } void TractClusteringFilter::SetNumPoints(unsigned int NumPoints) { m_NumPoints = NumPoints; } void TractClusteringFilter::SetMergeDuplicateThreshold(float MergeDuplicateThreshold) { m_MergeDuplicateThreshold = MergeDuplicateThreshold; } void TractClusteringFilter::SetInCentroids(const mitk::FiberBundle::Pointer &InCentroids) { m_InCentroids = InCentroids; } void TractClusteringFilter::SetTractogram(const mitk::FiberBundle::Pointer &Tractogram) { m_Tractogram = Tractogram; } std::vector< TractClusteringFilter::Cluster > TractClusteringFilter::MergeDuplicateClusters2(std::vector< TractClusteringFilter::Cluster >& clusters) { if (m_MergeDuplicateThreshold<0) m_MergeDuplicateThreshold = m_Distances.at(0)/2; else if (m_MergeDuplicateThreshold==0) return clusters; MITK_INFO << "Merging duplicate clusters with distance threshold " << m_MergeDuplicateThreshold; std::vector< TractClusteringFilter::Cluster > new_clusters; for (Cluster c1 : clusters) { vnl_matrix t = c1.h / c1.n; int min_idx = -1; float min_d = 99999; bool flip = false; #pragma omp parallel for for (int k2=0; k2<(int)new_clusters.size(); ++k2) { Cluster c2 = new_clusters.at(k2); vnl_matrix v = c2.h / c2.n; bool f = false; float d = 0; for (auto m : m_Metrics) d += m->CalculateDistance(t, v, f); d /= m_Metrics.size(); #pragma omp critical if (d& clusters) { if (m_MergeDuplicateThreshold<0) m_MergeDuplicateThreshold = m_Distances.at(0)/2; bool found = true; MITK_INFO << "Merging duplicate clusters with distance threshold " << m_MergeDuplicateThreshold; int start = 0; while (found && m_MergeDuplicateThreshold>mitk::eps) { std::cout << " \r"; std::cout << "Number of clusters: " << clusters.size() << '\r'; cout.flush(); found = false; for (int k1=start; k1<(int)clusters.size(); ++k1) { Cluster c1 = clusters.at(k1); vnl_matrix t = c1.h / c1.n; std::vector< int > merge_indices; std::vector< bool > flip_indices; #pragma omp parallel for for (int k2=start+1; k2<(int)clusters.size(); ++k2) { if (k1!=k2) { Cluster c2 = clusters.at(k2); vnl_matrix v = c2.h / c2.n; bool f = false; float d = 0; for (auto m : m_Metrics) d += m->CalculateDistance(t, v, f); d /= m_Metrics.size(); #pragma omp critical if (d TractClusteringFilter::AddToKnownClusters(std::vector< unsigned int > f_indices, std::vector >& centroids) { float dist_thres = m_Distances.at(0); int N = f_indices.size(); std::vector< Cluster > C; vnl_matrix zero_h; zero_h.set_size(T.at(0).rows(), T.at(0).cols()); zero_h.fill(0.0); Cluster no_fit; no_fit.h = zero_h; for (unsigned int i=0; i t = T.at(f_indices.at(i)); int min_cluster_index = -1; float min_cluster_distance = 99999; bool flip = false; if (CalcOverlap(t)>=m_OverlapThreshold) { int c_idx = 0; for (vnl_matrix centroid : centroids) { bool f = false; float d = 0; for (auto m : m_Metrics) d += m->CalculateDistance(t, centroid, f); d /= m_Metrics.size(); if (d=0 && min_cluster_distance 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; - int skipped = 0; + 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 { - skipped++; + m_DiscardedClusters++; } } - MITK_INFO << "Final number of clusters: " << m_OutTractograms.size() << " (discarded " << skipped << " clusters)"; + 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, false); ++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/FiberTracking/Algorithms/mitkTractClusteringFilter.h b/Modules/FiberTracking/Algorithms/mitkTractClusteringFilter.h index 9233a6f..75b574a 100644 --- a/Modules/FiberTracking/Algorithms/mitkTractClusteringFilter.h +++ b/Modules/FiberTracking/Algorithms/mitkTractClusteringFilter.h @@ -1,153 +1,131 @@ /*=================================================================== 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 TractClusteringFilter_h #define TractClusteringFilter_h // MITK #include #include #include #include // ITK #include // VTK #include #include #include #include #include namespace mitk{ /** * \brief */ class MITKFIBERTRACKING_EXPORT TractClusteringFilter { public: struct Cluster { Cluster() : n(0), f_id(-1) {} vnl_matrix h; std::vector< unsigned int > I; int n; int f_id; bool operator <(Cluster const& b) const { return this->n < b.n; } }; TractClusteringFilter(); ~TractClusteringFilter(); -// typedef TractClusteringFilter Self; -// typedef ProcessObject Superclass; -// typedef SmartPointer< Self > Pointer; -// typedef SmartPointer< const Self > ConstPointer; typedef itk::Image< float, 3 > FloatImageType; typedef itk::Image< unsigned char, 3 > UcharImageType; -// itkFactorylessNewMacro(Self) -// itkCloneMacro(Self) -// itkTypeMacro( TractClusteringFilter, ProcessObject ) - -// itkSetMacro(NumPoints, unsigned int) ///< Fibers are resampled to the specified number of points. If scalar maps are used, a larger number of points is recommended. -// itkGetMacro(NumPoints, unsigned int) ///< Fibers are resampled to the specified number of points. If scalar maps are used, a larger number of points is recommended. -// itkSetMacro(MinClusterSize, unsigned int) ///< Clusters with too few fibers are discarded -// itkGetMacro(MinClusterSize, unsigned int) ///< Clusters with too few fibers are discarded -// itkSetMacro(MaxClusters, unsigned int) ///< Only the N largest clusters are kept -// itkGetMacro(MaxClusters, unsigned int) ///< Only the N largest clusters are kept -// itkSetMacro(MergeDuplicateThreshold, float) ///< Clusters with centroids very close to each other are merged. Set to 0 to avoid merging and to -1 to use the original cluster size. -// itkGetMacro(MergeDuplicateThreshold, float) ///< Clusters with centroids very close to each other are merged. Set to 0 to avoid merging and to -1 to use the original cluster size. -// itkSetMacro(DoResampling, bool) ///< Resample fibers to equal number of points. This is mandatory, but can be performed outside of the filter if desired. -// itkGetMacro(DoResampling, bool) ///< Resample fibers to equal number of points. This is mandatory, but can be performed outside of the filter if desired. -// itkSetMacro(OverlapThreshold, float) ///< Overlap threshold used in conjunction with the filter mask when clustering around known centroids. -// itkGetMacro(OverlapThreshold, float) ///< Overlap threshold used in conjunction with the filter mask when clustering around known centroids. - -// itkSetMacro(Tractogram, mitk::FiberBundle::Pointer) ///< The streamlines to be clustered -// itkSetMacro(InCentroids, mitk::FiberBundle::Pointer) ///< If a tractogram containing known tract centroids is set, the input fibers are assigned to the closest centroid. If no centroid is found within the specified smallest clustering distance, the fiber is assigned to the no-fit cluster. -// itkSetMacro(FilterMask, UcharImageType::Pointer) ///< If fibers are clustered around the nearest input centroids (see SetInCentroids), the complete input tractogram can additionally be pre-filtered with this binary mask and a given overlap threshold (see SetOverlapThreshold). - void Update(){ this->GenerateData(); } void SetDistances(const std::vector &Distances); ///< Set clustering distances that are traversed recoursively. The distances have to be sorted in an ascending manner. The actual cluster size is determined by the smallest entry in the distance-list (index 0). std::vector GetOutTractograms() const; std::vector GetOutCentroids() const; std::vector GetOutClusters() const; std::vector > GetOutFiberIndices() const; void SetMetrics(const std::vector &Metrics); void SetTractogram(const mitk::FiberBundle::Pointer &Tractogram); void SetInCentroids(const mitk::FiberBundle::Pointer &InCentroids); void SetMergeDuplicateThreshold(float MergeDuplicateThreshold); void SetNumPoints(unsigned int NumPoints); void SetMaxClusters(unsigned int MaxClusters); void SetMinClusterSize(unsigned int MinClusterSize); void SetFilterMask(const UcharImageType::Pointer &FilterMask); void SetOverlapThreshold(float OverlapThreshold); void SetDoResampling(bool DoResampling); + unsigned int GetDiscardedClusters() const; + protected: void GenerateData(); std::vector< vnl_matrix > ResampleFibers(FiberBundle::Pointer tractogram); float CalcOverlap(vnl_matrix& t); std::vector< Cluster > ClusterStep(std::vector< unsigned int > f_indices, std::vector< float > distances); std::vector< TractClusteringFilter::Cluster > MergeDuplicateClusters2(std::vector< TractClusteringFilter::Cluster >& clusters); void MergeDuplicateClusters(std::vector< TractClusteringFilter::Cluster >& clusters); std::vector< Cluster > AddToKnownClusters(std::vector< unsigned int > f_indices, std::vector > ¢roids); void AppendCluster(std::vector< Cluster >& a, std::vector< Cluster >&b); unsigned int m_NumPoints; std::vector< float > m_Distances; mitk::FiberBundle::Pointer m_Tractogram; mitk::FiberBundle::Pointer m_InCentroids; std::vector< mitk::FiberBundle::Pointer > m_OutTractograms; std::vector< mitk::FiberBundle::Pointer > m_OutCentroids; std::vector > T; unsigned int m_MinClusterSize; unsigned int m_MaxClusters; + unsigned int m_DiscardedClusters; float m_MergeDuplicateThreshold; std::vector< Cluster > m_OutClusters; bool m_DoResampling; UcharImageType::Pointer m_FilterMask; float m_OverlapThreshold; std::vector< mitk::ClusteringMetric* > m_Metrics; std::vector< std::vector< unsigned int > > m_OutFiberIndices; }; } #endif diff --git a/Modules/FiberTracking/Testing/mitkStreamlineTractographyTest.cpp b/Modules/FiberTracking/Testing/mitkStreamlineTractographyTest.cpp index 8922705..a5e07f6 100644 --- a/Modules/FiberTracking/Testing/mitkStreamlineTractographyTest.cpp +++ b/Modules/FiberTracking/Testing/mitkStreamlineTractographyTest.cpp @@ -1,438 +1,439 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class mitkStreamlineTractographyTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkStreamlineTractographyTestSuite); MITK_TEST(Test_Peak1); MITK_TEST(Test_Peak2); MITK_TEST(Test_Tensor1); MITK_TEST(Test_Tensor2); MITK_TEST(Test_Tensor3); MITK_TEST(Test_Odf1); MITK_TEST(Test_Odf2); MITK_TEST(Test_Odf3); MITK_TEST(Test_Odf4); MITK_TEST(Test_Odf5); MITK_TEST(Test_Odf6); CPPUNIT_TEST_SUITE_END(); typedef itk::VectorImage< short, 3> ItkDwiType; private: public: /** Members used inside the different (sub-)tests. All members are initialized via setUp().*/ typedef itk::Image ItkFloatImgType; mitk::TrackingHandlerOdf::ItkOdfImageType::Pointer itk_odf_image; mitk::TrackingHandlerTensor::ItkTensorImageType::ConstPointer itk_tensor_image; mitk::TrackingHandlerPeaks::PeakImgType::Pointer itk_peak_image; ItkFloatImgType::Pointer itk_seed_image; ItkFloatImgType::Pointer itk_mask_image; ItkFloatImgType::Pointer itk_gfa_image; float gfa_threshold; float odf_threshold; float peak_threshold; std::shared_ptr params; itk::StreamlineTrackingFilter::Pointer tracker; void setUp() override { omp_set_num_threads(1); gfa_threshold = 0.2f; odf_threshold = 0.1f; peak_threshold = 0.1f; mitk::Image::Pointer odf_image = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/StreamlineTractography/qball_image.qbi")); mitk::Image::Pointer tensor_image = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/StreamlineTractography/tensor_image.dti")); mitk::Image::Pointer peak_image = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/StreamlineTractography/qball_peak_image.nii.gz")); mitk::Image::Pointer seed_image = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/StreamlineTractography/seed_image.nii.gz")); mitk::Image::Pointer mask_image = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/StreamlineTractography/mask_image.nii.gz")); mitk::Image::Pointer gfa_image = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/StreamlineTractography/gfa_image.nii.gz")); params = std::make_shared(); params->m_FixRandomSeed = true; params->m_InterpolateRoiImages = false; + params->SetLoopCheckDeg(-1); // todo: test loop check { typedef mitk::ImageToItk< mitk::TrackingHandlerPeaks::PeakImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(peak_image); caster->Update(); itk_peak_image = caster->GetOutput(); } { typedef mitk::ImageToItk< mitk::TrackingHandlerTensor::ItkTensorImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(tensor_image); caster->Update(); itk_tensor_image = caster->GetOutput(); } { typedef mitk::ImageToItk< mitk::TrackingHandlerOdf::ItkOdfImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(odf_image); caster->Update(); itk_odf_image = caster->GetOutput(); } itk_gfa_image = ItkFloatImgType::New(); mitk::CastToItkImage(gfa_image, itk_gfa_image); itk_seed_image = ItkFloatImgType::New(); mitk::CastToItkImage(seed_image, itk_seed_image); itk_mask_image = ItkFloatImgType::New(); mitk::CastToItkImage(mask_image, itk_mask_image); } mitk::FiberBundle::Pointer LoadReferenceFib(std::string filename) { mitk::FiberBundle::Pointer fib = nullptr; if (itksys::SystemTools::FileExists(GetTestDataFilePath("DiffusionImaging/StreamlineTractography/ReferenceFibs/" + filename))) { mitk::BaseData::Pointer baseData = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/StreamlineTractography/ReferenceFibs/" + filename)).at(0); fib = dynamic_cast(baseData.GetPointer()); } return fib; } mitk::Image::Pointer LoadReferenceImage(std::string filename) { mitk::Image::Pointer img = nullptr; if (itksys::SystemTools::FileExists(GetTestDataFilePath("DiffusionImaging/StreamlineTractography/ReferenceFibs/" + filename))) { img = mitk::IOUtil::Load(GetTestDataFilePath("DiffusionImaging/StreamlineTractography/ReferenceFibs/" + filename)); } return img; } void SetupTracker(mitk::TrackingDataHandler* handler) { tracker = itk::StreamlineTrackingFilter::New(); // tracker->SetInterpolateMasks(false); // tracker->SetNumberOfSamples(0); // tracker->SetAngularThreshold(-1); tracker->SetMaskImage(itk_mask_image); tracker->SetSeedImage(itk_seed_image); tracker->SetStoppingRegions(nullptr); // tracker->SetSeedsPerVoxel(1); // tracker->SetStepSize(0.5); // tracker->SetSamplingDistance(0.25); // tracker->SetUseStopVotes(true); // tracker->SetOnlyForwardSamples(true); // tracker->SetMinTractLength(20); // tracker->SetMaxNumTracts(-1); tracker->SetTrackingHandler(handler); // tracker->SetUseOutputProbabilityMap(false); tracker->SetParameters(params); } void tearDown() override { } void CheckFibResult(std::string ref_file, mitk::FiberBundle::Pointer test_fib) { mitk::FiberBundle::Pointer ref = LoadReferenceFib(ref_file); if (ref.IsNull()) { mitk::IOUtil::Save(test_fib, mitk::IOUtil::GetTempPath()+ref_file); CPPUNIT_FAIL("Reference file not found. Saving test file to " + mitk::IOUtil::GetTempPath() + ref_file); } else { bool is_equal = ref->Equals(test_fib); if (!is_equal) { mitk::IOUtil::Save(test_fib, mitk::IOUtil::GetTempPath()+ref_file); CPPUNIT_FAIL("Tractograms are not equal! Saving test file to " + mitk::IOUtil::GetTempPath() + ref_file); } } } void CheckImageResult(std::string ref_file, mitk::Image::Pointer test_img) { mitk::Image::Pointer ref = LoadReferenceImage(ref_file); if (ref.IsNull()) { mitk::IOUtil::Save(test_img, mitk::IOUtil::GetTempPath()+ref_file); CPPUNIT_FAIL("Reference file not found. Saving test file to " + mitk::IOUtil::GetTempPath() + ref_file); } else { MITK_ASSERT_EQUAL(test_img, ref, "Images should be equal"); } } void Test_Peak1() { mitk::TrackingHandlerPeaks* handler = new mitk::TrackingHandlerPeaks(); handler->SetPeakImage(itk_peak_image); params->m_Cutoff = peak_threshold; SetupTracker(handler); tracker->Update(); vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); CheckFibResult("Test_Peak1.fib", outFib); delete handler; } void Test_Peak2() { mitk::TrackingHandlerPeaks* handler = new mitk::TrackingHandlerPeaks(); handler->SetPeakImage(itk_peak_image); params->m_Cutoff = peak_threshold; params->m_InterpolateTractographyData = false; SetupTracker(handler); tracker->Update(); vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); CheckFibResult("Test_Peak2.fib", outFib); delete handler; } void Test_Tensor1() { mitk::TrackingHandlerTensor* handler = new mitk::TrackingHandlerTensor(); handler->SetTensorImage(itk_tensor_image); params->m_Cutoff = gfa_threshold; SetupTracker(handler); tracker->Update(); vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); CheckFibResult("Test_Tensor1.fib", outFib); delete handler; } void Test_Tensor2() { mitk::TrackingHandlerTensor* handler = new mitk::TrackingHandlerTensor(); handler->SetTensorImage(itk_tensor_image); params->m_Cutoff = gfa_threshold; params->m_InterpolateTractographyData = false; SetupTracker(handler); tracker->Update(); vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); CheckFibResult("Test_Tensor2.fib", outFib); delete handler; } void Test_Tensor3() { mitk::TrackingHandlerTensor* handler = new mitk::TrackingHandlerTensor(); handler->SetTensorImage(itk_tensor_image); params->m_Cutoff = gfa_threshold; params->m_InterpolateTractographyData = false; params->m_F = 0; params->m_G = 1; SetupTracker(handler); tracker->Update(); vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); CheckFibResult("Test_Tensor3.fib", outFib); delete handler; } void Test_Odf1() { mitk::TrackingHandlerOdf* handler = new mitk::TrackingHandlerOdf(); handler->SetOdfImage(itk_odf_image); params->m_Cutoff = gfa_threshold; params->m_OdfCutoff = 0; params->m_SharpenOdfs = true; SetupTracker(handler); tracker->Update(); vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); CheckFibResult("Test_Odf1.fib", outFib); delete handler; } void Test_Odf2() { mitk::TrackingHandlerOdf* handler = new mitk::TrackingHandlerOdf(); handler->SetOdfImage(itk_odf_image); params->m_Cutoff = gfa_threshold; params->m_OdfCutoff = 0; params->m_SharpenOdfs = false; SetupTracker(handler); tracker->Update(); vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); CheckFibResult("Test_Odf2.fib", outFib); delete handler; } void Test_Odf3() { mitk::TrackingHandlerOdf* handler = new mitk::TrackingHandlerOdf(); handler->SetOdfImage(itk_odf_image); params->m_Cutoff = gfa_threshold; params->m_OdfCutoff = 0; params->m_SharpenOdfs = true; params->m_InterpolateTractographyData = false; SetupTracker(handler); tracker->Update(); vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); CheckFibResult("Test_Odf3.fib", outFib); delete handler; } void Test_Odf4() { mitk::TrackingHandlerOdf* handler = new mitk::TrackingHandlerOdf(); handler->SetOdfImage(itk_odf_image); params->m_Cutoff = gfa_threshold; params->m_OdfCutoff = 0; params->m_SharpenOdfs = true; params->m_SeedsPerVoxel = 3; SetupTracker(handler); tracker->Update(); vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); CheckFibResult("Test_Odf4.fib", outFib); delete handler; } void Test_Odf5() { mitk::TrackingHandlerOdf* handler = new mitk::TrackingHandlerOdf(); handler->SetOdfImage(itk_odf_image); params->m_Cutoff = gfa_threshold; params->m_OdfCutoff = 0; params->m_SharpenOdfs = true; params->m_SeedsPerVoxel = 3; params->m_Mode = mitk::TrackingDataHandler::MODE::PROBABILISTIC; SetupTracker(handler); tracker->Update(); vtkSmartPointer< vtkPolyData > poly = tracker->GetFiberPolyData(); mitk::FiberBundle::Pointer outFib = mitk::FiberBundle::New(poly); CheckFibResult("Test_Odf5.fib", outFib); delete handler; } void Test_Odf6() { mitk::TrackingHandlerOdf* handler = new mitk::TrackingHandlerOdf(); handler->SetOdfImage(itk_odf_image); params->m_Cutoff = gfa_threshold; params->m_OdfCutoff = 0; params->m_SharpenOdfs = true; params->m_SeedsPerVoxel = 10; params->m_Mode = mitk::TrackingDataHandler::MODE::PROBABILISTIC; params->m_OutputProbMap = true; SetupTracker(handler); tracker->Update(); itk::StreamlineTrackingFilter::ItkDoubleImgType::Pointer outImg = tracker->GetOutputProbabilityMap(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); mitk::IOUtil::Save(img, mitk::IOUtil::GetTempPath()+"Test_Odf6.nrrd"); CheckImageResult("Test_Odf6.nrrd", img); delete handler; } }; MITK_TEST_SUITE_REGISTRATION(mitkStreamlineTractography) diff --git a/Modules/FiberTracking/mitkStreamlineTractographyParameters.h b/Modules/FiberTracking/mitkStreamlineTractographyParameters.h index 96fe4a8..7f35ad4 100644 --- a/Modules/FiberTracking/mitkStreamlineTractographyParameters.h +++ b/Modules/FiberTracking/mitkStreamlineTractographyParameters.h @@ -1,163 +1,163 @@ #pragma once /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include namespace mitk { /** * \brief Datastructure to manage streamline tractography parameters. * */ class MITKFIBERTRACKING_EXPORT StreamlineTractographyParameters { public: enum EndpointConstraints { NONE, ///< No constraints on endpoint locations EPS_IN_TARGET, ///< Both EPs are required to be located in the target image EPS_IN_TARGET_LABELDIFF, ///< Both EPs are required to be located in the target image and the image values at the respective position needs to be distinct EPS_IN_SEED_AND_TARGET, ///< One EP is required to be located in the seed image and one in the target image MIN_ONE_EP_IN_TARGET, ///< At least one EP is required to be located in the target image ONE_EP_IN_TARGET, ///< Exactly one EP is required to be located in the target image NO_EP_IN_TARGET ///< No EP is allowed to be located in the target image }; enum MODE { DETERMINISTIC, PROBABILISTIC }; typedef itk::Image ItkFloatImgType; typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkUcharImgType; StreamlineTractographyParameters(); StreamlineTractographyParameters(const StreamlineTractographyParameters ¶ms) = default; ~StreamlineTractographyParameters(); void SaveParameters(std::string filename); ///< Save image generation parameters to .stp file. void LoadParameters(std::string filename); ///< Load image generation parameters from .stp file. template< class ParameterType > ParameterType ReadVal(boost::property_tree::ptree::value_type const& v, std::string tag, ParameterType defaultValue, bool essential=false); // seeding unsigned int m_SeedsPerVoxel = 1; unsigned int m_TrialsPerSeed = 10; int m_MaxNumFibers = -1; // - seed image // interactive float m_InteractiveRadiusMm = 2; unsigned int m_NumInteractiveSeeds = 50; bool m_EnableInteractive = false; // ROI constraints EndpointConstraints m_EpConstraints; // - mask image // - stop image // - exclusion image // - target image // tractography MODE m_Mode= MODE::DETERMINISTIC; bool m_SharpenOdfs = false; float m_Cutoff = 0.1; // - fa/gfa image float m_OdfCutoff = 0.00025; float m_MinTractLengthMm = 20; float m_MaxTractLengthMm = 400; float m_F = 1; float m_G = 0; bool m_FixRandomSeed = false; unsigned int m_NumPreviousDirections = 1; float m_PeakJitter = 0.01; // actual jitter is drawn from a normal distribution with m_PeakJitter*fabs(direction_value) as standard deviation // prior // - peak image float m_Weight = 0.5; bool m_RestrictToPrior = true; bool m_NewDirectionsFromPrior = true; bool m_PriorFlipX = false; bool m_PriorFlipY = false; bool m_PriorFlipZ = false; // neighborhood sampling unsigned int m_NumSamples = 0; bool m_OnlyForwardSamples = false; bool m_StopVotes = false; bool m_AvoidStop = true; bool m_RandomSampling = false; float m_DeflectionMod = 1.0; // data handling bool m_FlipX = false; bool m_FlipY = false; bool m_FlipZ = false; bool m_InterpolateTractographyData = true; bool m_InterpolateRoiImages; bool m_ApplyDirectionMatrix = false; // output and postprocessing bool m_CompressFibers = true; float m_Compression = 0.1; bool m_OutputProbMap = false; float GetAngularThresholdDot() const; float GetAngularThresholdDeg() const; void SetAngularThresholdDeg(float angular_threshold_deg); float GetLoopCheckDeg() const; void SetLoopCheckDeg(float loop_check_deg); float GetStepSizeMm() const; float GetStepSizeVox() const; void SetStepSizeVox(float step_size_vox); float GetSamplingDistanceMm() const; float GetSamplingDistanceVox() const; void SetSamplingDistanceVox(float sampling_distance_vox); void SetMinVoxelSizeMm(float min_voxel_size_mm); float GetMinVoxelSizeMm() const; private: void AutoAdjust(); float m_SamplingDistanceVox = -1; float m_SamplingDistanceMm; float m_AngularThresholdDeg = -1; float m_AngularThresholdDot; - float m_LoopCheckDeg = -1; + float m_LoopCheckDeg = 30; float m_StepSizeVox = -1; float m_StepSizeMm; float m_MinVoxelSizeMm = 1.0; }; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/Perspectives/QmitkFiberProcessingPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/Perspectives/QmitkFiberProcessingPerspective.cpp index 5cea14d..038ed58 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/Perspectives/QmitkFiberProcessingPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/Perspectives/QmitkFiberProcessingPerspective.cpp @@ -1,51 +1,52 @@ /*=================================================================== 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 "QmitkFiberProcessingPerspective.h" #include "berryIViewLayout.h" void QmitkFiberProcessingPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// QString editorArea = layout->GetEditorArea(); layout->AddStandaloneViewPlaceholder("org.mitk.views.viewnavigatorview", berry::IPageLayout::LEFT, 0.3f, editorArea, false); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .7f, "org.mbi.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.fiberprocessing"); left->AddView("org.mitk.views.fiberquantification"); left->AddView("org.mitk.views.fiberclustering"); left->AddView("org.mitk.views.fiberfit"); + left->AddView("org.mitk.views.tractometry"); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp index 1c622f4..88a9f88 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp @@ -1,461 +1,539 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkFiberQuantificationView.h" // Qt #include // MITK #include #include #include #include #include #include #include #include #include // ITK #include #include #include #include +#include +#include #include const std::string QmitkFiberQuantificationView::VIEW_ID = "org.mitk.views.fiberquantification"; using namespace mitk; QmitkFiberQuantificationView::QmitkFiberQuantificationView() : QmitkAbstractView() , m_Controls( 0 ) , m_UpsamplingFactor(5) , m_Visible(false) { } // Destructor QmitkFiberQuantificationView::~QmitkFiberQuantificationView() { } void QmitkFiberQuantificationView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberQuantificationViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_ProcessFiberBundleButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedBundles()) ); connect( m_Controls->m_ExtractFiberPeaks, SIGNAL(clicked()), this, SLOT(CalculateFiberDirections()) ); m_Controls->m_TractBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isFib = mitk::TNodePredicateDataType::New(); m_Controls->m_TractBox->SetPredicate( isFib ); m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ImageBox->SetZeroEntryText("--"); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDimension::Pointer is3D = mitk::NodePredicateDimension::New(3); m_Controls->m_ImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, is3D) ); connect( (QObject*)(m_Controls->m_TractBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); connect( (QObject*)(m_Controls->m_ImageBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); } } void QmitkFiberQuantificationView::Activated() { } void QmitkFiberQuantificationView::Deactivated() { } void QmitkFiberQuantificationView::Visible() { m_Visible = true; } void QmitkFiberQuantificationView::Hidden() { m_Visible = false; } void QmitkFiberQuantificationView::SetFocus() { m_Controls->m_ProcessFiberBundleButton->setFocus(); } void QmitkFiberQuantificationView::CalculateFiberDirections() { typedef itk::Image ItkUcharImgType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(m_SelectedFB.back()->GetData()); itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); if (m_SelectedImage.IsNotNull()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); mitk::CastToItkImage(m_SelectedImage, itkMaskImage); fOdfFilter->SetMaskImage(itkMaskImage); } // extract directions from fiber bundle fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetAngularThreshold(cos(m_Controls->m_AngularThreshold->value()*itk::Math::pi/180)); switch (m_Controls->m_FiberDirNormBox->currentIndex()) { case 0: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::GLOBAL_MAX); break; case 1: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::SINGLE_VEC_NORM); break; case 2: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::MAX_VEC_NORM); break; } fOdfFilter->SetSizeThreshold(m_Controls->m_PeakThreshold->value()); fOdfFilter->SetMaxNumDirections(m_Controls->m_MaxNumDirections->value()); fOdfFilter->Update(); QString name = m_SelectedFB.back()->GetName().c_str(); if (m_Controls->m_NumDirectionsBox->isChecked()) { mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( fOdfFilter->GetNumDirectionsImage().GetPointer() ); mitkImage->SetVolume( fOdfFilter->GetNumDirectionsImage()->GetBufferPointer() ); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitkImage); node->SetName((name+"_NUM_DIRECTIONS").toStdString().c_str()); GetDataStorage()->Add(node, m_SelectedFB.back()); } Image::Pointer mitkImage = dynamic_cast(PeakImage::New().GetPointer()); mitk::CastToMitkImage(fOdfFilter->GetDirectionImage(), mitkImage); mitkImage->SetVolume(fOdfFilter->GetDirectionImage()->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitkImage); node->SetName( (name+"_DIRECTIONS").toStdString().c_str()); GetDataStorage()->Add(node, m_SelectedFB.back()); } void QmitkFiberQuantificationView::UpdateGui() { m_SelectedFB.clear(); if (m_Controls->m_TractBox->GetSelectedNode().IsNotNull()) m_SelectedFB.push_back(m_Controls->m_TractBox->GetSelectedNode()); m_SelectedImage = nullptr; if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) m_SelectedImage = dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData()); m_Controls->m_ProcessFiberBundleButton->setEnabled(!m_SelectedFB.empty()); m_Controls->m_ExtractFiberPeaks->setEnabled(!m_SelectedFB.empty()); } void QmitkFiberQuantificationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& ) { UpdateGui(); } void QmitkFiberQuantificationView::ProcessSelectedBundles() { if ( m_SelectedFB.empty() ){ QMessageBox::information( nullptr, "Warning", "No fibe bundle selected!"); MITK_WARN("QmitkFiberQuantificationView") << "no fibe bundle selected"; return; } int generationMethod = m_Controls->m_GenerationBox->currentIndex(); for( unsigned int i=0; i(node->GetData())) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); QString name(node->GetName().c_str()); DataNode::Pointer newNode = nullptr; switch(generationMethod){ case 0: newNode = GenerateTractDensityImage(fib, false, true, node->GetName()); name += "_TDI"; break; case 1: newNode = GenerateTractDensityImage(fib, false, false, node->GetName()); name += "_TDI"; break; case 2: newNode = GenerateTractDensityImage(fib, true, false, node->GetName()); name += "_envelope"; break; case 3: newNode = GenerateColorHeatmap(fib); break; case 4: newNode = GenerateFiberEndingsImage(fib); name += "_fiber_endings"; break; case 5: newNode = GenerateFiberEndingsPointSet(fib); name += "_fiber_endings"; break; + case 6: + newNode = GenerateDistanceMap(fib); + name += "_distance_map"; + break; + case 7: + newNode = GenerateBinarySkeleton(fib); + name += "_skeleton"; + break; } if (newNode.IsNotNull()) { newNode->SetName(name.toStdString()); GetDataStorage()->Add(newNode); } } } } // generate pointset displaying the fiber endings mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateFiberEndingsPointSet(mitk::FiberBundle::Pointer fib) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); vtkSmartPointer fiberPolyData = fib->GetFiberPolyData(); int count = 0; int numFibers = fib->GetNumFibers(); for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints>0) { double* point = points->GetPoint(0); itk::Point itkPoint = mitk::imv::GetItkPoint(point); pointSet->InsertPoint(count, itkPoint); count++; } if (numPoints>2) { double* point = points->GetPoint(numPoints-1); itk::Point itkPoint = mitk::imv::GetItkPoint(point); pointSet->InsertPoint(count, itkPoint); count++; } } mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( pointSet ); return node; } // generate image displaying the fiber endings mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateFiberEndingsImage(mitk::FiberBundle::Pointer fib) { typedef unsigned int OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToFiberEndingsImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image OutImageType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate rgba heatmap from fiber bundle mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateColorHeatmap(mitk::FiberBundle::Pointer fib) { typedef itk::RGBAPixel OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToRgbaImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { itk::Image::Pointer itkImage = itk::Image::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } +mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateBinarySkeleton(mitk::FiberBundle::Pointer fib) +{ + typedef itk::Image UcharImageType; + + itk::TractDensityImageFilter< UcharImageType >::Pointer envelope_generator = itk::TractDensityImageFilter< UcharImageType >::New(); + envelope_generator->SetFiberBundle(fib); + envelope_generator->SetBinaryOutput(true); + envelope_generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); + if (m_SelectedImage.IsNotNull()) + { + UcharImageType::Pointer itkImage = UcharImageType::New(); + CastToItkImage(m_SelectedImage, itkImage); + envelope_generator->SetInputImage(itkImage); + envelope_generator->SetUseImageGeometry(true); + + } + envelope_generator->Update(); + + itk::BinaryThinningImageFilter::Pointer map_generator = itk::BinaryThinningImageFilter::New(); + map_generator->SetInput(envelope_generator->GetOutput()); + map_generator->Update(); + + UcharImageType::Pointer outImg = map_generator->GetOutput(); + mitk::Image::Pointer img = mitk::Image::New(); + img->InitializeByItk(outImg.GetPointer()); + img->SetVolume(outImg->GetBufferPointer()); + + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(img); + return node; +} + +mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateDistanceMap(mitk::FiberBundle::Pointer fib) +{ + typedef itk::Image UcharImageType; + typedef itk::Image FloatImageType; + + itk::TractDensityImageFilter< UcharImageType >::Pointer envelope_generator = itk::TractDensityImageFilter< UcharImageType >::New(); + envelope_generator->SetFiberBundle(fib); + envelope_generator->SetBinaryOutput(true); + envelope_generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); + if (m_SelectedImage.IsNotNull()) + { + UcharImageType::Pointer itkImage = UcharImageType::New(); + CastToItkImage(m_SelectedImage, itkImage); + envelope_generator->SetInputImage(itkImage); + envelope_generator->SetUseImageGeometry(true); + + } + envelope_generator->Update(); + + itk::SignedMaurerDistanceMapImageFilter::Pointer map_generator = itk::SignedMaurerDistanceMapImageFilter::New(); + map_generator->SetInput(envelope_generator->GetOutput()); + map_generator->SetUseImageSpacing(true); + map_generator->SetSquaredDistance(false); + map_generator->SetInsideIsPositive(true); + map_generator->Update(); + + FloatImageType::Pointer outImg = map_generator->GetOutput(); + mitk::Image::Pointer img = mitk::Image::New(); + img->InitializeByItk(outImg.GetPointer()); + img->SetVolume(outImg->GetBufferPointer()); + + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(img); + return node; +} + // generate tract density image from fiber bundle mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateTractDensityImage(mitk::FiberBundle::Pointer fib, bool binary, bool absolute, std::string name) { mitk::DataNode::Pointer node = mitk::DataNode::New(); if (binary) { typedef unsigned char OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); if (m_SelectedImage.IsNotNull()) { mitk::LabelSetImage::Pointer multilabelImage = mitk::LabelSetImage::New(); multilabelImage->InitializeByLabeledImage(img); multilabelImage->GetActiveLabelSet()->SetActiveLabel(1); mitk::Label::Pointer label = multilabelImage->GetActiveLabel(); label->SetName("Tractogram"); // Add Segmented Property Category Code Sequence tags (0062, 0003): Sequence defining the general category of this // segment. // (0008,0100) Code Value label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_VALUE_PATH()).c_str(), TemporoSpatialStringProperty::New("T-D000A")); // (0008,0102) Coding Scheme Designator label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_SCHEME_PATH()).c_str(), TemporoSpatialStringProperty::New("SRT")); // (0008,0104) Code Meaning label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_MEANING_PATH()).c_str(), TemporoSpatialStringProperty::New("Anatomical Structure")); //------------------------------------------------------------ // Add Segmented Property Type Code Sequence (0062, 000F): Sequence defining the specific property type of this // segment. // (0008,0100) Code Value label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_VALUE_PATH()).c_str(), TemporoSpatialStringProperty::New("DUMMY")); // (0008,0102) Coding Scheme Designator label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_SCHEME_PATH()).c_str(), TemporoSpatialStringProperty::New("SRT")); // (0008,0104) Code Meaning label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_MEANING_PATH()).c_str(), TemporoSpatialStringProperty::New(name)); //Error: is undeclared// mitk::DICOMQIPropertyHandler::DeriveDICOMSourceProperties(m_SelectedImage, multilabelImage); // init data node node->SetData(multilabelImage); } else { // init data node node->SetData(img); } } else { typedef float OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } //generator->SetDoFiberResampling(false); generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node node->SetData(img); } return node; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.h index 5fb5380..bb3d808 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.h @@ -1,86 +1,89 @@ /*=================================================================== 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 QmitkFiberQuantificationView_h #define QmitkFiberQuantificationView_h #include #include "ui_QmitkFiberQuantificationViewControls.h" #include #include #include #include /*! \brief Generation of images from fiber bundles (TDI, envelopes, endpoint distribution) and extraction of principal fiber directions from tractograms. */ class QmitkFiberQuantificationView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { // 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; QmitkFiberQuantificationView(); virtual ~QmitkFiberQuantificationView(); virtual void CreateQtPartControl(QWidget *parent) override; /// /// Sets the focus to an internal widget. /// virtual void SetFocus() override; virtual void Activated() override; virtual void Deactivated() override; virtual void Visible() override; virtual void Hidden() override; protected slots: void ProcessSelectedBundles(); ///< start selected operation on fiber bundle (e.g. tract density image generation) void CalculateFiberDirections(); ///< Calculate main fiber directions from tractogram void UpdateGui(); ///< update button activity etc. dpending on current datamanager selection protected: /// \brief called by QmitkAbstractView when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; Ui::QmitkFiberQuantificationViewControls* m_Controls; std::vector m_SelectedFB; ///< selected fiber bundle nodes mitk::Image::Pointer m_SelectedImage; float m_UpsamplingFactor; ///< upsampling factor for all image generations mitk::DataNode::Pointer GenerateTractDensityImage(mitk::FiberBundle::Pointer fib, bool binary, bool absolute, std::string name); mitk::DataNode::Pointer GenerateColorHeatmap(mitk::FiberBundle::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsImage(mitk::FiberBundle::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsPointSet(mitk::FiberBundle::Pointer fib); + mitk::DataNode::Pointer GenerateDistanceMap(mitk::FiberBundle::Pointer fib); + mitk::DataNode::Pointer GenerateBinarySkeleton(mitk::FiberBundle::Pointer fib); + bool m_Visible; }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui index a2cd044..c427969 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui @@ -1,420 +1,430 @@ - + QmitkFiberQuantificationViewControls 0 0 365 581 Form QCommandLinkButton:disabled { border: none; } QGroupBox { background-color: transparent; } 25 Fiber-derived images 6 6 6 6 false 0 0 200 16777215 11 Perform selected operation on all selected fiber bundles. Generate Image 0 0 Upsampling factor 1 0.100000000000000 10.000000000000000 0.100000000000000 1.000000000000000 0 0 Tract Density Image (TDI) Normalized TDI Binary Envelope Fiber Bundle Image Fiber Endings Image Fiber Endings Pointset + + + Distance Map + + + + + Binary Skeleton + + Principal Fiber Directions 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 Fiber directions with an angle smaller than the defined threshold are clustered. 2 0.000000000000000 90.000000000000000 1.000000000000000 30.000000000000000 0 0 <html><head/><body><p>Directions shorter than the defined threshold are discarded.</p></body></html> 3 1.000000000000000 0.100000000000000 0.300000000000000 Angular Threshold: Max. Peaks: Size Threshold: 0 0 Maximum number of fiber directions per voxel. 100 3 Normalization: 0 0 0 Global maximum Single vector Voxel-wise maximum 0 0 Image containing the number of distinct fiber clusters per voxel. Output #Directions per Voxel false false Generate Directions Input Data 6 6 6 6 - + - + Tractogram: Reference Image: Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
- - -
\ No newline at end of file + + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryView.cpp index 8348c87..ff92686 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryView.cpp @@ -1,599 +1,598 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include "QmitkTractometryView.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include const std::string QmitkTractometryView::VIEW_ID = "org.mitk.views.tractometry"; using namespace mitk; QmitkTractometryView::QmitkTractometryView() : QmitkAbstractView() , m_Controls( nullptr ) , m_Visible(false) { } // Destructor QmitkTractometryView::~QmitkTractometryView() { } void QmitkTractometryView::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::QmitkTractometryViewControls; m_Controls->setupUi( parent ); - connect( m_Controls->m_SamplingPointsBox, SIGNAL(valueChanged(int)), this, SLOT(UpdateGui()) ); - connect( m_Controls->m_StDevBox, SIGNAL(stateChanged(int)), this, SLOT(UpdateGui()) ); + connect( m_Controls->m_MethodBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui()) ); + connect( m_Controls->m_StartButton, SIGNAL(clicked()), this, SLOT(StartTractometry()) ); mitk::TNodePredicateDataType::Pointer imageP = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDimension::Pointer dimP = mitk::NodePredicateDimension::New(3); m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ImageBox->SetPredicate(mitk::NodePredicateAnd::New(imageP, dimP)); m_Controls->m_ChartWidget->SetTheme(GetColorTheme()); m_Controls->m_ChartWidget->SetXAxisLabel("Tract position"); m_Controls->m_ChartWidget->SetYAxisLabel("Image Value"); } } ::QmitkChartWidget::ColorTheme QmitkTractometryView::GetColorTheme() { berry::IPreferencesService* prefService = berry::WorkbenchPlugin::GetDefault()->GetPreferencesService(); berry::IPreferences::Pointer m_StylePref = prefService->GetSystemPreferences()->Node(berry::QtPreferences::QT_STYLES_NODE); QString styleName = m_StylePref->Get(berry::QtPreferences::QT_STYLE_NAME, ""); if (styleName == ":/org.blueberry.ui.qt/darkstyle.qss") { return QmitkChartWidget::ColorTheme::darkstyle; } else { return QmitkChartWidget::ColorTheme::lightstyle; } } void QmitkTractometryView::SetFocus() { } void QmitkTractometryView::UpdateGui() { berry::IWorkbenchPart::Pointer nullPart; OnSelectionChanged(nullPart, QList(m_CurrentSelection)); } bool QmitkTractometryView::Flip(vtkSmartPointer< vtkPolyData > polydata1, int i, vtkSmartPointer< vtkPolyData > ref_poly) { double d_direct = 0; double d_flipped = 0; vtkCell* cell1 = polydata1->GetCell(0); if (ref_poly!=nullptr) cell1 = ref_poly->GetCell(0); auto numPoints1 = cell1->GetNumberOfPoints(); vtkPoints* points1 = cell1->GetPoints(); std::vector> ref_points; for (int j=0; jGetPoint(j); itk::Point itk_p; itk_p[0] = p1[0]; itk_p[1] = p1[1]; itk_p[2] = p1[2]; ref_points.push_back(itk_p); } vtkCell* cell2 = polydata1->GetCell(i); vtkPoints* points2 = cell2->GetPoints(); for (int j=0; jGetPoint(j); d_direct = (p1[0]-p2[0])*(p1[0]-p2[0]) + (p1[1]-p2[1])*(p1[1]-p2[1]) + (p1[2]-p2[2])*(p1[2]-p2[2]); double* p3 = points2->GetPoint(numPoints1-j-1); d_flipped = (p1[0]-p3[0])*(p1[0]-p3[0]) + (p1[1]-p3[1])*(p1[1]-p3[1]) + (p1[2]-p3[2])*(p1[2]-p3[2]); } if (d_direct>d_flipped) return true; return false; } template void QmitkTractometryView::StaticResamplingTractometry(const mitk::PixelType, mitk::Image::Pointer image, mitk::DataNode::Pointer node, std::vector > &data, std::string& clipboard_string) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); unsigned int num_points = m_Controls->m_SamplingPointsBox->value(); mitk::ImagePixelReadAccessor readimage(image, image->GetVolumeData(0)); mitk::FiberBundle::Pointer working_fib = fib->GetDeepCopy(); working_fib->ResampleToNumPoints(num_points); vtkSmartPointer< vtkPolyData > polydata = working_fib->GetFiberPolyData(); double rgb[3] = {0,0,0}; mitk::LookupTable::Pointer lookupTable = mitk::LookupTable::New(); lookupTable->SetType(mitk::LookupTable::MULTILABEL); std::vector > all_values; std::vector< double > mean_values; for (unsigned int i=0; iGetNumFibers(); ++i) { vtkCell* cell = polydata->GetCell(i); auto numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); std::vector< double > fib_vals; bool flip = false; if (i>0) flip = Flip(polydata, i); else if (m_ReferencePolyData!=nullptr) flip = Flip(polydata, 0, m_ReferencePolyData); for (int j=0; jGetTableValue(j, rgb); double* p; if (flip) { auto p_idx = numPoints - j - 1; p = points->GetPoint(p_idx); working_fib->ColorSinglePoint(i, p_idx, rgb); } else { p = points->GetPoint(j); working_fib->ColorSinglePoint(i, j, rgb); } Point3D px; px[0] = p[0]; px[1] = p[1]; px[2] = p[2]; double pixelValue = static_cast(readimage.GetPixelByWorldCoordinates(px)); fib_vals.push_back(pixelValue); mean += pixelValue; if (pixelValuemax) max = pixelValue; mean_values.at(j) += pixelValue; } all_values.push_back(fib_vals); } if (m_ReferencePolyData==nullptr) m_ReferencePolyData = polydata; std::vector< double > std_values1; std::vector< double > std_values2; for (unsigned int i=0; iGetNumFibers(); double stdev = 0; for (unsigned int j=0; j(mean_values.at(i)); clipboard_string += " "; clipboard_string += boost::lexical_cast(stdev); clipboard_string += "\n"; } clipboard_string += "\n"; data.push_back(mean_values); data.push_back(std_values1); data.push_back(std_values2); MITK_INFO << "Min: " << min; MITK_INFO << "Max: " << max; MITK_INFO << "Mean: " << mean/working_fib->GetNumberOfPoints(); if (m_Controls->m_ShowBinned->isChecked()) { - mitk::DataNode::Pointer new_node; + mitk::DataNode::Pointer new_node = mitk::DataNode::New(); auto children = GetDataStorage()->GetDerivations(node); for (unsigned int i=0; isize(); ++i) { if (children->at(i)->GetName() == "binned_static") { new_node = children->at(i); new_node->SetData(working_fib); + new_node->SetVisibility(true); + node->SetVisibility(false); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return; } } - new_node = mitk::DataNode::New(); new_node->SetData(working_fib); new_node->SetName("binned_static"); + new_node->SetVisibility(true); + node->SetVisibility(false); GetDataStorage()->Add(new_node, node); } } template void QmitkTractometryView::NearestCentroidPointTractometry(const mitk::PixelType, mitk::Image::Pointer image, mitk::DataNode::Pointer node, std::vector< std::vector< double > >& data, std::string& clipboard_string) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); unsigned int num_points = m_Controls->m_SamplingPointsBox->value(); mitk::ImagePixelReadAccessor readimage(image, image->GetVolumeData(0)); mitk::FiberBundle::Pointer working_fib = fib->GetDeepCopy(); working_fib->ResampleSpline(1.0); vtkSmartPointer< vtkPolyData > working_polydata = working_fib->GetFiberPolyData(); // clustering std::vector< mitk::ClusteringMetric* > metrics; - metrics.push_back({new mitk::ClusteringMetricEuclideanMean()}); - - int cluster_size = 20; - float max_d = 0; - int i=1; - std::vector< float > distances; - while (max_d < working_fib->GetGeometry()->GetDiagonalLength()/2) - { - distances.push_back(cluster_size*i); - max_d = cluster_size*i; - ++i; - } + metrics.push_back({new mitk::ClusteringMetricEuclideanStd()}); mitk::FiberBundle::Pointer fib_static_resampled = fib->GetDeepCopy(); fib_static_resampled->ResampleToNumPoints(num_points); vtkSmartPointer< vtkPolyData > polydata_static_resampled = fib_static_resampled->GetFiberPolyData(); + std::vector centroids; std::shared_ptr< mitk::TractClusteringFilter > clusterer = std::make_shared(); - clusterer->SetDistances(distances); - clusterer->SetTractogram(fib_static_resampled); - - clusterer->SetMetrics(metrics); - clusterer->SetMergeDuplicateThreshold(-1); - clusterer->SetNumPoints(num_points); - clusterer->SetMaxClusters(3); - clusterer->SetMinClusterSize(5); - clusterer->Update(); -// std::vector tracts = clusterer->GetOutTractograms(); - std::vector centroids = clusterer->GetOutCentroids(); + int c=0; + while (c<30 && (centroids.empty() || centroids.size()>static_cast(m_Controls->m_MaxCentroids->value()))) + { + float cluster_size = m_Controls->m_ClusterSize->value() + m_Controls->m_ClusterSize->value()*c*0.2; + float max_d = 0; + int i=1; + std::vector< float > distances; + while (max_d < working_fib->GetGeometry()->GetDiagonalLength()/2) + { + distances.push_back(cluster_size*i); + max_d = cluster_size*i; + ++i; + } + + clusterer->SetDistances(distances); + clusterer->SetTractogram(fib_static_resampled); + clusterer->SetMetrics(metrics); + clusterer->SetMergeDuplicateThreshold(cluster_size); + clusterer->SetDoResampling(false); + clusterer->SetNumPoints(num_points); + // clusterer->SetMaxClusters(m_Controls->m_MaxCentroids->value()); + clusterer->SetMinClusterSize(1); + clusterer->Update(); + centroids = clusterer->GetOutCentroids(); + ++c; + } double rgb[3] = {0,0,0}; mitk::LookupTable::Pointer lookupTable = mitk::LookupTable::New(); lookupTable->SetType(mitk::LookupTable::MULTILABEL); std::vector > all_values; std::vector< double > mean_values; std::vector< unsigned int > value_count; for (unsigned int i=0; iGetFiberPolyData(); - double min = 100000.0; double max = 0; double mean = 0; for (unsigned int i=0; iGetNumFibers(); ++i) { vtkCell* cell = working_polydata->GetCell(i); auto numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); std::vector< double > fib_vals; - - bool flip = false; - if (i>0) - flip = Flip(polydata_static_resampled, i); - else if (m_ReferencePolyData!=nullptr) - flip = Flip(polydata_static_resampled, 0, m_ReferencePolyData); - for (int j=0; jGetPoint(numPoints - j - 1); - else - p = points->GetPoint(j); + double* p = points->GetPoint(j); int min_bin = 0; float d=999999; for (auto centroid : centroids) { auto centroid_polydata = centroid->GetFiberPolyData(); vtkCell* centroid_cell = centroid_polydata->GetCell(0); auto centroid_numPoints = centroid_cell->GetNumberOfPoints(); vtkPoints* centroid_points = centroid_cell->GetPoints(); + bool centroid_flip = Flip(centroid_polydata, 0, centroids.at(0)->GetFiberPolyData()); + for (int bin=0; binGetPoint(bin); float temp_d = std::sqrt((p[0]-centroid_p[0])*(p[0]-centroid_p[0]) + (p[1]-centroid_p[1])*(p[1]-centroid_p[1]) + (p[2]-centroid_p[2])*(p[2]-centroid_p[2])); if (temp_dGetTableValue(min_bin, rgb); - if (flip) - working_fib->ColorSinglePoint(i, numPoints - j - 1, rgb); - else - working_fib->ColorSinglePoint(i, j, rgb); + working_fib->ColorSinglePoint(i, j, rgb); Point3D px; px[0] = p[0]; px[1] = p[1]; px[2] = p[2]; double pixelValue = static_cast(readimage.GetPixelByWorldCoordinates(px)); fib_vals.push_back(pixelValue); mean += pixelValue; if (pixelValuemax) max = pixelValue; mean_values.at(min_bin) += pixelValue; value_count.at(min_bin) += 1; } all_values.push_back(fib_vals); } if (m_ReferencePolyData==nullptr) m_ReferencePolyData = working_polydata; std::vector< double > std_values1; std::vector< double > std_values2; for (unsigned int i=0; i(mean_values.at(i)); clipboard_string += " "; clipboard_string += boost::lexical_cast(stdev); clipboard_string += "\n"; } clipboard_string += "\n"; data.push_back(mean_values); data.push_back(std_values1); data.push_back(std_values2); MITK_INFO << "Min: " << min; MITK_INFO << "Max: " << max; MITK_INFO << "Mean: " << mean/working_fib->GetNumberOfPoints(); if (m_Controls->m_ShowBinned->isChecked()) { - mitk::DataNode::Pointer new_node; - mitk::DataNode::Pointer new_node2; + mitk::DataNode::Pointer new_node = mitk::DataNode::New(); +// mitk::DataNode::Pointer new_node2; auto children = GetDataStorage()->GetDerivations(node); for (unsigned int i=0; isize(); ++i) { if (children->at(i)->GetName() == "binned_centroid") { new_node = children->at(i); new_node->SetData(working_fib); + new_node->SetVisibility(true); + node->SetVisibility(false); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return; } - - if (children->at(i)->GetName() == "binned_centroid_centroid") - { - new_node2 = children->at(i); - new_node2->SetData(centroids.at(0)); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - return; - } - } - - new_node = mitk::DataNode::New(); new_node->SetData(working_fib); new_node->SetName("binned_centroid"); + new_node->SetVisibility(true); + node->SetVisibility(false); GetDataStorage()->Add(new_node, node); - - new_node2 = mitk::DataNode::New(); - new_node2->SetData(centroids.at(0)); - new_node2->SetName("binned_centroid_centroid"); - GetDataStorage()->Add(new_node2, node); } } void QmitkTractometryView::Activated() { } void QmitkTractometryView::Deactivated() { } void QmitkTractometryView::Visible() { m_Visible = true; QList selection = GetDataManagerSelection(); berry::IWorkbenchPart::Pointer nullPart; OnSelectionChanged(nullPart, selection); } void QmitkTractometryView::Hidden() { m_Visible = false; } std::string QmitkTractometryView::RGBToHexString(double *rgb) { std::ostringstream os; for (int i = 0; i < 3; ++i) { os << std::setw(2) << std::setfill('0') << std::hex << static_cast(rgb[i] * 255); } return os.str(); } -void QmitkTractometryView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) +void QmitkTractometryView::StartTractometry() { - if (!m_Visible) - return; - - m_CurrentSelection.clear(); - if(m_Controls->m_ImageBox->GetSelectedNode().IsNull()) - return; - - std::string clipboardString = ""; m_ReferencePolyData = nullptr; - mitk::Image::Pointer image = dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData()); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 1.0); lookupTable->Build(); - int num_tracts = 0; - for (auto node: nodes) - if ( dynamic_cast(node->GetData()) ) - num_tracts++; + mitk::Image::Pointer image = dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData()); - int c = 1; this->m_Controls->m_ChartWidget->Clear(); - for (auto node: nodes) + std::string clipboardString = ""; + int c = 1; + for (auto node : m_CurrentSelection) { - if ( dynamic_cast(node->GetData()) ) - { - clipboardString += node->GetName() + "\n"; - clipboardString += "mean stdev\n"; - m_CurrentSelection.push_back(node); + clipboardString += node->GetName() + "\n"; + clipboardString += "mean stdev\n"; - std::vector< std::vector< double > > data; + std::vector< std::vector< double > > data; + if (m_Controls->m_MethodBox->currentIndex()==0) + { + mitkPixelTypeMultiplex4( StaticResamplingTractometry, image->GetPixelType(), image, node, data, clipboardString ); + } + else + { mitkPixelTypeMultiplex4( NearestCentroidPointTractometry, image->GetPixelType(), image, node, data, clipboardString ); + } - m_Controls->m_ChartWidget->AddData1D(data.at(0), node->GetName() + " Mean", QmitkChartWidget::ChartType::line); - if (m_Controls->m_StDevBox->isChecked()) - { - this->m_Controls->m_ChartWidget->AddData1D(data.at(1), node->GetName() + " +STDEV", QmitkChartWidget::ChartType::line); - this->m_Controls->m_ChartWidget->AddData1D(data.at(2), node->GetName() + " -STDEV", QmitkChartWidget::ChartType::line); - } - - double color[3]; - if (num_tracts>1) - { - float scalar_color = ( (float)c/num_tracts - 1.0/num_tracts )/(1.0-1.0/num_tracts); - lookupTable->GetColor(1.0 - scalar_color, color); - } - else - lookupTable->GetColor(0, color); + m_Controls->m_ChartWidget->AddData1D(data.at(0), node->GetName() + " Mean", QmitkChartWidget::ChartType::line); + if (m_Controls->m_StDevBox->isChecked()) + { + this->m_Controls->m_ChartWidget->AddData1D(data.at(1), node->GetName() + " +STDEV", QmitkChartWidget::ChartType::line); + this->m_Controls->m_ChartWidget->AddData1D(data.at(2), node->GetName() + " -STDEV", QmitkChartWidget::ChartType::line); + } - this->m_Controls->m_ChartWidget->SetColor(node->GetName() + " Mean", RGBToHexString(color)); + double color[3]; + if (m_CurrentSelection.size()>1) + { + float scalar_color = ( (float)c/m_CurrentSelection.size() - 1.0/m_CurrentSelection.size() )/(1.0-1.0/m_CurrentSelection.size()); + lookupTable->GetColor(1.0 - scalar_color, color); + } + else + lookupTable->GetColor(0, color); - if (m_Controls->m_StDevBox->isChecked()) - { - color[0] *= 0.5; - color[1] *= 0.5; - color[2] *= 0.5; - this->m_Controls->m_ChartWidget->SetColor(node->GetName() + " +STDEV", RGBToHexString(color)); - this->m_Controls->m_ChartWidget->SetColor(node->GetName() + " -STDEV", RGBToHexString(color)); - } + this->m_Controls->m_ChartWidget->SetColor(node->GetName() + " Mean", RGBToHexString(color)); - this->m_Controls->m_ChartWidget->Show(true); - this->m_Controls->m_ChartWidget->SetShowDataPoints(false); - ++c; + if (m_Controls->m_StDevBox->isChecked()) + { + color[0] *= 0.5; + color[1] *= 0.5; + color[2] *= 0.5; + this->m_Controls->m_ChartWidget->SetColor(node->GetName() + " +STDEV", RGBToHexString(color)); + this->m_Controls->m_ChartWidget->SetColor(node->GetName() + " -STDEV", RGBToHexString(color)); } + + this->m_Controls->m_ChartWidget->Show(true); + this->m_Controls->m_ChartWidget->SetShowDataPoints(false); + ++c; } QApplication::clipboard()->setText(clipboardString.c_str(), QClipboard::Clipboard); +} +void QmitkTractometryView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) +{ + m_Controls->m_StartButton->setEnabled(false); + + if (!m_Visible) + return; + + if (m_Controls->m_MethodBox->currentIndex()==0) + m_Controls->m_ClusterFrame->setVisible(false); + else + m_Controls->m_ClusterFrame->setVisible(true); + + m_CurrentSelection.clear(); + if(m_Controls->m_ImageBox->GetSelectedNode().IsNull()) + return; + + for (auto node: nodes) + if ( dynamic_cast(node->GetData()) ) + m_CurrentSelection.push_back(node); + if (!m_CurrentSelection.empty()) + m_Controls->m_StartButton->setEnabled(true); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryView.h index cae5b26..d8939fb 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryView.h @@ -1,84 +1,85 @@ /*=================================================================== 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 QmitkTractometryView_h #define QmitkTractometryView_h #include #include "ui_QmitkTractometryViewControls.h" #include #include #include #include #include #include /*! \brief Weight fibers by linearly fitting them to the image data. */ class QmitkTractometryView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; QmitkTractometryView(); virtual ~QmitkTractometryView(); virtual void CreateQtPartControl(QWidget *parent) override; template void StaticResamplingTractometry(const mitk::PixelType, mitk::Image::Pointer image, mitk::DataNode::Pointer node, std::vector< std::vector< double > >& data, std::string& clipboard_string); template void NearestCentroidPointTractometry(const mitk::PixelType, mitk::Image::Pointer image, mitk::DataNode::Pointer node, std::vector< std::vector< double > >& data, std::string& clipboard_string); virtual void SetFocus() override; virtual void Activated() override; virtual void Deactivated() override; virtual void Visible() override; virtual void Hidden() override; protected slots: void UpdateGui(); + void StartTractometry(); protected: /// \brief called by QmitkAbstractView when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; QmitkChartWidget::ColorTheme GetColorTheme(); Ui::QmitkTractometryViewControls* m_Controls; bool Flip(vtkSmartPointer< vtkPolyData > polydata1, int i, vtkSmartPointer ref_poly=nullptr); std::string RGBToHexString(double *rgb); vtkSmartPointer< vtkPolyData > m_ReferencePolyData; QList m_CurrentSelection; bool m_Visible; }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui index 6ae9a07..5123bbe 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui @@ -1,146 +1,217 @@ QmitkTractometryViewControls 0 0 484 - 715 + 744 Form QCommandLinkButton:disabled { border: none; } QGroupBox { background-color: transparent; } + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Show STDEV + + + true + + + + + + + Show binned tract + + + true + + + + + + + + 0 + 600 + + + + + + + + Centroid Options + + + + + + Cluster Size: + + + + + + + Max. Number of Centroids: + + + + + + + 1 + + + 99 + + + 1 + + + + + + + 15.000000000000000 + + + + + + QFrame::NoFrame QFrame::Raised 0 0 0 0 6 - - - - Input Image: - - - - + 3 99999 20 - + + + + Input Image: + + + + Sampling Points: + + + + + Static Resampling + + + + + Centroid Based + + + + + + + + Binning Method: + + + - - - - - 0 - 600 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - Show STDEV - - - true - - - - - + - Show binned tract - - - true + Start Tractometry QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkChartWidget QWidget
QmitkChartWidget.h
diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui index 66f5d48..89eedb8 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui @@ -1,1652 +1,1652 @@ QmitkStreamlineTrackingViewControls 0 0 453 859 0 0 QmitkTemplate QCommandLinkButton:disabled { border: none; } QGroupBox { background-color: transparent; } 3 3 0 40 QFrame::NoFrame QFrame::Raised 0 15 0 0 6 15 true 0 0 true QFrame::NoFrame QFrame::Raised 0 0 0 0 0 true Save parameters to json file Save Parameters :/QmitkTractography/download.png:/QmitkTractography/download.png true Load parameters from json file Load Parameters :/QmitkTractography/upload.png:/QmitkTractography/upload.png false Start Tractography :/QmitkTractography/right.png:/QmitkTractography/right.png true Stop tractography and return all fibers reconstructed until now. Stop Tractography :/QmitkTractography/stop.png:/QmitkTractography/stop.png QFrame::NoFrame QFrame::Raised 0 0 0 0 Input Image. ODF, tensor and peak images are currently supported. Input Image: Input Image. ODF, tensor, peak, and, in case of ML tractography, raw diffusion-weighted images are currently supported. <html><head/><body><p><span style=" color:#ff0000;">select image in data-manager</span></p></body></html> true Tractography Forest: 0 0 0 0 75 true 0 0 0 421 254 Seeding Specify how, where and how many tractography seed points are placed. QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Number of seed points equally distributed around selected position. 1 9999999 50 Radius: Seedpoints are equally distributed within a sphere centered at the selected position with the specified radius (in mm). 2 50.000000000000000 0.100000000000000 2.000000000000000 Num. Seeds: true When checked, parameter changes cause instant retracking while in interactive mode. Update on Parameter Change true QFrame::NoFrame QFrame::Raised 0 0 0 0 Try each seed N times until a valid streamline is obtained (only for probabilistic tractography). Minimum fiber length (in mm) 1 999 10 Trials Per Seed: Max. Num. Fibers: Tractography is stopped after the desired number of fibers is reached, even before all seed points are processed (-1 means no limit). -1 999999999 -1 QFrame::NoFrame QFrame::Raised 0 0 0 0 Seeds per Voxel: Seed Image: Number of seed points placed in each voxel. 1 9999999 true Dynamically pick a seed location by click into image. Enable Interactive Tractography Qt::Vertical 20 40 0 0 435 - 184 + 181 ROI Constraints Specify various ROI and mask images to constrain the tractography process. Mask Image: Select which fibers should be accepted or rejected based on the location of their endpoints. QComboBox::AdjustToMinimumContentsLength No Constraints on EP locations Both EPs in Target Image Both EPs in Target Image But Different Label One EP in Seed Image and One EP in Target Image At Least One EP in Target Image Exactly One EP in Target Image No EP in Target Image Endpoint Constraints: Stop ROI Image: Exclusion ROI Image: Target ROI Image: Qt::Vertical 20 40 0 - 0 + -191 421 428 Tractography Parameters Specify the behavior of the tractography at each streamline integration step (step size, deterministic/probabilistic, ...). Minimum tract length in mm. Shorter fibers are discarded. Minimum fiber length (in mm) 1 999.000000000000000 1.000000000000000 20.000000000000000 f parameter of tensor tractography. f=1 + g=0 means FACT (depending on the chosen interpolation). f=0 and g=1 means TEND (disable interpolation for this mode!). f: f=1 + g=0 means FACT (depending on the chosen interpolation). f=0 and g=1 means TEND (disable interpolation for this mode!). 2 1.000000000000000 0.100000000000000 0.000000000000000 Sharpen ODFs: Fix Random Seed: - Maximum allowed angular SDTEV over 4 voxel lengths. Default: no loop check. + Maximum allowed angular SDTEV over 4 voxel lengths. Default: 30° -1 180 - -1 + 30 Angular Threshold: Max. Tract Length: Cutoff: If you are using dODF images as input, it is advisable to sharpen the ODFs (min-max normalize and raise to the power of 4). This is not necessary for CSD fODFs, since they are naturally much sharper. Angular threshold between two steps (in degree). Default: 90° * step_size -1 90 1 -1 Qt::Vertical 20 40 f=1 + g=0 means FACT (depending on the chosen interpolation). f=0 and g=1 means TEND (disable interpolation for this mode!). 2 1.000000000000000 0.100000000000000 1.000000000000000 Toggle between deterministic and probabilistic tractography. Some modes might not be available for all types of tractography. Deterministic Probabilistic Mode: Additional threshold on the ODF magnitude. This is useful in case of CSD fODF tractography. For fODFs a good default value is 0.1, for normalized dODFs, e.g. Q-ball ODFs, this threshold should be very low (0.00025) or 0. 5 1.000000000000000 0.100000000000000 0.000250000000000 Min. Tract Length: FA/GFA Image: Loop Check: Minimum tract length in mm. Shorter fibers are discarded. Maximum fiber length (in mm) 1 999.000000000000000 1.000000000000000 400.000000000000000 Always produce the same random numbers. Step Size: ODF Cutoff: Step size (in voxels) 2 0.010000000000000 10.000000000000000 0.100000000000000 0.500000000000000 g: Threshold on peak magnitude, FA, GFA, ... 5 1.000000000000000 0.100000000000000 0.100000000000000 Peak Jitter: Important for probabilistic peak tractography and peak prior. Actual jitter is drawn from a normal distribution with peak_jitter*fabs(direction_value) as standard deviation. 3 1.000000000000000 0.100000000000000 0.010000000000000 0 0 435 - 184 + 181 Tractography Prior Weight: Weighting factor between prior and data. 1.000000000000000 0.100000000000000 0.500000000000000 Peak Image: Qt::Vertical 20 40 If unchecked, the prior cannot create directions where there are none in the data. true New Directions from Prior: Restrict to Prior: Restrict tractography to regions where the prior is valid. true QFrame::NoFrame QFrame::Raised 0 0 0 0 0 y x z Flip Directions: 0 0 435 - 184 + 181 Neighborhood Sampling Specify if and how information about the current streamline neighborhood should be used. Only neighborhood samples in front of the current streamline position are considered. Use Only Frontal Samples false If checked, the majority of sampling points has to place a stop-vote for the streamline to terminate. If not checked, all sampling positions have to vote for a streamline termination. Use Stop-Votes false QFrame::NoFrame QFrame::Raised 0 0 0 0 Num. Samples: Number of neighborhood samples that are used to determine the next fiber progression direction. 50 Sampling Distance: Sampling distance (in voxels) 2 10.000000000000000 0.100000000000000 0.250000000000000 Qt::Vertical 20 40 0 0 435 - 184 + 181 Data Handling Specify interpolation and direction flips. QFrame::NoFrame QFrame::Raised 0 0 0 0 Trilinearly interpolate the input image used for tractography. Interpolate Tractography Data true Trilinearly interpolate the ROI images used to constrain the tractography. Interpolate ROI Images true QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Internally flips progression directions. This might be necessary depending on the input data. x Internally flips progression directions. This might be necessary depending on the input data. y Internally flips progression directions. This might be necessary depending on the input data. z Flip directions: Qt::Vertical 20 40 0 0 435 - 184 + 181 Output and Postprocessing Specify the tractography output (streamlines or probability maps) and postprocessing steps. Qt::Vertical 20 40 Compress fibers using the specified error constraint. Compress Fibers true Output map with voxel-wise visitation counts instead of streamlines. Output Probability Map false QmitkSingleNodeSelectionWidget QWidget
QmitkSingleNodeSelectionWidget.h
1