22 #ifndef otbScalarImageToTexturesFilter_hxx
23 #define otbScalarImageToTexturesFilter_hxx
26 #include "itkImageRegionIteratorWithIndex.h"
27 #include "itkConstNeighborhoodIterator.h"
28 #include "itkImageRegionIterator.h"
29 #include "itkProgressReporter.h"
30 #include "itkNumericTraits.h"
36 template <
class TInputImage,
class TOutputImage>
40 m_NeighborhoodRadius(),
41 m_NumberOfBinsPerAxis(8),
42 m_InputImageMinimum(0),
43 m_InputImageMaximum(255),
48 this->SetNumberOfRequiredOutputs(8);
51 this->SetNthOutput(0, OutputImageType::New());
52 this->SetNthOutput(1, OutputImageType::New());
53 this->SetNthOutput(2, OutputImageType::New());
54 this->SetNthOutput(3, OutputImageType::New());
55 this->SetNthOutput(4, OutputImageType::New());
56 this->SetNthOutput(5, OutputImageType::New());
57 this->SetNthOutput(6, OutputImageType::New());
58 this->SetNthOutput(7, OutputImageType::New());
64 template <
class TInputImage,
class TOutputImage>
69 template <
class TInputImage,
class TOutputImage>
72 if (this->GetNumberOfOutputs() < 1)
79 template <
class TInputImage,
class TOutputImage>
82 if (this->GetNumberOfOutputs() < 2)
89 template <
class TInputImage,
class TOutputImage>
92 if (this->GetNumberOfOutputs() < 3)
99 template <
class TInputImage,
class TOutputImage>
103 if (this->GetNumberOfOutputs() < 4)
110 template <
class TInputImage,
class TOutputImage>
113 if (this->GetNumberOfOutputs() < 5)
120 template <
class TInputImage,
class TOutputImage>
124 if (this->GetNumberOfOutputs() < 6)
131 template <
class TInputImage,
class TOutputImage>
135 if (this->GetNumberOfOutputs() < 7)
142 template <
class TInputImage,
class TOutputImage>
146 if (this->GetNumberOfOutputs() < 8)
153 template <
class TInputImage,
class TOutputImage>
157 Superclass::GenerateOutputInformation();
160 InputRegionType inputRegion = this->GetInput()->GetLargestPossibleRegion();
162 outputRegion.SetIndex(0, 0);
163 outputRegion.SetIndex(1, 0);
164 outputRegion.SetSize(0, 1 + (inputRegion.GetSize(0) - 1 - m_SubsampleOffset[0]) / m_SubsampleFactor[0]);
165 outputRegion.SetSize(1, 1 + (inputRegion.GetSize(1) - 1 - m_SubsampleOffset[1]) / m_SubsampleFactor[1]);
167 typename OutputImageType::SpacingType outSpacing = this->GetInput()->GetSignedSpacing();
168 outSpacing[0] *= m_SubsampleFactor[0];
169 outSpacing[1] *= m_SubsampleFactor[1];
171 typename OutputImageType::PointType outOrigin;
172 this->GetInput()->TransformIndexToPhysicalPoint(inputRegion.GetIndex() + m_SubsampleOffset, outOrigin);
174 for (
unsigned int i = 0; i < this->GetNumberOfOutputs(); i++)
177 outputPtr->SetLargestPossibleRegion(outputRegion);
178 outputPtr->SetOrigin(outOrigin);
179 outputPtr->SetSignedSpacing(outSpacing);
183 template <
class TInputImage,
class TOutputImage>
187 Superclass::GenerateInputRequestedRegion();
193 if (!inputPtr || !outputPtr)
203 typename OutputRegionType::IndexType outputIndex = outputRequestedRegion.GetIndex();
204 typename OutputRegionType::SizeType outputSize = outputRequestedRegion.GetSize();
205 typename InputRegionType::IndexType inputIndex;
206 typename InputRegionType::SizeType inputSize;
210 outputIndex[0] = outputIndex[0] * m_SubsampleFactor[0] + m_SubsampleOffset[0] + inputLargest.GetIndex(0);
211 outputIndex[1] = outputIndex[1] * m_SubsampleFactor[1] + m_SubsampleOffset[1] + inputLargest.GetIndex(1);
212 outputSize[0] = 1 + (outputSize[0] - 1) * m_SubsampleFactor[0];
213 outputSize[1] = 1 + (outputSize[1] - 1) * m_SubsampleFactor[1];
216 for (
unsigned int dim = 0; dim < InputImageType::ImageDimension; ++dim)
218 inputIndex[dim] = std::min(outputIndex[dim], outputIndex[dim] + m_Offset[dim]);
219 inputSize[dim] = std::max(outputIndex[dim] + outputSize[dim], outputIndex[dim] + outputSize[dim] + m_Offset[dim]) - inputIndex[dim];
224 inputRequestedRegion.SetIndex(inputIndex);
225 inputRequestedRegion.SetSize(inputSize);
228 inputRequestedRegion.PadByRadius(m_Radius);
231 if (inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()))
233 inputPtr->SetRequestedRegion(inputRequestedRegion);
238 itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
239 e.SetLocation(ITK_LOCATION);
240 e.SetDescription(
"Requested region is (at least partially) outside the largest possible region.");
241 e.SetDataObject(inputPtr);
246 template <
class TInputImage,
class TOutputImage>
249 unsigned int minRadius = 0;
250 for (
unsigned int i = 0; i < m_Offset.GetOffsetDimension(); i++)
252 unsigned int distance = std::abs(m_Offset[i]);
253 if (distance > minRadius)
255 minRadius = distance;
258 m_NeighborhoodRadius.Fill(minRadius);
261 template <
class TInputImage,
class TOutputImage>
276 itk::ImageRegionIteratorWithIndex<OutputImageType> energyIt(energyPtr, outputRegionForThread);
277 itk::ImageRegionIterator<OutputImageType> entropyIt(entropyPtr, outputRegionForThread);
278 itk::ImageRegionIterator<OutputImageType> correlationIt(correlationPtr, outputRegionForThread);
279 itk::ImageRegionIterator<OutputImageType> invDiffMomentIt(invDiffMomentPtr, outputRegionForThread);
280 itk::ImageRegionIterator<OutputImageType> inertiaIt(inertiaPtr, outputRegionForThread);
281 itk::ImageRegionIterator<OutputImageType> clusterShadeIt(clusterShadePtr, outputRegionForThread);
282 itk::ImageRegionIterator<OutputImageType> clusterProminenceIt(clusterProminencePtr, outputRegionForThread);
283 itk::ImageRegionIterator<OutputImageType> haralickCorIt(haralickCorPtr, outputRegionForThread);
286 energyIt.GoToBegin();
287 entropyIt.GoToBegin();
288 correlationIt.GoToBegin();
289 invDiffMomentIt.GoToBegin();
290 inertiaIt.GoToBegin();
291 clusterShadeIt.GoToBegin();
292 clusterProminenceIt.GoToBegin();
293 haralickCorIt.GoToBegin();
295 const double log2 = std::log(2.0);
300 itk::ProgressReporter progress(
this, threadId, outputRegionForThread.GetNumberOfPixels());
303 while (!energyIt.IsAtEnd() && !entropyIt.IsAtEnd() && !correlationIt.IsAtEnd() && !invDiffMomentIt.IsAtEnd() && !inertiaIt.IsAtEnd() &&
304 !clusterShadeIt.IsAtEnd() && !clusterProminenceIt.IsAtEnd() && !haralickCorIt.IsAtEnd())
307 typename InputRegionType::IndexType inputIndex;
308 typename InputRegionType::SizeType inputSize;
311 typename OutputImageType::IndexType outIndex;
315 for (
unsigned int dim = 0; dim < InputImageType::ImageDimension; ++dim)
317 outIndex[dim] = energyIt.GetIndex()[dim] * m_SubsampleFactor[dim] + m_SubsampleOffset[dim] + inputLargest.GetIndex(dim);
318 inputIndex[dim] = outIndex[dim] - m_Radius[dim];
319 inputSize[dim] = 2 * m_Radius[dim] + 1;
324 inputRegion.SetIndex(inputIndex);
325 inputRegion.SetSize(inputSize);
326 inputRegion.Crop(inputPtr->GetRequestedRegion());
329 GLCIList->Initialize(m_NumberOfBinsPerAxis, m_InputImageMinimum, m_InputImageMaximum);
331 typedef itk::ConstNeighborhoodIterator<InputImageType> NeighborhoodIteratorType;
332 NeighborhoodIteratorType neighborIt;
333 neighborIt = NeighborhoodIteratorType(m_NeighborhoodRadius, inputPtr, inputRegion);
334 for (neighborIt.GoToBegin(); !neighborIt.IsAtEnd(); ++neighborIt)
336 const InputPixelType centerPixelIntensity = neighborIt.GetCenterPixel();
338 const InputPixelType pixelIntensity = neighborIt.GetPixel(m_Offset, pixelInBounds);
344 GLCIList->AddPixelPair(centerPixelIntensity, pixelIntensity);
347 double pixelMean = 0.;
349 double marginalDevSquared = 0.;
350 double pixelVariance = 0.;
353 std::vector<double> marginalSums(m_NumberOfBinsPerAxis, 0);
357 double totalFrequency =
static_cast<double>(GLCIList->GetTotalFrequency());
360 typename VectorType::iterator it = glcVector.begin();
361 while (it != glcVector.end())
363 double frequency = (*it).second / totalFrequency;
365 pixelMean += index[0] * frequency;
366 marginalSums[index[0]] += frequency;
380 std::vector<double>::const_iterator msIt = marginalSums.begin();
381 marginalMean = *msIt;
384 for (
int k = 2; msIt != marginalSums.end(); ++k, ++msIt)
386 double M_k_minus_1 = marginalMean;
387 double S_k_minus_1 = marginalDevSquared;
389 double M_k = M_k_minus_1 + (x_k - M_k_minus_1) / k;
390 double S_k = S_k_minus_1 + (x_k - M_k_minus_1) * (x_k - M_k);
392 marginalDevSquared = S_k;
394 marginalDevSquared = marginalDevSquared / m_NumberOfBinsPerAxis;
397 constVectorIt = glcVector.begin();
398 while (constVectorIt != glcVector.end())
402 pixelVariance += (index[0] - pixelMean) * (index[0] - pixelMean) * frequency;
406 double pixelVarianceSquared = pixelVariance * pixelVariance;
410 if (pixelVarianceSquared < GetPixelValueTolerance())
412 pixelVarianceSquared = 1.;
417 PixelValueType entropy = itk::NumericTraits<PixelValueType>::Zero;
418 PixelValueType correlation = itk::NumericTraits<PixelValueType>::Zero;
419 PixelValueType inverseDifferenceMoment = itk::NumericTraits<PixelValueType>::Zero;
420 PixelValueType inertia = itk::NumericTraits<PixelValueType>::Zero;
421 PixelValueType clusterShade = itk::NumericTraits<PixelValueType>::Zero;
422 PixelValueType clusterProminence = itk::NumericTraits<PixelValueType>::Zero;
423 PixelValueType haralickCorrelation = itk::NumericTraits<PixelValueType>::Zero;
426 constVectorIt = glcVector.begin();
427 while (constVectorIt != glcVector.end())
431 energy += frequency * frequency;
432 entropy -= (frequency > GetPixelValueTolerance()) ? frequency * std::log(frequency) / log2 : 0;
433 correlation += ((index[0] - pixelMean) * (index[1] - pixelMean) * frequency) / pixelVarianceSquared;
434 inverseDifferenceMoment += frequency / (1.0 + (index[0] - index[1]) * (index[0] - index[1]));
435 inertia += (index[0] - index[1]) * (index[0] - index[1]) * frequency;
436 clusterShade += std::pow((index[0] - pixelMean) + (index[1] - pixelMean), 3) * frequency;
437 clusterProminence += std::pow((index[0] - pixelMean) + (index[1] - pixelMean), 4) * frequency;
438 haralickCorrelation += index[0] * index[1] * frequency;
442 haralickCorrelation = (fabs(marginalDevSquared) > 1E-8) ? (haralickCorrelation - marginalMean * marginalMean) / marginalDevSquared : 0;
445 energyIt.Set(energy);
446 entropyIt.Set(entropy);
447 correlationIt.Set(correlation);
448 invDiffMomentIt.Set(inverseDifferenceMoment);
449 inertiaIt.Set(inertia);
450 clusterShadeIt.Set(clusterShade);
451 clusterProminenceIt.Set(clusterProminence);
452 haralickCorIt.Set(haralickCorrelation);
455 progress.CompletedPixel();
464 ++clusterProminenceIt;