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

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany | html generated using doxygen and Python vigra 1.11.1 (Fri May 19 2017)