OTB  9.0.0
Orfeo Toolbox
otbShapeAttributesLabelMapFilter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1999-2011 Insight Software Consortium
3  * Copyright (C) 2005-2022 Centre National d'Etudes Spatiales (CNES)
4  *
5  * This file is part of Orfeo Toolbox
6  *
7  * https://www.orfeo-toolbox.org/
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 #ifndef otbShapeAttributesLabelMapFilter_hxx
23 #define otbShapeAttributesLabelMapFilter_hxx
24 
26 #include "itkProgressReporter.h"
27 #include "itkConstNeighborhoodIterator.h"
28 #include "itkConstShapedNeighborhoodIterator.h"
29 #include "itkLabelMapToLabelImageFilter.h"
30 #include "itkConstantBoundaryCondition.h"
31 #include "itkGeometryUtilities.h"
32 #include "itkConnectedComponentAlgorithm.h"
33 #include "vnl/algo/vnl_real_eigensystem.h"
34 #include "vnl/algo/vnl_symmetric_eigensystem.h"
35 
36 #include "otbMacro.h"
37 #include <deque>
38 
39 namespace otb
40 {
41 
42 namespace Functor
43 {
44 
45 template <class TLabelObject, class TLabelImage>
47  : m_ComputeFeretDiameter(false), m_ComputePerimeter(false), m_ComputeFlusser(true), m_ComputePolygon(true), m_ReducedAttributeSet(true), m_LabelImage(nullptr)
48 {
49 }
50 
52 template <class TLabelObject, class TLabelImage>
54 {
55  // Initialize response
56  bool resp = true;
57 
58  // Check for differences
59  resp = resp && (m_ComputeFeretDiameter != self.m_ComputeFeretDiameter);
60  resp = resp && (m_ComputePerimeter != self.m_ComputePerimeter);
61  resp = resp && (m_ReducedAttributeSet != self.m_ReducedAttributeSet);
62  resp = resp && (m_LabelImage != self.m_LabelImage);
63 
64  // Return
65  return resp;
66 }
67 
69 template <class TLabelObject, class TLabelImage>
71 {
72  // Call the != implementation
73  return !(this != self);
74 }
75 
77 template <class TLabelObject, class TLabelImage>
79 {
80  m_ComputePerimeter = flag;
81 }
82 
84 template <class TLabelObject, class TLabelImage>
86 {
87  return m_ComputePerimeter;
88 }
89 
91 template <class TLabelObject, class TLabelImage>
93 {
94  m_ComputePolygon = flag;
95 }
96 
98 template <class TLabelObject, class TLabelImage>
100 {
101  return m_ComputePolygon;
102 }
103 
105 template <class TLabelObject, class TLabelImage>
107 {
108  m_ComputeFlusser = flag;
109 }
110 
112 template <class TLabelObject, class TLabelImage>
114 {
115  return m_ComputeFlusser;
116 }
117 
119 template <class TLabelObject, class TLabelImage>
121 {
122  m_ComputeFeretDiameter = flag;
123 }
124 
126 template <class TLabelObject, class TLabelImage>
128 {
129  return m_ComputeFeretDiameter;
130 }
131 
133 template <class TLabelObject, class TLabelImage>
135 {
136  m_ReducedAttributeSet = flag;
137 }
138 
140 template <class TLabelObject, class TLabelImage>
142 {
143  return m_ReducedAttributeSet;
144 }
145 
148 template <class TLabelObject, class TLabelImage>
150 {
151  m_LabelImage = image;
152 }
153 
155 template <class TLabelObject, class TLabelImage>
157 {
158  return m_LabelImage;
159 }
160 
161 
165 template <class TLabelObject, class TLabelImage>
167 {
168  const typename LabelObjectType::LabelType& label = lo->GetLabel();
169 
170  // TODO: compute sizePerPixel, borderMin and borderMax in BeforeThreadedGenerateData() ?
171 
172  // compute the size per pixel, to be used later
173  double sizePerPixel = 1;
174  for (DimensionType i = 0; i < LabelObjectType::ImageDimension; ++i)
175  {
176  sizePerPixel *= std::abs(m_LabelImage->GetSignedSpacing()[i]);
177  }
178 
179  typename std::vector<double> sizePerPixelPerDimension;
180  for (DimensionType i = 0; i < LabelObjectType::ImageDimension; ++i)
181  {
182  sizePerPixelPerDimension.push_back(sizePerPixel / std::abs(m_LabelImage->GetSignedSpacing()[i]));
183  }
184 
185  // compute the max the index on the border of the image
186  typename LabelObjectType::IndexType borderMin = m_LabelImage->GetLargestPossibleRegion().GetIndex();
187  typename LabelObjectType::IndexType borderMax = borderMin;
188  for (DimensionType i = 0; i < LabelObjectType::ImageDimension; ++i)
189  {
190  borderMax[i] += borderMin[i] + m_LabelImage->GetLargestPossibleRegion().GetSize()[i] - 1;
191  }
192 
193  // init the vars
194  unsigned long size = 0;
195  itk::ContinuousIndex<double, LabelObjectType::ImageDimension> centroid;
196  centroid.Fill(0);
197  typename LabelObjectType::IndexType mins;
198  mins.Fill(itk::NumericTraits<long>::max());
199  typename LabelObjectType::IndexType maxs;
200  maxs.Fill(itk::NumericTraits<long>::NonpositiveMin());
201  unsigned long sizeOnBorder = 0;
202  double physicalSizeOnBorder = 0;
203  itk::Matrix<double, LabelObjectType::ImageDimension, LabelObjectType::ImageDimension> centralMoments;
204  centralMoments.Fill(0);
205 
207  lit.GoToBegin();
208  // lit = IteratorType( ref );
209  // typename LabelObjectType::LineContainerType& lineContainer = lo->GetLineContainer();
210 
211  // iterate over all the lines
212  while (!lit.IsAtEnd())
213  // for (lit = lineContainer.begin(); lit != lineContainer.end(); lit++)
214  {
215  const typename LabelObjectType::IndexType& idx = lit.GetLine().GetIndex();
216  unsigned long length = lit.GetLine().GetLength();
217 
218  // update the size
219  size += length;
220 
221  // update the centroid - and report the progress
222  // first, update the axes which are not 0
223  for (DimensionType i = 1; i < LabelObjectType::ImageDimension; ++i)
224  {
225  centroid[i] += length * idx[i];
226  }
227  // then, update the axis 0
228  centroid[0] += idx[0] * length + (length * (length - 1)) / 2.0;
229 
230  // update the mins and maxs
231  for (DimensionType i = 0; i < LabelObjectType::ImageDimension; ++i)
232  {
233  if (idx[i] < mins[i])
234  {
235  mins[i] = idx[i];
236  }
237  if (idx[i] > maxs[i])
238  {
239  maxs[i] = idx[i];
240  }
241  }
242  // must fix the max for the axis 0
243  if (idx[0] + (long)length > maxs[0])
244  {
245  maxs[0] = idx[0] + length - 1;
246  }
247 
248  // object is on a border ?
249  bool isOnBorder = false;
250  for (DimensionType i = 1; i < LabelObjectType::ImageDimension; ++i)
251  {
252  if (idx[i] == borderMin[i] || idx[i] == borderMax[i])
253  {
254  isOnBorder = true;
255  break;
256  }
257  }
258  if (isOnBorder)
259  {
260  // the line touch a border on a dimension other than 0, so
261  // all the line touch a border
262  sizeOnBorder += length;
263  }
264  else
265  {
266  // we must check for the dimension 0
267  bool isOnBorder0 = false;
268  if (idx[0] == borderMin[0])
269  {
270  // one more pixel on the border
271  sizeOnBorder++;
272  isOnBorder0 = true;
273  }
274  if (!isOnBorder0 || length > 1)
275  {
276  // we can check for the end of the line
277  if (idx[0] + (long)length - 1 == borderMax[0])
278  {
279  // one more pixel on the border
280  sizeOnBorder++;
281  }
282  }
283  }
284 
285  // physical size on border
286  // first, the dimension 0
287  if (idx[0] == borderMin[0])
288  {
289  // the beginning of the line
290  physicalSizeOnBorder += sizePerPixelPerDimension[0];
291  }
292  if (idx[0] + (long)length - 1 == borderMax[0])
293  {
294  // and the end of the line
295  physicalSizeOnBorder += sizePerPixelPerDimension[0];
296  }
297  // then the other dimensions
298  for (DimensionType i = 1; i < LabelObjectType::ImageDimension; ++i)
299  {
300  if (idx[i] == borderMin[i])
301  {
302  // one border
303  physicalSizeOnBorder += sizePerPixelPerDimension[i] * length;
304  }
305  if (idx[i] == borderMax[i])
306  {
307  // and the other
308  physicalSizeOnBorder += sizePerPixelPerDimension[i] * length;
309  }
310  }
311 
312  /*
313  // moments computation
314  // ****************************************************************
315  // that commented code is the basic implementation. The next piece of code
316  // give the same result in a much efficient way, by using expanded formulae
317  // allowed by the binary case instead of loops.
318  // ****************************************************************
319  long endIdx0 = idx[0] + length;
320  for( typename LabelObjectType::IndexType iidx = idx; iidx[0]<endIdx0; iidx[0]++)
321  {
322  typename TLabelImage::PointType pP;
323  m_LabelImage->TransformIndexToPhysicalPoint(iidx, pP);
324 
325  for(unsigned int i=0; i<LabelObjectType::ImageDimension; ++i)
326  {
327  for(unsigned int j=0; j<LabelObjectType::ImageDimension; ++j)
328  {
329  centralMoments[i][j] += pP[i] * pP[j];
330  }
331  }
332  }
333  */
334 
335  // get the physical position and the spacing - they are used several times later
336  typename TLabelImage::PointType physicalPosition;
337  m_LabelImage->TransformIndexToPhysicalPoint(idx, physicalPosition);
338  const typename TLabelImage::SpacingType& spacing = m_LabelImage->GetSignedSpacing();
339  // the sum of x positions, also reused several times
340  double sumX = length * (physicalPosition[0] + (spacing[0] * (length - 1)) / 2.0);
341  // the real job - the sum of square of x positions
342  // that's the central moments for dims 0, 0
343  centralMoments[0][0] +=
344  length * (physicalPosition[0] * physicalPosition[0] + spacing[0] * (length - 1) * ((spacing[0] * (2 * length - 1)) / 6.0 + physicalPosition[0]));
345  // the other ones
346  for (DimensionType i = 1; i < LabelObjectType::ImageDimension; ++i)
347  {
348  // do this one here to avoid the double assignment in the following loop
349  // when i == j
350  centralMoments[i][i] += length * physicalPosition[i] * physicalPosition[i];
351  // central moments are symmetrics, so avoid to compute them 2 times
352  for (DimensionType j = i + 1; j < LabelObjectType::ImageDimension; ++j)
353  {
354  // note that we won't use that code if the image dimension is less than 3
355  // --> the tests should be in 3D at least
356  double cm = length * physicalPosition[i] * physicalPosition[j];
357  centralMoments[i][j] += cm;
358  centralMoments[j][i] += cm;
359  }
360  // the last moments: the ones for the dimension 0
361  double cm = sumX * physicalPosition[i];
362  centralMoments[i][0] += cm;
363  centralMoments[0][i] += cm;
364  }
365  ++lit;
366  }
367 
368  // final computation
369  typename TLabelImage::SizeType regionSize;
370  double minSize = itk::NumericTraits<double>::max();
371  double maxSize = itk::NumericTraits<double>::NonpositiveMin();
372  for (DimensionType i = 0; i < LabelObjectType::ImageDimension; ++i)
373  {
374  centroid[i] /= size;
375  regionSize[i] = maxs[i] - mins[i] + 1;
376  double s = regionSize[i] * std::abs(m_LabelImage->GetSignedSpacing()[i]);
377  minSize = std::min(s, minSize);
378  maxSize = std::max(s, maxSize);
379  for (DimensionType j = 0; j < LabelObjectType::ImageDimension; ++j)
380  {
381  centralMoments[i][j] /= size;
382  }
383  }
384  typename TLabelImage::RegionType region(mins, regionSize);
385  typename TLabelImage::PointType physicalCentroid;
386  m_LabelImage->TransformContinuousIndexToPhysicalPoint(centroid, physicalCentroid);
387 
388  // Center the second order moments
389  for (DimensionType i = 0; i < LabelObjectType::ImageDimension; ++i)
390  {
391  for (DimensionType j = 0; j < LabelObjectType::ImageDimension; ++j)
392  {
393  centralMoments[i][j] -= physicalCentroid[i] * physicalCentroid[j];
394  }
395  }
396 
397  // Compute principal moments and axes
398  itk::Vector<double, LabelObjectType::ImageDimension> principalMoments;
399  vnl_symmetric_eigensystem<double> eigen(centralMoments.GetVnlMatrix());
400  vnl_diag_matrix<double> pm = eigen.D;
401  for (unsigned int i = 0; i < LabelObjectType::ImageDimension; ++i)
402  {
403  // principalMoments[i] = 4 * std::sqrt( pm(i, i) );
404  principalMoments[i] = pm(i, i);
405  }
406  itk::Matrix<double, LabelObjectType::ImageDimension, LabelObjectType::ImageDimension> principalAxes = eigen.V.transpose();
407 
408  // Add a final reflection if needed for a proper rotation,
409  // by multiplying the last row by the determinant
410  vnl_real_eigensystem eigenrot(principalAxes.GetVnlMatrix());
411  vnl_diag_matrix<std::complex<double>> eigenval = eigenrot.D;
412  std::complex<double> det(1.0, 0.0);
413 
414  for (DimensionType i = 0; i < LabelObjectType::ImageDimension; ++i)
415  {
416  det *= eigenval(i, i);
417  }
418 
419  for (DimensionType i = 0; i < LabelObjectType::ImageDimension; ++i)
420  {
421  principalAxes[LabelObjectType::ImageDimension - 1][i] *= std::real(det);
422  }
423 
424  double elongation = 0;
425  if (principalMoments[LabelObjectType::ImageDimension - 2] != 0)
426  {
427  elongation = std::sqrt(principalMoments[LabelObjectType::ImageDimension - 1] / principalMoments[LabelObjectType::ImageDimension - 2]);
428  }
429 
430  double physicalSize = size * sizePerPixel;
431  double equivalentRadius = hyperSphereRadiusFromVolume(physicalSize);
432  double equivalentPerimeter = hyperSpherePerimeter(equivalentRadius);
433 
434  // compute equilalent ellipsoid radius
435  itk::Vector<double, LabelObjectType::ImageDimension> ellipsoidSize;
436  double edet = 1.0;
437  for (DimensionType i = 0; i < LabelObjectType::ImageDimension; ++i)
438  {
439  edet *= principalMoments[i];
440  }
441  edet = std::pow(edet, 1.0 / LabelObjectType::ImageDimension);
442  for (DimensionType i = 0; i < LabelObjectType::ImageDimension; ++i)
443  {
444  ellipsoidSize[i] = 2.0 * equivalentRadius * std::sqrt(principalMoments[i] / edet);
445  }
446 
447 
448  if (m_ComputeFlusser)
449  {
450  // Flusser moments (only make sense when ImageDimension == 2)
451  if (LabelObjectType::ImageDimension == 2)
452  {
453  // complex centered moments
454  std::complex<double> c11, c20, c12, c21, c22, c30, c31, c40;
455  c11 = c20 = c12 = c21 = c22 = c30 = c31 = c40 = std::complex<double>(0, 0);
456  // Update the line iterator to the beginning
457  lit.GoToBegin();
458  // for (lit = lineContainer.begin(); lit != lineContainer.end();
459  // lit++)
460  while (!lit.IsAtEnd())
461  {
462  const typename LabelObjectType::IndexType& idx = lit.GetLine().GetIndex();
463  unsigned long length = lit.GetLine().GetLength();
464  //
465  long endIdx0 = idx[0] + length;
466  for (typename LabelObjectType::IndexType iidx = idx; iidx[0] < endIdx0; iidx[0]++)
467  {
468  typename TLabelImage::PointType cPP;
469  m_LabelImage->TransformIndexToPhysicalPoint(iidx, cPP);
470  cPP -= physicalCentroid.GetVectorFromOrigin();
471  std::complex<double> xpiy(cPP[0], cPP[1]); // x + i y
472  std::complex<double> xmiy(cPP[0], -cPP[1]); // x - i y
473 
474  c11 += xpiy * xmiy;
475  c20 += xpiy * xpiy;
476  c12 += xpiy * xmiy * xmiy;
477  c21 += xpiy * xpiy * xmiy;
478  c30 += xpiy * xpiy * xpiy;
479  c22 += xpiy * xpiy * xmiy * xmiy;
480  c31 += xpiy * xpiy * xpiy * xmiy;
481  c40 += xpiy * xpiy * xpiy * xpiy;
482  }
483  ++lit;
484  }
485 
486  // normalize
487  c11 /= physicalSize * physicalSize;
488  c20 /= physicalSize * physicalSize;
489  c12 /= std::pow(physicalSize, 5.0 / 2);
490  c21 /= std::pow(physicalSize, 5.0 / 2);
491  c30 /= std::pow(physicalSize, 5.0 / 2);
492  c22 /= std::pow(physicalSize, 3);
493  c31 /= std::pow(physicalSize, 3);
494  c40 /= std::pow(physicalSize, 3);
495 
496  lo->SetAttribute("SHAPE::Flusser01", c11.real());
497  lo->SetAttribute("SHAPE::Flusser02", (c21 * c12).real());
498  lo->SetAttribute("SHAPE::Flusser03", (c20 * std::pow(c12, 2)).real());
499  lo->SetAttribute("SHAPE::Flusser04", (c20 * std::pow(c12, 2)).imag());
500  lo->SetAttribute("SHAPE::Flusser05", (c30 * std::pow(c12, 3)).real());
501  lo->SetAttribute("SHAPE::Flusser06", (c30 * std::pow(c12, 3)).imag());
502  lo->SetAttribute("SHAPE::Flusser07", c22.real());
503  lo->SetAttribute("SHAPE::Flusser08", (c31 * std::pow(c12, 2)).real());
504  lo->SetAttribute("SHAPE::Flusser09", (c31 * std::pow(c12, 2)).imag());
505  lo->SetAttribute("SHAPE::Flusser10", (c40 * std::pow(c12, 4)).real());
506  lo->SetAttribute("SHAPE::Flusser11", (c40 * std::pow(c12, 4)).imag());
507  }
508  }
509 
510  // Set the attributes
511  if (m_ComputePolygon)
512  {
513  PolygonFunctorType polygonFunctor;
514  SimplifyPolygonFunctorType simplifyFunctor;
515  polygonFunctor.SetStartIndex(m_LabelImage->GetLargestPossibleRegion().GetIndex());
516  polygonFunctor.SetOrigin(m_LabelImage->GetOrigin());
517  polygonFunctor.SetSpacing(m_LabelImage->GetSignedSpacing());
518  typename PolygonType::Pointer polygon = simplifyFunctor(polygonFunctor(lo));
519  lo->SetPolygon(polygon);
520  }
521 
522  // Physical size
523  lo->SetAttribute("SHAPE::PhysicalSize", physicalSize);
524 
525  // Elongation
526  lo->SetAttribute("SHAPE::Elongation", elongation);
527 
528  if (m_ComputeFeretDiameter)
529  {
530  // init the vars
531  unsigned long ssize = 0;
532  typedef typename std::deque<typename LabelObjectType::IndexType> IndexListType;
533  IndexListType idxList;
534 
535  // Line iterator
537  llit.GoToBegin();
538 
539  typedef typename itk::ConstNeighborhoodIterator<LabelImageType> NeighborIteratorType;
540  typename TLabelImage::SizeType neighborHoodRadius;
541  neighborHoodRadius.Fill(1);
542  NeighborIteratorType it(neighborHoodRadius, m_LabelImage, m_LabelImage->GetBufferedRegion());
543  itk::ConstantBoundaryCondition<LabelImageType> lcbc;
544  // use label + 1 to have a label different of the current label on the border
545  lcbc.SetConstant(label + 1);
546  it.OverrideBoundaryCondition(&lcbc);
547  it.GoToBegin();
548 
549  // iterate over all the lines
550  while (!llit.IsAtEnd())
551  {
552  const typename LabelObjectType::IndexType& firstIdx = llit.GetLine().GetIndex();
553  unsigned long length = llit.GetLine().GetLength();
554 
555  long endIdx0 = firstIdx[0] + length;
556  for (typename LabelObjectType::IndexType idx = firstIdx; idx[0] < endIdx0; idx[0]++)
557  {
558 
559  // move the iterator to the new location
560  it += idx - it.GetIndex();
561 
562  // push the pixel in the list if it is on the border of the object
563  for (unsigned i = 0; i < it.Size(); ++i)
564  {
565  if (it.GetPixel(i) != label)
566  {
567  idxList.push_back(idx);
568  ssize++;
569  break;
570  }
571  }
572  }
573  ++llit;
574  }
575 
576  // we can now search the feret diameter
577  double feretDiameter = 0;
578  for (typename IndexListType::const_iterator iIt1 = idxList.begin(); iIt1 != idxList.end(); iIt1++)
579  {
580  typename IndexListType::const_iterator iIt2 = iIt1;
581  for (iIt2++; iIt2 != idxList.end(); iIt2++)
582  {
583  // Compute the length between the 2 indexes
584  double length = 0;
585  for (DimensionType i = 0; i < LabelObjectType::ImageDimension; ++i)
586  {
587  length += std::pow((iIt1->operator[](i) - iIt2->operator[](i)) * m_LabelImage->GetSignedSpacing()[i], 2);
588  }
589  if (feretDiameter < length)
590  {
591  feretDiameter = length;
592  }
593  }
594  }
595  // final computation
596  feretDiameter = std::sqrt(feretDiameter);
597 
598  // finally put the values in the label object
599  lo->SetAttribute("SHAPE::FeretDiameter", feretDiameter);
600  }
601 
602  // be sure that the calculator has the perimeter estimation for that label.
603  // The calculator may not have the label if the object is only on a border.
604  // It will occur for sure when processing a 2D image with a 3D filter.
605  if (m_ComputePerimeter)
606  {
607  double perimeter = this->ComputePerimeter(lo, region);
608  // double perimeter = lo->ComputePerimeter();
609  lo->SetAttribute("SHAPE::Perimeter", perimeter);
610  lo->SetAttribute("SHAPE::Roundness", equivalentPerimeter / perimeter);
611  }
612 
613  // Complete feature set
614 
615  if (!m_ReducedAttributeSet)
616  {
617  lo->SetAttribute("SHAPE::Size", size);
618  std::ostringstream oss;
619  for (unsigned int dim = 0; dim < LabelObjectType::ImageDimension; ++dim)
620  {
621  oss.str("");
622  oss << "SHAPE::RegionIndex" << dim;
623  lo->SetAttribute(oss.str().c_str(), region.GetIndex()[dim]);
624  oss.str("");
625  oss << "SHAPE::RegionSize" << dim;
626  lo->SetAttribute(oss.str().c_str(), region.GetSize()[dim]);
627  oss.str("");
628  oss << "SHAPE::PhysicalCentroid" << dim;
629  lo->SetAttribute(oss.str().c_str(), physicalCentroid[dim]);
630  oss.str("");
631  oss << "SHAPE::EquivalentEllipsoidRadius" << dim;
632  lo->SetAttribute(oss.str().c_str(), ellipsoidSize[dim]);
633  oss.str("");
634  oss << "SHAPE::PrincipalMoments" << dim;
635  lo->SetAttribute(oss.str().c_str(), principalMoments[dim]);
636 
637  for (unsigned int dim2 = 0; dim2 < LabelObjectType::ImageDimension; ++dim2)
638  {
639  oss.str("");
640  oss << "SHAPE::PrincipalAxis" << dim << dim2;
641  lo->SetAttribute(oss.str().c_str(), principalAxes(dim, dim2));
642  }
643  }
644 
645  lo->SetAttribute("SHAPE::RegionElongation", maxSize / minSize);
646  lo->SetAttribute("SHAPE::RegionRatio", size / (double)region.GetNumberOfPixels());
647  lo->SetAttribute("SHAPE::SizeOnBorder", sizeOnBorder);
648  lo->SetAttribute("SHAPE::PhysicalSizeOnBorder", physicalSizeOnBorder);
649  lo->SetAttribute("SHAPE::EquivalentPerimeter", equivalentPerimeter);
650  lo->SetAttribute("SHAPE::EquivalentRadius", equivalentRadius);
651  }
652 }
653 
654 template <class TLabelObject, class TLabelImage>
656 {
657  // store the lines in a N-1D image of vectors
658  typedef std::deque<typename LabelObjectType::LineType> VectorLineType;
659  typedef itk::Image<VectorLineType, ImageDimension - 1> LineImageType;
660  typename LineImageType::Pointer lineImage = LineImageType::New();
661  typename LineImageType::IndexType lIdx;
662  typename LineImageType::SizeType lSize;
663  RegionType boundingBox = region;
664  for (DimensionType i = 0; i < ImageDimension - 1; i++)
665  {
666  lIdx[i] = boundingBox.GetIndex()[i + 1];
667  lSize[i] = boundingBox.GetSize()[i + 1];
668  }
669  typename LineImageType::RegionType lRegion;
670  lRegion.SetIndex(lIdx);
671  lRegion.SetSize(lSize);
672  // enlarge the region a bit to avoid boundary problems
673  typename LineImageType::RegionType elRegion(lRegion);
674  lSize.Fill(1);
675  elRegion.PadByRadius(lSize);
676  // std::cout << boundingBox << " " << lRegion << " " << elRegion << std::endl;
677  // now initialize the image
678  lineImage->SetRegions(elRegion);
679  lineImage->Allocate();
680  lineImage->FillBuffer(VectorLineType());
681 
682  // std::cout << "lineContainer.size(): " << lineContainer.size() << std::endl;
683 
684  // Iterate over all the lines and fill the image of lines
685  typename LabelObjectType::ConstLineIterator lit(labelObject);
686  while (!lit.IsAtEnd())
687  {
688  const typename TLabelObject::IndexType& idx = lit.GetLine().GetIndex();
689  for (DimensionType i = 0; i < ImageDimension - 1; i++)
690  {
691  lIdx[i] = idx[i + 1];
692  }
693  lineImage->GetPixel(lIdx).push_back(lit.GetLine());
694  ++lit;
695  }
696 
697  // a data structure to store the number of intercepts on each direction
698  typedef typename std::map<OffsetType, itk::SizeValueType, typename OffsetType::LexicographicCompare> MapInterceptType;
699  MapInterceptType intercepts;
700  // int nbOfDirections = (int)std::pow( 2.0, (int)ImageDimension ) - 1;
701  // intecepts.resize(nbOfDirections + 1); // code begins at position 1
702 
703  // now iterate over the vectors of lines
704  typedef itk::ConstShapedNeighborhoodIterator<LineImageType> LineImageIteratorType;
705  LineImageIteratorType lIt(lSize, lineImage, lRegion); // the original, non padded region
706  setConnectivity(&lIt, true);
707  for (lIt.GoToBegin(); !lIt.IsAtEnd(); ++lIt)
708  {
709  const VectorLineType& ls = lIt.GetCenterPixel();
710 
711  // there are two intercepts on the 0 axis for each line
712  OffsetType no;
713  no.Fill(0);
714  no[0] = 1;
715  // std::cout << no << "-> " << 2 * ls.size() << std::endl;
716  intercepts[no] += 2 * ls.size();
717 
718  // and look at the neighbors
719  typename LineImageIteratorType::ConstIterator ci;
720  for (ci = lIt.Begin(); ci != lIt.End(); ci++)
721  {
722  // std::cout << "-------------" << std::endl;
723  // the vector of lines in the neighbor
724  const VectorLineType& ns = ci.Get();
725  // prepare the offset to be stored in the intercepts map
726  typename LineImageType::OffsetType lno = ci.GetNeighborhoodOffset();
727  no[0] = 0;
728  for (DimensionType i = 0; i < ImageDimension - 1; i++)
729  {
730  no[i + 1] = vnl_math_abs(lno[i]);
731  }
732  OffsetType dno = no; // offset for the diagonal
733  dno[0] = 1;
734 
735  // now process the two lines to search the pixels on the contour of the object
736  if (ls.empty())
737  {
738  // std::cout << "ls.empty()" << std::endl;
739  // nothing to do
740  }
741  if (ns.empty())
742  {
743  // no line in the neighbors - all the lines in ls are on the contour
744  for (typename VectorLineType::const_iterator li = ls.begin(); li != ls.end(); ++li)
745  {
746  // std::cout << "ns.empty()" << std::endl;
747  const typename LabelObjectType::LineType& l = *li;
748  // add as much intercepts as the line size
749  intercepts[no] += l.GetLength();
750  // and 2 times as much diagonal intercepts as the line size
751  intercepts[dno] += l.GetLength() * 2;
752  }
753  }
754  else
755  {
756  // std::cout << "else" << std::endl;
757  // TODO - fix the code when the line starts at NumericTraits<IndexValueType>::NonpositiveMin()
758  // or end at NumericTraits<IndexValueType>::max()
759  typename VectorLineType::const_iterator li = ls.begin();
760  typename VectorLineType::const_iterator ni = ns.begin();
761 
762  itk::IndexValueType lZero = 0;
763  itk::IndexValueType lMin = 0;
764  itk::IndexValueType lMax = 0;
765 
766  itk::IndexValueType nMin = itk::NumericTraits<itk::IndexValueType>::NonpositiveMin() + 1;
767  itk::IndexValueType nMax = ni->GetIndex()[0] - 1;
768 
769  while (li != ls.end())
770  {
771  // update the current line min and max. Neighbor line data is already up to date.
772  lMin = li->GetIndex()[0];
773  lMax = lMin + li->GetLength() - 1;
774 
775  // add as much intercepts as intersections of the 2 lines
776  intercepts[no] += vnl_math_max(lZero, vnl_math_min(lMax, nMax) - vnl_math_max(lMin, nMin) + 1);
777  // std::cout << "============" << std::endl;
778  // std::cout << " lMin:" << lMin << " lMax:" << lMax << " nMin:" << nMin << " nMax:" << nMax;
779  // std::cout << " count: " << vnl_math_max( 0l, vnl_math_min(lMax, nMax) - vnl_math_max(lMin, nMin) + 1 ) << std::endl;
780  // std::cout << " " << no << ": " << intercepts[no] << std::endl;
781  // std::cout << vnl_math_max( lZero, vnl_math_min(lMax, nMax+1) - vnl_math_max(lMin, nMin+1) + 1 ) << std::endl;
782  // std::cout << vnl_math_max( lZero, vnl_math_min(lMax, nMax-1) - vnl_math_max(lMin, nMin-1) + 1 ) << std::endl;
783  // left diagonal intercepts
784  intercepts[dno] += vnl_math_max(lZero, vnl_math_min(lMax, nMax + 1) - vnl_math_max(lMin, nMin + 1) + 1);
785  // right diagonal intercepts
786  intercepts[dno] += vnl_math_max(lZero, vnl_math_min(lMax, nMax - 1) - vnl_math_max(lMin, nMin - 1) + 1);
787 
788  // go to the next line or the next neighbor depending on where we are
789  if (nMax <= lMax)
790  {
791  // go to next neighbor
792  nMin = ni->GetIndex()[0] + ni->GetLength();
793  ni++;
794 
795  if (ni != ns.end())
796  {
797  nMax = ni->GetIndex()[0] - 1;
798  }
799  else
800  {
801  nMax = itk::NumericTraits<itk::IndexValueType>::max() - 1;
802  }
803  }
804  else
805  {
806  // go to next line
807  li++;
808  }
809  }
810  }
811  }
812  }
813 
814  // compute the perimeter based on the intercept counts
815  double perimeter = PerimeterFromInterceptCount(intercepts, m_LabelImage->GetSignedSpacing());
816  return perimeter;
817 }
818 
819 template <class TLabelObject, class TLabelImage>
820 template <class TMapIntercept, class TSpacing>
822 {
823  // std::cout << "PerimeterFromInterceptCount<>" << std::endl;
824  double perimeter = 0.0;
825  double pixelSize = 1.0;
826  int dim = TSpacing::GetVectorDimension();
827  for (int i = 0; i < dim; i++)
828  {
829  pixelSize *= spacing[i];
830  }
831 
832  for (int i = 0; i < dim; i++)
833  {
834  OffsetType no;
835  no.Fill(0);
836  no[i] = 1;
837  // std::cout << no << ": " << intercepts[no] << std::endl;
838  perimeter += pixelSize / spacing[i] * intercepts[no] / 2.0;
839  }
840 
841  // Crofton's constant
842  perimeter *= itk::GeometryUtilities::HyperSphereVolume(dim, 1.0) / itk::GeometryUtilities::HyperSphereVolume(dim - 1, 1.0);
843  return perimeter;
844 }
845 
846 #if !defined(ITK_DO_NOT_USE_PERIMETER_SPECIALIZATION)
847 template <class TLabelObject, class TLabelImage>
849 {
850  // std::cout << "PerimeterFromInterceptCount2" << std::endl;
851  double dx = spacing[0];
852  double dy = spacing[1];
853 
854  Offset2Type nx = {{1, 0}};
855  Offset2Type ny = {{0, 1}};
856  Offset2Type nxy = {{1, 1}};
857 
858  // std::cout << "nx: " << intercepts[nx] << std::endl;
859  // std::cout << "ny: " << intercepts[ny] << std::endl;
860  // std::cout << "nxy: " << intercepts[nxy] << std::endl;
861 
862  double perimeter = 0.0;
863  perimeter += dy * intercepts[nx] / 2.0;
864  perimeter += dx * intercepts[ny] / 2.0;
865  perimeter += dx * dy / spacing.GetNorm() * intercepts[nxy] / 2.0;
866  perimeter *= itk::Math::pi / 4.0;
867  return perimeter;
868 };
869 
870 template <class TLabelObject, class TLabelImage>
872 {
873  // std::cout << "PerimeterFromInterceptCount3" << std::endl;
874  double dx = spacing[0];
875  double dy = spacing[1];
876  double dz = spacing[2];
877  double dxy = std::sqrt(spacing[0] * spacing[0] + spacing[1] * spacing[1]);
878  double dxz = std::sqrt(spacing[0] * spacing[0] + spacing[2] * spacing[2]);
879  double dyz = std::sqrt(spacing[1] * spacing[1] + spacing[2] * spacing[2]);
880  double dxyz = std::sqrt(spacing[0] * spacing[0] + spacing[1] * spacing[1] + spacing[2] * spacing[2]);
881  double vol = spacing[0] * spacing[1] * spacing[2];
882 
883  // 'magical numbers', corresponding to area of voronoi partition on the
884  // unit sphere, when germs are the 26 directions on the unit cube
885  // Sum of (c1+c2+c3 + c4*2+c5*2+c6*2 + c7*4) equals 1.
886  double c1 = 0.04577789120476 * 2; // Ox
887  double c2 = 0.04577789120476 * 2; // Oy
888  double c3 = 0.04577789120476 * 2; // Oz
889  double c4 = 0.03698062787608 * 2; // Oxy
890  double c5 = 0.03698062787608 * 2; // Oxz
891  double c6 = 0.03698062787608 * 2; // Oyz
892  double c7 = 0.03519563978232 * 2; // Oxyz
893  // TODO - recompute those values if the spacing is non isotrope
894 
895  Offset3Type nx = {{1, 0, 0}};
896  Offset3Type ny = {{0, 1, 0}};
897  Offset3Type nz = {{0, 0, 1}};
898  Offset3Type nxy = {{1, 1, 0}};
899  Offset3Type nxz = {{1, 0, 1}};
900  Offset3Type nyz = {{0, 1, 1}};
901  Offset3Type nxyz = {{1, 1, 1}};
902 
903  // std::cout << "nx: " << intercepts[nx] << std::endl;
904  // std::cout << "ny: " << intercepts[ny] << std::endl;
905  // std::cout << "nz: " << intercepts[nz] << std::endl;
906  // std::cout << "nxy: " << intercepts[nxy] << std::endl;
907  // std::cout << "nxz: " << intercepts[nxz] << std::endl;
908  // std::cout << "nyz: " << intercepts[nyz] << std::endl;
909  // std::cout << "nxyz: " << intercepts[nxyz] << std::endl;
910 
911  double perimeter = 0.0;
912  perimeter += vol / dx * intercepts[nx] / 2.0 * c1;
913  perimeter += vol / dy * intercepts[ny] / 2.0 * c2;
914  perimeter += vol / dz * intercepts[nz] / 2.0 * c3;
915  perimeter += vol / dxy * intercepts[nxy] / 2.0 * c4;
916  perimeter += vol / dxz * intercepts[nxz] / 2.0 * c5;
917  perimeter += vol / dyz * intercepts[nyz] / 2.0 * c6;
918  perimeter += vol / dxyz * intercepts[nxyz] / 2.0 * c7;
919  perimeter *= 4;
920  return perimeter;
921 };
922 #endif
923 
925 template <class TLabelObject, class TLabelImage>
927 {
928  if (n < 1)
929  {
930  return 1;
931  }
932  return n * factorial(n - 1);
933 }
935 
937 template <class TLabelObject, class TLabelImage>
939 {
940  if (n < 2)
941  {
942  return 1;
943  }
944  return n * doubleFactorial(n - 2);
945 }
947 
949 template <class TLabelObject, class TLabelImage>
951 {
952  bool even = n % 2 == 0;
953  if (even)
954  {
955  return factorial(n / 2);
956  }
957  else
958  {
959  return otb::CONST_SQRTPI * doubleFactorial(n) / std::pow(2, (n + 1) / 2.0);
960  }
961 }
963 
965 template <class TLabelObject, class TLabelImage>
967 {
968  return std::pow(otb::CONST_PI, LabelObjectType::ImageDimension / 2.0) * std::pow(radius, LabelObjectType::ImageDimension) /
969  gammaN2p1(LabelObjectType::ImageDimension);
970 }
971 
973 template <class TLabelObject, class TLabelImage>
975 {
976  return LabelObjectType::ImageDimension * hyperSphereVolume(radius) / radius;
977 }
978 
980 template <class TLabelObject, class TLabelImage>
982 {
983  return std::pow(volume * gammaN2p1(LabelObjectType::ImageDimension) / std::pow(otb::CONST_PI, LabelObjectType::ImageDimension / 2.0),
984  1.0 / LabelObjectType::ImageDimension);
985 }
986 
987 } // End namespace Functor
988 
989 template <class TImage, class TLabelImage>
991 {
992  if (this->GetFunctor().GetComputeFeretDiameter() != flag)
993  {
994  this->GetFunctor().SetComputeFeretDiameter(flag);
995  this->Modified();
996  }
997 }
998 
999 template <class TImage, class TLabelImage>
1001 {
1002  return this->GetFunctor().GetComputeFeretDiameter();
1003 }
1004 
1005 template <class TImage, class TLabelImage>
1007 {
1008  if (this->GetFunctor().GetComputePerimeter() != flag)
1009  {
1010  this->GetFunctor().SetComputePerimeter(flag);
1011  this->Modified();
1012  }
1013 }
1014 
1015 template <class TImage, class TLabelImage>
1017 {
1018  return this->GetFunctor().GetComputePerimeter();
1019 }
1020 
1021 template <class TImage, class TLabelImage>
1023 {
1024  if (this->GetFunctor().GetComputePolygon() != flag)
1025  {
1026  this->GetFunctor().SetComputePolygon(flag);
1027  this->Modified();
1028  }
1029 }
1030 
1031 template <class TImage, class TLabelImage>
1033 {
1034  return this->GetFunctor().GetComputePolygon();
1035 }
1036 
1037 template <class TImage, class TLabelImage>
1039 {
1040  if (this->GetFunctor().GetComputeFlusser() != flag)
1041  {
1042  this->GetFunctor().SetComputeFlusser(flag);
1043  this->Modified();
1044  }
1045 }
1046 
1047 template <class TImage, class TLabelImage>
1049 {
1050  return this->GetFunctor().GetComputeFlusser();
1051 }
1052 
1053 
1054 template <class TImage, class TLabelImage>
1056 {
1057  if (this->GetFunctor().GetReducedAttributeSet() != flag)
1058  {
1059  this->GetFunctor().SetReducedAttributeSet(flag);
1060  this->Modified();
1061  }
1062 }
1063 
1064 template <class TImage, class TLabelImage>
1066 {
1067  return this->GetFunctor().GetReducedAttributeSet();
1068 }
1069 
1070 template <class TImage, class TLabelImage>
1072 {
1073  if (this->GetFunctor().GetLabelImage() != img)
1074  {
1075  this->GetFunctor().SetLabelImage(img);
1076  this->Modified();
1077  }
1078 }
1079 
1080 template <class TImage, class TLabelImage>
1082 {
1083  return this->GetFunctor().GetLabelImage();
1084 }
1085 
1086 template <class TImage, class TLabelImage>
1088 {
1089  // if told to run in place and the types support it,
1090  if (this->GetInPlace() && this->CanRunInPlace())
1091  {
1092  // Graft this first input to the output. Later, we'll need to
1093  // remove the input's hold on the bulk data.
1094  //
1095  ImagePointer inputAsOutput = dynamic_cast<TImage*>(const_cast<TImage*>(this->GetInput()));
1096 
1097  if (inputAsOutput)
1098  {
1099 
1100  this->GraftOutput(inputAsOutput);
1101  this->GetOutput()->SetLargestPossibleRegion(this->GetOutput()->GetLargestPossibleRegion());
1102  this->GetOutput()->SetRequestedRegion(this->GetOutput()->GetRequestedRegion());
1103  this->GetOutput()->SetBufferedRegion(this->GetOutput()->GetBufferedRegion());
1104  }
1105 
1106  // If there are more than one outputs, allocate the remaining outputs
1107  for (unsigned int i = 1; i < this->GetNumberOfOutputs(); ++i)
1108  {
1109  ImagePointer outputPtr;
1110 
1111  outputPtr = this->GetOutput(i);
1112  outputPtr->SetBufferedRegion(outputPtr->GetRequestedRegion());
1113  outputPtr->Allocate();
1114  }
1115  }
1116  else
1117  {
1118  //
1119  Superclass::AllocateOutputs();
1120  // copy the content of the input image to the output image (will be done by ImageSource AllocateOutputs Method)
1121  // would never occur : inputasoutput condition is always true, since output and input type is TImage for
1122  // ShapeAttributesLabelMapFilter class
1123  }
1124 }
1125 
1126 template <class TImage, class TLabelImage>
1128 {
1129  itk::ImageToImageFilter<TImage, TImage>::GenerateInputRequestedRegion();
1130 }
1131 
1132 
1133 template <class TImage, class TLabelImage>
1135 {
1136  Superclass::BeforeThreadedGenerateData();
1137  if (!this->GetFunctor().GetLabelImage())
1138  {
1139  // generate an image of the labelized image
1140  typedef itk::LabelMapToLabelImageFilter<TImage, TLabelImage> LCI2IType;
1141  typename LCI2IType::Pointer lci2i = LCI2IType::New();
1142  lci2i->SetInput(this->GetInput());
1143  // respect the number of threads of the filter
1144  lci2i->SetNumberOfThreads(this->GetNumberOfThreads());
1145  lci2i->Update();
1146  this->GetFunctor().SetLabelImage(lci2i->GetOutput());
1147  }
1148 
1149  /* // delegate the computation of the perimeter to a dedicated calculator */
1150  /* if (this->GetFunctor().GetComputePerimeter()) */
1151  /* { */
1152  /* typename PerimeterCalculatorType::Pointer pc = PerimeterCalculatorType::New(); */
1153  /* pc->SetImage(this->GetFunctor().GetLabelImage()); */
1154  /* pc->Compute(); */
1155  /* this->GetFunctor().SetPerimeterCalculator(pc); */
1156  /* } */
1157 }
1158 
1159 template <class TImage, class TLabelImage>
1160 void ShapeAttributesLabelMapFilter<TImage, TLabelImage>::PrintSelf(std::ostream& os, itk::Indent indent) const
1161 {
1162  Superclass::PrintSelf(os, indent);
1163 
1164  os << indent << "ComputeFeretDiameter: " << this->GetFunctor().GetComputeFeretDiameter() << std::endl;
1165  os << indent << "ComputePerimeter: " << this->GetFunctor().GetComputePerimeter() << std::endl;
1166 }
1167 
1168 } // end namespace otb
1169 #endif
otb::ShapeAttributesLabelMapFilter
This class is a fork of the itk::ShapeLabelMapFilter working with AttributesMapLabelObject.
Definition: otbShapeAttributesLabelMapFilter.h:212
otb::ShapeAttributesLabelMapFilter::GetComputePolygon
bool GetComputePolygon() const
Definition: otbShapeAttributesLabelMapFilter.hxx:1032
otb::Functor::LabelObjectToPolygonFunctor::SetOrigin
void SetOrigin(const PointType &origin)
Definition: otbLabelObjectToPolygonFunctor.h:105
otb::CONST_PI
constexpr double CONST_PI
Definition: otbMath.h:49
otb::CONST_SQRTPI
const double CONST_SQRTPI
Definition: otbMath.h:59
otb::SimplifyPathFunctor
This filter performs a simplification of the input path.
Definition: otbSimplifyPathFunctor.h:54
otb::ShapeAttributesLabelMapFilter::GetComputePerimeter
bool GetComputePerimeter() const
Definition: otbShapeAttributesLabelMapFilter.hxx:1016
otb::ShapeAttributesLabelMapFilter::GetComputeFeretDiameter
bool GetComputeFeretDiameter() const
Definition: otbShapeAttributesLabelMapFilter.hxx:1000
otb::Functor::LabelObjectToPolygonFunctor
This class vectorizes a LabelObject to a Polygon.
Definition: otbLabelObjectToPolygonFunctor.h:62
otb::Functor::ShapeAttributesLabelObjectFunctor< TImage::LabelObjectType, Image< typename TImage::PixelType, TImage::ImageDimension > >::DimensionType
unsigned int DimensionType
Definition: otbShapeAttributesLabelMapFilter.h:67
otb::ShapeAttributesLabelMapFilter::GetLabelImage
const TLabelImage * GetLabelImage() const
Definition: otbShapeAttributesLabelMapFilter.hxx:1081
otb::Functor::ShapeAttributesLabelObjectFunctor< TImage::LabelObjectType, Image< typename TImage::PixelType, TImage::ImageDimension > >::OffsetType
itk::Offset< TImage::LabelObjectType ::ImageDimension > OffsetType
Definition: otbShapeAttributesLabelMapFilter.h:72
otb::ShapeAttributesLabelMapFilter::SetComputePerimeter
void SetComputePerimeter(bool flag)
Definition: otbShapeAttributesLabelMapFilter.hxx:1006
otb::Functor::LabelObjectToPolygonFunctor::SetSpacing
void SetSpacing(const SpacingType &spacing)
Definition: otbLabelObjectToPolygonFunctor.h:117
otb
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
Definition: otbJoinContainer.h:32
otb::Functor::ShapeAttributesLabelObjectFunctor< TImage::LabelObjectType, Image< typename TImage::PixelType, TImage::ImageDimension > >::MapIntercept3Type
std::map< Offset3Type, itk::SizeValueType, Offset3Type::LexicographicCompare > MapIntercept3Type
Definition: otbShapeAttributesLabelMapFilter.h:155
otbMacro.h
otb::Functor::ShapeAttributesLabelObjectFunctor< TImage::LabelObjectType, Image< typename TImage::PixelType, TImage::ImageDimension > >::MapIntercept2Type
std::map< Offset2Type, itk::SizeValueType, Offset2Type::LexicographicCompare > MapIntercept2Type
Definition: otbShapeAttributesLabelMapFilter.h:154
otb::operator==
constexpr bool operator==(extents< StaticExtentsL... > const &lhs, extents< StaticExtentsR... > const &rhs)
Definition: otbExtents.h:150
otbShapeAttributesLabelMapFilter.h
otb::ShapeAttributesLabelMapFilter::GetReducedAttributeSet
bool GetReducedAttributeSet() const
Definition: otbShapeAttributesLabelMapFilter.hxx:1065
otb::ShapeAttributesLabelMapFilter::GetComputeFlusser
bool GetComputeFlusser() const
Definition: otbShapeAttributesLabelMapFilter.hxx:1048
otb::ShapeAttributesLabelMapFilter::SetComputeFlusser
void SetComputeFlusser(bool flag)
Definition: otbShapeAttributesLabelMapFilter.hxx:1038
otb::Functor::ShapeAttributesLabelObjectFunctor< TImage::LabelObjectType, Image< typename TImage::PixelType, TImage::ImageDimension > >::Spacing2Type
itk::Vector< double, 2 > Spacing2Type
Definition: otbShapeAttributesLabelMapFilter.h:152
otb::Functor::ShapeAttributesLabelObjectFunctor< TImage::LabelObjectType, Image< typename TImage::PixelType, TImage::ImageDimension > >::ConstLineIteratorType
LabelObjectType::ConstLineIterator ConstLineIteratorType
Definition: otbShapeAttributesLabelMapFilter.h:56
otb::ShapeAttributesLabelMapFilter::SetComputePolygon
void SetComputePolygon(bool flag)
Definition: otbShapeAttributesLabelMapFilter.hxx:1022
otb::Functor::ShapeAttributesLabelObjectFunctor< TImage::LabelObjectType, Image< typename TImage::PixelType, TImage::ImageDimension > >::LabelObjectType
TImage::LabelObjectType LabelObjectType
Definition: otbShapeAttributesLabelMapFilter.h:53
otb::Functor::LabelObjectToPolygonFunctor::SetStartIndex
void SetStartIndex(const RegionIndexType &index)
Definition: otbLabelObjectToPolygonFunctor.h:93
otb::ShapeAttributesLabelMapFilter::SetComputeFeretDiameter
void SetComputeFeretDiameter(bool flag)
Definition: otbShapeAttributesLabelMapFilter.hxx:990
otb::Functor::ShapeAttributesLabelObjectFunctor< TImage::LabelObjectType, Image< typename TImage::PixelType, TImage::ImageDimension > >::Spacing3Type
itk::Vector< double, 3 > Spacing3Type
Definition: otbShapeAttributesLabelMapFilter.h:153
otb::Functor::ShapeAttributesLabelObjectFunctor< TImage::LabelObjectType, Image< typename TImage::PixelType, TImage::ImageDimension > >::Offset3Type
itk::Offset< 3 > Offset3Type
Definition: otbShapeAttributesLabelMapFilter.h:151
otb::operator!=
constexpr bool operator!=(extents< StaticExtentsL... > const &lhs, extents< StaticExtentsR... > const &rhs)
Definition: otbExtents.h:164
otb::Functor::ShapeAttributesLabelObjectFunctor
Functor to compute shape attributes of one LabelObject.
Definition: otbShapeAttributesLabelMapFilter.h:46
otb::Functor::ShapeAttributesLabelObjectFunctor< TImage::LabelObjectType, Image< typename TImage::PixelType, TImage::ImageDimension > >::RegionType
itk::ImageRegion< TImage::LabelObjectType ::ImageDimension > RegionType
Definition: otbShapeAttributesLabelMapFilter.h:71
otb::Functor::ShapeAttributesLabelObjectFunctor< TImage::LabelObjectType, Image< typename TImage::PixelType, TImage::ImageDimension > >::Offset2Type
itk::Offset< 2 > Offset2Type
Definition: otbShapeAttributesLabelMapFilter.h:150
otb::Functor::ShapeAttributesLabelObjectFunctor::ShapeAttributesLabelObjectFunctor
ShapeAttributesLabelObjectFunctor()
Definition: otbShapeAttributesLabelMapFilter.hxx:46
otb::ShapeAttributesLabelMapFilter::SetReducedAttributeSet
void SetReducedAttributeSet(bool flag)
Definition: otbShapeAttributesLabelMapFilter.hxx:1055
otb::ShapeAttributesLabelMapFilter::SetLabelImage
void SetLabelImage(const TLabelImage *)
Definition: otbShapeAttributesLabelMapFilter.hxx:1071
otb::ShapeAttributesLabelMapFilter::ImagePointer
ImageType::Pointer ImagePointer
Definition: otbShapeAttributesLabelMapFilter.h:229