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 
namevigra::acc::AccumulatorBegin434     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 
name()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 
name()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>
execvigra::acc::acc_detail::ActivateDependencies599     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>
execvigra::acc::acc_detail::ActivateDependencies606     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>
execvigra::acc::acc_detail::ActivateDependencies617     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>
execvigra::acc::acc_detail::ActivateDependencies628     static void exec(ActiveFlags &)
629     {}
630 
631     template <class Chain, class ActiveFlags, class GlobalFlags>
execvigra::acc::acc_detail::ActivateDependencies632     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>
execvigra::acc::acc_detail::CollectAccumulatorNames707     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>
execvigra::acc::acc_detail::CollectAccumulatorNames719     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>
execvigra::acc::acc_detail::ApplyVisitorToTag730     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>
execvigra::acc::acc_detail::ApplyVisitorToTag749     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>
execvigra::acc::acc_detail::ActivateTag_Visitor758     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>
execvigra::acc::acc_detail::TagIsActive_Visitor769     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>
execvigra::acc::acc_detail::SetHistogramBincount785     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>
execvigra::acc::acc_detail::SetHistogramBincount793     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>
execvigra::acc::acc_detail::ApplyHistogramOptions803     static void exec(Accu &, HistogramOptions const &)
804     {}
805 };
806 
807 template <class TAG>
808 struct ApplyHistogramOptions<StandardQuantiles<TAG> >
809 {
810     template <class Accu>
execvigra::acc::acc_detail::ApplyHistogramOptions811     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>
execvigra::acc::acc_detail::ApplyHistogramOptions824     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>
execvigra::acc::acc_detail::ApplyHistogramOptions834     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>
execvigra::acc::acc_detail::ApplyHistogramOptions846     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>
execvigra::acc::acc_detail::ApplyHistogramOptions858     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>
setGlobalAccumulatorvigra::acc::acc_detail::AccumulatorEndImpl902     void setGlobalAccumulator(GlobalAccumulator const * a)
903     {
904         globalAccumulator_.pointer_ = a;
905     }
906 
namevigra::acc::acc_detail::AccumulatorEndImpl907     static std::string name()
908     {
909         return "AccumulatorEnd (internal)";
910     }
911 
operator ()vigra::acc::acc_detail::AccumulatorEndImpl912     bool operator()() const { return false; }
getvigra::acc::acc_detail::AccumulatorEndImpl913     bool get() const { return false; }
914 
915     template <unsigned, class U>
passvigra::acc::acc_detail::AccumulatorEndImpl916     void pass(U const &)
917     {}
918 
919     template <unsigned, class U>
passvigra::acc::acc_detail::AccumulatorEndImpl920     void pass(U const &, double)
921     {}
922 
923     template <class U>
mergeImplvigra::acc::acc_detail::AccumulatorEndImpl924     void mergeImpl(U const &)
925     {}
926 
927     template <class U>
resizevigra::acc::acc_detail::AccumulatorEndImpl928     void resize(U const &)
929     {}
930 
931     template <class U>
setCoordinateOffsetImplvigra::acc::acc_detail::AccumulatorEndImpl932     void setCoordinateOffsetImpl(U const &)
933     {}
934 
activatevigra::acc::acc_detail::AccumulatorEndImpl935     void activate()
936     {}
937 
isActivevigra::acc::acc_detail::AccumulatorEndImpl938     bool isActive() const
939     {
940         return false;
941     }
942 
943     template <class Flags>
activateImplvigra::acc::acc_detail::AccumulatorEndImpl944     static void activateImpl(Flags &)
945     {}
946 
947     template <class Accu, class Flags1, class Flags2>
activateImplvigra::acc::acc_detail::AccumulatorEndImpl948     static void activateImpl(Flags1 &, Flags2 &)
949     {}
950 
951     template <class Flags>
isActiveImplvigra::acc::acc_detail::AccumulatorEndImpl952     static bool isActiveImpl(Flags const &)
953     {
954         return true;
955     }
956 
applyHistogramOptionsvigra::acc::acc_detail::AccumulatorEndImpl957     void applyHistogramOptions(HistogramOptions const &)
958     {}
959 
passesRequiredvigra::acc::acc_detail::AccumulatorEndImpl960     static unsigned int passesRequired()
961     {
962         return 0;
963     }
964 
passesRequiredvigra::acc::acc_detail::AccumulatorEndImpl965     static unsigned int passesRequired(AccumulatorFlags const &)
966     {
967         return 0;
968     }
969 
resetvigra::acc::acc_detail::AccumulatorEndImpl970     void reset()
971     {
972         active_accumulators_.clear();
973         is_dirty_.clear();
974     }
975 
976     template <int which>
setDirtyImplvigra::acc::acc_detail::AccumulatorEndImpl977     void setDirtyImpl() const
978     {
979         is_dirty_.template set<which>();
980     }
981 
982     template <int which>
setCleanImplvigra::acc::acc_detail::AccumulatorEndImpl983     void setCleanImpl() const
984     {
985         is_dirty_.template reset<which>();
986     }
987 
988     template <int which>
isDirtyImplvigra::acc::acc_detail::AccumulatorEndImpl989     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>
execvigra::acc::acc_detail::DecoratorImpl1000     static void exec(A &, T const &)
1001     {}
1002 
1003     template <class T>
execvigra::acc::acc_detail::DecoratorImpl1004     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>
execvigra::acc::acc_detail::DecoratorImpl1012     static void exec(A & a, T const & t)
1013     {
1014         a.update(t);
1015     }
1016 
1017     template <class T>
execvigra::acc::acc_detail::DecoratorImpl1018     static void exec(A & a, T const & t, double weight)
1019     {
1020         a.update(t, weight);
1021     }
1022 
getvigra::acc::acc_detail::DecoratorImpl1023     static typename A::result_type get(A const & a)
1024     {
1025         return a();
1026     }
1027 
mergeImplvigra::acc::acc_detail::DecoratorImpl1028     static void mergeImpl(A & a, A const & o)
1029     {
1030         a += o;
1031     }
1032 
1033     template <class T>
resizevigra::acc::acc_detail::DecoratorImpl1034     static void resize(A & a, T const & t)
1035     {
1036         a.reshape(t);
1037     }
1038 
applyHistogramOptionsvigra::acc::acc_detail::DecoratorImpl1039     static void applyHistogramOptions(A & a, HistogramOptions const & options)
1040     {
1041         ApplyHistogramOptions<typename A::Tag>::exec(a, options);
1042     }
1043 
passesRequiredvigra::acc::acc_detail::DecoratorImpl1044     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 {
isActivevigra::acc::acc_detail::DecoratorImpl1054     static bool isActive(A const & a)
1055     {
1056         return A::isActiveImpl(getAccumulator<AccumulatorEnd>(a).active_accumulators_);
1057     }
1058 
1059     template <class T>
execvigra::acc::acc_detail::DecoratorImpl1060     static void exec(A & a, T const & t)
1061     {
1062         if(isActive(a))
1063             a.update(t);
1064     }
1065 
1066     template <class T>
execvigra::acc::acc_detail::DecoratorImpl1067     static void exec(A & a, T const & t, double weight)
1068     {
1069         if(isActive(a))
1070             a.update(t, weight);
1071     }
1072 
getvigra::acc::acc_detail::DecoratorImpl1073     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 
mergeImplvigra::acc::acc_detail::DecoratorImpl1084     static void mergeImpl(A & a, A const & o)
1085     {
1086         if(isActive(a))
1087             a += o;
1088     }
1089 
1090     template <class T>
resizevigra::acc::acc_detail::DecoratorImpl1091     static void resize(A & a, T const & t)
1092     {
1093         if(isActive(a))
1094             a.reshape(t);
1095     }
1096 
applyHistogramOptionsvigra::acc::acc_detail::DecoratorImpl1097     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>
passesRequiredvigra::acc::acc_detail::DecoratorImpl1104     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>
reshapeImpl(T &,Shape const &)1116 void reshapeImpl(T &, Shape const &)
1117 {}
1118 
1119 template <class T, class Shape, class Initial>
reshapeImpl(T &,Shape const &,Initial const &=T ())1120 void reshapeImpl(T &, Shape const &, Initial const & = T())
1121 {}
1122 
1123 template <unsigned int N, class T, class Alloc, class Shape>
reshapeImpl(MultiArray<N,T,Alloc> & a,Shape const & s,T const & initial=T ())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>
reshapeImpl(Matrix<T,Alloc> & a,Shape const & s,T const & initial=T ())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>
copyShapeImpl(T const &,U const &)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>
copyShapeImpl(MultiArray<N,T,Alloc> const & from,U & to)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>
copyShapeImpl(Matrix<T,Alloc> const & from,U & to)1146 void copyShapeImpl(Matrix<T, Alloc> const & from, U & to)
1147 {
1148     to.reshape(from.shape());
1149 }
1150 
1151 template <class T, class U>
hasDataImpl(T const &)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>
hasDataImpl(MultiArrayView<N,T,Stride> const & a)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
shapeOf(MultiArrayView<N,T,Stride> const & a)1166 shapeOf(MultiArrayView<N, T, Stride> const & a)
1167 {
1168     return a.shape();
1169 }
1170 
1171 template <class T, int N>
1172 inline Shape1
shapeOf(TinyVector<T,N> const &)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 &
shapeOf(CoupledHandle<T,NEXT> const & t)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 
activatevigra::acc::acc_detail::LabelDispatch::ActivateImpl1264         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 
isActivevigra::acc::acc_detail::LabelDispatch::ActivateImpl1273         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     {
activatevigra::acc::acc_detail::LabelDispatch::ActivateImpl1282         static void activate(GlobalAccumulatorChain & globals, RegionAccumulatorArray &, ActiveFlagsType &)
1283         {
1284             LookupTag<TAG, GlobalAccumulatorChain>::type::activateImpl(getAccumulator<AccumulatorEnd>(globals).active_accumulators_);
1285         }
1286 
isActivevigra::acc::acc_detail::LabelDispatch::ActivateImpl1287         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     {
activatevigra::acc::acc_detail::LabelDispatch::ActivateImpl1296         static void activate(GlobalAccumulatorChain &, RegionAccumulatorArray &, ActiveFlagsType &)
1297         {}
1298 
isActivevigra::acc::acc_detail::LabelDispatch::ActivateImpl1299         static bool isActive(GlobalAccumulatorChain const & globals, ActiveFlagsType const &)
1300         {
1301             return getAccumulator<LabelArg<INDEX> >(globals).isActive();
1302         }
1303     };
1304 
LabelDispatchvigra::acc::acc_detail::LabelDispatch1305     LabelDispatch()
1306     : next_(),
1307       regions_(),
1308       region_histogram_options_(),
1309       ignore_label_(-1),
1310       active_region_accumulators_()
1311     {}
1312 
LabelDispatchvigra::acc::acc_detail::LabelDispatch1313     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 
maxRegionLabelvigra::acc::acc_detail::LabelDispatch1326     MultiArrayIndex maxRegionLabel() const
1327     {
1328         return (MultiArrayIndex)regions_.size() - 1;
1329     }
1330 
setMaxRegionLabelvigra::acc::acc_detail::LabelDispatch1331     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 
ignoreLabelvigra::acc::acc_detail::LabelDispatch1346     void ignoreLabel(MultiArrayIndex l)
1347     {
1348         ignore_label_ = l;
1349     }
1350 
ignoredLabelvigra::acc::acc_detail::LabelDispatch1351     MultiArrayIndex ignoredLabel() const
1352     {
1353         return ignore_label_;
1354     }
1355 
applyHistogramOptionsvigra::acc::acc_detail::LabelDispatch1356     void applyHistogramOptions(HistogramOptions const & options)
1357     {
1358         applyHistogramOptions(options, options);
1359     }
1360 
applyHistogramOptionsvigra::acc::acc_detail::LabelDispatch1361     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 
setCoordinateOffsetImplvigra::acc::acc_detail::LabelDispatch1372     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 
setCoordinateOffsetImplvigra::acc::acc_detail::LabelDispatch1382     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>
resizevigra::acc::acc_detail::LabelDispatch1390     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>
passvigra::acc::acc_detail::LabelDispatch1411     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>
passvigra::acc::acc_detail::LabelDispatch1422     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 
passesRequiredvigra::acc::acc_detail::LabelDispatch1432     static unsigned int passesRequired()
1433     {
1434         return std::max(GlobalAccumulatorChain::passesRequired(), RegionAccumulatorChain::passesRequired());
1435     }
1436 
passesRequiredDynamicvigra::acc::acc_detail::LabelDispatch1437     unsigned int passesRequiredDynamic() const
1438     {
1439         return std::max(GlobalAccumulatorChain::passesRequired(getAccumulator<AccumulatorEnd>(next_).active_accumulators_),
1440                         RegionAccumulatorChain::passesRequired(active_region_accumulators_));
1441     }
1442 
resetvigra::acc::acc_detail::LabelDispatch1443     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>
activatevigra::acc::acc_detail::LabelDispatch1455     void activate()
1456     {
1457         ActivateImpl<TAG>::activate(next_, regions_, active_region_accumulators_);
1458     }
1459 
activateAllvigra::acc::acc_detail::LabelDispatch1460     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>
isActivevigra::acc::acc_detail::LabelDispatch1469     bool isActive() const
1470     {
1471         return ActivateImpl<TAG>::isActive(next_, active_region_accumulators_);
1472     }
1473 
mergeImplvigra::acc::acc_detail::LabelDispatch1474     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 
mergeImplvigra::acc::acc_detail::LabelDispatch1481     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>
mergeImplvigra::acc::acc_detail::LabelDispatch1489     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 
namevigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1571         static std::string name()
1572         {
1573             return TAG::name();
1574         }
1575 
1576         template <class ActiveFlags>
activateImplvigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1577         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>
activateImplvigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1585         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>
isActiveImplvigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1593         static bool isActiveImpl(ActiveFlags & flags)
1594         {
1595             return flags.template test<index>();
1596         }
1597 
setDirtyvigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1598         void setDirty() const
1599         {
1600             next_.template setDirtyImpl<index>();
1601         }
1602 
1603         template <int INDEX>
setDirtyImplvigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1604         void setDirtyImpl() const
1605         {
1606             next_.template setDirtyImpl<INDEX>();
1607         }
1608 
setCleanvigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1609         void setClean() const
1610         {
1611             next_.template setCleanImpl<index>();
1612         }
1613 
1614         template <int INDEX>
setCleanImplvigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1615         void setCleanImpl() const
1616         {
1617             next_.template setCleanImpl<INDEX>();
1618         }
1619 
isDirtyvigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1620         bool isDirty() const
1621         {
1622             return next_.template isDirtyImpl<index>();
1623         }
1624 
1625         template <int INDEX>
isDirtyImplvigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1626         bool isDirtyImpl() const
1627         {
1628             return next_.template isDirtyImpl<INDEX>();
1629         }
1630 
resetvigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1631         void reset()
1632         {}
1633 
1634         template <class Shape>
setCoordinateOffsetvigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1635         void setCoordinateOffset(Shape const &)
1636         {}
1637 
1638         template <class Shape>
reshapevigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1639         void reshape(Shape const &)
1640         {}
1641 
operator +=vigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1642         void operator+=(AccumulatorBase const &)
1643         {}
1644 
1645         template <class U>
updatevigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1646         void update(U const &)
1647         {}
1648 
1649         template <class U>
updatevigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1650         void update(U const &, double)
1651         {}
1652 
1653         template <class TargetTag>
1654         typename LookupDependency<TargetTag, ThisType>::result_type
call_getDependencyvigra::acc::acc_detail::AccumulatorFactory::AccumulatorBase1655         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>
resizevigra::acc::acc_detail::AccumulatorFactory::Accumulator1680         void resize(T const & t)
1681         {
1682             this->next_.resize(t);
1683             DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>::resize(*this, t);
1684         }
1685 
resetvigra::acc::acc_detail::AccumulatorFactory::Accumulator1686         void reset()
1687         {
1688             this->next_.reset();
1689             A::reset();
1690         }
1691 
getvigra::acc::acc_detail::AccumulatorFactory::Accumulator1692         typename A::result_type get() const
1693         {
1694             return DecoratorImpl<A, workInPass, allowRuntimeActivation>::get(*this);
1695         }
1696 
1697         template <unsigned N, class T>
passvigra::acc::acc_detail::AccumulatorFactory::Accumulator1698         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>
passvigra::acc::acc_detail::AccumulatorFactory::Accumulator1705         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 
mergeImplvigra::acc::acc_detail::AccumulatorFactory::Accumulator1711         void mergeImpl(Accumulator const & o)
1712         {
1713             DecoratorImpl<Accumulator, Accumulator::workInPass, allowRuntimeActivation>::mergeImpl(*this, o);
1714             this->next_.mergeImpl(o.next_);
1715         }
1716 
applyHistogramOptionsvigra::acc::acc_detail::AccumulatorFactory::Accumulator1717         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>
setCoordinateOffsetImplvigra::acc::acc_detail::AccumulatorFactory::Accumulator1724         void setCoordinateOffsetImpl(SHAPE const & offset)
1725         {
1726             this->setCoordinateOffset(offset);
1727             this->next_.setCoordinateOffsetImpl(offset);
1728         }
1729 
passesRequiredvigra::acc::acc_detail::AccumulatorFactory::Accumulator1730         static unsigned int passesRequired()
1731         {
1732             return DecoratorImpl<Accumulator, workInPass, allowRuntimeActivation>::passesRequired();
1733         }
1734 
1735         template <class ActiveFlags>
passesRequiredvigra::acc::acc_detail::AccumulatorFactory::Accumulator1736         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 
InvalidGlobalAccumulatorHandlevigra::acc::acc_detail::InvalidGlobalAccumulatorHandle1755     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 
GlobalAccumulatorHandlevigra::acc::acc_detail::ConfigureAccumulatorChainArray::GlobalAccumulatorHandle1803         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 
AccumulatorChainImpl()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     */
setHistogramOptions(HistogramOptions const & options)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     */
setHistogramOptions(HistogramOptions const & regionoptions,HistogramOptions const & globaloptions)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>
setCoordinateOffset(SHAPE const & offset)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     */
reset(unsigned int reset_to_pass=0)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>
update(T const & t)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>
update(T const & t,double weight)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     */
operator +=(AccumulatorChainImpl const & o)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     */
merge(AccumulatorChainImpl const & o)1937     void merge(AccumulatorChainImpl const & o)
1938     {
1939         next_.mergeImpl(o.next_);
1940     }
1941 
operator ()() const1942     result_type operator()() const
1943     {
1944         return next_.get();
1945     }
1946 
operator ()(T const & t)1947     void operator()(T const & t)
1948     {
1949         update<1>(t);
1950     }
1951 
operator ()(T const & t,double weight)1952     void operator()(T const & t, double weight)
1953     {
1954         update<1>(t, weight);
1955     }
1956 
updatePass2(T const & t)1957     void updatePass2(T const & t)
1958     {
1959         update<2>(t);
1960     }
1961 
updatePass2(T const & t,double weight)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     */
updatePassN(T const & t,unsigned int N)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     */
updatePassN(T const & t,double weight,unsigned int N)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     */
passesRequired() const2003     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>
2042 class AccumulatorChain
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>
reshape(TinyVector<U,N> const & s)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     */
tagNames()2064     static ArrayVector<std::string> const & tagNames()
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:
collectTagNames()2111     static ArrayVector<std::string> collectTagNames()
2112     {
2113         ArrayVector<std::string> n;
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>
2157 class DynamicAccumulatorChain
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     */
activate(std::string tag)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>
activate()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     */
activateAll()2182     void activateAll()
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     */
isActive(std::string tag) const2188     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>
isActive() const2199     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     */
activeNames() const2206     ArrayVector<std::string> activeNames() const
2207     {
2208         ArrayVector<std::string> res;
2209         for(unsigned k=0; k<DynamicAccumulatorChain::tagNames().size(); ++k)
2210             if(isActive(DynamicAccumulatorChain::tagNames()[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     */
passesRequired() const2217     unsigned int passesRequired() const
2218     {
2219         return InternalBaseType::passesRequired(getAccumulator<AccumulatorEnd>(*this).active_accumulators_);
2220     }
2221 
2222   protected:
2223 
activateImpl(std::string tag)2224     bool activateImpl(std::string tag)
2225     {
2226         return acc_detail::ApplyVisitorToTag<AccumulatorTags>::exec(*this,
2227                                          normalizeString(tag), acc_detail::ActivateTag_Visitor());
2228     }
2229 
isActiveImpl(std::string tag,acc_detail::TagIsActive_Visitor & v) const2230     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>
2268 class StandAloneAccumulatorChain
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;
2277     typedef AccumulatorChain<HandleType, SelectType>  BaseType;
2278 
StandAloneAccumulatorChain()2279     StandAloneAccumulatorChain()
2280     :   BaseType(),
2281         handle_((T const *)0, CoordType(), CoordHandle(CoordType()))
2282     {}
2283 
updatePassN(const T & val,const CoordType & coord,unsigned int p)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>
2318 class StandAloneDataFreeAccumulatorChain
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;
2327     typedef AccumulatorChain<HandleType, SelectType>  BaseType;
2328 
StandAloneDataFreeAccumulatorChain()2329     StandAloneDataFreeAccumulatorChain()
2330     :   BaseType(),
2331         handle_(CoordType())
2332     {}
2333 
2334     template<class IGNORED_DATA>
2335     void
updatePassN(const IGNORED_DATA &,const CoordType & coord,unsigned int p)2336     updatePassN(const IGNORED_DATA &,
2337                 const CoordType & coord,
2338                 unsigned int p)
2339     {
2340         this->updatePassN(coord, p);
2341     }
2342 
2343 
updatePassN(const CoordType & coord,unsigned int p)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>
2379 class AccumulatorChainArray
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     */
ignoreLabel(MultiArrayIndex l)2393     void ignoreLabel(MultiArrayIndex l)
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     */
ignoredLabel() const2400     MultiArrayIndex ignoredLabel() const
2401     {
2402         return this->next_.ignoredLabel();
2403     }
2404 
2405     /** Set the maximum region label (e.g. for merging two accumulator chains).
2406     */
setMaxRegionLabel(unsigned label)2407     void setMaxRegionLabel(unsigned label)
2408     {
2409         this->next_.setMaxRegionLabel(label);
2410     }
2411 
2412     /** Maximum region label. (equal to regionCount() - 1)
2413     */
maxRegionLabel() const2414     MultiArrayIndex maxRegionLabel() const
2415     {
2416         return this->next_.maxRegionLabel();
2417     }
2418 
2419     /** Number of Regions. (equal to maxRegionLabel() + 1)
2420     */
regionCount() const2421     unsigned int regionCount() const
2422     {
2423         return this->next_.regions_.size();
2424     }
2425 
2426     /** Equivalent to <tt>merge(o)</tt>.
2427     */
operator +=(AccumulatorChainArray const & o)2428     void operator+=(AccumulatorChainArray const & o)
2429     {
2430         merge(o);
2431     }
2432 
2433     /** Merge region i with region j.
2434     */
merge(unsigned i,unsigned j)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     */
merge(AccumulatorChainArray const & o)2444     void merge(AccumulatorChainArray const & o)
2445     {
2446         if(maxRegionLabel() == -1)
2447             setMaxRegionLabel(o.maxRegionLabel());
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>
merge(AccumulatorChainArray const & o,ArrayLike const & labelMapping)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     */
tagNames()2465     static ArrayVector<std::string> const & tagNames()
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>
setCoordinateOffset(MultiArrayIndex k,SHAPE const & offset)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:
collectTagNames()2514     static ArrayVector<std::string> collectTagNames()
2515     {
2516         ArrayVector<std::string> n;
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>
2550 class DynamicAccumulatorChainArray
2551 : public AccumulatorChainArray<T, Selected, true>
2552 {
2553   public:
2554     typedef typename DynamicAccumulatorChainArray::AccumulatorTags AccumulatorTags;
2555 
2556     /** \copydoc DynamicAccumulatorChain::activate(std::string tag) */
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>
activate()2565     void activate()
2566     {
2567         this->next_.template activate<TAG>();
2568     }
2569 
2570     /** \copydoc DynamicAccumulatorChain::activateAll() */
activateAll()2571     void 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      */
isActive(std::string tag) const2578     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>
isActive() const2589     bool isActive() const
2590     {
2591         return this->next_.template isActive<TAG>();
2592     }
2593 
2594     /** \copydoc DynamicAccumulatorChain::activeNames() */
activeNames() const2595     ArrayVector<std::string> activeNames() const
2596     {
2597         ArrayVector<std::string> res;
2598         for(unsigned k=0; k<DynamicAccumulatorChainArray::tagNames().size(); ++k)
2599             if(isActive(DynamicAccumulatorChainArray::tagNames()[k]))
2600                 res.push_back(DynamicAccumulatorChainArray::tagNames()[k]);
2601         return res;
2602     }
2603 
2604     /** \copydoc DynamicAccumulatorChain::passesRequired() */
passesRequired() const2605     unsigned int passesRequired() const
2606     {
2607         return this->next_.passesRequiredDynamic();
2608     }
2609 
2610   protected:
2611 
activateImpl(std::string tag)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 
isActiveImpl(std::string tag,acc_detail::TagIsActive_Visitor & v) const2618     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>
execvigra::acc::acc_detail::CastImpl2771     static reference exec(A & a)
2772     {
2773         return CastImpl<Tag, typename A::InternalBaseType::Tag, reference>::exec(a.next_);
2774     }
2775 
2776     template <class A>
execvigra::acc::acc_detail::CastImpl2777     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>
execvigra::acc::acc_detail::CastImpl2787     static reference exec(A & a)
2788     {
2789         return const_cast<reference>(a);
2790     }
2791 
2792     template <class A>
execvigra::acc::acc_detail::CastImpl2793     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>
execvigra::acc::acc_detail::CastImpl2805     static reference exec(A & a)
2806     {
2807         return a;
2808     }
2809 
2810     template <class A>
execvigra::acc::acc_detail::CastImpl2811     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>
execvigra::acc::acc_detail::CastImpl2821     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>
execvigra::acc::acc_detail::CastImpl2831     static reference exec(A & a)
2832     {
2833         return a;
2834     }
2835 
2836     template <class A>
execvigra::acc::acc_detail::CastImpl2837     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>
execvigra::acc::acc_detail::CastImpl2847     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>
execvigra::acc::acc_detail::CastImpl2855     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>
execvigra::acc::acc_detail::CastImpl2865     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>
execvigra::acc::acc_detail::CastImpl2875     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
getAccumulator(A & a)2910 getAccumulator(A & a)
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
getAccumulator(A & a,MultiArrayIndex label)2922 getAccumulator(A & a, MultiArrayIndex label)
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
get(A const & a)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
get(A const & a,MultiArrayIndex label)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
getDependency(A const & a)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
activate(A & a)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
isActive(A const & a)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 */
doxygen_overloaded_function(template<...> void extractFeatures)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>
extractFeatures(MultiArrayView<N,T1,S1> const & a1,ACCUMULATOR & a)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>
extractFeatures(MultiArrayView<N,T1,S1> const & a1,MultiArrayView<N,T2,S2> const & a2,ACCUMULATOR & a)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>
extractFeatures(MultiArrayView<N,T1,S1> const & a1,MultiArrayView<N,T2,S2> const & a2,MultiArrayView<N,T3,S3> const & a3,ACCUMULATOR & a)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>
extractFeatures(MultiArrayView<N,T1,S1> const & a1,MultiArrayView<N,T2,S2> const & a2,MultiArrayView<N,T3,S3> const & a3,MultiArrayView<N,T4,S4> const & a4,ACCUMULATOR & a)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>
extractFeatures(MultiArrayView<N,T1,S1> const & a1,MultiArrayView<N,T2,S2> const & a2,MultiArrayView<N,T3,S3> const & a3,MultiArrayView<N,T4,S4> const & a4,MultiArrayView<N,T5,S5> const & a5,ACCUMULATOR & a)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 
name()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 
name()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 &
getHandlevigra::acc::acc_detail::HandleArgSelectorImpl3305     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
getValuevigra::acc::acc_detail::HandleArgSelectorImpl3312     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 &
getHandlevigra::acc::acc_detail::HandleArgSelectorImpl3328     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
getValuevigra::acc::acc_detail::HandleArgSelectorImpl3335     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 
name()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>
reshapevigra::acc::DataFromHandle::Impl3394         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>
updatevigra::acc::DataFromHandle::Impl3400         void update(CoupledHandle<U, NEXT> const & t)
3401         {
3402             ImplType::update(DataHandle::getValue(t));
3403         }
3404 
3405         template <class U, class NEXT>
updatevigra::acc::DataFromHandle::Impl3406         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 
name()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 
Implvigra::acc::Coord::Impl3444         Impl()
3445         : offset_()
3446         {}
3447 
setCoordinateOffsetvigra::acc::Coord::Impl3448         void setCoordinateOffset(input_type const & offset)
3449         {
3450             offset_ = offset;
3451         }
3452 
3453         using ImplType::reshape;
3454 
3455         template <class U, class NEXT>
reshapevigra::acc::Coord::Impl3456         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>
updatevigra::acc::Coord::Impl3462         void update(CoupledHandle<U, NEXT> const & t)
3463         {
3464             ImplType::update(CoordHandle::getValue(t)+offset_);
3465         }
3466 
3467         template <class U, class NEXT>
updatevigra::acc::Coord::Impl3468         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 
name()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 
name()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>
execvigra::acc::Weighted::WeightIndexSelector3525         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>
execvigra::acc::Weighted::WeightIndexSelector3535         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>
updatevigra::acc::Weighted::Impl3550         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 
name()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 
Implvigra::acc::Centralize::Impl3582         Impl()
3583         : value_()  // call default constructor explicitly to ensure zero initialization
3584         {}
3585 
resetvigra::acc::Centralize::Impl3586         void reset()
3587         {
3588             value_ = element_type();
3589         }
3590 
3591         template <class Shape>
reshapevigra::acc::Centralize::Impl3592         void reshape(Shape const & s)
3593         {
3594             acc_detail::reshapeImpl(value_, s);
3595         }
3596 
updatevigra::acc::Centralize::Impl3597         void update(U const & t) const
3598         {
3599             using namespace vigra::multi_math;
3600             value_ = t - getDependency<Mean>(*this);
3601         }
3602 
updatevigra::acc::Centralize::Impl3603         void update(U const & t, double) const
3604         {
3605             update(t);
3606         }
3607 
operator ()vigra::acc::Centralize::Impl3608         result_type operator()(U const & t) const
3609         {
3610             update(t);
3611             return value_;
3612         }
3613 
operator ()vigra::acc::Centralize::Impl3614         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 
name()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 
operator +=vigra::acc::Central::Impl3647         void operator+=(Impl const &)
3648         {
3649             vigra_precondition(false,
3650                 "Central<...>::operator+=(): not supported.");
3651         }
3652 
3653         template <class T>
updatevigra::acc::Central::Impl3654         void update(T const &)
3655         {
3656             ImplType::update(getDependency<Centralize>(*this));
3657         }
3658 
3659         template <class T>
updatevigra::acc::Central::Impl3660         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 
name()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 
Implvigra::acc::PrincipalProjection::Impl3729         Impl()
3730         : value_()  // call default constructor explicitly to ensure zero initialization
3731         {}
3732 
resetvigra::acc::PrincipalProjection::Impl3733         void reset()
3734         {
3735             value_ = element_type();
3736         }
3737 
3738         template <class Shape>
reshapevigra::acc::PrincipalProjection::Impl3739         void reshape(Shape const & s)
3740         {
3741             acc_detail::reshapeImpl(value_, s);
3742         }
3743 
updatevigra::acc::PrincipalProjection::Impl3744         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 
updatevigra::acc::PrincipalProjection::Impl3754         void update(U const & t, double) const
3755         {
3756             update(t);
3757         }
3758 
operator ()vigra::acc::PrincipalProjection::Impl3759         result_type operator()(U const & t) const
3760         {
3761             getAccumulator<Centralize>(*this).update(t);
3762             update(t);
3763             return value_;
3764         }
3765 
operator ()vigra::acc::PrincipalProjection::Impl3766         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 
name()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 
operator +=vigra::acc::Principal::Impl3799         void operator+=(Impl const &)
3800         {
3801             vigra_precondition(false,
3802                 "Principal<...>::operator+=(): not supported.");
3803         }
3804 
3805         template <class T>
updatevigra::acc::Principal::Impl3806         void update(T const &)
3807         {
3808             ImplType::update(getDependency<PrincipalProjection>(*this));
3809         }
3810 
3811         template <class T>
updatevigra::acc::Principal::Impl3812         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 */
3846 class CoordinateSystem
3847 {
3848   public:
3849     typedef Select<> Dependencies;
3850 
name()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 
Implvigra::acc::CoordinateSystem::Impl3868         Impl()
3869         : value_()  // call default constructor explicitly to ensure zero initialization
3870         {}
3871 
resetvigra::acc::CoordinateSystem::Impl3872         void reset()
3873         {
3874             value_ = element_type();
3875         }
3876 
3877         template <class Shape>
reshapevigra::acc::CoordinateSystem::Impl3878         void reshape(Shape const & s)
3879         {
3880             acc_detail::reshapeImpl(value_, s);
3881         }
3882 
operator ()vigra::acc::CoordinateSystem::Impl3883         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 
SumBaseImplvigra::acc::SumBaseImpl3902     SumBaseImpl()
3903     : value_()  // call default constructor explicitly to ensure zero initialization
3904     {}
3905 
resetvigra::acc::SumBaseImpl3906     void reset()
3907     {
3908         value_ = element_type();
3909     }
3910 
3911     template <class Shape>
reshapevigra::acc::SumBaseImpl3912     void reshape(Shape const & s)
3913     {
3914         acc_detail::reshapeImpl(value_, s);
3915     }
3916 
operator +=vigra::acc::SumBaseImpl3917     void operator+=(SumBaseImpl const & o)
3918     {
3919         value_ += o.value_;
3920     }
3921 
operator ()vigra::acc::SumBaseImpl3922     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 
name()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     {
updatevigra::acc::PowerSum::Impl3946         void update(T const &)
3947         {
3948             ++this->value_;
3949         }
3950 
updatevigra::acc::PowerSum::Impl3951         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 
name()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     {
updatevigra::acc::PowerSum::Impl3976         void update(U const & t)
3977         {
3978             this->value_ += t;
3979         }
3980 
updatevigra::acc::PowerSum::Impl3981         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 
name()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     {
updatevigra::acc::PowerSum::Impl4011         void update(U const & t)
4012         {
4013             using namespace vigra::multi_math;
4014             this->value_ += pow(t, (int)N);
4015         }
4016 
updatevigra::acc::PowerSum::Impl4017         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 
name()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     {
updatevigra::acc::AbsPowerSum::Impl4042         void update(U const & t)
4043         {
4044             using namespace vigra::multi_math;
4045             this->value_ += abs(t);
4046         }
4047 
updatevigra::acc::AbsPowerSum::Impl4048         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 
name()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     {
updatevigra::acc::AbsPowerSum::Impl4077         void update(U const & t)
4078         {
4079             using namespace vigra::multi_math;
4080             this->value_ += pow(abs(t), (int)N);
4081         }
4082 
updatevigra::acc::AbsPowerSum::Impl4083         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 
CachedResultBasevigra::acc::CachedResultBase4101     CachedResultBase()
4102     : value_()  // call default constructor explicitly to ensure zero initialization
4103     {}
4104 
resetvigra::acc::CachedResultBase4105     void reset()
4106     {
4107         value_ = element_type();
4108         this->setClean();
4109     }
4110 
4111     template <class Shape>
reshapevigra::acc::CachedResultBase4112     void reshape(Shape const & s)
4113     {
4114         acc_detail::reshapeImpl(value_, s);
4115     }
4116 
operator +=vigra::acc::CachedResultBase4117     void operator+=(CachedResultBase const &)
4118     {
4119         this->setDirty();
4120     }
4121 
updatevigra::acc::CachedResultBase4122     void update(U const &)
4123     {
4124         this->setDirty();
4125     }
4126 
updatevigra::acc::CachedResultBase4127     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 
name()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 
operator ()vigra::acc::DivideByCount::Impl4156         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 
name()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 
operator ()vigra::acc::DivideUnbiased::Impl4193         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 
name()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 
operator ()vigra::acc::RootDivideByCount::Impl4226         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 
name()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 
operator ()vigra::acc::RootDivideUnbiased::Impl4259         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:
4273     typedef Select<Mean, Count> Dependencies;
4274 
name()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     {
operator +=vigra::acc::Central::Impl4286         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 
updatevigra::acc::Central::Impl4300         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 
updatevigra::acc::Central::Impl4310         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:
4328     typedef Select<Centralize, Count, Mean, Central<PowerSum<2> > > Dependencies;
4329 
name()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 
operator +=vigra::acc::Central::Impl4345         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 
updatevigra::acc::Central::Impl4365         void update(U const &)
4366         {
4367             using namespace vigra::multi_math;
4368             this->value_ += pow(getDependency<Centralize>(*this), 3);
4369         }
4370 
updatevigra::acc::Central::Impl4371         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:
4384     typedef Select<Centralize, Central<PowerSum<3> > > Dependencies;
4385 
name()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 
operator +=vigra::acc::Central::Impl4401         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 
updatevigra::acc::Central::Impl4426         void update(U const &)
4427         {
4428             using namespace vigra::multi_math;
4429             this->value_ += pow(getDependency<Centralize>(*this), 4);
4430         }
4431 
updatevigra::acc::Central::Impl4432         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 */
4445 class Skewness
4446 {
4447   public:
4448     typedef Select<Central<PowerSum<2> >, Central<PowerSum<3> > > Dependencies;
4449 
name()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 
operator ()vigra::acc::Skewness::Impl4466         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 */
4481 class UnbiasedSkewness
4482 {
4483   public:
4484     typedef Select<Skewness> Dependencies;
4485 
name()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 
operator ()vigra::acc::UnbiasedSkewness::Impl4502         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 */
4517 class Kurtosis
4518 {
4519   public:
4520     typedef Select<Central<PowerSum<2> >, Central<PowerSum<4> > > Dependencies;
4521 
name()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 
operator ()vigra::acc::Kurtosis::Impl4538         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 */
4553 class UnbiasedKurtosis
4554 {
4555   public:
4556     typedef Select<Kurtosis> Dependencies;
4557 
name()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 
operator ()vigra::acc::UnbiasedKurtosis::Impl4574         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>
updateFlatScatterMatrix(Scatter & sc,Sum const & s,double w)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>
updateFlatScatterMatrix(double & sc,Sum const & s,double w)4595 void updateFlatScatterMatrix(double & sc, Sum const & s, double w)
4596 {
4597     sc += w*s*s;
4598 }
4599 
4600 template <class Cov, class Scatter>
flatScatterMatrixToScatterMatrix(Cov & cov,Scatter const & sc)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>
flatScatterMatrixToScatterMatrix(double & cov,Scatter const & sc)4616 void flatScatterMatrixToScatterMatrix(double & cov, Scatter const & sc)
4617 {
4618     cov = sc;
4619 }
4620 
4621 template <class Cov, class Scatter>
flatScatterMatrixToCovariance(Cov & cov,Scatter const & sc,double n)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>
flatScatterMatrixToCovariance(double & cov,Scatter const & sc,double n)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 */
4649 class FlatScatterMatrix
4650 {
4651   public:
4652     typedef Select<Mean, Count> Dependencies;
4653 
name()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 
Implvigra::acc::FlatScatterMatrix::Impl4674         Impl()
4675         : value_(),  // call default constructor explicitly to ensure zero initialization
4676           diff_()
4677         {}
4678 
resetvigra::acc::FlatScatterMatrix::Impl4679         void reset()
4680         {
4681             value_ = element_type();
4682         }
4683 
4684         template <class Shape>
reshapevigra::acc::FlatScatterMatrix::Impl4685         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 
operator +=vigra::acc::FlatScatterMatrix::Impl4692         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 
updatevigra::acc::FlatScatterMatrix::Impl4708         void update(U const & t)
4709         {
4710             compute(t);
4711         }
4712 
updatevigra::acc::FlatScatterMatrix::Impl4713         void update(U const & t, double weight)
4714         {
4715             compute(t, weight);
4716         }
4717 
operator ()vigra::acc::FlatScatterMatrix::Impl4718         result_type operator()() const
4719         {
4720             return value_;
4721         }
4722 
4723       private:
computevigra::acc::FlatScatterMatrix::Impl4724         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 <>
4739 class DivideByCount<FlatScatterMatrix>
4740 {
4741   public:
4742     typedef Select<FlatScatterMatrix, Count> Dependencies;
4743 
name()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>
reshapevigra::acc::DivideByCount::Impl4759         void reshape(Shape const & s)
4760         {
4761             int size = prod(s);
4762             acc_detail::reshapeImpl(this->value_, Shape2(size,size));
4763         }
4764 
operator ()vigra::acc::DivideByCount::Impl4765         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 
name()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>
reshapevigra::acc::DivideUnbiased::Impl4799         void reshape(Shape const & s)
4800         {
4801             int size = prod(s);
4802             acc_detail::reshapeImpl(this->value_, Shape2(size,size));
4803         }
4804 
operator ()vigra::acc::DivideUnbiased::Impl4805         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 */
4819 class ScatterMatrixEigensystem
4820 {
4821   public:
4822     typedef Select<FlatScatterMatrix> Dependencies;
4823 
name()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 
Implvigra::acc::ScatterMatrixEigensystem::Impl4843         Impl()
4844         : value_()
4845         {}
4846 
operator +=vigra::acc::ScatterMatrixEigensystem::Impl4847         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 
updatevigra::acc::ScatterMatrixEigensystem::Impl4857         void update(U const &)
4858         {
4859             this->setDirty();
4860         }
4861 
updatevigra::acc::ScatterMatrixEigensystem::Impl4862         void update(U const &, double)
4863         {
4864              this->setDirty();
4865         }
4866 
resetvigra::acc::ScatterMatrixEigensystem::Impl4867         void reset()
4868         {
4869             value_.first = element_type();
4870             value_.second = element_type();
4871             this->setClean();
4872         }
4873 
4874         template <class Shape>
reshapevigra::acc::ScatterMatrixEigensystem::Impl4875         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 
operator ()vigra::acc::ScatterMatrixEigensystem::Impl4882         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>
computevigra::acc::ScatterMatrixEigensystem::Impl4894         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 
computevigra::acc::ScatterMatrixEigensystem::Impl4903         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 <>
4913 class DivideByCount<ScatterMatrixEigensystem>
4914 {
4915   public:
4916     typedef Select<ScatterMatrixEigensystem, Count> Dependencies;
4917 
name()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 
Implvigra::acc::DivideByCount::Impl4938         Impl()
4939         : value_(EigenvalueType(), BASE::template call_getDependency<ScatterMatrixEigensystem>().second)
4940         {}
4941 
operator +=vigra::acc::DivideByCount::Impl4942         void operator+=(Impl const &)
4943         {
4944             this->setDirty();
4945         }
4946 
updatevigra::acc::DivideByCount::Impl4947         void update(U const &)
4948         {
4949             this->setDirty();
4950         }
4951 
updatevigra::acc::DivideByCount::Impl4952         void update(U const &, double)
4953         {
4954              this->setDirty();
4955         }
4956 
resetvigra::acc::DivideByCount::Impl4957         void reset()
4958         {
4959             value_.first = element_type();
4960             this->setClean();
4961         }
4962 
4963         template <class Shape>
reshapevigra::acc::DivideByCount::Impl4964         void reshape(Shape const & s)
4965         {
4966             int size = prod(s);
4967             acc_detail::reshapeImpl(value_.first, Shape2(size,1));
4968         }
4969 
operator ()vigra::acc::DivideByCount::Impl4970         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 <>
5067 class Principal<PowerSum<2> >
5068 {
5069   public:
5070     typedef Select<ScatterMatrixEigensystem> Dependencies;
5071 
name()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 
operator ()vigra::acc::Principal::Impl5086         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 <>
5098 class Principal<CoordinateSystem>
5099 {
5100   public:
5101     typedef Select<ScatterMatrixEigensystem> Dependencies;
5102 
name()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 
operator ()vigra::acc::Principal::Impl5117         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 
name()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 
Implvigra::acc::Minimum::Impl5150         Impl()
5151         {
5152             value_ = NumericTraits<element_type>::max();
5153         }
5154 
resetvigra::acc::Minimum::Impl5155         void reset()
5156         {
5157             value_ = NumericTraits<element_type>::max();
5158         }
5159 
5160         template <class Shape>
reshapevigra::acc::Minimum::Impl5161         void reshape(Shape const & s)
5162         {
5163             acc_detail::reshapeImpl(value_, s, NumericTraits<element_type>::max());
5164         }
5165 
operator +=vigra::acc::Minimum::Impl5166         void operator+=(Impl const & o)
5167         {
5168             updateImpl(o.value_); // necessary because std::min causes ambiguous overload
5169         }
5170 
updatevigra::acc::Minimum::Impl5171         void update(U const & t)
5172         {
5173             updateImpl(t);
5174         }
5175 
updatevigra::acc::Minimum::Impl5176         void update(U const & t, double)
5177         {
5178             updateImpl(t);
5179         }
5180 
operator ()vigra::acc::Minimum::Impl5181         result_type operator()() const
5182         {
5183             return value_;
5184         }
5185 
5186       private:
5187         template <class T>
updateImplvigra::acc::Minimum::Impl5188         void updateImpl(T const & o)
5189         {
5190             using namespace multi_math;
5191             value_ = min(value_, o);
5192         }
5193 
5194         template <class T, class Alloc>
updateImplvigra::acc::Minimum::Impl5195         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 
name()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 
Implvigra::acc::Maximum::Impl5228         Impl()
5229         {
5230             value_ = NumericTraits<element_type>::min();
5231         }
5232 
resetvigra::acc::Maximum::Impl5233         void reset()
5234         {
5235             value_ = NumericTraits<element_type>::min();
5236         }
5237 
5238         template <class Shape>
reshapevigra::acc::Maximum::Impl5239         void reshape(Shape const & s)
5240         {
5241             acc_detail::reshapeImpl(value_, s, NumericTraits<element_type>::min());
5242         }
5243 
operator +=vigra::acc::Maximum::Impl5244         void operator+=(Impl const & o)
5245         {
5246             updateImpl(o.value_); // necessary because std::max causes ambiguous overload
5247         }
5248 
updatevigra::acc::Maximum::Impl5249         void update(U const & t)
5250         {
5251             updateImpl(t);
5252         }
5253 
updatevigra::acc::Maximum::Impl5254         void update(U const & t, double)
5255         {
5256             updateImpl(t);
5257         }
5258 
operator ()vigra::acc::Maximum::Impl5259         result_type operator()() const
5260         {
5261             return value_;
5262         }
5263 
5264       private:
5265         template <class T>
updateImplvigra::acc::Maximum::Impl5266         void updateImpl(T const & o)
5267         {
5268             using namespace multi_math;
5269             value_ = max(value_, o);
5270         }
5271 
5272         template <class T, class Alloc>
updateImplvigra::acc::Maximum::Impl5273         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 */
5285 class FirstSeen
5286 {
5287   public:
5288     typedef Select<Count> Dependencies;
5289 
name()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 
Implvigra::acc::FirstSeen::Impl5307         Impl()
5308         : value_()
5309         {}
5310 
resetvigra::acc::FirstSeen::Impl5311         void reset()
5312         {
5313             value_ = element_type();
5314         }
5315 
5316         template <class Shape>
reshapevigra::acc::FirstSeen::Impl5317         void reshape(Shape const & s)
5318         {
5319             acc_detail::reshapeImpl(value_, s);
5320         }
5321 
operator +=vigra::acc::FirstSeen::Impl5322         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 
updatevigra::acc::FirstSeen::Impl5329         void update(U const & t)
5330         {
5331             if(getDependency<Count>(*this) == 1)
5332                 value_ = t;
5333         }
5334 
updatevigra::acc::FirstSeen::Impl5335         void update(U const & t, double)
5336         {
5337             update(t);
5338         }
5339 
operator ()vigra::acc::FirstSeen::Impl5340         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:
5356     typedef Select<Minimum, Maximum> Dependencies;
5357 
name()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 
operator ()vigra::acc::Range::Impl5373         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 */
5384 class ArgMinWeight
5385 {
5386   public:
5387     typedef Select<> Dependencies;
5388 
name()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 
Implvigra::acc::ArgMinWeight::Impl5407         Impl()
5408         : min_weight_(NumericTraits<double>::max()),
5409           value_()
5410         {}
5411 
resetvigra::acc::ArgMinWeight::Impl5412         void reset()
5413         {
5414             min_weight_ = NumericTraits<double>::max();
5415             value_ = element_type();
5416         }
5417 
5418         template <class Shape>
reshapevigra::acc::ArgMinWeight::Impl5419         void reshape(Shape const & s)
5420         {
5421             acc_detail::reshapeImpl(value_, s);
5422         }
5423 
operator +=vigra::acc::ArgMinWeight::Impl5424         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 
updatevigra::acc::ArgMinWeight::Impl5434         void update(U const &)
5435         {
5436             vigra_precondition(false, "ArgMinWeight::update() needs weights.");
5437         }
5438 
updatevigra::acc::ArgMinWeight::Impl5439         void update(U const & t, double weight)
5440         {
5441             if(weight < min_weight_)
5442             {
5443                 min_weight_ = weight;
5444                 value_ = t;
5445             }
5446         }
5447 
operator ()vigra::acc::ArgMinWeight::Impl5448         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 */
5459 class ArgMaxWeight
5460 {
5461   public:
5462     typedef Select<> Dependencies;
5463 
name()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 
Implvigra::acc::ArgMaxWeight::Impl5482         Impl()
5483         : max_weight_(NumericTraits<double>::min()),
5484           value_()
5485         {}
5486 
resetvigra::acc::ArgMaxWeight::Impl5487         void reset()
5488         {
5489             max_weight_ = NumericTraits<double>::min();
5490             value_ = element_type();
5491         }
5492 
5493         template <class Shape>
reshapevigra::acc::ArgMaxWeight::Impl5494         void reshape(Shape const & s)
5495         {
5496             acc_detail::reshapeImpl(value_, s);
5497         }
5498 
operator +=vigra::acc::ArgMaxWeight::Impl5499         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 
updatevigra::acc::ArgMaxWeight::Impl5509         void update(U const &)
5510         {
5511             vigra_precondition(false, "ArgMaxWeight::update() needs weights.");
5512         }
5513 
updatevigra::acc::ArgMaxWeight::Impl5514         void update(U const & t, double weight)
5515         {
5516             if(weight > max_weight_)
5517             {
5518                 max_weight_ = weight;
5519                 value_ = t;
5520             }
5521         }
5522 
operator ()vigra::acc::ArgMaxWeight::Impl5523         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 
HistogramBase()5544     HistogramBase()
5545     : value_(),
5546       left_outliers(),
5547       right_outliers()
5548     {}
5549 
reset()5550     void reset()
5551     {
5552         value_ = element_type();
5553         left_outliers = 0.0;
5554         right_outliers = 0.0;
5555     }
5556 
operator +=(HistogramBase const & o)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 
operator ()() const5564     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 
HistogramBase()5583     HistogramBase()
5584     : value_(),
5585       left_outliers(),
5586       right_outliers()
5587     {}
5588 
reset()5589     void reset()
5590     {
5591         value_ = element_type();
5592         left_outliers = 0.0;
5593         right_outliers = 0.0;
5594     }
5595 
operator +=(HistogramBase const & o)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 
setBinCount(int binCount)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 
operator ()() const5619     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 
RangeHistogramBase()5632     RangeHistogramBase()
5633     : scale_(),
5634       offset_(),
5635       inverse_scale_()
5636     {}
5637 
reset()5638     void reset()
5639     {
5640         scale_ = 0.0;
5641         offset_ = 0.0;
5642         inverse_scale_ = 0.0;
5643         HistogramBase<BASE, BinCount>::reset();
5644     }
5645 
operator +=(RangeHistogramBase const & o)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 
5651         HistogramBase<BASE, BinCount>::operator+=(o);
5652         if(scale_ == 0.0)
5653         {
5654             scale_ = o.scale_;
5655             offset_ = o.offset_;
5656             inverse_scale_ = o.inverse_scale_;
5657         }
5658     }
5659 
update(U const & t)5660     void update(U const & t)
5661     {
5662         update(t, 1.0);
5663     }
5664 
update(U const & t,double weight)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 
setMinMax(double mi,double ma)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 
mapItem(double t) const5692     double mapItem(double t) const
5693     {
5694         return scale_ * (t - offset_);
5695     }
5696 
mapItemInverse(double t) const5697     double mapItemInverse(double t) const
5698     {
5699         return inverse_scale_ * t + offset_;
5700     }
5701 
5702     template <class ArrayLike>
computeStandardQuantiles(double minimum,double maximum,double count,ArrayLike const & desiredQuantiles,ArrayLike & res) const5703     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 
name()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     {
updatevigra::acc::IntegerHistogram::Impl5814         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 
updatevigra::acc::IntegerHistogram::Impl5824         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>
computeStandardQuantilesvigra::acc::IntegerHistogram::Impl5832         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 
name()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     {
updatevigra::acc::UserRangeHistogram::Impl5927         void update(U const & t)
5928         {
5929             update(t, 1.0);
5930         }
5931 
updatevigra::acc::UserRangeHistogram::Impl5932         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 
name()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 
updatevigra::acc::AutoRangeHistogram::Impl5971         void update(U const & t)
5972         {
5973             update(t, 1.0);
5974         }
5975 
updatevigra::acc::AutoRangeHistogram::Impl5976         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 
name()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 
Implvigra::acc::GlobalRangeHistogram::Impl6017         Impl()
6018         : useLocalMinimax_(false)
6019         {}
6020 
setRegionAutoInitvigra::acc::GlobalRangeHistogram::Impl6021         void setRegionAutoInit(bool locally)
6022         {
6023             this->scale_ = 0.0;
6024             useLocalMinimax_ = locally;
6025         }
6026 
updatevigra::acc::GlobalRangeHistogram::Impl6027         void update(U const & t)
6028         {
6029             update(t, 1.0);
6030         }
6031 
updatevigra::acc::GlobalRangeHistogram::Impl6032         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 
name()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 
operator ()vigra::acc::StandardQuantiles::Impl6075         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  */
6099 class RegionContour
6100 {
6101   public:
6102     typedef Select<Count> Dependencies;
6103 
name()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 
Implvigra::acc::RegionContour::Impl6123         Impl()
6124         : offset_()
6125         , contour_()
6126         {}
6127 
setCoordinateOffsetvigra::acc::RegionContour::Impl6128         void setCoordinateOffset(point_type const & offset)
6129         {
6130             offset_ = offset;
6131         }
6132 
6133         template <class U, class NEXT>
updatevigra::acc::RegionContour::Impl6134         void update(CoupledHandle<U, NEXT> const & t)
6135         {
6136             VIGRA_STATIC_ASSERT((feature_RegionContour_can_only_be_computed_for_2D_arrays<
6137                                  CoupledHandle<U, NEXT>::dimensions>));
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>
updatevigra::acc::RegionContour::Impl6147         void update(CoupledHandle<U, NEXT> const & t, double)
6148         {
6149             update(t);
6150         }
6151 
operator +=vigra::acc::RegionContour::Impl6152         void operator+=(Impl const &)
6153         {
6154             vigra_precondition(false,
6155                 "RegionContour::operator+=(): RegionContour cannot be merged.");
6156         }
6157 
operator ()vigra::acc::RegionContour::Impl6158         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  */
6172 class RegionPerimeter
6173 {
6174   public:
6175     typedef Select<RegionContour> Dependencies;
6176 
name()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 
operator ()vigra::acc::RegionPerimeter::Impl6191         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  */
6205 class RegionCircularity
6206 {
6207   public:
6208     typedef Select<Count, RegionContour> Dependencies;
6209 
name()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 
operator ()vigra::acc::RegionCircularity::Impl6224         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  */
6237 class RegionEccentricity
6238 {
6239   public:
6240     typedef Select<RegionRadii> Dependencies;
6241 
name()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 
operator ()vigra::acc::RegionEccentricity::Impl6256         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  */
6275 class ConvexHull
6276 {
6277   public:
6278     typedef Select<RegionCenter> Dependencies;
6279 
name()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 
Implvigra::acc::ConvexHull::Impl6302         Impl()
6303         : convex_hull_()
6304         , initialized_(false)
6305         {}
6306 
6307         template <class U, class NEXT>
updatevigra::acc::ConvexHull::Impl6308         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>
updatevigra::acc::ConvexHull::Impl6319         void update(CoupledHandle<U, NEXT> const & t, double)
6320         {
6321             update(t);
6322         }
6323 
initializevigra::acc::ConvexHull::Impl6324         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 
operator +=vigra::acc::ConvexHull::Impl6337         void operator+=(Impl const &)
6338         {
6339             vigra_precondition(
6340                     false,
6341                     "ConvexHull::operator+=(): ConvexHull features cannot be merged.");
6342         }
6343 
operator ()vigra::acc::ConvexHull::Impl6344         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 */
6379 class ConvexHullFeatures
6380 {
6381   public:
6382     typedef Select<BoundingBox, RegionCenter, Count, ConvexHull> Dependencies;
6383 
name()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 
6398         typedef ConvexPolytope<dimensions, double>      polytope_type;
6399         typedef Impl<T, BASE>                           value_type;
6400         typedef value_type const &                      result_type;
6401         typedef TinyVector<double, dimensions>          point_type;
6402         typedef HandleArgSelector<T, CoordArgTag, BASE> coord_handle_type;
6403         typedef typename coord_handle_type::value_type  coord_type;
6404 
6405         typedef MultiArray<dimensions, unsigned int> array_type;
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 
Implvigra::acc::ConvexHullFeatures::Impl6421         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>
updatevigra::acc::ConvexHullFeatures::Impl6436         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>
updatevigra::acc::ConvexHullFeatures::Impl6452         void update(CoupledHandle<U, NEXT> const & t, double)
6453         {
6454             update(t);
6455         }
6456 
initializevigra::acc::ConvexHullFeatures::Impl6457         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
6471             AccumulatorChainArray<
6472                     CoupledArrays<dimensions, unsigned int>,
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         */
finalizevigra::acc::ConvexHullFeatures::Impl6487         void finalize()
6488         {
6489             if (!finalized_)
6490             {
6491                 dofinalize();
6492                 finalized_ = true;
6493             }
6494         }
6495 
dofinalizevigra::acc::ConvexHullFeatures::Impl6496         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
6504             AccumulatorChainArray<
6505                     CoupledArrays<dimensions, unsigned int>,
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             {
6520                 AccumulatorChainArray<
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);
6534                 AccumulatorChain<
6535                         MultiArrayIndex,
6536                         Select< Mean,
6537                                 UnbiasedVariance,
6538                                 UnbiasedSkewness,
6539                                 UnbiasedKurtosis> > volumes_acc;
6540                 extractFeatures(
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 
operator +=vigra::acc::ConvexHullFeatures::Impl6560         void operator+=(Impl const &)
6561         {
6562             vigra_precondition(
6563                     false,
6564                     "ConvexHullFeatures::operator+=(): features cannot be merged.");
6565         }
6566 
operator ()vigra::acc::ConvexHullFeatures::Impl6567         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         */
inputCentervigra::acc::ConvexHullFeatures::Impl6578         const point_type & inputCenter() const {
6579             return getDependency<RegionCenter>(*this);
6580         }
6581 
6582         /** \brief Center of the convex hull of the input region.
6583         */
hullCentervigra::acc::ConvexHullFeatures::Impl6584         const point_type & hullCenter() const {
6585             return hull_center_;
6586         }
6587 
6588         /** \brief Volume of the input region.
6589         */
inputVolumevigra::acc::ConvexHullFeatures::Impl6590         int inputVolume() const {
6591             return getDependency<Count>(*this);
6592         }
6593 
6594         /** \brief Volume of the convex hull of the input region.
6595         */
hullVolumevigra::acc::ConvexHullFeatures::Impl6596         int hullVolume() const {
6597             return hull_volume_;
6598         }
6599 
6600         /** \brief Weighted center of mass of the convexity defects.
6601         */
defectCentervigra::acc::ConvexHullFeatures::Impl6602         const point_type & defectCenter() const {
6603             return defect_center_;
6604         }
6605 
6606         /** \brief Average volume of the convexity defects.
6607         */
defectVolumeMeanvigra::acc::ConvexHullFeatures::Impl6608         double defectVolumeMean() const {
6609             return defect_volume_mean_;
6610         }
6611 
6612         /** \brief Variance of the volumes of the convexity defects.
6613         */
defectVolumeVariancevigra::acc::ConvexHullFeatures::Impl6614         double defectVolumeVariance() const {
6615             return defect_volume_variance_;
6616         }
6617 
6618         /** \brief Skewness of the volumes of the convexity defects.
6619         */
defectVolumeSkewnessvigra::acc::ConvexHullFeatures::Impl6620         double defectVolumeSkewness() const {
6621             return defect_volume_skewness_;
6622         }
6623 
6624         /** \brief Kurtosis of the volumes of the convexity defects.
6625         */
defectVolumeKurtosisvigra::acc::ConvexHullFeatures::Impl6626         double defectVolumeKurtosis() const {
6627             return defect_volume_kurtosis_;
6628         }
6629 
6630         /** \brief Number of convexity defects.
6631         */
defectCountvigra::acc::ConvexHullFeatures::Impl6632         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         */
defectDisplacementMeanvigra::acc::ConvexHullFeatures::Impl6639         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         */
convexityvigra::acc::ConvexHullFeatures::Impl6648         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
6658