[ 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 #ifdef WITH_LEMON
57  #include "polytope.hxx"
58 #endif
59 #include "functorexpression.hxx"
60 #include "labelimage.hxx"
61 #include "multi_labeling.hxx"
62 #include <algorithm>
63 #include <iostream>
64 
65 namespace vigra {
66 
67 /** \defgroup FeatureAccumulators Feature Accumulators
68 
69 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.
70 
71 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".
72 
73 <b>\#include</b> <vigra/accumulator.hxx>
74 
75 
76 <b>Basic statistics:</b>
77  - PowerSum<N> (computes @f$ \sum_i x_i^N @f$)
78  - AbsPowerSum<N> (computes @f$ \sum_i |x_i|^N @f$)
79  - Skewness, UnbiasedSkewness
80  - Kurtosis, UnbiasedKurtosis
81  - Minimum, Maximum
82  - FlatScatterMatrix (flattened upper-triangular part of scatter matrix)
83  - 4 histogram classes (see \ref histogram "below")
84  - StandardQuantiles (0%, 10%, 25%, 50%, 75%, 90%, 100%)
85  - ArgMinWeight, ArgMaxWeight (store data or coordinate where weight assumes its minimal or maximal value)
86  - CoordinateSystem (identity matrix of appropriate size)
87 
88  <b>Modifiers:</b> (S is the statistc to be modified)
89  - Normalization
90  <table border="0">
91  <tr><td> DivideByCount<S> </td><td> S/Count </td></tr>
92  <tr><td> RootDivideByCount<S> </td><td> sqrt( S/Count ) </td></tr>
93  <tr><td> DivideUnbiased<S> </td><td> S/(Count-1) </td></tr>
94  <tr><td> RootDivideUnbiased<S> &nbsp; &nbsp; </td><td> sqrt( S/(Count-1) ) </td></tr>
95  </table>
96  - Data preparation:
97  <table border="0">
98  <tr><td> Central<S> </td><td> substract mean before computing S </td></tr>
99  <tr><td> Principal<S> </td><td> project onto PCA eigenvectors </td></tr>
100  <tr><td> Whitened<S> &nbsp; &nbsp; </td><td> scale to unit variance after PCA </td></tr>
101  <tr><td> Coord<S> </td><td> compute S from pixel coordinates rather than from pixel values </td></tr>
102  <tr><td> Weighted<S> </td><td> compute weighted version of S </td></tr>
103  <tr><td> Global<S> </td><td> compute S globally rather than per region (per region is default if labels are given) </td></tr>
104  </table>
105 
106  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:
107 
108  <table border="0">
109  <tr><th> Alias </th><th> Full Name </th></tr>
110  <tr><td> Count </td><td> PowerSum<0> </td></tr>
111  <tr><td> Sum </td><td> PowerSum<1> </td></tr>
112  <tr><td> SumOfSquares </td><td> PowerSum<2> </td></tr>
113  <tr><td> Mean </td><td> DivideByCount<PowerSum<1>> </td></tr>
114  <tr><td> RootMeanSquares &nbsp; </td><td> RootDivideByCount<PowerSum<2>> </td></tr>
115  <tr><td> Moment<N> </td><td> DivideByCount<PowerSum<N>> </td></tr>
116  <tr><td> Variance </td><td> DivideByCount<Central<PowerSum<2>>> </td></tr>
117  <tr><td> StdDev </td><td> RootDivideByCount<Central<PowerSum<2>>> </td></tr>
118  <tr><td> Covariance </td><td> DivideByCount<FlatScatterMatrix> </td></tr>
119  <tr><td> RegionCenter </td><td> Coord<Mean> </td></tr>
120  <tr><td> CenterOfMass </td><td> Weighted<Coord<Mean>> </td></tr>
121  </table>
122 
123  There are a few <b>rules for composing statistics</b>:
124  - modifiers can be specified in any order, but are internally transformed to standard order: Global<Weighted<Coord<normalization<data preparation<basic statistic
125  - only one normalization modifier and one data preparation modifier (Central or Principal or Whitened) is permitted
126  - Count ignores all modifiers except Global and Weighted
127  - Sum ignores Central and Principal, because sum would be zero
128  - ArgMinWeight and ArgMaxWeight are automatically Weighted
129 
130 
131  Here is an example how to use \ref acc::AccumulatorChain to compute statistics. (To use Weighted<> or Coord<> modifiers, see below):
132 
133  \code
134  #include <vigra/multi_array.hxx>
135  #include <vigra/impex.hxx>
136  #include <vigra/accumulator.hxx>
137  using namespace vigra::acc;
138  typedef double DataType;
139  int size = 1000;
140  vigra::MultiArray<2, DataType> data(vigra::Shape2(size, size));
141 
142  AccumulatorChain<DataType,
143  Select<Variance, Mean, StdDev, Minimum, Maximum, RootMeanSquares, Skewness, Covariance> >
144  a;
145 
146  std::cout << "passes required: " << a.passesRequired() << std::endl;
147  extractFeatures(data.begin(), data.end(), a);
148 
149  std::cout << "Mean: " << get<Mean>(a) << std::endl;
150  std::cout << "Variance: " << get<Variance>(a) << std::endl;
151  \endcode
152 
153  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 .
154 
155  Rules and notes:
156  - order of statistics in Select<> is arbitrary
157  - up to 20 statistics in Select<>, but Select<> can be nested
158  - dependencies are automatically inserted
159  - duplicates are automatically removed
160  - extractFeatures() does as many passes through the data as necessary
161  - each accumulator only sees data in the appropriate pass (its "working pass")
162 
163  The Accumulators can also be used with vector-valued data (vigra::RGBValue, vigra::TinyVector, vigra::MultiArray or vigra::MultiArrayView):
164 
165  \code
166  typedef vigra::RGBValue<double> DataType;
167  AccumulatorChain<DataType, Select<...> > a;
168  ...
169  \endcode
170 
171  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 :
172 
173  \code
174  vigra::MultiArray<3, RGBValue<unsigned char> > data(...);
175  vigra::MultiArray<3, double> weights(...);
176 
177  AccumulatorChain<CoupledArrays<3, RGBValue<unsigned char>, double>,
178  Select<...> > a;
179  \endcode
180 
181 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)
182  - DataArg<INDEX>: data are in array 'INDEX' (default INDEX=1)
183  - LabelArg<INDEX>: labels are in array 'INDEX' (default INDEX=2)
184  - WeightArg<INDEX>: weights are in array 'INDEX' (default INDEX=rightmost index)
185 
186 Pixel coordinates are always at index 0. To collect statistics, you simply pass all arrays to the <tt>extractFeatures()</tt> function:
187  \code
188  using namespace vigra::acc;
189  vigra::MultiArray<3, double> data(...), weights(...);
190 
191  AccumulatorChain<CoupledArrays<3, double, double>, // two 3D arrays for data and weights
192  Select<DataArg<1>, WeightArg<2>, // in which array to look (coordinates are always arg 0)
193  Mean, Variance, //statistics over values
194  Coord<Mean>, Coord<Variance>, //statistics over coordinates,
195  Weighted<Mean>, Weighted<Variance>, //weighted values,
196  Weighted<Coord<Mean> > > > //weighted coordinates.
197  a;
198 
199  extractFeatures(data, weights, a);
200  \endcode
201 
202  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):
203  \code
204  using namespace vigra::acc;
205  vigra::MultiArray<3, double> data(...);
206 
207  AccumulatorChain<CoupledArrays<3, double>,
208  Select<WeightArg<1>, // we interprete the data as weights
209  Coord<ArgMinWeight> > > // and look for the coordinate with minimal weight
210  a;
211 
212  extractFeatures(data, a);
213  std::cout << "minimum is at " << get<Coord<ArgMinWeight> >(a) << std::endl;
214  \endcode
215 
216  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:
217 
218  \code
219  using namespace vigra::acc;
220  vigra::MultiArray<3, double> data(...);
221  vigra::MultiArray<3, int> labels(...);
222 
223  AccumulatorChainArray<CoupledArrays<3, double, int>,
224  Select<DataArg<1>, LabelArg<2>, // in which array to look (coordinates are always arg 0)
225  Mean, Variance, //per-region statistics over values
226  Coord<Mean>, Coord<Variance>, //per-region statistics over coordinates
227  Global<Mean>, Global<Variance> > > //global statistics
228  a;
229 
230  a.ignoreLabel(0); //statistics will not be computed for region 0 (e.g. background)
231 
232  extractFeatures(data, labels, a);
233 
234  int regionlabel = ...;
235  std::cout << get<Mean>(a, regionlabel) << std::endl; //get Mean of region with label 'regionlabel'
236  \endcode
237 
238 
239  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:
240 
241  \code
242  using namespace vigra::acc;
243  vigra::MultiArray<2, double> data(...);
244  DynamicAccumulatorChain<double,
245  Select<Mean, Minimum, Maximum, Variance, StdDev> > a; // at compile-time
246  activate<Mean>(a); //at run-time
247  a.activate("Minimum"); //same as activate<Minimum>(a) (alias names are not recognized)
248 
249  extractFeatures(data.begin(), data.end(), a);
250  std::cout << "Mean: " << get<Mean>(a) << std::endl; //ok
251  //std::cout << "Maximum: " << get<Maximum>(a) << std::endl; // run-time error because Maximum not activated
252  \endcode
253 
254  Likewise, for run-time activation of region statistics, use \ref acc::DynamicAccumulatorChainArray.
255 
256  <b>Accumulator merging</b> (e.g. for parallelization or hierarchical segmentation) is possible for many accumulators:
257 
258  \code
259  using namespace vigra::acc;
260  vigra::MultiArray<2, double> data(...);
261  AccumulatorChain<double, Select<Mean, Variance, Skewness> > a, a1, a2;
262 
263  extractFeatures(data.begin(), data.end(), a); //process entire data set at once
264  extractFeatures(data.begin(), data.begin()+data.size()/2, a1); //process first half
265  extractFeatures(data.begin()+data.size()/2, data.end(), a2); //process second half
266  a1 += a2; // merge: a1 now equals a0 (within numerical tolerances)
267  \endcode
268 
269  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:
270 
271  \code
272  using namespace vigra::acc;
273  vigra::MultiArray<2, double> data(...);
274  AccumulatorChain<double, Select<Mean, Variance> > a;
275 
276  extractFeatures(data.begin(), data.begin()+data.size()/2, a); // this works because
277  extractFeatures(data.begin()+data.size()/2, data.end(), a); // all statistics only need pass 1
278  \endcode
279 
280  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:
281 
282  \code
283  using namespace vigra;
284  using namespace vigra::acc;
285 
286  MultiArray<2, double> data(width, height);
287  MultiArray<2, int> labels(width, height);
288 
289  AccumulatorChainArray<CoupledArrays<2, double, int>,
290  Select<DataArg<1>, LabelArg<2>,
291  RegionCenter> >
292  a1, a2;
293 
294  // a1 is responsible for the left half of the image. The local coordinate system of this ROI
295  // happens to be identical to the global coordinate system, so the offset is zero.
296  Shape2 origin(0,0);
297  a1.setCoordinateOffset(origin);
298  extractFeatures(data.subarray(origin, Shape2(width/2, height)),
299  labels.subarray(origin, Shape2(width/2, height)),
300  a1);
301 
302  // a2 is responsible for the right half, so the offset of the local coordinate system is (width/2, 0)
303  origin = Shape2(width/2, 0);
304  a2.setCoordinateOffset(origin);
305  extractFeatures(data.subarray(origin, Shape2(width, height)),
306  labels.subarray(origin, Shape2(width, height)),
307  a2);
308 
309  // since both accumulators worked in the same global coordinate system, we can safely merge them
310  a1.merge(a2);
311  \endcode
312 
313  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:
314 
315  \code
316  std::vector<int> labelMapping(2);
317  labelMapping[0] = 0; // background keeps label 0
318  labelMapping[1] = 2; // local region 1 becomes global region 2
319 
320  a1.merge(a2, labelMapping);
321  \endcode
322 
323  \anchor histogram
324  Four kinds of <b>histograms</b> are currently implemented:
325 
326  <table border="0">
327  <tr><td> IntegerHistogram </td><td> Data values are equal to bin indices </td></tr>
328  <tr><td> UserRangeHistogram </td><td> User provides lower and upper bounds for linear range mapping from values to indices. </td></tr>
329  <tr><td> AutoRangeHistogram </td><td> Range mapping bounds are defiend by minimum and maximum of the data (2 passes needed!) </td></tr>
330  <tr><td> GlobalRangeHistogram &nbsp; </td><td> Likewise, but use global min/max rather than region min/max as AutoRangeHistogram will </td></tr>
331  </table>
332 
333 
334 
335  - 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).
336  - If UserRangeHistogram is used, the bounds for the linear range mapping from values to indices must be set before seeing data (see below).
337  - 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.
338  - Merging is supported if the range mapping of the histograms is the same.
339  - Histogram accumulators have two members for outliers (left_outliers, right_outliers).
340 
341  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> .
342 
343  \anchor acc_hist_options Usage:
344  \code
345  using namespace vigra::acc;
346  typedef double DataType;
347  vigra::MultiArray<2, DataType> data(...);
348 
349  typedef UserRangeHistogram<40> SomeHistogram; //binCount set at compile time
350  typedef UserRangeHistogram<0> SomeHistogram2; // binCount must be set at run-time
351  typedef AutoRangeHistogram<0> SomeHistogram3;
352  typedef StandardQuantiles<SomeHistogram3> Quantiles3;
353 
354  AccumulatorChain<DataType, Select<SomeHistogram, SomeHistogram2, SomeHistogram3, Quantiles3> > a;
355 
356  //set options for all histograms in the accumulator chain:
357  vigra::HistogramOptions histogram_opt;
358  histogram_opt = histogram_opt.setBinCount(50);
359  //histogram_opt = histogram_opt.setMinMax(0.1, 0.9); // this would set min/max for all three histograms, but range bounds
360  // shall be set automatically by min/max of data for SomeHistogram3
361  a.setHistogramOptions(histogram_opt);
362 
363  // set options for a specific histogram in the accumulator chain:
364  getAccumulator<SomeHistogram>(a).setMinMax(0.1, 0.9); // number of bins must be set before setting min/max
365  getAccumulator<SomeHistogram2>(a).setMinMax(0.0, 1.0);
366 
367  extractFeatures(data.begin(), data.end(), a);
368 
369  vigra::TinyVector<double, 40> hist = get<SomeHistogram>(a);
370  vigra::MultiArray<1, double> hist2 = get<SomeHistogram2>(a);
371  vigra::TinyVector<double, 7> quant = get<Quantiles3>(a);
372  double right_outliers = getAccumulator<SomeHistogram>(a).right_outliers;
373  \endcode
374 
375 
376 
377 */
378 
379 
380 /** \brief Efficient computation of object statistics.
381 
382  This namespace contains the accumulator classes, fundamental statistics and modifiers. See \ref FeatureAccumulators for examples of usage.
383 */
384 namespace acc {
385 
386 /****************************************************************************/
387 /* */
388 /* infrastructure */
389 /* */
390 /****************************************************************************/
391 
392  /// \brief Wrapper for MakeTypeList that additionally performs tag standardization.
393 
394 template <class T01=void, class T02=void, class T03=void, class T04=void, class T05=void,
395  class T06=void, class T07=void, class T08=void, class T09=void, class T10=void,
396  class T11=void, class T12=void, class T13=void, class T14=void, class T15=void,
397  class T16=void, class T17=void, class T18=void, class T19=void, class T20=void>
398 struct Select
399 : public MakeTypeList<
400  typename StandardizeTag<T01>::type, typename StandardizeTag<T02>::type, typename StandardizeTag<T03>::type,
401  typename StandardizeTag<T04>::type, typename StandardizeTag<T05>::type, typename StandardizeTag<T06>::type,
402  typename StandardizeTag<T07>::type, typename StandardizeTag<T08>::type, typename StandardizeTag<T09>::type,
403  typename StandardizeTag<T10>::type, typename StandardizeTag<T11>::type, typename StandardizeTag<T12>::type,
404  typename StandardizeTag<T13>::type, typename StandardizeTag<T14>::type, typename StandardizeTag<T15>::type,
405  typename StandardizeTag<T16>::type, typename StandardizeTag<T17>::type, typename StandardizeTag<T18>::type,
406  typename StandardizeTag<T19>::type, typename StandardizeTag<T20>::type
407  >
408 {};
409 
410  // enable nesting of Select<> expressions
411 template <class T01, class T02, class T03, class T04, class T05,
412  class T06, class T07, class T08, class T09, class T10,
413  class T11, class T12, class T13, class T14, class T15,
414  class T16, class T17, class T18, class T19, class T20>
415 struct StandardizeTag<Select<T01, T02, T03, T04, T05,
416  T06, T07, T08, T09, T10,
417  T11, T12, T13, T14, T15,
418  T16, T17, T18, T19, T20>,
419  Select<T01, T02, T03, T04, T05,
420  T06, T07, T08, T09, T10,
421  T11, T12, T13, T14, T15,
422  T16, T17, T18, T19, T20> >
423 {
424  typedef typename Select<T01, T02, T03, T04, T05,
425  T06, T07, T08, T09, T10,
426  T11, T12, T13, T14, T15,
427  T16, T17, T18, T19, T20>::type type;
428 };
429 
430 struct AccumulatorBegin
431 {
432  typedef Select<> Dependencies;
433 
434  static std::string name()
435  {
436  return "AccumulatorBegin (internal)";
437  // static const std::string n("AccumulatorBegin (internal)");
438  // return n;
439  }
440 
441  template <class T, class BASE>
442  struct Impl
443  : public BASE
444  {};
445 };
446 
447 
448 struct AccumulatorEnd;
449 struct DataArgTag;
450 struct WeightArgTag;
451 struct LabelArgTag;
452 struct CoordArgTag;
453 struct LabelDispatchTag;
454 
455 template <class T, class TAG, class CHAIN>
456 struct HandleArgSelector; // find the correct handle in a CoupledHandle
457 
458 struct Error__Global_statistics_are_only_defined_for_AccumulatorChainArray;
459 
460 /** \brief Specifies index of labels in CoupledHandle.
461 
462  LabelArg<INDEX> tells the acc::AccumulatorChainArray which index of the Handle contains the labels. (Note that coordinates are always index 0)
463  */
464 template <int INDEX>
465 class LabelArg
466 {
467  public:
468  typedef Select<> Dependencies;
469 
470  static std::string name()
471  {
472  return std::string("LabelArg<") + asString(INDEX) + "> (internal)";
473  // static const std::string n = std::string("LabelArg<") + asString(INDEX) + "> (internal)";
474  // return n;
475  }
476 
477  template <class T, class BASE>
478  struct Impl
479  : public BASE
480  {
481  typedef LabelArgTag Tag;
482  typedef void value_type;
483  typedef void result_type;
484 
485  static const int value = INDEX;
486  static const unsigned int workInPass = 0;
487  };
488 };
489 
490 template <int INDEX>
491 class CoordArg
492 {
493  public:
494  typedef Select<> Dependencies;
495 
496  static std::string name()
497  {
498  return std::string("CoordArg<") + asString(INDEX) + "> (internal)";
499  // static const std::string n = std::string("CoordArg<") + asString(INDEX) + "> (internal)";
500  // return n;
501  }
502 
503  template <class T, class BASE>
504  struct Impl
505  : public BASE
506  {
507  typedef CoordArgTag Tag;
508  typedef void value_type;
509  typedef void result_type;
510 
511  static const int value = INDEX;
512  static const unsigned int workInPass = 0;
513  };
514 };
515 
516 template <class T, class TAG, class NEXT=AccumulatorEnd>
517 struct AccumulatorBase;
518 
519 template <class Tag, class A>
520 struct LookupTag;
521 
522 template <class Tag, class A, class TargetTag=typename A::Tag>
523 struct LookupDependency;
524 
525 #ifndef _MSC_VER // compiler bug? (causes 'ambiguous overload error')
526 
527 template <class TAG, class A>
528 typename LookupTag<TAG, A>::reference
529 getAccumulator(A & a);
530 
531 template <class TAG, class A>
532 typename LookupDependency<TAG, A>::result_type
533 getDependency(A const & a);
534 
535 #endif
536 
537 namespace acc_detail {
538 
539 /****************************************************************************/
540 /* */
541 /* internal tag handling meta-functions */
542 /* */
543 /****************************************************************************/
544 
545  // we must make sure that Arg<INDEX> tags are at the end of the chain because
546  // all other tags potentially depend on them
547 template <class T>
548 struct PushArgTagToTail
549 {
550  typedef T type;
551 };
552 
553 #define VIGRA_PUSHARGTAG(TAG) \
554 template <int INDEX, class TAIL> \
555 struct PushArgTagToTail<TypeList<TAG<INDEX>, TAIL> > \
556 { \
557  typedef typename Push<TAIL, TypeList<TAG<INDEX> > >::type type; \
558 };
559 
560 VIGRA_PUSHARGTAG(DataArg)
561 VIGRA_PUSHARGTAG(WeightArg)
562 VIGRA_PUSHARGTAG(CoordArg)
563 VIGRA_PUSHARGTAG(LabelArg)
564 
565 #undef VIGRA_PUSHARGTAG
566 
567  // Insert the dependencies of the selected functors into the TypeList and sort
568  // the list such that dependencies come after the functors using them. Make sure
569  // that each functor is contained only once.
570 template <class T>
571 struct AddDependencies;
572 
573 template <class HEAD, class TAIL>
574 struct AddDependencies<TypeList<HEAD, TAIL> >
575 {
576  typedef typename AddDependencies<TAIL>::type TailWithDependencies;
577  typedef typename StandardizeDependencies<HEAD>::type HeadDependencies;
578  typedef typename AddDependencies<HeadDependencies>::type TransitiveHeadDependencies;
579  typedef TypeList<HEAD, TransitiveHeadDependencies> HeadWithDependencies;
580  typedef typename PushUnique<HeadWithDependencies, TailWithDependencies>::type UnsortedDependencies;
581  typedef typename PushArgTagToTail<UnsortedDependencies>::type type;
582 };
583 
584 template <>
585 struct AddDependencies<void>
586 {
587  typedef void type;
588 };
589 
590  // Helper class to activate dependencies at runtime (i.e. when activate<Tag>(accu) is called,
591  // activate() must also be called for Tag's dependencies).
592 template <class Dependencies>
593 struct ActivateDependencies;
594 
595 template <class HEAD, class TAIL>
596 struct ActivateDependencies<TypeList<HEAD, TAIL> >
597 {
598  template <class Chain, class ActiveFlags>
599  static void exec(ActiveFlags & flags)
600  {
601  LookupTag<HEAD, Chain>::type::activateImpl(flags);
602  ActivateDependencies<TAIL>::template exec<Chain>(flags);
603  }
604 
605  template <class Chain, class ActiveFlags, class GlobalFlags>
606  static void exec(ActiveFlags & flags, GlobalFlags & gflags)
607  {
608  LookupTag<HEAD, Chain>::type::template activateImpl<Chain>(flags, gflags);
609  ActivateDependencies<TAIL>::template exec<Chain>(flags, gflags);
610  }
611 };
612 
613 template <class HEAD, class TAIL>
614 struct ActivateDependencies<TypeList<Global<HEAD>, TAIL> >
615 {
616  template <class Chain, class ActiveFlags, class GlobalFlags>
617  static void exec(ActiveFlags & flags, GlobalFlags & gflags)
618  {
619  LookupTag<Global<HEAD>, Chain>::type::activateImpl(gflags);
620  ActivateDependencies<TAIL>::template exec<Chain>(flags, gflags);
621  }
622 };
623 
624 template <>
625 struct ActivateDependencies<void>
626 {
627  template <class Chain, class ActiveFlags>
628  static void exec(ActiveFlags &)
629  {}
630 
631  template <class Chain, class ActiveFlags, class GlobalFlags>
632  static void exec(ActiveFlags &, GlobalFlags &)
633  {}
634 };
635 
636 template <class List>
637 struct SeparateGlobalAndRegionTags;
638 
639 template <class HEAD, class TAIL>
640 struct SeparateGlobalAndRegionTags<TypeList<HEAD, TAIL> >
641 {
642  typedef SeparateGlobalAndRegionTags<TAIL> Inner;
643  typedef TypeList<HEAD, typename Inner::RegionTags> RegionTags;
644  typedef typename Inner::GlobalTags GlobalTags;
645 };
646 
647 template <class HEAD, class TAIL>
648 struct SeparateGlobalAndRegionTags<TypeList<Global<HEAD>, TAIL> >
649 {
650  typedef SeparateGlobalAndRegionTags<TAIL> Inner;
651  typedef typename Inner::RegionTags RegionTags;
652  typedef TypeList<HEAD, typename Inner::GlobalTags> GlobalTags;
653 };
654 
655 template <int INDEX, class TAIL>
656 struct SeparateGlobalAndRegionTags<TypeList<DataArg<INDEX>, TAIL> >
657 {
658  typedef SeparateGlobalAndRegionTags<TAIL> Inner;
659  typedef TypeList<DataArg<INDEX>, typename Inner::RegionTags> RegionTags;
660  typedef TypeList<DataArg<INDEX>, typename Inner::GlobalTags> GlobalTags;
661 };
662 
663 template <int INDEX, class TAIL>
664 struct SeparateGlobalAndRegionTags<TypeList<LabelArg<INDEX>, TAIL> >
665 {
666  typedef SeparateGlobalAndRegionTags<TAIL> Inner;
667  typedef TypeList<LabelArg<INDEX>, typename Inner::RegionTags> RegionTags;
668  typedef TypeList<LabelArg<INDEX>, typename Inner::GlobalTags> GlobalTags;
669 };
670 
671 template <int INDEX, class TAIL>
672 struct SeparateGlobalAndRegionTags<TypeList<WeightArg<INDEX>, TAIL> >
673 {
674  typedef SeparateGlobalAndRegionTags<TAIL> Inner;
675  typedef TypeList<WeightArg<INDEX>, typename Inner::RegionTags> RegionTags;
676  typedef TypeList<WeightArg<INDEX>, typename Inner::GlobalTags> GlobalTags;
677 };
678 
679 template <int INDEX, class TAIL>
680 struct SeparateGlobalAndRegionTags<TypeList<CoordArg<INDEX>, TAIL> >
681 {
682  typedef SeparateGlobalAndRegionTags<TAIL> Inner;
683  typedef TypeList<CoordArg<INDEX>, typename Inner::RegionTags> RegionTags;
684  typedef TypeList<CoordArg<INDEX>, typename Inner::GlobalTags> GlobalTags;
685 };
686 
687 template <>
688 struct SeparateGlobalAndRegionTags<void>
689 {
690  typedef void RegionTags;
691  typedef void GlobalTags;
692 };
693 
694 /****************************************************************************/
695 /* */
696 /* helper classes to handle tags at runtime via strings */
697 /* */
698 /****************************************************************************/
699 
700 template <class Accumulators>
701 struct CollectAccumulatorNames;
702 
703 template <class HEAD, class TAIL>
704 struct CollectAccumulatorNames<TypeList<HEAD, TAIL> >
705 {
706  template <class BackInsertable>
707  static void exec(BackInsertable & a, bool skipInternals=true)
708  {
709  if(!skipInternals || HEAD::name().find("internal") == std::string::npos)
710  a.push_back(HEAD::name());
711  CollectAccumulatorNames<TAIL>::exec(a, skipInternals);
712  }
713 };
714 
715 template <>
716 struct CollectAccumulatorNames<void>
717 {
718  template <class BackInsertable>
719  static void exec(BackInsertable &, bool /* skipInternals */ = true)
720  {}
721 };
722 
723 template <class T>
724 struct ApplyVisitorToTag;
725 
726 template <class HEAD, class TAIL>
727 struct ApplyVisitorToTag<TypeList<HEAD, TAIL> >
728 {
729  template <class Accu, class Visitor>
730  static bool exec(Accu & a, std::string const & tag, Visitor const & v)
731  {
732  static std::string * name = VIGRA_SAFE_STATIC(name, new std::string(normalizeString(HEAD::name())));
733  if(*name == tag)
734  {
735  v.template exec<HEAD>(a);
736  return true;
737  }
738  else
739  {
740  return ApplyVisitorToTag<TAIL>::exec(a, tag, v);
741  }
742  }
743 };
744 
745 template <>
746 struct ApplyVisitorToTag<void>
747 {
748  template <class Accu, class Visitor>
749  static bool exec(Accu &, std::string const &, Visitor const &)
750  {
751  return false;
752  }
753 };
754 
755 struct ActivateTag_Visitor
756 {
757  template <class TAG, class Accu>
758  void exec(Accu & a) const
759  {
760  a.template activate<TAG>();
761  }
762 };
763 
764 struct TagIsActive_Visitor
765 {
766  mutable bool result;
767 
768  template <class TAG, class Accu>
769  void exec(Accu & a) const
770  {
771  result = a.template isActive<TAG>();
772  }
773 };
774 
775 /****************************************************************************/
776 /* */
777 /* histogram initialization functors */
778 /* */
779 /****************************************************************************/
780 
781 template <class TAG>
782 struct SetHistogramBincount
783 {
784  template <class Accu>
785  static void exec(Accu &, HistogramOptions const &)
786  {}
787 };
788 
789 template <template <int> class Histogram>
790 struct SetHistogramBincount<Histogram<0> >
791 {
792  template <class Accu>
793  static void exec(Accu & a, HistogramOptions const & options)
794  {
795  a.setBinCount(options.binCount);
796  }
797 };
798 
799 template <class TAG>
800 struct ApplyHistogramOptions
801 {
802  template <class Accu>
803  static void exec(Accu &, HistogramOptions const &)
804  {}
805 };
806 
807 template <class TAG>
808 struct ApplyHistogramOptions<StandardQuantiles<TAG> >
809 {
810  template <class Accu>
811  static void exec(Accu &, HistogramOptions const &)
812  {}
813 };
814 
815 template <class TAG, template <class> class MODIFIER>
816 struct ApplyHistogramOptions<MODIFIER<TAG> >
817 : public ApplyHistogramOptions<TAG>
818 {};
819 
820 template <>
821 struct ApplyHistogramOptions<IntegerHistogram<0> >
822 {
823  template <class Accu>
824  static void exec(Accu & a, HistogramOptions const & options)
825  {
826  SetHistogramBincount<IntegerHistogram<0> >::exec(a, options);
827  }
828 };
829 
830 template <int BinCount>
831 struct ApplyHistogramOptions<UserRangeHistogram<BinCount> >
832 {
833  template <class Accu>
834  static void exec(Accu & a, HistogramOptions const & options)
835  {
836  SetHistogramBincount<UserRangeHistogram<BinCount> >::exec(a, options);
837  if(a.scale_ == 0.0 && options.validMinMax())
838  a.setMinMax(options.minimum, options.maximum);
839  }
840 };
841 
842 template <int BinCount>
843 struct ApplyHistogramOptions<AutoRangeHistogram<BinCount> >
844 {
845  template <class Accu>
846  static void exec(Accu & a, HistogramOptions const & options)
847  {
848  SetHistogramBincount<AutoRangeHistogram<BinCount> >::exec(a, options);
849  if(a.scale_ == 0.0 && options.validMinMax())
850  a.setMinMax(options.minimum, options.maximum);
851  }
852 };
853 
854 template <int BinCount>
855 struct ApplyHistogramOptions<GlobalRangeHistogram<BinCount> >
856 {
857  template <class Accu>
858  static void exec(Accu & a, HistogramOptions const & options)
859  {
860  SetHistogramBincount<GlobalRangeHistogram<BinCount> >::exec(a, options);
861  if(a.scale_ == 0.0)
862  {
863  if(options.validMinMax())
864  a.setMinMax(options.minimum, options.maximum);
865  else
866  a.setRegionAutoInit(options.local_auto_init);
867  }
868  }
869 };
870 
871 /****************************************************************************/
872 /* */
873 /* internal accumulator chain classes */
874 /* */
875 /****************************************************************************/
876 
877  // AccumulatorEndImpl has the following functionalities:
878  // * marks end of accumulator chain by the AccumulatorEnd tag
879  // * provides empty implementation of standard accumulator functions
880  // * provides active_accumulators_ flags for run-time activation of dynamic accumulators
881  // * provides is_dirty_ flags for caching accumulators
882  // * hold the GlobalAccumulatorHandle for global accumulator lookup from region accumulators
883 template <unsigned LEVEL, class GlobalAccumulatorHandle>
884 struct AccumulatorEndImpl
885 {
886  typedef typename GlobalAccumulatorHandle::type GlobalAccumulatorType;
887 
888  typedef AccumulatorEnd Tag;
889  typedef void value_type;
890  typedef bool result_type;
891  typedef BitArray<LEVEL> AccumulatorFlags;
892 
893  static const unsigned int workInPass = 0;
894  static const int index = -1;
895  static const unsigned level = LEVEL;
896 
897  AccumulatorFlags active_accumulators_;
898  mutable AccumulatorFlags is_dirty_;
899  GlobalAccumulatorHandle globalAccumulator_;
900 
901  template <class GlobalAccumulator>
902  void setGlobalAccumulator(GlobalAccumulator const * a)
903  {
904  globalAccumulator_.pointer_ = a;
905  }
906 
907  static std::string name()
908  {
909  return "AccumulatorEnd (internal)";
910  }
911 
912  bool operator()() const { return false; }
913  bool get() const { return false; }
914 
915  template <unsigned, class U>
916  void pass(U const &)
917  {}
918 
919  template <unsigned, class U>
920  void pass(U const &, double)
921  {}
922 
923  template <class U>
924  void mergeImpl(U const &)
925  {}
926 
927  template <class U>
928  void resize(U const &)
929  {}
930 
931  template <class U>
932  void setCoordinateOffsetImpl(U const &)
933  {}
934 
935  void activate()
936  {}
937 
938  bool isActive() const
939  {
940  return false;
941  }
942 
943  template <class Flags>
944  static void activateImpl(Flags &)
945  {}
946 
947  template <class Accu, class Flags1, class Flags2>
948  static void activateImpl(Flags1 &, Flags2 &)
949  {}
950 
951  template <class Flags>
952  static bool isActiveImpl(Flags const &)
953  {
954  return true;
955  }
956 
957  void applyHistogramOptions(HistogramOptions const &)
958  {}
959 
960  static unsigned int passesRequired()
961  {
962  return 0;
963  }
964 
965  static unsigned int passesRequired(AccumulatorFlags const &)
966  {
967  return 0;
968  }
969 
970  void reset()
971  {
972  active_accumulators_.clear();
973  is_dirty_.clear();
974  }
975 
976  template <int which>
977  void setDirtyImpl() const
978  {
979  is_dirty_.template set<which>();
980  }
981 
982  template <int which>
983  void setCleanImpl() const
984  {
985  is_dirty_.template reset<which>();
986  }
987 
988  template <int which>
989  bool isDirtyImpl() const
990  {
991  return is_dirty_.template test<which>();
992  }
993 };
994 
995  // DecoratorImpl implement the functionality of Decorator below
996 template <class A, unsigned CurrentPass, bool allowRuntimeActivation, unsigned WorkPass=A::workInPass>
997 struct DecoratorImpl
998 {
999  template <class T>
1000  static void exec(A &, T const &)
1001  {}
1002 
1003  template <class T>
1004  static void exec(A &, T const &, double)
1005  {}
1006 };
1007 
1008 template <class A, unsigned CurrentPass>
1009 struct DecoratorImpl<A, CurrentPass, false, CurrentPass>
1010 {
1011  template <class T>
1012  static void exec(A & a, T const & t)
1013  {
1014  a.update(t);
1015  }
1016 
1017  template <class T>
1018  static void exec(A & a, T const & t, double weight)
1019  {
1020  a.update(t, weight);
1021  }
1022 
1023  static typename A::result_type get(A const & a)
1024  {
1025  return a();
1026  }
1027 
1028  static void mergeImpl(A & a, A const & o)
1029  {
1030  a += o;
1031  }
1032 
1033  template <class T>
1034  static void resize(A & a, T const & t)
1035  {
1036  a.reshape(t);
1037  }
1038 
1039  static void applyHistogramOptions(A & a, HistogramOptions const & options)
1040  {
1041  ApplyHistogramOptions<typename A::Tag>::exec(a, options);
1042  }
1043 
1044  static unsigned int passesRequired()
1045  {
1046  static const unsigned int A_workInPass = A::workInPass;
1047  return std::max(A_workInPass, A::InternalBaseType::passesRequired());
1048  }
1049 };
1050 
1051 template <class A, unsigned CurrentPass>
1052 struct DecoratorImpl<A, CurrentPass, true, CurrentPass>
1053 {
1054  static bool isActive(A const & a)
1055  {
1056  return A::isActiveImpl(getAccumulator<AccumulatorEnd>(a).active_accumulators_);
1057  }
1058 
1059  template <class T>
1060  static void exec(A & a, T const & t)
1061  {
1062  if(isActive(a))
1063  a.update(t);
1064  }
1065 
1066  template <class T>
1067  static void exec(A & a, T const & t, double weight)
1068  {
1069  if(isActive(a))
1070  a.update(t, weight);
1071  }
1072 
1073  static typename A::result_type get(A const & a)
1074  {
1075  if(!isActive(a))
1076  {
1077  std::string message = std::string("get(accumulator): attempt to access inactive statistic '") +
1078  A::Tag::name() + "'.";
1079  vigra_precondition(false, message);
1080  }
1081  return a();
1082  }
1083 
1084  static void mergeImpl(A & a, A const & o)
1085  {
1086  if(isActive(a))
1087  a += o;
1088  }
1089 
1090  template <class T>
1091  static void resize(A & a, T const & t)
1092  {
1093  if(isActive(a))
1094  a.reshape(t);
1095  }
1096 
1097  static void applyHistogramOptions(A & a, HistogramOptions const & options)
1098  {
1099  if(isActive(a))
1100  ApplyHistogramOptions<typename A::Tag>::exec(a, options);
1101  }
1102 
1103  template <class ActiveFlags>
1104  static unsigned int passesRequired(ActiveFlags const & flags)
1105  {
1106  static const unsigned int A_workInPass = A::workInPass;
1107  return A::isActiveImpl(flags)
1108  ? std::max(A_workInPass, A::InternalBaseType::passesRequired(flags))
1109  : A::InternalBaseType::passesRequired(flags);
1110  }
1111 };
1112 
1113  // Generic reshape function (expands to a no-op when T has fixed shape, and to
1114  // the appropriate specialized call otherwise). Shape is an instance of MultiArrayShape<N>::type.
1115 template <class T, class Shape>
1116 void reshapeImpl(T &, Shape const &)
1117 {}
1118 
1119 template <class T, class Shape, class Initial>
1120 void reshapeImpl(T &, Shape const &, Initial const & = T())
1121 {}
1122 
1123 template <unsigned int N, class T, class Alloc, class Shape>
1124 void reshapeImpl(MultiArray<N, T, Alloc> & a, Shape const & s, T const & initial = T())
1125 {
1126  MultiArray<N, T, Alloc>(s, initial).swap(a);
1127 }
1128 
1129 template <class T, class Alloc, class Shape>
1130 void reshapeImpl(Matrix<T, Alloc> & a, Shape const & s, T const & initial = T())
1131 {
1132  Matrix<T, Alloc>(s, initial).swap(a);
1133 }
1134 
1135 template <class T, class U>
1136 void copyShapeImpl(T const &, U const &) // to be used for scalars and static arrays
1137 {}
1138 
1139 template <unsigned int N, class T, class Alloc, class U>
1140 void copyShapeImpl(MultiArray<N, T, Alloc> const & from, U & to)
1141 {
1142  to.reshape(from.shape());
1143 }
1144 
1145 template <class T, class Alloc, class U>
1146 void copyShapeImpl(Matrix<T, Alloc> const & from, U & to)
1147 {
1148  to.reshape(from.shape());
1149 }
1150 
1151 template <class T, class U>
1152 bool hasDataImpl(T const &) // to be used for scalars and static arrays
1153 {
1154  return true;
1155 }
1156 
1157 template <unsigned int N, class T, class Stride>
1158 bool hasDataImpl(MultiArrayView<N, T, Stride> const & a)
1159 {
1160  return a.hasData();
1161 }
1162 
1163  // generic functions to create suitable shape objects from various input data types
1164 template <unsigned int N, class T, class Stride>
1165 inline typename MultiArrayShape<N>::type
1166 shapeOf(MultiArrayView<N, T, Stride> const & a)
1167 {
1168  return a.shape();
1169 }
1170 
1171 template <class T, int N>
1172 inline Shape1
1173 shapeOf(TinyVector<T, N> const &)
1174 {
1175  return Shape1(N);
1176 }
1177 
1178 template <class T, class NEXT>
1179 inline CoupledHandle<T, NEXT> const &
1180 shapeOf(CoupledHandle<T, NEXT> const & t)
1181 {
1182  return t;
1183 }
1184 
1185 #define VIGRA_SHAPE_OF(type) \
1186 inline Shape1 \
1187 shapeOf(type) \
1188 { \
1189  return Shape1(1); \
1190 }
1191 
1192 VIGRA_SHAPE_OF(unsigned char)
1193 VIGRA_SHAPE_OF(signed char)
1194 VIGRA_SHAPE_OF(unsigned short)
1195 VIGRA_SHAPE_OF(short)
1196 VIGRA_SHAPE_OF(unsigned int)
1197 VIGRA_SHAPE_OF(int)
1198 VIGRA_SHAPE_OF(unsigned long)
1199 VIGRA_SHAPE_OF(long)
1200 VIGRA_SHAPE_OF(unsigned long long)
1201 VIGRA_SHAPE_OF(long long)
1202 VIGRA_SHAPE_OF(float)
1203 VIGRA_SHAPE_OF(double)
1204 VIGRA_SHAPE_OF(long double)
1205 
1206 #undef VIGRA_SHAPE_OF
1207 
1208  // LabelDispatch is only used in AccumulatorChainArrays and has the following functionalities:
1209  // * hold an accumulator chain for global statistics
1210  // * hold an array of accumulator chains (one per region) for region statistics
1211  // * forward data to the appropriate chains
1212  // * allocate the region array with appropriate size
1213  // * store and forward activation requests
1214  // * compute required number of passes as maximum from global and region accumulators
1215 template <class T, class GlobalAccumulators, class RegionAccumulators>
1216 struct LabelDispatch
1217 {
1218  typedef LabelDispatchTag Tag;
1219  typedef GlobalAccumulators GlobalAccumulatorChain;
1220  typedef RegionAccumulators RegionAccumulatorChain;
1221  typedef typename LookupTag<AccumulatorEnd, RegionAccumulatorChain>::type::AccumulatorFlags ActiveFlagsType;
1222  typedef ArrayVector<RegionAccumulatorChain> RegionAccumulatorArray;
1223 
1224  typedef LabelDispatch type;
1225  typedef LabelDispatch & reference;
1226  typedef LabelDispatch const & const_reference;
1227  typedef GlobalAccumulatorChain InternalBaseType;
1228 
1229  typedef T const & argument_type;
1230  typedef argument_type first_argument_type;
1231  typedef double second_argument_type;
1232  typedef RegionAccumulatorChain & result_type;
1233 
1234  static const int index = GlobalAccumulatorChain::index + 1;
1235 
1236  template <class IndexDefinition, class TagFound=typename IndexDefinition::Tag>
1237  struct CoordIndexSelector
1238  {
1239  static const int value = 0; // default: CoupledHandle holds coordinates at index 0
1240  };
1241 
1242  template <class IndexDefinition>
1243  struct CoordIndexSelector<IndexDefinition, CoordArgTag>
1244  {
1245  static const int value = IndexDefinition::value;
1246  };
1247 
1248  static const int coordIndex = CoordIndexSelector<typename LookupTag<CoordArgTag, GlobalAccumulatorChain>::type>::value;
1249  static const int coordSize = CoupledHandleCast<coordIndex, T>::type::value_type::static_size;
1250  typedef TinyVector<double, coordSize> CoordinateType;
1251 
1252  GlobalAccumulatorChain next_;
1253  RegionAccumulatorArray regions_;
1254  HistogramOptions region_histogram_options_;
1255  MultiArrayIndex ignore_label_;
1256  ActiveFlagsType active_region_accumulators_;
1257  CoordinateType coordinateOffset_;
1258 
1259  template <class TAG>
1260  struct ActivateImpl
1261  {
1262  typedef typename LookupTag<TAG, type>::type TargetAccumulator;
1263 
1264  static void activate(GlobalAccumulatorChain & globals, RegionAccumulatorArray & regions,
1265  ActiveFlagsType & flags)
1266  {
1267  TargetAccumulator::template activateImpl<LabelDispatch>(
1268  flags, getAccumulator<AccumulatorEnd>(globals).active_accumulators_);
1269  for(unsigned int k=0; k<regions.size(); ++k)
1270  getAccumulator<AccumulatorEnd>(regions[k]).active_accumulators_ = flags;
1271  }
1272 
1273  static bool isActive(GlobalAccumulatorChain const &, ActiveFlagsType const & flags)
1274  {
1275  return TargetAccumulator::isActiveImpl(flags);
1276  }
1277  };
1278 
1279  template <class TAG>
1280  struct ActivateImpl<Global<TAG> >
1281  {
1282  static void activate(GlobalAccumulatorChain & globals, RegionAccumulatorArray &, ActiveFlagsType &)
1283  {
1284  LookupTag<TAG, GlobalAccumulatorChain>::type::activateImpl(getAccumulator<AccumulatorEnd>(globals).active_accumulators_);
1285  }
1286 
1287  static bool isActive(GlobalAccumulatorChain const & globals, ActiveFlagsType const &)
1288  {
1289  return LookupTag<TAG, GlobalAccumulatorChain>::type::isActiveImpl(getAccumulator<AccumulatorEnd>(globals).active_accumulators_);
1290  }
1291  };
1292 
1293  template <int INDEX>
1294  struct ActivateImpl<LabelArg<INDEX> >
1295  {
1296  static void activate(GlobalAccumulatorChain &, RegionAccumulatorArray &, ActiveFlagsType &)
1297  {}
1298 
1299  static bool isActive(GlobalAccumulatorChain const & globals, ActiveFlagsType const &)
1300  {
1301  return getAccumulator<LabelArg<INDEX> >(globals).isActive();
1302  }
1303  };
1304 
1305  LabelDispatch()
1306  : next_(),
1307  regions_(),
1308  region_histogram_options_(),
1309  ignore_label_(-1),
1310  active_region_accumulators_()
1311  {}
1312 
1313  LabelDispatch(LabelDispatch const & o)
1314  : next_(o.next_),
1315  regions_(o.regions_),
1316  region_histogram_options_(o.region_histogram_options_),
1317  ignore_label_(o.ignore_label_),
1318  active_region_accumulators_(o.active_region_accumulators_)
1319  {
1320  for(unsigned int k=0; k<regions_.size(); ++k)
1321  {
1322  getAccumulator<AccumulatorEnd>(regions_[k]).setGlobalAccumulator(&next_);
1323  }
1324  }
1325 
1326  MultiArrayIndex maxRegionLabel() const
1327  {
1328  return (MultiArrayIndex)regions_.size() - 1;
1329  }
1330 
1331  void setMaxRegionLabel(unsigned maxlabel)
1332  {
1333  if(maxRegionLabel() == (MultiArrayIndex)maxlabel)
1334  return;
1335  unsigned int oldSize = regions_.size();
1336  regions_.resize(maxlabel + 1);
1337  for(unsigned int k=oldSize; k<regions_.size(); ++k)
1338  {
1339  getAccumulator<AccumulatorEnd>(regions_[k]).setGlobalAccumulator(&next_);
1340  getAccumulator<AccumulatorEnd>(regions_[k]).active_accumulators_ = active_region_accumulators_;
1341  regions_[k].applyHistogramOptions(region_histogram_options_);
1342  regions_[k].setCoordinateOffsetImpl(coordinateOffset_);
1343  }
1344  }
1345 
1346  void ignoreLabel(MultiArrayIndex l)
1347  {
1348  ignore_label_ = l;
1349  }
1350 
1351  MultiArrayIndex ignoredLabel() const
1352  {
1353  return ignore_label_;
1354  }
1355 
1356  void applyHistogramOptions(HistogramOptions const & options)
1357  {
1358  applyHistogramOptions(options, options);
1359  }
1360 
1361  void applyHistogramOptions(HistogramOptions const & regionoptions,
1362  HistogramOptions const & globaloptions)
1363  {
1364  region_histogram_options_ = regionoptions;
1365  for(unsigned int k=0; k<regions_.size(); ++k)
1366  {
1367  regions_[k].applyHistogramOptions(region_histogram_options_);
1368  }
1369  next_.applyHistogramOptions(globaloptions);
1370  }
1371 
1372  void setCoordinateOffsetImpl(CoordinateType const & offset)
1373  {
1374  coordinateOffset_ = offset;
1375  for(unsigned int k=0; k<regions_.size(); ++k)
1376  {
1377  regions_[k].setCoordinateOffsetImpl(coordinateOffset_);
1378  }
1379  next_.setCoordinateOffsetImpl(coordinateOffset_);
1380  }
1381 
1382  void setCoordinateOffsetImpl(MultiArrayIndex k, CoordinateType const & offset)
1383  {
1384  vigra_precondition(0 <= k && k < (MultiArrayIndex)regions_.size(),
1385  "Accumulator::setCoordinateOffset(k, offset): region k does not exist.");
1386  regions_[k].setCoordinateOffsetImpl(offset);
1387  }
1388 
1389  template <class U>
1390  void resize(U const & t)
1391  {
1392  if(regions_.size() == 0)
1393  {
1394  typedef HandleArgSelector<U, LabelArgTag, GlobalAccumulatorChain> LabelHandle;
1395  typedef typename LabelHandle::value_type LabelType;
1396  typedef MultiArrayView<LabelHandle::size, LabelType, StridedArrayTag> LabelArray;
1397  LabelArray labelArray(t.shape(), LabelHandle::getHandle(t).strides(),
1398  const_cast<LabelType *>(LabelHandle::getHandle(t).ptr()));
1399 
1400  LabelType minimum, maximum;
1401  labelArray.minmax(&minimum, &maximum);
1402  setMaxRegionLabel(maximum);
1403  }
1404  next_.resize(t);
1405  // FIXME: only call resize when label k actually exists?
1406  for(unsigned int k=0; k<regions_.size(); ++k)
1407  regions_[k].resize(t);
1408  }
1409 
1410  template <unsigned N>
1411  void pass(T const & t)
1412  {
1413  typedef HandleArgSelector<T, LabelArgTag, GlobalAccumulatorChain> LabelHandle;
1414  if(LabelHandle::getValue(t) != ignore_label_)
1415  {
1416  next_.template pass<N>(t);
1417  regions_[LabelHandle::getValue(t)].template pass<N>(t);
1418  }
1419  }
1420 
1421  template <unsigned N>
1422  void pass(T const & t, double weight)
1423  {
1424  typedef HandleArgSelector<T, LabelArgTag, GlobalAccumulatorChain> LabelHandle;
1425  if(LabelHandle::getValue(t) != ignore_label_)
1426  {
1427  next_.template pass<N>(t, weight);
1428  regions_[LabelHandle::getValue(t)].template pass<N>(t, weight);
1429  }
1430  }
1431 
1432  static unsigned int passesRequired()
1433  {
1434  return std::max(GlobalAccumulatorChain::passesRequired(), RegionAccumulatorChain::passesRequired());
1435  }
1436 
1437  unsigned int passesRequiredDynamic() const
1438  {
1439  return std::max(GlobalAccumulatorChain::passesRequired(getAccumulator<AccumulatorEnd>(next_).active_accumulators_),
1440  RegionAccumulatorChain::passesRequired(active_region_accumulators_));
1441  }
1442 
1443  void reset()
1444  {
1445  next_.reset();
1446 
1447  active_region_accumulators_.clear();
1448  RegionAccumulatorArray().swap(regions_);
1449  // FIXME: or is it better to just reset the region accumulators?
1450  // for(unsigned int k=0; k<regions_.size(); ++k)
1451  // regions_[k].reset();
1452  }
1453 
1454  template <class TAG>
1455  void activate()
1456  {
1457  ActivateImpl<TAG>::activate(next_, regions_, active_region_accumulators_);
1458  }
1459 
1460  void activateAll()
1461  {
1462  getAccumulator<AccumulatorEnd>(next_).active_accumulators_.set();
1463  active_region_accumulators_.set();
1464  for(unsigned int k=0; k<regions_.size(); ++k)
1465  getAccumulator<AccumulatorEnd>(regions_[k]).active_accumulators_.set();
1466  }
1467 
1468  template <class TAG>
1469  bool isActive() const
1470  {
1471  return ActivateImpl<TAG>::isActive(next_, active_region_accumulators_);
1472  }
1473 
1474  void mergeImpl(LabelDispatch const & o)
1475  {
1476  for(unsigned int k=0; k<regions_.size(); ++k)
1477  regions_[k].mergeImpl(o.regions_[k]);
1478  next_.mergeImpl(o.next_);
1479  }
1480 
1481  void mergeImpl(unsigned i, unsigned j)
1482  {
1483  regions_[i].mergeImpl(regions_[j]);
1484  regions_[j].reset();
1485  getAccumulator<AccumulatorEnd>(regions_[j]).active_accumulators_ = active_region_accumulators_;
1486  }
1487 
1488  template <class ArrayLike>
1489  void mergeImpl(LabelDispatch const & o, ArrayLike const & labelMapping)
1490  {
1491  MultiArrayIndex newMaxLabel = std::max<MultiArrayIndex>(maxRegionLabel(), *argMax(labelMapping.begin(), labelMapping.end()));
1492  setMaxRegionLabel(newMaxLabel);
1493  for(unsigned int k=0; k<labelMapping.size(); ++k)
1494  regions_[labelMapping[k]].mergeImpl(o.regions_[k]);
1495  next_.mergeImpl(o.next_);
1496  }
1497 };
1498 
1499 template <class TargetTag, class TagList>
1500 struct FindNextTag;
1501 
1502 template <class TargetTag, class HEAD, class TAIL>
1503 struct FindNextTag<TargetTag, TypeList<HEAD, TAIL> >
1504 {
1505  typedef typename FindNextTag<TargetTag, TAIL>::type type;
1506 };
1507 
1508 template <class TargetTag, class TAIL>
1509 struct FindNextTag<TargetTag, TypeList<TargetTag, TAIL> >
1510 {
1511  typedef typename TAIL::Head type;
1512 };
1513 
1514 template <class TargetTag>
1515 struct FindNextTag<TargetTag, TypeList<TargetTag, void> >
1516 {
1517  typedef void type;
1518 };
1519 
1520 template <class TargetTag>
1521 struct FindNextTag<TargetTag, void>
1522 {
1523  typedef void type;
1524 };
1525 
1526  // AccumulatorFactory creates the decorator hierarchy for the given TAG and configuration CONFIG
1527 template <class TAG, class CONFIG, unsigned LEVEL=0>
1528 struct AccumulatorFactory
1529 {
1530  typedef typename FindNextTag<TAG, typename CONFIG::TagList>::type NextTag;
1531  typedef typename AccumulatorFactory<NextTag, CONFIG, LEVEL+1>::type NextType;
1532  typedef typename CONFIG::InputType InputType;
1533 
1534  template <class T>
1535  struct ConfigureTag
1536  {
1537  typedef TAG type;
1538  };
1539 
1540  // When InputType is a CoupledHandle, some tags need to be wrapped into
1541  // DataFromHandle<> and/or Weighted<> modifiers. The following code does
1542  // this when appropriate.
1543  template <class T, class NEXT>
1544  struct ConfigureTag<CoupledHandle<T, NEXT> >
1545  {
1546  typedef typename StandardizeTag<DataFromHandle<TAG> >::type WrappedTag;
1547  typedef typename IfBool<(!HasModifierPriority<WrappedTag, WeightingPriority>::value && ShouldBeWeighted<WrappedTag>::value),
1548  Weighted<WrappedTag>, WrappedTag>::type type;
1549  };
1550 
1551  typedef typename ConfigureTag<InputType>::type UseTag;
1552 
1553  // base class of the decorator hierarchy: default (possibly empty)
1554  // implementations of all members
1555  struct AccumulatorBase
1556  {
1557  typedef AccumulatorBase ThisType;
1558  typedef TAG Tag;
1559  typedef NextType InternalBaseType;
1560  typedef InputType input_type;
1561  typedef input_type const & argument_type;
1562  typedef argument_type first_argument_type;
1563  typedef double second_argument_type;
1564  typedef void result_type;
1565 
1566  static const unsigned int workInPass = 1;
1567  static const int index = InternalBaseType::index + 1;
1568 
1569  InternalBaseType next_;
1570 
1571  static std::string name()
1572  {
1573  return TAG::name();
1574  }
1575 
1576  template <class ActiveFlags>
1577  static void activateImpl(ActiveFlags & flags)
1578  {
1579  flags.template set<index>();
1580  typedef typename StandardizeDependencies<Tag>::type StdDeps;
1581  acc_detail::ActivateDependencies<StdDeps>::template exec<ThisType>(flags);
1582  }
1583 
1584  template <class Accu, class ActiveFlags, class GlobalFlags>
1585  static void activateImpl(ActiveFlags & flags, GlobalFlags & gflags)
1586  {
1587  flags.template set<index>();
1588  typedef typename StandardizeDependencies<Tag>::type StdDeps;
1589  acc_detail::ActivateDependencies<StdDeps>::template exec<Accu>(flags, gflags);
1590  }
1591 
1592  template <class ActiveFlags>
1593  static bool isActiveImpl(ActiveFlags & flags)
1594  {
1595  return flags.template test<index>();
1596  }
1597 
1598  void setDirty() const
1599  {
1600  next_.template setDirtyImpl<index>();
1601  }
1602 
1603  template <int INDEX>
1604  void setDirtyImpl() const
1605  {
1606  next_.template setDirtyImpl<INDEX>();
1607  }
1608 
1609  void setClean() const
1610  {
1611  next_.template setCleanImpl<index>();
1612  }
1613 
1614  template <int INDEX>
1615  void setCleanImpl() const
1616  {
1617  next_.template setCleanImpl<INDEX>();
1618  }
1619 
1620  bool isDirty() const
1621  {
1622  return next_.template isDirtyImpl<index>();
1623  }
1624 
1625  template <int INDEX>
1626  bool isDirtyImpl() const
1627  {
1628  return next_.template isDirtyImpl<INDEX>();
1629  }
1630 
1631  void reset()
1632  {}
1633 
1634  template <class Shape>
1635  void setCoordinateOffset(Shape const &)
1636  {}
1637 
1638  template <class Shape>
1639  void reshape(Shape const &)
1640  {}
1641 
1642  void operator+=(AccumulatorBase const &)
1643  {}
1644 
1645  template <class U>
1646  void update(U const &)
1647  {}
1648 
1649  template <class U>
1650  void update(U const &, double)
1651  {}
1652 
1653  template <class TargetTag>
1654  typename LookupDependency<TargetTag, ThisType>::result_type
1655  call_getDependency() const
1656  {
1657  return getDependency<TargetTag>(*this);
1658  }
1659  };
1660 
1661  // The middle class(es) of the decorator hierarchy implement the actual feature computation.
1662  typedef typename UseTag::template Impl<InputType, AccumulatorBase> AccumulatorImpl;
1663 
1664  // outer class of the decorator hierarchy. It has the following functionalities
1665  // * ensure that only active accumulators are called in a dynamic accumulator chain
1666  // * ensure that each accumulator is only called in its desired pass as defined in A::workInPass
1667  // * determine how many passes through the data are required
1668  struct Accumulator
1669  : public AccumulatorImpl
1670  {
1671  typedef Accumulator type;
1672  typedef Accumulator & reference;
1673  typedef Accumulator const & const_reference;
1674  typedef AccumulatorImpl A;
1675 
1676  static const unsigned int workInPass = A::workInPass;
1677  static const bool allowRuntimeActivation = CONFIG::allowRuntimeActivation;
1678 
1679  template <class T>
1680  void resize(T const & t)
1681  {
1682  this->next_.resize(t);
1683  DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>::resize(*this, t);
1684  }
1685 
1686  void reset()
1687  {
1688  this->next_.reset();
1689  A::reset();
1690  }
1691 
1692  typename A::result_type get() const
1693  {
1694  return DecoratorImpl<A, workInPass, allowRuntimeActivation>::get(*this);
1695  }
1696 
1697  template <unsigned N, class T>
1698  void pass(T const & t)
1699  {
1700  this->next_.template pass<N>(t);
1701  DecoratorImpl<Accumulator, N, allowRuntimeActivation>::exec(*this, t);
1702  }
1703 
1704  template <unsigned N, class T>
1705  void pass(T const & t, double weight)
1706  {
1707  this->next_.template pass<N>(t, weight);
1708  DecoratorImpl<Accumulator, N, allowRuntimeActivation>::exec(*this, t, weight);
1709  }
1710 
1711  void mergeImpl(Accumulator const & o)
1712  {
1713  DecoratorImpl<Accumulator, Accumulator::workInPass, allowRuntimeActivation>::mergeImpl(*this, o);
1714  this->next_.mergeImpl(o.next_);
1715  }
1716 
1717  void applyHistogramOptions(HistogramOptions const & options)
1718  {
1719  DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>::applyHistogramOptions(*this, options);
1720  this->next_.applyHistogramOptions(options);
1721  }
1722 
1723  template <class SHAPE>
1724  void setCoordinateOffsetImpl(SHAPE const & offset)
1725  {
1726  this->setCoordinateOffset(offset);
1727  this->next_.setCoordinateOffsetImpl(offset);
1728  }
1729 
1730  static unsigned int passesRequired()
1731  {
1732  return DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>::passesRequired();
1733  }
1734 
1735  template <class ActiveFlags>
1736  static unsigned int passesRequired(ActiveFlags const & flags)
1737  {
1738  return DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>::passesRequired(flags);
1739  }
1740  };
1741 
1742  typedef Accumulator type;
1743 };
1744 
1745 template <class CONFIG, unsigned LEVEL>
1746 struct AccumulatorFactory<void, CONFIG, LEVEL>
1747 {
1748  typedef AccumulatorEndImpl<LEVEL, typename CONFIG::GlobalAccumulatorHandle> type;
1749 };
1750 
1751 struct InvalidGlobalAccumulatorHandle
1752 {
1753  typedef Error__Global_statistics_are_only_defined_for_AccumulatorChainArray type;
1754 
1755  InvalidGlobalAccumulatorHandle()
1756  : pointer_(0)
1757  {}
1758 
1759  type const * pointer_;
1760 };
1761 
1762  // helper classes to create an accumulator chain from a TypeList
1763  // if dynamic=true, a dynamic accumulator will be created
1764  // if dynamic=false, a plain accumulator will be created
1765 template <class T, class Selected, bool dynamic=false, class GlobalHandle=InvalidGlobalAccumulatorHandle>
1766 struct ConfigureAccumulatorChain
1767 #ifndef DOXYGEN
1768 : public ConfigureAccumulatorChain<T, typename AddDependencies<typename Selected::type>::type, dynamic>
1769 #endif
1770 {};
1771 
1772 template <class T, class HEAD, class TAIL, bool dynamic, class GlobalHandle>
1773 struct ConfigureAccumulatorChain<T, TypeList<HEAD, TAIL>, dynamic, GlobalHandle>
1774 {
1775  typedef TypeList<HEAD, TAIL> TagList;
1776  typedef T InputType;
1777  static const bool allowRuntimeActivation = dynamic;
1778  typedef GlobalHandle GlobalAccumulatorHandle;
1779 
1780  typedef typename AccumulatorFactory<HEAD, ConfigureAccumulatorChain>::type type;
1781 };
1782 
1783 template <class T, class Selected, bool dynamic=false>
1784 struct ConfigureAccumulatorChainArray
1785 #ifndef DOXYGEN
1786 : public ConfigureAccumulatorChainArray<T, typename AddDependencies<typename Selected::type>::type, dynamic>
1787 #endif
1788 {};
1789 
1790 template <class T, class HEAD, class TAIL, bool dynamic>
1791 struct ConfigureAccumulatorChainArray<T, TypeList<HEAD, TAIL>, dynamic>
1792 {
1793  typedef TypeList<HEAD, TAIL> TagList;
1794  typedef SeparateGlobalAndRegionTags<TagList> TagSeparator;
1795  typedef typename TagSeparator::GlobalTags GlobalTags;
1796  typedef typename TagSeparator::RegionTags RegionTags;
1797  typedef typename ConfigureAccumulatorChain<T, GlobalTags, dynamic>::type GlobalAccumulatorChain;
1798 
1799  struct GlobalAccumulatorHandle
1800  {
1801  typedef GlobalAccumulatorChain type;
1802 
1803  GlobalAccumulatorHandle()
1804  : pointer_(0)
1805  {}
1806 
1807  type const * pointer_;
1808  };
1809 
1810  typedef typename ConfigureAccumulatorChain<T, RegionTags, dynamic, GlobalAccumulatorHandle>::type RegionAccumulatorChain;
1811 
1812  typedef LabelDispatch<T, GlobalAccumulatorChain, RegionAccumulatorChain> type;
1813 };
1814 
1815 } // namespace acc_detail
1816 
1817 /****************************************************************************/
1818 /* */
1819 /* accumulator chain */
1820 /* */
1821 /****************************************************************************/
1822 
1823 // Implement the high-level interface of an accumulator chain
1824 template <class T, class NEXT>
1825 class AccumulatorChainImpl
1826 {
1827  public:
1828  typedef NEXT InternalBaseType;
1829  typedef AccumulatorBegin Tag;
1830  typedef typename InternalBaseType::argument_type argument_type;
1831  typedef typename InternalBaseType::first_argument_type first_argument_type;
1832  typedef typename InternalBaseType::second_argument_type second_argument_type;
1833  typedef void value_type;
1834  typedef typename InternalBaseType::result_type result_type;
1835 
1836  static const int staticSize = InternalBaseType::index;
1837 
1838  InternalBaseType next_;
1839 
1840  /** \brief Current pass of the accumulator chain.
1841  */
1842  unsigned int current_pass_;
1843 
1844  AccumulatorChainImpl()
1845  : current_pass_(0)
1846  {}
1847 
1848  /** 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.
1849  */
1850  void setHistogramOptions(HistogramOptions const & options)
1851  {
1852  next_.applyHistogramOptions(options);
1853  }
1854 
1855 
1856  /** Set regional and global options for all histograms in the accumulator chain.
1857  */
1858  void setHistogramOptions(HistogramOptions const & regionoptions, HistogramOptions const & globaloptions)
1859  {
1860  next_.applyHistogramOptions(regionoptions, globaloptions);
1861  }
1862 
1863  /** Set an offset for <tt>Coord<...></tt> statistics.
1864 
1865  If the offset is non-zero, coordinate statistics such as <tt>RegionCenter</tt> are computed
1866  in the global coordinate system defined by the \a offset. Without an offset, these statistics
1867  are computed in the local coordinate system of the current region of interest.
1868  */
1869  template <class SHAPE>
1870  void setCoordinateOffset(SHAPE const & offset)
1871  {
1872  next_.setCoordinateOffsetImpl(offset);
1873  }
1874 
1875  /** Reset current_pass_ of the accumulator chain to 'reset_to_pass'.
1876  */
1877  void reset(unsigned int reset_to_pass = 0)
1878  {
1879  current_pass_ = reset_to_pass;
1880  if(reset_to_pass == 0)
1881  next_.reset();
1882  }
1883 
1884  template <unsigned N>
1885  void update(T const & t)
1886  {
1887  if(current_pass_ == N)
1888  {
1889  next_.template pass<N>(t);
1890  }
1891  else if(current_pass_ < N)
1892  {
1893  current_pass_ = N;
1894  if(N == 1)
1895  next_.resize(acc_detail::shapeOf(t));
1896  next_.template pass<N>(t);
1897  }
1898  else
1899  {
1900  std::string message("AccumulatorChain::update(): cannot return to pass ");
1901  message << N << " after working on pass " << current_pass_ << ".";
1902  vigra_precondition(false, message);
1903  }
1904  }
1905 
1906  template <unsigned N>
1907  void update(T const & t, double weight)
1908  {
1909  if(current_pass_ == N)
1910  {
1911  next_.template pass<N>(t, weight);
1912  }
1913  else if(current_pass_ < N)
1914  {
1915  current_pass_ = N;
1916  if(N == 1)
1917  next_.resize(acc_detail::shapeOf(t));
1918  next_.template pass<N>(t, weight);
1919  }
1920  else
1921  {
1922  std::string message("AccumulatorChain::update(): cannot return to pass ");
1923  message << N << " after working on pass " << current_pass_ << ".";
1924  vigra_precondition(false, message);
1925  }
1926  }
1927 
1928  /** Equivalent to merge(o) .
1929  */
1930  void operator+=(AccumulatorChainImpl const & o)
1931  {
1932  merge(o);
1933  }
1934 
1935  /** 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.
1936  */
1937  void merge(AccumulatorChainImpl const & o)
1938  {
1939  next_.mergeImpl(o.next_);
1940  }
1941 
1942  result_type operator()() const
1943  {
1944  return next_.get();
1945  }
1946 
1947  void operator()(T const & t)
1948  {
1949  update<1>(t);
1950  }
1951 
1952  void operator()(T const & t, double weight)
1953  {
1954  update<1>(t, weight);
1955  }
1956 
1957  void updatePass2(T const & t)
1958  {
1959  update<2>(t);
1960  }
1961 
1962  void updatePass2(T const & t, double weight)
1963  {
1964  update<2>(t, weight);
1965  }
1966 
1967  /** 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.
1968  */
1969  void updatePassN(T const & t, unsigned int N)
1970  {
1971  switch (N)
1972  {
1973  case 1: update<1>(t); break;
1974  case 2: update<2>(t); break;
1975  case 3: update<3>(t); break;
1976  case 4: update<4>(t); break;
1977  case 5: update<5>(t); break;
1978  default:
1979  vigra_precondition(false,
1980  "AccumulatorChain::updatePassN(): 0 < N < 6 required.");
1981  }
1982  }
1983 
1984  /** 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.
1985  */
1986  void updatePassN(T const & t, double weight, unsigned int N)
1987  {
1988  switch (N)
1989  {
1990  case 1: update<1>(t, weight); break;
1991  case 2: update<2>(t, weight); break;
1992  case 3: update<3>(t, weight); break;
1993  case 4: update<4>(t, weight); break;
1994  case 5: update<5>(t, weight); break;
1995  default:
1996  vigra_precondition(false,
1997  "AccumulatorChain::updatePassN(): 0 < N < 6 required.");
1998  }
1999  }
2000 
2001  /** Return the number of passes required to compute all statistics in the accumulator chain.
2002  */
2003  unsigned int passesRequired() const
2004  {
2005  return InternalBaseType::passesRequired();
2006  }
2007 };
2008 
2009 
2010 
2011  // Create an accumulator chain containing the Selected statistics and their dependencies.
2012 
2013 /** \brief Create an accumulator chain containing the selected statistics and their dependencies.
2014 
2015  AccumulatorChain is used to compute global statistics which have to be selected at compile time.
2016 
2017  The template parameters are as follows:
2018  - T: The input type
2019  - either element type of the data(e.g. double, int, RGBValue, ...)
2020  - or type of CoupledHandle (for simultaneous access to coordinates and/or weights)
2021  - Selected: statistics to be computed and index specifier for the CoupledHandle, wrapped with Select
2022 
2023  <b>Usage:</b>
2024 
2025  \code
2026  typedef double DataType;
2027  AccumulatorChain<DataType, Select<Variance, Mean, Minimum, ...> > accumulator;
2028  \endcode
2029 
2030  Usage, using CoupledHandle:
2031  \code
2032  const int dim = 3; //dimension of MultiArray
2033  typedef double DataType;
2034  typedef double WeightType;
2035  typedef vigra::CoupledIteratorType<dim, DataType, WeightType>::HandleType Handle;
2036  AccumulatorChain<Handle, Select<DataArg<1>, WeightArg<2>, Mean,...> > a;
2037  \endcode
2038 
2039  See \ref FeatureAccumulators for more information and examples of use.
2040  */
2041 template <class T, class Selected, bool dynamic=false>
2043 #ifndef DOXYGEN // hide AccumulatorChainImpl from documentation
2044 : public AccumulatorChainImpl<T, typename acc_detail::ConfigureAccumulatorChain<T, Selected, dynamic>::type>
2045 #endif
2046 {
2047  public:
2048  // \brief TypeList of Tags in the accumulator chain (?).
2049  typedef typename acc_detail::ConfigureAccumulatorChain<T, Selected, dynamic>::TagList AccumulatorTags;
2050 
2051  /** Before having seen data (current_pass_==0), the shape of the data can be changed... (?)
2052  */
2053  template <class U, int N>
2054  void reshape(TinyVector<U, N> const & s)
2055  {
2056  vigra_precondition(this->current_pass_ == 0,
2057  "AccumulatorChain::reshape(): cannot reshape after seeing data. Call AccumulatorChain::reset() first.");
2058  this->next_.resize(s);
2059  this->current_pass_ = 1;
2060  }
2061 
2062  /** Return the names of all tags in the accumulator chain (selected statistics and their dependencies).
2063  */
2065  {
2066  static ArrayVector<std::string> * n = VIGRA_SAFE_STATIC(n, new ArrayVector<std::string>(collectTagNames()));
2067  return *n;
2068  }
2069 
2070 
2071 #ifdef DOXYGEN // hide AccumulatorChainImpl from documentation
2072 
2073  /** 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.
2074  */
2075  void setHistogramOptions(HistogramOptions const & options);
2076 
2077  /** Set an offset for <tt>Coord<...></tt> statistics.
2078 
2079  If the offset is non-zero, coordinate statistics such as <tt>RegionCenter</tt> are computed
2080  in the global coordinate system defined by the \a offset. Without an offset, these statistics
2081  are computed in the local coordinate system of the current region of interest.
2082  */
2083  template <class SHAPE>
2084  void setCoordinateOffset(SHAPE const & offset);
2085 
2086  /** Reset current_pass_ of the accumulator chain to 'reset_to_pass'. */
2087  void reset(unsigned int reset_to_pass = 0);
2088 
2089  /** Equivalent to merge(o) . */
2090  void operator+=(AccumulatorChainImpl const & o);
2091 
2092  /** 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.
2093  */
2094  void merge(AccumulatorChainImpl const & o);
2095 
2096  /** 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.
2097  */
2098  void updatePassN(T const & t, unsigned int N);
2099 
2100  /** 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.
2101  */
2102  void updatePassN(T const & t, double weight, unsigned int N);
2103 
2104  /** Return the number of passes required to compute all statistics in the accumulator chain.
2105  */
2106  unsigned int passesRequired() const;
2107 
2108 #endif
2109 
2110  private:
2111  static ArrayVector<std::string> collectTagNames()
2112  {
2114  acc_detail::CollectAccumulatorNames<AccumulatorTags>::exec(n);
2115  std::sort(n.begin(), n.end());
2116  return n;
2117  }
2118 };
2119 
2120 template <unsigned int N, class T1, class T2, class T3, class T4, class T5, class Selected, bool dynamic>
2121 class AccumulatorChain<CoupledArrays<N, T1, T2, T3, T4, T5>, Selected, dynamic>
2122 : public AccumulatorChain<typename CoupledArrays<N, T1, T2, T3, T4, T5>::HandleType, Selected, dynamic>
2123 {};
2124 
2125 
2126  // Create a dynamic accumulator chain containing the Selected statistics and their dependencies.
2127  // Statistics will only be computed if activate<Tag>() is called at runtime.
2128 /** \brief Create a dynamic accumulator chain containing the selected statistics and their dependencies.
2129 
2130  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).
2131 
2132  The template parameters are as follows:
2133  - T: The input type
2134  - either element type of the data(e.g. double, int, RGBValue, ...)
2135  - or type of CoupledHandle (for access to coordinates and/or weights)
2136  - Selected: statistics to be computed and index specifier for the CoupledHandle, wrapped with Select
2137 
2138  <b>Usage:</b>
2139 
2140  \code
2141  typedef double DataType;
2142  DynamicAccumulatorChain<DataType, Select<Variance, Mean, Minimum, ...> > accumulator;
2143  \endcode
2144 
2145  Usage, using CoupledHandle:
2146  \code
2147  const int dim = 3; //dimension of MultiArray
2148  typedef double DataType;
2149  typedef double WeightType;
2150  typedef vigra::CoupledIteratorType<dim, DataType, WeightType>::HandleType Handle;
2151  DynamicAccumulatorChain<Handle, Select<DataArg<1>, WeightArg<2>, Mean,...> > a;
2152  \endcode
2153 
2154  See \ref FeatureAccumulators for more information and examples of use.
2155  */
2156 template <class T, class Selected>
2158 : public AccumulatorChain<T, Selected, true>
2159 {
2160  public:
2161  typedef typename AccumulatorChain<T, Selected, true>::InternalBaseType InternalBaseType;
2162  typedef typename DynamicAccumulatorChain::AccumulatorTags AccumulatorTags;
2163 
2164  /** Activate statistic 'tag'. Alias names are not recognized. If the statistic is not in the accumulator chain a PreconditionViolation is thrown.
2165  */
2166  void activate(std::string tag)
2167  {
2168  vigra_precondition(activateImpl(tag),
2169  std::string("DynamicAccumulatorChain::activate(): Tag '") + tag + "' not found.");
2170  }
2171 
2172  /** %activate<TAG>() activates statistic 'TAG'. If the statistic is not in the accumulator chain it is ignored. (?)
2173  */
2174  template <class TAG>
2175  void activate()
2176  {
2177  LookupTag<TAG, DynamicAccumulatorChain>::type::activateImpl(getAccumulator<AccumulatorEnd>(*this).active_accumulators_);
2178  }
2179 
2180  /** Activate all statistics in the accumulator chain.
2181  */
2183  {
2184  getAccumulator<AccumulatorEnd>(*this).active_accumulators_.set();
2185  }
2186  /** 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.)
2187  */
2188  bool isActive(std::string tag) const
2189  {
2190  acc_detail::TagIsActive_Visitor v;
2191  vigra_precondition(isActiveImpl(tag, v),
2192  std::string("DynamicAccumulatorChain::isActive(): Tag '") + tag + "' not found.");
2193  return v.result;
2194  }
2195 
2196  /** %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. (?)
2197  */
2198  template <class TAG>
2199  bool isActive() const
2200  {
2201  return LookupTag<TAG, DynamicAccumulatorChain>::type::isActiveImpl(getAccumulator<AccumulatorEnd>(*this).active_accumulators_);
2202  }
2203 
2204  /** Return names of all statistics in the accumulator chain that are active.
2205  */
2207  {
2209  for(unsigned k=0; k<DynamicAccumulatorChain::tagNames().size(); ++k)
2211  res.push_back(DynamicAccumulatorChain::tagNames()[k]);
2212  return res;
2213  }
2214 
2215  /** Return number of passes required to compute the active statistics in the accumulator chain.
2216  */
2217  unsigned int passesRequired() const
2218  {
2219  return InternalBaseType::passesRequired(getAccumulator<AccumulatorEnd>(*this).active_accumulators_);
2220  }
2221 
2222  protected:
2223 
2224  bool activateImpl(std::string tag)
2225  {
2226  return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(*this,
2227  normalizeString(tag), acc_detail::ActivateTag_Visitor());
2228  }
2229 
2230  bool isActiveImpl(std::string tag, acc_detail::TagIsActive_Visitor & v) const
2231  {
2232  return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(*this, normalizeString(tag), v);
2233  }
2234 };
2235 
2236 template <unsigned int N, class T1, class T2, class T3, class T4, class T5, class Selected>
2237 class DynamicAccumulatorChain<CoupledArrays<N, T1, T2, T3, T4, T5>, Selected>
2238 : public DynamicAccumulatorChain<typename CoupledArrays<N, T1, T2, T3, T4, T5>::HandleType, Selected>
2239 {};
2240 
2241 
2242 
2243 /** \brief Create an accumulator chain that works independently of a MultiArray.
2244 
2245  Instead of a CoupledHandle (the internal type of the MultiArray iterator),
2246  you simply pass a data item of type T and a coordinate object of size N
2247  (<tt>MultiArrayShape<N>::type</tt>) explicitly.
2248 
2249  <b>Usage:</b>
2250 
2251  \code
2252  typedef double DataType;
2253  const int dim = 3;
2254  StandAloneAccumulatorChain<dim, DataType, Select<Variance, Mean, Minimum, ...> > accumulator;
2255 
2256  int pass = 1;
2257  for( all items )
2258  {
2259  typename MultiArrayShape<dim>::type coord = ...;
2260  DataType value = ...;
2261  accumulator.updatePassN(value, coord, pass);
2262  }
2263  \endcode
2264 
2265  See \ref FeatureAccumulators for more information and examples of use.
2266 */
2267 template<unsigned int N, class T, class SELECT>
2269 : public AccumulatorChain<typename CoupledHandleType<N, T>::type,
2270  SELECT>
2271 {
2272  public:
2273  typedef typename CoupledHandleType<N, T>::type HandleType;
2274  typedef typename HandleType::base_type CoordHandle;
2275  typedef typename CoordHandle::value_type CoordType;
2276  typedef SELECT SelectType;
2278 
2280  : BaseType(),
2281  handle_((T const *)0, CoordType(), CoordHandle(CoordType()))
2282  {}
2283 
2284  void updatePassN(const T & val, const CoordType & coord, unsigned int p)
2285  {
2286  cast<0>(handle_).internal_reset(coord);
2287  cast<1>(handle_).internal_reset(&val);
2288  BaseType::updatePassN(handle_, p);
2289  }
2290 
2291  private:
2292  HandleType handle_;
2293 };
2294 
2295 /** \brief Create an accumulator chain that works independently of a MultiArray.
2296 
2297  Instead of a CoupledHandle (the internal type of the MultiArray iterator),
2298  you just pass a coordinate object of size N (<tt>MultiArrayShape<N>::type</tt>)
2299  explicitly.
2300 
2301  <b>Usage:</b>
2302 
2303  \code
2304  const int dim = 3;
2305  StandAloneDataFreeAccumulatorChain<dim, Select<Variance, Mean, Minimum, ...> > accumulator;
2306 
2307  int pass = 1;
2308  for( all items )
2309  {
2310  typename MultiArrayShape<dim>::type coord = ...;
2311  accumulator.updatePassN(coord, pass);
2312  }
2313  \endcode
2314 
2315  See \ref FeatureAccumulators for more information and examples of use.
2316 */
2317 template<unsigned int N, class SELECT>
2319 : public AccumulatorChain<typename CoupledHandleType<N>::type,
2320  SELECT>
2321 {
2322  public:
2323  typedef typename CoupledHandleType<N>::type HandleType;
2324  typedef typename HandleType::value_type CoordType;
2325 
2326  typedef SELECT SelectType;
2328 
2330  : BaseType(),
2331  handle_(CoordType())
2332  {}
2333 
2334  template<class IGNORED_DATA>
2335  void
2336  updatePassN(const IGNORED_DATA &,
2337  const CoordType & coord,
2338  unsigned int p)
2339  {
2340  this->updatePassN(coord, p);
2341  }
2342 
2343 
2344  void updatePassN(const CoordType & coord, unsigned int p)
2345  {
2346  handle_.internal_reset(coord);
2347  BaseType::updatePassN(handle_, p);
2348  }
2349 
2350  private:
2351  HandleType handle_;
2352 };
2353 
2354 
2355 
2356 
2357 
2358 /** \brief Create an array of accumulator chains containing the selected per-region and global statistics and their dependencies.
2359 
2360  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).
2361 
2362  The template parameters are as follows:
2363  - T: The input type, type of CoupledHandle (for access to coordinates, labels and weights)
2364  - Selected: statistics to be computed and index specifier for the CoupledHandle, wrapped with Select
2365 
2366  Usage:
2367  \code
2368  const int dim = 3; //dimension of MultiArray
2369  typedef double DataType;
2370  typedef double WeightType;
2371  typedef unsigned int LabelType;
2372  typedef vigra::CoupledIteratorType<dim, DataType, WeightType, LabelType>::HandleType Handle;
2373  AccumulatorChainArray<Handle, Select<DataArg<1>, WeightArg<2>, LabelArg<3>, Mean, Variance, ...> > a;
2374  \endcode
2375 
2376  See \ref FeatureAccumulators for more information and examples of use.
2377 */
2378 template <class T, class Selected, bool dynamic=false>
2380 #ifndef DOXYGEN //hide AccumulatorChainImpl vom documentation
2381 : public AccumulatorChainImpl<T, typename acc_detail::ConfigureAccumulatorChainArray<T, Selected, dynamic>::type>
2382 #endif
2383 {
2384  public:
2385  typedef AccumulatorChainImpl<T, typename acc_detail::ConfigureAccumulatorChainArray<T, Selected, dynamic>::type> base_type;
2386  typedef typename acc_detail::ConfigureAccumulatorChainArray<T, Selected, dynamic> Creator;
2387  typedef typename Creator::TagList AccumulatorTags;
2388  typedef typename Creator::GlobalTags GlobalTags;
2389  typedef typename Creator::RegionTags RegionTags;
2390 
2391  /** Statistics will not be computed for label l. Note that only one label can be ignored.
2392  */
2394  {
2395  this->next_.ignoreLabel(l);
2396  }
2397 
2398  /** Ask for a label to be ignored. Default: -1 (meaning that no label is ignored).
2399  */
2401  {
2402  return this->next_.ignoredLabel();
2403  }
2404 
2405  /** Set the maximum region label (e.g. for merging two accumulator chains).
2406  */
2407  void setMaxRegionLabel(unsigned label)
2408  {
2409  this->next_.setMaxRegionLabel(label);
2410  }
2411 
2412  /** Maximum region label. (equal to regionCount() - 1)
2413  */
2415  {
2416  return this->next_.maxRegionLabel();
2417  }
2418 
2419  /** Number of Regions. (equal to maxRegionLabel() + 1)
2420  */
2421  unsigned int regionCount() const
2422  {
2423  return this->next_.regions_.size();
2424  }
2425 
2426  /** Equivalent to <tt>merge(o)</tt>.
2427  */
2429  {
2430  merge(o);
2431  }
2432 
2433  /** Merge region i with region j.
2434  */
2435  void merge(unsigned i, unsigned j)
2436  {
2437  vigra_precondition(i <= maxRegionLabel() && j <= maxRegionLabel(),
2438  "AccumulatorChainArray::merge(): region labels out of range.");
2439  this->next_.mergeImpl(i, j);
2440  }
2441 
2442  /** Merge with accumulator chain o. maxRegionLabel() of the two accumulators must be equal.
2443  */
2445  {
2446  if(maxRegionLabel() == -1)
2448  vigra_precondition(maxRegionLabel() == o.maxRegionLabel(),
2449  "AccumulatorChainArray::merge(): maxRegionLabel must be equal.");
2450  this->next_.mergeImpl(o.next_);
2451  }
2452 
2453  /** 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().
2454  */
2455  template <class ArrayLike>
2456  void merge(AccumulatorChainArray const & o, ArrayLike const & labelMapping)
2457  {
2458  vigra_precondition(labelMapping.size() == o.regionCount(),
2459  "AccumulatorChainArray::merge(): labelMapping.size() must match regionCount() of RHS.");
2460  this->next_.mergeImpl(o.next_, labelMapping);
2461  }
2462 
2463  /** Return names of all tags in the accumulator chain (selected statistics and their dependencies).
2464  */
2466  {
2467  static const ArrayVector<std::string> n = collectTagNames();
2468  return n;
2469  }
2470 
2471  using base_type::setCoordinateOffset;