diff --git a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp index de2531f..027d3f1 100644 --- a/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp +++ b/Modules/DiffusionCore/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.cpp @@ -1,781 +1,781 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_cpp #define __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_cpp #include "itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h" #include "itkImageRegionConstIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkImageRegionIterator.h" #include "vnl/vnl_matrix.h" #include "vnl/algo/vnl_symmetric_eigensystem.h" #include "itkRegularizedIVIMReconstructionFilter.h" #include #define IVIM_FOO -100000 namespace itk { template< class TIn, class TOut> DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::DiffusionIntravoxelIncoherentMotionReconstructionImageFilter() : - m_GradientDirectionContainer(nullptr), - m_Method(IVIM_DSTAR_FIX), - m_FitDStar(true), - m_Verbose(false) + m_GradientDirectionContainer(nullptr), + m_Method(IVIM_DSTAR_FIX), + m_FitDStar(true), + m_Verbose(false) { - this->SetNumberOfRequiredInputs( 1 ); - - this->SetNumberOfRequiredOutputs( 3 ); - typename OutputImageType::Pointer outputPtr1 = OutputImageType::New(); - this->SetNthOutput(0, outputPtr1.GetPointer()); - typename OutputImageType::Pointer outputPtr2 = OutputImageType::New(); - this->SetNthOutput(1, outputPtr2.GetPointer()); - typename OutputImageType::Pointer outputPtr3 = OutputImageType::New(); - this->SetNthOutput(2, outputPtr3.GetPointer()); + this->SetNumberOfRequiredInputs( 1 ); + + this->SetNumberOfRequiredOutputs( 3 ); + typename OutputImageType::Pointer outputPtr1 = OutputImageType::New(); + this->SetNthOutput(0, outputPtr1.GetPointer()); + typename OutputImageType::Pointer outputPtr2 = OutputImageType::New(); + this->SetNthOutput(1, outputPtr2.GetPointer()); + typename OutputImageType::Pointer outputPtr3 = OutputImageType::New(); + this->SetNthOutput(2, outputPtr3.GetPointer()); } template< class TIn, class TOut> void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::BeforeThreadedGenerateData() { - // Input must be an itk::VectorImage. - std::string gradientImageClassName( - this->ProcessObject::GetInput(0)->GetNameOfClass()); - if ( strcmp(gradientImageClassName.c_str(),"VectorImage") != 0 ) + // Input must be an itk::VectorImage. + std::string gradientImageClassName( + this->ProcessObject::GetInput(0)->GetNameOfClass()); + if ( strcmp(gradientImageClassName.c_str(),"VectorImage") != 0 ) + { + itkExceptionMacro( << + "There is only one Gradient image. I expect that to be a VectorImage. " + << "But its of type: " << gradientImageClassName ); + } + + // Compute the indicies of the baseline images and gradient images + // If no b=0 mm/s² gradients ar found, the next lowest b-value is used. + GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin(); + double minNorm = itk::NumericTraits::max(); + while( gdcit != this->m_GradientDirectionContainer->End() ) + { + double norm = gdcit.Value().one_norm(); + if (normm_GradientDirectionContainer->Begin(); + while( gdcit != this->m_GradientDirectionContainer->End() ) + { + if(gdcit.Value().one_norm() <= minNorm) { - itkExceptionMacro( << - "There is only one Gradient image. I expect that to be a VectorImage. " - << "But its of type: " << gradientImageClassName ); + m_Snap.baselineind.push_back(gdcit.Index()); } - - // Compute the indicies of the baseline images and gradient images - // If no b=0 mm/s² gradients ar found, the next lowest b-value is used. - GradientDirectionContainerType::ConstIterator gdcit = this->m_GradientDirectionContainer->Begin(); - double minNorm = itk::NumericTraits::max(); - while( gdcit != this->m_GradientDirectionContainer->End() ) + else { - double norm = gdcit.Value().one_norm(); - if (normm_GradientDirectionContainer->Begin(); - while( gdcit != this->m_GradientDirectionContainer->End() ) + ++gdcit; + } + if (m_Snap.gradientind.size()==0) + itkExceptionMacro("Only one b-value supplied. At least two needed for IVIM fit."); + + // check sind die grad und base gleichlang? alle grad gerade und base ungerade? dann iterierende aufnahme!! + m_Snap.iterated_sequence = false; + if(m_Snap.baselineind.size() == m_Snap.gradientind.size()) + { + int size = m_Snap.baselineind.size(); + int sum_b = 0, sum_g = 0; + for(int i=0; im_BThres) - { - m_Snap.high_indices.push_back(i); - } - } - } - m_Snap.Nhigh = m_Snap.high_indices.size(); - m_Snap.high_bvalues.set_size(m_Snap.Nhigh); - m_Snap.high_meas.set_size(m_Snap.Nhigh); - for(int i=0; im_BThres) + { + m_Snap.high_indices.push_back(i); + } } + } + m_Snap.Nhigh = m_Snap.high_indices.size(); + m_Snap.high_bvalues.set_size(m_Snap.Nhigh); + m_Snap.high_meas.set_size(m_Snap.Nhigh); + for(int i=0; i MeasAndBvals DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::ApplyS0Threshold(vnl_vector &meas, vnl_vector &bvals) { - std::vector newmeas; - std::vector newbvals; + std::vector newmeas; + std::vector newbvals; - int N = meas.size(); - for(int i=0; i void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType ) { - typename OutputImageType::Pointer outputImage = - static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); - ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); - oit.GoToBegin(); - - typename OutputImageType::Pointer dImage = - static_cast< OutputImageType * >(this->ProcessObject::GetOutput(1)); - ImageRegionIterator< OutputImageType > oit1(dImage, outputRegionForThread); - oit1.GoToBegin(); - - typename OutputImageType::Pointer dstarImage = - static_cast< OutputImageType * >(this->ProcessObject::GetOutput(2)); - ImageRegionIterator< OutputImageType > oit2(dstarImage, outputRegionForThread); - oit2.GoToBegin(); - - typedef ImageRegionConstIterator< InputImageType > InputIteratorType; - typedef typename InputImageType::PixelType InputVectorType; - typename InputImageType::Pointer inputImagePointer = nullptr; - - // Would have liked a dynamic_cast here, but seems SGI doesn't like it - // The enum will DiffusionIntravoxelIncoherentMotionReconstructionImageFilterensure that an inappropriate cast is not done - inputImagePointer = static_cast< InputImageType * >( - this->ProcessObject::GetInput(0) ); - - InputIteratorType iit(inputImagePointer, outputRegionForThread ); - iit.GoToBegin(); - - // init internal vector image for regularized fit - m_InternalVectorImage = VectorImageType::New(); - m_InternalVectorImage->SetSpacing( inputImagePointer->GetSpacing() ); // Set the image spacing - m_InternalVectorImage->SetOrigin( inputImagePointer->GetOrigin() ); // Set the image origin - m_InternalVectorImage->SetDirection( inputImagePointer->GetDirection() ); // Set the image direction - m_InternalVectorImage->SetRegions( inputImagePointer->GetLargestPossibleRegion() ); + typename OutputImageType::Pointer outputImage = + static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); + ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); + oit.GoToBegin(); + + typename OutputImageType::Pointer dImage = + static_cast< OutputImageType * >(this->ProcessObject::GetOutput(1)); + ImageRegionIterator< OutputImageType > oit1(dImage, outputRegionForThread); + oit1.GoToBegin(); + + typename OutputImageType::Pointer dstarImage = + static_cast< OutputImageType * >(this->ProcessObject::GetOutput(2)); + ImageRegionIterator< OutputImageType > oit2(dstarImage, outputRegionForThread); + oit2.GoToBegin(); + + typedef ImageRegionConstIterator< InputImageType > InputIteratorType; + typedef typename InputImageType::PixelType InputVectorType; + typename InputImageType::Pointer inputImagePointer = nullptr; + + // Would have liked a dynamic_cast here, but seems SGI doesn't like it + // The enum will DiffusionIntravoxelIncoherentMotionReconstructionImageFilterensure that an inappropriate cast is not done + inputImagePointer = static_cast< InputImageType * >( + this->ProcessObject::GetInput(0) ); + + InputIteratorType iit(inputImagePointer, outputRegionForThread ); + iit.GoToBegin(); + + // init internal vector image for regularized fit + m_InternalVectorImage = VectorImageType::New(); + m_InternalVectorImage->SetSpacing( inputImagePointer->GetSpacing() ); // Set the image spacing + m_InternalVectorImage->SetOrigin( inputImagePointer->GetOrigin() ); // Set the image origin + m_InternalVectorImage->SetDirection( inputImagePointer->GetDirection() ); // Set the image direction + m_InternalVectorImage->SetRegions( inputImagePointer->GetLargestPossibleRegion() ); + + m_InitialFitImage = InitialFitImageType::New(); + m_InitialFitImage->SetSpacing( inputImagePointer->GetSpacing() ); // Set the image spacing + m_InitialFitImage->SetOrigin( inputImagePointer->GetOrigin() ); // Set the image origin + m_InitialFitImage->SetDirection( inputImagePointer->GetDirection() ); // Set the image direction + m_InitialFitImage->SetRegions( inputImagePointer->GetLargestPossibleRegion() ); + + if(m_Method == IVIM_REGULARIZED) + { + m_InternalVectorImage->SetVectorLength(m_Snap.Nhigh); + m_InternalVectorImage->Allocate(); + VectorImageType::PixelType varvec(m_Snap.Nhigh); + for(int i=0; iFillBuffer(varvec); + + m_InitialFitImage->Allocate(); + InitialFitImageType::PixelType vec; + vec[0] = 0.5; vec[1] = 0.01; vec[2]=0.001; + m_InitialFitImage->FillBuffer(vec); + } + + typedef itk::ImageRegionIterator VectorIteratorType; + VectorIteratorType vecit(m_InternalVectorImage, outputRegionForThread ); + vecit.GoToBegin(); + + typedef itk::ImageRegionIterator InitIteratorType; + InitIteratorType initit(m_InitialFitImage, outputRegionForThread ); + initit.GoToBegin(); + + while( !iit.IsAtEnd() ) + { + InputVectorType measvec = iit.Get(); + + typename NumericTraits::AccumulateType b0 = NumericTraits::Zero; + + m_Snap.meas.set_size(m_Snap.N); + m_Snap.allmeas.set_size(m_Snap.N); + if(!m_Snap.iterated_sequence) + { + // Average the baseline image pixels + for(unsigned int i = 0; i < m_Snap.baselineind.size(); ++i) + { + b0 += measvec[m_Snap.baselineind[i]]; + } + if(m_Snap.baselineind.size()) + b0 /= m_Snap.baselineind.size(); + + // measurement vector + for(int i = 0; i < m_Snap.N; ++i) + { + m_Snap.allmeas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); + + if(measvec[m_Snap.gradientind[i]] > m_S0Thres) + { + m_Snap.meas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); + } + else + { + m_Snap.meas[i] = IVIM_FOO; + } + } + } + else + { + // measurement vector + for(int i = 0; i < m_Snap.N; ++i) + { + b0 = measvec[m_Snap.baselineind[i]]; - m_InitialFitImage = InitialFitImageType::New(); - m_InitialFitImage->SetSpacing( inputImagePointer->GetSpacing() ); // Set the image spacing - m_InitialFitImage->SetOrigin( inputImagePointer->GetOrigin() ); // Set the image origin - m_InitialFitImage->SetDirection( inputImagePointer->GetDirection() ); // Set the image direction - m_InitialFitImage->SetRegions( inputImagePointer->GetLargestPossibleRegion() ); + m_Snap.allmeas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); - if(m_Method == IVIM_REGULARIZED) - { - m_InternalVectorImage->SetVectorLength(m_Snap.Nhigh); - m_InternalVectorImage->Allocate(); - VectorImageType::PixelType varvec(m_Snap.Nhigh); - for(int i=0; iFillBuffer(varvec); - - m_InitialFitImage->Allocate(); - InitialFitImageType::PixelType vec; - vec[0] = 0.5; vec[1] = 0.01; vec[2]=0.001; - m_InitialFitImage->FillBuffer(vec); + if(measvec[m_Snap.gradientind[i]] > m_S0Thres) + { + m_Snap.meas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); + } + else + { + m_Snap.meas[i] = IVIM_FOO; + } + } } - typedef itk::ImageRegionIterator VectorIteratorType; - VectorIteratorType vecit(m_InternalVectorImage, outputRegionForThread ); - vecit.GoToBegin(); + m_Snap.currentF = 0; + m_Snap.currentD = 0; + m_Snap.currentDStar = 0; - typedef itk::ImageRegionIterator InitIteratorType; - InitIteratorType initit(m_InitialFitImage, outputRegionForThread ); - initit.GoToBegin(); + switch(m_Method) + { - while( !iit.IsAtEnd() ) + case IVIM_D_THEN_DSTAR: { - InputVectorType measvec = iit.Get(); - typename NumericTraits::AccumulateType b0 = NumericTraits::Zero; + for(int i=0; i m_S0Thres) - { - m_Snap.meas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); - } - else - { - m_Snap.meas[i] = IVIM_FOO; - } - } + m_Snap.currentD = - log(input.meas[0]) / input.bvals[0]; + m_Snap.currentF = 0; + m_Snap.currentDStar = 0; } - else + break; + } + + IVIM_d_and_f f_donly(input.N); + f_donly.set_bvalues(input.bvals); + f_donly.set_measurements(input.meas); + + vnl_vector< double > x_donly(2); + x_donly[0] = 0.001; + x_donly[1] = 0.1; + // f 0.1 Dstar 0.01 D 0.001 + + vnl_levenberg_marquardt lm_donly(f_donly); + lm_donly.set_f_tolerance(0.0001); + lm_donly.minimize(x_donly); + m_Snap.currentD = x_donly[0]; + m_Snap.currentF = x_donly[1]; + + + if(m_FitDStar) + { + MeasAndBvals input2 = ApplyS0Threshold(m_Snap.meas, m_Snap.bvalues); + m_Snap.bvals2 = input2.bvals; + m_Snap.meas2 = input2.meas; + if (input2.N < 2) break; + + IVIM_dstar_only f_dstar_only(input2.N,m_Snap.currentD,m_Snap.currentF); + f_dstar_only.set_bvalues(input2.bvals); + f_dstar_only.set_measurements(input2.meas); + + vnl_vector< double > x_dstar_only(1); + vnl_vector< double > fx_dstar_only(input2.N); + + double opt = 1111111111111111.0; + int opt_idx = -1; + int num_its = 100; + double min_val = .001; + double max_val = .15; + for(int i=0; i m_S0Thres) - { - m_Snap.meas[i] = measvec[m_Snap.gradientind[i]] / (b0+.0001); - } - else - { - m_Snap.meas[i] = IVIM_FOO; - } - } + x_dstar_only[0] = min_val + i * ((max_val-min_val) / num_its); + f_dstar_only.f(x_dstar_only, fx_dstar_only); + double err = fx_dstar_only.two_norm(); + if(err x_fixd(2); + // x_fixd[0] = 0.1; + // x_fixd[1] = 0.01; + // // f 0.1 Dstar 0.01 D 0.001 - case IVIM_D_THEN_DSTAR: - { + // vnl_levenberg_marquardt lm_fixd(f_fixd); + // lm_fixd.set_f_tolerance(0.0001); + // lm_fixd.minimize(x_fixd); - for(int i=0; i x_donly(2); - x_donly[0] = 0.001; - x_donly[1] = 0.1; - // f 0.1 Dstar 0.01 D 0.001 - - vnl_levenberg_marquardt lm_donly(f_donly); - lm_donly.set_f_tolerance(0.0001); - lm_donly.minimize(x_donly); - m_Snap.currentD = x_donly[0]; - m_Snap.currentF = x_donly[1]; - - - if(m_FitDStar) - { - MeasAndBvals input2 = ApplyS0Threshold(m_Snap.meas, m_Snap.bvalues); - m_Snap.bvals2 = input2.bvals; - m_Snap.meas2 = input2.meas; - if (input2.N < 2) break; - - IVIM_dstar_only f_dstar_only(input2.N,m_Snap.currentD,m_Snap.currentF); - f_dstar_only.set_bvalues(input2.bvals); - f_dstar_only.set_measurements(input2.meas); - - vnl_vector< double > x_dstar_only(1); - vnl_vector< double > fx_dstar_only(input2.N); - - double opt = 1111111111111111.0; - int opt_idx = -1; - int num_its = 100; - double min_val = .001; - double max_val = .15; - for(int i=0; i x_fixd(2); - // x_fixd[0] = 0.1; - // x_fixd[1] = 0.01; - // // f 0.1 Dstar 0.01 D 0.001 - - // vnl_levenberg_marquardt lm_fixd(f_fixd); - // lm_fixd.set_f_tolerance(0.0001); - // lm_fixd.minimize(x_fixd); - - // m_Snap.currentF = x_fixd[0]; - // m_Snap.currentDStar = x_fixd[1]; - } - - break; - } + // m_Snap.currentF = x_fixd[0]; + // m_Snap.currentDStar = x_fixd[1]; + } - case IVIM_DSTAR_FIX: - { - MeasAndBvals input = ApplyS0Threshold(m_Snap.meas, m_Snap.bvalues); - m_Snap.bvals1 = input.bvals; - m_Snap.meas1 = input.meas; - if (input.N < 2) break; + break; + } - IVIM_fixdstar f_fixdstar(input.N,m_DStar); - f_fixdstar.set_bvalues(input.bvals); - f_fixdstar.set_measurements(input.meas); + case IVIM_DSTAR_FIX: + { + MeasAndBvals input = ApplyS0Threshold(m_Snap.meas, m_Snap.bvalues); + m_Snap.bvals1 = input.bvals; + m_Snap.meas1 = input.meas; + if (input.N < 2) break; - vnl_vector< double > x(2); - x[0] = 0.1; - x[1] = 0.001; - // f 0.1 Dstar 0.01 D 0.001 + IVIM_fixdstar f_fixdstar(input.N,m_DStar); + f_fixdstar.set_bvalues(input.bvals); + f_fixdstar.set_measurements(input.meas); - vnl_levenberg_marquardt lm(f_fixdstar); - lm.set_f_tolerance(0.0001); - lm.minimize(x); + vnl_vector< double > x(2); + x[0] = 0.1; + x[1] = 0.001; + // f 0.1 Dstar 0.01 D 0.001 - m_Snap.currentF = x[0]; - m_Snap.currentD = x[1]; - m_Snap.currentDStar = m_DStar; + vnl_levenberg_marquardt lm(f_fixdstar); + lm.set_f_tolerance(0.0001); + lm.minimize(x); - break; - } + m_Snap.currentF = x[0]; + m_Snap.currentD = x[1]; + m_Snap.currentDStar = m_DStar; - case IVIM_FIT_ALL: - { + break; + } - MeasAndBvals input = ApplyS0Threshold(m_Snap.meas, m_Snap.bvalues); - m_Snap.bvals1 = input.bvals; - m_Snap.meas1 = input.meas; - if (input.N < 3) break; + case IVIM_FIT_ALL: + { - IVIM_3param f_3param(input.N); - f_3param.set_bvalues(input.bvals); - f_3param.set_measurements(input.meas); + MeasAndBvals input = ApplyS0Threshold(m_Snap.meas, m_Snap.bvalues); + m_Snap.bvals1 = input.bvals; + m_Snap.meas1 = input.meas; + if (input.N < 3) break; - vnl_vector< double > x(3); - x[0] = 0.1; - x[1] = 0.001; - x[2] = 0.01; - // f 0.1 Dstar 0.01 D 0.001 + IVIM_3param f_3param(input.N); + f_3param.set_bvalues(input.bvals); + f_3param.set_measurements(input.meas); - vnl_levenberg_marquardt lm(f_3param); - lm.set_f_tolerance(0.0001); - lm.minimize(x); + vnl_vector< double > x(3); + x[0] = 0.1; + x[1] = 0.001; + x[2] = 0.01; + // f 0.1 Dstar 0.01 D 0.001 - m_Snap.currentF = x[0]; - m_Snap.currentD = x[1]; - m_Snap.currentDStar = x[2]; + vnl_levenberg_marquardt lm(f_3param); + lm.set_f_tolerance(0.0001); + lm.minimize(x); - break; - } + m_Snap.currentF = x[0]; + m_Snap.currentD = x[1]; + m_Snap.currentDStar = x[2]; - case IVIM_LINEAR_D_THEN_F: - { + break; + } - // // neglect zero-measurements - // bool zero = false; - // for(int i=0; i X(input.N,2); - for(int i=0; i XX = X.transpose() * X; - vnl_symmetric_eigensystem eigs(XX); - - vnl_vector eig; - if(eigs.get_eigenvalue(0) > eigs.get_eigenvalue(1)) - eig = eigs.get_eigenvector(0); - else - eig = eigs.get_eigenvector(1); - - m_Snap.currentF = 1 - exp( meas_m - bval_m*(eig(1)/eig(0)) ); - m_Snap.currentD = -eig(1)/eig(0); - - if(m_FitDStar) - { - MeasAndBvals input2 = ApplyS0Threshold(m_Snap.meas, m_Snap.bvalues); - m_Snap.bvals2 = input2.bvals; - m_Snap.meas2 = input2.meas; - if (input2.N < 2) break; - - IVIM_dstar_only f_dstar_only(input2.N,m_Snap.currentD,m_Snap.currentF); - f_dstar_only.set_bvalues(input2.bvals); - f_dstar_only.set_measurements(input2.meas); - - vnl_vector< double > x_dstar_only(1); - vnl_vector< double > fx_dstar_only(input2.N); - - double opt = 1111111111111111.0; - int opt_idx = -1; - int num_its = 100; - double min_val = .001; - double max_val = .15; - for(int i=0; i " << DStar; - // x_dstar_only[0] = 0.01; - // // f 0.1 Dstar 0.01 D 0.001 - - // vnl_levenberg_marquardt lm_dstar_only(f_dstar_only); - // lm_dstar_only.set_f_tolerance(0.0001); - // lm_dstar_only.minimize(x_dstar_only); - - // DStar = x_dstar_only[0]; - - break; - } + case IVIM_LINEAR_D_THEN_F: + { - case IVIM_REGULARIZED: + // // neglect zero-measurements + // bool zero = false; + // for(int i=0; i x_donly(2); - x_donly[0] = 0.001; - x_donly[1] = 0.1; - - if(input.N >= 2) - { - IVIM_d_and_f f_donly(input.N); - f_donly.set_bvalues(input.bvals); - f_donly.set_measurements(input.meas); - //MITK_INFO << "initial fit N=" << input.N << ", min-b = " << input.bvals[0] << ", max-b = " << input.bvals[input.N-1]; - vnl_levenberg_marquardt lm_donly(f_donly); - lm_donly.set_f_tolerance(0.0001); - lm_donly.minimize(x_donly); - } - - typename InitialFitImageType::PixelType initvec; - initvec[0] = x_donly[1]; - initvec[1] = x_donly[0]; - initit.Set(initvec); - //MITK_INFO << "Init vox " << initit.GetIndex() << " with " << initvec[0] << "; " << initvec[1]; - ++initit; - - int N = m_Snap.high_meas.size(); - typename VectorImageType::PixelType vec(N); - for(int i=0; i " << DStar; + // x_dstar_only[0] = 0.01; + // // f 0.1 Dstar 0.01 D 0.001 - // std::cout << "\tf=" << x[0] << "\tD=" << x[1] << " ; "< x_donly(2); + x_donly[0] = 0.001; + x_donly[1] = 0.1; + + if(input.N >= 2) + { + IVIM_d_and_f f_donly(input.N); + f_donly.set_bvalues(input.bvals); + f_donly.set_measurements(input.meas); + //MITK_INFO << "initial fit N=" << input.N << ", min-b = " << input.bvals[0] << ", max-b = " << input.bvals[input.N-1]; + vnl_levenberg_marquardt lm_donly(f_donly); + lm_donly.set_f_tolerance(0.0001); + lm_donly.minimize(x_donly); + } + + typename InitialFitImageType::PixelType initvec; + initvec[0] = x_donly[1]; + initvec[1] = x_donly[0]; + initit.Set(initvec); + //MITK_INFO << "Init vox " << initit.GetIndex() << " with " << initvec[0] << "; " << initvec[1]; + ++initit; + + int N = m_Snap.high_meas.size(); + typename VectorImageType::PixelType vec(N); + for(int i=0; i void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::AfterThreadedGenerateData() { - if(m_Method == IVIM_REGULARIZED) + if(m_Method == IVIM_REGULARIZED) + { + typename OutputImageType::Pointer outputImage = + static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); + ImageRegionIterator< OutputImageType > oit0(outputImage, outputImage->GetLargestPossibleRegion()); + oit0.GoToBegin(); + + typename OutputImageType::Pointer dImage = + static_cast< OutputImageType * >(this->ProcessObject::GetOutput(1)); + ImageRegionIterator< OutputImageType > oit1(dImage, dImage->GetLargestPossibleRegion()); + oit1.GoToBegin(); + + typename OutputImageType::Pointer dstarImage = + static_cast< OutputImageType * >(this->ProcessObject::GetOutput(2)); + ImageRegionIterator< OutputImageType > oit2(dstarImage, dstarImage->GetLargestPossibleRegion()); + oit2.GoToBegin(); + + typedef itk::RegularizedIVIMReconstructionFilter + RegFitType; + RegFitType::Pointer filter = RegFitType::New(); + filter->SetInput(m_InitialFitImage); + filter->SetReferenceImage(m_InternalVectorImage); + filter->SetBValues(m_Snap.high_bvalues); + filter->SetNumberIterations(m_NumberIterations); + filter->SetNumberOfThreads(1); + filter->SetLambda(m_Lambda); + filter->Update(); + typename RegFitType::OutputImageType::Pointer outimg = filter->GetOutput(); + + ImageRegionConstIterator< RegFitType::OutputImageType > iit(outimg, outimg->GetLargestPossibleRegion()); + iit.GoToBegin(); + + while( !iit.IsAtEnd() ) { - typename OutputImageType::Pointer outputImage = - static_cast< OutputImageType * >(this->ProcessObject::GetPrimaryOutput()); - ImageRegionIterator< OutputImageType > oit0(outputImage, outputImage->GetLargestPossibleRegion()); - oit0.GoToBegin(); - - typename OutputImageType::Pointer dImage = - static_cast< OutputImageType * >(this->ProcessObject::GetOutput(1)); - ImageRegionIterator< OutputImageType > oit1(dImage, dImage->GetLargestPossibleRegion()); - oit1.GoToBegin(); - - typename OutputImageType::Pointer dstarImage = - static_cast< OutputImageType * >(this->ProcessObject::GetOutput(2)); - ImageRegionIterator< OutputImageType > oit2(dstarImage, dstarImage->GetLargestPossibleRegion()); - oit2.GoToBegin(); - - typedef itk::RegularizedIVIMReconstructionFilter - RegFitType; - RegFitType::Pointer filter = RegFitType::New(); - filter->SetInput(m_InitialFitImage); - filter->SetReferenceImage(m_InternalVectorImage); - filter->SetBValues(m_Snap.high_bvalues); - filter->SetNumberIterations(m_NumberIterations); - filter->SetNumberOfThreads(1); - filter->SetLambda(m_Lambda); - filter->Update(); - typename RegFitType::OutputImageType::Pointer outimg = filter->GetOutput(); - - ImageRegionConstIterator< RegFitType::OutputImageType > iit(outimg, outimg->GetLargestPossibleRegion()); - iit.GoToBegin(); - - while( !iit.IsAtEnd() ) + double f = iit.Get()[0]; + IVIM_CEIL( f, 0.0, 1.0 ); + + oit0.Set( myround(f * 100.0) ); + oit1.Set( myround(iit.Get()[1] * 10000.0) ); + oit2.Set( myround(iit.Get()[2] * 1000.0) ); + + if(!m_Verbose) + { + // report the middle voxel + if( iit.GetIndex()[0] == m_CrossPosition[0] + && iit.GetIndex()[1] == m_CrossPosition[1] + && iit.GetIndex()[2] == m_CrossPosition[2] ) { - double f = iit.Get()[0]; - IVIM_CEIL( f, 0.0, 1.0 ); - - oit0.Set( myround(f * 100.0) ); - oit1.Set( myround(iit.Get()[1] * 10000.0) ); - oit2.Set( myround(iit.Get()[2] * 1000.0) ); - - if(!m_Verbose) - { - // report the middle voxel - if( iit.GetIndex()[0] == m_CrossPosition[0] - && iit.GetIndex()[1] == m_CrossPosition[1] - && iit.GetIndex()[2] == m_CrossPosition[2] ) - { - m_Snap.currentF = f; - m_Snap.currentD = iit.Get()[1]; - m_Snap.currentDStar = iit.Get()[2]; - m_Snap.allmeas = m_tmp_allmeas; - MITK_INFO << "setting " << f << ";" << iit.Get()[1] << ";" << iit.Get()[2]; - } - } - - ++oit0; - ++oit1; - ++oit2; - ++iit; + m_Snap.currentF = f; + m_Snap.currentD = iit.Get()[1]; + m_Snap.currentDStar = iit.Get()[2]; + m_Snap.allmeas = m_tmp_allmeas; + MITK_INFO << "setting " << f << ";" << iit.Get()[1] << ";" << iit.Get()[2]; } + } + + ++oit0; + ++oit1; + ++oit2; + ++iit; } + } } template< class TIn, class TOut> double DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::myround(double number) { - return number < 0.0 ? ceil(number - 0.5) : floor(number + 0.5); + return number < 0.0 ? ceil(number - 0.5) : floor(number + 0.5); } template< class TIn, class TOut> void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::SetGradientDirections( GradientDirectionContainerType *gradientDirection ) { - this->m_GradientDirectionContainer = gradientDirection; - this->m_NumberOfGradientDirections = gradientDirection->Size(); + this->m_GradientDirectionContainer = gradientDirection; + this->m_NumberOfGradientDirections = gradientDirection->Size(); } template< class TIn, class TOut> void DiffusionIntravoxelIncoherentMotionReconstructionImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { - Superclass::PrintSelf(os,indent); - - if ( m_GradientDirectionContainer ) - { - os << indent << "GradientDirectionContainer: " - << m_GradientDirectionContainer << std::endl; - } - else - { - os << indent << - "GradientDirectionContainer: (Gradient directions not set)" << std::endl; - } + Superclass::PrintSelf(os,indent); + + if ( m_GradientDirectionContainer ) + { + os << indent << "GradientDirectionContainer: " + << m_GradientDirectionContainer << std::endl; + } + else + { + os << indent << + "GradientDirectionContainer: (Gradient directions not set)" << std::endl; + } } } #endif // __itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter_cpp diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/CMakeLists.txt b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/CMakeLists.txt index 03cd599..e7e6da3 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/CMakeLists.txt @@ -1,10 +1,10 @@ # The project name must correspond to the directory name of your plug-in # and must not contain periods. project(org_mitk_gui_qt_diffusionimaging_ivim) mitk_create_plugin( SUBPROJECTS MITK-Diffusion EXPORT_DIRECTIVE DIFFUSIONIMAGING_IVIM_EXPORT EXPORTED_INCLUDE_SUFFIXES src - MODULE_DEPENDS MitkQtWidgetsExt MitkDiffusionCore + MODULE_DEPENDS MitkQtWidgetsExt MitkChart MitkDiffusionCore ) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/files.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/files.cmake index 4d36129..8c02d3f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/files.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/files.cmake @@ -1,46 +1,45 @@ set(SRC_CPP_FILES - QmitkIVIMWidget.cpp - QmitkKurtosisWidget.cpp + ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkIVIMView.cpp Perspectives/QmitkDIAppIVIMPerspective.cpp ) set(UI_FILES src/internal/QmitkIVIMViewControls.ui ) set(MOC_H_FILES src/internal/mitkPluginActivator.h src/internal/QmitkIVIMView.h src/internal/Perspectives/QmitkDIAppIVIMPerspective.h ) set(CACHED_RESOURCE_FILES plugin.xml resources/IVIM_48.png resources/ivim.png ) set(QRC_FILES ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/QmitkIVIMWidget.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/QmitkIVIMWidget.cpp deleted file mode 100644 index 5faa88e..0000000 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/QmitkIVIMWidget.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center. - -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#include "QmitkIVIMWidget.h" - -#include "mitkHistogramGenerator.h" - - -#include -#include - - -QmitkIVIMWidget::QmitkIVIMWidget( QWidget * parent ) - : QmitkPlotWidget(parent) -{ - // this->SetAxisTitle( QwtPlot::xBottom, "Grayvalue" ); - // this->SetAxisTitle( QwtPlot::yLeft, "Probability" ); - // this->Replot(); - QFrame* canvas = qobject_cast(m_Plot->canvas()); - if (canvas) - { - canvas->setLineWidth(0); - canvas->setContentsMargins(0,0,0,0); - } - - auto linScale = new QwtLinearScaleEngine(); - m_Plot->setAxisScaleEngine(1, linScale); - - auto logScale = new QwtLogScaleEngine(); - m_Plot->setAxisScaleEngine(0, logScale); - - m_Plot->setAxisScale( 0, 0.15, 1.0 ); -} - - - -QmitkIVIMWidget::~QmitkIVIMWidget() -{ -} - - -void QmitkIVIMWidget::DrawGauss() -{ - -} - - -void QmitkIVIMWidget::ClearItemModel() -{ - -} - -std::vector QmitkIVIMWidget::vec(const vnl_vector& vector) -{ - std::vector retval(vector.size()); - for(unsigned int i=0; iClear(); - if (snap.bvalues.empty()) - return; - - QString s("f=%1, D=%2, D*=%3"); - s = s.arg(snap.currentF,4); - s = s.arg(snap.currentD,4); - s = s.arg(snap.currentDStar,4); - int curveId = this->InsertCurve( s.toLatin1(), QColor(Qt::lightGray) ); - this->SetCurvePen( curveId, QPen( Qt::NoPen ) ); - - QPen pen; - pen.setColor( QColor(Qt::cyan) ); - pen.setStyle( Qt::DotLine ); - pen.setWidth(2); - double maxb = snap.bvalues.max_value(); - vnl_vector xvals(2); - vnl_vector yvals(2); - xvals[0] = 0; - xvals[1] = maxb; - yvals[0] = 1-snap.currentFunceiled; - yvals[1] = yvals[0]*exp(-maxb * snap.currentD); - curveId = this->InsertCurve( "contribution of D to the signal", QColor(Qt::lightGray) ); - this->SetCurveData( curveId, vec(xvals), vec(yvals) ); - this->SetCurvePen( curveId, pen ); - this->SetCurveAntialiasingOn( curveId ); - - if(snap.currentDStar != 0) - { - pen.setStyle( Qt::SolidLine ); - pen.setColor(Qt::red); - int nsampling = 50; - xvals.set_size(nsampling); - yvals.set_size(nsampling); - double f = 1-snap.currentFunceiled; - for(int i=0; iInsertCurve( "resulting fit of the model", QColor(Qt::lightGray) ); - this->SetCurveData( curveId, vec(xvals), vec(yvals) ); - this->SetCurvePen( curveId, pen ); - this->SetCurveAntialiasingOn( curveId ); - } - - // plot points after all curves to force prettier legend formatting - // lines - // points -// curveId = this->InsertCurve( "ignored measurement points", QColor(Qt::lightGray) ); -// this->SetCurveData( curveId, vec(snap.bvalues), vec(snap.allmeas) ); -// this->SetCurvePen( curveId, QPen(Qt::NoPen) ); -// QwtSymbol* blackSymbol = new QwtSymbol(QwtSymbol::Diamond, QColor(Qt::black), QColor(Qt::black), QSize(8,8)); -// this->SetCurveSymbol(curveId, blackSymbol); - -// QwtSymbol* redSymbol = new QwtSymbol(QwtSymbol::Diamond, QColor(Qt::red), QColor(Qt::red), QSize(8,8)); - QwtSymbol* whiteDiamond = new QwtSymbol(QwtSymbol::Diamond, QColor(Qt::white), QColor(Qt::black), QSize(8,8)); - QwtSymbol* whiteStar = new QwtSymbol(QwtSymbol::XCross, QColor(Qt::white), QColor(Qt::white), QSize(8,8)); - - curveId = this->InsertCurve( "points first fit", QColor(Qt::lightGray) ); - this->SetCurveData( curveId, vec(snap.bvals1), vec(snap.meas1) ); - this->SetCurvePen( curveId, QPen( Qt::NoPen ) ); - this->SetCurveSymbol(curveId, whiteDiamond); - - if(snap.currentDStar != 0 && !snap.high_indices.empty()) - { - std::vector< double > additonal_bvals; - std::vector< double > additonal_meas; - for (int i=0; iInsertCurve( "additional points second fit", QColor(Qt::lightGray) ); - this->SetCurveData( curveId, additonal_bvals, additonal_meas ); - this->SetCurvePen( curveId, QPen( Qt::NoPen ) ); - this->SetCurveSymbol(curveId, whiteStar); - } - } - - auto legend = new QwtLegend(); - m_Plot->insertLegend(legend, QwtPlot::BottomLegend); - - m_Plot->setAxisTitle(0, "S/S0"); - m_Plot->setAxisTitle(1, "b"); - this->Replot(); - -} diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/QmitkIVIMWidget.h b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/QmitkIVIMWidget.h deleted file mode 100644 index 31f3781..0000000 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/QmitkIVIMWidget.h +++ /dev/null @@ -1,58 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center. - -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#ifndef QmitkIVIMWidget_H_ -#define QmitkIVIMWidget_H_ - -#include "QmitkPlotWidget.h" - -#include "mitkImage.h" - -#include "itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h" - - -/** - * \brief Widget for displaying image histograms based on the vtkQtChart - * framework - */ -class QmitkIVIMWidget : public QmitkPlotWidget -{ - -public: - - typedef itk::DiffusionIntravoxelIncoherentMotionReconstructionImageFilter IVIMFilterType; - - typedef mitk::Image::HistogramType HistogramType; - typedef mitk::Image::HistogramType::ConstIterator HistogramConstIteratorType; - - void SetParameters( IVIMFilterType::IVIMSnapshot snap ); - - QmitkIVIMWidget( QWidget * /*parent = 0 */); - virtual ~QmitkIVIMWidget(); - - void DrawGauss(); - - void ClearItemModel(); - - std::vector< std::vector* > m_Vals; - -private: - - std::vector vec(const vnl_vector& vector); - -}; - -#endif /* QmitkIVIMWidget_H_ */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/QmitkKurtosisWidget.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/QmitkKurtosisWidget.cpp deleted file mode 100644 index 2918173..0000000 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/QmitkKurtosisWidget.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center. - -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#include "QmitkKurtosisWidget.h" - -#include -#include - -QmitkKurtosisWidget::QmitkKurtosisWidget(QWidget *parent) - : QmitkPlotWidget(parent) -{ - QFrame* canvas = qobject_cast< QFrame* >( m_Plot->canvas() ); - if( canvas ) - { - canvas->setLineWidth(0); - canvas->setContentsMargins(0, 0, 0, 0); - } - -} - -QmitkKurtosisWidget::~QmitkKurtosisWidget() -{ - -} - - -void QmitkKurtosisWidget::SetData(KurtosisFilterType::KurtosisSnapshot snap) -{ - this->Clear(); - - if( snap.bvalues.empty() ) - return; - - double max_y_val = 1.4 * fmax( snap.measurements[0], snap.m_BzeroFit ); - - auto logScale = new QwtLogScaleEngine(); - m_Plot->setAxisScaleEngine(0, logScale ); - m_Plot->setAxisScale(0, 0.1, max_y_val ); - - QString s("D=%1, K=%2"); - s = s.arg( snap.m_D, 4); s = s.arg( snap.m_K, 4); - - // insert formatted value string to legend (curve without pen) - int curveId = this->InsertCurve( s.toLatin1(), QColor( Qt::lightGray ) ); - this->SetCurvePen( curveId, QPen( Qt::NoPen ) ); - - // get the x-axis maximum - const double max_bvalue = snap.bvalues.max_value(); - - // - // Data-points - // - auto measured_values = toStdVec( snap.measurements ); - double y_bzero = measured_values[0]; - - MITK_INFO << "-------------"; - MITK_INFO << y_bzero; - MITK_INFO << snap.m_D; - MITK_INFO << snap.m_K; - - - const unsigned int num_samples = 50; - vnl_vector x_K_model(num_samples); - vnl_vector y_K_model(num_samples); - vnl_vector y_D_model(num_samples); - const double x_tics_offset = max_bvalue / static_cast( num_samples ); - for( unsigned int i=0; iInsertCurve( "D-part of the fitted model", QColor(Qt::lightGray) ); - this->SetCurveData( d_curve, toStdVec( x_K_model ), toStdVec( y_D_model ) ); - this->SetCurvePen( d_curve, pen ); - this->SetCurveAntialiasingOn( d_curve ); - - // Kurtosis - full modelled signal - pen.setColor( QColor( Qt::red )); - pen.setStyle( Qt::SolidLine ); - - auto kurtosis_curve = this->InsertCurve( "Resulting fit of the model", QColor(Qt::lightGray) ); - this->SetCurveData( kurtosis_curve, toStdVec( x_K_model ), toStdVec( y_K_model ) ); - this->SetCurvePen( kurtosis_curve, pen ); - this->SetCurveAntialiasingOn( kurtosis_curve ); - - auto measurements_curve = this->InsertCurve( "Measured values", QColor(Qt::lightGray) ); - this->SetCurveData( measurements_curve, toStdVec( snap.fit_bvalues ), toStdVec( snap.fit_measurements) ); - this->SetCurvePen( measurements_curve, QPen(Qt::NoPen) ); - QwtSymbol* whiteDiamond = new QwtSymbol(QwtSymbol::Diamond, QColor(Qt::white), QColor(Qt::black), QSize(8,8)); - this->SetCurveSymbol( measurements_curve, whiteDiamond ); - - // add Legend - auto legend = new QwtLegend(); - legend->setMaxColumns(3); - m_Plot->insertLegend( legend, QwtPlot::BottomLegend ); - m_Plot->setAxisTitle(0, "S"); - - this->Replot(); -} - -std::vector QmitkKurtosisWidget::toStdVec(const vnl_vector& vector) -{ - std::vector retval(vector.size()); - for(unsigned int i=0; i KurtosisFilterType; - - QmitkKurtosisWidget( QWidget* /* parent */); - virtual ~QmitkKurtosisWidget(); - - void SetData( KurtosisFilterType::KurtosisSnapshot snap ); - - std::vector< std::vector* > m_Vals; - -private: - - std::vector toStdVec(const vnl_vector& vector); - -}; - -#endif // QMITKKURTOSISWIDGET_H diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.cpp index 99ca828..ebf9220 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.cpp @@ -1,939 +1,1098 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkIVIMView.h" // qt #include "qmessagebox.h" #include "qclipboard.h" // mitk #include "mitkImage.h" #include "mitkImageCast.h" #include "mitkLookupTable.h" #include "mitkLookupTableProperty.h" #include #include // itk #include "itkScalarImageToHistogramGenerator.h" #include "itkRegionOfInterestImageFilter.h" #include "itkImageRegionConstIteratorWithIndex.h" // itk/mitk #include "itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h" #include "itkRegularizedIVIMReconstructionFilter.h" #include "mitkImageCast.h" #include #include #include #include #include #include const std::string QmitkIVIMView::VIEW_ID = "org.mitk.views.ivim"; QmitkIVIMView::QmitkIVIMView() : QmitkAbstractView() , m_Controls( 0 ) , m_Active(false) , m_Visible(false) , m_HoldUpdate(false) { } QmitkIVIMView::~QmitkIVIMView() { } void QmitkIVIMView::CreateQtPartControl( QWidget *parent ) { // hold update untill all elements are set this->m_HoldUpdate = true; // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkIVIMViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_ButtonStart, SIGNAL(clicked()), this, SLOT(FittIVIMStart()) ); connect( m_Controls->m_ButtonAutoThres, SIGNAL(clicked()), this, SLOT(AutoThreshold()) ); - connect( m_Controls->m_MethodCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(MethodCombo(int)) ); + connect( m_Controls->m_MethodCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnIvimFitChanged(int)) ); connect( m_Controls->m_DStarSlider, SIGNAL(valueChanged(int)), this, SLOT(DStarSlider(int)) ); connect( m_Controls->m_BThreshSlider, SIGNAL(valueChanged(int)), this, SLOT(BThreshSlider(int)) ); connect( m_Controls->m_S0ThreshSlider, SIGNAL(valueChanged(int)), this, SLOT(S0ThreshSlider(int)) ); connect( m_Controls->m_NumItSlider, SIGNAL(valueChanged(int)), this, SLOT(NumItsSlider(int)) ); connect( m_Controls->m_LambdaSlider, SIGNAL(valueChanged(int)), this, SLOT(LambdaSlider(int)) ); connect( m_Controls->m_CheckDStar, SIGNAL(clicked()), this, SLOT(Checkbox()) ); connect( m_Controls->m_CheckD, SIGNAL(clicked()), this, SLOT(Checkbox()) ); connect( m_Controls->m_Checkf, SIGNAL(clicked()), this, SLOT(Checkbox()) ); - connect( m_Controls->m_ChooseMethod, SIGNAL(clicked()), this, SLOT(ChooseMethod()) ); connect( m_Controls->m_CurveClipboard, SIGNAL(clicked()), this, SLOT(ClipboardCurveButtonClicked()) ); connect( m_Controls->m_ValuesClipboard, SIGNAL(clicked()), this, SLOT(ClipboardStatisticsButtonClicked()) ); + connect( m_Controls->m_SavePlot, SIGNAL(clicked()), this, SLOT(SavePlotButtonClicked()) ); // connect all kurtosis actions to a recompute connect( m_Controls->m_KurtosisRangeWidget, SIGNAL( rangeChanged(double, double)), this, SLOT(OnKurtosisParamsChanged() ) ); - //connect( m_Controls->m_MaximalBValueWidget, SIGNAL( valueChanged(double)), this, SLOT( OnKurtosisParamsChanged() ) ); connect( m_Controls->m_OmitBZeroCB, SIGNAL( stateChanged(int) ), this, SLOT( OnKurtosisParamsChanged() ) ); connect( m_Controls->m_KurtosisFitScale, SIGNAL( currentIndexChanged(int)), this, SLOT( OnKurtosisParamsChanged() ) ); connect( m_Controls->m_UseKurtosisBoundsCB, SIGNAL(clicked() ), this, SLOT( OnKurtosisParamsChanged() ) ); - m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); - connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); - - m_Controls->m_DwiBox->SetDataStorage(this->GetDataStorage()); mitk::NodePredicateIsDWI::Pointer isDwi = mitk::NodePredicateIsDWI::New(); m_Controls->m_DwiBox->SetPredicate( isDwi ); connect( (QObject*)(m_Controls->m_DwiBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); m_Controls->m_MaskBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MaskBox->SetZeroEntryText("--"); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateDimension::Pointer is3D = mitk::NodePredicateDimension::New(3); m_Controls->m_MaskBox->SetPredicate( mitk::NodePredicateAnd::New(isBinaryPredicate, mitk::NodePredicateAnd::New(isImagePredicate, is3D)) ); connect( (QObject*)(m_Controls->m_MaskBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); - connect( (QObject*)(m_Controls->m_ModelTabSelectionWidget), SIGNAL(currentChanged(int)), this, SLOT(UpdateGui())); - + connect( (QObject*)(m_Controls->m_ModelTabSelectionWidget), SIGNAL(currentChanged(int)), this, SLOT(OnModelTabChanged(int))); } QString dstar = QString::number(m_Controls->m_DStarSlider->value()/1000.0); m_Controls->m_DStarLabel->setText(dstar); QString bthresh = QString::number(m_Controls->m_BThreshSlider->value()*5.0); m_Controls->m_BThreshLabel->setText(bthresh); QString s0thresh = QString::number(m_Controls->m_S0ThreshSlider->value()*0.5); m_Controls->m_S0ThreshLabel->setText(s0thresh); QString numits = QString::number(m_Controls->m_NumItSlider->value()); m_Controls->m_NumItsLabel->setText(numits); QString lambda = QString::number(m_Controls->m_LambdaSlider->value()*.00001); m_Controls->m_LambdaLabel->setText(lambda); - m_Controls->m_MethodCombo->setVisible(m_Controls->m_ChooseMethod->isChecked()); m_Controls->m_Warning->setVisible(false); - MethodCombo(m_Controls->m_MethodCombo->currentIndex()); + OnIvimFitChanged(m_Controls->m_MethodCombo->currentIndex()); m_Controls->m_KurtosisRangeWidget->setSingleStep(0.1); m_Controls->m_KurtosisRangeWidget->setRange( 0.0, 10.0 ); m_Controls->m_KurtosisRangeWidget->setMaximumValue( 5.0 ); // LogScale not working yet, have to fix that first // m_Controls->m_KurtosisFitScale->setEnabled(false); //m_Controls->m_MaximalBValueWidget->setVisible( false ); // release update block after the UI-elements were all set this->m_HoldUpdate = false; + QmitkIVIMView::InitChartIvim(); + + m_ListenerActive = false; + + if (this->GetRenderWindowPart()) + { + m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); + connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); + m_ListenerActive = true; + } +} + +void QmitkIVIMView::OnModelTabChanged(int tab) +{ + if (tab==0) + InitChartIvim(); + else if (tab==1) + InitChartKurtosis(); + + UpdateGui(); +} + +void QmitkIVIMView::AddSecondFitPlot() +{ + if (m_Controls->m_ChartWidget->GetDataElementByLabel("signal values (used for second fit)") == nullptr) + { + std::map< double, double > init_data; + m_Controls->m_ChartWidget->AddData2D(init_data, "signal values (used for second fit)", QmitkChartWidget::ChartType::scatter); + m_Controls->m_ChartWidget->SetColor("signal values (used for second fit)", "white"); + m_Controls->m_ChartWidget->SetMarkerSymbol("signal values (used for second fit)", QmitkChartWidget::MarkerSymbol::x_thin); + + m_Controls->m_ChartWidget->Show(true); + m_Controls->m_ChartWidget->SetShowDataPoints(false); + m_Controls->m_ChartWidget->SetShowSubchart(false); + } +} + +void QmitkIVIMView::RemoveSecondFitPlot() +{ + if (m_Controls->m_ChartWidget->GetDataElementByLabel("signal values (used for second fit)") != nullptr) + { + m_Controls->m_ChartWidget->RemoveData("signal values (used for second fit)"); + + m_Controls->m_ChartWidget->Show(true); + m_Controls->m_ChartWidget->SetShowDataPoints(false); + m_Controls->m_ChartWidget->SetShowSubchart(false); + } +} + +void QmitkIVIMView::InitChartIvim() +{ + m_Controls->m_ChartWidget->Clear(); + std::map< double, double > init_data; + m_Controls->m_ChartWidget->AddData2D(init_data, "D-part of fitted model", QmitkChartWidget::ChartType::line); + m_Controls->m_ChartWidget->AddData2D(init_data, "fitted model", QmitkChartWidget::ChartType::line); + m_Controls->m_ChartWidget->AddData2D(init_data, "signal values", QmitkChartWidget::ChartType::scatter); + + m_Controls->m_ChartWidget->SetColor("fitted model", "red"); + m_Controls->m_ChartWidget->SetColor("signal values", "white"); + m_Controls->m_ChartWidget->SetColor("D-part of fitted model", "cyan"); + m_Controls->m_ChartWidget->SetYAxisScale(QmitkChartWidget::AxisScale::log); + + m_Controls->m_ChartWidget->SetYAxisLabel("S/S0"); + m_Controls->m_ChartWidget->SetXAxisLabel("b-value"); + + m_Controls->m_ChartWidget->SetLineStyle("fitted model", QmitkChartWidget::LineStyle::solid); + m_Controls->m_ChartWidget->SetLineStyle("D-part of fitted model", QmitkChartWidget::LineStyle::dashed); + + m_Controls->m_ChartWidget->SetMarkerSymbol("signal values", QmitkChartWidget::MarkerSymbol::diamond); + + m_Controls->m_ChartWidget->Show(true); + m_Controls->m_ChartWidget->SetShowDataPoints(false); + m_Controls->m_ChartWidget->SetShowSubchart(false); + +} + +void QmitkIVIMView::InitChartKurtosis() +{ + m_Controls->m_ChartWidget->Clear(); + std::map< double, double > init_data; + m_Controls->m_ChartWidget->AddData2D(init_data, "D-part of fitted model", QmitkChartWidget::ChartType::line); + m_Controls->m_ChartWidget->AddData2D(init_data, "fitted model", QmitkChartWidget::ChartType::line); + m_Controls->m_ChartWidget->AddData2D(init_data, "signal values", QmitkChartWidget::ChartType::scatter); + + m_Controls->m_ChartWidget->SetColor("fitted model", "red"); + m_Controls->m_ChartWidget->SetColor("signal values", "white"); + m_Controls->m_ChartWidget->SetColor("D-part of fitted model", "cyan"); + m_Controls->m_ChartWidget->SetYAxisScale(QmitkChartWidget::AxisScale::log); + + m_Controls->m_ChartWidget->SetYAxisLabel("S"); + m_Controls->m_ChartWidget->SetXAxisLabel("b-value"); + + m_Controls->m_ChartWidget->SetLineStyle("fitted model", QmitkChartWidget::LineStyle::solid); + m_Controls->m_ChartWidget->SetLineStyle("D-part of fitted model", QmitkChartWidget::LineStyle::dashed); + + m_Controls->m_ChartWidget->SetMarkerSymbol("signal values", QmitkChartWidget::MarkerSymbol::diamond); + + m_Controls->m_ChartWidget->Show(true); + m_Controls->m_ChartWidget->SetShowDataPoints(false); + m_Controls->m_ChartWidget->SetShowSubchart(false); } void QmitkIVIMView::SetFocus() { m_Controls->m_ButtonAutoThres->setFocus(); } void QmitkIVIMView::Checkbox() { OnSliceChanged(); } -void QmitkIVIMView::MethodCombo(int val) +void QmitkIVIMView::OnIvimFitChanged(int val) { switch(val) { case 0: m_Controls->m_DstarFrame->setVisible(false); m_Controls->m_NeglSiFrame->setVisible(true); m_Controls->m_NeglBframe->setVisible(false); m_Controls->m_IterationsFrame->setVisible(false); m_Controls->m_LambdaFrame->setVisible(false); break; case 1: m_Controls->m_DstarFrame->setVisible(true); m_Controls->m_NeglSiFrame->setVisible(true); m_Controls->m_NeglBframe->setVisible(false); m_Controls->m_IterationsFrame->setVisible(false); m_Controls->m_LambdaFrame->setVisible(false); break; case 2: m_Controls->m_DstarFrame->setVisible(false); m_Controls->m_NeglSiFrame->setVisible(true); m_Controls->m_NeglBframe->setVisible(true); m_Controls->m_IterationsFrame->setVisible(false); m_Controls->m_LambdaFrame->setVisible(false); break; case 3: m_Controls->m_DstarFrame->setVisible(false); m_Controls->m_NeglSiFrame->setVisible(true); m_Controls->m_NeglBframe->setVisible(true); m_Controls->m_IterationsFrame->setVisible(false); m_Controls->m_LambdaFrame->setVisible(false); break; case 4: m_Controls->m_DstarFrame->setVisible(false); m_Controls->m_NeglSiFrame->setVisible(false); m_Controls->m_NeglBframe->setVisible(false); m_Controls->m_IterationsFrame->setVisible(false); m_Controls->m_LambdaFrame->setVisible(false); break; } OnSliceChanged(); } void QmitkIVIMView::DStarSlider (int val) { QString sval = QString::number(val/1000.0); m_Controls->m_DStarLabel->setText(sval); OnSliceChanged(); } void QmitkIVIMView::BThreshSlider (int val) { QString sval = QString::number(val*5.0); m_Controls->m_BThreshLabel->setText(sval); OnSliceChanged(); } void QmitkIVIMView::S0ThreshSlider (int val) { QString sval = QString::number(val*0.5); m_Controls->m_S0ThreshLabel->setText(sval); OnSliceChanged(); } void QmitkIVIMView::NumItsSlider (int val) { QString sval = QString::number(val); m_Controls->m_NumItsLabel->setText(sval); OnSliceChanged(); } void QmitkIVIMView::LambdaSlider (int val) { QString sval = QString::number(val*.00001); m_Controls->m_LambdaLabel->setText(sval); OnSliceChanged(); } void QmitkIVIMView::UpdateGui() { + m_Controls->m_FittedParamsLabel->setText(""); if (m_Controls->m_DwiBox->GetSelectedNode().IsNotNull()) { - m_Controls->m_VisualizeResultsWidget->setVisible(true); - m_Controls->m_KurtosisVisualizationWidget->setVisible(true); - + m_Controls->m_ChartWidget->setVisible(true); m_HoldUpdate = false; } else { - m_Controls->m_VisualizeResultsWidget->setVisible(false); - m_Controls->m_KurtosisVisualizationWidget->setVisible(false); + m_Controls->m_ChartWidget->setVisible(false); } m_Controls->m_ButtonStart->setEnabled( m_Controls->m_DwiBox->GetSelectedNode().IsNotNull() ); m_Controls->m_ButtonAutoThres->setEnabled( m_Controls->m_DwiBox->GetSelectedNode().IsNotNull() ); m_Controls->m_ControlsFrame->setEnabled( m_Controls->m_DwiBox->GetSelectedNode().IsNotNull() ); m_Controls->m_BottomControlsFrame->setEnabled( m_Controls->m_DwiBox->GetSelectedNode().IsNotNull() ); OnSliceChanged(); } void QmitkIVIMView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& ) { - UpdateGui(); +// UpdateGui(); } void QmitkIVIMView::AutoThreshold() { if (m_Controls->m_DwiBox->GetSelectedNode().IsNull()) { // Nothing selected. Inform the user and return QMessageBox::information( nullptr, "Template", "Please load and select a diffusion image before starting image processing."); return; } mitk::Image* dimg = dynamic_cast(m_Controls->m_DwiBox->GetSelectedNode()->GetData()); if (!dimg) { // Nothing selected. Inform the user and return QMessageBox::information( nullptr, "Template", "No valid diffusion image was found."); return; } // find bzero index int index = -1; auto directions = mitk::DiffusionPropertyHelper::GetGradientContainer(dimg); for(DirContainerType::ConstIterator it = directions->Begin(); it != directions->End(); ++it) { index++; GradientDirectionType g = it.Value(); if(g[0] == 0 && g[1] == 0 && g[2] == 0 ) break; } VecImgType::Pointer vecimg = VecImgType::New(); mitk::CastToItkImage(dimg, vecimg); int vecLength = vecimg->GetVectorLength(); index = index > vecLength-1 ? vecLength-1 : index; MITK_INFO << "Performing Histogram Analysis on Channel" << index; typedef itk::Image ImgType; ImgType::Pointer img = ImgType::New(); mitk::CastToItkImage(dimg, img); itk::ImageRegionIterator itw (img, img->GetLargestPossibleRegion() ); itw.GoToBegin(); itk::ImageRegionConstIterator itr (vecimg, vecimg->GetLargestPossibleRegion() ); itr.GoToBegin(); while(!itr.IsAtEnd()) { itw.Set(itr.Get().GetElement(index)); ++itr; ++itw; } typedef itk::Statistics::ScalarImageToHistogramGenerator< ImgType > HistogramGeneratorType; typedef HistogramGeneratorType::HistogramType HistogramType; HistogramGeneratorType::Pointer histogramGenerator = HistogramGeneratorType::New(); histogramGenerator->SetInput( img ); histogramGenerator->SetMarginalScale( 10 ); // Defines y-margin width of histogram histogramGenerator->SetNumberOfBins( 100 ); // CT range [-1024, +2048] --> bin size 4 values histogramGenerator->SetHistogramMin( dimg->GetStatistics()->GetScalarValueMin() ); histogramGenerator->SetHistogramMax( dimg->GetStatistics()->GetScalarValueMax() * .5 ); histogramGenerator->Compute(); HistogramType::ConstIterator iter = histogramGenerator->GetOutput()->Begin(); float maxFreq = 0; float maxValue = 0; while ( iter != histogramGenerator->GetOutput()->End() ) { if(iter.GetFrequency() > maxFreq) { maxFreq = iter.GetFrequency(); maxValue = iter.GetMeasurementVector()[0]; } ++iter; } maxValue *= 2; int sliderPos = maxValue * 2; m_Controls->m_S0ThreshSlider->setValue(sliderPos); S0ThreshSlider(sliderPos); } void QmitkIVIMView::FittIVIMStart() { if (m_Controls->m_DwiBox->GetSelectedNode().IsNull()) { QMessageBox::information( nullptr, "Template", "No valid diffusion-weighted image selected."); return; } mitk::Image* img = dynamic_cast(m_Controls->m_DwiBox->GetSelectedNode()->GetData()); VecImgType::Pointer vecimg = VecImgType::New(); mitk::CastToItkImage(img, vecimg); OutImgType::IndexType dummy; if( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) { // KURTOSIS KurtosisFilterType::Pointer filter = KurtosisFilterType::New(); filter->SetInput(vecimg); filter->SetReferenceBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(img)); filter->SetGradientDirections(mitk::DiffusionPropertyHelper::GetGradientContainer(img)); - filter->SetSmoothingSigma( this->m_Controls->m_SigmaSpinBox->value() ); + filter->SetSmoothingSigma( m_Controls->m_SigmaSpinBox->value() ); - if( this->m_Controls->m_UseKurtosisBoundsCB->isChecked() ) - filter->SetBoundariesForKurtosis( this->m_Controls->m_KurtosisRangeWidget->minimumValue(), this->m_Controls->m_KurtosisRangeWidget->maximumValue() ); + if( m_Controls->m_UseKurtosisBoundsCB->isChecked() ) + filter->SetBoundariesForKurtosis( m_Controls->m_KurtosisRangeWidget->minimumValue(), m_Controls->m_KurtosisRangeWidget->maximumValue() ); - filter->SetFittingScale( static_cast(this->m_Controls->m_KurtosisFitScale->currentIndex() ) ); + filter->SetFittingScale( static_cast(m_Controls->m_KurtosisFitScale->currentIndex() ) ); if( m_Controls->m_MaskBox->GetSelectedNode().IsNotNull() ) { mitk::Image::Pointer maskImg = dynamic_cast(m_Controls->m_MaskBox->GetSelectedNode()->GetData()); typedef itk::Image MaskImgType; MaskImgType::Pointer maskItk; CastToItkImage( maskImg, maskItk ); filter->SetImageMask( maskItk ); } filter->Update(); mitk::LookupTable::Pointer kurt_map_lut = mitk::LookupTable::New(); kurt_map_lut->SetType( mitk::LookupTable::JET ); mitk::LookupTableProperty::Pointer kurt_lut_prop = mitk::LookupTableProperty::New(); kurt_lut_prop->SetLookupTable( kurt_map_lut ); mitk::Image::Pointer dimage = mitk::Image::New(); dimage->InitializeByItk( filter->GetOutput(0) ); dimage->SetVolume( filter->GetOutput(0)->GetBufferPointer()); mitk::Image::Pointer kimage = mitk::Image::New(); kimage->InitializeByItk( filter->GetOutput(1) ); kimage->SetVolume( filter->GetOutput(1)->GetBufferPointer()); QString new_dname = "Kurtosis_DMap"; new_dname.append("_Method-"+m_Controls->m_KurtosisFitScale->currentText()); QString new_kname = "Kurtosis_KMap"; new_kname.append("_Method-"+m_Controls->m_KurtosisFitScale->currentText()); - if( this->m_Controls->m_CheckKurtD->isChecked() ) + if( m_Controls->m_CheckKurtD->isChecked() ) { mitk::DataNode::Pointer dnode = mitk::DataNode::New(); dnode->SetData( dimage ); dnode->SetName(new_dname.toLatin1()); dnode->SetProperty("LookupTable", kurt_lut_prop ); GetDataStorage()->Add(dnode, m_Controls->m_DwiBox->GetSelectedNode()); } - if( this->m_Controls->m_CheckKurtK->isChecked() ) + if( m_Controls->m_CheckKurtK->isChecked() ) { mitk::DataNode::Pointer knode = mitk::DataNode::New(); knode->SetData( kimage ); knode->SetName(new_kname.toLatin1()); knode->SetProperty("LookupTable", kurt_lut_prop ); GetDataStorage()->Add(knode, m_Controls->m_DwiBox->GetSelectedNode()); } } else { FittIVIM(vecimg, mitk::DiffusionPropertyHelper::GetGradientContainer(img), mitk::DiffusionPropertyHelper::GetReferenceBValue(img), true, dummy); OutputToDatastorage(m_Controls->m_DwiBox->GetSelectedNode()); } } void QmitkIVIMView::OnKurtosisParamsChanged() { OnSliceChanged(); } void QmitkIVIMView::OnSliceChanged() { if(m_HoldUpdate || !m_Visible) return; m_Controls->m_Warning->setVisible(false); - if(!m_Controls || m_Controls->m_DwiBox->GetSelectedNode().IsNull()) + if(m_Controls->m_DwiBox->GetSelectedNode().IsNull()) return; - m_Controls->m_VisualizeResultsWidget->setVisible(false); - m_Controls->m_KurtosisVisualizationWidget->setVisible(false); - mitk::Image::Pointer diffusionImg = dynamic_cast(m_Controls->m_DwiBox->GetSelectedNode()->GetData()); mitk::Image::Pointer maskImg = nullptr; if (m_Controls->m_MaskBox->GetSelectedNode().IsNotNull()) maskImg = dynamic_cast(m_Controls->m_MaskBox->GetSelectedNode()->GetData()); - if (!this->GetRenderWindowPart()) return; + if (!this->GetRenderWindowPart()) + return; + + if (!m_ListenerActive) + { + m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); + connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); + m_ListenerActive = true; + } VecImgType::Pointer vecimg = VecImgType::New(); mitk::CastToItkImage(diffusionImg, vecimg); VecImgType::Pointer roiImage = VecImgType::New(); - bool success = false; if(maskImg.IsNull()) { int roisize = 0; if(m_Controls->m_MethodCombo->currentIndex() == 4) roisize = 5; mitk::Point3D pos = this->GetRenderWindowPart()->GetSelectedPosition(); VecImgType::IndexType crosspos; diffusionImg->GetGeometry()->WorldToIndex(pos, crosspos); if (!vecimg->GetLargestPossibleRegion().IsInside(crosspos)) { m_Controls->m_Warning->setText(QString("Crosshair position not inside of selected diffusion weighted image. Reinit needed!")); m_Controls->m_Warning->setVisible(true); return; } else m_Controls->m_Warning->setVisible(false); VecImgType::IndexType index; index[0] = crosspos[0] - roisize; index[0] = index[0] < 0 ? 0 : index[0]; index[1] = crosspos[1] - roisize; index[1] = index[1] < 0 ? 0 : index[1]; index[2] = crosspos[2] - roisize; index[2] = index[2] < 0 ? 0 : index[2]; VecImgType::SizeType size; size[0] = roisize*2+1; size[1] = roisize*2+1; size[2] = roisize*2+1; VecImgType::SizeType maxSize = vecimg->GetLargestPossibleRegion().GetSize(); size[0] = index[0]+size[0] > maxSize[0] ? maxSize[0]-index[0] : size[0]; size[1] = index[1]+size[1] > maxSize[1] ? maxSize[1]-index[1] : size[1]; size[2] = index[2]+size[2] > maxSize[2] ? maxSize[2]-index[2] : size[2]; VecImgType::RegionType region; region.SetSize( size ); region.SetIndex( index ); vecimg->SetRequestedRegion( region ); VecImgType::IndexType newstart; newstart.Fill(0); VecImgType::RegionType newregion; newregion.SetSize( size ); newregion.SetIndex( newstart ); roiImage->CopyInformation( vecimg ); roiImage->SetRegions( newregion ); roiImage->SetOrigin( pos ); roiImage->Allocate(); roiImage->SetPixel(newstart, vecimg->GetPixel(index)); if( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) { - success = FitKurtosis(roiImage, - mitk::DiffusionPropertyHelper::GetGradientContainer(diffusionImg), - mitk::DiffusionPropertyHelper::GetReferenceBValue(diffusionImg), - newstart); + FitKurtosis(roiImage, + mitk::DiffusionPropertyHelper::GetGradientContainer(diffusionImg), + mitk::DiffusionPropertyHelper::GetReferenceBValue(diffusionImg), + newstart); } else { - success = FittIVIM(roiImage, - mitk::DiffusionPropertyHelper::GetGradientContainer(diffusionImg), - mitk::DiffusionPropertyHelper::GetReferenceBValue(diffusionImg), - false, - crosspos); + FittIVIM(roiImage, + mitk::DiffusionPropertyHelper::GetGradientContainer(diffusionImg), + mitk::DiffusionPropertyHelper::GetReferenceBValue(diffusionImg), + false, + crosspos); } } else { typedef itk::Image MaskImgType; MaskImgType::Pointer maskItk; CastToItkImage( maskImg, maskItk ); mitk::Point3D pos; pos[0] = 0; pos[1] = 0; pos[2] = 0; VecImgType::IndexType index; index[0] = 0; index[1] = 0; index[2] = 0; VecImgType::SizeType size; size[0] = 1; size[1] = 1; size[2] = 1; VecImgType::RegionType region; region.SetSize( size ); region.SetIndex( index ); vecimg->SetRequestedRegion( region ); // iterators over output and input itk::ImageRegionConstIteratorWithIndex vecit(vecimg, vecimg->GetLargestPossibleRegion()); itk::VariableLengthVector avg(vecimg->GetVectorLength()); avg.Fill(0); float numPixels = 0; while ( ! vecit.IsAtEnd() ) { VecImgType::PointType point; vecimg->TransformIndexToPhysicalPoint(vecit.GetIndex(), point); MaskImgType::IndexType index; maskItk->TransformPhysicalPointToIndex(point, index); if(maskItk->GetPixel(index) != 0) { avg += vecit.Get(); numPixels += 1.0; } // update iterators ++vecit; } avg /= numPixels; m_Controls->m_Warning->setText(QString("Averaging ")+QString::number((int)numPixels)+QString(" voxels!")); m_Controls->m_Warning->setVisible(true); roiImage->CopyInformation( vecimg ); roiImage->SetRegions( region ); roiImage->SetOrigin( pos ); roiImage->Allocate(); roiImage->SetPixel(index, avg); if( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) { - success = FitKurtosis(roiImage, - mitk::DiffusionPropertyHelper::GetGradientContainer(diffusionImg), - mitk::DiffusionPropertyHelper::GetReferenceBValue(diffusionImg), - index); + FitKurtosis(roiImage, + mitk::DiffusionPropertyHelper::GetGradientContainer(diffusionImg), + mitk::DiffusionPropertyHelper::GetReferenceBValue(diffusionImg), + index); } else { - success = FittIVIM(roiImage, - mitk::DiffusionPropertyHelper::GetGradientContainer(diffusionImg), - mitk::DiffusionPropertyHelper::GetReferenceBValue(diffusionImg), - false, - index); + FittIVIM(roiImage, + mitk::DiffusionPropertyHelper::GetGradientContainer(diffusionImg), + mitk::DiffusionPropertyHelper::GetReferenceBValue(diffusionImg), + false, + index); } // do not update until selection changed, the values will remain the same as long as the mask is selected! m_HoldUpdate = true; - } vecimg->SetRegions( vecimg->GetLargestPossibleRegion() ); - - if (success) - { - // 0 - IVIM, 1 - Kurtosis - if( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) - { - m_Controls->m_KurtosisVisualizationWidget->setVisible(true); - m_Controls->m_KurtosisVisualizationWidget->SetData(m_KurtosisSnap); - } - else - { - m_Controls->m_VisualizeResultsWidget->setVisible(true); - m_Controls->m_VisualizeResultsWidget->SetParameters(m_Snap); - } - } } bool QmitkIVIMView::FitKurtosis( itk::VectorImage *vecimg, DirContainerType *dirs, float bval, OutImgType::IndexType &crosspos ) { KurtosisFilterType::Pointer filter = KurtosisFilterType::New(); itk::KurtosisFitConfiguration fit_config; - fit_config.omit_bzero = this->m_Controls->m_OmitBZeroCB->isChecked(); - if( this->m_Controls->m_UseKurtosisBoundsCB->isChecked() ) + fit_config.omit_bzero = m_Controls->m_OmitBZeroCB->isChecked(); + if( m_Controls->m_UseKurtosisBoundsCB->isChecked() ) { fit_config.use_K_limits = true; vnl_vector_fixed k_limits; - k_limits[0] = this->m_Controls->m_KurtosisRangeWidget->minimumValue(); - k_limits[1] = this->m_Controls->m_KurtosisRangeWidget->maximumValue(); + k_limits[0] = m_Controls->m_KurtosisRangeWidget->minimumValue(); + k_limits[1] = m_Controls->m_KurtosisRangeWidget->maximumValue(); fit_config.K_limits = k_limits; - } - fit_config.fit_scale = static_cast(this->m_Controls->m_KurtosisFitScale->currentIndex() ); + fit_config.fit_scale = static_cast(m_Controls->m_KurtosisFitScale->currentIndex() ); m_KurtosisSnap = filter->GetSnapshot( vecimg->GetPixel( crosspos ), dirs, bval, fit_config ); + QString param_label_text("K=%2, D=%1"); + param_label_text = param_label_text.arg( m_KurtosisSnap.m_K, 4); + param_label_text = param_label_text.arg( m_KurtosisSnap.m_D, 4); + m_Controls->m_FittedParamsLabel->setText(param_label_text); + + const double maxb = m_KurtosisSnap.bvalues.max_value(); + double S0 = m_KurtosisSnap.measurements[0]; + + std::map d_line; + d_line[0] = S0; + d_line[maxb] = d_line[0]*exp(-maxb * m_KurtosisSnap.m_D); + m_Controls->m_ChartWidget->UpdateData2D(d_line, "D-part of fitted model"); + + const unsigned int num_samples = 50; + std::map y; + + for( unsigned int i=0; i<=num_samples; ++i) + { + double b = (((1.0)*i)/(1.0*num_samples))*maxb; + y[b] = S0 * exp( -b * m_KurtosisSnap.m_D + b*b * m_KurtosisSnap.m_D * m_KurtosisSnap.m_D * m_KurtosisSnap.m_K / 6.0 ); + } + m_Controls->m_ChartWidget->UpdateData2D(y, "fitted model"); + + std::map y_meas; + for (unsigned int i=0; im_OmitBZeroCB->isChecked() || m_KurtosisSnap.bvalues[i] > 0.01) + y_meas[m_KurtosisSnap.bvalues[i]] = m_KurtosisSnap.measurements[i]; + + m_Controls->m_ChartWidget->UpdateData2D(y_meas, "signal values"); + return true; } bool QmitkIVIMView::FittIVIM(itk::VectorImage* vecimg, DirContainerType* dirs, float bval, bool multivoxel, OutImgType::IndexType &crosspos) { IVIMFilterType::Pointer filter = IVIMFilterType::New(); filter->SetInput(vecimg); filter->SetGradientDirections(dirs); filter->SetBValue(bval); switch(m_Controls->m_MethodCombo->currentIndex()) { case 0: filter->SetMethod(IVIMFilterType::IVIM_FIT_ALL); filter->SetS0Thres(m_Controls->m_S0ThreshLabel->text().toDouble()); break; case 1: filter->SetMethod(IVIMFilterType::IVIM_DSTAR_FIX); filter->SetDStar(m_Controls->m_DStarLabel->text().toDouble()); filter->SetS0Thres(m_Controls->m_S0ThreshLabel->text().toDouble()); break; case 2: filter->SetMethod(IVIMFilterType::IVIM_D_THEN_DSTAR); filter->SetBThres(m_Controls->m_BThreshLabel->text().toDouble()); filter->SetS0Thres(m_Controls->m_S0ThreshLabel->text().toDouble()); filter->SetFitDStar(m_Controls->m_CheckDStar->isChecked()); break; case 3: filter->SetMethod(IVIMFilterType::IVIM_LINEAR_D_THEN_F); filter->SetBThres(m_Controls->m_BThreshLabel->text().toDouble()); filter->SetS0Thres(m_Controls->m_S0ThreshLabel->text().toDouble()); filter->SetFitDStar(m_Controls->m_CheckDStar->isChecked()); break; case 4: filter->SetMethod(IVIMFilterType::IVIM_REGULARIZED); filter->SetBThres(m_Controls->m_BThreshLabel->text().toDouble()); filter->SetS0Thres(m_Controls->m_S0ThreshLabel->text().toDouble()); filter->SetNumberIterations(m_Controls->m_NumItsLabel->text().toInt()); filter->SetLambda(m_Controls->m_LambdaLabel->text().toDouble()); filter->SetFitDStar(m_Controls->m_CheckDStar->isChecked()); break; } if(!multivoxel) { filter->SetFitDStar(true); } filter->SetNumberOfThreads(1); filter->SetVerbose(false); filter->SetCrossPosition(crosspos); try{ filter->Update(); - m_Snap = filter->GetSnapshot(); + m_IvimSnap = filter->GetSnapshot(); m_DStarMap = filter->GetOutput(2); m_DMap = filter->GetOutput(1); m_fMap = filter->GetOutput(); + + QString param_label_text("f=%1, D=%2, D*=%3"); + param_label_text = param_label_text.arg(m_IvimSnap.currentF,4); + param_label_text = param_label_text.arg(m_IvimSnap.currentD,4); + param_label_text = param_label_text.arg(m_IvimSnap.currentDStar,4); + m_Controls->m_FittedParamsLabel->setText(param_label_text); + + double maxb = m_IvimSnap.bvalues.max_value(); + + std::map d_line; + d_line[0] = 1-m_IvimSnap.currentFunceiled; + d_line[maxb] = d_line[0]*exp(-maxb * m_IvimSnap.currentD); + m_Controls->m_ChartWidget->UpdateData2D(d_line, "D-part of fitted model"); + + if(m_IvimSnap.currentDStar != 0) + { + std::map y; + int nsampling = 50; + double f = 1-m_IvimSnap.currentFunceiled; + for(int i=0; i<=nsampling; i++) + { + double x = (((1.0)*i)/(1.0*nsampling))*maxb; + y[x] = f*exp(- x * m_IvimSnap.currentD) + (1-f)*exp(- x * (m_IvimSnap.currentD+m_IvimSnap.currentDStar)); + } + m_Controls->m_ChartWidget->UpdateData2D(y, "fitted model"); + + std::map y_meas; + for (unsigned int i=0; im_ChartWidget->UpdateData2D(y_meas, "signal values"); + + if(!m_IvimSnap.high_indices.empty()) + { + MITK_INFO << "m_Snap.high_indices found"; + AddSecondFitPlot(); + std::map additonal_meas; + for (int i=0; im_ChartWidget->UpdateData2D(additonal_meas, "signal values (used for second fit)"); + } + else + { + MITK_INFO << "NO m_Snap.high_indices found"; + RemoveSecondFitPlot(); + } + } } catch (itk::ExceptionObject &ex) { MITK_INFO << ex ; m_Controls->m_Warning->setText(QString("IVIM fit not possible: ")+ex.GetDescription()); m_Controls->m_Warning->setVisible(true); return false; } return true; } void QmitkIVIMView::OutputToDatastorage(mitk::DataNode::Pointer node) { mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType( mitk::LookupTable::JET ); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable( lut ); if(m_Controls->m_CheckDStar->isChecked()) { mitk::Image::Pointer dstarimage = mitk::Image::New(); dstarimage->InitializeByItk(m_DStarMap.GetPointer()); dstarimage->SetVolume(m_DStarMap->GetBufferPointer()); QString newname2 = ""; newname2 = newname2.append("IVIM_DStarMap_Method-%1").arg(m_Controls->m_MethodCombo->currentText()); mitk::DataNode::Pointer node2=mitk::DataNode::New(); node2->SetData( dstarimage ); node2->SetName(newname2.toLatin1()); node2->SetProperty("LookupTable", lut_prop ); GetDataStorage()->Add(node2, node); } if(m_Controls->m_CheckD->isChecked()) { mitk::Image::Pointer dimage = mitk::Image::New(); dimage->InitializeByItk(m_DMap.GetPointer()); dimage->SetVolume(m_DMap->GetBufferPointer()); QString newname1 = ""; newname1 = newname1.append("IVIM_DMap_Method-%1").arg(m_Controls->m_MethodCombo->currentText()); mitk::DataNode::Pointer node1=mitk::DataNode::New(); node1->SetData( dimage ); node1->SetName(newname1.toLatin1()); node1->SetProperty("LookupTable", lut_prop ); GetDataStorage()->Add(node1, node); } if(m_Controls->m_Checkf->isChecked()) { mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(m_fMap.GetPointer()); image->SetVolume(m_fMap->GetBufferPointer()); QString newname0 = ""; newname0 = newname0.append("IVIM_fMap_Method-%1").arg(m_Controls->m_MethodCombo->currentText()); mitk::DataNode::Pointer node3=mitk::DataNode::New(); node3->SetData( image ); node3->SetName(newname0.toLatin1()); node3->SetProperty("LookupTable", lut_prop ); GetDataStorage()->Add(node3, node); } this->GetRenderWindowPart()->RequestUpdate(); } -void QmitkIVIMView::ChooseMethod() -{ - m_Controls->m_MethodCombo->setVisible(m_Controls->m_ChooseMethod->isChecked()); -} - void QmitkIVIMView::ClipboardCurveButtonClicked() { // Kurtosis if ( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) { std::stringstream ss; QString clipboard("Measurement Points\n"); ss << m_KurtosisSnap.bvalues << "\n" << m_KurtosisSnap.measurements << "\n\n"; ss << "Fitted Values ( D K [b_0] ) \n" << m_KurtosisSnap.m_D << " " << m_KurtosisSnap.m_K; if( m_KurtosisSnap.m_fittedBZero ) ss << " " << m_KurtosisSnap.m_BzeroFit; ss << "\n\n"; clipboard.append( QString( ss.str().c_str() )); ss.str( std::string() ); ss.clear(); QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); } else { QString clipboard("Measurement Points\n"); - for ( unsigned int i=0; isetText( clipboard, QClipboard::Clipboard ); } } +void QmitkIVIMView::SavePlotButtonClicked() +{ + m_Controls->m_ChartWidget->SavePlotAsImage(); +} + void QmitkIVIMView::ClipboardStatisticsButtonClicked() { // Kurtosis if ( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) { QString clipboard( "D \t K \n" ); clipboard = clipboard.append( "%L1 \t %L2" ) - .arg( m_KurtosisSnap.m_D, 0, 'f', 10 ) - .arg( m_KurtosisSnap.m_K, 0, 'f', 10 ) ; + .arg( m_KurtosisSnap.m_D, 0, 'f', 10 ) + .arg( m_KurtosisSnap.m_K, 0, 'f', 10 ) ; QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); } else { QString clipboard( "f \t D \t D* \n" ); clipboard = clipboard.append( "%L1 \t %L2 \t %L3" ) - .arg( m_Snap.currentF, 0, 'f', 10 ) - .arg( m_Snap.currentD, 0, 'f', 10 ) - .arg( m_Snap.currentDStar, 0, 'f', 10 ) ; + .arg( m_IvimSnap.currentF, 0, 'f', 10 ) + .arg( m_IvimSnap.currentD, 0, 'f', 10 ) + .arg( m_IvimSnap.currentDStar, 0, 'f', 10 ) ; QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); } } void QmitkIVIMView::Activated() { m_Active = true; } void QmitkIVIMView::Deactivated() { m_Active = false; } void QmitkIVIMView::Visible() { m_Visible = true; - QList selection = GetDataManagerSelection(); - berry::IWorkbenchPart::Pointer nullPart; - OnSelectionChanged(nullPart, selection); + if (this->GetRenderWindowPart() and !m_ListenerActive) + { + m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); + connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); + m_ListenerActive = true; + } } void QmitkIVIMView::Hidden() { m_Visible = false; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.h b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.h index 3b4e060..63e87de 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMView.h @@ -1,127 +1,136 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _QMITKIVIMVIEW_H_INCLUDED #define _QMITKIVIMVIEW_H_INCLUDED #include #include #include #include #include "ui_QmitkIVIMViewControls.h" #include "itkVectorImage.h" #include "itkImage.h" #include #include "itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h" #include "itkDiffusionKurtosisReconstructionImageFilter.h" #include +#include /*! \brief QmitkIVIMView \warning This application module is not yet documented. Use "svn blame/praise/annotate" and ask the author to provide basic documentation. */ class QmitkIVIMView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; QmitkIVIMView(); virtual ~QmitkIVIMView(); typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType DirContainerType; typedef itk::DiffusionIntravoxelIncoherentMotionReconstructionImageFilter IVIMFilterType; typedef itk::DiffusionKurtosisReconstructionImageFilter KurtosisFilterType; typedef itk::VectorImage VecImgType; typedef itk::Image OutImgType; virtual void CreateQtPartControl(QWidget *parent) override; /// /// Sets the focus to an internal widget. /// virtual void SetFocus() override; void OutputToDatastorage(mitk::DataNode::Pointer node); bool FittIVIM(itk::VectorImage* vecimg, DirContainerType* dirs, float bval, bool multivoxel, OutImgType::IndexType &crosspos); void Activated() override; void Deactivated() override; void Visible() override; void Hidden() override; protected slots: void OnSliceChanged(); /// \brief Called when the user clicks the GUI button void FittIVIMStart(); void AutoThreshold(); - void MethodCombo(int val); + void OnModelTabChanged(int tab); + + void OnIvimFitChanged(int val); void Checkbox(); void DStarSlider(int val); void BThreshSlider(int val); void S0ThreshSlider(int val); void NumItsSlider(int val); void LambdaSlider(int val); - void ChooseMethod(); void ClipboardStatisticsButtonClicked(); void ClipboardCurveButtonClicked(); + void SavePlotButtonClicked(); void OnKurtosisParamsChanged(); void UpdateGui(); protected: + void InitChartIvim(); + void InitChartKurtosis(); + void AddSecondFitPlot(); + void RemoveSecondFitPlot(); + /// \brief called by QmitkAbstractView when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; bool FitKurtosis( itk::VectorImage *vecimg, DirContainerType *dirs, float bval, OutImgType::IndexType &crosspos); Ui::QmitkIVIMViewControls* m_Controls; OutImgType::Pointer m_DStarMap; OutImgType::Pointer m_DMap; OutImgType::Pointer m_fMap; - IVIMFilterType::IVIMSnapshot m_Snap; + IVIMFilterType::IVIMSnapshot m_IvimSnap; KurtosisFilterType::KurtosisSnapshot m_KurtosisSnap; bool m_Active; bool m_Visible; + bool m_ListenerActive; bool m_HoldUpdate; QmitkSliceNavigationListener m_SliceChangeListener; }; #endif // _QMITKIVIMVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui index aed0c64..4c9b10e 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui @@ -1,1199 +1,1218 @@ QmitkIVIMViewControls 0 0 423 - 1563 + 648 0 0 QmitkTemplate QCommandLinkButton:disabled { border: none; } QGroupBox { background-color: transparent; } 9 9 9 9 9 - - - - Intra Voxel Incoherent Motion Estimation - - - - 6 - - - 9 - - - 6 - - - 6 - - - - - - - - Input Data - - - - 6 - - - 6 - - - 6 - - - 6 - - - - - Optional ROI image - - - ROI: - - - - - - - DWI to analyze - - - Raw DWI: - - - - - - - - - - - - QFrame::NoFrame QFrame::Raised 0 0 0 0 warning display Qt::RichText true 0 0 16 16 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 16 16 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 16 16 QFrame::NoFrame QFrame::Raised 0 0 0 0 - + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + + + + Generate Parameter Maps + + + + QFrame::StyledPanel QFrame::Raised 0 0 0 0 0 0 0 IVIM Parameters 9 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 51 16777215 200 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 80 16777215 D* 100 60 Qt::Horizontal + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 130 + 0 + + + + + 130 + 16777215 + + + + Signal threshold: + + + + + + + 100 + + + 0 + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 30 + 16777215 + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 15 + 16777215 + + + + Calculate threshold from histogram + + + * + + + + + + + + + QFrame::NoFrame QFrame::Raised 0 0 0 0 0 130 0 130 16777215 Ignore b< (first fit) 250 34 Qt::Horizontal 51 16777215 46.5 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 - #iterations + #iterations: 100 10 Qt::Horizontal 30 16777215 TextLabel Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 - lambda + lambda: 1000 10 Qt::Horizontal 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 30 16777215 TextLabel Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 15 16777215 Calculate threshold from histogram * - - + + QFrame::NoFrame - QFrame::Plain + QFrame::Raised - + 0 0 0 0 - - 0 - - - - - 130 - 0 - - - - - 130 - 16777215 - - + - Signal threshold: + Fit method: - - - 100 - - - 0 - - - Qt::Horizontal - - - - - - - - 0 - 0 - - - - QFrame::NoFrame - - - QFrame::Raised + + + 2 - - - 0 + + + 3 Param. Fit - - 0 + + + + Fit D & f with fixed D* value - - 0 + + + + Fit D & f (high b), then fit D* - - 0 + + + + Linearly fit D & f (high b), then fit D* - - 0 + + + + Regularized fit - - - - - 0 - 0 - - - - - 30 - 16777215 - - - - TextLabel - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 15 - 16777215 - - - - Calculate threshold from histogram - - - * - - - - + QFrame::NoFrame QFrame::Raised 0 0 0 0 80 0 - Output Images + Output Maps f true D false D* false - - - - true - - - - 0 - 0 - - - - - 0 - 400 - - - - - - - - - - Choose Method - - - - - - - 2 - - - - 3 Param. Fit - - - - - Fit D & f with fixed D* value - - - - - Fit D & f (high b), then fit D* - - - - - Linearly fit D & f (high b), then fit D* - - - - - Regularized - - - - - - Kurtosis QFrame::StyledPanel QFrame::Raised 2 2 2 2 2 Smoothing sigma Select Fit Type Omit b=0 Measurements + + true + 80 0 - Output Images + Output Maps Force the fitting of K to remain within the given boundaries Boundaries for K Select if the data is fitted directly (straight) or the logarithmic equation is used Straight Fit Logarithmic Fit 2 QLayout::SetMaximumSize D false K true Signa for gaussian smoothing applied prior to map computation 0.000000000000000 5.000000000000000 0.100000000000000 On - - - - - 0 - 0 - - - - - 0 - 400 - - - - - - + + + + Input Data + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + Optional ROI image + + + ROI: + + + + + + + DWI to analyze + + + Raw DWI: + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Copy the signal values in the current voxel to the clipboard. + - Generate Output Images + Save plot as image - + QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 - - - QFrame::NoFrame + + + Copy the signal values in the current voxel to the clipboard. - - QFrame::Raised + + Signal values to clipboard - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Datapoints to Clipboard - - - - + + Copy the parameters of the curve fit in the current voxel to the clipboard. + - Parameters to Clipboard + Fit-parameters to clipboard + + + + Intra Voxel Incoherent Motion Estimation + + + + 6 + + + 9 + + + 6 + + + 6 + + + + + + + + + + + Qt::AlignCenter + + + QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
- QmitkIVIMWidget - QWidget -
QmitkIVIMWidget.h
- 1 -
- - QmitkKurtosisWidget + ctkRangeWidget QWidget -
QmitkKurtosisWidget.h
+
ctkRangeWidget.h
1
- ctkRangeWidget + QmitkChartWidget QWidget -
ctkRangeWidget.h
+
QmitkChartWidget.h
1