diff --git a/Modules/Classification/CLCore/files.cmake b/Modules/Classification/CLCore/files.cmake index 0e43386e0d..c3ae208ff9 100644 --- a/Modules/Classification/CLCore/files.cmake +++ b/Modules/Classification/CLCore/files.cmake @@ -1,10 +1,11 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkConfigurationHolder.cpp mitkAbstractClassifier.cpp mitkAbstractGlobalImageFeature.cpp + mitkIntensityQuantifier.cpp ) set( TOOL_FILES ) diff --git a/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h b/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h index 082f162fa6..30ecaea6ff 100644 --- a/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h +++ b/Modules/Classification/CLCore/include/mitkAbstractGlobalImageFeature.h @@ -1,139 +1,156 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkAbstractGlobalImageFeature_h #define mitkAbstractGlobalImageFeature_h #include #include #include #include +#include + +// STD Includes // Eigen #include -// STD Includes - // MITK includes #include namespace mitk { class MITKCLCORE_EXPORT AbstractGlobalImageFeature : public BaseData { public: mitkClassMacro(AbstractGlobalImageFeature, BaseData) typedef std::vector< std::pair > FeatureListType; typedef std::vector< std::string> FeatureNameListType; typedef std::map ParameterTypes; /** * \brief Calculates the feature of this abstact interface. Does not necessarily considers the parameter settings. */ virtual FeatureListType CalculateFeatures(const Image::Pointer & feature, const Image::Pointer &mask) = 0; /** * \brief Calculates the feature of this abstact interface. Does not necessarily considers the parameter settings. */ virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) = 0; /** * \brief Returns a list of the names of all features that are calculated from this class */ virtual FeatureNameListType GetFeatureNames() = 0; itkSetMacro(Prefix, std::string); itkSetMacro(ShortName, std::string); itkSetMacro(LongName, std::string); itkSetMacro(Direction, int); void SetParameter(ParameterTypes param) { m_Parameter=param; }; itkGetConstMacro(Prefix, std::string); itkGetConstMacro(ShortName, std::string); itkGetConstMacro(LongName, std::string); itkGetConstMacro(Parameter, ParameterTypes); + + itkSetMacro(UseQuantifier, bool); + itkGetConstMacro(UseQuantifier, bool); + itkSetMacro(Quantifier, IntensityQuantifier::Pointer); + itkGetMacro(Quantifier, IntensityQuantifier::Pointer); + itkGetConstMacro(Direction, int); itkSetMacro(MinimumIntensity, float); itkSetMacro(UseMinimumIntensity, bool); itkSetMacro(MaximumIntensity, float); itkSetMacro(UseMaximumIntensity, bool); itkGetConstMacro(MinimumIntensity, float); itkGetConstMacro(UseMinimumIntensity, bool); itkGetConstMacro(MaximumIntensity, float); itkGetConstMacro(UseMaximumIntensity, bool); + itkSetMacro(MorphMask, mitk::Image::Pointer); + itkGetConstMacro(MorphMask, mitk::Image::Pointer); + itkSetMacro(Bins, int); itkGetConstMacro(Bins, int); std::string GetOptionPrefix() const { if (m_Prefix.length() > 0) return m_Prefix + "::" + m_ShortName; return m_ShortName; } virtual void AddArguments(mitkCommandLineParser &parser) = 0; std::vector SplitDouble(std::string str, char delimiter); + void AddQuantifierArguments(mitkCommandLineParser &parser); + void InitializeQuantifier(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList, unsigned int defaultBins = 256); + public: //#ifndef DOXYGEN_SKIP virtual void SetRequestedRegionToLargestPossibleRegion() override {}; virtual bool RequestedRegionIsOutsideOfTheBufferedRegion() override { return true; }; virtual bool VerifyRequestedRegion() override { return false; }; virtual void SetRequestedRegion (const itk::DataObject * /*data*/) override {}; // Override virtual bool IsEmpty() const override { if(IsInitialized() == false) return true; const TimeGeometry* timeGeometry = const_cast(this)->GetUpdatedTimeGeometry(); if(timeGeometry == nullptr) return true; return false; } private: std::string m_Prefix; // Prefix before all input parameters std::string m_ShortName; // Name of all variables std::string m_LongName; // Long version of the name (For turning on) ParameterTypes m_Parameter; // Parameter setting + bool m_UseQuantifier = false; + IntensityQuantifier::Pointer m_Quantifier; + double m_MinimumIntensity = 0; bool m_UseMinimumIntensity = false; double m_MaximumIntensity = 100; bool m_UseMaximumIntensity = false; int m_Bins = 256; int m_Direction = 0; + 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 new file mode 100644 index 0000000000..a9c51b301f --- /dev/null +++ b/Modules/Classification/CLCore/include/mitkIntensityQuantifier.h @@ -0,0 +1,87 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef 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 InitializeByImageRegion(mitk::Image::Pointer image, mitk::Image::Pointer mask, unsigned int bins); + void InitializeByImageAndBinsize(mitk::Image::Pointer image, double binsize); + void InitializeByImageRegionAndBinsize(mitk::Image::Pointer image, mitk::Image::Pointer mask, double binsize); + + unsigned int IntensityToIndex(double intensity); + double IndexToMinimumIntensity(unsigned int index); + double IndexToMeanIntensity(unsigned int index); + double IndexToMaximumIntensity(unsigned int index); + + itkGetConstMacro(Initialized, bool); + itkGetConstMacro(Bins, unsigned int); + itkGetConstMacro(Binsize, double); + itkGetConstMacro(Minimum, double); + itkGetConstMacro(Maximum, double); + +public: + +//#ifndef DOXYGEN_SKIP + + virtual void SetRequestedRegionToLargestPossibleRegion() override {}; + virtual bool RequestedRegionIsOutsideOfTheBufferedRegion() override { return true; }; + virtual bool VerifyRequestedRegion() override { return false; }; + virtual void SetRequestedRegion (const itk::DataObject * /*data*/) override {}; + + // Override + virtual bool IsEmpty() const override + { + if(IsInitialized() == false) + return true; + const TimeGeometry* timeGeometry = const_cast(this)->GetUpdatedTimeGeometry(); + if(timeGeometry == nullptr) + return true; + return false; + } + + +private: + bool m_Initialized; + unsigned int m_Bins; + double m_Binsize; + double m_Minimum; + double m_Maximum; + +}; +} + +#endif //mitkIntensityQuantifier_h diff --git a/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp b/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp index 5de783d940..b991012430 100644 --- a/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp +++ b/Modules/Classification/CLCore/src/mitkAbstractGlobalImageFeature.cpp @@ -1,31 +1,116 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include std::vector mitk::AbstractGlobalImageFeature::SplitDouble(std::string str, char delimiter) { std::vector internal; std::stringstream ss(str); // Turn the string into a stream. std::string tok; double val; while (std::getline(ss, tok, delimiter)) { std::stringstream s2(tok); s2 >> val; internal.push_back(val); } return internal; -} \ No newline at end of file +} + +void mitk::AbstractGlobalImageFeature::AddQuantifierArguments(mitkCommandLineParser &parser) +{ + std::string name = GetOptionPrefix(); + + parser.addArgument(name + "::minimum", name + "::min", mitkCommandLineParser::Float, "Minium Intensity for Quantification", "Defines the minimum Intensity used for Quantification", us::Any()); + parser.addArgument(name + "::maximum", name + "::max", mitkCommandLineParser::Float, "Maximum Intensity for Quantification", "Defines the maximum Intensity used for Quantification", us::Any()); + parser.addArgument(name + "::bins", name + "::bins", mitkCommandLineParser::Int, "Number of Bins", "Define the number of bins that is used ", us::Any()); + parser.addArgument(name + "::binsize", name + "::binsize", mitkCommandLineParser::Float, "Binsize", "Define the size of the used bins", us::Any()); + +} +void mitk::AbstractGlobalImageFeature::InitializeQuantifier(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList, unsigned int defaultBins) +{ + bool useBins = false; + unsigned int bins = 0; + + bool useBinsize = false; + double binsize = 0; + + bool useMinimum = false; + double minimum = 0; + + bool useMaximum = false; + double maximum = 0; + + auto parsedArgs = GetParameter(); + std::string name = GetOptionPrefix(); + + if (parsedArgs.count("bins")) + { + bins = us::any_cast(parsedArgs["bins"]); + useBins = true; + } + if (parsedArgs.count(name + "::bins")) + { + bins = us::any_cast(parsedArgs[name + "::bins"]); + useBins = true; + } + if (parsedArgs.count("binsize")) + { + binsize = us::any_cast(parsedArgs["binsize"]); + useBinsize = true; + } + if (parsedArgs.count(name + "::binsize")) + { + binsize = us::any_cast(parsedArgs[name + "::binsize"]); + useBinsize = true; + } + if (parsedArgs.count("minimum-intensity")) + { + minimum = us::any_cast(parsedArgs["minimum-intensity"]); + useMinimum = true; + } + if (parsedArgs.count(name + "::minimum")) + { + minimum = us::any_cast(parsedArgs[name + "::minimum"]); + useMinimum = true; + } + if (parsedArgs.count("maximum-intensity")) + { + maximum = us::any_cast(parsedArgs["maximum-intensity"]); + useMaximum = true; + } + if (parsedArgs.count(name + "::maximum")) + { + maximum = us::any_cast(parsedArgs[name + "::maximum"]); + useMaximum = true; + } + + MITK_INFO << useMinimum << " " << useMaximum << " " << useBins << " " << useBinsize; + + m_Quantifier = IntensityQuantifier::New(); + if (useMinimum && useMaximum && useBinsize) + m_Quantifier->InitializeByBinsizeAndMaximum(minimum, maximum, binsize); + else if (useMinimum && useBins && useBinsize) + m_Quantifier->InitializeByBinsizeAndBins(minimum, bins, binsize); + else if (useMinimum && useMaximum && useBins) + m_Quantifier->InitializeByMinimumMaximum(minimum, maximum, bins); + else if (useBinsize) + m_Quantifier->InitializeByImageRegionAndBinsize(feature, mask, binsize); + else if (useBins) + m_Quantifier->InitializeByImageRegion(feature, mask, bins); + else + m_Quantifier->InitializeByImage(feature, defaultBins); +} diff --git a/Modules/Classification/CLCore/src/mitkIntensityQuantifier.cpp b/Modules/Classification/CLCore/src/mitkIntensityQuantifier.cpp new file mode 100644 index 0000000000..ef731a28b4 --- /dev/null +++ b/Modules/Classification/CLCore/src/mitkIntensityQuantifier.cpp @@ -0,0 +1,151 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +// STD +#include + +// ITK +#include + +// MITK +#include +#include + +template +static void +CalculateImageMinMax(itk::Image* itkImage, double &minimum, double &maximum) +{ + typedef itk::Image ImageType; + + minimum = std::numeric_limits::max(); + maximum = std::numeric_limits::lowest(); + + itk::ImageRegionConstIterator iter(itkImage, itkImage->GetLargestPossibleRegion()); + + while (!iter.IsAtEnd()) + { + minimum = std::min(minimum, iter.Get()); + maximum = std::max(maximum, iter.Get()); + ++iter; + } +} + +template +static void +CalculateImageRegionMinMax(itk::Image* itkImage, mitk::Image::Pointer mask, double &minimum, double &maximum) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + + typename MaskType::Pointer itkMask = MaskType::New(); + mitk::CastToItkImage(mask, itkMask); + + minimum = std::numeric_limits::max(); + maximum = std::numeric_limits::lowest(); + + itk::ImageRegionConstIterator iter(itkImage, itkImage->GetLargestPossibleRegion()); + itk::ImageRegionConstIterator maskIter(itkMask, itkMask->GetLargestPossibleRegion()); + + while (!iter.IsAtEnd()) + { + if (maskIter.Get() > 0) + { + minimum = std::min(minimum, iter.Get()); + maximum = std::max(maximum, iter.Get()); + } + ++iter; + ++maskIter; + } +} + +mitk::IntensityQuantifier::IntensityQuantifier() : + m_Initialized(false), + m_Bins(0), + m_Binsize(0), + m_Minimum(0), + m_Maximum(0) +{} + +void mitk::IntensityQuantifier::InitializeByMinimumMaximum(double minimum, double maximum, unsigned int bins) { + m_Minimum = minimum; + m_Maximum = maximum; + m_Bins = bins; + m_Binsize = (maximum - minimum) / bins; + m_Initialized = true; +} + +void mitk::IntensityQuantifier::InitializeByBinsizeAndBins(double minimum, unsigned int bins, double binsize) { + m_Minimum = minimum; + m_Maximum = minimum + bins*binsize; + m_Bins = bins; + m_Binsize = binsize; + m_Initialized = true; +} + +void mitk::IntensityQuantifier::InitializeByBinsizeAndMaximum(double minimum, double maximum, double binsize) { + m_Minimum = minimum; + m_Bins = std::ceil((maximum - minimum) / binsize); + m_Maximum = minimum + m_Bins*binsize; + m_Binsize = binsize; + m_Initialized = true; +} + +void mitk::IntensityQuantifier::InitializeByImage(mitk::Image::Pointer image, unsigned int bins) { + double minimum, maximum; + AccessByItk_2(image, CalculateImageMinMax, minimum, maximum); + InitializeByMinimumMaximum(minimum, maximum, bins); +} + +void mitk::IntensityQuantifier::InitializeByImageRegion(mitk::Image::Pointer image, mitk::Image::Pointer mask, unsigned int bins) { + double minimum, maximum; + AccessByItk_3(image, CalculateImageRegionMinMax, mask, minimum, maximum); + InitializeByMinimumMaximum(minimum, maximum, bins); +} + +void mitk::IntensityQuantifier::InitializeByImageAndBinsize(mitk::Image::Pointer image, double binsize) { + double minimum, maximum; + AccessByItk_2(image, CalculateImageMinMax, minimum, maximum); + InitializeByBinsizeAndMaximum(minimum, maximum, binsize); +} + +void mitk::IntensityQuantifier::InitializeByImageRegionAndBinsize(mitk::Image::Pointer image, mitk::Image::Pointer mask, double binsize) { + double minimum, maximum; + AccessByItk_3(image, CalculateImageRegionMinMax, mask, minimum, maximum); + InitializeByBinsizeAndMaximum(minimum, maximum, binsize); +} + +unsigned int mitk::IntensityQuantifier::IntensityToIndex(double intensity) +{ + double index = std::floor((intensity - m_Minimum) / m_Binsize); + return std::min(index, m_Bins-1); +} + +double mitk::IntensityQuantifier::IndexToMinimumIntensity(unsigned int index) +{ + return index*m_Binsize + m_Minimum; +} + +double mitk::IntensityQuantifier::IndexToMeanIntensity(unsigned int index) +{ + return (index + 0.5) * m_Binsize + m_Minimum; +} + +double mitk::IntensityQuantifier::IndexToMaximumIntensity(unsigned int index) +{ + return (index + 1) * m_Binsize + m_Minimum; +} diff --git a/Modules/Classification/CLMiniApps/CLDicom2Nrrd.cpp b/Modules/Classification/CLMiniApps/CLDicom2Nrrd.cpp index cb069d96c0..07625c4784 100644 --- a/Modules/Classification/CLMiniApps/CLDicom2Nrrd.cpp +++ b/Modules/Classification/CLMiniApps/CLDicom2Nrrd.cpp @@ -1,108 +1,88 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDicomSeriesReader.h" #include "mitkProperties.h" #include "mitkCommandLineParser.h" #include "mitkIOUtil.h" +#include "mitkPreferenceListReaderOptionsFunctor.h" + int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Dicom Loader"); parser.setCategory("Preprocessing Tools"); parser.setDescription(""); parser.setContributor("MBI"); parser.setArgumentPrefix("--","-"); // Add command line argument names parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text"); parser.addArgument("input", "i", mitkCommandLineParser::InputDirectory, "Input folder:", "Input folder",us::Any(),false); - parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file",us::Any(),false); + parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file", us::Any(), false); + parser.addArgument("reader", "r", mitkCommandLineParser::String, "Reader Name", "Reader Name", us::Any(), false); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; // Show a help message if ( parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } std::string inputFolder = us::any_cast(parsedArgs["input"]); std::string outFileName = us::any_cast(parsedArgs["output"]); - - /* - //check if DICOMTags have been set as property for mitk::Image - mitk::DicomSeriesReader::FileNamesGrouping seriesInFiles = mitk::DicomSeriesReader::GetSeries( inputFolder, true ); - std::list images; - std::map fileMap; - - // TODO sort series UIDs, implementation of map iterator might differ on different platforms (or verify this is a standard topic??) - for (mitk::DicomSeriesReader::FileNamesGrouping::const_iterator seriesIter = seriesInFiles.begin(); - seriesIter != seriesInFiles.end(); - ++seriesIter) + //mitk::PreferenceListReaderOptionsFunctor::ListType preference = { "MITK DICOM Reader v2 (classic config)" }; + mitk::PreferenceListReaderOptionsFunctor::ListType preference = {}; + if (parsedArgs.count("reader")) { - mitk::DicomSeriesReader::StringContainer files = seriesIter->second.GetFilenames(); - - mitk::DataNode::Pointer node = mitk::DicomSeriesReader::LoadDicomSeries( files ); - - if (node.IsNotNull()) - { - mitk::Image::Pointer image = dynamic_cast( node->GetData() ); - - images.push_back( image ); - fileMap.insert( std::pair(image,files)); - } + preference.push_back(us::any_cast(parsedArgs["reader"])); } - */ + mitk::PreferenceListReaderOptionsFunctor::ListType emptyList = {}; + mitk::IOUtil::LoadInfo info(inputFolder); + mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(preference, emptyList); + functor(info); + std::string extension = itksys::SystemTools::GetFilenameExtension(outFileName); std::string filename = itksys::SystemTools::GetFilenameWithoutExtension(outFileName); std::string path = itksys::SystemTools::GetFilenamePath(outFileName); - auto nodes = mitk::IOUtil::Load(inputFolder); + auto nodes = mitk::IOUtil::Load(inputFolder, &functor); unsigned count = 0; for (auto node : nodes) { std::string writeName = path + "/" + filename + extension; if (count > 0) { writeName = path + "/" + filename + "_" + std::to_string(count) + extension; } mitk::IOUtil::Save(node, writeName); ++count; } - /* - // WARN: EXPECT ONLY ONE ITEM PER FOLDER - for ( std::list::const_iterator imageIter = images.begin(); - imageIter != images.end(); - ++imageIter ) - { - const mitk::Image::Pointer image = *imageIter; - mitk::IOUtil::Save(image,outFileName); - }*/ return EXIT_SUCCESS; } diff --git a/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp b/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp index 2cc4b252a0..4e5c567faa 100644 --- a/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp +++ b/Modules/Classification/CLMiniApps/CLGlobalImageFeatures.cpp @@ -1,666 +1,745 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkCLPolyToNrrd_cpp #define mitkCLPolyToNrrd_cpp #include "time.h" #include #include #include #include "mitkCommandLineParser.h" #include #include #include #include #include #include +#include #include +#include #include +#include +#include +#include +#include +#include #include #include #include #include #include #include +#include + +#include +#include #include #include #include "itkNearestNeighborInterpolateImageFunction.h" #include "itkResampleImageFilter.h" #include #include #include "QmitkRegisterClasses.h" #include "QmitkRenderWindow.h" #include "vtkRenderLargeImage.h" #include "vtkPNGWriter.h" typedef itk::Image< double, 3 > FloatImageType; typedef itk::Image< unsigned char, 3 > MaskImageType; +template +class punct_facet : public std::numpunct { +public: + punct_facet(charT sep) : + m_Sep(sep) + { + + } +protected: + charT do_decimal_point() const { return m_Sep; } +private: + charT m_Sep; +}; + template void ResampleImage(itk::Image* itkImage, float resolution, mitk::Image::Pointer& newImage) { typedef itk::Image ImageType; typedef itk::ResampleImageFilter ResampleFilterType; typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); auto spacing = itkImage->GetSpacing(); auto size = itkImage->GetLargestPossibleRegion().GetSize(); for (unsigned int i = 0; i < VImageDimension; ++i) { size[i] = size[i] / (1.0*resolution)*(1.0*spacing[i])+1.0; } spacing.Fill(resolution); resampler->SetInput(itkImage); resampler->SetSize(size); resampler->SetOutputSpacing(spacing); resampler->SetOutputOrigin(itkImage->GetOrigin()); resampler->SetOutputDirection(itkImage->GetDirection()); resampler->Update(); newImage->InitializeByItk(resampler->GetOutput()); mitk::GrabItkImageMemory(resampler->GetOutput(), newImage); } template static void CreateNoNaNMask(itk::Image* itkValue, mitk::Image::Pointer mask, mitk::Image::Pointer& newMask) { typedef itk::Image< TPixel, VImageDimension> LFloatImageType; typedef itk::Image< unsigned char, VImageDimension> LMaskImageType; typename LMaskImageType::Pointer itkMask = LMaskImageType::New(); mitk::CastToItkImage(mask, itkMask); typedef itk::ImageDuplicator< LMaskImageType > DuplicatorType; typename DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage(itkMask); duplicator->Update(); auto tmpMask = duplicator->GetOutput(); itk::ImageRegionIterator mask1Iter(itkMask, itkMask->GetLargestPossibleRegion()); itk::ImageRegionIterator mask2Iter(tmpMask, tmpMask->GetLargestPossibleRegion()); itk::ImageRegionIterator imageIter(itkValue, itkValue->GetLargestPossibleRegion()); while (!mask1Iter.IsAtEnd()) { mask2Iter.Set(0); if (mask1Iter.Value() > 0) { // Is not NaN if (imageIter.Value() == imageIter.Value()) { mask2Iter.Set(1); } } ++mask1Iter; ++mask2Iter; ++imageIter; } newMask->InitializeByItk(tmpMask); mitk::GrabItkImageMemory(tmpMask, newMask); } template static void ResampleMask(itk::Image* itkMoving, mitk::Image::Pointer ref, mitk::Image::Pointer& newMask) { typedef itk::Image< TPixel, VImageDimension> LMaskImageType; typedef itk::NearestNeighborInterpolateImageFunction< LMaskImageType> NearestNeighborInterpolateImageFunctionType; typedef itk::ResampleImageFilter ResampleFilterType; typename NearestNeighborInterpolateImageFunctionType::Pointer nn_interpolator = NearestNeighborInterpolateImageFunctionType::New(); typename LMaskImageType::Pointer itkRef = LMaskImageType::New(); mitk::CastToItkImage(ref, itkRef); typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); resampler->SetInput(itkMoving); resampler->SetReferenceImage(itkRef); resampler->UseReferenceImageOn(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); newMask->InitializeByItk(resampler->GetOutput()); mitk::GrabItkImageMemory(resampler->GetOutput(), newMask); } static void -ExtractSlicesFromImages(mitk::Image::Pointer image, mitk::Image::Pointer mask, mitk::Image::Pointer maskNoNaN, +ExtractSlicesFromImages(mitk::Image::Pointer image, mitk::Image::Pointer mask, + mitk::Image::Pointer maskNoNaN, mitk::Image::Pointer morphMask, int direction, std::vector &imageVector, std::vector &maskVector, - std::vector &maskNoNaNVector) + std::vector &maskNoNaNVector, + std::vector &morphMaskVector) { typedef itk::Image< double, 2 > FloatImage2DType; typedef itk::Image< unsigned char, 2 > MaskImage2DType; FloatImageType::Pointer itkFloat = FloatImageType::New(); MaskImageType::Pointer itkMask = MaskImageType::New(); MaskImageType::Pointer itkMaskNoNaN = MaskImageType::New(); + MaskImageType::Pointer itkMorphMask = MaskImageType::New(); mitk::CastToItkImage(mask, itkMask); mitk::CastToItkImage(maskNoNaN, itkMaskNoNaN); mitk::CastToItkImage(image, itkFloat); + mitk::CastToItkImage(morphMask, itkMorphMask); int idxA, idxB, idxC; switch (direction) { case 0: idxA = 1; idxB = 2; idxC = 0; break; case 1: idxA = 0; idxB = 2; idxC = 1; break; case 2: idxA = 0; idxB = 1; idxC = 2; break; default: idxA = 1; idxB = 2; idxC = 0; break; } auto imageSize = image->GetLargestPossibleRegion().GetSize(); FloatImageType::IndexType index3D; FloatImage2DType::IndexType index2D; FloatImage2DType::SpacingType spacing2D; spacing2D[0] = itkFloat->GetSpacing()[idxA]; spacing2D[1] = itkFloat->GetSpacing()[idxB]; for (unsigned int i = 0; i < imageSize[idxC]; ++i) { FloatImage2DType::RegionType region; FloatImage2DType::IndexType start; FloatImage2DType::SizeType size; start[0] = 0; start[1] = 0; size[0] = imageSize[idxA]; size[1] = imageSize[idxB]; region.SetIndex(start); region.SetSize(size); FloatImage2DType::Pointer image2D = FloatImage2DType::New(); image2D->SetRegions(region); image2D->Allocate(); MaskImage2DType::Pointer mask2D = MaskImage2DType::New(); mask2D->SetRegions(region); mask2D->Allocate(); MaskImage2DType::Pointer masnNoNaN2D = MaskImage2DType::New(); masnNoNaN2D->SetRegions(region); masnNoNaN2D->Allocate(); + MaskImage2DType::Pointer morph2D = MaskImage2DType::New(); + morph2D->SetRegions(region); + morph2D->Allocate(); + + unsigned long voxelsInMask = 0; for (unsigned int a = 0; a < imageSize[idxA]; ++a) { for (unsigned int b = 0; b < imageSize[idxB]; ++b) { index3D[idxA] = a; index3D[idxB] = b; index3D[idxC] = i; index2D[0] = a; index2D[1] = b; image2D->SetPixel(index2D, itkFloat->GetPixel(index3D)); mask2D->SetPixel(index2D, itkMask->GetPixel(index3D)); masnNoNaN2D->SetPixel(index2D, itkMaskNoNaN->GetPixel(index3D)); + morph2D->SetPixel(index2D, itkMorphMask->GetPixel(index3D)); voxelsInMask += (itkMask->GetPixel(index3D) > 0) ? 1 : 0; } } image2D->SetSpacing(spacing2D); mask2D->SetSpacing(spacing2D); masnNoNaN2D->SetSpacing(spacing2D); + morph2D->SetSpacing(spacing2D); mitk::Image::Pointer tmpFloatImage = mitk::Image::New(); tmpFloatImage->InitializeByItk(image2D.GetPointer()); mitk::GrabItkImageMemory(image2D, tmpFloatImage); mitk::Image::Pointer tmpMaskImage = mitk::Image::New(); tmpMaskImage->InitializeByItk(mask2D.GetPointer()); mitk::GrabItkImageMemory(mask2D, tmpMaskImage); mitk::Image::Pointer tmpMaskNoNaNImage = mitk::Image::New(); tmpMaskNoNaNImage->InitializeByItk(masnNoNaN2D.GetPointer()); mitk::GrabItkImageMemory(masnNoNaN2D, tmpMaskNoNaNImage); + mitk::Image::Pointer tmpMorphMaskImage = mitk::Image::New(); + tmpMorphMaskImage->InitializeByItk(morph2D.GetPointer()); + mitk::GrabItkImageMemory(morph2D, tmpMorphMaskImage); + if (voxelsInMask > 0) { imageVector.push_back(tmpFloatImage); maskVector.push_back(tmpMaskImage); maskNoNaNVector.push_back(tmpMaskNoNaNImage); + morphMaskVector.push_back(tmpMorphMaskImage); } } } static void SaveSliceOrImageAsPNG(mitk::Image::Pointer image, mitk::Image::Pointer mask, std::string path, int index) { // Create a Standalone Datastorage for the single purpose of saving screenshots.. mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); QmitkRenderWindow renderWindow; renderWindow.GetRenderer()->SetDataStorage(ds); auto nodeI = mitk::DataNode::New(); nodeI->SetData(image); auto nodeM = mitk::DataNode::New(); nodeM->SetData(mask); ds->Add(nodeI); ds->Add(nodeM); mitk::TimeGeometry::Pointer geo = ds->ComputeBoundingGeometry3D(ds->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews(geo); mitk::SliceNavigationController::Pointer sliceNaviController = renderWindow.GetSliceNavigationController(); unsigned int numberOfSteps = 1; if (sliceNaviController) { numberOfSteps = sliceNaviController->GetSlice()->GetSteps(); sliceNaviController->GetSlice()->SetPos(0); } renderWindow.show(); renderWindow.resize(256, 256); for (unsigned int currentStep = 0; currentStep < numberOfSteps; ++currentStep) { if (sliceNaviController) { sliceNaviController->GetSlice()->SetPos(currentStep); } renderWindow.GetRenderer()->PrepareRender(); vtkRenderWindow* renderWindow2 = renderWindow.GetVtkRenderWindow(); mitk::BaseRenderer* baserenderer = mitk::BaseRenderer::GetInstance(renderWindow2); auto vtkRender = baserenderer->GetVtkRenderer(); vtkRender->GetRenderWindow()->WaitForCompletion(); vtkRenderLargeImage* magnifier = vtkRenderLargeImage::New(); magnifier->SetInput(vtkRender); magnifier->SetMagnification(3.0); std::stringstream ss; ss << path << "_Idx-" << index << "_Step-"<> tmpImageName; auto fileWriter = vtkPNGWriter::New(); fileWriter->SetInputConnection(magnifier->GetOutputPort()); fileWriter->SetFileName(tmpImageName.c_str()); fileWriter->Write(); fileWriter->Delete(); } } int main(int argc, char* argv[]) { - + mitk::GIFImageDescriptionFeatures::Pointer ipCalculator = mitk::GIFImageDescriptionFeatures::New(); mitk::GIFFirstOrderStatistics::Pointer firstOrderCalculator = mitk::GIFFirstOrderStatistics::New(); + mitk::GIFFirstOrderHistogramStatistics::Pointer firstOrderHistoCalculator = mitk::GIFFirstOrderHistogramStatistics::New(); mitk::GIFVolumetricStatistics::Pointer volCalculator = mitk::GIFVolumetricStatistics::New(); + mitk::GIFVolumetricDensityStatistics::Pointer voldenCalculator = mitk::GIFVolumetricDensityStatistics::New(); mitk::GIFCooccurenceMatrix::Pointer coocCalculator = mitk::GIFCooccurenceMatrix::New(); mitk::GIFCooccurenceMatrix2::Pointer cooc2Calculator = mitk::GIFCooccurenceMatrix2::New(); mitk::GIFNeighbouringGreyLevelDependenceFeature::Pointer ngldCalculator = mitk::GIFNeighbouringGreyLevelDependenceFeature::New(); mitk::GIFGrayLevelRunLength::Pointer rlCalculator = mitk::GIFGrayLevelRunLength::New(); mitk::GIFGreyLevelSizeZone::Pointer glszCalculator = mitk::GIFGreyLevelSizeZone::New(); + mitk::GIFGreyLevelDistanceZone::Pointer gldzCalculator = mitk::GIFGreyLevelDistanceZone::New(); + mitk::GIFLocalIntensity::Pointer lociCalculator = mitk::GIFLocalIntensity::New(); + mitk::GIFIntensityVolumeHistogramFeatures::Pointer ivohCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); + mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::Pointer ngtdCalculator = mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::New(); std::vector features; - features.push_back(firstOrderCalculator.GetPointer()); features.push_back(volCalculator.GetPointer()); + features.push_back(voldenCalculator.GetPointer()); + features.push_back(firstOrderCalculator.GetPointer()); + features.push_back(firstOrderHistoCalculator.GetPointer()); + features.push_back(ivohCalculator.GetPointer()); + features.push_back(lociCalculator.GetPointer()); features.push_back(coocCalculator.GetPointer()); features.push_back(cooc2Calculator.GetPointer()); features.push_back(ngldCalculator.GetPointer()); features.push_back(rlCalculator.GetPointer()); features.push_back(glszCalculator.GetPointer()); + features.push_back(gldzCalculator.GetPointer()); + features.push_back(ipCalculator.GetPointer()); + features.push_back(ngtdCalculator.GetPointer()); mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); mitk::cl::GlobalImageFeaturesParameter param; param.AddParameter(parser); parser.addArgument("--","-", mitkCommandLineParser::String, "---", "---", us::Any(),true); for (auto cFeature : features) { cFeature->AddArguments(parser); } parser.addArgument("--", "-", mitkCommandLineParser::String, "---", "---", us::Any(), true); parser.addArgument("description","d",mitkCommandLineParser::String,"Text","Description that is added to the output",us::Any()); parser.addArgument("direction", "dir", mitkCommandLineParser::String, "Int", "Allows to specify the direction for Cooc and RL. 0: All directions, 1: Only single direction (Test purpose), 2,3,4... Without dimension 0,1,2... ", us::Any()); parser.addArgument("slice-wise", "slice", mitkCommandLineParser::String, "Int", "Allows to specify if the image is processed slice-wise (number giving direction) ", us::Any()); parser.addArgument("output-mode", "omode", mitkCommandLineParser::Int, "Int", "Defines if the results of an image / slice are written in a single row (0 , default) or column (1)."); // Miniapp Infos parser.setCategory("Classification Tools"); parser.setTitle("Global Image Feature calculator"); parser.setDescription("Calculates different global statistics for a given segmentation / image combination"); parser.setContributor("MBI"); std::map parsedArgs = parser.parseArguments(argc, argv); param.ParseParameter(parsedArgs); if (parsedArgs.size()==0) { return EXIT_FAILURE; } if ( parsedArgs.count("help") || parsedArgs.count("h")) { return EXIT_SUCCESS; } //bool savePNGofSlices = true; - std::string folderForPNGOfSlices = "E:\\tmp\\bonekamp\\fig\\"; + //std::string folderForPNGOfSlices = "E:\\tmp\\bonekamp\\fig\\"; - std::string version = "Version: 1.20"; + std::string version = "Version: 1.21"; MITK_INFO << version; std::ofstream log; if (param.useLogfile) { log.open(param.logfilePath, std::ios::app); log << version; log << "Image: " << param.imagePath; log << "Mask: " << param.maskPath; } + + if (param.useDecimalPoint) + { + std::cout.imbue(std::locale(std::cout.getloc(), new punct_facet(param.decimalPoint))); + } + mitk::Image::Pointer image; mitk::Image::Pointer mask; mitk::Image::Pointer tmpImage = mitk::IOUtil::LoadImage(param.imagePath); mitk::Image::Pointer tmpMask = mitk::IOUtil::LoadImage(param.maskPath); image = tmpImage; mask = tmpMask; + mitk::Image::Pointer morphMask = mask; + if (param.useMorphMask) + { + morphMask = mitk::IOUtil::LoadImage(param.morphPath); + } + if ((image->GetDimension() != mask->GetDimension())) { MITK_INFO << "Dimension of image does not match. "; MITK_INFO << "Correct one image, may affect the result"; if (image->GetDimension() == 2) { mitk::Convert2Dto3DImageFilter::Pointer multiFilter2 = mitk::Convert2Dto3DImageFilter::New(); multiFilter2->SetInput(tmpImage); multiFilter2->Update(); image = multiFilter2->GetOutput(); } if (mask->GetDimension() == 2) { mitk::Convert2Dto3DImageFilter::Pointer multiFilter3 = mitk::Convert2Dto3DImageFilter::New(); multiFilter3->SetInput(tmpMask); multiFilter3->Update(); mask = multiFilter3->GetOutput(); } } int writeDirection = 0; if (parsedArgs.count("output-mode")) { writeDirection = us::any_cast(parsedArgs["output-mode"]); } if (param.resampleToFixIsotropic) { mitk::Image::Pointer newImage = mitk::Image::New(); AccessByItk_2(image, ResampleImage, param.resampleResolution, newImage); image = newImage; } if ( ! mitk::Equal(mask->GetGeometry(0)->GetOrigin(), image->GetGeometry(0)->GetOrigin())) { MITK_INFO << "Not equal Origins"; if (param.ensureSameSpace) { MITK_INFO << "Warning!"; MITK_INFO << "The origin of the input image and the mask do not match. They are"; MITK_INFO << "now corrected. Please check to make sure that the images still match"; image->GetGeometry(0)->SetOrigin(mask->GetGeometry(0)->GetOrigin()); } else { return -1; } } if (param.resampleMask) { mitk::Image::Pointer newMaskImage = mitk::Image::New(); AccessByItk_2(mask, ResampleMask, image, newMaskImage); mask = newMaskImage; } if ( ! mitk::Equal(mask->GetGeometry(0)->GetSpacing(), image->GetGeometry(0)->GetSpacing())) { MITK_INFO << "Not equal Sapcings"; if (param.ensureSameSpace) { MITK_INFO << "Warning!"; MITK_INFO << "The spacing of the mask was set to match the spacing of the input image."; MITK_INFO << "This might cause unintended spacing of the mask image"; image->GetGeometry(0)->SetSpacing(mask->GetGeometry(0)->GetSpacing()); } else { MITK_INFO << "The spacing of the mask and the input images is not equal."; MITK_INFO << "Terminating the programm. You may use the '-fi' option"; return -1; } } int direction = 0; if (parsedArgs.count("direction")) { direction = mitk::cl::splitDouble(parsedArgs["direction"].ToString(), ';')[0]; } MITK_INFO << "Start creating Mask without NaN"; mitk::Image::Pointer maskNoNaN = mitk::Image::New(); AccessByItk_2(image, CreateNoNaNMask, mask, maskNoNaN); //CreateNoNaNMask(mask, image, maskNoNaN); bool sliceWise = false; int sliceDirection = 0; unsigned int currentSlice = 0; bool imageToProcess = true; std::vector floatVector; std::vector maskVector; std::vector maskNoNaNVector; + std::vector morphMaskVector; if ((parsedArgs.count("slice-wise")) && image->GetDimension() > 2) { MITK_INFO << "Enabled slice-wise"; sliceWise = true; sliceDirection = mitk::cl::splitDouble(parsedArgs["slice-wise"].ToString(), ';')[0]; MITK_INFO << sliceDirection; - ExtractSlicesFromImages(image, mask, maskNoNaN, sliceDirection, floatVector, maskVector, maskNoNaNVector); + ExtractSlicesFromImages(image, mask, maskNoNaN, morphMask, sliceDirection, floatVector, maskVector, maskNoNaNVector, morphMaskVector); MITK_INFO << "Slice"; } for (auto cFeature : features) { if (param.defineGlobalMinimumIntensity) { cFeature->SetMinimumIntensity(param.globalMinimumIntensity); cFeature->SetUseMinimumIntensity(true); } if (param.defineGlobalMaximumIntensity) { cFeature->SetMaximumIntensity(param.globalMaximumIntensity); cFeature->SetUseMaximumIntensity(true); } if (param.defineGlobalNumberOfBins) { cFeature->SetBins(param.globalNumberOfBins); MITK_INFO << param.globalNumberOfBins; } cFeature->SetParameter(parsedArgs); cFeature->SetDirection(direction); } bool addDescription = parsedArgs.count("description"); mitk::cl::FeatureResultWritter writer(param.outputPath, writeDirection); + if (param.useDecimalPoint) + { + writer.SetDecimalPoint(param.decimalPoint); + } + std::string description = ""; if (addDescription) { description = parsedArgs["description"].ToString(); } mitk::Image::Pointer cImage = image; mitk::Image::Pointer cMask = mask; mitk::Image::Pointer cMaskNoNaN = maskNoNaN; + mitk::Image::Pointer cMorphMask = morphMask; if (param.useHeader) { + writer.AddColumn("SoftwareVersion"); writer.AddColumn("Patient"); writer.AddColumn("Image"); writer.AddColumn("Segmentation"); } // Create a QTApplication and a Datastorage // This is necessary in order to save screenshots of // each image / slice. QApplication qtapplication(argc, argv); QmitkRegisterClasses(); std::vector allStats; while (imageToProcess) { if (sliceWise) { cImage = floatVector[currentSlice]; cMask = maskVector[currentSlice]; cMaskNoNaN = maskNoNaNVector[currentSlice]; + cMorphMask = morphMaskVector[currentSlice]; imageToProcess = (floatVector.size()-1 > (currentSlice)) ? true : false ; } else { imageToProcess = false; } if (param.writePNGScreenshots) { SaveSliceOrImageAsPNG(cImage, cMask, param.pngScreenshotsPath, currentSlice); } if (param.writeAnalysisImage) { mitk::IOUtil::Save(cImage, param.anaylsisImagePath); } if (param.writeAnalysisMask) { mitk::IOUtil::Save(cMask, param.analysisMaskPath); } mitk::AbstractGlobalImageFeature::FeatureListType stats; for (auto cFeature : features) { + cFeature->SetMorphMask(cMorphMask); cFeature->CalculateFeaturesUsingParameters(cImage, cMask, cMaskNoNaN, stats); } for (std::size_t i = 0; i < stats.size(); ++i) { std::cout << stats[i].first << " - " << stats[i].second << std::endl; } writer.AddHeader(description, currentSlice, stats, param.useHeader, addDescription); if (true) { - writer.AddColumn(param.imageFolder); - writer.AddColumn(param.imageName); - writer.AddColumn(param.maskName); + writer.AddSubjectInformation(MITK_REVISION); + writer.AddSubjectInformation(param.imageFolder); + writer.AddSubjectInformation(param.imageName); + writer.AddSubjectInformation(param.maskName); } writer.AddResult(description, currentSlice, stats, param.useHeader, addDescription); allStats.push_back(stats); ++currentSlice; } if (sliceWise) { mitk::AbstractGlobalImageFeature::FeatureListType statMean, statStd; for (std::size_t i = 0; i < allStats[0].size(); ++i) { auto cElement1 = allStats[0][i]; cElement1.first = "SliceWise Mean " + cElement1.first; cElement1.second = 0.0; auto cElement2 = allStats[0][i]; cElement2.first = "SliceWise Var. " + cElement2.first; cElement2.second = 0.0; statMean.push_back(cElement1); statStd.push_back(cElement2); } for (auto cStat : allStats) { for (std::size_t i = 0; i < cStat.size(); ++i) { statMean[i].second += cStat[i].second / (1.0*allStats.size()); } } for (auto cStat : allStats) { for (std::size_t i = 0; i < cStat.size(); ++i) { statStd[i].second += (cStat[i].second - statMean[i].second)*(cStat[i].second - statMean[i].second) / (1.0*allStats.size()); } } for (std::size_t i = 0; i < statMean.size(); ++i) { std::cout << statMean[i].first << " - " << statMean[i].second << std::endl; std::cout << statStd[i].first << " - " << statStd[i].second << std::endl; } if (true) { - writer.AddColumn(param.imageFolder); - writer.AddColumn(param.imageName); - writer.AddColumn(param.maskName + " - Mean"); + writer.AddSubjectInformation(MITK_REVISION); + writer.AddSubjectInformation(param.imageFolder); + writer.AddSubjectInformation(param.imageName); + writer.AddSubjectInformation(param.maskName + " - Mean"); } writer.AddResult(description, currentSlice, statMean, param.useHeader, addDescription); if (true) { - writer.AddColumn(param.imageFolder); - writer.AddColumn(param.imageName); - writer.AddColumn(param.maskName + " - Var."); + writer.AddSubjectInformation(MITK_REVISION); + writer.AddSubjectInformation(param.imageFolder); + writer.AddSubjectInformation(param.imageName); + writer.AddSubjectInformation(param.maskName + " - Var."); } writer.AddResult(description, currentSlice, statStd, param.useHeader, addDescription); } if (param.useLogfile) { log << "Finished calculation"; log.close(); } return 0; } #endif diff --git a/Modules/Classification/CLMiniApps/CLMatchPointReg.cpp b/Modules/Classification/CLMiniApps/CLMatchPointReg.cpp new file mode 100644 index 0000000000..35bc660048 --- /dev/null +++ b/Modules/Classification/CLMiniApps/CLMatchPointReg.cpp @@ -0,0 +1,174 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkDicomSeriesReader.h" +#include "mitkProperties.h" + +#include "mitkCommandLineParser.h" +#include "mitkIOUtil.h" + +#include "mitkPreferenceListReaderOptionsFunctor.h" + + +// MatchPoint +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +// Qt +#include +#include +#include +//#include +#include +#include +#include +#include + + +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + + parser.setTitle("Dicom Loader"); + parser.setCategory("Preprocessing Tools"); + parser.setDescription(""); + parser.setContributor("MBI"); + + parser.setArgumentPrefix("--","-"); + // Add command line argument names + parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text"); + parser.addArgument("moving", "m", mitkCommandLineParser::InputDirectory, "Input folder:", "Input folder", us::Any(), false); + parser.addArgument("fixed", "f", mitkCommandLineParser::InputDirectory, "Input folder:", "Input folder", us::Any(), false); + parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file", us::Any(), false); + parser.addArgument("reader", "r", mitkCommandLineParser::Int, "Reader ID", "Reader Name", us::Any(), false); + parser.addArgument("interpolation", "interp", mitkCommandLineParser::Int, "Reader ID", "Reader Name", us::Any(), false); + + //int selectedAlgorithm = 4; + //std::string movingFile = "E:\\Projects\\Myelom\\data\\0001622391R\\00.00.0000\\T2.nrrd"; + //std::string fixedFile = "E:\\Projects\\Myelom\\data\\0001622391R\\00.00.0000\\0001622391R_00.00.0000_T1KM_Resampled.nrrd"; + + + std::map parsedArgs = parser.parseArguments(argc, argv); + + QFileInfo fi(argv[0]); + map::deployment::DLLDirectoryBrowser::Pointer browser = map::deployment::DLLDirectoryBrowser::New(); + browser->addDLLSearchLocation(QDir::homePath().toStdString()); + browser->addDLLSearchLocation(QDir::currentPath().toStdString()); + browser->addDLLSearchLocation(fi.canonicalPath().toStdString()); + browser->update(); + auto dllList = browser->getLibraryInfos(); + + int id = 0; + std::cout << std::endl << " --- Algorithm List --- " << std::endl; + for (auto info : dllList) + { + std::cout << "Algorithm ID " << id << ": " << info->getAlgorithmUID().getName() << std::endl; + ++id; + } + std::cout << std::endl << " --- Interpolation List --- " << std::endl; + std::cout << "Interpolation ID 0: Linear Interpolation " << std::endl; + std::cout << "Interpolation ID 1: Nearest Neighbour" << std::endl; + std::cout << "Interpolation ID 2: BSpline 3D" << std::endl << std::endl; + + mitk::ImageMappingInterpolator::Type interpolationMode = mitk::ImageMappingInterpolator::Linear; + + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + // Show a help message + if ( parsedArgs.count("help") || parsedArgs.count("h")) + { + std::cout << parser.helpText(); + return EXIT_SUCCESS; + } + + + std::string movingFile = us::any_cast(parsedArgs["moving"]); + std::string fixedFile = us::any_cast(parsedArgs["fixed"]); + int selectedAlgorithm = us::any_cast(parsedArgs["reader"]); + std::string outputPath = us::any_cast(parsedArgs["output"]); + + if (parsedArgs.count("interpolation")) + { + switch (us::any_cast(parsedArgs["interpolation"])) + { + case 0: + interpolationMode = mitk::ImageMappingInterpolator::Linear; + break; + case 1: + interpolationMode = mitk::ImageMappingInterpolator::NearestNeighbor; + break; + case 2: + interpolationMode = mitk::ImageMappingInterpolator::BSpline_3; + break; + default: + interpolationMode = mitk::ImageMappingInterpolator::Linear; + } + } + + + mitk::Image::Pointer movingImage = dynamic_cast(mitk::IOUtil::Load(movingFile)[0].GetPointer()); + mitk::Image::Pointer fixedImage = dynamic_cast(mitk::IOUtil::Load(fixedFile)[0].GetPointer()); + + map::deployment::DLLInfo::ConstPointer dllInfo = dllList[selectedAlgorithm]; + + if (!dllInfo) + { + MITK_ERROR << "No valid algorithm is selected. Cannot load algorithm. ABORTING."; + return -1; + } + + ::map::deployment::DLLHandle::Pointer tempDLLHandle = ::map::deployment::openDeploymentDLL( + dllInfo->getLibraryFilePath()); + ::map::algorithm::RegistrationAlgorithmBase::Pointer tempAlgorithm + = ::map::deployment::getRegistrationAlgorithm(tempDLLHandle); + MITK_INFO << "Well...."; + if (tempAlgorithm.IsNull()) + { + MITK_ERROR << "Error. Cannot load selected algorithm."; + return -2; + } + + mitk::MITKAlgorithmHelper helper(tempAlgorithm); + helper.SetData(movingImage, fixedImage); + auto registration = helper.GetRegistration(); + MITK_INFO << "Well...."; + + mitk::Image::Pointer spResultData= mitk::ImageMappingHelper::map(movingImage, + registration, + false, // Use all Pixels + 0.0, // Padding Value + fixedImage->GetGeometry()->Clone().GetPointer(), // Ref. Geometry + false, //!(this->m_allowUnregPixels), + 0, // Error Value + mitk::ImageMappingInterpolator::BSpline_3 // Interpolator Type + ); + + MITK_INFO << "Well...."; + mitk::IOUtil::Save(spResultData, outputPath); + + return EXIT_SUCCESS; +} diff --git a/Modules/Classification/CLMiniApps/CMakeLists.txt b/Modules/Classification/CLMiniApps/CMakeLists.txt index af8f088c36..fe57ea9845 100644 --- a/Modules/Classification/CLMiniApps/CMakeLists.txt +++ b/Modules/Classification/CLMiniApps/CMakeLists.txt @@ -1,135 +1,140 @@ option(BUILD_ClassificationMiniApps "Build commandline tools for classification" OFF) if(BUILD_ClassificationMiniApps OR MITK_BUILD_ALL_APPS) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( classificationminiapps RandomForestTraining^^MitkCLVigraRandomForest NativeHeadCTSegmentation^^MitkCLVigraRandomForest ManualSegmentationEvaluation^^MitkCLVigraRandomForest CLScreenshot^^MitkCore_MitkQtWidgetsExt_MitkCLUtilities CLDicom2Nrrd^^MitkCore CLImageTypeConverter^^MitkCore CLResampleImageToReference^^MitkCore CLGlobalImageFeatures^^MitkCLUtilities_MitkQtWidgetsExt CLMRNormalization^^MitkCLUtilities_MitkCLMRUtilities CLStaple^^MitkCLUtilities CLVoxelFeatures^^MitkCLUtilities CLPolyToNrrd^^ CLSimpleVoxelClassification^^MitkDataCollection_MitkCLVigraRandomForest CLVoxelClassification^^MitkDataCollection_MitkCLImportanceWeighting_MitkCLVigraRandomForest CLBrainMask^^MitkCLUtilities XRaxSimulationFromCT^^MitkCLUtilities CLRandomSampling^^MitkCore_MitkCLUtilities CLRemoveEmptyVoxels^^MitkCore CLN4^^MitkCore CLMultiForestPrediction^^MitkDataCollection_MitkCLVigraRandomForest CLNrrdToPoly^^MitkCore CL2Dto3DImage^^MitkCore CLWeighting^^MitkCore_MitkCLImportanceWeighting_MitkCLUtilities CLOverlayRoiCenterOfMass^^MitkCore_MitkCLUtilities_MitkQtWidgetsExt CLLungSegmentation^^MitkCore_MitkSegmentation_MitkMultilabel # RandomForestPrediction^^MitkCLVigraRandomForest ) foreach(classificationminiapps ${classificationminiapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${classificationminiapps}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitk_create_executable(${appname} DEPENDS MitkCore MitkCLCore MitkCommandLine ${dependencies_list} PACKAGE_DEPENDS ITK Qt5|Core Vigra CPP_FILES ${appname}.cpp ) # CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp if(EXECUTABLE_IS_ENABLED) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) if(APPLE) if(_is_bundle) set(_target_locations ${EXECUTABLE_TARGET}.app) set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${EXECUTABLE_TARGET}) set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) endif() endif() endforeach() # This mini app does not depend on mitkDiffusionImaging at all + mitk_create_executable(CLMatchPointReg + DEPENDS MitkCore MitkCLUtilities MitkMatchPointRegistration MitkCommandLine MitkMatchPointRegistrationUI + PACKAGE_DEPENDS ITK Qt5|Core Vigra MatchPoint + CPP_FILES CLMatchPointReg.cpp + ) #mitk_create_executable(CLGlobalImageFeatures # DEPENDS MitkCore MitkCLUtilities # CPP_FILES CLGlobalImageFeatures.cpp mitkCommandLineParser.cpp #) #mitk_create_executable(CLBrainMask # DEPENDS MitkCore MitkCLUtilities # CPP_FILES CLBrainMask.cpp mitkCommandLineParser.cpp #) #mitk_create_executable(CLImageConverter # DEPENDS MitkCore # CPP_FILES CLImageConverter.cpp mitkCommandLineParser.cpp #) #mitk_create_executable(CLSurWeighting # DEPENDS MitkCore MitkCLUtilities MitkDataCollection #MitkCLImportanceWeighting # CPP_FILES CLSurWeighting.cpp mitkCommandLineParser.cpp #) #mitk_create_executable(CLImageCropper # DEPENDS MitkCore MitkCLUtilities MitkAlgorithmsExt # CPP_FILES CLImageCropper.cpp mitkCommandLineParser.cpp #) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/Classification/CLUtilities/files.cmake b/Modules/Classification/CLUtilities/files.cmake index 27aeaf329d..72f3cc8123 100644 --- a/Modules/Classification/CLUtilities/files.cmake +++ b/Modules/Classification/CLUtilities/files.cmake @@ -1,31 +1,38 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkCLResultWritter.cpp Algorithms/itkLabelSampler.cpp Algorithms/itkSmoothedClassProbabilites.cpp Algorithms/mitkRandomImageSampler.cpp Features/itkNeighborhoodFunctorImageFilter.cpp Features/itkLineHistogramBasedMassImageFilter.cpp GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp GlobalImageFeatures/mitkGIFGrayLevelRunLength.cpp GlobalImageFeatures/mitkGIFGrayLevelSizeZone.cpp + GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp + GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp GlobalImageFeatures/mitkGIFNeighbourhoodGreyLevelDifference.cpp GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp + GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp + GlobalImageFeatures/mitkGIFLocalIntensity.cpp + GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp + GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp + GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp MiniAppUtils/mitkSplitParameterToVector.cpp mitkCLUtil.cpp ) set( TOOL_FILES ) diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToRunLengthFeaturesFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToRunLengthFeaturesFilter.hxx index c38efff322..f4a702d76b 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToRunLengthFeaturesFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToRunLengthFeaturesFilter.hxx @@ -1,663 +1,662 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef __itkEnhancedHistogramToRunLengthFeaturesFilter_hxx #define __itkEnhancedHistogramToRunLengthFeaturesFilter_hxx #include "itkEnhancedHistogramToRunLengthFeaturesFilter.h" #include "itkNumericTraits.h" #include "vnl/vnl_math.h" namespace itk { namespace Statistics { //constructor template EnhancedHistogramToRunLengthFeaturesFilter ::EnhancedHistogramToRunLengthFeaturesFilter() : m_NumberOfVoxels(1) { this->ProcessObject::SetNumberOfRequiredInputs( 1 ); // allocate the data objects for the outputs which are // just decorators real types for( unsigned int i = 0; i < 17; i++ ) { this->ProcessObject::SetNthOutput( i, this->MakeOutput( i ) ); } } template void EnhancedHistogramToRunLengthFeaturesFilter< THistogram> ::SetInput( const HistogramType *histogram ) { this->ProcessObject::SetNthInput( 0, const_cast( histogram ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::HistogramType * EnhancedHistogramToRunLengthFeaturesFilter< THistogram> ::GetInput() const { if ( this->GetNumberOfInputs() < 1 ) { return ITK_NULLPTR; } return itkDynamicCastInDebugMode(this->ProcessObject::GetInput( 0 ) ); } template typename EnhancedHistogramToRunLengthFeaturesFilter::DataObjectPointer EnhancedHistogramToRunLengthFeaturesFilter ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed( idx ) ) { return MeasurementObjectType::New().GetPointer(); } template void EnhancedHistogramToRunLengthFeaturesFilter< THistogram>:: GenerateData( void ) { const HistogramType * inputHistogram = this->GetInput(); this->m_TotalNumberOfRuns = static_cast ( inputHistogram->GetTotalFrequency() ); MeasurementType shortRunEmphasis = NumericTraits::ZeroValue(); MeasurementType longRunEmphasis = NumericTraits::ZeroValue(); MeasurementType greyLevelNonuniformity = NumericTraits::ZeroValue(); MeasurementType runLengthNonuniformity = NumericTraits::ZeroValue(); MeasurementType lowGreyLevelRunEmphasis = NumericTraits::ZeroValue(); MeasurementType highGreyLevelRunEmphasis = NumericTraits::ZeroValue(); MeasurementType shortRunLowGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType shortRunHighGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType longRunLowGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType longRunHighGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType runPercentage = NumericTraits::ZeroValue(); MeasurementType numberOfRuns = NumericTraits::ZeroValue(); //Added 15.07.2016 MeasurementType greyLevelVariance = NumericTraits::ZeroValue(); MeasurementType runLengthVariance = NumericTraits::ZeroValue(); MeasurementType runEntropy = NumericTraits::ZeroValue(); //Added 09.09.2016 MeasurementType greyLevelNonuniformityNormalized = NumericTraits::ZeroValue(); MeasurementType runLengthNonuniformityNormalized = NumericTraits::ZeroValue(); vnl_vector greyLevelNonuniformityVector( inputHistogram->GetSize()[0], 0.0 ); vnl_vector runLengthNonuniformityVector( inputHistogram->GetSize()[1], 0.0 ); typedef typename HistogramType::ConstIterator HistogramIterator; double mu_i = 0.0; double mu_j = 0.0; //Calculate the means. for ( HistogramIterator hit = inputHistogram->Begin(); hit != inputHistogram->End(); ++hit ) { IndexType index = hit.GetIndex(); MeasurementType frequency = hit.GetFrequency(); if ( frequency == 0 ) { continue; } // MITK_INFO << index[0] + 1 << "|" << index[1] + 1 << " " << frequency; MeasurementVectorType measurement = hit.GetMeasurementVector(); double i = index[0] + 1; double j = index[1] + 1; double p_ij = frequency / (1.0*m_TotalNumberOfRuns); mu_i += i * p_ij; mu_j += j * p_ij; } // MITK_INFO << "Mu_i " << mu_i << " Mu_j " << mu_j; //Calculate the other features. const double log2 = std::log(2.0); for ( HistogramIterator hit = inputHistogram->Begin(); hit != inputHistogram->End(); ++hit ) { MeasurementType frequency = hit.GetFrequency(); if ( frequency == 0 ) { continue; } MeasurementVectorType measurement = hit.GetMeasurementVector(); IndexType index = hit.GetIndex(); // inputHistogram->GetIndex( hit.GetInstanceIdentifier() ); double i = index[0] + 1; double j = index[1] + 1; double i2 = i*i; double j2 = j*j; - MITK_INFO << i << " " << j; double p_ij = frequency / m_TotalNumberOfRuns; greyLevelVariance += ((i - mu_i) * (i - mu_i) * p_ij); runLengthVariance += ((j - mu_j) * (j - mu_j) * p_ij); runEntropy -= ( p_ij > 0.0001 ) ? p_ij *std::log(p_ij) / log2 : 0; // Traditional measures shortRunEmphasis += ( frequency / j2 ); longRunEmphasis += ( frequency * j2 ); greyLevelNonuniformityVector[index[0]] += frequency; runLengthNonuniformityVector[index[1]] += frequency; // measures from Chu et al. lowGreyLevelRunEmphasis += (i2 > 0.0001) ? ( frequency / i2 ) : 0; highGreyLevelRunEmphasis += ( frequency * i2 ); // measures from Dasarathy and Holder shortRunLowGreyLevelEmphasis += ((i2 * j2) > 0.0001) ? ( frequency / ( i2 * j2 ) ) : 0; shortRunHighGreyLevelEmphasis += (j2 > 0.0001) ? ( frequency * i2 / j2 ) : 0; longRunLowGreyLevelEmphasis += (i2 > 0.0001) ? ( frequency * j2 / i2 ) : 0; longRunHighGreyLevelEmphasis += ( frequency * i2 * j2 ); } greyLevelNonuniformity = greyLevelNonuniformityVector.squared_magnitude(); runLengthNonuniformity = runLengthNonuniformityVector.squared_magnitude(); // Normalize all measures by the total number of runs if (this->m_TotalNumberOfRuns > 0) { shortRunEmphasis /= static_cast( this->m_TotalNumberOfRuns ); longRunEmphasis /= static_cast( this->m_TotalNumberOfRuns ); greyLevelNonuniformity /= static_cast( this->m_TotalNumberOfRuns ); runLengthNonuniformity /= static_cast( this->m_TotalNumberOfRuns ); lowGreyLevelRunEmphasis /= static_cast( this->m_TotalNumberOfRuns ); highGreyLevelRunEmphasis /= static_cast( this->m_TotalNumberOfRuns ); shortRunLowGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfRuns ); shortRunHighGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfRuns ); longRunLowGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfRuns ); longRunHighGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfRuns ); runPercentage = static_cast( this->m_TotalNumberOfRuns ) / static_cast( this->m_NumberOfVoxels ); numberOfRuns = static_cast( this->m_TotalNumberOfRuns ) ; greyLevelNonuniformityNormalized = greyLevelNonuniformity / static_cast(this->m_TotalNumberOfRuns); runLengthNonuniformityNormalized = runLengthNonuniformity / static_cast(this->m_TotalNumberOfRuns); } else { shortRunEmphasis = 0; longRunEmphasis = 0; greyLevelNonuniformity = 0; runLengthNonuniformity= 0; lowGreyLevelRunEmphasis = 0; highGreyLevelRunEmphasis = 0; shortRunLowGreyLevelEmphasis = 0; shortRunHighGreyLevelEmphasis= 0; longRunLowGreyLevelEmphasis = 0; longRunHighGreyLevelEmphasis = 0; runPercentage = 0; greyLevelNonuniformityNormalized = 0; runLengthNonuniformityNormalized = 0; numberOfRuns = static_cast( this->m_TotalNumberOfRuns ) ; } MeasurementObjectType* shortRunEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 0 ) ); shortRunEmphasisOutputObject->Set( shortRunEmphasis ); MeasurementObjectType* longRunEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 1 ) ); longRunEmphasisOutputObject->Set( longRunEmphasis ); MeasurementObjectType* greyLevelNonuniformityOutputObject = static_cast( this->ProcessObject::GetOutput( 2 ) ); greyLevelNonuniformityOutputObject->Set( greyLevelNonuniformity ); MeasurementObjectType* greyLevelNonuniformityNormalizedOutputObject = static_cast( this->ProcessObject::GetOutput( 15 ) ); greyLevelNonuniformityNormalizedOutputObject->Set( greyLevelNonuniformityNormalized ); MeasurementObjectType* runLengthNonuniformityNormalizedOutputObject = static_cast( this->ProcessObject::GetOutput( 16 ) ); runLengthNonuniformityNormalizedOutputObject->Set( runLengthNonuniformityNormalized ); MeasurementObjectType* runLengthNonuniformityOutputObject = static_cast( this->ProcessObject::GetOutput( 3 ) ); runLengthNonuniformityOutputObject->Set( runLengthNonuniformity ); MeasurementObjectType* lowGreyLevelRunEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 4 ) ); lowGreyLevelRunEmphasisOutputObject->Set( lowGreyLevelRunEmphasis ); MeasurementObjectType* highGreyLevelRunEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 5 ) ); highGreyLevelRunEmphasisOutputObject->Set( highGreyLevelRunEmphasis ); MeasurementObjectType* shortRunLowGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 6 ) ); shortRunLowGreyLevelEmphasisOutputObject->Set( shortRunLowGreyLevelEmphasis ); MeasurementObjectType* shortRunHighGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 7 ) ); shortRunHighGreyLevelEmphasisOutputObject->Set( shortRunHighGreyLevelEmphasis ); MeasurementObjectType* longRunLowGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 8 ) ); longRunLowGreyLevelEmphasisOutputObject->Set( longRunLowGreyLevelEmphasis ); MeasurementObjectType* longRunHighGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 9 ) ); longRunHighGreyLevelEmphasisOutputObject->Set( longRunHighGreyLevelEmphasis ); MeasurementObjectType* runPercentagesOutputObject = static_cast( this->ProcessObject::GetOutput( 10 ) ); runPercentagesOutputObject->Set( runPercentage ); MeasurementObjectType* numberOfRunsOutputObject = static_cast( this->ProcessObject::GetOutput( 11 ) ); numberOfRunsOutputObject->Set( numberOfRuns ); MeasurementObjectType* greyLevelVarianceOutputObject = static_cast( this->ProcessObject::GetOutput( 12 ) ); greyLevelVarianceOutputObject->Set( greyLevelVariance ); MeasurementObjectType* runLengthVarianceOutputObject = static_cast( this->ProcessObject::GetOutput( 13 ) ); runLengthVarianceOutputObject->Set( runLengthVariance ); MeasurementObjectType* runEntropyOutputObject = static_cast( this->ProcessObject::GetOutput( 14 ) ); runEntropyOutputObject->Set( runEntropy ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetShortRunEmphasisOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 0 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetLongRunEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetGreyLevelNonuniformityOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 2 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetRunLengthNonuniformityOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 3 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetLowGreyLevelRunEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 4 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetHighGreyLevelRunEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 5 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetShortRunLowGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 6 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetShortRunHighGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 7 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetLongRunLowGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 8 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetLongRunHighGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 9 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetRunPercentageOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 10 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetNumberOfRunsOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 11 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetGreyLevelVarianceOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 12 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetRunLengthVarianceOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 13 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetRunEntropyOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 14 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetGreyLevelNonuniformityNormalizedOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 15 ) ); } template const typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementObjectType* EnhancedHistogramToRunLengthFeaturesFilter ::GetRunLengthNonuniformityNormalizedOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 16 ) ); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetShortRunEmphasis() const { return this->GetShortRunEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetLongRunEmphasis() const { return this->GetLongRunEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetGreyLevelNonuniformity() const { return this->GetGreyLevelNonuniformityOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetRunLengthNonuniformity() const { return this->GetRunLengthNonuniformityOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetLowGreyLevelRunEmphasis() const { return this->GetLowGreyLevelRunEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetHighGreyLevelRunEmphasis() const { return this->GetHighGreyLevelRunEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetShortRunLowGreyLevelEmphasis() const { return this->GetShortRunLowGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetShortRunHighGreyLevelEmphasis() const { return this->GetShortRunHighGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetLongRunLowGreyLevelEmphasis() const { return this->GetLongRunLowGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetLongRunHighGreyLevelEmphasis() const { return this->GetLongRunHighGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetRunPercentage() const { return this->GetRunPercentageOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetNumberOfRuns() const { return this->GetNumberOfRunsOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetGreyLevelVariance() const { return this->GetGreyLevelVarianceOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetRunLengthVariance() const { return this->GetRunLengthVarianceOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetRunEntropy() const { return this->GetRunEntropyOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetGreyLevelNonuniformityNormalized() const { return this->GetGreyLevelNonuniformityNormalizedOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetRunLengthNonuniformityNormalized() const { return this->GetRunLengthNonuniformityNormalizedOutput()->Get(); } template typename EnhancedHistogramToRunLengthFeaturesFilter< THistogram>::MeasurementType EnhancedHistogramToRunLengthFeaturesFilter ::GetFeature( RunLengthFeatureName feature ) { switch( feature ) { case ShortRunEmphasis: return this->GetShortRunEmphasis(); case LongRunEmphasis: return this->GetLongRunEmphasis(); case GreyLevelNonuniformity: return this->GetGreyLevelNonuniformity(); case GreyLevelNonuniformityNormalized: return this->GetGreyLevelNonuniformityNormalized(); case RunLengthNonuniformity: return this->GetRunLengthNonuniformity(); case RunLengthNonuniformityNormalized: return this->GetRunLengthNonuniformityNormalized(); case LowGreyLevelRunEmphasis: return this->GetLowGreyLevelRunEmphasis(); case HighGreyLevelRunEmphasis: return this->GetHighGreyLevelRunEmphasis(); case ShortRunLowGreyLevelEmphasis: return this->GetShortRunLowGreyLevelEmphasis(); case ShortRunHighGreyLevelEmphasis: return this->GetShortRunHighGreyLevelEmphasis(); case LongRunLowGreyLevelEmphasis: return this->GetLongRunLowGreyLevelEmphasis(); case LongRunHighGreyLevelEmphasis: return this->GetLongRunHighGreyLevelEmphasis(); case RunPercentage: return this->GetRunPercentage(); case NumberOfRuns: return this->GetNumberOfRuns(); case GreyLevelVariance: return this->GetGreyLevelVariance(); case RunLengthVariance: return this->GetRunLengthVariance(); case RunEntropy: return this->GetRunEntropy(); default: return 0; } } template< typename THistogram> void EnhancedHistogramToRunLengthFeaturesFilter< THistogram>:: PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf( os,indent ); } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.hxx index d8c5bdeb72..878f09bcd5 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.hxx @@ -1,669 +1,669 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef __itkEnhancedHistogramToSizeZoneFeaturesFilter_hxx #define __itkEnhancedHistogramToSizeZoneFeaturesFilter_hxx #include "itkEnhancedHistogramToSizeZoneFeaturesFilter.h" #include "itkNumericTraits.h" #include "vnl/vnl_math.h" namespace itk { namespace Statistics { //constructor template EnhancedHistogramToSizeZoneFeaturesFilter ::EnhancedHistogramToSizeZoneFeaturesFilter() : m_NumberOfVoxels(1) { this->ProcessObject::SetNumberOfRequiredInputs( 1 ); // allocate the data objects for the outputs which are // just decorators real types for( unsigned int i = 0; i < 17; i++ ) { this->ProcessObject::SetNthOutput( i, this->MakeOutput( i ) ); } } template void EnhancedHistogramToSizeZoneFeaturesFilter< THistogram> ::SetInput( const HistogramType *histogram ) { this->ProcessObject::SetNthInput( 0, const_cast( histogram ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::HistogramType * EnhancedHistogramToSizeZoneFeaturesFilter< THistogram> ::GetInput() const { if ( this->GetNumberOfInputs() < 1 ) { return ITK_NULLPTR; } return itkDynamicCastInDebugMode(this->ProcessObject::GetInput( 0 ) ); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::DataObjectPointer EnhancedHistogramToSizeZoneFeaturesFilter ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed( idx ) ) { return MeasurementObjectType::New().GetPointer(); } template void EnhancedHistogramToSizeZoneFeaturesFilter< THistogram>:: GenerateData( void ) { const HistogramType * inputHistogram = this->GetInput(); this->m_TotalNumberOfZones = static_cast ( inputHistogram->GetTotalFrequency() ); MeasurementType SmallZoneEmphasis = NumericTraits::ZeroValue(); MeasurementType LargeZoneEmphasis = NumericTraits::ZeroValue(); MeasurementType greyLevelNonuniformity = NumericTraits::ZeroValue(); MeasurementType SizeZoneNonuniformity = NumericTraits::ZeroValue(); MeasurementType lowGreyLevelZoneEmphasis = NumericTraits::ZeroValue(); MeasurementType highGreyLevelZoneEmphasis = NumericTraits::ZeroValue(); MeasurementType SmallZoneLowGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType SmallZoneHighGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType LargeZoneLowGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType LargeZoneHighGreyLevelEmphasis = NumericTraits::ZeroValue(); MeasurementType ZonePercentage = NumericTraits::ZeroValue(); MeasurementType numberOfZones = NumericTraits::ZeroValue(); //Added 15.07.2016 MeasurementType greyLevelVariance = NumericTraits::ZeroValue(); MeasurementType SizeZoneVariance = NumericTraits::ZeroValue(); MeasurementType ZoneEntropy = NumericTraits::ZeroValue(); //Added 09.09.2016 MeasurementType greyLevelNonuniformityNormalized = NumericTraits::ZeroValue(); MeasurementType SizeZoneNonuniformityNormalized = NumericTraits::ZeroValue(); vnl_vector greyLevelNonuniformityVector( inputHistogram->GetSize()[0], 0.0 ); vnl_vector SizeZoneNonuniformityVector( inputHistogram->GetSize()[1], 0.0 ); typedef typename HistogramType::ConstIterator HistogramIterator; double mu_i = 0.0; double mu_j = 0.0; //Calculate the means. for ( HistogramIterator hit = inputHistogram->Begin(); hit != inputHistogram->End(); ++hit ) { MeasurementType frequency = hit.GetFrequency(); if ( frequency == 0 ) { continue; } MeasurementVectorType measurement = hit.GetMeasurementVector(); IndexType index = hit.GetIndex(); int value = floor(measurement[0] + 0.5); int count = measurement[1]; double i = value; double j = count; double p_ij = frequency / m_TotalNumberOfZones; mu_i += i * p_ij; mu_j += j * p_ij; } //Calculate the other features. const double log2 = std::log(2.0); int totNumOfVoxelsUsed = 0; for ( HistogramIterator hit = inputHistogram->Begin(); hit != inputHistogram->End(); ++hit ) { MeasurementType frequency = hit.GetFrequency(); if ( frequency == 0 ) { continue; } MeasurementVectorType measurement = hit.GetMeasurementVector(); IndexType index = hit.GetIndex(); // inputHistogram->GetIndex( hit.GetInstanceIdentifier() ); int value = floor(measurement[0] + 0.5); int count = measurement[1]; double i = value; double j = count; double i2 = static_cast( i*i ); double j2 = static_cast( j*j ); double p_ij = frequency / m_TotalNumberOfZones; greyLevelVariance += ((i - mu_i) * (i - mu_i) * p_ij); SizeZoneVariance += ((j - mu_j) * (j - mu_j) * p_ij); ZoneEntropy -= ( p_ij > 0.0001 ) ? p_ij *std::log(p_ij) / log2 : 0; // Traditional measures SmallZoneEmphasis += ( frequency / j2 ); LargeZoneEmphasis += ( frequency * j2 ); greyLevelNonuniformityVector[index[0]] += frequency; SizeZoneNonuniformityVector[index[1]] += frequency; // measures from Chu et al. lowGreyLevelZoneEmphasis += (i2 > 0.0001) ? ( frequency / i2 ) : 0; highGreyLevelZoneEmphasis += ( frequency * i2 ); // measures from Dasarathy and Holder SmallZoneLowGreyLevelEmphasis += ((i2 * j2) > 0.0001) ? ( frequency / ( i2 * j2 ) ) : 0; - SmallZoneHighGreyLevelEmphasis += (j2 > 0.0001) ? ( frequency * i2 / j2 ) : 0; - LargeZoneLowGreyLevelEmphasis += (i2 = 0.0001) ? ( frequency * j2 / i2 ) : 0; + SmallZoneHighGreyLevelEmphasis += (j2 > 0.00001) ? ( frequency * i2 / j2 ) : 0; + LargeZoneLowGreyLevelEmphasis += (i2 > 0.00001) ? ( frequency * j2 / i2 ) : 0; LargeZoneHighGreyLevelEmphasis += ( frequency * i2 * j2 ); - totNumOfVoxelsUsed += (count * frequency); + totNumOfVoxelsUsed += (frequency); } greyLevelNonuniformity = greyLevelNonuniformityVector.squared_magnitude(); SizeZoneNonuniformity = SizeZoneNonuniformityVector.squared_magnitude(); // Normalize all measures by the total number of Zones m_TotalNumberOfZones = totNumOfVoxelsUsed; if (this->m_TotalNumberOfZones > 0) { SmallZoneEmphasis /= static_cast( this->m_TotalNumberOfZones ); LargeZoneEmphasis /= static_cast( this->m_TotalNumberOfZones ); greyLevelNonuniformity /= static_cast( this->m_TotalNumberOfZones ); SizeZoneNonuniformity /= static_cast( this->m_TotalNumberOfZones ); lowGreyLevelZoneEmphasis /= static_cast( this->m_TotalNumberOfZones ); highGreyLevelZoneEmphasis /= static_cast( this->m_TotalNumberOfZones ); SmallZoneLowGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfZones ); SmallZoneHighGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfZones ); LargeZoneLowGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfZones ); LargeZoneHighGreyLevelEmphasis /= static_cast( this->m_TotalNumberOfZones ); ZonePercentage = static_cast( this->m_TotalNumberOfZones ) / static_cast( this->m_NumberOfVoxels ); numberOfZones = static_cast( this->m_TotalNumberOfZones ) ; greyLevelNonuniformityNormalized = greyLevelNonuniformity / static_cast(this->m_TotalNumberOfZones); SizeZoneNonuniformityNormalized = SizeZoneNonuniformity / static_cast(this->m_TotalNumberOfZones); } else { SmallZoneEmphasis = 0; LargeZoneEmphasis = 0; greyLevelNonuniformity = 0; SizeZoneNonuniformity = 0; greyLevelNonuniformityNormalized = 0; SizeZoneNonuniformityNormalized = 0; lowGreyLevelZoneEmphasis = 0; highGreyLevelZoneEmphasis = 0; SmallZoneLowGreyLevelEmphasis = 0; SmallZoneHighGreyLevelEmphasis= 0; LargeZoneLowGreyLevelEmphasis = 0; LargeZoneHighGreyLevelEmphasis= 0; ZonePercentage = 0; numberOfZones = static_cast( this->m_TotalNumberOfZones ) ; } MeasurementObjectType* SmallZoneEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 0 ) ); SmallZoneEmphasisOutputObject->Set( SmallZoneEmphasis ); MeasurementObjectType* LargeZoneEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 1 ) ); LargeZoneEmphasisOutputObject->Set( LargeZoneEmphasis ); MeasurementObjectType* greyLevelNonuniformityOutputObject = static_cast( this->ProcessObject::GetOutput( 2 ) ); greyLevelNonuniformityOutputObject->Set( greyLevelNonuniformity ); MeasurementObjectType* SizeZoneNonuniformityOutputObject = static_cast( this->ProcessObject::GetOutput( 3 ) ); SizeZoneNonuniformityOutputObject->Set( SizeZoneNonuniformity ); MeasurementObjectType* lowGreyLevelZoneEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 4 ) ); lowGreyLevelZoneEmphasisOutputObject->Set( lowGreyLevelZoneEmphasis ); MeasurementObjectType* highGreyLevelZoneEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 5 ) ); highGreyLevelZoneEmphasisOutputObject->Set( highGreyLevelZoneEmphasis ); MeasurementObjectType* SmallZoneLowGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 6 ) ); SmallZoneLowGreyLevelEmphasisOutputObject->Set( SmallZoneLowGreyLevelEmphasis ); MeasurementObjectType* SmallZoneHighGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 7 ) ); SmallZoneHighGreyLevelEmphasisOutputObject->Set( SmallZoneHighGreyLevelEmphasis ); MeasurementObjectType* LargeZoneLowGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 8 ) ); LargeZoneLowGreyLevelEmphasisOutputObject->Set( LargeZoneLowGreyLevelEmphasis ); MeasurementObjectType* LargeZoneHighGreyLevelEmphasisOutputObject = static_cast( this->ProcessObject::GetOutput( 9 ) ); LargeZoneHighGreyLevelEmphasisOutputObject->Set( LargeZoneHighGreyLevelEmphasis ); MeasurementObjectType* ZonePercentagesOutputObject = static_cast( this->ProcessObject::GetOutput( 10 ) ); ZonePercentagesOutputObject->Set( ZonePercentage ); MeasurementObjectType* numberOfZonesOutputObject = static_cast( this->ProcessObject::GetOutput( 11 ) ); numberOfZonesOutputObject->Set( numberOfZones ); MeasurementObjectType* greyLevelVarianceOutputObject = static_cast( this->ProcessObject::GetOutput( 12 ) ); greyLevelVarianceOutputObject->Set( greyLevelVariance ); MeasurementObjectType* SizeZoneVarianceOutputObject = static_cast( this->ProcessObject::GetOutput( 13 ) ); SizeZoneVarianceOutputObject->Set( SizeZoneVariance ); MeasurementObjectType* ZoneEntropyOutputObject = static_cast( this->ProcessObject::GetOutput( 14 ) ); ZoneEntropyOutputObject->Set( ZoneEntropy ); MeasurementObjectType* greyLevelNonuniformityNormalizedOutputObject = static_cast( this->ProcessObject::GetOutput( 15 ) ); greyLevelNonuniformityNormalizedOutputObject->Set( greyLevelNonuniformityNormalized ); MeasurementObjectType* SizeZoneNonuniformityNormalizedOutputObject = static_cast( this->ProcessObject::GetOutput( 16 ) ); SizeZoneNonuniformityNormalizedOutputObject->Set( SizeZoneNonuniformityNormalized ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetSmallZoneEmphasisOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 0 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetLargeZoneEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetGreyLevelNonuniformityOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 2 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetSizeZoneNonuniformityOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 3 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetGreyLevelNonuniformityNormalizedOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 15 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetSizeZoneNonuniformityNormalizedOutput() const { return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 16 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetLowGreyLevelZoneEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 4 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetHighGreyLevelZoneEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 5 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetSmallZoneLowGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 6 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetSmallZoneHighGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 7 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetLargeZoneLowGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 8 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetLargeZoneHighGreyLevelEmphasisOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 9 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetZonePercentageOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 10 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetNumberOfZonesOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 11 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetGreyLevelVarianceOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 12 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetSizeZoneVarianceOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 13 ) ); } template const typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* EnhancedHistogramToSizeZoneFeaturesFilter ::GetZoneEntropyOutput() const { return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 14 ) ); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetSmallZoneEmphasis() const { return this->GetSmallZoneEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetLargeZoneEmphasis() const { return this->GetLargeZoneEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetGreyLevelNonuniformity() const { return this->GetGreyLevelNonuniformityOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetGreyLevelNonuniformityNormalized() const { return this->GetGreyLevelNonuniformityNormalizedOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetSizeZoneNonuniformity() const { return this->GetSizeZoneNonuniformityOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetSizeZoneNonuniformityNormalized() const { return this->GetSizeZoneNonuniformityNormalizedOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetLowGreyLevelZoneEmphasis() const { return this->GetLowGreyLevelZoneEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetHighGreyLevelZoneEmphasis() const { return this->GetHighGreyLevelZoneEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetSmallZoneLowGreyLevelEmphasis() const { return this->GetSmallZoneLowGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetSmallZoneHighGreyLevelEmphasis() const { return this->GetSmallZoneHighGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetLargeZoneLowGreyLevelEmphasis() const { return this->GetLargeZoneLowGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetLargeZoneHighGreyLevelEmphasis() const { return this->GetLargeZoneHighGreyLevelEmphasisOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetZonePercentage() const { return this->GetZonePercentageOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetNumberOfZones() const { return this->GetNumberOfZonesOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetGreyLevelVariance() const { return this->GetGreyLevelVarianceOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetSizeZoneVariance() const { return this->GetSizeZoneVarianceOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetZoneEntropy() const { return this->GetZoneEntropyOutput()->Get(); } template typename EnhancedHistogramToSizeZoneFeaturesFilter< THistogram>::MeasurementType EnhancedHistogramToSizeZoneFeaturesFilter ::GetFeature( SizeZoneFeatureName feature ) { switch( feature ) { case SmallZoneEmphasis: return this->GetSmallZoneEmphasis(); case LargeZoneEmphasis: return this->GetLargeZoneEmphasis(); case GreyLevelNonuniformity: return this->GetGreyLevelNonuniformity(); case GreyLevelNonuniformityNormalized: return this->GetGreyLevelNonuniformityNormalized(); case SizeZoneNonuniformity: return this->GetSizeZoneNonuniformity(); case SizeZoneNonuniformityNormalized: return this->GetSizeZoneNonuniformityNormalized(); case LowGreyLevelZoneEmphasis: return this->GetLowGreyLevelZoneEmphasis(); case HighGreyLevelZoneEmphasis: return this->GetHighGreyLevelZoneEmphasis(); case SmallZoneLowGreyLevelEmphasis: return this->GetSmallZoneLowGreyLevelEmphasis(); case SmallZoneHighGreyLevelEmphasis: return this->GetSmallZoneHighGreyLevelEmphasis(); case LargeZoneLowGreyLevelEmphasis: return this->GetLargeZoneLowGreyLevelEmphasis(); case LargeZoneHighGreyLevelEmphasis: return this->GetLargeZoneHighGreyLevelEmphasis(); case ZonePercentage: return this->GetZonePercentage(); case GreyLevelVariance: return this->GetGreyLevelVariance(); case SizeZoneVariance: return this->GetSizeZoneVariance(); case ZoneEntropy: return this->GetZoneEntropy(); default: return 0; } } template< typename THistogram> void EnhancedHistogramToSizeZoneFeaturesFilter< THistogram>:: PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf( os,indent ); } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Classification/CLUtilities/include/mitkCLResultWritter.h b/Modules/Classification/CLUtilities/include/mitkCLResultWritter.h index be6d760e75..4d813247c6 100644 --- a/Modules/Classification/CLUtilities/include/mitkCLResultWritter.h +++ b/Modules/Classification/CLUtilities/include/mitkCLResultWritter.h @@ -1,56 +1,63 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkCLResultWritter_h #define mitkCLResultWritter_h #include "MitkCLUtilitiesExports.h" #include #include #include #include namespace mitk { namespace cl { class MITKCLUTILITIES_EXPORT FeatureResultWritter { public: FeatureResultWritter(std::string, int mode); ~FeatureResultWritter(); + void SetDecimalPoint(char decimal); + + void AddSubjectInformation(std::string value); void AddColumn(std::string value); void AddColumn(double value); void NewRow(std::string endName); void AddResult(std::string desc, int slice, mitk::AbstractGlobalImageFeature::FeatureListType stats, bool , bool withDescription); void AddHeader(std::string, int slice, mitk::AbstractGlobalImageFeature::FeatureListType stats, bool withHeader, bool withDescription); private: int m_Mode; std::size_t m_CurrentRow; int m_CurrentElement; std::string m_Separator; std::ofstream m_Output; std::vector m_List; + std::string m_SubjectInformation; + bool m_UsedSubjectInformation; + bool m_UseSpecialDecimalPoint; + char m_DecimalPoint; }; } } #endif //mitkCLResultWritter_h \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h b/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h index 2665167adc..b4e9caefaa 100644 --- a/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h +++ b/Modules/Classification/CLUtilities/include/mitkGIFCooccurenceMatrix2.h @@ -1,147 +1,151 @@ #ifndef mitkGIFCooccurenceMatrix2_h #define mitkGIFCooccurenceMatrix2_h #include #include #include #include namespace mitk { struct CoocurenceMatrixHolder { public: CoocurenceMatrixHolder(double min, double max, int number); int IntensityToIndex(double intensity); double IndexToMinIntensity(int index); double IndexToMeanIntensity(int index); double IndexToMaxIntensity(int index); double m_MinimumRange; double m_MaximumRange; double m_Stepsize; int m_NumberOfBins; Eigen::MatrixXd m_Matrix; }; struct CoocurenceMatrixFeatures { CoocurenceMatrixFeatures(): JointMaximum(0), JointAverage(0), JointVariance(0), JointEntropy(0), RowMaximum(0), RowAverage(0), RowVariance(0), RowEntropy(0), FirstRowColumnEntropy(0), SecondRowColumnEntropy(0), DifferenceAverage(0), DifferenceVariance(0), DifferenceEntropy(0), SumAverage(0), SumVariance(0), SumEntropy(0), AngularSecondMoment(0), Contrast(0), Dissimilarity(0), InverseDifference(0), InverseDifferenceNormalised(0), InverseDifferenceMoment(0), InverseDifferenceMomentNormalised(0), InverseVariance(0), Correlation(0), Autocorrelation(0), ClusterTendency(0), ClusterShade(0), ClusterProminence(0), FirstMeasureOfInformationCorrelation(0), SecondMeasureOfInformationCorrelation(0) { } public: double JointMaximum; double JointAverage; double JointVariance; double JointEntropy; double RowMaximum; double RowAverage; double RowVariance; double RowEntropy; double FirstRowColumnEntropy; double SecondRowColumnEntropy; double DifferenceAverage; double DifferenceVariance; double DifferenceEntropy; double SumAverage; double SumVariance; double SumEntropy; double AngularSecondMoment; double Contrast; double Dissimilarity; double InverseDifference; double InverseDifferenceNormalised; double InverseDifferenceMoment; double InverseDifferenceMomentNormalised; double InverseVariance; double Correlation; double Autocorrelation; double ClusterTendency; double ClusterShade; double ClusterProminence; double FirstMeasureOfInformationCorrelation; double SecondMeasureOfInformationCorrelation; }; class MITKCLUTILITIES_EXPORT GIFCooccurenceMatrix2 : public AbstractGlobalImageFeature { public: mitkClassMacro(GIFCooccurenceMatrix2, AbstractGlobalImageFeature); itkFactorylessNewMacro(Self) itkCloneMacro(Self) GIFCooccurenceMatrix2(); /** * \brief Calculates the Cooccurence-Matrix based features for this class. */ virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; /** * \brief Returns a list of the names of all features that are calculated from this class */ virtual FeatureNameListType GetFeatureNames() override; virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); virtual void AddArguments(mitkCommandLineParser &parser); itkGetConstMacro(Range,double); itkSetMacro(Range, double); itkGetConstMacro(Bins, int); itkSetMacro(Bins, int); + itkGetConstMacro(Binsize, double); + itkSetMacro(Binsize, double); struct GIFCooccurenceMatrix2Configuration { double range; unsigned int direction; double MinimumIntensity; bool UseMinimumIntensity; double MaximumIntensity; bool UseMaximumIntensity; int Bins; + double BinSize; }; private: double m_Range; int m_Bins; + double m_Binsize; }; } #endif //mitkGIFCooccurenceMatrix2_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderHistogramStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderHistogramStatistics.h new file mode 100644 index 0000000000..eaf8d245df --- /dev/null +++ b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderHistogramStatistics.h @@ -0,0 +1,77 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkGIFFirstOrderHistogramStatistics_h +#define mitkGIFFirstOrderHistogramStatistics_h + +#include +#include +#include + +namespace mitk +{ + class MITKCLUTILITIES_EXPORT GIFFirstOrderHistogramStatistics : public AbstractGlobalImageFeature + { + public: + mitkClassMacro(GIFFirstOrderHistogramStatistics,AbstractGlobalImageFeature) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + GIFFirstOrderHistogramStatistics(); + + /** + * \brief Calculates the Cooccurence-Matrix based features for this class. + */ + virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + + /** + * \brief Returns a list of the names of all features that are calculated from this class + */ + virtual FeatureNameListType GetFeatureNames() override; + + itkGetConstMacro(Range,double); + itkSetMacro(Range, double); + itkGetConstMacro(HistogramSize,int); + itkSetMacro(HistogramSize, int); + itkGetConstMacro(UseCtRange,bool); + itkSetMacro(UseCtRange, bool); + itkGetConstMacro(BinSize, double); + itkSetMacro(BinSize, double); + + virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); + virtual void AddArguments(mitkCommandLineParser &parser); + + + struct ParameterStruct { + int m_HistogramSize; + bool m_UseCtRange; + + double MinimumIntensity; + bool UseMinimumIntensity; + double MaximumIntensity; + bool UseMaximumIntensity; + int Bins; + double BinSize; + }; + + private: + double m_Range; + int m_HistogramSize; + bool m_UseCtRange; + double m_BinSize; + }; +} +#endif //mitkGIFFirstOrderHistogramStatistics_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelDistanceZone.h b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelDistanceZone.h new file mode 100644 index 0000000000..8a77f1025d --- /dev/null +++ b/Modules/Classification/CLUtilities/include/mitkGIFGreyLevelDistanceZone.h @@ -0,0 +1,125 @@ +#ifndef mitkGIFGreyLevelDistanceZone_h +#define mitkGIFGreyLevelDistanceZone_h + +#include +#include +#include + +#include + +namespace mitk +{ + struct GreyLevelDistanceZoneMatrixHolder + { + public: + GreyLevelDistanceZoneMatrixHolder(double min, double max, int number, int maxSize); + + int IntensityToIndex(double intensity); + double IndexToMinIntensity(int index); + double IndexToMeanIntensity(int index); + double IndexToMaxIntensity(int index); + + double m_MinimumRange; + double m_MaximumRange; + double m_Stepsize; + int m_NumberOfBins; + int m_MaximumSize; + int m_NumerOfVoxels; + Eigen::MatrixXd m_Matrix; + + }; + + struct GreyLevelDistanceZoneFeatures + { + GreyLevelDistanceZoneFeatures() : + SmallDistanceEmphasis(0), + LargeDistanceEmphasis(0), + LowGreyLevelEmphasis(0), + HighGreyLevelEmphasis(0), + SmallDistanceLowGreyLevelEmphasis(0), + SmallDistanceHighGreyLevelEmphasis(0), + LargeDistanceLowGreyLevelEmphasis(0), + LargeDistanceHighGreyLevelEmphasis(0), + GreyLevelNonUniformity(0), + GreyLevelNonUniformityNormalized(0), + ZoneDistanceNonUniformity(0), + ZoneDistanceNoneUniformityNormalized(0), + ZonePercentage(0), + GreyLevelMean(0), + GreyLevelVariance(0), + ZoneDistanceMean(0), + ZoneDistanceVariance(0), + ZoneDistanceEntropy(0) + { + } + + public: + double SmallDistanceEmphasis; + double LargeDistanceEmphasis; + double LowGreyLevelEmphasis; + double HighGreyLevelEmphasis; + double SmallDistanceLowGreyLevelEmphasis; + double SmallDistanceHighGreyLevelEmphasis; + double LargeDistanceLowGreyLevelEmphasis; + double LargeDistanceHighGreyLevelEmphasis; + double GreyLevelNonUniformity; + double GreyLevelNonUniformityNormalized; + double ZoneDistanceNonUniformity; + double ZoneDistanceNoneUniformityNormalized; + double ZonePercentage; + double GreyLevelMean; + double GreyLevelVariance; + double ZoneDistanceMean; + double ZoneDistanceVariance; + double ZoneDistanceEntropy; + }; + + + class MITKCLUTILITIES_EXPORT GIFGreyLevelDistanceZone : public AbstractGlobalImageFeature + { + public: + mitkClassMacro(GIFGreyLevelDistanceZone, AbstractGlobalImageFeature); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + GIFGreyLevelDistanceZone(); + + /** + * \brief Calculates the Cooccurence-Matrix based features for this class. + */ + virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + + /** + * \brief Returns a list of the names of all features that are calculated from this class + */ + virtual FeatureNameListType GetFeatureNames() override; + + virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); + virtual void AddArguments(mitkCommandLineParser &parser); + + itkGetConstMacro(Range,double); + itkSetMacro(Range, double); + itkGetConstMacro(Bins, int); + itkSetMacro(Bins, int); + + struct GIFGreyLevelDistanceZoneConfiguration + { + mitk::Image::Pointer distanceMask; + + double range; + unsigned int direction; + + double MinimumIntensity; + bool UseMinimumIntensity; + double MaximumIntensity; + bool UseMaximumIntensity; + int Bins; + }; + + private: + double m_Range; + int m_Bins; + }; + +} +#endif //mitkGIFGreyLevelDistanceZone_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFImageDescriptionFeatures.h b/Modules/Classification/CLUtilities/include/mitkGIFImageDescriptionFeatures.h new file mode 100644 index 0000000000..899f4c1a89 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/mitkGIFImageDescriptionFeatures.h @@ -0,0 +1,73 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkGIFImageDescriptionFeatures_h +#define mitkGIFImageDescriptionFeatures_h + +#include +#include +#include + +namespace mitk +{ + class MITKCLUTILITIES_EXPORT GIFImageDescriptionFeatures : public AbstractGlobalImageFeature + { + public: + mitkClassMacro(GIFImageDescriptionFeatures,AbstractGlobalImageFeature) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + GIFImageDescriptionFeatures(); + + /** + * \brief Calculates the Cooccurence-Matrix based features for this class. + */ + virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + + /** + * \brief Returns a list of the names of all features that are calculated from this class + */ + virtual FeatureNameListType GetFeatureNames() override; + + itkGetConstMacro(Range,double); + itkSetMacro(Range, double); + itkGetConstMacro(HistogramSize,int); + itkSetMacro(HistogramSize, int); + itkGetConstMacro(UseCtRange,bool); + itkSetMacro(UseCtRange, bool); + + virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); + virtual void AddArguments(mitkCommandLineParser &parser); + + + struct ParameterStruct { + int m_HistogramSize; + bool m_UseCtRange; + + double MinimumIntensity; + bool UseMinimumIntensity; + double MaximumIntensity; + bool UseMaximumIntensity; + int Bins; + }; + + private: + double m_Range; + int m_HistogramSize; + bool m_UseCtRange; + }; +} +#endif //mitkGIFImageDescriptionFeatures_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFIntensityVolumeHistogramFeatures.h b/Modules/Classification/CLUtilities/include/mitkGIFIntensityVolumeHistogramFeatures.h new file mode 100644 index 0000000000..9bde8ddc48 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/mitkGIFIntensityVolumeHistogramFeatures.h @@ -0,0 +1,51 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkGIFIntensityVolumeHistogramFeatures_h +#define mitkGIFIntensityVolumeHistogramFeatures_h + +#include +#include +#include + +namespace mitk +{ + class MITKCLUTILITIES_EXPORT GIFIntensityVolumeHistogramFeatures : public AbstractGlobalImageFeature + { + public: + mitkClassMacro(GIFIntensityVolumeHistogramFeatures, AbstractGlobalImageFeature); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + GIFIntensityVolumeHistogramFeatures(); + + /** + * \brief Calculates the Cooccurence-Matrix based features for this class. + */ + virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature); + + /** + * \brief Returns a list of the names of all features that are calculated from this class + */ + virtual FeatureNameListType GetFeatureNames(); + + virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); + virtual void AddArguments(mitkCommandLineParser &parser); + + private: + }; +} +#endif //mitkGIFIntensityVolumeHistogramFeatures_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFLocalIntensity.h b/Modules/Classification/CLUtilities/include/mitkGIFLocalIntensity.h new file mode 100644 index 0000000000..50000d7416 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/mitkGIFLocalIntensity.h @@ -0,0 +1,51 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkGIFLocalIntensity_h +#define mitkGIFLocalIntensity_h + +#include +#include +#include + +namespace mitk +{ + class MITKCLUTILITIES_EXPORT GIFLocalIntensity : public AbstractGlobalImageFeature + { + public: + mitkClassMacro(GIFLocalIntensity, AbstractGlobalImageFeature); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + GIFLocalIntensity(); + + /** + * \brief Calculates the Cooccurence-Matrix based features for this class. + */ + virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature); + + /** + * \brief Returns a list of the names of all features that are calculated from this class + */ + virtual FeatureNameListType GetFeatureNames(); + + virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); + virtual void AddArguments(mitkCommandLineParser &parser); + + private: + }; +} +#endif //mitkGIFLocalIntensity_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h b/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h new file mode 100644 index 0000000000..43117da109 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h @@ -0,0 +1,51 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkGIFNeighbourhoodGreyToneDifferenceFeatures_h +#define mitkGIFNeighbourhoodGreyToneDifferenceFeatures_h + +#include +#include +#include + +namespace mitk +{ + class MITKCLUTILITIES_EXPORT GIFNeighbourhoodGreyToneDifferenceFeatures : public AbstractGlobalImageFeature + { + public: + mitkClassMacro(GIFNeighbourhoodGreyToneDifferenceFeatures, AbstractGlobalImageFeature); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + GIFNeighbourhoodGreyToneDifferenceFeatures(); + + /** + * \brief Calculates the Cooccurence-Matrix based features for this class. + */ + virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature); + + /** + * \brief Returns a list of the names of all features that are calculated from this class + */ + virtual FeatureNameListType GetFeatureNames(); + + virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); + virtual void AddArguments(mitkCommandLineParser &parser); + + private: + }; +} +#endif //mitkGIFNeighbourhoodGreyToneDifferenceFeatures_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFVolumetricDensityStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFVolumetricDensityStatistics.h new file mode 100644 index 0000000000..a396eec618 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/mitkGIFVolumetricDensityStatistics.h @@ -0,0 +1,51 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkGIFVolumetricDensityStatistics_h +#define mitkGIFVolumetricDensityStatistics_h + +#include +#include +#include + +namespace mitk +{ + class MITKCLUTILITIES_EXPORT GIFVolumetricDensityStatistics : public AbstractGlobalImageFeature + { + public: + mitkClassMacro(GIFVolumetricDensityStatistics,AbstractGlobalImageFeature) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + GIFVolumetricDensityStatistics(); + + /** + * \brief Calculates the Cooccurence-Matrix based features for this class. + */ + virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature); + + /** + * \brief Returns a list of the names of all features that are calculated from this class + */ + virtual FeatureNameListType GetFeatureNames(); + + virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); + virtual void AddArguments(mitkCommandLineParser &parser); + + private: + }; +} +#endif //mitkGIFVolumetricDensityStatistics_h diff --git a/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h b/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h index ddb9a68030..26ce96cf6a 100644 --- a/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h +++ b/Modules/Classification/CLUtilities/include/mitkGlobalImageFeaturesParameter.h @@ -1,80 +1,86 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkGlobalImageFeaturesParameter_h #define mitkGlobalImageFeaturesParameter_h #include "MitkCLUtilitiesExports.h" #include "mitkCommandLineParser.h" #include namespace mitk { namespace cl { class MITKCLUTILITIES_EXPORT GlobalImageFeaturesParameter { public: void AddParameter(mitkCommandLineParser &parser); void ParseParameter(std::map parsedArgs); std::string imagePath; std::string imageName; std::string imageFolder; std::string maskPath; std::string maskName; std::string maskFolder; std::string outputPath; + std::string morphPath; + std::string morphName; + bool useMorphMask; + bool useLogfile; std::string logfilePath; bool writeAnalysisImage; std::string anaylsisImagePath; bool writeAnalysisMask; std::string analysisMaskPath; bool writePNGScreenshots; std::string pngScreenshotsPath; bool useHeader; bool useHeaderForFirstLineOnly; bool ensureSameSpace; bool resampleMask; bool resampleToFixIsotropic; double resampleResolution; bool defineGlobalMinimumIntensity; double globalMinimumIntensity; bool defineGlobalMaximumIntensity; double globalMaximumIntensity; bool defineGlobalNumberOfBins; int globalNumberOfBins; + bool useDecimalPoint; + char decimalPoint; private: void ParseFileLocations(std::map &parsedArgs); void ParseAdditionalOutputs(std::map &parsedArgs); void ParseHeaderInformation(std::map &parsedArgs); void ParseMaskAdaptation(std::map &parsedArgs); void ParseGlobalFeatureParameter(std::map &parsedArgs); }; } } #endif //mitkGlobalImageFeaturesParameter_h \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp index 6b95762fda..1b2bfbab89 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp @@ -1,607 +1,624 @@ #include // MITK #include #include #include // ITK #include #include #include #include // STL #include +#include static void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, std::string prefix, mitk::GIFCooccurenceMatrix2::FeatureListType &featureList); static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature); static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number); mitk::CoocurenceMatrixHolder::CoocurenceMatrixHolder(double min, double max, int number) : m_MinimumRange(min), m_MaximumRange(max), m_NumberOfBins(number) { m_Matrix.resize(number, number); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::CoocurenceMatrixHolder::IntensityToIndex(double intensity) { - return std::floor((intensity - m_MinimumRange) / m_Stepsize); + int index = std::floor((intensity - m_MinimumRange) / m_Stepsize); + return std::max(0, std::min(index, m_NumberOfBins - 1)); } double mitk::CoocurenceMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template void CalculateCoOcMatrix(itk::Image* itkImage, itk::Image* mask, itk::Offset offset, int range, mitk::CoocurenceMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef itk::ShapedNeighborhoodIterator ShapeIterType; typedef itk::ShapedNeighborhoodIterator ShapeMaskIterType; typedef itk::ImageRegionConstIterator ConstIterType; typedef itk::ImageRegionConstIterator ConstMaskIterType; itk::Size radius; radius.Fill(range+1); ShapeIterType imageOffsetIter(radius, itkImage, itkImage->GetLargestPossibleRegion()); ShapeMaskIterType maskOffsetIter(radius, mask, mask->GetLargestPossibleRegion()); imageOffsetIter.ActivateOffset(offset); maskOffsetIter.ActivateOffset(offset); ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); // iterator.GetIndex() + ci.GetNeighborhoodOffset() auto region = mask->GetLargestPossibleRegion(); while (!maskIter.IsAtEnd()) { auto ciMask = maskOffsetIter.Begin(); auto ciValue = imageOffsetIter.Begin(); if (maskIter.Value() > 0 && ciMask.Get() > 0 && imageIter.Get() == imageIter.Get() && ciValue.Get() == ciValue.Get() && region.IsInside(maskOffsetIter.GetIndex() + ciMask.GetNeighborhoodOffset())) { int i = holder.IntensityToIndex(imageIter.Get()); int j = holder.IntensityToIndex(ciValue.Get()); holder.m_Matrix(i, j) += 1; holder.m_Matrix(j, i) += 1; } ++imageOffsetIter; ++maskOffsetIter; ++imageIter; ++maskIter; } } void CalculateFeatures( mitk::CoocurenceMatrixHolder &holder, mitk::CoocurenceMatrixFeatures & results ) { auto pijMatrix = holder.m_Matrix; auto piMatrix = holder.m_Matrix; auto pjMatrix = holder.m_Matrix; double Ng = holder.m_NumberOfBins; int NgSize = holder.m_NumberOfBins; pijMatrix /= pijMatrix.sum(); piMatrix.rowwise().normalize(); pjMatrix.colwise().normalize(); for (int i = 0; i < holder.m_NumberOfBins; ++i) for (int j = 0; j < holder.m_NumberOfBins; ++j) { if (pijMatrix(i, j) != pijMatrix(i, j)) pijMatrix(i, j) = 0; if (piMatrix(i, j) != piMatrix(i, j)) piMatrix(i, j) = 0; if (pjMatrix(i, j) != pjMatrix(i, j)) pjMatrix(i, j) = 0; } Eigen::VectorXd piVector = pijMatrix.colwise().sum(); Eigen::VectorXd pjVector = pijMatrix.rowwise().sum(); double sigmai = 0;; for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1;// holder.IndexToMeanIntensity(i); results.RowAverage += iInt * piVector(i); if (piVector(i) > 0) { results.RowEntropy -= piVector(i) * std::log(piVector(i)) / std::log(2); } } for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1; // holder.IndexToMeanIntensity(i); results.RowVariance += (iInt - results.RowAverage)*(iInt - results.RowAverage) * piVector(i); } results.RowMaximum = piVector.maxCoeff(); sigmai = std::sqrt(results.RowVariance); Eigen::VectorXd pimj(NgSize); pimj.fill(0); Eigen::VectorXd pipj(2*NgSize); pipj.fill(0); results.JointMaximum += pijMatrix.maxCoeff(); for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1;// holder.IndexToMeanIntensity(i); double jInt = j + 1;// holder.IndexToMeanIntensity(j); double pij = pijMatrix(i, j); int deltaK = (i - j)>0?(i-j) : (j-i); pimj(deltaK) += pij; pipj(i + j) += pij; results.JointAverage += iInt * pij; if (pij > 0) { results.JointEntropy -= pij * std::log(pij) / std::log(2); results.FirstRowColumnEntropy -= pij * std::log(piVector(i)*pjVector(j)) / std::log(2); } if (piVector(i) > 0 && pjVector(j) > 0 ) { results.SecondRowColumnEntropy -= piVector(i)*pjVector(j) * std::log(piVector(i)*pjVector(j)) / std::log(2); } results.AngularSecondMoment += pij*pij; results.Contrast += (iInt - jInt)* (iInt - jInt) * pij; results.Dissimilarity += std::abs(iInt - jInt) * pij; results.InverseDifference += pij / (1 + (std::abs(iInt - jInt))); results.InverseDifferenceNormalised += pij / (1 + (std::abs(iInt - jInt) / Ng)); results.InverseDifferenceMoment += pij / (1 + (iInt - jInt)*(iInt - jInt)); results.InverseDifferenceMomentNormalised += pij / (1 + (iInt - jInt)*(iInt - jInt)/Ng/Ng); results.Autocorrelation += iInt*jInt * pij; double cluster = (iInt + jInt - 2 * results.RowAverage); results.ClusterTendency += cluster*cluster * pij; results.ClusterShade += cluster*cluster*cluster * pij; results.ClusterProminence += cluster*cluster*cluster*cluster * pij; if (iInt != jInt) { results.InverseVariance += pij / (iInt - jInt) / (iInt - jInt); } } } results.Correlation = 1 / sigmai / sigmai * (-results.RowAverage*results.RowAverage+ results.Autocorrelation); results.FirstMeasureOfInformationCorrelation = (results.JointEntropy - results.FirstRowColumnEntropy) / results.RowEntropy; if (results.JointEntropy < results.SecondRowColumnEntropy) { results.SecondMeasureOfInformationCorrelation = sqrt(1 - exp(-2 * (results.SecondRowColumnEntropy - results.JointEntropy))); } else { results.SecondMeasureOfInformationCorrelation = 0; } for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1; double pij = pijMatrix(i, j); results.JointVariance += (iInt - results.JointAverage)* (iInt - results.JointAverage)*pij; } } for (int k = 0; k < NgSize; ++k) { results.DifferenceAverage += k* pimj(k); if (pimj(k) > 0) { results.DifferenceEntropy -= pimj(k) * log(pimj(k)) / std::log(2); } } for (int k = 0; k < NgSize; ++k) { results.DifferenceVariance += (results.DifferenceAverage-k)* (results.DifferenceAverage-k)*pimj(k); } for (int k = 0; k <2* NgSize ; ++k) { results.SumAverage += (2+k)* pipj(k); if (pipj(k) > 0) { results.SumEntropy -= pipj(k) * log(pipj(k)) / std::log(2); } } for (int k = 0; k < 2*NgSize; ++k) { results.SumVariance += (2+k - results.SumAverage)* (2+k - results.SumAverage)*pipj(k); } //MITK_INFO << std::endl << holder.m_Matrix; //MITK_INFO << std::endl << pijMatrix; //MITK_INFO << std::endl << piMatrix; //MITK_INFO << std::endl << pjMatrix; //for (int i = 0; i < holder.m_NumberOfBins; ++i) //{ // MITK_INFO << "Bin " << i << " Min: " << holder.IndexToMinIntensity(i) << " Max: " << holder.IndexToMaxIntensity(i); //} //MITK_INFO << pimj; //MITK_INFO << pipj; } template void CalculateCoocurenceFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFCooccurenceMatrix2::FeatureListType & featureList, mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2Configuration config) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); minMaxComputer->SetImage(itkImage); minMaxComputer->Compute(); double rangeMin = -0.5 + minMaxComputer->GetMinimum(); double rangeMax = 0.5 + minMaxComputer->GetMaximum(); if (config.UseMinimumIntensity) rangeMin = config.MinimumIntensity; if (config.UseMaximumIntensity) rangeMax = config.MaximumIntensity; // Define Range int numberOfBins = config.Bins; + if (config.BinSize > 0) + { + numberOfBins = std::ceil((rangeMax - rangeMin) / config.BinSize); + rangeMax = rangeMin + config.BinSize * numberOfBins; + } + + MITK_INFO << "Bins: " << numberOfBins << " , Min, Max: " << rangeMin << " -> " << rangeMax; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); //Find possible directions std::vector < itk::Offset > offsetVector; NeighborhoodType hood; hood.SetRadius(1); unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetType offset; for (unsigned int d = 0; d < centerIndex; d++) { offset = hood.GetOffset(d); bool useOffset = true; for (unsigned int i = 0; i < VImageDimension; ++i) { offset[i] *= config.range; if (config.direction == i + 2 && offset[i] != 0) { useOffset = false; } } if (useOffset) { offsetVector.push_back(offset); } } if (config.direction == 1) { offsetVector.clear(); offset[0] = 0; offset[1] = 0; offset[2] = 1; } std::vector resultVector; mitk::CoocurenceMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures overallFeature; for (std::size_t i = 0; i < offsetVector.size(); ++i) { if (config.direction > 1) { if (offsetVector[i][config.direction - 2] != 0) { continue; } } offset = offsetVector[i]; mitk::CoocurenceMatrixHolder holder(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures coocResults; CalculateCoOcMatrix(itkImage, maskImage, offset, config.range, holder); holderOverall.m_Matrix += holder.m_Matrix; CalculateFeatures(holder, coocResults); resultVector.push_back(coocResults); } CalculateFeatures(holderOverall, overallFeature); //NormalizeMatrixFeature(overallFeature, offsetVector.size()); mitk::CoocurenceMatrixFeatures featureMean; mitk::CoocurenceMatrixFeatures featureStd; CalculateMeanAndStdDevFeatures(resultVector, featureMean, featureStd); std::ostringstream ss; ss << config.range; std::string strRange = ss.str(); MatrixFeaturesTo(overallFeature, "co-occ. 2 (" + strRange + ") overall", featureList); MatrixFeaturesTo(featureMean, "co-occ. 2 (" + strRange + ") mean", featureList); MatrixFeaturesTo(featureStd, "co-occ. 2 (" + strRange + ") std.dev.", featureList); } static void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, std::string prefix, mitk::GIFCooccurenceMatrix2::FeatureListType &featureList) { featureList.push_back(std::make_pair(prefix + " Joint Maximum", features.JointMaximum)); featureList.push_back(std::make_pair(prefix + " Joint Average", features.JointAverage)); featureList.push_back(std::make_pair(prefix + " Joint Variance", features.JointVariance)); featureList.push_back(std::make_pair(prefix + " Joint Entropy", features.JointEntropy)); featureList.push_back(std::make_pair(prefix + " Row Maximum", features.RowMaximum)); featureList.push_back(std::make_pair(prefix + " Row Average", features.RowAverage)); featureList.push_back(std::make_pair(prefix + " Row Variance", features.RowVariance)); featureList.push_back(std::make_pair(prefix + " Row Entropy", features.RowEntropy)); featureList.push_back(std::make_pair(prefix + " First Row-Column Entropy", features.FirstRowColumnEntropy)); featureList.push_back(std::make_pair(prefix + " Second Row-Column Entropy", features.SecondRowColumnEntropy)); featureList.push_back(std::make_pair(prefix + " Difference Average", features.DifferenceAverage)); featureList.push_back(std::make_pair(prefix + " Difference Variance", features.DifferenceVariance)); featureList.push_back(std::make_pair(prefix + " Difference Entropy", features.DifferenceEntropy)); featureList.push_back(std::make_pair(prefix + " Sum Average", features.SumAverage)); featureList.push_back(std::make_pair(prefix + " Sum Variance", features.SumVariance)); featureList.push_back(std::make_pair(prefix + " Sum Entropy", features.SumEntropy)); featureList.push_back(std::make_pair(prefix + " Angular Second Moment", features.AngularSecondMoment)); featureList.push_back(std::make_pair(prefix + " Contrast", features.Contrast)); featureList.push_back(std::make_pair(prefix + " Dissimilarity", features.Dissimilarity)); featureList.push_back(std::make_pair(prefix + " Inverse Difference", features.InverseDifference)); featureList.push_back(std::make_pair(prefix + " Inverse Difference Normalized", features.InverseDifferenceNormalised)); featureList.push_back(std::make_pair(prefix + " Inverse Difference Moment", features.InverseDifferenceMoment)); featureList.push_back(std::make_pair(prefix + " Inverse Difference Moment Normalized", features.InverseDifferenceMomentNormalised)); featureList.push_back(std::make_pair(prefix + " Inverse Variance", features.InverseVariance)); featureList.push_back(std::make_pair(prefix + " Correlation", features.Correlation)); featureList.push_back(std::make_pair(prefix + " Autocorrleation", features.Autocorrelation)); featureList.push_back(std::make_pair(prefix + " Cluster Tendency", features.ClusterTendency)); featureList.push_back(std::make_pair(prefix + " Cluster Shade", features.ClusterShade)); featureList.push_back(std::make_pair(prefix + " Cluster Prominence", features.ClusterProminence)); featureList.push_back(std::make_pair(prefix + " First Measure of Information Correlation", features.FirstMeasureOfInformationCorrelation)); featureList.push_back(std::make_pair(prefix + " Second Measure of Information Correlation", features.SecondMeasureOfInformationCorrelation)); } static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature) { #define ADDFEATURE(a) meanFeature.a += featureList[i].a;stdFeature.a += featureList[i].a*featureList[i].a #define CALCVARIANCE(a) stdFeature.a =sqrt(stdFeature.a - meanFeature.a*meanFeature.a) for (std::size_t i = 0; i < featureList.size(); ++i) { ADDFEATURE(JointMaximum); ADDFEATURE(JointAverage); ADDFEATURE(JointVariance); ADDFEATURE(JointEntropy); ADDFEATURE(RowMaximum); ADDFEATURE(RowAverage); ADDFEATURE(RowVariance); ADDFEATURE(RowEntropy); ADDFEATURE(FirstRowColumnEntropy); ADDFEATURE(SecondRowColumnEntropy); ADDFEATURE(DifferenceAverage); ADDFEATURE(DifferenceVariance); ADDFEATURE(DifferenceEntropy); ADDFEATURE(SumAverage); ADDFEATURE(SumVariance); ADDFEATURE(SumEntropy); ADDFEATURE(AngularSecondMoment); ADDFEATURE(Contrast); ADDFEATURE(Dissimilarity); ADDFEATURE(InverseDifference); ADDFEATURE(InverseDifferenceNormalised); ADDFEATURE(InverseDifferenceMoment); ADDFEATURE(InverseDifferenceMomentNormalised); ADDFEATURE(InverseVariance); ADDFEATURE(Correlation); ADDFEATURE(Autocorrelation); ADDFEATURE(ClusterShade); ADDFEATURE(ClusterTendency); ADDFEATURE(ClusterProminence); ADDFEATURE(FirstMeasureOfInformationCorrelation); ADDFEATURE(SecondMeasureOfInformationCorrelation); } NormalizeMatrixFeature(meanFeature, featureList.size()); NormalizeMatrixFeature(stdFeature, featureList.size()); CALCVARIANCE(JointMaximum); CALCVARIANCE(JointAverage); CALCVARIANCE(JointVariance); CALCVARIANCE(JointEntropy); CALCVARIANCE(RowMaximum); CALCVARIANCE(RowAverage); CALCVARIANCE(RowVariance); CALCVARIANCE(RowEntropy); CALCVARIANCE(FirstRowColumnEntropy); CALCVARIANCE(SecondRowColumnEntropy); CALCVARIANCE(DifferenceAverage); CALCVARIANCE(DifferenceVariance); CALCVARIANCE(DifferenceEntropy); CALCVARIANCE(SumAverage); CALCVARIANCE(SumVariance); CALCVARIANCE(SumEntropy); CALCVARIANCE(AngularSecondMoment); CALCVARIANCE(Contrast); CALCVARIANCE(Dissimilarity); CALCVARIANCE(InverseDifference); CALCVARIANCE(InverseDifferenceNormalised); CALCVARIANCE(InverseDifferenceMoment); CALCVARIANCE(InverseDifferenceMomentNormalised); CALCVARIANCE(InverseVariance); CALCVARIANCE(Correlation); CALCVARIANCE(Autocorrelation); CALCVARIANCE(ClusterShade); CALCVARIANCE(ClusterTendency); CALCVARIANCE(ClusterProminence); CALCVARIANCE(FirstMeasureOfInformationCorrelation); CALCVARIANCE(SecondMeasureOfInformationCorrelation); #undef ADDFEATURE #undef CALCVARIANCE } static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number) { features.JointMaximum = features.JointMaximum / number; features.JointAverage = features.JointAverage / number; features.JointVariance = features.JointVariance / number; features.JointEntropy = features.JointEntropy / number; features.RowMaximum = features.RowMaximum / number; features.RowAverage = features.RowAverage / number; features.RowVariance = features.RowVariance / number; features.RowEntropy = features.RowEntropy / number; features.FirstRowColumnEntropy = features.FirstRowColumnEntropy / number; features.SecondRowColumnEntropy = features.SecondRowColumnEntropy / number; features.DifferenceAverage = features.DifferenceAverage / number; features.DifferenceVariance = features.DifferenceVariance / number; features.DifferenceEntropy = features.DifferenceEntropy / number; features.SumAverage = features.SumAverage / number; features.SumVariance = features.SumVariance / number; features.SumEntropy = features.SumEntropy / number; features.AngularSecondMoment = features.AngularSecondMoment / number; features.Contrast = features.Contrast / number; features.Dissimilarity = features.Dissimilarity / number; features.InverseDifference = features.InverseDifference / number; features.InverseDifferenceNormalised = features.InverseDifferenceNormalised / number; features.InverseDifferenceMoment = features.InverseDifferenceMoment / number; features.InverseDifferenceMomentNormalised = features.InverseDifferenceMomentNormalised / number; features.InverseVariance = features.InverseVariance / number; features.Correlation = features.Correlation / number; features.Autocorrelation = features.Autocorrelation / number; features.ClusterShade = features.ClusterShade / number; features.ClusterTendency = features.ClusterTendency / number; features.ClusterProminence = features.ClusterProminence / number; features.FirstMeasureOfInformationCorrelation = features.FirstMeasureOfInformationCorrelation / number; features.SecondMeasureOfInformationCorrelation = features.SecondMeasureOfInformationCorrelation / number; } mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2(): -m_Range(1.0), m_Bins(128) +m_Range(1.0), m_Bins(128), m_Binsize(-1) { SetShortName("cooc2"); SetLongName("cooccurence2"); } mitk::GIFCooccurenceMatrix2::FeatureListType mitk::GIFCooccurenceMatrix2::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; GIFCooccurenceMatrix2Configuration config; config.direction = GetDirection(); config.range = m_Range; config.MinimumIntensity = GetMinimumIntensity(); config.MaximumIntensity = GetMaximumIntensity(); config.UseMinimumIntensity = GetUseMinimumIntensity(); config.UseMaximumIntensity = GetUseMaximumIntensity(); config.Bins = GetBins(); + config.BinSize = GetBinsize(); AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList,config); return featureList; } mitk::GIFCooccurenceMatrix2::FeatureNameListType mitk::GIFCooccurenceMatrix2::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFCooccurenceMatrix2::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Co-occurence matrix", "calculates Co-occurence based features (new implementation)", us::Any()); parser.addArgument(name+"::range", name+"::range", mitkCommandLineParser::String, "Cooc 2 Range", "Define the range that is used (Semicolon-separated)", us::Any()); parser.addArgument(name + "::bins", name + "::bins", mitkCommandLineParser::String, "Cooc 2 Number of Bins", "Define the number of bins that is used ", us::Any()); + parser.addArgument(name + "::binsize", name + "::binsize", mitkCommandLineParser::String, "Cooc 2 Number of Bins", "Define the number of bins that is used ", us::Any()); + } void mitk::GIFCooccurenceMatrix2::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); std::string name = GetOptionPrefix(); if (parsedArgs.count(GetLongName())) { std::vector ranges; if (parsedArgs.count(name + "::range")) { ranges = SplitDouble(parsedArgs[name + "::range"].ToString(), ';'); } else { ranges.push_back(1); } if (parsedArgs.count(name + "::bins")) { auto bins = SplitDouble(parsedArgs[name + "::bins"].ToString(), ';')[0]; this->SetBins(bins); } + if (parsedArgs.count(name + "::binsize")) + { + auto binsize = SplitDouble(parsedArgs[name + "::binsize"].ToString(), ';')[0]; + this->SetBinsize(binsize); + } for (std::size_t i = 0; i < ranges.size(); ++i) { MITK_INFO << "Start calculating coocurence with range " << ranges[i] << "...."; this->SetRange(ranges[i]); auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating coocurence with range " << ranges[i] << "...."; } } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp new file mode 100644 index 0000000000..c6cce01cbd --- /dev/null +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp @@ -0,0 +1,373 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +// MITK +#include +#include +#include + +// ITK +#include +#include +#include + +// STL +#include +#include +#include + +#define GET_VARIABLE_INDEX(value) \ + mv[0] = value; \ + histogram->GetIndex(mv, resultingIndex); + + +template +void +CalculateFirstOrderHistogramStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFFirstOrderHistogramStatistics::FeatureListType & featureList, mitk::GIFFirstOrderHistogramStatistics::ParameterStruct params) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + typedef itk::LabelStatisticsImageFilter FilterType; + typedef typename FilterType::HistogramType HistogramType; + typedef typename HistogramType::IndexType HIndexType; + typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; + + typename MaskType::Pointer maskImage = MaskType::New(); + mitk::CastToItkImage(mask, maskImage); + + typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); + minMaxComputer->SetImage(itkImage); + minMaxComputer->Compute(); + + itk::ImageRegionConstIteratorWithIndex imageIter(itkImage, itkImage->GetLargestPossibleRegion()); + itk::ImageRegionConstIteratorWithIndex maskIter(maskImage, maskImage->GetLargestPossibleRegion()); + + TPixel minimum = std::numeric_limits::max(); + TPixel maximum = std::numeric_limits::min(); + + while (!imageIter.IsAtEnd()) + { + if (maskIter.Get() > 0) + { + minimum = (imageIter.Get() < minimum) ? imageIter.Get() : minimum; + maximum = (imageIter.Get() > maximum) ? imageIter.Get() : maximum; + } + ++imageIter; +++maskIter; + } + + typename FilterType::Pointer labelStatisticsImageFilter = FilterType::New(); + labelStatisticsImageFilter->SetInput(itkImage); + labelStatisticsImageFilter->SetLabelInput(maskImage); + labelStatisticsImageFilter->SetUseHistograms(true); + if (params.BinSize < 0) + { + labelStatisticsImageFilter->SetHistogramParameters(params.Bins, minimum, maximum); + } + else + { + int tmpBins = std::ceil((maximum - minimum) / params.BinSize); + double tmpMax = minimum + tmpBins * params.BinSize; + labelStatisticsImageFilter->SetHistogramParameters(tmpBins, minimum, tmpMax); + } + labelStatisticsImageFilter->Update(); + + + HistogramType::MeasurementVectorType mv(1); + mv[0] = 4.1; + HistogramType::IndexType resultingIndex; + + + auto histogram = labelStatisticsImageFilter->GetHistogram(1); + double meanValue = 0; // labelStatisticsImageFilter->GetMean(1); + GET_VARIABLE_INDEX(meanValue); + double meanIndex = 0; // resultingIndex[0]; + //double varianceValue = labelStatisticsImageFilter->GetVariance(1); + //GET_VARIABLE_INDEX(varianceValue); + //auto varianceIndex = resultingIndex[0]; + double medianValue = labelStatisticsImageFilter->GetMedian(1); + GET_VARIABLE_INDEX(medianValue); + double medianIndex = resultingIndex[0]; + double minimumValue = labelStatisticsImageFilter->GetMinimum(1); + GET_VARIABLE_INDEX(minimumValue); + double minimumIndex = resultingIndex[0]; + double p10Value = histogram->Quantile(0, 0.10); + GET_VARIABLE_INDEX(p10Value); + double p10Index = resultingIndex[0]; + double p25Value = histogram->Quantile(0, 0.25); + GET_VARIABLE_INDEX(p25Value); + double p25Index = resultingIndex[0]; + double p75Value = histogram->Quantile(0, 0.75); + GET_VARIABLE_INDEX(p75Value); + double p75Index = resultingIndex[0]; + double p90Value = histogram->Quantile(0, 0.90); + GET_VARIABLE_INDEX(p90Value); + double p90Index = resultingIndex[0]; + double maximumValue = labelStatisticsImageFilter->GetMaximum(1); + GET_VARIABLE_INDEX(maximumValue); + double maximumIndex = resultingIndex[0]; + + double Log2 = log(2); + HIndexType index; + HIndexType index2; + index.SetSize(1); + index2.SetSize(1); + double binWidth = histogram->GetBinMax(0, 0) - histogram->GetBinMin(0, 0); + double count = labelStatisticsImageFilter->GetCount(1); + + double robustMeanValue = 0; + double robustMeanIndex = 0; + double robustCount = 0; + + for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) + { + index[0] = i; + double frequence = histogram->GetFrequency(index); + double probability = frequence / count; + double voxelValue = histogram->GetBinMin(0, i) + binWidth * 0.5; + + meanValue += probability * voxelValue; + meanIndex += probability * (i); + + if ((i >= p10Index) && (i <= p90Index)) + { + robustMeanValue += frequence * voxelValue; + robustMeanIndex += frequence * i; + robustCount += frequence; + } + } + robustMeanValue /= robustCount; + robustMeanIndex /= robustCount; + + double varianceValue = 0; + double varianceIndex = 0; + double skewnessValue = 0; + double skewnessIndex = 0; + double kurtosisValue = 0; + double kurtosisIndex = 0; + double modeValue = 0; + double modeIndex = 0; + double modeFrequence = 0; + double meanAbsoluteDeviationValue = 0; + double meanAbsoluteDeviationIndex = 0; + double robustMeanAbsoluteDeviationValue = 0; + double robustMeanAbsoluteDeivationIndex = 0; + double medianAbsoluteDeviationValue = 0; + double medianAbsoluteDeviationIndex = 0; + double coefficientOfVariationValue = 0; + double coefficientOfVariationIndex = 0; + double quantileCoefficientOfDispersionValue = 0; + double quantileCoefficientOfDispersionIndex = 0; + double entropyValue = 0; + double entropyIndex = 0; + double uniformityValue = 0; + double uniformityIndex = 0; + + double maximumGradientValue = std::numeric_limits::min(); + double maximumGradientIndex = 0; + double minimumGradientValue = std::numeric_limits::max(); + double minimumGradientIndex = 0; + + double gradient = 0; + + for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) + { + index[0] = i; + double frequence = histogram->GetFrequency(index); + double probability = frequence / count; + double voxelValue = histogram->GetBinMin(0, i) + binWidth * 0.5; + + double deltaValue = (voxelValue - meanValue); + double deltaIndex = (i - meanIndex); + + varianceValue += probability * deltaValue * deltaValue; + varianceIndex += probability * deltaIndex * deltaIndex; + skewnessValue += probability * deltaValue * deltaValue * deltaValue; + skewnessIndex += probability * deltaIndex * deltaIndex * deltaIndex; + kurtosisValue += probability * deltaValue * deltaValue * deltaValue * deltaValue; + kurtosisIndex += probability * deltaIndex * deltaIndex * deltaIndex * deltaIndex; + + if (modeFrequence < frequence) + { + modeFrequence = frequence; + modeValue = voxelValue; + modeIndex = i; + } + meanAbsoluteDeviationValue += probability * std::abs(deltaValue); + meanAbsoluteDeviationIndex += probability * std::abs(deltaIndex); + if ((i >= p10Index) && (i <= p90Index)) + { + robustMeanAbsoluteDeviationValue += frequence * std::abs(voxelValue - robustMeanValue); + robustMeanAbsoluteDeivationIndex += frequence * std::abs(i*1.0 - robustMeanIndex*1.0); + } + medianAbsoluteDeviationValue += probability * std::abs(voxelValue - medianValue); + medianAbsoluteDeviationIndex += probability * std::abs(i*1.0 - medianIndex); + if (probability > 0.0000001) + { + entropyValue -= probability * std::log(probability) / Log2; + entropyIndex = entropyValue; + } + uniformityValue += probability*probability; + uniformityIndex = uniformityValue; + if (i == 0) + { + index[0] = 1; index2[0] = 0; + gradient = histogram->GetFrequency(index)*1.0 - histogram->GetFrequency(index2)*1.0; + } + else if (i == (int)(histogram->GetSize(0)) - 1) + { + index[0] = i; index2[0] = i - 1; + gradient = histogram->GetFrequency(index)*1.0 - histogram->GetFrequency(index2)*1.0; + } + else + { + index[0] = i+1; index2[0] = i - 1; + gradient = (histogram->GetFrequency(index)*1.0 - histogram->GetFrequency(index2)*1.0) / 2.0; + } + if (gradient > maximumGradientValue) + { + maximumGradientValue = gradient; + maximumGradientIndex = i + 1; + } + if (gradient < minimumGradientValue) + { + minimumGradientValue = gradient; + minimumGradientIndex = i + 1; + } + } + skewnessValue = skewnessValue / (varianceValue * std::sqrt(varianceValue)); + skewnessIndex = skewnessIndex / (varianceIndex * std::sqrt(varianceIndex)); + kurtosisValue = kurtosisValue / (varianceValue * varianceValue) - 3; // Excess Kurtosis + kurtosisIndex = kurtosisIndex / (varianceIndex * varianceIndex) - 3; // Excess Kurtosis + coefficientOfVariationValue = std::sqrt(varianceValue) / meanValue; + coefficientOfVariationIndex = std::sqrt(varianceIndex) / (meanIndex+1); + quantileCoefficientOfDispersionValue = (p75Value - p25Value) / (p75Value + p25Value); + quantileCoefficientOfDispersionIndex = (p75Index - p25Index) / (p75Index + p25Index); + robustMeanAbsoluteDeviationValue /= robustCount; + robustMeanAbsoluteDeivationIndex /= robustCount; + + featureList.push_back(std::make_pair("FirstOrderHistogram Mean Value", meanValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Variance Value", varianceValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Skewness Value", skewnessValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Kurtosis Value", kurtosisValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Median Value", medianValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Minimum Value", minimumValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Percentile 10 Value", p10Value)); + featureList.push_back(std::make_pair("FirstOrderHistogram Percentile 90 Value", p90Value)); + featureList.push_back(std::make_pair("FirstOrderHistogram Maximum Value", maximumValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Mode Value", modeValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Interquantile Range Value", p75Value - p25Value)); + featureList.push_back(std::make_pair("FirstOrderHistogram Range Value", maximumValue - minimumValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Mean Absolute Deviation Value", meanAbsoluteDeviationValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Robust Mean Absolute Deviation Value", robustMeanAbsoluteDeviationValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Median Absolute Deviation Value", medianAbsoluteDeviationValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Coefficient of Variation Value", coefficientOfVariationValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Quantile coefficient of Dispersion Value", quantileCoefficientOfDispersionValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Entropy Value", entropyValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Uniformity Value", uniformityValue)); + + featureList.push_back(std::make_pair("FirstOrderHistogram Mean Index", meanIndex + 1 )); + featureList.push_back(std::make_pair("FirstOrderHistogram Variance Index", varianceIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram Skewness Index", skewnessIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram Kurtosis Index", kurtosisIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram Median Index", medianIndex + 1)); + featureList.push_back(std::make_pair("FirstOrderHistogram Minimum Index", minimumIndex + 1)); + featureList.push_back(std::make_pair("FirstOrderHistogram Percentile 10 Index", p10Index + 1)); + featureList.push_back(std::make_pair("FirstOrderHistogram Percentile 90 Index", p90Index + 1)); + featureList.push_back(std::make_pair("FirstOrderHistogram Maximum Index", maximumIndex + 1)); + featureList.push_back(std::make_pair("FirstOrderHistogram Mode Index", modeIndex + 1)); + featureList.push_back(std::make_pair("FirstOrderHistogram Interquantile Range Index", p75Index - p25Index)); + featureList.push_back(std::make_pair("FirstOrderHistogram Range Index", maximumIndex - minimumIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram Mean Absolute Deviation Index", meanAbsoluteDeviationIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram Robust Mean Absolute Deviation Index", robustMeanAbsoluteDeivationIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram Median Absolute Deviation Index", medianAbsoluteDeviationIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram Coefficient of Variation Index", coefficientOfVariationIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram Quantile coefficient of Dispersion Index", quantileCoefficientOfDispersionIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram Entropy Index", entropyIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram Uniformity Index", uniformityIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram Maximum Gradient", maximumGradientValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Maximum Gradient Index", maximumGradientIndex)); + featureList.push_back(std::make_pair("FirstOrderHistogram Minimum Gradient", minimumGradientValue)); + featureList.push_back(std::make_pair("FirstOrderHistogram Minimum Gradient Index", minimumGradientIndex)); + + featureList.push_back(std::make_pair("FirstOrderHistogram Number of Bins", histogram->GetSize(0))); + featureList.push_back(std::make_pair("FirstOrderHistogram Bin Size", binWidth)); +} + +mitk::GIFFirstOrderHistogramStatistics::GIFFirstOrderHistogramStatistics() : +m_HistogramSize(256), m_UseCtRange(false), m_BinSize(-1) +{ + SetShortName("foh"); + SetLongName("first-order-histogram"); +} + +mitk::GIFFirstOrderHistogramStatistics::FeatureListType mitk::GIFFirstOrderHistogramStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +{ + FeatureListType featureList; + + ParameterStruct params; + params.m_HistogramSize = this->m_HistogramSize; + params.m_UseCtRange = this->m_UseCtRange; + + params.MinimumIntensity = GetMinimumIntensity(); + params.MaximumIntensity = GetMaximumIntensity(); + params.UseMinimumIntensity = GetUseMinimumIntensity(); + params.UseMaximumIntensity = GetUseMaximumIntensity(); + params.Bins = GetBins(); + params.BinSize = GetBinSize(); + + AccessByItk_3(image, CalculateFirstOrderHistogramStatistics, mask, featureList, params); + + return featureList; +} + +mitk::GIFFirstOrderHistogramStatistics::FeatureNameListType mitk::GIFFirstOrderHistogramStatistics::GetFeatureNames() +{ + FeatureNameListType featureList; + return featureList; +} + + +void mitk::GIFFirstOrderHistogramStatistics::AddArguments(mitkCommandLineParser &parser) +{ + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Volume-Statistic", "calculates volume based features", us::Any()); + parser.addArgument(name + "::binsize", name + "::binsize", mitkCommandLineParser::Float, "RL Bins", "Define the number of bins that is used (Semicolon-separated)", us::Any()); + +} + +void +mitk::GIFFirstOrderHistogramStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +{ + std::string name = GetOptionPrefix(); + auto parsedArgs = GetParameter(); + if (parsedArgs.count(GetLongName())) + { + MITK_INFO << "Start calculating first order features ...."; + if (parsedArgs.count(name + "::binsize")) + { + auto binsize = SplitDouble(parsedArgs[name + "::binsize"].ToString(), ';')[0]; + SetBinSize(binsize); + } + auto localResults = this->CalculateFeatures(feature, maskNoNAN); + featureList.insert(featureList.end(), localResults.begin(), localResults.end()); + MITK_INFO << "Finished calculating first order features...."; + } +} + diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp index 12e51bc740..5e7e4eec48 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp @@ -1,324 +1,339 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include // MITK #include #include #include // ITK #include #include // STL #include template void CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFFirstOrderStatistics::FeatureListType & featureList, mitk::GIFFirstOrderStatistics::ParameterStruct params) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::LabelStatisticsImageFilter FilterType; typedef typename FilterType::HistogramType HistogramType; typedef typename HistogramType::IndexType HIndexType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); double voxelVolume = 1; for (int i = 0; i < std::min(3, VImageDimension); ++i) voxelVolume *= itkImage->GetSpacing()[i]; double voxelSpace = 1; for (int i = 0; i < int(VImageDimension); ++i) voxelSpace *= itkImage->GetSpacing()[i]; typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); minMaxComputer->SetImage(itkImage); minMaxComputer->Compute(); double imageRange = minMaxComputer->GetMaximum() - minMaxComputer->GetMinimum(); typename FilterType::Pointer labelStatisticsImageFilter = FilterType::New(); labelStatisticsImageFilter->SetInput( itkImage ); labelStatisticsImageFilter->SetLabelInput(maskImage); labelStatisticsImageFilter->SetUseHistograms(true); if (params.m_UseCtRange) { labelStatisticsImageFilter->SetHistogramParameters(1024.5+3096.5, -1024.5,3096.5); } else { double min = minMaxComputer->GetMinimum() -0.5; double max = minMaxComputer->GetMaximum() +0.5; if (params.UseMinimumIntensity) min = params.MinimumIntensity; if (params.UseMaximumIntensity) max = params.MaximumIntensity; labelStatisticsImageFilter->SetHistogramParameters(params.Bins, min,max); } labelStatisticsImageFilter->Update(); // --------------- Range -------------------- double range = labelStatisticsImageFilter->GetMaximum(1) - labelStatisticsImageFilter->GetMinimum(1); // --------------- Uniformity, Entropy -------------------- double count = labelStatisticsImageFilter->GetCount(1); //double std_dev = labelStatisticsImageFilter->GetSigma(1); double mean = labelStatisticsImageFilter->GetMean(1); + double median = labelStatisticsImageFilter->GetMedian(1); auto histogram = labelStatisticsImageFilter->GetHistogram(1); bool histogramIsCalculated = histogram; HIndexType index; index.SetSize(1); double uniformity = 0; double entropy = 0; double squared_sum = 0; double kurtosis = 0; double mean_absolut_deviation = 0; + double median_absolut_deviation = 0; double skewness = 0; double sum_prob = 0; double binWidth = 0; double p05th = 0, p10th = 0, p15th = 0, p20th = 0, p25th = 0, p30th = 0, p35th = 0, p40th = 0, p45th = 0, p50th = 0; double p55th = 0, p60th = 0, p65th = 0, p70th = 0, p75th = 0, p80th = 0, p85th = 0, p90th = 0, p95th = 0; double voxelValue = 0; if (histogramIsCalculated) { binWidth = histogram->GetBinMax(0, 0) - histogram->GetBinMin(0, 0); p05th = histogram->Quantile(0, 0.05); p10th = histogram->Quantile(0, 0.10); p15th = histogram->Quantile(0, 0.15); p20th = histogram->Quantile(0, 0.20); p25th = histogram->Quantile(0, 0.25); p30th = histogram->Quantile(0, 0.30); p35th = histogram->Quantile(0, 0.35); p40th = histogram->Quantile(0, 0.40); p45th = histogram->Quantile(0, 0.45); p50th = histogram->Quantile(0, 0.50); p55th = histogram->Quantile(0, 0.55); p60th = histogram->Quantile(0, 0.60); p65th = histogram->Quantile(0, 0.65); p70th = histogram->Quantile(0, 0.70); p75th = histogram->Quantile(0, 0.75); p80th = histogram->Quantile(0, 0.80); p85th = histogram->Quantile(0, 0.85); p90th = histogram->Quantile(0, 0.90); p95th = histogram->Quantile(0, 0.95); } double Log2=log(2); double mode_bin; double mode_value = 0; double variance = 0; if (histogramIsCalculated) { for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; double prob = histogram->GetFrequency(index); if (prob < 0.00000001) continue; voxelValue = histogram->GetBinMin(0, i) + binWidth * 0.5; if (prob > mode_value) { mode_value = prob; mode_bin = voxelValue; } sum_prob += prob; squared_sum += prob * voxelValue*voxelValue; prob /= count; mean_absolut_deviation += prob* std::abs(voxelValue - mean); + median_absolut_deviation += prob* std::abs(voxelValue - median); variance += prob * (voxelValue - mean) * (voxelValue - mean); kurtosis += prob* (voxelValue - mean) * (voxelValue - mean) * (voxelValue - mean) * (voxelValue - mean); skewness += prob* (voxelValue - mean) * (voxelValue - mean) * (voxelValue - mean); uniformity += prob*prob; if (prob > 0) { entropy += prob * std::log(prob) / Log2; } } } entropy = -entropy; double uncorrected_std_dev = std::sqrt(variance); double rms = std::sqrt(squared_sum / count); kurtosis = kurtosis / (variance * variance); skewness = skewness / (variance * uncorrected_std_dev); - //mean_absolut_deviation = mean_absolut_deviation; double coveredGrayValueRange = range / imageRange; - - featureList.push_back(std::make_pair("FirstOrder Range",range)); - featureList.push_back(std::make_pair("FirstOrder Uniformity",uniformity)); - featureList.push_back(std::make_pair("FirstOrder Entropy",entropy)); - featureList.push_back(std::make_pair("FirstOrder Energy",squared_sum)); - featureList.push_back(std::make_pair("FirstOrder RMS",rms)); - featureList.push_back(std::make_pair("FirstOrder Kurtosis", kurtosis)); - featureList.push_back(std::make_pair("FirstOrder Excess Kurtosis", kurtosis-3)); - featureList.push_back(std::make_pair("FirstOrder Skewness",skewness)); - featureList.push_back(std::make_pair("FirstOrder Mean absolute deviation",mean_absolut_deviation)); - featureList.push_back(std::make_pair("FirstOrder Covered Image Intensity Range",coveredGrayValueRange)); - - featureList.push_back(std::make_pair("FirstOrder Minimum",labelStatisticsImageFilter->GetMinimum(1))); - featureList.push_back(std::make_pair("FirstOrder Maximum",labelStatisticsImageFilter->GetMaximum(1))); - featureList.push_back(std::make_pair("FirstOrder Mean",labelStatisticsImageFilter->GetMean(1))); - featureList.push_back(std::make_pair("FirstOrder Unbiased Variance", labelStatisticsImageFilter->GetVariance(1))); //Siehe Definition von Unbiased Variance estimation. (Wird nicht durch n sondern durch n-1 normalisiert) - featureList.push_back(std::make_pair("FirstOrder Biased Variance", variance)); - featureList.push_back(std::make_pair("FirstOrder Sum",labelStatisticsImageFilter->GetSum(1))); - featureList.push_back(std::make_pair("FirstOrder Median", labelStatisticsImageFilter->GetMedian(1))); - featureList.push_back(std::make_pair("FirstOrder Mode", mode_bin)); - featureList.push_back(std::make_pair("FirstOrder Mode Probability", mode_value)); - featureList.push_back(std::make_pair("FirstOrder Standard deviation",labelStatisticsImageFilter->GetSigma(1))); - featureList.push_back(std::make_pair("FirstOrder No. of Voxel",labelStatisticsImageFilter->GetCount(1))); - - featureList.push_back(std::make_pair("FirstOrder 05th Percentile", p05th)); - featureList.push_back(std::make_pair("FirstOrder 10th Percentile", p10th)); - featureList.push_back(std::make_pair("FirstOrder 15th Percentile", p15th)); - featureList.push_back(std::make_pair("FirstOrder 20th Percentile", p20th)); - featureList.push_back(std::make_pair("FirstOrder 25th Percentile", p25th)); - featureList.push_back(std::make_pair("FirstOrder 30th Percentile", p30th)); - featureList.push_back(std::make_pair("FirstOrder 35th Percentile", p35th)); - featureList.push_back(std::make_pair("FirstOrder 40th Percentile", p40th)); - featureList.push_back(std::make_pair("FirstOrder 45th Percentile", p45th)); - featureList.push_back(std::make_pair("FirstOrder 50th Percentile", p50th)); - featureList.push_back(std::make_pair("FirstOrder 55th Percentile", p55th)); - featureList.push_back(std::make_pair("FirstOrder 60th Percentile", p60th)); - featureList.push_back(std::make_pair("FirstOrder 65th Percentile", p65th)); - featureList.push_back(std::make_pair("FirstOrder 70th Percentile", p70th)); - featureList.push_back(std::make_pair("FirstOrder 75th Percentile", p75th)); - featureList.push_back(std::make_pair("FirstOrder 80th Percentile", p80th)); - featureList.push_back(std::make_pair("FirstOrder 85th Percentile", p85th)); - featureList.push_back(std::make_pair("FirstOrder 90th Percentile", p90th)); - featureList.push_back(std::make_pair("FirstOrder 95th Percentile", p95th)); - featureList.push_back(std::make_pair("FirstOrder Interquartile Range",(p75th - p25th))); - featureList.push_back(std::make_pair("FirstOrder Image Dimension", VImageDimension)); - featureList.push_back(std::make_pair("FirstOrder Voxel Space", voxelSpace)); - featureList.push_back(std::make_pair("FirstOrder Voxel Volume", voxelVolume)); + double coefficient_of_variation = (mean == 0) ? 0 : std::sqrt(variance) / mean; + double quantile_coefficient_of_dispersion = (p75th - p25th) / (p75th + p25th); //Calculate the robust mean absolute deviation //First, set all frequencies to 0 that are <10th or >90th percentile double meanRobust = 0.0; double robustMeanAbsoluteDeviation = 0.0; if (histogramIsCalculated) { for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; if (histogram->GetBinMax(0, i) < p10th) { histogram->SetFrequencyOfIndex(index, 0); } else if (histogram->GetBinMin(0, i) > p90th) { histogram->SetFrequencyOfIndex(index, 0); } } //Calculate the mean for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; meanRobust += histogram->GetFrequency(index) * 0.5 * (histogram->GetBinMin(0, i) + histogram->GetBinMax(0, i)); } meanRobust = meanRobust / histogram->GetTotalFrequency(); for (int i = 0; i < (int)(histogram->GetSize(0)); ++i) { index[0] = i; robustMeanAbsoluteDeviation += std::abs(histogram->GetFrequency(index) * ((0.5 * (histogram->GetBinMin(0, i) + histogram->GetBinMax(0, i))) - meanRobust )); } robustMeanAbsoluteDeviation = robustMeanAbsoluteDeviation / histogram->GetTotalFrequency(); } - featureList.push_back(std::make_pair("FirstOrder Robust Mean", meanRobust)); + + featureList.push_back(std::make_pair("FirstOrder Mean", labelStatisticsImageFilter->GetMean(1))); + featureList.push_back(std::make_pair("FirstOrder Unbiased Variance", labelStatisticsImageFilter->GetVariance(1))); //Siehe Definition von Unbiased Variance estimation. (Wird nicht durch n sondern durch n-1 normalisiert) + featureList.push_back(std::make_pair("FirstOrder Biased Variance", variance)); + featureList.push_back(std::make_pair("FirstOrder Skewness", skewness)); + featureList.push_back(std::make_pair("FirstOrder Kurtosis", kurtosis)); + featureList.push_back(std::make_pair("FirstOrder Median", labelStatisticsImageFilter->GetMedian(1))); + featureList.push_back(std::make_pair("FirstOrder Minimum", labelStatisticsImageFilter->GetMinimum(1))); + featureList.push_back(std::make_pair("FirstOrder Maximum", labelStatisticsImageFilter->GetMaximum(1))); + featureList.push_back(std::make_pair("FirstOrder Range", range)); + featureList.push_back(std::make_pair("FirstOrder Mean absolute deviation", mean_absolut_deviation)); featureList.push_back(std::make_pair("FirstOrder Robust Mean Absolute Deviation", robustMeanAbsoluteDeviation)); + featureList.push_back(std::make_pair("FirstOrder Median absolute deviation", median_absolut_deviation)); + featureList.push_back(std::make_pair("FirstOrder Coefficient of variation", coefficient_of_variation)); + featureList.push_back(std::make_pair("FirstOrder Quantile coefficient of dispersion", quantile_coefficient_of_dispersion)); + featureList.push_back(std::make_pair("FirstOrder Energy", squared_sum)); + featureList.push_back(std::make_pair("FirstOrder RMS", rms)); + + HistogramType::MeasurementVectorType mv(1); + mv[0] = 0; + HistogramType::IndexType resultingIndex; + histogram->GetIndex(mv, resultingIndex); + MITK_INFO << "aaa" << resultingIndex; + std::cout << "Instance identifier of index " << resultingIndex + << " is " << histogram->GetInstanceIdentifier(resultingIndex) + << std::endl; + featureList.push_back(std::make_pair("FirstOrder Minimum Bin", 0)); + featureList.push_back(std::make_pair("FirstOrder Robust Mean", meanRobust)); + featureList.push_back(std::make_pair("FirstOrder Uniformity", uniformity)); + featureList.push_back(std::make_pair("FirstOrder Entropy", entropy)); + featureList.push_back(std::make_pair("FirstOrder Excess Kurtosis", kurtosis - 3)); + featureList.push_back(std::make_pair("FirstOrder Covered Image Intensity Range", coveredGrayValueRange)); + featureList.push_back(std::make_pair("FirstOrder Sum", labelStatisticsImageFilter->GetSum(1))); + featureList.push_back(std::make_pair("FirstOrder Mode", mode_bin)); + featureList.push_back(std::make_pair("FirstOrder Mode Probability", mode_value)); + featureList.push_back(std::make_pair("FirstOrder Standard deviation", labelStatisticsImageFilter->GetSigma(1))); + featureList.push_back(std::make_pair("FirstOrder No. of Voxel", labelStatisticsImageFilter->GetCount(1))); + featureList.push_back(std::make_pair("FirstOrder 05th Percentile", p05th)); + featureList.push_back(std::make_pair("FirstOrder 10th Percentile", p10th)); + featureList.push_back(std::make_pair("FirstOrder 15th Percentile", p15th)); + featureList.push_back(std::make_pair("FirstOrder 20th Percentile", p20th)); + featureList.push_back(std::make_pair("FirstOrder 25th Percentile", p25th)); + featureList.push_back(std::make_pair("FirstOrder 30th Percentile", p30th)); + featureList.push_back(std::make_pair("FirstOrder 35th Percentile", p35th)); + featureList.push_back(std::make_pair("FirstOrder 40th Percentile", p40th)); + featureList.push_back(std::make_pair("FirstOrder 45th Percentile", p45th)); + featureList.push_back(std::make_pair("FirstOrder 50th Percentile", p50th)); + featureList.push_back(std::make_pair("FirstOrder 55th Percentile", p55th)); + featureList.push_back(std::make_pair("FirstOrder 60th Percentile", p60th)); + featureList.push_back(std::make_pair("FirstOrder 65th Percentile", p65th)); + featureList.push_back(std::make_pair("FirstOrder 70th Percentile", p70th)); + featureList.push_back(std::make_pair("FirstOrder 75th Percentile", p75th)); + featureList.push_back(std::make_pair("FirstOrder 80th Percentile", p80th)); + featureList.push_back(std::make_pair("FirstOrder 85th Percentile", p85th)); + featureList.push_back(std::make_pair("FirstOrder 90th Percentile", p90th)); + featureList.push_back(std::make_pair("FirstOrder 95th Percentile", p95th)); + featureList.push_back(std::make_pair("FirstOrder Interquartile Range", (p75th - p25th))); + featureList.push_back(std::make_pair("FirstOrder Image Dimension", VImageDimension)); + featureList.push_back(std::make_pair("FirstOrder Voxel Space", voxelSpace)); + featureList.push_back(std::make_pair("FirstOrder Voxel Volume", voxelVolume)); } mitk::GIFFirstOrderStatistics::GIFFirstOrderStatistics() : m_HistogramSize(256), m_UseCtRange(false) { SetShortName("fo"); SetLongName("first-order"); } mitk::GIFFirstOrderStatistics::FeatureListType mitk::GIFFirstOrderStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; ParameterStruct params; params.m_HistogramSize = this->m_HistogramSize; params.m_UseCtRange = this->m_UseCtRange; params.MinimumIntensity = GetMinimumIntensity(); params.MaximumIntensity = GetMaximumIntensity(); params.UseMinimumIntensity = GetUseMinimumIntensity(); params.UseMaximumIntensity = GetUseMaximumIntensity(); params.Bins = GetBins(); AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, params); return featureList; } mitk::GIFFirstOrderStatistics::FeatureNameListType mitk::GIFFirstOrderStatistics::GetFeatureNames() { FeatureNameListType featureList; featureList.push_back("FirstOrder Minimum"); featureList.push_back("FirstOrder Maximum"); featureList.push_back("FirstOrder Mean"); featureList.push_back("FirstOrder Variance"); featureList.push_back("FirstOrder Sum"); featureList.push_back("FirstOrder Median"); featureList.push_back("FirstOrder Standard deviation"); featureList.push_back("FirstOrder No. of Voxel"); return featureList; } void mitk::GIFFirstOrderStatistics::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Volume-Statistic", "calculates volume based features", us::Any()); } void mitk::GIFFirstOrderStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { MITK_INFO << "Start calculating first order features ...."; auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating first order features...."; } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGrayLevelRunLength.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGrayLevelRunLength.cpp index eb446f7f21..7f4c83d1d9 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGrayLevelRunLength.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGrayLevelRunLength.cpp @@ -1,340 +1,338 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include // MITK #include #include #include // ITK #include #include // STL #include template void CalculateGrayLevelRunLengthFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFGrayLevelRunLength::FeatureListType & featureList, mitk::GIFGrayLevelRunLength::ParameterStruct params) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::Statistics::EnhancedScalarImageToRunLengthFeaturesFilter FilterType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typedef typename FilterType::RunLengthFeaturesFilterType TextureFilterType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); typename FilterType::Pointer filter = FilterType::New(); typename FilterType::Pointer filter2 = FilterType::New(); typename FilterType::OffsetVector::Pointer newOffset = FilterType::OffsetVector::New(); auto oldOffsets = filter->GetOffsets(); auto oldOffsetsIterator = oldOffsets->Begin(); while (oldOffsetsIterator != oldOffsets->End()) { bool continueOuterLoop = false; typename FilterType::OffsetType offset = oldOffsetsIterator->Value(); for (unsigned int i = 0; i < VImageDimension; ++i) { if (params.m_Direction == i + 2 && offset[i] != 0) { continueOuterLoop = true; } } if (params.m_Direction == 1) { offset[0] = 0; offset[1] = 0; offset[2] = 1; newOffset->push_back(offset); break; } oldOffsetsIterator++; if (continueOuterLoop) continue; newOffset->push_back(offset); } filter->SetOffsets(newOffset); filter2->SetOffsets(newOffset); // All features are required typename FilterType::FeatureNameVectorPointer requestedFeatures = FilterType::FeatureNameVector::New(); requestedFeatures->push_back(TextureFilterType::ShortRunEmphasis); requestedFeatures->push_back(TextureFilterType::LongRunEmphasis); requestedFeatures->push_back(TextureFilterType::GreyLevelNonuniformity); requestedFeatures->push_back(TextureFilterType::GreyLevelNonuniformityNormalized); requestedFeatures->push_back(TextureFilterType::RunLengthNonuniformity); requestedFeatures->push_back(TextureFilterType::RunLengthNonuniformityNormalized); requestedFeatures->push_back(TextureFilterType::LowGreyLevelRunEmphasis); requestedFeatures->push_back(TextureFilterType::HighGreyLevelRunEmphasis); requestedFeatures->push_back(TextureFilterType::ShortRunLowGreyLevelEmphasis); requestedFeatures->push_back(TextureFilterType::ShortRunHighGreyLevelEmphasis); requestedFeatures->push_back(TextureFilterType::LongRunLowGreyLevelEmphasis); requestedFeatures->push_back(TextureFilterType::LongRunHighGreyLevelEmphasis); requestedFeatures->push_back(TextureFilterType::RunPercentage); requestedFeatures->push_back(TextureFilterType::NumberOfRuns); requestedFeatures->push_back(TextureFilterType::GreyLevelVariance); requestedFeatures->push_back(TextureFilterType::RunLengthVariance); requestedFeatures->push_back(TextureFilterType::RunEntropy); typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); minMaxComputer->SetImage(itkImage); minMaxComputer->Compute(); filter->SetInput(itkImage); filter->SetMaskImage(maskImage); filter->SetRequestedFeatures(requestedFeatures); filter2->SetInput(itkImage); filter2->SetMaskImage(maskImage); filter2->SetRequestedFeatures(requestedFeatures); int rangeOfPixels = params.Bins; if (rangeOfPixels < 2) rangeOfPixels = 256; if (params.m_UseCtRange) { filter->SetPixelValueMinMax((TPixel)(-1024.5),(TPixel)(3096.5)); filter->SetNumberOfBinsPerAxis(3096.5 + 1024.5); filter2->SetPixelValueMinMax((TPixel)(-1024.5), (TPixel)(3096.5)); filter2->SetNumberOfBinsPerAxis(3096.5 + 1024.5); } else { double minRange = minMaxComputer->GetMinimum() - 0.5; double maxRange = minMaxComputer->GetMaximum() + 0.5; if (params.UseMinimumIntensity) minRange = params.MinimumIntensity; if (params.UseMaximumIntensity) maxRange = params.MaximumIntensity; - MITK_INFO << minRange << " " << maxRange; - filter->SetPixelValueMinMax(minRange, maxRange); filter->SetNumberOfBinsPerAxis(rangeOfPixels); filter2->SetPixelValueMinMax(minRange, maxRange); filter2->SetNumberOfBinsPerAxis(rangeOfPixels); } filter->SetDistanceValueMinMax(0, rangeOfPixels); filter2->SetDistanceValueMinMax(0, rangeOfPixels); filter2->CombinedFeatureCalculationOn(); filter->Update(); filter2->Update(); auto featureMeans = filter->GetFeatureMeans (); auto featureStd = filter->GetFeatureStandardDeviations(); auto featureCombined = filter2->GetFeatureMeans(); std::ostringstream ss; ss << rangeOfPixels; std::string strRange = ss.str(); for (std::size_t i = 0; i < featureMeans->size(); ++i) { switch (i) { case TextureFilterType::ShortRunEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") ShortRunEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") ShortRunEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") ShortRunEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::LongRunEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") LongRunEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LongRunEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LongRunEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::GreyLevelNonuniformity : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") GreyLevelNonuniformity Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") GreyLevelNonuniformity Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") GreyLevelNonuniformity Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::GreyLevelNonuniformityNormalized : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") GreyLevelNonuniformityNormalized Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") GreyLevelNonuniformityNormalized Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") GreyLevelNonuniformityNormalized Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::RunLengthNonuniformity : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") RunLengthNonuniformity Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunLengthNonuniformity Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunLengthNonuniformity Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::RunLengthNonuniformityNormalized : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") RunLengthNonuniformityNormalized Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunLengthNonuniformityNormalized Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunLengthNonuniformityNormalized Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::LowGreyLevelRunEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") LowGreyLevelRunEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LowGreyLevelRunEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LowGreyLevelRunEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::HighGreyLevelRunEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") HighGreyLevelRunEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") HighGreyLevelRunEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") HighGreyLevelRunEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::ShortRunLowGreyLevelEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") ShortRunLowGreyLevelEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") ShortRunLowGreyLevelEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") ShortRunLowGreyLevelEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::ShortRunHighGreyLevelEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") ShortRunHighGreyLevelEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") ShortRunHighGreyLevelEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") ShortRunHighGreyLevelEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::LongRunLowGreyLevelEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") LongRunLowGreyLevelEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LongRunLowGreyLevelEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LongRunLowGreyLevelEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::LongRunHighGreyLevelEmphasis : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") LongRunHighGreyLevelEmphasis Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LongRunHighGreyLevelEmphasis Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") LongRunHighGreyLevelEmphasis Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::RunPercentage : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") RunPercentage Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunPercentage Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunPercentage Comb.", featureCombined->ElementAt(i)/newOffset->size())); break; case TextureFilterType::NumberOfRuns : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") NumberOfRuns Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") NumberOfRuns Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") NumberOfRuns Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::GreyLevelVariance : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") GreyLevelVariance Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") GreyLevelVariance Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") GreyLevelVariance Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::RunLengthVariance : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") RunLengthVariance Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunLengthVariance Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunLengthVariance Comb.", featureCombined->ElementAt(i))); break; case TextureFilterType::RunEntropy : featureList.push_back(std::make_pair("RunLength. ("+ strRange+") RunEntropy Means",featureMeans->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunEntropy Std.", featureStd->ElementAt(i))); featureList.push_back(std::make_pair("RunLength. (" + strRange + ") RunEntropy Comb.", featureCombined->ElementAt(i))); break; default: break; } } } mitk::GIFGrayLevelRunLength::GIFGrayLevelRunLength(): m_Range(1.0), m_UseCtRange(false) { SetShortName("rl"); SetLongName("run-length"); } mitk::GIFGrayLevelRunLength::FeatureListType mitk::GIFGrayLevelRunLength::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; ParameterStruct params; params.m_UseCtRange=m_UseCtRange; params.m_Range = m_Range; params.m_Direction = GetDirection(); params.MinimumIntensity = GetMinimumIntensity(); params.MaximumIntensity = GetMaximumIntensity(); params.UseMinimumIntensity = GetUseMinimumIntensity(); params.UseMaximumIntensity = GetUseMaximumIntensity(); params.Bins = GetBins(); MITK_INFO << params.MinimumIntensity; MITK_INFO << params.MaximumIntensity; MITK_INFO << params.m_UseCtRange; MITK_INFO << params.m_Direction; MITK_INFO << params.Bins; MITK_INFO << params.m_Range; AccessByItk_3(image, CalculateGrayLevelRunLengthFeatures, mask, featureList,params); return featureList; } mitk::GIFGrayLevelRunLength::FeatureNameListType mitk::GIFGrayLevelRunLength::GetFeatureNames() { FeatureNameListType featureList; featureList.push_back("RunLength. ShortRunEmphasis Means"); featureList.push_back("RunLength. ShortRunEmphasis Std."); featureList.push_back("RunLength. LongRunEmphasis Means"); featureList.push_back("RunLength. LongRunEmphasis Std."); featureList.push_back("RunLength. GreyLevelNonuniformity Means"); featureList.push_back("RunLength. GreyLevelNonuniformity Std."); featureList.push_back("RunLength. RunLengthNonuniformity Means"); featureList.push_back("RunLength. RunLengthNonuniformity Std."); featureList.push_back("RunLength. LowGreyLevelRunEmphasis Means"); featureList.push_back("RunLength. LowGreyLevelRunEmphasis Std."); featureList.push_back("RunLength. HighGreyLevelRunEmphasis Means"); featureList.push_back("RunLength. HighGreyLevelRunEmphasis Std."); featureList.push_back("RunLength. ShortRunLowGreyLevelEmphasis Means"); featureList.push_back("RunLength. ShortRunLowGreyLevelEmphasis Std."); featureList.push_back("RunLength. ShortRunHighGreyLevelEmphasis Means"); featureList.push_back("RunLength. ShortRunHighGreyLevelEmphasis Std."); featureList.push_back("RunLength. LongRunHighGreyLevelEmphasis Means"); featureList.push_back("RunLength. LongRunHighGreyLevelEmphasis Std."); return featureList; } void mitk::GIFGrayLevelRunLength::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Co-occurence matrix", "calculates Co-occurence based features (new implementation)", us::Any()); parser.addArgument(name + "::bins", name + "::bins", mitkCommandLineParser::String, "RL Bins", "Define the number of bins that is used (Semicolon-separated)", us::Any()); } void mitk::GIFGrayLevelRunLength::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); std::string name = GetOptionPrefix(); if (parsedArgs.count(GetLongName())) { std::vector bins; bins.push_back(GetBins()); if (parsedArgs.count(name + "::bins")) { bins = SplitDouble(parsedArgs[name + "::bins"].ToString(), ';'); } for (std::size_t i = 0; i < bins.size(); ++i) { MITK_INFO << "Start calculating Run-length with range " << bins[i] << "...."; this->SetBins(bins[i]); auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating Run-length with range " << bins[i] << "...."; } } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp new file mode 100644 index 0000000000..d74d0b34cb --- /dev/null +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp @@ -0,0 +1,524 @@ +#include + +// MITK +#include +#include +#include +#include +#include + +// ITK + +#include +#include +#include +#include +#include + +// STL +#include + +static +void MatrixFeaturesTo(mitk::GreyLevelDistanceZoneFeatures features, + std::string prefix, + mitk::GIFGreyLevelDistanceZone::FeatureListType &featureList); + + + +mitk::GreyLevelDistanceZoneMatrixHolder::GreyLevelDistanceZoneMatrixHolder(double min, double max, int number, int maxSize) : + m_MinimumRange(min), + m_MaximumRange(max), + m_NumberOfBins(number), + m_MaximumSize(maxSize), + m_NumerOfVoxels(0) +{ + m_Matrix.resize(number, maxSize); + m_Matrix.fill(0); + m_Stepsize = (max - min) / (number); +} + +int mitk::GreyLevelDistanceZoneMatrixHolder::IntensityToIndex(double intensity) +{ + return std::floor((intensity - m_MinimumRange) / m_Stepsize); +} + +double mitk::GreyLevelDistanceZoneMatrixHolder::IndexToMinIntensity(int index) +{ + return m_MinimumRange + index * m_Stepsize; +} +double mitk::GreyLevelDistanceZoneMatrixHolder::IndexToMeanIntensity(int index) +{ + return m_MinimumRange + (index+0.5) * m_Stepsize; +} +double mitk::GreyLevelDistanceZoneMatrixHolder::IndexToMaxIntensity(int index) +{ + return m_MinimumRange + (index + 1) * m_Stepsize; +} + +template +int +CalculateGlSZMatrix(itk::Image* itkImage, + itk::Image* mask, + itk::Image* distanceImage, + std::vector > offsets, + bool estimateLargestRegion, + mitk::GreyLevelDistanceZoneMatrixHolder &holder) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskImageType; + typedef typename ImageType::IndexType IndexType; + + typedef itk::ImageRegionIteratorWithIndex ConstIterType; + typedef itk::ImageRegionIteratorWithIndex ConstMaskIterType; + + auto region = mask->GetLargestPossibleRegion(); + typename MaskImageType::RegionType newRegion; + newRegion.SetSize(region.GetSize()); + newRegion.SetIndex(region.GetIndex()); + + ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); + ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); + + typename MaskImageType::Pointer visitedImage = MaskImageType::New(); + visitedImage->SetRegions(newRegion); + visitedImage->Allocate(); + visitedImage->FillBuffer(0); + + int largestRegion = 0; + holder.m_NumberOfBins = 0; + + while (!maskIter.IsAtEnd()) + { + if (maskIter.Value() > 0 ) + { + auto startIntensityIndex = holder.IntensityToIndex(imageIter.Value()); + std::vector indices; + indices.push_back(maskIter.GetIndex()); + unsigned int steps = 0; + int smallestDistance = 500; + + while (indices.size() > 0) + { + auto currentIndex = indices.back(); + indices.pop_back(); + + if (!region.IsInside(currentIndex)) + { + continue; + } + + auto wasVisited = visitedImage->GetPixel(currentIndex); + auto newIntensityIndex = holder.IntensityToIndex(itkImage->GetPixel(currentIndex)); + auto isInMask = mask->GetPixel(currentIndex); + + if ((isInMask > 0) && + (newIntensityIndex == startIntensityIndex) && + (wasVisited < 1)) + { + ++(holder.m_NumerOfVoxels); + smallestDistance = (smallestDistance > distanceImage->GetPixel(currentIndex)) ? distanceImage->GetPixel(currentIndex) : smallestDistance; + ++steps; + visitedImage->SetPixel(currentIndex, 1); + for (auto offset : offsets) + { + auto newIndex = currentIndex + offset; + indices.push_back(newIndex); + newIndex = currentIndex - offset; + indices.push_back(newIndex); + } + + } + } + if (steps > 0) + { + largestRegion = std::max(steps, largestRegion); + steps = std::min(steps, holder.m_MaximumSize); + if (!estimateLargestRegion) + { + holder.m_Matrix(startIntensityIndex, smallestDistance-1) += 1; + } + } + } + ++imageIter; + ++maskIter; + } + return largestRegion; +} + +template +void itkErode( + itk::Image *sourceImage, + mitk::Image::Pointer &resultImage, + bool &segmentationRemaining) +{ + typedef itk::Image ImageType; + typedef itk::BinaryCrossStructuringElement CrossType; + typedef typename itk::BinaryErodeImageFilter CrossErodeFilterType; + + CrossType cross; + typename CrossType::SizeType size; + size.Fill(1); + cross.SetRadius(size); + cross.CreateStructuringElement(); + + typename CrossErodeFilterType::Pointer erodeFilter = CrossErodeFilterType::New(); + erodeFilter->SetKernel(cross); + erodeFilter->SetInput(sourceImage); + erodeFilter->SetErodeValue(1); + erodeFilter->UpdateLargestPossibleRegion(); + + segmentationRemaining = false; + itk::ImageRegionConstIterator iter(erodeFilter->GetOutput(), erodeFilter->GetOutput()->GetLargestPossibleRegion()); + while ((!iter.IsAtEnd()) && (!segmentationRemaining)) + { + if (iter.Get() > 0) + segmentationRemaining = true; + ++iter; + } + + mitk::CastToMitkImage(erodeFilter->GetOutput(), resultImage); +} + +template +void itkAdd( + itk::Image *imageA, mitk::Image::Pointer mitkImageB, + mitk::Image::Pointer &resultImage) +{ + typedef itk::Image ImageType; + typedef itk::AddImageFilter AddFilterType; + + typename ImageType::Pointer imageB; + mitk::CastToItkImage(mitkImageB, imageB); + + typename AddFilterType::Pointer addFilter = AddFilterType::New(); + addFilter->SetInput1(imageA); + addFilter->SetInput2(imageB); + addFilter->UpdateLargestPossibleRegion(); + + mitk::CastToMitkImage(addFilter->GetOutput(), resultImage); +} + +void erode(mitk::Image::Pointer input, mitk::Image::Pointer &output, bool &segmentationRemaining) +{ + AccessByItk_2(input, itkErode, output, segmentationRemaining); +} +void add(mitk::Image::Pointer inputA, mitk::Image::Pointer inputB, mitk::Image::Pointer &output) +{ + AccessByItk_2(inputA, itkAdd, inputB, output); +} + +void erodeAndAdd(mitk::Image::Pointer input, mitk::Image::Pointer& finalOutput, int &maxDistance) +{ + mitk::Image::Pointer workingImage = input; + mitk::Image::Pointer output = input; + maxDistance = 0; + bool segmentationRemaining = true; + while (segmentationRemaining) + { + mitk::Image::Pointer erodedImage = mitk::Image::New(); + mitk::Image::Pointer result = mitk::Image::New(); + erode(workingImage, erodedImage, segmentationRemaining); + workingImage = erodedImage; + add(output, erodedImage, result); + output = result; + ++maxDistance; + } + finalOutput = output; +} + + +void static CalculateFeatures( + mitk::GreyLevelDistanceZoneMatrixHolder &holder, + mitk::GreyLevelDistanceZoneFeatures & results + ) +{ + auto SgzMatrix = holder.m_Matrix; + auto pgzMatrix = holder.m_Matrix; + auto pgMatrix = holder.m_Matrix; + auto pzMatrix = holder.m_Matrix; + + double Ns = pgzMatrix.sum(); + pgzMatrix /= Ns; + pgMatrix.rowwise().normalize(); + pzMatrix.colwise().normalize(); + + for (int i = 0; i < holder.m_NumberOfBins; ++i) + for (int j = 0; j < holder.m_NumberOfBins; ++j) + { + if (pgzMatrix(i, j) != pgzMatrix(i, j)) + pgzMatrix(i, j) = 0; + if (pgMatrix(i, j) != pgMatrix(i, j)) + pgMatrix(i, j) = 0; + if (pzMatrix(i, j) != pzMatrix(i, j)) + pzMatrix(i, j) = 0; + } + + Eigen::VectorXd SgVector = SgzMatrix.rowwise().sum(); + Eigen::VectorXd SzVector = SgzMatrix.colwise().sum(); + + for (int j = 0; j < SzVector.size(); ++j) + { + results.SmallDistanceEmphasis += SzVector(j) / (j+1) / (j+1); + results.LargeDistanceEmphasis += SzVector(j) * (j + 1.0) * (j + 1.0); + results.ZoneDistanceNonUniformity += SzVector(j) * SzVector(j); + results.ZoneDistanceNoneUniformityNormalized += SzVector(j) * SzVector(j); + } + for (int i = 0; i < SgVector.size(); ++i) + { + results.LowGreyLevelEmphasis += SgVector(i) / (i + 1) / (i + 1); + results.HighGreyLevelEmphasis += SgVector(i) * (i + 1) * (i + 1); + results.GreyLevelNonUniformity += SgVector(i)*SgVector(i); + results.GreyLevelNonUniformityNormalized += SgVector(i)*SgVector(i); + } + + for (int i = 0; i < SgzMatrix.rows(); ++i) + { + for (int j = 0; j < SgzMatrix.cols(); ++j) + { + results.SmallDistanceLowGreyLevelEmphasis += SgzMatrix(i, j) / (i + 1) / (i + 1) / (j + 1) / (j + 1); + results.SmallDistanceHighGreyLevelEmphasis += SgzMatrix(i, j) * (i + 1) * (i + 1) / (j + 1) / (j + 1); + results.LargeDistanceLowGreyLevelEmphasis += SgzMatrix(i, j) / (i + 1) / (i + 1) * (j + 1.0) * (j + 1.0); + results.LargeDistanceHighGreyLevelEmphasis += SgzMatrix(i, j) * (i + 1) * (i + 1) * (j + 1.0) * (j + 1.0); + results.ZonePercentage += SgzMatrix(i, j); + + results.GreyLevelMean += (i + 1)*pgzMatrix(i, j); + results.ZoneDistanceMean += (j + 1)*pgzMatrix(i, j); + if (pgzMatrix(i, j) > 0) + results.ZoneDistanceEntropy -= pgzMatrix(i, j) * std::log(pgzMatrix(i, j)) / std::log(2); + } + } + + for (int i = 0; i < SgzMatrix.rows(); ++i) + { + for (int j = 0; j < SgzMatrix.cols(); ++j) + { + results.GreyLevelVariance += (i + 1 - results.GreyLevelMean)*(i + 1 - results.GreyLevelMean)*pgzMatrix(i, j); + results.ZoneDistanceVariance += (j + 1 - results.ZoneDistanceMean)*(j + 1 - results.ZoneDistanceMean)*pgzMatrix(i, j); + } + } + + results.SmallDistanceEmphasis /= Ns; + results.LargeDistanceEmphasis /= Ns; + results.LowGreyLevelEmphasis /= Ns; + results.HighGreyLevelEmphasis /= Ns; + + results.SmallDistanceLowGreyLevelEmphasis /= Ns; + results.SmallDistanceHighGreyLevelEmphasis /= Ns; + results.LargeDistanceLowGreyLevelEmphasis /= Ns; + results.LargeDistanceHighGreyLevelEmphasis /= Ns; + results.GreyLevelNonUniformity /= Ns; + results.GreyLevelNonUniformityNormalized /= Ns*Ns; + results.ZoneDistanceNonUniformity /= Ns; + results.ZoneDistanceNoneUniformityNormalized /= Ns*Ns; + + results.ZonePercentage = Ns / holder.m_NumerOfVoxels;// results.ZonePercentage; +} + +template +static void +CalculateGreyLevelDistanceZoneFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFGreyLevelDistanceZone::FeatureListType & featureList, mitk::GIFGreyLevelDistanceZone::GIFGreyLevelDistanceZoneConfiguration config) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; + typedef itk::Neighborhood NeighborhoodType; + typedef itk::Offset OffsetType; + + /////////////////////////////////////////////////////////////////////////////////////////////// + + typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); + minMaxComputer->SetImage(itkImage); + minMaxComputer->Compute(); + + double rangeMin = -0.5 + minMaxComputer->GetMinimum(); + double rangeMax = 0.5 + minMaxComputer->GetMaximum(); + + if (config.UseMinimumIntensity) + rangeMin = config.MinimumIntensity; + if (config.UseMaximumIntensity) + rangeMax = config.MaximumIntensity; + + // Define Range + int numberOfBins = config.Bins; + + int maximumDistance = 0; + mitk::Image::Pointer mitkDistanceImage = mitk::Image::New(); + erodeAndAdd(config.distanceMask, mitkDistanceImage, maximumDistance); + typename MaskType::Pointer distanceImage = MaskType::New(); + mitk::CastToItkImage(mitkDistanceImage, distanceImage); + + typename MaskType::Pointer maskImage = MaskType::New(); + mitk::CastToItkImage(mask, maskImage); + + //Find possible directions + std::vector < itk::Offset > offsetVector; + NeighborhoodType hood; + hood.SetRadius(1); + unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); + OffsetType offset; + for (unsigned int d = 0; d < centerIndex; d++) + { + offset = hood.GetOffset(d); + bool useOffset = true; + for (unsigned int i = 0; i < VImageDimension; ++i) + { + offset[i] *= config.range; + if ((config.direction == i + 2) && offset[i] != 0) + { + useOffset = false; + } + } + if (useOffset) + { + offsetVector.push_back(offset); + } + } + if (config.direction == 1) + { + offsetVector.clear(); + offset[0] = 0; + offset[1] = 0; + offset[2] = 1; + offsetVector.push_back(offset); + } + + MITK_INFO << "Maximum Distance: " << maximumDistance; + std::vector resultVector; + mitk::GreyLevelDistanceZoneMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins, maximumDistance+1); + mitk::GreyLevelDistanceZoneFeatures overallFeature; + CalculateGlSZMatrix(itkImage, maskImage, distanceImage, offsetVector, false, holderOverall); + CalculateFeatures(holderOverall, overallFeature); + + std::stringstream ss; + ss << config.range; + std::string strRange = ss.str(); + MatrixFeaturesTo(overallFeature, "Grey Level Distance Zone (" + strRange + ")", featureList); +} + + +static +void MatrixFeaturesTo(mitk::GreyLevelDistanceZoneFeatures features, + std::string prefix, + mitk::GIFGreyLevelDistanceZone::FeatureListType &featureList) +{ + featureList.push_back(std::make_pair(prefix + " Small Distance Emphasis", features.SmallDistanceEmphasis)); + featureList.push_back(std::make_pair(prefix + " Large Distance Emphasis", features.LargeDistanceEmphasis)); + featureList.push_back(std::make_pair(prefix + " Low Grey Level Emphasis", features.LowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + " High Grey Level Emphasis", features.HighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + " Small Distance Low Grey LEvel Emphasis", features.SmallDistanceLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + " Small Distance High Grey LEvel Emphasis", features.SmallDistanceHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + " Large Distance Low Grey Level Emphasis", features.LargeDistanceLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + " Large Distance High Grey Level Emphasis", features.LargeDistanceHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(prefix + " Grey Level Non-Uniformity", features.GreyLevelNonUniformity)); + featureList.push_back(std::make_pair(prefix + " Grey Level Non-Uniformity Normalized", features.GreyLevelNonUniformityNormalized)); + featureList.push_back(std::make_pair(prefix + " Distance Size Non-Uniformity", features.ZoneDistanceNonUniformity)); + featureList.push_back(std::make_pair(prefix + " Distance Size Non-Uniformity Normalized", features.ZoneDistanceNoneUniformityNormalized)); + featureList.push_back(std::make_pair(prefix + " Zone Percentage", features.ZonePercentage)); + featureList.push_back(std::make_pair(prefix + " Grey Level Mean", features.GreyLevelMean)); + featureList.push_back(std::make_pair(prefix + " Grey Level Variance", features.GreyLevelVariance)); + featureList.push_back(std::make_pair(prefix + " Zone Distance Size Mean", features.ZoneDistanceMean)); + featureList.push_back(std::make_pair(prefix + " Zone Distance Size Variance", features.ZoneDistanceVariance)); + featureList.push_back(std::make_pair(prefix + " Zone Distance Size Entropy", features.ZoneDistanceEntropy)); +} + + mitk::GIFGreyLevelDistanceZone::GIFGreyLevelDistanceZone() : + m_Range(1.0), m_Bins(128) +{ + SetShortName("gldz"); + SetLongName("disctancezone"); +} + +mitk::GIFGreyLevelDistanceZone::FeatureListType mitk::GIFGreyLevelDistanceZone::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +{ + FeatureListType featureList; + + GIFGreyLevelDistanceZoneConfiguration config; + config.direction = GetDirection(); + config.range = m_Range; + + config.MinimumIntensity = GetMinimumIntensity(); + config.MaximumIntensity = GetMaximumIntensity(); + config.UseMinimumIntensity = GetUseMinimumIntensity(); + config.UseMaximumIntensity = GetUseMaximumIntensity(); + config.Bins = GetBins(); + + if (GetMorphMask().IsNull()) + { + config.distanceMask = mask->Clone(); + } + else + { + config.distanceMask = GetMorphMask(); + } + + if (GetQuantifier()->GetInitialized()) + { + MITK_INFO << GetQuantifier()->GetMinimum(); + MITK_INFO << GetQuantifier()->GetMaximum(); + MITK_INFO << GetQuantifier()->GetBins(); + MITK_INFO << GetQuantifier()->GetBinsize(); + config.MinimumIntensity = GetQuantifier()->GetMinimum(); + config.MaximumIntensity = GetQuantifier()->GetMaximum(); + config.Bins = GetQuantifier()->GetBins(); + } + + AccessByItk_3(image, CalculateGreyLevelDistanceZoneFeatures, mask, featureList, config); + + return featureList; +} + +mitk::GIFGreyLevelDistanceZone::FeatureNameListType mitk::GIFGreyLevelDistanceZone::GetFeatureNames() +{ + FeatureNameListType featureList; + return featureList; +} + + + + +void mitk::GIFGreyLevelDistanceZone::AddArguments(mitkCommandLineParser &parser) +{ + AddQuantifierArguments(parser); + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Grey Level Distance Zone", "Calculates the size zone based features.", us::Any()); + parser.addArgument(name + "::range", name + "::range", mitkCommandLineParser::String, "Grey ", "Define the range that is used (Semicolon-separated)", us::Any()); +} + +void +mitk::GIFGreyLevelDistanceZone::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +{ + auto parsedArgs = GetParameter(); + std::string name = GetOptionPrefix(); + + if (parsedArgs.count(GetLongName())) + { + InitializeQuantifier(feature, mask, maskNoNAN, featureList); + + std::vector ranges; + if (parsedArgs.count(name + "::range")) + { + ranges = SplitDouble(parsedArgs[name + "::range"].ToString(), ';'); + } + else + { + ranges.push_back(1); + } + if (parsedArgs.count(name + "::bins")) + { + auto bins = SplitDouble(parsedArgs[name + "::bins"].ToString(), ';')[0]; + this->SetBins(bins); + } + + for (std::size_t i = 0; i < ranges.size(); ++i) + { + MITK_INFO << "Start calculating Grey Level Distance Zone with range " << ranges[i] << "...."; + this->SetRange(ranges[i]); + auto localResults = this->CalculateFeatures(feature, maskNoNAN); + featureList.insert(featureList.end(), localResults.begin(), localResults.end()); + MITK_INFO << "Finished calculating Grey Level Distance Zone with range " << ranges[i] << "...."; + } + } + +} + diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp index d0682b80d1..597caaaff4 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp @@ -1,397 +1,405 @@ #include // MITK #include #include #include // ITK #include #include // STL #include static void MatrixFeaturesTo(mitk::GreyLevelSizeZoneFeatures features, std::string prefix, mitk::GIFGreyLevelSizeZone::FeatureListType &featureList); mitk::GreyLevelSizeZoneMatrixHolder::GreyLevelSizeZoneMatrixHolder(double min, double max, int number, int maxSize) : m_MinimumRange(min), m_MaximumRange(max), m_NumberOfBins(number), m_MaximumSize(maxSize) { m_Matrix.resize(number, maxSize); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::GreyLevelSizeZoneMatrixHolder::IntensityToIndex(double intensity) { return std::floor((intensity - m_MinimumRange) / m_Stepsize); } double mitk::GreyLevelSizeZoneMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::GreyLevelSizeZoneMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::GreyLevelSizeZoneMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template -void +int CalculateGlSZMatrix(itk::Image* itkImage, itk::Image* mask, std::vector > offsets, - int, + bool estimateLargestRegion, mitk::GreyLevelSizeZoneMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef typename ImageType::IndexType IndexType; typedef itk::ImageRegionIteratorWithIndex ConstIterType; typedef itk::ImageRegionIteratorWithIndex ConstMaskIterType; auto region = mask->GetLargestPossibleRegion(); typename MaskImageType::RegionType newRegion; newRegion.SetSize(region.GetSize()); newRegion.SetIndex(region.GetIndex()); ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); typename MaskImageType::Pointer visitedImage = MaskImageType::New(); visitedImage->SetRegions(newRegion); visitedImage->Allocate(); visitedImage->FillBuffer(0); + int largestRegion = 0; while (!maskIter.IsAtEnd()) { if (maskIter.Value() > 0 ) { auto startIntensityIndex = holder.IntensityToIndex(imageIter.Value()); std::vector indices; indices.push_back(maskIter.GetIndex()); unsigned int steps = 0; while (indices.size() > 0) { auto currentIndex = indices.back(); indices.pop_back(); if (!region.IsInside(currentIndex)) { continue; } auto wasVisited = visitedImage->GetPixel(currentIndex); auto newIntensityIndex = holder.IntensityToIndex(itkImage->GetPixel(currentIndex)); auto isInMask = mask->GetPixel(currentIndex); if ((isInMask > 0) && (newIntensityIndex == startIntensityIndex) && (wasVisited < 1)) { ++steps; visitedImage->SetPixel(currentIndex, 1); for (auto offset : offsets) { auto newIndex = currentIndex + offset; indices.push_back(newIndex); newIndex = currentIndex - offset; indices.push_back(newIndex); } } } if (steps > 0) { + largestRegion = std::max(steps, largestRegion); steps = std::min(steps, holder.m_MaximumSize); - holder.m_Matrix(startIntensityIndex, steps-1) += 1; + if (!estimateLargestRegion) + { + holder.m_Matrix(startIntensityIndex, steps - 1) += 1; + } } } ++imageIter; ++maskIter; } + return largestRegion; } void CalculateFeatures( mitk::GreyLevelSizeZoneMatrixHolder &holder, mitk::GreyLevelSizeZoneFeatures & results ) { auto SgzMatrix = holder.m_Matrix; auto pgzMatrix = holder.m_Matrix; auto pgMatrix = holder.m_Matrix; auto pzMatrix = holder.m_Matrix; double Ns = pgzMatrix.sum(); pgzMatrix /= Ns; pgMatrix.rowwise().normalize(); pzMatrix.colwise().normalize(); for (int i = 0; i < holder.m_NumberOfBins; ++i) for (int j = 0; j < holder.m_NumberOfBins; ++j) { if (pgzMatrix(i, j) != pgzMatrix(i, j)) pgzMatrix(i, j) = 0; if (pgMatrix(i, j) != pgMatrix(i, j)) pgMatrix(i, j) = 0; if (pzMatrix(i, j) != pzMatrix(i, j)) pzMatrix(i, j) = 0; } Eigen::VectorXd SgVector = SgzMatrix.rowwise().sum(); Eigen::VectorXd SzVector = SgzMatrix.colwise().sum(); for (int j = 0; j < SzVector.size(); ++j) { results.SmallZoneEmphasis += SzVector(j) / (j + 1) / (j + 1); - results.LargeZoneEmphasis += SzVector(j) * (j + 1) * (j + 1); + results.LargeZoneEmphasis += SzVector(j) * (j + 1.0) * (j + 1.0); results.ZoneSizeNonUniformity += SzVector(j) * SzVector(j); results.ZoneSizeNoneUniformityNormalized += SzVector(j) * SzVector(j); } for (int i = 0; i < SgVector.size(); ++i) { results.LowGreyLevelEmphasis += SgVector(i) / (i + 1) / (i + 1); results.HighGreyLevelEmphasis += SgVector(i) * (i + 1) * (i + 1); results.GreyLevelNonUniformity += SgVector(i)*SgVector(i); results.GreyLevelNonUniformityNormalized += SgVector(i)*SgVector(i); } for (int i = 0; i < SgzMatrix.rows(); ++i) { for (int j = 0; j < SgzMatrix.cols(); ++j) { results.SmallZoneLowGreyLevelEmphasis += SgzMatrix(i, j) / (i + 1) / (i + 1) / (j + 1) / (j + 1); results.SmallZoneHighGreyLevelEmphasis += SgzMatrix(i, j) * (i + 1) * (i + 1) / (j + 1) / (j + 1); results.LargeZoneLowGreyLevelEmphasis += SgzMatrix(i, j) / (i + 1) / (i + 1) * (j + 1.0) * (j + 1.0); results.LargeZoneHighGreyLevelEmphasis += SgzMatrix(i, j) * (i + 1) * (i + 1) * (j + 1.0) * (j + 1.0); results.ZonePercentage += SgzMatrix(i, j)*(j + 1); results.GreyLevelMean += (i + 1)*pgzMatrix(i, j); results.ZoneSizeMean += (j + 1)*pgzMatrix(i, j); if (pgzMatrix(i, j) > 0) results.ZoneSizeEntropy -= pgzMatrix(i, j) * std::log(pgzMatrix(i, j)) / std::log(2); } } for (int i = 0; i < SgzMatrix.rows(); ++i) { for (int j = 0; j < SgzMatrix.cols(); ++j) { results.GreyLevelVariance += (i + 1 - results.GreyLevelMean)*(i + 1 - results.GreyLevelMean)*pgzMatrix(i, j); results.ZoneSizeVariance += (j + 1 - results.ZoneSizeMean)*(j + 1 - results.ZoneSizeMean)*pgzMatrix(i, j); } } results.SmallZoneEmphasis /= Ns; results.LargeZoneEmphasis /= Ns; results.LowGreyLevelEmphasis /= Ns; results.HighGreyLevelEmphasis /= Ns; results.SmallZoneLowGreyLevelEmphasis /= Ns; results.SmallZoneHighGreyLevelEmphasis /= Ns; results.LargeZoneLowGreyLevelEmphasis /= Ns; results.LargeZoneHighGreyLevelEmphasis /= Ns; results.GreyLevelNonUniformity /= Ns; results.GreyLevelNonUniformityNormalized /= Ns*Ns; results.ZoneSizeNonUniformity /= Ns; results.ZoneSizeNoneUniformityNormalized /= Ns*Ns; results.ZonePercentage = Ns / results.ZonePercentage; } template void CalculateGreyLevelSizeZoneFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFGreyLevelSizeZone::FeatureListType & featureList, mitk::GIFGreyLevelSizeZone::GIFGreyLevelSizeZoneConfiguration config) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); minMaxComputer->SetImage(itkImage); minMaxComputer->Compute(); double rangeMin = -0.5 + minMaxComputer->GetMinimum(); double rangeMax = 0.5 + minMaxComputer->GetMaximum(); if (config.UseMinimumIntensity) rangeMin = config.MinimumIntensity; if (config.UseMaximumIntensity) rangeMax = config.MaximumIntensity; // Define Range int numberOfBins = config.Bins; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); //Find possible directions std::vector < itk::Offset > offsetVector; NeighborhoodType hood; hood.SetRadius(1); unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetType offset; for (unsigned int d = 0; d < centerIndex; d++) { offset = hood.GetOffset(d); bool useOffset = true; for (unsigned int i = 0; i < VImageDimension; ++i) { offset[i] *= config.range; if ((config.direction == i + 2) && offset[i] != 0) { useOffset = false; } } if (useOffset) { offsetVector.push_back(offset); MITK_INFO << offset; } } if (config.direction == 1) { offsetVector.clear(); offset[0] = 0; offset[1] = 0; offset[2] = 1; offsetVector.push_back(offset); } std::vector resultVector; - mitk::GreyLevelSizeZoneMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins,100); + mitk::GreyLevelSizeZoneMatrixHolder tmpHolder(rangeMin, rangeMax, numberOfBins, 3); + int largestRegion = CalculateGlSZMatrix(itkImage, maskImage, offsetVector, true, tmpHolder); + mitk::GreyLevelSizeZoneMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins,largestRegion); mitk::GreyLevelSizeZoneFeatures overallFeature; - CalculateGlSZMatrix(itkImage, maskImage, offsetVector, config.range, holderOverall); + CalculateGlSZMatrix(itkImage, maskImage, offsetVector, false, holderOverall); CalculateFeatures(holderOverall, overallFeature); std::stringstream ss; ss << config.range; std::string strRange = ss.str(); MatrixFeaturesTo(overallFeature, "Grey Level Size Zone (" + strRange + ")", featureList); } static void MatrixFeaturesTo(mitk::GreyLevelSizeZoneFeatures features, std::string prefix, mitk::GIFGreyLevelSizeZone::FeatureListType &featureList) { featureList.push_back(std::make_pair(prefix + " Small Zone Emphasis", features.SmallZoneEmphasis)); featureList.push_back(std::make_pair(prefix + " Large Zone Emphasis", features.LargeZoneEmphasis)); featureList.push_back(std::make_pair(prefix + " Low Grey Level Emphasis", features.LowGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + " High Grey Level Emphasis", features.HighGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + " Small Zone Low Grey LEvel Emphasis", features.SmallZoneLowGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + " Small Zone High Grey LEvel Emphasis", features.SmallZoneHighGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + " Large Zone Low Grey Level Emphasis", features.LargeZoneLowGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + " Large Zone High Grey Level Emphasis", features.LargeZoneHighGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + " Grey Level Non-Uniformity", features.GreyLevelNonUniformity)); featureList.push_back(std::make_pair(prefix + " Grey Level Non-Uniformity Normalized", features.GreyLevelNonUniformityNormalized)); featureList.push_back(std::make_pair(prefix + " Zone Size Non-Uniformity", features.ZoneSizeNonUniformity)); featureList.push_back(std::make_pair(prefix + " Zone Size Non-Uniformity Normalized", features.ZoneSizeNoneUniformityNormalized)); featureList.push_back(std::make_pair(prefix + " Zone Percentage", features.ZonePercentage)); featureList.push_back(std::make_pair(prefix + " Grey Level Mean", features.GreyLevelMean)); featureList.push_back(std::make_pair(prefix + " Grey Level Variance", features.GreyLevelVariance)); featureList.push_back(std::make_pair(prefix + " Zone Size Mean", features.ZoneSizeMean)); featureList.push_back(std::make_pair(prefix + " Zone Size Variance", features.ZoneSizeVariance)); featureList.push_back(std::make_pair(prefix + " Zone Size Entropy", features.ZoneSizeEntropy)); } mitk::GIFGreyLevelSizeZone::GIFGreyLevelSizeZone() : m_Range(1.0), m_Bins(128) { SetShortName("glsz"); SetLongName("sizezone"); } mitk::GIFGreyLevelSizeZone::FeatureListType mitk::GIFGreyLevelSizeZone::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; GIFGreyLevelSizeZoneConfiguration config; config.direction = GetDirection(); config.range = m_Range; config.MinimumIntensity = GetMinimumIntensity(); config.MaximumIntensity = GetMaximumIntensity(); config.UseMinimumIntensity = GetUseMinimumIntensity(); config.UseMaximumIntensity = GetUseMaximumIntensity(); config.Bins = GetBins(); AccessByItk_3(image, CalculateGreyLevelSizeZoneFeatures, mask, featureList, config); return featureList; } mitk::GIFGreyLevelSizeZone::FeatureNameListType mitk::GIFGreyLevelSizeZone::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFGreyLevelSizeZone::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Grey Level Size Zone", "Calculates the size zone based features.", us::Any()); parser.addArgument(name+"::range", name+"::range", mitkCommandLineParser::String, "Cooc 2 Range", "Define the range that is used (Semicolon-separated)", us::Any()); parser.addArgument(name + "::bins", name + "::bins", mitkCommandLineParser::String, "Cooc 2 Number of Bins", "Define the number of bins that is used ", us::Any()); } void mitk::GIFGreyLevelSizeZone::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); std::string name = GetOptionPrefix(); if (parsedArgs.count(GetLongName())) { std::vector ranges; if (parsedArgs.count(name + "::range")) { ranges = SplitDouble(parsedArgs[name + "::range"].ToString(), ';'); } else { ranges.push_back(1); } if (parsedArgs.count(name + "::bins")) { auto bins = SplitDouble(parsedArgs[name + "::bins"].ToString(), ';')[0]; this->SetBins(bins); } for (std::size_t i = 0; i < ranges.size(); ++i) { MITK_INFO << "Start calculating coocurence with range " << ranges[i] << "...."; this->SetRange(ranges[i]); auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating coocurence with range " << ranges[i] << "...."; } } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp new file mode 100644 index 0000000000..fbdd915ccd --- /dev/null +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp @@ -0,0 +1,190 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +// MITK +#include +#include +#include + +// ITK +#include +#include +#include + +// STL +#include + +template +void +CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFImageDescriptionFeatures::FeatureListType & featureList, mitk::GIFImageDescriptionFeatures::ParameterStruct params) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + typedef itk::LabelStatisticsImageFilter FilterType; + typedef typename FilterType::HistogramType HistogramType; + typedef typename HistogramType::IndexType HIndexType; + typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; + + typename MaskType::Pointer maskImage = MaskType::New(); + mitk::CastToItkImage(mask, maskImage); + + unsigned int imageDimensionX = itkImage->GetLargestPossibleRegion().GetSize()[0]; + unsigned int imageDimensionY = itkImage->GetLargestPossibleRegion().GetSize()[1]; + unsigned int imageDimensionZ = itkImage->GetLargestPossibleRegion().GetSize()[2]; + + double imageVoxelSpacingX = itkImage->GetSpacing()[0]; + double imageVoxelSpacingY = itkImage->GetSpacing()[1]; + double imageVoxelSpacingZ = itkImage->GetSpacing()[2]; + + typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); + minMaxComputer->SetImage(itkImage); + minMaxComputer->Compute(); + + double imageMinimum = minMaxComputer->GetMinimum(); + double imageMaximum = minMaxComputer->GetMaximum(); + + + unsigned int maskDimensionX = maskImage->GetLargestPossibleRegion().GetSize()[0]; + unsigned int maskDimensionY = maskImage->GetLargestPossibleRegion().GetSize()[1]; + unsigned int maskDimensionZ = maskImage->GetLargestPossibleRegion().GetSize()[2]; + + double maskVoxelSpacingX = maskImage->GetSpacing()[0]; + double maskVoxelSpacingY = maskImage->GetSpacing()[1]; + double maskVoxelSpacingZ = maskImage->GetSpacing()[2]; + + + unsigned int voxelCount = 0; + unsigned int maskVoxelCount = 0; + double maskMinimum = imageMaximum; + double maskMaximum = imageMinimum; + double imageMean = 0; + double maskMean = 0; + + unsigned int maskMinimumX = maskDimensionX; + unsigned int maskMaximumX = 0; + unsigned int maskMinimumY = maskDimensionY; + unsigned int maskMaximumY = 0; + unsigned int maskMinimumZ = maskDimensionZ; + unsigned int maskMaximumZ = 0; + + + itk::ImageRegionConstIteratorWithIndex imIter(itkImage, itkImage->GetLargestPossibleRegion()); + itk::ImageRegionConstIteratorWithIndex maIter(maskImage, maskImage->GetLargestPossibleRegion()); + + while (!imIter.IsAtEnd()) + { + auto pixelValue = imIter.Get(); + if (maIter.Get() > 0) + { + ++maskVoxelCount; + maskMean += pixelValue; + maskMinimum = (maskMinimum > pixelValue) ? pixelValue : maskMinimum; + maskMaximum = (maskMaximum < pixelValue) ? pixelValue : maskMaximum; + maskMinimumX = (maskMinimumX > imIter.GetIndex()[0]) ? imIter.GetIndex()[0] : maskMinimumX; + maskMaximumX = (maskMaximumX < imIter.GetIndex()[0]) ? imIter.GetIndex()[0] : maskMaximumX; + maskMinimumY = (maskMinimumY > imIter.GetIndex()[1]) ? imIter.GetIndex()[1] : maskMinimumY; + maskMaximumY = (maskMaximumY < imIter.GetIndex()[1]) ? imIter.GetIndex()[1] : maskMaximumY; + maskMinimumZ = (maskMinimumZ > imIter.GetIndex()[2]) ? imIter.GetIndex()[2] : maskMinimumZ; + maskMaximumZ = (maskMaximumZ < imIter.GetIndex()[2]) ? imIter.GetIndex()[2] : maskMaximumZ; + } + ++voxelCount; + imageMean += pixelValue; + ++imIter; + ++maIter; + } + imageMean /= voxelCount; + maskMean /= maskVoxelCount; + + featureList.push_back(std::make_pair("Diagnostic (Image)::Dimension X", imageDimensionX)); + featureList.push_back(std::make_pair("Diagnostic (Image)::Dimension Y", imageDimensionY)); + featureList.push_back(std::make_pair("Diagnostic (Image)::Dimension Z", imageDimensionZ)); + featureList.push_back(std::make_pair("Diagnostic (Image)::Spacing X", imageVoxelSpacingX)); + featureList.push_back(std::make_pair("Diagnostic (Image)::Spacing Y", imageVoxelSpacingY)); + featureList.push_back(std::make_pair("Diagnostic (Image)::Spacing Z", imageVoxelSpacingZ)); + featureList.push_back(std::make_pair("Diagnostic (Image)::Mean Intensity", imageMean)); + featureList.push_back(std::make_pair("Diagnostic (Image)::Minimum Intensity", imageMinimum)); + featureList.push_back(std::make_pair("Diagnostic (Image)::Maximum Intensity", imageMaximum)); + + featureList.push_back(std::make_pair("Diagnostic (Mask)::Dimension X", maskDimensionX)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Dimension Y", maskDimensionY)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Dimension Z", maskDimensionZ)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Mask Bounding Box X", maskMaximumX - maskMinimumX + 1)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Mask Bounding Box Y", maskMaximumY - maskMinimumY + 1)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Mask Bounding Box Z", maskMaximumZ - maskMinimumZ + 1)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Spacing X", maskVoxelSpacingX)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Spacing Y", maskVoxelSpacingY)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Spacing Z", maskVoxelSpacingZ)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Voxel Count ", maskVoxelCount)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Mean Intensity", maskMean)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Minimum Intensity", maskMinimum)); + featureList.push_back(std::make_pair("Diagnostic (Mask)::Maximum Intensity", maskMaximum)); + +} + +mitk::GIFImageDescriptionFeatures::GIFImageDescriptionFeatures() : +m_HistogramSize(256), m_UseCtRange(false) +{ + SetShortName("id"); + SetLongName("image-diagnostic"); +} + +mitk::GIFImageDescriptionFeatures::FeatureListType mitk::GIFImageDescriptionFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +{ + FeatureListType featureList; + + ParameterStruct params; + params.m_HistogramSize = this->m_HistogramSize; + params.m_UseCtRange = this->m_UseCtRange; + + params.MinimumIntensity = GetMinimumIntensity(); + params.MaximumIntensity = GetMaximumIntensity(); + params.UseMinimumIntensity = GetUseMinimumIntensity(); + params.UseMaximumIntensity = GetUseMaximumIntensity(); + params.Bins = GetBins(); + + AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, params); + + return featureList; +} + +mitk::GIFImageDescriptionFeatures::FeatureNameListType mitk::GIFImageDescriptionFeatures::GetFeatureNames() +{ + FeatureNameListType featureList; + return featureList; +} + + +void mitk::GIFImageDescriptionFeatures::AddArguments(mitkCommandLineParser &parser) +{ + std::string name = GetOptionPrefix(); + parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Volume-Statistic", "calculates volume based features", us::Any()); +} + +void +mitk::GIFImageDescriptionFeatures::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +{ + auto parsedArgs = GetParameter(); + if (parsedArgs.count(GetLongName())) + { + MITK_INFO << "Start calculating first order features ...."; + auto localResults = this->CalculateFeatures(feature, maskNoNAN); + featureList.insert(featureList.end(), localResults.begin(), localResults.end()); + MITK_INFO << "Finished calculating first order features...."; + } +} + diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp new file mode 100644 index 0000000000..51ea36dd88 --- /dev/null +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp @@ -0,0 +1,159 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +// MITK +#include +#include +#include +#include +#include + +// ITK +#include +#include +// STL +#include + + + + +template +static void +CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::IntensityQuantifier::Pointer quantifier, mitk::GIFIntensityVolumeHistogramFeatures::FeatureListType & featureList) +{ + int bins = 1000; + typedef itk::Image ImageType; + typedef itk::Image MaskType; + + typename MaskType::Pointer itkMask = MaskType::New(); + mitk::CastToItkImage(mask, itkMask); + + itk::ImageRegionConstIterator iter(itkImage, itkImage->GetLargestPossibleRegion()); + itk::ImageRegionConstIterator iterMask(itkMask, itkMask->GetLargestPossibleRegion()); + + MITK_INFO << "Quantification: " << quantifier->GetMinimum() << " to " << quantifier->GetMaximum() << " with " << quantifier->GetBins()<< " bins"; + + iter.GoToBegin(); + iterMask.GoToBegin(); + std::vector hist; + hist.resize(quantifier->GetBins() , 0); + + int count = 0; + while (!iter.IsAtEnd()) + { + if (iterMask.Get() > 0) + { + double value = iter.Get(); + //std::size_t index = std::floor((value - minimum) / (maximum - minimum) * (bins-1)); + std::size_t index = quantifier->IntensityToIndex(value); + ++count; + hist[index] += 1.0;// / count; + } + ++iterMask; + ++iter; + } + + bool notFoundIntenstiy010 = true; + bool notFoundIntenstiy090 = true; + + double intensity010 = -1; + double intensity090 = -1; + double fraction = 0; + double auc = 0; + bool firstRound = true; + for (int i = quantifier->GetBins()-1; i >= 0; --i) + { + hist[i] /= count; + hist[i] += fraction; + fraction = hist[i]; + if (!firstRound) + { + auc += 0.5 * (hist[i] + hist[i+1]) / (quantifier->GetBins()-1); + } + firstRound = false; + + if (notFoundIntenstiy010 && fraction > 0.1) + { + intensity010 = quantifier->IndexToMeanIntensity(i + 1); + notFoundIntenstiy010 = false; + } + if (notFoundIntenstiy090 && fraction > 0.9) + { + intensity090 = quantifier->IndexToMeanIntensity(i + 1); + notFoundIntenstiy090 = false; + } + } + + unsigned int index010 = std::ceil(quantifier->GetBins() * 0.1); + unsigned int index090 = std::floor(quantifier->GetBins() * 0.9); + + featureList.push_back(std::make_pair("Intensity Volume Histogram Volume fration at 0.10 intensity", hist[index010])); + featureList.push_back(std::make_pair("Intensity Volume Histogram Volume fration at 0.90 intensity", hist[index090])); + featureList.push_back(std::make_pair("Intensity Volume Histogram Intensity at 0.10 volume", intensity010)); + featureList.push_back(std::make_pair("Intensity Volume Histogram Intensity at 0.90 volume", intensity090)); + featureList.push_back(std::make_pair("Intensity Volume Histogram Difference intensity at 0.10 and 0.90 volume", std::abs(hist[index010] - hist[index090]))); + featureList.push_back(std::make_pair("Intensity Volume Histogram Difference intensity at 0.10 and 0.90 volume", std::abs(intensity090 - intensity010))); + featureList.push_back(std::make_pair("Intensity Volume Histogram Area under IVH curve", auc)); + //featureList.push_back(std::make_pair("Local Intensity Global Intensity Peak", globalPeakValue)); +} + + +mitk::GIFIntensityVolumeHistogramFeatures::GIFIntensityVolumeHistogramFeatures() +{ + SetLongName("intensity-volume-histogram"); + SetShortName("ivoh"); +} + +mitk::GIFIntensityVolumeHistogramFeatures::FeatureListType mitk::GIFIntensityVolumeHistogramFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +{ + FeatureListType featureList; + AccessByItk_3(image, CalculateIntensityPeak, mask, GetQuantifier(), featureList); + return featureList; +} + +mitk::GIFIntensityVolumeHistogramFeatures::FeatureNameListType mitk::GIFIntensityVolumeHistogramFeatures::GetFeatureNames() +{ + FeatureNameListType featureList; + return featureList; +} + + +void mitk::GIFIntensityVolumeHistogramFeatures::AddArguments(mitkCommandLineParser &parser) +{ + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Local Intensity", "calculates local intensity based features", us::Any()); + + AddQuantifierArguments(parser); +} + +void +mitk::GIFIntensityVolumeHistogramFeatures::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNaN, FeatureListType &featureList) +{ + InitializeQuantifier(feature, mask, maskNoNaN, featureList,1000); + + auto parsedArgs = GetParameter(); + if (parsedArgs.count(GetLongName())) + { + MITK_INFO << "Start calculating local intensity features ...."; + auto localResults = this->CalculateFeatures(feature, mask); + featureList.insert(featureList.end(), localResults.begin(), localResults.end()); + MITK_INFO << "Finished calculating local intensity features...."; + } +} + diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp new file mode 100644 index 0000000000..56c4575e55 --- /dev/null +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFLocalIntensity.cpp @@ -0,0 +1,150 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +// MITK +#include +#include +#include +#include +#include + +// ITK +#include +#include +// STL +#include + + +template +static void +CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFLocalIntensity::FeatureListType & featureList) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + + typename MaskType::Pointer itkMask = MaskType::New(); + mitk::CastToItkImage(mask, itkMask); + + double minimumSpacing = std::numeric_limits::max(); + itkImage->GetSpacing(); + for (int i = 0; i < VImageDimension; ++i) + { + minimumSpacing = (minimumSpacing < itkImage->GetSpacing()[i]) ? minimumSpacing : itkImage->GetSpacing()[i]; + } + ImageType::SizeType regionSize; + int offset = std::ceil(6.2 / minimumSpacing); + regionSize.Fill(offset); + + itk::NeighborhoodIterator iter(regionSize, itkImage, itkImage->GetLargestPossibleRegion()); + itk::NeighborhoodIterator iterMask(regionSize, itkMask, itkMask->GetLargestPossibleRegion()); + + ImageType::PointType origin; + ImageType::PointType localPoint; + itk::Index index; + + double tmpPeakValue; + double globalPeakValue = 0; + double localPeakValue = 0; + TPixel localMaximum = 0; + + int count = 0; + while (!iter.IsAtEnd()) + { + if (iterMask.GetCenterPixel() > 0) + { + tmpPeakValue = 0; + count = 0; + index = iter.GetIndex(); + itkImage->TransformIndexToPhysicalPoint(index, origin); + for (int i = 0; i < iter.Size(); ++i) + { + itkImage->TransformIndexToPhysicalPoint(iter.GetIndex(i), localPoint); + double dist = origin.EuclideanDistanceTo(localPoint); + if (dist < 6.2) + { + if (iter.IndexInBounds(i)) + { + tmpPeakValue += iter.GetPixel(i); + ++count; + } + } + } + tmpPeakValue /= count; + globalPeakValue = std::max(tmpPeakValue, globalPeakValue); + if (localMaximum == iter.GetCenterPixel()) + { + localPeakValue = std::max(tmpPeakValue,localPeakValue); + } + else if (localMaximum < iter.GetCenterPixel()) + { + localMaximum = iter.GetCenterPixel(); + localPeakValue = tmpPeakValue; + } + } + ++iterMask; + ++iter; + } + featureList.push_back(std::make_pair("Local Intensity Local Intensity Peak", localPeakValue)); + featureList.push_back(std::make_pair("Local Intensity Global Intensity Peak", globalPeakValue)); +} + + +mitk::GIFLocalIntensity::GIFLocalIntensity() +{ + SetLongName("local-intensity"); + SetShortName("loci"); +} + +mitk::GIFLocalIntensity::FeatureListType mitk::GIFLocalIntensity::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +{ + FeatureListType featureList; + if (image->GetDimension() < 3) + { + return featureList; + } + AccessByItk_2(image, CalculateIntensityPeak, mask, featureList); + return featureList; +} + +mitk::GIFLocalIntensity::FeatureNameListType mitk::GIFLocalIntensity::GetFeatureNames() +{ + FeatureNameListType featureList; + return featureList; +} + + +void mitk::GIFLocalIntensity::AddArguments(mitkCommandLineParser &parser) +{ + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Local Intensity", "calculates local intensity based features", us::Any()); +} + +void +mitk::GIFLocalIntensity::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) +{ + auto parsedArgs = GetParameter(); + if (parsedArgs.count(GetLongName())) + { + MITK_INFO << "Start calculating local intensity features ...."; + auto localResults = this->CalculateFeatures(feature, mask); + featureList.insert(featureList.end(), localResults.begin(), localResults.end()); + MITK_INFO << "Finished calculating local intensity features...."; + } +} + diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp new file mode 100644 index 0000000000..dd3b6d5722 --- /dev/null +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp @@ -0,0 +1,190 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +// MITK +#include +#include +#include +#include +#include + +// ITK +#include +#include +// STL +#include + + +template +static void +CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::IntensityQuantifier::Pointer quantifier, mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::FeatureListType & featureList) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + + typename MaskType::Pointer itkMask = MaskType::New(); + mitk::CastToItkImage(mask, itkMask); + + ImageType::SizeType regionSize; + regionSize.Fill(1); + + itk::NeighborhoodIterator iter(regionSize, itkImage, itkImage->GetLargestPossibleRegion()); + itk::NeighborhoodIterator iterMask(regionSize, itkMask, itkMask->GetLargestPossibleRegion()); + + std::vector pVector; + std::vector sVector; + pVector.resize(quantifier->GetBins(), 0); + sVector.resize(quantifier->GetBins(), 0); + + int count = 0; + while (!iter.IsAtEnd()) + { + if (iterMask.GetCenterPixel() > 0) + { + int localCount = 0; + double localMean = 0; + unsigned int localIndex = quantifier->IntensityToIndex(iter.GetCenterPixel()); + for (int i = 0; i < iter.Size(); ++i) + { + if (i == (iter.Size() / 2)) + continue; + if (iterMask.GetPixel(i) > 0) + { + ++localCount; + localMean += quantifier->IntensityToIndex(iter.GetPixel(i))+1; + } + } + if (localCount > 0) + { + localMean /= localCount; + } + localMean = std::abs(localIndex + 1 - localMean); + + pVector[localIndex] += 1; + sVector[localIndex] += localMean; + ++count; + + + } + ++iterMask; + ++iter; + } + + unsigned int Ngp = 0; + for (unsigned int i = 0; i < quantifier->GetBins(); ++i) + { + if (pVector[i] > 0.1) + { + ++Ngp; + } + pVector[i] /= count; + } + + double sumS = 0; + double sumStimesP = 0; + + double contrastA = 0; + double busynessA = 0; + double complexity = 0; + double strengthA = 0; + for (unsigned int i = 0; i < quantifier->GetBins(); ++i) + { + sumS += sVector[i]; + sumStimesP += pVector[i] * sVector[i]; + for (unsigned int j = 0; j < quantifier->GetBins(); ++j) + { + double iMinusj = 1.0*i - 1.0*j; + contrastA += pVector[i] * pVector[j] * iMinusj*iMinusj; + if ((pVector[i] > 0) && (pVector[j] > 0)) + { + busynessA += std::abs((i + 1.0)*pVector[i] - (j + 1.0)*pVector[j]); + complexity += std::abs(iMinusj)*(pVector[i] * sVector[i] + pVector[j] * sVector[j]) / (pVector[i] + pVector[j]); + strengthA += (pVector[i] + pVector[j])*iMinusj*iMinusj; + } + } + } + double coarsness = 1.0 / std::min(sumStimesP, 1000000); + double contrast = 0; + double busyness = 0; + if (Ngp > 1) + { + contrast = contrastA / Ngp / (Ngp - 1) / count * sumS; + busyness = sumStimesP / busynessA; + } + complexity /= count; + double strength = 0; + if (sumS > 0) + { + strength = strengthA / sumS; + } + + featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference Coarsness", coarsness)); + featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference Contrast", contrast)); + featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference Busyness", busyness)); + featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference Complexity", complexity)); + featureList.push_back(std::make_pair("Neighbourhood Grey Tone Difference Strength", strength)); +} + + +mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::GIFNeighbourhoodGreyToneDifferenceFeatures() +{ + SetLongName("neighbourhood-grey-tone-difference"); + SetShortName("ngtd"); +} + +mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::FeatureListType mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +{ + FeatureListType featureList; + //if (image->GetDimension() < 3) + //{ + // return featureList; + //} + AccessByItk_3(image, CalculateIntensityPeak, mask, GetQuantifier(), featureList); + return featureList; +} + +mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::FeatureNameListType mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::GetFeatureNames() +{ + FeatureNameListType featureList; + return featureList; +} + + +void mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::AddArguments(mitkCommandLineParser &parser) +{ + AddQuantifierArguments(parser); + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Local Intensity", "calculates local intensity based features", us::Any()); +} + +void +mitk::GIFNeighbourhoodGreyToneDifferenceFeatures::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNaN, FeatureListType &featureList) +{ + InitializeQuantifier(feature, mask, maskNoNaN, featureList); + + auto parsedArgs = GetParameter(); + if (parsedArgs.count(GetLongName())) + { + MITK_INFO << "Start calculating local intensity features ...."; + auto localResults = this->CalculateFeatures(feature, mask); + featureList.insert(featureList.end(), localResults.begin(), localResults.end()); + MITK_INFO << "Finished calculating local intensity features...."; + } +} + diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp index cfd0992fdb..8b2efc661d 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp @@ -1,412 +1,412 @@ #include // MITK #include #include #include // ITK #include #include #include #include // STL #include static void MatrixFeaturesTo(mitk::NGLDMMatrixFeatures features, std::string prefix, mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType &featureList); mitk::NGLDMMatrixHolder::NGLDMMatrixHolder(double min, double max, int number, int depenence) : m_MinimumRange(min), m_MaximumRange(max), m_Stepsize(0), m_NumberOfDependences(depenence), m_NumberOfBins(number), m_NeighbourhoodSize(1), m_NumberOfNeighbourVoxels(0), m_NumberOfDependenceNeighbourVoxels(0), m_NumberOfNeighbourhoods(0), m_NumberOfCompleteNeighbourhoods(0) { m_Matrix.resize(number, depenence); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::NGLDMMatrixHolder::IntensityToIndex(double intensity) { return std::floor((intensity - m_MinimumRange) / m_Stepsize); } double mitk::NGLDMMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::NGLDMMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::NGLDMMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template void CalculateNGLDMMatrix(itk::Image* itkImage, itk::Image* mask, int alpha, int range, unsigned int direction, mitk::NGLDMMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef itk::NeighborhoodIterator ShapeIterType; typedef itk::NeighborhoodIterator ShapeMaskIterType; holder.m_NumberOfCompleteNeighbourhoods = 0; holder.m_NumberOfNeighbourhoods = 0; holder.m_NumberOfNeighbourVoxels = 0; holder.m_NumberOfDependenceNeighbourVoxels = 0; itk::Size radius; radius.Fill(range); if ((direction > 1) && (direction - 2 GetLargestPossibleRegion()); ShapeMaskIterType maskIter(radius, mask, mask->GetLargestPossibleRegion()); auto region = mask->GetLargestPossibleRegion(); auto center = imageIter.Size() / 2; auto iterSize = imageIter.Size(); holder.m_NeighbourhoodSize = iterSize-1; while (!maskIter.IsAtEnd()) { int sameValues = 0; bool completeNeighbourhood = true; int i = holder.IntensityToIndex(imageIter.GetCenterPixel()); if ((imageIter.GetCenterPixel() != imageIter.GetCenterPixel()) || (maskIter.GetCenterPixel() < 1)) { ++imageIter; ++maskIter; continue; } for (unsigned int position = 0; position < iterSize; ++position) { if (position == center) { continue; } if ( ! region.IsInside(maskIter.GetIndex(position))) { completeNeighbourhood = false; continue; } bool isInBounds; auto jIntensity = imageIter.GetPixel(position, isInBounds); auto jMask = maskIter.GetPixel(position, isInBounds); if (jMask < 1 || (jIntensity != jIntensity) || ( ! isInBounds)) { completeNeighbourhood = false; continue; } int j = holder.IntensityToIndex(jIntensity); holder.m_NumberOfNeighbourVoxels += 1; if (std::abs(i - j) <= alpha) { holder.m_NumberOfDependenceNeighbourVoxels += 1; ++sameValues; } } holder.m_Matrix(i, sameValues) += 1; holder.m_NumberOfNeighbourhoods += 1; if (completeNeighbourhood) { holder.m_NumberOfCompleteNeighbourhoods += 1; } ++imageIter; ++maskIter; } } void LocalCalculateFeatures( mitk::NGLDMMatrixHolder &holder, mitk::NGLDMMatrixFeatures & results ) { auto sijMatrix = holder.m_Matrix; auto piMatrix = holder.m_Matrix; auto pjMatrix = holder.m_Matrix; // double Ng = holder.m_NumberOfBins; // int NgSize = holder.m_NumberOfBins; double Ns = sijMatrix.sum(); piMatrix.rowwise().normalize(); pjMatrix.colwise().normalize(); for (int i = 0; i < holder.m_NumberOfBins; ++i) { double sj = 0; for (int j = 0; j < holder.m_NumberOfDependences; ++j) { - double iInt = i + 1;// holder.IndexToMeanIntensity(i); + double iInt = i+1 ;// holder.IndexToMeanIntensity(i); double sij = sijMatrix(i, j); - double k = j+1; + double k = j + 1; double pij = sij / Ns; results.LowDependenceEmphasis += sij / k / k; results.HighDependenceEmphasis += sij * k*k; if (iInt != 0) { results.LowGreyLevelCountEmphasis += sij / iInt / iInt; } results.HighGreyLevelCountEmphasis += sij * iInt*iInt; if (iInt != 0) { results.LowDependenceLowGreyLevelEmphasis += sij / k / k / iInt / iInt; } results.LowDependenceHighGreyLevelEmphasis += sij * iInt*iInt / k / k; if (iInt != 0) { results.HighDependenceLowGreyLevelEmphasis += sij *k * k / iInt / iInt; } results.HighDependenceHighGreyLevelEmphasis += sij * k*k*iInt*iInt; results.MeanGreyLevelCount += iInt * pij; results.MeanDependenceCount += k * pij; if (pij > 0) { results.DependenceCountEntropy -= pij * std::log(pij) / std::log(2); } results.DependenceCountEnergy += pij*pij; sj += sij; } results.GreyLevelNonUniformity += sj*sj; results.GreyLevelNonUniformityNormalised += sj*sj; } for (int j = 0; j < holder.m_NumberOfDependences; ++j) { double si = 0; for (int i = 0; i < holder.m_NumberOfBins; ++i) { double sij = sijMatrix(i, j); si += sij; } results.DependenceCountNonUniformity += si*si; results.DependenceCountNonUniformityNormalised += si*si; } for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfDependences; ++j) { double iInt = i + 1;// holder.IndexToMeanIntensity(i); double sij = sijMatrix(i, j); double k = j + 1; double pij = sij / Ns; results.GreyLevelVariance += (iInt - results.MeanGreyLevelCount)* (iInt - results.MeanGreyLevelCount) * pij; results.DependenceCountVariance += (k - results.MeanDependenceCount)* (k - results.MeanDependenceCount) * pij; } } results.LowDependenceEmphasis /= Ns; results.HighDependenceEmphasis /= Ns; results.LowGreyLevelCountEmphasis /= Ns; results.HighGreyLevelCountEmphasis /= Ns; results.LowDependenceLowGreyLevelEmphasis /= Ns; results.LowDependenceHighGreyLevelEmphasis /= Ns; results.HighDependenceLowGreyLevelEmphasis /= Ns; results.HighDependenceHighGreyLevelEmphasis /= Ns; results.GreyLevelNonUniformity /= Ns; results.GreyLevelNonUniformityNormalised /= (Ns*Ns); results.DependenceCountNonUniformity /= Ns; results.DependenceCountNonUniformityNormalised /= (Ns*Ns); results.DependenceCountPercentage = 1; results.ExpectedNeighbourhoodSize = holder.m_NeighbourhoodSize; results.AverageNeighbourhoodSize = holder.m_NumberOfNeighbourVoxels / (1.0 * holder.m_NumberOfNeighbourhoods); results.AverageIncompleteNeighbourhoodSize = (holder.m_NumberOfNeighbourVoxels - holder.m_NumberOfCompleteNeighbourhoods* holder.m_NeighbourhoodSize) / (1.0 * (holder.m_NumberOfNeighbourhoods - holder.m_NumberOfCompleteNeighbourhoods)); results.PercentageOfCompleteNeighbourhoods = (1.0*holder.m_NumberOfCompleteNeighbourhoods) / (1.0 * holder.m_NumberOfNeighbourhoods); results.PercentageOfDependenceNeighbours = holder.m_NumberOfDependenceNeighbourVoxels / (1.0 * holder.m_NumberOfNeighbourVoxels); } template void CalculateCoocurenceFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType & featureList, mitk::GIFNeighbouringGreyLevelDependenceFeature::GIFNeighbouringGreyLevelDependenceFeatureConfiguration config) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; /////////////////////////////////////////////////////////////////////////////////////////////// typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); minMaxComputer->SetImage(itkImage); minMaxComputer->Compute(); double rangeMin = -0.5 + minMaxComputer->GetMinimum(); double rangeMax = 0.5 + minMaxComputer->GetMaximum(); if (config.UseMinimumIntensity) rangeMin = config.MinimumIntensity; if (config.UseMaximumIntensity) rangeMax = config.MaximumIntensity; // Define Range int numberOfBins = config.Bins; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); std::vector resultVector; int numberofDependency = 37; if (VImageDimension == 2) numberofDependency = 37; mitk::NGLDMMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins, numberofDependency); mitk::NGLDMMatrixFeatures overallFeature; CalculateNGLDMMatrix(itkImage, maskImage, config.alpha, config.range, config.direction, holderOverall); LocalCalculateFeatures(holderOverall, overallFeature); std::ostringstream ss; ss << config.range; std::string strRange = ss.str(); MatrixFeaturesTo(overallFeature, "NGLDM (" + strRange + ") overall", featureList); } static void MatrixFeaturesTo(mitk::NGLDMMatrixFeatures features, std::string prefix, mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType &featureList) { featureList.push_back(std::make_pair(prefix + " Low Dependence Emphasis", features.LowDependenceEmphasis)); featureList.push_back(std::make_pair(prefix + " High Dependence Emphasis", features.HighDependenceEmphasis)); featureList.push_back(std::make_pair(prefix + " Low Grey Level Count Emphasis", features.LowGreyLevelCountEmphasis)); featureList.push_back(std::make_pair(prefix + " High Grey Level Count Emphasis", features.HighGreyLevelCountEmphasis)); featureList.push_back(std::make_pair(prefix + " Low Dependence Low Grey Level Emphasis", features.LowDependenceLowGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + " Low Dependence High Grey Level Emphasis", features.LowDependenceHighGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + " High Dependence Low Grey Level Emphasis", features.HighDependenceLowGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + " High Dependence High Grey Level Emphasis", features.HighDependenceHighGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + " Grey Level Non-Uniformity", features.GreyLevelNonUniformity)); featureList.push_back(std::make_pair(prefix + " Grey Level Non-Uniformity Normalised", features.GreyLevelNonUniformityNormalised)); featureList.push_back(std::make_pair(prefix + " Dependence Count Non-Uniformity", features.DependenceCountNonUniformity)); featureList.push_back(std::make_pair(prefix + " Dependence Count Non-Uniformtiy Normalised", features.DependenceCountNonUniformityNormalised)); featureList.push_back(std::make_pair(prefix + " Dependence Count Percentage", features.DependenceCountPercentage)); featureList.push_back(std::make_pair(prefix + " Grey Level Mean", features.MeanGreyLevelCount)); featureList.push_back(std::make_pair(prefix + " Grey Level Variance", features.GreyLevelVariance)); featureList.push_back(std::make_pair(prefix + " Dependence Count Mean", features.MeanDependenceCount)); featureList.push_back(std::make_pair(prefix + " Dependence Count Variance", features.DependenceCountVariance)); featureList.push_back(std::make_pair(prefix + " Dependence Count Entropy", features.DependenceCountEntropy)); featureList.push_back(std::make_pair(prefix + " Dependence Count Energy", features.DependenceCountEnergy)); featureList.push_back(std::make_pair(prefix + " Expected Neighbourhood Size", features.ExpectedNeighbourhoodSize)); featureList.push_back(std::make_pair(prefix + " Average Neighbourhood Size", features.AverageNeighbourhoodSize)); featureList.push_back(std::make_pair(prefix + " Average Incomplete Neighbourhood Size", features.AverageIncompleteNeighbourhoodSize)); featureList.push_back(std::make_pair(prefix + " Percentage of complete Neighbourhoods", features.PercentageOfCompleteNeighbourhoods)); featureList.push_back(std::make_pair(prefix + " Percentage of Dependence Neighbour Voxels", features.PercentageOfDependenceNeighbours)); } mitk::GIFNeighbouringGreyLevelDependenceFeature::GIFNeighbouringGreyLevelDependenceFeature() : m_Range(1.0), m_Bins(6) { SetShortName("ngldm"); SetLongName("ngldm"); } mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType mitk::GIFNeighbouringGreyLevelDependenceFeature::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; GIFNeighbouringGreyLevelDependenceFeatureConfiguration config; config.direction = GetDirection(); config.range = m_Range; config.alpha = 0; config.MinimumIntensity = GetMinimumIntensity(); config.MaximumIntensity = GetMaximumIntensity(); config.UseMinimumIntensity = GetUseMinimumIntensity(); config.UseMaximumIntensity = GetUseMaximumIntensity(); config.Bins = GetBins(); AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList,config); return featureList; } mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureNameListType mitk::GIFNeighbouringGreyLevelDependenceFeature::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFNeighbouringGreyLevelDependenceFeature::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Calculate Neighbouring grey level dependence based features", "Calculate Neighbouring grey level dependence based features", us::Any()); parser.addArgument(name + "::range", name + "::range", mitkCommandLineParser::String, "NGLD Range", "Define the range that is used (Semicolon-separated)", us::Any()); parser.addArgument(name + "::bins", name + "::bins", mitkCommandLineParser::String, "NGLD Number of Bins", "Define the number of bins that is used ", us::Any()); } void mitk::GIFNeighbouringGreyLevelDependenceFeature::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); std::string name = GetOptionPrefix(); if (parsedArgs.count(GetLongName())) { std::vector ranges; if (parsedArgs.count(name + "::range")) { ranges = SplitDouble(parsedArgs[name + "::range"].ToString(), ';'); } else { ranges.push_back(1); } if (parsedArgs.count(name + "::bins")) { auto bins = SplitDouble(parsedArgs[name + "::bins"].ToString(), ';')[0]; this->SetBins(bins); } for (std::size_t i = 0; i < ranges.size(); ++i) { MITK_INFO << "Start calculating NGLDM 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 NGLDM with range " << ranges[i] << "...."; } } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp new file mode 100644 index 0000000000..d870dc16bd --- /dev/null +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp @@ -0,0 +1,528 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +// MITK +#include +#include +#include +#include +#include + +// ITK +#include +#include +#include +#include + +// VTK +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +// STL +#include +#include + +// OpenCV +#include + +// Eigen +#include + +template +void + CalculateVolumeDensityStatistic(itk::Image* itkImage, mitk::Image::Pointer mask, double volume, mitk::GIFVolumetricDensityStatistics::FeatureListType & featureList) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + typedef itk::LabelGeometryImageFilter FilterType; + + typename MaskType::Pointer maskImage = MaskType::New(); + mitk::CastToItkImage(mask, maskImage); + + itk::ImageRegionConstIteratorWithIndex imgA(itkImage, itkImage->GetLargestPossibleRegion()); + itk::ImageRegionConstIteratorWithIndex imgB(itkImage, itkImage->GetLargestPossibleRegion()); + itk::ImageRegionConstIteratorWithIndex maskA(maskImage, maskImage->GetLargestPossibleRegion()); + itk::ImageRegionConstIteratorWithIndex maskB(maskImage, maskImage->GetLargestPossibleRegion()); + + double moranA = 0; + double moranB = 0; + double geary = 0; + double Nv = 0; + double w_ij = 0; + double mean = 0; + + ImageType::PointType pointA; + ImageType::PointType pointB; + + while (!imgA.IsAtEnd()) + { + if (maskA.Get() > 0) + { + Nv += 1; + mean += imgA.Get(); + } + ++imgA; + ++maskA; + } + mean /= Nv; + imgA.GoToBegin(); + maskA.GoToBegin(); + while (!imgA.IsAtEnd()) + { + if (maskA.Get() > 0) + { + imgB.GoToBegin(); + maskB.GoToBegin(); + while (!imgB.IsAtEnd()) + { + if ((imgA.GetIndex() == imgB.GetIndex()) || + (maskB.Get() < 1)) + { + ++imgB; + ++maskB; + continue; + } + itkImage->TransformIndexToPhysicalPoint(maskA.GetIndex(), pointA); + itkImage->TransformIndexToPhysicalPoint(maskB.GetIndex(), pointB); + + double w = 1 / pointA.EuclideanDistanceTo(pointB); + moranA += w*(imgA.Get() - mean)* (imgB.Get() - mean); + geary += w * (imgA.Get() - imgB.Get()) * (imgA.Get() - imgB.Get()); + + w_ij += w; + + ++imgB; + ++maskB; + } + moranB += (imgA.Get() - mean)* (imgA.Get() - mean); + } + ++imgA; + ++maskA; + } + + featureList.push_back(std::make_pair("Morphological Density Volume Integrated Intensity", volume* mean)); + featureList.push_back(std::make_pair("Morphological Density Volume Moran's I Index", Nv / w_ij * moranA / moranB)); + featureList.push_back(std::make_pair("Morphological Density Volume Geary's C measure", ( Nv -1 ) / 2 / w_ij * geary/ moranB)); +} + +void calculateMOBB(vtkPointSet *pointset, double &volume, double &surface) +{ + auto cell = pointset->GetCell(0); + volume = 10000000000000000000; + + for (int cellID = 0; cellID < pointset->GetNumberOfCells(); ++cellID) + { + auto cell = pointset->GetCell(cellID); + + for (int edgeID = 0; edgeID < 3; ++edgeID) + { + auto edge = cell->GetEdge(edgeID); + + double pA[3], pB[3]; + double pAA[3], pBB[3]; + + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->PostMultiply(); + pointset->GetPoint(edge->GetPointId(0), pA); + pointset->GetPoint(edge->GetPointId(1), pB); + + double angleZ = std::atan2((- pA[2] + pB[2]) ,(pA[1] - pB[1])); + angleZ *= 180 / vnl_math::pi; + if (pA[2] == pB[2]) + angleZ = 0; + + transform->RotateX(angleZ); + transform->TransformPoint(pA, pAA); + transform->TransformPoint(pB, pBB); + + double angleY = std::atan2((pAA[1] -pBB[1]) ,-(pAA[0] - pBB[0])); + angleY *= 180 / vnl_math::pi; + if (pAA[1] == pBB[1]) + angleY = 0; + transform->RotateZ(angleY); + + double p0[3]; + pointset->GetPoint(edge->GetPointId(0), p0); + + double curMinX = 1000000000000000; + double curMaxX = -10000000000000000; + double curMinY = 1000000000000000; + double curMaxY = -10000000000000000; + double curMinZ = 1000000000000000; + double curMaxZ = -10000000000000000; + for (int pointID = 0; pointID < pointset->GetNumberOfPoints(); ++pointID) + { + double p[3]; + double p2[3]; + pointset->GetPoint(pointID, p); + p[0] -= p0[0]; p[1] -= p0[1]; p[2] -= p0[2]; + transform->TransformPoint(p, p2); + + curMinX = std::min(p2[0], curMinX); + curMaxX = std::max(p2[0], curMaxX); + curMinY = std::min(p2[1], curMinY); + curMaxY = std::max(p2[1], curMaxY); + curMinZ = std::min(p2[2], curMinZ); + curMaxZ = std::max(p2[2], curMaxZ); + + //std::cout << pointID << " (" << p[0] << "|" << p[1] << "|" << p[2] << ") (" << p2[0] << "|" << p2[1] << "|" << p2[2] << ")" << std::endl; + } + + if ((curMaxX - curMinX)*(curMaxY - curMinY)*(curMaxZ - curMinZ) < volume) + { + volume = (curMaxX - curMinX)*(curMaxY - curMinY)*(curMaxZ - curMinZ); + surface = (curMaxX - curMinX)*(curMaxX - curMinX) + (curMaxY - curMinY)*(curMaxY - curMinY) + (curMaxZ - curMinZ)*(curMaxZ - curMinZ); + surface *= 2; + } + + + } + } +} + +void calculateMEE(vtkPointSet *pointset, double &vol, double &surf, double tolerance=0.0000001) +{ + // Inspired by https://github.com/smdabdoub/ProkaryMetrics/blob/master/calc/fitting.py + + int numberOfPoints = pointset->GetNumberOfPoints(); + int dimension = 3; + Eigen::MatrixXd points(3, numberOfPoints); + Eigen::MatrixXd Q(3+1, numberOfPoints); + double p[3]; + for (int i = 0; i < numberOfPoints; ++i) + { + pointset->GetPoint(i, p); + points(0, i) = p[0]; + points(1, i) = p[1]; + points(2, i) = p[2]; + Q(0, i) = p[0]; + Q(1, i) = p[1]; + Q(2, i) = p[2]; + Q(3, i) = p[3]; + } + + int count = 1; + double error = 1; + Eigen::VectorXd u_vector(numberOfPoints); + u_vector.fill(1.0 / numberOfPoints); + Eigen::DiagonalMatrix u = u_vector.asDiagonal(); + Eigen::VectorXd ones(dimension + 1); + ones.fill(1); + Eigen::MatrixXd Ones = ones.asDiagonal(); + + // Khachiyan Algorithm + while (error > tolerance) + { + auto Qt = Q.transpose(); + Eigen::MatrixXd X = Q*u*Qt; + Eigen::FullPivHouseholderQR qr(X); + Eigen::MatrixXd Xi = qr.solve(Ones); + Eigen::MatrixXd M = Qt * Xi * Q; + + double maximumValue = M(0, 0); + int maximumPosition = 0; + for (int i = 0; i < numberOfPoints; ++i) + { + if (maximumValue < M(i, i)) + { + maximumValue = M(i, i); + maximumPosition = i; + } + } + double stepsize = (maximumValue - dimension - 1) / ((dimension + 1) * (maximumValue - 1)); + Eigen::DiagonalMatrix new_u = (1.0 - stepsize) * u; + new_u.diagonal()[maximumPosition] = (new_u.diagonal())(maximumPosition) + stepsize; + ++count; + error = (new_u.diagonal() - u.diagonal()).norm(); + u.diagonal() = new_u.diagonal(); + } + + // U = u + Eigen::MatrixXd Ai = points * u * points.transpose() - points * u *(points * u).transpose(); + Eigen::FullPivHouseholderQR qr(Ai); + Eigen::VectorXd ones2(dimension); + ones2.fill(1); + Eigen::MatrixXd Ones2 = ones2.asDiagonal(); + Eigen::MatrixXd A = qr.solve(Ones2)*1.0/dimension; + + Eigen::JacobiSVD svd(A); + double c = 1 / sqrt(svd.singularValues()[0]); + double b = 1 / sqrt(svd.singularValues()[1]); + double a = 1 / sqrt(svd.singularValues()[2]); + double V = 4 * vnl_math::pi*a*b*c / 3; + + double ad_mvee= 0; + double alpha = std::sqrt(1 - b*b / a / a); + double beta = std::sqrt(1 - c*c / a / a); + for (int i = 0; i < 20; ++i) + { + ad_mvee += 4 * vnl_math::pi*a*b*(alpha*alpha + beta*beta) / (2 * alpha*beta) * (std::pow(alpha*beta, i)) / (1 - 4 * i*i); + } + vol = V; + surf = ad_mvee; +} + +mitk::GIFVolumetricDensityStatistics::FeatureListType mitk::GIFVolumetricDensityStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +{ + FeatureListType featureList; + if (image->GetDimension() < 3) + { + return featureList; + } + + + //AccessByItk_2(mask, CalculateLargestDiameter, image, featureList); + + vtkSmartPointer mesher = vtkSmartPointer::New(); + vtkSmartPointer stats = vtkSmartPointer::New(); + vtkSmartPointer stats2 = vtkSmartPointer::New(); + mesher->SetInputData(mask->GetVtkImageData()); + mesher->SetValue(0, 0.5); + stats->SetInputConnection(mesher->GetOutputPort()); + stats->Update(); + + vtkSmartPointer delaunay = + vtkSmartPointer< vtkDelaunay3D >::New(); + delaunay->SetInputConnection(mesher->GetOutputPort()); + //delaunay->SetInputData(mask->GetVtkImageData()); + delaunay->SetAlpha(0); + delaunay->Update(); + vtkSmartPointer geometryFilter = + vtkSmartPointer::New(); + geometryFilter->SetInputConnection(delaunay->GetOutputPort()); + geometryFilter->Update(); + stats2->SetInputConnection(geometryFilter->GetOutputPort()); + stats2->Update(); + + auto data = mesher->GetOutput()->GetPointData(); + + double vol_mvee; + double surf_mvee; + calculateMEE(mesher->GetOutput(), vol_mvee, surf_mvee); + + double vol_mobb; + double surf_mobb; + calculateMOBB(geometryFilter->GetOutput(), vol_mobb, surf_mobb); + + double pi = vnl_math::pi; + + double meshVolume = stats->GetVolume(); + double meshSurf = stats->GetSurfaceArea(); + + + AccessByItk_3(image, CalculateVolumeDensityStatistic, mask, meshVolume, featureList); + + //Calculate center of mass shift + int xx = mask->GetDimensions()[0]; + int yy = mask->GetDimensions()[1]; + int zz = mask->GetDimensions()[2]; + + double xd = mask->GetGeometry()->GetSpacing()[0]; + double yd = mask->GetGeometry()->GetSpacing()[1]; + double zd = mask->GetGeometry()->GetSpacing()[2]; + + std::vector pointsForPCA; + std::vector pointsForPCAUncorrected; + + int minimumX=xx; + int maximumX=0; + int minimumY=yy; + int maximumY=0; + int minimumZ=zz; + int maximumZ=0; + + vtkSmartPointer points = + vtkSmartPointer< vtkPoints >::New(); + + for (int x = 0; x < xx; x++) + { + for (int y = 0; y < yy; y++) + { + for (int z = 0; z < zz; z++) + { + itk::Image::IndexType index; + + index[0] = x; + index[1] = y; + index[2] = z; + + mitk::ScalarType pxImage; + mitk::ScalarType pxMask; + + mitkPixelTypeMultiplex5( + mitk::FastSinglePixelAccess, + image->GetChannelDescriptor().GetPixelType(), + image, + image->GetVolumeData(), + index, + pxImage, + 0); + + mitkPixelTypeMultiplex5( + mitk::FastSinglePixelAccess, + mask->GetChannelDescriptor().GetPixelType(), + mask, + mask->GetVolumeData(), + index, + pxMask, + 0); + + //Check if voxel is contained in segmentation + if (pxMask > 0) + { + minimumX = std::min(x, minimumX); + minimumY = std::min(y, minimumY); + minimumZ = std::min(z, minimumZ); + maximumX = std::max(x, maximumX); + maximumY = std::max(y, maximumY); + maximumZ = std::max(z, maximumZ); + points->InsertNextPoint(x*xd, y*yd, z*zd); + cv::Point3d tmp; + tmp.x = x * xd; + tmp.y = y * yd; + tmp.z = z * zd; + pointsForPCAUncorrected.push_back(tmp); + + if (pxImage == pxImage) + { + pointsForPCA.push_back(tmp); + } + } + } + } + } + + + //Calculate PCA Features + int sz = pointsForPCA.size(); + cv::Mat data_pts = cv::Mat(sz, 3, CV_64FC1); + for (int i = 0; i < data_pts.rows; ++i) + { + data_pts.at(i, 0) = pointsForPCA[i].x; + data_pts.at(i, 1) = pointsForPCA[i].y; + data_pts.at(i, 2) = pointsForPCA[i].z; + } + + //Calculate PCA Features + int szUC = pointsForPCAUncorrected.size(); + cv::Mat data_ptsUC = cv::Mat(szUC, 3, CV_64FC1); + for (int i = 0; i < data_ptsUC.rows; ++i) + { + data_ptsUC.at(i, 0) = pointsForPCAUncorrected[i].x; + data_ptsUC.at(i, 1) = pointsForPCAUncorrected[i].y; + data_ptsUC.at(i, 2) = pointsForPCAUncorrected[i].z; + } + + //Perform PCA analysis + cv::PCA pca_analysis(data_pts, cv::Mat(), CV_PCA_DATA_AS_ROW); + cv::PCA pca_analysisUC(data_ptsUC, cv::Mat(), CV_PCA_DATA_AS_ROW); + + //Store the eigenvalues + std::vector eigen_val(3); + std::vector eigen_valUC(3); + for (int i = 0; i < 3; ++i) + { + eigen_val[i] = pca_analysis.eigenvalues.at(0, i); + eigen_valUC[i] = pca_analysisUC.eigenvalues.at(0, i); + } + + std::sort(eigen_val.begin(), eigen_val.end()); + std::sort(eigen_valUC.begin(), eigen_valUC.end()); + + double major = 2*sqrt(eigen_val[2]); + double minor = 2*sqrt(eigen_val[1]); + double least = 2*sqrt(eigen_val[0]); + + double alpha = std::sqrt(1 - minor*minor / major / major); + double beta = std::sqrt(1 - least*least / major / major); + + double a = (maximumX - minimumX+1) * xd; + double b = (maximumY - minimumY+1) * yd; + double c = (maximumZ - minimumZ+1) * zd; + + double vd_aabb = meshVolume / (a*b*c); + double ad_aabb = meshSurf / (2 * a*b + 2 * a*c + 2 * b*c); + + double vd_aee = 3 * meshVolume / (4.0*pi*major*minor*least); + double ad_aee = 0; + for (int i = 0; i < 20; ++i) + { + ad_aee += 4 * pi*major*minor*(alpha*alpha + beta*beta) / (2 * alpha*beta) * (std::pow(alpha*beta, i)) / (1 - 4 * i*i); + } + ad_aee = meshSurf / ad_aee; + + double vd_ch = meshVolume / stats2->GetVolume(); + double ad_ch = meshSurf / stats2->GetSurfaceArea(); + + featureList.push_back(std::make_pair("Morphological Density Volume Density axis-aligned bounding box", vd_aabb)); + featureList.push_back(std::make_pair("Morphological Density Surface Density axis-aligned bounding box", ad_aabb)); + featureList.push_back(std::make_pair("Morphological Density Volume Density oriented bounding box", meshVolume / vol_mobb)); + featureList.push_back(std::make_pair("Morphological Density Surface Density oriented bounding box", meshSurf / surf_mobb)); + featureList.push_back(std::make_pair("Morphological Density Volume Density Approx. enclosing ellipsoid", vd_aee)); + featureList.push_back(std::make_pair("Morphological Density Surface Density Approx. enclosing ellipsoid", ad_aee)); + featureList.push_back(std::make_pair("Morphological Density Volume Density Approx. minimum enclosing ellipsoid", meshVolume / vol_mvee)); + featureList.push_back(std::make_pair("Morphological Density Surface Density Approx. minimum enclosing ellipsoid", meshSurf / surf_mvee)); + featureList.push_back(std::make_pair("Morphological Density Volume Density Convex Hull", vd_ch)); + featureList.push_back(std::make_pair("Morphological Density Surface Density Convex Hull", ad_ch)); + + return featureList; +} + +mitk::GIFVolumetricDensityStatistics::GIFVolumetricDensityStatistics() +{ + SetLongName("volume-density"); + SetShortName("volden"); +} + +mitk::GIFVolumetricDensityStatistics::FeatureNameListType mitk::GIFVolumetricDensityStatistics::GetFeatureNames() +{ + FeatureNameListType featureList; + return featureList; +} + + +void mitk::GIFVolumetricDensityStatistics::AddArguments(mitkCommandLineParser &parser) +{ + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Volume-Density Statistic", "calculates volume density based features", us::Any()); +} + +void +mitk::GIFVolumetricDensityStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) +{ + auto parsedArgs = GetParameter(); + if (parsedArgs.count(GetLongName())) + { + MITK_INFO << "Start calculating volumetric density features ...."; + auto localResults = this->CalculateFeatures(feature, mask); + featureList.insert(featureList.end(), localResults.begin(), localResults.end()); + MITK_INFO << "Finished calculating volumetric density features...."; + } +} + diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp index ca5faec970..091e19c9dd 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp @@ -1,432 +1,444 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include // MITK #include #include #include #include #include // ITK #include #include // VTK #include #include #include // STL #include #include // OpenCV #include template void CalculateVolumeStatistic(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFVolumetricStatistics::FeatureListType & featureList) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::LabelStatisticsImageFilter FilterType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); typename FilterType::Pointer labelStatisticsImageFilter = FilterType::New(); labelStatisticsImageFilter->SetInput( itkImage ); labelStatisticsImageFilter->SetLabelInput(maskImage); labelStatisticsImageFilter->Update(); double volume = labelStatisticsImageFilter->GetCount(1); double voxelVolume = 1; for (int i = 0; i < (int)(VImageDimension); ++i) { volume *= itkImage->GetSpacing()[i]; voxelVolume *= itkImage->GetSpacing()[i]; } featureList.push_back(std::make_pair("Volumetric Features Volume (pixel based)", volume)); featureList.push_back(std::make_pair("Volumetric Features Voxel Volume", voxelVolume)); } template void CalculateLargestDiameter(itk::Image* mask, mitk::Image::Pointer valueImage, mitk::GIFVolumetricStatistics::FeatureListType & featureList) { typedef itk::Image ValueImageType; typename ValueImageType::Pointer itkValueImage = ValueImageType::New(); mitk::CastToItkImage(valueImage, itkValueImage); - typedef itk::Image ImageType; typedef typename ImageType::PointType PointType; typename ImageType::SizeType radius; for (int i=0; i < (int)VImageDimension; ++i) radius[i] = 1; itk::NeighborhoodIterator iterator(radius, mask, mask->GetRequestedRegion()); itk::NeighborhoodIterator valueIter(radius, itkValueImage, itkValueImage->GetRequestedRegion()); std::vector borderPoints; + unsigned int maskDimensionX = mask->GetLargestPossibleRegion().GetSize()[0]; + unsigned int maskDimensionY = mask->GetLargestPossibleRegion().GetSize()[1]; + unsigned int maskDimensionZ = mask->GetLargestPossibleRegion().GetSize()[2]; + + double maskVoxelSpacingX = mask->GetSpacing()[0]; + double maskVoxelSpacingY = mask->GetSpacing()[1]; + double maskVoxelSpacingZ = mask->GetSpacing()[2]; + + unsigned int maskMinimumX = maskDimensionX; + unsigned int maskMaximumX = 0; + unsigned int maskMinimumY = maskDimensionY; + unsigned int maskMaximumY = 0; + unsigned int maskMinimumZ = maskDimensionZ; + unsigned int maskMaximumZ = 0; + // // Calculate surface in different directions // double surface = 0; std::vector directionSurface; for (int i = 0; i < (int)(iterator.Size()); ++i) { auto offset = iterator.GetOffset(i); double deltaS = 1; int nonZeros = 0; for (unsigned int j = 0; j < VImageDimension; ++j) { if (offset[j] != 0 && nonZeros == 0) { for (unsigned int k = 0; k < VImageDimension; ++k) { if (k != j) deltaS *= mask->GetSpacing()[k]; } nonZeros++; } else if (offset[j] != 0) { deltaS = 0; } } if (nonZeros < 1) deltaS = 0; directionSurface.push_back(deltaS); } // // Prepare calulation of Centre of mass shift // PointType normalCenter(0); PointType normalCenterUncorrected(0); PointType weightedCenter(0); PointType currentPoint; int numberOfPoints = 0; int numberOfPointsUncorrected = 0; double sumOfPoints = 0; while(!iterator.IsAtEnd()) { if (iterator.GetCenterPixel() == 0) { ++iterator; ++valueIter; continue; } + maskMinimumX = (maskMinimumX > iterator.GetIndex()[0]) ? iterator.GetIndex()[0] : maskMinimumX; + maskMaximumX = (maskMaximumX < iterator.GetIndex()[0]) ? iterator.GetIndex()[0] : maskMaximumX; + maskMinimumY = (maskMinimumY > iterator.GetIndex()[1]) ? iterator.GetIndex()[1] : maskMinimumY; + maskMaximumY = (maskMaximumY < iterator.GetIndex()[1]) ? iterator.GetIndex()[1] : maskMaximumY; + maskMinimumZ = (maskMinimumZ > iterator.GetIndex()[2]) ? iterator.GetIndex()[2] : maskMinimumZ; + maskMaximumZ = (maskMaximumZ < iterator.GetIndex()[2]) ? iterator.GetIndex()[2] : maskMaximumZ; + mask->TransformIndexToPhysicalPoint(iterator.GetIndex(), currentPoint); normalCenterUncorrected += currentPoint.GetVectorFromOrigin(); ++numberOfPointsUncorrected; double intensityValue = valueIter.GetCenterPixel(); if (intensityValue == intensityValue) { normalCenter += currentPoint.GetVectorFromOrigin(); weightedCenter += currentPoint.GetVectorFromOrigin() * intensityValue; sumOfPoints += intensityValue; ++numberOfPoints; } bool border = false; for (int i = 0; i < (int)(iterator.Size()); ++i) { if (iterator.GetPixel(i) == 0 || ( ! iterator.IndexInBounds(i))) { border = true; surface += directionSurface[i]; //break; } } if (border) { auto centerIndex = iterator.GetIndex(); PointType centerPoint; mask->TransformIndexToPhysicalPoint(centerIndex, centerPoint ); borderPoints.push_back(centerPoint); } ++iterator; ++valueIter; } auto normalCenterVector = normalCenter.GetVectorFromOrigin() / numberOfPoints; auto normalCenterVectorUncorrected = normalCenter.GetVectorFromOrigin() / numberOfPointsUncorrected; auto weightedCenterVector = weightedCenter.GetVectorFromOrigin() / sumOfPoints; auto differenceOfCentersUncorrected = (normalCenterVectorUncorrected - weightedCenterVector).GetNorm(); auto differenceOfCenters = (normalCenterVector - weightedCenterVector).GetNorm(); double longestDiameter = 0; unsigned long numberOfBorderPoints = borderPoints.size(); for (int i = 0; i < (int)numberOfBorderPoints; ++i) { auto point = borderPoints[i]; for (int j = i; j < (int)numberOfBorderPoints; ++j) { double newDiameter=point.EuclideanDistanceTo(borderPoints[j]); if (newDiameter > longestDiameter) longestDiameter = newDiameter; } } + double boundingBoxVolume = maskVoxelSpacingX* (maskMaximumX - maskMinimumX) * maskVoxelSpacingY* (maskMaximumY - maskMinimumY) * maskVoxelSpacingZ* (maskMaximumZ - maskMinimumZ); + featureList.push_back(std::make_pair("Volumetric Features Maximum 3D diameter", longestDiameter)); featureList.push_back(std::make_pair("Volumetric Features Surface (Voxel based)", surface)); featureList.push_back(std::make_pair("Volumetric Features Centre of mass shift", differenceOfCenters)); featureList.push_back(std::make_pair("Volumetric Features Centre of mass shift (Uncorrected)", differenceOfCentersUncorrected)); + featureList.push_back(std::make_pair("Volumetric Features Bounding Box Volume", boundingBoxVolume)); } mitk::GIFVolumetricStatistics::GIFVolumetricStatistics() { SetLongName("volume"); SetShortName("vol"); } mitk::GIFVolumetricStatistics::FeatureListType mitk::GIFVolumetricStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; if (image->GetDimension() < 3) { return featureList; } AccessByItk_2(image, CalculateVolumeStatistic, mask, featureList); AccessByItk_2(mask, CalculateLargestDiameter, image, featureList); vtkSmartPointer mesher = vtkSmartPointer::New(); vtkSmartPointer stats = vtkSmartPointer::New(); mesher->SetInputData(mask->GetVtkImageData()); mesher->SetValue(0, 0.5); stats->SetInputConnection(mesher->GetOutputPort()); stats->Update(); double pi = vnl_math::pi; double meshVolume = stats->GetVolume(); double meshSurf = stats->GetSurfaceArea(); double pixelVolume = featureList[0].second; double pixelSurface = featureList[3].second; MITK_INFO << "Surf: " << pixelSurface << " Vol " << pixelVolume; double compactness1 = pixelVolume / (std::sqrt(pi) * std::pow(meshSurf, 2.0 / 3.0)); double compactness1Pixel = pixelVolume / (std::sqrt(pi) * std::pow(pixelSurface, 2.0 / 3.0)); //This is the definition used by Aertz. However, due to 2/3 this feature is not demensionless. Use compactness3 instead. double compactness2 = 36 * pi*pixelVolume*pixelVolume / meshSurf / meshSurf / meshSurf; double compactness2Pixel = 36 * pi*pixelVolume*pixelVolume / pixelSurface / pixelSurface / pixelSurface; double compactness3 = pixelVolume / (std::sqrt(pi) * std::pow(meshSurf, 3.0 / 2.0)); double compactness3Pixel = pixelVolume / (std::sqrt(pi) * std::pow(pixelSurface, 3.0 / 2.0)); double sphericity = std::pow(pi, 1 / 3.0) *std::pow(6 * pixelVolume, 2.0 / 3.0) / meshSurf; double sphericityPixel = std::pow(pi, 1 / 3.0) *std::pow(6 * pixelVolume, 2.0 / 3.0) / pixelSurface; double surfaceToVolume = meshSurf / pixelVolume; double surfaceToVolumePixel = pixelSurface / pixelVolume; double sphericalDisproportion = meshSurf / 4 / pi / std::pow(3.0 / 4.0 / pi * pixelVolume, 2.0 / 3.0); double sphericalDisproportionPixel = pixelSurface / 4 / pi / std::pow(3.0 / 4.0 / pi * pixelVolume, 2.0 / 3.0); double asphericity = std::pow(1.0/compactness2, (1.0 / 3.0)) - 1; double asphericityPixel = std::pow(1.0/compactness2Pixel, (1.0 / 3.0)) - 1; //Calculate center of mass shift int xx = mask->GetDimensions()[0]; int yy = mask->GetDimensions()[1]; int zz = mask->GetDimensions()[2]; double xd = mask->GetGeometry()->GetSpacing()[0]; double yd = mask->GetGeometry()->GetSpacing()[1]; double zd = mask->GetGeometry()->GetSpacing()[2]; - std::vector pointsForPCA; std::vector pointsForPCAUncorrected; for (int x = 0; x < xx; x++) { for (int y = 0; y < yy; y++) { for (int z = 0; z < zz; z++) { itk::Image::IndexType index; index[0] = x; index[1] = y; index[2] = z; mitk::ScalarType pxImage; mitk::ScalarType pxMask; mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, image->GetChannelDescriptor().GetPixelType(), image, image->GetVolumeData(), index, pxImage, 0); mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, mask->GetChannelDescriptor().GetPixelType(), mask, mask->GetVolumeData(), index, pxMask, 0); //Check if voxel is contained in segmentation if (pxMask > 0) { cv::Point3d tmp; tmp.x = x * xd; tmp.y = y * yd; tmp.z = z * zd; pointsForPCAUncorrected.push_back(tmp); if (pxImage == pxImage) { pointsForPCA.push_back(tmp); } } } } } //Calculate PCA Features int sz = pointsForPCA.size(); cv::Mat data_pts = cv::Mat(sz, 3, CV_64FC1); for (int i = 0; i < data_pts.rows; ++i) { data_pts.at(i, 0) = pointsForPCA[i].x; data_pts.at(i, 1) = pointsForPCA[i].y; data_pts.at(i, 2) = pointsForPCA[i].z; } //Calculate PCA Features int szUC = pointsForPCAUncorrected.size(); cv::Mat data_ptsUC = cv::Mat(szUC, 3, CV_64FC1); for (int i = 0; i < data_ptsUC.rows; ++i) { data_ptsUC.at(i, 0) = pointsForPCAUncorrected[i].x; data_ptsUC.at(i, 1) = pointsForPCAUncorrected[i].y; data_ptsUC.at(i, 2) = pointsForPCAUncorrected[i].z; } //Perform PCA analysis cv::PCA pca_analysis(data_pts, cv::Mat(), CV_PCA_DATA_AS_ROW); cv::PCA pca_analysisUC(data_ptsUC, cv::Mat(), CV_PCA_DATA_AS_ROW); //Store the eigenvalues std::vector eigen_val(3); std::vector eigen_valUC(3); for (int i = 0; i < 3; ++i) { eigen_val[i] = pca_analysis.eigenvalues.at(0, i); eigen_valUC[i] = pca_analysisUC.eigenvalues.at(0, i); } std::sort(eigen_val.begin(), eigen_val.end()); std::sort(eigen_valUC.begin(), eigen_valUC.end()); double major = 4*sqrt(eigen_val[2]); double minor = 4*sqrt(eigen_val[1]); double least = 4*sqrt(eigen_val[0]); - double elongation = major == 0 ? 0 : sqrt(minor/major); - double flatness = major == 0 ? 0 : sqrt(least / major); + double elongation = (major == 0) ? 0 : sqrt(eigen_val[1] / eigen_val[2]); + double flatness = (major == 0) ? 0 : sqrt(eigen_val[0] / eigen_val[2]); double majorUC = 4*sqrt(eigen_valUC[2]); double minorUC = 4*sqrt(eigen_valUC[1]); double leastUC = 4*sqrt(eigen_valUC[0]); - double elongationUC = majorUC == 0 ? 0 : sqrt(minorUC / majorUC); - double flatnessUC = majorUC == 0 ? 0 : sqrt(leastUC / majorUC); + double elongationUC = majorUC == 0 ? 0 : sqrt(eigen_valUC[1] / eigen_valUC[2]); + double flatnessUC = majorUC == 0 ? 0 : sqrt(eigen_valUC[0] / eigen_valUC[2]); featureList.push_back(std::make_pair("Volumetric Features Volume (mesh based)",meshVolume)); featureList.push_back(std::make_pair("Volumetric Features Surface area",meshSurf)); featureList.push_back(std::make_pair("Volumetric Features Surface to volume ratio",surfaceToVolume)); featureList.push_back(std::make_pair("Volumetric Features Sphericity",sphericity)); featureList.push_back(std::make_pair("Volumetric Features Asphericity",asphericity)); featureList.push_back(std::make_pair("Volumetric Features Compactness 1",compactness1)); featureList.push_back(std::make_pair("Volumetric Features Compactness 2",compactness2)); featureList.push_back(std::make_pair("Volumetric Features Compactness 3",compactness3)); featureList.push_back(std::make_pair("Volumetric Features Spherical disproportion", sphericalDisproportion)); featureList.push_back(std::make_pair("Volumetric Features Surface to volume ratio (Voxel based)", surfaceToVolumePixel)); featureList.push_back(std::make_pair("Volumetric Features Sphericity (Voxel based)", sphericityPixel)); featureList.push_back(std::make_pair("Volumetric Features Asphericity (Voxel based)", asphericityPixel)); featureList.push_back(std::make_pair("Volumetric Features Compactness 1 (Voxel based)", compactness1Pixel)); featureList.push_back(std::make_pair("Volumetric Features Compactness 2 (Voxel based)", compactness2Pixel)); featureList.push_back(std::make_pair("Volumetric Features Compactness 3 (Voxel based)", compactness3Pixel)); featureList.push_back(std::make_pair("Volumetric Features Spherical disproportion (Voxel based)", sphericalDisproportionPixel)); featureList.push_back(std::make_pair("Volumetric Features PCA Major Axis",major)); featureList.push_back(std::make_pair("Volumetric Features PCA Minor Axis",minor)); featureList.push_back(std::make_pair("Volumetric Features PCA Least Axis",least)); featureList.push_back(std::make_pair("Volumetric Features PCA Elongation",elongation)); featureList.push_back(std::make_pair("Volumetric Features PCA Flatness",flatness)); featureList.push_back(std::make_pair("Volumetric Features PCA Major Axis (Uncorrected)", majorUC)); featureList.push_back(std::make_pair("Volumetric Features PCA Minor Axis (Uncorrected)", minorUC)); featureList.push_back(std::make_pair("Volumetric Features PCA Least Axis (Uncorrected)", leastUC)); featureList.push_back(std::make_pair("Volumetric Features PCA Elongation (Uncorrected)", elongationUC)); featureList.push_back(std::make_pair("Volumetric Features PCA Flatness (Uncorrected)", flatnessUC)); return featureList; } mitk::GIFVolumetricStatistics::FeatureNameListType mitk::GIFVolumetricStatistics::GetFeatureNames() { FeatureNameListType featureList; - featureList.push_back("Volumetric Features Compactness 1"); - featureList.push_back("Volumetric Features Compactness 2"); - featureList.push_back("Volumetric Features Compactness 3"); - featureList.push_back("Volumetric Features Sphericity"); - featureList.push_back("Volumetric Features Asphericity"); - featureList.push_back("Volumetric Features Surface to volume ratio"); - featureList.push_back("Volumetric Features Surface area"); - featureList.push_back("Volumetric Features Volume (mesh based)"); - featureList.push_back("Volumetric Features Volume (pixel based)"); - featureList.push_back("Volumetric Features Spherical disproportion"); - featureList.push_back("Volumetric Features Maximum 3D diameter"); return featureList; } void mitk::GIFVolumetricStatistics::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::String, "Use Volume-Statistic", "calculates volume based features", us::Any()); } void mitk::GIFVolumetricStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) { auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { MITK_INFO << "Start calculating volumetric features ...."; auto localResults = this->CalculateFeatures(feature, mask); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating volumetric features...."; } } diff --git a/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp b/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp index 4a0fcacdaa..bda60124ab 100644 --- a/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp +++ b/Modules/Classification/CLUtilities/src/MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp @@ -1,193 +1,214 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include static bool fileExists(const std::string& filename) { std::ifstream infile(filename.c_str()); bool isGood = infile.good(); infile.close(); return isGood; } void mitk::cl::GlobalImageFeaturesParameter::AddParameter(mitkCommandLineParser &parser) { // Required Parameter parser.addArgument("image", "i", mitkCommandLineParser::InputImage, "Input Image", "Path to the input image file", us::Any(), false); - parser.addArgument("mask", "m", mitkCommandLineParser::InputImage, "Input Mask", "Path to the mask Image that specifies the area over for the statistic (Values = 1)", us::Any(), false); + parser.addArgument("mask", "m", mitkCommandLineParser::InputImage, "Input Mask", "Path to the mask Image that specifies the area over for the statistic (Values = 1)", us::Any(), false); + parser.addArgument("morph-mask", "morph", mitkCommandLineParser::InputImage, "Morphological Image Mask", "Path to the mask Image that specifies the area over for the statistic (Values = 1)", us::Any()); parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output text file", "Path to output file. The output statistic is appended to this file.", us::Any(), false); // Optional Parameter parser.addArgument("logfile", "log", mitkCommandLineParser::InputFile, "Text Logfile", "Path to the location of the target log file. ", us::Any()); parser.addArgument("save-image", "save-image", mitkCommandLineParser::OutputFile, "Output Image", "If spezified, the image that is used for the analysis is saved to this location.", us::Any()); parser.addArgument("save-mask", "save-mask", mitkCommandLineParser::OutputFile, "Output Image", "If spezified, the mask that is used for the analysis is saved to this location. ", us::Any()); parser.addArgument("save-image-screenshots", "save-screenshot", mitkCommandLineParser::OutputFile, "Output Image", "If spezified, a screenshot of each slice is saved. Specify an EXISTING folder with prefix (for example ~/demo/ or ~/demo/image-", us::Any()); parser.addArgument("header", "head", mitkCommandLineParser::Bool, "Add Header (Labels) to output", "", us::Any()); parser.addArgument("first-line-header", "fl-head", mitkCommandLineParser::Bool, "Add Header (Labels) to first line of output", "", us::Any()); + parser.addArgument("decimal-point", "decimal", mitkCommandLineParser::String, "Decima Point that is used in Conversion", "", us::Any()); parser.addArgument("resample-mask", "rm", mitkCommandLineParser::Bool, "Bool", "Resamples the mask to the resolution of the input image ", us::Any()); parser.addArgument("same-space", "sp", mitkCommandLineParser::Bool, "Bool", "Set the spacing of all images to equal. Otherwise an error will be thrown. ", us::Any()); parser.addArgument("fixed-isotropic", "fi", mitkCommandLineParser::Float, "Float", "Input image resampled to fixed isotropic resolution given in mm. Should be used with resample-mask ", us::Any()); parser.addArgument("minimum-intensity", "minimum", mitkCommandLineParser::Float, "Float", "Minimum intensity. If set, it is overwritten by more specific intensity minima", us::Any()); parser.addArgument("maximum-intensity", "maximum", mitkCommandLineParser::Float, "Float", "Maximum intensity. If set, it is overwritten by more specific intensity maxima", us::Any()); parser.addArgument("bins", "bins", mitkCommandLineParser::Int, "Int", "Number of bins if bins are used. If set, it is overwritten by more specific bin count", us::Any()); + parser.addArgument("binsize", "binsize", mitkCommandLineParser::Float, "Int", "Size of bins that is used. If set, it is overwritten by more specific bin count", us::Any()); } void mitk::cl::GlobalImageFeaturesParameter::ParseParameter(std::map parsedArgs) { ParseFileLocations(parsedArgs); ParseAdditionalOutputs(parsedArgs); ParseHeaderInformation(parsedArgs); ParseMaskAdaptation(parsedArgs); ParseGlobalFeatureParameter(parsedArgs); } void mitk::cl::GlobalImageFeaturesParameter::ParseFileLocations(std::map &parsedArgs) { // // Read input and output file informations // imagePath = parsedArgs["image"].ToString(); maskPath = parsedArgs["mask"].ToString(); outputPath = parsedArgs["output"].ToString(); imageFolder = itksys::SystemTools::GetFilenamePath(imagePath); imageName = itksys::SystemTools::GetFilenameName(imagePath); maskFolder = itksys::SystemTools::GetFilenamePath(maskPath); maskName = itksys::SystemTools::GetFilenameName(maskPath); + useMorphMask = false; + if (parsedArgs.count("morph-mask")) + { + useMorphMask = true; + morphPath = parsedArgs["morph-mask"].ToString(); + morphName = itksys::SystemTools::GetFilenameName(morphPath); + } + } void mitk::cl::GlobalImageFeaturesParameter::ParseAdditionalOutputs(std::map &parsedArgs) { // // Read input and output file informations // useLogfile = false; if (parsedArgs.count("logfile")) { useLogfile = true; logfilePath = us::any_cast(parsedArgs["logfile"]); } writeAnalysisImage = false; if (parsedArgs.count("save-image")) { writeAnalysisImage = true; anaylsisImagePath = us::any_cast(parsedArgs["save-image"]); } writeAnalysisMask = false; if (parsedArgs.count("save-mask")) { writeAnalysisMask = true; analysisMaskPath = us::any_cast(parsedArgs["save-mask"]); } writePNGScreenshots = false; if (parsedArgs.count("save-image-screenshots")) { writePNGScreenshots = true; pngScreenshotsPath = us::any_cast(parsedArgs["save-image-screenshots"]); std::string pngScrenshotFolderPath = itksys::SystemTools::GetFilenamePath(pngScreenshotsPath); if (pngScreenshotsPath.back() == '/' || pngScreenshotsPath.back() == '\\') { pngScrenshotFolderPath = pngScreenshotsPath; } itk::FileTools::CreateDirectory(pngScrenshotFolderPath.c_str()); } + useDecimalPoint = false; + if (parsedArgs.count("decimal-point")) + { + auto tmpDecimalPoint = us::any_cast(parsedArgs["decimal-point"]); + if (tmpDecimalPoint.length() > 0) + { + useDecimalPoint = true; + decimalPoint = tmpDecimalPoint.at(0); + } + } } void mitk::cl::GlobalImageFeaturesParameter::ParseHeaderInformation(std::map &parsedArgs) { // // Check if an header is required or not. Consider also first line header option. // useHeader = false; useHeaderForFirstLineOnly = false; if (parsedArgs.count("header")) { useHeader = us::any_cast(parsedArgs["header"]); } if (parsedArgs.count("first-line-header")) { useHeaderForFirstLineOnly = us::any_cast(parsedArgs["first-line-header"]); } if (useHeaderForFirstLineOnly) { useHeader = !fileExists(outputPath); } } void mitk::cl::GlobalImageFeaturesParameter::ParseMaskAdaptation(std::map &parsedArgs) { // // Parse parameters that control how the input mask is adapted to the input image // resampleMask = false; ensureSameSpace = false; resampleToFixIsotropic = false; resampleResolution = 1.0; if (parsedArgs.count("resample-mask")) { resampleMask = us::any_cast(parsedArgs["resample-mask"]); } if (parsedArgs.count("same-space")) { ensureSameSpace = us::any_cast(parsedArgs["same-space"]); } if (parsedArgs.count("fixed-isotropic")) { resampleToFixIsotropic = true; resampleResolution = us::any_cast(parsedArgs["fixed-isotropic"]); } } void mitk::cl::GlobalImageFeaturesParameter::ParseGlobalFeatureParameter(std::map &parsedArgs) { // // Parse parameters that control how the input mask is adapted to the input image // defineGlobalMinimumIntensity = false; defineGlobalMaximumIntensity = false; defineGlobalNumberOfBins = false; if (parsedArgs.count("minimum-intensity")) { defineGlobalMinimumIntensity = true; globalMinimumIntensity = us::any_cast(parsedArgs["minimum-intensity"]); } if (parsedArgs.count("maximum-intensity")) { defineGlobalMaximumIntensity = true; globalMaximumIntensity = us::any_cast(parsedArgs["maximum-intensity"]); } if (parsedArgs.count("bins")) { defineGlobalNumberOfBins = true; globalNumberOfBins = us::any_cast(parsedArgs["bins"]); } } diff --git a/Modules/Classification/CLUtilities/src/mitkCLResultWritter.cpp b/Modules/Classification/CLUtilities/src/mitkCLResultWritter.cpp index b2f44e47de..b2b5fa14e6 100644 --- a/Modules/Classification/CLUtilities/src/mitkCLResultWritter.cpp +++ b/Modules/Classification/CLUtilities/src/mitkCLResultWritter.cpp @@ -1,120 +1,188 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include +#include +#include + +template +class punct_facet : public std::numpunct { +public: + punct_facet(charT sep) : + m_Sep(sep) + { + + } +protected: + charT do_decimal_point() const { return m_Sep; } +private: + charT m_Sep; +}; + mitk::cl::FeatureResultWritter::FeatureResultWritter(std::string file, int mode) : - m_Mode(mode), - m_CurrentRow(0), - m_CurrentElement(0), - m_Separator(";") +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) + 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) + 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) + 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 (withDescription) - { - AddColumn(desc); - } - if (slice >= 0) + if (m_Mode == 2) { - AddColumn(slice); + 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(stats[i].second); + NewRow(""); + ++m_CurrentElement; + } + m_UsedSubjectInformation = true; } - for (std::size_t i = 0; i < stats.size(); ++i) + else { - AddColumn(stats[i].second); + 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; } - 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); } NewRow("EndOfMeasurement"); } } \ No newline at end of file diff --git a/Modules/ModuleList.cmake b/Modules/ModuleList.cmake index 3197835d83..e5d3f654ab 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,82 +1,82 @@ # The entries in the mitk_modules list must be # ordered according to their dependencies. set(mitk_modules Core CommandLine AppUtil DCMTesting RDF LegacyIO DataTypesExt Annotation LegacyGL AlgorithmsExt MapperExt DICOMReader DICOMReaderServices DICOMTesting SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction SceneSerialization Gizmo GraphAlgorithms Multilabel ImageStatistics ContourModel SurfaceInterpolation Segmentation PlanarFigureSegmentation OpenViewCore QtWidgets QtWidgetsExt Chart QmlItems SegmentationUI + MatchPointRegistration + MatchPointRegistrationUI Classification DiffusionImaging GPGPU OpenIGTLink IGTBase IGT CameraCalibration OpenCL OpenCVVideoSupport QtOverlays ToFHardware ToFProcessing ToFUI PhotoacousticsHardware PhotoacousticsAlgorithms US USUI DicomUI Simulation Remeshing Python QtPython Persistence OpenIGTLinkUI IGTUI VtkShaders DicomRT RTUI IOExt XNAT TubeGraph BiophotonicsHardware TumorInvasionAnalysis - MatchPointRegistration - MatchPointRegistrationUI BoundingShape RenderWindowManager RenderWindowManagerUI CEST DICOMQI ) if(MITK_ENABLE_PIC_READER) list(APPEND mitk_modules IpPicSupportIO) endif() diff --git a/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingView.cpp b/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingView.cpp index 749a3e3081..cd11230654 100644 --- a/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingView.cpp +++ b/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingView.cpp @@ -1,413 +1,416 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkPreprocessingResamplingView.h" // QT includes (GUI) #include #include #include #include #include #include #include // Berry includes (selection service) #include #include // MITK includes (GUI) #include "QmitkStdMultiWidget.h" #include "QmitkDataNodeSelectionProvider.h" #include "mitkDataNodeObject.h" // MITK includes (general) #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateDimension.h" #include "mitkNodePredicateAnd.h" #include "mitkImageTimeSelector.h" #include "mitkVectorImageMapper2D.h" #include "mitkProperties.h" // Includes for image casting between ITK and MITK #include "mitkImageCast.h" #include "mitkITKImageImport.h" // ITK includes (general) #include #include // Resampling #include #include #include #include #include #include #include +// STD +#include + // Convenient Definitions -typedef itk::Image ImageType; +typedef itk::Image ImageType; typedef itk::Image SegmentationImageType; typedef itk::Image DoubleImageType; typedef itk::Image, 3> VectorImageType; typedef itk::ResampleImageFilter< ImageType, ImageType > ResampleImageFilterType; typedef itk::ResampleImageFilter< ImageType, ImageType > ResampleImageFilterType2; typedef itk::CastImageFilter< ImageType, DoubleImageType > ImagePTypeToFloatPTypeCasterType; typedef itk::LinearInterpolateImageFunction< ImageType, double > LinearInterpolatorType; typedef itk::NearestNeighborInterpolateImageFunction< ImageType, double > NearestInterpolatorType; typedef itk::BSplineInterpolateImageFunction BSplineInterpolatorType; QmitkPreprocessingResampling::QmitkPreprocessingResampling() : QmitkAbstractView(), m_Controls(NULL), m_SelectedImageNode(NULL), m_TimeStepperAdapter(NULL) { } QmitkPreprocessingResampling::~QmitkPreprocessingResampling() { } void QmitkPreprocessingResampling::CreateQtPartControl(QWidget *parent) { if (m_Controls == NULL) { m_Controls = new Ui::QmitkPreprocessingResamplingViewControls; m_Controls->setupUi(parent); this->CreateConnections(); mitk::NodePredicateDimension::Pointer dimensionPredicate = mitk::NodePredicateDimension::New(3); mitk::NodePredicateDataType::Pointer imagePredicate = mitk::NodePredicateDataType::New("Image"); } m_SelectedImageNode = mitk::DataStorageSelection::New(this->GetDataStorage(), false); // Setup Controls this->m_Controls->cbParam4->clear(); this->m_Controls->cbParam4->insertItem(LINEAR, "Linear"); this->m_Controls->cbParam4->insertItem(NEAREST, "Nearest neighbor"); this->m_Controls->cbParam4->insertItem(SPLINE, "B-Spline"); } void QmitkPreprocessingResampling::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->btnDoIt), SIGNAL(clicked()),(QObject*) this, SLOT(StartButtonClicked())); connect( (QObject*)(m_Controls->cbParam4), SIGNAL( activated(int) ), this, SLOT( SelectInterpolator(int) ) ); } } void QmitkPreprocessingResampling::InternalGetTimeNavigationController() { auto renwin_part = GetRenderWindowPart(); if( renwin_part != nullptr ) { auto tnc = renwin_part->GetTimeNavigationController(); if( tnc != nullptr ) { m_TimeStepperAdapter = new QmitkStepperAdapter((QObject*) m_Controls->sliceNavigatorTime, tnc->GetTime(), "sliceNavigatorTimeFromBIP"); } } } void QmitkPreprocessingResampling::SetFocus() { } //datamanager selection changed void QmitkPreprocessingResampling::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) { ResetOneImageOpPanel(); //any nodes there? if (!nodes.empty()) { // reset GUI m_Controls->sliceNavigatorTime->setEnabled(false); m_Controls->leImage1->setText(tr("Select an Image in Data Manager")); m_SelectedImageNode->RemoveAllNodes(); //get the selected Node mitk::DataNode* _DataNode = nodes.front(); *m_SelectedImageNode = _DataNode; //try to cast to image mitk::Image::Pointer tempImage = dynamic_cast(m_SelectedImageNode->GetNode()->GetData()); //no image if( tempImage.IsNull() || (tempImage->IsInitialized() == false) ) { m_Controls->leImage1->setText(tr("Not an image.")); return; } //2D image if( tempImage->GetDimension() < 3) { m_Controls->leImage1->setText(tr("2D images are not supported.")); return; } //image m_Controls->leImage1->setText(QString(m_SelectedImageNode->GetNode()->GetName().c_str())); mitk::Vector3D aSpacing = tempImage->GetGeometry()->GetSpacing(); std::string text("x-spacing (" + std::to_string(aSpacing[0]) + ")"); m_Controls->tlParam1->setText(text.c_str()); text = "y-spacing (" + std::to_string(aSpacing[1]) + ")"; m_Controls->tlParam2->setText(text.c_str()); text = "z-spacing (" + std::to_string(aSpacing[2]) + ")"; m_Controls->tlParam3->setText(text.c_str()); MITK_INFO << "Spacing of current Image : " << aSpacing; // m_Controls->tlParam1->setText("y-spacing"); // m_Controls->tlParam1->setText("z-spacing"); // button coding if ( tempImage->GetDimension() > 3 ) { // try to retrieve the TNC (for 4-D Processing ) this->InternalGetTimeNavigationController(); m_Controls->sliceNavigatorTime->setEnabled(true); m_Controls->tlTime->setEnabled(true); } ResetParameterPanel(); } } void QmitkPreprocessingResampling::ResetOneImageOpPanel() { m_Controls->tlTime->setEnabled(false); m_Controls->btnDoIt->setEnabled(false); m_Controls->cbHideOrig->setEnabled(false); m_Controls->leImage1->setText(tr("Select an Image in Data Manager")); m_Controls->tlParam1->setText("x-spacing"); m_Controls->tlParam1->setText("y-spacing"); m_Controls->tlParam1->setText("z-spacing"); } void QmitkPreprocessingResampling::ResetParameterPanel() { m_Controls->btnDoIt->setEnabled(true); m_Controls->cbHideOrig->setEnabled(true); } void QmitkPreprocessingResampling::ResetTwoImageOpPanel() { } void QmitkPreprocessingResampling::StartButtonClicked() { if(!m_SelectedImageNode->GetNode()) return; this->BusyCursorOn(); mitk::Image::Pointer newImage; try { newImage = dynamic_cast(m_SelectedImageNode->GetNode()->GetData()); } catch ( std::exception &e ) { QString exceptionString = tr("An error occured during image loading:\n"); exceptionString.append( e.what() ); QMessageBox::warning( NULL, "Preprocessing - Resampling: ", exceptionString , QMessageBox::Ok, QMessageBox::NoButton ); this->BusyCursorOff(); return; } // check if input image is valid, casting does not throw exception when casting from 'NULL-Object' if ( (! newImage) || (newImage->IsInitialized() == false) ) { this->BusyCursorOff(); QMessageBox::warning( NULL, "Preprocessing - Resampling", tr("Input image is broken or not initialized. Returning."), QMessageBox::Ok, QMessageBox::NoButton ); return; } // check if operation is done on 4D a image time step if(newImage->GetDimension() > 3) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(newImage); timeSelector->SetTimeNr( ((QmitkSliderNavigatorWidget*)m_Controls->sliceNavigatorTime)->GetPos() ); timeSelector->Update(); newImage = timeSelector->GetOutput(); } // check if image or vector image ImageType::Pointer itkImage = ImageType::New(); VectorImageType::Pointer itkVecImage = VectorImageType::New(); int isVectorImage = newImage->GetPixelType().GetNumberOfComponents(); if(isVectorImage > 1) { CastToItkImage( newImage, itkVecImage ); } else { CastToItkImage( newImage, itkImage ); } std::stringstream nameAddition(""); double dparam1 = m_Controls->dsbParam1->value(); double dparam2 = m_Controls->dsbParam2->value(); double dparam3 = m_Controls->dsbParam3->value(); try{ std::string selectedInterpolator; ResampleImageFilterType::Pointer resampler = ResampleImageFilterType::New(); switch (m_SelectedInterpolation) { case LINEAR: { LinearInterpolatorType::Pointer interpolator = LinearInterpolatorType::New(); resampler->SetInterpolator(interpolator); selectedInterpolator = "Linear"; break; } case NEAREST: { NearestInterpolatorType::Pointer interpolator = NearestInterpolatorType::New(); resampler->SetInterpolator(interpolator); selectedInterpolator = "Nearest"; break; } case SPLINE: { BSplineInterpolatorType::Pointer interpolator = BSplineInterpolatorType::New(); interpolator->SetSplineOrder(3); resampler->SetInterpolator(interpolator); selectedInterpolator = "B-Spline"; break; } default: { LinearInterpolatorType::Pointer interpolator = LinearInterpolatorType::New(); resampler->SetInterpolator(interpolator); selectedInterpolator = "Linear"; break; } } resampler->SetInput( itkImage ); resampler->SetOutputOrigin( itkImage->GetOrigin() ); ImageType::SizeType input_size = itkImage->GetLargestPossibleRegion().GetSize(); ImageType::SpacingType input_spacing = itkImage->GetSpacing(); ImageType::SizeType output_size; ImageType::SpacingType output_spacing; - output_size[0] = input_size[0] * (input_spacing[0] / dparam1); - output_size[1] = input_size[1] * (input_spacing[1] / dparam2); - output_size[2] = input_size[2] * (input_spacing[2] / dparam3); + output_size[0] = std::ceil(input_size[0] * (input_spacing[0] / dparam1)); + output_size[1] = std::ceil(input_size[1] * (input_spacing[1] / dparam2)); + output_size[2] = std::ceil(input_size[2] * (input_spacing[2] / dparam3)); output_spacing [0] = dparam1; output_spacing [1] = dparam2; output_spacing [2] = dparam3; resampler->SetSize( output_size ); resampler->SetOutputSpacing( output_spacing ); resampler->SetOutputDirection( itkImage->GetDirection() ); resampler->UpdateLargestPossibleRegion(); ImageType::Pointer resampledImage = resampler->GetOutput(); newImage = mitk::ImportItkImage( resampledImage )->Clone(); nameAddition << "_Resampled_" << selectedInterpolator; std::cout << "Resampling successful." << std::endl; } catch (...) { this->BusyCursorOff(); QMessageBox::warning(NULL, "Warning", "Problem when applying filter operation. Check your input..."); return; } newImage->DisconnectPipeline(); // adjust level/window to new image mitk::LevelWindow levelwindow; levelwindow.SetAuto( newImage ); mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); levWinProp->SetLevelWindow( levelwindow ); // compose new image name std::string name = m_SelectedImageNode->GetNode()->GetName(); if (name.find(".pic.gz") == name.size() -7 ) { name = name.substr(0,name.size() -7); } name.append( nameAddition.str() ); // create final result MITK data storage node mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty( "levelwindow", levWinProp ); result->SetProperty( "name", mitk::StringProperty::New( name.c_str() ) ); result->SetData( newImage ); // for vector images, a different mapper is needed if(isVectorImage > 1) { mitk::VectorImageMapper2D::Pointer mapper = mitk::VectorImageMapper2D::New(); result->SetMapper(1,mapper); } // reset GUI to ease further processing // this->ResetOneImageOpPanel(); // add new image to data storage and set as active to ease further processing GetDataStorage()->Add( result, m_SelectedImageNode->GetNode() ); if ( m_Controls->cbHideOrig->isChecked() == true ) m_SelectedImageNode->GetNode()->SetProperty( "visible", mitk::BoolProperty::New(false) ); // TODO!! m_Controls->m_ImageSelector1->SetSelectedNode(result); // show the results mitk::RenderingManager::GetInstance()->RequestUpdateAll(); this->BusyCursorOff(); } void QmitkPreprocessingResampling::SelectInterpolator(int interpolator) { switch (interpolator) { case 0: { m_SelectedInterpolation = LINEAR; break; } case 1: { m_SelectedInterpolation = NEAREST; break; } case 2: { m_SelectedInterpolation = SPLINE; } } }