Orfeo Toolbox  3.16
itkStatisticsAlgorithm.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkStatisticsAlgorithm.txx,v $
5  Language: C++
6  Date: $Date: 2010-01-22 22:16:14 $
7  Version: $Revision: 1.26 $
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 __itkStatisticsAlgorithm_txx
18 #define __itkStatisticsAlgorithm_txx
19 
20 #include "itkStatisticsAlgorithm.h"
21 #include "itkNumericTraits.h"
22 
23 namespace itk {
24 namespace Statistics {
25 
26 template< class TSize >
27 inline TSize FloorLog(TSize size)
28 {
29  TSize k;
30 
31  for (k = 0; size != 1; size >>= 1)
32  {
33  ++k;
34  }
35 
36  return k;
37 }
38 
44 template< class TSubsample >
45 inline int Partition(TSubsample* sample,
46  unsigned int activeDimension,
47  int beginIndex, int endIndex,
48  const typename TSubsample::MeasurementType partitionValue)
49 {
50  typedef typename TSubsample::MeasurementType MeasurementType;
51 
52  int moveToFrontIndex = beginIndex;
53  int moveToBackIndex = endIndex-1;
54 
55  //
56  // Move to the back all entries whose activeDimension component is equal to
57  // the partitionValue.
58  //
59  while( moveToFrontIndex < moveToBackIndex )
60  {
61  //
62  // Find the first element (from the back) that is in the wrong side of the partition.
63  //
64  while( moveToBackIndex >= beginIndex )
65  {
66  if( sample->GetMeasurementVectorByIndex(moveToBackIndex)[activeDimension] != partitionValue )
67  {
68  break;
69  }
70  moveToBackIndex--;
71  }
72 
73  //
74  // Find the first element (from the front) that is in the wrong side of the partition.
75  //
76  while( moveToFrontIndex < endIndex )
77  {
78  if( sample->GetMeasurementVectorByIndex(moveToFrontIndex)[activeDimension] == partitionValue )
79  {
80  break;
81  }
82  moveToFrontIndex++;
83  }
84 
85  if( moveToFrontIndex < moveToBackIndex )
86  {
87  //
88  // Swap them to place them in the correct side of the partition
89  //
90  sample->Swap( moveToBackIndex, moveToFrontIndex );
91  }
92  }
93 
94 
95  //
96  // Now, ignore the section at the end with all the values equal to the partition value,
97  // and start swapping entries that are in the wrong side of the partition.
98  //
99  moveToFrontIndex = beginIndex;
100  moveToBackIndex = endIndex-1;
101  while( moveToFrontIndex < moveToBackIndex )
102  {
103  //
104  // Find the first element (from the back) that is in the wrong side of the partition.
105  //
106  while( moveToBackIndex >= beginIndex )
107  {
108  if( sample->GetMeasurementVectorByIndex(moveToBackIndex)[activeDimension] < partitionValue )
109  {
110  break;
111  }
112  moveToBackIndex--;
113  }
114 
115  //
116  // Find the first element (from the front) that is in the wrong side of the partition.
117  //
118  while( moveToFrontIndex < endIndex )
119  {
120  if( sample->GetMeasurementVectorByIndex(moveToFrontIndex)[activeDimension] > partitionValue )
121  {
122  break;
123  }
124  moveToFrontIndex++;
125  }
126 
127 
128  if( moveToFrontIndex < moveToBackIndex )
129  {
130  //
131  // Swap them to place them in the correct side of the partition
132  //
133  sample->Swap( moveToBackIndex, moveToFrontIndex );
134  }
135  }
136 
137 
138  //
139  // Take all the entries with activeDimension component equal to
140  // partitionValue, that were placed at the end of the list, and move them to
141  // the interface between smaller and larger values.
142  //
143  int beginOfSectionEqualToPartition = moveToFrontIndex;
144  moveToBackIndex = endIndex-1;
145  while( moveToFrontIndex < moveToBackIndex )
146  {
147  //
148  // Find the first element (from the back) that is in the wrong side of the partition.
149  //
150  while( moveToBackIndex >= beginIndex )
151  {
152  if( sample->GetMeasurementVectorByIndex(moveToBackIndex)[activeDimension] == partitionValue )
153  {
154  break;
155  }
156  moveToBackIndex--;
157  }
158 
159 
160  //
161  // Find the first element (from the front) that is in the wrong side of the partition.
162  //
163  while( moveToFrontIndex < endIndex )
164  {
165  if( sample->GetMeasurementVectorByIndex(moveToFrontIndex)[activeDimension] != partitionValue )
166  {
167  break;
168  }
169  moveToFrontIndex++;
170  }
171 
172  if( moveToFrontIndex < moveToBackIndex )
173  {
174  //
175  // Swap them to place them in the correct side of the partition
176  //
177  sample->Swap( moveToBackIndex, moveToFrontIndex );
178  }
179  }
180  int endOfSectionEqualToPartition = moveToFrontIndex-1;
181 
182  int storeIndex = ( beginOfSectionEqualToPartition + endOfSectionEqualToPartition ) / 2;
183 
184  const MeasurementType pivotValue = sample->GetMeasurementVectorByIndex( storeIndex )[activeDimension];
185  if( pivotValue != partitionValue )
186  {
187  // The partition was done using a value that is not present in the sample.
188  // Therefore we must now find the largest value of the left section and
189  // swap it to the boundary between smaller and larger than the
190  // partitionValue.
191  for(int kk=beginIndex; kk<storeIndex; kk++)
192  {
193  MeasurementType nodeValue = sample->GetMeasurementVectorByIndex( kk )[activeDimension];
194  MeasurementType boundaryValue = sample->GetMeasurementVectorByIndex( storeIndex )[activeDimension];
195  if( nodeValue > boundaryValue )
196  {
197  sample->Swap(kk, storeIndex);
198  }
199  }
200 
201  }
202 
203  return storeIndex;
204 }
205 
206 
207 template< class TValue >
208 inline TValue MedianOfThree(const TValue a,
209  const TValue b,
210  const TValue c)
211 {
212  if (a < b) {
213  if (b < c) {
214  return b;
215  }
216  else if (a < c) {
217  return c;
218  }
219  else {
220  return a;
221  }
222  }
223  else if (a < c) {
224  return a;
225  }
226  else if (b < c) {
227  return c;
228  }
229  else {
230  return b;
231  }
232 }
233 
234 template< class TSample >
235 inline void FindSampleBound(const TSample* sample,
236  typename TSample::ConstIterator begin,
237  typename TSample::ConstIterator end,
238  typename TSample::MeasurementVectorType &min,
239  typename TSample::MeasurementVectorType &max)
240 {
241  typedef typename TSample::MeasurementVectorSizeType MeasurementVectorSizeType;
242 
243  const MeasurementVectorSizeType Dimension = sample->GetMeasurementVectorSize();
244  if( Dimension == 0 )
245  {
246  itkGenericExceptionMacro(
247  << "Length of a sample's measurement vector hasn't been set.");
248  }
249  // Sanity check
250  MeasurementVectorTraits::Assert( max, Dimension,
251  "Length mismatch StatisticsAlgorithm::FindSampleBound");
252  MeasurementVectorTraits::Assert( min, Dimension,
253  "Length mismatch StatisticsAlgorithm::FindSampleBound");
254 
255  unsigned int dimension;
256  typename TSample::MeasurementVectorType temp;
257 
258  min = max = temp = begin.GetMeasurementVector();
259  while (true)
260  {
261  for (dimension= 0; dimension < Dimension; dimension++)
262  {
263  if ( temp[dimension] < min[dimension])
264  {
265  min[dimension] = temp[dimension];
266  }
267  else if (temp[dimension] > max[dimension])
268  {
269  max[dimension] = temp[dimension];
270  }
271  }
272  ++begin;
273  if (begin == end)
274  {
275  break;
276  }
277  temp = begin.GetMeasurementVector();
278  } // end of while
279 }
280 
282 template< class TSubsample >
283 inline void
284 FindSampleBoundAndMean(const TSubsample* sample,
285  int beginIndex,
286  int endIndex,
287  typename TSubsample::MeasurementVectorType &min,
288  typename TSubsample::MeasurementVectorType &max,
289  typename TSubsample::MeasurementVectorType &mean)
290 {
291  typedef typename TSubsample::MeasurementType MeasurementType;
292  typedef typename TSubsample::MeasurementVectorType MeasurementVectorType;
293 
294  typedef typename TSubsample::MeasurementVectorSizeType MeasurementVectorSizeType;
295  const MeasurementVectorSizeType Dimension = sample->GetMeasurementVectorSize();
296  if( Dimension == 0 )
297  {
298  itkGenericExceptionMacro(
299  << "Length of a sample's measurement vector hasn't been set.");
300  }
301 
302  Array< double > sum( Dimension );
303 
304  MeasurementVectorSizeType dimension;
305  MeasurementVectorType temp;
306  MeasurementVectorTraits::SetLength( temp, Dimension );
307  MeasurementVectorTraits::SetLength( mean, Dimension );
308 
309  min = max = temp = sample->GetMeasurementVectorByIndex(beginIndex);
310  double frequencySum = sample->GetFrequencyByIndex(beginIndex);
311  sum.Fill(0.0);
312 
313  while (true)
314  {
315  for (dimension= 0; dimension < Dimension; dimension++)
316  {
317  if ( temp[dimension] < min[dimension])
318  {
319  min[dimension] = temp[dimension];
320  }
321  else if (temp[dimension] > max[dimension])
322  {
323  max[dimension] = temp[dimension];
324  }
325  sum[dimension] += temp[dimension];
326  }
327  ++beginIndex;
328  if (beginIndex == endIndex)
329  {
330  break;
331  }
332  temp = sample->GetMeasurementVectorByIndex(beginIndex);
333  frequencySum += sample->GetFrequencyByIndex(beginIndex);
334  } // end of while
335 
336  for (unsigned int i = 0; i < Dimension; i++)
337  {
338  mean[i] = (MeasurementType)(sum[i] / frequencySum);
339  }
340 }
341 
347 template< class TSubsample >
348 inline typename TSubsample::MeasurementType
349 QuickSelect(TSubsample* sample,
350  unsigned int activeDimension,
351  int beginIndex,
352  int endIndex,
353  int kth,
354  typename TSubsample::MeasurementType medianGuess)
355 {
356  typedef typename TSubsample::MeasurementType MeasurementType;
357 
358  int begin = beginIndex;
359  int end = endIndex - 1;
360  int kthIndex = kth + beginIndex;
361 
362  MeasurementType tempMedian;
363 
364  //
365  // Select a pivot value
366  //
367  if (medianGuess != NumericTraits< MeasurementType >::NonpositiveMin())
368  {
369  tempMedian = medianGuess;
370  }
371  else
372  {
373  const int length = end - begin;
374  const int middle = begin + length / 2;
375  const MeasurementType v1 = sample->GetMeasurementVectorByIndex(begin)[activeDimension];
376  const MeasurementType v2 = sample->GetMeasurementVectorByIndex(end)[activeDimension];
377  const MeasurementType v3 = sample->GetMeasurementVectorByIndex(middle)[activeDimension];
378  tempMedian = MedianOfThree< MeasurementType >( v1, v2, v3 );
379  }
380 
381  while( true )
382  {
383  // Partition expects the end argument to be one past-the-end of the array.
384  // The index pivotNewIndex returned by Partition is in the range [begin,end].
385  int pivotNewIndex =
386  Partition< TSubsample >(sample, activeDimension, begin, end+1, tempMedian);
387 
388  if( kthIndex == pivotNewIndex )
389  {
390  break;
391  }
392 
393  if( kthIndex < pivotNewIndex )
394  {
395  end = pivotNewIndex - 1;
396  }
397  else
398  {
399  begin = pivotNewIndex + 1;
400  }
401 
402  if( begin > end )
403  {
404  break;
405  }
406 
407  const int length = end - begin;
408  const MeasurementType v1 = sample->GetMeasurementVectorByIndex(begin)[activeDimension];
409  const MeasurementType v2 = sample->GetMeasurementVectorByIndex(end)[activeDimension];
410 
411  // current partition has only 1 or 2 elements
412  if( length < 2 )
413  {
414  if( v2 < v1 )
415  {
416  sample->Swap(begin, end);
417  }
418  break;
419  }
420 
421  const int middle = begin + length / 2;
422  const MeasurementType v3 = sample->GetMeasurementVectorByIndex(middle)[activeDimension];
423  tempMedian = MedianOfThree< MeasurementType >( v1, v2, v3 );
424  }
425 
426 
427  return sample->GetMeasurementVectorByIndex(kthIndex)[activeDimension];
428 }
429 
430 
431 template< class TSubsample >
432 inline typename TSubsample::MeasurementType
433 QuickSelect(TSubsample* sample,
434  unsigned int activeDimension,
435  int beginIndex,
436  int endIndex,
437  int kth)
438 {
439  typedef typename TSubsample::MeasurementType MeasurementType;
440  MeasurementType medianGuess = NumericTraits< MeasurementType >::NonpositiveMin();
441  return QuickSelect< TSubsample >(sample, activeDimension,
442  beginIndex, endIndex, kth, medianGuess);
443 }
444 
445 
446 template< class TSubsample >
447 inline typename TSubsample::MeasurementType
448 NthElement(TSubsample* sample,
449  unsigned int activeDimension,
450  int beginIndex,
451  int endIndex,
452  int nth)
453 {
454  typedef typename TSubsample::MeasurementType MeasurementType;
455 
456  const int nthIndex = beginIndex + nth;
457 
458  int beginElement = beginIndex;
459  int endElement = endIndex;
460 
461  while( endElement - beginElement > 3)
462  {
463  const int begin = beginElement;
464  const int end = endElement-1;
465  const int length = endElement - beginElement;
466  const int middle = beginElement + length / 2;
467 
468  const MeasurementType v1 = sample->GetMeasurementVectorByIndex(begin)[activeDimension];
469  const MeasurementType v2 = sample->GetMeasurementVectorByIndex(end)[activeDimension];
470  const MeasurementType v3 = sample->GetMeasurementVectorByIndex(middle)[activeDimension];
471 
472  const MeasurementType tempMedian = MedianOfThree< MeasurementType >( v1, v2, v3 );
473 
474  int cut = UnguardedPartition( sample, activeDimension, beginElement, endElement, tempMedian );
475 
476  if( cut <= nthIndex )
477  {
478  beginElement = cut;
479  }
480  else
481  {
482  endElement = cut;
483  }
484  }
485 
486  InsertSort( sample, activeDimension, beginElement, endElement );
487 
488  return sample->GetMeasurementVectorByIndex(nthIndex)[activeDimension];
489 }
490 
491 
492 template< class TSubsample >
493 inline int UnguardedPartition(TSubsample* sample,
494  unsigned int activeDimension,
495  int beginIndex,
496  int endIndex,
497  typename TSubsample::MeasurementType pivotValue )
498 {
499  typedef typename TSubsample::MeasurementType MeasurementType;
500  while( true )
501  {
502  MeasurementType beginValue =
503  sample->GetMeasurementVectorByIndex(beginIndex)[activeDimension];
504 
505  while( beginValue < pivotValue )
506  {
507  ++beginIndex;
508 
509  beginValue = sample->GetMeasurementVectorByIndex(beginIndex)[activeDimension];
510  }
511 
512  --endIndex;
513 
514  MeasurementType endValue =
515  sample->GetMeasurementVectorByIndex(endIndex)[activeDimension];
516 
517  while( pivotValue < endValue )
518  {
519  --endIndex;
520  endValue = sample->GetMeasurementVectorByIndex(endIndex)[activeDimension];
521  }
522 
523  if( !(beginIndex < endIndex) )
524  {
525  return beginIndex;
526  }
527 
528  sample->Swap( beginIndex, endIndex );
529 
530  ++beginIndex;
531  }
532 }
533 
534 
535 template< class TSubsample >
536 inline void InsertSort(TSubsample* sample,
537  unsigned int activeDimension,
538  int beginIndex,
539  int endIndex)
540 {
541  int backwardSearchBegin;
542  int backwardIndex;
543 
544  for (backwardSearchBegin = beginIndex + 1;
545  backwardSearchBegin < endIndex;
546  backwardSearchBegin++)
547  {
548  backwardIndex = backwardSearchBegin;
549  while (backwardIndex > beginIndex)
550  {
551  typedef typename TSubsample::MeasurementType MeasurementType;
552  const MeasurementType value1 = sample->GetMeasurementVectorByIndex(backwardIndex)[activeDimension];
553  const MeasurementType value2 = sample->GetMeasurementVectorByIndex(backwardIndex - 1)[activeDimension];
554 
555  if( value1 < value2 )
556  {
557  sample->Swap(backwardIndex, backwardIndex - 1);
558  }
559  else
560  {
561  break;
562  }
563  --backwardIndex;
564  }
565  }
566 }
567 
568 template< class TSubsample >
569 inline void DownHeap(TSubsample* sample,
570  unsigned int activeDimension,
571  int beginIndex, int endIndex, int node)
572 {
573  int currentNode = node;
574  int leftChild;
575  int rightChild;
576  int largerChild;
577  typedef typename TSubsample::MeasurementType MeasurementType;
578  MeasurementType currentNodeValue =
579  sample->GetMeasurementVectorByIndex(currentNode)[activeDimension];
580  MeasurementType leftChildValue;
581  MeasurementType rightChildValue;
582  MeasurementType largerChildValue;
583 
584  while (true)
585  {
586  // location of first child
587  largerChild = leftChild =
588  beginIndex + 2*(currentNode - beginIndex) + 1;
589  rightChild = leftChild + 1;
590  if (leftChild > endIndex - 1)
591  {
592  // leaf node
593  return;
594  }
595 
596  largerChildValue = rightChildValue = leftChildValue =
597  sample->GetMeasurementVectorByIndex(leftChild)[activeDimension];
598 
599  if (rightChild < endIndex)
600  {
601  rightChildValue =
602  sample->GetMeasurementVectorByIndex(rightChild)[activeDimension];
603  }
604 
605  if (leftChildValue < rightChildValue)
606  {
607  largerChild = rightChild;
608  largerChildValue = rightChildValue;
609  }
610 
611  if (largerChildValue <= currentNodeValue)
612  {
613  // the node satisfies heap property
614  return;
615  }
616  // move down current node value to the larger child
617  sample->Swap(currentNode, largerChild);
618  currentNode = largerChild;
619  }
620 }
621 
622 template< class TSubsample >
623 inline void HeapSort(TSubsample* sample,
624  unsigned int activeDimension,
625  int beginIndex,
626  int endIndex)
627 {
628  // construct a heap
629  int node;
630 
631  for (node = beginIndex + (endIndex - beginIndex) / 2 - 1;
632  node >= beginIndex; node--)
633  {
634  DownHeap< TSubsample >(sample, activeDimension,
635  beginIndex, endIndex, node);
636  }
637 
638  // sort
639  int newEndIndex;
640  for (newEndIndex = endIndex - 1; newEndIndex >= beginIndex;
641  --newEndIndex)
642  {
643  sample->Swap(beginIndex, newEndIndex);
644  DownHeap< TSubsample >(sample, activeDimension,
645  beginIndex, newEndIndex, beginIndex);
646  }
647 }
648 
649 
650 template< class TSubsample >
651 inline void IntrospectiveSortLoop(TSubsample* sample,
652  unsigned int activeDimension,
653  int beginIndex,
654  int endIndex,
655  int depthLimit,
656  int sizeThreshold)
657 {
658  typedef typename TSubsample::MeasurementType MeasurementType;
659 
660  int length = endIndex - beginIndex;
661  int cut;
662  while(length > sizeThreshold)
663  {
664  if (depthLimit == 0)
665  {
666  HeapSort< TSubsample >(sample, activeDimension,
667  beginIndex, endIndex);
668  return;
669  }
670 
671  --depthLimit;
672  cut = Partition< TSubsample >(sample, activeDimension,
673  beginIndex, endIndex,
674  MedianOfThree< MeasurementType >
675  (sample->GetMeasurementVectorByIndex(beginIndex)[activeDimension],
676  sample->GetMeasurementVectorByIndex(beginIndex + length/2)[activeDimension],
677  sample->GetMeasurementVectorByIndex(endIndex - 1)[activeDimension]));
678  IntrospectiveSortLoop< TSubsample >(sample, activeDimension,
679  cut, endIndex,
680  depthLimit, sizeThreshold);
681  endIndex = cut;
682  length = endIndex - beginIndex;
683  }
684 }
685 
686 template< class TSubsample >
687 inline void IntrospectiveSort(TSubsample* sample,
688  unsigned int activeDimension,
689  int beginIndex,
690  int endIndex,
691  int sizeThreshold)
692 {
693  typedef typename TSubsample::MeasurementType MeasurementType;
694  IntrospectiveSortLoop< TSubsample >(sample, activeDimension, beginIndex, endIndex,
695  2 * FloorLog(endIndex - beginIndex), sizeThreshold);
696  InsertSort< TSubsample >(sample, activeDimension, beginIndex, endIndex);
697 }
698 
699 } // end of namespace Statistics
700 } // end of namespace itk
701 
702 #endif // #ifndef __itkStatisticsAlgorithm_txx

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