diff --git a/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.cpp b/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.cpp index b2f8429ad2..22f0f65ac7 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.cpp @@ -1,520 +1,528 @@ /*=================================================================== 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 __itkFiniteDiffOdfMaximaExtractionFilter_cpp #define __itkFiniteDiffOdfMaximaExtractionFilter_cpp #include "itkFiniteDiffOdfMaximaExtractionFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace boost::math; namespace itk { static bool CompareVectors(const vnl_vector_fixed< double, 3 >& v1, const vnl_vector_fixed< double, 3 >& v2) { return (v1.magnitude()>v2.magnitude()); } template< class PixelType, int ShOrder, int NrOdfDirections > FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::FiniteDiffOdfMaximaExtractionFilter() : m_NormalizationMethod(MAX_VEC_NORM) , m_MaxNumPeaks(2) , m_PeakThreshold(0.4) , m_AbsolutePeakThreshold(0) , m_ClusteringThreshold(0.9) , m_AngularThreshold(0.7) , m_NumCoeffs((ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder) , m_Toolkit(FSL) { this->SetNumberOfRequiredInputs(1); } template< class PixelType, int ShOrder, int NrOdfDirections > void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::FindCandidatePeaks(OdfType& odf, double thr, std::vector< DirectionType >& container) { double gfa = odf.GetGeneralizedFractionalAnisotropy(); //Find the peaks using a finite difference method bool flag = true; vnl_vector_fixed< bool, NrOdfDirections > used; used.fill(false); //Find the peaks for (int i=0; ithr && val*gfa>m_AbsolutePeakThreshold) // limit to one hemisphere ??? { flag = true; std::vector< int > neighbours = odf.GetNeighbors(i); for (unsigned int j=0; j std::vector< vnl_vector_fixed< double, 3 > > FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections>::MeanShiftClustering(std::vector< vnl_vector_fixed< double, 3 > >& inDirs) { std::vector< DirectionType > outDirs; if (inDirs.empty()) return inDirs; DirectionType oldMean, currentMean, workingMean; std::vector< int > touched; // initialize touched.resize(inDirs.size(), 0); bool free = true; currentMean = inDirs[0]; // initialize first seed while (free) { oldMean.fill(0.0); // start mean-shift clustering float angle = 0.0; int counter = 0; while ((currentMean-oldMean).magnitude()>0.0001) { counter = 0; oldMean = currentMean; workingMean = oldMean; workingMean.normalize(); currentMean.fill(0.0); for (unsigned int i=0; i=m_ClusteringThreshold) { currentMean += inDirs[i]; touched[i] = 1; counter++; } else if (-angle>=m_ClusteringThreshold) { currentMean -= inDirs[i]; touched[i] = 1; counter++; } } } // found stable mean if (counter>0) { float mag = currentMean.magnitude(); if (mag>0) { currentMean /= mag; outDirs.push_back(currentMean); } } // find next unused seed free = false; for (unsigned int i=0; i void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::BeforeThreadedGenerateData() { typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) ); itk::Vector spacing = ShCoeffImage->GetSpacing(); double minSpacing = spacing[0]; if (spacing[1]GetOrigin(); itk::Matrix direction = ShCoeffImage->GetDirection(); ImageRegion<3> imageRegion = ShCoeffImage->GetLargestPossibleRegion(); if (m_MaskImage.IsNotNull()) { origin = m_MaskImage->GetOrigin(); direction = m_MaskImage->GetDirection(); imageRegion = m_MaskImage->GetLargestPossibleRegion(); } m_DirectionImageContainer = ItkDirectionImageContainer::New(); for (unsigned int i=0; i nullVec; nullVec.Fill(0.0); ItkDirectionImage::Pointer img = ItkDirectionImage::New(); img->SetSpacing( spacing ); img->SetOrigin( origin ); img->SetDirection( direction ); img->SetRegions( imageRegion ); img->Allocate(); img->FillBuffer(nullVec); m_DirectionImageContainer->InsertElement(m_DirectionImageContainer->Size(), img); } if (m_MaskImage.IsNull()) { m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( spacing ); m_MaskImage->SetOrigin( origin ); m_MaskImage->SetDirection( direction ); m_MaskImage->SetRegions( imageRegion ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } m_NumDirectionsImage = ItkUcharImgType::New(); m_NumDirectionsImage->SetSpacing( spacing ); m_NumDirectionsImage->SetOrigin( origin ); m_NumDirectionsImage->SetDirection( direction ); m_NumDirectionsImage->SetRegions( imageRegion ); m_NumDirectionsImage->Allocate(); m_NumDirectionsImage->FillBuffer(0); this->SetNumberOfIndexedOutputs(m_MaxNumPeaks); // calculate SH basis OdfType odf; vnl_matrix_fixed* directions = odf.GetDirections(); vnl_matrix< double > sphCoords; std::vector< DirectionType > dirs; for (int i=0; iget_column(i)); Cart2Sph(dirs, sphCoords); // convert candidate peaks to spherical angles m_ShBasis = CalcShBasis(sphCoords); // evaluate spherical harmonics at each peak MITK_INFO << "Starting finite differences maximum extraction"; MITK_INFO << "ODF sampling points: " << NrOdfDirections; MITK_INFO << "SH order: " << ShOrder; MITK_INFO << "Maximum peaks: " << m_MaxNumPeaks; MITK_INFO << "Relative threshold: " << m_PeakThreshold; MITK_INFO << "Absolute threshold: " << m_AbsolutePeakThreshold; MITK_INFO << "Clustering threshold: " << m_ClusteringThreshold; MITK_INFO << "Angular threshold: " << m_AngularThreshold; } template< class PixelType, int ShOrder, int NrOdfDirections > void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::AfterThreadedGenerateData() { MITK_INFO << "Generating vector field"; vtkSmartPointer m_VtkCellArray = vtkSmartPointer::New(); vtkSmartPointer m_VtkPoints = vtkSmartPointer::New(); typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) ); ImageRegionConstIterator< CoefficientImageType > cit(ShCoeffImage, ShCoeffImage->GetLargestPossibleRegion() ); mitk::Vector3D spacing = ShCoeffImage->GetSpacing(); double minSpacing = spacing[0]; if (spacing[1]GetLargestPossibleRegion().GetSize()[0]*ShCoeffImage->GetLargestPossibleRegion().GetSize()[1]*ShCoeffImage->GetLargestPossibleRegion().GetSize()[2]; boost::progress_display disp(maxProgress); while( !cit.IsAtEnd() ) { ++disp; typename CoefficientImageType::IndexType index = cit.GetIndex(); if (m_MaskImage->GetPixel(index)==0) { ++cit; continue; } for (unsigned int i=0; iSize(); i++) { ItkDirectionImage::Pointer img = m_DirectionImageContainer->GetElement(i); itk::Vector< float, 3 > pixel = img->GetPixel(index); DirectionType dir; dir[0] = pixel[0]; dir[1] = pixel[1]; dir[2] = pixel[2]; vtkSmartPointer container = vtkSmartPointer::New(); itk::ContinuousIndex center; center[0] = index[0]; center[1] = index[1]; center[2] = index[2]; itk::Point worldCenter; m_MaskImage->TransformContinuousIndexToPhysicalPoint( center, worldCenter ); itk::Point worldStart; worldStart[0] = worldCenter[0]-dir[0]/2 * minSpacing; worldStart[1] = worldCenter[1]-dir[1]/2 * minSpacing; worldStart[2] = worldCenter[2]-dir[2]/2 * minSpacing; vtkIdType id = m_VtkPoints->InsertNextPoint(worldStart.GetDataPointer()); container->GetPointIds()->InsertNextId(id); itk::Point worldEnd; worldEnd[0] = worldCenter[0]+dir[0]/2 * minSpacing; worldEnd[1] = worldCenter[1]+dir[1]/2 * minSpacing; worldEnd[2] = worldCenter[2]+dir[2]/2 * minSpacing; id = m_VtkPoints->InsertNextPoint(worldEnd.GetDataPointer()); container->GetPointIds()->InsertNextId(id); m_VtkCellArray->InsertNextCell(container); } ++cit; } vtkSmartPointer directionsPolyData = vtkSmartPointer::New(); directionsPolyData->SetPoints(m_VtkPoints); directionsPolyData->SetLines(m_VtkCellArray); m_OutputFiberBundle = mitk::FiberBundle::New(directionsPolyData); for (unsigned int i=0; iSize(); i++) { ItkDirectionImage::Pointer img = m_DirectionImageContainer->GetElement(i); this->SetNthOutput(i, img); } } template< class PixelType, int ShOrder, int NrOdfDirections > void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::ThreadedGenerateData( const OutputImageRegionType& outputRegionForThread, ThreadIdType threadID ) { typename CoefficientImageType::Pointer ShCoeffImage = static_cast< CoefficientImageType* >( this->ProcessObject::GetInput(0) ); ImageRegionConstIterator< CoefficientImageType > cit(ShCoeffImage, outputRegionForThread ); OdfType odf; while( !cit.IsAtEnd() ) { typename CoefficientImageType::IndexType index = cit.GetIndex(); if (m_MaskImage->GetPixel(index)==0) { ++cit; continue; } CoefficientPixelType c = cit.Get(); // calculate ODF double max = 0; odf.Fill(0.0); for (int i=0; imax) max = odf[i]; } if (max<0.0001) { ++cit; continue; } std::vector< DirectionType > candidates, peaks, temp; peaks.clear(); max *= m_PeakThreshold; // relative threshold FindCandidatePeaks(odf, max, candidates); // find all local maxima candidates = MeanShiftClustering(candidates); // cluster maxima vnl_matrix< double > shBasis, sphCoords; Cart2Sph(candidates, sphCoords); // convert candidate peaks to spherical angles shBasis = CalcShBasis(sphCoords); // evaluate spherical harmonics at each peak max = 0.0; for (unsigned int i=0; imax) max = val; peaks.push_back(candidates[i]*val); } std::sort( peaks.begin(), peaks.end(), CompareVectors ); // sort peaks // kick out directions to close to a larger direction (too far away to cluster but too close to keep) unsigned int m = peaks.size(); if ( m>m_DirectionImageContainer->Size() ) m = m_DirectionImageContainer->Size(); for (unsigned int i=0; im_AngularThreshold && valm_DirectionImageContainer->Size() ) num = m_DirectionImageContainer->Size(); for (unsigned int i=0; i dir = peaks.at(i); ItkDirectionImage::Pointer img = m_DirectionImageContainer->GetElement(i); switch (m_NormalizationMethod) { case NO_NORM: break; case SINGLE_VEC_NORM: dir.normalize(); break; case MAX_VEC_NORM: dir /= max; break; } dir = m_MaskImage->GetDirection()*dir; + + if (m_FlipX) + dir[0] = -dir[0]; + if (m_FlipY) + dir[1] = -dir[1]; + if (m_FlipZ) + dir[2] = -dir[2]; + itk::Vector< float, 3 > pixel; - pixel.SetElement(0, -dir[0]); + pixel.SetElement(0, dir[0]); pixel.SetElement(1, dir[1]); pixel.SetElement(2, dir[2]); img->SetPixel(index, pixel); } m_NumDirectionsImage->SetPixel(index, num); ++cit; } MITK_INFO << "Thread " << threadID << " finished extraction"; } // convert cartesian to spherical coordinates template< class PixelType, int ShOrder, int NrOdfDirections > void FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::Cart2Sph(const std::vector< DirectionType >& dir, vnl_matrix& sphCoords) { sphCoords.set_size(dir.size(), 2); for (unsigned int i=0; i vnl_matrix FiniteDiffOdfMaximaExtractionFilter< PixelType, ShOrder, NrOdfDirections> ::CalcShBasis(vnl_matrix& sphCoords) { int M = sphCoords.rows(); int j, m; double mag, plm; vnl_matrix shBasis; shBasis.set_size(M, m_NumCoeffs); for (int p=0; p(l,abs(m),cos(sphCoords(p,0))); mag = sqrt((double)(2*l+1)/(4.0*M_PI)*factorial(l-abs(m))/factorial(l+abs(m)))*plm; if (m<0) shBasis(p,j) = sqrt(2.0)*mag*cos(fabs((double)m)*sphCoords(p,1)); else if (m==0) shBasis(p,j) = mag; else shBasis(p,j) = pow(-1.0, m)*sqrt(2.0)*mag*sin(m*sphCoords(p,1)); break; case MRTRIX: plm = legendre_p(l,abs(m),-cos(sphCoords(p,0))); mag = sqrt((double)(2*l+1)/(4.0*M_PI)*factorial(l-abs(m))/factorial(l+abs(m)))*plm; if (m>0) shBasis(p,j) = mag*cos(m*sphCoords(p,1)); else if (m==0) shBasis(p,j) = mag; else shBasis(p,j) = mag*sin(-m*sphCoords(p,1)); break; } j++; } } return shBasis; } } #endif // __itkFiniteDiffOdfMaximaExtractionFilter_cpp diff --git a/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h b/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h index 85e715b5e6..5fa2abdbb5 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h +++ b/Modules/DiffusionImaging/DiffusionCore/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h @@ -1,145 +1,151 @@ /*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkDiffusionTensor3DReconstructionImageFilter.h,v $ Language: C++ Date: $Date: 2006-03-27 17:01:06 $ Version: $Revision: 1.12 $ Copyright (c) Insight Software Consortium. All rights reserved. See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef __itkFiniteDiffOdfMaximaExtractionFilter_h_ #define __itkFiniteDiffOdfMaximaExtractionFilter_h_ #include "itkImageToImageFilter.h" #include "vnl/vnl_vector_fixed.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_svd.h" #include "itkVectorContainer.h" #include "itkVectorImage.h" #include #include namespace itk{ /** * \brief Extract ODF peaks by searching all local maxima on a densely sampled ODF und clustering these maxima to get the underlying fiber direction. * NrOdfDirections: number of sampling points on the ODF surface (about 20000 is a good value) */ template< class PixelType, int ShOrder, int NrOdfDirections > class FiniteDiffOdfMaximaExtractionFilter : public ImageToImageFilter< Image< Vector< PixelType, (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder >, 3 >, Image< Vector< PixelType, 3 >, 3 > > { public: enum Toolkit { ///< SH coefficient convention (depends on toolkit) FSL, MRTRIX }; enum NormalizationMethods { NO_NORM, ///< no length normalization of the output peaks SINGLE_VEC_NORM, ///< normalize the single peaks to length 1 MAX_VEC_NORM ///< normalize all peaks according to their length in comparison to the largest peak (0-1) }; typedef FiniteDiffOdfMaximaExtractionFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< Vector< PixelType, (ShOrder*ShOrder + ShOrder + 2)/2 + ShOrder >, 3 >, Image< Vector< PixelType, 3 >, 3 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) - /** Runtime information support. */ - itkTypeMacro(FiniteDiffOdfMaximaExtractionFilter, ImageToImageFilter) + /** Runtime information support. */ + itkTypeMacro(FiniteDiffOdfMaximaExtractionFilter, ImageToImageFilter) typedef typename Superclass::InputImageType CoefficientImageType; typedef typename CoefficientImageType::RegionType CoefficientImageRegionType; typedef typename CoefficientImageType::PixelType CoefficientPixelType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef OrientationDistributionFunction OdfType; typedef itk::Image ItkUcharImgType; typedef vnl_vector_fixed< double, 3 > DirectionType; typedef Image< Vector< float, 3 >, 3> ItkDirectionImage; typedef VectorContainer< unsigned int, ItkDirectionImage::Pointer > ItkDirectionImageContainer; // input itkSetMacro( MaxNumPeaks, unsigned int) ///< maximum number of peaks per voxel. if more peaks are detected, only the largest are kept. itkSetMacro( PeakThreshold, double) ///< threshold on the peak length relative to the largest peak inside the current voxel itkSetMacro( AbsolutePeakThreshold, double) ///< hard threshold on the peak length of all local maxima itkSetMacro( ClusteringThreshold, double) ///< directions closer together than the specified angular threshold will be clustered (in rad) itkSetMacro( AngularThreshold, double) ///< directions closer together than the specified threshold that remain after clustering are discarded (largest is kept) (in rad) itkSetMacro( MaskImage, ItkUcharImgType::Pointer) ///< only voxels inside the binary mask are processed itkSetMacro( NormalizationMethod, NormalizationMethods) ///< normalization method of ODF peaks + itkSetMacro( FlipX, bool) ///< flip peaks in x direction + itkSetMacro( FlipY, bool) ///< flip peaks in y direction + itkSetMacro( FlipZ, bool) ///< flip peaks in z direction // output itkGetMacro( OutputFiberBundle, mitk::FiberBundle::Pointer) ///< vector field (peak sizes rescaled for visualization purposes) itkGetMacro( DirectionImageContainer, ItkDirectionImageContainer::Pointer) ///< container for output peaks itkGetMacro( NumDirectionsImage, ItkUcharImgType::Pointer) ///< number of peaks per voxel itkSetMacro( Toolkit, Toolkit) ///< define SH coefficient convention (depends on toolkit) itkGetMacro( Toolkit, Toolkit) ///< SH coefficient convention (depends on toolkit) protected: FiniteDiffOdfMaximaExtractionFilter(); ~FiniteDiffOdfMaximaExtractionFilter(){} void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadID ); void AfterThreadedGenerateData(); /** Extract all local maxima from the densely sampled ODF surface. Thresholding possible. **/ void FindCandidatePeaks(OdfType& odf, double odfMax, std::vector< DirectionType >& inDirs); /** Cluster input directions within a certain angular threshold **/ std::vector< DirectionType > MeanShiftClustering(std::vector< DirectionType >& inDirs); /** Convert cartesian to spherical coordinates **/ void Cart2Sph(const std::vector< DirectionType >& dir, vnl_matrix& sphCoords); /** Calculate spherical harmonic basis of the defined order **/ vnl_matrix CalcShBasis(vnl_matrix& sphCoords); private: NormalizationMethods m_NormalizationMethod; ///< normalization method of ODF peaks unsigned int m_MaxNumPeaks; ///< maximum number of peaks per voxel. if more peaks are detected, only the largest are kept. double m_PeakThreshold; ///< threshold on the peak length relative to the largest peak inside the current voxel double m_AbsolutePeakThreshold;///< hard threshold on the peak length of all local maxima vnl_matrix< double > m_ShBasis; ///< container for evaluated SH base functions double m_ClusteringThreshold; ///< directions closer together than the specified angular threshold will be clustered (in rad) double m_AngularThreshold; ///< directions closer together than the specified threshold that remain after clustering are discarded (largest is kept) (in rad) const int m_NumCoeffs; ///< number of spherical harmonics coefficients - mitk::FiberBundle::Pointer m_OutputFiberBundle; ///< vector field (peak sizes rescaled for visualization purposes) + mitk::FiberBundle::Pointer m_OutputFiberBundle; ///< vector field (peak sizes rescaled for visualization purposes) ItkDirectionImageContainer::Pointer m_DirectionImageContainer;///< container for output peaks ItkUcharImgType::Pointer m_NumDirectionsImage; ///< number of peaks per voxel ItkUcharImgType::Pointer m_MaskImage; ///< only voxels inside the binary mask are processed Toolkit m_Toolkit; + bool m_FlipX; + bool m_FlipY; + bool m_FlipZ; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkFiniteDiffOdfMaximaExtractionFilter.cpp" #endif #endif //__itkFiniteDiffOdfMaximaExtractionFilter_h_ diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkPlanarFigureCompositeReader.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkPlanarFigureCompositeReader.cpp index ac5c37c7e7..62980678ef 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkPlanarFigureCompositeReader.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkPlanarFigureCompositeReader.cpp @@ -1,99 +1,100 @@ /*=================================================================== 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 "mitkPlanarFigureCompositeReader.h" #include #include #include #include #include #include #include "mitkDiffusionIOMimeTypes.h" #include +#define RAPIDXML_NO_EXCEPTIONS #include #include #include #include mitk::PlanarFigureCompositeReader::PlanarFigureCompositeReader() : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::PLANARFIGURECOMPOSITE_MIMETYPE(), "Planar Figure Composite Reader" ) { m_ServiceReg = this->RegisterService(); } mitk::PlanarFigureCompositeReader::PlanarFigureCompositeReader(const PlanarFigureCompositeReader &other) :mitk::AbstractFileReader(other) { } mitk::PlanarFigureCompositeReader * mitk::PlanarFigureCompositeReader::Clone() const { return new PlanarFigureCompositeReader(*this); } std::vector > mitk::PlanarFigureCompositeReader::Read() { std::vector > result; try { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, NULL ); setlocale(LC_ALL, locale.c_str()); std::string filename = this->GetInputLocation(); std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename); ext = itksys::SystemTools::LowerCase(ext); boost::property_tree::ptree tree; boost::property_tree::xml_parser::read_xml(filename, tree); int comptype = tree.get("comptype"); mitk::PlanarFigureComposite::Pointer pfc = mitk::PlanarFigureComposite::New(); switch(comptype) { case 0: pfc->setOperationType(mitk::PlanarFigureComposite::AND); MITK_INFO << "loading AND composition"; break; case 1: pfc->setOperationType(mitk::PlanarFigureComposite::OR); MITK_INFO << "loading OR composition"; break; case 2: pfc->setOperationType(mitk::PlanarFigureComposite::NOT); MITK_INFO << "loading NOT composition"; break; default: MITK_ERROR << filename << " contains no valid composition type!"; } std::vector > result; result.push_back(pfc.GetPointer()); setlocale(LC_ALL, currLocale.c_str()); return result; } catch(...) { throw; } return result; } diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkPlanarFigureCompositeWriter.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkPlanarFigureCompositeWriter.cpp index 66ca8d9ed7..65f024cbfd 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkPlanarFigureCompositeWriter.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkPlanarFigureCompositeWriter.cpp @@ -1,89 +1,90 @@ /*=================================================================== 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 "mitkPlanarFigureCompositeWriter.h" #include #include #include #include "mitkDiffusionIOMimeTypes.h" #include +#define RAPIDXML_NO_EXCEPTIONS #include #include mitk::PlanarFigureCompositeWriter::PlanarFigureCompositeWriter() : mitk::AbstractFileWriter(mitk::PlanarFigureComposite::GetStaticNameOfClass(), mitk::DiffusionIOMimeTypes::PLANARFIGURECOMPOSITE_MIMETYPE(), "Planar Figure Composite Writer") { RegisterService(); } mitk::PlanarFigureCompositeWriter::PlanarFigureCompositeWriter(const mitk::PlanarFigureCompositeWriter & other) :mitk::AbstractFileWriter(other) {} mitk::PlanarFigureCompositeWriter::~PlanarFigureCompositeWriter() {} mitk::PlanarFigureCompositeWriter * mitk::PlanarFigureCompositeWriter::Clone() const { return new mitk::PlanarFigureCompositeWriter(*this); } void mitk::PlanarFigureCompositeWriter::Write() { std::ostream* out; std::ofstream outStream; if( this->GetOutputStream() ) { out = this->GetOutputStream(); }else{ outStream.open( this->GetOutputLocation().c_str() ); out = &outStream; } if ( !out->good() ) { mitkThrow() << "Stream not good."; } try { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, NULL ); setlocale(LC_ALL, locale.c_str()); std::locale previousLocale(out->getloc()); std::locale I("C"); out->imbue(I); std::string filename = this->GetOutputLocation().c_str(); mitk::PlanarFigureComposite::ConstPointer input = dynamic_cast(this->GetInput()); std::string ext = itksys::SystemTools::GetFilenameLastExtension(this->GetOutputLocation().c_str()); boost::property_tree::ptree type; type.put("comptype", input->getOperationType()); boost::property_tree::xml_writer_settings writerSettings(' ', 2); boost::property_tree::xml_parser::write_xml(filename, type, std::locale(), writerSettings); setlocale(LC_ALL, currLocale.c_str()); } catch(...) { throw; } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkAddArtifactsToDwiImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkAddArtifactsToDwiImageFilter.cpp index 8b1fab2b28..68b3292bd6 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkAddArtifactsToDwiImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkAddArtifactsToDwiImageFilter.cpp @@ -1,376 +1,348 @@ /*=================================================================== 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 __itkAddArtifactsToDwiImageFilter_txx #define __itkAddArtifactsToDwiImageFilter_txx #include #include #include #include "itkAddArtifactsToDwiImageFilter.h" #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include namespace itk { template< class TPixelType > AddArtifactsToDwiImageFilter< TPixelType > ::AddArtifactsToDwiImageFilter() : m_UseConstantRandSeed(false) { this->SetNumberOfRequiredInputs( 1 ); m_RandGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); m_RandGen->SetSeed(); } template< class TPixelType > void AddArtifactsToDwiImageFilter< TPixelType > ::GenerateData() { if (m_UseConstantRandSeed) // always generate the same random numbers? m_RandGen->SetSeed(0); else m_RandGen->SetSeed(); m_StartTime = clock(); m_StatusText = "Starting simulation\n"; typename InputImageType::Pointer inputImage = static_cast< InputImageType* >( this->ProcessObject::GetInput(0) ); itk::ImageRegion<3> inputRegion = inputImage->GetLargestPossibleRegion(); typename itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage( inputImage ); duplicator->Update(); typename InputImageType::Pointer outputImage = duplicator->GetOutput(); // is input slize size even? int xMax=inputRegion.GetSize(0); int yMax=inputRegion.GetSize(1); if ( xMax%2 == 1 ) xMax += 1; if ( yMax%2 == 1 ) yMax += 1; // create slice object typename SliceType::Pointer slice = SliceType::New(); ImageRegion<2> sliceRegion; sliceRegion.SetSize(0, xMax); sliceRegion.SetSize(1, yMax); slice->SetLargestPossibleRegion( sliceRegion ); slice->SetBufferedRegion( sliceRegion ); slice->SetRequestedRegion( sliceRegion ); slice->Allocate(); slice->FillBuffer(0.0); ImageRegion<2> upsampledSliceRegion; if ( m_Parameters.m_SignalGen.m_DoAddGibbsRinging) { upsampledSliceRegion.SetSize(0, xMax*2); upsampledSliceRegion.SetSize(1, yMax*2); } - // frequency map slice - typename SliceType::Pointer fMapSlice = NULL; - if ( m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) - { - fMapSlice = SliceType::New(); - fMapSlice->SetLargestPossibleRegion( sliceRegion ); - fMapSlice->SetBufferedRegion( sliceRegion ); - fMapSlice->SetRequestedRegion( sliceRegion ); - fMapSlice->Allocate(); - fMapSlice->FillBuffer(0.0); - } - m_Parameters.m_SignalGen.m_SignalScale = 1; m_Parameters.m_SignalGen.m_DoSimulateRelaxation = false; if ( m_Parameters.m_SignalGen.m_Spikes>0 || m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull() || m_Parameters.m_SignalGen.m_KspaceLineOffset>0.0 || m_Parameters.m_SignalGen.m_DoAddGibbsRinging || m_Parameters.m_SignalGen.m_EddyStrength>0 || m_Parameters.m_SignalGen.m_CroppingFactor<1.0) { ImageRegion<3> croppedRegion = inputRegion; croppedRegion.SetSize(1, croppedRegion.GetSize(1)* m_Parameters.m_SignalGen.m_CroppingFactor); itk::Point shiftedOrigin = inputImage->GetOrigin(); shiftedOrigin[1] += (inputRegion.GetSize(1)-croppedRegion.GetSize(1))*inputImage->GetSpacing()[1]/2; outputImage = InputImageType::New(); outputImage->SetSpacing( inputImage->GetSpacing() ); outputImage->SetOrigin( shiftedOrigin ); outputImage->SetDirection( inputImage->GetDirection() ); outputImage->SetLargestPossibleRegion( croppedRegion ); outputImage->SetBufferedRegion( croppedRegion ); outputImage->SetRequestedRegion( croppedRegion ); outputImage->SetVectorLength( inputImage->GetVectorLength() ); outputImage->Allocate(); typename InputImageType::PixelType temp; temp.SetSize(inputImage->GetVectorLength()); temp.Fill(0.0); outputImage->FillBuffer(temp); int tempY=croppedRegion.GetSize(1); tempY += tempY%2; croppedRegion.SetSize(1, tempY); m_StatusText += this->GetTime()+" > Adjusting complex signal\n"; if ( m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) m_StatusText += "Simulating distortions\n"; if ( m_Parameters.m_SignalGen.m_DoAddGibbsRinging) m_StatusText += "Simulating ringing artifacts\n"; if ( m_Parameters.m_SignalGen.m_EddyStrength>0) m_StatusText += "Simulating eddy currents\n"; if ( m_Parameters.m_SignalGen.m_Spikes>0) m_StatusText += "Simulating spikes\n"; if ( m_Parameters.m_SignalGen.m_CroppingFactor<1.0) m_StatusText += "Simulating aliasing artifacts\n"; if ( m_Parameters.m_SignalGen.m_KspaceLineOffset>0) m_StatusText += "Simulating ghosts\n"; std::vector< unsigned int > spikeVolume; for (unsigned int i=0; i< m_Parameters.m_SignalGen.m_Spikes; i++) spikeVolume.push_back(m_RandGen->GetIntegerVariate()%inputImage->GetVectorLength()); std::sort (spikeVolume.begin(), spikeVolume.end()); std::reverse (spikeVolume.begin(), spikeVolume.end()); FiberfoxParameters doubleParam = m_Parameters.CopyParameters(); m_StatusText += "0% 10 20 30 40 50 60 70 80 90 100%\n"; m_StatusText += "|----|----|----|----|----|----|----|----|----|----|\n*"; unsigned long lastTick = 0; boost::progress_display disp(inputImage->GetVectorLength()*inputRegion.GetSize(2)); for (unsigned int g=0; gGetVectorLength(); g++) { std::vector< unsigned int > spikeSlice; while (!spikeVolume.empty() && spikeVolume.back()==g) { spikeSlice.push_back(m_RandGen->GetIntegerVariate()%inputImage->GetLargestPossibleRegion().GetSize(2)); spikeVolume.pop_back(); } std::sort (spikeSlice.begin(), spikeSlice.end()); std::reverse (spikeSlice.begin(), spikeSlice.end()); for (unsigned int z=0; zGetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } std::vector< SliceType::Pointer > compartmentSlices; // extract slice from channel g for (unsigned int y=0; yGetPixel(index3D)[g]; slice->SetPixel(index2D, pix2D); - if (fMapSlice.IsNotNull()) - fMapSlice->SetPixel(index2D, m_Parameters.m_SignalGen.m_FrequencyMap->GetPixel(index3D)); } if ( m_Parameters.m_SignalGen.m_DoAddGibbsRinging) { itk::ResampleImageFilter::Pointer resampler = itk::ResampleImageFilter::New(); resampler->SetInput(slice); resampler->SetOutputParametersFromImage(slice); resampler->SetSize(upsampledSliceRegion.GetSize()); resampler->SetOutputSpacing(slice->GetSpacing()/2); itk::NearestNeighborInterpolateImageFunction::Pointer nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); typename SliceType::Pointer upslice = resampler->GetOutput(); compartmentSlices.push_back(upslice); - - if (fMapSlice.IsNotNull()) - { - itk::ResampleImageFilter::Pointer resampler = itk::ResampleImageFilter::New(); - resampler->SetInput(fMapSlice); - resampler->SetOutputParametersFromImage(fMapSlice); - resampler->SetSize(upsampledSliceRegion.GetSize()); - resampler->SetOutputSpacing(fMapSlice->GetSpacing()/2); - itk::NearestNeighborInterpolateImageFunction::Pointer nn_interpolator - = itk::NearestNeighborInterpolateImageFunction::New(); - resampler->SetInterpolator(nn_interpolator); - resampler->Update(); - fMapSlice = resampler->GetOutput(); - } } else compartmentSlices.push_back(slice); // fourier transform slice typename ComplexSliceType::Pointer fSlice; itk::Size<2> outSize; outSize.SetElement(0, xMax); outSize.SetElement(1, croppedRegion.GetSize()[1]); typename itk::KspaceImageFilter< SliceType::PixelType >::Pointer idft = itk::KspaceImageFilter< SliceType::PixelType >::New(); idft->SetUseConstantRandSeed(m_UseConstantRandSeed); idft->SetParameters(doubleParam); idft->SetCompartmentImages(compartmentSlices); - idft->SetFrequencyMapSlice(fMapSlice); idft->SetDiffusionGradientDirection( m_Parameters.m_SignalGen.GetGradientDirection(g)); idft->SetZ((double)z-(double)inputRegion.GetSize(2)/2.0); idft->SetOutSize(outSize); int numSpikes = 0; while (!spikeSlice.empty() && spikeSlice.back()==z) { numSpikes++; spikeSlice.pop_back(); } idft->SetSpikesPerSlice(numSpikes); idft->Update(); fSlice = idft->GetOutput(); // inverse fourier transform slice - typename SliceType::Pointer newSlice; + typename ComplexSliceType::Pointer newSlice; typename itk::DftImageFilter< SliceType::PixelType >::Pointer dft = itk::DftImageFilter< SliceType::PixelType >::New(); dft->SetInput(fSlice); dft->Update(); newSlice = dft->GetOutput(); // put slice back into channel g for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { typename InputImageType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; typename InputImageType::PixelType pix3D = outputImage->GetPixel(index3D); - typename SliceType::IndexType index2D; + typename ComplexSliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; - double signal = newSlice->GetPixel(index2D); + ComplexSliceType::PixelType cPix = newSlice->GetPixel(index2D); + double signal = sqrt(cPix.real()*cPix.real()+cPix.imag()*cPix.imag()); if (signal>0) signal = floor(signal+0.5); else signal = ceil(signal-0.5); pix3D[g] = signal; outputImage->SetPixel(index3D, pix3D); } ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; } } m_StatusText += "\n\n"; } if ( m_Parameters.m_NoiseModel!=NULL) { m_StatusText += this->GetTime()+" > Adding noise\n"; m_StatusText += "0% 10 20 30 40 50 60 70 80 90 100%\n"; m_StatusText += "|----|----|----|----|----|----|----|----|----|----|\n*"; unsigned long lastTick = 0; ImageRegionIterator it1 (outputImage, outputImage->GetLargestPossibleRegion()); boost::progress_display disp(outputImage->GetLargestPossibleRegion().GetNumberOfPixels()); while(!it1.IsAtEnd()) { if (this->GetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; typename InputImageType::PixelType signal = it1.Get(); m_Parameters.m_NoiseModel->AddNoise(signal); it1.Set(signal); ++it1; } m_StatusText += "\n\n"; } this->SetNthOutput(0, outputImage); m_StatusText += "Finished simulation\n"; m_StatusText += "Simulation time: "+GetTime(); } template< class TPixelType > std::string AddArtifactsToDwiImageFilter< TPixelType >::GetTime() { unsigned long total = (double)(clock() - m_StartTime)/CLOCKS_PER_SEC; unsigned long hours = total/3600; unsigned long minutes = (total%3600)/60; unsigned long seconds = total%60; std::string out = ""; out.append(boost::lexical_cast(hours)); out.append(":"); out.append(boost::lexical_cast(minutes)); out.append(":"); out.append(boost::lexical_cast(seconds)); return out; } template< class TPixelType > void AddArtifactsToDwiImageFilter< TPixelType >::UpdateOutputInformation() { // Calls to superclass updateoutputinformation Superclass::UpdateOutputInformation(); typename InputImageType::Pointer inputImage = static_cast< InputImageType* >( this->ProcessObject::GetInput(0) ); itk::ImageRegion<3> inputRegion = inputImage->GetLargestPossibleRegion(); typename itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage( inputImage ); duplicator->Update(); typename InputImageType::Pointer outputImage = duplicator->GetOutput(); if ( m_Parameters.m_SignalGen.m_CroppingFactor<1.0) { ImageRegion<3> croppedRegion = inputRegion; croppedRegion.SetSize(1, croppedRegion.GetSize(1)* m_Parameters.m_SignalGen.m_CroppingFactor); itk::Point shiftedOrigin = inputImage->GetOrigin(); shiftedOrigin[1] += (inputRegion.GetSize(1)-croppedRegion.GetSize(1))*inputImage->GetSpacing()[1]/2; outputImage = InputImageType::New(); outputImage->SetSpacing( inputImage->GetSpacing() ); outputImage->SetOrigin( shiftedOrigin ); outputImage->SetDirection( inputImage->GetDirection() ); outputImage->SetLargestPossibleRegion( croppedRegion ); outputImage->SetBufferedRegion( croppedRegion ); outputImage->SetRequestedRegion( croppedRegion ); outputImage->SetVectorLength( inputImage->GetVectorLength() ); outputImage->Allocate(); typename InputImageType::PixelType temp; temp.SetSize(inputImage->GetVectorLength()); temp.Fill(0.0); outputImage->FillBuffer(temp); } this->GetOutput()->SetOrigin( outputImage->GetOrigin() ); this->GetOutput()->SetLargestPossibleRegion( outputImage->GetLargestPossibleRegion() ); this->GetOutput()->SetBufferedRegion( outputImage->GetLargestPossibleRegion() ); this->GetOutput()->SetRequestedRegion( outputImage->GetLargestPossibleRegion() ); } } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.cpp index 2bb093a428..1c58e38e3e 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.cpp @@ -1,90 +1,119 @@ /*=================================================================== 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 __itkDftImageFilter_txx #define __itkDftImageFilter_txx #include #include #include #include "itkDftImageFilter.h" #include #include #include #define _USE_MATH_DEFINES #include namespace itk { template< class TPixelType > DftImageFilter< TPixelType > ::DftImageFilter() { this->SetNumberOfRequiredInputs( 1 ); } +template< class TPixelType > +void DftImageFilter< TPixelType > +::BeforeThreadedGenerateData() +{ + +} + template< class TPixelType > void DftImageFilter< TPixelType > ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); typedef ImageRegionConstIterator< InputImageType > InputIteratorType; typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); int szx = outputImage->GetLargestPossibleRegion().GetSize(0); int szy = outputImage->GetLargestPossibleRegion().GetSize(1); while( !oit.IsAtEnd() ) { - int kx = oit.GetIndex()[0]; - int ky = oit.GetIndex()[1]; + double kx = oit.GetIndex()[0]; + double ky = oit.GetIndex()[1]; +// kx -= (double)szx/2; +// ky -= (double)szy/2; - if( kx < szx/2 ) - kx = kx + szx/2; + if ((int)szx%2==1) + kx -= (szx-1)/2; else - kx = kx - szx/2; - - if( ky < szy/2 ) - ky = ky + szy/2; + kx -= szx/2; + if ((int)szy%2==1) + ky -= (szy-1)/2; else - ky = ky - szy/2; + ky -= szy/2; + +// if( kx < szx/2 ) +// kx = kx + szx/2; +// else +// kx = kx - szx/2; + +// if( ky < szy/2 ) +// ky = ky + szy/2; +// else +// ky = ky - szy/2; vcl_complex s(0,0); InputIteratorType it(inputImage, inputImage->GetLargestPossibleRegion() ); while( !it.IsAtEnd() ) { int x = it.GetIndex()[0]; int y = it.GetIndex()[1]; +// x -= (double)szx/2; +// y -= (double)szy/2; + + if ((int)szx%2==1) + x -= (szx-1)/2; + else + x -= szx/2; + if ((int)szy%2==1) + y -= (szy-1)/2; + else + y -= szy/2; vcl_complex f(it.Get().real(), it.Get().imag()); + s += f * exp( std::complex(0, -2 * M_PI * (kx*(double)x/szx + ky*(double)y/szy) ) ); ++it; } - double magn = sqrt(s.real()*s.real()+s.imag()*s.imag()); - oit.Set(magn); + oit.Set(s); ++oit; } } } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.h index 6062dc8cc0..477bb5f4b1 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.h @@ -1,75 +1,81 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkDftImageFilter_h_ #define __itkDftImageFilter_h_ #include #include #include #include +#include namespace itk{ /** * \brief 2D Discrete Fourier Transform Filter (complex to real). Special issue for Fiberfox -> rearranges slice. */ - template< class TPixelType > - class DftImageFilter : - public ImageToImageFilter< Image< vcl_complex< TPixelType > >, Image< TPixelType > > - { +template< class TPixelType > +class DftImageFilter : + public ImageToImageFilter< Image< vcl_complex< TPixelType > >, Image< vcl_complex< TPixelType > > > +{ - public: +public: typedef DftImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; - typedef ImageToImageFilter< Image< vcl_complex< TPixelType > >, Image< TPixelType > > Superclass; + typedef ImageToImageFilter< Image< vcl_complex< TPixelType > >, Image< vcl_complex< TPixelType > > > Superclass; + typedef itk::Statistics::MersenneTwisterRandomVariateGenerator RandGenType; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(DftImageFilter, ImageToImageFilter) typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; - protected: + void SetParameters( FiberfoxParameters param ){ m_Parameters = param; } + +protected: DftImageFilter(); ~DftImageFilter() {} + void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId); - private: +private: - }; + FiberfoxParameters m_Parameters; +}; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkDftImageFilter.cpp" #endif #endif //__itkDftImageFilter_h_ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.cpp index cfcbf0e488..6c8c0bd12b 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.cpp @@ -1,225 +1,373 @@ /*=================================================================== 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 __itkKspaceImageFilter_txx #define __itkKspaceImageFilter_txx #include #include #include #include "itkKspaceImageFilter.h" #include #include #include #include #define _USE_MATH_DEFINES #include namespace itk { template< class TPixelType > KspaceImageFilter< TPixelType > ::KspaceImageFilter() - : m_FrequencyMapSlice(NULL) - , m_Z(0) + : m_Z(0) , m_UseConstantRandSeed(false) , m_SpikesPerSlice(0) , m_IsBaseline(true) { m_DiffusionGradientDirection.Fill(0.0); - m_RandGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); - m_RandGen->SetSeed(); + m_CoilPosition.Fill(0.0); } template< class TPixelType > void KspaceImageFilter< TPixelType > ::BeforeThreadedGenerateData() { - if (m_UseConstantRandSeed) // always generate the same random numbers? - m_RandGen->SetSeed(0); - else - m_RandGen->SetSeed(); + m_Spike = vcl_complex(0,0); typename OutputImageType::Pointer outputImage = OutputImageType::New(); itk::ImageRegion<2> region; region.SetSize(0, m_OutSize[0]); region.SetSize(1, m_OutSize[1]); outputImage->SetLargestPossibleRegion( region ); outputImage->SetBufferedRegion( region ); outputImage->SetRequestedRegion( region ); outputImage->Allocate(); + outputImage->FillBuffer(m_Spike); - double gamma = 42576000; // Gyromagnetic ratio in Hz/T + m_KSpaceImage = InputImageType::New(); + m_KSpaceImage->SetLargestPossibleRegion( region ); + m_KSpaceImage->SetBufferedRegion( region ); + m_KSpaceImage->SetRequestedRegion( region ); + m_KSpaceImage->Allocate(); + m_KSpaceImage->FillBuffer(0.0); + + m_Gamma = 42576000; // Gyromagnetic ratio in Hz/T if ( m_Parameters.m_SignalGen.m_EddyStrength>0 && m_DiffusionGradientDirection.GetNorm()>0.001) { m_DiffusionGradientDirection.Normalize(); - m_DiffusionGradientDirection = m_DiffusionGradientDirection * m_Parameters.m_SignalGen.m_EddyStrength/1000 * gamma; + m_DiffusionGradientDirection = m_DiffusionGradientDirection * m_Parameters.m_SignalGen.m_EddyStrength/1000 * m_Gamma; m_IsBaseline = false; } this->SetNthOutput(0, outputImage); - m_Spike = vcl_complex(0,0); m_Transform = m_Parameters.m_SignalGen.m_ImageDirection; for (int i=0; i<3; i++) for (int j=0; j<3; j++) m_Transform[i][j] *= m_Parameters.m_SignalGen.m_ImageSpacing[j]; + + double a = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(0)*m_Parameters.m_SignalGen.m_ImageSpacing[0]; + double b = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1)*m_Parameters.m_SignalGen.m_ImageSpacing[1]; + double diagonal = sqrt(a*a+b*b)/1000; // image diagonal in m + + switch (m_Parameters.m_SignalGen.m_CoilSensitivityProfile) + { + case SignalGenerationParameters::COIL_CONSTANT: + { + m_CoilSensitivityFactor = 1; // same signal everywhere + break; + } + case SignalGenerationParameters::COIL_LINEAR: + { + m_CoilSensitivityFactor = -1/diagonal; // about 50% of the signal in the image center remaining + break; + } + case SignalGenerationParameters::COIL_EXPONENTIAL: + { + m_CoilSensitivityFactor = -log(0.1)/diagonal; // about 32% of the signal in the image center remaining + break; + } + } +} + +template< class TPixelType > +double KspaceImageFilter< TPixelType >::CoilSensitivity(DoubleVectorType& pos) +{ + // ************************************************************************* + // Coil ring is moving with excited slice (FIX THIS SOMETIME) + m_CoilPosition[2] = pos[2]; + // ************************************************************************* + + switch (m_Parameters.m_SignalGen.m_CoilSensitivityProfile) + { + case SignalGenerationParameters::COIL_CONSTANT: + return 1; + case SignalGenerationParameters::COIL_LINEAR: + { + DoubleVectorType diff = pos-m_CoilPosition; + double sens = diff.GetNorm()*m_CoilSensitivityFactor + 1; + if (sens<0) + sens = 0; + return sens; + } + case SignalGenerationParameters::COIL_EXPONENTIAL: + { + DoubleVectorType diff = pos-m_CoilPosition; + double dist = diff.GetNorm(); + return exp(-dist*m_CoilSensitivityFactor); + } + default: + return 1; + } } template< class TPixelType > void KspaceImageFilter< TPixelType > -::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType) +::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType threadID) { + itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); + randGen->SetSeed(); + if (m_UseConstantRandSeed) // always generate the same random numbers? + randGen->SetSeed(threadID*100); + else + randGen->SetSeed(); + typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); typedef ImageRegionConstIterator< InputImageType > InputIteratorType; double kxMax = outputImage->GetLargestPossibleRegion().GetSize(0); // k-space size in x-direction double kyMax = outputImage->GetLargestPossibleRegion().GetSize(1); // k-space size in y-direction double xMax = m_CompartmentImages.at(0)->GetLargestPossibleRegion().GetSize(0); // scanner coverage in x-direction double yMax = m_CompartmentImages.at(0)->GetLargestPossibleRegion().GetSize(1); // scanner coverage in y-direction double numPix = kxMax*kyMax; double dt = m_Parameters.m_SignalGen.m_tLine/kxMax; - double fromMaxEcho = - m_Parameters.m_SignalGen.m_tLine*kyMax/2; - double upsampling = xMax/kxMax; // discrepany between k-space resolution and image resolution - double yMaxFov = kyMax*upsampling; // actual FOV in y-direction (in x-direction xMax==FOV) + // k-space center at maximum echo + double fromMaxEcho = 0; + if ( (int)kyMax%2==0 ) + { + fromMaxEcho = -m_Parameters.m_SignalGen.m_tLine*(kyMax-1)/2 + dt*(kxMax-(int)kxMax%2)/2; + } + else + fromMaxEcho = -m_Parameters.m_SignalGen.m_tLine*(kyMax-1)/2 - dt*(kxMax-(int)kxMax%2)/2; - int xRingingOffset = xMax-kxMax; - int yRingingOffset = yMaxFov-kyMax; + double yMaxFov = yMax*m_Parameters.m_SignalGen.m_CroppingFactor; // actual FOV in y-direction (in x-direction FOV=xMax) + + double noiseVar = m_Parameters.m_SignalGen.m_PartialFourier*m_Parameters.m_SignalGen.m_NoiseVariance/(kyMax*kxMax); // adjust noise variance since it is the intended variance in physical space and not in k-space while( !oit.IsAtEnd() ) { itk::Index< 2 > kIdx; kIdx[0] = oit.GetIndex()[0]; kIdx[1] = oit.GetIndex()[1]; // dephasing time - double t = 0; - if (!m_Parameters.m_SignalGen.m_ReversePhase) - t = fromMaxEcho + ((double)kIdx[1]*kxMax+(double)kIdx[0])*dt; - else - t = fromMaxEcho + ((double)(kyMax-1-kIdx[1])*kxMax+(double)kIdx[0])*dt; - - // rearrange slice - if( kIdx[0] < kxMax/2 ) - kIdx[0] = kIdx[0] + kxMax/2; - else - kIdx[0] = kIdx[0] - kxMax/2; + double t= fromMaxEcho + ((double)kIdx[1]*kxMax+(double)kIdx[0])*dt; - if( kIdx[1] < kyMax/2 ) - kIdx[1] = kIdx[1] + kyMax/2; - else - kIdx[1] = kIdx[1] - kyMax/2; + // readout time + double tall = ((double)kIdx[1]*kxMax+(double)kIdx[0])*dt; - // calculate eddy current decay factors + // calculate eddy current decay factor double eddyDecay = 0; - if ( m_Parameters.m_SignalGen.m_EddyStrength>0) - eddyDecay = exp(-( m_Parameters.m_SignalGen.m_tEcho/2 + t)/ m_Parameters.m_SignalGen.m_Tau) * t/1000; + if ( m_Parameters.m_Misc.m_CheckAddEddyCurrentsBox && m_Parameters.m_SignalGen.m_EddyStrength>0) + eddyDecay = exp(-tall/m_Parameters.m_SignalGen.m_Tau ); // calcualte signal relaxation factors std::vector< double > relaxFactor; if ( m_Parameters.m_SignalGen.m_DoSimulateRelaxation) for (unsigned int i=0; ikyMax*m_Parameters.m_SignalGen.m_PartialFourier) + pf = true; + + // reverse readout direction + if (oit.GetIndex()[1]%2 == 1) + kIdx[0] = kxMax-kIdx[0]-1; + + // shift k for DFT: (0 -- N) --> (-N/2 -- N/2) double kx = kIdx[0]; double ky = kIdx[1]; - if (oit.GetIndex()[1]%2 == 1) // reverse readout direction and add ghosting - { - kIdx[0] = kxMax-kIdx[0]-1; // reverse readout direction - kx = (double)kIdx[0]- m_Parameters.m_SignalGen.m_KspaceLineOffset; // add gradient delay induced offset - } + if ((int)kxMax%2==1) + kx -= (kxMax-1)/2; + else + kx -= kxMax/2; + if ((int)kyMax%2==1) + ky -= (kyMax-1)/2; else - kx += m_Parameters.m_SignalGen.m_KspaceLineOffset; // add gradient delay induced offset + ky -= kyMax/2; - // add gibbs ringing offset (cropps k-space) - if (kx>=kxMax/2) - kx += xRingingOffset; - if (ky>=kyMax/2) - ky += yRingingOffset; + // add ghosting + if (oit.GetIndex()[1]%2 == 1) + kx -= m_Parameters.m_SignalGen.m_KspaceLineOffset; // add gradient delay induced offset + else + kx += m_Parameters.m_SignalGen.m_KspaceLineOffset; // add gradient delay induced offset - vcl_complex s(0,0); - InputIteratorType it(m_CompartmentImages.at(0), m_CompartmentImages.at(0)->GetLargestPossibleRegion() ); - while( !it.IsAtEnd() ) + if (!pf) { - double x = it.GetIndex()[0]-xMax/2; - double y = it.GetIndex()[1]-yMax/2; - - vcl_complex f(0, 0); - - // sum compartment signals and simulate relaxation - for (unsigned int i=0; i( m_CompartmentImages.at(i)->GetPixel(it.GetIndex()) * relaxFactor.at(i) * m_Parameters.m_SignalGen.m_SignalScale, 0); + vcl_complex s(0,0); + InputIteratorType it(m_CompartmentImages.at(0), m_CompartmentImages.at(0)->GetLargestPossibleRegion() ); + while( !it.IsAtEnd() ) + { + double x = it.GetIndex()[0]; + double y = it.GetIndex()[1]; + if ((int)xMax%2==1) + x -= (xMax-1)/2; else - f += std::complex( m_CompartmentImages.at(i)->GetPixel(it.GetIndex()) * m_Parameters.m_SignalGen.m_SignalScale ); + x -= xMax/2; + if ((int)yMax%2==1) + y -= (yMax-1)/2; + else + y -= yMax/2; - // simulate eddy currents and other distortions - double omega_t = 0; - if ( m_Parameters.m_SignalGen.m_EddyStrength>0 && !m_IsBaseline) - { - itk::Vector< double, 3 > pos; pos[0] = x; pos[1] = y; pos[2] = m_Z; + DoubleVectorType pos; pos[0] = x; pos[1] = y; pos[2] = m_Z; pos = m_Transform*pos/1000; // vector from image center to current position (in meter) - omega_t += (m_DiffusionGradientDirection[0]*pos[0]+m_DiffusionGradientDirection[1]*pos[1]+m_DiffusionGradientDirection[2]*pos[2])*eddyDecay; + + vcl_complex f(0, 0); + + // sum compartment signals and simulate relaxation + for (unsigned int i=0; i( m_CompartmentImages.at(i)->GetPixel(it.GetIndex()) * relaxFactor.at(i) * m_Parameters.m_SignalGen.m_SignalScale, 0); + else + f += std::complex( m_CompartmentImages.at(i)->GetPixel(it.GetIndex()) * m_Parameters.m_SignalGen.m_SignalScale ); + + if (m_Parameters.m_SignalGen.m_CoilSensitivityProfile!=SignalGenerationParameters::COIL_CONSTANT) + f *= CoilSensitivity(pos); + + // simulate eddy currents and other distortions + double omega = 0; // frequency offset + if ( m_Parameters.m_SignalGen.m_EddyStrength>0 && m_Parameters.m_Misc.m_CheckAddEddyCurrentsBox && !m_IsBaseline) + { + omega += (m_DiffusionGradientDirection[0]*pos[0]+m_DiffusionGradientDirection[1]*pos[1]+m_DiffusionGradientDirection[2]*pos[2]) * eddyDecay; + } + if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) // simulate distortions + { + itk::Point point3D; + ItkDoubleImgType::IndexType index; index[0] = it.GetIndex()[0]; index[1] = it.GetIndex()[1]; index[2] = m_Zidx; + if (m_Parameters.m_SignalGen.m_DoAddMotion) + { + m_Parameters.m_SignalGen.m_FrequencyMap->TransformIndexToPhysicalPoint(index, point3D); + point3D = m_FiberBundle->TransformPoint(point3D.GetVnlVector(), -m_Rotation[0],-m_Rotation[1],-m_Rotation[2],-m_Translation[0],-m_Translation[1],-m_Translation[2]); + m_Parameters.m_SignalGen.m_FrequencyMap->TransformPhysicalPointToIndex(point3D, index); + if (m_Parameters.m_SignalGen.m_FrequencyMap->GetLargestPossibleRegion().IsInside(index)) + omega += m_Parameters.m_SignalGen.m_FrequencyMap->GetPixel(index); + } + else + { + omega += m_Parameters.m_SignalGen.m_FrequencyMap->GetPixel(index); + } + } + + // if signal comes from outside FOV, mirror it back (wrap-around artifact - aliasing) + if (y<-yMaxFov/2) + y += yMaxFov; + else if (y>=yMaxFov/2) + y -= yMaxFov; + + // actual DFT term + s += f * exp( std::complex(0, 2 * M_PI * (kx*x/xMax + ky*y/yMaxFov + omega*t/1000 )) ); + + ++it; } - if (m_FrequencyMapSlice.IsNotNull()) // simulate distortions - omega_t += m_FrequencyMapSlice->GetPixel(it.GetIndex())*t/1000; + s /= numPix; - if (y<-yMaxFov/2) - y += yMaxFov; - else if (y>=yMaxFov/2) - y -= yMaxFov; + if (m_SpikesPerSlice>0 && sqrt(s.imag()*s.imag()+s.real()*s.real()) > sqrt(m_Spike.imag()*m_Spike.imag()+m_Spike.real()*m_Spike.real()) ) + m_Spike = s; - // actual DFT term - s += f * exp( std::complex(0, 2 * M_PI * (kx*x/xMax + ky*y/yMaxFov + omega_t )) ); + if (m_Parameters.m_SignalGen.m_NoiseVariance>0) + s = vcl_complex(s.real()+randGen->GetNormalVariate(0,noiseVar), s.imag()+randGen->GetNormalVariate(0,noiseVar)); - ++it; + outputImage->SetPixel(kIdx, s); +// m_KSpaceImage->SetPixel(kIdx, t/dt ); + m_KSpaceImage->SetPixel(kIdx, sqrt(s.imag()*s.imag()+s.real()*s.real()) ); } - s /= numPix; - - if (m_SpikesPerSlice>0 && sqrt(s.imag()*s.imag()+s.real()*s.real()) > sqrt(m_Spike.imag()*m_Spike.imag()+m_Spike.real()*m_Spike.real()) ) - m_Spike = s; - outputImage->SetPixel(kIdx, s); ++oit; } } template< class TPixelType > void KspaceImageFilter< TPixelType > ::AfterThreadedGenerateData() { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); double kxMax = outputImage->GetLargestPossibleRegion().GetSize(0); // k-space size in x-direction double kyMax = outputImage->GetLargestPossibleRegion().GetSize(1); // k-space size in y-direction + ImageRegionIterator< OutputImageType > oit(outputImage, outputImage->GetLargestPossibleRegion()); + while( !oit.IsAtEnd() ) // use hermitian k-space symmetry to fill empty k-space parts resulting from partial fourier acquisition + { + itk::Index< 2 > kIdx; + kIdx[0] = oit.GetIndex()[0]; + kIdx[1] = oit.GetIndex()[1]; + + // reverse phase + if (!m_Parameters.m_SignalGen.m_ReversePhase) + kIdx[1] = kyMax-1-kIdx[1]; + + if (kIdx[1]>kyMax*m_Parameters.m_SignalGen.m_PartialFourier) + { + // reverse readout direction + if (oit.GetIndex()[1]%2 == 1) + kIdx[0] = kxMax-kIdx[0]-1; + + // calculate symmetric index + itk::Index< 2 > kIdx2; + kIdx2[0] = (int)(kxMax-kIdx[0]-(int)kxMax%2)%(int)kxMax; + kIdx2[1] = (int)(kyMax-kIdx[1]-(int)kyMax%2)%(int)kyMax; + + // use complex conjugate of symmetric index value at current index + vcl_complex s = outputImage->GetPixel(kIdx2); + s = vcl_complex(s.real(), -s.imag()); + outputImage->SetPixel(kIdx, s); + + m_KSpaceImage->SetPixel(kIdx, sqrt(s.imag()*s.imag()+s.real()*s.real()) ); + } + ++oit; + } + + itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); + randGen->SetSeed(); + if (m_UseConstantRandSeed) // always generate the same random numbers? + randGen->SetSeed(0); + else + randGen->SetSeed(); + m_Spike *= m_Parameters.m_SignalGen.m_SpikeAmplitude; itk::Index< 2 > spikeIdx; for (unsigned int i=0; iGetIntegerVariate()%(int)kxMax; - spikeIdx[1] = m_RandGen->GetIntegerVariate()%(int)kyMax; + spikeIdx[0] = randGen->GetIntegerVariate()%(int)kxMax; + spikeIdx[1] = randGen->GetIntegerVariate()%(int)kyMax; outputImage->SetPixel(spikeIdx, m_Spike); } } } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.h index 1e2ad4c9ff..afadd1e8d2 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.h @@ -1,124 +1,141 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*=================================================================== This file is based heavily on a corresponding ITK filter. ===================================================================*/ #ifndef __itkKspaceImageFilter_h_ #define __itkKspaceImageFilter_h_ #include #include #include #include #include #include +#include using namespace std; namespace itk{ /** * \brief Simulates k-space acquisition of one slice with a single shot EPI sequence. Enables the simulation of various effects occuring during real MR acquisitions: * - T2 signal relaxation * - Spikes * - N/2 Ghosts * - Aliasing (wrap around) * - Image distortions (off-frequency effects) * - Gibbs ringing * - Eddy current effects * Based on a discrete fourier transformation. * See "Fiberfox: Facilitating the creation of realistic white matter software phantoms" (DOI: 10.1002/mrm.25045) for details. */ template< class TPixelType > class KspaceImageFilter : public ImageSource< Image< vcl_complex< TPixelType >, 2 > > { public: typedef KspaceImageFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageSource< Image< vcl_complex< TPixelType >, 2 > > Superclass; /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Runtime information support. */ itkTypeMacro(KspaceImageFilter, ImageToImageFilter) typedef typename itk::Image< double, 2 > InputImageType; typedef typename InputImageType::Pointer InputImagePointerType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef itk::Matrix MatrixType; typedef itk::Point Point2D; + typedef itk::Vector< double,3> DoubleVectorType; + typedef itk::Image ItkDoubleImgType; itkSetMacro( SpikesPerSlice, unsigned int ) ///< Number of spikes per slice. Corresponding parameter in fiberfox parameter object specifies the number of spikes for the whole image and can thus not be used here. - itkSetMacro( FrequencyMapSlice, typename InputImageType::Pointer ) ///< Used to simulate distortions. Specifies additional frequency component per voxel. itkSetMacro( Z, double ) ///< Slice position, necessary for eddy current simulation. itkSetMacro( OutSize, itk::Size<2> ) ///< Output slice size. Can be different from input size, e.g. if Gibbs ringing is enabled. itkSetMacro( UseConstantRandSeed, bool ) ///< Use constant seed for random generator for reproducible results. + itkSetMacro( Rotation, DoubleVectorType ) + itkSetMacro( Translation, DoubleVectorType ) + itkSetMacro( Zidx, int ) + itkSetMacro( FiberBundle, FiberBundle::Pointer ) + itkSetMacro( CoilPosition, DoubleVectorType ) + itkGetMacro( KSpaceImage, typename InputImageType::Pointer ) ///< k-space magnitude image void SetParameters( FiberfoxParameters param ){ m_Parameters = param; } FiberfoxParameters GetParameters(){ return m_Parameters; } void SetCompartmentImages( std::vector< InputImagePointerType > cImgs ) { m_CompartmentImages=cImgs; } ///< One signal image per compartment. void SetT2( std::vector< double > t2Vector ) { m_T2=t2Vector; } ///< One T2 relaxation constant per compartment image. void SetT1( std::vector< double > t1Vector ) { m_T1=t1Vector; } ///< One T1 relaxation constant per compartment image. void SetDiffusionGradientDirection(itk::Vector g) { m_DiffusionGradientDirection=g; } ///< Gradient direction is needed for eddy current simulation. protected: KspaceImageFilter(); ~KspaceImageFilter() {} + double CoilSensitivity(DoubleVectorType& pos); + void BeforeThreadedGenerateData(); - void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType); + void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadID); void AfterThreadedGenerateData(); + DoubleVectorType m_CoilPosition; FiberfoxParameters m_Parameters; - typename InputImageType::Pointer m_FrequencyMapSlice; vector< double > m_T2; vector< double > m_T1; vector< InputImagePointerType > m_CompartmentImages; itk::Vector m_DiffusionGradientDirection; double m_Z; + int m_Zidx; bool m_UseConstantRandSeed; unsigned int m_SpikesPerSlice; itk::Size<2> m_OutSize; + FiberBundle::Pointer m_FiberBundle; + double m_Gamma; + DoubleVectorType m_Rotation; ///< used to find correct point in frequency map (head motion) + DoubleVectorType m_Translation; ///< used to find correct point in frequency map (head motion) bool m_IsBaseline; vcl_complex m_Spike; MatrixType m_Transform; - itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer m_RandGen; + + double m_CoilSensitivityFactor; + typename InputImageType::Pointer m_KSpaceImage; private: }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkKspaceImageFilter.cpp" #endif #endif //__itkKspaceImageFilter_h_ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp index 7906df9dcb..c0532267c6 100755 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp @@ -1,1325 +1,1569 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "itkTractsToDWIImageFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include +#include namespace itk { template< class PixelType > TractsToDWIImageFilter< PixelType >::TractsToDWIImageFilter() : m_FiberBundle(NULL) , m_StatusText("") , m_UseConstantRandSeed(false) , m_RandGen(itk::Statistics::MersenneTwisterRandomVariateGenerator::New()) { m_RandGen->SetSeed(); } template< class PixelType > TractsToDWIImageFilter< PixelType >::~TractsToDWIImageFilter() { } template< class PixelType > -TractsToDWIImageFilter< PixelType >::DoubleDwiType::Pointer TractsToDWIImageFilter< PixelType >::DoKspaceStuff( std::vector< DoubleDwiType::Pointer >& images ) +TractsToDWIImageFilter< PixelType >::DoubleDwiType::Pointer TractsToDWIImageFilter< PixelType >::SimulateKspaceAcquisition( std::vector< DoubleDwiType::Pointer >& images ) { int numFiberCompartments = m_Parameters.m_FiberModelList.size(); // create slice object ImageRegion<2> sliceRegion; sliceRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]); sliceRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]); Vector< double, 2 > sliceSpacing; sliceSpacing[0] = m_WorkingSpacing[0]; sliceSpacing[1] = m_WorkingSpacing[1]; - // frequency map slice - SliceType::Pointer fMapSlice = NULL; - if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) - { - fMapSlice = SliceType::New(); - ImageRegion<2> region; - region.SetSize(0, m_WorkingImageRegion.GetSize()[0]); - region.SetSize(1, m_WorkingImageRegion.GetSize()[1]); - fMapSlice->SetLargestPossibleRegion( region ); - fMapSlice->SetBufferedRegion( region ); - fMapSlice->SetRequestedRegion( region ); - fMapSlice->Allocate(); - fMapSlice->FillBuffer(0.0); - } - - DoubleDwiType::Pointer newImage = DoubleDwiType::New(); - newImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); - newImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); - newImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); - newImage->SetLargestPossibleRegion( m_CroppedRegion ); - newImage->SetBufferedRegion( m_CroppedRegion ); - newImage->SetRequestedRegion( m_CroppedRegion ); - newImage->SetVectorLength( images.at(0)->GetVectorLength() ); - newImage->Allocate(); + DoubleDwiType::PixelType nullPix; nullPix.SetSize(images.at(0)->GetVectorLength()); nullPix.Fill(0.0); + DoubleDwiType::Pointer magnitudeDwiImage = DoubleDwiType::New(); + magnitudeDwiImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); + magnitudeDwiImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); + magnitudeDwiImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); + magnitudeDwiImage->SetLargestPossibleRegion( m_CroppedRegion ); + magnitudeDwiImage->SetBufferedRegion( m_CroppedRegion ); + magnitudeDwiImage->SetRequestedRegion( m_CroppedRegion ); + magnitudeDwiImage->SetVectorLength( images.at(0)->GetVectorLength() ); + magnitudeDwiImage->Allocate(); + magnitudeDwiImage->FillBuffer(nullPix); + + m_PhaseImage = DoubleDwiType::New(); + m_PhaseImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); + m_PhaseImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); + m_PhaseImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); + m_PhaseImage->SetLargestPossibleRegion( m_CroppedRegion ); + m_PhaseImage->SetBufferedRegion( m_CroppedRegion ); + m_PhaseImage->SetRequestedRegion( m_CroppedRegion ); + m_PhaseImage->SetVectorLength( images.at(0)->GetVectorLength() ); + m_PhaseImage->Allocate(); + m_PhaseImage->FillBuffer(nullPix); + + +// itk::ImageRegion<4> imageRegion4D; +// itk::Vector imageSpacing4D; imageSpacing4D.Fill(1); +// itk::Point imageOrigin4D; imageOrigin4D.Fill(0); +// itk::Matrix imageDirection4D; imageDirection4D.SetIdentity(); +// imageRegion4D.SetSize(0, m_CroppedRegion.GetSize(0)); +// imageRegion4D.SetSize(1, m_CroppedRegion.GetSize(1)); +// imageRegion4D.SetSize(2, m_CroppedRegion.GetSize(2)); +// imageRegion4D.SetSize(3, m_Parameters.m_SignalGen.m_NumberOfCoils); +// for (int i=0; i<3; i++) +// { +// imageSpacing4D[i] = m_Parameters.m_SignalGen.m_ImageSpacing[i]; +// imageOrigin4D[i] = m_Parameters.m_SignalGen.m_ImageOrigin[i]; +// for (int j=0; j<3; j++) +// imageDirection4D[i][j]=m_Parameters.m_SignalGen.m_ImageDirection[i][j]; +// } + +//// ItkDoubleImgType4D::PixelType nullPix4D; +//// nullPix4D.SetSize(images.at(0)->GetVectorLength()); +//// nullPix4D.Fill(0.0); +// m_KspaceImage = ItkDoubleImgType4D::New(); +// m_KspaceImage->SetSpacing( imageSpacing4D ); +// m_KspaceImage->SetOrigin( imageOrigin4D ); +// m_KspaceImage->SetDirection( imageDirection4D ); +// m_KspaceImage->SetLargestPossibleRegion( imageRegion4D ); +// m_KspaceImage->SetBufferedRegion( imageRegion4D ); +// m_KspaceImage->SetRequestedRegion( imageRegion4D ); +//// m_KspaceImage->SetVectorLength( images.at(0)->GetVectorLength() ); +// m_KspaceImage->Allocate(); +// m_KspaceImage->FillBuffer(0); + + m_KspaceImage = DoubleDwiType::New(); + m_KspaceImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); + m_KspaceImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); + m_KspaceImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); + m_KspaceImage->SetLargestPossibleRegion( m_CroppedRegion ); + m_KspaceImage->SetBufferedRegion( m_CroppedRegion ); + m_KspaceImage->SetRequestedRegion( m_CroppedRegion ); + m_KspaceImage->SetVectorLength( m_Parameters.m_SignalGen.m_NumberOfCoils ); + m_KspaceImage->Allocate(); + m_KspaceImage->FillBuffer(nullPix); std::vector< unsigned int > spikeVolume; for (unsigned int i=0; iGetIntegerVariate()%(images.at(0)->GetVectorLength())); std::sort (spikeVolume.begin(), spikeVolume.end()); std::reverse (spikeVolume.begin(), spikeVolume.end()); + // calculate coil positions + double a = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(0)*m_Parameters.m_SignalGen.m_ImageSpacing[0]; + double b = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1)*m_Parameters.m_SignalGen.m_ImageSpacing[1]; + double c = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(2)*m_Parameters.m_SignalGen.m_ImageSpacing[2]; + double diagonal = sqrt(a*a+b*b)/1000; // image diagonal in m + + m_CoilPointset = mitk::PointSet::New(); + std::vector< itk::Vector > coilPositions; + itk::Vector pos; pos.Fill(0.0); pos[1] = -diagonal/2; + itk::Vector center; + center[0] = a/2-m_Parameters.m_SignalGen.m_ImageSpacing[0]/2; + center[1] = b/2-m_Parameters.m_SignalGen.m_ImageSpacing[2]/2; + center[2] = c/2-m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; + for (int c=0; cInsertPoint(c, pos*1000 + m_Parameters.m_SignalGen.m_ImageOrigin.GetVectorFromOrigin() + center ); + + double rz = 360.0/m_Parameters.m_SignalGen.m_NumberOfCoils * M_PI/180; + vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); + rotZ[0][0] = cos(rz); + rotZ[1][1] = rotZ[0][0]; + rotZ[0][1] = -sin(rz); + rotZ[1][0] = -rotZ[0][1]; + + pos.SetVnlVector(rotZ*pos.GetVnlVector()); + } + m_StatusText += "0% 10 20 30 40 50 60 70 80 90 100%\n"; m_StatusText += "|----|----|----|----|----|----|----|----|----|----|\n*"; unsigned long lastTick = 0; - boost::progress_display disp(2*images.at(0)->GetVectorLength()*images.at(0)->GetLargestPossibleRegion().GetSize(2)); + boost::progress_display disp(images.at(0)->GetVectorLength()*images.at(0)->GetLargestPossibleRegion().GetSize(2)); for (unsigned int g=0; gGetVectorLength(); g++) { std::vector< unsigned int > spikeSlice; while (!spikeVolume.empty() && spikeVolume.back()==g) { spikeSlice.push_back(m_RandGen->GetIntegerVariate()%images.at(0)->GetLargestPossibleRegion().GetSize(2)); spikeVolume.pop_back(); } std::sort (spikeSlice.begin(), spikeSlice.end()); std::reverse (spikeSlice.begin(), spikeSlice.end()); for (unsigned int z=0; zGetLargestPossibleRegion().GetSize(2); z++) { std::vector< SliceType::Pointer > compartmentSlices; std::vector< double > t2Vector; std::vector< double > t1Vector; for (unsigned int i=0; i* signalModel; if (iSetLargestPossibleRegion( sliceRegion ); slice->SetBufferedRegion( sliceRegion ); slice->SetRequestedRegion( sliceRegion ); slice->SetSpacing(sliceSpacing); slice->Allocate(); slice->FillBuffer(0.0); // extract slice from channel g for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; slice->SetPixel(index2D, images.at(i)->GetPixel(index3D)[g]); - - if (fMapSlice.IsNotNull() && i==0) - fMapSlice->SetPixel(index2D, m_Parameters.m_SignalGen.m_FrequencyMap->GetPixel(index3D)); } compartmentSlices.push_back(slice); t2Vector.push_back(signalModel->GetT2()); t1Vector.push_back(signalModel->GetT1()); } - if (this->GetAbortGenerateData()) - return NULL; - - // create k-sapce (inverse fourier transform slices) - itk::Size<2> outSize; outSize.SetElement(0, m_CroppedRegion.GetSize(0)); outSize.SetElement(1, m_CroppedRegion.GetSize(1)); - itk::KspaceImageFilter< SliceType::PixelType >::Pointer idft = itk::KspaceImageFilter< SliceType::PixelType >::New(); - idft->SetCompartmentImages(compartmentSlices); - idft->SetT2(t2Vector); - idft->SetT1(t1Vector); - idft->SetUseConstantRandSeed(m_UseConstantRandSeed); - idft->SetParameters(m_Parameters); - idft->SetZ((double)z-(double)images.at(0)->GetLargestPossibleRegion().GetSize(2)/2.0); - idft->SetDiffusionGradientDirection(m_Parameters.m_SignalGen.GetGradientDirection(g)); - idft->SetFrequencyMapSlice(fMapSlice); - idft->SetOutSize(outSize); int numSpikes = 0; while (!spikeSlice.empty() && spikeSlice.back()==z) { numSpikes++; spikeSlice.pop_back(); } - idft->SetSpikesPerSlice(numSpikes); - idft->Update(); + int spikeCoil = m_RandGen->GetIntegerVariate()%m_Parameters.m_SignalGen.m_NumberOfCoils; - ComplexSliceType::Pointer fSlice; - fSlice = idft->GetOutput(); + if (this->GetAbortGenerateData()) + return NULL; - ++disp; - unsigned long newTick = 50*disp.count()/disp.expected_count(); - for (unsigned long tick = 0; tick<(newTick-lastTick); tick++) - m_StatusText += "*"; - lastTick = newTick; +#pragma omp parallel for + for (int c=0; c outSize; outSize.SetElement(0, m_CroppedRegion.GetSize(0)); outSize.SetElement(1, m_CroppedRegion.GetSize(1)); + itk::KspaceImageFilter< SliceType::PixelType >::Pointer idft = itk::KspaceImageFilter< SliceType::PixelType >::New(); + idft->SetCompartmentImages(compartmentSlices); + idft->SetT2(t2Vector); + idft->SetT1(t1Vector); + idft->SetUseConstantRandSeed(m_UseConstantRandSeed); + idft->SetParameters(m_Parameters); + idft->SetZ((double)z-(double)(images.at(0)->GetLargestPossibleRegion().GetSize(2)-images.at(0)->GetLargestPossibleRegion().GetSize(2)%2)/2.0); + idft->SetZidx(z); + idft->SetCoilPosition(coilPositions.at(c)); + idft->SetFiberBundle(m_FiberBundleWorkingCopy); + if (m_Parameters.m_SignalGen.m_DoAddMotion) + { + idft->SetTranslation(m_Translations.at(g)); + idft->SetRotation(m_Rotations.at(g)); + } + idft->SetDiffusionGradientDirection(m_Parameters.m_SignalGen.GetGradientDirection(g)); + idft->SetOutSize(outSize); + if (c==spikeCoil) + idft->SetSpikesPerSlice(numSpikes); +// idft->SetNumberOfThreads(1); + idft->Update(); + + ComplexSliceType::Pointer fSlice; + fSlice = idft->GetOutput(); + + // fourier transform slice + ComplexSliceType::Pointer newSlice; + itk::DftImageFilter< SliceType::PixelType >::Pointer dft = itk::DftImageFilter< SliceType::PixelType >::New(); + dft->SetInput(fSlice); + dft->SetParameters(m_Parameters); + dft->Update(); + newSlice = dft->GetOutput(); + + // put slice back into channel g + for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) + for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) + { + DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; + ComplexSliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; - // fourier transform slice - SliceType::Pointer newSlice; - itk::DftImageFilter< SliceType::PixelType >::Pointer dft = itk::DftImageFilter< SliceType::PixelType >::New(); - dft->SetInput(fSlice); - dft->Update(); - newSlice = dft->GetOutput(); + ComplexSliceType::PixelType cPix = newSlice->GetPixel(index2D); + double magn = sqrt(cPix.real()*cPix.real()+cPix.imag()*cPix.imag()); + double phase = 0; + if (cPix.real()!=0) + phase = atan( cPix.imag()/cPix.real() ); - // put slice back into channel g - for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) - for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) - { - DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; - SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; - DoubleDwiType::PixelType pix3D = newImage->GetPixel(index3D); - pix3D[g] = newSlice->GetPixel(index2D); - newImage->SetPixel(index3D, pix3D); - } + DoubleDwiType::PixelType dwiPix = magnitudeDwiImage->GetPixel(index3D); + DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D); + + if (m_Parameters.m_SignalGen.m_NumberOfCoils>1) + { + dwiPix[g] += magn*magn; + phasePix[g] += phase*phase; + } + else + { + dwiPix[g] = magn; + phasePix[g] = phase; + } + +#pragma omp critical + { + magnitudeDwiImage->SetPixel(index3D, dwiPix); + m_PhaseImage->SetPixel(index3D, phasePix); + + // k-space image +// { +// DoubleDwiType4D::IndexType idx4d; +// idx4d[0]=index3D[0]; +// idx4d[1]=index3D[1]; +// idx4d[2]=index3D[2]; +// idx4d[3]=c; +// ItkDoubleImgType4D::PixelType pix4D = m_KspaceImage->GetPixel(idx4d); +// pix4D = idft->GetKSpaceImage()->GetPixel(index2D); +// m_KspaceImage->SetPixel(idx4d, pix4D); +// } + + if (g==0) + { + DoubleDwiType::PixelType kspacePix = m_KspaceImage->GetPixel(index3D); + kspacePix[c] = idft->GetKSpaceImage()->GetPixel(index2D); + m_KspaceImage->SetPixel(index3D, kspacePix); + } + } + } + } + + if (m_Parameters.m_SignalGen.m_NumberOfCoils>1) + { +#pragma omp parallel for collapse(2) + for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) + for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) + { + DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; + DoubleDwiType::PixelType magPix = magnitudeDwiImage->GetPixel(index3D); + magPix[g] = sqrt(magPix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils); + + DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D); + phasePix[g] = sqrt(phasePix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils); + +#pragma omp critical + { + magnitudeDwiImage->SetPixel(index3D, magPix); + m_PhaseImage->SetPixel(index3D, phasePix); + } + } + } + ++disp; - newTick = 50*disp.count()/disp.expected_count(); + unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned long tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; } } m_StatusText += "\n\n"; - return newImage; + return magnitudeDwiImage; +} + +template< class PixelType > +TractsToDWIImageFilter< PixelType >::ItkDoubleImgType::Pointer TractsToDWIImageFilter< PixelType >::NormalizeInsideMask(ItkDoubleImgType::Pointer image) +{ + double max = itk::NumericTraits< double >::min(); + double min = itk::NumericTraits< double >::max(); + + itk::ImageRegionIterator< ItkDoubleImgType > it(image, image->GetLargestPossibleRegion()); + while(!it.IsAtEnd()) + { + if (m_Parameters.m_SignalGen.m_MaskImage.IsNotNull() && m_Parameters.m_SignalGen.m_MaskImage->GetPixel(it.GetIndex())<=0) + { + it.Set(0.0); + ++it; + continue; + } + // if (it.Get()>900) + // it.Set(900); + + if (it.Get()>max) + max = it.Get(); + if (it.Get()::Pointer scaler = itk::ShiftScaleImageFilter< ItkDoubleImgType, ItkDoubleImgType >::New(); + scaler->SetInput(image); + scaler->SetShift(-min); + scaler->SetScale(1.0/(max-min)); + scaler->Update(); + return scaler->GetOutput(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::CheckVolumeFractionImages() { + m_UseRelativeNonFiberVolumeFractions = false; + // check for fiber volume fraction maps + int fibVolImages = 0; for (int i=0; iGetVolumeFractionImage().IsNotNull()) + { m_StatusText += "Using volume fraction map for fiber compartment " + boost::lexical_cast(i+1) + "\n"; + MITK_INFO << "Using volume fraction map for fiber compartment " + boost::lexical_cast(i+1); + fibVolImages++; + } // check for non-fiber volume fraction maps + int nonfibVolImages = 0; for (int i=0; iGetVolumeFractionImage().IsNotNull()) + { m_StatusText += "Using volume fraction map for non-fiber compartment " + boost::lexical_cast(i+1) + "\n"; + MITK_INFO << "Using volume fraction map for non-fiber compartment " + boost::lexical_cast(i+1); + nonfibVolImages++; + } - // check volume fraction images - if (m_Parameters.m_FiberModelList.size()>2) - for (int i=0; iGetVolumeFractionImage().IsNull()) - itkExceptionMacro("More than two fiber compartment selected but no volume fraction maps set!"); + // not all fiber compartments are using volume fraction maps --> non-fiber volume fractions are assumed to be relative to the non-fiber volume and not absolute voxel-volume fractions. + // this means if two non-fiber compartments are used but only one of them has an associated volume fraction map, the repesctive other volume fraction map can be determined as inverse (1-val) of the present volume fraction map- + if ( fibVolImages1) - for (int i=0; iGetVolumeFractionImage().IsNull()) - itkExceptionMacro("More than one non-fiber compartment selected but no volume fraction maps set!"); + itk::InvertIntensityImageFilter< ItkDoubleImgType, ItkDoubleImgType >::Pointer inverter = itk::InvertIntensityImageFilter< ItkDoubleImgType, ItkDoubleImgType >::New(); + inverter->SetMaximum(1.0); + if ( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNull() && m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNotNull() ) + { + // m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage( NormalizeInsideMask( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() ) ); + inverter->SetInput( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() ); + inverter->Update(); + m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage(inverter->GetOutput()); + } + else if ( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNull() && m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNotNull() ) + { + // m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage( NormalizeInsideMask( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() ) ); + inverter->SetInput( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() ); + inverter->Update(); + m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage(inverter->GetOutput()); + } + else + { + itkExceptionMacro("Something went wrong in automatically calculating the missing non-fiber volume fraction image! Did you use two non fiber compartments but only one volume fraction image? Then it should work and this error is really strange."); + } + nonfibVolImages++; + } + + // Up to two fiber compartments are allowed without volume fraction maps since the volume fractions can then be determined automatically + if (m_Parameters.m_FiberModelList.size()>2 && fibVolImages!=m_Parameters.m_FiberModelList.size()) + itkExceptionMacro("More than two fiber compartment selected but no corresponding volume fraction maps set!"); + + // One non-fiber compartment is allowed without volume fraction map since the volume fraction can then be determined automatically + if (m_Parameters.m_NonFiberModelList.size()>1 && nonfibVolImages!=m_Parameters.m_NonFiberModelList.size()) + itkExceptionMacro("More than one non-fiber compartment selected but no volume fraction maps set!"); + + if (fibVolImages0) + { + m_StatusText += "Not all fiber compartments are using an associated volume fraction image.\nAssuming non-fiber volume fraction images to contain values relative to the remaining non-fiber volume, not absolute values.\n"; + MITK_INFO << "Not all fiber compartments are using an associated volume fraction image.\nAssuming non-fiber volume fraction images to contain values relative to the remaining non-fiber volume, not absolute values."; + m_UseRelativeNonFiberVolumeFractions = true; + + // itk::ImageFileWriter::Pointer wr = itk::ImageFileWriter::New(); + // wr->SetInput(m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage()); + // wr->SetFileName("/local/volumefraction.nrrd"); + // wr->Update(); + } // initialize the images that store the output volume fraction of each compartment m_VolumeFractions.clear(); for (int i=0; iSetSpacing( m_WorkingSpacing ); doubleImg->SetOrigin( m_WorkingOrigin ); doubleImg->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); doubleImg->SetLargestPossibleRegion( m_WorkingImageRegion ); doubleImg->SetBufferedRegion( m_WorkingImageRegion ); doubleImg->SetRequestedRegion( m_WorkingImageRegion ); doubleImg->Allocate(); doubleImg->FillBuffer(0); m_VolumeFractions.push_back(doubleImg); } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::InitializeData() { // initialize output dwi image m_CroppedRegion = m_Parameters.m_SignalGen.m_ImageRegion; m_CroppedRegion.SetSize(1, m_CroppedRegion.GetSize(1)*m_Parameters.m_SignalGen.m_CroppingFactor); itk::Point shiftedOrigin = m_Parameters.m_SignalGen.m_ImageOrigin; shiftedOrigin[1] += (m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1)-m_CroppedRegion.GetSize(1))*m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; m_OutputImage = OutputImageType::New(); m_OutputImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_OutputImage->SetOrigin( shiftedOrigin ); m_OutputImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_OutputImage->SetLargestPossibleRegion( m_CroppedRegion ); m_OutputImage->SetBufferedRegion( m_CroppedRegion ); m_OutputImage->SetRequestedRegion( m_CroppedRegion ); m_OutputImage->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); m_OutputImage->Allocate(); typename OutputImageType::PixelType temp; temp.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); temp.Fill(0.0); m_OutputImage->FillBuffer(temp); - if ( m_CroppedRegion.GetSize(0)%2 == 1 ) - m_CroppedRegion.SetSize(0, m_CroppedRegion.GetSize(0)+1); - if ( m_CroppedRegion.GetSize(1)%2 == 1 ) - m_CroppedRegion.SetSize(1, m_CroppedRegion.GetSize(1)+1); - - // ADJUST GEOMETRY FOR FURTHER PROCESSING - // is input slize size a power of two? - unsigned int x=m_Parameters.m_SignalGen.m_ImageRegion.GetSize(0); unsigned int y=m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1); - ItkDoubleImgType::SizeType pad; pad[0]=x%2; pad[1]=y%2; pad[2]=0; - m_Parameters.m_SignalGen.m_ImageRegion.SetSize(0, x+pad[0]); - m_Parameters.m_SignalGen.m_ImageRegion.SetSize(1, y+pad[1]); - if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull() && (pad[0]>0 || pad[1]>0)) - { - itk::ConstantPadImageFilter::Pointer zeroPadder = itk::ConstantPadImageFilter::New(); - zeroPadder->SetInput(m_Parameters.m_SignalGen.m_FrequencyMap); - zeroPadder->SetConstant(0); - zeroPadder->SetPadUpperBound(pad); - zeroPadder->Update(); - m_Parameters.m_SignalGen.m_FrequencyMap = zeroPadder->GetOutput(); - } - if (m_Parameters.m_SignalGen.m_MaskImage.IsNotNull() && (pad[0]>0 || pad[1]>0)) - { - itk::ConstantPadImageFilter::Pointer zeroPadder = itk::ConstantPadImageFilter::New(); - zeroPadder->SetInput(m_Parameters.m_SignalGen.m_MaskImage); - zeroPadder->SetConstant(0); - zeroPadder->SetPadUpperBound(pad); - zeroPadder->Update(); - m_Parameters.m_SignalGen.m_MaskImage = zeroPadder->GetOutput(); - } + //// NOT NECESSARY ANYMORE +// if ( m_CroppedRegion.GetSize(0)%2 == 1 ) +// m_CroppedRegion.SetSize(0, m_CroppedRegion.GetSize(0)+1); +// if ( m_CroppedRegion.GetSize(1)%2 == 1 ) +// m_CroppedRegion.SetSize(1, m_CroppedRegion.GetSize(1)+1); + +// // ADJUST GEOMETRY FOR FURTHER PROCESSING +// // is input slize size a power of two? +// unsigned int x=m_Parameters.m_SignalGen.m_ImageRegion.GetSize(0); unsigned int y=m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1); +// ItkDoubleImgType::SizeType pad; pad[0]=x%2; pad[1]=y%2; pad[2]=0; +// m_Parameters.m_SignalGen.m_ImageRegion.SetSize(0, x+pad[0]); +// m_Parameters.m_SignalGen.m_ImageRegion.SetSize(1, y+pad[1]); +// if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull() && (pad[0]>0 || pad[1]>0)) +// { +// itk::ConstantPadImageFilter::Pointer zeroPadder = itk::ConstantPadImageFilter::New(); +// zeroPadder->SetInput(m_Parameters.m_SignalGen.m_FrequencyMap); +// zeroPadder->SetConstant(0); +// zeroPadder->SetPadUpperBound(pad); +// zeroPadder->Update(); +// m_Parameters.m_SignalGen.m_FrequencyMap = zeroPadder->GetOutput(); +// } +// if (m_Parameters.m_SignalGen.m_MaskImage.IsNotNull() && (pad[0]>0 || pad[1]>0)) +// { +// itk::ConstantPadImageFilter::Pointer zeroPadder = itk::ConstantPadImageFilter::New(); +// zeroPadder->SetInput(m_Parameters.m_SignalGen.m_MaskImage); +// zeroPadder->SetConstant(0); +// zeroPadder->SetPadUpperBound(pad); +// zeroPadder->Update(); +// m_Parameters.m_SignalGen.m_MaskImage = zeroPadder->GetOutput(); +// } // Apply in-plane upsampling for Gibbs ringing artifact double upsampling = 1; if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) upsampling = 2; m_WorkingSpacing = m_Parameters.m_SignalGen.m_ImageSpacing; m_WorkingSpacing[0] /= upsampling; m_WorkingSpacing[1] /= upsampling; m_WorkingImageRegion = m_Parameters.m_SignalGen.m_ImageRegion; m_WorkingImageRegion.SetSize(0, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[0]*upsampling); m_WorkingImageRegion.SetSize(1, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[1]*upsampling); m_WorkingOrigin = m_Parameters.m_SignalGen.m_ImageOrigin; m_WorkingOrigin[0] -= m_Parameters.m_SignalGen.m_ImageSpacing[0]/2; m_WorkingOrigin[0] += m_WorkingSpacing[0]/2; m_WorkingOrigin[1] -= m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; m_WorkingOrigin[1] += m_WorkingSpacing[1]/2; m_WorkingOrigin[2] -= m_Parameters.m_SignalGen.m_ImageSpacing[2]/2; m_WorkingOrigin[2] += m_WorkingSpacing[2]/2; m_VoxelVolume = m_WorkingSpacing[0]*m_WorkingSpacing[1]*m_WorkingSpacing[2]; // generate double images to store the individual compartment signals m_CompartmentImages.clear(); int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); for (int i=0; iSetSpacing( m_WorkingSpacing ); doubleDwi->SetOrigin( m_WorkingOrigin ); doubleDwi->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); doubleDwi->SetLargestPossibleRegion( m_WorkingImageRegion ); doubleDwi->SetBufferedRegion( m_WorkingImageRegion ); doubleDwi->SetRequestedRegion( m_WorkingImageRegion ); doubleDwi->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); doubleDwi->Allocate(); DoubleDwiType::PixelType pix; pix.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); pix.Fill(0.0); doubleDwi->FillBuffer(pix); m_CompartmentImages.push_back(doubleDwi); } // resample mask image and frequency map to fit upsampled geometry if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) { if (m_Parameters.m_SignalGen.m_MaskImage.IsNotNull()) { // rescale mask image (otherwise there are problems with the resampling) itk::RescaleIntensityImageFilter::Pointer rescaler = itk::RescaleIntensityImageFilter::New(); rescaler->SetInput(0,m_Parameters.m_SignalGen.m_MaskImage); rescaler->SetOutputMaximum(100); rescaler->SetOutputMinimum(0); rescaler->Update(); // resample mask image itk::ResampleImageFilter::Pointer resampler = itk::ResampleImageFilter::New(); resampler->SetInput(rescaler->GetOutput()); resampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_MaskImage); resampler->SetSize(m_WorkingImageRegion.GetSize()); resampler->SetOutputSpacing(m_WorkingSpacing); resampler->SetOutputOrigin(m_WorkingOrigin); itk::NearestNeighborInterpolateImageFunction::Pointer nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); m_Parameters.m_SignalGen.m_MaskImage = resampler->GetOutput(); } // resample frequency map if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) { itk::ResampleImageFilter::Pointer resampler = itk::ResampleImageFilter::New(); resampler->SetInput(m_Parameters.m_SignalGen.m_FrequencyMap); resampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_FrequencyMap); resampler->SetSize(m_WorkingImageRegion.GetSize()); resampler->SetOutputSpacing(m_WorkingSpacing); resampler->SetOutputOrigin(m_WorkingOrigin); itk::NearestNeighborInterpolateImageFunction::Pointer nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); m_Parameters.m_SignalGen.m_FrequencyMap = resampler->GetOutput(); } } m_MaskImageSet = true; if (m_Parameters.m_SignalGen.m_MaskImage.IsNull()) { // no input tissue mask is set -> create default m_StatusText += "No tissue mask set\n"; MITK_INFO << "No tissue mask set"; m_Parameters.m_SignalGen.m_MaskImage = ItkUcharImgType::New(); m_Parameters.m_SignalGen.m_MaskImage->SetSpacing( m_WorkingSpacing ); m_Parameters.m_SignalGen.m_MaskImage->SetOrigin( m_WorkingOrigin ); m_Parameters.m_SignalGen.m_MaskImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_Parameters.m_SignalGen.m_MaskImage->SetLargestPossibleRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->SetBufferedRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->SetRequestedRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->Allocate(); m_Parameters.m_SignalGen.m_MaskImage->FillBuffer(100); m_MaskImageSet = false; } else { - if (m_Parameters.m_SignalGen.m_MaskImage->GetLargestPossibleRegion()!=m_Parameters.m_SignalGen.m_ImageRegion) + if (m_Parameters.m_SignalGen.m_MaskImage->GetLargestPossibleRegion()!=m_WorkingImageRegion) itkExceptionMacro("Mask image and specified DWI geometry are not matching!"); m_StatusText += "Using tissue mask\n"; MITK_INFO << "Using tissue mask"; } if (m_Parameters.m_SignalGen.m_DoAddMotion) { std::string fileName = "fiberfox_motion_0.log"; std::string filePath = mitk::IOUtil::GetTempPath(); if (m_Parameters.m_Misc.m_OutputPath.size()>0) filePath = m_Parameters.m_Misc.m_OutputPath; int c = 1; while (itksys::SystemTools::FileExists((filePath+fileName).c_str())) { fileName = "fiberfox_motion_"; fileName += boost::lexical_cast(c); fileName += ".log"; c++; } m_Logfile.open((filePath+fileName).c_str()); m_Logfile << "0 rotation: 0,0,0; translation: 0,0,0\n"; if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { m_StatusText += "Adding random motion artifacts:\n"; m_StatusText += "Maximum rotation: +/-" + boost::lexical_cast(m_Parameters.m_SignalGen.m_Rotation) + "°\n"; m_StatusText += "Maximum translation: +/-" + boost::lexical_cast(m_Parameters.m_SignalGen.m_Translation) + "mm\n"; } else { m_StatusText += "Adding linear motion artifacts:\n"; m_StatusText += "Maximum rotation: " + boost::lexical_cast(m_Parameters.m_SignalGen.m_Rotation) + "°\n"; m_StatusText += "Maximum translation: " + boost::lexical_cast(m_Parameters.m_SignalGen.m_Translation) + "mm\n"; } m_StatusText += "Motion logfile: " + (filePath+fileName) + "\n"; MITK_INFO << "Adding motion artifacts"; MITK_INFO << "Maximum rotation: " << m_Parameters.m_SignalGen.m_Rotation; MITK_INFO << "Maxmimum translation: " << m_Parameters.m_SignalGen.m_Translation; + MITK_INFO << "Motion logfile: " << filePath << fileName; } // get transform for motion artifacts + m_Rotation.Fill(0.0); + m_Translation.Fill(0.0); + m_Rotations.push_back(m_Rotation); + m_Translations.push_back(m_Translation); m_Rotation = m_Parameters.m_SignalGen.m_Rotation/m_Parameters.m_SignalGen.GetNumVolumes(); m_Translation = m_Parameters.m_SignalGen.m_Translation/m_Parameters.m_SignalGen.GetNumVolumes(); // creat image to hold transformed mask (motion artifact) m_TransformedMaskImage = ItkUcharImgType::New(); itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage(m_Parameters.m_SignalGen.m_MaskImage); duplicator->Update(); m_TransformedMaskImage = duplicator->GetOutput(); // second upsampling needed for motion artifacts ImageRegion<3> upsampledImageRegion = m_WorkingImageRegion; DoubleVectorType upsampledSpacing = m_WorkingSpacing; upsampledSpacing[0] /= 4; upsampledSpacing[1] /= 4; upsampledSpacing[2] /= 4; upsampledImageRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]*4); upsampledImageRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]*4); upsampledImageRegion.SetSize(2, m_WorkingImageRegion.GetSize()[2]*4); itk::Point upsampledOrigin = m_WorkingOrigin; upsampledOrigin[0] -= m_WorkingSpacing[0]/2; upsampledOrigin[0] += upsampledSpacing[0]/2; upsampledOrigin[1] -= m_WorkingSpacing[1]/2; upsampledOrigin[1] += upsampledSpacing[1]/2; upsampledOrigin[2] -= m_WorkingSpacing[2]/2; upsampledOrigin[2] += upsampledSpacing[2]/2; m_UpsampledMaskImage = ItkUcharImgType::New(); itk::ResampleImageFilter::Pointer upsampler = itk::ResampleImageFilter::New(); upsampler->SetInput(m_Parameters.m_SignalGen.m_MaskImage); upsampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_MaskImage); upsampler->SetSize(upsampledImageRegion.GetSize()); upsampler->SetOutputSpacing(upsampledSpacing); upsampler->SetOutputOrigin(upsampledOrigin); itk::NearestNeighborInterpolateImageFunction::Pointer nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); upsampler->SetInterpolator(nn_interpolator); upsampler->Update(); m_UpsampledMaskImage = upsampler->GetOutput(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::InitializeFiberData() { // resample fiber bundle for sufficient voxel coverage m_StatusText += "\n"+this->GetTime()+" > Resampling fibers ...\n"; - segmentVolume = 0.0001; + m_SegmentVolume = 0.0001; float minSpacing = 1; if(m_WorkingSpacing[0]GetDeepCopy(); // working copy is needed because we need to resample the fibers but do not want to change the original bundle double volumeAccuracy = 10; m_FiberBundleWorkingCopy->ResampleSpline(minSpacing/volumeAccuracy); - mmRadius = m_Parameters.m_SignalGen.m_AxonRadius/1000; - if (mmRadius>0) - segmentVolume = M_PI*mmRadius*mmRadius*minSpacing/volumeAccuracy; + m_mmRadius = m_Parameters.m_SignalGen.m_AxonRadius/1000; + if (m_mmRadius>0) + m_SegmentVolume = M_PI*m_mmRadius*m_mmRadius*minSpacing/volumeAccuracy; m_FiberBundleTransformed = m_FiberBundleWorkingCopy; // a secon fiber bundle is needed to store the transformed version of the m_FiberBundleWorkingCopy } template< class PixelType > void TractsToDWIImageFilter< PixelType >::GenerateData() { m_TimeProbe.Start(); m_StatusText = "Starting simulation\n"; // check input data if (m_FiberBundle.IsNull()) itkExceptionMacro("Input fiber bundle is NULL!"); if (m_Parameters.m_FiberModelList.empty()) itkExceptionMacro("No diffusion model for fiber compartments defined! At least one fiber compartment is necessary."); if (m_Parameters.m_NonFiberModelList.empty()) itkExceptionMacro("No diffusion model for non-fiber compartments defined! At least one non-fiber compartment is necessary."); int baselineIndex = m_Parameters.m_SignalGen.GetFirstBaselineIndex(); if (baselineIndex<0) itkExceptionMacro("No baseline index found!"); if (!m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition) // No upsampling of input image needed if no k-space simulation is performed m_Parameters.m_SignalGen.m_DoAddGibbsRinging = false; if (m_UseConstantRandSeed) // always generate the same random numbers? m_RandGen->SetSeed(0); else m_RandGen->SetSeed(); InitializeData(); CheckVolumeFractionImages(); InitializeFiberData(); int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); double maxVolume = 0; unsigned long lastTick = 0; int signalModelSeed = m_RandGen->GetIntegerVariate(); m_StatusText += "\n"+this->GetTime()+" > Generating " + boost::lexical_cast(numFiberCompartments+numNonFiberCompartments) + "-compartment diffusion-weighted signal.\n"; MITK_INFO << "Generating " << numFiberCompartments+numNonFiberCompartments << "-compartment diffusion-weighted signal."; int numFibers = m_FiberBundleWorkingCopy->GetNumFibers(); boost::progress_display disp(numFibers*m_Parameters.m_SignalGen.GetNumVolumes()); switch (m_Parameters.m_SignalGen.m_DiffusionDirectionMode) { case(SignalGenerationParameters::FIBER_TANGENT_DIRECTIONS): // use fiber tangent directions to determine diffusion direction { m_StatusText += "0% 10 20 30 40 50 60 70 80 90 100%\n"; m_StatusText += "|----|----|----|----|----|----|----|----|----|----|\n*"; for (unsigned int g=0; gSetSeed(signalModelSeed); for (int i=0; iSetSeed(signalModelSeed); // storing voxel-wise intra-axonal volume in mm³ ItkDoubleImgType::Pointer intraAxonalVolumeImage = ItkDoubleImgType::New(); intraAxonalVolumeImage->SetSpacing( m_WorkingSpacing ); intraAxonalVolumeImage->SetOrigin( m_WorkingOrigin ); intraAxonalVolumeImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); intraAxonalVolumeImage->SetLargestPossibleRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetBufferedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetRequestedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->Allocate(); intraAxonalVolumeImage->FillBuffer(0); maxVolume = 0; vtkPolyData* fiberPolyData = m_FiberBundleTransformed->GetFiberPolyData(); // generate fiber signal (if there are any fiber models present) if (!m_Parameters.m_FiberModelList.empty()) for( int i=0; iGetFiberWeight(i); vtkCell* cell = fiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints<2) continue; for( int j=0; jGetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } double* temp = points->GetPoint(j); itk::Point vertex = GetItkPoint(temp); itk::Vector v = GetItkVector(temp); itk::Vector dir(3); if (jGetPoint(j+1))-v; else dir = v-GetItkVector(points->GetPoint(j-1)); if (dir.GetSquaredNorm()<0.0001 || dir[0]!=dir[0] || dir[1]!=dir[1] || dir[2]!=dir[2]) continue; itk::Index<3> idx; itk::ContinuousIndex contIndex; m_TransformedMaskImage->TransformPhysicalPointToIndex(vertex, idx); m_TransformedMaskImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex); if (!m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(idx) || m_TransformedMaskImage->GetPixel(idx)<=0) continue; // generate signal for each fiber compartment for (int k=0; kSetFiberDirection(dir); DoubleDwiType::PixelType pix = m_CompartmentImages.at(k)->GetPixel(idx); - pix[g] += fiberWeight*segmentVolume*m_Parameters.m_FiberModelList[k]->SimulateMeasurement(g); + pix[g] += fiberWeight*m_SegmentVolume*m_Parameters.m_FiberModelList[k]->SimulateMeasurement(g); m_CompartmentImages.at(k)->SetPixel(idx, pix); } // update fiber volume image - double vol = intraAxonalVolumeImage->GetPixel(idx) + segmentVolume*fiberWeight; + double vol = intraAxonalVolumeImage->GetPixel(idx) + m_SegmentVolume*fiberWeight; intraAxonalVolumeImage->SetPixel(idx, vol); if (vol>maxVolume) // we assume that the first volume is always unweighted! maxVolume = vol; } // progress report ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; } // generate non-fiber signal ImageRegionIterator it3(m_TransformedMaskImage, m_TransformedMaskImage->GetLargestPossibleRegion()); double fact = 1; // density correction factor in mm³ if (m_Parameters.m_SignalGen.m_AxonRadius<0.0001 || maxVolume>m_VoxelVolume) // the fullest voxel is always completely full fact = m_VoxelVolume/maxVolume; while(!it3.IsAtEnd()) { if (it3.Get()>0) { DoubleDwiType::IndexType index = it3.GetIndex(); itk::Point point; m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, point); if (m_Parameters.m_SignalGen.m_DoAddMotion) { if (m_Parameters.m_SignalGen.m_DoRandomizeMotion && g>0) point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(), -m_Rotation[0],-m_Rotation[1],-m_Rotation[2],-m_Translation[0],-m_Translation[1],-m_Translation[2]); else if (g>=0) point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(), -m_Rotation[0]*g,-m_Rotation[1]*g,-m_Rotation[2]*g,-m_Translation[0]*g,-m_Translation[1]*g,-m_Translation[2]*g); } double iAxVolume = intraAxonalVolumeImage->GetPixel(index); // if volume fraction image is set use it, otherwise use scaling factor to obtain one full fiber voxel double fact2 = fact; if (m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()!=nullptr && iAxVolume>0.0001) { DoubleDwiType::IndexType newIndex; m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()->TransformPhysicalPointToIndex(point, newIndex); if (m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()->GetLargestPossibleRegion().IsInside(newIndex)) fact2 = m_VoxelVolume*m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()->GetPixel(newIndex)/iAxVolume; } // adjust intra-axonal image value for (int i=0; iGetPixel(index); pix[g] *= fact2; m_CompartmentImages.at(i)->SetPixel(index, pix); } // simulate other compartments SimulateExtraAxonalSignal(index, iAxVolume*fact2, g); } ++it3; } // move fibers SimulateMotion(g); } break; } case (SignalGenerationParameters::MAIN_FIBER_DIRECTIONS): // use main fiber directions to determine voxel-wise diffusion directions { typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType; typedef itk::VectorContainer< unsigned int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; // calculate main fiber directions itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); fOdfFilter->SetFiberBundle(m_FiberBundleTransformed); fOdfFilter->SetMaskImage(m_TransformedMaskImage); fOdfFilter->SetAngularThreshold(cos(m_Parameters.m_SignalGen.m_FiberSeparationThreshold*M_PI/180.0)); fOdfFilter->SetNormalizeVectors(false); fOdfFilter->SetUseWorkingCopy(true); fOdfFilter->SetSizeThreshold(0); fOdfFilter->SetMaxNumDirections(3); fOdfFilter->Update(); ItkDirectionImageContainerType::Pointer directionImageContainer = fOdfFilter->GetDirectionImageContainer(); // allocate image storing intra-axonal volume fraction information ItkDoubleImgType::Pointer intraAxonalVolumeImage = ItkDoubleImgType::New(); intraAxonalVolumeImage->SetSpacing( m_WorkingSpacing ); intraAxonalVolumeImage->SetOrigin( m_WorkingOrigin ); intraAxonalVolumeImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); intraAxonalVolumeImage->SetLargestPossibleRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetBufferedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetRequestedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->Allocate(); intraAxonalVolumeImage->FillBuffer(0); // determine intra-axonal volume fraction using the tract density itk::TractDensityImageFilter< ItkDoubleImgType >::Pointer tdiFilter = itk::TractDensityImageFilter< ItkDoubleImgType >::New(); tdiFilter->SetFiberBundle(m_FiberBundleTransformed); tdiFilter->SetBinaryOutput(false); tdiFilter->SetOutputAbsoluteValues(false); tdiFilter->SetInputImage(intraAxonalVolumeImage); tdiFilter->SetUseImageGeometry(true); tdiFilter->Update(); intraAxonalVolumeImage = tdiFilter->GetOutput(); m_StatusText += "0% 10 20 30 40 50 60 70 80 90 100%\n"; m_StatusText += "|----|----|----|----|----|----|----|----|----|----|\n*"; boost::progress_display disp(m_TransformedMaskImage->GetLargestPossibleRegion().GetNumberOfPixels()*m_Parameters.m_SignalGen.GetNumVolumes()); for (unsigned int g=0; gSetSeed(signalModelSeed); for (int i=0; iSetSeed(signalModelSeed); if (m_Parameters.m_SignalGen.m_DoAddMotion && g>0) // if fibers have moved we need a new TDI and new directions { fOdfFilter->SetFiberBundle(m_FiberBundleTransformed); fOdfFilter->SetMaskImage(m_TransformedMaskImage); fOdfFilter->Update(); directionImageContainer = fOdfFilter->GetDirectionImageContainer(); tdiFilter->SetFiberBundle(m_FiberBundleTransformed); tdiFilter->Update(); intraAxonalVolumeImage = tdiFilter->GetOutput(); } ImageRegionIterator< ItkUcharImgType > it(m_TransformedMaskImage, m_TransformedMaskImage->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; if (this->GetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } if (it.Get()>0) { // generate fiber signal for (int c=0; cGetPixel(it.GetIndex()); for (unsigned int i=0; iSize(); i++) { itk::Vector< double, 3> dir; dir.CastFrom(directionImageContainer->GetElement(i)->GetPixel(it.GetIndex())); double norm = dir.GetNorm(); if (norm>0.0001) { m_Parameters.m_FiberModelList.at(c)->SetFiberDirection(dir); pix[g] += m_Parameters.m_FiberModelList.at(c)->SimulateMeasurement(g)*norm; count++; } } if (count>0) pix[g] /= count; pix[g] *= intraAxonalVolumeImage->GetPixel(it.GetIndex())*m_VoxelVolume; m_CompartmentImages.at(c)->SetPixel(it.GetIndex(), pix); } // simulate other compartments SimulateExtraAxonalSignal(it.GetIndex(), intraAxonalVolumeImage->GetPixel(it.GetIndex())*m_VoxelVolume, g); } ++it; } SimulateMotion(g); } itk::ImageFileWriter< ItkUcharImgType >::Pointer wr = itk::ImageFileWriter< ItkUcharImgType >::New(); wr->SetInput(fOdfFilter->GetNumDirectionsImage()); wr->SetFileName(mitk::IOUtil::GetTempPath()+"/NumDirections_MainFiberDirections.nrrd"); wr->Update(); break; } case (SignalGenerationParameters::RANDOM_DIRECTIONS): { ItkUcharImgType::Pointer numDirectionsImage = ItkUcharImgType::New(); numDirectionsImage->SetSpacing( m_WorkingSpacing ); numDirectionsImage->SetOrigin( m_WorkingOrigin ); numDirectionsImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); numDirectionsImage->SetLargestPossibleRegion( m_WorkingImageRegion ); numDirectionsImage->SetBufferedRegion( m_WorkingImageRegion ); numDirectionsImage->SetRequestedRegion( m_WorkingImageRegion ); numDirectionsImage->Allocate(); numDirectionsImage->FillBuffer(0); double sepAngle = cos(m_Parameters.m_SignalGen.m_FiberSeparationThreshold*M_PI/180.0); m_StatusText += "0% 10 20 30 40 50 60 70 80 90 100%\n"; m_StatusText += "|----|----|----|----|----|----|----|----|----|----|\n*"; boost::progress_display disp(m_TransformedMaskImage->GetLargestPossibleRegion().GetNumberOfPixels()); ImageRegionIterator it(m_TransformedMaskImage, m_TransformedMaskImage->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; if (this->GetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } if (it.Get()>0) { int numFibs = m_RandGen->GetIntegerVariate(2)+1; DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(it.GetIndex()); double volume = m_RandGen->GetVariateWithClosedRange(0.3); // double sum = 0; std::vector< double > fractions; for (int i=0; iGetVariateWithClosedRange(0.5)); // sum += fractions.at(i); } // for (int i=0; i > directions; for (int i=0; iGetVariateWithClosedRange(2)-1.0; fib[1] = m_RandGen->GetVariateWithClosedRange(2)-1.0; fib[2] = m_RandGen->GetVariateWithClosedRange(2)-1.0; fib.Normalize(); double min = 0; for (unsigned int d=0; dmin) min = angle; } if (minSetFiberDirection(fib); pix += m_Parameters.m_FiberModelList.at(0)->SimulateMeasurement()*fractions[i]; directions.push_back(fib); } else i--; } pix *= (1-volume); m_CompartmentImages.at(0)->SetPixel(it.GetIndex(), pix); // CSF/GM { pix += volume*m_Parameters.m_NonFiberModelList.at(0)->SimulateMeasurement(); } numDirectionsImage->SetPixel(it.GetIndex(), numFibs); } ++it; } itk::ImageFileWriter< ItkUcharImgType >::Pointer wr = itk::ImageFileWriter< ItkUcharImgType >::New(); wr->SetInput(numDirectionsImage); wr->SetFileName(mitk::IOUtil::GetTempPath()+"/NumDirections_RandomDirections.nrrd"); wr->Update(); } } if (m_Logfile.is_open()) { m_Logfile << "DONE"; m_Logfile.close(); } m_StatusText += "\n\n"; if (this->GetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } DoubleDwiType::Pointer doubleOutImage; + double signalScale = m_Parameters.m_SignalGen.m_SignalScale; if ( m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition ) // do k-space stuff { - m_StatusText += this->GetTime()+" > Adjusting complex signal\n"; - MITK_INFO << "Adjusting complex signal:"; + m_StatusText += this->GetTime()+" > Simulating k-space acquisition using "+boost::lexical_cast(m_Parameters.m_SignalGen.m_NumberOfCoils)+" coil(s)\n"; + MITK_INFO << "Simulating k-space acquisition using " << m_Parameters.m_SignalGen.m_NumberOfCoils << " coil(s)."; if (m_Parameters.m_SignalGen.m_DoSimulateRelaxation) m_StatusText += "Simulating signal relaxation\n"; if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) m_StatusText += "Simulating distortions\n"; if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) m_StatusText += "Simulating ringing artifacts\n"; if (m_Parameters.m_SignalGen.m_EddyStrength>0) m_StatusText += "Simulating eddy currents\n"; if (m_Parameters.m_SignalGen.m_Spikes>0) m_StatusText += "Simulating spikes\n"; if (m_Parameters.m_SignalGen.m_CroppingFactor<1.0) m_StatusText += "Simulating aliasing artifacts\n"; if (m_Parameters.m_SignalGen.m_KspaceLineOffset>0) m_StatusText += "Simulating ghosts\n"; - doubleOutImage = DoKspaceStuff(m_CompartmentImages); - m_Parameters.m_SignalGen.m_SignalScale = 1; // already scaled in DoKspaceStuff + doubleOutImage = SimulateKspaceAcquisition(m_CompartmentImages); + signalScale = 1; // already scaled in DoKspaceStuff } else // don't do k-space stuff, just sum compartments { m_StatusText += this->GetTime()+" > Summing compartments\n"; MITK_INFO << "Summing compartments"; doubleOutImage = m_CompartmentImages.at(0); for (unsigned int i=1; i::Pointer adder = itk::AddImageFilter< DoubleDwiType, DoubleDwiType, DoubleDwiType>::New(); adder->SetInput1(doubleOutImage); adder->SetInput2(m_CompartmentImages.at(i)); adder->Update(); doubleOutImage = adder->GetOutput(); } } if (this->GetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } m_StatusText += this->GetTime()+" > Finalizing image\n"; MITK_INFO << "Finalizing image"; - if (m_Parameters.m_SignalGen.m_SignalScale>1) + if (signalScale>1) m_StatusText += " Scaling signal\n"; if (m_Parameters.m_NoiseModel!=NULL) m_StatusText += " Adding noise\n"; unsigned int window = 0; unsigned int min = itk::NumericTraits::max(); ImageRegionIterator it4 (m_OutputImage, m_OutputImage->GetLargestPossibleRegion()); DoubleDwiType::PixelType signal; signal.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); boost::progress_display disp2(m_OutputImage->GetLargestPossibleRegion().GetNumberOfPixels()); m_StatusText += "0% 10 20 30 40 50 60 70 80 90 100%\n"; m_StatusText += "|----|----|----|----|----|----|----|----|----|----|\n*"; lastTick = 0; while(!it4.IsAtEnd()) { if (this->GetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } ++disp2; unsigned long newTick = 50*disp2.count()/disp2.expected_count(); for (unsigned long tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; typename OutputImageType::IndexType index = it4.GetIndex(); - signal = doubleOutImage->GetPixel(index)*m_Parameters.m_SignalGen.m_SignalScale; + signal = doubleOutImage->GetPixel(index)*signalScale; if (m_Parameters.m_NoiseModel!=NULL) m_Parameters.m_NoiseModel->AddNoise(signal); for (unsigned int i=0; i0) signal[i] = floor(signal[i]+0.5); else signal[i] = ceil(signal[i]-0.5); if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]>window) window = signal[i]; if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]SetNthOutput(0, m_OutputImage); m_StatusText += "\n\n"; m_StatusText += "Finished simulation\n"; m_StatusText += "Simulation time: "+GetTime(); m_TimeProbe.Stop(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::SimulateMotion(int g) { if (m_Parameters.m_SignalGen.m_DoAddMotion && gGetDeepCopy(); m_Rotation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[0]*2)-m_Parameters.m_SignalGen.m_Rotation[0]; m_Rotation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[1]*2)-m_Parameters.m_SignalGen.m_Rotation[1]; m_Rotation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[2]*2)-m_Parameters.m_SignalGen.m_Rotation[2]; m_Translation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[0]*2)-m_Parameters.m_SignalGen.m_Translation[0]; m_Translation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[1]*2)-m_Parameters.m_SignalGen.m_Translation[1]; m_Translation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[2]*2)-m_Parameters.m_SignalGen.m_Translation[2]; } // rotate mask image if (m_MaskImageSet) { ImageRegionIterator maskIt(m_UpsampledMaskImage, m_UpsampledMaskImage->GetLargestPossibleRegion()); m_TransformedMaskImage->FillBuffer(0); while(!maskIt.IsAtEnd()) { if (maskIt.Get()<=0) { ++maskIt; continue; } DoubleDwiType::IndexType index = maskIt.GetIndex(); itk::Point point; m_UpsampledMaskImage->TransformIndexToPhysicalPoint(index, point); if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(), m_Rotation[0],m_Rotation[1],m_Rotation[2],m_Translation[0],m_Translation[1],m_Translation[2]); else point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(), m_Rotation[0]*(g+1),m_Rotation[1]*(g+1),m_Rotation[2]*(g+1),m_Translation[0]*(g+1),m_Translation[1]*(g+1),m_Translation[2]*(g+1)); m_TransformedMaskImage->TransformPhysicalPointToIndex(point, index); if (m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(index)) m_TransformedMaskImage->SetPixel(index,100); ++maskIt; } } + if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) + { + m_Rotations.push_back(m_Rotation); + m_Translations.push_back(m_Translation); + } + else + { + m_Rotations.push_back(m_Rotation*(g+1)); + m_Translations.push_back(m_Translation*(g+1)); + } + // rotate fibers if (m_Logfile.is_open()) { m_Logfile << g+1 << " rotation: " << m_Rotation[0] << "," << m_Rotation[1] << "," << m_Rotation[2] << ";"; m_Logfile << " translation: " << m_Translation[0] << "," << m_Translation[1] << "," << m_Translation[2] << "\n"; } m_FiberBundleTransformed->TransformFibers(m_Rotation[0],m_Rotation[1],m_Rotation[2],m_Translation[0],m_Translation[1],m_Translation[2]); } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::SimulateExtraAxonalSignal(ItkUcharImgType::IndexType index, double intraAxonalVolume, int g) { int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); if (intraAxonalVolume>0.0001 && m_Parameters.m_SignalGen.m_DoDisablePartialVolume) // only fiber in voxel { DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); if (g>=0) pix[g] *= m_VoxelVolume/intraAxonalVolume; else pix *= m_VoxelVolume/intraAxonalVolume; m_CompartmentImages.at(0)->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(0)->SetPixel(index, 1); for (int i=1; iGetPixel(index); if (g>=0) pix[g] = 0.0; else pix.Fill(0.0); m_CompartmentImages.at(i)->SetPixel(index, pix); } } else { if (g==0) m_VolumeFractions.at(0)->SetPixel(index, intraAxonalVolume/m_VoxelVolume); // get non-transformed point (remove headmotion tranformation) // this point can then be transformed to each of the original images, regardless of their geometry itk::Point point; m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, point); if (m_Parameters.m_SignalGen.m_DoAddMotion) { if (m_Parameters.m_SignalGen.m_DoRandomizeMotion && g>0) point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(), -m_Rotation[0],-m_Rotation[1],-m_Rotation[2],-m_Translation[0],-m_Translation[1],-m_Translation[2]); else if (g>=0) point = m_FiberBundleWorkingCopy->TransformPoint(point.GetVnlVector(), -m_Rotation[0]*g,-m_Rotation[1]*g,-m_Rotation[2]*g,-m_Translation[0]*g,-m_Translation[1]*g,-m_Translation[2]*g); } if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) { int maxVolumeIndex = 0; double maxWeight = 0; for (int i=0; i1) { -// ItkUcharImgType::IndexType maskIndex; -// m_UpsampledMaskImage->TransformPhysicalPointToIndex(point, maskIndex); -// if (!m_UpsampledMaskImage->GetLargestPossibleRegion().IsInside(maskIndex) || m_UpsampledMaskImage->GetPixel(maskIndex)==0) -// continue; + // ItkUcharImgType::IndexType maskIndex; + // m_UpsampledMaskImage->TransformPhysicalPointToIndex(point, maskIndex); + // if (!m_UpsampledMaskImage->GetLargestPossibleRegion().IsInside(maskIndex) || m_UpsampledMaskImage->GetPixel(maskIndex)==0) + // continue; DoubleDwiType::IndexType newIndex; m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()->TransformPhysicalPointToIndex(point, newIndex); if (!m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()->GetLargestPossibleRegion().IsInside(newIndex)) continue; weight = m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()->GetPixel(newIndex); } if (weight>maxWeight) { maxWeight = weight; maxVolumeIndex = i; } } DoubleDwiType::Pointer doubleDwi = m_CompartmentImages.at(maxVolumeIndex+numFiberCompartments); DoubleDwiType::PixelType pix = doubleDwi->GetPixel(index); if (g>=0) pix[g] += m_Parameters.m_NonFiberModelList[maxVolumeIndex]->SimulateMeasurement(g); else pix += m_Parameters.m_NonFiberModelList[maxVolumeIndex]->SimulateMeasurement(); doubleDwi->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(maxVolumeIndex+numFiberCompartments)->SetPixel(index, 1); } else { double extraAxonalVolume = m_VoxelVolume-intraAxonalVolume; // non-fiber volume if (extraAxonalVolume<0) { MITK_ERROR << "Coorupted intra-axonal signal voxel detected. Fiber volume larger voxel volume!"; extraAxonalVolume = 0; } double interAxonalVolume = 0; if (numFiberCompartments>1) interAxonalVolume = extraAxonalVolume * intraAxonalVolume/m_VoxelVolume; // inter-axonal fraction of non fiber compartment double other = extraAxonalVolume - interAxonalVolume; // rest of compartment if (other<0) { MITK_ERROR << "Coorupted signal voxel detected. Fiber volume larger voxel volume!"; other = 0; } // adjust non-fiber and intra-axonal signal for (int i=1; iGetPixel(index); if (intraAxonalVolume>0) // remove scaling by intra-axonal volume from inter-axonal compartment { if (g>=0) pix[g] /= intraAxonalVolume; else pix /= intraAxonalVolume; } if (m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage()!=nullptr) { -// ItkUcharImgType::IndexType maskIndex; -// m_UpsampledMaskImage->TransformPhysicalPointToIndex(point, maskIndex); -// if (!m_UpsampledMaskImage->GetLargestPossibleRegion().IsInside(maskIndex) || m_UpsampledMaskImage->GetPixel(maskIndex)==0) -// continue; + // ItkUcharImgType::IndexType maskIndex; + // m_UpsampledMaskImage->TransformPhysicalPointToIndex(point, maskIndex); + // if (!m_UpsampledMaskImage->GetLargestPossibleRegion().IsInside(maskIndex) || m_UpsampledMaskImage->GetPixel(maskIndex)==0) + // continue; DoubleDwiType::IndexType newIndex; m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage()->TransformPhysicalPointToIndex(point, newIndex); if (!m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage()->GetLargestPossibleRegion().IsInside(newIndex)) continue; weight = m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage()->GetPixel(newIndex)*m_VoxelVolume; } if (g>=0) pix[g] *= weight; else pix *= weight; m_CompartmentImages.at(i)->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(i)->SetPixel(index, weight/m_VoxelVolume); } for (int i=0; iGetPixel(index); if (m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()!=nullptr) { -// ItkUcharImgType::IndexType maskIndex; -// m_UpsampledMaskImage->TransformPhysicalPointToIndex(point, maskIndex); -// if (!m_UpsampledMaskImage->GetLargestPossibleRegion().IsInside(maskIndex) || m_UpsampledMaskImage->GetPixel(maskIndex)==0) -// continue; + // ItkUcharImgType::IndexType maskIndex; + // m_UpsampledMaskImage->TransformPhysicalPointToIndex(point, maskIndex); + // if (!m_UpsampledMaskImage->GetLargestPossibleRegion().IsInside(maskIndex) || m_UpsampledMaskImage->GetPixel(maskIndex)==0) + // continue; DoubleDwiType::IndexType newIndex; m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()->TransformPhysicalPointToIndex(point, newIndex); if (!m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()->GetLargestPossibleRegion().IsInside(newIndex)) continue; weight = m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()->GetPixel(newIndex)*m_VoxelVolume; + if (m_UseRelativeNonFiberVolumeFractions) + weight *= other/m_VoxelVolume; } if (g>=0) pix[g] += m_Parameters.m_NonFiberModelList[i]->SimulateMeasurement(g)*weight; else pix += m_Parameters.m_NonFiberModelList[i]->SimulateMeasurement()*weight; m_CompartmentImages.at(i+numFiberCompartments)->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(i+numFiberCompartments)->SetPixel(index, weight/m_VoxelVolume); } } } } template< class PixelType > itk::Point TractsToDWIImageFilter< PixelType >::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } template< class PixelType > itk::Vector TractsToDWIImageFilter< PixelType >::GetItkVector(double point[3]) { itk::Vector itkVector; itkVector[0] = point[0]; itkVector[1] = point[1]; itkVector[2] = point[2]; return itkVector; } template< class PixelType > vnl_vector_fixed TractsToDWIImageFilter< PixelType >::GetVnlVector(double point[3]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } template< class PixelType > vnl_vector_fixed TractsToDWIImageFilter< PixelType >::GetVnlVector(Vector& vector) { vnl_vector_fixed vnlVector; vnlVector[0] = vector[0]; vnlVector[1] = vector[1]; vnlVector[2] = vector[2]; return vnlVector; } template< class PixelType > double TractsToDWIImageFilter< PixelType >::RoundToNearest(double num) { return (num > 0.0) ? floor(num + 0.5) : ceil(num - 0.5); } template< class PixelType > std::string TractsToDWIImageFilter< PixelType >::GetTime() { m_TimeProbe.Stop(); unsigned long total = RoundToNearest(m_TimeProbe.GetTotal()); unsigned long hours = total/3600; unsigned long minutes = (total%3600)/60; unsigned long seconds = total%60; std::string out = ""; out.append(boost::lexical_cast(hours)); out.append(":"); out.append(boost::lexical_cast(minutes)); out.append(":"); out.append(boost::lexical_cast(seconds)); m_TimeProbe.Start(); return out; } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h index 7e28f3403a..fd5dcbd8ed 100755 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h @@ -1,140 +1,155 @@ /*=================================================================== 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 __itkTractsToDWIImageFilter_h__ #define __itkTractsToDWIImageFilter_h__ #include #include #include #include #include #include #include #include +#include namespace itk { /** * \brief Generates artificial diffusion weighted image volume from the input fiberbundle using a generic multicompartment model. * See "Fiberfox: Facilitating the creation of realistic white matter software phantoms" (DOI: 10.1002/mrm.25045) for details. */ template< class PixelType > class TractsToDWIImageFilter : public ImageSource< itk::VectorImage< PixelType, 3 > > { public: typedef TractsToDWIImageFilter Self; typedef ImageSource< itk::VectorImage< PixelType, 3 > > Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef typename Superclass::OutputImageType OutputImageType; + typedef itk::Image ItkDoubleImgType4D; typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkFloatImgType; typedef itk::Image ItkUcharImgType; typedef mitk::FiberBundle::Pointer FiberBundleType; typedef itk::VectorImage< double, 3 > DoubleDwiType; + typedef itk::VectorImage< double, 4 > DoubleDwiType4D; typedef itk::Matrix MatrixType; typedef itk::Image< double, 2 > SliceType; typedef itk::VnlForwardFFTImageFilter::OutputImageType ComplexSliceType; + typedef itk::VectorImage< vcl_complex< double >, 3 > ComplexDwiType; typedef itk::Vector< double,3> DoubleVectorType; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( TractsToDWIImageFilter, ImageSource ) /** Input */ itkSetMacro( FiberBundle, FiberBundleType ) ///< Input fiber bundle itkSetMacro( UseConstantRandSeed, bool ) ///< Seed for random generator. void SetParameters( FiberfoxParameters param ) ///< Simulation parameters. { m_Parameters = param; } /** Output */ FiberfoxParameters GetParameters(){ return m_Parameters; } std::vector< ItkDoubleImgType::Pointer > GetVolumeFractions() ///< one double image for each compartment containing the corresponding volume fraction per voxel { return m_VolumeFractions; } mitk::LevelWindow GetLevelWindow(){ return m_LevelWindow; } itkGetMacro( StatusText, std::string ) + itkGetMacro( PhaseImage, DoubleDwiType::Pointer ) + itkGetMacro( KspaceImage, DoubleDwiType::Pointer ) + itkGetMacro( CoilPointset, mitk::PointSet::Pointer ) void GenerateData(); protected: TractsToDWIImageFilter(); virtual ~TractsToDWIImageFilter(); itk::Point GetItkPoint(double point[3]); itk::Vector GetItkVector(double point[3]); vnl_vector_fixed GetVnlVector(double point[3]); vnl_vector_fixed GetVnlVector(Vector< float, 3 >& vector); double RoundToNearest(double num); std::string GetTime(); /** Transform generated image compartment by compartment, channel by channel and slice by slice using DFT and add k-space artifacts. */ - DoubleDwiType::Pointer DoKspaceStuff(std::vector< DoubleDwiType::Pointer >& images); + DoubleDwiType::Pointer SimulateKspaceAcquisition(std::vector< DoubleDwiType::Pointer >& images); /** Generate signal of non-fiber compartments. */ void SimulateExtraAxonalSignal(ItkUcharImgType::IndexType index, double intraAxonalVolume, int g=-1); /** Move fibers to simulate headmotion */ void SimulateMotion(int g=-1); void CheckVolumeFractionImages(); + ItkDoubleImgType::Pointer NormalizeInsideMask(ItkDoubleImgType::Pointer image); void InitializeData(); void InitializeFiberData(); // input mitk::FiberfoxParameters m_Parameters; FiberBundleType m_FiberBundle; // output typename OutputImageType::Pointer m_OutputImage; + typename DoubleDwiType::Pointer m_PhaseImage; + typename DoubleDwiType::Pointer m_KspaceImage; mitk::LevelWindow m_LevelWindow; std::vector< ItkDoubleImgType::Pointer > m_VolumeFractions; std::string m_StatusText; // MISC itk::TimeProbe m_TimeProbe; bool m_UseConstantRandSeed; bool m_MaskImageSet; ofstream m_Logfile; // signal generation FiberBundleType m_FiberBundleWorkingCopy; ///< we work on an upsampled version of the input bundle FiberBundleType m_FiberBundleTransformed; ///< transformed bundle simulating headmotion itk::Vector m_WorkingSpacing; itk::Point m_WorkingOrigin; ImageRegion<3> m_WorkingImageRegion; double m_VoxelVolume; std::vector< DoubleDwiType::Pointer > m_CompartmentImages; - ItkUcharImgType::Pointer m_TransformedMaskImage; ///< copy of mask image (changes for each motion step) + ItkUcharImgType::Pointer m_TransformedMaskImage; ///< copy of mask image (changes for each motion step) ItkUcharImgType::Pointer m_UpsampledMaskImage; ///< helper image for motion simulation DoubleVectorType m_Rotation; DoubleVectorType m_Translation; + std::vector< DoubleVectorType > m_Rotations; /// m_Translations; /// m_CroppedRegion; - double mmRadius; - double segmentVolume; + double m_mmRadius; + double m_SegmentVolume; + bool m_UseRelativeNonFiberVolumeFractions; + mitk::PointSet::Pointer m_CoilPointset; + itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer m_RandGen; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkTractsToDWIImageFilter.cpp" #endif #endif diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp index c10eec78d6..0bddf44ae0 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp @@ -1,723 +1,775 @@ /*=================================================================== 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 +#define RAPIDXML_NO_EXCEPTIONS #include #include - #include #include template< class ScalarType > mitk::FiberfoxParameters< ScalarType >::FiberfoxParameters() : m_NoiseModel(NULL) { } template< class ScalarType > mitk::FiberfoxParameters< ScalarType >::~FiberfoxParameters() { // if (m_NoiseModel!=NULL) // delete m_NoiseModel; } void mitk::SignalGenerationParameters::GenerateGradientHalfShell() { int NPoints = 2*m_NumGradients; m_GradientDirections.clear(); m_NumBaseline = NPoints/20; if (m_NumBaseline==0) m_NumBaseline=1; GradientType g; g.Fill(0.0); for (unsigned int i=0; i theta; theta.set_size(NPoints); vnl_vector phi; phi.set_size(NPoints); double C = sqrt(4*M_PI); phi(0) = 0.0; phi(NPoints-1) = 0.0; for(int i=0; i0 && i mitk::SignalGenerationParameters::GetBaselineIndices() { std::vector< int > result; for( unsigned int i=0; im_GradientDirections.size(); i++) if (m_GradientDirections.at(i).GetNorm()<0.0001) result.push_back(i); return result; } unsigned int mitk::SignalGenerationParameters::GetFirstBaselineIndex() { for( unsigned int i=0; im_GradientDirections.size(); i++) if (m_GradientDirections.at(i).GetNorm()<0.0001) return i; return -1; } bool mitk::SignalGenerationParameters::IsBaselineIndex(unsigned int idx) { if (m_GradientDirections.size()>idx && m_GradientDirections.at(idx).GetNorm()<0.0001) return true; return false; } unsigned int mitk::SignalGenerationParameters::GetNumWeightedVolumes() { return m_NumGradients; } unsigned int mitk::SignalGenerationParameters::GetNumBaselineVolumes() { return m_NumBaseline; } unsigned int mitk::SignalGenerationParameters::GetNumVolumes() { return m_GradientDirections.size(); } mitk::SignalGenerationParameters::GradientListType mitk::SignalGenerationParameters::GetGradientDirections() { return m_GradientDirections; } mitk::SignalGenerationParameters::GradientType mitk::SignalGenerationParameters::GetGradientDirection(unsigned int i) { return m_GradientDirections.at(i); } void mitk::SignalGenerationParameters::SetNumWeightedVolumes(int numGradients) { m_NumGradients = numGradients; GenerateGradientHalfShell(); } void mitk::SignalGenerationParameters::SetGradienDirections(GradientListType gradientList) { m_GradientDirections = gradientList; m_NumGradients = 0; m_NumBaseline = 0; for( unsigned int i=0; im_GradientDirections.size(); i++) { if (m_GradientDirections.at(i).GetNorm()>0.0001) m_NumGradients++; else m_NumBaseline++; } } void mitk::SignalGenerationParameters::SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientList) { m_NumGradients = 0; m_NumBaseline = 0; m_GradientDirections.clear(); for( unsigned int i=0; iSize(); i++) { GradientType g; g[0] = gradientList->at(i)[0]; g[1] = gradientList->at(i)[1]; g[2] = gradientList->at(i)[2]; m_GradientDirections.push_back(g); if (m_GradientDirections.at(i).GetNorm()>0.0001) m_NumGradients++; else m_NumBaseline++; } } template< class ScalarType > void mitk::FiberfoxParameters< ScalarType >::SaveParameters(string filename) { if(filename.empty()) return; if(".ffp"!=filename.substr(filename.size()-4, 4)) filename += ".ffp"; const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, NULL ); if ( locale.compare(currLocale)!=0 ) { - try - { - setlocale(LC_ALL, locale.c_str()); - } - catch(...) - { - MITK_INFO << "Could not set locale " << locale; - } + try + { + setlocale(LC_ALL, locale.c_str()); + } + catch(...) + { + MITK_INFO << "Could not set locale " << locale; + } } boost::property_tree::ptree parameters; // fiber generation parameters parameters.put("fiberfox.fibers.distribution", m_FiberGen.m_Distribution); parameters.put("fiberfox.fibers.variance", m_FiberGen.m_Variance); parameters.put("fiberfox.fibers.density", m_FiberGen.m_Density); parameters.put("fiberfox.fibers.spline.sampling", m_FiberGen.m_Sampling); parameters.put("fiberfox.fibers.spline.tension", m_FiberGen.m_Tension); parameters.put("fiberfox.fibers.spline.continuity", m_FiberGen.m_Continuity); parameters.put("fiberfox.fibers.spline.bias", m_FiberGen.m_Bias); parameters.put("fiberfox.fibers.rotation.x", m_FiberGen.m_Rotation[0]); parameters.put("fiberfox.fibers.rotation.y", m_FiberGen.m_Rotation[1]); parameters.put("fiberfox.fibers.rotation.z", m_FiberGen.m_Rotation[2]); parameters.put("fiberfox.fibers.translation.x", m_FiberGen.m_Translation[0]); parameters.put("fiberfox.fibers.translation.y", m_FiberGen.m_Translation[1]); parameters.put("fiberfox.fibers.translation.z", m_FiberGen.m_Translation[2]); parameters.put("fiberfox.fibers.scale.x", m_FiberGen.m_Scale[0]); parameters.put("fiberfox.fibers.scale.y", m_FiberGen.m_Scale[1]); parameters.put("fiberfox.fibers.scale.z", m_FiberGen.m_Scale[2]); // image generation parameters parameters.put("fiberfox.image.basic.size.x", m_SignalGen.m_ImageRegion.GetSize(0)); parameters.put("fiberfox.image.basic.size.y", m_SignalGen.m_ImageRegion.GetSize(1)); parameters.put("fiberfox.image.basic.size.z", m_SignalGen.m_ImageRegion.GetSize(2)); parameters.put("fiberfox.image.basic.spacing.x", m_SignalGen.m_ImageSpacing[0]); parameters.put("fiberfox.image.basic.spacing.y", m_SignalGen.m_ImageSpacing[1]); parameters.put("fiberfox.image.basic.spacing.z", m_SignalGen.m_ImageSpacing[2]); parameters.put("fiberfox.image.basic.origin.x", m_SignalGen.m_ImageOrigin[0]); parameters.put("fiberfox.image.basic.origin.y", m_SignalGen.m_ImageOrigin[1]); parameters.put("fiberfox.image.basic.origin.z", m_SignalGen.m_ImageOrigin[2]); parameters.put("fiberfox.image.basic.direction.1", m_SignalGen.m_ImageDirection[0][0]); parameters.put("fiberfox.image.basic.direction.2", m_SignalGen.m_ImageDirection[0][1]); parameters.put("fiberfox.image.basic.direction.3", m_SignalGen.m_ImageDirection[0][2]); parameters.put("fiberfox.image.basic.direction.4", m_SignalGen.m_ImageDirection[1][0]); parameters.put("fiberfox.image.basic.direction.5", m_SignalGen.m_ImageDirection[1][1]); parameters.put("fiberfox.image.basic.direction.6", m_SignalGen.m_ImageDirection[1][2]); parameters.put("fiberfox.image.basic.direction.7", m_SignalGen.m_ImageDirection[2][0]); parameters.put("fiberfox.image.basic.direction.8", m_SignalGen.m_ImageDirection[2][1]); parameters.put("fiberfox.image.basic.direction.9", m_SignalGen.m_ImageDirection[2][2]); parameters.put("fiberfox.image.basic.numgradients", m_SignalGen.GetNumWeightedVolumes()); for( unsigned int i=0; im_SignalGen.GetNumVolumes(); i++) { parameters.put("fiberfox.image.gradients."+boost::lexical_cast(i)+".x", m_SignalGen.GetGradientDirection(i)[0]); parameters.put("fiberfox.image.gradients."+boost::lexical_cast(i)+".y", m_SignalGen.GetGradientDirection(i)[1]); parameters.put("fiberfox.image.gradients."+boost::lexical_cast(i)+".z", m_SignalGen.GetGradientDirection(i)[2]); } + parameters.put("fiberfox.image.coilsensitivityprofile", m_SignalGen.m_CoilSensitivityProfile); + parameters.put("fiberfox.image.numberofcoils", m_SignalGen.m_NumberOfCoils); + parameters.put("fiberfox.image.reversephase", m_SignalGen.m_ReversePhase); + parameters.put("fiberfox.image.partialfourier", m_SignalGen.m_PartialFourier); + parameters.put("fiberfox.image.noisevariance", m_SignalGen.m_NoiseVariance); + parameters.put("fiberfox.image.trep", m_SignalGen.m_tRep); parameters.put("fiberfox.image.signalScale", m_SignalGen.m_SignalScale); parameters.put("fiberfox.image.tEcho", m_SignalGen.m_tEcho); parameters.put("fiberfox.image.tLine", m_SignalGen.m_tLine); parameters.put("fiberfox.image.tInhom", m_SignalGen.m_tInhom); parameters.put("fiberfox.image.bvalue", m_SignalGen.m_Bvalue); parameters.put("fiberfox.image.simulatekspace", m_SignalGen.m_SimulateKspaceAcquisition); parameters.put("fiberfox.image.axonRadius", m_SignalGen.m_AxonRadius); parameters.put("fiberfox.image.diffusiondirectionmode", m_SignalGen.m_DiffusionDirectionMode); parameters.put("fiberfox.image.fiberseparationthreshold", m_SignalGen.m_FiberSeparationThreshold); parameters.put("fiberfox.image.doSimulateRelaxation", m_SignalGen.m_DoSimulateRelaxation); parameters.put("fiberfox.image.doDisablePartialVolume", m_SignalGen.m_DoDisablePartialVolume); parameters.put("fiberfox.image.artifacts.spikesnum", m_SignalGen.m_Spikes); parameters.put("fiberfox.image.artifacts.spikesscale", m_SignalGen.m_SpikeAmplitude); parameters.put("fiberfox.image.artifacts.kspaceLineOffset", m_SignalGen.m_KspaceLineOffset); parameters.put("fiberfox.image.artifacts.eddyStrength", m_SignalGen.m_EddyStrength); parameters.put("fiberfox.image.artifacts.eddyTau", m_SignalGen.m_Tau); parameters.put("fiberfox.image.artifacts.aliasingfactor", m_SignalGen.m_CroppingFactor); parameters.put("fiberfox.image.artifacts.addringing", m_SignalGen.m_DoAddGibbsRinging); parameters.put("fiberfox.image.artifacts.doAddMotion", m_SignalGen.m_DoAddMotion); parameters.put("fiberfox.image.artifacts.randomMotion", m_SignalGen.m_DoRandomizeMotion); parameters.put("fiberfox.image.artifacts.translation0", m_SignalGen.m_Translation[0]); parameters.put("fiberfox.image.artifacts.translation1", m_SignalGen.m_Translation[1]); parameters.put("fiberfox.image.artifacts.translation2", m_SignalGen.m_Translation[2]); parameters.put("fiberfox.image.artifacts.rotation0", m_SignalGen.m_Rotation[0]); parameters.put("fiberfox.image.artifacts.rotation1", m_SignalGen.m_Rotation[1]); parameters.put("fiberfox.image.artifacts.rotation2", m_SignalGen.m_Rotation[2]); parameters.put("fiberfox.image.artifacts.addnoise", m_Misc.m_CheckAddNoiseBox); parameters.put("fiberfox.image.artifacts.addghosts", m_Misc.m_CheckAddGhostsBox); parameters.put("fiberfox.image.artifacts.addaliasing", m_Misc.m_CheckAddAliasingBox); parameters.put("fiberfox.image.artifacts.addspikes", m_Misc.m_CheckAddSpikesBox); parameters.put("fiberfox.image.artifacts.addeddycurrents", m_Misc.m_CheckAddEddyCurrentsBox); parameters.put("fiberfox.image.artifacts.doAddDistortions", m_Misc.m_CheckAddDistortionsBox); parameters.put("fiberfox.image.outputvolumefractions", m_Misc.m_CheckOutputVolumeFractionsBox); parameters.put("fiberfox.image.showadvanced", m_Misc.m_CheckAdvancedSignalOptionsBox); parameters.put("fiberfox.image.signalmodelstring", m_Misc.m_SignalModelString); parameters.put("fiberfox.image.artifactmodelstring", m_Misc.m_ArtifactModelString); parameters.put("fiberfox.image.outpath", m_Misc.m_OutputPath); parameters.put("fiberfox.fibers.realtime", m_Misc.m_CheckRealTimeFibersBox); parameters.put("fiberfox.fibers.showadvanced", m_Misc.m_CheckAdvancedFiberOptionsBox); parameters.put("fiberfox.fibers.constantradius", m_Misc.m_CheckConstantRadiusBox); parameters.put("fiberfox.fibers.includeFiducials", m_Misc.m_CheckIncludeFiducialsBox); if (m_NoiseModel!=NULL) { parameters.put("fiberfox.image.artifacts.noisevariance", m_NoiseModel->GetNoiseVariance()); if (dynamic_cast*>(m_NoiseModel)) parameters.put("fiberfox.image.artifacts.noisetype", "rice"); else if (dynamic_cast*>(m_NoiseModel)) parameters.put("fiberfox.image.artifacts.noisetype", "chisquare"); } for (int i=0; i* signalModel = NULL; if (i(i)+".type", "fiber"); } else { signalModel = m_NonFiberModelList.at(i-m_FiberModelList.size()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".type", "non-fiber"); } if (dynamic_cast*>(signalModel)) { mitk::StickModel* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".model", "stick"); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".d", model->GetDiffusivity()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t2", model->GetT2()); + parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t1", model->GetT1()); } else if (dynamic_cast*>(signalModel)) { mitk::TensorModel* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".model", "tensor"); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".d1", model->GetDiffusivity1()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".d2", model->GetDiffusivity2()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".d3", model->GetDiffusivity3()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t2", model->GetT2()); + parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t1", model->GetT1()); } else if (dynamic_cast*>(signalModel)) { mitk::RawShModel* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".model", "prototype"); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".minFA", model->GetFaRange().first); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".maxFA", model->GetFaRange().second); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".minADC", model->GetAdcRange().first); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".maxADC", model->GetAdcRange().second); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".maxNumSamples", model->GetMaxNumKernels()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".numSamples", model->GetNumberOfKernels()); int shOrder = model->GetShOrder(); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".numCoeffs", (shOrder*shOrder + shOrder + 2)/2 + shOrder); for (unsigned int j=0; jGetNumberOfKernels(); j++) { vnl_vector< double > coeffs = model->GetCoefficients(j); for (unsigned int k=0; k(i)+".kernels."+boost::lexical_cast(j)+".coeffs."+boost::lexical_cast(k), coeffs[k]); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".kernels."+boost::lexical_cast(j)+".B0", model->GetBaselineSignal(j)); } } else if (dynamic_cast*>(signalModel)) { mitk::BallModel* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".model", "ball"); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".d", model->GetDiffusivity()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t2", model->GetT2()); + parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t1", model->GetT1()); } else if (dynamic_cast*>(signalModel)) { mitk::AstroStickModel* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".model", "astrosticks"); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".d", model->GetDiffusivity()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t2", model->GetT2()); + parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t1", model->GetT1()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".randomize", model->GetRandomizeSticks()); } else if (dynamic_cast*>(signalModel)) { mitk::DotModel* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".model", "dot"); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t2", model->GetT2()); + parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t1", model->GetT1()); } if (signalModel!=NULL) { parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".ID", signalModel->m_CompartmentId); if (signalModel->GetVolumeFractionImage().IsNotNull()) { try{ itk::ImageFileWriter::Pointer writer = itk::ImageFileWriter::New(); writer->SetFileName(filename+"_VOLUME"+boost::lexical_cast(signalModel->m_CompartmentId)+".nrrd"); writer->SetInput(signalModel->GetVolumeFractionImage()); writer->Update(); MITK_INFO << "Volume fraction image for compartment "+boost::lexical_cast(signalModel->m_CompartmentId)+" saved."; } catch(...) { } } } } boost::property_tree::xml_writer_settings writerSettings(' ', 2); boost::property_tree::xml_parser::write_xml(filename, parameters, std::locale(), writerSettings); try{ itk::ImageFileWriter::Pointer writer = itk::ImageFileWriter::New(); writer->SetFileName(filename+"_FMAP.nrrd"); writer->SetInput(m_SignalGen.m_FrequencyMap); writer->Update(); } catch(...) { MITK_INFO << "No frequency map saved."; } try{ itk::ImageFileWriter::Pointer writer = itk::ImageFileWriter::New(); writer->SetFileName(filename+"_MASK.nrrd"); writer->SetInput(m_SignalGen.m_MaskImage); writer->Update(); } catch(...) { MITK_INFO << "No mask image saved."; } setlocale(LC_ALL, currLocale.c_str()); } + +template< class ScalarType > +template< class ParameterType > +ParameterType mitk::FiberfoxParameters< ScalarType >::ReadVal(boost::property_tree::ptree::value_type const& v, std::string tag, ParameterType defaultValue, bool essential) +{ + try + { + return v.second.get(tag); + } + catch (...) + { + if (essential) + { + mitkThrow() << "Parameter file corrupted. Essential tag is missing: '" << tag << "'"; + } + if (tag!="artifacts.noisetype") + { + MITK_INFO << "Tag '" << tag << "' not found. Using default value '" << defaultValue << "'."; + m_MissingTags += "\n- "; + m_MissingTags += tag; + } + return defaultValue; + } +} + template< class ScalarType > void mitk::FiberfoxParameters< ScalarType >::LoadParameters(string filename) { + m_MissingTags = ""; if(filename.empty()) return; const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, NULL ); if ( locale.compare(currLocale)!=0 ) { - try - { - setlocale(LC_ALL, locale.c_str()); - } - catch(...) - { - MITK_INFO << "Could not set locale " << locale; - } + try + { + setlocale(LC_ALL, locale.c_str()); + } + catch(...) + { + MITK_INFO << "Could not set locale " << locale; + } } + boost::property_tree::ptree parameterTree; boost::property_tree::xml_parser::read_xml(filename, parameterTree); + m_FiberModelList.clear(); m_NonFiberModelList.clear(); if (m_NoiseModel!=NULL) delete m_NoiseModel; BOOST_FOREACH( boost::property_tree::ptree::value_type const& v1, parameterTree.get_child("fiberfox") ) { if( v1.first == "fibers" ) { - m_Misc.m_CheckRealTimeFibersBox = v1.second.get("realtime", m_Misc.m_CheckRealTimeFibersBox); - m_Misc.m_CheckAdvancedFiberOptionsBox = v1.second.get("showadvanced", m_Misc.m_CheckAdvancedFiberOptionsBox); - m_Misc.m_CheckConstantRadiusBox = v1.second.get("constantradius", m_Misc.m_CheckConstantRadiusBox); - m_Misc.m_CheckIncludeFiducialsBox = v1.second.get("includeFiducials", m_Misc.m_CheckIncludeFiducialsBox); + m_Misc.m_CheckRealTimeFibersBox = ReadVal(v1,"realtime", m_Misc.m_CheckRealTimeFibersBox); + m_Misc.m_CheckAdvancedFiberOptionsBox = ReadVal(v1,"showadvanced", m_Misc.m_CheckAdvancedFiberOptionsBox); + m_Misc.m_CheckConstantRadiusBox = ReadVal(v1,"constantradius", m_Misc.m_CheckConstantRadiusBox); + m_Misc.m_CheckIncludeFiducialsBox = ReadVal(v1,"includeFiducials", m_Misc.m_CheckIncludeFiducialsBox); - switch (v1.second.get("distribution", 0)) + switch (ReadVal(v1,"distribution", 0)) { case 0: m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; break; case 1: m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_GAUSSIAN; break; default: m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; } - m_FiberGen.m_Variance = v1.second.get("variance", m_FiberGen.m_Variance); - m_FiberGen.m_Density = v1.second.get("density", m_FiberGen.m_Density); - m_FiberGen.m_Sampling = v1.second.get("spline.sampling", m_FiberGen.m_Sampling); - m_FiberGen.m_Tension = v1.second.get("spline.tension", m_FiberGen.m_Tension); - m_FiberGen.m_Continuity = v1.second.get("spline.continuity", m_FiberGen.m_Continuity); - m_FiberGen.m_Bias = v1.second.get("spline.bias", m_FiberGen.m_Bias); - m_FiberGen.m_Rotation[0] = v1.second.get("rotation.x", m_FiberGen.m_Rotation[0]); - m_FiberGen.m_Rotation[1] = v1.second.get("rotation.y", m_FiberGen.m_Rotation[1]); - m_FiberGen.m_Rotation[2] = v1.second.get("rotation.z", m_FiberGen.m_Rotation[2]); - m_FiberGen.m_Translation[0] = v1.second.get("translation.x", m_FiberGen.m_Translation[0]); - m_FiberGen.m_Translation[1] = v1.second.get("translation.y", m_FiberGen.m_Translation[1]); - m_FiberGen.m_Translation[2] = v1.second.get("translation.z", m_FiberGen.m_Translation[2]); - m_FiberGen.m_Scale[0] = v1.second.get("scale.x", m_FiberGen.m_Scale[0]); - m_FiberGen.m_Scale[1] = v1.second.get("scale.y", m_FiberGen.m_Scale[1]); - m_FiberGen.m_Scale[2] = v1.second.get("scale.z", m_FiberGen.m_Scale[2]); + m_FiberGen.m_Variance = ReadVal(v1,"variance", m_FiberGen.m_Variance); + m_FiberGen.m_Density = ReadVal(v1,"density", m_FiberGen.m_Density); + m_FiberGen.m_Sampling = ReadVal(v1,"spline.sampling", m_FiberGen.m_Sampling); + m_FiberGen.m_Tension = ReadVal(v1,"spline.tension", m_FiberGen.m_Tension); + m_FiberGen.m_Continuity = ReadVal(v1,"spline.continuity", m_FiberGen.m_Continuity); + m_FiberGen.m_Bias = ReadVal(v1,"spline.bias", m_FiberGen.m_Bias); + m_FiberGen.m_Rotation[0] = ReadVal(v1,"rotation.x", m_FiberGen.m_Rotation[0]); + m_FiberGen.m_Rotation[1] = ReadVal(v1,"rotation.y", m_FiberGen.m_Rotation[1]); + m_FiberGen.m_Rotation[2] = ReadVal(v1,"rotation.z", m_FiberGen.m_Rotation[2]); + m_FiberGen.m_Translation[0] = ReadVal(v1,"translation.x", m_FiberGen.m_Translation[0]); + m_FiberGen.m_Translation[1] = ReadVal(v1,"translation.y", m_FiberGen.m_Translation[1]); + m_FiberGen.m_Translation[2] = ReadVal(v1,"translation.z", m_FiberGen.m_Translation[2]); + m_FiberGen.m_Scale[0] = ReadVal(v1,"scale.x", m_FiberGen.m_Scale[0]); + m_FiberGen.m_Scale[1] = ReadVal(v1,"scale.y", m_FiberGen.m_Scale[1]); + m_FiberGen.m_Scale[2] = ReadVal(v1,"scale.z", m_FiberGen.m_Scale[2]); } else if ( v1.first == "image" ) { - m_Misc.m_SignalModelString = v1.second.get("signalmodelstring", m_Misc.m_SignalModelString); - m_Misc.m_ArtifactModelString = v1.second.get("artifactmodelstring", m_Misc.m_ArtifactModelString); - m_Misc.m_OutputPath = v1.second.get("outpath", m_Misc.m_OutputPath); - m_Misc.m_CheckOutputVolumeFractionsBox = v1.second.get("outputvolumefractions", m_Misc.m_CheckOutputVolumeFractionsBox); - m_Misc.m_CheckAdvancedSignalOptionsBox = v1.second.get("showadvanced", m_Misc.m_CheckAdvancedSignalOptionsBox); - m_Misc.m_CheckAddDistortionsBox = v1.second.get("artifacts.doAddDistortions", m_Misc.m_CheckAddDistortionsBox); - m_Misc.m_CheckAddNoiseBox = v1.second.get("artifacts.addnoise", m_Misc.m_CheckAddNoiseBox); - m_Misc.m_CheckAddGhostsBox = v1.second.get("artifacts.addghosts", m_Misc.m_CheckAddGhostsBox); - m_Misc.m_CheckAddAliasingBox = v1.second.get("artifacts.addaliasing", m_Misc.m_CheckAddAliasingBox); - m_Misc.m_CheckAddSpikesBox = v1.second.get("artifacts.addspikes", m_Misc.m_CheckAddSpikesBox); - m_Misc.m_CheckAddEddyCurrentsBox = v1.second.get("artifacts.addeddycurrents", m_Misc.m_CheckAddEddyCurrentsBox); - - m_SignalGen.m_ImageRegion.SetSize(0, v1.second.get("basic.size.x",m_SignalGen.m_ImageRegion.GetSize(0))); - m_SignalGen.m_ImageRegion.SetSize(1, v1.second.get("basic.size.y",m_SignalGen.m_ImageRegion.GetSize(1))); - m_SignalGen.m_ImageRegion.SetSize(2, v1.second.get("basic.size.z",m_SignalGen.m_ImageRegion.GetSize(2))); - m_SignalGen.m_ImageSpacing[0] = v1.second.get("basic.spacing.x",m_SignalGen.m_ImageSpacing[0]); - m_SignalGen.m_ImageSpacing[1] = v1.second.get("basic.spacing.y",m_SignalGen.m_ImageSpacing[1]); - m_SignalGen.m_ImageSpacing[2] = v1.second.get("basic.spacing.z",m_SignalGen.m_ImageSpacing[2]); - m_SignalGen.m_ImageOrigin[0] = v1.second.get("basic.origin.x",m_SignalGen.m_ImageOrigin[0]); - m_SignalGen.m_ImageOrigin[1] = v1.second.get("basic.origin.y",m_SignalGen.m_ImageOrigin[1]); - m_SignalGen.m_ImageOrigin[2] = v1.second.get("basic.origin.z",m_SignalGen.m_ImageOrigin[2]); - m_SignalGen.m_ImageDirection[0][0] = v1.second.get("basic.direction.1",m_SignalGen.m_ImageDirection[0][0]); - m_SignalGen.m_ImageDirection[0][1] = v1.second.get("basic.direction.2",m_SignalGen.m_ImageDirection[0][1]); - m_SignalGen.m_ImageDirection[0][2] = v1.second.get("basic.direction.3",m_SignalGen.m_ImageDirection[0][2]); - m_SignalGen.m_ImageDirection[1][0] = v1.second.get("basic.direction.4",m_SignalGen.m_ImageDirection[1][0]); - m_SignalGen.m_ImageDirection[1][1] = v1.second.get("basic.direction.5",m_SignalGen.m_ImageDirection[1][1]); - m_SignalGen.m_ImageDirection[1][2] = v1.second.get("basic.direction.6",m_SignalGen.m_ImageDirection[1][2]); - m_SignalGen.m_ImageDirection[2][0] = v1.second.get("basic.direction.7",m_SignalGen.m_ImageDirection[2][0]); - m_SignalGen.m_ImageDirection[2][1] = v1.second.get("basic.direction.8",m_SignalGen.m_ImageDirection[2][1]); - m_SignalGen.m_ImageDirection[2][2] = v1.second.get("basic.direction.9",m_SignalGen.m_ImageDirection[2][2]); - - m_SignalGen.m_SignalScale = v1.second.get("signalScale", m_SignalGen.m_SignalScale); - m_SignalGen.m_tEcho = v1.second.get("tEcho", m_SignalGen.m_tEcho); - m_SignalGen.m_tLine = v1.second.get("tLine", m_SignalGen.m_tLine); - m_SignalGen.m_tInhom = v1.second.get("tInhom", m_SignalGen.m_tInhom); - m_SignalGen.m_Bvalue = v1.second.get("bvalue", m_SignalGen.m_Bvalue); - m_SignalGen.m_SimulateKspaceAcquisition = v1.second.get("simulatekspace", m_SignalGen.m_SimulateKspaceAcquisition); - - m_SignalGen.m_AxonRadius = v1.second.get("axonRadius", m_SignalGen.m_AxonRadius); - switch (v1.second.get("diffusiondirectionmode", 0)) + m_Misc.m_SignalModelString = ReadVal(v1,"signalmodelstring", m_Misc.m_SignalModelString); + m_Misc.m_ArtifactModelString = ReadVal(v1,"artifactmodelstring", m_Misc.m_ArtifactModelString); + m_Misc.m_OutputPath = ReadVal(v1,"outpath", m_Misc.m_OutputPath); + m_Misc.m_CheckOutputVolumeFractionsBox = ReadVal(v1,"outputvolumefractions", m_Misc.m_CheckOutputVolumeFractionsBox); + m_Misc.m_CheckAdvancedSignalOptionsBox = ReadVal(v1,"showadvanced", m_Misc.m_CheckAdvancedSignalOptionsBox); + m_Misc.m_CheckAddDistortionsBox = ReadVal(v1,"artifacts.doAddDistortions", m_Misc.m_CheckAddDistortionsBox); + m_Misc.m_CheckAddNoiseBox = ReadVal(v1,"artifacts.addnoise", m_Misc.m_CheckAddNoiseBox); + m_Misc.m_CheckAddGhostsBox = ReadVal(v1,"artifacts.addghosts", m_Misc.m_CheckAddGhostsBox); + m_Misc.m_CheckAddAliasingBox = ReadVal(v1,"artifacts.addaliasing", m_Misc.m_CheckAddAliasingBox); + m_Misc.m_CheckAddSpikesBox = ReadVal(v1,"artifacts.addspikes", m_Misc.m_CheckAddSpikesBox); + m_Misc.m_CheckAddEddyCurrentsBox = ReadVal(v1,"artifacts.addeddycurrents", m_Misc.m_CheckAddEddyCurrentsBox); + + m_SignalGen.m_ImageRegion.SetSize(0, ReadVal(v1,"basic.size.x",m_SignalGen.m_ImageRegion.GetSize(0))); + m_SignalGen.m_ImageRegion.SetSize(1, ReadVal(v1,"basic.size.y",m_SignalGen.m_ImageRegion.GetSize(1))); + m_SignalGen.m_ImageRegion.SetSize(2, ReadVal(v1,"basic.size.z",m_SignalGen.m_ImageRegion.GetSize(2))); + m_SignalGen.m_ImageSpacing[0] = ReadVal(v1,"basic.spacing.x",m_SignalGen.m_ImageSpacing[0]); + m_SignalGen.m_ImageSpacing[1] = ReadVal(v1,"basic.spacing.y",m_SignalGen.m_ImageSpacing[1]); + m_SignalGen.m_ImageSpacing[2] = ReadVal(v1,"basic.spacing.z",m_SignalGen.m_ImageSpacing[2]); + m_SignalGen.m_ImageOrigin[0] = ReadVal(v1,"basic.origin.x",m_SignalGen.m_ImageOrigin[0]); + m_SignalGen.m_ImageOrigin[1] = ReadVal(v1,"basic.origin.y",m_SignalGen.m_ImageOrigin[1]); + m_SignalGen.m_ImageOrigin[2] = ReadVal(v1,"basic.origin.z",m_SignalGen.m_ImageOrigin[2]); + m_SignalGen.m_ImageDirection[0][0] = ReadVal(v1,"basic.direction.1",m_SignalGen.m_ImageDirection[0][0]); + m_SignalGen.m_ImageDirection[0][1] = ReadVal(v1,"basic.direction.2",m_SignalGen.m_ImageDirection[0][1]); + m_SignalGen.m_ImageDirection[0][2] = ReadVal(v1,"basic.direction.3",m_SignalGen.m_ImageDirection[0][2]); + m_SignalGen.m_ImageDirection[1][0] = ReadVal(v1,"basic.direction.4",m_SignalGen.m_ImageDirection[1][0]); + m_SignalGen.m_ImageDirection[1][1] = ReadVal(v1,"basic.direction.5",m_SignalGen.m_ImageDirection[1][1]); + m_SignalGen.m_ImageDirection[1][2] = ReadVal(v1,"basic.direction.6",m_SignalGen.m_ImageDirection[1][2]); + m_SignalGen.m_ImageDirection[2][0] = ReadVal(v1,"basic.direction.7",m_SignalGen.m_ImageDirection[2][0]); + m_SignalGen.m_ImageDirection[2][1] = ReadVal(v1,"basic.direction.8",m_SignalGen.m_ImageDirection[2][1]); + m_SignalGen.m_ImageDirection[2][2] = ReadVal(v1,"basic.direction.9",m_SignalGen.m_ImageDirection[2][2]); + + m_SignalGen.m_CoilSensitivityProfile = (SignalGenerationParameters::CoilSensitivityProfile)ReadVal(v1,"coilsensitivityprofile", m_SignalGen.m_CoilSensitivityProfile); + m_SignalGen.m_NumberOfCoils = ReadVal(v1,"numberofcoils", m_SignalGen.m_NumberOfCoils); + m_SignalGen.m_ReversePhase = ReadVal(v1,"reversephase", m_SignalGen.m_ReversePhase); + m_SignalGen.m_PartialFourier = ReadVal(v1,"partialfourier", m_SignalGen.m_PartialFourier); + m_SignalGen.m_NoiseVariance = ReadVal(v1,"noisevariance", m_SignalGen.m_NoiseVariance); + m_SignalGen.m_tRep = ReadVal(v1,"trep", m_SignalGen.m_tRep); + m_SignalGen.m_SignalScale = ReadVal(v1,"signalScale", m_SignalGen.m_SignalScale); + m_SignalGen.m_tEcho = ReadVal(v1,"tEcho", m_SignalGen.m_tEcho); + m_SignalGen.m_tLine = ReadVal(v1,"tLine", m_SignalGen.m_tLine); + m_SignalGen.m_tInhom = ReadVal(v1,"tInhom", m_SignalGen.m_tInhom); + m_SignalGen.m_Bvalue = ReadVal(v1,"bvalue", m_SignalGen.m_Bvalue); + m_SignalGen.m_SimulateKspaceAcquisition = ReadVal(v1,"simulatekspace", m_SignalGen.m_SimulateKspaceAcquisition); + + m_SignalGen.m_AxonRadius = ReadVal(v1,"axonRadius", m_SignalGen.m_AxonRadius); + switch (ReadVal(v1,"diffusiondirectionmode", 0)) { case 0: m_SignalGen.m_DiffusionDirectionMode = SignalGenerationParameters::FIBER_TANGENT_DIRECTIONS; break; case 1: m_SignalGen.m_DiffusionDirectionMode = SignalGenerationParameters::MAIN_FIBER_DIRECTIONS; break; case 2: m_SignalGen.m_DiffusionDirectionMode = SignalGenerationParameters::RANDOM_DIRECTIONS; break; default: m_SignalGen.m_DiffusionDirectionMode = SignalGenerationParameters::FIBER_TANGENT_DIRECTIONS; } - m_SignalGen.m_FiberSeparationThreshold = v1.second.get("fiberseparationthreshold", m_SignalGen.m_FiberSeparationThreshold); - m_SignalGen.m_Spikes = v1.second.get("artifacts.spikesnum", m_SignalGen.m_Spikes); - m_SignalGen.m_SpikeAmplitude = v1.second.get("artifacts.spikesscale", m_SignalGen.m_SpikeAmplitude); - m_SignalGen.m_KspaceLineOffset = v1.second.get("artifacts.kspaceLineOffset", m_SignalGen.m_KspaceLineOffset); - m_SignalGen.m_EddyStrength = v1.second.get("artifacts.eddyStrength", m_SignalGen.m_EddyStrength); - m_SignalGen.m_Tau = v1.second.get("artifacts.eddyTau", m_SignalGen.m_Tau); - m_SignalGen.m_CroppingFactor = v1.second.get("artifacts.aliasingfactor", m_SignalGen.m_CroppingFactor); - m_SignalGen.m_DoAddGibbsRinging = v1.second.get("artifacts.addringing", m_SignalGen.m_DoAddGibbsRinging); - m_SignalGen.m_DoSimulateRelaxation = v1.second.get("doSimulateRelaxation", m_SignalGen.m_DoSimulateRelaxation); - m_SignalGen.m_DoDisablePartialVolume = v1.second.get("doDisablePartialVolume", m_SignalGen.m_DoDisablePartialVolume); - m_SignalGen.m_DoAddMotion = v1.second.get("artifacts.doAddMotion", m_SignalGen.m_DoAddMotion); - m_SignalGen.m_DoRandomizeMotion = v1.second.get("artifacts.randomMotion", m_SignalGen.m_DoRandomizeMotion); - m_SignalGen.m_Translation[0] = v1.second.get("artifacts.translation0", m_SignalGen.m_Translation[0]); - m_SignalGen.m_Translation[1] = v1.second.get("artifacts.translation1", m_SignalGen.m_Translation[1]); - m_SignalGen.m_Translation[2] = v1.second.get("artifacts.translation2", m_SignalGen.m_Translation[2]); - m_SignalGen.m_Rotation[0] = v1.second.get("artifacts.rotation0", m_SignalGen.m_Rotation[0]); - m_SignalGen.m_Rotation[1] = v1.second.get("artifacts.rotation1", m_SignalGen.m_Rotation[1]); - m_SignalGen.m_Rotation[2] = v1.second.get("artifacts.rotation2", m_SignalGen.m_Rotation[2]); -// m_SignalGen.SetNumWeightedVolumes(v1.second.get("numgradients", m_SignalGen.GetNumWeightedVolumes())); + m_SignalGen.m_FiberSeparationThreshold = ReadVal(v1,"fiberseparationthreshold", m_SignalGen.m_FiberSeparationThreshold); + m_SignalGen.m_Spikes = ReadVal(v1,"artifacts.spikesnum", m_SignalGen.m_Spikes); + m_SignalGen.m_SpikeAmplitude = ReadVal(v1,"artifacts.spikesscale", m_SignalGen.m_SpikeAmplitude); + m_SignalGen.m_KspaceLineOffset = ReadVal(v1,"artifacts.kspaceLineOffset", m_SignalGen.m_KspaceLineOffset); + m_SignalGen.m_EddyStrength = ReadVal(v1,"artifacts.eddyStrength", m_SignalGen.m_EddyStrength); + m_SignalGen.m_Tau = ReadVal(v1,"artifacts.eddyTau", m_SignalGen.m_Tau); + m_SignalGen.m_CroppingFactor = ReadVal(v1,"artifacts.aliasingfactor", m_SignalGen.m_CroppingFactor); + m_SignalGen.m_DoAddGibbsRinging = ReadVal(v1,"artifacts.addringing", m_SignalGen.m_DoAddGibbsRinging); + m_SignalGen.m_DoSimulateRelaxation = ReadVal(v1,"doSimulateRelaxation", m_SignalGen.m_DoSimulateRelaxation); + m_SignalGen.m_DoDisablePartialVolume = ReadVal(v1,"doDisablePartialVolume", m_SignalGen.m_DoDisablePartialVolume); + m_SignalGen.m_DoAddMotion = ReadVal(v1,"artifacts.doAddMotion", m_SignalGen.m_DoAddMotion); + m_SignalGen.m_DoRandomizeMotion = ReadVal(v1,"artifacts.randomMotion", m_SignalGen.m_DoRandomizeMotion); + m_SignalGen.m_Translation[0] = ReadVal(v1,"artifacts.translation0", m_SignalGen.m_Translation[0]); + m_SignalGen.m_Translation[1] = ReadVal(v1,"artifacts.translation1", m_SignalGen.m_Translation[1]); + m_SignalGen.m_Translation[2] = ReadVal(v1,"artifacts.translation2", m_SignalGen.m_Translation[2]); + m_SignalGen.m_Rotation[0] = ReadVal(v1,"artifacts.rotation0", m_SignalGen.m_Rotation[0]); + m_SignalGen.m_Rotation[1] = ReadVal(v1,"artifacts.rotation1", m_SignalGen.m_Rotation[1]); + m_SignalGen.m_Rotation[2] = ReadVal(v1,"artifacts.rotation2", m_SignalGen.m_Rotation[2]); + // m_SignalGen.SetNumWeightedVolumes(ReadVal(v1,"numgradients", m_SignalGen.GetNumWeightedVolumes())); SignalGenerationParameters::GradientListType gradients; BOOST_FOREACH( boost::property_tree::ptree::value_type const& v2, v1.second.get_child("gradients") ) { SignalGenerationParameters::GradientType g; - g[0] = v2.second.get("x"); - g[1] = v2.second.get("y"); - g[2] = v2.second.get("z"); + g[0] = ReadVal(v2,"x",0); + g[1] = ReadVal(v2,"y",0); + g[2] = ReadVal(v2,"z",0); gradients.push_back(g); } m_SignalGen.SetGradienDirections(gradients); try { - if (v1.second.get("artifacts.noisetype")=="rice") + if (ReadVal(v1,"artifacts.noisetype","")=="rice") { m_NoiseModel = new mitk::RicianNoiseModel(); - m_NoiseModel->SetNoiseVariance(v1.second.get("artifacts.noisevariance")); + m_NoiseModel->SetNoiseVariance(ReadVal(v1,"artifacts.noisevariance",m_NoiseModel->GetNoiseVariance())); } } catch(...) {} try { - if (v1.second.get("artifacts.noisetype")=="chisquare") + if (ReadVal(v1,"artifacts.noisetype","")=="chisquare") { m_NoiseModel = new mitk::ChiSquareNoiseModel(); - m_NoiseModel->SetNoiseVariance(v1.second.get("artifacts.noisevariance")); + m_NoiseModel->SetNoiseVariance(ReadVal(v1,"artifacts.noisevariance",m_NoiseModel->GetNoiseVariance())); } } catch(...){ } BOOST_FOREACH( boost::property_tree::ptree::value_type const& v2, v1.second.get_child("compartments") ) { mitk::DiffusionSignalModel* signalModel = NULL; - std::string model = v2.second.get("model"); + std::string model = ReadVal(v2,"model","",true); if (model=="stick") { mitk::StickModel* model = new mitk::StickModel(); - model->SetDiffusivity(v2.second.get("d")); - model->SetT2(v2.second.get("t2")); - model->m_CompartmentId = v2.second.get("ID"); - if (v2.second.get("type")=="fiber") + model->SetDiffusivity(ReadVal(v2,"d",model->GetDiffusivity())); + model->SetT2(ReadVal(v2,"t2",model->GetT2())); + model->SetT1(ReadVal(v2,"t1",model->GetT1())); + model->m_CompartmentId = ReadVal(v2,"ID",0,true); + if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); - else if (v2.second.get("type")=="non-fiber") + else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="tensor") { mitk::TensorModel* model = new mitk::TensorModel(); - model->SetDiffusivity1(v2.second.get("d1")); - model->SetDiffusivity2(v2.second.get("d2")); - model->SetDiffusivity3(v2.second.get("d3")); - model->SetT2(v2.second.get("t2")); - model->m_CompartmentId = v2.second.get("ID"); - if (v2.second.get("type")=="fiber") + model->SetDiffusivity1(ReadVal(v2,"d1",model->GetDiffusivity1())); + model->SetDiffusivity2(ReadVal(v2,"d2",model->GetDiffusivity2())); + model->SetDiffusivity3(ReadVal(v2,"d3",model->GetDiffusivity3())); + model->SetT2(ReadVal(v2,"t2",model->GetT2())); + model->SetT1(ReadVal(v2,"t1",model->GetT1())); + model->m_CompartmentId = ReadVal(v2,"ID",0,true); + if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); - else if (v2.second.get("type")=="non-fiber") + else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="ball") { mitk::BallModel* model = new mitk::BallModel(); - model->SetDiffusivity(v2.second.get("d")); - model->SetT2(v2.second.get("t2")); - model->m_CompartmentId = v2.second.get("ID"); - if (v2.second.get("type")=="fiber") + model->SetDiffusivity(ReadVal(v2,"d",model->GetDiffusivity())); + model->SetT2(ReadVal(v2,"t2",model->GetT2())); + model->SetT1(ReadVal(v2,"t1",model->GetT1())); + model->m_CompartmentId = ReadVal(v2,"ID",0,true); + if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); - else if (v2.second.get("type")=="non-fiber") + else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="astrosticks") { mitk::AstroStickModel* model = new AstroStickModel(); - model->SetDiffusivity(v2.second.get("d")); - model->SetT2(v2.second.get("t2")); - model->SetRandomizeSticks(v2.second.get("randomize")); - model->m_CompartmentId = v2.second.get("ID"); - if (v2.second.get("type")=="fiber") + model->SetDiffusivity(ReadVal(v2,"d",model->GetDiffusivity())); + model->SetT2(ReadVal(v2,"t2",model->GetT2())); + model->SetT1(ReadVal(v2,"t1",model->GetT1())); + model->SetRandomizeSticks(ReadVal(v2,"randomize",model->GetRandomizeSticks())); + model->m_CompartmentId = ReadVal(v2,"ID",0,true); + if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); - else if (v2.second.get("type")=="non-fiber") + else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="dot") { mitk::DotModel* model = new mitk::DotModel(); - model->SetT2(v2.second.get("t2")); - model->m_CompartmentId = v2.second.get("ID"); - if (v2.second.get("type")=="fiber") + model->SetT2(ReadVal(v2,"t2",model->GetT2())); + model->SetT1(ReadVal(v2,"t1",model->GetT1())); + model->m_CompartmentId = ReadVal(v2,"ID",0,true); + if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); - else if (v2.second.get("type")=="non-fiber") + else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="prototype") { mitk::RawShModel* model = new mitk::RawShModel(); - model->SetMaxNumKernels(v2.second.get("maxNumSamples")); - model->SetFaRange(v2.second.get("minFA"), v2.second.get("maxFA")); - model->SetAdcRange(v2.second.get("minADC"), v2.second.get("maxADC")); - model->m_CompartmentId = v2.second.get("ID"); - unsigned int numCoeffs = v2.second.get("numCoeffs"); - unsigned int numSamples = v2.second.get("numSamples"); + model->SetMaxNumKernels(ReadVal(v2,"maxNumSamples",model->GetMaxNumKernels())); + model->SetFaRange(ReadVal(v2,"minFA",model->GetFaRange().first), ReadVal(v2,"maxFA",model->GetFaRange().second)); + model->SetAdcRange(ReadVal(v2,"minADC",model->GetAdcRange().first), ReadVal(v2,"maxADC",model->GetAdcRange().second)); + model->m_CompartmentId = ReadVal(v2,"ID",0,true); + unsigned int numCoeffs = ReadVal(v2,"numCoeffs",0,true); + unsigned int numSamples = ReadVal(v2,"numSamples",0,true); for (unsigned int j=0; j coeffs(numCoeffs); for (unsigned int k=0; k("kernels."+boost::lexical_cast(j)+".coeffs."+boost::lexical_cast(k)); + coeffs[k] = ReadVal(v2,"kernels."+boost::lexical_cast(j)+".coeffs."+boost::lexical_cast(k),0,true); } - model->SetShCoefficients( coeffs, v2.second.get("kernels."+boost::lexical_cast(j)+".B0") ); + model->SetShCoefficients( coeffs, ReadVal(v2,"kernels."+boost::lexical_cast(j)+".B0",0,true) ); } - if (v2.second.get("type")=="fiber") + if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); - else if (v2.second.get("type")=="non-fiber") + else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } if (signalModel!=NULL) { signalModel->SetGradientList(gradients); try{ itk::ImageFileReader::Pointer reader = itk::ImageFileReader::New(); - reader->SetFileName(filename+"_VOLUME"+v2.second.get("ID")+".nrrd"); + reader->SetFileName(filename+"_VOLUME"+ReadVal(v2,"ID","")+".nrrd"); reader->Update(); signalModel->SetVolumeFractionImage(reader->GetOutput()); + MITK_INFO << "Volume fraction image loaded for compartment " << signalModel->m_CompartmentId; } catch(...) { + MITK_INFO << "No volume fraction image found for compartment " << signalModel->m_CompartmentId; } } } } } try{ itk::ImageFileReader::Pointer reader = itk::ImageFileReader::New(); reader->SetFileName(filename+"_FMAP.nrrd"); reader->Update(); m_SignalGen.m_FrequencyMap = reader->GetOutput(); + MITK_INFO << "Frequency map loaded."; } catch(...) { - MITK_INFO << "No frequency map saved."; + MITK_INFO << "No frequency map found."; } try{ itk::ImageFileReader::Pointer reader = itk::ImageFileReader::New(); reader->SetFileName(filename+"_MASK.nrrd"); reader->Update(); m_SignalGen.m_MaskImage = reader->GetOutput(); + MITK_INFO << "Mask image loaded."; } catch(...) { - MITK_INFO << "No mask image saved."; + MITK_INFO << "No mask image found."; } setlocale(LC_ALL, currLocale.c_str()); } template< class ScalarType > void mitk::FiberfoxParameters< ScalarType >::PrintSelf() { MITK_INFO << "Not implemented :("; } diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.h b/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.h index 4f43a70a78..2e4c6921e3 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.h +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.h @@ -1,325 +1,344 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_FiberfoxParameters_H #define _MITK_FiberfoxParameters_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include +#include using namespace std; namespace mitk { /** Signal generation */ class SignalGenerationParameters { public: typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkUcharImgType; typedef itk::Vector GradientType; typedef std::vector GradientListType; enum DiffusionDirectionMode { FIBER_TANGENT_DIRECTIONS, MAIN_FIBER_DIRECTIONS, RANDOM_DIRECTIONS }; + enum CoilSensitivityProfile : int { + COIL_CONSTANT, + COIL_LINEAR, + COIL_EXPONENTIAL + }; + SignalGenerationParameters() : m_SignalScale(100) , m_tEcho(100) - , m_tRep(500) + , m_tRep(4000) , m_tLine(1) , m_tInhom(50) , m_ReversePhase(false) + , m_PartialFourier(1.0) + , m_NoiseVariance(0.001) + , m_NumberOfCoils(1) + , m_CoilSensitivityProfile(SignalGenerationParameters::COIL_CONSTANT) , m_Bvalue(1000) , m_SimulateKspaceAcquisition(false) , m_AxonRadius(0) , m_DoDisablePartialVolume(false) , m_DiffusionDirectionMode(SignalGenerationParameters::FIBER_TANGENT_DIRECTIONS) , m_FiberSeparationThreshold(30) , m_Spikes(0) , m_SpikeAmplitude(1) , m_KspaceLineOffset(0) - , m_EddyStrength(0) + , m_EddyStrength(300) , m_Tau(70) , m_CroppingFactor(1) , m_DoAddGibbsRinging(false) , m_DoSimulateRelaxation(true) , m_DoAddMotion(false) , m_DoRandomizeMotion(true) , m_FrequencyMap(NULL) , m_MaskImage(NULL) { m_ImageRegion.SetSize(0, 12); m_ImageRegion.SetSize(1, 12); m_ImageRegion.SetSize(2, 3); m_ImageSpacing.Fill(2.0); m_ImageOrigin.Fill(0.0); m_ImageDirection.SetIdentity(); m_Translation.Fill(0.0); m_Rotation.Fill(0.0); SetNumWeightedVolumes(6); } /** input/output image specifications */ itk::ImageRegion<3> m_ImageRegion; ///< Image size. itk::Vector m_ImageSpacing; ///< Image voxel size. itk::Point m_ImageOrigin; ///< Image origin. itk::Matrix m_ImageDirection; ///< Image rotation matrix. /** Other acquisitions parameters */ double m_SignalScale; ///< Scaling factor for output signal (before noise is added). double m_tEcho; ///< Echo time TE. double m_tRep; ///< Echo time TR. double m_tLine; ///< k-space line readout time (dwell time). double m_tInhom; ///< T2' bool m_ReversePhase; ///< If true, the phase readout direction will be inverted (-y instead of y) + double m_PartialFourier; ///< Partial fourier factor (0.5-1) + double m_NoiseVariance; ///< Variance of complex gaussian noise + int m_NumberOfCoils; ///< Number of coils in multi-coil acquisition + CoilSensitivityProfile m_CoilSensitivityProfile; ///< Choose between constant, linear or exponential sensitivity profile of the used coils double m_Bvalue; ///< Acquisition b-value bool m_SimulateKspaceAcquisition;///< Flag to enable/disable k-space acquisition simulation double m_AxonRadius; ///< Determines compartment volume fractions (0 == automatic axon radius estimation) bool m_DoDisablePartialVolume; ///< Disable partial volume effects. Each voxel is either all fiber or all non-fiber. DiffusionDirectionMode m_DiffusionDirectionMode; ///< Determines how the main diffusion direction of the signal models is selected double m_FiberSeparationThreshold; ///< Used for random and and mein fiber deriction DiffusionDirectionMode /** Artifacts and other effects */ unsigned int m_Spikes; ///< Number of spikes randomly appearing in the image double m_SpikeAmplitude; ///< amplitude of spikes relative to the largest signal intensity (magnitude of complex) double m_KspaceLineOffset; ///< Causes N/2 ghosts. Larger offset means stronger ghost. double m_EddyStrength; ///< Strength of eddy current induced gradients in mT/m. double m_Tau; ///< Eddy current decay constant (in ms) double m_CroppingFactor; ///< FOV size in y-direction is multiplied by this factor. Causes aliasing artifacts. bool m_DoAddGibbsRinging; ///< Add Gibbs ringing artifact bool m_DoSimulateRelaxation; ///< Add T2 relaxation effects bool m_DoAddMotion; ///< Enable motion artifacts. bool m_DoRandomizeMotion; ///< Toggles between random and linear motion. itk::Vector m_Translation; ///< Maximum translational motion. itk::Vector m_Rotation; ///< Maximum rotational motion. ItkDoubleImgType::Pointer m_FrequencyMap; ///< If != NULL, distortions are added to the image using this frequency map. ItkUcharImgType::Pointer m_MaskImage; ///< Signal is only genrated inside of the mask image. inline void GenerateGradientHalfShell(); ///< Generates half shell of gradient directions (with m_NumGradients non-zero directions) inline std::vector< int > GetBaselineIndices(); ///< Returns list of nun-diffusion-weighted image volume indices inline unsigned int GetFirstBaselineIndex(); ///< Returns index of first non-diffusion-weighted image volume inline bool IsBaselineIndex(unsigned int idx); ///< Checks if image volume with given index is non-diffusion-weighted volume or not. inline unsigned int GetNumWeightedVolumes(); ///< Get number of diffusion-weighted image volumes inline unsigned int GetNumBaselineVolumes(); ///< Get number of non-diffusion-weighted image volumes inline unsigned int GetNumVolumes(); ///< Get number of baseline and diffusion-weighted image volumes inline GradientListType GetGradientDirections(); ///< Return gradient direction container inline GradientType GetGradientDirection(unsigned int i); inline void SetNumWeightedVolumes(int numGradients); ///< Automaticall calls GenerateGradientHalfShell() afterwards. inline void SetGradienDirections(GradientListType gradientList); inline void SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientList); protected: unsigned int m_NumGradients; ///< Number of diffusion-weighted image volumes. unsigned int m_NumBaseline; ///< Number of non-diffusion-weighted image volumes. GradientListType m_GradientDirections; ///< Total number of image volumes. }; /** Fiber generation */ class FiberGenerationParameters { public: enum FiberDistribution{ DISTRIBUTE_UNIFORM, // distribute fibers uniformly in the ROIs DISTRIBUTE_GAUSSIAN // distribute fibers using a 2D gaussian }; typedef vector< vector< mitk::PlanarEllipse::Pointer > > FiducialListType; typedef vector< vector< unsigned int > > FlipListType; FiberGenerationParameters() : m_Distribution(DISTRIBUTE_UNIFORM) , m_Density(100) , m_Variance(100) , m_Sampling(1) , m_Tension(0) , m_Continuity(0) , m_Bias(0) { m_Rotation.Fill(0.0); m_Translation.Fill(0.0); m_Scale.Fill(1.0); } FiberDistribution m_Distribution; unsigned int m_Density; double m_Variance; double m_Sampling; double m_Tension; double m_Continuity; double m_Bias; mitk::Vector3D m_Rotation; mitk::Vector3D m_Translation; mitk::Vector3D m_Scale; FlipListType m_FlipList; ///< contains flags indicating a flip of the 2D fiber x-coordinates (needed to resolve some unwanted fiber twisting) FiducialListType m_Fiducials; ///< container of the planar ellipses used as fiducials for the fiber generation process }; /** GUI persistence, input, output, ... */ class MiscFiberfoxParameters { public: MiscFiberfoxParameters() : m_ResultNode(DataNode::New()) , m_ParentNode(NULL) , m_SignalModelString("") , m_ArtifactModelString("") , m_OutputPath("") , m_CheckOutputVolumeFractionsBox(false) , m_CheckAdvancedSignalOptionsBox(false) , m_CheckAddNoiseBox(false) , m_CheckAddGhostsBox(false) , m_CheckAddAliasingBox(false) , m_CheckAddSpikesBox(false) , m_CheckAddEddyCurrentsBox(false) , m_CheckAddDistortionsBox(false) , m_CheckRealTimeFibersBox(true) , m_CheckAdvancedFiberOptionsBox(false) , m_CheckConstantRadiusBox(false) , m_CheckIncludeFiducialsBox(true) {} DataNode::Pointer m_ResultNode; ///< Stores resulting image. DataNode::Pointer m_ParentNode; ///< Parent node of result node. string m_SignalModelString; ///< Appendet to the name of the result node string m_ArtifactModelString; ///< Appendet to the name of the result node string m_OutputPath; ///< Image is automatically saved to the specified folder after simulation is finished. /** member variables that store the check-state of GUI checkboxes */ // image generation bool m_CheckOutputVolumeFractionsBox; bool m_CheckAdvancedSignalOptionsBox; bool m_CheckAddNoiseBox; bool m_CheckAddGhostsBox; bool m_CheckAddAliasingBox; bool m_CheckAddSpikesBox; bool m_CheckAddEddyCurrentsBox; bool m_CheckAddDistortionsBox; // fiber generation bool m_CheckRealTimeFibersBox; bool m_CheckAdvancedFiberOptionsBox; bool m_CheckConstantRadiusBox; bool m_CheckIncludeFiducialsBox; }; /** * \brief Datastructure to manage the Fiberfox signal generation parameters. * */ template< class ScalarType = double > class FiberfoxParameters { public: typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkUcharImgType; typedef DiffusionSignalModel DiffusionModelType; typedef std::vector< DiffusionModelType* > DiffusionModelListType; typedef DiffusionNoiseModel NoiseModelType; FiberfoxParameters(); ~FiberfoxParameters(); /** Get same parameter object with different template parameter */ template< class OutType > FiberfoxParameters< OutType > CopyParameters() { FiberfoxParameters< OutType > out; out.m_FiberGen = m_FiberGen; out.m_SignalGen = m_SignalGen; out.m_Misc = m_Misc; if (m_NoiseModel!=NULL) { if (dynamic_cast*>(m_NoiseModel)) out.m_NoiseModel = new mitk::RicianNoiseModel(); else if (dynamic_cast*>(m_NoiseModel)) out.m_NoiseModel = new mitk::ChiSquareNoiseModel(); out.m_NoiseModel->SetNoiseVariance(m_NoiseModel->GetNoiseVariance()); } for (unsigned int i=0; i* outModel = NULL; mitk::DiffusionSignalModel* signalModel = NULL; if (i*>(signalModel)) outModel = new mitk::StickModel(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::TensorModel(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::RawShModel(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::BallModel(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::AstroStickModel(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::DotModel(dynamic_cast*>(signalModel)); if (i + ParameterType ReadVal(boost::property_tree::ptree::value_type const& v, std::string tag, ParameterType defaultValue, bool essential=false); + std::string m_MissingTags; }; } #include "mitkFiberfoxParameters.cpp" #endif diff --git a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDiffusionSignalModel.h b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDiffusionSignalModel.h index bb58532d59..7ff59dfb22 100644 --- a/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDiffusionSignalModel.h +++ b/Modules/DiffusionImaging/FiberTracking/SignalModels/mitkDiffusionSignalModel.h @@ -1,96 +1,96 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_DiffusionSignalModel_H #define _MITK_DiffusionSignalModel_H #include #include #include #include #include #include namespace mitk { /** * \brief Abstract class for diffusion signal models * */ template< class ScalarType = double > class DiffusionSignalModel { public: DiffusionSignalModel() : m_T2(100) - , m_T1(800) + , m_T1(0) {} ~DiffusionSignalModel(){} typedef itk::Image ItkDoubleImgType; typedef itk::VariableLengthVector< ScalarType > PixelType; typedef itk::Vector GradientType; typedef std::vector GradientListType; typedef itk::Statistics::MersenneTwisterRandomVariateGenerator ItkRandGenType; /** Realizes actual signal generation. Has to be implemented in subclass. **/ virtual PixelType SimulateMeasurement() = 0; virtual ScalarType SimulateMeasurement(unsigned int dir) = 0; virtual void SetFiberDirection(GradientType fiberDirection) = 0; GradientType GetFiberDirection(){ return m_FiberDirection; } virtual void SetGradientList(GradientListType gradientList) = 0; GradientListType GetGradientList(){ return m_GradientList; } GradientType GetGradientDirection(int i) { return m_GradientList.at(i); } void SetT2(double T2) { m_T2 = T2; } double GetT2() { return m_T2; } void SetT1(double T1) { m_T1 = T1; } double GetT1() { return m_T1; } void SetVolumeFractionImage(ItkDoubleImgType::Pointer img){ m_VolumeFractionImage = img; } ItkDoubleImgType::Pointer GetVolumeFractionImage(){ return m_VolumeFractionImage; } void SetRandomGenerator(ItkRandGenType::Pointer randgen){ m_RandGen = randgen; } ItkRandGenType::Pointer GetRandomGenerator(){ return m_RandGen; } void SetSeed(int s) ///< set seed for random generator { if (m_RandGen.IsNull()) m_RandGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); m_RandGen->SetSeed(s); } unsigned int m_CompartmentId; ///< GUI flag. Which compartment is this model assigned to? protected: GradientType m_FiberDirection; ///< Needed to generate anisotropc signal to determin direction of anisotropy GradientListType m_GradientList; ///< Diffusion gradient direction container double m_T2; ///< Tissue specific transversal relaxation time double m_T1; ///< Tissue specific longitudinal relaxation time ItkDoubleImgType::Pointer m_VolumeFractionImage; ///< Tissue specific volume fraction for each voxel (only relevant for non fiber compartments) ItkRandGenType::Pointer m_RandGen; ///< Random number generator }; } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt b/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt index 712d4ecde0..7dbcd2e2cf 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt +++ b/Modules/DiffusionImaging/FiberTracking/Testing/CMakeLists.txt @@ -1,14 +1,14 @@ MITK_CREATE_MODULE_TESTS() if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") mitkAddCustomModuleTest(mitkFiberBundleReaderWriterTest mitkFiberBundleReaderWriterTest) mitkAddCustomModuleTest(mitkGibbsTrackingTest mitkGibbsTrackingTest ${MITK_DATA_DIR}/DiffusionImaging/qBallImage.qbi ${MITK_DATA_DIR}/DiffusionImaging/diffusionImageMask.nrrd ${MITK_DATA_DIR}/DiffusionImaging/gibbsTrackingParameters.gtp ${MITK_DATA_DIR}/DiffusionImaging/gibbsTractogram.fib) mitkAddCustomModuleTest(mitkStreamlineTrackingTest mitkStreamlineTrackingTest ${MITK_DATA_DIR}/DiffusionImaging/tensorImage.dti ${MITK_DATA_DIR}/DiffusionImaging/diffusionImageMask.nrrd ${MITK_DATA_DIR}/DiffusionImaging/streamlineTractogramInterpolated.fib) -#mitkAddCustomModuleTest(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) -mitkAddCustomModuleTest(mitkFiberfoxSignalGenerationTest mitkFiberfoxSignalGenerationTest ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/gaussian.fib ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/StickBall_RELAX.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/StickAstrosticks_RELAX.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/StickDot_RELAX.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/TensorBall_RELAX.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/StickTensorBall_RELAX.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/StickTensorBallAstrosticks_RELAX.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/gibbsringing.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/ghost.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/aliasing.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/eddy.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/linearmotion.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/randommotion.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/spikes.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/riciannoise.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/chisquarenoise.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/distortions.dwi ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/Fieldmap.nrrd) -mitkAddCustomModuleTest(mitkFiberfoxAddArtifactsToDwiTest mitkFiberfoxAddArtifactsToDwiTest) + +mitkAddCustomModuleTest(mitkFiberfoxSignalGenerationTest mitkFiberfoxSignalGenerationTest ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/Signalgen.fib ${MITK_DATA_DIR}/DiffusionImaging/Fiberfox/params/param1) +#mitkAddCustomModuleTest(mitkFiberfoxAddArtifactsToDwiTest mitkFiberfoxAddArtifactsToDwiTest) ENDIF() diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberfoxSignalGenerationTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberfoxSignalGenerationTest.cpp index b6604ff129..3604bb4127 100644 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberfoxSignalGenerationTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkFiberfoxSignalGenerationTest.cpp @@ -1,297 +1,128 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef itk::VectorImage< short, 3> ItkDwiType; /**Documentation * Test the Fiberfox simulation functions (fiberBundle -> diffusion weighted image) */ bool CompareDwi(itk::VectorImage< short, 3 >* dwi1, itk::VectorImage< short, 3 >* dwi2) { typedef itk::VectorImage< short, 3 > DwiImageType; try{ itk::ImageRegionIterator< DwiImageType > it1(dwi1, dwi1->GetLargestPossibleRegion()); itk::ImageRegionIterator< DwiImageType > it2(dwi2, dwi2->GetLargestPossibleRegion()); while(!it1.IsAtEnd()) { if (it1.Get()!=it2.Get()) { MITK_INFO << it1.GetIndex() << ":" << it1.Get(); MITK_INFO << it2.GetIndex() << ":" << it2.Get(); return false; } ++it1; ++it2; } } catch(...) { return false; } return true; } void StartSimulation(FiberfoxParameters parameters, FiberBundle::Pointer fiberBundle, mitk::Image::Pointer refImage, string message) { itk::TractsToDWIImageFilter< short >::Pointer tractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); tractsToDwiFilter->SetUseConstantRandSeed(true); tractsToDwiFilter->SetParameters(parameters); tractsToDwiFilter->SetFiberBundle(fiberBundle); tractsToDwiFilter->Update(); mitk::Image::Pointer testImage = mitk::GrabItkImageMemory( tractsToDwiFilter->GetOutput() ); testImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() ) ); testImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.m_Bvalue ) ); mitk::DiffusionPropertyHelper propertyHelper( testImage ); propertyHelper.InitializeImage(); if (refImage.IsNotNull()) { - if( static_cast( refImage->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer().IsNotNull() ) - { - ItkDwiType::Pointer itkTestImagePointer = ItkDwiType::New(); - mitk::CastToItkImage(testImage, itkTestImagePointer); - ItkDwiType::Pointer itkRefImagePointer = ItkDwiType::New(); - mitk::CastToItkImage(refImage, itkRefImagePointer); - - bool cond = CompareDwi(itkTestImagePointer, itkRefImagePointer); - if (!cond) + if( static_cast( refImage->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer().IsNotNull() ) { - MITK_INFO << "Saving test and rference image to " << mitk::IOUtil::GetTempPath(); - mitk::IOUtil::SaveBaseData(testImage, mitk::IOUtil::GetTempPath()+"testImage.nrrd"); - mitk::IOUtil::SaveBaseData(refImage, mitk::IOUtil::GetTempPath()+"refImage.nrrd"); + ItkDwiType::Pointer itkTestImagePointer = ItkDwiType::New(); + mitk::CastToItkImage(testImage, itkTestImagePointer); + ItkDwiType::Pointer itkRefImagePointer = ItkDwiType::New(); + mitk::CastToItkImage(refImage, itkRefImagePointer); + + bool cond = CompareDwi(itkTestImagePointer, itkRefImagePointer); + if (!cond) + { + MITK_INFO << "Saving test and rference image to " << mitk::IOUtil::GetTempPath(); + mitk::IOUtil::SaveBaseData(testImage, mitk::IOUtil::GetTempPath()+"testImage.dwi"); + mitk::IOUtil::SaveBaseData(refImage, mitk::IOUtil::GetTempPath()+"refImage.dwi"); + } + MITK_TEST_CONDITION_REQUIRED(cond, message); } - MITK_TEST_CONDITION_REQUIRED(cond, message); - } } } int mitkFiberfoxSignalGenerationTest(int argc, char* argv[]) { MITK_TEST_BEGIN("mitkFiberfoxSignalGenerationTest"); - MITK_TEST_CONDITION_REQUIRED(argc>=19,"check for input data"); - // input fiber bundle FiberBundle::Pointer fiberBundle = dynamic_cast(mitk::IOUtil::Load(argv[1])[0].GetPointer()); - // reference diffusion weighted images - mitk::Image::Pointer stickBall = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[2])->GetData()); - mitk::Image::Pointer stickAstrosticks = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[3])->GetData()); - mitk::Image::Pointer stickDot = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[4])->GetData()); - mitk::Image::Pointer tensorBall = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[5])->GetData()); - mitk::Image::Pointer stickTensorBall = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[6])->GetData()); - mitk::Image::Pointer stickTensorBallAstrosticks = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[7])->GetData()); - mitk::Image::Pointer gibbsringing = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[8])->GetData()); - mitk::Image::Pointer ghost = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[9])->GetData()); - mitk::Image::Pointer aliasing = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[10])->GetData()); - mitk::Image::Pointer eddy = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[11])->GetData()); - mitk::Image::Pointer linearmotion = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[12])->GetData()); - mitk::Image::Pointer randommotion = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[13])->GetData()); - mitk::Image::Pointer spikes = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[14])->GetData()); - mitk::Image::Pointer riciannoise = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[15])->GetData()); - mitk::Image::Pointer chisquarenoise = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[16])->GetData()); - mitk::Image::Pointer distortions = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[17])->GetData()); - mitk::Image::Pointer mitkFMap = dynamic_cast(mitk::IOUtil::LoadDataNode(argv[18])->GetData()); - typedef itk::Image ItkDoubleImgType; - ItkDoubleImgType::Pointer fMap = ItkDoubleImgType::New(); - mitk::CastToItkImage(mitkFMap, fMap); - - ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); - mitk::CastToItkImage(stickBall, itkVectorImagePointer); - - FiberfoxParameters parameters; - parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; - parameters.m_SignalGen.m_SignalScale = 10000; - parameters.m_SignalGen.m_ImageRegion = itkVectorImagePointer->GetLargestPossibleRegion(); - parameters.m_SignalGen.m_ImageSpacing = itkVectorImagePointer->GetSpacing(); - parameters.m_SignalGen.m_ImageOrigin = itkVectorImagePointer->GetOrigin(); - parameters.m_SignalGen.m_ImageDirection = itkVectorImagePointer->GetDirection(); - parameters.m_SignalGen.m_Bvalue = static_cast(stickBall->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue(); - parameters.m_SignalGen.SetGradienDirections( static_cast( stickBall->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer() ); - - // intra and inter axonal compartments - mitk::StickModel stickModel; - stickModel.SetBvalue(parameters.m_SignalGen.m_Bvalue); - stickModel.SetT2(110); - stickModel.SetDiffusivity(0.001); - stickModel.SetGradientList(parameters.m_SignalGen.GetGradientDirections()); - - mitk::TensorModel tensorModel; - tensorModel.SetT2(110); - stickModel.SetBvalue(parameters.m_SignalGen.m_Bvalue); - tensorModel.SetDiffusivity1(0.001); - tensorModel.SetDiffusivity2(0.00025); - tensorModel.SetDiffusivity3(0.00025); - tensorModel.SetGradientList(parameters.m_SignalGen.GetGradientDirections()); - - // extra axonal compartment models - mitk::BallModel ballModel; - ballModel.SetT2(80); - ballModel.SetBvalue(parameters.m_SignalGen.m_Bvalue); - ballModel.SetDiffusivity(0.001); - ballModel.SetGradientList(parameters.m_SignalGen.GetGradientDirections()); - - mitk::AstroStickModel astrosticksModel; - astrosticksModel.SetT2(80); - astrosticksModel.SetBvalue(parameters.m_SignalGen.m_Bvalue); - astrosticksModel.SetDiffusivity(0.001); - astrosticksModel.SetRandomizeSticks(true); - astrosticksModel.SetSeed(0); - astrosticksModel.SetGradientList(parameters.m_SignalGen.GetGradientDirections()); - - mitk::DotModel dotModel; - dotModel.SetT2(80); - dotModel.SetGradientList(parameters.m_SignalGen.GetGradientDirections()); - - // noise models - mitk::RicianNoiseModel* ricianNoiseModel = new mitk::RicianNoiseModel(); - ricianNoiseModel->SetNoiseVariance(1000000); - ricianNoiseModel->SetSeed(0); - - // Rician noise - mitk::ChiSquareNoiseModel* chiSquareNoiseModel = new mitk::ChiSquareNoiseModel(); - chiSquareNoiseModel->SetNoiseVariance(1000000); - chiSquareNoiseModel->SetSeed(0); - - try{ - // Stick-Ball - parameters.m_FiberModelList.push_back(&stickModel); - parameters.m_NonFiberModelList.push_back(&ballModel); - StartSimulation(parameters, fiberBundle, stickBall, argv[2]); - - // Srick-Astrosticks - parameters.m_NonFiberModelList.clear(); - parameters.m_NonFiberModelList.push_back(&astrosticksModel); - StartSimulation(parameters, fiberBundle, stickAstrosticks, argv[3]); - - // Stick-Dot - parameters.m_NonFiberModelList.clear(); - parameters.m_NonFiberModelList.push_back(&dotModel); - StartSimulation(parameters, fiberBundle, stickDot, argv[4]); - - // Tensor-Ball - parameters.m_FiberModelList.clear(); - parameters.m_FiberModelList.push_back(&tensorModel); - parameters.m_NonFiberModelList.clear(); - parameters.m_NonFiberModelList.push_back(&ballModel); - StartSimulation(parameters, fiberBundle, tensorBall, argv[5]); - - // Stick-Tensor-Ball - parameters.m_FiberModelList.clear(); - parameters.m_FiberModelList.push_back(&stickModel); - parameters.m_FiberModelList.push_back(&tensorModel); - parameters.m_NonFiberModelList.clear(); - parameters.m_NonFiberModelList.push_back(&ballModel); - StartSimulation(parameters, fiberBundle, stickTensorBall, argv[6]); - - // Stick-Tensor-Ball-Astrosticks -// parameters.m_NonFiberModelList.push_back(&astrosticksModel); -// StartSimulation(parameters, fiberBundle, stickTensorBallAstrosticks, argv[7]); - - // Gibbs ringing - parameters.m_FiberModelList.clear(); - parameters.m_FiberModelList.push_back(&stickModel); - parameters.m_NonFiberModelList.clear(); - parameters.m_NonFiberModelList.push_back(&ballModel); - parameters.m_SignalGen.m_DoAddGibbsRinging = true; - StartSimulation(parameters, fiberBundle, gibbsringing, argv[8]); - - // Ghost - parameters.m_SignalGen.m_DoAddGibbsRinging = false; - parameters.m_SignalGen.m_KspaceLineOffset = 0.25; - StartSimulation(parameters, fiberBundle, ghost, argv[9]); - - // Aliasing - parameters.m_SignalGen.m_KspaceLineOffset = 0; - parameters.m_SignalGen.m_CroppingFactor = 0.4; - parameters.m_SignalGen.m_SignalScale = 1000; - StartSimulation(parameters, fiberBundle, aliasing, argv[10]); - - // Eddy currents - parameters.m_SignalGen.m_CroppingFactor = 1; - parameters.m_SignalGen.m_SignalScale = 10000; - parameters.m_SignalGen.m_EddyStrength = 0.05; - StartSimulation(parameters, fiberBundle, eddy, argv[11]); - - // Motion (linear) - parameters.m_SignalGen.m_EddyStrength = 0.0; - parameters.m_SignalGen.m_DoAddMotion = true; - parameters.m_SignalGen.m_DoRandomizeMotion = false; - parameters.m_SignalGen.m_Translation[1] = 10; - parameters.m_SignalGen.m_Rotation[2] = 90; - StartSimulation(parameters, fiberBundle, linearmotion, argv[12]); - - // Motion (random) - parameters.m_SignalGen.m_DoRandomizeMotion = true; - parameters.m_SignalGen.m_Translation[1] = 5; - parameters.m_SignalGen.m_Rotation[2] = 45; - StartSimulation(parameters, fiberBundle, randommotion, argv[13]); - - // Spikes - parameters.m_SignalGen.m_DoAddMotion = false; - parameters.m_SignalGen.m_Spikes = 5; - parameters.m_SignalGen.m_SpikeAmplitude = 1; - StartSimulation(parameters, fiberBundle, spikes, argv[14]); - - // Rician noise - parameters.m_SignalGen.m_Spikes = 0; - parameters.m_NoiseModel = ricianNoiseModel; - StartSimulation(parameters, fiberBundle, riciannoise, argv[15]); - delete parameters.m_NoiseModel; + for (int i=2; i parameters; + string file = argv[i]; + parameters.LoadParameters(file+".ffp"); - // Chi-square noise - parameters.m_NoiseModel = chiSquareNoiseModel; - StartSimulation(parameters, fiberBundle, chisquarenoise, argv[16]); - delete parameters.m_NoiseModel; + // Load reference diffusion weighted image + mitk::Image::Pointer mitkRef = dynamic_cast(mitk::IOUtil::LoadDataNode(file+".dwi")->GetData()); - // Distortions - parameters.m_NoiseModel = NULL; - parameters.m_SignalGen.m_FrequencyMap = fMap; - StartSimulation(parameters, fiberBundle, distortions, argv[17]); - } - catch (std::exception &e) - { - MITK_TEST_CONDITION_REQUIRED(false, e.what()); + StartSimulation(parameters, fiberBundle, mitkRef, file); } // always end with this! MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/MiniApps/Fiberfox.cpp b/Modules/DiffusionImaging/MiniApps/Fiberfox.cpp index d47a1db705..b08bcde76c 100755 --- a/Modules/DiffusionImaging/MiniApps/Fiberfox.cpp +++ b/Modules/DiffusionImaging/MiniApps/Fiberfox.cpp @@ -1,83 +1,116 @@ /*=================================================================== 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 "mitkCommandLineParser.h" #include #include - -#include "boost/property_tree/ptree.hpp" -#include "boost/property_tree/xml_parser.hpp" -#include "boost/foreach.hpp" +#include /** TODO: Proritype signal komplett speichern oder bild mit speichern. */ /** TODO: Tarball aus images und parametern? */ /** TODO: Artefakte auf bild in miniapp */ using namespace mitk; int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("FiberFox"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setContributor("MBI"); parser.setDescription(" "); parser.setArgumentPrefix("--", "-"); parser.addArgument("out", "o", mitkCommandLineParser::OutputFile, "Output root:", "output root", us::Any(), false); parser.addArgument("parameters", "p", mitkCommandLineParser::InputFile, "Parameter file:", "fiberfox parameter file", us::Any(), false); parser.addArgument("fiberbundle", "f", mitkCommandLineParser::String, "Fiberbundle:", "", us::Any(), false); + parser.addArgument("verbose", "v", mitkCommandLineParser::Bool, "Output additional images:", "", false, true); map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; string outName = us::any_cast(parsedArgs["out"]); string paramName = us::any_cast(parsedArgs["parameters"]); string fibFile = ""; if (parsedArgs.count("fiberbundle")) fibFile = us::any_cast(parsedArgs["fiberbundle"]); - { - FiberfoxParameters parameters; - parameters.LoadParameters(paramName); + bool verbose = false; + if (parsedArgs.count("verbose")) + verbose = us::any_cast(parsedArgs["verbose"]); + + FiberfoxParameters parameters; + parameters.LoadParameters(paramName); + parameters.m_Misc.m_OutputPath = itksys::SystemTools::GetFilenamePath(outName)+"/"; + + if (verbose) + parameters.SaveParameters(outName+".ffp"); - mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::LoadDataNode(fibFile)->GetData()); + mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::LoadDataNode(fibFile)->GetData()); - itk::TractsToDWIImageFilter< short >::Pointer tractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); - tractsToDwiFilter->SetParameters(parameters); - tractsToDwiFilter->SetFiberBundle(inputTractogram); - tractsToDwiFilter->Update(); + itk::TractsToDWIImageFilter< short >::Pointer tractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); + tractsToDwiFilter->SetParameters(parameters); + tractsToDwiFilter->SetFiberBundle(inputTractogram); + tractsToDwiFilter->Update(); - mitk::Image::Pointer image = mitk::GrabItkImageMemory( tractsToDwiFilter->GetOutput() ); - image->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() ) ); - image->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.m_Bvalue ) ); - mitk::DiffusionPropertyHelper propertyHelper( image ); - propertyHelper.InitializeImage(); + mitk::Image::Pointer image = mitk::GrabItkImageMemory( tractsToDwiFilter->GetOutput() ); + image->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() ) ); + image->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.m_Bvalue ) ); + mitk::DiffusionPropertyHelper propertyHelper( image ); + propertyHelper.InitializeImage(); - mitk::IOUtil::Save(image, outName.c_str()); + mitk::IOUtil::Save(image, outName+".dwi"); + + if (verbose) + { + std::vector< itk::TractsToDWIImageFilter< short >::ItkDoubleImgType::Pointer > volumeFractions = tractsToDwiFilter->GetVolumeFractions(); + for (unsigned int k=0; kInitializeByItk(volumeFractions.at(k).GetPointer()); + image->SetVolume(volumeFractions.at(k)->GetBufferPointer()); + mitk::IOUtil::Save(image, outName+"_Compartment"+boost::lexical_cast(k)+".nrrd"); + } + + if (tractsToDwiFilter->GetPhaseImage().IsNotNull()) + { + mitk::Image::Pointer image = mitk::Image::New(); + itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer itkPhase = tractsToDwiFilter->GetPhaseImage(); + image = mitk::GrabItkImageMemory( itkPhase.GetPointer() ); + mitk::IOUtil::Save(image, outName+"_Phase.nrrd"); + } + + if (tractsToDwiFilter->GetKspaceImage().IsNotNull()) + { + mitk::Image::Pointer image = mitk::Image::New(); + itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer itkImage = tractsToDwiFilter->GetKspaceImage(); + image = mitk::GrabItkImageMemory( itkImage.GetPointer() ); + mitk::IOUtil::Save(image, outName+"_kSpace.nrrd"); + } } + return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/MiniApps/PeakExtraction.cpp b/Modules/DiffusionImaging/MiniApps/PeakExtraction.cpp index 25145658c4..2a39c3dcb5 100755 --- a/Modules/DiffusionImaging/MiniApps/PeakExtraction.cpp +++ b/Modules/DiffusionImaging/MiniApps/PeakExtraction.cpp @@ -1,355 +1,380 @@ /*=================================================================== 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 "mitkCommandLineParser.h" #include #include #include #include #include template int StartPeakExtraction(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("image", "i", mitkCommandLineParser::InputFile, "Input image", "sh coefficient image", us::Any(), false); parser.addArgument("outroot", "o", mitkCommandLineParser::OutputDirectory, "Output directory", "output root", us::Any(), false); parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask", "mask image"); parser.addArgument("normalization", "n", mitkCommandLineParser::Int, "Normalization", "0=no norm, 1=max norm, 2=single vec norm", 1, true); parser.addArgument("numpeaks", "p", mitkCommandLineParser::Int, "Max. number of peaks", "maximum number of extracted peaks", 2, true); parser.addArgument("peakthres", "r", mitkCommandLineParser::Float, "Peak threshold", "peak threshold relative to largest peak", 0.4, true); parser.addArgument("abspeakthres", "a", mitkCommandLineParser::Float, "Absolute peak threshold", "absolute peak threshold weighted with local GFA value", 0.06, true); parser.addArgument("shConvention", "s", mitkCommandLineParser::String, "Use specified SH-basis", "use specified SH-basis (MITK, FSL, MRtrix)", string("MITK"), true); parser.addArgument("noFlip", "f", mitkCommandLineParser::Bool, "No flip", "do not flip input image to match MITK coordinate convention"); + parser.addArgument("clusterThres", "c", mitkCommandLineParser::Float, "Clustering threshold", "directions closer together than the specified angular threshold will be clustered (in rad)", 0.9); + parser.addArgument("flipX", "fx", mitkCommandLineParser::Bool, "Flip X", "Flip peaks in x direction"); + parser.addArgument("flipY", "fy", mitkCommandLineParser::Bool, "Flip Y", "Flip peaks in y direction"); + parser.addArgument("flipZ", "fz", mitkCommandLineParser::Bool, "Flip Z", "Flip peaks in z direction"); + parser.setCategory("Preprocessing Tools"); parser.setTitle("Peak Extraction"); parser.setDescription(""); parser.setContributor("MBI"); map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; // mandatory arguments string imageName = us::any_cast(parsedArgs["image"]); string outRoot = us::any_cast(parsedArgs["outroot"]); // optional arguments string maskImageName(""); if (parsedArgs.count("mask")) maskImageName = us::any_cast(parsedArgs["mask"]); int normalization = 1; if (parsedArgs.count("normalization")) normalization = us::any_cast(parsedArgs["normalization"]); int numPeaks = 2; if (parsedArgs.count("numpeaks")) numPeaks = us::any_cast(parsedArgs["numpeaks"]); float peakThres = 0.4; if (parsedArgs.count("peakthres")) peakThres = us::any_cast(parsedArgs["peakthres"]); float absPeakThres = 0.06; if (parsedArgs.count("abspeakthres")) absPeakThres = us::any_cast(parsedArgs["abspeakthres"]); + float clusterThres = 0.9; + if (parsedArgs.count("clusterThres")) + clusterThres = us::any_cast(parsedArgs["clusterThres"]); + bool noFlip = false; if (parsedArgs.count("noFlip")) noFlip = us::any_cast(parsedArgs["noFlip"]); + bool flipX = false; + if (parsedArgs.count("flipX")) + flipX = us::any_cast(parsedArgs["flipX"]); + + bool flipY = false; + if (parsedArgs.count("flipY")) + flipY = us::any_cast(parsedArgs["flipY"]); + + bool flipZ = false; + if (parsedArgs.count("flipZ")) + flipZ = us::any_cast(parsedArgs["flipZ"]); + std::cout << "image: " << imageName; std::cout << "outroot: " << outRoot; if (!maskImageName.empty()) std::cout << "mask: " << maskImageName; else std::cout << "no mask image selected"; std::cout << "numpeaks: " << numPeaks; std::cout << "peakthres: " << peakThres; std::cout << "abspeakthres: " << absPeakThres; std::cout << "shOrder: " << shOrder; try { mitk::Image::Pointer image = mitk::IOUtil::LoadImage(imageName); mitk::Image::Pointer mask = mitk::IOUtil::LoadImage(maskImageName); typedef itk::Image ItkUcharImgType; typedef itk::FiniteDiffOdfMaximaExtractionFilter< float, shOrder, 20242 > MaximaExtractionFilterType; typename MaximaExtractionFilterType::Pointer filter = MaximaExtractionFilterType::New(); int toolkitConvention = 0; if (parsedArgs.count("shConvention")) { string convention = us::any_cast(parsedArgs["shConvention"]).c_str(); if ( boost::algorithm::equals(convention, "FSL") ) { toolkitConvention = 1; std::cout << "Using FSL SH-basis"; } else if ( boost::algorithm::equals(convention, "MRtrix") ) { toolkitConvention = 2; std::cout << "Using MRtrix SH-basis"; } else std::cout << "Using MITK SH-basis"; } else std::cout << "Using MITK SH-basis"; ItkUcharImgType::Pointer itkMaskImage = NULL; if (mask.IsNotNull()) { try{ itkMaskImage = ItkUcharImgType::New(); mitk::CastToItkImage(mask, itkMaskImage); filter->SetMaskImage(itkMaskImage); } catch(...) { } } if (toolkitConvention>0) { std::cout << "Converting coefficient image to MITK format"; typedef itk::ShCoefficientImageImporter< float, shOrder > ConverterType; typedef mitk::ImageToItk< itk::Image< float, 4 > > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(image); caster->Update(); itk::Image< float, 4 >::Pointer itkImage = caster->GetOutput(); typename ConverterType::Pointer converter = ConverterType::New(); if (noFlip) { converter->SetInputImage(itkImage); } else { std::cout << "Flipping image"; itk::FixedArray flipAxes; flipAxes[0] = true; flipAxes[1] = true; flipAxes[2] = false; flipAxes[3] = false; itk::FlipImageFilter< itk::Image< float, 4 > >::Pointer flipper = itk::FlipImageFilter< itk::Image< float, 4 > >::New(); flipper->SetInput(itkImage); flipper->SetFlipAxes(flipAxes); flipper->Update(); itk::Image< float, 4 >::Pointer flipped = flipper->GetOutput(); itk::Matrix< double,4,4 > m = itkImage->GetDirection(); m[0][0] *= -1; m[1][1] *= -1; flipped->SetDirection(m); itk::Point< float, 4 > o = itkImage->GetOrigin(); o[0] -= (flipped->GetLargestPossibleRegion().GetSize(0)-1); o[1] -= (flipped->GetLargestPossibleRegion().GetSize(1)-1); flipped->SetOrigin(o); converter->SetInputImage(flipped); } std::cout << "Starting conversion"; switch (toolkitConvention) { case 1: converter->SetToolkit(ConverterType::FSL); filter->SetToolkit(MaximaExtractionFilterType::FSL); break; case 2: converter->SetToolkit(ConverterType::MRTRIX); filter->SetToolkit(MaximaExtractionFilterType::MRTRIX); break; default: converter->SetToolkit(ConverterType::FSL); filter->SetToolkit(MaximaExtractionFilterType::FSL); break; } converter->GenerateData(); filter->SetInput(converter->GetCoefficientImage()); } else { try{ typedef mitk::ImageToItk< typename MaximaExtractionFilterType::CoefficientImageType > CasterType; typename CasterType::Pointer caster = CasterType::New(); caster->SetInput(image); caster->Update(); filter->SetInput(caster->GetOutput()); } catch(...) { std::cout << "wrong image type"; return EXIT_FAILURE; } } filter->SetMaxNumPeaks(numPeaks); filter->SetPeakThreshold(peakThres); filter->SetAbsolutePeakThreshold(absPeakThres); filter->SetAngularThreshold(1); + filter->SetClusteringThreshold(clusterThres); + filter->SetFlipX(flipX); + filter->SetFlipY(flipY); + filter->SetFlipZ(flipZ); switch (normalization) { case 0: filter->SetNormalizationMethod(MaximaExtractionFilterType::NO_NORM); break; case 1: filter->SetNormalizationMethod(MaximaExtractionFilterType::MAX_VEC_NORM); break; case 2: filter->SetNormalizationMethod(MaximaExtractionFilterType::SINGLE_VEC_NORM); break; } std::cout << "Starting extraction"; filter->Update(); // write direction images { typedef typename MaximaExtractionFilterType::ItkDirectionImageContainer ItkDirectionImageContainer; typename ItkDirectionImageContainer::Pointer container = filter->GetDirectionImageContainer(); for (unsigned int i=0; iSize(); i++) { typename MaximaExtractionFilterType::ItkDirectionImage::Pointer itkImg = container->GetElement(i); if (itkMaskImage.IsNotNull()) { itkImg->SetDirection(itkMaskImage->GetDirection()); itkImg->SetOrigin(itkMaskImage->GetOrigin()); } string outfilename = outRoot; outfilename.append("_DIRECTION_"); outfilename.append(boost::lexical_cast(i)); outfilename.append(".nrrd"); typedef itk::ImageFileWriter< typename MaximaExtractionFilterType::ItkDirectionImage > WriterType; typename WriterType::Pointer writer = WriterType::New(); writer->SetFileName(outfilename); writer->SetInput(itkImg); writer->Update(); } } // write num directions image { ItkUcharImgType::Pointer numDirImage = filter->GetNumDirectionsImage(); if (itkMaskImage.IsNotNull()) { numDirImage->SetDirection(itkMaskImage->GetDirection()); numDirImage->SetOrigin(itkMaskImage->GetOrigin()); } string outfilename = outRoot.c_str(); outfilename.append("_NUM_DIRECTIONS.nrrd"); typedef itk::ImageFileWriter< ItkUcharImgType > WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetFileName(outfilename); writer->SetInput(numDirImage); writer->Update(); } // write vector field { mitk::FiberBundle::Pointer directions = filter->GetOutputFiberBundle(); string outfilename = outRoot.c_str(); outfilename.append("_VECTOR_FIELD.fib"); mitk::IOUtil::Save(directions.GetPointer(),outfilename.c_str()); } } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("image", "i", mitkCommandLineParser::InputFile, "Input image", "sh coefficient image", us::Any(), false); parser.addArgument("shOrder", "sh", mitkCommandLineParser::Int, "Spherical harmonics order", "spherical harmonics order"); parser.addArgument("outroot", "o", mitkCommandLineParser::OutputDirectory, "Output directory", "output root", us::Any(), false); parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask", "mask image"); parser.addArgument("normalization", "n", mitkCommandLineParser::Int, "Normalization", "0=no norm, 1=max norm, 2=single vec norm", 1, true); parser.addArgument("numpeaks", "p", mitkCommandLineParser::Int, "Max. number of peaks", "maximum number of extracted peaks", 2, true); parser.addArgument("peakthres", "r", mitkCommandLineParser::Float, "Peak threshold", "peak threshold relative to largest peak", 0.4, true); parser.addArgument("abspeakthres", "a", mitkCommandLineParser::Float, "Absolute peak threshold", "absolute peak threshold weighted with local GFA value", 0.06, true); parser.addArgument("shConvention", "s", mitkCommandLineParser::String, "Use specified SH-basis", "use specified SH-basis (MITK, FSL, MRtrix)", string("MITK"), true); parser.addArgument("noFlip", "f", mitkCommandLineParser::Bool, "No flip", "do not flip input image to match MITK coordinate convention"); parser.setCategory("Preprocessing Tools"); parser.setTitle("Peak Extraction"); parser.setDescription(""); parser.setContributor("MBI"); map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; int shOrder = -1; if (parsedArgs.count("shOrder")) shOrder = us::any_cast(parsedArgs["shOrder"]); switch (shOrder) { case 4: return StartPeakExtraction<4>(argc, argv); case 6: return StartPeakExtraction<6>(argc, argv); case 8: return StartPeakExtraction<8>(argc, argv); case 10: return StartPeakExtraction<10>(argc, argv); case 12: return StartPeakExtraction<12>(argc, argv); } return EXIT_FAILURE; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp index aab7594158..8443c5c8b3 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp @@ -1,2698 +1,2839 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //misc #define _USE_MATH_DEFINES #include // Blueberry #include #include // Qmitk #include "QmitkFiberfoxView.h" // MITK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#define RAPIDXML_NO_EXCEPTIONS #include #include #include #include #include "usModuleRegistry.h" #include #include #include #include #include #include #include #include #include #include "mitkNodePredicateDataType.h" #include #include #include #include #define _USE_MATH_DEFINES #include QmitkFiberfoxWorker::QmitkFiberfoxWorker(QmitkFiberfoxView* view) : m_View(view) { } void QmitkFiberfoxWorker::run() { try{ switch (m_FilterType) { case 0: m_View->m_TractsToDwiFilter->Update(); break; case 1: m_View->m_ArtifactsToDwiFilter->Update(); break; } } catch( ... ) { } m_View->m_Thread.quit(); } const std::string QmitkFiberfoxView::VIEW_ID = "org.mitk.views.fiberfoxview"; QmitkFiberfoxView::QmitkFiberfoxView() : QmitkAbstractView() , m_Controls( 0 ) , m_SelectedImageNode( NULL ) , m_Worker(this) , m_ThreadIsRunning(false) { m_Worker.moveToThread(&m_Thread); connect(&m_Thread, SIGNAL(started()), this, SLOT(BeforeThread())); connect(&m_Thread, SIGNAL(started()), &m_Worker, SLOT(run())); connect(&m_Thread, SIGNAL(finished()), this, SLOT(AfterThread())); connect(&m_Thread, SIGNAL(terminated()), this, SLOT(AfterThread())); m_SimulationTimer = new QTimer(this); } void QmitkFiberfoxView::KillThread() { MITK_INFO << "Aborting DWI simulation."; switch (m_Worker.m_FilterType) { case 0: m_TractsToDwiFilter->SetAbortGenerateData(true); break; case 1: m_ArtifactsToDwiFilter->SetAbortGenerateData(true); break; } m_Controls->m_AbortSimulationButton->setEnabled(false); m_Controls->m_AbortSimulationButton->setText("Aborting simulation ..."); } void QmitkFiberfoxView::BeforeThread() { m_SimulationTime = QTime::currentTime(); m_SimulationTimer->start(100); m_Controls->m_AbortSimulationButton->setVisible(true); m_Controls->m_GenerateImageButton->setVisible(false); m_Controls->m_SimulationStatusText->setVisible(true); m_ThreadIsRunning = true; } void QmitkFiberfoxView::AfterThread() { UpdateSimulationStatus(); m_SimulationTimer->stop(); m_Controls->m_AbortSimulationButton->setVisible(false); m_Controls->m_AbortSimulationButton->setEnabled(true); m_Controls->m_AbortSimulationButton->setText("Abort simulation"); m_Controls->m_GenerateImageButton->setVisible(true); m_ThreadIsRunning = false; QString statusText; FiberfoxParameters parameters; mitk::Image::Pointer mitkImage = mitk::Image::New(); switch (m_Worker.m_FilterType) { case 0: { statusText = QString(m_TractsToDwiFilter->GetStatusText().c_str()); if (m_TractsToDwiFilter->GetAbortGenerateData()) { MITK_INFO << "Simulation aborted."; return; } parameters = m_TractsToDwiFilter->GetParameters(); mitkImage = mitk::GrabItkImageMemory( m_TractsToDwiFilter->GetOutput() ); mitkImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() )); mitkImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.m_Bvalue )); mitk::DiffusionPropertyHelper propertyHelper( mitkImage ); propertyHelper.InitializeImage(); parameters.m_Misc.m_ResultNode->SetData( mitkImage ); parameters.m_Misc.m_ResultNode->SetName(parameters.m_Misc.m_ParentNode->GetName() +"_D"+QString::number(parameters.m_SignalGen.m_ImageRegion.GetSize(0)).toStdString() +"-"+QString::number(parameters.m_SignalGen.m_ImageRegion.GetSize(1)).toStdString() +"-"+QString::number(parameters.m_SignalGen.m_ImageRegion.GetSize(2)).toStdString() +"_S"+QString::number(parameters.m_SignalGen.m_ImageSpacing[0]).toStdString() +"-"+QString::number(parameters.m_SignalGen.m_ImageSpacing[1]).toStdString() +"-"+QString::number(parameters.m_SignalGen.m_ImageSpacing[2]).toStdString() +"_b"+QString::number(parameters.m_SignalGen.m_Bvalue).toStdString() +"_"+parameters.m_Misc.m_SignalModelString +parameters.m_Misc.m_ArtifactModelString); GetDataStorage()->Add(parameters.m_Misc.m_ResultNode, parameters.m_Misc.m_ParentNode); parameters.m_Misc.m_ResultNode->SetProperty( "levelwindow", mitk::LevelWindowProperty::New(m_TractsToDwiFilter->GetLevelWindow()) ); if (m_Controls->m_VolumeFractionsBox->isChecked()) { std::vector< itk::TractsToDWIImageFilter< short >::ItkDoubleImgType::Pointer > volumeFractions = m_TractsToDwiFilter->GetVolumeFractions(); for (unsigned int k=0; kInitializeByItk(volumeFractions.at(k).GetPointer()); image->SetVolume(volumeFractions.at(k)->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); - node->SetName(parameters.m_Misc.m_ParentNode->GetName()+"_CompartmentVolume-"+QString::number(k).toStdString()); - GetDataStorage()->Add(node, parameters.m_Misc.m_ParentNode); + node->SetName("CompartmentVolume-"+QString::number(k).toStdString()); + GetDataStorage()->Add(node, parameters.m_Misc.m_ResultNode); + } + + if (m_TractsToDwiFilter->GetPhaseImage().IsNotNull()) + { + mitk::Image::Pointer phaseImage = mitk::Image::New(); + itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer itkPhase = m_TractsToDwiFilter->GetPhaseImage(); + phaseImage = mitk::GrabItkImageMemory( itkPhase.GetPointer() ); + mitk::DataNode::Pointer phaseNode = mitk::DataNode::New(); + phaseNode->SetData( phaseImage ); + phaseNode->SetName("Phase Image"); + GetDataStorage()->Add(phaseNode, parameters.m_Misc.m_ResultNode); + } + + if (m_TractsToDwiFilter->GetKspaceImage().IsNotNull()) + { + mitk::Image::Pointer image = mitk::Image::New(); + itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer itkImage = m_TractsToDwiFilter->GetKspaceImage(); + image = mitk::GrabItkImageMemory( itkImage.GetPointer() ); + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData( image ); + node->SetName("k-Space"); + GetDataStorage()->Add(node, parameters.m_Misc.m_ResultNode); + } + + { + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(m_TractsToDwiFilter->GetCoilPointset()); + node->SetName("Coil Positions"); + node->SetProperty("pointsize", mitk::FloatProperty::New(parameters.m_SignalGen.m_ImageSpacing[0]/4)); + node->SetProperty("color", mitk::ColorProperty::New(0, 1, 0)); + GetDataStorage()->Add(node, parameters.m_Misc.m_ResultNode); } } m_TractsToDwiFilter = NULL; break; } case 1: { statusText = QString(m_ArtifactsToDwiFilter->GetStatusText().c_str()); if (m_ArtifactsToDwiFilter->GetAbortGenerateData()) { MITK_INFO << "Simulation aborted."; return; } parameters = m_ArtifactsToDwiFilter->GetParameters().CopyParameters(); mitk::Image::Pointer diffImg = dynamic_cast(parameters.m_Misc.m_ParentNode->GetData()); mitkImage = mitk::GrabItkImageMemory( m_ArtifactsToDwiFilter->GetOutput() ); mitkImage->SetProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( static_cast( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer() ) ); mitkImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( static_cast( diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue() ) ); mitk::DiffusionPropertyHelper propertyHelper( mitkImage ); propertyHelper.InitializeImage(); parameters.m_Misc.m_ResultNode->SetData( mitkImage ); parameters.m_Misc.m_ResultNode->SetName(parameters.m_Misc.m_ParentNode->GetName()+parameters.m_Misc.m_ArtifactModelString); GetDataStorage()->Add(parameters.m_Misc.m_ResultNode, parameters.m_Misc.m_ParentNode); m_ArtifactsToDwiFilter = NULL; break; } } mitk::BaseData::Pointer basedata = parameters.m_Misc.m_ResultNode->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } if (!parameters.m_Misc.m_OutputPath.empty()) { try{ QString outputFileName(parameters.m_Misc.m_OutputPath.c_str()); outputFileName += parameters.m_Misc.m_ResultNode->GetName().c_str(); outputFileName.replace(QString("."), QString("_")); outputFileName += ".dwi"; QString status("Saving output image to "); status += outputFileName; m_Controls->m_SimulationStatusText->append(status); mitk::IOUtil::SaveBaseData(mitkImage, outputFileName.toStdString()); m_Controls->m_SimulationStatusText->append("File saved successfully."); } catch (itk::ExceptionObject &e) { QString status("Exception during DWI writing: "); status += e.GetDescription(); m_Controls->m_SimulationStatusText->append(status); } catch (...) { m_Controls->m_SimulationStatusText->append("Unknown exception during DWI writing!"); } } parameters.m_SignalGen.m_FrequencyMap = NULL; } void QmitkFiberfoxView::UpdateSimulationStatus() { QString statusText; switch (m_Worker.m_FilterType) { case 0: statusText = QString(m_TractsToDwiFilter->GetStatusText().c_str()); break; case 1: statusText = QString(m_ArtifactsToDwiFilter->GetStatusText().c_str()); break; } if (QString::compare(m_SimulationStatusText,statusText)!=0) { m_Controls->m_SimulationStatusText->clear(); statusText = "
"+statusText+"
"; m_Controls->m_SimulationStatusText->setText(statusText); QScrollBar *vScrollBar = m_Controls->m_SimulationStatusText->verticalScrollBar(); vScrollBar->triggerAction(QScrollBar::SliderToMaximum); } } // Destructor QmitkFiberfoxView::~QmitkFiberfoxView() { delete m_SimulationTimer; } void QmitkFiberfoxView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberfoxViewControls; m_Controls->setupUi( parent ); - // commented out - m_Controls->m_DiffusionDirectionBox->setVisible(false); - m_Controls->label_3->setVisible(false); - m_Controls->m_SeparationAngleBox->setVisible(false); - m_Controls->label_4->setVisible(false); - // - m_Controls->m_StickWidget1->setVisible(true); m_Controls->m_StickWidget2->setVisible(false); m_Controls->m_ZeppelinWidget1->setVisible(false); m_Controls->m_ZeppelinWidget2->setVisible(false); m_Controls->m_TensorWidget1->setVisible(false); m_Controls->m_TensorWidget2->setVisible(false); m_Controls->m_BallWidget1->setVisible(true); m_Controls->m_BallWidget2->setVisible(false); m_Controls->m_AstrosticksWidget1->setVisible(false); m_Controls->m_AstrosticksWidget2->setVisible(false); m_Controls->m_DotWidget1->setVisible(false); m_Controls->m_DotWidget2->setVisible(false); m_Controls->m_PrototypeWidget1->setVisible(false); m_Controls->m_PrototypeWidget2->setVisible(false); m_Controls->m_PrototypeWidget3->setVisible(false); m_Controls->m_PrototypeWidget4->setVisible(false); m_Controls->m_PrototypeWidget3->SetMinFa(0.0); m_Controls->m_PrototypeWidget3->SetMaxFa(0.15); m_Controls->m_PrototypeWidget4->SetMinFa(0.0); m_Controls->m_PrototypeWidget4->SetMaxFa(0.15); m_Controls->m_PrototypeWidget3->SetMinAdc(0.0); m_Controls->m_PrototypeWidget3->SetMaxAdc(0.001); m_Controls->m_PrototypeWidget4->SetMinAdc(0.003); m_Controls->m_PrototypeWidget4->SetMaxAdc(0.004); m_Controls->m_Comp2FractionFrame->setVisible(false); m_Controls->m_Comp4FractionFrame->setVisible(false); m_Controls->m_DiffusionPropsMessage->setVisible(false); m_Controls->m_GeometryMessage->setVisible(false); m_Controls->m_AdvancedSignalOptionsFrame->setVisible(false); m_Controls->m_AdvancedFiberOptionsFrame->setVisible(false); m_Controls->m_VarianceBox->setVisible(false); m_Controls->m_NoiseFrame->setVisible(false); m_Controls->m_GhostFrame->setVisible(false); m_Controls->m_DistortionsFrame->setVisible(false); m_Controls->m_EddyFrame->setVisible(false); m_Controls->m_SpikeFrame->setVisible(false); m_Controls->m_AliasingFrame->setVisible(false); m_Controls->m_MotionArtifactFrame->setVisible(false); m_ParameterFile = QDir::currentPath()+"/param.ffp"; m_Controls->m_AbortSimulationButton->setVisible(false); m_Controls->m_SimulationStatusText->setVisible(false); m_Controls->m_FrequencyMapBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_Comp1VolumeFraction->SetDataStorage(this->GetDataStorage()); m_Controls->m_Comp2VolumeFraction->SetDataStorage(this->GetDataStorage()); m_Controls->m_Comp3VolumeFraction->SetDataStorage(this->GetDataStorage()); m_Controls->m_Comp4VolumeFraction->SetDataStorage(this->GetDataStorage()); m_Controls->m_MaskComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_TemplateComboBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_FiberBundleComboBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isFiberBundle = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isMitkImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateIsDWI::Pointer isDwi = mitk::NodePredicateIsDWI::New( ); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isQbi = mitk::NodePredicateDataType::New("QBallImage"); mitk::NodePredicateOr::Pointer isDiffusionImage = mitk::NodePredicateOr::New(isDwi, isDti); isDiffusionImage = mitk::NodePredicateOr::New(isDiffusionImage, isQbi); mitk::NodePredicateNot::Pointer noDiffusionImage = mitk::NodePredicateNot::New(isDiffusionImage); mitk::NodePredicateAnd::Pointer isNonDiffMitkImage = mitk::NodePredicateAnd::New(isMitkImage, noDiffusionImage); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isBinaryMitkImage = mitk::NodePredicateAnd::New( isNonDiffMitkImage, isBinaryPredicate ); m_Controls->m_FrequencyMapBox->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp1VolumeFraction->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp1VolumeFraction->SetZeroEntryText("--"); m_Controls->m_Comp2VolumeFraction->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp2VolumeFraction->SetZeroEntryText("--"); m_Controls->m_Comp3VolumeFraction->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp3VolumeFraction->SetZeroEntryText("--"); m_Controls->m_Comp4VolumeFraction->SetPredicate(isNonDiffMitkImage); m_Controls->m_Comp4VolumeFraction->SetZeroEntryText("--"); m_Controls->m_MaskComboBox->SetPredicate(isBinaryMitkImage); m_Controls->m_MaskComboBox->SetZeroEntryText("--"); m_Controls->m_TemplateComboBox->SetPredicate(isMitkImage); m_Controls->m_TemplateComboBox->SetZeroEntryText("--"); m_Controls->m_FiberBundleComboBox->SetPredicate(isFiberBundle); m_Controls->m_FiberBundleComboBox->SetZeroEntryText("--"); // mitk::NodePredicateDimension::Pointer dimensionPredicate = mitk::NodePredicateDimension::New(3); connect( m_SimulationTimer, SIGNAL(timeout()), this, SLOT(UpdateSimulationStatus()) ); connect((QObject*) m_Controls->m_AbortSimulationButton, SIGNAL(clicked()), (QObject*) this, SLOT(KillThread())); connect((QObject*) m_Controls->m_GenerateImageButton, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateImage())); connect((QObject*) m_Controls->m_GenerateFibersButton, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateFibers())); connect((QObject*) m_Controls->m_CircleButton, SIGNAL(clicked()), (QObject*) this, SLOT(OnDrawROI())); connect((QObject*) m_Controls->m_FlipButton, SIGNAL(clicked()), (QObject*) this, SLOT(OnFlipButton())); connect((QObject*) m_Controls->m_JoinBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(JoinBundles())); connect((QObject*) m_Controls->m_VarianceBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnVarianceChanged(double))); connect((QObject*) m_Controls->m_DistributionBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnDistributionChanged(int))); connect((QObject*) m_Controls->m_FiberDensityBox, SIGNAL(valueChanged(int)), (QObject*) this, SLOT(OnFiberDensityChanged(int))); connect((QObject*) m_Controls->m_FiberSamplingBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnFiberSamplingChanged(double))); connect((QObject*) m_Controls->m_TensionBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnTensionChanged(double))); connect((QObject*) m_Controls->m_ContinuityBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnContinuityChanged(double))); connect((QObject*) m_Controls->m_BiasBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnBiasChanged(double))); connect((QObject*) m_Controls->m_AddNoise, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddNoise(int))); connect((QObject*) m_Controls->m_AddGhosts, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddGhosts(int))); connect((QObject*) m_Controls->m_AddDistortions, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddDistortions(int))); connect((QObject*) m_Controls->m_AddEddy, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddEddy(int))); connect((QObject*) m_Controls->m_AddSpikes, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddSpikes(int))); connect((QObject*) m_Controls->m_AddAliasing, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddAliasing(int))); connect((QObject*) m_Controls->m_AddMotion, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddMotion(int))); connect((QObject*) m_Controls->m_ConstantRadiusBox, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnConstantRadius(int))); connect((QObject*) m_Controls->m_CopyBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(CopyBundles())); connect((QObject*) m_Controls->m_TransformBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(ApplyTransform())); connect((QObject*) m_Controls->m_AlignOnGrid, SIGNAL(clicked()), (QObject*) this, SLOT(AlignOnGrid())); connect((QObject*) m_Controls->m_Compartment1Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp1ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_Compartment2Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp2ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_Compartment3Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp3ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_Compartment4Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp4ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_AdvancedOptionsBox, SIGNAL( stateChanged(int)), (QObject*) this, SLOT(ShowAdvancedOptions(int))); connect((QObject*) m_Controls->m_AdvancedOptionsBox_2, SIGNAL( stateChanged(int)), (QObject*) this, SLOT(ShowAdvancedOptions(int))); connect((QObject*) m_Controls->m_SaveParametersButton, SIGNAL(clicked()), (QObject*) this, SLOT(SaveParameters())); connect((QObject*) m_Controls->m_LoadParametersButton, SIGNAL(clicked()), (QObject*) this, SLOT(LoadParameters())); connect((QObject*) m_Controls->m_OutputPathButton, SIGNAL(clicked()), (QObject*) this, SLOT(SetOutputPath())); connect((QObject*) m_Controls->m_MaskComboBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnMaskSelected(int))); connect((QObject*) m_Controls->m_TemplateComboBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnTemplateSelected(int))); connect((QObject*) m_Controls->m_FiberBundleComboBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnFibSelected(int))); } } void QmitkFiberfoxView::OnMaskSelected(int value) { UpdateGui(); } void QmitkFiberfoxView::OnTemplateSelected(int value) { UpdateGui(); } void QmitkFiberfoxView::OnFibSelected(int value) { UpdateGui(); } template< class ScalarType > -FiberfoxParameters< ScalarType > QmitkFiberfoxView::UpdateImageParameters() +FiberfoxParameters< ScalarType > QmitkFiberfoxView::UpdateImageParameters(bool all) { FiberfoxParameters< ScalarType > parameters; parameters.m_Misc.m_OutputPath = ""; parameters.m_Misc.m_CheckAdvancedFiberOptionsBox = m_Controls->m_AdvancedOptionsBox->isChecked(); parameters.m_Misc.m_CheckAdvancedSignalOptionsBox = m_Controls->m_AdvancedOptionsBox_2->isChecked(); parameters.m_Misc.m_CheckOutputVolumeFractionsBox = m_Controls->m_VolumeFractionsBox->isChecked(); string outputPath = m_Controls->m_SavePathEdit->text().toStdString(); if (outputPath.compare("-")!=0) { parameters.m_Misc.m_OutputPath = outputPath; parameters.m_Misc.m_OutputPath += "/"; } + + switch(m_Controls->m_DistributionBox->currentIndex()) + { + case 0: + parameters.m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; + break; + case 1: + parameters.m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_GAUSSIAN; + break; + default: + parameters.m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; + } + parameters.m_FiberGen.m_Variance = m_Controls->m_VarianceBox->value(); + parameters.m_FiberGen.m_Density = m_Controls->m_FiberDensityBox->value(); + parameters.m_FiberGen.m_Sampling = m_Controls->m_FiberSamplingBox->value(); + parameters.m_FiberGen.m_Tension = m_Controls->m_TensionBox->value(); + parameters.m_FiberGen.m_Continuity = m_Controls->m_ContinuityBox->value(); + parameters.m_FiberGen.m_Bias = m_Controls->m_BiasBox->value(); + parameters.m_FiberGen.m_Rotation[0] = m_Controls->m_XrotBox->value(); + parameters.m_FiberGen.m_Rotation[1] = m_Controls->m_YrotBox->value(); + parameters.m_FiberGen.m_Rotation[2] = m_Controls->m_ZrotBox->value(); + parameters.m_FiberGen.m_Translation[0] = m_Controls->m_XtransBox->value(); + parameters.m_FiberGen.m_Translation[1] = m_Controls->m_YtransBox->value(); + parameters.m_FiberGen.m_Translation[2] = m_Controls->m_ZtransBox->value(); + parameters.m_FiberGen.m_Scale[0] = m_Controls->m_XscaleBox->value(); + parameters.m_FiberGen.m_Scale[1] = m_Controls->m_YscaleBox->value(); + parameters.m_FiberGen.m_Scale[2] = m_Controls->m_ZscaleBox->value(); + + if (!all) + return parameters; + if (m_Controls->m_MaskComboBox->GetSelectedNode().IsNotNull()) { mitk::Image::Pointer mitkMaskImage = dynamic_cast(m_Controls->m_MaskComboBox->GetSelectedNode()->GetData()); mitk::CastToItkImage(mitkMaskImage, parameters.m_SignalGen.m_MaskImage); itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage(parameters.m_SignalGen.m_MaskImage); duplicator->Update(); parameters.m_SignalGen.m_MaskImage = duplicator->GetOutput(); } if (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull() && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( m_Controls->m_TemplateComboBox->GetSelectedNode())) // use parameters of selected DWI { mitk::Image::Pointer dwi = dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(dwi, itkVectorImagePointer); parameters.m_SignalGen.m_ImageRegion = itkVectorImagePointer->GetLargestPossibleRegion(); parameters.m_SignalGen.m_ImageSpacing = itkVectorImagePointer->GetSpacing(); parameters.m_SignalGen.m_ImageOrigin = itkVectorImagePointer->GetOrigin(); parameters.m_SignalGen.m_ImageDirection = itkVectorImagePointer->GetDirection(); parameters.m_SignalGen.m_Bvalue = static_cast(dwi->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue(); parameters.m_SignalGen.SetGradienDirections(static_cast( dwi->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer()); } else if (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull()) // use geometry of selected image { mitk::Image::Pointer img = dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()); itk::Image< float, 3 >::Pointer itkImg = itk::Image< float, 3 >::New(); CastToItkImage< itk::Image< float, 3 > >(img, itkImg); parameters.m_SignalGen.m_ImageRegion = itkImg->GetLargestPossibleRegion(); parameters.m_SignalGen.m_ImageSpacing = itkImg->GetSpacing(); parameters.m_SignalGen.m_ImageOrigin = itkImg->GetOrigin(); parameters.m_SignalGen.m_ImageDirection = itkImg->GetDirection(); parameters.m_SignalGen.SetNumWeightedVolumes(m_Controls->m_NumGradientsBox->value()); parameters.m_SignalGen.m_Bvalue = m_Controls->m_BvalueBox->value(); } else if (parameters.m_SignalGen.m_MaskImage.IsNotNull()) // use geometry of mask image { ItkUcharImgType::Pointer itkImg = parameters.m_SignalGen.m_MaskImage; parameters.m_SignalGen.m_ImageRegion = itkImg->GetLargestPossibleRegion(); parameters.m_SignalGen.m_ImageSpacing = itkImg->GetSpacing(); parameters.m_SignalGen.m_ImageOrigin = itkImg->GetOrigin(); parameters.m_SignalGen.m_ImageDirection = itkImg->GetDirection(); parameters.m_SignalGen.SetNumWeightedVolumes(m_Controls->m_NumGradientsBox->value()); parameters.m_SignalGen.m_Bvalue = m_Controls->m_BvalueBox->value(); } else // use GUI parameters { parameters.m_SignalGen.m_ImageRegion.SetSize(0, m_Controls->m_SizeX->value()); parameters.m_SignalGen.m_ImageRegion.SetSize(1, m_Controls->m_SizeY->value()); parameters.m_SignalGen.m_ImageRegion.SetSize(2, m_Controls->m_SizeZ->value()); parameters.m_SignalGen.m_ImageSpacing[0] = m_Controls->m_SpacingX->value(); parameters.m_SignalGen.m_ImageSpacing[1] = m_Controls->m_SpacingY->value(); parameters.m_SignalGen.m_ImageSpacing[2] = m_Controls->m_SpacingZ->value(); parameters.m_SignalGen.m_ImageOrigin[0] = parameters.m_SignalGen.m_ImageSpacing[0]/2; parameters.m_SignalGen.m_ImageOrigin[1] = parameters.m_SignalGen.m_ImageSpacing[1]/2; parameters.m_SignalGen.m_ImageOrigin[2] = parameters.m_SignalGen.m_ImageSpacing[2]/2; parameters.m_SignalGen.m_ImageDirection.SetIdentity(); parameters.m_SignalGen.SetNumWeightedVolumes(m_Controls->m_NumGradientsBox->value()); parameters.m_SignalGen.m_Bvalue = m_Controls->m_BvalueBox->value(); parameters.m_SignalGen.GenerateGradientHalfShell(); } // signal relaxation parameters.m_SignalGen.m_DoSimulateRelaxation = m_Controls->m_RelaxationBox->isChecked(); parameters.m_SignalGen.m_SimulateKspaceAcquisition = parameters.m_SignalGen.m_DoSimulateRelaxation; if (parameters.m_SignalGen.m_DoSimulateRelaxation && m_Controls->m_FiberBundleComboBox->GetSelectedNode().IsNotNull() ) + { + parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Relaxation", BoolProperty::New(true)); parameters.m_Misc.m_ArtifactModelString += "_RELAX"; + } // N/2 ghosts parameters.m_Misc.m_CheckAddGhostsBox = m_Controls->m_AddGhosts->isChecked(); if (m_Controls->m_AddGhosts->isChecked()) { parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; parameters.m_Misc.m_ArtifactModelString += "_GHOST"; parameters.m_SignalGen.m_KspaceLineOffset = m_Controls->m_kOffsetBox->value(); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Ghost", DoubleProperty::New(parameters.m_SignalGen.m_KspaceLineOffset)); } else parameters.m_SignalGen.m_KspaceLineOffset = 0; // Aliasing parameters.m_Misc.m_CheckAddAliasingBox = m_Controls->m_AddAliasing->isChecked(); if (m_Controls->m_AddAliasing->isChecked()) { parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; parameters.m_Misc.m_ArtifactModelString += "_ALIASING"; parameters.m_SignalGen.m_CroppingFactor = (100-m_Controls->m_WrapBox->value())/100; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Aliasing", DoubleProperty::New(m_Controls->m_WrapBox->value())); } // Spikes parameters.m_Misc.m_CheckAddSpikesBox = m_Controls->m_AddSpikes->isChecked(); if (m_Controls->m_AddSpikes->isChecked()) { parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; parameters.m_SignalGen.m_Spikes = m_Controls->m_SpikeNumBox->value(); parameters.m_SignalGen.m_SpikeAmplitude = m_Controls->m_SpikeScaleBox->value(); parameters.m_Misc.m_ArtifactModelString += "_SPIKES"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Spikes.Number", IntProperty::New(parameters.m_SignalGen.m_Spikes)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Spikes.Amplitude", DoubleProperty::New(parameters.m_SignalGen.m_SpikeAmplitude)); } // gibbs ringing parameters.m_SignalGen.m_DoAddGibbsRinging = m_Controls->m_AddGibbsRinging->isChecked(); if (m_Controls->m_AddGibbsRinging->isChecked()) { parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Ringing", BoolProperty::New(true)); parameters.m_Misc.m_ArtifactModelString += "_RINGING"; } // add distortions parameters.m_Misc.m_CheckAddDistortionsBox = m_Controls->m_AddDistortions->isChecked(); if (m_Controls->m_AddDistortions->isChecked() && m_Controls->m_FrequencyMapBox->GetSelectedNode().IsNotNull()) { mitk::DataNode::Pointer fMapNode = m_Controls->m_FrequencyMapBox->GetSelectedNode(); mitk::Image* img = dynamic_cast(fMapNode->GetData()); ItkDoubleImgType::Pointer itkImg = ItkDoubleImgType::New(); CastToItkImage< ItkDoubleImgType >(img, itkImg); if (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNull()) // use geometry of frequency map { parameters.m_SignalGen.m_ImageRegion = itkImg->GetLargestPossibleRegion(); parameters.m_SignalGen.m_ImageSpacing = itkImg->GetSpacing(); parameters.m_SignalGen.m_ImageOrigin = itkImg->GetOrigin(); parameters.m_SignalGen.m_ImageDirection = itkImg->GetDirection(); } if (parameters.m_SignalGen.m_ImageRegion.GetSize(0)==itkImg->GetLargestPossibleRegion().GetSize(0) && parameters.m_SignalGen.m_ImageRegion.GetSize(1)==itkImg->GetLargestPossibleRegion().GetSize(1) && parameters.m_SignalGen.m_ImageRegion.GetSize(2)==itkImg->GetLargestPossibleRegion().GetSize(2)) { parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage(itkImg); duplicator->Update(); parameters.m_SignalGen.m_FrequencyMap = duplicator->GetOutput(); parameters.m_Misc.m_ArtifactModelString += "_DISTORTED"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Distortions", BoolProperty::New(true)); } } parameters.m_SignalGen.m_EddyStrength = 0; parameters.m_Misc.m_CheckAddEddyCurrentsBox = m_Controls->m_AddEddy->isChecked(); if (m_Controls->m_AddEddy->isChecked()) { parameters.m_SignalGen.m_EddyStrength = m_Controls->m_EddyGradientStrength->value(); parameters.m_Misc.m_ArtifactModelString += "_EDDY"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Eddy-strength", DoubleProperty::New(parameters.m_SignalGen.m_EddyStrength)); } // Motion parameters.m_SignalGen.m_DoAddMotion = m_Controls->m_AddMotion->isChecked(); parameters.m_SignalGen.m_DoRandomizeMotion = m_Controls->m_RandomMotion->isChecked(); parameters.m_SignalGen.m_Translation[0] = m_Controls->m_MaxTranslationBoxX->value(); parameters.m_SignalGen.m_Translation[1] = m_Controls->m_MaxTranslationBoxY->value(); parameters.m_SignalGen.m_Translation[2] = m_Controls->m_MaxTranslationBoxZ->value(); parameters.m_SignalGen.m_Rotation[0] = m_Controls->m_MaxRotationBoxX->value(); parameters.m_SignalGen.m_Rotation[1] = m_Controls->m_MaxRotationBoxY->value(); parameters.m_SignalGen.m_Rotation[2] = m_Controls->m_MaxRotationBoxZ->value(); if ( m_Controls->m_AddMotion->isChecked() && m_Controls->m_FiberBundleComboBox->GetSelectedNode().IsNotNull() ) { parameters.m_Misc.m_ArtifactModelString += "_MOTION"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Random", BoolProperty::New(parameters.m_SignalGen.m_DoRandomizeMotion)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Translation-x", DoubleProperty::New(parameters.m_SignalGen.m_Translation[0])); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Translation-y", DoubleProperty::New(parameters.m_SignalGen.m_Translation[1])); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Translation-z", DoubleProperty::New(parameters.m_SignalGen.m_Translation[2])); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Rotation-x", DoubleProperty::New(parameters.m_SignalGen.m_Rotation[0])); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Rotation-y", DoubleProperty::New(parameters.m_SignalGen.m_Rotation[1])); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Motion.Rotation-z", DoubleProperty::New(parameters.m_SignalGen.m_Rotation[2])); } // other imaging parameters + parameters.m_SignalGen.m_CoilSensitivityProfile = (SignalGenerationParameters::CoilSensitivityProfile)m_Controls->m_CoilSensBox->currentIndex(); + parameters.m_SignalGen.m_NumberOfCoils = m_Controls->m_NumCoilsBox->value(); + parameters.m_SignalGen.m_PartialFourier = m_Controls->m_PartialFourier->value(); parameters.m_SignalGen.m_ReversePhase = m_Controls->m_ReversePhaseBox->isChecked(); parameters.m_SignalGen.m_tLine = m_Controls->m_LineReadoutTimeBox->value(); parameters.m_SignalGen.m_tInhom = m_Controls->m_T2starBox->value(); parameters.m_SignalGen.m_tEcho = m_Controls->m_TEbox->value(); parameters.m_SignalGen.m_tRep = m_Controls->m_TRbox->value(); parameters.m_SignalGen.m_DoDisablePartialVolume = m_Controls->m_EnforcePureFiberVoxelsBox->isChecked(); parameters.m_SignalGen.m_AxonRadius = m_Controls->m_FiberRadius->value(); parameters.m_SignalGen.m_SignalScale = m_Controls->m_SignalScaleBox->value(); + double voxelVolume = parameters.m_SignalGen.m_ImageSpacing[0]*parameters.m_SignalGen.m_ImageSpacing[1]*parameters.m_SignalGen.m_ImageSpacing[2]; + if ( parameters.m_SignalGen.m_SignalScale*voxelVolume > itk::NumericTraits::max()*0.75 ) + { + parameters.m_SignalGen.m_SignalScale = itk::NumericTraits::max()*0.75/voxelVolume; + m_Controls->m_SignalScaleBox->setValue(parameters.m_SignalGen.m_SignalScale); + QMessageBox::information( NULL, "Warning", "Maximum signal exceeding data type limits. Automatically adjusted to "+QString::number(parameters.m_SignalGen.m_SignalScale)+" to obtain a maximum signal of 75% of the data type maximum. Relaxation and other effects that affect the signal intensities are not accounted for."); + } // adjust echo time if needed - if ( parameters.m_SignalGen.m_tEcho < parameters.m_SignalGen.m_ImageRegion.GetSize(1)*parameters.m_SignalGen.m_tLine ) + int numLines = parameters.m_SignalGen.m_ImageRegion.GetSize(1)+parameters.m_SignalGen.m_ImageRegion.GetSize(1)%2; + if ( parameters.m_SignalGen.m_tEcho < numLines*parameters.m_SignalGen.m_tLine ) { - this->m_Controls->m_TEbox->setValue( parameters.m_SignalGen.m_ImageRegion.GetSize(1)*parameters.m_SignalGen.m_tLine ); + this->m_Controls->m_TEbox->setValue( numLines*parameters.m_SignalGen.m_tLine ); parameters.m_SignalGen.m_tEcho = m_Controls->m_TEbox->value(); - QMessageBox::information( NULL, "Warning", "Echo time is too short! Time not sufficient to read slice. Automaticall adjusted to "+QString::number(parameters.m_SignalGen.m_tEcho)+" ms"); + QMessageBox::information( NULL, "Warning", "Echo time is too short! Time not sufficient to read slice. Automatically adjusted to "+QString::number(parameters.m_SignalGen.m_tEcho)+" ms"); } // Noise parameters.m_Misc.m_CheckAddNoiseBox = m_Controls->m_AddNoise->isChecked(); + parameters.m_SignalGen.m_NoiseVariance = 0; if (m_Controls->m_AddNoise->isChecked()) { double noiseVariance = m_Controls->m_NoiseLevel->value(); + + switch (m_Controls->m_NoiseDistributionBox->currentIndex()) + { + case 0: { - switch (m_Controls->m_NoiseDistributionBox->currentIndex()) + if (noiseVariance>0) { - case 0: + parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; + parameters.m_Misc.m_ArtifactModelString += "_COMPLEX-GAUSSIAN-"; + parameters.m_SignalGen.m_NoiseVariance = m_Controls->m_NoiseLevel->value(); + parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Complex Gaussian")); + } + break; + } + case 1: + { + if (noiseVariance>0) { parameters.m_NoiseModel = new mitk::RicianNoiseModel(); parameters.m_Misc.m_ArtifactModelString += "_RICIAN-"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Rician")); - break; + parameters.m_NoiseModel->SetNoiseVariance(noiseVariance); } - case 1: + break; + } + case 2: + { + if (noiseVariance>0) { parameters.m_NoiseModel = new mitk::ChiSquareNoiseModel(); parameters.m_Misc.m_ArtifactModelString += "_CHISQUARED-"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Chi-squared")); - break; + parameters.m_NoiseModel->SetNoiseVariance(noiseVariance); } - default: + break; + } + default: + { + if (noiseVariance>0) { - parameters.m_NoiseModel = new mitk::RicianNoiseModel(); - parameters.m_Misc.m_ArtifactModelString += "_RICIAN-"; - parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Rician")); - } + parameters.m_SignalGen.m_SimulateKspaceAcquisition = true; + parameters.m_Misc.m_ArtifactModelString += "_COMPLEX-GAUSSIAN-"; + parameters.m_SignalGen.m_NoiseVariance = m_Controls->m_NoiseLevel->value(); + parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Complex Gaussian")); } + break; + } + } + + if (noiseVariance>0) + { + parameters.m_Misc.m_ArtifactModelString += QString::number(noiseVariance).toStdString(); + parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Variance", DoubleProperty::New(noiseVariance)); } - parameters.m_NoiseModel->SetNoiseVariance(noiseVariance); - parameters.m_Misc.m_ArtifactModelString += QString::number(noiseVariance).toStdString(); - parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Noise-Variance", DoubleProperty::New(noiseVariance)); } // adjusting line readout time to the adapted image size needed for the DFT - unsigned int y = parameters.m_SignalGen.m_ImageRegion.GetSize(1); - y += y%2; - if ( y>parameters.m_SignalGen.m_ImageRegion.GetSize(1) ) - parameters.m_SignalGen.m_tLine *= (double)parameters.m_SignalGen.m_ImageRegion.GetSize(1)/y; + // unsigned int y = parameters.m_SignalGen.m_ImageRegion.GetSize(1); + // y += y%2; + // if ( y>parameters.m_SignalGen.m_ImageRegion.GetSize(1) ) + // parameters.m_SignalGen.m_tLine *= (double)parameters.m_SignalGen.m_ImageRegion.GetSize(1)/y; // signal models { // compartment 1 switch (m_Controls->m_Compartment1Box->currentIndex()) { case 0: { mitk::StickModel* model = new mitk::StickModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity(m_Controls->m_StickWidget1->GetD()); model->SetT2(m_Controls->m_StickWidget1->GetT2()); model->SetT1(m_Controls->m_StickWidget1->GetT1()); model->m_CompartmentId = 1; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Stick"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Stick") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D", DoubleProperty::New(m_Controls->m_StickWidget1->GetD()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(model->GetT2()) ); break; } case 1: { mitk::TensorModel* model = new mitk::TensorModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity1(m_Controls->m_ZeppelinWidget1->GetD1()); model->SetDiffusivity2(m_Controls->m_ZeppelinWidget1->GetD2()); model->SetDiffusivity3(m_Controls->m_ZeppelinWidget1->GetD2()); model->SetT2(m_Controls->m_ZeppelinWidget1->GetT2()); model->SetT1(m_Controls->m_ZeppelinWidget1->GetT1()); model->m_CompartmentId = 1; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Zeppelin"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Zeppelin") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D1", DoubleProperty::New(m_Controls->m_ZeppelinWidget1->GetD1()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D2", DoubleProperty::New(m_Controls->m_ZeppelinWidget1->GetD2()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(model->GetT2()) ); break; } case 2: { mitk::TensorModel* model = new mitk::TensorModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity1(m_Controls->m_TensorWidget1->GetD1()); model->SetDiffusivity2(m_Controls->m_TensorWidget1->GetD2()); model->SetDiffusivity3(m_Controls->m_TensorWidget1->GetD3()); model->SetT2(m_Controls->m_TensorWidget1->GetT2()); model->SetT1(m_Controls->m_TensorWidget1->GetT1()); model->m_CompartmentId = 1; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Tensor"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Tensor") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D1", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD1()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D2", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD2()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.D3", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD3()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(model->GetT2()) ); break; } case 3: { mitk::RawShModel* model = new mitk::RawShModel(); parameters.m_SignalGen.m_DoSimulateRelaxation = false; model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetMaxNumKernels(m_Controls->m_PrototypeWidget1->GetNumberOfSamples()); model->SetFaRange(m_Controls->m_PrototypeWidget1->GetMinFa(), m_Controls->m_PrototypeWidget1->GetMaxFa()); model->SetAdcRange(m_Controls->m_PrototypeWidget1->GetMinAdc(), m_Controls->m_PrototypeWidget1->GetMaxAdc()); model->m_CompartmentId = 1; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Prototype"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Prototype") ); break; } } if (m_Controls->m_Comp1VolumeFraction->GetSelectedNode().IsNotNull()) { mitk::DataNode::Pointer volumeNode = m_Controls->m_Comp1VolumeFraction->GetSelectedNode(); ItkDoubleImgType::Pointer comp1VolumeImage = ItkDoubleImgType::New(); mitk::Image* img = dynamic_cast(volumeNode->GetData()); CastToItkImage< ItkDoubleImgType >(img, comp1VolumeImage); parameters.m_FiberModelList.back()->SetVolumeFractionImage(comp1VolumeImage); } // compartment 2 switch (m_Controls->m_Compartment2Box->currentIndex()) { case 0: break; case 1: { mitk::StickModel* model = new mitk::StickModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity(m_Controls->m_StickWidget2->GetD()); model->SetT2(m_Controls->m_StickWidget2->GetT2()); model->SetT1(m_Controls->m_StickWidget2->GetT1()); model->m_CompartmentId = 2; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Stick"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Stick") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D", DoubleProperty::New(m_Controls->m_StickWidget2->GetD()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(model->GetT2()) ); break; } case 2: { mitk::TensorModel* model = new mitk::TensorModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity1(m_Controls->m_ZeppelinWidget2->GetD1()); model->SetDiffusivity2(m_Controls->m_ZeppelinWidget2->GetD2()); model->SetDiffusivity3(m_Controls->m_ZeppelinWidget2->GetD2()); model->SetT2(m_Controls->m_ZeppelinWidget2->GetT2()); model->SetT1(m_Controls->m_ZeppelinWidget2->GetT1()); model->m_CompartmentId = 2; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Zeppelin"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Zeppelin") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D1", DoubleProperty::New(m_Controls->m_ZeppelinWidget2->GetD1()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D2", DoubleProperty::New(m_Controls->m_ZeppelinWidget2->GetD2()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(model->GetT2()) ); break; } case 3: { mitk::TensorModel* model = new mitk::TensorModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity1(m_Controls->m_TensorWidget2->GetD1()); model->SetDiffusivity2(m_Controls->m_TensorWidget2->GetD2()); model->SetDiffusivity3(m_Controls->m_TensorWidget2->GetD3()); model->SetT2(m_Controls->m_TensorWidget2->GetT2()); model->SetT1(m_Controls->m_TensorWidget2->GetT1()); model->m_CompartmentId = 2; parameters.m_FiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Tensor"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Tensor") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D1", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD1()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D2", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD2()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.D3", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD3()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(model->GetT2()) ); break; } } if (m_Controls->m_Comp2VolumeFraction->GetSelectedNode().IsNotNull() && parameters.m_FiberModelList.size()==2) { mitk::DataNode::Pointer volumeNode = m_Controls->m_Comp2VolumeFraction->GetSelectedNode(); ItkDoubleImgType::Pointer comp1VolumeImage = ItkDoubleImgType::New(); mitk::Image* img = dynamic_cast(volumeNode->GetData()); CastToItkImage< ItkDoubleImgType >(img, comp1VolumeImage); parameters.m_FiberModelList.back()->SetVolumeFractionImage(comp1VolumeImage); } // compartment 3 switch (m_Controls->m_Compartment3Box->currentIndex()) { case 0: { mitk::BallModel* model = new mitk::BallModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity(m_Controls->m_BallWidget1->GetD()); model->SetT2(m_Controls->m_BallWidget1->GetT2()); model->SetT1(m_Controls->m_BallWidget1->GetT1()); model->m_CompartmentId = 3; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Ball"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Ball") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.D", DoubleProperty::New(m_Controls->m_BallWidget1->GetD()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(model->GetT2()) ); break; } case 1: { mitk::AstroStickModel* model = new mitk::AstroStickModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity(m_Controls->m_AstrosticksWidget1->GetD()); model->SetT2(m_Controls->m_AstrosticksWidget1->GetT2()); model->SetT1(m_Controls->m_AstrosticksWidget1->GetT1()); model->SetRandomizeSticks(m_Controls->m_AstrosticksWidget1->GetRandomizeSticks()); model->m_CompartmentId = 3; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Astrosticks"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Astrosticks") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.D", DoubleProperty::New(m_Controls->m_AstrosticksWidget1->GetD()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(model->GetT2()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.RandomSticks", BoolProperty::New(m_Controls->m_AstrosticksWidget1->GetRandomizeSticks()) ); break; } case 2: { mitk::DotModel* model = new mitk::DotModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetT2(m_Controls->m_DotWidget1->GetT2()); model->SetT1(m_Controls->m_DotWidget1->GetT1()); model->m_CompartmentId = 3; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Dot"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Dot") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(model->GetT2()) ); break; } case 3: { mitk::RawShModel* model = new mitk::RawShModel(); parameters.m_SignalGen.m_DoSimulateRelaxation = false; model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetMaxNumKernels(m_Controls->m_PrototypeWidget3->GetNumberOfSamples()); model->SetFaRange(m_Controls->m_PrototypeWidget3->GetMinFa(), m_Controls->m_PrototypeWidget3->GetMaxFa()); model->SetAdcRange(m_Controls->m_PrototypeWidget3->GetMinAdc(), m_Controls->m_PrototypeWidget3->GetMaxAdc()); model->m_CompartmentId = 3; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Prototype"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Prototype") ); break; } } if (m_Controls->m_Comp3VolumeFraction->GetSelectedNode().IsNotNull()) { mitk::DataNode::Pointer volumeNode = m_Controls->m_Comp3VolumeFraction->GetSelectedNode(); ItkDoubleImgType::Pointer comp1VolumeImage = ItkDoubleImgType::New(); mitk::Image* img = dynamic_cast(volumeNode->GetData()); CastToItkImage< ItkDoubleImgType >(img, comp1VolumeImage); parameters.m_NonFiberModelList.back()->SetVolumeFractionImage(comp1VolumeImage); } switch (m_Controls->m_Compartment4Box->currentIndex()) { case 0: break; case 1: { mitk::BallModel* model = new mitk::BallModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity(m_Controls->m_BallWidget2->GetD()); model->SetT2(m_Controls->m_BallWidget2->GetT2()); model->SetT1(m_Controls->m_BallWidget2->GetT1()); model->m_CompartmentId = 4; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Ball"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Ball") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.D", DoubleProperty::New(m_Controls->m_BallWidget2->GetD()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(model->GetT2()) ); break; } case 2: { mitk::AstroStickModel* model = new mitk::AstroStickModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetBvalue(parameters.m_SignalGen.m_Bvalue); model->SetDiffusivity(m_Controls->m_AstrosticksWidget2->GetD()); model->SetT2(m_Controls->m_AstrosticksWidget2->GetT2()); model->SetT1(m_Controls->m_AstrosticksWidget2->GetT1()); model->SetRandomizeSticks(m_Controls->m_AstrosticksWidget2->GetRandomizeSticks()); model->m_CompartmentId = 4; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Astrosticks"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Astrosticks") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.D", DoubleProperty::New(m_Controls->m_AstrosticksWidget2->GetD()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(model->GetT2()) ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.RandomSticks", BoolProperty::New(m_Controls->m_AstrosticksWidget2->GetRandomizeSticks()) ); break; } case 3: { mitk::DotModel* model = new mitk::DotModel(); model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetT2(m_Controls->m_DotWidget2->GetT2()); model->SetT1(m_Controls->m_DotWidget2->GetT1()); model->m_CompartmentId = 4; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Dot"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Dot") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(model->GetT2()) ); break; } case 4: { mitk::RawShModel* model = new mitk::RawShModel(); parameters.m_SignalGen.m_DoSimulateRelaxation = false; model->SetGradientList(parameters.m_SignalGen.GetGradientDirections()); model->SetMaxNumKernels(m_Controls->m_PrototypeWidget4->GetNumberOfSamples()); model->SetFaRange(m_Controls->m_PrototypeWidget4->GetMinFa(), m_Controls->m_PrototypeWidget4->GetMaxFa()); model->SetAdcRange(m_Controls->m_PrototypeWidget4->GetMinAdc(), m_Controls->m_PrototypeWidget4->GetMaxAdc()); model->m_CompartmentId = 4; parameters.m_NonFiberModelList.push_back(model); parameters.m_Misc.m_SignalModelString += "Prototype"; parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Prototype") ); break; } } if (m_Controls->m_Comp4VolumeFraction->GetSelectedNode().IsNotNull() && parameters.m_NonFiberModelList.size()==2) { mitk::DataNode::Pointer volumeNode = m_Controls->m_Comp4VolumeFraction->GetSelectedNode(); ItkDoubleImgType::Pointer compVolumeImage = ItkDoubleImgType::New(); mitk::Image* img = dynamic_cast(volumeNode->GetData()); CastToItkImage< ItkDoubleImgType >(img, compVolumeImage); parameters.m_NonFiberModelList.back()->SetVolumeFractionImage(compVolumeImage); } } - // check if comp 3 or 4 volume fraction image is set - if (parameters.m_NonFiberModelList.size()==2 && (parameters.m_NonFiberModelList[0]->GetVolumeFractionImage()==nullptr || parameters.m_NonFiberModelList[1]->GetVolumeFractionImage()==nullptr)) - { - m_Controls->m_Compartment4Box->setCurrentIndex(0); - parameters.m_NonFiberModelList.pop_back(); - QMessageBox::information(NULL, "Compartment 4 disabled", "More than one non-fiber compartment selected but no volume fraction maps set!"); - } - -// RELICT -// parameters.m_SignalGen.m_FiberSeparationThreshold = m_Controls->m_SeparationAngleBox->value(); -// switch (m_Controls->m_DiffusionDirectionBox->currentIndex()) -// { -// case 0: -// parameters.m_SignalGen.m_DiffusionDirectionMode = SignalGenerationParameters::FIBER_TANGENT_DIRECTIONS; -// break; -// case 1: -// parameters.m_SignalGen.m_DiffusionDirectionMode = SignalGenerationParameters::MAIN_FIBER_DIRECTIONS; -// break; -// case 2: -// parameters.m_SignalGen.m_DiffusionDirectionMode = SignalGenerationParameters::RANDOM_DIRECTIONS; -// parameters.m_SignalGen.m_DoAddMotion = false; -// parameters.m_SignalGen.m_DoAddGibbsRinging = false; -// parameters.m_SignalGen.m_KspaceLineOffset = 0.0; -// parameters.m_SignalGen.m_FrequencyMap = NULL; -// parameters.m_SignalGen.m_CroppingFactor = 1.0; -// parameters.m_SignalGen.m_EddyStrength = 0; -// break; -// default: -// parameters.m_SignalGen.m_DiffusionDirectionMode = SignalGenerationParameters::FIBER_TANGENT_DIRECTIONS; -// } + // // check if comp 3 or 4 volume fraction image is set + // if (parameters.m_NonFiberModelList.size()==2 && (parameters.m_NonFiberModelList[0]->GetVolumeFractionImage()==nullptr || parameters.m_NonFiberModelList[1]->GetVolumeFractionImage()==nullptr)) + // { + // m_Controls->m_Compartment4Box->setCurrentIndex(0); + // parameters.m_NonFiberModelList.pop_back(); + // QMessageBox::information(NULL, "Compartment 4 disabled", "More than one non-fiber compartment selected but no volume fraction maps set!"); + // } + + // RELIKT + // parameters.m_SignalGen.m_FiberSeparationThreshold = m_Controls->m_SeparationAngleBox->value(); + // switch (m_Controls->m_DiffusionDirectionBox->currentIndex()) + // { + // case 0: + // parameters.m_SignalGen.m_DiffusionDirectionMode = SignalGenerationParameters::FIBER_TANGENT_DIRECTIONS; + // break; + // case 1: + // parameters.m_SignalGen.m_DiffusionDirectionMode = SignalGenerationParameters::MAIN_FIBER_DIRECTIONS; + // break; + // case 2: + // parameters.m_SignalGen.m_DiffusionDirectionMode = SignalGenerationParameters::RANDOM_DIRECTIONS; + // parameters.m_SignalGen.m_DoAddMotion = false; + // parameters.m_SignalGen.m_DoAddGibbsRinging = false; + // parameters.m_SignalGen.m_KspaceLineOffset = 0.0; + // parameters.m_SignalGen.m_FrequencyMap = NULL; + // parameters.m_SignalGen.m_CroppingFactor = 1.0; + // parameters.m_SignalGen.m_EddyStrength = 0; + // break; + // default: + // parameters.m_SignalGen.m_DiffusionDirectionMode = SignalGenerationParameters::FIBER_TANGENT_DIRECTIONS; + // } parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.SignalScale", IntProperty::New(parameters.m_SignalGen.m_SignalScale)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.FiberRadius", IntProperty::New(parameters.m_SignalGen.m_AxonRadius)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Tinhom", DoubleProperty::New(parameters.m_SignalGen.m_tInhom)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Tline", DoubleProperty::New(parameters.m_SignalGen.m_tLine)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.TE", DoubleProperty::New(parameters.m_SignalGen.m_tEcho)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.b-value", DoubleProperty::New(parameters.m_SignalGen.m_Bvalue)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.NoPartialVolume", BoolProperty::New(parameters.m_SignalGen.m_DoDisablePartialVolume)); parameters.m_Misc.m_ResultNode->AddProperty("Fiberfox.Relaxation", BoolProperty::New(parameters.m_SignalGen.m_DoSimulateRelaxation)); parameters.m_Misc.m_ResultNode->AddProperty("binary", BoolProperty::New(false)); parameters.m_Misc.m_CheckRealTimeFibersBox = m_Controls->m_RealTimeFibers->isChecked(); parameters.m_Misc.m_CheckAdvancedFiberOptionsBox = m_Controls->m_AdvancedOptionsBox->isChecked(); parameters.m_Misc.m_CheckIncludeFiducialsBox = m_Controls->m_IncludeFiducials->isChecked(); parameters.m_Misc.m_CheckConstantRadiusBox = m_Controls->m_ConstantRadiusBox->isChecked(); - switch(m_Controls->m_DistributionBox->currentIndex()) - { - case 0: - parameters.m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; - break; - case 1: - parameters.m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_GAUSSIAN; - break; - default: - parameters.m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; - } - parameters.m_FiberGen.m_Variance = m_Controls->m_VarianceBox->value(); - parameters.m_FiberGen.m_Density = m_Controls->m_FiberDensityBox->value(); - parameters.m_FiberGen.m_Sampling = m_Controls->m_FiberSamplingBox->value(); - parameters.m_FiberGen.m_Tension = m_Controls->m_TensionBox->value(); - parameters.m_FiberGen.m_Continuity = m_Controls->m_ContinuityBox->value(); - parameters.m_FiberGen.m_Bias = m_Controls->m_BiasBox->value(); - parameters.m_FiberGen.m_Rotation[0] = m_Controls->m_XrotBox->value(); - parameters.m_FiberGen.m_Rotation[1] = m_Controls->m_YrotBox->value(); - parameters.m_FiberGen.m_Rotation[2] = m_Controls->m_ZrotBox->value(); - parameters.m_FiberGen.m_Translation[0] = m_Controls->m_XtransBox->value(); - parameters.m_FiberGen.m_Translation[1] = m_Controls->m_YtransBox->value(); - parameters.m_FiberGen.m_Translation[2] = m_Controls->m_ZtransBox->value(); - parameters.m_FiberGen.m_Scale[0] = m_Controls->m_XscaleBox->value(); - parameters.m_FiberGen.m_Scale[1] = m_Controls->m_YscaleBox->value(); - parameters.m_FiberGen.m_Scale[2] = m_Controls->m_ZscaleBox->value(); - return parameters; } void QmitkFiberfoxView::SaveParameters() { FiberfoxParameters<> ffParamaters = UpdateImageParameters(); QString filename = QFileDialog::getSaveFileName( 0, tr("Save Parameters"), m_ParameterFile, tr("Fiberfox Parameters (*.ffp)") ); bool ok = true; bool first = true; bool dosampling = false; mitk::Image::Pointer diffImg = NULL; itk::Image< itk::DiffusionTensor3D< double >, 3 >::Pointer tensorImage = NULL; const int shOrder = 2; typedef itk::AnalyticalDiffusionQballReconstructionImageFilter QballFilterType; QballFilterType::CoefficientImageType::Pointer itkFeatureImage = NULL; ItkDoubleImgType::Pointer adcImage = NULL; for (unsigned int i=0; i* model = NULL; if (i* >(ffParamaters.m_FiberModelList.at(i)); else model = dynamic_cast< mitk::RawShModel<>* >(ffParamaters.m_NonFiberModelList.at(i-ffParamaters.m_FiberModelList.size())); if (model!=0 && model->GetNumberOfKernels()<=0) { if (first==true) { if (QMessageBox::question(NULL, "Prototype signal sampling", "Do you want to sample prototype signals from the selected diffusion-weighted imag and save them?",QMessageBox::Yes,QMessageBox::No)==QMessageBox::Yes) dosampling = true; first = false; if (dosampling && (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNull() || !mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData())))) { QMessageBox::information(NULL, "Parameter file not saved", "No diffusion-weighted image selected to sample signal from."); return; } else if (dosampling) { diffImg = dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()); typedef itk::DiffusionTensor3DReconstructionImageFilter< short, short, double > TensorReconstructionImageFilterType; TensorReconstructionImageFilterType::Pointer filter = TensorReconstructionImageFilterType::New(); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(diffImg, itkVectorImagePointer); filter->SetGradientImage( static_cast( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), itkVectorImagePointer ); filter->SetBValue( static_cast(diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue() ); filter->Update(); tensorImage = filter->GetOutput(); const int NumCoeffs = (shOrder*shOrder + shOrder + 2)/2 + shOrder; QballFilterType::Pointer qballfilter = QballFilterType::New(); qballfilter->SetGradientImage( static_cast( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), itkVectorImagePointer ); qballfilter->SetBValue( static_cast(diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue() ); qballfilter->SetLambda(0.006); qballfilter->SetNormalizationMethod(QballFilterType::QBAR_RAW_SIGNAL); qballfilter->Update(); itkFeatureImage = qballfilter->GetCoefficientImage(); itk::AdcImageFilter< short, double >::Pointer adcFilter = itk::AdcImageFilter< short, double >::New(); adcFilter->SetInput( itkVectorImagePointer ); adcFilter->SetGradientDirections( static_cast( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer() ); adcFilter->SetB_value( static_cast(diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue() ); adcFilter->Update(); adcImage = adcFilter->GetOutput(); } } if (dosampling && diffImg.IsNotNull()) { ok = model->SampleKernels(diffImg, ffParamaters.m_SignalGen.m_MaskImage, tensorImage, itkFeatureImage, adcImage); if (!ok) { QMessageBox::information( NULL, "Parameter file not saved", "No valid prototype signals could be sampled."); return; } } } } ffParamaters.SaveParameters(filename.toStdString()); m_ParameterFile = filename; } void QmitkFiberfoxView::LoadParameters() { QString filename = QFileDialog::getOpenFileName(0, tr("Load Parameters"), QString(itksys::SystemTools::GetFilenamePath(m_ParameterFile.toStdString()).c_str()), tr("Fiberfox Parameters (*.ffp)") ); if(filename.isEmpty() || filename.isNull()) return; m_ParameterFile = filename; - FiberfoxParameters<> parameters; + FiberfoxParameters<> parameters = UpdateImageParameters(); parameters.LoadParameters(filename.toStdString()); + if (parameters.m_MissingTags.size()>0) + { + QString missing("Parameter file might be corrupted. The following parameters could not be read: "); + missing += QString(parameters.m_MissingTags.c_str()); + missing += "\nDefault values have been assigned to the missing parameters."; + QMessageBox::information( NULL, "Warning!", missing); + } + m_Controls->m_RealTimeFibers->setChecked(parameters.m_Misc.m_CheckRealTimeFibersBox); m_Controls->m_AdvancedOptionsBox->setChecked(parameters.m_Misc.m_CheckAdvancedFiberOptionsBox); m_Controls->m_IncludeFiducials->setChecked(parameters.m_Misc.m_CheckIncludeFiducialsBox); m_Controls->m_ConstantRadiusBox->setChecked(parameters.m_Misc.m_CheckConstantRadiusBox); m_Controls->m_DistributionBox->setCurrentIndex(parameters.m_FiberGen.m_Distribution); m_Controls->m_VarianceBox->setValue(parameters.m_FiberGen.m_Variance); m_Controls->m_FiberDensityBox->setValue(parameters.m_FiberGen.m_Density); m_Controls->m_FiberSamplingBox->setValue(parameters.m_FiberGen.m_Sampling); m_Controls->m_TensionBox->setValue(parameters.m_FiberGen.m_Tension); m_Controls->m_ContinuityBox->setValue(parameters.m_FiberGen.m_Continuity); m_Controls->m_BiasBox->setValue(parameters.m_FiberGen.m_Bias); m_Controls->m_XrotBox->setValue(parameters.m_FiberGen.m_Rotation[0]); m_Controls->m_YrotBox->setValue(parameters.m_FiberGen.m_Rotation[1]); m_Controls->m_ZrotBox->setValue(parameters.m_FiberGen.m_Rotation[2]); m_Controls->m_XtransBox->setValue(parameters.m_FiberGen.m_Translation[0]); m_Controls->m_YtransBox->setValue(parameters.m_FiberGen.m_Translation[1]); m_Controls->m_ZtransBox->setValue(parameters.m_FiberGen.m_Translation[2]); m_Controls->m_XscaleBox->setValue(parameters.m_FiberGen.m_Scale[0]); m_Controls->m_YscaleBox->setValue(parameters.m_FiberGen.m_Scale[1]); m_Controls->m_ZscaleBox->setValue(parameters.m_FiberGen.m_Scale[2]); // image generation parameters m_Controls->m_SizeX->setValue(parameters.m_SignalGen.m_ImageRegion.GetSize(0)); m_Controls->m_SizeY->setValue(parameters.m_SignalGen.m_ImageRegion.GetSize(1)); m_Controls->m_SizeZ->setValue(parameters.m_SignalGen.m_ImageRegion.GetSize(2)); m_Controls->m_SpacingX->setValue(parameters.m_SignalGen.m_ImageSpacing[0]); m_Controls->m_SpacingY->setValue(parameters.m_SignalGen.m_ImageSpacing[1]); m_Controls->m_SpacingZ->setValue(parameters.m_SignalGen.m_ImageSpacing[2]); m_Controls->m_NumGradientsBox->setValue(parameters.m_SignalGen.GetNumWeightedVolumes()); m_Controls->m_BvalueBox->setValue(parameters.m_SignalGen.m_Bvalue); m_Controls->m_SignalScaleBox->setValue(parameters.m_SignalGen.m_SignalScale); m_Controls->m_TEbox->setValue(parameters.m_SignalGen.m_tEcho); m_Controls->m_LineReadoutTimeBox->setValue(parameters.m_SignalGen.m_tLine); m_Controls->m_T2starBox->setValue(parameters.m_SignalGen.m_tInhom); m_Controls->m_FiberRadius->setValue(parameters.m_SignalGen.m_AxonRadius); m_Controls->m_RelaxationBox->setChecked(parameters.m_SignalGen.m_DoSimulateRelaxation); m_Controls->m_EnforcePureFiberVoxelsBox->setChecked(parameters.m_SignalGen.m_DoDisablePartialVolume); + m_Controls->m_ReversePhaseBox->setChecked(parameters.m_SignalGen.m_ReversePhase); + m_Controls->m_PartialFourier->setValue(parameters.m_SignalGen.m_PartialFourier); + m_Controls->m_TRbox->setValue(parameters.m_SignalGen.m_tRep); + m_Controls->m_NumCoilsBox->setValue(parameters.m_SignalGen.m_NumberOfCoils); + m_Controls->m_CoilSensBox->setCurrentIndex(parameters.m_SignalGen.m_CoilSensitivityProfile); if (parameters.m_NoiseModel!=NULL) { m_Controls->m_AddNoise->setChecked(parameters.m_Misc.m_CheckAddNoiseBox); if (dynamic_cast*>(parameters.m_NoiseModel)) m_Controls->m_NoiseDistributionBox->setCurrentIndex(0); else if (dynamic_cast*>(parameters.m_NoiseModel)) m_Controls->m_NoiseDistributionBox->setCurrentIndex(1); m_Controls->m_NoiseLevel->setValue(parameters.m_NoiseModel->GetNoiseVariance()); } else - m_Controls->m_AddNoise->setChecked(false); + { + m_Controls->m_AddNoise->setChecked(parameters.m_Misc.m_CheckAddNoiseBox); + m_Controls->m_NoiseLevel->setValue(parameters.m_SignalGen.m_NoiseVariance); + } m_Controls->m_VolumeFractionsBox->setChecked(parameters.m_Misc.m_CheckOutputVolumeFractionsBox); m_Controls->m_AdvancedOptionsBox_2->setChecked(parameters.m_Misc.m_CheckAdvancedSignalOptionsBox); m_Controls->m_AddGhosts->setChecked(parameters.m_Misc.m_CheckAddGhostsBox); m_Controls->m_AddAliasing->setChecked(parameters.m_Misc.m_CheckAddAliasingBox); m_Controls->m_AddDistortions->setChecked(parameters.m_Misc.m_CheckAddDistortionsBox); m_Controls->m_AddSpikes->setChecked(parameters.m_Misc.m_CheckAddSpikesBox); m_Controls->m_AddEddy->setChecked(parameters.m_Misc.m_CheckAddEddyCurrentsBox); m_Controls->m_kOffsetBox->setValue(parameters.m_SignalGen.m_KspaceLineOffset); m_Controls->m_WrapBox->setValue(100*(1-parameters.m_SignalGen.m_CroppingFactor)); m_Controls->m_SpikeNumBox->setValue(parameters.m_SignalGen.m_Spikes); m_Controls->m_SpikeScaleBox->setValue(parameters.m_SignalGen.m_SpikeAmplitude); m_Controls->m_EddyGradientStrength->setValue(parameters.m_SignalGen.m_EddyStrength); m_Controls->m_AddGibbsRinging->setChecked(parameters.m_SignalGen.m_DoAddGibbsRinging); m_Controls->m_AddMotion->setChecked(parameters.m_SignalGen.m_DoAddMotion); m_Controls->m_RandomMotion->setChecked(parameters.m_SignalGen.m_DoRandomizeMotion); m_Controls->m_MaxTranslationBoxX->setValue(parameters.m_SignalGen.m_Translation[0]); m_Controls->m_MaxTranslationBoxY->setValue(parameters.m_SignalGen.m_Translation[1]); m_Controls->m_MaxTranslationBoxZ->setValue(parameters.m_SignalGen.m_Translation[2]); m_Controls->m_MaxRotationBoxX->setValue(parameters.m_SignalGen.m_Rotation[0]); m_Controls->m_MaxRotationBoxY->setValue(parameters.m_SignalGen.m_Rotation[1]); m_Controls->m_MaxRotationBoxZ->setValue(parameters.m_SignalGen.m_Rotation[2]); - m_Controls->m_DiffusionDirectionBox->setCurrentIndex(parameters.m_SignalGen.m_DiffusionDirectionMode); - m_Controls->m_SeparationAngleBox->setValue(parameters.m_SignalGen.m_FiberSeparationThreshold); m_Controls->m_Compartment1Box->setCurrentIndex(0); m_Controls->m_Compartment2Box->setCurrentIndex(0); m_Controls->m_Compartment3Box->setCurrentIndex(0); m_Controls->m_Compartment4Box->setCurrentIndex(0); for (unsigned int i=0; i* signalModel = NULL; if (iGetVolumeFractionImage().IsNotNull() ) + { + compVolNode = mitk::DataNode::New(); + mitk::Image::Pointer image = mitk::Image::New(); + image->InitializeByItk(signalModel->GetVolumeFractionImage().GetPointer()); + image->SetVolume(signalModel->GetVolumeFractionImage()->GetBufferPointer()); + + compVolNode->SetData( image ); + compVolNode->SetName("Compartment volume "+QString::number(signalModel->m_CompartmentId).toStdString()); + GetDataStorage()->Add(compVolNode); + } + switch (signalModel->m_CompartmentId) { case 1: { + if (compVolNode.IsNotNull()) + m_Controls->m_Comp1VolumeFraction->SetSelectedNode(compVolNode); if (dynamic_cast*>(signalModel)) { mitk::StickModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_StickWidget1->SetT2(model->GetT2()); + m_Controls->m_StickWidget1->SetT1(model->GetT1()); m_Controls->m_StickWidget1->SetD(model->GetDiffusivity()); m_Controls->m_Compartment1Box->setCurrentIndex(0); break; } else if (dynamic_cast*>(signalModel)) { mitk::TensorModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_TensorWidget1->SetT2(model->GetT2()); + m_Controls->m_TensorWidget1->SetT1(model->GetT1()); m_Controls->m_TensorWidget1->SetD1(model->GetDiffusivity1()); m_Controls->m_TensorWidget1->SetD2(model->GetDiffusivity2()); m_Controls->m_TensorWidget1->SetD3(model->GetDiffusivity3()); m_Controls->m_Compartment1Box->setCurrentIndex(2); break; } else if (dynamic_cast*>(signalModel)) { mitk::RawShModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_PrototypeWidget1->SetNumberOfSamples(model->GetMaxNumKernels()); m_Controls->m_PrototypeWidget1->SetMinFa(model->GetFaRange().first); m_Controls->m_PrototypeWidget1->SetMaxFa(model->GetFaRange().second); m_Controls->m_PrototypeWidget1->SetMinAdc(model->GetAdcRange().first); m_Controls->m_PrototypeWidget1->SetMaxAdc(model->GetAdcRange().second); m_Controls->m_Compartment1Box->setCurrentIndex(3); break; } break; } case 2: { + if (compVolNode.IsNotNull()) + m_Controls->m_Comp2VolumeFraction->SetSelectedNode(compVolNode); if (dynamic_cast*>(signalModel)) { mitk::StickModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_StickWidget2->SetT2(model->GetT2()); + m_Controls->m_StickWidget2->SetT1(model->GetT1()); m_Controls->m_StickWidget2->SetD(model->GetDiffusivity()); m_Controls->m_Compartment2Box->setCurrentIndex(1); break; } else if (dynamic_cast*>(signalModel)) { mitk::TensorModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_TensorWidget2->SetT2(model->GetT2()); + m_Controls->m_TensorWidget2->SetT1(model->GetT1()); m_Controls->m_TensorWidget2->SetD1(model->GetDiffusivity1()); m_Controls->m_TensorWidget2->SetD2(model->GetDiffusivity2()); m_Controls->m_TensorWidget2->SetD3(model->GetDiffusivity3()); m_Controls->m_Compartment2Box->setCurrentIndex(3); break; } break; } case 3: { + if (compVolNode.IsNotNull()) + m_Controls->m_Comp3VolumeFraction->SetSelectedNode(compVolNode); if (dynamic_cast*>(signalModel)) { mitk::BallModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_BallWidget1->SetT2(model->GetT2()); + m_Controls->m_BallWidget1->SetT1(model->GetT1()); m_Controls->m_BallWidget1->SetD(model->GetDiffusivity()); m_Controls->m_Compartment3Box->setCurrentIndex(0); break; } else if (dynamic_cast*>(signalModel)) { mitk::AstroStickModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_AstrosticksWidget1->SetT2(model->GetT2()); + m_Controls->m_AstrosticksWidget1->SetT1(model->GetT1()); m_Controls->m_AstrosticksWidget1->SetD(model->GetDiffusivity()); m_Controls->m_AstrosticksWidget1->SetRandomizeSticks(model->GetRandomizeSticks()); m_Controls->m_Compartment3Box->setCurrentIndex(1); break; } else if (dynamic_cast*>(signalModel)) { mitk::DotModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_DotWidget1->SetT2(model->GetT2()); + m_Controls->m_DotWidget1->SetT1(model->GetT1()); m_Controls->m_Compartment3Box->setCurrentIndex(2); break; } else if (dynamic_cast*>(signalModel)) { mitk::RawShModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_PrototypeWidget3->SetNumberOfSamples(model->GetMaxNumKernels()); m_Controls->m_PrototypeWidget3->SetMinFa(model->GetFaRange().first); m_Controls->m_PrototypeWidget3->SetMaxFa(model->GetFaRange().second); m_Controls->m_PrototypeWidget3->SetMinAdc(model->GetAdcRange().first); m_Controls->m_PrototypeWidget3->SetMaxAdc(model->GetAdcRange().second); m_Controls->m_Compartment3Box->setCurrentIndex(3); break; } break; } case 4: { + if (compVolNode.IsNotNull()) + m_Controls->m_Comp4VolumeFraction->SetSelectedNode(compVolNode); if (dynamic_cast*>(signalModel)) { mitk::BallModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_BallWidget2->SetT2(model->GetT2()); + m_Controls->m_BallWidget2->SetT1(model->GetT1()); m_Controls->m_BallWidget2->SetD(model->GetDiffusivity()); m_Controls->m_Compartment4Box->setCurrentIndex(1); break; } else if (dynamic_cast*>(signalModel)) { mitk::AstroStickModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_AstrosticksWidget2->SetT2(model->GetT2()); + m_Controls->m_AstrosticksWidget2->SetT1(model->GetT1()); m_Controls->m_AstrosticksWidget2->SetD(model->GetDiffusivity()); m_Controls->m_AstrosticksWidget2->SetRandomizeSticks(model->GetRandomizeSticks()); m_Controls->m_Compartment4Box->setCurrentIndex(2); break; } else if (dynamic_cast*>(signalModel)) { mitk::DotModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_DotWidget2->SetT2(model->GetT2()); + m_Controls->m_DotWidget2->SetT1(model->GetT1()); m_Controls->m_Compartment4Box->setCurrentIndex(3); break; } else if (dynamic_cast*>(signalModel)) { mitk::RawShModel<>* model = dynamic_cast*>(signalModel); m_Controls->m_PrototypeWidget4->SetNumberOfSamples(model->GetMaxNumKernels()); m_Controls->m_PrototypeWidget4->SetMinFa(model->GetFaRange().first); m_Controls->m_PrototypeWidget4->SetMaxFa(model->GetFaRange().second); m_Controls->m_PrototypeWidget4->SetMinAdc(model->GetAdcRange().first); m_Controls->m_PrototypeWidget4->SetMaxAdc(model->GetAdcRange().second); m_Controls->m_Compartment4Box->setCurrentIndex(4); break; } break; } } } + + if ( parameters.m_SignalGen.m_MaskImage ) + { + mitk::Image::Pointer image = mitk::Image::New(); + image->InitializeByItk(parameters.m_SignalGen.m_MaskImage.GetPointer()); + image->SetVolume(parameters.m_SignalGen.m_MaskImage->GetBufferPointer()); + + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData( image ); + node->SetName("Tissue mask"); + GetDataStorage()->Add(node); + m_Controls->m_MaskComboBox->SetSelectedNode(node); + } + + if ( parameters.m_SignalGen.m_FrequencyMap ) + { + mitk::Image::Pointer image = mitk::Image::New(); + image->InitializeByItk(parameters.m_SignalGen.m_FrequencyMap.GetPointer()); + image->SetVolume(parameters.m_SignalGen.m_FrequencyMap->GetBufferPointer()); + + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData( image ); + node->SetName("Frequency map"); + GetDataStorage()->Add(node); + m_Controls->m_FrequencyMapBox->SetSelectedNode(node); + } } void QmitkFiberfoxView::ShowAdvancedOptions(int state) { if (state) { m_Controls->m_AdvancedFiberOptionsFrame->setVisible(true); m_Controls->m_AdvancedSignalOptionsFrame->setVisible(true); m_Controls->m_AdvancedOptionsBox->setChecked(true); m_Controls->m_AdvancedOptionsBox_2->setChecked(true); } else { m_Controls->m_AdvancedFiberOptionsFrame->setVisible(false); m_Controls->m_AdvancedSignalOptionsFrame->setVisible(false); m_Controls->m_AdvancedOptionsBox->setChecked(false); m_Controls->m_AdvancedOptionsBox_2->setChecked(false); } } void QmitkFiberfoxView::Comp1ModelFrameVisibility(int index) { m_Controls->m_StickWidget1->setVisible(false); m_Controls->m_ZeppelinWidget1->setVisible(false); m_Controls->m_TensorWidget1->setVisible(false); m_Controls->m_PrototypeWidget1->setVisible(false); switch (index) { case 0: m_Controls->m_StickWidget1->setVisible(true); break; case 1: m_Controls->m_ZeppelinWidget1->setVisible(true); break; case 2: m_Controls->m_TensorWidget1->setVisible(true); break; case 3: m_Controls->m_PrototypeWidget1->setVisible(true); break; } } void QmitkFiberfoxView::Comp2ModelFrameVisibility(int index) { m_Controls->m_StickWidget2->setVisible(false); m_Controls->m_ZeppelinWidget2->setVisible(false); m_Controls->m_TensorWidget2->setVisible(false); m_Controls->m_Comp2FractionFrame->setVisible(false); switch (index) { case 0: break; case 1: m_Controls->m_StickWidget2->setVisible(true); m_Controls->m_Comp2FractionFrame->setVisible(true); break; case 2: m_Controls->m_ZeppelinWidget2->setVisible(true); m_Controls->m_Comp2FractionFrame->setVisible(true); break; case 3: m_Controls->m_TensorWidget2->setVisible(true); m_Controls->m_Comp2FractionFrame->setVisible(true); break; } } void QmitkFiberfoxView::Comp3ModelFrameVisibility(int index) { m_Controls->m_BallWidget1->setVisible(false); m_Controls->m_AstrosticksWidget1->setVisible(false); m_Controls->m_DotWidget1->setVisible(false); m_Controls->m_PrototypeWidget3->setVisible(false); switch (index) { case 0: m_Controls->m_BallWidget1->setVisible(true); break; case 1: m_Controls->m_AstrosticksWidget1->setVisible(true); break; case 2: m_Controls->m_DotWidget1->setVisible(true); break; case 3: m_Controls->m_PrototypeWidget3->setVisible(true); break; } } void QmitkFiberfoxView::Comp4ModelFrameVisibility(int index) { m_Controls->m_BallWidget2->setVisible(false); m_Controls->m_AstrosticksWidget2->setVisible(false); m_Controls->m_DotWidget2->setVisible(false); m_Controls->m_PrototypeWidget4->setVisible(false); m_Controls->m_Comp4FractionFrame->setVisible(false); switch (index) { case 0: break; case 1: m_Controls->m_BallWidget2->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; case 2: m_Controls->m_AstrosticksWidget2->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; case 3: m_Controls->m_DotWidget2->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; case 4: m_Controls->m_PrototypeWidget4->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; } } void QmitkFiberfoxView::OnConstantRadius(int value) { if (value>0 && m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnAddMotion(int value) { if (value>0) m_Controls->m_MotionArtifactFrame->setVisible(true); else m_Controls->m_MotionArtifactFrame->setVisible(false); } void QmitkFiberfoxView::OnAddAliasing(int value) { if (value>0) m_Controls->m_AliasingFrame->setVisible(true); else m_Controls->m_AliasingFrame->setVisible(false); } void QmitkFiberfoxView::OnAddSpikes(int value) { if (value>0) m_Controls->m_SpikeFrame->setVisible(true); else m_Controls->m_SpikeFrame->setVisible(false); } void QmitkFiberfoxView::OnAddEddy(int value) { if (value>0) m_Controls->m_EddyFrame->setVisible(true); else m_Controls->m_EddyFrame->setVisible(false); } void QmitkFiberfoxView::OnAddDistortions(int value) { if (value>0) m_Controls->m_DistortionsFrame->setVisible(true); else m_Controls->m_DistortionsFrame->setVisible(false); } void QmitkFiberfoxView::OnAddGhosts(int value) { if (value>0) m_Controls->m_GhostFrame->setVisible(true); else m_Controls->m_GhostFrame->setVisible(false); } void QmitkFiberfoxView::OnAddNoise(int value) { if (value>0) m_Controls->m_NoiseFrame->setVisible(true); else m_Controls->m_NoiseFrame->setVisible(false); } void QmitkFiberfoxView::OnDistributionChanged(int value) { if (value==1) m_Controls->m_VarianceBox->setVisible(true); else m_Controls->m_VarianceBox->setVisible(false); if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnVarianceChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFiberDensityChanged(int) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFiberSamplingChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnTensionChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnContinuityChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnBiasChanged(double) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::AlignOnGrid() { for (unsigned int i=0; i(m_SelectedFiducials.at(i)->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::DataStorage::SetOfObjects::ConstPointer parentFibs = GetDataStorage()->GetSources(m_SelectedFiducials.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = parentFibs->begin(); it != parentFibs->end(); ++it ) { mitk::DataNode::Pointer pFibNode = *it; if ( pFibNode.IsNotNull() && dynamic_cast(pFibNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer parentImgs = GetDataStorage()->GetSources(pFibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = parentImgs->begin(); it2 != parentImgs->end(); ++it2 ) { mitk::DataNode::Pointer pImgNode = *it2; if ( pImgNode.IsNotNull() && dynamic_cast(pImgNode->GetData()) ) { mitk::Image::Pointer img = dynamic_cast(pImgNode->GetData()); mitk::BaseGeometry::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); break; } } break; } } } for(unsigned int i=0; iGetSources(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it = sources->begin(); it != sources->end(); ++it ) { mitk::DataNode::Pointer imgNode = *it; if ( imgNode.IsNotNull() && dynamic_cast(imgNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::Image::Pointer img = dynamic_cast(imgNode->GetData()); mitk::BaseGeometry::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); } } break; } } } for(unsigned int i=0; i(m_SelectedImages.at(i)->GetData()); mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(m_SelectedImages.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = derivations->begin(); it != derivations->end(); ++it ) { mitk::DataNode::Pointer fibNode = *it; if ( fibNode.IsNotNull() && dynamic_cast(fibNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer derivations2 = GetDataStorage()->GetDerivations(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations2->begin(); it2 != derivations2->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::BaseGeometry::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); } } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFlipButton() { if (m_SelectedFiducial.IsNull()) return; std::map::iterator it = m_DataNodeToPlanarFigureData.find(m_SelectedFiducial.GetPointer()); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; data.m_Flipped += 1; data.m_Flipped %= 2; } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } QmitkFiberfoxView::GradientListType QmitkFiberfoxView::GenerateHalfShell(int NPoints) { NPoints *= 2; GradientListType pointshell; int numB0 = NPoints/20; if (numB0==0) numB0=1; GradientType g; g.Fill(0.0); for (int i=0; i theta; theta.set_size(NPoints); vnl_vector phi; phi.set_size(NPoints); double C = sqrt(4*M_PI); phi(0) = 0.0; phi(NPoints-1) = 0.0; for(int i=0; i0 && i std::vector > QmitkFiberfoxView::MakeGradientList() { std::vector > retval; vnl_matrix_fixed* U = itk::PointShell >::DistributePointShell(); // Add 0 vector for B0 int numB0 = ndirs/10; if (numB0==0) numB0=1; itk::Vector v; v.Fill(0.0); for (int i=0; i v; v[0] = U->get(0,i); v[1] = U->get(1,i); v[2] = U->get(2,i); retval.push_back(v); } return retval; } void QmitkFiberfoxView::OnAddBundle() { if (m_SelectedImageNode.IsNull()) return; mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedImageNode); mitk::FiberBundle::Pointer bundle = mitk::FiberBundle::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( bundle ); QString name = QString("Bundle_%1").arg(children->size()); node->SetName(name.toStdString()); m_SelectedBundles.push_back(node); UpdateGui(); GetDataStorage()->Add(node, m_SelectedImageNode); } void QmitkFiberfoxView::OnDrawROI() { if (m_SelectedBundles.empty()) OnAddBundle(); if (m_SelectedBundles.empty()) return; mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedBundles.at(0)); mitk::PlanarEllipse::Pointer figure = mitk::PlanarEllipse::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( figure ); node->SetBoolProperty("planarfigure.3drendering", true); node->SetBoolProperty("planarfigure.3drendering.fill", true); QList nodes = this->GetDataManagerSelection(); for( int i=0; iSetSelected(false); m_SelectedFiducial = node; QString name = QString("Fiducial_%1").arg(children->size()); node->SetName(name.toStdString()); node->SetSelected(true); this->DisableCrosshairNavigation(); mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New(); us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" ); figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule ); figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule ); figureInteractor->SetDataNode( node ); } UpdateGui(); GetDataStorage()->Add(node, m_SelectedBundles.at(0)); } bool CompareLayer(mitk::DataNode::Pointer i,mitk::DataNode::Pointer j) { int li = -1; i->GetPropertyValue("layer", li); int lj = -1; j->GetPropertyValue("layer", lj); return liGetSources(m_SelectedFiducial); for( mitk::DataStorage::SetOfObjects::const_iterator it = parents->begin(); it != parents->end(); ++it ) if(dynamic_cast((*it)->GetData())) m_SelectedBundles.push_back(*it); if (m_SelectedBundles.empty()) return; } - FiberfoxParameters parameters; // = UpdateImageParameters(); + FiberfoxParameters parameters = UpdateImageParameters(false); for (unsigned int i=0; iGetDerivations(m_SelectedBundles.at(i)); std::vector< mitk::DataNode::Pointer > childVector; for( mitk::DataStorage::SetOfObjects::const_iterator it = children->begin(); it != children->end(); ++it ) childVector.push_back(*it); sort(childVector.begin(), childVector.end(), CompareLayer); vector< mitk::PlanarEllipse::Pointer > fib; vector< unsigned int > flip; float radius = 1; int count = 0; for( std::vector< mitk::DataNode::Pointer >::const_iterator it = childVector.begin(); it != childVector.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { mitk::PlanarEllipse* ellipse = dynamic_cast(node->GetData()); if (m_Controls->m_ConstantRadiusBox->isChecked()) { ellipse->SetTreatAsCircle(true); mitk::Point2D c = ellipse->GetControlPoint(0); mitk::Point2D p = ellipse->GetControlPoint(1); mitk::Vector2D v = p-c; if (count==0) { radius = v.GetVnlVector().magnitude(); ellipse->SetControlPoint(1, p); ellipse->Modified(); } else { v.Normalize(); v *= radius; ellipse->SetControlPoint(1, c+v); ellipse->Modified(); } } fib.push_back(ellipse); std::map::iterator it = m_DataNodeToPlanarFigureData.find(node.GetPointer()); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; flip.push_back(data.m_Flipped); } else flip.push_back(0); } count++; } if (fib.size()>1) { parameters.m_FiberGen.m_Fiducials.push_back(fib); parameters.m_FiberGen.m_FlipList.push_back(flip); } else if (fib.size()>0) m_SelectedBundles.at(i)->SetData( mitk::FiberBundle::New() ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } itk::FibersFromPlanarFiguresFilter::Pointer filter = itk::FibersFromPlanarFiguresFilter::New(); filter->SetParameters(parameters.m_FiberGen); filter->Update(); vector< mitk::FiberBundle::Pointer > fiberBundles = filter->GetFiberBundles(); for (unsigned int i=0; iSetData( fiberBundles.at(i) ); if (fiberBundles.at(i)->GetNumFibers()>50000) m_SelectedBundles.at(i)->SetVisibility(false); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::GenerateImage() { if (m_Controls->m_FiberBundleComboBox->GetSelectedNode().IsNull() && !mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( m_Controls->m_TemplateComboBox->GetSelectedNode())) { mitk::Image::Pointer image = mitk::ImageGenerator::GenerateGradientImage( m_Controls->m_SizeX->value(), m_Controls->m_SizeY->value(), m_Controls->m_SizeZ->value(), m_Controls->m_SpacingX->value(), m_Controls->m_SpacingY->value(), m_Controls->m_SpacingZ->value()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("Dummy"); unsigned int window = m_Controls->m_SizeX->value()*m_Controls->m_SizeY->value()*m_Controls->m_SizeZ->value(); unsigned int level = window/2; mitk::LevelWindow lw; lw.SetLevelWindow(level, window); node->SetProperty( "levelwindow", mitk::LevelWindowProperty::New( lw ) ); GetDataStorage()->Add(node); m_SelectedImageNode = node; mitk::BaseData::Pointer basedata = node->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } UpdateGui(); QMessageBox::information(NULL, "Template image generated", "You have selected no fiber bundle or diffusion-weighted image, which can be used to simulate a new diffusion-weighted image. A template image with the specified geometry has been generated that can be used to draw artificial fibers (see tab 'Fiber Definition')."); } else if (m_Controls->m_FiberBundleComboBox->GetSelectedNode().IsNotNull()) SimulateImageFromFibers(m_Controls->m_FiberBundleComboBox->GetSelectedNode()); else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( m_Controls->m_TemplateComboBox->GetSelectedNode()) ) SimulateForExistingDwi(m_Controls->m_TemplateComboBox->GetSelectedNode()); else QMessageBox::information(NULL, "No image generated", "You have selected no fiber bundle or diffusion-weighted image, which can be used to simulate a new diffusion-weighted image."); } void QmitkFiberfoxView::SimulateForExistingDwi(mitk::DataNode* imageNode) { bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(imageNode->GetData())) ); if ( !isDiffusionImage ) { return; } FiberfoxParameters parameters = UpdateImageParameters(); if (parameters.m_NoiseModel==NULL && parameters.m_SignalGen.m_Spikes==0 && parameters.m_SignalGen.m_FrequencyMap.IsNull() && parameters.m_SignalGen.m_KspaceLineOffset<=0.000001 && !parameters.m_SignalGen.m_DoAddGibbsRinging && !(parameters.m_SignalGen.m_EddyStrength>0) && parameters.m_SignalGen.m_CroppingFactor>0.999) { QMessageBox::information( NULL, "Simulation cancelled", "No valid artifact enabled! Motion artifacts and relaxation effects can NOT be added to an existing diffusion weighted image."); return; } mitk::Image::Pointer diffImg = dynamic_cast(imageNode->GetData()); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(diffImg, itkVectorImagePointer); m_ArtifactsToDwiFilter = itk::AddArtifactsToDwiImageFilter< short >::New(); m_ArtifactsToDwiFilter->SetInput(itkVectorImagePointer); parameters.m_Misc.m_ParentNode = imageNode; m_ArtifactsToDwiFilter->SetParameters(parameters); m_Worker.m_FilterType = 1; m_Thread.start(QThread::LowestPriority); } void QmitkFiberfoxView::SimulateImageFromFibers(mitk::DataNode* fiberNode) { mitk::FiberBundle::Pointer fiberBundle = dynamic_cast(fiberNode->GetData()); if (fiberBundle->GetNumFibers()<=0) return; FiberfoxParameters parameters = UpdateImageParameters(); m_TractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); parameters.m_Misc.m_ParentNode = fiberNode; if (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull() && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()))) { bool first = true; bool ok = true; mitk::Image::Pointer diffImg = dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()); itk::Image< itk::DiffusionTensor3D< double >, 3 >::Pointer tensorImage = NULL; const int shOrder = 2; typedef itk::AnalyticalDiffusionQballReconstructionImageFilter QballFilterType; QballFilterType::CoefficientImageType::Pointer itkFeatureImage = NULL; ItkDoubleImgType::Pointer adcImage = NULL; for (unsigned int i=0; i* model = NULL; if (i* >(parameters.m_FiberModelList.at(i)); else model = dynamic_cast< mitk::RawShModel<>* >(parameters.m_NonFiberModelList.at(i-parameters.m_FiberModelList.size())); if (model!=0 && model->GetNumberOfKernels()<=0) { if (first==true) { ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(diffImg, itkVectorImagePointer); typedef itk::DiffusionTensor3DReconstructionImageFilter< short, short, double > TensorReconstructionImageFilterType; TensorReconstructionImageFilterType::Pointer filter = TensorReconstructionImageFilterType::New(); filter->SetGradientImage( static_cast( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), itkVectorImagePointer ); filter->SetBValue( static_cast(diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue() ); filter->Update(); tensorImage = filter->GetOutput(); const int NumCoeffs = (shOrder*shOrder + shOrder + 2)/2 + shOrder; QballFilterType::Pointer qballfilter = QballFilterType::New(); qballfilter->SetGradientImage( static_cast( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), itkVectorImagePointer ); qballfilter->SetBValue( static_cast(diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue() ); qballfilter->SetLambda(0.006); qballfilter->SetNormalizationMethod(QballFilterType::QBAR_RAW_SIGNAL); qballfilter->Update(); itkFeatureImage = qballfilter->GetCoefficientImage(); itk::AdcImageFilter< short, double >::Pointer adcFilter = itk::AdcImageFilter< short, double >::New(); adcFilter->SetInput( itkVectorImagePointer ); adcFilter->SetGradientDirections( static_cast( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer() ); adcFilter->SetB_value( static_cast(diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue() ); adcFilter->Update(); adcImage = adcFilter->GetOutput(); } ok = model->SampleKernels(diffImg, parameters.m_SignalGen.m_MaskImage, tensorImage, itkFeatureImage, adcImage); if (!ok) break; } } if (!ok) { QMessageBox::information( NULL, "Simulation cancelled", "No valid prototype signals could be sampled."); return; } } else if ( m_Controls->m_Compartment1Box->currentIndex()==3 || m_Controls->m_Compartment3Box->currentIndex()==3 || m_Controls->m_Compartment4Box->currentIndex()==4 ) { QMessageBox::information( NULL, "Simulation cancelled", "Prototype signal but no diffusion-weighted image selected to sample signal from."); return; } m_TractsToDwiFilter->SetParameters(parameters); m_TractsToDwiFilter->SetFiberBundle(fiberBundle); m_Worker.m_FilterType = 0; m_Thread.start(QThread::LowestPriority); } void QmitkFiberfoxView::ApplyTransform() { vector< mitk::DataNode::Pointer > selectedBundles; for(unsigned int i=0; iGetDerivations(m_SelectedImages.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = derivations->begin(); it != derivations->end(); ++it ) { mitk::DataNode::Pointer fibNode = *it; if ( fibNode.IsNotNull() && dynamic_cast(fibNode->GetData()) ) selectedBundles.push_back(fibNode); } } if (selectedBundles.empty()) selectedBundles = m_SelectedBundles2; if (!selectedBundles.empty()) { for (std::vector::const_iterator it = selectedBundles.begin(); it!=selectedBundles.end(); ++it) { mitk::FiberBundle::Pointer fib = dynamic_cast((*it)->GetData()); fib->RotateAroundAxis(m_Controls->m_XrotBox->value(), m_Controls->m_YrotBox->value(), m_Controls->m_ZrotBox->value()); fib->TranslateFibers(m_Controls->m_XtransBox->value(), m_Controls->m_YtransBox->value(), m_Controls->m_ZtransBox->value()); fib->ScaleFibers(m_Controls->m_XscaleBox->value(), m_Controls->m_YscaleBox->value(), m_Controls->m_ZscaleBox->value()); // handle child fiducials if (m_Controls->m_IncludeFiducials->isChecked()) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse* pe = dynamic_cast(fiducialNode->GetData()); mitk::BaseGeometry* geom = pe->GetGeometry(); // translate mitk::Vector3D world; world[0] = m_Controls->m_XtransBox->value(); world[1] = m_Controls->m_YtransBox->value(); world[2] = m_Controls->m_ZtransBox->value(); geom->Translate(world); // calculate rotation matrix double x = m_Controls->m_XrotBox->value()*M_PI/180; double y = m_Controls->m_YrotBox->value()*M_PI/180; double z = m_Controls->m_ZrotBox->value()*M_PI/180; itk::Matrix< double, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; itk::Matrix< double, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; itk::Matrix< double, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< double, 3, 3 > rot = rotZ*rotY*rotX; // transform control point coordinate into geometry translation geom->SetOrigin(pe->GetWorldControlPoint(0)); mitk::Point2D cp; cp.Fill(0.0); pe->SetControlPoint(0, cp); // rotate fiducial geom->GetIndexToWorldTransform()->SetMatrix(rot*geom->GetIndexToWorldTransform()->GetMatrix()); // implicit translation mitk::Vector3D trans; trans[0] = geom->GetOrigin()[0]-fib->GetGeometry()->GetCenter()[0]; trans[1] = geom->GetOrigin()[1]-fib->GetGeometry()->GetCenter()[1]; trans[2] = geom->GetOrigin()[2]-fib->GetGeometry()->GetCenter()[2]; mitk::Vector3D newWc = rot*trans; newWc = newWc-trans; geom->Translate(newWc); pe->Modified(); } } } } } else { for (unsigned int i=0; i(m_SelectedFiducials.at(i)->GetData()); mitk::BaseGeometry* geom = pe->GetGeometry(); // translate mitk::Vector3D world; world[0] = m_Controls->m_XtransBox->value(); world[1] = m_Controls->m_YtransBox->value(); world[2] = m_Controls->m_ZtransBox->value(); geom->Translate(world); // calculate rotation matrix double x = m_Controls->m_XrotBox->value()*M_PI/180; double y = m_Controls->m_YrotBox->value()*M_PI/180; double z = m_Controls->m_ZrotBox->value()*M_PI/180; itk::Matrix< double, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; itk::Matrix< double, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; itk::Matrix< double, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< double, 3, 3 > rot = rotZ*rotY*rotX; // transform control point coordinate into geometry translation geom->SetOrigin(pe->GetWorldControlPoint(0)); mitk::Point2D cp; cp.Fill(0.0); pe->SetControlPoint(0, cp); // rotate fiducial geom->GetIndexToWorldTransform()->SetMatrix(rot*geom->GetIndexToWorldTransform()->GetMatrix()); pe->Modified(); } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::CopyBundles() { if ( m_SelectedBundles.size()<1 ){ QMessageBox::information( NULL, "Warning", "Select at least one fiber bundle!"); MITK_WARN("QmitkFiberFoxView") << "Select at least one fiber bundle!"; return; } for (std::vector::const_iterator it = m_SelectedBundles.begin(); it!=m_SelectedBundles.end(); ++it) { // find parent image mitk::DataNode::Pointer parentNode; mitk::DataStorage::SetOfObjects::ConstPointer parentImgs = GetDataStorage()->GetSources(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = parentImgs->begin(); it2 != parentImgs->end(); ++it2 ) { mitk::DataNode::Pointer pImgNode = *it2; if ( pImgNode.IsNotNull() && dynamic_cast(pImgNode->GetData()) ) { parentNode = pImgNode; break; } } mitk::FiberBundle::Pointer fib = dynamic_cast((*it)->GetData()); mitk::FiberBundle::Pointer newBundle = fib->GetDeepCopy(); QString name((*it)->GetName().c_str()); name += "_copy"; mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); if (parentNode.IsNotNull()) GetDataStorage()->Add(fbNode, parentNode); else GetDataStorage()->Add(fbNode); // copy child fiducials if (m_Controls->m_IncludeFiducials->isChecked()) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData())->Clone(); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(pe); newNode->SetName(fiducialNode->GetName()); newNode->SetBoolProperty("planarfigure.3drendering", true); GetDataStorage()->Add(newNode, fbNode); } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::JoinBundles() { if ( m_SelectedBundles.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberFoxView") << "Select at least two fiber bundles!"; return; } std::vector::const_iterator it = m_SelectedBundles.begin(); mitk::FiberBundle::Pointer newBundle = dynamic_cast((*it)->GetData()); QString name(""); name += QString((*it)->GetName().c_str()); ++it; for (; it!=m_SelectedBundles.end(); ++it) { newBundle = newBundle->AddBundle(dynamic_cast((*it)->GetData())); name += "+"+QString((*it)->GetName().c_str()); } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::UpdateGui() { m_Controls->m_GeometryFrame->setEnabled(true); m_Controls->m_GeometryMessage->setVisible(false); m_Controls->m_DiffusionPropsMessage->setVisible(false); m_Controls->m_FiberGenMessage->setVisible(true); m_Controls->m_TransformBundlesButton->setEnabled(false); m_Controls->m_CopyBundlesButton->setEnabled(false); m_Controls->m_GenerateFibersButton->setEnabled(false); m_Controls->m_FlipButton->setEnabled(false); m_Controls->m_CircleButton->setEnabled(false); m_Controls->m_BvalueBox->setEnabled(true); m_Controls->m_NumGradientsBox->setEnabled(true); m_Controls->m_JoinBundlesButton->setEnabled(false); m_Controls->m_AlignOnGrid->setEnabled(false); // Fiber generation gui if (m_SelectedFiducial.IsNotNull()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_FlipButton->setEnabled(true); m_Controls->m_AlignOnGrid->setEnabled(true); } if (m_SelectedImageNode.IsNotNull() || !m_SelectedBundles.empty()) { m_Controls->m_CircleButton->setEnabled(true); m_Controls->m_FiberGenMessage->setVisible(false); } if (m_SelectedImageNode.IsNotNull() && !m_SelectedBundles.empty()) m_Controls->m_AlignOnGrid->setEnabled(true); if (!m_SelectedBundles.empty()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_CopyBundlesButton->setEnabled(true); m_Controls->m_GenerateFibersButton->setEnabled(true); if (m_SelectedBundles.size()>1) m_Controls->m_JoinBundlesButton->setEnabled(true); } // Signal generation gui if (m_Controls->m_MaskComboBox->GetSelectedNode().IsNotNull() || m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull()) { m_Controls->m_GeometryMessage->setVisible(true); m_Controls->m_GeometryFrame->setEnabled(false); } if (m_Controls->m_TemplateComboBox->GetSelectedNode().IsNotNull() && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_Controls->m_TemplateComboBox->GetSelectedNode()->GetData()))) { m_Controls->m_DiffusionPropsMessage->setVisible(true); m_Controls->m_BvalueBox->setEnabled(false); m_Controls->m_NumGradientsBox->setEnabled(false); m_Controls->m_GeometryMessage->setVisible(true); m_Controls->m_GeometryFrame->setEnabled(false); } } void QmitkFiberfoxView::OnSelectionChanged( berry::IWorkbenchPart::Pointer, const QList& nodes ) { m_SelectedBundles2.clear(); m_SelectedImages.clear(); m_SelectedFiducials.clear(); m_SelectedFiducial = NULL; m_SelectedBundles.clear(); m_SelectedImageNode = NULL; // iterate all selected objects, adjust warning visibility for( int i=0; i(node->GetData())); // } // if ( node.IsNotNull() && isDiffusionImage ) // { // m_SelectedDWI = node; // m_SelectedImage = node; // m_SelectedImages.push_back(node); // } if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedImages.push_back(node); m_SelectedImageNode = node; } else if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedBundles2.push_back(node); if (m_Controls->m_RealTimeFibers->isChecked()) { m_SelectedBundles.push_back(node); mitk::FiberBundle::Pointer newFib = dynamic_cast(node->GetData()); if (newFib->GetNumFibers()!=m_Controls->m_FiberDensityBox->value()) GenerateFibers(); } else m_SelectedBundles.push_back(node); } else if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedFiducials.push_back(node); m_SelectedFiducial = node; m_SelectedBundles.clear(); mitk::DataStorage::SetOfObjects::ConstPointer parents = GetDataStorage()->GetSources(node); for( mitk::DataStorage::SetOfObjects::const_iterator it = parents->begin(); it != parents->end(); ++it ) { mitk::DataNode::Pointer pNode = *it; if ( pNode.IsNotNull() && dynamic_cast(pNode->GetData()) ) m_SelectedBundles.push_back(pNode); } } } UpdateGui(); } void QmitkFiberfoxView::EnableCrosshairNavigation() { MITK_DEBUG << "EnableCrosshairNavigation"; // enable the crosshair navigation if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart())) { MITK_DEBUG << "enabling linked navigation"; linkedRenderWindow->EnableLinkedNavigation(true); // linkedRenderWindow->EnableSlicingPlanes(true); } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::DisableCrosshairNavigation() { MITK_DEBUG << "DisableCrosshairNavigation"; // disable the crosshair navigation during the drawing if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart())) { MITK_DEBUG << "disabling linked navigation"; linkedRenderWindow->EnableLinkedNavigation(false); // linkedRenderWindow->EnableSlicingPlanes(false); } } void QmitkFiberfoxView::NodeRemoved(const mitk::DataNode* node) { mitk::DataNode* nonConstNode = const_cast(node); std::map::iterator it = m_DataNodeToPlanarFigureData.find(nonConstNode); if (dynamic_cast(node->GetData())) { m_SelectedBundles.clear(); m_SelectedBundles2.clear(); } else if (dynamic_cast(node->GetData())) m_SelectedImages.clear(); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; // remove observers data.m_Figure->RemoveObserver( data.m_EndPlacementObserverTag ); data.m_Figure->RemoveObserver( data.m_SelectObserverTag ); data.m_Figure->RemoveObserver( data.m_StartInteractionObserverTag ); data.m_Figure->RemoveObserver( data.m_EndInteractionObserverTag ); m_DataNodeToPlanarFigureData.erase( it ); } } void QmitkFiberfoxView::NodeAdded( const mitk::DataNode* node ) { // add observer for selection in renderwindow mitk::PlanarFigure* figure = dynamic_cast(node->GetData()); bool isPositionMarker (false); node->GetBoolProperty("isContourMarker", isPositionMarker); if( figure && !isPositionMarker ) { MITK_DEBUG << "figure added. will add interactor if needed."; mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetDataInteractor().GetPointer()); mitk::DataNode* nonConstNode = const_cast( node ); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New(); us::Module* planarFigureModule = us::ModuleRegistry::GetModule( "MitkPlanarFigure" ); figureInteractor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule ); figureInteractor->SetEventConfig( "PlanarFigureConfig.xml", planarFigureModule ); figureInteractor->SetDataNode( nonConstNode ); } MITK_DEBUG << "will now add observers for planarfigure"; QmitkPlanarFigureData data; data.m_Figure = figure; // // add observer for event when figure has been placed typedef itk::SimpleMemberCommand< QmitkFiberfoxView > SimpleCommandType; // SimpleCommandType::Pointer initializationCommand = SimpleCommandType::New(); // initializationCommand->SetCallbackFunction( this, &QmitkFiberfoxView::PlanarFigureInitialized ); // data.m_EndPlacementObserverTag = figure->AddObserver( mitk::EndPlacementPlanarFigureEvent(), initializationCommand ); // add observer for event when figure is picked (selected) typedef itk::MemberCommand< QmitkFiberfoxView > MemberCommandType; MemberCommandType::Pointer selectCommand = MemberCommandType::New(); selectCommand->SetCallbackFunction( this, &QmitkFiberfoxView::PlanarFigureSelected ); data.m_SelectObserverTag = figure->AddObserver( mitk::SelectPlanarFigureEvent(), selectCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer startInteractionCommand = SimpleCommandType::New(); startInteractionCommand->SetCallbackFunction( this, &QmitkFiberfoxView::DisableCrosshairNavigation); data.m_StartInteractionObserverTag = figure->AddObserver( mitk::StartInteractionPlanarFigureEvent(), startInteractionCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer endInteractionCommand = SimpleCommandType::New(); endInteractionCommand->SetCallbackFunction( this, &QmitkFiberfoxView::EnableCrosshairNavigation); data.m_EndInteractionObserverTag = figure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), endInteractionCommand ); m_DataNodeToPlanarFigureData[nonConstNode] = data; } } void QmitkFiberfoxView::PlanarFigureSelected( itk::Object* object, const itk::EventObject& ) { mitk::TNodePredicateDataType::Pointer isPf = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer allPfs = this->GetDataStorage()->GetSubset( isPf ); for ( mitk::DataStorage::SetOfObjects::const_iterator it = allPfs->begin(); it!=allPfs->end(); ++it) { mitk::DataNode* node = *it; if( node->GetData() == object ) { node->SetSelected(true); m_SelectedFiducial = node; } else node->SetSelected(false); } UpdateGui(); this->RequestRenderWindowUpdate(); } void QmitkFiberfoxView::SetFocus() { m_Controls->m_CircleButton->setFocus(); } void QmitkFiberfoxView::SetOutputPath() { // SELECT FOLDER DIALOG string outputPath = QFileDialog::getExistingDirectory(NULL, "Save images to...", QString(outputPath.c_str())).toStdString(); if (outputPath.empty()) m_Controls->m_SavePathEdit->setText("-"); else { outputPath += "/"; m_Controls->m_SavePathEdit->setText(QString(outputPath.c_str())); } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h index 886cb5679e..5fbfd125d2 100755 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h @@ -1,219 +1,219 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include "ui_QmitkFiberfoxViewControls.h" #include #include #include #ifndef Q_MOC_RUN #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif #include #include #include #include /*! \brief View for fiber based diffusion software phantoms (Fiberfox). See "Fiberfox: Facilitating the creation of realistic white matter software phantoms" (DOI: 10.1002/mrm.25045) for details. \sa QmitkFunctionality \ingroup Functionalities */ // Forward Qt class declarations using namespace std; class QmitkFiberfoxView; class QmitkFiberfoxWorker : public QObject { Q_OBJECT public: QmitkFiberfoxWorker(QmitkFiberfoxView* view); int m_FilterType; public slots: void run(); private: QmitkFiberfoxView* m_View; }; class QmitkFiberfoxView : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const string VIEW_ID; QmitkFiberfoxView(); virtual ~QmitkFiberfoxView(); virtual void CreateQtPartControl(QWidget *parent) override; void SetFocus() override; typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientDirectionContainerType; typedef itk::Vector GradientType; typedef vector GradientListType; typedef itk::VectorImage< short, 3 > ItkDwiType; typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkFloatImgType; typedef itk::Image ItkUcharImgType; template vector > MakeGradientList(); protected slots: void SetOutputPath(); ///< path where image is automatically saved to after the simulation is finished void LoadParameters(); ///< load fiberfox parameters void SaveParameters(); ///< save fiberfox parameters void BeforeThread(); void AfterThread(); void KillThread(); ///< abort simulation void UpdateSimulationStatus(); ///< print simulation progress and satus messages void OnDrawROI(); ///< adds new ROI, handles interactors etc. void OnAddBundle(); ///< adds new fiber bundle to datastorage void OnFlipButton(); ///< negate one coordinate of the fiber waypoints in the selcted planar figure. needed in case of unresolvable twists void GenerateFibers(); ///< generate fibers from the selected ROIs void GenerateImage(); ///< start image simulation void JoinBundles(); ///< merges selcted fiber bundles into one void CopyBundles(); ///< add copy of the selected bundle to the datamanager void ApplyTransform(); ///< rotate and shift selected bundles void AlignOnGrid(); ///< shift selected fiducials to nearest voxel center void Comp1ModelFrameVisibility(int index); ///< only show parameters of selected signal model for compartment 1 void Comp2ModelFrameVisibility(int index); ///< only show parameters of selected signal model for compartment 2 void Comp3ModelFrameVisibility(int index); ///< only show parameters of selected signal model for compartment 3 void Comp4ModelFrameVisibility(int index); ///< only show parameters of selected signal model for compartment 4 void ShowAdvancedOptions(int state); /** update fibers if any parameter changes */ void OnFiberDensityChanged(int value); void OnFiberSamplingChanged(double value); void OnTensionChanged(double value); void OnContinuityChanged(double value); void OnBiasChanged(double value); void OnVarianceChanged(double value); void OnDistributionChanged(int value); void OnConstantRadius(int value); /** update GUI elements */ void OnAddNoise(int value); void OnAddGhosts(int value); void OnAddDistortions(int value); void OnAddEddy(int value); void OnAddSpikes(int value); void OnAddAliasing(int value); void OnAddMotion(int value); void OnMaskSelected(int value); void OnFibSelected(int value); void OnTemplateSelected(int value); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList&) override; GradientListType GenerateHalfShell(int NPoints); ///< generate vectors distributed over the halfsphere Ui::QmitkFiberfoxViewControls* m_Controls; void SimulateForExistingDwi(mitk::DataNode* imageNode); ///< add artifacts to existing diffusion weighted image void SimulateImageFromFibers(mitk::DataNode* fiberNode); ///< simulate new diffusion weighted image - template< class ScalarType > FiberfoxParameters< ScalarType > UpdateImageParameters(); ///< update fiberfox paramater object (template parameter defines noise model type) + template< class ScalarType > FiberfoxParameters< ScalarType > UpdateImageParameters(bool all=true); ///< update fiberfox paramater object (template parameter defines noise model type) void UpdateGui(); ///< enable/disbale buttons etc. according to current datamanager selection void PlanarFigureSelected( itk::Object* object, const itk::EventObject& ); void EnableCrosshairNavigation(); ///< enable crosshair navigation if planar figure interaction ends void DisableCrosshairNavigation(); ///< disable crosshair navigation if planar figure interaction starts void NodeAdded( const mitk::DataNode* node ) override; ///< add observers void NodeRemoved(const mitk::DataNode* node) override; ///< remove observers /** structure to keep track of planar figures and observers */ struct QmitkPlanarFigureData { QmitkPlanarFigureData() : m_Figure(0) , m_EndPlacementObserverTag(0) , m_SelectObserverTag(0) , m_StartInteractionObserverTag(0) , m_EndInteractionObserverTag(0) , m_Flipped(0) { } mitk::PlanarFigure* m_Figure; unsigned int m_EndPlacementObserverTag; unsigned int m_SelectObserverTag; unsigned int m_StartInteractionObserverTag; unsigned int m_EndInteractionObserverTag; unsigned int m_Flipped; }; std::map m_DataNodeToPlanarFigureData; ///< map each planar figure uniquely to a QmitkPlanarFigureData mitk::DataNode::Pointer m_SelectedFiducial; ///< selected planar ellipse mitk::DataNode::Pointer m_SelectedImageNode; vector< mitk::DataNode::Pointer > m_SelectedBundles; vector< mitk::DataNode::Pointer > m_SelectedBundles2; vector< mitk::DataNode::Pointer > m_SelectedFiducials; vector< mitk::DataNode::Pointer > m_SelectedImages; QString m_ParameterFile; ///< parameter file name // GUI thread QmitkFiberfoxWorker m_Worker; ///< runs filter QThread m_Thread; ///< worker thread bool m_ThreadIsRunning; QTimer* m_SimulationTimer; QTime m_SimulationTime; QString m_SimulationStatusText; /** Image filters that do all the simulations. */ itk::TractsToDWIImageFilter< short >::Pointer m_TractsToDwiFilter; itk::AddArtifactsToDwiImageFilter< short >::Pointer m_ArtifactsToDwiFilter; friend class QmitkFiberfoxWorker; }; diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui index 6afa25f654..ad1930e97a 100755 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui @@ -1,3254 +1,3376 @@ QmitkFiberfoxViewControls 0 0 524 2652 Form Load Parameters :/QmitkDiffusionImaging/general_icons/upload.ico:/QmitkDiffusionImaging/general_icons/upload.ico - 1 + 0 Fiber Definition Qt::Vertical 20 40 color: rgb(255, 0, 0); Please select an image or an existing fiber bundle to draw the fiber fiducials. If you can't provide a suitable image, generate one using the "Signal Generation" tab. Qt::AutoText Qt::AlignJustify|Qt::AlignVCenter true Fiducial Options All fiducials are treated as circles with the same radius as the first fiducial. Use Constant Fiducial Radius false false Align selected fiducials with voxel grid. Shifts selected fiducials to nearest voxel center. Align With Grid :/QmitkDiffusionImaging/general_icons/right.ico:/QmitkDiffusionImaging/general_icons/right.ico Operations false Join Bundles :/QmitkDiffusionImaging/general_icons/plus.ico:/QmitkDiffusionImaging/general_icons/plus.ico QFrame::NoFrame QFrame::Raised 0 0 0 0 Y false Rotation angle (in degree) around x-axis. 3 -360.000000000000000 360.000000000000000 0.100000000000000 Axis: false Rotation angle (in degree) around y-axis. 3 -360.000000000000000 360.000000000000000 0.100000000000000 Translation: false Translation (in mm) in direction of the z-axis. 3 -1000.000000000000000 1000.000000000000000 0.100000000000000 Translation (in mm) in direction of the y-axis. 3 -1000.000000000000000 1000.000000000000000 0.100000000000000 X false Rotation: false Z false Rotation angle (in degree) around z-axis. 3 -360.000000000000000 360.000000000000000 0.100000000000000 Translation (in mm) in direction of the x-axis. 3 -1000.000000000000000 1000.000000000000000 0.100000000000000 Scaling: false Scaling factor for selected fiber bundle along the x-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the y-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the z-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 false Copy Bundles :/QmitkDiffusionImaging/general_icons/copy2.ico:/QmitkDiffusionImaging/general_icons/copy2.ico false Transform Selection :/QmitkDiffusionImaging/general_icons/refresh.ico:/QmitkDiffusionImaging/general_icons/refresh.ico If checked, the fiducials belonging to the modified bundle are also modified. Include Fiducials true Fiber Options QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Tension: false Fiber Sampling: false 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 Bias: false Continuity: false 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 Distance of fiber sampling points (in mm) 1 0.100000000000000 0.100000000000000 1.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 #Fibers: false Specify number of fibers to generate for the selected bundle. 1 1000000 100 100 false Generate Fibers :/QmitkDiffusionImaging/general_icons/right.ico:/QmitkDiffusionImaging/general_icons/right.ico QFrame::NoFrame QFrame::Raised 0 0 0 0 Select fiber distribution inside of the fiducials. Uniform Gaussian Fiber Distribution: false Variance of the gaussian 3 0.001000000000000 10.000000000000000 0.010000000000000 0.100000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Disable to only generate fibers if "Generate Fibers" button is pressed. Real Time Fibers true Disable to only generate fibers if "Generate Fibers" button is pressed. Advanced Options false QFrame::NoFrame QFrame::Raised 0 0 0 0 false 30 30 Draw elliptical fiducial. :/QmitkDiffusionImaging/circle.png:/QmitkDiffusionImaging/circle.png 32 32 false true false 30 30 Flip fiber waypoints of selcted fiducial around one axis. :/QmitkDiffusionImaging/refresh.xpm:/QmitkDiffusionImaging/refresh.xpm 32 32 false true Qt::Horizontal 40 20 Signal Generation Extra-axonal Compartments QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Select signal model for extra-axonal compartment. Ball Model Astrosticks Model Dot Model Prototype Signal Qt::Horizontal QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers. Select signal model for extra-axonal compartment. -- Ball Model Astrosticks Model Dot Model Prototype Signal Qt::Vertical 20 40 Image Settings Advanced Options QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Gradient Directions: Number of gradient directions distributed over the half sphere. 0 10000 1 30 <html><head/><body><p>b-Value<span style=" font-style:italic;"> [s/mm</span><span style=" font-style:italic; vertical-align:super;">2</span><span style=" font-style:italic;">]</span>:</p></body></html> false b-value in s/mm² 0 10000 100 1000 color: rgb(255, 0, 0); Using geometry of selected image! color: rgb(255, 0, 0); Using gradients of selected DWI! QFrame::NoFrame QFrame::Raised 0 0 0 0 6 - - + + - Output one image per compartment containing the corresponding volume fractions per voxel. + Disable partial volume. Treat voxel content as fiber-only if at least one fiber is present. - Reverse Phase Encoding Direction + Disable Partial Volume Effects false - - + + + + + + + + + + + - Signal Scale: + <html><head/><body><p>Echo Time <span style=" font-style:italic;">TE</span>: </p></body></html> + + + false - - + + - Relaxation time due to magnetic field inhomogeneities (T2', in milliseconds). + Partial fourier factor (0.5-1) + + + 3 - 1 + 0.500000000000000 - 10000 + 1.000000000000000 - 1 + 0.100000000000000 - 50 + 1.000000000000000 - - + + - Output one image per compartment containing the corresponding volume fractions per voxel. + <html><head/><body><p><span style=" font-style:italic;">TE</span>, <span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> and <span style=" font-style:italic;">T2</span> will have no effect if unchecked.</p></body></html> - Output Volume Fractions + Simulate Signal Relaxation - false + true - - - - Fiber Radius: + + + + TE in milliseconds + + + 1 + + + 10000 + + + 1 + + + 100 - + - T2* relaxation time (in milliseconds). + Dwell time (time to read one line in k-space) in ms. 100.000000000000000 0.100000000000000 1.000000000000000 - - - - <html><head/><body><p><span style=" font-style:italic;">TE</span>, <span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> and <span style=" font-style:italic;">T2</span> will have no effect if unchecked.</p></body></html> - - - Simulate Signal Relaxation - - - true - - - - + Fiber radius used to calculate volume fractions (in µm). Set to 0 for automatic radius estimation. 0 1000 0 - + + + + + + + + + + + + + Partial Fourier: + + + false + + + + TE in milliseconds 1 - 10000 + 999999999 1 100 - + - Dwell time: + Dwell Time: false - - + + - Disable partial volume. Treat voxel content as fiber-only if at least one fiber is present. + + + + + + + - Disable Partial Volume Effects + <html><head/><body><p><span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> Relaxation: </p></body></html> - + false - <html><head/><body><p>Echo Time <span style=" font-style:italic;">TE</span>: </p></body></html> + <html><head/><body><p>Number of Coils:</p></body></html> false - - + + - TE in milliseconds + Output one image per compartment containing the corresponding volume fractions per voxel. + + + Reverse Phase Encoding Direction + + + false + + + + + + + Signal Scale: + + + + + + + Relaxation time due to magnetic field inhomogeneities (T2', in milliseconds). 1 10000 1 - 100 + 50 + + + + + + + Output phase image and volume fraction maps. + + + Output Additional Images + + + false - + - <html><head/><body><p><span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> Relaxation: </p></body></html> + <html><head/><body><p>Repetition Time <span style=" font-style:italic;">TR</span>: </p></body></html> false - + TR in milliseconds 1 999999999 1 - 2000 + 4000 + + + + + + + Number of coils + + + 1 + + + 128 + + + 1 + + + 1 + + + + + + + Fiber Radius: - + - <html><head/><body><p>Repetition Time <span style=" font-style:italic;">TR</span>: </p></body></html> + <html><head/><body><p>Coil Sensitivity:</p></body></html> false + + + + + Constant + + + + + Linear + + + + + Exponential + + + + QFrame::NoFrame QFrame::Raised 0 0 0 0 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 Image Spacing: 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 Image Dimensions: Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 - 11 + 20 Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 - 11 + 20 Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 3 Inter-axonal Compartment Select signal model for intra-axonal compartment. -- Stick Model Zeppelin Model Tensor Model QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers. true Stop current simulation. Abort Simulation :/QmitkDiffusionImaging/general_icons/abort.ico:/QmitkDiffusionImaging/general_icons/abort.ico Data QFrame::NoFrame QFrame::Raised 0 0 0 0 0 - ... <html><head/><body><p>Select a binary image to define the area of signal generation. Outside of the mask image only noise will be actively generated.</p></body></html> QComboBox::AdjustToMinimumContentsLength Fiber Bundle: false Save path: false Tissue Mask: false <html><head/><body><p>Select a fiber bundle to generate the white matter signal from. You can either use the fiber definition tab to manually define an input fiber bundle or you can also use any existing bundle, e.g. yielded by a tractography algorithm.</p></body></html> QComboBox::AdjustToMinimumContentsLength Template Image: false <html><head/><body><p>The parameters for the simulation (e.g. spacing, size, diffuison-weighted gradients, b-value) are adopted from this image.</p></body></html> QComboBox::AdjustToMinimumContentsLength 8 true Noise and other Artifacts Qt::Horizontal Add Noise false Add ringing artifacts occuring at strong edges in the image. Add Gibbs Ringing false true QFrame::NoFrame QFrame::Raised 6 0 0 0 0 Shrink FOV (%): false Shrink FOV by this percentage. 1 0.000000000000000 90.000000000000000 0.100000000000000 25.000000000000000 Qt::Horizontal QFrame::NoFrame QFrame::Raised 0 0 0 0 Num. Spikes: The number of randomly occurring signal spikes. 1 Spike amplitude relative to the largest signal amplitude of the corresponding k-space slice. 0.100000000000000 0.100000000000000 Scale: !!!EXPERIMENTAL!!! Add Eddy Current Effects false Add Spikes false QFrame::NoFrame QFrame::Raised 0 0 0 0 Variance: Variance of selected noise distribution. - 4 + 10 0.000000000000000 999999999.000000000000000 0.001000000000000 50.000000000000000 Distribution: Noise distribution - Rician + Complex Gaussian - Chi-squared + Rician Add N/2 Ghosts false true QFrame::NoFrame QFrame::Raised 6 0 0 0 0 Frequency Map: false Select image specifying the frequency inhomogeneities (in Hz). Qt::Horizontal Qt::Horizontal Qt::Horizontal true QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 6 0 6 0 0 Toggle between random movement and linear movement. Randomize motion true Rotation 0 9 0 0 Degree: false x false Axis: false Maximum rotation around x-axis. 1 360.000000000000000 1.000000000000000 0.000000000000000 Maximum rotation around z-axis. 1 360.000000000000000 1.000000000000000 15.000000000000000 y false z false Maximum rotation around y-axis. 1 360.000000000000000 1.000000000000000 0.000000000000000 Translation 0 0 0 Distance: false x false y false Axis: false z false Maximum translation along x-axis. 1 1000.000000000000000 1.000000000000000 0.000000000000000 Maximum translation along y-axis. 1 1000.000000000000000 1.000000000000000 0.000000000000000 Maximum translation along z-axis. 1 1000.000000000000000 1.000000000000000 0.000000000000000 Add Motion Artifacts false Add Distortions false Add Aliasing false true QFrame::NoFrame QFrame::Raised 6 0 0 0 0 K-Space Line Offset: false A larger offset increases the inensity of the ghost image. 3 1.000000000000000 0.010000000000000 0.250000000000000 true QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 6 0 0 0 0 - + - Magnitude: + Gradient: false - + - Maximum magnitude of eddy current induced magnetic field inhomogeneities (in mT). + Eddy current induced magnetic field gradient (in mT/m). - 5 + 4 1000.000000000000000 0.001000000000000 - 0.005000000000000 - - - - - - - color: rgb(255, 0, 0); - - - Experimental! + 0.010000000000000 Qt::Horizontal Qt::Horizontal true <html><head/><body><p>Start DWI generation from selected fiber bundle.</p><p>If no fiber bundle but an existing diffusion weighted image is selected, the enabled artifacts are added to this image.</p><p>If neither a fiber bundle nor a diffusion weighted image is selected, a grayscale image containing a simple gradient is generated.</p></body></html> Start Simulation :/QmitkDiffusionImaging/general_icons/right.ico:/QmitkDiffusionImaging/general_icons/right.ico Intra-axonal Compartment Select signal model for intra-axonal compartment. Stick Model Zeppelin Model Tensor Model Prototype Signal QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers. Save Parameters :/QmitkDiffusionImaging/general_icons/download.ico:/QmitkDiffusionImaging/general_icons/download.ico QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkTensorModelParametersWidget QWidget
QmitkTensorModelParametersWidget.h
1
QmitkStickModelParametersWidget QWidget
QmitkStickModelParametersWidget.h
1
QmitkZeppelinModelParametersWidget QWidget
QmitkZeppelinModelParametersWidget.h
1
QmitkBallModelParametersWidget QWidget
QmitkBallModelParametersWidget.h
1
QmitkAstrosticksModelParametersWidget QWidget
QmitkAstrosticksModelParametersWidget.h
1
QmitkDotModelParametersWidget QWidget
QmitkDotModelParametersWidget.h
1
QmitkPrototypeSignalParametersWidget QWidget
QmitkPrototypeSignalParametersWidget.h
1
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
m_CircleButton m_FlipButton m_RealTimeFibers m_AdvancedOptionsBox m_DistributionBox m_VarianceBox m_FiberDensityBox m_FiberSamplingBox m_TensionBox m_ContinuityBox m_BiasBox m_GenerateFibersButton m_ConstantRadiusBox m_AlignOnGrid m_XrotBox m_YrotBox m_ZrotBox m_XtransBox m_YtransBox m_ZtransBox m_XscaleBox m_YscaleBox m_ZscaleBox m_TransformBundlesButton m_CopyBundlesButton m_JoinBundlesButton m_IncludeFiducials + m_FiberBundleComboBox + m_MaskComboBox + m_TemplateComboBox + m_SavePathEdit + m_OutputPathButton m_GenerateImageButton + m_AbortSimulationButton + m_SimulationStatusText m_SizeX m_SizeY m_SizeZ m_SpacingX m_SpacingY m_SpacingZ m_NumGradientsBox m_BvalueBox m_AdvancedOptionsBox_2 m_SignalScaleBox m_TEbox + m_TRbox m_LineReadoutTimeBox + m_PartialFourier m_T2starBox m_FiberRadius + m_ReversePhaseBox m_RelaxationBox m_EnforcePureFiberVoxelsBox m_VolumeFractionsBox m_Compartment1Box + m_Comp1VolumeFraction m_Compartment2Box + m_Comp2VolumeFraction m_Compartment3Box + m_Comp3VolumeFraction m_Compartment4Box + m_Comp4VolumeFraction m_AddNoise + m_NoiseDistributionBox m_NoiseLevel m_AddSpikes m_SpikeNumBox m_SpikeScaleBox m_AddGhosts m_kOffsetBox m_AddAliasing m_WrapBox m_AddDistortions m_FrequencyMapBox m_AddMotion m_RandomMotion m_MaxRotationBoxX m_MaxRotationBoxY m_MaxRotationBoxZ m_MaxTranslationBoxX m_MaxTranslationBoxY m_MaxTranslationBoxZ m_AddEddy m_EddyGradientStrength m_AddGibbsRinging m_SaveParametersButton m_LoadParametersButton tabWidget