Skip to content

Commit a13e986

Browse files
authored
Merge pull request #12 from blowekamp/AddFirstOrderTextureHistorgram
Add first order texture historgram
2 parents b0c09ce + b95a220 commit a13e986

8 files changed

+575
-5
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*=========================================================================
2+
*
3+
* Copyright Insight Software Consortium
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0.txt
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*=========================================================================*/
18+
#ifndef itkFirstOrderTextureFeaturesImageFilter_h
19+
#define itkFirstOrderTextureFeaturesImageFilter_h
20+
21+
#include "itkMovingHistogramImageFilter.h"
22+
#include "itkFirstOrderTextureHistogram.h"
23+
24+
namespace itk
25+
{
26+
/**
27+
* \class FirstOrderTextureFeaturesImageFilter
28+
* \brief Compute first order statistics in a neighborhood for each
29+
* pixel.
30+
*
31+
* The output of this filter is a multi-component image where each
32+
* pixel is:
33+
* -# mean
34+
* -# minimum
35+
* -# maximum
36+
* -# variance
37+
* -# standard deviation (sigma)
38+
* -# skewness
39+
* -# kurtosis
40+
* -# entropy.
41+
* These first order statistics are computed based on a define
42+
* neighborhood or kernel such as FlatStructuringElement::Box.
43+
*
44+
* The boundary is handle by only considering the pixel in the image,
45+
* so that the boundary pixel have lets data to compute the
46+
* statistics.
47+
*
48+
* \ingroup ITKTextureFeatures
49+
*/
50+
51+
template< class TInputImage, class TOutputImage, class TKernel >
52+
class ITK_TEMPLATE_EXPORT FirstOrderTextureFeaturesImageFilter:
53+
public MovingHistogramImageFilter< TInputImage,
54+
TOutputImage,
55+
TKernel,
56+
typename Function::FirstOrderTextureHistogram< typename TInputImage::PixelType,
57+
typename TOutputImage::PixelType > >
58+
{
59+
public:
60+
/** Standard class typedefs. */
61+
typedef FirstOrderTextureFeaturesImageFilter Self;
62+
typedef MovingHistogramImageFilter< TInputImage, TOutputImage, TKernel,
63+
typename Function::FirstOrderTextureHistogram< typename TInputImage::PixelType, typename TOutputImage::PixelType> > Superclass;
64+
typedef SmartPointer< Self > Pointer;
65+
typedef SmartPointer< const Self > ConstPointer;
66+
67+
/** Standard New method. */
68+
itkNewMacro(Self);
69+
70+
/** Runtime information support. */
71+
itkTypeMacro(FirstOrderTextureFeaturesImageFilter,
72+
MovingHistogramMorphologyImageFilter);
73+
74+
/** Image related typedefs. */
75+
typedef TInputImage InputImageType;
76+
typedef TOutputImage OutputImageType;
77+
typedef typename TInputImage::RegionType RegionType;
78+
typedef typename TInputImage::SizeType SizeType;
79+
typedef typename TInputImage::IndexType IndexType;
80+
typedef typename TInputImage::PixelType PixelType;
81+
typedef typename TInputImage::OffsetType OffsetType;
82+
typedef typename Superclass::OutputImageRegionType OutputImageRegionType;
83+
typedef typename TOutputImage::PixelType OutputPixelType;
84+
85+
/** Image related typedefs. */
86+
itkStaticConstMacro(ImageDimension, unsigned int,
87+
TInputImage::ImageDimension);
88+
protected:
89+
90+
unsigned int GetNumberOfOutputComponents() { return 8;}
91+
92+
FirstOrderTextureFeaturesImageFilter()
93+
{
94+
}
95+
96+
void GenerateOutputInformation()
97+
{
98+
// this methods is overloaded so that if the output image is a
99+
// VectorImage then the correct number of components are set.
100+
101+
Superclass::GenerateOutputInformation();
102+
OutputImageType* output = this->GetOutput();
103+
104+
if ( !output )
105+
{
106+
return;
107+
}
108+
if ( output->GetNumberOfComponentsPerPixel() != this->GetNumberOfOutputComponents() )
109+
{
110+
output->SetNumberOfComponentsPerPixel( this->GetNumberOfOutputComponents() );
111+
}
112+
}
113+
114+
115+
~FirstOrderTextureFeaturesImageFilter() {}
116+
private:
117+
FirstOrderTextureFeaturesImageFilter(const Self &); //purposely not implemented
118+
void operator=(const Self &); //purposely not implemented
119+
}; // end of class
120+
} // end namespace itk
121+
122+
#endif
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*=========================================================================
2+
*
3+
* Copyright Insight Software Consortium
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0.txt
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*=========================================================================*/
18+
#ifndef itkFirstOrderTextureHistogram_h
19+
#define itkFirstOrderTextureHistogram_h
20+
21+
#include "itkNumericTraits.h"
22+
#include "itkMath.h"
23+
#include <map>
24+
25+
namespace itk
26+
{
27+
namespace Function
28+
{
29+
30+
/* \class FirstOrderTextureHistogram
31+
*
32+
* An implementation of the "MovingHistogram" interface for the
33+
* MovingHistogramImageFilter class. This implementation maintains a
34+
* std::map based "histogram" during iteration and computes first
35+
* order statistics from the histogram.
36+
*
37+
* \ingroup ITKTextureFeatures
38+
*/
39+
template< class TInputPixel, class TOutputPixel >
40+
class ITK_TEMPLATE_EXPORT FirstOrderTextureHistogram
41+
{
42+
public:
43+
44+
FirstOrderTextureHistogram()
45+
{
46+
m_Count = 0;
47+
}
48+
49+
void AddPixel(const TInputPixel & p)
50+
{
51+
m_Map[p]++;
52+
++m_Count;
53+
}
54+
55+
void RemovePixel(const TInputPixel & p)
56+
{
57+
58+
// insert new item if one doesn't exist
59+
typename MapType::iterator it = m_Map.find( p );
60+
61+
assert( it != m_Map.end() );
62+
63+
if ( --(it->second) == 0 )
64+
{
65+
m_Map.erase( it );
66+
}
67+
--m_Count;
68+
69+
}
70+
71+
TOutputPixel GetValue(const TInputPixel &)
72+
{
73+
TOutputPixel out;
74+
NumericTraits<TOutputPixel>::SetLength( out, 8 );
75+
76+
double sum = 0.0;
77+
double sum2 = 0.0;
78+
double sum3 = 0.0;
79+
double sum4 = 0.0;
80+
const size_t count = m_Count;
81+
82+
double entropy = 0.0;
83+
size_t curCount = 0;
84+
85+
for ( typename MapType::iterator i = m_Map.begin(); i != m_Map.end(); ++i )
86+
{
87+
double t = double(i->first)*double(i->second);
88+
sum += t;
89+
sum2 += ( t *= double(i->first) );
90+
sum3 += ( t *= double(i->first) );
91+
sum4 += ( t *= double(i->first) );
92+
93+
curCount += i->second;
94+
95+
const double p_x = double( i->second ) / count;
96+
entropy += -p_x*std::log( p_x ) / itk::Math::ln2;
97+
}
98+
99+
const double mean = sum / count;
100+
101+
// unbiased estimate
102+
const double variance = ( sum2 - ( sum * sum ) / count ) / ( count - 1 );
103+
const double sigma = std::sqrt(variance);
104+
double skewness = 0.0;
105+
double kurtosis = 0.0;
106+
if(std::abs(variance * sigma) > itk::NumericTraits<double>::min())
107+
{
108+
109+
skewness = ( ( sum3 - 3.0 * mean * sum2 ) / count + 2.0 * mean * mean*mean ) / ( variance * sigma );
110+
}
111+
if(std::abs(variance) > itk::NumericTraits<double>::min())
112+
{
113+
kurtosis = ( sum4 / count + mean *( -4.0 * sum3 / count + mean * ( 6.0 *sum2 / count - 3.0 * mean * mean ))) /
114+
( variance * variance ) - 3.0;
115+
}
116+
117+
unsigned int i = 0;
118+
out[i++] = mean;
119+
out[i++] = m_Map.begin()->first;
120+
out[i++] = m_Map.rbegin()->first;
121+
out[i++] = variance;
122+
out[i++] = sigma;
123+
out[i++] = skewness;
124+
out[i++] = kurtosis;
125+
out[i++] = entropy;
126+
return out;
127+
}
128+
129+
void AddBoundary(){}
130+
131+
void RemoveBoundary(){}
132+
133+
private:
134+
typedef typename std::map< TInputPixel, size_t > MapType;
135+
136+
MapType m_Map;
137+
size_t m_Count;
138+
};
139+
140+
} // end namespace Function
141+
} // end namespace itk
142+
#endif

