[ 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  {
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;
2472 
2473  /** Set an offset for <tt>Coord<...></tt> statistics for region \a k.
2474 
2475  If the offset is non-zero, coordinate statistics such as <tt>RegionCenter</tt> are computed
2476  in the global coordinate system defined by the \a offset. Without an offset, these statistics
2477  are computed in the local coordinate system of the current region of interest.
2478  */
2479  template <class SHAPE>
2480  void setCoordinateOffset(MultiArrayIndex k, SHAPE const & offset)
2481  {
2482  this->next_.setCoordinateOffsetImpl(k, offset);
2483  }
2484 
2485 #ifdef DOXYGEN // hide AccumulatorChainImpl from documentation
2486 
2487  /** \copydoc vigra::acc::AccumulatorChain::setHistogramOptions(HistogramOptions const &) */
2488  void setHistogramOptions(HistogramOptions const & options);
2489 
2490  /** Set regional and global options for all histograms in the accumulator chain.
2491  */
2492  void setHistogramOptions(HistogramOptions const & regionoptions, HistogramOptions const & globaloptions);
2493 
2494  /** \copydoc vigra::acc::AccumulatorChain::setCoordinateOffset(SHAPE const &)
2495  */
2496  template <class SHAPE>
2497  void setCoordinateOffset(SHAPE const & offset)
2498 
2499  /** \copydoc vigra::acc::AccumulatorChain::reset() */
2500  void reset(unsigned int reset_to_pass = 0);
2501 
2502  /** \copydoc vigra::acc::AccumulatorChain::operator+=() */
2503  void operator+=(AccumulatorChainImpl const & o);
2504 
2505  /** \copydoc vigra::acc::AccumulatorChain::updatePassN(T const &,unsigned int) */
2506  void updatePassN(T const & t, unsigned int N);
2507 
2508  /** \copydoc vigra::acc::AccumulatorChain::updatePassN(T const &,double,unsigned int) */
2509  void updatePassN(T const & t, double weight, unsigned int N);
2510 
2511 #endif
2512 
2513  private:
2514  static ArrayVector<std::string> collectTagNames()
2515  {
2517  acc_detail::CollectAccumulatorNames<AccumulatorTags>::exec(n);
2518  std::sort(n.begin(), n.end());
2519  return n;
2520  }
2521 };
2522 
2523 template <unsigned int N, class T1, class T2, class T3, class T4, class T5, class Selected, bool dynamic>
2524 class AccumulatorChainArray<CoupledArrays<N, T1, T2, T3, T4, T5>, Selected, dynamic>
2525 : public AccumulatorChainArray<typename CoupledArrays<N, T1, T2, T3, T4, T5>::HandleType, Selected, dynamic>
2526 {};
2527 
2528 /** \brief Create an array of dynamic accumulator chains containing the selected per-region and global statistics and their dependencies.
2529 
2530 
2531  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).
2532 
2533  The template parameters are as follows:
2534  - T: The input type, type of CoupledHandle (for access to coordinates, labels and weights)
2535  - Selected: statistics to be computed and index specifier for the CoupledHandle, wrapped with Select
2536 
2537  Usage:
2538  \code
2539  const int dim = 3; //dimension of MultiArray
2540  typedef double DataType;
2541  typedef double WeightType;
2542  typedef unsigned int LabelType;
2543  typedef vigra::CoupledIteratorType<dim, DataType, WeightType, LabelType>::HandleType Handle;
2544  DynamicAccumulatorChainArray<Handle, Select<DataArg<1>, WeightArg<2>, LabelArg<3>, Mean, Variance, ...> > a;
2545  \endcode
2546 
2547  See \ref FeatureAccumulators for more information and examples of use.
2548 */
2549 template <class T, class Selected>
2551 : public AccumulatorChainArray<T, Selected, true>
2552 {
2553  public:
2554  typedef typename DynamicAccumulatorChainArray::AccumulatorTags AccumulatorTags;
2555 
2556  /** \copydoc DynamicAccumulatorChain::activate(std::string tag) */
2557  void activate(std::string tag)
2558  {
2559  vigra_precondition(activateImpl(tag),
2560  std::string("DynamicAccumulatorChainArray::activate(): Tag '") + tag + "' not found.");
2561  }
2562 
2563  /** \copydoc DynamicAccumulatorChain::activate() */
2564  template <class TAG>
2565  void activate()
2566  {
2567  this->next_.template activate<TAG>();
2568  }
2569 
2570  /** \copydoc DynamicAccumulatorChain::activateAll() */
2572  {
2573  this->next_.activateAll();
2574  }
2575 
2576  /** 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.)
2577  */
2578  bool isActive(std::string tag) const
2579  {
2580  acc_detail::TagIsActive_Visitor v;
2581  vigra_precondition(isActiveImpl(tag, v),
2582  std::string("DynamicAccumulatorChainArray::isActive(): Tag '") + tag + "' not found.");
2583  return v.result;
2584  }
2585 
2586  /** %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. (?)
2587  */
2588  template <class TAG>
2589  bool isActive() const
2590  {
2591  return this->next_.template isActive<TAG>();
2592  }
2593 
2594  /** \copydoc DynamicAccumulatorChain::activeNames() */
2596  {
2598  for(unsigned k=0; k<DynamicAccumulatorChainArray::tagNames().size(); ++k)
2600  res.push_back(DynamicAccumulatorChainArray::tagNames()[k]);
2601  return res;
2602  }
2603 
2604  /** \copydoc DynamicAccumulatorChain::passesRequired() */
2605  unsigned int passesRequired() const
2606  {
2607  return this->next_.passesRequiredDynamic();
2608  }
2609 
2610  protected:
2611 
2612  bool activateImpl(std::string tag)
2613  {
2614  return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(this->next_,
2615  normalizeString(tag), acc_detail::ActivateTag_Visitor());
2616  }
2617 
2618  bool isActiveImpl(std::string tag, acc_detail::TagIsActive_Visitor & v) const
2619  {
2620  return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(this->next_, normalizeString(tag), v);
2621  }
2622 };
2623 
2624 template <unsigned int N, class T1, class T2, class T3, class T4, class T5, class Selected>
2625 class DynamicAccumulatorChainArray<CoupledArrays<N, T1, T2, T3, T4, T5>, Selected>
2626 : public DynamicAccumulatorChainArray<typename CoupledArrays<N, T1, T2, T3, T4, T5>::HandleType, Selected>
2627 {};
2628 
2629 /****************************************************************************/
2630 /* */
2631 /* generic access functions */
2632 /* */
2633 /****************************************************************************/
2634 
2635 template <class TAG>
2636 struct Error__Attempt_to_access_inactive_statistic;
2637 
2638 namespace acc_detail {
2639 
2640  // accumulator lookup rules: find the accumulator that implements TAG
2641 
2642  // When A does not implement TAG, continue search in A::InternalBaseType.
2643 template <class TAG, class A, class FromTag=typename A::Tag>
2644 struct LookupTagImpl
2645 #ifndef DOXYGEN
2646 : public LookupTagImpl<TAG, typename A::InternalBaseType>
2647 #endif
2648 {};
2649 
2650  // 'const A' is treated like A, except that the reference member is now const.
2651 template <class TAG, class A, class FromTag>
2652 struct LookupTagImpl<TAG, A const, FromTag>
2653 : public LookupTagImpl<TAG, A>
2654 {
2655  typedef typename LookupTagImpl<TAG, A>::type const & reference;
2656  typedef typename LookupTagImpl<TAG, A>::type const * pointer;
2657 };
2658 
2659  // When A implements TAG, report its type and associated information.
2660 template <class TAG, class A>
2661 struct LookupTagImpl<TAG, A, TAG>
2662 {
2663  typedef TAG Tag;
2664  typedef A type;
2665  typedef A & reference;
2666  typedef A * pointer;
2667  typedef typename A::value_type value_type;
2668  typedef typename A::result_type result_type;
2669 };
2670 
2671  // Again, 'const A' is treated like A, except that the reference member is now const.
2672 template <class TAG, class A>
2673 struct LookupTagImpl<TAG, A const, TAG>
2674 : public LookupTagImpl<TAG, A, TAG>
2675 {
2676  typedef typename LookupTagImpl<TAG, A, TAG>::type const & reference;
2677  typedef typename LookupTagImpl<TAG, A, TAG>::type const * pointer;
2678 };
2679 
2680  // Recursion termination: when we end up in AccumulatorEnd without finding a
2681  // suitable A, we stop and report an error
2682 template <class TAG, class A>
2683 struct LookupTagImpl<TAG, A, AccumulatorEnd>
2684 {
2685  typedef TAG Tag;
2686  typedef A type;
2687  typedef A & reference;
2688  typedef A * pointer;
2689  typedef Error__Attempt_to_access_inactive_statistic<TAG> value_type;
2690  typedef Error__Attempt_to_access_inactive_statistic<TAG> result_type;
2691 };
2692 
2693  // ... except when we are actually looking for AccumulatorEnd
2694 template <class A>
2695 struct LookupTagImpl<AccumulatorEnd, A, AccumulatorEnd>
2696 {
2697  typedef AccumulatorEnd Tag;
2698  typedef A type;
2699  typedef A & reference;
2700  typedef A * pointer;
2701  typedef void value_type;
2702  typedef void result_type;
2703 };
2704 
2705  // ... or we are looking for a global statistic, in which case
2706  // we continue the serach via A::GlobalAccumulatorType, but remember that
2707  // we are actually looking for a global tag.
2708 template <class TAG, class A>
2709 struct LookupTagImpl<Global<TAG>, A, AccumulatorEnd>
2710 : public LookupTagImpl<TAG, typename A::GlobalAccumulatorType>
2711 {
2712  typedef Global<TAG> Tag;
2713 };
2714 
2715  // When we encounter the LabelDispatch accumulator, we continue the
2716  // search via LabelDispatch::RegionAccumulatorChain by default
2717 template <class TAG, class A>
2718 struct LookupTagImpl<TAG, A, LabelDispatchTag>
2719 : public LookupTagImpl<TAG, typename A::RegionAccumulatorChain>
2720 {};
2721 
2722  // ... except when we are looking for a global statistic, in which case
2723  // we continue via LabelDispatch::GlobalAccumulatorChain, but remember that
2724  // we are actually looking for a global tag.
2725 template <class TAG, class A>
2726 struct LookupTagImpl<Global<TAG>, A, LabelDispatchTag>
2727 : public LookupTagImpl<TAG, typename A::GlobalAccumulatorChain>
2728 {
2729  typedef Global<TAG> Tag;
2730 };
2731 
2732  // ... or we are looking for the LabelDispatch accumulator itself
2733 template <class A>
2734 struct LookupTagImpl<LabelDispatchTag, A, LabelDispatchTag>
2735 {
2736  typedef LabelDispatchTag Tag;
2737  typedef A type;
2738  typedef A & reference;
2739  typedef A * pointer;
2740  typedef void value_type;
2741  typedef void result_type;
2742 };
2743 
2744 } // namespace acc_detail
2745 
2746  // Lookup the accumulator in the chain A that implements the given TAG.
2747 template <class Tag, class A>
2748 struct LookupTag
2749 : public acc_detail::LookupTagImpl<typename StandardizeTag<Tag>::type, A>
2750 {};
2751 
2752  // Lookup the dependency TAG of the accumulator A.
2753  // This template ensures that dependencies are used with matching modifiers.
2754  // Specifically, if you search for Count as a dependency of Weighted<Mean>, the search
2755  // actually returns Weighted<Count>, wheras Count will be returned for plain Mean.
2756 template <class Tag, class A, class TargetTag>
2757 struct LookupDependency
2758 : public acc_detail::LookupTagImpl<
2759  typename TransferModifiers<TargetTag, typename StandardizeTag<Tag>::type>::type, A>
2760 {};
2761 
2762 
2763 namespace acc_detail {
2764 
2765  // CastImpl applies the same rules as LookupTagImpl, but returns a reference to an
2766  // accumulator instance rather than an accumulator type
2767 template <class Tag, class FromTag, class reference>
2768 struct CastImpl
2769 {
2770  template <class A>
2771  static reference exec(A & a)
2772  {
2773  return CastImpl<Tag, typename A::InternalBaseType::Tag, reference>::exec(a.next_);
2774  }
2775 
2776  template <class A>
2777  static reference exec(A & a, MultiArrayIndex label)
2778  {
2779  return CastImpl<Tag, typename A::InternalBaseType::Tag, reference>::exec(a.next_, label);
2780  }
2781 };
2782 
2783 template <class Tag, class reference>
2784 struct CastImpl<Tag, Tag, reference>
2785 {
2786  template <class A>
2787  static reference exec(A & a)
2788  {
2789  return const_cast<reference>(a);
2790  }
2791 
2792  template <class A>
2793  static reference exec(A & a, MultiArrayIndex)
2794  {
2795  vigra_precondition(false,
2796  "getAccumulator(): region accumulators can only be queried for AccumulatorChainArray.");
2797  return a;
2798  }
2799 };
2800 
2801 template <class Tag, class reference>
2802 struct CastImpl<Tag, AccumulatorEnd, reference>
2803 {
2804  template <class A>
2805  static reference exec(A & a)
2806  {
2807  return a;
2808  }
2809 
2810  template <class A>
2811  static reference exec(A & a, MultiArrayIndex)
2812  {
2813  return a;
2814  }
2815 };
2816 
2817 template <class Tag, class reference>
2818 struct CastImpl<Global<Tag>, AccumulatorEnd, reference>
2819 {
2820  template <class A>
2821  static reference exec(A & a)
2822  {
2823  return CastImpl<Tag, typename A::GlobalAccumulatorType::Tag, reference>::exec(*a.globalAccumulator_.pointer_);
2824  }
2825 };
2826 
2827 template <class reference>
2828 struct CastImpl<AccumulatorEnd, AccumulatorEnd, reference>
2829 {
2830  template <class A>
2831  static reference exec(A & a)
2832  {
2833  return a;
2834  }
2835 
2836  template <class A>
2837  static reference exec(A & a, MultiArrayIndex)
2838  {
2839  return a;
2840  }
2841 };
2842 
2843 template <class Tag, class reference>
2844 struct CastImpl<Tag, LabelDispatchTag, reference>
2845 {
2846  template <class A>
2847  static reference exec(A & a)
2848  {
2849  vigra_precondition(false,
2850  "getAccumulator(): a region label is required when a region accumulator is queried.");
2851  return CastImpl<Tag, typename A::RegionAccumulatorChain::Tag, reference>::exec(a.regions_[0]);
2852  }
2853 
2854  template <class A>
2855  static reference exec(A & a, MultiArrayIndex label)
2856  {
2857  return CastImpl<Tag, typename A::RegionAccumulatorChain::Tag, reference>::exec(a.regions_[label]);
2858  }
2859 };
2860 
2861 template <class Tag, class reference>
2862 struct CastImpl<Global<Tag>, LabelDispatchTag, reference>
2863 {
2864  template <class A>
2865  static reference exec(A & a)
2866  {
2867  return CastImpl<Tag, typename A::GlobalAccumulatorChain::Tag, reference>::exec(a.next_);
2868  }
2869 };
2870 
2871 template <class reference>
2872 struct CastImpl<LabelDispatchTag, LabelDispatchTag, reference>
2873 {
2874  template <class A>
2875  static reference exec(A & a)
2876  {
2877  return a;
2878  }
2879 };
2880 
2881 } // namespace acc_detail
2882 
2883  // Get a reference to the accumulator TAG in the accumulator chain A
2884 /** 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
2885 Example of use (set options):
2886 \code
2887  vigra::MultiArray<2, double> data(...);
2888  typedef UserRangeHistogram<40> SomeHistogram; //binCount set at compile time
2889  typedef UserRangeHistogram<0> SomeHistogram2; // binCount must be set at run-time
2890  AccumulatorChain<DataType, Select<SomeHistogram, SomeHistogram2> > a;
2891 
2892  getAccumulator<SomeHistogram>(a).setMinMax(0.1, 0.9);
2893  getAccumulator<SomeHistogram2>(a).setMinMax(0.0, 1.0);
2894 
2895  extractFeatures(data.begin(), data.end(), a);
2896 \endcode
2897 
2898 Example of use (get information):
2899 \code
2900  vigra::MultiArray<2, double> data(...));
2901  AccumulatorChain<double, Select<Mean, Skewness> > a;
2902 
2903  std::cout << "passes required for all statistics: " << a.passesRequired() << std::endl; //skewness needs two passes
2904  std::cout << "passes required by Mean: " << getAccumulator<Mean>(a).passesRequired() << std::endl;
2905 \endcode
2906 See \ref FeatureAccumulators for more information about feature computation via accumulators.
2907 */
2908 template <class TAG, class A>
2909 inline typename LookupTag<TAG, A>::reference
2911 {
2912  typedef typename LookupTag<TAG, A>::Tag StandardizedTag;
2913  typedef typename LookupTag<TAG, A>::reference reference;
2914  return acc_detail::CastImpl<StandardizedTag, typename A::Tag, reference>::exec(a);
2915 }
2916 
2917  // Get a reference to the accumulator TAG for region 'label' in the accumulator chain A
2918 /** Get a reference to the accumulator 'TAG' for region 'label' in the accumulator chain 'a'.
2919 */
2920 template <class TAG, class A>
2921 inline typename LookupTag<TAG, A>::reference
2923 {
2924  typedef typename LookupTag<TAG, A>::Tag StandardizedTag;
2925  typedef typename LookupTag<TAG, A>::reference reference;
2926  return acc_detail::CastImpl<StandardizedTag, typename A::Tag, reference>::exec(a, label);
2927 }
2928 
2929  // get the result of the accumulator specified by TAG
2930 /** Get the result of the accumulator 'TAG' in the accumulator chain 'a'.\n
2931 Example of use:
2932 \code
2933  vigra::MultiArray<2, double> data(...);
2934  AccumulatorChain<DataType, Select<Variance, Mean, StdDev> > a;
2935  extractFeatures(data.begin(), data.end(), a);
2936  double mean = get<Mean>(a);
2937 \endcode
2938 See \ref FeatureAccumulators for more information about feature computation via accumulators.
2939 */
2940 template <class TAG, class A>
2941 inline typename LookupTag<TAG, A>::result_type
2942 get(A const & a)
2943 {
2944  return getAccumulator<TAG>(a).get();
2945 }
2946 
2947  // get the result of the accumulator TAG for region 'label'
2948 /** Get the result of the accumulator 'TAG' for region 'label' in the accumulator chain 'a'.\n
2949 Example of use:
2950 \code
2951  vigra::MultiArray<2, double> data(...);
2952  vigra::MultiArray<2, int> labels(...);
2953  typedef vigra::CoupledIteratorType<2, double, int>::type Iterator;
2954  typedef Iterator::value_type Handle;
2955 
2956  AccumulatorChainArray<Handle,
2957  Select<DataArg<1>, LabelArg<2>, Mean, Variance> > a;
2958 
2959  Iterator start = createCoupledIterator(data, labels);
2960  Iterator end = start.getEndIterator();
2961  extractFeatures(start,end,a);
2962 
2963  double mean_of_region_1 = get<Mean>(a,1);
2964  double mean_of_background = get<Mean>(a,0);
2965 \endcode
2966 See \ref FeatureAccumulators for more information about feature computation via accumulators.
2967 */
2968 template <class TAG, class A>
2969 inline typename LookupTag<TAG, A>::result_type
2970 get(A const & a, MultiArrayIndex label)
2971 {
2972  return getAccumulator<TAG>(a, label).get();
2973 }
2974 
2975  // Get the result of the accumulator specified by TAG without checking if the accumulator is active.
2976  // This must be used within an accumulator implementation to access dependencies because
2977  // it applies the approprate modifiers to the given TAG. It must not be used in other situations.
2978  // FIXME: is there a shorter name?
2979 template <class TAG, class A>
2980 inline typename LookupDependency<TAG, A>::result_type
2981 getDependency(A const & a)
2982 {
2983  typedef typename LookupDependency<TAG, A>::Tag StandardizedTag;
2984  typedef typename LookupDependency<TAG, A>::reference reference;
2985  return acc_detail::CastImpl<StandardizedTag, typename A::Tag, reference>::exec(a)();
2986 }
2987 
2988  // activate the dynamic accumulator specified by Tag
2989 /** 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
2990 See \ref FeatureAccumulators for more information about feature computation via accumulators.
2991 */
2992 template <class Tag, class A>
2993 inline void
2994 activate(A & a)
2995 {
2996  a.template activate<Tag>();
2997 }
2998 
2999  // check if the dynamic accumulator specified by Tag is active
3000 /** 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
3001 See \ref FeatureAccumulators for more information about feature computation via accumulators.
3002 */
3003 template <class Tag, class A>
3004 inline bool
3005 isActive(A const & a)
3006 {
3007  return a.template isActive<Tag>();
3008 }
3009 
3010 /****************************************************************************/
3011 /* */
3012 /* generic loops */
3013 /* */
3014 /****************************************************************************/
3015 
3016 /** Generic loop to collect statistics from one or several arrays.
3017 
3018 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:
3019 \code
3020 namespace vigra { namespace acc {
3021 
3022  template <class ITERATOR, class ACCUMULATOR>
3023  void extractFeatures(ITERATOR start, ITERATOR end, ACCUMULATOR & a);
3024 }}
3025 \endcode
3026 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:
3027 \code
3028  AccumulatorChain<double, Select<Mean, Variance> > a;
3029 
3030  double * start = ...,
3031  * end = ...;
3032  extractFeatures(start, end, a);
3033 \endcode
3034 Similarly, you can use MultiArray's scan-order iterator:
3035 \code
3036  AccumulatorChain<TinyVector<float, 2>, Select<Mean, Variance> > a;
3037 
3038  MultiArray<3, TinyVector<float, 2> > data(...);
3039  extractFeatures(data.begin(), data.end(), a);
3040 \endcode
3041 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:
3042 \code
3043  MultiArray<3, double> data(...);
3044  MultiArray<3, int> labels(...);
3045 
3046  AccumulatorChainArray<CoupledArrays<3, double, int>,
3047  Select<DataArg<1>, LabelArg<2>, // where to look for data and region labels
3048  Mean, Variance> > // what statistics to compute
3049  a;
3050 
3051  extractFeatures(data, labels, a);
3052 \endcode
3053 This form of <tt>extractFeatures()</tt> is supported for up to five arrays (although at most three are currently making sense in practice):
3054 \code
3055 namespace vigra { namespace acc {
3056 
3057  template <unsigned int N, class T1, class S1,
3058  class ACCUMULATOR>
3059  void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
3060  ACCUMULATOR & a);
3061 
3062  ...
3063 
3064  template <unsigned int N, class T1, class S1,
3065  class T2, class S2,
3066  class T3, class S3,
3067  class T4, class S4,
3068  class T5, class S5,
3069  class ACCUMULATOR>
3070  void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
3071  MultiArrayView<N, T2, S2> const & a2,
3072  MultiArrayView<N, T3, S3> const & a3,
3073  MultiArrayView<N, T4, S4> const & a4,
3074  MultiArrayView<N, T5, S5> const & a5,
3075  ACCUMULATOR & a);
3076 }}
3077 \endcode
3078 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>.
3079 
3080 See \ref FeatureAccumulators for more information about feature computation via accumulators.
3081 */
3082 doxygen_overloaded_function(template <...> void extractFeatures)
3083 
3084 
3085 template <class ITERATOR, class ACCUMULATOR>
3086 void extractFeatures(ITERATOR start, ITERATOR end, ACCUMULATOR & a)
3087 {
3088  for(unsigned int k=1; k <= a.passesRequired(); ++k)
3089  for(ITERATOR i=start; i < end; ++i)
3090  a.updatePassN(*i, k);
3091 }
3092 
3093 template <unsigned int N, class T1, class S1,
3094  class ACCUMULATOR>
3095 void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
3096  ACCUMULATOR & a)
3097 {
3098  typedef typename CoupledIteratorType<N, T1>::type Iterator;
3099  Iterator start = createCoupledIterator(a1),
3100  end = start.getEndIterator();
3101  extractFeatures(start, end, a);
3102 }
3103 
3104 template <unsigned int N, class T1, class S1,
3105  class T2, class S2,
3106  class ACCUMULATOR>
3107 void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
3108  MultiArrayView<N, T2, S2> const & a2,
3109  ACCUMULATOR & a)
3110 {
3111  typedef typename CoupledIteratorType<N, T1, T2>::type Iterator;
3112  Iterator start = createCoupledIterator(a1, a2),
3113  end = start.getEndIterator();
3114  extractFeatures(start, end, a);
3115 }
3116 
3117 template <unsigned int N, class T1, class S1,
3118  class T2, class S2,
3119  class T3, class S3,
3120  class ACCUMULATOR>
3121 void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
3122  MultiArrayView<N, T2, S2> const & a2,
3123  MultiArrayView<N, T3, S3> const & a3,
3124  ACCUMULATOR & a)
3125 {
3126  typedef typename CoupledIteratorType<N, T1, T2, T3>::type Iterator;
3127  Iterator start = createCoupledIterator(a1, a2, a3),
3128  end = start.getEndIterator();
3129  extractFeatures(start, end, a);
3130 }
3131 
3132 template <unsigned int N, class T1, class S1,
3133  class T2, class S2,
3134  class T3, class S3,
3135  class T4, class S4,
3136  class ACCUMULATOR>
3137 void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
3138  MultiArrayView<N, T2, S2> const & a2,
3139  MultiArrayView<N, T3, S3> const & a3,
3140  MultiArrayView<N, T4, S4> const & a4,
3141  ACCUMULATOR & a)
3142 {
3143  typedef typename CoupledIteratorType<N, T1, T2, T3, T4>::type Iterator;
3144  Iterator start = createCoupledIterator(a1, a2, a3, a4),
3145  end = start.getEndIterator();
3146  extractFeatures(start, end, a);
3147 }
3148 
3149 template <unsigned int N, class T1, class S1,
3150  class T2, class S2,
3151  class T3, class S3,
3152  class T4, class S4,
3153  class T5, class S5,
3154  class ACCUMULATOR>
3155 void extractFeatures(MultiArrayView<N, T1, S1> const & a1,
3156  MultiArrayView<N, T2, S2> const & a2,
3157  MultiArrayView<N, T3, S3> const & a3,
3158  MultiArrayView<N, T4, S4> const & a4,
3159  MultiArrayView<N, T5, S5> const & a5,
3160  ACCUMULATOR & a)
3161 {
3162  typedef typename CoupledIteratorType<N, T1, T2, T3, T4, T5>::type Iterator;
3163  Iterator start = createCoupledIterator(a1, a2, a3, a4, a5),
3164  end = start.getEndIterator();
3165  extractFeatures(start, end, a);
3166 }
3167 
3168 /****************************************************************************/
3169 /* */
3170 /* AccumulatorResultTraits */
3171 /* */
3172 /****************************************************************************/
3173 
3174 template <class T>
3175 struct AccumulatorResultTraits
3176 {
3177  typedef T type;
3178  typedef T element_type;
3179  typedef double element_promote_type;
3180  typedef T MinmaxType;
3181  typedef element_promote_type SumType;
3182  typedef element_promote_type FlatCovarianceType;
3183  typedef element_promote_type CovarianceType;
3184 };
3185 
3186 template <class T, int N>
3187 struct AccumulatorResultTraits<TinyVector<T, N> >
3188 {
3189  typedef TinyVector<T, N> type;
3190  typedef T element_type;
3191  typedef double element_promote_type;
3192  typedef TinyVector<T, N> MinmaxType;
3193  typedef TinyVector<element_promote_type, N> SumType;
3194  typedef TinyVector<element_promote_type, N*(N+1)/2> FlatCovarianceType;
3195  typedef Matrix<element_promote_type> CovarianceType;
3196 };
3197 
3198 // (?) beign change
3199 template <class T, unsigned int RED_IDX, unsigned int GREEN_IDX, unsigned int BLUE_IDX>
3200 struct AccumulatorResultTraits<RGBValue<T, RED_IDX, GREEN_IDX, BLUE_IDX> >
3201 {
3202  typedef RGBValue<T> type;
3203  typedef T element_type;
3204  typedef double element_promote_type;
3205  typedef RGBValue<T> MinmaxType;
3206  typedef RGBValue<element_promote_type> SumType;
3207  typedef TinyVector<element_promote_type, 3*(3+1)/2> FlatCovarianceType;
3208  typedef Matrix<element_promote_type> CovarianceType;
3209 };
3210 // end change
3211 
3212 
3213 template <unsigned int N, class T, class Stride>
3214 struct AccumulatorResultTraits<MultiArrayView<N, T, Stride> >
3215 {
3216  typedef MultiArrayView<N, T, Stride> type;
3217  typedef T element_type;
3218  typedef double element_promote_type;
3219  typedef MultiArray<N, T> MinmaxType;
3220  typedef MultiArray<N, element_promote_type> SumType;
3221  typedef MultiArray<1, element_promote_type> FlatCovarianceType;
3222  typedef Matrix<element_promote_type> CovarianceType;
3223 };
3224 
3225 template <unsigned int N, class T, class Alloc>
3226 struct AccumulatorResultTraits<MultiArray<N, T, Alloc> >
3227 {
3228  typedef MultiArrayView<N, T, Alloc> type;
3229  typedef T element_type;
3230  typedef double element_promote_type;
3231  typedef MultiArray<N, T> MinmaxType;
3232  typedef MultiArray<N, element_promote_type> SumType;
3233  typedef MultiArray<1, element_promote_type> FlatCovarianceType;
3234  typedef Matrix<element_promote_type> CovarianceType;
3235 };
3236 
3237 /****************************************************************************/
3238 /* */
3239 /* modifier implementations */
3240 /* */
3241 /****************************************************************************/
3242 
3243 /** \brief Modifier. Compute statistic globally rather than per region.
3244 
3245 This modifier only works when labels are given (with (Dynamic)AccumulatorChainArray), in which case statistics are computed per-region by default.
3246 */
3247 template <class TAG>
3248 class Global
3249 {
3250  public:
3251  typedef typename StandardizeTag<TAG>::type TargetTag;
3252  typedef typename TargetTag::Dependencies Dependencies;
3253 
3254  static std::string name()
3255  {
3256  return std::string("Global<") + TargetTag::name() + " >";
3257  // static const std::string n = std::string("Global<") + TargetTag::name() + " >";
3258  // return n;
3259  }
3260 };
3261 
3262 /** \brief Specifies index of data in CoupledHandle.
3263 
3264  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)
3265 */
3266 template <int INDEX>
3267 class DataArg
3268 {
3269  public:
3270  typedef Select<> Dependencies;
3271 
3272  static std::string name()
3273  {
3274  return std::string("DataArg<") + asString(INDEX) + "> (internal)";
3275  // static const std::string n = std::string("DataArg<") + asString(INDEX) + "> (internal)";
3276  // return n;
3277  }
3278 
3279  template <class T, class BASE>
3280  struct Impl
3281  : public BASE
3282  {
3283  typedef DataArgTag Tag;
3284  typedef void value_type;
3285  typedef void result_type;
3286 
3287  static const int value = INDEX;
3288  static const unsigned int workInPass = 0;
3289  };
3290 };
3291 
3292 namespace acc_detail {
3293 
3294 template <class T, int DEFAULT, class TAG, class IndexDefinition,
3295  class TagFound=typename IndexDefinition::Tag>
3296 struct HandleArgSelectorImpl
3297 {
3298  static const int value = DEFAULT;
3299  typedef typename CoupledHandleCast<value, T>::type type;
3300  typedef typename CoupledHandleCast<value, T>::value_type value_type;
3301  static const int size = type::dimensions;
3302 
3303  template <class U, class NEXT>
3304  static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type const &
3305  getHandle(CoupledHandle<U, NEXT> const & t)
3306  {
3307  return vigra::cast<value>(t);
3308  }
3309 
3310  template <class U, class NEXT>
3311  static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type::const_reference
3312  getValue(CoupledHandle<U, NEXT> const & t)
3313  {
3314  return vigra::get<value>(t);
3315  }
3316 };
3317 
3318 template <class T, int DEFAULT, class TAG, class IndexDefinition>
3319 struct HandleArgSelectorImpl<T, DEFAULT, TAG, IndexDefinition, TAG>
3320 {
3321  static const int value = IndexDefinition::value;
3322  typedef typename CoupledHandleCast<value, T>::type type;
3323  typedef typename CoupledHandleCast<value, T>::value_type value_type;
3324  static const int size = type::dimensions;
3325 
3326  template <class U, class NEXT>
3327  static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type const &
3328  getHandle(CoupledHandle<U, NEXT> const & t)
3329  {
3330  return vigra::cast<value>(t);
3331  }
3332 
3333  template <class U, class NEXT>
3334  static typename CoupledHandleCast<value, CoupledHandle<U, NEXT> >::type::const_reference
3335  getValue(CoupledHandle<U, NEXT> const & t)
3336  {
3337  return vigra::get<value>(t);
3338  }
3339 };
3340 
3341 } // namespace acc_detail
3342 
3343 template <class T, class CHAIN>
3344 struct HandleArgSelector<T, LabelArgTag, CHAIN>
3345 : public acc_detail::HandleArgSelectorImpl<T, 2, LabelArgTag,
3346  typename LookupTag<LabelArgTag, CHAIN>::type>
3347 {};
3348 
3349 template <class T, class CHAIN>
3350 struct HandleArgSelector<T, DataArgTag, CHAIN>
3351 : public acc_detail::HandleArgSelectorImpl<T, 1, DataArgTag,
3352  typename LookupTag<DataArgTag, CHAIN>::type>
3353 {};
3354 
3355 template <class T, class CHAIN>
3356 struct HandleArgSelector<T, CoordArgTag, CHAIN>
3357 : public acc_detail::HandleArgSelectorImpl<T, 0, CoordArgTag,
3358  typename LookupTag<CoordArgTag, CHAIN>::type>
3359 {
3360  typedef acc_detail::HandleArgSelectorImpl<T, 0, CoordArgTag,
3361  typename LookupTag<CoordArgTag, CHAIN>::type> base_type;
3362  typedef TinyVector<double, base_type::size> value_type;
3363 };
3364 
3365 // Tags are automatically wrapped with DataFromHandle if CoupledHandle used
3366 template <class TAG>
3367 class DataFromHandle
3368 {
3369  public:
3370  typedef typename StandardizeTag<TAG>::type TargetTag;
3371  typedef typename TargetTag::Dependencies Dependencies;
3372 
3373  static std::string name()
3374  {
3375  return std::string("DataFromHandle<") + TargetTag::name() + " > (internal)";
3376  // static const std::string n = std::string("DataFromHandle<") + TargetTag::name() + " > (internal)";
3377  // return n;
3378  }
3379 
3380  template <class T, class BASE>
3381  struct Impl
3382  : public TargetTag::template Impl<typename HandleArgSelector<T, DataArgTag, BASE>::value_type, BASE>
3383  {
3384  typedef HandleArgSelector<T, DataArgTag, BASE> DataHandle;
3385  typedef typename DataHandle::value_type input_type;
3386  typedef input_type const & argument_type;
3387  typedef argument_type first_argument_type;
3388 
3389  typedef typename TargetTag::template Impl<input_type, BASE> ImplType;
3390 
3391  using ImplType::reshape;
3392 
3393  template <class U, class NEXT>
3394  void reshape(CoupledHandle<U, NEXT> const & t)
3395  {
3396  ImplType::reshape(acc_detail::shapeOf(DataHandle::getValue(t)));
3397  }
3398 
3399  template <class U, class NEXT>
3400  void update(CoupledHandle<U, NEXT> const & t)
3401  {
3402  ImplType::update(DataHandle::getValue(t));
3403  }
3404 
3405  template <class U, class NEXT>
3406  void update(CoupledHandle<U, NEXT> const & t, double weight)
3407  {
3408  ImplType::update(DataHandle::getValue(t), weight);
3409  }
3410  };
3411 };
3412 
3413 /** \brief Modifier. Compute statistic from pixel coordinates rather than from pixel values.
3414 
3415  AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
3416  */
3417 template <class TAG>
3418 class Coord
3419 {
3420  public:
3421  typedef typename StandardizeTag<TAG>::type TargetTag;
3422  typedef typename TargetTag::Dependencies Dependencies;
3423 
3424  static std::string name()
3425  {
3426  return std::string("Coord<") + TargetTag::name() + " >";
3427  // static const std::string n = std::string("Coord<") + TargetTag::name() + " >";
3428  // return n;
3429  }
3430 
3431  template <class T, class BASE>
3432  struct Impl
3433  : public TargetTag::template Impl<typename HandleArgSelector<T, CoordArgTag, BASE>::value_type, BASE>
3434  {
3435  typedef HandleArgSelector<T, CoordArgTag, BASE> CoordHandle;
3436  typedef typename CoordHandle::value_type input_type;
3437  typedef input_type const & argument_type;
3438  typedef argument_type first_argument_type;
3439 
3440  typedef typename TargetTag::template Impl<input_type, BASE> ImplType;
3441 
3442  input_type offset_;
3443 
3444  Impl()
3445  : offset_()
3446  {}
3447 
3448  void setCoordinateOffset(input_type const & offset)
3449  {
3450  offset_ = offset;
3451  }
3452 
3453  using ImplType::reshape;
3454 
3455  template <class U, class NEXT>
3456  void reshape(CoupledHandle<U, NEXT> const & t)
3457  {
3458  ImplType::reshape(acc_detail::shapeOf(CoordHandle::getValue(t)));
3459  }
3460 
3461  template <class U, class NEXT>
3462  void update(CoupledHandle<U, NEXT> const & t)
3463  {
3464  ImplType::update(CoordHandle::getValue(t)+offset_);
3465  }
3466 
3467  template <class U, class NEXT>
3468  void update(CoupledHandle<U, NEXT> const & t, double weight)
3469  {
3470  ImplType::update(CoordHandle::getValue(t)+offset_, weight);
3471  }
3472  };
3473 };
3474 
3475 /** \brief Specifies index of data in CoupledHandle.
3476 
3477  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.)
3478 */
3479 template <int INDEX>
3480 class WeightArg
3481 {
3482  public:
3483  typedef Select<> Dependencies;
3484 
3485  static std::string name()
3486  {
3487  return std::string("WeightArg<") + asString(INDEX) + "> (internal)";
3488  // static const std::string n = std::string("WeightArg<") + asString(INDEX) + "> (internal)";
3489  // return n;
3490  }
3491 
3492  template <class T, class BASE>
3493  struct Impl
3494  : public BASE
3495  {
3496  typedef WeightArgTag Tag;
3497  typedef void value_type;
3498  typedef void result_type;
3499 
3500  static const int value = INDEX;
3501  static const unsigned int workInPass = 0;
3502  };
3503 };
3504 
3505 /** \brief Compute weighted version of the statistic.
3506 */
3507 template <class TAG>
3508 class Weighted
3509 {
3510  public:
3511  typedef typename StandardizeTag<TAG>::type TargetTag;
3512  typedef typename TargetTag::Dependencies Dependencies;
3513 
3514  static std::string name()
3515  {
3516  return std::string("Weighted<") + TargetTag::name() + " >";
3517  // static const std::string n = std::string("Weighted<") + TargetTag::name() + " >";
3518  // return n;
3519  }
3520 
3521  template <class IndexDefinition, class TagFound=typename IndexDefinition::Tag>
3522  struct WeightIndexSelector
3523  {
3524  template <class U, class NEXT>
3525  static double exec(CoupledHandle<U, NEXT> const & t)
3526  {
3527  return (double)*t; // default: CoupledHandle holds weights at the last (outermost) index
3528  }
3529  };
3530 
3531  template <class IndexDefinition>
3532  struct WeightIndexSelector<IndexDefinition, WeightArgTag>
3533  {
3534  template <class U, class NEXT>
3535  static double exec(CoupledHandle<U, NEXT> const & t)
3536  {
3537  return (double)get<IndexDefinition::value>(t);
3538  }
3539  };
3540 
3541  template <class T, class BASE>
3542  struct Impl
3543  : public TargetTag::template Impl<T, BASE>
3544  {
3545  typedef typename TargetTag::template Impl<T, BASE> ImplType;
3546 
3547  typedef typename LookupTag<WeightArgTag, BASE>::type FindWeightIndex;
3548 
3549  template <class U, class NEXT>
3550  void update(CoupledHandle<U, NEXT> const & t)
3551  {
3552  ImplType::update(t, WeightIndexSelector<FindWeightIndex>::exec(t));
3553  }
3554  };
3555 };
3556 
3557 // Centralize by subtracting the mean and cache the result
3558 class Centralize
3559 {
3560  public:
3561  typedef Select<Mean> Dependencies;
3562 
3563  static std::string name()
3564  {
3565  return "Centralize (internal)";
3566  // static const std::string n("Centralize (internal)");
3567  // return n;
3568  }
3569 
3570  template <class U, class BASE>
3571  struct Impl
3572  : public BASE
3573  {
3574  static const unsigned int workInPass = 2;
3575 
3576  typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
3577  typedef typename AccumulatorResultTraits<U>::SumType value_type;
3578  typedef value_type const & result_type;
3579 
3580  mutable value_type value_;
3581 
3582  Impl()
3583  : value_() // call default constructor explicitly to ensure zero initialization
3584  {}
3585 
3586  void reset()
3587  {
3588  value_ = element_type();
3589  }
3590 
3591  template <class Shape>
3592  void reshape(Shape const & s)
3593  {
3594  acc_detail::reshapeImpl(value_, s);
3595  }
3596 
3597  void update(U const & t) const
3598  {
3599  using namespace vigra::multi_math;
3600  value_ = t - getDependency<Mean>(*this);
3601  }
3602 
3603  void update(U const & t, double) const
3604  {
3605  update(t);
3606  }
3607 
3608  result_type operator()(U const & t) const
3609  {
3610  update(t);
3611  return value_;
3612  }
3613 
3614  result_type operator()() const
3615  {
3616  return value_;
3617  }
3618  };
3619 };
3620 
3621 /** \brief Modifier. Substract mean before computing statistic.
3622 
3623 Works in pass 2, %operator+=() not supported (merging not supported).
3624 */
3625 template <class TAG>
3626 class Central
3627 {
3628  public:
3629  typedef typename StandardizeTag<TAG>::type TargetTag;
3630  typedef Select<Centralize, typename TargetTag::Dependencies> Dependencies;
3631 
3632  static std::string name()
3633  {
3634  return std::string("Central<") + TargetTag::name() + " >";
3635  // static const std::string n = std::string("Central<") + TargetTag::name() + " >";
3636  // return n;
3637  }
3638 
3639  template <class U, class BASE>
3640  struct Impl
3641  : public TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE>
3642  {
3643  typedef typename TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE> ImplType;
3644 
3645  static const unsigned int workInPass = 2;
3646 
3647  void operator+=(Impl const &)
3648  {
3649  vigra_precondition(false,
3650  "Central<...>::operator+=(): not supported.");
3651  }
3652 
3653  template <class T>
3654  void update(T const &)
3655  {
3656  ImplType::update(getDependency<Centralize>(*this));
3657  }
3658 
3659  template <class T>
3660  void update(T const &, double weight)
3661  {
3662  ImplType::update(getDependency<Centralize>(*this), weight);
3663  }
3664  };
3665 };
3666 
3667  // alternative implementation without caching
3668  //
3669 // template <class TAG>
3670 // class Central
3671 // {
3672  // public:
3673  // typedef typename StandardizeTag<TAG>::type TargetTag;
3674  // typedef TypeList<Mean, typename TransferModifiers<Central<TargetTag>, typename TargetTag::Dependencies::type>::type> Dependencies;
3675 
3676  // template <class U, class BASE>
3677  // struct Impl
3678  // : public TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE>
3679  // {
3680  // typedef typename TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE> ImplType;
3681 
3682  // static const unsigned int workInPass = 2;
3683 
3684  // void operator+=(Impl const & o)
3685  // {
3686  // vigra_precondition(false,
3687  // "Central<...>::operator+=(): not supported.");
3688  // }
3689 
3690  // template <class T>
3691  // void update(T const & t)
3692  // {
3693  // ImplType::update(t - getDependency<Mean>(*this));
3694  // }
3695 
3696  // template <class T>
3697  // void update(T const & t, double weight)
3698  // {
3699  // ImplType::update(t - getDependency<Mean>(*this), weight);
3700  // }
3701  // };
3702 // };
3703 
3704 
3705 class PrincipalProjection
3706 {
3707  public:
3708  typedef Select<Centralize, Principal<CoordinateSystem> > Dependencies;
3709 
3710  static std::string name()
3711  {
3712  return "PrincipalProjection (internal)";
3713  // static const std::string n("PrincipalProjection (internal)");
3714  // return n;
3715  }
3716 
3717  template <class U, class BASE>
3718  struct Impl
3719  : public BASE
3720  {
3721  static const unsigned int workInPass = 2;
3722 
3723  typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
3724  typedef typename AccumulatorResultTraits<U>::SumType value_type;
3725  typedef value_type const & result_type;
3726 
3727  mutable value_type value_;
3728 
3729  Impl()
3730  : value_() // call default constructor explicitly to ensure zero initialization
3731  {}
3732 
3733  void reset()
3734  {
3735  value_ = element_type();
3736  }
3737 
3738  template <class Shape>
3739  void reshape(Shape const & s)
3740  {
3741  acc_detail::reshapeImpl(value_, s);
3742  }
3743 
3744  void update(U const & t) const
3745  {
3746  for(unsigned int k=0; k<t.size(); ++k)
3747  {
3748  value_[k] = getDependency<Principal<CoordinateSystem> >(*this)(0, k)*getDependency<Centralize>(*this)[0];
3749  for(unsigned int d=1; d<t.size(); ++d)
3750  value_[k] += getDependency<Principal<CoordinateSystem> >(*this)(d, k)*getDependency<Centralize>(*this)[d];
3751  }
3752  }
3753 
3754  void update(U const & t, double) const
3755  {
3756  update(t);
3757  }
3758 
3759  result_type operator()(U const & t) const
3760  {
3761  getAccumulator<Centralize>(*this).update(t);
3762  update(t);
3763  return value_;
3764  }
3765 
3766  result_type operator()() const
3767  {
3768  return value_;
3769  }
3770  };
3771 };
3772 
3773 /** \brief Modifier. Project onto PCA eigenvectors.
3774 
3775  Works in pass 2, %operator+=() not supported (merging not supported).
3776 */
3777 template <class TAG>
3778 class Principal
3779 {
3780  public:
3781  typedef typename StandardizeTag<TAG>::type TargetTag;
3782  typedef Select<PrincipalProjection, typename TargetTag::Dependencies> Dependencies;
3783 
3784  static std::string name()
3785  {
3786  return std::string("Principal<") + TargetTag::name() + " >";
3787  // static const std::string n = std::string("Principal<") + TargetTag::name() + " >";
3788  // return n;
3789  }
3790 
3791  template <class U, class BASE>
3792  struct Impl
3793  : public TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE>
3794  {
3795  typedef typename TargetTag::template Impl<typename AccumulatorResultTraits<U>::SumType, BASE> ImplType;
3796 
3797  static const unsigned int workInPass = 2;
3798 
3799  void operator+=(Impl const &)
3800  {
3801  vigra_precondition(false,
3802  "Principal<...>::operator+=(): not supported.");
3803  }
3804 
3805  template <class T>
3806  void update(T const &)
3807  {
3808  ImplType::update(getDependency<PrincipalProjection>(*this));
3809  }
3810 
3811  template <class T>
3812  void update(T const &, double weight)
3813  {
3814  ImplType::update(getDependency<PrincipalProjection>(*this), weight);
3815  }
3816  };
3817 };
3818 
3819 /*
3820 important notes on modifiers:
3821  * upon accumulator creation, modifiers are reordered so that data preparation is innermost,
3822  and data access is outermost, e.g.:
3823  Coord<DivideByCount<Principal<PowerSum<2> > > >
3824  * modifiers are automatically transfered to dependencies as appropriate
3825  * modifiers for lookup (getAccumulator and get) of dependent accumulators are automatically adjusted
3826  * modifiers must adjust workInPass for the contained accumulator as appropriate
3827  * we may implement convenience versions of Select that apply a modifier to all
3828  contained tags at once
3829  * weighted accumulators have their own Count object when used together
3830  with unweighted ones (this is as yet untested - FIXME)
3831  * certain accumulators must remain unchanged when wrapped in certain modifiers:
3832  * Count: always except for Weighted<Count> and CoordWeighted<Count>
3833  * Sum: data preparation modifiers
3834  * FlatScatterMatrixImpl, CovarianceEigensystemImpl: Principal and Whitened
3835  * will it be useful to implement initPass<N>() or finalizePass<N>() ?
3836 */
3837 
3838 /****************************************************************************/
3839 /* */
3840 /* the actual accumulators */
3841 /* */
3842 /****************************************************************************/
3843 
3844 /** \brief Basic statistic. Identity matrix of appropriate size.
3845 */
3847 {
3848  public:
3849  typedef Select<> Dependencies;
3850 
3851  static std::string name()
3852  {
3853  return "CoordinateSystem";
3854  // static const std::string n("CoordinateSystem");
3855  // return n;
3856  }
3857 
3858  template <class U, class BASE>
3859  struct Impl
3860  : public BASE
3861  {
3862  typedef double element_type;
3863  typedef Matrix<double> value_type;
3864  typedef value_type const & result_type;
3865 
3866  value_type value_;
3867 
3868  Impl()
3869  : value_() // call default constructor explicitly to ensure zero initialization
3870  {}
3871 
3872  void reset()
3873  {
3874  value_ = element_type();
3875  }
3876 
3877  template <class Shape>
3878  void reshape(Shape const & s)
3879  {
3880  acc_detail::reshapeImpl(value_, s);
3881  }
3882 
3883  result_type operator()() const
3884  {
3885  return value_;
3886  }
3887  };
3888 };
3889 
3890 template <class BASE, class T,
3891  class ElementType=typename AccumulatorResultTraits<T>::element_promote_type,
3892  class SumType=typename AccumulatorResultTraits<T>::SumType>
3893 struct SumBaseImpl
3894 : public BASE
3895 {
3896  typedef ElementType element_type;
3897  typedef SumType value_type;
3898  typedef value_type const & result_type;
3899 
3900  value_type value_;
3901 
3902  SumBaseImpl()
3903  : value_() // call default constructor explicitly to ensure zero initialization
3904  {}
3905 
3906  void reset()
3907  {
3908  value_ = element_type();
3909  }
3910 
3911  template <class Shape>
3912  void reshape(Shape const & s)
3913  {
3914  acc_detail::reshapeImpl(value_, s);
3915  }
3916 
3917  void operator+=(SumBaseImpl const & o)
3918  {
3919  value_ += o.value_;
3920  }
3921 
3922  result_type operator()() const
3923  {
3924  return value_;
3925  }
3926 };
3927 
3928 // Count
3929 template <>
3930 class PowerSum<0>
3931 {
3932  public:
3933  typedef Select<> Dependencies;
3934 
3935  static std::string name()
3936  {
3937  return "PowerSum<0>";
3938  // static const std::string n("PowerSum<0>");
3939  // return n;
3940  }
3941 
3942  template <class T, class BASE>
3943  struct Impl
3944  : public SumBaseImpl<BASE, T, double, double>
3945  {
3946  void update(T const &)
3947  {
3948  ++this->value_;
3949  }
3950 
3951  void update(T const &, double weight)
3952  {
3953  this->value_ += weight;
3954  }
3955  };
3956 };
3957 
3958 // Sum
3959 template <>
3960 class PowerSum<1>
3961 {
3962  public:
3963  typedef Select<> Dependencies;
3964 
3965  static std::string name()
3966  {
3967  return "PowerSum<1>";
3968  // static const std::string n("PowerSum<1>");
3969  // return n;
3970  }
3971 
3972  template <class U, class BASE>
3973  struct Impl
3974  : public SumBaseImpl<BASE, U>
3975  {
3976  void update(U const & t)
3977  {
3978  this->value_ += t;
3979  }
3980 
3981  void update(U const & t, double weight)
3982  {
3983  using namespace multi_math;
3984 
3985  this->value_ += weight*t;
3986  }
3987  };
3988 };
3989 
3990 /** \brief Basic statistic. PowerSum<N> =@f$ \sum_i x_i^N @f$
3991 
3992  Works in pass 1, %operator+=() supported (merging supported).
3993 */
3994 template <unsigned N>
3995 class PowerSum
3996 {
3997  public:
3998  typedef Select<> Dependencies;
3999 
4000  static std::string name()
4001  {
4002  return std::string("PowerSum<") + asString(N) + ">";
4003  // static const std::string n = std::string("PowerSum<") + asString(N) + ">";
4004  // return n;
4005  }
4006 
4007  template <class U, class BASE>
4008  struct Impl
4009  : public SumBaseImpl<BASE, U>
4010  {
4011  void update(U const & t)
4012  {
4013  using namespace vigra::multi_math;
4014  this->value_ += pow(t, (int)N);
4015  }
4016 
4017  void update(U const & t, double weight)
4018  {
4019  using namespace vigra::multi_math;
4020  this->value_ += weight*pow(t, (int)N);
4021  }
4022  };
4023 };
4024 
4025 template <>
4026 class AbsPowerSum<1>
4027 {
4028  public:
4029  typedef Select<> Dependencies;
4030 
4031  static std::string name()
4032  {
4033  return "AbsPowerSum<1>";
4034  // static const std::string n("AbsPowerSum<1>");
4035  // return n;
4036  }
4037 
4038  template <class U, class BASE>
4039  struct Impl
4040  : public SumBaseImpl<BASE, U>
4041  {
4042  void update(U const & t)
4043  {
4044  using namespace vigra::multi_math;
4045  this->value_ += abs(t);
4046  }
4047 
4048  void update(U const & t, double weight)
4049  {
4050  using namespace vigra::multi_math;
4051  this->value_ += weight*abs(t);
4052  }
4053  };
4054 };
4055 
4056 /** \brief Basic statistic. AbsPowerSum<N> =@f$ \sum_i |x_i|^N @f$
4057 
4058  Works in pass 1, %operator+=() supported (merging supported).
4059 */
4060 template <unsigned N>
4061 class AbsPowerSum
4062 {
4063  public:
4064  typedef Select<> Dependencies;
4065 
4066  static std::string name()
4067  {
4068  return std::string("AbsPowerSum<") + asString(N) + ">";
4069  // static const std::string n = std::string("AbsPowerSum<") + asString(N) + ">";
4070  // return n;
4071  }
4072 
4073  template <class U, class BASE>
4074  struct Impl
4075  : public SumBaseImpl<BASE, U>
4076  {
4077  void update(U const & t)
4078  {
4079  using namespace vigra::multi_math;
4080  this->value_ += pow(abs(t), (int)N);
4081  }
4082 
4083  void update(U const & t, double weight)
4084  {
4085  using namespace vigra::multi_math;
4086  this->value_ += weight*pow(abs(t), (int)N);
4087  }
4088  };
4089 };
4090 
4091 template <class BASE, class VALUE_TYPE, class U>
4092 struct CachedResultBase
4093 : public BASE
4094 {
4095  typedef typename AccumulatorResultTraits<U>::element_type element_type;
4096  typedef VALUE_TYPE value_type;
4097  typedef value_type const & result_type;
4098 
4099  mutable value_type value_;
4100 
4101  CachedResultBase()
4102  : value_() // call default constructor explicitly to ensure zero initialization
4103  {}
4104 
4105  void reset()
4106  {
4107  value_ = element_type();
4108  this->setClean();
4109  }
4110 
4111  template <class Shape>
4112  void reshape(Shape const & s)
4113  {
4114  acc_detail::reshapeImpl(value_, s);
4115  }
4116 
4117  void operator+=(CachedResultBase const &)
4118  {
4119  this->setDirty();
4120  }
4121 
4122  void update(U const &)
4123  {
4124  this->setDirty();
4125  }
4126 
4127  void update(U const &, double)
4128  {
4129  this->setDirty();
4130  }
4131 };
4132 
4133 // cached Mean and Variance
4134 /** \brief Modifier. Divide statistic by Count: DivideByCount<TAG> = TAG / Count .
4135 */
4136 template <class TAG>
4137 class DivideByCount
4138 {
4139  public:
4140  typedef typename StandardizeTag<TAG>::type TargetTag;
4141  typedef Select<TargetTag, Count> Dependencies;
4142 
4143  static std::string name()
4144  {
4145  return std::string("DivideByCount<") + TargetTag::name() + " >";
4146  // static const std::string n = std::string("DivideByCount<") + TargetTag::name() + " >";
4147  // return n;
4148  }
4149 
4150  template <class U, class BASE>
4151  struct Impl
4152  : public CachedResultBase<BASE, typename LookupDependency<TargetTag, BASE>::value_type, U>
4153  {
4154  typedef typename CachedResultBase<BASE, typename LookupDependency<TargetTag, BASE>::value_type, U>::result_type result_type;
4155 
4156  result_type operator()() const
4157  {
4158  if(this->isDirty())
4159  {
4160  using namespace multi_math;
4161  this->value_ = getDependency<TargetTag>(*this) / getDependency<Count>(*this);
4162  this->setClean();
4163  }
4164  return this->value_;
4165  }
4166  };
4167 };
4168 
4169 // UnbiasedVariance
4170 /** \brief Modifier. Divide statistics by Count-1: DivideUnbiased<TAG> = TAG / (Count-1)
4171 */
4172 template <class TAG>
4173 class DivideUnbiased
4174 {
4175  public:
4176  typedef typename StandardizeTag<TAG>::type TargetTag;
4177  typedef Select<TargetTag, Count> Dependencies;
4178 
4179  static std::string name()
4180  {
4181  return std::string("DivideUnbiased<") + TargetTag::name() + " >";
4182  // static const std::string n = std::string("DivideUnbiased<") + TargetTag::name() + " >";
4183  // return n;
4184  }
4185 
4186  template <class U, class BASE>
4187  struct Impl
4188  : public BASE
4189  {
4190  typedef typename LookupDependency<TargetTag, BASE>::value_type value_type;
4191  typedef value_type result_type;
4192 
4193  result_type operator()() const
4194  {
4195  using namespace multi_math;
4196  return getDependency<TargetTag>(*this) / (getDependency<Count>(*this) - 1.0);
4197  }
4198  };
4199 };
4200 
4201 // RootMeanSquares and StdDev
4202 /** \brief Modifier. RootDivideByCount<TAG> = sqrt( TAG/Count )
4203 */
4204 template <class TAG>
4205 class RootDivideByCount
4206 {
4207  public:
4208  typedef typename StandardizeTag<DivideByCount<TAG> >::type TargetTag;
4209  typedef Select<TargetTag> Dependencies;
4210 
4211  static std::string name()
4212  {
4213  typedef typename StandardizeTag<TAG>::type InnerTag;
4214  return std::string("RootDivideByCount<") + InnerTag::name() + " >";
4215  // static const std::string n = std::string("RootDivideByCount<") + InnerTag::name() + " >";
4216  // return n;
4217  }
4218 
4219  template <class U, class BASE>
4220  struct Impl
4221  : public BASE
4222  {
4223  typedef typename LookupDependency<TargetTag, BASE>::value_type value_type;
4224  typedef value_type result_type;
4225 
4226  result_type operator()() const
4227  {
4228  using namespace multi_math;
4229  return sqrt(getDependency<TargetTag>(*this));
4230  }
4231  };
4232 };
4233 
4234 // UnbiasedStdDev
4235 /** \brief Modifier. RootDivideUnbiased<TAG> = sqrt( TAG / (Count-1) )
4236 */
4237 template <class TAG>
4238 class RootDivideUnbiased
4239 {
4240  public:
4241  typedef typename StandardizeTag<DivideUnbiased<TAG> >::type TargetTag;
4242  typedef Select<TargetTag> Dependencies;
4243 
4244  static std::string name()
4245  {
4246  typedef typename StandardizeTag<TAG>::type InnerTag;
4247  return std::string("RootDivideUnbiased<") + InnerTag::name() + " >";
4248  // static const std::string n = std::string("RootDivideUnbiased<") + InnerTag::name() + " >";
4249  // return n;
4250  }
4251 
4252  template <class U, class BASE>
4253  struct Impl
4254  : public BASE
4255  {
4256  typedef typename LookupDependency<TargetTag, BASE>::value_type value_type;
4257  typedef value_type result_type;
4258 
4259  result_type operator()() const
4260  {
4261  using namespace multi_math;
4262  return sqrt(getDependency<TargetTag>(*this));
4263  }
4264  };
4265 };
4266 
4267 /** \brief Spezialization: works in pass 1, %operator+=() supported (merging supported).
4268 */
4269 template <>
4270 class Central<PowerSum<2> >
4271 {
4272  public:
4274 
4275  static std::string name()
4276  {
4277  return "Central<PowerSum<2> >";
4278  // static const std::string n("Central<PowerSum<2> >");
4279  // return n;
4280  }
4281 
4282  template <class U, class BASE>
4283  struct Impl
4284  : public SumBaseImpl<BASE, U>
4285  {
4286  void operator+=(Impl const & o)
4287  {
4288  using namespace vigra::multi_math;
4289  double n1 = getDependency<Count>(*this), n2 = getDependency<Count>(o);
4290  if(n1 == 0.0)
4291  {
4292  this->value_ = o.value_;
4293  }
4294  else if(n2 != 0.0)
4295  {
4296  this->value_ += o.value_ + n1 * n2 / (n1 + n2) * sq(getDependency<Mean>(*this) - getDependency<Mean>(o));
4297  }
4298  }
4299 
4300  void update(U const & t)
4301  {
4302  double n = getDependency<Count>(*this);
4303  if(n > 1.0)
4304  {
4305  using namespace vigra::multi_math;
4306  this->value_ += n / (n - 1.0) * sq(getDependency<Mean>(*this) - t);
4307  }
4308  }
4309 
4310  void update(U const & t, double weight)
4311  {
4312  double n = getDependency<Count>(*this);
4313  if(n > weight)
4314  {
4315  using namespace vigra::multi_math;
4316  this->value_ += n / (n - weight) * sq(getDependency<Mean>(*this) - t);
4317  }
4318  }
4319  };
4320 };
4321 
4322 /** \brief Specialization: works in pass 2, %operator+=() supported (merging supported).
4323 */
4324 template <>
4325 class Central<PowerSum<3> >
4326 {
4327  public:
4329 
4330  static std::string name()
4331  {
4332  return "Central<PowerSum<3> >";
4333  // static const std::string n("Central<PowerSum<3> >");
4334  // return n;
4335  }
4336 
4337  template <class U, class BASE>
4338  struct Impl
4339  : public SumBaseImpl<BASE, U>
4340  {
4341  typedef typename SumBaseImpl<BASE, U>::value_type value_type;
4342 
4343  static const unsigned int workInPass = 2;
4344 
4345  void operator+=(Impl const & o)
4346  {
4347  typedef Central<PowerSum<2> > Sum2Tag;
4348 
4349  using namespace vigra::multi_math;
4350  double n1 = getDependency<Count>(*this), n2 = getDependency<Count>(o);
4351  if(n1 == 0.0)
4352  {
4353  this->value_ = o.value_;
4354  }
4355  else if(n2 != 0.0)
4356  {
4357  double n = n1 + n2;
4358  double weight = n1 * n2 * (n1 - n2) / sq(n);
4359  value_type delta = getDependency<Mean>(o) - getDependency<Mean>(*this);
4360  this->value_ += o.value_ + weight * pow(delta, 3) +
4361  3.0 / n * delta * (n1 * getDependency<Sum2Tag>(o) - n2 * getDependency<Sum2Tag>(*this));
4362  }
4363  }
4364 
4365  void update(U const &)
4366  {
4367  using namespace vigra::multi_math;
4368  this->value_ += pow(getDependency<Centralize>(*this), 3);
4369  }
4370 
4371  void update(U const &, double weight)
4372  {
4373  using namespace vigra::multi_math;
4374  this->value_ += weight*pow(getDependency<Centralize>(*this), 3);
4375  }
4376  };
4377 };
4378 /** \brief Specialization: works in pass 2, %operator+=() supported (merging supported).
4379 */
4380 template <>
4381 class Central<PowerSum<4> >
4382 {
4383  public:
4385 
4386  static std::string name()
4387  {
4388  return "Central<PowerSum<4> >";
4389  // static const std::string n("Central<PowerSum<4> >");
4390  // return n;
4391  }
4392 
4393  template <class U, class BASE>
4394  struct Impl
4395  : public SumBaseImpl<BASE, U>
4396  {
4397  typedef typename SumBaseImpl<BASE, U>::value_type value_type;
4398 
4399  static const unsigned int workInPass = 2;
4400 
4401  void operator+=(Impl const & o)
4402  {
4403  typedef Central<PowerSum<2> > Sum2Tag;
4404  typedef Central<PowerSum<3> > Sum3Tag;
4405 
4406  using namespace vigra::multi_math;
4407  double n1 = getDependency<Count>(*this), n2 = getDependency<Count>(o);
4408  if(n1 == 0.0)
4409  {
4410  this->value_ = o.value_;
4411  }
4412  else if(n2 != 0.0)
4413  {
4414  double n = n1 + n2;
4415  double n1_2 = sq(n1);
4416  double n2_2 = sq(n2);
4417  double n_2 = sq(n);
4418  double weight = n1 * n2 * (n1_2 - n1*n2 + n2_2) / n_2 / n;
4419  value_type delta = getDependency<Mean>(o) - getDependency<Mean>(*this);
4420  this->value_ += o.value_ + weight * pow(delta, 4) +
4421  6.0 / n_2 * sq(delta) * (n1_2 * getDependency<Sum2Tag>(o) + n2_2 * getDependency<Sum2Tag>(*this)) +
4422  4.0 / n * delta * (n1 * getDependency<Sum3Tag>(o) - n2 * getDependency<Sum3Tag>(*this));
4423  }
4424  }
4425 
4426  void update(U const &)
4427  {
4428  using namespace vigra::multi_math;
4429  this->value_ += pow(getDependency<Centralize>(*this), 4);
4430  }
4431 
4432  void update(U const &, double weight)
4433  {
4434  using namespace vigra::multi_math;
4435  this->value_ += weight*pow(getDependency<Centralize>(*this), 4);
4436  }
4437  };
4438 };
4439 
4440 /** \brief Basic statistic. Skewness.
4441 
4442  %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$ .
4443  Works in pass 2, %operator+=() supported (merging supported).
4444 */
4446 {
4447  public:
4449 
4450  static std::string name()
4451  {
4452  return "Skewness";
4453  // static const std::string n("Skewness");
4454  // return n;
4455  }
4456 
4457  template <class U, class BASE>
4458  struct Impl
4459  : public BASE
4460  {
4461  static const unsigned int workInPass = 2;
4462 
4463  typedef typename LookupDependency<Central<PowerSum<3> >, BASE>::value_type value_type;
4464  typedef value_type result_type;
4465 
4466  result_type operator()() const
4467  {
4468  typedef Central<PowerSum<3> > Sum3;
4469  typedef Central<PowerSum<2> > Sum2;
4470 
4471  using namespace multi_math;
4472  return sqrt(getDependency<Count>(*this)) * getDependency<Sum3>(*this) / pow(getDependency<Sum2>(*this), 1.5);
4473  }
4474  };
4475 };
4476 
4477 /** \brief Basic statistic. Unbiased Skewness.
4478 
4479  Works in pass 2, %operator+=() supported (merging supported).
4480 */
4482 {
4483  public:
4485 
4486  static std::string name()
4487  {
4488  return "UnbiasedSkewness";
4489  // static const std::string n("UnbiasedSkewness");
4490  // return n;
4491  }
4492 
4493  template <class U, class BASE>
4494  struct Impl
4495  : public BASE
4496  {
4497  static const unsigned int workInPass = 2;
4498 
4499  typedef typename LookupDependency<Central<PowerSum<3> >, BASE>::value_type value_type;
4500  typedef value_type result_type;
4501 
4502  result_type operator()() const
4503  {
4504  using namespace multi_math;
4505  double n = getDependency<Count>(*this);
4506  return sqrt(n*(n-1.0)) / (n - 2.0) * getDependency<Skewness>(*this);
4507  }
4508  };
4509 };
4510 
4511 /** \brief Basic statistic. Kurtosis.
4512 
4513  %Kurtosis = @f$ \frac{ \frac{1}{n}\sum_i (x_i-\bar{x})^4 }{
4514  (\frac{1}{n} \sum_i(x_i-\bar{x})^2)^2 } - 3 @f$ .
4515  Works in pass 2, %operator+=() supported (merging supported).
4516 */
4518 {
4519  public:
4521 
4522  static std::string name()
4523  {
4524  return "Kurtosis";
4525  // static const std::string n("Kurtosis");
4526  // return n;
4527  }
4528 
4529  template <class U, class BASE>
4530  struct Impl
4531  : public BASE
4532  {
4533  static const unsigned int workInPass = 2;
4534 
4535  typedef typename LookupDependency<Central<PowerSum<4> >, BASE>::value_type value_type;
4536  typedef value_type result_type;
4537 
4538  result_type operator()() const
4539  {
4540  typedef Central<PowerSum<4> > Sum4;
4541  typedef Central<PowerSum<2> > Sum2;
4542 
4543  using namespace multi_math;
4544  return getDependency<Count>(*this) * getDependency<Sum4>(*this) / sq(getDependency<Sum2>(*this)) - 3.0;
4545  }
4546  };
4547 };
4548 
4549 /** \brief Basic statistic. Unbiased Kurtosis.
4550 
4551  Works in pass 2, %operator+=() supported (merging supported).
4552 */
4554 {
4555  public:
4557 
4558  static std::string name()
4559  {
4560  return "UnbiasedKurtosis";
4561  // static const std::string n("UnbiasedKurtosis");
4562  // return n;
4563  }
4564 
4565  template <class U, class BASE>
4566  struct Impl
4567  : public BASE
4568  {
4569  static const unsigned int workInPass = 2;
4570 
4571  typedef typename LookupDependency<Central<PowerSum<4> >, BASE>::value_type value_type;
4572  typedef value_type result_type;
4573 
4574  result_type operator()() const
4575  {
4576  using namespace multi_math;
4577  double n = getDependency<Count>(*this);
4578  return (n-1.0)/((n-2.0)*(n-3.0))*((n+1.0)*getDependency<Kurtosis>(*this) + value_type(6.0));
4579  }
4580  };
4581 };
4582 
4583 namespace acc_detail {
4584 
4585 template <class Scatter, class Sum>
4586 void updateFlatScatterMatrix(Scatter & sc, Sum const & s, double w)
4587 {
4588  int size = s.size();
4589  for(MultiArrayIndex j=0, k=0; j<size; ++j)
4590  for(MultiArrayIndex i=j; i<size; ++i, ++k)
4591  sc[k] += w*s[i]*s[j];
4592 }
4593 
4594 template <class Sum>
4595 void updateFlatScatterMatrix(double & sc, Sum const & s, double w)
4596 {
4597  sc += w*s*s;
4598 }
4599 
4600 template <class Cov, class Scatter>
4601 void flatScatterMatrixToScatterMatrix(Cov & cov, Scatter const & sc)
4602 {
4603  int size = cov.shape(0), k=0;
4604  for(MultiArrayIndex j=0; j<size; ++j)
4605  {
4606  cov(j,j) = sc[k++];
4607  for(MultiArrayIndex i=j+1; i<size; ++i)
4608  {
4609  cov(i,j) = sc[k++];
4610  cov(j,i) = cov(i,j);
4611  }
4612  }
4613 }
4614 
4615 template <class Scatter>
4616 void flatScatterMatrixToScatterMatrix(double & cov, Scatter const & sc)
4617 {
4618  cov = sc;
4619 }
4620 
4621 template <class Cov, class Scatter>
4622 void flatScatterMatrixToCovariance(Cov & cov, Scatter const & sc, double n)
4623 {
4624  int size = cov.shape(0), k=0;
4625  for(MultiArrayIndex j=0; j<size; ++j)
4626  {
4627  cov(j,j) = sc[k++] / n;
4628  for(MultiArrayIndex i=j+1; i<size; ++i)
4629  {
4630  cov(i,j) = sc[k++] / n;
4631  cov(j,i) = cov(i,j);
4632  }
4633  }
4634 }
4635 
4636 template <class Scatter>
4637 void flatScatterMatrixToCovariance(double & cov, Scatter const & sc, double n)
4638 {
4639  cov = sc / n;
4640 }
4641 
4642 } // namespace acc_detail
4643 
4644 // we only store the flattened upper triangular part of the scatter matrix
4645 /** \brief Basic statistic. Flattened uppter-triangular part of scatter matrix.
4646 
4647  Works in pass 1, %operator+=() supported (merging supported).
4648 */
4650 {
4651  public:
4653 
4654  static std::string name()
4655  {
4656  return "FlatScatterMatrix";
4657  // static const std::string n("FlatScatterMatrix");
4658  // return n;
4659  }
4660 
4661  template <class U, class BASE>
4662  struct Impl
4663  : public BASE
4664  {
4665  typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
4666  typedef typename AccumulatorResultTraits<U>::FlatCovarianceType value_type;
4667  typedef value_type const & result_type;
4668 
4669  typedef typename AccumulatorResultTraits<U>::SumType SumType;
4670 
4671  value_type value_;
4672  SumType diff_;
4673 
4674  Impl()
4675  : value_(), // call default constructor explicitly to ensure zero initialization
4676  diff_()
4677  {}
4678 
4679  void reset()
4680  {
4681  value_ = element_type();
4682  }
4683 
4684  template <class Shape>
4685  void reshape(Shape const & s)
4686  {
4687  int size = prod(s);
4688  acc_detail::reshapeImpl(value_, Shape1(size*(size+1)/2));
4689  acc_detail::reshapeImpl(diff_, s);
4690  }
4691 
4692  void operator+=(Impl const & o)
4693  {
4694  double n1 = getDependency<Count>(*this), n2 = getDependency<Count>(o);
4695  if(n1 == 0.0)
4696  {
4697  value_ = o.value_;
4698  }
4699  else if(n2 != 0.0)
4700  {
4701  using namespace vigra::multi_math;
4702  diff_ = getDependency<Mean>(*this) - getDependency<Mean>(o);
4703  acc_detail::updateFlatScatterMatrix(value_, diff_, n1 * n2 / (n1 + n2));
4704  value_ += o.value_;
4705  }
4706  }
4707 
4708  void update(U const & t)
4709  {
4710  compute(t);
4711  }
4712 
4713  void update(U const & t, double weight)
4714  {
4715  compute(t, weight);
4716  }
4717 
4718  result_type operator()() const
4719  {
4720  return value_;
4721  }
4722 
4723  private:
4724  void compute(U const & t, double weight = 1.0)
4725  {
4726  double n = getDependency<Count>(*this);
4727  if(n > weight)
4728  {
4729  using namespace vigra::multi_math;
4730  diff_ = getDependency<Mean>(*this) - t;
4731  acc_detail::updateFlatScatterMatrix(value_, diff_, n * weight / (n - weight));
4732  }
4733  }
4734  };
4735 };
4736 
4737 // Covariance
4738 template <>
4740 {
4741  public:
4742  typedef Select<FlatScatterMatrix, Count> Dependencies;
4743 
4744  static std::string name()
4745  {
4746  return "DivideByCount<FlatScatterMatrix>";
4747  // static const std::string n("DivideByCount<FlatScatterMatrix>");
4748  // return n;
4749  }
4750 
4751  template <class U, class BASE>
4752  struct Impl
4753  : public CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U>
4754  {
4755  typedef CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U> BaseType;
4756  typedef typename BaseType::result_type result_type;
4757 
4758  template <class Shape>
4759  void reshape(Shape const & s)
4760  {
4761  int size = prod(s);
4762  acc_detail::reshapeImpl(this->value_, Shape2(size,size));
4763  }
4764 
4765  result_type operator()() const
4766  {
4767  if(this->isDirty())
4768  {
4769  acc_detail::flatScatterMatrixToCovariance(this->value_, getDependency<FlatScatterMatrix>(*this), getDependency<Count>(*this));
4770  this->setClean();
4771  }
4772  return this->value_;
4773  }
4774  };
4775 };
4776 
4777 // UnbiasedCovariance
4778 template <>
4779 class DivideUnbiased<FlatScatterMatrix>
4780 {
4781  public:
4782  typedef Select<FlatScatterMatrix, Count> Dependencies;
4783 
4784  static std::string name()
4785  {
4786  return "DivideUnbiased<FlatScatterMatrix>";
4787  // static const std::string n("DivideUnbiased<FlatScatterMatrix>");
4788  // return n;
4789  }
4790 
4791  template <class U, class BASE>
4792  struct Impl
4793  : public CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U>
4794  {
4795  typedef CachedResultBase<BASE, typename AccumulatorResultTraits<U>::CovarianceType, U> BaseType;
4796  typedef typename BaseType::result_type result_type;
4797 
4798  template <class Shape>
4799  void reshape(Shape const & s)
4800  {
4801  int size = prod(s);
4802  acc_detail::reshapeImpl(this->value_, Shape2(size,size));
4803  }
4804 
4805  result_type operator()() const
4806  {
4807  if(this->isDirty())
4808  {
4809  acc_detail::flatScatterMatrixToCovariance(this->value_, getDependency<FlatScatterMatrix>(*this), getDependency<Count>(*this) - 1.0);
4810  this->setClean();
4811  }
4812  return this->value_;
4813  }
4814  };
4815 };
4816 
4817 /** Basic statistic. ScatterMatrixEigensystem (?)
4818 */
4820 {
4821  public:
4823 
4824  static std::string name()
4825  {
4826  return "ScatterMatrixEigensystem";
4827  // static const std::string n("ScatterMatrixEigensystem");
4828  // return n;
4829  }
4830 
4831  template <class U, class BASE>
4832  struct Impl
4833  : public BASE
4834  {
4835  typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
4836  typedef typename AccumulatorResultTraits<U>::SumType EigenvalueType;
4837  typedef typename AccumulatorResultTraits<U>::CovarianceType EigenvectorType;
4838  typedef std::pair<EigenvalueType, EigenvectorType> value_type;
4839  typedef value_type const & result_type;
4840 
4841  mutable value_type value_;
4842 
4843  Impl()
4844  : value_()
4845  {}
4846 
4847  void operator+=(Impl const & o)
4848  {
4849  if(!acc_detail::hasDataImpl(value_.second))
4850  {
4851  acc_detail::copyShapeImpl(o.value_.first, value_.first);
4852  acc_detail::copyShapeImpl(o.value_.second, value_.second);
4853  }
4854  this->setDirty();
4855  }
4856 
4857  void update(U const &)
4858  {
4859  this->setDirty();
4860  }
4861 
4862  void update(U const &, double)
4863  {
4864  this->setDirty();
4865  }
4866 
4867  void reset()
4868  {
4869  value_.first = element_type();
4870  value_.second = element_type();
4871  this->setClean();
4872  }
4873 
4874  template <class Shape>
4875  void reshape(Shape const & s)
4876  {
4877  int size = prod(s);
4878  acc_detail::reshapeImpl(value_.first, Shape1(size));
4879  acc_detail::reshapeImpl(value_.second, Shape2(size,size));
4880  }
4881 
4882  result_type operator()() const
4883  {
4884  if(this->isDirty())
4885  {
4886  compute(getDependency<FlatScatterMatrix>(*this), value_.first, value_.second);
4887  this->setClean();
4888  }
4889  return value_;
4890  }
4891 
4892  private:
4893  template <class Flat, class EW, class EV>
4894  static void compute(Flat const & flatScatter, EW & ew, EV & ev)
4895  {
4896  EigenvectorType scatter(ev.shape());
4897  acc_detail::flatScatterMatrixToScatterMatrix(scatter, flatScatter);
4898  // create a view because EW could be a TinyVector
4899  MultiArrayView<2, element_type> ewview(Shape2(ev.shape(0), 1), &ew[0]);
4900  symmetricEigensystem(scatter, ewview, ev);
4901  }
4902 
4903  static void compute(double v, double & ew, double & ev)
4904  {
4905  ew = v;
4906  ev = 1.0;
4907  }
4908  };
4909 };
4910 
4911 // CovarianceEigensystem
4912 template <>
4914 {
4915  public:
4916  typedef Select<ScatterMatrixEigensystem, Count> Dependencies;
4917 
4918  static std::string name()
4919  {
4920  return "DivideByCount<ScatterMatrixEigensystem>";
4921  // static const std::string n("DivideByCount<ScatterMatrixEigensystem>");
4922  // return n;
4923  }
4924 
4925  template <class U, class BASE>
4926  struct Impl
4927  : public BASE
4928  {
4929  typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>::type SMImpl;
4930  typedef typename SMImpl::element_type element_type;
4931  typedef typename SMImpl::EigenvalueType EigenvalueType;
4932  typedef typename SMImpl::EigenvectorType EigenvectorType;
4933  typedef std::pair<EigenvalueType, EigenvectorType const &> value_type;
4934  typedef value_type const & result_type;
4935 
4936  mutable value_type value_;
4937 
4938  Impl()
4939  : value_(EigenvalueType(), BASE::template call_getDependency<ScatterMatrixEigensystem>().second)
4940  {}
4941 
4942  void operator+=(Impl const &)
4943  {
4944  this->setDirty();
4945  }
4946 
4947  void update(U const &)
4948  {
4949  this->setDirty();
4950  }
4951 
4952  void update(U const &, double)
4953  {
4954  this->setDirty();
4955  }
4956 
4957  void reset()
4958  {
4959  value_.first = element_type();
4960  this->setClean();
4961  }
4962 
4963  template <class Shape>
4964  void reshape(Shape const & s)
4965  {
4966  int size = prod(s);
4967  acc_detail::reshapeImpl(value_.first, Shape2(size,1));
4968  }
4969 
4970  result_type operator()() const
4971  {
4972  if(this->isDirty())
4973  {
4974  value_.first = getDependency<ScatterMatrixEigensystem>(*this).first / getDependency<Count>(*this);
4975  this->setClean();
4976  }
4977  return value_;
4978  }
4979  };
4980 };
4981 
4982 // alternative implementation of CovarianceEigensystem - solve eigensystem directly
4983 //
4984 // template <>
4985 // class DivideByCount<ScatterMatrixEigensystem>
4986 // {
4987  // public:
4988  // typedef Select<Covariance> Dependencies;
4989 
4990  // template <class U, class BASE>
4991  // struct Impl
4992  // : public BASE
4993  // {
4994  // typedef typename AccumulatorResultTraits<U>::element_promote_type element_type;
4995  // typedef typename AccumulatorResultTraits<U>::SumType EigenvalueType;
4996  // typedef typename AccumulatorResultTraits<U>::CovarianceType EigenvectorType;
4997  // typedef std::pair<EigenvalueType, EigenvectorType> value_type;
4998  // typedef value_type const & result_type;
4999 
5000  // mutable value_type value_;
5001 
5002  // Impl()
5003  // : value_()
5004  // {}
5005 
5006  // void operator+=(Impl const &)
5007  // {
5008  // this->setDirty();
5009  // }
5010 
5011  // void update(U const &)
5012  // {
5013  // this->setDirty();
5014  // }
5015 
5016  // void update(U const &, double)
5017  // {
5018  // this->setDirty();
5019  // }
5020 
5021  // void reset()
5022  // {
5023  // value_.first = element_type();
5024  // value_.second = element_type();
5025  // this->setClean();
5026  // }
5027 
5028  // template <class Shape>
5029  // void reshape(Shape const & s)
5030  // {
5031  // int size = prod(s);
5032  // acc_detail::reshapeImpl(value_.first, Shape2(size,1));
5033  // acc_detail::reshapeImpl(value_.second, Shape2(size,size));
5034  // }
5035 
5036  // result_type operator()() const
5037  // {
5038  // if(this->isDirty())
5039  // {
5040  // compute(getDependency<Covariance>(*this), value_.first, value_.second);
5041  // this->setClean();
5042  // }
5043  // return value_;
5044  // }
5045 
5046  // private:
5047  // template <class Cov, class EW, class EV>
5048  // static void compute(Cov const & cov, EW & ew, EV & ev)
5049  // {
5050  // // create a view because EW could be a TinyVector
5051  // MultiArrayView<2, element_type> ewview(Shape2(cov.shape(0), 1), &ew[0]);
5052  // symmetricEigensystem(cov, ewview, ev);
5053  // }
5054 
5055  // static void compute(double cov, double & ew, double & ev)
5056  // {
5057  // ew = cov;
5058  // ev = 1.0;
5059  // }
5060  // };
5061 // };
5062 
5063 // covariance eigenvalues
5064 /** \brief Specialization (covariance eigenvalues): works in pass 1, %operator+=() supported (merging).
5065 */
5066 template <>
5068 {
5069  public:
5071 
5072  static std::string name()
5073  {
5074  return "Principal<PowerSum<2> >";
5075  // static const std::string n("Principal<PowerSum<2> >");
5076  // return n;
5077  }
5078 
5079  template <class U, class BASE>
5080  struct Impl
5081  : public BASE
5082  {
5083  typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>::type::EigenvalueType value_type;
5084  typedef value_type const & result_type;
5085 
5086  result_type operator()() const
5087  {
5088  return getDependency<ScatterMatrixEigensystem>(*this).first;
5089  }
5090  };
5091 };
5092 
5093 
5094 // Principal<CoordinateSystem> == covariance eigenvectors
5095 /** \brief Specialization (covariance eigenvectors): works in pass 1, %operator+=() supported (merging).
5096 */
5097 template <>
5099 {
5100  public:
5102 
5103  static std::string name()
5104  {
5105  return "Principal<CoordinateSystem>";
5106  // static const std::string n("Principal<CoordinateSystem>");
5107  // return n;
5108  }
5109 
5110  template <class U, class BASE>
5111  struct Impl
5112  : public BASE
5113  {
5114  typedef typename LookupDependency<ScatterMatrixEigensystem, BASE>::type::EigenvectorType value_type;
5115  typedef value_type const & result_type;
5116 
5117  result_type operator()() const
5118  {
5119  return getDependency<ScatterMatrixEigensystem>(*this).second;
5120  }
5121  };
5122 };
5123 
5124 /** \brief Basic statistic. %Minimum value.
5125 
5126  Works in pass 1, %operator+=() supported (merging supported).
5127 */
5128 class Minimum
5129 {
5130  public:
5131  typedef Select<> Dependencies;
5132 
5133  static std::string name()
5134  {
5135  return "Minimum";
5136  // static const std::string n("Minimum");
5137  // return n;
5138  }
5139 
5140  template <class U, class BASE>
5141  struct Impl
5142  : public BASE
5143  {
5144  typedef typename AccumulatorResultTraits<U>::element_type element_type;
5145  typedef typename AccumulatorResultTraits<U>::MinmaxType value_type;
5146  typedef value_type const & result_type;
5147 
5148  value_type value_;
5149 
5150  Impl()
5151  {
5152  value_ = NumericTraits<element_type>::max();
5153  }
5154 
5155  void reset()
5156  {
5157  value_ = NumericTraits<element_type>::max();
5158  }
5159 
5160  template <class Shape>
5161  void reshape(Shape const & s)
5162  {
5163  acc_detail::reshapeImpl(value_, s, NumericTraits<element_type>::max());
5164  }
5165 
5166  void operator+=(Impl const & o)
5167  {
5168  updateImpl(o.value_); // necessary because std::min causes ambiguous overload
5169  }
5170 
5171  void update(U const & t)
5172  {
5173  updateImpl(t);
5174  }
5175 
5176  void update(U const & t, double)
5177  {
5178  updateImpl(t);
5179  }
5180 
5181  result_type operator()() const
5182  {
5183  return value_;
5184  }
5185 
5186  private:
5187  template <class T>
5188  void updateImpl(T const & o)
5189  {
5190  using namespace multi_math;
5191  value_ = min(value_, o);
5192  }
5193 
5194  template <class T, class Alloc>
5195  void updateImpl(MultiArray<1, T, Alloc> const & o)
5196  {
5197  value_ = multi_math::min(value_, o);
5198  }
5199  };
5200 };
5201 
5202 /** \brief Basic statistic. %Maximum value.
5203 
5204  Works in pass 1, %operator+=() supported (merging supported).
5205 */
5206 class Maximum
5207 {
5208  public:
5209  typedef Select<> Dependencies;
5210 
5211  static std::string name()
5212  {
5213  return "Maximum";
5214  // static const std::string n("Maximum");
5215  // return n;
5216  }
5217 
5218  template <class U, class BASE>
5219  struct Impl
5220  : public BASE
5221  {
5222  typedef typename AccumulatorResultTraits<U>::element_type element_type;
5223  typedef typename AccumulatorResultTraits<U>::MinmaxType value_type;
5224  typedef value_type const & result_type;
5225 
5226  value_type value_;
5227 
5228  Impl()
5229  {
5230  value_ = NumericTraits<element_type>::min();
5231  }
5232 
5233  void reset()
5234  {
5235  value_ = NumericTraits<element_type>::min();
5236  }
5237 
5238  template <class Shape>
5239  void reshape(Shape const & s)
5240  {
5241  acc_detail::reshapeImpl(value_, s, NumericTraits<element_type>::min());
5242  }
5243 
5244  void operator+=(Impl const & o)
5245  {
5246  updateImpl(o.value_); // necessary because std::max causes ambiguous overload
5247  }
5248 
5249  void update(U const & t)
5250  {
5251  updateImpl(t);
5252  }
5253 
5254  void update(U const & t, double)
5255  {
5256  updateImpl(t);
5257  }
5258 
5259  result_type operator()() const
5260  {
5261  return value_;
5262  }
5263 
5264  private:
5265  template <class T>
5266  void updateImpl(T const & o)
5267  {
5268  using namespace multi_math;
5269  value_ = max(value_, o);
5270  }
5271 
5272  template <class T, class Alloc>
5273  void updateImpl(MultiArray<1, T, Alloc> const & o)
5274  {
5275  value_ = multi_math::max(value_, o);
5276  }
5277  };
5278 };
5279 
5280 /** \brief Basic statistic. First data value seen of the object.
5281 
5282  Usually used as <tt>Coord<FirstSeen></tt> (alias <tt>RegionAnchor</tt>)
5283  which provides a well-defined anchor point for the region.
5284 */
5286 {
5287  public:
5288  typedef Select<Count> Dependencies;
5289 
5290  static std::string name()
5291  {
5292  return "FirstSeen";
5293  // static const std::string n("FirstSeen");
5294  // return n;
5295  }
5296 
5297  template <class U, class BASE>
5298  struct Impl
5299  : public BASE
5300  {
5301  typedef typename AccumulatorResultTraits<U>::element_type element_type;
5302  typedef typename AccumulatorResultTraits<U>::MinmaxType value_type;
5303  typedef value_type const & result_type;
5304 
5305  value_type value_;
5306 
5307  Impl()
5308  : value_()
5309  {}
5310 
5311  void reset()
5312  {
5313  value_ = element_type();
5314  }
5315 
5316  template <class Shape>
5317  void reshape(Shape const & s)
5318  {
5319  acc_detail::reshapeImpl(value_, s);
5320  }
5321 
5322  void operator+=(Impl const & o)
5323  {
5324  // FIXME: only works for Coord<FirstSeen>
5325  if(reverse(o.value_) < reverse(value_))
5326  value_ = o.value_;
5327  }
5328 
5329  void update(U const & t)
5330  {
5331  if(getDependency<Count>(*this) == 1)
5332  value_ = t;
5333  }
5334 
5335  void update(U const & t, double)
5336  {
5337  update(t);
5338  }
5339 
5340  result_type operator()() const
5341  {
5342  return value_;
5343  }
5344  };
5345 };
5346 
5347 /** \brief Return both the minimum and maximum in <tt>std::pair</tt>.
5348 
5349  Usually used as <tt>Coord<Range></tt> (alias <tt>BoundingBox</tt>).
5350  Note that <tt>Range</tt> returns a closed interval, i.e. the upper
5351  limit is part of the range.
5352 */
5353 class Range
5354 {
5355  public:
5357 
5358  static std::string name()
5359  {
5360  return "Range";
5361  // static const std::string n("Range");
5362  // return n;
5363  }
5364 
5365  template <class U, class BASE>
5366  struct Impl
5367  : public BASE
5368  {
5369  typedef typename AccumulatorResultTraits<U>::MinmaxType minmax_type;
5370  typedef std::pair<minmax_type, minmax_type> value_type;
5371  typedef value_type result_type;
5372 
5373  result_type operator()() const
5374  {
5375  return value_type(getDependency<Minimum>(*this), getDependency<Maximum>(*this));
5376  }
5377  };
5378 };
5379 
5380 /** \brief Basic statistic. Data value where weight assumes its minimal value.
5381 
5382  Weights must be given. Coord<ArgMinWeight> gives coordinate where weight assumes its minimal value. Works in pass 1, %operator+=() supported (merging supported).
5383 */
5385 {
5386  public:
5387  typedef Select<> Dependencies;
5388 
5389  static std::string name()
5390  {
5391  return "ArgMinWeight";
5392  // static const std::string n("ArgMinWeight");
5393  // return n;
5394  }
5395 
5396  template <class U, class BASE>
5397  struct Impl
5398  : public BASE
5399  {
5400  typedef typename AccumulatorResultTraits<U>::element_type element_type;
5401  typedef typename AccumulatorResultTraits<U>::MinmaxType value_type;
5402  typedef value_type const & result_type;
5403 
5404  double min_weight_;
5405  value_type value_;
5406 
5407  Impl()
5408  : min_weight_(NumericTraits<double>::max()),
5409  value_()
5410  {}
5411 
5412  void reset()
5413  {
5414  min_weight_ = NumericTraits<double>::max();
5415  value_ = element_type();
5416  }
5417 
5418  template <class Shape>
5419  void reshape(Shape const & s)
5420  {
5421  acc_detail::reshapeImpl(value_, s);
5422  }
5423 
5424  void operator+=(Impl const & o)
5425  {
5426  using namespace multi_math;
5427  if(o.min_weight_ < min_weight_)
5428  {
5429  min_weight_ = o.min_weight_;
5430  value_ = o.value_;
5431  }
5432  }
5433 
5434  void update(U const &)
5435  {
5436  vigra_precondition(false, "ArgMinWeight::update() needs weights.");
5437  }
5438 
5439  void update(U const & t, double weight)
5440  {
5441  if(weight < min_weight_)
5442  {
5443  min_weight_ = weight;
5444  value_ = t;
5445  }
5446  }
5447 
5448  result_type operator()() const
5449  {
5450  return value_;
5451  }
5452  };
5453 };
5454 
5455 /** \brief Basic statistic. Data where weight assumes its maximal value.
5456 
5457  Weights must be given. Coord<ArgMinWeight> gives coordinate where weight assumes its maximal value. Works in pass 1, %operator+=() supported (merging supported).
5458 */
5460 {
5461  public:
5462  typedef Select<> Dependencies;
5463 
5464  static std::string name()
5465  {
5466  return "ArgMaxWeight";
5467  // static const std::string n("ArgMaxWeight");
5468  // return n;
5469  }
5470 
5471  template <class U, class BASE>
5472  struct Impl
5473  : public BASE
5474  {
5475  typedef typename AccumulatorResultTraits<U>::element_type element_type;
5476  typedef typename AccumulatorResultTraits<U>::MinmaxType value_type;
5477  typedef value_type const & result_type;
5478 
5479  double max_weight_;
5480  value_type value_;
5481 
5482  Impl()
5483  : max_weight_(NumericTraits<double>::min()),
5484  value_()
5485  {}
5486 
5487  void reset()
5488  {
5489  max_weight_ = NumericTraits<double>::min();
5490  value_ = element_type();
5491  }
5492 
5493  template <class Shape>
5494  void reshape(Shape const & s)
5495  {
5496  acc_detail::reshapeImpl(value_, s);
5497  }
5498 
5499  void operator+=(Impl const & o)
5500  {
5501  using namespace multi_math;
5502  if(o.max_weight_ > max_weight_)
5503  {
5504  max_weight_ = o.max_weight_;
5505  value_ = o.value_;
5506  }
5507  }
5508 
5509  void update(U const &)
5510  {
5511  vigra_precondition(false, "ArgMaxWeight::update() needs weights.");
5512  }
5513 
5514  void update(U const & t, double weight)
5515  {
5516  if(weight > max_weight_)
5517  {
5518  max_weight_ = weight;
5519  value_ = t;
5520  }
5521  }
5522 
5523  result_type operator()() const
5524  {
5525  return value_;
5526  }
5527  };
5528 };
5529 
5530 
5531 template <class BASE, int BinCount>
5532 class HistogramBase
5533 : public BASE
5534 {
5535  public:
5536 
5537  typedef double element_type;
5538  typedef TinyVector<double, BinCount> value_type;
5539  typedef value_type const & result_type;
5540 
5541  value_type value_;
5542  double left_outliers, right_outliers;
5543 
5544  HistogramBase()
5545  : value_(),
5546  left_outliers(),
5547  right_outliers()
5548  {}
5549 
5550  void reset()
5551  {
5552  value_ = element_type();
5553  left_outliers = 0.0;
5554  right_outliers = 0.0;
5555  }
5556 
5557  void operator+=(HistogramBase const & o)
5558  {
5559  value_ += o.value_;
5560  left_outliers += o.left_outliers;
5561  right_outliers += o.right_outliers;
5562  }
5563 
5564  result_type operator()() const
5565  {
5566  return value_;
5567  }
5568 };
5569 
5570 template <class BASE>
5571 class HistogramBase<BASE, 0>
5572 : public BASE
5573 {
5574  public:
5575 
5576  typedef double element_type;
5577  typedef MultiArray<1, double> value_type;
5578  typedef value_type const & result_type;
5579 
5580  value_type value_;
5581  double left_outliers, right_outliers;
5582 
5583  HistogramBase()
5584  : value_(),
5585  left_outliers(),
5586  right_outliers()
5587  {}
5588 
5589  void reset()
5590  {
5591  value_ = element_type();
5592  left_outliers = 0.0;
5593  right_outliers = 0.0;
5594  }
5595 
5596  void operator+=(HistogramBase const & o)
5597  {
5598  if(value_.size() == 0)
5599  {
5600  value_ = o.value_;
5601  }
5602  else if(o.value_.size() > 0)
5603  {
5604  vigra_precondition(value_.size() == o.value_.size(),
5605  "HistogramBase::operator+=(): bin counts must be equal.");
5606  value_ += o.value_;
5607  }
5608  left_outliers += o.left_outliers;
5609  right_outliers += o.right_outliers;
5610  }
5611 
5612  void setBinCount(int binCount)
5613  {
5614  vigra_precondition(binCount > 0,
5615  "HistogramBase:.setBinCount(): binCount > 0 required.");
5616  value_type(Shape1(binCount)).swap(value_);
5617  }
5618 
5619  result_type operator()() const
5620  {
5621  return value_;
5622  }
5623 };
5624 
5625 template <class BASE, int BinCount, class U=typename BASE::input_type>
5626 class RangeHistogramBase
5627 : public HistogramBase<BASE, BinCount>
5628 {
5629  public:
5630  double scale_, offset_, inverse_scale_;
5631 
5632  RangeHistogramBase()
5633  : scale_(),
5634  offset_(),
5635  inverse_scale_()
5636  {}
5637 
5638  void reset()
5639  {
5640  scale_ = 0.0;
5641  offset_ = 0.0;
5642  inverse_scale_ = 0.0;
5643  HistogramBase<BASE, BinCount>::reset();
5644  }
5645 
5646  void operator+=(RangeHistogramBase const & o)
5647  {
5648  vigra_precondition(scale_ == 0.0 || o.scale_ == 0.0 || (scale_ == o.scale_ && offset_ == o.offset_),
5649  "RangeHistogramBase::operator+=(): cannot merge histograms with different data mapping.");
5650 
5652  if(scale_ == 0.0)
5653  {
5654  scale_ = o.scale_;
5655  offset_ = o.offset_;
5656  inverse_scale_ = o.inverse_scale_;
5657  }
5658  }
5659 
5660  void update(U const & t)
5661  {
5662  update(t, 1.0);
5663  }
5664 
5665  void update(U const & t, double weight)
5666  {
5667  double m = mapItem(t);
5668  int index = (m == (double)this->value_.size())
5669  ? (int)m - 1
5670  : (int)m;
5671  if(index < 0)
5672  this->left_outliers += weight;
5673  else if(index >= (int)this->value_.size())
5674  this->right_outliers += weight;
5675  else
5676  this->value_[index] += weight;
5677  }
5678 
5679  void setMinMax(double mi, double ma)
5680  {
5681  vigra_precondition(this->value_.size() > 0,
5682  "RangeHistogramBase::setMinMax(...): setBinCount(...) has not been called.");
5683  vigra_precondition(mi <= ma,
5684  "RangeHistogramBase::setMinMax(...): min <= max required.");
5685  if(mi == ma)
5686  ma += this->value_.size() * NumericTraits<double>::epsilon();
5687  offset_ = mi;
5688  scale_ = (double)this->value_.size() / (ma - mi);
5689  inverse_scale_ = 1.0 / scale_;
5690  }
5691 
5692  double mapItem(double t) const
5693  {
5694  return scale_ * (t - offset_);
5695  }
5696 
5697  double mapItemInverse(double t) const
5698  {
5699  return inverse_scale_ * t + offset_;
5700  }
5701 
5702  template <class ArrayLike>
5703  void computeStandardQuantiles(double minimum, double maximum, double count,
5704  ArrayLike const & desiredQuantiles, ArrayLike & res) const
5705  {
5706  if(count == 0.0) {
5707  return;
5708  }
5709 
5710  ArrayVector<double> keypoints, cumhist;
5711  double mappedMinimum = mapItem(minimum);
5712  double mappedMaximum = mapItem(maximum);
5713 
5714  keypoints.push_back(mappedMinimum);
5715  cumhist.push_back(0.0);
5716 
5717  if(this->left_outliers > 0.0)
5718  {
5719  keypoints.push_back(0.0);
5720  cumhist.push_back(this->left_outliers);
5721  }
5722 
5723  int size = (int)this->value_.size();
5724  double cumulative = this->left_outliers;
5725  for(int k=0; k<size; ++k)
5726  {
5727  if(this->value_[k] > 0.0)
5728  {
5729  if(keypoints.back() <= k)
5730  {
5731  keypoints.push_back(k);
5732  cumhist.push_back(cumulative);
5733  }
5734  cumulative += this->value_[k];
5735  keypoints.push_back(k+1);
5736  cumhist.push_back(cumulative);
5737  }
5738  }
5739 
5740  if(this->right_outliers > 0.0)
5741  {
5742  if(keypoints.back() != size)
5743  {
5744  keypoints.push_back(size);
5745  cumhist.push_back(cumulative);
5746  }
5747  keypoints.push_back(mappedMaximum);
5748  cumhist.push_back(count);
5749  }
5750  else
5751  {
5752  keypoints.back() = mappedMaximum;
5753  cumhist.back() = count;
5754  }
5755 
5756  int quantile = 0, end = (int)desiredQuantiles.size();
5757 
5758  if(desiredQuantiles[0] == 0.0)
5759  {
5760  res[0] = minimum;
5761  ++quantile;
5762  }
5763  if(desiredQuantiles[end-1] == 1.0)
5764  {
5765  res[end-1] = maximum;
5766  --end;
5767  }
5768 
5769  int point = 0;
5770  double qcount = count * desiredQuantiles[quantile];
5771  while(quantile < end)
5772  {
5773  if(cumhist[point] < qcount && cumhist[point+1] >= qcount)
5774  {
5775  double t = (qcount - cumhist[point]) / (cumhist[point+1] - cumhist[point]) * (keypoints[point+1] - keypoints[point]);
5776  res[quantile] = mapItemInverse(t + keypoints[point]);
5777  ++quantile;
5778  qcount = count * desiredQuantiles[quantile];
5779  }
5780  else
5781  {
5782  ++point;
5783  }
5784  }
5785  }
5786 };
5787 
5788 /** \brief Histogram where data values are equal to bin indices.
5789 
5790  - If BinCount != 0, the return type of the accumulator is TinyVector<double, BinCount> .
5791  - 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).
5792  - Outliers can be accessed via getAccumulator<IntegerHistogram<Bincount>>(a).left_outliers and getAccumulator<...>(acc_chain).right_outliers.
5793  - 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().
5794  Works in pass 1, %operator+=() supported (merging supported).
5795 */
5796 template <int BinCount>
5797 class IntegerHistogram
5798 {
5799  public:
5800 
5801  typedef Select<> Dependencies;
5802 
5803  static std::string name()
5804  {
5805  return std::string("IntegerHistogram<") + asString(BinCount) + ">";
5806  // static const std::string n = std::string("IntegerHistogram<") + asString(BinCount) + ">";
5807  // return n;
5808  }
5809 
5810  template <class U, class BASE>
5811  struct Impl
5812  : public HistogramBase<BASE, BinCount>
5813  {
5814  void update(int index)
5815  {
5816  if(index < 0)
5817  ++this->left_outliers;
5818  else if(index >= (int)this->value_.size())
5819  ++this->right_outliers;
5820  else
5821  ++this->value_[index];
5822  }
5823 
5824  void update(int, double)
5825  {
5826  // cannot compute quantile from weighted integer histograms,
5827  // so force people to use UserRangeHistogram or AutoRangeHistogram
5828  vigra_precondition(false, "IntegerHistogram::update(): weighted histograms not supported, use another histogram type.");
5829  }
5830 
5831  template <class ArrayLike>
5832  void computeStandardQuantiles(double minimum, double maximum, double count,
5833  ArrayLike const & desiredQuantiles, ArrayLike & res) const
5834  {
5835  int quantile = 0, end = (int)desiredQuantiles.size();
5836 
5837  if(desiredQuantiles[0] == 0.0)
5838  {
5839  res[0] = minimum;
5840  ++quantile;
5841  }
5842  if(desiredQuantiles[end-1] == 1.0)
5843  {
5844  res[end-1] = maximum;
5845  --end;
5846  }
5847 
5848  count -= 1.0;
5849  int currentBin = 0, size = (int)this->value_.size();
5850  double cumulative1 = this->left_outliers,
5851  cumulative2 = this->value_[currentBin] + cumulative1;
5852 
5853  // add a to the quantiles to account for the fact that counting
5854  // corresponds to 1-based indexing (one element == index 1)
5855  double qcount = desiredQuantiles[quantile]*count + 1.0;
5856 
5857  while(quantile < end)
5858  {
5859  if(cumulative2 == qcount)
5860  {
5861  res[quantile] = currentBin;
5862  ++quantile;
5863  qcount = desiredQuantiles[quantile]*count + 1.0;
5864  }
5865  else if(cumulative2 > qcount)
5866  {
5867  if(cumulative1 > qcount) // in left_outlier bin
5868  {
5869  res[quantile] = minimum;
5870  }
5871  if(cumulative1 + 1.0 > qcount) // between bins
5872  {
5873  res[quantile] = currentBin - 1 + qcount - std::floor(qcount);
5874  }
5875  else // standard case
5876  {
5877  res[quantile] = currentBin;
5878  }
5879  ++quantile;
5880  qcount = desiredQuantiles[quantile]*count + 1.0;
5881  }
5882  else if(currentBin == size-1) // in right outlier bin
5883  {
5884  res[quantile] = maximum;
5885  ++quantile;
5886  qcount = desiredQuantiles[quantile]*count + 1.0;
5887  }
5888  else
5889  {
5890  ++currentBin;
5891  cumulative1 = cumulative2;
5892  cumulative2 += this->value_[currentBin];
5893  }
5894  }
5895  }
5896  };
5897 };
5898 
5899 /** \brief Histogram where user provides bounds for linear range mapping from values to indices.
5900 
5901  - If BinCount != 0, the return type of the accumulator is TinyVector<double, BinCount> .
5902  - 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).
5903  - Bounds for the mapping (min/max) must be set before seeing data by calling getAccumulator<UserRangeHistogram<BinCount> >.setMinMax(min, max).
5904  - Options can also be passed to the accumulator chain via an instance of HistogramOptions .
5905  - Works in pass 1, %operator+=() is supported (merging) if both histograms have the same data mapping.
5906  - Outliers can be accessed via getAccumulator<...>(a).left_outliers and getAccumulator<...>(a).right_outliers.
5907  - 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().
5908 */
5909 template <int BinCount>
5910 class UserRangeHistogram
5911 {
5912  public:
5913 
5914  typedef Select<> Dependencies;
5915 
5916  static std::string name()
5917  {
5918  return std::string("UserRangeHistogram<") + asString(BinCount) + ">";
5919  // static const std::string n = std::string("UserRangeHistogram<") + asString(BinCount) + ">";
5920  // return n;
5921  }
5922 
5923  template <class U, class BASE>
5924  struct Impl
5925  : public RangeHistogramBase<BASE, BinCount, U>
5926  {
5927  void update(U const & t)
5928  {
5929  update(t, 1.0);
5930  }
5931 
5932  void update(U const & t, double weight)
5933  {
5934  vigra_precondition(this->scale_ != 0.0,
5935  "UserRangeHistogram::update(): setMinMax(...) has not been called.");
5936 
5937  RangeHistogramBase<BASE, BinCount, U>::update(t, weight);
5938  }
5939  };
5940 };
5941 
5942 /** \brief Histogram where range mapping bounds are defined by minimum and maximum of data.
5943 
5944  - If BinCount != 0, the return type of the accumulator is TinyVector<double, BinCount> .
5945  - 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).
5946  - Becomes a UserRangeHistogram if min/max is set.
5947  - Works in pass 2, %operator+=() is supported (merging) if both histograms have the same data mapping.
5948  - Outliers can be accessed via getAccumulator<...>(acc_chain).left_outliers and getAccumulator<...>(acc_chain).right_outliers .
5949  - 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().
5950 */
5951 template <int BinCount>
5952 class AutoRangeHistogram
5953 {
5954  public:
5955 
5956  typedef Select<Minimum, Maximum> Dependencies;
5957 
5958  static std::string name()
5959  {
5960  return std::string("AutoRangeHistogram<") + asString(BinCount) + ">";
5961  // static const std::string n = std::string("AutoRangeHistogram<") + asString(BinCount) + ">";
5962  // return n;
5963  }
5964 
5965  template <class U, class BASE>
5966  struct Impl
5967  : public RangeHistogramBase<BASE, BinCount, U>
5968  {
5969  static const unsigned int workInPass = LookupDependency<Minimum, BASE>::type::workInPass + 1;
5970 
5971  void update(U const & t)
5972  {
5973  update(t, 1.0);
5974  }
5975 
5976  void update(U const & t, double weight)
5977  {
5978  if(this->scale_ == 0.0)
5979  this->setMinMax(getDependency<Minimum>(*this), getDependency<Maximum>(*this));
5980 
5981  RangeHistogramBase<BASE, BinCount, U>::update(t, weight);
5982  }
5983  };
5984 };
5985 
5986 /** \brief Like AutoRangeHistogram, but use global min/max rather than region min/max.
5987 
5988  - If BinCount != 0, the return type of the accumulator is TinyVector<double, BinCount> .
5989  - 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).
5990  - Becomes a UserRangeHistogram if min/max is set.
5991  - Works in pass 2, %operator+=() is supported (merging) if both histograms have the same data mapping.
5992  - Outliers can be accessed via getAccumulator<GlobalRangeHistogram<Bincount>>(acc_chain).left_outliers and getAccumulator<...>(acc_chain).right_outliers .
5993  - 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().
5994 */
5995 template <int BinCount>
5996 class GlobalRangeHistogram
5997 {
5998  public:
5999 
6000  typedef Select<Global<Minimum>, Global<Maximum>, Minimum, Maximum> Dependencies;
6001 
6002  static std::string name()
6003  {
6004  return std::string("GlobalRangeHistogram<") + asString(BinCount) + ">";
6005  // static const std::string n = std::string("GlobalRangeHistogram<") + asString(BinCount) + ">";
6006  // return n;
6007  }
6008 
6009  template <class U, class BASE>
6010  struct Impl
6011  : public RangeHistogramBase<BASE, BinCount, U>
6012  {
6013  static const unsigned int workInPass = LookupDependency<Minimum, BASE>::type::workInPass + 1;
6014 
6015  bool useLocalMinimax_;
6016 
6017  Impl()
6018  : useLocalMinimax_(false)
6019  {}
6020 
6021  void setRegionAutoInit(bool locally)
6022  {
6023  this->scale_ = 0.0;
6024  useLocalMinimax_ = locally;
6025  }
6026 
6027  void update(U const & t)
6028  {
6029  update(t, 1.0);
6030  }
6031 
6032  void update(U const & t, double weight)
6033  {
6034  if(this->scale_ == 0.0)
6035  {
6036  if(useLocalMinimax_)
6037  this->setMinMax(getDependency<Minimum>(*this), getDependency<Maximum>(*this));
6038  else
6039  this->setMinMax(getDependency<Global<Minimum> >(*this), getDependency<Global<Maximum> >(*this));
6040  }
6041 
6042  RangeHistogramBase<BASE, BinCount, U>::update(t, weight);
6043  }
6044  };
6045 };
6046 
6047 /** \brief Compute (0%, 10%, 25%, 50%, 75%, 90%, 100%) quantiles from given histogram.
6048 
6049  Return type is TinyVector<double, 7> .
6050 */
6051 template <class HistogramAccumulator>
6052 class StandardQuantiles
6053 {
6054  public:
6055 
6056  typedef typename StandardizeTag<HistogramAccumulator>::type HistogramTag;
6057  typedef Select<HistogramTag, Minimum, Maximum, Count> Dependencies;
6058 
6059  static std::string name()
6060  {
6061  return std::string("StandardQuantiles<") + HistogramTag::name() + " >";
6062  // static const std::string n = std::string("StandardQuantiles<") + HistogramTag::name() + " >";
6063  // return n;
6064  }
6065 
6066  template <class U, class BASE>
6067  struct Impl
6068  : public CachedResultBase<BASE, TinyVector<double, 7>, U>
6069  {
6070  typedef typename CachedResultBase<BASE, TinyVector<double, 7>, U>::result_type result_type;
6071  typedef typename CachedResultBase<BASE, TinyVector<double, 7>, U>::value_type value_type;
6072 
6073  static const unsigned int workInPass = LookupDependency<HistogramTag, BASE>::type::workInPass;
6074 
6075  result_type operator()() const
6076  {
6077  if(this->isDirty())
6078  {
6079  double desiredQuantiles[] = {0.0, 0.1, 0.25, 0.5, 0.75, 0.9, 1.0 };
6080  getAccumulator<HistogramTag>(*this).computeStandardQuantiles(getDependency<Minimum>(*this), getDependency<Maximum>(*this),
6081  getDependency<Count>(*this), value_type(desiredQuantiles),
6082  this->value_);
6083  this->setClean();
6084  }
6085  return this->value_;
6086  }
6087  };
6088 };
6089 
6090 template <int N>
6091 struct feature_RegionContour_can_only_be_computed_for_2D_arrays
6092 : vigra::staticAssert::AssertBool<N==2>
6093 {};
6094 
6095 /** \brief Compute the contour of a 2D region.
6096 
6097  AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
6098  */
6100 {
6101  public:
6102  typedef Select<Count> Dependencies;
6103 
6104  static std::string name()
6105  {
6106  return std::string("RegionContour");
6107  // static const std::string n = std::string("RegionContour");
6108  // return n;
6109  }
6110 
6111  template <class T, class BASE>
6112  struct Impl
6113  : public BASE
6114  {
6115  typedef HandleArgSelector<T, LabelArgTag, BASE> LabelHandle;
6116  typedef TinyVector<double, 2> point_type;
6117  typedef Polygon<point_type> value_type;
6118  typedef value_type const & result_type;
6119 
6120  point_type offset_;
6121  value_type contour_;
6122 
6123  Impl()
6124  : offset_()
6125  , contour_()
6126  {}
6127 
6128  void setCoordinateOffset(point_type const & offset)
6129  {
6130  offset_ = offset;
6131  }
6132 
6133  template <class U, class NEXT>
6134  void update(CoupledHandle<U, NEXT> const & t)
6135  {
6136  VIGRA_STATIC_ASSERT((feature_RegionContour_can_only_be_computed_for_2D_arrays<
6138  if(getDependency<Count>(*this) == 1)
6139  {
6140  contour_.clear();
6141  extractContour(LabelHandle::getHandle(t).arrayView(), t.point(), contour_);
6142  contour_ += offset_;
6143  }
6144  }
6145 
6146  template <class U, class NEXT>
6147  void update(CoupledHandle<U, NEXT> const & t, double)
6148  {
6149  update(t);
6150  }
6151 
6152  void operator+=(Impl const &)
6153  {
6154  vigra_precondition(false,
6155  "RegionContour::operator+=(): RegionContour cannot be merged.");
6156  }
6157 
6158  result_type operator()() const
6159  {
6160  return contour_;
6161  }
6162  };
6163 };
6164 
6165 
6166 /** \brief Compute the perimeter of a 2D region.
6167 
6168  This is the length of the polygon returned by RegionContour.
6169 
6170  AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
6171  */
6173 {
6174  public:
6176 
6177  static std::string name()
6178  {
6179  return std::string("RegionPerimeter");
6180  // static const std::string n = std::string("RegionPerimeter");
6181  // return n;
6182  }
6183 
6184  template <class T, class BASE>
6185  struct Impl
6186  : public BASE
6187  {
6188  typedef double value_type;
6189  typedef value_type result_type;
6190 
6191  result_type operator()() const
6192  {
6193  return getDependency<RegionContour>(*this).length();
6194  }
6195  };
6196 };
6197 
6198 /** \brief Compute the circularity of a 2D region.
6199 
6200  The is the ratio between the perimeter of a circle with the same area as the
6201  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.
6202 
6203  AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
6204  */
6206 {
6207  public:
6209 
6210  static std::string name()
6211  {
6212  return std::string("RegionCircularity");
6213  // static const std::string n = std::string("RegionCircularity");
6214  // return n;
6215  }
6216 
6217  template <class T, class BASE>
6218  struct Impl
6219  : public BASE
6220  {
6221  typedef double value_type;
6222  typedef value_type result_type;
6223 
6224  result_type operator()() const
6225  {
6226  return 2.0*sqrt(M_PI*getDependency<RegionContour>(*this).area()) / getDependency<RegionContour>(*this).length();
6227  }
6228  };
6229 };
6230 
6231 /** \brief Compute the eccentricity of a 2D region in terms of its prinipal radii.
6232 
6233  Formula: \f[ e = \sqrt{1 - m^2 / M^2 } \f], where m and M are the minor and major principal radius.
6234 
6235  AccumulatorChain must be used with CoupledIterator in order to have access to pixel coordinates.
6236  */
6238 {
6239  public:
6241 
6242  static std::string name()
6243  {
6244  return std::string("RegionEccentricity");
6245  // static const std::string n = std::string("RegionEccentricity");
6246  // return n;
6247  }
6248 
6249  template <class T, class BASE>
6250  struct Impl
6251  : public BASE
6252  {
6253  typedef double value_type;
6254  typedef value_type result_type;
6255 
6256  result_type operator()() const
6257  {
6258  double M = getDependency<RegionRadii>(*this).front(),
6259  m = getDependency<RegionRadii>(*this).back();
6260  return sqrt(1.0 - sq(m/M));
6261  }
6262  };
6263 };
6264 
6265 // Compile only if lemon is available
6266 #ifdef WITH_LEMON
6267 
6268 /** \brief Compute the convex hull of a region.
6269 
6270  AccumulatorChain must be used with CoupledIterator in order to have access
6271  to pixel coordinates.
6272 
6273  The result type is the ConvexPolytop class.
6274  */
6276 {
6277  public:
6279 
6280  static std::string name()
6281  {
6282  return std::string("ConvexHull");
6283  }
6284 
6285  template <class T, class BASE>
6286  struct Impl
6287  : public BASE
6288  {
6289  static const unsigned int workInPass = 2;
6290  static const unsigned int dimensions = T::dimensions;
6291 
6292  typedef ConvexPolytope<dimensions, double> polytope_type;
6293  typedef polytope_type value_type;
6294  typedef value_type const & result_type;
6295  typedef TinyVector<double, dimensions> point_type;
6296  typedef HandleArgSelector<T, CoordArgTag, BASE> coord_handle_type;
6297  typedef typename coord_handle_type::value_type coord_type;
6298 
6299  polytope_type convex_hull_;
6300  bool initialized_;
6301 
6302  Impl()
6303  : convex_hull_()
6304  , initialized_(false)
6305  {}
6306 
6307  template <class U, class NEXT>
6308  void update(CoupledHandle<U, NEXT> const & t)
6309  {
6310  if (!initialized_)
6311  {
6312  initialize();
6313  }
6314  point_type vec(t.point().begin());
6315  convex_hull_.addExtremeVertex(vec);
6316  }
6317 
6318  template <class U, class NEXT>
6319  void update(CoupledHandle<U, NEXT> const & t, double)
6320  {
6321  update(t);
6322  }
6323 
6324  void initialize()
6325  {
6326  convex_hull_.addVertex(getDependency<RegionCenter>(*this));
6327  for (int dim = 0; dim < dimensions; dim++)
6328  {
6329  coord_type vec;
6330  vec[dim] = .5;
6331  convex_hull_.addVertex(
6332  vec + getDependency<RegionCenter>(*this));
6333  }
6334  initialized_ = true;
6335  }
6336 
6337  void operator+=(Impl const &)
6338  {
6339  vigra_precondition(
6340  false,
6341  "ConvexHull::operator+=(): ConvexHull features cannot be merged.");
6342  }
6343 
6344  result_type operator()() const
6345  {
6346  return convex_hull_;
6347  }
6348  };
6349 };
6350 
6351 /** \brief Compute object features related to the convex hull.
6352 
6353  AccumulatorChain must be used with CoupledIterator in order to have access
6354  to pixel coordinates. The convex hull features are only available when
6355  `WITH_LEMON` is set.
6356 
6357  Minimal example how to calculate the features:
6358  \code
6359  // "labels" is the array with the region labels
6360  MultiArrayView<2, int> labels = ...;
6361 
6362  // Set up the accumulator chain and ignore the zero label
6363  AccumulatorChainArray<
6364  CoupledArrays<2, int>,
6365  Select<LabelArg<1>, ConvexHullFeatures> > chain;
6366  chain.ignoreLabel(0);
6367 
6368  // Extract the features
6369  extractFeatures(labels, chain);
6370 
6371  // Finalize the calculation for label 1
6372  getAccumulator<ConvexHullFeatures>(chain, 1).finalize();
6373 
6374  // Get the features
6375  ... = getAccumulator<ConvexHullFeatures>(chain, 1).inputCenter();
6376  \endcode
6377 
6378 */
6380 {
6381  public:
6383 
6384  static std::string name()
6385  {
6386  return std::string("ConvexHullFeatures");
6387  }
6388 
6389  /** \brief Result type of the covex hull feature calculation
6390  */
6391  template <class T, class BASE>
6392  struct Impl
6393  : public BASE
6394  {
6395  static const unsigned int workInPass = 3;
6396  static const unsigned int dimensions = T::dimensions;
6397 
6399  typedef Impl<T, BASE> value_type;
6400  typedef value_type const & result_type;
6402  typedef HandleArgSelector<T, CoordArgTag, BASE> coord_handle_type;
6403  typedef typename coord_handle_type::value_type coord_type;
6404 
6406 
6407  array_type label_array_;
6408  point_type hull_center_;
6409  int hull_volume_;
6410  point_type defect_center_;
6411  double defect_displacement_mean_;
6412  double defect_volume_mean_;
6413  double defect_volume_variance_;
6414  double defect_volume_skewness_;
6415  double defect_volume_kurtosis_;
6416  int defect_count_;
6417  bool initialized_;
6418  bool finalized_;
6419  int num_values_;
6420 
6421  Impl()
6422  : hull_center_()
6423  , hull_volume_()
6424  , defect_center_()
6425  , defect_volume_mean_()
6426  , defect_volume_variance_()
6427  , defect_volume_skewness_()
6428  , defect_volume_kurtosis_()
6429  , defect_count_()
6430  , initialized_(false)
6431  , finalized_(false)
6432  , num_values_(0)
6433  {}
6434 
6435  template <class U, class NEXT>
6436  void update(CoupledHandle<U, NEXT> const & t)
6437  {
6438  vigra_precondition(
6439  finalized_ == false,
6440  "ConvexHullFeatures::update(): "
6441  "Finalize must not be called before update");
6442  if (!initialized_)
6443  {
6444  initialize();
6445  }
6446  const coord_type & coord_min = getDependency<Coord<Minimum> >(*this);
6447  // Update label array
6448  label_array_[coord_handle_type::getValue(t) - coord_min] = 0;
6449  }
6450 
6451  template <class U, class NEXT>
6452  void update(CoupledHandle<U, NEXT> const & t, double)
6453  {
6454  update(t);
6455  }
6456 
6457  void initialize()
6458  {
6459  // Get hull and bounding box
6460  const polytope_type & hull = getDependency<ConvexHull>(*this);
6461  const coord_type & coord_min = getDependency<Coord<Minimum> >(*this);
6462  coord_type coord_max = getDependency<Coord<Maximum> >(*this);
6463  coord_max += coord_type(1);
6464  // Get offset
6465  point_type offset;
6466  std::copy(coord_min.begin(), coord_min.end(), offset.begin());
6467  // Create the label array
6468  label_array_.reshape(coord_max - coord_min, 0);
6469  hull.fill(label_array_, 1, offset);
6470  // Extract convex hull features
6473  Select<LabelArg<1>, Count, RegionCenter> > hull_acc;
6474  hull_acc.ignoreLabel(0);
6475  extractFeatures(label_array_, hull_acc);
6476  hull_center_ = get<RegionCenter>(hull_acc, 1) + coord_min;
6477  hull_volume_ = get<Count>(hull_acc, 1);
6478  // Set initialized flag
6479  initialized_ = true;
6480  }
6481 
6482  /* \brief Finalize the calculation of the convex hull features.
6483 
6484  Finalize must be called in order to trigger the calculation of
6485  the convexity defect features.
6486  */
6487  void finalize()
6488  {
6489  if (!finalized_)
6490  {
6491  dofinalize();
6492  finalized_ = true;
6493  }
6494  }
6495 
6496  void dofinalize()
6497  {
6498  vigra_precondition(
6499  initialized_,
6500  "ConvexHullFeatures::finalize(): "
6501  "Feature computation was not initialized.");
6502  const coord_type & coord_min = getDependency<Coord<Minimum> >(*this);
6503  // Calculate defect center
6506  Select<LabelArg<1>, RegionCenter, Count> > defect_acc;
6507  extractFeatures(label_array_, defect_acc);
6508  defect_center_ = get<RegionCenter>(defect_acc, 1) + coord_min;
6509  // Calculate defect stats
6510  array_type defects_array(label_array_.shape());
6511  defect_count_ = labelMultiArrayWithBackground(
6512  label_array_,
6513  defects_array);
6514  defect_volume_mean_ = 0.0;
6515  defect_volume_variance_ = 0.0;
6516  defect_volume_skewness_ = 0.0;
6517  defect_volume_kurtosis_ = 0.0;
6518  if (defect_count_ != 0)
6519  {
6521  CoupledArrays<dimensions, unsigned int>,
6522  Select<LabelArg<1>, Count, RegionCenter> > defects_acc;
6523  extractFeatures(defects_array, defects_acc);
6524  ArrayVector<double> defect_volumes;
6525  point_type center = getDependency<RegionCenter>(*this)
6526  -getDependency<Coord<Minimum> >(*this);
6527  for (int k = 1; k <= defect_count_; k++)
6528  {
6529  defect_volumes.push_back(get<Count>(defects_acc, k));
6530  defect_displacement_mean_ += get<Count>(defects_acc, k)
6531  * norm(get<RegionCenter>(defects_acc, k) - center);
6532  }
6533  defect_displacement_mean_ /= get<Count>(defect_acc, 1);
6536  Select< Mean,
6539  UnbiasedKurtosis> > volumes_acc;
6541  defect_volumes.begin(),
6542  defect_volumes.end(),
6543  volumes_acc);
6544  defect_volume_mean_ = get<Mean>(volumes_acc);
6545  if (defect_count_ > 1)
6546  {
6547  defect_volume_variance_ = get<UnbiasedVariance>(volumes_acc);
6548  }
6549  if (defect_count_ > 2)
6550  {
6551  defect_volume_skewness_ = get<UnbiasedSkewness>(volumes_acc);
6552  }
6553  if (defect_count_ > 3)
6554  {
6555  defect_volume_kurtosis_ = get<UnbiasedKurtosis>(volumes_acc);
6556  }
6557  }
6558  }
6559 
6560  void operator+=(Impl const &)
6561  {
6562  vigra_precondition(
6563  false,
6564  "ConvexHullFeatures::operator+=(): features cannot be merged.");
6565  }
6566 
6567  result_type operator()() const
6568  {
6569  vigra_precondition(
6570  finalized_,
6571  "ConvexHullFeatures::operator(): "
6572  "Finalize must be called before operator()");
6573  return *this;
6574  }
6575 
6576  /** \brief Center of the input region.
6577  */
6578  const point_type & inputCenter() const {
6579  return getDependency<RegionCenter>(*this);
6580  }
6581 
6582  /** \brief Center of the convex hull of the input region.
6583  */
6584  const point_type & hullCenter() const {
6585  return hull_center_;
6586  }
6587 
6588  /** \brief Volume of the input region.
6589  */
6590  int inputVolume() const {
6591  return getDependency<Count>(*this);
6592  }
6593 
6594  /** \brief Volume of the convex hull of the input region.
6595  */
6596  int hullVolume() const {
6597  return hull_volume_;
6598  }
6599 
6600  /** \brief Weighted center of mass of the convexity defects.
6601  */
6602  const point_type & defectCenter() const {
6603  return defect_center_;
6604  }
6605 
6606  /** \brief Average volume of the convexity defects.
6607  */
6608  double defectVolumeMean() const {
6609  return defect_volume_mean_;
6610  }
6611 
6612  /** \brief Variance of the volumes of the convexity defects.
6613  */
6614  double defectVolumeVariance() const {
6615  return defect_volume_variance_;
6616  }
6617 
6618  /** \brief Skewness of the volumes of the convexity defects.
6619  */
6620  double defectVolumeSkewness() const {
6621  return defect_volume_skewness_;
6622  }
6623 
6624  /** \brief Kurtosis of the volumes of the convexity defects.
6625  */
6626  double defectVolumeKurtosis() const {
6627  return defect_volume_kurtosis_;
6628  }
6629 
6630  /** \brief Number of convexity defects.
6631  */
6632  int defectCount() const {
6633  return defect_count_;
6634  }
6635 
6636  /** \brief Average displacement of the convexity defects from the input
6637  region center weighted by their size.
6638  */
6639  double defectDisplacementMean() const {
6640  return defect_displacement_mean_;
6641  }
6642 
6643  /** \brief Convexity of the input region
6644 
6645  The convexity is the ratio of the input volume to the convex hull
6646  volume: \f[c = \frac{V_\mathrm{input}}{V_\mathrm{hull}}\f]
6647  */
6648  double convexity() const {
6649  return static_cast<double>(inputVolume()) / hullVolume();
6650  }
6651  };
6652 };
6653 #endif // WITH_LEMON
6654 
6655 }} // namespace vigra::acc
6656 
6657 #endif // VIGRA_ACCUMULATOR_HXX
CoupledHandleCast< TARGET_INDEX, Handle >::reference get(Handle &handle)
Definition: multi_handle.hxx:927
void operator+=(AccumulatorChainArray const &o)
Definition: accumulator.hxx:2428
Basic statistic. Data value where weight assumes its minimal value.
Definition: accumulator.hxx:5384
Basic statistic. PowerSum<N> = .
Definition: accumulator-grammar.hxx:59
PowerSum< 0 > Count
Alias. Count.
Definition: accumulator-grammar.hxx:157
Basic statistic. First data value seen of the object.
Definition: accumulator.hxx:5285
ArrayVector< std::string > activeNames() const
Definition: accumulator.hxx:2206
const point_type & inputCenter() const
Center of the input region.
Definition: accumulator.hxx:6578
Basic statistic. Maximum value.
Definition: accumulator.hxx:5206
Compute the eccentricity of a 2D region in terms of its prinipal radii.
Definition: accumulator.hxx:6237
unsigned int passesRequired() const
Definition: accumulator.hxx:2605
double convexity() const
Convexity of the input region.
Definition: accumulator.hxx:6648
void extractContour(MultiArrayView< 2, T, S > const &label_image, Shape2 const &anchor_point, PointArray &contour_points)
Create a polygon from the interpixel contour of a labeled region.
Definition: polygon.hxx:766
Return both the minimum and maximum in std::pair.
Definition: accumulator.hxx:5353
double defectVolumeMean() const
Average volume of the convexity defects.
Definition: accumulator.hxx:6608
Basic statistic. Skewness.
Definition: accumulator.hxx:4445
unsigned int passesRequired() const
Definition: accumulator.hxx:2217
void reshape(TinyVector< U, N > const &s)
Definition: accumulator.hxx:2054
Compute the convex hull of a region.
Definition: accumulator.hxx:6275
Basic statistic. Identity matrix of appropriate size.
Definition: accumulator.hxx:3846
ArrayVector< std::string > activeNames() const
Definition: accumulator.hxx:2595
const_iterator begin() const
Definition: array_vector.hxx:223
void setMaxRegionLabel(unsigned label)
Definition: accumulator.hxx:2407
Compute object features related to the convex hull.
Definition: accumulator.hxx:6379
void setCoordinateOffset(SHAPE const &offset)
MultiArrayIndex ignoredLabel() const
Definition: accumulator.hxx:2400
Basic statistic. Kurtosis.
Definition: accumulator.hxx:4517
Basic statistic. Unbiased Kurtosis.
Definition: accumulator.hxx:4553
Main MultiArray class containing the memory management.
Definition: multi_array.hxx:2474
void activateAll()
Definition: accumulator.hxx:2182
double defectVolumeSkewness() const
Skewness of the volumes of the convexity defects.
Definition: accumulator.hxx:6620
LookupTag< TAG, A >::reference getAccumulator(A &a)
Definition: accumulator.hxx:2910
void merge(AccumulatorChainImpl const &o)
Create an accumulator chain containing the selected statistics and their dependencies.
Definition: accumulator.hxx:2042
Basic statistic. Flattened uppter-triangular part of scatter matrix.
Definition: accumulator.hxx:4649
Modifier. Substract mean before computing statistic.
Definition: accumulator-grammar.hxx:151
DivideUnbiased< Central< PowerSum< 2 > > > UnbiasedVariance
Alias. Unbiased variance.
Definition: accumulator-grammar.hxx:199
Wrapper for MakeTypeList that additionally performs tag standardization.
Definition: accumulator.hxx:398
std::ptrdiff_t MultiArrayIndex
Definition: multi_fwd.hxx:60
bool isActive(A const &a)
Definition: accumulator.hxx:3005
Create an array of dynamic accumulator chains containing the selected per-region and global statistic...
Definition: accumulator.hxx:2550
void setCoordinateOffset(MultiArrayIndex k, SHAPE const &offset)
Definition: accumulator.hxx:2480
void reset(unsigned int reset_to_pass=0)
double defectVolumeVariance() const
Variance of the volumes of the convexity defects.
Definition: accumulator.hxx:6614
bool isActive(std::string tag) const
Definition: accumulator.hxx:2578
const point_type & hullCenter() const
Center of the convex hull of the input region.
Definition: accumulator.hxx:6584
void activate(std::string tag)
Definition: accumulator.hxx:2166
bool isActive() const
Definition: accumulator.hxx:2589
FFTWComplex< R >::NormType norm(const FFTWComplex< R > &a)
norm (= magnitude)
Definition: fftw3.hxx:1037
bool isActive() const
Definition: accumulator.hxx:2199
Compute the contour of a 2D region.
Definition: accumulator.hxx:6099
Definition: array_vector.hxx:58
FFTWComplex< R > & operator+=(FFTWComplex< R > &a, const FFTWComplex< R > &b)
add-assignment
Definition: fftw3.hxx:859
NumericTraits< T >::Promote sq(T t)
The square function.
Definition: mathutil.hxx:382
DivideByCount< Sum > Mean
Alias. Mean.
Definition: accumulator-grammar.hxx:173
unsigned int labelMultiArrayWithBackground(...)
Find the connected components of a MultiArray with arbitrary many dimensions, excluding the backgroun...
void activate()
Definition: accumulator.hxx:2565
Basic statistic. Unbiased Skewness.
Definition: accumulator.hxx:4481
NumericTraits< V >::Promote prod(TinyVectorBase< V, SIZE, D1, D2 > const &l)
product of the vector's elements
Definition: tinyvector.hxx:2097
void activate()
Definition: accumulator.hxx:2175
Coord< Mean > RegionCenter
Alias. Region center.
Definition: accumulator-grammar.hxx:223
bool symmetricEigensystem(MultiArrayView< 2, T, C1 > const &a, MultiArrayView< 2, T, C2 > &ew, MultiArrayView< 2, T, C3 > &ev)
Definition: eigensystem.hxx:1008
void merge(AccumulatorChainArray const &o)
Definition: accumulator.hxx:2444
std::string asString(T t)(...)
iterator begin()
Definition: tinyvector.hxx:861
void extractFeatures(...)
void activateAll()
Definition: accumulator.hxx:2571
static ArrayVector< std::string > const & tagNames()
Definition: accumulator.hxx:2465
void operator+=(AccumulatorChainImpl const &o)
void updatePassN(T const &t, unsigned int N)
Iterator argMax(Iterator first, Iterator last)
Find the maximum element in a sequence.
Definition: algorithm.hxx:96
Definition: multi_iterator_coupled.hxx:729
Create an accumulator chain that works independently of a MultiArray.
Definition: accumulator.hxx:2318
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
std::string normalizeString(std::string const &s)
Definition: utilities.hxx:110
Create an accumulator chain that works independently of a MultiArray.
Definition: accumulator.hxx:2268
void updatePassN(T const &t, unsigned int N)
unsigned int regionCount() const
Definition: accumulator.hxx:2421
int defectCount() const
Number of convexity defects.
Definition: accumulator.hxx:6632
PowerSum< 1 > Sum
Alias. Sum.
Definition: accumulator-grammar.hxx:168
virtual unsigned int fill(MultiArrayView< N, unsigned int > &array, const unsigned int label, const point_view_type offset, const point_view_type scale) const
Definition: polytope.hxx:247
Class for fixed size vectors.This class contains an array of size SIZE of the specified VALUETYPE...
Definition: accessor.hxx:940
Result type of the covex hull feature calculation.
Definition: accumulator.hxx:6392
Definition: multi_fwd.hxx:115
void ignoreLabel(MultiArrayIndex l)
Definition: accumulator.hxx:2393
int hullVolume() const
Volume of the convex hull of the input region.
Definition: accumulator.hxx:6596
unsigned int passesRequired() const
Definition: accumulator.hxx:4819
void setHistogramOptions(HistogramOptions const &options)
Modifier. Project onto PCA eigenvectors.
Definition: accumulator-grammar.hxx:152
Basic statistic. Data where weight assumes its maximal value.
Definition: accumulator.hxx:5459
int inputVolume() const
Volume of the input region.
Definition: accumulator.hxx:6590
bool isActive(std::string tag) const
Definition: accumulator.hxx:2188
static ArrayVector< std::string > const & tagNames()
Definition: accumulator.hxx:2064
FFTWComplex< R >::NormType abs(const FFTWComplex< R > &a)
absolute value (= magnitude)
Definition: fftw3.hxx:1002
Base class for, and view to, vigra::MultiArray.
Definition: multi_array.hxx:704
void merge(unsigned i, unsigned j)
Definition: accumulator.hxx:2435
void activate(std::string tag)
Definition: accumulator.hxx:2557
double defectDisplacementMean() const
Average displacement of the convexity defects from the input region center weighted by their size...
Definition: accumulator.hxx:6639
MultiArrayIndex maxRegionLabel() const
Definition: accumulator.hxx:2414
const_iterator end() const
Definition: array_vector.hxx:237
Compute the perimeter of a 2D region.
Definition: accumulator.hxx:6172
void merge(AccumulatorChainArray const &o, ArrayLike const &labelMapping)
Definition: accumulator.hxx:2456
const point_type & defectCenter() const
Weighted center of mass of the convexity defects.
Definition: accumulator.hxx:6602
Modifier. Divide statistic by Count: DivideByCount<TAG> = TAG / Count .
Definition: accumulator-grammar.hxx:139
void activate(A &a)
Definition: accumulator.hxx:2994
double defectVolumeKurtosis() const
Kurtosis of the volumes of the convexity defects.
Definition: accumulator.hxx:6626
void setHistogramOptions(HistogramOptions const &options)
int floor(FixedPoint< IntBits, FracBits > v)
rounding down.
Definition: fixedpoint.hxx:667
Basic statistic. Minimum value.
Definition: accumulator.hxx:5128
Create a dynamic accumulator chain containing the selected statistics and their dependencies.
Definition: accumulator.hxx:2157
Compute the circularity of a 2D region.
Definition: accumulator.hxx:6205
Modifier. Compute statistic from pixel coordinates rather than from pixel values. ...
Definition: accumulator-grammar.hxx:145
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616
Create an array of accumulator chains containing the selected per-region and global statistics and th...
Definition: accumulator.hxx:2379
Set histogram options.
Definition: histogram.hxx:49

© 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.11.1 (Fri May 19 2017)