vigra - vigra/accumulator.hxx Source File

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

accumulator.hxx |

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

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany | html generated using doxygen and Python vigra 1.10.0 (Thu Jan 8 2015)