diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateDirectionImagesFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateDirectionImagesFilter.h index 964c17e5fc..24a987606b 100755 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateDirectionImagesFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateDirectionImagesFilter.h @@ -1,110 +1,111 @@ /*=================================================================== 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 __itkEvaluateDirectionImagesFilter_h_ #define __itkEvaluateDirectionImagesFilter_h_ #include #include #include namespace itk{ -/** \class EvaluateDirectionImagesFilter +/** \brief Evaluates the voxel-wise angular error between two sets of directions. */ template< class PixelType > class EvaluateDirectionImagesFilter : public ImageSource< Image< PixelType, 3 > > { public: typedef EvaluateDirectionImagesFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageSource< Image< PixelType, 3 > > Superclass; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef typename Superclass::OutputImageType OutputImageType; /** Method for creation through the object factory. */ itkNewMacro(Self) /** Runtime information support. */ itkTypeMacro(EvaluateDirectionImagesFilter, ImageToImageFilter) typedef Vector< float, 3 > DirectionType; typedef Image< DirectionType, 3 > DirectionImageType; typedef VectorContainer< int, DirectionImageType::Pointer > DirectionImageContainerType; typedef Image< float, 3 > FloatImageType; typedef Image< bool, 3 > BoolImageType; typedef Image< unsigned char, 3 > UCharImageType; - itkSetMacro( ImageSet , DirectionImageContainerType::Pointer) - itkSetMacro( ReferenceImageSet , DirectionImageContainerType::Pointer) - itkSetMacro( MaskImage , UCharImageType::Pointer) - itkSetMacro( IgnoreMissingDirections , bool) + itkSetMacro( ImageSet , DirectionImageContainerType::Pointer) ///< test image containers + itkSetMacro( ReferenceImageSet , DirectionImageContainerType::Pointer) ///< reference image containers + itkSetMacro( MaskImage , UCharImageType::Pointer) ///< Calculation is only performed inside of the mask image. + itkSetMacro( IgnoreMissingDirections , bool) ///< If in one voxel, the number of directions differs between the test container and the reference, the excess directions are ignored. Otherwise, the error to the next closest direction is calculated. + /** Output statistics of the measured angular errors. */ itkGetMacro( MeanAngularError, float) itkGetMacro( MinAngularError, float) itkGetMacro( MaxAngularError, float) itkGetMacro( VarAngularError, float) itkGetMacro( MedianAngularError, float) + /** Output statistics of the measured peak length errors. */ itkGetMacro( MeanLengthError, float) itkGetMacro( MinLengthError, float) itkGetMacro( MaxLengthError, float) itkGetMacro( VarLengthError, float) itkGetMacro( MedianLengthError, float) protected: EvaluateDirectionImagesFilter(); ~EvaluateDirectionImagesFilter() {} void GenerateData(); - UCharImageType::Pointer m_MaskImage; - DirectionImageContainerType::Pointer m_ImageSet; - DirectionImageContainerType::Pointer m_ReferenceImageSet; - bool m_IgnoreMissingDirections; + UCharImageType::Pointer m_MaskImage; + DirectionImageContainerType::Pointer m_ImageSet; + DirectionImageContainerType::Pointer m_ReferenceImageSet; + bool m_IgnoreMissingDirections; double m_MeanAngularError; double m_MedianAngularError; double m_MaxAngularError; double m_MinAngularError; double m_VarAngularError; std::vector< double > m_AngularErrorVector; - double m_MeanLengthError; double m_MedianLengthError; double m_MaxLengthError; double m_MinLengthError; double m_VarLengthError; std::vector< double > m_LengthErrorVector; double m_Eps; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkEvaluateDirectionImagesFilter.cpp" #endif #endif //__itkEvaluateDirectionImagesFilter_h_ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateTractogramDirectionsFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateTractogramDirectionsFilter.h index cf1cddc6c7..4396531a8b 100755 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateTractogramDirectionsFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkEvaluateTractogramDirectionsFilter.h @@ -1,107 +1,107 @@ /*=================================================================== 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 __itkEvaluateTractogramDirectionsFilter_h_ #define __itkEvaluateTractogramDirectionsFilter_h_ #include #include #include #include namespace itk{ -/** \class EvaluateTractogramDirectionsFilter +/** \brief Calculates the voxel-wise angular error of the input tractogram to a set of voxel-wise directions. */ template< class PixelType > class EvaluateTractogramDirectionsFilter : public ImageSource< Image< PixelType, 3 > > { public: typedef EvaluateTractogramDirectionsFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageSource< Image< PixelType, 3 > > Superclass; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef typename Superclass::OutputImageType OutputImageType; /** Method for creation through the object factory. */ itkNewMacro(Self) /** Runtime information support. */ itkTypeMacro(EvaluateTractogramDirectionsFilter, ImageToImageFilter) typedef mitk::FiberBundleX FiberBundleType; typedef Vector< float, 3 > DirectionType; typedef Image< DirectionType, 3 > DirectionImageType; typedef VectorContainer< int, DirectionImageType::Pointer > DirectionImageContainerType; typedef Image< float, 3 > FloatImageType; typedef Image< bool, 3 > BoolImageType; typedef Image< unsigned char, 3 > UCharImageType; typedef Image< double, 3 > DoubleImageType; - itkSetMacro( Tractogram, FiberBundleType::Pointer) - itkSetMacro( ReferenceImageSet , DirectionImageContainerType::Pointer) - itkSetMacro( MaskImage , UCharImageType::Pointer) - itkSetMacro( IgnoreMissingDirections , bool) - itkSetMacro( UseInterpolation , bool) + itkSetMacro( Tractogram, FiberBundleType::Pointer) ///< Input tractogram + itkSetMacro( ReferenceImageSet , DirectionImageContainerType::Pointer) ///< Input images containing one reference direction per voxel. + itkSetMacro( MaskImage , UCharImageType::Pointer) ///< Calculation is only performed inside of the mask image. + itkSetMacro( IgnoreMissingDirections , bool) ///< If in one voxel, the number of directions differs between the input tractogram and the reference, the excess directions are ignored. Otherwise, the error to the next closest direction is calculated. + itkSetMacro( UseInterpolation , bool) ///< Use trilinear interpolation. + /** Output statistics. */ itkGetMacro( MeanAngularError, float) itkGetMacro( MinAngularError, float) itkGetMacro( MaxAngularError, float) itkGetMacro( VarAngularError, float) itkGetMacro( MedianAngularError, float) protected: EvaluateTractogramDirectionsFilter(); ~EvaluateTractogramDirectionsFilter() {} void GenerateData(); itk::Point GetItkPoint(double point[3]); itk::Vector GetItkVector(double point[3]); vnl_vector_fixed GetVnlVector(double point[3]); vnl_vector_fixed GetVnlVector(Vector< PixelType, 3 >& vector); - UCharImageType::Pointer m_MaskImage; - DirectionImageContainerType::Pointer m_ReferenceImageSet; - bool m_IgnoreMissingDirections; - double m_MeanAngularError; - double m_MedianAngularError; - double m_MaxAngularError; - double m_MinAngularError; - double m_VarAngularError; - std::vector< double > m_AngularErrorVector; - + UCharImageType::Pointer m_MaskImage; + DirectionImageContainerType::Pointer m_ReferenceImageSet; + bool m_IgnoreMissingDirections; + double m_MeanAngularError; + double m_MedianAngularError; + double m_MaxAngularError; + double m_MinAngularError; + double m_VarAngularError; + std::vector< double > m_AngularErrorVector; double m_Eps; FiberBundleType::Pointer m_Tractogram; bool m_UseInterpolation; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkEvaluateTractogramDirectionsFilter.cpp" #endif #endif //__itkEvaluateTractogramDirectionsFilter_h_ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFibersFromPlanarFiguresFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFibersFromPlanarFiguresFilter.h index b0d24d3530..2445de2fbd 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFibersFromPlanarFiguresFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFibersFromPlanarFiguresFilter.h @@ -1,105 +1,105 @@ /*=================================================================== 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 itkFibersFromPlanarFiguresFilter_h #define itkFibersFromPlanarFiguresFilter_h // MITK #include #include // ITK #include // VTK #include #include #include #include #include using namespace std; namespace itk{ /** * \brief Generates artificial fibers distributed in and interpolated between the input planar figures. */ class FibersFromPlanarFiguresFilter : public ProcessObject { public: enum FiberDistribution{ DISTRIBUTE_UNIFORM, // distribute fibers uniformly in the ROIs DISTRIBUTE_GAUSSIAN // distribute fibers using a 2D gaussian }; typedef FibersFromPlanarFiguresFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef vector< vector< mitk::PlanarEllipse::Pointer > > FiducialListType; typedef vector< vector< unsigned int > > FlipListType; typedef mitk::FiberBundleX::Pointer FiberType; typedef vector< mitk::FiberBundleX::Pointer > FiberContainerType; itkNewMacro(Self) itkTypeMacro( FibersFromPlanarFiguresFilter, ProcessObject ) - void GenerateData(); - virtual void Update(){ this->GenerateData(); } // input void SetFlipList(FlipListType fliplist){ m_FlipList = fliplist; } ///< contains flags indicating a flip of the 2D fiber x-coordinates (needed to resolve some unwanted fiber twisting) void SetFiducials(FiducialListType fiducials){ m_Fiducials = fiducials; } ///< container of the planar ellipses used as fiducials for the fiber generation process itkSetMacro(Density, int) ///< number of fibers per bundle - itkSetMacro(FiberSampling, double) ///< sampling points of the fibers per cm + itkSetMacro(FiberSampling, double) ///< sampling points of the fibers per cm itkSetMacro(Tension, double) ///< tension parameter of the Kochanek-Bartels splines itkSetMacro(Continuity, double) ///< continuity parameter of the Kochanek-Bartels splines itkSetMacro(Bias, double) ///< bias parameter of the Kochanek-Bartels splines itkSetMacro(FiberDistribution, FiberDistribution) ///< flag to switch between uniform and gaussian distribution of the fiber waypoints inside of the fiducials itkSetMacro(Variance, double) ///< variance of the gaussian waypoint distribution // output FiberContainerType GetFiberBundles(){ return m_FiberBundles; } protected: + void GenerateData(); + FibersFromPlanarFiguresFilter(); virtual ~FibersFromPlanarFiguresFilter(); void GeneratePoints(); FiberDistribution m_FiberDistribution; ///< flag to switch between uniform and gaussian distribution of the fiber waypoints inside of the fiducials 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 FiberContainerType m_FiberBundles; ///< container for the output fiber bundles int m_Density; ///< number of fibers per bundle double m_FiberSampling; ///< sampling points of the fibers per cm double m_Tension; ///< tension parameter of the Kochanek-Bartels splines double m_Continuity; ///< continuity parameter of the Kochanek-Bartels splines double m_Bias; ///< bias parameter of the Kochanek-Bartels splines double m_Variance; ///< variance of the gaussian waypoint distribution vector< mitk::Vector2D > m_2DPoints; ///< container for the 2D fiber waypoints }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkFibersFromPlanarFiguresFilter.cpp" #endif #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFieldmapGeneratorFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFieldmapGeneratorFilter.h index 73030eef3c..eda579bbd0 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFieldmapGeneratorFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFieldmapGeneratorFilter.h @@ -1,85 +1,92 @@ /*=================================================================== 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 __itkFieldmapGeneratorFilter_h__ #define __itkFieldmapGeneratorFilter_h__ #include #include #include #include #include #include #include namespace itk{ /** -* \brief Generates tract density images from input fiberbundles (Calamante 2010). */ +* \brief Generate float image with artificial frequency maps used by Fiberfox. Simulates additional frequencies at (possibly multiple) positions based on 3D gaussians with the specified variance and amplitude and/or as a linear gradient in the image. +* See "Fiberfox: Facilitating the creation of realistic white matter software phantoms" (DOI: 10.1002/mrm.25045) for details. +*/ template< class OutputImageType > class FieldmapGeneratorFilter : public ImageSource< OutputImageType > { public: typedef FieldmapGeneratorFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef typename OutputImageType::PixelType PixelType; typedef typename OutputImageType::IndexType IndexType; typedef itk::ImageRegion<3> OutputImageRegionType; typedef itk::Matrix MatrixType; itkNewMacro(Self) itkTypeMacro( FieldmapGeneratorFilter, ImageSource ) + /** Output image parameters. */ itkSetMacro( Spacing, itk::Vector ) itkSetMacro( Origin, mitk::Point3D ) itkSetMacro( DirectionMatrix, MatrixType ) itkSetMacro( ImageRegion, OutputImageRegionType ) + + /** Gradient direction and offset. */ void SetGradient( vnl_vector_fixed< double, 3 > gradient ) { m_Gradient=gradient; } void SetOffset( vnl_vector_fixed< double, 3 > offset ) { m_Offset=offset; } + + /** Parameters of gaussian frequency sources. */ void SetVariances( std::vector< double > variances ) { m_Variances=variances; } void SetHeights( std::vector< double > heights ) { m_Heights=heights; } void SetWorldPositions( std::vector< mitk::Point3D > worldPositions ) { m_WorldPositions=worldPositions; } protected: void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId); FieldmapGeneratorFilter(); virtual ~FieldmapGeneratorFilter(); itk::Vector m_Spacing; ///< output image spacing mitk::Point3D m_Origin; ///< output image origin MatrixType m_DirectionMatrix; ///< output image rotation OutputImageRegionType m_ImageRegion; ///< output image size std::vector< double > m_Variances; std::vector< double > m_Heights; std::vector< mitk::Point3D > m_WorldPositions; vnl_vector_fixed< double, 3 > m_Gradient; vnl_vector_fixed< double, 3 > m_Offset; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkFieldmapGeneratorFilter.cpp" #endif #endif // __itkFieldmapGeneratorFilter_h__ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.h index 831e995140..470f22c8a9 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.h @@ -1,153 +1,152 @@ /*=================================================================== 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 itkGibbsTrackingFilter_h #define itkGibbsTrackingFilter_h // MITK #include // ITK #include #include #include #include // VTK #include #include #include #include #include namespace itk{ /** * \brief Performes global fiber tractography on the input Q-Ball or tensor image (Gibbs tracking, Reisert 2010). */ template< class ItkQBallImageType > class GibbsTrackingFilter : public ProcessObject { public: typedef GibbsTrackingFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; itkNewMacro(Self) itkTypeMacro( GibbsTrackingFilter, ProcessObject ) typedef Image< DiffusionTensor3D, 3 > ItkTensorImage; typedef typename ItkQBallImageType::Pointer ItkQBallImageTypePointer; typedef Image< float, 3 > ItkFloatImageType; typedef vtkSmartPointer< vtkPolyData > FiberPolyDataType; - // parameter setter - itkSetMacro( StartTemperature, float ) - itkSetMacro( EndTemperature, float ) - itkSetMacro( Iterations, unsigned long ) - itkSetMacro( ParticleWeight, float ) - itkSetMacro( ParticleWidth, float ) + /** Setter. */ + itkSetMacro( StartTemperature, float ) ///< Start temperature of simulated annealing process. + itkSetMacro( EndTemperature, float ) ///< End temperature of simulated annealing process. + itkSetMacro( Iterations, unsigned long ) ///< Number of iterations. More iterations usually mean better results. Maximum 5x10^8 + itkSetMacro( ParticleWeight, float ) ///< Smaller particle weights result in a higher sensitivity if the method. + itkSetMacro( ParticleWidth, float ) ///< Thinner particles cause more reconstructed fibers. itkSetMacro( ParticleLength, float ) itkSetMacro( ConnectionPotential, float ) - itkSetMacro( InexBalance, float ) + itkSetMacro( InexBalance, float ) ///< Values < 0 result in a stronger weighting of the internal energy, values > 0 cause a stronger weighting of the external energy, itkSetMacro( ParticlePotential, float ) - itkSetMacro( MinFiberLength, int ) - itkSetMacro( AbortTracking, bool ) - itkSetMacro( CurvatureThreshold, float) - itkSetMacro( DuplicateImage, bool ) - itkSetMacro( RandomSeed, int ) - itkSetMacro( LoadParameterFile, std::string ) + itkSetMacro( MinFiberLength, int ) ///< Shorter fibers are discarded + itkSetMacro( AbortTracking, bool ) ///< Set flag to prematurely abort tracking. + itkSetMacro( CurvatureThreshold, float) ///< Absolute angular threshold between two particles (in radians). + itkSetMacro( DuplicateImage, bool ) ///< Work on copy of input image. + itkSetMacro( RandomSeed, int ) ///< Seed for random generator. + itkSetMacro( LoadParameterFile, std::string ) ///< Parameter file. itkSetMacro( SaveParameterFile, std::string ) - itkSetMacro( LutPath, std::string ) + itkSetMacro( LutPath, std::string ) ///< Path to lookuptables. Default is binary directory. - // getter + /** Getter. */ itkGetMacro( ParticleWeight, float ) itkGetMacro( ParticleWidth, float ) itkGetMacro( ParticleLength, float ) itkGetMacro( CurrentStep, unsigned long ) itkGetMacro( NumParticles, int ) itkGetMacro( NumConnections, int ) itkGetMacro( NumAcceptedFibers, int ) itkGetMacro( ProposalAcceptance, float ) itkGetMacro( Steps, unsigned int) itkGetMacro( IsInValidState, bool) + FiberPolyDataType GetFiberBundle(); ///< Output fibers - // input data + /** Input images. */ itkSetMacro(QBallImage, typename ItkQBallImageType::Pointer) itkSetMacro(MaskImage, ItkFloatImageType::Pointer) itkSetMacro(TensorImage, ItkTensorImage::Pointer) - void GenerateData(); - virtual void Update(){ this->GenerateData(); } - FiberPolyDataType GetFiberBundle(); - protected: + void GenerateData(); + GibbsTrackingFilter(); virtual ~GibbsTrackingFilter(); void EstimateParticleWeight(); void PrepareMaskImage(); bool LoadParameters(); bool SaveParameters(); // Input Images typename ItkQBallImageType::Pointer m_QBallImage; typename ItkFloatImageType::Pointer m_MaskImage; typename ItkTensorImage::Pointer m_TensorImage; // Tracking parameters float m_StartTemperature; ///< Start temperature float m_EndTemperature; ///< End temperature unsigned long m_Iterations; ///< Total number of iterations unsigned long m_CurrentStep; ///< current tracking step float m_ParticleWeight; ///< w (unitless) float m_ParticleWidth; ///< sigma (mm) float m_ParticleLength; ///< l (mm) float m_ConnectionPotential; ///< gross L (chemisches potential, default 10) float m_InexBalance; ///< gewichtung zwischen den lambdas; -5 ... 5 -> nur intern ... nur extern,default 0 float m_ParticlePotential; ///< default 0.2 int m_MinFiberLength; ///< discard all fibers shortan than the specified length in mm bool m_AbortTracking; ///< set flag to abort tracking int m_NumAcceptedFibers; ///< number of reconstructed fibers generated by the FiberBuilder volatile bool m_BuildFibers; ///< set flag to generate fibers from particle grid unsigned int m_Steps; ///< number of temperature decrease steps float m_ProposalAcceptance; ///< proposal acceptance rate (0-1) float m_CurvatureThreshold; ///< curvature threshold in radians (1 -> no curvature is accepted, -1 all curvature angles are accepted) bool m_DuplicateImage; ///< generates a working copy of the qball image so that the original image won't be changed by the mean subtraction int m_NumParticles; ///< current number of particles in grid int m_NumConnections; ///< current number of connections between particles in grid int m_RandomSeed; ///< seed value for random generator (-1 for standard seeding) std::string m_LoadParameterFile; ///< filename of parameter file (reader) std::string m_SaveParameterFile; ///< filename of parameter file (writer) std::string m_LutPath; ///< path to lookuptables used by the sphere interpolator bool m_IsInValidState; ///< Whether the filter is in a valid state, false if error occured FiberPolyDataType m_FiberPolyData; ///< container for reconstructed fibers //Constant values static const int m_ParticleGridCellCapacity = 1024; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkGibbsTrackingFilter.cpp" #endif #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.h index f80d616398..63ebd14c39 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.h @@ -1,124 +1,134 @@ /*=================================================================== 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 "FiberTrackingExports.h" #include #include #include #include using namespace std; namespace itk{ /** -* \brief Performes deterministic streamline tracking on the input tensor image. */ +* \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. */ itkNewMacro(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; - itkSetMacro( FrequencyMap, typename InputImageType::Pointer ) - itkSetMacro( tLine, double ) - itkSetMacro( kOffset, double ) - itkSetMacro( TE, double) - itkSetMacro( Tinhom, double) - itkSetMacro( Tau, double) ///< eddy current decay constant - itkSetMacro( SimulateRelaxation, bool ) - itkSetMacro( Z, double ) - itkSetMacro( DirectionMatrix, MatrixType ) - itkSetMacro( SignalScale, double ) - itkSetMacro( OutSize, itk::Size<2> ) - itkSetMacro( Spikes, int ) - itkSetMacro( SpikeAmplitude, double ) - itkSetMacro( UseConstantRandSeed, bool ) - itkSetMacro( EddyGradientMagnitude, double) ///< in T/m - - void SetT2( std::vector< double > t2Vector ) { m_T2=t2Vector; } - void SetCompartmentImages( std::vector< InputImagePointerType > cImgs ) { m_CompartmentImages=cImgs; } - void SetDiffusionGradientDirection(itk::Vector g) { m_DiffusionGradientDirection=g; } + itkSetMacro( FrequencyMap, typename InputImageType::Pointer ) ///< Used to simulate distortions. Specifies additional frequency component per voxel. + itkSetMacro( tLine, double ) ///< Time needed to fill one line in k-space (in ms). + itkSetMacro( kOffset, double ) ///< Causes N/2 ghosting artifacts. + itkSetMacro( TE, double) ///< Echo time TE (in ms). + itkSetMacro( Tinhom, double) ///< T2' signal relaxation constant (in ms). + itkSetMacro( Tau, double) ///< Eddy current decay constant (in ms). + itkSetMacro( SimulateRelaxation, bool ) ///< Enable T2 signal relaxation. + itkSetMacro( Z, double ) ///< Slice position, necessary for eddy current simulation. + itkSetMacro( DirectionMatrix, MatrixType ) ///< Image rotation matrix, necessary for eddy current simulation. + itkSetMacro( SignalScale, double ) ///< Scaling factor for resulting signal. + itkSetMacro( OutSize, itk::Size<2> ) ///< Output slice size. Can be different from input size, e.g. if Gibbs ringing is enabled. + itkSetMacro( Spikes, int ) ///< Number of randomly placed spikes per slice. + itkSetMacro( SpikeAmplitude, double ) ///< Spike amplitude relative to the largest slice value (magnitude of complex). + itkSetMacro( UseConstantRandSeed, bool ) ///< Use constant seed for random generator for reproducible results. + itkSetMacro( EddyGradientMagnitude, double) ///< Magnitude of eddy current induced gradients in T/m + + 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 SetDiffusionGradientDirection(itk::Vector g) { m_DiffusionGradientDirection=g; } ///< Gradient direction is needed for eddy current simulation. protected: KspaceImageFilter(); ~KspaceImageFilter() {} void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId); void AfterThreadedGenerateData(); bool m_SimulateRelaxation; typename InputImageType::Pointer m_FrequencyMap; double m_tLine; double m_kOffset; double m_Tinhom; double m_TE; vector< double > m_T2; vector< InputImagePointerType > m_CompartmentImages; itk::Vector m_DiffusionGradientDirection; double m_Tau; double m_EddyGradientMagnitude; double m_Z; MatrixType m_DirectionMatrix; bool m_IsBaseline; double m_SignalScale; itk::Size<2> m_OutSize; int m_Spikes; double m_SpikeAmplitude; itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer m_RandGen; bool m_UseConstantRandSeed; vcl_complex m_Spike; private: }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkKspaceImageFilter.cpp" #endif #endif //__itkKspaceImageFilter_h_ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.h index 7d588adad0..9885496b5b 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.h @@ -1,141 +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 __itkStreamlineTrackingFilter_h_ #define __itkStreamlineTrackingFilter_h_ #include "FiberTrackingExports.h" #include #include #include #include #include #include #include #include #include namespace itk{ /** * \brief Performes deterministic streamline tracking on the input tensor image. */ template< class TTensorPixelType, class TPDPixelType=double> class StreamlineTrackingFilter : public ImageToImageFilter< Image< DiffusionTensor3D, 3 >, Image< Vector< TPDPixelType, 3 >, 3 > > { public: typedef StreamlineTrackingFilter Self; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef ImageToImageFilter< Image< DiffusionTensor3D, 3 >, Image< Vector< TPDPixelType, 3 >, 3 > > Superclass; /** Method for creation through the object factory. */ itkNewMacro(Self) /** Runtime information support. */ itkTypeMacro(StreamlineTrackingFilter, ImageToImageFilter) typedef TTensorPixelType TensorComponentType; typedef TPDPixelType DirectionPixelType; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::OutputImageRegionType OutputImageRegionType; typedef itk::Image ItkUcharImgType; typedef itk::Image ItkFloatImgType; typedef itk::Image< vnl_vector_fixed, 3> ItkPDImgType; typedef vtkSmartPointer< vtkPolyData > FiberPolyDataType; - itkGetMacro( FiberPolyData, FiberPolyDataType ) - itkSetMacro( SeedImage, ItkUcharImgType::Pointer) - itkSetMacro( MaskImage, ItkUcharImgType::Pointer) - itkSetMacro( FaImage, ItkFloatImgType::Pointer) - itkSetMacro( SeedsPerVoxel, int) - itkSetMacro( FaThreshold, float) - itkSetMacro( StepSize, float) - itkSetMacro( F, float ) - itkSetMacro( G, float ) - itkSetMacro( Interpolate, bool ) - itkSetMacro( MinTractLength, float ) + itkGetMacro( FiberPolyData, FiberPolyDataType ) ///< Output fibers + itkSetMacro( SeedImage, ItkUcharImgType::Pointer) ///< Seeds are only placed inside of this mask. + itkSetMacro( MaskImage, ItkUcharImgType::Pointer) ///< Tracking is only performed inside of this mask image. + itkSetMacro( FaImage, ItkFloatImgType::Pointer) ///< Use this FA image instead of the automatically calculated one. Necessary for multi tensor tracking. + itkSetMacro( SeedsPerVoxel, int) ///< One seed placed in the center of each voxel or multiple seeds randomly placed inside each voxel. + itkSetMacro( FaThreshold, float) ///< FA termination criterion. + itkSetMacro( StepSize, float) ///< Integration step size in mm + itkSetMacro( F, float ) ///< Tensor deflection parameter f + itkSetMacro( G, float ) ///< Tensor deflection parameter g + itkSetMacro( Interpolate, bool ) ///< Toggle between nearest neighbour (false) and trilinear interpolation (true) + itkSetMacro( MinTractLength, float ) ///< Shorter tracts are discarded. itkGetMacro( MinTractLength, float ) - itkSetMacro( MinCurvatureRadius, float ) + itkSetMacro( MinCurvatureRadius, float ) ///< Tracking is stopped if curvature radius (in mm) is too small. itkGetMacro( MinCurvatureRadius, float ) - itkSetMacro( ResampleFibers, bool ) + itkSetMacro( ResampleFibers, bool ) ///< If enabled, the resulting fibers are resampled to feature point distances of 0.5*MinSpacing. This is recommendable for very short integration steps and many seeds. If disabled, the resulting fiber bundle might become very large. protected: StreamlineTrackingFilter(); ~StreamlineTrackingFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; - void CalculateNewPosition(itk::ContinuousIndex& pos, vnl_vector_fixed& dir, typename InputImageType::IndexType& index); - float FollowStreamline(itk::ContinuousIndex pos, int dirSign, vtkPoints* points, std::vector< vtkIdType >& ids, int imageIdx); - bool IsValidPosition(itk::ContinuousIndex& pos, typename InputImageType::IndexType& index, vnl_vector_fixed< float, 8 >& interpWeights, int imageIdx); + void CalculateNewPosition(itk::ContinuousIndex& pos, vnl_vector_fixed& dir, typename InputImageType::IndexType& index); ///< Calculate next integration step. + float FollowStreamline(itk::ContinuousIndex pos, int dirSign, vtkPoints* points, std::vector< vtkIdType >& ids, int imageIdx); ///< Start streamline in one direction. + bool IsValidPosition(itk::ContinuousIndex& pos, typename InputImageType::IndexType& index, vnl_vector_fixed< float, 8 >& interpWeights, int imageIdx); ///< Are we outside of the mask image? Is the FA too low? double RoundToNearest(double num); void BeforeThreadedGenerateData(); void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId); void AfterThreadedGenerateData(); - FiberPolyDataType AddPolyData(FiberPolyDataType poly1, FiberPolyDataType poly2); - - FiberPolyDataType m_FiberPolyData; - vtkSmartPointer m_Points; - vtkSmartPointer m_Cells; - - std::vector< ItkFloatImgType::Pointer > m_EmaxImage; - ItkFloatImgType::Pointer m_FaImage; - std::vector< ItkPDImgType::Pointer > m_PdImage; - std::vector< typename InputImageType::Pointer > m_InputImage; - - int m_NumberOfInputs; - float m_FaThreshold; - float m_MinCurvatureRadius; - float m_StepSize; - int m_MaxLength; - float m_MinTractLength; - int m_SeedsPerVoxel; - float m_F; - float m_G; - std::vector< int > m_ImageSize; - std::vector< float > m_ImageSpacing; - ItkUcharImgType::Pointer m_SeedImage; - ItkUcharImgType::Pointer m_MaskImage; - bool m_Interpolate; - float m_PointPistance; - bool m_ResampleFibers; + FiberPolyDataType AddPolyData(FiberPolyDataType poly1, FiberPolyDataType poly2); ///< Combine tracking results generated by the individual threads. + + FiberPolyDataType m_FiberPolyData; + vtkSmartPointer m_Points; + vtkSmartPointer m_Cells; + + std::vector< ItkFloatImgType::Pointer > m_EmaxImage; ///< Stores largest eigenvalues per voxel (one for each tensor) + ItkFloatImgType::Pointer m_FaImage; ///< FA image used to determine streamline termination. + std::vector< ItkPDImgType::Pointer > m_PdImage; ///< Stores principal direction of each tensor in each voxel. + std::vector< typename InputImageType::Pointer > m_InputImage; ///< Input tensor images. For multi tensor tracking provide multiple tensor images. + + int m_NumberOfInputs; + float m_FaThreshold; + float m_MinCurvatureRadius; + float m_StepSize; + int m_MaxLength; + float m_MinTractLength; + int m_SeedsPerVoxel; + float m_F; + float m_G; + bool m_Interpolate; + float m_PointPistance; + bool m_ResampleFibers; + std::vector< int > m_ImageSize; + std::vector< float > m_ImageSpacing; + ItkUcharImgType::Pointer m_SeedImage; + ItkUcharImgType::Pointer m_MaskImage; itk::VectorContainer< int, FiberPolyDataType >::Pointer m_PolyDataContainer; private: }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkStreamlineTrackingFilter.cpp" #endif #endif //__itkStreamlineTrackingFilter_h_ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp index 993b9c70d6..03dbaedf03 100755 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp @@ -1,886 +1,885 @@ /*=================================================================== 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 namespace itk { template< class PixelType > TractsToDWIImageFilter< PixelType >::TractsToDWIImageFilter() : 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 ) { // create slice object ImageRegion<2> sliceRegion; sliceRegion.SetSize(0, m_UpsampledImageRegion.GetSize()[0]); sliceRegion.SetSize(1, m_UpsampledImageRegion.GetSize()[1]); Vector< double, 2 > sliceSpacing; sliceSpacing[0] = m_UpsampledSpacing[0]; sliceSpacing[1] = m_UpsampledSpacing[1]; // frequency map slice SliceType::Pointer fMapSlice = NULL; if (m_Parameters.m_FrequencyMap.IsNotNull()) { fMapSlice = SliceType::New(); ImageRegion<2> region; region.SetSize(0, m_UpsampledImageRegion.GetSize()[0]); region.SetSize(1, m_UpsampledImageRegion.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_ImageSpacing ); newImage->SetOrigin( m_Parameters.m_ImageOrigin ); newImage->SetDirection( m_Parameters.m_ImageDirection ); newImage->SetLargestPossibleRegion( m_Parameters.m_ImageRegion ); newImage->SetBufferedRegion( m_Parameters.m_ImageRegion ); newImage->SetRequestedRegion( m_Parameters.m_ImageRegion ); newImage->SetVectorLength( images.at(0)->GetVectorLength() ); newImage->Allocate(); MatrixType transform = m_Parameters.m_ImageDirection; for (int i=0; i<3; i++) for (int j=0; j<3; j++) { if (j<2) transform[i][j] *= m_UpsampledSpacing[j]; else transform[i][j] *= m_Parameters.m_ImageSpacing[j]; } std::vector< unsigned int > spikeVolume; for (int i=0; iGetIntegerVariate()%images.at(0)->GetVectorLength()); std::sort (spikeVolume.begin(), spikeVolume.end()); std::reverse (spikeVolume.begin(), spikeVolume.end()); 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)); for (unsigned int g=0; gGetVectorLength(); g++) { std::vector< 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; 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_FrequencyMap->GetPixel(index3D)); } compartmentSlices.push_back(slice); t2Vector.push_back(signalModel->GetT2()); } if (this->GetAbortGenerateData()) return NULL; // create k-sapce (inverse fourier transform slices) itk::Size<2> outSize; outSize.SetElement(0, m_Parameters.m_ImageRegion.GetSize(0)); outSize.SetElement(1, m_Parameters.m_ImageRegion.GetSize(1)); itk::KspaceImageFilter< SliceType::PixelType >::Pointer idft = itk::KspaceImageFilter< SliceType::PixelType >::New(); idft->SetCompartmentImages(compartmentSlices); idft->SetT2(t2Vector); idft->SetUseConstantRandSeed(m_UseConstantRandSeed); idft->SetkOffset(m_Parameters.m_KspaceLineOffset); idft->SettLine(m_Parameters.m_tLine); idft->SetTE(m_Parameters.m_tEcho); idft->SetTinhom(m_Parameters.m_tInhom); idft->SetSimulateRelaxation(m_Parameters.m_DoSimulateRelaxation); idft->SetEddyGradientMagnitude(m_Parameters.m_EddyStrength); idft->SetZ((double)z-(double)images.at(0)->GetLargestPossibleRegion().GetSize(2)/2.0); idft->SetDirectionMatrix(transform); idft->SetDiffusionGradientDirection(m_Parameters.m_FiberModelList.at(0)->GetGradientDirection(g)); idft->SetFrequencyMap(fMapSlice); idft->SetSignalScale(m_Parameters.m_SignalScale); idft->SetOutSize(outSize); int numSpikes = 0; while (!spikeSlice.empty() && spikeSlice.back()==z) { numSpikes++; spikeSlice.pop_back(); } idft->SetSpikes(numSpikes); idft->SetSpikeAmplitude(m_Parameters.m_SpikeAmplitude); idft->Update(); ComplexSliceType::Pointer fSlice; fSlice = idft->GetOutput(); ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; // 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(); // 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); } ++disp; newTick = 50*disp.count()/disp.expected_count(); for (int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; } } m_StatusText += "\n\n"; return newImage; } template< class PixelType > void TractsToDWIImageFilter< PixelType >::GenerateData() { m_StartTime = clock(); m_StatusText = "Starting simulation\n"; // check input data if (m_FiberBundle.IsNull()) itkExceptionMacro("Input fiber bundle is NULL!"); if (m_Parameters.m_DoDisablePartialVolume) while (m_Parameters.m_FiberModelList.size()>1) m_Parameters.m_FiberModelList.pop_back(); if (m_Parameters.m_NonFiberModelList.empty()) itkExceptionMacro("No diffusion model for non-fiber compartments defined!"); int baselineIndex = m_Parameters.GetFirstBaselineIndex(); if (baselineIndex<0) itkExceptionMacro("No baseline index found!"); if (m_UseConstantRandSeed) // always generate the same random numbers? m_RandGen->SetSeed(0); else m_RandGen->SetSeed(); // initialize output dwi image ImageRegion<3> croppedRegion = m_Parameters.m_ImageRegion; croppedRegion.SetSize(1, croppedRegion.GetSize(1)*m_Parameters.m_Wrap); itk::Point shiftedOrigin = m_Parameters.m_ImageOrigin; shiftedOrigin[1] += (m_Parameters.m_ImageRegion.GetSize(1)-croppedRegion.GetSize(1))*m_Parameters.m_ImageSpacing[1]/2; - typename OutputImageType::Pointer outImage = OutputImageType::New(); outImage->SetSpacing( m_Parameters.m_ImageSpacing ); outImage->SetOrigin( shiftedOrigin ); outImage->SetDirection( m_Parameters.m_ImageDirection ); outImage->SetLargestPossibleRegion( croppedRegion ); outImage->SetBufferedRegion( croppedRegion ); outImage->SetRequestedRegion( croppedRegion ); outImage->SetVectorLength( m_Parameters.GetNumVolumes() ); outImage->Allocate(); typename OutputImageType::PixelType temp; temp.SetSize(m_Parameters.GetNumVolumes()); temp.Fill(0.0); outImage->FillBuffer(temp); // ADJUST GEOMETRY FOR FURTHER PROCESSING // is input slize size a power of two? unsigned int x=m_Parameters.m_ImageRegion.GetSize(0); unsigned int y=m_Parameters.m_ImageRegion.GetSize(1); ItkDoubleImgType::SizeType pad; pad[0]=x%2; pad[1]=y%2; pad[2]=0; m_Parameters.m_ImageRegion.SetSize(0, x+pad[0]); m_Parameters.m_ImageRegion.SetSize(1, y+pad[1]); if (m_Parameters.m_FrequencyMap.IsNotNull() && (pad[0]>0 || pad[1]>0)) { itk::ConstantPadImageFilter::Pointer zeroPadder = itk::ConstantPadImageFilter::New(); zeroPadder->SetInput(m_Parameters.m_FrequencyMap); zeroPadder->SetConstant(0); zeroPadder->SetPadUpperBound(pad); zeroPadder->Update(); m_Parameters.m_FrequencyMap = zeroPadder->GetOutput(); } if (m_Parameters.m_MaskImage.IsNotNull() && (pad[0]>0 || pad[1]>0)) { itk::ConstantPadImageFilter::Pointer zeroPadder = itk::ConstantPadImageFilter::New(); zeroPadder->SetInput(m_Parameters.m_MaskImage); zeroPadder->SetConstant(0); zeroPadder->SetPadUpperBound(pad); zeroPadder->Update(); m_Parameters.m_MaskImage = zeroPadder->GetOutput(); } - // apply in-plane upsampling + // Apply in-plane upsampling for Gibbs ringing artifact double upsampling = 1; if (m_Parameters.m_DoAddGibbsRinging) upsampling = 2; m_UpsampledSpacing = m_Parameters.m_ImageSpacing; m_UpsampledSpacing[0] /= upsampling; m_UpsampledSpacing[1] /= upsampling; m_UpsampledImageRegion = m_Parameters.m_ImageRegion; m_UpsampledImageRegion.SetSize(0, m_Parameters.m_ImageRegion.GetSize()[0]*upsampling); m_UpsampledImageRegion.SetSize(1, m_Parameters.m_ImageRegion.GetSize()[1]*upsampling); m_UpsampledOrigin = m_Parameters.m_ImageOrigin; m_UpsampledOrigin[0] -= m_Parameters.m_ImageSpacing[0]/2; m_UpsampledOrigin[0] += m_UpsampledSpacing[0]/2; m_UpsampledOrigin[1] -= m_Parameters.m_ImageSpacing[1]/2; m_UpsampledOrigin[1] += m_UpsampledSpacing[1]/2; m_UpsampledOrigin[2] -= m_Parameters.m_ImageSpacing[2]/2; m_UpsampledOrigin[2] += m_UpsampledSpacing[2]/2; // generate double images to store the individual compartment signals std::vector< DoubleDwiType::Pointer > compartments; for (unsigned int i=0; iSetSpacing( m_UpsampledSpacing ); doubleDwi->SetOrigin( m_UpsampledOrigin ); doubleDwi->SetDirection( m_Parameters.m_ImageDirection ); doubleDwi->SetLargestPossibleRegion( m_UpsampledImageRegion ); doubleDwi->SetBufferedRegion( m_UpsampledImageRegion ); doubleDwi->SetRequestedRegion( m_UpsampledImageRegion ); doubleDwi->SetVectorLength( m_Parameters.GetNumVolumes() ); doubleDwi->Allocate(); DoubleDwiType::PixelType pix; pix.SetSize(m_Parameters.GetNumVolumes()); pix.Fill(0.0); doubleDwi->FillBuffer(pix); compartments.push_back(doubleDwi); } // initialize volume fraction images m_VolumeFractions.clear(); for (unsigned int i=0; iSetSpacing( m_UpsampledSpacing ); doubleImg->SetOrigin( m_UpsampledOrigin ); doubleImg->SetDirection( m_Parameters.m_ImageDirection ); doubleImg->SetLargestPossibleRegion( m_UpsampledImageRegion ); doubleImg->SetBufferedRegion( m_UpsampledImageRegion ); doubleImg->SetRequestedRegion( m_UpsampledImageRegion ); doubleImg->Allocate(); doubleImg->FillBuffer(0); m_VolumeFractions.push_back(doubleImg); } // resample mask image and frequency map to fit upsampled geometry if (m_Parameters.m_DoAddGibbsRinging) { if (m_Parameters.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_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_MaskImage); resampler->SetSize(m_UpsampledImageRegion.GetSize()); resampler->SetOutputSpacing(m_UpsampledSpacing); resampler->SetOutputOrigin(m_UpsampledOrigin); resampler->Update(); m_Parameters.m_MaskImage = resampler->GetOutput(); } // resample frequency map if (m_Parameters.m_FrequencyMap.IsNotNull()) { itk::ResampleImageFilter::Pointer resampler = itk::ResampleImageFilter::New(); resampler->SetInput(m_Parameters.m_FrequencyMap); resampler->SetOutputParametersFromImage(m_Parameters.m_FrequencyMap); resampler->SetSize(m_UpsampledImageRegion.GetSize()); resampler->SetOutputSpacing(m_UpsampledSpacing); resampler->SetOutputOrigin(m_UpsampledOrigin); resampler->Update(); m_Parameters.m_FrequencyMap = resampler->GetOutput(); } } // no input tissue mask is set -> create default bool maskImageSet = true; if (m_Parameters.m_MaskImage.IsNull()) { m_StatusText += "No tissue mask set\n"; MITK_INFO << "No tissue mask set"; m_Parameters.m_MaskImage = ItkUcharImgType::New(); m_Parameters.m_MaskImage->SetSpacing( m_UpsampledSpacing ); m_Parameters.m_MaskImage->SetOrigin( m_UpsampledOrigin ); m_Parameters.m_MaskImage->SetDirection( m_Parameters.m_ImageDirection ); m_Parameters.m_MaskImage->SetLargestPossibleRegion( m_UpsampledImageRegion ); m_Parameters.m_MaskImage->SetBufferedRegion( m_UpsampledImageRegion ); m_Parameters.m_MaskImage->SetRequestedRegion( m_UpsampledImageRegion ); m_Parameters.m_MaskImage->Allocate(); m_Parameters.m_MaskImage->FillBuffer(1); maskImageSet = false; } else { m_StatusText += "Using tissue mask\n"; MITK_INFO << "Using tissue mask"; } m_Parameters.m_ImageRegion = croppedRegion; x=m_Parameters.m_ImageRegion.GetSize(0); y=m_Parameters.m_ImageRegion.GetSize(1); if ( x%2 == 1 ) m_Parameters.m_ImageRegion.SetSize(0, x+1); if ( y%2 == 1 ) m_Parameters.m_ImageRegion.SetSize(1, y+1); // resample fiber bundle for sufficient voxel coverage m_StatusText += "\n"+this->GetTime()+" > Resampling fibers ...\n"; double segmentVolume = 0.0001; float minSpacing = 1; if(m_UpsampledSpacing[0]GetDeepCopy(); double volumeAccuracy = 10; fiberBundle->ResampleFibers(minSpacing/volumeAccuracy); double mmRadius = m_Parameters.m_AxonRadius/1000; if (mmRadius>0) segmentVolume = M_PI*mmRadius*mmRadius*minSpacing/volumeAccuracy; double maxVolume = 0; double voxelVolume = m_UpsampledSpacing[0]*m_UpsampledSpacing[1]*m_UpsampledSpacing[2]; if (m_Parameters.m_DoAddMotion) { if (m_Parameters.m_DoRandomizeMotion) { m_StatusText += "Adding random motion artifacts:\n"; m_StatusText += "Maximum rotation: +/-" + boost::lexical_cast(m_Parameters.m_Rotation) + "°\n"; m_StatusText += "Maximum translation: +/-" + boost::lexical_cast(m_Parameters.m_Translation) + "mm\n"; } else { m_StatusText += "Adding linear motion artifacts:\n"; m_StatusText += "Maximum rotation: " + boost::lexical_cast(m_Parameters.m_Rotation) + "°\n"; m_StatusText += "Maximum translation: " + boost::lexical_cast(m_Parameters.m_Translation) + "mm\n"; } MITK_INFO << "Adding motion artifacts"; MITK_INFO << "Maximum rotation: " << m_Parameters.m_Rotation; MITK_INFO << "Maxmimum translation: " << m_Parameters.m_Translation; } maxVolume = 0; m_StatusText += "\n"+this->GetTime()+" > Generating signal of " + boost::lexical_cast(m_Parameters.m_FiberModelList.size()) + " fiber compartments\n"; MITK_INFO << "Generating signal of " << m_Parameters.m_FiberModelList.size() << " fiber compartments"; int numFibers = m_FiberBundle->GetNumFibers(); boost::progress_display disp(numFibers*m_Parameters.GetNumVolumes()); ofstream logFile; logFile.open("fiberfox_motion.log"); logFile << "0 rotation: 0,0,0; translation: 0,0,0\n"; // get transform for motion artifacts FiberBundleType fiberBundleTransformed = fiberBundle; VectorType rotation = m_Parameters.m_Rotation/m_Parameters.GetNumVolumes(); VectorType translation = m_Parameters.m_Translation/m_Parameters.GetNumVolumes(); // creat image to hold transformed mask (motion artifact) ItkUcharImgType::Pointer tempTissueMask = ItkUcharImgType::New(); itk::ImageDuplicator::Pointer duplicator = itk::ImageDuplicator::New(); duplicator->SetInputImage(m_Parameters.m_MaskImage); duplicator->Update(); tempTissueMask = duplicator->GetOutput(); // second upsampling needed for motion artifacts ImageRegion<3> upsampledImageRegion = m_UpsampledImageRegion; itk::Vector upsampledSpacing = m_UpsampledSpacing; upsampledSpacing[0] /= 4; upsampledSpacing[1] /= 4; upsampledSpacing[2] /= 4; upsampledImageRegion.SetSize(0, m_UpsampledImageRegion.GetSize()[0]*4); upsampledImageRegion.SetSize(1, m_UpsampledImageRegion.GetSize()[1]*4); upsampledImageRegion.SetSize(2, m_UpsampledImageRegion.GetSize()[2]*4); itk::Point upsampledOrigin = m_UpsampledOrigin; upsampledOrigin[0] -= m_UpsampledSpacing[0]/2; upsampledOrigin[0] += upsampledSpacing[0]/2; upsampledOrigin[1] -= m_UpsampledSpacing[1]/2; upsampledOrigin[1] += upsampledSpacing[1]/2; upsampledOrigin[2] -= m_UpsampledSpacing[2]/2; upsampledOrigin[2] += upsampledSpacing[2]/2; ItkUcharImgType::Pointer upsampledTissueMask = ItkUcharImgType::New(); itk::ResampleImageFilter::Pointer upsampler = itk::ResampleImageFilter::New(); upsampler->SetInput(m_Parameters.m_MaskImage); upsampler->SetOutputParametersFromImage(m_Parameters.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(); upsampledTissueMask = upsampler->GetOutput(); m_StatusText += "0% 10 20 30 40 50 60 70 80 90 100%\n"; m_StatusText += "|----|----|----|----|----|----|----|----|----|----|\n*"; unsigned int lastTick = 0; for (int g=0; gGetFiberPolyData(); ItkDoubleImgType::Pointer intraAxonalVolume = ItkDoubleImgType::New(); intraAxonalVolume->SetSpacing( m_UpsampledSpacing ); intraAxonalVolume->SetOrigin( m_UpsampledOrigin ); intraAxonalVolume->SetDirection( m_Parameters.m_ImageDirection ); intraAxonalVolume->SetLargestPossibleRegion( m_UpsampledImageRegion ); intraAxonalVolume->SetBufferedRegion( m_UpsampledImageRegion ); intraAxonalVolume->SetRequestedRegion( m_UpsampledImageRegion ); intraAxonalVolume->Allocate(); intraAxonalVolume->FillBuffer(0); // generate fiber signal (if there are any fiber models present) if (!m_Parameters.m_FiberModelList.empty()) for( int i=0; iGetCell(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; tempTissueMask->TransformPhysicalPointToIndex(vertex, idx); tempTissueMask->TransformPhysicalPointToContinuousIndex(vertex, contIndex); if (!tempTissueMask->GetLargestPossibleRegion().IsInside(idx) || tempTissueMask->GetPixel(idx)<=0) continue; // generate signal for each fiber compartment for (unsigned int k=0; kSetFiberDirection(dir); DoubleDwiType::PixelType pix = doubleDwi->GetPixel(idx); pix[g] += segmentVolume*m_Parameters.m_FiberModelList[k]->SimulateMeasurement(g); doubleDwi->SetPixel(idx, pix ); double vol = intraAxonalVolume->GetPixel(idx) + segmentVolume; intraAxonalVolume->SetPixel(idx, vol ); if (g==0 && vol>maxVolume) maxVolume = vol; } } ++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(tempTissueMask, tempTissueMask->GetLargestPossibleRegion()); double fact = 1; if (m_Parameters.m_AxonRadius<0.0001) fact = voxelVolume/maxVolume; while(!it3.IsAtEnd()) { if (it3.Get()>0) { DoubleDwiType::IndexType index = it3.GetIndex(); // get fiber volume fraction DoubleDwiType::Pointer fiberDwi = compartments.at(0); DoubleDwiType::PixelType fiberPix = fiberDwi->GetPixel(index); // intra axonal compartment if (fact>1) // auto scale intra-axonal if no fiber radius is specified { fiberPix[g] *= fact; fiberDwi->SetPixel(index, fiberPix); } double f = intraAxonalVolume->GetPixel(index)*fact; if (f>voxelVolume || (f>0.0 && m_Parameters.m_DoDisablePartialVolume) ) // more fiber than space in voxel? { fiberPix[g] *= voxelVolume/f; fiberDwi->SetPixel(index, fiberPix); m_VolumeFractions.at(0)->SetPixel(index, 1); } else { m_VolumeFractions.at(0)->SetPixel(index, f/voxelVolume); double nonf = voxelVolume-f; // non-fiber volume double inter = 0; if (m_Parameters.m_FiberModelList.size()>1) inter = nonf * f/voxelVolume; // inter-axonal fraction of non fiber compartment scales linearly with f double other = nonf - inter; // rest of compartment double singleinter = inter/(m_Parameters.m_FiberModelList.size()-1); // adjust non-fiber and intra-axonal signal for (unsigned int i=1; iGetPixel(index); if (f>0) pix[g] /= f; pix[g] *= singleinter; doubleDwi->SetPixel(index, pix); m_VolumeFractions.at(i)->SetPixel(index, singleinter/voxelVolume); } for (unsigned int i=0; iGetPixel(index); // if (dynamic_cast< mitk::AstroStickModel* >(m_Parameters.m_NonFiberModelList.at(i))) // { // mitk::AstroStickModel* model = dynamic_cast< mitk::AstroStickModel* >(m_Parameters.m_NonFiberModelList.at(i)); // model->SetSeed(8111984); // } pix[g] += m_Parameters.m_NonFiberModelList[i]->SimulateMeasurement(g)*other*m_Parameters.m_NonFiberModelList[i]->GetWeight(); doubleDwi->SetPixel(index, pix); m_VolumeFractions.at(i+m_Parameters.m_FiberModelList.size())->SetPixel(index, other/voxelVolume*m_Parameters.m_NonFiberModelList[i]->GetWeight()); } } } ++it3; } // move fibers if (m_Parameters.m_DoAddMotion) { if (m_Parameters.m_DoRandomizeMotion) { fiberBundleTransformed = fiberBundle->GetDeepCopy(); rotation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_Rotation[0]*2)-m_Parameters.m_Rotation[0]; rotation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_Rotation[1]*2)-m_Parameters.m_Rotation[1]; rotation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_Rotation[2]*2)-m_Parameters.m_Rotation[2]; translation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_Translation[0]*2)-m_Parameters.m_Translation[0]; translation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_Translation[1]*2)-m_Parameters.m_Translation[1]; translation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_Translation[2]*2)-m_Parameters.m_Translation[2]; } // rotate mask image if (maskImageSet) { ImageRegionIterator maskIt(upsampledTissueMask, upsampledTissueMask->GetLargestPossibleRegion()); tempTissueMask->FillBuffer(0); while(!maskIt.IsAtEnd()) { if (maskIt.Get()<=0) { ++maskIt; continue; } DoubleDwiType::IndexType index = maskIt.GetIndex(); itk::Point point; upsampledTissueMask->TransformIndexToPhysicalPoint(index, point); if (m_Parameters.m_DoRandomizeMotion) point = fiberBundle->TransformPoint(point.GetVnlVector(), rotation[0],rotation[1],rotation[2],translation[0],translation[1],translation[2]); else point = fiberBundle->TransformPoint(point.GetVnlVector(), rotation[0]*(g+1),rotation[1]*(g+1),rotation[2]*(g+1),translation[0]*(g+1),translation[1]*(g+1),translation[2]*(g+1)); tempTissueMask->TransformPhysicalPointToIndex(point, index); if (tempTissueMask->GetLargestPossibleRegion().IsInside(index)) tempTissueMask->SetPixel(index,100); ++maskIt; } } // rotate fibers logFile << g+1 << " rotation:" << rotation[0] << "," << rotation[1] << "," << rotation[2] << ";"; logFile << " translation:" << translation[0] << "," << translation[1] << "," << translation[2] << "\n"; fiberBundleTransformed->TransformFibers(rotation[0],rotation[1],rotation[2],translation[0],translation[1],translation[2]); } } logFile.close(); m_StatusText += "\n\n"; if (this->GetAbortGenerateData()) { m_StatusText += "\n"+this->GetTime()+" > Simulation aborted\n"; return; } // do k-space stuff DoubleDwiType::Pointer doubleOutImage; if (m_Parameters.m_Spikes>0 || m_Parameters.m_FrequencyMap.IsNotNull() || m_Parameters.m_KspaceLineOffset>0 || m_Parameters.m_DoSimulateRelaxation || m_Parameters.m_EddyStrength>0 || m_Parameters.m_DoAddGibbsRinging || m_Parameters.m_Wrap<1.0) { m_StatusText += this->GetTime()+" > Adjusting complex signal\n"; MITK_INFO << "Adjusting complex signal:"; if (m_Parameters.m_DoSimulateRelaxation) m_StatusText += "Simulating signal relaxation\n"; if (m_Parameters.m_FrequencyMap.IsNotNull()) m_StatusText += "Simulating distortions\n"; if (m_Parameters.m_DoAddGibbsRinging) m_StatusText += "Simulating ringing artifacts\n"; if (m_Parameters.m_EddyStrength>0) m_StatusText += "Simulating eddy currents\n"; if (m_Parameters.m_Spikes>0) m_StatusText += "Simulating spikes\n"; if (m_Parameters.m_Wrap<1.0) m_StatusText += "Simulating aliasing artifacts\n"; if (m_Parameters.m_KspaceLineOffset>0) m_StatusText += "Simulating ghosts\n"; doubleOutImage = DoKspaceStuff(compartments); m_Parameters.m_SignalScale = 1; } else { m_StatusText += this->GetTime()+" > Summing compartments\n"; MITK_INFO << "Summing compartments"; doubleOutImage = compartments.at(0); for (unsigned int i=1; i::Pointer adder = itk::AddImageFilter< DoubleDwiType, DoubleDwiType, DoubleDwiType>::New(); adder->SetInput1(doubleOutImage); adder->SetInput2(compartments.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_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 (outImage, outImage->GetLargestPossibleRegion()); DoubleDwiType::PixelType signal; signal.SetSize(m_Parameters.GetNumVolumes()); boost::progress_display disp2(outImage->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 (int tick = 0; tick<(newTick-lastTick); tick++) m_StatusText += "*"; lastTick = newTick; typename OutputImageType::IndexType index = it4.GetIndex(); signal = doubleOutImage->GetPixel(index)*m_Parameters.m_SignalScale; if (m_Parameters.m_NoiseModel!=NULL) { DoubleDwiType::PixelType accu = signal; accu.Fill(0.0); for (unsigned int i=0; iAddNoise(temp); accu += temp; } signal = accu/m_Parameters.m_Repetitions; } for (unsigned int i=0; i0) signal[i] = floor(signal[i]+0.5); else signal[i] = ceil(signal[i]-0.5); if (!m_Parameters.IsBaselineIndex(i) && signal[i]>window) window = signal[i]; if (!m_Parameters.IsBaselineIndex(i) && signal[i]SetNthOutput(0, outImage); m_StatusText += "\n\n"; m_StatusText += "Finished simulation\n"; m_StatusText += "Simulation time: "+GetTime(); } 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 > std::string TractsToDWIImageFilter< PixelType >::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; } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h index 4b3a9fcb4d..55e21eee46 100755 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h @@ -1,103 +1,104 @@ /*=================================================================== 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 "FiberTrackingExports.h" namespace itk { /** -* \brief Generates artificial diffusion weighted image volume from the input fiberbundle using a generic multicompartment model. */ +* \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 ItkDoubleImgType; typedef itk::Image ItkUcharImgType; typedef mitk::FiberBundleX::Pointer FiberBundleType; typedef itk::VectorImage< double, 3 > DoubleDwiType; typedef itk::Matrix MatrixType; typedef itk::Image< double, 2 > SliceType; typedef itk::VnlForwardFFTImageFilter::OutputImageType ComplexSliceType; typedef itk::Vector< double,3> VectorType; itkNewMacro(Self) itkTypeMacro( TractsToDWIImageFilter, ImageSource ) - // input - itkSetMacro( FiberBundle, FiberBundleType ) ///< input fiber bundle - mitk::LevelWindow GetLevelWindow(){ return m_LevelWindow; } - itkGetMacro( StatusText, std::string ) - itkSetMacro( UseConstantRandSeed, bool ) + /** Input */ + itkSetMacro( FiberBundle, FiberBundleType ) ///< Input fiber bundle + itkSetMacro( UseConstantRandSeed, bool ) ///< Seed for random generator. + void SetParameters( FiberfoxParameters param ) ///< Simulation parameters. + { m_Parameters = param; } - void SetParameters( FiberfoxParameters param ){ m_Parameters = param; } + /** Output */ FiberfoxParameters GetParameters(){ return m_Parameters; } - - // output 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 ) 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); 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); - mitk::FiberfoxParameters m_Parameters; - - itk::Vector m_UpsampledSpacing; - itk::Point m_UpsampledOrigin; - ImageRegion<3> m_UpsampledImageRegion; - FiberBundleType m_FiberBundle; + mitk::FiberfoxParameters m_Parameters; + itk::Vector m_UpsampledSpacing; + itk::Point m_UpsampledOrigin; + ImageRegion<3> m_UpsampledImageRegion; + FiberBundleType m_FiberBundle; mitk::LevelWindow m_LevelWindow; std::vector< ItkDoubleImgType::Pointer > m_VolumeFractions; + std::string m_StatusText; + time_t m_StartTime; + bool m_UseConstantRandSeed; itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer m_RandGen; - std::string m_StatusText; - time_t m_StartTime; - bool m_UseConstantRandSeed; }; } #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 18cce5ed37..240242320c 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp @@ -1,450 +1,450 @@ /*=================================================================== 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 "mitkFiberfoxParameters.h" #include #include #include #include #include template< class ScalarType > mitk::FiberfoxParameters< ScalarType >::FiberfoxParameters() : m_DoAddGibbsRinging(false) , m_ArtifactModelString("") , m_AxonRadius(0) , m_Bvalue(1000) , m_DoAddMotion(false) , m_DoDisablePartialVolume(false) , m_DoSimulateRelaxation(true) , m_EddyStrength(0) , m_KspaceLineOffset(0) , m_NumGradients(6) , m_NumBaseline(1) , m_OutputPath("") , m_DoRandomizeMotion(true) , m_Repetitions(1) , m_SignalModelString("") , m_SignalScale(100) , m_SpikeAmplitude(1) , m_Spikes(0) , m_tEcho(100) , m_tInhom(50) , m_tLine(1) , m_Wrap(1) , m_MaskImage(NULL) , m_FrequencyMap(NULL) , m_NoiseModel(NULL) { m_ImageDirection.SetIdentity(); m_ImageOrigin.Fill(0.0); m_ImageRegion.SetSize(0, 11); m_ImageRegion.SetSize(1, 11); m_ImageRegion.SetSize(2, 3); m_ImageSpacing.Fill(2.0); m_Translation.Fill(0.0); m_Rotation.Fill(0.0); m_ResultNode = mitk::DataNode::New(); m_ParentNode = NULL; - GenerateHalfShell(); + GenerateGradientHalfShell(); } template< class ScalarType > mitk::FiberfoxParameters< ScalarType >::~FiberfoxParameters() { // if (m_NoiseModel!=NULL) // delete m_NoiseModel; } template< class ScalarType > -void mitk::FiberfoxParameters< ScalarType >::GenerateHalfShell() +void mitk::FiberfoxParameters< ScalarType >::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 std::vector< int > mitk::FiberfoxParameters< ScalarType >::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; } template< class ScalarType > unsigned int mitk::FiberfoxParameters< ScalarType >::GetFirstBaselineIndex() { for( unsigned int i=0; im_GradientDirections.size(); i++) if (m_GradientDirections.at(i).GetNorm()<0.0001) return i; return -1; } template< class ScalarType > bool mitk::FiberfoxParameters< ScalarType >::IsBaselineIndex(unsigned int idx) { if (m_GradientDirections.size()>idx && m_GradientDirections.at(idx).GetNorm()<0.0001) return true; return false; } template< class ScalarType > unsigned int mitk::FiberfoxParameters< ScalarType >::GetNumWeightedVolumes() { return m_NumGradients; } template< class ScalarType > unsigned int mitk::FiberfoxParameters< ScalarType >::GetNumBaselineVolumes() { return m_NumBaseline; } template< class ScalarType > unsigned int mitk::FiberfoxParameters< ScalarType >::GetNumVolumes() { return m_GradientDirections.size(); } template< class ScalarType > typename mitk::FiberfoxParameters< ScalarType >::GradientListType mitk::FiberfoxParameters< ScalarType >::GetGradientDirections() { return m_GradientDirections; } template< class ScalarType > typename mitk::FiberfoxParameters< ScalarType >::GradientType mitk::FiberfoxParameters< ScalarType >::GetGradientDirection(unsigned int i) { if (i void mitk::FiberfoxParameters< ScalarType >::SetNumWeightedGradients(int numGradients) { m_NumGradients = numGradients; - GenerateHalfShell(); + GenerateGradientHalfShell(); } template< class ScalarType > void mitk::FiberfoxParameters< ScalarType >::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++; } } template< class ScalarType > void mitk::FiberfoxParameters< ScalarType >::SetGradienDirections(mitk::DiffusionImage::GradientDirectionContainerType::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 >::LoadParameters(string filename) { boost::property_tree::ptree parameters; boost::property_tree::xml_parser::read_xml(filename, parameters); m_FiberModelList.clear(); m_NonFiberModelList.clear(); if (m_NoiseModel!=NULL) delete m_NoiseModel; BOOST_FOREACH( boost::property_tree::ptree::value_type const& v1, parameters.get_child("fiberfox") ) { if( v1.first == "image" ) { m_ImageRegion.SetSize(0, v1.second.get("basic.size.x")); m_ImageRegion.SetSize(1, v1.second.get("basic.size.y")); m_ImageRegion.SetSize(2, v1.second.get("basic.size.z")); m_ImageSpacing[0] = v1.second.get("basic.spacing.x"); m_ImageSpacing[1] = v1.second.get("basic.spacing.y"); m_ImageSpacing[2] = v1.second.get("basic.spacing.z"); m_NumGradients = v1.second.get("basic.numgradients"); - GenerateHalfShell(); + GenerateGradientHalfShell(); m_Bvalue = v1.second.get("basic.bvalue"); m_Repetitions = v1.second.get("repetitions"); m_SignalScale = v1.second.get("signalScale"); m_tEcho = v1.second.get("tEcho"); m_tLine = v1.second.get("tLine"); m_tInhom = v1.second.get("tInhom"); m_AxonRadius = v1.second.get("axonRadius"); m_DoSimulateRelaxation = v1.second.get("doSimulateRelaxation"); m_DoDisablePartialVolume = v1.second.get("doDisablePartialVolume"); if (v1.second.get("artifacts.addnoise")) { switch (v1.second.get("artifacts.noisedistribution")) { case 0: m_NoiseModel = new mitk::RicianNoiseModel< ScalarType >(); break; case 1: m_NoiseModel = new mitk::ChiSquareNoiseModel< ScalarType >(); break; default: m_NoiseModel = new mitk::RicianNoiseModel< ScalarType >(); } m_NoiseModel->SetNoiseVariance(v1.second.get("artifacts.noisevariance")); } m_KspaceLineOffset = v1.second.get("artifacts.m_KspaceLineOffset"); m_Wrap = (100-v1.second.get("artifacts.aliasingfactor"))/100; m_Spikes = v1.second.get("artifacts.m_Spikesnum"); m_SpikeAmplitude = v1.second.get("artifacts.m_Spikesscale"); m_EddyStrength = v1.second.get("artifacts.m_EddyStrength"); m_DoAddGibbsRinging = v1.second.get("artifacts.addringing"); m_DoAddMotion = v1.second.get("artifacts.m_DoAddMotion"); m_DoRandomizeMotion = v1.second.get("artifacts.m_RandomMotion"); m_Translation[0] = v1.second.get("artifacts.m_Translation0"); m_Translation[1] = v1.second.get("artifacts.m_Translation1"); m_Translation[2] = v1.second.get("artifacts.m_Translation2"); m_Rotation[0] = v1.second.get("artifacts.m_Rotation0"); m_Rotation[1] = v1.second.get("artifacts.m_Rotation1"); m_Rotation[2] = v1.second.get("artifacts.m_Rotation2"); // compartment 1 switch (v1.second.get("compartment1.index")) { case 0: mitk::StickModel* stickModel = new mitk::StickModel(); stickModel->SetGradientList(m_GradientDirections); stickModel->SetBvalue(m_Bvalue); stickModel->SetDiffusivity(v1.second.get("compartment1.stick.d")); stickModel->SetT2(v1.second.get("compartment1.stick.t2")); m_FiberModelList.push_back(stickModel); break; case 1: mitk::TensorModel* zeppelinModel = new mitk::TensorModel(); zeppelinModel->SetGradientList(m_GradientDirections); zeppelinModel->SetBvalue(m_Bvalue); zeppelinModel->SetDiffusivity1(v1.second.get("compartment1.zeppelin.d1")); zeppelinModel->SetDiffusivity2(v1.second.get("compartment1.zeppelin.d2")); zeppelinModel->SetDiffusivity3(v1.second.get("compartment1.zeppelin.d2")); zeppelinModel->SetT2(v1.second.get("compartment1.zeppelin.t2")); m_FiberModelList.push_back(zeppelinModel); break; case 2: mitk::TensorModel* tensorModel = new mitk::TensorModel(); tensorModel->SetGradientList(m_GradientDirections); tensorModel->SetBvalue(m_Bvalue); tensorModel->SetDiffusivity1(v1.second.get("compartment1.tensor.d1")); tensorModel->SetDiffusivity2(v1.second.get("compartment1.tensor.d2")); tensorModel->SetDiffusivity3(v1.second.get("compartment1.tensor.d3")); tensorModel->SetT2(v1.second.get("compartment1.tensor.t2")); m_FiberModelList.push_back(tensorModel); break; } // compartment 2 switch (v1.second.get("compartment2.index")) { case 0: mitk::StickModel* stickModel = new mitk::StickModel(); stickModel->SetGradientList(m_GradientDirections); stickModel->SetBvalue(m_Bvalue); stickModel->SetDiffusivity(v1.second.get("compartment2.stick.d")); stickModel->SetT2(v1.second.get("compartment2.stick.t2")); m_FiberModelList.push_back(stickModel); break; case 1: mitk::TensorModel* zeppelinModel = new mitk::TensorModel(); zeppelinModel->SetGradientList(m_GradientDirections); zeppelinModel->SetBvalue(m_Bvalue); zeppelinModel->SetDiffusivity1(v1.second.get("compartment2.zeppelin.d1")); zeppelinModel->SetDiffusivity2(v1.second.get("compartment2.zeppelin.d2")); zeppelinModel->SetDiffusivity3(v1.second.get("compartment2.zeppelin.d2")); zeppelinModel->SetT2(v1.second.get("compartment2.zeppelin.t2")); m_FiberModelList.push_back(zeppelinModel); break; case 2: mitk::TensorModel* tensorModel = new mitk::TensorModel(); tensorModel->SetGradientList(m_GradientDirections); tensorModel->SetBvalue(m_Bvalue); tensorModel->SetDiffusivity1(v1.second.get("compartment2.tensor.d1")); tensorModel->SetDiffusivity2(v1.second.get("compartment2.tensor.d2")); tensorModel->SetDiffusivity3(v1.second.get("compartment2.tensor.d3")); tensorModel->SetT2(v1.second.get("compartment2.tensor.t2")); m_FiberModelList.push_back(tensorModel); break; } // compartment 3 switch (v1.second.get("compartment3.index")) { case 0: mitk::BallModel* ballModel = new mitk::BallModel(); ballModel->SetGradientList(m_GradientDirections); ballModel->SetBvalue(m_Bvalue); ballModel->SetDiffusivity(v1.second.get("compartment3.ball.d")); ballModel->SetT2(v1.second.get("compartment3.ball.t2")); ballModel->SetWeight(v1.second.get("compartment3.weight")); m_NonFiberModelList.push_back(ballModel); break; case 1: mitk::AstroStickModel* astrosticksModel = new mitk::AstroStickModel(); astrosticksModel->SetGradientList(m_GradientDirections); astrosticksModel->SetBvalue(m_Bvalue); astrosticksModel->SetDiffusivity(v1.second.get("compartment3.astrosticks.d")); astrosticksModel->SetT2(v1.second.get("compartment3.astrosticks.t2")); astrosticksModel->SetRandomizeSticks(v1.second.get("compartment3.astrosticks.randomize")); astrosticksModel->SetWeight(v1.second.get("compartment3.weight")); m_NonFiberModelList.push_back(astrosticksModel); break; case 2: mitk::DotModel* dotModel = new mitk::DotModel(); dotModel->SetGradientList(m_GradientDirections); dotModel->SetT2(v1.second.get("compartment3.dot.t2")); dotModel->SetWeight(v1.second.get("compartment3.weight")); m_NonFiberModelList.push_back(dotModel); break; } // compartment 4 switch (v1.second.get("compartment4.index")) { case 0: mitk::BallModel* ballModel = new mitk::BallModel(); ballModel->SetGradientList(m_GradientDirections); ballModel->SetBvalue(m_Bvalue); ballModel->SetDiffusivity(v1.second.get("compartment4.ball.d")); ballModel->SetT2(v1.second.get("compartment4.ball.t2")); ballModel->SetWeight(v1.second.get("compartment4.weight")); m_NonFiberModelList.push_back(ballModel); break; case 1: mitk::AstroStickModel* astrosticksModel = new mitk::AstroStickModel(); astrosticksModel->SetGradientList(m_GradientDirections); astrosticksModel->SetBvalue(m_Bvalue); astrosticksModel->SetDiffusivity(v1.second.get("compartment4.astrosticks.d")); astrosticksModel->SetT2(v1.second.get("compartment4.astrosticks.t2")); astrosticksModel->SetRandomizeSticks(v1.second.get("compartment4.astrosticks.randomize")); astrosticksModel->SetWeight(v1.second.get("compartment4.weight")); m_NonFiberModelList.push_back(astrosticksModel); break; case 2: mitk::DotModel* dotModel = new mitk::DotModel(); dotModel->SetGradientList(m_GradientDirections); dotModel->SetT2(v1.second.get("compartment4.dot.t2")); dotModel->SetWeight(v1.second.get("compartment4.weight")); m_NonFiberModelList.push_back(dotModel); break; } } } } template< class ScalarType > void mitk::FiberfoxParameters< ScalarType >::PrintSelf() { MITK_INFO << "m_ImageRegion: " << m_ImageRegion; MITK_INFO << "m_ImageSpacing: " << m_ImageSpacing; MITK_INFO << "m_ImageOrigin: " << m_ImageOrigin; MITK_INFO << "m_ImageDirection: " << m_ImageDirection; MITK_INFO << "m_NumGradients: " << m_NumGradients; MITK_INFO << "m_Bvalue: " << m_Bvalue; MITK_INFO << "m_Repetitions: " << m_Repetitions; MITK_INFO << "m_SignalScale: " << m_SignalScale; MITK_INFO << "m_tEcho: " << m_tEcho; MITK_INFO << "m_tLine: " << m_tLine; MITK_INFO << "m_tInhom: " << m_tInhom; MITK_INFO << "m_AxonRadius: " << m_AxonRadius; MITK_INFO << "m_KspaceLineOffset: " << m_KspaceLineOffset; MITK_INFO << "m_AddGibbsRinging: " << m_DoAddGibbsRinging; MITK_INFO << "m_EddyStrength: " << m_EddyStrength; MITK_INFO << "m_Spikes: " << m_Spikes; MITK_INFO << "m_SpikeAmplitude: " << m_SpikeAmplitude; MITK_INFO << "m_Wrap: " << m_Wrap; MITK_INFO << "m_DoSimulateRelaxation: " << m_DoSimulateRelaxation; MITK_INFO << "m_DoDisablePartialVolume: " << m_DoDisablePartialVolume; MITK_INFO << "m_DoAddMotion: " << m_DoAddMotion; MITK_INFO << "m_RandomMotion: " << m_DoRandomizeMotion; MITK_INFO << "m_Translation: " << m_Translation; MITK_INFO << "m_Rotation: " << m_Rotation; MITK_INFO << "m_SignalModelString: " << m_SignalModelString; MITK_INFO << "m_ArtifactModelString: " << m_ArtifactModelString; MITK_INFO << "m_OutputPath: " << m_OutputPath; } diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.h b/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.h index e3f05ce6d4..4fd5029bbb 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.h +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.h @@ -1,174 +1,175 @@ /*=================================================================== 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 using namespace std; namespace mitk { /** - * \brief Datastructure to manage the Fiberfox signal generation parameters + * \brief Datastructure to manage the Fiberfox signal generation parameters. * */ template< class ScalarType > class FiberfoxParameters { public: - typedef itk::Image ItkDoubleImgType; - typedef itk::Image ItkUcharImgType; - typedef std::vector< DiffusionSignalModel* > DiffusionModelListType; - typedef DiffusionSignalModel::GradientListType GradientListType; - typedef DiffusionSignalModel::GradientType GradientType; - typedef DiffusionNoiseModel NoiseModelType; - typedef DiffusionSignalModel* DiffusionModelType; + typedef itk::Image ItkDoubleImgType; + typedef itk::Image ItkUcharImgType; + typedef std::vector< DiffusionSignalModel* > DiffusionModelListType; + typedef DiffusionSignalModel::GradientListType GradientListType; + typedef DiffusionSignalModel::GradientType GradientType; + typedef DiffusionNoiseModel NoiseModelType; + typedef DiffusionSignalModel* DiffusionModelType; FiberfoxParameters(); ~FiberfoxParameters(); + /** Get same parameter object with different template parameter */ template< class OutType > FiberfoxParameters< OutType > CopyParameters() { FiberfoxParameters< OutType > out; out.m_ImageRegion = m_ImageRegion; out.m_ImageSpacing = m_ImageSpacing; out.m_ImageOrigin = m_ImageOrigin; out.m_ImageDirection = m_ImageDirection; out.SetNumWeightedGradients(m_NumGradients); out.m_Bvalue = m_Bvalue; out.m_Repetitions = m_Repetitions; out.m_SignalScale = m_SignalScale; out.m_tEcho = m_tEcho; out.m_tLine = m_tLine; out.m_tInhom = m_tInhom; out.m_AxonRadius = m_AxonRadius; out.m_KspaceLineOffset = m_KspaceLineOffset; out.m_DoAddGibbsRinging = m_DoAddGibbsRinging; out.m_EddyStrength = m_EddyStrength; out.m_Spikes = m_Spikes; out.m_SpikeAmplitude = m_SpikeAmplitude; out.m_Wrap = m_Wrap; out.m_DoSimulateRelaxation = m_DoSimulateRelaxation; out.m_DoDisablePartialVolume = m_DoDisablePartialVolume; out.m_DoAddMotion = m_DoAddMotion; out.m_DoRandomizeMotion = m_DoRandomizeMotion; out.m_Translation = m_Translation; out.m_Rotation = m_Rotation; 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()); } out.m_FrequencyMap = m_FrequencyMap; out.m_MaskImage = m_MaskImage; out.m_ResultNode = m_ResultNode; out.m_ParentNode = m_ParentNode; out.m_SignalModelString = m_SignalModelString; out.m_ArtifactModelString = m_ArtifactModelString; out.m_OutputPath = m_OutputPath; return out; } /** Output image specifications */ - itk::ImageRegion<3> m_ImageRegion; - itk::Vector m_ImageSpacing; - itk::Point m_ImageOrigin; - itk::Matrix m_ImageDirection; + 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 */ - unsigned int m_Repetitions; - double m_SignalScale; - double m_tEcho; - double m_tLine; - double m_tInhom; + unsigned int m_Repetitions; ///< Noise will be summed N times and afterwards averaged. + double m_SignalScale; ///< Scaling factor for output signal (before noise is added). + double m_tEcho; ///< Echo time TE. + double m_tLine; ///< k-space line readout time. + double m_tInhom; ///< T2' double m_Bvalue; /** Signal generation */ - DiffusionModelListType m_FiberModelList; ///< Intra- and inter-axonal compartments - DiffusionModelListType m_NonFiberModelList; ///< Extra-axonal compartments - double m_AxonRadius; ///< Determines compartment volume fractions (0 == automatic axon radius estimation) + DiffusionModelListType m_FiberModelList; ///< Intra- and inter-axonal compartments. + DiffusionModelListType m_NonFiberModelList; ///< Extra-axonal compartments. + double m_AxonRadius; ///< Determines compartment volume fractions (0 == automatic axon radius estimation) /** Artifacts */ - int m_Spikes; - double m_SpikeAmplitude; - double m_KspaceLineOffset; - double m_EddyStrength; - double m_Wrap; - bool m_DoAddGibbsRinging; - bool m_DoSimulateRelaxation; - bool m_DoDisablePartialVolume; - bool m_DoAddMotion; - bool m_DoRandomizeMotion; - itk::Vector m_Translation; - itk::Vector m_Rotation; - NoiseModelType* m_NoiseModel; - ItkDoubleImgType::Pointer m_FrequencyMap; - ItkUcharImgType::Pointer m_MaskImage; - - /** Output parameters */ - mitk::DataNode::Pointer m_ResultNode; - mitk::DataNode::Pointer m_ParentNode; - string m_SignalModelString; - string m_ArtifactModelString; - string m_OutputPath; - - void PrintSelf(); - void LoadParameters(string filename); - void GenerateHalfShell(); + 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 T/m. + double m_Wrap; ///< 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_DoDisablePartialVolume; ///< Disable partial volume effects. Each voxel is either all fiber or all non-fiber. + 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. + NoiseModelType* m_NoiseModel; ///< If != NULL, noise is added to the image. + 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. + + /** Output parameters (only relevant in GUI application) */ + mitk::DataNode::Pointer m_ResultNode; ///< Stores resulting image. + mitk::DataNode::Pointer m_ParentNode; ///< Parent node or 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. + + void PrintSelf(); ///< Print parameters to stdout. + void LoadParameters(string filename); ///< Load image generation parameters from .ffp file. + void GenerateGradientHalfShell(); ///< Generates half shell of gradient directions (with m_NumGradients non-zero directions) std::vector< int > GetBaselineIndices(); unsigned int GetFirstBaselineIndex(); bool IsBaselineIndex(unsigned int idx); unsigned int GetNumWeightedVolumes(); unsigned int GetNumBaselineVolumes(); unsigned int GetNumVolumes(); GradientListType GetGradientDirections(); GradientType GetGradientDirection(unsigned int i); - void SetNumWeightedGradients(int numGradients); + void SetNumWeightedGradients(int numGradients); ///< Automaticall calls GenerateGradientHalfShell() afterwards. void SetGradienDirections(GradientListType gradientList); void SetGradienDirections(mitk::DiffusionImage::GradientDirectionContainerType::Pointer gradientList); protected: - unsigned int m_NumBaseline; - unsigned int m_NumGradients; - GradientListType m_GradientDirections; + unsigned int m_NumBaseline; ///< Number of non-diffusion-weighted image volumes. + unsigned int m_NumGradients; ///< Number of diffusion-weighted image volumes. + GradientListType m_GradientDirections; ///< Total number of image volumes. }; } #include "mitkFiberfoxParameters.cpp" #endif diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberfoxViewUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberfoxViewUserManual.dox index 631610fb52..cb0d30503e 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberfoxViewUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberfoxViewUserManual.dox @@ -1,115 +1,115 @@ /** \page org_mitk_views_fiberfoxview Fiberfox This view provides the user interface for Fiberfox [1,2,3], an interactive simulation tool for defining artificial white matter fibers and generating corresponding diffusion weighted images. Arbitrary fiber configurations like bent, crossing, kissing, twisting, and fanning bundles can be intuitively defined by positioning only a few 3D waypoints to trigger the automated generation of synthetic fibers. From these fibers a diffusion weighted signal is simulated using a flexible combination of various diffusion models. It can be modified using specified acquisition settings such as gradient direction, b-value, signal-to-noise ratio, image size, and resolution. Additionally it enables the simulation of magnetic resonance artifacts including thermal noise, Gibbs ringing, N/2 ghosting, susceptibility distortions and motion artifacts. The employed parameters can be saved and loaded as xml file with the ending ".ffp" (Fiberfox parameters). Available sections: - \ref QmitkFiberfoxViewUserManualFiberDefinition - \ref QmitkFiberfoxViewUserManualSignalGeneration - \ref QmitkFiberfoxViewUserManualKnownIssues - \ref QmitkFiberfoxViewUserManualReferences \image html Fiberfox.png Fig. 1: Screenshot of the Fiberfox framework. The four render windows display an axial (top left), sagittal (top right) and coronal (bottom left) 2D cut as well as a 3D view of a synthetic fiber helix and the fiducials used to define its shape. In the 2D views the helix is superimposing the baseline volume of the corresponding diffusion weighted image. The sagittal render window shows a close-up view on one of the circular fiducials. \section QmitkFiberfoxViewUserManualFiberDefinition Fiber Definition Fiber strands are defined simply by placing markers in a 3D image volume. The fibers are then interpolated between these fiducials. Example: \li Chose an image volume to place the markers used to define the fiber pathway. If you don't have such an image available switch to the "Signal Generation" tab, define the size and spacing of the desired image and click "Generate Image". If no fiber bundle is selected, this will generate a dummy image that can be used to place the fiducials. \li Start placing fiducials at the desired positions to define the fiber pathway. To do that, click on the button with the circle pictogram, then click at the desired position and plane in the image volume and drag your mouse while keeping the button pressed to generate a circular shape. Adjust the shape using the control points (Fig. 2). The position of control point D introduces a twist of the fibers between two successive fiducials. The actual fiber generation is triggered automatically as soon as you place the second control point. \li In some cases the fibers are entangled in a way that can't be resolved by introducing an additional fiber twist. Fiberfox tries to avoid these situations, which arise from different normal orientations of succeeding fiducials, automatically. In rare cases this is not successful. Use the double-arrow button to flip the fiber positions of the selected fiducial in one dimension. Either the problem is resolved now or you can resolve it manually by adjusting the twist-control point. \li To create non elliptical fiber profile shapes switch to the Fiber Extraction View. This view provides tools to extract subesets of fibers from fiber bundles and enables to cut out arbitrary polygonal fiber shapes from existing bundles. \image html Fiberfox-Fiducial.png Fig. 2: Control points defining the actual shape of the fiducial. A specifies the fiducials position in space, B and C the two ellipse radii and D the twisting angle between two successive fiducials. Fiber Options: \li Real Time Fibers: If checked, each parameter adjustment (fiducial position, number of fibers, ...) will be directly applied to the selected fiber bundle. If unchecked, the fibers will only be generated if the corresponding button "Generate Fibers" is clicked. \li Advanced Options: Show/hide advanced options \li #Fibers: Specifies the number of fibers that will be generated for the selected bundle. \li Fiber Sampling: Adjusts the distenace of the fiber sampling points (in mm). A higher sampling rate is needed if high curvatures are modeled. \li Tension, Continuity, Bias: Parameters controlling the shape of the splines interpolation the fiducials. See Wikipedia for details. Fiducial Options: \li Use Constant Fiducial Radius: If checked, all fiducials are treated as circles with the same radius. The first fiducial of the bundle defines the radius of all other fiducials. \li Align with grid: Click to shift all fiducial center points to the next voxel center. Operations: \li Rotation: Define the rotation of the selected fiber bundle around each axis (in degree). \li Translation: Define the translation of the selected fiber bundle along each axis (in mm). \li Scaling: Define a scaling factor for the selected fiber bundle in each dimension. \li Transform Selection: Apply specified rotation, translation and scaling to the selected Bundle/Fiducial \li Copy Bundles: Add copies of the selected fiber bundles to the datamanager. \li Join Bundles: Add new bundle to the datamanager that contains all fibers from the selected bundles. \li Include Fiducials: If checked, the specified transformation is also applied to the fiducials belonging to the selected fiber bundle and the fiducials are also copied. \image html FiberfoxExamples.png Fig. 3: Examples of artificial crossing (a,b), fanning (c,d), highly curved (e,f), kissing (g,h) and twisting (i,j) fibers as well as of the corresponding tensor images generated with Fiberfox. \section QmitkFiberfoxViewUserManualSignalGeneration Signal Generation To generate an artificial signal from the input fibers we follow the concepts recently presented by Panagiotaki et al. in a review and taxonomy of different compartment models: a flexible model combining multiple compartments is used to simulate the anisotropic diffusion inside (intra-axonal compartment) and between axons (inter-axonal compartment), isotropic diffusion outside of the axons (extra-axonal compartment 1) and the restricted diffusion in other cell types (extra-axonal compartment 2) weighted according to their respective volume fraction. A diffusion weighted image is generated from the fibers by selecting the according fiber bundle in the datamanager and clicking "Generate Image". If some other diffusion weighted image is selected together with the fiber bundle, Fiberfox directly uses the parameters of the selected image (size, spacing, gradient directions, b-values) for the signal generation process. Additionally a binary image can be selected that defines the tissue area. Voxels outside of this mask will contain no signal, only noise. Basic Image Settings: \li Image Dimensions: Specifies actual image size (number of voxels in each dimension). \li Image Spacing: Specifies voxel size in mm. Beware that changing the voxel size also changes the signal strength, e.g. increasing the resolution from 2x2x2 mm to 1x1x1 mm decreases the signal obtained for each voxel by a factor 8. \li Gradient Directions: Number of gradients directions distributed equally over the half sphere. 10% baseline images are automatically added. \li b-Value: Diffusion weighting in s/mm². If an existing diffusion weighted image is used to set the basic parameters, the b-value is defined by the gradient direction magnitudes of this image, which also enables the use of multiple b-values. Advanced Image Settings (activate checkbox "Advanced Options"): \li Repetitions: Specifies the number of averages used for the acquisition to reduce noise. \li Signal Scale: Additional scaling factor for the signal in each voxel. The default value of 125 results in a maximum signal amplitude of 1000 for 2x2x2 mm voxels. Beware that changing this value without changing the noise variance results in a changed SNR. Adjustment of this value might be needed if the overall signal values are much too high or much too low (depends on a variety of factors like voxel size and relaxation times). \li Echo Time TE: Time between the 90° excitation pulse and the first spin echo. Increasing this time results in a stronger T2-relaxation effect (Wikipedia). \li Line Readout Time: Time to read one line in k-space. Increasing this time results in a stronger T2* effect which causes an attenuation of the higher frequencies in phase direction (here along y-axis) which again results in a blurring effect of sharp edges perpendicular to the phase direction. \li Tinhom Relaxation: Time constant specifying the signal decay due to magnetic field inhomogeneities (also called T2'). Together with the tissue specific relaxation time constant T2 this defines the T2* decay constant: T2*=(T2 T2')/(T2+T2') \li Fiber Radius (in µm): Used to calculate the volume fractions of the used compartments (fiber, water, etc.). If set to 0 (default) the fiber radius is set automatically so that the voxel containing the most fibers is filled completely. A realistic axon radius ranges from about 5 to 20 microns. Using the automatic estimation the resulting value might very well be much larger or smaller than this range. \li Simulate Signal Relaxation: If checked, the relaxation induced signal decay is simulated, other wise the parameters TE, Line Readout Time, Tinhom, and T2 are ignored. \li Disable Partial Volume Effects: If checked, the actual volume fractions of the single compartments are ignored. A voxel will either be filled by the intra axonal compartment completely or will contain no fiber at all. \li Output Volume Fractions: Output a double image for each compartment. The voxel values correspond to the volume fraction of the respective compartment. Compartment Settings: The group-boxes "Intra-axonal Compartment", "Inter-axonal Compartment" and "Extra-axonal Compartments" allow the specification which model to use and the corresponding model parameters. Currently the following models are implemented: \li Stick: The “stick” model describes diffusion in an idealized cylinder with zero radius. Parameter: Diffusivity d \li Zeppelin: Cylindrically symmetric diffusion tensor. Parameters: Parallel diffusivity d|| and perpendicular diffusivity d \li Tensor: Full diffusion tensor. Parameters: Parallel diffusivity d|| and perpendicular diffusivity constants d⊥1 and d⊥2 \li Ball: Isotropic compartment. Parameter: Diffusivity d \li Astrosticks: Consists of multiple stick models pointing in different directions. The single stick orientations can either be distributed equally over the sphere or are sampled randomly. The model represents signal coming from a type of glial cell called astrocytes, or populations of axons with arbitrary orientation. Parameters: randomization of the stick orientations and diffusivity of the sticks d. \li Dot: Isotropically restricted compartment. No parameter. For a detailed description of the single models, please refer to Panagiotaki et al. "Compartment models of the diffusion MR signal in brain white matter: A taxonomy and comparison". Additionally to the model parameters, each compartment has its own T2 signal relaxation constant (in ms). Noise and Artifacts: -\li Rician Noise: Add Rician noise with the specified variance to the signal. +\li Noise: Add Rician or Chi-Square distributed noise with the specified variance to the signal. \li Spikes: Add signal spikes to the k-space signal resulting in stripe artifacts across the corresponding image slice. \li Aliasing: Aliasing artifacts occur if the FOV in phase direction is smaller than the imaged object. The parameter defines the percentage by which the FOV is shrunk. \li N/2 Ghosts: Specify the offset between successive lines in k-space. This offset causes ghost images in distance N/2 in phase direction due to the alternating EPI readout directions. \li Distortions: Simulate distortions due to magnetic field inhomogeneities. This is achieved by adding an additional phase during the readout process. The input is a frequency map specifying the inhomogeneities. The "Fieldmap Generator" view provides an interface to generate simple artificial frequency maps. \li Motion Artifacts: To simulate motion artifacts, the fiber configuration is moved between the signal simulation of the individual gradient volumes. The motion can be performed randomly, where the parameters are used to define the +/- maximum of the corresponding motion, or linearly, where the parameters define the maximum rotation/translation around/along the corresponding axis at the and of the simulated acquisition. \li Eddy Currents: EXPERIMENTAL! This feature is currently being tested and might not yet behave as expected! \li Gibbs Ringing: Ringing artifacts occurring on edges in the image due to the frequency low-pass filtering caused by the limited size of the k-space. \section QmitkFiberfoxViewUserManualKnownIssues Known Issues \li If fiducials are created in one of the marginal slices of the underlying image, a position change of the fiducial can be observed upon selection/deselection. If the fiducial is created in any other slice this bug does not occur. \li If a scaling factor is applied to the selcted fiber bundle, the corresponding fiducials are not scaled accordingly. \li In some cases the automatic update of the selected fiber bundle is not triggered even if "Real Time Fibers" is checked, e.g. if a fiducial is deleted. If this happens on can always force an update by pressing the "Generate Fibers" button. If any other issues or feature requests arises during the use of Fiberfox, please don't hesitate to send us an e-mail or directly report the issue in our bugtracker: http://bugs.mitk.org/ \section QmitkFiberfoxViewUserManualReferences References -[1] Peter F. Neher, Frederik B. Laun, Bram Stieltjes, and Klaus H. Fritzsche: Fiberfox: Facilitating the creation of realistic white matter software phantoms, Magn Reson Med, Accepted for publication. +[1] Peter F. Neher, Frederik B. Laun, Bram Stieltjes, and Klaus H. Fritzsche: Fiberfox: Facilitating the creation of realistic white matter software phantoms, Magn Reson Med, DOI: 10.1002/mrm.25045. [2] Peter F. Neher, Frederik B. Laun, Bram Stieltjes, and Klaus H. Fritzsche: Fiberfox: An extensible system for generating realistic white matter software phantoms, MICCAI CDMRI Workshop, Nagoya; 09/2013 [3] Peter F. Neher, Bram Stieltjes, Frederik B. Laun, Hans-Peter Meinzer, and Klaus H. Fritzsche: Fiberfox: Fiberfox: A novel tool to generate software phantoms of complex fiber geometries, ISMRM, Salt Lake City; 04/2013 */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberExtractionView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberExtractionView.h index b0544e16f6..76c0ad0c49 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberExtractionView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberExtractionView.h @@ -1,175 +1,175 @@ /*=================================================================== 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 QmitkFiberExtractionView_h #define QmitkFiberExtractionView_h #include #include "ui_QmitkFiberExtractionViewControls.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*! -\brief View to process fiber bundles. Supplies methods to extract fibers from the bundle, join and subtract bundles, generate images from the selected bundle and much more. +\brief View to process fiber bundles. Supplies methods to extract fibers from the bundle, join and subtract bundles and much more. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkFiberExtractionView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: typedef itk::Image< unsigned char, 3 > itkUCharImageType; static const std::string VIEW_ID; QmitkFiberExtractionView(); virtual ~QmitkFiberExtractionView(); virtual void CreateQtPartControl(QWidget *parent); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); virtual void Activated(); protected slots: void OnDrawCircle(); ///< add circle interactors etc. void OnDrawPolygon(); ///< add circle interactors etc. void DoFiberExtraction(); ///< Extract fibers from selected bundle void GenerateAndComposite(); void GenerateOrComposite(); void GenerateNotComposite(); void DoRemoveOutsideMask(); void DoRemoveInsideMask(); void JoinBundles(); ///< merge selected fiber bundles void SubstractBundles(); ///< subtract bundle A from bundle B. Not commutative! Defined by order of selection. void GenerateRoiImage(); ///< generate binary image of selected planar figures. void ExtractPassingMask(); ///< extract all fibers passing the selected surface mesh void ExtractEndingInMask(); ///< extract all fibers passing the selected surface mesh virtual void AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name, const char *propertyKey = NULL, mitk::BaseProperty *property = NULL ); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ); Ui::QmitkFiberExtractionViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; /** Connection from VTK to ITK */ template void ConnectPipelines(VTK_Exporter* exporter, ITK_Importer importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template < typename TPixel, unsigned int VImageDimension > void InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ); template < typename TPixel, unsigned int VImageDimension > void InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* planegeo3D, int additionalIndex ); void GenerateStats(); ///< generate statistics of selected fiber bundles void UpdateGui(); ///< update button activity etc. dpending on current datamanager selection int m_CircleCounter; ///< used for data node naming int m_PolygonCounter; ///< used for data node naming std::vector m_SelectedFB; ///< selected fiber bundle nodes std::vector m_SelectedPF; ///< selected planar figure nodes std::vector m_SelectedSurfaces; mitk::Image::Pointer m_SelectedImage; mitk::Image::Pointer m_InternalImage; mitk::PlanarFigure::Pointer m_PlanarFigure; itkUCharImageType::Pointer m_InternalImageMask3D; itkUCharImageType::Pointer m_PlanarFigureImage; float m_UpsamplingFactor; ///< upsampling factor for all image generations mitk::DataNode::Pointer m_MaskImageNode; mitk::DataNode::Pointer m_LastAddedPf; void AddCompositeToDatastorage(mitk::PlanarFigureComposite::Pointer, mitk::DataNode::Pointer); void debugPFComposition(mitk::PlanarFigureComposite::Pointer , int ); void CompositeExtraction(mitk::DataNode::Pointer node, mitk::Image* image); mitk::DataNode::Pointer GenerateTractDensityImage(mitk::FiberBundleX::Pointer fib, bool binary, bool absolute); mitk::DataNode::Pointer GenerateColorHeatmap(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsImage(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsPointSet(mitk::FiberBundleX::Pointer fib); }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h index b9a9aa22dd..cccc42e14a 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberProcessingView.h @@ -1,154 +1,154 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkFiberProcessingView_h #define QmitkFiberProcessingView_h #include #include "ui_QmitkFiberProcessingViewControls.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*! -\brief View to process fiber bundles. Supplies methods to extract fibers from the bundle, join and subtract bundles, generate images from the selected bundle and much more. +\brief View to process fiber bundles. Supplies methods to generate images from the selected bundle and much more. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkFiberProcessingView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: typedef itk::Image< unsigned char, 3 > itkUCharImageType; static const std::string VIEW_ID; QmitkFiberProcessingView(); virtual ~QmitkFiberProcessingView(); virtual void CreateQtPartControl(QWidget *parent); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); virtual void Activated(); protected slots: void PruneBundle(); ///< remove too short/too long fibers void MirrorFibers(); ///< mirror bundle on the specified plane void ProcessSelectedBundles(); ///< start selected operation on fiber bundle (e.g. tract density image generation) void ResampleSelectedBundles(); ///< smooth fiber bundle using the specified number of sampling points per cm. void DoImageColorCoding(); ///< color fibers by selected scalar image void ApplyCurvatureThreshold(); ///< remove/split fibers with a too high curvature threshold protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ); Ui::QmitkFiberProcessingViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; /** Connection from VTK to ITK */ template void ConnectPipelines(VTK_Exporter* exporter, ITK_Importer importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } template < typename TPixel, unsigned int VImageDimension > void InternalCalculateMaskFromPlanarFigure( itk::Image< TPixel, VImageDimension > *image, unsigned int axis, std::string nodeName ); template < typename TPixel, unsigned int VImageDimension > void InternalReorientImagePlane( const itk::Image< TPixel, VImageDimension > *image, mitk::Geometry3D* planegeo3D, int additionalIndex ); void GenerateStats(); ///< generate statistics of selected fiber bundles void UpdateGui(); ///< update button activity etc. dpending on current datamanager selection std::vector m_SelectedFB; ///< selected fiber bundle nodes mitk::Image::Pointer m_SelectedImage; float m_UpsamplingFactor; ///< upsampling factor for all image generations std::vector m_SelectedSurfaces; mitk::DataNode::Pointer GenerateTractDensityImage(mitk::FiberBundleX::Pointer fib, bool binary, bool absolute); mitk::DataNode::Pointer GenerateColorHeatmap(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsImage(mitk::FiberBundleX::Pointer fib); mitk::DataNode::Pointer GenerateFiberEndingsPointSet(mitk::FiberBundleX::Pointer fib); }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED 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 b21a218e1f..959f6b346f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp @@ -1,2229 +1,2229 @@ /*=================================================================== 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 #include #include #include #include "usModuleRegistry.h" #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_SelectedImage( NULL ) , m_OutputPath("") , 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; } } 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_GenerateImageButton->setVisible(true); //m_Controls->m_SimulationStatusText->setVisible(false); m_ThreadIsRunning = false; FiberfoxParameters parameters; mitk::DiffusionImage::Pointer mitkImage = mitk::DiffusionImage::New(); switch (m_Worker.m_FilterType) { case 0: { if (m_TractsToDwiFilter->GetAbortGenerateData()) { MITK_INFO << "Simulation aborted."; return; } parameters = m_TractsToDwiFilter->GetParameters(); mitkImage->SetVectorImage( m_TractsToDwiFilter->GetOutput() ); mitkImage->SetB_Value(parameters.m_Bvalue); mitkImage->SetDirections(parameters.GetGradientDirections()); mitkImage->InitializeFromVectorImage(); parameters.m_ResultNode->SetData( mitkImage ); parameters.m_ResultNode->SetName(parameters.m_ParentNode->GetName() +"_D"+QString::number(parameters.m_ImageRegion.GetSize(0)).toStdString() +"-"+QString::number(parameters.m_ImageRegion.GetSize(1)).toStdString() +"-"+QString::number(parameters.m_ImageRegion.GetSize(2)).toStdString() +"_S"+QString::number(parameters.m_ImageSpacing[0]).toStdString() +"-"+QString::number(parameters.m_ImageSpacing[1]).toStdString() +"-"+QString::number(parameters.m_ImageSpacing[2]).toStdString() +"_b"+QString::number(parameters.m_Bvalue).toStdString() +"_"+parameters.m_SignalModelString +parameters.m_ArtifactModelString); GetDataStorage()->Add(parameters.m_ResultNode, parameters.m_ParentNode); parameters.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 (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_ParentNode->GetName()+"_CompartmentVolume-"+QString::number(k).toStdString()); GetDataStorage()->Add(node, parameters.m_ParentNode); } } m_TractsToDwiFilter = NULL; break; } case 1: { if (m_ArtifactsToDwiFilter->GetAbortGenerateData()) { MITK_INFO << "Simulation aborted."; return; } parameters = m_ArtifactsToDwiFilter->GetParameters().CopyParameters(); mitk::DiffusionImage::Pointer diffImg = dynamic_cast*>(parameters.m_ParentNode->GetData()); mitkImage = mitk::DiffusionImage::New(); mitkImage->SetVectorImage( m_ArtifactsToDwiFilter->GetOutput() ); mitkImage->SetB_Value(diffImg->GetB_Value()); mitkImage->SetDirections(diffImg->GetDirections()); mitkImage->InitializeFromVectorImage(); parameters.m_ResultNode->SetData( mitkImage ); parameters.m_ResultNode->SetName(parameters.m_ParentNode->GetName()+parameters.m_ArtifactModelString); GetDataStorage()->Add(parameters.m_ResultNode, parameters.m_ParentNode); m_ArtifactsToDwiFilter = NULL; break; } } mitk::BaseData::Pointer basedata = parameters.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_OutputPath.empty()) { try{ QString status("Saving output image to "); status += QString(parameters.m_OutputPath.c_str()); status += parameters.m_ResultNode->GetName().c_str(); status += ".dwi"; m_Controls->m_SimulationStatusText->append(status); mitk::NrrdDiffusionImageWriter::Pointer writer = NrrdDiffusionImageWriter::New(); writer->SetFileName(parameters.m_OutputPath+parameters.m_ResultNode->GetName()+".dwi"); writer->SetInput(mitkImage); writer->Update(); 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_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); } } // 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 ); 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_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()); mitk::TNodePredicateDataType::Pointer isMitkImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer 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 finalPredicate = mitk::NodePredicateAnd::New(isMitkImage, noDiffusionImage); m_Controls->m_FrequencyMapBox->SetPredicate(finalPredicate); 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())); } } template< class ScalarType > FiberfoxParameters< ScalarType > QmitkFiberfoxView::UpdateImageParameters() { FiberfoxParameters< ScalarType > parameters; parameters.m_OutputPath = m_OutputPath; parameters.m_MaskImage = m_ItkMaskImage; if (m_SelectedDWI.IsNotNull()) // use parameters of selected DWI { mitk::DiffusionImage::Pointer dwi = dynamic_cast*>(m_SelectedDWI->GetData()); parameters.m_ImageRegion = dwi->GetVectorImage()->GetLargestPossibleRegion(); parameters.m_ImageSpacing = dwi->GetVectorImage()->GetSpacing(); parameters.m_ImageOrigin = dwi->GetVectorImage()->GetOrigin(); parameters.m_ImageDirection = dwi->GetVectorImage()->GetDirection(); parameters.m_Bvalue = dwi->GetB_Value(); parameters.SetGradienDirections(dwi->GetDirections()); } else if (m_SelectedImage.IsNotNull()) // use geometry of selected image { mitk::Image::Pointer img = dynamic_cast(m_SelectedImage->GetData()); itk::Image< float, 3 >::Pointer itkImg = itk::Image< float, 3 >::New(); CastToItkImage< itk::Image< float, 3 > >(img, itkImg); parameters.m_ImageRegion = itkImg->GetLargestPossibleRegion(); parameters.m_ImageSpacing = itkImg->GetSpacing(); parameters.m_ImageOrigin = itkImg->GetOrigin(); parameters.m_ImageDirection = itkImg->GetDirection(); parameters.SetNumWeightedGradients(m_Controls->m_NumGradientsBox->value()); parameters.m_Bvalue = m_Controls->m_BvalueBox->value(); } else // use GUI parameters { parameters.m_ImageRegion.SetSize(0, m_Controls->m_SizeX->value()); parameters.m_ImageRegion.SetSize(1, m_Controls->m_SizeY->value()); parameters.m_ImageRegion.SetSize(2, m_Controls->m_SizeZ->value()); parameters.m_ImageSpacing[0] = m_Controls->m_SpacingX->value(); parameters.m_ImageSpacing[1] = m_Controls->m_SpacingY->value(); parameters.m_ImageSpacing[2] = m_Controls->m_SpacingZ->value(); parameters.m_ImageOrigin[0] = parameters.m_ImageSpacing[0]/2; parameters.m_ImageOrigin[1] = parameters.m_ImageSpacing[1]/2; parameters.m_ImageOrigin[2] = parameters.m_ImageSpacing[2]/2; parameters.m_ImageDirection.SetIdentity(); parameters.SetNumWeightedGradients(m_Controls->m_NumGradientsBox->value()); parameters.m_Bvalue = m_Controls->m_BvalueBox->value(); - parameters.GenerateHalfShell(); + parameters.GenerateGradientHalfShell(); } // signal relaxation parameters.m_DoSimulateRelaxation = m_Controls->m_RelaxationBox->isChecked(); if (parameters.m_DoSimulateRelaxation && m_SelectedBundles.size()>0 ) parameters.m_ArtifactModelString += "_RELAX"; // N/2 ghosts if (m_Controls->m_AddGhosts->isChecked()) { parameters.m_ArtifactModelString += "_GHOST"; parameters.m_KspaceLineOffset = m_Controls->m_kOffsetBox->value(); parameters.m_ResultNode->AddProperty("Fiberfox.Ghost", DoubleProperty::New(parameters.m_KspaceLineOffset)); } else parameters.m_KspaceLineOffset = 0; // Aliasing if (m_Controls->m_AddAliasing->isChecked()) { parameters.m_ArtifactModelString += "_ALIASING"; parameters.m_Wrap = (100-m_Controls->m_WrapBox->value())/100; parameters.m_ResultNode->AddProperty("Fiberfox.Aliasing", DoubleProperty::New(m_Controls->m_WrapBox->value())); } // Motion parameters.m_DoAddMotion = m_Controls->m_AddMotion->isChecked(); parameters.m_DoRandomizeMotion = m_Controls->m_RandomMotion->isChecked(); parameters.m_Translation[0] = m_Controls->m_MaxTranslationBoxX->value(); parameters.m_Translation[1] = m_Controls->m_MaxTranslationBoxY->value(); parameters.m_Translation[2] = m_Controls->m_MaxTranslationBoxZ->value(); parameters.m_Rotation[0] = m_Controls->m_MaxRotationBoxX->value(); parameters.m_Rotation[1] = m_Controls->m_MaxRotationBoxY->value(); parameters.m_Rotation[2] = m_Controls->m_MaxRotationBoxZ->value(); if ( m_Controls->m_AddMotion->isChecked() && m_SelectedBundles.size()>0 ) { parameters.m_ArtifactModelString += "_MOTION"; parameters.m_ResultNode->AddProperty("Fiberfox.Motion.Random", BoolProperty::New(parameters.m_DoRandomizeMotion)); parameters.m_ResultNode->AddProperty("Fiberfox.Motion.Translation-x", DoubleProperty::New(parameters.m_Translation[0])); parameters.m_ResultNode->AddProperty("Fiberfox.Motion.Translation-y", DoubleProperty::New(parameters.m_Translation[1])); parameters.m_ResultNode->AddProperty("Fiberfox.Motion.Translation-z", DoubleProperty::New(parameters.m_Translation[2])); parameters.m_ResultNode->AddProperty("Fiberfox.Motion.Rotation-x", DoubleProperty::New(parameters.m_Rotation[0])); parameters.m_ResultNode->AddProperty("Fiberfox.Motion.Rotation-y", DoubleProperty::New(parameters.m_Rotation[1])); parameters.m_ResultNode->AddProperty("Fiberfox.Motion.Rotation-z", DoubleProperty::New(parameters.m_Rotation[2])); } // other imaging parameters parameters.m_tLine = m_Controls->m_LineReadoutTimeBox->value(); parameters.m_tInhom = m_Controls->m_T2starBox->value(); parameters.m_tEcho = m_Controls->m_TEbox->value(); parameters.m_Repetitions = m_Controls->m_RepetitionsBox->value(); parameters.m_DoDisablePartialVolume = m_Controls->m_EnforcePureFiberVoxelsBox->isChecked(); parameters.m_AxonRadius = m_Controls->m_FiberRadius->value(); parameters.m_SignalScale = m_Controls->m_SignalScaleBox->value(); if (m_Controls->m_AddSpikes->isChecked()) { parameters.m_Spikes = m_Controls->m_SpikeNumBox->value(); parameters.m_SpikeAmplitude = m_Controls->m_SpikeScaleBox->value(); parameters.m_ArtifactModelString += "_SPIKES"; parameters.m_ResultNode->AddProperty("Fiberfox.Spikes.Number", IntProperty::New(parameters.m_Spikes)); parameters.m_ResultNode->AddProperty("Fiberfox.Spikes.Amplitude", DoubleProperty::New(parameters.m_SpikeAmplitude)); } // adjust echo time if needed if ( parameters.m_tEcho < parameters.m_ImageRegion.GetSize(1)*parameters.m_tLine ) { this->m_Controls->m_TEbox->setValue( parameters.m_ImageRegion.GetSize(1)*parameters.m_tLine ); parameters.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_tEcho)+" ms"); } // rician noise if (m_Controls->m_AddNoise->isChecked()) { double noiseVariance = m_Controls->m_NoiseLevel->value(); { switch (m_Controls->m_NoiseDistributionBox->currentIndex()) { case 0: { parameters.m_NoiseModel = new mitk::RicianNoiseModel(); parameters.m_ArtifactModelString += "_RICIAN-"; parameters.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Rician")); break; } case 1: { parameters.m_NoiseModel = new mitk::ChiSquareNoiseModel(); parameters.m_ArtifactModelString += "_CHISQUARED-"; parameters.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Chi-squared")); break; } default: { parameters.m_NoiseModel = new mitk::RicianNoiseModel(); parameters.m_ArtifactModelString += "_RICIAN-"; parameters.m_ResultNode->AddProperty("Fiberfox.Noise-Distribution", StringProperty::New("Rician")); } } } parameters.m_NoiseModel->SetNoiseVariance(noiseVariance); parameters.m_ArtifactModelString += QString::number(noiseVariance).toStdString(); parameters.m_ResultNode->AddProperty("Fiberfox.Noise-Variance", DoubleProperty::New(noiseVariance)); } // gibbs ringing parameters.m_DoAddGibbsRinging = m_Controls->m_AddGibbsRinging->isChecked(); if (m_Controls->m_AddGibbsRinging->isChecked()) { parameters.m_ResultNode->AddProperty("Fiberfox.Ringing", BoolProperty::New(true)); parameters.m_ArtifactModelString += "_RINGING"; } // adjusting line readout time to the adapted image size needed for the DFT int y = parameters.m_ImageRegion.GetSize(1); if ( y%2 == 1 ) y += 1; if ( y>parameters.m_ImageRegion.GetSize(1) ) parameters.m_tLine *= (double)parameters.m_ImageRegion.GetSize(1)/y; // add distortions 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 (parameters.m_ImageRegion.GetSize(0)==itkImg->GetLargestPossibleRegion().GetSize(0) && parameters.m_ImageRegion.GetSize(1)==itkImg->GetLargestPossibleRegion().GetSize(1) && parameters.m_ImageRegion.GetSize(2)==itkImg->GetLargestPossibleRegion().GetSize(2)) { parameters.m_FrequencyMap = itkImg; parameters.m_ArtifactModelString += "_DISTORTED"; parameters.m_ResultNode->AddProperty("Fiberfox.Distortions", BoolProperty::New(true)); } } parameters.m_EddyStrength = 0; if (m_Controls->m_AddEddy->isChecked()) { parameters.m_EddyStrength = m_Controls->m_EddyGradientStrength->value(); parameters.m_ArtifactModelString += "_EDDY"; parameters.m_ResultNode->AddProperty("Fiberfox.Eddy-strength", DoubleProperty::New(parameters.m_EddyStrength)); } // signal models double m_Comp3Weight = 1; double m_Comp4Weight = 0; if (m_Controls->m_Compartment4Box->currentIndex()>0) { m_Comp4Weight = m_Controls->m_Comp4FractionBox->value(); m_Comp3Weight -= m_Comp4Weight; parameters.m_ResultNode->AddProperty("Fiberfox.Compartment3.weight", DoubleProperty::New(m_Comp3Weight)); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment4.weight", DoubleProperty::New(m_Comp4Weight)); } // compartment 1 switch (m_Controls->m_Compartment1Box->currentIndex()) { case 0: m_StickModel1.SetGradientList(parameters.GetGradientDirections()); m_StickModel1.SetBvalue(parameters.m_Bvalue); m_StickModel1.SetDiffusivity(m_Controls->m_StickWidget1->GetD()); m_StickModel1.SetT2(m_Controls->m_StickWidget1->GetT2()); parameters.m_FiberModelList.push_back(&m_StickModel1); parameters.m_SignalModelString += "Stick"; parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Stick") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.D", DoubleProperty::New(m_Controls->m_StickWidget1->GetD()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(m_StickModel1.GetT2()) ); break; case 1: m_ZeppelinModel1.SetGradientList(parameters.GetGradientDirections()); m_ZeppelinModel1.SetBvalue(parameters.m_Bvalue); m_ZeppelinModel1.SetDiffusivity1(m_Controls->m_ZeppelinWidget1->GetD1()); m_ZeppelinModel1.SetDiffusivity2(m_Controls->m_ZeppelinWidget1->GetD2()); m_ZeppelinModel1.SetDiffusivity3(m_Controls->m_ZeppelinWidget1->GetD2()); m_ZeppelinModel1.SetT2(m_Controls->m_ZeppelinWidget1->GetT2()); parameters.m_FiberModelList.push_back(&m_ZeppelinModel1); parameters.m_SignalModelString += "Zeppelin"; parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Zeppelin") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.D1", DoubleProperty::New(m_Controls->m_ZeppelinWidget1->GetD1()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.D2", DoubleProperty::New(m_Controls->m_ZeppelinWidget1->GetD2()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(m_ZeppelinModel1.GetT2()) ); break; case 2: m_TensorModel1.SetGradientList(parameters.GetGradientDirections()); m_TensorModel1.SetBvalue(parameters.m_Bvalue); m_TensorModel1.SetDiffusivity1(m_Controls->m_TensorWidget1->GetD1()); m_TensorModel1.SetDiffusivity2(m_Controls->m_TensorWidget1->GetD2()); m_TensorModel1.SetDiffusivity3(m_Controls->m_TensorWidget1->GetD3()); m_TensorModel1.SetT2(m_Controls->m_TensorWidget1->GetT2()); parameters.m_FiberModelList.push_back(&m_TensorModel1); parameters.m_SignalModelString += "Tensor"; parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Tensor") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.D1", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD1()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.D2", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD2()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.D3", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD3()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(m_ZeppelinModel1.GetT2()) ); break; } // compartment 2 switch (m_Controls->m_Compartment2Box->currentIndex()) { case 0: break; case 1: m_StickModel2.SetGradientList(parameters.GetGradientDirections()); m_StickModel2.SetBvalue(parameters.m_Bvalue); m_StickModel2.SetDiffusivity(m_Controls->m_StickWidget2->GetD()); m_StickModel2.SetT2(m_Controls->m_StickWidget2->GetT2()); parameters.m_FiberModelList.push_back(&m_StickModel2); parameters.m_SignalModelString += "Stick"; parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Stick") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.D", DoubleProperty::New(m_Controls->m_StickWidget2->GetD()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(m_StickModel2.GetT2()) ); break; case 2: m_ZeppelinModel2.SetGradientList(parameters.GetGradientDirections()); m_ZeppelinModel2.SetBvalue(parameters.m_Bvalue); m_ZeppelinModel2.SetDiffusivity1(m_Controls->m_ZeppelinWidget2->GetD1()); m_ZeppelinModel2.SetDiffusivity2(m_Controls->m_ZeppelinWidget2->GetD2()); m_ZeppelinModel2.SetDiffusivity3(m_Controls->m_ZeppelinWidget2->GetD2()); m_ZeppelinModel2.SetT2(m_Controls->m_ZeppelinWidget2->GetT2()); parameters.m_FiberModelList.push_back(&m_ZeppelinModel2); parameters.m_SignalModelString += "Zeppelin"; parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Zeppelin") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.D1", DoubleProperty::New(m_Controls->m_ZeppelinWidget2->GetD1()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.D2", DoubleProperty::New(m_Controls->m_ZeppelinWidget2->GetD2()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(m_ZeppelinModel2.GetT2()) ); break; case 3: m_TensorModel2.SetGradientList(parameters.GetGradientDirections()); m_TensorModel2.SetBvalue(parameters.m_Bvalue); m_TensorModel2.SetDiffusivity1(m_Controls->m_TensorWidget2->GetD1()); m_TensorModel2.SetDiffusivity2(m_Controls->m_TensorWidget2->GetD2()); m_TensorModel2.SetDiffusivity3(m_Controls->m_TensorWidget2->GetD3()); m_TensorModel2.SetT2(m_Controls->m_TensorWidget2->GetT2()); parameters.m_FiberModelList.push_back(&m_TensorModel2); parameters.m_SignalModelString += "Tensor"; parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Tensor") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.D1", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD1()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.D2", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD2()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.D3", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD3()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(m_ZeppelinModel2.GetT2()) ); break; } // compartment 3 switch (m_Controls->m_Compartment3Box->currentIndex()) { case 0: m_BallModel1.SetGradientList(parameters.GetGradientDirections()); m_BallModel1.SetBvalue(parameters.m_Bvalue); m_BallModel1.SetDiffusivity(m_Controls->m_BallWidget1->GetD()); m_BallModel1.SetT2(m_Controls->m_BallWidget1->GetT2()); m_BallModel1.SetWeight(m_Comp3Weight); parameters.m_NonFiberModelList.push_back(&m_BallModel1); parameters.m_SignalModelString += "Ball"; parameters.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Ball") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment3.D", DoubleProperty::New(m_Controls->m_BallWidget1->GetD()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(m_BallModel1.GetT2()) ); break; case 1: m_AstrosticksModel1.SetGradientList(parameters.GetGradientDirections()); m_AstrosticksModel1.SetBvalue(parameters.m_Bvalue); m_AstrosticksModel1.SetDiffusivity(m_Controls->m_AstrosticksWidget1->GetD()); m_AstrosticksModel1.SetT2(m_Controls->m_AstrosticksWidget1->GetT2()); m_AstrosticksModel1.SetRandomizeSticks(m_Controls->m_AstrosticksWidget1->GetRandomizeSticks()); m_AstrosticksModel1.SetWeight(m_Comp3Weight); parameters.m_NonFiberModelList.push_back(&m_AstrosticksModel1); parameters.m_SignalModelString += "Astrosticks"; parameters.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Astrosticks") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment3.D", DoubleProperty::New(m_Controls->m_AstrosticksWidget1->GetD()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(m_AstrosticksModel1.GetT2()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment3.RandomSticks", BoolProperty::New(m_Controls->m_AstrosticksWidget1->GetRandomizeSticks()) ); break; case 2: m_DotModel1.SetGradientList(parameters.GetGradientDirections()); m_DotModel1.SetT2(m_Controls->m_DotWidget1->GetT2()); m_DotModel1.SetWeight(m_Comp3Weight); parameters.m_NonFiberModelList.push_back(&m_DotModel1); parameters.m_SignalModelString += "Dot"; parameters.m_ResultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Dot") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(m_DotModel1.GetT2()) ); break; } // compartment 4 switch (m_Controls->m_Compartment4Box->currentIndex()) { case 0: break; case 1: m_BallModel2.SetGradientList(parameters.GetGradientDirections()); m_BallModel2.SetBvalue(parameters.m_Bvalue); m_BallModel2.SetDiffusivity(m_Controls->m_BallWidget2->GetD()); m_BallModel2.SetT2(m_Controls->m_BallWidget2->GetT2()); m_BallModel2.SetWeight(m_Comp4Weight); parameters.m_NonFiberModelList.push_back(&m_BallModel2); parameters.m_SignalModelString += "Ball"; parameters.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Ball") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment4.D", DoubleProperty::New(m_Controls->m_BallWidget2->GetD()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(m_BallModel2.GetT2()) ); break; case 2: m_AstrosticksModel2.SetGradientList(parameters.GetGradientDirections()); m_AstrosticksModel2.SetBvalue(parameters.m_Bvalue); m_AstrosticksModel2.SetDiffusivity(m_Controls->m_AstrosticksWidget2->GetD()); m_AstrosticksModel2.SetT2(m_Controls->m_AstrosticksWidget2->GetT2()); m_AstrosticksModel2.SetRandomizeSticks(m_Controls->m_AstrosticksWidget2->GetRandomizeSticks()); m_AstrosticksModel2.SetWeight(m_Comp4Weight); parameters.m_NonFiberModelList.push_back(&m_AstrosticksModel2); parameters.m_SignalModelString += "Astrosticks"; parameters.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Astrosticks") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment4.D", DoubleProperty::New(m_Controls->m_AstrosticksWidget2->GetD()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(m_AstrosticksModel2.GetT2()) ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment4.RandomSticks", BoolProperty::New(m_Controls->m_AstrosticksWidget2->GetRandomizeSticks()) ); break; case 3: m_DotModel2.SetGradientList(parameters.GetGradientDirections()); m_DotModel2.SetT2(m_Controls->m_DotWidget2->GetT2()); m_DotModel2.SetWeight(m_Comp4Weight); parameters.m_NonFiberModelList.push_back(&m_DotModel2); parameters.m_SignalModelString += "Dot"; parameters.m_ResultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Dot") ); parameters.m_ResultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(m_DotModel2.GetT2()) ); break; } parameters.m_ResultNode->AddProperty("Fiberfox.SignalScale", IntProperty::New(parameters.m_SignalScale)); parameters.m_ResultNode->AddProperty("Fiberfox.FiberRadius", IntProperty::New(parameters.m_AxonRadius)); parameters.m_ResultNode->AddProperty("Fiberfox.Tinhom", DoubleProperty::New(parameters.m_tInhom)); parameters.m_ResultNode->AddProperty("Fiberfox.Tline", DoubleProperty::New(parameters.m_tLine)); parameters.m_ResultNode->AddProperty("Fiberfox.TE", DoubleProperty::New(parameters.m_tEcho)); parameters.m_ResultNode->AddProperty("Fiberfox.Repetitions", IntProperty::New(parameters.m_Repetitions)); parameters.m_ResultNode->AddProperty("Fiberfox.b-value", DoubleProperty::New(parameters.m_Bvalue)); parameters.m_ResultNode->AddProperty("Fiberfox.NoPartialVolume", BoolProperty::New(parameters.m_DoDisablePartialVolume)); parameters.m_ResultNode->AddProperty("Fiberfox.Relaxation", BoolProperty::New(parameters.m_DoSimulateRelaxation)); parameters.m_ResultNode->AddProperty("binary", BoolProperty::New(false)); return parameters; } void QmitkFiberfoxView::SaveParameters() { FiberfoxParameters ffParamaters = UpdateImageParameters(); QString filename = QFileDialog::getSaveFileName( 0, tr("Save Parameters"), m_ParameterFile, tr("Fiberfox Parameters (*.ffp)") ); if(filename.isEmpty() || filename.isNull()) return; if(!filename.endsWith(".ffp")) filename += ".ffp"; m_ParameterFile = filename; boost::property_tree::ptree parameters; // fiber generation parameters parameters.put("fiberfox.fibers.realtime", m_Controls->m_RealTimeFibers->isChecked()); parameters.put("fiberfox.fibers.showadvanced", m_Controls->m_AdvancedOptionsBox->isChecked()); parameters.put("fiberfox.fibers.distribution", m_Controls->m_DistributionBox->currentIndex()); parameters.put("fiberfox.fibers.variance", m_Controls->m_VarianceBox->value()); parameters.put("fiberfox.fibers.density", m_Controls->m_FiberDensityBox->value()); parameters.put("fiberfox.fibers.spline.sampling", m_Controls->m_FiberSamplingBox->value()); parameters.put("fiberfox.fibers.spline.tension", m_Controls->m_TensionBox->value()); parameters.put("fiberfox.fibers.spline.continuity", m_Controls->m_ContinuityBox->value()); parameters.put("fiberfox.fibers.spline.bias", m_Controls->m_BiasBox->value()); parameters.put("fiberfox.fibers.constantradius", m_Controls->m_ConstantRadiusBox->isChecked()); parameters.put("fiberfox.fibers.m_Rotation.x", m_Controls->m_XrotBox->value()); parameters.put("fiberfox.fibers.m_Rotation.y", m_Controls->m_YrotBox->value()); parameters.put("fiberfox.fibers.m_Rotation.z", m_Controls->m_ZrotBox->value()); parameters.put("fiberfox.fibers.m_Translation.x", m_Controls->m_XtransBox->value()); parameters.put("fiberfox.fibers.m_Translation.y", m_Controls->m_YtransBox->value()); parameters.put("fiberfox.fibers.m_Translation.z", m_Controls->m_ZtransBox->value()); parameters.put("fiberfox.fibers.scale.x", m_Controls->m_XscaleBox->value()); parameters.put("fiberfox.fibers.scale.y", m_Controls->m_YscaleBox->value()); parameters.put("fiberfox.fibers.scale.z", m_Controls->m_ZscaleBox->value()); parameters.put("fiberfox.fibers.includeFiducials", m_Controls->m_IncludeFiducials->isChecked()); parameters.put("fiberfox.fibers.includeFiducials", m_Controls->m_IncludeFiducials->isChecked()); // image generation parameters parameters.put("fiberfox.image.basic.size.x", ffParamaters.m_ImageRegion.GetSize(0)); parameters.put("fiberfox.image.basic.size.y", ffParamaters.m_ImageRegion.GetSize(1)); parameters.put("fiberfox.image.basic.size.z", ffParamaters.m_ImageRegion.GetSize(2)); parameters.put("fiberfox.image.basic.spacing.x", ffParamaters.m_ImageSpacing[0]); parameters.put("fiberfox.image.basic.spacing.y", ffParamaters.m_ImageSpacing[1]); parameters.put("fiberfox.image.basic.spacing.z", ffParamaters.m_ImageSpacing[2]); parameters.put("fiberfox.image.basic.numgradients", ffParamaters.GetNumWeightedVolumes()); parameters.put("fiberfox.image.basic.bvalue", ffParamaters.m_Bvalue); parameters.put("fiberfox.image.showadvanced", m_Controls->m_AdvancedOptionsBox_2->isChecked()); parameters.put("fiberfox.image.repetitions", ffParamaters.m_Repetitions); parameters.put("fiberfox.image.signalScale", ffParamaters.m_SignalScale); parameters.put("fiberfox.image.tEcho", ffParamaters.m_tEcho); parameters.put("fiberfox.image.tLine", m_Controls->m_LineReadoutTimeBox->value()); parameters.put("fiberfox.image.tInhom", ffParamaters.m_tInhom); parameters.put("fiberfox.image.axonRadius", ffParamaters.m_AxonRadius); parameters.put("fiberfox.image.doSimulateRelaxation", ffParamaters.m_DoSimulateRelaxation); parameters.put("fiberfox.image.doDisablePartialVolume", ffParamaters.m_DoDisablePartialVolume); parameters.put("fiberfox.image.outputvolumefractions", m_Controls->m_VolumeFractionsBox->isChecked()); parameters.put("fiberfox.image.artifacts.addnoise", m_Controls->m_AddNoise->isChecked()); parameters.put("fiberfox.image.artifacts.noisedistribution", m_Controls->m_NoiseDistributionBox->currentIndex()); parameters.put("fiberfox.image.artifacts.noisevariance", m_Controls->m_NoiseLevel->value()); parameters.put("fiberfox.image.artifacts.addghost", m_Controls->m_AddGhosts->isChecked()); parameters.put("fiberfox.image.artifacts.m_KspaceLineOffset", m_Controls->m_kOffsetBox->value()); parameters.put("fiberfox.image.artifacts.distortions", m_Controls->m_AddDistortions->isChecked()); parameters.put("fiberfox.image.artifacts.addeddy", m_Controls->m_AddEddy->isChecked()); parameters.put("fiberfox.image.artifacts.m_EddyStrength", m_Controls->m_EddyGradientStrength->value()); parameters.put("fiberfox.image.artifacts.addringing", m_Controls->m_AddGibbsRinging->isChecked()); parameters.put("fiberfox.image.artifacts.addspikes", m_Controls->m_AddSpikes->isChecked()); parameters.put("fiberfox.image.artifacts.m_Spikesnum", m_Controls->m_SpikeNumBox->value()); parameters.put("fiberfox.image.artifacts.m_Spikesscale", m_Controls->m_SpikeScaleBox->value()); parameters.put("fiberfox.image.artifacts.addaliasing", m_Controls->m_AddAliasing->isChecked()); parameters.put("fiberfox.image.artifacts.aliasingfactor", m_Controls->m_WrapBox->value()); parameters.put("fiberfox.image.artifacts.m_DoAddMotion", m_Controls->m_AddMotion->isChecked()); parameters.put("fiberfox.image.artifacts.m_RandomMotion", m_Controls->m_RandomMotion->isChecked()); parameters.put("fiberfox.image.artifacts.m_Translation0", m_Controls->m_MaxTranslationBoxX->value()); parameters.put("fiberfox.image.artifacts.m_Translation1", m_Controls->m_MaxTranslationBoxY->value()); parameters.put("fiberfox.image.artifacts.m_Translation2", m_Controls->m_MaxTranslationBoxZ->value()); parameters.put("fiberfox.image.artifacts.m_Rotation0", m_Controls->m_MaxRotationBoxX->value()); parameters.put("fiberfox.image.artifacts.m_Rotation1", m_Controls->m_MaxRotationBoxY->value()); parameters.put("fiberfox.image.artifacts.m_Rotation2", m_Controls->m_MaxRotationBoxZ->value()); parameters.put("fiberfox.image.compartment1.index", m_Controls->m_Compartment1Box->currentIndex()); parameters.put("fiberfox.image.compartment2.index", m_Controls->m_Compartment2Box->currentIndex()); parameters.put("fiberfox.image.compartment3.index", m_Controls->m_Compartment3Box->currentIndex()); parameters.put("fiberfox.image.compartment4.index", m_Controls->m_Compartment4Box->currentIndex()); parameters.put("fiberfox.image.compartment1.stick.d", m_Controls->m_StickWidget1->GetD()); parameters.put("fiberfox.image.compartment1.stick.t2", m_Controls->m_StickWidget1->GetT2()); parameters.put("fiberfox.image.compartment1.zeppelin.d1", m_Controls->m_ZeppelinWidget1->GetD1()); parameters.put("fiberfox.image.compartment1.zeppelin.d2", m_Controls->m_ZeppelinWidget1->GetD2()); parameters.put("fiberfox.image.compartment1.zeppelin.t2", m_Controls->m_ZeppelinWidget1->GetT2()); parameters.put("fiberfox.image.compartment1.tensor.d1", m_Controls->m_TensorWidget1->GetD1()); parameters.put("fiberfox.image.compartment1.tensor.d2", m_Controls->m_TensorWidget1->GetD2()); parameters.put("fiberfox.image.compartment1.tensor.d3", m_Controls->m_TensorWidget1->GetD3()); parameters.put("fiberfox.image.compartment1.tensor.t2", m_Controls->m_TensorWidget1->GetT2()); parameters.put("fiberfox.image.compartment2.stick.d", m_Controls->m_StickWidget2->GetD()); parameters.put("fiberfox.image.compartment2.stick.t2", m_Controls->m_StickWidget2->GetT2()); parameters.put("fiberfox.image.compartment2.zeppelin.d1", m_Controls->m_ZeppelinWidget2->GetD1()); parameters.put("fiberfox.image.compartment2.zeppelin.d2", m_Controls->m_ZeppelinWidget2->GetD2()); parameters.put("fiberfox.image.compartment2.zeppelin.t2", m_Controls->m_ZeppelinWidget2->GetT2()); parameters.put("fiberfox.image.compartment2.tensor.d1", m_Controls->m_TensorWidget2->GetD1()); parameters.put("fiberfox.image.compartment2.tensor.d2", m_Controls->m_TensorWidget2->GetD2()); parameters.put("fiberfox.image.compartment2.tensor.d3", m_Controls->m_TensorWidget2->GetD3()); parameters.put("fiberfox.image.compartment2.tensor.t2", m_Controls->m_TensorWidget2->GetT2()); parameters.put("fiberfox.image.compartment3.ball.d", m_Controls->m_BallWidget1->GetD()); parameters.put("fiberfox.image.compartment3.ball.t2", m_Controls->m_BallWidget1->GetT2()); parameters.put("fiberfox.image.compartment3.astrosticks.d", m_Controls->m_AstrosticksWidget1->GetD()); parameters.put("fiberfox.image.compartment3.astrosticks.t2", m_Controls->m_AstrosticksWidget1->GetT2()); parameters.put("fiberfox.image.compartment3.astrosticks.randomize", m_Controls->m_AstrosticksWidget1->GetRandomizeSticks()); parameters.put("fiberfox.image.compartment3.dot.t2", m_Controls->m_DotWidget1->GetT2()); parameters.put("fiberfox.image.compartment4.ball.d", m_Controls->m_BallWidget2->GetD()); parameters.put("fiberfox.image.compartment4.ball.t2", m_Controls->m_BallWidget2->GetT2()); parameters.put("fiberfox.image.compartment4.astrosticks.d", m_Controls->m_AstrosticksWidget2->GetD()); parameters.put("fiberfox.image.compartment4.astrosticks.t2", m_Controls->m_AstrosticksWidget2->GetT2()); parameters.put("fiberfox.image.compartment4.astrosticks.randomize", m_Controls->m_AstrosticksWidget2->GetRandomizeSticks()); parameters.put("fiberfox.image.compartment4.dot.t2", m_Controls->m_DotWidget2->GetT2()); parameters.put("fiberfox.image.compartment4.weight", m_Controls->m_Comp4FractionBox->value()); boost::property_tree::xml_parser::write_xml(filename.toStdString(), parameters); } 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; boost::property_tree::ptree parameters; boost::property_tree::xml_parser::read_xml(filename.toStdString(), parameters); BOOST_FOREACH( boost::property_tree::ptree::value_type const& v1, parameters.get_child("fiberfox") ) { if( v1.first == "fibers" ) { m_Controls->m_RealTimeFibers->setChecked(v1.second.get("realtime")); m_Controls->m_AdvancedOptionsBox->setChecked(v1.second.get("showadvanced")); m_Controls->m_DistributionBox->setCurrentIndex(v1.second.get("distribution")); m_Controls->m_VarianceBox->setValue(v1.second.get("variance")); m_Controls->m_FiberDensityBox->setValue(v1.second.get("density")); m_Controls->m_IncludeFiducials->setChecked(v1.second.get("includeFiducials")); m_Controls->m_ConstantRadiusBox->setChecked(v1.second.get("constantradius")); BOOST_FOREACH( boost::property_tree::ptree::value_type const& v2, v1.second ) { if( v2.first == "spline" ) { m_Controls->m_FiberSamplingBox->setValue(v2.second.get("sampling")); m_Controls->m_TensionBox->setValue(v2.second.get("tension")); m_Controls->m_ContinuityBox->setValue(v2.second.get("continuity")); m_Controls->m_BiasBox->setValue(v2.second.get("bias")); } if( v2.first == "rotation" ) { m_Controls->m_XrotBox->setValue(v2.second.get("x")); m_Controls->m_YrotBox->setValue(v2.second.get("y")); m_Controls->m_ZrotBox->setValue(v2.second.get("z")); } if( v2.first == "translation" ) { m_Controls->m_XtransBox->setValue(v2.second.get("x")); m_Controls->m_YtransBox->setValue(v2.second.get("y")); m_Controls->m_ZtransBox->setValue(v2.second.get("z")); } if( v2.first == "scale" ) { m_Controls->m_XscaleBox->setValue(v2.second.get("x")); m_Controls->m_YscaleBox->setValue(v2.second.get("y")); m_Controls->m_ZscaleBox->setValue(v2.second.get("z")); } } } if( v1.first == "image" ) { m_Controls->m_SizeX->setValue(v1.second.get("basic.size.x")); m_Controls->m_SizeY->setValue(v1.second.get("basic.size.y")); m_Controls->m_SizeZ->setValue(v1.second.get("basic.size.z")); m_Controls->m_SpacingX->setValue(v1.second.get("basic.spacing.x")); m_Controls->m_SpacingY->setValue(v1.second.get("basic.spacing.y")); m_Controls->m_SpacingZ->setValue(v1.second.get("basic.spacing.z")); m_Controls->m_NumGradientsBox->setValue(v1.second.get("basic.numgradients")); m_Controls->m_BvalueBox->setValue(v1.second.get("basic.bvalue")); m_Controls->m_AdvancedOptionsBox_2->setChecked(v1.second.get("showadvanced")); m_Controls->m_RepetitionsBox->setValue(v1.second.get("repetitions")); m_Controls->m_SignalScaleBox->setValue(v1.second.get("signalScale")); m_Controls->m_TEbox->setValue(v1.second.get("tEcho")); m_Controls->m_LineReadoutTimeBox->setValue(v1.second.get("tLine")); m_Controls->m_T2starBox->setValue(v1.second.get("tInhom")); m_Controls->m_FiberRadius->setValue(v1.second.get("axonRadius")); m_Controls->m_RelaxationBox->setChecked(v1.second.get("doSimulateRelaxation")); m_Controls->m_EnforcePureFiberVoxelsBox->setChecked(v1.second.get("doDisablePartialVolume")); m_Controls->m_VolumeFractionsBox->setChecked(v1.second.get("outputvolumefractions")); m_Controls->m_AddNoise->setChecked(v1.second.get("artifacts.addnoise")); m_Controls->m_NoiseDistributionBox->setCurrentIndex(v1.second.get("artifacts.noisedistribution")); m_Controls->m_NoiseLevel->setValue(v1.second.get("artifacts.noisevariance")); m_Controls->m_AddGhosts->setChecked(v1.second.get("artifacts.addghost")); m_Controls->m_kOffsetBox->setValue(v1.second.get("artifacts.m_KspaceLineOffset")); m_Controls->m_AddAliasing->setChecked(v1.second.get("artifacts.addaliasing")); m_Controls->m_WrapBox->setValue(v1.second.get("artifacts.aliasingfactor")); m_Controls->m_AddDistortions->setChecked(v1.second.get("artifacts.distortions")); m_Controls->m_AddSpikes->setChecked(v1.second.get("artifacts.addspikes")); m_Controls->m_SpikeNumBox->setValue(v1.second.get("artifacts.m_Spikesnum")); m_Controls->m_SpikeScaleBox->setValue(v1.second.get("artifacts.m_Spikesscale")); m_Controls->m_AddEddy->setChecked(v1.second.get("artifacts.addeddy")); m_Controls->m_EddyGradientStrength->setValue(v1.second.get("artifacts.m_EddyStrength")); m_Controls->m_AddGibbsRinging->setChecked(v1.second.get("artifacts.addringing")); m_Controls->m_AddMotion->setChecked(v1.second.get("artifacts.m_DoAddMotion")); m_Controls->m_RandomMotion->setChecked(v1.second.get("artifacts.m_RandomMotion")); m_Controls->m_MaxTranslationBoxX->setValue(v1.second.get("artifacts.m_Translation0")); m_Controls->m_MaxTranslationBoxY->setValue(v1.second.get("artifacts.m_Translation1")); m_Controls->m_MaxTranslationBoxZ->setValue(v1.second.get("artifacts.m_Translation2")); m_Controls->m_MaxRotationBoxX->setValue(v1.second.get("artifacts.m_Rotation0")); m_Controls->m_MaxRotationBoxY->setValue(v1.second.get("artifacts.m_Rotation1")); m_Controls->m_MaxRotationBoxZ->setValue(v1.second.get("artifacts.m_Rotation2")); m_Controls->m_Compartment1Box->setCurrentIndex(v1.second.get("compartment1.index")); m_Controls->m_Compartment2Box->setCurrentIndex(v1.second.get("compartment2.index")); m_Controls->m_Compartment3Box->setCurrentIndex(v1.second.get("compartment3.index")); m_Controls->m_Compartment4Box->setCurrentIndex(v1.second.get("compartment4.index")); m_Controls->m_StickWidget1->SetD(v1.second.get("compartment1.stick.d")); m_Controls->m_StickWidget1->SetT2(v1.second.get("compartment1.stick.t2")); m_Controls->m_ZeppelinWidget1->SetD1(v1.second.get("compartment1.zeppelin.d1")); m_Controls->m_ZeppelinWidget1->SetD2(v1.second.get("compartment1.zeppelin.d2")); m_Controls->m_ZeppelinWidget1->SetT2(v1.second.get("compartment1.zeppelin.t2")); m_Controls->m_TensorWidget1->SetD1(v1.second.get("compartment1.tensor.d1")); m_Controls->m_TensorWidget1->SetD2(v1.second.get("compartment1.tensor.d2")); m_Controls->m_TensorWidget1->SetD3(v1.second.get("compartment1.tensor.d3")); m_Controls->m_TensorWidget1->SetT2(v1.second.get("compartment1.tensor.t2")); m_Controls->m_StickWidget2->SetD(v1.second.get("compartment2.stick.d")); m_Controls->m_StickWidget2->SetT2(v1.second.get("compartment2.stick.t2")); m_Controls->m_ZeppelinWidget2->SetD1(v1.second.get("compartment2.zeppelin.d1")); m_Controls->m_ZeppelinWidget2->SetD2(v1.second.get("compartment2.zeppelin.d2")); m_Controls->m_ZeppelinWidget2->SetT2(v1.second.get("compartment2.zeppelin.t2")); m_Controls->m_TensorWidget2->SetD1(v1.second.get("compartment2.tensor.d1")); m_Controls->m_TensorWidget2->SetD2(v1.second.get("compartment2.tensor.d2")); m_Controls->m_TensorWidget2->SetD3(v1.second.get("compartment2.tensor.d3")); m_Controls->m_TensorWidget2->SetT2(v1.second.get("compartment2.tensor.t2")); m_Controls->m_BallWidget1->SetD(v1.second.get("compartment3.ball.d")); m_Controls->m_BallWidget1->SetT2(v1.second.get("compartment3.ball.t2")); m_Controls->m_AstrosticksWidget1->SetD(v1.second.get("compartment3.astrosticks.d")); m_Controls->m_AstrosticksWidget1->SetT2(v1.second.get("compartment3.astrosticks.t2")); m_Controls->m_AstrosticksWidget1->SetRandomizeSticks(v1.second.get("compartment3.astrosticks.randomize")); m_Controls->m_DotWidget1->SetT2(v1.second.get("compartment3.dot.t2")); m_Controls->m_BallWidget2->SetD(v1.second.get("compartment4.ball.d")); m_Controls->m_BallWidget2->SetT2(v1.second.get("compartment4.ball.t2")); m_Controls->m_AstrosticksWidget2->SetD(v1.second.get("compartment4.astrosticks.d")); m_Controls->m_AstrosticksWidget2->SetT2(v1.second.get("compartment4.astrosticks.t2")); m_Controls->m_AstrosticksWidget2->SetRandomizeSticks(v1.second.get("compartment4.astrosticks.randomize")); m_Controls->m_DotWidget2->SetT2(v1.second.get("compartment4.dot.t2")); m_Controls->m_Comp4FractionBox->setValue(v1.second.get("compartment4.weight")); } } } 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); 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; } } void QmitkFiberfoxView::Comp2ModelFrameVisibility(int index) { m_Controls->m_StickWidget2->setVisible(false); m_Controls->m_ZeppelinWidget2->setVisible(false); m_Controls->m_TensorWidget2->setVisible(false); switch (index) { case 0: break; case 1: m_Controls->m_StickWidget2->setVisible(true); break; case 2: m_Controls->m_ZeppelinWidget2->setVisible(true); break; case 3: m_Controls->m_TensorWidget2->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); 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; } } 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_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; } } 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 value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFiberDensityChanged(int value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFiberSamplingChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnTensionChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnContinuityChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnBiasChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::AlignOnGrid() { for (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::Geometry3D::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( 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::Geometry3D::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( 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::Geometry3D::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_SelectedImage.IsNull()) return; mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedImage); mitk::FiberBundleX::Pointer bundle = mitk::FiberBundleX::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_SelectedImage); } 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 ); 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( "PlanarFigure" ); 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; } vector< vector< mitk::PlanarEllipse::Pointer > > fiducials; vector< vector< unsigned int > > fliplist; for (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); } else { v.Normalize(); v *= radius; ellipse->SetControlPoint(1, c+v); } } 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) { fiducials.push_back(fib); fliplist.push_back(flip); } else if (fib.size()>0) m_SelectedBundles.at(i)->SetData( mitk::FiberBundleX::New() ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } itk::FibersFromPlanarFiguresFilter::Pointer filter = itk::FibersFromPlanarFiguresFilter::New(); filter->SetFiducials(fiducials); filter->SetFlipList(fliplist); switch(m_Controls->m_DistributionBox->currentIndex()){ case 0: filter->SetFiberDistribution(itk::FibersFromPlanarFiguresFilter::DISTRIBUTE_UNIFORM); break; case 1: filter->SetFiberDistribution(itk::FibersFromPlanarFiguresFilter::DISTRIBUTE_GAUSSIAN); filter->SetVariance(m_Controls->m_VarianceBox->value()); break; } filter->SetDensity(m_Controls->m_FiberDensityBox->value()); filter->SetTension(m_Controls->m_TensionBox->value()); filter->SetContinuity(m_Controls->m_ContinuityBox->value()); filter->SetBias(m_Controls->m_BiasBox->value()); filter->SetFiberSampling(m_Controls->m_FiberSamplingBox->value()); filter->Update(); vector< mitk::FiberBundleX::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_SelectedBundles.empty() && m_SelectedDWI.IsNull()) { 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_SelectedImage = node; mitk::BaseData::Pointer basedata = node->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } UpdateGui(); } else if (!m_SelectedBundles.empty()) SimulateImageFromFibers(m_SelectedBundles.at(0)); else if (m_SelectedDWI.IsNotNull()) SimulateForExistingDwi(m_SelectedDWI); } void QmitkFiberfoxView::SimulateForExistingDwi(mitk::DataNode* imageNode) { if (!dynamic_cast*>(imageNode->GetData())) return; FiberfoxParameters parameters = UpdateImageParameters(); if (parameters.m_NoiseModel==NULL && parameters.m_Spikes==0 && parameters.m_FrequencyMap.IsNull() && parameters.m_KspaceLineOffset<=0.000001 && !parameters.m_DoAddGibbsRinging && !(parameters.m_EddyStrength>0) && parameters.m_Wrap>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::DiffusionImage::Pointer diffImg = dynamic_cast*>(imageNode->GetData()); m_ArtifactsToDwiFilter = itk::AddArtifactsToDwiImageFilter< short >::New(); m_ArtifactsToDwiFilter->SetInput(diffImg->GetVectorImage()); parameters.m_ParentNode = imageNode; m_ArtifactsToDwiFilter->SetParameters(parameters); m_Worker.m_FilterType = 1; m_Thread.start(QThread::LowestPriority); } void QmitkFiberfoxView::SimulateImageFromFibers(mitk::DataNode* fiberNode) { mitk::FiberBundleX::Pointer fiberBundle = dynamic_cast(fiberNode->GetData()); if (fiberBundle->GetNumFibers()<=0) return; FiberfoxParameters parameters = UpdateImageParameters(); m_TractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); parameters.m_ParentNode = fiberNode; 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( 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()) { std::vector::const_iterator it = selectedBundles.begin(); for (it; it!=selectedBundles.end(); ++it) { mitk::FiberBundleX::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::Geometry3D* 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); } } } } } else { for (int i=0; i(m_SelectedFiducials.at(i)->GetData()); mitk::Geometry3D* 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()); } 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("QmitkFiberProcessingView") << "Select at least one fiber bundle!"; return; } std::vector::const_iterator it = m_SelectedBundles.begin(); for (it; 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::FiberBundleX::Pointer fib = dynamic_cast((*it)->GetData()); mitk::FiberBundleX::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 = mitk::PlanarEllipse::New(); pe->DeepCopy(dynamic_cast(fiducialNode->GetData())); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(pe); newNode->SetName(fiducialNode->GetName()); 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("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; return; } std::vector::const_iterator it = m_SelectedBundles.begin(); mitk::FiberBundleX::Pointer newBundle = dynamic_cast((*it)->GetData()); QString name(""); name += QString((*it)->GetName().c_str()); ++it; for (it; 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_FiberBundleLabel->setText("mandatory"); 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); if (m_SelectedFiducial.IsNotNull()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_FlipButton->setEnabled(true); m_Controls->m_AlignOnGrid->setEnabled(true); } if (m_SelectedImage.IsNotNull() || !m_SelectedBundles.empty()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_CircleButton->setEnabled(true); m_Controls->m_FiberGenMessage->setVisible(false); m_Controls->m_AlignOnGrid->setEnabled(true); } if (m_ItkMaskImage.IsNotNull() || m_SelectedImage.IsNotNull()) { m_Controls->m_GeometryMessage->setVisible(true); m_Controls->m_GeometryFrame->setEnabled(false); } if (m_SelectedDWI.IsNotNull()) { 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); } if (!m_SelectedBundles.empty()) { m_Controls->m_CopyBundlesButton->setEnabled(true); m_Controls->m_GenerateFibersButton->setEnabled(true); m_Controls->m_FiberBundleLabel->setText(m_SelectedBundles.at(0)->GetName().c_str()); if (m_SelectedBundles.size()>1) m_Controls->m_JoinBundlesButton->setEnabled(true); } } 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_SelectedImage = NULL; m_SelectedDWI = NULL; m_ItkMaskImage = NULL; m_Controls->m_TissueMaskLabel->setText("optional"); // iterate all selected objects, adjust warning visibility for( int i=0; i*>(node->GetData()) ) { m_SelectedDWI = node; m_SelectedImage = node; m_SelectedImages.push_back(node); } else if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedImages.push_back(node); m_SelectedImage = node; mitk::Image::Pointer image = dynamic_cast(node->GetData()); bool isbinary = false; node->GetPropertyValue("binary", isbinary); if (isbinary) { mitk::CastToItkImage(image, m_ItkMaskImage); m_Controls->m_TissueMaskLabel->setText(node->GetName().c_str()); } } 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::FiberBundleX::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( "PlanarFigure" ); 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 m_OutputPath = QFileDialog::getExistingDirectory(NULL, "Save images to...", QString(m_OutputPath.c_str())).toStdString(); if (m_OutputPath.empty()) m_Controls->m_SavePathEdit->setText("-"); else { m_OutputPath += "/"; m_Controls->m_SavePathEdit->setText(QString(m_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 1a40009c25..e36fb3cb77 100755 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h @@ -1,224 +1,225 @@ /*=================================================================== 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*! -\brief View for fiber based diffusion software phantoms (Fiberfox). - +\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); void SetFocus(); typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkUcharImgType; typedef itk::Vector GradientType; typedef vector GradientListType; 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); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList&); 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) 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 ); ///< add observers void NodeRemoved(const mitk::DataNode* node); ///< 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_SelectedImage; mitk::DataNode::Pointer m_SelectedDWI; vector< mitk::DataNode::Pointer > m_SelectedBundles; vector< mitk::DataNode::Pointer > m_SelectedBundles2; vector< mitk::DataNode::Pointer > m_SelectedFiducials; vector< mitk::DataNode::Pointer > m_SelectedImages; ItkUcharImgType::Pointer m_ItkMaskImage; /** intra and inter axonal compartments */ mitk::StickModel m_StickModel1; mitk::StickModel m_StickModel2; mitk::TensorModel m_ZeppelinModel1; mitk::TensorModel m_ZeppelinModel2; mitk::TensorModel m_TensorModel1; mitk::TensorModel m_TensorModel2; /** extra axonal compartment models */ mitk::BallModel m_BallModel1; mitk::BallModel m_BallModel2; mitk::AstroStickModel m_AstrosticksModel1; mitk::AstroStickModel m_AstrosticksModel2; mitk::DotModel m_DotModel1; mitk::DotModel m_DotModel2; QString m_ParameterFile; ///< parameter file name string m_OutputPath; ///< image save path // GUI thread QmitkFiberfoxWorker m_Worker; ///< runs filter QThread m_Thread; ///< worker thread - itk::TractsToDWIImageFilter< short >::Pointer m_TractsToDwiFilter; - itk::AddArtifactsToDwiImageFilter< short >::Pointer m_ArtifactsToDwiFilter; 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/QmitkFieldmapGeneratorView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFieldmapGeneratorView.h index fa93f52bde..2e816b301b 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFieldmapGeneratorView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFieldmapGeneratorView.h @@ -1,81 +1,82 @@ /*=================================================================== 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 _QMITKQmitkFieldmapGeneratorView_H_INCLUDED #define _QMITKQmitkFieldmapGeneratorView_H_INCLUDED #include #include #include "ui_QmitkFieldmapGeneratorViewControls.h" #include #include /*! - \brief View displaying details of the orientation distribution function in the voxel at the current crosshair position. + \brief Generate float image with artificial frequency maps used by Fiberfox. Simulates additional frequencies at (possibly multiple) positions based on 3D gaussians with the specified variance and amplitude and/or as a linear gradient in the image. +* See "Fiberfox: Facilitating the creation of realistic white matter software phantoms" (DOI: 10.1002/mrm.25045) for details.. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkFieldmapGeneratorView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; QmitkFieldmapGeneratorView(); virtual ~QmitkFieldmapGeneratorView(); virtual void CreateQtPartControl(QWidget *parent); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); void OnSliceChanged(const itk::EventObject& e); protected slots: void GenerateFieldmap(); void PlaceFieldSource(); void OnVarianceChanged(double value); void OnHeightChanged(double value); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ); Ui::QmitkFieldmapGeneratorViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; /** observer flags */ int m_SliceObserverTag1; int m_SliceObserverTag2; int m_SliceObserverTag3; int m_PropertyObserverTag; mitk::Point3D m_WorldPoint; mitk::DataNode::Pointer m_SelectedSource; }; #endif // _QmitkFieldmapGeneratorView_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.h index 118a270370..fb4407ab0f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkStreamlineTrackingView.h @@ -1,90 +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. ===================================================================*/ #ifndef QmitkStreamlineTrackingView_h #define QmitkStreamlineTrackingView_h #include #include "ui_QmitkStreamlineTrackingViewControls.h" #include #include #include #include #include /*! -\brief View for deterministic streamline fiber tracking. +\brief View for tensor based deterministic streamline fiber tracking. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkStreamlineTrackingView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; typedef itk::Image< unsigned char, 3 > ItkUCharImageType; typedef itk::Image< float, 3 > ItkFloatImageType; QmitkStreamlineTrackingView(); virtual ~QmitkStreamlineTrackingView(); virtual void CreateQtPartControl(QWidget *parent); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); protected slots: void DoFiberTracking(); ///< start fiber tracking protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ); Ui::QmitkStreamlineTrackingViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; protected slots: /** update labels if parameters have changed */ void OnSeedsPerVoxelChanged(int value); void OnMinTractLengthChanged(int value); void OnFaThresholdChanged(int value); void OnAngularThresholdChanged(int value); void OnfChanged(int value); void OngChanged(int value); void OnStepsizeChanged(int value); private: mitk::Image::Pointer m_MaskImage; ///< abort tracking if leaving mask mitk::Image::Pointer m_SeedRoi; ///< binary image defining seed voxels for tracking process std::vector< mitk::DataNode::Pointer > m_TensorImageNodes; ///< input images std::vector< mitk::TensorImage::Pointer > m_TensorImages; ///< input image datanode }; #endif // _QMITKFIBERTRACKINGVIEW_H_INCLUDED