itk-module.cmake

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,23 @@ file(READ "${MY_CURRENT_DIR}/README.rst" DOCUMENTATION)
1010
# By convention those modules outside of ITK are not prefixed with
1111
# ITK.
1212

13+
if( NOT "${ITK_VERSION_MAJOR}.${ITK_VERSION_MINOR}" VERSION_LESS "4.12" )
14+
set(_GoogleTest_DEPENDS ITKGoogleTest)
15+
endif()
16+
1317
# define the dependencies of the include module and the tests
1418
itk_module(TextureFeatures
1519
DEPENDS
1620
ITKCommon
1721
ITKStatistics
1822
ITKImageGrid
19-
COMPILE_DEPENDS
20-
ITKImageSources
23+
ITKMathematicalMorphology
2124
TEST_DEPENDS
2225
ITKTestKernel
2326
ITKMetaIO
2427
ITKImageIntensity
28+
ITKImageNoise
29+
${_GoogleTest_DEPENDS}
2530
DESCRIPTION
2631
"${DOCUMENTATION}"
2732
EXCLUDE_FROM_DEFAULT

test/CMakeLists.txt

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ set(TextureFeaturesTests ScalarImageToRunLengthFeaturesImageFilterInstantiationT
1111
ScalarImageToTextureFeaturesImageFilterTestSeparateFeatures.cxx
1212
ScalarImageToTextureFeaturesImageFilterTestWithoutMask.cxx
1313
ScalarImageToTextureFeaturesImageFilterTestWithVectorImage.cxx
14-
ScalarImageToTextureFeaturesImageFilterTestVectorImageSeparateFeatures.cxx)
14+
)
1515

