diff --git a/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake index 5158c2452d..eaacdac1da 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake @@ -1,35 +1,35 @@ #----------------------------------------------------------------------------- # MITK Data #----------------------------------------------------------------------------- # Sanity checks if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") endif() set(proj MITK-Data) set(proj_DEPENDENCIES) set(MITK-Data_DEPENDS ${proj}) if(BUILD_TESTING) - set(revision_tag 5f90eb5e) + set(revision_tag 248b7888) # ^^^^^^^^ these are just to check correct length of hash part ExternalProject_Add(${proj} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/MITK-Data_${revision_tag}.tar.gz UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS ${proj_DEPENDENCIES} ) set(MITK_DATA_DIR ${ep_source_dir}/${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif(BUILD_TESTING) diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp index 4a19131757..fcc0f997e6 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp @@ -1,883 +1,883 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkStreamlineTrackingFilter_txx #define __itkStreamlineTrackingFilter_txx #include #include #include #include "itkStreamlineTrackingFilter.h" #include #include #include #define _USE_MATH_DEFINES #include namespace itk { //#define QBALL_RECON_PI M_PI template< class TTensorPixelType, class TPDPixelType> StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::StreamlineTrackingFilter(): m_FaThreshold(0.2), m_StepSize(1), m_MaxLength(10000), m_SeedsPerVoxel(1), m_F(1.0), m_G(0.0), m_Interpolate(true), m_MinTractLength(0.0), m_ResampleFibers(false) { // At least 1 inputs is necessary for a vector image. // For images added one at a time we need at least six this->SetNumberOfRequiredInputs( 1 ); this->SetNumberOfIndexedInputs(3); } template< class TTensorPixelType, class TPDPixelType> double StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::RoundToNearest(double num) { return (num > 0.0) ? floor(num + 0.5) : ceil(num - 0.5); } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::BeforeThreadedGenerateData() { m_FiberPolyData = FiberPolyDataType::New(); m_Points = vtkPoints::New(); m_Cells = vtkCellArray::New(); InputImageType* inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); m_ImageSize.resize(3); m_ImageSize[0] = inputImage->GetLargestPossibleRegion().GetSize()[0]; m_ImageSize[1] = inputImage->GetLargestPossibleRegion().GetSize()[1]; m_ImageSize[2] = inputImage->GetLargestPossibleRegion().GetSize()[2]; if (m_ImageSize[0]<3 || m_ImageSize[1]<3 || m_ImageSize[2]<3) m_Interpolate = false; m_ImageSpacing.resize(3); m_ImageSpacing[0] = inputImage->GetSpacing()[0]; m_ImageSpacing[1] = inputImage->GetSpacing()[1]; m_ImageSpacing[2] = inputImage->GetSpacing()[2]; float minSpacing; if(m_ImageSpacing[0]::New(); for (unsigned int i=0; iGetNumberOfThreads(); i++) { FiberPolyDataType poly = FiberPolyDataType::New(); m_PolyDataContainer->InsertElement(i, poly); } if (m_SeedImage.IsNull()) { // initialize mask image m_SeedImage = ItkUcharImgType::New(); m_SeedImage->SetSpacing( inputImage->GetSpacing() ); m_SeedImage->SetOrigin( inputImage->GetOrigin() ); m_SeedImage->SetDirection( inputImage->GetDirection() ); m_SeedImage->SetRegions( inputImage->GetLargestPossibleRegion() ); m_SeedImage->Allocate(); m_SeedImage->FillBuffer(1); } if (m_MaskImage.IsNull()) { // initialize mask image m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( inputImage->GetSpacing() ); m_MaskImage->SetOrigin( inputImage->GetOrigin() ); m_MaskImage->SetDirection( inputImage->GetDirection() ); m_MaskImage->SetRegions( inputImage->GetLargestPossibleRegion() ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } bool useUserFaImage = true; if (m_FaImage.IsNull()) { m_FaImage = ItkFloatImgType::New(); m_FaImage->SetSpacing( inputImage->GetSpacing() ); m_FaImage->SetOrigin( inputImage->GetOrigin() ); m_FaImage->SetDirection( inputImage->GetDirection() ); m_FaImage->SetRegions( inputImage->GetLargestPossibleRegion() ); m_FaImage->Allocate(); m_FaImage->FillBuffer(0.0); useUserFaImage = false; } m_NumberOfInputs = 0; for (unsigned int i=0; iGetNumberOfIndexedInputs(); i++) { if (this->ProcessObject::GetInput(i)==NULL) break; ItkPDImgType::Pointer pdImage = ItkPDImgType::New(); pdImage->SetSpacing( inputImage->GetSpacing() ); pdImage->SetOrigin( inputImage->GetOrigin() ); pdImage->SetDirection( inputImage->GetDirection() ); pdImage->SetRegions( inputImage->GetLargestPossibleRegion() ); pdImage->Allocate(); m_PdImage.push_back(pdImage); ItkFloatImgType::Pointer emaxImage = ItkFloatImgType::New(); emaxImage->SetSpacing( inputImage->GetSpacing() ); emaxImage->SetOrigin( inputImage->GetOrigin() ); emaxImage->SetDirection( inputImage->GetDirection() ); emaxImage->SetRegions( inputImage->GetLargestPossibleRegion() ); emaxImage->Allocate(); emaxImage->FillBuffer(1.0); m_EmaxImage.push_back(emaxImage); typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(i) ); m_InputImage.push_back(inputImage); m_NumberOfInputs++; } MITK_INFO << "Processing " << m_NumberOfInputs << " tensor files"; typedef itk::DiffusionTensor3D TensorType; typename TensorType::EigenValuesArrayType eigenvalues; typename TensorType::EigenVectorsMatrixType eigenvectors; for (int x=0; xGetPixel(index); vnl_vector_fixed dir; tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); dir[0] = eigenvectors(2, 0); dir[1] = eigenvectors(2, 1); dir[2] = eigenvectors(2, 2); dir.normalize(); m_PdImage.at(i)->SetPixel(index, dir); if (!useUserFaImage) m_FaImage->SetPixel(index, m_FaImage->GetPixel(index)+tensor.GetFractionalAnisotropy()); m_EmaxImage.at(i)->SetPixel(index, 2/eigenvalues[2]); } if (!useUserFaImage) m_FaImage->SetPixel(index, m_FaImage->GetPixel(index)/m_NumberOfInputs); } if (m_Interpolate) std::cout << "StreamlineTrackingFilter: using trilinear interpolation" << std::endl; else { if (m_MinCurvatureRadius<0.0) m_MinCurvatureRadius = 0.1*minSpacing; std::cout << "StreamlineTrackingFilter: using nearest neighbor interpolation" << std::endl; } if (m_MinCurvatureRadius<0.0) m_MinCurvatureRadius = 0.5*minSpacing; std::cout << "StreamlineTrackingFilter: Min. curvature radius: " << m_MinCurvatureRadius << std::endl; std::cout << "StreamlineTrackingFilter: FA threshold: " << m_FaThreshold << std::endl; std::cout << "StreamlineTrackingFilter: stepsize: " << m_StepSize << " mm" << std::endl; std::cout << "StreamlineTrackingFilter: f: " << m_F << std::endl; std::cout << "StreamlineTrackingFilter: g: " << m_G << std::endl; - std::cout << "StreamlineTrackingFilter: starting streamline tracking" << std::endl; + std::cout << "StreamlineTrackingFilter: starting streamline tracking using " << this->GetNumberOfThreads() << " threads." << std::endl; } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::CalculateNewPosition(itk::ContinuousIndex& pos, vnl_vector_fixed& dir, typename InputImageType::IndexType& index) { vnl_matrix_fixed< double, 3, 3 > rot = m_InputImage.at(0)->GetDirection().GetTranspose(); dir = rot*dir; if (true) { dir *= m_StepSize; pos[0] += dir[0]/m_ImageSpacing[0]; pos[1] += dir[1]/m_ImageSpacing[1]; pos[2] += dir[2]/m_ImageSpacing[2]; index[0] = RoundToNearest(pos[0]); index[1] = RoundToNearest(pos[1]); index[2] = RoundToNearest(pos[2]); } else { dir[0] /= m_ImageSpacing[0]; dir[1] /= m_ImageSpacing[1]; dir[2] /= m_ImageSpacing[2]; int smallest = 0; float x = 100000; if (dir[0]>0) { if (fabs(fabs(RoundToNearest(pos[0])-pos[0])-0.5)>mitk::eps) x = fabs(pos[0]-RoundToNearest(pos[0])-0.5)/dir[0]; else x = fabs(pos[0]-std::ceil(pos[0])-0.5)/dir[0]; } else if (dir[0]<0) { if (fabs(fabs(RoundToNearest(pos[0])-pos[0])-0.5)>mitk::eps) x = -fabs(pos[0]-RoundToNearest(pos[0])+0.5)/dir[0]; else x = -fabs(pos[0]-std::floor(pos[0])+0.5)/dir[0]; } float s = x; float y = 100000; if (dir[1]>0) { if (fabs(fabs(RoundToNearest(pos[1])-pos[1])-0.5)>mitk::eps) y = fabs(pos[1]-RoundToNearest(pos[1])-0.5)/dir[1]; else y = fabs(pos[1]-std::ceil(pos[1])-0.5)/dir[1]; } else if (dir[1]<0) { if (fabs(fabs(RoundToNearest(pos[1])-pos[1])-0.5)>mitk::eps) y = -fabs(pos[1]-RoundToNearest(pos[1])+0.5)/dir[1]; else y = -fabs(pos[1]-std::floor(pos[1])+0.5)/dir[1]; } if (s>y) { s=y; smallest = 1; } float z = 100000; if (dir[2]>0) { if (fabs(fabs(RoundToNearest(pos[2])-pos[2])-0.5)>mitk::eps) z = fabs(pos[2]-RoundToNearest(pos[2])-0.5)/dir[2]; else z = fabs(pos[2]-std::ceil(pos[2])-0.5)/dir[2]; } else if (dir[2]<0) { if (fabs(fabs(RoundToNearest(pos[2])-pos[2])-0.5)>mitk::eps) z = -fabs(pos[2]-RoundToNearest(pos[2])+0.5)/dir[2]; else z = -fabs(pos[2]-std::floor(pos[2])+0.5)/dir[2]; } if (s>z) { s=z; smallest = 2; } // MITK_INFO << "---------------------------------------------"; // MITK_INFO << "s: " << s; // MITK_INFO << "dir: " << dir; // MITK_INFO << "old: " << pos[0] << ", " << pos[1] << ", " << pos[2]; pos[0] += dir[0]*s; pos[1] += dir[1]*s; pos[2] += dir[2]*s; switch (smallest) { case 0: if (dir[0]<0) index[0] = std::floor(pos[0]); else index[0] = std::ceil(pos[0]); index[1] = RoundToNearest(pos[1]); index[2] = RoundToNearest(pos[2]); break; case 1: if (dir[1]<0) index[1] = std::floor(pos[1]); else index[1] = std::ceil(pos[1]); index[0] = RoundToNearest(pos[0]); index[2] = RoundToNearest(pos[2]); break; case 2: if (dir[2]<0) index[2] = std::floor(pos[2]); else index[2] = std::ceil(pos[2]); index[1] = RoundToNearest(pos[1]); index[0] = RoundToNearest(pos[0]); } // float x = 100000; // if (dir[0]>0) // x = fabs(pos[0]-RoundToNearest(pos[0])-0.5)/dir[0]; // else if (dir[0]<0) // x = -fabs(pos[0]-RoundToNearest(pos[0])+0.5)/dir[0]; // float s = x; // float y = 100000; // if (dir[1]>0) // y = fabs(pos[1]-RoundToNearest(pos[1])-0.5)/dir[1]; // else if (dir[1]<0) // y = -fabs(pos[1]-RoundToNearest(pos[1])+0.5)/dir[1]; // if (s>y) // s=y; // float z = 100000; // if (dir[2]>0) // z = fabs(pos[2]-RoundToNearest(pos[2])-0.5)/dir[2]; // else if (dir[2]<0) // z = -fabs(pos[2]-RoundToNearest(pos[2])+0.5)/dir[2]; // if (s>z) // s=z; // s *= 1.001; // pos[0] += dir[0]*s; // pos[1] += dir[1]*s; // pos[2] += dir[2]*s; // index[0] = RoundToNearest(pos[0]); // index[1] = RoundToNearest(pos[1]); // index[2] = RoundToNearest(pos[2]); // MITK_INFO << "new: " << pos[0] << ", " << pos[1] << ", " << pos[2]; } } template< class TTensorPixelType, class TPDPixelType> bool StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::IsValidPosition(itk::ContinuousIndex& pos, typename InputImageType::IndexType &index, vnl_vector_fixed< float, 8 >& interpWeights, int imageIdx) { if (!m_InputImage.at(imageIdx)->GetLargestPossibleRegion().IsInside(index) || m_MaskImage->GetPixel(index)==0) return false; if (m_Interpolate) { float frac_x = pos[0] - index[0]; float frac_y = pos[1] - index[1]; float frac_z = pos[2] - index[2]; if (frac_x<0) { index[0] -= 1; frac_x += 1; } if (frac_y<0) { index[1] -= 1; frac_y += 1; } if (frac_z<0) { index[2] -= 1; frac_z += 1; } frac_x = 1-frac_x; frac_y = 1-frac_y; frac_z = 1-frac_z; // int coordinates inside image? if (index[0] < 0 || index[0] >= m_ImageSize[0]-1) return false; if (index[1] < 0 || index[1] >= m_ImageSize[1]-1) return false; if (index[2] < 0 || index[2] >= m_ImageSize[2]-1) return false; interpWeights[0] = ( frac_x)*( frac_y)*( frac_z); interpWeights[1] = (1-frac_x)*( frac_y)*( frac_z); interpWeights[2] = ( frac_x)*(1-frac_y)*( frac_z); interpWeights[3] = ( frac_x)*( frac_y)*(1-frac_z); interpWeights[4] = (1-frac_x)*(1-frac_y)*( frac_z); interpWeights[5] = ( frac_x)*(1-frac_y)*(1-frac_z); interpWeights[6] = (1-frac_x)*( frac_y)*(1-frac_z); interpWeights[7] = (1-frac_x)*(1-frac_y)*(1-frac_z); typename InputImageType::IndexType tmpIdx; float FA = m_FaImage->GetPixel(index) * interpWeights[0]; tmpIdx = index; tmpIdx[0]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[1]; tmpIdx = index; tmpIdx[1]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[2]; tmpIdx = index; tmpIdx[2]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[3]; tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[4]; tmpIdx = index; tmpIdx[1]++; tmpIdx[2]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[5]; tmpIdx = index; tmpIdx[2]++; tmpIdx[0]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[6]; tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++; FA += m_FaImage->GetPixel(tmpIdx) * interpWeights[7]; if (FAGetPixel(index) float StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::FollowStreamline(itk::ContinuousIndex pos, int dirSign, vtkPoints* points, std::vector< vtkIdType >& ids, int imageIdx) { float tractLength = 0; typedef itk::DiffusionTensor3D TensorType; typename TensorType::EigenValuesArrayType eigenvalues; typename TensorType::EigenVectorsMatrixType eigenvectors; vnl_vector_fixed< float, 8 > interpWeights; typename InputImageType::IndexType index, indexOld; indexOld[0] = -1; indexOld[1] = -1; indexOld[2] = -1; itk::Point worldPos; float distance = 0; float distanceInVoxel = 0; // starting index and direction index[0] = RoundToNearest(pos[0]); index[1] = RoundToNearest(pos[1]); index[2] = RoundToNearest(pos[2]); vnl_vector_fixed dir = m_PdImage.at(imageIdx)->GetPixel(index); dir *= dirSign; // reverse direction vnl_vector_fixed dirOld = dir; if (dir.magnitude()TransformContinuousIndexToPhysicalPoint( pos, worldPos ); ids.push_back(points->InsertNextPoint(worldPos.GetDataPointer())); return tractLength; } else if (distance>=m_PointPistance) { m_SeedImage->TransformContinuousIndexToPhysicalPoint( pos, worldPos ); ids.push_back(points->InsertNextPoint(worldPos.GetDataPointer())); distance = 0; } if (!m_Interpolate) // use nearest neighbour interpolation { if (indexOld!=index) // did we enter a new voxel? if yes, calculate new direction { double minAngle = 0; for (int img=0; img newDir = m_PdImage.at(img)->GetPixel(index); // get principal direction if (newDir.magnitude()GetPixel(index); float scale = m_EmaxImage.at(img)->GetPixel(index); newDir[0] = m_F*newDir[0] + (1-m_F)*( (1-m_G)*dirOld[0] + scale*m_G*(tensor[0]*dirOld[0] + tensor[1]*dirOld[1] + tensor[2]*dirOld[2])); newDir[1] = m_F*newDir[1] + (1-m_F)*( (1-m_G)*dirOld[1] + scale*m_G*(tensor[1]*dirOld[0] + tensor[3]*dirOld[1] + tensor[4]*dirOld[2])); newDir[2] = m_F*newDir[2] + (1-m_F)*( (1-m_G)*dirOld[2] + scale*m_G*(tensor[2]*dirOld[0] + tensor[4]*dirOld[1] + tensor[5]*dirOld[2])); newDir.normalize(); float angle = dot_product(dirOld, newDir); if (angle<0) { newDir *= -1; angle *= -1; } if (angle>minAngle) { minAngle = angle; dir = newDir; } } //float r = m_StepSize/(2*std::asin(std::acos(minAngle)/2)); vnl_vector_fixed v3 = dir+dirOld; v3 *= m_StepSize; float a = m_StepSize; float b = m_StepSize; float c = v3.magnitude(); float r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle) if (r1) { double minAngle = 0; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor = tmpTensor * interpWeights[0]; minAngle = 0; tmpIdx = index; tmpIdx[0]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[1]; minAngle = 0; tmpIdx = index; tmpIdx[1]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[2]; minAngle = 0; tmpIdx = index; tmpIdx[2]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[3]; minAngle = 0; tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[4]; minAngle = 0; tmpIdx = index; tmpIdx[1]++; tmpIdx[2]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[5]; minAngle = 0; tmpIdx = index; tmpIdx[2]++; tmpIdx[0]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[6]; minAngle = 0; tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++; for (int img=0; imgGetPixel(tmpIdx)); if (fabs(angle)>minAngle) { minAngle = angle; tmpTensor = m_InputImage.at(img)->GetPixel(tmpIdx); } } tensor += tmpTensor * interpWeights[7]; } else { tensor = m_InputImage.at(0)->GetPixel(index) * interpWeights[0]; typename InputImageType::IndexType tmpIdx = index; tmpIdx[0]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[1]; tmpIdx = index; tmpIdx[1]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[2]; tmpIdx = index; tmpIdx[2]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[3]; tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[4]; tmpIdx = index; tmpIdx[1]++; tmpIdx[2]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[5]; tmpIdx = index; tmpIdx[2]++; tmpIdx[0]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[6]; tmpIdx = index; tmpIdx[0]++; tmpIdx[1]++; tmpIdx[2]++; tensor += m_InputImage.at(0)->GetPixel(tmpIdx) * interpWeights[7]; } tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors); dir[0] = eigenvectors(2, 0); dir[1] = eigenvectors(2, 1); dir[2] = eigenvectors(2, 2); if (dir.magnitude() v3 = dir+dirOld; v3 *= m_StepSize; float a = m_StepSize; float b = m_StepSize; float c = v3.magnitude(); float r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle) if (r void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType threadId) { FiberPolyDataType poly = m_PolyDataContainer->GetElement(threadId); vtkSmartPointer points = vtkSmartPointer::New(); vtkSmartPointer Cells = vtkSmartPointer::New(); typedef itk::DiffusionTensor3D TensorType; typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typedef ImageRegionConstIterator< ItkUcharImgType > MaskIteratorType; typedef ImageRegionConstIterator< ItkFloatImgType > FloatIteratorType; typedef typename InputImageType::PixelType InputTensorType; MaskIteratorType sit(m_SeedImage, outputRegionForThread ); FloatIteratorType fit(m_FaImage, outputRegionForThread ); MaskIteratorType mit(m_MaskImage, outputRegionForThread ); for (int img=0; img worldPos; while( !sit.IsAtEnd() ) { if (sit.Value()==0 || fit.Value() line = vtkSmartPointer::New(); std::vector< vtkIdType > pointIDs; typename InputImageType::IndexType index = sit.GetIndex(); itk::ContinuousIndex start; unsigned int counter = 0; if (m_SeedsPerVoxel>1) { start[0] = index[0]+(double)(rand()%99-49)/100; start[1] = index[1]+(double)(rand()%99-49)/100; start[2] = index[2]+(double)(rand()%99-49)/100; } else { start[0] = index[0]; start[1] = index[1]; start[2] = index[2]; } // forward tracking float tractLength = FollowStreamline(start, 1, points, pointIDs, img); // add ids to line counter += pointIDs.size(); while (!pointIDs.empty()) { line->GetPointIds()->InsertNextId(pointIDs.back()); pointIDs.pop_back(); } // insert start point m_SeedImage->TransformContinuousIndexToPhysicalPoint( start, worldPos ); line->GetPointIds()->InsertNextId(points->InsertNextPoint(worldPos.GetDataPointer())); // backward tracking tractLength += FollowStreamline(start, -1, points, pointIDs, img); counter += pointIDs.size(); //MITK_INFO << "Tract length " << tractLength; if (tractLengthGetPointIds()->InsertNextId(pointIDs.at(i)); Cells->InsertNextCell(line); } ++sit; ++mit; ++fit; } } poly->SetPoints(points); poly->SetLines(Cells); std::cout << "Thread " << threadId << " finished tracking" << std::endl; } template< class TTensorPixelType, class TPDPixelType> vtkSmartPointer< vtkPolyData > StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::AddPolyData(FiberPolyDataType poly1, FiberPolyDataType poly2) { vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = poly1->GetLines(); vtkSmartPointer vNewPoints = poly1->GetPoints(); for( int i=0; iGetNumberOfLines(); i++ ) { vtkCell* cell = poly2->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } // initialize polydata vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); return vNewPolyData; } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::AfterThreadedGenerateData() { MITK_INFO << "Generating polydata "; m_FiberPolyData = m_PolyDataContainer->GetElement(0); for (unsigned int i=1; iGetNumberOfThreads(); i++) { m_FiberPolyData = AddPolyData(m_FiberPolyData, m_PolyDataContainer->GetElement(i)); } MITK_INFO << "done"; } template< class TTensorPixelType, class TPDPixelType> void StreamlineTrackingFilter< TTensorPixelType, TPDPixelType> ::PrintSelf(std::ostream& os, Indent indent) const { } } #endif // __itkDiffusionQballPrincipleDirectionsImageFilter_txx diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt b/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt index 2050e47d81..f5a6692d8d 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt +++ b/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt @@ -1,11 +1,11 @@ MITK_CREATE_MODULE_TESTS() mitkAddCustomModuleTest(mitkFiberBundleXReaderWriterTest mitkFiberBundleXReaderWriterTest ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX.fib) mitkAddCustomModuleTest(mitkGibbsTrackingTest mitkGibbsTrackingTest ${MITK_DATA_DIR}/DiffusionImaging/qBallImage.qbi ${MITK_DATA_DIR}/DiffusionImaging/diffusionImageMask.nrrd ${MITK_DATA_DIR}/DiffusionImaging/gibbsTrackingParameters.gtp ${MITK_DATA_DIR}/DiffusionImaging/gibbsTractogram.fib) -mitkAddCustomModuleTest(mitkStreamlineTrackingTest mitkStreamlineTrackingTest ${MITK_DATA_DIR}/DiffusionImaging/tensorImage.dti ${MITK_DATA_DIR}/DiffusionImaging/diffusionImageMask.nrrd ${MITK_DATA_DIR}/DiffusionImaging/streamlineTractogram.fib) +mitkAddCustomModuleTest(mitkStreamlineTrackingTest mitkStreamlineTrackingTest ${MITK_DATA_DIR}/DiffusionImaging/tensorImage.dti ${MITK_DATA_DIR}/DiffusionImaging/diffusionImageMask.nrrd ${MITK_DATA_DIR}/DiffusionImaging/streamlineTractogramInterpolated.fib) #mitkAddCustomModuleTest(mitkPeakExtractionTest mitkPeakExtractionTest ${MITK_DATA_DIR}/DiffusionImaging/qBallImage_SHCoeffs.nrrd ${MITK_DATA_DIR}/DiffusionImaging/diffusionImageMask.nrrd ${MITK_DATA_DIR}/DiffusionImaging/qBallImage_VectorField.fib) mitkAddCustomModuleTest(mitkLocalFiberPlausibilityTest mitkLocalFiberPlausibilityTest ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX.fib ${MITK_DATA_DIR}/DiffusionImaging/LDFP_GT_DIRECTION_0.nrrd ${MITK_DATA_DIR}/DiffusionImaging/LDFP_GT_DIRECTION_1.nrrd ${MITK_DATA_DIR}/DiffusionImaging/LDFP_ERROR_IMAGE.nrrd ${MITK_DATA_DIR}/DiffusionImaging/LDFP_NUM_DIRECTIONS.nrrd ${MITK_DATA_DIR}/DiffusionImaging/LDFP_VECTOR_FIELD.fib ${MITK_DATA_DIR}/DiffusionImaging/LDFP_ERROR_IMAGE_IGNORE.nrrd) mitkAddCustomModuleTest(mitkFiberTransformationTest mitkFiberTransformationTest ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_transformed.fib) mitkAddCustomModuleTest(mitkFiberExtractionTest mitkFiberExtractionTest ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_extracted.fib ${MITK_DATA_DIR}/DiffusionImaging/ROI1.pf ${MITK_DATA_DIR}/DiffusionImaging/ROI2.pf ${MITK_DATA_DIR}/DiffusionImaging/ROI3.pf ${MITK_DATA_DIR}/DiffusionImaging/ROIIMAGE.nrrd ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_inside.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_outside.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_passing-mask.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_ending-in-mask.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_subtracted.fib ${MITK_DATA_DIR}/DiffusionImaging/fiberBundleX_added.fib) mitkAddCustomModuleTest(mitkFiberGenerationTest mitkFiberGenerationTest ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/Fiducial_0.pf ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/Fiducial_1.pf ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/Fiducial_2.pf ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/uniform.fib ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/gaussian.fib) # TODO: fiberfox signalgen diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkStreamlineTrackingTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkStreamlineTrackingTest.cpp index ade4aa983d..6ed17969da 100755 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkStreamlineTrackingTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkStreamlineTrackingTest.cpp @@ -1,130 +1,135 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include using namespace std; int mitkStreamlineTrackingTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkStreamlineTrackingTest"); MITK_TEST_CONDITION_REQUIRED(argc>3,"check for input data") string dtiFileName = argv[1]; string maskFileName = argv[2]; string referenceFileName = argv[3]; MITK_INFO << "DTI file: " << dtiFileName; MITK_INFO << "Mask file: " << maskFileName; MITK_INFO << "Reference fiber file: " << referenceFileName; float minFA = 0.05; float minCurv = -1; float stepSize = -1; float tendf = 1; float tendg = 0; float minLength = 20; int numSeeds = 1; - bool interpolate = false; + bool interpolate = true; try { RegisterDiffusionCoreObjectFactory(); RegisterFiberTrackingObjectFactory(); // load input image const std::string s1="", s2=""; std::vector infile = mitk::BaseDataIO::LoadBaseDataFromFile( dtiFileName, s1, s2, false ); MITK_INFO << "Loading tensor image ..."; typedef itk::Image< itk::DiffusionTensor3D, 3 > ItkTensorImage; mitk::TensorImage::Pointer mitkTensorImage = dynamic_cast(infile.at(0).GetPointer()); ItkTensorImage::Pointer itk_dti = ItkTensorImage::New(); mitk::CastToItkImage(mitkTensorImage, itk_dti); MITK_INFO << "Loading seed image ..."; typedef itk::Image< unsigned char, 3 > ItkUCharImageType; mitk::Image::Pointer mitkSeedImage = mitk::IOUtil::LoadImage(maskFileName); MITK_INFO << "Loading mask image ..."; mitk::Image::Pointer mitkMaskImage = mitk::IOUtil::LoadImage(maskFileName); // instantiate tracker typedef itk::StreamlineTrackingFilter< float > FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput(itk_dti); filter->SetSeedsPerVoxel(numSeeds); filter->SetFaThreshold(minFA); filter->SetMinCurvatureRadius(minCurv); filter->SetStepSize(stepSize); filter->SetF(tendf); filter->SetG(tendg); filter->SetInterpolate(interpolate); filter->SetMinTractLength(minLength); filter->SetNumberOfThreads(1); if (mitkSeedImage.IsNotNull()) { ItkUCharImageType::Pointer mask = ItkUCharImageType::New(); mitk::CastToItkImage(mitkSeedImage, mask); filter->SetSeedImage(mask); } if (mitkMaskImage.IsNotNull()) { ItkUCharImageType::Pointer mask = ItkUCharImageType::New(); mitk::CastToItkImage(mitkMaskImage, mask); filter->SetMaskImage(mask); } filter->Update(); vtkSmartPointer fiberBundle = filter->GetFiberPolyData(); mitk::FiberBundleX::Pointer fib1 = mitk::FiberBundleX::New(fiberBundle); + mitk::FiberBundleXWriter::Pointer writer = mitk::FiberBundleXWriter::New(); + writer->SetFileName("testBundle.fib"); + writer->SetInputFiberBundleX(fib1); + writer->Update(); + infile = mitk::BaseDataIO::LoadBaseDataFromFile( referenceFileName, s1, s2, false ); mitk::FiberBundleX::Pointer fib2 = dynamic_cast(infile.at(0).GetPointer()); MITK_TEST_CONDITION_REQUIRED(fib2.IsNotNull(), "Check if reference tractogram is not null."); MITK_TEST_CONDITION_REQUIRED(fib1->Equals(fib2), "Check if tractograms are equal."); } catch (itk::ExceptionObject e) { MITK_INFO << e; return EXIT_FAILURE; } catch (std::exception e) { MITK_INFO << e.what(); return EXIT_FAILURE; } catch (...) { MITK_INFO << "ERROR!?!"; return EXIT_FAILURE; } MITK_TEST_END(); }