Orfeo Toolbox  3.16
itkParallelSparseFieldLevelSetImageFilter.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkParallelSparseFieldLevelSetImageFilter.txx,v $
5  Language: C++
6  Date: $Date: 2009-09-30 16:07:13 $
7  Version: $Revision: 1.44 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  This software is distributed WITHOUT ANY WARRANTY; without even
13  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  PURPOSE. See the above copyright notices for more information.
15 
16 =========================================================================*/
17 #ifndef __itkParallelSparseFieldLevelSetImageFilter_txx
18 #define __itkParallelSparseFieldLevelSetImageFilter_txx
19 
23 #include "itkImageRegionIterator.h"
25 #include "itkNumericTraits.h"
27 #include "itkMacro.h"
28 #include <iostream>
29 #include <fstream>
30 
31 namespace itk {
32 
33 template <class TNeighborhoodType>
36 {
37  typedef typename NeighborhoodType::ImageType ImageType;
38  typename ImageType::Pointer dummy_image = ImageType::New();
39 
40  unsigned int i, nCenter;
41  int d;
42  OffsetType zero_offset;
43 
44  for (i = 0; i < Dimension; ++i)
45  {
46  m_Radius[i] = 1;
47  zero_offset[i] = 0;
48  }
49  NeighborhoodType it(m_Radius, dummy_image, dummy_image->GetRequestedRegion());
50  nCenter = it.Size() / 2;
51 
52  m_Size = 2 * Dimension;
53  m_ArrayIndex.reserve(m_Size);
54  m_NeighborhoodOffset.reserve(m_Size);
55 
56  for (i = 0; i < m_Size; ++i)
57  {
58  m_NeighborhoodOffset.push_back(zero_offset);
59  }
60 
61  for (d = Dimension - 1, i = 0; d >= 0; --d, ++i)
62  {
63  m_ArrayIndex.push_back( nCenter - it.GetStride(d) );
64  m_NeighborhoodOffset[i][d] = -1;
65  }
66  for (d = 0; d < static_cast<int> (Dimension); ++d, ++i)
67  {
68  m_ArrayIndex.push_back( nCenter + it.GetStride(d) );
69  m_NeighborhoodOffset[i][d] = 1;
70  }
71 
72  for (i = 0; i < Dimension; ++i)
73  {
74  m_StrideTable[i] = it.GetStride(i);
75  }
76 }
77 
78 template <class TNeighborhoodType>
79 void
81 ::Print(std::ostream &os) const
82 {
83  os << "ParallelSparseFieldCityBlockNeighborList: " << std::endl;
84  for (unsigned i = 0; i < this->GetSize(); ++i)
85  {
86  os << "m_ArrayIndex[" << i << "]: " << m_ArrayIndex[i] << std::endl
87  << "m_NeighborhoodOffset[" << i << "]: " << m_NeighborhoodOffset[i] << std::endl;
88  }
89 }
90 
91 template<class TInputImage, class TOutputImage>
94 ::m_ValueOne = NumericTraits<ITK_TYPENAME ParallelSparseFieldLevelSetImageFilter<TInputImage,
95  TOutputImage>::ValueType >::One;
96 
97 template<class TInputImage, class TOutputImage>
100 ::m_ValueZero = NumericTraits<ITK_TYPENAME ParallelSparseFieldLevelSetImageFilter<TInputImage,
101  TOutputImage>::ValueType >::Zero;
102 
103 template<class TInputImage, class TOutputImage>
106 ::m_StatusNull = NumericTraits<ITK_TYPENAME ParallelSparseFieldLevelSetImageFilter<TInputImage,
107  TOutputImage>::StatusType >::NonpositiveMin();
108 
109 template<class TInputImage, class TOutputImage>
112 ::m_StatusChanging = -1;
113 
114 template<class TInputImage, class TOutputImage>
117 ::m_StatusActiveChangingUp = -2;
118 
119 template<class TInputImage, class TOutputImage>
122 ::m_StatusActiveChangingDown = -3;
123 
124 template<class TInputImage, class TOutputImage>
127 ::m_StatusBoundaryPixel = -4;
128 
129 template<class TInputImage, class TOutputImage>
132 {
133  m_IsoSurfaceValue = m_ValueZero;
134  m_NumberOfLayers = ImageDimension;
135  this->SetRMSChange( static_cast<double>( m_ValueOne ) );
136  m_InterpolateSurfaceLocation = true;
137  m_BoundsCheckingActive = false;
138  m_ConstantGradientValue = 1.0;
139  m_GlobalZHistogram = 0;
140  m_ZCumulativeFrequency = 0;
141  m_MapZToThreadNumber = 0;
142  m_Boundary = 0;
143  m_Data = 0;
144 }
145 
146 template<class TInputImage, class TOutputImage>
147 void
150 {
151  if (this->GetState() == Superclass::UNINITIALIZED)
152  {
153  // Clean up any memory from any aborted previous filter executions.
154  this->DeallocateData();
155 
156  // Allocate the output image
157  m_OutputImage= this->GetOutput();
158  m_OutputImage->SetBufferedRegion(m_OutputImage->GetRequestedRegion());
159  m_OutputImage->Allocate();
160 
161  // Copy the input image to the output image. Algorithms will operate
162  // directly on the output image
163  this->CopyInputToOutput();
164 
165  // Perform any other necessary pre-iteration initialization.
166  this->Initialize();
167  this->SetElapsedIterations(0);
168 
169  //NOTE: Cannot set state to initialized yet since more initialization is
170  //done in the Iterate method.
171 
172  }
173 
174  // Evolve the surface
175  this->Iterate();
176 
177  // Clean up
178  if (this->GetManualReinitialization() == false)
179  {
180  this->DeallocateData();
181  this->SetStateToUninitialized(); // Reset the state once execution is
182  // completed
183  }
184 }
185 
186 template<class TInputImage, class TOutputImage>
187 void
190 {
191  // This method is the first step in initializing the level-set image, which
192  // is also the output of the filter. The input is passed through a
193  // zero crossing filter, which produces zero's at pixels closest to the zero
194  // level set and one's elsewhere. The actual zero level set values will be
195  // adjusted in the Initialize() step to more accurately represent the
196  // position of the zero level set.
197 
198  // First need to subtract the iso-surface value from the input image.
199  typedef ShiftScaleImageFilter<InputImageType, OutputImageType> ShiftScaleFilterType;
200  typename ShiftScaleFilterType::Pointer shiftScaleFilter = ShiftScaleFilterType::New();
201  shiftScaleFilter->SetInput( this->GetInput() );
202  shiftScaleFilter->SetShift( - m_IsoSurfaceValue );
203  // keep a handle to the shifted output
204  m_ShiftedImage = shiftScaleFilter->GetOutput();
205 
208  zeroCrossingFilter->SetInput(m_ShiftedImage);
209  zeroCrossingFilter->GraftOutput(m_OutputImage);
210  zeroCrossingFilter->SetBackgroundValue(m_ValueOne);
211  zeroCrossingFilter->SetForegroundValue(m_ValueZero);
212  zeroCrossingFilter->SetNumberOfThreads(1);
213  zeroCrossingFilter->Update();
214 
215  // Here the output is the result of zerocrossings
216  this->GraftOutput(zeroCrossingFilter->GetOutput());
217 }
218 
219 template<class TInputImage, class TOutputImage>
220 void
223 {
224  unsigned int i;
225 
226  // A node pool used during initialization of the level set.
227  m_LayerNodeStore = LayerNodeStorageType::New();
228  m_LayerNodeStore->SetGrowthStrategyToExponential();
229 
230  // Allocate the status image.
231  m_StatusImage = StatusImageType::New();
232  m_StatusImage->SetRegions(m_OutputImage->GetRequestedRegion());
233  m_StatusImage->Allocate();
234 
235  // Initialize the status image to contain all m_StatusNull values.
236  ImageRegionIterator<StatusImageType> statusIt(m_StatusImage,
237  m_StatusImage->GetRequestedRegion());
238  for (statusIt = statusIt.Begin(); ! statusIt.IsAtEnd(); ++statusIt)
239  {
240  statusIt.Set( m_StatusNull );
241  }
242 
243  // Initialize the boundary pixels in the status images to
244  // m_StatusBoundaryPixel values. Uses the face calculator to find all of the
245  // region faces.
247  BFCType;
248 
249  BFCType faceCalculator;
250  typename BFCType::FaceListType faceList;
251  typename BFCType::SizeType sz;
252  typename BFCType::FaceListType::iterator fit;
253 
254  sz.Fill(1);
255  faceList = faceCalculator(m_StatusImage, m_StatusImage->GetRequestedRegion(),
256  sz);
257  fit = faceList.begin();
258 
259  for (++fit; fit != faceList.end(); ++fit) // skip the first (nonboundary) region
260  {
261  statusIt = ImageRegionIterator<StatusImageType>(m_StatusImage, *fit);
262  for (statusIt.GoToBegin(); ! statusIt.IsAtEnd(); ++statusIt)
263  {
264  statusIt.Set( m_StatusBoundaryPixel );
265  }
266  }
267 
268  // Allocate the layers of the sparse field.
269  m_Layers.reserve(2 * m_NumberOfLayers + 1);
270  for (i = 0; i < 2 * static_cast<unsigned int>(m_NumberOfLayers) + 1; ++i)
271  {
272  m_Layers.push_back( LayerType::New() );
273  }
274 
275  m_SplitAxis = m_OutputImage->GetImageDimension() - 1; // always the "Z" dimension
276  if (m_OutputImage->GetImageDimension() < 1)
277  {
278  // cannot split
279  itkDebugMacro ("Unable to choose an axis for workload distribution among threads");
280  return;
281  }
282 
283  typename OutputImageType::SizeType requestedRegionSize
284  = m_OutputImage->GetRequestedRegion().GetSize();
285  m_ZSize = requestedRegionSize[m_SplitAxis];
286 
287  // Histogram of number of pixels in each Z plane for the entire 3D volume
288  m_GlobalZHistogram = new int[m_ZSize];
289  for (i = 0; i < m_ZSize; i++)
290  {
291  m_GlobalZHistogram[i] = 0;
292  }
293 
294  // Construct the active layer and initialize the first layers inside and
295  // outside of the active layer
296  this->ConstructActiveLayer();
297 
298  // Construct the rest of the non active set layers using the first two
299  // layers. Inside layers are odd numbers, outside layers are even numbers.
300  for (i = 1; i < m_Layers.size() - 2; ++i)
301  {
302  this->ConstructLayer(i, i+2);
303  }
304 
305  // Set the values in the output image for the active layer.
306  this->InitializeActiveLayerValues();
307 
308  // Initialize layer values using the active layer as seeds.
309  this->PropagateAllLayerValues();
310 
311  // Initialize pixels inside and outside the sparse field layers to positive
312  // and negative values, respectively. This is not necessary for the
313  // calculations, but is useful for presenting a more intuitive output to the
314  // filter. See PostProcessOutput method for more information.
315  this->InitializeBackgroundPixels();
316 
317  m_NumOfThreads = this->GetNumberOfThreads();
318 
319  // Cumulative frequency of number of pixels in each Z plane for the entire 3D
320  // volume
321  m_ZCumulativeFrequency = new int[m_ZSize];
322  for (i = 0; i < m_ZSize; i++)
323  {
324  m_ZCumulativeFrequency[i] = 0;
325  }
326 
327  // The mapping from a z-value to the thread in whose region the z-value lies
328  m_MapZToThreadNumber = new unsigned int[m_ZSize];
329  for (i = 0; i < m_ZSize; i++)
330  {
331  m_MapZToThreadNumber[i] = 0;
332  }
333 
334  // The boundaries defining thread regions
335  m_Boundary = new unsigned int[m_NumOfThreads];
336  for (i = 0; i < m_NumOfThreads; i++)
337  {
338  m_Boundary[i] = 0;
339  }
340 
341  // A boolean variable stating if the boundaries had been changed during
342  // CheckLoadBalance()
343  m_BoundaryChanged = false;
344 
345  // A global barrier for all threads.
346  m_Barrier = Barrier::New();
347  m_Barrier->Initialize(m_NumOfThreads);
348 
349  // Allocate data for each thread.
350  m_Data = new ThreadData[m_NumOfThreads];
351 }
352 
353 template <class TInputImage, class TOutputImage>
354 void
357 {
358  // We find the active layer by searching for 0's in the zero crossing image
359  // (output image). The first inside and outside layers are also constructed
360  // by searching the neighbors of the active layer in the (shifted) input image.
361  // Negative neighbors not in the active set are assigned to the inside,
362  // positive neighbors are assigned to the outside.
363 
364  NeighborhoodIterator<OutputImageType> shiftedIt(m_NeighborList.GetRadius(),
365  m_ShiftedImage, m_OutputImage->GetRequestedRegion());
366  NeighborhoodIterator<OutputImageType> outputIt (m_NeighborList.GetRadius(),
367  m_OutputImage, m_OutputImage->GetRequestedRegion());
368  NeighborhoodIterator<StatusImageType> statusIt (m_NeighborList.GetRadius(),
369  m_StatusImage, m_OutputImage->GetRequestedRegion());
370 
371  IndexType center_index, offset_index;
372  LayerNodeType *node;
373  bool bounds_status = true;
374  ValueType value;
375  StatusType layer_number;
376 
377  typename OutputImageType::SizeType regionSize
378  = m_OutputImage->GetRequestedRegion().GetSize();
379  typename OutputImageType::IndexType startIndex
380  = m_OutputImage->GetRequestedRegion().GetIndex();
381  typedef typename OutputImageType::IndexType::IndexValueType StartIndexValueType;
382 
383  for (outputIt.GoToBegin(); !outputIt.IsAtEnd(); ++outputIt)
384  {
385  bounds_status = true;
386  if ( outputIt.GetCenterPixel() == m_ValueZero )
387  {
388  // Grab the neighborhood in the status image.
389  center_index = outputIt.GetIndex();
390  statusIt.SetLocation( center_index );
391 
392  for(unsigned int j = 0; j < ImageDimension; j++)
393  {
394  if ( (center_index[j]) <= (startIndex[j]) ||
395  (center_index[j]) >= startIndex[j] +
396  static_cast<StartIndexValueType>(regionSize[j]-1))
397  {
398  bounds_status = false;
399  break;
400  }
401  }
402  if(bounds_status == true)
403  {
404  // Here record the hisgram information
405  m_GlobalZHistogram[ center_index[m_SplitAxis] ]++;
406 
407  // Borrow a node from the store and set its value.
408  node = m_LayerNodeStore->Borrow();
409  node->m_Index = center_index;
410 
411  // Add the node to the active list and set the status in the status
412  // image.
413  m_Layers[0]->PushFront( node );
414  statusIt.SetCenterPixel( 0 );
415 
416  // Grab the neighborhood in the image of shifted input values.
417  shiftedIt.SetLocation( center_index );
418 
419  // Search the neighborhood pixels for first inside & outside layer
420  // members. Construct these lists and set status list values.
421  for (unsigned int i = 0; i < m_NeighborList.GetSize(); ++i)
422  {
423  offset_index = center_index + m_NeighborList.GetNeighborhoodOffset(i);
424 
425  if ( outputIt.GetPixel(m_NeighborList.GetArrayIndex(i)) != m_ValueZero &&
426  statusIt.GetPixel(m_NeighborList.GetArrayIndex(i)) == m_StatusNull)
427  {
428  value = shiftedIt.GetPixel(m_NeighborList.GetArrayIndex(i));
429 
430  if ( value < m_ValueZero ) // Assign to first outside layer.
431  {
432  layer_number = 1;
433  }
434  else // Assign to first inside layer
435  {
436  layer_number = 2;
437  }
438 
439  statusIt.SetPixel( m_NeighborList.GetArrayIndex(i), layer_number, bounds_status );
440  if ( bounds_status == true ) // In bounds
441  {
442  node = m_LayerNodeStore->Borrow();
443  node->m_Index = offset_index;
444  m_Layers[layer_number]->PushFront( node );
445  } // else do nothing.
446  }
447  }
448  }
449  }
450  }
451 }
452 
453 template<class TInputImage, class TOutputImage>
454 void
457 {
458  LayerNodeType *node;
459  bool boundary_status;
460  typename LayerType::ConstIterator fromIt;
461  NeighborhoodIterator<StatusImageType> statusIt(m_NeighborList.GetRadius(), m_StatusImage,
462  m_OutputImage->GetRequestedRegion() );
463 
464  // For all indicies in the "from" layer...
465  for (fromIt = m_Layers[from]->Begin(); fromIt != m_Layers[from]->End(); ++fromIt)
466  {
467  // Search the neighborhood of this index in the status image for
468  // unassigned indicies. Push those indicies onto the "to" layer and
469  // assign them values in the status image. Status pixels outside the
470  // boundary will be ignored.
471  statusIt.SetLocation( fromIt->m_Index );
472 
473  for (unsigned int i = 0; i < m_NeighborList.GetSize(); ++i)
474  {
475  if ( statusIt.GetPixel( m_NeighborList.GetArrayIndex(i) ) == m_StatusNull )
476  {
477  statusIt.SetPixel(m_NeighborList.GetArrayIndex(i), to, boundary_status);
478 
479  if (boundary_status == true) // in bounds
480  {
481  node = m_LayerNodeStore->Borrow();
482  node->m_Index = statusIt.GetIndex() + m_NeighborList.GetNeighborhoodOffset(i);
483  m_Layers[to]->PushFront( node );
484  }
485  }
486  }
487  }
488 }
489 
490 template <class TInputImage, class TOutputImage>
491 void
494 {
495  const ValueType CHANGE_FACTOR = m_ConstantGradientValue / 2.0;
496  ValueType MIN_NORM = 1.0e-6;
497  if (this->GetUseImageSpacing())
498  {
499  double minSpacing = NumericTraits<double>::max();
500  for (unsigned int i=0; i<ImageDimension; i++)
501  {
502  minSpacing = vnl_math_min(minSpacing,this->GetInput()->GetSpacing()[i]);
503  }
504  MIN_NORM *= minSpacing;
505  }
506 
507  typename LayerType::ConstIterator activeIt;
508  ConstNeighborhoodIterator<OutputImageType>shiftedIt (m_NeighborList.GetRadius(), m_ShiftedImage,
509  m_OutputImage->GetRequestedRegion());
510 
511  unsigned int center = shiftedIt.Size() /2;
512  unsigned int stride;
513 
514  const NeighborhoodScalesType neighborhoodScales = this->GetDifferenceFunction()->ComputeNeighborhoodScales();
515 
516  ValueType dx_forward, dx_backward, length, distance;
517 
518  // For all indicies in the active layer...
519  for (activeIt = m_Layers[0]->Begin(); activeIt != m_Layers[0]->End(); ++activeIt)
520  {
521  // Interpolate on the (shifted) input image values at this index to
522  // assign an active layer value in the output image.
523  shiftedIt.SetLocation( activeIt->m_Index );
524 
525  length = m_ValueZero;
526  for (unsigned int i = 0; i < static_cast<unsigned int>(ImageDimension); ++i)
527  {
528  stride = shiftedIt.GetStride(i);
529 
530  dx_forward = ( shiftedIt.GetPixel(center + stride) - shiftedIt.GetCenterPixel() ) * neighborhoodScales[i];
531  dx_backward = ( shiftedIt.GetCenterPixel() - shiftedIt.GetPixel(center - stride) ) * neighborhoodScales[i];
532 
533  if ( vnl_math_abs(dx_forward) > vnl_math_abs(dx_backward) )
534  {
535  length += dx_forward * dx_forward;
536  }
537  else
538  {
539  length += dx_backward * dx_backward;
540  }
541  }
542  length = vcl_sqrt(length) + MIN_NORM;
543  distance = shiftedIt.GetCenterPixel() / length;
544 
545  m_OutputImage->SetPixel( activeIt->m_Index ,
546  vnl_math_min(vnl_math_max(-CHANGE_FACTOR, distance), CHANGE_FACTOR));
547  }
548 }
549 
550 template <class TInputImage, class TOutputImage>
551 void
554 {
555  // Update values in the first inside and first outside layers using the
556  // active layer as a seed. Inside layers are odd numbers, outside layers are
557  // even numbers.
558  this->PropagateLayerValues (0, 1, 3, 1); // first inside
559  this->PropagateLayerValues (0, 2, 4, 0); // first outside
560 
561  // Update the rest of the layers.
562  for (unsigned int i = 1; i < m_Layers.size() - 2; ++i)
563  {
564  this->PropagateLayerValues (i, i+2, i+4, (i+2)%2);
565  }
566 }
567 
568 template <class TInputImage, class TOutputImage>
569 void
571 ::PropagateLayerValues(StatusType from, StatusType to, StatusType promote, unsigned int InOrOut)
572 {
573  unsigned int i;
574  ValueType value, value_temp, delta;
575  bool found_neighbor_flag;
576  LayerNodeType* node;
577  StatusType past_end = static_cast<StatusType>( m_Layers.size() ) - 1;
578 
579  // Are we propagating values inward (more negative) or outward (more positive)?
580  if (InOrOut == 1)
581  {
582  delta = - m_ConstantGradientValue; // inward
583  }
584  else
585  {
586  delta = m_ConstantGradientValue;
587  }
588 
589  NeighborhoodIterator<OutputImageType> outputIt (m_NeighborList.GetRadius(), m_OutputImage,
590  m_OutputImage->GetRequestedRegion());
591  NeighborhoodIterator<StatusImageType> statusIt (m_NeighborList.GetRadius(), m_StatusImage,
592  m_OutputImage->GetRequestedRegion());
593 
594  typename LayerType::Iterator toIt = m_Layers[to]->Begin();
595  while ( toIt != m_Layers[to]->End() )
596  {
597  statusIt.SetLocation( toIt->m_Index );
598  // Is this index marked for deletion? If the status image has
599  // been marked with another layer's value, we need to delete this node
600  // from the current list then skip to the next iteration.
601  if (statusIt.GetCenterPixel() != to)
602  {
603  node = toIt.GetPointer();
604  ++toIt;
605  m_Layers[to]->Unlink( node );
606  m_LayerNodeStore->Return( node );
607  continue;
608  }
609 
610  outputIt.SetLocation( toIt->m_Index );
611 
612  value = m_ValueZero;
613  found_neighbor_flag = false;
614  for (i = 0; i < m_NeighborList.GetSize(); ++i)
615  {
616  // If this neighbor is in the "from" list, compare its absolute value
617  // to any previous values found in the "from" list. Keep the value
618  // that will cause the next layer to be closest to the zero level set.
619  if ( statusIt.GetPixel( m_NeighborList.GetArrayIndex(i) ) == from )
620  {
621  value_temp = outputIt.GetPixel( m_NeighborList.GetArrayIndex(i) );
622 
623  if (found_neighbor_flag == false)
624  {
625  value = value_temp;
626  }
627  else
628  {
629  if (vnl_math_abs(value_temp+delta) < vnl_math_abs(value+delta))
630  {
631  // take the value closest to zero
632  value= value_temp;
633  }
634  }
635  found_neighbor_flag = true;
636  }
637  }
638  if (found_neighbor_flag == true)
639  {
640  // Set the new value using the smallest magnitude
641  // found in our "from" neighbors.
642  outputIt.SetCenterPixel( value + delta );
643  ++toIt;
644  }
645  else
646  {
647  // Did not find any neighbors on the "from" list, then promote this
648  // node. A "promote" value past the end of my sparse field size
649  // means delete the node instead. Change the status value in the
650  // status image accordingly.
651  node = toIt.GetPointer();
652  ++toIt;
653  m_Layers[to]->Unlink( node );
654  if ( promote > past_end )
655  {
656  m_LayerNodeStore->Return( node );
657  statusIt.SetCenterPixel(m_StatusNull);
658  }
659  else
660  {
661  m_Layers[promote]->PushFront( node );
662  statusIt.SetCenterPixel(promote);
663  }
664  }
665  }
666 }
667 
668 template <class TInputImage, class TOutputImage>
669 void
672 {
673  // Assign background pixels INSIDE the sparse field layers to a new level set
674  // with value less than the innermost layer. Assign background pixels
675  // OUTSIDE the sparse field layers to a new level set with value greater than
676  // the outermost layer.
677  const ValueType max_layer = static_cast<ValueType>(m_NumberOfLayers);
678 
679  const ValueType outside_value = (max_layer+1) * m_ConstantGradientValue;
680  const ValueType inside_value = -(max_layer+1) * m_ConstantGradientValue;
681 
682  ImageRegionConstIterator<StatusImageType> statusIt(m_StatusImage,
683  this->GetOutput()->GetRequestedRegion());
684 
685  ImageRegionIterator<OutputImageType> outputIt(this->GetOutput(),
686  this->GetOutput()->GetRequestedRegion());
687 
688  ImageRegionConstIterator<OutputImageType> shiftedIt(m_ShiftedImage,
689  this->GetOutput()->GetRequestedRegion());
690 
691  for (outputIt = outputIt.Begin(), statusIt = statusIt.Begin(),
692  shiftedIt = shiftedIt.Begin();
693  ! outputIt.IsAtEnd(); ++outputIt, ++statusIt, ++shiftedIt)
694  {
695  if (statusIt.Get() == m_StatusNull || statusIt.Get() == m_StatusBoundaryPixel)
696  {
697  if (shiftedIt.Get() > m_ValueZero)
698  {
699  outputIt.Set(outside_value);
700  }
701  else
702  {
703  outputIt.Set(inside_value);
704  }
705  }
706  }
707 
708  // deallocate the shifted-image
709  m_ShiftedImage = 0;
710 }
711 
712 template<class TInputImage, class TOutputImage>
713 void
716 {
717  // NOTE: Properties of the boundary computation algorithm
718  // 1. Thread-0 always has something to work on.
719  // 2. If a particular thread numbered i has the m_Boundary = (mZSize -
720  // 1) then ALL threads numbered > i do NOT have anything to work on.
721 
722  // Compute the cumulative frequency distribution using the global histogram.
723  unsigned int i, j;
724  m_ZCumulativeFrequency[0] = m_GlobalZHistogram[0];
725  for (i= 1; i < m_ZSize; i++)
726  {
727  m_ZCumulativeFrequency[i] = m_ZCumulativeFrequency[i-1] + m_GlobalZHistogram[i];
728  }
729 
730  // Now define the regions that each thread will process and the corresponding
731  // boundaries.
732  m_Boundary[m_NumOfThreads - 1] = m_ZSize - 1; // special case: the upper
733  // bound for the last thread
734  for (i= 0; i < m_NumOfThreads - 1; i++)
735  {
736  // compute m_Boundary[i]
737 
738  float cutOff = 1.0 * (i+1) * m_ZCumulativeFrequency[m_ZSize-1] / m_NumOfThreads;
739 
740  // find the position in the cumulative freq dist where this cutoff is met
741  for (j = (i == 0 ? 0 : m_Boundary[i-1]); j < m_ZSize; j++)
742  {
743  if (cutOff > m_ZCumulativeFrequency[j])
744  {
745  continue;
746  }
747  else
748  {
749  // Optimize a little.
750  // Go further FORWARD and find the first index (k) in the cumulative
751  // freq distribution s.t. m_ZCumulativeFrequency[k] !=
752  // m_ZCumulativeFrequency[j] This is to be done because if we have a
753  // flat patch in the cumulative freq. dist. then we can choose
754  // a bound midway in that flat patch .
755  unsigned int k;
756  for (k= 1; j+k < m_ZSize; k++)
757  {
758  if (m_ZCumulativeFrequency[j+k] != m_ZCumulativeFrequency[j])
759  {
760  break;
761  }
762  }
763 
764  //
765  m_Boundary[i]= static_cast<unsigned int>( (j + k / 2) );
766  break;
767  }
768  }
769  }
770 
771  // Initialize the local histograms using the global one and the boundaries
772  // Also initialize the mapping from the Z value --> the thread number
773  // i.e. m_MapZToThreadNumber[]
774  // Also divide the lists up according to the boundaries
775  for (i = 0; i <= m_Boundary[0]; i++)
776  {
777  // this Z belongs to the region associated with thread-0
778  m_MapZToThreadNumber[i]= 0;
779  }
780 
781  for (unsigned int t= 1; t < m_NumOfThreads; t++)
782  {
783  for (i = m_Boundary[t-1]+1; i <= m_Boundary[t]; i++)
784  {
785  // this Z belongs to the region associated with thread-0
786  m_MapZToThreadNumber[i]= t;
787  }
788  }
789 }
790 
791 template<class TInputImage, class TOutputImage>
792 void
794 ::ThreadedAllocateData (unsigned int ThreadId)
795 {
796  static const float SAFETY_FACTOR = 4.0;
797  unsigned int i, j;
798  // create semaphores
799  m_Data[ThreadId].m_Semaphore[0] = Semaphore::New ();
800  m_Data[ThreadId].m_Semaphore[1] = Semaphore::New ();
801  m_Data[ThreadId].m_Semaphore[0]->Initialize(0);
802  m_Data[ThreadId].m_Semaphore[1]->Initialize(0);
803 
804  // Allocate the layers for the sparse field.
805  m_Data[ThreadId].m_Layers.reserve(2 * m_NumberOfLayers + 1);
806  for (i = 0; i < 2 * static_cast<unsigned int>(m_NumberOfLayers) + 1; ++i)
807  {
808  m_Data[ThreadId].m_Layers.push_back( LayerType::New() );
809  }
810  // Throw an exception if we don't have enough layers.
811  if (m_Data[ThreadId].m_Layers.size() < 3)
812  {
813  itkExceptionMacro( << "Not enough layers have been allocated for the sparse"
814  << "field. Requires at least one layer." );
815  }
816 
817  // Layers used as buffers for transfering pixels during load balancing
818  m_Data[ThreadId].m_LoadTransferBufferLayers
819  = new LayerListType[2*m_NumberOfLayers+1];
820  for (i = 0; i < 2 * static_cast<unsigned int>(m_NumberOfLayers) + 1; i++)
821  {
822  m_Data[ThreadId].m_LoadTransferBufferLayers[i].reserve( m_NumOfThreads );
823 
824  for (j = 0; j < m_NumOfThreads; j++)
825  {
826  m_Data[ThreadId].m_LoadTransferBufferLayers[i].push_back(LayerType::New());
827  }
828  }
829 
830  // Every thread allocates a local node pool (improving memory locality)
831  m_Data[ThreadId].m_LayerNodeStore = LayerNodeStorageType::New();
832  m_Data[ThreadId].m_LayerNodeStore->SetGrowthStrategyToExponential();
833 
834  // The SAFETY_FACTOR simple ensures that the number of nodes created
835  // is larger than those required to start with for each thread.
836  unsigned int nodeNum= static_cast<unsigned int>(SAFETY_FACTOR * m_Layers[0]->Size()
837  * (2*m_NumberOfLayers+1) / m_NumOfThreads);
838 
839  m_Data[ThreadId].m_LayerNodeStore->Reserve(nodeNum);
840  m_Data[ThreadId].m_RMSChange = m_ValueZero;
841 
842  // UpLists and Downlists
843  for (i = 0; i < 2; ++i)
844  {
845  m_Data[ThreadId].UpList[i] = LayerType::New();
846  m_Data[ThreadId].DownList[i] = LayerType::New();
847  }
848 
849  // Used during the time when status lists are being processed (in ThreadedApplyUpdate() )
850  // for the Uplists
851  m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[0]
852  = new LayerPointerType * [m_NumberOfLayers + 1];
853 
854  // for the Downlists
855  m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[1]
856  = new LayerPointerType * [m_NumberOfLayers + 1];
857 
858  for (i= 0; i < static_cast<unsigned int>(m_NumberOfLayers) + 1; i++)
859  {
860  m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[0][i] =
861  new LayerPointerType[m_NumOfThreads];
862  m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[1][i] =
863  new LayerPointerType[m_NumOfThreads];
864  }
865 
866  for (i= 0; i < static_cast<unsigned int>(m_NumberOfLayers) + 1; i++)
867  {
868  for (j= 0; j < m_NumOfThreads; j++)
869  {
870  m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[0][i][j]
871  = LayerType::New();
872  m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[1][i][j]
873  = LayerType::New();
874  }
875  }
876 
877  // Local histogram for every thread (used during Iterate() )
878  m_Data[ThreadId].m_ZHistogram = new int[m_ZSize];
879  for (i = 0; i < m_ZSize; i++)
880  {
881  m_Data[ThreadId].m_ZHistogram[i] = 0;
882  }
883 
884  // Every thread must have its own copy of the the GlobalData struct.
885  m_Data[ThreadId].globalData
886  = this->GetDifferenceFunction()->GetGlobalDataPointer();
887 
888  //
889  m_Data[ThreadId].m_SemaphoreArrayNumber = 0;
890 }
891 
892 template<class TInputImage, class TOutputImage>
893 void
895 ::ThreadedInitializeData(unsigned int ThreadId, const ThreadRegionType & ThreadRegion)
896 {
897  // divide the lists based on the boundaries
898 
899  LayerNodeType * nodePtr, * nodeTempPtr;
900 
901  for (unsigned int i = 0; i < 2 * static_cast<unsigned int>(m_NumberOfLayers) + 1; i++)
902  {
903  typename LayerType::Iterator layerIt = m_Layers[i]->Begin();
904  typename LayerType::Iterator layerEnd= m_Layers[i]->End();
905 
906  while (layerIt != layerEnd)
907  {
908  nodePtr = layerIt.GetPointer();
909  ++layerIt;
910 
911  unsigned int k = this->GetThreadNumber(nodePtr->m_Index[m_SplitAxis]);
912  if (k != ThreadId)
913  {
914  continue; // some other thread's node => ignore
915  }
916 
917  // Borrow a node from the specific thread's layer so that MEMORY LOCALITY
918  // is maintained.
919  // NOTE : We already pre-allocated more than enough
920  // nodes for each thread implying no new nodes are created here.
921  nodeTempPtr= m_Data[ThreadId].m_LayerNodeStore->Borrow ();
922  nodeTempPtr->m_Index= nodePtr->m_Index;
923  // push the node on the approproate layer
924  m_Data[ThreadId].m_Layers[i]->PushFront(nodeTempPtr);
925 
926  // for the active layer (layer-0) build the histogram for each thread
927  if (i == 0)
928  {
929  // this Z histogram value should be given to thread-0
930  m_Data[ThreadId].m_ZHistogram[ (nodePtr->m_Index)[m_SplitAxis] ]
931  = m_Data[ThreadId].m_ZHistogram[ (nodePtr->m_Index)[m_SplitAxis] ] + 1;
932  }
933  }
934  }
935 
936  // Make use of the SGI default "first-touch" memory placement policy
937  // Copy from the current status/output images to the new ones and let each
938  // thread do the copy of its own region.
939  // This will make each thread be the FIRST to write to "it's" data in the new
940  // images and hence the memory will get allocated
941  // in the corresponding thread's memory-node.
942  ImageRegionConstIterator<StatusImageType> statusIt(m_StatusImage, ThreadRegion);
943  ImageRegionIterator<StatusImageType> statusItNew (m_StatusImageTemp, ThreadRegion);
944  ImageRegionConstIterator<OutputImageType> outputIt(m_OutputImage, ThreadRegion);
945  ImageRegionIterator<OutputImageType> outputItNew(m_OutputImageTemp, ThreadRegion);
946 
947  for (outputIt = outputIt.Begin(), statusIt = statusIt.Begin(),
948  outputItNew = outputItNew.Begin(), statusItNew = statusItNew.Begin();
949  ! outputIt.IsAtEnd(); ++outputIt, ++statusIt, ++outputItNew, ++statusItNew)
950  {
951  statusItNew.Set (statusIt.Get());
952  outputItNew.Set (outputIt.Get());
953  }
954 }
955 
956 template <class TInputImage, class TOutputImage>
957 void
960 {
961  unsigned int i, j;
962  // Delete data structures used for load distribution and balancing.
963  if ( m_GlobalZHistogram != 0 )
964  {
965  delete [] m_GlobalZHistogram;
966  m_GlobalZHistogram = 0;
967  }
968  if ( m_ZCumulativeFrequency != 0 )
969  {
970  delete [] m_ZCumulativeFrequency;
971  m_ZCumulativeFrequency = 0;
972  }
973  if ( m_MapZToThreadNumber != 0 )
974  {
975  delete [] m_MapZToThreadNumber;
976  m_MapZToThreadNumber = 0;
977  }
978  if (m_Boundary != 0)
979  {
980  delete [] m_Boundary;
981  m_Boundary = 0;
982  }
983 
984  // Deallocate the status image.
985  m_StatusImage= 0;
986 
987  // Remove the barrier from the system.
988  // m_Barrier->Remove ();
989 
990  // Delete initial nodes, the node pool, the layers.
991  if (! m_Layers.empty())
992  {
993  for (i = 0; i < 2* static_cast<unsigned int>(m_NumberOfLayers)+1; i++)
994  {
995  // return all the nodes in layer i to the main node pool
996  LayerNodeType * nodePtr= 0;
997  LayerPointerType layerPtr= m_Layers[i];
998  while (! layerPtr->Empty())
999  {
1000  nodePtr= layerPtr->Front();
1001  layerPtr->PopFront();
1002  m_LayerNodeStore->Return (nodePtr);
1003  }
1004  }
1005  }
1006  if (m_LayerNodeStore)
1007  {
1008  m_LayerNodeStore->Clear();
1009  m_Layers.clear();
1010  }
1011 
1012  if (m_Data != 0)
1013  {
1014  // Deallocate the thread local data structures.
1015  for (unsigned int ThreadId= 0; ThreadId < m_NumOfThreads; ThreadId++)
1016  {
1017  // Remove semaphores from the system.
1018  m_Data[ThreadId].m_Semaphore[0]->Remove();
1019  m_Data[ThreadId].m_Semaphore[1]->Remove();
1020 
1021  delete [] m_Data[ThreadId].m_ZHistogram;
1022 
1023  if (m_Data[ThreadId].globalData != 0)
1024  {
1025  this->GetDifferenceFunction()->ReleaseGlobalDataPointer (m_Data[ThreadId].globalData);
1026  m_Data[ThreadId].globalData= 0;
1027  }
1028 
1029  // 1. delete nodes on the thread layers
1030  for (i = 0; i < 2 * static_cast<unsigned int>(m_NumberOfLayers) + 1; i++)
1031  {
1032  // return all the nodes in layer i to thread-i's node pool
1033  LayerNodeType * nodePtr;
1034  LayerPointerType layerPtr= m_Data[ThreadId].m_Layers[i];
1035  while (! layerPtr->Empty())
1036  {
1037  nodePtr= layerPtr->Front();
1038  layerPtr->PopFront();
1039  m_Data[ThreadId].m_LayerNodeStore->Return(nodePtr);
1040  }
1041  }
1042  m_Data[ThreadId].m_Layers.clear();
1043 
1044  // 2. cleanup the LoadTransferBufferLayers: empty all and return the nodes
1045  // to the pool
1046  for (i = 0; i < 2 * static_cast<unsigned int>(m_NumberOfLayers) + 1; i++)
1047  {
1048  for (j= 0; j < m_NumOfThreads; j++)
1049  {
1050  if (j == ThreadId)
1051  {
1052  // a thread does NOT pass nodes to istelf
1053  continue;
1054  }
1055 
1056  LayerNodeType * nodePtr;
1057  LayerPointerType layerPtr= m_Data[ThreadId].m_LoadTransferBufferLayers[i][j];
1058 
1059  while (! layerPtr->Empty())
1060  {
1061  nodePtr= layerPtr->Front();
1062  layerPtr->PopFront();
1063  m_Data[ThreadId].m_LayerNodeStore->Return (nodePtr);
1064  }
1065  }
1066  m_Data[ThreadId].m_LoadTransferBufferLayers[i].clear();
1067  }
1068  delete [] m_Data[ThreadId].m_LoadTransferBufferLayers;
1069 
1070  // 3. clear up the nodes in the last layer of m_InterNeighborNodeTransferBufferLayers (if any)
1071  for (i= 0; i < m_NumOfThreads; i++)
1072  {
1073  LayerNodeType* nodePtr;
1074  for (unsigned int InOrOut= 0; InOrOut < 2; InOrOut++)
1075  {
1076  LayerPointerType layerPtr
1077  = m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[InOrOut][m_NumberOfLayers][i];
1078 
1079  while (! layerPtr->Empty())
1080  {
1081  nodePtr= layerPtr->Front();
1082  layerPtr->PopFront();
1083  m_Data[ThreadId].m_LayerNodeStore->Return(nodePtr);
1084  }
1085  }
1086  }
1087 
1088  // check if all last layers are empty and then delete them
1089  for (i = 0; i < static_cast<unsigned int>(m_NumberOfLayers) + 1; i++)
1090  {
1091  delete [] m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[0][i];
1092  delete [] m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[1][i];
1093  }
1094  delete [] m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[0];
1095  delete [] m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[1];
1096 
1097  // 4. check if all the uplists and downlists are empty
1098 
1099  // 5. delete all nodes in the node pool
1100  m_Data[ThreadId].m_LayerNodeStore->Clear();
1101  }
1102 
1103  delete [] m_Data;
1104  } // if m_data != 0
1105  m_Data= 0;
1106 }
1107 
1108 template<class TInputImage, class TOutputImage>
1109 void
1111 ::ThreadedInitializeIteration (unsigned int itkNotUsed(ThreadId))
1112 {
1113  // If child classes need an entry point to the start of every iteration step
1114  // they can override this method.
1115  return;
1116 }
1117 
1118 template<class TInputImage, class TOutputImage>
1119 void
1122 {
1123  // Set up for multithreaded processing
1125  str.Filter = this;
1126  str.TimeStep = NumericTraits<TimeStepType>::Zero;
1127 
1128  this->GetMultiThreader()->SetNumberOfThreads (m_NumOfThreads);
1129 
1130  // Initialize the list of time step values that will be generated by the
1131  // various threads. There is one distinct slot for each possible thread,
1132  // so this data structure is thread-safe.
1133  str.TimeStepList = new TimeStepType[m_NumOfThreads];
1134  str.ValidTimeStepList = new bool [m_NumOfThreads];
1135 
1136  for (unsigned int i =0; i < m_NumOfThreads; ++i)
1137  {
1138  str.ValidTimeStepList[i] = true;
1139  }
1140 
1141  // Multithread the execution
1142  this->GetMultiThreader()->SetSingleMethod(this->IterateThreaderCallback, &str);
1143  // It is this method that will results in the creation of the threads
1144  this->GetMultiThreader()->SingleMethodExecute ();
1145 
1146  delete [] str.TimeStepList;
1147  delete [] str.ValidTimeStepList;
1148 }
1149 
1150 template<class TInputImage, class TOutputImage>
1154 {
1155  // Controls how often we check for balance of the load among the threads and perform
1156  // load balancing (if needed) by redistributing the load.
1157  const unsigned int LOAD_BALANCE_ITERATION_FREQUENCY = 30;
1158 
1159  unsigned int i;
1160  unsigned int ThreadId = ((MultiThreader::ThreadInfoStruct *)(arg))->ThreadID;
1161 
1164  (((MultiThreader::ThreadInfoStruct *)(arg))->UserData);
1165 
1166 
1167 #ifdef ITK_USE_SPROC
1168  // Every thread should 'usadd' itself to the arena as the very first thing so
1169  // as to detect errors (if any) early.
1170  if (str->Filter->GetState() == Superclass::UNINITIALIZED)
1171  {
1172  if (MultiThreader::GetThreadArena() != 0)
1173  {
1174  int code= usadd (MultiThreader::GetThreadArena());
1175  if (code != 0)
1176  {
1177  OStringStream message;
1178  message << "Thread failed to join SGI arena: error";
1179  throw ::itk::ExceptionObject(__FILE__, __LINE__, message.str().c_str(),ITK_LOCATION);
1180  }
1181  }
1182  }
1183 #endif
1184 
1185  // allocate thread data: every thread allocates its own data
1186  // We do NOT assume here that malloc is thread safe: hence make threads
1187  // allocate data serially
1188  if (str->Filter->GetState() == Superclass::UNINITIALIZED)
1189  {
1190  if (ThreadId == 0)
1191  {
1193 
1194  // Create the temporary status image
1195  str->Filter->m_StatusImageTemp = StatusImageType::New();
1196  str->Filter->m_StatusImageTemp->SetRegions(str->Filter->m_OutputImage->GetRequestedRegion());
1197  str->Filter->m_StatusImageTemp->Allocate();
1198 
1199  // Create the temporary output image
1200  str->Filter->m_OutputImageTemp = OutputImageType::New();
1201  str->Filter->m_OutputImageTemp->CopyInformation(str->Filter->m_OutputImage);
1202  str->Filter->m_OutputImageTemp->SetRegions(str->Filter->m_OutputImage->GetRequestedRegion());
1203  str->Filter->m_OutputImageTemp->Allocate();
1204  }
1205  str->Filter->WaitForAll();
1206 
1207  // Data allocation performed serially.
1208  for (i= 0; i < str->Filter->m_NumOfThreads; i++)
1209  {
1210  if (ThreadId == i)
1211  {
1212  str->Filter->ThreadedAllocateData (ThreadId);
1213  }
1214  str->Filter->WaitForAll();
1215  }
1216 
1217  // Data initialization performed in parallel.
1218  // Make use of the SGI default first-touch memory placement policy
1219  str->Filter->GetThreadRegionSplitByBoundary(ThreadId,
1220  str->Filter->m_Data[ThreadId].ThreadRegion);
1221  str->Filter->ThreadedInitializeData(ThreadId,
1222  str->Filter->m_Data[ThreadId].ThreadRegion);
1223  str->Filter->WaitForAll();
1224 
1225  if (ThreadId == 0)
1226  {
1227  str->Filter->m_StatusImage = 0;
1229  str->Filter->m_StatusImageTemp = 0;
1230 
1231  str->Filter->m_OutputImage = 0;
1233  str->Filter->m_OutputImageTemp = 0;
1234  //
1235  str->Filter->GraftOutput(str->Filter->m_OutputImage);
1236  }
1237  str->Filter->WaitForAll();
1238  str->Filter->SetStateToInitialized();
1239  }
1240 
1241  unsigned int iter = str->Filter->GetElapsedIterations();
1242  while (! (str->Filter->ThreadedHalt(arg)) )
1243  {
1244  str->Filter->ThreadedInitializeIteration(ThreadId);
1245 
1246  // Threaded Calculate Change
1247  str->Filter->m_Data[ThreadId].TimeStep
1248  = str->Filter->ThreadedCalculateChange(ThreadId);
1249 
1250  str->Filter->WaitForAll();
1251 
1252  // Handle AbortGenerateData()
1253  if (str->Filter->m_NumOfThreads == 1 || ThreadId == 0)
1254  {
1255  if( str->Filter->GetAbortGenerateData() )
1256  {
1257  str->Filter->InvokeEvent( IterationEvent() );
1258  str->Filter->ResetPipeline();
1259  ProcessAborted e(__FILE__,__LINE__);
1260  e.SetDescription("Process aborted.");
1261  e.SetLocation(ITK_LOCATION);
1262  throw e;
1263  }
1264  }
1265 
1266  // Calculate the timestep (no need to do this when there is just 1 thread)
1267  if (str->Filter->m_NumOfThreads == 1)
1268  {
1269  if (iter != 0)
1270  {
1271  // Update the RMS difference here
1272  str->Filter->SetRMSChange( static_cast<double>(str->Filter->m_Data[0].m_RMSChange));
1273  unsigned int count = str->Filter->m_Data[0].m_Count;
1274  if (count != 0)
1275  {
1276  str->Filter->SetRMSChange( static_cast<double>(vcl_sqrt(
1277  (static_cast<float> (str->Filter->GetRMSChange())) / count)));
1278  }
1279  }
1280 
1281  // this is done by the thread0
1282  str->Filter->InvokeEvent( IterationEvent() );
1283  str->Filter->InvokeEvent( ProgressEvent () );
1284  str->Filter->SetElapsedIterations(++iter);
1285 
1286  str->TimeStep = str->Filter->m_Data[0].TimeStep; // (works for the 1-thread
1287  // case else redefined below)
1288  }
1289  else
1290  {
1291  if (ThreadId == 0)
1292  {
1293  if (iter != 0)
1294  {
1295  // Update the RMS difference here
1296  unsigned int count = 0;
1297  str->Filter->SetRMSChange(static_cast<double>( m_ValueZero ));
1298  for (i = 0; i < str->Filter->m_NumOfThreads; i++)
1299  {
1300  str->Filter->SetRMSChange(str->Filter->GetRMSChange() + str->Filter->m_Data[i].m_RMSChange);
1301  count += str->Filter->m_Data[i].m_Count;
1302  }
1303  if (count != 0)
1304  {
1305  str->Filter->SetRMSChange( static_cast<double>( vcl_sqrt((static_cast<float> (str->Filter->m_RMSChange))
1306  / count) ));
1307  }
1308  }
1309 
1310  // Should we stop iterating ? (in case there are too few pixels to
1311  // process for every thread)
1312  str->Filter->m_Stop= true;
1313  for (i= 0; i < str->Filter->m_NumOfThreads; i++)
1314  {
1315  if (str->Filter->m_Data[i].m_Layers[0]->Size() > 10)
1316  {
1317  str->Filter->m_Stop= false;
1318  break;
1319  }
1320  }
1321 
1322  str->Filter->InvokeEvent ( IterationEvent() );
1323  str->Filter->InvokeEvent ( ProgressEvent () );
1324  str->Filter->SetElapsedIterations (++iter);
1325  }
1326 
1327  if (ThreadId == 0)
1328  {
1329  for (i= 0; i < str->Filter->m_NumOfThreads; i++)
1330  {
1331  str->TimeStepList[i]= str->Filter->m_Data[i].TimeStep;
1332  }
1333  str->TimeStep = str->Filter->ResolveTimeStep(str->TimeStepList,
1335  }
1336 
1337  }
1338 
1339  str->Filter->WaitForAll();
1340 
1341  // The active layer is too small => stop iterating
1342  if (str->Filter->m_Stop == true)
1343  {
1344  return ITK_THREAD_RETURN_VALUE;
1345  }
1346 
1347  // Threaded Apply Update
1348  str->Filter->ThreadedApplyUpdate(str->TimeStep, ThreadId);
1349 
1350  // We only need to wait for neighbors because ThreadedCalculateChange
1351  // requires information only from the neighbors.
1352  str->Filter->SignalNeighborsAndWait(ThreadId);
1353 
1354  if (str->Filter->GetElapsedIterations()
1355  % LOAD_BALANCE_ITERATION_FREQUENCY == 0)
1356  {
1357  str->Filter->WaitForAll();
1358  // change boundaries if needed
1359  if (ThreadId == 0)
1360  {
1361  str->Filter->CheckLoadBalance();
1362  }
1363  str->Filter->WaitForAll();
1364 
1365  if (str->Filter->m_BoundaryChanged == true)
1366  {
1367  str->Filter->ThreadedLoadBalance (ThreadId);
1368  str->Filter->WaitForAll();
1369  }
1370  }
1371  }
1372 
1373  // post-process output
1374  str->Filter->GetThreadRegionSplitUniformly(ThreadId,
1375  str->Filter->m_Data[ThreadId].ThreadRegion);
1377  str->Filter->m_Data[ThreadId].ThreadRegion);
1378 
1379  return ITK_THREAD_RETURN_VALUE;
1380 }
1381 
1382 template <class TInputImage, class TOutputImage>
1383 typename
1386 ::ThreadedCalculateChange(unsigned int ThreadId)
1387 {
1388  typename FiniteDifferenceFunctionType::Pointer df = this->GetDifferenceFunction();
1390  ValueType norm_grad_phi_squared, dx_forward, dx_backward;
1391  ValueType centerValue, forwardValue, backwardValue;
1392  ValueType MIN_NORM = 1.0e-6;
1393  if (this->GetUseImageSpacing())
1394  {
1395  double minSpacing = NumericTraits<double>::max();
1396  for (unsigned int i=0; i<ImageDimension; i++)
1397  {
1398  minSpacing = vnl_math_min(minSpacing,this->GetInput()->GetSpacing()[i]);
1399  }
1400  MIN_NORM *= minSpacing;
1401  }
1402 
1403  ConstNeighborhoodIterator<OutputImageType> outputIt (df->GetRadius(), m_OutputImage,
1404  m_OutputImage->GetRequestedRegion());
1405  if ( m_BoundsCheckingActive == false )
1406  {
1407  outputIt.NeedToUseBoundaryConditionOff();
1408  }
1409  unsigned int i, center = outputIt.Size() /2;
1410 
1411  const NeighborhoodScalesType neighborhoodScales = this->GetDifferenceFunction()->ComputeNeighborhoodScales();
1412 
1413  // Calculates the update values for the active layer indicies in this
1414  // iteration. Iterates through the active layer index list, applying
1415  // the level set function to the output image (level set image) at each
1416  // index.
1417 
1418  typename LayerType::Iterator layerIt = m_Data[ThreadId].m_Layers[0]->Begin();
1419  typename LayerType::Iterator layerEnd = m_Data[ThreadId].m_Layers[0]->End();
1420 
1421  for (; layerIt != layerEnd; ++layerIt)
1422  {
1423  outputIt.SetLocation(layerIt->m_Index);
1424  // Calculate the offset to the surface from the center of this
1425  // neighborhood. This is used by some level set functions in sampling a
1426  // speed, advection, or curvature term.
1427  if (this->m_InterpolateSurfaceLocation &&
1428  (centerValue=outputIt.GetCenterPixel()) != NumericTraits<ValueType>::Zero)
1429  {
1430  // Surface is at the zero crossing, so distance to surface is:
1431  // phi(x) / norm(grad(phi)), where phi(x) is the center of the
1432  // neighborhood. The location is therefore
1433  // (i,j,k) - ( phi(x) * grad(phi(x)) ) / norm(grad(phi))^2
1434  norm_grad_phi_squared = 0.0;
1435 
1436  for (i = 0; i < static_cast<unsigned int>(ImageDimension); ++i)
1437  {
1438  forwardValue = outputIt.GetPixel(center + m_NeighborList.GetStride(i));
1439  backwardValue= outputIt.GetPixel(center - m_NeighborList.GetStride(i));
1440 
1441  if (forwardValue * backwardValue >= 0)
1442  {
1443  // 1. both neighbors have the same sign OR at least one of them is ZERO
1444  dx_forward = forwardValue - centerValue;
1445  dx_backward = centerValue - backwardValue;
1446 
1447  // take the one-sided derivative with the larger magnitude
1448  if (vnl_math_abs(dx_forward) > vnl_math_abs(dx_backward))
1449  {
1450  offset[i]= dx_forward;
1451  }
1452  else
1453  {
1454  offset[i]= dx_backward;
1455  }
1456  }
1457  else
1458  {
1459  // 2. neighbors have opposite sign
1460  // take the one-sided derivative using the neighbor that has the opposite sign w.r.t. oneself
1461  if (centerValue * forwardValue < 0)
1462  {
1463  offset[i]= forwardValue - centerValue;
1464  }
1465  else
1466  {
1467  offset[i]= centerValue - backwardValue;
1468  }
1469  }
1470 
1471  norm_grad_phi_squared += offset[i] * offset[i];
1472  }
1473 
1474  for (i = 0; i < static_cast<unsigned int>(ImageDimension); ++i)
1475  {
1476  offset[i] = ( offset[i] * outputIt.GetCenterPixel() )
1477  / (norm_grad_phi_squared + MIN_NORM);
1478  }
1479 
1480  layerIt->m_Value = df->ComputeUpdate (outputIt, (void *) m_Data[ThreadId].globalData, offset);
1481  }
1482  else // Don't do interpolation
1483  {
1484  layerIt->m_Value = df->ComputeUpdate (outputIt, (void *) m_Data[ThreadId].globalData);
1485  }
1486  }
1487 
1488  TimeStepType timeStep= df->ComputeGlobalTimeStep ((void*) m_Data[ThreadId].globalData);
1489 
1490  return timeStep;
1491 }
1492 
1493 template <class TInputImage, class TOutputImage>
1494 void
1496 ::ThreadedApplyUpdate (TimeStepType dt, unsigned int ThreadId)
1497 {
1498  this->ThreadedUpdateActiveLayerValues(dt,
1499  m_Data[ThreadId].UpList[0],
1500  m_Data[ThreadId].DownList[0],
1501  ThreadId);
1502 
1503  // We need to update histogram information (because some pixels are LEAVING
1504  // layer-0 (the active layer)
1505 
1506  this->SignalNeighborsAndWait(ThreadId);
1507 
1508  // Process status lists and update value for first inside/outside layers
1509 
1510  this->ThreadedProcessStatusList( 0, 1, 2, 1, 1, 0, ThreadId);
1511  this->ThreadedProcessStatusList( 0, 1, 1, 2, 0, 0, ThreadId);
1512 
1513  this->SignalNeighborsAndWait(ThreadId);
1514 
1515  // Update first layer value, process first layer
1516  this->ThreadedProcessFirstLayerStatusLists( 1, 0, 3, 1, 1, ThreadId);
1517  this->ThreadedProcessFirstLayerStatusLists( 1, 0, 4, 0, 1, ThreadId);
1518 
1519  // We need to update histogram information (because some pixels are ENTERING
1520  // layer-0
1521 
1522  this->SignalNeighborsAndWait(ThreadId);
1523 
1524  StatusType up_to= 1, up_search= 5;
1525  StatusType down_to= 2, down_search= 6;
1526  unsigned char j= 0, k= 1;
1527 
1528  // The 3D case: this loop is executed at least once
1529  while ( down_search < 2 * m_NumberOfLayers + 1 )
1530  {
1531  this->ThreadedProcessStatusList(j, k, up_to, up_search, 1,
1532  (up_search - 1) / 2, ThreadId);
1533  this->ThreadedProcessStatusList(j, k, down_to, down_search, 0,
1534  (up_search - 1) / 2, ThreadId);
1535 
1536  this->SignalNeighborsAndWait(ThreadId);
1537 
1538  up_to += 2;
1539  down_to += 2;
1540  up_search += 2;
1541  down_search += 2;
1542 
1543  // Swap the lists so we can re-use the empty one.
1544  j = k;
1545  k = 1 - j;
1546  }
1547  // now up_search = 2 * m_NumberOfLayers + 1 (= 7 if m_NumberOfLayers = 3)
1548  // now down_search = 2 * m_NumberOfLayers + 2 (= 8 if m_NumberOfLayers = 3)
1549 
1550  // Process the outermost inside/outside layers in the sparse field
1551  this->ThreadedProcessStatusList(j, k, up_to, m_StatusNull, 1,
1552  (up_search - 1) / 2, ThreadId);
1553  this->ThreadedProcessStatusList(j, k, down_to, m_StatusNull, 0,
1554  (up_search - 1) / 2, ThreadId);
1555 
1556  this->SignalNeighborsAndWait(ThreadId);
1557 
1558  this->ThreadedProcessOutsideList(k,(2 * m_NumberOfLayers + 1) - 2, 1,
1559  (up_search + 1) / 2, ThreadId);
1560  this->ThreadedProcessOutsideList(k,(2 * m_NumberOfLayers + 1) - 1, 0,
1561  (up_search + 1) / 2, ThreadId);
1562 
1563  if (m_OutputImage->GetImageDimension() < 3)
1564  {
1565  this->SignalNeighborsAndWait(ThreadId);
1566  }
1567 
1568  // A synchronize is NOT required here because in 3D case we have at least 7
1569  // layers, thus ThreadedProcessOutsideList() works on layers 5 & 6 while
1570  // ThreadedPropagateLayerValues() works on 0, 1, 2, 3, 4 only. => There can
1571  // NOT be any dependencies amoing different threads.
1572 
1573  // Finally, we update all of the layer VALUES (excluding the active layer,
1574  // which has already been updated)
1575  this->ThreadedPropagateLayerValues(0, 1, 3, 1, ThreadId); // first inside
1576  this->ThreadedPropagateLayerValues(0, 2, 4, 0, ThreadId); // first outside
1577 
1578  this->SignalNeighborsAndWait (ThreadId);
1579 
1580  // Update the rest of the layer values
1581  unsigned int i;
1582  for (i = 1; i < (2 * static_cast<unsigned int>(m_NumberOfLayers) + 1) - 2; i += 2)
1583  {
1584  j = i+1;
1585  this->ThreadedPropagateLayerValues(i, i+2, i+4, 1, ThreadId);
1586  this->ThreadedPropagateLayerValues(j, j+2, j+4, 0, ThreadId);
1587  this->SignalNeighborsAndWait (ThreadId);
1588  }
1589 }
1590 
1591 template <class TInputImage, class TOutputImage>
1592 void
1595  LayerType * DownList, unsigned int ThreadId)
1596 {
1597  // This method scales the update buffer values by the time step and adds
1598  // them to the active layer pixels. New values at an index which fall
1599  // outside of the active layer range trigger that index to be placed on the
1600  // "up" or "down" status list. The neighbors of any such index are then
1601  // assigned new values if they are determined to be part of the active list
1602  // for the next iteration (i.e. their values will be raised or lowered into
1603  // the active range).
1604  ValueType LOWER_ACTIVE_THRESHOLD = - (m_ConstantGradientValue / 2.0);
1605  ValueType UPPER_ACTIVE_THRESHOLD = m_ConstantGradientValue / 2.0;
1606 
1607  LayerNodeType *release_node;
1608  bool flag;
1609 
1610  IndexType centerIndex;
1611  PixelType centerValue;
1612 
1613  unsigned long int counter =0;
1614  float new_value;
1615  float rms_change_accumulator = m_ValueZero;
1616 
1617  unsigned int Neighbor_Size = m_NeighborList.GetSize();
1618 
1619  typename LayerType::Iterator layerIt
1620  = m_Data[ThreadId].m_Layers[0]->Begin();
1621  typename LayerType::Iterator layerEnd
1622  = m_Data[ThreadId].m_Layers[0]->End();
1623 
1624  while (layerIt != layerEnd )
1625  {
1626  centerIndex = layerIt->m_Index;
1627  centerValue = m_OutputImage->GetPixel(centerIndex);
1628 
1629  new_value = this->ThreadedCalculateUpdateValue(ThreadId, centerIndex, dt,
1630  centerValue, layerIt->m_Value);
1631 
1632  // If this index needs to be moved to another layer, then search its
1633  // neighborhood for indicies that need to be pulled up/down into the
1634  // active layer. Set those new active layer values appropriately,
1635  // checking first to make sure they have not been set by a more
1636  // influential neighbor.
1637 
1638  // ...But first make sure any neighbors in the active layer are not
1639  // moving to a layer in the opposite direction. This step is necessary
1640  // to avoid the creation of holes in the active layer. The fix is simply
1641  // to not change this value and leave the index in the active set.
1642 
1643  if (new_value > UPPER_ACTIVE_THRESHOLD)
1644  {
1645  // This index will move UP into a positive (outside) layer
1646  // First check for active layer neighbors moving in the opposite
1647  // direction
1648  flag = false;
1649  for (unsigned int i = 0; i < Neighbor_Size; ++i)
1650  {
1651  if (m_StatusImage->GetPixel(centerIndex + m_NeighborList.GetNeighborhoodOffset(i))
1652  == m_StatusActiveChangingDown)
1653  {
1654  flag = true;
1655  break;
1656  }
1657  }
1658  if (flag == true)
1659  {
1660  ++layerIt;
1661  continue;
1662  }
1663 
1664  rms_change_accumulator += vnl_math_sqr(static_cast<float>(new_value - centerValue ));
1665  // update the value of the pixel
1666  m_OutputImage->SetPixel (centerIndex, new_value);
1667 
1668  // Now remove this index from the active list.
1669  release_node = layerIt.GetPointer();
1670  ++layerIt;
1671 
1672  m_Data[ThreadId].m_Layers[0]->Unlink(release_node);
1673  m_Data[ThreadId].m_ZHistogram[ release_node->m_Index[m_SplitAxis] ]
1674  = m_Data[ThreadId].m_ZHistogram[ release_node->m_Index[m_SplitAxis] ] - 1;
1675 
1676  // add the release_node to status up list
1677  UpList->PushFront(release_node);
1678 
1679  //
1680  m_StatusImage->SetPixel(centerIndex, m_StatusActiveChangingUp);
1681  }
1682  else if (new_value < LOWER_ACTIVE_THRESHOLD)
1683  {
1684  // This index will move DOWN into a negative (inside) layer.
1685  // First check for active layer neighbors moving in the opposite direction
1686  flag = false;
1687  for (unsigned int i = 0; i < Neighbor_Size; ++i)
1688  {
1689  if (m_StatusImage->GetPixel(centerIndex+m_NeighborList.GetNeighborhoodOffset(i))
1690  == m_StatusActiveChangingUp)
1691  {
1692  flag = true;
1693  break;
1694  }
1695  }
1696  if (flag == true)
1697  {
1698  ++layerIt;
1699  continue;
1700  }
1701 
1702  rms_change_accumulator += vnl_math_sqr(static_cast<float>(new_value - centerValue));
1703  // update the value of the pixel
1704  m_OutputImage->SetPixel(centerIndex, new_value );
1705 
1706  // Now remove this index from the active list.
1707  release_node = layerIt.GetPointer();
1708  ++layerIt;
1709 
1710  m_Data[ThreadId].m_Layers[0]->Unlink(release_node);
1711  m_Data[ThreadId].m_ZHistogram[ release_node->m_Index[m_SplitAxis] ]
1712  = m_Data[ThreadId].m_ZHistogram[ release_node->m_Index[m_SplitAxis] ] - 1;
1713 
1714  // now add release_node to status down list
1715  DownList->PushFront(release_node);
1716 
1717  m_StatusImage->SetPixel(centerIndex, m_StatusActiveChangingDown);
1718  }
1719  else
1720  {
1721  rms_change_accumulator += vnl_math_sqr(static_cast<float>(new_value - centerValue));
1722  // update the value of the pixel
1723  m_OutputImage->SetPixel(centerIndex, new_value );
1724  ++layerIt;
1725  }
1726  ++counter;
1727  }
1728 
1729  // Determine the average change during this iteration
1730  if (counter == 0)
1731  {
1732  m_Data[ThreadId].m_RMSChange = m_ValueZero;
1733  }
1734  else
1735  {
1736  m_Data[ThreadId].m_RMSChange = rms_change_accumulator;
1737  }
1738 
1739  m_Data[ThreadId].m_Count = counter;
1740 }
1741 
1742 template <class TInputImage, class TOutputImage>
1743 void
1745 ::CopyInsertList (unsigned int ThreadId, LayerPointerType FromListPtr,
1746  LayerPointerType ToListPtr)
1747 {
1748  typename LayerType::Iterator layerIt = FromListPtr->Begin();
1749  typename LayerType::Iterator layerEnd= FromListPtr->End();
1750 
1751  LayerNodeType * nodePtr;
1752  LayerNodeType * nodeTempPtr;
1753 
1754  while (layerIt != layerEnd)
1755  {
1756  // copy the node
1757  nodePtr= layerIt.GetPointer();
1758  ++layerIt;
1759 
1760  nodeTempPtr= m_Data[ThreadId].m_LayerNodeStore->Borrow();
1761  nodeTempPtr->m_Index= nodePtr->m_Index;
1762 
1763  // insert
1764  ToListPtr->PushFront (nodeTempPtr);
1765  }
1766 }
1767 
1768 template <class TInputImage, class TOutputImage>
1769 void
1771 ::ClearList (unsigned int ThreadId, LayerPointerType ListPtr)
1772 {
1773  LayerNodeType * nodePtr;
1774 
1775  while (! ListPtr->Empty())
1776  {
1777  nodePtr= ListPtr->Front();
1778  // remove node from layer
1779  ListPtr->PopFront();
1780  // return node to node-pool
1781  m_Data[ThreadId].m_LayerNodeStore->Return (nodePtr);
1782  }
1783 }
1784 
1785 template <class TInputImage, class TOutputImage>
1786 void
1789  unsigned int InOrOut, unsigned int BufferLayerNumber)
1790 {
1791  if (ThreadId != 0)
1792  {
1793  CopyInsertList(ThreadId,
1794  m_Data[this->GetThreadNumber(m_Boundary[ThreadId-1])].m_InterNeighborNodeTransferBufferLayers[InOrOut][BufferLayerNumber][ThreadId],
1795  List);
1796  }
1797 
1798  if (m_Boundary[ThreadId] != m_ZSize - 1)
1799  {
1800  CopyInsertList(ThreadId,
1801  m_Data[this->GetThreadNumber (m_Boundary[ThreadId] + 1)].m_InterNeighborNodeTransferBufferLayers[InOrOut][BufferLayerNumber][ThreadId],
1802  List);
1803  }
1804 }
1805 
1806 template <class TInputImage, class TOutputImage>
1807 void
1809 ::ClearInterNeighborNodeTransferBufferLayers (unsigned int ThreadId, unsigned int InOrOut,
1810  unsigned int BufferLayerNumber)
1811 {
1812  for (unsigned int i= 0; i < m_NumOfThreads; i++)
1813  {
1814  ClearList(ThreadId, m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[InOrOut][BufferLayerNumber][i]);
1815  }
1816 }
1817 
1818 template <class TInputImage, class TOutputImage>
1819 void
1821 ::ThreadedProcessFirstLayerStatusLists (unsigned int InputLayerNumber, unsigned int OutputLayerNumber,
1822  StatusType SearchForStatus,
1823  unsigned int InOrOut, unsigned int BufferLayerNumber, unsigned int ThreadId)
1824 {
1825  LayerNodeType* nodePtr;
1826  StatusType from, neighbor_status;
1827  ValueType value, value_temp, delta;
1828  bool found_neighbor_flag;
1829 
1830  IndexType center_index, n_index;
1831 
1832  unsigned int neighbor_Size = m_NeighborList.GetSize();
1833  LayerPointerType InputList, OutputList;
1834 
1835  //InOrOut == 1, inside, more negative, uplist
1836  //InOrOut == 0, outside
1837  if (InOrOut == 1)
1838  {
1839  delta = - m_ConstantGradientValue;
1840  from = 2;
1841  InputList = m_Data[ThreadId].UpList[InputLayerNumber];
1842  OutputList = m_Data[ThreadId].UpList[OutputLayerNumber];
1843  }
1844  else
1845  {
1846  delta = m_ConstantGradientValue;
1847  from = 1;
1848  InputList = m_Data[ThreadId].DownList[InputLayerNumber];
1849  OutputList = m_Data[ThreadId].DownList[OutputLayerNumber];
1850  }
1851 
1852  // 1. nothing to clear
1853  // 2. make a copy of the node on the
1854  // m_InterNeighborNodeTransferBufferLayers[InOrOut][BufferLayerNumber - 1][i]
1855  // for all neighbors i ... and insert it in one's own InputList
1856  CopyInsertInterNeighborNodeTransferBufferLayers(ThreadId, InputList, InOrOut,
1857  BufferLayerNumber - 1);
1858 
1859  typename LayerType::Iterator layerIt = InputList->Begin();
1860  typename LayerType::Iterator layerEnd = InputList->End();
1861  while (layerIt != layerEnd)
1862  {
1863  nodePtr = layerIt.GetPointer();
1864  ++layerIt;
1865 
1866  center_index = nodePtr->m_Index;
1867 
1868  // remove node from InputList
1869  InputList->Unlink(nodePtr);
1870 
1871  // check if this is not a duplicate pixel in the InputList
1872  // In the case when the thread boundaries differ by just 1 pixel some
1873  // nodes may get added twice in the InputLists Even if the boundaries are
1874  // more than 1 pixel wide the *_shape_* of the layer may allow this to
1875  // happen. Solution: If a pixel comes multiple times than we would find
1876  // that the Status image would already be reflecting the new status after
1877  // the pixel was encountered the first time
1878  if (m_StatusImage->GetPixel(center_index) == 0)
1879  {
1880  // duplicate node => return it to the node pool
1881  m_Data[ThreadId].m_LayerNodeStore->Return (nodePtr);
1882  continue;
1883  }
1884 
1885  // set status to zero
1886  m_StatusImage->SetPixel(center_index, 0);
1887  // add node to the layer-0
1888  m_Data[ThreadId].m_Layers[0]->PushFront(nodePtr);
1889 
1890  m_Data[ThreadId].m_ZHistogram[ nodePtr->m_Index[m_SplitAxis] ]
1891  = m_Data[ThreadId].m_ZHistogram[ nodePtr->m_Index[m_SplitAxis] ] + 1;
1892 
1893  value = m_OutputImage->GetPixel(center_index);
1894  found_neighbor_flag = false;
1895  for (unsigned int i = 0; i < neighbor_Size; ++i)
1896  {
1897  n_index = center_index + m_NeighborList.GetNeighborhoodOffset(i);
1898  neighbor_status = m_StatusImage->GetPixel(n_index);
1899 
1900  // Have we bumped up against the boundary? If so, turn on bounds checking.
1901  if ( neighbor_status == m_StatusBoundaryPixel )
1902  {
1903  m_BoundsCheckingActive = true;
1904  }
1905 
1906  if (neighbor_status == from)
1907  {
1908  value_temp = m_OutputImage->GetPixel(n_index);
1909 
1910  if (found_neighbor_flag == false)
1911  {
1912  value = value_temp;
1913  }
1914  else
1915  {
1916  if (vnl_math_abs(value_temp+delta) < vnl_math_abs(value+delta))
1917  {
1918  // take the value closest to zero
1919  value= value_temp;
1920  }
1921  }
1922  found_neighbor_flag = true;
1923  }
1924 
1925  if (neighbor_status == SearchForStatus)
1926  {
1927  // mark this pixel so we MAY NOT add it twice
1928  // This STILL DOES NOT GUARANTEE RACE CONDITIONS BETWEEN THREADS. This
1929  // is handled at the next stage
1930  m_StatusImage->SetPixel(n_index, m_StatusChanging);
1931 
1932  unsigned int tmpId = this->GetThreadNumber(n_index[m_SplitAxis]);
1933 
1934  nodePtr = m_Data[ThreadId].m_LayerNodeStore->Borrow();
1935  nodePtr->m_Index = n_index;
1936 
1937  if (tmpId != ThreadId)
1938  {
1939  m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[InOrOut][BufferLayerNumber][tmpId]->PushFront(nodePtr);
1940  }
1941  else
1942  {
1943  OutputList->PushFront(nodePtr);
1944  }
1945  }
1946  }
1947  m_OutputImage->SetPixel(center_index, value + delta );
1948  // This function can be overridden in the derived classes to process pixels entering the active layer.
1949  this->ThreadedProcessPixelEnteringActiveLayer (center_index, value + delta, ThreadId);
1950  }
1951 }
1952 
1953 template <class TInputImage, class TOutputImage>
1954 void
1957  const ValueType itkNotUsed(value),
1958  const unsigned int itkNotUsed(ThreadId))
1959 {
1960  // This function can be overridden in the derived classes to process pixels entering the active layer.
1961  return;
1962 }
1963 
1964 template <class TInputImage, class TOutputImage>
1965 void
1967 ::ThreadedProcessStatusList (unsigned int InputLayerNumber, unsigned int OutputLayerNumber,
1968  StatusType ChangeToStatus, StatusType SearchForStatus,
1969  unsigned int InOrOut, unsigned int BufferLayerNumber, unsigned int ThreadId)
1970 {
1971  unsigned int i;
1972  LayerNodeType* nodePtr;
1973  StatusType neighbor_status;
1974 
1975  IndexType center_index, n_index;
1976 
1977  LayerPointerType InputList, OutputList;
1978 
1979  // Push each index in the input list into its appropriate status layer
1980  // (ChangeToStatus) and update the status image value at that index.
1981  // Also examine the neighbors of the index to determine which need to go onto
1982  // the output list (search for SearchForStatus).
1983  if (InOrOut == 1)
1984  {
1985  InputList = m_Data[ThreadId].UpList[InputLayerNumber];
1986  OutputList = m_Data[ThreadId].UpList[OutputLayerNumber];
1987  }
1988  else
1989  {
1990  InputList = m_Data[ThreadId].DownList[InputLayerNumber];
1991  OutputList = m_Data[ThreadId].DownList[OutputLayerNumber];
1992  }
1993 
1994  // 1. clear one's own
1995  // m_InterNeighborNodeTransferBufferLayers[InOrOut][BufferLayerNumber - 2][i]
1996  // for all threads i.
1997  if (BufferLayerNumber >= 2)
1998  {
1999  ClearInterNeighborNodeTransferBufferLayers(ThreadId, InOrOut,
2000  BufferLayerNumber - 2);
2001  }
2002  // SPECIAL CASE: clear one's own
2003  // m_InterNeighborNodeTransferBufferLayers[InOrOut][m_NumberOfLayers][i] for
2004  // all threads i
2005  if (BufferLayerNumber == 0)
2006  {
2007  ClearInterNeighborNodeTransferBufferLayers(ThreadId, InOrOut, m_NumberOfLayers);
2008  }
2009  // obtain the pixels (from last iteration) that were given to you from other
2010  // (neighboring) threads 2. make a copy of the node on the
2011  // m_InterNeighborNodeTransferBufferLayers[InOrOut][LastLayer - 1][i] for all
2012  // thread neighbors i ... ... and insert it in one's own InputList
2013  if (BufferLayerNumber > 0)
2014  {
2015  CopyInsertInterNeighborNodeTransferBufferLayers(ThreadId, InputList,
2016  InOrOut, BufferLayerNumber - 1);
2017  }
2018 
2019  unsigned int neighbor_size = m_NeighborList.GetSize();
2020  while ( ! InputList->Empty() )
2021  {
2022  nodePtr = InputList->Front();
2023  center_index = nodePtr->m_Index;
2024 
2025  InputList->PopFront();
2026 
2027  // Check if this is not a duplicate pixel in the InputList.
2028  // Solution: If a pixel comes multiple times than we would find that the
2029  // Status image would already be reflecting
2030  // the new status after the pixel was encountered the first time
2031  if ((BufferLayerNumber != 0)
2032  && (m_StatusImage->GetPixel(center_index) == ChangeToStatus))
2033  {
2034  // duplicate node => return it to the node pool
2035  m_Data[ThreadId].m_LayerNodeStore->Return (nodePtr);
2036 
2037  continue;
2038  }
2039 
2040  // add to layer
2041  m_Data[ThreadId].m_Layers[ChangeToStatus]->PushFront (nodePtr);
2042  // change the status
2043  m_StatusImage->SetPixel(center_index, ChangeToStatus);
2044 
2045  for (i = 0; i < neighbor_size; ++i)
2046  {
2047  n_index = center_index + m_NeighborList.GetNeighborhoodOffset(i);
2048 
2049  neighbor_status = m_StatusImage->GetPixel(n_index);
2050 
2051  // Have we bumped up against the boundary? If so, turn on bounds checking.
2052  if ( neighbor_status == m_StatusBoundaryPixel )
2053  {
2054  m_BoundsCheckingActive = true;
2055  }
2056 
2057  if (neighbor_status == SearchForStatus)
2058  {
2059  // mark this pixel so we MAY NOT add it twice
2060  // This STILL DOES NOT AVOID RACE CONDITIONS BETWEEN THREADS (This is
2061  // handled at the next stage)
2062  m_StatusImage->SetPixel(n_index, m_StatusChanging);
2063 
2064  unsigned int tmpId = this->GetThreadNumber (n_index[m_SplitAxis]);
2065 
2066  nodePtr = m_Data[ThreadId].m_LayerNodeStore->Borrow();
2067  nodePtr->m_Index = n_index;
2068 
2069  if (tmpId != ThreadId)
2070  {
2071  m_Data[ThreadId].m_InterNeighborNodeTransferBufferLayers[InOrOut][BufferLayerNumber][tmpId]->PushFront(nodePtr);
2072  }
2073  else
2074  {
2075  OutputList->PushFront(nodePtr);
2076  }
2077  }
2078  }
2079  }
2080 }
2081 
2082 template <class TInputImage, class TOutputImage>
2083 void
2085 ::ThreadedProcessOutsideList (unsigned int InputLayerNumber, StatusType ChangeToStatus,
2086  unsigned int InOrOut, unsigned int BufferLayerNumber, unsigned int ThreadId)
2087 {
2088  LayerPointerType OutsideList;
2089  if (InOrOut == 1)
2090  {
2091  OutsideList= m_Data[ThreadId].UpList [InputLayerNumber];
2092  }
2093  else
2094  {
2095  OutsideList= m_Data[ThreadId].DownList[InputLayerNumber];
2096  }
2097 
2098  // obtain the pixels (from last iteration of ThreadedProcessStatusList() )
2099  // that were given to you from other (neighboring) threads
2100  // 1. clear one's own
2101  // m_InterNeighborNodeTransferBufferLayers[InOrOut][BufferLayerNumber - 2][i]
2102  // for all threads i.
2103  ClearInterNeighborNodeTransferBufferLayers(ThreadId, InOrOut, BufferLayerNumber - 2);
2104 
2105  // 2. make a copy of the node on the
2106  // m_InterNeighborNodeTransferBufferLayers[InOrOut][LastLayer - 1][i] for
2107  // all thread neighbors i ... ... and insert it in one's own InoutList
2108  CopyInsertInterNeighborNodeTransferBufferLayers(ThreadId, OutsideList, InOrOut,
2109  BufferLayerNumber - 1);
2110 
2111  // Push each index in the input list into its appropriate status layer
2112  // (ChangeToStatus) and ... ... update the status image value at that index
2113  LayerNodeType* nodePtr;
2114  while ( ! OutsideList->Empty() )
2115  {
2116  nodePtr = OutsideList->Front();
2117  OutsideList->PopFront();
2118 
2119  m_StatusImage->SetPixel(nodePtr->m_Index, ChangeToStatus);
2120  m_Data[ThreadId].m_Layers[ChangeToStatus]->PushFront (nodePtr);
2121  }
2122 }
2123 
2124 template <class TInputImage, class TOutputImage>
2125 void
2128  unsigned int InOrOut, unsigned int ThreadId)
2129 {
2130  ValueType value, value_temp, delta;
2131  bool found_neighbor_flag;
2132  typename LayerType::Iterator toIt;
2133  typename LayerType::Iterator toEnd;
2134  LayerNodeType* nodePtr;
2135  StatusType past_end = static_cast<StatusType>( m_Layers.size() ) - 1;
2136 
2137  // Are we propagating values inward (more negative) or outward (more positive)?
2138  if (InOrOut == 1)
2139  {
2140  delta = - m_ConstantGradientValue;
2141  }
2142  else
2143  {
2144  delta = m_ConstantGradientValue;
2145  }
2146 
2147  unsigned int Neighbor_Size = m_NeighborList.GetSize();
2148  toIt = m_Data[ThreadId].m_Layers[to]->Begin();
2149  toEnd = m_Data[ThreadId].m_Layers[to]->End();
2150 
2151  IndexType centerIndex, nIndex;
2152  StatusType centerStatus, nStatus;
2153 
2154  while ( toIt != toEnd )
2155  {
2156  centerIndex = toIt->m_Index;
2157 
2158  centerStatus = m_StatusImage->GetPixel(centerIndex);
2159 
2160  if (centerStatus != to)
2161  {
2162  // delete nodes NOT deleted earlier
2163  nodePtr = toIt.GetPointer();
2164  ++toIt;
2165 
2166  // remove the node from the layer
2167  m_Data[ThreadId].m_Layers[to]->Unlink( nodePtr );
2168  m_Data[ThreadId].m_LayerNodeStore->Return( nodePtr );
2169  continue;
2170  }
2171 
2172  value = m_ValueZero;
2173  found_neighbor_flag = false;
2174  for (unsigned int i = 0; i < Neighbor_Size; ++i)
2175  {
2176  nIndex = centerIndex + m_NeighborList.GetNeighborhoodOffset(i);
2177  nStatus = m_StatusImage->GetPixel(nIndex);
2178  // If this neighbor is in the "from" list, compare its absolute value
2179  // to any previous values found in the "from" list. Keep only the
2180  // value with the smallest magnitude.
2181 
2182  if (nStatus == from)
2183  {
2184  value_temp = m_OutputImage->GetPixel(nIndex);
2185 
2186  if (found_neighbor_flag == false)
2187  {
2188  value = value_temp;
2189  }
2190  else
2191  {
2192  if (vnl_math_abs(value_temp+delta) < vnl_math_abs(value+delta))
2193  {
2194  // take the value closest to zero
2195  value= value_temp;
2196  }
2197  }
2198  found_neighbor_flag = true;
2199  }
2200  }
2201  if (found_neighbor_flag == true)
2202  {
2203  // Set the new value using the smallest magnitude found in our "from"
2204  // neighbors
2205  m_OutputImage->SetPixel (centerIndex, value + delta);
2206  ++toIt;
2207  }
2208  else
2209  {
2210  // Did not find any neighbors on the "from" list, then promote this
2211  // node. A "promote" value past the end of my sparse field size
2212  // means delete the node instead. Change the status value in the
2213  // status image accordingly.
2214  nodePtr = toIt.GetPointer();
2215  ++toIt;
2216  m_Data[ThreadId].m_Layers[to]->Unlink( nodePtr );
2217 
2218  if ( promote > past_end )
2219  {
2220  m_Data[ThreadId].m_LayerNodeStore->Return( nodePtr );
2221  m_StatusImage->SetPixel(centerIndex, m_StatusNull);
2222  }
2223  else
2224  {
2225  m_Data[ThreadId].m_Layers[promote]->PushFront( nodePtr );
2226  m_StatusImage->SetPixel(centerIndex, promote);
2227  }
2228  }
2229  }
2230 }
2231 
2232 template<class TInputImage, class TOutputImage>
2233 void
2236 {
2237  unsigned int i, j;
2238 
2239  // This parameter defines a degree of unbalancedness of the load among threads.
2240  const float MAX_PIXEL_DIFFERENCE_PERCENT = 0.025;
2241  m_BoundaryChanged = false;
2242 
2243  // work load division based on the nodes on the active layer (layer-0)
2244  long int min = NumericTraits<long int>::max();
2245  long int max = 0;
2246  long int total= 0; // the total nodes in the active layer of the surface
2247 
2248  for (i = 0; i < m_NumOfThreads; i++)
2249  {
2250  long int count = m_Data[i].m_Layers[0]->Size();
2251  total += count;
2252  if (min > count) min = count;
2253  if (max < count) max = count;
2254  }
2255 
2256  if (max - min < MAX_PIXEL_DIFFERENCE_PERCENT * total / m_NumOfThreads)
2257  {
2258  // if the difference between max and min is NOT even x% of the average
2259  // nodes in the thread layers then no need to change the boundaries next
2260  return;
2261  }
2262 
2263  // Change the boundaries --------------------------
2264 
2265  // compute the global histogram from the individual histograms
2266  for (i= 0; i < m_NumOfThreads; i++)
2267  {
2268  for (j= (i == 0 ? 0 : m_Boundary[i-1] + 1); j <= m_Boundary[i]; j++)
2269  {
2270  m_GlobalZHistogram[j] = m_Data[i].m_ZHistogram[j];
2271  }
2272  }
2273 
2274  // compute the cumulative frequency distribution using the histogram
2275  m_ZCumulativeFrequency[0] = m_GlobalZHistogram[0];
2276  for (i= 1; i < m_ZSize; i++)
2277  {
2278  m_ZCumulativeFrequency[i] = m_ZCumulativeFrequency[i-1] + m_GlobalZHistogram[i];
2279  }
2280 
2281  // now define the boundaries
2282  m_Boundary[m_NumOfThreads - 1] = m_ZSize - 1; // special case: the last bound
2283 
2284  for (i= 0; i < m_NumOfThreads - 1; i++)
2285  {
2286  // compute m_Boundary[i]
2287  float cutOff= 1.0f * (i+1) * m_ZCumulativeFrequency[m_ZSize-1] / m_NumOfThreads;
2288 
2289  // find the position in the cumulative freq dist where this cutoff is met
2290  for (j= (i == 0 ? 0 : m_Boundary[i-1]); j < m_ZSize; j++)
2291  {
2292  if (cutOff > m_ZCumulativeFrequency[j])
2293  {
2294  continue;
2295  }
2296  else
2297  {
2298  // do some optimization !
2299  // go further FORWARD and find the first index (k) in the cumulative
2300  // freq distribution s.t. m_ZCumulativeFrequency[k] !=
2301  // m_ZCumulativeFrequency[j]. This is to be done because if we have a
2302  // flat patch in the cum freq dist then ... . we can choose a bound
2303  // midway in that flat patch
2304  unsigned int k;
2305  for (k= 1; j+k < m_ZSize; k++)
2306  {
2307  if (m_ZCumulativeFrequency[j+k] != m_ZCumulativeFrequency[j])
2308  {
2309  break;
2310  }
2311  }
2312 
2313  // if ALL new boundaries same as the original then NO NEED TO DO
2314  // ThreadedLoadBalance() next !!!
2315  unsigned int newBoundary= static_cast<unsigned int> ((j + (j+k)) / 2);
2316  if (newBoundary != m_Boundary[i])
2317  {
2318  //
2319  m_BoundaryChanged= true;
2320  m_Boundary[i]= newBoundary;
2321  }
2322  break;
2323  }
2324  }
2325  }
2326 
2327  if (m_BoundaryChanged == false)
2328  {
2329  return;
2330  }
2331 
2332  // Reset the individual histograms to reflect the new distrbution
2333  // Also reset the mapping from the Z value --> the thread number i.e. m_MapZToThreadNumber[]
2334  for (i= 0; i < m_NumOfThreads; i++)
2335  {
2336  if (i != 0)
2337  {
2338  for (j= 0; j <= m_Boundary[i-1]; j++)
2339  {
2340  m_Data[i].m_ZHistogram[j] = 0;
2341  }
2342  }
2343 
2344  for (j= (i == 0 ? 0 : m_Boundary[i-1] + 1); j <= m_Boundary[i]; j++)
2345  {
2346  // this Z histogram value should be given to thread-i
2347  m_Data[i].m_ZHistogram[j] = m_GlobalZHistogram[j];
2348 
2349  // this Z belongs to the region associated with thread-i
2350  m_MapZToThreadNumber[j]= i;
2351  }
2352 
2353  for (j= m_Boundary[i] + 1; j < m_ZSize; j++)
2354  {
2355  m_Data[i].m_ZHistogram[j] = 0;
2356  }
2357  }
2358 }
2359 
2360 template<class TInputImage, class TOutputImage>
2361 void
2363 ::ThreadedLoadBalance(unsigned int ThreadId)
2364 {
2365  // the situation at this point in time::
2366  // the OPTIMAL boundaries (that divide work equally) have changed but ...
2367  // the thread data lags behind the boundaries (it is still following the old
2368  // boundaries) the m_ZHistogram[], however, reflects the latest optimal
2369  // boundaries
2370 
2371  // The task:
2372  // 1. Every thread checks for pixels with itself that should NOT be with
2373  // itself anymore (because of the changed boundaries).
2374  // These pixels are now put in extra "buckets" for other threads to grab
2375  // 2. WaitForAll ().
2376  // 3. Every thread grabs those pixels, from every other thread, that come
2377  // within its boundaries (from the extra buckets).
2378 
2380  // 1.
2381 
2382  unsigned int i, j;
2383  // cleanup the layers first
2384  for (i = 0; i < 2 * static_cast<unsigned int>(m_NumberOfLayers) + 1; i++)
2385  {
2386  for (j= 0; j < m_NumOfThreads; j++)
2387  {
2388  if (j == ThreadId)
2389  {
2390  // a thread does NOT pass nodes to istelf
2391  continue;
2392  }
2393 
2394  ClearList(ThreadId, m_Data[ThreadId].m_LoadTransferBufferLayers[i][j]);
2395  }
2396  }
2397 
2398  LayerNodeType * nodePtr;
2399  for (i = 0; i < 2 * static_cast<unsigned int>(m_NumberOfLayers) + 1; i++) // for all layers
2400  {
2401  typename LayerType::Iterator layerIt = m_Data[ThreadId].m_Layers[i]->Begin();
2402  typename LayerType::Iterator layerEnd = m_Data[ThreadId].m_Layers[i]->End();
2403 
2404  while (layerIt != layerEnd)
2405  {
2406  nodePtr= layerIt.GetPointer();
2407  ++layerIt;
2408 
2409  // use the latest (just updated in CheckLoadBalance) boundaries to
2410  // determine to which thread region does the pixel now belong
2411  unsigned int tmpId = this->GetThreadNumber(nodePtr->m_Index[m_SplitAxis]);
2412 
2413  if (tmpId != ThreadId) // this pixel no longer belongs to this thread
2414  {
2415  // remove from the layer
2416  m_Data[ThreadId].m_Layers[i]->Unlink(nodePtr);
2417 
2418  // insert temporarily into the special-layers TO BE LATER taken by the
2419  // other thread
2420  // NOTE: What is pushed is a node belonging to the LayerNodeStore of
2421  // ThreadId. This is deleted later (during the start of the next
2422  // SpecialIteration). What is taken by the other thread is NOT this
2423  // node BUT a copy of it.
2424  m_Data[ThreadId].m_LoadTransferBufferLayers[i][tmpId]->PushFront(nodePtr);
2425  }
2426  }
2427  }
2428 
2430  // 2.
2431  this->WaitForAll();
2432 
2434  // 3.
2435  for (i = 0; i < 2 * static_cast<unsigned int>(m_NumberOfLayers) + 1; i++)
2436  {
2437  // check all other threads
2438  for (j= 0; j < m_NumOfThreads; j++)
2439  {
2440  if (j == ThreadId)
2441  {
2442  continue; // exclude oneself
2443  }
2444 
2445  CopyInsertList(ThreadId, m_Data[j].m_LoadTransferBufferLayers[i][ThreadId],
2446  m_Data[ThreadId].m_Layers[i]);
2447  }
2448  }
2449 }
2450 
2451 template<class TInputImage, class TOutputImage>
2452 void
2454 ::GetThreadRegionSplitByBoundary(unsigned int ThreadId, ThreadRegionType & ThreadRegion)
2455 {
2456  // Initialize the ThreadRegion to the output's requested region
2457  ThreadRegion = m_OutputImage->GetRequestedRegion();
2458 
2459  // compute lower bound on the index
2460  typename TOutputImage::IndexType threadRegionIndex = ThreadRegion.GetIndex();
2461  if (ThreadId != 0)
2462  {
2463  if (m_Boundary[ThreadId-1] < m_Boundary[m_NumOfThreads -1])
2464  {
2465  threadRegionIndex[m_SplitAxis] += m_Boundary[ThreadId-1] + 1;
2466  }
2467  else
2468  {
2469  threadRegionIndex[m_SplitAxis] += m_Boundary[ThreadId-1];
2470  }
2471  }
2472 
2473  ThreadRegion.SetIndex (threadRegionIndex);
2474 
2475  // compute the size of the region
2476  typename TOutputImage::SizeType threadRegionSize = ThreadRegion.GetSize();
2477  threadRegionSize[m_SplitAxis] = (ThreadId == 0
2478  ? (m_Boundary[0] + 1)
2479  : m_Boundary[ThreadId] - m_Boundary[ThreadId-1]);
2480  ThreadRegion.SetSize(threadRegionSize);
2481 }
2482 
2483 template<class TInputImage, class TOutputImage>
2484 void
2486 ::GetThreadRegionSplitUniformly(unsigned int ThreadId, ThreadRegionType & ThreadRegion)
2487 {
2488  // Initialize the ThreadRegion to the output's requested region
2489  ThreadRegion = m_OutputImage->GetRequestedRegion();
2490 
2491  typename TOutputImage::IndexType threadRegionIndex = ThreadRegion.GetIndex();
2492  threadRegionIndex[m_SplitAxis]
2493  += static_cast<unsigned int> (1.0 * ThreadId * m_ZSize / m_NumOfThreads);
2494  ThreadRegion.SetIndex(threadRegionIndex);
2495 
2496  typename TOutputImage::SizeType threadRegionSize = ThreadRegion.GetSize();
2497 
2498  // compute lower bound on the index and the size of the region
2499  if (ThreadId < m_NumOfThreads - 1) // this is NOT the last thread
2500  {
2501  threadRegionSize [m_SplitAxis] = static_cast<unsigned int> (1.0 * (ThreadId+1) * m_ZSize / m_NumOfThreads)
2502  - static_cast<unsigned int> (1.0 * ThreadId * m_ZSize / m_NumOfThreads);
2503  }
2504  else
2505  {
2506  threadRegionSize [m_SplitAxis] = m_ZSize
2507  - static_cast<unsigned int> (1.0 * ThreadId * m_ZSize / m_NumOfThreads);
2508  }
2509  ThreadRegion.SetSize(threadRegionSize);
2510 }
2511 
2512 template<class TInputImage, class TOutputImage>
2513 void
2516 {
2517  // Assign background pixels INSIDE the sparse field layers to a new level set
2518  // with value less than the innermost layer. Assign background pixels
2519  // OUTSIDE the sparse field layers to a new level set with value greater than
2520  // the outermost layer.
2521  const ValueType max_layer = static_cast<ValueType>(m_NumberOfLayers);
2522  const ValueType outside_value = (max_layer+1) * m_ConstantGradientValue;
2523  const ValueType inside_value = -(max_layer+1) * m_ConstantGradientValue;
2524 
2525  ImageRegionConstIterator <StatusImageType> statusIt(m_StatusImage, regionToProcess);
2526  ImageRegionIterator <OutputImageType> outputIt(m_OutputImage, regionToProcess);
2527 
2528  for (outputIt = outputIt.Begin(), statusIt = statusIt.Begin();
2529  ! outputIt.IsAtEnd(); ++outputIt, ++statusIt)
2530  {
2531  if (statusIt.Get() == m_StatusNull || statusIt.Get() == m_StatusBoundaryPixel)
2532  {
2533  if (outputIt.Get() > m_ValueZero)
2534  {
2535  outputIt.Set (outside_value);
2536  }
2537  else
2538  {
2539  outputIt.Set (inside_value);
2540  }
2541  }
2542  }
2543 }
2544 
2545 template<class TInputImage, class TOutputImage>
2546 unsigned int
2548 ::GetThreadNumber (unsigned int splitAxisValue)
2549 {
2550  return ( m_MapZToThreadNumber[splitAxisValue] );
2551 }
2552 
2553 template<class TInputImage, class TOutputImage>
2554 void
2556 ::SignalNeighborsAndWait (unsigned int ThreadId)
2557 {
2558  // This is the case when a thread has no pixels to process
2559  // This case is analogous to NOT using that thread at all
2560  // Hence this thread does not need to signal / wait for any other neighbor
2561  // thread during the iteration
2562  if (ThreadId != 0)
2563  {
2564  if (m_Boundary[ThreadId-1] == m_Boundary[ThreadId])
2565  {
2566  m_Data[ThreadId].m_SemaphoreArrayNumber= 1
2567  - m_Data[ThreadId].m_SemaphoreArrayNumber;
2568  return;
2569  }
2570  }
2571 
2572  unsigned int lastThreadId = m_NumOfThreads - 1;
2573  if (lastThreadId == 0)
2574  {
2575  return; // only 1 thread => no need to wait
2576  }
2577 
2578  // signal neighbors that work is done
2579  if (ThreadId != 0) // not the first thread
2580  {
2581  this->SignalNeighbor(m_Data[ThreadId].m_SemaphoreArrayNumber,
2582  this->GetThreadNumber ( m_Boundary[ThreadId-1] ));
2583  }
2584  if (m_Boundary[ThreadId] != m_ZSize - 1) // not the last thread
2585  {
2586  this->SignalNeighbor (m_Data[ThreadId].m_SemaphoreArrayNumber,
2587  this->GetThreadNumber ( m_Boundary[ThreadId] + 1 ));
2588  }
2589 
2590  // wait for signal from neighbors signifying that their work is done
2591  if ((ThreadId == 0) || (m_Boundary[ThreadId] == m_ZSize - 1))
2592  {
2593  // do it just once for the first and the last threads because they share
2594  // just 1 boundary (just 1 neighbor)
2595  this->WaitForNeighbor (m_Data[ThreadId].m_SemaphoreArrayNumber, ThreadId);
2596  m_Data[ThreadId].m_SemaphoreArrayNumber= 1 - m_Data[ThreadId].m_SemaphoreArrayNumber;
2597  }
2598  else
2599  {
2600  // do twice because share 2 boundaries with neighbors
2601  this->WaitForNeighbor (m_Data[ThreadId].m_SemaphoreArrayNumber, ThreadId);
2602  this->WaitForNeighbor (m_Data[ThreadId].m_SemaphoreArrayNumber, ThreadId);
2603 
2604  m_Data[ThreadId].m_SemaphoreArrayNumber= 1 - m_Data[ThreadId].m_SemaphoreArrayNumber;
2605  }
2606 }
2607 
2608 template<class TInputImage, class TOutputImage>
2609 void
2611 ::SignalNeighbor(unsigned int SemaphoreArrayNumber, unsigned int ThreadId)
2612 {
2613  m_Data[ThreadId].m_Semaphore[SemaphoreArrayNumber]->Up();
2614 }
2615 
2616 template<class TInputImage, class TOutputImage>
2617 void
2619 ::WaitForNeighbor(unsigned int SemaphoreArrayNumber, unsigned int ThreadId)
2620 {
2621  m_Data[ThreadId].m_Semaphore[SemaphoreArrayNumber]->Down();
2622 }
2623 
2624 template<class TInputImage, class TOutputImage>
2625 void
2628 {
2629  m_Barrier->Wait();
2630 }
2631 
2632 template<class TInputImage, class TOutputImage>
2633 void
2635 ::PrintSelf(std::ostream& os, Indent indent) const
2636 {
2637  Superclass::PrintSelf(os, indent);
2638 
2639  unsigned int i;
2640  os << indent << "m_NumberOfLayers: " << NumericTraits<StatusType>::PrintType(this->GetNumberOfLayers()) << std::endl;
2641  os << indent << "m_IsoSurfaceValue: " << this->GetIsoSurfaceValue() << std::endl;
2642  os << indent << "m_LayerNodeStore: " << m_LayerNodeStore;
2643  unsigned int ThreadId;
2644  for (ThreadId=0; ThreadId < m_NumOfThreads; ThreadId++)
2645  {
2646  os << indent << "ThreadId: " << ThreadId << std::endl;
2647  if (m_Data != 0)
2648  {
2649  for (i=0; i < m_Data[ThreadId].m_Layers.size(); i++)
2650  {
2651  os << indent << "m_Layers[" << i << "]: size="
2652  << m_Data[ThreadId].m_Layers[i]->Size() << std::endl;
2653  os << indent << m_Data[ThreadId].m_Layers[i];
2654  }
2655  }
2656  }
2657 }
2658 } // end namespace itk
2659 
2660 #endif

Generated at Sat Feb 2 2013 23:58:33 for Orfeo Toolbox with doxygen 1.8.1.1