diff --git a/Modules/BasicImageProcessing/CMakeLists.txt b/Modules/BasicImageProcessing/CMakeLists.txt index 2f337313f9..6302c23500 100644 --- a/Modules/BasicImageProcessing/CMakeLists.txt +++ b/Modules/BasicImageProcessing/CMakeLists.txt @@ -1,8 +1,8 @@ MITK_CREATE_MODULE( - DEPENDS MitkCore + DEPENDS MitkCore MitkMatchPointRegistration MitkMatchPointRegistrationIO PACKAGE_DEPENDS - PUBLIC - PRIVATE ITK|ITKIOImageBase+ITKIOGDCM + PUBLIC + PRIVATE ITK|ITKIOImageBase+ITKIOGDCM ) add_subdirectory(MiniApps) diff --git a/Modules/BasicImageProcessing/files.cmake b/Modules/BasicImageProcessing/files.cmake index 562652a41d..e6dc2c3eaf 100644 --- a/Modules/BasicImageProcessing/files.cmake +++ b/Modules/BasicImageProcessing/files.cmake @@ -1,9 +1,11 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkArithmeticOperation.cpp + mitkTransformationOperation.cpp + mitkMaskCleaningOperation.cpp ) set(RESOURCE_FILES ) diff --git a/Modules/BasicImageProcessing/include/mitkMaskCleaningOperation.h b/Modules/BasicImageProcessing/include/mitkMaskCleaningOperation.h new file mode 100644 index 0000000000..caee955184 --- /dev/null +++ b/Modules/BasicImageProcessing/include/mitkMaskCleaningOperation.h @@ -0,0 +1,62 @@ +/*=================================================================== + +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 mitkMaskClearningOperation_h +#define mitkMaskClearningOperation_h + +#include +#include + +namespace mitk +{ + + /** \brief Executes operations to clean-up Masks. + * + * It is assumed that the segmentation is of type + */ + class MITKBASICIMAGEPROCESSING_EXPORT MaskCleaningOperation { + public: + /** \brief Limits a Mask to a given Range + * + * Removes all elements of a mask that are not within the given range. If lowerLimitOn is true, all voxels that + * cover voxels with an intensity below lowerLimit will be set to 0 in the resulting mask. Similar, all voxels + * that cover voxels with an intensity above upperLimit will be set to 0 if upperLimitOn is true. + * + * Parameter + * - mitk::Image::Pointer image : Grey-Scale image + * - mitk::Image::Pointer mask : Original mask + * - optional: bool lowerLimitOn : If true, voxels below lowerLimit are not masked, default false + * - optional: double lowerLimit : Lower Threshold limit, default 0 + * - optional: bool upperLimitOn : If true, voxels above upperLimit are not masked, default false + * - optional: double upperLimit : Lower Threshold limit, default 1 + */ + static Image::Pointer RangeBasedMasking(Image::Pointer & image, Image::Pointer & mask, bool lowerLimitOn=false, double lowerLimit=0, bool upperLimitOn=false, double upperLimit=1); + + /** \brief Removes outlier from a mask + * + * Removes all elements of a mask that are not within the range \f$ [\mu - 3 \sigma , \mu + 3 \sigma\] \f$ + * + * Parameter + * - mitk::Image::Pointer image : Grey-Scale image + * - mitk::Image::Pointer mask : Original mask + */ + static Image::Pointer MaskOutlierFiltering(Image::Pointer & image, Image::Pointer & mask); + + }; + + +} +#endif // mitkMaskClearningOperation_h \ No newline at end of file diff --git a/Modules/BasicImageProcessing/include/mitkTransformationOperation.h b/Modules/BasicImageProcessing/include/mitkTransformationOperation.h new file mode 100644 index 0000000000..ffdf369bde --- /dev/null +++ b/Modules/BasicImageProcessing/include/mitkTransformationOperation.h @@ -0,0 +1,67 @@ +/*=================================================================== + +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 mitkArithmeticOperation_h +#define mitkArithmeticOperation_h + +#include +#include +#include + +namespace mitk +{ + + enum BorderCondition + { + Constant, + Periodic, + ZeroFluxNeumann + }; + + enum WaveletType + { + Held, + Vow, + Simoncelli, + Shannon + }; + + enum GridInterpolationPositionType + { + SameSize, + OriginAligned, + CenterAligned + }; + + /** \brief Executes a transformation operations on one or two images + * + * All parameters of the arithmetic operations must be specified during construction. + * The actual operation is executed when calling GetResult(). + */ + class MITKBASICIMAGEPROCESSING_EXPORT TransformationOperation { + public: + static std::vector MultiResolution(Image::Pointer & image, unsigned int numberOfLevels, bool outputAsDouble = false); + static Image::Pointer LaplacianOfGaussian(Image::Pointer & image, double sigma, bool outputAsDouble = false); + static std::vector WaveletForward(Image::Pointer & image, unsigned int numberOfLevels, unsigned int numberOfBands, BorderCondition condition, WaveletType waveletType); + + static Image::Pointer ResampleImage(Image::Pointer &image, mitk::Vector3D spacing, mitk::ImageMappingInterpolator::Type interpolator, GridInterpolationPositionType position, bool returnAsDouble, bool roundOutput); + static Image::Pointer ResampleMask(Image::Pointer &image, mitk::Vector3D spacing, mitk::ImageMappingInterpolator::Type interpolator, GridInterpolationPositionType position); + + }; + + +} +#endif // mitkArithmeticOperation_h \ No newline at end of file diff --git a/Modules/BasicImageProcessing/src/mitkMaskCleaningOperation.cpp b/Modules/BasicImageProcessing/src/mitkMaskCleaningOperation.cpp new file mode 100644 index 0000000000..ce6d2bb4b2 --- /dev/null +++ b/Modules/BasicImageProcessing/src/mitkMaskCleaningOperation.cpp @@ -0,0 +1,141 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkMaskCleaningOperation.h" + +#include +#include +#include + +#include +#include +#include + +#include "itkCastImageFilter.h" + +namespace mitk +{ + namespace Functor + { + template< class TInput, class TOutput> + class RangeBasedMasking + { + public: + RangeBasedMasking() {}; + ~RangeBasedMasking() {}; + bool operator!=(const RangeBasedMasking &) const + { + return false; + } + bool operator==(const RangeBasedMasking & other) const + { + return !(*this != other); + } + inline TOutput operator()(const TInput & A, const TOutput & B) const + { + unsigned short erg = B; + if (lowerLimitOn && (A < lowerLimit)) + { + erg = 0; + } + if (upperLimitOn && (upperLimit < A)) + { + erg = 0; + } + return erg; + } + + bool lowerLimitOn = false; + bool upperLimitOn = false; + double lowerLimit = 0; + double upperLimit = 1; + }; + } +} + + + +template +static void ExecuteRangeBasedMasking(itk::Image* image, mitk::Image::Pointer & mask, bool lowerLimitOn, double lowerLimit, bool upperLimitOn, double upperLimit, mitk::Image::Pointer & resultImage) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskImageType; + typedef itk::BinaryFunctorImageFilter< ImageType, MaskImageType, MaskImageType, mitk::Functor::RangeBasedMasking > DefaultFilterType; + + typename MaskImageType::Pointer itkMask = MaskImageType::New(); + mitk::CastToItkImage(mask.GetPointer(), itkMask); + + typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); + filter->SetInput1(image); + filter->SetInput2(itkMask); + filter->GetFunctor().lowerLimitOn = lowerLimitOn; + filter->GetFunctor().upperLimitOn = upperLimitOn; + filter->GetFunctor().lowerLimit = lowerLimit; + filter->GetFunctor().upperLimit = upperLimit; + filter->Update(); + + CastToMitkImage(filter->GetOutput(), resultImage); +} + +mitk::Image::Pointer mitk::MaskCleaningOperation::RangeBasedMasking(Image::Pointer & image, Image::Pointer & mask, bool lowerLimitOn, double lowerLimit, bool upperLimitOn, double upperLimit) +{ + Image::Pointer resultImage; + AccessByItk_n(image, ExecuteRangeBasedMasking, (mask, lowerLimitOn, lowerLimit, upperLimitOn, upperLimit, resultImage)); + return resultImage; +} + + +template +static void CalculateMeanAndStd(itk::Image* image, mitk::Image::Pointer & mask, double &mean, double &std) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskImageType; + + typename MaskImageType::Pointer itkMask = MaskImageType::New(); + mitk::CastToItkImage(mask.GetPointer(), itkMask); + + itk::ImageRegionConstIterator image_iter(image, image->GetLargestPossibleRegion()); + itk::ImageRegionConstIterator mask_iter(itkMask, itkMask->GetLargestPossibleRegion()); + + unsigned int number_of_voxels = 0; + while (!image_iter.IsAtEnd()) + { + if (mask_iter.Get() > 0) + { + mean += image_iter.Get(); + std += image_iter.Get() * image_iter.Get(); + ++number_of_voxels; + } + + ++image_iter; + ++mask_iter; + } + mean /= number_of_voxels; + std /= number_of_voxels; + std -= mean; + std = sqrt(std); +} + + +mitk::Image::Pointer mitk::MaskCleaningOperation::MaskOutlierFiltering(Image::Pointer & image, Image::Pointer & mask) +{ + Image::Pointer resultImage; + double mean = 0; + double std = 0; + AccessByItk_n(image, CalculateMeanAndStd, (mask, mean, std)); + return MaskCleaningOperation::RangeBasedMasking(image, mask, true, mean - 3 * std, true, mean + 3 * std); + +} \ No newline at end of file diff --git a/Modules/BasicImageProcessing/src/mitkTransformationOperation.cpp b/Modules/BasicImageProcessing/src/mitkTransformationOperation.cpp new file mode 100644 index 0000000000..1020ad90c7 --- /dev/null +++ b/Modules/BasicImageProcessing/src/mitkTransformationOperation.cpp @@ -0,0 +1,507 @@ +/*=================================================================== + +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 "mitkTransformationOperation.h" + +#include +#include +#include + +#include +#include +#include + +// Wavelet +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "itkZeroFluxNeumannBoundaryCondition.h" +#include "itkPeriodicBoundaryCondition.h" +#include "itkConstantBoundaryCondition.h" +//#include +#include "itkCastImageFilter.h" + +#include "itkUnaryFunctorImageFilter.h" +#include +#include +#include + +namespace mitk +{ + namespace Functor + { + template< class TInput> + class ThresholdValue + { + public: + ThresholdValue() {}; + ~ThresholdValue() {}; + bool operator!=(const ThresholdValue &) const + { + return false; + } + bool operator==(const ThresholdValue & other) const + { + return !(*this != other); + } + inline unsigned short operator()(const TInput & A) const + { + if (A < value) + return 0; + else + return 1; + } + double value = 0.0; + }; + + template< class TInput, class TOutput> + class RoundValue + { + public: + RoundValue() {}; + ~RoundValue() {}; + bool operator!=(const RoundValue &) const + { + return false; + } + bool operator==(const RoundValue & other) const + { + return !(*this != other); + } + inline TOutput operator()(const TInput & A) const + { + return std::round(A); + } + }; + } +} + +template +static void ExecuteMultiResolution(itk::Image* image, unsigned int numberOfLevels, bool outputAsDouble, std::vector &resultImages) +{ + typedef itk::Image ImageType; + typedef itk::Image DoubleOutputType; + typedef itk::RecursiveMultiResolutionPyramidImageFilter ImageTypeFilterType; + typedef itk::RecursiveMultiResolutionPyramidImageFilter DoubleTypeFilterType; + + if (outputAsDouble) + { + typename DoubleTypeFilterType::Pointer recursiveMultiResolutionPyramidImageFilter = DoubleTypeFilterType::New(); + recursiveMultiResolutionPyramidImageFilter->SetInput(image); + recursiveMultiResolutionPyramidImageFilter->SetNumberOfLevels(numberOfLevels); + recursiveMultiResolutionPyramidImageFilter->Update(); + + // This outputs the levels (0 is the lowest resolution) + for (unsigned int i = 0; i < numberOfLevels; ++i) + { + mitk::Image::Pointer outputImage = mitk::Image::New(); + CastToMitkImage(recursiveMultiResolutionPyramidImageFilter->GetOutput(i), outputImage); + resultImages.push_back(outputImage); + } + } + else { + typename ImageTypeFilterType::Pointer recursiveMultiResolutionPyramidImageFilter = ImageTypeFilterType::New(); + recursiveMultiResolutionPyramidImageFilter->SetInput(image); + recursiveMultiResolutionPyramidImageFilter->SetNumberOfLevels(numberOfLevels); + recursiveMultiResolutionPyramidImageFilter->Update(); + + // This outputs the levels (0 is the lowest resolution) + for (unsigned int i = 0; i < numberOfLevels; ++i) + { + mitk::Image::Pointer outputImage = mitk::Image::New(); + CastToMitkImage(recursiveMultiResolutionPyramidImageFilter->GetOutput(i), outputImage); + resultImages.push_back(outputImage); + } + } +} + +std::vector mitk::TransformationOperation::MultiResolution(Image::Pointer & image, unsigned int numberOfLevels, bool outputAsDouble) +{ + std::vector resultImages; + AccessByItk_n(image, ExecuteMultiResolution, (numberOfLevels, outputAsDouble, resultImages)); + return resultImages; +} + + + + +template +static void ExecuteLaplacianOfGaussian(itk::Image* image, double sigma, bool outputAsDouble, mitk::Image::Pointer &resultImage) +{ + typedef itk::Image ImageType; + typedef itk::Image DoubleOutputType; + typedef itk::LaplacianRecursiveGaussianImageFilter ImageTypeFilterType; + typedef itk::LaplacianRecursiveGaussianImageFilter DoubleTypeFilterType; + + if (outputAsDouble) + { + typename DoubleTypeFilterType::Pointer filter = DoubleTypeFilterType::New(); + filter->SetInput(image); + filter->SetSigma(sigma); + filter->Update(); + + CastToMitkImage(filter->GetOutput(), resultImage); + } + else { + typename ImageTypeFilterType::Pointer filter = ImageTypeFilterType::New(); + filter->SetInput(image); + filter->SetSigma(sigma); + filter->Update(); + + CastToMitkImage(filter->GetOutput(), resultImage); + } +} + +mitk::Image::Pointer mitk::TransformationOperation::LaplacianOfGaussian(Image::Pointer & image, double sigma, bool outputAsDouble) +{ + Image::Pointer resultImage; + AccessByItk_n(image, ExecuteLaplacianOfGaussian, (sigma, outputAsDouble, resultImage)); + return resultImage; +} + + + +template +static void ExecuteSpecificWaveletTransformation(itk::Image* image, unsigned int numberOfLevels, unsigned int numberOfBands, mitk::BorderCondition condition, std::vector &resultImages) +{ + const unsigned int Dimension = VImageDimension; + typedef TInputPixel PixelType; + typedef TOutputPixel OutputPixelType; + typedef itk::Image< PixelType, Dimension > ImageType; + typedef itk::Image< double, Dimension > DoubleImageType; + typedef itk::Image< OutputPixelType, Dimension > OutputImageType; + + typedef itk::CastImageFilter< ImageType, DoubleImageType > CastFilterType; + typedef itk::FFTPadPositiveIndexImageFilter< DoubleImageType > FFTPadType; + typedef itk::ForwardFFTImageFilter< DoubleImageType, itk::Image< std::complex, Dimension> > FFTFilterType; + typedef typename FFTFilterType::OutputImageType ComplexImageType; + + typedef TWaveletFunction WaveletFunctionType; + typedef itk::WaveletFrequencyFilterBankGenerator< ComplexImageType, WaveletFunctionType > WaveletFilterBankType; + typedef itk::WaveletFrequencyForward< ComplexImageType, ComplexImageType, WaveletFilterBankType > ForwardWaveletType; + + typedef itk::InverseFFTImageFilter< ComplexImageType, OutputImageType > InverseFFTFilterType; + + // Convert input parameter + unsigned int highSubBands = numberOfBands; //inputBands; + unsigned int levels = numberOfLevels; + + + // Perform FFT on input image + typename CastFilterType::Pointer castFilter = CastFilterType::New(); + castFilter->SetInput(image); + + // Pad Image so it fits the expect + typename FFTPadType::Pointer fftpad = FFTPadType::New(); + fftpad->SetSizeGreatestPrimeFactor(4); + itk::ConstantBoundaryCondition< DoubleImageType > constantBoundaryCondition; + itk::PeriodicBoundaryCondition< DoubleImageType > periodicBoundaryCondition; + itk::ZeroFluxNeumannBoundaryCondition< DoubleImageType > zeroFluxNeumannBoundaryCondition; + switch (condition) + { + case mitk::BorderCondition::Constant: + fftpad->SetBoundaryCondition(&constantBoundaryCondition); + break; + case mitk::BorderCondition::Periodic: + fftpad->SetBoundaryCondition(&periodicBoundaryCondition); + break; + case mitk::BorderCondition::ZeroFluxNeumann: + fftpad->SetBoundaryCondition(&zeroFluxNeumannBoundaryCondition); + break; + default: + break; + } + fftpad->SetInput(castFilter->GetOutput()); + + typename FFTFilterType::Pointer fftFilter = FFTFilterType::New(); + fftFilter->SetInput(fftpad->GetOutput()); + + // Calculate forward transformation + typename ForwardWaveletType::Pointer forwardWavelet = ForwardWaveletType::New(); + + forwardWavelet->SetHighPassSubBands(highSubBands); + forwardWavelet->SetLevels(levels); + forwardWavelet->SetInput(fftFilter->GetOutput()); + forwardWavelet->Update(); + + // Obtain target spacing, size and origin + typename ComplexImageType::SpacingType inputSpacing; + for (unsigned int i = 0; i < Dimension; ++i) + { + inputSpacing[i] = image->GetLargestPossibleRegion().GetSize()[i]; + } + typename ComplexImageType::SpacingType expectedSpacing = inputSpacing; + typename ComplexImageType::PointType inputOrigin = image->GetOrigin(); + typename ComplexImageType::PointType expectedOrigin = inputOrigin; + typename ComplexImageType::SizeType inputSize = fftFilter->GetOutput()->GetLargestPossibleRegion().GetSize(); + typename ComplexImageType::SizeType expectedSize = inputSize; + + // Inverse FFT to obtain filtered images + typename InverseFFTFilterType::Pointer inverseFFT = InverseFFTFilterType::New(); + for (unsigned int level = 0; level < numberOfLevels + 1; ++level) + { + double scaleFactorPerLevel = std::pow(static_cast< double >(forwardWavelet->GetScaleFactor()),static_cast< double >(level)); + for (unsigned int i = 0; i < Dimension; ++i) + { + expectedSize[i] = inputSize[i] / scaleFactorPerLevel; + expectedOrigin[i] = inputOrigin[i]; + expectedSpacing[i] = inputSpacing[i] * scaleFactorPerLevel; + } + for (unsigned int band = 0; band < highSubBands; ++band) + { + unsigned int nOutput = level * forwardWavelet->GetHighPassSubBands() + band; + // Do not compute bands in low-pass level. + if (level == numberOfLevels && band == 0) + { + nOutput = forwardWavelet->GetTotalOutputs() - 1; + } + else if (level == numberOfLevels && band != 0) + { + break; + } + + inverseFFT->SetInput(forwardWavelet->GetOutput(nOutput)); + inverseFFT->Update(); + + auto itkOutputImage = inverseFFT->GetOutput(); + itkOutputImage->SetSpacing(expectedSpacing); + mitk::Image::Pointer outputImage = mitk::Image::New(); + CastToMitkImage(itkOutputImage, outputImage); + resultImages.push_back(outputImage); + } + } +} + +template +static void ExecuteWaveletTransformation(itk::Image* image, unsigned int numberOfLevels, unsigned int numberOfBands, mitk::BorderCondition condition, mitk::WaveletType waveletType, std::vector &resultImages) +{ + typedef itk::Point< double, VImageDimension > PointType; + typedef itk::HeldIsotropicWavelet< double, VImageDimension, PointType > HeldIsotropicWaveletType; + typedef itk::VowIsotropicWavelet< double, VImageDimension, PointType > VowIsotropicWaveletType; + typedef itk::SimoncelliIsotropicWavelet< double, VImageDimension, PointType > SimoncelliIsotropicWaveletType; + typedef itk::ShannonIsotropicWavelet< double, VImageDimension, PointType > ShannonIsotropicWaveletType; + + switch (waveletType) + { + case mitk::WaveletType::Held: + ExecuteSpecificWaveletTransformation(image, numberOfLevels, numberOfBands, condition, resultImages); + break; + case mitk::WaveletType::Shannon: + ExecuteSpecificWaveletTransformation(image, numberOfLevels, numberOfBands, condition, resultImages); + break; + case mitk::WaveletType::Simoncelli: + ExecuteSpecificWaveletTransformation(image, numberOfLevels, numberOfBands, condition, resultImages); + break; + case mitk::WaveletType::Vow: + ExecuteSpecificWaveletTransformation(image, numberOfLevels, numberOfBands, condition, resultImages); + break; + default: + ExecuteSpecificWaveletTransformation(image, numberOfLevels, numberOfBands, condition, resultImages); + break; + } +} + +std::vector mitk::TransformationOperation::WaveletForward(Image::Pointer & image, unsigned int numberOfLevels, unsigned int numberOfBands, mitk::BorderCondition condition, mitk::WaveletType waveletType) +{ + std::vector resultImages; + AccessByItk_n(image, ExecuteWaveletTransformation, (numberOfLevels, numberOfBands, condition, waveletType, resultImages)); + return resultImages; +} + + +template +static void ExecuteImageTypeToDouble(itk::Image* image, mitk::Image::Pointer &outputImage) +{ + typedef itk::Image< TPixel, VImageDimension > ImageType; + typedef itk::Image< double, VImageDimension > DoubleImageType; + typedef itk::CastImageFilter< ImageType, DoubleImageType > CastFilterType; + typedef itk::ImageDuplicator< DoubleImageType > DuplicatorType; + + // Perform FFT on input image + typename CastFilterType::Pointer castFilter = CastFilterType::New(); + castFilter->SetInput(image); + castFilter->Update(); + typename DuplicatorType::Pointer duplicator = DuplicatorType::New(); + duplicator->SetInputImage(castFilter->GetOutput()); + duplicator->Update(); + CastToMitkImage(duplicator->GetOutput(), outputImage); +} + +template +static void ExecuteRoundImage(itk::Image* image, mitk::Image::Pointer resampledImage, mitk::Image::Pointer &outputImage) +{ + typedef itk::Image< TPixel, VImageDimension > ImageType; + typedef itk::Image< double, VImageDimension > DoubleImageType; + typedef itk::CastImageFilter< ImageType, DoubleImageType > CastFilterType; + typedef itk::ImageDuplicator< DoubleImageType > DuplicatorType; + + typedef itk::UnaryFunctorImageFilter< DoubleImageType, ImageType, mitk::Functor::RoundValue > DefaultFilterType; + + typename DoubleImageType::Pointer itkImage = DoubleImageType::New(); + mitk::CastToItkImage(resampledImage, itkImage); + + typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); + filter->SetInput(itkImage); + filter->Update(); + + CastToMitkImage(filter->GetOutput(), outputImage); +} + +mitk::Image::Pointer mitk::TransformationOperation::ResampleImage(Image::Pointer &image, mitk::Vector3D spacingVector, mitk::ImageMappingInterpolator::Type interpolator, GridInterpolationPositionType position, bool returnAsDouble, bool roundOutput) +{ + // Convert image to double if required + mitk::Image::Pointer tmpImage = image; + if (returnAsDouble) + { + AccessByItk_n(image, ExecuteImageTypeToDouble, (tmpImage)); + } + + auto newGeometry = image->GetGeometry()->Clone(); + mitk::Vector3D spacing; + mitk::BaseGeometry::BoundsArrayType bounds = newGeometry->GetBounds(); + for (int i = 0; i < 3; ++i) + { + spacing[i] = newGeometry->GetSpacing()[i]; + //bounds[i*2+1] = newGeometry->GetBounds()[i * 2 + 1]; + if (spacingVector[i] > 0) + { + spacing[i] = spacingVector[i]; + if (position == mitk::GridInterpolationPositionType::SameSize) + { + unsigned int samples = image->GetDimensions()[i]; + double currentSpacing = newGeometry->GetSpacing()[i]; + double newFactor = std::floor(samples*currentSpacing / spacingVector[i]); + spacing[i] = samples * currentSpacing / newFactor; + } + } + bounds[i * 2] = 0; + bounds[i*2+1] = std::ceil(bounds[i*2+1] * newGeometry->GetSpacing()[i] *1.0 / spacing[i]); + } + mitk::Point3D origin = newGeometry->GetOrigin(); + if (position == mitk::GridInterpolationPositionType::CenterAligned) + { + for (int i = 0; i < 3; ++i) + { + double oldLength = newGeometry->GetSpacing()[i] * newGeometry->GetBounds()[i*2+1]; + double newLength = spacing[i] * bounds[i*2+1]; + origin[i] = origin[i] - (newLength - oldLength) / 2; + } + } + + newGeometry->SetSpacing(spacing); + newGeometry->SetOrigin(origin); + newGeometry->SetBounds(bounds); + + mitk::Image::Pointer tmpResult = ImageMappingHelper::map( + tmpImage, + mitk::GenerateIdentityRegistration3D().GetPointer(), + false, + 0.0, //Padding Value + newGeometry.GetPointer(), + false, + 0, //Error Value + interpolator + ); + + mitk::Image::Pointer result = mitk::Image::New(); + + if (roundOutput) + { + AccessByItk_n(tmpImage, ExecuteRoundImage, (tmpResult, result)); + } + else + { + result = tmpResult; + } + + return result; +} + + +template +static void ExecuteImageThresholding(itk::Image* image, mitk::Image::Pointer &resultImage) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + typedef itk::UnaryFunctorImageFilter< ImageType, MaskType, mitk::Functor::ThresholdValue > DefaultFilterType; + + typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); + filter->SetInput(image); + filter->GetFunctor().value = 0.5; + filter->Update(); + + CastToMitkImage(filter->GetOutput(), resultImage); + +} + +mitk::Image::Pointer mitk::TransformationOperation::ResampleMask(Image::Pointer &image, mitk::Vector3D spacingVector, mitk::ImageMappingInterpolator::Type interpolator, GridInterpolationPositionType position) +{ + mitk::Image::Pointer result; + if (interpolator == mitk::ImageMappingInterpolator::NearestNeighbor) + { + result = TransformationOperation::ResampleImage(image, spacingVector, interpolator, position, false, false); + } + else + { + auto tmpResult = TransformationOperation::ResampleImage(image, spacingVector, interpolator, position, true, false); + AccessByItk_n(tmpResult, ExecuteImageThresholding, (result)); + } + return result; +} + +namespace itk +{ + namespace utils + { + + IndexPairType IndexToLevelBandSteerablePyramid(unsigned int linearIndex, + unsigned int levels, unsigned int bands) + { + unsigned int totalOutputs = 1 + levels * bands; + if (linearIndex > totalOutputs - 1) + { + itkGenericExceptionMacro(<< "Failed converting linearIndex " << linearIndex + << " with levels: " << levels << " bands: " << bands << + " to Level,Band pair : out of bounds"); + } + + // Low pass (band = 0). + if (linearIndex == totalOutputs - 1) + { + return std::make_pair(levels - 1, 0); + } + + unsigned int band = (linearIndex) % bands + 1; + // note integer division ahead. + unsigned int level = (linearIndex) / bands; + itkAssertInDebugAndIgnoreInReleaseMacro(level < levels); + return std::make_pair(level, band); + } + + // Instantiation + template + unsigned int ComputeMaxNumberOfLevels<3>(const Size< 3 >& inputSize, const unsigned int & scaleFactor); + + template + unsigned int ComputeMaxNumberOfLevels<2>(const Size< 2 >& inputSize, const unsigned int & scaleFactor); + } // end namespace utils +} // end namespace itk \ No newline at end of file diff --git a/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h b/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h index 3e757d2802..362dcd73bf 100644 --- a/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h +++ b/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h @@ -1,289 +1,295 @@ /*=================================================================== 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 mitkAbstractGlobalImageFeature_h #define mitkAbstractGlobalImageFeature_h #include #include #include #include #include // STD Includes // Eigen #include // MITK includes #include namespace mitk { /** * * * ## Histogram Configuration ## * Most Feature Generation Classes that use histograms use the same parameters and * initialization logic. In general, all information can be passed either by the corresponding * Setter (which does not differenciate between global setting and feature specific setting) and * a parameter object which can be obtained from the command line arguments, for example. * * If the image values are used for the initializiation of the histogram, it can be defined * whether the whole image is used or only the masked areas to find minima and maxima. This is * done by the option SetIgnoreMask or the corrsponding options * -NAME::ignore-mask-for-histogram and -ignore-mask-for-histogram. If these are * true, the whole image is used for the calculation. * * Depending on the passed arguments, different initialization methods are used. The initialization * is in the following order: * - If Minimum Intensity, Maximum Intensity, and Binsize: The histogram is * initialized between the minimum and maximum intensity. the number of bins is determined by the * binsize. If the distance between minimum and maximum is not a multiple of the binsize, the maximum * is increase so that it is. * - Minimum Intensity, Bins, and Binsize: The histogram is initialized with the * given binsize, and the intensity range from the minimum to \f$maximum = minimum + binsize*bins\f$. * - Minimum Intensity, Maximum Intensity, and Bins: The histogram is initialized * between the given minimum and maximum intensity. The binsize is calculated so that the number * of bins is equal to the given number of bins. * - Binsize, and Minimum Intensity: The maximum is set to the maximum that * occur in the given image. Depending if the mask is considered or not, either only masked voxels or * the whole image is used for the calculation. The initialization is then equal as if the minimum * and maximum would have been given right from the beginning. * - Binsize, and Maximum Intensity: The minimum intensity is set to the minimum that * occur in the given image. Depending if the mask is considered or not, either only masked voxels or * the whole image is used for the calculation. The initialization is then equal as if the minimum * and maximum would have been given right from the beginning. * - Binsize: The maximum and the minimum intensity is set to the minimum and maximum that * occur in the given image. Depending if the mask is considered or not, either only masked voxels or * the whole image is used for the calculation. The initialization is then equal as if the minimum * and maximum would have been given right from the beginning. * - Bins, and Minimum Intensity: The maximum is calculated from the image. Depending * if the mask is considered or not, either only masked voxels or the whole image is used for the calculation. The histogram is * then initialized as if these values would have been given as minimum and maximum intensity. * - Bins, and Maximum Intensity: The minimum is calculated from the image. Depending * if the mask is considered or not, either only masked voxels or the whole image is used for the calculation. The histogram is * then initialized as if these values would have been given as minimum and maximum intensity. * - Bins: The minimum and the maximum is calculated from the image. Depending * if the mask is considered or not, either only masked voxels or * the whole image is used for the calculation. The histogram is * then initialized as if these values would have been given as minimum and maximum intensity. * - No Parameter given:The minimum and maximum intensity from the whole image or masked image is calculated and * the histogram then initialized to this with a standard number of bins (Is set by each filter on its own.) * * ### Remark about command line parameter#### * There are generally two options to set a parameter via the command line. A global one that works for * all filters that use histograms and a local one that set this parameter specific for this filter. The * local parameters start with the filter name (Indiciated by NAME) followed by two colons, for example * vol::min to set the minimum intensity for the volume filter. The global parameter is overwritten * by the local parameter, if it is specified. Otherwise, it is still valid. If this prevents the specification * of an histogram initialization method (for example, because the binsize is globally specified but the histogram * should be initialized using a fixed numbe of bins), the parameter NAME::ignore-global-histogram can be passed. * Then, all global histogram parameters are ignored and only local ones are used. * * The maximum intensity can be set by different command line parameters: global for all filters that use histograms * by -minimum-intensity and -minimum. Alternative it can be set only for this filter by * -NAME::minimum and -NAME::min. * * The minimum intensity can be set by different command line parameters: global for all filters that use histograms * by -maximum-intensity and -maximum. Alternative it can be set only for this filter by * \NAME::maximum and NAME::max. * * The binsize can be set by different command line parameters: global for all filters that use histograms * by -binsize. Alternative it can be set only for this filter by * \NAME::binsize. * * The number of bins can be set by different command line parameters: global for all filters that use histograms * by -bins. Alternative it can be set only for this filter by * \NAME::bins. * ### Note to the developers ### * All features are supposed to work the same way if a histogram is used somewhere in * the code. For this, each derived class that makes use of a histogram should use * the Quantifier object. In order to use this object correctly, the AddArguments-Function should * contain the line AddQuantifierArguments(parser);, the CalculateFeaturesUsingParameters function * should contain the line InitializeQuantifierFromParameters(feature, mask); and the CalculateFeatures function * sould contain the line InitializeQuantifier(image, mask);. These function * calls ensure that the necessary options are given to the configuration file, and that the initialization * of the quantifier is done correctly. This ensures an consistend behavior over all FeatureGeneration Classes. * */ class MITKCLCORE_EXPORT AbstractGlobalImageFeature : public BaseData { public: mitkClassMacro(AbstractGlobalImageFeature, BaseData) typedef std::vector< std::pair > FeatureListType; typedef std::vector< std::string> FeatureNameListType; typedef std::map ParameterTypes; /** * \brief Calculates the feature of this abstact interface. Does not necessarily considers the parameter settings. */ virtual FeatureListType CalculateFeatures(const Image::Pointer & feature, const Image::Pointer &mask) = 0; /** * \brief Calculates the given feature Slice-wise. Might not be availble for an individual filter! */ FeatureListType CalculateFeaturesSlicewise(const Image::Pointer & feature, const Image::Pointer &mask, int sliceID); + /** + * \brief Calculates the feature of this abstact interface. Does not necessarily considers the parameter settings. + */ + virtual void CalculateFeaturesSliceWiseUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, int sliceID, FeatureListType &featureList); + /** * \brief Calculates the feature of this abstact interface. Does not necessarily considers the parameter settings. */ virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) = 0; /** * \brief Returns a list of the names of all features that are calculated from this class */ virtual FeatureNameListType GetFeatureNames() = 0; /** * \brief Adds an additional Separator to the name of the feature, which encodes the used parameters */ virtual std::string GetCurrentFeatureEncoding(); /** * \brief Returns a string that encodes the feature class name. * * This Feature returns a string that should be put before every other feature * value. It has the format [::]::[::]. * The options and are only added, if the corresponding * options are set. */ std::string FeatureDescriptionPrefix(); itkSetMacro(Prefix, std::string); itkSetMacro(ShortName, std::string); itkSetMacro(LongName, std::string); itkSetMacro(FeatureClassName, std::string); itkSetMacro(Direction, int); void SetParameter(ParameterTypes param) { m_Parameter=param; }; itkGetConstMacro(Prefix, std::string); itkGetConstMacro(ShortName, std::string); itkGetConstMacro(LongName, std::string); itkGetConstMacro(FeatureClassName, std::string); itkGetConstMacro(Parameter, ParameterTypes); itkSetMacro(UseQuantifier, bool); itkGetConstMacro(UseQuantifier, bool); itkSetMacro(Quantifier, IntensityQuantifier::Pointer); itkGetMacro(Quantifier, IntensityQuantifier::Pointer); itkGetConstMacro(Direction, int); itkSetMacro(MinimumIntensity, double); itkSetMacro(UseMinimumIntensity, bool); itkSetMacro(MaximumIntensity, double); itkSetMacro(UseMaximumIntensity, bool); itkGetConstMacro(MinimumIntensity, double); itkGetConstMacro(UseMinimumIntensity, bool); itkGetConstMacro(MaximumIntensity, double); itkGetConstMacro(UseMaximumIntensity, bool); itkSetMacro(Binsize, double); itkSetMacro(UseBinsize, bool); itkGetConstMacro(Binsize, double); itkGetConstMacro(UseBinsize, bool); itkSetMacro(MorphMask, mitk::Image::Pointer); itkGetConstMacro(MorphMask, mitk::Image::Pointer); itkSetMacro(Bins, int); itkSetMacro(UseBins, bool); itkGetConstMacro(UseBins, bool); itkGetConstMacro(Bins, int); itkSetMacro(IgnoreMask, bool); itkGetConstMacro(IgnoreMask, bool); itkSetMacro(EncodeParameters, bool); itkGetConstMacro(EncodeParameters, bool); std::string GetOptionPrefix() const { if (m_Prefix.length() > 0) return m_Prefix + "::" + m_ShortName; return m_ShortName; } virtual void AddArguments(mitkCommandLineParser &parser) = 0; std::vector SplitDouble(std::string str, char delimiter); void AddQuantifierArguments(mitkCommandLineParser &parser); void InitializeQuantifierFromParameters(const Image::Pointer & feature, const Image::Pointer &mask,unsigned int defaultBins = 256); void InitializeQuantifier(const Image::Pointer & feature, const Image::Pointer &mask, unsigned int defaultBins = 256); std::string QuantifierParameterString(); public: //#ifndef DOXYGEN_SKIP void SetRequestedRegionToLargestPossibleRegion() override {}; bool RequestedRegionIsOutsideOfTheBufferedRegion() override { return true; }; bool VerifyRequestedRegion() override { return false; }; void SetRequestedRegion (const itk::DataObject * /*data*/) override {}; // Override bool IsEmpty() const override { if(IsInitialized() == false) return true; const TimeGeometry* timeGeometry = const_cast(this)->GetUpdatedTimeGeometry(); if(timeGeometry == nullptr) return true; return false; } private: std::string m_Prefix; // Prefix before all input parameters std::string m_ShortName; // Name of all variables std::string m_LongName; // Long version of the name (For turning on) std::string m_FeatureClassName; ParameterTypes m_Parameter; // Parameter setting bool m_UseQuantifier = false; IntensityQuantifier::Pointer m_Quantifier; double m_MinimumIntensity = 0; bool m_UseMinimumIntensity = false; double m_MaximumIntensity = 100; bool m_UseMaximumIntensity = false; bool m_EncodeParameters = false; double m_Binsize = 1; bool m_UseBinsize = false; int m_Bins = 256; bool m_UseBins = true; int m_Direction = 0; bool m_IgnoreMask = false; + bool m_CalculateWithParameter = false; mitk::Image::Pointer m_MorphMask = nullptr; //#endif // Skip Doxygen }; } #endif //mitkAbstractGlobalImageFeature_h diff --git a/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp b/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp index ca0d167275..5920b99ce2 100644 --- a/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp +++ b/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp @@ -1,391 +1,406 @@ /*=================================================================== 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 static void ExtractSlicesFromImages(mitk::Image::Pointer image, mitk::Image::Pointer mask, int direction, std::vector &imageVector, std::vector &maskVector) { typedef itk::Image< double, 2 > FloatImage2DType; typedef itk::Image< unsigned short, 2 > MaskImage2DType; typedef itk::Image< double, 3 > FloatImageType; typedef itk::Image< unsigned short, 3 > MaskImageType; FloatImageType::Pointer itkFloat = FloatImageType::New(); MaskImageType::Pointer itkMask = MaskImageType::New(); mitk::CastToItkImage(mask, itkMask); mitk::CastToItkImage(image, itkFloat); int idxA, idxB, idxC; switch (direction) { case 0: idxA = 1; idxB = 2; idxC = 0; break; case 1: idxA = 0; idxB = 2; idxC = 1; break; case 2: idxA = 0; idxB = 1; idxC = 2; break; default: idxA = 1; idxB = 2; idxC = 0; break; } auto imageSize = image->GetLargestPossibleRegion().GetSize(); FloatImageType::IndexType index3D; FloatImage2DType::IndexType index2D; FloatImage2DType::SpacingType spacing2D; spacing2D[0] = itkFloat->GetSpacing()[idxA]; spacing2D[1] = itkFloat->GetSpacing()[idxB]; for (unsigned int i = 0; i < imageSize[idxC]; ++i) { FloatImage2DType::RegionType region; FloatImage2DType::IndexType start; FloatImage2DType::SizeType size; start[0] = 0; start[1] = 0; size[0] = imageSize[idxA]; size[1] = imageSize[idxB]; region.SetIndex(start); region.SetSize(size); FloatImage2DType::Pointer image2D = FloatImage2DType::New(); image2D->SetRegions(region); image2D->Allocate(); MaskImage2DType::Pointer mask2D = MaskImage2DType::New(); mask2D->SetRegions(region); mask2D->Allocate(); unsigned long voxelsInMask = 0; for (unsigned int a = 0; a < imageSize[idxA]; ++a) { for (unsigned int b = 0; b < imageSize[idxB]; ++b) { index3D[idxA] = a; index3D[idxB] = b; index3D[idxC] = i; index2D[0] = a; index2D[1] = b; image2D->SetPixel(index2D, itkFloat->GetPixel(index3D)); mask2D->SetPixel(index2D, itkMask->GetPixel(index3D)); voxelsInMask += (itkMask->GetPixel(index3D) > 0) ? 1 : 0; } } image2D->SetSpacing(spacing2D); mask2D->SetSpacing(spacing2D); mitk::Image::Pointer tmpFloatImage = mitk::Image::New(); tmpFloatImage->InitializeByItk(image2D.GetPointer()); mitk::GrabItkImageMemory(image2D, tmpFloatImage); mitk::Image::Pointer tmpMaskImage = mitk::Image::New(); tmpMaskImage->InitializeByItk(mask2D.GetPointer()); mitk::GrabItkImageMemory(mask2D, tmpMaskImage); if (voxelsInMask > 0) { imageVector.push_back(tmpFloatImage); maskVector.push_back(tmpMaskImage); } } } std::vector mitk::AbstractGlobalImageFeature::SplitDouble(std::string str, char delimiter) { std::vector internal; std::stringstream ss(str); // Turn the string into a stream. std::string tok; double val; while (std::getline(ss, tok, delimiter)) { std::stringstream s2(tok); s2 >> val; internal.push_back(val); } return internal; } void mitk::AbstractGlobalImageFeature::AddQuantifierArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(name + "::minimum", name + "::min", mitkCommandLineParser::Float, "Minium Intensity for Quantification", "Defines the minimum Intensity used for Quantification", us::Any()); parser.addArgument(name + "::maximum", name + "::max", mitkCommandLineParser::Float, "Maximum Intensity for Quantification", "Defines the maximum Intensity used for Quantification", us::Any()); parser.addArgument(name + "::bins", name + "::bins", mitkCommandLineParser::Int, "Number of Bins", "Define the number of bins that is used ", us::Any()); parser.addArgument(name + "::binsize", name + "::binsize", mitkCommandLineParser::Float, "Binsize", "Define the size of the used bins", us::Any()); parser.addArgument(name + "::ignore-global-histogram", name + "::ignore-global-histogram", mitkCommandLineParser::Bool, "Ignore the global histogram Parameters", "Ignores the global histogram parameters", us::Any()); parser.addArgument(name + "::ignore-mask-for-histogram", name + "::ignore-mask", mitkCommandLineParser::Bool, "Ignore the global histogram Parameters", "Ignores the global histogram parameters", us::Any()); } void mitk::AbstractGlobalImageFeature::InitializeQuantifierFromParameters(const Image::Pointer & feature, const Image::Pointer &mask, unsigned int defaultBins) { unsigned int bins = 0; double binsize = 0; double minimum = 0; double maximum = 0; auto parsedArgs = GetParameter(); std::string name = GetOptionPrefix(); bool useGlobal = true; if (parsedArgs.count(name + "::ignore-global-histogram")) { useGlobal = false; SetUseMinimumIntensity(false); SetUseMaximumIntensity(false); SetUseBinsize(false); SetUseBins(false); } if (useGlobal) { if (parsedArgs.count("ignore-mask-for-histogram")) { bool tmp = us::any_cast(parsedArgs["ignore-mask-for-histogram"]); SetIgnoreMask(tmp); } if (parsedArgs.count("minimum-intensity")) { minimum = us::any_cast(parsedArgs["minimum-intensity"]); SetMinimumIntensity(minimum); SetUseMinimumIntensity(true); } if (parsedArgs.count("maximum-intensity")) { maximum = us::any_cast(parsedArgs["maximum-intensity"]); SetMaximumIntensity(maximum); SetUseMaximumIntensity(true); } if (parsedArgs.count("bins")) { bins = us::any_cast(parsedArgs["bins"]); SetBins(bins); SetUseBins(true); } if (parsedArgs.count("binsize")) { binsize = us::any_cast(parsedArgs["binsize"]); SetBinsize(binsize); SetUseBinsize(true); } } if (parsedArgs.count(name+"::ignore-mask-for-histogram")) { bool tmp = us::any_cast(parsedArgs[name+"::ignore-mask-for-histogram"]); SetIgnoreMask(tmp); } if (parsedArgs.count(name + "::minimum")) { minimum = us::any_cast(parsedArgs[name + "::minimum"]); SetMinimumIntensity(minimum); SetUseMinimumIntensity(true); } if (parsedArgs.count(name + "::maximum")) { maximum = us::any_cast(parsedArgs[name + "::maximum"]); SetMaximumIntensity(maximum); SetUseMaximumIntensity(true); } if (parsedArgs.count(name + "::bins")) { bins = us::any_cast(parsedArgs[name + "::bins"]); SetBins(bins); } if (parsedArgs.count(name + "::binsize")) { binsize = us::any_cast(parsedArgs[name + "::binsize"]); SetBinsize(binsize); SetUseBinsize(true); } InitializeQuantifier(feature, mask, defaultBins); } void mitk::AbstractGlobalImageFeature::InitializeQuantifier(const Image::Pointer & feature, const Image::Pointer &mask, unsigned int defaultBins) { m_Quantifier = IntensityQuantifier::New(); if (GetUseMinimumIntensity() && GetUseMaximumIntensity() && GetUseBinsize()) m_Quantifier->InitializeByBinsizeAndMaximum(GetMinimumIntensity(), GetMaximumIntensity(), GetBinsize()); else if (GetUseMinimumIntensity() && GetUseBins() && GetUseBinsize()) m_Quantifier->InitializeByBinsizeAndBins(GetMinimumIntensity(), GetBins(), GetBinsize()); else if (GetUseMinimumIntensity() && GetUseMaximumIntensity() && GetUseBins()) m_Quantifier->InitializeByMinimumMaximum(GetMinimumIntensity(), GetMaximumIntensity(), GetBins()); // Intialize from Image and Binsize else if (GetUseBinsize() && GetIgnoreMask() && GetUseMinimumIntensity()) m_Quantifier->InitializeByImageAndBinsizeAndMinimum(feature, GetMinimumIntensity(), GetBinsize()); else if (GetUseBinsize() && GetIgnoreMask() && GetUseMaximumIntensity()) m_Quantifier->InitializeByImageAndBinsizeAndMaximum(feature, GetMaximumIntensity(), GetBinsize()); else if (GetUseBinsize() && GetIgnoreMask()) m_Quantifier->InitializeByImageAndBinsize(feature, GetBinsize()); // Initialize form Image, Mask and Binsize else if (GetUseBinsize() && GetUseMinimumIntensity()) m_Quantifier->InitializeByImageRegionAndBinsizeAndMinimum(feature, mask, GetMinimumIntensity(), GetBinsize()); else if (GetUseBinsize() && GetUseMaximumIntensity()) m_Quantifier->InitializeByImageRegionAndBinsizeAndMaximum(feature, mask, GetMaximumIntensity(), GetBinsize()); else if (GetUseBinsize()) m_Quantifier->InitializeByImageRegionAndBinsize(feature, mask, GetBinsize()); // Intialize from Image and Bins else if (GetUseBins() && GetIgnoreMask() && GetUseMinimumIntensity()) m_Quantifier->InitializeByImageAndMinimum(feature, GetMinimumIntensity(), GetBins()); else if (GetUseBins() && GetIgnoreMask() && GetUseMaximumIntensity()) m_Quantifier->InitializeByImageAndMaximum(feature, GetMaximumIntensity(), GetBins()); else if (GetUseBins()) m_Quantifier->InitializeByImage(feature, GetBins()); // Intialize from Image, Mask and Bins else if (GetUseBins() && GetUseMinimumIntensity()) m_Quantifier->InitializeByImageRegionAndMinimum(feature, mask, GetMinimumIntensity(), GetBins()); else if (GetUseBins() && GetUseMaximumIntensity()) m_Quantifier->InitializeByImageRegionAndMaximum(feature, mask, GetMaximumIntensity(), GetBins()); else if (GetUseBins()) m_Quantifier->InitializeByImageRegion(feature, mask, GetBins()); // Default else if (GetIgnoreMask()) m_Quantifier->InitializeByImage(feature, GetBins()); else m_Quantifier->InitializeByImageRegion(feature, mask, defaultBins); } std::string mitk::AbstractGlobalImageFeature::GetCurrentFeatureEncoding() { return ""; } std::string mitk::AbstractGlobalImageFeature::FeatureDescriptionPrefix() { std::string output; output = m_FeatureClassName + "::"; if (m_EncodeParameters) { output += GetCurrentFeatureEncoding() + "::"; } return output; } std::string mitk::AbstractGlobalImageFeature::QuantifierParameterString() { std::stringstream ss; if (GetUseMinimumIntensity() && GetUseMaximumIntensity() && GetUseBinsize()) ss << "Min-" << GetMinimumIntensity() << "_Max-" << GetMaximumIntensity() << "_BS-" << GetBinsize(); else if (GetUseMinimumIntensity() && GetUseBins() && GetUseBinsize()) ss << "Min-" << GetMinimumIntensity() << "_Bins-" << GetBins() << "_BS-" << GetBinsize(); else if (GetUseMinimumIntensity() && GetUseMaximumIntensity() && GetUseBins()) ss << "Min-" << GetMinimumIntensity() << "_Max-" << GetMaximumIntensity() << "_Bins-" << GetBins(); // Intialize from Image and Binsize else if (GetUseBinsize() && GetIgnoreMask() && GetUseMinimumIntensity()) ss << "Min-" << GetMinimumIntensity() << "_BS-" << GetBinsize() << "_FullImage"; else if (GetUseBinsize() && GetIgnoreMask() && GetUseMaximumIntensity()) ss << "Max-" << GetMaximumIntensity() << "_BS-" << GetBinsize() << "_FullImage"; else if (GetUseBinsize() && GetIgnoreMask()) ss << "BS-" << GetBinsize() << "_FullImage"; // Initialize form Image, Mask and Binsize else if (GetUseBinsize() && GetUseMinimumIntensity()) ss << "Min-" << GetMinimumIntensity() << "_BS-" << GetBinsize(); else if (GetUseBinsize() && GetUseMaximumIntensity()) ss << "Max-" << GetMaximumIntensity() << "_BS-" << GetBinsize(); else if (GetUseBinsize()) ss << "BS-" << GetBinsize(); // Intialize from Image and Bins else if (GetUseBins() && GetIgnoreMask() && GetUseMinimumIntensity()) ss << "Min-" << GetMinimumIntensity() << "_Bins-" << GetBins() << "_FullImage"; else if (GetUseBins() && GetIgnoreMask() && GetUseMaximumIntensity()) ss << "Max-" << GetMaximumIntensity() << "_Bins-" << GetBins() << "_FullImage"; else if (GetUseBins()) ss << "Bins-" << GetBins() << "_FullImage"; // Intialize from Image, Mask and Bins else if (GetUseBins() && GetUseMinimumIntensity()) ss << "Min-" << GetMinimumIntensity() << "_Bins-" << GetBins(); else if (GetUseBins() && GetUseMaximumIntensity()) ss << "Max-" << GetMaximumIntensity() << "_Bins-" << GetBins(); else if (GetUseBins()) ss << "Bins-" << GetBins(); // Default else if (GetIgnoreMask()) ss << "Bins-" << GetBins() << "_FullImage"; else ss << "Bins-" << GetBins(); return ss.str(); } + +void mitk::AbstractGlobalImageFeature::CalculateFeaturesSliceWiseUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, int sliceID, FeatureListType &featureList) +{ + m_CalculateWithParameter = true; + auto result = CalculateFeaturesSlicewise(feature, mask, sliceID); + featureList.insert(featureList.end(), result.begin(), result.end()); +} + mitk::AbstractGlobalImageFeature::FeatureListType mitk::AbstractGlobalImageFeature::CalculateFeaturesSlicewise(const Image::Pointer & feature, const Image::Pointer &mask, int sliceID) { std::vector imageVector; std::vector maskVector; ExtractSlicesFromImages(feature, mask,sliceID, imageVector, maskVector); - std::vector statVector; for (std::size_t index = 0; index < imageVector.size(); ++index) { - auto stat = this->CalculateFeatures(imageVector[index], maskVector[index]); - statVector.push_back(stat); + if (m_CalculateWithParameter) + { + FeatureListType stat; + this->CalculateFeaturesUsingParameters(imageVector[index], maskVector[index], maskVector[index], stat); + statVector.push_back(stat); + } + else + { + auto stat = this->CalculateFeatures(imageVector[index], maskVector[index]); + statVector.push_back(stat); + } } if (statVector.size() < 1) return FeatureListType(); FeatureListType statMean, statStd, result; for (std::size_t i = 0; i < statVector[0].size(); ++i) { auto cElement1 = statVector[0][i]; cElement1.first = "SliceWise Mean " + cElement1.first; cElement1.second = 0.0; auto cElement2 = statVector[0][i]; cElement2.first = "SliceWise Var. " + cElement2.first; cElement2.second = 0.0; statMean.push_back(cElement1); statStd.push_back(cElement2); } - for (auto cStat : statVector) { for (std::size_t i = 0; i < cStat.size(); ++i) { statMean[i].second += cStat[i].second / (1.0*statVector.size()); } } for (auto cStat : statVector) { for (std::size_t i = 0; i < cStat.size(); ++i) { statStd[i].second += (cStat[i].second - statMean[i].second)*(cStat[i].second - statMean[i].second) / (1.0*statVector.size()); } } for (auto cStat : statVector) { std::copy(cStat.begin(), cStat.end(), std::back_inserter(result)); } std::copy(statMean.begin(), statMean.end(), std::back_inserter(result)); std::copy(statStd.begin(), statStd.end(), std::back_inserter(result)); return result; } \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/include/itkLocalIntensityFilter.hxx b/Modules/Classification/CLUtilities/include/itkLocalIntensityFilter.hxx index e489992fb8..2a6cd76857 100644 --- a/Modules/Classification/CLUtilities/include/itkLocalIntensityFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkLocalIntensityFilter.hxx @@ -1,309 +1,318 @@ /*=================================================================== 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 itkLocalIntensityFilter_cpp #define itkLocalIntensityFilter_cpp #include #include #include #include #include #include "itkImageScanlineIterator.h" #include "itkProgressReporter.h" namespace itk { template< typename TInputImage > LocalIntensityFilter< TInputImage > ::LocalIntensityFilter() :m_ThreadLocalMaximum(1), m_ThreadLocalPeakValue(1), m_ThreadGlobalPeakValue(1) { // first output is a copy of the image, DataObject created by // superclass // allocate the data objects for the outputs which are // just decorators around real types for (int i = 1; i < 4; ++i) { typename RealObjectType::Pointer output = static_cast< RealObjectType * >(this->MakeOutput(i).GetPointer()); this->ProcessObject::SetNthOutput(i, output.GetPointer()); } } template< typename TInputImage > DataObject::Pointer LocalIntensityFilter< TInputImage > ::MakeOutput(DataObjectPointerArraySizeType output) { switch (output) { case 0: return TInputImage::New().GetPointer(); break; case 1: case 2: case 3: case 4: case 5: case 6: return RealObjectType::New().GetPointer(); break; default: // might as well make an image return TInputImage::New().GetPointer(); break; } } template< typename TInputImage > typename LocalIntensityFilter< TInputImage >::RealObjectType * LocalIntensityFilter< TInputImage > ::GetLocalPeakOutput() { return static_cast< RealObjectType * >(this->ProcessObject::GetOutput(1)); } template< typename TInputImage > const typename LocalIntensityFilter< TInputImage >::RealObjectType * LocalIntensityFilter< TInputImage > ::GetLocalPeakOutput() const { return static_cast< const RealObjectType * >(this->ProcessObject::GetOutput(1)); } template< typename TInputImage > typename LocalIntensityFilter< TInputImage >::RealObjectType * LocalIntensityFilter< TInputImage > ::GetGlobalPeakOutput() { return static_cast< RealObjectType * >(this->ProcessObject::GetOutput(2)); } template< typename TInputImage > const typename LocalIntensityFilter< TInputImage >::RealObjectType * LocalIntensityFilter< TInputImage > ::GetGlobalPeakOutput() const { return static_cast< const RealObjectType * >(this->ProcessObject::GetOutput(2)); } template< typename TInputImage > typename LocalIntensityFilter< TInputImage >::RealObjectType * LocalIntensityFilter< TInputImage > ::GetLocalMaximumOutput() { return static_cast< RealObjectType * >(this->ProcessObject::GetOutput(3)); } template< typename TInputImage > const typename LocalIntensityFilter< TInputImage >::RealObjectType * LocalIntensityFilter< TInputImage > ::GetLocalMaximumOutput() const { return static_cast< const RealObjectType * >(this->ProcessObject::GetOutput(3)); } template< typename TInputImage > void LocalIntensityFilter< TInputImage > ::GenerateInputRequestedRegion() { Superclass::GenerateInputRequestedRegion(); if (this->GetInput()) { InputImagePointer image = const_cast< typename Superclass::InputImageType * >(this->GetInput()); image->SetRequestedRegionToLargestPossibleRegion(); } } template< typename TInputImage > void LocalIntensityFilter< TInputImage > ::EnlargeOutputRequestedRegion(DataObject *data) { Superclass::EnlargeOutputRequestedRegion(data); data->SetRequestedRegionToLargestPossibleRegion(); } template< typename TInputImage > void LocalIntensityFilter< TInputImage > ::AllocateOutputs() { // Pass the input through as the output InputImagePointer image = const_cast< TInputImage * >(this->GetInput()); this->GraftOutput(image); // Nothing that needs to be allocated for the remaining outputs } template< typename TInputImage > void LocalIntensityFilter< TInputImage > ::BeforeThreadedGenerateData() { ThreadIdType numberOfThreads = this->GetNumberOfThreads(); // Resize the thread temporaries m_ThreadLocalMaximum.SetSize(numberOfThreads); m_ThreadLocalPeakValue.SetSize(numberOfThreads); m_ThreadGlobalPeakValue.SetSize(numberOfThreads); // Initialize the temporaries m_ThreadLocalMaximum.Fill(std::numeric_limits< RealType>::lowest()); m_ThreadLocalPeakValue.Fill(std::numeric_limits< RealType>::lowest()); m_ThreadGlobalPeakValue.Fill(std::numeric_limits< RealType>::lowest()); } template< typename TInputImage > void LocalIntensityFilter< TInputImage > ::AfterThreadedGenerateData() { ThreadIdType i; ThreadIdType numberOfThreads = this->GetNumberOfThreads(); RealType localMaximum = std::numeric_limits< RealType >::lowest(); RealType localPeakValue = std::numeric_limits< RealType >::lowest(); RealType globalPeakValue = std::numeric_limits< RealType >::lowest(); for (i = 0; i < numberOfThreads; i++) { globalPeakValue = std::max(globalPeakValue, m_ThreadGlobalPeakValue[i]); if (localMaximum == m_ThreadLocalMaximum[i]) { localPeakValue = std::max< RealType >(m_ThreadLocalPeakValue[i], localPeakValue); } else if (localMaximum < m_ThreadLocalMaximum[i]) { localMaximum = m_ThreadLocalMaximum[i]; localPeakValue = m_ThreadLocalPeakValue[i]; } } - - // Set the outputs + // Set the outputs this->GetLocalPeakOutput()->Set(localPeakValue); this->GetGlobalPeakOutput()->Set(globalPeakValue); this->GetLocalMaximumOutput()->Set(localMaximum); } template< typename TInputImage > void LocalIntensityFilter< TInputImage > ::ThreadedGenerateData(const RegionType & outputRegionForThread, ThreadIdType threadId) { typename TInputImage::ConstPointer itkImage = this->GetInput(); typename MaskImageType::Pointer itkMask = m_Mask; double range = m_Range; double minimumSpacing = 1; typename TInputImage::SizeType regionSize; int offset = std::ceil(range / minimumSpacing); regionSize.Fill(1); for (unsigned int i = 0; i < TInputImage::ImageDimension; ++i) { minimumSpacing = itkImage->GetSpacing()[i]; offset = std::ceil(range / minimumSpacing); regionSize[i] = offset; } - itk::ConstNeighborhoodIterator iter(regionSize, itkImage, outputRegionForThread); itk::ConstNeighborhoodIterator iterMask(regionSize, itkMask, outputRegionForThread); typename TInputImage::PointType origin; typename TInputImage::PointType localPoint; itk::Index index; double tmpPeakValue; double globalPeakValue = std::numeric_limits::lowest(); double localPeakValue = std::numeric_limits::lowest(); PixelType localMaximum = std::numeric_limits::lowest(); std::vector vectorIsInRange; index = iter.GetIndex(); itkImage->TransformIndexToPhysicalPoint(index, origin); for (itk::SizeValueType i = 0; i < iter.Size(); ++i) { itkImage->TransformIndexToPhysicalPoint(iter.GetIndex(i), localPoint); double dist = origin.EuclideanDistanceTo(localPoint); vectorIsInRange.push_back((dist < range)); } int count = 0; iter.NeedToUseBoundaryConditionOff(); iterMask.NeedToUseBoundaryConditionOff(); + auto imageSize = itkImage->GetLargestPossibleRegion().GetSize(); + unsigned int imageDimension = itkImage->GetImageDimension(); + while (!iter.IsAtEnd()) { if (iterMask.GetCenterPixel() > 0) { tmpPeakValue = 0; count = 0; for (itk::SizeValueType i = 0; i < iter.Size(); ++i) { if (vectorIsInRange[i]) { - if (iter.IndexInBounds(i)) + auto localIndex = iter.GetIndex(i); + bool calculatePoint = true; + for (unsigned int dimension = 0; dimension < imageDimension; ++dimension) + { + calculatePoint &= (localIndex[dimension] < static_cast(imageSize[dimension])); + calculatePoint &= (0 <= localIndex[dimension]); + } + if (calculatePoint) { tmpPeakValue += iter.GetPixel(i); ++count; } } } tmpPeakValue /= count; globalPeakValue = std::max(tmpPeakValue, globalPeakValue); auto currentCenterPixelValue = iter.GetCenterPixel(); if (localMaximum == currentCenterPixelValue) { localPeakValue = std::max(tmpPeakValue, localPeakValue); } else if (localMaximum < currentCenterPixelValue) { localMaximum = currentCenterPixelValue; localPeakValue = tmpPeakValue; } } ++iterMask; ++iter; } + m_ThreadLocalMaximum[threadId] = localMaximum; m_ThreadLocalPeakValue[threadId] = localPeakValue; m_ThreadGlobalPeakValue[threadId] = globalPeakValue; } template< typename TImage > void LocalIntensityFilter< TImage > ::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "Local Peak: " << this->GetLocalPeak() << std::endl; os << indent << "Global Peak: " << this->GetGlobalPeak() << std::endl; os << indent << "Local Maximum: " << this->GetLocalMaximum() << std::endl; } } // end namespace itk #endif \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp index 3bb2973578..db1ca60ac6 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp @@ -1,693 +1,693 @@ #include // MITK #include #include #include // ITK #include #include #include // STL #include #include namespace mitk { struct CoocurenceMatrixHolder { public: CoocurenceMatrixHolder(double min, double max, int number); int IntensityToIndex(double intensity); double IndexToMinIntensity(int index); double IndexToMeanIntensity(int index); double IndexToMaxIntensity(int index); double m_MinimumRange; double m_MaximumRange; double m_Stepsize; int m_NumberOfBins; Eigen::MatrixXd m_Matrix; }; struct CoocurenceMatrixFeatures { CoocurenceMatrixFeatures() : JointMaximum(0), JointAverage(0), JointVariance(0), JointEntropy(0), RowMaximum(0), RowAverage(0), RowVariance(0), RowEntropy(0), FirstRowColumnEntropy(0), SecondRowColumnEntropy(0), DifferenceAverage(0), DifferenceVariance(0), DifferenceEntropy(0), SumAverage(0), SumVariance(0), SumEntropy(0), AngularSecondMoment(0), Contrast(0), Dissimilarity(0), InverseDifference(0), InverseDifferenceNormalised(0), InverseDifferenceMoment(0), InverseDifferenceMomentNormalised(0), InverseVariance(0), Correlation(0), Autocorrelation(0), ClusterTendency(0), ClusterShade(0), ClusterProminence(0), FirstMeasureOfInformationCorrelation(0), SecondMeasureOfInformationCorrelation(0) { } public: double JointMaximum; double JointAverage; double JointVariance; double JointEntropy; double RowMaximum; double RowAverage; double RowVariance; double RowEntropy; double FirstRowColumnEntropy; double SecondRowColumnEntropy; double DifferenceAverage; double DifferenceVariance; double DifferenceEntropy; double SumAverage; double SumVariance; double SumEntropy; double AngularSecondMoment; double Contrast; double Dissimilarity; double InverseDifference; double InverseDifferenceNormalised; double InverseDifferenceMoment; double InverseDifferenceMomentNormalised; double InverseVariance; double Correlation; double Autocorrelation; double ClusterTendency; double ClusterShade; double ClusterProminence; double FirstMeasureOfInformationCorrelation; double SecondMeasureOfInformationCorrelation; }; } static void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, std::string prefix, mitk::GIFCooccurenceMatrix2::FeatureListType &featureList); static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature); static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number); mitk::CoocurenceMatrixHolder::CoocurenceMatrixHolder(double min, double max, int number) : m_MinimumRange(min), m_MaximumRange(max), m_NumberOfBins(number) { m_Matrix.resize(number, number); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::CoocurenceMatrixHolder::IntensityToIndex(double intensity) { int index = std::floor((intensity - m_MinimumRange) / m_Stepsize); return std::max(0, std::min(index, m_NumberOfBins - 1)); } double mitk::CoocurenceMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template void CalculateCoOcMatrix(itk::Image* itkImage, itk::Image* mask, itk::Offset offset, int range, mitk::CoocurenceMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef itk::ShapedNeighborhoodIterator ShapeIterType; typedef itk::ShapedNeighborhoodIterator ShapeMaskIterType; typedef itk::ImageRegionConstIterator ConstIterType; typedef itk::ImageRegionConstIterator ConstMaskIterType; itk::Size radius; radius.Fill(range+1); ShapeIterType imageOffsetIter(radius, itkImage, itkImage->GetLargestPossibleRegion()); ShapeMaskIterType maskOffsetIter(radius, mask, mask->GetLargestPossibleRegion()); imageOffsetIter.ActivateOffset(offset); maskOffsetIter.ActivateOffset(offset); ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); // iterator.GetIndex() + ci.GetNeighborhoodOffset() auto region = mask->GetLargestPossibleRegion(); while (!maskIter.IsAtEnd()) { auto ciMask = maskOffsetIter.Begin(); auto ciValue = imageOffsetIter.Begin(); if (maskIter.Value() > 0 && ciMask.Get() > 0 && imageIter.Get() == imageIter.Get() && ciValue.Get() == ciValue.Get() && region.IsInside(maskOffsetIter.GetIndex() + ciMask.GetNeighborhoodOffset())) { int i = holder.IntensityToIndex(imageIter.Get()); int j = holder.IntensityToIndex(ciValue.Get()); holder.m_Matrix(i, j) += 1; holder.m_Matrix(j, i) += 1; } ++imageOffsetIter; ++maskOffsetIter; ++imageIter; ++maskIter; } } void CalculateFeatures( mitk::CoocurenceMatrixHolder &holder, mitk::CoocurenceMatrixFeatures & results ) { auto pijMatrix = holder.m_Matrix; auto piMatrix = holder.m_Matrix; auto pjMatrix = holder.m_Matrix; double Ng = holder.m_NumberOfBins; int NgSize = holder.m_NumberOfBins; pijMatrix /= pijMatrix.sum(); piMatrix.rowwise().normalize(); pjMatrix.colwise().normalize(); for (int i = 0; i < holder.m_NumberOfBins; ++i) for (int j = 0; j < holder.m_NumberOfBins; ++j) { if (pijMatrix(i, j) != pijMatrix(i, j)) pijMatrix(i, j) = 0; if (piMatrix(i, j) != piMatrix(i, j)) piMatrix(i, j) = 0; if (pjMatrix(i, j) != pjMatrix(i, j)) pjMatrix(i, j) = 0; } Eigen::VectorXd piVector = pijMatrix.colwise().sum(); Eigen::VectorXd pjVector = pijMatrix.rowwise().sum(); double sigmai = 0;; for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1;// holder.IndexToMeanIntensity(i); results.RowAverage += iInt * piVector(i); if (piVector(i) > 0) { results.RowEntropy -= piVector(i) * std::log(piVector(i)) / std::log(2); } } for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1; // holder.IndexToMeanIntensity(i); results.RowVariance += (iInt - results.RowAverage)*(iInt - results.RowAverage) * piVector(i); } results.RowMaximum = piVector.maxCoeff(); sigmai = std::sqrt(results.RowVariance); Eigen::VectorXd pimj(NgSize); pimj.fill(0); Eigen::VectorXd pipj(2*NgSize); pipj.fill(0); results.JointMaximum += pijMatrix.maxCoeff(); for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1;// holder.IndexToMeanIntensity(i); double jInt = j + 1;// holder.IndexToMeanIntensity(j); double pij = pijMatrix(i, j); int deltaK = (i - j)>0?(i-j) : (j-i); pimj(deltaK) += pij; pipj(i + j) += pij; results.JointAverage += iInt * pij; if (pij > 0) { results.JointEntropy -= pij * std::log(pij) / std::log(2); results.FirstRowColumnEntropy -= pij * std::log(piVector(i)*pjVector(j)) / std::log(2); } if (piVector(i) > 0 && pjVector(j) > 0 ) { results.SecondRowColumnEntropy -= piVector(i)*pjVector(j) * std::log(piVector(i)*pjVector(j)) / std::log(2); } results.AngularSecondMoment += pij*pij; results.Contrast += (iInt - jInt)* (iInt - jInt) * pij; results.Dissimilarity += std::abs(iInt - jInt) * pij; results.InverseDifference += pij / (1 + (std::abs(iInt - jInt))); results.InverseDifferenceNormalised += pij / (1 + (std::abs(iInt - jInt) / Ng)); results.InverseDifferenceMoment += pij / (1 + (iInt - jInt)*(iInt - jInt)); results.InverseDifferenceMomentNormalised += pij / (1 + (iInt - jInt)*(iInt - jInt)/Ng/Ng); results.Autocorrelation += iInt*jInt * pij; double cluster = (iInt + jInt - 2 * results.RowAverage); results.ClusterTendency += cluster*cluster * pij; results.ClusterShade += cluster*cluster*cluster * pij; results.ClusterProminence += cluster*cluster*cluster*cluster * pij; if (iInt != jInt) { results.InverseVariance += pij / (iInt - jInt) / (iInt - jInt); } } } results.Correlation = 1 / sigmai / sigmai * (-results.RowAverage*results.RowAverage+ results.Autocorrelation); results.FirstMeasureOfInformationCorrelation = (results.JointEntropy - results.FirstRowColumnEntropy) / results.RowEntropy; if (results.JointEntropy < results.SecondRowColumnEntropy) { results.SecondMeasureOfInformationCorrelation = sqrt(1 - exp(-2 * (results.SecondRowColumnEntropy - results.JointEntropy))); } else { results.SecondMeasureOfInformationCorrelation = 0; } for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1; double pij = pijMatrix(i, j); results.JointVariance += (iInt - results.JointAverage)* (iInt - results.JointAverage)*pij; } } for (int k = 0; k < NgSize; ++k) { results.DifferenceAverage += k* pimj(k); if (pimj(k) > 0) { results.DifferenceEntropy -= pimj(k) * log(pimj(k)) / std::log(2); } } for (int k = 0; k < NgSize; ++k) { results.DifferenceVariance += (results.DifferenceAverage-k)* (results.DifferenceAverage-k)*pimj(k); } for (int k = 0; k <2* NgSize ; ++k) { results.SumAverage += (2+k)* pipj(k); if (pipj(k) > 0) { results.SumEntropy -= pipj(k) * log(pipj(k)) / std::log(2); } } for (int k = 0; k < 2*NgSize; ++k) { results.SumVariance += (2+k - results.SumAverage)* (2+k - results.SumAverage)*pipj(k); } //MITK_INFO << std::endl << holder.m_Matrix; //MITK_INFO << std::endl << pijMatrix; //MITK_INFO << std::endl << piMatrix; //MITK_INFO << std::endl << pjMatrix; //for (int i = 0; i < holder.m_NumberOfBins; ++i) //{ // MITK_INFO << "Bin " << i << " Min: " << holder.IndexToMinIntensity(i) << " Max: " << holder.IndexToMaxIntensity(i); //} //MITK_INFO << pimj; //MITK_INFO << pipj; } template void CalculateCoocurenceFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFCooccurenceMatrix2::FeatureListType & featureList, mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2Configuration config) { typedef itk::Image MaskType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// double rangeMin = config.MinimumIntensity; double rangeMax = config.MaximumIntensity; int numberOfBins = config.Bins; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); //Find possible directions std::vector < itk::Offset > offsetVector; NeighborhoodType hood; hood.SetRadius(1); unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetType offset; for (unsigned int d = 0; d < centerIndex; d++) { offset = hood.GetOffset(d); bool useOffset = true; for (unsigned int i = 0; i < VImageDimension; ++i) { offset[i] *= config.range; if (config.direction == i + 2 && offset[i] != 0) { useOffset = false; } } if (useOffset) { offsetVector.push_back(offset); } } if (config.direction == 1) { offsetVector.clear(); offset[0] = 0; offset[1] = 0; offset[2] = 1; } std::vector resultVector; mitk::CoocurenceMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures overallFeature; for (std::size_t i = 0; i < offsetVector.size(); ++i) { if (config.direction > 1) { if (offsetVector[i][config.direction - 2] != 0) { continue; } } offset = offsetVector[i]; mitk::CoocurenceMatrixHolder holder(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures coocResults; CalculateCoOcMatrix(itkImage, maskImage, offset, config.range, holder); holderOverall.m_Matrix += holder.m_Matrix; CalculateFeatures(holder, coocResults); resultVector.push_back(coocResults); } CalculateFeatures(holderOverall, overallFeature); //NormalizeMatrixFeature(overallFeature, offsetVector.size()); mitk::CoocurenceMatrixFeatures featureMean; mitk::CoocurenceMatrixFeatures featureStd; CalculateMeanAndStdDevFeatures(resultVector, featureMean, featureStd); std::ostringstream ss; ss << config.range; std::string strRange = ss.str(); MatrixFeaturesTo(overallFeature, config.prefix + "Overall ", featureList); MatrixFeaturesTo(featureMean, config.prefix + "Mean ", featureList); MatrixFeaturesTo(featureStd, config.prefix + "Std.Dev. ", featureList); - - } static void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, std::string prefix, mitk::GIFCooccurenceMatrix2::FeatureListType &featureList) { featureList.push_back(std::make_pair(prefix + "Joint Maximum", features.JointMaximum)); featureList.push_back(std::make_pair(prefix + "Joint Average", features.JointAverage)); featureList.push_back(std::make_pair(prefix + "Joint Variance", features.JointVariance)); featureList.push_back(std::make_pair(prefix + "Joint Entropy", features.JointEntropy)); featureList.push_back(std::make_pair(prefix + "Difference Average", features.DifferenceAverage)); featureList.push_back(std::make_pair(prefix + "Difference Variance", features.DifferenceVariance)); featureList.push_back(std::make_pair(prefix + "Difference Entropy", features.DifferenceEntropy)); featureList.push_back(std::make_pair(prefix + "Sum Average", features.SumAverage)); featureList.push_back(std::make_pair(prefix + "Sum Variance", features.SumVariance)); featureList.push_back(std::make_pair(prefix + "Sum Entropy", features.SumEntropy)); featureList.push_back(std::make_pair(prefix + "Angular Second Moment", features.AngularSecondMoment)); featureList.push_back(std::make_pair(prefix + "Contrast", features.Contrast)); featureList.push_back(std::make_pair(prefix + "Dissimilarity", features.Dissimilarity)); featureList.push_back(std::make_pair(prefix + "Inverse Difference", features.InverseDifference)); featureList.push_back(std::make_pair(prefix + "Inverse Difference Normalized", features.InverseDifferenceNormalised)); featureList.push_back(std::make_pair(prefix + "Inverse Difference Moment", features.InverseDifferenceMoment)); featureList.push_back(std::make_pair(prefix + "Inverse Difference Moment Normalized", features.InverseDifferenceMomentNormalised)); featureList.push_back(std::make_pair(prefix + "Inverse Variance", features.InverseVariance)); featureList.push_back(std::make_pair(prefix + "Correlation", features.Correlation)); featureList.push_back(std::make_pair(prefix + "Autocorrelation", features.Autocorrelation)); featureList.push_back(std::make_pair(prefix + "Cluster Tendency", features.ClusterTendency)); featureList.push_back(std::make_pair(prefix + "Cluster Shade", features.ClusterShade)); featureList.push_back(std::make_pair(prefix + "Cluster Prominence", features.ClusterProminence)); featureList.push_back(std::make_pair(prefix + "First Measure of Information Correlation", features.FirstMeasureOfInformationCorrelation)); featureList.push_back(std::make_pair(prefix + "Second Measure of Information Correlation", features.SecondMeasureOfInformationCorrelation)); featureList.push_back(std::make_pair(prefix + "Row Maximum", features.RowMaximum)); featureList.push_back(std::make_pair(prefix + "Row Average", features.RowAverage)); featureList.push_back(std::make_pair(prefix + "Row Variance", features.RowVariance)); featureList.push_back(std::make_pair(prefix + "Row Entropy", features.RowEntropy)); featureList.push_back(std::make_pair(prefix + "First Row-Column Entropy", features.FirstRowColumnEntropy)); featureList.push_back(std::make_pair(prefix + "Second Row-Column Entropy", features.SecondRowColumnEntropy)); } static void CalculateMeanAndStdDevFeatures(std::vector featureList, - mitk::CoocurenceMatrixFeatures &meanFeature, - mitk::CoocurenceMatrixFeatures &stdFeature) + mitk::CoocurenceMatrixFeatures &meanFeature, + mitk::CoocurenceMatrixFeatures &stdFeature) { -#define ADDFEATURE(a) meanFeature.a += featureList[i].a;stdFeature.a += featureList[i].a*featureList[i].a +#define ADDFEATURE(a) \ + if ( ! (featureList[i].a == featureList[i].a)) featureList[i].a = 0; \ + meanFeature.a += featureList[i].a;stdFeature.a += featureList[i].a*featureList[i].a #define CALCVARIANCE(a) stdFeature.a =sqrt(stdFeature.a - meanFeature.a*meanFeature.a) for (std::size_t i = 0; i < featureList.size(); ++i) { ADDFEATURE(JointMaximum); ADDFEATURE(JointAverage); ADDFEATURE(JointVariance); ADDFEATURE(JointEntropy); ADDFEATURE(RowMaximum); ADDFEATURE(RowAverage); ADDFEATURE(RowVariance); ADDFEATURE(RowEntropy); ADDFEATURE(FirstRowColumnEntropy); ADDFEATURE(SecondRowColumnEntropy); ADDFEATURE(DifferenceAverage); ADDFEATURE(DifferenceVariance); ADDFEATURE(DifferenceEntropy); ADDFEATURE(SumAverage); ADDFEATURE(SumVariance); ADDFEATURE(SumEntropy); ADDFEATURE(AngularSecondMoment); ADDFEATURE(Contrast); ADDFEATURE(Dissimilarity); ADDFEATURE(InverseDifference); ADDFEATURE(InverseDifferenceNormalised); ADDFEATURE(InverseDifferenceMoment); ADDFEATURE(InverseDifferenceMomentNormalised); ADDFEATURE(InverseVariance); ADDFEATURE(Correlation); ADDFEATURE(Autocorrelation); ADDFEATURE(ClusterShade); ADDFEATURE(ClusterTendency); ADDFEATURE(ClusterProminence); ADDFEATURE(FirstMeasureOfInformationCorrelation); ADDFEATURE(SecondMeasureOfInformationCorrelation); } NormalizeMatrixFeature(meanFeature, featureList.size()); NormalizeMatrixFeature(stdFeature, featureList.size()); CALCVARIANCE(JointMaximum); CALCVARIANCE(JointAverage); CALCVARIANCE(JointVariance); CALCVARIANCE(JointEntropy); CALCVARIANCE(RowMaximum); CALCVARIANCE(RowAverage); CALCVARIANCE(RowVariance); CALCVARIANCE(RowEntropy); CALCVARIANCE(FirstRowColumnEntropy); CALCVARIANCE(SecondRowColumnEntropy); CALCVARIANCE(DifferenceAverage); CALCVARIANCE(DifferenceVariance); CALCVARIANCE(DifferenceEntropy); CALCVARIANCE(SumAverage); CALCVARIANCE(SumVariance); CALCVARIANCE(SumEntropy); CALCVARIANCE(AngularSecondMoment); CALCVARIANCE(Contrast); CALCVARIANCE(Dissimilarity); CALCVARIANCE(InverseDifference); CALCVARIANCE(InverseDifferenceNormalised); CALCVARIANCE(InverseDifferenceMoment); CALCVARIANCE(InverseDifferenceMomentNormalised); CALCVARIANCE(InverseVariance); CALCVARIANCE(Correlation); CALCVARIANCE(Autocorrelation); CALCVARIANCE(ClusterShade); CALCVARIANCE(ClusterTendency); CALCVARIANCE(ClusterProminence); CALCVARIANCE(FirstMeasureOfInformationCorrelation); CALCVARIANCE(SecondMeasureOfInformationCorrelation); #undef ADDFEATURE #undef CALCVARIANCE } static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number) { features.JointMaximum = features.JointMaximum / number; features.JointAverage = features.JointAverage / number; features.JointVariance = features.JointVariance / number; features.JointEntropy = features.JointEntropy / number; features.RowMaximum = features.RowMaximum / number; features.RowAverage = features.RowAverage / number; features.RowVariance = features.RowVariance / number; features.RowEntropy = features.RowEntropy / number; features.FirstRowColumnEntropy = features.FirstRowColumnEntropy / number; features.SecondRowColumnEntropy = features.SecondRowColumnEntropy / number; features.DifferenceAverage = features.DifferenceAverage / number; features.DifferenceVariance = features.DifferenceVariance / number; features.DifferenceEntropy = features.DifferenceEntropy / number; features.SumAverage = features.SumAverage / number; features.SumVariance = features.SumVariance / number; features.SumEntropy = features.SumEntropy / number; features.AngularSecondMoment = features.AngularSecondMoment / number; features.Contrast = features.Contrast / number; features.Dissimilarity = features.Dissimilarity / number; features.InverseDifference = features.InverseDifference / number; features.InverseDifferenceNormalised = features.InverseDifferenceNormalised / number; features.InverseDifferenceMoment = features.InverseDifferenceMoment / number; features.InverseDifferenceMomentNormalised = features.InverseDifferenceMomentNormalised / number; features.InverseVariance = features.InverseVariance / number; features.Correlation = features.Correlation / number; features.Autocorrelation = features.Autocorrelation / number; features.ClusterShade = features.ClusterShade / number; features.ClusterTendency = features.ClusterTendency / number; features.ClusterProminence = features.ClusterProminence / number; features.FirstMeasureOfInformationCorrelation = features.FirstMeasureOfInformationCorrelation / number; features.SecondMeasureOfInformationCorrelation = features.SecondMeasureOfInformationCorrelation / number; } mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2(): m_Range(1.0) { SetShortName("cooc2"); SetLongName("cooccurence2"); SetFeatureClassName("Co-occurenced Based Features"); } mitk::GIFCooccurenceMatrix2::FeatureListType mitk::GIFCooccurenceMatrix2::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { InitializeQuantifier(image, mask); FeatureListType featureList; GIFCooccurenceMatrix2Configuration config; config.direction = GetDirection(); config.range = m_Range; config.MinimumIntensity = GetQuantifier()->GetMinimum(); config.MaximumIntensity = GetQuantifier()->GetMaximum(); config.Bins = GetQuantifier()->GetBins(); config.prefix = FeatureDescriptionPrefix(); AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList,config); return featureList; } mitk::GIFCooccurenceMatrix2::FeatureNameListType mitk::GIFCooccurenceMatrix2::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFCooccurenceMatrix2::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Co-occurence matrix", "calculates Co-occurence based features (new implementation)", us::Any()); parser.addArgument(name+"::range", name+"::range", mitkCommandLineParser::String, "Cooc 2 Range", "Define the range that is used (Semicolon-separated)", us::Any()); AddQuantifierArguments(parser); } void mitk::GIFCooccurenceMatrix2::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); std::string name = GetOptionPrefix(); if (parsedArgs.count(GetLongName())) { InitializeQuantifierFromParameters(feature, maskNoNAN); std::vector ranges; if (parsedArgs.count(name + "::range")) { ranges = SplitDouble(parsedArgs[name + "::range"].ToString(), ';'); } else { ranges.push_back(1); } for (std::size_t i = 0; i < ranges.size(); ++i) { MITK_INFO << "Start calculating coocurence with range " << ranges[i] << "...."; this->SetRange(ranges[i]); auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating coocurence with range " << ranges[i] << "...."; } } } std::string mitk::GIFCooccurenceMatrix2::GetCurrentFeatureEncoding() { std::ostringstream ss; ss << m_Range; std::string strRange = ss.str(); return QuantifierParameterString() + "_Range-" + ss.str(); } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp index 38f3a7ad77..e7489a5c08 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp @@ -1,357 +1,359 @@ /*=================================================================== 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 // MITK #include #include #include // ITK #include #include #include // STL #include struct FirstOrderNumericParameterStruct { mitk::IntensityQuantifier::Pointer quantifier; double MinimumIntensity; double MaximumIntensity; int Bins; std::string prefix; }; template void CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFFirstOrderNumericStatistics::FeatureListType & featureList, FirstOrderNumericParameterStruct params) { typedef itk::Image ImageType; typedef itk::Image MaskType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); // // Calculate the Volume of Voxel (Maximum to the 3th order) // double voxelVolume = 1; for (unsigned int i = 0; i < std::min(3, VImageDimension); ++i) voxelVolume *= itkImage->GetSpacing()[i]; // // Calculate the Hypervolume of Voxel // double voxelSpace = 1; for (unsigned int i = 0; i < VImageDimension; ++i) voxelSpace *= itkImage->GetSpacing()[i]; unsigned int numberOfBins = params.quantifier->GetBins(); std::vector histogram; histogram.resize(numberOfBins, 0); double minimum = std::numeric_limits::max(); double maximum = std::numeric_limits::lowest(); double absoluteMinimum = std::numeric_limits::max(); double absoluteMaximum = std::numeric_limits::lowest(); double sum = 0; double sumTwo= 0; double sumThree = 0; unsigned int numberOfVoxels = 0; itk::ImageRegionIterator imageIter(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionIterator maskIter(maskImage, maskImage->GetLargestPossibleRegion()); while (!imageIter.IsAtEnd()) { double value = imageIter.Get(); absoluteMinimum = std::min(minimum, value); absoluteMaximum = std::max(maximum, value); if (maskIter.Get() > 0) { minimum = std::min(minimum, value); maximum = std::max(maximum, value); sum += value; sumTwo += value * value; sumThree += value * value*value; histogram[params.quantifier->IntensityToIndex(value)] += 1; ++numberOfVoxels; } ++maskIter; ++imageIter; } // // Histogram based calculations // unsigned int passedValues = 0; double doubleNoOfVoxes = numberOfVoxels; double median = 0; double lastIntensityWithValues = params.quantifier->IndexToMeanIntensity(0); std::size_t modeIdx = 0; double entropy = 0; double uniformity = 0; std::vector percentiles; percentiles.resize(20, 0); for (std::size_t idx = 0; idx < histogram.size(); ++idx) { unsigned int actualValues = histogram[idx]; for (std::size_t percentileIdx = 0; percentileIdx < percentiles.size(); ++percentileIdx) { double threshold = doubleNoOfVoxes * (percentileIdx + 1) *1.0 / (percentiles.size()); if ((passedValues < threshold) & ((passedValues + actualValues) >= threshold)) { // Lower Bound if (passedValues == std::floor(threshold)) { percentiles[percentileIdx] = 0.5*(lastIntensityWithValues + params.quantifier->IndexToMeanIntensity(idx)); } else { percentiles[percentileIdx] = params.quantifier->IndexToMeanIntensity(idx); } } } if ((passedValues < doubleNoOfVoxes * 0.5) & ((passedValues + actualValues) >= doubleNoOfVoxes * 0.5)) { // Lower Bound if (passedValues == std::floor(doubleNoOfVoxes * 0.5)) { median = 0.5*(lastIntensityWithValues + params.quantifier->IndexToMeanIntensity(idx)); } else { median = params.quantifier->IndexToMeanIntensity(idx); } } if (actualValues > histogram[modeIdx]) { modeIdx = idx; } if (actualValues > 0) { lastIntensityWithValues = params.quantifier->IndexToMeanIntensity(idx); double currentProbability = actualValues / (1.0 *numberOfVoxels); uniformity += currentProbability * currentProbability; entropy += currentProbability * std::log(currentProbability) / std::log(2); } passedValues += actualValues; } double p10 = percentiles[1]; - double p25idx = params.quantifier->IntensityToIndex(percentiles[4]); - double p75idx = params.quantifier->IntensityToIndex(percentiles[14]); + //double p25idx = params.quantifier->IntensityToIndex(percentiles[4]); + //double p75idx = params.quantifier->IntensityToIndex(percentiles[14]); + double p25idx = percentiles[4]; + double p75idx = percentiles[14]; double p90 = percentiles[17]; double mean = sum / (numberOfVoxels); double variance = sumTwo / (numberOfVoxels) - (mean*mean); double energy = sumTwo; double rootMeanSquare = std::sqrt(sumTwo / numberOfVoxels); double sumAbsoluteDistanceToMean = 0; double sumAbsoluteDistanceToMedian = 0; double sumRobust = 0; double sumRobustSquare = 0; double sumRobustAbsolulteDistanceToMean = 0; double sumValueMinusMean = 0; double sumValueMinusMeanThree = 0; double sumValueMinusMeanFour = 0; unsigned int numberOfRobustVoxel = 0; maskIter.GoToBegin(); imageIter.GoToBegin(); while (!imageIter.IsAtEnd()) { if (maskIter.Get() > 0) { double value = imageIter.Get(); double valueMinusMean = value - mean; sumAbsoluteDistanceToMean += std::abs(valueMinusMean); sumAbsoluteDistanceToMedian += std::abs(value - median); sumValueMinusMean += valueMinusMean; sumValueMinusMeanThree += valueMinusMean * valueMinusMean * valueMinusMean; sumValueMinusMeanFour += valueMinusMean * valueMinusMean * valueMinusMean * valueMinusMean; if ((p10 <= value) & (value <= p90)) { sumRobust += value; sumRobustSquare += value * value; ++numberOfRobustVoxel; } } ++maskIter; ++imageIter; } double robustMean = sumRobust / numberOfRobustVoxel; double robustVariance = sumRobustSquare / numberOfRobustVoxel - (robustMean * robustMean); maskIter.GoToBegin(); imageIter.GoToBegin(); while (!imageIter.IsAtEnd()) { if (maskIter.Get() > 0) { double value = imageIter.Get(); if ((p10 <= value) & (value <= p90)) { sumRobustAbsolulteDistanceToMean += std::abs(value - robustMean); } } ++maskIter; ++imageIter; } double meanAbsoluteDeviation = sumAbsoluteDistanceToMean / numberOfVoxels; double medianAbsoluteDeviation = sumAbsoluteDistanceToMedian / numberOfVoxels; double robustMeanAbsoluteDeviation = sumRobustAbsolulteDistanceToMean / numberOfRobustVoxel; double skewness = sumValueMinusMeanThree / numberOfVoxels / variance / std::sqrt(variance); double kurtosis = sumValueMinusMeanFour / numberOfVoxels / variance / variance; double interquantileRange = p75idx - p25idx; double coefficientOfVariation = std::sqrt(variance) / mean; - double quantileCoefficientOfDispersion = (p75idx - p25idx) / (p75idx + p25idx + 2); + double quantileCoefficientOfDispersion = (p75idx - p25idx) / (p75idx + p25idx); double coveredImageRange = (maximum - minimum)/ (absoluteMaximum - absoluteMinimum) ; featureList.push_back(std::make_pair(params.prefix + "Mean", mean)); featureList.push_back(std::make_pair(params.prefix + "Variance", variance)); featureList.push_back(std::make_pair(params.prefix + "Skewness", skewness)); featureList.push_back(std::make_pair(params.prefix + "Excess kurtosis", kurtosis-3)); featureList.push_back(std::make_pair(params.prefix + "Median", median)); featureList.push_back(std::make_pair(params.prefix + "Minimum", minimum)); featureList.push_back(std::make_pair(params.prefix + "05th Percentile", percentiles[0])); featureList.push_back(std::make_pair(params.prefix + "10th Percentile", percentiles[1])); featureList.push_back(std::make_pair(params.prefix + "15th Percentile", percentiles[2])); featureList.push_back(std::make_pair(params.prefix + "20th Percentile", percentiles[3])); featureList.push_back(std::make_pair(params.prefix + "25th Percentile", percentiles[4])); featureList.push_back(std::make_pair(params.prefix + "30th Percentile", percentiles[5])); featureList.push_back(std::make_pair(params.prefix + "35th Percentile", percentiles[6])); featureList.push_back(std::make_pair(params.prefix + "40th Percentile", percentiles[7])); featureList.push_back(std::make_pair(params.prefix + "45th Percentile", percentiles[8])); featureList.push_back(std::make_pair(params.prefix + "50th Percentile", percentiles[9])); featureList.push_back(std::make_pair(params.prefix + "55th Percentile", percentiles[10])); featureList.push_back(std::make_pair(params.prefix + "60th Percentile", percentiles[11])); featureList.push_back(std::make_pair(params.prefix + "65th Percentile", percentiles[12])); featureList.push_back(std::make_pair(params.prefix + "70th Percentile", percentiles[13])); featureList.push_back(std::make_pair(params.prefix + "75th Percentile", percentiles[14])); featureList.push_back(std::make_pair(params.prefix + "80th Percentile", percentiles[15])); featureList.push_back(std::make_pair(params.prefix + "85th Percentile", percentiles[16])); featureList.push_back(std::make_pair(params.prefix + "90th Percentile", percentiles[17])); featureList.push_back(std::make_pair(params.prefix + "95th Percentile", percentiles[18])); featureList.push_back(std::make_pair(params.prefix + "Maximum", maximum)); featureList.push_back(std::make_pair(params.prefix + "Interquantile range", interquantileRange)); featureList.push_back(std::make_pair(params.prefix + "Range", maximum-minimum)); featureList.push_back(std::make_pair(params.prefix + "Mean absolute deviation", meanAbsoluteDeviation)); featureList.push_back(std::make_pair(params.prefix + "Robust mean absolute deviation", robustMeanAbsoluteDeviation)); featureList.push_back(std::make_pair(params.prefix + "Median absolute deviation", medianAbsoluteDeviation)); featureList.push_back(std::make_pair(params.prefix + "Coefficient of variation", coefficientOfVariation)); featureList.push_back(std::make_pair(params.prefix + "Quantile coefficient of dispersion", quantileCoefficientOfDispersion)); featureList.push_back(std::make_pair(params.prefix + "Energy", energy)); featureList.push_back(std::make_pair(params.prefix + "Root mean square", rootMeanSquare)); featureList.push_back(std::make_pair(params.prefix + "Standard Deviation", std::sqrt(variance))); featureList.push_back(std::make_pair(params.prefix + "Kurtosis", kurtosis)); featureList.push_back(std::make_pair(params.prefix + "Robust mean", robustMean)); featureList.push_back(std::make_pair(params.prefix + "Robust variance", robustVariance)); featureList.push_back(std::make_pair(params.prefix + "Covered image intensity range", coveredImageRange)); featureList.push_back(std::make_pair(params.prefix + "Mode index", modeIdx)); featureList.push_back(std::make_pair(params.prefix + "Mode value", params.quantifier->IndexToMeanIntensity(modeIdx))); featureList.push_back(std::make_pair(params.prefix + "Mode probability", histogram[modeIdx] / (1.0*numberOfVoxels))); featureList.push_back(std::make_pair(params.prefix + "Entropy", entropy)); featureList.push_back(std::make_pair(params.prefix + "Uniformtiy", uniformity)); featureList.push_back(std::make_pair(params.prefix + "Number of voxels", numberOfVoxels)); featureList.push_back(std::make_pair(params.prefix + "Sum of voxels", sum)); featureList.push_back(std::make_pair(params.prefix + "Voxel space", voxelSpace)); featureList.push_back(std::make_pair(params.prefix + "Voxel volume", voxelVolume)); featureList.push_back(std::make_pair(params.prefix + "Image Dimension", VImageDimension)); return; } mitk::GIFFirstOrderNumericStatistics::GIFFirstOrderNumericStatistics() { SetShortName("fon"); SetLongName("first-order-numeric"); SetFeatureClassName("First Order Numeric"); } mitk::GIFFirstOrderNumericStatistics::FeatureListType mitk::GIFFirstOrderNumericStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { InitializeQuantifier(image, mask); FeatureListType featureList; FirstOrderNumericParameterStruct params; params.quantifier = GetQuantifier(); params.MinimumIntensity = GetQuantifier()->GetMinimum(); params.MaximumIntensity = GetQuantifier()->GetMaximum(); params.Bins = GetQuantifier()->GetBins(); params.prefix = FeatureDescriptionPrefix(); AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, params); return featureList; } mitk::GIFFirstOrderNumericStatistics::FeatureNameListType mitk::GIFFirstOrderNumericStatistics::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFFirstOrderNumericStatistics::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use First Order Statistic (Numeric)", "calculates First Order Statistic (Numeric)", us::Any()); AddQuantifierArguments(parser); } void mitk::GIFFirstOrderNumericStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { InitializeQuantifierFromParameters(feature, maskNoNAN); MITK_INFO << "Start calculating first order features ...."; auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating first order features...."; } } std::string mitk::GIFFirstOrderNumericStatistics::GetCurrentFeatureEncoding() { return QuantifierParameterString(); } \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp index 0690a13369..706e45890e 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp @@ -1,201 +1,129 @@ /*=================================================================== 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 // MITK #include #include #include #include #include // ITK #include #include #include // STL #include struct GIFLocalIntensityParameter { double range; std::string prefix; }; template static void CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFLocalIntensity::FeatureListType & featureList, GIFLocalIntensityParameter params) { typedef itk::Image ImageType; typedef itk::Image MaskType; typename MaskType::Pointer itkMask = MaskType::New(); mitk::CastToItkImage(mask, itkMask); double range = params.range; - //double minimumSpacing = 1; - //typename ImageType::SizeType regionSize; - //int offset = std::ceil(range / minimumSpacing); - //regionSize.Fill(1); - //for (unsigned int i = 0; i < VImageDimension; ++i) - //{ - // minimumSpacing = itkImage->GetSpacing()[i]; - // offset = std::ceil(range / minimumSpacing); - // regionSize[i] = offset; - //} - - //itk::NeighborhoodIterator iter(regionSize, itkImage, itkImage->GetLargestPossibleRegion()); - //itk::NeighborhoodIterator iterMask(regionSize, itkMask, itkMask->GetLargestPossibleRegion()); - - //typename ImageType::PointType origin; - //typename ImageType::PointType localPoint; - //itk::Index index; - - //double tmpPeakValue; - //double globalPeakValue = 0; - //double localPeakValue = 0; - //TPixel localMaximum = 0; - - //std::vector vectorIsInRange; - //index = iter.GetIndex(); - //itkImage->TransformIndexToPhysicalPoint(index, origin); - //for (itk::SizeValueType i = 0; i < iter.Size(); ++i) - //{ - // itkImage->TransformIndexToPhysicalPoint(iter.GetIndex(i), localPoint); - // double dist = origin.EuclideanDistanceTo(localPoint); - // vectorIsInRange.push_back((dist < params.range)); - //} - - //int count = 0; - //bool inbounds = true; - - //iter.NeedToUseBoundaryConditionOff(); - //iterMask.NeedToUseBoundaryConditionOff(); - - //while (!iter.IsAtEnd()) - //{ - // if (iterMask.GetCenterPixel() > 0) - // { - // tmpPeakValue = 0; - // count = 0; - // for (itk::SizeValueType i = 0; i < iter.Size(); ++i) - // { - // if (vectorIsInRange[i] ) - // { - // if (iter.IndexInBounds(i)) - // { - // tmpPeakValue += iter.GetPixel(i); - // ++count; - // } - // } - // } - // tmpPeakValue /= count; - // globalPeakValue = std::max(tmpPeakValue, globalPeakValue); - // auto currentCenterPixelValue = iter.GetCenterPixel(); - // if (localMaximum == currentCenterPixelValue) - // { - // localPeakValue = std::max(tmpPeakValue,localPeakValue); - // } - // else if (localMaximum < currentCenterPixelValue) - // { - // localMaximum = currentCenterPixelValue; - // localPeakValue = tmpPeakValue; - // } - // } - // ++iterMask; - // ++iter; - //} typename itk::LocalIntensityFilter::Pointer filter = itk::LocalIntensityFilter::New(); filter->SetInput(itkImage); filter->SetMask(itkMask); filter->SetRange(range); filter->Update(); featureList.push_back(std::make_pair(params.prefix + "2. Local Intensity Peak", filter->GetLocalPeak())); featureList.push_back(std::make_pair(params.prefix + "2. Global Intensity Peak", filter->GetGlobalPeak())); } mitk::GIFLocalIntensity::GIFLocalIntensity() : m_Range(6.2) { SetLongName("local-intensity"); SetShortName("loci"); SetFeatureClassName("Local Intensity"); } mitk::GIFLocalIntensity::FeatureListType mitk::GIFLocalIntensity::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; if (image->GetDimension() < 3) { return featureList; } GIFLocalIntensityParameter params; params.range = GetRange(); params.prefix = FeatureDescriptionPrefix(); AccessByItk_3(image, CalculateIntensityPeak, mask, featureList, params); return featureList; } mitk::GIFLocalIntensity::FeatureNameListType mitk::GIFLocalIntensity::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFLocalIntensity::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Local Intensity", "calculates local intensity based features", us::Any()); parser.addArgument(name + "::range", name+"::range", mitkCommandLineParser::Float, "Range for the local intensity", "Give the range that should be used for the local intensity in mm", us::Any()); } void mitk::GIFLocalIntensity::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) { std::string name = GetOptionPrefix(); auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { if (parsedArgs.count(name + "::range")) { double range = us::any_cast(parsedArgs[name + "::range"]); this->SetRange(range); } MITK_INFO << "Start calculating local intensity features ...."; auto localResults = this->CalculateFeatures(feature, mask); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating local intensity features...."; } } std::string mitk::GIFLocalIntensity::GetCurrentFeatureEncoding() { std::ostringstream ss; ss << m_Range; std::string strRange = ss.str(); return "Range-" + ss.str(); } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp index 6458c7f8ac..9e184ae7db 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp @@ -1,529 +1,531 @@ /*=================================================================== 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 // MITK #include #include #include #include #include // ITK #include #include #include #include // VTK #include #include #include #include #include #include #include #include // STL #include #include // Eigen #include struct GIFVolumetricDensityStatisticsParameters { double volume; std::string prefix; }; template void CalculateVolumeDensityStatistic(itk::Image* itkImage, mitk::Image::Pointer mask, GIFVolumetricDensityStatisticsParameters params, mitk::GIFVolumetricDensityStatistics::FeatureListType & featureList) { typedef itk::Image ImageType; typedef itk::Image MaskType; double volume = params.volume; std::string prefix = params.prefix; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); itk::ImageRegionConstIteratorWithIndex imgA(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex imgB(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex maskA(maskImage, maskImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex maskB(maskImage, maskImage->GetLargestPossibleRegion()); double moranA = 0; double moranB = 0; double geary = 0; double Nv = 0; double w_ij = 0; double mean = 0; typename ImageType::PointType pointA; typename ImageType::PointType pointB; while (!imgA.IsAtEnd()) { if (maskA.Get() > 0) { Nv += 1; mean += imgA.Get(); } ++imgA; ++maskA; } mean /= Nv; imgA.GoToBegin(); maskA.GoToBegin(); while (!imgA.IsAtEnd()) { if (maskA.Get() > 0) { imgB.GoToBegin(); maskB.GoToBegin(); while (!imgB.IsAtEnd()) { if ((imgA.GetIndex() == imgB.GetIndex()) || (maskB.Get() < 1)) { ++imgB; ++maskB; continue; } itkImage->TransformIndexToPhysicalPoint(maskA.GetIndex(), pointA); itkImage->TransformIndexToPhysicalPoint(maskB.GetIndex(), pointB); double w = 1 / pointA.EuclideanDistanceTo(pointB); moranA += w*(imgA.Get() - mean)* (imgB.Get() - mean); geary += w * (imgA.Get() - imgB.Get()) * (imgA.Get() - imgB.Get()); w_ij += w; ++imgB; ++maskB; } moranB += (imgA.Get() - mean)* (imgA.Get() - mean); } ++imgA; ++maskA; } + MITK_INFO << "Volume: " << volume; + MITK_INFO << " Mean: " << mean; featureList.push_back(std::make_pair(prefix + "Volume integrated intensity", volume* mean)); featureList.push_back(std::make_pair(prefix + "Volume Moran's I index", Nv / w_ij * moranA / moranB)); featureList.push_back(std::make_pair(prefix + "Volume Geary's C measure", ( Nv -1 ) / 2 / w_ij * geary/ moranB)); } void calculateMOBB(vtkPointSet *pointset, double &volume, double &surface) { volume = std::numeric_limits::max(); for (int cellID = 0; cellID < pointset->GetNumberOfCells(); ++cellID) { auto cell = pointset->GetCell(cellID); for (int edgeID = 0; edgeID < 3; ++edgeID) { auto edge = cell->GetEdge(edgeID); double pA[3], pB[3]; double pAA[3], pBB[3]; vtkSmartPointer transform = vtkSmartPointer::New(); transform->PostMultiply(); pointset->GetPoint(edge->GetPointId(0), pA); pointset->GetPoint(edge->GetPointId(1), pB); double angleZ = std::atan2((- pA[2] + pB[2]) ,(pA[1] - pB[1])); angleZ *= 180 / vnl_math::pi; if (pA[2] == pB[2]) angleZ = 0; transform->RotateX(angleZ); transform->TransformPoint(pA, pAA); transform->TransformPoint(pB, pBB); double angleY = std::atan2((pAA[1] -pBB[1]) ,-(pAA[0] - pBB[0])); angleY *= 180 / vnl_math::pi; if (pAA[1] == pBB[1]) angleY = 0; transform->RotateZ(angleY); double p0[3]; pointset->GetPoint(edge->GetPointId(0), p0); double curMinX = std::numeric_limits::max(); double curMaxX = std::numeric_limits::lowest(); double curMinY = std::numeric_limits::max(); double curMaxY = std::numeric_limits::lowest(); double curMinZ = std::numeric_limits::max(); double curMaxZ = std::numeric_limits::lowest(); for (int pointID = 0; pointID < pointset->GetNumberOfPoints(); ++pointID) { double p[3]; double p2[3]; pointset->GetPoint(pointID, p); p[0] -= p0[0]; p[1] -= p0[1]; p[2] -= p0[2]; transform->TransformPoint(p, p2); curMinX = std::min(p2[0], curMinX); curMaxX = std::max(p2[0], curMaxX); curMinY = std::min(p2[1], curMinY); curMaxY = std::max(p2[1], curMaxY); curMinZ = std::min(p2[2], curMinZ); curMaxZ = std::max(p2[2], curMaxZ); } if ((curMaxX - curMinX)*(curMaxY - curMinY)*(curMaxZ - curMinZ) < volume) { volume = (curMaxX - curMinX)*(curMaxY - curMinY)*(curMaxZ - curMinZ); surface = (curMaxX - curMinX)*(curMaxX - curMinX) + (curMaxY - curMinY)*(curMaxY - curMinY) + (curMaxZ - curMinZ)*(curMaxZ - curMinZ); surface *= 2; } } } } void calculateMEE(vtkPointSet *pointset, double &vol, double &surf, double tolerance=0.0001) { // Inspired by https://github.com/smdabdoub/ProkaryMetrics/blob/master/calc/fitting.py int numberOfPoints = pointset->GetNumberOfPoints(); int dimension = 3; Eigen::MatrixXd points(3, numberOfPoints); Eigen::MatrixXd Q(3+1, numberOfPoints); double p[3]; std::cout << "Initialize Q " << std::endl; for (int i = 0; i < numberOfPoints; ++i) { pointset->GetPoint(i, p); points(0, i) = p[0]; points(1, i) = p[1]; points(2, i) = p[2]; Q(0, i) = p[0]; Q(1, i) = p[1]; Q(2, i) = p[2]; Q(3, i) = 1.0; } int count = 1; double error = 1; Eigen::VectorXd u_vector(numberOfPoints); u_vector.fill(1.0 / numberOfPoints); Eigen::DiagonalMatrix u = u_vector.asDiagonal(); Eigen::VectorXd ones(dimension + 1); ones.fill(1); Eigen::MatrixXd Ones = ones.asDiagonal(); // Khachiyan Algorithm while (error > tolerance) { auto Qt = Q.transpose(); Eigen::MatrixXd X = Q*u*Qt; Eigen::FullPivHouseholderQR qr(X); Eigen::MatrixXd Xi = qr.solve(Ones); Eigen::MatrixXd M = Qt * Xi * Q; double maximumValue = M(0, 0); int maximumPosition = 0; for (int i = 0; i < numberOfPoints; ++i) { if (maximumValue < M(i, i)) { maximumValue = M(i, i); maximumPosition = i; } } double stepsize = (maximumValue - dimension - 1) / ((dimension + 1) * (maximumValue - 1)); Eigen::DiagonalMatrix new_u = (1.0 - stepsize) * u; new_u.diagonal()[maximumPosition] = (new_u.diagonal())(maximumPosition) + stepsize; ++count; error = (new_u.diagonal() - u.diagonal()).norm(); u.diagonal() = new_u.diagonal(); } // U = u Eigen::MatrixXd Ai = points * u * points.transpose() - points * u *(points * u).transpose(); Eigen::FullPivHouseholderQR qr(Ai); Eigen::VectorXd ones2(dimension); ones2.fill(1); Eigen::MatrixXd Ones2 = ones2.asDiagonal(); Eigen::MatrixXd A = qr.solve(Ones2)*1.0/dimension; Eigen::JacobiSVD svd(A); double c = 1 / sqrt(svd.singularValues()[0]); double b = 1 / sqrt(svd.singularValues()[1]); double a = 1 / sqrt(svd.singularValues()[2]); double V = 4 * vnl_math::pi*a*b*c / 3; double ad_mvee= 0; double alpha = std::sqrt(1 - b*b / a / a); double beta = std::sqrt(1 - c*c / a / a); for (int i = 0; i < 20; ++i) { ad_mvee += 4 * vnl_math::pi*a*b*(alpha*alpha + beta*beta) / (2 * alpha*beta) * (std::pow(alpha*beta, i)) / (1 - 4 * i*i); } vol = V; surf = ad_mvee; } mitk::GIFVolumetricDensityStatistics::FeatureListType mitk::GIFVolumetricDensityStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; if (image->GetDimension() < 3) { return featureList; } std::string prefix = FeatureDescriptionPrefix(); vtkSmartPointer mesher = vtkSmartPointer::New(); vtkSmartPointer stats = vtkSmartPointer::New(); vtkSmartPointer stats2 = vtkSmartPointer::New(); mesher->SetInputData(mask->GetVtkImageData()); mesher->SetValue(0, 0.5); stats->SetInputConnection(mesher->GetOutputPort()); stats->Update(); vtkSmartPointer delaunay = vtkSmartPointer< vtkDelaunay3D >::New(); delaunay->SetInputConnection(mesher->GetOutputPort()); delaunay->SetAlpha(0); delaunay->Update(); vtkSmartPointer geometryFilter = vtkSmartPointer::New(); geometryFilter->SetInputConnection(delaunay->GetOutputPort()); geometryFilter->Update(); stats2->SetInputConnection(geometryFilter->GetOutputPort()); stats2->Update(); double vol_mvee; double surf_mvee; calculateMEE(mesher->GetOutput(), vol_mvee, surf_mvee); double vol_mobb; double surf_mobb; calculateMOBB(geometryFilter->GetOutput(), vol_mobb, surf_mobb); double pi = vnl_math::pi; double meshVolume = stats->GetVolume(); double meshSurf = stats->GetSurfaceArea(); GIFVolumetricDensityStatisticsParameters params; params.volume = meshVolume; params.prefix = prefix; AccessByItk_3(image, CalculateVolumeDensityStatistic, mask, params, featureList); //Calculate center of mass shift int xx = mask->GetDimensions()[0]; int yy = mask->GetDimensions()[1]; int zz = mask->GetDimensions()[2]; double xd = mask->GetGeometry()->GetSpacing()[0]; double yd = mask->GetGeometry()->GetSpacing()[1]; double zd = mask->GetGeometry()->GetSpacing()[2]; int minimumX=xx; int maximumX=0; int minimumY=yy; int maximumY=0; int minimumZ=zz; int maximumZ=0; vtkSmartPointer dataset1Arr = vtkSmartPointer::New(); vtkSmartPointer dataset2Arr = vtkSmartPointer::New(); vtkSmartPointer dataset3Arr = vtkSmartPointer::New(); dataset1Arr->SetNumberOfComponents(1); dataset2Arr->SetNumberOfComponents(1); dataset3Arr->SetNumberOfComponents(1); dataset1Arr->SetName("M1"); dataset2Arr->SetName("M2"); dataset3Arr->SetName("M3"); vtkSmartPointer dataset1ArrU = vtkSmartPointer::New(); vtkSmartPointer dataset2ArrU = vtkSmartPointer::New(); vtkSmartPointer dataset3ArrU = vtkSmartPointer::New(); dataset1ArrU->SetNumberOfComponents(1); dataset2ArrU->SetNumberOfComponents(1); dataset3ArrU->SetNumberOfComponents(1); dataset1ArrU->SetName("M1"); dataset2ArrU->SetName("M2"); dataset3ArrU->SetName("M3"); vtkSmartPointer points = vtkSmartPointer< vtkPoints >::New(); for (int x = 0; x < xx; x++) { for (int y = 0; y < yy; y++) { for (int z = 0; z < zz; z++) { itk::Image::IndexType index; index[0] = x; index[1] = y; index[2] = z; mitk::ScalarType pxImage; mitk::ScalarType pxMask; mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, image->GetChannelDescriptor().GetPixelType(), image, image->GetVolumeData(), index, pxImage, 0); mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, mask->GetChannelDescriptor().GetPixelType(), mask, mask->GetVolumeData(), index, pxMask, 0); //Check if voxel is contained in segmentation if (pxMask > 0) { minimumX = std::min(x, minimumX); minimumY = std::min(y, minimumY); minimumZ = std::min(z, minimumZ); maximumX = std::max(x, maximumX); maximumY = std::max(y, maximumY); maximumZ = std::max(z, maximumZ); points->InsertNextPoint(x*xd, y*yd, z*zd); if (pxImage == pxImage) { dataset1Arr->InsertNextValue(x*xd); dataset2Arr->InsertNextValue(y*yd); dataset3Arr->InsertNextValue(z*zd); } } } } } vtkSmartPointer datasetTable = vtkSmartPointer::New(); datasetTable->AddColumn(dataset1Arr); datasetTable->AddColumn(dataset2Arr); datasetTable->AddColumn(dataset3Arr); vtkSmartPointer pcaStatistics = vtkSmartPointer::New(); pcaStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, datasetTable); pcaStatistics->SetColumnStatus("M1", 1); pcaStatistics->SetColumnStatus("M2", 1); pcaStatistics->SetColumnStatus("M3", 1); pcaStatistics->RequestSelectedColumns(); pcaStatistics->SetDeriveOption(true); pcaStatistics->Update(); vtkSmartPointer eigenvalues = vtkSmartPointer::New(); pcaStatistics->GetEigenvalues(eigenvalues); std::vector eigen_val(3); eigen_val[2] = eigenvalues->GetValue(0); eigen_val[1] = eigenvalues->GetValue(1); eigen_val[0] = eigenvalues->GetValue(2); double major = 2*sqrt(eigen_val[2]); double minor = 2*sqrt(eigen_val[1]); double least = 2*sqrt(eigen_val[0]); double alpha = std::sqrt(1 - minor*minor / major / major); double beta = std::sqrt(1 - least*least / major / major); double a = (maximumX - minimumX+1) * xd; double b = (maximumY - minimumY+1) * yd; double c = (maximumZ - minimumZ+1) * zd; double vd_aabb = meshVolume / (a*b*c); double ad_aabb = meshSurf / (2 * a*b + 2 * a*c + 2 * b*c); double vd_aee = 3 * meshVolume / (4.0*pi*major*minor*least); double ad_aee = 0; for (int i = 0; i < 20; ++i) { ad_aee += 4 * pi*major*minor*(alpha*alpha + beta*beta) / (2 * alpha*beta) * (std::pow(alpha*beta, i)) / (1 - 4 * i*i); } ad_aee = meshSurf / ad_aee; double vd_ch = meshVolume / stats2->GetVolume(); double ad_ch = meshSurf / stats2->GetSurfaceArea(); featureList.push_back(std::make_pair(prefix + "Volume density axis-aligned bounding box", vd_aabb)); featureList.push_back(std::make_pair(prefix + "Surface density axis-aligned bounding box", ad_aabb)); featureList.push_back(std::make_pair(prefix + "Volume density oriented minimum bounding box", meshVolume / vol_mobb)); featureList.push_back(std::make_pair(prefix + "Surface density oriented minimum bounding box", meshSurf / surf_mobb)); featureList.push_back(std::make_pair(prefix + "Volume density approx. enclosing ellipsoid", vd_aee)); featureList.push_back(std::make_pair(prefix + "Surface density approx. enclosing ellipsoid", ad_aee)); featureList.push_back(std::make_pair(prefix + "Volume density approx. minimum volume enclosing ellipsoid", meshVolume / vol_mvee)); featureList.push_back(std::make_pair(prefix + "Surface density approx. minimum volume enclosing ellipsoid", meshSurf / surf_mvee)); featureList.push_back(std::make_pair(prefix + "Volume density convex hull", vd_ch)); featureList.push_back(std::make_pair(prefix + "Surface density convex hull", ad_ch)); return featureList; } mitk::GIFVolumetricDensityStatistics::GIFVolumetricDensityStatistics() { SetLongName("volume-density"); SetShortName("volden"); SetFeatureClassName("Morphological Density"); } mitk::GIFVolumetricDensityStatistics::FeatureNameListType mitk::GIFVolumetricDensityStatistics::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFVolumetricDensityStatistics::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Volume-Density Statistic", "calculates volume density based features", us::Any()); } void mitk::GIFVolumetricDensityStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) { auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { MITK_INFO << "Start calculating volumetric density features ...."; auto localResults = this->CalculateFeatures(feature, mask); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating volumetric density features...."; } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp index 7353fd353a..6f01814153 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp @@ -1,460 +1,470 @@ /*=================================================================== 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 // MITK #include #include #include #include #include // ITK #include #include // VTK #include #include #include #include #include #include // STL #include template void CalculateVolumeStatistic(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFVolumetricStatistics::FeatureListType & featureList, std::string prefix) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::LabelStatisticsImageFilter FilterType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); typename FilterType::Pointer labelStatisticsImageFilter = FilterType::New(); labelStatisticsImageFilter->SetInput( itkImage ); labelStatisticsImageFilter->SetLabelInput(maskImage); labelStatisticsImageFilter->Update(); double volume = labelStatisticsImageFilter->GetCount(1); double voxelVolume = 1; for (int i = 0; i < (int)(VImageDimension); ++i) { volume *= itkImage->GetSpacing()[i]; voxelVolume *= itkImage->GetSpacing()[i]; } featureList.push_back(std::make_pair(prefix + "Voxel Volume", voxelVolume)); featureList.push_back(std::make_pair(prefix + "Volume (voxel based)", volume)); } template void CalculateLargestDiameter(itk::Image* mask, mitk::Image::Pointer valueImage, mitk::GIFVolumetricStatistics::FeatureListType & featureList, std::string prefix) { typedef itk::Image ValueImageType; typename ValueImageType::Pointer itkValueImage = ValueImageType::New(); mitk::CastToItkImage(valueImage, itkValueImage); typedef itk::Image ImageType; typedef typename ImageType::PointType PointType; typename ImageType::SizeType radius; for (int i=0; i < (int)VImageDimension; ++i) radius[i] = 1; itk::NeighborhoodIterator iterator(radius, mask, mask->GetRequestedRegion()); itk::NeighborhoodIterator valueIter(radius, itkValueImage, itkValueImage->GetRequestedRegion()); std::vector borderPoints; unsigned int maskDimensionX = mask->GetLargestPossibleRegion().GetSize()[0]; unsigned int maskDimensionY = mask->GetLargestPossibleRegion().GetSize()[1]; unsigned int maskDimensionZ = mask->GetLargestPossibleRegion().GetSize()[2]; double maskVoxelSpacingX = mask->GetSpacing()[0]; double maskVoxelSpacingY = mask->GetSpacing()[1]; double maskVoxelSpacingZ = mask->GetSpacing()[2]; unsigned int maskMinimumX = maskDimensionX; unsigned int maskMaximumX = 0; unsigned int maskMinimumY = maskDimensionY; unsigned int maskMaximumY = 0; unsigned int maskMinimumZ = maskDimensionZ; unsigned int maskMaximumZ = 0; // // Calculate surface in different directions // double surface = 0; std::vector directionSurface; for (int i = 0; i < (int)(iterator.Size()); ++i) { auto offset = iterator.GetOffset(i); double deltaS = 1; int nonZeros = 0; for (unsigned int j = 0; j < VImageDimension; ++j) { if (offset[j] != 0 && nonZeros == 0) { for (unsigned int k = 0; k < VImageDimension; ++k) { if (k != j) deltaS *= mask->GetSpacing()[k]; } nonZeros++; } else if (offset[j] != 0) { deltaS = 0; } } if (nonZeros < 1) deltaS = 0; directionSurface.push_back(deltaS); } // // Prepare calulation of Centre of mass shift // PointType normalCenter(0); PointType normalCenterUncorrected(0); PointType weightedCenter(0); PointType currentPoint; int numberOfPoints = 0; int numberOfPointsUncorrected = 0; double sumOfPoints = 0; while(!iterator.IsAtEnd()) { if (iterator.GetCenterPixel() == 0) { ++iterator; ++valueIter; continue; } maskMinimumX = (maskMinimumX > iterator.GetIndex()[0]) ? iterator.GetIndex()[0] : maskMinimumX; maskMaximumX = (maskMaximumX < iterator.GetIndex()[0]) ? iterator.GetIndex()[0] : maskMaximumX; maskMinimumY = (maskMinimumY > iterator.GetIndex()[1]) ? iterator.GetIndex()[1] : maskMinimumY; maskMaximumY = (maskMaximumY < iterator.GetIndex()[1]) ? iterator.GetIndex()[1] : maskMaximumY; maskMinimumZ = (maskMinimumZ > iterator.GetIndex()[2]) ? iterator.GetIndex()[2] : maskMinimumZ; maskMaximumZ = (maskMaximumZ < iterator.GetIndex()[2]) ? iterator.GetIndex()[2] : maskMaximumZ; mask->TransformIndexToPhysicalPoint(iterator.GetIndex(), currentPoint); normalCenterUncorrected += currentPoint.GetVectorFromOrigin(); ++numberOfPointsUncorrected; double intensityValue = valueIter.GetCenterPixel(); if (intensityValue == intensityValue) { normalCenter += currentPoint.GetVectorFromOrigin(); weightedCenter += currentPoint.GetVectorFromOrigin() * intensityValue; sumOfPoints += intensityValue; ++numberOfPoints; } bool border = false; for (int i = 0; i < (int)(iterator.Size()); ++i) { if (iterator.GetPixel(i) == 0 || ( ! iterator.IndexInBounds(i))) { border = true; surface += directionSurface[i]; //break; } } if (border) { auto centerIndex = iterator.GetIndex(); PointType centerPoint; mask->TransformIndexToPhysicalPoint(centerIndex, centerPoint ); borderPoints.push_back(centerPoint); } ++iterator; ++valueIter; } auto normalCenterVector = normalCenter.GetVectorFromOrigin() / numberOfPoints; auto normalCenterVectorUncorrected = normalCenter.GetVectorFromOrigin() / numberOfPointsUncorrected; auto weightedCenterVector = weightedCenter.GetVectorFromOrigin() / sumOfPoints; auto differenceOfCentersUncorrected = (normalCenterVectorUncorrected - weightedCenterVector).GetNorm(); auto differenceOfCenters = (normalCenterVector - weightedCenterVector).GetNorm(); double longestDiameter = 0; unsigned long numberOfBorderPoints = borderPoints.size(); for (int i = 0; i < (int)numberOfBorderPoints; ++i) { auto point = borderPoints[i]; for (int j = i; j < (int)numberOfBorderPoints; ++j) { double newDiameter=point.EuclideanDistanceTo(borderPoints[j]); if (newDiameter > longestDiameter) longestDiameter = newDiameter; } } double boundingBoxVolume = maskVoxelSpacingX* (maskMaximumX - maskMinimumX) * maskVoxelSpacingY* (maskMaximumY - maskMinimumY) * maskVoxelSpacingZ* (maskMaximumZ - maskMinimumZ); featureList.push_back(std::make_pair(prefix + "Maximum 3D diameter", longestDiameter)); featureList.push_back(std::make_pair(prefix + "Surface (voxel based)", surface)); featureList.push_back(std::make_pair(prefix + "Centre of mass shift", differenceOfCenters)); featureList.push_back(std::make_pair(prefix + "Centre of mass shift (uncorrected)", differenceOfCentersUncorrected)); featureList.push_back(std::make_pair(prefix + "Bounding Box Volume", boundingBoxVolume)); } mitk::GIFVolumetricStatistics::GIFVolumetricStatistics() { SetLongName("volume"); SetShortName("vol"); SetFeatureClassName("Volumetric Features"); } mitk::GIFVolumetricStatistics::FeatureListType mitk::GIFVolumetricStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; if (image->GetDimension() < 3) { return featureList; } AccessByItk_3(image, CalculateVolumeStatistic, mask, featureList, FeatureDescriptionPrefix()); AccessByItk_3(mask, CalculateLargestDiameter, image, featureList, FeatureDescriptionPrefix()); vtkSmartPointer mesher = vtkSmartPointer::New(); vtkSmartPointer stats = vtkSmartPointer::New(); mesher->SetInputData(mask->GetVtkImageData()); mesher->SetValue(0, 0.5); stats->SetInputConnection(mesher->GetOutputPort()); stats->Update(); double pi = vnl_math::pi; double meshVolume = stats->GetVolume(); double meshSurf = stats->GetSurfaceArea(); double pixelVolume = featureList[1].second; double pixelSurface = featureList[3].second; MITK_INFO << "Surface: " << pixelSurface << " Volume: " << pixelVolume; double compactness1 = pixelVolume / (std::sqrt(pi) * std::pow(meshSurf, 2.0 / 3.0)); double compactness1Pixel = pixelVolume / (std::sqrt(pi) * std::pow(pixelSurface, 2.0 / 3.0)); //This is the definition used by Aertz. However, due to 2/3 this feature is not demensionless. Use compactness3 instead. double compactness2 = 36 * pi*pixelVolume*pixelVolume / meshSurf / meshSurf / meshSurf; + double compactness2MeshMesh = 36 * pi*meshVolume*meshVolume / meshSurf / meshSurf / meshSurf; double compactness2Pixel = 36 * pi*pixelVolume*pixelVolume / pixelSurface / pixelSurface / pixelSurface; double compactness3 = pixelVolume / (std::sqrt(pi) * std::pow(meshSurf, 3.0 / 2.0)); + double compactness3MeshMesh = meshVolume / (std::sqrt(pi) * std::pow(meshSurf, 3.0 / 2.0)); double compactness3Pixel = pixelVolume / (std::sqrt(pi) * std::pow(pixelSurface, 3.0 / 2.0)); double sphericity = std::pow(pi, 1 / 3.0) *std::pow(6 * pixelVolume, 2.0 / 3.0) / meshSurf; + double sphericityMesh = std::pow(pi, 1 / 3.0) *std::pow(6 * meshVolume, 2.0 / 3.0) / meshSurf; double sphericityPixel = std::pow(pi, 1 / 3.0) *std::pow(6 * pixelVolume, 2.0 / 3.0) / pixelSurface; double surfaceToVolume = meshSurf / meshVolume; double surfaceToVolumePixel = pixelSurface / pixelVolume; double sphericalDisproportion = meshSurf / 4 / pi / std::pow(3.0 / 4.0 / pi * pixelVolume, 2.0 / 3.0); + double sphericalDisproportionMesh = meshSurf / 4 / pi / std::pow(3.0 / 4.0 / pi * meshVolume, 2.0 / 3.0); double sphericalDisproportionPixel = pixelSurface / 4 / pi / std::pow(3.0 / 4.0 / pi * pixelVolume, 2.0 / 3.0); double asphericity = std::pow(1.0/compactness2, (1.0 / 3.0)) - 1; + double asphericityMesh = std::pow(1.0 / compactness2MeshMesh, (1.0 / 3.0)) - 1; double asphericityPixel = std::pow(1.0/compactness2Pixel, (1.0 / 3.0)) - 1; //Calculate center of mass shift int xx = mask->GetDimensions()[0]; int yy = mask->GetDimensions()[1]; int zz = mask->GetDimensions()[2]; double xd = mask->GetGeometry()->GetSpacing()[0]; double yd = mask->GetGeometry()->GetSpacing()[1]; double zd = mask->GetGeometry()->GetSpacing()[2]; vtkSmartPointer dataset1Arr = vtkSmartPointer::New(); vtkSmartPointer dataset2Arr = vtkSmartPointer::New(); vtkSmartPointer dataset3Arr = vtkSmartPointer::New(); dataset1Arr->SetNumberOfComponents(1); dataset2Arr->SetNumberOfComponents(1); dataset3Arr->SetNumberOfComponents(1); dataset1Arr->SetName("M1"); dataset2Arr->SetName("M2"); dataset3Arr->SetName("M3"); vtkSmartPointer dataset1ArrU = vtkSmartPointer::New(); vtkSmartPointer dataset2ArrU = vtkSmartPointer::New(); vtkSmartPointer dataset3ArrU = vtkSmartPointer::New(); dataset1ArrU->SetNumberOfComponents(1); dataset2ArrU->SetNumberOfComponents(1); dataset3ArrU->SetNumberOfComponents(1); dataset1ArrU->SetName("M1"); dataset2ArrU->SetName("M2"); dataset3ArrU->SetName("M3"); for (int x = 0; x < xx; x++) { for (int y = 0; y < yy; y++) { for (int z = 0; z < zz; z++) { itk::Image::IndexType index; index[0] = x; index[1] = y; index[2] = z; mitk::ScalarType pxImage; mitk::ScalarType pxMask; mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, image->GetChannelDescriptor().GetPixelType(), image, image->GetVolumeData(), index, pxImage, 0); mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, mask->GetChannelDescriptor().GetPixelType(), mask, mask->GetVolumeData(), index, pxMask, 0); //Check if voxel is contained in segmentation if (pxMask > 0) { dataset1ArrU->InsertNextValue(x*xd); dataset2ArrU->InsertNextValue(y*yd); dataset3ArrU->InsertNextValue(z*zd); if (pxImage == pxImage) { dataset1Arr->InsertNextValue(x*xd); dataset2Arr->InsertNextValue(y*yd); dataset3Arr->InsertNextValue(z*zd); } } } } } vtkSmartPointer datasetTable = vtkSmartPointer::New(); datasetTable->AddColumn(dataset1Arr); datasetTable->AddColumn(dataset2Arr); datasetTable->AddColumn(dataset3Arr); vtkSmartPointer datasetTableU = vtkSmartPointer::New(); datasetTableU->AddColumn(dataset1ArrU); datasetTableU->AddColumn(dataset2ArrU); datasetTableU->AddColumn(dataset3ArrU); vtkSmartPointer pcaStatistics = vtkSmartPointer::New(); pcaStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, datasetTable); pcaStatistics->SetColumnStatus("M1", 1); pcaStatistics->SetColumnStatus("M2", 1); pcaStatistics->SetColumnStatus("M3", 1); pcaStatistics->RequestSelectedColumns(); pcaStatistics->SetDeriveOption(true); pcaStatistics->Update(); vtkSmartPointer eigenvalues = vtkSmartPointer::New(); pcaStatistics->GetEigenvalues(eigenvalues); pcaStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, datasetTableU); pcaStatistics->Update(); vtkSmartPointer eigenvaluesU = vtkSmartPointer::New(); pcaStatistics->GetEigenvalues(eigenvaluesU); std::vector eigen_val(3); std::vector eigen_valUC(3); eigen_val[2] = eigenvalues->GetValue(0); eigen_val[1] = eigenvalues->GetValue(1); eigen_val[0] = eigenvalues->GetValue(2); eigen_valUC[2] = eigenvaluesU->GetValue(0); eigen_valUC[1] = eigenvaluesU->GetValue(1); eigen_valUC[0] = eigenvaluesU->GetValue(2); double major = 4*sqrt(eigen_val[2]); double minor = 4*sqrt(eigen_val[1]); double least = 4*sqrt(eigen_val[0]); double elongation = (major == 0) ? 0 : sqrt(eigen_val[1] / eigen_val[2]); double flatness = (major == 0) ? 0 : sqrt(eigen_val[0] / eigen_val[2]); double majorUC = 4*sqrt(eigen_valUC[2]); double minorUC = 4*sqrt(eigen_valUC[1]); double leastUC = 4*sqrt(eigen_valUC[0]); double elongationUC = majorUC == 0 ? 0 : sqrt(eigen_valUC[1] / eigen_valUC[2]); double flatnessUC = majorUC == 0 ? 0 : sqrt(eigen_valUC[0] / eigen_valUC[2]); std::string prefix = FeatureDescriptionPrefix(); featureList.push_back(std::make_pair(prefix + "Volume (mesh based)",meshVolume)); featureList.push_back(std::make_pair(prefix + "Surface (mesh based)",meshSurf)); featureList.push_back(std::make_pair(prefix + "Surface to volume ratio (mesh based)",surfaceToVolume)); featureList.push_back(std::make_pair(prefix + "Sphericity (mesh based)",sphericity)); + featureList.push_back(std::make_pair(prefix + "Sphericity (mesh, mesh based)", sphericityMesh)); featureList.push_back(std::make_pair(prefix + "Asphericity (mesh based)", asphericity)); + featureList.push_back(std::make_pair(prefix + "Asphericity (mesh, mesh based)", asphericityMesh)); featureList.push_back(std::make_pair(prefix + "Compactness 1 (mesh based)", compactness3)); featureList.push_back(std::make_pair(prefix + "Compactness 1 old (mesh based)" ,compactness1)); featureList.push_back(std::make_pair(prefix + "Compactness 2 (mesh based)",compactness2)); + featureList.push_back(std::make_pair(prefix + "Compactness 1 (mesh, mesh based)", compactness3MeshMesh)); + featureList.push_back(std::make_pair(prefix + "Compactness 2 (mesh, mesh based)", compactness2MeshMesh)); featureList.push_back(std::make_pair(prefix + "Spherical disproportion (mesh based)", sphericalDisproportion)); + featureList.push_back(std::make_pair(prefix + "Spherical disproportion (mesh, mesh based)", sphericalDisproportionMesh)); featureList.push_back(std::make_pair(prefix + "Surface to volume ratio (voxel based)", surfaceToVolumePixel)); featureList.push_back(std::make_pair(prefix + "Sphericity (voxel based)", sphericityPixel)); featureList.push_back(std::make_pair(prefix + "Asphericity (voxel based)", asphericityPixel)); featureList.push_back(std::make_pair(prefix + "Compactness 1 (voxel based)", compactness3Pixel)); featureList.push_back(std::make_pair(prefix + "Compactness 1 old (voxel based)", compactness1Pixel)); featureList.push_back(std::make_pair(prefix + "Compactness 2 (voxel based)", compactness2Pixel)); featureList.push_back(std::make_pair(prefix + "Spherical disproportion (voxel based)", sphericalDisproportionPixel)); featureList.push_back(std::make_pair(prefix + "PCA Major axis length",major)); featureList.push_back(std::make_pair(prefix + "PCA Minor axis length",minor)); featureList.push_back(std::make_pair(prefix + "PCA Least axis length",least)); featureList.push_back(std::make_pair(prefix + "PCA Elongation",elongation)); featureList.push_back(std::make_pair(prefix + "PCA Flatness",flatness)); featureList.push_back(std::make_pair(prefix + "PCA Major axis length (uncorrected)", majorUC)); featureList.push_back(std::make_pair(prefix + "PCA Minor axis length (uncorrected)", minorUC)); featureList.push_back(std::make_pair(prefix + "PCA Least axis length (uncorrected)", leastUC)); featureList.push_back(std::make_pair(prefix + "PCA Elongation (uncorrected)", elongationUC)); featureList.push_back(std::make_pair(prefix + "PCA Flatness (uncorrected)", flatnessUC)); return featureList; } mitk::GIFVolumetricStatistics::FeatureNameListType mitk::GIFVolumetricStatistics::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFVolumetricStatistics::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Volume-Statistic", "calculates volume based features", us::Any()); } void mitk::GIFVolumetricStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) { auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { MITK_INFO << "Start calculating Volumetric Features::...."; auto localResults = this->CalculateFeatures(feature, mask); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating volumetric features...."; } } diff --git a/Modules/CommandLine/include/mitkCommandLineParser.h b/Modules/CommandLine/include/mitkCommandLineParser.h index 19bcef273f..bcd8dc2605 100644 --- a/Modules/CommandLine/include/mitkCommandLineParser.h +++ b/Modules/CommandLine/include/mitkCommandLineParser.h @@ -1,382 +1,391 @@ /*=================================================================== 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. ===================================================================*/ /*========================================================================= Library: CTK Copyright (c) Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.txt Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =========================================================================*/ #ifndef __mitkCommandLineParser_h #define __mitkCommandLineParser_h #include #include #include #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4251) #endif /** * * The MITK command line parser, based on the CTK command line parser. * * Use this class to add information about the command line arguments * your program understands and to easily parse them from a given list * of strings. * * This parser provides the following features: * *
    *
  • Add arguments by supplying a long name and/or a short name. * Arguments are validated using a regular expression. They can have * a default value and a help string.
  • *
  • Deprecated arguments.
  • *
  • Custom regular expressions for argument validation.
  • *
  • Set different argument name prefixes for native platform look and feel.
  • *
  • Create a help text for the command line arguments with support for * grouping arguments.
  • *
* * The main difference between the MITK command line parser and the CTK command line * parser is that the former does not depend on Qt. Apart from that an image type was * added and XML output improved for automatic GUI generation. * * std::out is used for output to keep dependencies to a minimum. */ class MITKCOMMANDLINE_EXPORT mitkCommandLineParser { public: enum Type { String = 0, Bool = 1, StringList = 2, Int = 3, Float = 4, InputDirectory = 5, InputFile = 6, OutputDirectory = 7, OutputFile = 8, InputImage = 9 }; typedef std::vector StringContainerType; mitkCommandLineParser(); ~mitkCommandLineParser(); /** * Parse a given list of command line arguments. * * This method parses a list of string elements considering the known arguments * added by calls to addArgument(). If any one of the argument * values does not match the corresponding regular expression, * ok is set to false and an empty map object is returned. * * The keys in the returned map object correspond to the long argument string, * if it is not empty. Otherwise, the short argument string is used as key. The * us::Any values can safely be converted to the type specified in the * addArgument() method call. * * @param arguments A StringContainerType containing command line arguments. * @param ok A pointer to a boolean variable. Will be set to true * if all regular expressions matched, false otherwise. * @return A map object mapping the long argument (if empty, the short one) * to a us::Any containing the value. */ std::map parseArguments(const StringContainerType &arguments, bool *ok = nullptr); /** * Convenient method allowing to parse a given list of command line arguments. * @see parseArguments(const StringContainerType &, bool*) */ std::map parseArguments(int argc, char **argv, bool *ok = nullptr); /** * Returns a detailed error description if a call to parseArguments() * failed. * * @return The error description, empty if no error occured. * @see parseArguments(const StringContainerType&, bool*) */ std::string errorString() const; /** * This method returns all unparsed arguments, i.e. all arguments * for which no long or short name has been registered via a call * to addArgument(). * * @see addArgument() * * @return A list containing unparsed arguments. */ const StringContainerType &unparsedArguments() const; /** * Checks if the given argument has been added via a call * to addArgument(). * * @see addArgument() * * @param argument The argument to be checked. * @return true if the argument was added, false * otherwise. */ bool argumentAdded(const std::string &argument) const; /** * Checks if the given argument has been parsed successfully by a previous * call to parseArguments(). * * @param argument The argument to be checked. * @return true if the argument was parsed, false * otherwise. */ bool argumentParsed(const std::string &argument) const; /** * Adds a command line argument. An argument can have a long name * (like --long-argument-name), a short name (like -l), or both. The type * of the argument can be specified by using the type parameter. * The following types are supported: * * * * * * * * *
Type# of parametersDefault regular exprExample
us::Any::String1.*--test-string StringParameter
us::Any::Bool0does not apply--enable-something
us::Any::StringList-1.*--test-list string1 string2
us::Any::Int1-?[0-9]+--test-int -5
* * The regular expressions are used to validate the parameters of command line * arguments. You can restrict the valid set of parameters by calling * setExactMatchRegularExpression() for your argument. * * Optionally, a help string and a default value can be provided for the argument. If * the us::Any type of the default value does not match type, an * exception is thrown. Arguments with default values are always returned by * parseArguments(). * * You can also declare an argument deprecated, by setting deprecated * to true. Alternatively you can add a deprecated argument by calling * addDeprecatedArgument(). * * If the long or short argument has already been added, or if both are empty strings, * the method call has no effect. * * @param longarg The long argument name. * @param shortarg The short argument name. * @param type The argument type (see the list above for supported types). * @param argLabel The label of this argument, when auto generated interface is used. * @param argHelp A help string describing the argument. * @param defaultValue A default value for the argument. * @param ignoreRest All arguments after the current one will be ignored. * @param deprecated Declares the argument deprecated. * * @see setExactMatchRegularExpression() * @see addDeprecatedArgument() * @throws std::logic_error If the us::Any type of defaultValue * does not match type, a std::logic_error is thrown. */ void addArgument(const std::string &longarg, const std::string &shortarg, Type type, const std::string &argLabel, const std::string &argHelp = std::string(), const us::Any &defaultValue = us::Any(), bool optional = true, bool ignoreRest = false, bool deprecated = false); /** * Adds a deprecated command line argument. If a deprecated argument is provided * on the command line, argHelp is displayed in the console and * processing continues with the next argument. * * Deprecated arguments are grouped separately at the end of the help text * returned by helpText(). * * @param longarg The long argument name. * @param shortarg The short argument name. * @param argHelp A help string describing alternatives to the deprecated argument. */ void addDeprecatedArgument(const std::string &longarg, const std::string &shortarg, const std::string &argLabel, const std::string &argHelp); + + /** + * Returns the vector of current Command line Parameter + * + */ + std::vector < std::map > getArgumentList(); + /** * Sets a custom regular expression for validating argument parameters. The method * errorString() can be used the get the last error description. * * @param argument The previously added long or short argument name. * @param expression A regular expression which the arugment parameters must match. * @param exactMatchFailedMessage An error message explaining why the parameter did * not match. * * @return true if the argument was found and the regular expression was set, * false otherwise. * * @see errorString() */ bool setExactMatchRegularExpression(const std::string &argument, const std::string &expression, const std::string &exactMatchFailedMessage); /** * The field width for the argument names without the help text. * * @return The argument names field width in the help text. */ std::string::size_type fieldWidth() const; /** * Creates a help text containing properly formatted argument names and help strings * provided by calls to addArgument(). The arguments can be grouped by * using beginGroup() and endGroup(). * * @param charPad The padding character. * @return The formatted help text. */ std::string helpText() const; /** * Sets the argument prefix for long and short argument names. This can be used * to create native command line arguments without changing the calls to * addArgument(). For example on Unix-based systems, long argument * names start with "--" and short names with "-", while on Windows argument names * always start with "/". * * Note that all methods in mitkCommandLineParser which take an argument name * expect the name as it was supplied to addArgument. * * Example usage: * * \code * ctkCommandLineParser parser; * parser.setArgumentPrefix("--", "-"); * parser.addArgument("long-argument", "l", us::Any::String); * StringContainerType args; * args << "program name" << "--long-argument Hi"; * parser.parseArguments(args); * \endcode * * @param longPrefix The prefix for long argument names. * @param shortPrefix The prefix for short argument names. */ void setArgumentPrefix(const std::string &longPrefix, const std::string &shortPrefix); /** * Begins a new group for documenting arguments. All newly added arguments via * addArgument() will be put in the new group. You can close the * current group by calling endGroup() or be opening a new group. * * Note that groups cannot be nested and all arguments which do not belong to * a group will be listed at the top of the text created by helpText(). * * @param description The description of the group */ void beginGroup(const std::string &description); /** * Ends the current group. * * @see beginGroup(const std::string&) */ void endGroup(); /** * Can be used to teach the parser to stop parsing the arguments and return False when * an unknown argument is encountered. By default StrictMode is disabled. * * @see parseArguments(const StringContainerType &, bool*) */ void setStrictModeEnabled(bool strictMode); /** * Is used to generate an XML output for any commandline program. */ void generateXmlOutput(); /** * Is used to set the title of the auto generated interface. * * @param title The title of the app. */ void setTitle(std::string title); /** * Is used to set the contributor for the help view in the auto generated interface. * * @param contributor Contributor of the app. */ void setContributor(std::string contributor); /** * Is used to categorize the apps in the commandline module. * * @param category The category of the app. */ void setCategory(std::string category); /** * Is used as the help text in the auto generated interface. * * @param description A short description for the app. */ void setDescription(std::string description); /** * Is used to group several Parameters in one groupbox in the auto generated interface. * Default name is "Parameters", with the tooltip: "Groupbox containing parameters." * * To change the group of several arguments, call this method before the arguments are added. * * @param name The name of the groupbox. * @param tooltip The tooltip of the groupbox. */ void changeParameterGroup(std::string name, std::string tooltip); private: class ctkInternal; ctkInternal *Internal; std::string Title; std::string Contributor; std::string Category; std::string Description; std::string ParameterGroupName; std::string ParameterGroupDescription; }; + + #endif diff --git a/Modules/CommandLine/src/mitkCommandLineParser.cpp b/Modules/CommandLine/src/mitkCommandLineParser.cpp index 3e092e0ec7..b585980a0f 100644 --- a/Modules/CommandLine/src/mitkCommandLineParser.cpp +++ b/Modules/CommandLine/src/mitkCommandLineParser.cpp @@ -1,958 +1,989 @@ /*=================================================================== 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. ===================================================================*/ /*========================================================================= Library: CTK Copyright (c) Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.txt Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =========================================================================*/ // STL includes #include #include // MITK includes #include "mitkCommandLineParser.h" using namespace std; namespace { // -------------------------------------------------------------------------- class CommandLineParserArgumentDescription { public: CommandLineParserArgumentDescription(const string &longArg, const string &longArgPrefix, const string &shortArg, const string &shortArgPrefix, mitkCommandLineParser::Type type, const string &argHelp, const string &argLabel, const us::Any &defaultValue, bool ignoreRest, bool deprecated, bool optional, string &argGroup, string &groupDescription) : LongArg(longArg), LongArgPrefix(longArgPrefix), ShortArg(shortArg), ShortArgPrefix(shortArgPrefix), ArgHelp(argHelp), ArgLabel(argLabel), ArgGroup(argGroup), ArgGroupDescription(groupDescription), IgnoreRest(ignoreRest), NumberOfParametersToProcess(0), Deprecated(deprecated), Optional(optional), DefaultValue(defaultValue), Value(type), ValueType(type) { Value = defaultValue; switch (type) { case mitkCommandLineParser::String: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::Bool: { NumberOfParametersToProcess = 0; } break; case mitkCommandLineParser::StringList: { NumberOfParametersToProcess = -1; } break; case mitkCommandLineParser::Int: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::Float: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::OutputDirectory: case mitkCommandLineParser::InputDirectory: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::OutputFile: case mitkCommandLineParser::InputFile: { NumberOfParametersToProcess = 1; } break; case mitkCommandLineParser::InputImage: { NumberOfParametersToProcess = 1; } break; default: std::cout << "Type not supported: " << static_cast(type); } } ~CommandLineParserArgumentDescription() {} bool addParameter(const string &value); string helpText(); string LongArg; string LongArgPrefix; string ShortArg; string ShortArgPrefix; string ArgHelp; string ArgLabel; string ArgGroup; string ArgGroupDescription; bool IgnoreRest; int NumberOfParametersToProcess; bool Deprecated; bool Optional; us::Any DefaultValue; us::Any Value; mitkCommandLineParser::Type ValueType; }; // -------------------------------------------------------------------------- bool CommandLineParserArgumentDescription::addParameter(const string &value) { switch (ValueType) { case mitkCommandLineParser::String: { Value = value; } break; case mitkCommandLineParser::Bool: { if (value.compare("true") == 0) Value = true; else Value = false; } break; case mitkCommandLineParser::StringList: { try { mitkCommandLineParser::StringContainerType list = us::any_cast(Value); list.push_back(value); Value = list; } catch (...) { mitkCommandLineParser::StringContainerType list; list.push_back(value); Value = list; } } break; case mitkCommandLineParser::Int: { stringstream ss(value); int i; ss >> i; Value = i; } break; case mitkCommandLineParser::Float: { stringstream ss(value); float f; ss >> f; Value = f; } break; case mitkCommandLineParser::InputDirectory: case mitkCommandLineParser::OutputDirectory: { Value = value; } break; case mitkCommandLineParser::InputFile: case mitkCommandLineParser::InputImage: case mitkCommandLineParser::OutputFile: { Value = value; } break; default: return false; } return true; } // -------------------------------------------------------------------------- string CommandLineParserArgumentDescription::helpText() { string text; string shortAndLongArg; if (!this->ShortArg.empty()) { shortAndLongArg = " "; shortAndLongArg += this->ShortArgPrefix; shortAndLongArg += this->ShortArg; } if (!this->LongArg.empty()) { if (this->ShortArg.empty()) shortAndLongArg.append(" "); else shortAndLongArg.append(", "); shortAndLongArg += this->LongArgPrefix; shortAndLongArg += this->LongArg; } text = text + shortAndLongArg + ", " + this->ArgHelp; if (this->Optional) text += " (optional)"; if (!this->DefaultValue.Empty()) { text = text + ", (default: " + this->DefaultValue.ToString() + ")"; } text += "\n"; return text; } } // -------------------------------------------------------------------------- // ctkCommandLineParser::ctkInternal class // -------------------------------------------------------------------------- class mitkCommandLineParser::ctkInternal { public: ctkInternal() : Debug(false), FieldWidth(0), StrictMode(false) {} ~ctkInternal() {} CommandLineParserArgumentDescription *argumentDescription(const string &argument); vector ArgumentDescriptionList; map ArgNameToArgumentDescriptionMap; map> GroupToArgumentDescriptionListMap; StringContainerType UnparsedArguments; StringContainerType ProcessedArguments; string ErrorString; bool Debug; string::size_type FieldWidth; string LongPrefix; string ShortPrefix; string CurrentGroup; string DisableQSettingsLongArg; string DisableQSettingsShortArg; bool StrictMode; }; // -------------------------------------------------------------------------- // ctkCommandLineParser::ctkInternal methods // -------------------------------------------------------------------------- CommandLineParserArgumentDescription *mitkCommandLineParser::ctkInternal::argumentDescription(const string &argument) { string unprefixedArg = argument; if (!LongPrefix.empty() && argument.compare(0, LongPrefix.size(), LongPrefix) == 0) { // Case when (ShortPrefix + UnPrefixedArgument) matches LongPrefix if (argument == LongPrefix && !ShortPrefix.empty() && argument.compare(0, ShortPrefix.size(), ShortPrefix) == 0) { unprefixedArg = argument.substr(ShortPrefix.size(), argument.size()); } else { unprefixedArg = argument.substr(LongPrefix.size(), argument.size()); } } else if (!ShortPrefix.empty() && argument.compare(0, ShortPrefix.size(), ShortPrefix) == 0) { unprefixedArg = argument.substr(ShortPrefix.size(), argument.size()); } else if (!LongPrefix.empty() && !ShortPrefix.empty()) { return nullptr; } if (ArgNameToArgumentDescriptionMap.count(unprefixedArg)) { return this->ArgNameToArgumentDescriptionMap[unprefixedArg]; } return nullptr; } // -------------------------------------------------------------------------- // ctkCommandLineParser methods // -------------------------------------------------------------------------- mitkCommandLineParser::mitkCommandLineParser() { this->Internal = new ctkInternal(); this->Category = string(); this->Title = string(); this->Contributor = string(); this->Description = string(); this->ParameterGroupName = "Parameters"; this->ParameterGroupDescription = "Parameters"; } // -------------------------------------------------------------------------- mitkCommandLineParser::~mitkCommandLineParser() { delete this->Internal; } // -------------------------------------------------------------------------- map mitkCommandLineParser::parseArguments(const StringContainerType &arguments, bool *ok) { // Reset this->Internal->UnparsedArguments.clear(); this->Internal->ProcessedArguments.clear(); this->Internal->ErrorString.clear(); // foreach (CommandLineParserArgumentDescription* desc, this->Internal->ArgumentDescriptionList) for (unsigned int i = 0; i < Internal->ArgumentDescriptionList.size(); i++) { CommandLineParserArgumentDescription *desc = Internal->ArgumentDescriptionList.at(i); desc->Value = us::Any(desc->ValueType); if (!desc->DefaultValue.Empty()) { desc->Value = desc->DefaultValue; } } bool error = false; bool ignoreRest = false; CommandLineParserArgumentDescription *currentArgDesc = nullptr; vector parsedArgDescriptions; for (unsigned int i = 1; i < arguments.size(); ++i) { string argument = arguments.at(i); if (this->Internal->Debug) { std::cout << "Processing" << argument; } if (!argument.compare("--xml") || !argument.compare("-xml") || !argument.compare("--XML") || !argument.compare("-XML")) { this->generateXmlOutput(); return map(); } // should argument be ignored ? if (ignoreRest) { if (this->Internal->Debug) { std::cout << " Skipping: IgnoreRest flag was been set"; } this->Internal->UnparsedArguments.push_back(argument); continue; } // Skip if the argument does not start with the defined prefix if (!(argument.compare(0, Internal->LongPrefix.size(), Internal->LongPrefix) == 0 || argument.compare(0, Internal->ShortPrefix.size(), Internal->ShortPrefix) == 0)) { if (this->Internal->StrictMode) { this->Internal->ErrorString = "Unknown argument "; this->Internal->ErrorString += argument; error = true; break; } if (this->Internal->Debug) { std::cout << " Skipping: It does not start with the defined prefix"; } this->Internal->UnparsedArguments.push_back(argument); continue; } // Skip if argument has already been parsed ... bool alreadyProcessed = false; for (auto alreadyHandledArgument : Internal->ProcessedArguments) if (argument.compare(alreadyHandledArgument) == 0) { alreadyProcessed = true; break; } if (alreadyProcessed) { if (this->Internal->StrictMode) { this->Internal->ErrorString = "Argument "; this->Internal->ErrorString += argument; this->Internal->ErrorString += " already processed !"; error = true; break; } if (this->Internal->Debug) { std::cout << " Skipping: Already processed !"; } continue; } // Retrieve corresponding argument description currentArgDesc = this->Internal->argumentDescription(argument); // Is there a corresponding argument description ? if (currentArgDesc) { // If the argument is deprecated, print the help text but continue processing if (currentArgDesc->Deprecated) { std::cout << "Deprecated argument " << argument << ": " << currentArgDesc->ArgHelp; } else { parsedArgDescriptions.push_back(currentArgDesc); } this->Internal->ProcessedArguments.push_back(currentArgDesc->ShortArg); this->Internal->ProcessedArguments.push_back(currentArgDesc->LongArg); int numberOfParametersToProcess = currentArgDesc->NumberOfParametersToProcess; ignoreRest = currentArgDesc->IgnoreRest; if (this->Internal->Debug && ignoreRest) { std::cout << " IgnoreRest flag is True"; } // Is the number of parameters associated with the argument being processed known ? if (numberOfParametersToProcess == 0) { currentArgDesc->addParameter("true"); } else if (numberOfParametersToProcess > 0) { string missingParameterError = "Argument %1 has %2 value(s) associated whereas exacly %3 are expected."; for (int j = 1; j <= numberOfParametersToProcess; ++j) { if (i + j >= arguments.size()) { // this->Internal->ErrorString = // missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess); // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } if (ok) { *ok = false; } return map(); } string parameter = arguments.at(i + j); if (this->Internal->Debug) { std::cout << " Processing parameter" << j << ", value:" << parameter; } if (this->argumentAdded(parameter)) { // this->Internal->ErrorString = // missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess); // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } if (ok) { *ok = false; } return map(); } if (!currentArgDesc->addParameter(parameter)) { // this->Internal->ErrorString = string( // "Value(s) associated with argument %1 are incorrect. %2"). // arg(argument).arg(currentArgDesc->ExactMatchFailedMessage); // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } if (ok) { *ok = false; } return map(); } } // Update main loop increment i = i + numberOfParametersToProcess; } else if (numberOfParametersToProcess == -1) { if (this->Internal->Debug) { std::cout << " Proccessing StringList ..."; } int j = 1; while (j + i < arguments.size()) { if (this->argumentAdded(arguments.at(j + i))) { if (this->Internal->Debug) { std::cout << " No more parameter for" << argument; } break; } string parameter = arguments.at(j + i); if (parameter.compare(0, Internal->LongPrefix.size(), Internal->LongPrefix) == 0 || parameter.compare(0, Internal->ShortPrefix.size(), Internal->ShortPrefix) == 0) { j--; break; } if (this->Internal->Debug) { std::cout << " Processing parameter" << j << ", value:" << parameter; } if (!currentArgDesc->addParameter(parameter)) { // this->Internal->ErrorString = string( // "Value(s) associated with argument %1 are incorrect. %2"). // arg(argument).arg(currentArgDesc->ExactMatchFailedMessage); // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } if (ok) { *ok = false; } return map(); } j++; } // Update main loop increment i = i + j; } } else { if (this->Internal->StrictMode) { this->Internal->ErrorString = "Unknown argument "; this->Internal->ErrorString += argument; error = true; break; } if (this->Internal->Debug) { std::cout << " Skipping: Unknown argument"; } this->Internal->UnparsedArguments.push_back(argument); } } if (ok) { *ok = !error; } map parsedArguments; int obligatoryArgs = 0; vector::iterator it; for (it = Internal->ArgumentDescriptionList.begin(); it != Internal->ArgumentDescriptionList.end(); ++it) { CommandLineParserArgumentDescription *desc = *it; if (!desc->Optional) obligatoryArgs++; } int parsedObligatoryArgs = 0; for (it = parsedArgDescriptions.begin(); it != parsedArgDescriptions.end(); ++it) { CommandLineParserArgumentDescription *desc = *it; string key; if (!desc->LongArg.empty()) { key = desc->LongArg; } else { key = desc->ShortArg; } if (!desc->Optional) parsedObligatoryArgs++; std::pair elem; elem.first = key; elem.second = desc->Value; parsedArguments.insert(elem); } if (obligatoryArgs > parsedObligatoryArgs) { parsedArguments.clear(); cout << helpText(); } return parsedArguments; } // ------------------------------------------------------------------------- map mitkCommandLineParser::parseArguments(int argc, char **argv, bool *ok) { std::cout << "Running Command Line Utility *" << Title << "*" << std::endl; StringContainerType arguments; // Create a StringContainerType of arguments for (int i = 0; i < argc; ++i) arguments.push_back(argv[i]); return this->parseArguments(arguments, ok); } // ------------------------------------------------------------------------- string mitkCommandLineParser::errorString() const { return this->Internal->ErrorString; } // ------------------------------------------------------------------------- const mitkCommandLineParser::StringContainerType &mitkCommandLineParser::unparsedArguments() const { return this->Internal->UnparsedArguments; } // -------------------------------------------------------------------------- void mitkCommandLineParser::addArgument(const string &longarg, const string &shortarg, Type type, const string &argLabel, const string &argHelp, const us::Any &defaultValue, bool optional, bool ignoreRest, bool deprecated) { if (longarg.empty() && shortarg.empty()) { return; } /* Make sure it's not already added */ bool added = (this->Internal->ArgNameToArgumentDescriptionMap.count(longarg) != 0); if (added) { return; } added = (this->Internal->ArgNameToArgumentDescriptionMap.count(shortarg) != 0); if (added) { return; } auto argDesc = new CommandLineParserArgumentDescription(longarg, this->Internal->LongPrefix, shortarg, this->Internal->ShortPrefix, type, argHelp, argLabel, defaultValue, ignoreRest, deprecated, optional, ParameterGroupName, ParameterGroupDescription); std::string::size_type argWidth = 0; if (!longarg.empty()) { this->Internal->ArgNameToArgumentDescriptionMap[longarg] = argDesc; argWidth += longarg.size() + this->Internal->LongPrefix.size(); } if (!shortarg.empty()) { this->Internal->ArgNameToArgumentDescriptionMap[shortarg] = argDesc; argWidth += shortarg.size() + this->Internal->ShortPrefix.size() + 2; } argWidth += 5; // Set the field width for the arguments if (argWidth > this->Internal->FieldWidth) { this->Internal->FieldWidth = argWidth; } this->Internal->ArgumentDescriptionList.push_back(argDesc); this->Internal->GroupToArgumentDescriptionListMap[this->Internal->CurrentGroup].push_back(argDesc); } // -------------------------------------------------------------------------- void mitkCommandLineParser::addDeprecatedArgument(const string &longarg, const string &shortarg, const string &argLabel, const string &argHelp) { addArgument(longarg, shortarg, StringList, argLabel, argHelp, us::Any(), false, true, false); } +// -------------------------------------------------------------------------- +std::vector < std::map > mitkCommandLineParser::getArgumentList() +{ + std::vector < std::map > parameterList; + //for (CommandLineParserArgumentDescription* argument : this->Internal->ArgumentDescriptionList) + for (std::size_t i = 0; i< this->Internal->ArgumentDescriptionList.size(); ++i) + { + CommandLineParserArgumentDescription* argument = this->Internal->ArgumentDescriptionList[i]; + std::map tmpMap; + //tmpMap["helptext"] = us::Any(argument->helpText); + tmpMap["longarg"] = us::Any(argument->LongArg); + tmpMap["longargprefix"] = us::Any(argument->LongArgPrefix); + tmpMap["shortarg"] = us::Any(argument->ShortArg); + tmpMap["shortargprefix"] = us::Any(argument->ShortArgPrefix); + tmpMap["arghelp"] = us::Any(argument->ArgHelp); + tmpMap["arglabel"] = us::Any(argument->ArgLabel); + tmpMap["arggroup"] = us::Any(argument->ArgGroup); + tmpMap["arggroupdescription"] = us::Any(argument->ArgGroupDescription); + tmpMap["ignorerest"] = us::Any(argument->IgnoreRest); + tmpMap["numberofparameterstoprocess"] = us::Any(argument->NumberOfParametersToProcess); + tmpMap["deprecated"] = us::Any(argument->Deprecated); + tmpMap["optional"] = us::Any(argument->Optional); + tmpMap["defaultvalue"] = argument->DefaultValue; + tmpMap["value"] = argument->Value; + tmpMap["valuetype"] = us::Any(argument->ValueType); + parameterList.push_back(tmpMap); + } + return parameterList; +} + // -------------------------------------------------------------------------- std::string::size_type mitkCommandLineParser::fieldWidth() const { return this->Internal->FieldWidth; } // -------------------------------------------------------------------------- void mitkCommandLineParser::beginGroup(const string &description) { this->Internal->CurrentGroup = description; } // -------------------------------------------------------------------------- void mitkCommandLineParser::endGroup() { this->Internal->CurrentGroup.clear(); } // -------------------------------------------------------------------------- string mitkCommandLineParser::helpText() const { string text; vector deprecatedArgs; text = "Command Line Utility *" + Title + "* in Category *" + Category + "*\n"; text += Description + "\n"; text += Contributor + "\n\n"; text += "Use --xml to generate an XML description parsable as a CTK Command Line Module Plugin.\n"; // Loop over grouped argument descriptions map>::iterator it; for (it = Internal->GroupToArgumentDescriptionListMap.begin(); it != Internal->GroupToArgumentDescriptionListMap.end(); ++it) { if (!(*it).first.empty()) { text = text + "\n" + (*it).first + "\n"; } vector::iterator it2; for (it2 = (*it).second.begin(); it2 != (*it).second.end(); ++it2) { CommandLineParserArgumentDescription *argDesc = *it2; if (argDesc->Deprecated) { deprecatedArgs.push_back(argDesc); } else { text += argDesc->helpText(); } } } if (!deprecatedArgs.empty()) { text += "\nDeprecated arguments:\n"; vector::iterator it2; for (it2 = deprecatedArgs.begin(); it2 != deprecatedArgs.end(); ++it2) { CommandLineParserArgumentDescription *argDesc = *it2; text += argDesc->helpText(); } } return text; } // -------------------------------------------------------------------------- bool mitkCommandLineParser::argumentAdded(const string &argument) const { return (this->Internal->ArgNameToArgumentDescriptionMap.count(argument) != 0); } // -------------------------------------------------------------------------- bool mitkCommandLineParser::argumentParsed(const string &argument) const { for (unsigned int i = 0; i < Internal->ProcessedArguments.size(); i++) if (argument.compare(Internal->ProcessedArguments.at(i)) == 0) return true; return false; } // -------------------------------------------------------------------------- void mitkCommandLineParser::setArgumentPrefix(const string &longPrefix, const string &shortPrefix) { this->Internal->LongPrefix = longPrefix; this->Internal->ShortPrefix = shortPrefix; } // -------------------------------------------------------------------------- void mitkCommandLineParser::setStrictModeEnabled(bool strictMode) { this->Internal->StrictMode = strictMode; } + void mitkCommandLineParser::generateXmlOutput() { std::stringstream xml; xml << "" << endl; xml << "" << Category << "" << endl; xml << "" << Title << "" << endl; xml << "" << Description << "" << endl; xml << "" << Contributor << "" << endl; xml << "" << endl; std::vector::iterator it; std::string lastParameterGroup = ""; for (it = this->Internal->ArgumentDescriptionList.begin(); it != this->Internal->ArgumentDescriptionList.end(); it++) { std::string type; switch ((*it)->ValueType) { case mitkCommandLineParser::String: type = "string"; break; case mitkCommandLineParser::Bool: type = "boolean"; break; case mitkCommandLineParser::StringList: type = "string-vector"; break; case mitkCommandLineParser::Int: type = "integer"; break; case mitkCommandLineParser::Float: type = "float"; break; case mitkCommandLineParser::OutputDirectory: case mitkCommandLineParser::InputDirectory: type = "directory"; break; case mitkCommandLineParser::InputImage: type = "image"; break; case mitkCommandLineParser::OutputFile: case mitkCommandLineParser::InputFile: type = "file"; break; } if (lastParameterGroup.compare((*it)->ArgGroup)) { if (it != this->Internal->ArgumentDescriptionList.begin()) { xml << "" << endl; xml << "" << endl; } xml << "" << endl; xml << "" << (*it)->ArgGroupDescription << "" << endl; lastParameterGroup = (*it)->ArgGroup; } // Skip help item, as it's no use in GUI if ((*it)->ShortArg == "h") continue; xml << "<" << type << ">" << endl; xml << "" << (*it)->LongArg << "" << endl; xml << "" << (*it)->ArgHelp << "" << endl; xml << "" << endl; if (!(*it)->DefaultValue.Empty()) xml << "" << (*it)->DefaultValue.ToString() << "" << endl; xml << "" << (*it)->LongArg << "" << endl; xml << "" << (*it)->ShortArg << "" << endl; if ((*it)->ValueType == mitkCommandLineParser::InputDirectory || (*it)->ValueType == mitkCommandLineParser::InputFile || (*it)->ValueType == mitkCommandLineParser::InputImage) { xml << "input" << endl; } else if ((*it)->ValueType == mitkCommandLineParser::OutputDirectory || (*it)->ValueType == mitkCommandLineParser::OutputFile) { xml << "output" << endl; } xml << "" << endl; } xml << "" << endl; xml << "" << endl; cout << xml.str(); } void mitkCommandLineParser::setTitle(string title) { Title = title; } void mitkCommandLineParser::setContributor(string contributor) { Contributor = contributor; } void mitkCommandLineParser::setCategory(string category) { Category = category; } void mitkCommandLineParser::setDescription(string description) { Description = description; } void mitkCommandLineParser::changeParameterGroup(string name, string tooltip) { ParameterGroupName = name; ParameterGroupDescription = tooltip; } diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index 03f3de6e54..8d8d736c21 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,102 +1,103 @@ # Plug-ins must be ordered according to their dependencies set(MITK_PLUGINS org.blueberry.core.runtime:ON org.blueberry.core.expressions:OFF org.blueberry.core.commands:OFF org.blueberry.core.jobs:OFF org.blueberry.ui.qt:OFF org.blueberry.ui.qt.help:ON org.blueberry.ui.qt.log:ON org.blueberry.ui.qt.objectinspector:OFF #org.blueberry.test:ON #org.blueberry.uitest:ON #Testing/org.blueberry.core.runtime.tests:ON #Testing/org.blueberry.osgi.tests:ON org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.coreapplication:OFF org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON org.mitk.gui.qt.common.legacy:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.diffusionimagingapp:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF org.mitk.gui.qt.properties:ON org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicom:OFF org.mitk.gui.qt.dicominspector:OFF org.mitk.gui.qt.diffusionimaging:OFF org.mitk.gui.qt.diffusionimaging.connectomics:OFF org.mitk.gui.qt.diffusionimaging.denoising:OFF org.mitk.gui.qt.diffusionimaging.fiberfox:OFF org.mitk.gui.qt.diffusionimaging.fiberprocessing:OFF org.mitk.gui.qt.diffusionimaging.ivim:OFF org.mitk.gui.qt.diffusionimaging.odfpeaks:OFF org.mitk.gui.qt.diffusionimaging.partialvolume:OFF org.mitk.gui.qt.diffusionimaging.preprocessing:OFF org.mitk.gui.qt.diffusionimaging.reconstruction:OFF org.mitk.gui.qt.diffusionimaging.registration:OFF org.mitk.gui.qt.diffusionimaging.tbss:OFF org.mitk.gui.qt.diffusionimaging.tractography:OFF org.mitk.gui.qt.diffusionimaging.python:OFF org.mitk.gui.qt.dosevisualization:OFF org.mitk.gui.qt.geometrytools:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF org.mitk.gui.qt.lasercontrol:OFF org.mitk.gui.qt.openigtlink:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.viewnavigator:OFF org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.pointsetinteractionmultispectrum:OFF org.mitk.gui.qt.python:OFF org.mitk.gui.qt.remeshing:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.aicpregistration:OFF org.mitk.gui.qt.renderwindowmanager:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.tubegraph:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.photoacoustics.pausviewer:OFF org.mitk.gui.qt.photoacoustics.imageprocessing:OFF org.mitk.gui.qt.photoacoustics.simulation:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF org.mitk.gui.qt.eventrecorder:OFF org.mitk.gui.qt.xnat:OFF org.mitk.gui.qt.igt.app.echotrack:OFF org.mitk.gui.qt.spectrocamrecorder:OFF org.mitk.gui.qt.classificationsegmentation:OFF org.mitk.gui.qt.overlaymanager:OFF org.mitk.gui.qt.igt.app.hummelprotocolmeasurements:OFF org.mitk.gui.qt.multilabelsegmentation:OFF org.mitk.matchpoint.core.helper:OFF org.mitk.gui.qt.matchpoint.algorithm.browser:OFF org.mitk.gui.qt.matchpoint.algorithm.control:OFF org.mitk.gui.qt.matchpoint.algorithm.batch:OFF org.mitk.gui.qt.matchpoint.mapper:OFF org.mitk.gui.qt.matchpoint.framereg:OFF org.mitk.gui.qt.matchpoint.visualizer:OFF org.mitk.gui.qt.matchpoint.evaluator:OFF org.mitk.gui.qt.matchpoint.manipulator:OFF org.mitk.gui.qt.preprocessing.resampling:OFF + org.mitk.gui.qt.radiomics:OFF org.mitk.gui.qt.cest:OFF ) diff --git a/Plugins/org.mitk.gui.qt.radiomics/CMakeLists.txt b/Plugins/org.mitk.gui.qt.radiomics/CMakeLists.txt new file mode 100644 index 0000000000..5915ac4fcf --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/CMakeLists.txt @@ -0,0 +1,9 @@ + +project(org_mitk_gui_qt_radiomics) + +mitk_create_plugin( + EXPORT_DIRECTIVE RADIOMICS_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgetsExt MitkCLUtilities MitkBasicImageProcessing + PACKAGE_DEPENDS ITK|ITKMathematicalMorphology +) diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/QmitkDiffusionImagingPortalPage.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/QmitkDiffusionImagingPortalPage.dox new file mode 100644 index 0000000000..d2052b2ff2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/QmitkDiffusionImagingPortalPage.dox @@ -0,0 +1,48 @@ +/** +\page org_mitk_gui_qt_diffusionimaging MITK Diffusion + +\tableofcontents + +MITK Diffusion offers a selection of image analysis methods for dMRI processing. It encompasses the research of the Division of Medical Image Computing of the German Cancer Research Center (DKFZ). + +\section org_mitk_gui_qt_diffusionimagingComponents Components + +MITK Diffusion consists of multiple components with their own documentation: + +\subsection sub1 Data formats, import and export +\li \subpage QmitkDiffusionImagingDataImportPage + +\subsection sub2 Preprocessing and Reconstruction +\li \subpage org_mitk_views_diffusionpreprocessing +\li \subpage org_mitk_views_simpleregistrationview +\li \subpage org_mitk_views_headmotioncorrectionview +\li \subpage org_mitk_views_denoisingview +\li \subpage org_mitk_views_tensorreconstruction +\li \subpage org_mitk_views_qballreconstruction + +\subsection sub3 Visualization and Quantification +\li \subpage org_mitk_views_controlvisualizationpropertiesview +\li \subpage org_mitk_views_odfdetails +\li \subpage org_mitk_views_odfmaximaextraction +\li \subpage org_mitk_views_partialvolumeanalysisview +\li \subpage org_mitk_views_diffusionquantification +\li \subpage org_mitk_views_ivim + +\subsection sub4 Fiber Tractography +\li \subpage org_mitk_views_streamlinetracking +\li \subpage org_mitk_views_gibbstracking +\li \subpage org_mitk_views_mlbtview +\li \subpage org_mitk_views_fiberprocessing +\li \subpage org_mitk_views_fiberquantification +\li \subpage org_mitk_views_fiberfit +\li \subpage org_mitk_views_fiberclustering + +\subsection sub5 Fiberfox dMRI Simulation +\li \subpage org_mitk_views_fiberfoxview +\li \subpage org_mitk_views_fieldmapgenerator + +\subsection sub6 TBSS and Connectomics +\li \subpage org_mitk_views_tractbasedspatialstatistics +\li \subpage org_mitk_diffusionimagingapp_perspectives_connectomics + +*/ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/QmitkPhenotypingPortalPage.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/QmitkPhenotypingPortalPage.dox new file mode 100644 index 0000000000..9920021448 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/QmitkPhenotypingPortalPage.dox @@ -0,0 +1,36 @@ +/** +\page org_mitk_gui_qt_mitkphenotyping MITK Phenotyping + +\tableofcontents + +MITK Phenotyping is a selection of algorithms that can be used to extract image-based phenotypes, for example using a radiomics approach. The software is part of the research of the Division of Medical Image Computing of the German Cancer Research Center (DKFZ). MITK Phenotyping is not intended to be a single application, it is rather a collection of the necessary plugins within the offical MITK releases. + +The functionality of MITK Phenotyping can be accessed in different ways: Using the graphical interface using the Plugins listed below, using command line applications, or using one of the programming interfaces. + +\section org_mitk_gui_qt_mitkphenotyping_Tutorials Tutorials +\li \subpage org_mitk_views_radiomicstutorial_gui_portal A tutorial on how to use the grapical interface of MITK Phenotying + +\section org_mitk_gui_qt_mitkphenotyping_Views Views + +\subsection sub2 Specific Views: +Views that were developed with the main focus on Radiomics. They still might be used in other use-cases as well: +\li \subpage org_mitk_views_radiomicstransformationview : Image transformations like Resampling, Laplacian of Gaussian, and Wavelet Transformations +\li \subpage org_mitk_views_radiomicsmaskprocessingview : Processing and Cleaning of Masks +\li \subpage org_mitk_views_radiomicsarithmetricview : Processing images using mathematical operations +\li \subpage org_mitk_views_radiomicsstatisticview : Calculate Radiomics Features + +\subsection sub1 Non-Specific Views: +This section contains views that are included within MITK Phenotyping, but were developed with a broader application in mind. +\li \subpage org_mitk_views_basicimageprocessing : Deprecated plugin for performing different image-related tasks like subtraction, mutliplaction, filtering etc. +\li \subpage org_mitk_gui_qt_matchpoint_algorithm_browser : Selection of MatchPoint (Registration) Algorithm +\li \subpage org_mitk_gui_qt_matchpoint_algorithm_control : Configuring and Controlling MatchPoint (Registration) Algorithm +\li \subpage org_mitk_gui_qt_matchpoint_evaluator : Evaluate the Registration performance using MatchPoint +\li \subpage org_mitk_gui_qt_matchpoint_manipulator : Adapt a registration calculated using MatchPoint +\li \subpage org_mitk_gui_qt_matchpoint_mapper : Apply a MatchPoint Registration to a specific image +\li \subpage org_mitk_gui_qt_matchpoint_visualizer : Visualize a Registration obtained with MatchPoint +\li \subpage org_mitk_gui_qt_matchpoint_algorithm_batch : Running MatchPoint over multiple images (BatchMode) +\li \subpage org_mitk_views_multilabelsegmentation : Create and editing of Multilabel-Segmentations. +\li \subpage org_mitk_views_segmentation : Create simple segmentations +\li \subpage org_mitk_views_segmentationutilities : Utilities for the processing of simple segmentations. + +*/ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/Data_CSD.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/Data_CSD.png new file mode 100644 index 0000000000..1eb60c1707 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/Data_CSD.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/Data_Tensors.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/Data_Tensors.png new file mode 100644 index 0000000000..7f42f2108a Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/Data_Tensors.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkBasicImageProcessing.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkBasicImageProcessing.dox new file mode 100644 index 0000000000..bff25497fa --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkBasicImageProcessing.dox @@ -0,0 +1,126 @@ +/** +\page org_mitk_views_basicimageprocessing The Basic Image Processing Plugin + +\imageMacro{QmitkBasicImageProcessing_ImageProcessing_48.png,"Icon of the Basic Image Processing Plugin",2.00} + +\tableofcontents + +\section QmitkBasicImageProcessingUserManualSummary Summary + +This view provides an easy interface to fundamental image preprocessing and enhancement filters. +It offers filter operations on 3D and 4D images in the areas of noise suppression, morphological operations, edge detection and image arithmetics, +as well as image inversion and downsampling. + +Please see \ref QmitkBasicImageProcessingUserManualOverview for more detailed information on usage and supported filters. +If you encounter problems using the view, please have a look at the \ref QmitkBasicImageProcessingUserManualTrouble page. + +\section QmitkBasicImageProcessingUserManualOverview Overview + +This view provides an easy interface to fundamental image preprocessing and image enhancement filters. +It offers a variety of filter operations in the areas of noise suppression, morphological operations, edge detection and image arithmetics. +Currently the view can be used with all 3D and 4D image types loadable by MITK. +2D image support will be added in the future. +All filters are encapsulated from the Insight Segmentation and Registration Toolkit (ITK, www.itk.org). + +\imageMacro{QmitkBasicImageProcessing_BIP_Overview.png,"MITK with the Basic Image Processing view",16.00} + +This document will tell you how to use this view, but it is assumed that you already know how to use MITK in general. + +\section QmitkBasicImageProcessingUserManualFilters Filters + +This section will not describe the fundamental functioning of the single filters in detail, though. +If you want to know more about a single filter, please have a look at http://www.itk.org/Doxygen316/html/classes.html +or in any good digital image processing book. For total denoising filter, please see Tony F. Chan et al., "The digital TV filter and nonlinear denoising". + +Available filters are: + +

\a Single image operations

+ +
    +
  • Noise Suppression
  • +
      +
    • Gaussian Denoising
    • +
    • Median Filtering
    • +
    • Total Variation Denoising
    • +
    + +
  • Morphological Operations
  • +
      +
    • Dilation
    • +
    • Erosion
    • +
    • Opening
    • +
    • Closing
    • +
    + +
  • %Edge Detection
  • +
      +
    • Gradient Image
    • +
    • Laplacian Operator (Second Derivative)
    • +
    • Sobel Operator
    • +
    + +
  • Misc
  • +
      +
    • Threshold
    • +
    • Image Inversion
    • +
    • Downsampling (isotropic)
    • +
    +
+ +

\a Dual image operations

+ +
    +
  • Image Arithmetics
  • +
      +
    • Add two images
    • +
    • Subtract two images
    • +
    • Multiply two images
    • +
    • Divide two images
    • +
    + +
  • Binary Operations
  • +
      +
    • Logical AND
    • +
    • Logical OR
    • +
    • Logical XOR
    • +
    +
+ +\section QmitkBasicImageProcessingUserManualUsage Usage + +All you have to do to use a filter is to: +
    +
  • Load an image into MITK
  • +
  • Select it in data manager +
  • Select which filter you want to use via the drop down list
  • +
  • Press the execute button
  • +
+A busy cursor appeares; when it vanishes, the operation is completed. Your filtered image is displayed and selected for further processing. +(If the checkbox "Hide original image" is not selected, you will maybe not see the filter result imideately, +because your filtered image is possibly hidden by the original.) + +For two image operations, please make sure that the correct second image is selected in the drop down menu, and the image order is correct. +For sure, image order only plays a role for image subtraction and division. These are conducted (Image1 - Image2) or (Image1 / Image2), respectively. + +Please Note: When you select a 4D image, you can select the time step for the filter to work on via the time slider at the top of the GUI. +The 3D image at this time step is extracted and processed. The result will also be a 3D image. +This means, a true 4D filtering is not yet supported. + +\section QmitkBasicImageProcessingUserManualTrouble Troubleshooting + +I get an error when using a filter on a 2D image.
+2D images are not yet supported... + +I use a filter on a 4D image, and the output is 3D.
+When you select a 4D image, you can select the time step for the filter to work on via the time slider at the top of the GUI. +The 3D image at this time step is extracted and processed. The result will also be a 3D image. +This means, a true 4D filtering is not supported by now. + +A filter crashes during execution.
+Maybe your image is too large. Some filter operations, like derivatives, take a lot of memory. +Try downsampling your image first. + +All other problems.
+Please report to the MITK mailing list. +See http://www.mitk.org/wiki/Mailinglist on how to do this. +*/ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkBasicImageProcessing_BIP_Overview.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkBasicImageProcessing_BIP_Overview.png new file mode 100644 index 0000000000..fc97b545a9 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkBasicImageProcessing_BIP_Overview.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkBasicImageProcessing_ImageProcessing_48.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkBasicImageProcessing_ImageProcessing_48.png new file mode 100644 index 0000000000..b0244a0320 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkBasicImageProcessing_ImageProcessing_48.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkDiffusionImagingAppUserManual.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkDiffusionImagingAppUserManual.dox new file mode 100644 index 0000000000..76d27ea5fd --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkDiffusionImagingAppUserManual.dox @@ -0,0 +1,8 @@ +/** +\page org_mitk_gui_qt_diffusionimagingapp What is the Diffusion Imaging Application + +MITK Diffusion offers a selection of image analysis methods for dMRI processing. It encompasses the research of the Division of Medical Image Computing of the German Cancer Research Center (DKFZ). + +For a detailed description of MITK Diffusion refer to \ref org_mitk_gui_qt_diffusionimaging . + +*/ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkDiffusionImagingDataImportPage.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkDiffusionImagingDataImportPage.dox new file mode 100644 index 0000000000..20f1b1a2f0 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkDiffusionImagingDataImportPage.dox @@ -0,0 +1,82 @@ +/** +\page QmitkDiffusionImagingDataImportPage Data formats, import and export + +MITK Diffusion supports many standard image formats such as NIFTI, NRRD and DICOM as well as common tractography file formats such as vtk/fib, trk, tck, and tractography DICOM. By including multiple tractography file formats native to other tools (e.g. 3D Slicer, MRtrix, DIPY), MITK Diffusion integrates seamlessly in complex workflows involving other tools. Additional file types such as spherical-harmonic coefficient files and voxel-wise fiber orientation or peak images are compliant with MRtrix. + +Data can be loaded using the open file dialog via the menu bar or by simply dragging and dropping the file into the data manager or one of data display windows. + +MITK Diffusion uses a left-posterior-superior coordinate system convention. Other toolkits, e.g. MRtrix, use an RAS coordinate system. This can cause flips for example of the complete tractogram or of the voxel-wise peaks or ODFs. MITK Diffusion implements mechanisms to deal with this by automatically catching and converting some cases and by providing the tools to manually correct for it, but it is important to keep this issue in mind and to perform the data processing in a corresponding thorough manner. + +\section DWI_format Diffusion-weighted Images + +This section describes the different file formats of raw diffusion-weighted images that are supported by MITK Diffusion. +General points: +\li MITK Diffusion internally applies the image rotation matrix to the diffusion-gradient vectors while loading the image. The original gradient directions are retained and used when saving the image again. + +\subsection dwi_nrrd NRRD (.nrrd/.dwi) + +NRRD (http://teem.sourceforge.net/nrrd/format.html) is the default file format for saving diffusion-weighted images with MITK Diffusion. The gradient and b-value information is directly stored in the file header. The image information is stored as a 3D vector image. Storing the file as .dwi or .nrrd is equivalent, only the file ending is different. Diffusion-weighted images are discerned from other images by the tag "modality:=DWMRI" in the NRRD image header. The gradient information is stored in the NRRD header in the following way: + +DWMRI_b-value:=1000.000000 + +DWMRI_gradient_0000:=0.000000 0.000000 0.000000 + +DWMRI_gradient_0001:=0.000000 0.000000 1.000000 + +DWMRI_gradient_0002:=-0.051773 0.252917 0.966102 + +... + +The b-value of the individual gradient directions is encoded via the squared norm of the respective vector. The tag "DWMRI_b-value" defines which b-value corresponds to a vector with norm 1. + +In some cases, dMRI NRRD files contain an additional "measurement frame" matrix, which specifies an additional rotation of the gradient vectors. This matrix is automatically applied when loading the file. The original gradient directions are retained and used when saving the image again. + +\subsection dwi_nifti NIFTI (.nii/.ni.gz) + +Diffusion-weighted images can be saved and loaded as NIFTI files (NIFTI-1 https://nifti.nimh.nih.gov/nifti-1). The gradient vector information is stored in to separate files for b-values (filename.bvals) and gradient vectors (filename.bvecs). When loading a nifti file (.nii or .nii.gz), MITK Diffusion looks for these two additional files (.bval/.bvals and .bvec/.bvecs) and if they are found, MITK will offer to load the image as diffusion-weighted image. In contrast to the NRRD format, all gradient vectors should have a length of 1. The b-values are stored explicietly in the .bval/.bvals file. When loaded into MITK, this information is again encoded into the gradient vectors, as it is done in the NRRD file format. + +\subsection dwi_dicom DICOM + +MITK is capable of importing diffusion-weighted DICOM images from GE, Siemens and Philips. Writing images is DICOM format is NOT supported! Mosaic images can be directly converted to regular images during import. To load a dMRI DICOM, simply drag and drop any file of the series into the application. + +\section special_format Special Image Types + +\subsection DTI_format Diffusion Tensor Images (.dti) + +The default format for diffusion tensor images in MITK Diffusion is a 3D NRRD file with a "3D-symmetric-matrix" pixel type. A tensor is encoded as 6 float values. The file ending for diffusion tensor files is .dti. +MITK Diffusion is also able to read NIFTI DTI files (6 or 9 component format), which are for example generated by the Camino multi tensor reconstruction. To be recognized as DTI files, the .nii or .nii.gz files have to be renamed to .dti. + +\subsection ODF_format ODF Images (.odf, .qbi (deprecated) ) + +MITK stores ODFs as 252 float values spherically sampled from the continuous ODF. The sampling directions are generate by a 5-fold subdivisions of an icosahedron. ODF images are stored in NRRD file format with the ending .odf. The image information is stored as a 3D vector image with a vector length of 252. + +The specific ODF sampling directions can be found here. + +\subsection sh_format Spherical Harmonics +Many applications in dMRI are using spherical harmonics to store spherical functions such as ODFs. MITK Diffusion stores these files as 3D vector images (NRRD format), where the vector components represent the SH coefficients. While this format is different from e.g. the MRtrix SH file format, MITK Diffusion can convert from MRtrix SH files to MITK Diffusion SH files. For historical reasons, the conversion tool is located in the \ref org_mitk_views_odfmaximaextraction view. Simply load the MRtrix SH image, select it in the data manager, select the "MRtrix" spherical harmonics convention and click "Start SH Coefficient Import". + +\subsection peak_format Peak Images (.nii, .nii.gz, .nrrd) + +MITK Diffusion stores peak images, resulting for example from an ODF maxima extraction, as 4D float images. The peak vector components are stored in the 4th dimension, therefore dimension 4 always contains a multiple of 3 entries. This format is the same as the format used by MRtrix. + +\section Tract_format Tractography Formats + +MITK Diffusion supports multiple formats for tractography files that are commonly used in the dMRI community. As in all other toolkits, the fiber point coordinates are stored as physical/world coordinates without any additional transformation. + +\subsection tract_vtk VTK (.vtk/.fib) + +The default format for tractograms is VTK (vtkPolyData) with the file endings .fib or .vtk. The advantage of the VTK format is that it can store additional information such as fiber weights and fiber colors. By default, both are saved with the actual tract information. + +\subsection tract_trk TrackVis (.trk) + +TRK is the tractography file format used by TrackVis and DIPY. See http://www.trackvis.org/docs/?subsect=fileformat for a detailed description of a format. + +\subsection tract_tck MRtrix (.tck) + +MITK Diffusion is able to read the tck file format native to MRtrix. Writing this format is currently not supported. By default, MRtrix uses a RAS coordinate convention in contrast to the MITK Diffusion (and also ITK) convention of LPS. To compensate for this, the fiber coordinates are negated in the x and y dimension. + +\subsection tract_dicom DICOM + +Tractography DICOM files compliant with the supplement 181 of the DICOM standard can be read and written by MITK Diffusion. This format is for example supported by the neuronavigation software of Brainlab. +DICOM tags of the read tractogram can be manually set or modified using the "Properties" view in MITK Diffusion. To do this, enable the "Developer Mode" option in Window>Preferences>Properties>Developer Mode. Then select the fiber bundle in the data manager and select the "Base Data" property list in the corresponding combobox of the "Properties" view. +*/ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkDiffusionImagingPortalPage.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkDiffusionImagingPortalPage.dox new file mode 100644 index 0000000000..d2052b2ff2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkDiffusionImagingPortalPage.dox @@ -0,0 +1,48 @@ +/** +\page org_mitk_gui_qt_diffusionimaging MITK Diffusion + +\tableofcontents + +MITK Diffusion offers a selection of image analysis methods for dMRI processing. It encompasses the research of the Division of Medical Image Computing of the German Cancer Research Center (DKFZ). + +\section org_mitk_gui_qt_diffusionimagingComponents Components + +MITK Diffusion consists of multiple components with their own documentation: + +\subsection sub1 Data formats, import and export +\li \subpage QmitkDiffusionImagingDataImportPage + +\subsection sub2 Preprocessing and Reconstruction +\li \subpage org_mitk_views_diffusionpreprocessing +\li \subpage org_mitk_views_simpleregistrationview +\li \subpage org_mitk_views_headmotioncorrectionview +\li \subpage org_mitk_views_denoisingview +\li \subpage org_mitk_views_tensorreconstruction +\li \subpage org_mitk_views_qballreconstruction + +\subsection sub3 Visualization and Quantification +\li \subpage org_mitk_views_controlvisualizationpropertiesview +\li \subpage org_mitk_views_odfdetails +\li \subpage org_mitk_views_odfmaximaextraction +\li \subpage org_mitk_views_partialvolumeanalysisview +\li \subpage org_mitk_views_diffusionquantification +\li \subpage org_mitk_views_ivim + +\subsection sub4 Fiber Tractography +\li \subpage org_mitk_views_streamlinetracking +\li \subpage org_mitk_views_gibbstracking +\li \subpage org_mitk_views_mlbtview +\li \subpage org_mitk_views_fiberprocessing +\li \subpage org_mitk_views_fiberquantification +\li \subpage org_mitk_views_fiberfit +\li \subpage org_mitk_views_fiberclustering + +\subsection sub5 Fiberfox dMRI Simulation +\li \subpage org_mitk_views_fiberfoxview +\li \subpage org_mitk_views_fieldmapgenerator + +\subsection sub6 TBSS and Connectomics +\li \subpage org_mitk_views_tractbasedspatialstatistics +\li \subpage org_mitk_diffusionimagingapp_perspectives_connectomics + +*/ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkDiffusionImagingVisualization.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkDiffusionImagingVisualization.dox new file mode 100644 index 0000000000..f111e4e593 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/QmitkDiffusionImagingVisualization.dox @@ -0,0 +1,22 @@ +/** +\page org_mitk_views_controlvisualizationpropertiesview Visualization Control Panel + +\section QmitkDiffusionImagingVisualizationSettings ODF Visualization + +In this small view, the visualization of ODFs and diffusion images can be configured. Depending on the selected image in the data storage, different options are shown here. + +For tensor or ODF images, the visibility of glyphs in the different render windows (T)ransversal, (S)agittal, and (C)oronal can be configured here. The maximal number of glyphs to display can also be configured here for. This is usefull to keep the system response time during rendering feasible. The other options configure normalization and scaling of the glyphs. + +This is how a visualization with activated glyphs should look like: + +\imageMacro{Data_CSD.png,"ODF image with glyph visibility toggled ON",1} + +\imageMacro{Data_Tensors.png,"Tensor image with glyph visibility toggled ON",1} + +\section QmitkDiffusionImagingTractVisualizationSettings Tractogram Visualization + +If a tractogram is selected in the data manager, this view enables to visualize the fibers as tubes or thick lines as well as to play with the 2D and 3D clipping of the fiber visualization. The 3D clipping works per tractogram individually, which enables nice visualization of e.g. a CST tract extending upwards out of the bottom half of a whole brain tractogram. + +\imageMacro{tract_visualization.png,"CST tube visualization with sagittal 3D clipping of the whole-brain tractogram.",1} + +*/ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/dicom1.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/dicom1.png new file mode 100644 index 0000000000..a11c978150 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/dicom1.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/tract_visualization.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/tract_visualization.png new file mode 100644 index 0000000000..9805ac1578 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/old/tract_visualization.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/QmitkRadiomicsArithmetricView.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/QmitkRadiomicsArithmetricView.dox new file mode 100644 index 0000000000..b262e84bc3 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/QmitkRadiomicsArithmetricView.dox @@ -0,0 +1,22 @@ +/** +\page org_mitk_views_radiomicsarithmetricview Image Arithmetrics + +Allows to perform basic arithmetic operations with all images. By default, the resulting image will be of the same type as the first input image. This also means that all operations will be perfomed using the same datatype as the input image. This can lead to rounding errors if an integer data type is used. It is possible to avoid this problem by creating a double-based image as result image by selecting the corresponding option. + +There are three different types of operations: +\li Single Image Operations: These are operations that are performed on each voxel value and do not need any additional parameter. Typical operations are calculating the absolute value of an image, or calculating an trigometric value. +\li Single Image and Double Value Operation: These are the basic mathematical operations (add, subtract, multiply, and dividive). +\li Two Images Operations: Allows to perfom basic operations between two images. + +\subsection sec1 Single Image Operations +Allows to perfom a arithmetic operation to each voxel of an image independently. Be aware that some operations expect a specific input range. This range is usually not tested for, and it might cause an error if the range if values outside of the expceted range occure. Also, some operations are rather expensive with respect to the calculation time and take some time to finish. + +\subsection sec2 Single Image and Double Value Operation +Performs a basic mathematical operation (add, subtract, multiply, and divide) between an image and a floating point value. The operation is execuded for each voxel independently. There are two options if the order of the input is relevant (i.e. for subtraction and division) to enable both ways. + +\subsection sec3 Two Image Operations +This allows to perfom mathematical operations between two images. The second image needs to be specified within this panel. Both images must match in size, it is also assumed (but not checked) that both images share the same geometry. This means that the corresponding voxels of both images share the same geometrical space. + +The first image, that would also be used for other operations, is used as "Image", while the image specified in the panel is used as "Second Image". In general, the first image is also used as first parameter in the mathematical operation. + +*/ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/QmitkRadiomicsMaskProcessingView.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/QmitkRadiomicsMaskProcessingView.dox new file mode 100644 index 0000000000..23a57edb3e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/QmitkRadiomicsMaskProcessingView.dox @@ -0,0 +1,20 @@ +/** +\page org_mitk_views_radiomicsmaskprocessingview Mask Processing + +This view gives the option to process existing masks. Currently this means cleaning the mask to remove areas that are probably wrongly segmented. + +The view expects two inputs. The first input (1) should be an image and the second input (2) a mask that corresponds to the given input. The mask needs to be a multi-label image. If the existing mask is not a multi-label image, it can be converted to such an image type by right-clicking on the corrsponding image in the "Data Manager" and selecting the point "Convert to Segmentation". + +The algorithm expects that the mask and the image share the same geomentry, e.g. have the same spacing, size, and origin. It further works only on the first layer of the segmentation , e.g. it is expected that the image contains only the values 0 and 1, with 1 marking the voxels that are segmented. + +There are two options to clean an existing mask. Either by defining a lower or upper limit or by removing the outlier. + +If the intensity values corresponds to clear image values, as it is for example with CT, it might be possible to limit the segmentation to only fixed intensity range. This can be done by defining an lower or upper limit and pressing the "Clean Mask based on Intervall" button (4). All elements of the mask which cover voxels with images outside of the specified intervall will then be set to zero, i.e. removed from the mask. To specify the limit, the corresponding values needs to be specified in the corresponding input (3). The lower or upper limit will only be applied if they are enabled! It is possible to either apply only a lower limit, only a upper limit, or applying a lower and an upper limit at the same time. + +The second option is to remove all voxels that are outside a three sigma interval from the mean value. The rational behind this is that those values are different from the other values and therefore might represent outliers. This option can be simply perfomed by pressing button "Remove outlier from Mask..." (5). + +The resulting image from all options will be masks again. + +\imageMacro{RadiomicsMaskProcessingView_01_Overview.png,"Overview of the Mask Processing View",1} + +*/ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/QmitkRadiomicsStatisticView.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/QmitkRadiomicsStatisticView.dox new file mode 100644 index 0000000000..c533696d6a --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/QmitkRadiomicsStatisticView.dox @@ -0,0 +1,31 @@ +/** +\page org_mitk_views_radiomicsstatisticview Radiomics Statistic + +This is a basic view to actually calculate different image features, for example those necessary for radiomic studies. It is possible to select the required feature classes that should be calculated from the given image. + +In order to be able to calculate the features it is necessary to define an image (1) and a corresponding mask (2). The image will be converted to an double image during the feature calculation and the mask must be a an Multi-Level Segmentation. If the mask is a standard mask, it is possible to convert the mask into a multilabel mask by right-clicking on the corresponding image on the "Data Manager" and selecting the point "Convert to Segmentation". The image and the segmentation must have the same geometry, e.g. the same spacing, origin, transformation matrix, and same dimensions. + +Before calculating the features, it is necessary to select the feature classes that should be calculated in the corresponding panel (3). Each feature class consists of a set of Radiomics Features that share common proporties in the calculation process. All possible feature classes are derived from the AbstractGlobalImageFeature class. To get more details about the individual features, please see the corresponding classes. + +It is possible to configure all feature classes within the "Feature Class Selection"-panel (3) but it is also possible to set more global configuration parameters in teh "Configuration Parameter" panel (4). The options set here will influence all features if the corresponding parameter is not explicitly overwritten. For a detailed description of the parameters, see the corresponding subsection. + +After starting the calculation process with the "Execute" Button (5), the features will be calculated and the result shown in the result table (6) at the end of the view. + +\imageMacro{RadiomicsStatisticView_01_Overview.png,"Overview of the Radiomics Statistic View. ",1} + +\section Parameters +There are two types of possible parameters. The Binning Parameters (1-4) which helps to control the histogram building process that most feature classes use. The second group represent more general parameter (5-7). All parameters are disabled by default (Checkbox left of feature description text), as there is no default value that fits all cases. In order to set a parameter, it must be first enabled. This is especially important for binary options like ignorign the mask for the histogram. + +The histogram options allow to define the histogram that is used for many feature classes. It is possible to define a minimum (1) and a maximum (2) intensity value for the histogram. In addition to this there is the possiblility to set the number of bins (3) or the bin size (4) for each histogram. A detailed description of each parameter is given in the description of the AbstractGlobalImageFeature class. + +With "Encode Parameter in Name" (5) it is possible to allow the actual parameter set to be encoded in the final feature name. By default, the resulting feature names will only contain the feature class and the actual feature name. If this option is checked, also all relevant parameters are encoded in the name of each feature. + +The parameter "Direction Parameter" allows to restrict the calculation of the feature to a given dimension, if this is supported by the feature classes. If it is set to 0, all directions are considered. If it is set to 1, only one direction is considered (mainly for testing purpose). If it is set to values 2 to n, the value-2 dimension is not considered during the feature calculation. + +The parameter "Slice-wise calculation" allows to perform slice-wise calculations. Generally, it can be used with all parameters but not all features are well-defined for 2D data (for example, volume based features expect at least 3 dimensions). The value defied here gives the axis along which the split is performed. + +\imageMacro{RadiomicsStatisticView_02_Parameter.png,"List of possible Parameters",1} + + + +*/ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/QmitkRadiomicsTransformationView.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/QmitkRadiomicsTransformationView.dox new file mode 100644 index 0000000000..c7147ec856 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/QmitkRadiomicsTransformationView.dox @@ -0,0 +1,49 @@ +/** +\page org_mitk_views_radiomicstransformationview Image Transformations + +This view can be used to apply various transformation to an image. Currently it is possible to apply one of four transformations. In order to do this, a first step is to select an image (1). After this, one of the four possible transformations must be selected (2). Possible actions are: +\li Multi-Reolution Pyramid +\li Resample Image +\li Wavelet Transformation +\li Lapalcian of Gaussian + +\imageMacro{RadiomicsTransformationView_01_Overview.png,"Overview of the transformation view",1} + +\section org_mitk_views_radiomicstransformationview_MultiResolutionPyramid Multi-Resolution Pyramid +Creates a multi-resolution pyramid by filtering the images using a gaussian kernel and then reduing the resolution by a factor 2 for each step of the pyramid. The spacing is adapted duringt the creation of each step. Therefore, the spacial size of the image will be kept. + +The view offers two possible parameters. With option (1), "Number of Levels" the number of pyramid levels are controlled. The image of the first level has always the same resolution as the input image. If the input image has 256x256 voxels in two dimensions and the number of levels is set to 4, the resulting output images will be: +\li Image 0 : Resolution 256x256 +\li Image 1 : Resolution 128x128 +\li Image 2 : Resolution 64x64 +\li Image 3 : Resolution 32x32 + +With the second option (2), it is possible to ensure that the output will be of the type "double". If this option is not checked, the result will be of the same type as the input image. Beware that this might lead to some artefacts due to the resmapling artefacts. + +\imageMacro{RadiomicsTransformationView_02_MultiResolution.png,"Multi-Resolution panel of the Transofrmation View",1} + +\section org_mitk_views_radiomicstransformationview_ResampleImage Image Resampling +Allows to simply resampling an existing image. It is based on the functionality of the MatchPoint Framework. + +Options: +\li Dimension ... (1) : The new target spacing. If this is not enabled (by deselecting the corrsponding option), or set to a negative or zero value, the original spacing will be kept and the corresponding dimension will not be resampled. +\li Interpolation mode (2): Set the mode for the interpolation. Possible options are "linear" e.g. using a linear model to determine the new intensity value, "B-Spline" e.g. using a higher-dimensional function (second order), "Nearest Neighbour" e.g. using the intensity of the nearest original voxel, "WSinc Hamming", "WSinc Welch" e.g. using Hamming or Welch windowing function. +\li Grid alignment method (3): Allows to define the alignment method for the newly created image. It is either "Origin algined" e.g. the origin of the original and resampled image match, "Center aligned" e.g. the center of the images are matched or "same size" in which case the resolution will be slightly adated so that the new created image will have the exact same spacial dimensions. +\li Output as double (4): Returns the resampled image as double output. Without selecting this option, the resulting image will be of the same datatype as the input image. +\li Round output (5): If this option is selected, the intensity values of the resampled image will be rounded to the next integer. +\li Resample as mask (6): Resamples the input as mask. Assumes that the input image is a mask, but will also work with other image types. The output value is either 0 or 1. If a interpolation method other than "nearest Neighbour" is chosen, the image will be thresholded with the value 0.5 in order to create the mask. + +\imageMacro{RadiomicsTransformationView_03_Resample.png,"Resampling panel of the Transformation View",1} + +\section org_mitk_views_radiomicstransformationview_WaveletTransform Wavelet Transformations +Applying wavelet transformations to the original image. It is expected that the user has sufficient knowledge about Wavelet transformations if this toolbox is used. + + +\section org_mitk_views_radiomicstransformationview_LoG Laplacian of Gaussian +Applies a Laplacian of Gaussian Transformation to the input image. This is defined as the second order deviation of a gaussian smoothed image. +The option "Gaussian Sigma" (1) defines the width of the gaussian kernel that is used by defining the corresponding sigma level in mm. It is possible to capture different details on the image by using various sigma levels. + +The option "Return result as double" allows to ensure that the result will be of type double. If this option is not selected, the resulting image will be of the same type as the input image. Be aware that all calculations will be performed using the output image data type. If this is not a floating point type, the result might be affected by rounding errors. + +\imageMacro{RadiomicsTransformationView_05_LoG.png,"Laplacian of Gaussian panel of the Transformation View",1} +*/ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsMaskProcessingView_01_Overview.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsMaskProcessingView_01_Overview.png new file mode 100644 index 0000000000..3487a3d27d Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsMaskProcessingView_01_Overview.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsStatisticView_01_Overview.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsStatisticView_01_Overview.png new file mode 100644 index 0000000000..1bc61c1966 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsStatisticView_01_Overview.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsStatisticView_02_Parameter.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsStatisticView_02_Parameter.png new file mode 100644 index 0000000000..fcdf83bb82 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsStatisticView_02_Parameter.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsTransformationView_01_Overview.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsTransformationView_01_Overview.png new file mode 100644 index 0000000000..07902bd644 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsTransformationView_01_Overview.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsTransformationView_02_MultiResolution.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsTransformationView_02_MultiResolution.png new file mode 100644 index 0000000000..0517912a71 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsTransformationView_02_MultiResolution.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsTransformationView_03_Resample.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsTransformationView_03_Resample.png new file mode 100644 index 0000000000..89b25cfc0b Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsTransformationView_03_Resample.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsTransformationView_05_LoG.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsTransformationView_05_LoG.png new file mode 100644 index 0000000000..e12c03be4d Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/RadiomicsTransformationView_05_LoG.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/modules.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/modules.dox new file mode 100644 index 0000000000..7bf036aa2a --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/modules.dox @@ -0,0 +1,16 @@ +/** + \defgroup org_mitk_gui_qt_basicimageprocessing org.mitk.gui.qt.basicimageprocessing + \ingroup MITKPlugins + + \brief Describe your plugin here. + +*/ + +/** + \defgroup org_mitk_gui_qt_basicimageprocessing_internal Internal + \ingroup org_mitk_gui_qt_basicimageprocessing + + \brief This subcategory includes the internal classes of the org.mitk.gui.qt.basicimageprocessing plugin. Other + plugins must not rely on these classes. They contain implementation details and their interface + may change at any time. We mean it. +*/ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_00_PortalPage.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_00_PortalPage.dox new file mode 100644 index 0000000000..6d7f5351bf --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_00_PortalPage.dox @@ -0,0 +1,22 @@ +/** +\page org_mitk_views_radiomicstutorial_gui_portal GUI based Radiomics Tutorial + +This is an basic tutorial to show how MITK Phenotyping can be used to perform the individual steps of an radiomics study. It assumes that you have MITK Phenotyping running on your server, and focuses on the usage of the graphical interface. + +In order to use the Tutorial you need an 3D image. We will use the Pic3D.nrrd image, which can be downloaded from http://mitk.org/download/tutorial-data/Pic3D.nrrd . So if you want to have a better comparability between our results and your results, we suggest that you use this image as well. However, feel free to use your own image if you want. + +The tutorial is designed along the steps that would be perfomed within a radiomics study until to the point where the radiomic features are obtained and the statistical analysis would be necessary. This should be done in the tool of choice of the scientist. Please be aware: This is not a real study, and you might perfom some steps differently or additional steps in a real radiomics study. The main aim of this study is to give the reader an idea how to perfom individual steps in MITK. + +The first step is to make MITK Phenotyping and the MITK Workbench familiar to you. If you know the basic of the MITK Workbench, you can skip this step. +\subpage org_mitk_views_radiomicstutorial_gui_01_basic + +The second step is to create a segmentation for the next steps. If you want to create the segmentations with a different tool, you can also skip this step. +\subpage org_mitk_views_radiomicstutorial_gui_02_Segmentation + +The third step is to preprocess the images. This step could also be perfomed before creating the segmentation, which is actually suggested. But it is common that the segmentations are already created for a study. Therefore, we put this step after the segmentation creation process. +\subpage org_mitk_views_radiomicstutorial_gui_03_preprocessing + +The fourth and last step of this tutorial covers the calculation of the features with the graphical interface. We only use a limited amount of features, feel free to calculate more features in one step. +\subpage org_mitk_views_radiomicstutorial_gui_04_featurecalulation + +*/ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_01_Basic.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_01_Basic.dox new file mode 100644 index 0000000000..f7f73f09b7 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_01_Basic.dox @@ -0,0 +1,30 @@ +/** +\page org_mitk_views_radiomicstutorial_gui_01_basic GUI based Radiomics Tutorial - Basic handling of MITK + +\subsection Basic handling of MITK + +Open a MITK Workbench which also includes MITK Phenotyping. You should see something similar to figure 1. At the top you'll see a bar (1), (2) with different important operations like open and saving data, different important views (like DICOM Window, Image Navigator and View Navigator), and a list of all Views included in your version (2). Items are grouped, and depending on the width of your screen might be hidden behind small arrows. + +The Data Manager (3) is usually placed at the left, although it could be also open at other positions. It is used to organize open images and other data items. Below it you see the Image Navigator (4) which helps to navigate through the 3D data. It allows to change the position within the data either in real-world coordinates (in mm) or by specifiying a slice number. + +In the center of your application you should see the Displays (5), which will display the images. It usually consists of four views, showing axial, sagittal, coronal and a 3D view of the data. It is possible to rearange the single displays and configure them to your wishes with the three small buttons which will become visible if the mouse is in the upper right corner of display. + +Beside these elements, there are various open views (6). You can close them with the cross and reopen them using the bar at the top (2). It is also possible to rearrange all Views to various positions left, right, above, or below the displays. + +An important view is the "View Navigator". In figure 1 it is hidden behind the Data Manager (3) and could be made visible with a click on the corresponding bar left of the "Data Manager" bar. The View Navigator is an easy and straight forward tool to show all available views and open them. It allows to search through all views. Offering a search function it allows to find views using their name of just searching for a functionality you are looking for. + +\imageMacro{RadiomicsTutorial_GUI_Step1_01_Overview.png,"Overview of MITK Workbench with active MITK Phenotyping",1} + +\subsection Loading image data +In order to calculate the radiomics features using the graphical interface you first need to load the data into the graphical environment. This can be done in different ways. If you want to load an DICOM series, it is sufficient to load a single image if the other images of the series are within the same folder. MITK will then combine all Series DICOM Images to a single 3D Image. + +\li Open an Image using the "Open File" menu item: If you click on the "Open File" item in the "File" menu or the "Open File" button in the top bar you will be presented a standard file dialog of your system. Select the image you want to load and click "Open". + +\li Drag n' Drop: Select the image you want to load with your standard data managing tool, for example with the explorer on windows or finder on Mac. Drag and drop the file into the open MITK Workbench window, the image will then be loaded if possible. If you + +\li DICOM Browser: MITK offers the basic possibiliy to manage and handle DICOM images using the DICOM Browser. You can enable this view by clicking on "DICOM", right of the "Redo"-Button. Within the DICOM Browser, it is possible to read complete folders, and load specific series into the workbench. For more information see \ref org_mitk_gui_qt_dicom . + + + + +*/ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_02_Segmenting.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_02_Segmenting.dox new file mode 100644 index 0000000000..ac82cd942d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_02_Segmenting.dox @@ -0,0 +1,19 @@ +/** +\page org_mitk_views_radiomicstutorial_gui_02_Segmentation GUI based Radiomics Tutorial - Creating a basic Segmentation + + +\subsection Creating a basic Segmentation +The first step is to create a new segmentation that can be used to calculate radiomics features. You might skip this step if you already have an segmentation at hand. Ti For this, we load the image we want to process and open the segmentation view. The easiest way to do this is to open the "View Navigator" and search for segmentation. The Segmentation view can then be opened by simply double-clicking on the view in the "View Navigator". + +With this view, we will create an One-Level segmentation. It would also be possible to create a multi-label segmentation where more than one structure can be segmented using the MultiLabel segmentation. Howerver, MITK Phenotyping is currently only supporting one Label per mask, so there would be no benefit in doing so. In addition, the created segmentation could be extended further if needed. + +\imageMacro{RadiomicsTutorial_GUI_Step2_01_Preparation.png,"MITK Workbench with open Segmentation View and loaded image. If you want to have the same view, you can go to the position indicated by the 'Image Navigator'",1} + +To now create a segmentation, we press the "New"-Button in the Data Selection part of the "Segmentation"-View. After giving the segmentation a name and probably selecting a new color if red isn't what we want, we can see a new image in the "Data Manager", the segmentation image. The segmentation can now be edited using the segmentation tools, either slice-by-slice wise or the whole 3D volume using one of the 3D tools. A good description of the different tools and their implication can be found a \ref org_mitk_views_segmentation . The different modes and options are also described there. + +We create a simple segmentation of a rib in a few slices, as indiciated by the following picture. At this point, we suggest that you play around to get used to the segmentation tool and then try to roughly reproduce our results. It is not necessary to obtain a one-to-one solution of our segmentation. + +\imageMacro{RadiomicsTutorial_GUI_Step2_02_StartSegmentation.png,"Basic segmentation of a rib we created in 6 slices. The color of the segmentation is changed to orange for bone.",1} + + +*/ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_03_Preprocessing.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_03_Preprocessing.dox new file mode 100644 index 0000000000..52194c1bcd --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_03_Preprocessing.dox @@ -0,0 +1,23 @@ +/** +\page org_mitk_views_radiomicstutorial_gui_03_preprocessing GUI based Radiomics Tutorial - Preprocessing the data + +\subsection Preprocessing the data +The first step we take is to resample the data. To do so, we open the "Radiomics Transformation" View and select the "Resample Image" panel. We start by resampling the original image and therefore select the original picture (for us, Pic3D). Right-clicking on the image in the "Data Manager" and selecting the option "Details" gives us more information on the image. As we can see, our image has a spacing of [1, 1, 3], with an inplane resolution of 1x1mm and a out-of-plane resolution of 3 mm. We therefore decide to resample the image to an isotropic resolution of 1x1x1 mm. + +\imageMacro{RadiomicsTutorial_GUI_Step3_01_DetailView.png,"Details showing the spacing of the original image.",1} + +To resample the image, we de-select "Dimension X" and "Dimension Y" option and set the "Dimension Z" option to 1, as indiciated by the image above. This tells the resampling algorithm to change only the last dimension to the value we specified. We further select to have the output image as double and chose B-Spline as resampling algorithm. This is a fast and still accurate option for resampling. To learn more about the other interpolation modes, refer to \ref org_mitk_gui_qt_matchpoint_mapper . + +After resampling the original image, we also need to resample the segmentation. For this, we select the segmentation, leave the dimensions unchanged. Remove the "Output as double" option, as segmentations are not double values and choose a linear interpolation, which seems to be a better solution for resampling masks. We also check the option that we are resampling a mask. + +After performing those two steps, there should be two additional, resampled images in the "Data Manager". + +As a second step, we calculate some Laplacian of Gaussian images of the resampled image that allow us to capture more detailed information. For this, we select the panel "Laplacian of Gaussian" of the "Radiomics Transformation"-view and perform the algorithm three times with different sigma values (we chose 1,2, and 4). Make sure that you selected the right image to calculate the image, i.e. the resampled image. + +Finally, we clear the mask to obtain a clear segmentation of the target structure and remove possible resampling artifacts. To do so, we open the "Radiomics Mask Processing" View and select the resampled image and the resampled mask. We then select a lower limit only and set it to 160. Since we are working with MR, this is not a fixed value but something we manually determined. With this set, we perform the mask reducing by cklicking "Clean Mask based on Intervall". After this, we have the resampled image, three LoG images and a resampled and cleaned mask. The result should look similar to the next picture. You can also see the final image structure we obtained from our processing. It might help you to compare your results, although it is not necessary to obtain the same structure as long as you have all necessary images. + +\imageMacro{RadiomicsTutorial_GUI_Step3_02_FinishedPreprocessing.png,"Final results with a completed resampling",1} + + + +*/ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_04_FeatureCalculating.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_04_FeatureCalculating.dox new file mode 100644 index 0000000000..82077815fa --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_04_FeatureCalculating.dox @@ -0,0 +1,44 @@ +/** +\page org_mitk_views_radiomicstutorial_gui_04_featurecalulation GUI based Radiomics Tutorial - Calculating the Radiomics Features + +\subsection Calculating the Radiomics Features +The most important step of a radiomic study is the calculating of the features. With MITK Phenotyping this is done using the "Radiomics Statistic" View. Open it using the View Navigator. Within this view, we select the resampled image and the resampled and cleaned mask. In a first step, we select the features we aim to calculate. For this tutorial we chose four features: +\li Volumetric Features +\li First Order Numerics +\li Intensity Volume Histogram +\li Co-occurence Based Features + +After selecting the features, we need to configure the features. We start with the "Intenstiy Volume Histogram" Features. Because this Feature class makes an uncommon use of the internal histogram, it makes sense to set the histogram parameter for this feature individually. To do so, click on the "+" next to the feature class name. You should see a list of feature specific parameter. Activate the following parameter and set them to the given parameter: +\li ivoh::minimum 159.5 +\li ivoh::maximum 900.5 +\li ivoh::binsize 1.0 +This configures a histogram that starts from 160 and ranges to 900 with a binsize of 1. Since the minimum and maximum parameter specify the borders of the histogram, we added /subtracted the half of the binsize, so that the middle of the bins will be on a integer. + +After this step switch to the "Configuration Parameter" panel. Select the default parameters for the histogram: +\li Minimum Intensity 160 +\li Maximum Intensity 900 +\li Number of Bins 32 +You will recognize that we chose a quite different setting for the histogram this time. Instead of the histogram binsize, we selected the number of bins. Don't forget to activate the features. + +As we will calculate multiple features, also activate the "Encode Parameter in Name" option. After this, you can enable the feature calculation by pressing "Execute". You should see the results of the feature calculation process in the table below the configuration list. + +We will now calculate the Co-occurence based feature with a different number of bins. For this, change the "Number of Bins" to 64, and deselect all features except the "Co-occurence based Features". In order to keep the previous results, execute the algorithm this time using the button "Execute & Append". The results will be appended to the results shown at the table in the bottom. + +Now select a different image and repeat the calculation of the Co-occurence feature with a bin number of 64. Then reselect the "First Order Numberics" and "Intensity Volume Histogram" again and set the number of Bins back to 32. You don't need to recalculate "Volumetric Features" as these features are based on the shape and therefore won't change if only the image is changed. + +You will now have a long list of features. To further process these features, press the "Table to Clipboard" button. You can now paste the results in your favourit editor or statistic program and perfom the analysis of the radiomic study. + +To give you some ideas how the results look like, here are some results from our experiment. If you used the same image and made a similar mask, you should obtain similar results, although small differences might be based on variations of the segmentation: +\li Pic3D__Resampled;Bone__Resampled__MaskRange;Co-occurenced Based Features::Min-160_Max-900_Bins-64_Range-1::Mean Sum Average;52.5338 +\li Pic3D__Resampled;Bone__Resampled__MaskRange;Co-occurenced Based Features::Min-160_Max-900_Bins-32_Range-1::Mean Sum Average;26.7659 +\li Pic3D__Resampled__LoG__Sigma-1;Bone__Resampled__MaskRange;Co-occurenced Based Features::Min-160_Max-900_Bins-64_Range-1::Overall Sum Average;2 +\li Pic3D__Resampled__LoG__Sigma-1;Bone__Resampled__MaskRange;Co-occurenced Based Features::Min-160_Max-900_Bins-32_Range-1::Overall Sum Average;2 +\li Pic3D__Resampled;Bone__Resampled__MaskRange;First Order Numeric::Min-160_Max-900_Bins-32::Mean;420.761 +\li Pic3D__Resampled__LoG__Sigma-1;Bone__Resampled__MaskRange;First Order Numeric::Min-160_Max-900_Bins-32::Mean;-137.746 + +You can see that the parameters used as well as image used have a clear impact on the final features. You can also see how the name of the image, the mask, and the parameters are encoded so that you are able to reproduce how the results were obtained. + + + + +*/ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step1_01_Overview.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step1_01_Overview.png new file mode 100644 index 0000000000..97e7bf73bb Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step1_01_Overview.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step2_01_Preparation.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step2_01_Preparation.png new file mode 100644 index 0000000000..39a8c9b693 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step2_01_Preparation.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step2_02_StartSegmentation.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step2_02_StartSegmentation.png new file mode 100644 index 0000000000..bc6e8660b8 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step2_02_StartSegmentation.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step3_01_DetailView.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step3_01_DetailView.png new file mode 100644 index 0000000000..a259f92b9b Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step3_01_DetailView.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step3_02_FinishedPreprocessing.png b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step3_02_FinishedPreprocessing.png new file mode 100644 index 0000000000..1f96c2a036 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/documentation/doxygen/tutorial_gui/RadiomicsTutorial_GUI_Step3_02_FinishedPreprocessing.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/files.cmake b/Plugins/org.mitk.gui.qt.radiomics/files.cmake new file mode 100644 index 0000000000..919e17ce03 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/files.cmake @@ -0,0 +1,55 @@ +set(SRC_CPP_FILES + +) + +set(INTERNAL_CPP_FILES + QmitkRadiomicsStatisticView.cpp + QmitkRadiomicsTransformationView.cpp + QmitkRadiomicsArithmetricView.cpp + QmitkRadiomicsMaskProcessingView.cpp + + + mitkBasicImageProcessingActivator.cpp + QmitkGIFConfigurationPanel.cpp +) + +set(UI_FILES + src/internal/QmitkRadiomicsStatisticViewControls.ui + src/internal/QmitkRadiomicsTransformationViewControls.ui + src/internal/QmitkRadiomicsArithmetricViewControls.ui + src/internal/QmitkRadiomicsMaskProcessingViewControls.ui +) + +set(MOC_H_FILES + src/internal/QmitkRadiomicsStatisticView.h + src/internal/QmitkRadiomicsTransformationView.h + src/internal/QmitkRadiomicsArithmetricView.h + src/internal/QmitkRadiomicsMaskProcessingView.h + + + src/internal/mitkBasicImageProcessingActivator.h + src/internal/QmitkGIFConfigurationPanel.h +) + +set(CACHED_RESOURCE_FILES + resources/lena.xpm + resources/Icon_Transformation.png + resources/bar-chart-radiomics.svg + resources/transformation-radiomics.svg + resources/arithmetric-radiomics.svg + resources/maskcleaning-radiomics.svg + plugin.xml +) + +set(QRC_FILES + resources/QmitkRadiomicsStatisticView.qrc +) + +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.radiomics/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.radiomics/manifest_headers.cmake new file mode 100644 index 0000000000..36b9e2c447 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "MITK Radiomics") +set(Plugin-Version "0.1") +set(Plugin-Vendor "DKFZ; Medical and Biological Informatics") +set(Plugin-ContactAddress "http://www.mitk.org") +set(Require-Plugin org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.radiomics/plugin.xml b/Plugins/org.mitk.gui.qt.radiomics/plugin.xml new file mode 100644 index 0000000000..760d0150df --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/plugin.xml @@ -0,0 +1,81 @@ + + + + + + Calculate Radiomics Features from Images + + + + Calculate Tranformations like LoG and Wavelet from Images + + + + Calculate Arithmetic Operations for Images + + + + Processing Masks for Radiomics + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.radiomics/resources/Icon_Transformation.png b/Plugins/org.mitk.gui.qt.radiomics/resources/Icon_Transformation.png new file mode 100644 index 0000000000..51a0a89cee Binary files /dev/null and b/Plugins/org.mitk.gui.qt.radiomics/resources/Icon_Transformation.png differ diff --git a/Plugins/org.mitk.gui.qt.radiomics/resources/ImageProcessing_64.xpm b/Plugins/org.mitk.gui.qt.radiomics/resources/ImageProcessing_64.xpm new file mode 100644 index 0000000000..9265a814a2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/resources/ImageProcessing_64.xpm @@ -0,0 +1,318 @@ +/* XPM */ +static char *ImageProcessing___[] = { +/* columns rows colors chars-per-pixel */ +"64 64 248 2", +" c #3F3235", +". c #572F3A", +"X c #592F3A", +"o c #463337", +"O c #483137", +"+ c #513037", +"@ c #503138", +"# c #503039", +"$ c #533038", +"% c #533138", +"& c #533139", +"* c #553039", +"= c #5B313C", +"- c #612F3B", +"; c #622E3B", +": c #632F3B", +"> c #652F3C", +", c #682E3C", +"< c #6F2D3E", +"1 c #712E3E", +"2 c #752D3E", +"3 c #742C3F", +"4 c #752C3F", +"5 c #7A2D40", +"6 c #6E3F4A", +"7 c #743F4D", +"8 c #773F4C", +"9 c #7B3D4C", +"0 c #783E4C", +"q c #7B3E4D", +"w c #7D3D4C", +"e c gray30", +"r c #5B444B", +"t c #67434C", +"y c #67434D", +"u c #62454C", +"i c #62464D", +"p c #62474D", +"a c #62464E", +"s c #65444C", +"d c #65454C", +"f c #66444C", +"g c #67444C", +"h c #66444D", +"j c #67444D", +"k c #66454D", +"l c #67454D", +"z c #64464D", +"x c #66464D", +"c c #67454E", +"v c #66464F", +"b c #68434C", +"n c #6E404C", +"m c #6F414D", +"M c #6D424C", +"N c #6E424C", +"B c #68444C", +"V c #69444C", +"C c #68454D", +"Z c #70414C", +"A c #71414C", +"S c #71404D", +"D c #70414D", +"F c #72404C", +"G c #73404D", +"H c #744651", +"J c #7D4351", +"K c #7D4F59", +"L c #665659", +"P c #615B5C", +"I c gray40", +"U c #676767", +"Y c #686868", +"T c DimGray", +"R c #6A6A6A", +"E c gray42", +"W c #6C6B6C", +"Q c #6C6C6C", +"! c #6D6D6D", +"~ c #717171", +"^ c #727272", +"/ c gray45", +"( c #747474", +") c gray46", +"_ c #767676", +"` c #777777", +"' c gray47", +"] c gray48", +"[ c #7B7B7B", +"{ c #7C7C7C", +"} c #852B41", +"| c #822D40", +" . c #8A2B42", +".. c #8C2B42", +"X. c #8E2A42", +"o. c #892C42", +"O. c #962B45", +"+. c #9E2A46", +"@. c #8D364C", +"#. c #833A4B", +"$. c #803B4C", +"%. c #823A4C", +"&. c #853A4C", +"*. c #863A4C", +"=. c #863A4D", +"-. c #813C4C", +";. c #833C4D", +":. c #88394C", +">. c #8B384C", +",. c #97344B", +"<. c #90364C", +"1. c #92374D", +"2. c #94344C", +"3. c #98334B", +"4. c #9F324B", +"5. c #9F304C", +"6. c #9D324C", +"7. c #AD2748", +"8. c #A22F4B", +"9. c #A42F4B", +"0. c #A72E4B", +"q. c #AF2848", +"w. c #AB2D4B", +"e. c #AC2D4B", +"r. c #AA2D4C", +"t. c #AD2C4C", +"y. c #B6274A", +"u. c #B7274A", +"i. c #B8274A", +"p. c #BB274B", +"a. c #BD264B", +"s. c #BD274B", +"d. c #BE264B", +"f. c #BF264B", +"g. c #BE274B", +"h. c #BF274B", +"j. c #B32A4B", +"k. c #B22B4B", +"l. c #B7284B", +"z. c #B6294B", +"x. c #B42A4B", +"c. c #B52A4B", +"v. c #B42A4C", +"b. c #B62A4C", +"n. c #B9284B", +"m. c #BA284B", +"M. c #BB284B", +"N. c #B9294C", +"B. c #A1304C", +"V. c #A2304C", +"C. c #B73152", +"Z. c #AB445D", +"A. c #825962", +"S. c #9D5667", +"D. c #95606E", +"F. c #95616E", +"G. c #93646F", +"H. c #8F6A72", +"J. c #8B7077", +"K. c #8C7077", +"L. c #8D777D", +"P. c #88797D", +"I. c #937077", +"U. c #907A7F", +"Y. c #897D81", +"T. c #8A7D80", +"R. c #8A7D81", +"E. c #8B7E81", +"W. c #8C7D82", +"Q. c #A87C85", +"!. c #808080", +"~. c #818181", +"^. c gray51", +"/. c #838383", +"(. c #848081", +"). c #868084", +"_. c #848484", +"`. c gray52", +"'. c gray53", +"]. c #8C8485", +"[. c #8D8485", +"{. c #8E8486", +"}. c #8F8487", +"|. c #8A8588", +" X c #8E8789", +".X c #888888", +"XX c #898989", +"oX c gray54", +"OX c #8F8889", +"+X c gray55", +"@X c #8D8C8D", +"#X c #8D8D8D", +"$X c #918586", +"%X c #908587", +"&X c #918587", +"*X c #928588", +"=X c #938588", +"-X c #96878A", +";X c #97878B", +":X c #918E8F", +">X c #99888B", +",X c #9A888B", +".f.f.f.s.9 FXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXg 0.f.f.f.j.M FXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX7 n.f.f.f.V.j FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXa @.f.f.f.h.=.FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXy r.f.f.f.b.S FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX8 m.f.f.f.B.c FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXi 1.f.f.f.h.&.FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXB w.f.f.f.v.D FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX0 M.f.f.f.4.h FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXu 2.f.f.f.g.;.FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXb t.f.f.f.j.N FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXq p.f.f.f.6.C FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXh 3.f.f.f.a.$.FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXr 9.f.f.f.k.M FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXT L d.f.n.%.d FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX& > , = W AXlXv 9 B FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX4 u.f.f.7.(.SXhXe FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX@ X.f.f.f.f.f.J P FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX+ +.f.f.f.f.f.f.f.5 FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXo . f.f.f.f.f.f.f.d.X FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFX2 $ q.f.f.f.f.f.f.o.FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFX* p.; | y.f.f.f.i.< FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFX3 f... O } 1 : # FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXO. .% FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFX- FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFX[ ! E E E E E ` XCXDXDXDXDXDXCXaXDXDXDXDXDXDX:XkXmXmXmXmXmX9X_ I I I I I U !.mXmXmXmXmXmX6XFXFX", +"FXFX[ Y I I I I I ) uXVXK 6 VXVXNX*XVXVXVXVXVXVX>XCXDXDXDXDXDXCXaXDXDXDXDXDXDX:XkXmXmXmXmXmX9X_ I I I I I U !.mXmXmXmXmXmX6XFXFX", +"FXFX[ Y I I I I I ) uXVXQ.rXVXVXNX*XVXVXVXVXVXVX>XCXDXDXDXDXDXCXaXDXDXDXDXDXDX:XkXmXmXmXmXmX9X_ I I I I I U !.mXmXmXmXmXmX6XFXFX", +"FXFX[ Y I I I I I ) uXVXVXVXVXVXNX*XVXVXVXVXVXVX>XCXDXDXDXDXDXCXaXDXDXDXDXDXDX:XkXmXmXmXmXmX9X_ I I I I I U !.mXmXmXmXmXmX6XFXFX", +"FXFX[ Y I I I I I ) uXVXVXVXVXVXNX*XVXVXVXVXVXVX>XCXDXDXDXDXDXCXaXDXDXDXDXDXDX:XkXmXmXmXmXmX9X_ I I I I I U !.mXmXmXmXmXmX6XFXFX", +"FXFX{ / ~ ~ ~ ~ ~ ] =XpXpXpXpXpXiX%XpXpXpXpXpXpX&XdXvXvXvXvXvXdX5XvXvXvXvXvXvX@XqXwXwXwXwXwX+X[ ~ ~ ~ ~ ~ ^ ~.wXwXwXwXwXwX#XFXFX", +"FXFXFX2X2X2X2X2X2XoXK.D.D.D.D.D.G.W.,X,X,X,X,X,X[.H.D.D.D.D.D.H.J.D.D.D.D.D.D.P.1X2X2X2X2X2XXXXX2X2X2X2X2X2X/._ _ _ _ _ _ { FXFX", +"FXFXoXbXmXmXmXmXmX8XS.f.f.f.f.f.C.U.VXVXVXVXVXVX>XZ.f.f.f.f.f.Z.F.f.f.f.f.f.f.L.kXmXmXmXmXmX9X6XmXmXmXmXmXnX/.I I I I I I ) FXFX", +"FXFXoXbXmXmXmXmXmX8XS.f.f.f.f.f.C.U.VXVXVXVXVXVX>XZ.f.f.f.f.f.Z.F.f.f.f.f.f.f.L.kXmXmXmXmXmX9X6XmXmXmXmXmXnX/.I I I I I I ) FXFX", +"FXFXoXbXmXmXmXmXmX8XS.f.f.f.f.f.C.U.VXVXVXVXVXVX>XZ.f.f.f.f.f.Z.F.f.f.f.f.f.f.L.kXmXmXmXmXmX9X6XmXmXmXmXmXnX/.I I I I I I ) FXFX", +"FXFXoXbXmXmXmXmXmX8XS.f.f.f.f.f.C.U.VXVXVXVXVXVX>XZ.f.f.f.f.f.Z.F.f.f.f.f.f.f.L.kXmXmXmXmXmX9X6XmXmXmXmXmXnX/.I I I I I I ) FXFX", +"FXFXoXbXmXmXmXmXmX8XS.f.f.f.f.f.C.U.VXVXVXVXVXVX>XZ.f.f.f.f.f.Z.F.f.f.f.f.f.f.L.kXmXmXmXmXmX9X6XmXmXmXmXmXnX/.I I I I I I ) FXFX", +"FXFXoXbXmXmXmXmXmX8XS.f.f.f.f.f.C.U.VXVXVXVXVXVX>XZ.f.f.f.f.f.Z.F.f.f.f.f.f.f.L.kXmXmXmXmXmX9X6XmXmXmXmXmXnX/.I I I I I I ) FXFX", +"FXFXFX^.^.^.^.^.^._.Y.T.T.T.T.T.R.].}.}.}.}.}.}.{.E.T.T.T.T.T.E.T.T.T.T.T.T.T.).^.^.^.^.^.^.~.XXoXoXoXoXoXoX'.^.^.^.^.^.^._.FXFX", +"FXFX[ R Y Y Y Y Y _ 8XxXxXxXxXxXjX XBXBXBXBXBXBX;XeXxXxXxXxXxXeX1XxXxXxXxXxXxX`.Q Y Y Y Y Y ) 3XxXxXxXxXxXzXXXxXxXxXxXxXxX4XFXFX", +"FXFX[ Y I I I I I ) 9XmXmXmXmXmXzXOXVXVXVXVXVXVX>XfXmXmXmXmXmXfX2XmXmXmXmXmXmX_.R I I I I I / 6XmXmXmXmXmXnXXXmXmXmXmXmXmX6XFXFX", +"FXFX[ Y I I I I I ) 9XmXmXmXmXmXzXOXVXVXVXVXVXVX>XfXmXmXmXmXmXfX2XmXmXmXmXmXmX_.R I I I I I / 6XmXmXmXmXmXnXXXmXmXmXmXmXmX6XFXFX", +"FXFX[ Y I I I I I ) 9XmXmXmXmXmXzXOXVXVXVXVXVXVX>XfXmXmXmXmXmXfX2XmXmXmXmXmXmX_.R I I I I I / 6XmXmXmXmXmXnXXXmXmXmXmXmXmX6XFXFX", +"FXFX[ Y I I I I I ) 9XmXmXmXmXmXzXOXVXVXVXVXVXVX>XfXmXmXmXmXmXfX2XmXmXmXmXmXmX_.R I I I I I / 6XmXmXmXmXmXnXXXmXmXmXmXmXmX6XFXFX", +"FXFX[ Y I I I I I ) 9XmXmXmXmXmXzXOXVXVXVXVXVXVX>XfXmXmXmXmXmXfX2XmXmXmXmXmXmX_.R I I I I I / 6XmXmXmXmXmXnXXXmXmXmXmXmXmX6XFXFX", +"FXFX{ ) ( ( ( ( ( { XX7X7X7X7X7X4X|.yXyXyXyXyXyX[.#X7X7X7X7X7X#XXX7X7X7X7X7X7X/._ ( ( ( ( ( { .X7X7X7X7X7X6X'.7X7X7X7X7X7XoXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX", +"FXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFXFX" +}; diff --git a/Plugins/org.mitk.gui.qt.radiomics/resources/QmitkRadiomicsStatisticView.qrc b/Plugins/org.mitk.gui.qt.radiomics/resources/QmitkRadiomicsStatisticView.qrc new file mode 100644 index 0000000000..d8074b5c48 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/resources/QmitkRadiomicsStatisticView.qrc @@ -0,0 +1,5 @@ + + + lena.xpm + + diff --git a/Plugins/org.mitk.gui.qt.radiomics/resources/arithmetric-radiomics.svg b/Plugins/org.mitk.gui.qt.radiomics/resources/arithmetric-radiomics.svg new file mode 100644 index 0000000000..87070bf96d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/resources/arithmetric-radiomics.svg @@ -0,0 +1,146 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + R + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.radiomics/resources/bar-chart-radiomics.svg b/Plugins/org.mitk.gui.qt.radiomics/resources/bar-chart-radiomics.svg new file mode 100644 index 0000000000..66c02b7975 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/resources/bar-chart-radiomics.svg @@ -0,0 +1,97 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + R + diff --git a/Plugins/org.mitk.gui.qt.radiomics/resources/lena.xpm b/Plugins/org.mitk.gui.qt.radiomics/resources/lena.xpm new file mode 100644 index 0000000000..ccfee69bc1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/resources/lena.xpm @@ -0,0 +1,255 @@ +/* XPM */ +static char *ImageProcessing___[] = { +/* columns rows colors chars-per-pixel */ +"48 48 201 2", +" c #542E38", +". c #5D2F3A", +"X c #4A3137", +"o c #4F3037", +"O c #612E3A", +"+ c #632E3D", +"@ c #662E3C", +"# c #6B2D3B", +"$ c #6F2D3D", +"% c #712D3D", +"& c #732E3D", +"* c #722D3E", +"= c #73303F", +"- c #7F2C41", +"; c #733F4B", +": c #753F4D", +"> c #773F4D", +", c #793D4B", +"< c #7E3C4B", +"1 c #793E4D", +"2 c #783F4D", +"3 c #7A3E4D", +"4 c #7C3D4C", +"5 c #7E3D4C", +"6 c #7E3D4D", +"7 c #6F414B", +"8 c #6E424B", +"9 c #70404B", +"0 c #71414B", +"q c #70414E", +"w c #73414E", +"e c #74404E", +"r c #74414E", +"t c #635E5F", +"y c #6F5D61", +"u c gray40", +"i c #686868", +"p c DimGray", +"a c gray42", +"s c #6F6F6F", +"d c #796B6E", +"f c gray44", +"g c #717171", +"h c #727272", +"j c gray45", +"k c gray46", +"l c #767676", +"z c #777777", +"x c #797979", +"c c #7C7C7C", +"v c #7E7E7E", +"b c #7F7F7F", +"n c #862B41", +"m c #802D41", +"M c #882B41", +"N c #8B2B42", +"B c #8C374D", +"V c #8F364C", +"C c #8F374C", +"Z c #8F374D", +"A c #823B4B", +"S c #833B4C", +"D c #843A4C", +"F c #873A4C", +"G c #803D4D", +"H c #89384B", +"J c #94354B", +"K c #95354B", +"L c #93354C", +"P c #92364D", +"I c #9B324C", +"U c #9E324C", +"Y c #A02A46", +"T c #A42946", +"R c #AA2748", +"E c #A52E4B", +"W c #A72E4A", +"Q c #A72F4C", +"! c #AD2848", +"~ c #A82D4B", +"^ c #AB2D4C", +"/ c #A82E4C", +"( c #B62749", +") c #BA274B", +"_ c #BC264A", +"` c #BD264B", +"' c #BC274B", +"] c #BE264B", +"[ c #BF264B", +"{ c #BE274B", +"} c #BF274B", +"| c #BD274C", +" . c #B02A4B", +".. c #B12A4B", +"X. c #B02B4B", +"o. c #B32B4B", +"O. c #B5294B", +"+. c #B7294B", +"@. c #B52A4B", +"#. c #B9284B", +"$. c #B8294B", +"%. c #B9294C", +"&. c #A1304B", +"*. c #A4304B", +"=. c #A2304C", +"-. c #B03A57", +";. c #8D4D5C", +":. c #995E6C", +">. c #A74860", +",. c #A05265", +"<. c #A05466", +"1. c #91646F", +"2. c #94656F", +"3. c #956772", +"4. c #906971", +"5. c #926973", +"6. c #966C76", +"7. c #9A6A74", +"8. c #8E727A", +"9. c #8C7D7E", +"0. c #907379", +"q. c #967179", +"w. c #91747A", +"e. c #97777F", +"r. c #8F7D82", +"t. c #927980", +"y. c #967880", +"u. c #808080", +"i. c #868686", +"p. c gray53", +"a. c #888787", +"s. c #888888", +"d. c #898989", +"f. c #8B8B8B", +"g. c gray55", +"h. c #8D8D8D", +"j. c #8E8E8E", +"k. c gray56", +"l. c #938185", +"z. c #938387", +"x. c #938486", +"c. c #948587", +"v. c #9C8186", +"b. c #938488", +"n. c #928789", +"m. c #938789", +"M. c #94888B", +"N. c #97888A", +"B. c #96898B", +"V. c #9A888A", +"C. c #9B888C", +"Z. c #9B8A8E", +"A. c #9D8C90", +"S. c #9F8C90", +"D. c #9E8D91", +"F. c #909090", +"G. c gray57", +"H. c #929292", +"J. c #939393", +"K. c gray59", +"L. c #979797", +"P. c gray60", +"I. c #9D989B", +"U. c #9D999B", +"Y. c #9E9B9C", +"T. c #B5838D", +"R. c #A58B90", +"E. c #A78D91", +"W. c #A78C92", +"Q. c #AA8C93", +"!. c #AA8D93", +"~. c #AD8D94", +"^. c #B18F95", +"/. c #B78C96", +"(. c #B49096", +"). c #A0A0A0", +"_. c gray63", +"`. c gray64", +"'. c #A5A5A5", +"]. c #A7A7A7", +"[. c #AAA3A7", +"{. c #ADA6AA", +"}. c #A9A9A9", +"|. c #AAAAAA", +" X c gray67", +".X c gray68", +"XX c #AEAEAE", +"oX c #B0A7AC", +"OX c gray69", +"+X c gray70", +"@X c #C5959F", +"#X c #CA96A1", +"$X c #CF98A3", +"%X c #C2B7BE", +"&X c #C7BAC1", +"*X c #CBBEC5", +"=X c #CACACA", +"-X c #D5C6CF", +";X c #DBCBD4", +":X c #E1D0DA", +">X c None", +/* pixels */ +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XS D >X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XI [ $.>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X: X.[ O.2 >X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XF | [ W w >X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X8 U [ [ K >X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X2 o.[ ' A >X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XH { [ ..: >X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xq &.[ [ =.>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X1 @.[ [ V >X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XB } [ ) 6 >X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X0 *.[ [ ^ r >X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X3 +.[ [ J >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XZ ] [ #.< >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xe E [ [ ~ 9 >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X5 $.[ [ P >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>XL [ [ %.4 >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X; ~ [ [ Q 7 >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X> #.[ [ C >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>Xt .[ / , >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X$ m = a.=Xy G >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>XY [ [ _ d d.>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X. R [ [ [ [ ( . >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X # [ [ [ [ [ T >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>XM @ [ [ [ [ ! + >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>XO ` * o N - & >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X% n >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>XX >X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X", +">X>Xf p p p p c.@X4./.@X!.R.@X@X@X@XA.-X-X-X-X%X[.-X-X-X-XI.]..X.X.X}.v p p p p k `..X.X.X.Xh.>X", +">X>Xs u u u u z.$X;.2.$X^.Q.$X$X$X$XS.:X:X:X:X*XoX:X:X:X:XY..X+X+X+XXXc u u u u h ].+X+X+X+Xg.>X", +">X>Xs u u u u z.$X7.T.$X^.Q.$X$X$X$XS.:X:X:X:X*XoX:X:X:X:XY..X+X+X+XXXc u u u u h ].+X+X+X+Xg.>X", +">X>Xs u u u u z.$X$X$X$X^.Q.$X$X$X$XS.:X:X:X:X*XoX:X:X:X:XY..X+X+X+XXXc u u u u h ].+X+X+X+Xg.>X", +">X>Xf i i i i b.#X#X#X#X~.W.#X#X#X#XD.;X;X;X;X&X{.;X;X;X;XU.|.OXOXOX Xv i i i i j '.OXOXOXOXg.>X", +">X>Xi.s.s.s.s.9.q.q.q.q.w.n.V.V.V.V.x.e.e.e.e.y.t.e.e.e.e.r.F.k.k.k.k.s.s.s.s.s.i.u.b b b b >X>X", +">X>X`.+X+X+X+X6.[ [ [ [ >.Q.$X$X$X$Xv.[ [ [ [ -.<.[ [ [ [ 3..X+X+X+XXXH.+X+X+X+XP.a u u u u x >X", +">X>X`.+X+X+X+X6.[ [ [ [ >.Q.$X$X$X$Xv.[ [ [ [ -.<.[ [ [ [ 3..X+X+X+XXXH.+X+X+X+XP.a u u u u x >X", +">X>X`.+X+X+X+X6.[ [ [ [ >.Q.$X$X$X$Xv.[ [ [ [ -.<.[ [ [ [ 3..X+X+X+XXXH.+X+X+X+XP.a u u u u x >X", +">X>X`.+X+X+X+X6.[ [ [ [ >.Q.$X$X$X$Xv.[ [ [ [ -.<.[ [ [ [ 3..X+X+X+XXXH.+X+X+X+XP.a u u u u x >X", +">X>XG.P.P.P.P.0.,.,.,.,.1.N.E.E.E.E.l.,.,.,.,.:.5.,.,.,.,.8.L.P.P.P.K.f.P.P.P.P.j.l h h h h >X>X", +">X>Xk s s s s d._._._._.J.C.(.(.(.(.B._._._._.P.G._._._._.d.g s s s f s._._._._.H.P._._._._.f.>X", +">X>Xs u u u u g.+X+X+X+X).Q.$X$X$X$XZ.+X+X+X+X].P.+X+X+X+Xf.p u u u i g.+X+X+X+XP.].+X+X+X+Xg.>X", +">X>Xs u u u u g.+X+X+X+X).Q.$X$X$X$XZ.+X+X+X+X].P.+X+X+X+Xf.p u u u i g.+X+X+X+XP.].+X+X+X+Xg.>X", +">X>Xs u u u u g.+X+X+X+X).Q.$X$X$X$XZ.+X+X+X+X].P.+X+X+X+Xf.p u u u i g.+X+X+X+XP.].+X+X+X+Xg.>X", +">X>Xs u u u u g.+X+X+X+X).Q.$X$X$X$XZ.+X+X+X+X].P.+X+X+X+Xf.p u u u i g.+X+X+X+XP.].+X+X+X+Xg.>X", +">X>Xx z z z z p.G.G.G.G.h.M.C.C.C.C.m.G.G.G.G.F.g.G.G.G.G.s.l z z z x d.G.G.G.G.h.F.G.G.G.G.>X>X", +">X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X" +}; diff --git a/Plugins/org.mitk.gui.qt.radiomics/resources/maskcleaning-radiomics.svg b/Plugins/org.mitk.gui.qt.radiomics/resources/maskcleaning-radiomics.svg new file mode 100644 index 0000000000..3e1cdb068d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/resources/maskcleaning-radiomics.svg @@ -0,0 +1,1225 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + R + diff --git a/Plugins/org.mitk.gui.qt.radiomics/resources/transformation-radiomics.svg b/Plugins/org.mitk.gui.qt.radiomics/resources/transformation-radiomics.svg new file mode 100644 index 0000000000..39a94e23a6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/resources/transformation-radiomics.svg @@ -0,0 +1,112 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + R + diff --git a/Plugins/org.mitk.gui.qt.radiomics/resources/transofmration-radiomics.svg b/Plugins/org.mitk.gui.qt.radiomics/resources/transofmration-radiomics.svg new file mode 100644 index 0000000000..39a94e23a6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/resources/transofmration-radiomics.svg @@ -0,0 +1,112 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + R + diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkGIFConfigurationPanel.cpp b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkGIFConfigurationPanel.cpp new file mode 100644 index 0000000000..946d5edf2e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkGIFConfigurationPanel.cpp @@ -0,0 +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 "QmitkGIFConfigurationPanel.h" + + +// QT +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + +mitkUI::GIFConfigurationPanel::GIFConfigurationPanel(QWidget * parent, mitk::AbstractGlobalImageFeature::Pointer calculator) : + QWidget(parent), + m_FeatureCalculator(calculator) +{ + QVBoxLayout * lay = new QVBoxLayout; + + QHBoxLayout * checkboxLayout = new QHBoxLayout; + m_CheckCalculateFeature = new QCheckBox; + m_CheckCalculateFeature->setText(m_FeatureCalculator->GetFeatureClassName().c_str()); + m_ButtonShowAdditionalConfiguration = new QPushButton; + m_ButtonShowAdditionalConfiguration->setText("+"); + m_ButtonShowAdditionalConfiguration->setMaximumWidth(30); + m_ButtonShowAdditionalConfiguration->setCheckable(true); + + checkboxLayout->addWidget(m_CheckCalculateFeature); + checkboxLayout->addWidget(m_ButtonShowAdditionalConfiguration); + lay->addItem(checkboxLayout); + + QFormLayout * argumentLayout = new QFormLayout; + QLabel * label1 = new QLabel("Use Argument"); + QLabel * label2 = new QLabel("Argument Value"); + argumentLayout->addRow(label1, label2); + + mitkCommandLineParser parser; + m_FeatureCalculator->AddArguments(parser); + std::vector < std::map > argumentList = parser.getArgumentList(); + for (auto argument : argumentList) + { + QString longarg(argument["longarg"].ToString().c_str()); + if (longarg.contains("::")) + { + + QCheckBox * argumentBox = new QCheckBox; + QWidget * secondWidget = NULL; + argumentBox->setText(longarg); + + mitkCommandLineParser::Type type = us::any_cast(argument["valuetype"]); + switch (type) + { + case mitkCommandLineParser::Bool: + secondWidget = new QCheckBox; + break; + case mitkCommandLineParser::String: + { + QLineEdit* lineEdit = new QLineEdit; + secondWidget = lineEdit; + break; + } + case mitkCommandLineParser::Int: + { + QSpinBox* spinBox = new QSpinBox(); + spinBox->setMinimum(std::numeric_limits::min()); + spinBox->setMaximum(std::numeric_limits::max()); + secondWidget = spinBox; + break; + } + case mitkCommandLineParser::Float: + { + QDoubleSpinBox* spindBox = new QDoubleSpinBox; + spindBox->setMinimum(std::numeric_limits::lowest()); + spindBox->setMaximum(std::numeric_limits::max()); + secondWidget = spindBox; + break; + } + default: + secondWidget = new QLabel("unkonw type"); + } + + argumentLayout->addRow(argumentBox, secondWidget); + } + } + if (argumentList.size() < 2) + { + m_ButtonShowAdditionalConfiguration->setVisible(false); + } + m_GroupBoxArguments = new QGroupBox; + m_GroupBoxArguments->setTitle(""); + m_GroupBoxArguments->setLayout(argumentLayout); + m_GroupBoxArguments->setVisible(false); + lay->addWidget(m_GroupBoxArguments); + //lay->addItem(argumentLayout); + + + // Buttons see https://joekuan.wordpress.com/2015/09/23/list-of-qt-icons/ + // Resolution https://itk.org/Doxygen/html/classitk_1_1RecursiveMultiResolutionPyramidImageFilter.html + // Wavelet https://code.google.com/archive/p/nwave/source/default/source + + this->setLayout(lay); + + connect((QObject*)(m_ButtonShowAdditionalConfiguration), SIGNAL(clicked(bool)), this, SLOT(OnSButtonShowAdditionalConfigurationPressed(bool))); +} + +void +mitkUI::GIFConfigurationPanel::OnSButtonShowAdditionalConfigurationPressed(bool status) +{ + if (m_ButtonShowAdditionalConfiguration->isChecked()) + { + m_ButtonShowAdditionalConfiguration->setText("-"); + m_GroupBoxArguments->setVisible(true); + } + else + { + m_ButtonShowAdditionalConfiguration->setText("+"); + m_GroupBoxArguments->setVisible(false); + } +} + +void +mitkUI::GIFConfigurationPanel::CalculateFeaturesUsingParameters(const mitk::Image::Pointer & feature, const mitk::Image::Pointer &mask, std::map < std::string, us::Any> parameter, mitk::AbstractGlobalImageFeature::FeatureListType &featureList) +{ + parameter[m_FeatureCalculator->GetLongName()] = us::Any(true); + + if (m_CheckCalculateFeature->isChecked()) + { + for (int i = 0; i < m_GroupBoxArguments->layout()->count(); i+=2) + { + QCheckBox * argumentBox = dynamic_cast(m_GroupBoxArguments->layout()->itemAt(i)->widget()); + if (argumentBox != NULL) + { + if (argumentBox->isChecked() == false) + { + continue; + } + std::string argumentName = argumentBox->text().toStdString(); + + + QCheckBox * paramBool = dynamic_cast(m_GroupBoxArguments->layout()->itemAt(i + 1)->widget()); + QLineEdit * paramText = dynamic_cast(m_GroupBoxArguments->layout()->itemAt(i + 1)->widget()); + QSpinBox * paramInt = dynamic_cast(m_GroupBoxArguments->layout()->itemAt(i + 1)->widget()); + QDoubleSpinBox * paramFloat = dynamic_cast(m_GroupBoxArguments->layout()->itemAt(i + 1)->widget()); + + if (paramBool == NULL && paramText == NULL && paramInt == NULL && paramFloat == NULL) + { + continue; + } + + us::Any value; + if (paramBool != NULL) + { + value = us::Any(paramBool->isChecked()); + } + if (paramText != NULL) + { + value = us::Any(paramText->text().toStdString()); + } + if (paramInt != NULL) + { + value = us::Any(paramInt->value()); + } + if (paramFloat != NULL) + { + value = us::Any(float(paramFloat->value())); + } + + parameter[argumentName] = value; + MITK_INFO << argumentName << " : " << value.ToString(); + } + } + auto tmpPointer = m_FeatureCalculator->Clone(); + mitk::AbstractGlobalImageFeature::Pointer tmpCalc = dynamic_cast(tmpPointer.GetPointer()); + for (auto item : parameter) + { + MITK_INFO << item.first << " : " << item.second.ToString(); + } + tmpCalc->SetParameter(parameter); + bool calculateSliceWise = false; + int slice = 0; + if (parameter.count("slice-wise")) + { + slice = us::any_cast(parameter["slice-wise"]); + calculateSliceWise = true; + } + if (parameter.count("encode-parameter-in-name")) + { + bool encodeParameter = us::any_cast(parameter["encode-parameter-in-name"]); + tmpCalc->SetEncodeParameters(encodeParameter); + } + if (calculateSliceWise) + { + tmpCalc->CalculateFeaturesSliceWiseUsingParameters(feature, mask, slice, featureList); + } + else + { + tmpCalc->CalculateFeaturesUsingParameters(feature, mask, mask, featureList); + } + } +} + diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkGIFConfigurationPanel.h b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkGIFConfigurationPanel.h new file mode 100644 index 0000000000..1b60f7bea0 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkGIFConfigurationPanel.h @@ -0,0 +1,50 @@ +/*=================================================================== + +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 QMITK_GIF_CONFIGURATION_PANEL_H +#define QMITK_GIF_CONFIGURATION_PANEL_H + +// MITK +#include + +// QT +#include +#include +#include +#include + +namespace mitkUI +{ + class GIFConfigurationPanel : public QWidget + { + Q_OBJECT + public: + GIFConfigurationPanel(QWidget * parent, mitk::AbstractGlobalImageFeature::Pointer calculator); + void CalculateFeaturesUsingParameters(const mitk::Image::Pointer & feature, const mitk::Image::Pointer &mask, std::map < std::string, us::Any> parameter, mitk::AbstractGlobalImageFeature::FeatureListType &featureList); + + protected slots: + void OnSButtonShowAdditionalConfigurationPressed(bool status); + + private: + mitk::AbstractGlobalImageFeature::Pointer m_FeatureCalculator; + + QCheckBox* m_CheckCalculateFeature; + QPushButton* m_ButtonShowAdditionalConfiguration; + QGroupBox* m_GroupBoxArguments; + }; +} + +#endif // QMITK_GIF_CONFIGURATION_PANEL_H \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsArithmetricView.cpp b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsArithmetricView.cpp new file mode 100644 index 0000000000..520c405bd1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsArithmetricView.cpp @@ -0,0 +1,478 @@ +/*=================================================================== + +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 "QmitkRadiomicsArithmetricView.h" + +// QT includes (GUI) +#include +#include +#include +#include +#include +#include +#include + +// Berry includes (selection service) +#include +#include + +// MITK includes (GUI) +#include +#include "QmitkDataNodeSelectionProvider.h" +#include "mitkDataNodeObject.h" + +// MITK includes (general +#include +#include +#include +#include + +// Specific GUI Includes +#include "QmitkGIFConfigurationPanel.h" + +QmitkRadiomicsArithmetric::QmitkRadiomicsArithmetric() +: QmitkAbstractView(), + m_Controls(nullptr) +{ +} + +QmitkRadiomicsArithmetric::~QmitkRadiomicsArithmetric() +{ + +} + +void QmitkRadiomicsArithmetric::CreateQtPartControl(QWidget *parent) +{ + if (m_Controls == nullptr) + { + m_Controls = new Ui::QmitkRadiomicsArithmetricViewControls; + m_Controls->setupUi(parent); + + QLabel * label1 = new QLabel("Image: "); + QmitkDataStorageComboBox * cb_inputimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); + m_Controls->m_InputImageGroup->layout()->addWidget(label1); + m_Controls->m_InputImageGroup->layout()->addWidget(cb_inputimage); + + QLabel * label2 = new QLabel("Second Image: "); + QmitkDataStorageComboBox * cb_inputimage2 = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); + m_Controls->secondImageWidget->layout()->addWidget(label2); + m_Controls->secondImageWidget->layout()->addWidget(cb_inputimage2); + + this->CreateConnections(); + } +} + +void QmitkRadiomicsArithmetric::CreateConnections() +{ + if ( m_Controls ) + { + connect( (QObject*)(m_Controls->buttonTan), SIGNAL(clicked() ), this, SLOT(TanButton())); + connect((QObject*)(m_Controls->buttonATan), SIGNAL(clicked()), this, SLOT(ATanButton())); + connect((QObject*)(m_Controls->buttonCos), SIGNAL(clicked()), this, SLOT(CosButton())); + connect((QObject*)(m_Controls->buttonACos), SIGNAL(clicked()), this, SLOT(ACosButton())); + connect((QObject*)(m_Controls->buttonSin), SIGNAL(clicked()), this, SLOT(SinButton())); + connect((QObject*)(m_Controls->buttonASin), SIGNAL(clicked()), this, SLOT(ASinButton())); + connect((QObject*)(m_Controls->buttonSquare), SIGNAL(clicked()), this, SLOT(SquareButton())); + connect((QObject*)(m_Controls->buttonSqrt), SIGNAL(clicked()), this, SLOT(SqrtButton())); + connect((QObject*)(m_Controls->buttonAbs), SIGNAL(clicked()), this, SLOT(AbsButton())); + connect((QObject*)(m_Controls->buttonExp), SIGNAL(clicked()), this, SLOT(ExpButton())); + connect((QObject*)(m_Controls->buttonExpNeg), SIGNAL(clicked()), this, SLOT(ExpNegButton())); + connect((QObject*)(m_Controls->buttonLog10), SIGNAL(clicked()), this, SLOT(Log10Button())); + + connect((QObject*)(m_Controls->buttonAddLeft), SIGNAL(clicked()), this, SLOT(AddLeftButton())); + connect((QObject*)(m_Controls->buttonSubLeft), SIGNAL(clicked()), this, SLOT(SubLeftButton())); + connect((QObject*)(m_Controls->buttonSubRight), SIGNAL(clicked()), this, SLOT(SubRightButton())); + connect((QObject*)(m_Controls->buttonMulLeft), SIGNAL(clicked()), this, SLOT(MulLeftButton())); + connect((QObject*)(m_Controls->buttonDivLeft), SIGNAL(clicked()), this, SLOT(DivLeftButton())); + connect((QObject*)(m_Controls->buttonDivRight), SIGNAL(clicked()), this, SLOT(DivRightButton())); + + connect((QObject*)(m_Controls->buttonAdd), SIGNAL(clicked()), this, SLOT(AddButton())); + connect((QObject*)(m_Controls->buttonSub), SIGNAL(clicked()), this, SLOT(SubButton())); + connect((QObject*)(m_Controls->buttonMul), SIGNAL(clicked()), this, SLOT(MulButton())); + connect((QObject*)(m_Controls->buttonDiv), SIGNAL(clicked()), this, SLOT(DivButton())); + } +} + +mitk::Image::Pointer QmitkRadiomicsArithmetric::GetFirstImage() +{ + QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); + mitk::BaseData* baseDataRawImage = NULL; + + mitk::Image::Pointer raw_image; + std::string nodeName; + if ((cb_image->GetSelectedNode().IsNotNull())) + { + baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); + nodeName = cb_image->GetSelectedNode()->GetName(); + } + if ((baseDataRawImage != NULL)) + { + raw_image = dynamic_cast(baseDataRawImage); + } + else { + QMessageBox msgBox; + msgBox.setText("Please specify the images that shlould be used."); + msgBox.exec(); + return NULL; + } + if (raw_image.IsNull()) + { + QMessageBox msgBox; + msgBox.setText("Error during processing the specified images."); + msgBox.exec(); + return NULL; + } + + return raw_image; +} + +mitk::Image::Pointer QmitkRadiomicsArithmetric::GetSecondImage() +{ + QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->secondImageWidget->layout()->itemAt(1)->widget()); + mitk::BaseData* baseDataRawImage = NULL; + + mitk::Image::Pointer raw_image; + std::string nodeName; + if ((cb_image->GetSelectedNode().IsNotNull())) + { + baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); + nodeName = cb_image->GetSelectedNode()->GetName(); + } + if ((baseDataRawImage != NULL)) + { + raw_image = dynamic_cast(baseDataRawImage); + } + else { + QMessageBox msgBox; + msgBox.setText("Please specify the second images that should be used."); + msgBox.exec(); + return NULL; + } + if (raw_image.IsNull()) + { + QMessageBox msgBox; + msgBox.setText("Error during processing the specified images."); + msgBox.exec(); + return NULL; + } + + return raw_image; +} + + +void QmitkRadiomicsArithmetric::AddImageToNode(mitk::Image::Pointer image, std::string nameAddition) +{ + QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); + std::string nodeName; + if ((cb_image->GetSelectedNode().IsNotNull())) + { + nodeName = cb_image->GetSelectedNode()->GetName(); + } + + mitk::DataNode::Pointer result = mitk::DataNode::New(); + result->SetProperty("name", mitk::StringProperty::New(nodeName + nameAddition)); + result->SetData(image); + GetDataStorage()->Add(result, cb_image->GetSelectedNode()); +} + + +void QmitkRadiomicsArithmetric::TanButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Tan(firstImage, asDouble); + AddImageToNode(result, "::Tan"); +} + +void QmitkRadiomicsArithmetric::ATanButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Tan(firstImage, asDouble); + AddImageToNode(result, "::ATan"); +} + +void QmitkRadiomicsArithmetric::CosButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Cos(firstImage, asDouble); + AddImageToNode(result, "::Cos"); +} + +void QmitkRadiomicsArithmetric::ACosButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Acos(firstImage, asDouble); + AddImageToNode(result, "::ACos"); +} + +void QmitkRadiomicsArithmetric::SinButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Sin(firstImage, asDouble); + AddImageToNode(result, "::Sin"); +} + +void QmitkRadiomicsArithmetric::ASinButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Asin(firstImage, asDouble); + AddImageToNode(result, "::ASin"); +} + +void QmitkRadiomicsArithmetric::SquareButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Square(firstImage, asDouble); + AddImageToNode(result, "::Square"); +} + +void QmitkRadiomicsArithmetric::SqrtButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Sqrt(firstImage, asDouble); + AddImageToNode(result, "::Sqrt"); +} + +void QmitkRadiomicsArithmetric::AbsButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Abs(firstImage, asDouble); + AddImageToNode(result, "::Abs"); +} + +void QmitkRadiomicsArithmetric::ExpButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Exp(firstImage, asDouble); + AddImageToNode(result, "::Exp"); +} + +void QmitkRadiomicsArithmetric::ExpNegButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::ExpNeg(firstImage, asDouble); + AddImageToNode(result, "::ExpNeg"); +} + +void QmitkRadiomicsArithmetric::Log10Button() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Log10(firstImage, asDouble); + AddImageToNode(result, "::Log10"); +} + +void QmitkRadiomicsArithmetric::AddLeftButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + double value = m_Controls->m_DoubleValue->value(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Add(firstImage, value, asDouble); + AddImageToNode(result, "::Add"); +} + +void QmitkRadiomicsArithmetric::SubLeftButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + double value = m_Controls->m_DoubleValue->value(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Subtract(firstImage, value, asDouble); + AddImageToNode(result, "::Sub"); +} + +void QmitkRadiomicsArithmetric::SubRightButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + double value = m_Controls->m_DoubleValue->value(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Subtract(value, firstImage, asDouble); + AddImageToNode(result, "::Sub"); +} + +void QmitkRadiomicsArithmetric::MulLeftButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + double value = m_Controls->m_DoubleValue->value(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Multiply(firstImage, value, asDouble); + AddImageToNode(result, "::Mul"); +} + +void QmitkRadiomicsArithmetric::DivLeftButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + double value = m_Controls->m_DoubleValue->value(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Divide(firstImage, value, asDouble); + AddImageToNode(result, "::Div"); +} + +void QmitkRadiomicsArithmetric::DivRightButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + double value = m_Controls->m_DoubleValue->value(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Divide(value, firstImage,asDouble); + AddImageToNode(result, "::Div"); +} + +void QmitkRadiomicsArithmetric::AddButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + mitk::Image::Pointer secondImage = GetSecondImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Add(firstImage, secondImage, asDouble); + AddImageToNode(result, "::Add"); +} + +void QmitkRadiomicsArithmetric::MulButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + mitk::Image::Pointer secondImage = GetSecondImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Multiply(firstImage, secondImage, asDouble); + AddImageToNode(result, "::Mul"); +} + +void QmitkRadiomicsArithmetric::SubButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + mitk::Image::Pointer secondImage = GetSecondImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Subtract(firstImage, secondImage, asDouble); + AddImageToNode(result, "::Sub"); +} + +void QmitkRadiomicsArithmetric::DivButton() +{ + mitk::Image::Pointer firstImage = GetFirstImage(); + mitk::Image::Pointer secondImage = GetSecondImage(); + bool asDouble = m_Controls->m_ResultAsDouble->isChecked(); + if (firstImage.IsNull()) + { + return; + } + auto result = mitk::ArithmeticOperation::Divide(firstImage, secondImage, asDouble); + AddImageToNode(result, "::Div"); +} + +void QmitkRadiomicsArithmetric::SetFocus() +{ +} + +//datamanager selection changed +void QmitkRadiomicsArithmetric::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) +{ + //any nodes there? + if (!nodes.empty()) + { + + } +} diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsArithmetricView.h b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsArithmetricView.h new file mode 100644 index 0000000000..f54521f569 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsArithmetricView.h @@ -0,0 +1,107 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#if !defined(QmitkRadiomicsArithmetricView_H__INCLUDED) +#define QmitkRadiomicsArithmetricView_H__INCLUDED + +#include +#include +#include "ui_QmitkRadiomicsArithmetricViewControls.h" + +#include "QmitkStepperAdapter.h" + +#include +#include +#include + + + +class RADIOMICS_EXPORT QmitkRadiomicsArithmetric : public QmitkAbstractView +{ + Q_OBJECT + +public: + + /*! + \brief default constructor + */ + QmitkRadiomicsArithmetric(); + + /*! + \brief default destructor + */ + virtual ~QmitkRadiomicsArithmetric(); + + /*! + \brief method for creating the widget containing the application controls, like sliders, buttons etc. + */ + virtual void CreateQtPartControl(QWidget *parent) override; + + virtual void SetFocus() override; + + /*! + \brief method for creating the connections of main and control widget + */ + virtual void CreateConnections(); + + /*! + \brief Invoked when the DataManager selection changed + */ + virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; + + + protected slots: + void TanButton(); + void ATanButton(); + void CosButton(); + void ACosButton(); + void SinButton(); + void ASinButton(); + void SquareButton(); + void SqrtButton(); + void AbsButton(); + void ExpButton(); + void ExpNegButton(); + void Log10Button(); + + void AddLeftButton(); + void SubLeftButton(); + void SubRightButton(); + void MulLeftButton(); + void DivLeftButton(); + void DivRightButton(); + + void AddButton(); + void SubButton(); + void MulButton(); + void DivButton(); + +private: + /*! + * controls containing sliders for scrolling through the slices + */ + Ui::QmitkRadiomicsArithmetricViewControls *m_Controls; + + mitk::Image::Pointer GetFirstImage(); + mitk::Image::Pointer GetSecondImage(); + void AddImageToNode(mitk::Image::Pointer image, std::string nameAddition); + + +}; + +#endif // !defined(QmitkRadiomicsArithmetric_H__INCLUDED) + + diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsArithmetricViewControls.ui b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsArithmetricViewControls.ui new file mode 100644 index 0000000000..43f909674e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsArithmetricViewControls.ui @@ -0,0 +1,346 @@ + + + QmitkRadiomicsArithmetricViewControls + + + + 0 + 0 + 448 + 980 + + + + Form + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 2 + + + + + 0 + 0 + 430 + 852 + + + + Single Image Operations + + + + + + + + Sinus + + + + + + + A-Sinus + + + + + + + Cosinus + + + + + + + A-Cosinus + + + + + + + Tangents + + + + + + + A-Tangents + + + + + + + Square + + + + + + + Square-Root + + + + + + + Absolute Value + + + + + + + Exponential (exp) + + + + + + + Negative Exponential + + + + + + + Logarithmic (Base 10) + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 0 + 0 + 430 + 852 + + + + Single Image and Double Value Operation + + + + + + + + + + Additional Value: + + + + + + + 4 + + + -1000000000000000000000.000000000000000 + + + 1000000000000000000000.000000000000000 + + + + + + + + + + + Add (Image + Value) + + + + + + + Subtract (Image - Value) + + + + + + + Subtract (Value - Image) + + + + + + + Multiply (Image x Value) + + + + + + + Divide (Image / Value) + + + + + + + Divide (Value / Image) + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 0 + 0 + 430 + 852 + + + + Two Image Operations + + + + + + + + + + + + 0 + 10 + + + + + + + + + Add (Image + Second Image) + + + + + + + Subtract (Image - Second Image) + + + + + + + Multiply (Image x Second Image) + + + + + + + Divide (Image - Second Image) + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + + + + true + + + + + + + Return result as double: + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsMaskProcessingView.cpp b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsMaskProcessingView.cpp new file mode 100644 index 0000000000..745f311609 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsMaskProcessingView.cpp @@ -0,0 +1,205 @@ +/*=================================================================== + +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 "QmitkRadiomicsMaskProcessingView.h" + +// QT includes (GUI) +#include +#include +#include +#include +#include +#include +#include + +// Berry includes (selection service) +#include +#include + +// MITK includes (GUI) +#include +#include "QmitkDataNodeSelectionProvider.h" +#include "mitkDataNodeObject.h" + +// MITK includes (general +#include +#include +#include +#include +#include + +// Specific GUI Includes +#include + +QmitkRadiomicsMaskProcessing::QmitkRadiomicsMaskProcessing() +: QmitkAbstractView(), + m_Controls(nullptr) +{ +} + +QmitkRadiomicsMaskProcessing::~QmitkRadiomicsMaskProcessing() +{ + //berry::ISelectionService* s = GetSite()->GetWorkbenchWindow()->GetSelectionService(); + //if(s) + // s->RemoveSelectionListener(m_SelectionListener); +} + +void QmitkRadiomicsMaskProcessing::CreateQtPartControl(QWidget *parent) +{ + if (m_Controls == nullptr) + { + m_Controls = new Ui::QmitkRadiomicsMaskProcessingViewControls; + m_Controls->setupUi(parent); + + QLabel * label1 = new QLabel("Image: "); + QLabel * label2 = new QLabel("Mask: "); + QmitkDataStorageComboBox * cb_inputimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); + QmitkDataStorageComboBox * cb_maskimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); + m_Controls->m_InputImageGroup->layout()->addWidget(label1); + m_Controls->m_InputImageGroup->layout()->addWidget(cb_inputimage); + m_Controls->m_InputImageGroup->layout()->addWidget(label2); + m_Controls->m_InputImageGroup->layout()->addWidget(cb_maskimage); + + this->CreateConnections(); + } +} + +void QmitkRadiomicsMaskProcessing::CreateConnections() +{ + if ( m_Controls ) + { + connect( (QObject*)(m_Controls->maskBasedExecutionButton), SIGNAL(clicked() ), this, SLOT(executeButtonIntervalBasedMaskClearning() ) ); + connect((QObject*)(m_Controls->outlierRemoveButton), SIGNAL(clicked()), this, SLOT(executeButtonMaskOutlierRemoval())); + } +} + +void QmitkRadiomicsMaskProcessing::executeButtonIntervalBasedMaskClearning() +{ + QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); + QmitkDataStorageComboBox * cb_maskimage = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(3)->widget()); + mitk::BaseData* baseDataRawImage = NULL; + mitk::BaseData* baseDataMaskImage = NULL; + + mitk::Image::Pointer raw_image; + mitk::Image::Pointer mask_image; + std::string nodeName; + + if ((cb_image->GetSelectedNode().IsNotNull()) && (cb_maskimage->GetSelectedNode().IsNotNull())) + { + baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); + baseDataMaskImage = (cb_maskimage->GetSelectedNode()->GetData()); + nodeName = cb_maskimage->GetSelectedNode()->GetName(); + } + if ((baseDataRawImage != NULL) && (baseDataMaskImage != NULL)) + { + raw_image = dynamic_cast(baseDataRawImage); + mask_image = dynamic_cast(baseDataMaskImage); + } + else { + QMessageBox msgBox; + msgBox.setText("Please specify the images that shlould be used."); + msgBox.exec(); + return; + } + if (raw_image.IsNull() || mask_image.IsNull()) + { + QMessageBox msgBox; + msgBox.setText("Error during processing the specified images."); + msgBox.exec(); + return; + } + + bool lowerLimitOn = m_Controls->lowerOn->isChecked(); + bool upperLimitOn = m_Controls->upperOn->isChecked(); + double lowerLimit = m_Controls->lowerLimitSpinbox->value(); + double upperLimit = m_Controls->spinboxUpperValue->value(); + + + auto image = mitk::MaskCleaningOperation::RangeBasedMasking(raw_image, mask_image, lowerLimitOn, lowerLimit, upperLimitOn, upperLimit); + + mitk::LabelSetImage::Pointer labelResult = mitk::LabelSetImage::New(); + labelResult->InitializeByLabeledImage(image); + mitk::LabelSetImage::Pointer oldLabelSet = dynamic_cast(mask_image.GetPointer()); + labelResult->AddLabelSetToLayer(labelResult->GetActiveLayer(), oldLabelSet->GetLabelSet()); + + mitk::DataNode::Pointer result = mitk::DataNode::New(); + result->SetProperty("name", mitk::StringProperty::New(nodeName+"::MaskRange")); + result->SetData(labelResult); + GetDataStorage()->Add(result, cb_image->GetSelectedNode()); +} + +void QmitkRadiomicsMaskProcessing::executeButtonMaskOutlierRemoval() +{ + QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); + QmitkDataStorageComboBox * cb_maskimage = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(3)->widget()); + mitk::BaseData* baseDataRawImage = NULL; + mitk::BaseData* baseDataMaskImage = NULL; + + mitk::Image::Pointer raw_image; + mitk::Image::Pointer mask_image; + std::string nodeName; + + if ((cb_image->GetSelectedNode().IsNotNull()) && (cb_maskimage->GetSelectedNode().IsNotNull())) + { + baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); + baseDataMaskImage = (cb_maskimage->GetSelectedNode()->GetData()); + nodeName = cb_maskimage->GetSelectedNode()->GetName(); + } + if ((baseDataRawImage != NULL) && (baseDataMaskImage != NULL)) + { + raw_image = dynamic_cast(baseDataRawImage); + mask_image = dynamic_cast(baseDataMaskImage); + } + else { + QMessageBox msgBox; + msgBox.setText("Please specify the images that shlould be used."); + msgBox.exec(); + return; + } + if (raw_image.IsNull() || mask_image.IsNull()) + { + QMessageBox msgBox; + msgBox.setText("Error during processing the specified images."); + msgBox.exec(); + return; + } + + auto image = mitk::MaskCleaningOperation::MaskOutlierFiltering(raw_image, mask_image); + + mitk::LabelSetImage::Pointer labelResult = mitk::LabelSetImage::New(); + labelResult->InitializeByLabeledImage(image); + mitk::LabelSetImage::Pointer oldLabelSet = dynamic_cast(mask_image.GetPointer()); + labelResult->AddLabelSetToLayer(labelResult->GetActiveLayer(), oldLabelSet->GetLabelSet()); + + mitk::DataNode::Pointer result = mitk::DataNode::New(); + result->SetProperty("name", mitk::StringProperty::New(nodeName + "::MaskOutlier")); + result->SetData(labelResult); + GetDataStorage()->Add(result, cb_image->GetSelectedNode()); +} + +void QmitkRadiomicsMaskProcessing::SetFocus() +{ +} + +//datamanager selection changed +void QmitkRadiomicsMaskProcessing::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) +{ + //any nodes there? + if (!nodes.empty()) + { + + } +} diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsMaskProcessingView.h b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsMaskProcessingView.h new file mode 100644 index 0000000000..18cad18ea5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsMaskProcessingView.h @@ -0,0 +1,97 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#if !defined(QmitkRadiomicsMaskProcessingView_H__INCLUDED) +#define QmitkRadiomicsMaskProcessingView_H__INCLUDED + +#include +#include +#include "ui_QmitkRadiomicsMaskProcessingViewControls.h" + +#include "QmitkStepperAdapter.h" + +#include +#include + +/*! +\brief This module allows to use some basic image processing filters for preprocessing, image enhancement and testing purposes + +Several basic ITK image processing filters, like denoising, morphological and edge detection +are encapsulated in this module and can be selected via a list and an intuitive parameter input. +The selected filter will be applied on the image, and a new image showing the output is displayed +as result. +Also, some image arithmetic operations are available. + +Images can be 3D or 4D. +In the 4D case, the filters work on the 3D image selected via the +time slider. The result is also a 3D image. + +\class QmitkRadiomicsMaskProcessing +\author Tobias Schwarz +\version 1.0 (3M3) +\date 2009-05-10 +\ingroup Bundles +*/ + +class RADIOMICS_EXPORT QmitkRadiomicsMaskProcessing : public QmitkAbstractView +{ + Q_OBJECT + +public: + + /*! + \brief default constructor + */ + QmitkRadiomicsMaskProcessing(); + + /*! + \brief default destructor + */ + virtual ~QmitkRadiomicsMaskProcessing(); + + /*! + \brief method for creating the widget containing the application controls, like sliders, buttons etc. + */ + virtual void CreateQtPartControl(QWidget *parent) override; + + virtual void SetFocus() override; + + /*! + \brief method for creating the connections of main and control widget + */ + virtual void CreateConnections(); + + /*! + \brief Invoked when the DataManager selection changed + */ + virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; + + + protected slots: + void executeButtonIntervalBasedMaskClearning(); + void executeButtonMaskOutlierRemoval(); + +private: + /*! + * controls containing sliders for scrolling through the slices + */ + Ui::QmitkRadiomicsMaskProcessingViewControls *m_Controls; + +}; + +#endif // !defined(QmitkRadiomicsMaskProcessing_H__INCLUDED) + + diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsMaskProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsMaskProcessingViewControls.ui new file mode 100644 index 0000000000..9562c074a4 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsMaskProcessingViewControls.ui @@ -0,0 +1,117 @@ + + + QmitkRadiomicsMaskProcessingViewControls + + + + 0 + 0 + 448 + 980 + + + + Form + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + Lower Limit: + + + + + + + 4 + + + -111111110111111104.000000000000000 + + + 1000000000000000000000.000000000000000 + + + + + + + Upper Limit: + + + + + + + 4 + + + -111111110111111104.000000000000000 + + + 1000000000000000000000.000000000000000 + + + + + + + + + + + Clean Mask based on Intervall + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Remove outlier from Mask (Limit to μ ± 3*σ) + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsStatisticView.cpp b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsStatisticView.cpp new file mode 100644 index 0000000000..6271d5a532 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsStatisticView.cpp @@ -0,0 +1,330 @@ +/*=================================================================== + +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 "QmitkRadiomicsStatisticView.h" + +// QT includes (GUI) +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Berry includes (selection service) +#include +#include + +// MITK includes (GUI) +#include +#include "QmitkDataNodeSelectionProvider.h" +#include "mitkDataNodeObject.h" + +// MITK includes (general) +#include "mitkLabelSetImage.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// Includes for image casting between ITK and MITK +#include +#include + +// Specific GUI Includes +#include "QmitkGIFConfigurationPanel.h" + +QmitkRadiomicsStatistic::QmitkRadiomicsStatistic() +: QmitkAbstractView(), + m_Controls(nullptr) +{ +} + +QmitkRadiomicsStatistic::~QmitkRadiomicsStatistic() +{ + //berry::ISelectionService* s = GetSite()->GetWorkbenchWindow()->GetSelectionService(); + //if(s) + // s->RemoveSelectionListener(m_SelectionListener); +} + +void QmitkRadiomicsStatistic::CreateQtPartControl(QWidget *parent) +{ + if (m_Controls == nullptr) + { + mitk::GIFImageDescriptionFeatures::Pointer ipCalculator = mitk::GIFImageDescriptionFeatures::New(); // Commented 2, Tested + mitk::GIFFirstOrderStatistics::Pointer firstOrderCalculator = mitk::GIFFirstOrderStatistics::New(); //Commented 2 + mitk::GIFFirstOrderHistogramStatistics::Pointer firstOrderHistoCalculator = mitk::GIFFirstOrderHistogramStatistics::New(); // Commented 2, Tested + mitk::GIFFirstOrderNumericStatistics::Pointer firstOrderNumericCalculator = mitk::GIFFirstOrderNumericStatistics::New(); // Commented 2, Tested + mitk::GIFVolumetricStatistics::Pointer volCalculator = mitk::GIFVolumetricStatistics::New(); // Commented 2, Tested + mitk::GIFVolumetricDensityStatistics::Pointer voldenCalculator = mitk::GIFVolumetricDensityStatistics::New(); // Commented 2, Tested + mitk::GIFCooccurenceMatrix::Pointer coocCalculator = mitk::GIFCooccurenceMatrix::New(); // Commented 2, Will not be tested + mitk::GIFCooccurenceMatrix2::Pointer cooc2Calculator = mitk::GIFCooccurenceMatrix2::New(); //Commented 2 + mitk::GIFNeighbouringGreyLevelDependenceFeature::Pointer ngldCalculator = mitk::GIFNeighbouringGreyLevelDependenceFeature::New(); //Commented 2, Tested + mitk::GIFGreyLevelRunLength::Pointer rlCalculator = mitk::GIFGreyLevelRunLength::New(); // Commented 2 + mitk::GIFGreyLevelSizeZone::Pointer glszCalculator = mitk::GIFGreyLevelSizeZone::New(); // Commented 2, Tested + mitk::GIFGreyLevelDistanceZone::Pointer gldzCalculator = mitk::GIFGreyLevelDistanceZone::New(); //Commented 2, Tested + mitk::GIFLocalIntensity::Pointer lociCalculator = mitk::GIFLocalIntensity::New(); //Commented 2, Tested + mitk::GIFIntensityVolumeHistogramFeatures::Pointer ivohCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); // Commented 2 + mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::Pointer ngtdCalculator = mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::New(); //Commented 2, Tested + mitk::GIFCurvatureStatistic::Pointer curvCalculator = mitk::GIFCurvatureStatistic::New(); //Commented 2, Tested + + std::vector features; + features.push_back(volCalculator.GetPointer()); + features.push_back(voldenCalculator.GetPointer()); + features.push_back(curvCalculator.GetPointer()); + features.push_back(firstOrderCalculator.GetPointer()); + features.push_back(firstOrderNumericCalculator.GetPointer()); + features.push_back(firstOrderHistoCalculator.GetPointer()); + features.push_back(ivohCalculator.GetPointer()); + features.push_back(lociCalculator.GetPointer()); + features.push_back(cooc2Calculator.GetPointer()); + features.push_back(ngldCalculator.GetPointer()); + features.push_back(rlCalculator.GetPointer()); + features.push_back(glszCalculator.GetPointer()); + features.push_back(gldzCalculator.GetPointer()); + features.push_back(ipCalculator.GetPointer()); + features.push_back(ngtdCalculator.GetPointer()); + + m_Controls = new Ui::QmitkRadiomicsStatisticViewControls; + m_Controls->setupUi(parent); + + for (auto cFeature : features) + { + mitkUI::GIFConfigurationPanel* gifPanel = new mitkUI::GIFConfigurationPanel(parent, cFeature); + m_Controls->m_FeaturesGroup->layout()->addWidget(gifPanel); + } + + QLabel * label1 = new QLabel("Image: "); + QLabel * label2 = new QLabel("Mask: "); + QmitkDataStorageComboBox * cb_inputimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); + QmitkDataStorageComboBox * cb_maskimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); + m_Controls->m_InputImageGroup->layout()->addWidget(label1); + m_Controls->m_InputImageGroup->layout()->addWidget(cb_inputimage); + m_Controls->m_InputImageGroup->layout()->addWidget(label2); + m_Controls->m_InputImageGroup->layout()->addWidget(cb_maskimage); + + this->CreateConnections(); + + //setup predictaes for combobox + + mitk::NodePredicateDimension::Pointer dimensionPredicate = mitk::NodePredicateDimension::New(3); + mitk::NodePredicateDataType::Pointer imagePredicate = mitk::NodePredicateDataType::New("Image"); + + + } +} + +void QmitkRadiomicsStatistic::CreateConnections() +{ + if ( m_Controls ) + { + connect( (QObject*)(m_Controls->buttonExecute), SIGNAL(clicked() ), this, SLOT(executeButtonPressed() ) ); + connect((QObject*)(m_Controls->buttonExecuteAndAppend), SIGNAL(clicked()), this, SLOT(executeAndAppendButtonPressed())); + connect((QObject*)(m_Controls->buttonTableToClipboard), SIGNAL(clicked()), this, SLOT(copyToClipboardButtonPressed())); + } +} + +std::map < std::string, us::Any> QmitkRadiomicsStatistic::GenerateParameters() +{ + std::map < std::string, us::Any> parameter; + + if (m_Controls->m_SetMinimumIntensity->isChecked()) + { + parameter["minimum-intensity"] = us::Any(float(m_Controls->m_ParamMinimumIntensity->value())); + } + if (m_Controls->m_SetMaximumIntensity->isChecked()) + { + parameter["maximum-intensity"] = us::Any(float(m_Controls->m_ParamMaximumIntensity->value())); + } + if (m_Controls->m_SetNumberOfBins->isChecked()) + { + parameter["bins"] = us::Any(m_Controls->m_ParamBins->value()); + } + if (m_Controls->m_SetBinSize->isChecked()) + { + parameter["binsize"] = us::Any(float(m_Controls->m_ParamBinSize->value())); + } + if (m_Controls->m_SetIgnoreBinSize->isChecked()) + { + parameter["ignore-mask-for-histogram"] = us::Any(m_Controls->m_ParamIgnoreMask->isChecked()); + } + if (m_Controls->m_SetEncodeParameterInName->isChecked()) + { + parameter["encode-parameter-in-name"] = us::Any(m_Controls->m_ParamEncodeName->isChecked()); + } + if (m_Controls->m_SetDirectionParameter->isChecked()) + { + parameter["direction"] = us::Any(m_Controls->m_ParamDirection->value()); + } + if (m_Controls->m_SetSliceWiseParameter->isChecked()) + { + parameter["slice-wise"] = us::Any(m_Controls->m_ParamSliceWise->value()); + } + + return parameter; +} + +void QmitkRadiomicsStatistic::executeButtonPressed() +{ + QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); + QmitkDataStorageComboBox * cb_maskimage = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(3)->widget()); + mitk::BaseData* baseDataRawImage = NULL; + mitk::BaseData* baseDataMaskImage = NULL; + + mitk::Image::Pointer raw_image; + mitk::Image::Pointer mask_image; + QString imageName; + QString maskName; + + if ((cb_image->GetSelectedNode().IsNotNull() ) && (cb_maskimage->GetSelectedNode().IsNotNull())) + { + imageName = cb_image->GetSelectedNode()->GetName().c_str(); + maskName = cb_maskimage->GetSelectedNode()->GetName().c_str(); + baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); + baseDataMaskImage = (cb_maskimage->GetSelectedNode()->GetData()); + } + if ((baseDataRawImage != NULL) && (baseDataMaskImage != NULL)) + { + raw_image = dynamic_cast(baseDataRawImage); + mask_image = dynamic_cast(baseDataMaskImage); + } + else { + QMessageBox msgBox; + msgBox.setText("Please specify the images that shlould be used."); + msgBox.exec(); + return; + } + if (raw_image.IsNull() || mask_image.IsNull()) + { + QMessageBox msgBox; + msgBox.setText("Error during processing the specified images."); + msgBox.exec(); + return; + } + + mitk::AbstractGlobalImageFeature::FeatureListType stats; + for (int i = 0; i < m_Controls->m_FeaturesGroup->layout()->count(); ++i) + { + auto parameter = this->GenerateParameters(); + + mitkUI::GIFConfigurationPanel* gifPanel = dynamic_cast(m_Controls->m_FeaturesGroup->layout()->itemAt(i)->widget()); + if (gifPanel == NULL) + continue; + gifPanel->CalculateFeaturesUsingParameters(raw_image, mask_image, parameter, stats); + } + + m_Controls->m_ResultTable->setRowCount(stats.size()); + + for (std::size_t i = 0; i < stats.size(); ++i) + { + m_Controls->m_ResultTable->setItem(i, 0, new QTableWidgetItem(imageName)); + m_Controls->m_ResultTable->setItem(i, 1, new QTableWidgetItem(maskName)); + m_Controls->m_ResultTable->setItem(i, 2, new QTableWidgetItem(stats[i].first.c_str())); + m_Controls->m_ResultTable->setItem(i, 3, new QTableWidgetItem(QString::number(stats[i].second))); + } + } + +void QmitkRadiomicsStatistic::executeAndAppendButtonPressed() +{ + std::vector elementImage; + std::vector elementMask; + std::vector elementText; + std::vector elementValue; + + for (std::size_t i = 0; i < m_Controls->m_ResultTable->rowCount(); ++i) + { + auto itemImage = m_Controls->m_ResultTable->item(i, 0)->clone(); + auto itemMask = m_Controls->m_ResultTable->item(i, 1)->clone(); + auto itemText = m_Controls->m_ResultTable->item(i, 2)->clone(); + auto itemValue = m_Controls->m_ResultTable->item(i, 3)->clone(); + elementImage.push_back(itemImage); + elementMask.push_back(itemMask); + elementText.push_back(itemText); + elementValue.push_back(itemValue); + } + + executeButtonPressed(); + + std::size_t oldSize = m_Controls->m_ResultTable->rowCount(); + m_Controls->m_ResultTable->setRowCount(oldSize + elementText.size()); + + for (std::size_t i = 0; i < elementText.size(); ++i) + { + m_Controls->m_ResultTable->setItem(i + oldSize, 0, elementImage[i]); + m_Controls->m_ResultTable->setItem(i + oldSize, 1, elementMask[i]); + m_Controls->m_ResultTable->setItem(i+oldSize, 2, elementText[i]); + m_Controls->m_ResultTable->setItem(i+oldSize, 3, elementValue[i]); + } +} + +void QmitkRadiomicsStatistic::copyToClipboardButtonPressed() +{ + QString selectedText; + for (std::size_t i = 0; i < m_Controls->m_ResultTable->rowCount(); ++i) + { + auto itemImage = m_Controls->m_ResultTable->item(i, 0); + auto itemMask = m_Controls->m_ResultTable->item(i, 1); + auto itemText = m_Controls->m_ResultTable->item(i, 2); + auto itemValue = m_Controls->m_ResultTable->item(i, 3); + selectedText.append(itemImage->text()); + selectedText.append(";"); + selectedText.append(itemMask->text()); + selectedText.append(";"); + selectedText.append(itemText->text()); + selectedText.append(";"); + selectedText.append(itemValue->text()); + selectedText.append("\n"); + } + QApplication::clipboard()->setText(selectedText); +} + +void QmitkRadiomicsStatistic::SetFocus() +{ +} + +//datamanager selection changed +void QmitkRadiomicsStatistic::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) +{ + //any nodes there? + if (!nodes.empty()) + { + + } +} diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsStatisticView.h b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsStatisticView.h new file mode 100644 index 0000000000..5602ab37d1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsStatisticView.h @@ -0,0 +1,100 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#if !defined(QmitkRadiomicsStatisticView_H__INCLUDED) +#define QmitkRadiomicsStatisticView_H__INCLUDED + +#include +#include +#include "ui_QmitkRadiomicsStatisticViewControls.h" + +#include "QmitkStepperAdapter.h" + +#include +#include + +/*! +\brief This module allows to use some basic image processing filters for preprocessing, image enhancement and testing purposes + +Several basic ITK image processing filters, like denoising, morphological and edge detection +are encapsulated in this module and can be selected via a list and an intuitive parameter input. +The selected filter will be applied on the image, and a new image showing the output is displayed +as result. +Also, some image arithmetic operations are available. + +Images can be 3D or 4D. +In the 4D case, the filters work on the 3D image selected via the +time slider. The result is also a 3D image. + +\class QmitkRadiomicsStatistic +\author Tobias Schwarz +\version 1.0 (3M3) +\date 2009-05-10 +\ingroup Bundles +*/ + +class RADIOMICS_EXPORT QmitkRadiomicsStatistic : public QmitkAbstractView +{ + Q_OBJECT + +public: + + /*! + \brief default constructor + */ + QmitkRadiomicsStatistic(); + + /*! + \brief default destructor + */ + virtual ~QmitkRadiomicsStatistic(); + + /*! + \brief method for creating the widget containing the application controls, like sliders, buttons etc. + */ + virtual void CreateQtPartControl(QWidget *parent) override; + + virtual void SetFocus() override; + + /*! + \brief method for creating the connections of main and control widget + */ + virtual void CreateConnections(); + + /*! + \brief Invoked when the DataManager selection changed + */ + virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; + + + protected slots: + void executeButtonPressed(); + void executeAndAppendButtonPressed(); + void copyToClipboardButtonPressed(); + +private: + std::map < std::string, us::Any> GenerateParameters(); + + /*! + * controls containing sliders for scrolling through the slices + */ + Ui::QmitkRadiomicsStatisticViewControls *m_Controls; + +}; + +#endif // !defined(QmitkRadiomicsStatistic_H__INCLUDED) + + diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsStatisticViewControls.ui b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsStatisticViewControls.ui new file mode 100644 index 0000000000..5fad0f11ce --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsStatisticViewControls.ui @@ -0,0 +1,363 @@ + + + QmitkRadiomicsStatisticViewControls + + + + 0 + 0 + 448 + 980 + + + + Form + + + + + + + + true + + + E&xecute + + + + + + + Execute && Append + + + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 0 + 20 + + + + + + + + + 16777215 + 16777209 + + + + 0 + + + 4 + + + false + + + + Image Name + + + + + Mask Name + + + + + Feature Name + + + + + Feature Values + + + + + + + + + 16777215 + 340 + + + + 1 + + + + Feature Class Selection + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 300 + + + + + 16777215 + 300 + + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustToContents + + + true + + + + + 0 + 0 + 422 + 298 + + + + + + + + + + + Configuration Parameter + + + + + + 0 + + + 0 + + + + + Binning Parameter: + + + + + + + Minimum Intensity + + + + + + + 4 + + + -100000.000000000000000 + + + 1000000.000000000000000 + + + + + + + Maximum Intensity + + + + + + + 4 + + + -100000.000000000000000 + + + 1000000.000000000000000 + + + + + + + Number of bins + + + + + + + 1 + + + 10000 + + + + + + + Bin Size + + + + + + + 6 + + + 0.000001000000000 + + + 1000000000.000000000000000 + + + + + + + Ignore mask for Histogram + + + + + + + + + + + + + + + + + + + + + General Parameter + + + + + + + Encode Parameter in Name + + + + + + + + + + + + + + Direction Parameter + + + + + + + + + + Slice-wise calculation + + + + + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Table to Clipboard + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.cpp b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.cpp new file mode 100644 index 0000000000..1564a26e04 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.cpp @@ -0,0 +1,380 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkRadiomicsTransformationView.h" + +// QT includes (GUI) +#include +#include +#include +#include +#include +#include +#include + +// Berry includes (selection service) +#include +#include + +// MITK includes (GUI) +#include +#include "QmitkDataNodeSelectionProvider.h" +#include "mitkDataNodeObject.h" + +// MITK includes (general +#include +#include +#include +#include +#include + +// Specific GUI Includes +#include "QmitkGIFConfigurationPanel.h" + +QmitkRadiomicsTransformation::QmitkRadiomicsTransformation() +: QmitkAbstractView(), + m_Controls(nullptr) +{ +} + +QmitkRadiomicsTransformation::~QmitkRadiomicsTransformation() +{ + //berry::ISelectionService* s = GetSite()->GetWorkbenchWindow()->GetSelectionService(); + //if(s) + // s->RemoveSelectionListener(m_SelectionListener); +} + +void QmitkRadiomicsTransformation::CreateQtPartControl(QWidget *parent) +{ + if (m_Controls == nullptr) + { + m_Controls = new Ui::QmitkRadiomicsTransformationViewControls; + m_Controls->setupUi(parent); + + QLabel * label1 = new QLabel("Image: "); + QLabel * label2 = new QLabel("Mask: "); + QmitkDataStorageComboBox * cb_inputimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); + m_Controls->m_InputImageGroup->layout()->addWidget(label1); + m_Controls->m_InputImageGroup->layout()->addWidget(cb_inputimage); + + this->CreateConnections(); + } +} + +void QmitkRadiomicsTransformation::CreateConnections() +{ + if ( m_Controls ) + { + connect( (QObject*)(m_Controls->buttonExecuteMultiresolution), SIGNAL(clicked() ), this, SLOT(executeButtonMultiResolutionPressed() ) ); + connect((QObject*)(m_Controls->m_WaveletExecuteButton), SIGNAL(clicked()), this, SLOT(executeButtonWaveletPressed())); + connect((QObject*)(m_Controls->m_ExecuteLOG), SIGNAL(clicked()), this, SLOT(executeButtonLoGPressed())); + connect((QObject*)(m_Controls->buttonResampleImage), SIGNAL(clicked()), this, SLOT(executeButtonResamplingPressed())); + + } +} + +void QmitkRadiomicsTransformation::executeButtonMultiResolutionPressed() +{ + QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); + mitk::BaseData* baseDataRawImage = NULL; + + mitk::Image::Pointer raw_image; + std::string nodeName; + if ((cb_image->GetSelectedNode().IsNotNull() ) ) + { + baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); + nodeName = cb_image->GetSelectedNode()->GetName(); + } + if ((baseDataRawImage != NULL)) + { + raw_image = dynamic_cast(baseDataRawImage); + } + else { + QMessageBox msgBox; + msgBox.setText("Please specify the images that shlould be used."); + msgBox.exec(); + return; + } + if (raw_image.IsNull()) + { + QMessageBox msgBox; + msgBox.setText("Error during processing the specified images."); + msgBox.exec(); + return; + } + + unsigned int numberOfLevels = m_Controls->m_NumberOfLevels->value(); + bool resultAsDouble = m_Controls->m_resultAsDouble->isChecked(); + + auto results = mitk::TransformationOperation::MultiResolution(raw_image, numberOfLevels, resultAsDouble); + unsigned int level = 1; + for (auto image : results) + { + mitk::DataNode::Pointer result = mitk::DataNode::New(); + result->SetProperty("name", mitk::StringProperty::New(nodeName+"::MultiRes::Level-"+us::Any(numberOfLevels-level).ToString())); + result->SetData(image); + GetDataStorage()->Add(result, cb_image->GetSelectedNode()); + ++level; + } +} + +void QmitkRadiomicsTransformation::executeButtonWaveletPressed() +{ + QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); + mitk::BaseData* baseDataRawImage = NULL; + + mitk::Image::Pointer raw_image; + std::string nodeName; + if ((cb_image->GetSelectedNode().IsNotNull())) + { + baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); + nodeName = cb_image->GetSelectedNode()->GetName(); + } + if ((baseDataRawImage != NULL)) + { + raw_image = dynamic_cast(baseDataRawImage); + } + else { + QMessageBox msgBox; + msgBox.setText("Please specify the images that shlould be used."); + msgBox.exec(); + return; + } + if (raw_image.IsNull()) + { + QMessageBox msgBox; + msgBox.setText("Error during processing the specified images."); + msgBox.exec(); + return; + } + + unsigned int numberOfLevels = m_Controls->m_WaveletNumberOfLevels->value(); + unsigned int numberOfBands = m_Controls->m_WaveletNumberOfBands->value(); + mitk::BorderCondition condition = mitk::BorderCondition::Constant; + mitk::WaveletType waveletType = mitk::WaveletType::Held; + + std::string waveletStr = m_Controls->m_WaveletWavelet->currentText().toStdString(); + if (waveletStr == "Shannon") + { + waveletType = mitk::WaveletType::Shannon; + } + if (waveletStr == "Simoncelli") + { + waveletType = mitk::WaveletType::Simoncelli; + } + if (waveletStr == "Vow") + { + waveletType = mitk::WaveletType::Vow; + } + if (waveletStr == "Held") + { + waveletType = mitk::WaveletType::Held; + } + + std::string conditionStr = m_Controls->m_WaveletBorderCondition->currentText().toStdString(); + if (conditionStr == "Constant") + { + condition = mitk::BorderCondition::Constant; + } + if (conditionStr == "Periodic") + { + condition = mitk::BorderCondition::Periodic; + } + if (conditionStr == "Zero Flux Neumann") + { + condition = mitk::BorderCondition::ZeroFluxNeumann; + } + + auto results = mitk::TransformationOperation::WaveletForward(raw_image, numberOfLevels, numberOfBands, condition, waveletType); + unsigned int level = 0; + for (auto image : results) + { + mitk::DataNode::Pointer result = mitk::DataNode::New(); + result->SetProperty("name", mitk::StringProperty::New(nodeName + "::Wavelet::"+waveletStr+"-"+conditionStr+"::Level-" + us::Any(level).ToString())); + result->SetData(image); + GetDataStorage()->Add(result, cb_image->GetSelectedNode()); + ++level; + } + +} + + +void QmitkRadiomicsTransformation::executeButtonLoGPressed() +{ + QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); + mitk::BaseData* baseDataRawImage = NULL; + + mitk::Image::Pointer raw_image; + std::string nodeName; + if ((cb_image->GetSelectedNode().IsNotNull())) + { + baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); + nodeName = cb_image->GetSelectedNode()->GetName(); + } + if ((baseDataRawImage != NULL)) + { + raw_image = dynamic_cast(baseDataRawImage); + } + else { + QMessageBox msgBox; + msgBox.setText("Please specify the images that shlould be used."); + msgBox.exec(); + return; + } + if (raw_image.IsNull()) + { + QMessageBox msgBox; + msgBox.setText("Error during processing the specified images."); + msgBox.exec(); + return; + } + + double sigma = m_Controls->m_LoGSigma->value(); + bool resultAsDouble = m_Controls->m_LogResultAsDouble->isChecked(); + + auto results = mitk::TransformationOperation::LaplacianOfGaussian(raw_image, sigma, resultAsDouble); + mitk::DataNode::Pointer result = mitk::DataNode::New(); + result->SetProperty("name", mitk::StringProperty::New(nodeName + "::LoG::Sigma-" + us::Any(sigma).ToString())); + result->SetData(results); + GetDataStorage()->Add(result, cb_image->GetSelectedNode()); +} + +void QmitkRadiomicsTransformation::executeButtonResamplingPressed() +{ + QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); + mitk::BaseData* baseDataRawImage = NULL; + + mitk::Image::Pointer raw_image; + std::string nodeName; + if ((cb_image->GetSelectedNode().IsNotNull())) + { + baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); + nodeName = cb_image->GetSelectedNode()->GetName(); + } + if ((baseDataRawImage != NULL)) + { + raw_image = dynamic_cast(baseDataRawImage); + } + else { + QMessageBox msgBox; + msgBox.setText("Please specify the images that shlould be used."); + msgBox.exec(); + return; + } + if (raw_image.IsNull()) + { + QMessageBox msgBox; + msgBox.setText("Error during processing the specified images."); + msgBox.exec(); + return; + } + + mitk::ImageMappingInterpolator::Type interpolatorType; + switch (m_Controls->comboInterpolationMode->currentIndex()) + { + case 0: + interpolatorType = mitk::ImageMappingInterpolator::Linear; + break; + + case 1: + interpolatorType = mitk::ImageMappingInterpolator::BSpline_3; + break; + + case 2: + interpolatorType = mitk::ImageMappingInterpolator::NearestNeighbor; + break; + + case 3: + interpolatorType = mitk::ImageMappingInterpolator::WSinc_Hamming; + break; + + case 4: + interpolatorType = mitk::ImageMappingInterpolator::WSinc_Welch; + break; + + default: + interpolatorType = mitk::ImageMappingInterpolator::Linear; + } + + mitk::GridInterpolationPositionType gridPosition; + switch (m_Controls->comboAxisAlignment->currentIndex()) + { + case 0: + gridPosition = mitk::GridInterpolationPositionType::OriginAligned; + break; + + case 1: + gridPosition = mitk::GridInterpolationPositionType::CenterAligned; + break; + + case 2: + gridPosition = mitk::GridInterpolationPositionType::SameSize; + break; + + default: + gridPosition = mitk::GridInterpolationPositionType::OriginAligned; + } + + bool resultAsDouble = m_Controls->checkResamplingOutputAsDouble->isChecked(); + bool roundResult = m_Controls->checkResamplingRoundOutput->isChecked(); + + mitk::Vector3D spacing; + spacing.Fill(-1); + if (m_Controls->checkResampleX->isChecked()) { + spacing[0] = m_Controls->doubleSpinDimensionX->value(); + } + if (m_Controls->checkResampleY->isChecked()) { + spacing[1] = m_Controls->doubleSpinDimensionY->value(); + } + if (m_Controls->checkResampleZ->isChecked()) { + spacing[2] = m_Controls->doubleSpinDimensionZ->value(); + } + + + mitk::Image::Pointer results; + if (m_Controls->checkResampleAsMask->isChecked()) { + results = mitk::TransformationOperation::ResampleMask(raw_image, spacing, interpolatorType, gridPosition); + mitk::LabelSetImage::Pointer oldLabelImage = dynamic_cast (raw_image.GetPointer()); + if (oldLabelImage.IsNotNull()) + { + mitk::LabelSetImage::Pointer labelResult = mitk::LabelSetImage::New(); + labelResult->InitializeByLabeledImage(results); + labelResult->AddLabelSetToLayer(labelResult->GetActiveLayer(), oldLabelImage->GetLabelSet()); + results = dynamic_cast(labelResult.GetPointer()); + } + } + else { + results = mitk::TransformationOperation::ResampleImage(raw_image, spacing, interpolatorType, gridPosition, resultAsDouble, roundResult); + } + mitk::DataNode::Pointer result = mitk::DataNode::New(); + result->SetProperty("name", mitk::StringProperty::New(nodeName + "::Resampled" )); + result->SetData(results); + GetDataStorage()->Add(result, cb_image->GetSelectedNode()); +} + +void QmitkRadiomicsTransformation::SetFocus() +{ +} + +//datamanager selection changed +void QmitkRadiomicsTransformation::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) +{ + //any nodes there? + if (!nodes.empty()) + { + + } +} diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.h b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.h new file mode 100644 index 0000000000..68ae5b0e14 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.h @@ -0,0 +1,99 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#if !defined(QmitkRadiomicsTransformationView_H__INCLUDED) +#define QmitkRadiomicsTransformationView_H__INCLUDED + +#include +#include +#include "ui_QmitkRadiomicsTransformationViewControls.h" + +#include "QmitkStepperAdapter.h" + +#include +#include + +/*! +\brief This module allows to use some basic image processing filters for preprocessing, image enhancement and testing purposes + +Several basic ITK image processing filters, like denoising, morphological and edge detection +are encapsulated in this module and can be selected via a list and an intuitive parameter input. +The selected filter will be applied on the image, and a new image showing the output is displayed +as result. +Also, some image arithmetic operations are available. + +Images can be 3D or 4D. +In the 4D case, the filters work on the 3D image selected via the +time slider. The result is also a 3D image. + +\class QmitkRadiomicsTransformation +\author Tobias Schwarz +\version 1.0 (3M3) +\date 2009-05-10 +\ingroup Bundles +*/ + +class RADIOMICS_EXPORT QmitkRadiomicsTransformation : public QmitkAbstractView +{ + Q_OBJECT + +public: + + /*! + \brief default constructor + */ + QmitkRadiomicsTransformation(); + + /*! + \brief default destructor + */ + virtual ~QmitkRadiomicsTransformation(); + + /*! + \brief method for creating the widget containing the application controls, like sliders, buttons etc. + */ + virtual void CreateQtPartControl(QWidget *parent) override; + + virtual void SetFocus() override; + + /*! + \brief method for creating the connections of main and control widget + */ + virtual void CreateConnections(); + + /*! + \brief Invoked when the DataManager selection changed + */ + virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; + + + protected slots: + void executeButtonMultiResolutionPressed(); + void executeButtonWaveletPressed(); + void executeButtonLoGPressed(); + void executeButtonResamplingPressed(); + +private: + /*! + * controls containing sliders for scrolling through the slices + */ + Ui::QmitkRadiomicsTransformationViewControls *m_Controls; + +}; + +#endif // !defined(QmitkRadiomicsTransformation_H__INCLUDED) + + diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationViewControls.ui b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationViewControls.ui new file mode 100644 index 0000000000..4dcd715d4f --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationViewControls.ui @@ -0,0 +1,506 @@ + + + QmitkRadiomicsTransformationViewControls + + + + 0 + 0 + 448 + 980 + + + + Form + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 0 + + + + + 0 + 0 + 430 + 846 + + + + Multi-Resolution Pyramid + + + + + + + + + + Number of Levels: + + + + + + + 1 + + + + + + + Return result as double: + + + + + + + + + + true + + + + + + + + + true + + + Execute Multi-Resolution Pyramid + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Resample Image + + + + + + + + + + Dimension X + + + true + + + + + + + Dimension Y + + + true + + + + + + + Dimension Z + + + true + + + + + + + 7 + + + 40000000.000000000000000 + + + + + + + 7 + + + 40000000.000000000000000 + + + + + + + 7 + + + 40000000.000000000000000 + + + + + + + Interpolation mode + + + + + + + Grid alignment method + + + + + + + + Linear + + + + + B-Spline + + + + + Nearest Neighbour + + + + + WSinc Hamming + + + + + WSinc Welch + + + + + + + + + Origin aligned + + + + + Center aligned + + + + + Same size (adapts final dimension) + + + + + + + + Output as double + + + + + + + Resample as mask + + + + + + + Round output + + + + + + + + + Resample Image + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 0 + 0 + 430 + 846 + + + + Wavelet Transformation + + + + + + + + + + Number of Levels: + + + + + + + 1 + + + 20000 + + + + + + + Number of Bands: + + + + + + + 1 + + + 2000 + + + + + + + Border Condition: + + + + + + + Wavelet: + + + + + + + + Constant + + + + + Periodic + + + + + Zero Flux Neumann + + + + + + + + + Shannon + + + + + Simoncelli + + + + + Vow + + + + + Held + + + + + + + + + + + + Execute Wavelet Transformation + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 0 + 0 + 430 + 846 + + + + Laplacian of Gaussian + + + + + + + + + + 4 + + + 1.000000000000000 + + + 1000000000000.000000000000000 + + + + + + + Gaussian Sigma: + + + + + + + Return result as double: + + + + + + + + + + true + + + + + + + + + Execute Laplacian of Gaussian + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/mitkBasicImageProcessingActivator.cpp b/Plugins/org.mitk.gui.qt.radiomics/src/internal/mitkBasicImageProcessingActivator.cpp new file mode 100644 index 0000000000..fb8849cfb4 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/mitkBasicImageProcessingActivator.cpp @@ -0,0 +1,38 @@ +/*=================================================================== + +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 "mitkBasicImageProcessingActivator.h" +#include "QmitkRadiomicsStatisticView.h" +#include "QmitkRadiomicsTransformationView.h" +#include "QmitkRadiomicsArithmetricView.h" +#include "QmitkRadiomicsMaskProcessingView.h" + +namespace mitk { + +void RadiomicsStatisticActivator::start(ctkPluginContext* context) +{ + BERRY_REGISTER_EXTENSION_CLASS(QmitkRadiomicsStatistic, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkRadiomicsTransformation, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkRadiomicsArithmetric, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkRadiomicsMaskProcessing, context) +} + +void RadiomicsStatisticActivator::stop(ctkPluginContext* context) +{ + Q_UNUSED(context) +} + +} diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/mitkBasicImageProcessingActivator.h b/Plugins/org.mitk.gui.qt.radiomics/src/internal/mitkBasicImageProcessingActivator.h new file mode 100644 index 0000000000..ceed7a5396 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/mitkBasicImageProcessingActivator.h @@ -0,0 +1,43 @@ +/*=================================================================== + +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 MITKRadiomicsStatisticACTIVATOR_H +#define MITKRadiomicsStatisticACTIVATOR_H + +#include + +namespace mitk { + +class RadiomicsStatisticActivator : + public QObject, public ctkPluginActivator +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_radiomicsstatistic") + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_radiomicstransformation") + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_radiomicsarithmetric") + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_radiomicsmaskprocessing") + Q_INTERFACES(ctkPluginActivator) + +public: + + void start(ctkPluginContext* context) override; + void stop(ctkPluginContext* context) override; + +}; // RadiomicsStatisticActivator + +} + +#endif // MITKRadiomicsStatisticACTIVATOR_H