[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

accumulator.hxx VIGRA

1 /************************************************************************/
2 /* */
3 /* Copyright 2011-2012 by Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 #ifndef VIGRA_ACCUMULATOR_HXX
37 #define VIGRA_ACCUMULATOR_HXX
38 
39 #ifdef _MSC_VER
40 #pragma warning (disable: 4503)
41 #endif
42 
43 #include "accumulator-grammar.hxx"
44 #include "config.hxx"
45 #include "metaprogramming.hxx"
46 #include "bit_array.hxx"
47 #include "static_assert.hxx"
48 #include "mathutil.hxx"
49 #include "utilities.hxx"
50 #include "multi_iterator_coupled.hxx"
51 #include "matrix.hxx"
52 #include "multi_math.hxx"
53 #include "eigensystem.hxx"
54 #include "histogram.hxx"
55 #include "polygon.hxx"
56 #include "functorexpression.hxx"
57 #include "labelimage.hxx"
58 #include <algorithm>
59 #include <iostream>
60 
61 namespace vigra {
62 
63 /** \defgroup FeatureAccumulators Feature Accumulators
64 
65 The namespace <tt>vigra::acc</tt> provides the function \ref vigra::acc::extractFeatures() along with associated statistics functors and accumulator classes. Together, they provide a framework for efficient compution of a wide variety of statistical features, both globally for an entire image, and locally for each region defined by a label array. Many different statistics can be composed out of a small number of fundamental statistics and suitable modifiers. The user simply selects the desired statistics by means of their <i>tags</i> (see below), and a template meta-program automatically generates an efficient functor that computes exactly those statistics.
66 
67 The function \ref acc::extractFeatures() "extractFeatures()" scans the data in as few passes as the selected statstics permit (usually one or two passes are sufficient). Statistics are computed by accurate incremental algorithms, whose internal state is maintained by accumulator objects. The state is updated by passing data to the accumulator one sample at a time. Accumulators are grouped within an accumulator chain. Dependencies between accumulators in the accumulator chain are automatically resolved and missing dependencies are inserted. For example, to compute the mean, you also need to count the number of samples. This allows accumulators to offload some of their computations on other accumulators, making the algorithms more efficient. Each accumulator only sees data in the appropriate pass through the data, called its "working pass".
68 
69 <b>\#include</b> <vigra/accumulator.hxx>
70 
71 
72 <b>Basic statistics:</b>
73  - PowerSum<N> (computes @f$ \sum_i x_i^N @f$)
74  - AbsPowerSum<N> (computes @f$ \sum_i |x_i|^N @f$)
75  - Skewness, UnbiasedSkewness
76  - Kurtosis, UnbiasedKurtosis
77  - Minimum, Maximum
78  - FlatScatterMatrix (flattened upper-triangular part of scatter matrix)
79  - 4 histogram classes (see \ref histogram "below")
80  - StandardQuantiles (0%, 10%, 25%, 50%, 75%, 90%, 100%)
81  - ArgMinWeight, ArgMaxWeight (store data or coordinate where weight assumes its minimal or maximal value)
82  - CoordinateSystem (identity matrix of appropriate size)
83 
84  <b>Modifiers:</b> (S is the statistc to be modified)
85  - Normalization
86  <table border="0">
87  <tr><td> DivideByCount<S> </td><td> S/Count </td></tr>
88  <tr><td> RootDivideByCount<S> </td><td> sqrt( S/Count ) </td></tr>
89  <tr><td> DivideUnbiased<S> </td><td> S/(Count-1) </td></tr>
90  <tr><td> RootDivideUnbiased<S> &nbsp; &nbsp; </td><td> sqrt( S/(Count-1) ) </td></tr>
91  </table>
92  - Data preparation:
93  <table border="0">
94  <tr><td> Central<S> </td><td> substract mean before computing S </td></tr>
95  <tr><td> Principal<S> </td><td> project onto PCA eigenvectors </td></tr>
96  <tr><td> Whitened<S> &nbsp; &nbsp; </td><td> scale to unit variance after PCA </td></tr>
97  <tr><td> Coord<S> </td><td> compute S from pixel coordinates rather than from pixel values </td></tr>
98  <tr><td> Weighted<S> </td><td> compute weighted version of S </td></tr>
99  <tr><td> Global<S> </td><td> compute S globally rather than per region (per region is default if labels are given) </td></tr>
100  </table>
101 
102  Aliases for many important features are implemented (mainly as <tt>typedef FullName Alias</tt>). The alias names are equivalent to full names. Below are some examples for supported alias names. A full list of all available statistics and alias names can be found in the namespace reference <tt>vigra::acc</tt>. These examples also show how to compose statistics from the fundamental statistics and modifiers:
103 
104  <table border="0">
105  <tr><th> Alias </th><th> Full Name </th></tr>
106  <tr><td> Count </td><td> PowerSum<0> </td></tr>
107  <tr><td> Sum </td><td> PowerSum<1> </td></tr>
108  <tr><td> SumOfSquares </td><td> PowerSum<2> </td></tr>
109  <tr><td> Mean </td><td> DivideByCount<PowerSum<1>> </td></tr>
110  <tr><td> RootMeanSquares &nbsp; </td><td> RootDivideByCount<PowerSum<2>> </td></tr>
111  <tr><td> Moment<N> </td><td> DivideByCount<PowerSum<N>> </td></tr>
112  <tr><td> Variance </td><td> DivideByCount<Central<PowerSum<2>>> </td></tr>
113  <tr><td> StdDev </td><td> RootDivideByCount<Central<PowerSum<2>>> </td></tr>
114  <tr><td> Covariance </td><td> DivideByCount<FlatScatterMatrix> </td></tr>
115  <tr><td> RegionCenter </td><td> Coord<Mean> </td></tr>
116  <tr><td> CenterOfMass </td><td> Weighted<Coord<Mean>> </td></tr>
117  </table>
118 
119  There are a few <b>rules for composing statistics</b>:
120  - modifiers can be specified in any order, but are internally transformed to standard order: Global<Weighted<Coord<normalization<data preparation<basic statistic
121  - only one normalization modifier and one data preparation modifier (Central or Principal or Whitened) is permitted
122  - Count ignores all modifiers except Global and Weighted
123  - Sum ignores Central and Principal, because sum would be zero
124  - ArgMinWeight and ArgMaxWeight are automatically Weighted
125 
126 
127  Here is an example how to use \ref acc::AccumulatorChain to compute statistics. (To use Weighted<> or Coord<> modifiers, see below):
128 
129  \code
130  #include <vigra/multi_array.hxx>
131  #include <vigra/impex.hxx>
132  #include <vigra/accumulator.hxx>
133  using namespace vigra::acc;
134  typedef double DataType;
135  int size = 1000;
136  vigra::MultiArray<2, DataType> data(vigra::Shape2(size, size));
137 
138  AccumulatorChain<DataType,
139  Select<Variance, Mean, StdDev, Minimum, Maximum, RootMeanSquares, Skewness, Covariance> >
140  a;
141 
142  std::cout << "passes required: " << a.passesRequired() << std::endl;
143  extractFeatures(data.begin(), data.end(), a);
144 
145  std::cout << "Mean: " << get<Mean>(a) << std::endl;
146  std::cout << "Variance: " << get<Variance>(a) << std::endl;
147  \endcode
148 
149  The \ref acc::AccumulatorChain object contains the selected statistics and their dependencies. Statistics have to be wrapped with \ref acc::Select. The statistics are computed with the acc::extractFeatures function and the statistics can be accessed with acc::get .
150 
151  Rules and notes:
152  - order of statistics in Select<> is arbitrary
153  - up to 20 statistics in Select<>, but Select<> can be nested
154  - dependencies are automatically inserted
155  - duplicates are automatically removed
156  - extractFeatures() does as many passes through the data as necessary
157  - each accumulator only sees data in the appropriate pass (its "working pass")
158 
159  The Accumulators can also be used with vector-valued data (vigra::RGBValue, vigra::TinyVector, vigra::MultiArray or vigra::MultiArrayView):
160 
161  \code
162  typedef vigra::RGBValue<double> DataType;
163  AccumulatorChain<DataType, Select<...> > a;
164  ...
165  \endcode
166 
167  To compute <b>weighted statistics</b> (Weighted<>) or <b>statistics over coordinates</b> (Coord<>), the accumulator chain can be used with several coupled arrays, one for the data and another for the weights and/or the labels. "Coupled" means that statistics are computed over the corresponding elements of the involved arrays. This is internally done by means of \ref CoupledScanOrderIterator and \ref vigra::CoupledHandle which provide simultaneous access to several arrays (e.g. weight and data) and corresponding coordinates. The types of the coupled arrays are best specified by means of the helper class \ref vigra::CoupledArrays :
168 
169  \code
170  vigra::MultiArray<3, RGBValue<unsigned char> > data(...);
171  vigra::MultiArray<3, double> weights(...);
172 
173  AccumulatorChain<CoupledArrays<3, RGBValue<unsigned char>, double>,
174  Select<...> > a;
175  \endcode
176 
177 This works likewise for label images which are needed for region statistics (see below). The indxx of the array holding data, weights, or labels respectively can be specified inside the Select wrapper. These <b>index specifiers</b> are: (INDEX is of type int)
178  - DataArg<INDEX>: data are in array 'INDEX' (default INDEX=1)
179  - LabelArg<INDEX>: labels are in array 'INDEX' (default INDEX=2)
180  - WeightArg<INDEX>: weights are in array 'INDEX' (default INDEX=rightmost index)
181 
182 Pixel coordinates are always at index 0. To collect statistics, you simply pass all arrays to the <tt>extractFeatures()</tt> function:
183  \code
184  using namespace vigra::acc;
185  vigra::MultiArray<3, double> data(...), weights(...);
186 
187  AccumulatorChain<CoupledArrays<3, double, double>, // two 3D arrays for data and weights
188  Select<DataArg<1>, WeightArg<2>, // in which array to look (coordinates are always arg 0)
189  Mean, Variance, //statistics over values
190  Coord<Mean>, Coord<Variance>, //statistics over coordinates,
191  Weighted<Mean>, Weighted<Variance>, //weighted values,
192  Weighted<Coord<Mean> > > > //weighted coordinates.
193  a;
194 
195  extractFeatures(data, weights, a);
196  \endcode
197 
198  This even works for a single array, which is useful if you want to combine values with coordinates. For example, to find the location of the minimum element in an array, you interpret the data as weights and select the <tt>Coord<ArgMinWeight></tt> statistic (note that the version of <tt>extractFeatures()</tt> below only works in conjunction with <tt>CoupledArrays</tt>, despite the fact that there is only one array involved):
199  \code
200  using namespace vigra::acc;
201  vigra::MultiArray<3, double> data(...);
202 
203  AccumulatorChain<CoupledArrays<3, double>,
204  Select<WeightArg<1>, // we interprete the data as weights
205  Coord<ArgMinWeight> > > // and look for the coordinate with minimal weight
206  a;
207 
208  extractFeatures(data, a);
209  std::cout << "minimum is at " << get<Coord<ArgMinWeight> >(a) << std::endl;
210  \endcode
211 
212  To compute <b>region statistics</b>, you use \ref acc::AccumulatorChainArray. Regions are defined by means of a label array whose elements specify the region ID of the corresponding point. Therefore, you will always need at least two arrays here, which are again best specified using the <tt>CoupledArrays</tt> helper:
213 
214  \code
215  using namespace vigra::acc;
216  vigra::MultiArray<3, double> data(...);
217  vigra::MultiArray<3, int> labels(...);
218 
219  AccumulatorChainArray<CoupledArrays<3, double, int>,
220  Select<DataArg<1>, LabelArg<2>, // in which array to look (coordinates are always arg 0)
221  Mean, Variance, //per-region statistics over values
222  Coord<Mean>, Coord<Variance>, //per-region statistics over coordinates
223  Global<Mean>, Global<Variance> > > //global statistics
224  a;
225 
226  a.ignoreLabel(0); //statistics will not be computed for region 0 (e.g. background)
227 
228  extractFeatures(data, labels, a);
229 
230  int regionlabel = ...;
231  std::cout << get<Mean>(a, regionlabel) << std::endl; //get Mean of region with label 'regionlabel'
232  \endcode
233 
234 
235  In some application it will be known only at run-time which statistics have to be computed. An Accumulator with <b>run-time activation</b> is provided by the \ref acc::DynamicAccumulatorChain class. One specifies a set of statistics at compile-time and from this set one can activate the needed statistics at run-time:
236 
237  \code
238  using namespace vigra::acc;
239  vigra::MultiArray<2, double> data(...);
240  DynamicAccumulatorChain<double,
241  Select<Mean, Minimum, Maximum, Variance, StdDev> > a; // at compile-time
242  activate<Mean>(a); //at run-time
243  a.activate("Minimum"); //same as activate<Minimum>(a) (alias names are not recognized)
244 
245  extractFeatures(data.begin(), data.end(), a);
246  std::cout << "Mean: " << get<Mean>(a) << std::endl; //ok
247  //std::cout << "Maximum: " << get<Maximum>(a) << std::endl; // run-time error because Maximum not activated
248  \endcode
249 
250  Likewise, for run-time activation of region statistics, use \ref acc::DynamicAccumulatorChainArray.
251 
252  <b>Accumulator merging</b> (e.g. for parallelization or hierarchical segmentation) is possible for many accumulators:
253 
254  \code
255  using namespace vigra::acc;
256  vigra::MultiArray<2, double> data(...);
257  AccumulatorChain<double, Select<Mean, Variance, Skewness> > a, a1, a2;
258 
259  extractFeatures(data.begin(), data.end(), a); //process entire data set at once
260  extractFeatures(data.begin(), data.begin()+data.size()/2, a1); //process first half
261  extractFeatures(data.begin()+data.size()/2, data.end(), a2); //process second half
262  a1 += a2; // merge: a1 now equals a0 (within numerical tolerances)
263  \endcode
264 
265  Not all statistics can be merged (e.g. Principal<A> usually cannot, except for some important specializations). A statistic can be merged if the "+=" operator is supported (see the documentation of that particular statistic). If the accumulator chain only requires one pass to collect the data, it is also possible to just apply the extractFeatures() function repeatedly:
266 
267  \code
268  using namespace vigra::acc;
269  vigra::MultiArray<2, double> data(...);
270  AccumulatorChain<double, Select<Mean, Variance> > a;
271 
272  extractFeatures(data.begin(), data.begin()+data.size()/2, a); // this works because
273  extractFeatures(data.begin()+data.size()/2, data.end(), a); // all statistics only need pass 1
274  \endcode
275 
276  More care is needed to merge coordinate-based statistics. By default, all coordinate statistics are computed in the local coordinate system of the current region of interest. That is, the upper left corner of the ROI has the coordinate (0, 0) by default. This behavior is not desirable when you want to merge coordinate statistics from different ROIs: then, all accumulators should use the same coordinate system, usually the global system of the entire dataset. This can be achieved by the <tt>setCoordinateOffset()</tt> function. The following code demonstrates this for the <tt>RegionCenter</tt> statistic:
277 
278  \code
279  using namespace vigra;
280  using namespace vigra::acc;
281 
282  MultiArray<2, double> data(width, height);
283  MultiArray<2, int> labels(width, height);
284 
285  AccumulatorChainArray<CoupledArrays<2, double, int>,
286  Select<DataArg<1>, LabelArg<2>,
287  RegionCenter> >
288  a1, a2;
289 
290  // a1 is responsible for the left half of the image. The local coordinate system of this ROI
291  // happens to be identical to the global coordinate system, so the offset is zero.
292  Shape2 origin(0,0);
293  a1.setCoordinateOffset(origin);
294  extractFeatures(data.subarray(origin, Shape2(width/2, height)),
295  labels.subarray(origin, Shape2(width/2, height)),
296  a1);
297 
298  // a2 is responsible for the right half, so the offset of the local coordinate system is (width/2, 0)
299  origin = Shape2(width/2, 0);
300  a2.setCoordinateOffset(origin);
301  extractFeatures(data.subarray(origin, Shape2(width, height)),
302  labels.subarray(origin, Shape2(width, height)),
303  a2);
304 
305  // since both accumulators worked in the same global coordinate system, we can safely merge them
306  a1.merge(a2);
307  \endcode
308 
309  When you compute region statistics in ROIs, it is sometimes desirable to use a local region labeling in each ROI. In this way, the labels of each ROI cover a consecutive range of numbers starting with 0. This can save a lot of memory, because <tt>AccumulatorChainArray</tt> internally uses dense arrays -- accumulators will be allocated for all labels from 0 to the maxmimum label, even when many of them are unused. This is avoided by a local labeling. However, this means that label 1 (say) may refer to two different regions in different ROIs. To adjust for this mismatch, you can pass a label mapping to <tt>merge()</tt> that provides a global label for each label of the accumulator to be merged. Thus, each region on the right hand side will be merged into the left-hand-side accumulator with the given <i>global</i> label. For example, let us assume that the left and right half of the image contain just one region and background. Then, the accumulators of both ROIs have the label 0 (background) and 1 (the region). Upon merging, the region from the right ROI should be given the global label 2, whereas the background should keep its label 0. This is achieved like this:
310 
311  \code
312  std::vector<int> labelMapping(2);
313  labelMapping[0] = 0; // background keeps label 0
314  labelMapping[1] = 2; // local region 1 becomes global region 2
315 
316  a1.merge(a2, labelMapping);
317  \endcode
318 
319  \anchor histogram
320  Four kinds of <b>histograms</b> are currently implemented:
321 
322  <table border="0">
323  <tr><td> IntegerHistogram </td><td> Data values are equal to bin indices </td></tr>
324  <tr><td> UserRangeHistogram </td><td> User provides lower and upper bounds for linear range mapping from values to indices. </td></tr>
325  <tr><td> AutoRangeHistogram </td><td> Range mapping bounds are defiend by minimum and maximum of the data (2 passes needed!) </td></tr>
326  <tr><td> GlobalRangeHistogram &nbsp; </td><td> Likewise, but use global min/max rather than region min/max as AutoRangeHistogram will </td></tr>
327  </table>
328 
329 
330 
331  - The number of bins is specified at compile time (as template parameter int BinCount) or at run-time (if BinCount is zero at compile time). In the first case the return type of the accumulator is TinyVector<double, BinCount> (number of bins cannot be changed). In the second case, the return type is MultiArray<1, double> and the number of bins must be set before seeing data (see example below).
332  - If UserRangeHistogram is used, the bounds for the linear range mapping from values to indices must be set before seeing data (see below).
333  - Options can be set by passing an instance of HistogramOptions to the accumulator chain (same options for all histograms in the chain) or by directly calling the appropriate member functions of the accumulators.
334  - Merging is supported if the range mapping of the histograms is the same.
335  - Histogram accumulators have two members for outliers (left_outliers, right_outliers).
336 
337  With the StandardQuantiles class, <b>histogram quantiles</b> (0%, 10%, 25%, 50%, 75%, 90%, 100%) are computed from a given histgram using linear interpolation. The return type is TinyVector<double, 7> .
338 
339  \anchor acc_hist_options Usage:
340  \code
341  using namespace vigra::acc;
342  typedef double DataType;
343  vigra::MultiArray<2, DataType> data(...);
344 
345  typedef UserRangeHistogram<40> SomeHistogram; //binCount set at compile time
346  typedef UserRangeHistogram<0> SomeHistogram2; // binCount must be set at run-time
347  typedef AutoRangeHistogram<0> SomeHistogram3;
348  typedef StandardQuantiles<SomeHistogram3> Quantiles3;
349 
350  AccumulatorChain<DataType, Select<SomeHistogram, SomeHistogram2, SomeHistogram3, Quantiles3> > a;
351 
352  //set options for all histograms in the accumulator chain:
353  vigra::HistogramOptions histogram_opt;
354  histogram_opt = histogram_opt.setBinCount(50);
355  //histogram_opt = histogram_opt.setMinMax(0.1, 0.9); // this would set min/max for all three histograms, but range bounds
356  // shall be set automatically by min/max of data for SomeHistogram3
357  a.setHistogramOptions(histogram_opt);
358 
359  // set options for a specific histogram in the accumulator chain:
360  getAccumulator<SomeHistogram>(a).setMinMax(0.1, 0.9); // number of bins must be set before setting min/max
361  getAccumulator<SomeHistogram2>(a).setMinMax(0.0, 1.0);
362 
363  extractFeatures(data.begin(), data.end(), a);
364 
365  vigra::TinyVector<double, 40> hist = get<SomeHistogram>(a);
366  vigra::MultiArray<1, double> hist2 = get<SomeHistogram2>(a);
367  vigra::TinyVector<double, 7> quant = get<Quantiles3>(a);
368  double right_outliers = getAccumulator<SomeHistogram>(a).right_outliers;
369  \endcode
370 
371 
372 
373 */
374 
375 
376 /** This namespace contains the accumulator classes, fundamental statistics and modifiers. See \ref FeatureAccumulators for examples of usage.
377 */
378 namespace acc {
379 
380 /****************************************************************************/
381 /* */
382 /* infrastructure */
383 /* */
384 /****************************************************************************/
385 
386  /// \brief Wrapper for MakeTypeList that additionally performs tag standardization.
387 
388 template <class T01=void, class T02=void, class T03=void, class T04=void, class T05=void,
389  class T06=void, class T07=void, class T08=void, class T09=void, class T10=void,
390  class T11=void, class T12=void, class T13=void, class T14=void, class T15=void,
391  class T16=void, class T17=void, class T18=void, class T19=void, class T20=void>
392 struct Select
393 : public MakeTypeList<
394  typename StandardizeTag<T01>::type, typename StandardizeTag<T02>::type, typename StandardizeTag<T03>::type,
395  typename StandardizeTag<T04>::type, typename StandardizeTag<T05>::type, typename StandardizeTag<T06>::type,
396  typename StandardizeTag<T07>::type, typename StandardizeTag<T08>::type, typename StandardizeTag<T09>::type,
397  typename StandardizeTag<T10>::type, typename StandardizeTag<T11>::type, typename StandardizeTag<T12>::type,
398  typename StandardizeTag<T13>::type, typename StandardizeTag<T14>::type, typename StandardizeTag<T15>::type,
399  typename StandardizeTag<T16>::type, typename StandardizeTag<T17>::type, typename StandardizeTag<T18>::type,
400  typename StandardizeTag<T19>::type, typename StandardizeTag<T20>::type
401  >
402 {};
403 
404  // enable nesting of Select<> expressions
405 template <class T01, class T02, class T03, class T04, class T05,
406  class T06, class T07, class T08, class T09, class T10,
407  class T11, class T12, class T13, class T14, class T15,
408  class T16, class T17, class T18, class T19, class T20>
409 struct StandardizeTag<Select<T01, T02, T03, T04, T05,
410  T06, T07, T08, T09, T10,
411  T11, T12, T13, T14, T15,
412  T16, T17, T18, T19, T20>,
413  Select<T01, T02, T03, T04, T05,
414  T06, T07, T08, T09, T10,
415  T11, T12, T13, T14, T15,
416  T16, T17, T18, T19, T20> >
417 {
418  typedef typename Select<T01, T02, T03, T04, T05,
419  T06, T07, T08, T09, T10,
420  T11, T12, T13, T14, T15,
421  T16, T17, T18, T19, T20>::type type;
422 };
423 
424 struct AccumulatorBegin
425 {
426  typedef Select<> Dependencies;
427 
428  static std::string name()
429  {
430  return "AccumulatorBegin (internal)";
431  // static const std::string n("AccumulatorBegin (internal)");
432  // return n;
433  }
434 
435  template <class T, class BASE>
436  struct Impl
437  : public BASE
438  {};
439 };
440 
441 
442 struct AccumulatorEnd;
443 struct DataArgTag;
444 struct WeightArgTag;
445 struct LabelArgTag;
446 struct CoordArgTag;
447 struct LabelDispatchTag;
448 
449 template <class T, class TAG, class CHAIN>
450 struct HandleArgSelector; // find the correct handle in a CoupledHandle
451 
452 struct Error__Global_statistics_are_only_defined_for_AccumulatorChainArray;
453 
454 /** \brief Specifies index of labels in CoupledHandle.
455 
456  LabelArg<INDEX> tells the acc::AccumulatorChainArray which index of the Handle contains the labels. (Note that coordinates are always index 0)
457  */
458 template <int INDEX>
459 class LabelArg
460 {
461  public:
462  typedef Select<> Dependencies;
463 
464  static std::string name()
465  {
466  return std::string("LabelArg<") + asString(INDEX) + "> (internal)";
467  // static const std::string n = std::string("LabelArg<") + asString(INDEX) + "> (internal)";
468  // return n;
469  }
470 
471  template <class T, class BASE>
472  struct Impl
473  : public BASE
474  {
475  typedef LabelArgTag Tag;
476  typedef void value_type;
477  typedef void result_type;
478 
479  static const int value = INDEX;
480  static const unsigned int workInPass = 0;
481  };
482 };
483 
484 template <int INDEX>
485 class CoordArg
486 {
487  public:
488  typedef Select<> Dependencies;
489 
490  static std::string name()
491  {
492  return std::string("CoordArg<") + asString(INDEX) + "> (internal)";
493  // static const std::string n = std::string("CoordArg<") + asString(INDEX) + "> (internal)";
494  // return n;
495  }
496 
497  template <class T, class BASE>
498  struct Impl
499  : public BASE
500  {
501  typedef CoordArgTag Tag;
502  typedef void value_type;
503  typedef void result_type;
504 
505  static const int value = INDEX;
506  static const unsigned int workInPass = 0;
507  };
508 };
509 
510 template <class T, class TAG, class NEXT=AccumulatorEnd>
511 struct AccumulatorBase;
512 
513 template <class Tag, class A>
514 struct LookupTag;
515 
516 template <class Tag, class A, class TargetTag=typename A::Tag>
517 struct LookupDependency;
518 
519 #ifndef _MSC_VER // compiler bug? (causes 'ambiguous overload error')
520 
521 template <class TAG, class A>
522 typename LookupTag<TAG, A>::reference
523 getAccumulator(A & a);
524 
525 template <class TAG, class A>
526 typename LookupDependency<TAG, A>::result_type
527 getDependency(A const & a);
528 
529 #endif
530 
531 namespace acc_detail {
532 
533 /****************************************************************************/
534 /* */
535 /* internal tag handling meta-functions */
536 /* */
537 /****************************************************************************/
538 
539  // we must make sure that Arg<INDEX> tags are at the end of the chain because
540  // all other tags potentially depend on them
541 template <class T>
542 struct PushArgTagToTail
543 {
544  typedef T type;
545 };
546 
547 #define VIGRA_PUSHARGTAG(TAG) \
548 template <int INDEX, class TAIL> \
549 struct PushArgTagToTail<TypeList<TAG<INDEX>, TAIL> > \
550 { \
551  typedef typename Push<TAIL, TypeList<TAG<INDEX> > >::type type; \
552 };
553 
554 VIGRA_PUSHARGTAG(DataArg)
555 VIGRA_PUSHARGTAG(WeightArg)
556 VIGRA_PUSHARGTAG(CoordArg)
557 VIGRA_PUSHARGTAG(LabelArg)
558 
559 #undef VIGRA_PUSHARGTAG
560 
561  // Insert the dependencies of the selected functors into the TypeList and sort
562  // the list such that dependencies come after the functors using them. Make sure
563  // that each functor is contained only once.
564 template <class T>
565 struct AddDependencies;
566 
567 template <class HEAD, class TAIL>
568 struct AddDependencies<TypeList<HEAD, TAIL> >
569 {
570  typedef typename AddDependencies<TAIL>::type TailWithDependencies;
571  typedef typename StandardizeDependencies<HEAD>::type HeadDependencies;
572  typedef typename AddDependencies<HeadDependencies>::type TransitiveHeadDependencies;
573  typedef TypeList<HEAD, TransitiveHeadDependencies> HeadWithDependencies;
574  typedef typename PushUnique<HeadWithDependencies, TailWithDependencies>::type UnsortedDependencies;
575  typedef typename PushArgTagToTail<UnsortedDependencies>::type type;
576 };
577 
578 template <>
579 struct AddDependencies<void>
580 {
581  typedef void type;
582 };
583 
584  // Helper class to activate dependencies at runtime (i.e. when activate<Tag>(accu) is called,
585  // activate() must also be called for Tag's dependencies).
586 template <class Dependencies>
587 struct ActivateDependencies;
588 
589 template <class HEAD, class TAIL>
590 struct ActivateDependencies<TypeList<HEAD, TAIL> >
591 {
592  template <class Chain, class ActiveFlags>
593  static void exec(ActiveFlags & flags)
594  {
595  LookupTag<HEAD, Chain>::type::activateImpl(flags);
596  ActivateDependencies<TAIL>::template exec<Chain>(flags);
597  }
598 
599  template <class Chain, class ActiveFlags, class GlobalFlags>
600  static void exec(ActiveFlags & flags, GlobalFlags & gflags)
601  {
602  LookupTag<HEAD, Chain>::type::template activateImpl<Chain>(flags, gflags);
603  ActivateDependencies<TAIL>::template exec<Chain>(flags, gflags);
604  }
605 };
606 
607 template <class HEAD, class TAIL>
608 struct ActivateDependencies<TypeList<Global<HEAD>, TAIL> >
609 {
610  template <class Chain, class ActiveFlags, class GlobalFlags>
611  static void exec(ActiveFlags & flags, GlobalFlags & gflags)
612  {
613  LookupTag<Global<HEAD>, Chain>::type::activateImpl(gflags);
614  ActivateDependencies<TAIL>::template exec<Chain>(flags, gflags);
615  }
616 };
617 
618 template <>
619 struct ActivateDependencies<void>
620 {
621  template <class Chain, class ActiveFlags>
622  static void exec(ActiveFlags &)
623  {}
624 
625  template <class Chain, class ActiveFlags, class GlobalFlags>
626  static void exec(ActiveFlags &, GlobalFlags &)
627  {}
628 };
629 
630 template <class List>
631 struct SeparateGlobalAndRegionTags;
632 
633 template <class HEAD, class TAIL>
634 struct SeparateGlobalAndRegionTags<TypeList<HEAD, TAIL> >
635 {
636  typedef SeparateGlobalAndRegionTags<TAIL> Inner;
637  typedef TypeList<HEAD, typename Inner::RegionTags> RegionTags;
638  typedef typename Inner::GlobalTags GlobalTags;
639 };
640 
641 template <class HEAD, class TAIL>
642 struct SeparateGlobalAndRegionTags<TypeList<Global<HEAD>, TAIL> >
643 {
644  typedef SeparateGlobalAndRegionTags<TAIL> Inner;
645  typedef typename Inner::RegionTags RegionTags;
646  typedef TypeList<HEAD, typename Inner::GlobalTags> GlobalTags;
647 };
648 
649 template <int INDEX, class TAIL>
650 struct SeparateGlobalAndRegionTags<TypeList<DataArg<INDEX>, TAIL> >
651 {
652  typedef SeparateGlobalAndRegionTags<TAIL> Inner;
653  typedef TypeList<DataArg<INDEX>, typename Inner::RegionTags> RegionTags;
654  typedef TypeList<DataArg<INDEX>, typename Inner::GlobalTags> GlobalTags;
655 };
656 
657 template <int INDEX, class TAIL>
658 struct SeparateGlobalAndRegionTags<TypeList<LabelArg<INDEX>, TAIL> >
659 {
660  typedef SeparateGlobalAndRegionTags<TAIL> Inner;
661  typedef TypeList<LabelArg<INDEX>, typename Inner::RegionTags> RegionTags;
662  typedef TypeList<LabelArg<INDEX>, typename Inner::GlobalTags> GlobalTags;
663 };
664 
665 template <int INDEX, class TAIL>
666 struct SeparateGlobalAndRegionTags<TypeList<WeightArg<INDEX>, TAIL> >
667 {
668  typedef SeparateGlobalAndRegionTags<TAIL> Inner;
669  typedef TypeList<WeightArg<INDEX>, typename Inner::RegionTags> RegionTags;
670  typedef TypeList<WeightArg<INDEX>, typename Inner::GlobalTags> GlobalTags;
671 };
672 
673 template <int INDEX, class TAIL>
674 struct SeparateGlobalAndRegionTags<TypeList<CoordArg<INDEX>, TAIL> >
675 {
676  typedef SeparateGlobalAndRegionTags<TAIL> Inner;
677  typedef TypeList<CoordArg<INDEX>, typename Inner::RegionTags> RegionTags;
678  typedef TypeList<CoordArg<INDEX>, typename Inner::GlobalTags> GlobalTags;
679 };
680 
681 template <>
682 struct SeparateGlobalAndRegionTags<void>
683 {
684  typedef void RegionTags;
685  typedef void GlobalTags;
686 };
687 
688 /****************************************************************************/
689 /* */
690 /* helper classes to handle tags at runtime via strings */
691 /* */
692 /****************************************************************************/
693 
694 template <class Accumulators>
695 struct CollectAccumulatorNames;
696 
697 template <class HEAD, class TAIL>
698 struct CollectAccumulatorNames<TypeList<HEAD, TAIL> >
699 {
700  template <class BackInsertable>
701  static void exec(BackInsertable & a, bool skipInternals=true)
702  {
703  if(!skipInternals || HEAD::name().find("internal") == std::string::npos)
704  a.push_back(HEAD::name());
705  CollectAccumulatorNames<TAIL>::exec(a, skipInternals);
706  }
707 };
708 
709 template <>
710 struct CollectAccumulatorNames<void>
711 {
712  template <class BackInsertable>
713  static void exec(BackInsertable & a, bool skipInternals=true)
714  {}
715 };
716 
717 template <class T>
718 struct ApplyVisitorToTag;
719 
720 template <class HEAD, class TAIL>
721 struct ApplyVisitorToTag<TypeList<HEAD, TAIL> >
722 {
723  template <class Accu, class Visitor>
724  static bool exec(Accu & a, std::string const & tag, Visitor const & v)
725  {
726  static std::string * name = VIGRA_SAFE_STATIC(name, new std::string(normalizeString(HEAD::name())));
727  if(*name == tag)
728  {
729  v.template exec<HEAD>(a);
730  return true;
731  }
732  else
733  {
734  return ApplyVisitorToTag<TAIL>::exec(a, tag, v);
735  }
736  }
737 };
738 
739 template <>
740 struct ApplyVisitorToTag<void>
741 {
742  template <class Accu, class Visitor>
743  static bool exec(Accu & a, std::string const & tag, Visitor const & v)
744  {
745  return false;
746  }
747 };
748 
749 struct ActivateTag_Visitor
750 {
751  template <class TAG, class Accu>
752  void exec(Accu & a) const
753  {
754  a.template activate<TAG>();
755  }
756 };
757 
758 struct TagIsActive_Visitor
759 {
760  mutable bool result;
761 
762  template <class TAG, class Accu>
763  void exec(Accu & a) const
764  {
765  result = a.template isActive<TAG>();
766  }
767 };
768 
769 /****************************************************************************/
770 /* */
771 /* histogram initialization functors */
772 /* */
773 /****************************************************************************/
774 
775 template <class TAG>
776 struct SetHistogramBincount
777 {
778  template <class Accu>
779  static void exec(Accu & a, HistogramOptions const & options)
780  {}
781 };
782 
783 template <template <int> class Histogram>
784 struct SetHistogramBincount<Histogram<0> >
785 {
786  template <class Accu>
787  static void exec(Accu & a, HistogramOptions const & options)
788  {
789  a.setBinCount(options.binCount);
790  }
791 };
792 
793 template <class TAG>
794 struct ApplyHistogramOptions
795 {
796  template <class Accu>
797  static void exec(Accu & a, HistogramOptions const & options)
798  {}
799 };
800 
801 template <class TAG>
802 struct ApplyHistogramOptions<StandardQuantiles<TAG> >
803 {
804  template <class Accu>
805  static void exec(Accu & a, HistogramOptions const & options)
806  {}
807 };
808 
809 template <class TAG, template <class> class MODIFIER>
810 struct ApplyHistogramOptions<MODIFIER<TAG> >
811 : public ApplyHistogramOptions<TAG>
812 {};
813 
814 template <>
815 struct ApplyHistogramOptions<IntegerHistogram<0> >
816 {
817  template <class Accu>
818  static void exec(Accu & a, HistogramOptions const & options)
819  {
820  SetHistogramBincount<IntegerHistogram<0> >::exec(a, options);
821  }
822 };
823 
824 template <int BinCount>
825 struct ApplyHistogramOptions<UserRangeHistogram<BinCount> >
826 {
827  template <class Accu>
828  static void exec(Accu & a, HistogramOptions const & options)
829  {
830  SetHistogramBincount<UserRangeHistogram<BinCount> >::exec(a, options);
831  if(a.scale_ == 0.0 && options.validMinMax())
832  a.setMinMax(options.minimum, options.maximum);
833  }
834 };
835 
836 template <int BinCount>
837 struct ApplyHistogramOptions<AutoRangeHistogram<BinCount> >
838 {
839  template <class Accu>
840  static void exec(Accu & a, HistogramOptions const & options)
841  {
842  SetHistogramBincount<AutoRangeHistogram<BinCount> >::exec(a, options);
843  if(a.scale_ == 0.0 && options.validMinMax())
844  a.setMinMax(options.minimum, options.maximum);
845  }
846 };
847 
848 template <int BinCount>
849 struct ApplyHistogramOptions<GlobalRangeHistogram<BinCount> >
850 {
851  template <class Accu>
852  static void exec(Accu & a, HistogramOptions const & options)
853  {
854  SetHistogramBincount<GlobalRangeHistogram<BinCount> >::exec(a, options);
855  if(a.scale_ == 0.0)
856  {
857  if(options.validMinMax())
858  a.setMinMax(options.minimum, options.maximum);
859  else
860  a.setRegionAutoInit(options.local_auto_init);
861  }
862  }
863 };
864 
865 /****************************************************************************/
866 /* */
867 /* internal accumulator chain classes */
868 /* */
869 /****************************************************************************/
870 
871  // AccumulatorEndImpl has the following functionalities:
872  // * marks end of accumulator chain by the AccumulatorEnd tag
873  // * provides empty implementation of standard accumulator functions
874  // * provides active_accumulators_ flags for run-time activation of dynamic accumulators
875  // * provides is_dirty_ flags for caching accumulators
876  // * hold the GlobalAccumulatorHandle for global accumulator lookup from region accumulators
877 template <unsigned LEVEL, class GlobalAccumulatorHandle>
878 struct AccumulatorEndImpl
879 {
880  typedef typename GlobalAccumulatorHandle::type GlobalAccumulatorType;
881 
882  typedef AccumulatorEnd Tag;
883  typedef void value_type;
884  typedef bool result_type;
885  typedef BitArray<LEVEL> AccumulatorFlags;
886 
887  static const unsigned int workInPass = 0;
888  static const int index = -1;
889  static const unsigned level = LEVEL;
890 
891  AccumulatorFlags active_accumulators_;
892  mutable AccumulatorFlags is_dirty_;
893  GlobalAccumulatorHandle globalAccumulator_;
894 
895  template <class GlobalAccumulator>
896  void setGlobalAccumulator(GlobalAccumulator const * a)
897  {
898  globalAccumulator_.pointer_ = a;
899  }
900 
901  static std::string name()
902  {
903  return "AccumulatorEnd (internal)";
904  }
905 
906  bool operator()() const { return false; }
907  bool get() const { return false; }
908 
909  template <unsigned, class U>
910  void pass(U const &)
911  {}
912 
913  template <unsigned, class U>
914  void pass(U const &, double)
915  {}
916 
917  template <class U>
918  void mergeImpl(U const &)
919  {}
920 
921  template <class U>
922  void resize(U const &)
923  {}
924 
925  template <class U>
926  void setCoordinateOffsetImpl(U const &)
927  {}
928 
929  void activate()
930  {}
931 
932  bool isActive() const
933  {
934  return false;
935  }
936 
937  template <class Flags>
938  static void activateImpl(Flags &)
939  {}
940 
941  template <class Accu, class Flags1, class Flags2>
942  static void activateImpl(Flags1 &, Flags2 &)
943  {}
944 
945  template <class Flags>
946  static bool isActiveImpl(Flags const &)
947  {
948  return true;
949  }
950 
951  void applyHistogramOptions(HistogramOptions const &)
952  {}
953 
954  static unsigned int passesRequired()
955  {
956  return 0;
957  }
958 
959  static unsigned int passesRequired(AccumulatorFlags const &)
960  {
961  return 0;
962  }
963 
964  void reset()
965  {
966  active_accumulators_.clear();
967  is_dirty_.clear();
968  }
969 
970  template <int which>
971  void setDirtyImpl() const
972  {
973  is_dirty_.template set<which>();
974  }
975 
976  template <int which>
977  void setCleanImpl() const
978  {
979  is_dirty_.template reset<which>();
980  }
981 
982  template <int which>
983  bool isDirtyImpl() const
984  {
985  return is_dirty_.template test<which>();
986  }
987 };
988 
989  // DecoratorImpl implement the functionality of Decorator below
990 template <class A, unsigned CurrentPass, bool allowRuntimeActivation, unsigned WorkPass=A::workInPass>
991 struct DecoratorImpl
992 {
993  template <class T>
994  static void exec(A & a, T const & t)
995  {}
996 
997  template <class T>
998  static void exec(A & a, T const & t, double weight)
999  {}
1000 };
1001 
1002 template <class A, unsigned CurrentPass>
1003 struct DecoratorImpl<A, CurrentPass, false, CurrentPass>
1004 {
1005  template <class T>
1006  static void exec(A & a, T const & t)
1007  {
1008  a.update(t);
1009  }
1010 
1011  template <class T>
1012  static void exec(A & a, T const & t, double weight)
1013  {
1014  a.update(t, weight);
1015  }
1016 
1017  static typename A::result_type get(A const & a)
1018  {
1019  return a();
1020  }
1021 
1022  static void mergeImpl(A & a, A const & o)
1023  {
1024  a += o;
1025  }
1026 
1027  template <class T>
1028  static void resize(A & a, T const & t)
1029  {
1030  a.reshape(t);
1031  }
1032 
1033  static void applyHistogramOptions(A & a, HistogramOptions const & options)
1034  {
1035  ApplyHistogramOptions<typename A::Tag>::exec(a, options);
1036  }
1037 
1038  static unsigned int passesRequired()
1039  {
1040  static const unsigned int A_workInPass = A::workInPass;
1041  return std::max(A_workInPass, A::InternalBaseType::passesRequired());
1042  }
1043 };
1044 
1045 template <class A, unsigned CurrentPass>
1046 struct DecoratorImpl<A, CurrentPass, true, CurrentPass>
1047 {
1048  static bool isActive(A const & a)
1049  {
1050  return A::isActiveImpl(getAccumulator<AccumulatorEnd>(a).active_accumulators_);
1051  }
1052 
1053  template <class T>
1054  static void exec(A & a, T const & t)
1055  {
1056  if(isActive(a))
1057  a.update(t);
1058  }
1059 
1060  template <class T>
1061  static void exec(A & a, T const & t, double weight)
1062  {
1063  if(isActive(a))
1064  a.update(t, weight);
1065  }
1066 
1067  static typename A::result_type get(A const & a)
1068  {
1069  if(!isActive(a))
1070  {
1071  std::string message = std::string("get(accumulator): attempt to access inactive statistic '") +
1072  A::Tag::name() + "'.";
1073  vigra_precondition(false, message);
1074  }
1075  return a();
1076  }
1077 
1078  static void mergeImpl(A & a, A const & o)
1079  {
1080  if(isActive(a))
1081  a += o;
1082  }
1083 
1084  template <class T>
1085  static void resize(A & a, T const & t)
1086  {
1087  if(isActive(a))
1088  a.reshape(t);
1089  }
1090 
1091  static void applyHistogramOptions(A & a, HistogramOptions const & options)
1092  {
1093  if(isActive(a))
1094  ApplyHistogramOptions<typename A::Tag>::exec(a, options);
1095  }
1096 
1097  template <class ActiveFlags>
1098  static unsigned int passesRequired(ActiveFlags const & flags)
1099  {
1100  static const unsigned int A_workInPass = A::workInPass;
1101  return A::isActiveImpl(flags)
1102  ? std::max(A_workInPass, A::InternalBaseType::passesRequired(flags))
1103  : A::InternalBaseType::passesRequired(flags);
1104  }
1105 };
1106 
1107  // Generic reshape function (expands to a no-op when T has fixed shape, and to
1108  // the appropriate specialized call otherwise). Shape is an instance of MultiArrayShape<N>::type.
1109 template <class T, class Shape>
1110 void reshapeImpl(T &, Shape const &)
1111 {}
1112 
1113 template <class T, class Shape, class Initial>
1114 void reshapeImpl(T &, Shape const &, Initial const & = T())
1115 {}
1116 
1117 template <unsigned int N, class T, class Alloc, class Shape>
1118 void reshapeImpl(MultiArray<N, T, Alloc> & a, Shape const & s, T const & initial = T())
1119 {
1120  MultiArray<N, T, Alloc>(s, initial).swap(a);
1121 }
1122 
1123 template <class T, class Alloc, class Shape>
1124 void reshapeImpl(Matrix<T, Alloc> & a, Shape const & s, T const & initial = T())
1125 {
1126  Matrix<T, Alloc>(s, initial).swap(a);
1127 }
1128 
1129 template <class T, class U>
1130 void copyShapeImpl(T const &, U const &) // to be used for scalars and static arrays
1131 {}
1132 
1133 template <unsigned int N, class T, class Alloc, class U>
1134 void copyShapeImpl(MultiArray<N, T, Alloc> const & from, U & to)
1135 {
1136  to.reshape(from.shape());
1137 }
1138 
1139 template <class T, class Alloc, class U>
1140 void copyShapeImpl(Matrix<T, Alloc> const & from, U & to)
1141 {
1142  to.reshape(from.shape());
1143 }
1144 
1145 template <class T, class U>
1146 bool hasDataImpl(T const &) // to be used for scalars and static arrays
1147 {
1148  return true;
1149 }
1150 
1151 template <unsigned int N, class T, class Stride>
1152 bool hasDataImpl(MultiArrayView<N, T, Stride> const & a)
1153 {
1154  return a.hasData();
1155 }
1156 
1157  // generic functions to create suitable shape objects from various input data types
1158 template <unsigned int N, class T, class Stride>
1159 inline typename MultiArrayShape<N>::type
1160 shapeOf(MultiArrayView<N, T, Stride> const & a)
1161 {
1162  return a.shape();
1163 }
1164 
1165 template <class T, int N>
1166 inline Shape1
1167 shapeOf(TinyVector<T, N> const &)
1168 {
1169  return Shape1(N);
1170 }
1171 
1172 template <class T, class NEXT>
1173 inline CoupledHandle<T, NEXT> const &
1174 shapeOf(CoupledHandle<T, NEXT> const & t)
1175 {
1176  return t;
1177 }
1178 
1179 #define VIGRA_SHAPE_OF(type) \
1180 inline Shape1 \
1181 shapeOf(type) \
1182 { \
1183  return Shape1(1); \
1184 }
1185 
1186 VIGRA_SHAPE_OF(unsigned char)
1187 VIGRA_SHAPE_OF(signed char)
1188 VIGRA_SHAPE_OF(unsigned short)
1189 VIGRA_SHAPE_OF(short)
1190 VIGRA_SHAPE_OF(unsigned int)
1191 VIGRA_SHAPE_OF(int)
1192 VIGRA_SHAPE_OF(unsigned long)
1193 VIGRA_SHAPE_OF(long)
1194 VIGRA_SHAPE_OF(unsigned long long)
1195 VIGRA_SHAPE_OF(long long)
1196 VIGRA_SHAPE_OF(float)
1197 VIGRA_SHAPE_OF(double)
1198 VIGRA_SHAPE_OF(long double)
1199 
1200 #undef VIGRA_SHAPE_OF
1201 
1202  // LabelDispatch is only used in AccumulatorChainArrays and has the following functionalities:
1203  // * hold an accumulator chain for global statistics
1204  // * hold an array of accumulator chains (one per region) for region statistics
1205  // * forward data to the appropriate chains
1206  // * allocate the region array with appropriate size
1207  // * store and forward activation requests
1208  // * compute required number of passes as maximum from global and region accumulators
1209 template <class T, class GlobalAccumulators, class RegionAccumulators>
1210 struct LabelDispatch
1211 {
1212  typedef LabelDispatchTag Tag;
1213  typedef GlobalAccumulators GlobalAccumulatorChain;
1214  typedef RegionAccumulators RegionAccumulatorChain;
1215  typedef typename LookupTag<AccumulatorEnd, RegionAccumulatorChain>::type::AccumulatorFlags ActiveFlagsType;
1216  typedef ArrayVector<RegionAccumulatorChain> RegionAccumulatorArray;
1217 
1218  typedef LabelDispatch type;
1219  typedef LabelDispatch & reference;
1220  typedef LabelDispatch const & const_reference;
1221  typedef GlobalAccumulatorChain InternalBaseType;
1222 
1223  typedef T const & argument_type;
1224  typedef argument_type first_argument_type;
1225  typedef double second_argument_type;
1226  typedef RegionAccumulatorChain & result_type;
1227 
1228  static const int index = GlobalAccumulatorChain::index + 1;
1229 
1230  template <class IndexDefinition, class TagFound=typename IndexDefinition::Tag>
1231  struct CoordIndexSelector
1232  {
1233  static const int value = 0; // default: CoupledHandle holds coordinates at index 0
1234  };
1235 
1236  template <class IndexDefinition>
1237  struct CoordIndexSelector<IndexDefinition, CoordArgTag>
1238  {
1239  static const int value = IndexDefinition::value;
1240  };
1241 
1242  static const int coordIndex = CoordIndexSelector<typename LookupTag<CoordArgTag, GlobalAccumulatorChain>::type>::value;
1243  static const int coordSize = CoupledHandleCast<coordIndex, T>::type::value_type::static_size;
1244  typedef TinyVector<double, coordSize> CoordinateType;
1245 
1246  GlobalAccumulatorChain next_;
1247  RegionAccumulatorArray regions_;
1248  HistogramOptions region_histogram_options_;
1249  MultiArrayIndex ignore_label_;
1250  ActiveFlagsType active_region_accumulators_;
1251  CoordinateType coordinateOffset_;
1252 
1253  template <class TAG>
1254  struct ActivateImpl
1255  {
1256  typedef typename LookupTag<TAG, type>::type TargetAccumulator;
1257 
1258  static void activate(GlobalAccumulatorChain & globals, RegionAccumulatorArray & regions,
1259  ActiveFlagsType & flags)
1260  {
1261  TargetAccumulator::template activateImpl<LabelDispatch>(
1262  flags, getAccumulator<AccumulatorEnd>(globals).active_accumulators_);
1263  for(unsigned int k=0; k<regions.size(); ++k)
1264  getAccumulator<AccumulatorEnd>(regions[k]).active_accumulators_ = flags;
1265  }
1266 
1267  static bool isActive(GlobalAccumulatorChain const &, ActiveFlagsType const & flags)
1268  {
1269  return TargetAccumulator::isActiveImpl(flags);
1270  }
1271  };
1272 
1273  template <class TAG>
1274  struct ActivateImpl<Global<TAG> >
1275  {
1276  static void activate(GlobalAccumulatorChain & globals, RegionAccumulatorArray &, ActiveFlagsType &)
1277  {
1278  LookupTag<TAG, GlobalAccumulatorChain>::type::activateImpl(getAccumulator<AccumulatorEnd>(globals).active_accumulators_);
1279  }
1280 
1281  static bool isActive(GlobalAccumulatorChain const & globals, ActiveFlagsType const &)
1282  {
1283  return LookupTag<TAG, GlobalAccumulatorChain>::type::isActiveImpl(getAccumulator<AccumulatorEnd>(globals).active_accumulators_);
1284  }
1285  };
1286 
1287  template <int INDEX>
1288  struct ActivateImpl<LabelArg<INDEX> >
1289  {
1290  static void activate(GlobalAccumulatorChain &, RegionAccumulatorArray &, ActiveFlagsType &)
1291  {}
1292 
1293  static bool isActive(GlobalAccumulatorChain const & globals, ActiveFlagsType const &)
1294  {
1295  return getAccumulator<LabelArg<INDEX> >(globals).isActive();
1296  }
1297  };
1298 
1299  LabelDispatch()
1300  : next_(),
1301  regions_(),
1302  region_histogram_options_(),
1303  ignore_label_(-1),
1304  active_region_accumulators_()
1305  {}
1306 
1307  LabelDispatch(LabelDispatch const & o)
1308  : next_(o.next_),
1309  regions_(o.regions_),
1310  region_histogram_options_(o.region_histogram_options_),
1311  ignore_label_(o.ignore_label_),
1312  active_region_accumulators_(o.active_region_accumulators_)
1313  {
1314  for(unsigned int k=0; k<regions_.size(); ++k)
1315  {
1316  getAccumulator<AccumulatorEnd>(regions_[k]).setGlobalAccumulator(&next_);
1317  }
1318  }
1319 
1320  MultiArrayIndex maxRegionLabel() const
1321  {
1322  return (MultiArrayIndex)regions_.size() - 1;
1323  }
1324 
1325  void setMaxRegionLabel(unsigned maxlabel)
1326  {
1327  if(maxRegionLabel() == (MultiArrayIndex)maxlabel)
1328  return;
1329  unsigned int oldSize = regions_.size();
1330  regions_.resize(maxlabel + 1);
1331  for(unsigned int k=oldSize; k<regions_.size(); ++k)
1332  {
1333  getAccumulator<AccumulatorEnd>(regions_[k]).setGlobalAccumulator(&next_);
1334  getAccumulator<AccumulatorEnd>(regions_[k]).active_accumulators_ = active_region_accumulators_;
1335  regions_[k].applyHistogramOptions(region_histogram_options_);
1336  regions_[k].setCoordinateOffsetImpl(coordinateOffset_);
1337  }
1338  }
1339 
1340  void ignoreLabel(MultiArrayIndex l)
1341  {
1342  ignore_label_ = l;
1343  }
1344 
1345  MultiArrayIndex ignoredLabel() const
1346  {
1347  return ignore_label_;
1348  }
1349 
1350  void applyHistogramOptions(HistogramOptions const & options)
1351  {
1352  applyHistogramOptions(options, options);
1353  }
1354 
1355  void applyHistogramOptions(HistogramOptions const & regionoptions,
1356  HistogramOptions const & globaloptions)
1357  {
1358  region_histogram_options_ = regionoptions;
1359  for(unsigned int k=0; k<regions_.size(); ++k)
1360  {
1361  regions_[k].applyHistogramOptions(region_histogram_options_);
1362  }
1363  next_.applyHistogramOptions(globaloptions);
1364  }
1365 
1366  void setCoordinateOffsetImpl(CoordinateType const & offset)
1367  {
1368  coordinateOffset_ = offset;
1369  for(unsigned int k=0; k<regions_.size(); ++k)
1370  {
1371  regions_[k].setCoordinateOffsetImpl(coordinateOffset_);
1372  }
1373  next_.setCoordinateOffsetImpl(coordinateOffset_);
1374  }
1375 
1376  void setCoordinateOffsetImpl(MultiArrayIndex k, CoordinateType const & offset)
1377  {
1378  vigra_precondition(0 <= k && k < (MultiArrayIndex)regions_.size(),
1379  "Accumulator::setCoordinateOffset(k, offset): region k does not exist.");
1380  regions_[k].setCoordinateOffsetImpl(offset);
1381  }
1382 
1383  template <class U>
1384  void resize(U const & t)
1385  {
1386  if(regions_.size() == 0)
1387  {
1388  typedef HandleArgSelector<U, LabelArgTag, GlobalAccumulatorChain> LabelHandle;
1389  typedef typename LabelHandle::value_type LabelType;
1390  typedef MultiArrayView<LabelHandle::size, LabelType, StridedArrayTag> LabelArray;
1391  LabelArray labelArray(t.shape(), LabelHandle::getHandle(t).strides(),
1392  const_cast<LabelType *>(LabelHandle::getHandle(t).ptr()));
1393 
1394  LabelType minimum, maximum;
1395  labelArray.minmax(&minimum, &maximum);
1396  setMaxRegionLabel(maximum);
1397  }
1398  next_.resize(t);
1399  // FIXME: only call resize when label k actually exists?
1400  for(unsigned int k=0; k<regions_.size(); ++k)
1401  regions_[k].resize(t);
1402  }
1403 
1404  template <unsigned N>
1405  void pass(T const & t)
1406  {
1407  typedef HandleArgSelector<T, LabelArgTag, GlobalAccumulatorChain> LabelHandle;
1408  if(LabelHandle::getValue(t) != ignore_label_)
1409  {
1410  next_.template pass<N>(t);
1411  regions_[LabelHandle::getValue(t)].template pass<N>(t);
1412  }
1413  }
1414 
1415  template <unsigned N>
1416  void pass(T const & t, double weight)
1417  {
1418  typedef HandleArgSelector<T, LabelArgTag, GlobalAccumulatorChain> LabelHandle;
1419  if(LabelHandle::getValue(t) != ignore_label_)
1420  {
1421  next_.template pass<N>(t, weight);
1422  regions_[LabelHandle::getValue(t)].template pass<N>(t, weight);
1423  }
1424  }
1425 
1426  static unsigned int passesRequired()
1427  {
1428  return std::max(GlobalAccumulatorChain::passesRequired(), RegionAccumulatorChain::passesRequired());
1429  }
1430 
1431  unsigned int passesRequiredDynamic() const
1432  {
1433  return std::max(GlobalAccumulatorChain::passesRequired(getAccumulator<AccumulatorEnd>(next_).active_accumulators_),
1434  RegionAccumulatorChain::passesRequired(active_region_accumulators_));
1435  }
1436 
1437  void reset()
1438  {
1439  next_.reset();
1440 
1441  active_region_accumulators_.clear();
1442  RegionAccumulatorArray().swap(regions_);
1443  // FIXME: or is it better to just reset the region accumulators?
1444  // for(unsigned int k=0; k<regions_.size(); ++k)
1445  // regions_[k].reset();
1446  }
1447 
1448  template <class TAG>
1449  void activate()
1450  {
1451  ActivateImpl<TAG>::activate(next_, regions_, active_region_accumulators_);
1452  }
1453 
1454  void activateAll()
1455  {
1456  getAccumulator<AccumulatorEnd>(next_).active_accumulators_.set();
1457  active_region_accumulators_.set();
1458  for(unsigned int k=0; k<regions_.size(); ++k)
1459  getAccumulator<AccumulatorEnd>(regions_[k]).active_accumulators_.set();
1460  }
1461 
1462  template <class TAG>
1463  bool isActive() const
1464  {
1465  return ActivateImpl<TAG>::isActive(next_, active_region_accumulators_);
1466  }
1467 
1468  void mergeImpl(LabelDispatch const & o)
1469  {
1470  for(unsigned int k=0; k<regions_.size(); ++k)
1471  regions_[k].mergeImpl(o.regions_[k]);
1472  next_.mergeImpl(o.next_);
1473  }
1474 
1475  void mergeImpl(unsigned i, unsigned j)
1476  {
1477  regions_[i].mergeImpl(regions_[j]);
1478  regions_[j].reset();
1479  getAccumulator<AccumulatorEnd>(regions_[j]).active_accumulators_ = active_region_accumulators_;
1480  }
1481 
1482  template <class ArrayLike>
1483  void mergeImpl(LabelDispatch const & o, ArrayLike const & labelMapping)
1484  {
1485  MultiArrayIndex newMaxLabel = std::max<MultiArrayIndex>(maxRegionLabel(), *argMax(labelMapping.begin(), labelMapping.end()));
1486  setMaxRegionLabel(newMaxLabel);
1487  for(unsigned int k=0; k<labelMapping.size(); ++k)
1488  regions_[labelMapping[k]].mergeImpl(o.regions_[k]);
1489  next_.mergeImpl(o.next_);
1490  }
1491 };
1492 
1493 template <class TargetTag, class TagList>
1494 struct FindNextTag;
1495 
1496 template <class TargetTag, class HEAD, class TAIL>
1497 struct FindNextTag<TargetTag, TypeList<HEAD, TAIL> >
1498 {
1499  typedef typename FindNextTag<TargetTag, TAIL>::type type;
1500 };
1501 
1502 template <class TargetTag, class TAIL>
1503 struct FindNextTag<TargetTag, TypeList<TargetTag, TAIL> >
1504 {
1505  typedef typename TAIL::Head type;
1506 };
1507 
1508 template <class TargetTag>
1509 struct FindNextTag<TargetTag, TypeList<TargetTag, void> >
1510 {
1511  typedef void type;
1512 };
1513 
1514 template <class TargetTag>
1515 struct FindNextTag<TargetTag, void>
1516 {
1517  typedef void type;
1518 };
1519 
1520  // AccumulatorFactory creates the decorator hierarchy for the given TAG and configuration CONFIG
1521 template <class TAG, class CONFIG, unsigned LEVEL=0>
1522 struct AccumulatorFactory
1523 {
1524  typedef typename FindNextTag<TAG, typename CONFIG::TagList>::type NextTag;
1525  typedef typename AccumulatorFactory<NextTag, CONFIG, LEVEL+1>::type NextType;
1526  typedef typename CONFIG::InputType InputType;
1527 
1528  template <class T>
1529  struct ConfigureTag
1530  {
1531  typedef TAG type;
1532  };
1533 
1534  // When InputType is a CoupledHandle, some tags need to be wrapped into
1535  // DataFromHandle<> and/or Weighted<> modifiers. The following code does
1536  // this when appropriate.
1537  template <class T, class NEXT>
1538  struct ConfigureTag<CoupledHandle<T, NEXT> >
1539  {
1540  typedef typename StandardizeTag<DataFromHandle<TAG> >::type WrappedTag;
1541  typedef typename IfBool<(!HasModifierPriority<WrappedTag, WeightingPriority>::value && ShouldBeWeighted<WrappedTag>::value),
1542  Weighted<WrappedTag>, WrappedTag>::type type;
1543  };
1544 
1545  typedef typename ConfigureTag<InputType>::type UseTag;
1546 
1547  // base class of the decorator hierarchy: default (possibly empty)
1548  // implementations of all members
1549  struct AccumulatorBase
1550  {
1551  typedef AccumulatorBase ThisType;
1552  typedef TAG Tag;
1553  typedef NextType InternalBaseType;
1554  typedef InputType input_type;
1555  typedef input_type const & argument_type;
1556  typedef argument_type first_argument_type;
1557  typedef double second_argument_type;
1558  typedef void result_type;
1559 
1560  static const unsigned int workInPass = 1;
1561  static const int index = InternalBaseType::index + 1;
1562 
1563  InternalBaseType next_;
1564 
1565  static std::string name()
1566  {
1567  return TAG::name();
1568  }
1569 
1570  template <class ActiveFlags>
1571  static void activateImpl(ActiveFlags & flags)
1572  {
1573  flags.template set<index>();
1574  typedef typename StandardizeDependencies<Tag>::type StdDeps;
1575  acc_detail::ActivateDependencies<StdDeps>::template exec<ThisType>(flags);
1576  }
1577 
1578  template <class Accu, class ActiveFlags, class GlobalFlags>
1579  static void activateImpl(ActiveFlags & flags, GlobalFlags & gflags)
1580  {
1581  flags.template set<index>();
1582  typedef typename StandardizeDependencies<Tag>::type StdDeps;
1583  acc_detail::ActivateDependencies<StdDeps>::template exec<Accu>(flags, gflags);
1584  }
1585 
1586  template <class ActiveFlags>
1587  static bool isActiveImpl(ActiveFlags & flags)
1588  {
1589  return flags.template test<index>();
1590  }
1591 
1592  void setDirty() const
1593  {
1594  next_.template setDirtyImpl<index>();
1595  }
1596 
1597  template <int INDEX>
1598  void setDirtyImpl() const
1599  {
1600  next_.template setDirtyImpl<INDEX>();
1601  }
1602 
1603  void setClean() const
1604  {
1605  next_.template setCleanImpl<index>();
1606  }
1607 
1608  template <int INDEX>
1609  void setCleanImpl() const
1610  {
1611  next_.template setCleanImpl<INDEX>();
1612  }
1613 
1614  bool isDirty() const
1615  {
1616  return next_.template isDirtyImpl<index>();
1617  }
1618 
1619  template <int INDEX>
1620  bool isDirtyImpl() const
1621  {
1622  return next_.template isDirtyImpl<INDEX>();
1623  }
1624 
1625  void reset()
1626  {}
1627 
1628  template <class Shape>
1629  void setCoordinateOffset(Shape const &)
1630  {}
1631 
1632  template <class Shape>
1633  void reshape(Shape const &)
1634  {}
1635 
1636  void operator+=(AccumulatorBase const &)
1637  {}
1638 
1639  template <class U>
1640  void update(U const &)
1641  {}
1642 
1643  template <class U>
1644  void update(U const &, double)
1645  {}
1646 
1647  template <class TargetTag>
1648  typename LookupDependency<TargetTag, ThisType>::result_type
1649  call_getDependency() const
1650  {
1651  return getDependency<TargetTag>(*this);
1652  }
1653  };
1654 
1655  // The middle class(es) of the decorator hierarchy implement the actual feature computation.
1656  typedef typename UseTag::template Impl<InputType, AccumulatorBase> AccumulatorImpl;
1657 
1658  // outer class of the decorator hierarchy. It has the following functionalities
1659  // * ensure that only active accumulators are called in a dynamic accumulator chain
1660  // * ensure that each accumulator is only called in its desired pass as defined in A::workInPass
1661  // * determine how many passes through the data are required
1662  struct Accumulator
1663  : public AccumulatorImpl
1664  {
1665  typedef Accumulator type;
1666  typedef Accumulator & reference;
1667  typedef Accumulator const & const_reference;
1668  typedef AccumulatorImpl A;
1669 
1670  static const unsigned int workInPass = A::workInPass;
1671  static const bool allowRuntimeActivation = CONFIG::allowRuntimeActivation;
1672 
1673  template <class T>
1674  void resize(T const & t)
1675  {
1676  this->next_.resize(t);
1677  DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>::resize(*this, t);
1678  }
1679 
1680  void reset()
1681  {
1682  this->next_.reset();
1683  A::reset();
1684  }
1685 
1686  typename A::result_type get() const
1687  {
1689  }
1690 
1691  template <unsigned N, class T>
1692  void pass(T const & t)
1693  {
1694  this->next_.template pass<N>(t);
1695  DecoratorImpl<Accumulator, N, allowRuntimeActivation>::exec(*this, t);
1696  }
1697 
1698  template <unsigned N, class T>
1699  void pass(T const & t, double weight)
1700  {
1701  this->next_.template pass<N>(t, weight);
1702  DecoratorImpl<Accumulator, N, allowRuntimeActivation>::exec(*this, t, weight);
1703  }
1704 
1705  void mergeImpl(Accumulator const & o)
1706  {
1707  DecoratorImpl<Accumulator, Accumulator::workInPass, allowRuntimeActivation>::mergeImpl(*this, o);
1708  this->next_.mergeImpl(o.next_);
1709  }
1710 
1711  void applyHistogramOptions(HistogramOptions const & options)
1712  {
1713  DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>::applyHistogramOptions(*this, options);
1714  this->next_.applyHistogramOptions(options);
1715  }
1716 
1717  template <class SHAPE>
1718  void setCoordinateOffsetImpl(SHAPE const & offset)
1719  {
1720  this->setCoordinateOffset(offset);
1721  this->next_.setCoordinateOffsetImpl(offset);
1722  }
1723 
1724  static unsigned int passesRequired()
1725  {
1726  return DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>::passesRequired();
1727  }
1728 
1729  template <class ActiveFlags>
1730  static unsigned int passesRequired(ActiveFlags const & flags)
1731  {
1732  return DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>::passesRequired(flags);
1733  }
1734  };
1735 
1736  typedef Accumulator type;
1737 };
1738 
1739 template <class CONFIG, unsigned LEVEL>
1740 struct AccumulatorFactory<void, CONFIG, LEVEL>
1741 {
1742  typedef AccumulatorEndImpl<LEVEL, typename CONFIG::GlobalAccumulatorHandle> type;
1743 };
1744 
1745 struct InvalidGlobalAccumulatorHandle
1746 {
1747  typedef Error__Global_statistics_are_only_defined_for_AccumulatorChainArray type;
1748 
1749  InvalidGlobalAccumulatorHandle()
1750  : pointer_(0)
1751  {}
1752 
1753  type const * pointer_;
1754 };
1755 
1756  // helper classes to create an accumulator chain from a TypeList
1757  // if dynamic=true, a dynamic accumulator will be created
1758  // if dynamic=false, a plain accumulator will be created
1759 template <class T, class Selected, bool dynamic=false, class GlobalHandle=InvalidGlobalAccumulatorHandle>
1760 struct ConfigureAccumulatorChain
1761 #ifndef DOXYGEN
1762 : public ConfigureAccumulatorChain<T, typename AddDependencies<typename Selected::type>::type, dynamic>
1763 #endif
1764 {};
1765 
1766 template <class T, class HEAD, class TAIL, bool dynamic, class GlobalHandle>
1767 struct ConfigureAccumulatorChain<T, TypeList<HEAD, TAIL>, dynamic, GlobalHandle>
1768 {
1769  typedef TypeList<HEAD, TAIL> TagList;
1770  typedef T InputType;
1771  static const bool allowRuntimeActivation = dynamic;
1772  typedef GlobalHandle GlobalAccumulatorHandle;
1773 
1774  typedef typename AccumulatorFactory<HEAD, ConfigureAccumulatorChain>::type type;
1775 };
1776 
1777 template <class T, class Selected, bool dynamic=false>
1778 struct ConfigureAccumulatorChainArray
1779 #ifndef DOXYGEN
1780 : public ConfigureAccumulatorChainArray<T, typename AddDependencies<typename Selected::type>::type, dynamic>
1781 #endif
1782 {};
1783 
1784 template <class T, class HEAD, class TAIL, bool dynamic>
1785 struct ConfigureAccumulatorChainArray<T, TypeList<HEAD, TAIL>, dynamic>
1786 {
1787  typedef TypeList<HEAD, TAIL> TagList;
1788  typedef SeparateGlobalAndRegionTags<TagList> TagSeparator;
1789  typedef typename TagSeparator::GlobalTags GlobalTags;
1790  typedef typename TagSeparator::RegionTags RegionTags;
1791  typedef typename ConfigureAccumulatorChain<T, GlobalTags, dynamic>::type GlobalAccumulatorChain;
1792 
1793  struct GlobalAccumulatorHandle
1794  {
1795  typedef GlobalAccumulatorChain type;
1796 
1797  GlobalAccumulatorHandle()
1798  : pointer_(0)
1799  {}
1800 
1801  type const * pointer_;
1802  };
1803 
1804  typedef typename ConfigureAccumulatorChain<T, RegionTags, dynamic, GlobalAccumulatorHandle>::type RegionAccumulatorChain;
1805 
1806  typedef LabelDispatch<T, GlobalAccumulatorChain, RegionAccumulatorChain> type;
1807 };
1808 
1809 } // namespace acc_detail
1810 
1811 /****************************************************************************/
1812 /* */
1813 /* accumulator chain */
1814 /* */
1815 /****************************************************************************/
1816 
1817 // Implement the high-level interface of an accumulator chain
1818 template <class T, class NEXT>
1819 class AccumulatorChainImpl
1820 {
1821  public:
1822  typedef NEXT InternalBaseType;
1823  typedef AccumulatorBegin Tag;
1824  typedef typename InternalBaseType::argument_type argument_type;
1825  typedef typename InternalBaseType::first_argument_type first_argument_type;
1826  typedef typename InternalBaseType::second_argument_type second_argument_type;
1827  typedef void value_type;
1828  typedef typename InternalBaseType::result_type result_type;
1829 
1830  static const int staticSize = InternalBaseType::index;
1831 
1832  InternalBaseType next_;
1833 
1834  /** \brief Current pass of the accumulator chain.
1835  */
1836  unsigned int current_pass_;
1837 
1838  AccumulatorChainImpl()
1839  : current_pass_(0)
1840  {}
1841 
1842  /** Set options for all histograms in the accumulator chain. See histogram accumulators for possible options. The function is ignored if there is no histogram in the accumulator chain.
1843  */
1844  void setHistogramOptions(HistogramOptions const & options)
1845  {
1846  next_.applyHistogramOptions(options);
1847  }
1848 
1849 
1850  /** Set regional and global options for all histograms in the accumulator chain.
1851  */
1852  void setHistogramOptions(HistogramOptions const & regionoptions, HistogramOptions const & globaloptions)
1853  {
1854  next_.applyHistogramOptions(regionoptions, globaloptions);
1855  }
1856 
1857  /** Set an offset for <tt>Coord<...></tt> statistics.
1858 
1859  If the offset is non-zero, coordinate statistics such as <tt>RegionCenter</tt> are computed
1860  in the global coordinate system defined by the \a offset. Without an offset, these statistics
1861  are computed in the local coordinate system of the current region of interest.
1862  */
1863  template <class SHAPE>
1864  void setCoordinateOffset(SHAPE const & offset)
1865  {
1866  next_.setCoordinateOffsetImpl(offset);
1867  }
1868 
1869  /** Reset current_pass_ of the accumulator chain to 'reset_to_pass'.
1870  */
1871  void reset(unsigned int reset_to_pass = 0)
1872  {
1873  current_pass_ = reset_to_pass;
1874  if(reset_to_pass == 0)
1875  next_.reset();
1876  }
1877 
1878  template <unsigned N>
1879  void update(T const & t)
1880  {
1881  if(current_pass_ == N)
1882  {
1883  next_.template pass<N>(t);
1884  }
1885  else if(current_pass_ < N)
1886  {
1887  current_pass_ = N;
1888  if(N == 1)
1889  next_.resize(acc_detail::shapeOf(t));
1890  next_.template pass<N>(t);
1891  }
1892  else
1893  {
1894  std::string message("AccumulatorChain::update(): cannot return to pass ");
1895  message << N << " after working on pass " << current_pass_ << ".";
1896  vigra_precondition(false, message);
1897  }
1898  }
1899 
1900  template <unsigned N>
1901  void update(T const & t, double weight)
1902  {
1903  if(current_pass_ == N)
1904  {
1905  next_.template pass<N>(t, weight);
1906  }
1907  else if(current_pass_ < N)
1908  {
1909  current_pass_ = N;
1910  if(N == 1)
1911  next_.resize(acc_detail::shapeOf(t));
1912  next_.template pass<N>(t, weight);
1913  }
1914  else
1915  {
1916  std::string message("AccumulatorChain::update(): cannot return to pass ");
1917  message << N << " after working on pass " << current_pass_ << ".";
1918  vigra_precondition(false, message);
1919  }
1920  }
1921 
1922  /** Equivalent to merge(o) .
1923  */
1924  void operator+=(AccumulatorChainImpl const & o)
1925  {
1926  merge(o);
1927  }
1928 
1929  /** Merge the accumulator chain with accumulator chain 'o'. This only works if all selected statistics in the accumulator chain support the '+=' operator. See the documentations of the particular statistics for support information.
1930  */
1931  void merge(AccumulatorChainImpl const & o)
1932  {
1933  next_.mergeImpl(o.next_);
1934  }
1935 
1936  result_type operator()() const
1937  {
1938  return next_.get();
1939  }
1940 
1941  void operator()(T const & t)
1942  {
1943  update<1>(t);
1944  }
1945 
1946  void operator()(T const & t, double weight)
1947  {
1948  update<1>(t, weight);
1949  }
1950 
1951  void updatePass2(T const & t)
1952  {
1953  update<2>(t);
1954  }
1955 
1956  void updatePass2(T const & t, double weight)
1957  {
1958  update<2>(t, weight);
1959  }
1960 
1961  /** Upate all accumulators in the accumulator chain that work in pass N with data t. Requirement: 0 < N < 6 and N >= current_pass_ . If N < current_pass_ call reset() first.
1962  */
1963  void updatePassN(T const & t, unsigned int N)
1964  {
1965  switch (N)
1966  {
1967  case 1: update<1>(t); break;
1968  case 2: update<2>(t); break;
1969  case 3: update<3>(t); break;
1970  case 4: update<4>(t); break;
1971  case 5: update<5>(t); break;
1972  default:
1973  vigra_precondition(false,
1974  "AccumulatorChain::updatePassN(): 0 < N < 6 required.");
1975  }
1976  }
1977 
1978  /** Upate all accumulators in the accumulator chain that work in pass N with data t and weight. Requirement: 0 < N < 6 and N >= current_pass_ . If N < current_pass_ call reset() first.
1979  */
1980  void updatePassN(T const & t, double weight, unsigned int N)
1981  {
1982  switch (N)
1983  {
1984  case 1: update<1>(t, weight); break;
1985  case 2: update<2>(t, weight); break;
1986  case 3: update<3>(t, weight); break;
1987  case 4: update<4>(t, weight); break;
1988  case 5: update<5>(t, weight); break;
1989  default:
1990  vigra_precondition(false,
1991  "AccumulatorChain::updatePassN(): 0 < N < 6 required.");
1992  }
1993  }
1994 
1995  /** Return the number of passes required to compute all statistics in the accumulator chain.
1996  */
1997  unsigned int passesRequired() const
1998  {
1999  return InternalBaseType::passesRequired();
2000  }
2001 };
2002 
2003 
2004 
2005  // Create an accumulator chain containing the Selected statistics and their dependencies.
2006 
2007 /** \brief Create an accumulator chain containing the selected statistics and their dependencies.
2008 
2009  AccumulatorChain is used to compute global statistics which have to be selected at compile time.
2010 
2011  The template parameters are as follows:
2012  - T: The input type
2013  - either element type of the data(e.g. double, int, RGBValue, ...)
2014  - or type of CoupledHandle (for simultaneous access to coordinates and/or weights)
2015  - Selected: statistics to be computed and index specifier for the CoupledHandle, wrapped with Select
2016 
2017  Usage:
2018  \code
2019  typedef double DataType;
2020  AccumulatorChain<DataType, Select<Variance, Mean, Minimum, ...> > accumulator;
2021  \endcode
2022 
2023  Usage, using CoupledHandle:
2024  \code
2025  const int dim = 3; //dimension of MultiArray
2026  typedef double DataType;
2027  typedef double WeightType;
2028  typedef vigra::CoupledIteratorType<dim, DataType, WeightType>::HandleType Handle;
2029  AccumulatorChain<Handle, Select<DataArg<1>, WeightArg<2>, Mean,...> > a;
2030  \endcode
2031 
2032  See \ref FeatureAccumulators for more information and examples of use.
2033  */
2034 template <class T, class Selected, bool dynamic=false>
2036 #ifndef DOXYGEN // hide AccumulatorChainImpl from documentation
2037 : public AccumulatorChainImpl<T, typename acc_detail::ConfigureAccumulatorChain<T, Selected, dynamic>::type>
2038 #endif
2039 {
2040  public:
2041  // \brief TypeList of Tags in the accumulator chain (?).
2042  typedef typename acc_detail::ConfigureAccumulatorChain<T, Selected, dynamic>::TagList AccumulatorTags;
2043 
2044  /** Before having seen data (current_pass_==0), the shape of the data can be changed... (?)
2045  */
2046  template <class U, int N>
2047  void reshape(TinyVector<U, N> const & s)
2048  {
2049  vigra_precondition(this->current_pass_ == 0,
2050  "AccumulatorChain::reshape(): cannot reshape after seeing data. Call AccumulatorChain::reset() first.");
2051  this->next_.resize(s);
2052  this->current_pass_ = 1;
2053  }
2054 
2055  /** Return the names of all tags in the accumulator chain (selected statistics and their dependencies).
2056  */
2058  {
2059  static ArrayVector<std::string> * n = VIGRA_SAFE_STATIC(n, new ArrayVector<std::string>(collectTagNames()));
2060  return *n;
2061  }
2062 
2063 
2064 #ifdef DOXYGEN // hide AccumulatorChainImpl from documentation
2065 
2066  /** Set options for all histograms in the accumulator chain. See histogram accumulators for possible options. The function is ignored if there is no histogram in the accumulator chain.
2067  */
2068  void setHistogramOptions(HistogramOptions const & options);
2069 
2070  /** Set an offset for <tt>Coord<...></tt> statistics.
2071 
2072  If the offset is non-zero, coordinate statistics such as <tt>RegionCenter</tt> are computed
2073  in the global coordinate system defined by the \a offset. Without an offset, these statistics
2074  are computed in the local coordinate system of the current region of interest.
2075  */
2076  template <class SHAPE>
2077  void setCoordinateOffset(SHAPE const & offset);
2078 
2079  /** Reset current_pass_ of the accumulator chain to 'reset_to_pass'. */
2080  void reset(unsigned int reset_to_pass = 0);
2081 
2082  /** Equivalent to merge(o) . */
2083  void operator+=(AccumulatorChainImpl const & o);
2084 
2085  /** Merge the accumulator chain with accumulator chain 'o'. This only works if all selected statistics in the accumulator chain support the '+=' operator. See the documentations of the particular statistics for support information.
2086  */
2087  void merge(AccumulatorChainImpl const & o);
2088 
2089  /** Upate all accumulators in the accumulator chain that work in pass N with data t. Requirement: 0 < N < 6 and N >= current_pass_ . If N < current_pass_ call reset first.
2090  */
2091  void updatePassN(T const & t, unsigned int N);
2092 
2093  /** Upate all accumulators in the accumulator chain that work in pass N with data t and weight. Requirement: 0 < N < 6 and N >= current_pass_ . If N < current_pass_ call reset first.
2094  */
2095  void updatePassN(T const & t, double weight, unsigned int N);
2096 
2097  /** Return the number of passes required to compute all statistics in the accumulator chain.
2098  */
2099  unsigned int passesRequired() const;
2100 
2101 #endif
2102 
2103  private:
2104  static ArrayVector<std::string> collectTagNames()
2105  {
2107  acc_detail::CollectAccumulatorNames<AccumulatorTags>::exec(n);
2108  std::sort(n.begin(), n.end());
2109  return n;
2110  }
2111 };
2112 
2113 template <unsigned int N, class T1, class T2, class T3, class T4, class T5, class Selected, bool dynamic>
2114 class AccumulatorChain<CoupledArrays<N, T1, T2, T3, T4, T5>, Selected, dynamic>
2115 : public AccumulatorChain<typename CoupledArrays<N, T1, T2, T3, T4, T5>::HandleType, Selected, dynamic>
2116 {};
2117 
2118 
2119  // Create a dynamic accumulator chain containing the Selected statistics and their dependencies.
2120  // Statistics will only be computed if activate<Tag>() is called at runtime.
2121 /** \brief Create a dynamic accumulator chain containing the selected statistics and their dependencies.
2122 
2123  DynamicAccumulatorChain is used to compute global statistics with run-time activation. A set of statistics is selected at run-time and from this set statistics can be activated at run-time by calling activate<stat>() or activate(std::string stat).
2124 
2125  The template parameters are as follows:
2126  - T: The input type
2127  - either element type of the data(e.g. double, int, RGBValue, ...)
2128  - or type of CoupledHandle (for access to coordinates and/or weights)
2129  - Selected: statistics to be computed and index specifier for the CoupledHandle, wrapped with Select
2130 
2131  Usage:
2132  \code
2133  typedef double DataType;
2134  DynamicAccumulatorChain<DataType, Select<Variance, Mean, Minimum, ...> > accumulator;
2135  \endcode
2136 
2137  Usage, using CoupledHandle:
2138  \code
2139  const int dim = 3; //dimension of MultiArray
2140  typedef double DataType;
2141  typedef double WeightType;
2142  typedef vigra::CoupledIteratorType<dim, DataType, WeightType>::HandleType Handle;
2143  DynamicAccumulatorChain<Handle, Select<DataArg<1>, WeightArg<2>, Mean,...> > a;
2144  \endcode
2145 
2146  See \ref FeatureAccumulators for more information and examples of use.
2147  */
2148 template <class T, class Selected>
2150 : public AccumulatorChain<T, Selected, true>
2151 {
2152  public:
2153  typedef typename AccumulatorChain<T, Selected, true>::InternalBaseType InternalBaseType;
2154  typedef typename DynamicAccumulatorChain::AccumulatorTags AccumulatorTags;
2155 
2156  /** Activate statistic 'tag'. Alias names are not recognized. If the statistic is not in the accumulator chain a PreconditionViolation is thrown.
2157  */
2158  void activate(std::string tag)
2159  {
2160  vigra_precondition(activateImpl(tag),
2161  std::string("DynamicAccumulatorChain::activate(): Tag '") + tag + "' not found.");
2162  }
2163 
2164  /** %activate<TAG>() activates statistic 'TAG'. If the statistic is not in the accumulator chain it is ignored. (?)
2165  */
2166  template <class TAG>
2167  void activate()
2168  {
2169  LookupTag<TAG, DynamicAccumulatorChain>::type::activateImpl(getAccumulator<AccumulatorEnd>(*this).active_accumulators_);
2170  }
2171 
2172  /** Activate all statistics in the accumulator chain.
2173  */
2175  {
2176  getAccumulator<AccumulatorEnd>(*this).active_accumulators_.set();
2177  }
2178  /** Return true if the statistic 'tag' is active, i.e. activate(std::string tag) or activate<TAG>() has been called. If the statistic is not in the accumulator chain a PreconditionViolation is thrown. (Note that alias names are not recognized.)
2179  */
2180  bool isActive(std::string tag) const
2181  {
2182  acc_detail::TagIsActive_Visitor v;
2183  vigra_precondition(isActiveImpl(tag, v),
2184  std::string("DynamicAccumulatorChain::isActive(): Tag '") + tag + "' not found.");
2185  return v.result;
2186  }
2187 
2188  /** %isActive<TAG>() returns true if statistic 'TAG' is active, i.e. activate(std::string tag) or activate<TAG>() has been called. If the statistic is not in the accumulator chain, true is returned. (?)
2189  */
2190  template <class TAG>
2191  bool isActive() const
2192  {
2193  return LookupTag<TAG, DynamicAccumulatorChain>::type::isActiveImpl(getAccumulator<AccumulatorEnd>(*this).active_accumulators_);
2194  }
2195 
2196  /** Return names of all statistics in the accumulator chain that are active.
2197  */
2199  {
2201  for(unsigned k=0; k<DynamicAccumulatorChain::tagNames().size(); ++k)
2203  res.push_back(DynamicAccumulatorChain::tagNames()[k]);
2204  return res;
2205  }
2206 
2207  /** Return number of passes required to compute the active statistics in the accumulator chain.
2208  */
2209  unsigned int passesRequired() const
2210  {
2211  return InternalBaseType::passesRequired(getAccumulator<AccumulatorEnd>(*this).active_accumulators_);
2212  }
2213 
2214  protected:
2215 
2216  bool activateImpl(std::string tag)
2217  {
2218  return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(*this,
2219  normalizeString(tag), acc_detail::ActivateTag_Visitor());
2220  }
2221 
2222  bool isActiveImpl(std::string tag, acc_detail::TagIsActive_Visitor & v) const
2223  {
2224  return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(*this, normalizeString(tag), v);
2225  }
2226 };
2227 
2228 template <unsigned int N, class T1, class T2, class T3, class T4, class T5, class Selected>
2229 class DynamicAccumulatorChain<CoupledArrays<N, T1, T2, T3, T4, T5>, Selected>
2230 : public DynamicAccumulatorChain<typename CoupledArrays<N, T1, T2, T3, T4, T5>::HandleType, Selected>
2231 {};
2232 
2233 
2234 
2235 /** \brief Create an array of accumulator chains containing the selected per-region and global statistics and their dependencies.
2236 
2237  AccumulatorChainArray is used to compute per-region statistics (as well as global statistics). The statistics are selected at compile-time. An array of accumulator chains (one per region) for region statistics is created and one accumulator chain for global statistics. The region labels always start at 0. Use the Global modifier to compute global statistics (by default per-region statistics are computed).
2238 
2239  The template parameters are as follows:
2240  - T: The input type, type of CoupledHandle (for access to coordinates, labels and weights)
2241  - Selected: statistics to be computed and index specifier for the CoupledHandle, wrapped with Select
2242 
2243  Usage:
2244  \code
2245  const int dim = 3; //dimension of MultiArray
2246  typedef double DataType;
2247  typedef double WeightType;
2248  typedef unsigned int LabelType;
2249  typedef vigra::CoupledIteratorType<dim, DataType, WeightType, LabelType>::HandleType Handle;
2250  AccumulatorChainArray<Handle, Select<DataArg<1>, WeightArg<2>, LabelArg<3>, Mean, Variance, ...> > a;
2251  \endcode
2252 
2253  See \ref FeatureAccumulators for more information and examples of use.
2254 */
2255 template <class T, class Selected, bool dynamic=false>
2257 #ifndef DOXYGEN //hide AccumulatorChainImpl vom documentation
2258 : public AccumulatorChainImpl<T, typename acc_detail::ConfigureAccumulatorChainArray<T, Selected, dynamic>::type>
2259 #endif
2260 {
2261  public:
2262  typedef AccumulatorChainImpl<T, typename acc_detail::ConfigureAccumulatorChainArray<T, Selected, dynamic>::type> base_type;
2263  typedef typename acc_detail::ConfigureAccumulatorChainArray<T, Selected, dynamic> Creator;
2264  typedef typename Creator::TagList AccumulatorTags;
2265  typedef typename Creator::GlobalTags GlobalTags;
2266  typedef typename Creator::RegionTags RegionTags;
2267 
2268  /** Statistics will not be computed for label l. Note that only one label can be ignored.
2269  */
2271  {
2272  this->next_.ignoreLabel(l);
2273  }
2274 
2275  /** Ask for a label to be ignored. Default: -1 (meaning that no label is ignored).
2276  */
2278  {
2279  return this->next_.ignoredLabel();
2280  }
2281 
2282  /** Set the maximum region label (e.g. for merging two accumulator chains).
2283  */
2284  void setMaxRegionLabel(unsigned label)
2285  {
2286  this->next_.setMaxRegionLabel(label);
2287  }
2288 
2289  /** Maximum region label. (equal to regionCount() - 1)
2290  */
2292  {
2293  return this->next_.maxRegionLabel();
2294  }
2295 
2296  /** Number of Regions. (equal to maxRegionLabel() + 1)
2297  */
2298  unsigned int regionCount() const
2299  {
2300  return this->next_.regions_.size();
2301  }
2302 
2303  /** Equivalent to <tt>merge(o)</tt>.
2304  */
2306  {
2307  merge(o);
2308  }
2309 
2310  /** Merge region i with region j.
2311  */
2312  void merge(unsigned i, unsigned j)
2313  {
2314  vigra_precondition(i <= maxRegionLabel() && j <= maxRegionLabel(),
2315  "AccumulatorChainArray::merge(): region labels out of range.");
2316  this->next_.mergeImpl(i, j);
2317  }
2318 
2319  /** Merge with accumulator chain o. maxRegionLabel() of the two accumulators must be equal.
2320  */
2322  {
2323  if(maxRegionLabel() == -1)
2325  vigra_precondition(maxRegionLabel() == o.maxRegionLabel(),
2326  "AccumulatorChainArray::merge(): maxRegionLabel must be equal.");
2327  this->next_.mergeImpl(o.next_);
2328  }
2329 
2330  /** Merge with accumulator chain o using a mapping between labels of the two accumulators. Label l of accumulator chain o is mapped to labelMapping[l]. Hence, all elements of labelMapping must be <= maxRegionLabel() and size of labelMapping must match o.regionCount().
2331  */
2332  template <class ArrayLike>
2333  void merge(AccumulatorChainArray const & o, ArrayLike const & labelMapping)
2334  {
2335  vigra_precondition(labelMapping.size() == o.regionCount(),
2336  "AccumulatorChainArray::merge(): labelMapping.size() must match regionCount() of RHS.");
2337  this->next_.mergeImpl(o.next_, labelMapping);
2338  }
2339 
2340  /** Return names of all tags in the accumulator chain (selected statistics and their dependencies).
2341  */
2343  {
2344  static const ArrayVector<std::string> n = collectTagNames();
2345  return n;
2346  }
2347 
2348  using base_type::setCoordinateOffset;
2349 
2350  /** Set an offset for <tt>Coord<...></tt> statistics for region \a k.
2351 
2352  If the offset is non-zero, coordinate statistics such as <tt>RegionCenter</tt> are computed
2353  in the global coordinate system defined by the \a offset. Without an offset, these statistics
2354  are computed in the local coordinate system of the current region of interest.
2355  */
2356  template <class SHAPE>
2357  void setCoordinateOffset(MultiArrayIndex k, SHAPE const & offset)
2358  {
2359  this->next_.setCoordinateOffsetImpl(k, offset);
2360  }
2361 
2362 #ifdef DOXYGEN // hide AccumulatorChainImpl from documentation
2363 
2364  /** \copydoc vigra::acc::AccumulatorChain::setHistogramOptions(HistogramOptions const &) */
2365  void setHistogramOptions(HistogramOptions const & options);
2366 
2367  /** Set regional and global options for all histograms in the accumulator chain.
2368  */
2369  void setHistogramOptions(HistogramOptions const & regionoptions, HistogramOptions const & globaloptions);
2370 
2371  /** \copydoc vigra::acc::AccumulatorChain::setCoordinateOffset(SHAPE const &)
2372  */
2373  template <class SHAPE>
2374  void setCoordinateOffset(SHAPE const & offset)
2375 
2376  /** \copydoc vigra::acc::AccumulatorChain::reset() */
2377  void reset(unsigned int reset_to_pass = 0);
2378 
2379  /** \copydoc vigra::acc::AccumulatorChain::operator+=() */
2380  void operator+=(AccumulatorChainImpl const & o);
2381 
2382  /** \copydoc vigra::acc::AccumulatorChain::updatePassN(T const &,unsigned int) */
2383  void updatePassN(T const & t, unsigned int N);
2384 
2385  /** \copydoc vigra::acc::AccumulatorChain::updatePassN(T const &,double,unsigned int) */
2386  void updatePassN(T const & t, double weight, unsigned int N);
2387 
2388 #endif
2389 
2390  private:
2391  static ArrayVector<std::string> collectTagNames()
2392  {
2394  acc_detail::CollectAccumulatorNames<AccumulatorTags>::exec(n);
2395  std::sort(n.begin(), n.end());
2396  return n;
2397  }
2398 };
2399 
2400 template <unsigned int N, class T1, class T2, class T3, class T4, class T5, class Selected, bool dynamic>
2401 class AccumulatorChainArray<CoupledArrays<N, T1, T2, T3, T4, T5>, Selected, dynamic>
2402 : public AccumulatorChainArray<typename CoupledArrays<N, T1, T2, T3, T4, T5>::HandleType, Selected, dynamic>
2403 {};
2404 
2405 /** \brief Create an array of dynamic accumulator chains containing the selected per-region and global statistics and their dependencies.
2406 
2407 
2408  DynamicAccumulatorChainArray is used to compute per-region statistics (as well as global statistics) with run-time activation. A set of statistics is selected at run-time and from this set statistics can be activated at run-time by calling activate<stat>() or activate(std::string stat).
2409 
2410  The template parameters are as follows:
2411  - T: The input type, type of CoupledHandle (for access to coordinates, labels and weights)
2412  - Selected: statistics to be computed and index specifier for the CoupledHandle, wrapped with Select
2413 
2414  Usage:
2415  \code
2416  const int dim = 3; //dimension of MultiArray
2417  typedef double DataType;
2418  typedef double WeightType;
2419  typedef unsigned int LabelType;
2420  typedef vigra::CoupledIteratorType<dim, DataType, WeightType, LabelType>::HandleType Handle;
2421  DynamicAccumulatorChainArray<Handle, Select<DataArg<1>, WeightArg<2>, LabelArg<3>, Mean, Variance, ...> > a;
2422  \endcode
2423 
2424  See \ref FeatureAccumulators for more information and examples of use.
2425 */
2426 template <class T, class Selected>
2428 : public AccumulatorChainArray<T, Selected, true>
2429 {
2430  public:
2431  typedef typename DynamicAccumulatorChainArray::AccumulatorTags AccumulatorTags;
2432 
2433  /** \copydoc DynamicAccumulatorChain::activate(std::string tag) */
2434  void activate(std::string tag)
2435  {
2436  vigra_precondition(activateImpl(tag),
2437  std::string("DynamicAccumulatorChainArray::activate(): Tag '") + tag + "' not found.");
2438  }
2439 
2440  /** \copydoc DynamicAccumulatorChain::activate() */
2441  template <class TAG>
2442  void activate()
2443  {
2444  this->next_.template activate<TAG>();
2445  }
2446 
2447  /** \copydoc DynamicAccumulatorChain::activateAll() */
2449  {
2450  this->next_.activateAll();
2451  }
2452 
2453  /** Return true if the statistic 'tag' is active, i.e. activate(std::string tag) or activate<TAG>() has been called. If the statistic is not in the accumulator chain a PreconditionViolation is thrown. (Note that alias names are not recognized.)
2454  */
2455  bool isActive(std::string tag) const
2456  {
2457  acc_detail::TagIsActive_Visitor v;
2458  vigra_precondition(isActiveImpl(tag, v),
2459  std::string("DynamicAccumulatorChainArray::isActive(): Tag '") + tag + "' not found.");
2460  return v.result;
2461  }
2462 
2463  /** %isActive<TAG>() returns true if statistic 'TAG' is active, i.e. activate(std::string tag) or activate<TAG>() has been called. If the statistic is not in the accumulator chain, true is returned. (?)
2464  */
2465  template <class TAG>
2466  bool isActive() const
2467  {
2468  return this->next_.template isActive<TAG>();
2469  }
2470 
2471  /** \copydoc DynamicAccumulatorChain::activeNames() */
2473  {
2475  for(unsigned k=0; k<DynamicAccumulatorChainArray::tagNames().size(); ++k)
2477  res.push_back(DynamicAccumulatorChainArray::tagNames()[k]);
2478  return res;
2479  }
2480 
2481  /** \copydoc DynamicAccumulatorChain::passesRequired() */
2482  unsigned int passesRequired() const
2483  {
2484  return this->next_.passesRequiredDynamic();
2485  }
2486 
2487  protected:
2488 
2489  bool activateImpl(std::string tag)
2490  {
2491  return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(this->next_,
2492  normalizeString(tag), acc_detail::ActivateTag_Visitor());
2493  }
2494 
2495  bool isActiveImpl(std::string tag, acc_detail::TagIsActive_Visitor & v) const
2496  {
2497  return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(this->next_, normalizeString(tag), v);
2498  }
2499 };
2500 
2501 template <unsigned int N, class T1, class T2, class T3, class T4, class T5, class Selected>
2502 class DynamicAccumulatorChainArray<CoupledArrays<N, T1, T2, T3, T4, T5>, Selected>
2503 : public DynamicAccumulatorChainArray<typename CoupledArrays<N, T1, T2, T3, T4, T5>::HandleType, Selected>
2504 {};
2505 
2506 /****************************************************************************/
2507 /* */
2508 /* generic access functions */
2509 /* */
2510 /****************************************************************************/
2511 
2512 template <class TAG>
2513 struct Error__Attempt_to_access_inactive_statistic;
2514 
2515 namespace acc_detail {
2516 
2517  // accumulator lookup rules: find the accumulator that implements TAG
2518 
2519  // When A does not implement TAG, continue search in A::InternalBaseType.
2520 template <class TAG, class A, class FromTag=typename A::Tag>
2521 struct LookupTagImpl
2522 #ifndef DOXYGEN
2523 : public LookupTagImpl<TAG, typename A::InternalBaseType>
2524 #endif
2525 {};
2526 
2527  // 'const A' is treated like A, except that the reference member is now const.
2528 template <class TAG, class A, class FromTag>
2529 struct LookupTagImpl<TAG, A const, FromTag>
2530 : public LookupTagImpl<TAG, A>
2531 {
2532  typedef typename LookupTagImpl<TAG, A>::type const & reference;
2533  typedef typename LookupTagImpl<TAG, A>::type const * pointer;
2534 };
2535 
2536  // When A implements TAG, report its type and associated information.
2537 template <class TAG, class A>
2538 struct LookupTagImpl<TAG, A, TAG>
2539 {
2540  typedef TAG Tag;
2541  typedef A type;
2542  typedef A & reference;
2543  typedef A * pointer;
2544  typedef typename A::value_type value_type;
2545  typedef typename A::result_type result_type;
2546 };
2547 
2548  // Again, 'const A' is treated like A, except that the reference member is now const.
2549 template <class TAG, class A>
2550 struct LookupTagImpl<TAG, A const, TAG>
2551 : public LookupTagImpl<TAG, A, TAG>
2552 {
2553  typedef typename LookupTagImpl<TAG, A, TAG>::type const & reference;
2554  typedef typename LookupTagImpl<TAG, A, TAG>::type const * pointer;
2555 };
2556 
2557  // Recursion termination: when we end up in AccumulatorEnd without finding a
2558  // suitable A, we stop and report an error
2559 template <class TAG, class A>
2560 struct LookupTagImpl<TAG, A, AccumulatorEnd>
2561 {
2562  typedef TAG Tag;
2563  typedef A type;
2564  typedef A & reference;
2565  typedef A * pointer;
2566  typedef Error__Attempt_to_access_inactive_statistic<TAG> value_type;
2567  typedef Error__Attempt_to_access_inactive_statistic<TAG> result_type;
2568 };
2569 
2570  // ... except when we are actually looking for AccumulatorEnd
2571 template <class A>
2572 struct LookupTagImpl<AccumulatorEnd, A, AccumulatorEnd>
2573 {
2574  typedef AccumulatorEnd Tag;
2575  typedef A type;
2576  typedef A & reference;
2577  typedef A * pointer;
2578  typedef void value_type;
2579  typedef void result_type;
2580 };
2581 
2582  // ... or we are looking for a global statistic, in which case
2583  // we continue the serach via A::GlobalAccumulatorType, but remember that
2584  // we are actually looking for a global tag.
2585 template <class TAG, class A>
2586 struct LookupTagImpl<Global<TAG>, A, AccumulatorEnd>
2587 : public LookupTagImpl<TAG, typename A::GlobalAccumulatorType>
2588 {
2589  typedef Global<TAG> Tag;
2590 };
2591 
2592  // When we encounter the LabelDispatch accumulator, we continue the
2593  // search via LabelDispatch::RegionAccumulatorChain by default
2594 template <class TAG, class A>
2595 struct LookupTagImpl<TAG, A, LabelDispatchTag>
2596 : public LookupTagImpl<TAG, typename A::RegionAccumulatorChain>
2597 {};
2598 
2599  // ... except when we are looking for a global statistic, in which case
2600  // we continue via LabelDispatch::GlobalAccumulatorChain, but remember that
2601  // we are actually looking for a global tag.
2602 template <class TAG, class A>
2603 struct LookupTagImpl<Global<TAG>, A, LabelDispatchTag>
2604 : public LookupTagImpl<TAG, typename A::GlobalAccumulatorChain>
2605 {
2606  typedef Global<TAG> Tag;
2607 };
2608 
2609  // ... or we are looking for the LabelDispatch accumulator itself
2610 template <class A>
2611 struct LookupTagImpl<LabelDispatchTag, A, LabelDispatchTag>
2612 {
2613  typedef LabelDispatchTag Tag;
2614  typedef A type;
2615  typedef A & reference;
2616  typedef A * pointer;
2617  typedef void value_type;
2618  typedef void result_type;
2619 };
2620 
2621 } // namespace acc_detail
2622 
2623  // Lookup the accumulator in the chain A that implements the given TAG.
2624 template <class Tag, class A>
2625 struct LookupTag
2626 : public acc_detail::LookupTagImpl<typename StandardizeTag<Tag>::type, A>
2627 {};
2628 
2629  // Lookup the dependency TAG of the accumulator A.
2630  // This template ensures that dependencies are used with matching modifiers.
2631  // Specifically, if you search for Count as a dependency of Weighted<Mean>, the search
2632  // actually returns Weighted<Count>, wheras Count will be returned for plain Mean.
2633 template <class Tag, class A, class TargetTag>
2634 struct LookupDependency
2635 : public acc_detail::LookupTagImpl<
2636  typename TransferModifiers<TargetTag, typename StandardizeTag<Tag>::type>::type, A>
2637 {};
2638 
2639 
2640 namespace acc_detail {
2641 
2642  // CastImpl applies the same rules as LookupTagImpl, but returns a reference to an
2643  // accumulator instance rather than an accumulator type
2644 template <class Tag, class FromTag, class reference>
2645 struct CastImpl
2646 {
2647  template <class A>
2648  static reference exec(A & a)
2649  {
2650  return CastImpl<Tag, typename A::InternalBaseType::Tag, reference>::exec(a.next_);
2651  }
2652 
2653  template <class A>
2654  static reference exec(A & a, MultiArrayIndex label)
2655  {
2656  return CastImpl<Tag, typename A::InternalBaseType::Tag, reference>::exec(a.next_, label);
2657  }
2658 };
2659 
2660 template <class Tag, class reference>
2661 struct CastImpl<Tag, Tag, reference>
2662 {
2663  template <class A>
2664  static reference exec(A & a)
2665  {
2666  return const_cast<reference>(a);
2667  }
2668 
2669  template <class A>
2670  static reference exec(A & a, MultiArrayIndex)
2671  {
2672  vigra_precondition(false,
2673  "getAccumulator(): region accumulators can only be queried for AccumulatorChainArray.");
2674  return a;
2675  }
2676 };
2677 
2678 template <class Tag, class reference>
2679 struct CastImpl<Tag, AccumulatorEnd, reference>
2680 {
2681  template <class A>
2682  static reference exec(A & a)
2683  {
2684  return a;
2685  }
2686 
2687  template <class A>
2688  static reference exec(A & a, MultiArrayIndex)
2689  {
2690  return a;
2691  }
2692 };
2693 
2694 template <class Tag, class reference>
2695 struct CastImpl<Global<Tag>, AccumulatorEnd, reference>
2696 {
2697  template <class A>
2698  static reference exec(A & a)
2699  {
2700  return CastImpl<Tag, typename A::GlobalAccumulatorType::Tag, reference>::exec(*a.globalAccumulator_.pointer_);
2701  }
2702 };
2703 
2704 template <class reference>
2705 struct CastImpl<AccumulatorEnd, AccumulatorEnd, reference>
2706 {
2707  template <class A>
2708  static reference exec(A & a)
2709  {
2710  return a;
2711  }
2712 
2713  template <class A>
2714  static reference exec(A & a, MultiArrayIndex)
2715  {
2716  return a;
2717  }
2718 };
2719 
2720 template <class Tag, class reference>
2721 struct CastImpl<Tag, LabelDispatchTag, reference>
2722 {
2723  template <class A>
2724  static reference exec(A & a)
2725  {
2726  vigra_precondition(false,
2727  "getAccumulator(): a region label is required when a region accumulator is queried.");
2728  return CastImpl<Tag, typename A::RegionAccumulatorChain::Tag, reference>::exec(a.regions_[0]);
2729  }
2730 
2731  template <class A>
2732  static reference exec(A & a, MultiArrayIndex label)
2733  {
2734  return CastImpl<Tag, typename A::RegionAccumulatorChain::Tag, reference>::exec(a.regions_[label]);
2735  }
2736 };
2737 
2738 template <class Tag, class reference>
2739 struct CastImpl<Global<Tag>, LabelDispatchTag, reference>
2740 {
2741  template <class A>
2742  static reference exec(A & a)
2743  {
2744  return CastImpl<Tag, typename A::GlobalAccumulatorChain::Tag, reference>::exec(a.next_);
2745  }
2746 };
2747 
2748 template <class reference>
2749 struct CastImpl<LabelDispatchTag, LabelDispatchTag, reference>
2750 {
2751  template <class A>
2752  static reference exec(A & a)
2753  {
2754  return a;
2755  }
2756 };
2757 
2758 } // namespace acc_detail
2759 
2760  // Get a reference to the accumulator TAG in the accumulator chain A
2761 /** Get a reference to the accumulator 'TAG' in the accumulator chain 'a'. This can be useful for example to update a certain accumulator with data, set individual options or get information about a certain accumulator.\n
2762 Example of use (set options):
2763 \code
2764  vigra::MultiArray<2, double> data(...);
2765  typedef UserRangeHistogram<40> SomeHistogram; //binCount set at compile time
2766  typedef UserRangeHistogram<0> SomeHistogram2; // binCount must be set at run-time
2767  AccumulatorChain<DataType, Select<SomeHistogram, SomeHistogram2> > a;
2768 
2769  getAccumulator<SomeHistogram>(a).setMinMax(0.1, 0.9);
2770  getAccumulator<SomeHistogram2>(a).setMinMax(0.0, 1.0);
2771 
2772  extractFeatures(data.begin(), data.end(), a);
2773 \endcode
2774 
2775 Example of use (get information):
2776 \code
2777  vigra::MultiArray<2, double> data(...));
2778  AccumulatorChain<double, Select<Mean, Skewness> > a;
2779 
2780  std::cout << "passes required for all statistics: " << a.passesRequired() << std::endl; //skewness needs two passes
2781  std::cout << "passes required by Mean: " << getAccumulator<Mean>(a).passesRequired() << std::endl;
2782 \endcode
2783 See \ref FeatureAccumulators for more information about feature computation via accumulators.
2784 */
2785 template <class TAG, class A>
2786 inline typename LookupTag<TAG, A>::reference
2788 {
2789  typedef typename LookupTag<TAG, A>::Tag StandardizedTag;
2790  typedef typename LookupTag<TAG, A>::reference reference;
2791  return acc_detail::CastImpl<StandardizedTag, typename A::Tag, reference>::exec(a);
2792 }
2793 
2794  // Get a reference to the accumulator TAG for region 'label' in the accumulator chain A
2795 /** Get a reference to the accumulator 'TAG' for region 'label' in the accumulator chain 'a'.
2796 */
2797 template <class TAG, class A>
2798 inline typename LookupTag<TAG, A>::reference
2800 {
2801  typedef typename LookupTag<TAG, A>::Tag StandardizedTag;
2802  typedef typename LookupTag<TAG, A>::reference reference;
2803  return acc_detail::CastImpl<StandardizedTag, typename A::Tag, reference>::exec(a, label);
2804 }
2805 
2806  // get the result of the accumulator specified by TAG
2807 /** Get the result of the accumulator 'TAG' in the accumulator chain 'a'.\n
2808 Example of use:
2809 \code
2810  vigra::MultiArray<2, double> data(...);
2811  AccumulatorChain<DataType, Select<Variance, Mean, StdDev> > a;
2812  extractFeatures(data.begin(), data.end(), a);
2813  double mean = get<Mean>(a);
2814 \endcode
2815 See \ref FeatureAccumulators for more information about feature computation via accumulators.
2816 */
2817 template <class TAG, class A>
2818 inline typename LookupTag<TAG, A>::result_type
2819 get(A const & a)
2820 {
2821  return getAccumulator<TAG>(a).get();
2822 }
2823 
2824  // get the result of the accumulator TAG for region 'label'
2825 /** Get the result of the accumulator 'TAG' for region 'label' in the accumulator chain 'a'.\n
2826 Example of use:
2827 \code
2828  vigra::MultiArray<2, double> data(...);
2829  vigra::MultiArray<2, int> labels(...);
2830  typedef vigra::CoupledIteratorType<2, double, int>::type Iterator;
2831  typedef Iterator::value_type Handle;
2832 
2833  AccumulatorChainArray<Handle,
2834  Select<DataArg<1>, LabelArg<2>, Mean, Variance> > a;
2835 
2836  Iterator start = createCoupledIterator(data, labels);
2837  Iterator end = start.getEndIterator();
2838  extractFeatures(start,end,a);
2839 
2840  double mean_of_region_1 = get<Mean>(a,1);
2841  double mean_of_background = get<Mean>(a,0);
2842 \endcode
2843 See \ref FeatureAccumulators for more information about feature computation via accumulators.
2844 */
2845 template <class TAG, class A>
2846 inline typename LookupTag<TAG, A>::result_type
2847 get(A const & a, MultiArrayIndex label)
2848 {
2849  return getAccumulator<TAG>(a, label).get();
2850 }
2851 
2852  // Get the result of the accumulator specified by TAG without checking if the accumulator is active.
2853  // This must be used within an accumulator implementation to access dependencies because
2854  // it applies the approprate modifiers to the given TAG. It must not be used in other situations.
2855  // FIXME: is there a shorter name?
2856 template <class TAG, class A>
2857 inline typename LookupDependency<TAG, A>::result_type
2858 getDependency(A const & a)
2859 {
2860  typedef typename LookupDependency<TAG, A>::Tag StandardizedTag;
2861  typedef typename LookupDependency<TAG, A>::reference reference;
2862  return acc_detail::CastImpl<StandardizedTag, typename A::Tag, reference>::exec(a)();
2863 }
2864 
2865  // activate the dynamic accumulator specified by Tag
2866 /** Activate the dynamic accumulator 'Tag' in the dynamic accumulator chain 'a'. Same as a.activate<Tag>() (see DynamicAccumulatorChain::activate<Tag>() or DynamicAccumulatorChainArray::activate<Tag>()). For run-time activation use DynamicAccumulatorChain::activate(std::string tag) or DynamicAccumulatorChainArray::activate(std::string tag) instead.\n
2867 See \ref FeatureAccumulators for more information about feature computation via accumulators.
2868 */
2869 template <class Tag, class A>
2870 inline void
2871 activate(A & a)
2872 {
2873  a.template activate<Tag>();
2874 }
2875 
2876  // check if the dynamic accumulator specified by Tag is active
2877 /** Check if the dynamic accumulator 'Tag' in the accumulator chain 'a' is active. Same as a.isActive<Tag>() (see DynamicAccumulatorChain::isActive<Tag>() or DynamicAccumulatorChainArray::isActive<Tag>()). At run-time, use DynamicAccumulatorChain::isActive(std::string tag) const or DynamicAccumulatorChainArray::isActive(std::string tag) const instead.\n
2878 See \ref FeatureAccumulators for more information about feature computation via accumulators.
2879 */
2880 template <class Tag, class A>
2881 inline bool
2882 isActive(A const & a)
2883 {
2884  return a.template isActive<Tag>();
2885 }
2886 
2887 /****************************************************************************/
2888 /* */
2889 /* generic loops */
2890 /* */
2891 /****************************************************************************/
2892 
2893 /** Generic loop to collect statistics from one or several arrays.
2894 
2895 This function automatically performs as many passes over the data as necessary for the selected statistics. The basic version of <tt>extractFeatures()</tt> takes an iterator pair and a reference to an accumulator chain:
2896 \code
2897 namespace vigra { namespace acc {
2898 
2899  template <class ITERATOR, class ACCUMULATOR>
2900  void extractFeatures(ITERATOR start, ITERATOR end, ACCUMULATOR & a);
2901 }}
2902 \endcode
2903 The <tt>ITERATOR</tt> can be any STL-conforming <i>forward iterator</i> (including raw pointers and \ref vigra::CoupledScanOrderIterator). The <tt>ACCUMULATOR</tt> must be instantiated with the <tt>ITERATOR</tt>'s <tt>value_type</tt> as its first template argument. For example, to use a raw pointer you write:
2904 \code
2905  AccumulatorChain<double, Select<Mean, Variance> > a;
2906 
2907  double * start = ...,
2908  * end = ...;
2909  extractFeatures(start, end, a);
2910 \endcode
2911 Similarly, you can use MultiArray's scan-order iterator:
2912 \code
2913  AccumulatorChain<TinyVector<float, 2>, Select<Mean, Variance> > a;
2914 
2915  MultiArray<3, TinyVector<float, 2> > data(...);
2916  extractFeatures(data.begin(), data.end(), a);
2917 \endcode
2918 An alternative syntax is used when you want to compute weighted or region statistics (or both). Then it is necessary to iterate over several arrays simultaneously. This fact is best conveyed to the accumulator via the helper class \ref vigra::CoupledArrays that is used as the accumulator's first template argument and holds the dimension and value types of the arrays involved. To actually compute the features, you then pass appropriate arrays to the <tt>extractfeatures()</tt> function directly. For example, region statistics can be obtained like this:
2919 \code
2920  MultiArray<3, double> data(...);
2921  MultiArray<3, int> labels(...);
2922 
2923  AccumulatorChainArray<CoupledArrays<3, double, int>,
2924  Select<DataArg<1>, LabelArg<2>, // where to look for data and region labels
2925  Mean, Variance> > // what statistics to compute
2926  a;
2927 
2928  extractFeatures(data, labels, a);
2929 \endcode
2930 This form of <tt>extractFeatures()</tt> is supported for up to five arrays (although at most three are currently making sense in practice):
2931 \code
2932 namespace vigra { namespace acc {
2933 
2934  template <unsigned int N, class T1, class S1,
2935  class ACCUMULATOR>
2936  void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
2937  ACCUMULATOR & a);
2938 
2939  ...
2940 
2941  template <unsigned int N, class T1, class S1,
2942  class T2, class S2,
2943  class T3, class S3,
2944  class T4, class S4,
2945  class T5, class S5,
2946  class ACCUMULATOR>
2947  void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
2948  MultiArrayView<N, T2, S2> const & a2,
2949  MultiArrayView<N, T3, S3> const & a3,
2950  MultiArrayView<N, T4, S4> const & a4,
2951  MultiArrayView<N, T5, S5> const & a5,
2952  ACCUMULATOR & a);
2953 }}
2954 \endcode
2955 Of course, the number and types of the arrays specified in <tt>CoupledArrays</tt> must conform to the number and types of the arrays passed to <tt>extractFeatures()</tt>.
2956 
2957 See \ref FeatureAccumulators for more information about feature computation via accumulators.
2958 */
2959 doxygen_overloaded_function(template <...> void extractFeatures)
2960 
2961 
2962 template <class ITERATOR, class ACCUMULATOR>
2963 void extractFeatures(ITERATOR start, ITERATOR end, ACCUMULATOR & a)
2964 {
2965  for(unsigned int k=1; k <= a.passesRequired(); ++k)
2966  for(ITERATOR i=start; i < end; ++i)
2967  a.updatePassN(*i, k);
2968 }
2969 
2970 template <unsigned int N, class T1, class S1,
2971  class ACCUMULATOR>
2972 void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
2973  ACCUMULATOR & a)
2974 {
2975  typedef typename CoupledIteratorType<N, T1>::type Iterator;
2976  Iterator start = createCoupledIterator(a1),
2977  end = start.getEndIterator();
2978  extractFeatures(start, end, a);
2979 }
2980 
2981 template <unsigned int N, class T1, class S1,
2982  class T2, class S2,
2983  class ACCUMULATOR>
2984 void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
2985  MultiArrayView<N, T2, S2> const & a2,
2986  ACCUMULATOR & a)
2987 {
2988  typedef typename CoupledIteratorType<N, T1, T2>::type Iterator;
2989  Iterator start = createCoupledIterator(a1, a2),
2990  end = start.getEndIterator();
2991  extractFeatures(start, end, a);
2992 }
2993 
2994 template <unsigned int N, class T1, class S1,
2995  class T2, class S2,
2996  class T3, class S3,
2997  class ACCUMULATOR>
2998 void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
2999  MultiArrayView<N, T2, S2> const & a2,
3000  MultiArrayView<N, T3, S3> const & a3,
3001  ACCUMULATOR & a)
3002 {
3003  typedef typename CoupledIteratorType<N, T1, T2, T3>::type Iterator;
3004  Iterator start = createCoupledIterator(a1, a2, a3),
3005  end = start.getEndIterator();
3006  extractFeatures(start, end, a);
3007 }
3008 
3009 template <unsigned int N, class T1, class S1,
3010  class T2, class S2,
3011  class T3, class S3,
3012  class T4, class S4,
3013  class ACCUMULATOR>
3014 void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
3015  MultiArrayView<N, T2, S2> const & a2,
3016  MultiArrayView<N, T3, S3> const & a3,
3017  MultiArrayView<N, T4, S4> const & a4,
3018  ACCUMULATOR & a)
3019 {
3020  typedef typename CoupledIteratorType<N, T1, T2, T3, T4>::type Iterator;
3021  Iterator start = createCoupledIterator(a1, a2, a3, a4),
3022  end = start.getEndIterator();
3023  extractFeatures(start, end, a);
3024 }
3025 
3026 template <unsigned int N, class T1, class S1,
3027  class T2, class S2,
3028  class T3, class S3,
3029  class T4, class S4,
3030  class T5, class S5,
3031  class ACCUMULATOR>
3032 void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
3033  MultiArrayView<N, T2, S2> const & a2,
3034  MultiArrayView<N, T3, S3> const & a3,
3035  MultiArrayView<N, T4, S4> const & a4,
3036  MultiArrayView<N, T5, S5> const & a5,
3037  ACCUMULATOR & a)
3038 {
3039  typedef typename CoupledIteratorType<N, T1, T2, T3, T4, T5>::type Iterator;
3040  Iterator start = createCoupledIterator(a1, a2, a3, a4, a5),
3041  end = start.getEndIterator();
3042  extractFeatures(start, end, a);
3043 }
3044 
3045 /****************************************************************************/
3046 /* */
3047 /* AccumulatorResultTraits */
3048 /* */
3049 /****************************************************************************/
3050 
3051 template <class T>
3052 struct AccumulatorResultTraits
3053 {
3054  typedef T type;
3055  typedef T element_type;
3056  typedef double element_promote_type;
3057  typedef T MinmaxType;
3058  typedef element_promote_type SumType;
3059  typedef element_promote_type FlatCovarianceType;
3060  typedef element_promote_type CovarianceType;
3061 };
3062 
3063 template <class T, int N>
3064 struct AccumulatorResultTraits<TinyVector<T, N> >
3065 {
3066  typedef TinyVector<T, N> type;
3067  typedef T element_type;
3068  typedef double element_promote_type;
3069  typedef TinyVector<T, N> MinmaxType;
3070  typedef TinyVector<element_promote_type, N> SumType;
3071  typedef TinyVector<element_promote_type, N*(N+1)/2> FlatCovarianceType;
3072  typedef Matrix<element_promote_type> CovarianceType;
3073 };
3074 
3075 // (?) beign change
3076 template <class T, unsigned int RED_IDX, unsigned int GREEN_IDX, unsigned int BLUE_IDX>
3077 struct AccumulatorResultTraits<RGBValue<T, RED_IDX, GREEN_IDX, BLUE_IDX> >
3078 {
3079  typedef RGBValue<T> type;
3080  typedef T element_type;
3081  typedef double element_promote_type;
3082  typedef RGBValue<T> MinmaxType;
3083  typedef RGBValue<element_promote_type> SumType;
3084  typedef TinyVector<element_promote_type, 3*(3+1)/2> FlatCovarianceType;
3085  typedef Matrix<element_promote_type> CovarianceType;
3086 };
3087 // end change
3088 
3089 
3090 template <unsigned int N, class T, class Stride>
3091 struct AccumulatorResultTraits<MultiArrayView<N, T, Stride> >
3092 {
3093  typedef MultiArrayView<N, T, Stride> type;
3094  typedef T element_type;
3095  typedef double element_promote_type;
3096  typedef MultiArray<N, T> MinmaxType;
3097  typedef MultiArray<N, element_promote_type> SumType;
3098  typedef MultiArray<1, element_promote_type> FlatCovarianceType;
3099  typedef Matrix<element_promote_type> CovarianceType;
3100 };
3101 
3102 template <unsigned int N, class T, class Alloc>
3103 struct AccumulatorResultTraits<MultiArray<N, T, Alloc> >
3104 {
3105  typedef MultiArrayView<N, T, Alloc> type;
3106  typedef T element_type;
3107  typedef double element_promote_type;
3108  typedef MultiArray<N, T> MinmaxType;
3109  typedef MultiArray<N, element_promote_type> SumType;
3110  typedef MultiArray<1, element_promote_type> FlatCovarianceType;
3111  typedef Matrix<element_promote_type> CovarianceType;
3112 };
3113 
3114 /****************************************************************************/
3115 /* */
3116 /* modifier implementations */
3117 /* */
3118 /****************************************************************************/
3119 
3120 /** \brief Modifier. Compute statistic globally rather than per region.
3121 
3122 This modifier only works when labels are given (with (Dynamic)AccumulatorChainArray), in which case statistics are computed per-region by default.
3123 */
3124 template <class TAG>
3125 class Global
3126 {
3127  public:
3128  typedef typename StandardizeTag<TAG>::type TargetTag;
3129  typedef typename TargetTag::Dependencies Dependencies;
3130 
3131  static std::string name()
3132  {
3133  return std::string("Global<") + TargetTag::name() + " >";
3134  // static const std::string n = std::string("Global<") + TargetTag::name() + " >";
3135  // return n;
3136  }
3137 };
3138 
3139 /** \brief Specifies index of data in CoupledHandle.
3140 
3141  If AccumulatorChain is used with CoupledIterator, DataArg<INDEX> tells the accumulator chain which index of the Handle contains the data. (Coordinates are always index 0)
3142 */
3143 template <int INDEX>
3144 class DataArg
3145 {
3146  public:
3147  typedef Select<> Dependencies;
3148 
3149  static std::string name()
3150  {
3151  return std::string("DataArg<") + asString(INDEX) + "> (internal)";
3152  // static const std::string n = std::string("DataArg<") + asString(INDEX) + "> (internal)";
3153  // return n;
3154  }
3155 
3156  template <class T, class BASE>
3157  struct Impl
3158  : public BASE
3159  {
3160  typedef DataArgTag Tag;
3161  typedef void value_type;
3162  typedef void result_type;
3163 
3164  static const int value = INDEX;
3165  static const unsigned int workInPass = 0;
3166  };
3167 };
3168 
3169 namespace acc_detail {
3170 
3171 template <class T, int DEFAULT, class TAG, class IndexDefinition,
3172  class TagFound=typename IndexDefinition::Tag>
3173 struct HandleArgSelectorImpl
3174 {
3175  static const int value = DEFAULT;
3176  typedef typename CoupledHandleCast<value, T>::type type;
3177  typedef typename CoupledHandleCast<value, T>::value_type value_type;
3178  static const int size = type::dimensions;
3179 
3180  template <class U, class NEXT>
3181  static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type const &
3182  getHandle(CoupledHandle<U, NEXT> const & t)
3183  {
3184  return vigra::cast<value>(t);
3185  }
3186 
3187  template <class U, class NEXT>
3188  static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type::const_reference
3189  getValue(CoupledHandle<U, NEXT> const & t)
3190  {
3191  return vigra::get<value>(t);
3192  }
3193 };
3194 
3195 template <class T, int DEFAULT, class TAG, class IndexDefinition>
3196 struct HandleArgSelectorImpl<T, DEFAULT, TAG, IndexDefinition, TAG>
3197 {
3198  static const int value = IndexDefinition::value;
3199  typedef typename CoupledHandleCast<value, T>::type type;
3200  typedef typename CoupledHandleCast<value, T>::value_type value_type;
3201  static const int size = type::dimensions;
3202 
3203  template <class U, class NEXT>
3204  static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type const &
3205  getHandle(CoupledHandle<U, NEXT> const & t)
3206  {
3207  return vigra::cast<value>(t);
3208  }
3209 
3210  template <class U, class NEXT>
3211  static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type::const_reference
3212  getValue(CoupledHandle<U, NEXT> const & t)
3213  {
3214  return vigra::get<value>(t);
3215  }
3216 };
3217 
3218 } // namespace acc_detail
3219 
3220 template <class T, class CHAIN>
3221 struct HandleArgSelector<T, LabelArgTag, CHAIN>
3222 : public acc_detail::HandleArgSelectorImpl<T, 2, LabelArgTag,
3223  typename LookupTag<LabelArgTag, CHAIN>::type>
3224 {};
3225 
3226 template <class T, class CHAIN>
3227 struct HandleArgSelector<T, DataArgTag, CHAIN>
3228 : public acc_detail::HandleArgSelectorImpl<T, 1, DataArgTag,
3229  typename LookupTag<DataArgTag, CHAIN>::type>
3230 {};
3231 
3232 template <class T, class CHAIN>
3233 struct HandleArgSelector<T, CoordArgTag, CHAIN>
3234 : public acc_detail::HandleArgSelectorImpl<T, 0, CoordArgTag,
3235  typename LookupTag<CoordArgTag, CHAIN>::type>
3236 {
3237  typedef acc_detail::HandleArgSelectorImpl<T, 0, CoordArgTag,
3238  typename LookupTag<CoordArgTag, CHAIN>::type> base_type;
3239  typedef TinyVector<double, base_type::size> value_type;
3240 };
3241 
3242 // Tags are automatically wrapped with DataFromHandle if CoupledHandle used
3243 template <class TAG>
3244 class DataFromHandle
3245 {
3246  public:
3247  typedef typename StandardizeTag<TAG>::type TargetTag;
3248  typedef typename TargetTag::Dependencies Dependencies;
3249 
3250  static std::string name()
3251  {
3252  return std::string("DataFromHandle<") + TargetTag::name() + " > (internal)";
3253  // static const std::string n = std::string("DataFromHandle<") + TargetTag::name() + " > (internal)";
3254  // return n;
3255  }
3256 
3257  template <class T, class BASE>
3258  struct Impl
3259  : public TargetTag::template Impl<typename HandleArgSelector<T, DataArgTag, BASE>::value_type, BASE>
3260  {
3261  typedef HandleArgSelector<T, DataArgTag, BASE> DataHandle;
3262  typedef typename DataHandle::value_type input_type;
3263  typedef input_type const & argument_type;
3264  typedef argument_type first_argument_type;
3265 
3266  typedef typename TargetTag::template Impl<input_type, BASE> ImplType;
3267 
3268  using ImplType::reshape;
3269 
3270  template <class U, class NEXT>
3271  void reshape(CoupledHandle<U, NEXT> const & t)
3272  {
3273  ImplType::reshape(acc_detail::shapeOf(DataHandle::getValue(t)));
3274  }
3275 
3276  template <class U, class NEXT>
3277  void update(CoupledHandle<U, NEXT> const & t)
3278  {
3279  ImplType::update(DataHandle::getValue(t));
3280  }
3281 
3282  template <class U, class NEXT>
3283  void update(CoupledHandle<U, NEXT> const & t, double weight)
3284  {
3285  ImplType::update(DataHandle::getValue(t), weight);
3286  }
3287  };
3288 };
3289 
3290 /** \brief Modifier. Compute statistic from pixel coordinates rather than from pixel values.
3291 
3292  AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
3293  */
3294 template <class TAG>
3295 class Coord
3296 {
3297  public:
3298  typedef typename StandardizeTag<TAG>::type TargetTag;
3299  typedef typename TargetTag::Dependencies Dependencies;
3300 
3301  static std::string name()
3302  {
3303  return std::string("Coord<") + TargetTag::name() + " >";
3304  // static const std::string n = std::string("Coord<") + TargetTag::name() + " >";
3305  // return n;
3306  }
3307 
3308  template <class T, class BASE>
3309  struct Impl
3310  : public TargetTag::template Impl<typename HandleArgSelector<T, CoordArgTag, BASE>::value_type, BASE>
3311  {
3312  typedef HandleArgSelector<T, CoordArgTag, BASE> CoordHandle;
3313  typedef typename CoordHandle::value_type input_type;
3314  typedef input_type const & argument_type;
3315  typedef argument_type first_argument_type;
3316 
3317  typedef typename TargetTag::template Impl<input_type, BASE> ImplType;
3318 
3319  input_type offset_;
3320 
3321  Impl()
3322  : offset_()
3323  {}
3324 
3325  void setCoordinateOffset(input_type const & offset)
3326  {
3327  offset_ = offset;
3328  }
3329 
3330  using ImplType::reshape;
3331 
3332  template <class U, class NEXT>
3333  void reshape(CoupledHandle<U, NEXT> const & t)
3334  {
3335  ImplType::reshape(acc_detail::shapeOf(CoordHandle::getValue(t)));
3336  }
3337 
3338  template <class U, class NEXT>
3339  void update(CoupledHandle<U, NEXT> const & t)
3340  {
3341  ImplType::update(CoordHandle::getValue(t)+offset_);
3342  }
3343 
3344  template <class U, class NEXT>
3345  void update(CoupledHandle<U, NEXT> const & t, double weight)
3346  {
3347  ImplType::update(CoordHandle::getValue(t)+offset_, weight);
3348  }
3349  };
3350 };
3351 
3352 /** \brief Specifies index of data in CoupledHandle.
3353 
3354  If AccumulatorChain is used with CoupledIterator, WeightArg<INDEX> tells the accumulator chain which index of the Handle contains the weights. (Note that coordinates are always index 0.)
3355 */
3356 template <int INDEX>
3357 class WeightArg
3358 {
3359  public:
3360  typedef Select<> Dependencies;
3361 
3362  static std::string name()
3363  {
3364  return std::string("WeightArg<") + asString(INDEX) + "> (internal)";
3365  // static const std::string n = std::string("WeightArg<") + asString(INDEX) + "> (internal)";
3366  // return n;
3367  }
3368 
3369  template <class T, class BASE>
3370  struct Impl
3371  : public BASE
3372  {
3373  typedef WeightArgTag Tag;
3374  typedef void value_type;
3375  typedef void result_type;
3376 
3377  static const int value = INDEX;
3378  static const unsigned int workInPass = 0;
3379  };
3380 };
3381 
3382 /** \brief Compute weighted version of the statistic.
3383 */
3384 template <class TAG>
3385 class Weighted
3386 {
3387  public:
3388  typedef typename StandardizeTag<TAG>::type TargetTag;
3389  typedef typename TargetTag::Dependencies Dependencies;
3390 
3391  static std::string name()
3392  {
3393  return std::string("Weighted<") + TargetTag::name() + " >";
3394  // static const std::string n = std::string("Weighted<") + TargetTag::name() + " >";
3395  // return n;
3396  }
3397 
3398  template <class IndexDefinition, class TagFound=typename IndexDefinition::Tag>
3399  struct WeightIndexSelector
3400  {
3401  template <class U, class NEXT>
3402  static double exec(CoupledHandle<U, NEXT> const & t)
3403  {
3404  return (double)*t; // default: CoupledHandle holds weights at the last (outermost) index
3405  }
3406  };
3407 
3408  template <class IndexDefinition>
3409  struct WeightIndexSelector<IndexDefinition, WeightArgTag>
3410  {
3411  template <class U, class NEXT>
3412  static double exec(CoupledHandle<U, NEXT> const & t)
3413  {
3414  return (double)get<IndexDefinition::value>(t);
3415  }
3416  };
3417 
3418  template <class T, class BASE>
3419  struct Impl
3420  : public TargetTag::template Impl<T, BASE>
3421  {
3422  typedef typename TargetTag::template Impl<T, BASE> ImplType;
3423 
3424  typedef typename LookupTag<WeightArgTag, BASE>::type FindWeightIndex;
3425 
3426  template <class U, class NEXT>
3427  void update(CoupledHandle<U, NEXT> const & t)
3428  {
3429  ImplType::update(t, WeightIndexSelector<FindWeightIndex>::exec(t));
3430  }
3431  };
3432 };
3433 
3434 // Centralize by subtracting the mean and cache the result
3435 class Centralize
3436 {
3437  public:
3438  typedef Select<Mean> Dependencies;
3439 
3440  static std::string name()
3441  {
3442  return "Centralize (internal)";
3443  // static const std::string n("Centralize (internal)");
3444  // return n;
3445  }
3446 
3447  template <class U, class BASE>
3448  struct Impl
3449  : public BASE
3450  {
3451  static const unsigned int workInPass = 2;
3452 
3453  typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
3454  typedef typename AccumulatorResultTraits<U>::SumType value_type;
3455  typedef value_type const & result_type;
3456 
3457  mutable value_type value_;
3458 
3459  Impl()
3460  : value_() // call default constructor explicitly to ensure zero initialization
3461  {}
3462 
3463  void reset()
3464  {
3465  value_ = element_type();
3466  }
3467 
3468  template <class Shape>
3469  void reshape(Shape const & s)
3470  {
3471  acc_detail::reshapeImpl(value_, s);
3472  }
3473 
3474  void update(U const & t) const
3475  {
3476  using namespace vigra::multi_math;
3477  value_ = t - getDependency<Mean>(*this);
3478  }
3479 
3480  void update(U const & t, double) const
3481  {
3482  update(t);
3483  }
3484 
3485  result_type operator()(U const & t) const
3486  {
3487  update(t);
3488  return value_;
3489  }
3490 
3491  result_type operator()() const
3492  {
3493  return value_;
3494  }
3495  };
3496 };
3497 
3498 /** \brief Modifier. Substract mean before computing statistic.
3499 
3500 Works in pass 2, %operator+=() not supported (merging not supported).
3501 */
3502 template <class TAG>
3503 class Central
3504 {
3505  public:
3506  typedef typename StandardizeTag<TAG>::type TargetTag;
3507  typedef Select<Centralize, typename TargetTag::Dependencies> Dependencies;
3508 
3509  static std::string name()
3510  {
3511  return std::string("Central<") + TargetTag::name() + " >";
3512  // static const std::string n = std::string("Central<") + TargetTag::name() + " >";
3513  // return n;
3514  }
3515 
3516  template <class U, class BASE>
3517  struct Impl
3518  : public TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE>
3519  {
3520  typedef typename TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE> ImplType;
3521 
3522  static const unsigned int workInPass = 2;
3523 
3524  void operator+=(Impl const & o)
3525  {
3526  vigra_precondition(false,
3527  "Central<...>::operator+=(): not supported.");
3528  }
3529 
3530  template <class T>
3531  void update(T const & t)
3532  {
3533  ImplType::update(getDependency<Centralize>(*this));
3534  }
3535 
3536  template <class T>
3537  void update(T const & t, double weight)
3538  {
3539  ImplType::update(getDependency<Centralize>(*this), weight);
3540  }
3541  };
3542 };
3543 
3544  // alternative implementation without caching
3545  //
3546 // template <class TAG>
3547 // class Central
3548 // {
3549  // public:
3550  // typedef typename StandardizeTag<TAG>::type TargetTag;
3551  // typedef TypeList<Mean, typename TransferModifiers<Central<TargetTag>, typename TargetTag::Dependencies::type>::type> Dependencies;
3552 
3553  // template <class U, class BASE>
3554  // struct Impl
3555  // : public TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE>
3556  // {
3557  // typedef typename TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE> ImplType;
3558 
3559  // static const unsigned int workInPass = 2;
3560 
3561  // void operator+=(Impl const & o)
3562  // {
3563  // vigra_precondition(false,
3564  // "Central<...>::operator+=(): not supported.");
3565  // }
3566 
3567  // template <class T>
3568  // void update(T const & t)
3569  // {
3570  // ImplType::update(t - getDependency<Mean>(*this));
3571  // }
3572 
3573  // template <class T>
3574  // void update(T const & t, double weight)
3575  // {
3576  // ImplType::update(t - getDependency<Mean>(*this), weight);
3577  // }
3578  // };
3579 // };
3580 
3581 
3582 class PrincipalProjection
3583 {
3584  public:
3585  typedef Select<Centralize, Principal<CoordinateSystem> > Dependencies;
3586 
3587  static std::string name()
3588  {
3589  return "PrincipalProjection (internal)";
3590  // static const std::string n("PrincipalProjection (internal)");
3591  // return n;
3592  }
3593 
3594  template <class U, class BASE>
3595  struct Impl
3596  : public BASE
3597  {
3598  static const unsigned int workInPass = 2;
3599 
3600  typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
3601  typedef typename AccumulatorResultTraits<U>::SumType value_type;
3602  typedef value_type const & result_type;
3603 
3604  mutable value_type value_;
3605 
3606  Impl()
3607  : value_() // call default constructor explicitly to ensure zero initialization
3608  {}
3609 
3610  void reset()
3611  {
3612  value_ = element_type();
3613  }
3614 
3615  template <class Shape>
3616  void reshape(Shape const & s)
3617  {
3618  acc_detail::reshapeImpl(value_, s);
3619  }
3620 
3621  void update(U const & t) const
3622  {
3623  for(unsigned int k=0; k<t.size(); ++k)
3624  {
3625  value_[k] = getDependency<Principal<CoordinateSystem> >(*this)(0, k)*getDependency<Centralize>(*this)[0];
3626  for(unsigned int d=1; d<t.size(); ++d)
3627  value_[k] += getDependency<Principal<CoordinateSystem> >(*this)(d, k)*getDependency<Centralize>(*this)[d];
3628  }
3629  }
3630 
3631  void update(U const & t, double) const
3632  {
3633  update(t);
3634  }
3635 
3636  result_type operator()(U const & t) const
3637  {
3638  getAccumulator<Centralize>(*this).update(t);
3639  update(t);
3640  return value_;
3641  }
3642 
3643  result_type operator()() const
3644  {
3645  return value_;
3646  }
3647  };
3648 };
3649 
3650 /** \brief Modifier. Project onto PCA eigenvectors.
3651 
3652  Works in pass 2, %operator+=() not supported (merging not supported).
3653 */
3654 template <class TAG>
3655 class Principal
3656 {
3657  public:
3658  typedef typename StandardizeTag<TAG>::type TargetTag;
3659  typedef Select<PrincipalProjection, typename TargetTag::Dependencies> Dependencies;
3660 
3661  static std::string name()
3662  {
3663  return std::string("Principal<") + TargetTag::name() + " >";
3664  // static const std::string n = std::string("Principal<") + TargetTag::name() + " >";
3665  // return n;
3666  }
3667 
3668  template <class U, class BASE>
3669  struct Impl
3670  : public TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE>
3671  {
3672  typedef typename TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE> ImplType;
3673 
3674  static const unsigned int workInPass = 2;
3675 
3676  void operator+=(Impl const & o)
3677  {
3678  vigra_precondition(false,
3679  "Principal<...>::operator+=(): not supported.");
3680  }
3681 
3682  template <class T>
3683  void update(T const & t)
3684  {
3685  ImplType::update(getDependency<PrincipalProjection>(*this));
3686  }
3687 
3688  template <class T>
3689  void update(T const & t, double weight)
3690  {
3691  ImplType::update(getDependency<PrincipalProjection>(*this), weight);
3692  }
3693  };
3694 };
3695 
3696 /*
3697 important notes on modifiers:
3698  * upon accumulator creation, modifiers are reordered so that data preparation is innermost,
3699  and data access is outermost, e.g.:
3700  Coord<DivideByCount<Principal<PowerSum<2> > > >
3701  * modifiers are automatically transfered to dependencies as appropriate
3702  * modifiers for lookup (getAccumulator and get) of dependent accumulators are automatically adjusted
3703  * modifiers must adjust workInPass for the contained accumulator as appropriate
3704  * we may implement convenience versions of Select that apply a modifier to all
3705  contained tags at once
3706  * weighted accumulators have their own Count object when used together
3707  with unweighted ones (this is as yet untested - FIXME)
3708  * certain accumulators must remain unchanged when wrapped in certain modifiers:
3709  * Count: always except for Weighted<Count> and CoordWeighted<Count>
3710  * Sum: data preparation modifiers
3711  * FlatScatterMatrixImpl, CovarianceEigensystemImpl: Principal and Whitened
3712  * will it be useful to implement initPass<N>() or finalizePass<N>() ?
3713 */
3714 
3715 /****************************************************************************/
3716 /* */
3717 /* the actual accumulators */
3718 /* */
3719 /****************************************************************************/
3720 
3721 /** \brief Basic statistic. Identity matrix of appropriate size.
3722 */
3724 {
3725  public:
3726  typedef Select<> Dependencies;
3727 
3728  static std::string name()
3729  {
3730  return "CoordinateSystem";
3731  // static const std::string n("CoordinateSystem");
3732  // return n;
3733  }
3734 
3735  template <class U, class BASE>
3736  struct Impl
3737  : public BASE
3738  {
3739  typedef double element_type;
3740  typedef Matrix<double> value_type;
3741  typedef value_type const & result_type;
3742 
3743  value_type value_;
3744 
3745  Impl()
3746  : value_() // call default constructor explicitly to ensure zero initialization
3747  {}
3748 
3749  void reset()
3750  {
3751  value_ = element_type();
3752  }
3753 
3754  template <class Shape>
3755  void reshape(Shape const & s)
3756  {
3757  acc_detail::reshapeImpl(value_, s);
3758  }
3759 
3760  result_type operator()() const
3761  {
3762  return value_;
3763  }
3764  };
3765 };
3766 
3767 template <class BASE, class T,
3768  class ElementType=typename AccumulatorResultTraits<T>::element_promote_type,
3769  class SumType=typename AccumulatorResultTraits<T>::SumType>
3770 struct SumBaseImpl
3771 : public BASE
3772 {
3773  typedef ElementType element_type;
3774  typedef SumType value_type;
3775  typedef value_type const & result_type;
3776 
3777  value_type value_;
3778 
3779  SumBaseImpl()
3780  : value_() // call default constructor explicitly to ensure zero initialization
3781  {}
3782 
3783  void reset()
3784  {
3785  value_ = element_type();
3786  }
3787 
3788  template <class Shape>
3789  void reshape(Shape const & s)
3790  {
3791  acc_detail::reshapeImpl(value_, s);
3792  }
3793 
3794  void operator+=(SumBaseImpl const & o)
3795  {
3796  value_ += o.value_;
3797  }
3798 
3799  result_type operator()() const
3800  {
3801  return value_;
3802  }
3803 };
3804 
3805 // Count
3806 template <>
3807 class PowerSum<0>
3808 {
3809  public:
3810  typedef Select<> Dependencies;
3811 
3812  static std::string name()
3813  {
3814  return "PowerSum<0>";
3815  // static const std::string n("PowerSum<0>");
3816  // return n;
3817  }
3818 
3819  template <class T, class BASE>
3820  struct Impl
3821  : public SumBaseImpl<BASE, T, double, double>
3822  {
3823  void update(T const & t)
3824  {
3825  ++this->value_;
3826  }
3827 
3828  void update(T const & t, double weight)
3829  {
3830  this->value_ += weight;
3831  }
3832  };
3833 };
3834 
3835 // Sum
3836 template <>
3837 class PowerSum<1>
3838 {
3839  public:
3840  typedef Select<> Dependencies;
3841 
3842  static std::string name()
3843  {
3844  return "PowerSum<1>";
3845  // static const std::string n("PowerSum<1>");
3846  // return n;
3847  }
3848 
3849  template <class U, class BASE>
3850  struct Impl
3851  : public SumBaseImpl<BASE, U>
3852  {
3853  void update(U const & t)
3854  {
3855  this->value_ += t;
3856  }
3857 
3858  void update(U const & t, double weight)
3859  {
3860  using namespace multi_math;
3861 
3862  this->value_ += weight*t;
3863  }
3864  };
3865 };
3866 
3867 /** \brief Basic statistic. PowerSum<N> =@f$ \sum_i x_i^N @f$
3868 
3869  Works in pass 1, %operator+=() supported (merging supported).
3870 */
3871 template <unsigned N>
3872 class PowerSum
3873 {
3874  public:
3875  typedef Select<> Dependencies;
3876 
3877  static std::string name()
3878  {
3879  return std::string("PowerSum<") + asString(N) + ">";
3880  // static const std::string n = std::string("PowerSum<") + asString(N) + ">";
3881  // return n;
3882  }
3883 
3884  template <class U, class BASE>
3885  struct Impl
3886  : public SumBaseImpl<BASE, U>
3887  {
3888  void update(U const & t)
3889  {
3890  using namespace vigra::multi_math;
3891  this->value_ += pow(t, (int)N);
3892  }
3893 
3894  void update(U const & t, double weight)
3895  {
3896  using namespace vigra::multi_math;
3897  this->value_ += weight*pow(t, (int)N);
3898  }
3899  };
3900 };
3901 
3902 template <>
3903 class AbsPowerSum<1>
3904 {
3905  public:
3906  typedef Select<> Dependencies;
3907 
3908  static std::string name()
3909  {
3910  return "AbsPowerSum<1>";
3911  // static const std::string n("AbsPowerSum<1>");
3912  // return n;
3913  }
3914 
3915  template <class U, class BASE>
3916  struct Impl
3917  : public SumBaseImpl<BASE, U>
3918  {
3919  void update(U const & t)
3920  {
3921  using namespace vigra::multi_math;
3922  this->value_ += abs(t);
3923  }
3924 
3925  void update(U const & t, double weight)
3926  {
3927  using namespace vigra::multi_math;
3928  this->value_ += weight*abs(t);
3929  }
3930  };
3931 };
3932 
3933 /** \brief Basic statistic. AbsPowerSum<N> =@f$ \sum_i |x_i|^N @f$
3934 
3935  Works in pass 1, %operator+=() supported (merging supported).
3936 */
3937 template <unsigned N>
3938 class AbsPowerSum
3939 {
3940  public:
3941  typedef Select<> Dependencies;
3942 
3943  static std::string name()
3944  {
3945  return std::string("AbsPowerSum<") + asString(N) + ">";
3946  // static const std::string n = std::string("AbsPowerSum<") + asString(N) + ">";
3947  // return n;
3948  }
3949 
3950  template <class U, class BASE>
3951  struct Impl
3952  : public SumBaseImpl<BASE, U>
3953  {
3954  void update(U const & t)
3955  {
3956  using namespace vigra::multi_math;
3957  this->value_ += pow(abs(t), (int)N);
3958  }
3959 
3960  void update(U const & t, double weight)
3961  {
3962  using namespace vigra::multi_math;
3963  this->value_ += weight*pow(abs(t), (int)N);
3964  }
3965  };
3966 };
3967 
3968 template <class BASE, class VALUE_TYPE, class U>
3969 struct CachedResultBase
3970 : public BASE
3971 {
3972  typedef typename AccumulatorResultTraits<U>::element_type element_type;
3973  typedef VALUE_TYPE value_type;
3974  typedef value_type const & result_type;
3975 
3976  mutable value_type value_;
3977 
3978  CachedResultBase()
3979  : value_() // call default constructor explicitly to ensure zero initialization
3980  {}
3981 
3982  void reset()
3983  {
3984  value_ = element_type();
3985  this->setClean();
3986  }
3987 
3988  template <class Shape>
3989  void reshape(Shape const & s)
3990  {
3991  acc_detail::reshapeImpl(value_, s);
3992  }
3993 
3994  void operator+=(CachedResultBase const &)
3995  {
3996  this->setDirty();
3997  }
3998 
3999  void update(U const &)
4000  {
4001  this->setDirty();
4002  }
4003 
4004  void update(U const &, double)
4005  {
4006  this->setDirty();
4007  }
4008 };
4009 
4010 // cached Mean and Variance
4011 /** \brief Modifier. Divide statistic by Count: DivideByCount<TAG> = TAG / Count .
4012 */
4013 template <class TAG>
4014 class DivideByCount
4015 {
4016  public:
4017  typedef typename StandardizeTag<TAG>::type TargetTag;
4018  typedef Select<TargetTag, Count> Dependencies;
4019 
4020  static std::string name()
4021  {
4022  return std::string("DivideByCount<") + TargetTag::name() + " >";
4023  // static const std::string n = std::string("DivideByCount<") + TargetTag::name() + " >";
4024  // return n;
4025  }
4026 
4027  template <class U, class BASE>
4028  struct Impl
4029  : public CachedResultBase<BASE, typename LookupDependency<TargetTag, BASE>::value_type, U>
4030  {
4031  typedef typename CachedResultBase<BASE, typename LookupDependency<TargetTag, BASE>::value_type, U>::result_type result_type;
4032 
4033  result_type operator()() const
4034  {
4035  if(this->isDirty())
4036  {
4037  using namespace multi_math;
4038  this->value_ = getDependency<TargetTag>(*this) / getDependency<Count>(*this);
4039  this->setClean();
4040  }
4041  return this->value_;
4042  }
4043  };
4044 };
4045 
4046 // UnbiasedVariance
4047 /** \brief Modifier. Divide statistics by Count-1: DivideUnbiased<TAG> = TAG / (Count-1)
4048 */
4049 template <class TAG>
4050 class DivideUnbiased
4051 {
4052  public:
4053  typedef typename StandardizeTag<TAG>::type TargetTag;
4054  typedef Select<TargetTag, Count> Dependencies;
4055 
4056  static std::string name()
4057  {
4058  return std::string("DivideUnbiased<") + TargetTag::name() + " >";
4059  // static const std::string n = std::string("DivideUnbiased<") + TargetTag::name() + " >";
4060  // return n;
4061  }
4062 
4063  template <class U, class BASE>
4064  struct Impl
4065  : public BASE
4066  {
4067  typedef typename LookupDependency<TargetTag, BASE>::value_type value_type;
4068  typedef value_type result_type;
4069 
4070  result_type operator()() const
4071  {
4072  using namespace multi_math;
4073  return getDependency<TargetTag>(*this) / (getDependency<Count>(*this) - 1.0);
4074  }
4075  };
4076 };
4077 
4078 // RootMeanSquares and StdDev
4079 /** \brief Modifier. RootDivideByCount<TAG> = sqrt( TAG/Count )
4080 */
4081 template <class TAG>
4082 class RootDivideByCount
4083 {
4084  public:
4085  typedef typename StandardizeTag<DivideByCount<TAG> >::type TargetTag;
4086  typedef Select<TargetTag> Dependencies;
4087 
4088  static std::string name()
4089  {
4090  typedef typename StandardizeTag<TAG>::type InnerTag;
4091  return std::string("RootDivideByCount<") + InnerTag::name() + " >";
4092  // static const std::string n = std::string("RootDivideByCount<") + InnerTag::name() + " >";
4093  // return n;
4094  }
4095 
4096  template <class U, class BASE>
4097  struct Impl
4098  : public BASE
4099  {
4100  typedef typename LookupDependency<TargetTag, BASE>::value_type value_type;
4101  typedef value_type result_type;
4102 
4103  result_type operator()() const
4104  {
4105  using namespace multi_math;
4106  return sqrt(getDependency<TargetTag>(*this));
4107  }
4108  };
4109 };
4110 
4111 // UnbiasedStdDev
4112 /** \brief Modifier. RootDivideUnbiased<TAG> = sqrt( TAG / (Count-1) )
4113 */
4114 template <class TAG>
4115 class RootDivideUnbiased
4116 {
4117  public:
4118  typedef typename StandardizeTag<DivideUnbiased<TAG> >::type TargetTag;
4119  typedef Select<TargetTag> Dependencies;
4120 
4121  static std::string name()
4122  {
4123  typedef typename StandardizeTag<TAG>::type InnerTag;
4124  return std::string("RootDivideUnbiased<") + InnerTag::name() + " >";
4125  // static const std::string n = std::string("RootDivideUnbiased<") + InnerTag::name() + " >";
4126  // return n;
4127  }
4128 
4129  template <class U, class BASE>
4130  struct Impl
4131  : public BASE
4132  {
4133  typedef typename LookupDependency<TargetTag, BASE>::value_type value_type;
4134  typedef value_type result_type;
4135 
4136  result_type operator()() const
4137  {
4138  using namespace multi_math;
4139  return sqrt(getDependency<TargetTag>(*this));
4140  }
4141  };
4142 };
4143 
4144 /** \brief Spezialization: works in pass 1, %operator+=() supported (merging supported).
4145 */
4146 template <>
4147 class Central<PowerSum<2> >
4148 {
4149  public:
4151 
4152  static std::string name()
4153  {
4154  return "Central<PowerSum<2> >";
4155  // static const std::string n("Central<PowerSum<2> >");
4156  // return n;
4157  }
4158 
4159  template <class U, class BASE>
4160  struct Impl
4161  : public SumBaseImpl<BASE, U>
4162  {
4163  void operator+=(Impl const & o)
4164  {
4165  using namespace vigra::multi_math;
4166  double n1 = getDependency<Count>(*this), n2 = getDependency<Count>(o);
4167  if(n1 == 0.0)
4168  {
4169  this->value_ = o.value_;
4170  }
4171  else if(n2 != 0.0)
4172  {
4173  this->value_ += o.value_ + n1 * n2 / (n1 + n2) * sq(getDependency<Mean>(*this) - getDependency<Mean>(o));
4174  }
4175  }
4176 
4177  void update(U const & t)
4178  {
4179  double n = getDependency<Count>(*this);
4180  if(n > 1.0)
4181  {
4182  using namespace vigra::multi_math;
4183  this->value_ += n / (n - 1.0) * sq(getDependency<Mean>(*this) - t);
4184  }
4185  }
4186 
4187  void update(U const & t, double weight)
4188  {
4189  double n = getDependency<Count>(*this);
4190  if(n > weight)
4191  {
4192  using namespace vigra::multi_math;
4193  this->value_ += n / (n - weight) * sq(getDependency<Mean>(*this) - t);
4194  }
4195  }
4196  };
4197 };
4198 
4199 /** \brief Specialization: works in pass 2, %operator+=() supported (merging supported).
4200 */
4201 template <>
4202 class Central<PowerSum<3> >
4203 {
4204  public:
4206 
4207  static std::string name()
4208  {
4209  return "Central<PowerSum<3> >";
4210  // static const std::string n("Central<PowerSum<3> >");
4211  // return n;
4212  }
4213 
4214  template <class U, class BASE>
4215  struct Impl
4216  : public SumBaseImpl<BASE, U>
4217  {
4218  typedef typename SumBaseImpl<BASE, U>::value_type value_type;
4219 
4220  static const unsigned int workInPass = 2;
4221 
4222  void operator+=(Impl const & o)
4223  {
4224  typedef Central<PowerSum<2> > Sum2Tag;
4225 
4226  using namespace vigra::multi_math;
4227  double n1 = getDependency<Count>(*this), n2 = getDependency<Count>(o);
4228  if(n1 == 0.0)
4229  {
4230  this->value_ = o.value_;
4231  }
4232  else if(n2 != 0.0)
4233  {
4234  double n = n1 + n2;
4235  double weight = n1 * n2 * (n1 - n2) / sq(n);
4236  value_type delta = getDependency<Mean>(o) - getDependency<Mean>(*this);
4237  this->value_ += o.value_ + weight * pow(delta, 3) +
4238  3.0 / n * delta * (n1 * getDependency<Sum2Tag>(o) - n2 * getDependency<Sum2Tag>(*this));
4239  }
4240  }
4241 
4242  void update(U const & t)
4243  {
4244  using namespace vigra::multi_math;
4245  this->value_ += pow(getDependency<Centralize>(*this), 3);
4246  }
4247 
4248  void update(U const & t, double weight)
4249  {
4250  using namespace vigra::multi_math;
4251  this->value_ += weight*pow(getDependency<Centralize>(*this), 3);
4252  }
4253  };
4254 };
4255 /** \brief Specialization: works in pass 2, %operator+=() supported (merging supported).
4256 */
4257 template <>
4258 class Central<PowerSum<4> >
4259 {
4260  public:
4262 
4263  static std::string name()
4264  {
4265  return "Central<PowerSum<4> >";
4266  // static const std::string n("Central<PowerSum<4> >");
4267  // return n;
4268  }
4269 
4270  template <class U, class BASE>
4271  struct Impl
4272  : public SumBaseImpl<BASE, U>
4273  {
4274  typedef typename SumBaseImpl<BASE, U>::value_type value_type;
4275 
4276  static const unsigned int workInPass = 2;
4277 
4278  void operator+=(Impl const & o)
4279  {
4280  typedef Central<PowerSum<2> > Sum2Tag;
4281  typedef Central<PowerSum<3> > Sum3Tag;
4282 
4283  using namespace vigra::multi_math;
4284  double n1 = getDependency<Count>(*this), n2 = getDependency<Count>(o);
4285  if(n1 == 0.0)
4286  {
4287  this->value_ = o.value_;
4288  }
4289  else if(n2 != 0.0)
4290  {
4291  double n = n1 + n2;
4292  double n1_2 = sq(n1);
4293  double n2_2 = sq(n2);
4294  double n_2 = sq(n);
4295  double weight = n1 * n2 * (n1_2 - n1*n2 + n2_2) / n_2 / n;
4296  value_type delta = getDependency<Mean>(o) - getDependency<Mean>(*this);
4297  this->value_ += o.value_ + weight * pow(delta, 4) +
4298  6.0 / n_2 * sq(delta) * (n1_2 * getDependency<Sum2Tag>(o) + n2_2 * getDependency<Sum2Tag>(*this)) +
4299  4.0 / n * delta * (n1 * getDependency<Sum3Tag>(o) - n2 * getDependency<Sum3Tag>(*this));
4300  }
4301  }
4302 
4303  void update(U const & t)
4304  {
4305  using namespace vigra::multi_math;
4306  this->value_ += pow(getDependency<Centralize>(*this), 4);
4307  }
4308 
4309  void update(U const & t, double weight)
4310  {
4311  using namespace vigra::multi_math;
4312  this->value_ += weight*pow(getDependency<Centralize>(*this), 4);
4313  }
4314  };
4315 };
4316 
4317 /** \brief Basic statistic. Skewness.
4318 
4319  %Skewness =@f$ \frac{ \frac{1}{n}\sum_i (x_i-\hat{x})^3 }{ (\frac{1}{n}\sum_i (x_i-\hat{x})^2)^{3/2} } @f$ .
4320  Works in pass 2, %operator+=() supported (merging supported).
4321 */
4323 {
4324  public:
4326 
4327  static std::string name()
4328  {
4329  return "Skewness";
4330  // static const std::string n("Skewness");
4331  // return n;
4332  }
4333 
4334  template <class U, class BASE>
4335  struct Impl
4336  : public BASE
4337  {
4338  static const unsigned int workInPass = 2;
4339 
4340  typedef typename LookupDependency<Central<PowerSum<3> >, BASE>::value_type value_type;
4341  typedef value_type result_type;
4342 
4343  result_type operator()() const
4344  {
4345  typedef Central<PowerSum<3> > Sum3;
4346  typedef Central<PowerSum<2> > Sum2;
4347 
4348  using namespace multi_math;
4349  return sqrt(getDependency<Count>(*this)) * getDependency<Sum3>(*this) / pow(getDependency<Sum2>(*this), 1.5);
4350  }
4351  };
4352 };
4353 
4354 /** \brief Basic statistic. Unbiased Skewness.
4355 
4356  Works in pass 2, %operator+=() supported (merging supported).
4357 */
4359 {
4360  public:
4362 
4363  static std::string name()
4364  {
4365  return "UnbiasedSkewness";
4366  // static const std::string n("UnbiasedSkewness");
4367  // return n;
4368  }
4369 
4370  template <class U, class BASE>
4371  struct Impl
4372  : public BASE
4373  {
4374  static const unsigned int workInPass = 2;
4375 
4376  typedef typename LookupDependency<Central<PowerSum<3> >, BASE>::value_type value_type;
4377  typedef value_type result_type;
4378 
4379  result_type operator()() const
4380  {
4381  using namespace multi_math;
4382  double n = getDependency<Count>(*this);
4383  return sqrt(n*(n-1.0)) / (n - 2.0) * getDependency<Skewness>(*this);
4384  }
4385  };
4386 };
4387 
4388 /** \brief Basic statistic. Kurtosis.
4389 
4390  %Kurtosis = @f$ \frac{ \frac{1}{n}\sum_i (x_i-\bar{x})^4 }{
4391  (\frac{1}{n} \sum_i(x_i-\bar{x})^2)^2 } - 3 @f$ .
4392  Works in pass 2, %operator+=() supported (merging supported).
4393 */
4395 {
4396  public:
4398 
4399  static std::string name()
4400  {
4401  return "Kurtosis";
4402  // static const std::string n("Kurtosis");
4403  // return n;
4404  }
4405 
4406  template <class U, class BASE>
4407  struct Impl
4408  : public BASE
4409  {
4410  static const unsigned int workInPass = 2;
4411 
4412  typedef typename LookupDependency<Central<PowerSum<4> >, BASE>::value_type value_type;
4413  typedef value_type result_type;
4414 
4415  result_type operator()() const
4416  {
4417  typedef Central<PowerSum<4> > Sum4;
4418  typedef Central<PowerSum<2> > Sum2;
4419 
4420  using namespace multi_math;
4421  return getDependency<Count>(*this) * getDependency<Sum4>(*this) / sq(getDependency<Sum2>(*this)) - 3.0;
4422  }
4423  };
4424 };
4425 
4426 /** \brief Basic statistic. Unbiased Kurtosis.
4427 
4428  Works in pass 2, %operator+=() supported (merging supported).
4429 */
4431 {
4432  public:
4434 
4435  static std::string name()
4436  {
4437  return "UnbiasedKurtosis";
4438  // static const std::string n("UnbiasedKurtosis");
4439  // return n;
4440  }
4441 
4442  template <class U, class BASE>
4443  struct Impl
4444  : public BASE
4445  {
4446  static const unsigned int workInPass = 2;
4447 
4448  typedef typename LookupDependency<Central<PowerSum<4> >, BASE>::value_type value_type;
4449  typedef value_type result_type;
4450 
4451  result_type operator()() const
4452  {
4453  using namespace multi_math;
4454  double n = getDependency<Count>(*this);
4455  return (n-1.0)/((n-2.0)*(n-3.0))*((n+1.0)*getDependency<Kurtosis>(*this) + value_type(6.0));
4456  }
4457  };
4458 };
4459 
4460 namespace acc_detail {
4461 
4462 template <class Scatter, class Sum>
4463 void updateFlatScatterMatrix(Scatter & sc, Sum const & s, double w)
4464 {
4465  int size = s.size();
4466  for(MultiArrayIndex j=0, k=0; j<size; ++j)
4467  for(MultiArrayIndex i=j; i<size; ++i, ++k)
4468  sc[k] += w*s[i]*s[j];
4469 }
4470 
4471 template <class Sum>
4472 void updateFlatScatterMatrix(double & sc, Sum const & s, double w)
4473 {
4474  sc += w*s*s;
4475 }
4476 
4477 template <class Cov, class Scatter>
4478 void flatScatterMatrixToScatterMatrix(Cov & cov, Scatter const & sc)
4479 {
4480  int size = cov.shape(0), k=0;
4481  for(MultiArrayIndex j=0; j<size; ++j)
4482  {
4483  cov(j,j) = sc[k++];
4484  for(MultiArrayIndex i=j+1; i<size; ++i)
4485  {
4486  cov(i,j) = sc[k++];
4487  cov(j,i) = cov(i,j);
4488  }
4489  }
4490 }
4491 
4492 template <class Scatter>
4493 void flatScatterMatrixToScatterMatrix(double & cov, Scatter const & sc)
4494 {
4495  cov = sc;
4496 }
4497 
4498 template <class Cov, class Scatter>
4499 void flatScatterMatrixToCovariance(Cov & cov, Scatter const & sc, double n)
4500 {
4501  int size = cov.shape(0), k=0;
4502  for(MultiArrayIndex j=0; j<size; ++j)
4503  {
4504  cov(j,j) = sc[k++] / n;
4505  for(MultiArrayIndex i=j+1; i<size; ++i)
4506  {
4507  cov(i,j) = sc[k++] / n;
4508  cov(j,i) = cov(i,j);
4509  }
4510  }
4511 }
4512 
4513 template <class Scatter>
4514 void flatScatterMatrixToCovariance(double & cov, Scatter const & sc, double n)
4515 {
4516  cov = sc / n;
4517 }
4518 
4519 } // namespace acc_detail
4520 
4521 // we only store the flattened upper triangular part of the scatter matrix
4522 /** \brief Basic statistic. Flattened uppter-triangular part of scatter matrix.
4523 
4524  Works in pass 1, %operator+=() supported (merging supported).
4525 */
4527 {
4528  public:
4530 
4531  static std::string name()
4532  {
4533  return "FlatScatterMatrix";
4534  // static const std::string n("FlatScatterMatrix");
4535  // return n;
4536  }
4537 
4538  template <class U, class BASE>
4539  struct Impl
4540  : public BASE
4541  {
4542  typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
4543  typedef typename AccumulatorResultTraits<U>::FlatCovarianceType value_type;
4544  typedef value_type const & result_type;
4545 
4546  typedef typename AccumulatorResultTraits<U>::SumType SumType;
4547 
4548  value_type value_;
4549  SumType diff_;
4550 
4551  Impl()
4552  : value_(), // call default constructor explicitly to ensure zero initialization
4553  diff_()
4554  {}
4555 
4556  void reset()
4557  {
4558  value_ = element_type();
4559  }
4560 
4561  template <class Shape>
4562  void reshape(Shape const & s)
4563  {
4564  int size = prod(s);
4565  acc_detail::reshapeImpl(value_, Shape1(size*(size+1)/2));
4566  acc_detail::reshapeImpl(diff_, s);
4567  }
4568 
4569  void operator+=(Impl const & o)
4570  {
4571  double n1 = getDependency<Count>(*this), n2 = getDependency<Count>(o);
4572  if(n1 == 0.0)
4573  {
4574  value_ = o.value_;
4575  }
4576  else if(n2 != 0.0)
4577  {
4578  using namespace vigra::multi_math;
4579  diff_ = getDependency<Mean>(*this) - getDependency<Mean>(o);
4580  acc_detail::updateFlatScatterMatrix(value_, diff_, n1 * n2 / (n1 + n2));
4581  value_ += o.value_;
4582  }
4583  }
4584 
4585  void update(U const & t)
4586  {
4587  compute(t);
4588  }
4589 
4590  void update(U const & t, double weight)
4591  {
4592  compute(t, weight);
4593  }
4594 
4595  result_type operator()() const
4596  {
4597  return value_;
4598  }
4599 
4600  private:
4601  void compute(U const & t, double weight = 1.0)
4602  {
4603  double n = getDependency<Count>(*this);
4604  if(n > weight)
4605  {
4606  using namespace vigra::multi_math;
4607  diff_ = getDependency<Mean>(*this) - t;
4608  acc_detail::updateFlatScatterMatrix(value_, diff_, n * weight / (n - weight));
4609  }
4610  }
4611  };
4612 };
4613 
4614 // Covariance
4615 template <>
4617 {
4618  public:
4619  typedef Select<FlatScatterMatrix, Count> Dependencies;
4620 
4621  static std::string name()
4622  {
4623  return "DivideByCount<FlatScatterMatrix>";
4624  // static const std::string n("DivideByCount<FlatScatterMatrix>");
4625  // return n;
4626  }
4627 
4628  template <class U, class BASE>
4629  struct Impl
4630  : public CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U>
4631  {
4632  typedef CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U> BaseType;
4633  typedef typename BaseType::result_type result_type;
4634 
4635  template <class Shape>
4636  void reshape(Shape const & s)
4637  {
4638  int size = prod(s);
4639  acc_detail::reshapeImpl(this->value_, Shape2(size,size));
4640  }
4641 
4642  result_type operator()() const
4643  {
4644  if(this->isDirty())
4645  {
4646  acc_detail::flatScatterMatrixToCovariance(this->value_, getDependency<FlatScatterMatrix>(*this), getDependency<Count>(*this));
4647  this->setClean();
4648  }
4649  return this->value_;
4650  }
4651  };
4652 };
4653 
4654 // UnbiasedCovariance
4655 template <>
4656 class DivideUnbiased<FlatScatterMatrix>
4657 {
4658  public:
4659  typedef Select<FlatScatterMatrix, Count> Dependencies;
4660 
4661  static std::string name()
4662  {
4663  return "DivideUnbiased<FlatScatterMatrix>";
4664  // static const std::string n("DivideUnbiased<FlatScatterMatrix>");
4665  // return n;
4666  }
4667 
4668  template <class U, class BASE>
4669  struct Impl
4670  : public CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U>
4671  {
4672  typedef CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U> BaseType;
4673  typedef typename BaseType::result_type result_type;
4674 
4675  template <class Shape>
4676  void reshape(Shape const & s)
4677  {
4678  int size = prod(s);
4679  acc_detail::reshapeImpl(this->value_, Shape2(size,size));
4680  }
4681 
4682  result_type operator()() const
4683  {
4684  if(this->isDirty())
4685  {
4686  acc_detail::flatScatterMatrixToCovariance(this->value_, getDependency<FlatScatterMatrix>(*this), getDependency<Count>(*this) - 1.0);
4687  this->setClean();
4688  }
4689  return this->value_;
4690  }
4691  };
4692 };
4693 
4694 /** Basic statistic. ScatterMatrixEigensystem (?)
4695 */
4697 {
4698  public:
4700 
4701  static std::string name()
4702  {
4703  return "ScatterMatrixEigensystem";
4704  // static const std::string n("ScatterMatrixEigensystem");
4705  // return n;
4706  }
4707 
4708  template <class U, class BASE>
4709  struct Impl
4710  : public BASE
4711  {
4712  typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
4713  typedef typename AccumulatorResultTraits<U>::SumType EigenvalueType;
4714  typedef typename AccumulatorResultTraits<U>::CovarianceType EigenvectorType;
4715  typedef std::pair<EigenvalueType, EigenvectorType> value_type;
4716  typedef value_type const & result_type;
4717 
4718  mutable value_type value_;
4719 
4720  Impl()
4721  : value_()
4722  {}
4723 
4724  void operator+=(Impl const & o)
4725  {
4726  if(!acc_detail::hasDataImpl(value_.second))
4727  {
4728  acc_detail::copyShapeImpl(o.value_.first, value_.first);
4729  acc_detail::copyShapeImpl(o.value_.second, value_.second);
4730  }
4731  this->setDirty();
4732  }
4733 
4734  void update(U const &)
4735  {
4736  this->setDirty();
4737  }
4738 
4739  void update(U const &, double)
4740  {
4741  this->setDirty();
4742  }
4743 
4744  void reset()
4745  {
4746  value_.first = element_type();
4747  value_.second = element_type();
4748  this->setClean();
4749  }
4750 
4751  template <class Shape>
4752  void reshape(Shape const & s)
4753  {
4754  int size = prod(s);
4755  acc_detail::reshapeImpl(value_.first, Shape1(size));
4756  acc_detail::reshapeImpl(value_.second, Shape2(size,size));
4757  }
4758 
4759  result_type operator()() const
4760  {
4761  if(this->isDirty())
4762  {
4763  compute(getDependency<FlatScatterMatrix>(*this), value_.first, value_.second);
4764  this->setClean();
4765  }
4766  return value_;
4767  }
4768 
4769  private:
4770  template <class Flat, class EW, class EV>
4771  static void compute(Flat const & flatScatter, EW & ew, EV & ev)
4772  {
4773  EigenvectorType scatter(ev.shape());
4774  acc_detail::flatScatterMatrixToScatterMatrix(scatter, flatScatter);
4775  // create a view because EW could be a TinyVector
4776  MultiArrayView<2, element_type> ewview(Shape2(ev.shape(0), 1), &ew[0]);
4777  symmetricEigensystem(scatter, ewview, ev);
4778  }
4779 
4780  static void compute(double v, double & ew, double & ev)
4781  {
4782  ew = v;
4783  ev = 1.0;
4784  }
4785  };
4786 };
4787 
4788 // CovarianceEigensystem
4789 template <>
4791 {
4792  public:
4793  typedef Select<ScatterMatrixEigensystem, Count> Dependencies;
4794 
4795  static std::string name()
4796  {
4797  return "DivideByCount<ScatterMatrixEigensystem>";
4798  // static const std::string n("DivideByCount<ScatterMatrixEigensystem>");
4799  // return n;
4800  }
4801 
4802  template <class U, class BASE>
4803  struct Impl
4804  : public BASE
4805  {
4806  typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>::type SMImpl;
4807  typedef typename SMImpl::element_type element_type;
4808  typedef typename SMImpl::EigenvalueType EigenvalueType;
4809  typedef typename SMImpl::EigenvectorType EigenvectorType;
4810  typedef std::pair<EigenvalueType, EigenvectorType const &> value_type;
4811  typedef value_type const & result_type;
4812 
4813  mutable value_type value_;
4814 
4815  Impl()
4816  : value_(EigenvalueType(), BASE::template call_getDependency<ScatterMatrixEigensystem>().second)
4817  {}
4818 
4819  void operator+=(Impl const &)
4820  {
4821  this->setDirty();
4822  }
4823 
4824  void update(U const &)
4825  {
4826  this->setDirty();
4827  }
4828 
4829  void update(U const &, double)
4830  {
4831  this->setDirty();
4832  }
4833 
4834  void reset()
4835  {
4836  value_.first = element_type();
4837  this->setClean();
4838  }
4839 
4840  template <class Shape>
4841  void reshape(Shape const & s)
4842  {
4843  int size = prod(s);
4844  acc_detail::reshapeImpl(value_.first, Shape2(size,1));
4845  }
4846 
4847  result_type operator()() const
4848  {
4849  if(this->isDirty())
4850  {
4851  value_.first = getDependency<ScatterMatrixEigensystem>(*this).first / getDependency<Count>(*this);
4852  this->setClean();
4853  }
4854  return value_;
4855  }
4856  };
4857 };
4858 
4859 // alternative implementation of CovarianceEigensystem - solve eigensystem directly
4860 //
4861 // template <>
4862 // class DivideByCount<ScatterMatrixEigensystem>
4863 // {
4864  // public:
4865  // typedef Select<Covariance> Dependencies;
4866 
4867  // template <class U, class BASE>
4868  // struct Impl
4869  // : public BASE
4870  // {
4871  // typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
4872  // typedef typename AccumulatorResultTraits<U>::SumType EigenvalueType;
4873  // typedef typename AccumulatorResultTraits<U>::CovarianceType EigenvectorType;
4874  // typedef std::pair<EigenvalueType, EigenvectorType> value_type;
4875  // typedef value_type const & result_type;
4876 
4877  // mutable value_type value_;
4878 
4879  // Impl()
4880  // : value_()
4881  // {}
4882 
4883  // void operator+=(Impl const &)
4884  // {
4885  // this->setDirty();
4886  // }
4887 
4888  // void update(U const &)
4889  // {
4890  // this->setDirty();
4891  // }
4892 
4893  // void update(U const &, double)
4894  // {
4895  // this->setDirty();
4896  // }
4897 
4898  // void reset()
4899  // {
4900  // value_.first = element_type();
4901  // value_.second = element_type();
4902  // this->setClean();
4903  // }
4904 
4905  // template <class Shape>
4906  // void reshape(Shape const & s)
4907  // {
4908  // int size = prod(s);
4909  // acc_detail::reshapeImpl(value_.first, Shape2(size,1));
4910  // acc_detail::reshapeImpl(value_.second, Shape2(size,size));
4911  // }
4912 
4913  // result_type operator()() const
4914  // {
4915  // if(this->isDirty())
4916  // {
4917  // compute(getDependency<Covariance>(*this), value_.first, value_.second);
4918  // this->setClean();
4919  // }
4920  // return value_;
4921  // }
4922 
4923  // private:
4924  // template <class Cov, class EW, class EV>
4925  // static void compute(Cov const & cov, EW & ew, EV & ev)
4926  // {
4927  // // create a view because EW could be a TinyVector
4928  // MultiArrayView<2, element_type> ewview(Shape2(cov.shape(0), 1), &ew[0]);
4929  // symmetricEigensystem(cov, ewview, ev);
4930  // }
4931 
4932  // static void compute(double cov, double & ew, double & ev)
4933  // {
4934  // ew = cov;
4935  // ev = 1.0;
4936  // }
4937  // };
4938 // };
4939 
4940 // covariance eigenvalues
4941 /** \brief Specialization (covariance eigenvalues): works in pass 1, %operator+=() supported (merging).
4942 */
4943 template <>
4945 {
4946  public:
4948 
4949  static std::string name()
4950  {
4951  return "Principal<PowerSum<2> >";
4952  // static const std::string n("Principal<PowerSum<2> >");
4953  // return n;
4954  }
4955 
4956  template <class U, class BASE>
4957  struct Impl
4958  : public BASE
4959  {
4960  typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>::type::EigenvalueType value_type;
4961  typedef value_type const & result_type;
4962 
4963  result_type operator()() const
4964  {
4965  return getDependency<ScatterMatrixEigensystem>(*this).first;
4966  }
4967  };
4968 };
4969 
4970 
4971 // Principal<CoordinateSystem> == covariance eigenvectors
4972 /** \brief Specialization (covariance eigenvectors): works in pass 1, %operator+=() supported (merging).
4973 */
4974 template <>
4976 {
4977  public:
4979 
4980  static std::string name()
4981  {
4982  return "Principal<CoordinateSystem>";
4983  // static const std::string n("Principal<CoordinateSystem>");
4984  // return n;
4985  }
4986 
4987  template <class U, class BASE>
4988  struct Impl
4989  : public BASE
4990  {
4991  typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>::type::EigenvectorType value_type;
4992  typedef value_type const & result_type;
4993 
4994  result_type operator()() const
4995  {
4996  return getDependency<ScatterMatrixEigensystem>(*this).second;
4997  }
4998  };
4999 };
5000 
5001 /** \brief Basic statistic. %Minimum value.
5002 
5003  Works in pass 1, %operator+=() supported (merging supported).
5004 */
5005 class Minimum
5006 {
5007  public:
5008  typedef Select<> Dependencies;
5009 
5010  static std::string name()
5011  {
5012  return "Minimum";
5013  // static const std::string n("Minimum");
5014  // return n;
5015  }
5016 
5017  template <class U, class BASE>
5018  struct Impl
5019  : public BASE
5020  {
5021  typedef typename AccumulatorResultTraits<U>::element_type element_type;
5022  typedef typename AccumulatorResultTraits<U>::MinmaxType value_type;
5023  typedef value_type const & result_type;
5024 
5025  value_type value_;
5026 
5027  Impl()
5028  {
5029  value_ = NumericTraits<element_type>::max();
5030  }
5031 
5032  void reset()
5033  {
5034  value_ = NumericTraits<element_type>::max();
5035  }
5036 
5037  template <class Shape>
5038  void reshape(Shape const & s)
5039  {
5040  acc_detail::reshapeImpl(value_, s, NumericTraits<element_type>::max());
5041  }
5042 
5043  void operator+=(Impl const & o)
5044  {
5045  updateImpl(o.value_); // necessary because std::min causes ambiguous overload
5046  }
5047 
5048  void update(U const & t)
5049  {
5050  updateImpl(t);
5051  }
5052 
5053  void update(U const & t, double)
5054  {
5055  updateImpl(t);
5056  }
5057 
5058  result_type operator()() const
5059  {
5060  return value_;
5061  }
5062 
5063  private:
5064  template <class T>
5065  void updateImpl(T const & o)
5066  {
5067  using namespace multi_math;
5068  value_ = min(value_, o);
5069  }
5070 
5071  template <class T, class Alloc>
5072  void updateImpl(MultiArray<1, T, Alloc> const & o)
5073  {
5074  value_ = multi_math::min(value_, o);
5075  }
5076  };
5077 };
5078 
5079 /** \brief Basic statistic. %Maximum value.
5080 
5081  Works in pass 1, %operator+=() supported (merging supported).
5082 */
5083 class Maximum
5084 {
5085  public:
5086  typedef Select<> Dependencies;
5087 
5088  static std::string name()
5089  {
5090  return "Maximum";
5091  // static const std::string n("Maximum");
5092  // return n;
5093  }
5094 
5095  template <class U, class BASE>
5096  struct Impl
5097  : public BASE
5098  {
5099  typedef typename AccumulatorResultTraits<U>::element_type element_type;
5100  typedef typename AccumulatorResultTraits<U>::MinmaxType value_type;
5101  typedef value_type const & result_type;
5102 
5103  value_type value_;
5104 
5105  Impl()
5106  {
5107  value_ = NumericTraits<element_type>::min();
5108  }
5109 
5110  void reset()
5111  {
5112  value_ = NumericTraits<element_type>::min();
5113  }
5114 
5115  template <class Shape>
5116  void reshape(Shape const & s)
5117  {
5118  acc_detail::reshapeImpl(value_, s, NumericTraits<element_type>::min());
5119  }
5120 
5121  void operator+=(Impl const & o)
5122  {
5123  updateImpl(o.value_); // necessary because std::max causes ambiguous overload
5124  }
5125 
5126  void update(U const & t)
5127  {
5128  updateImpl(t);
5129  }
5130 
5131  void update(U const & t, double)
5132  {
5133  updateImpl(t);
5134  }
5135 
5136  result_type operator()() const
5137  {
5138  return value_;
5139  }
5140 
5141  private:
5142  template <class T>
5143  void updateImpl(T const & o)
5144  {
5145  using namespace multi_math;
5146  value_ = max(value_, o);
5147  }
5148 
5149  template <class T, class Alloc>
5150  void updateImpl(MultiArray<1, T, Alloc> const & o)
5151  {
5152  value_ = multi_math::max(value_, o);
5153  }
5154  };
5155 };
5156 
5157 /** \brief Basic statistic. First data value seen of the object.
5158 
5159  Usually used as <tt>Coord<FirstSeen></tt> (alias <tt>RegionAnchor</tt>)
5160  which provides a well-defined anchor point for the region.
5161 */
5163 {
5164  public:
5165  typedef Select<Count> Dependencies;
5166 
5167  static std::string name()
5168  {
5169  return "FirstSeen";
5170  // static const std::string n("FirstSeen");
5171  // return n;
5172  }
5173 
5174  template <class U, class BASE>
5175  struct Impl
5176  : public BASE
5177  {
5178  typedef typename AccumulatorResultTraits<U>::element_type element_type;
5179  typedef typename AccumulatorResultTraits<U>::MinmaxType value_type;
5180  typedef value_type const & result_type;
5181 
5182  value_type value_;
5183 
5184  Impl()
5185  : value_()
5186  {}
5187 
5188  void reset()
5189  {
5190  value_ = element_type();
5191  }
5192 
5193  template <class Shape>
5194  void reshape(Shape const & s)
5195  {
5196  acc_detail::reshapeImpl(value_, s);
5197  }
5198 
5199  void operator+=(Impl const & o)
5200  {
5201  // FIXME: only works for Coord<FirstSeen>
5202  if(reverse(o.value_) < reverse(value_))
5203  value_ = o.value_;
5204  }
5205 
5206  void update(U const & t)
5207  {
5208  if(getDependency<Count>(*this) == 1)
5209  value_ = t;
5210  }
5211 
5212  void update(U const & t, double weight)
5213  {
5214  update(t);
5215  }
5216 
5217  result_type operator()() const
5218  {
5219  return value_;
5220  }
5221  };
5222 };
5223 
5224 /** \brief Return both the minimum and maximum in <tt>std::pair</tt>.
5225 
5226  Usually used as <tt>Coord<Range></tt> (alias <tt>BoundingBox</tt>).
5227  Note that <tt>Range</tt> returns a closed interval, i.e. the upper
5228  limit is part of the range.
5229 */
5230 class Range
5231 {
5232  public:
5234 
5235  static std::string name()
5236  {
5237  return "Range";
5238  // static const std::string n("Range");
5239  // return n;
5240  }
5241 
5242  template <class U, class BASE>
5243  struct Impl
5244  : public BASE
5245  {
5246  typedef typename AccumulatorResultTraits<U>::MinmaxType minmax_type;
5247  typedef std::pair<minmax_type, minmax_type> value_type;
5248  typedef value_type result_type;
5249 
5250  result_type operator()() const
5251  {
5252  return value_type(getDependency<Minimum>(*this), getDependency<Maximum>(*this));
5253  }
5254  };
5255 };
5256 
5257 /** \brief Basic statistic. Data value where weight assumes its minimal value.
5258 
5259  Weights must be given. Coord<ArgMinWeight> gives coordinate where weight assumes its minimal value. Works in pass 1, %operator+=() supported (merging supported).
5260 */
5262 {
5263  public:
5264  typedef Select<> Dependencies;
5265 
5266  static std::string name()
5267  {
5268  return "ArgMinWeight";
5269  // static const std::string n("ArgMinWeight");
5270  // return n;
5271  }
5272 
5273  template <class U, class BASE>
5274  struct Impl
5275  : public BASE
5276  {
5277  typedef typename AccumulatorResultTraits<U>::element_type element_type;
5278  typedef typename AccumulatorResultTraits<U>::MinmaxType value_type;
5279  typedef value_type const & result_type;
5280 
5281  double min_weight_;
5282  value_type value_;
5283 
5284  Impl()
5285  : min_weight_(NumericTraits<double>::max()),
5286  value_()
5287  {}
5288 
5289  void reset()
5290  {
5291  min_weight_ = NumericTraits<double>::max();
5292  value_ = element_type();
5293  }
5294 
5295  template <class Shape>
5296  void reshape(Shape const & s)
5297  {
5298  acc_detail::reshapeImpl(value_, s);
5299  }
5300 
5301  void operator+=(Impl const & o)
5302  {
5303  using namespace multi_math;
5304  if(o.min_weight_ < min_weight_)
5305  {
5306  min_weight_ = o.min_weight_;
5307  value_ = o.value_;
5308  }
5309  }
5310 
5311  void update(U const & t)
5312  {
5313  vigra_precondition(false, "ArgMinWeight::update() needs weights.");
5314  }
5315 
5316  void update(U const & t, double weight)
5317  {
5318  if(weight < min_weight_)
5319  {
5320  min_weight_ = weight;
5321  value_ = t;
5322  }
5323  }
5324 
5325  result_type operator()() const
5326  {
5327  return value_;
5328  }
5329  };
5330 };
5331 
5332 /** \brief Basic statistic. Data where weight assumes its maximal value.
5333 
5334  Weights must be given. Coord<ArgMinWeight> gives coordinate where weight assumes its maximal value. Works in pass 1, %operator+=() supported (merging supported).
5335 */
5337 {
5338  public:
5339  typedef Select<> Dependencies;
5340 
5341  static std::string name()
5342  {
5343  return "ArgMaxWeight";
5344  // static const std::string n("ArgMaxWeight");
5345  // return n;
5346  }
5347 
5348  template <class U, class BASE>
5349  struct Impl
5350  : public BASE
5351  {
5352  typedef typename AccumulatorResultTraits<U>::element_type element_type;
5353  typedef typename AccumulatorResultTraits<U>::MinmaxType value_type;
5354  typedef value_type const & result_type;
5355 
5356  double max_weight_;
5357  value_type value_;
5358 
5359  Impl()
5360  : max_weight_(NumericTraits<double>::min()),
5361  value_()
5362  {}
5363 
5364  void reset()
5365  {
5366  max_weight_ = NumericTraits<double>::min();
5367  value_ = element_type();
5368  }
5369 
5370  template <class Shape>
5371  void reshape(Shape const & s)
5372  {
5373  acc_detail::reshapeImpl(value_, s);
5374  }
5375 
5376  void operator+=(Impl const & o)
5377  {
5378  using namespace multi_math;
5379  if(o.max_weight_ > max_weight_)
5380  {
5381  max_weight_ = o.max_weight_;
5382  value_ = o.value_;
5383  }
5384  }
5385 
5386  void update(U const & t)
5387  {
5388  vigra_precondition(false, "ArgMaxWeight::update() needs weights.");
5389  }
5390 
5391  void update(U const & t, double weight)
5392  {
5393  if(weight > max_weight_)
5394  {
5395  max_weight_ = weight;
5396  value_ = t;
5397  }
5398  }
5399 
5400  result_type operator()() const
5401  {
5402  return value_;
5403  }
5404  };
5405 };
5406 
5407 
5408 template <class BASE, int BinCount>
5409 class HistogramBase
5410 : public BASE
5411 {
5412  public:
5413 
5414  typedef double element_type;
5415  typedef TinyVector<double, BinCount> value_type;
5416  typedef value_type const & result_type;
5417 
5418  value_type value_;
5419  double left_outliers, right_outliers;
5420 
5421  HistogramBase()
5422  : value_(),
5423  left_outliers(),
5424  right_outliers()
5425  {}
5426 
5427  void reset()
5428  {
5429  value_ = element_type();
5430  left_outliers = 0.0;
5431  right_outliers = 0.0;
5432  }
5433 
5434  void operator+=(HistogramBase const & o)
5435  {
5436  value_ += o.value_;
5437  left_outliers += o.left_outliers;
5438  right_outliers += o.right_outliers;
5439  }
5440 
5441  result_type operator()() const
5442  {
5443  return value_;
5444  }
5445 };
5446 
5447 template <class BASE>
5448 class HistogramBase<BASE, 0>
5449 : public BASE
5450 {
5451  public:
5452 
5453  typedef double element_type;
5454  typedef MultiArray<1, double> value_type;
5455  typedef value_type const & result_type;
5456 
5457  value_type value_;
5458  double left_outliers, right_outliers;
5459 
5460  HistogramBase()
5461  : value_(),
5462  left_outliers(),
5463  right_outliers()
5464  {}
5465 
5466  void reset()
5467  {
5468  value_ = element_type();
5469  left_outliers = 0.0;
5470  right_outliers = 0.0;
5471  }
5472 
5473  void operator+=(HistogramBase const & o)
5474  {
5475  if(value_.size() == 0)
5476  {
5477  value_ = o.value_;
5478  }
5479  else if(o.value_.size() > 0)
5480  {
5481  vigra_precondition(value_.size() == o.value_.size(),
5482  "HistogramBase::operator+=(): bin counts must be equal.");
5483  value_ += o.value_;
5484  }
5485  left_outliers += o.left_outliers;
5486  right_outliers += o.right_outliers;
5487  }
5488 
5489  void setBinCount(int binCount)
5490  {
5491  vigra_precondition(binCount > 0,
5492  "HistogramBase:.setBinCount(): binCount > 0 required.");
5493  value_type(Shape1(binCount)).swap(value_);
5494  }
5495 
5496  result_type operator()() const
5497  {
5498  return value_;
5499  }
5500 };
5501 
5502 template <class BASE, int BinCount, class U=typename BASE::input_type>
5503 class RangeHistogramBase
5504 : public HistogramBase<BASE, BinCount>
5505 {
5506  public:
5507  double scale_, offset_, inverse_scale_;
5508 
5509  RangeHistogramBase()
5510  : scale_(),
5511  offset_(),
5512  inverse_scale_()
5513  {}
5514 
5515  void reset()
5516  {
5517  scale_ = 0.0;
5518  offset_ = 0.0;
5519  inverse_scale_ = 0.0;
5520  HistogramBase<BASE, BinCount>::reset();
5521  }
5522 
5523  void operator+=(RangeHistogramBase const & o)
5524  {
5525  vigra_precondition(scale_ == 0.0 || o.scale_ == 0.0 || (scale_ == o.scale_ && offset_ == o.offset_),
5526  "RangeHistogramBase::operator+=(): cannot merge histograms with different data mapping.");
5527 
5529  if(scale_ == 0.0)
5530  {
5531  scale_ = o.scale_;
5532  offset_ = o.offset_;
5533  inverse_scale_ = o.inverse_scale_;
5534  }
5535  }
5536 
5537  void update(U const & t)
5538  {
5539  update(t, 1.0);
5540  }
5541 
5542  void update(U const & t, double weight)
5543  {
5544  double m = mapItem(t);
5545  int index = (m == (double)this->value_.size())
5546  ? (int)m - 1
5547  : (int)m;
5548  if(index < 0)
5549  this->left_outliers += weight;
5550  else if(index >= (int)this->value_.size())
5551  this->right_outliers += weight;
5552  else
5553  this->value_[index] += weight;
5554  }
5555 
5556  void setMinMax(double mi, double ma)
5557  {
5558  vigra_precondition(this->value_.size() > 0,
5559  "RangeHistogramBase::setMinMax(...): setBinCount(...) has not been called.");
5560  vigra_precondition(mi <= ma,
5561  "RangeHistogramBase::setMinMax(...): min <= max required.");
5562  if(mi == ma)
5563  ma += this->value_.size() * NumericTraits<double>::epsilon();
5564  offset_ = mi;
5565  scale_ = (double)this->value_.size() / (ma - mi);
5566  inverse_scale_ = 1.0 / scale_;
5567  }
5568 
5569  double mapItem(double t) const
5570  {
5571  return scale_ * (t - offset_);
5572  }
5573 
5574  double mapItemInverse(double t) const
5575  {
5576  return inverse_scale_ * t + offset_;
5577  }
5578 
5579  template <class ArrayLike>
5580  void computeStandardQuantiles(double minimum, double maximum, double count,
5581  ArrayLike const & desiredQuantiles, ArrayLike & res) const
5582  {
5583  if(count == 0.0) {
5584  return;
5585  }
5586 
5587  ArrayVector<double> keypoints, cumhist;
5588  double mappedMinimum = mapItem(minimum);
5589  double mappedMaximum = mapItem(maximum);
5590 
5591  keypoints.push_back(mappedMinimum);
5592  cumhist.push_back(0.0);
5593 
5594  if(this->left_outliers > 0.0)
5595  {
5596  keypoints.push_back(0.0);
5597  cumhist.push_back(this->left_outliers);
5598  }
5599 
5600  int size = (int)this->value_.size();
5601  double cumulative = this->left_outliers;
5602  for(int k=0; k<size; ++k)
5603  {
5604  if(this->value_[k] > 0.0)
5605  {
5606  if(keypoints.back() <= k)
5607  {
5608  keypoints.push_back(k);
5609  cumhist.push_back(cumulative);
5610  }
5611  cumulative += this->value_[k];
5612  keypoints.push_back(k+1);
5613  cumhist.push_back(cumulative);
5614  }
5615  }
5616 
5617  if(this->right_outliers > 0.0)
5618  {
5619  if(keypoints.back() != size)
5620  {
5621  keypoints.push_back(size);
5622  cumhist.push_back(cumulative);
5623  }
5624  keypoints.push_back(mappedMaximum);
5625  cumhist.push_back(count);
5626  }
5627  else
5628  {
5629  keypoints.back() = mappedMaximum;
5630  cumhist.back() = count;
5631  }
5632 
5633  int quantile = 0, end = (int)desiredQuantiles.size();
5634 
5635  if(desiredQuantiles[0] == 0.0)
5636  {
5637  res[0] = minimum;
5638  ++quantile;
5639  }
5640  if(desiredQuantiles[end-1] == 1.0)
5641  {
5642  res[end-1] = maximum;
5643  --end;
5644  }
5645 
5646  int point = 0;
5647  double qcount = count * desiredQuantiles[quantile];
5648  while(quantile < end)
5649  {
5650  if(cumhist[point] < qcount && cumhist[point+1] >= qcount)
5651  {
5652  double t = (qcount - cumhist[point]) / (cumhist[point+1] - cumhist[point]) * (keypoints[point+1] - keypoints[point]);
5653  res[quantile] = mapItemInverse(t + keypoints[point]);
5654  ++quantile;
5655  qcount = count * desiredQuantiles[quantile];
5656  }
5657  else
5658  {
5659  ++point;
5660  }
5661  }
5662  }
5663 };
5664 
5665 /** \brief Histogram where data values are equal to bin indices.
5666 
5667  - If BinCount != 0, the return type of the accumulator is TinyVector<double, BinCount> .
5668  - If BinCount == 0, the return type of the accumulator is MultiArray<1, double> . BinCount can be set by calling getAccumulator<IntegerHistogram<0> >(acc_chain).setBinCount(bincount).
5669  - Outliers can be accessed via getAccumulator<IntegerHistogram<Bincount>>(a).left_outliers and getAccumulator<...>(acc_chain).right_outliers.
5670  - Note that histogram options (for all histograms in the accumulator chain) can also be set by passing an instance of HistogramOptions to the accumulator chain via acc_chain.setHistogramOptions().
5671  Works in pass 1, %operator+=() supported (merging supported).
5672 */
5673 template <int BinCount>
5674 class IntegerHistogram
5675 {
5676  public:
5677 
5678  typedef Select<> Dependencies;
5679 
5680  static std::string name()
5681  {
5682  return std::string("IntegerHistogram<") + asString(BinCount) + ">";
5683  // static const std::string n = std::string("IntegerHistogram<") + asString(BinCount) + ">";
5684  // return n;
5685  }
5686 
5687  template <class U, class BASE>
5688  struct Impl
5689  : public HistogramBase<BASE, BinCount>
5690  {
5691  void update(int index)
5692  {
5693  if(index < 0)
5694  ++this->left_outliers;
5695  else if(index >= (int)this->value_.size())
5696  ++this->right_outliers;
5697  else
5698  ++this->value_[index];
5699  }
5700 
5701  void update(int index, double weight)
5702  {
5703  // cannot compute quantile from weighted integer histograms,
5704  // so force people to use UserRangeHistogram or AutoRangeHistogram
5705  vigra_precondition(false, "IntegerHistogram::update(): weighted histograms not supported, use another histogram type.");
5706  }
5707 
5708  template <class ArrayLike>
5709  void computeStandardQuantiles(double minimum, double maximum, double count,
5710  ArrayLike const & desiredQuantiles, ArrayLike & res) const
5711  {
5712  int quantile = 0, end = (int)desiredQuantiles.size();
5713 
5714  if(desiredQuantiles[0] == 0.0)
5715  {
5716  res[0] = minimum;
5717  ++quantile;
5718  }
5719  if(desiredQuantiles[end-1] == 1.0)
5720  {
5721  res[end-1] = maximum;
5722  --end;
5723  }
5724 
5725  count -= 1.0;
5726  int currentBin = 0, size = (int)this->value_.size();
5727  double cumulative1 = this->left_outliers,
5728  cumulative2 = this->value_[currentBin] + cumulative1;
5729 
5730  // add a to the quantiles to account for the fact that counting
5731  // corresponds to 1-based indexing (one element == index 1)
5732  double qcount = desiredQuantiles[quantile]*count + 1.0;
5733 
5734  while(quantile < end)
5735  {
5736  if(cumulative2 == qcount)
5737  {
5738  res[quantile] = currentBin;
5739  ++quantile;
5740  qcount = desiredQuantiles[quantile]*count + 1.0;
5741  }
5742  else if(cumulative2 > qcount)
5743  {
5744  if(cumulative1 > qcount) // in left_outlier bin
5745  {
5746  res[quantile] = minimum;
5747  }
5748  if(cumulative1 + 1.0 > qcount) // between bins
5749  {
5750  res[quantile] = currentBin - 1 + qcount - std::floor(qcount);
5751  }
5752  else // standard case
5753  {
5754  res[quantile] = currentBin;
5755  }
5756  ++quantile;
5757  qcount = desiredQuantiles[quantile]*count + 1.0;
5758  }
5759  else if(currentBin == size-1) // in right outlier bin
5760  {
5761  res[quantile] = maximum;
5762  ++quantile;
5763  qcount = desiredQuantiles[quantile]*count + 1.0;
5764  }
5765  else
5766  {
5767  ++currentBin;
5768  cumulative1 = cumulative2;
5769  cumulative2 += this->value_[currentBin];
5770  }
5771  }
5772  }
5773  };
5774 };
5775 
5776 /** \brief Histogram where user provides bounds for linear range mapping from values to indices.
5777 
5778  - If BinCount != 0, the return type of the accumulator is TinyVector<double, BinCount> .
5779  - If BinCount == 0, the return type of the accumulator is MultiArray<1, double> . BinCount can be set by calling getAccumulator<UserRangeHistogram<0> >(acc_chain).setBinCount(bincount).
5780  - Bounds for the mapping (min/max) must be set before seeing data by calling getAccumulator<UserRangeHistogram<BinCount> >.setMinMax(min, max).
5781  - Options can also be passed to the accumulator chain via an instance of HistogramOptions .
5782  - Works in pass 1, %operator+=() is supported (merging) if both histograms have the same data mapping.
5783  - Outliers can be accessed via getAccumulator<...>(a).left_outliers and getAccumulator<...>(a).right_outliers.
5784  - Note that histogram options (for all histograms in the accumulator chain) can also be set by passing an instance of HistogramOptions to the accumulator chain via acc_chain.setHistogramOptions().
5785 */
5786 template <int BinCount>
5787 class UserRangeHistogram
5788 {
5789  public:
5790 
5791  typedef Select<> Dependencies;
5792 
5793  static std::string name()
5794  {
5795  return std::string("UserRangeHistogram<") + asString(BinCount) + ">";
5796  // static const std::string n = std::string("UserRangeHistogram<") + asString(BinCount) + ">";
5797  // return n;
5798  }
5799 
5800  template <class U, class BASE>
5801  struct Impl
5802  : public RangeHistogramBase<BASE, BinCount, U>
5803  {
5804  void update(U const & t)
5805  {
5806  update(t, 1.0);
5807  }
5808 
5809  void update(U const & t, double weight)
5810  {
5811  vigra_precondition(this->scale_ != 0.0,
5812  "UserRangeHistogram::update(): setMinMax(...) has not been called.");
5813 
5814  RangeHistogramBase<BASE, BinCount, U>::update(t, weight);
5815  }
5816  };
5817 };
5818 
5819 /** \brief Histogram where range mapping bounds are defined by minimum and maximum of data.
5820 
5821  - If BinCount != 0, the return type of the accumulator is TinyVector<double, BinCount> .
5822  - If BinCount == 0, the return type of the accumulator is MultiArray<1, double> . BinCount can be set by calling getAccumulator<AutoRangeHistogram>(acc_chain).setBinCount(bincount).
5823  - Becomes a UserRangeHistogram if min/max is set.
5824  - Works in pass 2, %operator+=() is supported (merging) if both histograms have the same data mapping.
5825  - Outliers can be accessed via getAccumulator<...>(acc_chain).left_outliers and getAccumulator<...>(acc_chain).right_outliers .
5826  - Note that histogram options (for all histograms in the accumulator chain) can also be set by passing an instance of HistogramOptions to the accumulator chain via acc_chain.setHistogramOptions().
5827 */
5828 template <int BinCount>
5829 class AutoRangeHistogram
5830 {
5831  public:
5832 
5833  typedef Select<Minimum, Maximum> Dependencies;
5834 
5835  static std::string name()
5836  {
5837  return std::string("AutoRangeHistogram<") + asString(BinCount) + ">";
5838  // static const std::string n = std::string("AutoRangeHistogram<") + asString(BinCount) + ">";
5839  // return n;
5840  }
5841 
5842  template <class U, class BASE>
5843  struct Impl
5844  : public RangeHistogramBase<BASE, BinCount, U>
5845  {
5846  static const unsigned int workInPass = LookupDependency<Minimum, BASE>::type::workInPass + 1;
5847 
5848  void update(U const & t)
5849  {
5850  update(t, 1.0);
5851  }
5852 
5853  void update(U const & t, double weight)
5854  {
5855  if(this->scale_ == 0.0)
5856  this->setMinMax(getDependency<Minimum>(*this), getDependency<Maximum>(*this));
5857 
5858  RangeHistogramBase<BASE, BinCount, U>::update(t, weight);
5859  }
5860  };
5861 };
5862 
5863 /** \brief Like AutoRangeHistogram, but use global min/max rather than region min/max.
5864 
5865  - If BinCount != 0, the return type of the accumulator is TinyVector<double, BinCount> .
5866  - If BinCount == 0, the return type of the accumulator is MultiArray<1, double> . BinCount can be set by calling getAccumulator<GlobalRangeHistogram<0>>(acc_chain).setBinCount(bincount).
5867  - Becomes a UserRangeHistogram if min/max is set.
5868  - Works in pass 2, %operator+=() is supported (merging) if both histograms have the same data mapping.
5869  - Outliers can be accessed via getAccumulator<GlobalRangeHistogram<Bincount>>(acc_chain).left_outliers and getAccumulator<...>(acc_chain).right_outliers .
5870  - Histogram options (for all histograms in the accumulator chain) can also be set by passing an instance of HistogramOptions to the accumulator chain via acc_chain.setHistogramOptions().
5871 */
5872 template <int BinCount>
5873 class GlobalRangeHistogram
5874 {
5875  public:
5876 
5877  typedef Select<Global<Minimum>, Global<Maximum>, Minimum, Maximum> Dependencies;
5878 
5879  static std::string name()
5880  {
5881  return std::string("GlobalRangeHistogram<") + asString(BinCount) + ">";
5882  // static const std::string n = std::string("GlobalRangeHistogram<") + asString(BinCount) + ">";
5883  // return n;
5884  }
5885 
5886  template <class U, class BASE>
5887  struct Impl
5888  : public RangeHistogramBase<BASE, BinCount, U>
5889  {
5890  static const unsigned int workInPass = LookupDependency<Minimum, BASE>::type::workInPass + 1;
5891 
5892  bool useLocalMinimax_;
5893 
5894  Impl()
5895  : useLocalMinimax_(false)
5896  {}
5897 
5898  void setRegionAutoInit(bool locally)
5899  {
5900  this->scale_ = 0.0;
5901  useLocalMinimax_ = locally;
5902  }
5903 
5904  void update(U const & t)
5905  {
5906  update(t, 1.0);
5907  }
5908 
5909  void update(U const & t, double weight)
5910  {
5911  if(this->scale_ == 0.0)
5912  {
5913  if(useLocalMinimax_)
5914  this->setMinMax(getDependency<Minimum>(*this), getDependency<Maximum>(*this));
5915  else
5916  this->setMinMax(getDependency<Global<Minimum> >(*this), getDependency<Global<Maximum> >(*this));
5917  }
5918 
5919  RangeHistogramBase<BASE, BinCount, U>::update(t, weight);
5920  }
5921  };
5922 };
5923 
5924 /** \brief Compute (0%, 10%, 25%, 50%, 75%, 90%, 100%) quantiles from given histogram.
5925 
5926  Return type is TinyVector<double, 7> .
5927 */
5928 template <class HistogramAccumulator>
5929 class StandardQuantiles
5930 {
5931  public:
5932 
5933  typedef typename StandardizeTag<HistogramAccumulator>::type HistogramTag;
5934  typedef Select<HistogramTag, Minimum, Maximum, Count> Dependencies;
5935 
5936  static std::string name()
5937  {
5938  return std::string("StandardQuantiles<") + HistogramTag::name() + " >";
5939  // static const std::string n = std::string("StandardQuantiles<") + HistogramTag::name() + " >";
5940  // return n;
5941  }
5942 
5943  template <class U, class BASE>
5944  struct Impl
5945  : public CachedResultBase<BASE, TinyVector<double, 7>, U>
5946  {
5947  typedef typename CachedResultBase<BASE, TinyVector<double, 7>, U>::result_type result_type;
5948  typedef typename CachedResultBase<BASE, TinyVector<double, 7>, U>::value_type value_type;
5949 
5950  static const unsigned int workInPass = LookupDependency<HistogramTag, BASE>::type::workInPass;
5951 
5952  result_type operator()() const
5953  {
5954  if(this->isDirty())
5955  {
5956  double desiredQuantiles[] = {0.0, 0.1, 0.25, 0.5, 0.75, 0.9, 1.0 };
5957  getAccumulator<HistogramTag>(*this).computeStandardQuantiles(getDependency<Minimum>(*this), getDependency<Maximum>(*this),
5958  getDependency<Count>(*this), value_type(desiredQuantiles),
5959  this->value_);
5960  this->setClean();
5961  }
5962  return this->value_;
5963  }
5964  };
5965 };
5966 
5967 template <int N>
5968 struct feature_RegionContour_can_only_be_computed_for_2D_arrays
5969 : vigra::staticAssert::AssertBool<N==2>
5970 {};
5971 
5972 /** \brief Compute the contour of a 2D region.
5973 
5974  AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
5975  */
5977 {
5978  public:
5979  typedef Select<Count> Dependencies;
5980 
5981  static std::string name()
5982  {
5983  return std::string("RegionContour");
5984  // static const std::string n = std::string("RegionContour");
5985  // return n;
5986  }
5987 
5988  template <class T, class BASE>
5989  struct Impl
5990  : public BASE
5991  {
5992  typedef HandleArgSelector<T, LabelArgTag, BASE> LabelHandle;
5993  typedef TinyVector<double, 2> point_type;
5994  typedef Polygon<point_type> value_type;
5995  typedef value_type const & result_type;
5996 
5997  point_type offset_;
5998  value_type contour_;
5999 
6000  Impl()
6001  : offset_()
6002  , contour_()
6003  {}
6004 
6005  void setCoordinateOffset(point_type const & offset)
6006  {
6007  offset_ = offset;
6008  }
6009 
6010  template <class U, class NEXT>
6011  void update(CoupledHandle<U, NEXT> const & t)
6012  {
6013  VIGRA_STATIC_ASSERT((feature_RegionContour_can_only_be_computed_for_2D_arrays<
6015  if(getDependency<Count>(*this) == 1)
6016  {
6017  contour_.clear();
6018  extractContour(LabelHandle::getHandle(t).arrayView(), t.point(), contour_);
6019  contour_ += offset_;
6020  }
6021  }
6022 
6023  template <class U, class NEXT>
6024  void update(CoupledHandle<U, NEXT> const & t, double weight)
6025  {
6026  update(t);
6027  }
6028 
6029  void operator+=(Impl const & o)
6030  {
6031  vigra_precondition(false,
6032  "RegionContour::operator+=(): RegionContour cannot be merged.");
6033  }
6034 
6035  result_type operator()() const
6036  {
6037  return contour_;
6038  }
6039  };
6040 };
6041 
6042 
6043 /** \brief Compute the perimeter of a 2D region.
6044 
6045  This is the length of the polygon returned by RegionContour.
6046 
6047  AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
6048  */
6050 {
6051  public:
6053 
6054  static std::string name()
6055  {
6056  return std::string("RegionPerimeter");
6057  // static const std::string n = std::string("RegionPerimeter");
6058  // return n;
6059  }
6060 
6061  template <class T, class BASE>
6062  struct Impl
6063  : public BASE
6064  {
6065  typedef double value_type;
6066  typedef value_type result_type;
6067 
6068  result_type operator()() const
6069  {
6070  return getDependency<RegionContour>(*this).length();
6071  }
6072  };
6073 };
6074 
6075 /** \brief Compute the circularity of a 2D region.
6076 
6077  The is the ratio between the perimeter of a circle with the same area as the
6078  present region and the perimeter of the region, i.e. \f[c = \frac{2 \sqrt{\pi a}}{p} \f], where a and p are the area and length of the polygon returned by RegionContour.
6079 
6080  AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
6081  */
6083 {
6084  public:
6086 
6087  static std::string name()
6088  {
6089  return std::string("RegionCircularity");
6090  // static const std::string n = std::string("RegionCircularity");
6091  // return n;
6092  }
6093 
6094  template <class T, class BASE>
6095  struct Impl
6096  : public BASE
6097  {
6098  typedef double value_type;
6099  typedef value_type result_type;
6100 
6101  result_type operator()() const
6102  {
6103  return 2.0*sqrt(M_PI*getDependency<RegionContour>(*this).area()) / getDependency<RegionContour>(*this).length();
6104  }
6105  };
6106 };
6107 
6108 /** \brief Compute the eccentricity of a 2D region in terms of its prinipal radii.
6109 
6110  Formula: \f[ e = \sqrt{1 - m^2 / M^2 } \f], where m and M are the minor and major principal radius.
6111 
6112  AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
6113  */
6115 {
6116  public:
6118 
6119  static std::string name()
6120  {
6121  return std::string("RegionEccentricity");
6122  // static const std::string n = std::string("RegionEccentricity");
6123  // return n;
6124  }
6125 
6126  template <class T, class BASE>
6127  struct Impl
6128  : public BASE
6129  {
6130  typedef double value_type;
6131  typedef value_type result_type;
6132 
6133  result_type operator()() const
6134  {
6135  double M = getDependency<RegionRadii>(*this).front(),
6136  m = getDependency<RegionRadii>(*this).back();
6137  return sqrt(1.0 - sq(m/M));
6138  }
6139  };
6140 };
6141 
6142 template <int N>
6143 struct feature_ConvexHull_can_only_be_computed_for_2D_arrays
6144 : vigra::staticAssert::AssertBool<N==2>
6145 {};
6146 
6147 /** \brief Compute the contour of a 2D region.
6148 
6149  AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
6150  */
6152 {
6153  public:
6155 
6156  static std::string name()
6157  {
6158  return std::string("ConvexHull");
6159  // static const std::string n = std::string("ConvexHull");
6160  // return n;
6161  }
6162 
6163  template <class T, class BASE>
6164  struct Impl
6165  : public BASE
6166  {
6167  static const unsigned int workInPass = 2;
6168 
6169  typedef HandleArgSelector<T, LabelArgTag, BASE> LabelHandle;
6170  typedef TinyVector<double, 2> point_type;
6171  typedef Polygon<point_type> polygon_type;
6172  typedef Impl value_type;
6173  typedef value_type const & result_type;
6174 
6175  polygon_type convex_hull_;
6176  point_type input_center_, convex_hull_center_, defect_center_;
6177  double convexity_, rugosity_, mean_defect_displacement_,
6178  defect_area_mean_, defect_area_variance_, defect_area_skewness_, defect_area_kurtosis_;
6179  int convexity_defect_count_;
6180  ArrayVector<MultiArrayIndex> convexity_defect_area_;
6181  bool features_computed_;
6182 
6183  Impl()
6184  : convex_hull_()
6185  , input_center_()
6186  , convex_hull_center_()
6187  , defect_center_()
6188  , convexity_()
6189  , rugosity_()
6190  , mean_defect_displacement_()
6191  , defect_area_mean_()
6192  , defect_area_variance_()
6193  , defect_area_skewness_()
6194  , defect_area_kurtosis_()
6195  , convexity_defect_count_()
6196  , convexity_defect_area_()
6197  , features_computed_(false)
6198  {}
6199 
6200  template <class U, class NEXT>
6201  void update(CoupledHandle<U, NEXT> const & t)
6202  {
6203  VIGRA_STATIC_ASSERT((feature_ConvexHull_can_only_be_computed_for_2D_arrays<
6205  if(!features_computed_)
6206  {
6207  using namespace functor;
6208  Shape2 start = getDependency<Coord<Minimum> >(*this),
6209  stop = getDependency<Coord<Maximum> >(*this) + Shape2(1);
6210  point_type offset(start);
6211  input_center_ = getDependency<RegionCenter>(*this);
6212  MultiArrayIndex label = LabelHandle::getValue(t);
6213 
6214  convex_hull_.clear();
6215  convexHull(getDependency<RegionContour>(*this), convex_hull_);
6216  convex_hull_center_ = centroid(convex_hull_);
6217 
6218  convexity_ = getDependency<RegionContour>(*this).area() / convex_hull_.area();
6219  rugosity_ = getDependency<RegionContour>(*this).length() / convex_hull_.length();
6220 
6221  MultiArray<2, UInt8> convex_hull_difference(stop-start);
6222  fillPolygon(convex_hull_ - offset, convex_hull_difference, 1);
6223  combineTwoMultiArrays(convex_hull_difference,
6224  LabelHandle::getHandle(t).arrayView().subarray(start, stop),
6225  convex_hull_difference,
6226  ifThenElse(Arg2() == Param(label), Param(0), Arg1()));
6227 
6228  MultiArray<2, UInt32> convexity_defects(stop-start);
6229  convexity_defect_count_ =
6230  labelImageWithBackground(convex_hull_difference, convexity_defects, false, 0);
6231 
6232  if (convexity_defect_count_ != 0)
6233  {
6235  Select<LabelArg<1>, Count, RegionCenter> > convexity_defects_stats;
6236  convexity_defects_stats.ignoreLabel(0);
6237  extractFeatures(convexity_defects, convexity_defects_stats);
6238 
6239  double total_defect_area = 0.0;
6240  mean_defect_displacement_ = 0.0;
6241  defect_center_ = point_type();
6242  for (int k = 1; k <= convexity_defect_count_; ++k)
6243  {
6244  double area = get<Count>(convexity_defects_stats, k);
6245  point_type center = get<RegionCenter>(convexity_defects_stats, k) + offset;
6246 
6247  convexity_defect_area_.push_back(area);
6248  total_defect_area += area;
6249  defect_center_ += area*center;
6250  mean_defect_displacement_ += area*norm(input_center_ - center);
6251  }
6252  sort(convexity_defect_area_.begin(), convexity_defect_area_.end(),
6253  std::greater<MultiArrayIndex>());
6254  mean_defect_displacement_ /= total_defect_area;
6255  defect_center_ /= total_defect_area;
6256 
6259  extractFeatures(convexity_defect_area_.begin(),
6260  convexity_defect_area_.end(), defect_area_stats);
6261 
6262  defect_area_mean_ = convexity_defect_count_ > 0
6263  ? get<Mean>(defect_area_stats)
6264  : 0.0;
6265  defect_area_variance_ = convexity_defect_count_ > 1
6266  ? get<UnbiasedVariance>(defect_area_stats)
6267  : 0.0;
6268  defect_area_skewness_ = convexity_defect_count_ > 2
6269  ? get<UnbiasedSkewness>(defect_area_stats)
6270  : 0.0;
6271  defect_area_kurtosis_ = convexity_defect_count_ > 3
6272  ? get<UnbiasedKurtosis>(defect_area_stats)
6273  : 0.0;
6274  }
6275  /**********************************************/
6276  features_computed_ = true;
6277  }
6278  }
6279 
6280  template <class U, class NEXT>
6281  void update(CoupledHandle<U, NEXT> const & t, double weight)
6282  {
6283  update(t);
6284  }
6285 
6286  void operator+=(Impl const & o)
6287  {
6288  vigra_precondition(false,
6289  "ConvexHull::operator+=(): ConvexHull features cannot be merged.");
6290  }
6291 
6292  result_type operator()() const
6293  {
6294  return *this;
6295  }
6296 
6297  /*
6298  * Returns the convex hull polygon.
6299  */
6300  polygon_type const & hull() const
6301  {
6302  return convex_hull_;
6303  }
6304 
6305  /*
6306  * Returns the area enclosed by the input polygon.
6307  */
6308  double inputArea() const
6309  {
6310  vigra_precondition(features_computed_,
6311  "ConvexHull: features must be calculated first.");
6312  return getDependency<RegionContour>(*this).area();
6313  }
6314 
6315  /*
6316  * Returns the area enclosed by the convex hull polygon.
6317  */
6318  double hullArea() const
6319  {
6320  vigra_precondition(features_computed_,
6321  "ConvexHull: features must be calculated first.");
6322  return convex_hull_.area();
6323  }
6324 
6325  /*
6326  * Returns the perimeter of the input polygon.
6327  */
6328  double inputPerimeter() const
6329  {
6330  vigra_precondition(features_computed_,
6331  "ConvexHull: features must be calculated first.");
6332  return getDependency<RegionContour>(*this).length();
6333  }
6334 
6335  /*
6336  * Returns the perimeter of the convex hull polygon.
6337  */
6338  double hullPerimeter() const
6339  {
6340  vigra_precondition(features_computed_,
6341  "ConvexHull: features must be calculated first.");
6342  return convex_hull_.length();
6343  }
6344 
6345  /*
6346  * Center of the original region.
6347  */
6348  point_type const & inputCenter() const
6349  {
6350  return input_center_;
6351  }
6352 
6353  /*
6354  * Center of the region enclosed by the convex hull.
6355  */
6356  point_type const & hullCenter() const
6357  {
6358  return convex_hull_center_;
6359  }
6360 
6361  /*
6362  * Center of difference between the convex hull and the original region.
6363  */
6364  point_type const & convexityDefectCenter() const
6365  {
6366  return defect_center_;
6367  }
6368 
6369  /*
6370  * Returns the ratio between the input area and the convex hull area.
6371  * This is always <tt><= 1</tt>, and the smaller the value is,
6372  * the less convex is the input polygon.
6373  */
6374  double convexity() const
6375  {
6376  vigra_precondition(features_computed_,
6377  "ConvexHull: features must be calculated first.");
6378  return convexity_;
6379  }
6380 
6381  /*
6382  * Returns the ratio between the input perimeter and the convex perimeter.
6383  * This is always <tt>>= 1</tt>, and the higher the value is, the less
6384  * convex is the input polygon.
6385  */
6386  double rugosity() const
6387  {
6388  vigra_precondition(features_computed_,
6389  "ConvexHull: features must be calculated first.");
6390  return rugosity_;
6391  }
6392 
6393  /*
6394  * Returns the number of convexity defects (i.e. number of connected components
6395  * of the difference between convex hull and input region).
6396  */
6397  int convexityDefectCount() const
6398  {
6399  vigra_precondition(features_computed_,
6400  "ConvexHull: features must be calculated first.");
6401  return convexity_defect_count_;
6402  }
6403 
6404  /*
6405  * Returns the mean area of the convexity defects.
6406  */
6407  double convexityDefectAreaMean() const
6408  {
6409  vigra_precondition(features_computed_,
6410  "ConvexHull: features must be calculated first.");
6411  return defect_area_mean_;
6412  }
6413 
6414  /*
6415  * Returns the variance of the convexity defect areas.
6416  */
6417  double convexityDefectAreaVariance() const
6418  {
6419  vigra_precondition(features_computed_,
6420  "ConvexHull: features must be calculated first.");
6421  return defect_area_variance_;
6422  }
6423 
6424  /*
6425  * Returns the skewness of the convexity defect areas.
6426  */
6427  double convexityDefectAreaSkewness() const
6428  {
6429  vigra_precondition(features_computed_,
6430  "ConvexHull: features must be calculated first.");
6431  return defect_area_skewness_;
6432  }
6433 
6434  /*
6435  * Returns the kurtosis of the convexity defect areas.
6436  */
6437  double convexityDefectAreaKurtosis() const
6438  {
6439  vigra_precondition(features_computed_,
6440  "ConvexHull: features must be calculated first.");
6441  return defect_area_kurtosis_;
6442  }
6443 
6444  /*
6445  * Returns the mean distance between the defect areas and the center of
6446  * the input region, weighted by the area of each defect region.
6447  */
6448  double meanDefectDisplacement() const
6449  {
6450  vigra_precondition(features_computed_,
6451  "ConvexHull: features must be calculated first.");
6452  return mean_defect_displacement_;
6453  }
6454 
6455  /*
6456  * Returns the areas of the convexity defect regions (ordered descending).
6457  */
6458  ArrayVector<MultiArrayIndex> const & defectAreaList() const
6459  {
6460  vigra_precondition(features_computed_,
6461  "ConvexHull: features must be calculated first.");
6462  return convexity_defect_area_;
6463  }
6464  };
6465 };
6466 
6467 
6468 }} // namespace vigra::acc
6469 
6470 #endif // VIGRA_ACCUMULATOR_HXX

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.10.0 (Thu Jan 8 2015)