diff --git a/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h b/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h index a8fcb05fac..d927072723 100644 --- a/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h +++ b/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h @@ -1,291 +1,333 @@ /*============================================================================ 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 deature 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; + + 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* feature, const Image* mask); + virtual FeatureListType CalculateFeatures(const Image* feature, 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); /** * \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 & feature, 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* feature, 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 instance to the passed parser instance. + It always calls AddQuantifierArguments(...) and afterwards DoAddArguments(...). Implement DoAddArguments() to + handle class specific arguments.*/ + void AddArguments(mitkCommandLineParser &parser) const; + +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* feature, const Image* mask) = 0; + + virtual void DoAddArguments(mitkCommandLineParser& parser) const; + 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* feature, const Image*, 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. + */ + 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 + + mitk::Image::Pointer m_MorphMask = nullptr; - bool m_UseQuantifier = false; - IntensityQuantifier::Pointer m_Quantifier; + 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..f7bb379e7e 100644 --- a/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp +++ b/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp @@ -1,402 +1,495 @@ /*============================================================================ 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::AddArguments(mitkCommandLineParser& parser) const +{ + this->AddQuantifierArguments(parser); + this->DoAddArguments(parser); +} + +void mitk::AbstractGlobalImageFeature::DoAddArguments(mitkCommandLineParser& parser) const +{ + //Default implementation does nothing. + //Override to change behavior. +} + +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* feature, 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()); else if (GetUseBinsize() && GetIgnoreMask() && GetUseMaximumIntensity()) m_Quantifier->InitializeByImageAndBinsizeAndMaximum(feature, GetMaximumIntensity(), GetBinsize()); else if (GetUseBinsize() && GetIgnoreMask()) m_Quantifier->InitializeByImageAndBinsize(feature, GetBinsize()); // Initialize form Image, Mask and Binsize else if (GetUseBinsize() && GetUseMinimumIntensity()) m_Quantifier->InitializeByImageRegionAndBinsizeAndMinimum(feature, mask, GetMinimumIntensity(), GetBinsize()); else if (GetUseBinsize() && GetUseMaximumIntensity()) m_Quantifier->InitializeByImageRegionAndBinsizeAndMaximum(feature, mask, GetMaximumIntensity(), GetBinsize()); else if (GetUseBinsize()) m_Quantifier->InitializeByImageRegionAndBinsize(feature, mask, GetBinsize()); // Intialize from Image and Bins else if (GetUseBins() && GetIgnoreMask() && GetUseMinimumIntensity()) m_Quantifier->InitializeByImageAndMinimum(feature, GetMinimumIntensity(), GetBins()); else if (GetUseBins() && GetIgnoreMask() && GetUseMaximumIntensity()) m_Quantifier->InitializeByImageAndMaximum(feature, GetMaximumIntensity(), GetBins()); else if (GetUseBins()) m_Quantifier->InitializeByImage(feature, GetBins()); // Intialize from Image, Mask and Bins else if (GetUseBins() && GetUseMinimumIntensity()) m_Quantifier->InitializeByImageRegionAndMinimum(feature, mask, GetMinimumIntensity(), GetBins()); else if (GetUseBins() && GetUseMaximumIntensity()) m_Quantifier->InitializeByImageRegionAndMaximum(feature, mask, GetMaximumIntensity(), GetBins()); else if (GetUseBins()) m_Quantifier->InitializeByImageRegion(feature, mask, GetBins()); // Default else if (GetIgnoreMask()) m_Quantifier->InitializeByImage(feature, GetBins()); else m_Quantifier->InitializeByImageRegion(feature, mask, defaultBins); } -std::string mitk::AbstractGlobalImageFeature::GetCurrentFeatureEncoding() -{ - return ""; -} - -std::string mitk::AbstractGlobalImageFeature::FeatureDescriptionPrefix() +std::string 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::GenerateLegacyFeatureEncoding(const FeatureID& id) const +{ + return this->QuantifierParameterString(); } -std::string mitk::AbstractGlobalImageFeature::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; + } -void mitk::AbstractGlobalImageFeature::CalculateFeaturesSliceWiseUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, int sliceID, FeatureListType &featureList) + 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)); + } + } + + for (const auto& paramIter : additionalParams) + { + newID.parameters.insert(std::make_pair(paramIter.first, paramIter.second)); + } + return newID; +} + +void mitk::AbstractGlobalImageFeature::CalculateAndAppendFeaturesSliceWise(const Image::Pointer & feature, 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(feature, mask, sliceID); + featureList.insert(featureList.end(), result.begin(), result.end()); + } } mitk::AbstractGlobalImageFeature::FeatureListType mitk::AbstractGlobalImageFeature::CalculateFeaturesSlicewise(const Image::Pointer & feature, const Image::Pointer &mask, int sliceID) { std::vector imageVector; std::vector maskVector; ExtractSlicesFromImages(feature, mask,sliceID, imageVector, maskVector); std::vector statVector; for (std::size_t index = 0; index < imageVector.size(); ++index) { - 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* feature, const Image* mask, const Image* maskNoNAN, FeatureListType& featureList, bool checkParameterActivation) +{ + auto parsedArgs = GetParameters(); + + if (!checkParameterActivation || parsedArgs.count(GetLongName())) + { + auto result = CalculateFeatures(feature, mask, maskNoNAN); + featureList.insert(featureList.end(), result.begin(), result.end()); + } +} + +mitk::AbstractGlobalImageFeature::FeatureListType mitk::AbstractGlobalImageFeature::CalculateFeatures(const Image* feature, const Image* mask) +{ + auto result = this->DoCalculateFeatures(feature, mask); + + //ensure legacy names + for (auto& feature : result) + { + feature.first.legacyName = this->GenerateLegacyFeatureName(feature.first); + } + + 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/CLUtilities/include/mitkGIFCooccurenceMatrix2.h b/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h index 79852f8a0e..30c3db7906 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h @@ -1,174 +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. ============================================================================*/ #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; + + itkGetConstMacro(Ranges, std::vector); + void SetRanges(std::vector ranges); + void SetRange(double range); + + protected: + void DoAddArguments(mitkCommandLineParser& parser) const override; + + 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/mitkGIFGreyLevelRunLength.h b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelRunLength.h index 84a57b3bea..15270a3f6b 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelRunLength.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelRunLength.h @@ -1,131 +1,111 @@ /*============================================================================ 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(); - /** - * \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; - /** - * \brief Returns a list of the names of all features that are calculated from this class - */ - FeatureNameListType GetFeatureNames() override; + protected: - 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: + FeatureListType DoCalculateFeatures(const Image* image, const Image* mask) override; + void DoAddArguments(mitkCommandLineParser &parser) const override; }; } #endif //mitkGIFGreyLevelRunLength_h diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp index fba1f5f467..83da72f28f 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp @@ -1,705 +1,706 @@ /*============================================================================ 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, +void MatrixFeaturesTo(const mitk::CoocurenceMatrixFeatures& features, + const std::string& prefix, + const mitk::GIFCooccurenceMatrix2Configuration& config, mitk::GIFCooccurenceMatrix2::FeatureListType &featureList); static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature); static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number); mitk::CoocurenceMatrixHolder::CoocurenceMatrixHolder(double min, double max, int number) : m_MinimumRange(min), m_MaximumRange(max), m_NumberOfBins(number) { m_Matrix.resize(number, number); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::CoocurenceMatrixHolder::IntensityToIndex(double intensity) { int index = std::floor((intensity - m_MinimumRange) / m_Stepsize); return std::max(0, std::min(index, m_NumberOfBins - 1)); } double mitk::CoocurenceMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template void -CalculateCoOcMatrix(itk::Image* itkImage, - itk::Image* mask, +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); + MatrixFeaturesTo(overallFeature, "Overall ", config, featureList); + MatrixFeaturesTo(featureMean, "Mean ", config, featureList); + MatrixFeaturesTo(featureStd, "Std.Dev. ", config, featureList); } static -void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, - std::string prefix, +void MatrixFeaturesTo(const mitk::CoocurenceMatrixFeatures& features, + const std::string& prefix, + const mitk::GIFCooccurenceMatrix2Configuration& config, 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)); + 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) { #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::DoAddArguments(mitkCommandLineParser &parser) const { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Co-occurence matrix", "calculates Co-occurence based features (new implementation)", us::Any()); parser.addArgument(name+"::range", name+"::range", mitkCommandLineParser::String, "Cooc 2 Range", "Define the range that is used (Semicolon-separated)", us::Any()); - AddQuantifierArguments(parser); } -void -mitk::GIFCooccurenceMatrix2::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +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("::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/mitkGIFGreyLevelRunLength.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp index 35d3ebf7eb..3f6f16cae3 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp @@ -1,285 +1,279 @@ /*============================================================================ 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::DoAddArguments(mitkCommandLineParser &parser) const +{ + 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); - - return featureList; -} + AccessByItk_3(image, CalculateGrayLevelRunLengthFeatures, mask, featureList, params); -mitk::GIFGreyLevelRunLength::FeatureNameListType mitk::GIFGreyLevelRunLength::GetFeatureNames() -{ - FeatureNameListType featureList; + MITK_INFO << "Finished calculating Run-length"; + 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/mitkCLResultWritter.cpp b/Modules/Classification/CLUtilities/src/mitkCLResultWritter.cpp index 91e5308d46..b70455a3fd 100644 --- a/Modules/Classification/CLUtilities/src/mitkCLResultWritter.cpp +++ b/Modules/Classification/CLUtilities/src/mitkCLResultWritter.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 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) : 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() { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkGIFConfigurationPanel.cpp b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkGIFConfigurationPanel.cpp index b16243f70e..54f155ce45 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,217 @@ /*============================================================================ 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); } else { tmpCalc->CalculateFeaturesUsingParameters(feature, mask, mask, featureList); } } }