diff --git a/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h b/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h index 30ecaea6ff..6b2ee9bc06 100644 --- a/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h +++ b/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h @@ -1,156 +1,261 @@ /*=================================================================== 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 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; itkSetMacro(Prefix, std::string); itkSetMacro(ShortName, std::string); itkSetMacro(LongName, 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(Parameter, ParameterTypes); itkSetMacro(UseQuantifier, bool); itkGetConstMacro(UseQuantifier, bool); itkSetMacro(Quantifier, IntensityQuantifier::Pointer); itkGetMacro(Quantifier, IntensityQuantifier::Pointer); itkGetConstMacro(Direction, int); - itkSetMacro(MinimumIntensity, float); + itkSetMacro(MinimumIntensity, double); itkSetMacro(UseMinimumIntensity, bool); - itkSetMacro(MaximumIntensity, float); + itkSetMacro(MaximumIntensity, double); itkSetMacro(UseMaximumIntensity, bool); - itkGetConstMacro(MinimumIntensity, float); + itkGetConstMacro(MinimumIntensity, double); itkGetConstMacro(UseMinimumIntensity, bool); - itkGetConstMacro(MaximumIntensity, float); + 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); + 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 InitializeQuantifier(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList, unsigned int defaultBins = 256); + 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); public: //#ifndef DOXYGEN_SKIP virtual void SetRequestedRegionToLargestPossibleRegion() override {}; virtual bool RequestedRegionIsOutsideOfTheBufferedRegion() override { return true; }; virtual bool VerifyRequestedRegion() override { return false; }; virtual void SetRequestedRegion (const itk::DataObject * /*data*/) override {}; // Override virtual 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) 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; + double m_Binsize = 1; + bool m_UseBinsize = false; int m_Bins = 256; + bool m_UseBins = true; int m_Direction = 0; + bool m_IgnoreMask = false; + mitk::Image::Pointer m_MorphMask = nullptr; //#endif // Skip Doxygen }; } #endif //mitkAbstractGlobalImageFeature_h diff --git a/Modules/Classification/CLCore/include/mitkIntensityQuantifier.h b/Modules/Classification/CLCore/include/mitkIntensityQuantifier.h index a9c51b301f..306848c10b 100644 --- a/Modules/Classification/CLCore/include/mitkIntensityQuantifier.h +++ b/Modules/Classification/CLCore/include/mitkIntensityQuantifier.h @@ -1,87 +1,95 @@ /*=================================================================== 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 mitkIntensityQuantifier_h #define mitkIntensityQuantifier_h #include #include #include namespace mitk { class MITKCLCORE_EXPORT IntensityQuantifier : public BaseData { public: mitkClassMacro(IntensityQuantifier, BaseData) itkFactorylessNewMacro(Self) itkCloneMacro(Self) IntensityQuantifier(); void InitializeByMinimumMaximum(double minimum, double maximum, unsigned int bins); void InitializeByBinsizeAndBins(double minimum, unsigned int bins, double binsize); void InitializeByBinsizeAndMaximum(double minimum, double maximum, double binsize); void InitializeByImage(mitk::Image::Pointer image, unsigned int bins); + void InitializeByImageAndMaximum(mitk::Image::Pointer image, double maximum, unsigned int bins); + void InitializeByImageAndMinimum(mitk::Image::Pointer image, double minimum, unsigned int bins); void InitializeByImageRegion(mitk::Image::Pointer image, mitk::Image::Pointer mask, unsigned int bins); + void InitializeByImageRegionAndMinimum(mitk::Image::Pointer image, mitk::Image::Pointer mask, double minimum, unsigned int bins); + void InitializeByImageRegionAndMaximum(mitk::Image::Pointer image, mitk::Image::Pointer mask, double maximum, unsigned int bins); void InitializeByImageAndBinsize(mitk::Image::Pointer image, double binsize); + void InitializeByImageAndBinsizeAndMinimum(mitk::Image::Pointer image, double minimum, double binsize); + void InitializeByImageAndBinsizeAndMaximum(mitk::Image::Pointer image, double maximum, double binsize); void InitializeByImageRegionAndBinsize(mitk::Image::Pointer image, mitk::Image::Pointer mask, double binsize); + void InitializeByImageRegionAndBinsizeAndMinimum(mitk::Image::Pointer image, mitk::Image::Pointer mask, double minimum, double binsize); + void InitializeByImageRegionAndBinsizeAndMaximum(mitk::Image::Pointer image, mitk::Image::Pointer mask, double maximum, double binsize); unsigned int IntensityToIndex(double intensity); double IndexToMinimumIntensity(unsigned int index); double IndexToMeanIntensity(unsigned int index); double IndexToMaximumIntensity(unsigned int index); itkGetConstMacro(Initialized, bool); itkGetConstMacro(Bins, unsigned int); itkGetConstMacro(Binsize, double); itkGetConstMacro(Minimum, double); itkGetConstMacro(Maximum, double); public: //#ifndef DOXYGEN_SKIP virtual void SetRequestedRegionToLargestPossibleRegion() override {}; virtual bool RequestedRegionIsOutsideOfTheBufferedRegion() override { return true; }; virtual bool VerifyRequestedRegion() override { return false; }; virtual void SetRequestedRegion (const itk::DataObject * /*data*/) override {}; // Override virtual bool IsEmpty() const override { if(IsInitialized() == false) return true; const TimeGeometry* timeGeometry = const_cast(this)->GetUpdatedTimeGeometry(); if(timeGeometry == nullptr) return true; return false; } private: bool m_Initialized; unsigned int m_Bins; double m_Binsize; double m_Minimum; double m_Maximum; }; } #endif //mitkIntensityQuantifier_h diff --git a/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp b/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp index b991012430..2f6faf580e 100644 --- a/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp +++ b/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp @@ -1,116 +1,173 @@ /*=================================================================== 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 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::InitializeQuantifier(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList, unsigned int defaultBins) + +void mitk::AbstractGlobalImageFeature::InitializeQuantifierFromParameters(const Image::Pointer & feature, const Image::Pointer &mask, unsigned int defaultBins) { - bool useBins = false; unsigned int bins = 0; - - bool useBinsize = false; double binsize = 0; - - bool useMinimum = false; double minimum = 0; - - bool useMaximum = false; double maximum = 0; auto parsedArgs = GetParameter(); std::string name = GetOptionPrefix(); - if (parsedArgs.count("bins")) + bool useGlobal = true; + if (parsedArgs.count(name + "::ignore-global-histogram")) { - bins = us::any_cast(parsedArgs["bins"]); - useBins = true; + useGlobal = false; + SetUseMinimumIntensity(false); + SetUseMaximumIntensity(false); + SetUseBinsize(false); + SetUseBins(false); } - if (parsedArgs.count(name + "::bins")) - { - bins = us::any_cast(parsedArgs[name + "::bins"]); - useBins = true; - } - if (parsedArgs.count("binsize")) - { - binsize = us::any_cast(parsedArgs["binsize"]); - useBinsize = true; - } - if (parsedArgs.count(name + "::binsize")) + + if (useGlobal) { - binsize = us::any_cast(parsedArgs[name + "::binsize"]); - useBinsize = true; + 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("minimum-intensity")) + if (parsedArgs.count(name+"::ignore-mask-for-histogram")) { - minimum = us::any_cast(parsedArgs["minimum-intensity"]); - useMinimum = true; + 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"]); - useMinimum = true; - } - if (parsedArgs.count("maximum-intensity")) - { - maximum = us::any_cast(parsedArgs["maximum-intensity"]); - useMaximum = true; + SetMinimumIntensity(minimum); + SetUseMinimumIntensity(true); } if (parsedArgs.count(name + "::maximum")) { maximum = us::any_cast(parsedArgs[name + "::maximum"]); - useMaximum = true; + 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); +} - MITK_INFO << useMinimum << " " << useMaximum << " " << useBins << " " << useBinsize; +void mitk::AbstractGlobalImageFeature::InitializeQuantifier(const Image::Pointer & feature, const Image::Pointer &mask, unsigned int defaultBins) +{ + MITK_INFO << GetUseMinimumIntensity() << " " << GetUseMaximumIntensity() << " " << GetUseBins() << " " << GetUseBinsize(); m_Quantifier = IntensityQuantifier::New(); - if (useMinimum && useMaximum && useBinsize) - m_Quantifier->InitializeByBinsizeAndMaximum(minimum, maximum, binsize); - else if (useMinimum && useBins && useBinsize) - m_Quantifier->InitializeByBinsizeAndBins(minimum, bins, binsize); - else if (useMinimum && useMaximum && useBins) - m_Quantifier->InitializeByMinimumMaximum(minimum, maximum, bins); - else if (useBinsize) - m_Quantifier->InitializeByImageRegionAndBinsize(feature, mask, binsize); - else if (useBins) - m_Quantifier->InitializeByImageRegion(feature, mask, bins); + 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->InitializeByImage(feature, defaultBins); + m_Quantifier->InitializeByImageRegion(feature, mask, defaultBins); } diff --git a/Modules/Classification/CLCore/src/mitkIntensityQuantifier.cpp b/Modules/Classification/CLCore/src/mitkIntensityQuantifier.cpp index ef731a28b4..9b0bef2d6b 100644 --- a/Modules/Classification/CLCore/src/mitkIntensityQuantifier.cpp +++ b/Modules/Classification/CLCore/src/mitkIntensityQuantifier.cpp @@ -1,151 +1,199 @@ /*=================================================================== 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 // STD #include // ITK #include // MITK #include #include template static void CalculateImageMinMax(itk::Image* itkImage, double &minimum, double &maximum) { typedef itk::Image ImageType; minimum = std::numeric_limits::max(); maximum = std::numeric_limits::lowest(); itk::ImageRegionConstIterator iter(itkImage, itkImage->GetLargestPossibleRegion()); while (!iter.IsAtEnd()) { minimum = std::min(minimum, iter.Get()); maximum = std::max(maximum, iter.Get()); ++iter; } } template static void CalculateImageRegionMinMax(itk::Image* itkImage, mitk::Image::Pointer mask, double &minimum, double &maximum) { typedef itk::Image ImageType; typedef itk::Image MaskType; typename MaskType::Pointer itkMask = MaskType::New(); mitk::CastToItkImage(mask, itkMask); minimum = std::numeric_limits::max(); maximum = std::numeric_limits::lowest(); itk::ImageRegionConstIterator iter(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIterator maskIter(itkMask, itkMask->GetLargestPossibleRegion()); while (!iter.IsAtEnd()) { if (maskIter.Get() > 0) { minimum = std::min(minimum, iter.Get()); maximum = std::max(maximum, iter.Get()); } ++iter; ++maskIter; } } mitk::IntensityQuantifier::IntensityQuantifier() : m_Initialized(false), m_Bins(0), m_Binsize(0), m_Minimum(0), m_Maximum(0) {} void mitk::IntensityQuantifier::InitializeByMinimumMaximum(double minimum, double maximum, unsigned int bins) { m_Minimum = minimum; m_Maximum = maximum; m_Bins = bins; m_Binsize = (maximum - minimum) / bins; m_Initialized = true; } void mitk::IntensityQuantifier::InitializeByBinsizeAndBins(double minimum, unsigned int bins, double binsize) { m_Minimum = minimum; m_Maximum = minimum + bins*binsize; m_Bins = bins; m_Binsize = binsize; m_Initialized = true; } void mitk::IntensityQuantifier::InitializeByBinsizeAndMaximum(double minimum, double maximum, double binsize) { m_Minimum = minimum; m_Bins = std::ceil((maximum - minimum) / binsize); m_Maximum = minimum + m_Bins*binsize; m_Binsize = binsize; m_Initialized = true; } void mitk::IntensityQuantifier::InitializeByImage(mitk::Image::Pointer image, unsigned int bins) { double minimum, maximum; AccessByItk_2(image, CalculateImageMinMax, minimum, maximum); InitializeByMinimumMaximum(minimum, maximum, bins); } +void mitk::IntensityQuantifier::InitializeByImageAndMinimum(mitk::Image::Pointer image, double minimum, unsigned int bins) { + double tmp, maximum; + AccessByItk_2(image, CalculateImageMinMax, tmp, maximum); + InitializeByMinimumMaximum(minimum, maximum, bins); +} + +void mitk::IntensityQuantifier::InitializeByImageAndMaximum(mitk::Image::Pointer image, double maximum, unsigned int bins) { + double minimum, tmp; + AccessByItk_2(image, CalculateImageMinMax, minimum, tmp); + InitializeByMinimumMaximum(minimum, maximum, bins); +} + void mitk::IntensityQuantifier::InitializeByImageRegion(mitk::Image::Pointer image, mitk::Image::Pointer mask, unsigned int bins) { double minimum, maximum; AccessByItk_3(image, CalculateImageRegionMinMax, mask, minimum, maximum); InitializeByMinimumMaximum(minimum, maximum, bins); } +void mitk::IntensityQuantifier::InitializeByImageRegionAndMinimum(mitk::Image::Pointer image, mitk::Image::Pointer mask, double minimum, unsigned int bins) { + double tmp, maximum; + AccessByItk_3(image, CalculateImageRegionMinMax, mask, tmp, maximum); + InitializeByMinimumMaximum(minimum, maximum, bins); +} + +void mitk::IntensityQuantifier::InitializeByImageRegionAndMaximum(mitk::Image::Pointer image, mitk::Image::Pointer mask, double maximum, unsigned int bins) { + double minimum, tmp; + AccessByItk_3(image, CalculateImageRegionMinMax, mask, minimum, tmp); + InitializeByMinimumMaximum(minimum, maximum, bins); +} + void mitk::IntensityQuantifier::InitializeByImageAndBinsize(mitk::Image::Pointer image, double binsize) { double minimum, maximum; AccessByItk_2(image, CalculateImageMinMax, minimum, maximum); InitializeByBinsizeAndMaximum(minimum, maximum, binsize); } +void mitk::IntensityQuantifier::InitializeByImageAndBinsizeAndMinimum(mitk::Image::Pointer image, double minimum, double binsize) { + double tmp, maximum; + AccessByItk_2(image, CalculateImageMinMax, tmp, maximum); + InitializeByBinsizeAndMaximum(minimum, maximum, binsize); +} + +void mitk::IntensityQuantifier::InitializeByImageAndBinsizeAndMaximum(mitk::Image::Pointer image, double maximum, double binsize) { + double minimum, tmp; + AccessByItk_2(image, CalculateImageMinMax, minimum, tmp); + InitializeByBinsizeAndMaximum(minimum, maximum, binsize); +} + void mitk::IntensityQuantifier::InitializeByImageRegionAndBinsize(mitk::Image::Pointer image, mitk::Image::Pointer mask, double binsize) { double minimum, maximum; AccessByItk_3(image, CalculateImageRegionMinMax, mask, minimum, maximum); InitializeByBinsizeAndMaximum(minimum, maximum, binsize); } +void mitk::IntensityQuantifier::InitializeByImageRegionAndBinsizeAndMinimum(mitk::Image::Pointer image, mitk::Image::Pointer mask, double minimum, double binsize) { + double tmp, maximum; + AccessByItk_3(image, CalculateImageRegionMinMax, mask, tmp, maximum); + InitializeByBinsizeAndMaximum(minimum, maximum, binsize); +} + +void mitk::IntensityQuantifier::InitializeByImageRegionAndBinsizeAndMaximum(mitk::Image::Pointer image, mitk::Image::Pointer mask, double maximum, double binsize) { + double minimum, tmp; + AccessByItk_3(image, CalculateImageRegionMinMax, mask, minimum, tmp); + InitializeByBinsizeAndMaximum(minimum, maximum, binsize); +} + unsigned int mitk::IntensityQuantifier::IntensityToIndex(double intensity) { double index = std::floor((intensity - m_Minimum) / m_Binsize); return std::min(index, m_Bins-1); } double mitk::IntensityQuantifier::IndexToMinimumIntensity(unsigned int index) { return index*m_Binsize + m_Minimum; } double mitk::IntensityQuantifier::IndexToMeanIntensity(unsigned int index) { return (index + 0.5) * m_Binsize + m_Minimum; } double mitk::IntensityQuantifier::IndexToMaximumIntensity(unsigned int index) { return (index + 1) * m_Binsize + m_Minimum; } diff --git a/Modules/Classification/CLMRUtilities/include/mitkMRNormLinearStatisticBasedFilter.h b/Modules/Classification/CLMRUtilities/include/mitkMRNormLinearStatisticBasedFilter.h index 4ad3d3f5ae..b092fdfeff 100644 --- a/Modules/Classification/CLMRUtilities/include/mitkMRNormLinearStatisticBasedFilter.h +++ b/Modules/Classification/CLMRUtilities/include/mitkMRNormLinearStatisticBasedFilter.h @@ -1,75 +1,85 @@ /*=================================================================== 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 MRNORMLINEARSTATISTICBASEDFILTER_H #define MRNORMLINEARSTATISTICBASEDFILTER_H #include "mitkCommon.h" #include "MitkCLMRUtilitiesExports.h" #include "mitkImageToImageFilter.h" #include "mitkImageTimeSelector.h" #include "itkImage.h" namespace mitk { //##Documentation //## @brief //## @ingroup Process class MITKCLMRUTILITIES_EXPORT MRNormLinearStatisticBasedFilter : public ImageToImageFilter { public: mitkClassMacro(MRNormLinearStatisticBasedFilter, ImageToImageFilter); itkFactorylessNewMacro(Self); itkCloneMacro(Self); void SetMask( const mitk::Image* mask ); const mitk::Image* GetMask() const; enum NormalizationBase { MEAN, MODE, MEDIAN }; itkGetConstMacro(CenterMode, NormalizationBase); itkSetMacro(CenterMode, NormalizationBase); itkGetConstMacro(IgnoreOutlier, bool); itkSetMacro(IgnoreOutlier, bool); + itkGetConstMacro(TargetValue, double); + itkSetMacro(TargetValue, double); + + itkGetConstMacro(TargetWidth, double); + itkSetMacro(TargetWidth, double); + protected: MRNormLinearStatisticBasedFilter(); ~MRNormLinearStatisticBasedFilter(); virtual void GenerateInputRequestedRegion() override; virtual void GenerateOutputInformation() override; virtual void GenerateData() override; template < typename TPixel, unsigned int VImageDimension > void InternalComputeMask(itk::Image* itkImage); NormalizationBase m_CenterMode; bool m_IgnoreOutlier; + private: + double m_TargetValue; + double m_TargetWidth; + }; } // namespace mitk #endif /* MRNORMLINEARSTATISTICBASEDFILTER_H */ diff --git a/Modules/Classification/CLMRUtilities/src/MRNormalization/mitkMRNormLinearStatisticBasedFilter.cpp b/Modules/Classification/CLMRUtilities/src/MRNormalization/mitkMRNormLinearStatisticBasedFilter.cpp index a8dc779b22..2ae63163e2 100644 --- a/Modules/Classification/CLMRUtilities/src/MRNormalization/mitkMRNormLinearStatisticBasedFilter.cpp +++ b/Modules/Classification/CLMRUtilities/src/MRNormalization/mitkMRNormLinearStatisticBasedFilter.cpp @@ -1,173 +1,173 @@ /*=================================================================== 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 "mitkMRNormLinearStatisticBasedFilter.h" #include "mitkImageToItk.h" #include "mitkImageAccessByItk.h" #include "itkImageRegionIterator.h" // MITK #include #include #include // ITK #include #include mitk::MRNormLinearStatisticBasedFilter::MRNormLinearStatisticBasedFilter() : - m_CenterMode(MRNormLinearStatisticBasedFilter::MEDIAN) +m_CenterMode(MRNormLinearStatisticBasedFilter::MEDIAN), m_TargetValue(0), m_TargetWidth(1) { this->SetNumberOfIndexedInputs(2); this->SetNumberOfRequiredInputs(1); } mitk::MRNormLinearStatisticBasedFilter::~MRNormLinearStatisticBasedFilter() { } void mitk::MRNormLinearStatisticBasedFilter::SetMask( const mitk::Image* mask ) { // Process object is not const-correct so the const_cast is required here Image* nonconstMask = const_cast< mitk::Image * >( mask ); this->SetNthInput(1, nonconstMask ); } const mitk::Image* mitk::MRNormLinearStatisticBasedFilter::GetMask() const { return this->GetInput(1); } void mitk::MRNormLinearStatisticBasedFilter::GenerateInputRequestedRegion() { Superclass::GenerateInputRequestedRegion(); mitk::Image* input = const_cast< mitk::Image * > ( this->GetInput() ); input->SetRequestedRegionToLargestPossibleRegion(); } void mitk::MRNormLinearStatisticBasedFilter::GenerateOutputInformation() { mitk::Image::ConstPointer input = this->GetInput(); mitk::Image::Pointer output = this->GetOutput(); itkDebugMacro(<< "GenerateOutputInformation()"); output->Initialize(input->GetPixelType(), *input->GetTimeGeometry()); output->SetPropertyList(input->GetPropertyList()->Clone()); } template < typename TPixel, unsigned int VImageDimension > void mitk::MRNormLinearStatisticBasedFilter::InternalComputeMask(itk::Image* itkImage) { // Define all necessary Types typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::LabelStatisticsImageFilter FilterType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typename MaskType::Pointer itkMask0 = MaskType::New(); mitk::CastToItkImage(this->GetMask(), itkMask0); typename ImageType::Pointer outImage = ImageType::New(); mitk::CastToItkImage(this->GetOutput(0), outImage); typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); minMaxComputer->SetImage(itkImage); minMaxComputer->Compute(); double min = minMaxComputer->GetMinimum(); double max = minMaxComputer->GetMaximum(); if (m_IgnoreOutlier) { typename FilterType::Pointer labelStatisticsImageFilter = FilterType::New(); labelStatisticsImageFilter->SetUseHistograms(true); labelStatisticsImageFilter->SetHistogramParameters(2048, min, max); labelStatisticsImageFilter->SetInput(itkImage); labelStatisticsImageFilter->SetLabelInput(itkMask0); labelStatisticsImageFilter->Update(); auto histo = labelStatisticsImageFilter->GetHistogram(1); min = histo->Quantile(0, 0.02); max = histo->Quantile(0, 0.98); } typename FilterType::Pointer labelStatisticsImageFilter = FilterType::New(); labelStatisticsImageFilter->SetUseHistograms(true); labelStatisticsImageFilter->SetHistogramParameters(256, min, max); labelStatisticsImageFilter->SetInput( itkImage ); labelStatisticsImageFilter->SetLabelInput(itkMask0); labelStatisticsImageFilter->Update(); double median0 = labelStatisticsImageFilter->GetMedian(1); double mean0 = labelStatisticsImageFilter->GetMean(1); double stddev = labelStatisticsImageFilter->GetSigma(1); double modulo0=0; { auto histo = labelStatisticsImageFilter->GetHistogram(1); double maxFrequency=0; for (auto hIter=histo->Begin();hIter!=histo->End();++hIter) { if (maxFrequency < hIter.GetFrequency()) { maxFrequency = hIter.GetFrequency(); modulo0 = (histo->GetBinMin(0,hIter.GetInstanceIdentifier()) + histo->GetBinMax(0,hIter.GetInstanceIdentifier())) / 2.0; } } } double value0=0; switch (m_CenterMode) { case MRNormLinearStatisticBasedFilter::MEAN: value0=mean0; break; case MRNormLinearStatisticBasedFilter::MEDIAN: value0=median0; break; case MRNormLinearStatisticBasedFilter::MODE: value0=modulo0; break; } - double offset = value0; - double scaling = stddev; + double offset = value0+m_TargetValue; + double scaling = stddev*m_TargetWidth; if (scaling < 0.0001) return; itk::ImageRegionIterator inIter(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionIterator outIter(outImage, outImage->GetLargestPossibleRegion()); while (! inIter.IsAtEnd()) { TPixel value = inIter.Value(); if (m_IgnoreOutlier && (value < min)) { value = min; } else if (m_IgnoreOutlier && (value > max)) { value = max; } outIter.Set((value - offset) / scaling); ++inIter; ++outIter; } } void mitk::MRNormLinearStatisticBasedFilter::GenerateData() { AccessByItk(GetInput(0),InternalComputeMask); } \ No newline at end of file diff --git a/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp b/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp index 12e9735b44..e42ac87323 100644 --- a/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp +++ b/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp @@ -1,747 +1,747 @@ /*=================================================================== 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 mitkCLPolyToNrrd_cpp #define mitkCLPolyToNrrd_cpp #include "time.h" #include #include #include #include "mitkCommandLineParser.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 #include #include #include #include #include "itkNearestNeighborInterpolateImageFunction.h" #include "itkResampleImageFilter.h" #include #include #include "QmitkRegisterClasses.h" #include "QmitkRenderWindow.h" #include "vtkRenderLargeImage.h" #include "vtkPNGWriter.h" typedef itk::Image< double, 3 > FloatImageType; -typedef itk::Image< unsigned char, 3 > MaskImageType; +typedef itk::Image< unsigned short, 3 > MaskImageType; template class punct_facet : public std::numpunct { public: punct_facet(charT sep) : m_Sep(sep) { } protected: charT do_decimal_point() const { return m_Sep; } private: charT m_Sep; }; template void ResampleImage(itk::Image* itkImage, float resolution, mitk::Image::Pointer& newImage) { typedef itk::Image ImageType; typedef itk::ResampleImageFilter ResampleFilterType; typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); auto spacing = itkImage->GetSpacing(); auto size = itkImage->GetLargestPossibleRegion().GetSize(); for (unsigned int i = 0; i < VImageDimension; ++i) { size[i] = size[i] / (1.0*resolution)*(1.0*spacing[i])+1.0; } spacing.Fill(resolution); resampler->SetInput(itkImage); resampler->SetSize(size); resampler->SetOutputSpacing(spacing); resampler->SetOutputOrigin(itkImage->GetOrigin()); resampler->SetOutputDirection(itkImage->GetDirection()); resampler->Update(); newImage->InitializeByItk(resampler->GetOutput()); mitk::GrabItkImageMemory(resampler->GetOutput(), newImage); } template static void CreateNoNaNMask(itk::Image* itkValue, mitk::Image::Pointer mask, mitk::Image::Pointer& newMask) { typedef itk::Image< TPixel, VImageDimension> LFloatImageType; - typedef itk::Image< unsigned char, VImageDimension> LMaskImageType; + typedef itk::Image< unsigned short, VImageDimension> LMaskImageType; typename LMaskImageType::Pointer itkMask = LMaskImageType::New(); mitk::CastToItkImage(mask, itkMask); typedef itk::ImageDuplicator< LMaskImageType > DuplicatorType; typename DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage(itkMask); duplicator->Update(); auto tmpMask = duplicator->GetOutput(); itk::ImageRegionIterator mask1Iter(itkMask, itkMask->GetLargestPossibleRegion()); itk::ImageRegionIterator mask2Iter(tmpMask, tmpMask->GetLargestPossibleRegion()); itk::ImageRegionIterator imageIter(itkValue, itkValue->GetLargestPossibleRegion()); while (!mask1Iter.IsAtEnd()) { mask2Iter.Set(0); if (mask1Iter.Value() > 0) { // Is not NaN if (imageIter.Value() == imageIter.Value()) { mask2Iter.Set(1); } } ++mask1Iter; ++mask2Iter; ++imageIter; } newMask->InitializeByItk(tmpMask); mitk::GrabItkImageMemory(tmpMask, newMask); } template static void ResampleMask(itk::Image* itkMoving, mitk::Image::Pointer ref, mitk::Image::Pointer& newMask) { typedef itk::Image< TPixel, VImageDimension> LMaskImageType; typedef itk::NearestNeighborInterpolateImageFunction< LMaskImageType> NearestNeighborInterpolateImageFunctionType; typedef itk::ResampleImageFilter ResampleFilterType; typename NearestNeighborInterpolateImageFunctionType::Pointer nn_interpolator = NearestNeighborInterpolateImageFunctionType::New(); typename LMaskImageType::Pointer itkRef = LMaskImageType::New(); mitk::CastToItkImage(ref, itkRef); typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); resampler->SetInput(itkMoving); resampler->SetReferenceImage(itkRef); resampler->UseReferenceImageOn(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); newMask->InitializeByItk(resampler->GetOutput()); mitk::GrabItkImageMemory(resampler->GetOutput(), newMask); } static void ExtractSlicesFromImages(mitk::Image::Pointer image, mitk::Image::Pointer mask, mitk::Image::Pointer maskNoNaN, mitk::Image::Pointer morphMask, int direction, std::vector &imageVector, std::vector &maskVector, std::vector &maskNoNaNVector, std::vector &morphMaskVector) { typedef itk::Image< double, 2 > FloatImage2DType; - typedef itk::Image< unsigned char, 2 > MaskImage2DType; + typedef itk::Image< unsigned short, 2 > MaskImage2DType; FloatImageType::Pointer itkFloat = FloatImageType::New(); MaskImageType::Pointer itkMask = MaskImageType::New(); MaskImageType::Pointer itkMaskNoNaN = MaskImageType::New(); MaskImageType::Pointer itkMorphMask = MaskImageType::New(); mitk::CastToItkImage(mask, itkMask); mitk::CastToItkImage(maskNoNaN, itkMaskNoNaN); mitk::CastToItkImage(image, itkFloat); mitk::CastToItkImage(morphMask, itkMorphMask); 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(); MaskImage2DType::Pointer masnNoNaN2D = MaskImage2DType::New(); masnNoNaN2D->SetRegions(region); masnNoNaN2D->Allocate(); MaskImage2DType::Pointer morph2D = MaskImage2DType::New(); morph2D->SetRegions(region); morph2D->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)); masnNoNaN2D->SetPixel(index2D, itkMaskNoNaN->GetPixel(index3D)); morph2D->SetPixel(index2D, itkMorphMask->GetPixel(index3D)); voxelsInMask += (itkMask->GetPixel(index3D) > 0) ? 1 : 0; } } image2D->SetSpacing(spacing2D); mask2D->SetSpacing(spacing2D); masnNoNaN2D->SetSpacing(spacing2D); morph2D->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); mitk::Image::Pointer tmpMaskNoNaNImage = mitk::Image::New(); tmpMaskNoNaNImage->InitializeByItk(masnNoNaN2D.GetPointer()); mitk::GrabItkImageMemory(masnNoNaN2D, tmpMaskNoNaNImage); mitk::Image::Pointer tmpMorphMaskImage = mitk::Image::New(); tmpMorphMaskImage->InitializeByItk(morph2D.GetPointer()); mitk::GrabItkImageMemory(morph2D, tmpMorphMaskImage); if (voxelsInMask > 0) { imageVector.push_back(tmpFloatImage); maskVector.push_back(tmpMaskImage); maskNoNaNVector.push_back(tmpMaskNoNaNImage); morphMaskVector.push_back(tmpMorphMaskImage); } } } static void SaveSliceOrImageAsPNG(mitk::Image::Pointer image, mitk::Image::Pointer mask, std::string path, int index) { // Create a Standalone Datastorage for the single purpose of saving screenshots.. mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); QmitkRenderWindow renderWindow; renderWindow.GetRenderer()->SetDataStorage(ds); auto nodeI = mitk::DataNode::New(); nodeI->SetData(image); auto nodeM = mitk::DataNode::New(); nodeM->SetData(mask); ds->Add(nodeI); ds->Add(nodeM); mitk::TimeGeometry::Pointer geo = ds->ComputeBoundingGeometry3D(ds->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews(geo); mitk::SliceNavigationController::Pointer sliceNaviController = renderWindow.GetSliceNavigationController(); unsigned int numberOfSteps = 1; if (sliceNaviController) { numberOfSteps = sliceNaviController->GetSlice()->GetSteps(); sliceNaviController->GetSlice()->SetPos(0); } renderWindow.show(); renderWindow.resize(256, 256); for (unsigned int currentStep = 0; currentStep < numberOfSteps; ++currentStep) { if (sliceNaviController) { sliceNaviController->GetSlice()->SetPos(currentStep); } renderWindow.GetRenderer()->PrepareRender(); vtkRenderWindow* renderWindow2 = renderWindow.GetVtkRenderWindow(); mitk::BaseRenderer* baserenderer = mitk::BaseRenderer::GetInstance(renderWindow2); auto vtkRender = baserenderer->GetVtkRenderer(); vtkRender->GetRenderWindow()->WaitForCompletion(); vtkRenderLargeImage* magnifier = vtkRenderLargeImage::New(); magnifier->SetInput(vtkRender); magnifier->SetMagnification(3.0); std::stringstream ss; ss << path << "_Idx-" << index << "_Step-"<> tmpImageName; auto fileWriter = vtkPNGWriter::New(); fileWriter->SetInputConnection(magnifier->GetOutputPort()); fileWriter->SetFileName(tmpImageName.c_str()); fileWriter->Write(); fileWriter->Delete(); } } int main(int argc, char* argv[]) { - mitk::GIFImageDescriptionFeatures::Pointer ipCalculator = mitk::GIFImageDescriptionFeatures::New(); - mitk::GIFFirstOrderStatistics::Pointer firstOrderCalculator = mitk::GIFFirstOrderStatistics::New(); - mitk::GIFFirstOrderHistogramStatistics::Pointer firstOrderHistoCalculator = mitk::GIFFirstOrderHistogramStatistics::New(); - mitk::GIFVolumetricStatistics::Pointer volCalculator = mitk::GIFVolumetricStatistics::New(); - mitk::GIFVolumetricDensityStatistics::Pointer voldenCalculator = mitk::GIFVolumetricDensityStatistics::New(); - mitk::GIFCooccurenceMatrix::Pointer coocCalculator = mitk::GIFCooccurenceMatrix::New(); - mitk::GIFCooccurenceMatrix2::Pointer cooc2Calculator = mitk::GIFCooccurenceMatrix2::New(); + mitk::GIFImageDescriptionFeatures::Pointer ipCalculator = mitk::GIFImageDescriptionFeatures::New(); // Commented + mitk::GIFFirstOrderStatistics::Pointer firstOrderCalculator = mitk::GIFFirstOrderStatistics::New(); //Commented + mitk::GIFFirstOrderHistogramStatistics::Pointer firstOrderHistoCalculator = mitk::GIFFirstOrderHistogramStatistics::New(); // Commented + mitk::GIFVolumetricStatistics::Pointer volCalculator = mitk::GIFVolumetricStatistics::New(); // Commented + mitk::GIFVolumetricDensityStatistics::Pointer voldenCalculator = mitk::GIFVolumetricDensityStatistics::New(); // Commented + mitk::GIFCooccurenceMatrix::Pointer coocCalculator = mitk::GIFCooccurenceMatrix::New(); // Commented + mitk::GIFCooccurenceMatrix2::Pointer cooc2Calculator = mitk::GIFCooccurenceMatrix2::New(); //Commented mitk::GIFNeighbouringGreyLevelDependenceFeature::Pointer ngldCalculator = mitk::GIFNeighbouringGreyLevelDependenceFeature::New(); - mitk::GIFGrayLevelRunLength::Pointer rlCalculator = mitk::GIFGrayLevelRunLength::New(); - mitk::GIFGreyLevelSizeZone::Pointer glszCalculator = mitk::GIFGreyLevelSizeZone::New(); - mitk::GIFGreyLevelDistanceZone::Pointer gldzCalculator = mitk::GIFGreyLevelDistanceZone::New(); - mitk::GIFLocalIntensity::Pointer lociCalculator = mitk::GIFLocalIntensity::New(); - mitk::GIFIntensityVolumeHistogramFeatures::Pointer ivohCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); - mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::Pointer ngtdCalculator = mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::New(); + mitk::GIFGreyLevelRunLength::Pointer rlCalculator = mitk::GIFGreyLevelRunLength::New(); + mitk::GIFGreyLevelSizeZone::Pointer glszCalculator = mitk::GIFGreyLevelSizeZone::New(); // Commented + mitk::GIFGreyLevelDistanceZone::Pointer gldzCalculator = mitk::GIFGreyLevelDistanceZone::New(); //Commented + mitk::GIFLocalIntensity::Pointer lociCalculator = mitk::GIFLocalIntensity::New(); //Commented + mitk::GIFIntensityVolumeHistogramFeatures::Pointer ivohCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); // Commented + mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::Pointer ngtdCalculator = mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::New(); //Commented mitk::GIFCurvatureStatistic::Pointer curvCalculator = mitk::GIFCurvatureStatistic::New(); 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(firstOrderHistoCalculator.GetPointer()); features.push_back(ivohCalculator.GetPointer()); features.push_back(lociCalculator.GetPointer()); features.push_back(coocCalculator.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()); mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); mitk::cl::GlobalImageFeaturesParameter param; param.AddParameter(parser); parser.addArgument("--","-", mitkCommandLineParser::String, "---", "---", us::Any(),true); for (auto cFeature : features) { cFeature->AddArguments(parser); } parser.addArgument("--", "-", mitkCommandLineParser::String, "---", "---", us::Any(), true); parser.addArgument("description","d",mitkCommandLineParser::String,"Text","Description that is added to the output",us::Any()); parser.addArgument("direction", "dir", mitkCommandLineParser::String, "Int", "Allows to specify the direction for Cooc and RL. 0: All directions, 1: Only single direction (Test purpose), 2,3,4... Without dimension 0,1,2... ", us::Any()); parser.addArgument("slice-wise", "slice", mitkCommandLineParser::String, "Int", "Allows to specify if the image is processed slice-wise (number giving direction) ", us::Any()); parser.addArgument("output-mode", "omode", mitkCommandLineParser::Int, "Int", "Defines if the results of an image / slice are written in a single row (0 , default) or column (1)."); // Miniapp Infos parser.setCategory("Classification Tools"); parser.setTitle("Global Image Feature calculator"); parser.setDescription("Calculates different global statistics for a given segmentation / image combination"); parser.setContributor("MBI"); std::map parsedArgs = parser.parseArguments(argc, argv); param.ParseParameter(parsedArgs); if (parsedArgs.size()==0) { return EXIT_FAILURE; } if ( parsedArgs.count("help") || parsedArgs.count("h")) { return EXIT_SUCCESS; } //bool savePNGofSlices = true; //std::string folderForPNGOfSlices = "E:\\tmp\\bonekamp\\fig\\"; std::string version = "Version: 1.22"; MITK_INFO << version; std::ofstream log; if (param.useLogfile) { log.open(param.logfilePath, std::ios::app); log << version; log << "Image: " << param.imagePath; log << "Mask: " << param.maskPath; } if (param.useDecimalPoint) { std::cout.imbue(std::locale(std::cout.getloc(), new punct_facet(param.decimalPoint))); } mitk::Image::Pointer image; mitk::Image::Pointer mask; mitk::Image::Pointer tmpImage = mitk::IOUtil::LoadImage(param.imagePath); mitk::Image::Pointer tmpMask = mitk::IOUtil::LoadImage(param.maskPath); image = tmpImage; mask = tmpMask; mitk::Image::Pointer morphMask = mask; if (param.useMorphMask) { morphMask = mitk::IOUtil::LoadImage(param.morphPath); } if ((image->GetDimension() != mask->GetDimension())) { MITK_INFO << "Dimension of image does not match. "; MITK_INFO << "Correct one image, may affect the result"; if (image->GetDimension() == 2) { mitk::Convert2Dto3DImageFilter::Pointer multiFilter2 = mitk::Convert2Dto3DImageFilter::New(); multiFilter2->SetInput(tmpImage); multiFilter2->Update(); image = multiFilter2->GetOutput(); } if (mask->GetDimension() == 2) { mitk::Convert2Dto3DImageFilter::Pointer multiFilter3 = mitk::Convert2Dto3DImageFilter::New(); multiFilter3->SetInput(tmpMask); multiFilter3->Update(); mask = multiFilter3->GetOutput(); } } int writeDirection = 0; if (parsedArgs.count("output-mode")) { writeDirection = us::any_cast(parsedArgs["output-mode"]); } if (param.resampleToFixIsotropic) { mitk::Image::Pointer newImage = mitk::Image::New(); AccessByItk_2(image, ResampleImage, param.resampleResolution, newImage); image = newImage; } if ( ! mitk::Equal(mask->GetGeometry(0)->GetOrigin(), image->GetGeometry(0)->GetOrigin())) { MITK_INFO << "Not equal Origins"; if (param.ensureSameSpace) { MITK_INFO << "Warning!"; MITK_INFO << "The origin of the input image and the mask do not match. They are"; MITK_INFO << "now corrected. Please check to make sure that the images still match"; image->GetGeometry(0)->SetOrigin(mask->GetGeometry(0)->GetOrigin()); } else { return -1; } } if (param.resampleMask) { mitk::Image::Pointer newMaskImage = mitk::Image::New(); AccessByItk_2(mask, ResampleMask, image, newMaskImage); mask = newMaskImage; } if ( ! mitk::Equal(mask->GetGeometry(0)->GetSpacing(), image->GetGeometry(0)->GetSpacing())) { MITK_INFO << "Not equal Sapcings"; if (param.ensureSameSpace) { MITK_INFO << "Warning!"; MITK_INFO << "The spacing of the mask was set to match the spacing of the input image."; MITK_INFO << "This might cause unintended spacing of the mask image"; image->GetGeometry(0)->SetSpacing(mask->GetGeometry(0)->GetSpacing()); } else { MITK_INFO << "The spacing of the mask and the input images is not equal."; MITK_INFO << "Terminating the programm. You may use the '-fi' option"; return -1; } } int direction = 0; if (parsedArgs.count("direction")) { direction = mitk::cl::splitDouble(parsedArgs["direction"].ToString(), ';')[0]; } MITK_INFO << "Start creating Mask without NaN"; mitk::Image::Pointer maskNoNaN = mitk::Image::New(); AccessByItk_2(image, CreateNoNaNMask, mask, maskNoNaN); //CreateNoNaNMask(mask, image, maskNoNaN); bool sliceWise = false; int sliceDirection = 0; unsigned int currentSlice = 0; bool imageToProcess = true; std::vector floatVector; std::vector maskVector; std::vector maskNoNaNVector; std::vector morphMaskVector; if ((parsedArgs.count("slice-wise")) && image->GetDimension() > 2) { MITK_INFO << "Enabled slice-wise"; sliceWise = true; sliceDirection = mitk::cl::splitDouble(parsedArgs["slice-wise"].ToString(), ';')[0]; MITK_INFO << sliceDirection; ExtractSlicesFromImages(image, mask, maskNoNaN, morphMask, sliceDirection, floatVector, maskVector, maskNoNaNVector, morphMaskVector); MITK_INFO << "Slice"; } for (auto cFeature : features) { if (param.defineGlobalMinimumIntensity) { cFeature->SetMinimumIntensity(param.globalMinimumIntensity); cFeature->SetUseMinimumIntensity(true); } if (param.defineGlobalMaximumIntensity) { cFeature->SetMaximumIntensity(param.globalMaximumIntensity); cFeature->SetUseMaximumIntensity(true); } if (param.defineGlobalNumberOfBins) { cFeature->SetBins(param.globalNumberOfBins); MITK_INFO << param.globalNumberOfBins; } cFeature->SetParameter(parsedArgs); cFeature->SetDirection(direction); } bool addDescription = parsedArgs.count("description"); mitk::cl::FeatureResultWritter writer(param.outputPath, writeDirection); if (param.useDecimalPoint) { writer.SetDecimalPoint(param.decimalPoint); } std::string description = ""; if (addDescription) { description = parsedArgs["description"].ToString(); } mitk::Image::Pointer cImage = image; mitk::Image::Pointer cMask = mask; mitk::Image::Pointer cMaskNoNaN = maskNoNaN; mitk::Image::Pointer cMorphMask = morphMask; if (param.useHeader) { writer.AddColumn("SoftwareVersion"); writer.AddColumn("Patient"); writer.AddColumn("Image"); writer.AddColumn("Segmentation"); } // Create a QTApplication and a Datastorage // This is necessary in order to save screenshots of // each image / slice. QApplication qtapplication(argc, argv); QmitkRegisterClasses(); std::vector allStats; while (imageToProcess) { if (sliceWise) { cImage = floatVector[currentSlice]; cMask = maskVector[currentSlice]; cMaskNoNaN = maskNoNaNVector[currentSlice]; cMorphMask = morphMaskVector[currentSlice]; imageToProcess = (floatVector.size()-1 > (currentSlice)) ? true : false ; } else { imageToProcess = false; } if (param.writePNGScreenshots) { SaveSliceOrImageAsPNG(cImage, cMask, param.pngScreenshotsPath, currentSlice); } if (param.writeAnalysisImage) { mitk::IOUtil::Save(cImage, param.anaylsisImagePath); } if (param.writeAnalysisMask) { mitk::IOUtil::Save(cMask, param.analysisMaskPath); } mitk::AbstractGlobalImageFeature::FeatureListType stats; for (auto cFeature : features) { cFeature->SetMorphMask(cMorphMask); cFeature->CalculateFeaturesUsingParameters(cImage, cMask, cMaskNoNaN, stats); } for (std::size_t i = 0; i < stats.size(); ++i) { std::cout << stats[i].first << " - " << stats[i].second << std::endl; } writer.AddHeader(description, currentSlice, stats, param.useHeader, addDescription); if (true) { writer.AddSubjectInformation(MITK_REVISION); writer.AddSubjectInformation(param.imageFolder); writer.AddSubjectInformation(param.imageName); writer.AddSubjectInformation(param.maskName); } writer.AddResult(description, currentSlice, stats, param.useHeader, addDescription); allStats.push_back(stats); ++currentSlice; } if (sliceWise) { mitk::AbstractGlobalImageFeature::FeatureListType statMean, statStd; for (std::size_t i = 0; i < allStats[0].size(); ++i) { auto cElement1 = allStats[0][i]; cElement1.first = "SliceWise Mean " + cElement1.first; cElement1.second = 0.0; auto cElement2 = allStats[0][i]; cElement2.first = "SliceWise Var. " + cElement2.first; cElement2.second = 0.0; statMean.push_back(cElement1); statStd.push_back(cElement2); } for (auto cStat : allStats) { for (std::size_t i = 0; i < cStat.size(); ++i) { statMean[i].second += cStat[i].second / (1.0*allStats.size()); } } for (auto cStat : allStats) { 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*allStats.size()); } } for (std::size_t i = 0; i < statMean.size(); ++i) { std::cout << statMean[i].first << " - " << statMean[i].second << std::endl; std::cout << statStd[i].first << " - " << statStd[i].second << std::endl; } if (true) { writer.AddSubjectInformation(MITK_REVISION); writer.AddSubjectInformation(param.imageFolder); writer.AddSubjectInformation(param.imageName); writer.AddSubjectInformation(param.maskName + " - Mean"); } writer.AddResult(description, currentSlice, statMean, param.useHeader, addDescription); if (true) { writer.AddSubjectInformation(MITK_REVISION); writer.AddSubjectInformation(param.imageFolder); writer.AddSubjectInformation(param.imageName); writer.AddSubjectInformation(param.maskName + " - Var."); } writer.AddResult(description, currentSlice, statStd, param.useHeader, addDescription); } if (param.useLogfile) { log << "Finished calculation"; log.close(); } return 0; } #endif diff --git a/Modules/Classification/CLMiniApps/CLMRNormalization.cpp b/Modules/Classification/CLMiniApps/CLMRNormalization.cpp index 4d1eeb323a..453523dbd7 100644 --- a/Modules/Classification/CLMiniApps/CLMRNormalization.cpp +++ b/Modules/Classification/CLMiniApps/CLMRNormalization.cpp @@ -1,142 +1,165 @@ /*=================================================================== 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 mitkCLPolyToNrrd_cpp #define mitkCLPolyToNrrd_cpp #include "time.h" #include #include #include #include "mitkCommandLineParser.h" #include "itkImageRegionIterator.h" // MITK #include #include #include #include #include // ITK #include #include typedef itk::Image< double, 3 > FloatImageType; typedef itk::Image< unsigned char, 3 > MaskImageType; int main(int argc, char* argv[]) { MITK_INFO << "Start"; mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); // required params parser.addArgument("image", "i", mitkCommandLineParser::InputImage, "Input Image", "Path to the input VTK polydata", us::Any(), false); parser.addArgument("mode", "mode", mitkCommandLineParser::InputImage, "Normalisation mode", "1,2,3: Single Area normalization to Mean, Median, Mode, 4,5,6: Mean, Median, Mode of two regions. ", us::Any(), false); parser.addArgument("mask0", "m0", mitkCommandLineParser::InputImage, "Input Mask", "The median of the area covered by this mask will be set to 0", us::Any(), false); parser.addArgument("mask1", "m1", mitkCommandLineParser::InputImage, "Input Mask", "The median of the area covered by this mask will be set to 1", us::Any(), true); parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output Image", "Target file. The output statistic is appended to this file.", us::Any(), false); parser.addArgument("ignore-outlier", "outlier", mitkCommandLineParser::Bool, "Ignore Outlier", "Ignores the highest and lowest 2% during calculation. Only on single mask normalization.", us::Any(), true); + parser.addArgument("value", "v", mitkCommandLineParser::Float, "Target Value", "Target value, the target value (for example median) is set to this value.", us::Any(), true); + parser.addArgument("width", "w", mitkCommandLineParser::Float, "Target Width", "Ignores the highest and lowest 2% during calculation. Only on single mask normalization.", us::Any(), true); + parser.addArgument("float", "float", mitkCommandLineParser::Bool, "Target Width", "Ignores the highest and lowest 2% during calculation. Only on single mask normalization.", us::Any(), true); // Miniapp Infos parser.setCategory("Classification Tools"); parser.setTitle("MR Normalization Tool"); parser.setDescription("Normalizes a MR image. Sets the Median of the tissue covered by mask 0 to 0 and the median of the area covered by mask 1 to 1."); parser.setContributor("MBI"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) { return EXIT_FAILURE; } if ( parsedArgs.count("help") || parsedArgs.count("h")) { return EXIT_SUCCESS; } bool ignore_outlier = false; if (parsedArgs.count("ignore-outlier")) { ignore_outlier = us::any_cast(parsedArgs["ignore-outlier"]); } MITK_INFO << "Mode access"; int mode =std::stoi(us::any_cast(parsedArgs["mode"])); MITK_INFO << "Mode: " << mode; MITK_INFO << "Read images"; mitk::Image::Pointer mask1; mitk::Image::Pointer image = dynamic_cast(mitk::IOUtil::Load(parsedArgs["image"].ToString())[0].GetPointer()); + + if (parsedArgs.count("float")) + { + typedef itk::Image ImageType; + ImageType::Pointer img = ImageType::New(); + mitk::CastToItkImage(image, img); + mitk::CastToMitkImage(img, image); + } + mitk::Image::Pointer mask0 = dynamic_cast(mitk::IOUtil::Load(parsedArgs["mask0"].ToString())[0].GetPointer()); if (mode > 3) { mask1 = dynamic_cast(mitk::IOUtil::Load(parsedArgs["mask1"].ToString())[0].GetPointer()); } mitk::MRNormLinearStatisticBasedFilter::Pointer oneRegion = mitk::MRNormLinearStatisticBasedFilter::New(); mitk::MRNormTwoRegionsBasedFilter::Pointer twoRegion = mitk::MRNormTwoRegionsBasedFilter::New(); mitk::Image::Pointer output; oneRegion->SetInput(image); oneRegion->SetMask(mask0); oneRegion->SetIgnoreOutlier(ignore_outlier); twoRegion->SetInput(image); twoRegion->SetMask1(mask0); twoRegion->SetMask2(mask1); + if (parsedArgs.count("value")) + { + double target = us::any_cast(parsedArgs["value"]); + oneRegion->SetTargetValue(target); + } + if (parsedArgs.count("width")) + { + double width = us::any_cast(parsedArgs["width"]); + oneRegion->SetTargetValue(width); + } + switch (mode) { case 1: oneRegion->SetCenterMode(mitk::MRNormLinearStatisticBasedFilter::MEAN); oneRegion->Update(); output=oneRegion->GetOutput(); break; case 2: oneRegion->SetCenterMode(mitk::MRNormLinearStatisticBasedFilter::MEDIAN); oneRegion->Update(); output=oneRegion->GetOutput(); break; case 3: oneRegion->SetCenterMode(mitk::MRNormLinearStatisticBasedFilter::MODE); oneRegion->Update(); output=oneRegion->GetOutput(); break; case 4: twoRegion->SetArea1(mitk::MRNormTwoRegionsBasedFilter::MEAN); twoRegion->SetArea2(mitk::MRNormTwoRegionsBasedFilter::MEAN); twoRegion->Update(); output=twoRegion->GetOutput(); break; case 5: twoRegion->SetArea1(mitk::MRNormTwoRegionsBasedFilter::MEDIAN); twoRegion->SetArea2(mitk::MRNormTwoRegionsBasedFilter::MEDIAN); twoRegion->Update(); output=twoRegion->GetOutput(); break; case 6: twoRegion->SetArea1(mitk::MRNormTwoRegionsBasedFilter::MODE); twoRegion->SetArea2(mitk::MRNormTwoRegionsBasedFilter::MODE); twoRegion->Update(); output=twoRegion->GetOutput(); break; } mitk::IOUtil::Save(output, parsedArgs["output"].ToString()); return 0; } #endif \ No newline at end of file diff --git a/Modules/Classification/CLMiniApps/CLSkullMask.cpp b/Modules/Classification/CLMiniApps/CLSkullMask.cpp new file mode 100644 index 0000000000..04e3d4dce2 --- /dev/null +++ b/Modules/Classification/CLMiniApps/CLSkullMask.cpp @@ -0,0 +1,198 @@ +/*=================================================================== + +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 mitkCLPolyToNrrd_cpp +#define mitkCLPolyToNrrd_cpp + +#include "time.h" +#include +#include + +#include +#include "mitkCommandLineParser.h" + +#include "itkImageRegionIterator.h" +// MITK +#include +#include +#include +// ITK +#include +#include + +typedef itk::Image< double, 3 > FloatImageType; +typedef itk::Image< unsigned char, 3 > MaskImageType; + +template +static void + DetectSkull(itk::Image* itkImage, mitk::Image::Pointer im2, mitk::Image::Pointer mask1, std::string output) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + + typename ImageType::Pointer itkIm2 = ImageType::New(); + typename MaskType::Pointer itkMask1 = MaskType::New(); + mitk::CastToItkImage(im2, itkIm2); + mitk::CastToItkImage(mask1, itkMask1); + + itk::ImageRegionIterator iterI1(itkImage, itkImage->GetLargestPossibleRegion()); + itk::ImageRegionIterator iterI2(itkIm2, itkImage->GetLargestPossibleRegion()); + itk::ImageRegionIterator iter(itkMask1, itkImage->GetLargestPossibleRegion()); + while (! iter.IsAtEnd()) + { + unsigned char maskV = 0; + if (iterI1.Value() > 0.0001 && iterI2.Value() > 0.00001) + maskV = 1; + iter.Set(maskV); + ++iter; + ++iterI1; + ++iterI2; + } + + mitk::Image::Pointer img = mitk::ImportItkImage(itkMask1); + mitk::IOUtil::Save(img, output); +} + +int main(int argc, char* argv[]) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + + + mitkCommandLineParser parser; + parser.setArgumentPrefix("--", "-"); + // required params + parser.addArgument("image", "i", mitkCommandLineParser::StringList, "Input Image", "Path to the input images. Mask covers area of all images", us::Any(), false); + parser.addArgument("mask", "m", mitkCommandLineParser::InputImage, "Input Mask", "The median of the area covered by this mask will be set to 1", us::Any(), false); + + // Miniapp Infos + parser.setCategory("Classification Tools"); + parser.setTitle("MR Normalization Tool"); + parser.setDescription("Normalizes a MR image. Sets the Median of the tissue covered by mask 0 to 0 and the median of the area covered by mask 1 to 1."); + parser.setContributor("MBI"); + + std::map parsedArgs = parser.parseArguments(argc, argv); + + if (parsedArgs.size()==0) + { + return EXIT_FAILURE; + } + if ( parsedArgs.count("help") || parsedArgs.count("h")) + { + return EXIT_SUCCESS; + } + us::Any listAny = parsedArgs["image"]; + auto inputImageList = us::any_cast(listAny); + + std::vector imageList; + for (std::size_t i = 0; i < inputImageList.size(); ++i) + { + mitk::Image::Pointer image = dynamic_cast(mitk::IOUtil::Load(inputImageList[i])[0].GetPointer()); + ImageType::Pointer itkImage = ImageType::New(); + mitk::CastToItkImage(image, itkImage); + imageList.push_back(itkImage); + } + mitk::Image::Pointer mitkMask = dynamic_cast(mitk::IOUtil::Load(inputImageList[0])[0].GetPointer()); + MaskType::Pointer mask = MaskType::New(); + mitk::CastToItkImage(mitkMask, mask); + + itk::ImageRegionIterator maskIter(mask, mask->GetLargestPossibleRegion()); + while (!maskIter.IsAtEnd()) + { + maskIter.Set(0); + ++maskIter; + } + + std::vector listOfIndexes; + listOfIndexes.reserve(1000); + + // Find Start Location for the case that one corner is "blocked" by content. Works only on the first image! + ImageType::IndexType tmpIndex; + ImageType::IndexType startIndex; + startIndex.Fill(0); + for (unsigned char i = 0; i < 8; ++i) + { + tmpIndex.Fill(0); + if ((i & 1) > 0) tmpIndex[0] = mask->GetLargestPossibleRegion().GetSize(0)-1; + if ((i & 2) > 0) tmpIndex[1] = mask->GetLargestPossibleRegion().GetSize(1)-1; + if ((i & 4) > 0) tmpIndex[2] = mask->GetLargestPossibleRegion().GetSize(2)-1; + + MITK_INFO << tmpIndex; + if (imageList[0]->GetPixel(tmpIndex) < imageList[0]->GetPixel(startIndex)) + { + startIndex = tmpIndex; + } + } + listOfIndexes.push_back(tmpIndex); + + while (listOfIndexes.size() > 0) + { + ImageType::IndexType currentIndex = listOfIndexes.back(); + listOfIndexes.pop_back(); + if (!(mask->GetLargestPossibleRegion().IsInside(currentIndex))) + { + continue; + } + if (mask->GetPixel(currentIndex) == 0) + { + mask->SetPixel(currentIndex, 1); + double minimum = std::numeric_limits::max(); + for (std::size_t i = 0; i < imageList.size(); ++i) + { + minimum = std::min(minimum, imageList[i]->GetPixel(currentIndex)); + } + if (minimum < 35) + { + mask->SetPixel(currentIndex, 2); + tmpIndex = currentIndex; + tmpIndex[0] += 1; + listOfIndexes.push_back(tmpIndex); + tmpIndex[0] -= 2; + listOfIndexes.push_back(tmpIndex); + tmpIndex[0] += 1; + tmpIndex[1] += 1; + listOfIndexes.push_back(tmpIndex); + tmpIndex[1] -= 2; + listOfIndexes.push_back(tmpIndex); + tmpIndex[1] += 1; + tmpIndex[2] += 1; + listOfIndexes.push_back(tmpIndex); + tmpIndex[2] -= 2; + listOfIndexes.push_back(tmpIndex); + } + } + } + MITK_INFO << "Im here"; + maskIter.GoToBegin(); + while (!maskIter.IsAtEnd()) + { + if (maskIter.Get() == 2) + maskIter.Set(0); + else + maskIter.Set(1); + ++maskIter; + } + + mitk::Image::Pointer ergMask = mitk::ImportItkImage(mask); + + std::string maskPath = parsedArgs["mask"].ToString(); + mitk::IOUtil::Save(ergMask, maskPath); + + //AccessByItk_3(image, Normalize, im2, mask, parsedArgs["output"].ToString()); + + return 0; +} + +#endif \ No newline at end of file diff --git a/Modules/Classification/CLMiniApps/CLVoxelFeatures.cpp b/Modules/Classification/CLMiniApps/CLVoxelFeatures.cpp index 4a9dd92812..945f7fd5e9 100644 --- a/Modules/Classification/CLMiniApps/CLVoxelFeatures.cpp +++ b/Modules/Classification/CLMiniApps/CLVoxelFeatures.cpp @@ -1,437 +1,434 @@ /*=================================================================== 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 mitkCLVoxeFeatures_cpp #define mitkCLVoxeFeatures_cpp #include "time.h" #include #include #include #include #include #include "mitkCommandLineParser.h" -#include -#include - #include "itkDiscreteGaussianImageFilter.h" #include #include "itkHessianRecursiveGaussianImageFilter.h" #include "itkUnaryFunctorImageFilter.h" #include "vnl/algo/vnl_symmetric_eigensystem.h" #include #include #include static std::vector 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; } namespace Functor { template class MatrixFirstEigenvalue { public: MatrixFirstEigenvalue() {} virtual ~MatrixFirstEigenvalue() {} int order; inline TOutput operator ()(const TInput& input) { double a,b,c; if (input[0] < 0.01 && input[1] < 0.01 &&input[2] < 0.01 &&input[3] < 0.01 &&input[4] < 0.01 &&input[5] < 0.01) return 0; vnl_symmetric_eigensystem_compute_eigenvals(input[0], input[1],input[2],input[3],input[4],input[5],a,b,c); switch (order) { case 0: return a; case 1: return b; case 2: return c; default: return a; } } bool operator !=(const MatrixFirstEigenvalue) const { return false; } bool operator ==(const MatrixFirstEigenvalue& other) const { return !(*this != other); } }; } template void GaussianFilter(itk::Image* itkImage, double variance, mitk::Image::Pointer &output) { typedef itk::Image ImageType; typedef itk::DiscreteGaussianImageFilter< ImageType, ImageType > GaussFilterType; typename GaussFilterType::Pointer gaussianFilter = GaussFilterType::New(); gaussianFilter->SetInput( itkImage ); gaussianFilter->SetVariance(variance); gaussianFilter->Update(); mitk::CastToMitkImage(gaussianFilter->GetOutput(), output); } template void DifferenceOfGaussFilter(itk::Image* itkImage, double variance, mitk::Image::Pointer &output) { typedef itk::Image ImageType; typedef itk::DiscreteGaussianImageFilter< ImageType, ImageType > GaussFilterType; typedef itk::SubtractImageFilter SubFilterType; typename GaussFilterType::Pointer gaussianFilter1 = GaussFilterType::New(); gaussianFilter1->SetInput( itkImage ); gaussianFilter1->SetVariance(variance); gaussianFilter1->Update(); typename GaussFilterType::Pointer gaussianFilter2 = GaussFilterType::New(); gaussianFilter2->SetInput( itkImage ); gaussianFilter2->SetVariance(variance*0.66*0.66); gaussianFilter2->Update(); typename SubFilterType::Pointer subFilter = SubFilterType::New(); subFilter->SetInput1(gaussianFilter1->GetOutput()); subFilter->SetInput2(gaussianFilter2->GetOutput()); subFilter->Update(); mitk::CastToMitkImage(subFilter->GetOutput(), output); } template void LaplacianOfGaussianFilter(itk::Image* itkImage, double variance, mitk::Image::Pointer &output) { typedef itk::Image ImageType; typedef itk::DiscreteGaussianImageFilter< ImageType, ImageType > GaussFilterType; typedef itk::LaplacianRecursiveGaussianImageFilter LaplacianFilter; typename GaussFilterType::Pointer gaussianFilter = GaussFilterType::New(); gaussianFilter->SetInput( itkImage ); gaussianFilter->SetVariance(variance); gaussianFilter->Update(); typename LaplacianFilter::Pointer laplaceFilter = LaplacianFilter::New(); laplaceFilter->SetInput(gaussianFilter->GetOutput()); laplaceFilter->Update(); mitk::CastToMitkImage(laplaceFilter->GetOutput(), output); } template void HessianOfGaussianFilter(itk::Image* itkImage, double variance, std::vector &out) { typedef itk::Image ImageType; typedef itk::Image FloatImageType; typedef itk::HessianRecursiveGaussianImageFilter HessianFilterType; typedef typename HessianFilterType::OutputImageType VectorImageType; typedef Functor::MatrixFirstEigenvalue DeterminantFunctorType; typedef itk::UnaryFunctorImageFilter DetFilterType; typename HessianFilterType::Pointer hessianFilter = HessianFilterType::New(); hessianFilter->SetInput(itkImage); hessianFilter->SetSigma(std::sqrt(variance)); for (unsigned int i = 0; i < VImageDimension; ++i) { typename DetFilterType::Pointer detFilter = DetFilterType::New(); detFilter->SetInput(hessianFilter->GetOutput()); detFilter->GetFunctor().order = i; detFilter->Update(); mitk::CastToMitkImage(detFilter->GetOutput(), out[i]); } } template void LocalHistograms2(itk::Image* itkImage, std::vector &out, std::vector params) { typedef itk::Image ImageType; typedef itk::MultiHistogramFilter MultiHistogramType; double minimum = params[0]; double maximum = params[1]; int bins = std::round(params[2]); double offset = minimum; double delta = (maximum - minimum) / bins; typename MultiHistogramType::Pointer filter = MultiHistogramType::New(); filter->SetInput(itkImage); filter->SetOffset(offset); filter->SetDelta(delta); filter->SetBins(bins); filter->Update(); for (int i = 0; i < bins; ++i) { mitk::Image::Pointer img = mitk::Image::New(); mitk::CastToMitkImage(filter->GetOutput(i), img); out.push_back(img); } } template void LocalHistograms(itk::Image* itkImage, std::vector &out, double offset, double delta) { typedef itk::Image ImageType; typedef itk::MultiHistogramFilter MultiHistogramType; typename MultiHistogramType::Pointer filter = MultiHistogramType::New(); filter->SetInput(itkImage); filter->SetOffset(offset); filter->SetDelta(delta); filter->Update(); for (int i = 0; i < 11; ++i) { mitk::Image::Pointer img = mitk::Image::New(); mitk::CastToMitkImage(filter->GetOutput(i), img); out.push_back(img); } } template void localStatistic(itk::Image* itkImage, std::vector &out, int size) { typedef itk::Image ImageType; typedef itk::LocalStatisticFilter MultiHistogramType; typename MultiHistogramType::Pointer filter = MultiHistogramType::New(); filter->SetInput(itkImage); filter->SetSize(size); filter->Update(); for (int i = 0; i < 5; ++i) { mitk::Image::Pointer img = mitk::Image::New(); mitk::CastToMitkImage(filter->GetOutput(i), img); out.push_back(img); } } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); // required params parser.addArgument("image", "i", mitkCommandLineParser::InputImage, "Input Image", "Path to the input VTK polydata", us::Any(), false); parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output text file", "Target file. The output statistic is appended to this file.", us::Any(), false); parser.addArgument("extension", "e", mitkCommandLineParser::OutputFile, "Extension", "File extension. Default is .nii.gz", us::Any(), true); parser.addArgument("gaussian","g",mitkCommandLineParser::String, "Gaussian Filtering of the input images", "Gaussian Filter. Followed by the used variances seperated by ';' ",us::Any()); parser.addArgument("difference-of-gaussian","dog",mitkCommandLineParser::String, "Difference of Gaussian Filtering of the input images", "Difference of Gaussian Filter. Followed by the used variances seperated by ';' ",us::Any()); parser.addArgument("laplace-of-gauss","log",mitkCommandLineParser::String, "Laplacian of Gaussian Filtering", "Laplacian of Gaussian Filter. Followed by the used variances seperated by ';' ",us::Any()); parser.addArgument("hessian-of-gauss","hog",mitkCommandLineParser::String, "Hessian of Gaussian Filtering", "Hessian of Gaussian Filter. Followed by the used variances seperated by ';' ",us::Any()); parser.addArgument("local-histogram", "lh", mitkCommandLineParser::String, "Local Histograms", "Calculate the local histogram based feature. Specify Offset and Delta, for exampel -3;0.6 ", us::Any()); parser.addArgument("local-histogram2", "lh2", mitkCommandLineParser::String, "Local Histograms", "Calculate the local histogram based feature. Specify Minimum;Maximum;Bins, for exampel -3;3;6 ", us::Any()); parser.addArgument("local-statistic", "ls", mitkCommandLineParser::String, "Local Histograms", "Calculate the local histogram based feature. Specify Offset and Delta, for exampel -3;0.6 ", us::Any()); // Miniapp Infos parser.setCategory("Classification Tools"); parser.setTitle("Global Image Feature calculator"); parser.setDescription("Calculates different global statistics for a given segmentation / image combination"); parser.setContributor("MBI"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) { return EXIT_FAILURE; } if ( parsedArgs.count("help") || parsedArgs.count("h")) { return EXIT_SUCCESS; } mitk::Image::Pointer image = dynamic_cast(mitk::IOUtil::Load(parsedArgs["image"].ToString())[0].GetPointer()); std::string filename=parsedArgs["output"].ToString(); std::string extension = ".nii.gz"; if (parsedArgs.count("extension")) { extension = parsedArgs["extension"].ToString(); } //////////////////////////////////////////////////////////////// // CAlculate Local Histogram //////////////////////////////////////////////////////////////// MITK_INFO << "Check for Local Histogram..."; if (parsedArgs.count("local-histogram")) { std::vector outs; auto ranges = splitDouble(parsedArgs["local-histogram"].ToString(), ';'); if (ranges.size() < 2) { MITK_INFO << "Missing Delta and Offset for Local Histogram"; } else { AccessByItk_3(image, LocalHistograms, outs, ranges[0], ranges[1]); for (std::size_t i = 0; i < outs.size(); ++i) { std::string name = filename + "-lh" + us::any_value_to_string(i)+extension; mitk::IOUtil::Save(outs[i], name); } } } //////////////////////////////////////////////////////////////// // CAlculate Local Histogram 2 //////////////////////////////////////////////////////////////// MITK_INFO << "Check for Local Histogram..."; if (parsedArgs.count("local-histogram2")) { std::vector outs; auto ranges = splitDouble(parsedArgs["local-histogram2"].ToString(), ';'); if (ranges.size() < 3) { MITK_INFO << "Missing Delta and Offset for Local Histogram"; } else { AccessByItk_2(image, LocalHistograms2, outs, ranges); for (std::size_t i = 0; i < outs.size(); ++i) { std::string name = filename + "-lh2" + us::any_value_to_string(i)+extension; mitk::IOUtil::Save(outs[i], name); } } } //////////////////////////////////////////////////////////////// // CAlculate Local Statistic //////////////////////////////////////////////////////////////// MITK_INFO << "Check for Local Histogram..."; if (parsedArgs.count("local-statistic")) { std::vector outs; auto ranges = splitDouble(parsedArgs["local-statistic"].ToString(), ';'); if (ranges.size() < 1) { MITK_INFO << "Missing Rage"; } else { for (int j = 0; j < ranges.size(); ++j) { AccessByItk_2(image, localStatistic, outs, ranges[j]); for (std::size_t i = 0; i < outs.size(); ++i) { std::string name = filename + "-lstat" + us::any_value_to_string(ranges[j])+ "_" +us::any_value_to_string(i)+extension; mitk::IOUtil::Save(outs[i], name); } outs.clear(); } } } //////////////////////////////////////////////////////////////// // CAlculate Gaussian Features //////////////////////////////////////////////////////////////// MITK_INFO << "Check for Gaussian..."; if (parsedArgs.count("gaussian")) { MITK_INFO << "Calculate Gaussian... " << parsedArgs["gaussian"].ToString(); auto ranges = splitDouble(parsedArgs["gaussian"].ToString(),';'); for (std::size_t i = 0; i < ranges.size(); ++i) { MITK_INFO << "Gaussian with sigma: " << ranges[i]; mitk::Image::Pointer output; AccessByItk_2(image, GaussianFilter, ranges[i], output); MITK_INFO << "Write output:"; std::string name = filename + "-gaussian-" + us::any_value_to_string(ranges[i]) + extension; mitk::IOUtil::Save(output, name); } } //////////////////////////////////////////////////////////////// // CAlculate Difference of Gaussian Features //////////////////////////////////////////////////////////////// MITK_INFO << "Check for DoG..."; if (parsedArgs.count("difference-of-gaussian")) { MITK_INFO << "Calculate Difference of Gaussian... " << parsedArgs["difference-of-gaussian"].ToString(); auto ranges = splitDouble(parsedArgs["difference-of-gaussian"].ToString(),';'); for (std::size_t i = 0; i < ranges.size(); ++i) { mitk::Image::Pointer output; AccessByItk_2(image, DifferenceOfGaussFilter, ranges[i], output); std::string name = filename + "-dog-" + us::any_value_to_string(ranges[i]) + extension; mitk::IOUtil::Save(output, name); } } MITK_INFO << "Check for LoG..."; //////////////////////////////////////////////////////////////// // CAlculate Laplacian Of Gauss Features //////////////////////////////////////////////////////////////// if (parsedArgs.count("laplace-of-gauss")) { MITK_INFO << "Calculate LoG... " << parsedArgs["laplace-of-gauss"].ToString(); auto ranges = splitDouble(parsedArgs["laplace-of-gauss"].ToString(),';'); for (std::size_t i = 0; i < ranges.size(); ++i) { mitk::Image::Pointer output; AccessByItk_2(image, LaplacianOfGaussianFilter, ranges[i], output); std::string name = filename + "-log-" + us::any_value_to_string(ranges[i]) + extension; mitk::IOUtil::Save(output, name); } } MITK_INFO << "Check for HoG..."; //////////////////////////////////////////////////////////////// // CAlculate Hessian Of Gauss Features //////////////////////////////////////////////////////////////// if (parsedArgs.count("hessian-of-gauss")) { MITK_INFO << "Calculate HoG... " << parsedArgs["hessian-of-gauss"].ToString(); auto ranges = splitDouble(parsedArgs["hessian-of-gauss"].ToString(),';'); for (std::size_t i = 0; i < ranges.size(); ++i) { std::vector outs; outs.push_back(mitk::Image::New()); outs.push_back(mitk::Image::New()); outs.push_back(mitk::Image::New()); AccessByItk_2(image, HessianOfGaussianFilter, ranges[i], outs); std::string name = filename + "-hog0-" + us::any_value_to_string(ranges[i]) + extension; mitk::IOUtil::Save(outs[0], name); name = filename + "-hog1-" + us::any_value_to_string(ranges[i]) + extension; mitk::IOUtil::Save(outs[1], name); name = filename + "-hog2-" + us::any_value_to_string(ranges[i]) + extension; mitk::IOUtil::Save(outs[2], name); } } return 0; } #endif diff --git a/Modules/Classification/CLMiniApps/CMakeLists.txt b/Modules/Classification/CLMiniApps/CMakeLists.txt index 6108fb4b34..ab24948280 100644 --- a/Modules/Classification/CLMiniApps/CMakeLists.txt +++ b/Modules/Classification/CLMiniApps/CMakeLists.txt @@ -1,142 +1,143 @@ option(BUILD_ClassificationMiniApps "Build commandline tools for classification" OFF) if(BUILD_ClassificationMiniApps OR MITK_BUILD_ALL_APPS) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( classificationminiapps RandomForestTraining^^MitkCLVigraRandomForest NativeHeadCTSegmentation^^MitkCLVigraRandomForest ManualSegmentationEvaluation^^MitkCLVigraRandomForest CLScreenshot^^MitkCore_MitkQtWidgetsExt_MitkCLUtilities CLDicom2Nrrd^^MitkCore CLImageTypeConverter^^MitkCore CLResampleImageToReference^^MitkCore CLGlobalImageFeatures^^MitkCLUtilities_MitkQtWidgetsExt CLMRNormalization^^MitkCLUtilities_MitkCLMRUtilities CLStaple^^MitkCLUtilities CLVoxelFeatures^^MitkCLUtilities CLPolyToNrrd^^ CLPlanarFigureToNrrd^^MitkCore_MitkSegmentation_MitkMultilabel CLSimpleVoxelClassification^^MitkDataCollection_MitkCLVigraRandomForest CLVoxelClassification^^MitkDataCollection_MitkCLImportanceWeighting_MitkCLVigraRandomForest CLBrainMask^^MitkCLUtilities XRaxSimulationFromCT^^MitkCLUtilities CLRandomSampling^^MitkCore_MitkCLUtilities CLRemoveEmptyVoxels^^MitkCore CLN4^^MitkCore + CLSkullMask^^MitkCore CLPointSetToSegmentation^^ CLMultiForestPrediction^^MitkDataCollection_MitkCLVigraRandomForest CLNrrdToPoly^^MitkCore CL2Dto3DImage^^MitkCore CLWeighting^^MitkCore_MitkCLImportanceWeighting_MitkCLUtilities CLOverlayRoiCenterOfMass^^MitkCore_MitkCLUtilities_MitkQtWidgetsExt CLLungSegmentation^^MitkCore_MitkSegmentation_MitkMultilabel # RandomForestPrediction^^MitkCLVigraRandomForest ) foreach(classificationminiapps ${classificationminiapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${classificationminiapps}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitk_create_executable(${appname} DEPENDS MitkCore MitkCLCore MitkCommandLine ${dependencies_list} PACKAGE_DEPENDS ITK Qt5|Core Vigra CPP_FILES ${appname}.cpp ) # CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp if(EXECUTABLE_IS_ENABLED) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) if(APPLE) if(_is_bundle) set(_target_locations ${EXECUTABLE_TARGET}.app) set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${EXECUTABLE_TARGET}) set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) endif() endif() endforeach() # This mini app does not depend on mitkDiffusionImaging at all mitk_create_executable(CLMatchPointReg DEPENDS MitkCore MitkCLUtilities MitkMatchPointRegistration MitkCommandLine MitkMatchPointRegistrationUI PACKAGE_DEPENDS ITK Qt5|Core Vigra MatchPoint CPP_FILES CLMatchPointReg.cpp ) #mitk_create_executable(CLGlobalImageFeatures # DEPENDS MitkCore MitkCLUtilities # CPP_FILES CLGlobalImageFeatures.cpp mitkCommandLineParser.cpp #) #mitk_create_executable(CLBrainMask # DEPENDS MitkCore MitkCLUtilities # CPP_FILES CLBrainMask.cpp mitkCommandLineParser.cpp #) #mitk_create_executable(CLImageConverter # DEPENDS MitkCore # CPP_FILES CLImageConverter.cpp mitkCommandLineParser.cpp #) #mitk_create_executable(CLSurWeighting # DEPENDS MitkCore MitkCLUtilities MitkDataCollection #MitkCLImportanceWeighting # CPP_FILES CLSurWeighting.cpp mitkCommandLineParser.cpp #) #mitk_create_executable(CLImageCropper # DEPENDS MitkCore MitkCLUtilities MitkAlgorithmsExt # CPP_FILES CLImageCropper.cpp mitkCommandLineParser.cpp #) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/Classification/CLUtilities/CMakeLists.txt b/Modules/Classification/CLUtilities/CMakeLists.txt index 1f05800279..ebe7afa43e 100644 --- a/Modules/Classification/CLUtilities/CMakeLists.txt +++ b/Modules/Classification/CLUtilities/CMakeLists.txt @@ -1,6 +1,6 @@ MITK_CREATE_MODULE( DEPENDS MitkCore MitkCLCore MitkCommandLine - PACKAGE_DEPENDS PUBLIC Eigen OpenCV + PACKAGE_DEPENDS PUBLIC Eigen ) add_subdirectory(test) diff --git a/Modules/Classification/CLUtilities/files.cmake b/Modules/Classification/CLUtilities/files.cmake index 8e93d2eb20..17b04b392f 100644 --- a/Modules/Classification/CLUtilities/files.cmake +++ b/Modules/Classification/CLUtilities/files.cmake @@ -1,39 +1,38 @@ 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/mitkGIFGrayLevelRunLength.cpp - GlobalImageFeatures/mitkGIFGrayLevelSizeZone.cpp + GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.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/mitkGIFCooccurenceMatrix.h b/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix.h index 4d19e8046c..d43e6421f7 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix.h @@ -1,54 +1,62 @@ #ifndef mitkGIFCooccurenceMatrix_h #define mitkGIFCooccurenceMatrix_h #include #include #include namespace mitk { class MITKCLUTILITIES_EXPORT GIFCooccurenceMatrix : public AbstractGlobalImageFeature { + /** + * \brief Calculates features based on the co-occurence matrix. + * + * This filter calculates features based on the Co-Occurence Matrix. + * + * \warning{ This is a legacy class only. If possible, avoid to use it. Use + * GIFCooccurenceMatrix2 instead.} + */ public: mitkClassMacro(GIFCooccurenceMatrix,AbstractGlobalImageFeature) itkFactorylessNewMacro(Self) itkCloneMacro(Self) GIFCooccurenceMatrix(); /** * \brief Calculates the Cooccurence-Matrix based features for this class. */ virtual 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 */ virtual FeatureNameListType GetFeatureNames() override; itkGetConstMacro(Range,double); itkSetMacro(Range, double); virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); struct GIFCooccurenceMatrixConfiguration { double range; unsigned int direction; double MinimumIntensity; bool UseMinimumIntensity; double MaximumIntensity; bool UseMaximumIntensity; int Bins; }; private: double m_Range; }; } #endif //mitkGIFCooccurenceMatrix_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h b/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h index b4e9caefaa..fef8c39277 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h @@ -1,151 +1,248 @@ #ifndef mitkGIFCooccurenceMatrix2_h #define mitkGIFCooccurenceMatrix2_h #include #include #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; }; - + /** + * \brief Calculates features based on the co-occurence matrix. + * + * The co-occurence matrix describes the relations between voxels in a specific direction. The elements \f$m_{i,k} \f$ of the + * matrix count how often a voxel with the intensity \f$i \f$ has a neighbour in a certain direction with the intensity \f$ k \f$. + * The direction for each matrix is given by a directed vector \f$ \overrightarrow{d} \f$. + * + * It is important to calculate the matrices for all possible directions in order to obtain a rotation invariant feature. + * For the 3D case, this means that there are 26 possible directions. Using the symmetrical properties of the co-occurence + * matrix, it is then possible to calculate the features in all directions looking at 13 different directions. + * + * The standard length of the vector is 1, e.g. looking at direct neighbours. It is possible to look at more + * distance neighbours. This is achieved using the parameter range which defines the distance between + * two neighbouring voxels in number of voxels. The default value for this is 1. It can be changes using the Method + * SetRange() or by passing the option cooc2::range. + * + * There are two possible ways of combining the information obtained from the multiple directions. The first option + * is to calculate a common matrix for all directions and then use this matrix to calculate the describing features. + * The second method is to calculate a matrix for each direction, obtain the features and then report the mean and + * standard value of these features. Both mehtods are calcuated by this filters and reported, distinguisehd by either + * an "Overall" if a single matrix is used, a "Mean" for the mean Value, or an "Std.Dev." for the standard deviation. + * + * The connected areas are based on the binned image, the binning parameters can be set via the default + * parameters as described in AbstractGlobalImageFeature. The intensity used for the calculation is + * always equal to the bin number. 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. + * + * This feature calculator is activated by the option -cooccurence2 or -cooc2. + * + * 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 defined. We always give the notation for the overall matrix feature + * although those for the mean and std.dev. are basically equal. In the name, is replace + * by the distance of the neighbours. For the definitions of the feature, the probability of each + * intensity pair (i,k) \f$ p_{i,k} = \frac{m_{i,k}}{\sum_i \sum_k m_{i,k}} \f$. + * + * In addition, the marginal sum \f$ p_{i,\cdot} = p_{\cdot,k=i} = \sum_k p_{i,k} \f$, which is + * identical for both axis due to the symetrical nature of the matrix. Furthermore, the diagonal and + * cross diagnoal features are used: + * \f[ p_{i-k}(l) = \sum_i \sum_k p_{i,k} \delta(l - \| i -k \| ) \enspace \enspace l = 0, \dots, N_g -1 \f] + * \f[ p_{i+k}(l) = \sum_i \sum_k p_{i,k} \delta(l - ( i + k ) ) \enspace \enspace l = 2, \dots, 2 N_g \f] + * Here, \f$ \delta(x) \f$ is the dirac function, which is one for \f$x=0 \f$ and zero otherwise. + * - Co-occurenced Based Features ()::Overall Joint Maximum: + * \f[ \textup{Joint Maximum}= \textup{max}(p_{i,k}) \f] + * - Co-occurenced Based Features ()::Overall Joint Average: + * \f[ \textup{Joint Average} = \mu_{ja} = \sum_i \sum_k i p_{i,k} \f] + * - Co-occurenced Based Features ()::Overall Joint Variance: + * \f[ \textup{Joint Variance} = \sum_i \sum_k (i - \mu_{ja})^2 p_{i,k} \f] + * - Co-occurenced Based Features ()::Overall Joint Entropy: + * \f[ \textup{Joint Entropy} = e_j = - \sum_i \sum_k p_{i,k} \textup{log}_2 p_{i,k} \f] + * - Co-occurenced Based Features ()::Overall Row Maximum: + * \f[ \textup{Row Maximum}= \textup{max}(p_{i,\cdot}) \f] + * - Co-occurenced Based Features ()::Overall Row Average: + * \f[ \textup{Row Average} = \mu_{ra} = \sum_i i p_{i,\cdot} \f] + * - Co-occurenced Based Features ()::Overall Row Variance: + * \f[ \textup{Row Variance} = \sigma^2_{i, \cdot} = \sum_i (i - \mu_{ra})^2 p_{i,\cdot} \f] + * - Co-occurenced Based Features ()::Overall Row Entropy: + * \f[ \textup{Row Entropy} = e_r = - \sum_i p_{i,\cdot} \textup{log}_2 p_{i,\cdot} \f] + * - Co-occurenced Based Features ()::Overall First Row-Column Entropy: + * \f[ \textup{First Row-Column Entropy} = e_1 = - \sum_i \sum_k p_{i,k} \textup{log}_2 ( p_{i,\cdot} p_{\cdot,k}) \f] + * - Co-occurenced Based Features ()::Overall Second Row-Column Entropy: + * \f[ \textup{Second Row-Column Entropy} = e_2 = - \sum_i \sum_k p_{i,\cdot} p_{\cdot,k} \textup{log}_2 ( p_{i,\cdot} p_{\cdot,k}) \f] + * - Co-occurenced Based Features ()::Overall Difference Average: + * \f[ \textup{Difference Average} = \mu_{da} = \sum_l l p_{i-k}(l) \f] + * - Co-occurenced Based Features ()::Overall Difference Variance: + * \f[ \textup{Difference Variance} = \sum_l (i - \mu_{da})^2 p_{i-k}(l) \f] + * - Co-occurenced Based Features ()::Overall Difference Entropy: + * \f[ \textup{Difference Entropy} = - \sum_l p_{i-k}(l) \textup{log}_2 p_{i-k}(l) \f] + * - Co-occurenced Based Features ()::Overall Sum Average: + * \f[ \textup{Sum Average} = \mu_{sa} = \sum_l l p_{i+k}(l) \f] + * - Co-occurenced Based Features ()::Overall Sum Variance: + * \f[ \textup{Sum Variance} = \sum_l (i - \mu_{sa})^2 p_{i+k}(l) \f] + * - Co-occurenced Based Features ()::Overall Sum Entropy: + * \f[ \textup{Sum Entropy} = - \sum_l p_{i+k}(l) \textup{log}_2 p_{i+k}(l) \f] + * - Co-occurenced Based Features ()::Overall Angular Second Moment: + * \f[ \textup{Angular Second Moment} = \sum_i \sum_k p^2_{i,k} \f] + * - Co-occurenced Based Features ()::Overall Contrast: + * \f[ \textup{Contrast} = \sum_i \sum_k (i-k)^2 p_{i,k} \f] + * - Co-occurenced Based Features ()::Overall Dissimilarity: + * \f[ \textup{Dissimilarity} = \sum_i \sum_k \| i-k\| p^2_{i,k} \f] + * - Co-occurenced Based Features ()::Overall Inverse Difference: + * \f[ \textup{Inverse Difference} = \sum_i \sum_k \frac{p_{i,k}}{1+\| i-k\|} \f] + * - Co-occurenced Based Features ()::Overall Inverse Difference Normalized: + * \f[ \textup{Inverse Difference Normalized} = \sum_i \sum_k \frac{p_{i,k}}{1+\frac{\| i-k\|}{N_g}} \f] + * - Co-occurenced Based Features ()::Overall Inverse Difference Moment: + * \f[ \textup{Inverse Difference Moment} = \sum_i \sum_k \frac{p_{i,k}}{1+ ( i-k )^2} \f] + * - Co-occurenced Based Features ()::Overall Inverse Difference Moment Normalized: + * \f[ \textup{Inverse Difference Moment Normalized} = \sum_i \sum_k \frac{p_{i,k}}{1+\frac{( i-k ) ^2}{N_g}} \f] + * - Co-occurenced Based Features ()::Overall Inverse Variance: + * \f[ \textup{Inverse Difference Moment Normalized} = \sum_i \sum_k \frac{p_{i,k}}{(i-k)^2} \f] + * - Co-occurenced Based Features ()::Overall Correlation: + * \f[ \textup{Correlation} = \frac{1}{\sigma^2_{i,\cdot}} \sum_i \sum_k (i - \mu_{ra})(k - \mu_{ra}) p_{i,k} \f] + * - Co-occurenced Based Features ()::Overall Autocorrelation: + * \f[ \textup{Autocorrelation} = \sum_i \sum_k i k p_{i,k} \f] + * - Co-occurenced Based Features ()::Overall Cluster Tendency: + * \f[ \textup{Cluster Tendency} = \sum_i \sum_k (i + k - 2\mu_{ra})^2 p_{i,k} \f] + * - Co-occurenced Based Features ()::Overall Cluster Shade: + * \f[ \textup{Cluster Shade} = \sum_i \sum_k (i + k - 2\mu_{ra})^3 p_{i,k} \f] + * - Co-occurenced Based Features ()::Overall Cluster Prominence: + * \f[ \textup{Cluster Prominence} = \sum_i \sum_k (i + k - 2\mu_{ra})^4 p_{i,k} \f] + * - Co-occurenced Based Features ()::Overall First Measure of Information Correlation: + * \f[ \textup{First Measure of Information Correlation} = \frac{ e_j- e_1}{e_r} \f] + * - Co-occurenced Based Features ()::Overall Second Measure of Information Correlation: + * \f[ \textup{Second Measure of Information Correlation} = \sqrt{1- \exp(-2 (e_2 - e_j)} \f] + */ class MITKCLUTILITIES_EXPORT GIFCooccurenceMatrix2 : public AbstractGlobalImageFeature { public: mitkClassMacro(GIFCooccurenceMatrix2, AbstractGlobalImageFeature); itkFactorylessNewMacro(Self) itkCloneMacro(Self) GIFCooccurenceMatrix2(); /** * \brief Calculates the Cooccurence-Matrix based features for this class. */ virtual 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 */ virtual FeatureNameListType GetFeatureNames() override; virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); itkGetConstMacro(Range,double); itkSetMacro(Range, double); - itkGetConstMacro(Bins, int); - itkSetMacro(Bins, int); - itkGetConstMacro(Binsize, double); - itkSetMacro(Binsize, double); struct GIFCooccurenceMatrix2Configuration { double range; unsigned int direction; double MinimumIntensity; - bool UseMinimumIntensity; double MaximumIntensity; - bool UseMaximumIntensity; int Bins; - double BinSize; }; private: double m_Range; - int m_Bins; - double m_Binsize; }; } #endif //mitkGIFCooccurenceMatrix2_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderHistogramStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderHistogramStatistics.h index eaf8d245df..2c6103ef31 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderHistogramStatistics.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderHistogramStatistics.h @@ -1,77 +1,137 @@ /*=================================================================== 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 mitkGIFFirstOrderHistogramStatistics_h #define mitkGIFFirstOrderHistogramStatistics_h #include #include #include namespace mitk { + /** + * \brief Calulates first order features based on a histogram. + * + * This class can be used to calculate first order features based on a histogram. + * For each feature, two variations are given, once the value of the feature that is + * obtained if the mean intensity of the histogram bins is used and the + * histogram bin that corresponds to the feature value. See AbstractGlobalImageFeature for more + * information on the histogram initialization. The histogram gives a probability \f$p_i\f$ for the + * intensity \f$x_i\f$ that is linked to the bin \f$i\f$. The histogram bins start at index 1. + * + * This feature calculator is activated by the option "-first-order-histogram" or "-foh". + * Beside the options for the histogram definitions, which are given in the description of AbstractGlobalImageFeature , no + * additional parameters are available. + * + * The features are calculated based on a mask. It is assumed that the mask is + * of the type of an unsigned short image and all voxels with an value of 1 + * are treated as masked. + * + * The resulting features are: + * - FirstOrderHistogram::Mean Value: The mean intensity of all voxels, calulated by \f$ \mu_x = \sum p_i x_i\f$. + * - FirstOrderHistogram::Variance Value The variance intensity is calculated as : \f$ \sigma^2 = \sum p_i (x_i - \mu_x)^2\f$. + * - FirstOrderHistogram::Skewness Value: \f[ skewness = \frac{\sum p_i (x_i - \mu_x)^3}{\sigma^3} \f] + * - FirstOrderHistogram::Excess Kurtosis Value: \f[ skewness = \frac{\sum p_i (x_i - \mu_x)^4}{\sigma^4} - 3 \f] + * - FirstOrderHistogram::Median Value: The median intensity value based on the histogram values. + * - FirstOrderHistogram::Minimum Value: The minimum observed intensity value. + * - FirstOrderHistogram::Percentile 10 Value: The intensity that is equal or greater than 10% of all observed intensities. + * - FirstOrderHistogram::Percentile 90 Value: The intensity that is equal or greater than 90% of all observed intensities. + * - FirstOrderHistogram::Maximum Value: The maximum observerd intensity value. + * - FirstOrderHistogram::Mode Value: The most common intensity value, i.e. the value of the bin with the highest probability. + * - FirstOrderHistogram::Interquantile Range Value: The intensity difference between Percentile 75% (\f$ P75\f$) and Percentile 25% (\f$ P25\f$). + * - FirstOrderHistogram::Range Value: The difference between the observed maximum and minimum intensity. + * - FirstOrderHistogram::Mean Absolute Deviation Value: \f[ \textup{mean absolute deviation} = \sum p_i \left \| (x_i - \mu_x) \right \| \f] + * - FirstOrderHistogram::Robust Mean Value: The mean of all intensities between the 10% and 90% quantile. + * - FirstOrderHistogram::Robust Mean Absolute Deviation Value: The Mean absolute deviation for all values between the 10% and 90% quantile. It is based on the robust mean value. + * - FirstOrderHistogram::Median Absolute Deviation Value: \f[ \textup{mean absolute deviation} = \sum p_i \left \| (x_i - \textup{median}) \right \| \f] + * - FirstOrderHistogram::Coefficient of Variation Value: \f[ \frac{\sigma_x}{\mu_x} \f] + * - FirstOrderHistogram::Quantile coefficient of Dispersion Value: \f[ \textup{Quantile coefficient of Dispersion} = \frac{P75 - P25}{P75 + P25} \f] + * - FirstOrderHistogram::Entropy Value: The entropy is only based on histogram bins with a probability greater than 0.0000001: \f[ \textup{entropy} = - \sum p_i \textup{log}_2 p_i \f] + * - FirstOrderHistogram::Uniformity Value: \f$ \sum p_i^2 \f$ + * - FirstOrderHistogram::Mean Index: The mean index of all voxels, calulated by \f$ \mu_i = \sum p_i i\f$. + * - FirstOrderHistogram::Variance Index: The variance index is calculated as : \f$ \sigma_i^2 = \sum p_i (i - \mu_i)^2\f$. + * - FirstOrderHistogram::Skewness Index: \f[ skewness = \frac{\sum p_i (i - \mu_i)^3}{\sigma_i^3} \f] + * - FirstOrderHistogram::Excess Kurtosis Index: \f[ skewness = \frac{\sum p_i (i - \mu_i)^4}{\sigma_i^4} - 3 \f] + * - FirstOrderHistogram::Median Index: The median index value based on the histogram values. + * - FirstOrderHistogram::Minimum Index: The index of the minimum observed intensity value. + * - FirstOrderHistogram::Percentile 10 Index: The index oft the intensity that is equal or greater than 10% of all observed intensities. + * - FirstOrderHistogram::Percentile 90 Index: The index of the intensity that is equal or greater than 90% of all observed intensities. + * - FirstOrderHistogram::Maximum Index: The index of the maximum observerd intensity value. + * - FirstOrderHistogram::Mode Index: The index of the most common intensity value, i.e. the index of the bin with the highest probability. + * - FirstOrderHistogram::Interquantile Range Index: The index difference between Percentile 75% (\f$ P75\f$) and Percentile 25% (\f$ P25\f$). + * - FirstOrderHistogram::Range Index: The index difference between the index of the observed maximum and minimum intensity. + * - FirstOrderHistogram::Mean Absolute Deviation Index: \f[ \textup{mean absolute deviation} = \sum p_i \left \| (i - \mu_i) \right \| \f] + * - FirstOrderHistogram::Robust Mean Absolute Deviation Index: The Mean absolute deviation for all values between the 10% and 90% quantile. It is based on the robust mean value. + * - FirstOrderHistogram::Median Absolute Deviation Index: \f[ \textup{mean absolute deviation} = \sum p_i \left \| (i - \textup{median}) \right \| \f] + * - FirstOrderHistogram::Coefficient of Variation Index: \f[ \frac{\sigma_i}{\mu_i} \f] + * - FirstOrderHistogram::Quantile coefficient of Dispersion Index: \f[ \textup{Quantile coefficient of Dispersion} = \frac{P75 - P25}{P75 + P25} \f] + * - FirstOrderHistogram::Entropy Index: The entropy is only based on histogram bins with a probability greater than 0.0000001: \f$ \textup{entropy} = - \sum p_i \textup{log}_2 p_i \f$. Note that this is the same as the entropy value. + * - FirstOrderHistogram::Uniformity Index: \f$ \sum p_i^2 \f$. Note that this is the same as the uniformity value. + * - FirstOrderHistogram::Maximum Gradient: The maximum difference between the probability of three neighbouring bins. For bins at the edge of the histogram, only two bins are used for the calulation. + * - FirstOrderHistogram::Maximum Gradient Index: The index of the bin that belongs to the maximum gradient. + * - FirstOrderHistogram::Minimum Gradient: The minimum difference between the probability of three neighbouring bins. For bins at the edge of the histogram, only two bins are used for the calulation. + * - FirstOrderHistogram::Minimum Gradient Index:The index of the bin that belongs to the minimum gradient. + * - FirstOrderHistogram::Robust Mean Index: The mean index of all intensities between the 10% and 90% quantile. + * - FirstOrderHistogram::Number of Bins: The number of bins in the histogram. This is rather for control, as this parameter is likely to be determined by the configuration rather than the image. + * - FirstOrderHistogram::Bin Size: The binsize of the bins from the histogram. This is rather for control, as this parameter is likely to be determined by the configuration rather than the image. + */ class MITKCLUTILITIES_EXPORT GIFFirstOrderHistogramStatistics : public AbstractGlobalImageFeature { public: mitkClassMacro(GIFFirstOrderHistogramStatistics,AbstractGlobalImageFeature) itkFactorylessNewMacro(Self) itkCloneMacro(Self) GIFFirstOrderHistogramStatistics(); /** * \brief Calculates the Cooccurence-Matrix based features for this class. */ virtual 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 */ virtual FeatureNameListType GetFeatureNames() override; itkGetConstMacro(Range,double); itkSetMacro(Range, double); itkGetConstMacro(HistogramSize,int); itkSetMacro(HistogramSize, int); itkGetConstMacro(UseCtRange,bool); itkSetMacro(UseCtRange, bool); itkGetConstMacro(BinSize, double); itkSetMacro(BinSize, double); virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); struct ParameterStruct { - int m_HistogramSize; - bool m_UseCtRange; - double MinimumIntensity; - bool UseMinimumIntensity; double MaximumIntensity; - bool UseMaximumIntensity; int Bins; - double BinSize; }; private: double m_Range; int m_HistogramSize; bool m_UseCtRange; double m_BinSize; }; } #endif //mitkGIFFirstOrderHistogramStatistics_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderStatistics.h index 1a7a919b16..0bc4c2d034 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderStatistics.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderStatistics.h @@ -1,73 +1,162 @@ /*=================================================================== 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 GIFFirstOrderStatistics : 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(GIFFirstOrderStatistics,AbstractGlobalImageFeature) itkFactorylessNewMacro(Self) itkCloneMacro(Self) GIFFirstOrderStatistics(); /** - * \brief Calculates the Cooccurence-Matrix based features for this class. + * \brief Calculates the First Order Features based on a binned version of the image. */ virtual 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 */ virtual FeatureNameListType GetFeatureNames() override; - itkGetConstMacro(Range,double); - itkSetMacro(Range, double); - itkGetConstMacro(HistogramSize,int); - itkSetMacro(HistogramSize, int); - itkGetConstMacro(UseCtRange,bool); - itkSetMacro(UseCtRange, bool); - virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); struct ParameterStruct { - int m_HistogramSize; - bool m_UseCtRange; - double MinimumIntensity; - bool UseMinimumIntensity; double MaximumIntensity; - bool UseMaximumIntensity; int Bins; }; - private: - double m_Range; - int m_HistogramSize; - bool m_UseCtRange; }; } #endif //mitkGIFFirstOrderStatistics_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFGrayLevelSizeZone.h b/Modules/Classification/CLUtilities/include/mitkGIFGrayLevelSizeZone.h deleted file mode 100644 index 0046ef4f1d..0000000000 --- a/Modules/Classification/CLUtilities/include/mitkGIFGrayLevelSizeZone.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef mitkGIFGrayLevelSizeZone_h -#define mitkGIFGrayLevelSizeZone_h - -#include -#include -#include - -namespace mitk -{ - class MITKCLUTILITIES_EXPORT GIFGrayLevelSizeZone : public AbstractGlobalImageFeature - { - public: - mitkClassMacro(GIFGrayLevelSizeZone,AbstractGlobalImageFeature) - itkFactorylessNewMacro(Self) - itkCloneMacro(Self) - - GIFGrayLevelSizeZone(); - - /** - * \brief Calculates the Cooccurence-Matrix based features for this class. - */ - virtual 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 - */ - virtual FeatureNameListType GetFeatureNames() override; - - itkGetConstMacro(Range,double); - itkSetMacro(Range, double); - - itkGetConstMacro(UseCtRange, bool); - itkSetMacro(UseCtRange, bool); - - virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); - virtual void AddArguments(mitkCommandLineParser &parser); - - - struct ParameterStruct - { - bool m_UseCtRange; - double m_Range; - unsigned int m_Direction; - }; - - private: - double m_Range; - bool m_UseCtRange; - }; -} -#endif //mitkGIFGrayLevelSizeZone_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelDistanceZone.h b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelDistanceZone.h index 8a77f1025d..12b7a4e662 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelDistanceZone.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelDistanceZone.h @@ -1,125 +1,193 @@ #ifndef mitkGIFGreyLevelDistanceZone_h #define mitkGIFGreyLevelDistanceZone_h #include #include #include #include namespace mitk { struct GreyLevelDistanceZoneMatrixHolder { public: GreyLevelDistanceZoneMatrixHolder(double min, double max, int number, int maxSize); 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; int m_MaximumSize; int m_NumerOfVoxels; Eigen::MatrixXd m_Matrix; }; struct GreyLevelDistanceZoneFeatures { GreyLevelDistanceZoneFeatures() : SmallDistanceEmphasis(0), LargeDistanceEmphasis(0), LowGreyLevelEmphasis(0), HighGreyLevelEmphasis(0), SmallDistanceLowGreyLevelEmphasis(0), SmallDistanceHighGreyLevelEmphasis(0), LargeDistanceLowGreyLevelEmphasis(0), LargeDistanceHighGreyLevelEmphasis(0), GreyLevelNonUniformity(0), GreyLevelNonUniformityNormalized(0), ZoneDistanceNonUniformity(0), ZoneDistanceNoneUniformityNormalized(0), ZonePercentage(0), GreyLevelMean(0), GreyLevelVariance(0), ZoneDistanceMean(0), ZoneDistanceVariance(0), ZoneDistanceEntropy(0) { } public: double SmallDistanceEmphasis; double LargeDistanceEmphasis; double LowGreyLevelEmphasis; double HighGreyLevelEmphasis; double SmallDistanceLowGreyLevelEmphasis; double SmallDistanceHighGreyLevelEmphasis; double LargeDistanceLowGreyLevelEmphasis; double LargeDistanceHighGreyLevelEmphasis; double GreyLevelNonUniformity; double GreyLevelNonUniformityNormalized; double ZoneDistanceNonUniformity; double ZoneDistanceNoneUniformityNormalized; double ZonePercentage; double GreyLevelMean; double GreyLevelVariance; double ZoneDistanceMean; double ZoneDistanceVariance; double ZoneDistanceEntropy; }; class MITKCLUTILITIES_EXPORT GIFGreyLevelDistanceZone : public AbstractGlobalImageFeature { + /** + * \brief Calculates the Grey Level Distance Zone + * + * This class can be used to calculate Grey Level Distance Zone as presented in Thibault et al. 2014. + * + * The basic idea behind the Grey Level Distance Zone based features is to count the connected areas + * with a given intensity value \f$x_i\f$ and a given distance to the border of each segmentation \f$d_i\f$. + * Several features are then calculated based on a matrix, that gives the number of occurence for each + * combination of \f$x_i\f$ and \f$ d_i \f$ as \f$m_{x,d}\f$. + * + * This feature calculator is activated by the option -grey-level-distance-zone or -gldz. + * + * 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. It is expected that the image contains only voxels with value 0 and 1, + * of which all voxels with an value equal to one are treated as masked. + * + * The features depend on the distance to the border of the segmentation ROI. In some cases, the border + * definition might be different from the definition of the masked area, for example, if small openings + * in the mask should not influence the distance. Due to that, it is possible to submit a second mask, + * named Morphological Mask to the features that is then used to calculate the distance of each voxel to + * border of the segmented area. The morpological mask can be either set by the function call SetMorphMask() + * or by the corresponding global option. (Not parsed by the filter itself, but by the command line tool). + * + * Beside the complete matrix, which is represented by its individual elements \f$m_{x,d}\f$, som eadditional + * values are used for the definition. \f$N_g\f$ is the number of discrete grey levels, \f$ N_d\f$ the number + * (or maximum value) of possible distances, and \f$N_s\f$ the total number of zones. + * \f$m_{x,d}\f$ gives the number of connected areas with the discrete + * grey level x and distance to the boarder of d. Corresponding, \f$p_{x,d} = \frac{m_{x,d}}{N_s} gives the relativ + * probability of this matrix cell. \f$ \f$N_v\f$ is the number of voxels. In addition, the marginal + * sums \f$m_{x,\cdot} = m_x = \sum_d m_{x,d} \f$ , representing the sum of all zones with a given intensity, and + * sums \f$m_{\cdot, d} = m_d = \sum_x m_{x,d} \f$ , representing the sum of all zones with a given distance, are used. + * The distance are given as the number of voxels to the border and the voxel intensity is given as the + * bin number of the binned image, starting with 1. + * + * The following features are then defined: + * - Grey Level Distance Zone::Small Distance Emphasis: + * \f[ \textup{Small Distance Emphasis}= \frac{1}{N_s} \sum_d \frac{m_d}{d^2} \f] + * - Grey Level Distance Zone::Large Distance Emphasis: + * \f[ \textup{Large Distance Emphasis}= \frac{1}{N_s} \sum_d d^2 m_d \f] + * - Grey Level Distance Zone::Low Grey Level Emphasis: + * \f[ \textup{Low Grey Level Emphasis}= \frac{1}{N_s} \sum_x \frac{m_x}{x^2} \f] + * - Grey Level Distance Zone::High Grey Level Emphasis: + * \f[ \textup{High Grey Level Emphasis}= \frac{1}{N_s} \sum_x x^2 m_x \f] + * - Grey Level Distance Zone::Small Distance Low Grey Level Emphasis: + * \f[ \textup{Small Distance Low Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_d \frac{ m_{x,d}}{x^2 d^2}\f] + * - Grey Level Distance Zone::Small Distance High Grey Level Emphasis: + * \f[ \textup{Small Distance High Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_d \frac{x^2 m_{x,d}}{d^2}\f] + * - Grey Level Distance Zone::Large Distance Low Grey Level Emphasis: + * \f[ \textup{Large Distance Low Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_d \frac{d^2 m_{x,d}}{x^2}\f] + * - Grey Level Distance Zone::Large Distance High Grey Level Emphasis: + * \f[ \textup{Large Distance High Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_d \x^2 d^2 m_{x,d} \f] + * - Grey Level Distance Zone::Grey Level Non-Uniformity: + * \f[ \textup{Grey Level Non-Uniformity}= \frac{1}{N_s} \sum_x m_x^2 \f] + * - Grey Level Distance Zone::Grey Level Non-Uniformity Normalized: + * \f[ \textup{Grey Level Non-Uniformity Normalized}= \frac{1}{N_s^2} \sum_x m_x^2 \f] + * - Grey Level Distance Zone::Zone Distance Non-Uniformity: + * \f[ \textup{Grey Level Non-Uniformity}= \frac{1}{N_s} \sum_d m_d^2 \f] + * - Grey Level Distance Zone::Zone Distance Non-Uniformity Normalized: + * \f[ \textup{Grey Level Non-Uniformity Normalized}= \frac{1}{N_s^2} \sum_d m_d^2 \f] + * - Grey Level Distance Zone::Zone Percentage: The ratio of zones to the possible zones: + * \f[ \textup{Zone Percentage}= \frac{N_s}{N_v} \f] + * - Grey Level Distance Zone::Grey Level Mean: + * \f[ \textup{Grey Level Mean}= \mu_x = \sum_x \sum_d x p_{x,d} \f] + * - Grey Level Distance Zone::Grey Level Variance: + * \f[ \textup{Grey Level Variance} = \sum_x \sum_d \left(x - \mu_x \right)^2 p_{x,d} \f] + * - Grey Level Distance Zone::Zone Distance Mean: + * \f[ \textup{Zone Distance Mean}= \mu_d = \sum_x \sum_d d p_{x,d} \f] + * - Grey Level Distance Zone::Zone Distance Variance: + * \f[ \textup{Zone Distance Variance} = \sum_x \sum_d \left(d - \mu_d \right)^2 p_{x,d} \f] + * - Grey Level Distance Zone::Zone Distance Entropy : + * \f[ \textup{Zone Distance Entropy} = - \sum_x \sum_d p_{x,d} \textup{log}_2 ( p_{x,d} ) \f] + * - Grey Level Distance Zone::Grey Level Entropy : + * \f[ \textup{Grey Level Entropy} = - \sum_x \sum_d p_{x,d} \textup{log}_2 ( p_{x,d} ) \f] + */ public: mitkClassMacro(GIFGreyLevelDistanceZone, AbstractGlobalImageFeature); itkFactorylessNewMacro(Self) itkCloneMacro(Self) GIFGreyLevelDistanceZone(); /** * \brief Calculates the Cooccurence-Matrix based features for this class. */ virtual 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 */ virtual FeatureNameListType GetFeatureNames() override; virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); - itkGetConstMacro(Range,double); - itkSetMacro(Range, double); - itkGetConstMacro(Bins, int); - itkSetMacro(Bins, int); - struct GIFGreyLevelDistanceZoneConfiguration { mitk::Image::Pointer distanceMask; - double range; unsigned int direction; - double MinimumIntensity; - bool UseMinimumIntensity; double MaximumIntensity; - bool UseMaximumIntensity; int Bins; }; private: - double m_Range; - int m_Bins; }; } #endif //mitkGIFGreyLevelDistanceZone_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFGrayLevelRunLength.h b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelRunLength.h similarity index 83% rename from Modules/Classification/CLUtilities/include/mitkGIFGrayLevelRunLength.h rename to Modules/Classification/CLUtilities/include/mitkGIFGreyLevelRunLength.h index c9ff93d77a..630d021bb8 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFGrayLevelRunLength.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelRunLength.h @@ -1,57 +1,57 @@ -#ifndef mitkGIFGrayLevelRunLength_h -#define mitkGIFGrayLevelRunLength_h +#ifndef mitkGIFGreyLevelRunLength_h +#define mitkGIFGreyLevelRunLength_h #include #include #include namespace mitk { - class MITKCLUTILITIES_EXPORT GIFGrayLevelRunLength : public AbstractGlobalImageFeature + class MITKCLUTILITIES_EXPORT GIFGreyLevelRunLength : public AbstractGlobalImageFeature { public: - mitkClassMacro(GIFGrayLevelRunLength,AbstractGlobalImageFeature) + mitkClassMacro(GIFGreyLevelRunLength,AbstractGlobalImageFeature) itkFactorylessNewMacro(Self) itkCloneMacro(Self) - GIFGrayLevelRunLength(); + GIFGreyLevelRunLength(); /** * \brief Calculates the Cooccurence-Matrix based features for this class. */ virtual 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 */ virtual FeatureNameListType GetFeatureNames() override; itkGetConstMacro(Range,double); itkSetMacro(Range, double); itkGetConstMacro(UseCtRange, bool); itkSetMacro(UseCtRange, bool); virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); struct ParameterStruct { bool m_UseCtRange; double m_Range; unsigned int m_Direction; double MinimumIntensity; bool UseMinimumIntensity; double MaximumIntensity; bool UseMaximumIntensity; int Bins; }; private: double m_Range; bool m_UseCtRange; }; } -#endif //mitkGIFGrayLevelRunLength_h +#endif //mitkGIFGreyLevelRunLength_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelSizeZone.h b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelSizeZone.h index 7c17edf408..af39be735d 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelSizeZone.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelSizeZone.h @@ -1,122 +1,178 @@ #ifndef mitkGIFGreyLevelSizeZone_h #define mitkGIFGreyLevelSizeZone_h #include #include #include #include namespace mitk { struct GreyLevelSizeZoneMatrixHolder { public: GreyLevelSizeZoneMatrixHolder(double min, double max, int number, int maxSize); 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; int m_MaximumSize; Eigen::MatrixXd m_Matrix; }; struct GreyLevelSizeZoneFeatures { GreyLevelSizeZoneFeatures() : SmallZoneEmphasis(0), LargeZoneEmphasis(0), LowGreyLevelEmphasis(0), HighGreyLevelEmphasis(0), SmallZoneLowGreyLevelEmphasis(0), SmallZoneHighGreyLevelEmphasis(0), LargeZoneLowGreyLevelEmphasis(0), LargeZoneHighGreyLevelEmphasis(0), GreyLevelNonUniformity(0), GreyLevelNonUniformityNormalized(0), ZoneSizeNonUniformity(0), ZoneSizeNoneUniformityNormalized(0), ZonePercentage(0), GreyLevelMean(0), GreyLevelVariance(0), ZoneSizeMean(0), ZoneSizeVariance(0), ZoneSizeEntropy(0) { } public: double SmallZoneEmphasis; double LargeZoneEmphasis; double LowGreyLevelEmphasis; double HighGreyLevelEmphasis; double SmallZoneLowGreyLevelEmphasis; double SmallZoneHighGreyLevelEmphasis; double LargeZoneLowGreyLevelEmphasis; double LargeZoneHighGreyLevelEmphasis; double GreyLevelNonUniformity; double GreyLevelNonUniformityNormalized; double ZoneSizeNonUniformity; double ZoneSizeNoneUniformityNormalized; double ZonePercentage; double GreyLevelMean; double GreyLevelVariance; double ZoneSizeMean; double ZoneSizeVariance; double ZoneSizeEntropy; }; class MITKCLUTILITIES_EXPORT GIFGreyLevelSizeZone : public AbstractGlobalImageFeature { + /** + * \brief Calculates the Grey level size zone based features. + * + * Grey level size zone based features are similar to Grey Level Cooccurence features. But instead + * of measuring the similarity within a given neighbourhood, the size of areas with the same intensity + * is assessed. For this, a matrix is created that gives the number of areas \f$ m_{x,s} \f$ with the intensity \f$ x \f$ and + * the size of \f$ s \f$. Each area is specified as connected voxels with the given intensity. + * + * The image is quantified prior to the calculation of the features. This reduces the number of + * available intensity values. Instead of using the pure intensity value, the features are + * calculated using the number of the bins as intensity value \f$ x_i \f$. The parameter of the + * quantification of the image can be controlled using the general binning parameters as defined + * in AbstractGlobalImageFeature. + * + * By default, the calculation is based on a 26 neighourhood for 3D and a 8 neighbourhood in 2D. It is further + * possible to exclude directions from the calculation, e.g. calculating the feature in 2D, even if a + * 3D image is passed. This is controlled by determine the + * dimensionality of the neighbourhood using direction-related commands as described in AbstractGlobalImageFeature. + * No other options are possible beside these two options. + * + * This feature calculator is activated by the option -grey-level-sizezone or -glsz. + * + * 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. + * + * Several values are definied for the definition of the features. \f$ N_v \f$ is the number of masked voxels, + * \f$N_s \f$ is the number of different zones, \f$ m_{x,\cdot} = \sum_s m{x,s} \f$ is the number of all areas + * with a given intensity value, and likewise \f$ m_{\cdot, s} = \sum_x m{x,s} \f$ is the number of all areas + * with a given size. The features are then defined as: + * - Grey Level Size Zone::Small Zone Emphasis: + * \f[ \textup{Small Zone Emphasis}= \frac{1}{N_s} \sum_s { \frac{m_{\cdot, s}}{s^2} } \f] + * - Grey Level Size Zone::Large Zone Emphasis: + * \f[ \textup{Large Zone Emphasis}= \frac{1}{N_s} \sum_s { m_{\cdot, s} s^2} \f] + * - Grey Level Size Zone::Low Grey Level Zone Emphasis: + * \f[ \textup{Low Grey Level Zone Emphasis}= \frac{1}{N_s} \sum_x { \frac{m_{x,\cdot}}{x^2} } \f] + * - Grey Level Size Zone::High Grey Level Zone Emphasis: + * \f[ \textup{High Grey Level Zone Emphasis}= \frac{1}{N_s} \sum_x { m_{x,\cdot} x^2} \f] + * - Grey Level Size Zone::Small Zone Low Grey Level Emphasis: + * \f[ \textup{Small Zone Low Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_s { \frac{m_{x,s}}{x^2 s^2} } \f] + * - Grey Level Size Zone::Small Zone High Grey Level Emphasis: + * \f[ \textup{Small Zone High Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_s { \frac{x^2 m_{x,s}}{s^2} } \f] + * - Grey Level Size Zone::Large Zone Low Grey Level Emphasis: + * \f[ \textup{Large Zone Low Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_s { \frac{s^2 m_{x,s}}{x^2} } \f] + * - Grey Level Size Zone::Large Zone High Grey Level Emphasis: + * \f[ \textup{Large Zone High Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_s { x^2 s^2 m_{x,s} } \f] + * - Grey Level Size Zone::Grey Level Non-Uniformity: + * \f[ \textup{Grey Level Non-Uniformity}= \frac{1}{N_s} \sum_x m_{x,\cdot}^2 \f] + * - Grey Level Size Zone::Grey Level Non-Uniformity Normalized: + * \f[ \textup{Grey Level Non-Uniformity Normalized}= \frac{1}{N_s^2} \sum_x m_{x,\cdot}^2 \f] + * - Grey Level Size Zone::Zone Size Non-Uniformity: + * \f[ \textup{Zone Size Non-Uniformity}= \frac{1}{N_s} \sum_s m_{\cdot, s}^2 \f] + * - Grey Level Size Zone::Zone Size Non-Uniformity Normalized: + * \f[ \textup{Zone Size Non-Uniformity Normalized}= \frac{1}{N_s^2} \sum_s m_{\cdot, s}^2 \f] + * - Grey Level Size Zone::Zone Percentage: The ratio of realized areas to the theoretical limit of zones: + * \f[ \textup{Zone Percentage}= \frac{N_s}{N_v} \f] + * - Grey Level Size Zone::Grey Level Mean: + * \f[ \textup{Grey Level Mean} = \mu_x = \frac{1}{N_s} \sum_x x m_{x, \cdot} \f] + * - Grey Level Size Zone::Grey Level Variance: + * \f[ \textup{Grey Level Variance} = \frac{1}{N_s} \sum_x (x -mu_x)^2 m_{x, \cdot} \f] + * - Grey Level Size Zone::Zone Size Mean: + * \f[ \textup{Zone Size Mean} = \mu_s = \frac{1}{N_s} \sum_s s m_{\cdot, s} \f] + * - Grey Level Size Zone::Grey Level Variance: + * \f[ \textup{Grey Level Variance} = \frac{1}{N_s} \sum_s (s -mu_s)^2 m_{\cdot, s} \f] + * - Grey Level Size Zone::Zone Size Entropy: This feature would be equivalent with + * the Grey Level Entropy, which is therefore not included. It is based on the likelihood + * for a given intensity- size combination \f$ p_{x,s} = \frac{m_{x,s}}{N_s} \f$. : + * \f[ \textup{Zone Size Entropy} = \sum_x \sum_s p_{x,s} \textup{log}_2 \left( p{_x,s} \right) \f] + */ public: mitkClassMacro(GIFGreyLevelSizeZone, AbstractGlobalImageFeature); itkFactorylessNewMacro(Self) itkCloneMacro(Self) GIFGreyLevelSizeZone(); /** * \brief Calculates the Cooccurence-Matrix based features for this class. */ virtual 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 */ virtual FeatureNameListType GetFeatureNames() override; virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); - itkGetConstMacro(Range,double); - itkSetMacro(Range, double); - itkGetConstMacro(Bins, int); - itkSetMacro(Bins, int); - struct GIFGreyLevelSizeZoneConfiguration { - double range; unsigned int direction; double MinimumIntensity; - bool UseMinimumIntensity; double MaximumIntensity; - bool UseMaximumIntensity; int Bins; }; - - private: - double m_Range; - int m_Bins; }; } #endif //mitkGIFGreyLevelSizeZone_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFImageDescriptionFeatures.h b/Modules/Classification/CLUtilities/include/mitkGIFImageDescriptionFeatures.h index 899f4c1a89..cb1b6882a6 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFImageDescriptionFeatures.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFImageDescriptionFeatures.h @@ -1,73 +1,91 @@ /*=================================================================== 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 mitkGIFImageDescriptionFeatures_h #define mitkGIFImageDescriptionFeatures_h #include #include #include namespace mitk { + /** + * \brief Calculates simple features that describe the given image / mask + * + * This class can be used to calculated simple image describing features that + * can be used to compare different images. + * + * This feature calculator is activated by the option "-image-diagnostic" or "-id". + * There are no parameters to further define the behavior of this feature calculator. + * + * The paramters for this image are calculated from two images, a mask and an intenstiy + * image. It is assumed that the mask is + * of the type of an unsigned short image and all voxels with an value larger or equal + * to one are treated as masked. (Standard MITK mask) + * + * The definition of X, Y, and Z axis depends on the image format and does not necessarily + * correlates with axial, coronal, and sagittal. + * + * The features of this calculator are: + * - Diagnostic (Image)::Dimension X: The number of voxels in the intensity image along the first image dimension. + * - Diagnostic (Image)::Dimension Y: The number of voxels in the intensity image along the second image dimension. + * - Diagnostic (Image)::Dimension Z: The number of voxels in the intensity image along the third image dimension. + * - Diagnostic (Image)::Spacing X: The spacing of the intensity image in the first image dimension. + * - Diagnostic (Image)::Spacing Y: The spacing of the intensity image in the second image dimension. + * - Diagnostic (Image)::Spacing Z: The spacing of the intensity image in the third image dimension. + * - Diagnostic (Image)::Mean intensity: The mean intensity of the whole image. + * - Diagnostic (Image)::Minimum intensity: The minimum intensity that occurs in the whole image. + * - Diagnostic (Image)::Maximum intensity: The maximum intensity that occurs in the whole image. + * - Diagnostic (Mask)::Dimension X: The number of voxels in the mask image along the first image dimension. + * - Diagnostic (Mask)::Dimension Y: The number of voxels in the mask image along the second image dimension. + * - Diagnostic (Mask)::Dimension Z: The number of voxels in the mask image along the third image dimension. + * - Diagnostic (Mask)::Mask bounding box X: The distance between the maximum and minimum position of a masked voxel along the first axis. + * - Diagnostic (Mask)::Mask bounding box X: The distance between the maximum and minimum position of a masked voxel along the second axis. + * - Diagnostic (Mask)::Mask bounding box X: The distance between the maximum and minimum position of a masked voxel along the third axis. + * - Diagnostic (Mask)::Spacing X: The spacing of the mask image in the first image dimension. + * - Diagnostic (Mask)::Spacing Y: The spacing of the mask image in the second image dimension. + * - Diagnostic (Mask)::Spacing Z: The spacing of the mask image in the third image dimension. + * - Diagnostic (Mask)::Voxel count: The number of voxels that are masked. + * - Diagnostic (Mask)::Mean intensity: The mean intensity of all voxel that are masked. Also depends on the intensity image. + * - Diagnostic (Mask)::Minimum intensity The minimum masked intensity in the intensity image. + * - Diagnostic (Mask)::Maximum intensity The maximum masked intensity in the intensity image. + */ class MITKCLUTILITIES_EXPORT GIFImageDescriptionFeatures : public AbstractGlobalImageFeature { public: mitkClassMacro(GIFImageDescriptionFeatures,AbstractGlobalImageFeature) itkFactorylessNewMacro(Self) itkCloneMacro(Self) GIFImageDescriptionFeatures(); /** * \brief Calculates the Cooccurence-Matrix based features for this class. */ virtual 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 */ virtual FeatureNameListType GetFeatureNames() override; - itkGetConstMacro(Range,double); - itkSetMacro(Range, double); - itkGetConstMacro(HistogramSize,int); - itkSetMacro(HistogramSize, int); - itkGetConstMacro(UseCtRange,bool); - itkSetMacro(UseCtRange, bool); - virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); - - struct ParameterStruct { - int m_HistogramSize; - bool m_UseCtRange; - - double MinimumIntensity; - bool UseMinimumIntensity; - double MaximumIntensity; - bool UseMaximumIntensity; - int Bins; - }; - - private: - double m_Range; - int m_HistogramSize; - bool m_UseCtRange; }; } #endif //mitkGIFImageDescriptionFeatures_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFIntensityVolumeHistogramFeatures.h b/Modules/Classification/CLUtilities/include/mitkGIFIntensityVolumeHistogramFeatures.h index 9bde8ddc48..bdd6e5d8cc 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFIntensityVolumeHistogramFeatures.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFIntensityVolumeHistogramFeatures.h @@ -1,51 +1,86 @@ /*=================================================================== 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 mitkGIFIntensityVolumeHistogramFeatures_h #define mitkGIFIntensityVolumeHistogramFeatures_h #include #include #include namespace mitk { + /** + * \brief Calculates the Intensity Volume Histogram features + * + * This class can be used to calculate the volume histogram and features that are calculated from + * it. It is based on the intensity-volume histogram (IVH) which describes the relation between the + * grey level index i (and the corresponding intensity \f§x_i\f$) and the volume fraction \f$f\f$ that + * with an intensity that is equal or greater than \f$x_i\f$. This feature is original proposed in + * El Naqa et al. Exploring feature-based approaches in PET images for prediciting cancer treatment outcomes. + * Pattern recognition 2009. + * + * This feature calculator is activated by the option "-intensity-volume-histogram" or "-ivoh". + * Beside the configuration of the histogram, which follows the describtion given in AbstractGlobalImageFeature + * there are no additional parameters to configure this feature. Remark that, different from other features, + * the number of bins is 1000 by default and not 256. + * + * The features are calculated based on a mask. It is assumed that the mask is + * of the type of an unsigned short image and all voxels with an value of greater than zero + * are treated as masked. + * + * The resulting features are: + * - Intensity Volume Histogram::Volume fration at 0.10 intensity: The volume fraction with an intensity + * of greater or equal to 10% of the maximum intensity. + * - Intensity Volume Histogram::Volume fration at 0.90 intensity: The volume fraction with an intensity + * of greater or equal to 90% of the maximum intensity. + * - Intensity Volume Histogram::Intensity at 0.10 volume: The highest intensity so that at least + * 10% of the masked image area has the same or higher intensity. + * - Intensity Volume Histogram::Intensity at 0.90 volume: The highest intensity so that at least + * 10% of the masked image area has the same or higher intensity. + * - Intensity Volume Histogram::Difference volume fration at 0.10 and 0.90 intensity: The difference + * between the volume fraction at 10% intensity and 90% intensity. + * - Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume: The intensity difference + * between the intenstiy of 90% of the volume and 10% volume. + * - Intensity Volume Histogram::Area under IVH curve: If the IVH is interpreted as curve, this value represents + * the area under the curve. It is calculated using the bin indexes rather than the intensity values. + */ class MITKCLUTILITIES_EXPORT GIFIntensityVolumeHistogramFeatures : public AbstractGlobalImageFeature { public: mitkClassMacro(GIFIntensityVolumeHistogramFeatures, AbstractGlobalImageFeature); itkFactorylessNewMacro(Self) itkCloneMacro(Self) GIFIntensityVolumeHistogramFeatures(); /** * \brief Calculates the Cooccurence-Matrix based features for this class. */ virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature); /** * \brief Returns a list of the names of all features that are calculated from this class */ virtual FeatureNameListType GetFeatureNames(); virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); private: }; } #endif //mitkGIFIntensityVolumeHistogramFeatures_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFLocalIntensity.h b/Modules/Classification/CLUtilities/include/mitkGIFLocalIntensity.h index 50000d7416..00aa3d2b13 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFLocalIntensity.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFLocalIntensity.h @@ -1,51 +1,80 @@ /*=================================================================== 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 mitkGIFLocalIntensity_h #define mitkGIFLocalIntensity_h #include #include #include namespace mitk { + /** + * \brief Calculates the local intensity features + * + * This class can be used to calcualte the local intensity. The local intensity is defined as the + * mean intensity in a cube with the volume \f$ 1 \textup{cm}^3\f$ which correspond to a radius + * of approximate 0.62 cm. + * + * This feature calculator is activated by the option -local-intensity or -loci. + * + * The range that is used to calculate the local intensity can be set using the function SetRange. + * To set it with parameters set the option loci::range which expects an float value that is + * interpreted as mm length of the radius. The default value is 6.2. + * + * The features are calculated based on a mask. It is assumed that the mask is + * of the type of an unsigned short image and all voxels with an value of greater than zero + * are treated as masked. + * + * The resulting features are: + * - Local Intensity::Local Intensity Peak: This value is defined as the local intensity of the + * voxel with the highest intensity. If there are multiple voxels with the highest intensity, the mean + * of all local intensites of these voxels are reported. + * - Local Intensity::Global Intensity Peak: This value is defined as the highest local intensity + * that occur for all voxels within the mask. + */ class MITKCLUTILITIES_EXPORT GIFLocalIntensity : public AbstractGlobalImageFeature { public: mitkClassMacro(GIFLocalIntensity, AbstractGlobalImageFeature); itkFactorylessNewMacro(Self) itkCloneMacro(Self) GIFLocalIntensity(); /** * \brief Calculates the Cooccurence-Matrix based features for this class. */ virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature); /** * \brief Returns a list of the names of all features that are calculated from this class */ virtual FeatureNameListType GetFeatureNames(); virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); + itkGetConstMacro(Range, double); + itkSetMacro(Range, double); + private: + + double m_Range; }; } #endif //mitkGIFLocalIntensity_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h b/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h index 43117da109..d353b41dae 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h @@ -1,51 +1,104 @@ /*=================================================================== 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 mitkGIFNeighbourhoodGreyToneDifferenceFeatures_h #define mitkGIFNeighbourhoodGreyToneDifferenceFeatures_h #include #include #include namespace mitk { + /** + * \brief Calculates the Neighbourhood Grey Tone Difference Features. + * + * This class can be used to calculate Neighbourhood Grey Tone Difference Features which have been introduced in + * Amadasun and King: Textural features corresponding to textural properties. IEEE Transactions on Systems, Man and Cybernetricy, 1989. + * + * The Neighbourhood Grey Tone Difference (NGTD) is based on a table and is calcualted using + * a defined neighbourhood for each voxel. Within this neighbourhood, the mean intensity of the neighbouring + * voxel is calculated \f$A_i\f$, i.e. the mean intensity of the neighbourhood excluding the center voxel. + * Based on this a table with four columns is calculated. The first column represents the voxel + * value, or in our implementation, the histogram bin index \f$i\f$. The second column represents the + * number of voxel with this intensity value \f$n_i\f$. The proability for each intensity value \f$p_i\f$, which + * is equal to the bin probability. And the sum of the absolut differences of the intensity of all voxels with this + * intensity and the mean intensity of their neighbourhood: \f[s_i = \sum \left \| i- A_i \right \| \f]. + * Additional \f$ N_v\f$ is the number of voxels, \f$ N_g \f$ the number of bins, and \f$N_{g,p}\f$ the number of + * bins with a non-zero probability. + * + * This feature calculator is activated by the option -neighbourhood-grey-tone-difference or -ngtd. + * + * The range that is used to calculate the local intensity can be set using the function SetRange. + * To set it with parameters set the option ngtd::range which expects an int value n that is + * interpreted as voxel count. The neighbourhood includes symetrical n voxels additional + * to the center voxel in each directions. The default value for this parameter is 1. + * + * The features are calculated based on a mask. It is assumed that the mask is + * of the type of an unsigned short image and all voxels with an value of greater than zero + * are treated as masked. + * + * For the definition of the features we use the sum, this is always the sum over the bins of the histogram. + * If the denominator of a feature evaluates to zero, the feature is defined as zero. + * The resulting features are: + * - Neighbourhood Grey Tone Difference::Coarsness: The coarsness is defined as : + * \f[ \textup{Coarsness}= \frac{1}{\sum p_i s_i} \f] + * - Neighbourhood Grey Tone Difference::Contrast: The contrast is defined as : + * \f[ \textup{contrast}= \left( \frac{1}{N_{g,p} ( N_{g,p} - 1) } \sum_i \sum_j p_i p_j (i-j)^2 \right) \left( \frac{1}{N_v} \sum s_i \right) \f] + * - Neighbourhood Grey Tone Difference::Busyness: for all bins with a non-zero probability + * \f[ \textup{busyness} = \frac{\sum p_i s_i}{\sum_i \sum_j \left \| i p_i - j p_j \right \| } \f] + * - Neighbourhood Grey Tone Difference::Complexity: for all bins with a non-zero probability + * \f[ \textup{complexity} = \frac{1}{N_v} \sum_i \sum_j \left \| i - j \right \| \frac{p_i s_i + p_j s_j}{p_i + p_j} \f] + * - Neighbourhood Grey Tone Difference::Strength: for all bins with a non-zero probability + * \f[ \textup{strength} = \frac{\sum_i \sum_j (p_i + p_j) (i + j)^2}{\sum_i s_i } \f] + */ class MITKCLUTILITIES_EXPORT GIFNeighbourhoodGreyToneDifferenceFeatures : public AbstractGlobalImageFeature { public: mitkClassMacro(GIFNeighbourhoodGreyToneDifferenceFeatures, AbstractGlobalImageFeature); itkFactorylessNewMacro(Self) itkCloneMacro(Self) GIFNeighbourhoodGreyToneDifferenceFeatures(); /** * \brief Calculates the Cooccurence-Matrix based features for this class. */ virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature); /** * \brief Returns a list of the names of all features that are calculated from this class */ virtual FeatureNameListType GetFeatureNames(); virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); + itkSetMacro(Range, int); + itkGetConstMacro(Range, int); + struct NGTDFeatures + { + int Range = 1; + IntensityQuantifier::Pointer quantifier; + }; private: + + + + int m_Range; }; } #endif //mitkGIFNeighbourhoodGreyToneDifferenceFeatures_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFVolumetricDensityStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFVolumetricDensityStatistics.h index a396eec618..4099809e5f 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFVolumetricDensityStatistics.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFVolumetricDensityStatistics.h @@ -1,51 +1,132 @@ /*=================================================================== 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 mitkGIFVolumetricDensityStatistics_h #define mitkGIFVolumetricDensityStatistics_h #include #include #include namespace mitk { + /** + * \brief Calculates Volumetric Density Features + * + * These features characterize the compactness of the volume and shape by comparing the volumes + * of different volume and shape estimation methods. + * + * This feature calculator is activated by the option -volume-density or -volden. + * + * 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 equal or greater than 1 are treated as masked. + * + * The volume and surface are compared to the volume \f$ V \f$ and surface \f$ A \f$ that is calculated + * directly from the mask. The following features are then defined: + * - Morphological Density::Volume density axis-aligned bounding box: The axis-aligned bounding + * box is defined as the minimum axis aligned box in 3D space that encloses all masked voxels. + * It is calculated by using the maximum spacial extension of the mask. Based on the volume of the + * bounding box, \f$ V_{aabb} \f$, the feature is defined as: + * \f[ \textup{Volume density axis-aligned bounding box}= \frac{V}{V_{aabb}} \f] + * - Morphological Density::Surface density axis-aligned bounding box: As for the previous + * feature, the axis-aligned bounding box is compared to the mask, this time using the surface of the + * bounding box \f$ A_{aabb} \f$: + * \f[ \textup{Surface density axis-aligned bounding box}= \frac{A}{A_{aabb}} \f] + * - Morphological Density::Volume density oriented minimum bounding box: A three-dimensional + * bounding box is defined using the box with the minimum volume. We do not use an estimation + * for this feature, which makes the calculation of this feature slow. Based on the volume of the + * bounding box, \f$ V_{ombb} \f$, the feature is defined as: + * \f[ \textup{Volume density oriented minimum bounding box}= \frac{V}{V_{ombb}} \f] + * - Morphological Density::Surface density axis-aligned bounding box: As for the previous + * feature, theminimum oriented bounding box is compared to the mask, this time using the surface of the + * bounding box \f$ A_{ombb} \f$: + * \f[ \textup{Surface density axis-aligned bounding box}= \frac{A}{A_{ombb}} \f] + * - Morphological Density::Volume density approx. enclosing ellipsoid: Using a Principal Component Analysis (PCA) + * of the spacial coordinates gives the three main axis of the mask. They correspond to the length of + * a eclipse enclosing the mask. The length of the axis of the eclipse are given by the eigenvalues of the + * decomposition: \f$ a = 2 \sqrt{\lambda_1} \f$, \f$ b = 2 \sqrt{\lambda_2} \f$, and \f$ c = 2 \sqrt{\lambda_3} \f$ + * with \f$\lambda_x\f$ being the sorted eigenvalues (higher number indicates larger values). The volume + * of the enclosing eclipse can be estimated by \f$ V_{aee} = 4 \pi a b c \f$: + * \f[ \textup{Volume density approx. enclosing ellipsoid}= \frac{V}{V_{aee}} \f] + * - Morphological Density::Surface density approx. enclosing ellipsoid: As for the previous + * feature, the surface of the enclosing ellipsoid is used. To simplify the calulation of it, an approximation (20 iterations) + * for the surface is used (\f$ \alpha = \sqrt{1-\frac{b^2}{a^2}} \f$, \f$ \beta = \sqrt{1-\frac{c^2}{a^2}} \f$): + * \f[ A_{aee} = 2 \pi a b \frac{\alpha^2 + \beta^2}{\alpha \beta} \sum_v^\infty \frac{(a \beta)^v}{1-a v^2} \f] + * \f[ \textup{Surface density approx. enclosing ellipsoid}= \frac{A}{A_{aee}} \f] + * - Morphological Density::Volume density approx. minimum volume enclosing ellipsoid: + * The volume is compared to the volume of the minimum enclosing ellipsoid. While this ellipsoid can be + * found by brute-force calculation, this is quite time-consuming. It is therefore estimated using + * Khachiyan's Algorithm (Khachiyan, Rounding of Polytopes in the Real Number Model of Computation. Mathematics of Operations Research 1996) + * The so-found ellipsoid is described by the lengths \f$a, b, c \f$ of its axis. The volume is then + * defined as \f$ V_{mvee} = 4 \pi a b c \f$ and the feature given by: + * \f[ \textup{Volume density approx. minimum volume enclosing ellipsoid}= \frac{V}{V_{mvee}} \f] + * - Morphological Density::Surface density approx. minimum volume enclosing ellipsoid: As for the previous + * feature, the surface of the minimum volume enclosing ellipsoid is used. To simplify the calulation of it, + * an approximation with 20 iterations instead of infinite iterations is used for the calculation of the + * the surface (\f$ \alpha = \sqrt{1-\frac{b^2}{a^2}} \f$, \f$ \beta = \sqrt{1-\frac{c^2}{a^2}} \f$): + * \f[ A_{mvee} = 2 \pi a b \frac{\alpha^2 + \beta^2}{\alpha \beta} \sum_v^\infty \frac{(a \beta)^v}{1-a v^2} \f] + * \f[ \textup{Surface density approx. minimum volume enclosing ellipsoid}= \frac{A}{A_{mvee}} \f] + * - Morphological Density::Volume density convex hull: The volume of the density + * hull is calculated using a convex mesh and then calculating the volume of this mesh \f$V_{convex} \f$. + * The feature is then calculated using: + * \f[ \textup{Volume density convex hull}= \frac{V}{V_{convex}} \f] + * - Morphological Density::Surface density convex hull: The surface of the density + * hull is calculated using a convex mesh and then calculating the surface of this mesh \f$A_{convex} \f$. + * The feature is then calculated using: + * \f[ \textup{Volume density convex hull}= \frac{A}{A_{convex}} \f] + * - Morphological Density::Volume integrated intensity: Integrated intensity is the + * average intensity times the volume. It is often used in conjunction with PET-images, where + * this feature is also called "total legion glycolysis". It is defined using the volume \f$V \f$, the + * number of masked voxels \f$ N_v \f$ and the intensity of each voxel \f$ x_i \f$: + * \f[ \textup{Volume integrated intensity}= V \frac{1}{N_v} \sum x_i \f] + * - Morphological Density::Volume Moran's I index: Moran's I index is an measure for + * the spacial autocorrelation. It is defined using the inverse spacial distance between two voxels \f$i, j \f$ \f$w_{ij} \f$, + * the number of masked voxels \f$ N_v \f$, the intensity of each voxel \f$ x_i \f$, + * and the mean intensity of all masked voxels \f$ \mu = \frac{1}{N_v} sum x_i \f$: + * \f[ \textup{Volume Moran's I index}= \frac{N_v}{\sum_i \sum_j w_{ij}} \frac{\sum_i \sum_j (x_i - \mu) (x_j -\mu)}{\sum_i (x_i - \mu)^2 } \enspace \enspace {; i \neq j} \f] + * - Morphological Density::Volume Geary's C measure: Geary's C meansure is similar to Moran's I index. + * However, it is more sensitive to grey level differences and spacial autocorrelation: + * the spacial autocorrelation. It is defined using the inverse spacial distance between two voxels \f$i, j \f$ \f$w_{ij} \f$, + * the number of masked voxels \f$ N_v \f$, the intensity of each voxel \f$ x_i \f$, + * and the mean intensity of all masked voxels \f$ \mu = \frac{1}{N_v} sum x_i \f$: + * \f[ \textup{Volume Geary's C measure}= \frac{N_v - 1}{2 \sum_i \sum_j w_{ij}} \frac{ \sum_i \sum_j w_{ij} (x_i - x_j)^2 }{\sum_i (x_i - \mu)^2 } \enspace \enspace {; i \neq j} \f] + */ class MITKCLUTILITIES_EXPORT GIFVolumetricDensityStatistics : public AbstractGlobalImageFeature { public: mitkClassMacro(GIFVolumetricDensityStatistics,AbstractGlobalImageFeature) itkFactorylessNewMacro(Self) itkCloneMacro(Self) GIFVolumetricDensityStatistics(); /** * \brief Calculates the Cooccurence-Matrix based features for this class. */ virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature); /** * \brief Returns a list of the names of all features that are calculated from this class */ virtual FeatureNameListType GetFeatureNames(); virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); private: }; } #endif //mitkGIFVolumetricDensityStatistics_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFVolumetricStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFVolumetricStatistics.h index 2310cacf87..d6a1062278 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFVolumetricStatistics.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFVolumetricStatistics.h @@ -1,51 +1,137 @@ /*=================================================================== 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 mitkGIFVolumetricStatistics_h #define mitkGIFVolumetricStatistics_h #include #include #include namespace mitk { + /** + * \brief Calulates simpel shape-related features. + * + * This class can be used to calculate simple, shape-related features describing + * a given segmentation. There are no parameters that can be externaly set. + * + * This feature calculator is activated by the option "-volume" or "-vol" + * + * The features are calculated based on a mask. It is assumed that the mask is + * of the type of an unsigned short image and all voxels with an value larger or equal + * to one are treated as masked. (Standard MITK mask) + * + * Some of the features are calculated twice using different methods. For voxel- + * based approaches, the corresponding parameter is calcualted using the voxel, + * for example the volume is then calculated by multiplying the volume of a + * single volume with the number of voxels in the mask. In the second method, the + * mesh based appraoch, a mesh is created prior to the feature calculation which + * is then done using the features. + * + * Another difference between two features might be the evaluation of invalid + * values within the image. There are two possibilities: By default, only those + * voxels are used with an valid intensity value, i.e. where the value is not + * infinite or NaN. The second possibility is not correcting for these voxels + * and only looking at the mask. Features that use these method are marked as + * "(uncorrected)" + * + * The resulting features are: + * - Volumetric Features:: Voxel Volume: \f$ V_{single\_voxel} \f$ , the volume of an single volume, calculated as the + * multiplication of the voxel spacing in all directions. + * - Volumetric Features:: Volume (voxel based): \f$ V_{voxel} \f$, the volume of the masked area. Calulated by + * multiplying the numer of voxels with the Voxel Volume. + * - Volumetric Features:: Volume (mesh based): \f$ V_{shape} \f$, The volume based on the mesh-representation of + * the mask. + * - Volumetric Features:: Surface (voxel based): \f$ A_{voxel} \f$, the surface of the given mask. It is calulated + * by summing the surfaces between a masked and an unmasked voxel. + * - Volumetric Features:: Surface (mesh based): \f$ A_{mesh} \f$, the surface of the given mask calculated using + * the mask representation + * - Volumetric Features:: Surface to volume ration (voxel based): The ratio between voxel based surface and voxel based + * volume given as: \f[ F_{av\_voxel}=\frac{A_{voxel}}{V_{voxel}} \f] + * - Volumetric Features:: Surface to volume ration (mesh based): The ratio between voxel based surface and voxel based + * volume given as: \f[ F_{av\_mesh}=\frac{A_{mesh}}{V_{mesh}} \f] + * - Volumetric Features:: Compactness 1 (voxel based): + * - Volumetric Features:: Compactness 1 (mesh based): + The compatness is a measure how spheric a shape is given. + * Compactness 1 is defined as: + * \f[ F_{compactness\_1} = \frac{V}{\pi^{1/2} A^{3/2}}\f] + * - Volumetric Features:: Compactness 1 old (voxel based): + * - Volumetric Features:: Compactness 1 old (mesh based): Some implementations use a slightly different definition of + * compactness 1. Although this is most likely an error and leads to an non-dimensionless feature, + * this defition is still calculated as: + * \f[ F_{compactness\_1\_old} = \frac{V}{\pi^{1/2} A^{2/3}}\f] + * - Volumetric Features:: Compactness 2 (voxel based): + * - Volumetric Features:: Compactness 2 (mesh based): The compatness is a measure how spheric a shape is given. + * Compactness 2 is defined as: + * \f[ F_{compactness\_1} = 36 \pi \frac{V^2}{A^3}\f] + * - Volumetric Features::Sphericity (voxel based): + * - Volumetric Features::Sphericity (mesh based): Sphericity is measure of how sphere-like a shape is: + * \f[ F_{sphericity} = \frac{(36 \pi V^2)^{1/3}}{A} \f] + * - Volumetric Features::Asphericity (voxel based): + * - Volumetric Features::Asphericity (mesh based): Sphericity is measure of how sphere-like a shape is: + * \f[ F_{asphericity} = \left(\frac{1}{36 \pi }\frac{(A^3}{V^2}\right)^{1/3} - 1 \f] + * - Volumetric Features::Spherical disproportion (voxel based): + * - Volumetric Features::Spherical disproportion (mesh based): Sphericity is measure of how sphere-like a shape is: + * \f[ F_{spherical\_disproportion} = \frac{A}{4\pi R^2}= \frac{A}{\left(36\pi V^2\right)^{1/3}} \f] + * - Volumetric Features:: Maximum 3D diameter: This is the largest distance between the centers of two voxels that + * are masked. + * - Volumetric Features::Bounding box volume: The bounding box volume is the volume of the smallest axis-aligned box + * that encapuslates all voxel centres. + * - Volumetric Features::Centre of mass shift: + * - Volumetric Features::Centre of mass shift (uncorrected): This is the distance between two centres of mass, + * namely the geometric centre and the weighted centre. The geometric centre is the mean position + * of all masked voxels, and the weighted centre is the mean position if the position of each + * voxel is weighted according to its intensity. + * - Volumetric Features::PCA Major Axis length: + * - Volumetric Features::PCA Major Axis length (uncorrected): A Principal component analysis (PCA) of the masekd voxel + * positions will give the main orientation and elongation of the masked area. The resulting + * eigenvectors of the PCA are sorted so that \f$ \lambda_{major}\geq \lambda_{minor} \geq \lambda_{least}\f$. + * The major axis length is defined as: + * \f[ F_{pca\_major} = 4 \sqrt{\lambda_{major}} \f] + * - Volumetric Features::PCA Minor axis length: + * - Volumetric Features::PCA Minor axis length: The Minor axis length is defined as: + * \f[ F_{pca\_minor} = 4 \sqrt{\lambda_{minor}} \f] + * - Volumetric Features::PCA Least axis length: + * - Volumetric Features::PCA Least axis length: The Minor axis length is defined as: + * \f[ F_{pca\_Least} = 4 \sqrt{\lambda_{Least}} \f] + */ class MITKCLUTILITIES_EXPORT GIFVolumetricStatistics : public AbstractGlobalImageFeature { public: mitkClassMacro(GIFVolumetricStatistics,AbstractGlobalImageFeature) itkFactorylessNewMacro(Self) itkCloneMacro(Self) GIFVolumetricStatistics(); /** * \brief Calculates the Cooccurence-Matrix based features for this class. */ virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature); /** * \brief Returns a list of the names of all features that are calculated from this class */ virtual FeatureNameListType GetFeatureNames(); virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); private: }; } #endif //mitkGIFVolumetricStatistics_h diff --git a/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h b/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h index 26ce96cf6a..41226cbf50 100644 --- a/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h +++ b/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h @@ -1,86 +1,87 @@ /*=================================================================== 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 mitkGlobalImageFeaturesParameter_h #define mitkGlobalImageFeaturesParameter_h #include "MitkCLUtilitiesExports.h" #include "mitkCommandLineParser.h" #include namespace mitk { namespace cl { class MITKCLUTILITIES_EXPORT GlobalImageFeaturesParameter { public: void AddParameter(mitkCommandLineParser &parser); void ParseParameter(std::map parsedArgs); std::string imagePath; std::string imageName; std::string imageFolder; std::string maskPath; std::string maskName; std::string maskFolder; std::string outputPath; std::string morphPath; std::string morphName; bool useMorphMask; bool useLogfile; std::string logfilePath; bool writeAnalysisImage; std::string anaylsisImagePath; bool writeAnalysisMask; std::string analysisMaskPath; bool writePNGScreenshots; std::string pngScreenshotsPath; bool useHeader; bool useHeaderForFirstLineOnly; bool ensureSameSpace; bool resampleMask; bool resampleToFixIsotropic; double resampleResolution; + bool ignoreMaskForHistogram; bool defineGlobalMinimumIntensity; double globalMinimumIntensity; bool defineGlobalMaximumIntensity; double globalMaximumIntensity; bool defineGlobalNumberOfBins; int globalNumberOfBins; bool useDecimalPoint; char decimalPoint; private: void ParseFileLocations(std::map &parsedArgs); void ParseAdditionalOutputs(std::map &parsedArgs); void ParseHeaderInformation(std::map &parsedArgs); void ParseMaskAdaptation(std::map &parsedArgs); void ParseGlobalFeatureParameter(std::map &parsedArgs); }; } } #endif //mitkGlobalImageFeaturesParameter_h \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp index 18570d49bf..9cc6438857 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp @@ -1,369 +1,369 @@ #include // MITK #include #include #include // ITK #include #include // STL #include template void CalculateCoocurenceFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFCooccurenceMatrix::FeatureListType & featureList, mitk::GIFCooccurenceMatrix::GIFCooccurenceMatrixConfiguration config) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::Statistics::EnhancedScalarImageToTextureFeaturesFilter FilterType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typedef typename FilterType::TextureFeaturesFilterType TextureFilterType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); typename FilterType::Pointer filter = FilterType::New(); typename FilterType::OffsetVector::Pointer newOffset = FilterType::OffsetVector::New(); auto oldOffsets = filter->GetOffsets(); auto oldOffsetsIterator = oldOffsets->Begin(); while(oldOffsetsIterator != oldOffsets->End()) { bool continueOuterLoop = false; typename FilterType::OffsetType offset = oldOffsetsIterator->Value(); for (unsigned int i = 0; i < VImageDimension; ++i) { offset[i] *= config.range; if (config.direction == i + 2 && offset[i] != 0) { continueOuterLoop = true; } } if (config.direction == 1) { offset[0] = 0; offset[1] = 0; offset[2] = 1; newOffset->push_back(offset); break; } oldOffsetsIterator++; if (continueOuterLoop) continue; newOffset->push_back(offset); } filter->SetOffsets(newOffset); // All features are required typename FilterType::FeatureNameVectorPointer requestedFeatures = FilterType::FeatureNameVector::New(); requestedFeatures->push_back(TextureFilterType::Energy); requestedFeatures->push_back(TextureFilterType::Entropy); requestedFeatures->push_back(TextureFilterType::Correlation); requestedFeatures->push_back(TextureFilterType::InverseDifferenceMoment); requestedFeatures->push_back(TextureFilterType::Inertia); requestedFeatures->push_back(TextureFilterType::ClusterShade); requestedFeatures->push_back(TextureFilterType::ClusterProminence); requestedFeatures->push_back(TextureFilterType::HaralickCorrelation); requestedFeatures->push_back(TextureFilterType::Autocorrelation); requestedFeatures->push_back(TextureFilterType::Contrast); requestedFeatures->push_back(TextureFilterType::Dissimilarity); requestedFeatures->push_back(TextureFilterType::MaximumProbability); requestedFeatures->push_back(TextureFilterType::InverseVariance); requestedFeatures->push_back(TextureFilterType::Homogeneity1); requestedFeatures->push_back(TextureFilterType::ClusterTendency); requestedFeatures->push_back(TextureFilterType::Variance); requestedFeatures->push_back(TextureFilterType::SumAverage); requestedFeatures->push_back(TextureFilterType::SumEntropy); requestedFeatures->push_back(TextureFilterType::SumVariance); requestedFeatures->push_back(TextureFilterType::DifferenceAverage); requestedFeatures->push_back(TextureFilterType::DifferenceEntropy); requestedFeatures->push_back(TextureFilterType::DifferenceVariance); requestedFeatures->push_back(TextureFilterType::InverseDifferenceMomentNormalized); requestedFeatures->push_back(TextureFilterType::InverseDifferenceNormalized); requestedFeatures->push_back(TextureFilterType::InverseDifference); requestedFeatures->push_back(TextureFilterType::JointAverage); requestedFeatures->push_back(TextureFilterType::FirstMeasureOfInformationCorrelation); requestedFeatures->push_back(TextureFilterType::SecondMeasureOfInformationCorrelation); typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); minMaxComputer->SetImage(itkImage); minMaxComputer->Compute(); filter->SetInput(itkImage); filter->SetMaskImage(maskImage); filter->SetRequestedFeatures(requestedFeatures); double min = minMaxComputer->GetMinimum() - 0.5; double max = minMaxComputer->GetMaximum() + 0.5; if (config.UseMinimumIntensity) min = config.MinimumIntensity; if (config.UseMaximumIntensity) max = config.MaximumIntensity; filter->SetPixelValueMinMax(min,max); //filter->SetPixelValueMinMax(-1024,3096); //filter->SetNumberOfBinsPerAxis(5); filter->Update(); auto featureMeans = filter->GetFeatureMeans (); auto featureStd = filter->GetFeatureStandardDeviations(); std::ostringstream ss; ss << config.range; std::string strRange = ss.str(); for (std::size_t i = 0; i < featureMeans->size(); ++i) { switch (i) { case TextureFilterType::Energy : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Energy Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Energy Std.",featureStd->ElementAt(i))); break; case TextureFilterType::Entropy : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Entropy Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Entropy Std.",featureStd->ElementAt(i))); break; case TextureFilterType::Correlation : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Correlation Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Correlation Std.",featureStd->ElementAt(i))); break; case TextureFilterType::InverseDifferenceMoment : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") InverseDifferenceMoment Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") InverseDifferenceMoment Std.",featureStd->ElementAt(i))); break; case TextureFilterType::Inertia : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Inertia Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Inertia Std.",featureStd->ElementAt(i))); break; case TextureFilterType::ClusterShade : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") ClusterShade Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") ClusterShade Std.",featureStd->ElementAt(i))); break; case TextureFilterType::ClusterProminence : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") ClusterProminence Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") ClusterProminence Std.",featureStd->ElementAt(i))); break; case TextureFilterType::HaralickCorrelation : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") HaralickCorrelation Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") HaralickCorrelation Std.",featureStd->ElementAt(i))); break; case TextureFilterType::Autocorrelation : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Autocorrelation Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Autocorrelation Std.",featureStd->ElementAt(i))); break; case TextureFilterType::Contrast : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Contrast Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Contrast Std.",featureStd->ElementAt(i))); break; case TextureFilterType::Dissimilarity : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Dissimilarity Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Dissimilarity Std.",featureStd->ElementAt(i))); break; case TextureFilterType::MaximumProbability : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") MaximumProbability Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") MaximumProbability Std.",featureStd->ElementAt(i))); break; case TextureFilterType::InverseVariance : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") InverseVariance Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") InverseVariance Std.",featureStd->ElementAt(i))); break; case TextureFilterType::Homogeneity1 : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Homogeneity1 Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Homogeneity1 Std.",featureStd->ElementAt(i))); break; case TextureFilterType::ClusterTendency : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") ClusterTendency Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") ClusterTendency Std.",featureStd->ElementAt(i))); break; case TextureFilterType::Variance : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Variance Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") Variance Std.",featureStd->ElementAt(i))); break; case TextureFilterType::SumAverage : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") SumAverage Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") SumAverage Std.",featureStd->ElementAt(i))); break; case TextureFilterType::SumEntropy : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") SumEntropy Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") SumEntropy Std.",featureStd->ElementAt(i))); break; case TextureFilterType::SumVariance : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") SumVariance Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") SumVariance Std.",featureStd->ElementAt(i))); break; case TextureFilterType::DifferenceAverage : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") DifferenceAverage Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") DifferenceAverage Std.",featureStd->ElementAt(i))); break; case TextureFilterType::DifferenceEntropy : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") DifferenceEntropy Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") DifferenceEntropy Std.",featureStd->ElementAt(i))); break; case TextureFilterType::DifferenceVariance : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") DifferenceVariance Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") DifferenceVariance Std.",featureStd->ElementAt(i))); break; case TextureFilterType::InverseDifferenceMomentNormalized : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") InverseDifferenceMomentNormalized Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") InverseDifferenceMomentNormalized Std.",featureStd->ElementAt(i))); break; case TextureFilterType::InverseDifferenceNormalized : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") InverseDifferenceNormalized Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") InverseDifferenceNormalized Std.",featureStd->ElementAt(i))); break; case TextureFilterType::InverseDifference : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") InverseDifference Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") InverseDifference Std.",featureStd->ElementAt(i))); break; case TextureFilterType::JointAverage : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") JointAverage Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") JointAverage Std.",featureStd->ElementAt(i))); break; case TextureFilterType::FirstMeasureOfInformationCorrelation : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") FirstMeasureOfInformationCorrelation Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") FirstMeasureOfInformationCorrelation Std.",featureStd->ElementAt(i))); break; case TextureFilterType::SecondMeasureOfInformationCorrelation : featureList.push_back(std::make_pair("co-occ. ("+ strRange+") SecondMeasureOfInformationCorrelation Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("co-occ. ("+ strRange+") SecondMeasureOfInformationCorrelation Std.",featureStd->ElementAt(i))); break; default: break; } } } mitk::GIFCooccurenceMatrix::GIFCooccurenceMatrix(): m_Range(1.0) { - SetShortName("cooc"); - SetLongName("cooccurence"); + SetShortName("deprecated-cooc"); + SetLongName("deprecated-cooccurence"); } mitk::GIFCooccurenceMatrix::FeatureListType mitk::GIFCooccurenceMatrix::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; GIFCooccurenceMatrixConfiguration config; config.direction = GetDirection(); config.range = m_Range; config.MinimumIntensity = GetMinimumIntensity(); config.MaximumIntensity = GetMaximumIntensity(); config.UseMinimumIntensity = GetUseMinimumIntensity(); config.UseMaximumIntensity = GetUseMaximumIntensity(); config.Bins = GetBins(); AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList,config); return featureList; } mitk::GIFCooccurenceMatrix::FeatureNameListType mitk::GIFCooccurenceMatrix::GetFeatureNames() { FeatureNameListType featureList; featureList.push_back("co-occ. Energy Means"); featureList.push_back("co-occ. Energy Std."); featureList.push_back("co-occ. Entropy Means"); featureList.push_back("co-occ. Entropy Std."); featureList.push_back("co-occ. Correlation Means"); featureList.push_back("co-occ. Correlation Std."); featureList.push_back("co-occ. InverseDifferenceMoment Means"); featureList.push_back("co-occ. InverseDifferenceMoment Std."); featureList.push_back("co-occ. Inertia Means"); featureList.push_back("co-occ. Inertia Std."); featureList.push_back("co-occ. ClusterShade Means"); featureList.push_back("co-occ. ClusterShade Std."); featureList.push_back("co-occ. ClusterProminence Means"); featureList.push_back("co-occ. ClusterProminence Std."); featureList.push_back("co-occ. HaralickCorrelation Means"); featureList.push_back("co-occ. HaralickCorrelation Std."); featureList.push_back("co-occ. Autocorrelation Means"); featureList.push_back("co-occ. Autocorrelation Std."); featureList.push_back("co-occ. Contrast Means"); featureList.push_back("co-occ. Contrast Std."); featureList.push_back("co-occ. Dissimilarity Means"); featureList.push_back("co-occ. Dissimilarity Std."); featureList.push_back("co-occ. MaximumProbability Means"); featureList.push_back("co-occ. MaximumProbability Std."); featureList.push_back("co-occ. InverseVariance Means"); featureList.push_back("co-occ. InverseVariance Std."); featureList.push_back("co-occ. Homogeneity1 Means"); featureList.push_back("co-occ. Homogeneity1 Std."); featureList.push_back("co-occ. ClusterTendency Means"); featureList.push_back("co-occ. ClusterTendency Std."); featureList.push_back("co-occ. Variance Means"); featureList.push_back("co-occ. Variance Std."); featureList.push_back("co-occ. SumAverage Means"); featureList.push_back("co-occ. SumAverage Std."); featureList.push_back("co-occ. SumEntropy Means"); featureList.push_back("co-occ. SumEntropy Std."); featureList.push_back("co-occ. SumVariance Means"); featureList.push_back("co-occ. SumVariance Std."); featureList.push_back("co-occ. DifferenceAverage Means"); featureList.push_back("co-occ. DifferenceAverage Std."); featureList.push_back("co-occ. DifferenceEntropy Means"); featureList.push_back("co-occ. DifferenceEntropy Std."); featureList.push_back("co-occ. DifferenceVariance Means"); featureList.push_back("co-occ. DifferenceVariance Std."); featureList.push_back("co-occ. InverseDifferenceMomentNormalized Means"); featureList.push_back("co-occ. InverseDifferenceMomentNormalized Std."); featureList.push_back("co-occ. InverseDifferenceNormalized Means"); featureList.push_back("co-occ. InverseDifferenceNormalized Std."); featureList.push_back("co-occ. InverseDifference Means"); featureList.push_back("co-occ. InverseDifference Std."); featureList.push_back("co-occ. JointAverage Means"); featureList.push_back("co-occ. JointAverage Std."); featureList.push_back("co-occ. FirstMeasurementOfInformationCorrelation Means"); featureList.push_back("co-occ. FirstMeasurementOfInformationCorrelation Std."); featureList.push_back("co-occ. SecondMeasurementOfInformationCorrelation Means"); featureList.push_back("co-occ. SecondMeasurementOfInformationCorrelation Std."); return featureList; } void mitk::GIFCooccurenceMatrix::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); - parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Co-occurence matrix", "calculates Co-occurence based features", us::Any()); + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Co-occurence matrix", "calculates Co-occurence based features", us::Any()); parser.addArgument(name + "::range", name + "::range", mitkCommandLineParser::String, "Cooc 2 Range", "Define the range that is used (Semicolon-separated)", us::Any()); } void mitk::GIFCooccurenceMatrix::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())) { 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] << "...."; mitk::GIFCooccurenceMatrix::Pointer coocCalculator = mitk::GIFCooccurenceMatrix::New(); coocCalculator->SetRange(ranges[i]); auto localResults = coocCalculator->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating coocurence with range " << ranges[i] << "...."; } } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp index 1b2bfbab89..0652ded536 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp @@ -1,624 +1,591 @@ #include // MITK #include #include #include // ITK #include -#include #include #include // STL #include #include 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::Image* mask, itk::Offset offset, int range, mitk::CoocurenceMatrixHolder &holder) { typedef itk::Image ImageType; - typedef itk::Image MaskImageType; + 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 ImageType; - typedef itk::Image MaskType; - typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; + typedef itk::Image MaskType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// - - typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); - minMaxComputer->SetImage(itkImage); - minMaxComputer->Compute(); - - double rangeMin = -0.5 + minMaxComputer->GetMinimum(); - double rangeMax = 0.5 + minMaxComputer->GetMaximum(); - - if (config.UseMinimumIntensity) - rangeMin = config.MinimumIntensity; - if (config.UseMaximumIntensity) - rangeMax = config.MaximumIntensity; - - // Define Range + double rangeMin = config.MinimumIntensity; + double rangeMax = config.MaximumIntensity; int numberOfBins = config.Bins; - if (config.BinSize > 0) - { - numberOfBins = std::ceil((rangeMax - rangeMin) / config.BinSize); - rangeMax = rangeMin + config.BinSize * numberOfBins; - } - - MITK_INFO << "Bins: " << numberOfBins << " , Min, Max: " << rangeMin << " -> " << rangeMax; 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, "co-occ. 2 (" + strRange + ") overall", featureList); - MatrixFeaturesTo(featureMean, "co-occ. 2 (" + strRange + ") mean", featureList); - MatrixFeaturesTo(featureStd, "co-occ. 2 (" + strRange + ") std.dev.", featureList); + MatrixFeaturesTo(overallFeature, "Co-occurenced Based Features (" + strRange + ")::Overall", featureList); + MatrixFeaturesTo(featureMean, "Co-occurenced Based Features (" + strRange + ")::Mean", featureList); + MatrixFeaturesTo(featureStd, "Co-occurenced Based Features (" + strRange + ")::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 + " 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)); 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 + " Autocorrleation", 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)); } static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature) { #define ADDFEATURE(a) 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), m_Bins(128), m_Binsize(-1) +m_Range(1.0) { SetShortName("cooc2"); SetLongName("cooccurence2"); } 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 = GetMinimumIntensity(); - config.MaximumIntensity = GetMaximumIntensity(); - config.UseMinimumIntensity = GetUseMinimumIntensity(); - config.UseMaximumIntensity = GetUseMaximumIntensity(); - config.Bins = GetBins(); - config.BinSize = GetBinsize(); + config.MinimumIntensity = GetQuantifier()->GetMinimum(); + config.MaximumIntensity = GetQuantifier()->GetMaximum(); + config.Bins = GetQuantifier()->GetBins(); 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::String, "Use Co-occurence matrix", "calculates Co-occurence based features (new implementation)", us::Any()); + 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()); - parser.addArgument(name + "::bins", name + "::bins", mitkCommandLineParser::String, "Cooc 2 Number of Bins", "Define the number of bins that is used ", us::Any()); - parser.addArgument(name + "::binsize", name + "::binsize", mitkCommandLineParser::String, "Cooc 2 Number of Bins", "Define the number of bins that is used ", 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); } - if (parsedArgs.count(name + "::bins")) - { - auto bins = SplitDouble(parsedArgs[name + "::bins"].ToString(), ';')[0]; - this->SetBins(bins); - } - if (parsedArgs.count(name + "::binsize")) - { - auto binsize = SplitDouble(parsedArgs[name + "::binsize"].ToString(), ';')[0]; - this->SetBinsize(binsize); - } 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] << "...."; } } - } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCurvatureStatistic.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCurvatureStatistic.cpp index 23227d90e4..5aad939dc2 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCurvatureStatistic.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCurvatureStatistic.cpp @@ -1,202 +1,182 @@ /*=================================================================== 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 // STL #include #include -// OpenCV -#include - static void calculateLocalStatistic(vtkDataArray* scalars, std::string name, mitk::GIFCurvatureStatistic::FeatureListType & featureList) { int size = scalars->GetNumberOfTuples(); double minimum = std::numeric_limits::max(); double maximum = std::numeric_limits::lowest(); double mean1 = 0; double mean2 = 0; double mean3 = 0; double mean4 = 0; double mean1p = 0; double mean2p = 0; double mean3p = 0; double mean4p = 0; double mean1n = 0; double mean2n = 0; double mean3n = 0; double mean4n = 0; int countPositive = 0; int countNegative = 0; for (int i = 0; i < size; ++i) { double actualValue = scalars->GetComponent(i, 0); minimum = std::min(minimum, scalars->GetComponent(i, 0)); maximum = std::max(maximum, scalars->GetComponent(i, 0)); mean1 += actualValue; mean2 += actualValue*actualValue; mean3 += actualValue*actualValue*actualValue; mean4 += actualValue*actualValue*actualValue*actualValue; if (actualValue > 0) { mean1p += actualValue; mean2p += actualValue*actualValue; mean3p += actualValue*actualValue*actualValue; mean4p += actualValue*actualValue*actualValue*actualValue; countPositive++; } if (actualValue < 0) { mean1n += actualValue; mean2n += actualValue*actualValue; mean3n += actualValue*actualValue*actualValue; mean4n += actualValue*actualValue*actualValue*actualValue; countNegative++; } } double mean = mean1 / size; double stddev = std::sqrt(mean2 / size - mean*mean); double skewness = ((mean3 / size) - 3 * mean*stddev*stddev - mean*mean*mean) / (stddev*stddev*stddev); double meanP = mean1p / countPositive; double stddevP = std::sqrt(mean2p / countPositive - meanP*meanP); double skewnessP = ((mean3p / countPositive) - 3 * meanP*stddevP*stddevP - meanP*meanP*meanP) / (stddevP*stddevP*stddevP); double meanN = mean1n / countNegative; double stddevN = std::sqrt(mean2n / countNegative - meanN*meanN); double skewnessN = ((mean3n / countNegative) - 3 * meanN*stddevN*stddevN - meanN*meanN*meanN) / (stddevN*stddevN*stddevN); featureList.push_back(std::make_pair("Curvature Feature Minimum " + name + " Curvature", minimum)); featureList.push_back(std::make_pair("Curvature Feature Maximum " + name + " Curvature", maximum)); featureList.push_back(std::make_pair("Curvature Feature Mean " + name + " Curvature", mean)); featureList.push_back(std::make_pair("Curvature Feature Standard Deviation " + name + " Curvature", stddev)); featureList.push_back(std::make_pair("Curvature Feature Skewness " + name + " Curvature", skewness)); featureList.push_back(std::make_pair("Curvature Feature Mean Positive " + name + " Curvature", meanP)); featureList.push_back(std::make_pair("Curvature Feature Standard Deviation Positive " + name + " Curvature", stddevP)); featureList.push_back(std::make_pair("Curvature Feature Skewness Positive " + name + " Curvature", skewnessP)); featureList.push_back(std::make_pair("Curvature Feature Mean Negative " + name + " Curvature", meanN)); featureList.push_back(std::make_pair("Curvature Feature Standard Deviation Negative " + name + " Curvature", stddevN)); featureList.push_back(std::make_pair("Curvature Feature Skewness Negative " + name + " Curvature", skewnessN)); } mitk::GIFCurvatureStatistic::GIFCurvatureStatistic() { SetLongName("curvature"); SetShortName("cur"); } mitk::GIFCurvatureStatistic::FeatureListType mitk::GIFCurvatureStatistic::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; if (image->GetDimension() < 3) { return featureList; } - //AccessByItk_2(image, CalculateVolumeStatistic, mask, featureList); - //AccessByItk_2(mask, CalculateLargestDiameter, image, featureList); vtkSmartPointer mesher = vtkSmartPointer::New(); vtkSmartPointer curvator = vtkSmartPointer::New(); -// vtkSmartPointer stats = vtkSmartPointer::New(); mesher->SetInputData(mask->GetVtkImageData()); mesher->SetValue(0, 0.5); curvator->SetInputConnection(mesher->GetOutputPort()); curvator->SetCurvatureTypeToMean(); curvator->Update(); vtkDataArray* scalars = curvator->GetOutput()->GetPointData()->GetScalars(); calculateLocalStatistic(scalars, "Mean", featureList); curvator->SetCurvatureTypeToGaussian(); curvator->Update(); scalars = curvator->GetOutput()->GetPointData()->GetScalars(); calculateLocalStatistic(scalars, "Gaussian", featureList); curvator->SetCurvatureTypeToMinimum(); curvator->Update(); scalars = curvator->GetOutput()->GetPointData()->GetScalars(); calculateLocalStatistic(scalars, "Minimum", featureList); curvator->SetCurvatureTypeToMaximum(); curvator->Update(); scalars = curvator->GetOutput()->GetPointData()->GetScalars(); calculateLocalStatistic(scalars, "Maximum", featureList); - - - - - //double meshVolume = stats->GetVolume(); - //double meshSurf = stats->GetSurfaceArea(); - //double pixelVolume = featureList[0].second; - //double pixelSurface = featureList[3].second; - //MITK_INFO << "Surf: " << pixelSurface << " Vol " << pixelVolume; - - //featureList.push_back(std::make_pair("Volumetric Features Volume (mesh based)",meshVolume)); - //featureList.push_back(std::make_pair("Volumetric Features Surface area",meshSurf)); - - return featureList; } mitk::GIFCurvatureStatistic::FeatureNameListType mitk::GIFCurvatureStatistic::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFCurvatureStatistic::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Curvature of Surface as feature", "calculates shape curvature based features", us::Any()); } void mitk::GIFCurvatureStatistic::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/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp index c6cce01cbd..526772545c 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp @@ -1,373 +1,332 @@ /*=================================================================== 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 #include #include #define GET_VARIABLE_INDEX(value) \ mv[0] = value; \ histogram->GetIndex(mv, resultingIndex); template void CalculateFirstOrderHistogramStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFFirstOrderHistogramStatistics::FeatureListType & featureList, mitk::GIFFirstOrderHistogramStatistics::ParameterStruct params) { typedef itk::Image ImageType; - typedef itk::Image MaskType; + typedef itk::Image MaskType; typedef itk::LabelStatisticsImageFilter FilterType; typedef typename FilterType::HistogramType HistogramType; typedef typename HistogramType::IndexType HIndexType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); - typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); - minMaxComputer->SetImage(itkImage); - minMaxComputer->Compute(); - - itk::ImageRegionConstIteratorWithIndex imageIter(itkImage, itkImage->GetLargestPossibleRegion()); - itk::ImageRegionConstIteratorWithIndex maskIter(maskImage, maskImage->GetLargestPossibleRegion()); - - TPixel minimum = std::numeric_limits::max(); - TPixel maximum = std::numeric_limits::min(); - - while (!imageIter.IsAtEnd()) - { - if (maskIter.Get() > 0) - { - minimum = (imageIter.Get() < minimum) ? imageIter.Get() : minimum; - maximum = (imageIter.Get() > maximum) ? imageIter.Get() : maximum; - } - ++imageIter; -++maskIter; - } - typename FilterType::Pointer labelStatisticsImageFilter = FilterType::New(); labelStatisticsImageFilter->SetInput(itkImage); labelStatisticsImageFilter->SetLabelInput(maskImage); labelStatisticsImageFilter->SetUseHistograms(true); - if (params.BinSize < 0) - { - labelStatisticsImageFilter->SetHistogramParameters(params.Bins, minimum, maximum); - } - else - { - int tmpBins = std::ceil((maximum - minimum) / params.BinSize); - double tmpMax = minimum + tmpBins * params.BinSize; - labelStatisticsImageFilter->SetHistogramParameters(tmpBins, minimum, tmpMax); - } - labelStatisticsImageFilter->Update(); + labelStatisticsImageFilter->SetHistogramParameters(params.Bins, params.MinimumIntensity, params.MaximumIntensity); + labelStatisticsImageFilter->Update(); HistogramType::MeasurementVectorType mv(1); mv[0] = 4.1; HistogramType::IndexType resultingIndex; - auto histogram = labelStatisticsImageFilter->GetHistogram(1); double meanValue = 0; // labelStatisticsImageFilter->GetMean(1); GET_VARIABLE_INDEX(meanValue); double meanIndex = 0; // resultingIndex[0]; - //double varianceValue = labelStatisticsImageFilter->GetVariance(1); - //GET_VARIABLE_INDEX(varianceValue); - //auto varianceIndex = resultingIndex[0]; double medianValue = labelStatisticsImageFilter->GetMedian(1); GET_VARIABLE_INDEX(medianValue); double medianIndex = resultingIndex[0]; double minimumValue = labelStatisticsImageFilter->GetMinimum(1); GET_VARIABLE_INDEX(minimumValue); double minimumIndex = resultingIndex[0]; double p10Value = histogram->Quantile(0, 0.10); GET_VARIABLE_INDEX(p10Value); double p10Index = resultingIndex[0]; double p25Value = histogram->Quantile(0, 0.25); GET_VARIABLE_INDEX(p25Value); double p25Index = resultingIndex[0]; double p75Value = histogram->Quantile(0, 0.75); GET_VARIABLE_INDEX(p75Value); double p75Index = resultingIndex[0]; double p90Value = histogram->Quantile(0, 0.90); GET_VARIABLE_INDEX(p90Value); double p90Index = resultingIndex[0]; double maximumValue = labelStatisticsImageFilter->GetMaximum(1); GET_VARIABLE_INDEX(maximumValue); double maximumIndex = resultingIndex[0]; double Log2 = log(2); HIndexType index; HIndexType index2; index.SetSize(1); index2.SetSize(1); double binWidth = histogram->GetBinMax(0, 0) - histogram->GetBinMin(0, 0); double count = labelStatisticsImageFilter->GetCount(1); double robustMeanValue = 0; double robustMeanIndex = 0; double robustCount = 0; for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; double frequence = histogram->GetFrequency(index); double probability = frequence / count; double voxelValue = histogram->GetBinMin(0, i) + binWidth * 0.5; meanValue += probability * voxelValue; meanIndex += probability * (i); if ((i >= p10Index) && (i <= p90Index)) { robustMeanValue += frequence * voxelValue; robustMeanIndex += frequence * i; robustCount += frequence; } } robustMeanValue /= robustCount; robustMeanIndex /= robustCount; double varianceValue = 0; double varianceIndex = 0; double skewnessValue = 0; double skewnessIndex = 0; double kurtosisValue = 0; double kurtosisIndex = 0; double modeValue = 0; double modeIndex = 0; double modeFrequence = 0; double meanAbsoluteDeviationValue = 0; double meanAbsoluteDeviationIndex = 0; double robustMeanAbsoluteDeviationValue = 0; double robustMeanAbsoluteDeivationIndex = 0; double medianAbsoluteDeviationValue = 0; double medianAbsoluteDeviationIndex = 0; double coefficientOfVariationValue = 0; double coefficientOfVariationIndex = 0; double quantileCoefficientOfDispersionValue = 0; double quantileCoefficientOfDispersionIndex = 0; double entropyValue = 0; double entropyIndex = 0; double uniformityValue = 0; double uniformityIndex = 0; double maximumGradientValue = std::numeric_limits::min(); double maximumGradientIndex = 0; double minimumGradientValue = std::numeric_limits::max(); double minimumGradientIndex = 0; double gradient = 0; for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; double frequence = histogram->GetFrequency(index); double probability = frequence / count; double voxelValue = histogram->GetBinMin(0, i) + binWidth * 0.5; double deltaValue = (voxelValue - meanValue); double deltaIndex = (i - meanIndex); varianceValue += probability * deltaValue * deltaValue; varianceIndex += probability * deltaIndex * deltaIndex; skewnessValue += probability * deltaValue * deltaValue * deltaValue; skewnessIndex += probability * deltaIndex * deltaIndex * deltaIndex; kurtosisValue += probability * deltaValue * deltaValue * deltaValue * deltaValue; kurtosisIndex += probability * deltaIndex * deltaIndex * deltaIndex * deltaIndex; if (modeFrequence < frequence) { modeFrequence = frequence; modeValue = voxelValue; modeIndex = i; } meanAbsoluteDeviationValue += probability * std::abs(deltaValue); meanAbsoluteDeviationIndex += probability * std::abs(deltaIndex); if ((i >= p10Index) && (i <= p90Index)) { robustMeanAbsoluteDeviationValue += frequence * std::abs(voxelValue - robustMeanValue); robustMeanAbsoluteDeivationIndex += frequence * std::abs(i*1.0 - robustMeanIndex*1.0); } medianAbsoluteDeviationValue += probability * std::abs(voxelValue - medianValue); medianAbsoluteDeviationIndex += probability * std::abs(i*1.0 - medianIndex); if (probability > 0.0000001) { entropyValue -= probability * std::log(probability) / Log2; entropyIndex = entropyValue; } uniformityValue += probability*probability; uniformityIndex = uniformityValue; if (i == 0) { index[0] = 1; index2[0] = 0; gradient = histogram->GetFrequency(index)*1.0 - histogram->GetFrequency(index2)*1.0; } else if (i == (int)(histogram->GetSize(0)) - 1) { index[0] = i; index2[0] = i - 1; gradient = histogram->GetFrequency(index)*1.0 - histogram->GetFrequency(index2)*1.0; } else { index[0] = i+1; index2[0] = i - 1; gradient = (histogram->GetFrequency(index)*1.0 - histogram->GetFrequency(index2)*1.0) / 2.0; } if (gradient > maximumGradientValue) { maximumGradientValue = gradient; maximumGradientIndex = i + 1; } if (gradient < minimumGradientValue) { minimumGradientValue = gradient; minimumGradientIndex = i + 1; } } skewnessValue = skewnessValue / (varianceValue * std::sqrt(varianceValue)); skewnessIndex = skewnessIndex / (varianceIndex * std::sqrt(varianceIndex)); kurtosisValue = kurtosisValue / (varianceValue * varianceValue) - 3; // Excess Kurtosis kurtosisIndex = kurtosisIndex / (varianceIndex * varianceIndex) - 3; // Excess Kurtosis coefficientOfVariationValue = std::sqrt(varianceValue) / meanValue; coefficientOfVariationIndex = std::sqrt(varianceIndex) / (meanIndex+1); quantileCoefficientOfDispersionValue = (p75Value - p25Value) / (p75Value + p25Value); quantileCoefficientOfDispersionIndex = (p75Index - p25Index) / (p75Index + p25Index); robustMeanAbsoluteDeviationValue /= robustCount; robustMeanAbsoluteDeivationIndex /= robustCount; - featureList.push_back(std::make_pair("FirstOrderHistogram Mean Value", meanValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Variance Value", varianceValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Skewness Value", skewnessValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Kurtosis Value", kurtosisValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Median Value", medianValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Minimum Value", minimumValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Percentile 10 Value", p10Value)); - featureList.push_back(std::make_pair("FirstOrderHistogram Percentile 90 Value", p90Value)); - featureList.push_back(std::make_pair("FirstOrderHistogram Maximum Value", maximumValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Mode Value", modeValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Interquantile Range Value", p75Value - p25Value)); - featureList.push_back(std::make_pair("FirstOrderHistogram Range Value", maximumValue - minimumValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Mean Absolute Deviation Value", meanAbsoluteDeviationValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Robust Mean Absolute Deviation Value", robustMeanAbsoluteDeviationValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Median Absolute Deviation Value", medianAbsoluteDeviationValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Coefficient of Variation Value", coefficientOfVariationValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Quantile coefficient of Dispersion Value", quantileCoefficientOfDispersionValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Entropy Value", entropyValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Uniformity Value", uniformityValue)); - - featureList.push_back(std::make_pair("FirstOrderHistogram Mean Index", meanIndex + 1 )); - featureList.push_back(std::make_pair("FirstOrderHistogram Variance Index", varianceIndex)); - featureList.push_back(std::make_pair("FirstOrderHistogram Skewness Index", skewnessIndex)); - featureList.push_back(std::make_pair("FirstOrderHistogram Kurtosis Index", kurtosisIndex)); - featureList.push_back(std::make_pair("FirstOrderHistogram Median Index", medianIndex + 1)); - featureList.push_back(std::make_pair("FirstOrderHistogram Minimum Index", minimumIndex + 1)); - featureList.push_back(std::make_pair("FirstOrderHistogram Percentile 10 Index", p10Index + 1)); - featureList.push_back(std::make_pair("FirstOrderHistogram Percentile 90 Index", p90Index + 1)); - featureList.push_back(std::make_pair("FirstOrderHistogram Maximum Index", maximumIndex + 1)); - featureList.push_back(std::make_pair("FirstOrderHistogram Mode Index", modeIndex + 1)); - featureList.push_back(std::make_pair("FirstOrderHistogram Interquantile Range Index", p75Index - p25Index)); - featureList.push_back(std::make_pair("FirstOrderHistogram Range Index", maximumIndex - minimumIndex)); - featureList.push_back(std::make_pair("FirstOrderHistogram Mean Absolute Deviation Index", meanAbsoluteDeviationIndex)); - featureList.push_back(std::make_pair("FirstOrderHistogram Robust Mean Absolute Deviation Index", robustMeanAbsoluteDeivationIndex)); - featureList.push_back(std::make_pair("FirstOrderHistogram Median Absolute Deviation Index", medianAbsoluteDeviationIndex)); - featureList.push_back(std::make_pair("FirstOrderHistogram Coefficient of Variation Index", coefficientOfVariationIndex)); - featureList.push_back(std::make_pair("FirstOrderHistogram Quantile coefficient of Dispersion Index", quantileCoefficientOfDispersionIndex)); - featureList.push_back(std::make_pair("FirstOrderHistogram Entropy Index", entropyIndex)); - featureList.push_back(std::make_pair("FirstOrderHistogram Uniformity Index", uniformityIndex)); - featureList.push_back(std::make_pair("FirstOrderHistogram Maximum Gradient", maximumGradientValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Maximum Gradient Index", maximumGradientIndex)); - featureList.push_back(std::make_pair("FirstOrderHistogram Minimum Gradient", minimumGradientValue)); - featureList.push_back(std::make_pair("FirstOrderHistogram Minimum Gradient Index", minimumGradientIndex)); - - featureList.push_back(std::make_pair("FirstOrderHistogram Number of Bins", histogram->GetSize(0))); - featureList.push_back(std::make_pair("FirstOrderHistogram Bin Size", binWidth)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Mean Value", meanValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Variance Value", varianceValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Skewness Value", skewnessValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Excess Kurtosis Value", kurtosisValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Median Value", medianValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Minimum Value", minimumValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Percentile 10 Value", p10Value)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Percentile 90 Value", p90Value)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Maximum Value", maximumValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Mode Value", modeValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Interquantile Range Value", p75Value - p25Value)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Range Value", maximumValue - minimumValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Mean Absolute Deviation Value", meanAbsoluteDeviationValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Robust Mean Absolute Deviation Value", robustMeanAbsoluteDeviationValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Median Absolute Deviation Value", medianAbsoluteDeviationValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Coefficient of Variation Value", coefficientOfVariationValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Quantile coefficient of Dispersion Value", quantileCoefficientOfDispersionValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Entropy Value", entropyValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Uniformity Value", uniformityValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Robust Mean Value", robustMeanValue)); + + featureList.push_back(std::make_pair("FirstOrderHistogram::Mean Index", meanIndex + 1 )); + featureList.push_back(std::make_pair("FirstOrderHistogram::Variance Index", varianceIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Skewness Index", skewnessIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Excess Kurtosis Index", kurtosisIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Median Index", medianIndex + 1)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Minimum Index", minimumIndex + 1)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Percentile 10 Index", p10Index + 1)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Percentile 90 Index", p90Index + 1)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Maximum Index", maximumIndex + 1)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Mode Index", modeIndex + 1)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Interquantile Range Index", p75Index - p25Index)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Range Index", maximumIndex - minimumIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Mean Absolute Deviation Index", meanAbsoluteDeviationIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Robust Mean Absolute Deviation Index", robustMeanAbsoluteDeivationIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Median Absolute Deviation Index", medianAbsoluteDeviationIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Coefficient of Variation Index", coefficientOfVariationIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Quantile coefficient of Dispersion Index", quantileCoefficientOfDispersionIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Entropy Index", entropyIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Uniformity Index", uniformityIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Maximum Gradient", maximumGradientValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Maximum Gradient Index", maximumGradientIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Minimum Gradient", minimumGradientValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Minimum Gradient Index", minimumGradientIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram::Robust Mean Index", robustMeanIndex)); + + featureList.push_back(std::make_pair("FirstOrderHistogram::Number of Bins", histogram->GetSize(0))); + featureList.push_back(std::make_pair("FirstOrderHistogram::Bin Size", binWidth)); } mitk::GIFFirstOrderHistogramStatistics::GIFFirstOrderHistogramStatistics() : m_HistogramSize(256), m_UseCtRange(false), m_BinSize(-1) { SetShortName("foh"); SetLongName("first-order-histogram"); } mitk::GIFFirstOrderHistogramStatistics::FeatureListType mitk::GIFFirstOrderHistogramStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { + InitializeQuantifier(image, mask); FeatureListType featureList; ParameterStruct params; - params.m_HistogramSize = this->m_HistogramSize; - params.m_UseCtRange = this->m_UseCtRange; - - params.MinimumIntensity = GetMinimumIntensity(); - params.MaximumIntensity = GetMaximumIntensity(); - params.UseMinimumIntensity = GetUseMinimumIntensity(); - params.UseMaximumIntensity = GetUseMaximumIntensity(); - params.Bins = GetBins(); - params.BinSize = GetBinSize(); + params.MinimumIntensity = GetQuantifier()->GetMinimum(); + params.MaximumIntensity = GetQuantifier()->GetMaximum(); + params.Bins = GetQuantifier()->GetBins(); AccessByItk_3(image, CalculateFirstOrderHistogramStatistics, mask, featureList, params); return featureList; } mitk::GIFFirstOrderHistogramStatistics::FeatureNameListType mitk::GIFFirstOrderHistogramStatistics::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFFirstOrderHistogramStatistics::AddArguments(mitkCommandLineParser &parser) { + AddQuantifierArguments(parser); std::string name = GetOptionPrefix(); - parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Volume-Statistic", "calculates volume based features", us::Any()); - parser.addArgument(name + "::binsize", name + "::binsize", mitkCommandLineParser::Float, "RL Bins", "Define the number of bins that is used (Semicolon-separated)", us::Any()); - + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Histogram based First order features", "calculates first order features based on a histogram", us::Any()); } void -mitk::GIFFirstOrderHistogramStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +mitk::GIFFirstOrderHistogramStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { std::string name = GetOptionPrefix(); auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { - MITK_INFO << "Start calculating first order features ...."; - if (parsedArgs.count(name + "::binsize")) - { - auto binsize = SplitDouble(parsedArgs[name + "::binsize"].ToString(), ';')[0]; - SetBinSize(binsize); - } + InitializeQuantifierFromParameters(feature, mask); + + MITK_INFO << "Start calculating first order histogram features ...."; auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); - MITK_INFO << "Finished calculating first order features...."; + MITK_INFO << "Finished calculating first order histogram features...."; } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp index 5e7e4eec48..c171967bc9 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp @@ -1,339 +1,322 @@ /*=================================================================== 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 // STL #include template void CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFFirstOrderStatistics::FeatureListType & featureList, mitk::GIFFirstOrderStatistics::ParameterStruct params) { typedef itk::Image ImageType; - typedef itk::Image MaskType; + typedef itk::Image MaskType; typedef itk::LabelStatisticsImageFilter FilterType; typedef typename FilterType::HistogramType HistogramType; typedef typename HistogramType::IndexType HIndexType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); double voxelVolume = 1; - for (int i = 0; i < std::min(3, VImageDimension); ++i) + for (unsigned int i = 0; i < std::min(3, VImageDimension); ++i) voxelVolume *= itkImage->GetSpacing()[i]; double voxelSpace = 1; - for (int i = 0; i < int(VImageDimension); ++i) + for (unsigned int i = 0; i < VImageDimension; ++i) voxelSpace *= itkImage->GetSpacing()[i]; typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); minMaxComputer->SetImage(itkImage); minMaxComputer->Compute(); double imageRange = minMaxComputer->GetMaximum() - minMaxComputer->GetMinimum(); typename FilterType::Pointer labelStatisticsImageFilter = FilterType::New(); labelStatisticsImageFilter->SetInput( itkImage ); labelStatisticsImageFilter->SetLabelInput(maskImage); labelStatisticsImageFilter->SetUseHistograms(true); - if (params.m_UseCtRange) - { - labelStatisticsImageFilter->SetHistogramParameters(1024.5+3096.5, -1024.5,3096.5); - } else { - double min = minMaxComputer->GetMinimum() -0.5; - double max = minMaxComputer->GetMaximum() +0.5; - if (params.UseMinimumIntensity) - min = params.MinimumIntensity; - if (params.UseMaximumIntensity) - max = params.MaximumIntensity; + double min = params.MinimumIntensity; + double max = params.MaximumIntensity; - labelStatisticsImageFilter->SetHistogramParameters(params.Bins, min,max); - } + labelStatisticsImageFilter->SetHistogramParameters(params.Bins, min,max); labelStatisticsImageFilter->Update(); // --------------- Range -------------------- double range = labelStatisticsImageFilter->GetMaximum(1) - labelStatisticsImageFilter->GetMinimum(1); // --------------- Uniformity, Entropy -------------------- double count = labelStatisticsImageFilter->GetCount(1); //double std_dev = labelStatisticsImageFilter->GetSigma(1); double mean = labelStatisticsImageFilter->GetMean(1); double median = labelStatisticsImageFilter->GetMedian(1); auto histogram = labelStatisticsImageFilter->GetHistogram(1); bool histogramIsCalculated = histogram; HIndexType index; index.SetSize(1); - double uniformity = 0; double entropy = 0; double squared_sum = 0; double kurtosis = 0; double mean_absolut_deviation = 0; double median_absolut_deviation = 0; double skewness = 0; double sum_prob = 0; double binWidth = 0; double p05th = 0, p10th = 0, p15th = 0, p20th = 0, p25th = 0, p30th = 0, p35th = 0, p40th = 0, p45th = 0, p50th = 0; double p55th = 0, p60th = 0, p65th = 0, p70th = 0, p75th = 0, p80th = 0, p85th = 0, p90th = 0, p95th = 0; double voxelValue = 0; if (histogramIsCalculated) { binWidth = histogram->GetBinMax(0, 0) - histogram->GetBinMin(0, 0); p05th = histogram->Quantile(0, 0.05); p10th = histogram->Quantile(0, 0.10); p15th = histogram->Quantile(0, 0.15); p20th = histogram->Quantile(0, 0.20); p25th = histogram->Quantile(0, 0.25); p30th = histogram->Quantile(0, 0.30); p35th = histogram->Quantile(0, 0.35); p40th = histogram->Quantile(0, 0.40); p45th = histogram->Quantile(0, 0.45); p50th = histogram->Quantile(0, 0.50); p55th = histogram->Quantile(0, 0.55); p60th = histogram->Quantile(0, 0.60); p65th = histogram->Quantile(0, 0.65); p70th = histogram->Quantile(0, 0.70); p75th = histogram->Quantile(0, 0.75); p80th = histogram->Quantile(0, 0.80); p85th = histogram->Quantile(0, 0.85); p90th = histogram->Quantile(0, 0.90); p95th = histogram->Quantile(0, 0.95); } double Log2=log(2); double mode_bin; double mode_value = 0; double variance = 0; if (histogramIsCalculated) { for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; double prob = histogram->GetFrequency(index); if (prob < 0.00000001) continue; voxelValue = histogram->GetBinMin(0, i) + binWidth * 0.5; if (prob > mode_value) { mode_value = prob; mode_bin = voxelValue; } sum_prob += prob; squared_sum += prob * voxelValue*voxelValue; prob /= count; mean_absolut_deviation += prob* std::abs(voxelValue - mean); median_absolut_deviation += prob* std::abs(voxelValue - median); variance += prob * (voxelValue - mean) * (voxelValue - mean); kurtosis += prob* (voxelValue - mean) * (voxelValue - mean) * (voxelValue - mean) * (voxelValue - mean); skewness += prob* (voxelValue - mean) * (voxelValue - mean) * (voxelValue - mean); uniformity += prob*prob; if (prob > 0) { entropy += prob * std::log(prob) / Log2; } } } entropy = -entropy; double uncorrected_std_dev = std::sqrt(variance); double rms = std::sqrt(squared_sum / count); kurtosis = kurtosis / (variance * variance); skewness = skewness / (variance * uncorrected_std_dev); double coveredGrayValueRange = range / imageRange; double coefficient_of_variation = (mean == 0) ? 0 : std::sqrt(variance) / mean; double quantile_coefficient_of_dispersion = (p75th - p25th) / (p75th + p25th); //Calculate the robust mean absolute deviation //First, set all frequencies to 0 that are <10th or >90th percentile double meanRobust = 0.0; double robustMeanAbsoluteDeviation = 0.0; if (histogramIsCalculated) { for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; if (histogram->GetBinMax(0, i) < p10th) { histogram->SetFrequencyOfIndex(index, 0); } else if (histogram->GetBinMin(0, i) > p90th) { histogram->SetFrequencyOfIndex(index, 0); } } //Calculate the mean for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; meanRobust += histogram->GetFrequency(index) * 0.5 * (histogram->GetBinMin(0, i) + histogram->GetBinMax(0, i)); } meanRobust = meanRobust / histogram->GetTotalFrequency(); for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; robustMeanAbsoluteDeviation += std::abs(histogram->GetFrequency(index) * ((0.5 * (histogram->GetBinMin(0, i) + histogram->GetBinMax(0, i))) - meanRobust )); } robustMeanAbsoluteDeviation = robustMeanAbsoluteDeviation / histogram->GetTotalFrequency(); } - featureList.push_back(std::make_pair("FirstOrder Mean", labelStatisticsImageFilter->GetMean(1))); - featureList.push_back(std::make_pair("FirstOrder Unbiased Variance", labelStatisticsImageFilter->GetVariance(1))); //Siehe Definition von Unbiased Variance estimation. (Wird nicht durch n sondern durch n-1 normalisiert) - featureList.push_back(std::make_pair("FirstOrder Biased Variance", variance)); - featureList.push_back(std::make_pair("FirstOrder Skewness", skewness)); - featureList.push_back(std::make_pair("FirstOrder Kurtosis", kurtosis)); - featureList.push_back(std::make_pair("FirstOrder Median", labelStatisticsImageFilter->GetMedian(1))); - featureList.push_back(std::make_pair("FirstOrder Minimum", labelStatisticsImageFilter->GetMinimum(1))); - featureList.push_back(std::make_pair("FirstOrder Maximum", labelStatisticsImageFilter->GetMaximum(1))); - featureList.push_back(std::make_pair("FirstOrder Range", range)); - featureList.push_back(std::make_pair("FirstOrder Mean absolute deviation", mean_absolut_deviation)); - featureList.push_back(std::make_pair("FirstOrder Robust Mean Absolute Deviation", robustMeanAbsoluteDeviation)); - featureList.push_back(std::make_pair("FirstOrder Median absolute deviation", median_absolut_deviation)); - featureList.push_back(std::make_pair("FirstOrder Coefficient of variation", coefficient_of_variation)); - featureList.push_back(std::make_pair("FirstOrder Quantile coefficient of dispersion", quantile_coefficient_of_dispersion)); - featureList.push_back(std::make_pair("FirstOrder Energy", squared_sum)); - featureList.push_back(std::make_pair("FirstOrder RMS", rms)); + featureList.push_back(std::make_pair("First Order::Mean", labelStatisticsImageFilter->GetMean(1))); + featureList.push_back(std::make_pair("First Order::Unbiased Variance", labelStatisticsImageFilter->GetVariance(1))); //Siehe Definition von Unbiased Variance estimation. (Wird nicht durch n sondern durch n-1 normalisiert) + featureList.push_back(std::make_pair("First Order::Biased Variance", variance)); + featureList.push_back(std::make_pair("First Order::Skewness", skewness)); + featureList.push_back(std::make_pair("First Order::Kurtosis", kurtosis)); + featureList.push_back(std::make_pair("First Order::Median", labelStatisticsImageFilter->GetMedian(1))); + featureList.push_back(std::make_pair("First Order::Minimum", labelStatisticsImageFilter->GetMinimum(1))); + featureList.push_back(std::make_pair("First Order::Maximum", labelStatisticsImageFilter->GetMaximum(1))); + featureList.push_back(std::make_pair("First Order::Range", range)); + featureList.push_back(std::make_pair("First Order::Mean Absolute Deviation", mean_absolut_deviation)); + featureList.push_back(std::make_pair("First Order::Robust Mean Absolute Deviation", robustMeanAbsoluteDeviation)); + featureList.push_back(std::make_pair("First Order::Median Absolute Deviation", median_absolut_deviation)); + featureList.push_back(std::make_pair("First Order::Coefficient Of Variation", coefficient_of_variation)); + featureList.push_back(std::make_pair("First Order::Quantile Coefficient Of Dispersion", quantile_coefficient_of_dispersion)); + featureList.push_back(std::make_pair("First Order::Energy", squared_sum)); + featureList.push_back(std::make_pair("First Order::Root Mean Square", rms)); HistogramType::MeasurementVectorType mv(1); mv[0] = 0; HistogramType::IndexType resultingIndex; histogram->GetIndex(mv, resultingIndex); - MITK_INFO << "aaa" << resultingIndex; - std::cout << "Instance identifier of index " << resultingIndex - << " is " << histogram->GetInstanceIdentifier(resultingIndex) - << std::endl; - featureList.push_back(std::make_pair("FirstOrder Minimum Bin", 0)); - - featureList.push_back(std::make_pair("FirstOrder Robust Mean", meanRobust)); - featureList.push_back(std::make_pair("FirstOrder Uniformity", uniformity)); - featureList.push_back(std::make_pair("FirstOrder Entropy", entropy)); - featureList.push_back(std::make_pair("FirstOrder Excess Kurtosis", kurtosis - 3)); - featureList.push_back(std::make_pair("FirstOrder Covered Image Intensity Range", coveredGrayValueRange)); - featureList.push_back(std::make_pair("FirstOrder Sum", labelStatisticsImageFilter->GetSum(1))); - featureList.push_back(std::make_pair("FirstOrder Mode", mode_bin)); - featureList.push_back(std::make_pair("FirstOrder Mode Probability", mode_value)); - featureList.push_back(std::make_pair("FirstOrder Standard deviation", labelStatisticsImageFilter->GetSigma(1))); - featureList.push_back(std::make_pair("FirstOrder No. of Voxel", labelStatisticsImageFilter->GetCount(1))); - - featureList.push_back(std::make_pair("FirstOrder 05th Percentile", p05th)); - featureList.push_back(std::make_pair("FirstOrder 10th Percentile", p10th)); - featureList.push_back(std::make_pair("FirstOrder 15th Percentile", p15th)); - featureList.push_back(std::make_pair("FirstOrder 20th Percentile", p20th)); - featureList.push_back(std::make_pair("FirstOrder 25th Percentile", p25th)); - featureList.push_back(std::make_pair("FirstOrder 30th Percentile", p30th)); - featureList.push_back(std::make_pair("FirstOrder 35th Percentile", p35th)); - featureList.push_back(std::make_pair("FirstOrder 40th Percentile", p40th)); - featureList.push_back(std::make_pair("FirstOrder 45th Percentile", p45th)); - featureList.push_back(std::make_pair("FirstOrder 50th Percentile", p50th)); - featureList.push_back(std::make_pair("FirstOrder 55th Percentile", p55th)); - featureList.push_back(std::make_pair("FirstOrder 60th Percentile", p60th)); - featureList.push_back(std::make_pair("FirstOrder 65th Percentile", p65th)); - featureList.push_back(std::make_pair("FirstOrder 70th Percentile", p70th)); - featureList.push_back(std::make_pair("FirstOrder 75th Percentile", p75th)); - featureList.push_back(std::make_pair("FirstOrder 80th Percentile", p80th)); - featureList.push_back(std::make_pair("FirstOrder 85th Percentile", p85th)); - featureList.push_back(std::make_pair("FirstOrder 90th Percentile", p90th)); - featureList.push_back(std::make_pair("FirstOrder 95th Percentile", p95th)); - featureList.push_back(std::make_pair("FirstOrder Interquartile Range", (p75th - p25th))); - featureList.push_back(std::make_pair("FirstOrder Image Dimension", VImageDimension)); - featureList.push_back(std::make_pair("FirstOrder Voxel Space", voxelSpace)); - featureList.push_back(std::make_pair("FirstOrder Voxel Volume", voxelVolume)); + featureList.push_back(std::make_pair("First Order::Robust Mean", meanRobust)); + featureList.push_back(std::make_pair("First Order::Uniformity", uniformity)); + featureList.push_back(std::make_pair("First Order::Entropy", entropy)); + featureList.push_back(std::make_pair("First Order::Excess Kurtosis", kurtosis - 3)); + featureList.push_back(std::make_pair("First Order::Covered Image Intensity Range", coveredGrayValueRange)); + featureList.push_back(std::make_pair("First Order::Sum", labelStatisticsImageFilter->GetSum(1))); + featureList.push_back(std::make_pair("First Order::Mode", mode_bin)); + featureList.push_back(std::make_pair("First Order::Mode Probability", mode_value)); + featureList.push_back(std::make_pair("First Order::Unbiased Standard deviation", labelStatisticsImageFilter->GetSigma(1))); + featureList.push_back(std::make_pair("First Order::Biased Standard deviation", sqrt(variance))); + featureList.push_back(std::make_pair("First Order::Number Of Voxels", labelStatisticsImageFilter->GetCount(1))); + + featureList.push_back(std::make_pair("First Order::05th Percentile", p05th)); + featureList.push_back(std::make_pair("First Order::10th Percentile", p10th)); + featureList.push_back(std::make_pair("First Order::15th Percentile", p15th)); + featureList.push_back(std::make_pair("First Order::20th Percentile", p20th)); + featureList.push_back(std::make_pair("First Order::25th Percentile", p25th)); + featureList.push_back(std::make_pair("First Order::30th Percentile", p30th)); + featureList.push_back(std::make_pair("First Order::35th Percentile", p35th)); + featureList.push_back(std::make_pair("First Order::40th Percentile", p40th)); + featureList.push_back(std::make_pair("First Order::45th Percentile", p45th)); + featureList.push_back(std::make_pair("First Order::50th Percentile", p50th)); + featureList.push_back(std::make_pair("First Order::55th Percentile", p55th)); + featureList.push_back(std::make_pair("First Order::60th Percentile", p60th)); + featureList.push_back(std::make_pair("First Order::65th Percentile", p65th)); + featureList.push_back(std::make_pair("First Order::70th Percentile", p70th)); + featureList.push_back(std::make_pair("First Order::75th Percentile", p75th)); + featureList.push_back(std::make_pair("First Order::80th Percentile", p80th)); + featureList.push_back(std::make_pair("First Order::85th Percentile", p85th)); + featureList.push_back(std::make_pair("First Order::90th Percentile", p90th)); + featureList.push_back(std::make_pair("First Order::95th Percentile", p95th)); + featureList.push_back(std::make_pair("First Order::Interquartile Range", (p75th - p25th))); + featureList.push_back(std::make_pair("First Order::Image Dimension", VImageDimension)); + featureList.push_back(std::make_pair("First Order::Voxel Space", voxelSpace)); + featureList.push_back(std::make_pair("First Order::Voxel Volume", voxelVolume)); } -mitk::GIFFirstOrderStatistics::GIFFirstOrderStatistics() : -m_HistogramSize(256), m_UseCtRange(false) +mitk::GIFFirstOrderStatistics::GIFFirstOrderStatistics() { SetShortName("fo"); SetLongName("first-order"); } mitk::GIFFirstOrderStatistics::FeatureListType mitk::GIFFirstOrderStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { + InitializeQuantifier(image, mask); FeatureListType featureList; ParameterStruct params; - params.m_HistogramSize = this->m_HistogramSize; - params.m_UseCtRange = this->m_UseCtRange; - params.MinimumIntensity = GetMinimumIntensity(); - params.MaximumIntensity = GetMaximumIntensity(); - params.UseMinimumIntensity = GetUseMinimumIntensity(); - params.UseMaximumIntensity = GetUseMaximumIntensity(); - params.Bins = GetBins(); + params.MinimumIntensity = GetQuantifier()->GetMinimum(); + params.MaximumIntensity = GetQuantifier()->GetMaximum(); + params.Bins = GetQuantifier()->GetBins(); AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, params); return featureList; } mitk::GIFFirstOrderStatistics::FeatureNameListType mitk::GIFFirstOrderStatistics::GetFeatureNames() { FeatureNameListType featureList; - featureList.push_back("FirstOrder Minimum"); - featureList.push_back("FirstOrder Maximum"); - featureList.push_back("FirstOrder Mean"); - featureList.push_back("FirstOrder Variance"); - featureList.push_back("FirstOrder Sum"); - featureList.push_back("FirstOrder Median"); - featureList.push_back("FirstOrder Standard deviation"); - featureList.push_back("FirstOrder No. of Voxel"); + featureList.push_back("First Order::Minimum"); + featureList.push_back("First Order::Maximum"); + featureList.push_back("First Order::Mean"); + featureList.push_back("First Order::Variance"); + featureList.push_back("First Order::Sum"); + featureList.push_back("First Order::Median"); + featureList.push_back("First Order::Standard deviation"); + featureList.push_back("First Order::No. of Voxel"); return featureList; } void mitk::GIFFirstOrderStatistics::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); - parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Volume-Statistic", "calculates volume based features", us::Any()); + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Volume-Statistic", "calculates volume based features", us::Any()); + AddQuantifierArguments(parser); } void mitk::GIFFirstOrderStatistics::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...."; } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGrayLevelSizeZone.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGrayLevelSizeZone.cpp deleted file mode 100644 index e0e80f4be9..0000000000 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGrayLevelSizeZone.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/*=================================================================== - -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 - -// STL -#include - -template -void - CalculateGrayLevelSizeZoneFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFGrayLevelSizeZone::FeatureListType & featureList, mitk::GIFGrayLevelSizeZone::ParameterStruct params) -{ - typedef itk::Image ImageType; - typedef itk::Image MaskType; - typedef itk::Statistics::EnhancedScalarImageToSizeZoneFeaturesFilter FilterType; - typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; - typedef typename FilterType::SizeZoneFeaturesFilterType TextureFilterType; - - typename MaskType::Pointer maskImage = MaskType::New(); - mitk::CastToItkImage(mask, maskImage); - - typename FilterType::Pointer filter = FilterType::New(); - - typename FilterType::OffsetVector::Pointer newOffset = FilterType::OffsetVector::New(); - auto oldOffsets = filter->GetOffsets(); - auto oldOffsetsIterator = oldOffsets->Begin(); - while (oldOffsetsIterator != oldOffsets->End()) - { - bool continueOuterLoop = false; - typename FilterType::OffsetType offset = oldOffsetsIterator->Value(); - for (unsigned int i = 0; i < VImageDimension; ++i) - { - if (params.m_Direction == i + 2 && offset[i] != 0) - { - continueOuterLoop = true; - } - } - if (params.m_Direction == 1) - { - offset[0] = 0; - offset[1] = 0; - offset[2] = 1; - newOffset->push_back(offset); - break; - } - - oldOffsetsIterator++; - if (continueOuterLoop) - continue; - newOffset->push_back(offset); - } - filter->SetOffsets(newOffset); - - - // All features are required - typename FilterType::FeatureNameVectorPointer requestedFeatures = FilterType::FeatureNameVector::New(); - requestedFeatures->push_back(TextureFilterType::SmallZoneEmphasis); - requestedFeatures->push_back(TextureFilterType::LargeZoneEmphasis); - requestedFeatures->push_back(TextureFilterType::GreyLevelNonuniformity); - requestedFeatures->push_back(TextureFilterType::GreyLevelNonuniformityNormalized); - requestedFeatures->push_back(TextureFilterType::SizeZoneNonuniformity); - requestedFeatures->push_back(TextureFilterType::SizeZoneNonuniformityNormalized); - requestedFeatures->push_back(TextureFilterType::LowGreyLevelZoneEmphasis); - requestedFeatures->push_back(TextureFilterType::HighGreyLevelZoneEmphasis); - requestedFeatures->push_back(TextureFilterType::SmallZoneLowGreyLevelEmphasis); - requestedFeatures->push_back(TextureFilterType::SmallZoneHighGreyLevelEmphasis); - requestedFeatures->push_back(TextureFilterType::LargeZoneLowGreyLevelEmphasis); - requestedFeatures->push_back(TextureFilterType::LargeZoneHighGreyLevelEmphasis); - requestedFeatures->push_back(TextureFilterType::ZonePercentage); - requestedFeatures->push_back(TextureFilterType::GreyLevelVariance); - requestedFeatures->push_back(TextureFilterType::SizeZoneVariance); - requestedFeatures->push_back(TextureFilterType::ZoneEntropy); - - typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); - minMaxComputer->SetImage(itkImage); - minMaxComputer->Compute(); - - filter->SetInput(itkImage); - filter->SetMaskImage(maskImage); - filter->SetRequestedFeatures(requestedFeatures); - int rangeOfPixels = params.m_Range; - if (rangeOfPixels < 2) - rangeOfPixels = 256; - - if (params.m_UseCtRange) - { - filter->SetPixelValueMinMax((TPixel)(-1024.5),(TPixel)(3096.5)); - filter->SetNumberOfBinsPerAxis(3096.5+1024.5); - } else - { - filter->SetPixelValueMinMax(minMaxComputer->GetMinimum(),minMaxComputer->GetMaximum()); - filter->SetNumberOfBinsPerAxis(rangeOfPixels); - } - - filter->SetDistanceValueMinMax(0,rangeOfPixels); - - filter->Update(); - - auto featureMeans = filter->GetFeatureMeans (); - auto featureStd = filter->GetFeatureStandardDeviations(); - - std::ostringstream ss; - ss << rangeOfPixels; - std::string strRange = ss.str(); - for (std::size_t i = 0; i < featureMeans->size(); ++i) - { - switch (i) - { - case TextureFilterType::SmallZoneEmphasis : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") SmallZoneEmphasis Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::LargeZoneEmphasis : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") LargeZoneEmphasis Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::GreyLevelNonuniformity : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") GreyLevelNonuniformity Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::GreyLevelNonuniformityNormalized : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") GreyLevelNonuniformityNormalized Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::SizeZoneNonuniformity : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") SizeZoneNonuniformity Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::SizeZoneNonuniformityNormalized : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") SizeZoneNonuniformityNormalized Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::LowGreyLevelZoneEmphasis : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") LowGreyLevelZoneEmphasis Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::HighGreyLevelZoneEmphasis : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") HighGreyLevelZoneEmphasis Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::SmallZoneLowGreyLevelEmphasis : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") SmallZoneLowGreyLevelEmphasis Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::SmallZoneHighGreyLevelEmphasis : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") SmallZoneHighGreyLevelEmphasis Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::LargeZoneLowGreyLevelEmphasis : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") LargeZoneLowGreyLevelEmphasis Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::LargeZoneHighGreyLevelEmphasis : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") LargeZoneHighGreyLevelEmphasis Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::ZonePercentage : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") ZonePercentage Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::GreyLevelVariance : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") GreyLevelVariance Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::SizeZoneVariance : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") SizeZoneVariance Means",featureMeans->ElementAt(i))); - break; - case TextureFilterType::ZoneEntropy : - featureList.push_back(std::make_pair("SizeZone ("+ strRange+") ZoneEntropy Means",featureMeans->ElementAt(i))); - break; - default: - break; - } - } -} - -mitk::GIFGrayLevelSizeZone::GIFGrayLevelSizeZone(): -m_Range(1.0), m_UseCtRange(false) -{ - SetShortName("glsz"); - SetLongName("greylevelsizezone"); -} - -mitk::GIFGrayLevelSizeZone::FeatureListType mitk::GIFGrayLevelSizeZone::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) -{ - FeatureListType featureList; - - ParameterStruct params; - params.m_UseCtRange=m_UseCtRange; - params.m_Range = m_Range; - params.m_Direction = GetDirection(); - - AccessByItk_3(image, CalculateGrayLevelSizeZoneFeatures, mask, featureList,params); - - return featureList; -} - -mitk::GIFGrayLevelSizeZone::FeatureNameListType mitk::GIFGrayLevelSizeZone::GetFeatureNames() -{ - FeatureNameListType featureList; - featureList.push_back("SizeZone SmallZoneEmphasis Means"); - featureList.push_back("SizeZone SmallZoneEmphasis Std."); - featureList.push_back("SizeZone LargeZoneEmphasis Means"); - featureList.push_back("SizeZone LargeZoneEmphasis Std."); - featureList.push_back("SizeZone GreyLevelNonuniformity Means"); - featureList.push_back("SizeZone GreyLevelNonuniformity Std."); - featureList.push_back("SizeZone SizeZoneNonuniformity Means"); - featureList.push_back("SizeZone SizeZoneNonuniformity Std."); - featureList.push_back("SizeZone LowGreyLevelZoneEmphasis Means"); - featureList.push_back("SizeZone LowGreyLevelZoneEmphasis Std."); - featureList.push_back("SizeZone HighGreyLevelZoneEmphasis Means"); - featureList.push_back("SizeZone HighGreyLevelZoneEmphasis Std."); - featureList.push_back("SizeZone SmallZoneLowGreyLevelEmphasis Means"); - featureList.push_back("SizeZone SmallZoneLowGreyLevelEmphasis Std."); - featureList.push_back("SizeZone SmallZoneHighGreyLevelEmphasis Means"); - featureList.push_back("SizeZone SmallZoneHighGreyLevelEmphasis Std."); - featureList.push_back("SizeZone LargeZoneHighGreyLevelEmphasis Means"); - featureList.push_back("SizeZone LargeZoneHighGreyLevelEmphasis Std."); - return featureList; -} - - - -void mitk::GIFGrayLevelSizeZone::AddArguments(mitkCommandLineParser &parser) -{ - std::string name = GetOptionPrefix(); - - parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "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()); - parser.addArgument(name + "::direction", name + "::dir", mitkCommandLineParser::String, "Int", "Allows to specify the direction for Cooc and RL. 0: All directions, 1: Only single direction (Test purpose), 2,3,4... without dimension 0,1,2... ", us::Any()); - parser.addArgument(name + "::ctrange", name + "::ctrange", mitkCommandLineParser::String, "Int", "Turn on if CT images are used", us::Any()); -} - -void -mitk::GIFGrayLevelSizeZone::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())) - { - int direction = 0; - if (parsedArgs.count(name + "::direction")) - { - direction = SplitDouble(parsedArgs[name + "::direction"].ToString(), ';')[0]; - } - std::vector ranges; - if (parsedArgs.count(name + "::range")) - { - ranges = SplitDouble(parsedArgs[name + "::range"].ToString(), ';'); - } - else - { - ranges.push_back(1); - } - - if (parsedArgs.count(name + "::ctrange")) - { - SetUseCtRange(true); - } - - - for (std::size_t i = 0; i < ranges.size(); ++i) - { - MITK_INFO << "Start calculating coocurence with range " << ranges[i] << "...."; - this->SetRange(ranges[i]); - this->SetDirection(direction); - auto localResults = this->CalculateFeatures(feature, maskNoNAN); - featureList.insert(featureList.end(), localResults.begin(), localResults.end()); - MITK_INFO << "Finished calculating coocurence with range " << ranges[i] << "...."; - } - } - -} - - diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp index d74d0b34cb..3ef0c99140 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp @@ -1,524 +1,471 @@ #include // MITK #include #include #include #include #include // ITK - #include #include #include #include #include -// STL -#include - static void MatrixFeaturesTo(mitk::GreyLevelDistanceZoneFeatures features, std::string prefix, mitk::GIFGreyLevelDistanceZone::FeatureListType &featureList); mitk::GreyLevelDistanceZoneMatrixHolder::GreyLevelDistanceZoneMatrixHolder(double min, double max, int number, int maxSize) : m_MinimumRange(min), m_MaximumRange(max), m_NumberOfBins(number), m_MaximumSize(maxSize), m_NumerOfVoxels(0) { m_Matrix.resize(number, maxSize); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::GreyLevelDistanceZoneMatrixHolder::IntensityToIndex(double intensity) { return std::floor((intensity - m_MinimumRange) / m_Stepsize); } double mitk::GreyLevelDistanceZoneMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::GreyLevelDistanceZoneMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::GreyLevelDistanceZoneMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template int CalculateGlSZMatrix(itk::Image* itkImage, - itk::Image* mask, - itk::Image* distanceImage, + itk::Image* mask, + itk::Image* distanceImage, std::vector > offsets, bool estimateLargestRegion, mitk::GreyLevelDistanceZoneMatrixHolder &holder) { typedef itk::Image ImageType; - typedef itk::Image MaskImageType; + typedef itk::Image MaskImageType; typedef typename ImageType::IndexType IndexType; typedef itk::ImageRegionIteratorWithIndex ConstIterType; typedef itk::ImageRegionIteratorWithIndex ConstMaskIterType; auto region = mask->GetLargestPossibleRegion(); typename MaskImageType::RegionType newRegion; newRegion.SetSize(region.GetSize()); newRegion.SetIndex(region.GetIndex()); ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); typename MaskImageType::Pointer visitedImage = MaskImageType::New(); visitedImage->SetRegions(newRegion); visitedImage->Allocate(); visitedImage->FillBuffer(0); int largestRegion = 0; holder.m_NumberOfBins = 0; while (!maskIter.IsAtEnd()) { if (maskIter.Value() > 0 ) { auto startIntensityIndex = holder.IntensityToIndex(imageIter.Value()); std::vector indices; indices.push_back(maskIter.GetIndex()); unsigned int steps = 0; int smallestDistance = 500; while (indices.size() > 0) { auto currentIndex = indices.back(); indices.pop_back(); if (!region.IsInside(currentIndex)) { continue; } auto wasVisited = visitedImage->GetPixel(currentIndex); auto newIntensityIndex = holder.IntensityToIndex(itkImage->GetPixel(currentIndex)); auto isInMask = mask->GetPixel(currentIndex); if ((isInMask > 0) && (newIntensityIndex == startIntensityIndex) && (wasVisited < 1)) { ++(holder.m_NumerOfVoxels); smallestDistance = (smallestDistance > distanceImage->GetPixel(currentIndex)) ? distanceImage->GetPixel(currentIndex) : smallestDistance; ++steps; visitedImage->SetPixel(currentIndex, 1); for (auto offset : offsets) { auto newIndex = currentIndex + offset; indices.push_back(newIndex); newIndex = currentIndex - offset; indices.push_back(newIndex); } } } if (steps > 0) { largestRegion = std::max(steps, largestRegion); steps = std::min(steps, holder.m_MaximumSize); if (!estimateLargestRegion) { holder.m_Matrix(startIntensityIndex, smallestDistance-1) += 1; } } } ++imageIter; ++maskIter; } return largestRegion; } template void itkErode( itk::Image *sourceImage, mitk::Image::Pointer &resultImage, bool &segmentationRemaining) { typedef itk::Image ImageType; typedef itk::BinaryCrossStructuringElement CrossType; typedef typename itk::BinaryErodeImageFilter CrossErodeFilterType; CrossType cross; typename CrossType::SizeType size; size.Fill(1); cross.SetRadius(size); cross.CreateStructuringElement(); typename CrossErodeFilterType::Pointer erodeFilter = CrossErodeFilterType::New(); erodeFilter->SetKernel(cross); erodeFilter->SetInput(sourceImage); erodeFilter->SetErodeValue(1); erodeFilter->UpdateLargestPossibleRegion(); segmentationRemaining = false; itk::ImageRegionConstIterator iter(erodeFilter->GetOutput(), erodeFilter->GetOutput()->GetLargestPossibleRegion()); while ((!iter.IsAtEnd()) && (!segmentationRemaining)) { if (iter.Get() > 0) segmentationRemaining = true; ++iter; } mitk::CastToMitkImage(erodeFilter->GetOutput(), resultImage); } template void itkAdd( itk::Image *imageA, mitk::Image::Pointer mitkImageB, mitk::Image::Pointer &resultImage) { typedef itk::Image ImageType; typedef itk::AddImageFilter AddFilterType; typename ImageType::Pointer imageB; mitk::CastToItkImage(mitkImageB, imageB); typename AddFilterType::Pointer addFilter = AddFilterType::New(); addFilter->SetInput1(imageA); addFilter->SetInput2(imageB); addFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(addFilter->GetOutput(), resultImage); } void erode(mitk::Image::Pointer input, mitk::Image::Pointer &output, bool &segmentationRemaining) { AccessByItk_2(input, itkErode, output, segmentationRemaining); } void add(mitk::Image::Pointer inputA, mitk::Image::Pointer inputB, mitk::Image::Pointer &output) { AccessByItk_2(inputA, itkAdd, inputB, output); } void erodeAndAdd(mitk::Image::Pointer input, mitk::Image::Pointer& finalOutput, int &maxDistance) { mitk::Image::Pointer workingImage = input; mitk::Image::Pointer output = input; maxDistance = 0; bool segmentationRemaining = true; while (segmentationRemaining) { mitk::Image::Pointer erodedImage = mitk::Image::New(); mitk::Image::Pointer result = mitk::Image::New(); erode(workingImage, erodedImage, segmentationRemaining); workingImage = erodedImage; add(output, erodedImage, result); output = result; ++maxDistance; } finalOutput = output; } void static CalculateFeatures( mitk::GreyLevelDistanceZoneMatrixHolder &holder, mitk::GreyLevelDistanceZoneFeatures & results ) { auto SgzMatrix = holder.m_Matrix; auto pgzMatrix = holder.m_Matrix; auto pgMatrix = holder.m_Matrix; auto pzMatrix = holder.m_Matrix; double Ns = pgzMatrix.sum(); pgzMatrix /= Ns; pgMatrix.rowwise().normalize(); pzMatrix.colwise().normalize(); for (int i = 0; i < holder.m_NumberOfBins; ++i) for (int j = 0; j < holder.m_NumberOfBins; ++j) { if (pgzMatrix(i, j) != pgzMatrix(i, j)) pgzMatrix(i, j) = 0; if (pgMatrix(i, j) != pgMatrix(i, j)) pgMatrix(i, j) = 0; if (pzMatrix(i, j) != pzMatrix(i, j)) pzMatrix(i, j) = 0; } Eigen::VectorXd SgVector = SgzMatrix.rowwise().sum(); Eigen::VectorXd SzVector = SgzMatrix.colwise().sum(); for (int j = 0; j < SzVector.size(); ++j) { results.SmallDistanceEmphasis += SzVector(j) / (j+1) / (j+1); results.LargeDistanceEmphasis += SzVector(j) * (j + 1.0) * (j + 1.0); results.ZoneDistanceNonUniformity += SzVector(j) * SzVector(j); results.ZoneDistanceNoneUniformityNormalized += SzVector(j) * SzVector(j); } for (int i = 0; i < SgVector.size(); ++i) { results.LowGreyLevelEmphasis += SgVector(i) / (i + 1) / (i + 1); results.HighGreyLevelEmphasis += SgVector(i) * (i + 1) * (i + 1); results.GreyLevelNonUniformity += SgVector(i)*SgVector(i); results.GreyLevelNonUniformityNormalized += SgVector(i)*SgVector(i); } for (int i = 0; i < SgzMatrix.rows(); ++i) { for (int j = 0; j < SgzMatrix.cols(); ++j) { results.SmallDistanceLowGreyLevelEmphasis += SgzMatrix(i, j) / (i + 1) / (i + 1) / (j + 1) / (j + 1); results.SmallDistanceHighGreyLevelEmphasis += SgzMatrix(i, j) * (i + 1) * (i + 1) / (j + 1) / (j + 1); results.LargeDistanceLowGreyLevelEmphasis += SgzMatrix(i, j) / (i + 1) / (i + 1) * (j + 1.0) * (j + 1.0); results.LargeDistanceHighGreyLevelEmphasis += SgzMatrix(i, j) * (i + 1) * (i + 1) * (j + 1.0) * (j + 1.0); results.ZonePercentage += SgzMatrix(i, j); results.GreyLevelMean += (i + 1)*pgzMatrix(i, j); results.ZoneDistanceMean += (j + 1)*pgzMatrix(i, j); if (pgzMatrix(i, j) > 0) results.ZoneDistanceEntropy -= pgzMatrix(i, j) * std::log(pgzMatrix(i, j)) / std::log(2); } } for (int i = 0; i < SgzMatrix.rows(); ++i) { for (int j = 0; j < SgzMatrix.cols(); ++j) { results.GreyLevelVariance += (i + 1 - results.GreyLevelMean)*(i + 1 - results.GreyLevelMean)*pgzMatrix(i, j); results.ZoneDistanceVariance += (j + 1 - results.ZoneDistanceMean)*(j + 1 - results.ZoneDistanceMean)*pgzMatrix(i, j); } } results.SmallDistanceEmphasis /= Ns; results.LargeDistanceEmphasis /= Ns; results.LowGreyLevelEmphasis /= Ns; results.HighGreyLevelEmphasis /= Ns; results.SmallDistanceLowGreyLevelEmphasis /= Ns; results.SmallDistanceHighGreyLevelEmphasis /= Ns; results.LargeDistanceLowGreyLevelEmphasis /= Ns; results.LargeDistanceHighGreyLevelEmphasis /= Ns; results.GreyLevelNonUniformity /= Ns; results.GreyLevelNonUniformityNormalized /= Ns*Ns; results.ZoneDistanceNonUniformity /= Ns; results.ZoneDistanceNoneUniformityNormalized /= Ns*Ns; results.ZonePercentage = Ns / holder.m_NumerOfVoxels;// results.ZonePercentage; } template static void CalculateGreyLevelDistanceZoneFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFGreyLevelDistanceZone::FeatureListType & featureList, mitk::GIFGreyLevelDistanceZone::GIFGreyLevelDistanceZoneConfiguration config) { typedef itk::Image ImageType; - typedef itk::Image MaskType; + typedef itk::Image MaskType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// - - typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); - minMaxComputer->SetImage(itkImage); - minMaxComputer->Compute(); - - double rangeMin = -0.5 + minMaxComputer->GetMinimum(); - double rangeMax = 0.5 + minMaxComputer->GetMaximum(); - - if (config.UseMinimumIntensity) - rangeMin = config.MinimumIntensity; - if (config.UseMaximumIntensity) - rangeMax = config.MaximumIntensity; - - // Define Range + double rangeMin = config.MinimumIntensity; + double rangeMax = config.MaximumIntensity; int numberOfBins = config.Bins; int maximumDistance = 0; mitk::Image::Pointer mitkDistanceImage = mitk::Image::New(); erodeAndAdd(config.distanceMask, mitkDistanceImage, maximumDistance); typename MaskType::Pointer distanceImage = MaskType::New(); mitk::CastToItkImage(mitkDistanceImage, distanceImage); 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; offsetVector.push_back(offset); } MITK_INFO << "Maximum Distance: " << maximumDistance; std::vector resultVector; mitk::GreyLevelDistanceZoneMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins, maximumDistance+1); mitk::GreyLevelDistanceZoneFeatures overallFeature; CalculateGlSZMatrix(itkImage, maskImage, distanceImage, offsetVector, false, holderOverall); CalculateFeatures(holderOverall, overallFeature); - std::stringstream ss; - ss << config.range; - std::string strRange = ss.str(); - MatrixFeaturesTo(overallFeature, "Grey Level Distance Zone (" + strRange + ")", featureList); + MatrixFeaturesTo(overallFeature, "Grey Level Distance Zone::", featureList); } static void MatrixFeaturesTo(mitk::GreyLevelDistanceZoneFeatures features, std::string prefix, mitk::GIFGreyLevelDistanceZone::FeatureListType &featureList) { - featureList.push_back(std::make_pair(prefix + " Small Distance Emphasis", features.SmallDistanceEmphasis)); - featureList.push_back(std::make_pair(prefix + " Large Distance Emphasis", features.LargeDistanceEmphasis)); - featureList.push_back(std::make_pair(prefix + " Low Grey Level Emphasis", features.LowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + " High Grey Level Emphasis", features.HighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + " Small Distance Low Grey LEvel Emphasis", features.SmallDistanceLowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + " Small Distance High Grey LEvel Emphasis", features.SmallDistanceHighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + " Large Distance Low Grey Level Emphasis", features.LargeDistanceLowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + " Large Distance High Grey Level Emphasis", features.LargeDistanceHighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + " Grey Level Non-Uniformity", features.GreyLevelNonUniformity)); - featureList.push_back(std::make_pair(prefix + " Grey Level Non-Uniformity Normalized", features.GreyLevelNonUniformityNormalized)); - featureList.push_back(std::make_pair(prefix + " Distance Size Non-Uniformity", features.ZoneDistanceNonUniformity)); - featureList.push_back(std::make_pair(prefix + " Distance Size Non-Uniformity Normalized", features.ZoneDistanceNoneUniformityNormalized)); - featureList.push_back(std::make_pair(prefix + " Zone Percentage", features.ZonePercentage)); - featureList.push_back(std::make_pair(prefix + " Grey Level Mean", features.GreyLevelMean)); - featureList.push_back(std::make_pair(prefix + " Grey Level Variance", features.GreyLevelVariance)); - featureList.push_back(std::make_pair(prefix + " Zone Distance Size Mean", features.ZoneDistanceMean)); - featureList.push_back(std::make_pair(prefix + " Zone Distance Size Variance", features.ZoneDistanceVariance)); - featureList.push_back(std::make_pair(prefix + " Zone Distance Size Entropy", features.ZoneDistanceEntropy)); + featureList.push_back(std::make_pair(prefix + "Small Distance Emphasis", features.SmallDistanceEmphasis)); + featureList.push_back(std::make_pair(prefix + "Large Distance Emphasis", features.LargeDistanceEmphasis)); + featureList.push_back(std::make_pair(prefix + "Low Grey Level Emphasis", features.LowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + "High Grey Level Emphasis", features.HighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + "Small Distance Low Grey Level Emphasis", features.SmallDistanceLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + "Small Distance High Grey Level Emphasis", features.SmallDistanceHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + "Large Distance Low Grey Level Emphasis", features.LargeDistanceLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + "Large Distance High Grey Level Emphasis", features.LargeDistanceHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + "Grey Level Non-Uniformity", features.GreyLevelNonUniformity)); + featureList.push_back(std::make_pair(prefix + "Grey Level Non-Uniformity Normalized", features.GreyLevelNonUniformityNormalized)); + featureList.push_back(std::make_pair(prefix + "Distance Size Non-Uniformity", features.ZoneDistanceNonUniformity)); + featureList.push_back(std::make_pair(prefix + "Distance Size Non-Uniformity Normalized", features.ZoneDistanceNoneUniformityNormalized)); + featureList.push_back(std::make_pair(prefix + "Zone Percentage", features.ZonePercentage)); + featureList.push_back(std::make_pair(prefix + "Grey Level Mean", features.GreyLevelMean)); + featureList.push_back(std::make_pair(prefix + "Grey Level Variance", features.GreyLevelVariance)); + featureList.push_back(std::make_pair(prefix + "Zone Distance Mean", features.ZoneDistanceMean)); + featureList.push_back(std::make_pair(prefix + "Zone Distance Variance", features.ZoneDistanceVariance)); + featureList.push_back(std::make_pair(prefix + "Zone Distance Entropy", features.ZoneDistanceEntropy)); + featureList.push_back(std::make_pair(prefix + "Grey Level Entropy", features.ZoneDistanceEntropy)); } - mitk::GIFGreyLevelDistanceZone::GIFGreyLevelDistanceZone() : - m_Range(1.0), m_Bins(128) + mitk::GIFGreyLevelDistanceZone::GIFGreyLevelDistanceZone() { SetShortName("gldz"); - SetLongName("disctancezone"); + SetLongName("distance-zone"); } mitk::GIFGreyLevelDistanceZone::FeatureListType mitk::GIFGreyLevelDistanceZone::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { + InitializeQuantifier(image, mask); FeatureListType featureList; GIFGreyLevelDistanceZoneConfiguration config; config.direction = GetDirection(); - config.range = m_Range; - - config.MinimumIntensity = GetMinimumIntensity(); - config.MaximumIntensity = GetMaximumIntensity(); - config.UseMinimumIntensity = GetUseMinimumIntensity(); - config.UseMaximumIntensity = GetUseMaximumIntensity(); - config.Bins = GetBins(); if (GetMorphMask().IsNull()) { config.distanceMask = mask->Clone(); } else { config.distanceMask = GetMorphMask(); } - if (GetQuantifier()->GetInitialized()) - { - MITK_INFO << GetQuantifier()->GetMinimum(); - MITK_INFO << GetQuantifier()->GetMaximum(); - MITK_INFO << GetQuantifier()->GetBins(); - MITK_INFO << GetQuantifier()->GetBinsize(); - config.MinimumIntensity = GetQuantifier()->GetMinimum(); - config.MaximumIntensity = GetQuantifier()->GetMaximum(); - config.Bins = GetQuantifier()->GetBins(); - } + config.MinimumIntensity = GetQuantifier()->GetMinimum(); + config.MaximumIntensity = GetQuantifier()->GetMaximum(); + config.Bins = GetQuantifier()->GetBins(); AccessByItk_3(image, CalculateGreyLevelDistanceZoneFeatures, mask, featureList, config); return featureList; } mitk::GIFGreyLevelDistanceZone::FeatureNameListType mitk::GIFGreyLevelDistanceZone::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFGreyLevelDistanceZone::AddArguments(mitkCommandLineParser &parser) { AddQuantifierArguments(parser); std::string name = GetOptionPrefix(); - parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Grey Level Distance Zone", "Calculates the size zone based features.", us::Any()); - parser.addArgument(name + "::range", name + "::range", mitkCommandLineParser::String, "Grey ", "Define the range that is used (Semicolon-separated)", us::Any()); + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Grey Level Distance Zone", "Calculates the size zone based features.", us::Any()); } void mitk::GIFGreyLevelDistanceZone::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); std::string name = GetOptionPrefix(); if (parsedArgs.count(GetLongName())) { - InitializeQuantifier(feature, mask, maskNoNAN, featureList); + InitializeQuantifierFromParameters(feature, mask); - std::vector ranges; - if (parsedArgs.count(name + "::range")) - { - ranges = SplitDouble(parsedArgs[name + "::range"].ToString(), ';'); - } - else - { - ranges.push_back(1); - } - if (parsedArgs.count(name + "::bins")) - { - auto bins = SplitDouble(parsedArgs[name + "::bins"].ToString(), ';')[0]; - this->SetBins(bins); - } - - for (std::size_t i = 0; i < ranges.size(); ++i) - { - MITK_INFO << "Start calculating Grey Level Distance Zone 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 Grey Level Distance Zone with range " << ranges[i] << "...."; - } + MITK_INFO << "Start calculating Grey Level Distance Zone ...."; + auto localResults = this->CalculateFeatures(feature, maskNoNAN); + featureList.insert(featureList.end(), localResults.begin(), localResults.end()); + MITK_INFO << "Finished calculating Grey Level Distance Zone."; } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGrayLevelRunLength.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp similarity index 97% rename from Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGrayLevelRunLength.cpp rename to Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp index 7f4c83d1d9..5db8283500 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGrayLevelRunLength.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp @@ -1,338 +1,338 @@ /*=================================================================== 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 // MITK #include #include #include // ITK #include #include // STL #include template void - CalculateGrayLevelRunLengthFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFGrayLevelRunLength::FeatureListType & featureList, mitk::GIFGrayLevelRunLength::ParameterStruct params) + CalculateGrayLevelRunLengthFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFGreyLevelRunLength::FeatureListType & featureList, mitk::GIFGreyLevelRunLength::ParameterStruct params) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::Statistics::EnhancedScalarImageToRunLengthFeaturesFilter FilterType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typedef typename FilterType::RunLengthFeaturesFilterType TextureFilterType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); typename FilterType::Pointer filter = FilterType::New(); typename FilterType::Pointer filter2 = FilterType::New(); typename FilterType::OffsetVector::Pointer newOffset = FilterType::OffsetVector::New(); auto oldOffsets = filter->GetOffsets(); auto oldOffsetsIterator = oldOffsets->Begin(); while (oldOffsetsIterator != oldOffsets->End()) { bool continueOuterLoop = false; typename FilterType::OffsetType offset = oldOffsetsIterator->Value(); for (unsigned int i = 0; i < VImageDimension; ++i) { if (params.m_Direction == i + 2 && offset[i] != 0) { continueOuterLoop = true; } } if (params.m_Direction == 1) { offset[0] = 0; offset[1] = 0; offset[2] = 1; newOffset->push_back(offset); break; } oldOffsetsIterator++; if (continueOuterLoop) continue; newOffset->push_back(offset); } filter->SetOffsets(newOffset); filter2->SetOffsets(newOffset); // All features are required typename FilterType::FeatureNameVectorPointer requestedFeatures = FilterType::FeatureNameVector::New(); requestedFeatures->push_back(TextureFilterType::ShortRunEmphasis); requestedFeatures->push_back(TextureFilterType::LongRunEmphasis); requestedFeatures->push_back(TextureFilterType::GreyLevelNonuniformity); requestedFeatures->push_back(TextureFilterType::GreyLevelNonuniformityNormalized); requestedFeatures->push_back(TextureFilterType::RunLengthNonuniformity); requestedFeatures->push_back(TextureFilterType::RunLengthNonuniformityNormalized); requestedFeatures->push_back(TextureFilterType::LowGreyLevelRunEmphasis); requestedFeatures->push_back(TextureFilterType::HighGreyLevelRunEmphasis); requestedFeatures->push_back(TextureFilterType::ShortRunLowGreyLevelEmphasis); requestedFeatures->push_back(TextureFilterType::ShortRunHighGreyLevelEmphasis); requestedFeatures->push_back(TextureFilterType::LongRunLowGreyLevelEmphasis); requestedFeatures->push_back(TextureFilterType::LongRunHighGreyLevelEmphasis); requestedFeatures->push_back(TextureFilterType::RunPercentage); requestedFeatures->push_back(TextureFilterType::NumberOfRuns); requestedFeatures->push_back(TextureFilterType::GreyLevelVariance); requestedFeatures->push_back(TextureFilterType::RunLengthVariance); requestedFeatures->push_back(TextureFilterType::RunEntropy); typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); minMaxComputer->SetImage(itkImage); minMaxComputer->Compute(); filter->SetInput(itkImage); filter->SetMaskImage(maskImage); filter->SetRequestedFeatures(requestedFeatures); filter2->SetInput(itkImage); filter2->SetMaskImage(maskImage); filter2->SetRequestedFeatures(requestedFeatures); int rangeOfPixels = params.Bins; if (rangeOfPixels < 2) rangeOfPixels = 256; if (params.m_UseCtRange) { filter->SetPixelValueMinMax((TPixel)(-1024.5),(TPixel)(3096.5)); filter->SetNumberOfBinsPerAxis(3096.5 + 1024.5); filter2->SetPixelValueMinMax((TPixel)(-1024.5), (TPixel)(3096.5)); filter2->SetNumberOfBinsPerAxis(3096.5 + 1024.5); } else { double minRange = minMaxComputer->GetMinimum() - 0.5; double maxRange = minMaxComputer->GetMaximum() + 0.5; if (params.UseMinimumIntensity) minRange = params.MinimumIntensity; if (params.UseMaximumIntensity) maxRange = params.MaximumIntensity; filter->SetPixelValueMinMax(minRange, maxRange); filter->SetNumberOfBinsPerAxis(rangeOfPixels); filter2->SetPixelValueMinMax(minRange, maxRange); filter2->SetNumberOfBinsPerAxis(rangeOfPixels); } filter->SetDistanceValueMinMax(0, rangeOfPixels); filter2->SetDistanceValueMinMax(0, rangeOfPixels); filter2->CombinedFeatureCalculationOn(); filter->Update(); filter2->Update(); auto featureMeans = filter->GetFeatureMeans (); auto featureStd = filter->GetFeatureStandardDeviations(); auto featureCombined = filter2->GetFeatureMeans(); std::ostringstream ss; ss << rangeOfPixels; std::string strRange = ss.str(); for (std::size_t i = 0; i < featureMeans->size(); ++i) { switch (i) { case TextureFilterType::ShortRunEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") ShortRunEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") ShortRunEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") ShortRunEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::LongRunEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") LongRunEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LongRunEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LongRunEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::GreyLevelNonuniformity : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") GreyLevelNonuniformity Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") GreyLevelNonuniformity Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") GreyLevelNonuniformity Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::GreyLevelNonuniformityNormalized : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") GreyLevelNonuniformityNormalized Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") GreyLevelNonuniformityNormalized Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") GreyLevelNonuniformityNormalized Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::RunLengthNonuniformity : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") RunLengthNonuniformity Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunLengthNonuniformity Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunLengthNonuniformity Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::RunLengthNonuniformityNormalized : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") RunLengthNonuniformityNormalized Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunLengthNonuniformityNormalized Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunLengthNonuniformityNormalized Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::LowGreyLevelRunEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") LowGreyLevelRunEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LowGreyLevelRunEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LowGreyLevelRunEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::HighGreyLevelRunEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") HighGreyLevelRunEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") HighGreyLevelRunEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") HighGreyLevelRunEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::ShortRunLowGreyLevelEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") ShortRunLowGreyLevelEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") ShortRunLowGreyLevelEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") ShortRunLowGreyLevelEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::ShortRunHighGreyLevelEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") ShortRunHighGreyLevelEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") ShortRunHighGreyLevelEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") ShortRunHighGreyLevelEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::LongRunLowGreyLevelEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") LongRunLowGreyLevelEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LongRunLowGreyLevelEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LongRunLowGreyLevelEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::LongRunHighGreyLevelEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") LongRunHighGreyLevelEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LongRunHighGreyLevelEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LongRunHighGreyLevelEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::RunPercentage : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") RunPercentage Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunPercentage Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunPercentage Comb.", featureCombined->ElementAt(i)/newOffset->size())); break; case TextureFilterType::NumberOfRuns : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") NumberOfRuns Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") NumberOfRuns Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") NumberOfRuns Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::GreyLevelVariance : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") GreyLevelVariance Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") GreyLevelVariance Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") GreyLevelVariance Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::RunLengthVariance : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") RunLengthVariance Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunLengthVariance Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunLengthVariance Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::RunEntropy : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") RunEntropy Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunEntropy Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunEntropy Comb.", featureCombined->ElementAt(i))); break; default: break; } } } -mitk::GIFGrayLevelRunLength::GIFGrayLevelRunLength(): +mitk::GIFGreyLevelRunLength::GIFGreyLevelRunLength(): m_Range(1.0), m_UseCtRange(false) { SetShortName("rl"); SetLongName("run-length"); } -mitk::GIFGrayLevelRunLength::FeatureListType mitk::GIFGrayLevelRunLength::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +mitk::GIFGreyLevelRunLength::FeatureListType mitk::GIFGreyLevelRunLength::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; ParameterStruct params; params.m_UseCtRange=m_UseCtRange; params.m_Range = m_Range; params.m_Direction = GetDirection(); params.MinimumIntensity = GetMinimumIntensity(); params.MaximumIntensity = GetMaximumIntensity(); params.UseMinimumIntensity = GetUseMinimumIntensity(); params.UseMaximumIntensity = GetUseMaximumIntensity(); params.Bins = GetBins(); MITK_INFO << params.MinimumIntensity; MITK_INFO << params.MaximumIntensity; MITK_INFO << params.m_UseCtRange; MITK_INFO << params.m_Direction; MITK_INFO << params.Bins; MITK_INFO << params.m_Range; AccessByItk_3(image, CalculateGrayLevelRunLengthFeatures, mask, featureList,params); return featureList; } -mitk::GIFGrayLevelRunLength::FeatureNameListType mitk::GIFGrayLevelRunLength::GetFeatureNames() +mitk::GIFGreyLevelRunLength::FeatureNameListType mitk::GIFGreyLevelRunLength::GetFeatureNames() { FeatureNameListType featureList; featureList.push_back("RunLength. ShortRunEmphasis Means"); featureList.push_back("RunLength. ShortRunEmphasis Std."); featureList.push_back("RunLength. LongRunEmphasis Means"); featureList.push_back("RunLength. LongRunEmphasis Std."); featureList.push_back("RunLength. GreyLevelNonuniformity Means"); featureList.push_back("RunLength. GreyLevelNonuniformity Std."); featureList.push_back("RunLength. RunLengthNonuniformity Means"); featureList.push_back("RunLength. RunLengthNonuniformity Std."); featureList.push_back("RunLength. LowGreyLevelRunEmphasis Means"); featureList.push_back("RunLength. LowGreyLevelRunEmphasis Std."); featureList.push_back("RunLength. HighGreyLevelRunEmphasis Means"); featureList.push_back("RunLength. HighGreyLevelRunEmphasis Std."); featureList.push_back("RunLength. ShortRunLowGreyLevelEmphasis Means"); featureList.push_back("RunLength. ShortRunLowGreyLevelEmphasis Std."); featureList.push_back("RunLength. ShortRunHighGreyLevelEmphasis Means"); featureList.push_back("RunLength. ShortRunHighGreyLevelEmphasis Std."); featureList.push_back("RunLength. LongRunHighGreyLevelEmphasis Means"); featureList.push_back("RunLength. LongRunHighGreyLevelEmphasis Std."); return featureList; } -void mitk::GIFGrayLevelRunLength::AddArguments(mitkCommandLineParser &parser) +void mitk::GIFGreyLevelRunLength::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Co-occurence matrix", "calculates Co-occurence based features (new implementation)", us::Any()); parser.addArgument(name + "::bins", name + "::bins", mitkCommandLineParser::String, "RL Bins", "Define the number of bins that is used (Semicolon-separated)", us::Any()); } void -mitk::GIFGrayLevelRunLength::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +mitk::GIFGreyLevelRunLength::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())) { std::vector bins; bins.push_back(GetBins()); if (parsedArgs.count(name + "::bins")) { bins = SplitDouble(parsedArgs[name + "::bins"].ToString(), ';'); } for (std::size_t i = 0; i < bins.size(); ++i) { MITK_INFO << "Start calculating Run-length with range " << bins[i] << "...."; this->SetBins(bins[i]); auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating Run-length with range " << bins[i] << "...."; } } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp index 597caaaff4..5a6e7ae016 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp @@ -1,405 +1,365 @@ #include // MITK #include #include #include // ITK - -#include #include // STL -#include static void MatrixFeaturesTo(mitk::GreyLevelSizeZoneFeatures features, std::string prefix, mitk::GIFGreyLevelSizeZone::FeatureListType &featureList); mitk::GreyLevelSizeZoneMatrixHolder::GreyLevelSizeZoneMatrixHolder(double min, double max, int number, int maxSize) : m_MinimumRange(min), m_MaximumRange(max), m_NumberOfBins(number), m_MaximumSize(maxSize) { m_Matrix.resize(number, maxSize); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::GreyLevelSizeZoneMatrixHolder::IntensityToIndex(double intensity) { return std::floor((intensity - m_MinimumRange) / m_Stepsize); } double mitk::GreyLevelSizeZoneMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::GreyLevelSizeZoneMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::GreyLevelSizeZoneMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template -int +static int CalculateGlSZMatrix(itk::Image* itkImage, - itk::Image* mask, + itk::Image* mask, std::vector > offsets, bool estimateLargestRegion, mitk::GreyLevelSizeZoneMatrixHolder &holder) { typedef itk::Image ImageType; - typedef itk::Image MaskImageType; + typedef itk::Image MaskImageType; typedef typename ImageType::IndexType IndexType; typedef itk::ImageRegionIteratorWithIndex ConstIterType; typedef itk::ImageRegionIteratorWithIndex ConstMaskIterType; auto region = mask->GetLargestPossibleRegion(); typename MaskImageType::RegionType newRegion; newRegion.SetSize(region.GetSize()); newRegion.SetIndex(region.GetIndex()); ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); typename MaskImageType::Pointer visitedImage = MaskImageType::New(); visitedImage->SetRegions(newRegion); visitedImage->Allocate(); visitedImage->FillBuffer(0); int largestRegion = 0; while (!maskIter.IsAtEnd()) { if (maskIter.Value() > 0 ) { auto startIntensityIndex = holder.IntensityToIndex(imageIter.Value()); std::vector indices; indices.push_back(maskIter.GetIndex()); unsigned int steps = 0; while (indices.size() > 0) { auto currentIndex = indices.back(); indices.pop_back(); if (!region.IsInside(currentIndex)) { continue; } auto wasVisited = visitedImage->GetPixel(currentIndex); auto newIntensityIndex = holder.IntensityToIndex(itkImage->GetPixel(currentIndex)); auto isInMask = mask->GetPixel(currentIndex); if ((isInMask > 0) && (newIntensityIndex == startIntensityIndex) && (wasVisited < 1)) { ++steps; visitedImage->SetPixel(currentIndex, 1); for (auto offset : offsets) { auto newIndex = currentIndex + offset; indices.push_back(newIndex); newIndex = currentIndex - offset; indices.push_back(newIndex); } } } if (steps > 0) { largestRegion = std::max(steps, largestRegion); steps = std::min(steps, holder.m_MaximumSize); if (!estimateLargestRegion) { holder.m_Matrix(startIntensityIndex, steps - 1) += 1; } } } ++imageIter; ++maskIter; } return largestRegion; } -void CalculateFeatures( +static void CalculateFeatures( mitk::GreyLevelSizeZoneMatrixHolder &holder, mitk::GreyLevelSizeZoneFeatures & results ) { auto SgzMatrix = holder.m_Matrix; auto pgzMatrix = holder.m_Matrix; auto pgMatrix = holder.m_Matrix; auto pzMatrix = holder.m_Matrix; double Ns = pgzMatrix.sum(); pgzMatrix /= Ns; pgMatrix.rowwise().normalize(); pzMatrix.colwise().normalize(); for (int i = 0; i < holder.m_NumberOfBins; ++i) for (int j = 0; j < holder.m_NumberOfBins; ++j) { if (pgzMatrix(i, j) != pgzMatrix(i, j)) pgzMatrix(i, j) = 0; if (pgMatrix(i, j) != pgMatrix(i, j)) pgMatrix(i, j) = 0; if (pzMatrix(i, j) != pzMatrix(i, j)) pzMatrix(i, j) = 0; } Eigen::VectorXd SgVector = SgzMatrix.rowwise().sum(); Eigen::VectorXd SzVector = SgzMatrix.colwise().sum(); for (int j = 0; j < SzVector.size(); ++j) { results.SmallZoneEmphasis += SzVector(j) / (j + 1) / (j + 1); results.LargeZoneEmphasis += SzVector(j) * (j + 1.0) * (j + 1.0); results.ZoneSizeNonUniformity += SzVector(j) * SzVector(j); results.ZoneSizeNoneUniformityNormalized += SzVector(j) * SzVector(j); } for (int i = 0; i < SgVector.size(); ++i) { results.LowGreyLevelEmphasis += SgVector(i) / (i + 1) / (i + 1); results.HighGreyLevelEmphasis += SgVector(i) * (i + 1) * (i + 1); results.GreyLevelNonUniformity += SgVector(i)*SgVector(i); results.GreyLevelNonUniformityNormalized += SgVector(i)*SgVector(i); } for (int i = 0; i < SgzMatrix.rows(); ++i) { for (int j = 0; j < SgzMatrix.cols(); ++j) { results.SmallZoneLowGreyLevelEmphasis += SgzMatrix(i, j) / (i + 1) / (i + 1) / (j + 1) / (j + 1); results.SmallZoneHighGreyLevelEmphasis += SgzMatrix(i, j) * (i + 1) * (i + 1) / (j + 1) / (j + 1); results.LargeZoneLowGreyLevelEmphasis += SgzMatrix(i, j) / (i + 1) / (i + 1) * (j + 1.0) * (j + 1.0); results.LargeZoneHighGreyLevelEmphasis += SgzMatrix(i, j) * (i + 1) * (i + 1) * (j + 1.0) * (j + 1.0); results.ZonePercentage += SgzMatrix(i, j)*(j + 1); results.GreyLevelMean += (i + 1)*pgzMatrix(i, j); results.ZoneSizeMean += (j + 1)*pgzMatrix(i, j); if (pgzMatrix(i, j) > 0) results.ZoneSizeEntropy -= pgzMatrix(i, j) * std::log(pgzMatrix(i, j)) / std::log(2); } } for (int i = 0; i < SgzMatrix.rows(); ++i) { for (int j = 0; j < SgzMatrix.cols(); ++j) { results.GreyLevelVariance += (i + 1 - results.GreyLevelMean)*(i + 1 - results.GreyLevelMean)*pgzMatrix(i, j); results.ZoneSizeVariance += (j + 1 - results.ZoneSizeMean)*(j + 1 - results.ZoneSizeMean)*pgzMatrix(i, j); } } results.SmallZoneEmphasis /= Ns; results.LargeZoneEmphasis /= Ns; results.LowGreyLevelEmphasis /= Ns; results.HighGreyLevelEmphasis /= Ns; results.SmallZoneLowGreyLevelEmphasis /= Ns; results.SmallZoneHighGreyLevelEmphasis /= Ns; results.LargeZoneLowGreyLevelEmphasis /= Ns; results.LargeZoneHighGreyLevelEmphasis /= Ns; results.GreyLevelNonUniformity /= Ns; results.GreyLevelNonUniformityNormalized /= Ns*Ns; results.ZoneSizeNonUniformity /= Ns; results.ZoneSizeNoneUniformityNormalized /= Ns*Ns; results.ZonePercentage = Ns / results.ZonePercentage; } template -void +static void CalculateGreyLevelSizeZoneFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFGreyLevelSizeZone::FeatureListType & featureList, mitk::GIFGreyLevelSizeZone::GIFGreyLevelSizeZoneConfiguration config) { typedef itk::Image ImageType; - typedef itk::Image MaskType; - typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; + typedef itk::Image MaskType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// - - typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); - minMaxComputer->SetImage(itkImage); - minMaxComputer->Compute(); - - double rangeMin = -0.5 + minMaxComputer->GetMinimum(); - double rangeMax = 0.5 + minMaxComputer->GetMaximum(); - - if (config.UseMinimumIntensity) - rangeMin = config.MinimumIntensity; - if (config.UseMaximumIntensity) - rangeMax = config.MaximumIntensity; - - // Define Range + 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); MITK_INFO << offset; } } if (config.direction == 1) { offsetVector.clear(); offset[0] = 0; offset[1] = 0; offset[2] = 1; offsetVector.push_back(offset); } std::vector resultVector; mitk::GreyLevelSizeZoneMatrixHolder tmpHolder(rangeMin, rangeMax, numberOfBins, 3); int largestRegion = CalculateGlSZMatrix(itkImage, maskImage, offsetVector, true, tmpHolder); mitk::GreyLevelSizeZoneMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins,largestRegion); mitk::GreyLevelSizeZoneFeatures overallFeature; CalculateGlSZMatrix(itkImage, maskImage, offsetVector, false, holderOverall); CalculateFeatures(holderOverall, overallFeature); - std::stringstream ss; - ss << config.range; - std::string strRange = ss.str(); - MatrixFeaturesTo(overallFeature, "Grey Level Size Zone (" + strRange + ")", featureList); + MatrixFeaturesTo(overallFeature, "Grey Level Size Zone::", featureList); } static void MatrixFeaturesTo(mitk::GreyLevelSizeZoneFeatures features, std::string prefix, mitk::GIFGreyLevelSizeZone::FeatureListType &featureList) { - featureList.push_back(std::make_pair(prefix + " Small Zone Emphasis", features.SmallZoneEmphasis)); - featureList.push_back(std::make_pair(prefix + " Large Zone Emphasis", features.LargeZoneEmphasis)); - featureList.push_back(std::make_pair(prefix + " Low Grey Level Emphasis", features.LowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + " High Grey Level Emphasis", features.HighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + " Small Zone Low Grey LEvel Emphasis", features.SmallZoneLowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + " Small Zone High Grey LEvel Emphasis", features.SmallZoneHighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + " Large Zone Low Grey Level Emphasis", features.LargeZoneLowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + " Large Zone High Grey Level Emphasis", features.LargeZoneHighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + " Grey Level Non-Uniformity", features.GreyLevelNonUniformity)); - featureList.push_back(std::make_pair(prefix + " Grey Level Non-Uniformity Normalized", features.GreyLevelNonUniformityNormalized)); - featureList.push_back(std::make_pair(prefix + " Zone Size Non-Uniformity", features.ZoneSizeNonUniformity)); - featureList.push_back(std::make_pair(prefix + " Zone Size Non-Uniformity Normalized", features.ZoneSizeNoneUniformityNormalized)); - featureList.push_back(std::make_pair(prefix + " Zone Percentage", features.ZonePercentage)); - featureList.push_back(std::make_pair(prefix + " Grey Level Mean", features.GreyLevelMean)); - featureList.push_back(std::make_pair(prefix + " Grey Level Variance", features.GreyLevelVariance)); - featureList.push_back(std::make_pair(prefix + " Zone Size Mean", features.ZoneSizeMean)); - featureList.push_back(std::make_pair(prefix + " Zone Size Variance", features.ZoneSizeVariance)); - featureList.push_back(std::make_pair(prefix + " Zone Size Entropy", features.ZoneSizeEntropy)); + featureList.push_back(std::make_pair(prefix + "Small Zone Emphasis", features.SmallZoneEmphasis)); + featureList.push_back(std::make_pair(prefix + "Large Zone Emphasis", features.LargeZoneEmphasis)); + featureList.push_back(std::make_pair(prefix + "Low Grey Level Emphasis", features.LowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + "High Grey Level Emphasis", features.HighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + "Small Zone Low Grey Level Emphasis", features.SmallZoneLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + "Small Zone High Grey Level Emphasis", features.SmallZoneHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + "Large Zone Low Grey Level Emphasis", features.LargeZoneLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + "Large Zone High Grey Level Emphasis", features.LargeZoneHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + "Grey Level Non-Uniformity", features.GreyLevelNonUniformity)); + featureList.push_back(std::make_pair(prefix + "Grey Level Non-Uniformity Normalized", features.GreyLevelNonUniformityNormalized)); + featureList.push_back(std::make_pair(prefix + "Zone Size Non-Uniformity", features.ZoneSizeNonUniformity)); + featureList.push_back(std::make_pair(prefix + "Zone Size Non-Uniformity Normalized", features.ZoneSizeNoneUniformityNormalized)); + featureList.push_back(std::make_pair(prefix + "Zone Percentage", features.ZonePercentage)); + featureList.push_back(std::make_pair(prefix + "Grey Level Mean", features.GreyLevelMean)); + featureList.push_back(std::make_pair(prefix + "Grey Level Variance", features.GreyLevelVariance)); + featureList.push_back(std::make_pair(prefix + "Zone Size Mean", features.ZoneSizeMean)); + featureList.push_back(std::make_pair(prefix + "Zone Size Variance", features.ZoneSizeVariance)); + featureList.push_back(std::make_pair(prefix + "Zone Size Entropy", features.ZoneSizeEntropy)); } - mitk::GIFGreyLevelSizeZone::GIFGreyLevelSizeZone() : - m_Range(1.0), m_Bins(128) + mitk::GIFGreyLevelSizeZone::GIFGreyLevelSizeZone() { SetShortName("glsz"); - SetLongName("sizezone"); + SetLongName("grey-level-sizezone"); } mitk::GIFGreyLevelSizeZone::FeatureListType mitk::GIFGreyLevelSizeZone::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { + InitializeQuantifier(image, mask); + FeatureListType featureList; GIFGreyLevelSizeZoneConfiguration config; config.direction = GetDirection(); - config.range = m_Range; - config.MinimumIntensity = GetMinimumIntensity(); - config.MaximumIntensity = GetMaximumIntensity(); - config.UseMinimumIntensity = GetUseMinimumIntensity(); - config.UseMaximumIntensity = GetUseMaximumIntensity(); - config.Bins = GetBins(); + config.MinimumIntensity = GetQuantifier()->GetMinimum(); + config.MaximumIntensity = GetQuantifier()->GetMaximum(); + config.Bins = GetQuantifier()->GetBins(); AccessByItk_3(image, CalculateGreyLevelSizeZoneFeatures, mask, featureList, config); return featureList; } mitk::GIFGreyLevelSizeZone::FeatureNameListType mitk::GIFGreyLevelSizeZone::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFGreyLevelSizeZone::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); - parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Grey Level Size Zone", "Calculates the size zone based features.", us::Any()); - parser.addArgument(name+"::range", name+"::range", mitkCommandLineParser::String, "Cooc 2 Range", "Define the range that is used (Semicolon-separated)", us::Any()); - parser.addArgument(name + "::bins", name + "::bins", mitkCommandLineParser::String, "Cooc 2 Number of Bins", "Define the number of bins that is used ", us::Any()); + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Grey Level Size Zone", "Calculates the size zone based features.", us::Any()); + AddQuantifierArguments(parser); } void mitk::GIFGreyLevelSizeZone::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())) { - std::vector ranges; - if (parsedArgs.count(name + "::range")) - { - ranges = SplitDouble(parsedArgs[name + "::range"].ToString(), ';'); - } - else - { - ranges.push_back(1); - } - if (parsedArgs.count(name + "::bins")) - { - auto bins = SplitDouble(parsedArgs[name + "::bins"].ToString(), ';')[0]; - this->SetBins(bins); - } + InitializeQuantifierFromParameters(feature, maskNoNAN); - 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] << "...."; - } + MITK_INFO << "Start calculating Grey leve size zone ..."; + auto localResults = this->CalculateFeatures(feature, maskNoNAN); + featureList.insert(featureList.end(), localResults.begin(), localResults.end()); + MITK_INFO << "Finished calculating Grey level size zone ..."; } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp index fbdd915ccd..88a07ee7c0 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp @@ -1,190 +1,178 @@ /*=================================================================== 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 template -void -CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFImageDescriptionFeatures::FeatureListType & featureList, mitk::GIFImageDescriptionFeatures::ParameterStruct params) +static void +CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFImageDescriptionFeatures::FeatureListType & featureList) { typedef itk::Image ImageType; - typedef itk::Image MaskType; + typedef itk::Image MaskType; typedef itk::LabelStatisticsImageFilter FilterType; typedef typename FilterType::HistogramType HistogramType; typedef typename HistogramType::IndexType HIndexType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); unsigned int imageDimensionX = itkImage->GetLargestPossibleRegion().GetSize()[0]; unsigned int imageDimensionY = itkImage->GetLargestPossibleRegion().GetSize()[1]; unsigned int imageDimensionZ = itkImage->GetLargestPossibleRegion().GetSize()[2]; double imageVoxelSpacingX = itkImage->GetSpacing()[0]; double imageVoxelSpacingY = itkImage->GetSpacing()[1]; double imageVoxelSpacingZ = itkImage->GetSpacing()[2]; typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); minMaxComputer->SetImage(itkImage); minMaxComputer->Compute(); double imageMinimum = minMaxComputer->GetMinimum(); double imageMaximum = minMaxComputer->GetMaximum(); unsigned int maskDimensionX = maskImage->GetLargestPossibleRegion().GetSize()[0]; unsigned int maskDimensionY = maskImage->GetLargestPossibleRegion().GetSize()[1]; unsigned int maskDimensionZ = maskImage->GetLargestPossibleRegion().GetSize()[2]; double maskVoxelSpacingX = maskImage->GetSpacing()[0]; double maskVoxelSpacingY = maskImage->GetSpacing()[1]; double maskVoxelSpacingZ = maskImage->GetSpacing()[2]; unsigned int voxelCount = 0; unsigned int maskVoxelCount = 0; double maskMinimum = imageMaximum; double maskMaximum = imageMinimum; double imageMean = 0; double maskMean = 0; unsigned int maskMinimumX = maskDimensionX; unsigned int maskMaximumX = 0; unsigned int maskMinimumY = maskDimensionY; unsigned int maskMaximumY = 0; unsigned int maskMinimumZ = maskDimensionZ; unsigned int maskMaximumZ = 0; itk::ImageRegionConstIteratorWithIndex imIter(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex maIter(maskImage, maskImage->GetLargestPossibleRegion()); while (!imIter.IsAtEnd()) { auto pixelValue = imIter.Get(); if (maIter.Get() > 0) { ++maskVoxelCount; maskMean += pixelValue; maskMinimum = (maskMinimum > pixelValue) ? pixelValue : maskMinimum; maskMaximum = (maskMaximum < pixelValue) ? pixelValue : maskMaximum; maskMinimumX = (maskMinimumX > imIter.GetIndex()[0]) ? imIter.GetIndex()[0] : maskMinimumX; maskMaximumX = (maskMaximumX < imIter.GetIndex()[0]) ? imIter.GetIndex()[0] : maskMaximumX; maskMinimumY = (maskMinimumY > imIter.GetIndex()[1]) ? imIter.GetIndex()[1] : maskMinimumY; maskMaximumY = (maskMaximumY < imIter.GetIndex()[1]) ? imIter.GetIndex()[1] : maskMaximumY; maskMinimumZ = (maskMinimumZ > imIter.GetIndex()[2]) ? imIter.GetIndex()[2] : maskMinimumZ; maskMaximumZ = (maskMaximumZ < imIter.GetIndex()[2]) ? imIter.GetIndex()[2] : maskMaximumZ; } ++voxelCount; imageMean += pixelValue; ++imIter; ++maIter; } imageMean /= voxelCount; maskMean /= maskVoxelCount; featureList.push_back(std::make_pair("Diagnostic (Image)::Dimension X", imageDimensionX)); featureList.push_back(std::make_pair("Diagnostic (Image)::Dimension Y", imageDimensionY)); featureList.push_back(std::make_pair("Diagnostic (Image)::Dimension Z", imageDimensionZ)); featureList.push_back(std::make_pair("Diagnostic (Image)::Spacing X", imageVoxelSpacingX)); featureList.push_back(std::make_pair("Diagnostic (Image)::Spacing Y", imageVoxelSpacingY)); featureList.push_back(std::make_pair("Diagnostic (Image)::Spacing Z", imageVoxelSpacingZ)); - featureList.push_back(std::make_pair("Diagnostic (Image)::Mean Intensity", imageMean)); - featureList.push_back(std::make_pair("Diagnostic (Image)::Minimum Intensity", imageMinimum)); - featureList.push_back(std::make_pair("Diagnostic (Image)::Maximum Intensity", imageMaximum)); + featureList.push_back(std::make_pair("Diagnostic (Image)::Mean intensity", imageMean)); + featureList.push_back(std::make_pair("Diagnostic (Image)::Minimum intensity", imageMinimum)); + featureList.push_back(std::make_pair("Diagnostic (Image)::Maximum intensity", imageMaximum)); featureList.push_back(std::make_pair("Diagnostic (Mask)::Dimension X", maskDimensionX)); featureList.push_back(std::make_pair("Diagnostic (Mask)::Dimension Y", maskDimensionY)); featureList.push_back(std::make_pair("Diagnostic (Mask)::Dimension Z", maskDimensionZ)); - featureList.push_back(std::make_pair("Diagnostic (Mask)::Mask Bounding Box X", maskMaximumX - maskMinimumX + 1)); - featureList.push_back(std::make_pair("Diagnostic (Mask)::Mask Bounding Box Y", maskMaximumY - maskMinimumY + 1)); - featureList.push_back(std::make_pair("Diagnostic (Mask)::Mask Bounding Box Z", maskMaximumZ - maskMinimumZ + 1)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Mask bounding box X", maskMaximumX - maskMinimumX + 1)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Mask bounding box Y", maskMaximumY - maskMinimumY + 1)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Mask bounding box Z", maskMaximumZ - maskMinimumZ + 1)); featureList.push_back(std::make_pair("Diagnostic (Mask)::Spacing X", maskVoxelSpacingX)); featureList.push_back(std::make_pair("Diagnostic (Mask)::Spacing Y", maskVoxelSpacingY)); featureList.push_back(std::make_pair("Diagnostic (Mask)::Spacing Z", maskVoxelSpacingZ)); featureList.push_back(std::make_pair("Diagnostic (Mask)::Voxel Count ", maskVoxelCount)); - featureList.push_back(std::make_pair("Diagnostic (Mask)::Mean Intensity", maskMean)); - featureList.push_back(std::make_pair("Diagnostic (Mask)::Minimum Intensity", maskMinimum)); - featureList.push_back(std::make_pair("Diagnostic (Mask)::Maximum Intensity", maskMaximum)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Mean intensity", maskMean)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Minimum intensity", maskMinimum)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Maximum intensity", maskMaximum)); } -mitk::GIFImageDescriptionFeatures::GIFImageDescriptionFeatures() : -m_HistogramSize(256), m_UseCtRange(false) +mitk::GIFImageDescriptionFeatures::GIFImageDescriptionFeatures() { SetShortName("id"); SetLongName("image-diagnostic"); } mitk::GIFImageDescriptionFeatures::FeatureListType mitk::GIFImageDescriptionFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; - - ParameterStruct params; - params.m_HistogramSize = this->m_HistogramSize; - params.m_UseCtRange = this->m_UseCtRange; - - params.MinimumIntensity = GetMinimumIntensity(); - params.MaximumIntensity = GetMaximumIntensity(); - params.UseMinimumIntensity = GetUseMinimumIntensity(); - params.UseMaximumIntensity = GetUseMaximumIntensity(); - params.Bins = GetBins(); - - AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, params); + AccessByItk_2(image, CalculateFirstOrderStatistics, mask, featureList); return featureList; } mitk::GIFImageDescriptionFeatures::FeatureNameListType mitk::GIFImageDescriptionFeatures::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFImageDescriptionFeatures::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); - parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Volume-Statistic", "calculates volume based features", us::Any()); + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Image Description", "calculates image description features", us::Any()); } void mitk::GIFImageDescriptionFeatures::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { - MITK_INFO << "Start calculating first order features ...."; + MITK_INFO << "Start calculating image description features...."; auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); - MITK_INFO << "Finished calculating first order features...."; + MITK_INFO << "Finished calculating image description features...."; } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp index 51ea36dd88..c94b39dfc2 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp @@ -1,159 +1,158 @@ /*=================================================================== 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 // STL #include template static void CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::IntensityQuantifier::Pointer quantifier, mitk::GIFIntensityVolumeHistogramFeatures::FeatureListType & featureList) { int bins = 1000; typedef itk::Image ImageType; - typedef itk::Image MaskType; + typedef itk::Image MaskType; typename MaskType::Pointer itkMask = MaskType::New(); mitk::CastToItkImage(mask, itkMask); itk::ImageRegionConstIterator iter(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIterator iterMask(itkMask, itkMask->GetLargestPossibleRegion()); MITK_INFO << "Quantification: " << quantifier->GetMinimum() << " to " << quantifier->GetMaximum() << " with " << quantifier->GetBins()<< " bins"; iter.GoToBegin(); iterMask.GoToBegin(); std::vector hist; hist.resize(quantifier->GetBins() , 0); int count = 0; while (!iter.IsAtEnd()) { if (iterMask.Get() > 0) { double value = iter.Get(); //std::size_t index = std::floor((value - minimum) / (maximum - minimum) * (bins-1)); std::size_t index = quantifier->IntensityToIndex(value); ++count; hist[index] += 1.0;// / count; } ++iterMask; ++iter; } bool notFoundIntenstiy010 = true; bool notFoundIntenstiy090 = true; double intensity010 = -1; double intensity090 = -1; double fraction = 0; double auc = 0; bool firstRound = true; for (int i = quantifier->GetBins()-1; i >= 0; --i) { hist[i] /= count; hist[i] += fraction; fraction = hist[i]; if (!firstRound) { auc += 0.5 * (hist[i] + hist[i+1]) / (quantifier->GetBins()-1); } firstRound = false; if (notFoundIntenstiy010 && fraction > 0.1) { intensity010 = quantifier->IndexToMeanIntensity(i + 1); notFoundIntenstiy010 = false; } if (notFoundIntenstiy090 && fraction > 0.9) { intensity090 = quantifier->IndexToMeanIntensity(i + 1); notFoundIntenstiy090 = false; } } unsigned int index010 = std::ceil(quantifier->GetBins() * 0.1); unsigned int index090 = std::floor(quantifier->GetBins() * 0.9); - featureList.push_back(std::make_pair("Intensity Volume Histogram Volume fration at 0.10 intensity", hist[index010])); - featureList.push_back(std::make_pair("Intensity Volume Histogram Volume fration at 0.90 intensity", hist[index090])); - featureList.push_back(std::make_pair("Intensity Volume Histogram Intensity at 0.10 volume", intensity010)); - featureList.push_back(std::make_pair("Intensity Volume Histogram Intensity at 0.90 volume", intensity090)); - featureList.push_back(std::make_pair("Intensity Volume Histogram Difference intensity at 0.10 and 0.90 volume", std::abs(hist[index010] - hist[index090]))); - featureList.push_back(std::make_pair("Intensity Volume Histogram Difference intensity at 0.10 and 0.90 volume", std::abs(intensity090 - intensity010))); - featureList.push_back(std::make_pair("Intensity Volume Histogram Area under IVH curve", auc)); + featureList.push_back(std::make_pair("Intensity Volume Histogram::Volume fration at 0.10 intensity", hist[index010])); + featureList.push_back(std::make_pair("Intensity Volume Histogram::Volume fration at 0.90 intensity", hist[index090])); + featureList.push_back(std::make_pair("Intensity Volume Histogram::Intensity at 0.10 volume", intensity010)); + featureList.push_back(std::make_pair("Intensity Volume Histogram::Intensity at 0.90 volume", intensity090)); + featureList.push_back(std::make_pair("Intensity Volume Histogram::Difference volume fration at 0.10 and 0.90 intensity", std::abs(hist[index010] - hist[index090]))); + featureList.push_back(std::make_pair("Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume", std::abs(intensity090 - intensity010))); + featureList.push_back(std::make_pair("Intensity Volume Histogram::Area under IVH curve", auc)); //featureList.push_back(std::make_pair("Local Intensity Global Intensity Peak", globalPeakValue)); } mitk::GIFIntensityVolumeHistogramFeatures::GIFIntensityVolumeHistogramFeatures() { SetLongName("intensity-volume-histogram"); SetShortName("ivoh"); } mitk::GIFIntensityVolumeHistogramFeatures::FeatureListType mitk::GIFIntensityVolumeHistogramFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { + InitializeQuantifier(image, mask, 1000); FeatureListType featureList; AccessByItk_3(image, CalculateIntensityPeak, mask, GetQuantifier(), featureList); return featureList; } mitk::GIFIntensityVolumeHistogramFeatures::FeatureNameListType mitk::GIFIntensityVolumeHistogramFeatures::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFIntensityVolumeHistogramFeatures::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); - parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Local Intensity", "calculates local intensity based features", us::Any()); - + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Local Intensity", "calculates local intensity based features", us::Any()); AddQuantifierArguments(parser); } void mitk::GIFIntensityVolumeHistogramFeatures::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNaN, FeatureListType &featureList) { - InitializeQuantifier(feature, mask, maskNoNaN, featureList,1000); + InitializeQuantifierFromParameters(feature, mask, 1000); auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { 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...."; } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp index 56c4575e55..ac5e25cb30 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp @@ -1,150 +1,159 @@ /*=================================================================== 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 // STL #include template static void -CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFLocalIntensity::FeatureListType & featureList) +CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFLocalIntensity::FeatureListType & featureList, double range) { typedef itk::Image ImageType; - typedef itk::Image MaskType; + typedef itk::Image MaskType; typename MaskType::Pointer itkMask = MaskType::New(); mitk::CastToItkImage(mask, itkMask); double minimumSpacing = std::numeric_limits::max(); itkImage->GetSpacing(); for (int i = 0; i < VImageDimension; ++i) { minimumSpacing = (minimumSpacing < itkImage->GetSpacing()[i]) ? minimumSpacing : itkImage->GetSpacing()[i]; } ImageType::SizeType regionSize; - int offset = std::ceil(6.2 / minimumSpacing); + int offset = std::ceil(range / minimumSpacing); regionSize.Fill(offset); itk::NeighborhoodIterator iter(regionSize, itkImage, itkImage->GetLargestPossibleRegion()); itk::NeighborhoodIterator iterMask(regionSize, itkMask, itkMask->GetLargestPossibleRegion()); ImageType::PointType origin; ImageType::PointType localPoint; itk::Index index; double tmpPeakValue; double globalPeakValue = 0; double localPeakValue = 0; TPixel localMaximum = 0; int count = 0; while (!iter.IsAtEnd()) { if (iterMask.GetCenterPixel() > 0) { tmpPeakValue = 0; count = 0; index = iter.GetIndex(); itkImage->TransformIndexToPhysicalPoint(index, origin); for (int i = 0; i < iter.Size(); ++i) { itkImage->TransformIndexToPhysicalPoint(iter.GetIndex(i), localPoint); double dist = origin.EuclideanDistanceTo(localPoint); if (dist < 6.2) { if (iter.IndexInBounds(i)) { tmpPeakValue += iter.GetPixel(i); ++count; } } } tmpPeakValue /= count; globalPeakValue = std::max(tmpPeakValue, globalPeakValue); if (localMaximum == iter.GetCenterPixel()) { localPeakValue = std::max(tmpPeakValue,localPeakValue); } else if (localMaximum < iter.GetCenterPixel()) { localMaximum = iter.GetCenterPixel(); localPeakValue = tmpPeakValue; } } ++iterMask; ++iter; } - featureList.push_back(std::make_pair("Local Intensity Local Intensity Peak", localPeakValue)); - featureList.push_back(std::make_pair("Local Intensity Global Intensity Peak", globalPeakValue)); + featureList.push_back(std::make_pair("Local Intensity::Local Intensity Peak", localPeakValue)); + featureList.push_back(std::make_pair("Local Intensity::Global Intensity Peak", globalPeakValue)); } -mitk::GIFLocalIntensity::GIFLocalIntensity() +mitk::GIFLocalIntensity::GIFLocalIntensity() : +m_Range(6.2) { SetLongName("local-intensity"); SetShortName("loci"); } mitk::GIFLocalIntensity::FeatureListType mitk::GIFLocalIntensity::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; if (image->GetDimension() < 3) { return featureList; } - AccessByItk_2(image, CalculateIntensityPeak, mask, featureList); + double range = GetRange(); + AccessByItk_3(image, CalculateIntensityPeak, mask, featureList, range); 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::String, "Use Local Intensity", "calculates local intensity based features", us::Any()); + 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...."; } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp index dd3b6d5722..4a19d344b5 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp @@ -1,190 +1,202 @@ /*=================================================================== 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 // STL #include template static void -CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::IntensityQuantifier::Pointer quantifier, mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::FeatureListType & featureList) +CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::NGTDFeatures params, mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::FeatureListType & featureList) { typedef itk::Image ImageType; - typedef itk::Image MaskType; + typedef itk::Image MaskType; typename MaskType::Pointer itkMask = MaskType::New(); mitk::CastToItkImage(mask, itkMask); ImageType::SizeType regionSize; - regionSize.Fill(1); + regionSize.Fill(params.Range); itk::NeighborhoodIterator iter(regionSize, itkImage, itkImage->GetLargestPossibleRegion()); itk::NeighborhoodIterator iterMask(regionSize, itkMask, itkMask->GetLargestPossibleRegion()); std::vector pVector; std::vector sVector; - pVector.resize(quantifier->GetBins(), 0); - sVector.resize(quantifier->GetBins(), 0); + pVector.resize(params.quantifier->GetBins(), 0); + sVector.resize(params.quantifier->GetBins(), 0); int count = 0; while (!iter.IsAtEnd()) { if (iterMask.GetCenterPixel() > 0) { int localCount = 0; double localMean = 0; - unsigned int localIndex = quantifier->IntensityToIndex(iter.GetCenterPixel()); + unsigned int localIndex = params.quantifier->IntensityToIndex(iter.GetCenterPixel()); for (int i = 0; i < iter.Size(); ++i) { if (i == (iter.Size() / 2)) continue; if (iterMask.GetPixel(i) > 0) { ++localCount; - localMean += quantifier->IntensityToIndex(iter.GetPixel(i))+1; + localMean += params.quantifier->IntensityToIndex(iter.GetPixel(i)) + 1; } } if (localCount > 0) { localMean /= localCount; } localMean = std::abs(localIndex + 1 - localMean); pVector[localIndex] += 1; sVector[localIndex] += localMean; ++count; } ++iterMask; ++iter; } unsigned int Ngp = 0; - for (unsigned int i = 0; i < quantifier->GetBins(); ++i) + for (unsigned int i = 0; i < params.quantifier->GetBins(); ++i) { if (pVector[i] > 0.1) { ++Ngp; } pVector[i] /= count; } double sumS = 0; double sumStimesP = 0; double contrastA = 0; double busynessA = 0; double complexity = 0; double strengthA = 0; - for (unsigned int i = 0; i < quantifier->GetBins(); ++i) + for (unsigned int i = 0; i < params.quantifier->GetBins(); ++i) { sumS += sVector[i]; sumStimesP += pVector[i] * sVector[i]; - for (unsigned int j = 0; j < quantifier->GetBins(); ++j) + for (unsigned int j = 0; j < params.quantifier->GetBins(); ++j) { double iMinusj = 1.0*i - 1.0*j; contrastA += pVector[i] * pVector[j] * iMinusj*iMinusj; if ((pVector[i] > 0) && (pVector[j] > 0)) { busynessA += std::abs((i + 1.0)*pVector[i] - (j + 1.0)*pVector[j]); complexity += std::abs(iMinusj)*(pVector[i] * sVector[i] + pVector[j] * sVector[j]) / (pVector[i] + pVector[j]); strengthA += (pVector[i] + pVector[j])*iMinusj*iMinusj; } } } double coarsness = 1.0 / std::min(sumStimesP, 1000000); double contrast = 0; double busyness = 0; if (Ngp > 1) { contrast = contrastA / Ngp / (Ngp - 1) / count * sumS; busyness = sumStimesP / busynessA; } complexity /= count; double strength = 0; if (sumS > 0) { strength = strengthA / sumS; } - featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference Coarsness", coarsness)); - featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference Contrast", contrast)); - featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference Busyness", busyness)); - featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference Complexity", complexity)); - featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference Strength", strength)); + featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference::Coarsness", coarsness)); + featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference::Contrast", contrast)); + featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference::Busyness", busyness)); + featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference::Complexity", complexity)); + featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference::Strength", strength)); } -mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::GIFNeighbourhoodGreyToneDifferenceFeatures() +mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::GIFNeighbourhoodGreyToneDifferenceFeatures() : +m_Range(1) { SetLongName("neighbourhood-grey-tone-difference"); SetShortName("ngtd"); } mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::FeatureListType mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; - //if (image->GetDimension() < 3) - //{ - // return featureList; - //} - AccessByItk_3(image, CalculateIntensityPeak, mask, GetQuantifier(), featureList); + + InitializeQuantifierFromParameters(image, mask); + + NGTDFeatures params; + params.Range = GetRange(); + params.quantifier = GetQuantifier(); + + AccessByItk_3(image, CalculateIntensityPeak, mask, params, featureList); return featureList; } mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::FeatureNameListType mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::AddArguments(mitkCommandLineParser &parser) { AddQuantifierArguments(parser); std::string name = GetOptionPrefix(); - parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Local Intensity", "calculates local intensity based features", us::Any()); + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Neighbourhood Grey Tone Difference", "calculates Neighborhood Grey Tone based features", us::Any()); + parser.addArgument(name + "::range", name + "::range", mitkCommandLineParser::Int, "Range for the local intensity", "Give the range that should be used for the local intensity in mm", us::Any()); + } void mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNaN, FeatureListType &featureList) { - InitializeQuantifier(feature, mask, maskNoNaN, featureList); + InitializeQuantifierFromParameters(feature, mask); + std::string name = GetOptionPrefix(); auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { - MITK_INFO << "Start calculating local intensity features ...."; + MITK_INFO << "Start calculating Neighbourhood Grey Tone Difference features ...."; + if (parsedArgs.count(name + "::range")) + { + int range = us::any_cast(parsedArgs[name + "::range"]); + this->SetRange(range); + } auto localResults = this->CalculateFeatures(feature, mask); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); - MITK_INFO << "Finished calculating local intensity features...."; + MITK_INFO << "Finished calculating Neighbourhood Grey Tone Difference features...."; } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp index d870dc16bd..a0151b1f42 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp @@ -1,528 +1,515 @@ /*=================================================================== 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 -#include - #include +#include +#include +#include // STL -#include +#include #include -// OpenCV -#include - // Eigen #include template void CalculateVolumeDensityStatistic(itk::Image* itkImage, mitk::Image::Pointer mask, double volume, mitk::GIFVolumetricDensityStatistics::FeatureListType & featureList) { typedef itk::Image ImageType; - typedef itk::Image MaskType; + typedef itk::Image MaskType; typedef itk::LabelGeometryImageFilter FilterType; 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; ImageType::PointType pointA; 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; } - featureList.push_back(std::make_pair("Morphological Density Volume Integrated Intensity", volume* mean)); - featureList.push_back(std::make_pair("Morphological Density Volume Moran's I Index", Nv / w_ij * moranA / moranB)); - featureList.push_back(std::make_pair("Morphological Density Volume Geary's C measure", ( Nv -1 ) / 2 / w_ij * geary/ moranB)); + featureList.push_back(std::make_pair("Morphological Density::Volume integrated intensity", volume* mean)); + featureList.push_back(std::make_pair("Morphological Density::Volume Moran's I index", Nv / w_ij * moranA / moranB)); + featureList.push_back(std::make_pair("Morphological Density::Volume Geary's C measure", ( Nv -1 ) / 2 / w_ij * geary/ moranB)); } void calculateMOBB(vtkPointSet *pointset, double &volume, double &surface) { auto cell = pointset->GetCell(0); - volume = 10000000000000000000; + 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 = 1000000000000000; - double curMaxX = -10000000000000000; - double curMinY = 1000000000000000; - double curMaxY = -10000000000000000; - double curMinZ = 1000000000000000; - double curMaxZ = -10000000000000000; + 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); //std::cout << pointID << " (" << p[0] << "|" << p[1] << "|" << p[2] << ") (" << p2[0] << "|" << p2[1] << "|" << p2[2] << ")" << std::endl; } 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.0000001) { // 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]; 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) = p[3]; } 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; } - - //AccessByItk_2(mask, CalculateLargestDiameter, image, featureList); - 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->SetInputData(mask->GetVtkImageData()); delaunay->SetAlpha(0); delaunay->Update(); vtkSmartPointer geometryFilter = vtkSmartPointer::New(); geometryFilter->SetInputConnection(delaunay->GetOutputPort()); geometryFilter->Update(); stats2->SetInputConnection(geometryFilter->GetOutputPort()); stats2->Update(); auto data = mesher->GetOutput()->GetPointData(); 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(); - AccessByItk_3(image, CalculateVolumeDensityStatistic, mask, meshVolume, 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]; - std::vector pointsForPCA; - std::vector pointsForPCAUncorrected; - 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); - cv::Point3d tmp; - tmp.x = x * xd; - tmp.y = y * yd; - tmp.z = z * zd; - pointsForPCAUncorrected.push_back(tmp); if (pxImage == pxImage) { - pointsForPCA.push_back(tmp); + 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); - //Calculate PCA Features - int sz = pointsForPCA.size(); - cv::Mat data_pts = cv::Mat(sz, 3, CV_64FC1); - for (int i = 0; i < data_pts.rows; ++i) - { - data_pts.at(i, 0) = pointsForPCA[i].x; - data_pts.at(i, 1) = pointsForPCA[i].y; - data_pts.at(i, 2) = pointsForPCA[i].z; - } - - //Calculate PCA Features - int szUC = pointsForPCAUncorrected.size(); - cv::Mat data_ptsUC = cv::Mat(szUC, 3, CV_64FC1); - for (int i = 0; i < data_ptsUC.rows; ++i) - { - data_ptsUC.at(i, 0) = pointsForPCAUncorrected[i].x; - data_ptsUC.at(i, 1) = pointsForPCAUncorrected[i].y; - data_ptsUC.at(i, 2) = pointsForPCAUncorrected[i].z; - } + 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(); - //Perform PCA analysis - cv::PCA pca_analysis(data_pts, cv::Mat(), CV_PCA_DATA_AS_ROW); - cv::PCA pca_analysisUC(data_ptsUC, cv::Mat(), CV_PCA_DATA_AS_ROW); + vtkSmartPointer eigenvalues = vtkSmartPointer::New(); + pcaStatistics->GetEigenvalues(eigenvalues); - //Store the eigenvalues std::vector eigen_val(3); - std::vector eigen_valUC(3); - for (int i = 0; i < 3; ++i) - { - eigen_val[i] = pca_analysis.eigenvalues.at(0, i); - eigen_valUC[i] = pca_analysisUC.eigenvalues.at(0, i); - } - - std::sort(eigen_val.begin(), eigen_val.end()); - std::sort(eigen_valUC.begin(), eigen_valUC.end()); + 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("Morphological Density Volume Density axis-aligned bounding box", vd_aabb)); - featureList.push_back(std::make_pair("Morphological Density Surface Density axis-aligned bounding box", ad_aabb)); - featureList.push_back(std::make_pair("Morphological Density Volume Density oriented bounding box", meshVolume / vol_mobb)); - featureList.push_back(std::make_pair("Morphological Density Surface Density oriented bounding box", meshSurf / surf_mobb)); - featureList.push_back(std::make_pair("Morphological Density Volume Density Approx. enclosing ellipsoid", vd_aee)); - featureList.push_back(std::make_pair("Morphological Density Surface Density Approx. enclosing ellipsoid", ad_aee)); - featureList.push_back(std::make_pair("Morphological Density Volume Density Approx. minimum enclosing ellipsoid", meshVolume / vol_mvee)); - featureList.push_back(std::make_pair("Morphological Density Surface Density Approx. minimum enclosing ellipsoid", meshSurf / surf_mvee)); - featureList.push_back(std::make_pair("Morphological Density Volume Density Convex Hull", vd_ch)); - featureList.push_back(std::make_pair("Morphological Density Surface Density Convex Hull", ad_ch)); + featureList.push_back(std::make_pair("Morphological Density::Volume density axis-aligned bounding box", vd_aabb)); + featureList.push_back(std::make_pair("Morphological Density::Surface density axis-aligned bounding box", ad_aabb)); + featureList.push_back(std::make_pair("Morphological Density::Volume density oriented minimum bounding box", meshVolume / vol_mobb)); + featureList.push_back(std::make_pair("Morphological Density::Surface density oriented minimum bounding box", meshSurf / surf_mobb)); + featureList.push_back(std::make_pair("Morphological Density::Volume density approx. enclosing ellipsoid", vd_aee)); + featureList.push_back(std::make_pair("Morphological Density::Surface density approx. enclosing ellipsoid", ad_aee)); + featureList.push_back(std::make_pair("Morphological Density::Volume density approx. minimum volume enclosing ellipsoid", meshVolume / vol_mvee)); + featureList.push_back(std::make_pair("Morphological Density::Surface density approx. minimum volume enclosing ellipsoid", meshSurf / surf_mvee)); + featureList.push_back(std::make_pair("Morphological Density::Volume density convex hull", vd_ch)); + featureList.push_back(std::make_pair("Morphological Density::Surface density convex hull", ad_ch)); return featureList; } mitk::GIFVolumetricDensityStatistics::GIFVolumetricDensityStatistics() { SetLongName("volume-density"); SetShortName("volden"); } 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::String, "Use Volume-Density Statistic", "calculates volume density based features", us::Any()); + 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 091e19c9dd..b69e79541b 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp @@ -1,444 +1,458 @@ /*=================================================================== 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 #include -// OpenCV -#include - template void CalculateVolumeStatistic(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFVolumetricStatistics::FeatureListType & featureList) { 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("Volumetric Features Volume (pixel based)", volume)); - featureList.push_back(std::make_pair("Volumetric Features Voxel Volume", voxelVolume)); + featureList.push_back(std::make_pair("Volumetric Features::Voxel Volume", voxelVolume)); + featureList.push_back(std::make_pair("Volumetric Features::Volume (voxel based)", volume)); } template void CalculateLargestDiameter(itk::Image* mask, mitk::Image::Pointer valueImage, mitk::GIFVolumetricStatistics::FeatureListType & featureList) { 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("Volumetric Features Maximum 3D diameter", longestDiameter)); - featureList.push_back(std::make_pair("Volumetric Features Surface (Voxel based)", surface)); - featureList.push_back(std::make_pair("Volumetric Features Centre of mass shift", differenceOfCenters)); - featureList.push_back(std::make_pair("Volumetric Features Centre of mass shift (Uncorrected)", differenceOfCentersUncorrected)); - featureList.push_back(std::make_pair("Volumetric Features Bounding Box Volume", boundingBoxVolume)); + featureList.push_back(std::make_pair("Volumetric Features::Maximum 3D diameter", longestDiameter)); + featureList.push_back(std::make_pair("Volumetric Features::Surface (voxel based)", surface)); + featureList.push_back(std::make_pair("Volumetric Features::Centre of mass shift", differenceOfCenters)); + featureList.push_back(std::make_pair("Volumetric Features::Centre of mass shift (uncorrected)", differenceOfCentersUncorrected)); + featureList.push_back(std::make_pair("Volumetric Features::Bounding Box Volume", boundingBoxVolume)); } mitk::GIFVolumetricStatistics::GIFVolumetricStatistics() { SetLongName("volume"); SetShortName("vol"); } mitk::GIFVolumetricStatistics::FeatureListType mitk::GIFVolumetricStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; if (image->GetDimension() < 3) { return featureList; } AccessByItk_2(image, CalculateVolumeStatistic, mask, featureList); AccessByItk_2(mask, CalculateLargestDiameter, image, featureList); 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[0].second; double pixelSurface = featureList[3].second; - MITK_INFO << "Surf: " << pixelSurface << " Vol " << pixelVolume; + 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 compactness2Pixel = 36 * pi*pixelVolume*pixelVolume / pixelSurface / pixelSurface / pixelSurface; double compactness3 = pixelVolume / (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 sphericityPixel = std::pow(pi, 1 / 3.0) *std::pow(6 * pixelVolume, 2.0 / 3.0) / pixelSurface; double surfaceToVolume = meshSurf / pixelVolume; double surfaceToVolumePixel = pixelSurface / pixelVolume; double sphericalDisproportion = meshSurf / 4 / pi / std::pow(3.0 / 4.0 / pi * pixelVolume, 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 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]; - std::vector pointsForPCA; - std::vector pointsForPCAUncorrected; + 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) { - cv::Point3d tmp; - tmp.x = x * xd; - tmp.y = y * yd; - tmp.z = z * zd; - pointsForPCAUncorrected.push_back(tmp); + dataset1ArrU->InsertNextValue(x*xd); + dataset2ArrU->InsertNextValue(y*yd); + dataset3ArrU->InsertNextValue(z*zd); if (pxImage == pxImage) { - pointsForPCA.push_back(tmp); + 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); - //Calculate PCA Features - int sz = pointsForPCA.size(); - cv::Mat data_pts = cv::Mat(sz, 3, CV_64FC1); - for (int i = 0; i < data_pts.rows; ++i) - { - data_pts.at(i, 0) = pointsForPCA[i].x; - data_pts.at(i, 1) = pointsForPCA[i].y; - data_pts.at(i, 2) = pointsForPCA[i].z; - } - - //Calculate PCA Features - int szUC = pointsForPCAUncorrected.size(); - cv::Mat data_ptsUC = cv::Mat(szUC, 3, CV_64FC1); - for (int i = 0; i < data_ptsUC.rows; ++i) - { - data_ptsUC.at(i, 0) = pointsForPCAUncorrected[i].x; - data_ptsUC.at(i, 1) = pointsForPCAUncorrected[i].y; - data_ptsUC.at(i, 2) = pointsForPCAUncorrected[i].z; - } - - //Perform PCA analysis - cv::PCA pca_analysis(data_pts, cv::Mat(), CV_PCA_DATA_AS_ROW); - cv::PCA pca_analysisUC(data_ptsUC, cv::Mat(), CV_PCA_DATA_AS_ROW); - - //Store the eigenvalues std::vector eigen_val(3); std::vector eigen_valUC(3); - for (int i = 0; i < 3; ++i) - { - eigen_val[i] = pca_analysis.eigenvalues.at(0, i); - eigen_valUC[i] = pca_analysisUC.eigenvalues.at(0, i); - } + 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); - std::sort(eigen_val.begin(), eigen_val.end()); - std::sort(eigen_valUC.begin(), eigen_valUC.end()); 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]); - - featureList.push_back(std::make_pair("Volumetric Features Volume (mesh based)",meshVolume)); - featureList.push_back(std::make_pair("Volumetric Features Surface area",meshSurf)); - featureList.push_back(std::make_pair("Volumetric Features Surface to volume ratio",surfaceToVolume)); - featureList.push_back(std::make_pair("Volumetric Features Sphericity",sphericity)); - featureList.push_back(std::make_pair("Volumetric Features Asphericity",asphericity)); - featureList.push_back(std::make_pair("Volumetric Features Compactness 1",compactness1)); - featureList.push_back(std::make_pair("Volumetric Features Compactness 2",compactness2)); - featureList.push_back(std::make_pair("Volumetric Features Compactness 3",compactness3)); - featureList.push_back(std::make_pair("Volumetric Features Spherical disproportion", sphericalDisproportion)); - featureList.push_back(std::make_pair("Volumetric Features Surface to volume ratio (Voxel based)", surfaceToVolumePixel)); - featureList.push_back(std::make_pair("Volumetric Features Sphericity (Voxel based)", sphericityPixel)); - featureList.push_back(std::make_pair("Volumetric Features Asphericity (Voxel based)", asphericityPixel)); - featureList.push_back(std::make_pair("Volumetric Features Compactness 1 (Voxel based)", compactness1Pixel)); - featureList.push_back(std::make_pair("Volumetric Features Compactness 2 (Voxel based)", compactness2Pixel)); - featureList.push_back(std::make_pair("Volumetric Features Compactness 3 (Voxel based)", compactness3Pixel)); - featureList.push_back(std::make_pair("Volumetric Features Spherical disproportion (Voxel based)", sphericalDisproportionPixel)); - featureList.push_back(std::make_pair("Volumetric Features PCA Major Axis",major)); - featureList.push_back(std::make_pair("Volumetric Features PCA Minor Axis",minor)); - featureList.push_back(std::make_pair("Volumetric Features PCA Least Axis",least)); - featureList.push_back(std::make_pair("Volumetric Features PCA Elongation",elongation)); - featureList.push_back(std::make_pair("Volumetric Features PCA Flatness",flatness)); - featureList.push_back(std::make_pair("Volumetric Features PCA Major Axis (Uncorrected)", majorUC)); - featureList.push_back(std::make_pair("Volumetric Features PCA Minor Axis (Uncorrected)", minorUC)); - featureList.push_back(std::make_pair("Volumetric Features PCA Least Axis (Uncorrected)", leastUC)); - featureList.push_back(std::make_pair("Volumetric Features PCA Elongation (Uncorrected)", elongationUC)); - featureList.push_back(std::make_pair("Volumetric Features PCA Flatness (Uncorrected)", flatnessUC)); - + featureList.push_back(std::make_pair("Volumetric Features::Volume (mesh based)",meshVolume)); + featureList.push_back(std::make_pair("Volumetric Features::Surface (mesh based)",meshSurf)); + featureList.push_back(std::make_pair("Volumetric Features::Surface to volume ratio (mesh based)",surfaceToVolume)); + featureList.push_back(std::make_pair("Volumetric Features::Sphericity (mesh based)",sphericity)); + featureList.push_back(std::make_pair("Volumetric Features::Asphericity (mesh based)", asphericity)); + featureList.push_back(std::make_pair("Volumetric Features::Compactness 1 (mesh based)", compactness3)); + featureList.push_back(std::make_pair("Volumetric Features::Compactness 1 old (mesh based)" ,compactness1)); + featureList.push_back(std::make_pair("Volumetric Features::Compactness 2 (mesh based)",compactness2)); + featureList.push_back(std::make_pair("Volumetric Features::Spherical disproportion (mesh based)", sphericalDisproportion)); + featureList.push_back(std::make_pair("Volumetric Features::Surface to volume ratio (voxel based)", surfaceToVolumePixel)); + featureList.push_back(std::make_pair("Volumetric Features::Sphericity (voxel based)", sphericityPixel)); + featureList.push_back(std::make_pair("Volumetric Features::Asphericity (voxel based)", asphericityPixel)); + featureList.push_back(std::make_pair("Volumetric Features::Compactness 1 (voxel based)", compactness3Pixel)); + featureList.push_back(std::make_pair("Volumetric Features::Compactness 1 old (voxel based)", compactness1Pixel)); + featureList.push_back(std::make_pair("Volumetric Features::Compactness 2 (voxel based)", compactness2Pixel)); + featureList.push_back(std::make_pair("Volumetric Features::Spherical disproportion (voxel based)", sphericalDisproportionPixel)); + featureList.push_back(std::make_pair("Volumetric Features::PCA Major axis length",major)); + featureList.push_back(std::make_pair("Volumetric Features::PCA Minor axis length",minor)); + featureList.push_back(std::make_pair("Volumetric Features::PCA Least axis length",least)); + featureList.push_back(std::make_pair("Volumetric Features::PCA Elongation",elongation)); + featureList.push_back(std::make_pair("Volumetric Features::PCA Flatness",flatness)); + featureList.push_back(std::make_pair("Volumetric Features::PCA Major axis length (uncorrected)", majorUC)); + featureList.push_back(std::make_pair("Volumetric Features::PCA Minor axis length (uncorrected)", minorUC)); + featureList.push_back(std::make_pair("Volumetric Features::PCA Least axis length (uncorrected)", leastUC)); + featureList.push_back(std::make_pair("Volumetric Features::PCA Elongation (uncorrected)", elongationUC)); + featureList.push_back(std::make_pair("Volumetric Features::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::String, "Use Volume-Statistic", "calculates volume based features", us::Any()); + 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 ...."; + 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/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp b/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp index bda60124ab..b2204c986a 100644 --- a/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp +++ b/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp @@ -1,214 +1,215 @@ /*=================================================================== 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 bool fileExists(const std::string& filename) { std::ifstream infile(filename.c_str()); bool isGood = infile.good(); infile.close(); return isGood; } void mitk::cl::GlobalImageFeaturesParameter::AddParameter(mitkCommandLineParser &parser) { // Required Parameter parser.addArgument("image", "i", mitkCommandLineParser::InputImage, "Input Image", "Path to the input image file", us::Any(), false); parser.addArgument("mask", "m", mitkCommandLineParser::InputImage, "Input Mask", "Path to the mask Image that specifies the area over for the statistic (Values = 1)", us::Any(), false); parser.addArgument("morph-mask", "morph", mitkCommandLineParser::InputImage, "Morphological Image Mask", "Path to the mask Image that specifies the area over for the statistic (Values = 1)", us::Any()); parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output text file", "Path to output file. The output statistic is appended to this file.", us::Any(), false); // Optional Parameter parser.addArgument("logfile", "log", mitkCommandLineParser::InputFile, "Text Logfile", "Path to the location of the target log file. ", us::Any()); parser.addArgument("save-image", "save-image", mitkCommandLineParser::OutputFile, "Output Image", "If spezified, the image that is used for the analysis is saved to this location.", us::Any()); parser.addArgument("save-mask", "save-mask", mitkCommandLineParser::OutputFile, "Output Image", "If spezified, the mask that is used for the analysis is saved to this location. ", us::Any()); parser.addArgument("save-image-screenshots", "save-screenshot", mitkCommandLineParser::OutputFile, "Output Image", "If spezified, a screenshot of each slice is saved. Specify an EXISTING folder with prefix (for example ~/demo/ or ~/demo/image-", us::Any()); parser.addArgument("header", "head", mitkCommandLineParser::Bool, "Add Header (Labels) to output", "", us::Any()); parser.addArgument("first-line-header", "fl-head", mitkCommandLineParser::Bool, "Add Header (Labels) to first line of output", "", us::Any()); parser.addArgument("decimal-point", "decimal", mitkCommandLineParser::String, "Decima Point that is used in Conversion", "", us::Any()); parser.addArgument("resample-mask", "rm", mitkCommandLineParser::Bool, "Bool", "Resamples the mask to the resolution of the input image ", us::Any()); parser.addArgument("same-space", "sp", mitkCommandLineParser::Bool, "Bool", "Set the spacing of all images to equal. Otherwise an error will be thrown. ", us::Any()); parser.addArgument("fixed-isotropic", "fi", mitkCommandLineParser::Float, "Float", "Input image resampled to fixed isotropic resolution given in mm. Should be used with resample-mask ", us::Any()); parser.addArgument("minimum-intensity", "minimum", mitkCommandLineParser::Float, "Float", "Minimum intensity. If set, it is overwritten by more specific intensity minima", us::Any()); parser.addArgument("maximum-intensity", "maximum", mitkCommandLineParser::Float, "Float", "Maximum intensity. If set, it is overwritten by more specific intensity maxima", us::Any()); parser.addArgument("bins", "bins", mitkCommandLineParser::Int, "Int", "Number of bins if bins are used. If set, it is overwritten by more specific bin count", us::Any()); parser.addArgument("binsize", "binsize", mitkCommandLineParser::Float, "Int", "Size of bins that is used. If set, it is overwritten by more specific bin count", us::Any()); + parser.addArgument("ignore-mask-for-histogram", "ignore-mask", mitkCommandLineParser::Bool, "Bool", "If the whole image is used to calculate the histogram. ", us::Any()); } void mitk::cl::GlobalImageFeaturesParameter::ParseParameter(std::map parsedArgs) { ParseFileLocations(parsedArgs); ParseAdditionalOutputs(parsedArgs); ParseHeaderInformation(parsedArgs); ParseMaskAdaptation(parsedArgs); ParseGlobalFeatureParameter(parsedArgs); } void mitk::cl::GlobalImageFeaturesParameter::ParseFileLocations(std::map &parsedArgs) { // // Read input and output file informations // imagePath = parsedArgs["image"].ToString(); maskPath = parsedArgs["mask"].ToString(); outputPath = parsedArgs["output"].ToString(); imageFolder = itksys::SystemTools::GetFilenamePath(imagePath); imageName = itksys::SystemTools::GetFilenameName(imagePath); maskFolder = itksys::SystemTools::GetFilenamePath(maskPath); maskName = itksys::SystemTools::GetFilenameName(maskPath); useMorphMask = false; if (parsedArgs.count("morph-mask")) { useMorphMask = true; morphPath = parsedArgs["morph-mask"].ToString(); morphName = itksys::SystemTools::GetFilenameName(morphPath); } } void mitk::cl::GlobalImageFeaturesParameter::ParseAdditionalOutputs(std::map &parsedArgs) { // // Read input and output file informations // useLogfile = false; if (parsedArgs.count("logfile")) { useLogfile = true; logfilePath = us::any_cast(parsedArgs["logfile"]); } writeAnalysisImage = false; if (parsedArgs.count("save-image")) { writeAnalysisImage = true; anaylsisImagePath = us::any_cast(parsedArgs["save-image"]); } writeAnalysisMask = false; if (parsedArgs.count("save-mask")) { writeAnalysisMask = true; analysisMaskPath = us::any_cast(parsedArgs["save-mask"]); } writePNGScreenshots = false; if (parsedArgs.count("save-image-screenshots")) { writePNGScreenshots = true; pngScreenshotsPath = us::any_cast(parsedArgs["save-image-screenshots"]); std::string pngScrenshotFolderPath = itksys::SystemTools::GetFilenamePath(pngScreenshotsPath); if (pngScreenshotsPath.back() == '/' || pngScreenshotsPath.back() == '\\') { pngScrenshotFolderPath = pngScreenshotsPath; } itk::FileTools::CreateDirectory(pngScrenshotFolderPath.c_str()); } useDecimalPoint = false; if (parsedArgs.count("decimal-point")) { auto tmpDecimalPoint = us::any_cast(parsedArgs["decimal-point"]); if (tmpDecimalPoint.length() > 0) { useDecimalPoint = true; decimalPoint = tmpDecimalPoint.at(0); } } } void mitk::cl::GlobalImageFeaturesParameter::ParseHeaderInformation(std::map &parsedArgs) { // // Check if an header is required or not. Consider also first line header option. // useHeader = false; useHeaderForFirstLineOnly = false; if (parsedArgs.count("header")) { useHeader = us::any_cast(parsedArgs["header"]); } if (parsedArgs.count("first-line-header")) { useHeaderForFirstLineOnly = us::any_cast(parsedArgs["first-line-header"]); } if (useHeaderForFirstLineOnly) { useHeader = !fileExists(outputPath); } } void mitk::cl::GlobalImageFeaturesParameter::ParseMaskAdaptation(std::map &parsedArgs) { // // Parse parameters that control how the input mask is adapted to the input image // resampleMask = false; ensureSameSpace = false; resampleToFixIsotropic = false; resampleResolution = 1.0; if (parsedArgs.count("resample-mask")) { resampleMask = us::any_cast(parsedArgs["resample-mask"]); } if (parsedArgs.count("same-space")) { ensureSameSpace = us::any_cast(parsedArgs["same-space"]); } if (parsedArgs.count("fixed-isotropic")) { resampleToFixIsotropic = true; resampleResolution = us::any_cast(parsedArgs["fixed-isotropic"]); } } void mitk::cl::GlobalImageFeaturesParameter::ParseGlobalFeatureParameter(std::map &parsedArgs) { // // Parse parameters that control how the input mask is adapted to the input image // defineGlobalMinimumIntensity = false; defineGlobalMaximumIntensity = false; defineGlobalNumberOfBins = false; if (parsedArgs.count("minimum-intensity")) { defineGlobalMinimumIntensity = true; globalMinimumIntensity = us::any_cast(parsedArgs["minimum-intensity"]); } if (parsedArgs.count("maximum-intensity")) { defineGlobalMaximumIntensity = true; globalMaximumIntensity = us::any_cast(parsedArgs["maximum-intensity"]); } if (parsedArgs.count("bins")) { defineGlobalNumberOfBins = true; globalNumberOfBins = us::any_cast(parsedArgs["bins"]); } } diff --git a/Modules/Classification/CLUtilities/test/mitkGlobalFeaturesTest.cpp b/Modules/Classification/CLUtilities/test/mitkGlobalFeaturesTest.cpp index 0eed3e55e6..ffd431a5ef 100644 --- a/Modules/Classification/CLUtilities/test/mitkGlobalFeaturesTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGlobalFeaturesTest.cpp @@ -1,317 +1,317 @@ /*=================================================================== 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 #include -#include +#include #include #include template static mitk::Image::Pointer GenerateMaskImage(unsigned int dimX, unsigned int dimY, unsigned int dimZ, float spacingX = 1, float spacingY = 1, float spacingZ = 1) { typedef itk::Image< TPixelType, 3 > ImageType; typename ImageType::RegionType imageRegion; imageRegion.SetSize(0, dimX); imageRegion.SetSize(1, dimY); imageRegion.SetSize(2, dimZ); typename ImageType::SpacingType spacing; spacing[0] = spacingX; spacing[1] = spacingY; spacing[2] = spacingZ; mitk::Point3D origin; origin.Fill(0.0); itk::Matrix directionMatrix; directionMatrix.SetIdentity(); typename ImageType::Pointer image = ImageType::New(); image->SetSpacing( spacing ); image->SetOrigin( origin ); image->SetDirection( directionMatrix ); image->SetLargestPossibleRegion( imageRegion ); image->SetBufferedRegion( imageRegion ); image->SetRequestedRegion( imageRegion ); image->Allocate(); image->FillBuffer(1); mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( image.GetPointer() ); mitkImage->SetVolume( image->GetBufferPointer() ); return mitkImage; } template static mitk::Image::Pointer GenerateGradientWithDimXImage(unsigned int dimX, unsigned int dimY, unsigned int dimZ, float spacingX = 1, float spacingY = 1, float spacingZ = 1) { typedef itk::Image< TPixelType, 3 > ImageType; typename ImageType::RegionType imageRegion; imageRegion.SetSize(0, dimX); imageRegion.SetSize(1, dimY); imageRegion.SetSize(2, dimZ); typename ImageType::SpacingType spacing; spacing[0] = spacingX; spacing[1] = spacingY; spacing[2] = spacingZ; mitk::Point3D origin; origin.Fill(0.0); itk::Matrix directionMatrix; directionMatrix.SetIdentity(); typename ImageType::Pointer image = ImageType::New(); image->SetSpacing( spacing ); image->SetOrigin( origin ); image->SetDirection( directionMatrix ); image->SetLargestPossibleRegion( imageRegion ); image->SetBufferedRegion( imageRegion ); image->SetRequestedRegion( imageRegion ); image->Allocate(); image->FillBuffer(0.0); typedef itk::ImageRegionIterator IteratorOutputType; IteratorOutputType it(image, imageRegion); it.GoToBegin(); TPixelType val = 0; while(!it.IsAtEnd()) { it.Set(val % dimX); val++; ++it; } mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( image.GetPointer() ); mitkImage->SetVolume( image->GetBufferPointer() ); return mitkImage; } class mitkGlobalFeaturesTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGlobalFeaturesTestSuite ); MITK_TEST(FirstOrder_SinglePoint); MITK_TEST(FirstOrder_QubicArea); //MITK_TEST(RunLenght_QubicArea); MITK_TEST(Coocurrence_QubicArea); //MITK_TEST(TestFirstOrderStatistic); // MITK_TEST(TestThreadedDecisionForest); CPPUNIT_TEST_SUITE_END(); private: typedef itk::Image ImageType; typedef itk::Image MaskType; mitk::Image::Pointer m_Image,m_Mask,m_Mask1; ImageType::Pointer m_ItkImage; MaskType::Pointer m_ItkMask,m_ItkMask1; mitk::Image::Pointer m_GradientImage, m_GradientMask; public: void setUp(void) { // Load Image Data m_Image = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("Pic3D.nrrd"))[0].GetPointer()); mitk::CastToItkImage(m_Image,m_ItkImage); // Create a single mask with only one pixel within the regions mitk::Image::Pointer mask1 = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("Pic3D.nrrd"))[0].GetPointer()); mitk::CastToItkImage(mask1,m_ItkMask); m_ItkMask->FillBuffer(0); MaskType::IndexType index; index[0]=88;index[1]=81;index[2]=13; m_ItkMask->SetPixel(index, 1); MITK_INFO << "Pixel Value: "<GetPixel(index); mitk::CastToMitkImage(m_ItkMask, m_Mask); // Create a mask with a covered region mitk::Image::Pointer lmask1 = dynamic_cast(mitk::IOUtil::Load(GetTestDataFilePath("Pic3D.nrrd"))[0].GetPointer()); mitk::CastToItkImage(lmask1,m_ItkMask1); m_ItkMask1->FillBuffer(0); int range=2; for (int x = 88-range;x < 88+range+1;++x) { for (int y=81-range;y<81+range+1;++y) { for (int z=13-range;z<13+range+1;++z) { index[0] = x; index[1] = y; index[2] = z; //MITK_INFO << "Pixel: " <GetPixel(index); m_ItkMask1->SetPixel(index, 1); } } } mitk::CastToMitkImage(m_ItkMask1, m_Mask1); m_GradientImage=GenerateGradientWithDimXImage(5,5,5); m_GradientMask = GenerateMaskImage(5,5,5); } void FirstOrder_SinglePoint() { mitk::GIFFirstOrderStatistics::Pointer calculator = mitk::GIFFirstOrderStatistics::New(); - calculator->SetHistogramSize(4096); - calculator->SetUseCtRange(true); + //calculator->SetHistogramSize(4096); + //calculator->SetUseCtRange(true); auto features = calculator->CalculateFeatures(m_Image, m_Mask); std::map results; for (auto iter=features.begin(); iter!=features.end();++iter) { results[(*iter).first]=(*iter).second; MITK_INFO << (*iter).first << " : " << (*iter).second; } CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The range of a single pixel should be 0",0.0, results["FirstOrder Range"], 0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The uniformity of a single pixel should be 1",1.0, results["FirstOrder Uniformity"], 0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The entropy of a single pixel should be 0",0.0, results["FirstOrder Entropy"], 0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Root-Means-Square of a single pixel with (-352) should be 352",352.0, results["FirstOrder RMS"], 0.01); CPPUNIT_ASSERT_EQUAL_MESSAGE("The Kurtosis of a single pixel should be undefined",results["FirstOrder Kurtosis"]==results["FirstOrder Kurtosis"], false); CPPUNIT_ASSERT_EQUAL_MESSAGE("The Skewness of a single pixel should be undefined",results["FirstOrder Skewness"]==results["FirstOrder Skewness"], false); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Mean absolute deviation of a single pixel with (-352) should be 0",0, results["FirstOrder Mean absolute deviation"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Covered image intensity range of a single pixel with (-352) should be 0",0, results["FirstOrder Covered Image Intensity Range"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Minimum of a single pixel with (-352) should be -352",-352, results["FirstOrder Minimum"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Maximum of a single pixel with (-352) should be -352",-352, results["FirstOrder Maximum"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Mean of a single pixel with (-352) should be -352",-352, results["FirstOrder Mean"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Variance (corrected) of a single pixel with (-352) should be 0",0, results["FirstOrder Variance"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Sum of a single pixel with (-352) should be -352",-352, results["FirstOrder Sum"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Median of a single pixel with (-352) should be -352",-352, results["FirstOrder Median"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Standard deviation (corrected) of a single pixel with (-352) should be -352",0, results["FirstOrder Standard deviation"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The number of voxels of a single pixel should be 1",1, results["FirstOrder No. of Voxel"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Energy of a single pixel should be 352*352",352*352, results["FirstOrder Energy"], 0.0); // MITK_ASSERT_EQUAL(results["FirstOrder Range"]==0.0,true,"The range of a single pixel should be 0"); } void FirstOrder_QubicArea() { mitk::GIFFirstOrderStatistics::Pointer calculator = mitk::GIFFirstOrderStatistics::New(); - calculator->SetHistogramSize(4096); - calculator->SetUseCtRange(true); + //calculator->SetHistogramSize(4096); + //calculator->SetUseCtRange(true); auto features = calculator->CalculateFeatures(m_Image, m_Mask1); std::map results; for (auto iter=features.begin(); iter!=features.end();++iter) { results[(*iter).first]=(*iter).second; MITK_INFO << (*iter).first << " : " << (*iter).second; } CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The range should be 981",981, results["FirstOrder Range"], 0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Root-Means-Square of a single pixel with (-352) should be 352",402.895778, results["FirstOrder RMS"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Minimum of a single pixel with (-352) should be -352",-937, results["FirstOrder Minimum"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Maximum of a single pixel with (-352) should be -352",44, results["FirstOrder Maximum"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Mean of a single pixel with (-352) should be -352",-304.448, results["FirstOrder Mean"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Sum of a single pixel with (-352) should be -352",-38056, results["FirstOrder Sum"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Median of a single pixel with (-352) should be -352",-202, results["FirstOrder Median"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The number of voxels of a single pixel should be 1",125, results["FirstOrder No. of Voxel"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Standard deviation (corrected) of a single pixel with (-352) should be -352",264.949066, results["FirstOrder Standard deviation"], 0.000001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Energy of a single pixel should be 352*352",20290626, results["FirstOrder Energy"], 0.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The uniformity of a single pixel should be 1",0.0088960, results["FirstOrder Uniformity"], 0.0000001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The entropy of a single pixel should be 0",-6.853784285, results["FirstOrder Entropy"], 0.000000005); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Variance (corrected) of a single pixel with (-352) should be 0",70198.0074, results["FirstOrder Variance"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Kurtosis of a single pixel should be 0",2.63480121, results["FirstOrder Kurtosis"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Skewness of a single pixel should be 0",-0.91817318, results["FirstOrder Skewness"], 0.00001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Mean absolute deviation of a single pixel with (-352) should be 0",219.348608, results["FirstOrder Mean absolute deviation"], 0.000001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The Covered image intensity range of a single pixel with (-352) should be 0",0.41149329, results["FirstOrder Covered Image Intensity Range"], 0.000001); } void RunLenght_QubicArea() { - mitk::GIFGrayLevelRunLength::Pointer calculator = mitk::GIFGrayLevelRunLength::New(); + mitk::GIFGreyLevelRunLength::Pointer calculator = mitk::GIFGreyLevelRunLength::New(); //calculator->SetHistogramSize(4096); calculator->SetUseCtRange(true); calculator->SetRange(981); auto features = calculator->CalculateFeatures(m_Image, m_Mask1); std::map results; for (auto iter=features.begin(); iter!=features.end();++iter) { results[(*iter).first]=(*iter).second; MITK_INFO << (*iter).first << " : " << (*iter).second; } } void Coocurrence_QubicArea() { /* * Expected Matrix: (Direction 0,0,1) * |------------------------| * | 20 | 0 | 0 | 0 | 0 | * |------------------------| * | 0 | 20 | 0 | 0 | 0 | * |------------------------| * | 0 | 0 | 20 | 0 | 0 | * |------------------------| * | 0 | 0 | 0 | 20 | 0 | * |------------------------| * | 0 | 0 | 0 | 0 | 20 | * |------------------------| * Expected Matrix: (Direction (1,0,0),(0,1,0)) * |------------------------| * | 20 | 0 | 0 | 0 | 0 | * |------------------------| * | 20 | 0 | 0 | 0 | 0 | * |------------------------| * | 20 | 0 | 0 | 0 | 0 | * |------------------------| * | 20 | 0 | 0 | 0 | 0 | * |------------------------| * | 20 | 0 | 0 | 0 | 0 | * |------------------------| */ mitk::GIFCooccurenceMatrix::Pointer calculator = mitk::GIFCooccurenceMatrix::New(); //calculator->SetHistogramSize(4096); //calculator->SetUseCtRange(true); //calculator->SetRange(981); calculator->SetDirection(1); auto features = calculator->CalculateFeatures(m_GradientImage, m_GradientMask); std::map results; for (auto iter=features.begin(); iter!=features.end();++iter) { results[(*iter).first]=(*iter).second; MITK_INFO << (*iter).first << " : " << (*iter).second; } CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The mean energy value should be 0.2",0.2, results["co-occ. (1) Energy Means"], mitk::eps); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The mean entropy value should be 0.2",2.321928, results["co-occ. (1) Entropy Means"], 0.000001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The mean contrast value should be 0.0",0, results["co-occ. (1) Contrast Means"], mitk::eps); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The mean dissimilarity value should be 0.0",0, results["co-occ. (1) Dissimilarity Means"], mitk::eps); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The mean homogenity1 value should be 1.0",1, results["co-occ. (1) Homogeneity1 Means"], mitk::eps); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("The mean InverseDifferenceMoment value should be 1.0",1, results["co-occ. (1) InverseDifferenceMoment Means"], mitk::eps); } }; MITK_TEST_SUITE_REGISTRATION(mitkGlobalFeatures) \ No newline at end of file diff --git a/Wrapper/swigutils.cmake b/Wrapper/swigutils.cmake new file mode 100644 index 0000000000..516778aff8 --- /dev/null +++ b/Wrapper/swigutils.cmake @@ -0,0 +1,63 @@ +macro(setup_swig) + if (NOT SWIG_DIR) + set(SWIG_DIR $ENV{SWIG_DIR} ) + endif() + if (NOT SWIG_EXECUTABLE) + set(SWIG_EXECUTABLE $ENV{SWIG_EXECUTABLE} ) + endif() + find_package(SWIG REQUIRED) + INCLUDE(${SWIG_USE_FILE}) + message(STATUS "SWIG_DIR = ${SWIG_DIR}" ) + message(STATUS "SWIG_EXECUTABLE = ${SWIG_EXECUTABLE}" ) +endmacro() + +macro(setup_python) + # CMake's python-detection is crazy broken, so we use python-config on *nix. + # Sadly on Windows python-config isn't available, so do our best with CMake. + # + # see https://cmake.org/Bug/view.php?id=14809 + # + if (WIN32) + find_package(PythonInterp) + find_package(PythonLibs) + + set(PYTHON_CFLAGS "-I${PYTHON_INCLUDE_PATH}") + set(PYTHON_LDFLAGS "${PYTHON_LIBRARIES}") + else() + if (ARCH STREQUAL "arm") + find_program(PYTHON_CONFIG_EXECUTABLE arm-linux-gnueabihf-python-config) + else() + find_program(PYTHON_CONFIG_EXECUTABLE python-config) + endif() + if (PYTHON_CONFIG_EXECUTABLE) + execute_process(COMMAND ${PYTHON_CONFIG_EXECUTABLE} --cflags OUTPUT_VARIABLE PYTHON_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${PYTHON_CONFIG_EXECUTABLE} --ldflags OUTPUT_VARIABLE PYTHON_LDFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + if (NOT PYTHON_EXECUTABLE) + execute_process(COMMAND ${PYTHON_CONFIG_EXECUTABLE} --exec-prefix OUTPUT_VARIABLE PYTHON_EXECUTABLE OUTPUT_STRIP_TRAILING_WHITESPACE) + set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}/bin/python) + endif() + endif() + endif() + + if (PYTHON_EXECUTABLE) + # get the python version + execute_process(COMMAND ${PYTHON_EXECUTABLE} --version ERROR_VARIABLE PYTHON_VERSION) + # message("rv='${PYTHON_VERSION}'") + string(STRIP ${PYTHON_VERSION} PYTHON_VERSION) + string(REPLACE " " ";" PYTHON_VERSION ${PYTHON_VERSION}) + list(GET PYTHON_VERSION 1 PYTHON_VERSION) + + message(STATUS "PYTHON_EXECUTABLE= ${PYTHON_EXECUTABLE}") + message(STATUS "PYTHON_VERSION= ${PYTHON_VERSION}") + message(STATUS "PYTHON_CFLAGS= ${PYTHON_CFLAGS}") + message(STATUS "PYTHON_LDFLAGS= ${PYTHON_LDFLAGS}") + + set(PYTHON 1) + endif() +endmacro() + +# build-time file replacement +set(FILE_REPLACE_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/replace.cmake) +file(WRITE ${FILE_REPLACE_SCRIPT} "file(READ \${FROM} file_contents) \n") +file(APPEND ${FILE_REPLACE_SCRIPT} "string(REPLACE \${MATCH_STRING} \${REPLACE_STRING} file_contents \${file_contents}) \n") +file(APPEND ${FILE_REPLACE_SCRIPT} "file(WRITE \${TO} \${file_contents}) \n")