diff --git a/Modules/BasicImageProcessing/include/mitkMaskCleaningOperation.h b/Modules/BasicImageProcessing/include/mitkMaskCleaningOperation.h index a483146e70..0d9371e9c1 100644 --- a/Modules/BasicImageProcessing/include/mitkMaskCleaningOperation.h +++ b/Modules/BasicImageProcessing/include/mitkMaskCleaningOperation.h @@ -1,58 +1,79 @@ /*============================================================================ 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. ============================================================================*/ #ifndef mitkMaskClearningOperation_h #define mitkMaskClearningOperation_h #include #include namespace mitk { - /** \brief Executes operations to clean-up Masks. * * It is assumed that the segmentation is of type */ class MITKBASICIMAGEPROCESSING_EXPORT MaskCleaningOperation { public: + enum DirectionType + { + Axial = 1, + Sagital = 2, + Coronal = 4, + Volume = 7 + }; + /** \brief Limits a Mask to a given Range * * Removes all elements of a mask that are not within the given range. If lowerLimitOn is true, all voxels that * cover voxels with an intensity below lowerLimit will be set to 0 in the resulting mask. Similar, all voxels * that cover voxels with an intensity above upperLimit will be set to 0 if upperLimitOn is true. * * Parameter * - mitk::Image::Pointer image : Grey-Scale image * - mitk::Image::Pointer mask : Original mask * - optional: bool lowerLimitOn : If true, voxels below lowerLimit are not masked, default false * - optional: double lowerLimit : Lower Threshold limit, default 0 * - optional: bool upperLimitOn : If true, voxels above upperLimit are not masked, default false * - optional: double upperLimit : Lower Threshold limit, default 1 */ static Image::Pointer RangeBasedMasking(Image::Pointer & image, Image::Pointer & mask, bool lowerLimitOn=false, double lowerLimit=0, bool upperLimitOn=false, double upperLimit=1); /** \brief Removes outlier from a mask * * Removes all elements of a mask that are not within the range \f$ [\mu - 3 \sigma , \mu + 3 \sigma\] \f$ * * Parameter * - mitk::Image::Pointer image : Grey-Scale image * - mitk::Image::Pointer mask : Original mask */ static Image::Pointer MaskOutlierFiltering(Image::Pointer & image, Image::Pointer & mask); + /** \brief Keeps only the boarder of a given segmentation + * + * Removes the inner elements of a given segmentation, keeping only the outer elements of a given mask. + * The width of the boarder is determined in number of voxels and can be measured either in + * a single direction (axial, sagital or coronal) or in 3D. + * + * Parameter + * - mitk::Image::Pointer mask : The mask that will be processed + * - unsigned int boarderWidth : The width of the boarder in number of pixels/voxels + * - DirectionType direction : The direction that will be considered. + */ + + static Image::Pointer LimitToBoarder(Image::Pointer &mask, unsigned int boarderWidth, DirectionType direction); + }; } #endif // mitkMaskClearningOperation_h diff --git a/Modules/BasicImageProcessing/src/mitkMaskCleaningOperation.cpp b/Modules/BasicImageProcessing/src/mitkMaskCleaningOperation.cpp index 93f301658f..8f6b03a168 100644 --- a/Modules/BasicImageProcessing/src/mitkMaskCleaningOperation.cpp +++ b/Modules/BasicImageProcessing/src/mitkMaskCleaningOperation.cpp @@ -1,138 +1,209 @@ /*============================================================================ 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 "mitkMaskCleaningOperation.h" #include #include #include -#include #include +#include #include +#include +#include +#include #include "itkCastImageFilter.h" namespace mitk { namespace Functor { - template< class TInput, class TOutput> + template class RangeBasedMasking { public: - RangeBasedMasking() {}; - ~RangeBasedMasking() {}; - bool operator!=(const RangeBasedMasking &) const - { - return false; - } - bool operator==(const RangeBasedMasking & other) const - { - return !(*this != other); - } - inline TOutput operator()(const TInput & A, const TOutput & B) const + RangeBasedMasking(){}; + ~RangeBasedMasking(){}; + bool operator!=(const RangeBasedMasking &) const { return false; } + bool operator==(const RangeBasedMasking &other) const { return !(*this != other); } + inline TOutput operator()(const TInput &A, const TOutput &B) const { unsigned short erg = B; if (lowerLimitOn && (A < lowerLimit)) { erg = 0; } if (upperLimitOn && (upperLimit < A)) { erg = 0; } return erg; } bool lowerLimitOn = false; bool upperLimitOn = false; double lowerLimit = 0; double upperLimit = 1; }; - } -} - - - -template -static void ExecuteRangeBasedMasking(itk::Image* image, mitk::Image::Pointer & mask, bool lowerLimitOn, double lowerLimit, bool upperLimitOn, double upperLimit, mitk::Image::Pointer & resultImage) + } // namespace Functor +} // namespace mitk + +template +static void ExecuteRangeBasedMasking(itk::Image *image, + mitk::Image::Pointer &mask, + bool lowerLimitOn, + double lowerLimit, + bool upperLimitOn, + double upperLimit, + mitk::Image::Pointer &resultImage) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; - typedef itk::BinaryFunctorImageFilter< ImageType, MaskImageType, MaskImageType, mitk::Functor::RangeBasedMasking > DefaultFilterType; + typedef itk::BinaryFunctorImageFilter> + DefaultFilterType; typename MaskImageType::Pointer itkMask = MaskImageType::New(); mitk::CastToItkImage(mask.GetPointer(), itkMask); typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); filter->SetInput1(image); filter->SetInput2(itkMask); filter->GetFunctor().lowerLimitOn = lowerLimitOn; filter->GetFunctor().upperLimitOn = upperLimitOn; filter->GetFunctor().lowerLimit = lowerLimit; filter->GetFunctor().upperLimit = upperLimit; filter->Update(); CastToMitkImage(filter->GetOutput(), resultImage); } -mitk::Image::Pointer mitk::MaskCleaningOperation::RangeBasedMasking(Image::Pointer & image, Image::Pointer & mask, bool lowerLimitOn, double lowerLimit, bool upperLimitOn, double upperLimit) +mitk::Image::Pointer mitk::MaskCleaningOperation::RangeBasedMasking(Image::Pointer &image, + Image::Pointer &mask, + bool lowerLimitOn, + double lowerLimit, + bool upperLimitOn, + double upperLimit) { Image::Pointer resultImage; - AccessByItk_n(image, ExecuteRangeBasedMasking, (mask, lowerLimitOn, lowerLimit, upperLimitOn, upperLimit, resultImage)); + AccessByItk_n( + image, ExecuteRangeBasedMasking, (mask, lowerLimitOn, lowerLimit, upperLimitOn, upperLimit, resultImage)); return resultImage; } - -template -static void CalculateMeanAndStd(itk::Image* image, mitk::Image::Pointer & mask, double &mean, double &std) +template +static void CalculateMeanAndStd(itk::Image *image, + mitk::Image::Pointer &mask, + double &mean, + double &std) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typename MaskImageType::Pointer itkMask = MaskImageType::New(); mitk::CastToItkImage(mask.GetPointer(), itkMask); itk::ImageRegionConstIterator image_iter(image, image->GetLargestPossibleRegion()); itk::ImageRegionConstIterator mask_iter(itkMask, itkMask->GetLargestPossibleRegion()); unsigned int number_of_voxels = 0; while (!image_iter.IsAtEnd()) { if (mask_iter.Get() > 0) { mean += image_iter.Get(); std += image_iter.Get() * image_iter.Get(); ++number_of_voxels; } ++image_iter; ++mask_iter; } mean /= number_of_voxels; std /= number_of_voxels; - std -= mean*mean; + std -= mean * mean; std = sqrt(std); MITK_INFO << "Mean: " << mean << " Sigma: " << std; } - -mitk::Image::Pointer mitk::MaskCleaningOperation::MaskOutlierFiltering(Image::Pointer & image, Image::Pointer & mask) +mitk::Image::Pointer mitk::MaskCleaningOperation::MaskOutlierFiltering(Image::Pointer &image, Image::Pointer &mask) { Image::Pointer resultImage; double mean = 0; double std = 0; AccessByItk_n(image, CalculateMeanAndStd, (mask, mean, std)); return MaskCleaningOperation::RangeBasedMasking(image, mask, true, mean - 3 * std, true, mean + 3 * std); +} +template +static void ExecuteLimitToBoarder(itk::Image *mask, + unsigned int boarderWidth, + mitk::MaskCleaningOperation::DirectionType direction, + mitk::Image::Pointer &resultMask) +{ + typedef itk::Image MaskType; + typedef itk::BinaryBallStructuringElement BallType; + typedef typename itk::BinaryErodeImageFilter BallErodeFilterType; + typedef typename itk::SubtractImageFilter SubtractFilterType; + + BallType ball; + typename BallType::SizeType size; + size.Fill(0); + switch (direction) + { + case mitk::MaskCleaningOperation::DirectionType::Axial : + size.SetElement(0, boarderWidth); + size.SetElement(1, boarderWidth); + break; + case mitk::MaskCleaningOperation::DirectionType::Coronal: + size.SetElement(0, boarderWidth); + size.SetElement(2, boarderWidth); + break; + case mitk::MaskCleaningOperation::DirectionType::Sagital: + size.SetElement(1, boarderWidth); + size.SetElement(2, boarderWidth); + break; + default: + size.Fill(boarderWidth); + break; + } + ball.SetRadius(size); + ball.CreateStructuringElement(); + + typename BallErodeFilterType::Pointer erodeFilter = BallErodeFilterType::New(); + erodeFilter->SetKernel(ball); + erodeFilter->SetInput(mask); + erodeFilter->SetErodeValue(1); + erodeFilter->SetBackgroundValue(0); + erodeFilter->UpdateLargestPossibleRegion(); + + typename SubtractFilterType::Pointer subtractFilter = SubtractFilterType::New(); + subtractFilter->SetInput1(mask); + subtractFilter->SetInput2(erodeFilter->GetOutput()); + subtractFilter->UpdateLargestPossibleRegion(); + + CastToMitkImage(subtractFilter->GetOutput(), resultMask); +} + +mitk::Image::Pointer mitk::MaskCleaningOperation::LimitToBoarder(mitk::Image::Pointer &mask, + unsigned int boarderWidth, + DirectionType direction) +{ + Image::Pointer resultImage; + AccessByItk_n( + mask, ExecuteLimitToBoarder, (boarderWidth, direction, resultImage)); + return resultImage; } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp index 56e1f0220e..c6f745f452 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp @@ -1,450 +1,450 @@ /*============================================================================ 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 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); 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(itk::Image* itkImage, 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::ImageRegionIteratorWithIndex ConstIterType; typedef itk::ImageRegionIteratorWithIndex ConstMaskIterType; auto region = mask->GetLargestPossibleRegion(); typename MaskImageType::RegionType newRegion; newRegion.SetSize(region.GetSize()); newRegion.SetIndex(region.GetIndex()); ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); typename MaskImageType::Pointer visitedImage = MaskImageType::New(); visitedImage->SetRegions(newRegion); visitedImage->Allocate(); visitedImage->FillBuffer(0); int largestRegion = 0; while (!maskIter.IsAtEnd()) { if (maskIter.Value() > 0 ) { auto startIntensityIndex = holder.IntensityToIndex(imageIter.Value()); std::vector indices; indices.push_back(maskIter.GetIndex()); unsigned int steps = 0; while (indices.size() > 0) { auto currentIndex = indices.back(); indices.pop_back(); if (!region.IsInside(currentIndex)) { continue; } auto wasVisited = visitedImage->GetPixel(currentIndex); auto newIntensityIndex = holder.IntensityToIndex(itkImage->GetPixel(currentIndex)); auto isInMask = mask->GetPixel(currentIndex); if ((isInMask > 0) && (newIntensityIndex == startIntensityIndex) && (wasVisited < 1)) { ++steps; visitedImage->SetPixel(currentIndex, 1); for (auto offset : offsets) { auto newIndex = currentIndex + offset; indices.push_back(newIndex); newIndex = currentIndex - offset; indices.push_back(newIndex); } } } if (steps > 0) { largestRegion = std::max(steps, largestRegion); steps = std::min(steps, holder.m_MaximumSize); 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 < holder.m_NumberOfBins; ++i) - for (int j = 0; j < holder.m_NumberOfBins; ++j) + 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(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFGreyLevelSizeZone::FeatureListType & featureList, mitk::GIFGreyLevelSizeZone::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.prefix, featureList); } static void MatrixFeaturesTo(mitk::GreyLevelSizeZoneFeatures features, std::string prefix, mitk::GIFGreyLevelSizeZone::FeatureListType &featureList) { featureList.push_back(std::make_pair(prefix + "Small Zone Emphasis", features.SmallZoneEmphasis)); featureList.push_back(std::make_pair(prefix + "Large Zone Emphasis", features.LargeZoneEmphasis)); featureList.push_back(std::make_pair(prefix + "Low Grey Level Emphasis", features.LowGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + "High Grey Level Emphasis", features.HighGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + "Small Zone Low Grey Level Emphasis", features.SmallZoneLowGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + "Small Zone High Grey Level Emphasis", features.SmallZoneHighGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + "Large Zone Low Grey Level Emphasis", features.LargeZoneLowGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + "Large Zone High Grey Level Emphasis", features.LargeZoneHighGreyLevelEmphasis)); featureList.push_back(std::make_pair(prefix + "Grey Level Non-Uniformity", features.GreyLevelNonUniformity)); featureList.push_back(std::make_pair(prefix + "Grey Level Non-Uniformity Normalized", features.GreyLevelNonUniformityNormalized)); featureList.push_back(std::make_pair(prefix + "Zone Size Non-Uniformity", features.ZoneSizeNonUniformity)); featureList.push_back(std::make_pair(prefix + "Zone Size Non-Uniformity Normalized", features.ZoneSizeNoneUniformityNormalized)); featureList.push_back(std::make_pair(prefix + "Zone Percentage", features.ZonePercentage)); featureList.push_back(std::make_pair(prefix + "Grey Level Mean", features.GreyLevelMean)); featureList.push_back(std::make_pair(prefix + "Grey Level Variance", features.GreyLevelVariance)); featureList.push_back(std::make_pair(prefix + "Zone Size Mean", features.ZoneSizeMean)); featureList.push_back(std::make_pair(prefix + "Zone Size Variance", features.ZoneSizeVariance)); featureList.push_back(std::make_pair(prefix + "Zone Size Entropy", features.ZoneSizeEntropy)); } mitk::GIFGreyLevelSizeZone::GIFGreyLevelSizeZone() { SetShortName("glsz"); SetLongName("grey-level-sizezone"); SetFeatureClassName("Grey Level Size Zone"); } mitk::GIFGreyLevelSizeZone::FeatureListType mitk::GIFGreyLevelSizeZone::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { InitializeQuantifier(image, mask); FeatureListType featureList; GIFGreyLevelSizeZoneConfiguration config; config.direction = GetDirection(); config.MinimumIntensity = GetQuantifier()->GetMinimum(); config.MaximumIntensity = GetQuantifier()->GetMaximum(); config.Bins = GetQuantifier()->GetBins(); config.prefix = FeatureDescriptionPrefix(); AccessByItk_3(image, CalculateGreyLevelSizeZoneFeatures, mask, featureList, config); return featureList; } mitk::GIFGreyLevelSizeZone::FeatureNameListType mitk::GIFGreyLevelSizeZone::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFGreyLevelSizeZone::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Grey Level Size Zone", "Calculates the size zone based features.", us::Any()); AddQuantifierArguments(parser); } void mitk::GIFGreyLevelSizeZone::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); std::string name = GetOptionPrefix(); if (parsedArgs.count(GetLongName())) { InitializeQuantifierFromParameters(feature, maskNoNAN); MITK_INFO << "Start calculating Grey leve size zone ..."; auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating Grey level size zone ..."; } } std::string mitk::GIFGreyLevelSizeZone::GetCurrentFeatureEncoding() { return QuantifierParameterString(); } diff --git a/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp b/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp index 7f011e2a9e..a11b1ee0be 100644 --- a/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp +++ b/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp @@ -1,414 +1,419 @@ /*============================================================================ 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 "mitkMorphologicalOperations.h" #include #include #include #include #include #include #include #include #include #include #include -void mitk::MorphologicalOperations::Closing(mitk::Image::Pointer &image, +mitk::Image::Pointer mitk::MorphologicalOperations::Closing(mitk::Image::Pointer &image, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElement) { MITK_INFO << "Start Closing..."; auto timeSteps = static_cast(image->GetTimeSteps()); if (timeSteps > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(image); for (int t = 0; t < timeSteps; ++t) { MITK_INFO << " Processing time step " << t; timeSelector->SetTimeNr(t); timeSelector->Update(); mitk::Image::Pointer img3D = timeSelector->GetOutput(); img3D->DisconnectPipeline(); AccessByItk_3(img3D, itkClosing, img3D, factor, structuralElement); mitk::ImageReadAccessor accessor(img3D); image->SetVolume(accessor.GetData(), t); } } else { AccessByItk_3(image, itkClosing, image, factor, structuralElement); } - + return image; MITK_INFO << "Finished Closing"; } -void mitk::MorphologicalOperations::Erode(mitk::Image::Pointer &image, +mitk::Image::Pointer mitk::MorphologicalOperations::Erode(mitk::Image::Pointer &image, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElement) { MITK_INFO << "Start Erode..."; auto timeSteps = static_cast(image->GetTimeSteps()); if (timeSteps > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(image); for (int t = 0; t < timeSteps; ++t) { MITK_INFO << " Processing time step " << t; timeSelector->SetTimeNr(t); timeSelector->Update(); mitk::Image::Pointer img3D = timeSelector->GetOutput(); img3D->DisconnectPipeline(); AccessByItk_3(img3D, itkErode, img3D, factor, structuralElement); mitk::ImageReadAccessor accessor(img3D); image->SetVolume(accessor.GetData(), t); } } else { - AccessByItk_3(image, itkErode, image, factor, structuralElement); + mitk::Image::Pointer ergImage = mitk::Image::New(); + AccessByItk_3(image, itkErode, ergImage, factor, structuralElement); + mitk::ImageReadAccessor accessor(ergImage); + image->SetVolume(accessor.GetData(), 0); } + return image; MITK_INFO << "Finished Erode"; } -void mitk::MorphologicalOperations::Dilate(mitk::Image::Pointer &image, +mitk::Image::Pointer mitk::MorphologicalOperations::Dilate( + mitk::Image::Pointer &image, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElement) { MITK_INFO << "Start Dilate..."; auto timeSteps = static_cast(image->GetTimeSteps()); if (timeSteps > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(image); for (int t = 0; t < timeSteps; ++t) { MITK_INFO << " Processing time step " << t; timeSelector->SetTimeNr(t); timeSelector->Update(); mitk::Image::Pointer img3D = timeSelector->GetOutput(); img3D->DisconnectPipeline(); AccessByItk_3(img3D, itkDilate, img3D, factor, structuralElement); mitk::ImageReadAccessor accessor(img3D); image->SetVolume(accessor.GetData(), t); } } else { AccessByItk_3(image, itkDilate, image, factor, structuralElement); } - + return image; MITK_INFO << "Finished Dilate"; } -void mitk::MorphologicalOperations::Opening(mitk::Image::Pointer &image, +mitk::Image::Pointer mitk::MorphologicalOperations::Opening(mitk::Image::Pointer &image, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElement) { MITK_INFO << "Start Opening..."; auto timeSteps = static_cast(image->GetTimeSteps()); if (timeSteps > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(image); for (int t = 0; t < timeSteps; ++t) { MITK_INFO << " Processing time step " << t; timeSelector->SetTimeNr(t); timeSelector->Update(); mitk::Image::Pointer img3D = timeSelector->GetOutput(); img3D->DisconnectPipeline(); AccessByItk_3(img3D, itkOpening, img3D, factor, structuralElement); mitk::ImageReadAccessor accessor(img3D); image->SetVolume(accessor.GetData(), t); } } else { AccessByItk_3(image, itkOpening, image, factor, structuralElement); } - + return image; MITK_INFO << "Finished Opening"; } -void mitk::MorphologicalOperations::FillHoles(mitk::Image::Pointer &image) +mitk::Image::Pointer mitk::MorphologicalOperations::FillHoles(mitk::Image::Pointer &image) { MITK_INFO << "Start FillHole..."; auto timeSteps = static_cast(image->GetTimeSteps()); if (timeSteps > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(image); for (int t = 0; t < timeSteps; ++t) { MITK_INFO << " Processing time step " << t; timeSelector->SetTimeNr(t); timeSelector->Update(); mitk::Image::Pointer img3D = timeSelector->GetOutput(); img3D->DisconnectPipeline(); AccessByItk_1(img3D, itkFillHoles, img3D); mitk::ImageReadAccessor accessor(img3D); image->SetVolume(accessor.GetData(), t); } } else { AccessByItk_1(image, itkFillHoles, image); } - + return image; MITK_INFO << "Finished FillHole"; } template void mitk::MorphologicalOperations::itkClosing( itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElementFlags) { typedef itk::Image ImageType; typedef itk::BinaryBallStructuringElement BallType; typedef itk::BinaryCrossStructuringElement CrossType; typedef typename itk::BinaryMorphologicalClosingImageFilter BallClosingFilterType; typedef typename itk::BinaryMorphologicalClosingImageFilter CrossClosingFilterType; if (structuralElementFlags & (Ball_Axial | Ball_Coronal | Ball_Sagital)) { BallType ball = CreateStructuringElement(structuralElementFlags, factor); typename BallClosingFilterType::Pointer closingFilter = BallClosingFilterType::New(); closingFilter->SetKernel(ball); closingFilter->SetInput(sourceImage); closingFilter->SetForegroundValue(1); closingFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(closingFilter->GetOutput(), resultImage); } else { CrossType cross = CreateStructuringElement(structuralElementFlags, factor); typename CrossClosingFilterType::Pointer closingFilter = CrossClosingFilterType::New(); closingFilter->SetKernel(cross); closingFilter->SetInput(sourceImage); closingFilter->SetForegroundValue(1); closingFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(closingFilter->GetOutput(), resultImage); } } template void mitk::MorphologicalOperations::itkErode( itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElementFlags) { typedef itk::Image ImageType; typedef itk::BinaryBallStructuringElement BallType; typedef itk::BinaryCrossStructuringElement CrossType; typedef typename itk::BinaryErodeImageFilter BallErodeFilterType; typedef typename itk::BinaryErodeImageFilter CrossErodeFilterType; if (structuralElementFlags & (Ball_Axial | Ball_Coronal | Ball_Sagital)) { BallType ball = CreateStructuringElement(structuralElementFlags, factor); typename BallErodeFilterType::Pointer erodeFilter = BallErodeFilterType::New(); erodeFilter->SetKernel(ball); erodeFilter->SetInput(sourceImage); erodeFilter->SetErodeValue(1); erodeFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(erodeFilter->GetOutput(), resultImage); } else { CrossType cross = CreateStructuringElement(structuralElementFlags, factor); typename CrossErodeFilterType::Pointer erodeFilter = CrossErodeFilterType::New(); erodeFilter->SetKernel(cross); erodeFilter->SetInput(sourceImage); erodeFilter->SetErodeValue(1); erodeFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(erodeFilter->GetOutput(), resultImage); } } template void mitk::MorphologicalOperations::itkDilate( itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElementFlags) { typedef itk::Image ImageType; typedef itk::BinaryBallStructuringElement BallType; typedef itk::BinaryCrossStructuringElement CrossType; typedef typename itk::BinaryDilateImageFilter BallDilateFilterType; typedef typename itk::BinaryDilateImageFilter CrossDilateFilterType; if (structuralElementFlags & (Ball_Axial | Ball_Coronal | Ball_Sagital)) { BallType ball = CreateStructuringElement(structuralElementFlags, factor); typename BallDilateFilterType::Pointer dilateFilter = BallDilateFilterType::New(); dilateFilter->SetKernel(ball); dilateFilter->SetInput(sourceImage); dilateFilter->SetDilateValue(1); dilateFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(dilateFilter->GetOutput(), resultImage); } else { CrossType cross = CreateStructuringElement(structuralElementFlags, factor); typename CrossDilateFilterType::Pointer dilateFilter = CrossDilateFilterType::New(); dilateFilter->SetKernel(cross); dilateFilter->SetInput(sourceImage); dilateFilter->SetDilateValue(1); dilateFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(dilateFilter->GetOutput(), resultImage); } } template void mitk::MorphologicalOperations::itkOpening( itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElementFlags) { typedef itk::Image ImageType; typedef itk::BinaryBallStructuringElement BallType; typedef itk::BinaryCrossStructuringElement CrossType; typedef typename itk::BinaryMorphologicalOpeningImageFilter BallOpeningFiltertype; typedef typename itk::BinaryMorphologicalOpeningImageFilter CrossOpeningFiltertype; if (structuralElementFlags & (Ball_Axial | Ball_Coronal | Ball_Sagital)) { BallType ball = CreateStructuringElement(structuralElementFlags, factor); typename BallOpeningFiltertype::Pointer openingFilter = BallOpeningFiltertype::New(); openingFilter->SetKernel(ball); openingFilter->SetInput(sourceImage); openingFilter->SetForegroundValue(1); openingFilter->SetBackgroundValue(0); openingFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(openingFilter->GetOutput(), resultImage); } else { CrossType cross = CreateStructuringElement(structuralElementFlags, factor); typename CrossOpeningFiltertype::Pointer openingFilter = CrossOpeningFiltertype::New(); openingFilter->SetKernel(cross); openingFilter->SetInput(sourceImage); openingFilter->SetForegroundValue(1); openingFilter->SetBackgroundValue(0); openingFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(openingFilter->GetOutput(), resultImage); } } template void mitk::MorphologicalOperations::itkFillHoles(itk::Image *sourceImage, mitk::Image::Pointer &resultImage) { typedef itk::Image ImageType; typedef typename itk::BinaryFillholeImageFilter FillHoleFilterType; typename FillHoleFilterType::Pointer fillHoleFilter = FillHoleFilterType::New(); fillHoleFilter->SetInput(sourceImage); fillHoleFilter->SetForegroundValue(1); fillHoleFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(fillHoleFilter->GetOutput(), resultImage); } template TStructuringElement mitk::MorphologicalOperations::CreateStructuringElement(StructuralElementType structuralElementFlag, int factor) { TStructuringElement strElem; typename TStructuringElement::SizeType size; size.Fill(0); switch (structuralElementFlag) { case Ball_Axial: case Cross_Axial: size.SetElement(0, factor); size.SetElement(1, factor); break; case Ball_Coronal: case Cross_Coronal: size.SetElement(0, factor); size.SetElement(2, factor); break; case Ball_Sagital: case Cross_Sagital: size.SetElement(1, factor); size.SetElement(2, factor); break; case Ball: case Cross: size.Fill(factor); break; } strElem.SetRadius(size); strElem.CreateStructuringElement(); return strElem; } diff --git a/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.h b/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.h index d5c7ebe3d6..194314971e 100644 --- a/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.h +++ b/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.h @@ -1,89 +1,89 @@ /*============================================================================ 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. ============================================================================*/ #ifndef mitkMorphologicalOperations_h #define mitkMorphologicalOperations_h #include #include namespace mitk { /** \brief Encapsulates several morphological operations that can be performed on segmentations. */ class MITKSEGMENTATION_EXPORT MorphologicalOperations { public: enum StructuralElementType { Ball = 7, Ball_Axial = 1, Ball_Sagital = 2, Ball_Coronal = 4, Cross = 56, Cross_Axial = 8, Cross_Sagital = 16, Cross_Coronal = 32 }; ///@{ /** \brief Perform morphological operation on 2D, 3D or 3D+t segmentation. */ - static void Closing(mitk::Image::Pointer &image, int factor, StructuralElementType structuralElement); - static void Erode(mitk::Image::Pointer &image, int factor, StructuralElementType structuralElement); - static void Dilate(mitk::Image::Pointer &image, int factor, StructuralElementType structuralElement); - static void Opening(mitk::Image::Pointer &image, int factor, StructuralElementType structuralElement); - static void FillHoles(mitk::Image::Pointer &image); + static Image::Pointer Closing(mitk::Image::Pointer &image, int factor, StructuralElementType structuralElement); + static Image::Pointer Erode(mitk::Image::Pointer &image, int factor, StructuralElementType structuralElement); + static Image::Pointer Dilate(mitk::Image::Pointer &image, int factor, StructuralElementType structuralElement); + static Image::Pointer Opening(mitk::Image::Pointer &image, int factor, StructuralElementType structuralElement); + static Image::Pointer FillHoles(mitk::Image::Pointer &image); ///@} private: MorphologicalOperations(); template static TStructuringElement CreateStructuringElement(StructuralElementType structuralElementFlag, int factor); ///@{ /** \brief Perform morphological operation by using corresponding ITK filter. */ template static void itkClosing(itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, StructuralElementType structuralElement); template static void itkErode(itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, StructuralElementType structuralElement); template static void itkDilate(itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, StructuralElementType structuralElement); template static void itkOpening(itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, StructuralElementType structuralElement); template static void itkFillHoles(itk::Image *sourceImage, mitk::Image::Pointer &resultImage); ///@} }; } #endif