diff --git a/Modules/DiffusionImaging/FiberTracking/Fiberfox/Sequences/mitkCartesianReadout.h b/Modules/DiffusionImaging/FiberTracking/Fiberfox/Sequences/mitkConventionalSpinEcho.h similarity index 85% rename from Modules/DiffusionImaging/FiberTracking/Fiberfox/Sequences/mitkCartesianReadout.h rename to Modules/DiffusionImaging/FiberTracking/Fiberfox/Sequences/mitkConventionalSpinEcho.h index 17073912d9..aa262f8c2d 100644 --- a/Modules/DiffusionImaging/FiberTracking/Fiberfox/Sequences/mitkCartesianReadout.h +++ b/Modules/DiffusionImaging/FiberTracking/Fiberfox/Sequences/mitkConventionalSpinEcho.h @@ -1,89 +1,89 @@ /*=================================================================== 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_CartesianReadout_H -#define _MITK_CartesianReadout_H +#ifndef _MITK_ConventionalSpinEcho_H +#define _MITK_ConventionalSpinEcho_H #include <mitkAcquisitionType.h> namespace mitk { /** - * \brief + * \brief Conventional spin echo sequence. Cartesian readout. One echo and one excitation per k-space line. * */ -class CartesianReadout : public AcquisitionType +class ConventionalSpinEcho : public AcquisitionType { public: - CartesianReadout(FiberfoxParameters* parameters) : AcquisitionType(parameters) + ConventionalSpinEcho(FiberfoxParameters* parameters) : AcquisitionType(parameters) { kxMax = m_Parameters->m_SignalGen.m_CroppedRegion.GetSize(0); kyMax = m_Parameters->m_SignalGen.m_CroppedRegion.GetSize(1); dt = m_Parameters->m_SignalGen.m_tLine/kxMax; // time to read one k-space voxel // maximum echo at center of each line m_NegTEhalf = -dt*(kxMax-(int)kxMax%2)/2; } - ~CartesianReadout() override + ~ConventionalSpinEcho() override {} float GetTimeFromMaxEcho(itk::Index< 2 > index) override { float t = 0; t = m_NegTEhalf + (float)index[0]*dt; return t; } float GetRedoutTime(itk::Index< 2 > index) override { float t = 0; t = (float)index[0]*dt; return t; } itk::Index< 2 > GetActualKspaceIndex(itk::Index< 2 > index) override { // reverse phase if (!m_Parameters->m_SignalGen.m_ReversePhase) index[1] = kyMax-1-index[1]; return index; } void AdjustEchoTime() override { if ( m_Parameters->m_SignalGen.m_tEcho/2 < m_Parameters->m_SignalGen.m_tLine/2 ) { m_Parameters->m_SignalGen.m_tEcho = m_Parameters->m_SignalGen.m_tLine; MITK_WARN << "Echo time is too short! Time not sufficient to read slice. Automatically adjusted to " << m_Parameters->m_SignalGen.m_tEcho << " ms"; m_Parameters->m_Misc.m_AfterSimulationMessage += "Echo time was chosen too short! Time not sufficient to read slice. Internally adjusted to " + boost::lexical_cast<std::string>(m_Parameters->m_SignalGen.m_tEcho) + " ms\n"; } } protected: float dt; int kxMax; int kyMax; }; } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkKspaceImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkKspaceImageFilter.cpp index 335241aba6..acaba8ddd3 100644 --- a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkKspaceImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkKspaceImageFilter.cpp @@ -1,463 +1,463 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkKspaceImageFilter_txx #define __itkKspaceImageFilter_txx //#endif #include <ctime> #include <cstdio> #include <cstdlib> #include <math.h> #include "itkKspaceImageFilter.h" #include <itkImageRegionConstIterator.h> #include <itkImageRegionConstIteratorWithIndex.h> #include <itkImageRegionIterator.h> #include <mitkSingleShotEpi.h> -#include <mitkCartesianReadout.h> +#include <mitkConventionalSpinEcho.h> #include <mitkDiffusionFunctionCollection.h> namespace itk { template< class ScalarType > KspaceImageFilter< ScalarType >::KspaceImageFilter() : m_Z(0) , m_RandSeed(-1) , m_SpikesPerSlice(0) , m_IsBaseline(true) { m_DiffusionGradientDirection.Fill(0.0); m_CoilPosition.Fill(0.0); } template< class ScalarType > void KspaceImageFilter< ScalarType > ::BeforeThreadedGenerateData() { m_Spike = vcl_complex<ScalarType>(0,0); m_SpikeLog = ""; m_TransX = -m_Translation[0]; m_TransY = -m_Translation[1]; m_TransZ = -m_Translation[2]; kxMax = m_Parameters->m_SignalGen.m_CroppedRegion.GetSize(0); kyMax = m_Parameters->m_SignalGen.m_CroppedRegion.GetSize(1); xMax = m_CompartmentImages.at(0)->GetLargestPossibleRegion().GetSize(0); // scanner coverage in x-direction yMax = m_CompartmentImages.at(0)->GetLargestPossibleRegion().GetSize(1); // scanner coverage in y-direction yMaxFov = yMax; if (m_Parameters->m_Misc.m_DoAddAliasing) yMaxFov *= m_Parameters->m_SignalGen.m_CroppingFactor; // actual FOV in y-direction (in x-direction FOV=xMax) yMaxFov_half = yMaxFov/2; numPix = kxMax*kyMax; float ringing_factor = static_cast<float>(m_Parameters->m_SignalGen.m_ZeroRinging)/100.0; ringing_lines_x = static_cast<int>(ceil(kxMax/2 * ringing_factor)); ringing_lines_y = static_cast<int>(ceil(kyMax/2 * ringing_factor)); // Adjust noise variance since it is the intended variance in physical space and not in k-space: float noiseVar = m_Parameters->m_SignalGen.m_PartialFourier*m_Parameters->m_SignalGen.m_NoiseVariance/(kyMax*kxMax); m_RandGen = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); if (m_RandSeed>=0) // always generate the same random numbers? m_RandGen->SetSeed(m_RandSeed); else m_RandGen->SetSeed(); typename OutputImageType::Pointer outputImage = OutputImageType::New(); itk::ImageRegion<2> region; region.SetSize(0, m_Parameters->m_SignalGen.m_CroppedRegion.GetSize(0)); region.SetSize(1, m_Parameters->m_SignalGen.m_CroppedRegion.GetSize(1)); outputImage->SetLargestPossibleRegion( region ); outputImage->SetBufferedRegion( region ); outputImage->SetRequestedRegion( region ); outputImage->Allocate(); vcl_complex<ScalarType> zero = vcl_complex<ScalarType>(0, 0); outputImage->FillBuffer(zero); if (m_Parameters->m_SignalGen.m_NoiseVariance>0 && m_Parameters->m_Misc.m_DoAddNoise) { ImageRegionIterator< OutputImageType > oit(outputImage, outputImage->GetLargestPossibleRegion()); while( !oit.IsAtEnd() ) { oit.Set(vcl_complex<ScalarType>(m_RandGen->GetNormalVariate(0, noiseVar), m_RandGen->GetNormalVariate(0, noiseVar))); ++oit; } } m_KSpaceImage = InputImageType::New(); m_KSpaceImage->SetLargestPossibleRegion( region ); m_KSpaceImage->SetBufferedRegion( region ); m_KSpaceImage->SetRequestedRegion( region ); m_KSpaceImage->Allocate(); m_KSpaceImage->FillBuffer(0.0); m_Gamma = 42576000; // Gyromagnetic ratio in Hz/T (1.5T) if ( m_Parameters->m_SignalGen.m_EddyStrength>0 && m_DiffusionGradientDirection.GetNorm()>0.001) { m_DiffusionGradientDirection.Normalize(); m_DiffusionGradientDirection = m_DiffusionGradientDirection * m_Parameters->m_SignalGen.m_EddyStrength/1000 * m_Gamma; m_IsBaseline = false; } this->SetNthOutput(0, outputImage); for (int i=0; i<3; i++) for (int j=0; j<3; j++) m_Transform[i][j] = m_Parameters->m_SignalGen.m_ImageDirection[i][j] * m_Parameters->m_SignalGen.m_ImageSpacing[j]/1000; float a = m_Parameters->m_SignalGen.m_ImageRegion.GetSize(0)*m_Parameters->m_SignalGen.m_ImageSpacing[0]; float b = m_Parameters->m_SignalGen.m_ImageRegion.GetSize(1)*m_Parameters->m_SignalGen.m_ImageSpacing[1]; float diagonal = sqrt(a*a+b*b)/1000; // image diagonal in m switch (m_Parameters->m_SignalGen.m_CoilSensitivityProfile) { case SignalGenerationParameters::COIL_CONSTANT: { m_CoilSensitivityFactor = 1; // same signal everywhere break; } case SignalGenerationParameters::COIL_LINEAR: { m_CoilSensitivityFactor = -1/diagonal; // about 50% of the signal in the image center remaining break; } case SignalGenerationParameters::COIL_EXPONENTIAL: { m_CoilSensitivityFactor = -log(0.1)/diagonal; // about 32% of the signal in the image center remaining break; } } switch (m_Parameters->m_SignalGen.m_AcquisitionType) { case SignalGenerationParameters::SingleShotEpi: m_ReadoutScheme = new mitk::SingleShotEpi(m_Parameters); break; - case SignalGenerationParameters::SpinEcho: - m_ReadoutScheme = new mitk::CartesianReadout(m_Parameters); + case SignalGenerationParameters::ConventionalSpinEcho: + m_ReadoutScheme = new mitk::ConventionalSpinEcho(m_Parameters); break; default: m_ReadoutScheme = new mitk::SingleShotEpi(m_Parameters); } m_ReadoutScheme->AdjustEchoTime(); m_MovedFmap = nullptr; if (m_Parameters->m_Misc.m_DoAddDistortions && m_Parameters->m_SignalGen.m_FrequencyMap.IsNotNull() && m_Parameters->m_SignalGen.m_DoAddMotion) { // we have to account for the head motion since this also moves our frequency map itk::LinearInterpolateImageFunction< itk::Image< float, 3 >, float >::Pointer fmapInterpolator; fmapInterpolator = itk::LinearInterpolateImageFunction< itk::Image< float, 3 >, float >::New(); fmapInterpolator->SetInputImage(m_Parameters->m_SignalGen.m_FrequencyMap); m_MovedFmap = itk::Image< ScalarType, 2 >::New(); m_MovedFmap->SetLargestPossibleRegion( m_CompartmentImages.at(0)->GetLargestPossibleRegion() ); m_MovedFmap->SetBufferedRegion( m_CompartmentImages.at(0)->GetLargestPossibleRegion() ); m_MovedFmap->SetRequestedRegion( m_CompartmentImages.at(0)->GetLargestPossibleRegion() ); m_MovedFmap->Allocate(); m_MovedFmap->FillBuffer(0); ImageRegionIterator< InputImageType > it(m_MovedFmap, m_MovedFmap->GetLargestPossibleRegion() ); while( !it.IsAtEnd() ) { itk::Image<float, 3>::IndexType index; index[0] = it.GetIndex()[0]; index[1] = it.GetIndex()[1]; index[2] = m_Zidx; itk::Point<float, 3> point3D; m_Parameters->m_SignalGen.m_FrequencyMap->TransformIndexToPhysicalPoint(index, point3D); m_FiberBundle->TransformPoint<float>( point3D, m_RotationMatrix, m_TransX, m_TransY, m_TransZ ); it.Set(mitk::imv::GetImageValue<float>(point3D, true, fmapInterpolator)); ++it; } } // calculate T1 relaxation (independent of actual readout) m_T1Relax.clear(); if ( m_Parameters->m_SignalGen.m_DoSimulateRelaxation) for (unsigned int i=0; i<m_CompartmentImages.size(); i++) { // account for T1 relaxation (how much magnetization is available since last excitation?) float relaxation = (1.0-std::exp(-m_Parameters->m_SignalGen.m_tRep/m_T1[i])); // account for inversion pulse and TI if (m_Parameters->m_SignalGen.m_tInv > 0) relaxation *= (1.0-std::exp(std::log(2) - m_Parameters->m_SignalGen.m_tInv/m_T1[i])); m_T1Relax.push_back(relaxation); } } template< class ScalarType > float KspaceImageFilter< ScalarType >::CoilSensitivity(VectorType& pos) { // ************************************************************************* // Coil ring is moving with excited slice (FIX THIS SOMETIME) m_CoilPosition[2] = pos[2]; // ************************************************************************* switch (m_Parameters->m_SignalGen.m_CoilSensitivityProfile) { case SignalGenerationParameters::COIL_CONSTANT: return 1; case SignalGenerationParameters::COIL_LINEAR: { VectorType diff = pos-m_CoilPosition; float sens = diff.GetNorm()*m_CoilSensitivityFactor + 1; if (sens<0) sens = 0; return sens; } case SignalGenerationParameters::COIL_EXPONENTIAL: { VectorType diff = pos-m_CoilPosition; float dist = static_cast<float>(diff.GetNorm()); return std::exp(-dist*m_CoilSensitivityFactor); } default: return 1; } } template< class ScalarType > void KspaceImageFilter< ScalarType > ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) { typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); typedef ImageRegionConstIterator< InputImageType > InputIteratorType; vcl_complex<ScalarType> zero = vcl_complex<ScalarType>(0, 0); while( !oit.IsAtEnd() ) { typename OutputImageType::IndexType out_idx = oit.GetIndex(); // get current k-space index (depends on the chosen k-space readout scheme) itk::Index< 2 > kIdx = m_ReadoutScheme->GetActualKspaceIndex(out_idx); // partial fourier if (kIdx[1]>kyMax*m_Parameters->m_SignalGen.m_PartialFourier) { outputImage->SetPixel(kIdx, zero); ++oit; continue; } // gibbs ringing by setting high frequencies to zero (alternative to using smaller k-space than input image space) if (m_Parameters->m_SignalGen.m_DoAddGibbsRinging && m_Parameters->m_SignalGen.m_ZeroRinging>0) { if (kIdx[0] < ringing_lines_x || kIdx[1] < ringing_lines_y || kIdx[0] >= kxMax - ringing_lines_x || kIdx[1] >= kyMax - ringing_lines_y) { outputImage->SetPixel(kIdx, zero); ++oit; continue; } } // shift k for DFT: (0 -- N) --> (-N/2 -- N/2) float kx = kIdx[0]; float ky = kIdx[1]; if (static_cast<int>(kxMax)%2==1) kx -= (kxMax-1)/2; else kx -= kxMax/2; if (static_cast<int>(kyMax)%2==1) ky -= (kyMax-1)/2; else ky -= kyMax/2; // time from maximum echo float t = m_ReadoutScheme->GetTimeFromMaxEcho(out_idx); // time passed since k-space readout started float tRead = m_ReadoutScheme->GetRedoutTime(out_idx); // time passes since application of the RF pulse float tRf = m_Parameters->m_SignalGen.m_tEcho+t; // calculate eddy current decay factor // (TODO: vielleicht umbauen dass hier die zeit vom letzten diffusionsgradienten an genommen wird. doku dann auch entsprechend anpassen.) float eddyDecay = 0; if ( m_Parameters->m_Misc.m_DoAddEddyCurrents && m_Parameters->m_SignalGen.m_EddyStrength>0) eddyDecay = std::exp(-tRead/m_Parameters->m_SignalGen.m_Tau ); // calcualte signal relaxation factors std::vector< float > relaxFactor; if ( m_Parameters->m_SignalGen.m_DoSimulateRelaxation) for (unsigned int i=0; i<m_CompartmentImages.size(); i++) { // account for T2 relaxation (how much transverse magnetization is left since applicatiohn of RF pulse?) relaxFactor.push_back(m_T1Relax[i] * std::exp(-tRf/m_T2[i] -fabs(t)/ m_Parameters->m_SignalGen.m_tInhom)); } // add ghosting by adding gradient delay induced offset if (m_Parameters->m_Misc.m_DoAddGhosts) { if (out_idx[1]%2 == 1) kx -= m_Parameters->m_SignalGen.m_KspaceLineOffset; else kx += m_Parameters->m_SignalGen.m_KspaceLineOffset; } // pull stuff out of inner loop t /= 1000; kx /= xMax; ky /= yMaxFov; // calculate signal s at k-space position (kx, ky) vcl_complex<ScalarType> s(0,0); InputIteratorType it(m_CompartmentImages[0], m_CompartmentImages[0]->GetLargestPossibleRegion() ); while( !it.IsAtEnd() ) { typename InputImageType::IndexType input_idx = it.GetIndex(); // shift x,y for DFT: (0 -- N) --> (-N/2 -- N/2) float x = input_idx[0]; float y = input_idx[1]; if (static_cast<int>(xMax)%2==1) x -= (xMax-1)/2; else x -= xMax/2; if (static_cast<int>(yMax)%2==1) y -= (yMax-1)/2; else y -= yMax/2; // sum compartment signals and simulate relaxation ScalarType f_real = 0; for (unsigned int i=0; i<m_CompartmentImages.size(); i++) if ( m_Parameters->m_SignalGen.m_DoSimulateRelaxation) f_real += m_CompartmentImages[i]->GetPixel(input_idx) * relaxFactor[i] * m_Parameters->m_SignalGen.m_SignalScale; else f_real += m_CompartmentImages[i]->GetPixel(input_idx) * m_Parameters->m_SignalGen.m_SignalScale; // vector from image center to current position (in meter) // only necessary for eddy currents and non-constant coil sensitivity VectorType pos; if ((m_Parameters->m_Misc.m_DoAddEddyCurrents && m_Parameters->m_SignalGen.m_EddyStrength>0 && !m_IsBaseline) || m_Parameters->m_SignalGen.m_CoilSensitivityProfile!=SignalGenerationParameters::COIL_CONSTANT) { pos[0] = x; pos[1] = y; pos[2] = m_Z; pos = m_Transform*pos; } if (m_Parameters->m_SignalGen.m_CoilSensitivityProfile!=SignalGenerationParameters::COIL_CONSTANT) f_real *= CoilSensitivity(pos); // simulate eddy currents and other distortions float omega = 0; // frequency offset if ( m_Parameters->m_Misc.m_DoAddEddyCurrents && m_Parameters->m_SignalGen.m_EddyStrength>0 && !m_IsBaseline) omega += (m_DiffusionGradientDirection[0]*pos[0]+m_DiffusionGradientDirection[1]*pos[1]+m_DiffusionGradientDirection[2]*pos[2]) * eddyDecay; // simulate distortions if (m_Parameters->m_Misc.m_DoAddDistortions) { if (m_MovedFmap.IsNotNull()) // if we have headmotion, use moved map omega += m_MovedFmap->GetPixel(input_idx); else if (m_Parameters->m_SignalGen.m_FrequencyMap.IsNotNull()) { itk::Image<float, 3>::IndexType index; index[0] = input_idx[0]; index[1] = input_idx[1]; index[2] = m_Zidx; omega += m_Parameters->m_SignalGen.m_FrequencyMap->GetPixel(index); } } // if signal comes from outside FOV, mirror it back (wrap-around artifact - aliasing if (m_Parameters->m_Misc.m_DoAddAliasing) { if (y<-yMaxFov_half) y += yMaxFov; else if (y>=yMaxFov_half) y -= yMaxFov; } // actual DFT term vcl_complex<ScalarType> f(f_real, 0); s += f * std::exp( std::complex<ScalarType>(0, itk::Math::twopi * (kx*x + ky*y + omega*t )) ); ++it; } s /= numPix; if (m_SpikesPerSlice>0 && sqrt(s.imag()*s.imag()+s.real()*s.real()) > sqrt(m_Spike.imag()*m_Spike.imag()+m_Spike.real()*m_Spike.real()) ) m_Spike = s; s += outputImage->GetPixel(kIdx); // add precalculated noise outputImage->SetPixel(kIdx, s); m_KSpaceImage->SetPixel(kIdx, sqrt(s.imag()*s.imag()+s.real()*s.real()) ); ++oit; } } template< class ScalarType > void KspaceImageFilter< ScalarType > ::AfterThreadedGenerateData() { delete m_ReadoutScheme; typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); int kxMax = outputImage->GetLargestPossibleRegion().GetSize(0); // k-space size in x-direction int kyMax = outputImage->GetLargestPossibleRegion().GetSize(1); // k-space size in y-direction ImageRegionIterator< OutputImageType > oit(outputImage, outputImage->GetLargestPossibleRegion()); while( !oit.IsAtEnd() ) // use hermitian k-space symmetry to fill empty k-space parts resulting from partial fourier acquisition { itk::Index< 2 > kIdx; kIdx[0] = oit.GetIndex()[0]; kIdx[1] = oit.GetIndex()[1]; // reverse phase if (!m_Parameters->m_SignalGen.m_ReversePhase) kIdx[1] = static_cast<int>(kyMax-1-kIdx[1]); if (kIdx[1]>kyMax*m_Parameters->m_SignalGen.m_PartialFourier) { // reverse readout direction if (oit.GetIndex()[1]%2 == 1) kIdx[0] = kxMax-kIdx[0]-1; // calculate symmetric index itk::Index< 2 > kIdx2; kIdx2[0] = (kxMax-kIdx[0]-kxMax%2)%kxMax; kIdx2[1] = (kyMax-kIdx[1]-kyMax%2)%kyMax; // use complex conjugate of symmetric index value at current index vcl_complex<ScalarType> s = outputImage->GetPixel(kIdx2); s = vcl_complex<ScalarType>(s.real(), -s.imag()); outputImage->SetPixel(kIdx, s); m_KSpaceImage->SetPixel(kIdx, sqrt(s.imag()*s.imag()+s.real()*s.real()) ); } ++oit; } m_Spike *= m_Parameters->m_SignalGen.m_SpikeAmplitude; itk::Index< 2 > spikeIdx; for (unsigned int i=0; i<m_SpikesPerSlice; i++) { spikeIdx[0] = m_RandGen->GetIntegerVariate()%kxMax; spikeIdx[1] = m_RandGen->GetIntegerVariate()%kyMax; outputImage->SetPixel(spikeIdx, m_Spike); m_SpikeLog += "[" + boost::lexical_cast<std::string>(spikeIdx[0]) + "," + boost::lexical_cast<std::string>(spikeIdx[1]) + "," + boost::lexical_cast<std::string>(m_Zidx) + "] Magnitude: " + boost::lexical_cast<std::string>(m_Spike.real()) + "+" + boost::lexical_cast<std::string>(m_Spike.imag()) + "i\n"; } } } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp index c81c025fa3..86a0959de0 100755 --- a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp @@ -1,1790 +1,1790 @@ /*=================================================================== 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 <boost/progress.hpp> #include <vtkSmartPointer.h> #include <vtkPolyData.h> #include <vtkCellArray.h> #include <vtkPoints.h> #include <vtkPolyLine.h> #include <itkImageRegionIteratorWithIndex.h> #include <itkResampleImageFilter.h> #include <itkNearestNeighborInterpolateImageFunction.h> #include <itkBSplineInterpolateImageFunction.h> #include <itkCastImageFilter.h> #include <itkImageFileWriter.h> #include <itkRescaleIntensityImageFilter.h> #include <itkWindowedSincInterpolateImageFunction.h> #include <itkResampleDwiImageFilter.h> #include <itkKspaceImageFilter.h> #include <itkDftImageFilter.h> #include <itkAddImageFilter.h> #include <itkConstantPadImageFilter.h> #include <itkCropImageFilter.h> #include <mitkAstroStickModel.h> #include <vtkTransform.h> #include <iostream> #include <fstream> #include <exception> #include <itkImageDuplicator.h> #include <itksys/SystemTools.hxx> #include <mitkIOUtil.h> #include <itkDiffusionTensor3DReconstructionImageFilter.h> #include <itkDiffusionTensor3D.h> #include <itkTractDensityImageFilter.h> #include <mitkLexicalCast.h> #include <itkTractsToVectorImageFilter.h> #include <itkInvertIntensityImageFilter.h> #include <itkShiftScaleImageFilter.h> #include <itkExtractImageFilter.h> #include <itkResampleDwiImageFilter.h> #include <boost/algorithm/string/replace.hpp> #include <omp.h> #include <cmath> #include <thread> namespace itk { template< class PixelType > TractsToDWIImageFilter< PixelType >::TractsToDWIImageFilter() : m_StatusText("") , m_UseConstantRandSeed(false) , m_RandGen(itk::Statistics::MersenneTwisterRandomVariateGenerator::New()) { m_DoubleInterpolator = itk::LinearInterpolateImageFunction< ItkDoubleImgType, float >::New(); m_NullDir.Fill(0); } template< class PixelType > TractsToDWIImageFilter< PixelType >::~TractsToDWIImageFilter() { } template< class PixelType > TractsToDWIImageFilter< PixelType >::DoubleDwiType::Pointer TractsToDWIImageFilter< PixelType >:: SimulateKspaceAcquisition( std::vector< DoubleDwiType::Pointer >& compartment_images ) { unsigned int numFiberCompartments = m_Parameters.m_FiberModelList.size(); // create slice object ImageRegion<2> sliceRegion; sliceRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]); sliceRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]); Vector< double, 2 > sliceSpacing; sliceSpacing[0] = m_WorkingSpacing[0]; sliceSpacing[1] = m_WorkingSpacing[1]; DoubleDwiType::PixelType nullPix; nullPix.SetSize(compartment_images.at(0)->GetVectorLength()); nullPix.Fill(0.0); auto magnitudeDwiImage = DoubleDwiType::New(); magnitudeDwiImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); magnitudeDwiImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); magnitudeDwiImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); magnitudeDwiImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetVectorLength( compartment_images.at(0)->GetVectorLength() ); magnitudeDwiImage->Allocate(); magnitudeDwiImage->FillBuffer(nullPix); m_PhaseImage = DoubleDwiType::New(); m_PhaseImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_PhaseImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); m_PhaseImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_PhaseImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetVectorLength( compartment_images.at(0)->GetVectorLength() ); m_PhaseImage->Allocate(); m_PhaseImage->FillBuffer(nullPix); m_KspaceImage = DoubleDwiType::New(); m_KspaceImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_KspaceImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); m_KspaceImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_KspaceImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetVectorLength( m_Parameters.m_SignalGen.m_NumberOfCoils ); m_KspaceImage->Allocate(); m_KspaceImage->FillBuffer(nullPix); // calculate coil positions double a = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(0)*m_Parameters.m_SignalGen.m_ImageSpacing[0]; double b = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1)*m_Parameters.m_SignalGen.m_ImageSpacing[1]; double c = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(2)*m_Parameters.m_SignalGen.m_ImageSpacing[2]; double diagonal = sqrt(a*a+b*b)/1000; // image diagonal in m m_CoilPointset = mitk::PointSet::New(); std::vector< itk::Vector<double, 3> > coilPositions; itk::Vector<double, 3> pos; pos.Fill(0.0); pos[1] = -diagonal/2; itk::Vector<double, 3> center; center[0] = a/2-m_Parameters.m_SignalGen.m_ImageSpacing[0]/2; center[1] = b/2-m_Parameters.m_SignalGen.m_ImageSpacing[2]/2; center[2] = c/2-m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; for (unsigned int c=0; c<m_Parameters.m_SignalGen.m_NumberOfCoils; c++) { coilPositions.push_back(pos); m_CoilPointset->InsertPoint(c, pos*1000 + m_Parameters.m_SignalGen.m_ImageOrigin.GetVectorFromOrigin() + center ); double rz = 360.0/m_Parameters.m_SignalGen.m_NumberOfCoils * itk::Math::pi/180; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; pos.SetVnlVector(rotZ*pos.GetVnlVector()); } auto num_slices = compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2); auto num_gradient_volumes = static_cast<int>(compartment_images.at(0)->GetVectorLength()); auto max_threads = omp_get_max_threads(); int out_threads = Math::ceil(std::sqrt(max_threads)); int in_threads = Math::floor(std::sqrt(max_threads)); if (out_threads > num_gradient_volumes) { out_threads = num_gradient_volumes; in_threads = Math::floor(static_cast<float>(max_threads/out_threads)); } PrintToLog("Parallel volumes: " + boost::lexical_cast<std::string>(out_threads), false, true, true); PrintToLog("Threads per slice: " + boost::lexical_cast<std::string>(in_threads), false, true, true); std::list< std::tuple<unsigned int, unsigned int, unsigned int> > spikes; if (m_Parameters.m_Misc.m_DoAddSpikes) for (unsigned int i=0; i<m_Parameters.m_SignalGen.m_Spikes; i++) { // gradient volume and slice index auto spike = std::tuple<unsigned int, unsigned int, unsigned int>( m_RandGen->GetIntegerVariate()%num_gradient_volumes, m_RandGen->GetIntegerVariate()%num_slices, m_RandGen->GetIntegerVariate()%m_Parameters.m_SignalGen.m_NumberOfCoils); spikes.push_back(spike); } PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); unsigned long lastTick = 0; boost::progress_display disp(static_cast<unsigned long>(num_gradient_volumes)*compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2)); #pragma omp parallel for num_threads(out_threads) for (int g=0; g<num_gradient_volumes; g++) { if (this->GetAbortGenerateData()) continue; std::list< std::tuple<unsigned int, unsigned int> > spikeSlice; #pragma omp critical { for (auto spike : spikes) if (std::get<0>(spike) == static_cast<unsigned int>(g)) spikeSlice.push_back(std::tuple<unsigned int, unsigned int>(std::get<1>(spike), std::get<2>(spike))); } for (unsigned int z=0; z<num_slices; z++) { std::vector< Float2DImageType::Pointer > compartment_slices; std::vector< float > t2Vector; std::vector< float > t1Vector; for (unsigned int i=0; i<compartment_images.size(); i++) { DiffusionSignalModel<double>* signalModel; if (i<numFiberCompartments) signalModel = m_Parameters.m_FiberModelList.at(i); else signalModel = m_Parameters.m_NonFiberModelList.at(i-numFiberCompartments); auto slice = Float2DImageType::New(); slice->SetLargestPossibleRegion( 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; y<compartment_images.at(0)->GetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; x<compartment_images.at(0)->GetLargestPossibleRegion().GetSize(0); x++) { Float2DImageType::IndexType index2D; index2D[0]=x; index2D[1]=y; DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; slice->SetPixel(index2D, compartment_images.at(i)->GetPixel(index3D)[g]); } compartment_slices.push_back(slice); t2Vector.push_back(signalModel->GetT2()); t1Vector.push_back(signalModel->GetT1()); } if (this->GetAbortGenerateData()) continue; for (unsigned int c=0; c<m_Parameters.m_SignalGen.m_NumberOfCoils; c++) { int numSpikes = 0; for (auto ss : spikeSlice) if (std::get<0>(ss) == z && std::get<1>(ss) == c) ++numSpikes; // create k-sapce (inverse fourier transform slices) auto idft = itk::KspaceImageFilter< Float2DImageType::PixelType >::New(); idft->SetCompartmentImages(compartment_slices); idft->SetT2(t2Vector); idft->SetT1(t1Vector); if (m_UseConstantRandSeed) { int linear_seed = g + num_gradient_volumes*z + num_gradient_volumes*compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2)*c; idft->SetRandSeed(linear_seed); } idft->SetParameters(&m_Parameters); idft->SetZ((float)z-(float)( compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2) -compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2)%2 ) / 2.0); idft->SetZidx(z); idft->SetCoilPosition(coilPositions.at(c)); idft->SetFiberBundle(m_FiberBundle); idft->SetTranslation(m_Translations.at(g)); idft->SetRotationMatrix(m_RotationsInv.at(g)); idft->SetDiffusionGradientDirection(m_Parameters.m_SignalGen.GetGradientDirection(g)); idft->SetSpikesPerSlice(numSpikes); idft->SetNumberOfThreads(in_threads); idft->Update(); #pragma omp critical if (numSpikes>0) { m_SpikeLog += "Volume " + boost::lexical_cast<std::string>(g) + " Coil " + boost::lexical_cast<std::string>(c) + "\n"; m_SpikeLog += idft->GetSpikeLog(); } Complex2DImageType::Pointer fSlice; fSlice = idft->GetOutput(); // fourier transform slice Complex2DImageType::Pointer newSlice; auto dft = itk::DftImageFilter< Float2DImageType::PixelType >::New(); dft->SetInput(fSlice); dft->SetParameters(m_Parameters); dft->SetNumberOfThreads(in_threads); dft->Update(); newSlice = dft->GetOutput(); // put slice back into channel g for (unsigned int y=0; y<fSlice->GetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; x<fSlice->GetLargestPossibleRegion().GetSize(0); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; Complex2DImageType::IndexType index2D; index2D[0]=x; index2D[1]=y; Complex2DImageType::PixelType cPix = newSlice->GetPixel(index2D); double magn = sqrt(cPix.real()*cPix.real()+cPix.imag()*cPix.imag()); double phase = 0; if (cPix.real()!=0) phase = atan( cPix.imag()/cPix.real() ); DoubleDwiType::PixelType real_pix = m_OutputImagesReal.at(c)->GetPixel(index3D); real_pix[g] = cPix.real(); m_OutputImagesReal.at(c)->SetPixel(index3D, real_pix); DoubleDwiType::PixelType imag_pix = m_OutputImagesImag.at(c)->GetPixel(index3D); imag_pix[g] = cPix.imag(); m_OutputImagesImag.at(c)->SetPixel(index3D, imag_pix); DoubleDwiType::PixelType dwiPix = magnitudeDwiImage->GetPixel(index3D); DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D); if (m_Parameters.m_SignalGen.m_NumberOfCoils>1) { dwiPix[g] += magn*magn; phasePix[g] += phase*phase; } else { dwiPix[g] = magn; phasePix[g] = phase; } //#pragma omp critical { magnitudeDwiImage->SetPixel(index3D, dwiPix); m_PhaseImage->SetPixel(index3D, phasePix); // k-space image if (g==0) { DoubleDwiType::PixelType kspacePix = m_KspaceImage->GetPixel(index3D); kspacePix[c] = idft->GetKSpaceImage()->GetPixel(index2D); m_KspaceImage->SetPixel(index3D, kspacePix); } } } } if (m_Parameters.m_SignalGen.m_NumberOfCoils>1) { for (int y=0; y<static_cast<int>(magnitudeDwiImage->GetLargestPossibleRegion().GetSize(1)); y++) for (int x=0; x<static_cast<int>(magnitudeDwiImage->GetLargestPossibleRegion().GetSize(0)); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; DoubleDwiType::PixelType magPix = magnitudeDwiImage->GetPixel(index3D); magPix[g] = sqrt(magPix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils); DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D); phasePix[g] = sqrt(phasePix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils); //#pragma omp critical { magnitudeDwiImage->SetPixel(index3D, magPix); m_PhaseImage->SetPixel(index3D, phasePix); } } } ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned long tick = 0; tick<(newTick-lastTick); tick++) PrintToLog("*", false, false, false); lastTick = newTick; } } PrintToLog("\n", false); return magnitudeDwiImage; } template< class PixelType > TractsToDWIImageFilter< PixelType >::ItkDoubleImgType::Pointer TractsToDWIImageFilter< PixelType >:: NormalizeInsideMask(ItkDoubleImgType::Pointer image) { double max = itk::NumericTraits< double >::min(); double min = itk::NumericTraits< double >::max(); itk::ImageRegionIterator< ItkDoubleImgType > it(image, image->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { if (m_Parameters.m_SignalGen.m_MaskImage.IsNotNull() && m_Parameters.m_SignalGen.m_MaskImage->GetPixel(it.GetIndex())<=0) { it.Set(0.0); ++it; continue; } if (it.Get()>max) max = it.Get(); if (it.Get()<min) min = it.Get(); ++it; } auto scaler = itk::ShiftScaleImageFilter< ItkDoubleImgType, ItkDoubleImgType >::New(); scaler->SetInput(image); scaler->SetShift(-min); scaler->SetScale(1.0/(max-min)); scaler->Update(); return scaler->GetOutput(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::CheckVolumeFractionImages() { m_UseRelativeNonFiberVolumeFractions = false; // check for fiber volume fraction maps unsigned int fibVolImages = 0; for (std::size_t i=0; i<m_Parameters.m_FiberModelList.size(); i++) { if (m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage().IsNotNull()) { PrintToLog("Using volume fraction map for fiber compartment " + boost::lexical_cast<std::string>(i+1), false); fibVolImages++; } } // check for non-fiber volume fraction maps unsigned int nonfibVolImages = 0; for (std::size_t i=0; i<m_Parameters.m_NonFiberModelList.size(); i++) { if (m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage().IsNotNull()) { PrintToLog("Using volume fraction map for non-fiber compartment " + boost::lexical_cast<std::string>(i+1), false); nonfibVolImages++; } } // not all fiber compartments are using volume fraction maps // --> non-fiber volume fractions are assumed to be relative to the // non-fiber volume and not absolute voxel-volume fractions. // this means if two non-fiber compartments are used but only one of them // has an associated volume fraction map, the repesctive other volume fraction map // can be determined as inverse (1-val) of the present volume fraction map- if ( fibVolImages<m_Parameters.m_FiberModelList.size() && nonfibVolImages==1 && m_Parameters.m_NonFiberModelList.size()==2) { PrintToLog("Calculating missing non-fiber volume fraction image by inverting the other.\n" "Assuming non-fiber volume fraction images to contain values relative to the" " remaining non-fiber volume, not absolute values.", false); auto inverter = itk::InvertIntensityImageFilter< ItkDoubleImgType, ItkDoubleImgType >::New(); inverter->SetMaximum(1.0); if ( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNull() && m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNotNull() ) { // m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage( // NormalizeInsideMask( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() ) ); inverter->SetInput( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() ); inverter->Update(); m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage(inverter->GetOutput()); } else if ( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNull() && m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNotNull() ) { // m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage( // NormalizeInsideMask( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() ) ); inverter->SetInput( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() ); inverter->Update(); m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage(inverter->GetOutput()); } else { itkExceptionMacro("Something went wrong in automatically calculating the missing non-fiber volume fraction image!" " Did you use two non fiber compartments but only one volume fraction image?" " Then it should work and this error is really strange."); } m_UseRelativeNonFiberVolumeFractions = true; nonfibVolImages++; } // Up to two fiber compartments are allowed without volume fraction maps since the volume fractions can then be determined automatically if (m_Parameters.m_FiberModelList.size()>2 && fibVolImages!=m_Parameters.m_FiberModelList.size()) itkExceptionMacro("More than two fiber compartment selected but no corresponding volume fraction maps set!"); // One non-fiber compartment is allowed without volume fraction map since the volume fraction can then be determined automatically if (m_Parameters.m_NonFiberModelList.size()>1 && nonfibVolImages!=m_Parameters.m_NonFiberModelList.size()) itkExceptionMacro("More than one non-fiber compartment selected but no volume fraction maps set!"); if (fibVolImages<m_Parameters.m_FiberModelList.size() && nonfibVolImages>0) { PrintToLog("Not all fiber compartments are using an associated volume fraction image.\n" "Assuming non-fiber volume fraction images to contain values relative to the" " remaining non-fiber volume, not absolute values.", false); m_UseRelativeNonFiberVolumeFractions = true; // mitk::LocaleSwitch localeSwitch("C"); // itk::ImageFileWriter<ItkDoubleImgType>::Pointer wr = itk::ImageFileWriter<ItkDoubleImgType>::New(); // wr->SetInput(m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage()); // wr->SetFileName("/local/volumefraction.nrrd"); // wr->Update(); } // initialize the images that store the output volume fraction of each compartment m_VolumeFractions.clear(); for (std::size_t i=0; i<m_Parameters.m_FiberModelList.size()+m_Parameters.m_NonFiberModelList.size(); i++) { auto doubleImg = ItkDoubleImgType::New(); doubleImg->SetSpacing( m_WorkingSpacing ); doubleImg->SetOrigin( m_WorkingOrigin ); doubleImg->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); doubleImg->SetLargestPossibleRegion( m_WorkingImageRegion ); doubleImg->SetBufferedRegion( m_WorkingImageRegion ); doubleImg->SetRequestedRegion( m_WorkingImageRegion ); doubleImg->Allocate(); doubleImg->FillBuffer(0); m_VolumeFractions.push_back(doubleImg); } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::InitializeData() { m_Rotations.clear(); m_Translations.clear(); m_MotionLog = ""; m_SpikeLog = ""; // initialize output dwi image m_Parameters.m_SignalGen.m_CroppedRegion = m_Parameters.m_SignalGen.m_ImageRegion; if (m_Parameters.m_Misc.m_DoAddAliasing) m_Parameters.m_SignalGen.m_CroppedRegion.SetSize( 1, m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(1) *m_Parameters.m_SignalGen.m_CroppingFactor); itk::Point<double,3> shiftedOrigin = m_Parameters.m_SignalGen.m_ImageOrigin; shiftedOrigin[1] += (m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1) -m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(1))*m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; m_OutputImage = OutputImageType::New(); m_OutputImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_OutputImage->SetOrigin( shiftedOrigin ); m_OutputImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_OutputImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); m_OutputImage->Allocate(); typename OutputImageType::PixelType temp; temp.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); temp.Fill(0.0); m_OutputImage->FillBuffer(temp); PrintToLog("Output image spacing: [" + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_ImageSpacing[0]) + "," + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_ImageSpacing[1]) + "," + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_ImageSpacing[2]) + "]", false); PrintToLog("Output image size: [" + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(0)) + "," + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(1)) + "," + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(2)) + "]", false); // images containing real and imaginary part of the dMRI signal for each coil m_OutputImagesReal.clear(); m_OutputImagesImag.clear(); for (unsigned int i=0; i<m_Parameters.m_SignalGen.m_NumberOfCoils; ++i) { typename DoubleDwiType::Pointer outputImageReal = DoubleDwiType::New(); outputImageReal->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); outputImageReal->SetOrigin( shiftedOrigin ); outputImageReal->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); outputImageReal->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageReal->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageReal->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageReal->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); outputImageReal->Allocate(); outputImageReal->FillBuffer(temp); m_OutputImagesReal.push_back(outputImageReal); typename DoubleDwiType::Pointer outputImageImag = DoubleDwiType::New(); outputImageImag->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); outputImageImag->SetOrigin( shiftedOrigin ); outputImageImag->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); outputImageImag->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageImag->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageImag->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageImag->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); outputImageImag->Allocate(); outputImageImag->FillBuffer(temp); m_OutputImagesImag.push_back(outputImageImag); } // Apply in-plane upsampling for Gibbs ringing artifact double upsampling = 1; if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging && m_Parameters.m_SignalGen.m_ZeroRinging==0) upsampling = 2; m_WorkingSpacing = m_Parameters.m_SignalGen.m_ImageSpacing; m_WorkingSpacing[0] /= upsampling; m_WorkingSpacing[1] /= upsampling; m_WorkingImageRegion = m_Parameters.m_SignalGen.m_ImageRegion; m_WorkingImageRegion.SetSize(0, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[0]*upsampling); m_WorkingImageRegion.SetSize(1, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[1]*upsampling); m_WorkingOrigin = m_Parameters.m_SignalGen.m_ImageOrigin; m_WorkingOrigin[0] -= m_Parameters.m_SignalGen.m_ImageSpacing[0]/2; m_WorkingOrigin[0] += m_WorkingSpacing[0]/2; m_WorkingOrigin[1] -= m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; m_WorkingOrigin[1] += m_WorkingSpacing[1]/2; m_WorkingOrigin[2] -= m_Parameters.m_SignalGen.m_ImageSpacing[2]/2; m_WorkingOrigin[2] += m_WorkingSpacing[2]/2; m_VoxelVolume = m_WorkingSpacing[0]*m_WorkingSpacing[1]*m_WorkingSpacing[2]; PrintToLog("Working image spacing: [" + boost::lexical_cast<std::string>(m_WorkingSpacing[0]) + "," + boost::lexical_cast<std::string>(m_WorkingSpacing[1]) + "," + boost::lexical_cast<std::string>(m_WorkingSpacing[2]) + "]", false); PrintToLog("Working image size: [" + boost::lexical_cast<std::string>(m_WorkingImageRegion.GetSize(0)) + "," + boost::lexical_cast<std::string>(m_WorkingImageRegion.GetSize(1)) + "," + boost::lexical_cast<std::string>(m_WorkingImageRegion.GetSize(2)) + "]", false); // generate double images to store the individual compartment signals m_CompartmentImages.clear(); int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); for (int i=0; i<numFiberCompartments+numNonFiberCompartments; i++) { auto doubleDwi = DoubleDwiType::New(); doubleDwi->SetSpacing( m_WorkingSpacing ); doubleDwi->SetOrigin( m_WorkingOrigin ); doubleDwi->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); doubleDwi->SetLargestPossibleRegion( m_WorkingImageRegion ); doubleDwi->SetBufferedRegion( m_WorkingImageRegion ); doubleDwi->SetRequestedRegion( m_WorkingImageRegion ); doubleDwi->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); doubleDwi->Allocate(); DoubleDwiType::PixelType pix; pix.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); pix.Fill(0.0); doubleDwi->FillBuffer(pix); m_CompartmentImages.push_back(doubleDwi); } if (m_FiberBundle.IsNull() && m_InputImage.IsNotNull()) { m_CompartmentImages.clear(); m_Parameters.m_SignalGen.m_DoAddMotion = false; m_Parameters.m_SignalGen.m_DoSimulateRelaxation = false; PrintToLog("Simulating acquisition for input diffusion-weighted image.", false); auto caster = itk::CastImageFilter< OutputImageType, DoubleDwiType >::New(); caster->SetInput(m_InputImage); caster->Update(); if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging && m_Parameters.m_SignalGen.m_ZeroRinging==0) { PrintToLog("Upsampling input diffusion-weighted image for Gibbs ringing simulation.", false); auto resampler = itk::ResampleDwiImageFilter< double >::New(); resampler->SetInput(caster->GetOutput()); itk::Vector< double, 3 > samplingFactor; samplingFactor[0] = upsampling; samplingFactor[1] = upsampling; samplingFactor[2] = 1; resampler->SetSamplingFactor(samplingFactor); resampler->SetInterpolation(itk::ResampleDwiImageFilter< double >::Interpolate_WindowedSinc); resampler->Update(); m_CompartmentImages.push_back(resampler->GetOutput()); } else m_CompartmentImages.push_back(caster->GetOutput()); VectorType translation; translation.Fill(0.0); MatrixType rotation; rotation.SetIdentity(); for (unsigned int g=0; g<m_Parameters.m_SignalGen.GetNumVolumes(); g++) { m_Rotations.push_back(rotation); m_RotationsInv.push_back(rotation); m_Translations.push_back(translation); } } // resample mask image and frequency map to fit upsampled geometry if (m_Parameters.m_SignalGen.m_MaskImage.IsNotNull() && m_Parameters.m_SignalGen.m_MaskImage->GetLargestPossibleRegion()!=m_WorkingImageRegion) { PrintToLog("Resampling tissue mask", false); // rescale mask image (otherwise there are problems with the resampling) auto rescaler = itk::RescaleIntensityImageFilter<ItkUcharImgType,ItkUcharImgType>::New(); rescaler->SetInput(0,m_Parameters.m_SignalGen.m_MaskImage); rescaler->SetOutputMaximum(100); rescaler->SetOutputMinimum(0); rescaler->Update(); // resample mask image auto resampler = itk::ResampleImageFilter<ItkUcharImgType, ItkUcharImgType>::New(); resampler->SetInput(rescaler->GetOutput()); resampler->SetSize(m_WorkingImageRegion.GetSize()); resampler->SetOutputSpacing(m_WorkingSpacing); resampler->SetOutputOrigin(m_WorkingOrigin); resampler->SetOutputDirection(m_Parameters.m_SignalGen.m_ImageDirection); resampler->SetOutputStartIndex ( m_WorkingImageRegion.GetIndex() ); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction<ItkUcharImgType, double>::New(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); m_Parameters.m_SignalGen.m_MaskImage = resampler->GetOutput(); } // resample frequency map if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull() && m_Parameters.m_SignalGen.m_FrequencyMap->GetLargestPossibleRegion()!=m_WorkingImageRegion) { PrintToLog("Resampling frequency map", false); auto resampler = itk::ResampleImageFilter<ItkFloatImgType, ItkFloatImgType>::New(); resampler->SetInput(m_Parameters.m_SignalGen.m_FrequencyMap); resampler->SetSize(m_WorkingImageRegion.GetSize()); resampler->SetOutputSpacing(m_WorkingSpacing); resampler->SetOutputOrigin(m_WorkingOrigin); resampler->SetOutputDirection(m_Parameters.m_SignalGen.m_ImageDirection); resampler->SetOutputStartIndex ( m_WorkingImageRegion.GetIndex() ); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction<ItkFloatImgType, double>::New(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); m_Parameters.m_SignalGen.m_FrequencyMap = resampler->GetOutput(); } m_MaskImageSet = true; if (m_Parameters.m_SignalGen.m_MaskImage.IsNull()) { // no input tissue mask is set -> create default PrintToLog("No tissue mask set", false); m_Parameters.m_SignalGen.m_MaskImage = ItkUcharImgType::New(); m_Parameters.m_SignalGen.m_MaskImage->SetSpacing( m_WorkingSpacing ); m_Parameters.m_SignalGen.m_MaskImage->SetOrigin( m_WorkingOrigin ); m_Parameters.m_SignalGen.m_MaskImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_Parameters.m_SignalGen.m_MaskImage->SetLargestPossibleRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->SetBufferedRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->SetRequestedRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->Allocate(); m_Parameters.m_SignalGen.m_MaskImage->FillBuffer(100); m_MaskImageSet = false; } else { PrintToLog("Using tissue mask", false); } if (m_Parameters.m_SignalGen.m_DoAddMotion) { if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { PrintToLog("Random motion artifacts:", false); PrintToLog("Maximum rotation: +/-" + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_Rotation) + "°", false); PrintToLog("Maximum translation: +/-" + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_Translation) + "mm", false); } else { PrintToLog("Linear motion artifacts:", false); PrintToLog("Maximum rotation: " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_Rotation) + "°", false); PrintToLog("Maximum translation: " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_Translation) + "mm", false); } } if ( m_Parameters.m_SignalGen.m_MotionVolumes.empty() ) { // no motion in first volume m_Parameters.m_SignalGen.m_MotionVolumes.push_back(false); // motion in all other volumes while ( m_Parameters.m_SignalGen.m_MotionVolumes.size() < m_Parameters.m_SignalGen.GetNumVolumes() ) { m_Parameters.m_SignalGen.m_MotionVolumes.push_back(true); } } // we need to know for every volume if there is motion. if this information is missing, then set corresponding fal to false while ( m_Parameters.m_SignalGen.m_MotionVolumes.size()<m_Parameters.m_SignalGen.GetNumVolumes() ) { m_Parameters.m_SignalGen.m_MotionVolumes.push_back(false); } m_NumMotionVolumes = 0; for (unsigned int i=0; i<m_Parameters.m_SignalGen.GetNumVolumes(); ++i) { if (m_Parameters.m_SignalGen.m_MotionVolumes[i]) ++m_NumMotionVolumes; } m_MotionCounter = 0; // creat image to hold transformed mask (motion artifact) m_TransformedMaskImage = ItkUcharImgType::New(); auto duplicator = itk::ImageDuplicator<ItkUcharImgType>::New(); duplicator->SetInputImage(m_Parameters.m_SignalGen.m_MaskImage); duplicator->Update(); m_TransformedMaskImage = duplicator->GetOutput(); // second upsampling needed for motion artifacts ImageRegion<3> upsampledImageRegion = m_WorkingImageRegion; VectorType upsampledSpacing = m_WorkingSpacing; upsampledSpacing[0] /= 4; upsampledSpacing[1] /= 4; upsampledSpacing[2] /= 4; upsampledImageRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]*4); upsampledImageRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]*4); upsampledImageRegion.SetSize(2, m_WorkingImageRegion.GetSize()[2]*4); itk::Point<double,3> upsampledOrigin = m_WorkingOrigin; upsampledOrigin[0] -= m_WorkingSpacing[0]/2; upsampledOrigin[0] += upsampledSpacing[0]/2; upsampledOrigin[1] -= m_WorkingSpacing[1]/2; upsampledOrigin[1] += upsampledSpacing[1]/2; upsampledOrigin[2] -= m_WorkingSpacing[2]/2; upsampledOrigin[2] += upsampledSpacing[2]/2; m_UpsampledMaskImage = ItkUcharImgType::New(); auto upsampler = itk::ResampleImageFilter<ItkUcharImgType, ItkUcharImgType>::New(); upsampler->SetInput(m_Parameters.m_SignalGen.m_MaskImage); upsampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_MaskImage); upsampler->SetSize(upsampledImageRegion.GetSize()); upsampler->SetOutputSpacing(upsampledSpacing); upsampler->SetOutputOrigin(upsampledOrigin); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction<ItkUcharImgType, double>::New(); upsampler->SetInterpolator(nn_interpolator); upsampler->Update(); m_UpsampledMaskImage = upsampler->GetOutput(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::InitializeFiberData() { m_mmRadius = m_Parameters.m_SignalGen.m_AxonRadius/1000; auto caster = itk::CastImageFilter< itk::Image<unsigned char, 3>, itk::Image<double, 3> >::New(); caster->SetInput(m_TransformedMaskImage); caster->Update(); vtkSmartPointer<vtkFloatArray> weights = m_FiberBundle->GetFiberWeights(); float mean_weight = 0; for (int i=0; i<weights->GetSize(); i++) mean_weight += weights->GetValue(i); mean_weight /= weights->GetSize(); if (mean_weight>0.000001) for (int i=0; i<weights->GetSize(); i++) m_FiberBundle->SetFiberWeight(i, weights->GetValue(i)/mean_weight); else PrintToLog("\nWarning: streamlines have VERY low weights. Average weight: " + boost::lexical_cast<std::string>(mean_weight) + ". Possible source of calculation errors.", false, true, true); auto density_calculator = itk::TractDensityImageFilter< itk::Image<double, 3> >::New(); density_calculator->SetFiberBundle(m_FiberBundle); density_calculator->SetInputImage(caster->GetOutput()); density_calculator->SetBinaryOutput(false); density_calculator->SetUseImageGeometry(true); density_calculator->SetOutputAbsoluteValues(true); density_calculator->Update(); double max_density = density_calculator->GetMaxDensity(); double voxel_volume = m_WorkingSpacing[0]*m_WorkingSpacing[1]*m_WorkingSpacing[2]; if (m_mmRadius>0) { std::stringstream stream; stream << std::fixed << setprecision(2) << itk::Math::pi*m_mmRadius*m_mmRadius*max_density; std::string s = stream.str(); PrintToLog("\nMax. fiber volume: " + s + "mm².", false, true, true); { double full_radius = 1000*std::sqrt(voxel_volume/(max_density*itk::Math::pi)); std::stringstream stream; stream << std::fixed << setprecision(2) << full_radius; std::string s = stream.str(); PrintToLog("\nA full fiber voxel corresponds to a fiber radius of ~" + s + "µm, given the current fiber configuration.", false, true, true); } } else { m_mmRadius = std::sqrt(voxel_volume/(max_density*itk::Math::pi)); std::stringstream stream; stream << std::fixed << setprecision(2) << m_mmRadius*1000; std::string s = stream.str(); PrintToLog("\nSetting fiber radius to " + s + "µm to obtain full voxel.", false, true, true); } // a second fiber bundle is needed to store the transformed version of the m_FiberBundleWorkingCopy m_FiberBundleTransformed = m_FiberBundle->GetDeepCopy(); } template< class PixelType > bool TractsToDWIImageFilter< PixelType >::PrepareLogFile() { if(m_Logfile.is_open()) m_Logfile.close(); std::string filePath; std::string fileName; // Get directory name: if (m_Parameters.m_Misc.m_OutputPath.size() > 0) { filePath = m_Parameters.m_Misc.m_OutputPath; if( *(--(filePath.cend())) != '/') { filePath.push_back('/'); } } else { filePath = mitk::IOUtil::GetTempPath() + '/'; } // check if directory exists, else use /tmp/: if( itksys::SystemTools::FileIsDirectory( filePath ) ) { while( *(--(filePath.cend())) == '/') { filePath.pop_back(); } filePath = filePath + '/'; } else { filePath = mitk::IOUtil::GetTempPath() + '/'; } // Get file name: if( ! m_Parameters.m_Misc.m_ResultNode->GetName().empty() ) { fileName = m_Parameters.m_Misc.m_ResultNode->GetName(); } else { fileName = ""; } if( ! m_Parameters.m_Misc.m_OutputPrefix.empty() ) { fileName = m_Parameters.m_Misc.m_OutputPrefix + fileName; } else { fileName = "fiberfox"; } // check if file already exists and DO NOT overwrite existing files: std::string NameTest = fileName; int c = 0; while( itksys::SystemTools::FileExists( filePath + '/' + fileName + ".log" ) && c <= std::numeric_limits<int>::max() ) { fileName = NameTest + "_" + boost::lexical_cast<std::string>(c); ++c; } try { m_Logfile.open( ( filePath + '/' + fileName + ".log" ).c_str() ); } catch (const std::ios_base::failure &fail) { MITK_ERROR << "itkTractsToDWIImageFilter.cpp: Exception " << fail.what() << " while trying to open file" << filePath << '/' << fileName << ".log"; return false; } if ( m_Logfile.is_open() ) { PrintToLog( "Logfile: " + filePath + '/' + fileName + ".log", false ); return true; } else { m_StatusText += "Logfile could not be opened!\n"; MITK_ERROR << "itkTractsToDWIImageFilter.cpp: Logfile could not be opened!"; return false; } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::GenerateData() { PrintToLog("\n**********************************************", false); // prepare logfile if ( ! PrepareLogFile() ) { this->SetAbortGenerateData( true ); return; } PrintToLog("Starting Fiberfox dMRI simulation"); m_TimeProbe.Start(); // check input data if (m_FiberBundle.IsNull() && m_InputImage.IsNull()) itkExceptionMacro("Input fiber bundle and input diffusion-weighted image is nullptr!"); if (m_Parameters.m_FiberModelList.empty() && m_InputImage.IsNull()) itkExceptionMacro("No diffusion model for fiber compartments defined and input diffusion-weighted" " image is nullptr! At least one fiber compartment is necessary to simulate diffusion."); if (m_Parameters.m_NonFiberModelList.empty() && m_InputImage.IsNull()) itkExceptionMacro("No diffusion model for non-fiber compartments defined and input diffusion-weighted" " image is nullptr! At least one non-fiber compartment is necessary to simulate diffusion."); if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) // no partial volume? remove all but first fiber compartment while (m_Parameters.m_FiberModelList.size()>1) m_Parameters.m_FiberModelList.pop_back(); if (!m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition) // No upsampling of input image needed if no k-space simulation is performed m_Parameters.m_SignalGen.m_DoAddGibbsRinging = false; if (m_UseConstantRandSeed) // always generate the same random numbers? m_RandGen->SetSeed(0); else m_RandGen->SetSeed(); InitializeData(); if ( m_FiberBundle.IsNotNull() ) // if no fiber bundle is found, we directly proceed to the k-space acquisition simulation { CheckVolumeFractionImages(); InitializeFiberData(); int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); double maxVolume = 0; unsigned long lastTick = 0; int signalModelSeed = m_RandGen->GetIntegerVariate(); PrintToLog("\n", false, false); PrintToLog("Generating " + boost::lexical_cast<std::string>(numFiberCompartments+numNonFiberCompartments) + "-compartment diffusion-weighted signal."); std::vector< int > bVals = m_Parameters.m_SignalGen.GetBvalues(); PrintToLog("b-values: ", false, false, true); for (auto v : bVals) PrintToLog(boost::lexical_cast<std::string>(v) + " ", false, false, true); PrintToLog("\nVolumes: " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.GetNumVolumes()), false, true, true); PrintToLog("\n", false, false, true); PrintToLog("\n", false, false, true); unsigned int image_size_x = m_WorkingImageRegion.GetSize(0); unsigned int region_size_y = m_WorkingImageRegion.GetSize(1); unsigned int num_gradients = m_Parameters.m_SignalGen.GetNumVolumes(); int numFibers = m_FiberBundle->GetNumFibers(); boost::progress_display disp(numFibers*num_gradients); if (m_FiberBundle->GetMeanFiberLength()<5.0) omp_set_num_threads(2); PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); for (unsigned int g=0; g<num_gradients; ++g) { // move fibers SimulateMotion(g); // Set signal model random generator seeds to get same configuration in each voxel for (std::size_t i=0; i<m_Parameters.m_FiberModelList.size(); i++) m_Parameters.m_FiberModelList.at(i)->SetSeed(signalModelSeed); for (std::size_t i=0; i<m_Parameters.m_NonFiberModelList.size(); i++) m_Parameters.m_NonFiberModelList.at(i)->SetSeed(signalModelSeed); // storing voxel-wise intra-axonal volume in mm³ auto intraAxonalVolumeImage = ItkDoubleImgType::New(); intraAxonalVolumeImage->SetSpacing( m_WorkingSpacing ); intraAxonalVolumeImage->SetOrigin( m_WorkingOrigin ); intraAxonalVolumeImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); intraAxonalVolumeImage->SetLargestPossibleRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetBufferedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetRequestedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->Allocate(); intraAxonalVolumeImage->FillBuffer(0); maxVolume = 0; double* intraAxBuffer = intraAxonalVolumeImage->GetBufferPointer(); if (this->GetAbortGenerateData()) continue; vtkPolyData* fiberPolyData = m_FiberBundleTransformed->GetFiberPolyData(); // generate fiber signal (if there are any fiber models present) if (!m_Parameters.m_FiberModelList.empty()) { std::vector< double* > buffers; for (unsigned int i=0; i<m_CompartmentImages.size(); ++i) buffers.push_back(m_CompartmentImages.at(i)->GetBufferPointer()); #pragma omp parallel for for( int i=0; i<numFibers; ++i ) { if (this->GetAbortGenerateData()) continue; float fiberWeight = m_FiberBundleTransformed->GetFiberWeight(i); int numPoints = -1; std::vector< itk::Vector<double, 3> > points_copy; #pragma omp critical { vtkCell* cell = fiberPolyData->GetCell(i); numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; j<numPoints; j++) points_copy.push_back(GetItkVector(points->GetPoint(j))); } if (numPoints<2) continue; double seg_volume = fiberWeight*itk::Math::pi*m_mmRadius*m_mmRadius; for( int j=0; j<numPoints - 1; ++j) { if (this->GetAbortGenerateData()) { j=numPoints; continue; } itk::Vector<double> v = points_copy.at(j); itk::Vector<double, 3> dir = points_copy.at(j+1)-v; if ( dir.GetSquaredNorm()<0.0001 || dir[0]!=dir[0] || dir[1]!=dir[1] || dir[2]!=dir[2] ) continue; dir.Normalize(); itk::Point<float, 3> startVertex = points_copy.at(j); itk::Index<3> startIndex; itk::ContinuousIndex<float, 3> startIndexCont; m_TransformedMaskImage->TransformPhysicalPointToIndex(startVertex, startIndex); m_TransformedMaskImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); itk::Point<float, 3> endVertex = points_copy.at(j+1); itk::Index<3> endIndex; itk::ContinuousIndex<float, 3> endIndexCont; m_TransformedMaskImage->TransformPhysicalPointToIndex(endVertex, endIndex); m_TransformedMaskImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(m_WorkingSpacing, startIndex, endIndex, startIndexCont, endIndexCont); // generate signal for each fiber compartment for (int k=0; k<numFiberCompartments; ++k) { double signal_add = m_Parameters.m_FiberModelList[k]->SimulateMeasurement(g, dir)*seg_volume; for (std::pair< itk::Index<3>, double > seg : segments) { if (!m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(seg.first) || m_TransformedMaskImage->GetPixel(seg.first)<=0) continue; double seg_signal = seg.second*signal_add; unsigned int linear_index = g + num_gradients*seg.first[0] + num_gradients*image_size_x*seg.first[1] + num_gradients*image_size_x*region_size_y*seg.first[2]; // update dMRI volume #pragma omp atomic buffers[k][linear_index] += seg_signal; // update fiber volume image if (k==0) { linear_index = seg.first[0] + image_size_x*seg.first[1] + image_size_x*region_size_y*seg.first[2]; #pragma omp atomic intraAxBuffer[linear_index] += seg.second*seg_volume; double vol = intraAxBuffer[linear_index]; if (vol>maxVolume) { maxVolume = vol; } } } } } #pragma omp critical { // progress report ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned int tick = 0; tick<(newTick-lastTick); ++tick) PrintToLog("*", false, false, false); lastTick = newTick; } } } // axon radius not manually defined --> set fullest voxel (maxVolume) to full fiber voxel double density_correctiony_global = 1.0; if (m_Parameters.m_SignalGen.m_AxonRadius<0.0001) density_correctiony_global = m_VoxelVolume/maxVolume; // generate non-fiber signal ImageRegionIterator<ItkUcharImgType> it3(m_TransformedMaskImage, m_TransformedMaskImage->GetLargestPossibleRegion()); while(!it3.IsAtEnd()) { if (it3.Get()>0) { DoubleDwiType::IndexType index = it3.GetIndex(); double iAxVolume = intraAxonalVolumeImage->GetPixel(index); // get non-transformed point (remove headmotion tranformation) // this point lives in the volume fraction image space itk::Point<float, 3> volume_fraction_point; if ( m_Parameters.m_SignalGen.m_DoAddMotion ) volume_fraction_point = GetMovedPoint(index, false); else m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, volume_fraction_point); if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) { if (iAxVolume>0.0001) // scale fiber compartment to voxel { DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); pix[g] *= m_VoxelVolume/iAxVolume; m_CompartmentImages.at(0)->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(0)->SetPixel(index, 1); } else { DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); pix[g] = 0; m_CompartmentImages.at(0)->SetPixel(index, pix); SimulateExtraAxonalSignal(index, volume_fraction_point, 0, g); } } else { // manually defined axon radius and voxel overflow --> rescale to voxel volume if ( m_Parameters.m_SignalGen.m_AxonRadius>=0.0001 && iAxVolume>m_VoxelVolume ) { for (int i=0; i<numFiberCompartments; ++i) { DoubleDwiType::PixelType pix = m_CompartmentImages.at(i)->GetPixel(index); pix[g] *= m_VoxelVolume/iAxVolume; m_CompartmentImages.at(i)->SetPixel(index, pix); } iAxVolume = m_VoxelVolume; } // if volume fraction image is set use it, otherwise use global scaling factor double density_correction_voxel = density_correctiony_global; if ( m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()!=nullptr && iAxVolume>0.0001 ) { m_DoubleInterpolator->SetInputImage(m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()); double volume_fraction = mitk::imv::GetImageValue<double>(volume_fraction_point, true, m_DoubleInterpolator); if (volume_fraction<0) mitkThrow() << "Volume fraction image (index 1) contains negative values (intra-axonal compartment)!"; density_correction_voxel = m_VoxelVolume*volume_fraction/iAxVolume; // remove iAxVolume sclaing and scale to volume_fraction } else if (m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()!=nullptr) density_correction_voxel = 0.0; // adjust intra-axonal compartment volume by density correction factor DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); pix[g] *= density_correction_voxel; m_CompartmentImages.at(0)->SetPixel(index, pix); // normalize remaining fiber volume fractions (they are rescaled in SimulateExtraAxonalSignal) if (iAxVolume>0.0001) { for (int i=1; i<numFiberCompartments; i++) { DoubleDwiType::PixelType pix = m_CompartmentImages.at(i)->GetPixel(index); pix[g] /= iAxVolume; m_CompartmentImages.at(i)->SetPixel(index, pix); } } else { for (int i=1; i<numFiberCompartments; i++) { DoubleDwiType::PixelType pix = m_CompartmentImages.at(i)->GetPixel(index); pix[g] = 0; m_CompartmentImages.at(i)->SetPixel(index, pix); } } iAxVolume = density_correction_voxel*iAxVolume; // new intra-axonal volume = old intra-axonal volume * correction factor // simulate other compartments SimulateExtraAxonalSignal(index, volume_fraction_point, iAxVolume, g); } } ++it3; } } PrintToLog("\n", false); } if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } DoubleDwiType::Pointer doubleOutImage; double signalScale = m_Parameters.m_SignalGen.m_SignalScale; if ( m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition ) // do k-space stuff { PrintToLog("\n", false, false); PrintToLog("Simulating k-space acquisition using " +boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_NumberOfCoils) +" coil(s)"); switch (m_Parameters.m_SignalGen.m_AcquisitionType) { case SignalGenerationParameters::SingleShotEpi: { PrintToLog("Acquisition type: single shot EPI", false); break; } - case SignalGenerationParameters::SpinEcho: + case SignalGenerationParameters::ConventionalSpinEcho: { PrintToLog("Acquisition type: classic spin echo with cartesian k-space trajectory", false); break; } default: { PrintToLog("Acquisition type: single shot EPI", false); break; } } if(m_Parameters.m_SignalGen.m_tInv>0) PrintToLog("Using inversion pulse with TI " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_tInv) + "ms", false); if (m_Parameters.m_SignalGen.m_DoSimulateRelaxation) PrintToLog("Simulating signal relaxation", false); if (m_Parameters.m_SignalGen.m_NoiseVariance>0 && m_Parameters.m_Misc.m_DoAddNoise) PrintToLog("Simulating complex Gaussian noise: " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_NoiseVariance), false); if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull() && m_Parameters.m_Misc.m_DoAddDistortions) PrintToLog("Simulating distortions", false); if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) { if (m_Parameters.m_SignalGen.m_ZeroRinging > 0) PrintToLog("Simulating ringing artifacts by zeroing " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_ZeroRinging) + "% of k-space frequencies", false); else PrintToLog("Simulating ringing artifacts by cropping high resolution inputs during k-space simulation", false); } if (m_Parameters.m_Misc.m_DoAddEddyCurrents && m_Parameters.m_SignalGen.m_EddyStrength>0) PrintToLog("Simulating eddy currents: " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_EddyStrength), false); if (m_Parameters.m_Misc.m_DoAddSpikes && m_Parameters.m_SignalGen.m_Spikes>0) PrintToLog("Simulating spikes: " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_Spikes), false); if (m_Parameters.m_Misc.m_DoAddAliasing && m_Parameters.m_SignalGen.m_CroppingFactor<1.0) PrintToLog("Simulating aliasing: " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_CroppingFactor), false); if (m_Parameters.m_Misc.m_DoAddGhosts && m_Parameters.m_SignalGen.m_KspaceLineOffset>0) PrintToLog("Simulating ghosts: " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_KspaceLineOffset), false); doubleOutImage = SimulateKspaceAcquisition(m_CompartmentImages); signalScale = 1; // already scaled in SimulateKspaceAcquisition() } else // don't do k-space stuff, just sum compartments { PrintToLog("Summing compartments"); doubleOutImage = m_CompartmentImages.at(0); for (unsigned int i=1; i<m_CompartmentImages.size(); i++) { auto adder = itk::AddImageFilter< DoubleDwiType, DoubleDwiType, DoubleDwiType>::New(); adder->SetInput1(doubleOutImage); adder->SetInput2(m_CompartmentImages.at(i)); adder->Update(); doubleOutImage = adder->GetOutput(); } } if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } PrintToLog("Finalizing image"); if (m_Parameters.m_SignalGen.m_DoAddDrift && m_Parameters.m_SignalGen.m_Drift>0.0) PrintToLog("Adding signal drift: " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_Drift), false); if (signalScale>1) PrintToLog("Scaling signal", false); if (m_Parameters.m_NoiseModel) PrintToLog("Adding noise: " + boost::lexical_cast<std::string>(m_Parameters.m_SignalGen.m_NoiseVariance), false); unsigned int window = 0; unsigned int min = itk::NumericTraits<unsigned int>::max(); ImageRegionIterator<OutputImageType> it4 (m_OutputImage, m_OutputImage->GetLargestPossibleRegion()); DoubleDwiType::PixelType signal; signal.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); boost::progress_display disp2(m_OutputImage->GetLargestPossibleRegion().GetNumberOfPixels()); PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); int lastTick = 0; while(!it4.IsAtEnd()) { if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } ++disp2; unsigned long newTick = 50*disp2.count()/disp2.expected_count(); for (unsigned long tick = 0; tick<(newTick-lastTick); tick++) PrintToLog("*", false, false, false); lastTick = newTick; typename OutputImageType::IndexType index = it4.GetIndex(); signal = doubleOutImage->GetPixel(index)*signalScale; for (unsigned int i=0; i<signal.Size(); i++) { if (m_Parameters.m_SignalGen.m_DoAddDrift) { double df = -m_Parameters.m_SignalGen.m_Drift/(signal.Size()*signal.Size()); signal[i] += signal[i]*df*i*i; } } if (m_Parameters.m_NoiseModel) m_Parameters.m_NoiseModel->AddNoise(signal); for (unsigned int i=0; i<signal.Size(); i++) { if (signal[i]>0) signal[i] = floor(signal[i]+0.5); else signal[i] = ceil(signal[i]-0.5); if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]>window) window = signal[i]; if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]<min) min = signal[i]; } it4.Set(signal); ++it4; } window -= min; unsigned int level = window/2 + min; m_LevelWindow.SetLevelWindow(level, window); this->SetNthOutput(0, m_OutputImage); PrintToLog("\n", false); PrintToLog("Finished simulation"); m_TimeProbe.Stop(); if (m_Parameters.m_SignalGen.m_DoAddMotion) { PrintToLog("\nHead motion log:", false); PrintToLog(m_MotionLog, false, false); } if (m_Parameters.m_Misc.m_DoAddSpikes && m_Parameters.m_SignalGen.m_Spikes>0) { PrintToLog("\nSpike log:", false); PrintToLog(m_SpikeLog, false, false); } if (m_Logfile.is_open()) m_Logfile.close(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::PrintToLog(std::string m, bool addTime, bool linebreak, bool stdOut) { // timestamp if (addTime) { m_Logfile << this->GetTime() << " > "; m_StatusText += this->GetTime() + " > "; if (stdOut) std::cout << this->GetTime() << " > "; } // message if (m_Logfile.is_open()) m_Logfile << m; m_StatusText += m; if (stdOut) std::cout << m; // new line if (linebreak) { if (m_Logfile.is_open()) m_Logfile << "\n"; m_StatusText += "\n"; if (stdOut) std::cout << "\n"; } m_Logfile.flush(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::SimulateMotion(int g) { if ( m_Parameters.m_SignalGen.m_DoAddMotion && m_Parameters.m_SignalGen.m_DoRandomizeMotion && g>0 && m_Parameters.m_SignalGen.m_MotionVolumes[g-1]) { // The last volume was randomly moved, so we have to reset to fiberbundle and the mask. // Without motion or with linear motion, we keep the last position --> no reset. m_FiberBundleTransformed = m_FiberBundle->GetDeepCopy(); if (m_MaskImageSet) { auto duplicator = itk::ImageDuplicator<ItkUcharImgType>::New(); duplicator->SetInputImage(m_Parameters.m_SignalGen.m_MaskImage); duplicator->Update(); m_TransformedMaskImage = duplicator->GetOutput(); } } VectorType rotation; VectorType translation; // is motion artifact enabled? // is the current volume g affected by motion? if ( m_Parameters.m_SignalGen.m_DoAddMotion && m_Parameters.m_SignalGen.m_MotionVolumes[g] && g<static_cast<int>(m_Parameters.m_SignalGen.GetNumVolumes()) ) { // adjust motion transforms if ( m_Parameters.m_SignalGen.m_DoRandomizeMotion ) { // randomly rotation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[0]*2) -m_Parameters.m_SignalGen.m_Rotation[0]; rotation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[1]*2) -m_Parameters.m_SignalGen.m_Rotation[1]; rotation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[2]*2) -m_Parameters.m_SignalGen.m_Rotation[2]; translation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[0]*2) -m_Parameters.m_SignalGen.m_Translation[0]; translation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[1]*2) -m_Parameters.m_SignalGen.m_Translation[1]; translation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[2]*2) -m_Parameters.m_SignalGen.m_Translation[2]; m_FiberBundleTransformed->TransformFibers(rotation[0], rotation[1], rotation[2], translation[0], translation[1], translation[2]); } else { // linearly rotation = m_Parameters.m_SignalGen.m_Rotation / m_NumMotionVolumes; translation = m_Parameters.m_SignalGen.m_Translation / m_NumMotionVolumes; m_MotionCounter++; m_FiberBundleTransformed->TransformFibers(rotation[0], rotation[1], rotation[2], translation[0], translation[1], translation[2]); rotation *= m_MotionCounter; translation *= m_MotionCounter; } MatrixType rotationMatrix = mitk::imv::GetRotationMatrixItk(rotation[0], rotation[1], rotation[2]); MatrixType rotationMatrixInv = mitk::imv::GetRotationMatrixItk(-rotation[0], -rotation[1], -rotation[2]); m_Rotations.push_back(rotationMatrix); m_RotationsInv.push_back(rotationMatrixInv); m_Translations.push_back(translation); // move mask image accoring to new transform if (m_MaskImageSet) { ImageRegionIterator<ItkUcharImgType> maskIt(m_UpsampledMaskImage, m_UpsampledMaskImage->GetLargestPossibleRegion()); m_TransformedMaskImage->FillBuffer(0); while(!maskIt.IsAtEnd()) { if (maskIt.Get()<=0) { ++maskIt; continue; } DoubleDwiType::IndexType index = maskIt.GetIndex(); m_TransformedMaskImage->TransformPhysicalPointToIndex(GetMovedPoint(index, true), index); if (m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(index)) m_TransformedMaskImage->SetPixel(index, 100); ++maskIt; } } } else { if (m_Parameters.m_SignalGen.m_DoAddMotion && !m_Parameters.m_SignalGen.m_DoRandomizeMotion && g>0) { rotation = m_Parameters.m_SignalGen.m_Rotation / m_NumMotionVolumes; rotation *= m_MotionCounter; m_Rotations.push_back(m_Rotations.back()); m_RotationsInv.push_back(m_RotationsInv.back()); m_Translations.push_back(m_Translations.back()); } else { rotation.Fill(0.0); VectorType translation; translation.Fill(0.0); MatrixType rotation_matrix; rotation_matrix.SetIdentity(); m_Rotations.push_back(rotation_matrix); m_RotationsInv.push_back(rotation_matrix); m_Translations.push_back(translation); } } if (m_Parameters.m_SignalGen.m_DoAddMotion) { m_MotionLog += boost::lexical_cast<std::string>(g) + " rotation: " + boost::lexical_cast<std::string>(rotation[0]) + "," + boost::lexical_cast<std::string>(rotation[1]) + "," + boost::lexical_cast<std::string>(rotation[2]) + ";"; m_MotionLog += " translation: " + boost::lexical_cast<std::string>(m_Translations.back()[0]) + "," + boost::lexical_cast<std::string>(m_Translations.back()[1]) + "," + boost::lexical_cast<std::string>(m_Translations.back()[2]) + "\n"; } } template< class PixelType > itk::Point<float, 3> TractsToDWIImageFilter< PixelType >::GetMovedPoint(itk::Index<3>& index, bool forward) { itk::Point<float, 3> transformed_point; float tx = m_Translations.back()[0]; float ty = m_Translations.back()[1]; float tz = m_Translations.back()[2]; if (forward) { m_UpsampledMaskImage->TransformIndexToPhysicalPoint(index, transformed_point); m_FiberBundle->TransformPoint<>(transformed_point, m_Rotations.back(), tx, ty, tz); } else { tx *= -1; ty *= -1; tz *= -1; m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, transformed_point); m_FiberBundle->TransformPoint<>(transformed_point, m_RotationsInv.back(), tx, ty, tz); } return transformed_point; } template< class PixelType > void TractsToDWIImageFilter< PixelType >:: SimulateExtraAxonalSignal(ItkUcharImgType::IndexType& index, itk::Point<float, 3>& volume_fraction_point, double intraAxonalVolume, int g) { int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) { // simulate signal for largest non-fiber compartment int max_compartment_index = 0; double max_fraction = 0; if (numNonFiberCompartments>1) { for (int i=0; i<numNonFiberCompartments; ++i) { m_DoubleInterpolator->SetInputImage(m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()); double compartment_fraction = mitk::imv::GetImageValue<double>(volume_fraction_point, true, m_DoubleInterpolator); if (compartment_fraction<0) mitkThrow() << "Volume fraction image (index " << i << ") contains values less than zero!"; if (compartment_fraction>max_fraction) { max_fraction = compartment_fraction; max_compartment_index = i; } } } DoubleDwiType::Pointer doubleDwi = m_CompartmentImages.at(max_compartment_index+numFiberCompartments); DoubleDwiType::PixelType pix = doubleDwi->GetPixel(index); pix[g] += m_Parameters.m_NonFiberModelList[max_compartment_index]->SimulateMeasurement(g, m_NullDir)*m_VoxelVolume; doubleDwi->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(max_compartment_index+numFiberCompartments)->SetPixel(index, 1); } else { std::vector< double > fractions; if (g==0) m_VolumeFractions.at(0)->SetPixel(index, intraAxonalVolume/m_VoxelVolume); double extraAxonalVolume = m_VoxelVolume-intraAxonalVolume; // non-fiber volume if (extraAxonalVolume<0) { if (extraAxonalVolume<-0.001) MITK_ERROR << "Corrupted intra-axonal signal voxel detected. Fiber volume larger voxel volume! " << m_VoxelVolume << "<" << intraAxonalVolume; extraAxonalVolume = 0; } double interAxonalVolume = 0; if (numFiberCompartments>1) interAxonalVolume = extraAxonalVolume * intraAxonalVolume/m_VoxelVolume; // inter-axonal fraction of non fiber compartment double nonFiberVolume = extraAxonalVolume - interAxonalVolume; // rest of compartment if (nonFiberVolume<0) { if (nonFiberVolume<-0.001) MITK_ERROR << "Corrupted signal voxel detected. Fiber volume larger voxel volume!"; nonFiberVolume = 0; interAxonalVolume = extraAxonalVolume; } double compartmentSum = intraAxonalVolume; fractions.push_back(intraAxonalVolume/m_VoxelVolume); // rescale extra-axonal fiber signal for (int i=1; i<numFiberCompartments; ++i) { if (m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage()!=nullptr) { m_DoubleInterpolator->SetInputImage(m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage()); interAxonalVolume = mitk::imv::GetImageValue<double>(volume_fraction_point, true, m_DoubleInterpolator)*m_VoxelVolume; if (interAxonalVolume<0) mitkThrow() << "Volume fraction image (index " << i+1 << ") contains negative values!"; } DoubleDwiType::PixelType pix = m_CompartmentImages.at(i)->GetPixel(index); pix[g] *= interAxonalVolume; m_CompartmentImages.at(i)->SetPixel(index, pix); compartmentSum += interAxonalVolume; fractions.push_back(interAxonalVolume/m_VoxelVolume); if (g==0) m_VolumeFractions.at(i)->SetPixel(index, interAxonalVolume/m_VoxelVolume); } for (int i=0; i<numNonFiberCompartments; ++i) { double volume = nonFiberVolume; if (m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()!=nullptr) { m_DoubleInterpolator->SetInputImage(m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()); volume = mitk::imv::GetImageValue<double>(volume_fraction_point, true, m_DoubleInterpolator)*m_VoxelVolume; if (volume<0) mitkThrow() << "Volume fraction image (index " << numFiberCompartments+i+1 << ") contains negative values (non-fiber compartment)!"; if (m_UseRelativeNonFiberVolumeFractions) volume *= nonFiberVolume/m_VoxelVolume; } DoubleDwiType::PixelType pix = m_CompartmentImages.at(i+numFiberCompartments)->GetPixel(index); pix[g] += m_Parameters.m_NonFiberModelList[i]->SimulateMeasurement(g, m_NullDir)*volume; m_CompartmentImages.at(i+numFiberCompartments)->SetPixel(index, pix); compartmentSum += volume; fractions.push_back(volume/m_VoxelVolume); if (g==0) m_VolumeFractions.at(i+numFiberCompartments)->SetPixel(index, volume/m_VoxelVolume); } if (compartmentSum/m_VoxelVolume>1.05) { MITK_ERROR << "Compartments do not sum to 1 in voxel " << index << " (" << compartmentSum/m_VoxelVolume << ")"; for (auto val : fractions) MITK_ERROR << val; } } } template< class PixelType > itk::Vector<double, 3> TractsToDWIImageFilter< PixelType >::GetItkVector(double point[3]) { itk::Vector<double, 3> itkVector; itkVector[0] = point[0]; itkVector[1] = point[1]; itkVector[2] = point[2]; return itkVector; } template< class PixelType > vnl_vector_fixed<double, 3> TractsToDWIImageFilter< PixelType >::GetVnlVector(double point[3]) { vnl_vector_fixed<double, 3> vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } template< class PixelType > vnl_vector_fixed<double, 3> TractsToDWIImageFilter< PixelType >::GetVnlVector(Vector<float,3>& vector) { vnl_vector_fixed<double, 3> vnlVector; vnlVector[0] = vector[0]; vnlVector[1] = vector[1]; vnlVector[2] = vector[2]; return vnlVector; } template< class PixelType > double TractsToDWIImageFilter< PixelType >::RoundToNearest(double num) { return (num > 0.0) ? floor(num + 0.5) : ceil(num - 0.5); } template< class PixelType > std::string TractsToDWIImageFilter< PixelType >::GetTime() { m_TimeProbe.Stop(); unsigned long total = RoundToNearest(m_TimeProbe.GetTotal()); unsigned long hours = total/3600; unsigned long minutes = (total%3600)/60; unsigned long seconds = total%60; std::string out = ""; out.append(boost::lexical_cast<std::string>(hours)); out.append(":"); out.append(boost::lexical_cast<std::string>(minutes)); out.append(":"); out.append(boost::lexical_cast<std::string>(seconds)); m_TimeProbe.Start(); return out; } } diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.h b/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.h index bcb285d2f4..ec61f3ea82 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.h +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.h @@ -1,333 +1,333 @@ /*=================================================================== 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 <itkImageRegion.h> #include <itkMatrix.h> #include <mitkDiffusionNoiseModel.h> #include <mitkDiffusionSignalModel.h> #include <mitkDataNode.h> #include <mitkRicianNoiseModel.h> #include <mitkChiSquareNoiseModel.h> #include <mitkImage.h> #include <mitkDiffusionPropertyHelper.h> #include <mitkPlanarEllipse.h> #include <mitkStickModel.h> #include <mitkTensorModel.h> #include <mitkAstroStickModel.h> #include <mitkBallModel.h> #include <mitkDotModel.h> #include <mitkRawShModel.h> #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/xml_parser.hpp> #include <limits> #include <MitkFiberTrackingExports.h> #include <itkMersenneTwisterRandomVariateGenerator.h> namespace mitk { class MITKFIBERTRACKING_EXPORT FiberfoxParameters; /** Signal generation */ class MITKFIBERTRACKING_EXPORT SignalGenerationParameters { friend FiberfoxParameters; public: typedef itk::Image<float, 3> ItkFloatImgType; typedef itk::Image<unsigned char, 3> ItkUcharImgType; typedef itk::Vector<double,3> GradientType; typedef std::vector<GradientType> GradientListType; enum CoilSensitivityProfile : int { COIL_CONSTANT, COIL_LINEAR, COIL_EXPONENTIAL }; enum AcquisitionType : int { SingleShotEpi, - SpinEcho + ConventionalSpinEcho }; SignalGenerationParameters() : m_AcquisitionType(SignalGenerationParameters::SingleShotEpi) , m_SignalScale(100) , m_tEcho(100) , m_tRep(4000) , m_tInv(0) , m_tLine(1) , m_tInhom(50) , m_ReversePhase(false) , m_PartialFourier(1.0) , m_NoiseVariance(0.001) , m_NumberOfCoils(1) , m_CoilSensitivityProfile(SignalGenerationParameters::COIL_CONSTANT) , m_SimulateKspaceAcquisition(false) , m_AxonRadius(0) , m_DoDisablePartialVolume(false) , m_Spikes(0) , m_SpikeAmplitude(1) , m_KspaceLineOffset(0) , m_EddyStrength(300) , m_Tau(70) , m_CroppingFactor(1) , m_Drift(0.06) , m_DoAddGibbsRinging(false) , m_ZeroRinging(0) , m_DoSimulateRelaxation(true) , m_DoAddMotion(false) , m_DoRandomizeMotion(true) , m_DoAddDrift(false) , m_FrequencyMap(nullptr) , m_MaskImage(nullptr) , m_Bvalue(1000) { m_ImageRegion.SetSize(0, 12); m_ImageRegion.SetSize(1, 12); m_ImageRegion.SetSize(2, 3); m_ImageSpacing.Fill(2.0); m_ImageOrigin.Fill(0.0); m_ImageDirection.SetIdentity(); m_Translation.Fill(0.0); m_Rotation.Fill(0.0); SetNumWeightedVolumes(6); } /** input/output image specifications */ itk::ImageRegion<3> m_CroppedRegion; ///< Image size with reduced FOV. itk::ImageRegion<3> m_ImageRegion; ///< Image size. itk::Vector<float,3> m_ImageSpacing; ///< Image voxel size. itk::Point<float,3> m_ImageOrigin; ///< Image origin. itk::Matrix<double, 3, 3> m_ImageDirection; ///< Image rotation matrix. /** Other acquisitions parameters */ AcquisitionType m_AcquisitionType; ///< determines k-space trajectory and maximum echo position(s) float m_SignalScale; ///< Scaling factor for output signal (before noise is added). float m_tEcho; ///< Echo time TE. float m_tRep; ///< Echo time TR. float m_tInv; ///< Inversion time float m_tLine; ///< k-space line readout time (dwell time). float m_tInhom; ///< T2' bool m_ReversePhase; ///< If true, the phase readout direction will be inverted (-y instead of y) float m_PartialFourier; ///< Partial fourier factor (0.5-1) float m_NoiseVariance; ///< Variance of complex gaussian noise unsigned int m_NumberOfCoils; ///< Number of coils in multi-coil acquisition CoilSensitivityProfile m_CoilSensitivityProfile; ///< Choose between constant, linear or exponential sensitivity profile of the used coils bool m_SimulateKspaceAcquisition;///< Flag to enable/disable k-space acquisition simulation double m_AxonRadius; ///< Determines compartment volume fractions (0 == automatic axon radius estimation) bool m_DoDisablePartialVolume; ///< Disable partial volume effects. Each voxel is either all fiber or all non-fiber. /** Artifacts and other effects */ unsigned int m_Spikes; ///< Number of spikes randomly appearing in the image float m_SpikeAmplitude; ///< amplitude of spikes relative to the largest signal intensity (magnitude of complex) float m_KspaceLineOffset; ///< Causes N/2 ghosts. Larger offset means stronger ghost. float m_EddyStrength; ///< Strength of eddy current induced gradients in mT/m. float m_Tau; ///< Eddy current decay constant (in ms) float m_CroppingFactor; ///< FOV size in y-direction is multiplied by this factor. Causes aliasing artifacts. float m_Drift; ///< Global signal decrease by the end of the acquisition. bool m_DoAddGibbsRinging; ///< Add Gibbs ringing artifact int m_ZeroRinging; ///< If > 0, ringing is simulated by by setting the defined percentage of higher frequencies to 0 in k-space. Otherwise, the input to the k-space simulation is generated with twice the resolution and cropped during k-space simulation (much slower). bool m_DoSimulateRelaxation; ///< Add T2 relaxation effects bool m_DoAddMotion; ///< Enable motion artifacts. bool m_DoRandomizeMotion; ///< Toggles between random and linear motion. bool m_DoAddDrift; ///< Add quadratic signal drift. std::vector< bool > m_MotionVolumes; ///< Indicates the image volumes that are affected by motion ///< with positive numbers, inverted logic with negative numbers. itk::Vector<float,3> m_Translation; ///< Maximum translational motion. itk::Vector<float,3> m_Rotation; ///< Maximum rotational motion. ItkFloatImgType::Pointer m_FrequencyMap; ///< If != nullptr, distortions are added to the image using this frequency map. ItkUcharImgType::Pointer m_MaskImage; ///< Signal is only genrated inside of the mask image. std::vector< int > GetBaselineIndices(); ///< Returns list of nun-diffusion-weighted image volume indices unsigned int GetFirstBaselineIndex(); ///< Returns index of first non-diffusion-weighted image volume bool IsBaselineIndex(unsigned int idx); ///< Checks if image volume with given index is non-diffusion-weighted volume or not. unsigned int GetNumWeightedVolumes(); ///< Get number of diffusion-weighted image volumes unsigned int GetNumBaselineVolumes(); ///< Get number of non-diffusion-weighted image volumes unsigned int GetNumVolumes(); ///< Get number of baseline and diffusion-weighted image volumes GradientListType GetGradientDirections(); ///< Return gradient direction container mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer GetItkGradientContainer(); GradientType GetGradientDirection(unsigned int i); std::vector< int > GetBvalues(); ///< Returns a vector with all unique b-values (determined by the gradient magnitudes) double GetBvalue(); void ApplyDirectionMatrix(); protected: unsigned int m_NumGradients; ///< Number of diffusion-weighted image volumes. unsigned int m_NumBaseline; ///< Number of non-diffusion-weighted image volumes. GradientListType m_GradientDirections; ///< Total number of image volumes. double m_Bvalue; ///< Acquisition b-value void SetNumWeightedVolumes(int numGradients); ///< Automaticall calls GenerateGradientHalfShell() afterwards. void SetGradienDirections(GradientListType gradientList); void SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientList); void GenerateGradientHalfShell(); ///< Generates half shell of gradient directions (with m_NumGradients non-zero directions) }; /** Fiber generation */ class MITKFIBERTRACKING_EXPORT FiberGenerationParameters { public: enum FiberDistribution { DISTRIBUTE_UNIFORM, // distribute fibers uniformly in the ROIs DISTRIBUTE_GAUSSIAN // distribute fibers using a 2D gaussian }; typedef std::vector< std::vector< mitk::PlanarEllipse::Pointer > > FiducialListType; typedef std::vector< std::vector< unsigned int > > FlipListType; FiberGenerationParameters() : m_Distribution(DISTRIBUTE_UNIFORM) , m_Density(100) , m_Variance(100) , m_Sampling(1) , m_Tension(0) , m_Continuity(0) , m_Bias(0) { m_Rotation.Fill(0.0); m_Translation.Fill(0.0); m_Scale.Fill(1.0); } FiberDistribution m_Distribution; unsigned int m_Density; double m_Variance; double m_Sampling; double m_Tension; double m_Continuity; double m_Bias; mitk::Vector3D m_Rotation; mitk::Vector3D m_Translation; mitk::Vector3D m_Scale; FlipListType m_FlipList; ///< contains flags indicating a flip of the 2D fiber x-coordinates (needed to resolve some unwanted fiber twisting) FiducialListType m_Fiducials; ///< container of the planar ellipses used as fiducials for the fiber generation process }; /** GUI persistence, input, output, ... */ class MITKFIBERTRACKING_EXPORT MiscFiberfoxParameters { public: MiscFiberfoxParameters() : m_ResultNode(DataNode::New()) , m_ParentNode(nullptr) , m_SignalModelString("") , m_ArtifactModelString("") , m_OutputPath("/tmp/") , m_OutputPrefix("fiberfox") , m_AfterSimulationMessage("") , m_BvalsFile("") , m_BvecsFile("") , m_CheckOutputVolumeFractionsBox(false) , m_CheckAdvancedSignalOptionsBox(false) , m_DoAddNoise(false) , m_DoAddGhosts(false) , m_DoAddAliasing(false) , m_DoAddSpikes(false) , m_DoAddEddyCurrents(false) , m_DoAddDistortions(false) , m_MotionVolumesBox("random") , m_CheckRealTimeFibersBox(true) , m_CheckAdvancedFiberOptionsBox(false) , m_CheckConstantRadiusBox(false) , m_CheckIncludeFiducialsBox(true) {} DataNode::Pointer m_ResultNode; ///< Stores resulting image. DataNode::Pointer m_ParentNode; ///< Parent node of result node. std::string m_SignalModelString; ///< Appendet to the name of the result node std::string m_ArtifactModelString; ///< Appendet to the name of the result node std::string m_OutputPath; ///< Image is automatically saved to the specified folder after simulation is finished. std::string m_OutputPrefix; /** Prefix for filename of output files and logfile. */ std::string m_AfterSimulationMessage; ///< Store messages that are displayed after the simulation has finished (e.g. warnings, automatic parameter adjustments etc.) std::string m_BvalsFile; std::string m_BvecsFile; /** member variables that store the check-state of GUI checkboxes */ // image generation bool m_CheckOutputVolumeFractionsBox; bool m_CheckAdvancedSignalOptionsBox; bool m_DoAddNoise; bool m_DoAddGhosts; bool m_DoAddAliasing; bool m_DoAddSpikes; bool m_DoAddEddyCurrents; bool m_DoAddDistortions; std::string m_MotionVolumesBox; // fiber generation bool m_CheckRealTimeFibersBox; bool m_CheckAdvancedFiberOptionsBox; bool m_CheckConstantRadiusBox; bool m_CheckIncludeFiducialsBox; }; /** * \brief Datastructure to manage the Fiberfox signal generation parameters. * */ class MITKFIBERTRACKING_EXPORT FiberfoxParameters { public: typedef itk::Image<float, 3> ItkFloatImgType; typedef itk::Image<double, 3> ItkDoubleImgType; typedef itk::Image<unsigned char, 3> ItkUcharImgType; typedef DiffusionSignalModel<double> DiffusionModelType; typedef std::vector< DiffusionModelType* > DiffusionModelListType; typedef DiffusionNoiseModel<double> NoiseModelType; FiberfoxParameters(); FiberfoxParameters(const FiberfoxParameters ¶ms); ~FiberfoxParameters(); /** Not templated parameters */ FiberGenerationParameters m_FiberGen; ///< Fiber generation parameters SignalGenerationParameters m_SignalGen; ///< Signal generation parameters MiscFiberfoxParameters m_Misc; ///< GUI realted and I/O parameters /** Templated parameters */ DiffusionModelListType m_FiberModelList; ///< Intra- and inter-axonal compartments. DiffusionModelListType m_NonFiberModelList; ///< Extra-axonal compartments. std::shared_ptr< NoiseModelType > m_NoiseModel; ///< If != nullptr, noise is added to the image. void GenerateGradientHalfShell(); void SetNumWeightedVolumes(int numGradients); ///< Automaticall calls GenerateGradientHalfShell() afterwards. void SetGradienDirections(mitk::SignalGenerationParameters::GradientListType gradientList); void SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientList); void SetBvalue(double Bvalue); void UpdateSignalModels(); void ClearFiberParameters(); void ClearSignalParameters(); void ApplyDirectionMatrix(); void PrintSelf(); ///< Print parameters to stdout. void SaveParameters(std::string filename); ///< Save image generation parameters to .ffp file. void LoadParameters(std::string filename, bool fix_seed=false); ///< Load image generation parameters from .ffp file. template< class ParameterType > ParameterType ReadVal(boost::property_tree::ptree::value_type const& v, std::string tag, ParameterType defaultValue, bool essential=false); std::string m_MissingTags; }; } #endif diff --git a/Modules/DiffusionImaging/FiberTracking/files.cmake b/Modules/DiffusionImaging/FiberTracking/files.cmake index a93ec3dcd5..5567d247a5 100644 --- a/Modules/DiffusionImaging/FiberTracking/files.cmake +++ b/Modules/DiffusionImaging/FiberTracking/files.cmake @@ -1,108 +1,108 @@ set(CPP_FILES mitkFiberTrackingModuleActivator.cpp ## IO datastructures IODataStructures/FiberBundle/mitkFiberBundle.cpp IODataStructures/FiberBundle/mitkTrackvis.cpp IODataStructures/PlanarFigureComposite/mitkPlanarFigureComposite.cpp IODataStructures/mitkTractographyForest.cpp IODataStructures/mitkFiberfoxParameters.cpp # Interactions # Tractography Algorithms/GibbsTracking/mitkParticleGrid.cpp Algorithms/GibbsTracking/mitkMetropolisHastingsSampler.cpp Algorithms/GibbsTracking/mitkEnergyComputer.cpp Algorithms/GibbsTracking/mitkGibbsEnergyComputer.cpp Algorithms/GibbsTracking/mitkFiberBuilder.cpp Algorithms/GibbsTracking/mitkSphereInterpolator.cpp Algorithms/itkStreamlineTrackingFilter.cpp Algorithms/TrackingHandlers/mitkTrackingDataHandler.cpp Algorithms/TrackingHandlers/mitkTrackingHandlerTensor.cpp Algorithms/TrackingHandlers/mitkTrackingHandlerPeaks.cpp Algorithms/TrackingHandlers/mitkTrackingHandlerOdf.cpp ) set(H_FILES # DataStructures -> FiberBundle IODataStructures/FiberBundle/mitkFiberBundle.h IODataStructures/FiberBundle/mitkTrackvis.h IODataStructures/mitkFiberfoxParameters.h IODataStructures/mitkTractographyForest.h # Algorithms Algorithms/itkTractDensityImageFilter.h Algorithms/itkTractsToFiberEndingsImageFilter.h Algorithms/itkTractsToRgbaImageFilter.h Algorithms/itkTractsToVectorImageFilter.h Algorithms/itkEvaluateDirectionImagesFilter.h Algorithms/itkEvaluateTractogramDirectionsFilter.h Algorithms/itkFiberCurvatureFilter.h Algorithms/itkFitFibersToImageFilter.h Algorithms/itkTractClusteringFilter.h Algorithms/itkTractDistanceFilter.h Algorithms/itkFiberExtractionFilter.h Algorithms/itkTdiToVolumeFractionFilter.h # Tractography Algorithms/TrackingHandlers/mitkTrackingDataHandler.h Algorithms/TrackingHandlers/mitkTrackingHandlerRandomForest.h Algorithms/TrackingHandlers/mitkTrackingHandlerTensor.h Algorithms/TrackingHandlers/mitkTrackingHandlerPeaks.h Algorithms/TrackingHandlers/mitkTrackingHandlerOdf.h Algorithms/itkGibbsTrackingFilter.h Algorithms/itkStochasticTractographyFilter.h Algorithms/GibbsTracking/mitkParticle.h Algorithms/GibbsTracking/mitkParticleGrid.h Algorithms/GibbsTracking/mitkMetropolisHastingsSampler.h Algorithms/GibbsTracking/mitkSimpSamp.h Algorithms/GibbsTracking/mitkEnergyComputer.h Algorithms/GibbsTracking/mitkGibbsEnergyComputer.h Algorithms/GibbsTracking/mitkSphereInterpolator.h Algorithms/GibbsTracking/mitkFiberBuilder.h Algorithms/itkStreamlineTrackingFilter.h # Clustering Algorithms/ClusteringMetrics/mitkClusteringMetric.h Algorithms/ClusteringMetrics/mitkClusteringMetricEuclideanMean.h Algorithms/ClusteringMetrics/mitkClusteringMetricEuclideanMax.h Algorithms/ClusteringMetrics/mitkClusteringMetricEuclideanStd.h Algorithms/ClusteringMetrics/mitkClusteringMetricAnatomic.h Algorithms/ClusteringMetrics/mitkClusteringMetricScalarMap.h Algorithms/ClusteringMetrics/mitkClusteringMetricInnerAngles.h Algorithms/ClusteringMetrics/mitkClusteringMetricLength.h # Fiberfox Fiberfox/itkFibersFromPlanarFiguresFilter.h Fiberfox/itkTractsToDWIImageFilter.h Fiberfox/itkKspaceImageFilter.h Fiberfox/itkDftImageFilter.h Fiberfox/itkFieldmapGeneratorFilter.h Fiberfox/itkRandomPhantomFilter.h Fiberfox/SignalModels/mitkDiffusionSignalModel.h Fiberfox/SignalModels/mitkTensorModel.h Fiberfox/SignalModels/mitkBallModel.h Fiberfox/SignalModels/mitkDotModel.h Fiberfox/SignalModels/mitkAstroStickModel.h Fiberfox/SignalModels/mitkStickModel.h Fiberfox/SignalModels/mitkRawShModel.h Fiberfox/SignalModels/mitkDiffusionNoiseModel.h Fiberfox/SignalModels/mitkRicianNoiseModel.h Fiberfox/SignalModels/mitkChiSquareNoiseModel.h Fiberfox/Sequences/mitkAcquisitionType.h Fiberfox/Sequences/mitkSingleShotEpi.h - Fiberfox/Sequences/mitkCartesianReadout.h + Fiberfox/Sequences/mitkConventionalSpinEcho.h ) set(RESOURCE_FILES # Binary directory resources FiberTrackingLUTBaryCoords.bin FiberTrackingLUTIndices.bin ) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui index 3966ac3473..a3373729d4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui @@ -1,2793 +1,2845 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>QmitkFiberfoxViewControls</class> <widget class="QWidget" name="QmitkFiberfoxViewControls"> <property name="geometry"> <rect> <x>0</x> <y>0</y> - <width>463</width> - <height>2744</height> + <width>490</width> + <height>2775</height> </rect> </property> <property name="windowTitle"> <string>Form</string> </property> <property name="styleSheet"> <string notr="true"/> </property> <layout class="QGridLayout" name="gridLayout_2"> - <item row="6" column="0"> - <widget class="QCommandLinkButton" name="m_SaveParametersButton"> + <item row="3" column="0"> + <widget class="QGroupBox" name="m_IntraAxonalGroupBox"> <property name="styleSheet"> - <string notr="true"/> - </property> - <property name="text"> - <string>Save Parameters</string> - </property> - <property name="icon"> - <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> - <normaloff>:/QmitkDiffusionImaging/general_icons/download.ico</normaloff>:/QmitkDiffusionImaging/general_icons/download.ico</iconset> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QFrame" name="frame_9"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> + <string notr="true">QGroupBox { + background-color: transparent; +}</string> </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> + <property name="title"> + <string>Intra-axonal Compartment</string> </property> - <layout class="QGridLayout" name="gridLayout_32"> + <layout class="QGridLayout" name="gridLayout_13"> <property name="leftMargin"> - <number>0</number> + <number>6</number> </property> <property name="topMargin"> - <number>0</number> + <number>6</number> </property> <property name="rightMargin"> - <number>0</number> + <number>6</number> </property> <property name="bottomMargin"> - <number>0</number> + <number>6</number> </property> + <item row="3" column="0"> + <widget class="QmitkTensorModelParametersWidget" name="m_TensorWidget1" native="true"/> + </item> <item row="1" column="0"> - <widget class="QCommandLinkButton" name="m_GenerateImageButton"> - <property name="enabled"> - <bool>true</bool> - </property> + <widget class="QmitkStickModelParametersWidget" name="m_StickWidget1" native="true"/> + </item> + <item row="4" column="0"> + <widget class="QmitkPrototypeSignalParametersWidget" name="m_PrototypeWidget1" native="true"/> + </item> + <item row="0" column="0"> + <widget class="QComboBox" name="m_Compartment1Box"> <property name="toolTip"> - <string><html><head/><body><p>Start DWI generation from selected fiber bundle.</p><p>If no fiber bundle but an existing diffusion weighted image is selected, the enabled artifacts are added to this image.</p><p>If neither a fiber bundle nor a diffusion weighted image is selected, a grayscale image containing a simple gradient is generated.</p></body></html></string> - </property> - <property name="styleSheet"> - <string notr="true"/> - </property> - <property name="text"> - <string>Start Simulation</string> - </property> - <property name="icon"> - <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> - <normaloff>:/QmitkDiffusionImaging/general_icons/right.ico</normaloff>:/QmitkDiffusionImaging/general_icons/right.ico</iconset> + <string>Select signal model for intra-axonal compartment.</string> </property> + <item> + <property name="text"> + <string>Stick Model</string> + </property> + </item> + <item> + <property name="text"> + <string>Zeppelin Model</string> + </property> + </item> + <item> + <property name="text"> + <string>Tensor Model</string> + </property> + </item> + <item> + <property name="text"> + <string>Prototype Signal</string> + </property> + </item> </widget> </item> - <item row="0" column="0"> - <widget class="QGroupBox" name="groupBox_2"> - <property name="styleSheet"> - <string notr="true">QGroupBox { - background-color: transparent; -}</string> + <item row="2" column="0"> + <widget class="QmitkZeppelinModelParametersWidget" name="m_ZeppelinWidget1" native="true"/> + </item> + <item row="5" column="0"> + <widget class="QFrame" name="m_Comp1FractionFrame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> </property> - <property name="title"> - <string>Input Data</string> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> </property> - <layout class="QGridLayout" name="gridLayout_10"> + <layout class="QGridLayout" name="gridLayout_26"> <property name="leftMargin"> - <number>6</number> + <number>0</number> </property> <property name="topMargin"> - <number>6</number> + <number>0</number> </property> <property name="rightMargin"> - <number>6</number> + <number>0</number> </property> <property name="bottomMargin"> - <number>6</number> + <number>0</number> </property> - <item row="4" column="2"> - <widget class="QFrame" name="frame_6"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QGridLayout" name="gridLayout_20"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QLineEdit" name="m_SavePathEdit"> - <property name="text"> - <string>-</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QToolButton" name="m_OutputPathButton"> - <property name="text"> - <string>...</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item row="2" column="2"> - <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_MaskComboBox"> - <property name="toolTip"> - <string><html><head/><body><p>Select a binary image to define the area of signal generation. Outside of the mask image only noise will be actively generated.</p></body></html></string> - </property> - <property name="sizeAdjustPolicy"> - <enum>QComboBox::AdjustToMinimumContentsLength</enum> - </property> - </widget> - </item> - <item row="0" column="0" rowspan="2" colspan="2"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_16"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>Fiber Bundle:</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="label_10"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>Save path:</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_3"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>Tissue Mask:</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_FiberBundleComboBox"> - <property name="toolTip"> - <string><html><head/><body><p>Select a fiber bundle to generate the white matter signal from. You can either use the fiber definition tab to manually define an input fiber bundle or you can also use any existing bundle, e.g. yielded by a tractography algorithm.</p></body></html></string> - </property> - <property name="sizeAdjustPolicy"> - <enum>QComboBox::AdjustToMinimumContentsLength</enum> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_11"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> + <item row="0" column="0"> + <widget class="QLabel" name="m_NoiseLabel_6"> <property name="text"> - <string>Template Image:</string> - </property> - <property name="wordWrap"> - <bool>false</bool> + <string>Volume Fraction:</string> </property> </widget> </item> - <item row="3" column="2"> - <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_TemplateComboBox"> + <item row="0" column="1"> + <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_Comp1VolumeFraction"> <property name="toolTip"> - <string><html><head/><body><p>The parameters for the simulation (e.g. spacing, size, diffuison-weighted gradients, b-value) are adopted from this image.</p></body></html></string> - </property> - <property name="sizeAdjustPolicy"> - <enum>QComboBox::AdjustToMinimumContentsLength</enum> + <string>Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers.</string> </property> </widget> </item> </layout> </widget> </item> - <item row="2" column="0"> - <widget class="QCommandLinkButton" name="m_AbortSimulationButton"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="toolTip"> - <string>Stop current simulation.</string> - </property> - <property name="styleSheet"> - <string notr="true"/> - </property> - <property name="text"> - <string>Abort Simulation</string> - </property> - <property name="icon"> - <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> - <normaloff>:/QmitkDiffusionImaging/general_icons/abort.ico</normaloff>:/QmitkDiffusionImaging/general_icons/abort.ico</iconset> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QTextEdit" name="m_SimulationStatusText"> - <property name="font"> - <font> - <family>Courier</family> - <pointsize>7</pointsize> - </font> - </property> - <property name="readOnly"> - <bool>true</bool> - </property> - </widget> - </item> </layout> </widget> </item> - <item row="2" column="0"> - <widget class="QGroupBox" name="m_IntraAxonalGroupBox"> + <item row="4" column="0"> + <widget class="QGroupBox" name="groupBox_5"> <property name="styleSheet"> <string notr="true">QGroupBox { background-color: transparent; }</string> </property> <property name="title"> - <string>Intra-axonal Compartment</string> + <string>Inter-axonal Compartment</string> </property> - <layout class="QGridLayout" name="gridLayout_13"> + <layout class="QGridLayout" name="gridLayout_17"> <property name="leftMargin"> <number>6</number> </property> <property name="topMargin"> <number>6</number> </property> <property name="rightMargin"> <number>6</number> </property> <property name="bottomMargin"> <number>6</number> </property> - <item row="3" column="0"> - <widget class="QmitkTensorModelParametersWidget" name="m_TensorWidget1" native="true"/> - </item> - <item row="1" column="0"> - <widget class="QmitkStickModelParametersWidget" name="m_StickWidget1" native="true"/> - </item> - <item row="4" column="0"> - <widget class="QmitkPrototypeSignalParametersWidget" name="m_PrototypeWidget1" native="true"/> - </item> <item row="0" column="0"> - <widget class="QComboBox" name="m_Compartment1Box"> + <widget class="QComboBox" name="m_Compartment2Box"> <property name="toolTip"> <string>Select signal model for intra-axonal compartment.</string> </property> <item> <property name="text"> - <string>Stick Model</string> + <string>--</string> </property> </item> <item> <property name="text"> - <string>Zeppelin Model</string> + <string>Stick Model</string> </property> </item> <item> <property name="text"> - <string>Tensor Model</string> + <string>Zeppelin Model</string> </property> </item> <item> <property name="text"> - <string>Prototype Signal</string> + <string>Tensor Model</string> </property> </item> </widget> </item> + <item row="1" column="0"> + <widget class="QmitkZeppelinModelParametersWidget" name="m_ZeppelinWidget2" native="true"/> + </item> <item row="2" column="0"> - <widget class="QmitkZeppelinModelParametersWidget" name="m_ZeppelinWidget1" native="true"/> + <widget class="QmitkStickModelParametersWidget" name="m_StickWidget2" native="true"/> + </item> + <item row="3" column="0"> + <widget class="QmitkTensorModelParametersWidget" name="m_TensorWidget2" native="true"/> + </item> + <item row="4" column="0"> + <widget class="QmitkPrototypeSignalParametersWidget" name="m_PrototypeWidget2" native="true"/> </item> <item row="5" column="0"> - <widget class="QFrame" name="m_Comp1FractionFrame"> + <widget class="QFrame" name="m_Comp2FractionFrame"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> - <layout class="QGridLayout" name="gridLayout_26"> + <layout class="QGridLayout" name="gridLayout_27"> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> <item row="0" column="0"> - <widget class="QLabel" name="m_NoiseLabel_6"> + <widget class="QLabel" name="m_NoiseLabel_7"> <property name="text"> <string>Volume Fraction:</string> </property> </widget> </item> <item row="0" column="1"> - <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_Comp1VolumeFraction"> + <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_Comp2VolumeFraction"> <property name="toolTip"> <string>Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers.</string> </property> </widget> </item> </layout> </widget> </item> </layout> </widget> </item> - <item row="7" column="0"> - <widget class="QCommandLinkButton" name="m_LoadParametersButton"> - <property name="styleSheet"> - <string notr="true"/> - </property> - <property name="text"> - <string>Load Parameters</string> - </property> - <property name="icon"> - <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> - <normaloff>:/QmitkDiffusionImaging/general_icons/upload.ico</normaloff>:/QmitkDiffusionImaging/general_icons/upload.ico</iconset> - </property> - </widget> - </item> - <item row="4" column="0"> - <widget class="QGroupBox" name="groupBox_6"> + <item row="2" column="0"> + <widget class="QGroupBox" name="groupBox"> <property name="styleSheet"> <string notr="true">QGroupBox { background-color: transparent; }</string> </property> <property name="title"> - <string>Extra-axonal Compartments</string> + <string>Image Settings</string> </property> - <layout class="QGridLayout" name="gridLayout_14"> + <layout class="QGridLayout" name="gridLayout"> <property name="leftMargin"> <number>6</number> </property> <property name="topMargin"> <number>6</number> </property> <property name="rightMargin"> <number>6</number> </property> <property name="bottomMargin"> <number>6</number> </property> - <item row="18" column="0"> - <widget class="QFrame" name="m_Comp4FractionFrame"> + <item row="2" column="0"> + <widget class="QLabel" name="m_GeometryMessage"> + <property name="styleSheet"> + <string notr="true">color: rgb(255, 0, 0);</string> + </property> + <property name="text"> + <string>Using geometry of selected image!</string> + </property> + </widget> + </item> + <item row="9" column="0"> + <widget class="QFrame" name="m_AdvancedSignalOptionsFrame"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> - <layout class="QGridLayout" name="gridLayout_30"> + <layout class="QGridLayout" name="gridLayout_23"> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> - <item row="0" column="0"> - <widget class="QLabel" name="m_NoiseLabel_9"> - <property name="text"> - <string>Volume Fraction:</string> + <property name="horizontalSpacing"> + <number>6</number> + </property> + <item row="1" column="1"> + <widget class="QSpinBox" name="m_SignalScaleBox"> + <property name="toolTip"> + <string>TE in milliseconds</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>10000</number> + </property> + <property name="singleStep"> + <number>1</number> + </property> + <property name="value"> + <number>100</number> </property> </widget> </item> <item row="0" column="1"> - <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_Comp4VolumeFraction"> - <property name="toolTip"> - <string/> - </property> + <widget class="QComboBox" name="m_AcquisitionTypeBox"> + <item> + <property name="text"> + <string>Single Shot EPI</string> + </property> + </item> + <item> + <property name="text"> + <string>Conventional Spin Echo</string> + </property> + </item> </widget> </item> - </layout> - </widget> - </item> - <item row="6" column="0"> - <widget class="QComboBox" name="m_Compartment3Box"> - <property name="toolTip"> - <string>Select signal model for extra-axonal compartment.</string> - </property> - <item> - <property name="text"> - <string>Ball Model</string> - </property> - </item> - <item> - <property name="text"> - <string>Astrosticks Model</string> - </property> - </item> - <item> - <property name="text"> - <string>Dot Model</string> - </property> - </item> - <item> - <property name="text"> - <string>Prototype Signal</string> - </property> - </item> - </widget> - </item> - <item row="8" column="0"> - <widget class="QmitkAstrosticksModelParametersWidget" name="m_AstrosticksWidget1" native="true"/> - </item> - <item row="10" column="0"> - <widget class="QmitkPrototypeSignalParametersWidget" name="m_PrototypeWidget3" native="true"/> - </item> - <item row="16" column="0"> - <widget class="QmitkDotModelParametersWidget" name="m_DotWidget2" native="true"/> - </item> - <item row="9" column="0"> - <widget class="QmitkDotModelParametersWidget" name="m_DotWidget1" native="true"/> - </item> - <item row="12" column="0"> - <widget class="Line" name="line_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item row="11" column="0"> - <widget class="QFrame" name="m_Comp3FractionFrame"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QGridLayout" name="gridLayout_29"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="m_NoiseLabel_8"> + <item row="12" column="0"> + <widget class="QLabel" name="m_TensorsToDWINumDirsLabel_4"> <property name="text"> - <string>Volume Fraction:</string> + <string>Fiber Radius:</string> </property> </widget> </item> - <item row="0" column="1"> - <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_Comp3VolumeFraction"> + <item row="2" column="1"> + <widget class="QSpinBox" name="m_NumCoilsBox"> <property name="toolTip"> - <string>Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers.</string> + <string>Number of coil elements used for the acquisiton.</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>128</number> + </property> + <property name="singleStep"> + <number>1</number> + </property> + <property name="value"> + <number>1</number> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QSpinBox" name="m_TEbox"> + <property name="toolTip"> + <string>TE in milliseconds</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>999999999</number> + </property> + <property name="singleStep"> + <number>1</number> + </property> + <property name="value"> + <number>100</number> + </property> + </widget> + </item> + <item row="16" column="0"> + <widget class="QCheckBox" name="m_VolumeFractionsBox"> + <property name="toolTip"> + <string>Output phase image and volume fraction maps.</string> + </property> + <property name="text"> + <string>Output Additional Images</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="8" column="1"> + <widget class="QDoubleSpinBox" name="m_LineReadoutTimeBox"> + <property name="toolTip"> + <string>Dwell time (time to read one line in k-space) in ms.</string> + </property> + <property name="maximum"> + <double>100.000000000000000</double> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + <property name="value"> + <double>1.000000000000000</double> + </property> + </widget> + </item> + <item row="9" column="1"> + <widget class="QDoubleSpinBox" name="m_PartialFourier"> + <property name="toolTip"> + <string>Partial fourier factor (0.5-1)</string> + </property> + <property name="decimals"> + <number>3</number> + </property> + <property name="minimum"> + <double>0.500000000000000</double> + </property> + <property name="maximum"> + <double>1.000000000000000</double> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + <property name="value"> + <double>1.000000000000000</double> </property> </widget> </item> - </layout> - </widget> - </item> - <item row="14" column="0"> - <widget class="QmitkBallModelParametersWidget" name="m_BallWidget2" native="true"/> - </item> - <item row="7" column="0"> - <widget class="QmitkBallModelParametersWidget" name="m_BallWidget1" native="true"/> - </item> - <item row="15" column="0"> - <widget class="QmitkAstrosticksModelParametersWidget" name="m_AstrosticksWidget2" native="true"/> - </item> - <item row="13" column="0"> - <widget class="QComboBox" name="m_Compartment4Box"> - <property name="toolTip"> - <string>Select signal model for extra-axonal compartment.</string> - </property> - <item> - <property name="text"> - <string>--</string> - </property> - </item> - <item> - <property name="text"> - <string>Ball Model</string> - </property> - </item> - <item> - <property name="text"> - <string>Astrosticks Model</string> - </property> - </item> - <item> - <property name="text"> - <string>Dot Model</string> - </property> - </item> - <item> - <property name="text"> - <string>Prototype Signal</string> - </property> - </item> - </widget> - </item> - <item row="17" column="0"> - <widget class="QmitkPrototypeSignalParametersWidget" name="m_PrototypeWidget4" native="true"/> - </item> - </layout> - </widget> - </item> - <item row="5" column="0"> - <widget class="QGroupBox" name="groupBox_3"> - <property name="styleSheet"> - <string notr="true">QGroupBox { - background-color: transparent; -}</string> - </property> - <property name="title"> - <string>Noise and other Artifacts</string> - </property> - <layout class="QGridLayout" name="gridLayout_6"> - <property name="leftMargin"> - <number>6</number> - </property> - <property name="topMargin"> - <number>6</number> - </property> - <property name="rightMargin"> - <number>6</number> - </property> - <property name="bottomMargin"> - <number>6</number> - </property> - <item row="8" column="0"> - <widget class="Line" name="line_7"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item row="19" column="0"> - <widget class="QFrame" name="m_MotionArtifactFrame"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QGridLayout" name="gridLayout_18"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>6</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="horizontalSpacing"> - <number>6</number> - </property> <item row="0" column="0"> - <widget class="QCheckBox" name="m_RandomMotion"> + <widget class="QLabel" name="m_TensorsToDWINumDirsLabel_6"> + <property name="text"> + <string>Acquisition Type:</string> + </property> + </widget> + </item> + <item row="12" column="1"> + <widget class="QDoubleSpinBox" name="m_FiberRadius"> <property name="toolTip"> - <string>Toggle between random movement and linear movement.</string> + <string>Fiber radius used to calculate volume fractions (in µm). Set to 0 for automatic radius estimation.</string> + </property> + <property name="maximum"> + <double>9999.000000000000000</double> + </property> + </widget> + </item> + <item row="9" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_32"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> </property> <property name="text"> - <string>Randomize motion</string> + <string>Partial Fourier:</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="13" column="0"> + <widget class="QCheckBox" name="m_ReversePhaseBox"> + <property name="toolTip"> + <string>Output one image per compartment containing the corresponding volume fractions per voxel.</string> + </property> + <property name="text"> + <string>Reverse Phase Encoding Direction</string> </property> <property name="checked"> - <bool>true</bool> + <bool>false</bool> </property> </widget> </item> <item row="3" column="0"> - <widget class="QGroupBox" name="m_RotationArtifactFrame"> - <property name="styleSheet"> - <string notr="true">QGroupBox { - background-color: transparent; -}</string> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_34"> + <property name="toolTip"> + <string/> </property> - <property name="title"> - <string>Rotation</string> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string><html><head/><body><p>Coil Sensitivity:</p></body></html></string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_13"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string><html><head/><body><p>Number of Channels:</p></body></html></string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_14"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string><html><head/><body><p>Repetition Time <span style=" font-style:italic;">TR</span>: </p></body></html></string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QSpinBox" name="m_TRbox"> + <property name="toolTip"> + <string>TR in milliseconds</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>999999999</number> + </property> + <property name="singleStep"> + <number>1</number> + </property> + <property name="value"> + <number>4000</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="m_TensorsToDWINumDirsLabel_5"> + <property name="text"> + <string>Signal Scale:</string> + </property> + </widget> + </item> + <item row="10" column="1"> + <widget class="QSpinBox" name="m_T2starBox"> + <property name="toolTip"> + <string>Relaxation time due to magnetic field inhomogeneities (T2', in milliseconds).</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>10000</number> + </property> + <property name="singleStep"> + <number>1</number> + </property> + <property name="value"> + <number>50</number> + </property> + </widget> + </item> + <item row="10" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_12"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string><html><head/><body><p><span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> Relaxation: </p></body></html></string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="14" column="0"> + <widget class="QCheckBox" name="m_RelaxationBox"> + <property name="toolTip"> + <string><html><head/><body><p><span style=" font-style:italic;">TE</span>, <span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> and <span style=" font-style:italic;">T2</span> will have no effect if unchecked.</p></body></html></string> + </property> + <property name="text"> + <string>Simulate Signal Relaxation</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_33"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string><html><head/><body><p>Echo Time <span style=" font-style:italic;">TE</span>: </p></body></html></string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="8" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_15"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>Dwell Time:</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="m_CoilSensBox"> + <item> + <property name="text"> + <string>Constant</string> + </property> + </item> + <item> + <property name="text"> + <string>Linear</string> + </property> + </item> + <item> + <property name="text"> + <string>Exponential</string> + </property> + </item> + </widget> + </item> + <item row="15" column="0"> + <widget class="QCheckBox" name="m_EnforcePureFiberVoxelsBox"> + <property name="toolTip"> + <string>Disable partial volume. Treat voxel content as fiber-only if at least one fiber is present.</string> + </property> + <property name="text"> + <string>Disable Partial Volume Effects</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="7" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_17"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string><html><head/><body><p>Inversion Time <span style=" font-style:italic;">TI</span>: </p></body></html></string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QSpinBox" name="m_TIbox"> + <property name="toolTip"> + <string>Inversion time (in ms) for inversion recovery sequences. If 0, no inversion pulse is simulated.</string> + </property> + <property name="minimum"> + <number>0</number> + </property> + <property name="maximum"> + <number>999999999</number> + </property> + <property name="singleStep"> + <number>1</number> + </property> + <property name="value"> + <number>0</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="7" column="0"> + <widget class="QFrame" name="m_GenerateGradientsFrame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout" name="gridLayout_24"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <item row="2" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string><html><head/><body><p>b-Value<span style=" font-style:italic;"> [s/mm</span><span style=" font-style:italic; vertical-align:super;">2</span><span style=" font-style:italic;">]</span>:</p></body></html></string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QSpinBox" name="m_BvalueBox"> + <property name="toolTip"> + <string>b-value in s/mm²</string> + </property> + <property name="minimum"> + <number>0</number> + </property> + <property name="maximum"> + <number>10000</number> + </property> + <property name="singleStep"> + <number>100</number> + </property> + <property name="value"> + <number>1000</number> </property> - <layout class="QGridLayout" name="gridLayout_19"> - <property name="leftMargin"> - <number>6</number> - </property> - <property name="topMargin"> - <number>9</number> - </property> - <property name="rightMargin"> - <number>6</number> - </property> - <property name="bottomMargin"> - <number>6</number> - </property> - <item row="1" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_36"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>Degree:</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_29"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>x</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_28"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>Axis:</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QDoubleSpinBox" name="m_MaxRotationBoxX"> - <property name="toolTip"> - <string>Maximum rotation around x-axis.</string> - </property> - <property name="decimals"> - <number>1</number> - </property> - <property name="minimum"> - <double>-360.000000000000000</double> - </property> - <property name="maximum"> - <double>360.000000000000000</double> - </property> - <property name="singleStep"> - <double>1.000000000000000</double> - </property> - <property name="value"> - <double>0.000000000000000</double> - </property> - </widget> - </item> - <item row="1" column="3"> - <widget class="QDoubleSpinBox" name="m_MaxRotationBoxZ"> - <property name="toolTip"> - <string>Maximum rotation around z-axis.</string> - </property> - <property name="decimals"> - <number>1</number> - </property> - <property name="minimum"> - <double>-360.000000000000000</double> - </property> - <property name="maximum"> - <double>360.000000000000000</double> - </property> - <property name="singleStep"> - <double>1.000000000000000</double> - </property> - <property name="value"> - <double>15.000000000000000</double> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_30"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>y</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_31"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>z</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QDoubleSpinBox" name="m_MaxRotationBoxY"> - <property name="toolTip"> - <string>Maximum rotation around y-axis.</string> - </property> - <property name="decimals"> - <number>1</number> - </property> - <property name="minimum"> - <double>-360.000000000000000</double> - </property> - <property name="maximum"> - <double>360.000000000000000</double> - </property> - <property name="singleStep"> - <double>1.000000000000000</double> - </property> - <property name="value"> - <double>0.000000000000000</double> - </property> - </widget> - </item> - </layout> </widget> </item> - <item row="4" column="0"> - <widget class="QGroupBox" name="m_TranslationArtifactFrame"> - <property name="styleSheet"> - <string notr="true">QGroupBox { - background-color: transparent; -}</string> + <item row="1" column="0"> + <widget class="QLabel" name="m_TensorsToDWINumDirsLabel"> + <property name="text"> + <string>Gradient Directions:</string> </property> - <property name="title"> - <string>Translation</string> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSpinBox" name="m_NumGradientsBox"> + <property name="toolTip"> + <string>Number of gradient directions distributed over the half sphere.</string> + </property> + <property name="minimum"> + <number>0</number> + </property> + <property name="maximum"> + <number>10000</number> + </property> + <property name="singleStep"> + <number>1</number> + </property> + <property name="value"> + <number>30</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="8" column="0"> + <widget class="QCheckBox" name="m_AdvancedOptionsBox_2"> + <property name="text"> + <string>Advanced Options</string> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="m_DiffusionPropsMessage"> + <property name="styleSheet"> + <string notr="true">color: rgb(255, 0, 0);</string> + </property> + <property name="text"> + <string>Using gradients of selected DWI!</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QFrame" name="m_GeometryFrame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout" name="gridLayout_7"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="2" column="2"> + <widget class="QDoubleSpinBox" name="m_SpacingY"> + <property name="decimals"> + <number>3</number> + </property> + <property name="minimum"> + <double>0.100000000000000</double> + </property> + <property name="maximum"> + <double>50.000000000000000</double> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + <property name="value"> + <double>2.000000000000000</double> </property> - <layout class="QGridLayout" name="gridLayout_28"> - <property name="leftMargin"> - <number>6</number> - </property> - <property name="rightMargin"> - <number>6</number> - </property> - <property name="bottomMargin"> - <number>6</number> - </property> - <item row="1" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_48"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>Distance:</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_51"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>x</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_52"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>y</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_47"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>Axis:</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_53"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>z</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QDoubleSpinBox" name="m_MaxTranslationBoxX"> - <property name="toolTip"> - <string>Maximum translation along x-axis.</string> - </property> - <property name="decimals"> - <number>1</number> - </property> - <property name="minimum"> - <double>-1000.000000000000000</double> - </property> - <property name="maximum"> - <double>1000.000000000000000</double> - </property> - <property name="singleStep"> - <double>1.000000000000000</double> - </property> - <property name="value"> - <double>0.000000000000000</double> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QDoubleSpinBox" name="m_MaxTranslationBoxY"> - <property name="toolTip"> - <string>Maximum translation along y-axis.</string> - </property> - <property name="decimals"> - <number>1</number> - </property> - <property name="minimum"> - <double>-1000.000000000000000</double> - </property> - <property name="maximum"> - <double>1000.000000000000000</double> - </property> - <property name="singleStep"> - <double>1.000000000000000</double> - </property> - <property name="value"> - <double>0.000000000000000</double> - </property> - </widget> - </item> - <item row="1" column="3"> - <widget class="QDoubleSpinBox" name="m_MaxTranslationBoxZ"> - <property name="toolTip"> - <string>Maximum translation along z-axis.</string> - </property> - <property name="decimals"> - <number>1</number> - </property> - <property name="minimum"> - <double>-1000.000000000000000</double> - </property> - <property name="maximum"> - <double>1000.000000000000000</double> - </property> - <property name="singleStep"> - <double>1.000000000000000</double> - </property> - <property name="value"> - <double>0.000000000000000</double> - </property> - </widget> - </item> - </layout> </widget> </item> <item row="2" column="0"> - <widget class="QFrame" name="frame_7"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Image Spacing:</string> </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> + </widget> + </item> + <item row="2" column="3"> + <widget class="QDoubleSpinBox" name="m_SpacingZ"> + <property name="decimals"> + <number>3</number> + </property> + <property name="minimum"> + <double>0.100000000000000</double> + </property> + <property name="maximum"> + <double>50.000000000000000</double> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + <property name="value"> + <double>2.000000000000000</double> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QDoubleSpinBox" name="m_SpacingX"> + <property name="decimals"> + <number>3</number> + </property> + <property name="minimum"> + <double>0.100000000000000</double> + </property> + <property name="maximum"> + <double>50.000000000000000</double> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + <property name="value"> + <double>2.000000000000000</double> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Image Dimensions:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSpinBox" name="m_SizeX"> + <property name="toolTip"> + <string>Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions.</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>1000</number> + </property> + <property name="singleStep"> + <number>1</number> + </property> + <property name="value"> + <number>20</number> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QSpinBox" name="m_SizeY"> + <property name="toolTip"> + <string>Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions.</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>1000</number> + </property> + <property name="singleStep"> + <number>1</number> + </property> + <property name="value"> + <number>20</number> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QSpinBox" name="m_SizeZ"> + <property name="toolTip"> + <string>Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions.</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>1000</number> + </property> + <property name="singleStep"> + <number>1</number> + </property> + <property name="value"> + <number>3</number> </property> - <layout class="QGridLayout" name="gridLayout_31"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Motion volumes:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="m_MotionVolumesBox"> - <property name="toolTip"> - <string>Type in the volume indices that should be affected by motion (e.g. "0 3 7" whithout quotation marks). Leave blank for motion in all volumes. Type in "random" to randomly select volumes for motion. A list of negative numbers (e.g. -1 -2 -3) excludes volumes (e.g. 1 2 3) selects all remaining volumes.</string> - </property> - <property name="text"> - <string>random</string> - </property> - </widget> - </item> - </layout> </widget> </item> </layout> </widget> </item> - <item row="4" column="0"> - <widget class="QFrame" name="m_SpikeFrame"> + <item row="5" column="0"> + <widget class="QCheckBox" name="m_UseBvalsBvecsBox"> + <property name="text"> + <string>Use bvals/bvecs files</string> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QFrame" name="m_LoadGradientsFrame"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> - <layout class="QFormLayout" name="formLayout_9"> + <layout class="QGridLayout" name="gridLayout_3"> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> - <item row="0" column="0"> - <widget class="QLabel" name="m_NoiseLabel_2"> + <item row="0" column="2"> + <widget class="QToolButton" name="m_LoadBvalsButton"> <property name="text"> - <string>Num. Spikes:</string> + <string>...</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QToolButton" name="m_LoadBvecsButton"> + <property name="text"> + <string>...</string> </property> </widget> </item> <item row="0" column="1"> - <widget class="QSpinBox" name="m_SpikeNumBox"> + <widget class="QLineEdit" name="m_LoadBvalsEdit"> + <property name="text"> + <string>-</string> + </property> + <property name="readOnly"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_12"> <property name="toolTip"> - <string>The number of randomly occurring signal spikes.</string> + <string/> </property> - <property name="value"> - <number>1</number> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>Bvecs:</string> + </property> + <property name="wordWrap"> + <bool>false</bool> </property> </widget> </item> - <item row="1" column="1"> - <widget class="QDoubleSpinBox" name="m_SpikeScaleBox"> + <item row="0" column="0"> + <widget class="QLabel" name="label_11"> <property name="toolTip"> - <string>Spike amplitude relative to the largest signal amplitude of the corresponding k-space slice.</string> + <string/> </property> - <property name="singleStep"> - <double>0.100000000000000</double> + <property name="statusTip"> + <string/> </property> - <property name="value"> - <double>0.100000000000000</double> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>Bvals:</string> + </property> + <property name="wordWrap"> + <bool>false</bool> </property> </widget> </item> - <item row="1" column="0"> - <widget class="QLabel" name="m_NoiseLabel_4"> + <item row="2" column="1"> + <widget class="QLineEdit" name="m_LoadBvecsEdit"> <property name="text"> - <string>Scale:</string> + <string>-</string> + </property> + <property name="readOnly"> + <bool>false</bool> </property> </widget> </item> </layout> </widget> </item> - <item row="10" column="0"> - <widget class="QFrame" name="m_AliasingFrame"> - <property name="enabled"> - <bool>true</bool> - </property> + </layout> + </widget> + </item> + <item row="5" column="0"> + <widget class="QGroupBox" name="groupBox_6"> + <property name="styleSheet"> + <string notr="true">QGroupBox { + background-color: transparent; +}</string> + </property> + <property name="title"> + <string>Extra-axonal Compartments</string> + </property> + <layout class="QGridLayout" name="gridLayout_14"> + <property name="leftMargin"> + <number>6</number> + </property> + <property name="topMargin"> + <number>6</number> + </property> + <property name="rightMargin"> + <number>6</number> + </property> + <property name="bottomMargin"> + <number>6</number> + </property> + <item row="18" column="0"> + <widget class="QFrame" name="m_Comp4FractionFrame"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> - <layout class="QFormLayout" name="formLayout_10"> - <property name="horizontalSpacing"> - <number>6</number> - </property> + <layout class="QGridLayout" name="gridLayout_30"> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> <item row="0" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_27"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> + <widget class="QLabel" name="m_NoiseLabel_9"> <property name="text"> - <string>Shrink FOV (%):</string> - </property> - <property name="wordWrap"> - <bool>false</bool> + <string>Volume Fraction:</string> </property> </widget> </item> <item row="0" column="1"> - <widget class="QDoubleSpinBox" name="m_WrapBox"> + <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_Comp4VolumeFraction"> <property name="toolTip"> - <string>Shrink FOV by this percentage.</string> - </property> - <property name="decimals"> - <number>1</number> - </property> - <property name="minimum"> - <double>0.000000000000000</double> - </property> - <property name="maximum"> - <double>90.000000000000000</double> - </property> - <property name="singleStep"> - <double>0.100000000000000</double> - </property> - <property name="value"> - <double>25.000000000000000</double> + <string/> </property> </widget> </item> </layout> </widget> </item> - <item row="5" column="0"> - <widget class="Line" name="line_8"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> + <item row="6" column="0"> + <widget class="QComboBox" name="m_Compartment3Box"> + <property name="toolTip"> + <string>Select signal model for extra-axonal compartment.</string> </property> + <item> + <property name="text"> + <string>Ball Model</string> + </property> + </item> + <item> + <property name="text"> + <string>Astrosticks Model</string> + </property> + </item> + <item> + <property name="text"> + <string>Dot Model</string> + </property> + </item> + <item> + <property name="text"> + <string>Prototype Signal</string> + </property> + </item> </widget> </item> + <item row="8" column="0"> + <widget class="QmitkAstrosticksModelParametersWidget" name="m_AstrosticksWidget1" native="true"/> + </item> + <item row="10" column="0"> + <widget class="QmitkPrototypeSignalParametersWidget" name="m_PrototypeWidget3" native="true"/> + </item> <item row="16" column="0"> - <widget class="QFrame" name="m_DriftFrame"> - <property name="enabled"> - <bool>true</bool> + <widget class="QmitkDotModelParametersWidget" name="m_DotWidget2" native="true"/> + </item> + <item row="9" column="0"> + <widget class="QmitkDotModelParametersWidget" name="m_DotWidget1" native="true"/> + </item> + <item row="12" column="0"> + <widget class="Line" name="line_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> + </widget> + </item> + <item row="11" column="0"> + <widget class="QFrame" name="m_Comp3FractionFrame"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> - <layout class="QFormLayout" name="formLayout_11"> - <property name="horizontalSpacing"> - <number>6</number> - </property> + <layout class="QGridLayout" name="gridLayout_29"> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> <item row="0" column="0"> - <widget class="QLabel" name="label_35"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> + <widget class="QLabel" name="m_NoiseLabel_8"> <property name="text"> - <string>Signal Reduction (%):</string> - </property> - <property name="wordWrap"> - <bool>false</bool> + <string>Volume Fraction:</string> </property> </widget> </item> <item row="0" column="1"> - <widget class="QDoubleSpinBox" name="m_DriftFactor"> + <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_Comp3VolumeFraction"> <property name="toolTip"> - <string>Global signal in last simulated volume is specified percentage lower than in the first volume.</string> - </property> - <property name="decimals"> - <number>1</number> - </property> - <property name="maximum"> - <double>100.000000000000000</double> - </property> - <property name="singleStep"> - <double>1.000000000000000</double> - </property> - <property name="value"> - <double>6.000000000000000</double> + <string>Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers.</string> </property> </widget> </item> </layout> </widget> </item> + <item row="14" column="0"> + <widget class="QmitkBallModelParametersWidget" name="m_BallWidget2" native="true"/> + </item> + <item row="7" column="0"> + <widget class="QmitkBallModelParametersWidget" name="m_BallWidget1" native="true"/> + </item> + <item row="15" column="0"> + <widget class="QmitkAstrosticksModelParametersWidget" name="m_AstrosticksWidget2" native="true"/> + </item> <item row="13" column="0"> - <widget class="QFrame" name="m_DistortionsFrame"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> + <widget class="QComboBox" name="m_Compartment4Box"> + <property name="toolTip"> + <string>Select signal model for extra-axonal compartment.</string> </property> - <layout class="QFormLayout" name="formLayout_7"> - <property name="horizontalSpacing"> - <number>6</number> + <item> + <property name="text"> + <string>--</string> </property> - <property name="leftMargin"> - <number>0</number> + </item> + <item> + <property name="text"> + <string>Ball Model</string> </property> - <property name="topMargin"> - <number>0</number> + </item> + <item> + <property name="text"> + <string>Astrosticks Model</string> </property> - <property name="rightMargin"> - <number>0</number> + </item> + <item> + <property name="text"> + <string>Dot Model</string> </property> - <property name="bottomMargin"> - <number>0</number> + </item> + <item> + <property name="text"> + <string>Prototype Signal</string> </property> - <item row="0" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_25"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>Frequency Map:</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QmitkDataStorageComboBox" name="m_FrequencyMapBox"> - <property name="toolTip"> - <string>Select image specifying the frequency inhomogeneities (in Hz).</string> - </property> - </widget> - </item> - </layout> + </item> </widget> </item> - <item row="23" column="0"> - <widget class="QFrame" name="m_EddyFrame"> + <item row="17" column="0"> + <widget class="QmitkPrototypeSignalParametersWidget" name="m_PrototypeWidget4" native="true"/> + </item> + </layout> + </widget> + </item> + <item row="6" column="0"> + <widget class="QGroupBox" name="groupBox_3"> + <property name="styleSheet"> + <string notr="true">QGroupBox { + background-color: transparent; +}</string> + </property> + <property name="title"> + <string>Noise and other Artifacts</string> + </property> + <layout class="QGridLayout" name="gridLayout_6"> + <property name="leftMargin"> + <number>6</number> + </property> + <property name="topMargin"> + <number>6</number> + </property> + <property name="rightMargin"> + <number>6</number> + </property> + <property name="bottomMargin"> + <number>6</number> + </property> + <item row="8" column="0"> + <widget class="Line" name="line_7"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="19" column="0"> + <widget class="QFrame" name="m_MotionArtifactFrame"> <property name="enabled"> <bool>true</bool> </property> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> - <layout class="QFormLayout" name="formLayout_8"> - <property name="fieldGrowthPolicy"> - <enum>QFormLayout::AllNonFixedFieldsGrow</enum> - </property> - <property name="horizontalSpacing"> - <number>6</number> - </property> + <layout class="QGridLayout" name="gridLayout_18"> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> - <number>0</number> + <number>6</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> + <property name="horizontalSpacing"> + <number>6</number> + </property> <item row="0" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_26"> + <widget class="QCheckBox" name="m_RandomMotion"> <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> + <string>Toggle between random movement and linear movement.</string> </property> <property name="text"> - <string>Gradient:</string> + <string>Randomize motion</string> </property> - <property name="wordWrap"> - <bool>false</bool> + <property name="checked"> + <bool>true</bool> </property> </widget> </item> - <item row="0" column="1"> - <widget class="QDoubleSpinBox" name="m_EddyGradientStrength"> - <property name="toolTip"> - <string>Eddy current induced magnetic field gradient (in mT/m).</string> - </property> - <property name="decimals"> - <number>4</number> - </property> - <property name="maximum"> - <double>1000.000000000000000</double> - </property> - <property name="singleStep"> - <double>0.001000000000000</double> - </property> - <property name="value"> - <double>0.010000000000000</double> + <item row="3" column="0"> + <widget class="QGroupBox" name="m_RotationArtifactFrame"> + <property name="styleSheet"> + <string notr="true">QGroupBox { + background-color: transparent; +}</string> </property> - </widget> - </item> - </layout> - </widget> - </item> - <item row="11" column="0"> - <widget class="Line" name="line_6"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item row="22" column="0"> - <widget class="QCheckBox" name="m_AddEddy"> - <property name="toolTip"> - <string/> - </property> - <property name="text"> - <string>Add Eddy Current Effects</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="12" column="0"> - <widget class="QCheckBox" name="m_AddDistortions"> - <property name="text"> - <string>Add Distortions</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QCheckBox" name="m_AddSpikes"> - <property name="text"> - <string>Add Spikes</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="15" column="0"> - <widget class="QCheckBox" name="m_AddDrift"> - <property name="text"> - <string>Add Signal Drift</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QFrame" name="m_NoiseFrame"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QFormLayout" name="formLayout_5"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="1" column="0"> - <widget class="QLabel" name="m_NoiseLabel"> - <property name="text"> - <string>Variance:</string> + <property name="title"> + <string>Rotation</string> </property> + <layout class="QGridLayout" name="gridLayout_19"> + <property name="leftMargin"> + <number>6</number> + </property> + <property name="topMargin"> + <number>9</number> + </property> + <property name="rightMargin"> + <number>6</number> + </property> + <property name="bottomMargin"> + <number>6</number> + </property> + <item row="1" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_36"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>Degree:</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_29"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>x</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_28"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>Axis:</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QDoubleSpinBox" name="m_MaxRotationBoxX"> + <property name="toolTip"> + <string>Maximum rotation around x-axis.</string> + </property> + <property name="decimals"> + <number>1</number> + </property> + <property name="minimum"> + <double>-360.000000000000000</double> + </property> + <property name="maximum"> + <double>360.000000000000000</double> + </property> + <property name="singleStep"> + <double>1.000000000000000</double> + </property> + <property name="value"> + <double>0.000000000000000</double> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QDoubleSpinBox" name="m_MaxRotationBoxZ"> + <property name="toolTip"> + <string>Maximum rotation around z-axis.</string> + </property> + <property name="decimals"> + <number>1</number> + </property> + <property name="minimum"> + <double>-360.000000000000000</double> + </property> + <property name="maximum"> + <double>360.000000000000000</double> + </property> + <property name="singleStep"> + <double>1.000000000000000</double> + </property> + <property name="value"> + <double>15.000000000000000</double> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_30"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>y</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_31"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>z</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QDoubleSpinBox" name="m_MaxRotationBoxY"> + <property name="toolTip"> + <string>Maximum rotation around y-axis.</string> + </property> + <property name="decimals"> + <number>1</number> + </property> + <property name="minimum"> + <double>-360.000000000000000</double> + </property> + <property name="maximum"> + <double>360.000000000000000</double> + </property> + <property name="singleStep"> + <double>1.000000000000000</double> + </property> + <property name="value"> + <double>0.000000000000000</double> + </property> + </widget> + </item> + </layout> </widget> </item> - <item row="1" column="1"> - <widget class="QDoubleSpinBox" name="m_NoiseLevel"> - <property name="toolTip"> - <string>Variance of selected noise distribution.</string> - </property> - <property name="decimals"> - <number>10</number> - </property> - <property name="minimum"> - <double>0.000000000000000</double> - </property> - <property name="maximum"> - <double>999999999.000000000000000</double> - </property> - <property name="singleStep"> - <double>0.001000000000000</double> - </property> - <property name="value"> - <double>50.000000000000000</double> + <item row="4" column="0"> + <widget class="QGroupBox" name="m_TranslationArtifactFrame"> + <property name="styleSheet"> + <string notr="true">QGroupBox { + background-color: transparent; +}</string> </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="m_NoiseLabel_5"> - <property name="text"> - <string>Distribution:</string> + <property name="title"> + <string>Translation</string> </property> + <layout class="QGridLayout" name="gridLayout_28"> + <property name="leftMargin"> + <number>6</number> + </property> + <property name="rightMargin"> + <number>6</number> + </property> + <property name="bottomMargin"> + <number>6</number> + </property> + <item row="1" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_48"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>Distance:</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_51"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>x</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_52"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>y</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_47"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>Axis:</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_53"> + <property name="toolTip"> + <string/> + </property> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>z</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QDoubleSpinBox" name="m_MaxTranslationBoxX"> + <property name="toolTip"> + <string>Maximum translation along x-axis.</string> + </property> + <property name="decimals"> + <number>1</number> + </property> + <property name="minimum"> + <double>-1000.000000000000000</double> + </property> + <property name="maximum"> + <double>1000.000000000000000</double> + </property> + <property name="singleStep"> + <double>1.000000000000000</double> + </property> + <property name="value"> + <double>0.000000000000000</double> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QDoubleSpinBox" name="m_MaxTranslationBoxY"> + <property name="toolTip"> + <string>Maximum translation along y-axis.</string> + </property> + <property name="decimals"> + <number>1</number> + </property> + <property name="minimum"> + <double>-1000.000000000000000</double> + </property> + <property name="maximum"> + <double>1000.000000000000000</double> + </property> + <property name="singleStep"> + <double>1.000000000000000</double> + </property> + <property name="value"> + <double>0.000000000000000</double> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QDoubleSpinBox" name="m_MaxTranslationBoxZ"> + <property name="toolTip"> + <string>Maximum translation along z-axis.</string> + </property> + <property name="decimals"> + <number>1</number> + </property> + <property name="minimum"> + <double>-1000.000000000000000</double> + </property> + <property name="maximum"> + <double>1000.000000000000000</double> + </property> + <property name="singleStep"> + <double>1.000000000000000</double> + </property> + <property name="value"> + <double>0.000000000000000</double> + </property> + </widget> + </item> + </layout> </widget> </item> - <item row="0" column="1"> - <widget class="QComboBox" name="m_NoiseDistributionBox"> - <property name="toolTip"> - <string>Noise distribution</string> + <item row="2" column="0"> + <widget class="QFrame" name="frame_7"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> </property> - <item> - <property name="text"> - <string>Complex Gaussian</string> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout" name="gridLayout_31"> + <property name="leftMargin"> + <number>0</number> </property> - </item> - <item> - <property name="text"> - <string>Rician</string> + <property name="topMargin"> + <number>0</number> </property> - </item> - </widget> - </item> - </layout> - </widget> - </item> - <item row="14" column="0"> - <widget class="Line" name="line_5"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item row="17" column="0"> - <widget class="Line" name="line_10"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item row="7" column="0"> - <widget class="QFrame" name="m_GhostFrame"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QFormLayout" name="formLayout_6"> - <property name="horizontalSpacing"> - <number>6</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_23"> - <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>K-Space Line Offset:</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QDoubleSpinBox" name="m_kOffsetBox"> - <property name="toolTip"> - <string>A larger offset increases the inensity of the ghost image.</string> - </property> - <property name="decimals"> - <number>3</number> - </property> - <property name="maximum"> - <double>1.000000000000000</double> - </property> - <property name="singleStep"> - <double>0.010000000000000</double> - </property> - <property name="value"> - <double>0.250000000000000</double> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item row="18" column="0"> - <widget class="QCheckBox" name="m_AddMotion"> - <property name="text"> - <string>Add Motion Artifacts</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="6" column="0"> - <widget class="QCheckBox" name="m_AddGhosts"> - <property name="text"> - <string>Add N/2 Ghosts</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="21" column="0"> - <widget class="Line" name="line_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item row="25" column="0"> - <widget class="QCheckBox" name="m_AddGibbsRinging"> - <property name="toolTip"> - <string>Add ringing artifacts occuring at strong edges in the image.</string> - </property> - <property name="text"> - <string>Add Gibbs Ringing</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="Line" name="line_9"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QCheckBox" name="m_AddNoise"> - <property name="text"> - <string>Add Noise</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="24" column="0"> - <widget class="Line" name="line"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item row="9" column="0"> - <widget class="QCheckBox" name="m_AddAliasing"> - <property name="text"> - <string>Add Aliasing</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="26" column="0"> - <widget class="QSpinBox" name="m_ZeroRinging"> - <property name="toolTip"> - <string>If > 0, ringing is simulated by by setting the defined percentage of higher frequencies to 0 in k-space. Otherwise, the input to the k-space simulation is generated with twice the resolution and cropped during k-space simulation (much slower).</string> - </property> - <property name="maximum"> - <number>100</number> - </property> - <property name="value"> - <number>10</number> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item row="1" column="0"> - <widget class="QGroupBox" name="groupBox"> - <property name="styleSheet"> - <string notr="true">QGroupBox { - background-color: transparent; -}</string> - </property> - <property name="title"> - <string>Image Settings</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <property name="leftMargin"> - <number>6</number> - </property> - <property name="topMargin"> - <number>6</number> - </property> - <property name="rightMargin"> - <number>6</number> - </property> - <property name="bottomMargin"> - <number>6</number> - </property> - <item row="2" column="0"> - <widget class="QLabel" name="m_GeometryMessage"> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>Using geometry of selected image!</string> - </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Motion volumes:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="m_MotionVolumesBox"> + <property name="toolTip"> + <string>Type in the volume indices that should be affected by motion (e.g. "0 3 7" whithout quotation marks). Leave blank for motion in all volumes. Type in "random" to randomly select volumes for motion. A list of negative numbers (e.g. -1 -2 -3) excludes volumes (e.g. 1 2 3) selects all remaining volumes.</string> + </property> + <property name="text"> + <string>random</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> </widget> </item> - <item row="9" column="0"> - <widget class="QFrame" name="m_AdvancedSignalOptionsFrame"> + <item row="4" column="0"> + <widget class="QFrame" name="m_SpikeFrame"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> - <layout class="QGridLayout" name="gridLayout_23"> + <layout class="QFormLayout" name="formLayout_9"> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> - <property name="horizontalSpacing"> - <number>6</number> - </property> - <item row="1" column="1"> - <widget class="QSpinBox" name="m_SignalScaleBox"> - <property name="toolTip"> - <string>TE in milliseconds</string> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>10000</number> - </property> - <property name="singleStep"> - <number>1</number> - </property> - <property name="value"> - <number>100</number> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QComboBox" name="m_AcquisitionTypeBox"> - <item> - <property name="text"> - <string>Single Shot EPI</string> - </property> - </item> - <item> - <property name="text"> - <string>Spin Echo</string> - </property> - </item> - </widget> - </item> - <item row="12" column="0"> - <widget class="QLabel" name="m_TensorsToDWINumDirsLabel_4"> + <item row="0" column="0"> + <widget class="QLabel" name="m_NoiseLabel_2"> <property name="text"> - <string>Fiber Radius:</string> + <string>Num. Spikes:</string> </property> </widget> </item> - <item row="2" column="1"> - <widget class="QSpinBox" name="m_NumCoilsBox"> + <item row="0" column="1"> + <widget class="QSpinBox" name="m_SpikeNumBox"> <property name="toolTip"> - <string>Number of coil elements used for the acquisiton.</string> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>128</number> - </property> - <property name="singleStep"> - <number>1</number> + <string>The number of randomly occurring signal spikes.</string> </property> <property name="value"> <number>1</number> </property> </widget> </item> - <item row="4" column="1"> - <widget class="QSpinBox" name="m_TEbox"> - <property name="toolTip"> - <string>TE in milliseconds</string> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>999999999</number> - </property> - <property name="singleStep"> - <number>1</number> - </property> - <property name="value"> - <number>100</number> - </property> - </widget> - </item> - <item row="16" column="0"> - <widget class="QCheckBox" name="m_VolumeFractionsBox"> - <property name="toolTip"> - <string>Output phase image and volume fraction maps.</string> - </property> - <property name="text"> - <string>Output Additional Images</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="8" column="1"> - <widget class="QDoubleSpinBox" name="m_LineReadoutTimeBox"> + <item row="1" column="1"> + <widget class="QDoubleSpinBox" name="m_SpikeScaleBox"> <property name="toolTip"> - <string>Dwell time (time to read one line in k-space) in ms.</string> - </property> - <property name="maximum"> - <double>100.000000000000000</double> + <string>Spike amplitude relative to the largest signal amplitude of the corresponding k-space slice.</string> </property> <property name="singleStep"> <double>0.100000000000000</double> </property> <property name="value"> - <double>1.000000000000000</double> - </property> - </widget> - </item> - <item row="9" column="1"> - <widget class="QDoubleSpinBox" name="m_PartialFourier"> - <property name="toolTip"> - <string>Partial fourier factor (0.5-1)</string> - </property> - <property name="decimals"> - <number>3</number> - </property> - <property name="minimum"> - <double>0.500000000000000</double> - </property> - <property name="maximum"> - <double>1.000000000000000</double> - </property> - <property name="singleStep"> <double>0.100000000000000</double> </property> - <property name="value"> - <double>1.000000000000000</double> - </property> </widget> </item> - <item row="0" column="0"> - <widget class="QLabel" name="m_TensorsToDWINumDirsLabel_6"> + <item row="1" column="0"> + <widget class="QLabel" name="m_NoiseLabel_4"> <property name="text"> - <string>Acquisition Type:</string> - </property> - </widget> - </item> - <item row="12" column="1"> - <widget class="QDoubleSpinBox" name="m_FiberRadius"> - <property name="toolTip"> - <string>Fiber radius used to calculate volume fractions (in µm). Set to 0 for automatic radius estimation.</string> - </property> - <property name="maximum"> - <double>9999.000000000000000</double> + <string>Scale:</string> </property> </widget> </item> - <item row="9" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_32"> + </layout> + </widget> + </item> + <item row="10" column="0"> + <widget class="QFrame" name="m_AliasingFrame"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QFormLayout" name="formLayout_10"> + <property name="horizontalSpacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_27"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> - <string>Partial Fourier:</string> + <string>Shrink FOV (%):</string> </property> <property name="wordWrap"> <bool>false</bool> </property> </widget> </item> - <item row="13" column="0"> - <widget class="QCheckBox" name="m_ReversePhaseBox"> - <property name="toolTip"> - <string>Output one image per compartment containing the corresponding volume fractions per voxel.</string> - </property> - <property name="text"> - <string>Reverse Phase Encoding Direction</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_34"> + <item row="0" column="1"> + <widget class="QDoubleSpinBox" name="m_WrapBox"> <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string><html><head/><body><p>Coil Sensitivity:</p></body></html></string> - </property> - <property name="wordWrap"> - <bool>false</bool> + <string>Shrink FOV by this percentage.</string> </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_13"> - <property name="toolTip"> - <string/> + <property name="decimals"> + <number>1</number> </property> - <property name="statusTip"> - <string/> + <property name="minimum"> + <double>0.000000000000000</double> </property> - <property name="whatsThis"> - <string/> + <property name="maximum"> + <double>90.000000000000000</double> </property> - <property name="text"> - <string><html><head/><body><p>Number of Channels:</p></body></html></string> + <property name="singleStep"> + <double>0.100000000000000</double> </property> - <property name="wordWrap"> - <bool>false</bool> + <property name="value"> + <double>25.000000000000000</double> </property> </widget> </item> - <item row="6" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_14"> + </layout> + </widget> + </item> + <item row="5" column="0"> + <widget class="Line" name="line_8"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="16" column="0"> + <widget class="QFrame" name="m_DriftFrame"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QFormLayout" name="formLayout_11"> + <property name="horizontalSpacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_35"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> - <string><html><head/><body><p>Repetition Time <span style=" font-style:italic;">TR</span>: </p></body></html></string> + <string>Signal Reduction (%):</string> </property> <property name="wordWrap"> <bool>false</bool> </property> </widget> </item> - <item row="6" column="1"> - <widget class="QSpinBox" name="m_TRbox"> - <property name="toolTip"> - <string>TR in milliseconds</string> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>999999999</number> - </property> - <property name="singleStep"> - <number>1</number> - </property> - <property name="value"> - <number>4000</number> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="m_TensorsToDWINumDirsLabel_5"> - <property name="text"> - <string>Signal Scale:</string> - </property> - </widget> - </item> - <item row="10" column="1"> - <widget class="QSpinBox" name="m_T2starBox"> + <item row="0" column="1"> + <widget class="QDoubleSpinBox" name="m_DriftFactor"> <property name="toolTip"> - <string>Relaxation time due to magnetic field inhomogeneities (T2', in milliseconds).</string> + <string>Global signal in last simulated volume is specified percentage lower than in the first volume.</string> </property> - <property name="minimum"> + <property name="decimals"> <number>1</number> </property> <property name="maximum"> - <number>10000</number> + <double>100.000000000000000</double> </property> <property name="singleStep"> - <number>1</number> + <double>1.000000000000000</double> </property> <property name="value"> - <number>50</number> + <double>6.000000000000000</double> </property> </widget> </item> - <item row="10" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_12"> + </layout> + </widget> + </item> + <item row="13" column="0"> + <widget class="QFrame" name="m_DistortionsFrame"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QFormLayout" name="formLayout_7"> + <property name="horizontalSpacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_25"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> - <string><html><head/><body><p><span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> Relaxation: </p></body></html></string> + <string>Frequency Map:</string> </property> <property name="wordWrap"> <bool>false</bool> </property> </widget> </item> - <item row="14" column="0"> - <widget class="QCheckBox" name="m_RelaxationBox"> + <item row="0" column="1"> + <widget class="QmitkDataStorageComboBox" name="m_FrequencyMapBox"> <property name="toolTip"> - <string><html><head/><body><p><span style=" font-style:italic;">TE</span>, <span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> and <span style=" font-style:italic;">T2</span> will have no effect if unchecked.</p></body></html></string> - </property> - <property name="text"> - <string>Simulate Signal Relaxation</string> - </property> - <property name="checked"> - <bool>true</bool> + <string>Select image specifying the frequency inhomogeneities (in Hz).</string> </property> </widget> </item> - <item row="4" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_33"> + </layout> + </widget> + </item> + <item row="23" column="0"> + <widget class="QFrame" name="m_EddyFrame"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QFormLayout" name="formLayout_8"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <property name="horizontalSpacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_26"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> - <string><html><head/><body><p>Echo Time <span style=" font-style:italic;">TE</span>: </p></body></html></string> + <string>Gradient:</string> </property> <property name="wordWrap"> <bool>false</bool> </property> </widget> </item> - <item row="8" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_15"> + <item row="0" column="1"> + <widget class="QDoubleSpinBox" name="m_EddyGradientStrength"> <property name="toolTip"> - <string/> + <string>Eddy current induced magnetic field gradient (in mT/m).</string> </property> - <property name="statusTip"> - <string/> + <property name="decimals"> + <number>4</number> </property> - <property name="whatsThis"> - <string/> + <property name="maximum"> + <double>1000.000000000000000</double> </property> - <property name="text"> - <string>Dwell Time:</string> + <property name="singleStep"> + <double>0.001000000000000</double> </property> - <property name="wordWrap"> - <bool>false</bool> + <property name="value"> + <double>0.010000000000000</double> </property> </widget> </item> - <item row="3" column="1"> - <widget class="QComboBox" name="m_CoilSensBox"> - <item> - <property name="text"> - <string>Constant</string> - </property> - </item> - <item> - <property name="text"> - <string>Linear</string> - </property> - </item> - <item> - <property name="text"> - <string>Exponential</string> - </property> - </item> - </widget> - </item> - <item row="15" column="0"> - <widget class="QCheckBox" name="m_EnforcePureFiberVoxelsBox"> - <property name="toolTip"> - <string>Disable partial volume. Treat voxel content as fiber-only if at least one fiber is present.</string> - </property> + </layout> + </widget> + </item> + <item row="11" column="0"> + <widget class="Line" name="line_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="22" column="0"> + <widget class="QCheckBox" name="m_AddEddy"> + <property name="toolTip"> + <string/> + </property> + <property name="text"> + <string>Add Eddy Current Effects</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="12" column="0"> + <widget class="QCheckBox" name="m_AddDistortions"> + <property name="text"> + <string>Add Distortions</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QCheckBox" name="m_AddSpikes"> + <property name="text"> + <string>Add Spikes</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="15" column="0"> + <widget class="QCheckBox" name="m_AddDrift"> + <property name="text"> + <string>Add Signal Drift</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QFrame" name="m_NoiseFrame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QFormLayout" name="formLayout_5"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="1" column="0"> + <widget class="QLabel" name="m_NoiseLabel"> <property name="text"> - <string>Disable Partial Volume Effects</string> - </property> - <property name="checked"> - <bool>false</bool> + <string>Variance:</string> </property> </widget> </item> - <item row="7" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel_17"> + <item row="1" column="1"> + <widget class="QDoubleSpinBox" name="m_NoiseLevel"> <property name="toolTip"> - <string/> - </property> - <property name="statusTip"> - <string/> - </property> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string><html><head/><body><p>Inversion Time <span style=" font-style:italic;">TI</span>: </p></body></html></string> - </property> - <property name="wordWrap"> - <bool>false</bool> + <string>Variance of selected noise distribution.</string> </property> - </widget> - </item> - <item row="7" column="1"> - <widget class="QSpinBox" name="m_TIbox"> - <property name="toolTip"> - <string>Inversion time (in ms) for inversion recovery sequences. If 0, no inversion pulse is simulated.</string> + <property name="decimals"> + <number>10</number> </property> <property name="minimum"> - <number>0</number> + <double>0.000000000000000</double> </property> <property name="maximum"> - <number>999999999</number> + <double>999999999.000000000000000</double> </property> <property name="singleStep"> - <number>1</number> + <double>0.001000000000000</double> </property> <property name="value"> - <number>0</number> + <double>50.000000000000000</double> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="m_NoiseLabel_5"> + <property name="text"> + <string>Distribution:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="m_NoiseDistributionBox"> + <property name="toolTip"> + <string>Noise distribution</string> </property> + <item> + <property name="text"> + <string>Complex Gaussian</string> + </property> + </item> + <item> + <property name="text"> + <string>Rician</string> + </property> + </item> </widget> </item> </layout> </widget> </item> + <item row="14" column="0"> + <widget class="Line" name="line_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="17" column="0"> + <widget class="Line" name="line_10"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> <item row="7" column="0"> - <widget class="QFrame" name="m_GenerateGradientsFrame"> + <widget class="QFrame" name="m_GhostFrame"> + <property name="enabled"> + <bool>true</bool> + </property> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> - <layout class="QGridLayout" name="gridLayout_24"> + <layout class="QFormLayout" name="formLayout_6"> + <property name="horizontalSpacing"> + <number>6</number> + </property> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> - <property name="spacing"> - <number>6</number> - </property> - <item row="2" column="0"> - <widget class="QLabel" name="m_TensorsToDWIBValueLabel"> + <item row="0" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_23"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> - <string><html><head/><body><p>b-Value<span style=" font-style:italic;"> [s/mm</span><span style=" font-style:italic; vertical-align:super;">2</span><span style=" font-style:italic;">]</span>:</p></body></html></string> + <string>K-Space Line Offset:</string> </property> <property name="wordWrap"> <bool>false</bool> </property> </widget> </item> - <item row="2" column="1"> - <widget class="QSpinBox" name="m_BvalueBox"> - <property name="toolTip"> - <string>b-value in s/mm²</string> - </property> - <property name="minimum"> - <number>0</number> - </property> - <property name="maximum"> - <number>10000</number> - </property> - <property name="singleStep"> - <number>100</number> - </property> - <property name="value"> - <number>1000</number> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="m_TensorsToDWINumDirsLabel"> - <property name="text"> - <string>Gradient Directions:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QSpinBox" name="m_NumGradientsBox"> + <item row="0" column="1"> + <widget class="QDoubleSpinBox" name="m_kOffsetBox"> <property name="toolTip"> - <string>Number of gradient directions distributed over the half sphere.</string> + <string>A larger offset increases the inensity of the ghost image.</string> </property> - <property name="minimum"> - <number>0</number> + <property name="decimals"> + <number>3</number> </property> <property name="maximum"> - <number>10000</number> + <double>1.000000000000000</double> </property> <property name="singleStep"> - <number>1</number> + <double>0.010000000000000</double> </property> <property name="value"> - <number>30</number> + <double>0.250000000000000</double> </property> </widget> </item> </layout> </widget> </item> - <item row="8" column="0"> - <widget class="QCheckBox" name="m_AdvancedOptionsBox_2"> + <item row="18" column="0"> + <widget class="QCheckBox" name="m_AddMotion"> + <property name="text"> + <string>Add Motion Artifacts</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QCheckBox" name="m_AddGhosts"> + <property name="text"> + <string>Add N/2 Ghosts</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="21" column="0"> + <widget class="Line" name="line_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="25" column="0"> + <widget class="QCheckBox" name="m_AddGibbsRinging"> + <property name="toolTip"> + <string>Add ringing artifacts occuring at strong edges in the image.</string> + </property> + <property name="text"> + <string>Add Gibbs Ringing</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="Line" name="line_9"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QCheckBox" name="m_AddNoise"> + <property name="text"> + <string>Add Noise</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="24" column="0"> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="9" column="0"> + <widget class="QCheckBox" name="m_AddAliasing"> + <property name="text"> + <string>Add Aliasing</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="26" column="0"> + <widget class="QSpinBox" name="m_ZeroRinging"> + <property name="toolTip"> + <string>If > 0, ringing is simulated by by setting the defined percentage of higher frequencies to 0 in k-space. Otherwise, the input to the k-space simulation is generated with twice the resolution and cropped during k-space simulation (much slower).</string> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="value"> + <number>10</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="7" column="0"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0"> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout" name="gridLayout_4"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="1"> + <widget class="QCommandLinkButton" name="m_SaveParametersButton"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Start DWI generation from selected fiber bundle.</p><p>If no fiber bundle but an existing diffusion weighted image is selected, the enabled artifacts are added to this image.</p><p>If neither a fiber bundle nor a diffusion weighted image is selected, a grayscale image containing a simple gradient is generated.</p></body></html></string> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> + <property name="text"> + <string>Save Parameters</string> + </property> + <property name="icon"> + <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> + <normaloff>:/QmitkDiffusionImaging/general_icons/download.ico</normaloff>:/QmitkDiffusionImaging/general_icons/download.ico</iconset> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QCommandLinkButton" name="m_LoadParametersButton"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Start DWI generation from selected fiber bundle.</p><p>If no fiber bundle but an existing diffusion weighted image is selected, the enabled artifacts are added to this image.</p><p>If neither a fiber bundle nor a diffusion weighted image is selected, a grayscale image containing a simple gradient is generated.</p></body></html></string> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> <property name="text"> - <string>Advanced Options</string> + <string>Load Parameters</string> + </property> + <property name="icon"> + <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> + <normaloff>:/QmitkDiffusionImaging/general_icons/upload.ico</normaloff>:/QmitkDiffusionImaging/general_icons/upload.ico</iconset> </property> </widget> </item> - <item row="4" column="0"> - <widget class="QLabel" name="m_DiffusionPropsMessage"> + </layout> + </widget> + </item> + <item row="0" column="0"> + <widget class="QFrame" name="frame_9"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout" name="gridLayout_32"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="1" column="0"> + <widget class="QCommandLinkButton" name="m_GenerateImageButton"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Start DWI generation from selected fiber bundle.</p><p>If no fiber bundle but an existing diffusion weighted image is selected, the enabled artifacts are added to this image.</p><p>If neither a fiber bundle nor a diffusion weighted image is selected, a grayscale image containing a simple gradient is generated.</p></body></html></string> + </property> <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> + <string notr="true"/> </property> <property name="text"> - <string>Using gradients of selected DWI!</string> + <string>Start Simulation</string> + </property> + <property name="icon"> + <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> + <normaloff>:/QmitkDiffusionImaging/general_icons/right.ico</normaloff>:/QmitkDiffusionImaging/general_icons/right.ico</iconset> </property> </widget> </item> - <item row="3" column="0"> - <widget class="QFrame" name="m_GeometryFrame"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> + <item row="0" column="0"> + <widget class="QGroupBox" name="groupBox_2"> + <property name="styleSheet"> + <string notr="true">QGroupBox { + background-color: transparent; +}</string> </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> + <property name="title"> + <string>Input Data</string> </property> - <layout class="QGridLayout" name="gridLayout_7"> + <layout class="QGridLayout" name="gridLayout_10"> <property name="leftMargin"> - <number>0</number> + <number>6</number> </property> <property name="topMargin"> - <number>0</number> + <number>6</number> </property> <property name="rightMargin"> - <number>0</number> + <number>6</number> </property> <property name="bottomMargin"> - <number>0</number> + <number>6</number> </property> - <item row="2" column="2"> - <widget class="QDoubleSpinBox" name="m_SpacingY"> - <property name="decimals"> - <number>3</number> - </property> - <property name="minimum"> - <double>0.100000000000000</double> - </property> - <property name="maximum"> - <double>50.000000000000000</double> - </property> - <property name="singleStep"> - <double>0.100000000000000</double> - </property> - <property name="value"> - <double>2.000000000000000</double> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Image Spacing:</string> - </property> - </widget> - </item> - <item row="2" column="3"> - <widget class="QDoubleSpinBox" name="m_SpacingZ"> - <property name="decimals"> - <number>3</number> - </property> - <property name="minimum"> - <double>0.100000000000000</double> - </property> - <property name="maximum"> - <double>50.000000000000000</double> - </property> - <property name="singleStep"> - <double>0.100000000000000</double> - </property> - <property name="value"> - <double>2.000000000000000</double> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QDoubleSpinBox" name="m_SpacingX"> - <property name="decimals"> - <number>3</number> - </property> - <property name="minimum"> - <double>0.100000000000000</double> - </property> - <property name="maximum"> - <double>50.000000000000000</double> - </property> - <property name="singleStep"> - <double>0.100000000000000</double> - </property> - <property name="value"> - <double>2.000000000000000</double> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Image Dimensions:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QSpinBox" name="m_SizeX"> - <property name="toolTip"> - <string>Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions.</string> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>1000</number> - </property> - <property name="singleStep"> - <number>1</number> - </property> - <property name="value"> - <number>20</number> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QSpinBox" name="m_SizeY"> - <property name="toolTip"> - <string>Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions.</string> - </property> - <property name="minimum"> - <number>1</number> + <item row="4" column="2"> + <widget class="QFrame" name="frame_6"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> </property> - <property name="maximum"> - <number>1000</number> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> </property> - <property name="singleStep"> - <number>1</number> + <layout class="QGridLayout" name="gridLayout_20"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QLineEdit" name="m_SavePathEdit"> + <property name="text"> + <string>-</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QToolButton" name="m_OutputPathButton"> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="2" column="2"> + <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_MaskComboBox"> + <property name="toolTip"> + <string><html><head/><body><p>Select a binary image to define the area of signal generation. Outside of the mask image only noise will be actively generated.</p></body></html></string> </property> - <property name="value"> - <number>20</number> + <property name="sizeAdjustPolicy"> + <enum>QComboBox::AdjustToMinimumContentsLength</enum> </property> </widget> </item> - <item row="0" column="3"> - <widget class="QSpinBox" name="m_SizeZ"> + <item row="0" column="0" rowspan="2" colspan="2"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_16"> <property name="toolTip"> - <string>Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions.</string> + <string/> </property> - <property name="minimum"> - <number>1</number> + <property name="statusTip"> + <string/> </property> - <property name="maximum"> - <number>1000</number> + <property name="whatsThis"> + <string/> </property> - <property name="singleStep"> - <number>1</number> + <property name="text"> + <string>Fiber Bundle:</string> </property> - <property name="value"> - <number>3</number> + <property name="wordWrap"> + <bool>false</bool> </property> </widget> </item> - </layout> - </widget> - </item> - <item row="5" column="0"> - <widget class="QCheckBox" name="m_UseBvalsBvecsBox"> - <property name="text"> - <string>Use bvals/bvecs files</string> - </property> - </widget> - </item> - <item row="6" column="0"> - <widget class="QFrame" name="m_LoadGradientsFrame"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QGridLayout" name="gridLayout_3"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="0" column="2"> - <widget class="QToolButton" name="m_LoadBvalsButton"> - <property name="text"> - <string>...</string> + <item row="4" column="0"> + <widget class="QLabel" name="label_10"> + <property name="toolTip"> + <string/> </property> - </widget> - </item> - <item row="2" column="2"> - <widget class="QToolButton" name="m_LoadBvecsButton"> - <property name="text"> - <string>...</string> + <property name="statusTip"> + <string/> + </property> + <property name="whatsThis"> + <string/> </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="m_LoadBvalsEdit"> <property name="text"> - <string>-</string> + <string>Save path:</string> </property> - <property name="readOnly"> + <property name="wordWrap"> <bool>false</bool> </property> </widget> </item> <item row="2" column="0"> - <widget class="QLabel" name="label_12"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_3"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> - <string>Bvecs:</string> + <string>Tissue Mask:</string> </property> <property name="wordWrap"> <bool>false</bool> </property> </widget> </item> - <item row="0" column="0"> - <widget class="QLabel" name="label_11"> + <item row="1" column="2"> + <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_FiberBundleComboBox"> + <property name="toolTip"> + <string><html><head/><body><p>Select a fiber bundle to generate the white matter signal from. You can either use the fiber definition tab to manually define an input fiber bundle or you can also use any existing bundle, e.g. yielded by a tractography algorithm.</p></body></html></string> + </property> + <property name="sizeAdjustPolicy"> + <enum>QComboBox::AdjustToMinimumContentsLength</enum> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="m_TensorsToDWIBValueLabel_11"> <property name="toolTip"> <string/> </property> <property name="statusTip"> <string/> </property> <property name="whatsThis"> <string/> </property> <property name="text"> - <string>Bvals:</string> + <string>Template Image:</string> </property> <property name="wordWrap"> <bool>false</bool> </property> </widget> </item> - <item row="2" column="1"> - <widget class="QLineEdit" name="m_LoadBvecsEdit"> - <property name="text"> - <string>-</string> + <item row="3" column="2"> + <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_TemplateComboBox"> + <property name="toolTip"> + <string><html><head/><body><p>The parameters for the simulation (e.g. spacing, size, diffuison-weighted gradients, b-value) are adopted from this image.</p></body></html></string> </property> - <property name="readOnly"> - <bool>false</bool> + <property name="sizeAdjustPolicy"> + <enum>QComboBox::AdjustToMinimumContentsLength</enum> </property> </widget> </item> </layout> </widget> </item> - </layout> - </widget> - </item> - <item row="3" column="0"> - <widget class="QGroupBox" name="groupBox_5"> - <property name="styleSheet"> - <string notr="true">QGroupBox { - background-color: transparent; -}</string> - </property> - <property name="title"> - <string>Inter-axonal Compartment</string> - </property> - <layout class="QGridLayout" name="gridLayout_17"> - <property name="leftMargin"> - <number>6</number> - </property> - <property name="topMargin"> - <number>6</number> - </property> - <property name="rightMargin"> - <number>6</number> - </property> - <property name="bottomMargin"> - <number>6</number> - </property> - <item row="0" column="0"> - <widget class="QComboBox" name="m_Compartment2Box"> + <item row="2" column="0"> + <widget class="QCommandLinkButton" name="m_AbortSimulationButton"> + <property name="enabled"> + <bool>true</bool> + </property> <property name="toolTip"> - <string>Select signal model for intra-axonal compartment.</string> + <string>Stop current simulation.</string> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> + <property name="text"> + <string>Abort Simulation</string> + </property> + <property name="icon"> + <iconset resource="../../resources/QmitkDiffusionImaging.qrc"> + <normaloff>:/QmitkDiffusionImaging/general_icons/abort.ico</normaloff>:/QmitkDiffusionImaging/general_icons/abort.ico</iconset> </property> - <item> - <property name="text"> - <string>--</string> - </property> - </item> - <item> - <property name="text"> - <string>Stick Model</string> - </property> - </item> - <item> - <property name="text"> - <string>Zeppelin Model</string> - </property> - </item> - <item> - <property name="text"> - <string>Tensor Model</string> - </property> - </item> </widget> </item> - <item row="1" column="0"> - <widget class="QmitkZeppelinModelParametersWidget" name="m_ZeppelinWidget2" native="true"/> - </item> - <item row="2" column="0"> - <widget class="QmitkStickModelParametersWidget" name="m_StickWidget2" native="true"/> - </item> <item row="3" column="0"> - <widget class="QmitkTensorModelParametersWidget" name="m_TensorWidget2" native="true"/> - </item> - <item row="4" column="0"> - <widget class="QmitkPrototypeSignalParametersWidget" name="m_PrototypeWidget2" native="true"/> - </item> - <item row="5" column="0"> - <widget class="QFrame" name="m_Comp2FractionFrame"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> + <widget class="QTextEdit" name="m_SimulationStatusText"> + <property name="font"> + <font> + <family>Courier</family> + <pointsize>7</pointsize> + </font> </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> + <property name="readOnly"> + <bool>true</bool> </property> - <layout class="QGridLayout" name="gridLayout_27"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="m_NoiseLabel_7"> - <property name="text"> - <string>Volume Fraction:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QmitkDataStorageComboBoxWithSelectNone" name="m_Comp2VolumeFraction"> - <property name="toolTip"> - <string>Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers.</string> - </property> - </widget> - </item> - </layout> </widget> </item> </layout> </widget> </item> - <item row="8" column="0"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> </layout> </widget> <customwidgets> <customwidget> <class>QmitkDataStorageComboBox</class> <extends>QComboBox</extends> <header location="global">QmitkDataStorageComboBox.h</header> </customwidget> <customwidget> <class>QmitkDataStorageComboBoxWithSelectNone</class> <extends>QComboBox</extends> <header>QmitkDataStorageComboBoxWithSelectNone.h</header> </customwidget> <customwidget> <class>QmitkTensorModelParametersWidget</class> <extends>QWidget</extends> <header location="global">QmitkTensorModelParametersWidget.h</header> <container>1</container> </customwidget> <customwidget> <class>QmitkStickModelParametersWidget</class> <extends>QWidget</extends> <header location="global">QmitkStickModelParametersWidget.h</header> <container>1</container> </customwidget> <customwidget> <class>QmitkZeppelinModelParametersWidget</class> <extends>QWidget</extends> <header location="global">QmitkZeppelinModelParametersWidget.h</header> <container>1</container> </customwidget> <customwidget> <class>QmitkBallModelParametersWidget</class> <extends>QWidget</extends> <header location="global">QmitkBallModelParametersWidget.h</header> <container>1</container> </customwidget> <customwidget> <class>QmitkAstrosticksModelParametersWidget</class> <extends>QWidget</extends> <header location="global">QmitkAstrosticksModelParametersWidget.h</header> <container>1</container> </customwidget> <customwidget> <class>QmitkDotModelParametersWidget</class> <extends>QWidget</extends> <header>QmitkDotModelParametersWidget.h</header> <container>1</container> </customwidget> <customwidget> <class>QmitkPrototypeSignalParametersWidget</class> <extends>QWidget</extends> <header>QmitkPrototypeSignalParametersWidget.h</header> <container>1</container> </customwidget> </customwidgets> <tabstops> <tabstop>m_FiberBundleComboBox</tabstop> <tabstop>m_MaskComboBox</tabstop> <tabstop>m_TemplateComboBox</tabstop> <tabstop>m_SavePathEdit</tabstop> <tabstop>m_OutputPathButton</tabstop> + <tabstop>m_GenerateImageButton</tabstop> + <tabstop>m_AbortSimulationButton</tabstop> + <tabstop>m_SimulationStatusText</tabstop> + <tabstop>m_LoadParametersButton</tabstop> + <tabstop>m_SaveParametersButton</tabstop> <tabstop>m_SizeX</tabstop> <tabstop>m_SizeY</tabstop> <tabstop>m_SizeZ</tabstop> <tabstop>m_SpacingX</tabstop> <tabstop>m_SpacingY</tabstop> <tabstop>m_SpacingZ</tabstop> + <tabstop>m_UseBvalsBvecsBox</tabstop> + <tabstop>m_LoadBvalsEdit</tabstop> + <tabstop>m_LoadBvalsButton</tabstop> + <tabstop>m_LoadBvecsEdit</tabstop> + <tabstop>m_LoadBvecsButton</tabstop> <tabstop>m_NumGradientsBox</tabstop> <tabstop>m_BvalueBox</tabstop> <tabstop>m_AdvancedOptionsBox_2</tabstop> + <tabstop>m_AcquisitionTypeBox</tabstop> <tabstop>m_SignalScaleBox</tabstop> + <tabstop>m_NumCoilsBox</tabstop> + <tabstop>m_CoilSensBox</tabstop> <tabstop>m_TEbox</tabstop> <tabstop>m_TRbox</tabstop> + <tabstop>m_TIbox</tabstop> <tabstop>m_LineReadoutTimeBox</tabstop> <tabstop>m_PartialFourier</tabstop> <tabstop>m_T2starBox</tabstop> <tabstop>m_FiberRadius</tabstop> <tabstop>m_ReversePhaseBox</tabstop> <tabstop>m_RelaxationBox</tabstop> <tabstop>m_EnforcePureFiberVoxelsBox</tabstop> <tabstop>m_VolumeFractionsBox</tabstop> <tabstop>m_Compartment1Box</tabstop> <tabstop>m_Comp1VolumeFraction</tabstop> <tabstop>m_Compartment2Box</tabstop> <tabstop>m_Comp2VolumeFraction</tabstop> <tabstop>m_Compartment3Box</tabstop> <tabstop>m_Comp3VolumeFraction</tabstop> <tabstop>m_Compartment4Box</tabstop> <tabstop>m_Comp4VolumeFraction</tabstop> <tabstop>m_AddNoise</tabstop> <tabstop>m_NoiseDistributionBox</tabstop> <tabstop>m_NoiseLevel</tabstop> <tabstop>m_AddSpikes</tabstop> <tabstop>m_SpikeNumBox</tabstop> <tabstop>m_SpikeScaleBox</tabstop> <tabstop>m_AddGhosts</tabstop> <tabstop>m_kOffsetBox</tabstop> <tabstop>m_AddAliasing</tabstop> <tabstop>m_WrapBox</tabstop> <tabstop>m_AddDistortions</tabstop> <tabstop>m_FrequencyMapBox</tabstop> + <tabstop>m_AddDrift</tabstop> + <tabstop>m_DriftFactor</tabstop> <tabstop>m_AddMotion</tabstop> <tabstop>m_RandomMotion</tabstop> + <tabstop>m_MotionVolumesBox</tabstop> <tabstop>m_MaxRotationBoxX</tabstop> <tabstop>m_MaxRotationBoxY</tabstop> <tabstop>m_MaxRotationBoxZ</tabstop> <tabstop>m_MaxTranslationBoxX</tabstop> <tabstop>m_MaxTranslationBoxY</tabstop> <tabstop>m_MaxTranslationBoxZ</tabstop> <tabstop>m_AddEddy</tabstop> <tabstop>m_EddyGradientStrength</tabstop> <tabstop>m_AddGibbsRinging</tabstop> - <tabstop>m_SaveParametersButton</tabstop> - <tabstop>m_LoadParametersButton</tabstop> + <tabstop>m_ZeroRinging</tabstop> </tabstops> <resources> <include location="../../resources/QmitkDiffusionImaging.qrc"/> </resources> <connections/> </ui>