1616
set(TextureFeaturesTests RunLengthTextureFeaturesImageFilterInstantiationTest.cxx
1717
RunLengthTextureFeaturesImageFilterTest.cxx
@@ -24,7 +24,8 @@ set(TextureFeaturesTests RunLengthTextureFeaturesImageFilterInstantiationTest.cx
2424
CoocurrenceTextureFeaturesImageFilterTestSeparateFeatures.cxx
2525
CoocurrenceTextureFeaturesImageFilterTestWithoutMask.cxx
2626
CoocurrenceTextureFeaturesImageFilterTestWithVectorImage.cxx
27-
CoocurrenceTextureFeaturesImageFilterTestVectorImageSeparateFeatures.cxx)
27+
CoocurrenceTextureFeaturesImageFilterTestVectorImageSeparateFeatures.cxx
28+
itkFirstOrderTextureFeaturesImageFilterTest.cxx)
2829

2930
CreateTestDriver(TextureFeatures "${TextureFeatures-Test_LIBRARIES}" "${TextureFeaturesTests}")
3031

@@ -240,4 +241,21 @@ itk_add_test(NAME CoocurrenceTextureFeaturesImageFilterTestVectorImageSeparateFe
240241
--compare DATA{Baseline/resultSeparateFeatures_18.nrrd}
241242
${ITK_TEST_OUTPUT_DIR}/resultVectorImageSeparateFeatures_18.nrrd
242243
CoocurrenceTextureFeaturesImageFilterTestVectorImageSeparateFeatures
243-
DATA{Input/Scan_CBCT_13R.nrrd} DATA{Input/SegmC_CBCT_13R.nrrd} ${ITK_TEST_OUTPUT_DIR}/resultVectorImageSeparateFeatures 10 0 4200 4)
244+
DATA{Input/Scan_CBCT_13R.nrrd} DATA{Input/SegmC_CBCT_13R.nrrd} ${ITK_TEST_OUTPUT_DIR}/resultVectorImageSeparateFeatures 10 0 4200 4)
245+
246+
247+
itk_add_test(NAME itkFirstOrderTextureFeaturesImageFilterTest1
248+
COMMAND TextureFeaturesTestDriver itkFirstOrderTextureFeaturesImageFilterTest
249+
DATA{Input/cthead1.png}
250+
${ITK_TEST_OUTPUT_DIR}/itkTextureFeatureImageFilterTest1.mha
251+
5
252+
)
253+
254+
if( NOT "${ITK_VERSION_MAJOR}.${ITK_VERSION_MINOR}" VERSION_LESS "4.12" )
255+
set(TextureFeaturesGTests
256+
itkFirstOrderTextureFeaturesImageFilterGTest.cxx
257+
)
258+
259+
CreateGoogleTestDriver(TextureFeatures "${TextureFeatures-Test_LIBRARIES}" "${TextureFeaturesGTests}")
260+
261+
endif()

test/Input/cthead1.png.md5

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
e395391caad7463c8231bd5f2ce9d61b

test/Input/cthead1.png.sha512

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
32d5c12cd02f537c901ee48ad2f438fcf5399f7292bf9c0abfb8da91b74fc2e0c4983e9650283db3462d22f05f05a8637a6c3b8188159e4bbd6dc68804a84870

0 commit comments

Comments
 (0)