/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkStatisticsLabelObject_h #define itkStatisticsLabelObject_h #include "itkShapeLabelObject.h" #include "itkHistogram.h" namespace itk { /** * \class StatisticsLabelObject * \brief A Label object to store the common attributes related to the statistics of the object * * StatisticsLabelObject stores the common attributes related to the statistics of the object * * \author Gaetan Lehmann. Biologie du Developpement et de la Reproduction, INRA de Jouy-en-Josas, France. * * This implementation was taken from the Insight Journal paper: * https://www.insight-journal.org/browse/publication/176 * * \ingroup DataRepresentation * \ingroup ITKLabelMap */ template class ITK_TEMPLATE_EXPORT StatisticsLabelObject : public ShapeLabelObject { public: ITK_DISALLOW_COPY_AND_MOVE(StatisticsLabelObject); /** Standard class type aliases */ using Self = StatisticsLabelObject; using Superclass = ShapeLabelObject; using LabelObjectType = typename Superclass::LabelObjectType; using Pointer = SmartPointer; using ConstPointer = SmartPointer; using ConstWeakPointer = WeakPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** \see LightObject::GetNameOfClass() */ itkOverrideGetNameOfClassMacro(StatisticsLabelObject); using LabelMapType = LabelMap; static constexpr unsigned int ImageDimension = VImageDimension; using typename Superclass::IndexType; using PointType = Point; using LabelType = TLabel; using typename Superclass::LineType; using typename Superclass::LengthType; using MatrixType = Matrix; using VectorType = Vector; using HistogramType = Statistics::Histogram; using typename Superclass::AttributeType; static constexpr AttributeType MINIMUM = 200; static constexpr AttributeType MAXIMUM = 201; static constexpr AttributeType MEAN = 202; static constexpr AttributeType SUM = 203; static constexpr AttributeType STANDARD_DEVIATION = 204; static constexpr AttributeType VARIANCE = 205; static constexpr AttributeType MEDIAN = 206; static constexpr AttributeType MAXIMUM_INDEX = 207; static constexpr AttributeType MINIMUM_INDEX = 208; static constexpr AttributeType CENTER_OF_GRAVITY = 209; // static constexpr AttributeType CENTRAL_MOMENTS = 210; static constexpr AttributeType WEIGHTED_PRINCIPAL_MOMENTS = 211; static constexpr AttributeType WEIGHTED_PRINCIPAL_AXES = 212; static constexpr AttributeType KURTOSIS = 213; static constexpr AttributeType SKEWNESS = 214; static constexpr AttributeType WEIGHTED_ELONGATION = 215; static constexpr AttributeType HISTOGRAM = 216; static constexpr AttributeType WEIGHTED_FLATNESS = 217; static AttributeType GetAttributeFromName(const std::string & s) { if (s == "Minimum") { return MINIMUM; } else if (s == "Maximum") { return MAXIMUM; } else if (s == "Mean") { return MEAN; } else if (s == "Sum") { return SUM; } else if (s == "StandardDeviation") { return STANDARD_DEVIATION; } else if (s == "Variance") { return VARIANCE; } else if (s == "Median") { return MEDIAN; } else if (s == "MaximumIndex") { return MAXIMUM_INDEX; } else if (s == "MinimumIndex") { return MINIMUM_INDEX; } else if (s == "CenterOfGravity") { return CENTER_OF_GRAVITY; } /* else if( s == "CentralMoments" ) { return CENTRAL_MOMENTS; } */ else if (s == "WeightedPrincipalMoments") { return WEIGHTED_PRINCIPAL_MOMENTS; } else if (s == "WeightedPrincipalAxes") { return WEIGHTED_PRINCIPAL_AXES; } else if (s == "Kurtosis") { return KURTOSIS; } else if (s == "Skewness") { return SKEWNESS; } else if (s == "WeightedElongation") { return WEIGHTED_ELONGATION; } else if (s == "Histogram") { return HISTOGRAM; } else if (s == "WeightedFlatness") { return WEIGHTED_FLATNESS; } // can't recognize the name return Superclass::GetAttributeFromName(s); } static std::string GetNameFromAttribute(const AttributeType & a) { switch (a) { case MINIMUM: return "Minimum"; case MAXIMUM: return "Maximum"; case MEAN: return "Mean"; case SUM: return "Sum"; case STANDARD_DEVIATION: return "StandardDeviation"; case VARIANCE: return "Variance"; case MEDIAN: return "Median"; case MAXIMUM_INDEX: return "MaximumIndex"; case MINIMUM_INDEX: return "MinimumIndex"; case CENTER_OF_GRAVITY: return "CenterOfGravity"; /* case CENTRAL_MOMENTS: return "CentralMoments";*/ case WEIGHTED_PRINCIPAL_MOMENTS: return "WeightedPrincipalMoments"; case WEIGHTED_PRINCIPAL_AXES: return "WeightedPrincipalAxes"; case KURTOSIS: return "Kurtosis"; case SKEWNESS: return "Skewness"; case WEIGHTED_ELONGATION: return "WeightedElongation"; case HISTOGRAM: return "Histogram"; case WEIGHTED_FLATNESS: return "WeightedFlatness"; } // can't recognize the name return Superclass::GetNameFromAttribute(a); } using RegionType = ImageRegion; using typename Superclass::CentroidType; template void CopyAttributesFrom(const TSourceLabelObject * src) { Superclass::template CopyAttributesFrom(src); m_Minimum = src->GetMinimum(); m_Maximum = src->GetMaximum(); m_Mean = src->GetMean(); m_Sum = src->GetSum(); m_StandardDeviation = src->GetStandardDeviation(); m_Variance = src->GetVariance(); m_Median = src->GetMedian(); m_MaximumIndex = src->GetMaximumIndex(); m_MinimumIndex = src->GetMinimumIndex(); m_CenterOfGravity = src->GetCenterOfGravity(); // m_CentralMoments = src->GetCentralMoments(); m_WeightedPrincipalMoments = src->GetWeightedPrincipalMoments(); m_WeightedPrincipalAxes = src->GetWeightedPrincipalAxes(); m_Kurtosis = src->GetKurtosis(); m_Skewness = src->GetSkewness(); m_WeightedElongation = src->GetWeightedElongation(); m_Histogram = src->GetHistogram(); m_WeightedFlatness = src->GetWeightedFlatness(); } template void CopyAllFrom(const TSourceLabelObject * src) { itkAssertOrThrowMacro((src != nullptr), "Null Pointer"); this->template CopyLinesFrom(src); this->template CopyAttributesFrom(src); } const double & GetMinimum() const { return m_Minimum; } void SetMinimum(const double v) { m_Minimum = v; } const double & GetMaximum() const { return m_Maximum; } void SetMaximum(const double v) { m_Maximum = v; } const double & GetMean() const { return m_Mean; } void SetMean(const double v) { m_Mean = v; } const double & GetSum() const { return m_Sum; } void SetSum(const double v) { m_Sum = v; } const double & GetStandardDeviation() const { return m_StandardDeviation; } void SetStandardDeviation(const double v) { m_StandardDeviation = v; } const double & GetVariance() const { return m_Variance; } void SetVariance(const double v) { m_Variance = v; } const double & GetMedian() const { return m_Median; } void SetMedian(const double v) { m_Median = v; } const IndexType & GetMaximumIndex() const { return m_MaximumIndex; } void SetMaximumIndex(const IndexType & v) { m_MaximumIndex = v; } const IndexType & GetMinimumIndex() const { return m_MinimumIndex; } void SetMinimumIndex(const IndexType & v) { m_MinimumIndex = v; } const PointType & GetCenterOfGravity() const { return m_CenterOfGravity; } void SetCenterOfGravity(const PointType & v) { m_CenterOfGravity = v; } /* const MatrixType & GetCentralMoments() const { return m_CentralMoments; } void SetCentralMoments( const MatrixType & v ) { m_CentralMoments = v; }*/ const VectorType & GetWeightedPrincipalMoments() const { return m_WeightedPrincipalMoments; } void SetWeightedPrincipalMoments(const VectorType & v) { m_WeightedPrincipalMoments = v; } const MatrixType & GetWeightedPrincipalAxes() const { return m_WeightedPrincipalAxes; } void SetWeightedPrincipalAxes(const MatrixType & v) { m_WeightedPrincipalAxes = v; } const double & GetSkewness() const { return m_Skewness; } void SetSkewness(const double v) { m_Skewness = v; } const double & GetKurtosis() const { return m_Kurtosis; } void SetKurtosis(const double v) { m_Kurtosis = v; } const double & GetWeightedElongation() const { return m_WeightedElongation; } void SetWeightedElongation(const double v) { m_WeightedElongation = v; } const HistogramType * GetHistogram() const { return m_Histogram; } void SetHistogram(const HistogramType * v) { m_Histogram = v; } const double & GetWeightedFlatness() const { return m_WeightedFlatness; } void SetWeightedFlatness(const double v) { m_WeightedFlatness = v; } // some helper methods - not really required, but really useful! /** Affine transform for mapping to and from principal axis */ using AffineTransformType = AffineTransform; using AffineTransformPointer = typename AffineTransformType::Pointer; /** Get the affine transform from principal axes to physical axes * This method returns an affine transform which transforms from * the principal axes coordinate system to physical coordinates. */ AffineTransformPointer GetWeightedPrincipalAxesToPhysicalAxesTransform() const { typename AffineTransformType::MatrixType matrix; typename AffineTransformType::OffsetType offset; for (unsigned int i = 0; i < ImageDimension; ++i) { offset[i] = m_CenterOfGravity[i]; for (unsigned int j = 0; j < ImageDimension; ++j) { matrix[j][i] = m_WeightedPrincipalAxes[i][j]; // Note the transposition } } AffineTransformPointer result = AffineTransformType::New(); result->SetMatrix(matrix); result->SetOffset(offset); return result; } /** Get the affine transform from physical axes to principal axes * This method returns an affine transform which transforms from * the physical coordinate system to the principal axes coordinate * system. */ AffineTransformPointer GetPhysicalAxesToWeightedPrincipalAxesTransform() const { typename AffineTransformType::MatrixType matrix; typename AffineTransformType::OffsetType offset; for (unsigned int i = 0; i < ImageDimension; ++i) { offset[i] = m_CenterOfGravity[i]; for (unsigned int j = 0; j < ImageDimension; ++j) { matrix[j][i] = m_WeightedPrincipalAxes[i][j]; // Note the transposition } } AffineTransformPointer result = AffineTransformType::New(); result->SetMatrix(matrix); result->SetOffset(offset); AffineTransformPointer inverse = AffineTransformType::New(); result->GetInverse(inverse); return inverse; } protected: StatisticsLabelObject() { m_Minimum = 0; m_Maximum = 0; m_Mean = 0; m_Sum = 0; m_StandardDeviation = 0; m_Variance = 0; m_Median = 0; m_MaximumIndex.Fill(0); m_MinimumIndex.Fill(0); m_CenterOfGravity.Fill(0); // m_CentralMoments.Fill(0); m_WeightedPrincipalMoments.Fill(0); m_WeightedPrincipalAxes.Fill(0); m_Kurtosis = 0; m_Skewness = 0; m_WeightedElongation = 0; m_Histogram = nullptr; m_WeightedFlatness = 0; } void PrintSelf(std::ostream & os, Indent indent) const override { Superclass::PrintSelf(os, indent); os << indent << "Minimum: " << m_Minimum << std::endl; os << indent << "Maximum: " << m_Maximum << std::endl; os << indent << "Mean: " << m_Mean << std::endl; os << indent << "Sum: " << m_Sum << std::endl; os << indent << "StandardDeviation: " << m_StandardDeviation << std::endl; os << indent << "Variance: " << m_Variance << std::endl; os << indent << "Median: " << m_Median << std::endl; os << indent << "Skewness: " << m_Skewness << std::endl; os << indent << "Kurtosis: " << m_Kurtosis << std::endl; os << indent << "WeightedElongation: " << m_WeightedElongation << std::endl; os << indent << "WeightedFlatness: " << m_WeightedFlatness << std::endl; os << indent << "MaximumIndex: " << m_MaximumIndex << std::endl; os << indent << "MinimumIndex: " << m_MinimumIndex << std::endl; os << indent << "CenterOfGravity: " << m_CenterOfGravity << std::endl; // os << indent << "CentralMoments: " << std::endl << m_CentralMoments; os << indent << "WeightedPrincipalMoments: " << m_WeightedPrincipalMoments << std::endl; os << indent << "WeightedPrincipalAxes: " << std::endl << m_WeightedPrincipalAxes; itkPrintSelfObjectMacro(Histogram); } private: double m_Minimum{}; double m_Maximum{}; double m_Mean{}; double m_Sum{}; double m_StandardDeviation{}; double m_Variance{}; double m_Median{}; IndexType m_MaximumIndex{}; IndexType m_MinimumIndex{}; PointType m_CenterOfGravity{}; // MatrixType m_CentralMoments; VectorType m_WeightedPrincipalMoments{}; MatrixType m_WeightedPrincipalAxes{}; double m_Skewness{}; double m_Kurtosis{}; double m_WeightedElongation{}; typename HistogramType::ConstPointer m_Histogram{}; double m_WeightedFlatness{}; }; } // end namespace itk #endif