22 #include <itkShapedNeighborhoodIterator.h> 23 #include <itkImageRegionConstIterator.h> 31 struct CoocurenceMatrixHolder
34 CoocurenceMatrixHolder(
double min,
double max,
int number);
36 int IntensityToIndex(
double intensity);
37 double IndexToMinIntensity(
int index);
38 double IndexToMeanIntensity(
int index);
39 double IndexToMaxIntensity(
int index);
41 double m_MinimumRange;
42 double m_MaximumRange;
45 Eigen::MatrixXd m_Matrix;
49 struct CoocurenceMatrixFeatures
51 CoocurenceMatrixFeatures() :
60 FirstRowColumnEntropy(0),
61 SecondRowColumnEntropy(0),
63 DifferenceVariance(0),
68 AngularSecondMoment(0),
72 InverseDifferenceNormalised(0),
73 InverseDifferenceMoment(0),
74 InverseDifferenceMomentNormalised(0),
81 FirstMeasureOfInformationCorrelation(0),
82 SecondMeasureOfInformationCorrelation(0)
95 double FirstRowColumnEntropy;
96 double SecondRowColumnEntropy;
97 double DifferenceAverage;
98 double DifferenceVariance;
99 double DifferenceEntropy;
103 double AngularSecondMoment;
105 double Dissimilarity;
106 double InverseDifference;
107 double InverseDifferenceNormalised;
108 double InverseDifferenceMoment;
109 double InverseDifferenceMomentNormalised;
110 double InverseVariance;
112 double Autocorrelation;
113 double ClusterTendency;
115 double ClusterProminence;
116 double FirstMeasureOfInformationCorrelation;
117 double SecondMeasureOfInformationCorrelation;
128 mitk::CoocurenceMatrixFeatures &meanFeature,
129 mitk::CoocurenceMatrixFeatures &stdFeature);
137 mitk::CoocurenceMatrixHolder::CoocurenceMatrixHolder(
double min,
double max,
int number) :
140 m_NumberOfBins(number)
142 m_Matrix.resize(number, number);
144 m_Stepsize = (max -
min) / (number);
147 int mitk::CoocurenceMatrixHolder::IntensityToIndex(
double intensity)
149 int index = std::floor((intensity - m_MinimumRange) / m_Stepsize);
153 double mitk::CoocurenceMatrixHolder::IndexToMinIntensity(
int index)
155 return m_MinimumRange + index * m_Stepsize;
157 double mitk::CoocurenceMatrixHolder::IndexToMeanIntensity(
int index)
159 return m_MinimumRange + (index+0.5) * m_Stepsize;
161 double mitk::CoocurenceMatrixHolder::IndexToMaxIntensity(
int index)
163 return m_MinimumRange + (index + 1) * m_Stepsize;
166 template<
typename TPixel,
unsigned int VImageDimension>
169 itk::Image<unsigned short, VImageDimension>*
mask,
170 itk::Offset<VImageDimension>
offset,
172 mitk::CoocurenceMatrixHolder &holder)
174 typedef itk::Image<TPixel, VImageDimension>
ImageType;
175 typedef itk::Image<unsigned short, VImageDimension>
MaskImageType;
176 typedef itk::ShapedNeighborhoodIterator<ImageType> ShapeIterType;
177 typedef itk::ShapedNeighborhoodIterator<MaskImageType> ShapeMaskIterType;
178 typedef itk::ImageRegionConstIterator<ImageType> ConstIterType;
179 typedef itk::ImageRegionConstIterator<MaskImageType> ConstMaskIterType;
182 itk::Size<VImageDimension> radius;
183 radius.Fill(range+1);
184 ShapeIterType imageOffsetIter(radius, itkImage, itkImage->GetLargestPossibleRegion());
185 ShapeMaskIterType maskOffsetIter(radius, mask, mask->GetLargestPossibleRegion());
186 imageOffsetIter.ActivateOffset(offset);
187 maskOffsetIter.ActivateOffset(offset);
188 ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion());
189 ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion());
191 auto region = mask->GetLargestPossibleRegion();
194 while (!maskIter.IsAtEnd())
196 auto ciMask = maskOffsetIter.Begin();
197 auto ciValue = imageOffsetIter.Begin();
198 if (maskIter.Value() > 0 &&
200 imageIter.Get() == imageIter.Get() &&
201 ciValue.Get() == ciValue.Get() &&
202 region.IsInside(maskOffsetIter.GetIndex() + ciMask.GetNeighborhoodOffset()))
204 int i = holder.IntensityToIndex(imageIter.Get());
205 int j = holder.IntensityToIndex(ciValue.Get());
206 holder.m_Matrix(i, j) += 1;
207 holder.m_Matrix(j, i) += 1;
217 mitk::CoocurenceMatrixHolder &holder,
218 mitk::CoocurenceMatrixFeatures & results
221 auto pijMatrix = holder.m_Matrix;
222 auto piMatrix = holder.m_Matrix;
223 auto pjMatrix = holder.m_Matrix;
224 double Ng = holder.m_NumberOfBins;
225 int NgSize = holder.m_NumberOfBins;
226 pijMatrix /= pijMatrix.sum();
227 piMatrix.rowwise().normalize();
228 pjMatrix.colwise().normalize();
230 for (
int i = 0; i < holder.m_NumberOfBins; ++i)
231 for (
int j = 0; j < holder.m_NumberOfBins; ++j)
233 if (pijMatrix(i, j) != pijMatrix(i, j))
235 if (piMatrix(i, j) != piMatrix(i, j))
237 if (pjMatrix(i, j) != pjMatrix(i, j))
241 Eigen::VectorXd piVector = pijMatrix.colwise().sum();
242 Eigen::VectorXd pjVector = pijMatrix.rowwise().sum();
244 for (
int i = 0; i < holder.m_NumberOfBins; ++i)
247 results.RowAverage += iInt * piVector(i);
250 results.RowEntropy -= piVector(i) * std::log(piVector(i)) / std::log(2);
253 for (
int i = 0; i < holder.m_NumberOfBins; ++i)
256 results.RowVariance += (iInt - results.RowAverage)*(iInt - results.RowAverage) * piVector(i);
258 results.RowMaximum = piVector.maxCoeff();
259 sigmai = std::sqrt(results.RowVariance);
261 Eigen::VectorXd pimj(NgSize);
263 Eigen::VectorXd pipj(2*NgSize);
267 results.JointMaximum += pijMatrix.maxCoeff();
269 for (
int i = 0; i < holder.m_NumberOfBins; ++i)
271 for (
int j = 0; j < holder.m_NumberOfBins; ++j)
277 double pij = pijMatrix(i, j);
279 int deltaK = (i - j)>0?(i-j) : (j-i);
283 results.JointAverage += iInt * pij;
286 results.JointEntropy -= pij * std::log(pij) / std::log(2);
287 results.FirstRowColumnEntropy -= pij * std::log(piVector(i)*pjVector(j)) / std::log(2);
289 if (piVector(i) > 0 && pjVector(j) > 0 )
291 results.SecondRowColumnEntropy -= piVector(i)*pjVector(j) * std::log(piVector(i)*pjVector(j)) / std::log(2);
293 results.AngularSecondMoment += pij*pij;
294 results.Contrast += (iInt - jInt)* (iInt - jInt) * pij;
295 results.Dissimilarity += std::abs<double>(iInt - jInt) * pij;
296 results.InverseDifference += pij / (1 + (std::abs<double>(iInt - jInt)));
297 results.InverseDifferenceNormalised += pij / (1 + (std::abs<double>(iInt - jInt) / Ng));
298 results.InverseDifferenceMoment += pij / (1 + (iInt - jInt)*(iInt - jInt));
299 results.InverseDifferenceMomentNormalised += pij / (1 + (iInt - jInt)*(iInt - jInt)/Ng/Ng);
300 results.Autocorrelation += iInt*jInt * pij;
301 double cluster = (iInt + jInt - 2 * results.RowAverage);
302 results.ClusterTendency += cluster*cluster * pij;
303 results.ClusterShade += cluster*cluster*cluster * pij;
304 results.ClusterProminence += cluster*cluster*cluster*cluster * pij;
307 results.InverseVariance += pij / (iInt - jInt) / (iInt - jInt);
311 results.Correlation = 1 / sigmai / sigmai * (-results.RowAverage*results.RowAverage+ results.Autocorrelation);
312 results.FirstMeasureOfInformationCorrelation = (results.JointEntropy - results.FirstRowColumnEntropy) / results.RowEntropy;
313 if (results.JointEntropy < results.SecondRowColumnEntropy)
315 results.SecondMeasureOfInformationCorrelation = sqrt(1 - exp(-2 * (results.SecondRowColumnEntropy - results.JointEntropy)));
319 results.SecondMeasureOfInformationCorrelation = 0;
322 for (
int i = 0; i < holder.m_NumberOfBins; ++i)
324 for (
int j = 0; j < holder.m_NumberOfBins; ++j)
329 double pij = pijMatrix(i, j);
331 results.JointVariance += (iInt - results.JointAverage)* (iInt - results.JointAverage)*pij;
335 for (
int k = 0;
k < NgSize; ++
k)
337 results.DifferenceAverage +=
k* pimj(
k);
340 results.DifferenceEntropy -= pimj(
k) * log(pimj(
k)) / std::log(2);
343 for (
int k = 0;
k < NgSize; ++
k)
345 results.DifferenceVariance += (results.DifferenceAverage-
k)* (results.DifferenceAverage-
k)*pimj(
k);
349 for (
int k = 0;
k <2* NgSize ; ++
k)
351 results.SumAverage += (2+
k)* pipj(
k);
354 results.SumEntropy -= pipj(
k) * log(pipj(
k)) / std::log(2);
357 for (
int k = 0;
k < 2*NgSize; ++
k)
359 results.SumVariance += (2+
k - results.SumAverage)* (2+
k - results.SumAverage)*pipj(
k);
376 template<
typename TPixel,
unsigned int VImageDimension>
380 typedef itk::Image<unsigned short, VImageDimension> MaskType;
381 typedef itk::Neighborhood<TPixel, VImageDimension > NeighborhoodType;
382 typedef itk::Offset<VImageDimension> OffsetType;
387 int numberOfBins = config.
Bins;
389 typename MaskType::Pointer maskImage = MaskType::New();
393 std::vector < itk::Offset<VImageDimension> > offsetVector;
394 NeighborhoodType hood;
396 unsigned int centerIndex = hood.GetCenterNeighborhoodIndex();
398 for (
unsigned int d = 0; d < centerIndex; d++)
400 offset = hood.GetOffset(d);
401 bool useOffset =
true;
402 for (
unsigned int i = 0; i < VImageDimension; ++i)
404 offset[i] *= config.
range;
405 if (config.
direction == i + 2 && offset[i] != 0)
412 offsetVector.push_back(offset);
417 offsetVector.clear();
423 std::vector<mitk::CoocurenceMatrixFeatures> resultVector;
424 mitk::CoocurenceMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins);
425 mitk::CoocurenceMatrixFeatures overallFeature;
426 for (std::size_t i = 0; i < offsetVector.size(); ++i)
430 if (offsetVector[i][config.
direction - 2] != 0)
437 offset = offsetVector[i];
438 mitk::CoocurenceMatrixHolder holder(rangeMin, rangeMax, numberOfBins);
439 mitk::CoocurenceMatrixFeatures coocResults;
440 CalculateCoOcMatrix<TPixel, VImageDimension>(itkImage, maskImage,
offset, config.
range, holder);
441 holderOverall.m_Matrix += holder.m_Matrix;
443 resultVector.push_back(coocResults);
449 mitk::CoocurenceMatrixFeatures featureMean;
450 mitk::CoocurenceMatrixFeatures featureStd;
453 std::ostringstream ss;
455 std::string strRange = ss.str();
468 featureList.push_back(std::make_pair(prefix +
"Joint Maximum", features.JointMaximum));
469 featureList.push_back(std::make_pair(prefix +
"Joint Average", features.JointAverage));
470 featureList.push_back(std::make_pair(prefix +
"Joint Variance", features.JointVariance));
471 featureList.push_back(std::make_pair(prefix +
"Joint Entropy", features.JointEntropy));
472 featureList.push_back(std::make_pair(prefix +
"Difference Average", features.DifferenceAverage));
473 featureList.push_back(std::make_pair(prefix +
"Difference Variance", features.DifferenceVariance));
474 featureList.push_back(std::make_pair(prefix +
"Difference Entropy", features.DifferenceEntropy));
475 featureList.push_back(std::make_pair(prefix +
"Sum Average", features.SumAverage));
476 featureList.push_back(std::make_pair(prefix +
"Sum Variance", features.SumVariance));
477 featureList.push_back(std::make_pair(prefix +
"Sum Entropy", features.SumEntropy));
478 featureList.push_back(std::make_pair(prefix +
"Angular Second Moment", features.AngularSecondMoment));
479 featureList.push_back(std::make_pair(prefix +
"Contrast", features.Contrast));
480 featureList.push_back(std::make_pair(prefix +
"Dissimilarity", features.Dissimilarity));
481 featureList.push_back(std::make_pair(prefix +
"Inverse Difference", features.InverseDifference));
482 featureList.push_back(std::make_pair(prefix +
"Inverse Difference Normalized", features.InverseDifferenceNormalised));
483 featureList.push_back(std::make_pair(prefix +
"Inverse Difference Moment", features.InverseDifferenceMoment));
484 featureList.push_back(std::make_pair(prefix +
"Inverse Difference Moment Normalized", features.InverseDifferenceMomentNormalised));
485 featureList.push_back(std::make_pair(prefix +
"Inverse Variance", features.InverseVariance));
486 featureList.push_back(std::make_pair(prefix +
"Correlation", features.Correlation));
487 featureList.push_back(std::make_pair(prefix +
"Autocorrelation", features.Autocorrelation));
488 featureList.push_back(std::make_pair(prefix +
"Cluster Tendency", features.ClusterTendency));
489 featureList.push_back(std::make_pair(prefix +
"Cluster Shade", features.ClusterShade));
490 featureList.push_back(std::make_pair(prefix +
"Cluster Prominence", features.ClusterProminence));
491 featureList.push_back(std::make_pair(prefix +
"First Measure of Information Correlation", features.FirstMeasureOfInformationCorrelation));
492 featureList.push_back(std::make_pair(prefix +
"Second Measure of Information Correlation", features.SecondMeasureOfInformationCorrelation));
493 featureList.push_back(std::make_pair(prefix +
"Row Maximum", features.RowMaximum));
494 featureList.push_back(std::make_pair(prefix +
"Row Average", features.RowAverage));
495 featureList.push_back(std::make_pair(prefix +
"Row Variance", features.RowVariance));
496 featureList.push_back(std::make_pair(prefix +
"Row Entropy", features.RowEntropy));
497 featureList.push_back(std::make_pair(prefix +
"First Row-Column Entropy", features.FirstRowColumnEntropy));
498 featureList.push_back(std::make_pair(prefix +
"Second Row-Column Entropy", features.SecondRowColumnEntropy));
503 mitk::CoocurenceMatrixFeatures &meanFeature,
504 mitk::CoocurenceMatrixFeatures &stdFeature)
506 #define ADDFEATURE(a) \ 507 if ( ! (featureList[i].a == featureList[i].a)) featureList[i].a = 0; \ 508 meanFeature.a += featureList[i].a;stdFeature.a += featureList[i].a*featureList[i].a 509 #define CALCVARIANCE(a) stdFeature.a =sqrt(stdFeature.a - meanFeature.a*meanFeature.a) 511 for (std::size_t i = 0; i < featureList.size(); ++i)
535 ADDFEATURE(InverseDifferenceMomentNormalised);
542 ADDFEATURE(FirstMeasureOfInformationCorrelation);
543 ADDFEATURE(SecondMeasureOfInformationCorrelation);
588 features.JointMaximum = features.JointMaximum / number;
589 features.JointAverage = features.JointAverage / number;
590 features.JointVariance = features.JointVariance / number;
591 features.JointEntropy = features.JointEntropy / number;
592 features.RowMaximum = features.RowMaximum / number;
593 features.RowAverage = features.RowAverage / number;
594 features.RowVariance = features.RowVariance / number;
595 features.RowEntropy = features.RowEntropy / number;
596 features.FirstRowColumnEntropy = features.FirstRowColumnEntropy / number;
597 features.SecondRowColumnEntropy = features.SecondRowColumnEntropy / number;
598 features.DifferenceAverage = features.DifferenceAverage / number;
599 features.DifferenceVariance = features.DifferenceVariance / number;
600 features.DifferenceEntropy = features.DifferenceEntropy / number;
601 features.SumAverage = features.SumAverage / number;
602 features.SumVariance = features.SumVariance / number;
603 features.SumEntropy = features.SumEntropy / number;
604 features.AngularSecondMoment = features.AngularSecondMoment / number;
605 features.Contrast = features.Contrast / number;
606 features.Dissimilarity = features.Dissimilarity / number;
607 features.InverseDifference = features.InverseDifference / number;
608 features.InverseDifferenceNormalised = features.InverseDifferenceNormalised / number;
609 features.InverseDifferenceMoment = features.InverseDifferenceMoment / number;
610 features.InverseDifferenceMomentNormalised = features.InverseDifferenceMomentNormalised / number;
611 features.InverseVariance = features.InverseVariance / number;
612 features.Correlation = features.Correlation / number;
613 features.Autocorrelation = features.Autocorrelation / number;
614 features.ClusterShade = features.ClusterShade / number;
615 features.ClusterTendency = features.ClusterTendency / number;
616 features.ClusterProminence = features.ClusterProminence / number;
617 features.FirstMeasureOfInformationCorrelation = features.FirstMeasureOfInformationCorrelation / number;
618 features.SecondMeasureOfInformationCorrelation = features.SecondMeasureOfInformationCorrelation / number;
637 config.
range = m_Range;
676 std::vector<double> ranges;
678 if (parsedArgs.count(name +
"::range"))
680 ranges =
SplitDouble(parsedArgs[name +
"::range"].ToString(),
';');
687 for (std::size_t i = 0; i < ranges.size(); ++i)
689 MITK_INFO <<
"Start calculating coocurence with range " << ranges[i] <<
"....";
692 featureList.insert(featureList.end(), localResults.begin(), localResults.end());
693 MITK_INFO <<
"Finished calculating coocurence with range " << ranges[i] <<
"....";
701 std::ostringstream ss;
703 std::string strRange = ss.str();
#define AccessByItk_3(mitkImage, itkImageTypeFunction, arg1, arg2, arg3)
void CalculateCoOcMatrix(itk::Image< TPixel, VImageDimension > *itkImage, itk::Image< unsigned short, VImageDimension > *mask, itk::Offset< VImageDimension > offset, int range, mitk::CoocurenceMatrixHolder &holder)
std::vector< std::string > FeatureNameListType
itk::Image< unsigned char, 3 > ImageType
virtual void SetLongName(std::string _arg)
DataCollection - Class to facilitate loading/accessing structured data.
static void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, std::string prefix, mitk::GIFCooccurenceMatrix2::FeatureListType &featureList)
void addArgument(const std::string &longarg, const std::string &shortarg, Type type, const std::string &argLabel, const std::string &argHelp=std::string(), const us::Any &defaultValue=us::Any(), bool optional=true, bool ignoreRest=false, bool deprecated=false, mitkCommandLineParser::Channel channel=mitkCommandLineParser::Channel::None)
virtual void SetShortName(std::string _arg)
static void CalculateMeanAndStdDevFeatures(std::vector< mitk::CoocurenceMatrixFeatures > featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature)
std::vector< std::pair< std::string, double > > FeatureListType
std::string QuantifierParameterString()
std::string FeatureDescriptionPrefix()
Returns a string that encodes the feature class name.
virtual std::string GetLongName() const
std::string GetOptionPrefix() const
void CalculateCoocurenceFeatures(itk::Image< TPixel, VImageDimension > *itkImage, mitk::Image::Pointer mask, mitk::GIFCooccurenceMatrix2::FeatureListType &featureList, mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2Configuration config)
void AddArguments(mitkCommandLineParser &parser) override
itk::Image< unsigned char, 3 > MaskImageType
FeatureListType CalculateFeatures(const Image::Pointer &image, const Image::Pointer &feature) override
Calculates the Cooccurence-Matrix based features for this class.
virtual int GetDirection() const
mitk::Image::Pointer image
void AddQuantifierArguments(mitkCommandLineParser &parser)
std::vector< double > SplitDouble(std::string str, char delimiter)
virtual void SetFeatureClassName(std::string _arg)
void MITKCORE_EXPORT CastToItkImage(const mitk::Image *mitkImage, itk::SmartPointer< ItkOutputImageType > &itkOutputImage)
Cast an mitk::Image to an itk::Image with a specific type.
mitk::Image::Pointer mask
FeatureListType CalculateFeatures(const Image::Pointer &image, const Image::Pointer &feature) override
Calculates the Cooccurence-Matrix based features for this class.
virtual IntensityQuantifier::Pointer GetQuantifier()
void InitializeQuantifierFromParameters(const Image::Pointer &feature, const Image::Pointer &mask, unsigned int defaultBins=256)
FeatureNameListType GetFeatureNames() override
Returns a list of the names of all features that are calculated from this class.
void CalculateFeaturesUsingParameters(const Image::Pointer &feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList) override
Calculates the feature of this abstact interface. Does not necessarily considers the parameter settin...
std::string GetCurrentFeatureEncoding() override
Adds an additional Separator to the name of the feature, which encodes the used parameters.
void InitializeQuantifier(const Image::Pointer &feature, const Image::Pointer &mask, unsigned int defaultBins=256)
virtual ParameterTypes GetParameter() const
static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::vcl_size_t number)
virtual void SetRange(double _arg)