/*========================================================================= * * 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 itkSpatialObjectToImageStatisticsCalculator_hxx #define itkSpatialObjectToImageStatisticsCalculator_hxx #include "itkImageRegionConstIteratorWithIndex.h" #include "itkMeanSampleFilter.h" #include "itkCovarianceSampleFilter.h" #include "itkImageMaskSpatialObject.h" #include // For max. namespace itk { template SpatialObjectToImageStatisticsCalculator:: SpatialObjectToImageStatisticsCalculator() { m_Image = nullptr; m_SpatialObject = nullptr; m_Mean.Fill(0); m_CovarianceMatrix.SetIdentity(); m_SampleDirection = TSampleDimension - 1; m_InternalImageTime = 0; m_InternalSpatialObjectTime = 0; m_Sum = 0; m_NumberOfPixels = 0; m_Sample = SampleType::New(); } template bool SpatialObjectToImageStatisticsCalculator::ComputeStatistics() { using MeanAlgorithmType = itk::Statistics::MeanSampleFilter; auto meanAlgorithm = MeanAlgorithmType::New(); meanAlgorithm->SetInput(m_Sample); meanAlgorithm->Update(); typename MeanAlgorithmType::MeasurementVectorType mean = meanAlgorithm->GetMean(); for (unsigned int i = 0; i < SampleDimension; ++i) { m_Mean[i] = mean[i]; } using CovarianceAlgorithmType = itk::Statistics::CovarianceSampleFilter; auto covarianceAlgorithm = CovarianceAlgorithmType::New(); covarianceAlgorithm->SetInput(m_Sample); covarianceAlgorithm->Update(); typename CovarianceAlgorithmType::MatrixType covarianceMatrix = covarianceAlgorithm->GetCovarianceMatrix(); for (unsigned int i = 0; i < covarianceMatrix.Rows(); ++i) { for (unsigned int j = 0; j < covarianceMatrix.Rows(); ++j) { m_CovarianceMatrix(i, j) = covarianceMatrix(i, j); } } return true; } template void SpatialObjectToImageStatisticsCalculator::Update() { if (!m_Image || !m_SpatialObject) { itkExceptionMacro("SpatialObjectToImageStatisticsCalculator: set image AND spatialObject."); } // Update only if the image or the spatial object has been modified if ((m_Image->GetMTime() == m_InternalImageTime) && (m_SpatialObject->GetMTime() == m_InternalSpatialObjectTime)) { return; // No need to update } m_InternalImageTime = m_Image->GetMTime(); m_InternalSpatialObjectTime = m_SpatialObject->GetMTime(); m_Sample = SampleType::New(); m_Sample->SetMeasurementVectorSize(SampleDimension); m_NumberOfPixels = 0; m_Sum = 0; // If this is an ImageMaskSpatialObject we cannot use the flood filled // iterator if (!strcmp(m_SpatialObject->GetTypeName().c_str(), "ImageMaskSpatialObject")) { using MaskImageType = Image; using MaskSOType = ImageMaskSpatialObject; typename MaskSOType::Pointer maskSpatialObject = dynamic_cast(m_SpatialObject.GetPointer()); if (maskSpatialObject.IsNull()) { itkExceptionMacro("Invalid dynamic cast."); } typename MaskImageType::ConstPointer maskImage = maskSpatialObject->GetImage(); using MaskIteratorType = ImageRegionConstIteratorWithIndex; MaskIteratorType it(maskImage, maskImage->GetLargestPossibleRegion()); it.GoToBegin(); IndexType ind; PointType pnt; PointType tPnt; VectorType mv; while (!it.IsAtEnd()) { if (it.Get() > 0) // if inside the mask { ind = it.GetIndex(); maskImage->TransformIndexToPhysicalPoint(ind, pnt); tPnt = maskSpatialObject->GetObjectToWorldTransform()->TransformPoint(pnt); ind = m_Image->TransformPhysicalPointToIndex(tPnt); mv[0] = m_Image->GetPixel(ind); m_Sum += static_cast(mv[0]); for (unsigned int i = 1; i < Self::SampleDimension; ++i) { ind[m_SampleDirection] += 1; mv[i] = m_Image->GetPixel(ind); m_Sum += static_cast(mv[i]); } m_Sample->PushBack(mv); ++m_NumberOfPixels; } ++it; } } else { // Get the bounding box m_SpatialObject->ComputeFamilyBoundingBox(SpatialObjectType::MaximumDepth); m_SpatialObject->Update(); const typename SpatialObjectType::BoundingBoxType::BoundsArrayType bounds = m_SpatialObject->GetFamilyBoundingBoxInWorldSpace()->GetBounds(); Point ptMin; Point ptMax; SizeType size; for (unsigned int i = 0; i < Self::ObjectDimension; ++i) { ptMin[i] = bounds[i * 2]; ptMax[i] = bounds[i * 2 + 1]; } auto indMin = m_Image->TransformPhysicalPointToIndex(ptMin); auto indMax = m_Image->TransformPhysicalPointToIndex(ptMax); IndexType imageIndex = m_Image->GetLargestPossibleRegion().GetIndex(); SizeType imageSize = m_Image->GetLargestPossibleRegion().GetSize(); for (unsigned int i = 0; i < Self::ObjectDimension; ++i) { if (indMin[i] > indMax[i]) { int tmpI = indMin[i]; indMin[i] = indMax[i]; indMax[i] = tmpI; } indMin[i] = std::max(indMin[i], imageIndex[i]); size[i] = indMax[i] - indMin[i] + 1; if (indMin[i] + size[i] < imageIndex[i] + imageSize[i]) { size[i] = imageIndex[i] + imageSize[i] - indMin[i]; } } const RegionType region(indMin, size); using IteratorType = ImageRegionConstIteratorWithIndex; IteratorType it(m_Image, region); it.GoToBegin(); IndexType ind; PointType pnt; VectorType mv; while (!it.IsAtEnd()) { ind = it.GetIndex(); m_Image->TransformIndexToPhysicalPoint(ind, pnt); if (m_SpatialObject->IsInsideInWorldSpace(pnt)) { mv[0] = it.Get(); m_Sum += static_cast(mv[0]); for (unsigned int i = 1; i < Self::SampleDimension; ++i) { ind[m_SampleDirection] += 1; mv[i] = m_Image->GetPixel(ind); m_Sum += static_cast(mv[i]); } m_Sample->PushBack(mv); ++m_NumberOfPixels; } ++it; } } this->ComputeStatistics(); } template void SpatialObjectToImageStatisticsCalculator::PrintSelf( std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); itkPrintSelfObjectMacro(Image); itkPrintSelfObjectMacro(SpatialObject); os << indent << "Mean: " << m_Mean << std::endl; os << indent << "Sum: " << static_cast::PrintType>(m_Sum) << std::endl; os << indent << "NumberOfPixels: " << static_cast::PrintType>(m_NumberOfPixels) << std::endl; os << indent << "CovarianceMatrix: " << m_CovarianceMatrix << std::endl; os << indent << "SampleDirection: " << m_SampleDirection << std::endl; os << indent << "InternalImageTime: " << static_cast::PrintType>(m_InternalImageTime) << std::endl; os << indent << "InternalSpatialObjectTime: " << static_cast::PrintType>(m_InternalSpatialObjectTime) << std::endl; os << indent << "ModifiedTime: " << static_cast::PrintType>(m_ModifiedTime) << std::endl; itkPrintSelfObjectMacro(Sample); } } // end namespace itk #endif