diff --git a/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h b/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h index a8fcb05fac..b55c3b17d8 100644 --- a/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h +++ b/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h @@ -1,291 +1,338 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkAbstractGlobalImageFeature_h #define mitkAbstractGlobalImageFeature_h #include #include #include #include #include // STD Includes // Eigen #include // MITK includes #include namespace mitk { + + /**Used as ID for features calculated by feature classes*/ + struct MITKCLCORE_EXPORT FeatureID + { + /**Name of the feature*/ + std::string name; + /**Name of the feature class*/ + std::string featureClass; + /**ID for the setting that is represented by parameters and is specified by the feature class while calculating the features. It must be as unique as the parameters themself.*/ + std::string settingID; + /**Alternative name that containes the legacy naming of the feature that encodes the parametersetting directly in the string.*/ + std::string legacyName; + /**Version of the feature definition*/ + std::string version = "1"; + + using ParametersType = std::map; + ParametersType parameters; + + bool operator < (const FeatureID& rh) const; + bool operator ==(const FeatureID& rh) const; + }; + + /**Helper that takes a pass templateID clones it and populates it with the also passed informations befor returning it. + * @param templateID reference ID that should be cloned. + * @param name Name of the feature.*/ + MITKCLCORE_EXPORT FeatureID CreateFeatureID(FeatureID templateID, std::string name); + /** * * * ## 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; + typedef std::vector< std::pair > FeatureListType; + using ParametersType = FeatureID::ParametersType; /** * \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; + FeatureListType CalculateFeatures(const Image* image, const Image* mask); + virtual FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) = 0; /** * \brief Calculates the given feature Slice-wise. Might not be availble for an individual filter! */ - FeatureListType CalculateFeaturesSlicewise(const Image::Pointer & feature, const Image::Pointer &mask, int sliceID); + FeatureListType CalculateFeaturesSlicewise(const Image::Pointer & image, const Image::Pointer &mask, int sliceID); /** * \brief Calculates the feature of this abstact interface. Does not necessarily considers the parameter settings. */ - virtual void CalculateFeaturesSliceWiseUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, int sliceID, FeatureListType &featureList); + virtual void CalculateAndAppendFeaturesSliceWise(const Image::Pointer & image, const Image::Pointer &mask, int sliceID, FeatureListType &featureList, bool checkParameterActivation = true); /** * \brief Calculates the feature of this abstact interface. Does not necessarily considers the parameter settings. + * @param checkParameterActivation Indicates if the features should only be calculated and added if the FeatureClass is activated in the parameters. + * True: only append if activated in the parametes. False: always and append it. */ - virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) = 0; - - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - virtual FeatureNameListType GetFeatureNames() = 0; - - /** - * \brief Adds an additional Separator to the name of the feature, which encodes the used parameters - */ - virtual std::string GetCurrentFeatureEncoding(); - - /** - * \brief Returns a string that encodes the feature class name. - * - * This Feature returns a string that should be put before every other feature - * value. It has the format [::]::[::]. - * The options and are only added, if the corresponding - * options are set. - */ - std::string FeatureDescriptionPrefix(); + void CalculateAndAppendFeatures(const Image* image, const Image* mask, const Image* maskNoNAN, FeatureListType &featureList, bool checkParameterActivation = true); itkSetMacro(Prefix, std::string); itkSetMacro(ShortName, std::string); itkSetMacro(LongName, std::string); itkSetMacro(FeatureClassName, std::string); itkSetMacro(Direction, int); - void SetParameter(ParameterTypes param) { m_Parameter=param; }; + + void SetParameters(ParametersType param) + { + m_Parameters = param; + this->ConfigureQuantifierSettingsByParameters(); + this->ConfigureSettingsByParameters(param); + this->Modified(); + }; itkGetConstMacro(Prefix, std::string); itkGetConstMacro(ShortName, std::string); itkGetConstMacro(LongName, std::string); itkGetConstMacro(FeatureClassName, std::string); - itkGetConstMacro(Parameter, ParameterTypes); + itkGetConstMacro(Parameters, ParametersType); - itkSetMacro(UseQuantifier, bool); - itkGetConstMacro(UseQuantifier, bool); - itkSetMacro(Quantifier, IntensityQuantifier::Pointer); itkGetMacro(Quantifier, IntensityQuantifier::Pointer); itkGetConstMacro(Direction, int); itkSetMacro(MinimumIntensity, double); itkSetMacro(UseMinimumIntensity, bool); itkSetMacro(MaximumIntensity, double); itkSetMacro(UseMaximumIntensity, bool); itkGetConstMacro(MinimumIntensity, double); itkGetConstMacro(UseMinimumIntensity, bool); itkGetConstMacro(MaximumIntensity, double); itkGetConstMacro(UseMaximumIntensity, bool); itkSetMacro(Binsize, double); itkSetMacro(UseBinsize, bool); itkGetConstMacro(Binsize, double); itkGetConstMacro(UseBinsize, bool); itkSetMacro(MorphMask, mitk::Image::Pointer); itkGetConstMacro(MorphMask, mitk::Image::Pointer); itkSetMacro(Bins, int); itkSetMacro(UseBins, bool); itkGetConstMacro(UseBins, bool); itkGetConstMacro(Bins, int); itkSetMacro(IgnoreMask, bool); itkGetConstMacro(IgnoreMask, bool); - itkSetMacro(EncodeParameters, bool); - itkGetConstMacro(EncodeParameters, bool); + itkSetMacro(EncodeParametersInFeaturePrefix, bool); + itkGetConstMacro(EncodeParametersInFeaturePrefix, bool); + itkBooleanMacro(EncodeParametersInFeaturePrefix); std::string GetOptionPrefix() const { - if (m_Prefix.length() > 0) + if (!m_Prefix.empty()) return m_Prefix + "::" + m_ShortName; return m_ShortName; - } - virtual void AddArguments(mitkCommandLineParser &parser) = 0; + /** Can be called to add all relevant argument for configuring the feature instance to the passed parser instance. + Must be implemented be derived classes. For adding the quantifier arguments use AddQuantifierArguments(...) as + helper function.*/ + virtual void AddArguments(mitkCommandLineParser &parser) const = 0; + + /** Helper function that generates the legacy feature name without encoding of parameters; as it is used e.g. + in the unit tests.*/ + static std::string GenerateLegacyFeatureNameWOEncoding(const FeatureID& id); + +protected: std::vector SplitDouble(std::string str, char delimiter); - void AddQuantifierArguments(mitkCommandLineParser &parser); - void InitializeQuantifierFromParameters(const Image::Pointer & feature, const Image::Pointer &mask,unsigned int defaultBins = 256); - void InitializeQuantifier(const Image::Pointer & feature, const Image::Pointer &mask, unsigned int defaultBins = 256); - std::string QuantifierParameterString(); + virtual FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) = 0; + + void AddQuantifierArguments(mitkCommandLineParser& parser) const; + + /** Ensures that all quantifier relevant variables of the instance are set correctly given the information in m_Parameters.*/ + void ConfigureQuantifierSettingsByParameters(); + + /** Ensures that the instance is configured according to the information given in the passed parameters. + * This method will be called by SetParameters(...) after ConfigureQuantifierSettingsByParameters() was called.*/ + virtual void ConfigureSettingsByParameters(const ParametersType& parameters); + + /**Initializes the quantifier gigen the quantifier relevant variables and the passed arguments.*/ + void InitializeQuantifier(const Image* image, const Image* mask, unsigned int defaultBins = 256); + + /** Helper that encodes the quantifier parameters in a string (e.g. used for the legacy feature name)*/ + std::string QuantifierParameterString() const; + + /* Creates a template feature id. + * it will set the featureClass, the settingID (assuming that it is the featureClass with the passed suffix + * and all parameters that are global or have the option prefix of the instance.*/ + FeatureID CreateTemplateFeatureID(std::string settingsSuffix = "", FeatureID::ParametersType additionalParams = {}); + + /** Helper that generates the legacy feature names for a passed FeatureID. + * Format of the legacy feature name is: ::[::] + * Overwrite GenerateLegacyFeatureNamePart and GenerateLegacyFeatureEncoding to change behavior in + * derived classes. + */ + virtual std::string GenerateLegacyFeatureName(const FeatureID& id) const; + virtual std::string GenerateLegacyFeatureNamePart(const FeatureID& id) const; + virtual std::string GenerateLegacyFeatureEncoding(const FeatureID& id) const; public: //#ifndef DOXYGEN_SKIP void SetRequestedRegionToLargestPossibleRegion() override {}; bool RequestedRegionIsOutsideOfTheBufferedRegion() override { return true; }; bool VerifyRequestedRegion() override { return false; }; void SetRequestedRegion (const itk::DataObject * /*data*/) override {}; // Override bool IsEmpty() const override { if(IsInitialized() == false) return true; const TimeGeometry* timeGeometry = const_cast(this)->GetUpdatedTimeGeometry(); if(timeGeometry == nullptr) return true; return false; } private: std::string m_Prefix; // Prefix before all input parameters std::string m_ShortName; // Name of all variables std::string m_LongName; // Long version of the name (For turning on) std::string m_FeatureClassName; - ParameterTypes m_Parameter; // Parameter setting + ParametersType m_Parameters; // Parameter setting - bool m_UseQuantifier = false; - IntensityQuantifier::Pointer m_Quantifier; + mitk::Image::Pointer m_MorphMask = nullptr; + + IntensityQuantifier::Pointer m_Quantifier; + //Quantifier relevant variables double m_MinimumIntensity = 0; bool m_UseMinimumIntensity = false; double m_MaximumIntensity = 100; bool m_UseMaximumIntensity = false; - bool m_EncodeParameters = false; + bool m_EncodeParametersInFeaturePrefix = false; double m_Binsize = 1; bool m_UseBinsize = false; int m_Bins = 256; bool m_UseBins = true; int m_Direction = 0; bool m_IgnoreMask = false; - bool m_CalculateWithParameter = false; - - mitk::Image::Pointer m_MorphMask = nullptr; //#endif // Skip Doxygen }; } #endif //mitkAbstractGlobalImageFeature_h diff --git a/Modules/Classification/CLCore/include/mitkIntensityQuantifier.h b/Modules/Classification/CLCore/include/mitkIntensityQuantifier.h index 88dd5b694f..2a3cc7f78f 100644 --- a/Modules/Classification/CLCore/include/mitkIntensityQuantifier.h +++ b/Modules/Classification/CLCore/include/mitkIntensityQuantifier.h @@ -1,91 +1,91 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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); + void InitializeByImage(const Image* image, unsigned int bins); + void InitializeByImageAndMaximum(const Image* image, double maximum, unsigned int bins); + void InitializeByImageAndMinimum(const Image* image, double minimum, unsigned int bins); + void InitializeByImageRegion(const Image* image, const Image* mask, unsigned int bins); + void InitializeByImageRegionAndMinimum(const Image* image, const Image* mask, double minimum, unsigned int bins); + void InitializeByImageRegionAndMaximum(const Image* image, const Image* mask, double maximum, unsigned int bins); + void InitializeByImageAndBinsize(const Image* image, double binsize); + void InitializeByImageAndBinsizeAndMinimum(const Image* image, double minimum, double binsize); + void InitializeByImageAndBinsizeAndMaximum(const Image* image, double maximum, double binsize); + void InitializeByImageRegionAndBinsize(const Image* image, const Image* mask, double binsize); + void InitializeByImageRegionAndBinsizeAndMinimum(const Image* image, const Image* mask, double minimum, double binsize); + void InitializeByImageRegionAndBinsizeAndMaximum(const Image* image, const Image* 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 void SetRequestedRegionToLargestPossibleRegion() override {}; bool RequestedRegionIsOutsideOfTheBufferedRegion() override { return true; }; bool VerifyRequestedRegion() override { return false; }; void SetRequestedRegion (const itk::DataObject * /*data*/) override {}; // Override bool IsEmpty() const override { if(IsInitialized() == false) return true; const TimeGeometry* timeGeometry = const_cast(this)->GetUpdatedTimeGeometry(); if(timeGeometry == nullptr) return true; return false; } private: 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 c689e7f622..e5b0a156d9 100644 --- a/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp +++ b/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp @@ -1,402 +1,523 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include + +bool mitk::FeatureID::operator < (const FeatureID& rh) const +{ + if (this->featureClass < rh.featureClass) return true; + if (this->featureClass == rh.featureClass) + { + if (this->name < rh.name) return true; + if (this->name == rh.name && this->settingID < rh.settingID) return true; + } + return false; +} + +bool mitk::FeatureID::operator ==(const FeatureID& rh) const +{ + if (this->name != rh.name) return false; + if (this->settingID != rh.settingID) return false; + if (this->featureClass != rh.featureClass) return false; + return true; +} + +mitk::FeatureID mitk::CreateFeatureID(FeatureID templateID, std::string name) +{ + auto newID = templateID; + newID.name = name; + return newID; +} + static void ExtractSlicesFromImages(mitk::Image::Pointer image, mitk::Image::Pointer mask, int direction, std::vector &imageVector, std::vector &maskVector) { typedef itk::Image< double, 2 > FloatImage2DType; typedef itk::Image< unsigned short, 2 > MaskImage2DType; typedef itk::Image< double, 3 > FloatImageType; typedef itk::Image< unsigned short, 3 > MaskImageType; FloatImageType::Pointer itkFloat = FloatImageType::New(); MaskImageType::Pointer itkMask = MaskImageType::New(); mitk::CastToItkImage(mask, itkMask); mitk::CastToItkImage(image, itkFloat); int idxA, idxB, idxC; switch (direction) { case 0: idxA = 1; idxB = 2; idxC = 0; break; case 1: idxA = 0; idxB = 2; idxC = 1; break; case 2: idxA = 0; idxB = 1; idxC = 2; break; default: idxA = 1; idxB = 2; idxC = 0; break; } auto imageSize = image->GetLargestPossibleRegion().GetSize(); FloatImageType::IndexType index3D; FloatImage2DType::IndexType index2D; FloatImage2DType::SpacingType spacing2D; spacing2D[0] = itkFloat->GetSpacing()[idxA]; spacing2D[1] = itkFloat->GetSpacing()[idxB]; for (unsigned int i = 0; i < imageSize[idxC]; ++i) { FloatImage2DType::RegionType region; FloatImage2DType::IndexType start; FloatImage2DType::SizeType size; start[0] = 0; start[1] = 0; size[0] = imageSize[idxA]; size[1] = imageSize[idxB]; region.SetIndex(start); region.SetSize(size); FloatImage2DType::Pointer image2D = FloatImage2DType::New(); image2D->SetRegions(region); image2D->Allocate(); MaskImage2DType::Pointer mask2D = MaskImage2DType::New(); mask2D->SetRegions(region); mask2D->Allocate(); unsigned long voxelsInMask = 0; for (unsigned int a = 0; a < imageSize[idxA]; ++a) { for (unsigned int b = 0; b < imageSize[idxB]; ++b) { index3D[idxA] = a; index3D[idxB] = b; index3D[idxC] = i; index2D[0] = a; index2D[1] = b; image2D->SetPixel(index2D, itkFloat->GetPixel(index3D)); mask2D->SetPixel(index2D, itkMask->GetPixel(index3D)); voxelsInMask += (itkMask->GetPixel(index3D) > 0) ? 1 : 0; } } image2D->SetSpacing(spacing2D); mask2D->SetSpacing(spacing2D); mitk::Image::Pointer tmpFloatImage = mitk::Image::New(); tmpFloatImage->InitializeByItk(image2D.GetPointer()); mitk::GrabItkImageMemory(image2D, tmpFloatImage); mitk::Image::Pointer tmpMaskImage = mitk::Image::New(); tmpMaskImage->InitializeByItk(mask2D.GetPointer()); mitk::GrabItkImageMemory(mask2D, tmpMaskImage); if (voxelsInMask > 0) { imageVector.push_back(tmpFloatImage); maskVector.push_back(tmpMaskImage); } } } - - - std::vector mitk::AbstractGlobalImageFeature::SplitDouble(std::string str, char delimiter) { std::vector internal; std::stringstream ss(str); // Turn the string into a stream. std::string tok; double val; while (std::getline(ss, tok, delimiter)) { std::stringstream s2(tok); s2 >> val; internal.push_back(val); } return internal; } -void mitk::AbstractGlobalImageFeature::AddQuantifierArguments(mitkCommandLineParser &parser) +void mitk::AbstractGlobalImageFeature::AddQuantifierArguments(mitkCommandLineParser &parser) const { std::string name = GetOptionPrefix(); parser.addArgument(name + "::minimum", name + "::min", mitkCommandLineParser::Float, "Minium Intensity for Quantification", "Defines the minimum Intensity used for Quantification", us::Any()); parser.addArgument(name + "::maximum", name + "::max", mitkCommandLineParser::Float, "Maximum Intensity for Quantification", "Defines the maximum Intensity used for Quantification", us::Any()); parser.addArgument(name + "::bins", name + "::bins", mitkCommandLineParser::Int, "Number of Bins", "Define the number of bins that is used ", us::Any()); parser.addArgument(name + "::binsize", name + "::binsize", mitkCommandLineParser::Float, "Binsize", "Define the size of the used bins", us::Any()); parser.addArgument(name + "::ignore-global-histogram", name + "::ignore-global-histogram", mitkCommandLineParser::Bool, "Ignore the global histogram Parameters", "Ignores the global histogram parameters", us::Any()); parser.addArgument(name + "::ignore-mask-for-histogram", name + "::ignore-mask", mitkCommandLineParser::Bool, "Ignore the global histogram Parameters", "Ignores the global histogram parameters", us::Any()); - } -void mitk::AbstractGlobalImageFeature::InitializeQuantifierFromParameters(const Image::Pointer & feature, const Image::Pointer &mask, unsigned int defaultBins) +void mitk::AbstractGlobalImageFeature::ConfigureQuantifierSettingsByParameters() { unsigned int bins = 0; double binsize = 0; double minimum = 0; double maximum = 0; - auto parsedArgs = GetParameter(); + auto parsedArgs = GetParameters(); std::string name = GetOptionPrefix(); bool useGlobal = true; if (parsedArgs.count(name + "::ignore-global-histogram")) { useGlobal = false; SetUseMinimumIntensity(false); SetUseMaximumIntensity(false); SetUseBinsize(false); SetUseBins(false); } if (useGlobal) { if (parsedArgs.count("ignore-mask-for-histogram")) { bool tmp = us::any_cast(parsedArgs["ignore-mask-for-histogram"]); SetIgnoreMask(tmp); } if (parsedArgs.count("minimum-intensity")) { minimum = us::any_cast(parsedArgs["minimum-intensity"]); SetMinimumIntensity(minimum); SetUseMinimumIntensity(true); } if (parsedArgs.count("maximum-intensity")) { maximum = us::any_cast(parsedArgs["maximum-intensity"]); SetMaximumIntensity(maximum); SetUseMaximumIntensity(true); } if (parsedArgs.count("bins")) { bins = us::any_cast(parsedArgs["bins"]); SetBins(bins); SetUseBins(true); } if (parsedArgs.count("binsize")) { binsize = us::any_cast(parsedArgs["binsize"]); SetBinsize(binsize); SetUseBinsize(true); } } if (parsedArgs.count(name+"::ignore-mask-for-histogram")) { bool tmp = us::any_cast(parsedArgs[name+"::ignore-mask-for-histogram"]); SetIgnoreMask(tmp); } if (parsedArgs.count(name + "::minimum")) { minimum = us::any_cast(parsedArgs[name + "::minimum"]); SetMinimumIntensity(minimum); SetUseMinimumIntensity(true); } if (parsedArgs.count(name + "::maximum")) { maximum = us::any_cast(parsedArgs[name + "::maximum"]); SetMaximumIntensity(maximum); SetUseMaximumIntensity(true); } if (parsedArgs.count(name + "::bins")) { bins = us::any_cast(parsedArgs[name + "::bins"]); SetBins(bins); } if (parsedArgs.count(name + "::binsize")) { binsize = us::any_cast(parsedArgs[name + "::binsize"]); SetBinsize(binsize); SetUseBinsize(true); } - InitializeQuantifier(feature, mask, defaultBins); } -void mitk::AbstractGlobalImageFeature::InitializeQuantifier(const Image::Pointer & feature, const Image::Pointer &mask, unsigned int defaultBins) +void mitk::AbstractGlobalImageFeature::ConfigureSettingsByParameters(const ParametersType& /*parameters*/) +{ + //Default implementation does nothing. + //Override to change behavior. +} + +void mitk::AbstractGlobalImageFeature::InitializeQuantifier(const Image* image, const Image* mask, unsigned int defaultBins) { m_Quantifier = IntensityQuantifier::New(); if (GetUseMinimumIntensity() && GetUseMaximumIntensity() && GetUseBinsize()) m_Quantifier->InitializeByBinsizeAndMaximum(GetMinimumIntensity(), GetMaximumIntensity(), GetBinsize()); else if (GetUseMinimumIntensity() && GetUseBins() && GetUseBinsize()) m_Quantifier->InitializeByBinsizeAndBins(GetMinimumIntensity(), GetBins(), GetBinsize()); else if (GetUseMinimumIntensity() && GetUseMaximumIntensity() && GetUseBins()) m_Quantifier->InitializeByMinimumMaximum(GetMinimumIntensity(), GetMaximumIntensity(), GetBins()); // Intialize from Image and Binsize else if (GetUseBinsize() && GetIgnoreMask() && GetUseMinimumIntensity()) - m_Quantifier->InitializeByImageAndBinsizeAndMinimum(feature, GetMinimumIntensity(), GetBinsize()); + m_Quantifier->InitializeByImageAndBinsizeAndMinimum(image, GetMinimumIntensity(), GetBinsize()); else if (GetUseBinsize() && GetIgnoreMask() && GetUseMaximumIntensity()) - m_Quantifier->InitializeByImageAndBinsizeAndMaximum(feature, GetMaximumIntensity(), GetBinsize()); + m_Quantifier->InitializeByImageAndBinsizeAndMaximum(image, GetMaximumIntensity(), GetBinsize()); else if (GetUseBinsize() && GetIgnoreMask()) - m_Quantifier->InitializeByImageAndBinsize(feature, GetBinsize()); + m_Quantifier->InitializeByImageAndBinsize(image, GetBinsize()); // Initialize form Image, Mask and Binsize else if (GetUseBinsize() && GetUseMinimumIntensity()) - m_Quantifier->InitializeByImageRegionAndBinsizeAndMinimum(feature, mask, GetMinimumIntensity(), GetBinsize()); + m_Quantifier->InitializeByImageRegionAndBinsizeAndMinimum(image, mask, GetMinimumIntensity(), GetBinsize()); else if (GetUseBinsize() && GetUseMaximumIntensity()) - m_Quantifier->InitializeByImageRegionAndBinsizeAndMaximum(feature, mask, GetMaximumIntensity(), GetBinsize()); + m_Quantifier->InitializeByImageRegionAndBinsizeAndMaximum(image, mask, GetMaximumIntensity(), GetBinsize()); else if (GetUseBinsize()) - m_Quantifier->InitializeByImageRegionAndBinsize(feature, mask, GetBinsize()); + m_Quantifier->InitializeByImageRegionAndBinsize(image, mask, GetBinsize()); // Intialize from Image and Bins else if (GetUseBins() && GetIgnoreMask() && GetUseMinimumIntensity()) - m_Quantifier->InitializeByImageAndMinimum(feature, GetMinimumIntensity(), GetBins()); + m_Quantifier->InitializeByImageAndMinimum(image, GetMinimumIntensity(), GetBins()); else if (GetUseBins() && GetIgnoreMask() && GetUseMaximumIntensity()) - m_Quantifier->InitializeByImageAndMaximum(feature, GetMaximumIntensity(), GetBins()); + m_Quantifier->InitializeByImageAndMaximum(image, GetMaximumIntensity(), GetBins()); else if (GetUseBins()) - m_Quantifier->InitializeByImage(feature, GetBins()); + m_Quantifier->InitializeByImage(image, GetBins()); // Intialize from Image, Mask and Bins else if (GetUseBins() && GetUseMinimumIntensity()) - m_Quantifier->InitializeByImageRegionAndMinimum(feature, mask, GetMinimumIntensity(), GetBins()); + m_Quantifier->InitializeByImageRegionAndMinimum(image, mask, GetMinimumIntensity(), GetBins()); else if (GetUseBins() && GetUseMaximumIntensity()) - m_Quantifier->InitializeByImageRegionAndMaximum(feature, mask, GetMaximumIntensity(), GetBins()); + m_Quantifier->InitializeByImageRegionAndMaximum(image, mask, GetMaximumIntensity(), GetBins()); else if (GetUseBins()) - m_Quantifier->InitializeByImageRegion(feature, mask, GetBins()); + m_Quantifier->InitializeByImageRegion(image, mask, GetBins()); // Default else if (GetIgnoreMask()) - m_Quantifier->InitializeByImage(feature, GetBins()); + m_Quantifier->InitializeByImage(image, GetBins()); else - m_Quantifier->InitializeByImageRegion(feature, mask, defaultBins); -} - -std::string mitk::AbstractGlobalImageFeature::GetCurrentFeatureEncoding() -{ - return ""; + m_Quantifier->InitializeByImageRegion(image, mask, defaultBins); } -std::string mitk::AbstractGlobalImageFeature::FeatureDescriptionPrefix() +std::string mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureName(const FeatureID& id) const { std::string output; output = m_FeatureClassName + "::"; - if (m_EncodeParameters) + if (m_EncodeParametersInFeaturePrefix) { - output += GetCurrentFeatureEncoding() + "::"; + output += this->GenerateLegacyFeatureEncoding(id) + "::"; } - return output; + + return output + this->GenerateLegacyFeatureNamePart(id); +}; + +std::string mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNamePart(const FeatureID& id) const +{ + return id.name; } -std::string mitk::AbstractGlobalImageFeature::QuantifierParameterString() +std::string mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureEncoding(const FeatureID& /*id*/) const +{ + return this->QuantifierParameterString(); +} + +std::string mitk::AbstractGlobalImageFeature::QuantifierParameterString() const { std::stringstream ss; + ss.imbue(std::locale("c")); if (GetUseMinimumIntensity() && GetUseMaximumIntensity() && GetUseBinsize()) ss << "Min-" << GetMinimumIntensity() << "_Max-" << GetMaximumIntensity() << "_BS-" << GetBinsize(); else if (GetUseMinimumIntensity() && GetUseBins() && GetUseBinsize()) ss << "Min-" << GetMinimumIntensity() << "_Bins-" << GetBins() << "_BS-" << GetBinsize(); else if (GetUseMinimumIntensity() && GetUseMaximumIntensity() && GetUseBins()) ss << "Min-" << GetMinimumIntensity() << "_Max-" << GetMaximumIntensity() << "_Bins-" << GetBins(); // Intialize from Image and Binsize else if (GetUseBinsize() && GetIgnoreMask() && GetUseMinimumIntensity()) ss << "Min-" << GetMinimumIntensity() << "_BS-" << GetBinsize() << "_FullImage"; else if (GetUseBinsize() && GetIgnoreMask() && GetUseMaximumIntensity()) ss << "Max-" << GetMaximumIntensity() << "_BS-" << GetBinsize() << "_FullImage"; else if (GetUseBinsize() && GetIgnoreMask()) ss << "BS-" << GetBinsize() << "_FullImage"; // Initialize form Image, Mask and Binsize else if (GetUseBinsize() && GetUseMinimumIntensity()) ss << "Min-" << GetMinimumIntensity() << "_BS-" << GetBinsize(); else if (GetUseBinsize() && GetUseMaximumIntensity()) ss << "Max-" << GetMaximumIntensity() << "_BS-" << GetBinsize(); else if (GetUseBinsize()) ss << "BS-" << GetBinsize(); // Intialize from Image and Bins else if (GetUseBins() && GetIgnoreMask() && GetUseMinimumIntensity()) ss << "Min-" << GetMinimumIntensity() << "_Bins-" << GetBins() << "_FullImage"; else if (GetUseBins() && GetIgnoreMask() && GetUseMaximumIntensity()) ss << "Max-" << GetMaximumIntensity() << "_Bins-" << GetBins() << "_FullImage"; else if (GetUseBins()) ss << "Bins-" << GetBins() << "_FullImage"; // Intialize from Image, Mask and Bins else if (GetUseBins() && GetUseMinimumIntensity()) ss << "Min-" << GetMinimumIntensity() << "_Bins-" << GetBins(); else if (GetUseBins() && GetUseMaximumIntensity()) ss << "Max-" << GetMaximumIntensity() << "_Bins-" << GetBins(); else if (GetUseBins()) ss << "Bins-" << GetBins(); // Default else if (GetIgnoreMask()) ss << "Bins-" << GetBins() << "_FullImage"; else ss << "Bins-" << GetBins(); return ss.str(); } +mitk::FeatureID mitk::AbstractGlobalImageFeature::CreateTemplateFeatureID(std::string settingsSuffix, FeatureID::ParametersType additionalParams) +{ + FeatureID newID; + newID.featureClass = this->GetFeatureClassName(); + newID.settingID = this->GetShortName(); + if (!settingsSuffix.empty()) + { + newID.settingID += "_" + settingsSuffix; + } + + std::string name = this->GetOptionPrefix(); + for (const auto& paramIter : m_Parameters) + { + if (paramIter.first.find(name) == 0) + { + newID.parameters.insert(std::make_pair(paramIter.first, paramIter.second)); + } + } + + if (m_Quantifier.IsNotNull()) + { //feature class uses the quantifier. So store the information in the feature ID + if (GetUseMinimumIntensity()) + { + newID.parameters["minimum-intensity"] = us::Any(GetMinimumIntensity()); + } + if (GetUseMaximumIntensity()) + { + newID.parameters["minimum-intensity"] = us::Any(GetMaximumIntensity()); + } + if (GetUseBinsize()) + { + newID.parameters["binsize"] = us::Any(GetBinsize()); + } + if (GetBins()) + { + newID.parameters["bins"] = us::Any(GetBins()); + } + if (GetIgnoreMask()) + { + newID.parameters["ignore-mask-for-histogram"] = us::Any(true); + } + } + + for (const auto& paramIter : additionalParams) + { + newID.parameters[paramIter.first] = paramIter.second; + } + return newID; +} -void mitk::AbstractGlobalImageFeature::CalculateFeaturesSliceWiseUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, int sliceID, FeatureListType &featureList) +void mitk::AbstractGlobalImageFeature::CalculateAndAppendFeaturesSliceWise(const Image::Pointer & image, const Image::Pointer &mask, int sliceID, FeatureListType &featureList, bool checkParameterActivation) { - m_CalculateWithParameter = true; - auto result = CalculateFeaturesSlicewise(feature, mask, sliceID); - featureList.insert(featureList.end(), result.begin(), result.end()); + auto parsedArgs = GetParameters(); + + if (!checkParameterActivation || parsedArgs.count(GetLongName())) + { + auto result = CalculateFeaturesSlicewise(image, mask, sliceID); + featureList.insert(featureList.end(), result.begin(), result.end()); + } } -mitk::AbstractGlobalImageFeature::FeatureListType mitk::AbstractGlobalImageFeature::CalculateFeaturesSlicewise(const Image::Pointer & feature, const Image::Pointer &mask, int sliceID) +mitk::AbstractGlobalImageFeature::FeatureListType mitk::AbstractGlobalImageFeature::CalculateFeaturesSlicewise(const Image::Pointer & image, const Image::Pointer &mask, int sliceID) { std::vector imageVector; std::vector maskVector; - ExtractSlicesFromImages(feature, mask,sliceID, imageVector, maskVector); + ExtractSlicesFromImages(image, mask,sliceID, imageVector, maskVector); std::vector statVector; for (std::size_t index = 0; index < imageVector.size(); ++index) { - if (m_CalculateWithParameter) - { - FeatureListType stat; - this->CalculateFeaturesUsingParameters(imageVector[index], maskVector[index], maskVector[index], stat); - statVector.push_back(stat); - } - else - { - auto stat = this->CalculateFeatures(imageVector[index], maskVector[index]); - statVector.push_back(stat); - } + auto stat = this->CalculateFeatures(imageVector[index], maskVector[index]); + statVector.push_back(stat); } if (statVector.size() < 1) return FeatureListType(); FeatureListType statMean, statStd, result; for (std::size_t i = 0; i < statVector[0].size(); ++i) { auto cElement1 = statVector[0][i]; - cElement1.first = "SliceWise Mean " + cElement1.first; + cElement1.first.name = "SliceWise Mean " + cElement1.first.name; + cElement1.first.legacyName = this->GenerateLegacyFeatureName(cElement1.first); cElement1.second = 0.0; auto cElement2 = statVector[0][i]; - cElement2.first = "SliceWise Var. " + cElement2.first; + cElement2.first.name = "SliceWise Var. " + cElement2.first.name; + cElement2.first.legacyName = this->GenerateLegacyFeatureName(cElement2.first); cElement2.second = 0.0; statMean.push_back(cElement1); statStd.push_back(cElement2); } for (auto cStat : statVector) { for (std::size_t i = 0; i < cStat.size(); ++i) { statMean[i].second += cStat[i].second / (1.0*statVector.size()); } } for (auto cStat : statVector) { for (std::size_t i = 0; i < cStat.size(); ++i) { statStd[i].second += (cStat[i].second - statMean[i].second)*(cStat[i].second - statMean[i].second) / (1.0*statVector.size()); } } for (auto cStat : statVector) { std::copy(cStat.begin(), cStat.end(), std::back_inserter(result)); } std::copy(statMean.begin(), statMean.end(), std::back_inserter(result)); std::copy(statStd.begin(), statStd.end(), std::back_inserter(result)); return result; } + +void mitk::AbstractGlobalImageFeature::CalculateAndAppendFeatures(const Image* image, const Image* mask, const Image* maskNoNAN, FeatureListType& featureList, bool checkParameterActivation) +{ + auto parsedArgs = this->GetParameters(); + + if (!checkParameterActivation || parsedArgs.count(this->GetLongName())) + { + auto result = this->CalculateFeatures(image, mask, maskNoNAN); + featureList.insert(featureList.end(), result.begin(), result.end()); + } +} + +mitk::AbstractGlobalImageFeature::FeatureListType mitk::AbstractGlobalImageFeature::CalculateFeatures(const Image* image, const Image* mask) +{ + auto result = this->DoCalculateFeatures(image, mask); + + //ensure legacy names + for (auto& feature : result) + { + feature.first.legacyName = this->GenerateLegacyFeatureName(feature.first); + } + + return result; +} + +std::string mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(const mitk::FeatureID& id) +{ + std::string result; + + if (id.name.find("SliceWise") == 0) + { + result = id.name.substr(0, 14) + " " + id.featureClass + "::" + id.name.substr(15, -1); + } + else + { + result = id.featureClass + "::" + id.name; + } + + return result; +} diff --git a/Modules/Classification/CLCore/src/mitkIntensityQuantifier.cpp b/Modules/Classification/CLCore/src/mitkIntensityQuantifier.cpp index 194d3bf175..0541393450 100644 --- a/Modules/Classification/CLCore/src/mitkIntensityQuantifier.cpp +++ b/Modules/Classification/CLCore/src/mitkIntensityQuantifier.cpp @@ -1,195 +1,195 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // STD #include // ITK #include // MITK #include #include template static void -CalculateImageMinMax(itk::Image* itkImage, double &minimum, double &maximum) +CalculateImageMinMax(const 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) +CalculateImageRegionMinMax(const itk::Image* itkImage, const mitk::Image* 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) { +void mitk::IntensityQuantifier::InitializeByImage(const Image* 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) { +void mitk::IntensityQuantifier::InitializeByImageAndMinimum(const Image* 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) { +void mitk::IntensityQuantifier::InitializeByImageAndMaximum(const Image* 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) { +void mitk::IntensityQuantifier::InitializeByImageRegion(const Image* image, const Image* 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) { +void mitk::IntensityQuantifier::InitializeByImageRegionAndMinimum(const Image* image, const Image* 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) { +void mitk::IntensityQuantifier::InitializeByImageRegionAndMaximum(const Image* image, const Image* 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) { +void mitk::IntensityQuantifier::InitializeByImageAndBinsize(const Image* 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) { +void mitk::IntensityQuantifier::InitializeByImageAndBinsizeAndMinimum(const Image* 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) { +void mitk::IntensityQuantifier::InitializeByImageAndBinsizeAndMaximum(const Image* 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) { +void mitk::IntensityQuantifier::InitializeByImageRegionAndBinsize(const Image* image, const Image* 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) { +void mitk::IntensityQuantifier::InitializeByImageRegionAndBinsizeAndMinimum(const Image* image, const Image* 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) { +void mitk::IntensityQuantifier::InitializeByImageRegionAndBinsizeAndMaximum(const Image* image, const Image* 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::max(0, 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/CLMiniApps/CLGlobalImageFeatures.cpp b/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp index 84a04d1522..76b347d77a 100644 --- a/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp +++ b/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp @@ -1,758 +1,789 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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 #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 short, 3 > MaskImageType; template class punct_facet : public std::numpunct { public: punct_facet(charT sep) : m_Sep(sep) { } protected: charT do_decimal_point() const override { 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 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 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); auto 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[]) { // Commented : Updated to a common interface, include, if possible, mask is type unsigned short, uses Quantification, Comments // Name follows standard scheme with Class Name::Feature Name // Commented 2: Updated to use automatic inclusion of list of parameters if required. mitk::GIFImageDescriptionFeatures::Pointer ipCalculator = mitk::GIFImageDescriptionFeatures::New(); // Commented 2, Tested mitk::GIFFirstOrderStatistics::Pointer firstOrderCalculator = mitk::GIFFirstOrderStatistics::New(); //Commented 2 mitk::GIFFirstOrderHistogramStatistics::Pointer firstOrderHistoCalculator = mitk::GIFFirstOrderHistogramStatistics::New(); // Commented 2, Tested mitk::GIFFirstOrderNumericStatistics::Pointer firstOrderNumericCalculator = mitk::GIFFirstOrderNumericStatistics::New(); // Commented 2, Tested mitk::GIFVolumetricStatistics::Pointer volCalculator = mitk::GIFVolumetricStatistics::New(); // Commented 2, Tested mitk::GIFVolumetricDensityStatistics::Pointer voldenCalculator = mitk::GIFVolumetricDensityStatistics::New(); // Commented 2, Tested mitk::GIFCooccurenceMatrix::Pointer coocCalculator = mitk::GIFCooccurenceMatrix::New(); // Commented 2, Will not be tested mitk::GIFCooccurenceMatrix2::Pointer cooc2Calculator = mitk::GIFCooccurenceMatrix2::New(); //Commented 2 mitk::GIFNeighbouringGreyLevelDependenceFeature::Pointer ngldCalculator = mitk::GIFNeighbouringGreyLevelDependenceFeature::New(); //Commented 2, Tested mitk::GIFGreyLevelRunLength::Pointer rlCalculator = mitk::GIFGreyLevelRunLength::New(); // Commented 2 mitk::GIFGreyLevelSizeZone::Pointer glszCalculator = mitk::GIFGreyLevelSizeZone::New(); // Commented 2, Tested mitk::GIFGreyLevelDistanceZone::Pointer gldzCalculator = mitk::GIFGreyLevelDistanceZone::New(); //Commented 2, Tested mitk::GIFLocalIntensity::Pointer lociCalculator = mitk::GIFLocalIntensity::New(); //Commented 2, Tested mitk::GIFIntensityVolumeHistogramFeatures::Pointer ivohCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); // Commented 2 mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::Pointer ngtdCalculator = mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::New(); //Commented 2, Tested mitk::GIFCurvatureStatistic::Pointer curvCalculator = mitk::GIFCurvatureStatistic::New(); //Commented 2, Tested std::vector features; features.push_back(volCalculator.GetPointer()); features.push_back(voldenCalculator.GetPointer()); features.push_back(curvCalculator.GetPointer()); features.push_back(firstOrderCalculator.GetPointer()); features.push_back(firstOrderNumericCalculator.GetPointer()); features.push_back(firstOrderHistoCalculator.GetPointer()); features.push_back(ivohCalculator.GetPointer()); features.push_back(lociCalculator.GetPointer()); features.push_back(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)."); + parser.addArgument("output-mode", "omode", mitkCommandLineParser::Int, "Int", "Defines the format of the output. 0: (Default) results of an image / slice are written in a single row;" + " 1: results of an image / slice are written in a single column; 2: store the result of on image as structured radiomocs report (XML)."); // 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("German Cancer Research Center (DKFZ)"); 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"; + std::string version = "Version: 1.23"; MITK_INFO << version; std::ofstream log; if (param.useLogfile) { log.open(param.logfilePath, std::ios::app); log << std::endl; 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::Load(param.imagePath); - mitk::Image::Pointer tmpMask = mitk::IOUtil::Load(param.maskPath); - image = tmpImage; - mask = tmpMask; + //representing the original loaded image data without any prepropcessing that might come. + mitk::Image::Pointer loadedImage = mitk::IOUtil::Load(param.imagePath); + //representing the original loaded mask data without any prepropcessing that might come. + mitk::Image::Pointer loadedMask = mitk::IOUtil::Load(param.maskPath); + + mitk::Image::Pointer image = loadedImage; + mitk::Image::Pointer mask = loadedMask; + + mitk::Image::Pointer tmpImage = loadedImage; + mitk::Image::Pointer tmpMask = loadedMask; mitk::Image::Pointer morphMask = mask; if (param.useMorphMask) { morphMask = mitk::IOUtil::Load(param.morphPath); } log << " Check for Dimensions -"; 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"]); } log << " Check for Resolution -"; if (param.resampleToFixIsotropic) { mitk::Image::Pointer newImage = mitk::Image::New(); AccessByItk_2(image, ResampleImage, param.resampleResolution, newImage); image = newImage; } + + log << " Resample if required -"; + if (param.resampleMask) + { + mitk::Image::Pointer newMaskImage = mitk::Image::New(); + AccessByItk_2(mask, ResampleMask, image, newMaskImage); + mask = newMaskImage; + } + 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; } } - log << " Resample if required -"; - if (param.resampleMask) - { - mitk::Image::Pointer newMaskImage = mitk::Image::New(); - AccessByItk_2(mask, ResampleMask, image, newMaskImage); - mask = newMaskImage; - } - log << " Check for Equality -"; if ( ! mitk::Equal(mask->GetGeometry(0)->GetSpacing(), image->GetGeometry(0)->GetSpacing())) { MITK_INFO << "Not equal Spacing"; 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"; } log << " Configure features -"; 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->SetParameters(parsedArgs); cFeature->SetDirection(direction); - cFeature->SetEncodeParameters(param.encodeParameter); + cFeature->SetEncodeParametersInFeaturePrefix(param.encodeParameter); } bool addDescription = parsedArgs.count("description"); - mitk::cl::FeatureResultWritter writer(param.outputPath, writeDirection); + mitk::cl::FeatureResultWriter 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; log << " Begin Processing -"; 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) { log << " Calculating " << cFeature->GetFeatureClassName() << " -"; cFeature->SetMorphMask(cMorphMask); - cFeature->CalculateFeaturesUsingParameters(cImage, cMask, cMaskNoNaN, stats); + cFeature->CalculateAndAppendFeatures(cImage, cMask, cMaskNoNaN, stats, !param.calculateAllFeatures); } for (std::size_t i = 0; i < stats.size(); ++i) { - std::cout << stats[i].first << " - " << stats[i].second << std::endl; + std::cout << stats[i].first.legacyName << " - " << 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; } log << " Process Slicewise -"; 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.first.legacyName = "SliceWise Mean " + cElement1.first.legacyName; cElement1.second = 0.0; auto cElement2 = allStats[0][i]; - cElement2.first = "SliceWise Var. " + cElement2.first; + cElement2.first.legacyName = "SliceWise Var. " + cElement2.first.legacyName; 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; + std::cout << statMean[i].first.legacyName << " - " << statMean[i].second << std::endl; + std::cout << statStd[i].first.legacyName << " - " << 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); } + int returnCode = EXIT_SUCCESS; + + if (!param.outputXMLPath.empty()) + { + if (sliceWise) + { + MITK_ERROR << "Xml output is not supported in slicewise mode"; + returnCode = EXIT_FAILURE; + } + else + { + mitk::cl::CLResultXMLWriter xmlWriter; + xmlWriter.SetCLIArgs(parsedArgs); + xmlWriter.SetFeatures(allStats.front()); + xmlWriter.SetImage(loadedImage); + xmlWriter.SetMask(loadedMask); + xmlWriter.SetMethodName("CLGlobalImageFeatures"); + xmlWriter.SetMethodVersion(version + "(mitk: " MITK_VERSION_STRING+")"); + xmlWriter.SetOrganisation("German Cancer Research Center (DKFZ)"); + xmlWriter.SetPipelineUID(param.pipelineUID); + xmlWriter.write(param.outputXMLPath); + } + } + if (param.useLogfile) { log << "Finished calculation" << std::endl; log.close(); } - return 0; + return returnCode; } #endif diff --git a/Modules/Classification/CLUtilities/CMakeLists.txt b/Modules/Classification/CLUtilities/CMakeLists.txt index 1a57c99513..0061dac5ba 100644 --- a/Modules/Classification/CLUtilities/CMakeLists.txt +++ b/Modules/Classification/CLUtilities/CMakeLists.txt @@ -1,14 +1,14 @@ mitk_create_module( - DEPENDS MitkCore MitkCLCore MitkCommandLine - PACKAGE_DEPENDS PUBLIC Eigen + DEPENDS MitkCore MitkCLCore MitkCommandLine MitkDICOMReader + PACKAGE_DEPENDS PUBLIC Eigen PRIVATE tinyxml ) if(TARGET ${MODULE_TARGET}) if(MITK_USE_OpenMP) target_link_libraries(${MODULE_TARGET} PUBLIC OpenMP::OpenMP_CXX) endif() if(BUILD_TESTING) add_subdirectory(test) endif() endif() diff --git a/Modules/Classification/CLUtilities/files.cmake b/Modules/Classification/CLUtilities/files.cmake index 64e037b845..6295ba3e1e 100644 --- a/Modules/Classification/CLUtilities/files.cmake +++ b/Modules/Classification/CLUtilities/files.cmake @@ -1,39 +1,40 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES - mitkCLResultWritter.cpp + mitkCLResultWriter.cpp + mitkCLResultXMLWriter.cpp Algorithms/itkLabelSampler.cpp Algorithms/itkSmoothedClassProbabilites.cpp Algorithms/mitkRandomImageSampler.cpp Features/itkNeighborhoodFunctorImageFilter.cpp Features/itkLineHistogramBasedMassImageFilter.cpp GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp GlobalImageFeatures/mitkGIFNeighbourhoodGreyLevelDifference.cpp GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp GlobalImageFeatures/mitkGIFLocalIntensity.cpp GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp GlobalImageFeatures/mitkGIFCurvatureStatistic.cpp MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp MiniAppUtils/mitkSplitParameterToVector.cpp mitkCLUtil.cpp ) set( TOOL_FILES ) diff --git a/Modules/Classification/CLUtilities/include/mitkCLResultWritter.h b/Modules/Classification/CLUtilities/include/mitkCLResultWriter.h similarity index 88% rename from Modules/Classification/CLUtilities/include/mitkCLResultWritter.h rename to Modules/Classification/CLUtilities/include/mitkCLResultWriter.h index abb5a76cb3..2b4c5c40c5 100644 --- a/Modules/Classification/CLUtilities/include/mitkCLResultWritter.h +++ b/Modules/Classification/CLUtilities/include/mitkCLResultWriter.h @@ -1,59 +1,59 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#ifndef mitkCLResultWritter_h -#define mitkCLResultWritter_h +#ifndef mitkCLResultWriter_h +#define mitkCLResultWriter_h #include "MitkCLUtilitiesExports.h" #include #include #include #include namespace mitk { namespace cl { - class MITKCLUTILITIES_EXPORT FeatureResultWritter + class MITKCLUTILITIES_EXPORT FeatureResultWriter { public: - FeatureResultWritter(std::string, int mode); - ~FeatureResultWritter(); + FeatureResultWriter(std::string, int mode); + ~FeatureResultWriter(); void SetDecimalPoint(char decimal); void AddSubjectInformation(std::string value); void AddColumn(std::string value); void AddColumn(double value); void NewRow(std::string endName); void AddResult(std::string desc, int slice, mitk::AbstractGlobalImageFeature::FeatureListType stats, bool , bool withDescription); void AddHeader(std::string, int slice, mitk::AbstractGlobalImageFeature::FeatureListType stats, bool withHeader, bool withDescription); private: int m_Mode; std::size_t m_CurrentRow; int m_CurrentElement; std::string m_Separator; std::ofstream m_Output; std::vector m_List; std::string m_SubjectInformation; bool m_UsedSubjectInformation; bool m_UseSpecialDecimalPoint; char m_DecimalPoint; }; } } #endif //mitkCLResultWritter_h diff --git a/Modules/Classification/CLUtilities/include/mitkCLResultXMLWriter.h b/Modules/Classification/CLUtilities/include/mitkCLResultXMLWriter.h new file mode 100644 index 0000000000..73f805ae06 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/mitkCLResultXMLWriter.h @@ -0,0 +1,60 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#ifndef mitkCLResultXMLWriter_h +#define mitkCLResultXMLWriter_h + +#include "MitkCLUtilitiesExports.h" + +#include "mitkImage.h" +#include "mitkAbstractGlobalImageFeature.h" + +namespace mitk +{ + namespace cl + { + class MITKCLUTILITIES_EXPORT CLResultXMLWriter + { + public: + CLResultXMLWriter() = default; + ~CLResultXMLWriter() = default; + + void SetImage(const Image* image); + void SetMask(const Image* mask); + void SetFeatures(const mitk::AbstractGlobalImageFeature::FeatureListType& features); + + void SetMethodName(const std::string& name); + void SetMethodVersion(const std::string& version); + void SetOrganisation(const std::string& orga); + void SetPipelineUID(const std::string& pipelineUID); + void SetCLIArgs(const std::map& args); + + void write(const std::string& filePath) const; + void write(std::ostream& stream) const; + + private: + CLResultXMLWriter(const CLResultXMLWriter&) = delete; + CLResultXMLWriter& operator = (const CLResultXMLWriter&) = delete; + + Image::ConstPointer m_Image; + Image::ConstPointer m_Mask; + mitk::AbstractGlobalImageFeature::FeatureListType m_Features; + std::string m_MethodName = "unknown"; + std::string m_MethodVersion = "unknown"; + std::string m_Organisation = "unknown"; + std::string m_PipelineUID = "unknown"; + std::map m_CLIArgs; + }; + } +} + +#endif //mitkCLResultXMLWriter_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix.h b/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix.h index 122350b4d4..e6bace87b8 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix.h @@ -1,74 +1,63 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; + itkGetConstMacro(Ranges, std::vector); + void SetRanges(std::vector ranges); + void SetRange(double range); - itkGetConstMacro(Range,double); - itkSetMacro(Range, double); + void AddArguments(mitkCommandLineParser& parser) const override; - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; + protected: + std::string GenerateLegacyFeatureNamePart(const FeatureID& id) const override; + std::string GenerateLegacyFeatureEncoding(const FeatureID& id) const override; - struct GIFCooccurenceMatrixConfiguration - { - double range; - unsigned int direction; + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; - double MinimumIntensity; - bool UseMinimumIntensity; - double MaximumIntensity; - bool UseMaximumIntensity; - int Bins; - }; + void ConfigureSettingsByParameters(const ParametersType& parameters) override; - private: - double m_Range; + private: + std::vector m_Ranges; }; } #endif //mitkGIFCooccurenceMatrix_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h b/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h index 79852f8a0e..cdc333aca5 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h @@ -1,174 +1,162 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkGIFCooccurenceMatrix2_h #define mitkGIFCooccurenceMatrix2_h #include #include #include #include namespace mitk { /** * \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. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; - - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; - - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; - std::string GetCurrentFeatureEncoding() override; - - itkGetConstMacro(Range,double); - itkSetMacro(Range, double); - - struct GIFCooccurenceMatrix2Configuration - { - double range; - unsigned int direction; - - double MinimumIntensity; - double MaximumIntensity; - int Bins; - std::string prefix; - }; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; + + itkGetConstMacro(Ranges, std::vector); + void SetRanges(std::vector ranges); + void SetRange(double range); + + void AddArguments(mitkCommandLineParser& parser) const override; + + protected: + std::string GenerateLegacyFeatureEncoding(const FeatureID& id) const override; + + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; + + void ConfigureSettingsByParameters(const ParametersType& parameters) override; private: - double m_Range; + std::vector m_Ranges; }; } #endif //mitkGIFCooccurenceMatrix2_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFCurvatureStatistic.h b/Modules/Classification/CLUtilities/include/mitkGIFCurvatureStatistic.h index c99fc58d7d..d2e8b022cc 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFCurvatureStatistic.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFCurvatureStatistic.h @@ -1,104 +1,98 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkGIFCurvatureStatistic_h #define mitkGIFCurvatureStatistic_h #include #include #include namespace mitk { /** * \brief Calculates features based on the co-occurence matrix. * * The Curvature is a measure for the bending of a surface and is therefore a measure for the description of the * surface of an segmentation. * * THe curvature is calculated for each point of the surface of the given object and then a combined measure is * produced. It measures the divergence of the orientation of an curve from the * tangent of the curve. There are multiple ways to calculate the Curvature: * * Gaussian Curvature: The discrete gaussian curvature (K) is computed as \f$K(\textup{Corner Point v}) = 2 * \pi - \sum_{\textup{Neighoubring Voxel Surfaces f of v}} (\textup{Angle}_f \textup{at} v) \f$. * Mean Curvature:The mean curvature (H) is computed as \f$H(\textup{Corner Point v}) = \textup{average over edges e neighbouring v of H(e)} \f$. * with \f$H(edge e) = length(e)*dihedral_angle(e)\f$ * Maximum (\f$k_max\f$) and Minimum (\f$k_min\f$) Principal Curvatures * \f$k_max = H + sqrt(H^2 - K)\f$ * \f$k_min = H - sqrt(H^2 - K)\f$ * Excepting spherical and planar surfaces which have equal principal curvatures, * the curvature at a point on a surface varies with the direction one "sets off" * from the point. For all directions, the curvature will pass through two extrema: * a minimum (\f$k_min\f$) and a maximum (\f$k_max\f$) which occur at mutually orthogonal * directions to each other. * * This method does not take any parameters. * * This feature calculator is activated by the option -curvature or -cur. * * The features are calculated based on a mask, which is converted into a mesh. * * The following features are defined. All features are calculated for all four possible * curvation calculation methods (Gaussian, Mean, Minimum, Maximum). The principal way * of calculating these features is the same, the used curvation is indicated by in the * feature name: * * - Curvature Feature::Minimum Curvature: * The minimum curvature for the whole given mask * - Curvature Feature::Maximum Curvature: * The maximum curvature for the whole given mask * - Curvature Feature::Mean Curvature: * The mean curvature for the whole given mask * - Curvature Feature::Standard Deviation Curvature: * The standard deviation curvature for the whole given mask * - Curvature Feature::Skewness Curvature: * The skewness curvature for the whole given mask * - Curvature Feature::Mean Positive Curvature: * The mean curvature of all positive curvatures from the whole given mask * - Curvature Feature::Standard Deviation Positive Curvature: * The Standard Deviation curvature of all positive curvatures from the whole given mask * - Curvature Feature::Skewness Positive Curvature: * The Skewness curvature of all positive curvatures from the whole given mask * - Curvature Feature::Mean Negative Curvature: * The mean curvature of all Negative curvatures from the whole given mask * - Curvature Feature::Standard Deviation Negative Curvature: * The Standard Deviation curvature of all Negative curvatures from the whole given mask * - Curvature Feature::Skewness Negative Curvature: * The Skewness curvature of all Negative curvatures from the whole given mask */ class MITKCLUTILITIES_EXPORT GIFCurvatureStatistic : public AbstractGlobalImageFeature { public: mitkClassMacro(GIFCurvatureStatistic,AbstractGlobalImageFeature); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - GIFCurvatureStatistic(); + GIFCurvatureStatistic(); - /** - * \brief Calculates the Cooccurence-Matrix based features for this class. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; + void AddArguments(mitkCommandLineParser &parser) const override; - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; + protected: - private: + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; }; } #endif //mitkGIFCurvatureStatistic_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderHistogramStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderHistogramStatistics.h index 7e8dc8da19..21c6bb2727 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderHistogramStatistics.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderHistogramStatistics.h @@ -1,126 +1,109 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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: * - First Order Histogram::Mean Value: The mean intensity of all voxels, calulated by \f$ \mu_x = \sum p_i x_i\f$. * - First Order Histogram::Variance Value The variance intensity is calculated as : \f$ \sigma^2 = \sum p_i (x_i - \mu_x)^2\f$. * - First Order Histogram::Skewness Value: \f[ skewness = \frac{\sum p_i (x_i - \mu_x)^3}{\sigma^3} \f] * - First Order Histogram::Excess Kurtosis Value: \f[ skewness = \frac{\sum p_i (x_i - \mu_x)^4}{\sigma^4} - 3 \f] * - First Order Histogram::Median Value: The median intensity value based on the histogram values. * - First Order Histogram::Minimum Value: The minimum observed intensity value. * - First Order Histogram::Percentile 10 Value: The intensity that is equal or greater than 10% of all observed intensities. * - First Order Histogram::Percentile 90 Value: The intensity that is equal or greater than 90% of all observed intensities. * - First Order Histogram::Maximum Value: The maximum observerd intensity value. * - First Order Histogram::Mode Value: The most common intensity value, i.e. the value of the bin with the highest probability. * - First Order Histogram::Interquantile Range Value: The intensity difference between Percentile 75% (\f$ P75\f$) and Percentile 25% (\f$ P25\f$). * - First Order Histogram::Range Value: The difference between the observed maximum and minimum intensity. * - First Order Histogram::Mean Absolute Deviation Value: \f[ \textup{mean absolute deviation} = \sum p_i \left \| (x_i - \mu_x) \right \| \f] * - First Order Histogram::Robust Mean Value: The mean of all intensities between the 10% and 90% quantile. * - First Order Histogram::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. * - First Order Histogram::Median Absolute Deviation Value: \f[ \textup{mean absolute deviation} = \sum p_i \left \| (x_i - \textup{median}) \right \| \f] * - First Order Histogram::Coefficient of Variation Value: \f[ \frac{\sigma_x}{\mu_x} \f] * - First Order Histogram::Quantile coefficient of Dispersion Value: \f[ \textup{Quantile coefficient of Dispersion} = \frac{P75 - P25}{P75 + P25} \f] * - First Order Histogram::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] * - First Order Histogram::Uniformity Value: \f$ \sum p_i^2 \f$ * - First Order Histogram::Mean Index: The mean index of all voxels, calulated by \f$ \mu_i = \sum p_i i\f$. * - First Order Histogram::Variance Index: The variance index is calculated as : \f$ \sigma_i^2 = \sum p_i (i - \mu_i)^2\f$. * - First Order Histogram::Skewness Index: \f[ skewness = \frac{\sum p_i (i - \mu_i)^3}{\sigma_i^3} \f] * - First Order Histogram::Excess Kurtosis Index: \f[ skewness = \frac{\sum p_i (i - \mu_i)^4}{\sigma_i^4} - 3 \f] * - First Order Histogram::Median Index: The median index value based on the histogram values. * - First Order Histogram::Minimum Index: The index of the minimum observed intensity value. * - First Order Histogram::Percentile 10 Index: The index oft the intensity that is equal or greater than 10% of all observed intensities. * - First Order Histogram::Percentile 90 Index: The index of the intensity that is equal or greater than 90% of all observed intensities. * - First Order Histogram::Maximum Index: The index of the maximum observerd intensity value. * - First Order Histogram::Mode Index: The index of the most common intensity value, i.e. the index of the bin with the highest probability. * - First Order Histogram::Interquantile Range Index: The index difference between Percentile 75% (\f$ P75\f$) and Percentile 25% (\f$ P25\f$). * - First Order Histogram::Range Index: The index difference between the index of the observed maximum and minimum intensity. * - First Order Histogram::Mean Absolute Deviation Index: \f[ \textup{mean absolute deviation} = \sum p_i \left \| (i - \mu_i) \right \| \f] * - First Order Histogram::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. * - First Order Histogram::Median Absolute Deviation Index: \f[ \textup{mean absolute deviation} = \sum p_i \left \| (i - \textup{median}) \right \| \f] * - First Order Histogram::Coefficient of Variation Index: \f[ \frac{\sigma_i}{\mu_i} \f] * - First Order Histogram::Quantile coefficient of Dispersion Index: \f[ \textup{Quantile coefficient of Dispersion} = \frac{P75 - P25}{P75 + P25} \f] * - First Order Histogram::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. * - First Order Histogram::Uniformity Index: \f$ \sum p_i^2 \f$. Note that this is the same as the uniformity value. * - First Order Histogram::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. * - First Order Histogram::Maximum Gradient Index: The index of the bin that belongs to the maximum gradient. * - First Order Histogram::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. * - First Order Histogram::Minimum Gradient Index:The index of the bin that belongs to the minimum gradient. * - First Order Histogram::Robust Mean Index: The mean index of all intensities between the 10% and 90% quantile. * - First Order Histogram::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. * - First Order Histogram::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. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - itkGetConstMacro(Range,double); - itkSetMacro(Range, double); + void AddArguments(mitkCommandLineParser& parser) const override; - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; - std::string GetCurrentFeatureEncoding() override; + protected: + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; - struct ParameterStruct { - double MinimumIntensity; - double MaximumIntensity; - int Bins; - std::string prefix; - }; - - private: - double m_Range; }; } #endif //mitkGIFFirstOrderHistogramStatistics_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h index ae3ca44567..4fdf5bceca 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h @@ -1,152 +1,146 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkGIFFirstNumericOrderStatistics_h #define mitkGIFFirstNumericOrderStatistics_h #include #include #include namespace mitk { class MITKCLUTILITIES_EXPORT GIFFirstOrderNumericStatistics : public AbstractGlobalImageFeature { public: /** * \brief Calculates first order statistics of the given image. * * The first order statistics for the intensity distribution within a given Region of Interest (ROI) * is caluclated. The ROI is defined using a mask. * * The features are calculated on a quantified image. If the bin-size is too big, the obtained values * can be errornous and missleading. It is therefore important to use enough bins. The binned approach is * used in order to avoid floating-point related errors. * * This feature calculator is activated by the option -first-order or -fo. * * The connected areas are based on the binned image, the binning parameters can be set via the default * parameters as described in AbstractGlobalImageFeature. It is also possible to determine the * dimensionality of the neighbourhood using direction-related commands as described in AbstractGlobalImageFeature. * No other options are possible beside these two options. * * The features are calculated based on a mask. It is assumed that the mask is * of the type of an unsigned short image. All voxels with the value 1 are treated as masked. * * The following features are then defined using the (binned) voxel intensity \f$ x_i \f$ of each voxel, the probability * an intensity \f$ p_x \f$, and the overall number of voxels within the mask \f$ N_v \f$: * - First Order::Mean: The mean intensity within the ROI * \f[ \textup{Mean}= \mu = \frac{1}{N_v} \sum x_i \f] * - First Order::Unbiased Variance: An unbiased estimation of the variance: * \f[ \textup{Unbiased Variance} = \frac{1}{N_v - 1} \sum \left( x_i - \mu \right)^2 \f] * - First Order::Biased Variance: An biased estimation of the variance. If not specified otherwise, this is * used as the variance: * \f[ \textup{Biased Variance} = \sigma^2 = \frac{1}{N_v} \sum \left( x_i - \mu \right)^2 \f] * - First Order::Unbiased Standard Deviation: Estimation of diversity within the intensity values * \f[ \textup{Unbiased Standard Deviation} = \sqrt{\frac{1}{N_v-1} \sum \left( x_i - \mu \right)^2} \f] * - First Order::Biased Standard Deviation: Estimation of diversity within the intensity values * \f[ \textup{Biased Standard Deviation} = \sigma = \sqrt{\frac{1}{N_v} \sum \left( x_i - \mu \right)^2} \f] * - First Order::Skewness: * \f[ \textup{Skewness} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^3}{\sigma^3} \f] * - First Order::Kurtosis: The kurtosis is a measurement of the peakness of the given * distirbution: * \f[ \textup{Kurtosis} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^4}{\sigma^4} \f] * - First Order::Excess Kurtosis: The kurtosis is a measurement of the peakness of the given * distirbution. The excess kurtosis is similar to the kurtosis, but is corrected by a fisher correction, * ensuring that a gaussian distribution has an excess kurtosis of 0. * \f[ \textup{Excess Kurtosis} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^4}{\sigma^4} - 3 \f] * - First Order::Median: The median is defined as the median of the all intensities in the ROI. * - First Order::Minimum: The minimum is defined as the minimum of the all intensities in the ROI. * - First Order::05th Percentile: \f$ P_{5\%} \f$ The 5% percentile. 5% of all voxel do have this or a lower intensity. * - First Order::10th Percentile: \f$ P_{10\%} \f$ The 10% percentile. 10% of all voxel do have this or a lower intensity. * - First Order::15th Percentile: \f$ P_{15\%} \f$ The 15% percentile. 15% of all voxel do have this or a lower intensity. * - First Order::20th Percentile: \f$ P_{20\%} \f$ The 20% percentile. 20% of all voxel do have this or a lower intensity. * - First Order::25th Percentile: \f$ P_{25\%} \f$ The 25% percentile. 25% of all voxel do have this or a lower intensity. * - First Order::30th Percentile: \f$ P_{30\%} \f$ The 30% percentile. 30% of all voxel do have this or a lower intensity. * - First Order::35th Percentile: \f$ P_{35\%} \f$ The 35% percentile. 35% of all voxel do have this or a lower intensity. * - First Order::40th Percentile: \f$ P_{40\%} \f$ The 40% percentile. 40% of all voxel do have this or a lower intensity. * - First Order::45th Percentile: \f$ P_{45\%} \f$ The 45% percentile. 45% of all voxel do have this or a lower intensity. * - First Order::50th Percentile: \f$ P_{50\%} \f$ The 50% percentile. 50% of all voxel do have this or a lower intensity. * - First Order::55th Percentile: \f$ P_{55\%} \f$ The 55% percentile. 55% of all voxel do have this or a lower intensity. * - First Order::60th Percentile: \f$ P_{60\%} \f$ The 60% percentile. 60% of all voxel do have this or a lower intensity. * - First Order::65th Percentile: \f$ P_{65\%} \f$ The 65% percentile. 65% of all voxel do have this or a lower intensity. * - First Order::70th Percentile: \f$ P_{70\%} \f$ The 70% percentile. 70% of all voxel do have this or a lower intensity. * - First Order::75th Percentile: \f$ P_{75\%} \f$ The 75% percentile. 75% of all voxel do have this or a lower intensity. * - First Order::80th Percentile: \f$ P_{80\%} \f$ The 80% percentile. 80% of all voxel do have this or a lower intensity. * - First Order::85th Percentile: \f$ P_{85\%} \f$ The 85% percentile. 85% of all voxel do have this or a lower intensity. * - First Order::90th Percentile: \f$ P_{90\%} \f$ The 90% percentile. 90% of all voxel do have this or a lower intensity. * - First Order::95th Percentile: \f$ P_{95\%} \f$ The 95% percentile. 95% of all voxel do have this or a lower intensity. * - First Order::Maximum: The maximum is defined as the minimum of the all intensities in the ROI. * - First Order::Range: The range of intensity values is defined as the difference between the maximum * and minimum intensity in the ROI. * - First Order::Interquartile Range: The difference between the 75% and 25% quantile. * - First Order::Mean Absolute Deviation: The mean absolute deviation gives the mean distance of each * voxel intensity to the overal mean intensity and is a measure of the dispersion of the intensity form the * mean value: * \f[ \textup{Mean Absolute Deviation} = \frac{1}{N_v} \sum \left \| x_i - \mu \right \| \f] * - First Order::Robust Mean: The mean intensity within the ROI for all voxels between the 10% and 90% quantile: * \f[ \textup{Robust Mean}= \mu_R = \frac{1}{N_{vr}} \sum x_i \f] * - First Order::Robust Mean Absolute Deviation: The absolute deviation of all intensities within the ROI for * all voxels between the 10% and 90% quantilefrom the robust mean intensity: * \f[ \textup{Robust Mean Absolute Deviation}= \mu_R = \frac{1}{N_{vr}} \sum \left \| x_i - \mu_R \right \| \f] * - First Order::Median Absolute Deviation: Similar to the mean absolute deviation, but uses the median * instead of the mean to measure the center of the distribution. * - First Order::Coefficient Of Variation: Measures the dispersion of the intensity distribution: * \f[ \textup{Coefficient Of Variation} = \frac{sigma}{\mu} \f] * - First Order::Quantile Coefficient Of Dispersion: A robust alternative to teh coefficient of variance: * \f[ \textup{Quantile Coefficient Of Dispersion} = \frac{P_{75\%} - P_{25\%} }{P_{75\%} + P_{25\%}} \f] * - First Order::Energy: The intensity energy: * \f[ \textup{Energy} = \sum x_i ^2 \f] * - First Order::Root Mean Square: Root mean square is an important measure for the error. * \f[ \textup{Root Mean Square} = \sqrt{\frac{\sum x_i ^2}{N_v}} \f] * - First Order::Uniformity: * \f[ \textup{Uniformity} = \sum p_x^2 \f] * - First Order::Entropy: * \f[ \textup{Entropy} = - \sum p_x \textup{log}_2(p_x) \f] * - First Order::Entropy: * \f[ \textup{Entropy} = - \sum p_x \textup{log}_2(p_x) \f] * - First Order::Covered Image Intensity Range: Percentage of the image intensity range (maximum - minimum in whole * image) that is covered by the ROI. * - First Order::Sum: The sum of all intensities. It is correlated to the mean intensity. * \f[ \textup{Sum} = \sum x_i \f] * - First Order::Mode: The most common intensity. * - First Order::Mode Probability: The likelihood of the most common intensity. * - First Order::Number Of Voxels: \f$ N_v \f$ the number of voxels covered by the ROI. * - First Order::Image Dimension: The dimensionality of the image (e.g. 2D, 3D, etc.). * - First Order::Number Of Voxels: The product of all spacing along all dimensions. In 3D, this is equal to the * volume. * - First Order::Number Of Voxels: The volume of a single voxel. If the dimensionality is only 2D, this is the * surface of an voxel. */ mitkClassMacro(GIFFirstOrderNumericStatistics,AbstractGlobalImageFeature); itkFactorylessNewMacro(Self); itkCloneMacro(Self); GIFFirstOrderNumericStatistics(); - /** - * \brief Calculates the First Order Features based on a binned version of the image. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; - std::string GetCurrentFeatureEncoding() override; + void AddArguments(mitkCommandLineParser& parser) const override; - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; + protected: + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; }; } #endif //mitkGIFFirstNumericOrderStatistics_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderStatistics.h index ea3951b622..844b8a31f7 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderStatistics.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderStatistics.h @@ -1,160 +1,145 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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 First Order Features based on a binned version of the image. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; - - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; - std::string GetCurrentFeatureEncoding() override; - - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; - + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - struct ParameterStruct { - double MinimumIntensity; - double MaximumIntensity; - int Bins; - std::string prefix; - }; + void AddArguments(mitkCommandLineParser& parser) const override; + protected: + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; }; } #endif //mitkGIFFirstOrderStatistics_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelDistanceZone.h b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelDistanceZone.h index 36382c6b7f..bae7c2269a 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelDistanceZone.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelDistanceZone.h @@ -1,190 +1,168 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkGIFGreyLevelDistanceZone_h #define mitkGIFGreyLevelDistanceZone_h #include #include #include #include namespace mitk { 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. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; + void AddArguments(mitkCommandLineParser& parser) const override; - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; - - std::string GetCurrentFeatureEncoding() override; - - struct GIFGreyLevelDistanceZoneConfiguration - { - mitk::Image::Pointer distanceMask; - - mitk::IntensityQuantifier::Pointer Quantifier; - - unsigned int direction; - double MinimumIntensity; - double MaximumIntensity; - int Bins; - std::string prefix; - }; - - private: + protected: + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; }; } #endif //mitkGIFGreyLevelDistanceZone_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelRunLength.h b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelRunLength.h index 84a57b3bea..1ad7047818 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelRunLength.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelRunLength.h @@ -1,131 +1,112 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkGIFGreyLevelRunLength_h #define mitkGIFGreyLevelRunLength_h #include #include #include namespace mitk { /** * \brief Calculates the Run Length based features. * * Grey Level Run Length based features are calcualted using the Run-Length-Matrix and were originally * defined by Galloway (1975). The basic idea behind this feature is to measure the length of * lines with similar intensity in an image. This allows to asses line-based structures in an image. * For this, the Run-Length-Matrix created that gives the number of lines \f$ m_{x,l} \f$ with the intensity \f$ x \f$ and * the length of \f$ l \f$ 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 -run-length or -rl. * * The features are calculated based on a mask. It is assumed that the mask is * of the same type as the input image. All voxels with a value greater 0.5 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 lines, \f$ m_{x,\cdot} = \sum_l m{x,l} \f$ is the number of all lines * with a given intensity value, and likewise \f$ m_{\cdot, l} = \sum_x m{x,l} \f$ is the number of all lines * with a given length. There are two options how to make this feature orientation-invariant. Either calculating a * single matrix for all directions and then extracting the features or by calculating a matrix per direction, * calculating all features and then reporting the mean and standard deviation for each feature. The result * of the first option is given with the extension "Comb.", the results for the second with "Std." and "Means". * All three options are always calculated, although we state only one in the following list: * - Run Length::Short run emphasis Comb.: * \f[ \textup{Short run emphasis}= \frac{1}{N_s} \sum_l { \frac{m_{\cdot, l}}{l^2} } \f] * - Run Length::Long run emphasis Comb.: * \f[ \textup{Long run emphasis}= \frac{1}{N_s} \sum_l { m_{\cdot, l} l^2} \f] * - Run Length::Low grey level run emphasis Comb.: * \f[ \textup{Low grey level run emphasis}= \frac{1}{N_s} \sum_x { \frac{m_{x,\cdot}}{x^2} } \f] * - Run Length::High grey level run emphasis Comb.: * \f[ \textup{High grey level run emphasis}= \frac{1}{N_s} \sum_x { m_{x,\cdot} x^2} \f] * - Run Length::Short run low grey level emphasis Comb.: * \f[ \textup{Short run low grey level emphasis}= \frac{1}{N_s} \sum_x \sum_l { \frac{m_{x,l}}{x^2 l^2} } \f] * - Run Length::Short run high grey level emphasis Comb.: * \f[ \textup{Short run high grey level emphasis}= \frac{1}{N_s} \sum_x \sum_l { \frac{x^2 m_{x,s}}{l^2} } \f] * - Run Length::Long run low grey level emphasis Comb.: * \f[ \textup{Long run low grey level emphasis}= \frac{1}{N_s} \sum_x \sum_l { \frac{l^2 m_{x,l}}{x^2} } \f] * - Run Length::Long run high grey level emphasis Comb.: * \f[ \textup{Long run high grey level emphasis}= \frac{1}{N_s} \sum_x \sum_l { x^2 l^2 m_{x,l} } \f] * - Run Length::Grey level nonuniformity Comb.: * \f[ \textup{Grey level nonuniformity}= \frac{1}{N_s} \sum_x m_{x,\cdot}^2 \f] * - Run Length::Grey level nonuniformity normalized Comb.: * \f[ \textup{Grey level nonuniformity normalized}= \frac{1}{N_s^2} \sum_x m_{x,\cdot}^2 \f] * - Run Length::Run length nonuniformity: * \f[ \textup{Run length nonuniformity}= \frac{1}{N_s} \sum_l m_{\cdot, l}^2 \f] * - Run Length::Run length nonuniformity normalized: * \f[ \textup{Run length nonuniformity normalized}= \frac{1}{N_s^2} \sum_l m_{\cdot, l}^2 \f] * - Run Length::Run percentage: The ratio of realized runs to the theoretical limit of zones: * \f[ \textup{Run percentage}= \frac{N_s}{N_v} \f] * - Run Length::Grey level variance: * \f[ \textup{Grey level variance} = \frac{1}{N_s} \sum_x (x -mu_x)^2 m_{x, \cdot} \f] * - Run Length::Run length variance: * \f[ \textup{Run length variance} = \frac{1}{N_s} \sum_l (l -mu_l)^2 m_{\cdot, l} \f] * - Run Length::Run length 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{Run length entropy} = \sum_x \sum_s p_{x,s} \textup{log}_2 \left( p{_x,s} \right) \f] * - Run Length::Number of runs: The overall number of realized runs: * \f[ \textup{Number of runs} = \sum m_{x, l} \f] */ class MITKCLUTILITIES_EXPORT GIFGreyLevelRunLength : public AbstractGlobalImageFeature { public: mitkClassMacro(GIFGreyLevelRunLength,AbstractGlobalImageFeature); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - GIFGreyLevelRunLength(); + GIFGreyLevelRunLength(); - /** - * \brief Calculates the Cooccurence-Matrix based features for this class. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; + void AddArguments(mitkCommandLineParser &parser) const override; - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; - - std::string GetCurrentFeatureEncoding() override; - - struct ParameterStruct - { - unsigned int m_Direction; - - double MinimumIntensity; - double MaximumIntensity; - int Bins; - std::string featurePrefix; - }; - - private: + protected: + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; }; } #endif //mitkGIFGreyLevelRunLength_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelSizeZone.h b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelSizeZone.h index 018a090c71..2fdaa255f8 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelSizeZone.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelSizeZone.h @@ -1,127 +1,112 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkGIFGreyLevelSizeZone_h #define mitkGIFGreyLevelSizeZone_h #include #include #include #include namespace mitk { 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. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; + void AddArguments(mitkCommandLineParser& parser) const override; - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; - std::string GetCurrentFeatureEncoding() override; + protected: - struct GIFGreyLevelSizeZoneConfiguration - { - unsigned int direction; - - double MinimumIntensity; - double MaximumIntensity; - int Bins; - std::string prefix; - }; + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; }; } #endif //mitkGIFGreyLevelSizeZone_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFImageDescriptionFeatures.h b/Modules/Classification/CLUtilities/include/mitkGIFImageDescriptionFeatures.h index 7e295a0e7f..89c6d4e4fb 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFImageDescriptionFeatures.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFImageDescriptionFeatures.h @@ -1,87 +1,82 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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::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 bounding box X: The distance between the maximum and minimum position of a masked voxel along the first axis. * - Diagnostic::Mask bounding box X: The distance between the maximum and minimum position of a masked voxel along the second axis. * - Diagnostic::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(); + GIFImageDescriptionFeatures(); - /** - * \brief Calculates the Cooccurence-Matrix based features for this class. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; + void AddArguments(mitkCommandLineParser& parser) const override; - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; + protected: + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; }; } #endif //mitkGIFImageDescriptionFeatures_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFIntensityVolumeHistogramFeatures.h b/Modules/Classification/CLUtilities/include/mitkGIFIntensityVolumeHistogramFeatures.h index a28c48a689..f190da4c40 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFIntensityVolumeHistogramFeatures.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFIntensityVolumeHistogramFeatures.h @@ -1,82 +1,76 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; - void AddArguments(mitkCommandLineParser &parser) override; + void AddArguments(mitkCommandLineParser& parser) const override; - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; + protected: - std::string GetCurrentFeatureEncoding() override; + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; }; } #endif //mitkGIFIntensityVolumeHistogramFeatures_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFLocalIntensity.h b/Modules/Classification/CLUtilities/include/mitkGIFLocalIntensity.h index feba7bb47a..c269edc56c 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFLocalIntensity.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFLocalIntensity.h @@ -1,78 +1,72 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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); + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); - GIFLocalIntensity(); + GIFLocalIntensity(); - /** - * \brief Calculates the Cooccurence-Matrix based features for this class. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; - - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; + itkGetConstMacro(Range, double); + itkSetMacro(Range, double); - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - std::string GetCurrentFeatureEncoding() override; + void AddArguments(mitkCommandLineParser& parser) const override; - itkGetConstMacro(Range, double); - itkSetMacro(Range, double); + protected: + std::string GenerateLegacyFeatureEncoding(const FeatureID& id) const override; + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; + void ConfigureSettingsByParameters(const ParametersType& parameters) override; private: - double m_Range; }; } #endif //mitkGIFLocalIntensity_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyLevelDifference.h b/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyLevelDifference.h index 9e477d91bd..5fcd775a3b 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyLevelDifference.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyLevelDifference.h @@ -1,63 +1,55 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkGIFNeighbourhoodGreyLevelDifference_h #define mitkGIFNeighbourhoodGreyLevelDifference_h #include #include #include namespace mitk { class MITKCLUTILITIES_EXPORT GIFNeighbourhoodGreyLevelDifference : public AbstractGlobalImageFeature { public: mitkClassMacro(GIFNeighbourhoodGreyLevelDifference,AbstractGlobalImageFeature); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - GIFNeighbourhoodGreyLevelDifference(); + GIFNeighbourhoodGreyLevelDifference(); - /** - * \brief Calculates the Cooccurence-Matrix based features for this class. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; + itkGetConstMacro(Ranges, std::vector); + void SetRanges(std::vector ranges); + void SetRange(double range); - itkGetConstMacro(Range,double); - itkSetMacro(Range, double); + itkGetConstMacro(UseCTRange, bool); + itkSetMacro(UseCTRange, bool); - itkGetConstMacro(UseCtRange, bool); - itkSetMacro(UseCtRange, bool); + void AddArguments(mitkCommandLineParser &parser) const override; - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; + protected: + std::string GenerateLegacyFeatureName(const FeatureID& id) const override; + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; - struct ParameterStruct - { - bool m_UseCtRange; - double m_Range; - unsigned int m_Direction; - }; + void ConfigureSettingsByParameters(const ParametersType& parameters) override; private: - double m_Range; - bool m_UseCtRange; + std::vector m_Ranges; + bool m_UseCTRange; }; } #endif //mitkGIFNeighbourhoodGreyLevelDifference_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h b/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h index 0929738d37..64298b1294 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h @@ -1,95 +1,90 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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); + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); - GIFNeighbourhoodGreyToneDifferenceFeatures(); + GIFNeighbourhoodGreyToneDifferenceFeatures(); - /** - * \brief Calculates the Cooccurence-Matrix based features for this class. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; - - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; + itkSetMacro(Range, int); + itkGetConstMacro(Range, int); - std::string GetCurrentFeatureEncoding() override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; + void AddArguments(mitkCommandLineParser& parser) const override; - itkSetMacro(Range, int); - itkGetConstMacro(Range, int); + protected: + std::string GenerateLegacyFeatureEncoding(const FeatureID& id) const override; + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; + void ConfigureSettingsByParameters(const ParametersType& parameters) override; private: int m_Range; }; } #endif //mitkGIFNeighbourhoodGreyToneDifferenceFeatures_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFNeighbouringGreyLevelDependenceFeatures.h b/Modules/Classification/CLUtilities/include/mitkGIFNeighbouringGreyLevelDependenceFeatures.h index fb4b464b40..2700efb0da 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFNeighbouringGreyLevelDependenceFeatures.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFNeighbouringGreyLevelDependenceFeatures.h @@ -1,164 +1,149 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkGIFNeighbouringGreyLevelDependenceFeatures_h #define mitkGIFNeighbouringGreyLevelDependenceFeatures_h #include #include #include #include namespace mitk { /** * \brief Calculates the Neighbouring Grey Level Dependence Features * * The Neighbouring Grey Level Dependence Features were proposed by Sun and Wee (1983) and * capture the coarsness of the image texture. They are rotational invariant. * * The features are calculated on a matrix \f$ m \f$. To obtain the matrix, a neighbourhood * around each feature is calculated and the number of voxels within the neighbourhood that * are greater than the center voxel plus \f$ \alpha \f$ is counted. This is called the * number of dependence voxels. The matrix gives the * number of voxels with an intesity \f$ x \f$ and \f$ d \f$ dependence neighbourhood voxels. * * 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. * * In addition to this, the size of the neighbourhood can be controlled by setting the parameter * ngld::range. By default it is one. To pass more than one range, separate the ranges with * a semicolon. E.g. 1;2;3 would calculate the features for the ranges 1, 2, and 3. * * This feature calculator is activated by the option -neighbouring-grey-level-dependence * or -ngld. * * The features are calculated based on a mask. It is assumed that the mask is * a unsigned short image. All voxels with a value greater 0 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 neighbourhoods, \f$ m_{x,\cdot} = \sum_d m{x,d} \f$ is the number of neighbourhoods * with a given intensity value, and likewise \f$ m_{\cdot, d} = \sum_x m{x,d} \f$ is the number of neighbourhoods * with a given number of dependence features: * - Neighbouring Grey Level Dependence::Low Dependence Emphasis: * \f[ \textup{Low dependence emphasis}= \frac{1}{N_s} \sum_d { \frac{m_{\cdot, d}}{d^2} } \f] * - Neighbouring Grey Level Dependence::High Dependence Emphasis: * \f[ \textup{High dependence emphasis}= \frac{1}{N_s} \sum_d { m_{\cdot, d} d^2} \f] * - Neighbouring Grey Level Dependence::Low Grey Level Count Emphasis: * \f[ \textup{Low grey level count emphasis}= \frac{1}{N_s} \sum_x { \frac{m_{x,\cdot}}{x^2} } \f] * - Neighbouring Grey Level Dependence::High Grey Level Count Emphasis: * \f[ \textup{High grey level count emphasis}= \frac{1}{N_s} \sum_x { m_{x,\cdot} x^2} \f] * - Neighbouring Grey Level Dependence::Low Dependence Low Grey Level Emphasis: * \f[ \textup{Low Dependence Low Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_d { \frac{m_{x,d}}{x^2 d^2} } \f] * - Neighbouring Grey Level Dependence::Low Dependence High Grey Level Emphasis: * \f[ \textup{Low dependence high grey level emphasis}= \frac{1}{N_s} \sum_x \sum_d { \frac{x^2 m_{x,d}}{d^2} } \f] * - Neighbouring Grey Level Dependence::High Dependence Low Grey Level Emphasis: * \f[ \textup{High Dependence Low Grey Level Emphasis}= \frac{1}{N_s} \sum_x \sum_d { \frac{d^2 m_{x,d}}{x^2} } \f] * - Neighbouring Grey Level Dependence::High Dependence High Grey Level Emphasis: * \f[ \textup{High dependence high grey level emphasis}= \frac{1}{N_s} \sum_x \sum_d { x^2 d^2 m_{x,d} } \f] * - Neighbouring Grey Level Dependence::Grey level nonuniformity: * \f[ \textup{Grey level nonuniformity}= \frac{1}{N_s} \sum_x m_{x,\cdot}^2 \f] * - Neighbouring Grey Level Dependence::Grey level nonuniformity normalized: * \f[ \textup{Grey level nonuniformity normalized}= \frac{1}{N_s^2} \sum_x m_{x,\cdot}^2 \f] * - Neighbouring Grey Level Dependence::Dependence Count Nonuniformity: * \f[ \textup{Dependence count nonuniformity}= \frac{1}{N_s} \sum_d m_{\cdot, d}^2 \f] * - Neighbouring Grey Level Dependence::Dependence Count Nonuniformity Normalized: * \f[ \textup{Dependence count nonuniformity normalized}= \frac{1}{N_s^2} \sum_d m_{\cdot, d}^2 \f] * - Neighbouring Grey Level Dependence::DEpendence Count Percentage THe number of realized * neighbourhoods relativ to the theoretical maximum of realized neighbourhoods. This feature is always * one for this implementation as partial neighbourhoods are still considered. * - Neighbouring Grey Level Dependence::Grey Level Mean: The mean value of all grey level. * \f[ \textup{Grey Level Mean} = \mu_x = \frac{1}{N_s} \sum_x x m_{x,\cdot} \f] * - Neighbouring Grey Level Dependence::Grey Level Variance: * \f[ \textup{Grey level variance} = \frac{1}{N_s} \sum_x (x -mu_x)^2 m_{x, \cdot} \f] * - Neighbouring Grey Level Dependence::Dependence Count Mean: The mean value of all dependence counts. * \f[ \textup{Dependence count mean} = \mu_d = \frac{1}{N_s} \sum_d d m_{\cdot,d} \f] * - Neighbouring Grey Level Dependence::Dependence Count Variance: * \f[ \textup{Dependence count variance} = \frac{1}{N_s} \sum_d (d -mu_d)^2 m_{\cdot, d} \f] * - Neighbouring Grey Level Dependence::Dependence Count 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,d} = \frac{m_{x,d}}{N_s} \f$. : * \f[ \textup{Dependence count entropy} = \sum_x \sum_d p_{x,d} \textup{log}_2 \left( p_{x,d} \right) \f] * - Neighbouring Grey Level Dependence::Dependence Count Energy: This feature would be equivalent with * the Grey Level Energy, which is therefore not included. It is based on the likelihood * for a given intensity- size combination \f$ p_{x,d} = \frac{m_{x,d}}{N_s} \f$. : * \f[ \textup{Dependence count energy} = \sum_x \sum_d p_{x,d}^2 \f] * - Neighbouring Grey Level Dependence::Expected Neighbourhood Size: The expected size of a * full neighbourhood. It depends on the dimension of the area that is looked at. * - Neighbouring Grey Level Dependence::Average Neighbourhood Size: The feature calculation * allows to consider partially masked neighbourhoods. Due to that, some neighbourhoods might be smaller. * This feature gives not the theoretical neighbourhood size but the average realized neighbourhood sizes. * - Neighbouring Grey Level Dependence::Average Incomplete Neighbourhood Size: Gives the average * size of all neighbourhoods that are not complete. * - Neighbouring Grey Level Dependence::Percentage of complete Neighbourhoods: Gives the percentage * of all complete neighbourhoods from all realized neighbourhoods. * - Neighbouring Grey Level Dependence::Percentage of Dependence Neighbour Voxels: Gives the * percentage of voxels in all neighbourhoods compared to the expected number of voxels. */ class MITKCLUTILITIES_EXPORT GIFNeighbouringGreyLevelDependenceFeature : public AbstractGlobalImageFeature { - public: - mitkClassMacro(GIFNeighbouringGreyLevelDependenceFeature, AbstractGlobalImageFeature); - itkFactorylessNewMacro(Self); - itkCloneMacro(Self); + public: + mitkClassMacro(GIFNeighbouringGreyLevelDependenceFeature, AbstractGlobalImageFeature); + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); - GIFNeighbouringGreyLevelDependenceFeature(); + GIFNeighbouringGreyLevelDependenceFeature(); - /** - * \brief Calculates the Cooccurence-Matrix based features for this class. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; - - std::string GetCurrentFeatureEncoding() override; - - itkGetConstMacro(Range,double); - itkSetMacro(Range, double); + itkGetConstMacro(Ranges, std::vector); + void SetRanges(std::vector ranges); + void SetRange(double range); itkGetConstMacro(Alpha, int); itkSetMacro(Alpha, int); - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; + void AddArguments(mitkCommandLineParser& parser) const override; + protected: + std::string GenerateLegacyFeatureEncoding(const FeatureID& id) const override; - struct GIFNeighbouringGreyLevelDependenceFeatureConfiguration - { - double range; - unsigned int direction; - int alpha; + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; - double MinimumIntensity; - double MaximumIntensity; - int Bins; - std::string FeatureEncoding; - }; + void ConfigureSettingsByParameters(const ParametersType& parameters) override; - private: - double m_Range; + private: + std::vector m_Ranges; int m_Alpha; }; } #endif //mitkGIFNeighbouringGreyLevelDependenceFeature_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFVolumetricDensityStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFVolumetricDensityStatistics.h index 3c29b8452c..8ada077bfb 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFVolumetricDensityStatistics.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFVolumetricDensityStatistics.h @@ -1,128 +1,122 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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(); + GIFVolumetricDensityStatistics(); - /** - * \brief Calculates the Cooccurence-Matrix based features for this class. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; + void AddArguments(mitkCommandLineParser& parser) const override; - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; + protected: - private: + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; }; } #endif //mitkGIFVolumetricDensityStatistics_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFVolumetricStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFVolumetricStatistics.h index 9dc8ebda77..660f7a1bf8 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFVolumetricStatistics.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFVolumetricStatistics.h @@ -1,133 +1,127 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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. - */ - FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + FeatureListType CalculateFeatures(const Image* image, const Image* mask, const Image* maskNoNAN) override; + using Superclass::CalculateFeatures; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; + void AddArguments(mitkCommandLineParser& parser) const override; - void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override; - void AddArguments(mitkCommandLineParser &parser) override; + protected: - private: + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; }; } #endif //mitkGIFVolumetricStatistics_h diff --git a/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h b/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h index 4f56d5886e..6556f1a3db 100644 --- a/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h +++ b/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h @@ -1,84 +1,87 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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 outputXMLPath; 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; bool encodeParameter; + std::string pipelineUID; + bool calculateAllFeatures; 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 diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp index ce15e9af7f..d806cf63a3 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp @@ -1,328 +1,348 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include // ITK #include #include // STL #include +struct GIFCooccurenceMatrixConfiguration +{ + double range; + unsigned int direction; + double MinimumIntensity; + bool UseMinimumIntensity; + double MaximumIntensity; + bool UseMaximumIntensity; + int Bins; + mitk::FeatureID id; +}; + template void -CalculateCoocurenceFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFCooccurenceMatrix::FeatureListType & featureList, mitk::GIFCooccurenceMatrix::GIFCooccurenceMatrixConfiguration config) +CalculateCoocurenceFeatures(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFCooccurenceMatrix::FeatureListType & featureList, 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. Energy Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. Entropy Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. Correlation Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. InverseDifferenceMoment Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. Inertia Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. ClusterShade Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. ClusterProminence Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. HaralickCorrelation Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. Autocorrelation Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. Contrast Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. Dissimilarity Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. MaximumProbability Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. InverseVariance Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. Homogeneity1 Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. ClusterTendency Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. Variance Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. SumAverage Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. SumEntropy Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. SumVariance Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. DifferenceAverage Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. DifferenceEntropy Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. DifferenceVariance Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. InverseDifferenceMomentNormalized Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. InverseDifferenceNormalized Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. InverseDifference Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. JointAverage Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. FirstMeasureOfInformationCorrelation Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. 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))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. SecondMeasureOfInformationCorrelation Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "co-occ. SecondMeasureOfInformationCorrelation Std."), featureStd->ElementAt(i))); break; default: break; } } } mitk::GIFCooccurenceMatrix::GIFCooccurenceMatrix(): -m_Range(1.0) + m_Ranges({ 1.0 }) { SetShortName("deprecated-cooc"); SetLongName("deprecated-cooccurence"); SetFeatureClassName("Deprecated Co-occurence Features"); } -mitk::GIFCooccurenceMatrix::FeatureListType mitk::GIFCooccurenceMatrix::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +void mitk::GIFCooccurenceMatrix::SetRanges(std::vector ranges) +{ + m_Ranges = ranges; + this->Modified(); +} + +void mitk::GIFCooccurenceMatrix::SetRange(double range) +{ + m_Ranges.resize(1); + m_Ranges[0] = range; + this->Modified(); +} + +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFCooccurenceMatrix::DoCalculateFeatures(const Image* image, const Image* mask) { FeatureListType featureList; - GIFCooccurenceMatrixConfiguration config; - config.direction = GetDirection(); - config.range = m_Range; + InitializeQuantifier(image, mask); + + for (const auto& range : m_Ranges) + { + MITK_INFO << "Start calculating coocurence with range " << range << "...."; - config.MinimumIntensity = GetMinimumIntensity(); - config.MaximumIntensity = GetMaximumIntensity(); - config.UseMinimumIntensity = GetUseMinimumIntensity(); - config.UseMaximumIntensity = GetUseMaximumIntensity(); - config.Bins = GetBins(); + GIFCooccurenceMatrixConfiguration config; + config.direction = GetDirection(); + config.range = range; + config.MinimumIntensity = GetQuantifier()->GetMinimum(); + config.MaximumIntensity = GetQuantifier()->GetMaximum(); + config.UseMinimumIntensity = GetUseMinimumIntensity(); + config.UseMaximumIntensity = GetUseMaximumIntensity(); + config.Bins = GetBins(); + config.id = this->CreateTemplateFeatureID(std::to_string(range), { {GetOptionPrefix() + "::range", range} }); - AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList,config); + AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList, config); + + MITK_INFO << "Finished calculating coocurence with range " << range << "...."; + } return featureList; } -mitk::GIFCooccurenceMatrix::FeatureNameListType mitk::GIFCooccurenceMatrix::GetFeatureNames() +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFCooccurenceMatrix::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { - FeatureNameListType featureList; - featureList.push_back("co-occ. Energy Means"); - featureList.push_back("co-occ. Energy Std."); - return featureList; + return Superclass::CalculateFeatures(image, maskNoNAN); } +void mitk::GIFCooccurenceMatrix::AddArguments(mitkCommandLineParser& parser) const +{ + std::string name = this->GetOptionPrefix(); + parser.addArgument(this->GetLongName(), name, mitkCommandLineParser::Bool, "Use Co-occurence matrix", "calculates Co-occurence based features", us::Any()); + parser.addArgument(name + "::range", name + "::range", mitkCommandLineParser::String, "Cooc Range", "Define the range that is used (Semicolon-separated)", us::Any()); +} -void mitk::GIFCooccurenceMatrix::AddArguments(mitkCommandLineParser &parser) +std::string mitk::GIFCooccurenceMatrix::GenerateLegacyFeatureNamePart(const FeatureID& id) const { - std::string name = GetOptionPrefix(); - - 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()); + auto result = id.name; + result.insert(7, " (" + id.parameters.at(this->GetOptionPrefix() + "::range").ToString() + ")"); + return result; } -void -mitk::GIFCooccurenceMatrix::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +std::string mitk::GIFCooccurenceMatrix::GenerateLegacyFeatureEncoding(const FeatureID& /*id*/) const { - auto parsedArgs = GetParameter(); - std::string name = GetOptionPrefix(); + //deprecated GIFCooccurenceMatrix does not support feature encoding + return ""; +} - if (parsedArgs.count(GetLongName())) +void mitk::GIFCooccurenceMatrix::ConfigureSettingsByParameters(const ParametersType& parameters) +{ + auto name = GetOptionPrefix() + "::range"; + if (parameters.count(name)) { - 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] << "...."; - } + m_Ranges = SplitDouble(parameters.at(name).ToString(), ';'); } } - diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp index fba1f5f467..e64aee3fb4 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp @@ -1,705 +1,702 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include // ITK #include #include #include // STL #include #include namespace mitk { + struct GIFCooccurenceMatrix2Configuration + { + double range; + unsigned int direction; + + double MinimumIntensity; + double MaximumIntensity; + int Bins; + FeatureID id; + }; + struct CoocurenceMatrixHolder { public: CoocurenceMatrixHolder(double min, double max, int number); int IntensityToIndex(double intensity); double IndexToMinIntensity(int index); double IndexToMeanIntensity(int index); double IndexToMaxIntensity(int index); double m_MinimumRange; double m_MaximumRange; double m_Stepsize; int m_NumberOfBins; Eigen::MatrixXd m_Matrix; }; struct CoocurenceMatrixFeatures { CoocurenceMatrixFeatures() : JointMaximum(0), JointAverage(0), JointVariance(0), JointEntropy(0), RowMaximum(0), RowAverage(0), RowVariance(0), RowEntropy(0), FirstRowColumnEntropy(0), SecondRowColumnEntropy(0), DifferenceAverage(0), DifferenceVariance(0), DifferenceEntropy(0), SumAverage(0), SumVariance(0), SumEntropy(0), AngularSecondMoment(0), Contrast(0), Dissimilarity(0), InverseDifference(0), InverseDifferenceNormalised(0), InverseDifferenceMoment(0), InverseDifferenceMomentNormalised(0), InverseVariance(0), Correlation(0), Autocorrelation(0), ClusterTendency(0), ClusterShade(0), ClusterProminence(0), FirstMeasureOfInformationCorrelation(0), SecondMeasureOfInformationCorrelation(0) { } public: double JointMaximum; double JointAverage; double JointVariance; double JointEntropy; double RowMaximum; double RowAverage; double RowVariance; double RowEntropy; double FirstRowColumnEntropy; double SecondRowColumnEntropy; double DifferenceAverage; double DifferenceVariance; double DifferenceEntropy; double SumAverage; double SumVariance; double SumEntropy; double AngularSecondMoment; double Contrast; double Dissimilarity; double InverseDifference; double InverseDifferenceNormalised; double InverseDifferenceMoment; double InverseDifferenceMomentNormalised; double InverseVariance; double Correlation; double Autocorrelation; double ClusterTendency; double ClusterShade; double ClusterProminence; double FirstMeasureOfInformationCorrelation; double SecondMeasureOfInformationCorrelation; }; } + static -void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, - std::string prefix, - mitk::GIFCooccurenceMatrix2::FeatureListType &featureList); +void MatrixFeaturesTo(const mitk::CoocurenceMatrixFeatures& features, + const std::string& prefix, + const mitk::GIFCooccurenceMatrix2Configuration& config, + mitk::GIFCooccurenceMatrix2::FeatureListType& featureList) +{ + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Joint Maximum"), features.JointMaximum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Joint Average"), features.JointAverage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Joint Variance"), features.JointVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Joint Entropy"), features.JointEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Difference Average"), features.DifferenceAverage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Difference Variance"), features.DifferenceVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Difference Entropy"), features.DifferenceEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Sum Average"), features.SumAverage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Sum Variance"), features.SumVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Sum Entropy"), features.SumEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Angular Second Moment"), features.AngularSecondMoment)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Contrast"), features.Contrast)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Dissimilarity"), features.Dissimilarity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Difference"), features.InverseDifference)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Difference Normalized"), features.InverseDifferenceNormalised)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Difference Moment"), features.InverseDifferenceMoment)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Difference Moment Normalized"), features.InverseDifferenceMomentNormalised)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Variance"), features.InverseVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Correlation"), features.Correlation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Autocorrelation"), features.Autocorrelation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Cluster Tendency"), features.ClusterTendency)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Cluster Shade"), features.ClusterShade)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Cluster Prominence"), features.ClusterProminence)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "First Measure of Information Correlation"), features.FirstMeasureOfInformationCorrelation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Second Measure of Information Correlation"), features.SecondMeasureOfInformationCorrelation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Row Maximum"), features.RowMaximum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Row Average"), features.RowAverage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Row Variance"), features.RowVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Row Entropy"), features.RowEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "First Row-Column Entropy"), features.FirstRowColumnEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Second Row-Column Entropy"), features.SecondRowColumnEntropy)); +} + + 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, +CalculateCoOcMatrix(const itk::Image* itkImage, + const itk::Image* mask, itk::Offset offset, int range, mitk::CoocurenceMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef itk::ShapedNeighborhoodIterator ShapeIterType; typedef itk::ShapedNeighborhoodIterator ShapeMaskIterType; typedef itk::ImageRegionConstIterator ConstIterType; typedef itk::ImageRegionConstIterator ConstMaskIterType; itk::Size radius; radius.Fill(range+1); ShapeIterType imageOffsetIter(radius, itkImage, itkImage->GetLargestPossibleRegion()); ShapeMaskIterType maskOffsetIter(radius, mask, mask->GetLargestPossibleRegion()); imageOffsetIter.ActivateOffset(offset); maskOffsetIter.ActivateOffset(offset); ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); // iterator.GetIndex() + ci.GetNeighborhoodOffset() auto region = mask->GetLargestPossibleRegion(); while (!maskIter.IsAtEnd()) { auto ciMask = maskOffsetIter.Begin(); auto ciValue = imageOffsetIter.Begin(); if (maskIter.Value() > 0 && ciMask.Get() > 0 && imageIter.Get() == imageIter.Get() && ciValue.Get() == ciValue.Get() && region.IsInside(maskOffsetIter.GetIndex() + ciMask.GetNeighborhoodOffset())) { int i = holder.IntensityToIndex(imageIter.Get()); int j = holder.IntensityToIndex(ciValue.Get()); holder.m_Matrix(i, j) += 1; holder.m_Matrix(j, i) += 1; } ++imageOffsetIter; ++maskOffsetIter; ++imageIter; ++maskIter; } } void CalculateFeatures( mitk::CoocurenceMatrixHolder &holder, mitk::CoocurenceMatrixFeatures & results ) { auto pijMatrix = holder.m_Matrix; auto piMatrix = holder.m_Matrix; auto pjMatrix = holder.m_Matrix; double Ng = holder.m_NumberOfBins; int NgSize = holder.m_NumberOfBins; pijMatrix /= pijMatrix.sum(); piMatrix.rowwise().normalize(); pjMatrix.colwise().normalize(); for (int i = 0; i < holder.m_NumberOfBins; ++i) for (int j = 0; j < holder.m_NumberOfBins; ++j) { if (pijMatrix(i, j) != pijMatrix(i, j)) pijMatrix(i, j) = 0; if (piMatrix(i, j) != piMatrix(i, j)) piMatrix(i, j) = 0; if (pjMatrix(i, j) != pjMatrix(i, j)) pjMatrix(i, j) = 0; } Eigen::VectorXd piVector = pijMatrix.colwise().sum(); Eigen::VectorXd pjVector = pijMatrix.rowwise().sum(); double sigmai = 0;; for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1;// holder.IndexToMeanIntensity(i); results.RowAverage += iInt * piVector(i); if (piVector(i) > 0) { results.RowEntropy -= piVector(i) * std::log(piVector(i)) / std::log(2); } } for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1; // holder.IndexToMeanIntensity(i); results.RowVariance += (iInt - results.RowAverage)*(iInt - results.RowAverage) * piVector(i); } results.RowMaximum = piVector.maxCoeff(); sigmai = std::sqrt(results.RowVariance); Eigen::VectorXd pimj(NgSize); pimj.fill(0); Eigen::VectorXd pipj(2*NgSize); pipj.fill(0); results.JointMaximum += pijMatrix.maxCoeff(); for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1;// holder.IndexToMeanIntensity(i); double jInt = j + 1;// holder.IndexToMeanIntensity(j); double pij = pijMatrix(i, j); int deltaK = (i - j)>0?(i-j) : (j-i); pimj(deltaK) += pij; pipj(i + j) += pij; results.JointAverage += iInt * pij; if (pij > 0) { results.JointEntropy -= pij * std::log(pij) / std::log(2); results.FirstRowColumnEntropy -= pij * std::log(piVector(i)*pjVector(j)) / std::log(2); } if (piVector(i) > 0 && pjVector(j) > 0 ) { results.SecondRowColumnEntropy -= piVector(i)*pjVector(j) * std::log(piVector(i)*pjVector(j)) / std::log(2); } results.AngularSecondMoment += pij*pij; results.Contrast += (iInt - jInt)* (iInt - jInt) * pij; results.Dissimilarity += std::abs(iInt - jInt) * pij; results.InverseDifference += pij / (1 + (std::abs(iInt - jInt))); results.InverseDifferenceNormalised += pij / (1 + (std::abs(iInt - jInt) / Ng)); results.InverseDifferenceMoment += pij / (1 + (iInt - jInt)*(iInt - jInt)); results.InverseDifferenceMomentNormalised += pij / (1 + (iInt - jInt)*(iInt - jInt)/Ng/Ng); results.Autocorrelation += iInt*jInt * pij; double cluster = (iInt + jInt - 2 * results.RowAverage); results.ClusterTendency += cluster*cluster * pij; results.ClusterShade += cluster*cluster*cluster * pij; results.ClusterProminence += cluster*cluster*cluster*cluster * pij; if (iInt != jInt) { results.InverseVariance += pij / (iInt - jInt) / (iInt - jInt); } } } results.Correlation = 1 / sigmai / sigmai * (-results.RowAverage*results.RowAverage+ results.Autocorrelation); results.FirstMeasureOfInformationCorrelation = (results.JointEntropy - results.FirstRowColumnEntropy) / results.RowEntropy; if (results.JointEntropy < results.SecondRowColumnEntropy) { results.SecondMeasureOfInformationCorrelation = sqrt(1 - exp(-2 * (results.SecondRowColumnEntropy - results.JointEntropy))); } else { results.SecondMeasureOfInformationCorrelation = 0; } for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1; double pij = pijMatrix(i, j); results.JointVariance += (iInt - results.JointAverage)* (iInt - results.JointAverage)*pij; } } for (int k = 0; k < NgSize; ++k) { results.DifferenceAverage += k* pimj(k); if (pimj(k) > 0) { results.DifferenceEntropy -= pimj(k) * log(pimj(k)) / std::log(2); } } for (int k = 0; k < NgSize; ++k) { results.DifferenceVariance += (results.DifferenceAverage-k)* (results.DifferenceAverage-k)*pimj(k); } for (int k = 0; k <2* NgSize ; ++k) { results.SumAverage += (2+k)* pipj(k); if (pipj(k) > 0) { results.SumEntropy -= pipj(k) * log(pipj(k)) / std::log(2); } } for (int k = 0; k < 2*NgSize; ++k) { results.SumVariance += (2+k - results.SumAverage)* (2+k - results.SumAverage)*pipj(k); } //MITK_INFO << std::endl << holder.m_Matrix; //MITK_INFO << std::endl << pijMatrix; //MITK_INFO << std::endl << piMatrix; //MITK_INFO << std::endl << pjMatrix; //for (int i = 0; i < holder.m_NumberOfBins; ++i) //{ // MITK_INFO << "Bin " << i << " Min: " << holder.IndexToMinIntensity(i) << " Max: " << holder.IndexToMaxIntensity(i); //} //MITK_INFO << pimj; //MITK_INFO << pipj; } template void -CalculateCoocurenceFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFCooccurenceMatrix2::FeatureListType & featureList, mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2Configuration config) +CalculateCoocurenceFeatures(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFCooccurenceMatrix2::FeatureListType & featureList, mitk::GIFCooccurenceMatrix2Configuration config) { typedef itk::Image MaskType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// double rangeMin = config.MinimumIntensity; double rangeMax = config.MaximumIntensity; int numberOfBins = config.Bins; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); //Find possible directions std::vector < itk::Offset > offsetVector; NeighborhoodType hood; hood.SetRadius(1); unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetType offset; for (unsigned int d = 0; d < centerIndex; d++) { offset = hood.GetOffset(d); bool useOffset = true; for (unsigned int i = 0; i < VImageDimension; ++i) { offset[i] *= config.range; if (config.direction == i + 2 && offset[i] != 0) { useOffset = false; } } if (useOffset) { offsetVector.push_back(offset); } } if (config.direction == 1) { offsetVector.clear(); offset[0] = 0; offset[1] = 0; offset[2] = 1; } std::vector resultVector; mitk::CoocurenceMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures overallFeature; for (std::size_t i = 0; i < offsetVector.size(); ++i) { if (config.direction > 1) { if (offsetVector[i][config.direction - 2] != 0) { continue; } } offset = offsetVector[i]; mitk::CoocurenceMatrixHolder holder(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures coocResults; CalculateCoOcMatrix(itkImage, maskImage, offset, config.range, holder); holderOverall.m_Matrix += holder.m_Matrix; CalculateFeatures(holder, coocResults); resultVector.push_back(coocResults); } CalculateFeatures(holderOverall, overallFeature); //NormalizeMatrixFeature(overallFeature, offsetVector.size()); mitk::CoocurenceMatrixFeatures featureMean; mitk::CoocurenceMatrixFeatures featureStd; CalculateMeanAndStdDevFeatures(resultVector, featureMean, featureStd); std::ostringstream ss; ss << config.range; std::string strRange = ss.str(); - MatrixFeaturesTo(overallFeature, config.prefix + "Overall ", featureList); - MatrixFeaturesTo(featureMean, config.prefix + "Mean ", featureList); - MatrixFeaturesTo(featureStd, config.prefix + "Std.Dev. ", featureList); -} - - -static -void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, - std::string prefix, - mitk::GIFCooccurenceMatrix2::FeatureListType &featureList) -{ - featureList.push_back(std::make_pair(prefix + "Joint Maximum", features.JointMaximum)); - featureList.push_back(std::make_pair(prefix + "Joint Average", features.JointAverage)); - featureList.push_back(std::make_pair(prefix + "Joint Variance", features.JointVariance)); - featureList.push_back(std::make_pair(prefix + "Joint Entropy", features.JointEntropy)); - featureList.push_back(std::make_pair(prefix + "Difference Average", features.DifferenceAverage)); - featureList.push_back(std::make_pair(prefix + "Difference Variance", features.DifferenceVariance)); - featureList.push_back(std::make_pair(prefix + "Difference Entropy", features.DifferenceEntropy)); - featureList.push_back(std::make_pair(prefix + "Sum Average", features.SumAverage)); - featureList.push_back(std::make_pair(prefix + "Sum Variance", features.SumVariance)); - featureList.push_back(std::make_pair(prefix + "Sum Entropy", features.SumEntropy)); - featureList.push_back(std::make_pair(prefix + "Angular Second Moment", features.AngularSecondMoment)); - featureList.push_back(std::make_pair(prefix + "Contrast", features.Contrast)); - featureList.push_back(std::make_pair(prefix + "Dissimilarity", features.Dissimilarity)); - featureList.push_back(std::make_pair(prefix + "Inverse Difference", features.InverseDifference)); - featureList.push_back(std::make_pair(prefix + "Inverse Difference Normalized", features.InverseDifferenceNormalised)); - featureList.push_back(std::make_pair(prefix + "Inverse Difference Moment", features.InverseDifferenceMoment)); - featureList.push_back(std::make_pair(prefix + "Inverse Difference Moment Normalized", features.InverseDifferenceMomentNormalised)); - featureList.push_back(std::make_pair(prefix + "Inverse Variance", features.InverseVariance)); - featureList.push_back(std::make_pair(prefix + "Correlation", features.Correlation)); - featureList.push_back(std::make_pair(prefix + "Autocorrelation", features.Autocorrelation)); - featureList.push_back(std::make_pair(prefix + "Cluster Tendency", features.ClusterTendency)); - featureList.push_back(std::make_pair(prefix + "Cluster Shade", features.ClusterShade)); - featureList.push_back(std::make_pair(prefix + "Cluster Prominence", features.ClusterProminence)); - featureList.push_back(std::make_pair(prefix + "First Measure of Information Correlation", features.FirstMeasureOfInformationCorrelation)); - featureList.push_back(std::make_pair(prefix + "Second Measure of Information Correlation", features.SecondMeasureOfInformationCorrelation)); - featureList.push_back(std::make_pair(prefix + "Row Maximum", features.RowMaximum)); - featureList.push_back(std::make_pair(prefix + "Row Average", features.RowAverage)); - featureList.push_back(std::make_pair(prefix + "Row Variance", features.RowVariance)); - featureList.push_back(std::make_pair(prefix + "Row Entropy", features.RowEntropy)); - featureList.push_back(std::make_pair(prefix + "First Row-Column Entropy", features.FirstRowColumnEntropy)); - featureList.push_back(std::make_pair(prefix + "Second Row-Column Entropy", features.SecondRowColumnEntropy)); + MatrixFeaturesTo(overallFeature, "Overall ", config, featureList); + MatrixFeaturesTo(featureMean, "Mean ", config, featureList); + MatrixFeaturesTo(featureStd, "Std.Dev. ", config, featureList); } static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature) { #define ADDFEATURE(a) \ if ( ! (featureList[i].a == featureList[i].a)) featureList[i].a = 0; \ meanFeature.a += featureList[i].a;stdFeature.a += featureList[i].a*featureList[i].a #define CALCVARIANCE(a) stdFeature.a =sqrt(stdFeature.a - meanFeature.a*meanFeature.a) for (std::size_t i = 0; i < featureList.size(); ++i) { ADDFEATURE(JointMaximum); ADDFEATURE(JointAverage); ADDFEATURE(JointVariance); ADDFEATURE(JointEntropy); ADDFEATURE(RowMaximum); ADDFEATURE(RowAverage); ADDFEATURE(RowVariance); ADDFEATURE(RowEntropy); ADDFEATURE(FirstRowColumnEntropy); ADDFEATURE(SecondRowColumnEntropy); ADDFEATURE(DifferenceAverage); ADDFEATURE(DifferenceVariance); ADDFEATURE(DifferenceEntropy); ADDFEATURE(SumAverage); ADDFEATURE(SumVariance); ADDFEATURE(SumEntropy); ADDFEATURE(AngularSecondMoment); ADDFEATURE(Contrast); ADDFEATURE(Dissimilarity); ADDFEATURE(InverseDifference); ADDFEATURE(InverseDifferenceNormalised); ADDFEATURE(InverseDifferenceMoment); ADDFEATURE(InverseDifferenceMomentNormalised); ADDFEATURE(InverseVariance); ADDFEATURE(Correlation); ADDFEATURE(Autocorrelation); ADDFEATURE(ClusterShade); ADDFEATURE(ClusterTendency); ADDFEATURE(ClusterProminence); ADDFEATURE(FirstMeasureOfInformationCorrelation); ADDFEATURE(SecondMeasureOfInformationCorrelation); } NormalizeMatrixFeature(meanFeature, featureList.size()); NormalizeMatrixFeature(stdFeature, featureList.size()); CALCVARIANCE(JointMaximum); CALCVARIANCE(JointAverage); CALCVARIANCE(JointVariance); CALCVARIANCE(JointEntropy); CALCVARIANCE(RowMaximum); CALCVARIANCE(RowAverage); CALCVARIANCE(RowVariance); CALCVARIANCE(RowEntropy); CALCVARIANCE(FirstRowColumnEntropy); CALCVARIANCE(SecondRowColumnEntropy); CALCVARIANCE(DifferenceAverage); CALCVARIANCE(DifferenceVariance); CALCVARIANCE(DifferenceEntropy); CALCVARIANCE(SumAverage); CALCVARIANCE(SumVariance); CALCVARIANCE(SumEntropy); CALCVARIANCE(AngularSecondMoment); CALCVARIANCE(Contrast); CALCVARIANCE(Dissimilarity); CALCVARIANCE(InverseDifference); CALCVARIANCE(InverseDifferenceNormalised); CALCVARIANCE(InverseDifferenceMoment); CALCVARIANCE(InverseDifferenceMomentNormalised); CALCVARIANCE(InverseVariance); CALCVARIANCE(Correlation); CALCVARIANCE(Autocorrelation); CALCVARIANCE(ClusterShade); CALCVARIANCE(ClusterTendency); CALCVARIANCE(ClusterProminence); CALCVARIANCE(FirstMeasureOfInformationCorrelation); CALCVARIANCE(SecondMeasureOfInformationCorrelation); #undef ADDFEATURE #undef CALCVARIANCE } static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number) { features.JointMaximum = features.JointMaximum / number; features.JointAverage = features.JointAverage / number; features.JointVariance = features.JointVariance / number; features.JointEntropy = features.JointEntropy / number; features.RowMaximum = features.RowMaximum / number; features.RowAverage = features.RowAverage / number; features.RowVariance = features.RowVariance / number; features.RowEntropy = features.RowEntropy / number; features.FirstRowColumnEntropy = features.FirstRowColumnEntropy / number; features.SecondRowColumnEntropy = features.SecondRowColumnEntropy / number; features.DifferenceAverage = features.DifferenceAverage / number; features.DifferenceVariance = features.DifferenceVariance / number; features.DifferenceEntropy = features.DifferenceEntropy / number; features.SumAverage = features.SumAverage / number; features.SumVariance = features.SumVariance / number; features.SumEntropy = features.SumEntropy / number; features.AngularSecondMoment = features.AngularSecondMoment / number; features.Contrast = features.Contrast / number; features.Dissimilarity = features.Dissimilarity / number; features.InverseDifference = features.InverseDifference / number; features.InverseDifferenceNormalised = features.InverseDifferenceNormalised / number; features.InverseDifferenceMoment = features.InverseDifferenceMoment / number; features.InverseDifferenceMomentNormalised = features.InverseDifferenceMomentNormalised / number; features.InverseVariance = features.InverseVariance / number; features.Correlation = features.Correlation / number; features.Autocorrelation = features.Autocorrelation / number; features.ClusterShade = features.ClusterShade / number; features.ClusterTendency = features.ClusterTendency / number; features.ClusterProminence = features.ClusterProminence / number; features.FirstMeasureOfInformationCorrelation = features.FirstMeasureOfInformationCorrelation / number; features.SecondMeasureOfInformationCorrelation = features.SecondMeasureOfInformationCorrelation / number; } mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2(): -m_Range(1.0) + m_Ranges({ 1.0 }) { SetShortName("cooc2"); SetLongName("cooccurence2"); SetFeatureClassName("Co-occurenced Based Features"); } -mitk::GIFCooccurenceMatrix2::FeatureListType mitk::GIFCooccurenceMatrix2::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +void mitk::GIFCooccurenceMatrix2::SetRanges(std::vector ranges) { - InitializeQuantifier(image, mask); + m_Ranges = ranges; + this->Modified(); +} + +void mitk::GIFCooccurenceMatrix2::SetRange(double range) +{ + m_Ranges.resize(1); + m_Ranges[0] = range; + this->Modified(); +} +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFCooccurenceMatrix2::DoCalculateFeatures(const Image* image, const Image* mask) +{ FeatureListType featureList; - GIFCooccurenceMatrix2Configuration config; - config.direction = GetDirection(); - config.range = m_Range; + InitializeQuantifier(image, mask); + + for (const auto& range: m_Ranges) + { + MITK_INFO << "Start calculating coocurence with range " << range << "...."; - config.MinimumIntensity = GetQuantifier()->GetMinimum(); - config.MaximumIntensity = GetQuantifier()->GetMaximum(); - config.Bins = GetQuantifier()->GetBins(); - config.prefix = FeatureDescriptionPrefix(); + GIFCooccurenceMatrix2Configuration config; + config.direction = GetDirection(); + config.range = range; + config.MinimumIntensity = GetQuantifier()->GetMinimum(); + config.MaximumIntensity = GetQuantifier()->GetMaximum(); + config.Bins = GetQuantifier()->GetBins(); + config.id = this->CreateTemplateFeatureID(std::to_string(range), { {GetOptionPrefix() + "::range", range} }); - AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList,config); + AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList, config); + + MITK_INFO << "Finished calculating coocurence with range " << range << "...."; + } return featureList; } -mitk::GIFCooccurenceMatrix2::FeatureNameListType mitk::GIFCooccurenceMatrix2::GetFeatureNames() +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFCooccurenceMatrix2::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { - FeatureNameListType featureList; - return featureList; + return Superclass::CalculateFeatures(image, maskNoNAN); } - - - -void mitk::GIFCooccurenceMatrix2::AddArguments(mitkCommandLineParser &parser) +void mitk::GIFCooccurenceMatrix2::AddArguments(mitkCommandLineParser &parser) const { - std::string name = GetOptionPrefix(); + this->AddQuantifierArguments(parser); - parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Co-occurence matrix", "calculates Co-occurence based features (new implementation)", us::Any()); + std::string name = this->GetOptionPrefix(); + + parser.addArgument(this->GetLongName(), name, mitkCommandLineParser::Bool, "Use Co-occurence matrix", "calculates Co-occurence based features (new implementation)", us::Any()); parser.addArgument(name+"::range", name+"::range", mitkCommandLineParser::String, "Cooc 2 Range", "Define the range that is used (Semicolon-separated)", us::Any()); - AddQuantifierArguments(parser); } -void -mitk::GIFCooccurenceMatrix2::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +std::string mitk::GIFCooccurenceMatrix2::GenerateLegacyFeatureEncoding(const FeatureID& id) const { - auto parsedArgs = GetParameter(); - std::string name = GetOptionPrefix(); - - if (parsedArgs.count(GetLongName())) - { - InitializeQuantifierFromParameters(feature, maskNoNAN); - std::vector ranges; - - if (parsedArgs.count(name + "::range")) - { - ranges = SplitDouble(parsedArgs[name + "::range"].ToString(), ';'); - } - else - { - ranges.push_back(1); - } - - for (std::size_t i = 0; i < ranges.size(); ++i) - { - MITK_INFO << "Start calculating coocurence with range " << ranges[i] << "...."; - this->SetRange(ranges[i]); - auto localResults = this->CalculateFeatures(feature, maskNoNAN); - featureList.insert(featureList.end(), localResults.begin(), localResults.end()); - MITK_INFO << "Finished calculating coocurence with range " << ranges[i] << "...."; - } - } + return QuantifierParameterString() + "_Range-" + id.parameters.at(this->GetOptionPrefix()+"::range").ToString(); } - -std::string mitk::GIFCooccurenceMatrix2::GetCurrentFeatureEncoding() +void mitk::GIFCooccurenceMatrix2::ConfigureSettingsByParameters(const ParametersType& parameters) { - std::ostringstream ss; - ss << m_Range; - std::string strRange = ss.str(); - return QuantifierParameterString() + "_Range-" + ss.str(); + auto name = GetOptionPrefix()+"::range"; + if (parameters.count(name)) + { + m_Ranges = SplitDouble(parameters.at(name).ToString(), ';'); + } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCurvatureStatistic.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCurvatureStatistic.cpp index 1c1582f862..5bd6a01c32 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCurvatureStatistic.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCurvatureStatistic.cpp @@ -1,177 +1,170 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include #include #include // ITK #include #include // VTK #include #include #include #include // STL #include #include -static void calculateLocalStatistic(vtkDataArray* scalars, std::string name, std::string featureDescriptionPrefix, mitk::GIFCurvatureStatistic::FeatureListType & featureList) +static void calculateLocalStatistic(vtkDataArray* scalars, const std::string& name, const mitk::FeatureID& featureID, 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(featureDescriptionPrefix + "Minimum " + name + " Curvature", minimum)); - featureList.push_back(std::make_pair(featureDescriptionPrefix + "Maximum " + name + " Curvature", maximum)); - featureList.push_back(std::make_pair(featureDescriptionPrefix + "Mean " + name + " Curvature", mean)); - featureList.push_back(std::make_pair(featureDescriptionPrefix + "Standard Deviation " + name + " Curvature", stddev)); - featureList.push_back(std::make_pair(featureDescriptionPrefix + "Skewness " + name + " Curvature", skewness)); - featureList.push_back(std::make_pair(featureDescriptionPrefix + "Mean Positive " + name + " Curvature", meanP)); - featureList.push_back(std::make_pair(featureDescriptionPrefix + "Standard Deviation Positive " + name + " Curvature", stddevP)); - featureList.push_back(std::make_pair(featureDescriptionPrefix + "Skewness Positive " + name + " Curvature", skewnessP)); - featureList.push_back(std::make_pair(featureDescriptionPrefix + "Mean Negative " + name + " Curvature", meanN)); - featureList.push_back(std::make_pair(featureDescriptionPrefix + "Standard Deviation Negative " + name + " Curvature", stddevN)); - featureList.push_back(std::make_pair(featureDescriptionPrefix + "Skewness Negative " + name + " Curvature", skewnessN)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Minimum " + name + " Curvature"), minimum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Maximum " + name + " Curvature"), maximum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mean " + name + " Curvature"), mean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Standard Deviation " + name + " Curvature"), stddev)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Skewness " + name + " Curvature"), skewness)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mean Positive " + name + " Curvature"), meanP)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Standard Deviation Positive " + name + " Curvature"), stddevP)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Skewness Positive " + name + " Curvature"), skewnessP)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mean Negative " + name + " Curvature"), meanN)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Standard Deviation Negative " + name + " Curvature"), stddevN)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Skewness Negative " + name + " Curvature"), skewnessN)); } mitk::GIFCurvatureStatistic::GIFCurvatureStatistic() { SetLongName("curvature"); SetShortName("cur"); SetFeatureClassName("Curvature Feature"); } -mitk::GIFCurvatureStatistic::FeatureListType mitk::GIFCurvatureStatistic::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) -{ - FeatureListType featureList; - if (image->GetDimension() < 3) - { - return featureList; - } - - vtkSmartPointer mesher = vtkSmartPointer::New(); - vtkSmartPointer curvator = 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", FeatureDescriptionPrefix(), featureList); - - curvator->SetCurvatureTypeToGaussian(); - curvator->Update(); - scalars = curvator->GetOutput()->GetPointData()->GetScalars(); - calculateLocalStatistic(scalars, "Gaussian", FeatureDescriptionPrefix(), featureList); - - curvator->SetCurvatureTypeToMinimum(); - curvator->Update(); - scalars = curvator->GetOutput()->GetPointData()->GetScalars(); - calculateLocalStatistic(scalars, "Minimum", FeatureDescriptionPrefix(), featureList); - - curvator->SetCurvatureTypeToMaximum(); - curvator->Update(); - scalars = curvator->GetOutput()->GetPointData()->GetScalars(); - calculateLocalStatistic(scalars, "Maximum", FeatureDescriptionPrefix(), featureList); - - return featureList; -} - -mitk::GIFCurvatureStatistic::FeatureNameListType mitk::GIFCurvatureStatistic::GetFeatureNames() -{ - FeatureNameListType featureList; - return featureList; -} - - -void mitk::GIFCurvatureStatistic::AddArguments(mitkCommandLineParser &parser) +void mitk::GIFCurvatureStatistic::AddArguments(mitkCommandLineParser &parser) const { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "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) +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFCurvatureStatistic::DoCalculateFeatures(const Image* image, const Image* mask) { - auto parsedArgs = GetParameter(); - if (parsedArgs.count(GetLongName())) + FeatureListType featureList; + + if (image->GetDimension() < 3) + { + MITK_INFO << "Passed calculating volumetric features due to wrong dimensionality ...."; + } + else { MITK_INFO << "Start calculating volumetric features ...."; - auto localResults = this->CalculateFeatures(feature, mask); - featureList.insert(featureList.end(), localResults.begin(), localResults.end()); + + auto id = this->CreateTemplateFeatureID(); + vtkSmartPointer mesher = vtkSmartPointer::New(); + vtkSmartPointer curvator = vtkSmartPointer::New(); + auto nonconstVtkData = const_cast(mask->GetVtkImageData()); + mesher->SetInputData(nonconstVtkData); + mesher->SetValue(0, 0.5); + curvator->SetInputConnection(mesher->GetOutputPort()); + curvator->SetCurvatureTypeToMean(); + curvator->Update(); + vtkDataArray* scalars = curvator->GetOutput()->GetPointData()->GetScalars(); + calculateLocalStatistic(scalars, "Mean", id, featureList); + + curvator->SetCurvatureTypeToGaussian(); + curvator->Update(); + scalars = curvator->GetOutput()->GetPointData()->GetScalars(); + calculateLocalStatistic(scalars, "Gaussian", id, featureList); + + curvator->SetCurvatureTypeToMinimum(); + curvator->Update(); + scalars = curvator->GetOutput()->GetPointData()->GetScalars(); + calculateLocalStatistic(scalars, "Minimum", id, featureList); + + curvator->SetCurvatureTypeToMaximum(); + curvator->Update(); + scalars = curvator->GetOutput()->GetPointData()->GetScalars(); + calculateLocalStatistic(scalars, "Maximum", id, featureList); + MITK_INFO << "Finished calculating volumetric features...."; } + + return featureList; } +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFCurvatureStatistic::CalculateFeatures(const Image* image, const Image* mask, const Image*) +{ + return Superclass::CalculateFeatures(image, mask); +} diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp index ac4f3bb0b6..dd2d2b789f 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp @@ -1,332 +1,327 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include // ITK #include #include #include // STL #include #include #include +namespace mitk +{ + struct GIFFirstOrderHistogramStatisticsConfiguration + { + double MinimumIntensity; + double MaximumIntensity; + int Bins; + FeatureID id; + }; +} + #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) +CalculateFirstOrderHistogramStatistics(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFFirstOrderHistogramStatistics::FeatureListType & featureList, mitk::GIFFirstOrderHistogramStatisticsConfiguration params) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::LabelStatisticsImageFilter FilterType; typedef typename FilterType::HistogramType HistogramType; typedef typename HistogramType::IndexType HIndexType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); typename FilterType::Pointer labelStatisticsImageFilter = FilterType::New(); labelStatisticsImageFilter->SetInput(itkImage); labelStatisticsImageFilter->SetLabelInput(maskImage); labelStatisticsImageFilter->SetUseHistograms(true); labelStatisticsImageFilter->SetHistogramParameters(params.Bins, params.MinimumIntensity, params.MaximumIntensity); labelStatisticsImageFilter->Update(); typename HistogramType::MeasurementVectorType mv(1); mv[0] = 4.1; typename HistogramType::IndexType resultingIndex; auto histogram = labelStatisticsImageFilter->GetHistogram(1); double meanValue = 0; // labelStatisticsImageFilter->GetMean(1); GET_VARIABLE_INDEX(meanValue); double meanIndex = 0; // 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 + 1.0 + p25Index + 1.0); robustMeanAbsoluteDeviationValue /= robustCount; robustMeanAbsoluteDeivationIndex /= robustCount; - featureList.push_back(std::make_pair(params.prefix + "Mean Value", meanValue)); - featureList.push_back(std::make_pair(params.prefix + "Variance Value", varianceValue)); - featureList.push_back(std::make_pair(params.prefix + "Skewness Value", skewnessValue)); - featureList.push_back(std::make_pair(params.prefix + "Excess Kurtosis Value", kurtosisValue)); - featureList.push_back(std::make_pair(params.prefix + "Median Value", medianValue)); - featureList.push_back(std::make_pair(params.prefix + "Minimum Value", minimumValue)); - featureList.push_back(std::make_pair(params.prefix + "Percentile 10 Value", p10Value)); - featureList.push_back(std::make_pair(params.prefix + "Percentile 90 Value", p90Value)); - featureList.push_back(std::make_pair(params.prefix + "Maximum Value", maximumValue)); - featureList.push_back(std::make_pair(params.prefix + "Mode Value", modeValue)); - featureList.push_back(std::make_pair(params.prefix + "Interquantile Range Value", p75Value - p25Value)); - featureList.push_back(std::make_pair(params.prefix + "Range Value", maximumValue - minimumValue)); - featureList.push_back(std::make_pair(params.prefix + "Mean Absolute Deviation Value", meanAbsoluteDeviationValue)); - featureList.push_back(std::make_pair(params.prefix + "Robust Mean Absolute Deviation Value", robustMeanAbsoluteDeviationValue)); - featureList.push_back(std::make_pair(params.prefix + "Median Absolute Deviation Value", medianAbsoluteDeviationValue)); - featureList.push_back(std::make_pair(params.prefix + "Coefficient of Variation Value", coefficientOfVariationValue)); - featureList.push_back(std::make_pair(params.prefix + "Quantile coefficient of Dispersion Value", quantileCoefficientOfDispersionValue)); - featureList.push_back(std::make_pair(params.prefix + "Entropy Value", entropyValue)); - featureList.push_back(std::make_pair(params.prefix + "Uniformity Value", uniformityValue)); - featureList.push_back(std::make_pair(params.prefix + "Robust Mean Value", robustMeanValue)); - - featureList.push_back(std::make_pair(params.prefix + "Mean Index", meanIndex + 1 )); - featureList.push_back(std::make_pair(params.prefix + "Variance Index", varianceIndex)); - featureList.push_back(std::make_pair(params.prefix + "Skewness Index", skewnessIndex)); - featureList.push_back(std::make_pair(params.prefix + "Excess Kurtosis Index", kurtosisIndex)); - featureList.push_back(std::make_pair(params.prefix + "Median Index", medianIndex + 1)); - featureList.push_back(std::make_pair(params.prefix + "Minimum Index", minimumIndex + 1)); - featureList.push_back(std::make_pair(params.prefix + "Percentile 10 Index", p10Index + 1)); - featureList.push_back(std::make_pair(params.prefix + "Percentile 90 Index", p90Index + 1)); - featureList.push_back(std::make_pair(params.prefix + "Maximum Index", maximumIndex + 1)); - featureList.push_back(std::make_pair(params.prefix + "Mode Index", modeIndex + 1)); - featureList.push_back(std::make_pair(params.prefix + "Interquantile Range Index", p75Index - p25Index)); - featureList.push_back(std::make_pair(params.prefix + "Range Index", maximumIndex - minimumIndex)); - featureList.push_back(std::make_pair(params.prefix + "Mean Absolute Deviation Index", meanAbsoluteDeviationIndex)); - featureList.push_back(std::make_pair(params.prefix + "Robust Mean Absolute Deviation Index", robustMeanAbsoluteDeivationIndex)); - featureList.push_back(std::make_pair(params.prefix + "Median Absolute Deviation Index", medianAbsoluteDeviationIndex)); - featureList.push_back(std::make_pair(params.prefix + "Coefficient of Variation Index", coefficientOfVariationIndex)); - featureList.push_back(std::make_pair(params.prefix + "Quantile coefficient of Dispersion Index", quantileCoefficientOfDispersionIndex)); - featureList.push_back(std::make_pair(params.prefix + "Entropy Index", entropyIndex)); - featureList.push_back(std::make_pair(params.prefix + "Uniformity Index", uniformityIndex)); - featureList.push_back(std::make_pair(params.prefix + "Maximum Gradient", maximumGradientValue)); - featureList.push_back(std::make_pair(params.prefix + "Maximum Gradient Index", maximumGradientIndex)); - featureList.push_back(std::make_pair(params.prefix + "Minimum Gradient", minimumGradientValue)); - featureList.push_back(std::make_pair(params.prefix + "Minimum Gradient Index", minimumGradientIndex)); - featureList.push_back(std::make_pair(params.prefix + "Robust Mean Index", robustMeanIndex)); - - featureList.push_back(std::make_pair(params.prefix + "Number of Bins", histogram->GetSize(0))); - featureList.push_back(std::make_pair(params.prefix + "Bin Size", binWidth)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Mean Value"), meanValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Variance Value"), varianceValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Skewness Value"), skewnessValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Excess Kurtosis Value"), kurtosisValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Median Value"), medianValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Minimum Value"), minimumValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Percentile 10 Value"), p10Value)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Percentile 90 Value"), p90Value)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Maximum Value"), maximumValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Mode Value"), modeValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Interquantile Range Value"), p75Value - p25Value)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Range Value"), maximumValue - minimumValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Mean Absolute Deviation Value"), meanAbsoluteDeviationValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Robust Mean Absolute Deviation Value"), robustMeanAbsoluteDeviationValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Median Absolute Deviation Value"), medianAbsoluteDeviationValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Coefficient of Variation Value"), coefficientOfVariationValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Quantile coefficient of Dispersion Value"), quantileCoefficientOfDispersionValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Entropy Value"), entropyValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Uniformity Value"), uniformityValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Robust Mean Value"), robustMeanValue)); + + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Mean Index"), meanIndex + 1 )); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Variance Index"), varianceIndex)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Skewness Index"), skewnessIndex)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Excess Kurtosis Index"), kurtosisIndex)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Median Index"), medianIndex + 1)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Minimum Index"), minimumIndex + 1)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Percentile 10 Index"), p10Index + 1)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Percentile 90 Index"), p90Index + 1)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Maximum Index"), maximumIndex + 1)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Mode Index"), modeIndex + 1)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Interquantile Range Index"), p75Index - p25Index)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Range Index"), maximumIndex - minimumIndex)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Mean Absolute Deviation Index"), meanAbsoluteDeviationIndex)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Robust Mean Absolute Deviation Index"), robustMeanAbsoluteDeivationIndex)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Median Absolute Deviation Index"), medianAbsoluteDeviationIndex)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Coefficient of Variation Index"), coefficientOfVariationIndex)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Quantile coefficient of Dispersion Index"), quantileCoefficientOfDispersionIndex)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Entropy Index"), entropyIndex)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Uniformity Index"), uniformityIndex)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Maximum Gradient"), maximumGradientValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Maximum Gradient Index"), maximumGradientIndex)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Minimum Gradient"), minimumGradientValue)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Minimum Gradient Index"), minimumGradientIndex)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Robust Mean Index"), robustMeanIndex)); + + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Number of Bins"), histogram->GetSize(0))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Bin Size"), binWidth)); } mitk::GIFFirstOrderHistogramStatistics::GIFFirstOrderHistogramStatistics() { SetShortName("foh"); SetLongName("first-order-histogram"); SetFeatureClassName("First Order Histogram"); } -mitk::GIFFirstOrderHistogramStatistics::FeatureListType mitk::GIFFirstOrderHistogramStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFFirstOrderHistogramStatistics::DoCalculateFeatures(const Image* image, const Image* mask) { - InitializeQuantifier(image, mask); FeatureListType featureList; - ParameterStruct params; - params.MinimumIntensity = GetQuantifier()->GetMinimum(); - params.MaximumIntensity = GetQuantifier()->GetMaximum(); - params.Bins = GetQuantifier()->GetBins(); - params.prefix = FeatureDescriptionPrefix(); + this->InitializeQuantifier(image, mask); - AccessByItk_3(image, CalculateFirstOrderHistogramStatistics, mask, featureList, params); + MITK_INFO << "Start calculating first order histogram features ...."; - return featureList; -} + GIFFirstOrderHistogramStatisticsConfiguration config; + config.MinimumIntensity = GetQuantifier()->GetMinimum(); + config.MaximumIntensity = GetQuantifier()->GetMaximum(); + config.Bins = GetQuantifier()->GetBins(); + config.id = this->CreateTemplateFeatureID(); + + AccessByItk_3(image, CalculateFirstOrderHistogramStatistics, mask, featureList, config); + + MITK_INFO << "Finished calculating first order histogram features...."; -mitk::GIFFirstOrderHistogramStatistics::FeatureNameListType mitk::GIFFirstOrderHistogramStatistics::GetFeatureNames() -{ - FeatureNameListType featureList; return featureList; } - -void mitk::GIFFirstOrderHistogramStatistics::AddArguments(mitkCommandLineParser &parser) +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFFirstOrderHistogramStatistics::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { - AddQuantifierArguments(parser); - std::string name = GetOptionPrefix(); - - parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Histogram based First order features", "calculates first order features based on a histogram", us::Any()); + return Superclass::CalculateFeatures(image, maskNoNAN); } -void -mitk::GIFFirstOrderHistogramStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +void mitk::GIFFirstOrderHistogramStatistics::AddArguments(mitkCommandLineParser& parser) const { - std::string name = GetOptionPrefix(); - auto parsedArgs = GetParameter(); - if (parsedArgs.count(GetLongName())) - { - InitializeQuantifierFromParameters(feature, mask); + this->AddQuantifierArguments(parser); - 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 histogram features...."; - } -} -std::string mitk::GIFFirstOrderHistogramStatistics::GetCurrentFeatureEncoding() -{ - return QuantifierParameterString(); + std::string name = this->GetOptionPrefix(); + + parser.addArgument(this->GetLongName(), name, mitkCommandLineParser::Bool, "Use Co-occurence matrix", "calculates Co-occurence based features (new implementation)", us::Any()); } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp index 9e451fae22..a1d4df5296 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp @@ -1,355 +1,339 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include // ITK #include #include #include // STL #include struct FirstOrderNumericParameterStruct { mitk::IntensityQuantifier::Pointer quantifier; double MinimumIntensity; double MaximumIntensity; int Bins; - std::string prefix; + mitk::FeatureID id; }; template void -CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFFirstOrderNumericStatistics::FeatureListType & featureList, FirstOrderNumericParameterStruct params) +CalculateFirstOrderStatistics(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFFirstOrderNumericStatistics::FeatureListType & featureList, FirstOrderNumericParameterStruct params) { typedef itk::Image ImageType; typedef itk::Image MaskType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); // // Calculate the Volume of Voxel (Maximum to the 3th order) // double voxelVolume = 1; for (unsigned int i = 0; i < std::min(3, VImageDimension); ++i) voxelVolume *= itkImage->GetSpacing()[i]; // // Calculate the Hypervolume of Voxel // double voxelSpace = 1; for (unsigned int i = 0; i < VImageDimension; ++i) voxelSpace *= itkImage->GetSpacing()[i]; unsigned int numberOfBins = params.quantifier->GetBins(); std::vector histogram; histogram.resize(numberOfBins, 0); double minimum = std::numeric_limits::max(); double maximum = std::numeric_limits::lowest(); double absoluteMinimum = std::numeric_limits::max(); double absoluteMaximum = std::numeric_limits::lowest(); double sum = 0; double sumTwo= 0; double sumThree = 0; unsigned int numberOfVoxels = 0; - itk::ImageRegionIterator imageIter(itkImage, itkImage->GetLargestPossibleRegion()); - itk::ImageRegionIterator maskIter(maskImage, maskImage->GetLargestPossibleRegion()); + itk::ImageRegionConstIterator imageIter(itkImage, itkImage->GetLargestPossibleRegion()); + itk::ImageRegionConstIterator maskIter(maskImage, maskImage->GetLargestPossibleRegion()); while (!imageIter.IsAtEnd()) { double value = imageIter.Get(); absoluteMinimum = std::min(minimum, value); absoluteMaximum = std::max(maximum, value); if (maskIter.Get() > 0) { minimum = std::min(minimum, value); maximum = std::max(maximum, value); sum += value; sumTwo += value * value; sumThree += value * value*value; histogram[params.quantifier->IntensityToIndex(value)] += 1; ++numberOfVoxels; } ++maskIter; ++imageIter; } // // Histogram based calculations // unsigned int passedValues = 0; double doubleNoOfVoxes = numberOfVoxels; double median = 0; double lastIntensityWithValues = params.quantifier->IndexToMeanIntensity(0); std::size_t modeIdx = 0; double entropy = 0; double uniformity = 0; std::vector percentiles; percentiles.resize(20, 0); for (std::size_t idx = 0; idx < histogram.size(); ++idx) { unsigned int actualValues = histogram[idx]; for (std::size_t percentileIdx = 0; percentileIdx < percentiles.size(); ++percentileIdx) { double threshold = doubleNoOfVoxes * (percentileIdx + 1) *1.0 / (percentiles.size()); if ((passedValues < threshold) & ((passedValues + actualValues) >= threshold)) { // Lower Bound if (passedValues == std::floor(threshold)) { percentiles[percentileIdx] = 0.5*(lastIntensityWithValues + params.quantifier->IndexToMeanIntensity(idx)); } else { percentiles[percentileIdx] = params.quantifier->IndexToMeanIntensity(idx); } } } if ((passedValues < doubleNoOfVoxes * 0.5) & ((passedValues + actualValues) >= doubleNoOfVoxes * 0.5)) { // Lower Bound if (passedValues == std::floor(doubleNoOfVoxes * 0.5)) { median = 0.5*(lastIntensityWithValues + params.quantifier->IndexToMeanIntensity(idx)); } else { median = params.quantifier->IndexToMeanIntensity(idx); } } if (actualValues > histogram[modeIdx]) { modeIdx = idx; } if (actualValues > 0) { lastIntensityWithValues = params.quantifier->IndexToMeanIntensity(idx); double currentProbability = actualValues / (1.0 *numberOfVoxels); uniformity += currentProbability * currentProbability; entropy += currentProbability * std::log(currentProbability) / std::log(2); } passedValues += actualValues; } double p10 = percentiles[1]; //double p25idx = params.quantifier->IntensityToIndex(percentiles[4]); //double p75idx = params.quantifier->IntensityToIndex(percentiles[14]); double p25idx = percentiles[4]; double p75idx = percentiles[14]; double p90 = percentiles[17]; double mean = sum / (numberOfVoxels); double variance = sumTwo / (numberOfVoxels) - (mean*mean); double energy = sumTwo; double rootMeanSquare = std::sqrt(sumTwo / numberOfVoxels); double sumAbsoluteDistanceToMean = 0; double sumAbsoluteDistanceToMedian = 0; double sumRobust = 0; double sumRobustSquare = 0; double sumRobustAbsolulteDistanceToMean = 0; double sumValueMinusMean = 0; double sumValueMinusMeanThree = 0; double sumValueMinusMeanFour = 0; unsigned int numberOfRobustVoxel = 0; maskIter.GoToBegin(); imageIter.GoToBegin(); while (!imageIter.IsAtEnd()) { if (maskIter.Get() > 0) { double value = imageIter.Get(); double valueMinusMean = value - mean; sumAbsoluteDistanceToMean += std::abs(valueMinusMean); sumAbsoluteDistanceToMedian += std::abs(value - median); sumValueMinusMean += valueMinusMean; sumValueMinusMeanThree += valueMinusMean * valueMinusMean * valueMinusMean; sumValueMinusMeanFour += valueMinusMean * valueMinusMean * valueMinusMean * valueMinusMean; if ((p10 <= value) & (value <= p90)) { sumRobust += value; sumRobustSquare += value * value; ++numberOfRobustVoxel; } } ++maskIter; ++imageIter; } double robustMean = sumRobust / numberOfRobustVoxel; double robustVariance = sumRobustSquare / numberOfRobustVoxel - (robustMean * robustMean); maskIter.GoToBegin(); imageIter.GoToBegin(); while (!imageIter.IsAtEnd()) { if (maskIter.Get() > 0) { double value = imageIter.Get(); if ((p10 <= value) & (value <= p90)) { sumRobustAbsolulteDistanceToMean += std::abs(value - robustMean); } } ++maskIter; ++imageIter; } double meanAbsoluteDeviation = sumAbsoluteDistanceToMean / numberOfVoxels; double medianAbsoluteDeviation = sumAbsoluteDistanceToMedian / numberOfVoxels; double robustMeanAbsoluteDeviation = sumRobustAbsolulteDistanceToMean / numberOfRobustVoxel; double skewness = sumValueMinusMeanThree / numberOfVoxels / variance / std::sqrt(variance); double kurtosis = sumValueMinusMeanFour / numberOfVoxels / variance / variance; double interquantileRange = p75idx - p25idx; double coefficientOfVariation = std::sqrt(variance) / mean; double quantileCoefficientOfDispersion = (p75idx - p25idx) / (p75idx + p25idx); double coveredImageRange = (maximum - minimum)/ (absoluteMaximum - absoluteMinimum) ; - featureList.push_back(std::make_pair(params.prefix + "Mean", mean)); - featureList.push_back(std::make_pair(params.prefix + "Variance", variance)); - featureList.push_back(std::make_pair(params.prefix + "Skewness", skewness)); - featureList.push_back(std::make_pair(params.prefix + "Excess kurtosis", kurtosis-3)); - featureList.push_back(std::make_pair(params.prefix + "Median", median)); - featureList.push_back(std::make_pair(params.prefix + "Minimum", minimum)); - featureList.push_back(std::make_pair(params.prefix + "05th Percentile", percentiles[0])); - featureList.push_back(std::make_pair(params.prefix + "10th Percentile", percentiles[1])); - featureList.push_back(std::make_pair(params.prefix + "15th Percentile", percentiles[2])); - featureList.push_back(std::make_pair(params.prefix + "20th Percentile", percentiles[3])); - featureList.push_back(std::make_pair(params.prefix + "25th Percentile", percentiles[4])); - featureList.push_back(std::make_pair(params.prefix + "30th Percentile", percentiles[5])); - featureList.push_back(std::make_pair(params.prefix + "35th Percentile", percentiles[6])); - featureList.push_back(std::make_pair(params.prefix + "40th Percentile", percentiles[7])); - featureList.push_back(std::make_pair(params.prefix + "45th Percentile", percentiles[8])); - featureList.push_back(std::make_pair(params.prefix + "50th Percentile", percentiles[9])); - featureList.push_back(std::make_pair(params.prefix + "55th Percentile", percentiles[10])); - featureList.push_back(std::make_pair(params.prefix + "60th Percentile", percentiles[11])); - featureList.push_back(std::make_pair(params.prefix + "65th Percentile", percentiles[12])); - featureList.push_back(std::make_pair(params.prefix + "70th Percentile", percentiles[13])); - featureList.push_back(std::make_pair(params.prefix + "75th Percentile", percentiles[14])); - featureList.push_back(std::make_pair(params.prefix + "80th Percentile", percentiles[15])); - featureList.push_back(std::make_pair(params.prefix + "85th Percentile", percentiles[16])); - featureList.push_back(std::make_pair(params.prefix + "90th Percentile", percentiles[17])); - featureList.push_back(std::make_pair(params.prefix + "95th Percentile", percentiles[18])); - featureList.push_back(std::make_pair(params.prefix + "Maximum", maximum)); - featureList.push_back(std::make_pair(params.prefix + "Interquantile range", interquantileRange)); - featureList.push_back(std::make_pair(params.prefix + "Range", maximum-minimum)); - featureList.push_back(std::make_pair(params.prefix + "Mean absolute deviation", meanAbsoluteDeviation)); - featureList.push_back(std::make_pair(params.prefix + "Robust mean absolute deviation", robustMeanAbsoluteDeviation)); - featureList.push_back(std::make_pair(params.prefix + "Median absolute deviation", medianAbsoluteDeviation)); - featureList.push_back(std::make_pair(params.prefix + "Coefficient of variation", coefficientOfVariation)); - featureList.push_back(std::make_pair(params.prefix + "Quantile coefficient of dispersion", quantileCoefficientOfDispersion)); - featureList.push_back(std::make_pair(params.prefix + "Energy", energy)); - featureList.push_back(std::make_pair(params.prefix + "Root mean square", rootMeanSquare)); - - featureList.push_back(std::make_pair(params.prefix + "Standard Deviation", std::sqrt(variance))); - featureList.push_back(std::make_pair(params.prefix + "Kurtosis", kurtosis)); - featureList.push_back(std::make_pair(params.prefix + "Robust mean", robustMean)); - featureList.push_back(std::make_pair(params.prefix + "Robust variance", robustVariance)); - featureList.push_back(std::make_pair(params.prefix + "Covered image intensity range", coveredImageRange)); - featureList.push_back(std::make_pair(params.prefix + "Mode index", modeIdx)); - featureList.push_back(std::make_pair(params.prefix + "Mode value", params.quantifier->IndexToMeanIntensity(modeIdx))); - featureList.push_back(std::make_pair(params.prefix + "Mode probability", histogram[modeIdx] / (1.0*numberOfVoxels))); - featureList.push_back(std::make_pair(params.prefix + "Entropy", entropy)); - featureList.push_back(std::make_pair(params.prefix + "Uniformtiy", uniformity)); - featureList.push_back(std::make_pair(params.prefix + "Number of voxels", numberOfVoxels)); - featureList.push_back(std::make_pair(params.prefix + "Sum of voxels", sum)); - featureList.push_back(std::make_pair(params.prefix + "Voxel space", voxelSpace)); - featureList.push_back(std::make_pair(params.prefix + "Voxel volume", voxelVolume)); - featureList.push_back(std::make_pair(params.prefix + "Image Dimension", VImageDimension)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Mean"),mean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Variance"),variance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Skewness"),skewness)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Excess kurtosis"),kurtosis-3)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Median"),median)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Minimum"),minimum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "05th Percentile"),percentiles[0])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "10th Percentile"),percentiles[1])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "15th Percentile"),percentiles[2])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "20th Percentile"),percentiles[3])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "25th Percentile"),percentiles[4])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "30th Percentile"),percentiles[5])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "35th Percentile"),percentiles[6])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "40th Percentile"),percentiles[7])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "45th Percentile"),percentiles[8])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "50th Percentile"),percentiles[9])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "55th Percentile"),percentiles[10])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "60th Percentile"),percentiles[11])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "65th Percentile"),percentiles[12])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "70th Percentile"), percentiles[13])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "75th Percentile"), percentiles[14])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "80th Percentile"), percentiles[15])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "85th Percentile"), percentiles[16])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "90th Percentile"), percentiles[17])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "95th Percentile"), percentiles[18])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Maximum"), maximum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Interquantile range"), interquantileRange)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Range"), maximum-minimum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Mean absolute deviation"), meanAbsoluteDeviation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Robust mean absolute deviation"), robustMeanAbsoluteDeviation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Median absolute deviation"), medianAbsoluteDeviation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Coefficient of variation"), coefficientOfVariation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Quantile coefficient of dispersion"), quantileCoefficientOfDispersion)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Energy"), energy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Root mean square"), rootMeanSquare)); + + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Standard Deviation"), std::sqrt(variance))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Kurtosis"), kurtosis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Robust mean"), robustMean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Robust variance"), robustVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Covered image intensity range"), coveredImageRange)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Mode index"), modeIdx)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Mode value"), params.quantifier->IndexToMeanIntensity(modeIdx))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Mode probability"), histogram[modeIdx] / (1.0*numberOfVoxels))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Entropy"), entropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Uniformtiy"), uniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Number of voxels"), numberOfVoxels)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Sum of voxels"), sum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Voxel space"), voxelSpace)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Voxel volume"), voxelVolume)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Image Dimension"), VImageDimension)); return; } mitk::GIFFirstOrderNumericStatistics::GIFFirstOrderNumericStatistics() { SetShortName("fon"); SetLongName("first-order-numeric"); SetFeatureClassName("First Order Numeric"); } -mitk::GIFFirstOrderNumericStatistics::FeatureListType mitk::GIFFirstOrderNumericStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +void mitk::GIFFirstOrderNumericStatistics::AddArguments(mitkCommandLineParser& parser) const +{ + this->AddQuantifierArguments(parser); + + std::string name = this->GetOptionPrefix(); + parser.addArgument(this->GetLongName(), name, mitkCommandLineParser::Bool, "Use first order statistics (numericaly) as feature", "calculates first order statistics based features", us::Any()); +} + +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFFirstOrderNumericStatistics::DoCalculateFeatures(const Image* image, const Image* mask) { - InitializeQuantifier(image, mask); FeatureListType featureList; - FirstOrderNumericParameterStruct params; + this->InitializeQuantifier(image, mask); + MITK_INFO << "Start calculating first order features ...."; + + FirstOrderNumericParameterStruct params; params.quantifier = GetQuantifier(); params.MinimumIntensity = GetQuantifier()->GetMinimum(); params.MaximumIntensity = GetQuantifier()->GetMaximum(); params.Bins = GetQuantifier()->GetBins(); - params.prefix = FeatureDescriptionPrefix(); + params.id = this->CreateTemplateFeatureID(); AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, params); - return featureList; -} + MITK_INFO << "Finished calculating first order features...."; -mitk::GIFFirstOrderNumericStatistics::FeatureNameListType mitk::GIFFirstOrderNumericStatistics::GetFeatureNames() -{ - FeatureNameListType featureList; return featureList; } - -void mitk::GIFFirstOrderNumericStatistics::AddArguments(mitkCommandLineParser &parser) -{ - std::string name = GetOptionPrefix(); - - parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use First Order Statistic (Numeric)", "calculates First Order Statistic (Numeric)", us::Any()); - AddQuantifierArguments(parser); -} - -void -mitk::GIFFirstOrderNumericStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFFirstOrderNumericStatistics::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { - 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...."; - } + return Superclass::CalculateFeatures(image, maskNoNAN); } -std::string mitk::GIFFirstOrderNumericStatistics::GetCurrentFeatureEncoding() -{ - return QuantifierParameterString(); -} diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp index 4352de4a66..2254e01b22 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp @@ -1,323 +1,309 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include // ITK #include #include // STL #include +namespace mitk +{ + struct GIFFirstOrderStatisticsParameterStruct + { + double MinimumIntensity; + double MaximumIntensity; + int Bins; + FeatureID id; + }; +} + template void -CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFFirstOrderStatistics::FeatureListType & featureList, mitk::GIFFirstOrderStatistics::ParameterStruct params) +CalculateFirstOrderStatistics(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFFirstOrderStatistics::FeatureListType & featureList, mitk::GIFFirstOrderStatisticsParameterStruct params) { typedef itk::Image ImageType; 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 (unsigned int i = 0; i < std::min(3, VImageDimension); ++i) voxelVolume *= itkImage->GetSpacing()[i]; double voxelSpace = 1; 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); double min = params.MinimumIntensity; double max = params.MaximumIntensity; 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(params.prefix + "Mean", labelStatisticsImageFilter->GetMean(1))); - featureList.push_back(std::make_pair(params.prefix + "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(params.prefix + "Biased Variance", variance)); - featureList.push_back(std::make_pair(params.prefix + "Skewness", skewness)); - featureList.push_back(std::make_pair(params.prefix + "Kurtosis", kurtosis)); - featureList.push_back(std::make_pair(params.prefix + "Median", labelStatisticsImageFilter->GetMedian(1))); - featureList.push_back(std::make_pair(params.prefix + "Minimum", labelStatisticsImageFilter->GetMinimum(1))); - featureList.push_back(std::make_pair(params.prefix + "Maximum", labelStatisticsImageFilter->GetMaximum(1))); - featureList.push_back(std::make_pair(params.prefix + "Range", range)); - featureList.push_back(std::make_pair(params.prefix + "Mean Absolute Deviation", mean_absolut_deviation)); - featureList.push_back(std::make_pair(params.prefix + "Robust Mean Absolute Deviation", robustMeanAbsoluteDeviation)); - featureList.push_back(std::make_pair(params.prefix + "Median Absolute Deviation", median_absolut_deviation)); - featureList.push_back(std::make_pair(params.prefix + "Coefficient Of Variation", coefficient_of_variation)); - featureList.push_back(std::make_pair(params.prefix + "Quantile Coefficient Of Dispersion", quantile_coefficient_of_dispersion)); - featureList.push_back(std::make_pair(params.prefix + "Energy", squared_sum)); - featureList.push_back(std::make_pair(params.prefix + "Root Mean Square", rms)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Mean"), labelStatisticsImageFilter->GetMean(1))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"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(mitk::CreateFeatureID(params.id,"Biased Variance"), variance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Skewness"), skewness)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Kurtosis"), kurtosis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Median"), labelStatisticsImageFilter->GetMedian(1))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Minimum"), labelStatisticsImageFilter->GetMinimum(1))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Maximum"), labelStatisticsImageFilter->GetMaximum(1))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Range"), range)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Mean Absolute Deviation"), mean_absolut_deviation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Robust Mean Absolute Deviation"), robustMeanAbsoluteDeviation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Median Absolute Deviation"), median_absolut_deviation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Coefficient Of Variation"), coefficient_of_variation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Quantile Coefficient Of Dispersion"), quantile_coefficient_of_dispersion)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Energy"), squared_sum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Root Mean Square"), rms)); typename HistogramType::MeasurementVectorType mv(1); mv[0] = 0; typename HistogramType::IndexType resultingIndex; histogram->GetIndex(mv, resultingIndex); - featureList.push_back(std::make_pair(params.prefix + "Robust Mean", meanRobust)); - featureList.push_back(std::make_pair(params.prefix + "Uniformity", uniformity)); - featureList.push_back(std::make_pair(params.prefix + "Entropy", entropy)); - featureList.push_back(std::make_pair(params.prefix + "Excess Kurtosis", kurtosis - 3)); - featureList.push_back(std::make_pair(params.prefix + "Covered Image Intensity Range", coveredGrayValueRange)); - featureList.push_back(std::make_pair(params.prefix + "Sum", labelStatisticsImageFilter->GetSum(1))); - featureList.push_back(std::make_pair(params.prefix + "Mode", mode_bin)); - featureList.push_back(std::make_pair(params.prefix + "Mode Probability", mode_value)); - featureList.push_back(std::make_pair(params.prefix + "Unbiased Standard deviation", labelStatisticsImageFilter->GetSigma(1))); - featureList.push_back(std::make_pair(params.prefix + "Biased Standard deviation", sqrt(variance))); - featureList.push_back(std::make_pair(params.prefix + "Number Of Voxels", labelStatisticsImageFilter->GetCount(1))); - - featureList.push_back(std::make_pair(params.prefix + "05th Percentile", p05th)); - featureList.push_back(std::make_pair(params.prefix + "10th Percentile", p10th)); - featureList.push_back(std::make_pair(params.prefix + "15th Percentile", p15th)); - featureList.push_back(std::make_pair(params.prefix + "20th Percentile", p20th)); - featureList.push_back(std::make_pair(params.prefix + "25th Percentile", p25th)); - featureList.push_back(std::make_pair(params.prefix + "30th Percentile", p30th)); - featureList.push_back(std::make_pair(params.prefix + "35th Percentile", p35th)); - featureList.push_back(std::make_pair(params.prefix + "40th Percentile", p40th)); - featureList.push_back(std::make_pair(params.prefix + "45th Percentile", p45th)); - featureList.push_back(std::make_pair(params.prefix + "50th Percentile", p50th)); - featureList.push_back(std::make_pair(params.prefix + "55th Percentile", p55th)); - featureList.push_back(std::make_pair(params.prefix + "60th Percentile", p60th)); - featureList.push_back(std::make_pair(params.prefix + "65th Percentile", p65th)); - featureList.push_back(std::make_pair(params.prefix + "70th Percentile", p70th)); - featureList.push_back(std::make_pair(params.prefix + "75th Percentile", p75th)); - featureList.push_back(std::make_pair(params.prefix + "80th Percentile", p80th)); - featureList.push_back(std::make_pair(params.prefix + "85th Percentile", p85th)); - featureList.push_back(std::make_pair(params.prefix + "90th Percentile", p90th)); - featureList.push_back(std::make_pair(params.prefix + "95th Percentile", p95th)); - featureList.push_back(std::make_pair(params.prefix + "Interquartile Range", (p75th - p25th))); - featureList.push_back(std::make_pair(params.prefix + "Image Dimension", VImageDimension)); - featureList.push_back(std::make_pair(params.prefix + "Voxel Space", voxelSpace)); - featureList.push_back(std::make_pair(params.prefix + "Voxel Volume", voxelVolume)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Robust Mean"), meanRobust)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Uniformity"), uniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Entropy"), entropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Excess Kurtosis"), kurtosis - 3)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Covered Image Intensity Range"), coveredGrayValueRange)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Sum"), labelStatisticsImageFilter->GetSum(1))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Mode"), mode_bin)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Mode Probability"), mode_value)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Unbiased Standard deviation"), labelStatisticsImageFilter->GetSigma(1))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Biased Standard deviation"), sqrt(variance))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Number Of Voxels"), labelStatisticsImageFilter->GetCount(1))); + + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"05th Percentile"), p05th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"10th Percentile"), p10th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"15th Percentile"), p15th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"20th Percentile"), p20th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"25th Percentile"), p25th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"30th Percentile"), p30th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"35th Percentile"), p35th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"40th Percentile"), p40th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"45th Percentile"), p45th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"50th Percentile"), p50th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"55th Percentile"), p55th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"60th Percentile"), p60th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"65th Percentile"), p65th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"70th Percentile"), p70th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"75th Percentile"), p75th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"80th Percentile"), p80th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"85th Percentile"), p85th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"90th Percentile"), p90th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"95th Percentile"), p95th)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Interquartile Range"), (p75th - p25th))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Image Dimension"), VImageDimension)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Voxel Space"), voxelSpace)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id,"Voxel Volume"), voxelVolume)); } mitk::GIFFirstOrderStatistics::GIFFirstOrderStatistics() { SetShortName("fo"); SetLongName("first-order"); SetFeatureClassName("First Order"); } -mitk::GIFFirstOrderStatistics::FeatureListType mitk::GIFFirstOrderStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +void mitk::GIFFirstOrderStatistics::AddArguments(mitkCommandLineParser& parser) const +{ + this->AddQuantifierArguments(parser); + + std::string name = this->GetOptionPrefix(); + parser.addArgument(this->GetLongName(), name, mitkCommandLineParser::Bool, "Use first order statistics as feature", "calculates first order statistics features", us::Any()); +} + +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFFirstOrderStatistics::DoCalculateFeatures(const Image* image, const Image* mask) { - InitializeQuantifier(image, mask); FeatureListType featureList; - ParameterStruct params; + this->InitializeQuantifier(image, mask); + + MITK_INFO << "Start calculating first order features ...."; + GIFFirstOrderStatisticsParameterStruct params; params.MinimumIntensity = GetQuantifier()->GetMinimum(); params.MaximumIntensity = GetQuantifier()->GetMaximum(); params.Bins = GetQuantifier()->GetBins(); - params.prefix = FeatureDescriptionPrefix(); + params.id = this->CreateTemplateFeatureID(); AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, params); - return featureList; -} + MITK_INFO << "Finished calculating first order features...."; -mitk::GIFFirstOrderStatistics::FeatureNameListType mitk::GIFFirstOrderStatistics::GetFeatureNames() -{ - FeatureNameListType featureList; - 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::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...."; - } -} - -std::string mitk::GIFFirstOrderStatistics::GetCurrentFeatureEncoding() +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFFirstOrderStatistics::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { - return QuantifierParameterString(); + return Superclass::CalculateFeatures(image, maskNoNAN); } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp index c09ea25cfd..c6c069473f 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp @@ -1,482 +1,467 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include #include #include // ITK #include #include #include #include #include namespace mitk{ + + struct GreyLevelDistanceZoneConfiguration + { + mitk::Image::Pointer distanceMask; + + mitk::IntensityQuantifier::Pointer Quantifier; + + unsigned int direction; + double MinimumIntensity; + double MaximumIntensity; + int Bins; + FeatureID id; + }; + struct GreyLevelDistanceZoneMatrixHolder { public: GreyLevelDistanceZoneMatrixHolder(mitk::IntensityQuantifier::Pointer quantifier, int number, int maxSize); int IntensityToIndex(double intensity); int m_NumberOfBins; int m_MaximumSize; int m_NumerOfVoxels; Eigen::MatrixXd m_Matrix; mitk::IntensityQuantifier::Pointer m_Quantifier; }; } static -void MatrixFeaturesTo(mitk::GreyLevelDistanceZoneFeatures features, - std::string prefix, - mitk::GIFGreyLevelDistanceZone::FeatureListType &featureList); - - +void MatrixFeaturesTo(const mitk::GreyLevelDistanceZoneFeatures& features, + const mitk::GreyLevelDistanceZoneConfiguration& config, + mitk::GIFGreyLevelDistanceZone::FeatureListType& featureList) +{ + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Distance Emphasis"), features.SmallDistanceEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Distance Emphasis"), features.LargeDistanceEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Grey Level Emphasis"), features.LowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Grey Level Emphasis"), features.HighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Distance Low Grey Level Emphasis"), features.SmallDistanceLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Distance High Grey Level Emphasis"), features.SmallDistanceHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Distance Low Grey Level Emphasis"), features.LargeDistanceLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Distance High Grey Level Emphasis"), features.LargeDistanceHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity"), features.GreyLevelNonUniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity Normalized"), features.GreyLevelNonUniformityNormalized)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Distance Size Non-Uniformity"), features.ZoneDistanceNonUniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Distance Size Non-Uniformity Normalized"), features.ZoneDistanceNoneUniformityNormalized)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Percentage"), features.ZonePercentage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Mean"), features.GreyLevelMean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Variance"), features.GreyLevelVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Distance Mean"), features.ZoneDistanceMean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Distance Variance"), features.ZoneDistanceVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Distance Entropy"), features.ZoneDistanceEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Entropy"), features.ZoneDistanceEntropy)); +} mitk::GreyLevelDistanceZoneMatrixHolder::GreyLevelDistanceZoneMatrixHolder(mitk::IntensityQuantifier::Pointer quantifier, int number, int maxSize) : m_NumberOfBins(number), m_MaximumSize(maxSize), m_NumerOfVoxels(0), m_Quantifier(quantifier) { m_Matrix.resize(number, maxSize); m_Matrix.fill(0); } int mitk::GreyLevelDistanceZoneMatrixHolder::IntensityToIndex(double intensity) { return m_Quantifier->IntensityToIndex(intensity); } template int -CalculateGlSZMatrix(itk::Image* itkImage, - itk::Image* mask, - itk::Image* distanceImage, +CalculateGlSZMatrix(const itk::Image* itkImage, + const itk::Image* mask, + const itk::Image* distanceImage, std::vector > offsets, bool estimateLargestRegion, mitk::GreyLevelDistanceZoneMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef typename ImageType::IndexType IndexType; - typedef itk::ImageRegionIteratorWithIndex ConstIterType; - typedef itk::ImageRegionIteratorWithIndex ConstMaskIterType; + typedef itk::ImageRegionConstIteratorWithIndex ConstIterType; + typedef itk::ImageRegionConstIteratorWithIndex 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 itkErode2( itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int &maxDistance) { typedef itk::Image ImageType; typedef unsigned short MaskType; typedef itk::Image MaskImageType; typename MaskImageType::Pointer distanceImage = MaskImageType::New(); distanceImage->SetRegions(sourceImage->GetLargestPossibleRegion()); distanceImage->SetOrigin(sourceImage->GetOrigin()); distanceImage->SetSpacing(sourceImage->GetSpacing()); distanceImage->SetDirection(sourceImage->GetDirection()); distanceImage->Allocate(); distanceImage->FillBuffer(std::numeric_limits::max()-1); typename ImageType::SizeType radius; radius.Fill(1); itk::NeighborhoodIterator neighbourIter(radius, sourceImage, sourceImage->GetLargestPossibleRegion()); itk::NeighborhoodIterator distanceIter(radius, distanceImage, distanceImage->GetLargestPossibleRegion()); bool imageChanged = true; while (imageChanged) { imageChanged = false; maxDistance = 0; neighbourIter.GoToBegin(); distanceIter.GoToBegin(); while (!neighbourIter.IsAtEnd()) { MaskType oldDistance = distanceIter.GetCenterPixel(); maxDistance = std::max(maxDistance, oldDistance); if (neighbourIter.GetCenterPixel() < 1) { if (oldDistance > 0) { distanceIter.SetCenterPixel(0); imageChanged = true; } } else if (oldDistance>0) { MaskType minimumDistance = oldDistance; for (unsigned int i = 0; i < distanceIter.Size(); ++i) { minimumDistance = std::min(minimumDistance, 1+distanceIter.GetPixel(i)); } if (minimumDistance != oldDistance) { distanceIter.SetCenterPixel(minimumDistance); imageChanged = true; } } ++neighbourIter; ++distanceIter; } } mitk::CastToMitkImage(distanceImage, resultImage); } void erode(mitk::Image::Pointer input, mitk::Image::Pointer &output, int &maxDistance) { AccessByItk_2(input, itkErode2, output, maxDistance); } void erodeAndAdd(mitk::Image::Pointer input, mitk::Image::Pointer& finalOutput, int &maxDistance) { maxDistance = 0; erode(input, finalOutput, maxDistance); } 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 < pgzMatrix.rows(); ++i) for (int j = 0; j < pgzMatrix.cols(); ++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) +CalculateGreyLevelDistanceZoneFeatures(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFGreyLevelDistanceZone::FeatureListType & featureList, mitk::GreyLevelDistanceZoneConfiguration config) { typedef itk::Image MaskType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// 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) { 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(config.Quantifier, config.Bins, maximumDistance + 1); mitk::GreyLevelDistanceZoneFeatures overallFeature; CalculateGlSZMatrix(itkImage, maskImage, distanceImage, offsetVector, false, holderOverall); CalculateFeatures(holderOverall, overallFeature); - MatrixFeaturesTo(overallFeature, config.prefix, 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 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)); + MatrixFeaturesTo(overallFeature, config, featureList); } mitk::GIFGreyLevelDistanceZone::GIFGreyLevelDistanceZone() { SetShortName("gldz"); SetLongName("distance-zone"); SetFeatureClassName("Grey Level Distance Zone"); } -mitk::GIFGreyLevelDistanceZone::FeatureListType mitk::GIFGreyLevelDistanceZone::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +void mitk::GIFGreyLevelDistanceZone::AddArguments(mitkCommandLineParser& parser) const +{ + this->AddQuantifierArguments(parser); + + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Grey Level Distance Zone", "Calculates the size zone based features.", us::Any()); +} + +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFGreyLevelDistanceZone::DoCalculateFeatures(const Image* image, const Image* mask) { - InitializeQuantifier(image, mask); FeatureListType featureList; - GIFGreyLevelDistanceZoneConfiguration config; + InitializeQuantifier(image, mask); + + MITK_INFO << "Start calculating Grey Level Distance Zone ...."; + + + GreyLevelDistanceZoneConfiguration config; config.direction = GetDirection(); if (GetMorphMask().IsNull()) { config.distanceMask = mask->Clone(); } else { config.distanceMask = GetMorphMask(); } config.MinimumIntensity = GetQuantifier()->GetMinimum(); config.MaximumIntensity = GetQuantifier()->GetMaximum(); config.Bins = GetQuantifier()->GetBins(); - config.prefix = FeatureDescriptionPrefix(); + config.id = this->CreateTemplateFeatureID(); config.Quantifier = GetQuantifier(); AccessByItk_3(image, CalculateGreyLevelDistanceZoneFeatures, mask, featureList, config); - return featureList; -} + MITK_INFO << "Finished calculating Grey Level Distance Zone."; -mitk::GIFGreyLevelDistanceZone::FeatureNameListType mitk::GIFGreyLevelDistanceZone::GetFeatureNames() -{ - FeatureNameListType featureList; return featureList; } - - - -void mitk::GIFGreyLevelDistanceZone::AddArguments(mitkCommandLineParser &parser) -{ - std::string name = GetOptionPrefix(); - - parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Grey Level Distance Zone", "Calculates the size zone based features.", us::Any()); - AddQuantifierArguments(parser); -} - -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())) - { - InitializeQuantifierFromParameters(feature, mask); - - 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."; - } - -} - -std::string mitk::GIFGreyLevelDistanceZone::GetCurrentFeatureEncoding() +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFGreyLevelDistanceZone::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { - return QuantifierParameterString(); + return Superclass::CalculateFeatures(image, maskNoNAN); } - diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp index 35d3ebf7eb..04631b1ed8 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp @@ -1,285 +1,281 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include // ITK #include // STL #include +namespace mitk +{ + struct GIFGreyLevelRunLengthParameters + { + unsigned int m_Direction; + + double MinimumIntensity; + double MaximumIntensity; + int Bins; + FeatureID id; + }; +} + + template void - CalculateGrayLevelRunLengthFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFGreyLevelRunLength::FeatureListType & featureList, mitk::GIFGreyLevelRunLength::ParameterStruct params) + CalculateGrayLevelRunLengthFeatures(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFGreyLevelRunLength::FeatureListType & featureList, mitk::GIFGreyLevelRunLengthParameters params) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::Statistics::EnhancedScalarImageToRunLengthFeaturesFilter FilterType; 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); filter->SetInput(itkImage); filter->SetMaskImage(maskImage); filter->SetRequestedFeatures(requestedFeatures); filter2->SetInput(itkImage); filter2->SetMaskImage(maskImage); filter2->SetRequestedFeatures(requestedFeatures); int numberOfBins = params.Bins; if (numberOfBins < 2) numberOfBins = 256; double minRange = params.MinimumIntensity; double maxRange = params.MaximumIntensity; filter->SetPixelValueMinMax(minRange, maxRange); filter->SetNumberOfBinsPerAxis(numberOfBins); filter2->SetPixelValueMinMax(minRange, maxRange); filter2->SetNumberOfBinsPerAxis(numberOfBins); filter->SetDistanceValueMinMax(0, numberOfBins); filter2->SetDistanceValueMinMax(0, numberOfBins); filter2->CombinedFeatureCalculationOn(); filter->Update(); filter2->Update(); auto featureMeans = filter->GetFeatureMeans (); auto featureStd = filter->GetFeatureStandardDeviations(); auto featureCombined = filter2->GetFeatureMeans(); for (std::size_t i = 0; i < featureMeans->size(); ++i) { switch (i) { case TextureFilterType::ShortRunEmphasis : - featureList.push_back(std::make_pair(params.featurePrefix + "Short run emphasis Means",featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Short run emphasis Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Short run emphasis Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Short run emphasis Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Short run emphasis Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Short run emphasis Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::LongRunEmphasis : - featureList.push_back(std::make_pair(params.featurePrefix + "Long run emphasis Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Long run emphasis Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Long run emphasis Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Long run emphasis Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Long run emphasis Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Long run emphasis Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::GreyLevelNonuniformity : - featureList.push_back(std::make_pair(params.featurePrefix + "Grey level nonuniformity Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Grey level nonuniformity Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Grey level nonuniformity Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Grey level nonuniformity Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Grey level nonuniformity Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Grey level nonuniformity Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::GreyLevelNonuniformityNormalized : - featureList.push_back(std::make_pair(params.featurePrefix + "Grey level nonuniformity normalized Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Grey level nonuniformity normalized Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Grey level nonuniformity normalized Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Grey level nonuniformity normalized Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Grey level nonuniformity normalized Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Grey level nonuniformity normalized Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::RunLengthNonuniformity : - featureList.push_back(std::make_pair(params.featurePrefix + "Run length nonuniformity Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Run length nonuniformity Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Run length nonuniformity Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run length nonuniformity Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run length nonuniformity Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run length nonuniformity Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::RunLengthNonuniformityNormalized : - featureList.push_back(std::make_pair(params.featurePrefix + "Run length nonuniformity normalized Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Run length nonuniformity normalized Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Run length nonuniformity normalized Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run length nonuniformity normalized Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run length nonuniformity normalized Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run length nonuniformity normalized Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::LowGreyLevelRunEmphasis : - featureList.push_back(std::make_pair(params.featurePrefix + "Low grey level run emphasis Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Low grey level run emphasis Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Low grey level run emphasis Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Low grey level run emphasis Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Low grey level run emphasis Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Low grey level run emphasis Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::HighGreyLevelRunEmphasis : - featureList.push_back(std::make_pair(params.featurePrefix + "High grey level run emphasis Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "High grey level run emphasis Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "High grey level run emphasis Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "High grey level run emphasis Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "High grey level run emphasis Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "High grey level run emphasis Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::ShortRunLowGreyLevelEmphasis : - featureList.push_back(std::make_pair(params.featurePrefix + "Short run low grey level emphasis Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Short run low grey level emphasis Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Short run low grey level emphasis Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Short run low grey level emphasis Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Short run low grey level emphasis Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Short run low grey level emphasis Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::ShortRunHighGreyLevelEmphasis : - featureList.push_back(std::make_pair(params.featurePrefix + "Short run high grey level emphasis Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Short run high grey level emphasis Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Short run high grey level emphasis Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Short run high grey level emphasis Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Short run high grey level emphasis Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Short run high grey level emphasis Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::LongRunLowGreyLevelEmphasis : - featureList.push_back(std::make_pair(params.featurePrefix + "Long run low grey level emphasis Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Long run low grey level emphasis Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Long run low grey level emphasis Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Long run low grey level emphasis Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Long run low grey level emphasis Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Long run low grey level emphasis Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::LongRunHighGreyLevelEmphasis : - featureList.push_back(std::make_pair(params.featurePrefix + "Long run high grey level emphasis Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Long run high grey level emphasis Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Long run high grey level emphasis Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Long run high grey level emphasis Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Long run high grey level emphasis Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Long run high grey level emphasis Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::RunPercentage : - featureList.push_back(std::make_pair(params.featurePrefix + "Run percentage Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Run percentage Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Run percentage Comb.", featureCombined->ElementAt(i) / newOffset->size())); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run percentage Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run percentage Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run percentage Comb."), featureCombined->ElementAt(i) / newOffset->size())); break; case TextureFilterType::NumberOfRuns : - featureList.push_back(std::make_pair(params.featurePrefix + "Number of runs Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Number of runs Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Number of runs Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Number of runs Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Number of runs Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Number of runs Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::GreyLevelVariance : - featureList.push_back(std::make_pair(params.featurePrefix + "Grey level variance Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Grey level variance Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Grey level variance Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Grey level variance Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Grey level variance Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Grey level variance Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::RunLengthVariance : - featureList.push_back(std::make_pair(params.featurePrefix + "Run length variance Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Run length variance Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Run length variance Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run length variance Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run length variance Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run length variance Comb."), featureCombined->ElementAt(i))); break; case TextureFilterType::RunEntropy : - featureList.push_back(std::make_pair(params.featurePrefix + "Run length entropy Means", featureMeans->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Run length entropy Std.", featureStd->ElementAt(i))); - featureList.push_back(std::make_pair(params.featurePrefix + "Run length entropy Comb.", featureCombined->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run length entropy Means"), featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run length entropy Std."), featureStd->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Run length entropy Comb."), featureCombined->ElementAt(i))); break; default: break; } } } mitk::GIFGreyLevelRunLength::GIFGreyLevelRunLength() { SetShortName("rl"); SetLongName("run-length"); SetFeatureClassName("Run Length"); } -mitk::GIFGreyLevelRunLength::FeatureListType mitk::GIFGreyLevelRunLength::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +void mitk::GIFGreyLevelRunLength::AddArguments(mitkCommandLineParser &parser) const +{ + this->AddQuantifierArguments(parser); + + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Run-Length", "Calculates Run-Length based features", us::Any()); +} + +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFGreyLevelRunLength::DoCalculateFeatures(const Image* image, const Image* mask) { - InitializeQuantifier(image, mask); FeatureListType featureList; - ParameterStruct params; + InitializeQuantifier(image, mask); + + MITK_INFO << "Start calculating Run-length"; + + GIFGreyLevelRunLengthParameters params; params.m_Direction = GetDirection(); params.MinimumIntensity = GetQuantifier()->GetMinimum(); params.MaximumIntensity = GetQuantifier()->GetMaximum(); params.Bins = GetQuantifier()->GetBins(); - params.featurePrefix = FeatureDescriptionPrefix(); + params.id = this->CreateTemplateFeatureID(); + MITK_INFO << params.MinimumIntensity; MITK_INFO << params.MaximumIntensity; MITK_INFO << params.m_Direction; MITK_INFO << params.Bins; - AccessByItk_3(image, CalculateGrayLevelRunLengthFeatures, mask, featureList,params); + AccessByItk_3(image, CalculateGrayLevelRunLengthFeatures, mask, featureList, params); + MITK_INFO << "Finished calculating Run-length"; + return featureList; } -mitk::GIFGreyLevelRunLength::FeatureNameListType mitk::GIFGreyLevelRunLength::GetFeatureNames() -{ - FeatureNameListType featureList; - return featureList; -} - - -void mitk::GIFGreyLevelRunLength::AddArguments(mitkCommandLineParser &parser) -{ - std::string name = GetOptionPrefix(); - - parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Run-Length", "Calculates Run-Length based features", us::Any()); - AddQuantifierArguments(parser); -} - -void -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())) - { - InitializeQuantifierFromParameters(feature, maskNoNAN); - - MITK_INFO << "Start calculating Run-length"; - auto localResults = this->CalculateFeatures(feature, maskNoNAN); - featureList.insert(featureList.end(), localResults.begin(), localResults.end()); - MITK_INFO << "Finished calculating Run-length"; - } - -} - -std::string mitk::GIFGreyLevelRunLength::GetCurrentFeatureEncoding() +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFGreyLevelRunLength::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { - return QuantifierParameterString(); + return Superclass::CalculateFeatures(image, maskNoNAN); } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp index 56e1f0220e..27df56c3b8 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp @@ -1,450 +1,429 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include // ITK #include // STL namespace mitk { + struct GIFGreyLevelSizeZoneConfiguration + { + unsigned int direction; + + double MinimumIntensity; + double MaximumIntensity; + int Bins; + FeatureID id; + }; + 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; }; } static -void MatrixFeaturesTo(mitk::GreyLevelSizeZoneFeatures features, - std::string prefix, - mitk::GIFGreyLevelSizeZone::FeatureListType &featureList); - - +void MatrixFeaturesTo(const mitk::GreyLevelSizeZoneFeatures& features, + const mitk::GIFGreyLevelSizeZoneConfiguration& config, + mitk::GIFGreyLevelSizeZone::FeatureListType& featureList) +{ + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Zone Emphasis"), features.SmallZoneEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Zone Emphasis"), features.LargeZoneEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Grey Level Emphasis"), features.LowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Grey Level Emphasis"), features.HighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Zone Low Grey Level Emphasis"), features.SmallZoneLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Zone High Grey Level Emphasis"), features.SmallZoneHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Zone Low Grey Level Emphasis"), features.LargeZoneLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Zone High Grey Level Emphasis"), features.LargeZoneHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity"), features.GreyLevelNonUniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity Normalized"), features.GreyLevelNonUniformityNormalized)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Size Non-Uniformity"), features.ZoneSizeNonUniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Size Non-Uniformity Normalized"), features.ZoneSizeNoneUniformityNormalized)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Percentage"), features.ZonePercentage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Mean"), features.GreyLevelMean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Variance"), features.GreyLevelVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Size Mean"), features.ZoneSizeMean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Size Variance"), features.ZoneSizeVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Size Entropy"), features.ZoneSizeEntropy)); +} 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 static int -CalculateGlSZMatrix(itk::Image* itkImage, - itk::Image* mask, +CalculateGlSZMatrix(const itk::Image* itkImage, + const itk::Image* mask, std::vector > offsets, bool estimateLargestRegion, mitk::GreyLevelSizeZoneMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef typename ImageType::IndexType IndexType; - typedef itk::ImageRegionIteratorWithIndex ConstIterType; - typedef itk::ImageRegionIteratorWithIndex ConstMaskIterType; + typedef itk::ImageRegionConstIteratorWithIndex ConstIterType; + typedef itk::ImageRegionConstIteratorWithIndex 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; } 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) + for (int i = 0; i < pgzMatrix.rows(); ++i) + for (int j = 0; j < pgzMatrix.cols(); ++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 static void -CalculateGreyLevelSizeZoneFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFGreyLevelSizeZone::FeatureListType & featureList, mitk::GIFGreyLevelSizeZone::GIFGreyLevelSizeZoneConfiguration config) +CalculateGreyLevelSizeZoneFeatures(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFGreyLevelSizeZone::FeatureListType & featureList, mitk::GIFGreyLevelSizeZoneConfiguration config) { typedef itk::Image MaskType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// double rangeMin = config.MinimumIntensity; double rangeMax = config.MaximumIntensity; int numberOfBins = config.Bins; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); //Find possible directions std::vector < itk::Offset > offsetVector; NeighborhoodType hood; hood.SetRadius(1); unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetType offset; for (unsigned int d = 0; d < centerIndex; d++) { offset = hood.GetOffset(d); bool useOffset = true; for (unsigned int i = 0; i < VImageDimension; ++i) { 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); - MatrixFeaturesTo(overallFeature, config.prefix, 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)); + MatrixFeaturesTo(overallFeature, config, featureList); } mitk::GIFGreyLevelSizeZone::GIFGreyLevelSizeZone() { SetShortName("glsz"); SetLongName("grey-level-sizezone"); SetFeatureClassName("Grey Level Size Zone"); } -mitk::GIFGreyLevelSizeZone::FeatureListType mitk::GIFGreyLevelSizeZone::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +void mitk::GIFGreyLevelSizeZone::AddArguments(mitkCommandLineParser& parser) const { - InitializeQuantifier(image, mask); + this->AddQuantifierArguments(parser); + + std::string name = GetOptionPrefix(); + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Grey Level Size Zone", "Calculates the size zone based features.", us::Any()); +} + +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFGreyLevelSizeZone::DoCalculateFeatures(const Image* image, const Image* mask) +{ FeatureListType featureList; + InitializeQuantifier(image, mask); + + MITK_INFO << "Start calculating Grey leve size zone ..."; + GIFGreyLevelSizeZoneConfiguration config; config.direction = GetDirection(); config.MinimumIntensity = GetQuantifier()->GetMinimum(); config.MaximumIntensity = GetQuantifier()->GetMaximum(); config.Bins = GetQuantifier()->GetBins(); - config.prefix = FeatureDescriptionPrefix(); + config.id = this->CreateTemplateFeatureID(); AccessByItk_3(image, CalculateGreyLevelSizeZoneFeatures, mask, featureList, config); - return featureList; -} + MITK_INFO << "Finished calculating Grey level size zone ..."; -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::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) +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFGreyLevelSizeZone::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { - auto parsedArgs = GetParameter(); - std::string name = GetOptionPrefix(); - - if (parsedArgs.count(GetLongName())) - { - InitializeQuantifierFromParameters(feature, maskNoNAN); - - 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 ..."; - } - + return Superclass::CalculateFeatures(image, maskNoNAN); } - -std::string mitk::GIFGreyLevelSizeZone::GetCurrentFeatureEncoding() -{ - return QuantifierParameterString(); -} - diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp index 186e059624..2605314a5f 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp @@ -1,173 +1,161 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include // ITK #include #include #include // STL #include template static void -CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFImageDescriptionFeatures::FeatureListType & featureList, std::string prefix) +CalculateFirstOrderStatistics(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFImageDescriptionFeatures::FeatureListType & featureList, const mitk::FeatureID& featureID) { typedef itk::Image ImageType; typedef itk::Image MaskType; 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; int maskMinimumX = maskDimensionX; int maskMaximumX = 0; int maskMinimumY = maskDimensionY; int maskMaximumY = 0; int maskMinimumZ = maskDimensionZ; 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(prefix + "Image Dimension X", imageDimensionX)); - featureList.push_back(std::make_pair(prefix + "Image Dimension Y", imageDimensionY)); - featureList.push_back(std::make_pair(prefix + "Image Dimension Z", imageDimensionZ)); - featureList.push_back(std::make_pair(prefix + "Image Spacing X", imageVoxelSpacingX)); - featureList.push_back(std::make_pair(prefix + "Image Spacing Y", imageVoxelSpacingY)); - featureList.push_back(std::make_pair(prefix + "Image Spacing Z", imageVoxelSpacingZ)); - featureList.push_back(std::make_pair(prefix + "Image Mean intensity", imageMean)); - featureList.push_back(std::make_pair(prefix + "Image Minimum intensity", imageMinimum)); - featureList.push_back(std::make_pair(prefix + "Image Maximum intensity", imageMaximum)); - - featureList.push_back(std::make_pair(prefix + "Mask Dimension X", maskDimensionX)); - featureList.push_back(std::make_pair(prefix + "Mask Dimension Y", maskDimensionY)); - featureList.push_back(std::make_pair(prefix + "Mask Dimension Z", maskDimensionZ)); - featureList.push_back(std::make_pair(prefix + "Mask bounding box X", maskMaximumX - maskMinimumX + 1)); - featureList.push_back(std::make_pair(prefix + "Mask bounding box Y", maskMaximumY - maskMinimumY + 1)); - featureList.push_back(std::make_pair(prefix + "Mask bounding box Z", maskMaximumZ - maskMinimumZ + 1)); - featureList.push_back(std::make_pair(prefix + "Mask Spacing X", maskVoxelSpacingX)); - featureList.push_back(std::make_pair(prefix + "Mask Spacing Y", maskVoxelSpacingY)); - featureList.push_back(std::make_pair(prefix + "Mask Spacing Z", maskVoxelSpacingZ)); - featureList.push_back(std::make_pair(prefix + "Mask Voxel Count", maskVoxelCount)); - featureList.push_back(std::make_pair(prefix + "Mask Mean intensity", maskMean)); - featureList.push_back(std::make_pair(prefix + "Mask Minimum intensity", maskMinimum)); - featureList.push_back(std::make_pair(prefix + "Mask Maximum intensity", maskMaximum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Image Dimension X"), imageDimensionX)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Image Dimension Y"), imageDimensionY)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Image Dimension Z"), imageDimensionZ)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Image Spacing X"), imageVoxelSpacingX)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Image Spacing Y"), imageVoxelSpacingY)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Image Spacing Z"), imageVoxelSpacingZ)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Image Mean intensity"), imageMean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Image Minimum intensity"), imageMinimum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Image Maximum intensity"), imageMaximum)); + + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mask Dimension X"), maskDimensionX)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mask Dimension Y"), maskDimensionY)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mask Dimension Z"), maskDimensionZ)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mask bounding box X"), maskMaximumX - maskMinimumX + 1)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mask bounding box Y"), maskMaximumY - maskMinimumY + 1)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mask bounding box Z"), maskMaximumZ - maskMinimumZ + 1)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mask Spacing X"), maskVoxelSpacingX)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mask Spacing Y"), maskVoxelSpacingY)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mask Spacing Z"), maskVoxelSpacingZ)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mask Voxel Count"), maskVoxelCount)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mask Mean intensity"), maskMean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mask Minimum intensity"), maskMinimum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Mask Maximum intensity"), maskMaximum)); } mitk::GIFImageDescriptionFeatures::GIFImageDescriptionFeatures() { SetShortName("id"); SetLongName("image-diagnostic"); SetFeatureClassName("Diagnostic"); } -mitk::GIFImageDescriptionFeatures::FeatureListType mitk::GIFImageDescriptionFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +void mitk::GIFImageDescriptionFeatures::AddArguments(mitkCommandLineParser &parser) const { - FeatureListType featureList; - AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, FeatureDescriptionPrefix()); - - return featureList; + std::string name = GetOptionPrefix(); + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Image Description", "calculates image description features", us::Any()); } -mitk::GIFImageDescriptionFeatures::FeatureNameListType mitk::GIFImageDescriptionFeatures::GetFeatureNames() +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFImageDescriptionFeatures::DoCalculateFeatures(const Image* image, const Image* mask) { - FeatureNameListType featureList; - return featureList; -} + FeatureListType featureList; + MITK_INFO << "Start calculating image description features...."; + auto id = this->CreateTemplateFeatureID(); + AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, id); + MITK_INFO << "Finished calculating image description features...."; -void mitk::GIFImageDescriptionFeatures::AddArguments(mitkCommandLineParser &parser) -{ - std::string name = GetOptionPrefix(); - parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Image Description", "calculates image description features", us::Any()); + return featureList; } -void -mitk::GIFImageDescriptionFeatures::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFImageDescriptionFeatures::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { - auto parsedArgs = GetParameter(); - if (parsedArgs.count(GetLongName())) - { - 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 image description features...."; - } + return Superclass::CalculateFeatures(image, maskNoNAN); } - diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp index c520c1d3d7..4cc6c40fa4 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp @@ -1,169 +1,150 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include #include // ITK #include #include // STL #include namespace { struct GIFIntensityVolumeHistogramFeaturesParameters { mitk::IntensityQuantifier::Pointer quantifier; - std::string prefix; + mitk::FeatureID id; }; template - void CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, GIFIntensityVolumeHistogramFeaturesParameters params, mitk::GIFIntensityVolumeHistogramFeatures::FeatureListType& featureList) + void CalculateIntensityPeak(const itk::Image* itkImage, const mitk::Image* mask, GIFIntensityVolumeHistogramFeaturesParameters params, mitk::GIFIntensityVolumeHistogramFeatures::FeatureListType& featureList) { typedef itk::Image ImageType; typedef itk::Image MaskType; typename MaskType::Pointer itkMask = MaskType::New(); mitk::CastToItkImage(mask, itkMask); mitk::IntensityQuantifier::Pointer quantifier = params.quantifier; - std::string prefix = params.prefix; 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(prefix + "Volume fraction at 0.10 intensity", hist[index010])); - featureList.push_back(std::make_pair(prefix + "Volume fraction at 0.90 intensity", hist[index090])); - featureList.push_back(std::make_pair(prefix + "Intensity at 0.10 volume", intensity010)); - featureList.push_back(std::make_pair(prefix + "Intensity at 0.90 volume", intensity090)); - featureList.push_back(std::make_pair(prefix + "Difference volume fraction at 0.10 and 0.90 intensity", std::abs(hist[index010] - hist[index090]))); - featureList.push_back(std::make_pair(prefix + "Difference intensity at 0.10 and 0.90 volume", std::abs(intensity090 - intensity010))); - featureList.push_back(std::make_pair(prefix + "Area under IVH curve", auc)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Volume fraction at 0.10 intensity"), hist[index010])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Volume fraction at 0.90 intensity"), hist[index090])); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Intensity at 0.10 volume"), intensity010)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Intensity at 0.90 volume"), intensity090)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Difference volume fraction at 0.10 and 0.90 intensity"), std::abs(hist[index010] - hist[index090]))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Difference intensity at 0.10 and 0.90 volume"), std::abs(intensity090 - intensity010))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "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"); SetFeatureClassName("Intensity Volume Histogram"); } -mitk::GIFIntensityVolumeHistogramFeatures::FeatureListType mitk::GIFIntensityVolumeHistogramFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) -{ - InitializeQuantifier(image, mask, 1000); - FeatureListType featureList; - GIFIntensityVolumeHistogramFeaturesParameters params; - params.quantifier = GetQuantifier(); - params.prefix = FeatureDescriptionPrefix(); - AccessByItk_3(image, CalculateIntensityPeak, mask, params, featureList); - return featureList; -} - -mitk::GIFIntensityVolumeHistogramFeatures::FeatureNameListType mitk::GIFIntensityVolumeHistogramFeatures::GetFeatureNames() -{ - FeatureNameListType featureList; - return featureList; -} - - -void mitk::GIFIntensityVolumeHistogramFeatures::AddArguments(mitkCommandLineParser &parser) +void mitk::GIFIntensityVolumeHistogramFeatures::AddArguments(mitkCommandLineParser& parser) const { + AddQuantifierArguments(parser); std::string name = GetOptionPrefix(); 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 &, FeatureListType &featureList) +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFIntensityVolumeHistogramFeatures::DoCalculateFeatures(const Image* image, const Image* mask) { - InitializeQuantifierFromParameters(feature, mask, 1000); + FeatureListType featureList; - 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...."; - } + InitializeQuantifier(image, mask, 1000); + + MITK_INFO << "Start calculating local intensity features ...."; + GIFIntensityVolumeHistogramFeaturesParameters params; + params.quantifier = GetQuantifier(); + params.id = this->CreateTemplateFeatureID(); + AccessByItk_3(image, CalculateIntensityPeak, mask, params, featureList); + MITK_INFO << "Finished calculating local intensity features...."; + + return featureList; } -std::string mitk::GIFIntensityVolumeHistogramFeatures::GetCurrentFeatureEncoding() +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFIntensityVolumeHistogramFeatures::CalculateFeatures(const Image* image, const Image* mask, const Image*) { - return QuantifierParameterString(); + return Superclass::CalculateFeatures(image, mask); } - diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp index 14a4e3b517..3afef7e48b 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp @@ -1,125 +1,117 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include #include #include // ITK #include #include #include // STL #include struct GIFLocalIntensityParameter { double range; - std::string prefix; + mitk::FeatureID id; }; template static void -CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFLocalIntensity::FeatureListType & featureList, GIFLocalIntensityParameter params) +CalculateIntensityPeak(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFLocalIntensity::FeatureListType & featureList, GIFLocalIntensityParameter params) { typedef itk::Image ImageType; typedef itk::Image MaskType; typename MaskType::Pointer itkMask = MaskType::New(); mitk::CastToItkImage(mask, itkMask); double range = params.range; typename itk::LocalIntensityFilter::Pointer filter = itk::LocalIntensityFilter::New(); filter->SetInput(itkImage); filter->SetMask(itkMask); filter->SetRange(range); filter->Update(); - featureList.push_back(std::make_pair(params.prefix + "2. Local Intensity Peak", filter->GetLocalPeak())); - featureList.push_back(std::make_pair(params.prefix + "2. Global Intensity Peak", filter->GetGlobalPeak())); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "2. Local Intensity Peak"), filter->GetLocalPeak())); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "2. Global Intensity Peak"), filter->GetGlobalPeak())); } mitk::GIFLocalIntensity::GIFLocalIntensity() : m_Range(6.2) { SetLongName("local-intensity"); SetShortName("loci"); SetFeatureClassName("Local Intensity"); } -mitk::GIFLocalIntensity::FeatureListType mitk::GIFLocalIntensity::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +std::string mitk::GIFLocalIntensity::GenerateLegacyFeatureEncoding(const FeatureID& id) const { - FeatureListType featureList; - if (image->GetDimension() < 3) - { - return featureList; - } - GIFLocalIntensityParameter params; - params.range = GetRange(); - params.prefix = FeatureDescriptionPrefix(); - AccessByItk_3(image, CalculateIntensityPeak, mask, featureList, params); - return featureList; + return "_Range-" + id.parameters.at(this->GetOptionPrefix() + "::range").ToString(); } -mitk::GIFLocalIntensity::FeatureNameListType mitk::GIFLocalIntensity::GetFeatureNames() -{ - FeatureNameListType featureList; - return featureList; -} - - -void mitk::GIFLocalIntensity::AddArguments(mitkCommandLineParser &parser) +void mitk::GIFLocalIntensity::AddArguments(mitkCommandLineParser& parser) const { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Local Intensity", "calculates local intensity based features", us::Any()); - parser.addArgument(name + "::range", name+"::range", mitkCommandLineParser::Float, "Range for the local intensity", "Give the range that should be used for the local intensity in mm", us::Any()); + 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) +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFLocalIntensity::DoCalculateFeatures(const Image* image, const Image* mask) { - std::string name = GetOptionPrefix(); - auto parsedArgs = GetParameter(); - if (parsedArgs.count(GetLongName())) + FeatureListType featureList; + + if (image->GetDimension() < 3) + { + MITK_INFO << "Skipped GIFLocalIntensity. Only supports 3D images ...."; + } + else { - 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()); + + GIFLocalIntensityParameter params; + params.range = GetRange(); + params.id = this->CreateTemplateFeatureID(); + AccessByItk_3(image, CalculateIntensityPeak, mask, featureList, params); + MITK_INFO << "Finished calculating local intensity features...."; } + + return featureList; } -std::string mitk::GIFLocalIntensity::GetCurrentFeatureEncoding() +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFLocalIntensity::CalculateFeatures(const Image* image, const Image* mask, const Image*) { - std::ostringstream ss; - ss << m_Range; - std::string strRange = ss.str(); - return "Range-" + ss.str(); + return Superclass::CalculateFeatures(image, mask); } - - +void mitk::GIFLocalIntensity::ConfigureSettingsByParameters(const ParametersType& parameters) +{ + auto name = GetOptionPrefix() + "::range"; + if (parameters.count(name)) + { + double range = us::any_cast(parameters.at(name)); + this->SetRange(range); + } +} diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyLevelDifference.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyLevelDifference.cpp index 50bcb5b731..ea0b3c9a46 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyLevelDifference.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyLevelDifference.cpp @@ -1,220 +1,227 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include // ITK #include #include // STL #include +struct GIFNeighbourhoodGreyLevelDifferenceParameterStruct +{ + bool m_UseCTRange; + double m_Range; + unsigned int m_Direction; + mitk::FeatureID id; +}; + template void - CalculateGrayLevelNeighbourhoodGreyLevelDifferenceFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFNeighbourhoodGreyLevelDifference::FeatureListType & featureList, mitk::GIFNeighbourhoodGreyLevelDifference::ParameterStruct params) + CalculateGrayLevelNeighbourhoodGreyLevelDifferenceFeatures(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFNeighbourhoodGreyLevelDifference::FeatureListType & featureList, GIFNeighbourhoodGreyLevelDifferenceParameterStruct params) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::Statistics::EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceFeaturesFilter FilterType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typedef typename FilterType::NeighbourhoodGreyLevelDifferenceFeaturesFilterType 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::Coarseness); requestedFeatures->push_back(TextureFilterType::Contrast); requestedFeatures->push_back(TextureFilterType::Busyness); requestedFeatures->push_back(TextureFilterType::Complexity); requestedFeatures->push_back(TextureFilterType::Strength); 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) + 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::Coarseness : - featureList.push_back(std::make_pair("NeighbourhoodGreyLevelDifference ("+ strRange+") Coarseness Means",featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Coarseness Means"),featureMeans->ElementAt(i))); break; case TextureFilterType::Contrast : - featureList.push_back(std::make_pair("NeighbourhoodGreyLevelDifference ("+ strRange+") Contrast Means",featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Contrast Means"),featureMeans->ElementAt(i))); break; case TextureFilterType::Busyness : - featureList.push_back(std::make_pair("NeighbourhoodGreyLevelDifference ("+ strRange+") Busyness Means",featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Busyness Means"),featureMeans->ElementAt(i))); break; case TextureFilterType::Complexity : - featureList.push_back(std::make_pair("NeighbourhoodGreyLevelDifference ("+ strRange+") Complexity Means",featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Complexity Means"),featureMeans->ElementAt(i))); break; case TextureFilterType::Strength : - featureList.push_back(std::make_pair("NeighbourhoodGreyLevelDifference ("+ strRange+") Strength Means",featureMeans->ElementAt(i))); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Strength Means"),featureMeans->ElementAt(i))); break; default: break; } } } mitk::GIFNeighbourhoodGreyLevelDifference::GIFNeighbourhoodGreyLevelDifference(): -m_Range(1.0), m_UseCtRange(false) + m_Ranges({ 1.0 }), m_UseCTRange(false) { SetShortName("ngld"); SetLongName("NeighbourhoodGreyLevelDifference"); } -mitk::GIFNeighbourhoodGreyLevelDifference::FeatureListType mitk::GIFNeighbourhoodGreyLevelDifference::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +void mitk::GIFNeighbourhoodGreyLevelDifference::SetRanges(std::vector ranges) { - FeatureListType featureList; + m_Ranges = ranges; + this->Modified(); +} - ParameterStruct params; - params.m_UseCtRange=m_UseCtRange; - params.m_Range = m_Range; - params.m_Direction = GetDirection(); +void mitk::GIFNeighbourhoodGreyLevelDifference::SetRange(double range) +{ + m_Ranges.resize(1); + m_Ranges[0] = range; + this->Modified(); +} - AccessByItk_3(image, CalculateGrayLevelNeighbourhoodGreyLevelDifferenceFeatures, mask, featureList,params); +void mitk::GIFNeighbourhoodGreyLevelDifference::AddArguments(mitkCommandLineParser &parser) const +{ + std::string name = GetOptionPrefix(); - return featureList; + 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::Int, "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 + "::useCTRange", name + "::ct", mitkCommandLineParser::Bool, "Use CT range", "If flag is set only value in the CT range will be used for feature computation.", us::Any()); } -mitk::GIFNeighbourhoodGreyLevelDifference::FeatureNameListType mitk::GIFNeighbourhoodGreyLevelDifference::GetFeatureNames() +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFNeighbourhoodGreyLevelDifference::DoCalculateFeatures(const Image* image, const Image* mask) { - FeatureNameListType featureList; - featureList.push_back("NeighbourhoodGreyLevelDifference. Coarseness Means"); - featureList.push_back("NeighbourhoodGreyLevelDifference. Coarseness Std."); - featureList.push_back("NeighbourhoodGreyLevelDifference. Contrast Means"); - featureList.push_back("NeighbourhoodGreyLevelDifference. Contrast Std."); - featureList.push_back("NeighbourhoodGreyLevelDifference. Busyness Means"); - featureList.push_back("NeighbourhoodGreyLevelDifference. Busyness Std."); - featureList.push_back("NeighbourhoodGreyLevelDifference. Complexity Means"); - featureList.push_back("NeighbourhoodGreyLevelDifference. Complexity Std."); - featureList.push_back("NeighbourhoodGreyLevelDifference. Strength Means"); - featureList.push_back("NeighbourhoodGreyLevelDifference. Strength Std."); - return featureList; -} + FeatureListType featureList; + for (const auto& range : m_Ranges) + { + MITK_INFO << "Start calculating Neighbourhood Grey Level Difference with range " << range << "...."; + GIFNeighbourhoodGreyLevelDifferenceParameterStruct params; + params.m_UseCTRange = m_UseCTRange; + params.m_Range = range; + params.m_Direction = GetDirection(); + params.id = this->CreateTemplateFeatureID(std::to_string(range), { {GetOptionPrefix() + "::range", range} }); + AccessByItk_3(image, CalculateGrayLevelNeighbourhoodGreyLevelDifferenceFeatures, mask, featureList, params); + MITK_INFO << "Finished calculating coocurence with range " << range << "...."; + } + return featureList; +} -void mitk::GIFNeighbourhoodGreyLevelDifference::AddArguments(mitkCommandLineParser &parser) +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFNeighbourhoodGreyLevelDifference::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { - std::string name = GetOptionPrefix(); + return Superclass::CalculateFeatures(image, maskNoNAN); +} - 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()); +std::string mitk::GIFNeighbourhoodGreyLevelDifference::GenerateLegacyFeatureName(const FeatureID& id) const +{ + return "NeighbourhoodGreyLevelDifference (" + id.parameters.at(this->GetOptionPrefix() + "::range").ToString() + ") " + id.name; } -void -mitk::GIFNeighbourhoodGreyLevelDifference::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +void mitk::GIFNeighbourhoodGreyLevelDifference::ConfigureSettingsByParameters(const ParametersType& parameters) { - auto parsedArgs = GetParameter(); - std::string name = GetOptionPrefix(); + auto prefixname = GetOptionPrefix(); - if (parsedArgs.count(GetLongName())) + auto name = prefixname + "::range"; + if (parameters.count(name)) { - 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); - } + m_Ranges = SplitDouble(parameters.at(name).ToString(), ';'); + } - for (std::size_t i = 0; i < ranges.size(); ++i) - { - MITK_INFO << "Start calculating Neighbourhood Grey Level Difference 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] << "...."; - } + name = prefixname + "::direction"; + if (parameters.count(name)) + { + int direction = us::any_cast(parameters.at(name)); + this->SetDirection(direction); } + name = prefixname + "::useCTRange"; + if (parameters.count(name)) + { + bool tmp = us::any_cast(parameters.at(name)); + m_UseCTRange = tmp; + } } - diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp index dddeca2a39..dcb5481593 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp @@ -1,217 +1,201 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include #include #include // ITK #include #include // STL #include struct GIFNeighbourhoodGreyToneDifferenceParameter { int Range = 1; mitk::IntensityQuantifier::Pointer quantifier; - std::string prefix; + mitk::FeatureID id; }; template static void -CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, GIFNeighbourhoodGreyToneDifferenceParameter params, mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::FeatureListType & featureList) +CalculateIntensityPeak(const itk::Image* itkImage, const mitk::Image* mask, GIFNeighbourhoodGreyToneDifferenceParameter params, mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::FeatureListType & featureList) { typedef itk::Image ImageType; typedef itk::Image MaskType; typename MaskType::Pointer itkMask = MaskType::New(); mitk::CastToItkImage(mask, itkMask); typename ImageType::SizeType regionSize; regionSize.Fill(params.Range); - itk::NeighborhoodIterator iter(regionSize, itkImage, itkImage->GetLargestPossibleRegion()); - itk::NeighborhoodIterator iterMask(regionSize, itkMask, itkMask->GetLargestPossibleRegion()); + itk::ConstNeighborhoodIterator iter(regionSize, itkImage, itkImage->GetLargestPossibleRegion()); + itk::ConstNeighborhoodIterator iterMask(regionSize, itkMask, itkMask->GetLargestPossibleRegion()); std::vector pVector; std::vector sVector; 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 = params.quantifier->IntensityToIndex(iter.GetCenterPixel()); for (itk::SizeValueType i = 0; i < iter.Size(); ++i) { if (i == (iter.Size() / 2)) continue; if (iterMask.GetPixel(i) > 0) { ++localCount; 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 < 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 < params.quantifier->GetBins(); ++i) { sumS += sVector[i]; sumStimesP += pVector[i] * sVector[i]; 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; } - std::string prefix = params.prefix; - featureList.push_back(std::make_pair(prefix + "Coarsness", coarsness)); - featureList.push_back(std::make_pair(prefix + "Contrast", contrast)); - featureList.push_back(std::make_pair(prefix + "Busyness", busyness)); - featureList.push_back(std::make_pair(prefix + "Complexity", complexity)); - featureList.push_back(std::make_pair(prefix + "Strength", strength)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Coarsness"), coarsness)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Contrast"), contrast)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Busyness"), busyness)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Complexity"), complexity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Strength"), strength)); } mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::GIFNeighbourhoodGreyToneDifferenceFeatures() : m_Range(1) { SetLongName("neighbourhood-grey-tone-difference"); SetShortName("ngtd"); SetFeatureClassName("Neighbourhood Grey Tone Difference"); } -mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::FeatureListType mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +std::string mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::GenerateLegacyFeatureEncoding(const FeatureID& id) const +{ + return this->QuantifierParameterString()+"_Range-" + id.parameters.at(this->GetOptionPrefix() + "::range").ToString(); +} + +void mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::AddArguments(mitkCommandLineParser& parser) const +{ + AddQuantifierArguments(parser); + std::string name = GetOptionPrefix(); + + 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()); +} + +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::DoCalculateFeatures(const Image* image, const Image* mask) { FeatureListType featureList; - InitializeQuantifierFromParameters(image, mask); + InitializeQuantifier(image, mask); + + MITK_INFO << "Start calculating Neighbourhood Grey Tone Difference features ...."; GIFNeighbourhoodGreyToneDifferenceParameter params; params.Range = GetRange(); params.quantifier = GetQuantifier(); - params.prefix = FeatureDescriptionPrefix(); + params.id = this->CreateTemplateFeatureID(); AccessByItk_3(image, CalculateIntensityPeak, mask, params, featureList); - return featureList; -} -mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::FeatureNameListType mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::GetFeatureNames() -{ - FeatureNameListType featureList; + MITK_INFO << "Finished calculating Neighbourhood Grey Tone Difference features...."; + return featureList; } - -void mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::AddArguments(mitkCommandLineParser &parser) +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::CalculateFeatures(const Image* image, const Image* mask, const Image*) { - AddQuantifierArguments(parser); - std::string name = GetOptionPrefix(); - - 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()); - + return Superclass::CalculateFeatures(image, mask); } -void -mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) +void mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::ConfigureSettingsByParameters(const ParametersType& parameters) { - InitializeQuantifierFromParameters(feature, mask); - std::string name = GetOptionPrefix(); - - auto parsedArgs = GetParameter(); - if (parsedArgs.count(GetLongName())) + auto name = GetOptionPrefix() + "::range"; + if (parameters.count(name)) { - 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 Neighbourhood Grey Tone Difference features...."; + int range = us::any_cast(parameters.at(name)); + this->SetRange(range); } } - -std::string mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::GetCurrentFeatureEncoding() -{ - std::ostringstream ss; - ss << m_Range; - std::string strRange = ss.str(); - return QuantifierParameterString() + "_Range-" + ss.str(); -} - - - diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp index 8efb80b3ef..aa76bc4362 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp @@ -1,498 +1,502 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include // ITK #include #include #include #include // STL #include +struct GIFNeighbouringGreyLevelDependenceFeatureConfiguration +{ + double range; + unsigned int direction; + int alpha; + + double MinimumIntensity; + double MaximumIntensity; + int Bins; + mitk::FeatureID id; +}; + namespace mitk { struct NGLDMMatrixHolder { public: NGLDMMatrixHolder(double min, double max, int number, int depenence); 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_NumberOfDependences; int m_NumberOfBins; Eigen::MatrixXd m_Matrix; int m_NeighbourhoodSize; unsigned long m_NumberOfNeighbourVoxels; unsigned long m_NumberOfDependenceNeighbourVoxels; unsigned long m_NumberOfNeighbourhoods; unsigned long m_NumberOfCompleteNeighbourhoods; }; struct NGLDMMatrixFeatures { NGLDMMatrixFeatures() : LowDependenceEmphasis(0), HighDependenceEmphasis(0), LowGreyLevelCountEmphasis(0), HighGreyLevelCountEmphasis(0), LowDependenceLowGreyLevelEmphasis(0), LowDependenceHighGreyLevelEmphasis(0), HighDependenceLowGreyLevelEmphasis(0), HighDependenceHighGreyLevelEmphasis(0), GreyLevelNonUniformity(0), GreyLevelNonUniformityNormalised(0), DependenceCountNonUniformity(0), DependenceCountNonUniformityNormalised(0), DependenceCountPercentage(0), GreyLevelVariance(0), DependenceCountVariance(0), DependenceCountEntropy(0), DependenceCountEnergy(0), MeanGreyLevelCount(0), MeanDependenceCount(0), ExpectedNeighbourhoodSize(0), AverageNeighbourhoodSize(0), AverageIncompleteNeighbourhoodSize(0), PercentageOfCompleteNeighbourhoods(0), PercentageOfDependenceNeighbours(0) { } public: double LowDependenceEmphasis; double HighDependenceEmphasis; double LowGreyLevelCountEmphasis; double HighGreyLevelCountEmphasis; double LowDependenceLowGreyLevelEmphasis; double LowDependenceHighGreyLevelEmphasis; double HighDependenceLowGreyLevelEmphasis; double HighDependenceHighGreyLevelEmphasis; double GreyLevelNonUniformity; double GreyLevelNonUniformityNormalised; double DependenceCountNonUniformity; double DependenceCountNonUniformityNormalised; double DependenceCountPercentage; double GreyLevelVariance; double DependenceCountVariance; double DependenceCountEntropy; double DependenceCountEnergy; double MeanGreyLevelCount; double MeanDependenceCount; double ExpectedNeighbourhoodSize; double AverageNeighbourhoodSize; double AverageIncompleteNeighbourhoodSize; double PercentageOfCompleteNeighbourhoods; double PercentageOfDependenceNeighbours; }; } static -void MatrixFeaturesTo(mitk::NGLDMMatrixFeatures features, - std::string prefix, - mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType &featureList); - +void MatrixFeaturesTo(const mitk::NGLDMMatrixFeatures& features, + const GIFNeighbouringGreyLevelDependenceFeatureConfiguration& config, + mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType& featureList) +{ + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Dependence Emphasis"), features.LowDependenceEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Dependence Emphasis"), features.HighDependenceEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Grey Level Count Emphasis"), features.LowGreyLevelCountEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Grey Level Count Emphasis"), features.HighGreyLevelCountEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Dependence Low Grey Level Emphasis"), features.LowDependenceLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Dependence High Grey Level Emphasis"), features.LowDependenceHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Dependence Low Grey Level Emphasis"), features.HighDependenceLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Dependence High Grey Level Emphasis"), features.HighDependenceHighGreyLevelEmphasis)); + + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity"), features.GreyLevelNonUniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity Normalised"), features.GreyLevelNonUniformityNormalised)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Non-Uniformity"), features.DependenceCountNonUniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Non-Uniformity Normalised"), features.DependenceCountNonUniformityNormalised)); + + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Percentage"), features.DependenceCountPercentage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Mean"), features.MeanGreyLevelCount)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Variance"), features.GreyLevelVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Mean"), features.MeanDependenceCount)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Variance"), features.DependenceCountVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Entropy"), features.DependenceCountEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Energy"), features.DependenceCountEnergy)); + + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Expected Neighbourhood Size"), features.ExpectedNeighbourhoodSize)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Average Neighbourhood Size"), features.AverageNeighbourhoodSize)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Average Incomplete Neighbourhood Size"), features.AverageIncompleteNeighbourhoodSize)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Percentage of complete Neighbourhoods"), features.PercentageOfCompleteNeighbourhoods)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Percentage of Dependence Neighbour Voxels"), features.PercentageOfDependenceNeighbours)); +} mitk::NGLDMMatrixHolder::NGLDMMatrixHolder(double min, double max, int number, int depenence) : m_MinimumRange(min), m_MaximumRange(max), m_Stepsize(0), m_NumberOfDependences(depenence), m_NumberOfBins(number), m_NeighbourhoodSize(1), m_NumberOfNeighbourVoxels(0), m_NumberOfDependenceNeighbourVoxels(0), m_NumberOfNeighbourhoods(0), m_NumberOfCompleteNeighbourhoods(0) { m_Matrix.resize(number, depenence); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::NGLDMMatrixHolder::IntensityToIndex(double intensity) { return std::floor((intensity - m_MinimumRange) / m_Stepsize); } double mitk::NGLDMMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::NGLDMMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::NGLDMMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template void -CalculateNGLDMMatrix(itk::Image* itkImage, - itk::Image* mask, +CalculateNGLDMMatrix(const itk::Image* itkImage, + const itk::Image* mask, int alpha, int range, unsigned int direction, mitk::NGLDMMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; - typedef itk::NeighborhoodIterator ShapeIterType; - typedef itk::NeighborhoodIterator ShapeMaskIterType; + typedef itk::ConstNeighborhoodIterator ShapeIterType; + typedef itk::ConstNeighborhoodIterator ShapeMaskIterType; holder.m_NumberOfCompleteNeighbourhoods = 0; holder.m_NumberOfNeighbourhoods = 0; holder.m_NumberOfNeighbourVoxels = 0; holder.m_NumberOfDependenceNeighbourVoxels = 0; itk::Size radius; radius.Fill(range); if ((direction > 1) && (direction - 2 GetLargestPossibleRegion()); ShapeMaskIterType maskIter(radius, mask, mask->GetLargestPossibleRegion()); auto region = mask->GetLargestPossibleRegion(); auto center = imageIter.Size() / 2; auto iterSize = imageIter.Size(); holder.m_NeighbourhoodSize = iterSize-1; while (!maskIter.IsAtEnd()) { int sameValues = 0; bool completeNeighbourhood = true; int i = holder.IntensityToIndex(imageIter.GetCenterPixel()); if ((imageIter.GetCenterPixel() != imageIter.GetCenterPixel()) || (maskIter.GetCenterPixel() < 1)) { ++imageIter; ++maskIter; continue; } for (unsigned int position = 0; position < iterSize; ++position) { if (position == center) { continue; } if ( ! region.IsInside(maskIter.GetIndex(position))) { completeNeighbourhood = false; continue; } bool isInBounds; auto jIntensity = imageIter.GetPixel(position, isInBounds); auto jMask = maskIter.GetPixel(position, isInBounds); if (jMask < 1 || (jIntensity != jIntensity) || ( ! isInBounds)) { completeNeighbourhood = false; continue; } int j = holder.IntensityToIndex(jIntensity); holder.m_NumberOfNeighbourVoxels += 1; if (std::abs(i - j) <= alpha) { holder.m_NumberOfDependenceNeighbourVoxels += 1; ++sameValues; } } holder.m_Matrix(i, sameValues) += 1; holder.m_NumberOfNeighbourhoods += 1; if (completeNeighbourhood) { holder.m_NumberOfCompleteNeighbourhoods += 1; } ++imageIter; ++maskIter; } } void LocalCalculateFeatures( mitk::NGLDMMatrixHolder &holder, mitk::NGLDMMatrixFeatures & results ) { auto sijMatrix = holder.m_Matrix; auto piMatrix = holder.m_Matrix; auto pjMatrix = holder.m_Matrix; // double Ng = holder.m_NumberOfBins; // int NgSize = holder.m_NumberOfBins; double Ns = sijMatrix.sum(); piMatrix.rowwise().normalize(); pjMatrix.colwise().normalize(); for (int i = 0; i < holder.m_NumberOfBins; ++i) { double sj = 0; for (int j = 0; j < holder.m_NumberOfDependences; ++j) { double iInt = i+1 ;// holder.IndexToMeanIntensity(i); double sij = sijMatrix(i, j); double k = j + 1; double pij = sij / Ns; results.LowDependenceEmphasis += sij / k / k; results.HighDependenceEmphasis += sij * k*k; if (iInt != 0) { results.LowGreyLevelCountEmphasis += sij / iInt / iInt; } results.HighGreyLevelCountEmphasis += sij * iInt*iInt; if (iInt != 0) { results.LowDependenceLowGreyLevelEmphasis += sij / k / k / iInt / iInt; } results.LowDependenceHighGreyLevelEmphasis += sij * iInt*iInt / k / k; if (iInt != 0) { results.HighDependenceLowGreyLevelEmphasis += sij *k * k / iInt / iInt; } results.HighDependenceHighGreyLevelEmphasis += sij * k*k*iInt*iInt; results.MeanGreyLevelCount += iInt * pij; results.MeanDependenceCount += k * pij; if (pij > 0) { results.DependenceCountEntropy -= pij * std::log(pij) / std::log(2); } results.DependenceCountEnergy += pij*pij; sj += sij; } results.GreyLevelNonUniformity += sj*sj; results.GreyLevelNonUniformityNormalised += sj*sj; } for (int j = 0; j < holder.m_NumberOfDependences; ++j) { double si = 0; for (int i = 0; i < holder.m_NumberOfBins; ++i) { double sij = sijMatrix(i, j); si += sij; } results.DependenceCountNonUniformity += si*si; results.DependenceCountNonUniformityNormalised += si*si; } for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfDependences; ++j) { double iInt = i + 1;// holder.IndexToMeanIntensity(i); double sij = sijMatrix(i, j); double k = j + 1; double pij = sij / Ns; results.GreyLevelVariance += (iInt - results.MeanGreyLevelCount)* (iInt - results.MeanGreyLevelCount) * pij; results.DependenceCountVariance += (k - results.MeanDependenceCount)* (k - results.MeanDependenceCount) * pij; } } results.LowDependenceEmphasis /= Ns; results.HighDependenceEmphasis /= Ns; results.LowGreyLevelCountEmphasis /= Ns; results.HighGreyLevelCountEmphasis /= Ns; results.LowDependenceLowGreyLevelEmphasis /= Ns; results.LowDependenceHighGreyLevelEmphasis /= Ns; results.HighDependenceLowGreyLevelEmphasis /= Ns; results.HighDependenceHighGreyLevelEmphasis /= Ns; results.GreyLevelNonUniformity /= Ns; results.GreyLevelNonUniformityNormalised /= (Ns*Ns); results.DependenceCountNonUniformity /= Ns; results.DependenceCountNonUniformityNormalised /= (Ns*Ns); results.DependenceCountPercentage = 1; results.ExpectedNeighbourhoodSize = holder.m_NeighbourhoodSize; results.AverageNeighbourhoodSize = holder.m_NumberOfNeighbourVoxels / (1.0 * holder.m_NumberOfNeighbourhoods); results.AverageIncompleteNeighbourhoodSize = (holder.m_NumberOfNeighbourVoxels - holder.m_NumberOfCompleteNeighbourhoods* holder.m_NeighbourhoodSize) / (1.0 * (holder.m_NumberOfNeighbourhoods - holder.m_NumberOfCompleteNeighbourhoods)); results.PercentageOfCompleteNeighbourhoods = (1.0*holder.m_NumberOfCompleteNeighbourhoods) / (1.0 * holder.m_NumberOfNeighbourhoods); results.PercentageOfDependenceNeighbours = holder.m_NumberOfDependenceNeighbourVoxels / (1.0 * holder.m_NumberOfNeighbourVoxels); } template void -CalculateCoocurenceFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType & featureList, mitk::GIFNeighbouringGreyLevelDependenceFeature::GIFNeighbouringGreyLevelDependenceFeatureConfiguration config) +CalculateCoocurenceFeatures(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType & featureList, GIFNeighbouringGreyLevelDependenceFeatureConfiguration config) { typedef itk::Image MaskType; double rangeMin = config.MinimumIntensity; double rangeMax = config.MaximumIntensity; int numberOfBins = config.Bins; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); std::vector resultVector; int numberofDependency = 37; if (VImageDimension == 2) numberofDependency = 37; mitk::NGLDMMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins, numberofDependency); mitk::NGLDMMatrixFeatures overallFeature; CalculateNGLDMMatrix(itkImage, maskImage, config.alpha, config.range, config.direction, holderOverall); LocalCalculateFeatures(holderOverall, overallFeature); - MatrixFeaturesTo(overallFeature, config.FeatureEncoding, featureList); + MatrixFeaturesTo(overallFeature, config, featureList); } +mitk::GIFNeighbouringGreyLevelDependenceFeature::GIFNeighbouringGreyLevelDependenceFeature() : + m_Ranges({ 1.0 }), m_Alpha(0.) +{ + SetShortName("ngld"); + SetLongName("neighbouring-grey-level-dependence"); + SetFeatureClassName("Neighbouring Grey Level Dependence"); +} -static -void MatrixFeaturesTo(mitk::NGLDMMatrixFeatures features, - std::string prefix, - mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType &featureList) +void mitk::GIFNeighbouringGreyLevelDependenceFeature::SetRanges(std::vector ranges) { - featureList.push_back(std::make_pair(prefix + "Low Dependence Emphasis", features.LowDependenceEmphasis)); - featureList.push_back(std::make_pair(prefix + "High Dependence Emphasis", features.HighDependenceEmphasis)); - featureList.push_back(std::make_pair(prefix + "Low Grey Level Count Emphasis", features.LowGreyLevelCountEmphasis)); - featureList.push_back(std::make_pair(prefix + "High Grey Level Count Emphasis", features.HighGreyLevelCountEmphasis)); - featureList.push_back(std::make_pair(prefix + "Low Dependence Low Grey Level Emphasis", features.LowDependenceLowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + "Low Dependence High Grey Level Emphasis", features.LowDependenceHighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + "High Dependence Low Grey Level Emphasis", features.HighDependenceLowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(prefix + "High Dependence High Grey Level Emphasis", features.HighDependenceHighGreyLevelEmphasis)); - - featureList.push_back(std::make_pair(prefix + "Grey Level Non-Uniformity", features.GreyLevelNonUniformity)); - featureList.push_back(std::make_pair(prefix + "Grey Level Non-Uniformity Normalised", features.GreyLevelNonUniformityNormalised)); - featureList.push_back(std::make_pair(prefix + "Dependence Count Non-Uniformity", features.DependenceCountNonUniformity)); - featureList.push_back(std::make_pair(prefix + "Dependence Count Non-Uniformity Normalised", features.DependenceCountNonUniformityNormalised)); - - featureList.push_back(std::make_pair(prefix + "Dependence Count Percentage", features.DependenceCountPercentage)); - featureList.push_back(std::make_pair(prefix + "Grey Level Mean", features.MeanGreyLevelCount)); - featureList.push_back(std::make_pair(prefix + "Grey Level Variance", features.GreyLevelVariance)); - featureList.push_back(std::make_pair(prefix + "Dependence Count Mean", features.MeanDependenceCount)); - featureList.push_back(std::make_pair(prefix + "Dependence Count Variance", features.DependenceCountVariance)); - featureList.push_back(std::make_pair(prefix + "Dependence Count Entropy", features.DependenceCountEntropy)); - featureList.push_back(std::make_pair(prefix + "Dependence Count Energy", features.DependenceCountEnergy)); - - featureList.push_back(std::make_pair(prefix + "Expected Neighbourhood Size", features.ExpectedNeighbourhoodSize)); - featureList.push_back(std::make_pair(prefix + "Average Neighbourhood Size", features.AverageNeighbourhoodSize)); - featureList.push_back(std::make_pair(prefix + "Average Incomplete Neighbourhood Size", features.AverageIncompleteNeighbourhoodSize)); - featureList.push_back(std::make_pair(prefix + "Percentage of complete Neighbourhoods", features.PercentageOfCompleteNeighbourhoods)); - featureList.push_back(std::make_pair(prefix + "Percentage of Dependence Neighbour Voxels", features.PercentageOfDependenceNeighbours)); + m_Ranges = ranges; + this->Modified(); +} +void mitk::GIFNeighbouringGreyLevelDependenceFeature::SetRange(double range) +{ + m_Ranges.resize(1); + m_Ranges[0] = range; + this->Modified(); } -mitk::GIFNeighbouringGreyLevelDependenceFeature::GIFNeighbouringGreyLevelDependenceFeature() : -m_Range(1.0) +void mitk::GIFNeighbouringGreyLevelDependenceFeature::AddArguments(mitkCommandLineParser& parser) const { - SetShortName("ngld"); - SetLongName("neighbouring-grey-level-dependence"); - SetFeatureClassName("Neighbouring Grey Level Dependence"); + AddQuantifierArguments(parser); + + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Calculate Neighbouring Grey Level Dependence Features", "Calculate Neighbouring grey level dependence based features", us::Any()); + parser.addArgument(name + "::range", name + "::range", mitkCommandLineParser::String, "NGLD Range", "Define the range that is used (Semicolon-separated)", us::Any()); + parser.addArgument(name + "::alpha", name + "::alpha", mitkCommandLineParser::Int, "Int", "", us::Any()); } -mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType mitk::GIFNeighbouringGreyLevelDependenceFeature::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFNeighbouringGreyLevelDependenceFeature::DoCalculateFeatures(const Image* image, const Image* mask) { FeatureListType featureList; - InitializeQuantifier(image, mask); - GIFNeighbouringGreyLevelDependenceFeatureConfiguration config; - config.direction = GetDirection(); - config.range = m_Range; - config.alpha = 0; + this->InitializeQuantifier(image, mask); + for (const auto& range : m_Ranges) + { + MITK_INFO << "Start calculating NGLD with range " << range << "...."; + GIFNeighbouringGreyLevelDependenceFeatureConfiguration config; + config.direction = GetDirection(); + config.range = range; + config.alpha = m_Alpha; - config.MinimumIntensity = GetQuantifier()->GetMinimum(); - config.MaximumIntensity = GetQuantifier()->GetMaximum(); - config.Bins = GetQuantifier()->GetBins(); + config.MinimumIntensity = GetQuantifier()->GetMinimum(); + config.MaximumIntensity = GetQuantifier()->GetMaximum(); + config.Bins = GetQuantifier()->GetBins(); - config.FeatureEncoding = FeatureDescriptionPrefix(); + config.id = this->CreateTemplateFeatureID(std::to_string(range), { {GetOptionPrefix() + "::range", range} }); - AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList,config); + AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList, config); + MITK_INFO << "Finished calculating NGLD with range " << range << "...."; + } return featureList; } -mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureNameListType mitk::GIFNeighbouringGreyLevelDependenceFeature::GetFeatureNames() +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFNeighbouringGreyLevelDependenceFeature::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { - FeatureNameListType featureList; - - return featureList; + return Superclass::CalculateFeatures(image, maskNoNAN); } - - -void mitk::GIFNeighbouringGreyLevelDependenceFeature::AddArguments(mitkCommandLineParser &parser) +std::string mitk::GIFNeighbouringGreyLevelDependenceFeature::GenerateLegacyFeatureEncoding(const FeatureID& id) const { - std::string name = GetOptionPrefix(); - - parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Calculate Neighbouring Grey Level Dependence Features", "Calculate Neighbouring grey level dependence based features", us::Any()); - parser.addArgument(name + "::range", name + "::range", mitkCommandLineParser::String, "NGLD Range", "Define the range that is used (Semicolon-separated)", us::Any()); - - AddQuantifierArguments(parser); + return QuantifierParameterString() + "_Range-" + id.parameters.at(this->GetOptionPrefix() + "::range").ToString(); } -void -mitk::GIFNeighbouringGreyLevelDependenceFeature::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +void mitk::GIFNeighbouringGreyLevelDependenceFeature::ConfigureSettingsByParameters(const ParametersType& parameters) { - auto parsedArgs = GetParameter(); - std::string name = GetOptionPrefix(); + auto prefixname = GetOptionPrefix(); - if (parsedArgs.count(GetLongName())) + auto name = prefixname + "::range"; + if (parameters.count(name)) { - std::vector ranges; - if (parsedArgs.count(name + "::range")) - { - ranges = SplitDouble(parsedArgs[name + "::range"].ToString(), ';'); - } - else - { - ranges.push_back(1); - } - for (double range : ranges) - { - InitializeQuantifierFromParameters(feature, maskNoNAN); - this->SetRange(range); - MITK_INFO << "Start calculating NGLD"; - auto localResults = this->CalculateFeatures(feature, maskNoNAN); - featureList.insert(featureList.end(), localResults.begin(), localResults.end()); - MITK_INFO << "Finished calculating NGLD"; - } + m_Ranges = SplitDouble(parameters.at(name).ToString(), ';'); } -} -std::string mitk::GIFNeighbouringGreyLevelDependenceFeature::GetCurrentFeatureEncoding() -{ - std::ostringstream ss; - ss << m_Range; - std::string strRange = ss.str(); - return QuantifierParameterString() + "_Range-"+ss.str(); + name = prefixname + "::alpha"; + if (parameters.count(name)) + { + int alpha = us::any_cast(parameters.at(name)); + this->SetAlpha(alpha); + } } - diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp index 82523f06bb..3b4130bc5c 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp @@ -1,527 +1,515 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include #include #include // ITK #include #include #include #include // VTK #include #include #include #include #include #include #include #include // STL #include #include // Eigen #include struct GIFVolumetricDensityStatisticsParameters { double volume; - std::string prefix; + mitk::FeatureID id; }; template void -CalculateVolumeDensityStatistic(itk::Image* itkImage, mitk::Image::Pointer mask, GIFVolumetricDensityStatisticsParameters params, mitk::GIFVolumetricDensityStatistics::FeatureListType & featureList) +CalculateVolumeDensityStatistic(const itk::Image* itkImage, const mitk::Image* mask, GIFVolumetricDensityStatisticsParameters params, mitk::GIFVolumetricDensityStatistics::FeatureListType & featureList) { typedef itk::Image ImageType; typedef itk::Image MaskType; double volume = params.volume; - std::string prefix = params.prefix; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); itk::ImageRegionConstIteratorWithIndex imgA(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex imgB(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex maskA(maskImage, maskImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex maskB(maskImage, maskImage->GetLargestPossibleRegion()); double moranA = 0; double moranB = 0; double geary = 0; double Nv = 0; double w_ij = 0; double mean = 0; typename ImageType::PointType pointA; typename ImageType::PointType pointB; while (!imgA.IsAtEnd()) { if (maskA.Get() > 0) { Nv += 1; mean += imgA.Get(); } ++imgA; ++maskA; } mean /= Nv; imgA.GoToBegin(); maskA.GoToBegin(); while (!imgA.IsAtEnd()) { if (maskA.Get() > 0) { imgB.GoToBegin(); maskB.GoToBegin(); while (!imgB.IsAtEnd()) { if ((imgA.GetIndex() == imgB.GetIndex()) || (maskB.Get() < 1)) { ++imgB; ++maskB; continue; } itkImage->TransformIndexToPhysicalPoint(maskA.GetIndex(), pointA); itkImage->TransformIndexToPhysicalPoint(maskB.GetIndex(), pointB); double w = 1 / pointA.EuclideanDistanceTo(pointB); moranA += w*(imgA.Get() - mean)* (imgB.Get() - mean); geary += w * (imgA.Get() - imgB.Get()) * (imgA.Get() - imgB.Get()); w_ij += w; ++imgB; ++maskB; } moranB += (imgA.Get() - mean)* (imgA.Get() - mean); } ++imgA; ++maskA; } MITK_INFO << "Volume: " << volume; MITK_INFO << " Mean: " << mean; - featureList.push_back(std::make_pair(prefix + "Volume integrated intensity", volume* mean)); - featureList.push_back(std::make_pair(prefix + "Volume Moran's I index", Nv / w_ij * moranA / moranB)); - featureList.push_back(std::make_pair(prefix + "Volume Geary's C measure", ( Nv -1 ) / 2 / w_ij * geary/ moranB)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Volume integrated intensity"), volume* mean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Volume Moran's I index"), Nv / w_ij * moranA / moranB)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Volume Geary's C measure"), ( Nv -1 ) / 2 / w_ij * geary/ moranB)); } void calculateMOBB(vtkPointSet *pointset, double &volume, double &surface) { volume = std::numeric_limits::max(); for (int cellID = 0; cellID < pointset->GetNumberOfCells(); ++cellID) { auto cell = pointset->GetCell(cellID); for (int edgeID = 0; edgeID < 3; ++edgeID) { auto edge = cell->GetEdge(edgeID); double pA[3], pB[3]; double pAA[3], pBB[3]; vtkSmartPointer transform = vtkSmartPointer::New(); transform->PostMultiply(); pointset->GetPoint(edge->GetPointId(0), pA); pointset->GetPoint(edge->GetPointId(1), pB); double angleZ = std::atan2((- pA[2] + pB[2]) ,(pA[1] - pB[1])); angleZ *= 180 / vnl_math::pi; if (pA[2] == pB[2]) angleZ = 0; transform->RotateX(angleZ); transform->TransformPoint(pA, pAA); transform->TransformPoint(pB, pBB); double angleY = std::atan2((pAA[1] -pBB[1]) ,-(pAA[0] - pBB[0])); angleY *= 180 / vnl_math::pi; if (pAA[1] == pBB[1]) angleY = 0; transform->RotateZ(angleY); double p0[3]; pointset->GetPoint(edge->GetPointId(0), p0); double curMinX = std::numeric_limits::max(); double curMaxX = std::numeric_limits::lowest(); double curMinY = std::numeric_limits::max(); double curMaxY = std::numeric_limits::lowest(); double curMinZ = std::numeric_limits::max(); double curMaxZ = std::numeric_limits::lowest(); for (int pointID = 0; pointID < pointset->GetNumberOfPoints(); ++pointID) { double p[3]; double p2[3]; pointset->GetPoint(pointID, p); p[0] -= p0[0]; p[1] -= p0[1]; p[2] -= p0[2]; transform->TransformPoint(p, p2); curMinX = std::min(p2[0], curMinX); curMaxX = std::max(p2[0], curMaxX); curMinY = std::min(p2[1], curMinY); curMaxY = std::max(p2[1], curMaxY); curMinZ = std::min(p2[2], curMinZ); curMaxZ = std::max(p2[2], curMaxZ); } if ((curMaxX - curMinX)*(curMaxY - curMinY)*(curMaxZ - curMinZ) < volume) { volume = (curMaxX - curMinX)*(curMaxY - curMinY)*(curMaxZ - curMinZ); surface = (curMaxX - curMinX)*(curMaxX - curMinX) + (curMaxY - curMinY)*(curMaxY - curMinY) + (curMaxZ - curMinZ)*(curMaxZ - curMinZ); surface *= 2; } } } } void calculateMEE(vtkPointSet *pointset, double &vol, double &surf, double tolerance=0.0001) { // Inspired by https://github.com/smdabdoub/ProkaryMetrics/blob/master/calc/fitting.py int numberOfPoints = pointset->GetNumberOfPoints(); int dimension = 3; Eigen::MatrixXd points(3, numberOfPoints); Eigen::MatrixXd Q(3+1, numberOfPoints); double p[3]; std::cout << "Initialize Q " << std::endl; for (int i = 0; i < numberOfPoints; ++i) { pointset->GetPoint(i, p); points(0, i) = p[0]; points(1, i) = p[1]; points(2, i) = p[2]; Q(0, i) = p[0]; Q(1, i) = p[1]; Q(2, i) = p[2]; Q(3, i) = 1.0; } int count = 1; double error = 1; Eigen::VectorXd u_vector(numberOfPoints); u_vector.fill(1.0 / numberOfPoints); Eigen::DiagonalMatrix u = u_vector.asDiagonal(); Eigen::VectorXd ones(dimension + 1); ones.fill(1); Eigen::MatrixXd Ones = ones.asDiagonal(); // Khachiyan Algorithm while (error > tolerance) { auto Qt = Q.transpose(); Eigen::MatrixXd X = Q*u*Qt; Eigen::FullPivHouseholderQR qr(X); Eigen::MatrixXd Xi = qr.solve(Ones); Eigen::MatrixXd M = Qt * Xi * Q; double maximumValue = M(0, 0); int maximumPosition = 0; for (int i = 0; i < numberOfPoints; ++i) { if (maximumValue < M(i, i)) { maximumValue = M(i, i); maximumPosition = i; } } double stepsize = (maximumValue - dimension - 1) / ((dimension + 1) * (maximumValue - 1)); Eigen::DiagonalMatrix new_u = (1.0 - stepsize) * u; new_u.diagonal()[maximumPosition] = (new_u.diagonal())(maximumPosition) + stepsize; ++count; error = (new_u.diagonal() - u.diagonal()).norm(); u.diagonal() = new_u.diagonal(); } // U = u Eigen::MatrixXd Ai = points * u * points.transpose() - points * u *(points * u).transpose(); Eigen::FullPivHouseholderQR qr(Ai); Eigen::VectorXd ones2(dimension); ones2.fill(1); Eigen::MatrixXd Ones2 = ones2.asDiagonal(); Eigen::MatrixXd A = qr.solve(Ones2)*1.0/dimension; Eigen::JacobiSVD svd(A); double c = 1 / sqrt(svd.singularValues()[0]); double b = 1 / sqrt(svd.singularValues()[1]); double a = 1 / sqrt(svd.singularValues()[2]); double V = 4 * vnl_math::pi*a*b*c / 3; double ad_mvee= 0; double alpha = std::sqrt(1 - b*b / a / a); double beta = std::sqrt(1 - c*c / a / a); for (int i = 0; i < 20; ++i) { ad_mvee += 4 * vnl_math::pi*a*b*(alpha*alpha + beta*beta) / (2 * alpha*beta) * (std::pow(alpha*beta, i)) / (1 - 4 * i*i); } vol = V; surf = ad_mvee; } -mitk::GIFVolumetricDensityStatistics::FeatureListType mitk::GIFVolumetricDensityStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +mitk::GIFVolumetricDensityStatistics::GIFVolumetricDensityStatistics() +{ + SetLongName("volume-density"); + SetShortName("volden"); + SetFeatureClassName("Morphological Density"); +} + +void mitk::GIFVolumetricDensityStatistics::AddArguments(mitkCommandLineParser& parser) const +{ + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Volume-Density Statistic", "calculates volume density based features", us::Any()); +} + +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFVolumetricDensityStatistics::DoCalculateFeatures(const Image* image, const Image* mask) { FeatureListType featureList; + if (image->GetDimension() < 3) { + MITK_INFO << "Skipped calculating volumetric density features; only 3D images are supported ...."; return featureList; } - std::string prefix = FeatureDescriptionPrefix(); + MITK_INFO << "Start calculating volumetric density features ...."; vtkSmartPointer mesher = vtkSmartPointer::New(); vtkSmartPointer stats = vtkSmartPointer::New(); vtkSmartPointer stats2 = vtkSmartPointer::New(); - mesher->SetInputData(mask->GetVtkImageData()); + auto nonconstVtkData = const_cast(mask->GetVtkImageData()); + mesher->SetInputData(nonconstVtkData); mesher->SetValue(0, 0.5); stats->SetInputConnection(mesher->GetOutputPort()); stats->Update(); vtkSmartPointer delaunay = vtkSmartPointer< vtkDelaunay3D >::New(); delaunay->SetInputConnection(mesher->GetOutputPort()); delaunay->SetAlpha(0); delaunay->Update(); vtkSmartPointer geometryFilter = vtkSmartPointer::New(); geometryFilter->SetInputConnection(delaunay->GetOutputPort()); geometryFilter->Update(); stats2->SetInputConnection(geometryFilter->GetOutputPort()); stats2->Update(); double vol_mvee; double surf_mvee; calculateMEE(mesher->GetOutput(), vol_mvee, surf_mvee); double vol_mobb; double surf_mobb; calculateMOBB(geometryFilter->GetOutput(), vol_mobb, surf_mobb); double pi = vnl_math::pi; double meshVolume = stats->GetVolume(); double meshSurf = stats->GetSurfaceArea(); GIFVolumetricDensityStatisticsParameters params; params.volume = meshVolume; - params.prefix = prefix; + params.id = this->CreateTemplateFeatureID(); AccessByItk_3(image, CalculateVolumeDensityStatistic, mask, params, featureList); //Calculate center of mass shift int xx = mask->GetDimensions()[0]; int yy = mask->GetDimensions()[1]; int zz = mask->GetDimensions()[2]; double xd = mask->GetGeometry()->GetSpacing()[0]; double yd = mask->GetGeometry()->GetSpacing()[1]; double zd = mask->GetGeometry()->GetSpacing()[2]; - int minimumX=xx; - int maximumX=0; - int minimumY=yy; - int maximumY=0; - int minimumZ=zz; - int maximumZ=0; + 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; + 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); + mitk::FastSinglePixelAccess, + image->GetChannelDescriptor().GetPixelType(), + image, + image->GetVolumeData(), + index, + pxImage, + 0); mitkPixelTypeMultiplex5( - mitk::FastSinglePixelAccess, - mask->GetChannelDescriptor().GetPixelType(), - mask, - mask->GetVolumeData(), - index, - pxMask, - 0); + 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); + points->InsertNextPoint(x * xd, y * yd, z * zd); if (pxImage == pxImage) { - dataset1Arr->InsertNextValue(x*xd); - dataset2Arr->InsertNextValue(y*yd); - dataset3Arr->InsertNextValue(z*zd); + dataset1Arr->InsertNextValue(x * xd); + dataset2Arr->InsertNextValue(y * yd); + dataset3Arr->InsertNextValue(z * zd); } } } } } vtkSmartPointer datasetTable = vtkSmartPointer::New(); datasetTable->AddColumn(dataset1Arr); datasetTable->AddColumn(dataset2Arr); datasetTable->AddColumn(dataset3Arr); vtkSmartPointer pcaStatistics = vtkSmartPointer::New(); pcaStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, datasetTable); pcaStatistics->SetColumnStatus("M1", 1); pcaStatistics->SetColumnStatus("M2", 1); pcaStatistics->SetColumnStatus("M3", 1); pcaStatistics->RequestSelectedColumns(); pcaStatistics->SetDeriveOption(true); pcaStatistics->Update(); vtkSmartPointer eigenvalues = vtkSmartPointer::New(); pcaStatistics->GetEigenvalues(eigenvalues); std::vector eigen_val(3); eigen_val[2] = eigenvalues->GetValue(0); eigen_val[1] = eigenvalues->GetValue(1); eigen_val[0] = eigenvalues->GetValue(2); - double major = 2*sqrt(eigen_val[2]); - double minor = 2*sqrt(eigen_val[1]); - double least = 2*sqrt(eigen_val[0]); + double 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 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 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_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 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 += 4 * pi * major * minor * (alpha * alpha + beta * beta) / (2 * alpha * beta) * (std::pow(alpha * beta, i)) / (1 - 4 * i * i); } ad_aee = meshSurf / ad_aee; double vd_ch = meshVolume / stats2->GetVolume(); double ad_ch = meshSurf / stats2->GetSurfaceArea(); - featureList.push_back(std::make_pair(prefix + "Volume density axis-aligned bounding box", vd_aabb)); - featureList.push_back(std::make_pair(prefix + "Surface density axis-aligned bounding box", ad_aabb)); - featureList.push_back(std::make_pair(prefix + "Volume density oriented minimum bounding box", meshVolume / vol_mobb)); - featureList.push_back(std::make_pair(prefix + "Surface density oriented minimum bounding box", meshSurf / surf_mobb)); - featureList.push_back(std::make_pair(prefix + "Volume density approx. enclosing ellipsoid", vd_aee)); - featureList.push_back(std::make_pair(prefix + "Surface density approx. enclosing ellipsoid", ad_aee)); - featureList.push_back(std::make_pair(prefix + "Volume density approx. minimum volume enclosing ellipsoid", meshVolume / vol_mvee)); - featureList.push_back(std::make_pair(prefix + "Surface density approx. minimum volume enclosing ellipsoid", meshSurf / surf_mvee)); - featureList.push_back(std::make_pair(prefix + "Volume density convex hull", vd_ch)); - featureList.push_back(std::make_pair(prefix + "Surface density convex hull", ad_ch)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Volume density axis-aligned bounding box"), vd_aabb)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Surface density axis-aligned bounding box"), ad_aabb)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Volume density oriented minimum bounding box"), meshVolume / vol_mobb)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Surface density oriented minimum bounding box"), meshSurf / surf_mobb)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Volume density approx. enclosing ellipsoid"), vd_aee)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Surface density approx. enclosing ellipsoid"), ad_aee)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Volume density approx. minimum volume enclosing ellipsoid"), meshVolume / vol_mvee)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Surface density approx. minimum volume enclosing ellipsoid"), meshSurf / surf_mvee)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Volume density convex hull"), vd_ch)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(params.id, "Surface density convex hull"), ad_ch)); - return featureList; -} + MITK_INFO << "Finished calculating volumetric density features...."; -mitk::GIFVolumetricDensityStatistics::GIFVolumetricDensityStatistics() -{ - SetLongName("volume-density"); - SetShortName("volden"); - SetFeatureClassName("Morphological Density"); -} - -mitk::GIFVolumetricDensityStatistics::FeatureNameListType mitk::GIFVolumetricDensityStatistics::GetFeatureNames() -{ - FeatureNameListType featureList; return featureList; } - -void mitk::GIFVolumetricDensityStatistics::AddArguments(mitkCommandLineParser &parser) +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFVolumetricDensityStatistics::CalculateFeatures(const Image* image, const Image* mask, const Image*) { - std::string name = GetOptionPrefix(); - - parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Volume-Density Statistic", "calculates volume density based features", us::Any()); -} - -void -mitk::GIFVolumetricDensityStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) -{ - auto parsedArgs = GetParameter(); - if (parsedArgs.count(GetLongName())) - { - MITK_INFO << "Start calculating volumetric density features ...."; - auto localResults = this->CalculateFeatures(feature, mask); - featureList.insert(featureList.end(), localResults.begin(), localResults.end()); - MITK_INFO << "Finished calculating volumetric density features...."; - } + return Superclass::CalculateFeatures(image, mask); } - diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp index e46cbc49d1..860265ced9 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp @@ -1,466 +1,456 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include #include #include // ITK #include #include // VTK #include #include #include #include #include #include // STL #include template void - CalculateVolumeStatistic(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFVolumetricStatistics::FeatureListType & featureList, std::string prefix) + CalculateVolumeStatistic(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFVolumetricStatistics::FeatureListType & featureList, const mitk::FeatureID& featureID) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::LabelStatisticsImageFilter FilterType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); typename FilterType::Pointer labelStatisticsImageFilter = FilterType::New(); labelStatisticsImageFilter->SetInput( itkImage ); labelStatisticsImageFilter->SetLabelInput(maskImage); labelStatisticsImageFilter->Update(); double volume = labelStatisticsImageFilter->GetCount(1); double voxelVolume = 1; for (int i = 0; i < (int)(VImageDimension); ++i) { volume *= itkImage->GetSpacing()[i]; voxelVolume *= itkImage->GetSpacing()[i]; } - featureList.push_back(std::make_pair(prefix + "Voxel Volume", voxelVolume)); - featureList.push_back(std::make_pair(prefix + "Volume (voxel based)", volume)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Voxel Volume"), voxelVolume)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Volume (voxel based)"), volume)); } template void - CalculateLargestDiameter(itk::Image* mask, mitk::Image::Pointer valueImage, mitk::GIFVolumetricStatistics::FeatureListType & featureList, std::string prefix) + CalculateLargestDiameter(const itk::Image* mask, const mitk::Image* valueImage, mitk::GIFVolumetricStatistics::FeatureListType & featureList, mitk::FeatureID featureID) { 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::ConstNeighborhoodIterator 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]; int maskMinimumX = maskDimensionX; int maskMaximumX = 0; int maskMinimumY = maskDimensionY; int maskMaximumY = 0; int maskMinimumZ = maskDimensionZ; int maskMaximumZ = 0; // // Calculate surface in different directions // double surface = 0; std::vector directionSurface; for (int i = 0; i < (int)(iterator.Size()); ++i) { auto offset = iterator.GetOffset(i); double deltaS = 1; int nonZeros = 0; for (unsigned int j = 0; j < VImageDimension; ++j) { if (offset[j] != 0 && nonZeros == 0) { for (unsigned int k = 0; k < VImageDimension; ++k) { if (k != j) deltaS *= mask->GetSpacing()[k]; } nonZeros++; } else if (offset[j] != 0) { deltaS = 0; } } if (nonZeros < 1) deltaS = 0; directionSurface.push_back(deltaS); } // // Prepare calulation of Centre of mass shift // PointType normalCenter(0); PointType normalCenterUncorrected(0); PointType weightedCenter(0); PointType currentPoint; int numberOfPoints = 0; int numberOfPointsUncorrected = 0; double sumOfPoints = 0; while(!iterator.IsAtEnd()) { if (iterator.GetCenterPixel() == 0) { ++iterator; ++valueIter; continue; } maskMinimumX = (maskMinimumX > iterator.GetIndex()[0]) ? iterator.GetIndex()[0] : maskMinimumX; maskMaximumX = (maskMaximumX < iterator.GetIndex()[0]) ? iterator.GetIndex()[0] : maskMaximumX; maskMinimumY = (maskMinimumY > iterator.GetIndex()[1]) ? iterator.GetIndex()[1] : maskMinimumY; maskMaximumY = (maskMaximumY < iterator.GetIndex()[1]) ? iterator.GetIndex()[1] : maskMaximumY; maskMinimumZ = (maskMinimumZ > iterator.GetIndex()[2]) ? iterator.GetIndex()[2] : maskMinimumZ; maskMaximumZ = (maskMaximumZ < iterator.GetIndex()[2]) ? iterator.GetIndex()[2] : maskMaximumZ; mask->TransformIndexToPhysicalPoint(iterator.GetIndex(), currentPoint); normalCenterUncorrected += currentPoint.GetVectorFromOrigin(); ++numberOfPointsUncorrected; double intensityValue = valueIter.GetCenterPixel(); if (intensityValue == intensityValue) { normalCenter += currentPoint.GetVectorFromOrigin(); weightedCenter += currentPoint.GetVectorFromOrigin() * intensityValue; sumOfPoints += intensityValue; ++numberOfPoints; } bool border = false; for (int i = 0; i < (int)(iterator.Size()); ++i) { if (iterator.GetPixel(i) == 0 || ( ! iterator.IndexInBounds(i))) { border = true; surface += directionSurface[i]; //break; } } if (border) { auto centerIndex = iterator.GetIndex(); PointType centerPoint; mask->TransformIndexToPhysicalPoint(centerIndex, centerPoint ); borderPoints.push_back(centerPoint); } ++iterator; ++valueIter; } auto normalCenterVector = normalCenter.GetVectorFromOrigin() / numberOfPoints; auto normalCenterVectorUncorrected = normalCenter.GetVectorFromOrigin() / numberOfPointsUncorrected; auto weightedCenterVector = weightedCenter.GetVectorFromOrigin() / sumOfPoints; auto differenceOfCentersUncorrected = (normalCenterVectorUncorrected - weightedCenterVector).GetNorm(); auto differenceOfCenters = (normalCenterVector - weightedCenterVector).GetNorm(); double longestDiameter = 0; unsigned long numberOfBorderPoints = borderPoints.size(); for (int i = 0; i < (int)numberOfBorderPoints; ++i) { auto point = borderPoints[i]; for (int j = i; j < (int)numberOfBorderPoints; ++j) { double newDiameter=point.EuclideanDistanceTo(borderPoints[j]); if (newDiameter > longestDiameter) longestDiameter = newDiameter; } } double boundingBoxVolume = maskVoxelSpacingX* (maskMaximumX - maskMinimumX) * maskVoxelSpacingY* (maskMaximumY - maskMinimumY) * maskVoxelSpacingZ* (maskMaximumZ - maskMinimumZ); - featureList.push_back(std::make_pair(prefix + "Maximum 3D diameter", longestDiameter)); - featureList.push_back(std::make_pair(prefix + "Surface (voxel based)", surface)); - featureList.push_back(std::make_pair(prefix + "Centre of mass shift", differenceOfCenters)); - featureList.push_back(std::make_pair(prefix + "Centre of mass shift (uncorrected)", differenceOfCentersUncorrected)); - featureList.push_back(std::make_pair(prefix + "Bounding Box Volume", boundingBoxVolume)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Maximum 3D diameter"), longestDiameter)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Surface (voxel based)"), surface)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Centre of mass shift"), differenceOfCenters)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Centre of mass shift (uncorrected)"), differenceOfCentersUncorrected)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Bounding Box Volume"), boundingBoxVolume)); } mitk::GIFVolumetricStatistics::GIFVolumetricStatistics() { SetLongName("volume"); SetShortName("vol"); SetFeatureClassName("Volumetric Features"); } -mitk::GIFVolumetricStatistics::FeatureListType mitk::GIFVolumetricStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +void mitk::GIFVolumetricStatistics::AddArguments(mitkCommandLineParser& parser) const +{ + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Volume-Statistic", "calculates volume based features", us::Any()); +} + +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFVolumetricStatistics::DoCalculateFeatures(const Image* image, const Image* mask) { FeatureListType featureList; + + MITK_INFO << "Start calculating Volumetric Features:...."; + if (image->GetDimension() < 3) { return featureList; } + auto featureID = this->CreateTemplateFeatureID(); - AccessByItk_3(image, CalculateVolumeStatistic, mask, featureList, FeatureDescriptionPrefix()); - AccessByItk_3(mask, CalculateLargestDiameter, image, featureList, FeatureDescriptionPrefix()); + AccessByItk_3(image, CalculateVolumeStatistic, mask, featureList, featureID); + AccessByItk_3(mask, CalculateLargestDiameter, image, featureList, featureID); vtkSmartPointer mesher = vtkSmartPointer::New(); vtkSmartPointer stats = vtkSmartPointer::New(); - mesher->SetInputData(mask->GetVtkImageData()); + auto nonconstVtkData = const_cast(mask->GetVtkImageData()); + mesher->SetInputData(nonconstVtkData); mesher->SetValue(0, 0.5); stats->SetInputConnection(mesher->GetOutputPort()); stats->Update(); double pi = vnl_math::pi; double meshVolume = stats->GetVolume(); double meshSurf = stats->GetSurfaceArea(); double pixelVolume = featureList[1].second; double pixelSurface = featureList[3].second; MITK_INFO << "Surface: " << pixelSurface << " Volume: " << pixelVolume; double compactness1 = pixelVolume / (std::sqrt(pi) * std::pow(meshSurf, 2.0 / 3.0)); double compactness1Pixel = pixelVolume / (std::sqrt(pi) * std::pow(pixelSurface, 2.0 / 3.0)); //This is the definition used by Aertz. However, due to 2/3 this feature is not demensionless. Use compactness3 instead. - double compactness2 = 36 * pi*pixelVolume*pixelVolume / meshSurf / meshSurf / meshSurf; - double compactness2MeshMesh = 36 * pi*meshVolume*meshVolume / meshSurf / meshSurf / meshSurf; - double compactness2Pixel = 36 * pi*pixelVolume*pixelVolume / pixelSurface / pixelSurface / pixelSurface; + double compactness2 = 36 * pi * pixelVolume * pixelVolume / meshSurf / meshSurf / meshSurf; + double compactness2MeshMesh = 36 * pi * meshVolume * meshVolume / meshSurf / meshSurf / meshSurf; + double compactness2Pixel = 36 * pi * pixelVolume * pixelVolume / pixelSurface / pixelSurface / pixelSurface; double compactness3 = pixelVolume / (std::sqrt(pi) * std::pow(meshSurf, 3.0 / 2.0)); double compactness3MeshMesh = meshVolume / (std::sqrt(pi) * std::pow(meshSurf, 3.0 / 2.0)); double compactness3Pixel = pixelVolume / (std::sqrt(pi) * std::pow(pixelSurface, 3.0 / 2.0)); - double sphericity = std::pow(pi, 1 / 3.0) *std::pow(6 * pixelVolume, 2.0 / 3.0) / meshSurf; - double sphericityMesh = std::pow(pi, 1 / 3.0) *std::pow(6 * meshVolume, 2.0 / 3.0) / meshSurf; - double sphericityPixel = std::pow(pi, 1 / 3.0) *std::pow(6 * pixelVolume, 2.0 / 3.0) / pixelSurface; + double sphericity = std::pow(pi, 1 / 3.0) * std::pow(6 * pixelVolume, 2.0 / 3.0) / meshSurf; + double sphericityMesh = std::pow(pi, 1 / 3.0) * std::pow(6 * meshVolume, 2.0 / 3.0) / meshSurf; + double sphericityPixel = std::pow(pi, 1 / 3.0) * std::pow(6 * pixelVolume, 2.0 / 3.0) / pixelSurface; double surfaceToVolume = meshSurf / meshVolume; double surfaceToVolumePixel = pixelSurface / pixelVolume; double sphericalDisproportion = meshSurf / 4 / pi / std::pow(3.0 / 4.0 / pi * pixelVolume, 2.0 / 3.0); double sphericalDisproportionMesh = meshSurf / 4 / pi / std::pow(3.0 / 4.0 / pi * meshVolume, 2.0 / 3.0); double sphericalDisproportionPixel = pixelSurface / 4 / pi / std::pow(3.0 / 4.0 / pi * pixelVolume, 2.0 / 3.0); - double asphericity = std::pow(1.0/compactness2, (1.0 / 3.0)) - 1; + double asphericity = std::pow(1.0 / compactness2, (1.0 / 3.0)) - 1; double asphericityMesh = std::pow(1.0 / compactness2MeshMesh, (1.0 / 3.0)) - 1; - double asphericityPixel = std::pow(1.0/compactness2Pixel, (1.0 / 3.0)) - 1; + double asphericityPixel = std::pow(1.0 / compactness2Pixel, (1.0 / 3.0)) - 1; //Calculate center of mass shift int xx = mask->GetDimensions()[0]; int yy = mask->GetDimensions()[1]; int zz = mask->GetDimensions()[2]; double xd = mask->GetGeometry()->GetSpacing()[0]; double yd = mask->GetGeometry()->GetSpacing()[1]; double zd = mask->GetGeometry()->GetSpacing()[2]; vtkSmartPointer dataset1Arr = vtkSmartPointer::New(); vtkSmartPointer dataset2Arr = vtkSmartPointer::New(); vtkSmartPointer dataset3Arr = vtkSmartPointer::New(); dataset1Arr->SetNumberOfComponents(1); dataset2Arr->SetNumberOfComponents(1); dataset3Arr->SetNumberOfComponents(1); dataset1Arr->SetName("M1"); dataset2Arr->SetName("M2"); dataset3Arr->SetName("M3"); vtkSmartPointer dataset1ArrU = vtkSmartPointer::New(); vtkSmartPointer dataset2ArrU = vtkSmartPointer::New(); vtkSmartPointer dataset3ArrU = vtkSmartPointer::New(); dataset1ArrU->SetNumberOfComponents(1); dataset2ArrU->SetNumberOfComponents(1); dataset3ArrU->SetNumberOfComponents(1); dataset1ArrU->SetName("M1"); dataset2ArrU->SetName("M2"); dataset3ArrU->SetName("M3"); for (int x = 0; x < xx; x++) { for (int y = 0; y < yy; y++) { for (int z = 0; z < zz; z++) { - itk::Image::IndexType index; + 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); + mitk::FastSinglePixelAccess, + image->GetChannelDescriptor().GetPixelType(), + image, + image->GetVolumeData(), + index, + pxImage, + 0); mitkPixelTypeMultiplex5( - mitk::FastSinglePixelAccess, - mask->GetChannelDescriptor().GetPixelType(), - mask, - mask->GetVolumeData(), - index, - pxMask, - 0); + mitk::FastSinglePixelAccess, + mask->GetChannelDescriptor().GetPixelType(), + mask, + mask->GetVolumeData(), + index, + pxMask, + 0); //Check if voxel is contained in segmentation if (pxMask > 0) { - dataset1ArrU->InsertNextValue(x*xd); - dataset2ArrU->InsertNextValue(y*yd); - dataset3ArrU->InsertNextValue(z*zd); + dataset1ArrU->InsertNextValue(x * xd); + dataset2ArrU->InsertNextValue(y * yd); + dataset3ArrU->InsertNextValue(z * zd); if (pxImage == pxImage) { - dataset1Arr->InsertNextValue(x*xd); - dataset2Arr->InsertNextValue(y*yd); - dataset3Arr->InsertNextValue(z*zd); + dataset1Arr->InsertNextValue(x * xd); + dataset2Arr->InsertNextValue(y * yd); + dataset3Arr->InsertNextValue(z * zd); } } } } } vtkSmartPointer datasetTable = vtkSmartPointer::New(); datasetTable->AddColumn(dataset1Arr); datasetTable->AddColumn(dataset2Arr); datasetTable->AddColumn(dataset3Arr); vtkSmartPointer datasetTableU = vtkSmartPointer::New(); datasetTableU->AddColumn(dataset1ArrU); datasetTableU->AddColumn(dataset2ArrU); datasetTableU->AddColumn(dataset3ArrU); vtkSmartPointer pcaStatistics = vtkSmartPointer::New(); pcaStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, datasetTable); pcaStatistics->SetColumnStatus("M1", 1); pcaStatistics->SetColumnStatus("M2", 1); pcaStatistics->SetColumnStatus("M3", 1); pcaStatistics->RequestSelectedColumns(); pcaStatistics->SetDeriveOption(true); pcaStatistics->Update(); vtkSmartPointer eigenvalues = vtkSmartPointer::New(); pcaStatistics->GetEigenvalues(eigenvalues); pcaStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, datasetTableU); pcaStatistics->Update(); vtkSmartPointer eigenvaluesU = vtkSmartPointer::New(); pcaStatistics->GetEigenvalues(eigenvaluesU); std::vector eigen_val(3); std::vector eigen_valUC(3); eigen_val[2] = eigenvalues->GetValue(0); eigen_val[1] = eigenvalues->GetValue(1); eigen_val[0] = eigenvalues->GetValue(2); eigen_valUC[2] = eigenvaluesU->GetValue(0); eigen_valUC[1] = eigenvaluesU->GetValue(1); eigen_valUC[0] = eigenvaluesU->GetValue(2); - double major = 4*sqrt(eigen_val[2]); - double minor = 4*sqrt(eigen_val[1]); - double least = 4*sqrt(eigen_val[0]); + double 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 majorUC = 4 * sqrt(eigen_valUC[2]); + double minorUC = 4 * sqrt(eigen_valUC[1]); + double leastUC = 4 * sqrt(eigen_valUC[0]); double elongationUC = majorUC == 0 ? 0 : sqrt(eigen_valUC[1] / eigen_valUC[2]); double flatnessUC = majorUC == 0 ? 0 : sqrt(eigen_valUC[0] / eigen_valUC[2]); - std::string prefix = FeatureDescriptionPrefix(); - featureList.push_back(std::make_pair(prefix + "Volume (mesh based)",meshVolume)); - featureList.push_back(std::make_pair(prefix + "Surface (mesh based)",meshSurf)); - featureList.push_back(std::make_pair(prefix + "Surface to volume ratio (mesh based)",surfaceToVolume)); - featureList.push_back(std::make_pair(prefix + "Sphericity (mesh based)",sphericity)); - featureList.push_back(std::make_pair(prefix + "Sphericity (mesh, mesh based)", sphericityMesh)); - featureList.push_back(std::make_pair(prefix + "Asphericity (mesh based)", asphericity)); - featureList.push_back(std::make_pair(prefix + "Asphericity (mesh, mesh based)", asphericityMesh)); - featureList.push_back(std::make_pair(prefix + "Compactness 1 (mesh based)", compactness3)); - featureList.push_back(std::make_pair(prefix + "Compactness 1 old (mesh based)" ,compactness1)); - featureList.push_back(std::make_pair(prefix + "Compactness 2 (mesh based)",compactness2)); - featureList.push_back(std::make_pair(prefix + "Compactness 1 (mesh, mesh based)", compactness3MeshMesh)); - featureList.push_back(std::make_pair(prefix + "Compactness 2 (mesh, mesh based)", compactness2MeshMesh)); - featureList.push_back(std::make_pair(prefix + "Spherical disproportion (mesh based)", sphericalDisproportion)); - featureList.push_back(std::make_pair(prefix + "Spherical disproportion (mesh, mesh based)", sphericalDisproportionMesh)); - featureList.push_back(std::make_pair(prefix + "Surface to volume ratio (voxel based)", surfaceToVolumePixel)); - featureList.push_back(std::make_pair(prefix + "Sphericity (voxel based)", sphericityPixel)); - featureList.push_back(std::make_pair(prefix + "Asphericity (voxel based)", asphericityPixel)); - featureList.push_back(std::make_pair(prefix + "Compactness 1 (voxel based)", compactness3Pixel)); - featureList.push_back(std::make_pair(prefix + "Compactness 1 old (voxel based)", compactness1Pixel)); - featureList.push_back(std::make_pair(prefix + "Compactness 2 (voxel based)", compactness2Pixel)); - featureList.push_back(std::make_pair(prefix + "Spherical disproportion (voxel based)", sphericalDisproportionPixel)); - featureList.push_back(std::make_pair(prefix + "PCA Major axis length",major)); - featureList.push_back(std::make_pair(prefix + "PCA Minor axis length",minor)); - featureList.push_back(std::make_pair(prefix + "PCA Least axis length",least)); - featureList.push_back(std::make_pair(prefix + "PCA Elongation",elongation)); - featureList.push_back(std::make_pair(prefix + "PCA Flatness",flatness)); - featureList.push_back(std::make_pair(prefix + "PCA Major axis length (uncorrected)", majorUC)); - featureList.push_back(std::make_pair(prefix + "PCA Minor axis length (uncorrected)", minorUC)); - featureList.push_back(std::make_pair(prefix + "PCA Least axis length (uncorrected)", leastUC)); - featureList.push_back(std::make_pair(prefix + "PCA Elongation (uncorrected)", elongationUC)); - featureList.push_back(std::make_pair(prefix + "PCA Flatness (uncorrected)", flatnessUC)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Volume (mesh based)"), meshVolume)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Surface (mesh based)"), meshSurf)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Surface to volume ratio (mesh based)"), surfaceToVolume)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Sphericity (mesh based)"), sphericity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Sphericity (mesh, mesh based)"), sphericityMesh)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Asphericity (mesh based)"), asphericity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Asphericity (mesh, mesh based)"), asphericityMesh)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Compactness 1 (mesh based)"), compactness3)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Compactness 1 old (mesh based)"), compactness1)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Compactness 2 (mesh based)"), compactness2)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Compactness 1 (mesh, mesh based)"), compactness3MeshMesh)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Compactness 2 (mesh, mesh based)"), compactness2MeshMesh)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Spherical disproportion (mesh based)"), sphericalDisproportion)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Spherical disproportion (mesh, mesh based)"), sphericalDisproportionMesh)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Surface to volume ratio (voxel based)"), surfaceToVolumePixel)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Sphericity (voxel based)"), sphericityPixel)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Asphericity (voxel based)"), asphericityPixel)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Compactness 1 (voxel based)"), compactness3Pixel)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Compactness 1 old (voxel based)"), compactness1Pixel)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Compactness 2 (voxel based)"), compactness2Pixel)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "Spherical disproportion (voxel based)"), sphericalDisproportionPixel)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "PCA Major axis length"), major)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "PCA Minor axis length"), minor)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "PCA Least axis length"), least)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "PCA Elongation"), elongation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "PCA Flatness"), flatness)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "PCA Major axis length (uncorrected)"), majorUC)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "PCA Minor axis length (uncorrected)"), minorUC)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "PCA Least axis length (uncorrected)"), leastUC)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "PCA Elongation (uncorrected)"), elongationUC)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(featureID, "PCA Flatness (uncorrected)"), flatnessUC)); + + MITK_INFO << "Finished calculating volumetric features...."; return featureList; } -mitk::GIFVolumetricStatistics::FeatureNameListType mitk::GIFVolumetricStatistics::GetFeatureNames() +mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFVolumetricStatistics::CalculateFeatures(const Image* image, const Image* mask, const Image* ) { - FeatureNameListType featureList; - return featureList; + return Superclass::CalculateFeatures(image, mask); } - - -void mitk::GIFVolumetricStatistics::AddArguments(mitkCommandLineParser &parser) -{ - std::string name = GetOptionPrefix(); - - parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Volume-Statistic", "calculates volume based features", us::Any()); -} - -void -mitk::GIFVolumetricStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) -{ - auto parsedArgs = GetParameter(); - if (parsedArgs.count(GetLongName())) - { - MITK_INFO << "Start calculating Volumetric Features::...."; - auto localResults = this->CalculateFeatures(feature, mask); - featureList.insert(featureList.end(), localResults.begin(), localResults.end()); - MITK_INFO << "Finished calculating volumetric features...."; - } -} - diff --git a/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp b/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp index 22297ab79e..8b12aeca34 100644 --- a/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp +++ b/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp @@ -1,216 +1,231 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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::Image, "Input Image", "Path to the input image file", us::Any(), false, false, false, mitkCommandLineParser::Input); parser.addArgument("mask", "m", mitkCommandLineParser::Image, "Input Mask", "Path to the mask Image that specifies the area over for the statistic (Values = 1)", us::Any(), false, false, false, mitkCommandLineParser::Input); parser.addArgument("morph-mask", "morph", mitkCommandLineParser::Image, "Morphological Image Mask", "Path to the mask Image that specifies the area over for the statistic (Values = 1)", us::Any(), true, false, false, mitkCommandLineParser::Input); parser.addArgument("output", "o", mitkCommandLineParser::File, "Output text file", "Path to output file. The output statistic is appended to this file.", us::Any(), false, false, false, mitkCommandLineParser::Output); // Optional Parameter + parser.addArgument("xml-output", "x", mitkCommandLineParser::File, "XML result file", "Path where the results should be stored as XML result file. ", us::Any(), true, false, false, mitkCommandLineParser::Input); parser.addArgument("logfile", "log", mitkCommandLineParser::File, "Text Logfile", "Path to the location of the target log file. ", us::Any(), true, false, false, mitkCommandLineParser::Input); parser.addArgument("save-image", "save-image", mitkCommandLineParser::File, "Output Image", "If spezified, the image that is used for the analysis is saved to this location.", us::Any(), true, false, false, mitkCommandLineParser::Output); parser.addArgument("save-mask", "save-mask", mitkCommandLineParser::File, "Output Image", "If spezified, the mask that is used for the analysis is saved to this location. ", us::Any(), true, false, false, mitkCommandLineParser::Output); parser.addArgument("save-image-screenshots", "save-screenshot", mitkCommandLineParser::File, "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(), true, false, false, mitkCommandLineParser::Output); 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()); - parser.addArgument("encode-parameter-in-name", "encode-parameter", mitkCommandLineParser::Bool, "Bool", "If true, the parameters used for each feature is encoded in its name. ", us::Any()); + parser.addArgument("encode-parameter-in-name", "encode-parameter", mitkCommandLineParser::Bool, "Bool", "If true, the parameters used for each feature is encoded in its name.", us::Any()); + parser.addArgument("pipeline-uid", "p", mitkCommandLineParser::String, "Pipeline UID", "UID that is stored in the XML output and identifies the processing pipeline the app is used in.", us::Any()); + parser.addArgument("all-features", "a", mitkCommandLineParser::Bool, "Calculate all features", "If true, all features will be calculated and the feature specific activation will be ignored.", 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); } + outputXMLPath = ""; + if (parsedArgs.count("xml-output")) + { + outputXMLPath = parsedArgs["xml-output"].ToString(); + } } 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); } } + pipelineUID = ""; + if (parsedArgs.count("pipeline-uid")) + { + pipelineUID = us::any_cast(parsedArgs["pipeline-uid"]); + } + + calculateAllFeatures = parsedArgs.count("all-features"); } 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; encodeParameter = 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"]); } if (parsedArgs.count("encode-parameter-in-name")) { encodeParameter = true; } } diff --git a/Modules/Classification/CLUtilities/src/mitkCLResultWritter.cpp b/Modules/Classification/CLUtilities/src/mitkCLResultWriter.cpp similarity index 77% rename from Modules/Classification/CLUtilities/src/mitkCLResultWritter.cpp rename to Modules/Classification/CLUtilities/src/mitkCLResultWriter.cpp index 91e5308d46..702dd00604 100644 --- a/Modules/Classification/CLUtilities/src/mitkCLResultWritter.cpp +++ b/Modules/Classification/CLUtilities/src/mitkCLResultWriter.cpp @@ -1,184 +1,184 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#include +#include #include #include template class punct_facet : public std::numpunct { public: punct_facet(charT sep) : m_Sep(sep) { } protected: charT do_decimal_point() const override { return m_Sep; } private: charT m_Sep; }; -mitk::cl::FeatureResultWritter::FeatureResultWritter(std::string file, int mode) : +mitk::cl::FeatureResultWriter::FeatureResultWriter(std::string file, int mode) : m_Mode(mode), m_CurrentRow(0), m_CurrentElement(0), m_Separator(";"), m_SubjectInformation(""), m_UsedSubjectInformation(false), m_UseSpecialDecimalPoint(false), m_DecimalPoint('.') { std::string str; m_List.push_back(str); m_Output.open(file, std::ios::app); } -mitk::cl::FeatureResultWritter::~FeatureResultWritter() +mitk::cl::FeatureResultWriter::~FeatureResultWriter() { for (std::size_t i = 0; i < m_List.size() - 1; ++i) { m_Output << m_List[i] << std::endl; } //m_Output << "EndOfFile" << std::endl; m_Output.close(); } -void mitk::cl::FeatureResultWritter::SetDecimalPoint(char decimal) +void mitk::cl::FeatureResultWriter::SetDecimalPoint(char decimal) { m_Output.imbue(std::locale(std::cout.getloc(), new punct_facet(decimal))); m_UseSpecialDecimalPoint = true; m_DecimalPoint = decimal; } -void mitk::cl::FeatureResultWritter::AddColumn(double value) { +void mitk::cl::FeatureResultWriter::AddColumn(double value) { std::ostringstream ss; if (m_UseSpecialDecimalPoint) { ss.imbue(std::locale(std::cout.getloc(), new punct_facet(m_DecimalPoint))); } ss << value; AddColumn(ss.str()); } -void mitk::cl::FeatureResultWritter::AddSubjectInformation(std::string value) { +void mitk::cl::FeatureResultWriter::AddSubjectInformation(std::string value) { if ((m_Mode == 0) || (m_Mode == 1)) { AddColumn(value); } else { if (m_UsedSubjectInformation) { m_SubjectInformation = ""; } m_SubjectInformation += value + m_Separator; m_UsedSubjectInformation = false; } } -void mitk::cl::FeatureResultWritter::AddColumn(std::string value) { +void mitk::cl::FeatureResultWriter::AddColumn(std::string value) { if ((m_Mode == 0) || (m_Mode == 2)) { m_List[m_CurrentRow] = m_List[m_CurrentRow] + value + m_Separator; } else { m_CurrentRow++; while (m_List.size() <= m_CurrentRow) { std::string str; m_List.push_back(str); } m_List[m_CurrentRow] = m_List[m_CurrentRow] + value + m_Separator; } } -void mitk::cl::FeatureResultWritter::NewRow(std::string endName) { +void mitk::cl::FeatureResultWriter::NewRow(std::string endName) { AddColumn(endName); if ((m_Mode == 0) || (m_Mode == 2)) { m_CurrentRow++; while (m_List.size() <= m_CurrentRow) { std::string str; m_List.push_back(str); } } else { m_CurrentRow = 0; } } -void mitk::cl::FeatureResultWritter::AddResult(std::string desc, int slice, mitk::AbstractGlobalImageFeature::FeatureListType stats, bool, bool withDescription) +void mitk::cl::FeatureResultWriter::AddResult(std::string desc, int slice, mitk::AbstractGlobalImageFeature::FeatureListType stats, bool, bool withDescription) { if (m_Mode == 2) { for (std::size_t i = 0; i < stats.size(); ++i) { if (withDescription) { AddColumn(desc); } if (slice >= 0) { AddColumn(slice); } - AddColumn(m_SubjectInformation + stats[i].first); + AddColumn(m_SubjectInformation + stats[i].first.legacyName); AddColumn(stats[i].second); NewRow(""); ++m_CurrentElement; } m_UsedSubjectInformation = true; } else { if (withDescription) { AddColumn(desc); } if (slice >= 0) { AddColumn(slice); } for (std::size_t i = 0; i < stats.size(); ++i) { AddColumn(stats[i].second); } NewRow("EndOfMeasurement"); ++m_CurrentElement; } } -void mitk::cl::FeatureResultWritter::AddHeader(std::string, int slice, mitk::AbstractGlobalImageFeature::FeatureListType stats, bool withHeader, bool withDescription) +void mitk::cl::FeatureResultWriter::AddHeader(std::string, int slice, mitk::AbstractGlobalImageFeature::FeatureListType stats, bool withHeader, bool withDescription) { if ((withHeader) && (m_CurrentElement == 0)) { if (withDescription) { AddColumn("Description"); } if (slice >= 0) { AddColumn("SliceNumber"); } for (std::size_t i = 0; i < stats.size(); ++i) { - AddColumn(stats[i].first); + AddColumn(stats[i].first.legacyName); } NewRow("EndOfMeasurement"); } } diff --git a/Modules/Classification/CLUtilities/src/mitkCLResultXMLWriter.cpp b/Modules/Classification/CLUtilities/src/mitkCLResultXMLWriter.cpp new file mode 100644 index 0000000000..0d3bf0c5ef --- /dev/null +++ b/Modules/Classification/CLUtilities/src/mitkCLResultXMLWriter.cpp @@ -0,0 +1,318 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +template +class punct_facet : public std::numpunct { +public: + punct_facet(charT sep) : + m_Sep(sep) + { + + } +protected: + charT do_decimal_point() const override { return m_Sep; } +private: + charT m_Sep; +}; + +void AddPropertyAsNode(const mitk::Image* image, const std::string& key, const std::string& tag, TiXmlElement* rootNode) +{ + auto prop = image->GetProperty(key.c_str()); + if (prop.IsNotNull()) + { + auto propNode = new TiXmlElement(tag); + TiXmlText* valueText = new TiXmlText(prop->GetValueAsString()); + propNode->LinkEndChild(valueText); + + rootNode->LinkEndChild(propNode); + } +} + +void AddSeriesInstanceUID(const mitk::Image* image, TiXmlElement* xmlNode) +{ + AddPropertyAsNode(image, mitk::DICOMTagPathToPropertyName(mitk::DICOMTagPath(0x0020, 0x000e)), "mp:seriesInstanceUID", xmlNode); +} + +void AddFilePath(const mitk::Image* image, TiXmlElement* xmlNode) +{ + AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_INPUTLOCATION()), "mp:filePath", xmlNode); +} + +void AddSOPInstanceUIDs(const mitk::Image* image, TiXmlElement* xmlNode) +{ + auto prop = image->GetProperty(mitk::DICOMTagPathToPropertyName(mitk::DICOMTagPath(0x0008, 0x0018)).c_str()); + auto dicomProp = dynamic_cast(prop.GetPointer()); + if (dicomProp != nullptr) + { + auto instanceUIDsNode = new TiXmlElement("mp:sopInstanceUIDs"); + xmlNode->LinkEndChild(instanceUIDsNode); + + if (dicomProp->IsUniform()) + { + auto instanceUIDNode = new TiXmlElement("mp:sopInstanceUID"); + TiXmlText* valueText = new TiXmlText(dicomProp->GetValueAsString()); + instanceUIDNode->LinkEndChild(valueText); + instanceUIDsNode->LinkEndChild(instanceUIDNode); + } + else + { + const auto timeSteps = dicomProp->GetAvailableTimeSteps(); + for (auto timeStep : timeSteps) + { + const auto slices = dicomProp->GetAvailableSlices(timeStep); + for (auto slice : slices) + { + auto instanceUIDNode = new TiXmlElement("mp:sopInstanceUID"); + instanceUIDNode->SetAttribute("z", slice); + instanceUIDNode->SetAttribute("t", timeStep); + TiXmlText* valueText = new TiXmlText(dicomProp->GetValue(timeStep, slice)); + instanceUIDNode->LinkEndChild(valueText); + instanceUIDsNode->LinkEndChild(instanceUIDNode); + } + } + } + } +} + +void AddDateAndTime(TiXmlElement* rootNode) +{ + auto dateNode = new TiXmlElement("mp:generationDate"); + auto time = std::time(nullptr); + std::ostringstream sstream; + sstream << std::put_time(std::localtime(&time), "%Y%m%d"); + TiXmlText* valueText = new TiXmlText(sstream.str()); + dateNode->LinkEndChild(valueText); + + rootNode->LinkEndChild(dateNode); + + auto timeNode = new TiXmlElement("mp:generationTime"); + std::ostringstream timestream; + timestream << std::put_time(std::localtime(&time), "%H%M%S"); + valueText = new TiXmlText(timestream.str()); + timeNode->LinkEndChild(valueText); + + rootNode->LinkEndChild(timeNode); +} + +void AddParameters(const std::map& parameters, TiXmlElement* paramsNode) +{ + for (const auto& param : parameters) + { + mitk::LocaleSwitch lswitch("C"); + auto paramNode = new TiXmlElement("mp:parameter"); + paramNode->SetAttribute("name", param.first); + TiXmlText* valueText = new TiXmlText(param.second.ToString()); + paramNode->LinkEndChild(valueText); + paramsNode->LinkEndChild(paramNode); + } +} + +void AddFeatures(const mitk::AbstractGlobalImageFeature::FeatureListType& features, TiXmlElement* featsNode) +{ + for (const auto& feat : features) + { + auto featNode = new TiXmlElement("mp:feature"); + featNode->SetAttribute("name", feat.first.name); + featNode->SetAttribute("version", feat.first.version); + featNode->SetAttribute("class", feat.first.featureClass); + featNode->SetAttribute("setting", feat.first.settingID); + std::ostringstream sstream; + sstream.imbue(std::locale("C")); + sstream << feat.second; + TiXmlText* valueText = new TiXmlText(sstream.str()); + featNode->LinkEndChild(valueText); + featsNode->LinkEndChild(featNode); + } +} + +void AddFeatureSettings(const mitk::AbstractGlobalImageFeature::FeatureListType& features, TiXmlElement* featSettingsNode) +{ + std::list coveredSettings; + for (const auto& feat : features) + { + auto finding = std::find(coveredSettings.begin(), coveredSettings.end(), feat.first.settingID); + if (finding == coveredSettings.end()) + { + auto featSettingNode = new TiXmlElement("mp:featureSetting"); + featSettingsNode->LinkEndChild(featSettingNode); + featSettingNode->SetAttribute("name", feat.first.settingID); + AddParameters(feat.first.parameters, featSettingNode); + coveredSettings.push_back(feat.first.settingID); + } + } +} + +void AddReaderInfo(const mitk::Image* image, TiXmlElement* imageNode) +{ + auto ioNode = new TiXmlElement("mp:IOReader"); + imageNode->LinkEndChild(ioNode); + AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_DESCRIPTION()), "mp:description", ioNode); + AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_VERSION()), "mp:version", ioNode); + AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_CONFIGURATION()), "mp:configuration", ioNode); + AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_GDCM()), "mp:gdcmVersion", ioNode); + AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_DCMTK()), "mp:dcmtkVersion", ioNode); +} + +void WriteDocument(std::ostream& stream, const mitk::Image* image, const mitk::Image* mask, + const mitk::AbstractGlobalImageFeature::FeatureListType& features, const std::string& methodName, + const std::string& organisation, const std::string& version, const std::string& pipelineUID, + const std::map& cliArgs) +{ + TiXmlDocument doc; + doc.SetCondenseWhiteSpace(false); + + auto decl = new TiXmlDeclaration( + "1.0", "UTF-8", ""); + doc.LinkEndChild(decl); + + auto rootNode = new TiXmlElement("mp:measurement"); + rootNode->SetAttribute("xmlns:mp", "http://www.mitk.org/Phenotyping"); + doc.LinkEndChild(rootNode); + + auto methodNode = new TiXmlElement("mp:measurementMethod"); + rootNode->LinkEndChild(methodNode); + + auto methodNameNode = new TiXmlElement("mp:name"); + TiXmlText* valueText = new TiXmlText(methodName); + methodNameNode->LinkEndChild(valueText); + methodNode->LinkEndChild(methodNameNode); + + auto organisationNode = new TiXmlElement("mp:organisation"); + valueText = new TiXmlText(organisation); + organisationNode->LinkEndChild(valueText); + methodNode->LinkEndChild(organisationNode); + + auto versionNode = new TiXmlElement("mp:version"); + valueText = new TiXmlText(version); + versionNode->LinkEndChild(valueText); + methodNode->LinkEndChild(versionNode); + + auto imageNode = new TiXmlElement("mp:image"); + rootNode->LinkEndChild(imageNode); + + AddSeriesInstanceUID(image, imageNode); + AddFilePath(image, imageNode); + AddSOPInstanceUIDs(image, imageNode); + AddReaderInfo(image,imageNode); + + + auto maskNode = new TiXmlElement("mp:mask"); + rootNode->LinkEndChild(maskNode); + + AddSeriesInstanceUID(mask, maskNode); + AddFilePath(mask, maskNode); + AddSOPInstanceUIDs(mask, maskNode); + AddReaderInfo(mask, maskNode); + + //todo mask reader meta info + + AddDateAndTime(rootNode); + + auto pipelineNode = new TiXmlElement("mp:pipelineUID"); + valueText = new TiXmlText(pipelineUID); + pipelineNode->LinkEndChild(valueText); + rootNode->LinkEndChild(pipelineNode); + + auto paramsNode = new TiXmlElement("mp:parameters"); + rootNode->LinkEndChild(paramsNode); + AddParameters(cliArgs, paramsNode); + + auto featsNode = new TiXmlElement("mp:features"); + rootNode->LinkEndChild(featsNode); + + AddFeatures(features, featsNode); + + auto featSettingsNode = new TiXmlElement("mp:featureSettings"); + rootNode->LinkEndChild(featSettingsNode); + AddFeatureSettings(features, featSettingsNode); + + TiXmlPrinter printer; + + doc.Accept(&printer); + stream << printer.Str(); +} + +void mitk::cl::CLResultXMLWriter::SetImage(const Image* image) +{ + m_Image = image; +} + +void mitk::cl::CLResultXMLWriter::SetMask(const Image* mask) +{ + m_Mask = mask; +} + +void mitk::cl::CLResultXMLWriter::SetFeatures(const mitk::AbstractGlobalImageFeature::FeatureListType& features) +{ + m_Features = features; +} + +void mitk::cl::CLResultXMLWriter::SetMethodName(const std::string& name) +{ + m_MethodName = name; +} + +void mitk::cl::CLResultXMLWriter::SetMethodVersion(const std::string& version) +{ + m_MethodVersion = version; +} + +void mitk::cl::CLResultXMLWriter::SetOrganisation(const std::string& orga) +{ + m_Organisation = orga; +} + +void mitk::cl::CLResultXMLWriter::SetPipelineUID(const std::string& pipelineUID) +{ + m_PipelineUID = pipelineUID; +} + +void mitk::cl::CLResultXMLWriter::SetCLIArgs(const std::map& args) +{ + m_CLIArgs = args; +} + +void mitk::cl::CLResultXMLWriter::write(const std::string& filePath) const +{ + std::ofstream resultFile; + resultFile.open(filePath.c_str()); + if (resultFile.is_open()) + { + this->write(resultFile); + resultFile.close(); + } + else + { + MITK_ERROR << "Cannot write xml results. Unable to open file: \""< #include #include "mitkIOUtil.h" #include #include class mitkGIFCooc2TestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFCooc2TestSuite); MITK_TEST(ImageDescription_PhantomTest_3D); MITK_TEST(ImageDescription_PhantomTest_2D); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest_3D() { mitk::GIFCooccurenceMatrix2::Pointer featureCalculator = mitk::GIFCooccurenceMatrix2::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[valuePair.first.featureClass + "::" + valuePair.first.name] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 18 features.", std::size_t(93), featureList.size()); // These values are obtained with IBSI (3D Comb) // Standard accuracy is 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Maximum with Large IBSI Phantom Image", 0.509, results["Co-occurenced Based Features::Overall Joint Maximum"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Average with Large IBSI Phantom Image", 2.149, results["Co-occurenced Based Features::Overall Joint Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Variance with Large IBSI Phantom Image", 3.132, results["Co-occurenced Based Features::Overall Joint Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Entropy with Large IBSI Phantom Image", 2.574, results["Co-occurenced Based Features::Overall Joint Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Difference Average with Large IBSI Phantom Image", 1.379, results["Co-occurenced Based Features::Overall Difference Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Difference Variance with Large IBSI Phantom Image", 3.215, results["Co-occurenced Based Features::Overall Difference Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Difference Entropy with Large IBSI Phantom Image", 1.641, results["Co-occurenced Based Features::Overall Difference Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Sum Average with Large IBSI Phantom Image", 4.298, results["Co-occurenced Based Features::Overall Sum Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Sum Variance with Large IBSI Phantom Image", 7.412, results["Co-occurenced Based Features::Overall Sum Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Sum Entropy with Large IBSI Phantom Image", 2.110, results["Co-occurenced Based Features::Overall Sum Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Angular Second Moment with Large IBSI Phantom Image", 0.291, results["Co-occurenced Based Features::Overall Angular Second Moment"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Contrast with Large IBSI Phantom Image", 5.118, results["Co-occurenced Based Features::Overall Contrast"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Dissimilarity with Large IBSI Phantom Image", 1.380, results["Co-occurenced Based Features::Overall Dissimilarity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference with Large IBSI Phantom Image", 0.688, results["Co-occurenced Based Features::Overall Inverse Difference"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference Normalized with Large IBSI Phantom Image", 0.856, results["Co-occurenced Based Features::Overall Inverse Difference Normalized"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference Moment with Large IBSI Phantom Image", 0.631, results["Co-occurenced Based Features::Overall Inverse Difference Moment"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.902, results["Co-occurenced Based Features::Overall Inverse Difference Moment Normalized"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Variance with Large IBSI Phantom Image", 0.057, results["Co-occurenced Based Features::Overall Inverse Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Correlation with Large IBSI Phantom Image", 0.183, results["Co-occurenced Based Features::Overall Correlation"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Autocorrelation with Large IBSI Phantom Image", 5.192, results["Co-occurenced Based Features::Overall Autocorrelation"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Cluster Tendency with Large IBSI Phantom Image", 7.412, results["Co-occurenced Based Features::Overall Cluster Tendency"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Cluster Shade with Large IBSI Phantom Image", 17.419, results["Co-occurenced Based Features::Overall Cluster Shade"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Cluster Prominence with Large IBSI Phantom Image", 147.464, results["Co-occurenced Based Features::Overall Cluster Prominence"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall First Measure of Information Correlation with Large IBSI Phantom Image", -0.0288, results["Co-occurenced Based Features::Overall First Measure of Information Correlation"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Second Measure of Information Correlation with Large IBSI Phantom Image", 0.269, results["Co-occurenced Based Features::Overall Second Measure of Information Correlation"], 0.001); // These values are obtained by manually running the tool // Values might be wrong. CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Maximum with Large IBSI Phantom Image", 0.679, results["Co-occurenced Based Features::Overall Row Maximum"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Average with Large IBSI Phantom Image", 2.149, results["Co-occurenced Based Features::Overall Row Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Variance with Large IBSI Phantom Image", 3.132, results["Co-occurenced Based Features::Overall Row Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Entropy with Large IBSI Phantom Image", 1.306, results["Co-occurenced Based Features::Overall Row Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall First Row-Column Entropy with Large IBSI Phantom Image", 2.611, results["Co-occurenced Based Features::Overall First Row-Column Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Second Row-Column Entropy with Large IBSI Phantom Image", 2.611, results["Co-occurenced Based Features::Overall Second Row-Column Entropy"], 0.001); // These values are obtained with IBSI (3D Avg) // Standard accuracy is 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Maximum with Large IBSI Phantom Image", 0.503, results["Co-occurenced Based Features::Mean Joint Maximum"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Average with Large IBSI Phantom Image", 2.143, results["Co-occurenced Based Features::Mean Joint Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Variance with Large IBSI Phantom Image", 3.099, results["Co-occurenced Based Features::Mean Joint Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Entropy with Large IBSI Phantom Image", 2.399, results["Co-occurenced Based Features::Mean Joint Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Difference Average with Large IBSI Phantom Image", 1.431, results["Co-occurenced Based Features::Mean Difference Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Difference Variance with Large IBSI Phantom Image", 3.056, results["Co-occurenced Based Features::Mean Difference Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Difference Entropy with Large IBSI Phantom Image", 1.563, results["Co-occurenced Based Features::Mean Difference Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Sum Average with Large IBSI Phantom Image", 4.2859, results["Co-occurenced Based Features::Mean Sum Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Sum Variance with Large IBSI Phantom Image", 7.072, results["Co-occurenced Based Features::Mean Sum Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Sum Entropy with Large IBSI Phantom Image", 1.9226, results["Co-occurenced Based Features::Mean Sum Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Angular Second Moment with Large IBSI Phantom Image", 0.303, results["Co-occurenced Based Features::Mean Angular Second Moment"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Contrast with Large IBSI Phantom Image", 5.3245, results["Co-occurenced Based Features::Mean Contrast"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Dissimilarity with Large IBSI Phantom Image", 1.431, results["Co-occurenced Based Features::Mean Dissimilarity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference with Large IBSI Phantom Image", 0.6766, results["Co-occurenced Based Features::Mean Inverse Difference"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference Normalized with Large IBSI Phantom Image", 0.8506, results["Co-occurenced Based Features::Mean Inverse Difference Normalized"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference Moment with Large IBSI Phantom Image", 0.6177, results["Co-occurenced Based Features::Mean Inverse Difference Moment"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.8984, results["Co-occurenced Based Features::Mean Inverse Difference Moment Normalized"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Variance with Large IBSI Phantom Image", 0.0604, results["Co-occurenced Based Features::Mean Inverse Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Correlation with Large IBSI Phantom Image", 0.157, results["Co-occurenced Based Features::Mean Correlation"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Autocorrelation with Large IBSI Phantom Image", 5.05544, results["Co-occurenced Based Features::Mean Autocorrelation"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Cluster Tendency with Large IBSI Phantom Image", 7.0728, results["Co-occurenced Based Features::Mean Cluster Tendency"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Cluster Shade with Large IBSI Phantom Image", 16.6441, results["Co-occurenced Based Features::Mean Cluster Shade"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Cluster Prominence with Large IBSI Phantom Image", 144.703, results["Co-occurenced Based Features::Mean Cluster Prominence"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean First Measure of Information Correlation with Large IBSI Phantom Image", -0.15684, results["Co-occurenced Based Features::Mean First Measure of Information Correlation"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Second Measure of Information Correlation with Large IBSI Phantom Image", 0.519588, results["Co-occurenced Based Features::Mean Second Measure of Information Correlation"], 0.001); // These values are obtained by manually running the tool // Values might be wrong. CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Maximum with Large IBSI Phantom Image", 0.6808, results["Co-occurenced Based Features::Mean Row Maximum"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Average with Large IBSI Phantom Image", 2.143, results["Co-occurenced Based Features::Mean Row Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Variance with Large IBSI Phantom Image", 3.0993, results["Co-occurenced Based Features::Mean Row Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Entropy with Large IBSI Phantom Image", 1.29699, results["Co-occurenced Based Features::Mean Row Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean First Row-Column Entropy with Large IBSI Phantom Image", 2.5939, results["Co-occurenced Based Features::Mean First Row-Column Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Second Row-Column Entropy with Large IBSI Phantom Image", 2.5939, results["Co-occurenced Based Features::Mean Second Row-Column Entropy"], 0.001); } void ImageDescription_PhantomTest_2D() { mitk::GIFCooccurenceMatrix2::Pointer featureCalculator = mitk::GIFCooccurenceMatrix2::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeaturesSlicewise(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large, 2); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 558 features.", std::size_t(558), featureList.size()); // These values are obtained with IBSI // Standard accuracy is 0.01 // These values are obtained with IBSI (2D Comb) // Standard accuracy is 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Maximum with Large IBSI Phantom Image", 0.512, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Maximum"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Average with Large IBSI Phantom Image", 2.143, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Variance with Large IBSI Phantom Image", 2.7115, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Entropy with Large IBSI Phantom Image", 2.2383, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Difference Average with Large IBSI Phantom Image", 1.3990, results["SliceWise Mean Co-occurenced Based Features::Overall Difference Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Difference Variance with Large IBSI Phantom Image", 3.06426, results["SliceWise Mean Co-occurenced Based Features::Overall Difference Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Difference Entropy with Large IBSI Phantom Image", 1.49262, results["SliceWise Mean Co-occurenced Based Features::Overall Difference Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Sum Average with Large IBSI Phantom Image", 4.28686, results["SliceWise Mean Co-occurenced Based Features::Overall Sum Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Sum Variance with Large IBSI Phantom Image", 5.65615, results["SliceWise Mean Co-occurenced Based Features::Overall Sum Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Sum Entropy with Large IBSI Phantom Image", 1.79494, results["SliceWise Mean Co-occurenced Based Features::Overall Sum Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Angular Second Moment with Large IBSI Phantom Image", 0.351678, results["SliceWise Mean Co-occurenced Based Features::Overall Angular Second Moment"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Contrast with Large IBSI Phantom Image", 5.19019, results["SliceWise Mean Co-occurenced Based Features::Overall Contrast"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Dissimilarity with Large IBSI Phantom Image", 1.3990, results["SliceWise Mean Co-occurenced Based Features::Overall Dissimilarity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference with Large IBSI Phantom Image", 0.683294, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Normalized with Large IBSI Phantom Image", 0.8538, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Normalized"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment with Large IBSI Phantom Image", 0.625003, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.90088, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment Normalized"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Variance with Large IBSI Phantom Image", 0.055286, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Correlation with Large IBSI Phantom Image", 0.0173072, results["SliceWise Mean Co-occurenced Based Features::Overall Correlation"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Autocorrelation with Large IBSI Phantom Image", 5.13953, results["SliceWise Mean Co-occurenced Based Features::Overall Autocorrelation"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Cluster Tendency with Large IBSI Phantom Image", 5.6561, results["SliceWise Mean Co-occurenced Based Features::Overall Cluster Tendency"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Cluster Shade with Large IBSI Phantom Image", 6.97661, results["SliceWise Mean Co-occurenced Based Features::Overall Cluster Shade"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Cluster Prominence with Large IBSI Phantom Image", 80.3855, results["SliceWise Mean Co-occurenced Based Features::Overall Cluster Prominence"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall First Measure of Information Correlation with Large IBSI Phantom Image", -0.0340891, results["SliceWise Mean Co-occurenced Based Features::Overall First Measure of Information Correlation"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Second Measure of Information Correlation with Large IBSI Phantom Image", 0.2625, results["SliceWise Mean Co-occurenced Based Features::Overall Second Measure of Information Correlation"], 0.001); // These values are obtained by manually running the tool // Values might be wrong. CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Maximum with Large IBSI Phantom Image", 0.682689, results["SliceWise Mean Co-occurenced Based Features::Overall Row Maximum"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Average with Large IBSI Phantom Image", 2.14343, results["SliceWise Mean Co-occurenced Based Features::Overall Row Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Variance with Large IBSI Phantom Image", 2.71158, results["SliceWise Mean Co-occurenced Based Features::Overall Row Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Entropy with Large IBSI Phantom Image", 1.13773, results["SliceWise Mean Co-occurenced Based Features::Overall Row Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall First Row-Column Entropy with Large IBSI Phantom Image", 2.27545, results["SliceWise Mean Co-occurenced Based Features::Overall First Row-Column Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Second Row-Column Entropy with Large IBSI Phantom Image", 2.27545, results["SliceWise Mean Co-occurenced Based Features::Overall Second Row-Column Entropy"], 0.001); // These values are obtained with IBSI (2D Avg) // Standard accuracy is 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Maximum with Large IBSI Phantom Image", 0.5188, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Maximum"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Average with Large IBSI Phantom Image", 2.14242, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Variance with Large IBSI Phantom Image", 2.6877, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Entropy with Large IBSI Phantom Image", 2.04966, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Difference Average with Large IBSI Phantom Image", 1.42247, results["SliceWise Mean Co-occurenced Based Features::Mean Difference Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Difference Variance with Large IBSI Phantom Image", 2.90159, results["SliceWise Mean Co-occurenced Based Features::Mean Difference Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Difference Entropy with Large IBSI Phantom Image", 1.39615, results["SliceWise Mean Co-occurenced Based Features::Mean Difference Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Sum Average with Large IBSI Phantom Image", 4.28484, results["SliceWise Mean Co-occurenced Based Features::Mean Sum Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Sum Variance with Large IBSI Phantom Image", 5.47293, results["SliceWise Mean Co-occurenced Based Features::Mean Sum Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Sum Entropy with Large IBSI Phantom Image", 1.60319, results["SliceWise Mean Co-occurenced Based Features::Mean Sum Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Angular Second Moment with Large IBSI Phantom Image", 0.367529, results["SliceWise Mean Co-occurenced Based Features::Mean Angular Second Moment"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Contrast with Large IBSI Phantom Image", 5.27785, results["SliceWise Mean Co-occurenced Based Features::Mean Contrast"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Dissimilarity with Large IBSI Phantom Image", 1.42247, results["SliceWise Mean Co-occurenced Based Features::Mean Dissimilarity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference with Large IBSI Phantom Image", 0.677949, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Normalized with Large IBSI Phantom Image", 0.851399, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Normalized"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment with Large IBSI Phantom Image", 0.618737, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.899219, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment Normalized"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Variance with Large IBSI Phantom Image", 0.0566983, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Correlation with Large IBSI Phantom Image", -.012107, results["SliceWise Mean Co-occurenced Based Features::Mean Correlation"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Autocorrelation with Large IBSI Phantom Image", 5.09437, results["SliceWise Mean Co-occurenced Based Features::Mean Autocorrelation"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Cluster Tendency with Large IBSI Phantom Image", 5.47293, results["SliceWise Mean Co-occurenced Based Features::Mean Cluster Tendency"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Cluster Shade with Large IBSI Phantom Image", 6.99782, results["SliceWise Mean Co-occurenced Based Features::Mean Cluster Shade"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Cluster Prominence with Large IBSI Phantom Image", 79.1126, results["SliceWise Mean Co-occurenced Based Features::Mean Cluster Prominence"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean First Measure of Information Correlation with Large IBSI Phantom Image", -0.15512, results["SliceWise Mean Co-occurenced Based Features::Mean First Measure of Information Correlation"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Second Measure of Information Correlation with Large IBSI Phantom Image", 0.487457, results["SliceWise Mean Co-occurenced Based Features::Mean Second Measure of Information Correlation"], 0.001); // These values are obtained by manually running the tool // Values might be wrong. CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Maximum with Large IBSI Phantom Image", 0.689717, results["SliceWise Mean Co-occurenced Based Features::Mean Row Maximum"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Average with Large IBSI Phantom Image", 2.14242, results["SliceWise Mean Co-occurenced Based Features::Mean Row Average"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Variance with Large IBSI Phantom Image", 2.6877, results["SliceWise Mean Co-occurenced Based Features::Mean Row Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Entropy with Large IBSI Phantom Image", 1.1238, results["SliceWise Mean Co-occurenced Based Features::Mean Row Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean First Row-Column Entropy with Large IBSI Phantom Image", 2.24761, results["SliceWise Mean Co-occurenced Based Features::Mean First Row-Column Entropy"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Second Row-Column Entropy with Large IBSI Phantom Image", 2.24761, results["SliceWise Mean Co-occurenced Based Features::Mean Second Row-Column Entropy"], 0.001); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFCooc2 ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFCurvatureStatisticTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFCurvatureStatisticTest.cpp index 633b9954b3..77591dcee2 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFCurvatureStatisticTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFCurvatureStatisticTest.cpp @@ -1,118 +1,118 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFCurvatureStatisticTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFCurvatureStatisticTestSuite); MITK_TEST(ImageDescription_PhantomTest); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest() { mitk::GIFCurvatureStatistic::Pointer featureCalculator = mitk::GIFCurvatureStatistic::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 44 features.", std::size_t(44), featureList.size()); // These values are obtained by a run of the filter. // The might be wrong! CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Minimum Mean Curvature with Large IBSI Phantom Image", -1.51, results["Curvature Feature::Minimum Mean Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Maximum Mean Curvature with Large IBSI Phantom Image", 0.51, results["Curvature Feature::Maximum Mean Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Mean Mean Curvature with Large IBSI Phantom Image", 0.095, results["Curvature Feature::Mean Mean Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Standard Deviation Mean Curvature with Large IBSI Phantom Image", 0.45, results["Curvature Feature::Standard Deviation Mean Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Skewness Mean Curvature with Large IBSI Phantom Image", -2.55, results["Curvature Feature::Skewness Mean Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Mean Positive Mean Curvature with Large IBSI Phantom Image", 0.30, results["Curvature Feature::Mean Positive Mean Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Standard Deviation Positive Mean Curvature with Large IBSI Phantom Image", 0.12, results["Curvature Feature::Standard Deviation Positive Mean Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Skewness Positive Mean Curvature with Large IBSI Phantom Image", 0.60, results["Curvature Feature::Skewness Positive Mean Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Mean Negative Mean Curvature with Large IBSI Phantom Image", -0.955, results["Curvature Feature::Mean Negative Mean Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Standard Deviation Negative Mean Curvature with Large IBSI Phantom Image", 0.56, results["Curvature Feature::Standard Deviation Negative Mean Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Skewness Negative Mean Curvature with Large IBSI Phantom Image", 0.09, results["Curvature Feature::Skewness Negative Mean Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Minimum Gaussian Curvature with Large IBSI Phantom Image", -0.211, results["Curvature Feature::Minimum Gaussian Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Maximum Gaussian Curvature with Large IBSI Phantom Image", 1.81, results["Curvature Feature::Maximum Gaussian Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Mean Gaussian Curvature with Large IBSI Phantom Image", 0.14, results["Curvature Feature::Mean Gaussian Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Standard Deviation Gaussian Curvature with Large IBSI Phantom Image", 0.42, results["Curvature Feature::Standard Deviation Gaussian Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Skewness Gaussian Curvature with Large IBSI Phantom Image", 3.51, results["Curvature Feature::Skewness Gaussian Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Mean Positive Gaussian Curvature with Large IBSI Phantom Image", 0.26, results["Curvature Feature::Mean Positive Gaussian Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Standard Deviation Positive Gaussian Curvature with Large IBSI Phantom Image", 0.53, results["Curvature Feature::Standard Deviation Positive Gaussian Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Skewness Positive Gaussian Curvature with Large IBSI Phantom Image", 2.52, results["Curvature Feature::Skewness Positive Gaussian Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Mean Negative Gaussian Curvature with Large IBSI Phantom Image", -0.03, results["Curvature Feature::Mean Negative Gaussian Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Standard Deviation Negative Gaussian Curvature with Large IBSI Phantom Image", 0.055, results["Curvature Feature::Standard Deviation Negative Gaussian Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Skewness Negative Gaussian Curvature with Large IBSI Phantom Image", -1.92, results["Curvature Feature::Skewness Negative Gaussian Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Minimum Minimum Curvature with Large IBSI Phantom Image", -2.19, results["Curvature Feature::Minimum Minimum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Maximum Minimum Curvature with Large IBSI Phantom Image", 0.35, results["Curvature Feature::Maximum Minimum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Mean Minimum Curvature with Large IBSI Phantom Image", -0.11, results["Curvature Feature::Mean Minimum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Standard Deviation Minimum Curvature with Large IBSI Phantom Image", 0.573, results["Curvature Feature::Standard Deviation Minimum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Skewness Minimum Curvature with Large IBSI Phantom Image", -2.742, results["Curvature Feature::Skewness Minimum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Mean Positive Minimum Curvature with Large IBSI Phantom Image", 0.161, results["Curvature Feature::Mean Positive Minimum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Standard Deviation Positive Minimum Curvature with Large IBSI Phantom Image", 0.165, results["Curvature Feature::Standard Deviation Positive Minimum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Skewness Positive Minimum Curvature with Large IBSI Phantom Image", 0.108, results["Curvature Feature::Skewness Positive Minimum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Mean Negative Minimum Curvature with Large IBSI Phantom Image", -0.42, results["Curvature Feature::Mean Negative Minimum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Standard Deviation Negative Minimum Curvature with Large IBSI Phantom Image", 0.733, results["Curvature Feature::Standard Deviation Negative Minimum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Skewness Negative Minimum Curvature with Large IBSI Phantom Image", -1.73, results["Curvature Feature::Skewness Negative Minimum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Minimum Maximum Curvature with Large IBSI Phantom Image", -0.83, results["Curvature Feature::Minimum Maximum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Maximum Maximum Curvature with Large IBSI Phantom Image", 0.79, results["Curvature Feature::Maximum Maximum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Mean Maximum Curvature with Large IBSI Phantom Image", 0.30, results["Curvature Feature::Mean Maximum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Standard Deviation Maximum Curvature with Large IBSI Phantom Image", 0.369, results["Curvature Feature::Standard Deviation Maximum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Skewness Maximum Curvature with Large IBSI Phantom Image", -1.617, results["Curvature Feature::Skewness Maximum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Mean Positive Maximum Curvature with Large IBSI Phantom Image", 0.419, results["Curvature Feature::Mean Positive Maximum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Standard Deviation Positive Maximum Curvature with Large IBSI Phantom Image", 0.217, results["Curvature Feature::Standard Deviation Positive Maximum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Skewness Positive Maximum Curvature with Large IBSI Phantom Image", -0.958, results["Curvature Feature::Skewness Positive Maximum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Mean Negative Maximum Curvature with Large IBSI Phantom Image", -0.44, results["Curvature Feature::Mean Negative Maximum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Standard Deviation Negative Maximum Curvature with Large IBSI Phantom Image", 0.399, results["Curvature Feature::Standard Deviation Negative Maximum Curvature"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Curvature Feature::Skewness Negative Maximum Curvature with Large IBSI Phantom Image", 0.109, results["Curvature Feature::Skewness Negative Maximum Curvature"], 0.01); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFCurvatureStatistic ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderHistogramStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderHistogramStatisticsTest.cpp index ee9d7c90d6..92a79b47c9 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderHistogramStatisticsTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderHistogramStatisticsTest.cpp @@ -1,123 +1,123 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFFirstOrderHistogramStatisticsTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFFirstOrderHistogramStatisticsTestSuite); MITK_TEST(ImageDescription_PhantomTest); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest() { mitk::GIFFirstOrderHistogramStatistics::Pointer featureCalculator = mitk::GIFFirstOrderHistogramStatistics::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 46 features.", std::size_t(46), featureList.size()); // These values are obtained by a run of the filter. // The might be wrong! CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mean Value should be 2.15 with Large IBSI Phantom Image", 2.15, results["First Order Histogram::Mean Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Variance Value should be 3.05 with Large IBSI Phantom Image", 3.05, results["First Order Histogram::Variance Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Skewness Value should be 1.08 with Large IBSI Phantom Image", 1.08, results["First Order Histogram::Skewness Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Excess Kurtosis Value should be -0.355 with Large IBSI Phantom Image", -0.355, results["First Order Histogram::Excess Kurtosis Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Median Value should be 1 with Large IBSI Phantom Image", 1.0, results["First Order Histogram::Median Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Minimum Value should be 1 with Large IBSI Phantom Image", 1, results["First Order Histogram::Minimum Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Percentile 10 Value should be 0.648 with Large IBSI Phantom Image", 0.648, results["First Order Histogram::Percentile 10 Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Percentile 90 Value should be 4.475 with Large IBSI Phantom Image", 4.475, results["First Order Histogram::Percentile 90 Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Maximum Value should be 6 with Large IBSI Phantom Image", 6, results["First Order Histogram::Maximum Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mode Value should be 1 with Large IBSI Phantom Image", 1, results["First Order Histogram::Mode Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Interquantile Range Value should be 2.9 with Large IBSI Phantom Image", 2.911, results["First Order Histogram::Interquantile Range Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Range Value should be 5 with Large IBSI Phantom Image", 5, results["First Order Histogram::Range Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mean Absolute Deviation Value should be 1.55 with Large IBSI Phantom Image", 1.55, results["First Order Histogram::Mean Absolute Deviation Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Robust Mean Absolute Deviation Value should be 1.11 with Large IBSI Phantom Image", 1.11, results["First Order Histogram::Robust Mean Absolute Deviation Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Median Absolute Deviation Value should be 1.14 with Large IBSI Phantom Image", 1.14, results["First Order Histogram::Median Absolute Deviation Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Coefficient of Variation Value should be 0.812 with Large IBSI Phantom Image", 0.812, results["First Order Histogram::Coefficient of Variation Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Quantile coefficient of Dispersion Value should be 0.626 with Large IBSI Phantom Image", 0.626, results["First Order Histogram::Quantile coefficient of Dispersion Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Entropy Value should be 1.27 with Large IBSI Phantom Image", 1.27, results["First Order Histogram::Entropy Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Uniformity Value should be 0.512 with Large IBSI Phantom Image", 0.512, results["First Order Histogram::Uniformity Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Robust Mean Index should be 0.746 with Large IBSI Phantom Image", 0.746, results["First Order Histogram::Robust Mean Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Robust Mean Value should be 1.746 with Large IBSI Phantom Image", 1.746, results["First Order Histogram::Robust Mean Value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Number of Bins should be 6", 6, results["First Order Histogram::Number of Bins"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Bin Size should be 1", 1, results["First Order Histogram::Bin Size"], 0.01); // These values are taken from the IBSI Initiative to ensure compatibility // The values are given with an accuracy of 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mean Index should be 2.15 with Large IBSI Phantom Image", 2.15, results["First Order Histogram::Mean Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Variance Index should be 3.05 with Large IBSI Phantom Image", 3.05, results["First Order Histogram::Variance Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Skewness Index should be 1.08 with Large IBSI Phantom Image", 1.08, results["First Order Histogram::Skewness Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Excess Kurtosis Index should be -0.355 with Large IBSI Phantom Image", -0.355, results["First Order Histogram::Excess Kurtosis Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Median Index should be 1 with Large IBSI Phantom Image", 1.0, results["First Order Histogram::Median Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Minimum Index should be 1 with Large IBSI Phantom Image", 1, results["First Order Histogram::Minimum Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Percentile 10 Index should be 1 with Large IBSI Phantom Image", 1, results["First Order Histogram::Percentile 10 Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Percentile 90 Index should be 2.15 with Large IBSI Phantom Image", 4, results["First Order Histogram::Percentile 90 Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Maximum Index should be 6 with Large IBSI Phantom Image", 6, results["First Order Histogram::Maximum Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mode Index should be 1 with Large IBSI Phantom Image", 1, results["First Order Histogram::Mode Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Interquantile Range Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Range Index should be 5 with Large IBSI Phantom Image", 5, results["First Order Histogram::Range Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mean Absolute Deviation Index should be 3 with Large IBSI Phantom Image", 1.55, results["First Order Histogram::Mean Absolute Deviation Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Robust Mean Absolute Deviation Index should be 1.11 with Large IBSI Phantom Image", 1.11, results["First Order Histogram::Robust Mean Absolute Deviation Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Median Absolute Deviation Index should be 1.14 with Large IBSI Phantom Image", 1.14, results["First Order Histogram::Median Absolute Deviation Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Coefficient of Variation Index should be 0.812 with Large IBSI Phantom Image", 0.812, results["First Order Histogram::Coefficient of Variation Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Quantile coefficient of Dispersion Index should be 0.6 with Large IBSI Phantom Image", 0.6, results["First Order Histogram::Quantile coefficient of Dispersion Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Entropy Index should be 1.27 with Large IBSI Phantom Image", 1.27, results["First Order Histogram::Entropy Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Uniformity Index should be 0.512 with Large IBSI Phantom Image", 0.512, results["First Order Histogram::Uniformity Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Maximum Gradient should be 8 with Large IBSI Phantom Image", 8, results["First Order Histogram::Maximum Gradient"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Maximum Gradient Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Maximum Gradient Index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Minimum Gradient should be -50 with Large IBSI Phantom Image", -50, results["First Order Histogram::Minimum Gradient"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Minimum Gradient Index should be 3 with Large IBSI Phantom Image", 1, results["First Order Histogram::Minimum Gradient Index"], 0.01); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderHistogramStatistics ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp index 4e224d7330..b6c31c2ee1 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp @@ -1,109 +1,109 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFFirstOrderNumericStatisticsTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFFirstOrderNumericStatisticsTestSuite); MITK_TEST(ImageDescription_PhantomTest); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest() { mitk::GIFFirstOrderNumericStatistics::Pointer featureCalculator = mitk::GIFFirstOrderNumericStatistics::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 50 features.", std::size_t(50), featureList.size()); // These values are obtained by a run of the filter. // The might be wrong! CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mean with Large IBSI Phantom Image", 2.15, results["First Order Numeric::Mean"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Variance with Large IBSI Phantom Image", 3.05, results["First Order Numeric::Variance"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Skewness with Large IBSI Phantom Image", 1.08, results["First Order Numeric::Skewness"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Excess kurtosis with Large IBSI Phantom Image", -0.355, results["First Order Numeric::Excess kurtosis"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Median with Large IBSI Phantom Image", 1, results["First Order Numeric::Median"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Minimum with Large IBSI Phantom Image", 1, results["First Order Numeric::Minimum"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::10th Percentile with Large IBSI Phantom Image", 1, results["First Order Numeric::10th Percentile"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::90th Percentile with Large IBSI Phantom Image", 4, results["First Order Numeric::90th Percentile"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Maximum with Large IBSI Phantom Image", 6, results["First Order Numeric::Maximum"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Interquantile range with Large IBSI Phantom Image", 3, results["First Order Numeric::Interquantile range"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Range with Large IBSI Phantom Image", 5, results["First Order Numeric::Range"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mean absolute deviation with Large IBSI Phantom Image", 1.55, results["First Order Numeric::Mean absolute deviation"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust mean absolute deviation with Large IBSI Phantom Image", 1.11, results["First Order Numeric::Robust mean absolute deviation"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Median absolute deviation with Large IBSI Phantom Image", 1.15, results["First Order Numeric::Median absolute deviation"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Coefficient of variation with Large IBSI Phantom Image", 0.812, results["First Order Numeric::Coefficient of variation"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Quantile coefficient of dispersion with Large IBSI Phantom Image", 0.6, results["First Order Numeric::Quantile coefficient of dispersion"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Energy with Large IBSI Phantom Image", 567, results["First Order Numeric::Energy"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Root mean square with Large IBSI Phantom Image", 2.77, results["First Order Numeric::Root mean square"], 0.01); // These values are taken from the IBSI Initiative to ensure compatibility // The values are given with an accuracy of 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Standard Deviation with Large IBSI Phantom Image", 1.74513, results["First Order Numeric::Standard Deviation"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Kurtosis with Large IBSI Phantom Image", 2.64538, results["First Order Numeric::Kurtosis"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust mean with Large IBSI Phantom Image", 1.74627, results["First Order Numeric::Robust mean"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust variance with Large IBSI Phantom Image", 1.65204, results["First Order Numeric::Robust variance"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Covered image intensity range with Large IBSI Phantom Image", 0.83333, results["First Order Numeric::Covered image intensity range"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode index with Large IBSI Phantom Image",0 , results["First Order Numeric::Mode index"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode value with Large IBSI Phantom Image", 1, results["First Order Numeric::Mode value"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode probability with Large IBSI Phantom Image", 0.675676, results["First Order Numeric::Mode probability"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Entropy with Large IBSI Phantom Image", -1.26561, results["First Order Numeric::Entropy"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Uniformtiy with Large IBSI Phantom Image", 0.512418, results["First Order Numeric::Uniformtiy"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Number of voxels with Large IBSI Phantom Image", 74 , results["First Order Numeric::Number of voxels"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Sum of voxels with Large IBSI Phantom Image", 159, results["First Order Numeric::Sum of voxels"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Voxel space with Large IBSI Phantom Image", 8, results["First Order Numeric::Voxel space"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Voxel volume with Large IBSI Phantom Image", 8, results["First Order Numeric::Voxel volume"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Image Dimension with Large IBSI Phantom Image", 3, results["First Order Numeric::Image Dimension"], 0.01); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderNumericStatistics ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp index 0378a5d88d..c6683a7255 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp @@ -1,108 +1,108 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFFirstOrderStatisticsTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFFirstOrderStatisticsTestSuite); MITK_TEST(ImageDescription_PhantomTest); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest() { mitk::GIFFirstOrderStatistics::Pointer featureCalculator = mitk::GIFFirstOrderStatistics::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 50 features.", std::size_t(50), featureList.size()); // These values are obtained by a run of the filter. // The might be wrong! // These values are taken from the IBSI Initiative to ensure compatibility // The values are given with an accuracy of 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mean with Large IBSI Phantom Image", 2.15, results["First Order::Mean"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Unbiased Variance with Large IBSI Phantom Image", 3.09, results["First Order::Unbiased Variance"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Biased Variance with Large IBSI Phantom Image", 3.05, results["First Order::Biased Variance"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Skewness with Large IBSI Phantom Image", 1.08, results["First Order::Skewness"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Kurtosis with Large IBSI Phantom Image", 2.65, results["First Order::Kurtosis"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Median with Large IBSI Phantom Image", 1, results["First Order::Median"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Minimum with Large IBSI Phantom Image", 1, results["First Order::Minimum"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Maximum with Large IBSI Phantom Image", 6, results["First Order::Maximum"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Range with Large IBSI Phantom Image", 5, results["First Order::Range"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mean Absolute Deviation with Large IBSI Phantom Image", 1.55, results["First Order::Mean Absolute Deviation"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Robust Mean Absolute Deviation with Large IBSI Phantom Image", 1.11, results["First Order::Robust Mean Absolute Deviation"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Median Absolute Deviation with Large IBSI Phantom Image", 1.15, results["First Order::Median Absolute Deviation"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Coefficient of variation with Large IBSI Phantom Image", 0.812, results["First Order::Coefficient Of Variation"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Quantile coefficient of dispersion with Large IBSI Phantom Image", 0.625, results["First Order::Quantile Coefficient Of Dispersion"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Energy with Large IBSI Phantom Image", 567, results["First Order::Energy"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Root mean square with Large IBSI Phantom Image", 2.77, results["First Order::Root Mean Square"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Entropy with Large IBSI Phantom Image", 1.26561, results["First Order::Entropy"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Excess Kurtosis with Large IBSI Phantom Image", -0.35462, results["First Order::Excess Kurtosis"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Covered image intensity range with Large IBSI Phantom Image", 0.5555555, results["First Order::Covered Image Intensity Range"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Sum of voxels with Large IBSI Phantom Image", 159, results["First Order::Sum"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mode with Large IBSI Phantom Image", 1, results["First Order::Mode"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mode Probability with Large IBSI Phantom Image", 50, results["First Order::Mode Probability"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Unbiased Standard deviation with Large IBSI Phantom Image", 1.757, results["First Order::Unbiased Standard deviation"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Biased Standard deviation with Large IBSI Phantom Image", 1.74627, results["First Order::Biased Standard deviation"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Robust mean with Large IBSI Phantom Image", 1.74627, results["First Order::Robust Mean"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Number Of Voxels with Large IBSI Phantom Image", 74, results["First Order::Number Of Voxels"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::10th Percentile with Large IBSI Phantom Image", 0.648, results["First Order::10th Percentile"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::90th Percentile with Large IBSI Phantom Image", 4.475, results["First Order::90th Percentile"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Interquantile Range with Large IBSI Phantom Image", 2.91125, results["First Order::Interquartile Range"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Voxel Space with Large IBSI Phantom Image", 8, results["First Order::Voxel Space"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Voxel Volume with Large IBSI Phantom Image", 8, results["First Order::Voxel Volume"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Image Dimension with Large IBSI Phantom Image", 3, results["First Order::Image Dimension"], 0.01); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderStatistics ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFGreyLevelDistanceZoneTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFGreyLevelDistanceZoneTest.cpp index 682a7cbdab..b197e1405f 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFGreyLevelDistanceZoneTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFGreyLevelDistanceZoneTest.cpp @@ -1,143 +1,143 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFGreyLevelDistanceZoneTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFGreyLevelDistanceZoneTestSuite ); MITK_TEST(ImageDescription_PhantomTest_3D); MITK_TEST(ImageDescription_PhantomTest_2D); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest_3D() { mitk::GIFGreyLevelDistanceZone::Pointer featureCalculator = mitk::GIFGreyLevelDistanceZone::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[valuePair.first.featureClass+"::"+valuePair.first.name] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 19 features.", std::size_t(19), featureList.size()); // These values are obtained with IBSI // Standard accuracy is 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Small Distance Emphasis with Large IBSI Phantom Image", 1, results["Grey Level Distance Zone::Small Distance Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Large Distance Emphasis with Large IBSI Phantom Image", 1, results["Grey Level Distance Zone::Large Distance Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Low Grey Level Emphasis with Large IBSI Phantom Image", 0.253, results["Grey Level Distance Zone::Low Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::High Grey Level Emphasis with Large IBSI Phantom Image", 15.6, results["Grey Level Distance Zone::High Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Small Distance Low Grey Level Emphasis with Large IBSI Phantom Image", 0.253, results["Grey Level Distance Zone::Small Distance Low Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Small Distance High Grey Level Emphasis with Large IBSI Phantom Image", 15.6, results["Grey Level Distance Zone::Small Distance High Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Large Distance Low Grey Level Emphasis with Large IBSI Phantom Image", 0.253, results["Grey Level Distance Zone::Large Distance Low Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Large Distance High Grey Level Emphasis with Large IBSI Phantom Image", 15.6, results["Grey Level Distance Zone::Large Distance High Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Grey Level Non-Uniformity with Large IBSI Phantom Image", 1.4, results["Grey Level Distance Zone::Grey Level Non-Uniformity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Grey Level Non-Uniformity Normalized with Large IBSI Phantom Image", 0.28, results["Grey Level Distance Zone::Grey Level Non-Uniformity Normalized"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Distance Size Non-Uniformity with Large IBSI Phantom Image", 5, results["Grey Level Distance Zone::Distance Size Non-Uniformity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Distance Size Non-Uniformity Normalized with Large IBSI Phantom Image", 1, results["Grey Level Distance Zone::Distance Size Non-Uniformity Normalized"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Zone Percentage with Large IBSI Phantom Image", 0.0676, results["Grey Level Distance Zone::Zone Percentage"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Grey Level Variance with Large IBSI Phantom Image", 2.64, results["Grey Level Distance Zone::Grey Level Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Zone Distance Variance with Large IBSI Phantom Image", 0, results["Grey Level Distance Zone::Zone Distance Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Zone Distance Entropy with Large IBSI Phantom Image", 1.92, results["Grey Level Distance Zone::Zone Distance Entropy"], 0.01); //CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone:: with Large IBSI Phantom Image", 0.045, results["Grey Level Distance Zone::"], 0.001); // These values are obtained by manually running the tool // Values might be wrong. CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Grey Level Mean with Large IBSI Phantom Image", 3.6, results["Grey Level Distance Zone::Grey Level Mean"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Zone Distance Mean with Large IBSI Phantom Image", 1, results["Grey Level Distance Zone::Zone Distance Mean"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone::Grey Level Entropy with Large IBSI Phantom Image", 1.92, results["Grey Level Distance Zone::Grey Level Entropy"], 0.01); } void ImageDescription_PhantomTest_2D() { mitk::GIFGreyLevelDistanceZone::Pointer featureCalculator = mitk::GIFGreyLevelDistanceZone::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeaturesSlicewise(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large, 2); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 114 features.", std::size_t(114), featureList.size()); // These values are obtained with IBSI // Standard accuracy is 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Small Distance Emphasis with Large IBSI Phantom Image", 0.946, results["SliceWise Mean Grey Level Distance Zone::Small Distance Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Large Distance Emphasis with Large IBSI Phantom Image", 1.21, results["SliceWise Mean Grey Level Distance Zone::Large Distance Emphasis"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Low Grey Level Emphasis with Large IBSI Phantom Image", 0.371, results["SliceWise Mean Grey Level Distance Zone::Low Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::High Grey Level Emphasis with Large IBSI Phantom Image", 16.4, results["SliceWise Mean Grey Level Distance Zone::High Grey Level Emphasis"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Small Distance Low Grey Level Emphasis with Large IBSI Phantom Image", 0.367, results["SliceWise Mean Grey Level Distance Zone::Small Distance Low Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Small Distance High Grey Level Emphasis with Large IBSI Phantom Image", 15.2, results["SliceWise Mean Grey Level Distance Zone::Small Distance High Grey Level Emphasis"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Large Distance Low Grey Level Emphasis with Large IBSI Phantom Image", 0.386, results["SliceWise Mean Grey Level Distance Zone::Large Distance Low Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Large Distance High Grey Level Emphasis with Large IBSI Phantom Image", 21.3, results["SliceWise Mean Grey Level Distance Zone::Large Distance High Grey Level Emphasis"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Grey Level Non-Uniformity with Large IBSI Phantom Image", 1.41, results["SliceWise Mean Grey Level Distance Zone::Grey Level Non-Uniformity"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Grey Level Non-Uniformity Normalized with Large IBSI Phantom Image", 0.323, results["SliceWise Mean Grey Level Distance Zone::Grey Level Non-Uniformity Normalized"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Distance Size Non-Uniformity with Large IBSI Phantom Image", 3.79, results["SliceWise Mean Grey Level Distance Zone::Distance Size Non-Uniformity"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Distance Size Non-Uniformity Normalized with Large IBSI Phantom Image", 0.898, results["SliceWise Mean Grey Level Distance Zone::Distance Size Non-Uniformity Normalized"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Zone Percentage with Large IBSI Phantom Image", 0.24, results["SliceWise Mean Grey Level Distance Zone::Zone Percentage"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Grey Level Variance with Large IBSI Phantom Image", 3.97, results["SliceWise Mean Grey Level Distance Zone::Grey Level Variance"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Zone Distance Variance with Large IBSI Phantom Image", 0.051, results["SliceWise Mean Grey Level Distance Zone::Zone Distance Variance"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Zone Distance Entropy with Large IBSI Phantom Image", 1.73, results["SliceWise Mean Grey Level Distance Zone::Zone Distance Entropy"], 0.01); //CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Distance Zone:: with Large IBSI Phantom Image", 0.045, results["Grey Level Distance Zone::"], 0.001); // These values are obtained by manually running the tool // Values might be wrong. CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Grey Level Mean with Large IBSI Phantom Image", 3.526, results["SliceWise Mean Grey Level Distance Zone::Grey Level Mean"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Zone Distance Mean with Large IBSI Phantom Image", 1.071, results["SliceWise Mean Grey Level Distance Zone::Zone Distance Mean"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Distance Zone::Grey Level Entropy with Large IBSI Phantom Image", 1.732, results["SliceWise Mean Grey Level Distance Zone::Grey Level Entropy"], 0.01); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFGreyLevelDistanceZone ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFGreyLevelSizeZoneTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFGreyLevelSizeZoneTest.cpp index 9d1b60874e..46adb4a03b 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFGreyLevelSizeZoneTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFGreyLevelSizeZoneTest.cpp @@ -1,141 +1,141 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFGreyLevelSizeZoneTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFGreyLevelSizeZoneTestSuite ); MITK_TEST(ImageDescription_PhantomTest_3D); MITK_TEST(ImageDescription_PhantomTest_2D); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest_3D() { mitk::GIFGreyLevelSizeZone::Pointer featureCalculator = mitk::GIFGreyLevelSizeZone::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 18 features.", std::size_t(18), featureList.size()); // These values are obtained with IBSI // Standard accuracy is 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Small Zone Emphasis with Large IBSI Phantom Image", 0.255, results["Grey Level Size Zone::Small Zone Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Large Zone Emphasis with Large IBSI Phantom Image", 550, results["Grey Level Size Zone::Large Zone Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Low Grey Level Emphasis with Large IBSI Phantom Image", 0.253, results["Grey Level Size Zone::Low Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::High Grey Level Emphasis with Large IBSI Phantom Image", 15.6, results["Grey Level Size Zone::High Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Small Zone Low Grey Level Emphasis with Large IBSI Phantom Image", 0.0256, results["Grey Level Size Zone::Small Zone Low Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Small Zone High Grey Level Emphasis with Large IBSI Phantom Image", 2.76, results["Grey Level Size Zone::Small Zone High Grey Level Emphasis"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Large Zone Low Grey Level Emphasis with Large IBSI Phantom Image", 503, results["Grey Level Size Zone::Large Zone Low Grey Level Emphasis"], 1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Large Zone High Grey Level Emphasis with Large IBSI Phantom Image", 1495, results["Grey Level Size Zone::Large Zone High Grey Level Emphasis"], 1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Grey Level Non-Uniformity with Large IBSI Phantom Image", 1.4, results["Grey Level Size Zone::Grey Level Non-Uniformity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Grey Level Non-Uniformity Normalized with Large IBSI Phantom Image", 0.28, results["Grey Level Size Zone::Grey Level Non-Uniformity Normalized"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Zone Size Non-Uniformity with Large IBSI Phantom Image", 1, results["Grey Level Size Zone::Zone Size Non-Uniformity"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Zone Size Non-Uniformity Normalized with Large IBSI Phantom Image", 0.2, results["Grey Level Size Zone::Zone Size Non-Uniformity Normalized"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Zone Percentage with Large IBSI Phantom Image", 0.0676, results["Grey Level Size Zone::Zone Percentage"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Grey Level Variance with Large IBSI Phantom Image", 2.64, results["Grey Level Size Zone::Grey Level Variance"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Zone Size Variance with Large IBSI Phantom Image", 331, results["Grey Level Size Zone::Zone Size Variance"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Zone Size Entropy with Large IBSI Phantom Image", 2.32, results["Grey Level Size Zone::Zone Size Entropy"], 0.01); //CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone:: with Large IBSI Phantom Image", 0.045, results["Grey Level Size Zone::"], 0.001); // These values are obtained by manually running the tool // Values might be wrong. CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Grey Level Mean with Large IBSI Phantom Image", 3.6, results["Grey Level Size Zone::Grey Level Mean"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Grey Level Size Zone::Zone Size Mean with Large IBSI Phantom Image", 14.8, results["Grey Level Size Zone::Zone Size Mean"], 0.001); } void ImageDescription_PhantomTest_2D() { mitk::GIFGreyLevelSizeZone::Pointer featureCalculator = mitk::GIFGreyLevelSizeZone::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeaturesSlicewise(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large, 2); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 108 features.", std::size_t(108), featureList.size()); // These values are obtained with IBSI // Standard accuracy is 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Small Zone Emphasis with Large IBSI Phantom Image", 0.363, results["SliceWise Mean Grey Level Size Zone::Small Zone Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Large Zone Emphasis with Large IBSI Phantom Image", 43.9, results["SliceWise Mean Grey Level Size Zone::Large Zone Emphasis"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Low Grey Level Emphasis with Large IBSI Phantom Image", 0.371, results["SliceWise Mean Grey Level Size Zone::Low Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::High Grey Level Emphasis with Large IBSI Phantom Image", 16.4, results["SliceWise Mean Grey Level Size Zone::High Grey Level Emphasis"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Small Zone Low Grey Level Emphasis with Large IBSI Phantom Image", 0.0259, results["SliceWise Mean Grey Level Size Zone::Small Zone Low Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Small Zone High Grey Level Emphasis with Large IBSI Phantom Image", 10.3, results["SliceWise Mean Grey Level Size Zone::Small Zone High Grey Level Emphasis"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Large Zone Low Grey Level Emphasis with Large IBSI Phantom Image", 40.4, results["SliceWise Mean Grey Level Size Zone::Large Zone Low Grey Level Emphasis"], 1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Large Zone High Grey Level Emphasis with Large IBSI Phantom Image", 113, results["SliceWise Mean Grey Level Size Zone::Large Zone High Grey Level Emphasis"], 1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Grey Level Non-Uniformity with Large IBSI Phantom Image", 1.41, results["SliceWise Mean Grey Level Size Zone::Grey Level Non-Uniformity"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Grey Level Non-Uniformity Normalized with Large IBSI Phantom Image", 0.323, results["SliceWise Mean Grey Level Size Zone::Grey Level Non-Uniformity Normalized"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Zone Size Non-Uniformity with Large IBSI Phantom Image", 1.49, results["SliceWise Mean Grey Level Size Zone::Zone Size Non-Uniformity"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Zone Size Non-Uniformity Normalized with Large IBSI Phantom Image", 0.333, results["SliceWise Mean Grey Level Size Zone::Zone Size Non-Uniformity Normalized"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Zone Percentage with Large IBSI Phantom Image", 0.24, results["SliceWise Mean Grey Level Size Zone::Zone Percentage"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Grey Level Variance with Large IBSI Phantom Image", 3.97, results["SliceWise Mean Grey Level Size Zone::Grey Level Variance"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Zone Size Variance with Large IBSI Phantom Image", 21, results["SliceWise Mean Grey Level Size Zone::Zone Size Variance"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Zone Size Entropy with Large IBSI Phantom Image", 1.93, results["SliceWise Mean Grey Level Size Zone::Zone Size Entropy"], 0.01); //CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone:: with Large IBSI Phantom Image", 0.045, results["SliceWise Mean Grey Level Size Zone::"], 0.001); // These values are obtained by manually running the tool // Values might be wrong. CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Grey Level Mean with Large IBSI Phantom Image", 3.526, results["SliceWise Mean Grey Level Size Zone::Grey Level Mean"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Grey Level Size Zone::Zone Size Mean with Large IBSI Phantom Image", 4.59524, results["SliceWise Mean Grey Level Size Zone::Zone Size Mean"], 0.001); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFGreyLevelSizeZone ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFImageDescriptionFeaturesTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFImageDescriptionFeaturesTest.cpp index 5b74aaa12b..74aa3d40c5 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFImageDescriptionFeaturesTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFImageDescriptionFeaturesTest.cpp @@ -1,91 +1,91 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFImageDescriptionFeaturesTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFImageDescriptionFeaturesTestSuite ); MITK_TEST(ImageDescription_PhantomTest); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest() { mitk::GIFImageDescriptionFeatures::Pointer featureCalculator = mitk::GIFImageDescriptionFeatures::New(); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 22 features.", std::size_t(22), featureList.size()); // These values are calculated obtained by using this filter. Changes, especially with mean values could happen. CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Image Dimension X should be 7 with Large IBSI Phantom Image", int(7), int(results["Diagnostic::Image Dimension X"])); CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Image Dimension Y should be 6 with Large IBSI Phantom Image", int(6), int(results["Diagnostic::Image Dimension Y"])); CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Image Dimension Z should be 6 with Large IBSI Phantom Image", int(6), int(results["Diagnostic::Image Dimension Z"])); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Spacing X should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Image Spacing X"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Spacing Y should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Image Spacing Y"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Spacing Z should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Image Spacing Z"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Mean intensity should be 0.6865 with Large IBSI Phantom Image", 0.686508, results["Diagnostic::Image Mean intensity"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Minimum intensity should be 0 with Large IBSI Phantom Image", 0, results["Diagnostic::Image Minimum intensity"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Maximum intensity should be 9 with Large IBSI Phantom Image", 9, results["Diagnostic::Image Maximum intensity"], 0.0001); CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask Dimension X should be 7 with Large IBSI Phantom Image", int(7), int(results["Diagnostic::Mask Dimension X"])); CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask Dimension Y should be 6 with Large IBSI Phantom Image", int(6), int(results["Diagnostic::Mask Dimension Y"])); CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask Dimension Z should be 6 with Large IBSI Phantom Image", int(6), int(results["Diagnostic::Mask Dimension Z"])); CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask bounding box X should be 5 with Large IBSI Phantom Image", int(5), int(results["Diagnostic::Mask bounding box X"])); CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask bounding box Y should be 4 with Large IBSI Phantom Image", int(4), int(results["Diagnostic::Mask bounding box Y"])); CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask bounding box Z should be 4 with Large IBSI Phantom Image", int(4), int(results["Diagnostic::Mask bounding box Z"])); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Spacing X should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Mask Spacing X"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Spacing Y should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Mask Spacing Y"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Spacing Z should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Mask Spacing Z"], 0.0001); CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask Voxel Count should be 74 with Large IBSI Phantom Image", int(74), int(results["Diagnostic::Mask Voxel Count"])); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Mean intensity should be 2.14865 with Large IBSI Phantom Image", 2.14865, results["Diagnostic::Mask Mean intensity"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Minimum intensity should be 1 with Large IBSI Phantom Image", 1, results["Diagnostic::Mask Minimum intensity"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Maximum intensity should be 6 with Large IBSI Phantom Image", 6, results["Diagnostic::Mask Maximum intensity"], 0.0001); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFImageDescriptionFeatures ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFIntensityVolumeHistogramTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFIntensityVolumeHistogramTest.cpp index 90c7d655b6..d8c238b798 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFIntensityVolumeHistogramTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFIntensityVolumeHistogramTest.cpp @@ -1,155 +1,155 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFIntensityVolumeHistogramTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE( mitkGIFIntensityVolumeHistogramTestSuite); MITK_TEST(ImageDescription_PhantomTest_Large); MITK_TEST(ImageDescription_PhantomTest_Small); MITK_TEST(ImageDescription_PhantomTest_2D); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest_Large() { mitk::GIFIntensityVolumeHistogramFeatures::Pointer featureCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 7 features.", std::size_t(7), featureList.size()); // These values are obtained in cooperation with IBSI // Reported with an accuracy of 0.1 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.3243, results["Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.09459, results["Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 5, results["Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 2, results["Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.22973, results["Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 3, results["Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.32027, results["Intensity Volume Histogram::Area under IVH curve"], 0.001); } void ImageDescription_PhantomTest_Small() { mitk::GIFIntensityVolumeHistogramFeatures::Pointer featureCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Small, m_IBSI_Phantom_Mask_Small); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 7 features.", std::size_t(7), featureList.size()); // These values are obtained in cooperation with IBSI // Reported with an accuracy of 0.1 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.3243, results["Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.09459, results["Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 5, results["Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 2, results["Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.22973, results["Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 3, results["Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.32027, results["Intensity Volume Histogram::Area under IVH curve"], 0.001); } void ImageDescription_PhantomTest_2D() { mitk::GIFIntensityVolumeHistogramFeatures::Pointer featureCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeaturesSlicewise(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large, 2); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 42 features.", std::size_t(42), featureList.size()); // These values are obtained by calculating on the features // Could be wrong! CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.31539, results["SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.0924106, results["SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 6, results["SliceWise Mean Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 2, results["SliceWise Mean Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.222979, results["SliceWise Mean Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 4, results["SliceWise Mean Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.314325, results["SliceWise Mean Intensity Volume Histogram::Area under IVH curve"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.0248178, results["SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.00149203, results["SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 1, results["SliceWise Var. Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 0, results["SliceWise Var. Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.01414, results["SliceWise Var. Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 1, results["SliceWise Var. Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.0110923, results["SliceWise Var. Intensity Volume Histogram::Area under IVH curve"], 0.001); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFIntensityVolumeHistogram) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFLocalIntensityTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFLocalIntensityTest.cpp index 4a6305526a..25df1f8a28 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFLocalIntensityTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFLocalIntensityTest.cpp @@ -1,110 +1,110 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFLocalIntensityTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFLocalIntensityTestSuite); MITK_TEST(ImageDescription_PhantomTest_Small); MITK_TEST(ImageDescription_PhantomTest_Large); MITK_TEST(ImageDescription_PhantomTest_Large_RangeChanged); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest_Small() { mitk::GIFLocalIntensity::Pointer featureCalculator = mitk::GIFLocalIntensity::New(); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Small, m_IBSI_Phantom_Mask_Small); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 2 features.", std::size_t(2), featureList.size()); // These values are obtained in cooperation with IBSI // Reported with an accuracy of 0.1 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Local Intensity::Local Intensity Peak with Large IBSI Phantom Image", 2.6, results["Local Intensity::2. Local Intensity Peak"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Local Intensity::Global Intensity Peak with Large IBSI Phantom Image", 3.1, results["Local Intensity::2. Global Intensity Peak"], 0.1); } void ImageDescription_PhantomTest_Large() { mitk::GIFLocalIntensity::Pointer featureCalculator = mitk::GIFLocalIntensity::New(); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 2 features.", std::size_t(2), featureList.size()); // These values are obtained by running the tool // They might be wrong CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Local Intensity::Local Intensity Peak with Large IBSI Phantom Image", 1.43, results["Local Intensity::2. Local Intensity Peak"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Local Intensity::Global Intensity Peak with Large IBSI Phantom Image", 1.43, results["Local Intensity::2. Global Intensity Peak"], 0.01); } void ImageDescription_PhantomTest_Large_RangeChanged() { mitk::GIFLocalIntensity::Pointer featureCalculator = mitk::GIFLocalIntensity::New(); featureCalculator->SetRange(1); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 2 features.", std::size_t(2), featureList.size()); // These values are obtained by running the tool // They might be wrong CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Local Intensity::Local Intensity Peak with Large IBSI Phantom Image", 6, results["Local Intensity::2. Local Intensity Peak"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Local Intensity::Global Intensity Peak with Large IBSI Phantom Image", 6, results["Local Intensity::2. Global Intensity Peak"], 0.01); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFLocalIntensity ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFNeighbourhoodGreyToneDifferenceFeaturesTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFNeighbourhoodGreyToneDifferenceFeaturesTest.cpp index 5de9f83d0f..ff0c33fce9 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFNeighbourhoodGreyToneDifferenceFeaturesTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFNeighbourhoodGreyToneDifferenceFeaturesTest.cpp @@ -1,107 +1,107 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFNeighbourhoodGreyToneDifferenceFeaturesTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFNeighbourhoodGreyToneDifferenceFeaturesTestSuite); MITK_TEST(ImageDescription_PhantomTest_3D); MITK_TEST(ImageDescription_PhantomTest_2D); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest_3D() { mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::Pointer featureCalculator = mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 5 features.", std::size_t(5), featureList.size()); // These values are obtained with IBSI // Standard accuracy is 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbourhood Grey Tone Difference::Coarsness with Large IBSI Phantom Image", 0.0296, results["Neighbourhood Grey Tone Difference::Coarsness"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbourhood Grey Tone Difference::Contrast with Large IBSI Phantom Image", 0.584, results["Neighbourhood Grey Tone Difference::Contrast"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbourhood Grey Tone Difference::Busyness with Large IBSI Phantom Image", 6.54, results["Neighbourhood Grey Tone Difference::Busyness"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbourhood Grey Tone Difference::Complexity with Large IBSI Phantom Image", 13.5, results["Neighbourhood Grey Tone Difference::Complexity"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbourhood Grey Tone Difference::Strength with Large IBSI Phantom Image", 0.763, results["Neighbourhood Grey Tone Difference::Strength"], 0.01); } void ImageDescription_PhantomTest_2D() { mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::Pointer featureCalculator = mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeaturesSlicewise(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large, 2); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 30 features.", std::size_t(30), featureList.size()); // These values are obtained with IBSI // Standard accuracy is 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbourhood Grey Tone Difference::Coarsness with Large IBSI Phantom Image", 0.121, results["SliceWise Mean Neighbourhood Grey Tone Difference::Coarsness"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbourhood Grey Tone Difference::Contrast with Large IBSI Phantom Image", 0.925, results["SliceWise Mean Neighbourhood Grey Tone Difference::Contrast"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbourhood Grey Tone Difference::Busyness with Large IBSI Phantom Image", 2.99, results["SliceWise Mean Neighbourhood Grey Tone Difference::Busyness"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbourhood Grey Tone Difference::Complexity with Large IBSI Phantom Image", 10.4, results["SliceWise Mean Neighbourhood Grey Tone Difference::Complexity"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbourhood Grey Tone Difference::Strength with Large IBSI Phantom Image", 2.88, results["SliceWise Mean Neighbourhood Grey Tone Difference::Strength"], 0.01); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFNeighbourhoodGreyToneDifferenceFeatures ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFNeighbouringGreyLevelDependenceFeatureTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFNeighbouringGreyLevelDependenceFeatureTest.cpp index 8304167464..989fb21ca4 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFNeighbouringGreyLevelDependenceFeatureTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFNeighbouringGreyLevelDependenceFeatureTest.cpp @@ -1,151 +1,151 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFNeighbouringGreyLevelDependenceFeatureTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFNeighbouringGreyLevelDependenceFeatureTestSuite ); MITK_TEST(ImageDescription_PhantomTest_3D); MITK_TEST(ImageDescription_PhantomTest_2D); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest_3D() { mitk::GIFNeighbouringGreyLevelDependenceFeature::Pointer featureCalculator = mitk::GIFNeighbouringGreyLevelDependenceFeature::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 24 features.", std::size_t(24), featureList.size()); // These values are obtained with IBSI // Standard accuracy is 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Low Dependence Emphasis with Large IBSI Phantom Image", 0.045, results["Neighbouring Grey Level Dependence::Low Dependence Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::High Dependence Emphasis with Large IBSI Phantom Image", 109, results["Neighbouring Grey Level Dependence::High Dependence Emphasis"], 1.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Low Grey Level Count Emphasis with Large IBSI Phantom Image", 0.693, results["Neighbouring Grey Level Dependence::Low Grey Level Count Emphasis"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::High Grey Level Count Emphasis with Large IBSI Phantom Image", 7.66, results["Neighbouring Grey Level Dependence::High Grey Level Count Emphasis"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Low Dependence Low Grey Level Emphasis with Large IBSI Phantom Image", 0.00963, results["Neighbouring Grey Level Dependence::Low Dependence Low Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Low Dependence High Grey Level Emphasis with Large IBSI Phantom Image", 0.736, results["Neighbouring Grey Level Dependence::Low Dependence High Grey Level Emphasis"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::High Dependence Low Grey Level Emphasis with Large IBSI Phantom Image", 102, results["Neighbouring Grey Level Dependence::High Dependence Low Grey Level Emphasis"], 1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::High Dependence High Grey Level Emphasis with Large IBSI Phantom Image", 235, results["Neighbouring Grey Level Dependence::High Dependence High Grey Level Emphasis"], 1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Grey Level Non-Uniformity with Large IBSI Phantom Image", 37.9, results["Neighbouring Grey Level Dependence::Grey Level Non-Uniformity"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Grey Level Non-Uniformity Normalised with Large IBSI Phantom Image", 0.512, results["Neighbouring Grey Level Dependence::Grey Level Non-Uniformity Normalised"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Dependence Count Non-Uniformity with Large IBSI Phantom Image", 4.86, results["Neighbouring Grey Level Dependence::Dependence Count Non-Uniformity"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Dependence Count Non-Uniformity Normalised with Large IBSI Phantom Image", 0.0657, results["Neighbouring Grey Level Dependence::Dependence Count Non-Uniformity Normalised"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Dependence Count Percentage with Large IBSI Phantom Image", 1, results["Neighbouring Grey Level Dependence::Dependence Count Percentage"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Grey Level Variance with Large IBSI Phantom Image", 3.05, results["Neighbouring Grey Level Dependence::Grey Level Variance"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Dependence Count Variance with Large IBSI Phantom Image", 22.1, results["Neighbouring Grey Level Dependence::Dependence Count Variance"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Dependence Count Entropy with Large IBSI Phantom Image", 4.4, results["Neighbouring Grey Level Dependence::Dependence Count Entropy"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Dependence Count Energy with Large IBSI Phantom Image", 0.0533, results["Neighbouring Grey Level Dependence::Dependence Count Energy"], 0.01); // These values are obtained by manually running the tool // Values might be wrong. CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Grey Level Mean with Large IBSI Phantom Image", 2.15, results["Neighbouring Grey Level Dependence::Grey Level Mean"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Dependence Count Mean with Large IBSI Phantom Image", 9.32, results["Neighbouring Grey Level Dependence::Dependence Count Mean"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Expected Neighbourhood Size with Large IBSI Phantom Image", 26, results["Neighbouring Grey Level Dependence::Expected Neighbourhood Size"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Average Neighbourhood Size with Large IBSI Phantom Image", 14.24, results["Neighbouring Grey Level Dependence::Average Neighbourhood Size"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Average Incomplete Neighbourhood Size with Large IBSI Phantom Image", 14.24, results["Neighbouring Grey Level Dependence::Average Incomplete Neighbourhood Size"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Percentage of complete Neighbourhoods with Large IBSI Phantom Image", 0, results["Neighbouring Grey Level Dependence::Percentage of complete Neighbourhoods"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Neighbouring Grey Level Dependence::Percentage of Dependence Neighbour Voxels with Large IBSI Phantom Image", 0.584, results["Neighbouring Grey Level Dependence::Percentage of Dependence Neighbour Voxels"], 0.01); } void ImageDescription_PhantomTest_2D() { mitk::GIFNeighbouringGreyLevelDependenceFeature::Pointer featureCalculator = mitk::GIFNeighbouringGreyLevelDependenceFeature::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeaturesSlicewise(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large, 2); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 144 features.", std::size_t(144), featureList.size()); // These values are obtained with IBSI // Standard accuracy is 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Low Dependence Emphasis with Large IBSI Phantom Image", 0.158, results["SliceWise Mean Neighbouring Grey Level Dependence::Low Dependence Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::High Dependence Emphasis with Large IBSI Phantom Image", 19.2, results["SliceWise Mean Neighbouring Grey Level Dependence::High Dependence Emphasis"], 1.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Low Grey Level Count Emphasis with Large IBSI Phantom Image", 0.702, results["SliceWise Mean Neighbouring Grey Level Dependence::Low Grey Level Count Emphasis"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::High Grey Level Count Emphasis with Large IBSI Phantom Image", 7.49, results["SliceWise Mean Neighbouring Grey Level Dependence::High Grey Level Count Emphasis"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Low Dependence Low Grey Level Emphasis with Large IBSI Phantom Image", 0.0473, results["SliceWise Mean Neighbouring Grey Level Dependence::Low Dependence Low Grey Level Emphasis"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Low Dependence High Grey Level Emphasis with Large IBSI Phantom Image", 3.06, results["SliceWise Mean Neighbouring Grey Level Dependence::Low Dependence High Grey Level Emphasis"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::High Dependence Low Grey Level Emphasis with Large IBSI Phantom Image", 17.6, results["SliceWise Mean Neighbouring Grey Level Dependence::High Dependence Low Grey Level Emphasis"], 1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::High Dependence High Grey Level Emphasis with Large IBSI Phantom Image", 49.5, results["SliceWise Mean Neighbouring Grey Level Dependence::High Dependence High Grey Level Emphasis"], 1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Grey Level Non-Uniformity with Large IBSI Phantom Image", 10.2, results["SliceWise Mean Neighbouring Grey Level Dependence::Grey Level Non-Uniformity"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Grey Level Non-Uniformity Normalised with Large IBSI Phantom Image", 0.562, results["SliceWise Mean Neighbouring Grey Level Dependence::Grey Level Non-Uniformity Normalised"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Non-Uniformity with Large IBSI Phantom Image", 3.96, results["SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Non-Uniformity"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Non-Uniformity Normalised with Large IBSI Phantom Image", 0.212, results["SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Non-Uniformity Normalised"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Percentage with Large IBSI Phantom Image", 1, results["SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Percentage"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Grey Level Variance with Large IBSI Phantom Image", 2.7, results["SliceWise Mean Neighbouring Grey Level Dependence::Grey Level Variance"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Variance with Large IBSI Phantom Image", 2.73, results["SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Variance"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Entropy with Large IBSI Phantom Image", 2.71, results["SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Entropy"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Energy with Large IBSI Phantom Image", 0.17, results["SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Energy"], 0.01); // These values are obtained by manually running the tool // Values might be wrong. CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Grey Level Mean with Large IBSI Phantom Image", 2.12, results["SliceWise Mean Neighbouring Grey Level Dependence::Grey Level Mean"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Mean with Large IBSI Phantom Image", 3.98, results["SliceWise Mean Neighbouring Grey Level Dependence::Dependence Count Mean"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Expected Neighbourhood Size with Large IBSI Phantom Image", 8, results["SliceWise Mean Neighbouring Grey Level Dependence::Expected Neighbourhood Size"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Average Neighbourhood Size with Large IBSI Phantom Image", 5.20, results["SliceWise Mean Neighbouring Grey Level Dependence::Average Neighbourhood Size"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Average Incomplete Neighbourhood Size with Large IBSI Phantom Image", 4.5598, results["SliceWise Mean Neighbouring Grey Level Dependence::Average Incomplete Neighbourhood Size"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Percentage of complete Neighbourhoods with Large IBSI Phantom Image", 0.1831, results["SliceWise Mean Neighbouring Grey Level Dependence::Percentage of complete Neighbourhoods"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Neighbouring Grey Level Dependence::Percentage of Dependence Neighbour Voxels with Large IBSI Phantom Image", 0.579, results["SliceWise Mean Neighbouring Grey Level Dependence::Percentage of Dependence Neighbour Voxels"], 0.01); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFNeighbouringGreyLevelDependenceFeature ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFVolumetricDensityStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFVolumetricDensityStatisticsTest.cpp index 7c2fbe8f64..c1de6520b6 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFVolumetricDensityStatisticsTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFVolumetricDensityStatisticsTest.cpp @@ -1,88 +1,88 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFVolumetricDensityStatisticsTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFVolumetricDensityStatisticsTestSuite); MITK_TEST(ImageDescription_PhantomTest); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest() { mitk::GIFVolumetricDensityStatistics::Pointer featureCalculator = mitk::GIFVolumetricDensityStatistics::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 13 features.", std::size_t(13), featureList.size()); // These values are obtained by a run of the filter. // The might be wrong! // These values are obtained in collaboration with IBSI. // They are usually reported with an accuracy of 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume integrated intensity with Large IBSI Phantom Image", 1195, results["Morphological Density::Volume integrated intensity"], 1.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Moran's I index with Large IBSI Phantom Image", 0.0397, results["Morphological Density::Volume Moran's I index"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Geary's C measure with Large IBSI Phantom Image", 0.974, results["Morphological Density::Volume Geary's C measure"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume density axis-aligned bounding box with Large IBSI Phantom Image", 0.87, results["Morphological Density::Volume density axis-aligned bounding box"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume density axis-aligned bounding box with Large IBSI Phantom Image", 0.87, results["Morphological Density::Surface density axis-aligned bounding box"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume oriented minimum bounding box with Large IBSI Phantom Image", 0.87, results["Morphological Density::Volume density oriented minimum bounding box"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume oriented minimum bounding box with Large IBSI Phantom Image", 0.86, results["Morphological Density::Surface density oriented minimum bounding box"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume approx. enclosing ellipsoid with Large IBSI Phantom Image", 1.17, results["Morphological Density::Volume density approx. enclosing ellipsoid"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume approx. enclosing ellipsoid with Large IBSI Phantom Image", 1.34, results["Morphological Density::Surface density approx. enclosing ellipsoid"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume minimum volume enclosing ellipsoid with Large IBSI Phantom Image", 0.24, results["Morphological Density::Volume density approx. minimum volume enclosing ellipsoid"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume minimum volume enclosing ellipsoid with Large IBSI Phantom Image", 0.49, results["Morphological Density::Surface density approx. minimum volume enclosing ellipsoid"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume convex hull with Large IBSI Phantom Image", 0.96, results["Morphological Density::Volume density convex hull"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume convex hull with Large IBSI Phantom Image", 1.03, results["Morphological Density::Surface density convex hull"], 0.01); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFVolumetricDensityStatistics ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFVolumetricStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFVolumetricStatisticsTest.cpp index 2c5afa46dd..c23fb3317f 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFVolumetricStatisticsTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFVolumetricStatisticsTest.cpp @@ -1,106 +1,106 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFVolumetricStatisticsTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFVolumetricStatisticsTestSuite); MITK_TEST(ImageDescription_PhantomTest); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest() { mitk::GIFVolumetricStatistics::Pointer featureCalculator = mitk::GIFVolumetricStatistics::New(); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { - MITK_INFO << valuePair.first << " : " << valuePair.second; - results[valuePair.first] = valuePair.second; + MITK_INFO << mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first) << " : " << valuePair.second; + results[mitk::AbstractGlobalImageFeature::GenerateLegacyFeatureNameWOEncoding(valuePair.first)] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Volume Statistic should calculate 33 features.", std::size_t(38), featureList.size()); // These values are obtained in cooperation with IBSI // Default accuracy is 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Volume (mesh based) with Large IBSI Phantom Image", 556, results["Volumetric Features::Volume (mesh based)"], 1.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Volume (voxel based) with Large IBSI Phantom Image", 592, results["Volumetric Features::Volume (voxel based)"], 1.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Surface (mesh based) with Large IBSI Phantom Image", 388, results["Volumetric Features::Surface (mesh based)"], 1.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Surface to volume ratio (mesh based) with Large IBSI Phantom Image", 0.698, results["Volumetric Features::Surface to volume ratio (mesh based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Compactness 1 (mesh, mesh based) with Large IBSI Phantom Image", 0.04105, results["Volumetric Features::Compactness 1 (mesh, mesh based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Compactness 2 (mesh, mesh based) with Large IBSI Phantom Image", 0.599, results["Volumetric Features::Compactness 2 (mesh, mesh based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Spherical disproportion (mesh, mesh based) with Large IBSI Phantom Image", 1.18, results["Volumetric Features::Spherical disproportion (mesh, mesh based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Sphericity (mesh, mesh based) with Large IBSI Phantom Image", 0.843, results["Volumetric Features::Sphericity (mesh, mesh based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Asphericity (mesh based) with Large IBSI Phantom Image", 0.186, results["Volumetric Features::Asphericity (mesh, mesh based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Centre of mass shift with Large IBSI Phantom Image", 0.672, results["Volumetric Features::Centre of mass shift"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Maximum 3D diameter with Large IBSI Phantom Image", 11.66, results["Volumetric Features::Maximum 3D diameter"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::PCA Major axis length with Large IBSI Phantom Image", 11.40, results["Volumetric Features::PCA Major axis length"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::PCA Minor axis length with Large IBSI Phantom Image", 9.31, results["Volumetric Features::PCA Minor axis length"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::PCA Least axis length with Large IBSI Phantom Image", 8.54, results["Volumetric Features::PCA Least axis length"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::PCA Elongation with Large IBSI Phantom Image", 0.816, results["Volumetric Features::PCA Elongation"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::PCA Flatness with Large IBSI Phantom Image", 0.749, results["Volumetric Features::PCA Flatness"], 0.01); // These values are obtained by running the filter // They might be wrong! CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Voxel Volume with Large IBSI Phantom Image", 8, results["Volumetric Features::Voxel Volume"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Volume (voxel based) with Large IBSI Phantom Image", 592, results["Volumetric Features::Volume (voxel based)"], 0.1); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Surface (voxel based) with Large IBSI Phantom Image", 488, results["Volumetric Features::Surface (voxel based)"], 1.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Centre of mass shift (uncorrected) with Large IBSI Phantom Image", 0.672, results["Volumetric Features::Centre of mass shift (uncorrected)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Bounding Box Volume with Large IBSI Phantom Image", 288, results["Volumetric Features::Bounding Box Volume"], 1.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Surface to volume ratio (voxel based) with Large IBSI Phantom Image", 0.824, results["Volumetric Features::Surface to volume ratio (voxel based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Sphericity (voxel based) with Large IBSI Phantom Image", 0.699, results["Volumetric Features::Sphericity (voxel based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Asphericity (voxel based) with Large IBSI Phantom Image", 0.431, results["Volumetric Features::Asphericity (voxel based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Sphericity (mesh based) with Large IBSI Phantom Image", 0.879, results["Volumetric Features::Sphericity (mesh based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Asphericity (mesh based) with Large IBSI Phantom Image", 0.138, results["Volumetric Features::Asphericity (mesh based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Asphericity (mesh based) with Large IBSI Phantom Image", 0.138, results["Volumetric Features::Asphericity (mesh based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Compactness 1 (voxel based) with Large IBSI Phantom Image", 0.031, results["Volumetric Features::Compactness 1 (voxel based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Compactness 1 old (voxel based) with Large IBSI Phantom Image", 5.388, results["Volumetric Features::Compactness 1 old (voxel based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Compactness 2 (voxel based) with Large IBSI Phantom Image", 0.341, results["Volumetric Features::Compactness 2 (voxel based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Compactness 1 (mesh based) with Large IBSI Phantom Image", 0.0437, results["Volumetric Features::Compactness 1 (mesh based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Compactness 2 (mesh based) with Large IBSI Phantom Image", 0.678, results["Volumetric Features::Compactness 2 (mesh based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Spherical disproportion (voxel based) with Large IBSI Phantom Image", 1.43, results["Volumetric Features::Spherical disproportion (voxel based)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::PCA Major axis length (uncorrected) with Large IBSI Phantom Image", 11.40, results["Volumetric Features::PCA Major axis length (uncorrected)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::PCA Minor axis length (uncorrected) with Large IBSI Phantom Image", 9.31, results["Volumetric Features::PCA Minor axis length (uncorrected)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::PCA Least axis length (uncorrected) with Large IBSI Phantom Image", 8.54, results["Volumetric Features::PCA Least axis length (uncorrected)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::PCA Elongation (uncorrected) with Large IBSI Phantom Image", 0.816, results["Volumetric Features::PCA Elongation (uncorrected)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::PCA Flatness (uncorrected) with Large IBSI Phantom Image", 0.749, results["Volumetric Features::PCA Flatness (uncorrected)"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Volumetric Features::Compactness 1 old (mesh based) with Large IBSI Phantom Image", 6.278, results["Volumetric Features::Compactness 1 old (mesh based)"], 0.01); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFVolumetricStatistics ) diff --git a/Modules/Core/include/mitkImagePixelReadAccessor.h b/Modules/Core/include/mitkImagePixelReadAccessor.h index fdebe4c56f..5eb0a5ec6c 100644 --- a/Modules/Core/include/mitkImagePixelReadAccessor.h +++ b/Modules/Core/include/mitkImagePixelReadAccessor.h @@ -1,191 +1,192 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKIMAGEPIXELREADACCESSOR_H #define MITKIMAGEPIXELREADACCESSOR_H #include "mitkImagePixelAccessor.h" #include "mitkImageReadAccessor.h" namespace mitk { class Image; /** * @brief Gives locked and index-based read access for a particular image part. * The class provides several set- and get-methods, which allow an easy pixel access. * It needs to know about pixel type and dimension of its image at compile time. * @tparam TPixel defines the PixelType * @tparam VDimension defines the dimension for accessing data * @ingroup Data */ template class ImagePixelReadAccessor : public ImagePixelAccessor { friend class Image; public: typedef ImagePixelAccessor ImagePixelAccessorType; typedef itk::SmartPointer ImagePointer; typedef itk::SmartPointer ImageConstPointer; /** \brief Instantiates a mitk::ImageReadAccessor (see its doxygen page for more details) * \param Image::Pointer specifies the associated Image * \param ImageDataItem* specifies the allocated image part * \param OptionFlags properties from mitk::ImageAccessorBase::Options can be chosen and assembled with bitwise * unification. * \throws mitk::Exception if the Constructor was created inappropriately * \throws mitk::MemoryIsLockedException if requested image area is exclusively locked and * mitk::ImageAccessorBase::ExceptionIfLocked is set in OptionFlags * * Includes a check if typeid of PixelType coincides with templated TPixel * and a check if VDimension equals to the Dimension of the Image. */ ImagePixelReadAccessor(ImageConstPointer iP, const ImageDataItem *iDI = nullptr, int OptionFlags = ImageAccessorBase::DefaultBehavior) : ImagePixelAccessor(iP, iDI), m_ReadAccessor(iP, iDI, OptionFlags) { } ImagePixelReadAccessor(ImagePointer iP, const ImageDataItem *iDI = nullptr, int OptionFlags = ImageAccessorBase::DefaultBehavior) : ImagePixelAccessor(iP.GetPointer(), iDI), m_ReadAccessor(iP, iDI, OptionFlags) { } ImagePixelReadAccessor(Image *iP, const ImageDataItem *iDI = nullptr, int OptionFlags = ImageAccessorBase::DefaultBehavior) : ImagePixelAccessor(iP, iDI), m_ReadAccessor(mitk::Image::ConstPointer(iP), iDI, OptionFlags) { } ImagePixelReadAccessor(const Image *iP, const ImageDataItem *iDI = nullptr, int OptionFlags = ImageAccessorBase::DefaultBehavior) : ImagePixelAccessor(iP, iDI), m_ReadAccessor(iP, iDI, OptionFlags) { } /** Destructor informs Image to unlock memory. */ ~ImagePixelReadAccessor() override {} /** Returns a const reference to the pixel at given index. */ const TPixel &GetPixelByIndex(const itk::Index &idx) const { unsigned int offset = ImagePixelAccessorType::GetOffset(idx); return *(((TPixel *)m_ReadAccessor.m_AddressBegin) + offset); } itk::VariableLengthVector GetConsecutivePixelsAsVector(const itk::Index &idx, int nrComponents) const { return itk::VariableLengthVector( (TPixel *)m_ReadAccessor.m_AddressBegin + ImagePixelAccessorType::GetOffset(idx) * m_ReadAccessor.GetImage()->GetPixelType().GetNumberOfComponents(), nrComponents); } /** Extends GetPixel by integrating index validation to prevent overflow. * \throws mitk::Exception in case of overflow */ const TPixel &GetPixelByIndexSafe(const itk::Index &idx) const { unsigned int offset = ImagePixelAccessorType::GetOffset(idx); TPixel *targetAddress = ((TPixel *)m_ReadAccessor.m_AddressBegin) + offset; if (!(targetAddress >= m_ReadAccessor.m_AddressBegin && targetAddress < m_ReadAccessor.m_AddressEnd)) { mitkThrow() << "ImageAccessor Overflow: image access exceeds the requested image area at " << idx << "."; } return *targetAddress; } /** Returns a const reference to the pixel at given world coordinate - works only with three-dimensional * ImageAccessor */ const TPixel &GetPixelByWorldCoordinates(mitk::Point3D position) { itk::Index<3> itkIndex; m_ReadAccessor.GetImage()->GetGeometry()->WorldToIndex(position, itkIndex); return GetPixelByIndex(itkIndex); } /** Returns a const reference to the pixel at given world coordinate - works only with four-dimensional * ImageAccessor */ const TPixel &GetPixelByWorldCoordinates(mitk::Point3D position, unsigned int timestep) { itk::Index<3> itkIndex; m_ReadAccessor.GetImage()->GetGeometry()->WorldToIndex(position, itkIndex); if (m_ReadAccessor.GetImage()->GetTimeSteps() < timestep) { timestep = m_ReadAccessor.GetImage()->GetTimeSteps(); } itk::Index<4> itk4Index; for (int i = 0; i < 3; ++i) itk4Index[i] = itkIndex[i]; itk4Index[3] = timestep; return GetPixelByIndex(itk4Index); } /** \brief Gives const access to the data. */ inline const TPixel *GetData() const { return static_cast(m_ReadAccessor.m_AddressBegin); } protected: // protected members private: ImageReadAccessor m_ReadAccessor; ImagePixelReadAccessor &operator=(const ImagePixelReadAccessor &); // Not implemented on purpose. ImagePixelReadAccessor(const ImagePixelReadAccessor &); }; /** Static method that gets direct access to a single pixel value. * The value is not guaranteed to be in a well-defined state and is automatically casted to mitk::ScalarType * The method can be called by the macros in mitkPixelTypeMultiplex.h */ template mitk::ScalarType FastSinglePixelAccess(mitk::PixelType, mitk::Image::Pointer im, ImageDataItem *item, itk::Index<3> idx, mitk::ScalarType &val, int component = 0) { ImagePixelReadAccessor imAccess(im, item, mitk::ImageAccessorBase::IgnoreLock); val = imAccess.GetConsecutivePixelsAsVector(idx, component + 1).GetElement(component); return val; } /** Const overload of FastSinglePixelAccess*/ template mitk::ScalarType FastSinglePixelAccess(mitk::PixelType, mitk::Image::ConstPointer im, const ImageDataItem* item, itk::Index<3> idx, mitk::ScalarType& val, int component = 0) { ImagePixelReadAccessor imAccess(im, item, mitk::ImageAccessorBase::IgnoreLock); val = imAccess.GetConsecutivePixelsAsVector(idx, component + 1).GetElement(component); return val; } + } #endif // MITKIMAGEPIXELREADACCESSOR_H diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkGIFConfigurationPanel.cpp b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkGIFConfigurationPanel.cpp index b16243f70e..8645205618 100644 --- a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkGIFConfigurationPanel.cpp +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkGIFConfigurationPanel.cpp @@ -1,217 +1,212 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkGIFConfigurationPanel.h" // QT #include #include #include #include #include #include #include #include #include mitkUI::GIFConfigurationPanel::GIFConfigurationPanel(QWidget * parent, mitk::AbstractGlobalImageFeature::Pointer calculator) : QWidget(parent), m_FeatureCalculator(calculator) { QVBoxLayout * lay = new QVBoxLayout; QHBoxLayout * checkboxLayout = new QHBoxLayout; m_CheckCalculateFeature = new QCheckBox; m_CheckCalculateFeature->setText(m_FeatureCalculator->GetFeatureClassName().c_str()); m_ButtonShowAdditionalConfiguration = new QPushButton; m_ButtonShowAdditionalConfiguration->setText("+"); m_ButtonShowAdditionalConfiguration->setMaximumWidth(30); m_ButtonShowAdditionalConfiguration->setCheckable(true); checkboxLayout->addWidget(m_CheckCalculateFeature); checkboxLayout->addWidget(m_ButtonShowAdditionalConfiguration); lay->addItem(checkboxLayout); QFormLayout * argumentLayout = new QFormLayout; QLabel * label1 = new QLabel("Use Argument"); QLabel * label2 = new QLabel("Argument Value"); argumentLayout->addRow(label1, label2); mitkCommandLineParser parser; m_FeatureCalculator->AddArguments(parser); std::vector < std::map > argumentList = parser.getArgumentList(); for (auto argument : argumentList) { QString longarg(argument["longarg"].ToString().c_str()); if (longarg.contains("::")) { QCheckBox * argumentBox = new QCheckBox; QWidget * secondWidget = nullptr; argumentBox->setText(longarg); mitkCommandLineParser::Type type = us::any_cast(argument["valuetype"]); switch (type) { case mitkCommandLineParser::Bool: secondWidget = new QCheckBox; break; case mitkCommandLineParser::String: { QLineEdit* lineEdit = new QLineEdit; secondWidget = lineEdit; break; } case mitkCommandLineParser::Int: { QSpinBox* spinBox = new QSpinBox(); spinBox->setMinimum(std::numeric_limits::min()); spinBox->setMaximum(std::numeric_limits::max()); secondWidget = spinBox; break; } case mitkCommandLineParser::Float: { QDoubleSpinBox* spindBox = new QDoubleSpinBox; spindBox->setMinimum(std::numeric_limits::lowest()); spindBox->setMaximum(std::numeric_limits::max()); secondWidget = spindBox; break; } default: secondWidget = new QLabel("unkonw type"); } argumentLayout->addRow(argumentBox, secondWidget); } } if (argumentList.size() < 2) { m_ButtonShowAdditionalConfiguration->setVisible(false); } m_GroupBoxArguments = new QGroupBox; m_GroupBoxArguments->setTitle(""); m_GroupBoxArguments->setLayout(argumentLayout); m_GroupBoxArguments->setVisible(false); lay->addWidget(m_GroupBoxArguments); //lay->addItem(argumentLayout); // Buttons see https://joekuan.wordpress.com/2015/09/23/list-of-qt-icons/ // Resolution https://itk.org/Doxygen/html/classitk_1_1RecursiveMultiResolutionPyramidImageFilter.html // Wavelet https://code.google.com/archive/p/nwave/source/default/source this->setLayout(lay); connect((QObject*)(m_ButtonShowAdditionalConfiguration), SIGNAL(clicked(bool)), this, SLOT(OnSButtonShowAdditionalConfigurationPressed(bool))); } void mitkUI::GIFConfigurationPanel::OnSButtonShowAdditionalConfigurationPressed(bool /*status*/) { if (m_ButtonShowAdditionalConfiguration->isChecked()) { m_ButtonShowAdditionalConfiguration->setText("-"); m_GroupBoxArguments->setVisible(true); } else { m_ButtonShowAdditionalConfiguration->setText("+"); m_GroupBoxArguments->setVisible(false); } } void mitkUI::GIFConfigurationPanel::CalculateFeaturesUsingParameters(const mitk::Image::Pointer & feature, const mitk::Image::Pointer &mask, std::map < std::string, us::Any> parameter, mitk::AbstractGlobalImageFeature::FeatureListType &featureList) { parameter[m_FeatureCalculator->GetLongName()] = us::Any(true); if (m_CheckCalculateFeature->isChecked()) { for (int i = 0; i < m_GroupBoxArguments->layout()->count(); i+=2) { QCheckBox * argumentBox = dynamic_cast(m_GroupBoxArguments->layout()->itemAt(i)->widget()); if (argumentBox != nullptr) { if (argumentBox->isChecked() == false) { continue; } std::string argumentName = argumentBox->text().toStdString(); QCheckBox * paramBool = dynamic_cast(m_GroupBoxArguments->layout()->itemAt(i + 1)->widget()); QLineEdit * paramText = dynamic_cast(m_GroupBoxArguments->layout()->itemAt(i + 1)->widget()); QSpinBox * paramInt = dynamic_cast(m_GroupBoxArguments->layout()->itemAt(i + 1)->widget()); QDoubleSpinBox * paramFloat = dynamic_cast(m_GroupBoxArguments->layout()->itemAt(i + 1)->widget()); if (paramBool == nullptr && paramText == nullptr && paramInt == nullptr && paramFloat == nullptr) { continue; } us::Any value; if (paramBool != nullptr) { value = us::Any(paramBool->isChecked()); } if (paramText != nullptr) { value = us::Any(paramText->text().toStdString()); } if (paramInt != nullptr) { value = us::Any(paramInt->value()); } if (paramFloat != nullptr) { value = us::Any(float(paramFloat->value())); } parameter[argumentName] = value; MITK_INFO << argumentName << " : " << value.ToString(); } } auto tmpPointer = m_FeatureCalculator->Clone(); mitk::AbstractGlobalImageFeature::Pointer tmpCalc = dynamic_cast(tmpPointer.GetPointer()); for (auto item : parameter) { MITK_INFO << item.first << " : " << item.second.ToString(); } - tmpCalc->SetParameter(parameter); + tmpCalc->SetParameters(parameter); bool calculateSliceWise = false; int slice = 0; if (parameter.count("slice-wise")) { slice = us::any_cast(parameter["slice-wise"]); calculateSliceWise = true; } - if (parameter.count("encode-parameter-in-name")) - { - bool encodeParameter = us::any_cast(parameter["encode-parameter-in-name"]); - tmpCalc->SetEncodeParameters(encodeParameter); - } if (calculateSliceWise) { - tmpCalc->CalculateFeaturesSliceWiseUsingParameters(feature, mask, slice, featureList); + tmpCalc->CalculateAndAppendFeaturesSliceWise(feature, mask, slice, featureList); } else { - tmpCalc->CalculateFeaturesUsingParameters(feature, mask, mask, featureList); + tmpCalc->CalculateAndAppendFeatures(feature, mask, mask, featureList); } } } diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsStatisticView.cpp b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsStatisticView.cpp index fd59e2b3cc..a5846b7cec 100644 --- a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsStatisticView.cpp +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsStatisticView.cpp @@ -1,326 +1,326 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkRadiomicsStatisticView.h" // QT includes (GUI) #include #include #include #include #include #include #include #include #include // Berry includes (selection service) #include #include // MITK includes (GUI) #include #include "QmitkDataNodeSelectionProvider.h" #include "mitkDataNodeObject.h" // MITK includes (general) #include "mitkLabelSetImage.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Includes for image casting between ITK and MITK #include #include // Specific GUI Includes #include "QmitkGIFConfigurationPanel.h" QmitkRadiomicsStatistic::QmitkRadiomicsStatistic() : QmitkAbstractView(), m_Controls(nullptr) { } QmitkRadiomicsStatistic::~QmitkRadiomicsStatistic() { //berry::ISelectionService* s = GetSite()->GetWorkbenchWindow()->GetSelectionService(); //if(s) // s->RemoveSelectionListener(m_SelectionListener); } void QmitkRadiomicsStatistic::CreateQtPartControl(QWidget *parent) { if (m_Controls == nullptr) { mitk::GIFImageDescriptionFeatures::Pointer ipCalculator = mitk::GIFImageDescriptionFeatures::New(); // Commented 2, Tested mitk::GIFFirstOrderStatistics::Pointer firstOrderCalculator = mitk::GIFFirstOrderStatistics::New(); //Commented 2 mitk::GIFFirstOrderHistogramStatistics::Pointer firstOrderHistoCalculator = mitk::GIFFirstOrderHistogramStatistics::New(); // Commented 2, Tested mitk::GIFFirstOrderNumericStatistics::Pointer firstOrderNumericCalculator = mitk::GIFFirstOrderNumericStatistics::New(); // Commented 2, Tested mitk::GIFVolumetricStatistics::Pointer volCalculator = mitk::GIFVolumetricStatistics::New(); // Commented 2, Tested mitk::GIFVolumetricDensityStatistics::Pointer voldenCalculator = mitk::GIFVolumetricDensityStatistics::New(); // Commented 2, Tested mitk::GIFCooccurenceMatrix::Pointer coocCalculator = mitk::GIFCooccurenceMatrix::New(); // Commented 2, Will not be tested mitk::GIFCooccurenceMatrix2::Pointer cooc2Calculator = mitk::GIFCooccurenceMatrix2::New(); //Commented 2 mitk::GIFNeighbouringGreyLevelDependenceFeature::Pointer ngldCalculator = mitk::GIFNeighbouringGreyLevelDependenceFeature::New(); //Commented 2, Tested mitk::GIFGreyLevelRunLength::Pointer rlCalculator = mitk::GIFGreyLevelRunLength::New(); // Commented 2 mitk::GIFGreyLevelSizeZone::Pointer glszCalculator = mitk::GIFGreyLevelSizeZone::New(); // Commented 2, Tested mitk::GIFGreyLevelDistanceZone::Pointer gldzCalculator = mitk::GIFGreyLevelDistanceZone::New(); //Commented 2, Tested mitk::GIFLocalIntensity::Pointer lociCalculator = mitk::GIFLocalIntensity::New(); //Commented 2, Tested mitk::GIFIntensityVolumeHistogramFeatures::Pointer ivohCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); // Commented 2 mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::Pointer ngtdCalculator = mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::New(); //Commented 2, Tested mitk::GIFCurvatureStatistic::Pointer curvCalculator = mitk::GIFCurvatureStatistic::New(); //Commented 2, Tested std::vector features; features.push_back(volCalculator.GetPointer()); features.push_back(voldenCalculator.GetPointer()); features.push_back(curvCalculator.GetPointer()); features.push_back(firstOrderCalculator.GetPointer()); features.push_back(firstOrderNumericCalculator.GetPointer()); features.push_back(firstOrderHistoCalculator.GetPointer()); features.push_back(ivohCalculator.GetPointer()); features.push_back(lociCalculator.GetPointer()); features.push_back(cooc2Calculator.GetPointer()); features.push_back(ngldCalculator.GetPointer()); features.push_back(rlCalculator.GetPointer()); features.push_back(glszCalculator.GetPointer()); features.push_back(gldzCalculator.GetPointer()); features.push_back(ipCalculator.GetPointer()); features.push_back(ngtdCalculator.GetPointer()); m_Controls = new Ui::QmitkRadiomicsStatisticViewControls; m_Controls->setupUi(parent); for (auto cFeature : features) { mitkUI::GIFConfigurationPanel* gifPanel = new mitkUI::GIFConfigurationPanel(parent, cFeature); m_Controls->m_FeaturesGroup->layout()->addWidget(gifPanel); } QLabel * label1 = new QLabel("Image: "); QLabel * label2 = new QLabel("Mask: "); QmitkDataStorageComboBox * cb_inputimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); QmitkDataStorageComboBox * cb_maskimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); m_Controls->m_InputImageGroup->layout()->addWidget(label1); m_Controls->m_InputImageGroup->layout()->addWidget(cb_inputimage); m_Controls->m_InputImageGroup->layout()->addWidget(label2); m_Controls->m_InputImageGroup->layout()->addWidget(cb_maskimage); this->CreateConnections(); //setup predictaes for combobox mitk::NodePredicateDimension::Pointer dimensionPredicate = mitk::NodePredicateDimension::New(3); mitk::NodePredicateDataType::Pointer imagePredicate = mitk::NodePredicateDataType::New("Image"); } } void QmitkRadiomicsStatistic::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->buttonExecute), SIGNAL(clicked() ), this, SLOT(executeButtonPressed() ) ); connect((QObject*)(m_Controls->buttonExecuteAndAppend), SIGNAL(clicked()), this, SLOT(executeAndAppendButtonPressed())); connect((QObject*)(m_Controls->buttonTableToClipboard), SIGNAL(clicked()), this, SLOT(copyToClipboardButtonPressed())); } } std::map < std::string, us::Any> QmitkRadiomicsStatistic::GenerateParameters() { std::map < std::string, us::Any> parameter; if (m_Controls->m_SetMinimumIntensity->isChecked()) { parameter["minimum-intensity"] = us::Any(float(m_Controls->m_ParamMinimumIntensity->value())); } if (m_Controls->m_SetMaximumIntensity->isChecked()) { parameter["maximum-intensity"] = us::Any(float(m_Controls->m_ParamMaximumIntensity->value())); } if (m_Controls->m_SetNumberOfBins->isChecked()) { parameter["bins"] = us::Any(m_Controls->m_ParamBins->value()); } if (m_Controls->m_SetBinSize->isChecked()) { parameter["binsize"] = us::Any(float(m_Controls->m_ParamBinSize->value())); } if (m_Controls->m_SetIgnoreBinSize->isChecked()) { parameter["ignore-mask-for-histogram"] = us::Any(m_Controls->m_ParamIgnoreMask->isChecked()); } if (m_Controls->m_SetEncodeParameterInName->isChecked()) { parameter["encode-parameter-in-name"] = us::Any(m_Controls->m_ParamEncodeName->isChecked()); } if (m_Controls->m_SetDirectionParameter->isChecked()) { parameter["direction"] = us::Any(m_Controls->m_ParamDirection->value()); } if (m_Controls->m_SetSliceWiseParameter->isChecked()) { parameter["slice-wise"] = us::Any(m_Controls->m_ParamSliceWise->value()); } return parameter; } void QmitkRadiomicsStatistic::executeButtonPressed() { QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); QmitkDataStorageComboBox * cb_maskimage = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(3)->widget()); mitk::BaseData* baseDataRawImage = nullptr; mitk::BaseData* baseDataMaskImage = nullptr; mitk::Image::Pointer raw_image; mitk::Image::Pointer mask_image; QString imageName; QString maskName; if ((cb_image->GetSelectedNode().IsNotNull() ) && (cb_maskimage->GetSelectedNode().IsNotNull())) { imageName = cb_image->GetSelectedNode()->GetName().c_str(); maskName = cb_maskimage->GetSelectedNode()->GetName().c_str(); baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); baseDataMaskImage = (cb_maskimage->GetSelectedNode()->GetData()); } if ((baseDataRawImage != nullptr) && (baseDataMaskImage != nullptr)) { raw_image = dynamic_cast(baseDataRawImage); mask_image = dynamic_cast(baseDataMaskImage); } else { QMessageBox msgBox; msgBox.setText("Please specify the images that shlould be used."); msgBox.exec(); return; } if (raw_image.IsNull() || mask_image.IsNull()) { QMessageBox msgBox; msgBox.setText("Error during processing the specified images."); msgBox.exec(); return; } mitk::AbstractGlobalImageFeature::FeatureListType stats; for (int i = 0; i < m_Controls->m_FeaturesGroup->layout()->count(); ++i) { auto parameter = this->GenerateParameters(); mitkUI::GIFConfigurationPanel* gifPanel = dynamic_cast(m_Controls->m_FeaturesGroup->layout()->itemAt(i)->widget()); if (gifPanel == nullptr) continue; gifPanel->CalculateFeaturesUsingParameters(raw_image, mask_image, parameter, stats); } m_Controls->m_ResultTable->setRowCount(stats.size()); for (std::size_t i = 0; i < stats.size(); ++i) { m_Controls->m_ResultTable->setItem(i, 0, new QTableWidgetItem(imageName)); m_Controls->m_ResultTable->setItem(i, 1, new QTableWidgetItem(maskName)); - m_Controls->m_ResultTable->setItem(i, 2, new QTableWidgetItem(stats[i].first.c_str())); + m_Controls->m_ResultTable->setItem(i, 2, new QTableWidgetItem(stats[i].first.legacyName.c_str())); m_Controls->m_ResultTable->setItem(i, 3, new QTableWidgetItem(QString::number(stats[i].second))); } } void QmitkRadiomicsStatistic::executeAndAppendButtonPressed() { std::vector elementImage; std::vector elementMask; std::vector elementText; std::vector elementValue; for (int i = 0; i < m_Controls->m_ResultTable->rowCount(); ++i) { auto itemImage = m_Controls->m_ResultTable->item(i, 0)->clone(); auto itemMask = m_Controls->m_ResultTable->item(i, 1)->clone(); auto itemText = m_Controls->m_ResultTable->item(i, 2)->clone(); auto itemValue = m_Controls->m_ResultTable->item(i, 3)->clone(); elementImage.push_back(itemImage); elementMask.push_back(itemMask); elementText.push_back(itemText); elementValue.push_back(itemValue); } executeButtonPressed(); std::size_t oldSize = m_Controls->m_ResultTable->rowCount(); m_Controls->m_ResultTable->setRowCount(oldSize + elementText.size()); for (std::size_t i = 0; i < elementText.size(); ++i) { m_Controls->m_ResultTable->setItem(i + oldSize, 0, elementImage[i]); m_Controls->m_ResultTable->setItem(i + oldSize, 1, elementMask[i]); m_Controls->m_ResultTable->setItem(i+oldSize, 2, elementText[i]); m_Controls->m_ResultTable->setItem(i+oldSize, 3, elementValue[i]); } } void QmitkRadiomicsStatistic::copyToClipboardButtonPressed() { QString selectedText; for (int i = 0; i < m_Controls->m_ResultTable->rowCount(); ++i) { auto itemImage = m_Controls->m_ResultTable->item(i, 0); auto itemMask = m_Controls->m_ResultTable->item(i, 1); auto itemText = m_Controls->m_ResultTable->item(i, 2); auto itemValue = m_Controls->m_ResultTable->item(i, 3); selectedText.append(itemImage->text()); selectedText.append(";"); selectedText.append(itemMask->text()); selectedText.append(";"); selectedText.append(itemText->text()); selectedText.append(";"); selectedText.append(itemValue->text()); selectedText.append("\n"); } QApplication::clipboard()->setText(selectedText); } void QmitkRadiomicsStatistic::SetFocus() { } //datamanager selection changed void QmitkRadiomicsStatistic::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) { //any nodes there? if (!nodes.empty()) { } }