diff --git a/Modules/DiffusionImaging/DiffusionCore/cmdapps/CMakeLists.txt b/Modules/DiffusionImaging/DiffusionCore/cmdapps/CMakeLists.txt index ebacfe8cfe..11f0c2aa2b 100644 --- a/Modules/DiffusionImaging/DiffusionCore/cmdapps/CMakeLists.txt +++ b/Modules/DiffusionImaging/DiffusionCore/cmdapps/CMakeLists.txt @@ -1,43 +1,44 @@ option(BUILD_DiffusionMiniApps "Build commandline tools for diffusion" OFF) if(BUILD_DiffusionMiniApps OR MITK_BUILD_ALL_APPS) # needed include directories include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of diffusion miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( diffusionminiapps DwiDenoising^^ ImageResampler^^ ExportShImage^^ CopyGeometry^^ DiffusionIndices^^ QballReconstruction^^ Registration^^ TensorReconstruction^^ TensorDerivedMapsExtraction^^ DiffusionDICOMLoader^^ + DiffusionIVIMFit^^ ) foreach(diffusionminiapp ${diffusionminiapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${diffusionminiapp}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitkFunctionCreateCommandLineApp( NAME ${appname} DEPENDS MitkCore MitkDiffusionCore ${dependencies_list} PACKAGE_DEPENDS ITK ) endforeach() endif() diff --git a/Modules/DiffusionImaging/DiffusionCore/cmdapps/DiffusionIVIMFit.cpp b/Modules/DiffusionImaging/DiffusionCore/cmdapps/DiffusionIVIMFit.cpp new file mode 100644 index 0000000000..6c49d7a7d0 --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionCore/cmdapps/DiffusionIVIMFit.cpp @@ -0,0 +1,207 @@ +/*=================================================================== + +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 "mitkCommandLineParser.h" +#include +#include + +#include +#include + +//vnl_includes +#include "vnl/vnl_math.h" +#include "vnl/vnl_cost_function.h" +#include "vnl/vnl_least_squares_function.h" +#include "vnl/algo/vnl_lbfgsb.h" +#include "vnl/algo/vnl_lbfgs.h" + +#include "vnl/algo/vnl_levenberg_marquardt.h" + +typedef mitk::DiffusionPropertyHelper DPH; + +#include +#include + +#include + +#include +#include +#include + +DPH::ImageType::Pointer GetBlurredVectorImage( DPH::ImageType::Pointer vectorImage, double sigma) +{ + typedef itk::DiscreteGaussianImageFilter< itk::Image, itk::Image > GaussianFilterType; + + typedef itk::VectorIndexSelectionCastImageFilter< DPH::ImageType, itk::Image > IndexSelectionType; + IndexSelectionType::Pointer indexSelectionFilter = IndexSelectionType::New(); + indexSelectionFilter->SetInput( vectorImage ); + + typedef itk::ComposeImageFilter< itk::Image, DPH::ImageType > ComposeFilterType; + ComposeFilterType::Pointer vec_composer = ComposeFilterType::New(); + + for( unsigned int i=0; iGetVectorLength(); ++i) + { + GaussianFilterType::Pointer gaussian_filter = GaussianFilterType::New(); + + indexSelectionFilter->SetIndex( i ); + + gaussian_filter->SetInput( indexSelectionFilter->GetOutput() ); + gaussian_filter->SetVariance( sigma ); + + vec_composer->SetInput(i, gaussian_filter->GetOutput() ); + + gaussian_filter->Update(); + } + + try + { + vec_composer->Update(); + } + catch(const itk::ExceptionObject &e) + { + mitkThrow() << "[VectorImage.GaussianSmoothing] !! Failed with ITK Exception: " << e.what(); + } + + DPH::ImageType::Pointer smoothed_vector = vec_composer->GetOutput(); +/* + itk::ImageFileWriter< DPH::ImageType >::Pointer writer = + itk::ImageFileWriter< DPH::ImageType >::New(); + + writer->SetInput( smoothed_vector ); + writer->SetFileName( "/tmp/itk_smoothed_vector.nrrd"); + writer->Update();*/ + + return smoothed_vector; + + +} + +void KurtosisMapComputation( mitk::Image::Pointer input, std::string output_prefix ) +{ + DPH::ImageType::Pointer vectorImage = DPH::ImageType::New(); + mitk::CastToItkImage( input, vectorImage ); + + + + typedef itk::DiffusionKurtosisReconstructionImageFilter< short, double > KurtosisFilterType; + KurtosisFilterType::Pointer kurtosis_filter = KurtosisFilterType::New(); + + kurtosis_filter->SetInput( GetBlurredVectorImage( vectorImage, 1.5 ) ); + kurtosis_filter->SetReferenceBValue( DPH::GetReferenceBValue( input.GetPointer() ) ); + kurtosis_filter->SetGradientDirections( DPH::GetGradientContainer( input.GetPointer() ) ); + kurtosis_filter->SetNumberOfThreads(1); + + KurtosisFilterType::OutputImageRegionType o_region; + KurtosisFilterType::OutputImageRegionType::SizeType o_size; + KurtosisFilterType::OutputImageRegionType::IndexType o_index; + + o_index.Fill(0); o_size.Fill(0); + o_index[0] = 48; o_index[1] = 18; o_index[2] = 12; + o_size[0] = 16; o_size[1] = 24; o_size[2] = 1; + + o_region.SetSize( o_size ); + o_region.SetIndex( o_index ); + kurtosis_filter->SetMapOutputRegion( o_region ); + + try + { + kurtosis_filter->Update(); + } + catch( const itk::ExceptionObject& e) + { + mitkThrow() << "Kurtosis fit failed with an ITK Exception: " << e.what(); + } + + mitk::Image::Pointer d_image = mitk::Image::New(); + d_image->InitializeByItk( kurtosis_filter->GetOutput(0) ); + d_image->SetVolume( kurtosis_filter->GetOutput(0)->GetBufferPointer() ); + + mitk::Image::Pointer k_image = mitk::Image::New(); + k_image->InitializeByItk( kurtosis_filter->GetOutput(1) ); + k_image->SetVolume( kurtosis_filter->GetOutput(1)->GetBufferPointer() ); + + std::string outputD_FileName = output_prefix + "_ADC_map.nrrd"; + std::string outputK_FileName = output_prefix + "_AKC_map.nrrd"; + + try + { + mitk::IOUtil::Save( d_image, outputD_FileName ); + mitk::IOUtil::Save( k_image, outputK_FileName ); + } + catch( const itk::ExceptionObject& e) + { + mitkThrow() << "Failed to save the KurtosisFit Results due to exception: " << e.what(); + } + +} + +int main( int argc, char* argv[] ) +{ + + + mitkCommandLineParser parser; + + parser.setTitle("Diffusion IVIM (Kurtosis) Fit"); + parser.setCategory("Signal Reconstruction"); + parser.setContributor("MIC"); + parser.setDescription("Fitting of IVIM / Kurtosis"); + + parser.setArgumentPrefix("--","-"); + // mandatory arguments + parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input: ", "input image (DWI)", us::Any(), false); + parser.addArgument("output", "o", mitkCommandLineParser::String, "Output Preifx: ", "Prefix for the output images, will append _f, _K, _D accordingly ", us::Any(), false); + parser.addArgument("fit", "f", mitkCommandLineParser::String, "Input: ", "input image (DWI)", us::Any(), false); + + // optional arguments + parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Masking Image: ", "ROI (segmentation)", us::Any(), true); + + + std::map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + // mandatory arguments + std::string inFileName = us::any_cast(parsedArgs["input"]); + std::string out_prefix = us::any_cast(parsedArgs["output"]); + std::string fit_name = us::any_cast(parsedArgs["fit"]); + + mitk::Image::Pointer inputImage = mitk::IOUtil::LoadImage(inFileName); + if( !DPH::IsDiffusionWeightedImage( inputImage ) ) + { + MITK_ERROR("DiffusionIVIMFit.Input") << "No valid diffusion-weighted image provided, failed to load " << inFileName << " as DW Image. Aborting..."; + return EXIT_FAILURE; + } + + if( fit_name == "Kurtosis" ) + { + MITK_INFO("DiffusionIVIMFit.Main") << "-----[ Kurtosis Fit ]-----"; + + KurtosisMapComputation( inputImage, out_prefix ); + + } + else if (fit_name == "IVIM" ) + { + MITK_INFO("DiffusionIVIMFit.Main") << "IVIM Fit not fully implemented yet. Aborting..."; + return EXIT_FAILURE; + } + else + { + MITK_ERROR("DiffusionIVIMFit.Main") << "Unrecognized option: " << fit_name << ". Valid values [\"IVIM\", \"Kurtosis\"] \n Aborting... \n"; + return EXIT_FAILURE; + + } + +} diff --git a/Modules/DiffusionImaging/DiffusionCore/files.cmake b/Modules/DiffusionImaging/DiffusionCore/files.cmake index 03dc6dd50c..5c8ea4789a 100644 --- a/Modules/DiffusionImaging/DiffusionCore/files.cmake +++ b/Modules/DiffusionImaging/DiffusionCore/files.cmake @@ -1,151 +1,152 @@ set(CPP_FILES # DicomImport # DicomImport/mitkGroupDiffusionHeadersFilter.cpp DicomImport/mitkDicomDiffusionImageHeaderReader.cpp DicomImport/mitkGEDicomDiffusionImageHeaderReader.cpp DicomImport/mitkPhilipsDicomDiffusionImageHeaderReader.cpp DicomImport/mitkSiemensDicomDiffusionImageHeaderReader.cpp DicomImport/mitkSiemensMosaicDicomDiffusionImageHeaderReader.cpp DicomImport/mitkDiffusionDICOMFileReader.cpp DicomImport/mitkDiffusionHeaderDICOMFileReader.cpp DicomImport/mitkDiffusionHeaderSiemensDICOMFileReader.cpp DicomImport/mitkDiffusionHeaderSiemensDICOMFileHelper.cpp DicomImport/mitkDiffusionHeaderSiemensMosaicDICOMFileReader.cpp DicomImport/mitkDiffusionHeaderGEDICOMFileReader.cpp DicomImport/mitkDiffusionHeaderPhilipsDICOMFileReader.cpp # DataStructures -> DWI IODataStructures/DiffusionWeightedImages/mitkDiffusionImageHeaderInformation.cpp IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCorrectionFilter.cpp IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.cpp # Properties IODataStructures/Properties/mitkBValueMapProperty.cpp IODataStructures/Properties/mitkGradientDirectionsProperty.cpp IODataStructures/Properties/mitkMeasurementFrameProperty.cpp IODataStructures/Properties/mitkDiffusionPropertyHelper.cpp IODataStructures/Properties/mitkNodePredicateIsDWI.cpp # Serializer IODataStructures/Properties/mitkBValueMapPropertySerializer.cpp IODataStructures/Properties/mitkGradientDirectionsPropertySerializer.cpp IODataStructures/Properties/mitkMeasurementFramePropertySerializer.cpp # DataStructures -> QBall IODataStructures/QBallImages/mitkQBallImageSource.cpp IODataStructures/QBallImages/mitkQBallImage.cpp # DataStructures -> Tensor IODataStructures/TensorImages/mitkTensorImage.cpp Rendering/vtkMaskedProgrammableGlyphFilter.cpp Rendering/mitkVectorImageVtkGlyphMapper3D.cpp Rendering/vtkOdfSource.cxx Rendering/vtkThickPlane.cxx Rendering/mitkOdfNormalizationMethodProperty.cpp Rendering/mitkOdfScaleByProperty.cpp # Algorithms Algorithms/mitkPartialVolumeAnalysisHistogramCalculator.cpp Algorithms/mitkPartialVolumeAnalysisClusteringCalculator.cpp Algorithms/itkDwiGradientLengthCorrectionFilter.cpp # Registration Algorithms & Co. Algorithms/Registration/mitkRegistrationWrapper.cpp Algorithms/Registration/mitkPyramidImageRegistrationMethod.cpp # Algorithms/Registration/mitkRegistrationMethodITK4.cpp Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.cpp # MultishellProcessing Algorithms/Reconstruction/MultishellProcessing/itkADCAverageFunctor.cpp Algorithms/Reconstruction/MultishellProcessing/itkADCFitFunctor.cpp Algorithms/Reconstruction/MultishellProcessing/itkKurtosisFitFunctor.cpp Algorithms/Reconstruction/MultishellProcessing/itkBiExpFitFunctor.cpp # Function Collection mitkDiffusionFunctionCollection.cpp ) set(H_FILES # function Collection include/mitkDiffusionFunctionCollection.h # Rendering include/Rendering/mitkOdfVtkMapper2D.h # Reconstruction include/Algorithms/Reconstruction/itkDiffusionQballReconstructionImageFilter.h include/Algorithms/Reconstruction/mitkTeemDiffusionTensor3DReconstructionImageFilter.h include/Algorithms/Reconstruction/itkAnalyticalDiffusionQballReconstructionImageFilter.h include/Algorithms/Reconstruction/itkDiffusionMultiShellQballReconstructionImageFilter.h include/Algorithms/Reconstruction/itkPointShell.h include/Algorithms/Reconstruction/itkOrientationDistributionFunction.h include/Algorithms/Reconstruction/itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h + include/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.h # MultishellProcessing include/Algorithms/Reconstruction/MultishellProcessing/itkRadialMultishellToSingleshellImageFilter.h include/Algorithms/Reconstruction/MultishellProcessing/itkDWIVoxelFunctor.h include/Algorithms/Reconstruction/MultishellProcessing/itkADCAverageFunctor.h include/Algorithms/Reconstruction/MultishellProcessing/itkKurtosisFitFunctor.h include/Algorithms/Reconstruction/MultishellProcessing/itkBiExpFitFunctor.h include/Algorithms/Reconstruction/MultishellProcessing/itkADCFitFunctor.h # Properties include/IODataStructures/Properties/mitkBValueMapProperty.h include/IODataStructures/Properties/mitkGradientDirectionsProperty.h include/IODataStructures/Properties/mitkMeasurementFrameProperty.h include/IODataStructures/Properties/mitkDiffusionPropertyHelper.h include/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageTransformedCreationFilter.h # Algorithms include/Algorithms/itkDiffusionQballGeneralizedFaImageFilter.h include/Algorithms/itkDiffusionQballPrepareVisualizationImageFilter.h include/Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.h include/Algorithms/itkTensorDerivedMeasurementsFilter.h include/Algorithms/itkBrainMaskExtractionImageFilter.h include/Algorithms/itkB0ImageExtractionImageFilter.h include/Algorithms/itkB0ImageExtractionToSeparateImageFilter.h include/Algorithms/itkTensorImageToDiffusionImageFilter.h include/Algorithms/itkTensorToL2NormImageFilter.h include/Algorithms/itkGaussianInterpolateImageFunction.h include/Algorithms/mitkPartialVolumeAnalysisHistogramCalculator.h include/Algorithms/mitkPartialVolumeAnalysisClusteringCalculator.h include/Algorithms/itkDiffusionTensorPrincipalDirectionImageFilter.h include/Algorithms/itkCartesianToPolarVectorImageFilter.h include/Algorithms/itkPolarToCartesianVectorImageFilter.h include/Algorithms/itkDistanceMapFilter.h include/Algorithms/itkProjectionFilter.h include/Algorithms/itkResidualImageFilter.h include/Algorithms/itkExtractChannelFromRgbaImageFilter.h include/Algorithms/itkTensorReconstructionWithEigenvalueCorrectionFilter.h include/Algorithms/itkMergeDiffusionImagesFilter.h include/Algorithms/itkDwiPhantomGenerationFilter.h include/Algorithms/itkFiniteDiffOdfMaximaExtractionFilter.h include/Algorithms/itkMrtrixPeakImageConverter.h include/Algorithms/itkFslPeakImageConverter.h include/Algorithms/itkShCoefficientImageImporter.h include/Algorithms/itkShCoefficientImageExporter.h include/Algorithms/itkOdfMaximaExtractionFilter.h include/Algorithms/itkResampleDwiImageFilter.h include/Algorithms/itkDwiGradientLengthCorrectionFilter.h include/Algorithms/itkAdcImageFilter.h include/Algorithms/itkDwiNormilzationFilter.h include/Algorithms/itkSplitDWImageFilter.h include/Algorithms/itkRemoveDwiChannelFilter.h include/Algorithms/itkExtractDwiChannelFilter.h include/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.h include/Algorithms/itkNonLocalMeansDenoisingFilter.h include/Algorithms/itkVectorImageToImageFilter.h ) set( TOOL_FILES ) diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx new file mode 100644 index 0000000000..24ce4e6e6c --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.cxx @@ -0,0 +1,486 @@ +/*=================================================================== + +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 DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_CXX +#define DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_CXX + +#include "itkDiffusionKurtosisReconstructionImageFilter.h" + +#include +#include +#include +#include + +#include +#include +#include + +template< class TInputPixelType> +static void FitSingleVoxel( const itk::VariableLengthVector< TInputPixelType > &input, + const vnl_vector& bvalues, + vnl_vector& result, + itk::KurtosisFitConfiguration kf_config) +{ + // check for length + assert( input.Size() == bvalues.size() ); + + // assembly data vectors for fitting + auto bvalueIter = bvalues.begin(); + unsigned int unused_values = 0; + while( bvalueIter != bvalues.end() ) + { + if( *bvalueIter < vnl_math::eps && kf_config.omit_bzero ) + { + ++unused_values; + } + ++bvalueIter; + } + + // initialize data vectors with the estimated size (after filtering) + vnl_vector fit_measurements( input.Size() - unused_values, 0 ); + vnl_vector fit_bvalues( input.Size() - unused_values, 0 ); + + bvalueIter = bvalues.begin(); + unsigned int running_index = 0; + unsigned int skip_count = 0; + while( bvalueIter != bvalues.end() ) + { + // skip b=0 if the corresponding flag is set + if( ( kf_config.omit_bzero && *bvalueIter < vnl_math::eps ) + // skip bvalues higher than the limit provided, if the flag is activated + || ( kf_config.exclude_high_b && *bvalueIter > kf_config.b_upper_threshold ) ) + { + ++skip_count; + } + else + { + fit_measurements[ running_index - skip_count ] = input.GetElement(running_index); + fit_bvalues[ running_index - skip_count] = *bvalueIter; + } + + ++running_index; + ++bvalueIter; + } + + + MITK_DEBUG("KurtosisFilter.FitSingleVoxel.Meas") << fit_measurements; + MITK_DEBUG("KurtosisFilter.FitSingleVoxel.Bval") << fit_bvalues; + + // perform fit on data vectors + if( kf_config.omit_bzero ) + { + itk::kurtosis_fit_omit_unweighted kurtosis_cost_fn( fit_measurements.size() ); + // configuration + kurtosis_cost_fn.set_fit_logscale( static_cast(kf_config.fit_scale) ); + kurtosis_cost_fn.initialize( fit_measurements, fit_bvalues ); + + if( kf_config.use_K_limits) + { + kurtosis_cost_fn.set_K_bounds( kf_config.K_limits ); + } + + vnl_levenberg_marquardt nonlinear_fit( kurtosis_cost_fn ); + nonlinear_fit.minimize( result ); + } + else + { + itk::kurtosis_fit_lsq_function kurtosis_cost_fn( fit_measurements.size() ); + // configuration + kurtosis_cost_fn.set_fit_logscale( static_cast(kf_config.fit_scale) ); + kurtosis_cost_fn.initialize( fit_measurements, fit_bvalues ); + + if( kf_config.use_K_limits) + { + kurtosis_cost_fn.set_K_bounds( kf_config.K_limits ); + } + + + vnl_levenberg_marquardt nonlinear_fit( kurtosis_cost_fn ); + nonlinear_fit.minimize(result); + } + + MITK_DEBUG("KurtosisFilter.FitSingleVoxel.Rslt") << result; +} + + + +template< class TInputPixelType, class TOutputPixelType> +itk::DiffusionKurtosisReconstructionImageFilter +::DiffusionKurtosisReconstructionImageFilter() + : m_ReferenceBValue(-1), + m_OmitBZero(false), + m_MaskImage(nullptr), + m_ApplyPriorSmoothing(false), + m_SmoothingSigma(1.5), + m_MaxFitBValue( 3000 ), + m_UseKBounds( false ), + m_ScaleForFitting( STRAIGHT ) +{ + this->m_InitialPosition = vnl_vector(3, 0); + this->m_InitialPosition[2] = 1000.0; // S_0 + this->m_InitialPosition[0] = 0.001; // D + this->m_InitialPosition[1] = 1; // K + + this->m_KurtosisBounds.fill(0); + + // single input image + this->SetNumberOfRequiredInputs(1); + + // two output images (D, K) + this->SetNumberOfRequiredOutputs(2); + typename OutputImageType::Pointer outputPtr1 = OutputImageType::New(); + typename OutputImageType::Pointer outputPtr2 = OutputImageType::New(); + + this->SetNthOutput(0, outputPtr1.GetPointer() ); + this->SetNthOutput(1, outputPtr2.GetPointer() ); + +} + +template< class TInputPixelType, class TOutputPixelType> +void itk::DiffusionKurtosisReconstructionImageFilter +::GenerateOutputInformation() +{ + // first call superclass + Superclass::GenerateOutputInformation(); +} + +template< class TInputPixelType, class TOutputPixelType> +void itk::DiffusionKurtosisReconstructionImageFilter +::SetImageMask(MaskImageType::Pointer mask) +{ + this->m_MaskImage = mask; +} + +template< class TInputPixelType, class TOutputPixelType> +void itk::DiffusionKurtosisReconstructionImageFilter +::BeforeThreadedGenerateData() +{ + // if we have a region set, convert it to a mask image, which is to be used as default for telling + // we need to set the image anyway, so by default the mask is overall 1 + if( m_MaskImage.IsNull() ) + { + m_MaskImage = MaskImageType::New(); + m_MaskImage->SetRegions( this->GetInput()->GetLargestPossibleRegion() ); + m_MaskImage->CopyInformation( this->GetInput() ); + m_MaskImage->Allocate(); + + if( this->m_MapOutputRegion.GetNumberOfPixels() > 0 ) + { + + m_MaskImage->FillBuffer(0); + + typedef itk::ImageRegionIteratorWithIndex< MaskImageType > MaskIteratorType; + MaskIteratorType maskIter( this->m_MaskImage, this->m_MapOutputRegion ); + maskIter.GoToBegin(); + + while( !maskIter.IsAtEnd() ) + { + maskIter.Set( 1 ); + ++maskIter; + } + + } + else + { + m_MaskImage->FillBuffer(1); + } + + + } + + + // apply smoothing to the input image + if( this->m_ApplyPriorSmoothing ) + { + // filter typedefs + typedef itk::DiscreteGaussianImageFilter< itk::Image, itk::Image > GaussianFilterType; + typedef itk::VectorIndexSelectionCastImageFilter< InputImageType, itk::Image > IndexSelectionType; + typedef itk::ComposeImageFilter< itk::Image, InputImageType > ComposeFilterType; + + + auto vectorImage = this->GetInput(); + typename IndexSelectionType::Pointer indexSelectionFilter = IndexSelectionType::New(); + indexSelectionFilter->SetInput( vectorImage ); + + typename ComposeFilterType::Pointer vec_composer = ComposeFilterType::New(); + + for( unsigned int i=0; iGetVectorLength(); ++i) + { + typename GaussianFilterType::Pointer gaussian_filter = GaussianFilterType::New(); + + indexSelectionFilter->SetIndex( i ); + + gaussian_filter->SetInput( indexSelectionFilter->GetOutput() ); + gaussian_filter->SetVariance( m_SmoothingSigma ); + + vec_composer->SetInput(i, gaussian_filter->GetOutput() ); + + gaussian_filter->Update(); + } + + try + { + vec_composer->Update(); + } + catch(const itk::ExceptionObject &e) + { + mitkThrow() << "[VectorImage.GaussianSmoothing] !! Failed with ITK Exception: " << e.what(); + } + + this->m_ProcessedInputImage = vec_composer->GetOutput(); + } + else + { + this->m_ProcessedInputImage = const_cast( this->GetInput() ); + } +} + +template< class TInputPixelType, class TOutputPixelType> +void itk::DiffusionKurtosisReconstructionImageFilter +::AfterThreadedGenerateData() +{ + /* // initialize buffer to zero overall, but don't forget the requested region pointer + for( unsigned int i=0; iGetNumberOfOutputs(); ++i) + { + typename OutputImageType::Pointer output = this->GetOutput(i); + + // after generating, set the buffered region to max, we have taken care about filling it with valid data in + // UpdateOutputInformation, if not set, a writer (or any filter using the LargestPossibleRegion() during update may + // complain about not getting the requested region + output->SetBufferedRegion( output->GetLargestPossibleRegion() ); + + std::cout << "[DiffusionKurtosisReconstructionImageFilter.After]" << output->GetLargestPossibleRegion() << std::endl; + }*/ + +} + +template< class TInputPixelType, class TOutputPixelType> +typename itk::DiffusionKurtosisReconstructionImageFilter::KurtosisSnapshot +itk::DiffusionKurtosisReconstructionImageFilter +::GetSnapshot(const itk::VariableLengthVector &input, GradientDirectionContainerType::Pointer gradients, float bvalue, KurtosisFitConfiguration kf_conf) +{ + // initialize bvalues from reference value and the gradients provided on input + this->SetReferenceBValue(bvalue); + this->SetGradientDirections( gradients ); + + // call the other method + return this->GetSnapshot( input, this->m_BValues, kf_conf ); +} + + +template< class TInputPixelType, class TOutputPixelType> +typename itk::DiffusionKurtosisReconstructionImageFilter::KurtosisSnapshot +itk::DiffusionKurtosisReconstructionImageFilter +::GetSnapshot(const itk::VariableLengthVector &input, vnl_vector bvalues, KurtosisFitConfiguration kf_conf) +{ + // initialize + vnl_vector initial_position; + bool omit_bzero = kf_conf.omit_bzero; + + if( !omit_bzero ) + { + initial_position.set_size(2); + initial_position[0] = this->m_InitialPosition[0]; + initial_position[1] = this->m_InitialPosition[1]; + } + else + { + initial_position.set_size(3); + initial_position = this->m_InitialPosition; + } + + // fit + FitSingleVoxel( input, bvalues, initial_position, kf_conf ); + + // assembly result snapshot + KurtosisSnapshot result; + result.m_D = initial_position[0]; + result.m_K = initial_position[1]; + + if( omit_bzero ) + { + result.m_f = 1 - initial_position[2] / std::fmax(0.01, input.GetElement(0)); + result.m_BzeroFit = initial_position[2]; + } + else + result.m_f = 1; + + // assembly data vectors for fitting + auto bvalueIter = bvalues.begin(); + unsigned int unused_values = 0; + while( bvalueIter != bvalues.end() ) + { + if( *bvalueIter < vnl_math::eps && omit_bzero ) + { + ++unused_values; + } + ++bvalueIter; + } + + // initialize data vectors with the estimated size (after filtering) + vnl_vector fit_measurements( input.Size() - unused_values, 0 ); + vnl_vector fit_bvalues( input.Size() - unused_values, 0 ); + + // original data + vnl_vector orig_measurements( input.Size(), 0 ); + + bvalueIter = bvalues.begin(); + unsigned int running_index = 0; + unsigned int skip_count = 0; + while( bvalueIter != bvalues.end() ) + { + if( *bvalueIter < vnl_math::eps && omit_bzero ) + { + ++skip_count; + } + else + { + fit_measurements[ running_index - skip_count ] = input.GetElement(running_index); + fit_bvalues[ running_index - skip_count ] = *bvalueIter; + } + + orig_measurements[ running_index ] = input.GetElement(running_index); + + ++running_index; + ++bvalueIter; + } + + result.fit_bvalues = fit_bvalues; + result.fit_measurements = fit_measurements; + + result.bvalues = bvalues; + result.measurements = orig_measurements; + + result.m_fittedBZero = omit_bzero; + + return result; +} + +template< class TInputPixelType, class TOutputPixelType> +void itk::DiffusionKurtosisReconstructionImageFilter +::SetGradientDirections(GradientDirectionContainerType::Pointer gradients) +{ + if( this->m_ReferenceBValue < 0) + { + itkExceptionMacro( << "Specify reference b-value prior to setting the gradient directions." ); + } + + if( gradients->Size() == 0 ) + { + itkExceptionMacro( << "Empty gradient directions container retrieved" ); + } + + vnl_vector vnl_bvalues( gradients->Size(), 0 ); + + // initialize the b-values + auto grIter = gradients->Begin(); + unsigned int index = 0; + while( grIter != gradients->End() ) + { + const double twonorm = grIter.Value().two_norm(); + vnl_bvalues( index++ ) = this->m_ReferenceBValue * twonorm * twonorm; + + ++grIter; + } + + this->m_BValues = vnl_bvalues; + + +} + +template< class TInputPixelType, class TOutputPixelType> +void itk::DiffusionKurtosisReconstructionImageFilter +::SetInitialSolution(const vnl_vector& x0 ) +{ + unsigned int param_size = 2 + static_cast( this->m_OmitBZero ); + assert( x0.size() == param_size ); + + this->m_InitialPosition = x0; +} + +template< class TInputPixelType, class TOutputPixelType> +void itk::DiffusionKurtosisReconstructionImageFilter +::ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType /*threadId*/) +{ + typename OutputImageType::Pointer dImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); + itk::ImageRegionIteratorWithIndex< OutputImageType > dImageIt(dImage, outputRegionForThread); + dImageIt.GoToBegin(); + + typename OutputImageType::Pointer kImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(1)); + itk::ImageRegionIteratorWithIndex< OutputImageType > kImageIt(kImage, outputRegionForThread); + kImageIt.GoToBegin(); + + typedef itk::ImageRegionConstIteratorWithIndex< InputImageType > InputIteratorType; + InputIteratorType inputIter( m_ProcessedInputImage, outputRegionForThread ); + inputIter.GoToBegin(); + + typedef itk::ImageRegionConstIteratorWithIndex< MaskImageType > MaskIteratorType; + MaskIteratorType maskIter( this->m_MaskImage, outputRegionForThread ); + maskIter.GoToBegin(); + + KurtosisFitConfiguration fit_config; + fit_config.omit_bzero = this->m_OmitBZero; + fit_config.fit_scale = this->m_ScaleForFitting; + + fit_config.use_K_limits = this->m_UseKBounds; + fit_config.K_limits = this->m_KurtosisBounds; + + vnl_vector initial_position; + if( !this->m_OmitBZero ) + { + initial_position.set_size(2); + initial_position[0] = this->m_InitialPosition[0]; + initial_position[1] = this->m_InitialPosition[1]; + + } + else + { + initial_position.set_size(3); + initial_position = this->m_InitialPosition; + } + + while( !inputIter.IsAtEnd() ) + { + // set (reset) each iteration + vnl_vector result = initial_position; + + // fit single voxel (if inside mask ) + if( maskIter.Get() > 0 ) + { + FitSingleVoxel( inputIter.Get(), this->m_BValues, result, fit_config ); + } + else + { + result.fill(0); + } + + // regardless the fit type, the parameters are always in the first two position + // of the results vector + dImageIt.Set( result[0] ); + kImageIt.Set( result[1] ); + + //std::cout << "[Kurtosis.Fit]" << inputIter.GetIndex() << " --> " << dImageIt.GetIndex() << " result: " << result << std::endl; + + ++maskIter; + ++inputIter; + ++dImageIt; + ++kImageIt; + } + +} + +#endif // guards diff --git a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.h b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.h new file mode 100644 index 0000000000..0c6935de3d --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkDiffusionKurtosisReconstructionImageFilter.h @@ -0,0 +1,438 @@ +/*=================================================================== + +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 DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_H +#define DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_H + +#include "itkImageToImageFilter.h" +#include "itkVectorImage.h" + +#include "mitkDiffusionPropertyHelper.h" + +// vnl includes +#include +#include + +namespace itk +{ + + // Fitting routines + + /** @struct Kurtosis_fit_lsq_function + @brief A base least-squares function for the diffusion kurtosis fit (non-IVIM) + + The basic function fits the signal to S_0 = S * exp [ -b * D + -b^2 * D^2 * K^2 ] + */ + struct kurtosis_fit_lsq_function : + public vnl_least_squares_function + { + public: + /** full lsq_function constructor */ + kurtosis_fit_lsq_function( unsigned int num_params, unsigned int num_measurements, UseGradient g=no_gradient) + : vnl_least_squares_function( num_params, num_measurements, g), + m_use_bounds(false), + m_use_logscale(false), + m_skip_fit(false) + {} + + /** simplified constructor for the 2-parameters fit */ + kurtosis_fit_lsq_function( unsigned int number_measurements) + : kurtosis_fit_lsq_function( 2, number_measurements, no_gradient ) + {} + + + /** Initialize the function by setting measurements and the corresponding b-values */ + void initialize( vnl_vector< double > const& _meas, vnl_vector< double> const& _bvals ) + { + meas = _meas; + if( m_use_logscale ) + { + for( unsigned int i=0; i< meas.size(); ++i) + { + // would produce NaN values, skip the fit + // using the virtual function from the superclass (sets a boolean flag) + if( meas[i] < vnl_math::eps ) + { + m_skip_fit = true; + throw_failure(); + + continue; + } + + meas[i] = log( meas[i] ); + + } + } + + bvalues = _bvals; + } + + + /** use penalty terms on fitting to force the parameters stay within the default bounds */ + void use_bounds() + { + m_use_bounds = true; + + // initialize bounds + double upper_bounds[2] = {4e-3, 4 }; + kurtosis_upper_bounds = vnl_vector(2, 2, upper_bounds); + kurtosis_lower_bounds = vnl_vector(2, 0); + } + + void set_fit_logscale( bool flag ) + { + this->m_use_logscale = flag; + } + + void set_K_bounds( const vnl_vector_fixed k_bounds ) + { + // init + this->use_bounds(); + + // override K bounds + kurtosis_lower_bounds[1] = k_bounds[0]; + kurtosis_upper_bounds[1] = k_bounds[1]; + } + + virtual void f(const vnl_vector &x, vnl_vector &fx) + { + for ( unsigned int s=0; s < fx.size(); s++ ) + { + const double factor = ( meas[s] - M(x, s) ); + fx[s] = factor * factor + penalty_term(x); + } + + MITK_DEBUG("Fit.x_and_f") << x << " | " << fx; + } + + protected: + + /** Formula for diffusion term, use for internal computations */ + double Diff( double x1, double x2, double b) + { + const double quotient = -1. * b * x1 + b*b * x1 * x1 * x2 / 6; + + if( m_use_logscale ) + return quotient; + else + return exp(quotient); + } + + /** The fitting measurement function, has to be reimplemented in the classes */ + virtual double M( vnl_vector const& x, unsigned int idx ) + { + const double bvalue = bvalues[idx]; + + double result = Diff( x[0], x[1], bvalue); + + if( m_use_logscale ) + return meas[0] + result; + else + return meas[0] * result ; + } + + /** Penalty term on D and K during fitting, make sure the vector that is passed in contains (D, K) in this ordering */ + virtual double penalty_term( vnl_vector const& x) + { + double penalty = 0; + + // skip when turned off + if( !m_use_bounds ) + return penalty; + + // we have bounds for D and K only (the first two params ) + for( unsigned int i=0; i< 2; i++) + { + // 5% penalty boundary + // use exponential function to scale the penalty (max when x[i] == bounds ) + double penalty_boundary = 0.02 * (kurtosis_upper_bounds[i] - kurtosis_lower_bounds[i]); + + if( x[i] < kurtosis_lower_bounds[i] + penalty_boundary ) + { + penalty += 1e6 * exp( -1 * ( x[i] - kurtosis_lower_bounds[i]) / penalty_boundary ); + } + else if ( x[i] > kurtosis_upper_bounds[i] - penalty_boundary ) + { + penalty += 1e6 * exp( -1 * ( kurtosis_upper_bounds[i] - x[i]) / penalty_boundary ); + } + } + + MITK_DEBUG("Fit.Orig.Penalty") << x << " || penalty: " << penalty; + + return penalty; + } + + bool m_use_bounds; + + bool m_use_logscale; + + bool m_skip_fit; + + vnl_vector kurtosis_upper_bounds; + vnl_vector kurtosis_lower_bounds; + + vnl_vector meas; + vnl_vector bvalues; + + }; + + /** @struct kurtosis_fit_omit_unweighted + @brief A fitting function handling the unweighted signal b_0 as a fitted parameter */ + struct kurtosis_fit_omit_unweighted + : public kurtosis_fit_lsq_function + { + public: + /** simplified constructor for the 3-parameters fit */ + kurtosis_fit_omit_unweighted( unsigned int number_measurements) + : kurtosis_fit_lsq_function( 3, number_measurements, no_gradient ) + {} + + protected: + virtual double M(const vnl_vector &x, unsigned int idx) override + { + const double bvalue = bvalues[idx]; + + double result = Diff( x[0], x[1], bvalue); + + if( m_use_logscale ) + return log( x[2] ) + result; + else + return x[2] * result ; + } + }; + + enum FitScale + { + STRAIGHT = 0, + LOGARITHMIC + }; + + struct KurtosisFitConfiguration + { + KurtosisFitConfiguration() + : omit_bzero(false),use_K_limits(false),exclude_high_b(false) {} + + bool omit_bzero; + FitScale fit_scale; + + bool use_K_limits; + vnl_vector_fixed K_limits; + + bool exclude_high_b; + double b_upper_threshold; + }; + +/** + @class DiffusionKurtosisReconstructionImageFilter + @brief This filter provides the fit of the kurtosis (non-IVIM) signal to the data + + It has two main modes of operation, either as an image filter to compute the D and K maps, i.e. fitting the values to each voxel or a computation on a single voxel + or a voxel group (with mask) can be triggered by @sa GetSnapshot, GetCurrentSnapshot methods. + */ +template< class TInputPixelType, class TOutputPixelType > +class DiffusionKurtosisReconstructionImageFilter : + public ImageToImageFilter< VectorImage< TInputPixelType, 3>, Image > +{ +public: + + /** + @struct KurtosisSnapshot + + @brief Struct describing a result (and the data) of a Kurtosis model fit + */ + struct KurtosisSnapshot + { + KurtosisSnapshot() + : m_f(1), m_BzeroFit(1), m_D(0.001), m_K(0) {} + + // input data structures + //vnl_vector filtered_measurements; + vnl_vector bvalues; + vnl_vector measurements; + + vnl_vector fit_bvalues; + vnl_vector fit_measurements; + vnl_vector weighted_image_indices; + + bool m_fittedBZero; + + // variables holding the fitted values + double m_f; + double m_BzeroFit; + double m_D; + double m_K; + }; + + //-- class typedefs + typedef DiffusionKurtosisReconstructionImageFilter Self; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + typedef ImageToImageFilter< VectorImage< TInputPixelType, 3>, + Image< TOutputPixelType,3 > > Superclass; + + /** Method for creation through the object factory. */ + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /** Runtime information support. */ + itkTypeMacro(DiffusionKurtosisReconstructionImageFilter, ImageToImageFilter) + + typedef TOutputPixelType OutputPixelType; + typedef TInputPixelType InputPixelType; + + typedef typename Superclass::InputImageType InputImageType; + typedef Image< OutputPixelType, 3 > OutputImageType; + + typedef itk::Image< short , 3> MaskImageType; + + typedef typename Superclass::OutputImageRegionType OutputImageRegionType; + + + /** Holds each magnetic field gradient used to acquire one DWImage */ + typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType + GradientDirectionContainerType; + + // vector image typedefs for regularized fit + typedef itk::VectorImage VectorImageType; + typedef itk::Image, 3> InitialFitImageType; + + //-- input (Set) methods + /** Set the initial solution for fitting, make sure the length and the values correspond to the parameters + * x0 = ( S_0, ADC_0, AKC_0 ) when also the S_0 is estimated + * x0 = ( ADC_0, AKC_0 ) when the S_0 is used in fitting + */ + void SetInitialSolution(const vnl_vector& x0 ); + + /** Set whether the S_0 value is fitted or used in fitting */ + void SetOmitUnweightedValue( bool flag) + { this->m_OmitBZero = flag; } + + /** + Trigger a single computation of the Kurtosis values from the given input vector and the bvalues and returns the result as a KurtosisSnapshot object */ + KurtosisSnapshot GetSnapshot( const itk::VariableLengthVector< TInputPixelType > &input, vnl_vector bvalues, KurtosisFitConfiguration kf_conf); + + /** + Trigger a single computation of the kurtosis values, first the bvalues vector is computed internally but then also stored into the returend snapshot */ + KurtosisSnapshot GetSnapshot( const itk::VariableLengthVector< TInputPixelType > &input, GradientDirectionContainerType::Pointer, float bvalue, KurtosisFitConfiguration kf_conf); + + /** + * Returns the value of the current data presented to the filter. + + If a mask is set, the voxels are first averaged before passed to the fitting procedure + */ + KurtosisSnapshot GetCurrentSnapshot(bool omit_bzero); + + /** Set the reference bvalue of the input DW image */ + void SetReferenceBValue( double bvalue ) + { this->m_ReferenceBValue = bvalue; } + + /** Set the gradient directions */ + void SetGradientDirections( GradientDirectionContainerType::Pointer gradients ); + + /** Restrict map generation to an image region */ + void SetMapOutputRegion( OutputImageRegionType region ) + { + m_MapOutputRegion = region; + this->m_ApplyPriorSmoothing = true; + } + + void SetImageMask( MaskImageType::Pointer mask ); + + /** Set smoothing sigma (default = 1.5 ), automatically enables smoothing prior to fitting */ + void SetSmoothingSigma( double sigma ) + { + this->m_SmoothingSigma = sigma; + this->m_ApplyPriorSmoothing = true; + } + + /** Activate/Deactivate the gaussian smoothing applied to the input prior to fitting ( default = off ) */ + void SetUseSmoothingPriorToFitting( bool flag) + { + this->m_ApplyPriorSmoothing = flag; + } + + /** Set boundaries enforced by penalty terms in the fitting procedure */ + void SetBoundariesForKurtosis( double lower, double upper ) + { + m_UseKBounds = true; + + m_KurtosisBounds[0] = lower; m_KurtosisBounds[1] = upper; + } + + /** Exclude measurements associated with b-values higher than max_bvalue from fitting */ + void SetMaximalBValueUsedForFitting( double max_bvalue ) + { + m_MaxFitBValue = max_bvalue; + } + + /** Select the method used in fitting of the data + + STRAIHT - fit the exponential signal equation S / S_0 = exp [ ... ] + LOGARITHMIC - fit the logarithmic signal equation ln( S / S_0 ) = [] + */ + void SetFittingScale( FitScale scale ) + { + m_ScaleForFitting = scale; + } + +protected: + DiffusionKurtosisReconstructionImageFilter(); + virtual ~DiffusionKurtosisReconstructionImageFilter() {} + + void GenerateOutputInformation() override; + + void AfterThreadedGenerateData() override; + + void BeforeThreadedGenerateData() override; + + void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, ThreadIdType threadId) override; + + double m_ReferenceBValue; + + vnl_vector m_BValues; + + vnl_vector m_InitialPosition; + + bool m_OmitBZero; + + OutputImageRegionType m_MapOutputRegion; + + MaskImageType::Pointer m_MaskImage; + + typename InputImageType::Pointer m_ProcessedInputImage; + + bool m_ApplyPriorSmoothing; + double m_SmoothingSigma; + + bool m_UseKBounds; + vnl_vector_fixed m_KurtosisBounds; + double m_MaxFitBValue; + + FitScale m_ScaleForFitting; + +private: + + +}; + +} //end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkDiffusionKurtosisReconstructionImageFilter.cxx" +#endif + + +#endif // DIFFUSIONKURTOSISRECONSTRUCTIONIMAGEFILTER_H diff --git a/Modules/DiffusionImaging/DiffusionCore/include/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.h b/Modules/DiffusionImaging/DiffusionCore/include/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.h index 0a104c7fe2..289a91c77d 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.h +++ b/Modules/DiffusionImaging/DiffusionCore/include/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.h @@ -1,111 +1,106 @@ /*=================================================================== 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 DIFFUSIONIMAGECREATIONFILTER_H #define DIFFUSIONIMAGECREATIONFILTER_H #include "mitkImageToImageFilter.h" #include "mitkDiffusionPropertyHelper.h" #include namespace mitk { /** * @brief The DiffusionImageHeaderDescriptor struct bundles the necessary diffusion-weighted image header meta information. */ struct MITKDIFFUSIONCORE_EXPORT DiffusionImageHeaderDescriptor { DiffusionImageHeaderDescriptor() : m_GradientDirections(nullptr) { m_BValue = -1; } float m_BValue; mitk::DiffusionPropertyHelper::BValueMapType m_BValueMapType; mitk::DiffusionPropertyHelper::MeasurementFrameType m_MeasurementFrame; mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer m_GradientDirections; }; /** * @brief The DiffusionImageCreationFilter class creates a diffusion-weighted image out of a * given 3D+t regular image and sufficient additional information about gradient directions and b values * * For easier use, the filter supports the usage of reference images. Here a diffusion-weighted (dw) image is expected and the meta * information of this image will be used for the output dw image. The diffusion information can also be specified by setting the HeaderDescriptor * directly (SetHeaderDescriptor). * * At least one of reference image or descriptor must be used, otherwise an exception is thrown. */ class MITKDIFFUSIONCORE_EXPORT DiffusionImageCreationFilter : public ImageToImageFilter { public: /** class macros */ mitkClassMacro( DiffusionImageCreationFilter, ImageToImageFilter ) itkNewMacro(Self) typedef short DiffusionPixelType; typedef mitk::DiffusionPropertyHelper DPH; typedef mitk::Image OutputType; typedef mitk::DiffusionPropertyHelper::ImageType VectorImageType; typedef mitk::DiffusionPropertyHelper::GradientDirectionType GradientDirectionType; typedef mitk::DiffusionPropertyHelper::MeasurementFrameType MeasurementFrameType; typedef mitk::DiffusionPropertyHelper::GradientDirectionsContainerType GradientDirectionContainerType; /** * @brief SetReferenceImage Set a diffusion image as reference, i.e. the header information will be extracted from it * @param reference_image A reference diffusion-weigted image - will throw exception of the input is not DW image */ void SetReferenceImage( mitk::Image::Pointer reference_image ); /** * @brief SetHeaderDescriptor set the information to be used with the dw image * @param header_descriptor * * \sa DiffusionImageHeaderDescriptor */ void SetHeaderDescriptor( DiffusionImageHeaderDescriptor header_descriptor ); virtual void GenerateData() override; - - virtual void GenerateOutputInformation() override; - protected: DiffusionImageCreationFilter(); ~DiffusionImageCreationFilter(); GradientDirectionContainerType::Pointer InternalGetGradientDirections( ); MeasurementFrameType InternalGetMeasurementFrame(); float InternalGetBValue(); - mitk::Image::Pointer RemapIntoVectorImage( mitk::Image::Pointer input); + VectorImageType::Pointer RemapIntoVectorImage( mitk::Image::Pointer input); mitk::Image::Pointer m_ReferenceImage; - mitk::Image::Pointer m_OutputCache; - DiffusionImageHeaderDescriptor m_HeaderDescriptor; bool m_HeaderDescriptorSet; }; } //end namespace mitk #endif // DIFFUSIONIMAGECREATIONFILTER_H diff --git a/Modules/DiffusionImaging/DiffusionCore/src/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.cpp b/Modules/DiffusionImaging/DiffusionCore/src/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.cpp index a5154d5ddd..ce2f1160ef 100644 --- a/Modules/DiffusionImaging/DiffusionCore/src/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/src/IODataStructures/DiffusionWeightedImages/mitkDiffusionImageCreationFilter.cpp @@ -1,231 +1,221 @@ /*=================================================================== 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 "mitkDiffusionImageCreationFilter.h" #include "mitkProperties.h" #include "mitkImageTimeSelector.h" #include "mitkImageCast.h" #include "mitkImageToItk.h" #include "mitkImageAccessByItk.h" #include "mitkITKImageImport.h" #include "mitkIOUtil.h" #include #include /** * @brief RemapIntoVectorImage Take a 3d+t image and reinterpret it as vector image * @return vectoriamge */ -mitk::Image::Pointer +mitk::DiffusionImageCreationFilter::VectorImageType::Pointer mitk::DiffusionImageCreationFilter::RemapIntoVectorImage( mitk::Image::Pointer input) { typedef itk::Image ImageVolumeType; typedef itk::ComposeImageFilter< ImageVolumeType > ComposeFilterType; ComposeFilterType::Pointer vec_composer = ComposeFilterType::New(); mitk::ImageTimeSelector::Pointer t_selector = mitk::ImageTimeSelector::New(); t_selector->SetInput( input ); for( unsigned int i=0; i< input->GetTimeSteps(); i++) { t_selector->SetTimeNr(i); t_selector->Update(); ImageVolumeType::Pointer singleImageItk; mitk::CastToItkImage( t_selector->GetOutput(), singleImageItk ); vec_composer->SetInput( i, singleImageItk ); } try { vec_composer->Update(); } catch( const itk::ExceptionObject& e) { MITK_ERROR << "Caught exception while updating compose filter: " << e.what(); } mitk::DiffusionImageCreationFilter::VectorImageType::Pointer vector_image = vec_composer->GetOutput(); - m_OutputCache = mitk::Image::New(); - - //mitk::GrabItkImageMemory( vector_image ); - m_OutputCache->InitializeByItk( vector_image.GetPointer() ); - m_OutputCache->SetImportVolume( vector_image->GetBufferPointer(), 0, 0, Image::CopyMemory ); vector_image->GetPixelContainer()->ContainerManageMemoryOff(); - return m_OutputCache; + return vector_image; } mitk::DiffusionImageCreationFilter::DiffusionImageCreationFilter() : m_ReferenceImage( nullptr ) { m_HeaderDescriptorSet = false; this->SetNumberOfRequiredInputs(1); this->SetNumberOfRequiredOutputs(1); } mitk::DiffusionImageCreationFilter::~DiffusionImageCreationFilter() { } -void mitk::DiffusionImageCreationFilter -::GenerateOutputInformation() -{ - mitk::Image::Pointer input = this->GetInput(); - mitk::Image::Pointer output = this->GetOutput(); - - // the filter merges all 3d+t to the components -> we need to adapt the pixel type accordingly - output->Initialize( MakePixelType< mitk::DiffusionPropertyHelper::DiffusionPixelType, 3>( input->GetTimeSteps() ), - *input->GetGeometry(0) ); -} - void mitk::DiffusionImageCreationFilter::SetReferenceImage( mitk::Image::Pointer reference_image ) { if( reference_image.IsNull() ) { mitkThrow() << "Null-pointer image provided as reference. "; } if( ! DPH::IsDiffusionWeightedImage(reference_image) ) { mitkThrow() << "The image provided as reference is not a diffusion-weighted image. Cannot proceed. "; } this->m_ReferenceImage = reference_image; } void mitk::DiffusionImageCreationFilter::GenerateData() { const mitk::Image::Pointer input_image = this->GetInput(0); if( input_image.IsNull() ) { mitkThrow() << "No input specified. Cannot proceed "; } if( !( m_HeaderDescriptorSet ^ m_ReferenceImage.IsNotNull() ) ) { mitkThrow() << "Either a header descriptor or a reference diffusion-weighted image have to be provided. Terminating."; } - mitk::Image::Pointer outputForCache = RemapIntoVectorImage( input_image ); - + mitk::Image::Pointer outputForCache = this->GetOutput(); + if( input_image->GetTimeSteps() > 1 ) + { + mitk::Image::Pointer mitkvectorimage = mitk::GrabItkImageMemory( RemapIntoVectorImage( input_image )); + outputForCache->Initialize( mitkvectorimage ); + } + // no need to remap, we expect to have a vector image directly + else + { + outputForCache->Initialize( input_image ); + } // header information GradientDirectionContainerType::Pointer DiffusionVectors = this->InternalGetGradientDirections( ); MeasurementFrameType MeasurementFrame = this->InternalGetMeasurementFrame(); float BValue = this->InternalGetBValue(); // create BValueMap mitk::BValueMapProperty::BValueMap BValueMap = mitk::BValueMapProperty::CreateBValueMap( DiffusionVectors, BValue ); - m_OutputCache->SetProperty( DPH::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( DiffusionVectors ) ); - m_OutputCache->SetProperty( DPH::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( MeasurementFrame ) ); - m_OutputCache->SetProperty( DPH::BVALUEMAPPROPERTYNAME.c_str(), mitk::BValueMapProperty::New( BValueMap ) ); - m_OutputCache->SetProperty( DPH::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( BValue ) ); - - DPH pHelper( m_OutputCache ); - pHelper.InitializeImage(); + outputForCache->SetProperty( DPH::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( DiffusionVectors ) ); + outputForCache->SetProperty( DPH::MEASUREMENTFRAMEPROPERTYNAME.c_str(), mitk::MeasurementFrameProperty::New( MeasurementFrame ) ); + outputForCache->SetProperty( DPH::BVALUEMAPPROPERTYNAME.c_str(), mitk::BValueMapProperty::New( BValueMap ) ); + outputForCache->SetProperty( DPH::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( BValue ) ); - this->SetPrimaryOutput( m_OutputCache ); + outputForCache->Modified(); } void mitk::DiffusionImageCreationFilter::SetHeaderDescriptor(DiffusionImageHeaderDescriptor header_descriptor) { this->m_HeaderDescriptor = header_descriptor; this->m_HeaderDescriptorSet = true; } mitk::DiffusionImageCreationFilter::MeasurementFrameType mitk::DiffusionImageCreationFilter::InternalGetMeasurementFrame() { MeasurementFrameType MeasurementFrame; if( m_ReferenceImage.IsNotNull() ) { MeasurementFrame = DPH::GetMeasurementFrame( m_ReferenceImage ); } else if ( m_HeaderDescriptorSet ) { MeasurementFrame = m_HeaderDescriptor.m_MeasurementFrame; } else { MeasurementFrame(0,0) = 1; MeasurementFrame(0,1) = 0; MeasurementFrame(0,2) = 0; MeasurementFrame(1,0) = 0; MeasurementFrame(1,1) = 1; MeasurementFrame(1,2) = 0; MeasurementFrame(2,0) = 0; MeasurementFrame(2,1) = 0; MeasurementFrame(2,2) = 1; MITK_WARN << "Created default measurement frame as non provided ( no reference image or header information provided)"; } return MeasurementFrame; } mitk::DiffusionImageCreationFilter::GradientDirectionContainerType::Pointer mitk::DiffusionImageCreationFilter::InternalGetGradientDirections() { GradientDirectionContainerType::Pointer DiffusionVectors = GradientDirectionContainerType::New(); if( this->m_ReferenceImage ) { DiffusionVectors = DPH::GetGradientContainer( this->m_ReferenceImage ); } else if ( m_HeaderDescriptorSet ) { DiffusionVectors = m_HeaderDescriptor.m_GradientDirections; } return DiffusionVectors; } float mitk::DiffusionImageCreationFilter::InternalGetBValue() { float bvalue = -1; if( m_ReferenceImage.IsNotNull() ) { bvalue = DPH::GetReferenceBValue( m_ReferenceImage ); } else if ( m_HeaderDescriptorSet ) { bvalue = m_HeaderDescriptor.m_BValue; } else { MITK_ERROR << "No reference image and no header descriptor provided."; } return bvalue; } diff --git a/Modules/QtWidgetsExt/include/QmitkPlotWidget.h b/Modules/QtWidgetsExt/include/QmitkPlotWidget.h index c5f27ed49e..fe08cbc011 100644 --- a/Modules/QtWidgetsExt/include/QmitkPlotWidget.h +++ b/Modules/QtWidgetsExt/include/QmitkPlotWidget.h @@ -1,285 +1,293 @@ /*=================================================================== 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 _QmitkPlotWidget_H_ #define _QmitkPlotWidget_H_ #include #include "MitkQtWidgetsExtExports.h" #include #include #include #include #include #include "mitkCommon.h" #include #include /** * Provides a convenient interface for plotting curves using qwt. * Designed for qwt version 5.2.1. * Can be used with a QmitkPlotDialog, which provides a "Close" button. * @see QmitkPlotDialog * * To plot data do the following: * 1. Create two QmitkPlotWidget::DataVector Objects and fill them * with corresponding x/y values. DataVectors are simple stl-vectors * of type std::vector. Please note that the xValues * vector and the yValues vector MUST have the same size. * 2. Instantiate the widget for example like that: * QmitkPlotWidget* widget = new QmitkPlotWidget( this, "widget" ); * widget->SetAxisTitle( QwtPlot::xBottom, "My x asis [mm]" ); * widget->SetAxisTitle( QwtPlot::yLeft, "My y axis [mm]" ); * int curveId = widget->InsertCurve( "My sophisticated data" ); * widget->SetCurveData( curveId, xValues, yValues ); * widget->SetCurvePen( curveId, QPen( red ) ); * widget->SetCurveTitle( curveId, "My curve description" ); * widget->Replot(); * 3. You can modify the behavior of the plot by directly referencing * the QwtPlot instance using the method GetPlot(). * @see QwtPlot */ class MITKQTWIDGETSEXT_EXPORT QmitkPlotWidget: public QWidget { private: Q_OBJECT public: /** * represents the data type used for scalar values stored * in data arrays. This type is provided by qwt and may not * be changed. */ typedef double ScalarType; /** * This type may be used to store a set of scalar values * representing either x or y coordinates of the data * points that should be rendered. */ typedef std::vector DataVector; /** * convenience type used to store pairs representing x/y coordinates * that should be rendered as a curve by the plot widget */ typedef std::vector< std::pair< double, double > > XYDataVector; /** * Standard qt constructor */ QmitkPlotWidget(QWidget* parent = nullptr,const char* title = nullptr, const char* name = nullptr, Qt::WindowFlags f = nullptr); /** * Virtual destructor */ virtual ~QmitkPlotWidget(); /** * Returns the instance of the plot-widget. This may be used * to modify any detail of the appearance of the plot. */ QwtPlot* GetPlot(); + /** + * Set the title using (formatted) QwtText object + */ + void SetPlotTitle(const QwtText& qwt_title); + + /** + * Set plain text title, using default formatting + */ void SetPlotTitle(const char* title); /** * Inserts a new curve into the plot-window. * @param title the name of the curve * @returns the id of the curve. Use this id to * refer to the curve, if you want to modify or add data. */ unsigned int InsertCurve(const char* title , QColor color = Qt::black); /** * Sets the title of the given axis. For the set of available axes * @see QwtPlot::Axis. * @param axis the axis for which the description should be set. * @param title the name of the axis. */ void SetAxisTitle(int axis, const char* title); /** * Sets the data for a previously added curve. Data is provided as two vectors of double. * The first vector represents the x coordinates, the second vector represents the y coordinates. * @param curveId the id of the curve for which data should be added. * @param xValues the x coordinates of the points that define the curve * @param yValues the y coordinates of the points that define the curve * @returns whether data was added successfully or not */ bool SetCurveData( unsigned int curveId, const DataVector& xValues, const DataVector& yValues ); /** * @brief Sets the data with errors for a previously added curve. * * @param curveId the id of the curve for which data should be added. * @param xValues the x coordinates of the points that define the curve * @param yValues the y coordinates of the points that define the curve * @param yLowerError the magnitude (>0) of the error in the lesser direction of y * @param yUpperError the magnitude (>0) of the error in the larger direction of y * @returns whether data was added successfully or not */ bool SetCurveData(unsigned int curveId, const DataVector& xValues, const DataVector& yValues, const DataVector& yLowerError, const DataVector& yUpperError); /** * @brief Sets the data with errors for a previously added curve. * * @param curveId the id of the curve for which data should be added. * @param xValues the x coordinates of the points that define the curve * @param yValues the y coordinates of the points that define the curve * @param xLowerError the magnitude (>0) of the error in the lesser direction of x * @param xUpperError the magnitude (>0) of the error in the larger direction of x * @param yLowerError the magnitude (>0) of the error in the lesser direction of y * @param yUpperError the magnitude (>0) of the error in the larger direction of y * @returns whether data was added successfully or not */ bool SetCurveData(unsigned int curveId, const DataVector& xValues, const DataVector& yValues, const DataVector& xLowerError, const DataVector& xUpperError, const DataVector& yLowerError, const DataVector& yUpperError); /** * Sets the data for a previously added curve. Data is provided as a vectors of pairs. * The pairs represent x/y coordinates of the points that define the curve. * @param curveId the id of the curve for which data should be added. * @param data the coordinates of the points that define the curve * @returns whether data was added successfully or not */ bool SetCurveData( unsigned int curveId, const XYDataVector& data ); /** * Defines how a curve should be drawn. For drawing a curve, a QPen is used. * @param curveId the id of the curve for which appearance should be changed * @param pen a QPen (@see QPen) defining the line style */ void SetCurvePen( unsigned int curveId, const QPen& pen ); /** * Assign a brush, which defines the fill pattern of shapes drawn by a QPainter. * In case of brush.style() != QBrush::NoBrush and * style() != QwtPlotCurve::Sticks * the area between the curve and the baseline will be filled. * In case !brush.color().isValid() the area will be filled by pen.color(). * The fill algorithm simply connects the first and the last curve point to the * baseline. So the curve data has to be sorted (ascending or descending). * @param curveId the id of the curve for which appearance should be changed * @param brush a QBrush (@see QBrush) defining the line style */ void SetCurveBrush( unsigned int curveId, const QBrush& brush); /** * Sets the style how the line is drawn for the curve; like, plain line, * or with the data points marked with a symbol; * @param: style A QwtPlotCurve::CurveStyle */ void SetCurveStyle( unsigned int curveId, const QwtPlotCurve::CurveStyle style ); /** * Sets the style data points are drawn for the curve; like, a line, * or dots; * @param: symbol A QwtSymbol */ void SetCurveSymbol( unsigned int curveId, QwtSymbol* symbol ); void SetCurveAntialiasingOn( unsigned int curveId); void SetCurveAntialiasingOff( unsigned int curveId); /** * Sets the title of the given curve. The title will be shown in the legend of * the QwtPlot. * @param curveId the id of the curve for which the title should be set * @param title the description of the curve that will be shown in the legend. */ void SetCurveTitle( unsigned int curveId, const char* title ); /** * Defines how a curves errors should be drawn. For drawing a QPen is used. * @param curveId the id of the curve for which error appearance should be changed * @param pen a QPen (@see QPen) defining the line style */ void SetErrorPen(unsigned int curveId, const QPen& pen); /** * Defines the style of errors, symbols or as a curve. * @param curveId the id of the curve for which error appearance should be changed * @param drawSmybols true - draw symbols, false - draw curve */ void SetErrorStyleSymbols(unsigned int curveId, bool drawSmybols); /** * Sets the legend of the plot * */ void SetLegend(QwtLegend* legend, QwtPlot::LegendPosition pos=QwtPlot::RightLegend, double ratio=-1); /** * Set a curve's legend attribute * @param curveId the id of the curve * @param attribute the öegend attribute to be set */ void SetLegendAttribute(unsigned int curveId, const QwtPlotCurve::LegendAttribute &attribute); /** * Triggers a replot of the curve. Replot should be called once after * setting new data. */ void Replot(); /** * Resets the plot into an empty state */ void Clear(); protected: /** * Converts the given values into a raw double* array. * A new array is allocated via new and must be deleted[] by the caller. */ double* ConvertToRawArray( const DataVector& values ); /** * Converts the given values into a raw double* array. * A new array is allocated via new and must be deleted[] by the caller. * @param values the x/y values to convert to an array * @param component defines if the x values (0) or the y values(1) should * be converted. Other values than 0 and 1 will not be accepted. */ double* ConvertToRawArray( const XYDataVector& values, unsigned int component ); /** * Adds an error interval curve. * * All errors should be absolutes. The magnitude will be used. * * @param curveId Which curve should the error curve be added to * @param xValues Vector of x values an error bar belongs to * @param values The original data value * @param lessError Error in the negative direction (value - lessError) * @param moreError Error in the positive direction (value + lessError) * @param isXError Should the error bars be drawn horizontally */ bool AddErrorIntervalCurve(unsigned int curveId, const DataVector& lessError, const DataVector& moreError, bool isXError); QwtPlot* m_Plot; std::vector > m_PlotCurveVector; }; #endif diff --git a/Modules/QtWidgetsExt/src/QmitkPlotWidget.cpp b/Modules/QtWidgetsExt/src/QmitkPlotWidget.cpp index 80fdb60bca..e38e1e31bd 100644 --- a/Modules/QtWidgetsExt/src/QmitkPlotWidget.cpp +++ b/Modules/QtWidgetsExt/src/QmitkPlotWidget.cpp @@ -1,318 +1,324 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include "QmitkPlotWidget.h" QmitkPlotWidget::QmitkPlotWidget(QWidget* parent, const char* title, const char*, Qt::WindowFlags f) : QWidget(parent, f) { auto boxLayout = new QVBoxLayout(this); m_Plot = new QwtPlot( QwtText(title), this ) ; m_Plot->setCanvasBackground(Qt::white); boxLayout->addWidget( m_Plot ); } QmitkPlotWidget::~QmitkPlotWidget() { this->Clear(); delete m_Plot; } QwtPlot* QmitkPlotWidget::GetPlot() { return m_Plot; } void QmitkPlotWidget::SetLegend(QwtLegend* legend, QwtPlot::LegendPosition pos, double ratio) { m_Plot->insertLegend(legend, pos, ratio); } void QmitkPlotWidget::SetLegendAttribute(unsigned int curveId, const QwtPlotCurve::LegendAttribute &attribute) { std::get<0>(m_PlotCurveVector[curveId])->setLegendAttribute(attribute); } unsigned int QmitkPlotWidget::InsertCurve(const char* title, QColor color ) { QwtText qwt_title = QwtText(title); qwt_title.setColor( color ); qwt_title.setPaintAttribute( QwtText::PaintUsingTextColor ); QwtPlotCurve* curve = new QwtPlotCurve( qwt_title ); QwtPlotIntervalCurve* xErrors = new QwtPlotIntervalCurve(); QwtPlotIntervalCurve* yErrors = new QwtPlotIntervalCurve(); auto tuple = std::make_tuple(curve, xErrors, yErrors); m_PlotCurveVector.push_back(tuple); std::get<0>(m_PlotCurveVector.back())->attach(m_Plot); std::get<1>(m_PlotCurveVector.back())->attach(m_Plot); std::get<2>(m_PlotCurveVector.back())->attach(m_Plot); // error curves should not show up on the legend std::get<1>(m_PlotCurveVector.back())->setItemAttribute(QwtPlotItem::Legend, false); std::get<2>(m_PlotCurveVector.back())->setItemAttribute(QwtPlotItem::Legend, false); return static_cast (m_PlotCurveVector.size() - 1); } +void QmitkPlotWidget::SetPlotTitle(const QwtText &qwt_title) +{ + this->m_Plot->setTitle( qwt_title ); +} + void QmitkPlotWidget::SetPlotTitle(const char* title) { - m_Plot->setTitle(title); + QwtText qwt_title_text(title); + this->SetPlotTitle(qwt_title_text); } void QmitkPlotWidget::SetAxisTitle(int axis, const char* title) { m_Plot->setAxisTitle(axis, title); } bool QmitkPlotWidget::SetCurveData( unsigned int curveId, const QmitkPlotWidget::DataVector& xValues, const QmitkPlotWidget::DataVector& yValues ) { if ( xValues.size() != yValues.size() ) { std::cerr << "Sizes of data arrays don't match." << std::endl; return false; } double* rawDataX = ConvertToRawArray( xValues ); double* rawDataY = ConvertToRawArray( yValues ); std::get<0>(m_PlotCurveVector[curveId])->setSamples(new QwtPointArrayData(rawDataX, rawDataY, static_cast(xValues.size()))); delete[] rawDataX; delete[] rawDataY; return true; } bool QmitkPlotWidget::SetCurveData(unsigned int curveId, const DataVector& xValues, const DataVector& yValues, const DataVector& yLowerError, const DataVector& yUpperError) { bool success = true; success = success && this->SetCurveData(curveId, xValues, yValues); success = success && this->AddErrorIntervalCurve(curveId, yLowerError, yUpperError, false); return success; } bool QmitkPlotWidget::SetCurveData(unsigned int curveId, const DataVector& xValues, const DataVector& yValues, const DataVector& xLowerError, const DataVector& xUpperError, const DataVector& yLowerError, const DataVector& yUpperError) { bool success = true; success = success && this->SetCurveData(curveId, xValues, yValues); success = success && this->AddErrorIntervalCurve(curveId, xLowerError, xUpperError, true); success = success && this->AddErrorIntervalCurve(curveId, yLowerError, yUpperError, false); return success; } bool QmitkPlotWidget::SetCurveData(unsigned int curveId, const XYDataVector& data ) { double* rawDataX = ConvertToRawArray( data, 0 ); double* rawDataY = ConvertToRawArray( data, 1 ); std::get<0>(m_PlotCurveVector[curveId])->setData(new QwtPointArrayData(rawDataX, rawDataY, static_cast(data.size()))); delete[] rawDataX; delete[] rawDataY; return true; } void QmitkPlotWidget::SetCurvePen( unsigned int curveId, const QPen& pen ) { std::get<0>(m_PlotCurveVector[curveId])->setPen( pen ); std::get<0>(m_PlotCurveVector[curveId])->setLegendAttribute( QwtPlotCurve::LegendShowLine ); } void QmitkPlotWidget::SetCurveBrush( unsigned int curveId, const QBrush& brush ) { std::get<0>(m_PlotCurveVector[curveId])->setBrush( brush ); std::get<0>(m_PlotCurveVector[curveId])->setLegendAttribute( QwtPlotCurve::LegendShowBrush ); } void QmitkPlotWidget::SetCurveTitle( unsigned int, const char* title ) { m_Plot->setTitle( title ); } void QmitkPlotWidget::SetCurveStyle( unsigned int curveId, const QwtPlotCurve::CurveStyle style ) { std::get<0>(m_PlotCurveVector[curveId])->setStyle(style); } void QmitkPlotWidget::SetCurveSymbol( unsigned int curveId, QwtSymbol* symbol ) { std::get<0>(m_PlotCurveVector[curveId])->setSymbol(symbol); std::get<0>(m_PlotCurveVector[curveId])->setLegendAttribute( QwtPlotCurve::LegendShowSymbol ); } void QmitkPlotWidget::SetCurveAntialiasingOn(unsigned int curveId) { std::get<0>(m_PlotCurveVector[curveId])->setRenderHint( QwtPlotItem::RenderAntialiased ); } void QmitkPlotWidget::SetCurveAntialiasingOff(unsigned int curveId) { std::get<0>(m_PlotCurveVector[curveId])->setRenderHint( QwtPlotItem::RenderAntialiased, false ); } void QmitkPlotWidget::SetErrorPen(unsigned int curveId, const QPen& pen) { std::get<1>(m_PlotCurveVector[curveId])->setPen(pen); QwtIntervalSymbol* errorBar = new QwtIntervalSymbol(QwtIntervalSymbol::Bar); errorBar->setPen(pen); std::get<1>(m_PlotCurveVector[curveId])->setSymbol(errorBar); std::get<2>(m_PlotCurveVector[curveId])->setPen(pen); errorBar = new QwtIntervalSymbol(QwtIntervalSymbol::Bar); errorBar->setPen(pen); std::get<2>(m_PlotCurveVector[curveId])->setSymbol(errorBar); } void QmitkPlotWidget::SetErrorStyleSymbols(unsigned int curveId, bool drawSmybols) { if (drawSmybols) { std::get<1>(m_PlotCurveVector[curveId])->setStyle(QwtPlotIntervalCurve::NoCurve); QwtIntervalSymbol* errorBar = new QwtIntervalSymbol(QwtIntervalSymbol::Bar); errorBar->setPen(std::get<1>(m_PlotCurveVector[curveId])->pen()); std::get<1>(m_PlotCurveVector[curveId])->setSymbol(errorBar); std::get<2>(m_PlotCurveVector[curveId])->setStyle(QwtPlotIntervalCurve::NoCurve); errorBar = new QwtIntervalSymbol(QwtIntervalSymbol::Bar); errorBar->setPen(std::get<2>(m_PlotCurveVector[curveId])->pen()); std::get<2>(m_PlotCurveVector[curveId])->setSymbol(errorBar); } else { std::get<1>(m_PlotCurveVector[curveId])->setStyle(QwtPlotIntervalCurve::Tube); std::get<1>(m_PlotCurveVector[curveId])->setSymbol(nullptr); std::get<2>(m_PlotCurveVector[curveId])->setStyle(QwtPlotIntervalCurve::Tube); std::get<2>(m_PlotCurveVector[curveId])->setSymbol(nullptr); } } void QmitkPlotWidget::Replot() { m_Plot->replot(); } void QmitkPlotWidget::Clear() { m_Plot->detachItems(); m_PlotCurveVector.clear(); m_PlotCurveVector.resize(0); } double* QmitkPlotWidget::ConvertToRawArray( const QmitkPlotWidget::DataVector& values ) { auto raw = new double[ values.size() ]; for( unsigned int i = 0; i < values.size(); ++i ) raw[i] = values[i]; return raw; } double* QmitkPlotWidget::ConvertToRawArray( const QmitkPlotWidget::XYDataVector& values, unsigned int component ) { auto raw = new double[ values.size() ]; for( unsigned int i = 0; i < values.size(); ++i ) { switch (component) { case (0): raw[i] = values[i].first; break; case (1): raw[i] = values[i].second; break; default: std::cout << "Component must be either 0 or 1."<< std::endl; } } return raw; } bool QmitkPlotWidget::AddErrorIntervalCurve(unsigned int curveId, const DataVector& lessError, const DataVector& moreError, bool isXError) { const QwtSeriesData< QPointF >* curveSeriesData = std::get<0>(this->m_PlotCurveVector[curveId])->data(); size_t size = curveSeriesData->size(); if (size != lessError.size() || size != moreError.size() ) { std::cerr << "Sizes of data arrays don't match." << std::endl; return false; } QVector samples; QwtIntervalSample *sample; QwtPlotIntervalCurve* curve; if ( isXError ) { curve = std::get<1>(m_PlotCurveVector[curveId]); } else { curve = std::get<2>(m_PlotCurveVector[curveId]); } for (unsigned int index = 0; index < size; ++index) { qreal xValue = curveSeriesData->sample(index).x(); qreal yValue = curveSeriesData->sample(index).y(); if (isXError) { sample = new QwtIntervalSample(xValue, xValue - lessError[index], xValue + moreError[index]); } else { sample = new QwtIntervalSample(xValue, yValue - lessError[index], yValue + moreError[index]); } samples.push_back(*sample); } curve->setSamples(samples); curve->setStyle(QwtPlotIntervalCurve::NoCurve); QwtIntervalSymbol* errorBar = new QwtIntervalSymbol(QwtIntervalSymbol::Bar); errorBar->setPen(QPen(Qt::black)); curve->setSymbol(errorBar); if (isXError) { curve->setOrientation(Qt::Horizontal); } else { curve->setOrientation(Qt::Vertical); } return true; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake b/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake index 8c931f7e90..54b3afae53 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/files.cmake @@ -1,220 +1,221 @@ set(SRC_CPP_FILES QmitkODFDetailsWidget.cpp QmitkODFRenderWidget.cpp QmitkPartialVolumeAnalysisWidget.cpp QmitkIVIMWidget.cpp + QmitkKurtosisWidget.cpp QmitkTbssRoiAnalysisWidget.cpp QmitkResidualAnalysisWidget.cpp QmitkResidualViewWidget.cpp QmitkTensorModelParametersWidget.cpp QmitkZeppelinModelParametersWidget.cpp QmitkStickModelParametersWidget.cpp QmitkDotModelParametersWidget.cpp QmitkBallModelParametersWidget.cpp QmitkAstrosticksModelParametersWidget.cpp QmitkPrototypeSignalParametersWidget.cpp QmitkMlbstTrainingDataWidget.cpp QmitkFreeSurferParcellationHandler.cpp QmitkFreeSurferParcellationWidget.cpp ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkQBallReconstructionView.cpp QmitkPreprocessingView.cpp QmitkDiffusionDicomImportView.cpp QmitkDiffusionQuantificationView.cpp QmitkTensorReconstructionView.cpp QmitkControlVisualizationPropertiesView.cpp QmitkODFDetailsView.cpp QmitkGibbsTrackingView.cpp QmitkStochasticFiberTrackingView.cpp QmitkStreamlineTrackingView.cpp QmitkFiberQuantificationView.cpp QmitkPartialVolumeAnalysisView.cpp QmitkIVIMView.cpp QmitkTractbasedSpatialStatisticsView.cpp QmitkTbssTableModel.cpp QmitkTbssMetaTableModel.cpp QmitkTbssSkeletonizationView.cpp Connectomics/QmitkConnectomicsDataView.cpp Connectomics/QmitkConnectomicsNetworkOperationsView.cpp Connectomics/QmitkConnectomicsStatisticsView.cpp Connectomics/QmitkNetworkHistogramCanvas.cpp Connectomics/QmitkRandomParcellationView.cpp QmitkOdfMaximaExtractionView.cpp QmitkFiberfoxView.cpp QmitkFiberProcessingView.cpp QmitkFieldmapGeneratorView.cpp QmitkDiffusionRegistrationView.cpp QmitkDenoisingView.cpp QmitkMLBTView.cpp Perspectives/QmitkFiberProcessingPerspective.cpp Perspectives/QmitkDiffusionImagingAppPerspective.cpp Perspectives/QmitkGibbsTractographyPerspective.cpp Perspectives/QmitkStreamlineTractographyPerspective.cpp Perspectives/QmitkProbabilisticTractographyPerspective.cpp Perspectives/QmitkDIAppSyntheticDataGenerationPerspective.cpp Perspectives/QmitkDIAppIVIMPerspective.cpp Perspectives/QmitkDiffusionDefaultPerspective.cpp Perspectives/QmitkMachineLearningTractographyPerspective.cpp ) set(UI_FILES src/internal/QmitkQBallReconstructionViewControls.ui src/internal/QmitkPreprocessingViewControls.ui src/internal/QmitkDiffusionDicomImportViewControls.ui src/internal/QmitkDiffusionQuantificationViewControls.ui src/internal/QmitkTensorReconstructionViewControls.ui src/internal/QmitkControlVisualizationPropertiesViewControls.ui src/internal/QmitkODFDetailsViewControls.ui src/internal/QmitkGibbsTrackingViewControls.ui src/internal/QmitkStochasticFiberTrackingViewControls.ui src/internal/QmitkStreamlineTrackingViewControls.ui src/internal/QmitkFiberQuantificationViewControls.ui # src/internal/QmitkFiberBundleDeveloperViewControls.ui src/internal/QmitkPartialVolumeAnalysisViewControls.ui src/internal/QmitkIVIMViewControls.ui src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui src/internal/QmitkTbssSkeletonizationViewControls.ui src/internal/Connectomics/QmitkConnectomicsDataViewControls.ui src/internal/Connectomics/QmitkConnectomicsNetworkOperationsViewControls.ui src/internal/Connectomics/QmitkConnectomicsStatisticsViewControls.ui src/internal/Connectomics/QmitkRandomParcellationViewControls.ui src/internal/QmitkOdfMaximaExtractionViewControls.ui src/internal/QmitkFiberfoxViewControls.ui src/internal/QmitkFiberProcessingViewControls.ui src/QmitkTensorModelParametersWidgetControls.ui src/QmitkZeppelinModelParametersWidgetControls.ui src/QmitkStickModelParametersWidgetControls.ui src/QmitkDotModelParametersWidgetControls.ui src/QmitkBallModelParametersWidgetControls.ui src/QmitkAstrosticksModelParametersWidgetControls.ui src/QmitkPrototypeSignalParametersWidgetControls.ui src/internal/QmitkFieldmapGeneratorViewControls.ui src/internal/QmitkDiffusionRegistrationViewControls.ui src/internal/QmitkDenoisingViewControls.ui src/internal/QmitkMLBTViewControls.ui src/QmitkFreeSurferParcellationWidgetControls.ui src/QmitkMlbstTrainingDataWidgetControls.ui ) set(MOC_H_FILES src/internal/mitkPluginActivator.h src/internal/QmitkQBallReconstructionView.h src/internal/QmitkPreprocessingView.h src/internal/QmitkDiffusionDicomImportView.h src/internal/QmitkDiffusionQuantificationView.h src/internal/QmitkTensorReconstructionView.h src/internal/QmitkControlVisualizationPropertiesView.h src/internal/QmitkODFDetailsView.h src/QmitkODFRenderWidget.h src/QmitkODFDetailsWidget.h src/internal/QmitkGibbsTrackingView.h src/internal/QmitkStochasticFiberTrackingView.h src/internal/QmitkStreamlineTrackingView.h src/internal/QmitkFiberQuantificationView.h # src/internal/QmitkFiberBundleDeveloperView.h src/internal/QmitkPartialVolumeAnalysisView.h src/QmitkPartialVolumeAnalysisWidget.h src/internal/QmitkIVIMView.h src/internal/QmitkTractbasedSpatialStatisticsView.h src/internal/QmitkTbssSkeletonizationView.h src/QmitkTbssRoiAnalysisWidget.h src/QmitkResidualAnalysisWidget.h src/QmitkResidualViewWidget.h src/internal/Connectomics/QmitkConnectomicsDataView.h src/internal/Connectomics/QmitkConnectomicsNetworkOperationsView.h src/internal/Connectomics/QmitkConnectomicsStatisticsView.h src/internal/Connectomics/QmitkNetworkHistogramCanvas.h src/internal/Connectomics/QmitkRandomParcellationView.h src/internal/QmitkOdfMaximaExtractionView.h src/internal/QmitkFiberfoxView.h src/internal/QmitkFiberProcessingView.h src/QmitkTensorModelParametersWidget.h src/QmitkZeppelinModelParametersWidget.h src/QmitkStickModelParametersWidget.h src/QmitkDotModelParametersWidget.h src/QmitkBallModelParametersWidget.h src/QmitkAstrosticksModelParametersWidget.h src/QmitkPrototypeSignalParametersWidget.h src/internal/QmitkFieldmapGeneratorView.h src/internal/QmitkDiffusionRegistrationView.h src/internal/QmitkDenoisingView.h src/internal/QmitkMLBTView.h src/internal/Perspectives/QmitkFiberProcessingPerspective.h src/internal/Perspectives/QmitkDiffusionImagingAppPerspective.h src/internal/Perspectives/QmitkGibbsTractographyPerspective.h src/internal/Perspectives/QmitkStreamlineTractographyPerspective.h src/internal/Perspectives/QmitkProbabilisticTractographyPerspective.h src/internal/Perspectives/QmitkDIAppSyntheticDataGenerationPerspective.h src/internal/Perspectives/QmitkDIAppIVIMPerspective.h src/internal/Perspectives/QmitkDiffusionDefaultPerspective.h src/internal/Perspectives/QmitkMachineLearningTractographyPerspective.h src/QmitkFreeSurferParcellationHandler.h src/QmitkFreeSurferParcellationWidget.h src/QmitkMlbstTrainingDataWidget.h ) set(CACHED_RESOURCE_FILES # list of resource files which can be used by the plug-in # system without loading the plug-ins shared library, # for example the icon used in the menu and tabs for the # plug-in views in the workbench plugin.xml resources/preprocessing.png resources/dwiimport.png resources/quantification.png resources/reconodf.png resources/recontensor.png resources/vizControls.png resources/OdfDetails.png resources/GibbsTracking.png resources/FiberBundleOperations.png resources/PartialVolumeAnalysis_24.png resources/IVIM_48.png resources/stochFB.png resources/tbss.png resources/connectomics/QmitkConnectomicsDataViewIcon_48.png resources/connectomics/QmitkConnectomicsNetworkOperationsViewIcon_48.png resources/connectomics/QmitkConnectomicsStatisticsViewIcon_48.png resources/connectomics/QmitkRandomParcellationIcon.png resources/arrow.png resources/qball_peaks.png resources/phantom.png resources/tensor.png resources/qball.png resources/StreamlineTracking.png resources/dwi2.png resources/dwi.png resources/odf.png resources/refresh.xpm resources/diffusionregistration.png resources/denoisingicon.png resources/syntheticdata.png resources/ivim.png resources/tractography.png resources/fiberTracking1.png ) set(QRC_FILES # uncomment the following line if you want to use Qt resources resources/QmitkDiffusionImaging.qrc #resources/QmitkTractbasedSpatialStatisticsView.qrc ) 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/src/QmitkKurtosisWidget.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkKurtosisWidget.cpp new file mode 100644 index 0000000000..8c963068a8 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkKurtosisWidget.cpp @@ -0,0 +1,161 @@ +/*=================================================================== + +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 "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::black ) ); + this->SetCurvePen( curveId, QPen( Qt::NoPen ) ); + + QPen pen; + pen.setColor( QColor( Qt::red )); + pen.setWidth(2); + pen.setStyle( Qt::PenStyle::DashLine ); + + // 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]; + + if( snap.m_fittedBZero ) + { + /*auto c_measurements_curve = this->InsertCurve( "Corrected measured values with fitted b=0" ); + this->SetCurveData( c_measurements_curve, toStdVec( snap.fit_bvalues ), toStdVec( snap.fit_measurements / snap.m_BzeroFit ) ); + this->SetCurvePen( c_measurements_curve, QPen(Qt::NoPen) ); + QwtSymbol* whiteDiamond = new QwtSymbol(QwtSymbol::Diamond, QColor(Qt::white), QColor(Qt::black), QSize(8,8)); + this->SetCurveSymbol( c_measurements_curve, whiteDiamond );*/ + + std::vector single_bzero; + single_bzero.push_back(0); + + std::vector fitted_bzero; + fitted_bzero.push_back( snap.m_BzeroFit ); + + auto c_measurements_bzero = this->InsertCurve( "Fitted b=0" ); + this->SetCurveData( c_measurements_bzero, single_bzero, fitted_bzero ); + this->SetCurvePen( c_measurements_bzero, QPen(Qt::NoPen) ); + QwtSymbol* blackDiamond = new QwtSymbol(QwtSymbol::Diamond, QColor(Qt::black), QColor(Qt::black), QSize(8,8)); + this->SetCurveSymbol( c_measurements_bzero, blackDiamond ); + + y_bzero = snap.m_BzeroFit; + + MITK_DEBUG("Kurtosis.Widget.Bzero") << "[Fitted] " << snap.m_BzeroFit << ": [Measured] " << snap.measurements[0]; + } + + + auto measurements_curve = this->InsertCurve( "Measured values" ); + this->SetCurveData( measurements_curve, toStdVec( snap.bvalues ), measured_values ); + this->SetCurvePen( measurements_curve, QPen(Qt::NoPen) ); + QwtSymbol* redDiamond = new QwtSymbol(QwtSymbol::Diamond, QColor(Qt::red), QColor(Qt::red), QSize(8,8)); + this->SetCurveSymbol( measurements_curve, redDiamond ); + + // + // Kurtosis - full modelled signal + // + pen.setColor( QColor( Qt::black )); + pen.setStyle( Qt::SolidLine ); + 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( "Resulting fit of the model" ); + this->SetCurveData( kurtosis_curve, toStdVec( x_K_model ), toStdVec( y_K_model ) ); + this->SetCurvePen( kurtosis_curve, pen ); + this->SetCurveAntialiasingOn( kurtosis_curve ); + + auto d_curve = this->InsertCurve( "D-part of the fitted model" ); + this->SetCurveData( d_curve, toStdVec( x_K_model ), toStdVec( y_D_model ) ); + + pen.setColor( QColor( Qt::red)); + pen.setStyle( Qt::PenStyle::DashLine ); + this->SetCurvePen( d_curve, pen ); + this->SetCurveAntialiasingOn( d_curve ); + + // + // add Legend + // + auto legend = new QwtLegend(); + legend->setMaxColumns(3); + m_Plot->insertLegend( legend, QwtPlot::BottomLegend ); + + 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/src/QmitkPartialVolumeAnalysisWidget.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkPartialVolumeAnalysisWidget.cpp index 34a8e65c56..95e340b4a4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkPartialVolumeAnalysisWidget.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/QmitkPartialVolumeAnalysisWidget.cpp @@ -1,138 +1,144 @@ /*=================================================================== 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 "QmitkPartialVolumeAnalysisWidget.h" #include #include QmitkPartialVolumeAnalysisWidget::QmitkPartialVolumeAnalysisWidget( 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); } } QmitkPartialVolumeAnalysisWidget::~QmitkPartialVolumeAnalysisWidget() { } void QmitkPartialVolumeAnalysisWidget::DrawGauss() { } void QmitkPartialVolumeAnalysisWidget::ClearItemModel() { } void QmitkPartialVolumeAnalysisWidget::SetParameters( ParamsType *params, ResultsType *results, HistType *hist ) { this->Clear(); if(params != nullptr && results != nullptr) { -// hist->Print(); -// params->Print(); -// results->Print(); - - for(unsigned int i=0; iGetXVals()); m_Vals.push_back(hist->GetHVals()); std::vector *xVals = hist->GetXVals(); std::vector *fiberVals = new std::vector(results->GetFiberVals()); std::vector *nonFiberVals = new std::vector(results->GetNonFiberVals()); std::vector *mixedVals = new std::vector(results->GetMixedVals()); std::vector *combiVals = new std::vector(results->GetCombiVals()); double fiberFA = 0.0; double weights = 0.0; for(unsigned int i=0; isize(); ++i) { fiberFA += xVals->at(i) * fiberVals->at(i); weights += fiberVals->at(i); } fiberFA = fiberFA / weights; - QPen pen( Qt::SolidLine ); - pen.setWidth(2); + pen.setWidth(1); + + QwtText plot_title("Compartment Histograms " ); + plot_title.setFont( QFont("Helvetica", 10, QFont::Bold) ); + this->SetPlotTitle( plot_title ); pen.setColor(Qt::black); - int curveId = this->InsertCurve( "histogram" ); + int curveId = this->InsertCurve( "Histogram" ); this->SetCurveData( curveId, (*m_Vals[0]), (*m_Vals[1]) ); this->SetCurvePen( curveId, pen ); + this->SetCurveAntialiasingOn( curveId ); // this->SetCurveTitle( curveId, "Image Histogram" ); + pen.setColor(Qt::blue); + pen.setWidth(2); + curveId = this->InsertCurve( "Combined" ); + this->SetCurveData( curveId, (*hist->GetXVals()), (*combiVals) ); + this->SetCurvePen( curveId, pen ); + m_Vals.push_back(combiVals); + this->SetCurveAntialiasingOn( curveId ); + - curveId = this->InsertCurve( "fiber" ); + curveId = this->InsertCurve( "Tissue class" ); this->SetCurveData(curveId, (*hist->GetXVals()), (*fiberVals)); this->SetCurvePen( curveId, QPen( Qt::NoPen ) ); this->SetCurveBrush(curveId, QBrush(QColor::fromRgbF(1,0,0,.5), Qt::SolidPattern)); m_Vals.push_back(fiberVals); - curveId = this->InsertCurve( "nonfiber" ); + curveId = this->InsertCurve( "Non-tissue class" ); this->SetCurveData( curveId, (*hist->GetXVals()), (*nonFiberVals) ); this->SetCurvePen( curveId, QPen( Qt::NoPen ) ); this->SetCurveBrush(curveId, QBrush(QColor::fromRgbF(0,1,0,.5), Qt::SolidPattern)); m_Vals.push_back(nonFiberVals); - curveId = this->InsertCurve( "mixed" ); + curveId = this->InsertCurve( "Mixed (PV) class" ); this->SetCurveData( curveId, (*hist->GetXVals()), (*mixedVals) ); this->SetCurvePen( curveId, QPen( Qt::NoPen ) ); this->SetCurveBrush(curveId, QBrush(QColor::fromRgbF(.7,.7,.7,.5), Qt::SolidPattern)); m_Vals.push_back(mixedVals); - pen.setColor(Qt::blue); - curveId = this->InsertCurve( "combi" ); - this->SetCurveData( curveId, (*hist->GetXVals()), (*combiVals) ); - this->SetCurvePen( curveId, pen ); - m_Vals.push_back(combiVals); + auto legend = new QwtLegend(); + m_Plot->insertLegend( legend, QwtPlot::TopLegend ); + + this->Replot(); } this->Replot(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkIVIMView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkIVIMView.cpp index 4cc7d3dc4f..0872515184 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkIVIMView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkIVIMView.cpp @@ -1,809 +1,1008 @@ /*=================================================================== 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. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkIVIMView.h" #include "QmitkStdMultiWidget.h" // qt #include "qmessagebox.h" #include "qclipboard.h" // mitk #include "mitkImage.h" #include "mitkImageCast.h" +#include "mitkLookupTable.h" +#include "mitkLookupTableProperty.h" + // itk #include "itkScalarImageToHistogramGenerator.h" #include "itkRegionOfInterestImageFilter.h" #include "itkImageRegionConstIteratorWithIndex.h" // itk/mitk #include "itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h" #include "itkRegularizedIVIMReconstructionFilter.h" #include "mitkImageCast.h" const std::string QmitkIVIMView::VIEW_ID = "org.mitk.views.ivim"; QmitkIVIMView::QmitkIVIMView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) , m_SliceObserverTag1(0), m_SliceObserverTag2(0), m_SliceObserverTag3(0) , m_DiffusionImageNode(NULL) , m_MaskImageNode(NULL) , m_Active(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_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 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() ) ); } 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()); + 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; + } void QmitkIVIMView::Checkbox() { itk::StartEvent dummy; OnSliceChanged(dummy); } void QmitkIVIMView::MethodCombo(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; } itk::StartEvent dummy; OnSliceChanged(dummy); } void QmitkIVIMView::DStarSlider (int val) { QString sval = QString::number(val/1000.0); m_Controls->m_DStarLabel->setText(sval); itk::StartEvent dummy; OnSliceChanged(dummy); } void QmitkIVIMView::BThreshSlider (int val) { QString sval = QString::number(val*5.0); m_Controls->m_BThreshLabel->setText(sval); itk::StartEvent dummy; OnSliceChanged(dummy); } void QmitkIVIMView::S0ThreshSlider (int val) { QString sval = QString::number(val*0.5); m_Controls->m_S0ThreshLabel->setText(sval); itk::StartEvent dummy; OnSliceChanged(dummy); } void QmitkIVIMView::NumItsSlider (int val) { QString sval = QString::number(val); m_Controls->m_NumItsLabel->setText(sval); itk::StartEvent dummy; OnSliceChanged(dummy); } void QmitkIVIMView::LambdaSlider (int val) { QString sval = QString::number(val*.00001); m_Controls->m_LambdaLabel->setText(sval); itk::StartEvent dummy; OnSliceChanged(dummy); } void QmitkIVIMView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; { mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget1->GetSliceNavigationController(); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkIVIMView::OnSliceChanged ); m_SliceObserverTag1 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); } { mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget2->GetSliceNavigationController(); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkIVIMView::OnSliceChanged ); m_SliceObserverTag2 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); } { mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget3->GetSliceNavigationController(); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkIVIMView::OnSliceChanged ); m_SliceObserverTag3 = slicer->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), command ); } } void QmitkIVIMView::StdMultiWidgetNotAvailable() { { mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget1->GetSliceNavigationController(); slicer->RemoveObserver( m_SliceObserverTag1 ); } { mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget2->GetSliceNavigationController(); slicer->RemoveObserver( m_SliceObserverTag2 ); } { mitk::SliceNavigationController* slicer = m_MultiWidget->mitkWidget3->GetSliceNavigationController(); slicer->RemoveObserver( m_SliceObserverTag3 ); } m_MultiWidget = NULL; } void QmitkIVIMView::OnSelectionChanged( std::vector nodes ) { bool foundOneDiffusionImage = false; m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_DiffusionImageLabel->setText("mandatory"); m_Controls->m_MaskImageLabel->setText("optional"); m_MaskImageNode = NULL; m_DiffusionImageNode = NULL; // iterate all selected objects, adjust warning visibility for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(node->GetData())) ); if( isDiffusionImage ) { m_DiffusionImageNode = node; foundOneDiffusionImage = true; m_Controls->m_DiffusionImageLabel->setText(node->GetName().c_str()); } else { bool isBinary = false; node->GetPropertyValue("binary", isBinary); if (isBinary) { m_MaskImageNode = node; m_Controls->m_MaskImageLabel->setText(node->GetName().c_str()); } } } } if (m_DiffusionImageNode.IsNotNull()) { m_Controls->m_VisualizeResultsWidget->setVisible(true); + m_Controls->m_KurtosisVisualizationWidget->setVisible(true); m_Controls->m_InputData->setTitle("Input Data"); + + m_HoldUpdate = false; } else { m_Controls->m_VisualizeResultsWidget->setVisible(false); + m_Controls->m_KurtosisVisualizationWidget->setVisible(false); m_Controls->m_DiffusionImageLabel->setText("mandatory"); } m_Controls->m_ButtonStart->setEnabled( foundOneDiffusionImage ); m_Controls->m_ButtonAutoThres->setEnabled( foundOneDiffusionImage ); m_Controls->m_ControlsFrame->setEnabled( foundOneDiffusionImage ); m_Controls->m_BottomControlsFrame->setEnabled( foundOneDiffusionImage ); itk::StartEvent dummy; OnSliceChanged(dummy); } void QmitkIVIMView::AutoThreshold() { std::vector nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; if (!nodes.front()) { // Nothing selected. Inform the user and return QMessageBox::information( NULL, "Template", "Please load and select a diffusion image before starting image processing."); return; } mitk::Image* dimg = dynamic_cast(nodes.front()->GetData()); if (!dimg) { // Nothing selected. Inform the user and return QMessageBox::information( NULL, "Template", "No valid diffusion image was found."); return; } // find bzero index int index = -1; DirContainerType::Pointer directions = static_cast( dimg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(); 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->GetScalarValueMin() ); histogramGenerator->SetHistogramMax( dimg->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() { - std::vector nodes = this->GetDataManagerSelection(); mitk::Image* img = 0; for ( unsigned int i=0; i(nodes.at(i)->GetData()); bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(nodes.at(i)->GetData())) ); if (img && isDiffusionImage) break; } if (!img) { QMessageBox::information( NULL, "Template", "No valid diffusion image was found."); return; } VecImgType::Pointer vecimg = VecImgType::New(); mitk::CastToItkImage(img, vecimg); OutImgType::IndexType dummy; - FittIVIM(vecimg, static_cast( img->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), static_cast(img->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue(), true, dummy); - OutputToDatastorage(nodes); + if( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) + { + // KURTOSIS + KurtosisFilterType::Pointer filter = KurtosisFilterType::New(); + filter->SetInput(vecimg); + filter->SetReferenceBValue( static_cast(img->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue() ); + filter->SetGradientDirections( static_cast( img->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer() ); + filter->SetSmoothingSigma( this->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() ); + + filter->SetFittingScale( static_cast(this->m_Controls->m_KurtosisFitScale->currentIndex() ) ); + + if( m_MaskImageNode.IsNotNull() ) + { + mitk::Image::Pointer maskImg = dynamic_cast(m_MaskImageNode->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_TRANSPARENT ); + 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 basename(nodes.front()->GetName().c_str()); + QString new_dname = basename; new_dname = new_dname.append("KurtFit_DMap"); + + QString new_kname = basename; new_kname = new_kname.append("KurtFit_KMap"); + + if( this->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 ); + GetDefaultDataStorage()->Add(dnode); + } + + if( this->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 ); + GetDefaultDataStorage()->Add(knode); + } + + } + else + { + FittIVIM(vecimg, + static_cast( img->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), + static_cast(img->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue(), + true, + dummy); + + OutputToDatastorage(nodes); + } +} + +void QmitkIVIMView::OnKurtosisParamsChanged() +{ + itk::StartEvent dummy; + OnSliceChanged(dummy); } void QmitkIVIMView::OnSliceChanged(const itk::EventObject& /*e*/) { if(!m_Visible) return; + if(m_HoldUpdate) + return; + m_Controls->m_Warning->setVisible(false); if(!m_Controls || m_DiffusionImageNode.IsNull()) return; m_Controls->m_VisualizeResultsWidget->setVisible(false); + m_Controls->m_KurtosisVisualizationWidget->setVisible(false); mitk::Image::Pointer diffusionImg = dynamic_cast(m_DiffusionImageNode->GetData()); mitk::Image::Pointer maskImg = NULL; if (m_MaskImageNode.IsNotNull()) maskImg = dynamic_cast(m_MaskImageNode->GetData()); if (!m_MultiWidget) return; 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 = m_MultiWidget->GetCrossPosition(); 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)); - success = FittIVIM(roiImage, static_cast( diffusionImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), static_cast(diffusionImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue(), false, crosspos); + if( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) + { + success = FitKurtosis(roiImage, + static_cast( diffusionImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), + static_cast(diffusionImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue(), + newstart); + } + else + { + success = FittIVIM(roiImage, + static_cast( diffusionImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), + static_cast(diffusionImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue(), + 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); - success = FittIVIM(roiImage, static_cast( diffusionImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), static_cast(diffusionImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue(), false, index); + if( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) + { + success = FitKurtosis(roiImage, + static_cast( diffusionImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), + static_cast(diffusionImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue(), + index); + } + else + { + success = FittIVIM(roiImage, + static_cast( diffusionImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer(), + static_cast(diffusionImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue(), + 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) { - m_Controls->m_VisualizeResultsWidget->setVisible(true); - m_Controls->m_VisualizeResultsWidget->SetParameters(m_Snap); + // 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.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(); + + fit_config.K_limits = k_limits; + + } + fit_config.fit_scale = static_cast(this->m_Controls->m_KurtosisFitScale->currentIndex() ); + + m_KurtosisSnap = filter->GetSnapshot( vecimg->GetPixel( crosspos ), dirs, bval, fit_config ); + + 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_DStarMap = filter->GetOutput(2); m_DMap = filter->GetOutput(1); m_fMap = filter->GetOutput(); } 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(std::vector nodes) { // Outputs to Datastorage QString basename(nodes.front()->GetName().c_str()); 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 = basename; newname2 = newname2.append("_DStarMap_%1").arg(m_Controls->m_MethodCombo->currentText()); mitk::DataNode::Pointer node2=mitk::DataNode::New(); node2->SetData( dstarimage ); node2->SetName(newname2.toLatin1()); GetDefaultDataStorage()->Add(node2); } 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 = basename; newname1 = newname1.append("_DMap_%1").arg(m_Controls->m_MethodCombo->currentText()); mitk::DataNode::Pointer node1=mitk::DataNode::New(); node1->SetData( dimage ); node1->SetName(newname1.toLatin1()); GetDefaultDataStorage()->Add(node1); } 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 = basename; newname0 = newname0.append("_fMap_%1").arg(m_Controls->m_MethodCombo->currentText()); mitk::DataNode::Pointer node=mitk::DataNode::New(); node->SetData( image ); node->SetName(newname0.toLatin1()); GetDefaultDataStorage()->Add(node); } m_MultiWidget->RequestUpdate(); // reset the data node labels, the selection in DataManager is lost after adding // a new node -> we cannot directly proceed twice, the DWI ( and MASK) image have to be selected again m_Controls->m_InputData->setTitle("Please Select Input Data"); m_Controls->m_DiffusionImageLabel->setText("mandatory"); m_Controls->m_MaskImageLabel->setText("optional"); m_MaskImageNode = NULL; m_DiffusionImageNode = NULL; } void QmitkIVIMView::ChooseMethod() { m_Controls->m_MethodCombo->setVisible(m_Controls->m_ChooseMethod->isChecked()); } void QmitkIVIMView::ClipboardCurveButtonClicked() { - if(true) + // 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 ); } - else - { - QApplication::clipboard()->clear(); - } } void QmitkIVIMView::ClipboardStatisticsButtonClicked() { - if ( true ) + // Kurtosis + if ( m_Controls->m_ModelTabSelectionWidget->currentIndex() ) { - 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 ) ; + 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 ) ; QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); } else { - QApplication::clipboard()->clear(); + 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 ) ; + + QApplication::clipboard()->setText( + clipboard, QClipboard::Clipboard ); } } void QmitkIVIMView::Activated() { m_Active = true; } void QmitkIVIMView::Deactivated() { m_Active = false; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkIVIMView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkIVIMView.h index b424caf378..0f147d7c43 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkIVIMView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkIVIMView.h @@ -1,117 +1,127 @@ /*=================================================================== 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 _QMITKIVIMVIEW_H_INCLUDED #define _QMITKIVIMVIEW_H_INCLUDED #include #include #include "ui_QmitkIVIMViewControls.h" #include "itkVectorImage.h" #include "itkImage.h" #include #include "itkDiffusionIntravoxelIncoherentMotionReconstructionImageFilter.h" +#include "itkDiffusionKurtosisReconstructionImageFilter.h" /*! \brief QmitkIVIMView \warning This application module is not yet documented. Use "svn blame/praise/annotate" and ask the author to provide basic documentation. \sa QmitkFunctionality \ingroup Functionalities */ class QmitkIVIMView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; 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; virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) override; virtual void StdMultiWidgetNotAvailable() override; void OnSliceChanged(const itk::EventObject& e); void OutputToDatastorage(std::vector nodes); bool FittIVIM(itk::VectorImage* vecimg, DirContainerType* dirs, float bval, bool multivoxel, OutImgType::IndexType &crosspos); void Activated() override; void Deactivated() override; protected slots: /// \brief Called when the user clicks the GUI button void FittIVIMStart(); void AutoThreshold(); void MethodCombo(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 OnKurtosisParamsChanged(); + protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( std::vector nodes ) override; + bool FitKurtosis( itk::VectorImage *vecimg, DirContainerType *dirs, float bval, OutImgType::IndexType &crosspos); + Ui::QmitkIVIMViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; int m_SliceObserverTag1; int m_SliceObserverTag2; int m_SliceObserverTag3; OutImgType::Pointer m_DStarMap; OutImgType::Pointer m_DMap; OutImgType::Pointer m_fMap; IVIMFilterType::IVIMSnapshot m_Snap; + KurtosisFilterType::KurtosisSnapshot m_KurtosisSnap; mitk::DataNode::Pointer m_DiffusionImageNode; mitk::DataNode::Pointer m_MaskImageNode; bool m_Active; + + bool m_HoldUpdate; + }; #endif // _QMITKIVIMVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkIVIMViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkIVIMViewControls.ui index 2e17470388..9eda318b11 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkIVIMViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkIVIMViewControls.ui @@ -1,819 +1,1172 @@ QmitkIVIMViewControls 0 0 - 360 - 928 + 379 + 1563 0 0 QmitkTemplate - + + 9 + + + 9 + + + 9 + + 9 Intra Voxel Incoherent Motion Estimation 0 9 0 0 Please Select Input Data - - + + - DWI to analyze + Optional ROI image - Raw DWI: + ROI: DWI to analyze <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> - - - - Optional ROI image - - - ROI: - - - Optional ROI image <html><head/><body><p><span style=" color:#969696;">optional</span></p></body></html> - - - - - - - Parameters - - - - 9 - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - 0 - - - - - - 80 - 16777215 - - - - D* - - - - - - - 100 - - - 60 - - - Qt::Horizontal - - - - - - - - 51 - 16777215 - - - - 200 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - 0 - - - - - - 80 - 16777215 - - - - neglect b< - - - - - - - - - - 250 - - - 34 - - - Qt::Horizontal - - - - - - - - 51 - 16777215 - - - - 46.5 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - - 0 - - - 0 - - - - - - 80 - 16777215 - - - - neglect Si< - - - - - - - 100 - - - 0 - - - Qt::Horizontal - - - - - - - - 0 - 0 - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 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 - - - - - - 80 - 16777215 - - - - #iterations - - - - - - - 100 - - - 10 - - - Qt::Horizontal - - - - - - - - 30 - 16777215 - - - - TextLabel - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - QFrame::NoFrame + + + DWI to analyze - - QFrame::Raised + + Raw DWI: - - - 0 - - - 0 - - - - - - 80 - 16777215 - - - - lambda - - - - - - - 1000 - - - 10 - - - Qt::Horizontal - - - - - - - - 0 - 0 - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 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 QFrame::NoFrame QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 QFrame::NoFrame QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 QFrame::NoFrame QFrame::Raised - + 0 - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - + + 0 + + + 0 + + 0 - - - - - 80 - 0 - - - - Output Images - - - - - - - f - - - true - - - - - - - D - - - false - - - - - - - D* - - - false - - - - - - - Generate Output Images - - - warning display Qt::RichText true QFrame::StyledPanel QFrame::Raised 0 - + + 0 + + + 0 + + + 0 + + 0 - - - true - - - - 0 - 0 - - - - - 0 - 400 - + + + 1 - - - 0 + + + + 0 + 0 + - + + IVIM + + + + + + Parameters + + + + 9 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 80 + 16777215 + + + + D* + + + + + + + 100 + + + 60 + + + Qt::Horizontal + + + + + + + + 51 + 16777215 + + + + 200 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 80 + 16777215 + + + + neglect b< + + + + + + + + + + 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 + + + + + + + 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 + + + + + + + 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 + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 80 + 16777215 + + + + neglect Si< + + + + + + + 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 + + + + + + 80 + 0 + + + + Output Images + + + + + + + f + + + true + + + + + + + D + + + false + + + + + + + D* + + + false + + + + + + + + + + true + + + + 0 + 0 + + + + + 0 + 400 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + 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 Measurement + + + + + + + + 80 + 0 + + + + Output Images + + + + + + + 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 + + + 1.000000000000000 + + + 5.000000000000000 + + + 0.100000000000000 + + + + + + + On + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 400 + + + + + + + + + + Generate Output Images + + + QFrame::NoFrame QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 QFrame::NoFrame QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 QFrame::NoFrame QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 Datapoints to Clipboard Parameters to Clipboard - - - - 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 - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 220 - - - - QmitkIVIMWidget QWidget
QmitkIVIMWidget.h
1
+ + QmitkKurtosisWidget + QWidget +
QmitkKurtosisWidget.h
+ 1 +
+ + ctkRangeWidget + QWidget +
ctkRangeWidget.h
+ 1 +