Orfeo Toolbox  3.16
otbMeanShiftSmoothingImageFilter.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: ORFEO Toolbox
4  Language: C++
5  Date: $Date$
6  Version: $Revision$
7 
8 
9  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
10  See OTBCopyright.txt for details.
11 
12 
13  This software is distributed WITHOUT ANY WARRANTY; without even
14  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  PURPOSE. See the above copyright notices for more information.
16 
17 =========================================================================*/
18 
19 #ifndef __otbMeanShiftSmoothingImageFilter_txx
20 #define __otbMeanShiftSmoothingImageFilter_txx
21 
24 #include "itkImageRegionIterator.h"
26 #include "otbMacro.h"
27 
28 #include "itkProgressReporter.h"
29 
30 
31 namespace otb
32 {
33 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
35  m_RangeBandwidth(16.), m_SpatialBandwidth(3)
36  // , m_SpatialRadius(???)
37  , m_Threshold(1e-3), m_MaxIterationNumber(10)
38  // , m_Kernel(...)
39  // , m_NumberOfComponentsPerPixel(...)
40  // , m_JointImage(0)
41  // , m_ModeTable(0)
42  , m_ModeSearch(true)
43 #if 0
44  , m_BucketOptimization(false)
45 #endif
46 {
47  this->SetNumberOfOutputs(4);
48  this->SetNthOutput(0, OutputImageType::New());
50  this->SetNthOutput(2, OutputIterationImageType::New());
52 }
53 
54 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
56 {
57 }
58 
59 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
62 {
63  return static_cast<const OutputSpatialImageType *> (this->itk::ProcessObject::GetOutput(1));
64 }
65 
66 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
69 {
70  return static_cast<OutputSpatialImageType *> (this->itk::ProcessObject::GetOutput(1));
71 }
72 
73 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
76 {
77  return static_cast<const OutputImageType *> (this->itk::ProcessObject::GetOutput(0));
78 }
79 
80 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
83 {
84  return static_cast<OutputImageType *> (this->itk::ProcessObject::GetOutput(0));
85 }
86 
87 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
90 {
91  return static_cast<OutputIterationImageType *> (this->itk::ProcessObject::GetOutput(2));
92 }
93 
94 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
97 {
98  return static_cast<OutputIterationImageType *> (this->itk::ProcessObject::GetOutput(2));
99 }
100 
101 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
104 {
105  return static_cast<OutputLabelImageType *> (this->itk::ProcessObject::GetOutput(3));
106 }
107 
108 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
111 {
112  return static_cast<OutputLabelImageType *> (this->itk::ProcessObject::GetOutput(3));
113 }
114 
115 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
117 {
118  typename OutputSpatialImageType::Pointer spatialOutputPtr = this->GetSpatialOutput();
119  typename OutputImageType::Pointer rangeOutputPtr = this->GetRangeOutput();
120  typename OutputIterationImageType::Pointer iterationOutputPtr = this->GetIterationOutput();
121  typename OutputLabelImageType::Pointer labelOutputPtr = this->GetLabelOutput();
122 
123  spatialOutputPtr->SetBufferedRegion(spatialOutputPtr->GetRequestedRegion());
124  spatialOutputPtr->Allocate();
125 
126  rangeOutputPtr->SetBufferedRegion(rangeOutputPtr->GetRequestedRegion());
127  rangeOutputPtr->Allocate();
128 
129  iterationOutputPtr->SetBufferedRegion(iterationOutputPtr->GetRequestedRegion());
130  iterationOutputPtr->Allocate();
131 
132  labelOutputPtr->SetBufferedRegion(labelOutputPtr->GetRequestedRegion());
133  labelOutputPtr->Allocate();
134 }
135 
136 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
138 {
139  Superclass::GenerateOutputInformation();
140 
141  m_NumberOfComponentsPerPixel = this->GetInput()->GetNumberOfComponentsPerPixel();
142 
143  if (this->GetSpatialOutput())
144  {
145  this->GetSpatialOutput()->SetNumberOfComponentsPerPixel(ImageDimension); // image lattice
146  }
147  if (this->GetRangeOutput())
148  {
149  this->GetRangeOutput()->SetNumberOfComponentsPerPixel(m_NumberOfComponentsPerPixel);
150  }
151 }
152 
153 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
155 {
156  // Call superclass implementation
157  Superclass::GenerateInputRequestedRegion();
158 
159  // Retrieve input pointers
160  InputImagePointerType inPtr = const_cast<TInputImage *> (this->GetInput());
161  OutputImagePointerType outRangePtr = this->GetRangeOutput();
162 
163  // Check pointers before using them
164  if (!inPtr || !outRangePtr)
165  {
166  return;
167  }
168 
169  // Retrieve requested region (TODO: check if we need to handle
170  // region for outHDispPtr)
171  RegionType outputRequestedRegion = outRangePtr->GetRequestedRegion();
172 
173  // Pad by the appropriate radius
174  RegionType inputRequestedRegion = outputRequestedRegion;
175 
176  // Initializes the spatial radius from kernel bandwidth
177  m_SpatialRadius.Fill(m_Kernel.GetRadius(m_SpatialBandwidth));
178 
179  inputRequestedRegion.PadByRadius(m_SpatialRadius);
180 
181  // Crop the input requested region at the input's largest possible region
182  if (inputRequestedRegion.Crop(inPtr->GetLargestPossibleRegion()))
183  {
184  inPtr->SetRequestedRegion(inputRequestedRegion);
185  return;
186  }
187  else
188  {
189  // Couldn't crop the region (requested region is outside the largest
190  // possible region). Throw an exception.
191 
192  // store what we tried to request (prior to trying to crop)
193  inPtr->SetRequestedRegion(inputRequestedRegion);
194 
195  // build an exception
196  itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
197  e.SetLocation(ITK_LOCATION);
198  e.SetDescription("Requested region is (at least partially) outside the largest possible region.");
199  e.SetDataObject(inPtr);
200  throw e;
201  }
202 
203 }
204 
205 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
207 {
208  // typedef itk::ImageRegionConstIteratorWithIndex<InputImageType> InputIteratorWithIndexType;
209  // typedef itk::ImageRegionIterator<RealVectorImageType> JointImageIteratorType;
210 
211  OutputSpatialImagePointerType outSpatialPtr = this->GetSpatialOutput();
212  OutputImagePointerType outRangePtr = this->GetRangeOutput();
213  typename InputImageType::ConstPointer inputPtr = this->GetInput();
214  typename OutputIterationImageType::Pointer iterationOutput = this->GetIterationOutput();
215  typename OutputSpatialImageType::Pointer spatialOutput = this->GetSpatialOutput();
216 
217  //InputIndexType index;
218 
219 
220  m_SpatialRadius.Fill(m_Kernel.GetRadius(m_SpatialBandwidth));
221 
222  m_NumberOfComponentsPerPixel = this->GetInput()->GetNumberOfComponentsPerPixel();
223 
224  // Allocate output images
225  this->AllocateOutputs();
226 
227  // Initialize output images to zero
228  iterationOutput->FillBuffer(0);
229  OutputSpatialPixelType zero(spatialOutput->GetNumberOfComponentsPerPixel());
230  zero.Fill(0);
231  spatialOutput->FillBuffer(zero);
232 
233  // m_JointImage is the input data expressed in the joint spatial-range
234  // domain, i.e. spatial coordinates are concatenated to the range values.
235  // Moreover, pixel components in this image are normalized by their respective
236  // (spatial or range) bandwith.
239  JointImageFunctorType;
240 
241  typename JointImageFunctorType::Pointer jointImageFunctor = JointImageFunctorType::New();
242 
243  jointImageFunctor->SetInput(inputPtr);
244  jointImageFunctor->GetFunctor().Initialize(ImageDimension, m_NumberOfComponentsPerPixel, m_SpatialBandwidth,
245  m_RangeBandwidth);
246  jointImageFunctor->Update();
247  m_JointImage = jointImageFunctor->GetOutput();
248 
249 #if 0
250  if (m_BucketOptimization)
251  {
252  // Create bucket image
253  // Note: because values in the input m_JointImage are normalized, the
254  // rangeRadius argument is just 1
255  m_BucketImage = BucketImageType(static_cast<typename RealVectorImageType::ConstPointer> (m_JointImage),
256  m_JointImage->GetRequestedRegion(), m_Kernel.GetRadius(m_SpatialBandwidth), 1,
257  ImageDimension);
258  }
259 #endif
260  /*
261  // Allocate the joint domain image
262  m_JointImage = RealVectorImageType::New();
263  m_JointImage->SetNumberOfComponentsPerPixel(ImageDimension + m_NumberOfComponentsPerPixel);
264  m_JointImage->SetRegions(inputPtr->GetRequestedRegion());
265  m_JointImage->Allocate();
266 
267  InputIteratorWithIndexType inputIt(inputPtr, inputPtr->GetRequestedRegion());
268  JointImageIteratorType jointIt(m_JointImage, inputPtr->GetRequestedRegion());
269 
270  // Initialize the joint image with scaled values
271  inputIt.GoToBegin();
272  jointIt.GoToBegin();
273 
274  while (!inputIt.IsAtEnd())
275  {
276  typename InputImageType::PixelType const& inputPixel = inputIt.Get();
277  index = inputIt.GetIndex();
278 
279  RealVector & jointPixel = jointIt.Get();
280  for(unsigned int comp = 0; comp < ImageDimension; comp++)
281  {
282  jointPixel[comp] = index[comp] / m_SpatialBandwidth;
283  }
284  for(unsigned int comp = 0; comp < m_NumberOfComponentsPerPixel; comp++)
285  {
286  jointPixel[ImageDimension + comp] = inputPixel[comp] / m_RangeBandwidth;
287  }
288  // jointIt.Set(jointPixel);
289 
290  ++inputIt;
291  ++jointIt;
292  }
293  */
294 
295  //TODO don't create mode table iterator when ModeSearch is set to false
296  m_ModeTable = ModeTableImageType::New();
297  m_ModeTable->SetRegions(inputPtr->GetRequestedRegion());
298  m_ModeTable->Allocate();
299  m_ModeTable->FillBuffer(0);
300 
301  if (m_ModeSearch)
302  {
303  // Image to store the status at each pixel:
304  // 0 : no mode has been found yet
305  // 1 : a mode has been assigned to this pixel
306  // 2 : a mode will be assigned to this pixel
307 
308 
309  // Initialize counters for mode (also used for mode labeling)
310  // Most significant bits of label counters are used to identify the thread
311  // Id.
312  unsigned int numThreads;
313 
314  numThreads = this->GetNumberOfThreads();
315  m_ThreadIdNumberOfBits = -1;
316  unsigned int n = numThreads;
317  while (n != 0)
318  {
319  n >>= 1;
320  m_ThreadIdNumberOfBits++;
321  }
322  if (m_ThreadIdNumberOfBits == 0) m_ThreadIdNumberOfBits = 1; // minimum 1 bit
323  m_NumLabels.SetSize(numThreads);
324  for (unsigned int i = 0; i < numThreads; i++)
325  {
326  m_NumLabels[i] = static_cast<LabelType> (i) << (sizeof(LabelType) * 8 - m_ThreadIdNumberOfBits);
327  }
328 
329  }
330 
331 }
332 
333 // Calculates the mean shift vector at the position given by jointPixel
334 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
336  const typename RealVectorImageType::Pointer jointImage,
337  const RealVector& jointPixel,
338  const OutputRegionType& outputRegion,
339  RealVector& meanShiftVector)
340 {
341  const unsigned int jointDimension = ImageDimension + m_NumberOfComponentsPerPixel;
342 
343  InputIndexType inputIndex;
344  InputIndexType regionIndex;
345  InputSizeType regionSize;
346 
347  assert(meanShiftVector.GetSize() == jointDimension);
348  meanShiftVector.Fill(0);
349 
350  // Calculates current pixel neighborhood region, restricted to the output image region
351  for (unsigned int comp = 0; comp < ImageDimension; ++comp)
352  {
353  inputIndex[comp] = jointPixel[comp] * m_SpatialBandwidth;
354 
355  regionIndex[comp] = vcl_max(static_cast<long int> (outputRegion.GetIndex().GetElement(comp)),
356  static_cast<long int> (inputIndex[comp] - m_SpatialRadius[comp]));
357  const long int indexRight = vcl_min(
358  static_cast<long int> (outputRegion.GetIndex().GetElement(comp)
359  + outputRegion.GetSize().GetElement(comp) - 1),
360  static_cast<long int> (inputIndex[comp] + m_SpatialRadius[comp]));
361 
362  regionSize[comp] = vcl_max(0l, indexRight - static_cast<long int> (regionIndex[comp]) + 1);
363  }
364 
365  RegionType neighborhoodRegion;
366  neighborhoodRegion.SetIndex(regionIndex);
367  neighborhoodRegion.SetSize(regionSize);
368 
369  RealType weightSum = 0;
370  RealVector jointNeighbor(ImageDimension + m_NumberOfComponentsPerPixel);
371 
372  // An iterator on the neighborhood of the current pixel (in joint
373  // spatial-range domain)
375  //itk::ImageRegionConstIterator<RealVectorImageType> it(jointImage, neighborhoodRegion);
376 
377  it.GoToBegin();
378  while (!it.IsAtEnd())
379  {
380  jointNeighbor.SetData(const_cast<RealType*> (it.GetPixelPointer()));
381 
382  // Compute the squared norm of the difference
383  // This is the L2 norm, TODO: replace by the templated norm
384  RealType norm2 = 0;
385  for (unsigned int comp = 0; comp < jointDimension; comp++)
386  {
387  const RealType d = jointNeighbor[comp] - jointPixel[comp];
388  norm2 += d * d;
389  }
390 
391  // Compute pixel weight from kernel
392  const RealType weight = m_Kernel(norm2);
393  /*
394  // The following code is an alternative way to compute norm2 and weight
395  // It separates the norms of spatial and range elements
396  RealType spatialNorm2;
397  RealType rangeNorm2;
398  spatialNorm2 = 0;
399  for (unsigned int comp = 0; comp < ImageDimension; comp++)
400  {
401  RealType d;
402  d = jointNeighbor[comp] - jointPixel[comp];
403  spatialNorm2 += d*d;
404  }
405 
406  if(spatialNorm2 >= 1.0)
407  {
408  weight = 0;
409  }
410  else
411  {
412  rangeNorm2 = 0;
413  for (unsigned int comp = 0; comp < m_NumberOfComponentsPerPixel; comp++)
414  {
415  RealType d;
416  d = jointNeighbor[ImageDimension + comp] - jointPixel[ImageDimension + comp];
417  rangeNorm2 += d*d;
418  }
419 
420  weight = (rangeNorm2 <= 1.0)? 1.0 : 0.0;
421  }
422  */
423 
424  // Update sum of weights
425  weightSum += weight;
426 
427  // Update mean shift vector
428  for (unsigned int comp = 0; comp < jointDimension; comp++)
429  {
430  meanShiftVector[comp] += weight * jointNeighbor[comp];
431  }
432 
433  ++it;
434  }
435 
436  if (weightSum > 0)
437  {
438  for (unsigned int comp = 0; comp < jointDimension; comp++)
439  {
440  meanShiftVector[comp] = meanShiftVector[comp] / weightSum - jointPixel[comp];
441  }
442  }
443 }
444 
445 #if 0
446 // Calculates the mean shift vector at the position given by jointPixel
447 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
449  const RealVector& jointPixel,
450  RealVector& meanShiftVector)
451 {
452  const unsigned int jointDimension = ImageDimension + m_NumberOfComponentsPerPixel;
453 
454  RealType weightSum = 0;
455 
456  for (unsigned int comp = 0; comp < jointDimension; comp++)
457  {
458  meanShiftVector[comp] = 0;
459  }
460 
461  RealVector jointNeighbor(ImageDimension + m_NumberOfComponentsPerPixel);
462 
463  InputIndexType index;
464  for (unsigned int dim = 0; dim < ImageDimension; ++dim)
465  {
466  index[dim] = jointPixel[dim] * m_SpatialBandwidth + 0.5;
467  }
468 
469  const std::vector<unsigned int>
470  neighborBuckets = m_BucketImage.GetNeighborhoodBucketListIndices(
471  m_BucketImage.BucketIndexToBucketListIndex(
472  m_BucketImage.GetBucketIndex(
473  jointPixel,
474  index)));
475 
476  unsigned int numNeighbors = m_BucketImage.GetNumberOfNeighborBuckets();
477  for (unsigned int neighborIndex = 0; neighborIndex < numNeighbors; ++neighborIndex)
478  {
479  const typename BucketImageType::BucketType & bucket = m_BucketImage.GetBucket(neighborBuckets[neighborIndex]);
480  if (bucket.empty()) continue;
481  typename BucketImageType::BucketType::const_iterator it = bucket.begin();
482  while (it != bucket.end())
483  {
484  jointNeighbor.SetData(const_cast<RealType*> (*it));
485 
486  // Compute the squared norm of the difference
487  // This is the L2 norm, TODO: replace by the templated norm
488  RealType norm2 = 0;
489  for (unsigned int comp = 0; comp < jointDimension; comp++)
490  {
491  const RealType d = jointNeighbor[comp] - jointPixel[comp];
492  norm2 += d * d;
493  }
494 
495  // Compute pixel weight from kernel
496  const RealType weight = m_Kernel(norm2);
497 
498  // Update sum of weights
499  weightSum += weight;
500 
501  // Update mean shift vector
502  for (unsigned int comp = 0; comp < jointDimension; comp++)
503  {
504  meanShiftVector[comp] += weight * jointNeighbor[comp];
505  }
506 
507  ++it;
508  }
509  }
510 
511  if (weightSum > 0)
512  {
513  for (unsigned int comp = 0; comp < jointDimension; comp++)
514  {
515  meanShiftVector[comp] = meanShiftVector[comp] / weightSum - jointPixel[comp];
516  }
517  }
518 }
519 #endif
520 
521 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
523  const OutputRegionType& outputRegionForThread,
524  int threadId)
525 {
526  // at the first iteration
527 
528 
529  // Retrieve output images pointers
530  typename OutputSpatialImageType::Pointer spatialOutput = this->GetSpatialOutput();
531  typename OutputImageType::Pointer rangeOutput = this->GetRangeOutput();
532  typename OutputIterationImageType::Pointer iterationOutput = this->GetIterationOutput();
533  typename OutputLabelImageType::Pointer labelOutput = this->GetLabelOutput();
534 
535  // Get input image pointer
536  typename InputImageType::ConstPointer input = this->GetInput();
537 
538  // defines input and output iterators
539  typedef itk::ImageRegionIterator<OutputImageType> OutputIteratorType;
540  typedef itk::ImageRegionIterator<OutputSpatialImageType> OutputSpatialIteratorType;
541  typedef itk::ImageRegionIterator<OutputIterationImageType> OutputIterationIteratorType;
542  typedef itk::ImageRegionIterator<OutputLabelImageType> OutputLabelIteratorType;
543 
544  const unsigned int jointDimension = ImageDimension + m_NumberOfComponentsPerPixel;
545 
546  typename OutputImageType::PixelType rangePixel(m_NumberOfComponentsPerPixel);
547  typename OutputSpatialImageType::PixelType spatialPixel(ImageDimension);
548 
549  RealVector jointPixel;
550 
551  RealVector bandwidth(jointDimension);
552  for (unsigned int comp = 0; comp < ImageDimension; comp++)
553  bandwidth[comp] = m_SpatialBandwidth;
554  for (unsigned int comp = ImageDimension; comp < jointDimension; comp++)
555  bandwidth[comp] = m_RangeBandwidth;
556 
557  itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels());
558 
559  RegionType const& requestedRegion = input->GetRequestedRegion();
560 
562  JointImageIteratorType jointIt(m_JointImage, outputRegionForThread);
563 
564  OutputIteratorType rangeIt(rangeOutput, outputRegionForThread);
565  OutputSpatialIteratorType spatialIt(spatialOutput, outputRegionForThread);
566  OutputIterationIteratorType iterationIt(iterationOutput, outputRegionForThread);
567  OutputLabelIteratorType labelIt(labelOutput, outputRegionForThread);
568 
569  typedef itk::ImageRegionIterator<ModeTableImageType> ModeTableImageIteratorType;
570  ModeTableImageIteratorType modeTableIt(m_ModeTable, outputRegionForThread);
571 
572  jointIt.GoToBegin();
573  rangeIt.GoToBegin();
574  spatialIt.GoToBegin();
575  iterationIt.GoToBegin();
576  modeTableIt.GoToBegin();
577  labelIt.GoToBegin();
578 
579  unsigned int iteration = 0;
580 
581  // Mean shift vector, updating the joint pixel at each iteration
582  RealVector meanShiftVector(jointDimension);
583 
584  // Variables used by mode search optimization
585  // List of indices where the current pixel passes through
586  std::vector<InputIndexType> pointList;
587  if (m_ModeSearch) pointList.resize(m_MaxIterationNumber);
588  // Number of times an already processed candidate pixel is encountered, resulting in no
589  // further computation (Used for statistics only)
590  unsigned int numBreaks = 0;
591  // index of the current pixel updated during the mean shift loop
592  InputIndexType modeCandidate;
593 
594  for (; !jointIt.IsAtEnd(); ++jointIt, ++rangeIt, ++spatialIt, ++iterationIt, ++modeTableIt, ++labelIt, progress.CompletedPixel())
595  {
596 
597  // if pixel has been already processed (by mode search optimization), skip
598  typename ModeTableImageType::InternalPixelType const& currentPixelMode = modeTableIt.Get();
599  if (m_ModeSearch && currentPixelMode == 1)
600  {
601  numBreaks++;
602  continue;
603  }
604 
605  bool hasConverged = false;
606 
607  // get input pixel in the joint spatial-range domain (with components
608  // normalized by bandwith)
609  jointPixel = jointIt.Get(); // Pixel in the joint spatial-range domain
610 
611  // index of the currently processed output pixel
612  InputIndexType const& currentIndex = jointIt.GetIndex();
613 
614  // Number of points currently in the pointList
615  unsigned int pointCount = 0; // Note: used only in mode search optimization
616  iteration = 0;
617  while ((iteration < m_MaxIterationNumber) && (!hasConverged))
618  {
619 
620  if (m_ModeSearch)
621  {
622  // Find index of the pixel closest to the current jointPixel (not normalized by bandwidth)
623  for (unsigned int comp = 0; comp < ImageDimension; comp++)
624  {
625  modeCandidate[comp] = jointPixel[comp] * m_SpatialBandwidth + 0.5;
626  }
627  // Check status of candidate mode
628 
629  // If pixel candidate has status 0 (no mode assigned) or 1 (mode assigned)
630  // but not 2 (pixel in current search path), and pixel has actually moved
631  // from its initial position, and pixel candidate is inside the output
632  // region, then perform optimization tasks
633  if (modeCandidate != currentIndex && m_ModeTable->GetPixel(modeCandidate) != 2
634  && outputRegionForThread.IsInside(modeCandidate))
635  {
636  // Obtain the data point to see if it close to jointPixel
637  RealType diff = 0;
638  RealVector const& candidatePixel = m_JointImage->GetPixel(modeCandidate);
639  for (unsigned int comp = ImageDimension; comp < jointDimension; comp++)
640  {
641  const RealType d = candidatePixel[comp] - jointPixel[comp];
642  diff += d * d;
643  }
644 
645  if (diff < 0.5) // Spectral value is close enough
646  {
647  // If no mode has been associated to the candidate pixel then
648  // associate it to the upcoming mode
649  if (m_ModeTable->GetPixel(modeCandidate) == 0)
650  {
651  // Add the candidate to the list of pixels that will be assigned the
652  // finally calculated mode value
653  pointList[pointCount++] = modeCandidate;
654  m_ModeTable->SetPixel(modeCandidate, 2);
655  }
656  else // == 1
657  {
658  // The candidate pixel has already been assigned to a mode
659  // Assign the same value
660  rangePixel = rangeOutput->GetPixel(modeCandidate);
661  for (unsigned int comp = 0; comp < m_NumberOfComponentsPerPixel; comp++)
662  {
663  jointPixel[ImageDimension + comp] = rangePixel[comp] / m_RangeBandwidth;
664  }
665  // Update the mode table because pixel will be assigned just now
666  modeTableIt.Set(2); // m_ModeTable->SetPixel(currentIndex, 2);
667  // bypass further calculation
668  numBreaks++;
669  break;
670  }
671  }
672 
673  }
674  } // end if (m_ModeSearch)
675 
676  //Calculate meanShiftVector
677 #if 0
678  if (m_BucketOptimization)
679  {
680  this->CalculateMeanShiftVectorBucket(jointPixel, meanShiftVector);
681  }
682  else
683  {
684 #endif
685  this->CalculateMeanShiftVector(m_JointImage, jointPixel, requestedRegion, meanShiftVector);
686 
687 #if 0
688  }
689 #endif
690 
691  // Compute mean shift vector squared norm (not normalized by bandwidth)
692  // and add mean shift vector to current joint pixel
693  double meanShiftVectorSqNorm = 0;
694  for (unsigned int comp = 0; comp < jointDimension; comp++)
695  {
696  const double v = meanShiftVector[comp] * bandwidth[comp];
697  meanShiftVectorSqNorm += v * v;
698  jointPixel[comp] += meanShiftVector[comp];
699  }
700 
701  //TODO replace SSD Test with templated metric
702  hasConverged = meanShiftVectorSqNorm < m_Threshold;
703  iteration++;
704  }
705 
706  for (unsigned int comp = 0; comp < m_NumberOfComponentsPerPixel; comp++)
707  {
708  rangePixel[comp] = jointPixel[ImageDimension + comp] * m_RangeBandwidth;
709  }
710 
711  for (unsigned int comp = 0; comp < ImageDimension; comp++)
712  {
713  spatialPixel[comp] = jointPixel[comp] * m_SpatialBandwidth - currentIndex[comp];
714  }
715 
716  rangeIt.Set(rangePixel);
717  spatialIt.Set(spatialPixel);
718 
719  const typename OutputIterationImageType::PixelType iterationPixel = iteration;
720  iterationIt.Set(iterationPixel);
721 
722  if (m_ModeSearch)
723  {
724  // Update the mode table now that the current pixel has been assigned
725  modeTableIt.Set(1); // m_ModeTable->SetPixel(currentIndex, 1);
726 
727  // If the loop exited with hasConverged or too many iterations, then we have a new mode
728  LabelType label;
729  if (hasConverged || iteration == m_MaxIterationNumber)
730  {
731  m_NumLabels[threadId]++;
732  label = m_NumLabels[threadId];
733  }
734  else // the loop exited through a break. Use the already assigned mode label
735  {
736  label = labelOutput->GetPixel(modeCandidate);
737  }
738  labelIt.Set(label);
739 
740  // Also assign all points in the list to the same mode
741  for (unsigned int i = 0; i < pointCount; i++)
742  {
743  rangeOutput->SetPixel(pointList[i], rangePixel);
744  m_ModeTable->SetPixel(pointList[i], 1);
745  labelOutput->SetPixel(pointList[i], label);
746  }
747  }
748  else // if ModeSearch is not set LabelOutput can't be generated
749  {
750  LabelType labelZero = 0;
751  labelIt.Set(labelZero);
752  }
753 
754  }
755  // std::cout << "numBreaks: " << numBreaks << " Break ratio: " << numBreaks / (RealType)outputRegionForThread.GetNumberOfPixels() << std::endl;
756 }
757 
758 /* after threaded convergence test */
759 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
761 {
762  typename OutputLabelImageType::Pointer labelOutput = this->GetLabelOutput();
763  typedef itk::ImageRegionIterator<OutputLabelImageType> OutputLabelIteratorType;
764  OutputLabelIteratorType labelIt(labelOutput, labelOutput->GetRequestedRegion());
765 
766  // Reassign mode labels
767  // Note: Labels are only computed when mode search optimization is enabled
768  if (m_ModeSearch)
769  {
770  // New labels will be consecutive. The following vector contains the new
771  // start label for each thread.
773  newLabelOffset.SetSize(this->GetNumberOfThreads());
774  newLabelOffset[0] = 0;
775  for (int i = 1; i < this->GetNumberOfThreads(); i++)
776  {
777  // Retrieve the number of labels in the thread by removing the threadId
778  // from the most significant bits
779  LabelType localNumLabel = m_NumLabels[i - 1] & ((static_cast<LabelType> (1) << (sizeof(LabelType) * 8
780  - m_ThreadIdNumberOfBits)) - static_cast<LabelType> (1));
781  newLabelOffset[i] = localNumLabel + newLabelOffset[i - 1];
782  }
783 
784  labelIt.GoToBegin();
785 
786  while (!labelIt.IsAtEnd())
787  {
788  LabelType const label = labelIt.Get();
789 
790  // Get threadId from most significant bits
791  const unsigned int threadId = label >> (sizeof(LabelType) * 8 - m_ThreadIdNumberOfBits);
792 
793  // Relabeling
794  // First get the label number by removing the threadId bits
795  // Then add the label offset specific to the threadId
796  LabelType newLabel = label & ((static_cast<LabelType> (1) << (sizeof(LabelType) * 8 - m_ThreadIdNumberOfBits))
797  - static_cast<LabelType> (1));
798  newLabel += newLabelOffset[threadId];
799 
800  labelIt.Set(newLabel);
801  ++labelIt;
802  }
803  }
804 
805 }
806 
807 template<class TInputImage, class TOutputImage, class TKernel, class TOutputIterationImage>
809  std::ostream& os,
810  itk::Indent indent) const
811 {
812  Superclass::PrintSelf(os, indent);
813  os << indent << "Spatial bandwidth: " << m_SpatialBandwidth << std::endl;
814  os << indent << "Range bandwidth: " << m_RangeBandwidth << std::endl;
815 }
816 
817 } // end namespace otb
818 
819 #endif

Generated at Sun Feb 3 2013 00:36:54 for Orfeo Toolbox with doxygen 1.8.1.1