diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp index 16d47c6c19..e64aee3fb4 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp @@ -1,708 +1,702 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include // ITK #include #include #include // STL #include #include namespace mitk { struct GIFCooccurenceMatrix2Configuration { double range; unsigned int direction; double MinimumIntensity; double MaximumIntensity; int Bins; FeatureID id; }; struct CoocurenceMatrixHolder { public: CoocurenceMatrixHolder(double min, double max, int number); int IntensityToIndex(double intensity); double IndexToMinIntensity(int index); double IndexToMeanIntensity(int index); double IndexToMaxIntensity(int index); double m_MinimumRange; double m_MaximumRange; double m_Stepsize; int m_NumberOfBins; Eigen::MatrixXd m_Matrix; }; struct CoocurenceMatrixFeatures { CoocurenceMatrixFeatures() : JointMaximum(0), JointAverage(0), JointVariance(0), JointEntropy(0), RowMaximum(0), RowAverage(0), RowVariance(0), RowEntropy(0), FirstRowColumnEntropy(0), SecondRowColumnEntropy(0), DifferenceAverage(0), DifferenceVariance(0), DifferenceEntropy(0), SumAverage(0), SumVariance(0), SumEntropy(0), AngularSecondMoment(0), Contrast(0), Dissimilarity(0), InverseDifference(0), InverseDifferenceNormalised(0), InverseDifferenceMoment(0), InverseDifferenceMomentNormalised(0), InverseVariance(0), Correlation(0), Autocorrelation(0), ClusterTendency(0), ClusterShade(0), ClusterProminence(0), FirstMeasureOfInformationCorrelation(0), SecondMeasureOfInformationCorrelation(0) { } public: double JointMaximum; double JointAverage; double JointVariance; double JointEntropy; double RowMaximum; double RowAverage; double RowVariance; double RowEntropy; double FirstRowColumnEntropy; double SecondRowColumnEntropy; double DifferenceAverage; double DifferenceVariance; double DifferenceEntropy; double SumAverage; double SumVariance; double SumEntropy; double AngularSecondMoment; double Contrast; double Dissimilarity; double InverseDifference; double InverseDifferenceNormalised; double InverseDifferenceMoment; double InverseDifferenceMomentNormalised; double InverseVariance; double Correlation; double Autocorrelation; double ClusterTendency; double ClusterShade; double ClusterProminence; double FirstMeasureOfInformationCorrelation; double SecondMeasureOfInformationCorrelation; }; } + static void MatrixFeaturesTo(const mitk::CoocurenceMatrixFeatures& features, - const std::string& prefix, - const mitk::GIFCooccurenceMatrix2Configuration& config, - mitk::GIFCooccurenceMatrix2::FeatureListType &featureList); + const std::string& prefix, + const mitk::GIFCooccurenceMatrix2Configuration& config, + mitk::GIFCooccurenceMatrix2::FeatureListType& featureList) +{ + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Joint Maximum"), features.JointMaximum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Joint Average"), features.JointAverage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Joint Variance"), features.JointVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Joint Entropy"), features.JointEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Difference Average"), features.DifferenceAverage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Difference Variance"), features.DifferenceVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Difference Entropy"), features.DifferenceEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Sum Average"), features.SumAverage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Sum Variance"), features.SumVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Sum Entropy"), features.SumEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Angular Second Moment"), features.AngularSecondMoment)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Contrast"), features.Contrast)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Dissimilarity"), features.Dissimilarity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Difference"), features.InverseDifference)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Difference Normalized"), features.InverseDifferenceNormalised)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Difference Moment"), features.InverseDifferenceMoment)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Difference Moment Normalized"), features.InverseDifferenceMomentNormalised)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Variance"), features.InverseVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Correlation"), features.Correlation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Autocorrelation"), features.Autocorrelation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Cluster Tendency"), features.ClusterTendency)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Cluster Shade"), features.ClusterShade)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Cluster Prominence"), features.ClusterProminence)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "First Measure of Information Correlation"), features.FirstMeasureOfInformationCorrelation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Second Measure of Information Correlation"), features.SecondMeasureOfInformationCorrelation)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Row Maximum"), features.RowMaximum)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Row Average"), features.RowAverage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Row Variance"), features.RowVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Row Entropy"), features.RowEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "First Row-Column Entropy"), features.FirstRowColumnEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Second Row-Column Entropy"), features.SecondRowColumnEntropy)); +} + + static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature); static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number); - - mitk::CoocurenceMatrixHolder::CoocurenceMatrixHolder(double min, double max, int number) : m_MinimumRange(min), m_MaximumRange(max), m_NumberOfBins(number) { m_Matrix.resize(number, number); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::CoocurenceMatrixHolder::IntensityToIndex(double intensity) { int index = std::floor((intensity - m_MinimumRange) / m_Stepsize); return std::max(0, std::min(index, m_NumberOfBins - 1)); } double mitk::CoocurenceMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template void CalculateCoOcMatrix(const itk::Image* itkImage, const itk::Image* mask, itk::Offset offset, int range, mitk::CoocurenceMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef itk::ShapedNeighborhoodIterator ShapeIterType; typedef itk::ShapedNeighborhoodIterator ShapeMaskIterType; typedef itk::ImageRegionConstIterator ConstIterType; typedef itk::ImageRegionConstIterator ConstMaskIterType; itk::Size radius; radius.Fill(range+1); ShapeIterType imageOffsetIter(radius, itkImage, itkImage->GetLargestPossibleRegion()); ShapeMaskIterType maskOffsetIter(radius, mask, mask->GetLargestPossibleRegion()); imageOffsetIter.ActivateOffset(offset); maskOffsetIter.ActivateOffset(offset); ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); // iterator.GetIndex() + ci.GetNeighborhoodOffset() auto region = mask->GetLargestPossibleRegion(); while (!maskIter.IsAtEnd()) { auto ciMask = maskOffsetIter.Begin(); auto ciValue = imageOffsetIter.Begin(); if (maskIter.Value() > 0 && ciMask.Get() > 0 && imageIter.Get() == imageIter.Get() && ciValue.Get() == ciValue.Get() && region.IsInside(maskOffsetIter.GetIndex() + ciMask.GetNeighborhoodOffset())) { int i = holder.IntensityToIndex(imageIter.Get()); int j = holder.IntensityToIndex(ciValue.Get()); holder.m_Matrix(i, j) += 1; holder.m_Matrix(j, i) += 1; } ++imageOffsetIter; ++maskOffsetIter; ++imageIter; ++maskIter; } } void CalculateFeatures( mitk::CoocurenceMatrixHolder &holder, mitk::CoocurenceMatrixFeatures & results ) { auto pijMatrix = holder.m_Matrix; auto piMatrix = holder.m_Matrix; auto pjMatrix = holder.m_Matrix; double Ng = holder.m_NumberOfBins; int NgSize = holder.m_NumberOfBins; pijMatrix /= pijMatrix.sum(); piMatrix.rowwise().normalize(); pjMatrix.colwise().normalize(); for (int i = 0; i < holder.m_NumberOfBins; ++i) for (int j = 0; j < holder.m_NumberOfBins; ++j) { if (pijMatrix(i, j) != pijMatrix(i, j)) pijMatrix(i, j) = 0; if (piMatrix(i, j) != piMatrix(i, j)) piMatrix(i, j) = 0; if (pjMatrix(i, j) != pjMatrix(i, j)) pjMatrix(i, j) = 0; } Eigen::VectorXd piVector = pijMatrix.colwise().sum(); Eigen::VectorXd pjVector = pijMatrix.rowwise().sum(); double sigmai = 0;; for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1;// holder.IndexToMeanIntensity(i); results.RowAverage += iInt * piVector(i); if (piVector(i) > 0) { results.RowEntropy -= piVector(i) * std::log(piVector(i)) / std::log(2); } } for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1; // holder.IndexToMeanIntensity(i); results.RowVariance += (iInt - results.RowAverage)*(iInt - results.RowAverage) * piVector(i); } results.RowMaximum = piVector.maxCoeff(); sigmai = std::sqrt(results.RowVariance); Eigen::VectorXd pimj(NgSize); pimj.fill(0); Eigen::VectorXd pipj(2*NgSize); pipj.fill(0); results.JointMaximum += pijMatrix.maxCoeff(); for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1;// holder.IndexToMeanIntensity(i); double jInt = j + 1;// holder.IndexToMeanIntensity(j); double pij = pijMatrix(i, j); int deltaK = (i - j)>0?(i-j) : (j-i); pimj(deltaK) += pij; pipj(i + j) += pij; results.JointAverage += iInt * pij; if (pij > 0) { results.JointEntropy -= pij * std::log(pij) / std::log(2); results.FirstRowColumnEntropy -= pij * std::log(piVector(i)*pjVector(j)) / std::log(2); } if (piVector(i) > 0 && pjVector(j) > 0 ) { results.SecondRowColumnEntropy -= piVector(i)*pjVector(j) * std::log(piVector(i)*pjVector(j)) / std::log(2); } results.AngularSecondMoment += pij*pij; results.Contrast += (iInt - jInt)* (iInt - jInt) * pij; results.Dissimilarity += std::abs(iInt - jInt) * pij; results.InverseDifference += pij / (1 + (std::abs(iInt - jInt))); results.InverseDifferenceNormalised += pij / (1 + (std::abs(iInt - jInt) / Ng)); results.InverseDifferenceMoment += pij / (1 + (iInt - jInt)*(iInt - jInt)); results.InverseDifferenceMomentNormalised += pij / (1 + (iInt - jInt)*(iInt - jInt)/Ng/Ng); results.Autocorrelation += iInt*jInt * pij; double cluster = (iInt + jInt - 2 * results.RowAverage); results.ClusterTendency += cluster*cluster * pij; results.ClusterShade += cluster*cluster*cluster * pij; results.ClusterProminence += cluster*cluster*cluster*cluster * pij; if (iInt != jInt) { results.InverseVariance += pij / (iInt - jInt) / (iInt - jInt); } } } results.Correlation = 1 / sigmai / sigmai * (-results.RowAverage*results.RowAverage+ results.Autocorrelation); results.FirstMeasureOfInformationCorrelation = (results.JointEntropy - results.FirstRowColumnEntropy) / results.RowEntropy; if (results.JointEntropy < results.SecondRowColumnEntropy) { results.SecondMeasureOfInformationCorrelation = sqrt(1 - exp(-2 * (results.SecondRowColumnEntropy - results.JointEntropy))); } else { results.SecondMeasureOfInformationCorrelation = 0; } for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1; double pij = pijMatrix(i, j); results.JointVariance += (iInt - results.JointAverage)* (iInt - results.JointAverage)*pij; } } for (int k = 0; k < NgSize; ++k) { results.DifferenceAverage += k* pimj(k); if (pimj(k) > 0) { results.DifferenceEntropy -= pimj(k) * log(pimj(k)) / std::log(2); } } for (int k = 0; k < NgSize; ++k) { results.DifferenceVariance += (results.DifferenceAverage-k)* (results.DifferenceAverage-k)*pimj(k); } for (int k = 0; k <2* NgSize ; ++k) { results.SumAverage += (2+k)* pipj(k); if (pipj(k) > 0) { results.SumEntropy -= pipj(k) * log(pipj(k)) / std::log(2); } } for (int k = 0; k < 2*NgSize; ++k) { results.SumVariance += (2+k - results.SumAverage)* (2+k - results.SumAverage)*pipj(k); } //MITK_INFO << std::endl << holder.m_Matrix; //MITK_INFO << std::endl << pijMatrix; //MITK_INFO << std::endl << piMatrix; //MITK_INFO << std::endl << pjMatrix; //for (int i = 0; i < holder.m_NumberOfBins; ++i) //{ // MITK_INFO << "Bin " << i << " Min: " << holder.IndexToMinIntensity(i) << " Max: " << holder.IndexToMaxIntensity(i); //} //MITK_INFO << pimj; //MITK_INFO << pipj; } template void CalculateCoocurenceFeatures(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFCooccurenceMatrix2::FeatureListType & featureList, mitk::GIFCooccurenceMatrix2Configuration config) { typedef itk::Image MaskType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// double rangeMin = config.MinimumIntensity; double rangeMax = config.MaximumIntensity; int numberOfBins = config.Bins; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); //Find possible directions std::vector < itk::Offset > offsetVector; NeighborhoodType hood; hood.SetRadius(1); unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetType offset; for (unsigned int d = 0; d < centerIndex; d++) { offset = hood.GetOffset(d); bool useOffset = true; for (unsigned int i = 0; i < VImageDimension; ++i) { offset[i] *= config.range; if (config.direction == i + 2 && offset[i] != 0) { useOffset = false; } } if (useOffset) { offsetVector.push_back(offset); } } if (config.direction == 1) { offsetVector.clear(); offset[0] = 0; offset[1] = 0; offset[2] = 1; } std::vector resultVector; mitk::CoocurenceMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures overallFeature; for (std::size_t i = 0; i < offsetVector.size(); ++i) { if (config.direction > 1) { if (offsetVector[i][config.direction - 2] != 0) { continue; } } offset = offsetVector[i]; mitk::CoocurenceMatrixHolder holder(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures coocResults; CalculateCoOcMatrix(itkImage, maskImage, offset, config.range, holder); holderOverall.m_Matrix += holder.m_Matrix; CalculateFeatures(holder, coocResults); resultVector.push_back(coocResults); } CalculateFeatures(holderOverall, overallFeature); //NormalizeMatrixFeature(overallFeature, offsetVector.size()); mitk::CoocurenceMatrixFeatures featureMean; mitk::CoocurenceMatrixFeatures featureStd; CalculateMeanAndStdDevFeatures(resultVector, featureMean, featureStd); std::ostringstream ss; ss << config.range; std::string strRange = ss.str(); MatrixFeaturesTo(overallFeature, "Overall ", config, featureList); MatrixFeaturesTo(featureMean, "Mean ", config, featureList); MatrixFeaturesTo(featureStd, "Std.Dev. ", config, featureList); } - -static -void MatrixFeaturesTo(const mitk::CoocurenceMatrixFeatures& features, - const std::string& prefix, - const mitk::GIFCooccurenceMatrix2Configuration& config, - mitk::GIFCooccurenceMatrix2::FeatureListType &featureList) -{ - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Joint Maximum"), features.JointMaximum)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Joint Average"), features.JointAverage)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Joint Variance"), features.JointVariance)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Joint Entropy"), features.JointEntropy)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Difference Average"), features.DifferenceAverage)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Difference Variance"), features.DifferenceVariance)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Difference Entropy"), features.DifferenceEntropy)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Sum Average"), features.SumAverage)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Sum Variance"), features.SumVariance)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Sum Entropy"), features.SumEntropy)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Angular Second Moment"), features.AngularSecondMoment)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Contrast"), features.Contrast)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Dissimilarity"), features.Dissimilarity)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Difference"), features.InverseDifference)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Difference Normalized"), features.InverseDifferenceNormalised)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Difference Moment"), features.InverseDifferenceMoment)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Difference Moment Normalized"), features.InverseDifferenceMomentNormalised)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Inverse Variance"), features.InverseVariance)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Correlation"), features.Correlation)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Autocorrelation"), features.Autocorrelation)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Cluster Tendency"), features.ClusterTendency)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Cluster Shade"), features.ClusterShade)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Cluster Prominence"), features.ClusterProminence)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "First Measure of Information Correlation"), features.FirstMeasureOfInformationCorrelation)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Second Measure of Information Correlation"), features.SecondMeasureOfInformationCorrelation)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Row Maximum"), features.RowMaximum)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Row Average"), features.RowAverage)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Row Variance"), features.RowVariance)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Row Entropy"), features.RowEntropy)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "First Row-Column Entropy"), features.FirstRowColumnEntropy)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, prefix + "Second Row-Column Entropy"), features.SecondRowColumnEntropy)); -} - static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature) { #define ADDFEATURE(a) \ if ( ! (featureList[i].a == featureList[i].a)) featureList[i].a = 0; \ meanFeature.a += featureList[i].a;stdFeature.a += featureList[i].a*featureList[i].a #define CALCVARIANCE(a) stdFeature.a =sqrt(stdFeature.a - meanFeature.a*meanFeature.a) for (std::size_t i = 0; i < featureList.size(); ++i) { ADDFEATURE(JointMaximum); ADDFEATURE(JointAverage); ADDFEATURE(JointVariance); ADDFEATURE(JointEntropy); ADDFEATURE(RowMaximum); ADDFEATURE(RowAverage); ADDFEATURE(RowVariance); ADDFEATURE(RowEntropy); ADDFEATURE(FirstRowColumnEntropy); ADDFEATURE(SecondRowColumnEntropy); ADDFEATURE(DifferenceAverage); ADDFEATURE(DifferenceVariance); ADDFEATURE(DifferenceEntropy); ADDFEATURE(SumAverage); ADDFEATURE(SumVariance); ADDFEATURE(SumEntropy); ADDFEATURE(AngularSecondMoment); ADDFEATURE(Contrast); ADDFEATURE(Dissimilarity); ADDFEATURE(InverseDifference); ADDFEATURE(InverseDifferenceNormalised); ADDFEATURE(InverseDifferenceMoment); ADDFEATURE(InverseDifferenceMomentNormalised); ADDFEATURE(InverseVariance); ADDFEATURE(Correlation); ADDFEATURE(Autocorrelation); ADDFEATURE(ClusterShade); ADDFEATURE(ClusterTendency); ADDFEATURE(ClusterProminence); ADDFEATURE(FirstMeasureOfInformationCorrelation); ADDFEATURE(SecondMeasureOfInformationCorrelation); } NormalizeMatrixFeature(meanFeature, featureList.size()); NormalizeMatrixFeature(stdFeature, featureList.size()); CALCVARIANCE(JointMaximum); CALCVARIANCE(JointAverage); CALCVARIANCE(JointVariance); CALCVARIANCE(JointEntropy); CALCVARIANCE(RowMaximum); CALCVARIANCE(RowAverage); CALCVARIANCE(RowVariance); CALCVARIANCE(RowEntropy); CALCVARIANCE(FirstRowColumnEntropy); CALCVARIANCE(SecondRowColumnEntropy); CALCVARIANCE(DifferenceAverage); CALCVARIANCE(DifferenceVariance); CALCVARIANCE(DifferenceEntropy); CALCVARIANCE(SumAverage); CALCVARIANCE(SumVariance); CALCVARIANCE(SumEntropy); CALCVARIANCE(AngularSecondMoment); CALCVARIANCE(Contrast); CALCVARIANCE(Dissimilarity); CALCVARIANCE(InverseDifference); CALCVARIANCE(InverseDifferenceNormalised); CALCVARIANCE(InverseDifferenceMoment); CALCVARIANCE(InverseDifferenceMomentNormalised); CALCVARIANCE(InverseVariance); CALCVARIANCE(Correlation); CALCVARIANCE(Autocorrelation); CALCVARIANCE(ClusterShade); CALCVARIANCE(ClusterTendency); CALCVARIANCE(ClusterProminence); CALCVARIANCE(FirstMeasureOfInformationCorrelation); CALCVARIANCE(SecondMeasureOfInformationCorrelation); #undef ADDFEATURE #undef CALCVARIANCE } static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number) { features.JointMaximum = features.JointMaximum / number; features.JointAverage = features.JointAverage / number; features.JointVariance = features.JointVariance / number; features.JointEntropy = features.JointEntropy / number; features.RowMaximum = features.RowMaximum / number; features.RowAverage = features.RowAverage / number; features.RowVariance = features.RowVariance / number; features.RowEntropy = features.RowEntropy / number; features.FirstRowColumnEntropy = features.FirstRowColumnEntropy / number; features.SecondRowColumnEntropy = features.SecondRowColumnEntropy / number; features.DifferenceAverage = features.DifferenceAverage / number; features.DifferenceVariance = features.DifferenceVariance / number; features.DifferenceEntropy = features.DifferenceEntropy / number; features.SumAverage = features.SumAverage / number; features.SumVariance = features.SumVariance / number; features.SumEntropy = features.SumEntropy / number; features.AngularSecondMoment = features.AngularSecondMoment / number; features.Contrast = features.Contrast / number; features.Dissimilarity = features.Dissimilarity / number; features.InverseDifference = features.InverseDifference / number; features.InverseDifferenceNormalised = features.InverseDifferenceNormalised / number; features.InverseDifferenceMoment = features.InverseDifferenceMoment / number; features.InverseDifferenceMomentNormalised = features.InverseDifferenceMomentNormalised / number; features.InverseVariance = features.InverseVariance / number; features.Correlation = features.Correlation / number; features.Autocorrelation = features.Autocorrelation / number; features.ClusterShade = features.ClusterShade / number; features.ClusterTendency = features.ClusterTendency / number; features.ClusterProminence = features.ClusterProminence / number; features.FirstMeasureOfInformationCorrelation = features.FirstMeasureOfInformationCorrelation / number; features.SecondMeasureOfInformationCorrelation = features.SecondMeasureOfInformationCorrelation / number; } mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2(): m_Ranges({ 1.0 }) { SetShortName("cooc2"); SetLongName("cooccurence2"); SetFeatureClassName("Co-occurenced Based Features"); } void mitk::GIFCooccurenceMatrix2::SetRanges(std::vector ranges) { m_Ranges = ranges; this->Modified(); } void mitk::GIFCooccurenceMatrix2::SetRange(double range) { m_Ranges.resize(1); m_Ranges[0] = range; this->Modified(); } mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFCooccurenceMatrix2::DoCalculateFeatures(const Image* image, const Image* mask) { FeatureListType featureList; InitializeQuantifier(image, mask); for (const auto& range: m_Ranges) { MITK_INFO << "Start calculating coocurence with range " << range << "...."; GIFCooccurenceMatrix2Configuration config; config.direction = GetDirection(); config.range = range; config.MinimumIntensity = GetQuantifier()->GetMinimum(); config.MaximumIntensity = GetQuantifier()->GetMaximum(); config.Bins = GetQuantifier()->GetBins(); config.id = this->CreateTemplateFeatureID(std::to_string(range), { {GetOptionPrefix() + "::range", range} }); AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList, config); MITK_INFO << "Finished calculating coocurence with range " << range << "...."; } return featureList; } mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFCooccurenceMatrix2::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { return Superclass::CalculateFeatures(image, maskNoNAN); } void mitk::GIFCooccurenceMatrix2::AddArguments(mitkCommandLineParser &parser) const { this->AddQuantifierArguments(parser); std::string name = this->GetOptionPrefix(); parser.addArgument(this->GetLongName(), name, mitkCommandLineParser::Bool, "Use Co-occurence matrix", "calculates Co-occurence based features (new implementation)", us::Any()); parser.addArgument(name+"::range", name+"::range", mitkCommandLineParser::String, "Cooc 2 Range", "Define the range that is used (Semicolon-separated)", us::Any()); } std::string mitk::GIFCooccurenceMatrix2::GenerateLegacyFeatureEncoding(const FeatureID& id) const { return QuantifierParameterString() + "_Range-" + id.parameters.at(this->GetOptionPrefix()+"::range").ToString(); } void mitk::GIFCooccurenceMatrix2::ConfigureSettingsByParameters(const ParametersType& parameters) { auto name = GetOptionPrefix()+"::range"; if (parameters.count(name)) { m_Ranges = SplitDouble(parameters.at(name).ToString(), ';'); } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp index f79a243301..c6c069473f 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp @@ -1,475 +1,467 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include #include #include // ITK #include #include #include #include #include namespace mitk{ struct GreyLevelDistanceZoneConfiguration { mitk::Image::Pointer distanceMask; mitk::IntensityQuantifier::Pointer Quantifier; unsigned int direction; double MinimumIntensity; double MaximumIntensity; int Bins; FeatureID id; }; struct GreyLevelDistanceZoneMatrixHolder { public: GreyLevelDistanceZoneMatrixHolder(mitk::IntensityQuantifier::Pointer quantifier, int number, int maxSize); int IntensityToIndex(double intensity); int m_NumberOfBins; int m_MaximumSize; int m_NumerOfVoxels; Eigen::MatrixXd m_Matrix; mitk::IntensityQuantifier::Pointer m_Quantifier; }; } static -void MatrixFeaturesTo(mitk::GreyLevelDistanceZoneFeatures features, - std::string prefix, - mitk::GIFGreyLevelDistanceZone::FeatureListType &featureList); - - +void MatrixFeaturesTo(const mitk::GreyLevelDistanceZoneFeatures& features, + const mitk::GreyLevelDistanceZoneConfiguration& config, + mitk::GIFGreyLevelDistanceZone::FeatureListType& featureList) +{ + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Distance Emphasis"), features.SmallDistanceEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Distance Emphasis"), features.LargeDistanceEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Grey Level Emphasis"), features.LowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Grey Level Emphasis"), features.HighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Distance Low Grey Level Emphasis"), features.SmallDistanceLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Distance High Grey Level Emphasis"), features.SmallDistanceHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Distance Low Grey Level Emphasis"), features.LargeDistanceLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Distance High Grey Level Emphasis"), features.LargeDistanceHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity"), features.GreyLevelNonUniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity Normalized"), features.GreyLevelNonUniformityNormalized)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Distance Size Non-Uniformity"), features.ZoneDistanceNonUniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Distance Size Non-Uniformity Normalized"), features.ZoneDistanceNoneUniformityNormalized)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Percentage"), features.ZonePercentage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Mean"), features.GreyLevelMean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Variance"), features.GreyLevelVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Distance Mean"), features.ZoneDistanceMean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Distance Variance"), features.ZoneDistanceVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Distance Entropy"), features.ZoneDistanceEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Entropy"), features.ZoneDistanceEntropy)); +} mitk::GreyLevelDistanceZoneMatrixHolder::GreyLevelDistanceZoneMatrixHolder(mitk::IntensityQuantifier::Pointer quantifier, int number, int maxSize) : m_NumberOfBins(number), m_MaximumSize(maxSize), m_NumerOfVoxels(0), m_Quantifier(quantifier) { m_Matrix.resize(number, maxSize); m_Matrix.fill(0); } int mitk::GreyLevelDistanceZoneMatrixHolder::IntensityToIndex(double intensity) { return m_Quantifier->IntensityToIndex(intensity); } template int CalculateGlSZMatrix(const itk::Image* itkImage, const itk::Image* mask, const itk::Image* distanceImage, std::vector > offsets, bool estimateLargestRegion, mitk::GreyLevelDistanceZoneMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef typename ImageType::IndexType IndexType; typedef itk::ImageRegionConstIteratorWithIndex ConstIterType; typedef itk::ImageRegionConstIteratorWithIndex ConstMaskIterType; auto region = mask->GetLargestPossibleRegion(); typename MaskImageType::RegionType newRegion; newRegion.SetSize(region.GetSize()); newRegion.SetIndex(region.GetIndex()); ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); typename MaskImageType::Pointer visitedImage = MaskImageType::New(); visitedImage->SetRegions(newRegion); visitedImage->Allocate(); visitedImage->FillBuffer(0); int largestRegion = 0; holder.m_NumberOfBins = 0; while (!maskIter.IsAtEnd()) { if (maskIter.Value() > 0 ) { auto startIntensityIndex = holder.IntensityToIndex(imageIter.Value()); std::vector indices; indices.push_back(maskIter.GetIndex()); unsigned int steps = 0; int smallestDistance = 500; while (indices.size() > 0) { auto currentIndex = indices.back(); indices.pop_back(); if (!region.IsInside(currentIndex)) { continue; } auto wasVisited = visitedImage->GetPixel(currentIndex); auto newIntensityIndex = holder.IntensityToIndex(itkImage->GetPixel(currentIndex)); auto isInMask = mask->GetPixel(currentIndex); if ((isInMask > 0) && (newIntensityIndex == startIntensityIndex) && (wasVisited < 1)) { ++(holder.m_NumerOfVoxels); smallestDistance = (smallestDistance > distanceImage->GetPixel(currentIndex)) ? distanceImage->GetPixel(currentIndex) : smallestDistance; ++steps; visitedImage->SetPixel(currentIndex, 1); for (auto offset : offsets) { auto newIndex = currentIndex + offset; indices.push_back(newIndex); newIndex = currentIndex - offset; indices.push_back(newIndex); } } } if (steps > 0) { largestRegion = std::max(steps, largestRegion); steps = std::min(steps, holder.m_MaximumSize); if (!estimateLargestRegion) { holder.m_Matrix(startIntensityIndex, smallestDistance-1) += 1; } } } ++imageIter; ++maskIter; } return largestRegion; } template void itkErode2( itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int &maxDistance) { typedef itk::Image ImageType; typedef unsigned short MaskType; typedef itk::Image MaskImageType; typename MaskImageType::Pointer distanceImage = MaskImageType::New(); distanceImage->SetRegions(sourceImage->GetLargestPossibleRegion()); distanceImage->SetOrigin(sourceImage->GetOrigin()); distanceImage->SetSpacing(sourceImage->GetSpacing()); distanceImage->SetDirection(sourceImage->GetDirection()); distanceImage->Allocate(); distanceImage->FillBuffer(std::numeric_limits::max()-1); typename ImageType::SizeType radius; radius.Fill(1); itk::NeighborhoodIterator neighbourIter(radius, sourceImage, sourceImage->GetLargestPossibleRegion()); itk::NeighborhoodIterator distanceIter(radius, distanceImage, distanceImage->GetLargestPossibleRegion()); bool imageChanged = true; while (imageChanged) { imageChanged = false; maxDistance = 0; neighbourIter.GoToBegin(); distanceIter.GoToBegin(); while (!neighbourIter.IsAtEnd()) { MaskType oldDistance = distanceIter.GetCenterPixel(); maxDistance = std::max(maxDistance, oldDistance); if (neighbourIter.GetCenterPixel() < 1) { if (oldDistance > 0) { distanceIter.SetCenterPixel(0); imageChanged = true; } } else if (oldDistance>0) { MaskType minimumDistance = oldDistance; for (unsigned int i = 0; i < distanceIter.Size(); ++i) { minimumDistance = std::min(minimumDistance, 1+distanceIter.GetPixel(i)); } if (minimumDistance != oldDistance) { distanceIter.SetCenterPixel(minimumDistance); imageChanged = true; } } ++neighbourIter; ++distanceIter; } } mitk::CastToMitkImage(distanceImage, resultImage); } void erode(mitk::Image::Pointer input, mitk::Image::Pointer &output, int &maxDistance) { AccessByItk_2(input, itkErode2, output, maxDistance); } void erodeAndAdd(mitk::Image::Pointer input, mitk::Image::Pointer& finalOutput, int &maxDistance) { maxDistance = 0; erode(input, finalOutput, maxDistance); } void static CalculateFeatures( mitk::GreyLevelDistanceZoneMatrixHolder &holder, mitk::GreyLevelDistanceZoneFeatures & results ) { auto SgzMatrix = holder.m_Matrix; auto pgzMatrix = holder.m_Matrix; auto pgMatrix = holder.m_Matrix; auto pzMatrix = holder.m_Matrix; double Ns = pgzMatrix.sum(); pgzMatrix /= Ns; pgMatrix.rowwise().normalize(); pzMatrix.colwise().normalize(); for (int i = 0; i < pgzMatrix.rows(); ++i) for (int j = 0; j < pgzMatrix.cols(); ++j) { if (pgzMatrix(i, j) != pgzMatrix(i, j)) pgzMatrix(i, j) = 0; if (pgMatrix(i, j) != pgMatrix(i, j)) pgMatrix(i, j) = 0; if (pzMatrix(i, j) != pzMatrix(i, j)) pzMatrix(i, j) = 0; } Eigen::VectorXd SgVector = SgzMatrix.rowwise().sum(); Eigen::VectorXd SzVector = SgzMatrix.colwise().sum(); for (int j = 0; j < SzVector.size(); ++j) { results.SmallDistanceEmphasis += SzVector(j) / (j+1) / (j+1); results.LargeDistanceEmphasis += SzVector(j) * (j + 1.0) * (j + 1.0); results.ZoneDistanceNonUniformity += SzVector(j) * SzVector(j); results.ZoneDistanceNoneUniformityNormalized += SzVector(j) * SzVector(j); } for (int i = 0; i < SgVector.size(); ++i) { results.LowGreyLevelEmphasis += SgVector(i) / (i + 1) / (i + 1); results.HighGreyLevelEmphasis += SgVector(i) * (i + 1) * (i + 1); results.GreyLevelNonUniformity += SgVector(i)*SgVector(i); results.GreyLevelNonUniformityNormalized += SgVector(i)*SgVector(i); } for (int i = 0; i < SgzMatrix.rows(); ++i) { for (int j = 0; j < SgzMatrix.cols(); ++j) { results.SmallDistanceLowGreyLevelEmphasis += SgzMatrix(i, j) / (i + 1) / (i + 1) / (j + 1) / (j + 1); results.SmallDistanceHighGreyLevelEmphasis += SgzMatrix(i, j) * (i + 1) * (i + 1) / (j + 1) / (j + 1); results.LargeDistanceLowGreyLevelEmphasis += SgzMatrix(i, j) / (i + 1) / (i + 1) * (j + 1.0) * (j + 1.0); results.LargeDistanceHighGreyLevelEmphasis += SgzMatrix(i, j) * (i + 1) * (i + 1) * (j + 1.0) * (j + 1.0); results.ZonePercentage += SgzMatrix(i, j); results.GreyLevelMean += (i + 1)*pgzMatrix(i, j); results.ZoneDistanceMean += (j + 1)*pgzMatrix(i, j); if (pgzMatrix(i, j) > 0) results.ZoneDistanceEntropy -= pgzMatrix(i, j) * std::log(pgzMatrix(i, j)) / std::log(2); } } for (int i = 0; i < SgzMatrix.rows(); ++i) { for (int j = 0; j < SgzMatrix.cols(); ++j) { results.GreyLevelVariance += (i + 1 - results.GreyLevelMean)*(i + 1 - results.GreyLevelMean)*pgzMatrix(i, j); results.ZoneDistanceVariance += (j + 1 - results.ZoneDistanceMean)*(j + 1 - results.ZoneDistanceMean)*pgzMatrix(i, j); } } results.SmallDistanceEmphasis /= Ns; results.LargeDistanceEmphasis /= Ns; results.LowGreyLevelEmphasis /= Ns; results.HighGreyLevelEmphasis /= Ns; results.SmallDistanceLowGreyLevelEmphasis /= Ns; results.SmallDistanceHighGreyLevelEmphasis /= Ns; results.LargeDistanceLowGreyLevelEmphasis /= Ns; results.LargeDistanceHighGreyLevelEmphasis /= Ns; results.GreyLevelNonUniformity /= Ns; results.GreyLevelNonUniformityNormalized /= Ns*Ns; results.ZoneDistanceNonUniformity /= Ns; results.ZoneDistanceNoneUniformityNormalized /= Ns*Ns; results.ZonePercentage = Ns / holder.m_NumerOfVoxels;// results.ZonePercentage; } template static void CalculateGreyLevelDistanceZoneFeatures(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFGreyLevelDistanceZone::FeatureListType & featureList, mitk::GreyLevelDistanceZoneConfiguration config) { typedef itk::Image MaskType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// int maximumDistance = 0; mitk::Image::Pointer mitkDistanceImage = mitk::Image::New(); erodeAndAdd(config.distanceMask, mitkDistanceImage, maximumDistance); typename MaskType::Pointer distanceImage = MaskType::New(); mitk::CastToItkImage(mitkDistanceImage, distanceImage); typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); //Find possible directions std::vector < itk::Offset > offsetVector; NeighborhoodType hood; hood.SetRadius(1); unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetType offset; for (unsigned int d = 0; d < centerIndex; d++) { offset = hood.GetOffset(d); bool useOffset = true; for (unsigned int i = 0; i < VImageDimension; ++i) { if ((config.direction == i + 2) && offset[i] != 0) { useOffset = false; } } if (useOffset) { offsetVector.push_back(offset); } } if (config.direction == 1) { offsetVector.clear(); offset[0] = 0; offset[1] = 0; offset[2] = 1; offsetVector.push_back(offset); } MITK_INFO << "Maximum Distance: " << maximumDistance; std::vector resultVector; mitk::GreyLevelDistanceZoneMatrixHolder holderOverall(config.Quantifier, config.Bins, maximumDistance + 1); mitk::GreyLevelDistanceZoneFeatures overallFeature; CalculateGlSZMatrix(itkImage, maskImage, distanceImage, offsetVector, false, holderOverall); CalculateFeatures(holderOverall, overallFeature); MatrixFeaturesTo(overallFeature, config, featureList); } - -static -void MatrixFeaturesTo(const mitk::GreyLevelDistanceZoneFeatures& features, - const mitk::GreyLevelDistanceZoneConfiguration& config, - mitk::GIFGreyLevelDistanceZone::FeatureListType &featureList) -{ - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Distance Emphasis"), features.SmallDistanceEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Distance Emphasis"), features.LargeDistanceEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Grey Level Emphasis"), features.LowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Grey Level Emphasis"), features.HighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Distance Low Grey Level Emphasis"), features.SmallDistanceLowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Distance High Grey Level Emphasis"), features.SmallDistanceHighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Distance Low Grey Level Emphasis"), features.LargeDistanceLowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Distance High Grey Level Emphasis"), features.LargeDistanceHighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity"), features.GreyLevelNonUniformity)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity Normalized"), features.GreyLevelNonUniformityNormalized)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Distance Size Non-Uniformity"), features.ZoneDistanceNonUniformity)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Distance Size Non-Uniformity Normalized"), features.ZoneDistanceNoneUniformityNormalized)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Percentage"), features.ZonePercentage)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Mean"), features.GreyLevelMean)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Variance"), features.GreyLevelVariance)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Distance Mean"), features.ZoneDistanceMean)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Distance Variance"), features.ZoneDistanceVariance)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Distance Entropy"), features.ZoneDistanceEntropy)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Entropy"), features.ZoneDistanceEntropy)); -} - mitk::GIFGreyLevelDistanceZone::GIFGreyLevelDistanceZone() { SetShortName("gldz"); SetLongName("distance-zone"); SetFeatureClassName("Grey Level Distance Zone"); } void mitk::GIFGreyLevelDistanceZone::AddArguments(mitkCommandLineParser& parser) const { this->AddQuantifierArguments(parser); std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Grey Level Distance Zone", "Calculates the size zone based features.", us::Any()); } mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFGreyLevelDistanceZone::DoCalculateFeatures(const Image* image, const Image* mask) { FeatureListType featureList; InitializeQuantifier(image, mask); MITK_INFO << "Start calculating Grey Level Distance Zone ...."; GreyLevelDistanceZoneConfiguration config; config.direction = GetDirection(); if (GetMorphMask().IsNull()) { config.distanceMask = mask->Clone(); } else { config.distanceMask = GetMorphMask(); } config.MinimumIntensity = GetQuantifier()->GetMinimum(); config.MaximumIntensity = GetQuantifier()->GetMaximum(); config.Bins = GetQuantifier()->GetBins(); config.id = this->CreateTemplateFeatureID(); config.Quantifier = GetQuantifier(); AccessByItk_3(image, CalculateGreyLevelDistanceZoneFeatures, mask, featureList, config); MITK_INFO << "Finished calculating Grey Level Distance Zone."; return featureList; } mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFGreyLevelDistanceZone::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { return Superclass::CalculateFeatures(image, maskNoNAN); } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp index cd3f98622f..27df56c3b8 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp @@ -1,437 +1,429 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include // ITK #include // STL namespace mitk { struct GIFGreyLevelSizeZoneConfiguration { unsigned int direction; double MinimumIntensity; double MaximumIntensity; int Bins; FeatureID id; }; struct GreyLevelSizeZoneMatrixHolder { public: GreyLevelSizeZoneMatrixHolder(double min, double max, int number, int maxSize); int IntensityToIndex(double intensity); double IndexToMinIntensity(int index); double IndexToMeanIntensity(int index); double IndexToMaxIntensity(int index); double m_MinimumRange; double m_MaximumRange; double m_Stepsize; int m_NumberOfBins; int m_MaximumSize; Eigen::MatrixXd m_Matrix; }; struct GreyLevelSizeZoneFeatures { GreyLevelSizeZoneFeatures() : SmallZoneEmphasis(0), LargeZoneEmphasis(0), LowGreyLevelEmphasis(0), HighGreyLevelEmphasis(0), SmallZoneLowGreyLevelEmphasis(0), SmallZoneHighGreyLevelEmphasis(0), LargeZoneLowGreyLevelEmphasis(0), LargeZoneHighGreyLevelEmphasis(0), GreyLevelNonUniformity(0), GreyLevelNonUniformityNormalized(0), ZoneSizeNonUniformity(0), ZoneSizeNoneUniformityNormalized(0), ZonePercentage(0), GreyLevelMean(0), GreyLevelVariance(0), ZoneSizeMean(0), ZoneSizeVariance(0), ZoneSizeEntropy(0) { } public: double SmallZoneEmphasis; double LargeZoneEmphasis; double LowGreyLevelEmphasis; double HighGreyLevelEmphasis; double SmallZoneLowGreyLevelEmphasis; double SmallZoneHighGreyLevelEmphasis; double LargeZoneLowGreyLevelEmphasis; double LargeZoneHighGreyLevelEmphasis; double GreyLevelNonUniformity; double GreyLevelNonUniformityNormalized; double ZoneSizeNonUniformity; double ZoneSizeNoneUniformityNormalized; double ZonePercentage; double GreyLevelMean; double GreyLevelVariance; double ZoneSizeMean; double ZoneSizeVariance; double ZoneSizeEntropy; }; } static -void MatrixFeaturesTo(mitk::GreyLevelSizeZoneFeatures features, - std::string prefix, - mitk::GIFGreyLevelSizeZone::FeatureListType &featureList); - - +void MatrixFeaturesTo(const mitk::GreyLevelSizeZoneFeatures& features, + const mitk::GIFGreyLevelSizeZoneConfiguration& config, + mitk::GIFGreyLevelSizeZone::FeatureListType& featureList) +{ + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Zone Emphasis"), features.SmallZoneEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Zone Emphasis"), features.LargeZoneEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Grey Level Emphasis"), features.LowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Grey Level Emphasis"), features.HighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Zone Low Grey Level Emphasis"), features.SmallZoneLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Small Zone High Grey Level Emphasis"), features.SmallZoneHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Zone Low Grey Level Emphasis"), features.LargeZoneLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Large Zone High Grey Level Emphasis"), features.LargeZoneHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity"), features.GreyLevelNonUniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity Normalized"), features.GreyLevelNonUniformityNormalized)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Size Non-Uniformity"), features.ZoneSizeNonUniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Size Non-Uniformity Normalized"), features.ZoneSizeNoneUniformityNormalized)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Percentage"), features.ZonePercentage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Mean"), features.GreyLevelMean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Variance"), features.GreyLevelVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Size Mean"), features.ZoneSizeMean)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Size Variance"), features.ZoneSizeVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Zone Size Entropy"), features.ZoneSizeEntropy)); +} mitk::GreyLevelSizeZoneMatrixHolder::GreyLevelSizeZoneMatrixHolder(double min, double max, int number, int maxSize) : m_MinimumRange(min), m_MaximumRange(max), m_NumberOfBins(number), m_MaximumSize(maxSize) { m_Matrix.resize(number, maxSize); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::GreyLevelSizeZoneMatrixHolder::IntensityToIndex(double intensity) { return std::floor((intensity - m_MinimumRange) / m_Stepsize); } double mitk::GreyLevelSizeZoneMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::GreyLevelSizeZoneMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::GreyLevelSizeZoneMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template static int CalculateGlSZMatrix(const itk::Image* itkImage, const itk::Image* mask, std::vector > offsets, bool estimateLargestRegion, mitk::GreyLevelSizeZoneMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef typename ImageType::IndexType IndexType; typedef itk::ImageRegionConstIteratorWithIndex ConstIterType; typedef itk::ImageRegionConstIteratorWithIndex ConstMaskIterType; auto region = mask->GetLargestPossibleRegion(); typename MaskImageType::RegionType newRegion; newRegion.SetSize(region.GetSize()); newRegion.SetIndex(region.GetIndex()); ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); typename MaskImageType::Pointer visitedImage = MaskImageType::New(); visitedImage->SetRegions(newRegion); visitedImage->Allocate(); visitedImage->FillBuffer(0); int largestRegion = 0; while (!maskIter.IsAtEnd()) { if (maskIter.Value() > 0 ) { auto startIntensityIndex = holder.IntensityToIndex(imageIter.Value()); std::vector indices; indices.push_back(maskIter.GetIndex()); unsigned int steps = 0; while (indices.size() > 0) { auto currentIndex = indices.back(); indices.pop_back(); if (!region.IsInside(currentIndex)) { continue; } auto wasVisited = visitedImage->GetPixel(currentIndex); auto newIntensityIndex = holder.IntensityToIndex(itkImage->GetPixel(currentIndex)); auto isInMask = mask->GetPixel(currentIndex); if ((isInMask > 0) && (newIntensityIndex == startIntensityIndex) && (wasVisited < 1)) { ++steps; visitedImage->SetPixel(currentIndex, 1); for (auto offset : offsets) { auto newIndex = currentIndex + offset; indices.push_back(newIndex); newIndex = currentIndex - offset; indices.push_back(newIndex); } } } if (steps > 0) { largestRegion = std::max(steps, largestRegion); steps = std::min(steps, holder.m_MaximumSize); if (!estimateLargestRegion) { holder.m_Matrix(startIntensityIndex, steps - 1) += 1; } } } ++imageIter; ++maskIter; } return largestRegion; } static void CalculateFeatures( mitk::GreyLevelSizeZoneMatrixHolder &holder, mitk::GreyLevelSizeZoneFeatures & results ) { auto SgzMatrix = holder.m_Matrix; auto pgzMatrix = holder.m_Matrix; auto pgMatrix = holder.m_Matrix; auto pzMatrix = holder.m_Matrix; double Ns = pgzMatrix.sum(); pgzMatrix /= Ns; pgMatrix.rowwise().normalize(); pzMatrix.colwise().normalize(); for (int i = 0; i < pgzMatrix.rows(); ++i) for (int j = 0; j < pgzMatrix.cols(); ++j) { if (pgzMatrix(i, j) != pgzMatrix(i, j)) pgzMatrix(i, j) = 0; if (pgMatrix(i, j) != pgMatrix(i, j)) pgMatrix(i, j) = 0; if (pzMatrix(i, j) != pzMatrix(i, j)) pzMatrix(i, j) = 0; } Eigen::VectorXd SgVector = SgzMatrix.rowwise().sum(); Eigen::VectorXd SzVector = SgzMatrix.colwise().sum(); for (int j = 0; j < SzVector.size(); ++j) { results.SmallZoneEmphasis += SzVector(j) / (j + 1) / (j + 1); results.LargeZoneEmphasis += SzVector(j) * (j + 1.0) * (j + 1.0); results.ZoneSizeNonUniformity += SzVector(j) * SzVector(j); results.ZoneSizeNoneUniformityNormalized += SzVector(j) * SzVector(j); } for (int i = 0; i < SgVector.size(); ++i) { results.LowGreyLevelEmphasis += SgVector(i) / (i + 1) / (i + 1); results.HighGreyLevelEmphasis += SgVector(i) * (i + 1) * (i + 1); results.GreyLevelNonUniformity += SgVector(i)*SgVector(i); results.GreyLevelNonUniformityNormalized += SgVector(i)*SgVector(i); } for (int i = 0; i < SgzMatrix.rows(); ++i) { for (int j = 0; j < SgzMatrix.cols(); ++j) { results.SmallZoneLowGreyLevelEmphasis += SgzMatrix(i, j) / (i + 1) / (i + 1) / (j + 1) / (j + 1); results.SmallZoneHighGreyLevelEmphasis += SgzMatrix(i, j) * (i + 1) * (i + 1) / (j + 1) / (j + 1); results.LargeZoneLowGreyLevelEmphasis += SgzMatrix(i, j) / (i + 1) / (i + 1) * (j + 1.0) * (j + 1.0); results.LargeZoneHighGreyLevelEmphasis += SgzMatrix(i, j) * (i + 1) * (i + 1) * (j + 1.0) * (j + 1.0); results.ZonePercentage += SgzMatrix(i, j)*(j + 1); results.GreyLevelMean += (i + 1)*pgzMatrix(i, j); results.ZoneSizeMean += (j + 1)*pgzMatrix(i, j); if (pgzMatrix(i, j) > 0) results.ZoneSizeEntropy -= pgzMatrix(i, j) * std::log(pgzMatrix(i, j)) / std::log(2); } } for (int i = 0; i < SgzMatrix.rows(); ++i) { for (int j = 0; j < SgzMatrix.cols(); ++j) { results.GreyLevelVariance += (i + 1 - results.GreyLevelMean)*(i + 1 - results.GreyLevelMean)*pgzMatrix(i, j); results.ZoneSizeVariance += (j + 1 - results.ZoneSizeMean)*(j + 1 - results.ZoneSizeMean)*pgzMatrix(i, j); } } results.SmallZoneEmphasis /= Ns; results.LargeZoneEmphasis /= Ns; results.LowGreyLevelEmphasis /= Ns; results.HighGreyLevelEmphasis /= Ns; results.SmallZoneLowGreyLevelEmphasis /= Ns; results.SmallZoneHighGreyLevelEmphasis /= Ns; results.LargeZoneLowGreyLevelEmphasis /= Ns; results.LargeZoneHighGreyLevelEmphasis /= Ns; results.GreyLevelNonUniformity /= Ns; results.GreyLevelNonUniformityNormalized /= Ns*Ns; results.ZoneSizeNonUniformity /= Ns; results.ZoneSizeNoneUniformityNormalized /= Ns*Ns; results.ZonePercentage = Ns / results.ZonePercentage; } template static void CalculateGreyLevelSizeZoneFeatures(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFGreyLevelSizeZone::FeatureListType & featureList, mitk::GIFGreyLevelSizeZoneConfiguration config) { typedef itk::Image MaskType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// double rangeMin = config.MinimumIntensity; double rangeMax = config.MaximumIntensity; int numberOfBins = config.Bins; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); //Find possible directions std::vector < itk::Offset > offsetVector; NeighborhoodType hood; hood.SetRadius(1); unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetType offset; for (unsigned int d = 0; d < centerIndex; d++) { offset = hood.GetOffset(d); bool useOffset = true; for (unsigned int i = 0; i < VImageDimension; ++i) { if ((config.direction == i + 2) && offset[i] != 0) { useOffset = false; } } if (useOffset) { offsetVector.push_back(offset); MITK_INFO << offset; } } if (config.direction == 1) { offsetVector.clear(); offset[0] = 0; offset[1] = 0; offset[2] = 1; offsetVector.push_back(offset); } std::vector resultVector; mitk::GreyLevelSizeZoneMatrixHolder tmpHolder(rangeMin, rangeMax, numberOfBins, 3); int largestRegion = CalculateGlSZMatrix(itkImage, maskImage, offsetVector, true, tmpHolder); mitk::GreyLevelSizeZoneMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins,largestRegion); mitk::GreyLevelSizeZoneFeatures overallFeature; CalculateGlSZMatrix(itkImage, maskImage, offsetVector, false, holderOverall); CalculateFeatures(holderOverall, overallFeature); MatrixFeaturesTo(overallFeature, config, featureList); } - -static -void MatrixFeaturesTo(const mitk::GreyLevelSizeZoneFeatures& features, - const mitk::GIFGreyLevelSizeZoneConfiguration& config, - mitk::GIFGreyLevelSizeZone::FeatureListType &featureList) -{ - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Small Zone Emphasis"), features.SmallZoneEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Large Zone Emphasis"), features.LargeZoneEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Low Grey Level Emphasis"), features.LowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"High Grey Level Emphasis"), features.HighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Small Zone Low Grey Level Emphasis"), features.SmallZoneLowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Small Zone High Grey Level Emphasis"), features.SmallZoneHighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Large Zone Low Grey Level Emphasis"), features.LargeZoneLowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Large Zone High Grey Level Emphasis"), features.LargeZoneHighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Grey Level Non-Uniformity"), features.GreyLevelNonUniformity)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Grey Level Non-Uniformity Normalized"), features.GreyLevelNonUniformityNormalized)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Zone Size Non-Uniformity"), features.ZoneSizeNonUniformity)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Zone Size Non-Uniformity Normalized"), features.ZoneSizeNoneUniformityNormalized)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Zone Percentage"), features.ZonePercentage)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Grey Level Mean"), features.GreyLevelMean)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Grey Level Variance"), features.GreyLevelVariance)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Zone Size Mean"), features.ZoneSizeMean)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Zone Size Variance"), features.ZoneSizeVariance)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id,"Zone Size Entropy"), features.ZoneSizeEntropy)); -} - mitk::GIFGreyLevelSizeZone::GIFGreyLevelSizeZone() { SetShortName("glsz"); SetLongName("grey-level-sizezone"); SetFeatureClassName("Grey Level Size Zone"); } void mitk::GIFGreyLevelSizeZone::AddArguments(mitkCommandLineParser& parser) const { this->AddQuantifierArguments(parser); std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Grey Level Size Zone", "Calculates the size zone based features.", us::Any()); } mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFGreyLevelSizeZone::DoCalculateFeatures(const Image* image, const Image* mask) { FeatureListType featureList; InitializeQuantifier(image, mask); MITK_INFO << "Start calculating Grey leve size zone ..."; GIFGreyLevelSizeZoneConfiguration config; config.direction = GetDirection(); config.MinimumIntensity = GetQuantifier()->GetMinimum(); config.MaximumIntensity = GetQuantifier()->GetMaximum(); config.Bins = GetQuantifier()->GetBins(); config.id = this->CreateTemplateFeatureID(); AccessByItk_3(image, CalculateGreyLevelSizeZoneFeatures, mask, featureList, config); MITK_INFO << "Finished calculating Grey level size zone ..."; return featureList; } mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFGreyLevelSizeZone::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { return Superclass::CalculateFeatures(image, maskNoNAN); } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp index b81a5b946e..aa76bc4362 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp @@ -1,510 +1,502 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include // MITK #include #include #include // ITK #include #include #include #include // STL #include struct GIFNeighbouringGreyLevelDependenceFeatureConfiguration { double range; unsigned int direction; int alpha; double MinimumIntensity; double MaximumIntensity; int Bins; mitk::FeatureID id; }; namespace mitk { struct NGLDMMatrixHolder { public: NGLDMMatrixHolder(double min, double max, int number, int depenence); int IntensityToIndex(double intensity); double IndexToMinIntensity(int index); double IndexToMeanIntensity(int index); double IndexToMaxIntensity(int index); double m_MinimumRange; double m_MaximumRange; double m_Stepsize; int m_NumberOfDependences; int m_NumberOfBins; Eigen::MatrixXd m_Matrix; int m_NeighbourhoodSize; unsigned long m_NumberOfNeighbourVoxels; unsigned long m_NumberOfDependenceNeighbourVoxels; unsigned long m_NumberOfNeighbourhoods; unsigned long m_NumberOfCompleteNeighbourhoods; }; struct NGLDMMatrixFeatures { NGLDMMatrixFeatures() : LowDependenceEmphasis(0), HighDependenceEmphasis(0), LowGreyLevelCountEmphasis(0), HighGreyLevelCountEmphasis(0), LowDependenceLowGreyLevelEmphasis(0), LowDependenceHighGreyLevelEmphasis(0), HighDependenceLowGreyLevelEmphasis(0), HighDependenceHighGreyLevelEmphasis(0), GreyLevelNonUniformity(0), GreyLevelNonUniformityNormalised(0), DependenceCountNonUniformity(0), DependenceCountNonUniformityNormalised(0), DependenceCountPercentage(0), GreyLevelVariance(0), DependenceCountVariance(0), DependenceCountEntropy(0), DependenceCountEnergy(0), MeanGreyLevelCount(0), MeanDependenceCount(0), ExpectedNeighbourhoodSize(0), AverageNeighbourhoodSize(0), AverageIncompleteNeighbourhoodSize(0), PercentageOfCompleteNeighbourhoods(0), PercentageOfDependenceNeighbours(0) { } public: double LowDependenceEmphasis; double HighDependenceEmphasis; double LowGreyLevelCountEmphasis; double HighGreyLevelCountEmphasis; double LowDependenceLowGreyLevelEmphasis; double LowDependenceHighGreyLevelEmphasis; double HighDependenceLowGreyLevelEmphasis; double HighDependenceHighGreyLevelEmphasis; double GreyLevelNonUniformity; double GreyLevelNonUniformityNormalised; double DependenceCountNonUniformity; double DependenceCountNonUniformityNormalised; double DependenceCountPercentage; double GreyLevelVariance; double DependenceCountVariance; double DependenceCountEntropy; double DependenceCountEnergy; double MeanGreyLevelCount; double MeanDependenceCount; double ExpectedNeighbourhoodSize; double AverageNeighbourhoodSize; double AverageIncompleteNeighbourhoodSize; double PercentageOfCompleteNeighbourhoods; double PercentageOfDependenceNeighbours; }; } static -void MatrixFeaturesTo(mitk::NGLDMMatrixFeatures features, - std::string prefix, - mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType &featureList); +void MatrixFeaturesTo(const mitk::NGLDMMatrixFeatures& features, + const GIFNeighbouringGreyLevelDependenceFeatureConfiguration& config, + mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType& featureList) +{ + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Dependence Emphasis"), features.LowDependenceEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Dependence Emphasis"), features.HighDependenceEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Grey Level Count Emphasis"), features.LowGreyLevelCountEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Grey Level Count Emphasis"), features.HighGreyLevelCountEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Dependence Low Grey Level Emphasis"), features.LowDependenceLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Dependence High Grey Level Emphasis"), features.LowDependenceHighGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Dependence Low Grey Level Emphasis"), features.HighDependenceLowGreyLevelEmphasis)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Dependence High Grey Level Emphasis"), features.HighDependenceHighGreyLevelEmphasis)); + + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity"), features.GreyLevelNonUniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity Normalised"), features.GreyLevelNonUniformityNormalised)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Non-Uniformity"), features.DependenceCountNonUniformity)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Non-Uniformity Normalised"), features.DependenceCountNonUniformityNormalised)); + + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Percentage"), features.DependenceCountPercentage)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Mean"), features.MeanGreyLevelCount)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Variance"), features.GreyLevelVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Mean"), features.MeanDependenceCount)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Variance"), features.DependenceCountVariance)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Entropy"), features.DependenceCountEntropy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Energy"), features.DependenceCountEnergy)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Expected Neighbourhood Size"), features.ExpectedNeighbourhoodSize)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Average Neighbourhood Size"), features.AverageNeighbourhoodSize)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Average Incomplete Neighbourhood Size"), features.AverageIncompleteNeighbourhoodSize)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Percentage of complete Neighbourhoods"), features.PercentageOfCompleteNeighbourhoods)); + featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Percentage of Dependence Neighbour Voxels"), features.PercentageOfDependenceNeighbours)); +} mitk::NGLDMMatrixHolder::NGLDMMatrixHolder(double min, double max, int number, int depenence) : m_MinimumRange(min), m_MaximumRange(max), m_Stepsize(0), m_NumberOfDependences(depenence), m_NumberOfBins(number), m_NeighbourhoodSize(1), m_NumberOfNeighbourVoxels(0), m_NumberOfDependenceNeighbourVoxels(0), m_NumberOfNeighbourhoods(0), m_NumberOfCompleteNeighbourhoods(0) { m_Matrix.resize(number, depenence); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::NGLDMMatrixHolder::IntensityToIndex(double intensity) { return std::floor((intensity - m_MinimumRange) / m_Stepsize); } double mitk::NGLDMMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::NGLDMMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::NGLDMMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template void CalculateNGLDMMatrix(const itk::Image* itkImage, const itk::Image* mask, int alpha, int range, unsigned int direction, mitk::NGLDMMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef itk::ConstNeighborhoodIterator ShapeIterType; typedef itk::ConstNeighborhoodIterator ShapeMaskIterType; holder.m_NumberOfCompleteNeighbourhoods = 0; holder.m_NumberOfNeighbourhoods = 0; holder.m_NumberOfNeighbourVoxels = 0; holder.m_NumberOfDependenceNeighbourVoxels = 0; itk::Size radius; radius.Fill(range); if ((direction > 1) && (direction - 2 GetLargestPossibleRegion()); ShapeMaskIterType maskIter(radius, mask, mask->GetLargestPossibleRegion()); auto region = mask->GetLargestPossibleRegion(); auto center = imageIter.Size() / 2; auto iterSize = imageIter.Size(); holder.m_NeighbourhoodSize = iterSize-1; while (!maskIter.IsAtEnd()) { int sameValues = 0; bool completeNeighbourhood = true; int i = holder.IntensityToIndex(imageIter.GetCenterPixel()); if ((imageIter.GetCenterPixel() != imageIter.GetCenterPixel()) || (maskIter.GetCenterPixel() < 1)) { ++imageIter; ++maskIter; continue; } for (unsigned int position = 0; position < iterSize; ++position) { if (position == center) { continue; } if ( ! region.IsInside(maskIter.GetIndex(position))) { completeNeighbourhood = false; continue; } bool isInBounds; auto jIntensity = imageIter.GetPixel(position, isInBounds); auto jMask = maskIter.GetPixel(position, isInBounds); if (jMask < 1 || (jIntensity != jIntensity) || ( ! isInBounds)) { completeNeighbourhood = false; continue; } int j = holder.IntensityToIndex(jIntensity); holder.m_NumberOfNeighbourVoxels += 1; if (std::abs(i - j) <= alpha) { holder.m_NumberOfDependenceNeighbourVoxels += 1; ++sameValues; } } holder.m_Matrix(i, sameValues) += 1; holder.m_NumberOfNeighbourhoods += 1; if (completeNeighbourhood) { holder.m_NumberOfCompleteNeighbourhoods += 1; } ++imageIter; ++maskIter; } } void LocalCalculateFeatures( mitk::NGLDMMatrixHolder &holder, mitk::NGLDMMatrixFeatures & results ) { auto sijMatrix = holder.m_Matrix; auto piMatrix = holder.m_Matrix; auto pjMatrix = holder.m_Matrix; // double Ng = holder.m_NumberOfBins; // int NgSize = holder.m_NumberOfBins; double Ns = sijMatrix.sum(); piMatrix.rowwise().normalize(); pjMatrix.colwise().normalize(); for (int i = 0; i < holder.m_NumberOfBins; ++i) { double sj = 0; for (int j = 0; j < holder.m_NumberOfDependences; ++j) { double iInt = i+1 ;// holder.IndexToMeanIntensity(i); double sij = sijMatrix(i, j); double k = j + 1; double pij = sij / Ns; results.LowDependenceEmphasis += sij / k / k; results.HighDependenceEmphasis += sij * k*k; if (iInt != 0) { results.LowGreyLevelCountEmphasis += sij / iInt / iInt; } results.HighGreyLevelCountEmphasis += sij * iInt*iInt; if (iInt != 0) { results.LowDependenceLowGreyLevelEmphasis += sij / k / k / iInt / iInt; } results.LowDependenceHighGreyLevelEmphasis += sij * iInt*iInt / k / k; if (iInt != 0) { results.HighDependenceLowGreyLevelEmphasis += sij *k * k / iInt / iInt; } results.HighDependenceHighGreyLevelEmphasis += sij * k*k*iInt*iInt; results.MeanGreyLevelCount += iInt * pij; results.MeanDependenceCount += k * pij; if (pij > 0) { results.DependenceCountEntropy -= pij * std::log(pij) / std::log(2); } results.DependenceCountEnergy += pij*pij; sj += sij; } results.GreyLevelNonUniformity += sj*sj; results.GreyLevelNonUniformityNormalised += sj*sj; } for (int j = 0; j < holder.m_NumberOfDependences; ++j) { double si = 0; for (int i = 0; i < holder.m_NumberOfBins; ++i) { double sij = sijMatrix(i, j); si += sij; } results.DependenceCountNonUniformity += si*si; results.DependenceCountNonUniformityNormalised += si*si; } for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfDependences; ++j) { double iInt = i + 1;// holder.IndexToMeanIntensity(i); double sij = sijMatrix(i, j); double k = j + 1; double pij = sij / Ns; results.GreyLevelVariance += (iInt - results.MeanGreyLevelCount)* (iInt - results.MeanGreyLevelCount) * pij; results.DependenceCountVariance += (k - results.MeanDependenceCount)* (k - results.MeanDependenceCount) * pij; } } results.LowDependenceEmphasis /= Ns; results.HighDependenceEmphasis /= Ns; results.LowGreyLevelCountEmphasis /= Ns; results.HighGreyLevelCountEmphasis /= Ns; results.LowDependenceLowGreyLevelEmphasis /= Ns; results.LowDependenceHighGreyLevelEmphasis /= Ns; results.HighDependenceLowGreyLevelEmphasis /= Ns; results.HighDependenceHighGreyLevelEmphasis /= Ns; results.GreyLevelNonUniformity /= Ns; results.GreyLevelNonUniformityNormalised /= (Ns*Ns); results.DependenceCountNonUniformity /= Ns; results.DependenceCountNonUniformityNormalised /= (Ns*Ns); results.DependenceCountPercentage = 1; results.ExpectedNeighbourhoodSize = holder.m_NeighbourhoodSize; results.AverageNeighbourhoodSize = holder.m_NumberOfNeighbourVoxels / (1.0 * holder.m_NumberOfNeighbourhoods); results.AverageIncompleteNeighbourhoodSize = (holder.m_NumberOfNeighbourVoxels - holder.m_NumberOfCompleteNeighbourhoods* holder.m_NeighbourhoodSize) / (1.0 * (holder.m_NumberOfNeighbourhoods - holder.m_NumberOfCompleteNeighbourhoods)); results.PercentageOfCompleteNeighbourhoods = (1.0*holder.m_NumberOfCompleteNeighbourhoods) / (1.0 * holder.m_NumberOfNeighbourhoods); results.PercentageOfDependenceNeighbours = holder.m_NumberOfDependenceNeighbourVoxels / (1.0 * holder.m_NumberOfNeighbourVoxels); } template void CalculateCoocurenceFeatures(const itk::Image* itkImage, const mitk::Image* mask, mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType & featureList, GIFNeighbouringGreyLevelDependenceFeatureConfiguration config) { typedef itk::Image MaskType; double rangeMin = config.MinimumIntensity; double rangeMax = config.MaximumIntensity; int numberOfBins = config.Bins; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); std::vector resultVector; int numberofDependency = 37; if (VImageDimension == 2) numberofDependency = 37; mitk::NGLDMMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins, numberofDependency); mitk::NGLDMMatrixFeatures overallFeature; CalculateNGLDMMatrix(itkImage, maskImage, config.alpha, config.range, config.direction, holderOverall); LocalCalculateFeatures(holderOverall, overallFeature); MatrixFeaturesTo(overallFeature, config, featureList); } - -static -void MatrixFeaturesTo(const mitk::NGLDMMatrixFeatures& features, - const GIFNeighbouringGreyLevelDependenceFeatureConfiguration& config, - mitk::GIFNeighbouringGreyLevelDependenceFeature::FeatureListType &featureList) -{ - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Dependence Emphasis"), features.LowDependenceEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Dependence Emphasis"), features.HighDependenceEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Grey Level Count Emphasis"), features.LowGreyLevelCountEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Grey Level Count Emphasis"), features.HighGreyLevelCountEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Dependence Low Grey Level Emphasis"), features.LowDependenceLowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Low Dependence High Grey Level Emphasis"), features.LowDependenceHighGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Dependence Low Grey Level Emphasis"), features.HighDependenceLowGreyLevelEmphasis)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "High Dependence High Grey Level Emphasis"), features.HighDependenceHighGreyLevelEmphasis)); - - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity"), features.GreyLevelNonUniformity)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Non-Uniformity Normalised"), features.GreyLevelNonUniformityNormalised)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Non-Uniformity"), features.DependenceCountNonUniformity)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Non-Uniformity Normalised"), features.DependenceCountNonUniformityNormalised)); - - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Percentage"), features.DependenceCountPercentage)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Mean"), features.MeanGreyLevelCount)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Grey Level Variance"), features.GreyLevelVariance)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Mean"), features.MeanDependenceCount)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Variance"), features.DependenceCountVariance)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Entropy"), features.DependenceCountEntropy)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Dependence Count Energy"), features.DependenceCountEnergy)); - - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Expected Neighbourhood Size"), features.ExpectedNeighbourhoodSize)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Average Neighbourhood Size"), features.AverageNeighbourhoodSize)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Average Incomplete Neighbourhood Size"), features.AverageIncompleteNeighbourhoodSize)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Percentage of complete Neighbourhoods"), features.PercentageOfCompleteNeighbourhoods)); - featureList.push_back(std::make_pair(mitk::CreateFeatureID(config.id, "Percentage of Dependence Neighbour Voxels"), features.PercentageOfDependenceNeighbours)); - -} - mitk::GIFNeighbouringGreyLevelDependenceFeature::GIFNeighbouringGreyLevelDependenceFeature() : m_Ranges({ 1.0 }), m_Alpha(0.) { SetShortName("ngld"); SetLongName("neighbouring-grey-level-dependence"); SetFeatureClassName("Neighbouring Grey Level Dependence"); } void mitk::GIFNeighbouringGreyLevelDependenceFeature::SetRanges(std::vector ranges) { m_Ranges = ranges; this->Modified(); } void mitk::GIFNeighbouringGreyLevelDependenceFeature::SetRange(double range) { m_Ranges.resize(1); m_Ranges[0] = range; this->Modified(); } void mitk::GIFNeighbouringGreyLevelDependenceFeature::AddArguments(mitkCommandLineParser& parser) const { AddQuantifierArguments(parser); std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Calculate Neighbouring Grey Level Dependence Features", "Calculate Neighbouring grey level dependence based features", us::Any()); parser.addArgument(name + "::range", name + "::range", mitkCommandLineParser::String, "NGLD Range", "Define the range that is used (Semicolon-separated)", us::Any()); parser.addArgument(name + "::alpha", name + "::alpha", mitkCommandLineParser::Int, "Int", "", us::Any()); } mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFNeighbouringGreyLevelDependenceFeature::DoCalculateFeatures(const Image* image, const Image* mask) { FeatureListType featureList; this->InitializeQuantifier(image, mask); for (const auto& range : m_Ranges) { MITK_INFO << "Start calculating NGLD with range " << range << "...."; GIFNeighbouringGreyLevelDependenceFeatureConfiguration config; config.direction = GetDirection(); config.range = range; config.alpha = m_Alpha; config.MinimumIntensity = GetQuantifier()->GetMinimum(); config.MaximumIntensity = GetQuantifier()->GetMaximum(); config.Bins = GetQuantifier()->GetBins(); config.id = this->CreateTemplateFeatureID(std::to_string(range), { {GetOptionPrefix() + "::range", range} }); AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList, config); MITK_INFO << "Finished calculating NGLD with range " << range << "...."; } return featureList; } mitk::AbstractGlobalImageFeature::FeatureListType mitk::GIFNeighbouringGreyLevelDependenceFeature::CalculateFeatures(const Image* image, const Image*, const Image* maskNoNAN) { return Superclass::CalculateFeatures(image, maskNoNAN); } std::string mitk::GIFNeighbouringGreyLevelDependenceFeature::GenerateLegacyFeatureEncoding(const FeatureID& id) const { return QuantifierParameterString() + "_Range-" + id.parameters.at(this->GetOptionPrefix() + "::range").ToString(); } void mitk::GIFNeighbouringGreyLevelDependenceFeature::ConfigureSettingsByParameters(const ParametersType& parameters) { auto prefixname = GetOptionPrefix(); auto name = prefixname + "::range"; if (parameters.count(name)) { m_Ranges = SplitDouble(parameters.at(name).ToString(), ';'); } name = prefixname + "::alpha"; if (parameters.count(name)) { int alpha = us::any_cast(parameters.at(name)); this->SetAlpha(alpha); } }