DataStatistics.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2017 Imperial College London
5  * Copyright 2013-2017 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifndef MIRTK_DataStatistics_H
21 #define MIRTK_DataStatistics_H
22 
23 #include "mirtk/DataOp.h"
24 
25 #include "mirtk/Math.h"
26 #include "mirtk/String.h"
27 #include "mirtk/Stream.h"
28 #include "mirtk/Array.h"
29 #include "mirtk/Algorithm.h" // partial_sort
30 
31 
32 namespace mirtk { namespace data {
33 
34 
35 // =============================================================================
36 // Base class
37 // =============================================================================
38 
39 // -----------------------------------------------------------------------------
40 /// Base class of all data statistics
41 class Statistic : public Op
42 {
43  /// Do not include statistic in output report
44  mirtkPublicAttributeMacro(bool, Hidden);
45 
46  /// Description of data statistic
47  mirtkPublicAttributeMacro(string, Description);
48 
49  /// Column names for (CSV) output
50  mirtkPublicAttributeMacro(Array<string>, Names);
51 
52  /// Values of data statistic
53  mirtkReadOnlyAttributeMacro(Array<double>, Values);
54 
55 protected:
56 
57  /// Constructor
58  Statistic(int nvalues, const char *desc = nullptr, const Array<string> *names = nullptr)
59  :
60  _Hidden(false),
61  _Description(desc ? desc : "Unknown statistic")
62  {
63  if (nvalues <= 0) nvalues = 1;
64  _Names .resize(nvalues);
65  _Values.resize(nvalues, NaN);
66  if (names) {
67  for (int i = 0; i < nvalues; ++i) {
68  _Names[i] = names->at(i);
69  }
70  }
71  }
72 
73  /// Set value of statistic (first entry of _Values vector)
74  void Value(double v)
75  {
76  _Values[0] = v;
77  }
78 
79 public:
80 
81  /// Destructor
82  virtual ~Statistic() {}
83 
84  /// Hide/Show statistic in output report
85  mirtkOnOffMacro(Hidden);
86 
87  /// Get value of statistic (first entry of _Values vector)
88  ///
89  /// @returns Reference to first element of _Values vector such that the
90  /// address of the this element can be passed on to subsequent
91  /// data operations.
92  virtual const double &Value() const
93  {
94  return _Values[0];
95  }
96 
97  /// Process given data
98  virtual void Process(int n, double *data, bool *mask = nullptr)
99  {
100  this->Evaluate(_Values, n, data, mask);
101  }
102 
103 #if MIRTK_Image_WITH_VTK
104 
105  /// Process given vtkDataArray
106  virtual void Process(vtkDataArray *data, bool *mask = nullptr)
107  {
108  const int n = static_cast<int>(data->GetNumberOfTuples() * data->GetNumberOfComponents());
109  if (data->GetDataType() == VTK_DOUBLE) {
110  this->Process(n, reinterpret_cast<double *>(data->GetVoidPointer(0)), mask);
111  } else {
112  UniquePtr<double[]> _data(new double[n]);
113  double *tuple = _data.get();
114  for (vtkIdType i = 0; i < data->GetNumberOfTuples(); ++i) {
115  data->GetTuple(i, tuple);
116  tuple += data->GetNumberOfComponents();
117  }
118  this->Process(n, _data.get(), mask);
119  // Unlike base class, no need to copy data back to input array
120  }
121  }
122 
123 #endif // MIRTK_Image_WITH_VTK
124 
125  /// Evaluate statistic for given data
126  virtual void Evaluate(Array<double> &, int, const double *, const bool * = nullptr) const = 0;
127 
128  /// Print column names of statistic values to output stream
129  virtual void PrintHeader(ostream &os = cout, const char *delimiter = ",") const
130  {
131  for (size_t i = 0; i < _Values.size(); ++i) {
132  if (i > 0) os << delimiter;
133  if (i < _Names.size()) os << _Names[i];
134  }
135  }
136 
137  /// Print delimited statistic values to output stream
138  virtual void PrintValues(ostream &os = cout, int digits = 5, const char *delimiter = ",") const
139  {
140  streamsize prev_precision = os.precision(digits);
141  for (size_t i = 0; i < _Values.size(); ++i) {
142  if (i > 0) os << delimiter;
143  os << _Values[i];
144  }
145  os.precision(prev_precision);
146  }
147 
148  /// Print statistic to output stream as "<desc> = <value>"
149  virtual void Print(ostream &os = cout, int digits = 5, const char *prefix = "") const
150  {
151  streamsize prev_precision = os.precision(digits);
152  if (prefix && prefix[0] != '\0') {
153  os << prefix << ' ';
154  os << char(tolower(_Description[0]));
155  os << _Description.substr(1);
156  } else {
157  os << _Description;
158  }
159  os << " = ";
160  if (_Values.size() != 1) os << "[";
161  for (size_t i = 0; i < _Values.size(); ++i) {
162  if (i > 0) os << ", ";
163  os << _Values[i];
164  }
165  if (_Values.size() != 1) os << "]";
166  os << endl;
167  os.precision(prev_precision);
168  }
169 
170 };
171 
172 
173 // =============================================================================
174 // Data statistics
175 // =============================================================================
176 
177 namespace statistic {
178 
179 
180 // -----------------------------------------------------------------------------
181 /// Count number of masked values (mask != false)
182 class Count : public Statistic
183 {
184 public:
185 
186  Count(const char *desc = "N", const Array<string> *names = nullptr)
187  :
188  Statistic(1, desc, names)
189  {
190  if (!names) _Names[0] = "N";
191  }
192 
193  template <class T>
194  static double Calculate(int n, const T *data, const bool *mask = nullptr)
195  {
196  if (mask) {
197  int count = 0;
198  for (int i = 0; i < n; ++i) {
199  if (mask[i]) ++count;
200  }
201  return count;
202  } else {
203  return n;
204  }
205  }
206 
207  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
208  {
209  values.resize(1);
210  values[0] = Calculate(n, data, mask);
211  }
212 
213  /// Print delimited statistic values to output stream
214  virtual void PrintValues(ostream &os = cout, int = 5, const char *delimiter = ",") const
215  {
216  for (size_t i = 0; i < _Values.size(); ++i) {
217  if (i > 0) os << delimiter;
218  os << int(_Values[i]);
219  }
220  }
221 
222  /// Print statistic to output stream as "<desc> = <value>"
223  virtual void Print(ostream &os = cout, int = 5, const char *prefix = "") const
224  {
225  if (prefix && prefix[0] != '\0') {
226  os << prefix << ' ';
227  os << char(tolower(_Description[0]));
228  os << _Description.substr(1);
229  } else {
230  os << _Description;
231  }
232  os << " = ";
233  if (_Values.size() != 1) os << "[";
234  for (size_t i = 0; i < _Values.size(); ++i) {
235  if (i > 0) os << ", ";
236  os << int(_Values[i]);
237  }
238  if (_Values.size() != 1) os << "]";
239  os << endl;
240  }
241 };
242 
243 // -----------------------------------------------------------------------------
244 /// Get sum of values
245 class Sum : public Statistic
246 {
247 public:
248 
249  Sum(const char *desc = "Sum", const Array<string> *names = nullptr)
250  :
251  Statistic(1, desc, names)
252  {
253  if (!names) _Names[0] = "Sum";
254  }
255 
256  template <class T>
257  static double Calculate(int n, const T *data, const bool *mask = nullptr)
258  {
259  double sum = 0.;
260  if (mask) {
261  for (int i = 0; i < n; ++i) {
262  if (mask[i]) {
263  sum += static_cast<double>(data[i]);
264  }
265  }
266  } else {
267  for (int i = 0; i < n; ++i) {
268  sum += static_cast<double>(data[i]);
269  }
270  }
271  return sum;
272  }
273 
274  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
275  {
276  values.resize(1);
277  values[0] = Calculate(n, data, mask);
278  }
279 
280  // Add support for vtkDataArray argument
281  mirtkCalculateVtkDataArray1();
282 };
283 
284 // -----------------------------------------------------------------------------
285 /// Get minimum value
286 class Min : public Statistic
287 {
288 public:
289 
290  Min(const char *desc = "Minimum", const Array<string> *names = nullptr)
291  :
292  Statistic(1, desc, names)
293  {
294  if (!names) _Names[0] = "Min";
295  }
296 
297  template <class T>
298  static double Calculate(int n, const T *data, const bool *mask = nullptr)
299  {
300  double d, v = inf;
301  if (mask) {
302  for (int i = 0; i < n; ++i) {
303  if (mask[i]) {
304  d = static_cast<double>(data[i]);
305  if (d < v) v = d;
306  }
307  }
308  } else {
309  for (int i = 0; i < n; ++i) {
310  d = static_cast<double>(data[i]);
311  if (d < v) v = d;
312  }
313  }
314  return (IsInf(v) ? NaN : v);
315  }
316 
317  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
318  {
319  values.resize(1);
320  values[0] = Calculate(n, data, mask);
321  }
322 
323  // Add support for vtkDataArray argument
324  mirtkCalculateVtkDataArray1();
325 };
326 
327 // -----------------------------------------------------------------------------
328 /// Get minimum absolute value
329 class MinAbs : public Statistic
330 {
331 public:
332 
333  MinAbs(const char *desc = "Minimum absolute value", const Array<string> *names = nullptr)
334  :
335  Statistic(1, desc, names)
336  {
337  if (!names) _Names[0] = "Min abs value";
338  }
339 
340  template <class T>
341  static double Calculate(int n, const T *data, const bool *mask = nullptr)
342  {
343  double d, v = inf;
344  if (mask) {
345  for (int i = 0; i < n; ++i) {
346  if (mask[i]) {
347  d = abs(static_cast<double>(data[i]));
348  if (d < v) v = d;
349  }
350  }
351  } else {
352  for (int i = 0; i < n; ++i) {
353  d = abs(static_cast<double>(data[i]));
354  if (d < v) v = d;
355  }
356  }
357  return (IsInf(v) ? NaN : v);
358  }
359 
360  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
361  {
362  values.resize(1);
363  values[0] = Calculate(n, data, mask);
364  }
365 
366  // Add support for vtkDataArray argument
367  mirtkCalculateVtkDataArray1();
368 };
369 
370 // -----------------------------------------------------------------------------
371 /// Get maximum value
372 class Max : public Statistic
373 {
374 public:
375 
376  Max(const char *desc = "Maximum", const Array<string> *names = nullptr)
377  :
378  Statistic(1, desc, names)
379  {
380  if (!names) _Names[0] = "Max";
381  }
382 
383  template <class T>
384  static double Calculate(int n, const T *data, const bool *mask = nullptr)
385  {
386  double d, v = -inf;
387  if (mask) {
388  for (int i = 0; i < n; ++i) {
389  if (mask[i]) {
390  d = static_cast<double>(data[i]);
391  if (d > v) v = d;
392  }
393  }
394  } else {
395  for (int i = 0; i < n; ++i) {
396  d = static_cast<double>(data[i]);
397  if (d > v) v = d;
398  }
399  }
400  return (IsInf(v) ? NaN : v);
401  }
402 
403  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
404  {
405  values.resize(1);
406  values[0] = Calculate(n, data, mask);
407  }
408 
409  // Add support for vtkDataArray argument
410  mirtkCalculateVtkDataArray1();
411 };
412 
413 // -----------------------------------------------------------------------------
414 /// Get maximum absolute value
415 class MaxAbs : public Statistic
416 {
417 public:
418 
419  MaxAbs(const char *desc = "Maximum absolute value", const Array<string> *names = nullptr)
420  :
421  Statistic(1, desc, names)
422  {
423  if (!names) _Names[0] = "Max abs value";
424  }
425 
426  template <class T>
427  static double Calculate(int n, const T *data, const bool *mask = nullptr)
428  {
429  double d, v = -inf;
430  if (mask) {
431  for (int i = 0; i < n; ++i) {
432  if (mask[i]) {
433  d = abs(static_cast<double>(data[i]));
434  if (d > v) v = d;
435  }
436  }
437  } else {
438  for (int i = 0; i < n; ++i) {
439  d = abs(static_cast<double>(data[i]));
440  if (d > v) v = d;
441  }
442  }
443  return (IsInf(v) ? NaN : v);
444  }
445 
446  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
447  {
448  values.resize(1);
449  values[0] = Calculate(n, data, mask);
450  }
451 
452  // Add support for vtkDataArray argument
453  mirtkCalculateVtkDataArray1();
454 };
455 
456 // -----------------------------------------------------------------------------
457 /// Get minimum and maximum values
458 class Extrema : public Statistic
459 {
460 public:
461 
462  Extrema(const char *desc = "Extrema", const Array<string> *names = nullptr)
463  :
464  Statistic(2, desc, names)
465  {
466  if (!names) {
467  _Names[0] = "Min";
468  _Names[1] = "Max";
469  }
470  }
471 
472  template <class T>
473  static void Calculate(double &v1, double &v2, int n, const T *data, const bool *mask = nullptr)
474  {
475  double d;
476  v1 = +inf;
477  v2 = -inf;
478  if (mask) {
479  for (int i = 0; i < n; ++i) {
480  if (mask[i]) {
481  d = static_cast<double>(data[i]);
482  if (d < v1) v1 = d;
483  if (d > v2) v2 = d;
484  }
485  }
486  } else {
487  for (int i = 0; i < n; ++i) {
488  d = static_cast<double>(data[i]);
489  if (d < v1) v1 = d;
490  if (d > v2) v2 = d;
491  }
492  }
493  if (v1 > v2) {
494  v1 = v2 = NaN;
495  }
496  }
497 
498  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
499  {
500  values.resize(2);
501  Calculate(values[0], values[1], n, data, mask);
502  }
503 
504  double Min() const { return _Values[0]; }
505  double Max() const { return _Values[1]; }
506 
507  // Add support for vtkDataArray argument
508  mirtkCalculateVtkDataArray2();
509 };
510 
511 // -----------------------------------------------------------------------------
512 /// Get value range
513 class Range : public Statistic
514 {
515 public:
516 
517  Range(const char *desc = "Range", const Array<string> *names = nullptr)
518  :
519  Statistic(1, desc, names)
520  {
521  if (!names) _Names[0] = "Range";
522  }
523 
524  template <class T>
525  static double Calculate(int n, const T *data, const bool *mask = nullptr)
526  {
527  double v1, v2;
528  Extrema::Calculate(v1, v2, n, data, mask);
529  return v2 - v1;
530  }
531 
532  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
533  {
534  values.resize(1);
535  values[0] = Calculate(n, data, mask);
536  }
537 
538  // Add support for vtkDataArray argument
539  mirtkCalculateVtkDataArray1();
540 };
541 
542 // -----------------------------------------------------------------------------
543 /// Median value (50th percentile)
544 class Median : public Statistic
545 {
546 public:
547 
548  Median(const char *desc = "Median", const Array<string> *names = nullptr)
549  :
550  Statistic(1, desc, names)
551  {
552  if (!names) _Names[0] = "Median";
553  }
554 
555  template <class T>
556  static double Calculate(int n, const T *data, const bool *mask = nullptr)
557  {
558  Array<T> values;
559  if (mask) {
560  values.reserve(n);
561  for (int i = 0; i < n; ++i) {
562  if (mask[i]) values.push_back(data[i]);
563  }
564  } else {
565  values.resize(n);
566  for (int i = 0; i < n; ++i) {
567  values[i] = data[i];
568  }
569  }
570  if (values.size() <= 0) return NaN;
571  return NthElement(values, static_cast<int>(values.size())/2);
572  }
573 
574  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
575  {
576  values.resize(1);
577  values[0] = Calculate(n, data, mask);
578  }
579 
580  // Add support for vtkDataArray argument
581  mirtkCalculateVtkDataArray1();
582 };
583 
584 // -----------------------------------------------------------------------------
585 /// Robust mean/average evaluation
586 class Mean : public Statistic
587 {
588 public:
589 
590  Mean(const char *desc = "Mean", const Array<string> *names = nullptr)
591  :
592  Statistic(1, desc, names)
593  {
594  if (!names) _Names[0] = "Mean";
595  }
596 
597  template <class T>
598  static double Calculate(int n, const T *data, const bool *mask = nullptr)
599  {
600  int m = 0;
601  double v = 0.;
602 
603  if (mask) {
604  for (int i = 0; i < n; ++i) {
605  if (mask[i]) {
606  ++m, v += (static_cast<double>(data[i]) - v) / m;
607  }
608  }
609  } else {
610  for (int i = 0; i < n; ++i) {
611  v += (static_cast<double>(data[i]) - v) / (i + 1);
612  }
613  m = n;
614  }
615 
616  return (m < 1 ? NaN : v);
617  }
618 
619  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
620  {
621  values.resize(1);
622  values[0] = Calculate(n, data, mask);
623  }
624 
625  // Add support for vtkDataArray argument
626  mirtkCalculateVtkDataArray1();
627 };
628 
629 // -----------------------------------------------------------------------------
630 /// Base class of statistics which compute mean, variance, and/or standard deviation
631 class MeanVar : public Statistic
632 {
633 protected:
634 
635  /// Constructor
636  MeanVar(int nvalues, const char *desc = nullptr, const Array<string> *names = nullptr)
637  :
638  Statistic(nvalues, desc, names)
639  {}
640 
641 public:
642 
643  template <class T>
644  static void Calculate(double &mean, double &var, int n, const T *data, const bool *mask = nullptr)
645  {
646  int m = 0;
647  mean = var = 0.;
648 
649  double delta, d;
650  for (int i = 0; i < n; ++i) {
651  if (!mask || mask[i]) {
652  ++m;
653  d = static_cast<double>(data[i]);
654  delta = d - mean;
655  mean += delta / m;
656  var += delta * (d - mean);
657  }
658  }
659 
660  if (m < 1) {
661  mean = var = NaN;
662  } else if (m < 2) {
663  var = 0.;
664  } else {
665  var /= m - 1;
666  }
667  }
668 };
669 
670 // -----------------------------------------------------------------------------
671 /// Robust variance evaluation
672 class Var : public MeanVar
673 {
674 public:
675 
676  Var(const char *desc = "Variance", const Array<string> *names = nullptr)
677  :
678  MeanVar(1, desc, names)
679  {
680  if (!names) _Names[0] = "Var";
681  }
682 
683  template <class T>
684  static double Calculate(int n, const T *data, const bool *mask = nullptr)
685  {
686  double mean, var;
687  MeanVar::Calculate(mean, var, n, data, mask);
688  return var;
689  }
690 
691  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
692  {
693  double mean;
694  values.resize(1);
695  MeanVar::Calculate(mean, values[0], n, data, mask);
696  }
697 
698  // Add support for vtkDataArray argument
699  mirtkCalculateVtkDataArray1();
700 };
701 
702 // -----------------------------------------------------------------------------
703 /// Robust evaluation of standard deviation
704 class StDev : public MeanVar
705 {
706 public:
707 
708  StDev(const char *desc = "Standard deviation", const Array<string> *names = nullptr)
709  :
710  MeanVar(1, desc, names)
711  {
712  if (!names) _Names[0] = "Sigma";
713  }
714 
715  template <class T>
716  static double Calculate(int n, const T *data, const bool *mask = nullptr)
717  {
718  double mean, var;
719  MeanVar::Calculate(mean, var, n, data, mask);
720  return sqrt(var);
721  }
722 
723  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
724  {
725  double mean, var;
726  MeanVar::Calculate(mean, var, n, data, mask);
727  values.resize(1);
728  values[0] = sqrt(var);
729  }
730 
731  // Add support for vtkDataArray argument
732  mirtkCalculateVtkDataArray1();
733 };
734 
735 // -----------------------------------------------------------------------------
736 /// Robust evaluation of Gaussian mean and standard deviation
738 {
739 public:
740 
741  NormalDistribution(const char *desc = "Normal distribution", const Array<string> *names = nullptr)
742  :
743  MeanVar(2, desc, names)
744  {
745  if (!names) {
746  _Names[0] = "Mean";
747  _Names[1] = "Sigma";
748  }
749  }
750 
751  template <class T>
752  static void Calculate(double &mean, double &sigma, int n, const T *data, const bool *mask = nullptr)
753  {
754  MeanVar::Calculate(mean, sigma, n, data, mask);
755  sigma = sqrt(sigma);
756  }
757 
758  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
759  {
760  values.resize(2);
761  Calculate(values[0], values[1], n, data, mask);
762  }
763 
764  double Mean() const { return _Values[0]; }
765  double Sigma() const { return _Values[1]; }
766 
767  // Add support for vtkDataArray argument
768  mirtkCalculateVtkDataArray2();
769 };
770 
771 // -----------------------------------------------------------------------------
772 /// Mean absolute difference/deviation around the specified value
774 {
775  /// Mean value
776  mirtkPublicAttributeMacro(double, Mean);
777 
778  /// Address of mean value storage
779  ///
780  /// This pointer can be set to the memory location of a double value that
781  /// will be set by a preceeding data statistic operation such as
782  /// data::statistic::Mean and data::statistic::Median. The result of this
783  /// statistic calculation thus becomes the input parameter of this operation.
784  mirtkPublicAggregateMacro(const double, MeanPointer);
785 
786 public:
787 
788  AverageAbsoluteDifference(double mean, const double *mean_ptr,
789  const char *desc = "Average absolute difference",
790  const Array<string> *names = nullptr)
791  :
792  Statistic(1, desc, names),
793  _Mean(mean),
794  _MeanPointer(mean_ptr)
795  {
796  if (!names) _Names[0] = "MAD";
797  }
798 
799  AverageAbsoluteDifference(double mean)
800  :
801  AverageAbsoluteDifference(mean, nullptr)
802  {}
803 
804  AverageAbsoluteDifference(const double *mean)
805  :
806  AverageAbsoluteDifference(0., mean)
807  {}
808 
809  template <class T>
810  static double Calculate(double mean, int n, const T *data, const bool *mask = nullptr)
811  {
812  int num = 0;
813  double mad = 0.;
814  if (mask) {
815  for (int i = 0; i < n; ++i) {
816  if (mask[i]) {
817  mad += abs(data[i] - mean);
818  num += 1;
819  }
820  }
821  } else {
822  for (int i = 0; i < n; ++i) {
823  mad += abs(data[i] - mean);
824  }
825  num = n;
826  }
827  return (num > 0 ? mad / num : 0.);
828  }
829 
830  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
831  {
832  values.resize(1);
833  values[0] = Calculate(_MeanPointer ? *_MeanPointer : _Mean, n, data, mask);
834  }
835 };
836 
837 // -----------------------------------------------------------------------------
838 /// Mean absolute difference/deviation around the mean
840 {
841 public:
842 
843  MeanAbsoluteDifference(const char *desc = "Mean absolute difference", const Array<string> *names = nullptr)
844  :
845  Statistic(1, desc, names)
846  {
847  if (!names) {
848  _Names[0] = "MAD mean";
849  }
850  }
851 
852  template <class T>
853  static void Calculate(double &mean, double &mad, int n, const T *data, const bool *mask = nullptr)
854  {
855  int num = 0;
856  mean = Mean::Calculate(n, data, mask);
857  mad = 0.;
858  if (mask) {
859  for (int i = 0; i < n; ++i) {
860  if (mask[i]) {
861  mad += abs(data[i] - mean);
862  num += 1;
863  }
864  }
865  } else {
866  for (int i = 0; i < n; ++i) {
867  mad += abs(data[i] - mean);
868  }
869  num = n;
870  }
871  if (num > 0) mad /= num;
872  }
873 
874  template <class T>
875  static double Calculate(int n, const T *data, const bool *mask = nullptr)
876  {
877  double mean, mad;
878  Calculate(mean, mad, n, data, mask);
879  return mad;
880  }
881 
882  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
883  {
884  values.resize(1);
885  values[0] = Calculate(n, data, mask);
886  }
887 
888  // Add support for vtkDataArray argument
889  mirtkCalculateVtkDataArray1();
890 };
891 
892 // -----------------------------------------------------------------------------
893 /// Mean absolute difference/deviation around the median
895 {
896 public:
897 
898  MedianAbsoluteDifference(const char *desc = "Median absolute difference", const Array<string> *names = nullptr)
899  :
900  Statistic(1, desc, names)
901  {
902  if (!names) {
903  _Names[0] = "MAD median";
904  }
905  }
906 
907  template <class T>
908  static void Calculate(double &median, double &mad, int n, const T *data, const bool *mask = nullptr)
909  {
910  int num = 0;
911  median = Median::Calculate(n, data, mask);
912  mad = 0.;
913  if (mask) {
914  for (int i = 0; i < n; ++i) {
915  if (mask[i]) {
916  mad += abs(data[i] - median);
917  num += 1;
918  }
919  }
920  } else {
921  for (int i = 0; i < n; ++i) {
922  mad += abs(data[i] - median);
923  }
924  num = n;
925  }
926  if (num > 0) mad /= num;
927  }
928 
929  template <class T>
930  static double Calculate(int n, const T *data, const bool *mask = nullptr)
931  {
932  double median, mad;
933  Calculate(median, mad, n, data, mask);
934  return mad;
935  }
936 
937  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
938  {
939  values.resize(1);
940  values[0] = Calculate(n, data, mask);
941  }
942 
943  // Add support for vtkDataArray argument
944  mirtkCalculateVtkDataArray1();
945 };
946 
947 // -----------------------------------------------------------------------------
948 /// Percentile calculation
949 class Percentile : public Statistic
950 {
951  /// Percentage of values that are lower than the percentile to look for
952  mirtkReadOnlyAttributeMacro(int, P);
953 
954 public:
955 
956  Percentile(int p, const char *desc = nullptr, const Array<string> *names = nullptr)
957  :
958  Statistic(1, desc, names), _P(p)
959  {
960  if (!desc) {
961  _Description = ToString(p);
962  if (p == 1) _Description += "st";
963  else if (p == 2) _Description += "nd";
964  else if (p == 3) _Description += "rd";
965  else _Description += "th";
966  _Description += " percentile";
967  }
968  if (!names) {
969  _Names[0] = ToString(p);
970  if (p == 1) _Names[0] += "st";
971  else if (p == 2) _Names[0] += "nd";
972  else if (p == 3) _Names[0] += "rd";
973  else _Names[0] += "th";
974  _Names[0] += "%";
975  }
976  }
977 
978  template <class T>
979  static double CalculateGivenSortedData(int p, double &rank, int n, const T *data)
980  {
981  if (n == 0) {
982  rank = NaN;
983  return NaN;
984  }
985 
986  // Compute percentile rank
987  rank = (double(p) / 100.) * double(n + 1);
988 
989  // Split rank into integer and decimal components
990  int k = int(rank);
991  double d = rank - k;
992 
993  // Compute percentile value according to NIST method
994  // (cf. http://en.wikipedia.org/wiki/Percentile#Definition_of_the_NIST_method )
995  if (k == 0) {
996  return Min::Calculate(n, data);
997  } else if (k >= n) {
998  return Max::Calculate(n, data);
999  } else {
1000  return data[k - 1] + d * (data[k] - data[k - 1]);
1001  }
1002  }
1003 
1004  template <class T>
1005  static double CalculateGivenSortedData(int p, int n, const T *data)
1006  {
1007  double rank;
1008  return CalculateGivenSortedData(p, rank, n, data);
1009  }
1010 
1011  template <class T>
1012  static double Calculate(int p, double &rank, int n, const T *data, const bool *mask = nullptr)
1013  {
1014  // Determine number of unmasked values
1015  int m = n;
1016  if (mask) {
1017  m = 0;
1018  for (int i = 0; i < n; ++i) {
1019  if (mask[i]) ++m;
1020  }
1021  }
1022 
1023  if (m == 0) {
1024  rank = NaN;
1025  return NaN;
1026  }
1027 
1028  // Compute percentile rank
1029  rank = (double(p) / 100.) * double(m + 1);
1030 
1031  // Split rank into integer and decimal components
1032  int k = int(rank);
1033  double d = rank - k;
1034 
1035  // Compute percentile value according to NIST method
1036  // (cf. http://en.wikipedia.org/wiki/Percentile#Definition_of_the_NIST_method )
1037  if (k == 0) {
1038  return Min::Calculate(n, data, mask);
1039  } else if (k >= m) {
1040  return Max::Calculate(n, data, mask);
1041  } else {
1042  // Copy unmasked data only
1043  double *v = new double[m];
1044  if (mask) {
1045  m = 0;
1046  for (int i = 0; i < n; ++i) {
1047  if (mask[i]) v[m++] = static_cast<double>(data[i]);
1048  }
1049  } else {
1050  for (int i = 0; i < n; ++i) {
1051  v[i] = static_cast<double>(data[i]);
1052  }
1053  }
1054  // Sort data below k + 1
1055  partial_sort(v, v + k + 1, v + m);
1056  // Compute percentile value
1057  double percentile = v[k - 1] + d * (v[k] - v[k - 1]);
1058  // Free (partially) sorted data copy
1059  delete[] v;
1060  return percentile;
1061  }
1062  }
1063 
1064  template <class T>
1065  static double Calculate(int p, int n, const T *data, const bool *mask = nullptr)
1066  {
1067  double rank;
1068  return Calculate(p, rank, n, data, mask);
1069  }
1070 
1071  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
1072  {
1073  values.resize(1);
1074  values[0] = Calculate(_P, n, data, mask);
1075  }
1076 
1077  // Add support for vtkDataArray
1078 #if MIRTK_Image_WITH_VTK
1079 
1080  static double Calculate(int p, double &rank, vtkDataArray *data, const bool *mask = nullptr)
1081  {
1082  const int n = static_cast<int>(data->GetNumberOfTuples());
1083  const void *ptr = data->GetVoidPointer(0);
1084  switch (data->GetDataType()) {
1085  case VTK_SHORT: return Calculate(p, rank, n, static_cast<const short *>(ptr), mask);
1086  case VTK_INT: return Calculate(p, rank, n, static_cast<const int *>(ptr), mask);
1087  case VTK_FLOAT: return Calculate(p, rank, n, static_cast<const float *>(ptr), mask);
1088  case VTK_DOUBLE: return Calculate(p, rank, n, static_cast<const double *>(ptr), mask);
1089  default:
1090  cerr << "Unsupported vtkDataArray type: " << data->GetDataType() << endl;
1091  exit(1);
1092  }
1093  rank = NaN;
1094  return NaN;
1095  }
1096 
1097  static double Calculate(int p, vtkDataArray *data, const bool *mask = nullptr)
1098  {
1099  double rank;
1100  return Calculate(p, rank, data, mask);
1101  }
1102 
1103 #endif // MIRTK_Image_WITH_VTK
1104 };
1105 
1106 // -----------------------------------------------------------------------------
1107 /// Absolute value percentile calculation
1108 class AbsPercentile : public Statistic
1109 {
1110  /// Percentage of values that are lower than the percentile to look for
1111  mirtkReadOnlyAttributeMacro(int, P);
1112 
1113 public:
1114 
1115  AbsPercentile(int p, const char *desc = nullptr, const Array<string> *names = nullptr)
1116  :
1117  Statistic(1, desc, names), _P(p)
1118  {
1119  if (!desc) {
1120  _Description = ToString(p);
1121  if (p == 1) _Description += "st";
1122  else if (p == 2) _Description += "nd";
1123  else if (p == 3) _Description += "rd";
1124  else _Description += "th";
1125  _Description += " absolute value percentile";
1126  }
1127  if (!names) {
1128  _Names[0] = ToString(p);
1129  if (p == 1) _Names[0] += "st";
1130  else if (p == 2) _Names[0] += "nd";
1131  else if (p == 3) _Names[0] += "rd";
1132  else _Names[0] += "th";
1133  _Names[0] += "% (abs)";
1134  }
1135  }
1136 
1137  template <class T>
1138  static double Calculate(int p, double &rank, int n, const T *data, const bool *mask = nullptr)
1139  {
1140  // Determine number of unmasked values
1141  int m = n;
1142  if (mask) {
1143  m = 0;
1144  for (int i = 0; i < n; ++i) {
1145  if (mask[i]) ++m;
1146  }
1147  }
1148 
1149  if (m == 0) {
1150  rank = NaN;
1151  return NaN;
1152  }
1153 
1154  // Compute percentile rank
1155  rank = (double(p) / 100.) * double(m + 1);
1156 
1157  // Split rank into integer and decimal components
1158  int k = int(rank);
1159  double d = rank - k;
1160 
1161  // Compute percentile value according to NIST method
1162  // (cf. http://en.wikipedia.org/wiki/Percentile#Definition_of_the_NIST_method )
1163  if (k == 0) {
1164  return MinAbs::Calculate(n, data, mask);
1165  } else if (k >= m) {
1166  return MaxAbs::Calculate(n, data, mask);
1167  } else {
1168  // Copy unmasked data only
1169  double *v = new double[m];
1170  if (mask) {
1171  m = 0;
1172  for (int i = 0; i < n; ++i) {
1173  if (mask[i]) v[m++] = abs(static_cast<double>(data[i]));
1174  }
1175  } else {
1176  for (int i = 0; i < n; ++i) {
1177  v[i] = abs(static_cast<double>(data[i]));
1178  }
1179  }
1180  // Sort data below k + 1
1181  partial_sort(v, v + k + 1, v + m);
1182  // Compute percentile value
1183  double percentile = v[k - 1] + d * (v[k] - v[k - 1]);
1184  // Free (partially) sorted data copy
1185  delete[] v;
1186  return percentile;
1187  }
1188  }
1189 
1190  template <class T>
1191  static double Calculate(int p, int n, const T *data, const bool *mask = nullptr)
1192  {
1193  double rank;
1194  return Calculate(p, rank, n, data, mask);
1195  }
1196 
1197  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
1198  {
1199  values.resize(1);
1200  values[0] = Calculate(_P, n, data, mask);
1201  }
1202 
1203  // Add support for vtkDataArray
1204 #if MIRTK_Image_WITH_VTK
1205 
1206  static double Calculate(int p, double &rank, vtkDataArray *data, const bool *mask = nullptr)
1207  {
1208  const int n = static_cast<int>(data->GetNumberOfTuples());
1209  const void *ptr = data->GetVoidPointer(0);
1210  switch (data->GetDataType()) {
1211  case VTK_SHORT: return Calculate(p, rank, n, static_cast<const short *>(ptr), mask);
1212  case VTK_INT: return Calculate(p, rank, n, static_cast<const int *>(ptr), mask);
1213  case VTK_FLOAT: return Calculate(p, rank, n, static_cast<const float *>(ptr), mask);
1214  case VTK_DOUBLE: return Calculate(p, rank, n, static_cast<const double *>(ptr), mask);
1215  default:
1216  cerr << "Unsupported vtkDataArray type: " << data->GetDataType() << endl;
1217  exit(1);
1218  }
1219  rank = numeric_limits<double>::quiet_NaN();
1220  return numeric_limits<double>::quiet_NaN();
1221  }
1222 
1223  static double Calculate(int p, vtkDataArray *data, const bool *mask = nullptr)
1224  {
1225  double rank;
1226  return Calculate(p, rank, data, mask);
1227  }
1228 
1229 #endif
1230 };
1231 
1232 // -----------------------------------------------------------------------------
1233 /// Lower percentile mean calculation
1235 {
1236 public:
1237 
1238  LowerPercentileMean(int p, const char *desc = nullptr, const Array<string> *names = nullptr)
1239  :
1240  Percentile(p, desc, names)
1241  {
1242  if (!desc) {
1243  _Description = "Mean below ";
1244  _Description += ToString(p);
1245  if (p == 1) _Description += "st";
1246  else if (p == 2) _Description += "nd";
1247  else if (p == 3) _Description += "rd";
1248  else _Description += "th";
1249  _Description += " percentile";
1250  }
1251  if (!names) {
1252  _Names[0] = "Mean <";
1253  _Names[0] += ToString(p);
1254  if (p == 1) _Names[0] += "st";
1255  else if (p == 2) _Names[0] += "nd";
1256  else if (p == 3) _Names[0] += "rd";
1257  else _Names[0] += "th";
1258  _Names[0] += "%";
1259  }
1260  }
1261 
1262  template <class T>
1263  static double Calculate(int p, int n, const T *data, const bool *mask = nullptr)
1264  {
1265  const double threshold = Percentile::Calculate(p, n, data, mask);
1266 
1267  int m = 0;
1268  double v = 0., d;
1269 
1270  if (mask) {
1271  for (int i = 0; i < n; ++i) {
1272  if (mask[i]) {
1273  d = static_cast<double>(data[i]);
1274  if (d <= threshold) {
1275  ++m;
1276  v += (d - v) / m;
1277  }
1278  }
1279  }
1280  } else {
1281  for (int i = 0; i < n; ++i) {
1282  d = static_cast<double>(data[i]);
1283  if (d <= threshold) {
1284  ++m;
1285  v += (d - v) / m;
1286  }
1287  }
1288  }
1289 
1290  return (m < 1 ? NaN : v);
1291  }
1292 
1293  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
1294  {
1295  values.resize(1);
1296  values[0] = Calculate(_P, n, data, mask);
1297  }
1298 
1299  // Add support for vtkDataArray
1300 #if MIRTK_Image_WITH_VTK
1301 
1302  static double Calculate(int p, vtkDataArray *data, const bool *mask = nullptr)
1303  {
1304  const int n = static_cast<int>(data->GetNumberOfTuples());
1305  const void *ptr = data->GetVoidPointer(0);
1306  switch (data->GetDataType()) {
1307  case VTK_SHORT: return Calculate(p, n, static_cast<const short *>(ptr), mask);
1308  case VTK_INT: return Calculate(p, n, static_cast<const int *>(ptr), mask);
1309  case VTK_FLOAT: return Calculate(p, n, static_cast<const float *>(ptr), mask);
1310  case VTK_DOUBLE: return Calculate(p, n, static_cast<const double *>(ptr), mask);
1311  default:
1312  cerr << "Unsupported vtkDataArray type: " << data->GetDataType() << endl;
1313  exit(1);
1314  }
1315  return NaN;
1316  }
1317 
1318 #endif // MIRTK_Image_WITH_VTK
1319 };
1320 
1321 // -----------------------------------------------------------------------------
1322 /// Upper percentile mean calculation
1324 {
1325 public:
1326 
1327  UpperPercentileMean(int p, const char *desc = nullptr, const Array<string> *names = nullptr)
1328  :
1329  Percentile(p, desc, names)
1330  {
1331  if (!desc) {
1332  _Description = "Mean above ";
1333  _Description += ToString(p);
1334  if (p == 1) _Description += "st";
1335  else if (p == 2) _Description += "nd";
1336  else if (p == 3) _Description += "rd";
1337  else _Description += "th";
1338  _Description += " percentile";
1339  }
1340  if (!names) {
1341  _Names[0] = "Mean >";
1342  _Names[0] += ToString(p);
1343  if (p == 1) _Names[0] += "st";
1344  else if (p == 2) _Names[0] += "nd";
1345  else if (p == 3) _Names[0] += "rd";
1346  else _Names[0] += "th";
1347  _Names[0] += "%";
1348  }
1349  }
1350 
1351  template <class T>
1352  static double Calculate(int p, int n, const T *data, const bool *mask = nullptr)
1353  {
1354  const double threshold = Percentile::Calculate(p, n, data, mask);
1355 
1356  int m = 0;
1357  double v = 0., d;
1358 
1359  if (mask) {
1360  for (int i = 0; i < n; ++i) {
1361  if (mask[i]) {
1362  d = static_cast<double>(data[i]);
1363  if (d >= threshold) {
1364  ++m;
1365  v += (d - v) / m;
1366  }
1367  }
1368  }
1369  } else {
1370  for (int i = 0; i < n; ++i) {
1371  d = static_cast<double>(data[i]);
1372  if (d >= threshold) {
1373  ++m;
1374  v += (d - v) / m;
1375  }
1376  }
1377  }
1378 
1379  return (m < 1 ? NaN : v);
1380  }
1381 
1382  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
1383  {
1384  values.resize(1);
1385  values[0] = Calculate(_P, n, data, mask);
1386  }
1387 
1388  // Add support for vtkDataArray
1389 #if MIRTK_Image_WITH_VTK
1390 
1391  static double Calculate(int p, vtkDataArray *data, const bool *mask = nullptr)
1392  {
1393  const int n = static_cast<int>(data->GetNumberOfTuples());
1394  const void *ptr = data->GetVoidPointer(0);
1395  switch (data->GetDataType()) {
1396  case VTK_SHORT: return Calculate(p, n, static_cast<const short *>(ptr), mask);
1397  case VTK_INT: return Calculate(p, n, static_cast<const int *>(ptr), mask);
1398  case VTK_FLOAT: return Calculate(p, n, static_cast<const float *>(ptr), mask);
1399  case VTK_DOUBLE: return Calculate(p, n, static_cast<const double *>(ptr), mask);
1400  default:
1401  cerr << "Unsupported vtkDataArray type: " << data->GetDataType() << endl;
1402  exit(1);
1403  }
1404  return NaN;
1405  }
1406 
1407 #endif // MIRTK_Image_WITH_VTK
1408 };
1409 
1410 // -----------------------------------------------------------------------------
1411 /// Robust mean calculation, ignoring values below and above a certain percentile
1412 class RobustMean : public Percentile
1413 {
1414 public:
1415 
1416  RobustMean(int p, const char *desc = nullptr, const Array<string> *names = nullptr)
1417  :
1418  Percentile(p, desc, names)
1419  {
1420  if (!desc) {
1421  _Description = "Mean excl. ";
1422  _Description += ToString(p);
1423  if (p == 1) _Description += "st";
1424  else if (p == 2) _Description += "nd";
1425  else if (p == 3) _Description += "rd";
1426  else _Description += "th";
1427  _Description += " percentile";
1428  }
1429  if (!names) {
1430  _Names[0] = "Mean <>";
1431  _Names[0] += ToString(p);
1432  if (p == 1) _Names[0] += "st";
1433  else if (p == 2) _Names[0] += "nd";
1434  else if (p == 3) _Names[0] += "rd";
1435  else _Names[0] += "th";
1436  _Names[0] += "%";
1437  }
1438  }
1439 
1440  template <class T>
1441  static double Calculate(int p, int n, const T *data, const bool *mask = nullptr)
1442  {
1443  const double min = Percentile::Calculate( p, n, data, mask);
1444  const double max = Percentile::Calculate(100 - p, n, data, mask);
1445 
1446  int m = 0;
1447  double v = 0., d;
1448 
1449  if (mask) {
1450  for (int i = 0; i < n; ++i) {
1451  if (mask[i]) {
1452  d = static_cast<double>(data[i]);
1453  if (min <= d && d <= max) {
1454  ++m;
1455  v += (d - v) / m;
1456  }
1457  }
1458  }
1459  } else {
1460  for (int i = 0; i < n; ++i) {
1461  d = static_cast<double>(data[i]);
1462  if (min <= d && d <= max) {
1463  ++m;
1464  v += (d - v) / m;
1465  }
1466  }
1467  }
1468 
1469  return (m < 1 ? NaN : v);
1470  }
1471 
1472  void Evaluate(Array<double> &values, int n, const double *data, const bool *mask = nullptr) const
1473  {
1474  values.resize(1);
1475  values[0] = Calculate(_P, n, data, mask);
1476  }
1477 
1478  // Add support for vtkDataArray
1479 #if MIRTK_Image_WITH_VTK
1480 
1481  static double Calculate(int p, vtkDataArray *data, const bool *mask = nullptr)
1482  {
1483  const int n = static_cast<int>(data->GetNumberOfTuples());
1484  const void *ptr = data->GetVoidPointer(0);
1485  switch (data->GetDataType()) {
1486  case VTK_SHORT: return Calculate(p, n, static_cast<const short *>(ptr), mask);
1487  case VTK_INT: return Calculate(p, n, static_cast<const int *>(ptr), mask);
1488  case VTK_FLOAT: return Calculate(p, n, static_cast<const float *>(ptr), mask);
1489  case VTK_DOUBLE: return Calculate(p, n, static_cast<const double *>(ptr), mask);
1490  default:
1491  cerr << "Unsupported vtkDataArray type: " << data->GetDataType() << endl;
1492  exit(1);
1493  }
1494  return NaN;
1495  }
1496 
1497 #endif // MIRTK_Image_WITH_VTK
1498 };
1499 
1500 
1501 } } } // namespace mirtk::data::statistic
1502 
1503 #endif // MIRTK_DataStatistics_H
1504 
Get minimum and maximum values.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
Statistic(int nvalues, const char *desc=nullptr, const Array< string > *names=nullptr)
Constructor.
Count number of masked values (mask != false)
virtual void PrintValues(ostream &os=cout, int digits=5, const char *delimiter=",") const
Print delimited statistic values to output stream.
Percentile calculation.
Base class of all data operations.
Definition: DataOp.h:61
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
Mean absolute difference/deviation around the median.
Defines base class and I/O functions for arbitrary 1D data sequences.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
virtual void PrintHeader(ostream &os=cout, const char *delimiter=",") const
Print column names of statistic values to output stream.
Mean absolute difference/deviation around the mean.
void Value(double v)
Set value of statistic (first entry of _Values vector)
Mean absolute difference/deviation around the specified value.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
Robust evaluation of standard deviation.
MeanVar(int nvalues, const char *desc=nullptr, const Array< string > *names=nullptr)
Constructor.
Absolute value percentile calculation.
Robust variance evaluation.
virtual void Print(ostream &os=cout, int digits=5, const char *prefix="") const
Print statistic to output stream as "<desc> = <value>".
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
Median value (50th percentile)
Base class of all data statistics.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
virtual const double & Value() const
Get maximum absolute value.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
virtual void Process(int n, double *data, bool *mask=nullptr)
Process given data.
Definition: IOConfig.h:41
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
MIRTKCU_API bool IsInf(double x)
Check if floating point value represents infinity.
Definition: Math.h:103
virtual void Print(ostream &os=cout, int=5, const char *prefix="") const
Print statistic to output stream as "<desc> = <value>".
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
Lower percentile mean calculation.
Robust mean calculation, ignoring values below and above a certain percentile.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
Get minimum absolute value.
Robust mean/average evaluation.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
Base class of statistics which compute mean, variance, and/or standard deviation. ...
string ToString(const EnergyMeasure &value, int w, char c, bool left)
Convert energy measure enumeration value to string.
mirtkOnOffMacro(Hidden)
Hide/Show statistic in output report.
virtual ~Statistic()
Destructor.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
Upper percentile mean calculation.
virtual void Evaluate(Array< double > &, int, const double *, const bool *=nullptr) const =0
Evaluate statistic for given data.
Robust evaluation of Gaussian mean and standard deviation.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
T & NthElement(Array< T > &values, int n)
Definition: Algorithm.h:181
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
MIRTK_Common_EXPORT const double inf
Positive infinity.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.
virtual void PrintValues(ostream &os=cout, int=5, const char *delimiter=",") const
Print delimited statistic values to output stream.
void Evaluate(Array< double > &values, int n, const double *data, const bool *mask=nullptr) const
Evaluate statistic for given data.