diff --git a/Modules/Classification/CLUtilities/files.cmake b/Modules/Classification/CLUtilities/files.cmake index 17b04b392f..64e037b845 100644 --- a/Modules/Classification/CLUtilities/files.cmake +++ b/Modules/Classification/CLUtilities/files.cmake @@ -1,38 +1,39 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkCLResultWritter.cpp Algorithms/itkLabelSampler.cpp Algorithms/itkSmoothedClassProbabilites.cpp Algorithms/mitkRandomImageSampler.cpp Features/itkNeighborhoodFunctorImageFilter.cpp Features/itkLineHistogramBasedMassImageFilter.cpp GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp + GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp GlobalImageFeatures/mitkGIFNeighbourhoodGreyLevelDifference.cpp GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp GlobalImageFeatures/mitkGIFLocalIntensity.cpp GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp GlobalImageFeatures/mitkGIFCurvatureStatistic.cpp MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp MiniAppUtils/mitkSplitParameterToVector.cpp mitkCLUtil.cpp ) set( TOOL_FILES ) diff --git a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h new file mode 100644 index 0000000000..9f28cde2d6 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h @@ -0,0 +1,156 @@ +/*=================================================================== + +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 mitkGIFFirstOrderStatistics_h +#define mitkGIFFirstOrderStatistics_h + +#include +#include +#include + +namespace mitk +{ + class MITKCLUTILITIES_EXPORT GIFFirstOrderNumericStatistics : public AbstractGlobalImageFeature + { + public: + /** + * \brief Calculates first order statistics of the given image. + * + * The first order statistics for the intensity distribution within a given Region of Interest (ROI) + * is caluclated. The ROI is defined using a mask. + * + * The features are calculated on a quantified image. If the bin-size is too big, the obtained values + * can be errornous and missleading. It is therefore important to use enough bins. The binned approach is + * used in order to avoid floating-point related errors. + * + * This feature calculator is activated by the option -first-order or -fo. + * + * The connected areas are based on the binned image, the binning parameters can be set via the default + * parameters as described in AbstractGlobalImageFeature. It is also possible to determine the + * dimensionality of the neighbourhood using direction-related commands as described in AbstractGlobalImageFeature. + * No other options are possible beside these two options. + * + * The features are calculated based on a mask. It is assumed that the mask is + * of the type of an unsigned short image. All voxels with the value 1 are treated as masked. + * + * The following features are then defined using the (binned) voxel intensity \f$ x_i \f$ of each voxel, the probability + * an intensity \f$ p_x \f$, and the overall number of voxels within the mask \f$ N_v \f$: + * - First Order::Mean: The mean intensity within the ROI + * \f[ \textup{Mean}= \mu = \frac{1}{N_v} \sum x_i \f] + * - First Order::Unbiased Variance: An unbiased estimation of the variance: + * \f[ \textup{Unbiased Variance} = \frac{1}{N_v - 1} \sum \left( x_i - \mu \right)^2 \f] + * - First Order::Biased Variance: An biased estimation of the variance. If not specified otherwise, this is + * used as the variance: + * \f[ \textup{Biased Variance} = \sigma^2 = \frac{1}{N_v} \sum \left( x_i - \mu \right)^2 \f] + * - First Order::Unbiased Standard Deviation: Estimation of diversity within the intensity values + * \f[ \textup{Unbiased Standard Deviation} = \sqrt{\frac{1}{N_v-1} \sum \left( x_i - \mu \right)^2} \f] + * - First Order::Biased Standard Deviation: Estimation of diversity within the intensity values + * \f[ \textup{Biased Standard Deviation} = \sigma = \sqrt{\frac{1}{N_v} \sum \left( x_i - \mu \right)^2} \f] + * - First Order::Skewness: + * \f[ \textup{Skewness} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^3}{\sigma^3} \f] + * - First Order::Kurtosis: The kurtosis is a measurement of the peakness of the given + * distirbution: + * \f[ \textup{Kurtosis} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^4}{\sigma^4} \f] + * - First Order::Excess Kurtosis: The kurtosis is a measurement of the peakness of the given + * distirbution. The excess kurtosis is similar to the kurtosis, but is corrected by a fisher correction, + * ensuring that a gaussian distribution has an excess kurtosis of 0. + * \f[ \textup{Excess Kurtosis} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^4}{\sigma^4} - 3 \f] + * - First Order::Median: The median is defined as the median of the all intensities in the ROI. + * - First Order::Minimum: The minimum is defined as the minimum of the all intensities in the ROI. + * - First Order::05th Percentile: \f$ P_{5\%} \f$ The 5% percentile. 5% of all voxel do have this or a lower intensity. + * - First Order::10th Percentile: \f$ P_{10\%} \f$ The 10% percentile. 10% of all voxel do have this or a lower intensity. + * - First Order::15th Percentile: \f$ P_{15\%} \f$ The 15% percentile. 15% of all voxel do have this or a lower intensity. + * - First Order::20th Percentile: \f$ P_{20\%} \f$ The 20% percentile. 20% of all voxel do have this or a lower intensity. + * - First Order::25th Percentile: \f$ P_{25\%} \f$ The 25% percentile. 25% of all voxel do have this or a lower intensity. + * - First Order::30th Percentile: \f$ P_{30\%} \f$ The 30% percentile. 30% of all voxel do have this or a lower intensity. + * - First Order::35th Percentile: \f$ P_{35\%} \f$ The 35% percentile. 35% of all voxel do have this or a lower intensity. + * - First Order::40th Percentile: \f$ P_{40\%} \f$ The 40% percentile. 40% of all voxel do have this or a lower intensity. + * - First Order::45th Percentile: \f$ P_{45\%} \f$ The 45% percentile. 45% of all voxel do have this or a lower intensity. + * - First Order::50th Percentile: \f$ P_{50\%} \f$ The 50% percentile. 50% of all voxel do have this or a lower intensity. + * - First Order::55th Percentile: \f$ P_{55\%} \f$ The 55% percentile. 55% of all voxel do have this or a lower intensity. + * - First Order::60th Percentile: \f$ P_{60\%} \f$ The 60% percentile. 60% of all voxel do have this or a lower intensity. + * - First Order::65th Percentile: \f$ P_{65\%} \f$ The 65% percentile. 65% of all voxel do have this or a lower intensity. + * - First Order::70th Percentile: \f$ P_{70\%} \f$ The 70% percentile. 70% of all voxel do have this or a lower intensity. + * - First Order::75th Percentile: \f$ P_{75\%} \f$ The 75% percentile. 75% of all voxel do have this or a lower intensity. + * - First Order::80th Percentile: \f$ P_{80\%} \f$ The 80% percentile. 80% of all voxel do have this or a lower intensity. + * - First Order::85th Percentile: \f$ P_{85\%} \f$ The 85% percentile. 85% of all voxel do have this or a lower intensity. + * - First Order::90th Percentile: \f$ P_{90\%} \f$ The 90% percentile. 90% of all voxel do have this or a lower intensity. + * - First Order::95th Percentile: \f$ P_{95\%} \f$ The 95% percentile. 95% of all voxel do have this or a lower intensity. + * - First Order::Maximum: The maximum is defined as the minimum of the all intensities in the ROI. + * - First Order::Range: The range of intensity values is defined as the difference between the maximum + * and minimum intensity in the ROI. + * - First Order::Interquartile Range: The difference between the 75% and 25% quantile. + * - First Order::Mean Absolute Deviation: The mean absolute deviation gives the mean distance of each + * voxel intensity to the overal mean intensity and is a measure of the dispersion of the intensity form the + * mean value: + * \f[ \textup{Mean Absolute Deviation} = \frac{1}{N_v} \sum \left \| x_i - \mu \right \| \f] + * - First Order::Robust Mean: The mean intensity within the ROI for all voxels between the 10% and 90% quantile: + * \f[ \textup{Robust Mean}= \mu_R = \frac{1}{N_{vr}} \sum x_i \f] + * - First Order::Robust Mean Absolute Deviation: The absolute deviation of all intensities within the ROI for + * all voxels between the 10% and 90% quantilefrom the robust mean intensity: + * \f[ \textup{Robust Mean Absolute Deviation}= \mu_R = \frac{1}{N_{vr}} \sum \left \| x_i - \mu_R \right \| \f] + * - First Order::Median Absolute Deviation: Similar to the mean absolute deviation, but uses the median + * instead of the mean to measure the center of the distribution. + * - First Order::Coefficient Of Variation: Measures the dispersion of the intensity distribution: + * \f[ \textup{Coefficient Of Variation} = \frac{sigma}{\mu} \f] + * - First Order::Quantile Coefficient Of Dispersion: A robust alternative to teh coefficient of variance: + * \f[ \textup{Quantile Coefficient Of Dispersion} = \frac{P_{75\%} - P_{25\%} }{P_{75\%} + P_{25\%}} \f] + * - First Order::Energy: The intensity energy: + * \f[ \textup{Energy} = \sum x_i ^2 \f] + * - First Order::Root Mean Square: Root mean square is an important measure for the error. + * \f[ \textup{Root Mean Square} = \sqrt{\frac{\sum x_i ^2}{N_v}} \f] + * - First Order::Uniformity: + * \f[ \textup{Uniformity} = \sum p_x^2 \f] + * - First Order::Entropy: + * \f[ \textup{Entropy} = - \sum p_x \textup{log}_2(p_x) \f] + * - First Order::Entropy: + * \f[ \textup{Entropy} = - \sum p_x \textup{log}_2(p_x) \f] + * - First Order::Covered Image Intensity Range: Percentage of the image intensity range (maximum - minimum in whole + * image) that is covered by the ROI. + * - First Order::Sum: The sum of all intensities. It is correlated to the mean intensity. + * \f[ \textup{Sum} = \sum x_i \f] + * - First Order::Mode: The most common intensity. + * - First Order::Mode Probability: The likelihood of the most common intensity. + * - First Order::Number Of Voxels: \f$ N_v \f$ the number of voxels covered by the ROI. + * - First Order::Image Dimension: The dimensionality of the image (e.g. 2D, 3D, etc.). + * - First Order::Number Of Voxels: The product of all spacing along all dimensions. In 3D, this is equal to the + * volume. + * - First Order::Number Of Voxels: The volume of a single voxel. If the dimensionality is only 2D, this is the + * surface of an voxel. + */ + mitkClassMacro(GIFFirstOrderNumericStatistics,AbstractGlobalImageFeature) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + GIFFirstOrderNumericStatistics(); + + /** + * \brief Calculates the First Order Features based on a binned version of the image. + */ + FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + + /** + * \brief Returns a list of the names of all features that are calculated from this class + */ + FeatureNameListType GetFeatureNames() override; + virtual std::string GetCurrentFeatureEncoding() override; + + virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); + virtual void AddArguments(mitkCommandLineParser &parser); + + }; +} +#endif //mitkGIFFirstOrderStatistics_h diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp new file mode 100644 index 0000000000..661da77654 --- /dev/null +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp @@ -0,0 +1,358 @@ +/*=================================================================== + +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 modeValue = 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 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 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/test/files.cmake b/Modules/Classification/CLUtilities/test/files.cmake index 4dc57754cc..579c0e0670 100644 --- a/Modules/Classification/CLUtilities/test/files.cmake +++ b/Modules/Classification/CLUtilities/test/files.cmake @@ -1,16 +1,18 @@ set(MODULE_TESTS mitkGIFCooc2Test mitkGIFCurvatureStatisticTest mitkGIFFirstOrderHistogramStatisticsTest + mitkGIFFirstOrderNumericStatisticsTest + mitkGIFFirstOrderStatisticsTest mitkGIFGreyLevelDistanceZoneTest mitkGIFGreyLevelSizeZoneTest mitkGIFImageDescriptionFeaturesTest mitkGIFIntensityVolumeHistogramTest mitkGIFLocalIntensityTest mitkGIFNeighbourhoodGreyToneDifferenceFeaturesTest mitkGIFNeighbouringGreyLevelDependenceFeatureTest mitkGIFVolumetricDensityStatisticsTest mitkGIFVolumetricStatisticsTest #mitkSmoothedClassProbabilitesTest.cpp #mitkGlobalFeaturesTest.cpp ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp new file mode 100644 index 0000000000..31bac39039 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp @@ -0,0 +1,113 @@ +/*=================================================================== + +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 "mitkIOUtil.h" +#include + +#include + +class mitkGIFFirstOrderNumericStatisticsTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkGIFFirstOrderNumericStatisticsTestSuite); + + MITK_TEST(ImageDescription_PhantomTest); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::Image::Pointer m_IBSI_Phantom_Image_Small; + mitk::Image::Pointer m_IBSI_Phantom_Image_Large; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; + +public: + + void setUp(void) override + { + m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); + m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); + m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); + m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); + } + + void ImageDescription_PhantomTest() + { + mitk::GIFFirstOrderNumericStatistics::Pointer featureCalculator = mitk::GIFFirstOrderNumericStatistics::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1.0); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 50 features.", std::size_t(50), featureList.size()); + + // These values are obtained by a run of the filter. + // The might be wrong! + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mean with Large IBSI Phantom Image", 2.15, results["First Order Numeric::Mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Variance with Large IBSI Phantom Image", 3.05, results["First Order Numeric::Variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Skewness with Large IBSI Phantom Image", 1.08, results["First Order Numeric::Skewness"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Excess kurtosis with Large IBSI Phantom Image", -0.355, results["First Order Numeric::Excess kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Median with Large IBSI Phantom Image", 1, results["First Order Numeric::Median"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Minimum with Large IBSI Phantom Image", 1, results["First Order Numeric::Minimum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::10th Percentile with Large IBSI Phantom Image", 1, results["First Order Numeric::10th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::90th Percentile with Large IBSI Phantom Image", 4, results["First Order Numeric::90th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Maximum with Large IBSI Phantom Image", 6, results["First Order Numeric::Maximum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Interquantile range with Large IBSI Phantom Image", 3, results["First Order Numeric::Interquantile range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Range with Large IBSI Phantom Image", 5, results["First Order Numeric::Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mean absolute deviation with Large IBSI Phantom Image", 1.55, results["First Order Numeric::Mean absolute deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust mean absolute deviation with Large IBSI Phantom Image", 1.11, results["First Order Numeric::Robust mean absolute deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Median absolute deviation with Large IBSI Phantom Image", 1.15, results["First Order Numeric::Median absolute deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Coefficient of variation with Large IBSI Phantom Image", 0.812, results["First Order Numeric::Coefficient of variation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Quantile coefficient of dispersion with Large IBSI Phantom Image", 0.6, results["First Order Numeric::Quantile coefficient of dispersion"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Energy with Large IBSI Phantom Image", 567, results["First Order Numeric::Energy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Root mean square with Large IBSI Phantom Image", 2.77, results["First Order Numeric::Root mean square"], 0.01); + + + // These values are taken from the IBSI Initiative to ensure compatibility + // The values are given with an accuracy of 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Standard Deviation with Large IBSI Phantom Image", 1.74513, results["First Order Numeric::Standard Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Kurtosis with Large IBSI Phantom Image", 2.64538, results["First Order Numeric::Kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust mean with Large IBSI Phantom Image", 1.74627, results["First Order Numeric::Robust mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust variance with Large IBSI Phantom Image", 1.65204, results["First Order Numeric::Robust variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Covered image intensity range with Large IBSI Phantom Image", 0.83333, results["First Order Numeric::Covered image intensity range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode index with Large IBSI Phantom Image",0 , results["First Order Numeric::Mode index"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode value with Large IBSI Phantom Image", 1, results["First Order Numeric::Mode value"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode probability with Large IBSI Phantom Image", 0.675676, results["First Order Numeric::Mode probability"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Entropy with Large IBSI Phantom Image", -1.26561, results["First Order Numeric::Entropy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Uniformtiy with Large IBSI Phantom Image", 0.512418, results["First Order Numeric::Uniformtiy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Number of voxels with Large IBSI Phantom Image", 74 , results["First Order Numeric::Number of voxels"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Sum of voxels with Large IBSI Phantom Image", 159, results["First Order Numeric::Sum of voxels"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Voxel space with Large IBSI Phantom Image", 8, results["First Order Numeric::Voxel space"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Voxel volume with Large IBSI Phantom Image", 8, results["First Order Numeric::Voxel volume"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Image Dimension with Large IBSI Phantom Image", 3, results["First Order Numeric::Image Dimension"], 0.01); + + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderNumericStatistics ) \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp new file mode 100644 index 0000000000..d6af72b9a8 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp @@ -0,0 +1,112 @@ +/*=================================================================== + +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 "mitkIOUtil.h" +#include + +#include + +class mitkGIFFirstOrderStatisticsTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkGIFFirstOrderStatisticsTestSuite); + + MITK_TEST(ImageDescription_PhantomTest); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::Image::Pointer m_IBSI_Phantom_Image_Small; + mitk::Image::Pointer m_IBSI_Phantom_Image_Large; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; + +public: + + void setUp(void) override + { + m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); + m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); + m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); + m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); + } + + void ImageDescription_PhantomTest() + { + mitk::GIFFirstOrderStatistics::Pointer featureCalculator = mitk::GIFFirstOrderStatistics::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 50 features.", std::size_t(50), featureList.size()); + + // These values are obtained by a run of the filter. + // The might be wrong! + + + // These values are taken from the IBSI Initiative to ensure compatibility + // The values are given with an accuracy of 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mean with Large IBSI Phantom Image", 2.15, results["First Order::Mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Unbiased Variance with Large IBSI Phantom Image", 3.09, results["First Order::Unbiased Variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Biased Variance with Large IBSI Phantom Image", 3.05, results["First Order::Biased Variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Skewness with Large IBSI Phantom Image", 1.08, results["First Order::Skewness"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Kurtosis with Large IBSI Phantom Image", 2.65, results["First Order::Kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Median with Large IBSI Phantom Image", 1, results["First Order::Median"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Minimum with Large IBSI Phantom Image", 1, results["First Order::Minimum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Maximum with Large IBSI Phantom Image", 6, results["First Order::Maximum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Range with Large IBSI Phantom Image", 5, results["First Order::Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mean Absolute Deviation with Large IBSI Phantom Image", 1.55, results["First Order::Mean Absolute Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Robust Mean Absolute Deviation with Large IBSI Phantom Image", 1.11, results["First Order::Robust Mean Absolute Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Median Absolute Deviation with Large IBSI Phantom Image", 1.15, results["First Order::Median Absolute Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Coefficient of variation with Large IBSI Phantom Image", 0.812, results["First Order::Coefficient Of Variation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Quantile coefficient of dispersion with Large IBSI Phantom Image", 0.625, results["First Order::Quantile Coefficient Of Dispersion"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Energy with Large IBSI Phantom Image", 567, results["First Order::Energy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Root mean square with Large IBSI Phantom Image", 2.77, results["First Order::Root Mean Square"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Entropy with Large IBSI Phantom Image", 1.26561, results["First Order::Entropy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Excess Kurtosis with Large IBSI Phantom Image", -0.35462, results["First Order::Excess Kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Covered image intensity range with Large IBSI Phantom Image", 0.5555555, results["First Order::Covered Image Intensity Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Sum of voxels with Large IBSI Phantom Image", 159, results["First Order::Sum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mode with Large IBSI Phantom Image", 1, results["First Order::Mode"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mode Probability with Large IBSI Phantom Image", 50, results["First Order::Mode Probability"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Unbiased Standard deviation with Large IBSI Phantom Image", 1.757, results["First Order::Unbiased Standard deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Biased Standard deviation with Large IBSI Phantom Image", 1.74627, results["First Order::Biased Standard deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Robust mean with Large IBSI Phantom Image", 1.74627, results["First Order::Robust Mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Number Of Voxels with Large IBSI Phantom Image", 74, results["First Order::Number Of Voxels"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::10th Percentile with Large IBSI Phantom Image", 0.648, results["First Order::10th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::90th Percentile with Large IBSI Phantom Image", 4.475, results["First Order::90th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Interquantile Range with Large IBSI Phantom Image", 2.91125, results["First Order::Interquartile Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Voxel Space with Large IBSI Phantom Image", 8, results["First Order::Voxel Space"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Voxel Volume with Large IBSI Phantom Image", 8, results["First Order::Voxel Volume"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Image Dimension with Large IBSI Phantom Image", 3, results["First Order::Image Dimension"], 0.01); + + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderStatistics ) \ No newline at end of file