diff --git a/Modules/Classification/CLUtilities/files.cmake b/Modules/Classification/CLUtilities/files.cmake index 35294a897a..22a91df6b0 100644 --- a/Modules/Classification/CLUtilities/files.cmake +++ b/Modules/Classification/CLUtilities/files.cmake @@ -1,25 +1,26 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES Algorithms/itkLabelSampler.cpp Algorithms/itkSmoothedClassProbabilites.cpp Algorithms/mitkRandomImageSampler.cpp Features/itkNeighborhoodFunctorImageFilter.cpp Features/itkLineHistogramBasedMassImageFilter.cpp GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp GlobalImageFeatures/mitkGIFGrayLevelRunLength.cpp + GlobalImageFeatures/mitkGIFGrayLevelSizeZone.cpp GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp #GlobalImageFeatures/itkEnhancedScalarImageToRunLengthFeaturesFilter.hxx #GlobalImageFeatures/itkEnhancedScalarImageToRunLengthMatrixFilter.hxx #GlobalImageFeatures/itkEnhancedHistogramToRunLengthFeaturesFilter.hxx #GlobalImageFeatures/itkEnhancedHistogramToTextureFeaturesFilter.hxx #GlobalImageFeatures/itkEnhancedScalarImageToTextureFeaturesFilter.hxx mitkCLUtil.cpp ) set( TOOL_FILES ) diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.h new file mode 100644 index 0000000000..a0fb584a3f --- /dev/null +++ b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.h @@ -0,0 +1,230 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +/*========================================================================= +* +* Copyright Insight Software Consortium +* +* 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 +* +* http://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 __itkEnhancedHistogramToSizeZoneFeaturesFilter_h +#define __itkEnhancedHistogramToSizeZoneFeaturesFilter_h + +#include "itkHistogram.h" +#include "itkMacro.h" +#include "itkProcessObject.h" +#include "itkSimpleDataObjectDecorator.h" + +namespace itk { + namespace Statistics { + /** \class EnhancedHistogramToSizeZoneFeaturesFilter + * \brief This class computes texture feature coefficients from a grey level + * Zone-length matrix. + * + * By default, Zone length features are computed for each spatial + * direction and then averaged afterward, so it is possible to access the + * standard deviations of the texture features. These values give a clue as + * to texture anisotropy. However, doing this is much more work, because it + * involved computing one for each offset given. To compute a single matrix + * using the first offset, call FastCalculationsOn(). If this is called, + * then the texture standard deviations will not be computed (and will be set + * to zero), but texture computation will be much faster. + * + * This class is templated over the input histogram type. + * + * Print references: + * M. M. Galloway. Texture analysis using gray level Zone lengths. Computer + * Graphics and Image Processing, 4:172-179, 1975. + * + * A. Chu, C. M. Sehgal, and J. F. Greenleaf. Use of gray value distribution of + * Zone lengths for texture analysis. Pattern Recognition Letters, 11:415-420, + * 1990. + * + * B. R. Dasarathy and E. B. Holder. Image characterizations based on joint + * gray-level Zone-length distributions. Pattern Recognition Letters, 12:490-502, + * 1991. + * + * IJ article: http://hdl.handle.net/1926/1374 + * + * \sa ScalarImageToSizeZoneFeaturesFilter + * \sa ScalarImageToSizeZoneMatrixFilter + * \sa EnhancedHistogramToSizeZoneFeaturesFilter + * + * \author: Nick Tustison + * \ingroup ITKStatistics + */ + + template< typename THistogram > + class EnhancedHistogramToSizeZoneFeaturesFilter : public ProcessObject + { + public: + /** Standard typedefs */ + typedef EnhancedHistogramToSizeZoneFeaturesFilter Self; + typedef ProcessObject Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Zone-time type information (and related methods). */ + itkTypeMacro( EnhancedHistogramToSizeZoneFeaturesFilter, ProcessObject ); + + /** standard New() method support */ + itkNewMacro( Self ); + + typedef THistogram HistogramType; + typedef typename HistogramType::Pointer HistogramPointer; + typedef typename HistogramType::ConstPointer HistogramConstPointer; + typedef typename HistogramType::MeasurementType MeasurementType; + typedef typename HistogramType::MeasurementVectorType MeasurementVectorType; + typedef typename HistogramType::IndexType IndexType; + typedef typename HistogramType:: + TotalAbsoluteFrequencyType FrequencyType; + + /** Method to Set/Get the input Histogram */ + using Superclass::SetInput; + void SetInput ( const HistogramType * histogram ); + const HistogramType * GetInput() const; + + /** Smart Pointer type to a DataObject. */ + typedef DataObject::Pointer DataObjectPointer; + + /** Type of DataObjects used for scalar outputs */ + typedef SimpleDataObjectDecorator MeasurementObjectType; + + /** Methods to return the short Zone emphasis. */ + MeasurementType GetSmallZoneEmphasis() const; + const MeasurementObjectType* GetSmallZoneEmphasisOutput() const; + + /** Methods to return the long Zone emphasis. */ + MeasurementType GetLargeZoneEmphasis() const; + const MeasurementObjectType* GetLargeZoneEmphasisOutput() const; + + /** Methods to return the grey level nonuniformity. */ + MeasurementType GetGreyLevelNonuniformity() const; + const MeasurementObjectType* GetGreyLevelNonuniformityOutput() const; + + /** Methods to return the Zone length nonuniformity. */ + MeasurementType GetSizeZoneNonuniformity() const; + const MeasurementObjectType* GetSizeZoneNonuniformityOutput() const; + + /** Methods to return the low grey level Zone emphasis. */ + MeasurementType GetLowGreyLevelZoneEmphasis() const; + const MeasurementObjectType* GetLowGreyLevelZoneEmphasisOutput() const; + + /** Methods to return the high grey level Zone emphasis. */ + MeasurementType GetHighGreyLevelZoneEmphasis() const; + const MeasurementObjectType* GetHighGreyLevelZoneEmphasisOutput() const; + + /** Methods to return the short Zone low grey level Zone emphasis. */ + MeasurementType GetSmallZoneLowGreyLevelEmphasis() const; + const MeasurementObjectType* GetSmallZoneLowGreyLevelEmphasisOutput() const; + + /** Methods to return the short Zone high grey level Zone emphasis. */ + MeasurementType GetSmallZoneHighGreyLevelEmphasis() const; + const MeasurementObjectType* GetSmallZoneHighGreyLevelEmphasisOutput() const; + + /** Methods to return the long Zone low grey level Zone emphasis. */ + MeasurementType GetLargeZoneLowGreyLevelEmphasis() const; + const MeasurementObjectType* GetLargeZoneLowGreyLevelEmphasisOutput() const; + + /** Methods to return the long Zone high grey level Zone emphasis. */ + MeasurementType GetLargeZoneHighGreyLevelEmphasis() const; + const MeasurementObjectType* GetLargeZoneHighGreyLevelEmphasisOutput() const; + + /** Methods to return the long Zone high grey level Zone emphasis. */ + MeasurementType GetZonePercentage() const; + const MeasurementObjectType* GetZonePercentageOutput() const; + + /** Methods to return the long Zone high grey level Zone emphasis. */ + MeasurementType GetNumberOfZones() const; + const MeasurementObjectType* GetNumberOfZonesOutput() const; + + /** Methods to return the grey level variance. */ + MeasurementType GetGreyLevelVariance() const; + const MeasurementObjectType* GetGreyLevelVarianceOutput() const; + + /** Methods to return the Zone length variance. */ + MeasurementType GetSizeZoneVariance() const; + const MeasurementObjectType* GetSizeZoneVarianceOutput() const; + + /** Methods to return the Zone entropy. */ + MeasurementType GetZoneEntropy() const; + const MeasurementObjectType* GetZoneEntropyOutput() const; + + itkGetMacro( TotalNumberOfZones, unsigned long ); + + itkGetConstMacro(NumberOfVoxels, unsigned long); + itkSetMacro(NumberOfVoxels, unsigned long); + + /** Zone-length feature types */ + typedef enum + { + SmallZoneEmphasis, + LargeZoneEmphasis, + GreyLevelNonuniformity, + SizeZoneNonuniformity, + LowGreyLevelZoneEmphasis, + HighGreyLevelZoneEmphasis, + SmallZoneLowGreyLevelEmphasis, + SmallZoneHighGreyLevelEmphasis, + LargeZoneLowGreyLevelEmphasis, + LargeZoneHighGreyLevelEmphasis, + ZonePercentage, + GreyLevelVariance, + SizeZoneVariance, + ZoneEntropy + } SizeZoneFeatureName; + + /** convenience method to access the Zone length values */ + MeasurementType GetFeature( SizeZoneFeatureName name ); + + protected: + EnhancedHistogramToSizeZoneFeaturesFilter(); + ~EnhancedHistogramToSizeZoneFeaturesFilter() {}; + virtual void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; + + /** Make a DataObject to be used for output output. */ + typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; + using Superclass::MakeOutput; + virtual DataObjectPointer MakeOutput( DataObjectPointerArraySizeType ) ITK_OVERRIDE; + + virtual void GenerateData() ITK_OVERRIDE; + + private: + EnhancedHistogramToSizeZoneFeaturesFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + unsigned long m_TotalNumberOfZones; + unsigned long m_NumberOfVoxels; + }; + } // end of namespace Statistics +} // end of namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkEnhancedHistogramToSizeZoneFeaturesFilter.hxx" +#endif + +#endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.hxx new file mode 100644 index 0000000000..e9dca786c2 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/itkEnhancedHistogramToSizeZoneFeaturesFilter.hxx @@ -0,0 +1,611 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +/*========================================================================= +* +* Copyright Insight Software Consortium +* +* 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 +* +* http://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 __itkEnhancedHistogramToSizeZoneFeaturesFilter_hxx +#define __itkEnhancedHistogramToSizeZoneFeaturesFilter_hxx + +#include "itkEnhancedHistogramToSizeZoneFeaturesFilter.h" + +#include "itkNumericTraits.h" +#include "vnl/vnl_math.h" + +namespace itk { + namespace Statistics { + //constructor + template + EnhancedHistogramToSizeZoneFeaturesFilter + ::EnhancedHistogramToSizeZoneFeaturesFilter() : + m_NumberOfVoxels(1) + { + this->ProcessObject::SetNumberOfRequiredInputs( 1 ); + + // allocate the data objects for the outputs which are + // just decorators real types + for( unsigned int i = 0; i < 15; i++ ) + { + this->ProcessObject::SetNthOutput( i, this->MakeOutput( i ) ); + } + } + + template + void + EnhancedHistogramToSizeZoneFeaturesFilter< THistogram> + ::SetInput( const HistogramType *histogram ) + { + this->ProcessObject::SetNthInput( 0, const_cast( histogram ) ); + } + + template + const typename + EnhancedHistogramToSizeZoneFeaturesFilter::HistogramType * + EnhancedHistogramToSizeZoneFeaturesFilter< THistogram> + ::GetInput() const + { + if ( this->GetNumberOfInputs() < 1 ) + { + return ITK_NULLPTR; + } + return itkDynamicCastInDebugMode(this->ProcessObject::GetInput( 0 ) ); + } + + template + typename + EnhancedHistogramToSizeZoneFeaturesFilter::DataObjectPointer + EnhancedHistogramToSizeZoneFeaturesFilter + ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed( idx ) ) + { + return MeasurementObjectType::New().GetPointer(); + } + + template + void + EnhancedHistogramToSizeZoneFeaturesFilter< THistogram>:: + GenerateData( void ) + { + const HistogramType * inputHistogram = this->GetInput(); + + this->m_TotalNumberOfZones = static_cast + ( inputHistogram->GetTotalFrequency() ); + + MeasurementType SmallZoneEmphasis = NumericTraits::ZeroValue(); + MeasurementType LargeZoneEmphasis = NumericTraits::ZeroValue(); + MeasurementType greyLevelNonuniformity = NumericTraits::ZeroValue(); + MeasurementType SizeZoneNonuniformity = NumericTraits::ZeroValue(); + MeasurementType lowGreyLevelZoneEmphasis = NumericTraits::ZeroValue(); + MeasurementType highGreyLevelZoneEmphasis = NumericTraits::ZeroValue(); + MeasurementType SmallZoneLowGreyLevelEmphasis = NumericTraits::ZeroValue(); + MeasurementType SmallZoneHighGreyLevelEmphasis = NumericTraits::ZeroValue(); + MeasurementType LargeZoneLowGreyLevelEmphasis = NumericTraits::ZeroValue(); + MeasurementType LargeZoneHighGreyLevelEmphasis = NumericTraits::ZeroValue(); + MeasurementType ZonePercentage = NumericTraits::ZeroValue(); + MeasurementType numberOfZones = NumericTraits::ZeroValue(); + //Added 15.07.2016 + MeasurementType greyLevelVariance = NumericTraits::ZeroValue(); + MeasurementType SizeZoneVariance = NumericTraits::ZeroValue(); + MeasurementType ZoneEntropy = NumericTraits::ZeroValue(); + + vnl_vector greyLevelNonuniformityVector( + inputHistogram->GetSize()[0], 0.0 ); + vnl_vector SizeZoneNonuniformityVector( + inputHistogram->GetSize()[1], 0.0 ); + + typedef typename HistogramType::ConstIterator HistogramIterator; + + double mu_i = 0.0; + double mu_j = 0.0; + + //Calculate the means. + for ( HistogramIterator hit = inputHistogram->Begin(); + hit != inputHistogram->End(); ++hit ) + { + MeasurementType frequency = hit.GetFrequency(); + if ( frequency == 0 ) + { + continue; + } + MeasurementVectorType measurement = hit.GetMeasurementVector(); + IndexType index = hit.GetIndex(); + + int value = floor(measurement[0] + 0.5); + int count = measurement[1]; + + double i = value; + double j = count; + + double p_ij = frequency / m_TotalNumberOfZones; + + mu_i += i * p_ij; + mu_j += j * p_ij; + } + + //Calculate the other features. + const double log2 = std::log(2.0); + int totNumOfVoxelsUsed = 0; + + for ( HistogramIterator hit = inputHistogram->Begin(); + hit != inputHistogram->End(); ++hit ) + { + MeasurementType frequency = hit.GetFrequency(); + if ( frequency == 0 ) + { + continue; + } + MeasurementVectorType measurement = hit.GetMeasurementVector(); + IndexType index = hit.GetIndex(); + // inputHistogram->GetIndex( hit.GetInstanceIdentifier() ); + + int value = floor(measurement[0] + 0.5); + int count = measurement[1]; + + double i = value; + double j = count; + + double i2 = static_cast( i*i ); + double j2 = static_cast( j*j ); + + double p_ij = frequency / m_TotalNumberOfZones; + + greyLevelVariance += ((i - mu_i) * (i - mu_i) * p_ij); + SizeZoneVariance += ((j - mu_j) * (j - mu_j) * p_ij); + ZoneEntropy -= ( p_ij > 0.0001 ) ? p_ij *std::log(p_ij) / log2 : 0; + + // Traditional measures + SmallZoneEmphasis += ( frequency / j2 ); + LargeZoneEmphasis += ( frequency * j2 ); + + greyLevelNonuniformityVector[index[0]] += frequency; + SizeZoneNonuniformityVector[index[1]] += frequency; + + // measures from Chu et al. + lowGreyLevelZoneEmphasis += ( frequency / i2 ); + highGreyLevelZoneEmphasis += ( frequency * i2 ); + + // measures from Dasarathy and Holder + SmallZoneLowGreyLevelEmphasis += ( frequency / ( i2 * j2 ) ); + SmallZoneHighGreyLevelEmphasis += ( frequency * i2 / j2 ); + LargeZoneLowGreyLevelEmphasis += ( frequency * j2 / i2 ); + LargeZoneHighGreyLevelEmphasis += ( frequency * i2 * j2 ); + + totNumOfVoxelsUsed += (count * frequency); + } + greyLevelNonuniformity = + greyLevelNonuniformityVector.squared_magnitude(); + SizeZoneNonuniformity = + SizeZoneNonuniformityVector.squared_magnitude(); + + // Normalize all measures by the total number of Zones + + m_TotalNumberOfZones = totNumOfVoxelsUsed; + + if (this->m_TotalNumberOfZones > 0) + { + SmallZoneEmphasis /= + static_cast( this->m_TotalNumberOfZones ); + LargeZoneEmphasis /= + static_cast( this->m_TotalNumberOfZones ); + greyLevelNonuniformity /= + static_cast( this->m_TotalNumberOfZones ); + SizeZoneNonuniformity /= + static_cast( this->m_TotalNumberOfZones ); + + lowGreyLevelZoneEmphasis /= + static_cast( this->m_TotalNumberOfZones ); + highGreyLevelZoneEmphasis /= + static_cast( this->m_TotalNumberOfZones ); + + SmallZoneLowGreyLevelEmphasis /= + static_cast( this->m_TotalNumberOfZones ); + SmallZoneHighGreyLevelEmphasis /= + static_cast( this->m_TotalNumberOfZones ); + LargeZoneLowGreyLevelEmphasis /= + static_cast( this->m_TotalNumberOfZones ); + LargeZoneHighGreyLevelEmphasis /= + static_cast( this->m_TotalNumberOfZones ); + ZonePercentage = static_cast( this->m_TotalNumberOfZones ) / static_cast( this->m_NumberOfVoxels ); + numberOfZones = static_cast( this->m_TotalNumberOfZones ) ; + } else { + SmallZoneEmphasis = 0; + LargeZoneEmphasis = 0; + greyLevelNonuniformity = 0; + SizeZoneNonuniformity= 0; + + lowGreyLevelZoneEmphasis = 0; + highGreyLevelZoneEmphasis = 0; + + SmallZoneLowGreyLevelEmphasis = 0; + SmallZoneHighGreyLevelEmphasis= 0; + LargeZoneLowGreyLevelEmphasis = 0; + LargeZoneHighGreyLevelEmphasis = 0; + ZonePercentage = 0; + numberOfZones = static_cast( this->m_TotalNumberOfZones ) ; + } + + MeasurementObjectType* SmallZoneEmphasisOutputObject = + static_cast( this->ProcessObject::GetOutput( 0 ) ); + SmallZoneEmphasisOutputObject->Set( SmallZoneEmphasis ); + + MeasurementObjectType* LargeZoneEmphasisOutputObject = + static_cast( this->ProcessObject::GetOutput( 1 ) ); + LargeZoneEmphasisOutputObject->Set( LargeZoneEmphasis ); + + MeasurementObjectType* greyLevelNonuniformityOutputObject = + static_cast( this->ProcessObject::GetOutput( 2 ) ); + greyLevelNonuniformityOutputObject->Set( greyLevelNonuniformity ); + + MeasurementObjectType* SizeZoneNonuniformityOutputObject = + static_cast( this->ProcessObject::GetOutput( 3 ) ); + SizeZoneNonuniformityOutputObject->Set( SizeZoneNonuniformity ); + + MeasurementObjectType* lowGreyLevelZoneEmphasisOutputObject = + static_cast( this->ProcessObject::GetOutput( 4 ) ); + lowGreyLevelZoneEmphasisOutputObject->Set( lowGreyLevelZoneEmphasis ); + + MeasurementObjectType* highGreyLevelZoneEmphasisOutputObject = + static_cast( this->ProcessObject::GetOutput( 5 ) ); + highGreyLevelZoneEmphasisOutputObject->Set( highGreyLevelZoneEmphasis ); + + MeasurementObjectType* SmallZoneLowGreyLevelEmphasisOutputObject = + static_cast( this->ProcessObject::GetOutput( 6 ) ); + SmallZoneLowGreyLevelEmphasisOutputObject->Set( SmallZoneLowGreyLevelEmphasis ); + + MeasurementObjectType* SmallZoneHighGreyLevelEmphasisOutputObject = + static_cast( this->ProcessObject::GetOutput( 7 ) ); + SmallZoneHighGreyLevelEmphasisOutputObject->Set( + SmallZoneHighGreyLevelEmphasis ); + + MeasurementObjectType* LargeZoneLowGreyLevelEmphasisOutputObject = + static_cast( this->ProcessObject::GetOutput( 8 ) ); + LargeZoneLowGreyLevelEmphasisOutputObject->Set( LargeZoneLowGreyLevelEmphasis ); + + MeasurementObjectType* LargeZoneHighGreyLevelEmphasisOutputObject = + static_cast( this->ProcessObject::GetOutput( 9 ) ); + LargeZoneHighGreyLevelEmphasisOutputObject->Set( LargeZoneHighGreyLevelEmphasis ); + + MeasurementObjectType* ZonePercentagesOutputObject = + static_cast( this->ProcessObject::GetOutput( 10 ) ); + ZonePercentagesOutputObject->Set( ZonePercentage ); + + MeasurementObjectType* numberOfZonesOutputObject = + static_cast( this->ProcessObject::GetOutput( 11 ) ); + numberOfZonesOutputObject->Set( numberOfZones ); + + MeasurementObjectType* greyLevelVarianceOutputObject = + static_cast( this->ProcessObject::GetOutput( 12 ) ); + greyLevelVarianceOutputObject->Set( greyLevelVariance ); + + MeasurementObjectType* SizeZoneVarianceOutputObject = + static_cast( this->ProcessObject::GetOutput( 13 ) ); + SizeZoneVarianceOutputObject->Set( SizeZoneVariance ); + + MeasurementObjectType* ZoneEntropyOutputObject = + static_cast( this->ProcessObject::GetOutput( 14 ) ); + ZoneEntropyOutputObject->Set( ZoneEntropy ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetSmallZoneEmphasisOutput() const + { + return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 0 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetLargeZoneEmphasisOutput() const + { + return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetGreyLevelNonuniformityOutput() const + { + return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 2 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetSizeZoneNonuniformityOutput() const + { + return itkDynamicCastInDebugMode(this->ProcessObject::GetOutput( 3 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetLowGreyLevelZoneEmphasisOutput() const + { + return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 4 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetHighGreyLevelZoneEmphasisOutput() const + { + return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 5 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetSmallZoneLowGreyLevelEmphasisOutput() const + { + return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 6 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetSmallZoneHighGreyLevelEmphasisOutput() const + { + return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 7 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetLargeZoneLowGreyLevelEmphasisOutput() const + { + return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 8 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetLargeZoneHighGreyLevelEmphasisOutput() const + { + return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 9 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetZonePercentageOutput() const + { + return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 10 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetNumberOfZonesOutput() const + { + return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 11 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetGreyLevelVarianceOutput() const + { + return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 12 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetSizeZoneVarianceOutput() const + { + return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 13 ) ); + } + + template + const + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementObjectType* + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetZoneEntropyOutput() const + { + return itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 14 ) ); + } + + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetSmallZoneEmphasis() const + { + return this->GetSmallZoneEmphasisOutput()->Get(); + } + + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetLargeZoneEmphasis() const + { + return this->GetLargeZoneEmphasisOutput()->Get(); + } + + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetGreyLevelNonuniformity() const + { + return this->GetGreyLevelNonuniformityOutput()->Get(); + } + + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetSizeZoneNonuniformity() const + { + return this->GetSizeZoneNonuniformityOutput()->Get(); + } + + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetLowGreyLevelZoneEmphasis() const + { + return this->GetLowGreyLevelZoneEmphasisOutput()->Get(); + } + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetHighGreyLevelZoneEmphasis() const + { + return this->GetHighGreyLevelZoneEmphasisOutput()->Get(); + } + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetSmallZoneLowGreyLevelEmphasis() const + { + return this->GetSmallZoneLowGreyLevelEmphasisOutput()->Get(); + } + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetSmallZoneHighGreyLevelEmphasis() const + { + return this->GetSmallZoneHighGreyLevelEmphasisOutput()->Get(); + } + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetLargeZoneLowGreyLevelEmphasis() const + { + return this->GetLargeZoneLowGreyLevelEmphasisOutput()->Get(); + } + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetLargeZoneHighGreyLevelEmphasis() const + { + return this->GetLargeZoneHighGreyLevelEmphasisOutput()->Get(); + } + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetZonePercentage() const + { + return this->GetZonePercentageOutput()->Get(); + } + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetNumberOfZones() const + { + return this->GetNumberOfZonesOutput()->Get(); + } + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetGreyLevelVariance() const + { + return this->GetGreyLevelVarianceOutput()->Get(); + } + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetSizeZoneVariance() const + { + return this->GetSizeZoneVarianceOutput()->Get(); + } + template + typename EnhancedHistogramToSizeZoneFeaturesFilter::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetZoneEntropy() const + { + return this->GetZoneEntropyOutput()->Get(); + } + + + template + typename EnhancedHistogramToSizeZoneFeaturesFilter< THistogram>::MeasurementType + EnhancedHistogramToSizeZoneFeaturesFilter + ::GetFeature( SizeZoneFeatureName feature ) + { + switch( feature ) + { + case SmallZoneEmphasis: + return this->GetSmallZoneEmphasis(); + case LargeZoneEmphasis: + return this->GetLargeZoneEmphasis(); + case GreyLevelNonuniformity: + return this->GetGreyLevelNonuniformity(); + case SizeZoneNonuniformity: + return this->GetSizeZoneNonuniformity(); + case LowGreyLevelZoneEmphasis: + return this->GetLowGreyLevelZoneEmphasis(); + case HighGreyLevelZoneEmphasis: + return this->GetHighGreyLevelZoneEmphasis(); + case SmallZoneLowGreyLevelEmphasis: + return this->GetSmallZoneLowGreyLevelEmphasis(); + case SmallZoneHighGreyLevelEmphasis: + return this->GetSmallZoneHighGreyLevelEmphasis(); + case LargeZoneLowGreyLevelEmphasis: + return this->GetLargeZoneLowGreyLevelEmphasis(); + case LargeZoneHighGreyLevelEmphasis: + return this->GetLargeZoneHighGreyLevelEmphasis(); + case ZonePercentage: + return this->GetZonePercentage(); + case GreyLevelVariance: + return this->GetGreyLevelVariance(); + case SizeZoneVariance: + return this->GetSizeZoneVariance(); + case ZoneEntropy: + return this->GetZoneEntropy(); + default: + return 0; + } + } + + template< typename THistogram> + void + EnhancedHistogramToSizeZoneFeaturesFilter< THistogram>:: + PrintSelf(std::ostream& os, Indent indent) const + { + Superclass::PrintSelf( os,indent ); + } + } // end of namespace Statistics +} // end of namespace itk + +#endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.h new file mode 100644 index 0000000000..cdb4bd4235 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.h @@ -0,0 +1,245 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +/*========================================================================= +* +* Copyright Insight Software Consortium +* +* 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 +* +* http://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 __itkEnhancedScalarImageToSizeZoneFeaturesFilter_h +#define __itkEnhancedScalarImageToSizeZoneFeaturesFilter_h + +#include "itkDataObjectDecorator.h" + +#include "itkEnhancedHistogramToSizeZoneFeaturesFilter.h" +#include "itkEnhancedScalarImageToSizeZoneMatrixFilter.h" + +namespace itk +{ + namespace Statistics + { + /** \class EnhancedScalarImageToSizeZoneFeaturesFilter + * \brief This class computes run length descriptions from an image. + * + * By default, run length features are computed for each spatial + * direction and then averaged afterward, so it is possible to access the + * standard deviations of the texture features. These values give a clue as + * to texture anisotropy. However, doing this is much more work, because it + * involved computing one for each offset given. To compute a single + * matrix using the first offset, call FastCalculationsOn(). If this is called, + * then the texture standard deviations will not be computed (and will be set + * to zero), but texture computation will be much faster. + * + * This class is templated over the input image type. + * + * Template Parameters: + * The image type, and the type of histogram frequency container. If you are + * using a large number of bins per axis, a sparse frequency container may be + * advisable. The default is to use a dense frequency container. + * + * Inputs and parameters: + * -# An image + * -# A mask defining the region over which texture features will be + * calculated. (Optional) + * -# The pixel value that defines the "inside" of the mask. (Optional, defaults + * to 1 if a mask is set.) + * -# The set of features to be calculated. These features are defined + * in the HistogramToSizeZoneFeaturesFilter class. + * -# The number of intensity bins. (Optional, defaults to 256.) + * -# The set of directions (offsets) to average across. (Optional, defaults to + * {(-1, 0), (-1, -1), (0, -1), (1, -1)} for 2D images and scales analogously + * for ND images.) + * -# The pixel intensity range over which the features will be calculated. + * (Optional, defaults to the full dynamic range of the pixel type.) + * -# The distance range over which the features will be calculated. + * (Optional, defaults to the full dynamic range of double type.) + * + * In general, the default parameter values should be sufficient. + * + * Outputs: + * (1) The average value of each feature. + * (2) The standard deviation in the values of each feature. + * + * Print references: + * M. M. Galloway. Texture analysis using gray level run lengths. Computer + * Graphics and Image Processing, 4:172-179, 1975. + * + * A. Chu, C. M. Sehgal, and J. F. Greenleaf. Use of gray value distribution of + * run lengths for texture analysis. Pattern Recognition Letters, 11:415-420, + * 1990. + * + * B. R. Dasarathy and E. B. Holder. Image characterizations based on joint + * gray-level run-length distributions. Pattern Recognition Letters, 12:490-502, + * 1991. + * + * IJ article: http://hdl.handle.net/1926/1374 + * + * \sa EnhancedScalarImageToSizeZoneFeaturesFilter + * \sa ScalarImageToSizeZoneMatrixFilter + * \sa HistogramToSizeZoneFeaturesFilter + * + * \author: Nick Tustison + * \ingroup ITKStatistics + */ + + template< typename TImageType, + typename THistogramFrequencyContainer = DenseFrequencyContainer2 > + class EnhancedScalarImageToSizeZoneFeaturesFilter:public ProcessObject + { + public: + /** Standard typedefs */ + typedef EnhancedScalarImageToSizeZoneFeaturesFilter Self; + typedef ProcessObject Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + /** Run-time type information (and related methods). */ + itkTypeMacro(EnhancedScalarImageToSizeZoneFeaturesFilter, ProcessObject); + + /** standard New() method support */ + itkNewMacro(Self); + + typedef THistogramFrequencyContainer FrequencyContainerType; + typedef TImageType ImageType; + typedef typename ImageType::Pointer ImagePointer; + + typedef typename ImageType::PixelType PixelType; + typedef typename ImageType::OffsetType OffsetType; + typedef VectorContainer< unsigned char, OffsetType > OffsetVector; + typedef typename OffsetVector::Pointer OffsetVectorPointer; + typedef typename OffsetVector::ConstPointer OffsetVectorConstPointer; + + typedef EnhancedScalarImageToSizeZoneMatrixFilter< + ImageType, FrequencyContainerType > SizeZoneMatrixFilterType; + + typedef typename SizeZoneMatrixFilterType::HistogramType + HistogramType; + + typedef EnhancedHistogramToSizeZoneFeaturesFilter< HistogramType > + SizeZoneFeaturesFilterType; + + typedef short SizeZoneFeatureName; + typedef VectorContainer FeatureNameVector; + typedef typename FeatureNameVector::Pointer FeatureNameVectorPointer; + typedef typename FeatureNameVector::ConstPointer FeatureNameVectorConstPointer; + typedef VectorContainer< unsigned char, double > FeatureValueVector; + typedef typename FeatureValueVector::Pointer FeatureValueVectorPointer; + + /** Smart Pointer type to a DataObject. */ + typedef DataObject::Pointer DataObjectPointer; + + /** Type of DataObjects used for scalar outputs */ + typedef DataObjectDecorator< FeatureValueVector > + FeatureValueVectorDataObjectType; + + const FeatureValueVectorDataObjectType * GetFeatureMeansOutput() const; + + const FeatureValueVectorDataObjectType * GetFeatureStandardDeviationsOutput() + const; + + /** Connects the input image for which the features are going to be computed + */ + using Superclass::SetInput; + void SetInput(const ImageType *); + + const ImageType * GetInput() const; + + /** Return the feature means and deviations. */ + itkGetConstReferenceObjectMacro(FeatureMeans, FeatureValueVector); + itkGetConstReferenceObjectMacro(FeatureStandardDeviations, FeatureValueVector); + + /** Set the desired feature set. Optional, for default value see above. */ + itkSetConstObjectMacro(RequestedFeatures, FeatureNameVector); + itkGetConstObjectMacro(RequestedFeatures, FeatureNameVector); + + /** Set the offsets over which the co-occurrence pairs will be computed. + Optional; for default value see above. */ + itkSetConstObjectMacro(Offsets, OffsetVector); + itkGetConstObjectMacro(Offsets, OffsetVector); + + /** Set number of histogram bins along each axis. + Optional; for default value see above. */ + void SetNumberOfBinsPerAxis(unsigned int); + + /** Set the min and max (inclusive) pixel value that will be used for + feature calculations. Optional; for default value see above. */ + void SetPixelValueMinMax(PixelType min, PixelType max); + + /** Set the min and max (inclusive) pixel value that will be used for + feature calculations. Optional; for default value see above. */ + void SetDistanceValueMinMax( double min, double max ); + + /** Connects the mask image for which the histogram is going to be computed. + Optional; for default value see above. */ + void SetMaskImage(const ImageType *); + + const ImageType * GetMaskImage() const; + + /** Set the pixel value of the mask that should be considered "inside" the + object. Optional; for default value see above. */ + void SetInsidePixelValue(PixelType InsidePixelValue); + + itkGetConstMacro(FastCalculations, bool); + itkSetMacro(FastCalculations, bool); + itkBooleanMacro(FastCalculations); + + protected: + EnhancedScalarImageToSizeZoneFeaturesFilter(); + virtual ~EnhancedScalarImageToSizeZoneFeaturesFilter() {} + virtual void PrintSelf( std::ostream & os, Indent indent ) const ITK_OVERRIDE; + + void FastCompute(); + + void FullCompute(); + + /** This method causes the filter to generate its output. */ + virtual void GenerateData() ITK_OVERRIDE; + + /** Make a DataObject to be used for output output. */ + typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; + using Superclass::MakeOutput; + virtual DataObjectPointer MakeOutput(DataObjectPointerArraySizeType) ITK_OVERRIDE; + + private: + typename SizeZoneMatrixFilterType::Pointer m_SizeZoneMatrixGenerator; + + FeatureValueVectorPointer m_FeatureMeans; + FeatureValueVectorPointer m_FeatureStandardDeviations; + FeatureNameVectorConstPointer m_RequestedFeatures; + OffsetVectorConstPointer m_Offsets; + bool m_FastCalculations; + }; + } // end of namespace Statistics +} // end of namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkEnhancedScalarImageToSizeZoneFeaturesFilter.hxx" +#endif + +#endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.hxx new file mode 100644 index 0000000000..c5fb14b406 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneFeaturesFilter.hxx @@ -0,0 +1,410 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +/*========================================================================= +* +* Copyright Insight Software Consortium +* +* 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 +* +* http://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 __itkEnhancedScalarImageToSizeZoneFeaturesFilter_hxx +#define __itkEnhancedScalarImageToSizeZoneFeaturesFilter_hxx + +#include "itkEnhancedScalarImageToSizeZoneFeaturesFilter.h" +#include "itkNeighborhood.h" +#include +#include "vnl/vnl_math.h" + +namespace itk +{ + namespace Statistics + { + template + EnhancedScalarImageToSizeZoneFeaturesFilter + ::EnhancedScalarImageToSizeZoneFeaturesFilter() + { + this->SetNumberOfRequiredInputs( 1 ); + this->SetNumberOfRequiredOutputs( 1 ); + + for( int i = 0; i < 2; ++i ) + { + this->ProcessObject::SetNthOutput( i, this->MakeOutput( i ) ); + } + + this->m_SizeZoneMatrixGenerator = SizeZoneMatrixFilterType::New(); + this->m_FeatureMeans = FeatureValueVector::New(); + this->m_FeatureStandardDeviations = FeatureValueVector::New(); + + // Set the requested features to the default value: + // {Energy, Entropy, InverseDifferenceMoment, Inertia, ClusterShade, + // ClusterProminence} + FeatureNameVectorPointer requestedFeatures = FeatureNameVector::New(); + // can't directly set this->m_RequestedFeatures since it is const! + + requestedFeatures->push_back( SizeZoneFeaturesFilterType::SmallZoneEmphasis ); + requestedFeatures->push_back( SizeZoneFeaturesFilterType::LargeZoneEmphasis ); + requestedFeatures->push_back( SizeZoneFeaturesFilterType::GreyLevelNonuniformity ); + requestedFeatures->push_back( SizeZoneFeaturesFilterType::SizeZoneNonuniformity ); + requestedFeatures->push_back( SizeZoneFeaturesFilterType::LowGreyLevelZoneEmphasis ); + requestedFeatures->push_back( SizeZoneFeaturesFilterType::HighGreyLevelZoneEmphasis ); + requestedFeatures->push_back( SizeZoneFeaturesFilterType::SmallZoneLowGreyLevelEmphasis ); + requestedFeatures->push_back( SizeZoneFeaturesFilterType::SmallZoneHighGreyLevelEmphasis ); + requestedFeatures->push_back( SizeZoneFeaturesFilterType::LargeZoneLowGreyLevelEmphasis ); + requestedFeatures->push_back( SizeZoneFeaturesFilterType::LargeZoneHighGreyLevelEmphasis ); + requestedFeatures->push_back( 20 ); + + this->SetRequestedFeatures( requestedFeatures ); + + // Set the offset directions to their defaults: half of all the possible + // directions 1 pixel away. (The other half is included by symmetry.) + // We use a neighborhood iterator to calculate the appropriate offsets. + typedef Neighborhood NeighborhoodType; + NeighborhoodType hood; + hood.SetRadius( 1 ); + + // select all "previous" neighbors that are face+edge+vertex + // connected to the current pixel. do not include the center pixel. + unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); + OffsetVectorPointer offsets = OffsetVector::New(); + for( unsigned int d = 0; d < centerIndex; d++ ) + { + OffsetType offset = hood.GetOffset( d ); + offsets->push_back( offset ); + } + this->SetOffsets( offsets ); + this->m_FastCalculations = false; + } + + template + typename + EnhancedScalarImageToSizeZoneFeaturesFilter + ::DataObjectPointer + EnhancedScalarImageToSizeZoneFeaturesFilter + ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed(idx) ) + { + return FeatureValueVectorDataObjectType::New().GetPointer(); + } + + template + void + EnhancedScalarImageToSizeZoneFeaturesFilter + ::GenerateData(void) + { + if ( this->m_FastCalculations ) + { + this->FastCompute(); + } + else + { + this->FullCompute(); + } + } + + template + void + EnhancedScalarImageToSizeZoneFeaturesFilter + ::FullCompute() + { + int numOffsets = this->m_Offsets->size(); + int numFeatures = this->m_RequestedFeatures->size(); + double **features; + + features = new double *[numOffsets]; + for( int i = 0; i < numOffsets; i++ ) + { + features[i] = new double[numFeatures]; + } + + unsigned long numberOfVoxels = 0; + ImageRegionConstIterator voxelCountIter(this->GetMaskImage(),this->GetMaskImage()->GetLargestPossibleRegion()); + while ( ! voxelCountIter.IsAtEnd() ) + { + if (voxelCountIter.Get() > 0) + ++numberOfVoxels; + ++voxelCountIter; + } + + // For each offset, calculate each feature + typename OffsetVector::ConstIterator offsetIt; + int offsetNum, featureNum; + typedef typename SizeZoneFeaturesFilterType::SizeZoneFeatureName + InternalSizeZoneFeatureName; + + for( offsetIt = this->m_Offsets->Begin(), offsetNum = 0; + offsetIt != this->m_Offsets->End(); offsetIt++, offsetNum++ ) + { + this->m_SizeZoneMatrixGenerator->SetOffset( offsetIt.Value() ); + this->m_SizeZoneMatrixGenerator->Update(); + typename SizeZoneFeaturesFilterType::Pointer SizeZoneMatrixCalculator = + SizeZoneFeaturesFilterType::New(); + SizeZoneMatrixCalculator->SetInput( + this->m_SizeZoneMatrixGenerator->GetOutput() ); + SizeZoneMatrixCalculator->SetNumberOfVoxels(numberOfVoxels); + SizeZoneMatrixCalculator->Update(); + + typename FeatureNameVector::ConstIterator fnameIt; + for( fnameIt = this->m_RequestedFeatures->Begin(), featureNum = 0; + fnameIt != this->m_RequestedFeatures->End(); fnameIt++, featureNum++ ) + { + features[offsetNum][featureNum] = SizeZoneMatrixCalculator->GetFeature( + ( InternalSizeZoneFeatureName )fnameIt.Value() ); + } + } + + // Now get the mean and deviaton of each feature across the offsets. + this->m_FeatureMeans->clear(); + this->m_FeatureStandardDeviations->clear(); + double *tempFeatureMeans = new double[numFeatures]; + double *tempFeatureDevs = new double[numFeatures]; + + /*Compute incremental mean and SD, a la Knuth, "The Art of Computer + Programming, Volume 2: Seminumerical Algorithms", section 4.2.2. + Compute mean and standard deviation using the recurrence relation: + M(1) = x(1), M(k) = M(k-1) + (x(k) - M(k-1) ) / k + S(1) = 0, S(k) = S(k-1) + (x(k) - M(k-1)) * (x(k) - M(k)) + for 2 <= k <= n, then + sigma = std::sqrt(S(n) / n) (or divide by n-1 for sample SD instead of + population SD). + */ + + // Set up the initial conditions (k = 1) + for( featureNum = 0; featureNum < numFeatures; featureNum++ ) + { + tempFeatureMeans[featureNum] = features[0][featureNum]; + tempFeatureDevs[featureNum] = 0; + } + // Zone through the recurrence (k = 2 ... N) + for( offsetNum = 1; offsetNum < numOffsets; offsetNum++ ) + { + int k = offsetNum + 1; + for( featureNum = 0; featureNum < numFeatures; featureNum++ ) + { + double M_k_minus_1 = tempFeatureMeans[featureNum]; + double S_k_minus_1 = tempFeatureDevs[featureNum]; + double x_k = features[offsetNum][featureNum]; + + double M_k = M_k_minus_1 + ( x_k - M_k_minus_1 ) / k; + double S_k = S_k_minus_1 + ( x_k - M_k_minus_1 ) * ( x_k - M_k ); + + tempFeatureMeans[featureNum] = M_k; + tempFeatureDevs[featureNum] = S_k; + } + } + for( featureNum = 0; featureNum < numFeatures; featureNum++ ) + { + tempFeatureDevs[featureNum] = std::sqrt( tempFeatureDevs[featureNum] / + numOffsets ); + + this->m_FeatureMeans->push_back( tempFeatureMeans[featureNum] ); + this->m_FeatureStandardDeviations->push_back( tempFeatureDevs[featureNum] ); + } + + FeatureValueVectorDataObjectType *meanOutputObject = + itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 0 ) ); + meanOutputObject->Set( this->m_FeatureMeans ); + + FeatureValueVectorDataObjectType *standardDeviationOutputObject = + itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); + standardDeviationOutputObject->Set( this->m_FeatureStandardDeviations ); + + delete[] tempFeatureMeans; + delete[] tempFeatureDevs; + for( int i = 0; i < numOffsets; i++ ) + { + delete[] features[i]; + } + delete[] features; + } + + template + void + EnhancedScalarImageToSizeZoneFeaturesFilter + ::FastCompute() + { + // Compute the feature for the first offset + typename OffsetVector::ConstIterator offsetIt = this->m_Offsets->Begin(); + this->m_SizeZoneMatrixGenerator->SetOffset( offsetIt.Value() ); + + this->m_SizeZoneMatrixGenerator->Update(); + typename SizeZoneFeaturesFilterType::Pointer SizeZoneMatrixCalculator = + SizeZoneFeaturesFilterType::New(); + SizeZoneMatrixCalculator->SetInput( + this->m_SizeZoneMatrixGenerator->GetOutput() ); + SizeZoneMatrixCalculator->Update(); + + typedef typename SizeZoneFeaturesFilterType::SizeZoneFeatureName + InternalSizeZoneFeatureName; + this->m_FeatureMeans->clear(); + this->m_FeatureStandardDeviations->clear(); + typename FeatureNameVector::ConstIterator fnameIt; + for( fnameIt = this->m_RequestedFeatures->Begin(); + fnameIt != this->m_RequestedFeatures->End(); fnameIt++ ) + { + this->m_FeatureMeans->push_back( SizeZoneMatrixCalculator->GetFeature( + ( InternalSizeZoneFeatureName )fnameIt.Value() ) ); + this->m_FeatureStandardDeviations->push_back( 0.0 ); + } + + FeatureValueVectorDataObjectType *meanOutputObject = + itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 0 ) ); + meanOutputObject->Set( this->m_FeatureMeans ); + + FeatureValueVectorDataObjectType *standardDeviationOutputObject = + itkDynamicCastInDebugMode( this->ProcessObject::GetOutput( 1 ) ); + standardDeviationOutputObject->Set( this->m_FeatureStandardDeviations ); + } + + template + void + EnhancedScalarImageToSizeZoneFeaturesFilter + ::SetInput( const ImageType *image ) + { + // Process object is not const-correct so the const_cast is required here + this->ProcessObject::SetNthInput( 0, + const_cast( image ) ); + + this->m_SizeZoneMatrixGenerator->SetInput( image ); + } + + template + void + EnhancedScalarImageToSizeZoneFeaturesFilter + ::SetNumberOfBinsPerAxis( unsigned int numberOfBins ) + { + itkDebugMacro( "setting NumberOfBinsPerAxis to " << numberOfBins ); + this->m_SizeZoneMatrixGenerator->SetNumberOfBinsPerAxis( numberOfBins ); + this->Modified(); + } + + template + void + EnhancedScalarImageToSizeZoneFeaturesFilter + ::SetPixelValueMinMax( PixelType min, PixelType max ) + { + itkDebugMacro( "setting Min to " << min << "and Max to " << max ); + this->m_SizeZoneMatrixGenerator->SetPixelValueMinMax( min, max ); + this->Modified(); + } + + template + void + EnhancedScalarImageToSizeZoneFeaturesFilter + ::SetDistanceValueMinMax( double min, double max ) + { + itkDebugMacro( "setting Min to " << min << "and Max to " << max ); + this->m_SizeZoneMatrixGenerator->SetDistanceValueMinMax( min, max ); + this->Modified(); + } + + template + void + EnhancedScalarImageToSizeZoneFeaturesFilter + ::SetMaskImage( const ImageType *image ) + { + // Process object is not const-correct so the const_cast is required here + this->ProcessObject::SetNthInput( 1, + const_cast< ImageType * >( image ) ); + + this->m_SizeZoneMatrixGenerator->SetMaskImage( image ); + } + + template + const TImage * + EnhancedScalarImageToSizeZoneFeaturesFilter + ::GetInput() const + { + if ( this->GetNumberOfInputs() < 1 ) + { + return ITK_NULLPTR; + } + return static_cast( this->ProcessObject::GetInput( 0 ) ); + } + + template + const typename + EnhancedScalarImageToSizeZoneFeaturesFilter + ::FeatureValueVectorDataObjectType * + EnhancedScalarImageToSizeZoneFeaturesFilter + ::GetFeatureMeansOutput() const + { + return itkDynamicCastInDebugMode + (this->ProcessObject::GetOutput( 0 ) ); + } + + template + const typename + EnhancedScalarImageToSizeZoneFeaturesFilter + ::FeatureValueVectorDataObjectType * + EnhancedScalarImageToSizeZoneFeaturesFilter + ::GetFeatureStandardDeviationsOutput() const + { + return itkDynamicCastInDebugMode< const FeatureValueVectorDataObjectType * > + ( this->ProcessObject::GetOutput( 1 ) ); + } + + template + const TImage * + EnhancedScalarImageToSizeZoneFeaturesFilter + ::GetMaskImage() const + { + if ( this->GetNumberOfInputs() < 2 ) + { + return ITK_NULLPTR; + } + return static_cast< const ImageType *>( this->ProcessObject::GetInput( 1 ) ); + } + + template + void + EnhancedScalarImageToSizeZoneFeaturesFilter + ::SetInsidePixelValue( PixelType insidePixelValue ) + { + itkDebugMacro( "setting InsidePixelValue to " << insidePixelValue ); + this->m_SizeZoneMatrixGenerator->SetInsidePixelValue( insidePixelValue ); + this->Modified(); + } + + template + void + EnhancedScalarImageToSizeZoneFeaturesFilter + ::PrintSelf(std::ostream & os, Indent indent) const + { + Superclass::PrintSelf(os, indent); + os << indent << "RequestedFeatures: " + << this->GetRequestedFeatures() << std::endl; + os << indent << "FeatureStandardDeviations: " + << this->GetFeatureStandardDeviations() << std::endl; + os << indent << "FastCalculations: " + << this->GetFastCalculations() << std::endl; + os << indent << "Offsets: " << this->GetOffsets() << std::endl; + os << indent << "FeatureMeans: " << this->GetFeatureMeans() << std::endl; + } + } // end of namespace Statistics +} // end of namespace itk + +#endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.h b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.h new file mode 100644 index 0000000000..a654543193 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.h @@ -0,0 +1,292 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +/*========================================================================= +* +* Copyright Insight Software Consortium +* +* 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 +* +* http://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 __itkEnhancedScalarImageToSizeZoneMatrixFilter_h +#define __itkEnhancedScalarImageToSizeZoneMatrixFilter_h + +#include "itkImage.h" +#include "itkHistogram.h" +#include "itkNumericTraits.h" +#include "itkVectorContainer.h" + +namespace itk +{ + namespace Statistics + { + /** \class EnhancedScalarImageToSizeZoneMatrixFilter + * \brief This class computes a run length matrix (histogram) from + * a given image and a mask image if provided. Run length matrces are + * used for image texture description. + * + * This filters creates a grey-level run length matrix from a N-D scalar + * image. This is another possible texture description. See the following + * references. + * M. M. Galloway. Texture analysis using gray level run lengths. Computer + * Graphics and Image Processing, 4:172-179, 1975. + * + * A. Chu, C. M. Sehgal, and J. F. Greenleaf. Use of gray value distribution of + * run lengths for texture analysis. Pattern Recognition Letters, 11:415-420, + * 1990. + * + * B. R. Dasarathy and E. B. Holder. Image characterizations based on joint + * gray-level run-length distributions. Pattern Recognition Letters, 12:490-502, + * 1991. + * + * The basic idea is as follows: + * Given an image and an offset (e.g. (1, -1) for a 2-d image), each element + * in the joint histogram describes the frequency for a particular distance/ + * intensity pair within a given image. This distance/intensity pair can be + * described as follows: we start at a given voxel which has some intensity. + * We then "jump" to neighboring pixels in increments provided by the offset(s) + * as long as the pixel to which we are jumping is within the same intensity + * bin as the original voxel. The distance component is given by the distance + * from the original to the final voxel satisfying our jumping criteria. + * + * The offset (or offsets) along which the co-occurences are calculated can be + * set by the user. Traditionally, only one offset is used per histogram, and + * offset components in the range [-1, 1] are used. For rotation-invariant + * features averages of features computed over several histograms with different + * offsets are generally used, instead of computing features from one histogram + * create with several offsets. Additionally, instead of using offsets of two or + * more pixels in any direction, multi-resolution techniques (e.g. image + * pyramids) are generally used to deal with texture at different spatial + * resolutions. + * + * This class calculates a 2-d histogram of all the intensity/distance pairs in + * the given image's requested region, for a given set of offsets. That is, if + * a given offset falls outside of the requested region (or outside the mask) + * at a particular point, that distance/intensity pair will not be added to + * the matrix. + * + * The number of histogram bins on each axis can be set (defaults to 256). Also, + * by default the histogram min and max corresponds to the largest and smallest + * possible pixel value of that pixel type. To customize the histogram bounds + * for a given image, the max and min pixel values that will be placed in the + * histogram can be set manually. NB: The min and max are INCLUSIVE. + * + * Further, the type of histogram frequency container used is an optional + * template parameter. By default, a dense container is used, but for images + * with little texture or in cases where the user wants more histogram bins, + * a sparse container can be used for the histogram instead. + * + * WARNING: This probably won't work for pixels of double or long-double type + * unless you set the histogram min and max manually. This is because the largest + * histogram bin by default has max value of the largest possible pixel value + * plus 1. For double and long-double types, whose "RealType" as defined by the + * NumericTraits class is the same, and thus cannot hold any larger values, + * this would cause a float overflow. + * + * IJ article: http://hdl.handle.net/1926/1374 + * + * \sa ScalarImageToSizeZoneFeaturesFilter + * \sa EnhancedScalarImageToSizeZoneMatrixFilter + * \sa HistogramToSizeZoneFeaturesFilter + * + * \author: Nick Tustison + * \ingroup ITKStatistics + */ + + template + class EnhancedScalarImageToSizeZoneMatrixFilter : public ProcessObject + { + public: + /** Standard typedefs */ + typedef EnhancedScalarImageToSizeZoneMatrixFilter Self; + typedef ProcessObject Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Run-time type information (and related methods). */ + itkTypeMacro( EnhancedScalarImageToSizeZoneMatrixFilter, ProcessObject ); + + /** standard New() method support */ + itkNewMacro( Self ); + + typedef TImageType ImageType; + typedef typename ImageType::Pointer ImagePointer; + typedef typename ImageType::ConstPointer ImageConstPointer; + typedef typename ImageType::PixelType PixelType; + typedef typename ImageType::IndexType IndexType; + typedef typename ImageType::RegionType RegionType; + typedef typename ImageType::SizeType RadiusType; + typedef typename ImageType::OffsetType OffsetType; + typedef VectorContainer OffsetVector; + typedef typename OffsetVector::Pointer OffsetVectorPointer; + typedef typename ImageType::PointType PointType; + + typedef typename NumericTraits::RealType MeasurementType; + typedef typename NumericTraits::RealType RealType; + + typedef Histogram + HistogramType; + typedef typename HistogramType::Pointer HistogramPointer; + typedef typename HistogramType::ConstPointer HistogramConstPointer; + typedef typename HistogramType::MeasurementVectorType MeasurementVectorType; + + /** ImageDimension constants */ + itkStaticConstMacro( ImageDimension, unsigned int, + TImageType::ImageDimension ); + + /** Specify the default number of bins per axis */ + itkStaticConstMacro( DefaultBinsPerAxis, unsigned int, 256 ); + + /** + * Set the offsets over which the intensity/distance pairs will be computed. + * Invoking this function clears the previous offsets. + * Note: for each individual offset in the OffsetVector, the rightmost non-zero + * offset element must be positive. For example, in the offset list of a 2D image, + * (1, 0) means the offset along x-axis. (1, 0) has to be set instead + * of (-1, 0). This is required from the iterating order of pixel iterator. + * + */ + itkSetObjectMacro( Offsets, OffsetVector ); + + /** + * Set offset over which the intensity/distance pairs will be computed. + * Invoking this function clears the previous offset(s). + * Note: for each individual offset, the rightmost non-zero + * offset element must be positive. For example, in the offset list of a 2D image, + * (1, 0) means the offset along x-axis. (1, 0) has to be set instead + * of (-1, 0). This is required from the iterating order of pixel iterator. + * + */ + void SetOffset( const OffsetType offset ); + + /** + * Get the current offset(s). + */ + itkGetModifiableObjectMacro(Offsets, OffsetVector ); + + /** Set number of histogram bins along each axis */ + itkSetMacro( NumberOfBinsPerAxis, unsigned int ); + + /** Get number of histogram bins along each axis */ + itkGetConstMacro( NumberOfBinsPerAxis, unsigned int ); + + /** + * Set the min and max (inclusive) pixel value that will be used in + * generating the histogram. + */ + void SetPixelValueMinMax( PixelType min, PixelType max ); + + /** Get the min pixel value defining one dimension of the joint histogram. */ + itkGetConstMacro( Min, PixelType ); + + /** Get the max pixel value defining one dimension of the joint histogram. */ + itkGetConstMacro( Max, PixelType ); + + /** + * Set the min and max (inclusive) pixel value that will be used in + * generating the histogram. + */ + void SetDistanceValueMinMax( RealType min, RealType max ); + + /** + * Get the min distance value defining one dimension of the joint histogram. + */ + itkGetConstMacro( MinDistance, RealType ); + + /** + * Get the max distance value defining one dimension of the joint histogram. + */ + itkGetConstMacro( MaxDistance, RealType ); + + /** Method to set the input image */ + using Superclass::SetInput; + void SetInput( const ImageType *image ); + + /** Method to get the input image */ + const ImageType * GetInput() const; + + /** Method to set the mask image */ + void SetMaskImage( const ImageType *image ); + + /** Method to get the mask image */ + const ImageType * GetMaskImage() const; + + /** method to get the Histogram */ + const HistogramType * GetOutput() const; + + /** + * Set the pixel value of the mask that should be considered "inside" the + * object. Defaults to 1. + */ + itkSetMacro( InsidePixelValue, PixelType ); + itkGetConstMacro( InsidePixelValue, PixelType ); + + protected: + EnhancedScalarImageToSizeZoneMatrixFilter(); + virtual ~EnhancedScalarImageToSizeZoneMatrixFilter() {}; + virtual void PrintSelf( std::ostream& os, Indent indent ) const ITK_OVERRIDE; + + /** Standard itk::ProcessObject subclass method. */ + typedef DataObject::Pointer DataObjectPointer; + + typedef ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; + using Superclass::MakeOutput; + virtual DataObjectPointer MakeOutput( DataObjectPointerArraySizeType idx ) ITK_OVERRIDE; + + /** This method causes the filter to generate its output. */ + virtual void GenerateData() ITK_OVERRIDE; + + /** + * Normalize the direction of the offset before it is applied. + * The last non-zero dimension of the offest has to be positive in order + * to match to scanning order of the iterator. Only the sign is changed. + * For example, the input offset (-1, 0) will be normalized as + * (1, 0). + * */ + void NormalizeOffsetDirection(OffsetType &offset); + + private: + + unsigned int m_NumberOfBinsPerAxis; + PixelType m_Min; + PixelType m_Max; + RealType m_MinDistance; + RealType m_MaxDistance; + PixelType m_InsidePixelValue; + + MeasurementVectorType m_LowerBound; + MeasurementVectorType m_UpperBound; + OffsetVectorPointer m_Offsets; + }; + } // end of namespace Statistics +} // end of namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkEnhancedScalarImageToSizeZoneMatrixFilter.hxx" +#endif + +#endif diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.hxx new file mode 100644 index 0000000000..8d234c374b --- /dev/null +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToSizeZoneMatrixFilter.hxx @@ -0,0 +1,431 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +/*========================================================================= +* +* Copyright Insight Software Consortium +* +* 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 +* +* http://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 __itkEnhancedScalarImageToSizeZoneMatrixFilter_hxx +#define __itkEnhancedScalarImageToSizeZoneMatrixFilter_hxx + +#include "itkEnhancedScalarImageToSizeZoneMatrixFilter.h" + +#include "itkConstNeighborhoodIterator.h" +#include "itkNeighborhood.h" +#include "vnl/vnl_math.h" +#include "itkMacro.h" +#include "itkRescaleIntensityImageFilter.h" +#include "itkMaskImageFilter.h" +#include "itkLabelStatisticsImageFilter.h" +#include "itkScalarConnectedComponentImageFilter.h" +#include "itkRelabelComponentImageFilter.h" +#include "itkCastImageFilter.h" + +#include + +namespace itk +{ +namespace Statistics +{ +template +EnhancedScalarImageToSizeZoneMatrixFilter +::EnhancedScalarImageToSizeZoneMatrixFilter() : + m_NumberOfBinsPerAxis( itkGetStaticConstMacro( DefaultBinsPerAxis ) ), + m_Min( NumericTraits::NonpositiveMin() ), + m_Max( NumericTraits::max() ), + m_MinDistance( NumericTraits::ZeroValue() ), + m_MaxDistance( NumericTraits::max() ), + m_InsidePixelValue( NumericTraits::OneValue() ) +{ + this->SetNumberOfRequiredInputs( 1 ); + this->SetNumberOfRequiredOutputs( 1 ); + + const unsigned int measurementVectorSize = 2; + + this->ProcessObject::SetNthOutput( 0, this->MakeOutput( 0 ) ); + HistogramType *output = const_cast( this->GetOutput() ); + output->SetMeasurementVectorSize( measurementVectorSize ); + + this->m_LowerBound.SetSize( measurementVectorSize ); + this->m_UpperBound.SetSize( measurementVectorSize ); + + this->m_LowerBound[0] = this->m_Min; + this->m_LowerBound[1] = this->m_MinDistance; + this->m_UpperBound[0] = this->m_Max; + this->m_UpperBound[1] = this->m_MaxDistance; +} + +template +void +EnhancedScalarImageToSizeZoneMatrixFilter +::SetOffset( const OffsetType offset ) +{ + OffsetVectorPointer offsetVector = OffsetVector::New(); + offsetVector->push_back( offset ); + this->SetOffsets( offsetVector ); +} + +template +void +EnhancedScalarImageToSizeZoneMatrixFilter +::SetInput( const ImageType *image ) +{ + // Process object is not const-correct so the const_cast is required here + this->ProcessObject::SetNthInput( 0, const_cast( image ) ); +} + +template +void +EnhancedScalarImageToSizeZoneMatrixFilter +::SetMaskImage( const ImageType *image ) +{ + // Process object is not const-correct so the const_cast is required here + this->ProcessObject::SetNthInput( 1, const_cast( image ) ); +} + +template +const TImageType * +EnhancedScalarImageToSizeZoneMatrixFilter +::GetInput() const +{ + if( this->GetNumberOfInputs() < 1 ) + { + return ITK_NULLPTR; + } + return static_cast( this->ProcessObject::GetInput( 0 ) ); +} + +template +const TImageType * +EnhancedScalarImageToSizeZoneMatrixFilter +::GetMaskImage() const +{ + if( this->GetNumberOfInputs() < 2 ) + { + return ITK_NULLPTR; + } + return static_cast( this->ProcessObject::GetInput( 1 ) ); +} + +template +const typename EnhancedScalarImageToSizeZoneMatrixFilter::HistogramType * +EnhancedScalarImageToSizeZoneMatrixFilter +::GetOutput() const +{ + const HistogramType *output = + static_cast( this->ProcessObject::GetOutput( 0 ) ); + return output; +} + +template +typename EnhancedScalarImageToSizeZoneMatrixFilter::DataObjectPointer +EnhancedScalarImageToSizeZoneMatrixFilter +::MakeOutput( DataObjectPointerArraySizeType itkNotUsed( idx ) ) +{ + return HistogramType::New().GetPointer(); +} + +template +void +EnhancedScalarImageToSizeZoneMatrixFilter +::GenerateData() +{ + HistogramType *output = + static_cast( this->ProcessObject::GetOutput( 0 ) ); + + const ImageType * inputImage = this->GetInput(); + const ImageType * maskImage = this->GetMaskImage(); + + // First, create an appropriate histogram with the right number of bins + // and mins and maxes correct for the image type. + typename HistogramType::SizeType size( output->GetMeasurementVectorSize() ); + + size.Fill( this->m_NumberOfBinsPerAxis ); + this->m_LowerBound[0] = this->m_Min; + this->m_LowerBound[1] = this->m_MinDistance; + this->m_UpperBound[0] = this->m_Max; + this->m_UpperBound[1] = this->m_MaxDistance; + + output->Initialize( size, this->m_LowerBound, this->m_UpperBound ); + + MeasurementVectorType run( output->GetMeasurementVectorSize() ); + typename HistogramType::IndexType hIndex; + + //Cast the image to a float image - with no respect to the incoming image + //to prevent some non-templated itk issues + typedef itk::Image FloatImageType; + typedef itk::CastImageFilter CastFilterType; + + typename CastFilterType::Pointer caster = CastFilterType::New(); + caster->SetInput(inputImage); + caster->Update(); + typename FloatImageType::Pointer floatImage = caster->GetOutput(); + + MITK_WARN << "InputImage casted."; + + //Cast the mask to an unsigned short image - with no respect to the incomimg maskimage + //to prevent some non-templated itk issues + typedef unsigned short LabelPixelType; + typedef itk::Image LabelImageType; + + typedef itk::CastImageFilter MaskCastFilterType; + typename MaskCastFilterType::Pointer maskCaster = MaskCastFilterType::New(); + maskCaster->SetInput(maskImage); + maskCaster->Update(); + + MITK_WARN << "MaskImage casted."; + + //Set all values out of the mask to (m_Min + m_Max) / 2. + typedef itk::MaskImageFilter< FloatImageType, LabelImageType, FloatImageType > MaskFilterType; + typename MaskFilterType::Pointer maskFilter = MaskFilterType::New(); + maskFilter->SetInput(floatImage); + maskFilter->SetMaskImage(maskCaster->GetOutput()); + maskFilter->SetOutsideValue((m_Max + m_Min) / 2); + maskFilter->Update(); + + MITK_WARN << "InputImage masked."; + + //Rescale intensity to match the size of the histogram + typedef itk::Image< unsigned int, 3 > OutputImageType; + + typedef itk::RescaleIntensityImageFilter< FloatImageType,OutputImageType> RescalerType; + typename RescalerType::Pointer rescaler = RescalerType::New(); + //We use 0 for nans, all valid numbers will be 1 < x < size + rescaler->SetOutputMinimum( 1 ); + rescaler->SetOutputMaximum( size[0] ); + rescaler->SetInput(maskFilter->GetOutput()); + rescaler->Update(); + + typename OutputImageType::Pointer rescaled = rescaler->GetOutput(); + + MITK_WARN << "Intensities rescaled."; + + //Write back the nans because they get lost during rescaling + + int xx = inputImage->GetLargestPossibleRegion().GetSize()[0]; + int yy = inputImage->GetLargestPossibleRegion().GetSize()[1]; + int zz = inputImage->GetLargestPossibleRegion().GetSize()[2]; + + for (int x = 0; x < xx; x++) + { + for (int y = 0; y < yy; y++) + { + for (int z = 0; z < zz; z++) + { + FloatImageType::IndexType indexF; + indexF[0] = x; + indexF[1] = y; + indexF[2] = z; + + OutputImageType::IndexType indexO; + indexO[0] = x; + indexO[1] = y; + indexO[2] = z; + + //Is Pixel NaN? + if(floatImage->GetPixel(indexF) != floatImage->GetPixel(indexF)) + { + rescaled->SetPixel(indexO,-1); + } + } + } + } + + OutputImageType::IndexType indexO; + indexO[0] = 0; + indexO[1] = 2; + indexO[2] = 1; + MITK_WARN << "is -1: " << rescaled->GetPixel(indexO); + indexO[0] = 0; + indexO[1] = 0; + indexO[2] = 0; + MITK_WARN << "is 1: " << rescaled->GetPixel(indexO); + + PixelType distanceThreshold = 1; + + //Calculate the connected components + typedef itk::ScalarConnectedComponentImageFilter + ConnectedComponentImageFilterType; + + typename ConnectedComponentImageFilterType::Pointer connected = ConnectedComponentImageFilterType::New (); + connected->SetInput(rescaled); + connected->SetMaskImage(maskCaster->GetOutput()); + connected->SetDistanceThreshold(distanceThreshold); + connected->Update(); + + MITK_WARN << "Connected components calculated."; + + //Relabel the components + typedef itk::RelabelComponentImageFilter RelabelFilterType; + typename RelabelFilterType::Pointer relabel = RelabelFilterType::New(); + + typename RelabelFilterType::ObjectSizeType minSize = 1; + + relabel->SetInput(connected->GetOutput()); + relabel->SetMinimumObjectSize(minSize); + relabel->Update(); + + MITK_WARN << "Components relabeled."; + + //Get the stats of the componentes + typedef itk::LabelStatisticsImageFilter< FloatImageType, LabelImageType> LabelStatisticsImageFilterType; + typename LabelStatisticsImageFilterType::Pointer labelStatisticsImageFilter = + LabelStatisticsImageFilterType::New(); + labelStatisticsImageFilter->SetLabelInput( relabel->GetOutput() ); + labelStatisticsImageFilter->SetInput(floatImage); + labelStatisticsImageFilter->UseHistogramsOn(); // needed to compute median + labelStatisticsImageFilter->Update(); + + /* + std::cout << "Number of labels: " + << labelStatisticsImageFilter->GetNumberOfLabels() << std::endl; + std::cout << std::endl; + */ + typedef typename LabelStatisticsImageFilterType::ValidLabelValuesContainerType ValidLabelValuesType; + + for(typename ValidLabelValuesType::const_iterator vIt = labelStatisticsImageFilter->GetValidLabelValues().begin(); + vIt != labelStatisticsImageFilter->GetValidLabelValues().end(); + ++vIt) + { + if ( labelStatisticsImageFilter->HasLabel(*vIt) ) + { + LabelPixelType labelValue = *vIt; +/* + MITK_INFO << "Label: " << *vIt; + + MITK_INFO << "\tmin: " + << labelStatisticsImageFilter->GetMinimum( labelValue ); + MITK_INFO << "\tmax: " + << labelStatisticsImageFilter->GetMaximum( labelValue ); + MITK_INFO << "\tmedian: " + << labelStatisticsImageFilter->GetMedian( labelValue ); + MITK_INFO << "\tmean: " + << labelStatisticsImageFilter->GetMean( labelValue ); + MITK_INFO << "\tsigma: " + << labelStatisticsImageFilter->GetSigma( labelValue ); + MITK_INFO << "\tvariance: " + << labelStatisticsImageFilter->GetVariance( labelValue ); + MITK_INFO << "\tsum: " + << labelStatisticsImageFilter->GetSum( labelValue ); + MITK_INFO << "\tcount: " + << labelStatisticsImageFilter->GetCount( labelValue ); + MITK_INFO << "\tregion: " + << labelStatisticsImageFilter->GetRegion( labelValue ); + +*/ + run[0] = (labelStatisticsImageFilter->GetMinimum( labelValue ) + labelStatisticsImageFilter->GetMinimum( labelValue )) /2; + run[1] = labelStatisticsImageFilter->GetCount( labelValue ); + + //Check for NaN and inf + if(run[0] == run[0] && !std::isinf(std::abs(run[0]))) + { + output->GetIndex( run, hIndex ); + output->IncreaseFrequencyOfIndex( hIndex, 1 ); + } + } + } +} + +template +void +EnhancedScalarImageToSizeZoneMatrixFilter +::SetPixelValueMinMax( PixelType min, PixelType max ) +{ + if( this->m_Min != min || this->m_Max != max ) + { + itkDebugMacro( "setting Min to " << min << "and Max to " << max ); + this->m_Min = min; + this->m_Max = max; + this->Modified(); + } +} + +template +void +EnhancedScalarImageToSizeZoneMatrixFilter +::SetDistanceValueMinMax( RealType min, RealType max ) +{ + if( this->m_MinDistance != min || this->m_MaxDistance != max ) + { + itkDebugMacro( "setting MinDistance to " << min << "and MaxDistance to " + << max ); + this->m_MinDistance = min; + this->m_MaxDistance = max; + this->Modified(); + } +} + +template +void +EnhancedScalarImageToSizeZoneMatrixFilter +::PrintSelf( std::ostream& os, Indent indent ) const +{ + Superclass::PrintSelf( os,indent ); + os << indent << "Offsets: " << this->GetOffsets() << std::endl; + os << indent << "Min: " << this->m_Min << std::endl; + os << indent << "Max: " << this->m_Max << std::endl; + os << indent << "Min distance: " << this->m_MinDistance << std::endl; + os << indent << "Max distance: " << this->m_MaxDistance << std::endl; + os << indent << "NumberOfBinsPerAxis: " << this->m_NumberOfBinsPerAxis + << std::endl; + os << indent << "InsidePixelValue: " << this->m_InsidePixelValue << std::endl; +} + +template +void +EnhancedScalarImageToSizeZoneMatrixFilter +::NormalizeOffsetDirection(OffsetType &offset) +{ + MITK_WARN <<" -> Size zone old offset = " << offset; + itkDebugMacro("old offset = " << offset << std::endl); + int sign = 1; + bool metLastNonZero = false; + for (int i = offset.GetOffsetDimension()-1; i>=0; i--) + { + if (metLastNonZero) + { + offset[i] *= sign; + } + else if (offset[i] != 0) + { + sign = (offset[i] > 0 ) ? 1 : -1; + metLastNonZero = true; + offset[i] *= sign; + } + } + + MITK_WARN << " -> size zone new offset = " << offset; + itkDebugMacro("new offset = " << offset << std::endl); +} +} // end of namespace Statistics +} // end of namespace itk + +#endif diff --git a/Modules/Classification/CLUtilities/include/mitkGIFGrayLevelSizeZone.h b/Modules/Classification/CLUtilities/include/mitkGIFGrayLevelSizeZone.h new file mode 100644 index 0000000000..0bf67bf627 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/mitkGIFGrayLevelSizeZone.h @@ -0,0 +1,51 @@ +#ifndef mitkGIFGrayLevelSizeZone_h +#define mitkGIFGrayLevelSizeZone_h + +#include +#include +#include + +namespace mitk +{ + class MITKCLUTILITIES_EXPORT GIFGrayLevelSizeZone : public AbstractGlobalImageFeature + { + public: + mitkClassMacro(GIFGrayLevelSizeZone,AbstractGlobalImageFeature) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + GIFGrayLevelSizeZone(); + + /** + * \brief Calculates the Cooccurence-Matrix based features for this class. + */ + virtual FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + + /** + * \brief Returns a list of the names of all features that are calculated from this class + */ + virtual FeatureNameListType GetFeatureNames() override; + + itkGetConstMacro(Range,double); + itkSetMacro(Range, double); + + itkGetConstMacro(UseCtRange, bool); + itkSetMacro(UseCtRange, bool); + + itkGetConstMacro(Direction, unsigned int); + itkSetMacro(Direction, unsigned int); + + struct ParameterStruct + { + bool m_UseCtRange; + double m_Range; + unsigned int m_Direction; + }; + + private: + double m_Range; + bool m_UseCtRange; + unsigned int m_Direction; + }; +} +#endif //mitkGIFGrayLevelSizeZone_h diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGrayLevelSizeZone.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGrayLevelSizeZone.cpp new file mode 100644 index 0000000000..10a7592630 --- /dev/null +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFGrayLevelSizeZone.cpp @@ -0,0 +1,218 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +// MITK +#include +#include +#include + +// ITK +#include +#include + +// STL +#include + +template +void + CalculateGrayLevelSizeZoneFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFGrayLevelSizeZone::FeatureListType & featureList, mitk::GIFGrayLevelSizeZone::ParameterStruct params) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + typedef itk::Statistics::EnhancedScalarImageToSizeZoneFeaturesFilter FilterType; + typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; + typedef typename FilterType::SizeZoneFeaturesFilterType TextureFilterType; + + typename MaskType::Pointer maskImage = MaskType::New(); + mitk::CastToItkImage(mask, maskImage); + + typename FilterType::Pointer filter = FilterType::New(); + + typename FilterType::OffsetVector::Pointer newOffset = FilterType::OffsetVector::New(); + auto oldOffsets = filter->GetOffsets(); + auto oldOffsetsIterator = oldOffsets->Begin(); + while (oldOffsetsIterator != oldOffsets->End()) + { + bool continueOuterLoop = false; + typename FilterType::OffsetType offset = oldOffsetsIterator->Value(); + for (unsigned int i = 0; i < VImageDimension; ++i) + { + if (params.m_Direction == i + 2 && offset[i] != 0) + { + continueOuterLoop = true; + } + } + if (params.m_Direction == 1) + { + offset[0] = 0; + offset[1] = 0; + offset[2] = 1; + newOffset->push_back(offset); + break; + } + + oldOffsetsIterator++; + if (continueOuterLoop) + continue; + newOffset->push_back(offset); + } + filter->SetOffsets(newOffset); + + + // All features are required + typename FilterType::FeatureNameVectorPointer requestedFeatures = FilterType::FeatureNameVector::New(); + requestedFeatures->push_back(TextureFilterType::SmallZoneEmphasis); + requestedFeatures->push_back(TextureFilterType::LargeZoneEmphasis); + requestedFeatures->push_back(TextureFilterType::GreyLevelNonuniformity); + requestedFeatures->push_back(TextureFilterType::SizeZoneNonuniformity); + requestedFeatures->push_back(TextureFilterType::LowGreyLevelZoneEmphasis); + requestedFeatures->push_back(TextureFilterType::HighGreyLevelZoneEmphasis); + requestedFeatures->push_back(TextureFilterType::SmallZoneLowGreyLevelEmphasis); + requestedFeatures->push_back(TextureFilterType::SmallZoneHighGreyLevelEmphasis); + requestedFeatures->push_back(TextureFilterType::LargeZoneLowGreyLevelEmphasis); + requestedFeatures->push_back(TextureFilterType::LargeZoneHighGreyLevelEmphasis); + requestedFeatures->push_back(TextureFilterType::ZonePercentage); + requestedFeatures->push_back(TextureFilterType::GreyLevelVariance); + requestedFeatures->push_back(TextureFilterType::SizeZoneVariance); + requestedFeatures->push_back(TextureFilterType::ZoneEntropy); + + typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); + minMaxComputer->SetImage(itkImage); + minMaxComputer->Compute(); + + filter->SetInput(itkImage); + filter->SetMaskImage(maskImage); + filter->SetRequestedFeatures(requestedFeatures); + int rangeOfPixels = params.m_Range; + if (rangeOfPixels < 2) + rangeOfPixels = 256; + + if (params.m_UseCtRange) + { + filter->SetPixelValueMinMax((TPixel)(-1024.5),(TPixel)(3096.5)); + filter->SetNumberOfBinsPerAxis(3096.5+1024.5); + } else + { + filter->SetPixelValueMinMax(minMaxComputer->GetMinimum(),minMaxComputer->GetMaximum()); + filter->SetNumberOfBinsPerAxis(rangeOfPixels); + } + + filter->SetDistanceValueMinMax(0,rangeOfPixels); + + filter->Update(); + + auto featureMeans = filter->GetFeatureMeans (); + auto featureStd = filter->GetFeatureStandardDeviations(); + + std::ostringstream ss; + ss << rangeOfPixels; + std::string strRange = ss.str(); + for (std::size_t i = 0; i < featureMeans->size(); ++i) + { + switch (i) + { + case TextureFilterType::SmallZoneEmphasis : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") SmallZoneEmphasis Means",featureMeans->ElementAt(i))); + break; + case TextureFilterType::LargeZoneEmphasis : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") LargeZoneEmphasis Means",featureMeans->ElementAt(i))); + break; + case TextureFilterType::GreyLevelNonuniformity : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") GreyLevelNonuniformity Means",featureMeans->ElementAt(i))); + break; + case TextureFilterType::SizeZoneNonuniformity : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") SizeZoneNonuniformity Means",featureMeans->ElementAt(i))); + break; + case TextureFilterType::LowGreyLevelZoneEmphasis : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") LowGreyLevelZoneEmphasis Means",featureMeans->ElementAt(i))); + break; + case TextureFilterType::HighGreyLevelZoneEmphasis : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") HighGreyLevelZoneEmphasis Means",featureMeans->ElementAt(i))); + break; + case TextureFilterType::SmallZoneLowGreyLevelEmphasis : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") SmallZoneLowGreyLevelEmphasis Means",featureMeans->ElementAt(i))); + break; + case TextureFilterType::SmallZoneHighGreyLevelEmphasis : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") SmallZoneHighGreyLevelEmphasis Means",featureMeans->ElementAt(i))); + break; + case TextureFilterType::LargeZoneLowGreyLevelEmphasis : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") LargeZoneLowGreyLevelEmphasis Means",featureMeans->ElementAt(i))); + break; + case TextureFilterType::LargeZoneHighGreyLevelEmphasis : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") LargeZoneHighGreyLevelEmphasis Means",featureMeans->ElementAt(i))); + break; + case TextureFilterType::ZonePercentage : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") ZonePercentage Means",featureMeans->ElementAt(i))); + break; + case TextureFilterType::GreyLevelVariance : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") GreyLevelVariance Means",featureMeans->ElementAt(i))); + break; + case TextureFilterType::SizeZoneVariance : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") SizeZoneVariance Means",featureMeans->ElementAt(i))); + break; + case TextureFilterType::ZoneEntropy : + featureList.push_back(std::make_pair("SizeZone. ("+ strRange+") ZoneEntropy Means",featureMeans->ElementAt(i))); + break; + default: + break; + } + } +} + +mitk::GIFGrayLevelSizeZone::GIFGrayLevelSizeZone(): +m_Range(1.0), m_UseCtRange(false), m_Direction(0) +{ +} + +mitk::GIFGrayLevelSizeZone::FeatureListType mitk::GIFGrayLevelSizeZone::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +{ + FeatureListType featureList; + + ParameterStruct params; + params.m_UseCtRange=m_UseCtRange; + params.m_Range = m_Range; + params.m_Direction = m_Direction; + + AccessByItk_3(image, CalculateGrayLevelSizeZoneFeatures, mask, featureList,params); + + return featureList; +} + +mitk::GIFGrayLevelSizeZone::FeatureNameListType mitk::GIFGrayLevelSizeZone::GetFeatureNames() +{ + FeatureNameListType featureList; + featureList.push_back("SizeZone. SmallZoneEmphasis Means"); + featureList.push_back("SizeZone. SmallZoneEmphasis Std."); + featureList.push_back("SizeZone. LargeZoneEmphasis Means"); + featureList.push_back("SizeZone. LargeZoneEmphasis Std."); + featureList.push_back("SizeZone. GreyLevelNonuniformity Means"); + featureList.push_back("SizeZone. GreyLevelNonuniformity Std."); + featureList.push_back("SizeZone. SizeZoneNonuniformity Means"); + featureList.push_back("SizeZone. SizeZoneNonuniformity Std."); + featureList.push_back("SizeZone. LowGreyLevelZoneEmphasis Means"); + featureList.push_back("SizeZone. LowGreyLevelZoneEmphasis Std."); + featureList.push_back("SizeZone. HighGreyLevelZoneEmphasis Means"); + featureList.push_back("SizeZone. HighGreyLevelZoneEmphasis Std."); + featureList.push_back("SizeZone. SmallZoneLowGreyLevelEmphasis Means"); + featureList.push_back("SizeZone. SmallZoneLowGreyLevelEmphasis Std."); + featureList.push_back("SizeZone. SmallZoneHighGreyLevelEmphasis Means"); + featureList.push_back("SizeZone. SmallZoneHighGreyLevelEmphasis Std."); + featureList.push_back("SizeZone. LargeZoneHighGreyLevelEmphasis Means"); + featureList.push_back("SizeZone. LargeZoneHighGreyLevelEmphasis Std."); + return featureList; +}