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

multi_pointoperators.hxx VIGRA

1 //-- -*- c++ -*-
2 /************************************************************************/
3 /* */
4 /* Copyright 2003 by Ullrich Koethe, B. Seppke, F. Heinrich */
5 /* */
6 /* This file is part of the VIGRA computer vision library. */
7 /* The VIGRA Website is */
8 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
9 /* Please direct questions, bug reports, and contributions to */
10 /* ullrich.koethe@iwr.uni-heidelberg.de or */
11 /* vigra@informatik.uni-hamburg.de */
12 /* */
13 /* Permission is hereby granted, free of charge, to any person */
14 /* obtaining a copy of this software and associated documentation */
15 /* files (the "Software"), to deal in the Software without */
16 /* restriction, including without limitation the rights to use, */
17 /* copy, modify, merge, publish, distribute, sublicense, and/or */
18 /* sell copies of the Software, and to permit persons to whom the */
19 /* Software is furnished to do so, subject to the following */
20 /* conditions: */
21 /* */
22 /* The above copyright notice and this permission notice shall be */
23 /* included in all copies or substantial portions of the */
24 /* Software. */
25 /* */
26 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
27 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
28 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
29 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
30 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
31 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
32 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
33 /* OTHER DEALINGS IN THE SOFTWARE. */
34 /* */
35 /************************************************************************/
36 
37 #ifndef VIGRA_MULTI_POINTOPERATORS_H
38 #define VIGRA_MULTI_POINTOPERATORS_H
39 
40 #include "initimage.hxx"
41 #include "copyimage.hxx"
42 #include "transformimage.hxx"
43 #include "combineimages.hxx"
44 #include "inspectimage.hxx"
45 #include "multi_array.hxx"
46 #include "metaprogramming.hxx"
47 #include "inspector_passes.hxx"
48 
49 
50 
51 namespace vigra
52 {
53 
54 /** \addtogroup MultiPointoperators Point operators for multi-dimensional arrays.
55 
56  Copy, transform, and inspect arbitrary dimensional arrays which are represented
57  by iterators compatible to \ref MultiIteratorPage. Note that are range is here
58  specified by a pair: an iterator referring to the first point of the array
59  and a shape object specifying the size of the (rectangular) ROI.
60 
61  <b>\#include</b> <vigra/multi_pointoperators.hxx><br/>
62  Namespace: vigra
63 */
64 //@{
65 
66 /********************************************************/
67 /* */
68 /* initMultiArray */
69 /* */
70 /********************************************************/
71 
72 template <class Iterator, class Shape, class Accessor,
73  class VALUETYPE>
74 inline void
75 initMultiArrayImpl(Iterator s, Shape const & shape, Accessor a, VALUETYPE const & v, MetaInt<0>)
76 {
77  initLine(s, s + shape[0], a, v);
78 }
79 
80 template <class Iterator, class Shape, class Accessor,
81  class VALUETYPE, int N>
82 void
83 initMultiArrayImpl(Iterator s, Shape const & shape, Accessor a,
84  VALUETYPE const & v, MetaInt<N>)
85 {
86  Iterator send = s + shape[N];
87  for(; s < send; ++s)
88  {
89  initMultiArrayImpl(s.begin(), shape, a, v, MetaInt<N-1>());
90  }
91 }
92 
93 /** \brief Write a value to every element in a multi-dimensional array.
94 
95  The initial value can either be a constant of appropriate type (compatible with
96  the destination's value_type), or a functor with compatible result_type. These two
97  cases are automatically distinguished when <tt>FunctorTraits<FUNCTOR>::isInitializer</tt>
98  yields <tt>VigraTrueType</tt>. Since the functor is passed by <tt>const</tt> reference, its
99  <tt>operator()</tt> must be const, and its internal state may need to be <tt>mutable</tt>.
100 
101  <b> Declarations:</b>
102 
103  pass arbitrary-dimensional array views:
104  \code
105  namespace vigra {
106  template <unsigned int N, class T, class S, class VALUETYPE>
107  void
108  initMultiArray(MultiArrayView<N, T, S> s, VALUETYPE const & v);
109 
110  template <unsigned int N, class T, class S, class FUNCTOR>
111  void
112  initMultiArray(MultiArrayView<N, T, S> s, FUNCTOR const & f);
113  }
114  \endcode
115 
116  \deprecatedAPI{initMultiArray}
117  pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
118  \code
119  namespace vigra {
120  template <class Iterator, class Shape, class Accessor, class VALUETYPE>
121  void
122  initMultiArray(Iterator s, Shape const & shape, Accessor a, VALUETYPE const & v);
123 
124  template <class Iterator, class Shape, class Accessor, class FUNCTOR>
125  void
126  initMultiArray(Iterator s, Shape const & shape, Accessor a, FUNCTOR const & f);
127  }
128  \endcode
129  use argument objects in conjunction with \ref ArgumentObjectFactories :
130  \code
131  namespace vigra {
132  template <class Iterator, class Shape, class Accessor, class VALUETYPE>
133  void
134  initMultiArray(triple<Iterator, Shape, Accessor> const & s, VALUETYPE const & v);
135 
136 
137  template <class Iterator, class Shape, class Accessor, class FUNCTOR>
138  void
139  initMultiArray(triple<Iterator, Shape, Accessor> const & s, FUNCTOR const & f);
140  }
141  \endcode
142  \deprecatedEnd
143 
144  <b> Usage:</b>
145 
146  <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
147  Namespace: vigra
148 
149  \code
150  MultiArray<3, unsigned int> array(Shape3(100, 200, 50));
151 
152  // make an array of all ones
153  initMultiArray(array, 1);
154 
155  // equivalent calls:
156  array = 1;
157  array.init(1);
158 
159  // fill the array with random numbers
160  #include <vigra/random.hxx>
161 
162  initMultiArray(array, MersenneTwister());
163  \endcode
164 
165  \deprecatedUsage{initMultiArray}
166  \code
167  MultiArray<3, int> array(Shape3(100, 200, 50));
168 
169  // make an array of all twos
170  vigra::initMultiArray(destMultiArrayRange(array), 2);
171  \endcode
172  <b> Required Interface:</b>
173  The function accepts either a value that is copied into every destination element:
174  \code
175  MultiIterator begin;
176 
177  Accessor accessor;
178  VALUETYPE v;
179 
180  accessor.set(v, begin);
181  \endcode
182  or a functor that is called (without argument) at every location,
183  and the result is written into the current element. Internally,
184  functors are recognized by the meta function
185  <tt>FunctorTraits<FUNCTOR>::isInitializer</tt> yielding <tt>VigraTrueType</tt>.
186  Make sure that your functor correctly defines <tt>FunctorTraits</tt> because
187  otherwise the code will not compile.
188  \code
189  MultiIterator begin;
190  Accessor accessor;
191 
192  FUNCTOR f;
193  assert(typeid(FunctorTraits<FUNCTOR>::isInitializer) == typeid(VigraTrueType));
194 
195  accessor.set(f(), begin);
196  \endcode
197  \deprecatedEnd
198 */
199 doxygen_overloaded_function(template <...> void initMultiArray)
200 
201 template <class Iterator, class Shape, class Accessor, class VALUETYPE>
202 inline void
203 initMultiArray(Iterator s, Shape const & shape, Accessor a, VALUETYPE const & v)
204 {
205  initMultiArrayImpl(s, shape, a, v, MetaInt<Iterator::level>());
206 }
207 
208 template <class Iterator, class Shape, class Accessor, class VALUETYPE>
209 inline void
210 initMultiArray(triple<Iterator, Shape, Accessor> const & s, VALUETYPE const & v)
211 {
212  initMultiArrayImpl(s.first, s.second, s.third, v, MetaInt<Iterator::level>());
213 }
214 
215 template <unsigned int N, class T, class S, class VALUETYPE>
216 inline void
217 initMultiArray(MultiArrayView<N, T, S> s, VALUETYPE const & v)
218 {
219  initMultiArray(destMultiArrayRange(s), v);
220 }
221 
222 /********************************************************/
223 /* */
224 /* initMultiArrayBorder */
225 /* */
226 /********************************************************/
227 
228 /** \brief Write values to the specified border values in the array.
229 
230  This functions is similar to \ref initMultiArray(), but it initializes only
231  the array elements whose distance from any array border is at most \a border_width.
232 
233  <b> Declarations:</b>
234 
235  pass arbitrary-dimensional array views:
236  \code
237  namespace vigra {
238  // init equal borders on all array sides
239  template <unsigned int N, class T, class S,
240  class VALUETYPE>
241  void
242  initMultiArrayBorder( MultiArrayView<N, T, S> array,
243  MultiArrayIndex border_width, VALUETYPE const & v);
244 
245  template <unsigned int N, class T, class S,
246  class FUNCTOR>
247  void
248  initMultiArrayBorder( MultiArrayView<N, T, S> array,
249  MultiArrayIndex border_width, FUNCTOR const & v);
250 
251  // specify border width individually for all array sides
252  template <unsigned int N, class T, class S,
253  class VALUETYPE>
254  void
255  initMultiArrayBorder( MultiArrayView<N, T, S> array,
256  typename MultiArrayShape<N>::type const & lower_border,
257  typename MultiArrayShape<N>::type const & upper_border,
258  VALUETYPE const & v);
259  }
260  \endcode
261 
262  \deprecatedAPI{initMultiArrayBorder}
263  pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
264  \code
265  namespace vigra {
266  template <class Iterator, class Diff_type, class Accessor,
267  class VALUETYPE>
268  void
269  initMultiArrayBorder(Iterator upperleft, Diff_type shape, Accessor a,
270  MultiArrayIndex border_width, VALUETYPE const & v);
271  }
272  \endcode
273  use argument objects in conjunction with \ref ArgumentObjectFactories :
274  \code
275  namespace vigra {
276  template <class Iterator, class Diff_type, class Accessor,
277  class VALUETYPE>
278  inline void
279  initMultiArrayBorder( triple<Iterator, Diff_type, Accessor> multiArray,
280  MultiArrayIndex border_width, VALUETYPE const & v);
281  }
282  \endcode
283  \deprecatedEnd
284 
285  <b> Usage:</b>
286 
287  <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
288  Namespace: vigra
289 
290  \code
291  MultiArray<3, unsigned int> array(Shape3(100, 200, 50));
292 
293  int border_width = 5;
294 
295  // init the array interior to 1, the border to 2
296  initMultiArray(array.subarray(Shape3(border_width), Shape3(-border_width)), 1);
297  initMultiArrayBorder(array, border_width, 2);
298  \endcode
299 */
301 
302 template <class Iterator, class Diff_type, class Accessor,
303  class VALUETYPE>
304 void
305 initMultiArrayBorder(Iterator upperleft, Diff_type shape, Accessor a,
306  Diff_type lower_border, Diff_type upper_border,
307  VALUETYPE const & v)
308 {
309  for(unsigned int dim=0; dim<shape.size(); dim++)
310  {
311  lower_border[dim] = (lower_border[dim] > shape[dim]) ? shape[dim] : lower_border[dim];
312  upper_border[dim] = (upper_border[dim] > shape[dim]) ? shape[dim] : upper_border[dim];
313  }
314 
315  for(unsigned int dim=0; dim<shape.size(); dim++)
316  {
317  Diff_type start,
318  offset(shape);
319  offset[dim] = lower_border[dim];
320 
321  initMultiArray(upperleft+start, offset, a, v);
322 
323  start[dim] = shape[dim] - upper_border[dim];
324  offset[dim] = upper_border[dim];
325  initMultiArray(upperleft+start, offset, a, v);
326  }
327 }
328 
329 template <class Iterator, class Diff_type, class Accessor,
330  class VALUETYPE>
331 inline void
332 initMultiArrayBorder(Iterator upperleft, Diff_type shape, Accessor a,
333  MultiArrayIndex border_width, VALUETYPE const & v)
334 {
335  initMultiArrayBorder(upperleft, shape, a,
336  Diff_type(border_width), Diff_type(border_width), v);
337 }
338 
339 template <class Iterator, class Diff_type, class Accessor,
340  class VALUETYPE>
341 inline void
342 initMultiArrayBorder( triple<Iterator, Diff_type, Accessor> multiArray,
343  MultiArrayIndex border_width, VALUETYPE const & v)
344 {
345  initMultiArrayBorder(multiArray.first, multiArray.second, multiArray.third, border_width, v);
346 }
347 
348 template <class Iterator, class Diff_type, class Accessor,
349  class VALUETYPE>
350 inline void
351 initMultiArrayBorder( triple<Iterator, Diff_type, Accessor> multiArray,
352  Diff_type const & lower_border, Diff_type const & upper_border,
353  VALUETYPE const & v)
354 {
355  initMultiArrayBorder(multiArray.first, multiArray.second, multiArray.third,
356  lower_border, upper_border, v);
357 }
358 
359 template <unsigned int N, class T, class S,
360  class VALUETYPE>
361 inline void
362 initMultiArrayBorder( MultiArrayView<N, T, S> array,
363  MultiArrayIndex border_width, VALUETYPE const & v)
364 {
365  initMultiArrayBorder(destMultiArrayRange(array), border_width, v);
366 }
367 
368 template <unsigned int N, class T, class S,
369  class VALUETYPE>
370 inline void
371 initMultiArrayBorder( MultiArrayView<N, T, S> array,
372  typename MultiArrayShape<N>::type const & lower_border,
373  typename MultiArrayShape<N>::type const & upper_border,
374  VALUETYPE const & v)
375 {
376  initMultiArrayBorder(destMultiArrayRange(array), lower_border, upper_border, v);
377 }
378 
379 /********************************************************/
380 /* */
381 /* copyMultiArray */
382 /* */
383 /********************************************************/
384 
385 template <class SrcIterator, class SrcShape, class SrcAccessor,
386  class DestIterator, class DestShape, class DestAccessor>
387 void
388 copyMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
389  DestIterator d, DestShape const & dshape, DestAccessor dest, MetaInt<0>)
390 {
391  if(sshape[0] == 1)
392  {
393  initLine(d, d + dshape[0], dest, src(s));
394  }
395  else
396  {
397  copyLine(s, s + sshape[0], src, d, dest);
398  }
399 }
400 
401 template <class SrcIterator, class SrcShape, class SrcAccessor,
402  class DestIterator, class DestShape, class DestAccessor, int N>
403 void
404 copyMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
405  DestIterator d, DestShape const & dshape, DestAccessor dest, MetaInt<N>)
406 {
407  DestIterator dend = d + dshape[N];
408  if(sshape[N] == 1)
409  {
410  for(; d < dend; ++d)
411  {
412  copyMultiArrayImpl(s.begin(), sshape, src, d.begin(), dshape, dest, MetaInt<N-1>());
413  }
414  }
415  else
416  {
417  for(; d < dend; ++s, ++d)
418  {
419  copyMultiArrayImpl(s.begin(), sshape, src, d.begin(), dshape, dest, MetaInt<N-1>());
420  }
421  }
422 }
423 
424 /** \brief Copy a multi-dimensional array.
425 
426  This function can be applied in two modes:
427 
428  <DL>
429  <DT><b>Standard Mode:</b>
430  <DD>If the source and destination arrays have the same size,
431  the corresponding array elements are simply copied.
432  If necessary, type conversion takes place.
433  <DT><b>Expanding Mode:</b>
434  <DD>If the source array has length 1 along some (or even all) dimensions,
435  the source value at index 0 is used for all destination
436  elements in those dimensions. For example, if we have single row of data
437  (column length is 1), we can copy it into a 2D image of the same width:
438  The given row is automatically repeated for every row of the destination image.
439  Again, type conversion os performed if necessary.
440  </DL>
441 
442  The arrays must be represented by
443  iterators compatible with \ref vigra::MultiIterator, and the iteration range
444  is specified by means of shape objects. If only the source shape is given
445  the destination array is assumed to have the same shape, and standard mode
446  is applied. If two shapes are given, the size of corresponding dimensions
447  must be either equal (standard copy), or the source length must be 1
448  (expanding copy).
449 
450  <b> Declarations:</b>
451 
452  <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
453  Namespace: vigra
454 
455  pass arbitrary-dimensional array views:
456  \code
457  namespace vigra {
458  template <unsigned int N, class T1, class S1,
459  class T2, class S2>
460  void
461  copyMultiArray(MultiArrayView<N, T1, S1> const & source,
462  MultiArrayView<N, T2, S2> dest);
463  }
464  \endcode
465 
466  \deprecatedAPI{copyMultiArray}
467  pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
468  \code
469  namespace vigra {
470  template <class SrcIterator, class SrcShape, class SrcAccessor,
471  class DestIterator, class DestAccessor>
472  void
473  copyMultiArray(SrcIterator s,
474  SrcShape const & shape, SrcAccessor src,
475  DestIterator d, DestAccessor dest);
476 
477 
478  template <class SrcIterator, class SrcShape, class SrcAccessor,
479  class DestIterator, class DestShape, class DestAccessor>
480  void
481  copyMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
482  DestIterator d, DestShape const & dshape, DestAccessor dest);
483  }
484  \endcode
485  use argument objects in conjunction with \ref ArgumentObjectFactories :
486  \code
487  namespace vigra {
488  template <class SrcIterator, class SrcShape, class SrcAccessor,
489  class DestIterator, class DestAccessor>
490  void
491  copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
492  pair<DestIterator, DestAccessor> const & dest);
493 
494 
495  template <class SrcIterator, class SrcShape, class SrcAccessor,
496  class DestIterator, class DestShape, class DestAccessor>
497  void
498  copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
499  triple<DestIterator, DestShape, DestAccessor> const & dest);
500  }
501  \endcode
502  \deprecatedEnd
503 
504  <b> Usage - Standard Mode:</b>
505 
506  \code
507  MultiArray<3, int> src(Shape3(100, 200, 50)),
508  dest(Shape3(100, 200, 50));
509  ...
510 
511  copyMultiArray(src, dest);
512 
513  // equivalent to
514  dest = src;
515 
516  // copy only the red channel (i.e. channl 0) of an RGB array
517  MultiArray<3, RGBValue<int> > rgb_src(Shape3(100, 200, 50));
518 
519  copyMultiArray(rgb_src.bindElementChannel(0), dest);
520 
521  // equivalent to
522  dest = rgb_src.bindElementChannel(0);
523  \endcode
524 
525  <b> Usage - Expanding Mode:</b>
526 
527  The source array is effectively only a 2D image (it has a 3D shape, but 'depth' is a
528  singleton dimension with length 1). Thus, the destination will contain 50 identical
529  copies of this image:
530 
531  \code
532  MultiArray<3, int> src(Shape2(100, 200)),
533  dest(Shape3(100, 200, 50));
534  ...
535 
536  copyMultiArray(src.insertSingletonDimension(2), dest);
537 
538  // create an RGB image with three identical color bands
539  MultiArray<3, RGBValue<int> > rgb_dest(Shape2(100, 200));
540 
541  copyMultiArray(src.insertSingletonDimension(2), rgb_dest.expandElements(2));
542  \endcode
543 
544  \deprecatedUsage{copyMultiArray}
545  \code
546  typedef vigra::MultiArray<3, int> Array;
547  Array src(Array::size_type(100, 200, 50)),
548  dest(Array::size_type(100, 200, 50));
549  ...
550 
551  vigra::copyMultiArray(srcMultiArrayRange(src), destMultiArray(dest));
552  \endcode
553  <b> Required Interface:</b>
554  \code
555  MultiIterator src_begin, dest_begin;
556 
557  SrcAccessor src_accessor;
558  DestAccessor dest_accessor;
559 
560  dest_accessor.set(src_accessor(src_begin), dest_begin);
561  \endcode
562  \deprecatedEnd
563 */
564 doxygen_overloaded_function(template <...> void copyMultiArray)
565 
566 template <class SrcIterator, class SrcShape, class SrcAccessor,
567  class DestIterator, class DestAccessor>
568 inline void
569 copyMultiArray(SrcIterator s,
570  SrcShape const & shape, SrcAccessor src,
571  DestIterator d, DestAccessor dest)
572 {
573  copyMultiArrayImpl(s, shape, src, d, shape, dest, MetaInt<SrcIterator::level>());
574 }
575 
576 template <class SrcIterator, class SrcShape, class SrcAccessor,
577  class DestIterator, class DestShape, class DestAccessor>
578 void
579 copyMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
580  DestIterator d, DestShape const & dshape, DestAccessor dest)
581 {
582  vigra_precondition(sshape.size() == dshape.size(),
583  "copyMultiArray(): dimensionality of source and destination array differ");
584  for(unsigned int i=0; i<sshape.size(); ++i)
585  vigra_precondition(sshape[i] == 1 || sshape[i] == dshape[i],
586  "copyMultiArray(): mismatch between source and destination shapes:\n"
587  "length of each source dimension must either be 1 or equal to the corresponding "
588  "destination length.");
589  copyMultiArrayImpl(s, sshape, src, d, dshape, dest, MetaInt<SrcIterator::level>());
590 }
591 
592 template <class SrcIterator, class SrcShape, class SrcAccessor,
593  class DestIterator, class DestAccessor>
594 inline void
595 copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
596  pair<DestIterator, DestAccessor> const & dest)
597 {
598 
599  copyMultiArray(src.first, src.second, src.third, dest.first, dest.second);
600 }
601 
602 template <class SrcIterator, class SrcShape, class SrcAccessor,
603  class DestIterator, class DestShape, class DestAccessor>
604 inline void
605 copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
606  triple<DestIterator, DestShape, DestAccessor> const & dest)
607 {
608 
609  copyMultiArray(src.first, src.second, src.third, dest.first, dest.second, dest.third);
610 }
611 
612 template <unsigned int N, class T1, class S1,
613  class T2, class S2>
614 inline void
615 copyMultiArray(MultiArrayView<N, T1, S1> const & source,
616  MultiArrayView<N, T2, S2> dest)
617 {
618  for(unsigned k=0; k<N; ++k)
619  vigra_precondition(source.shape(k) == dest.shape(k) || source.shape(k) == 1 || 1 == dest.shape(k),
620  "copyMultiArray(): shape mismatch between input and output.");
621  if(source.shape() == dest.shape())
622  copyMultiArray(srcMultiArrayRange(source), destMultiArray(dest));
623  else
624  copyMultiArray(srcMultiArrayRange(source), destMultiArrayRange(dest));
625 }
626 
627 /********************************************************/
628 /* */
629 /* transformMultiArray */
630 /* */
631 /********************************************************/
632 
633 template <class SrcIterator, class SrcShape, class SrcAccessor,
634  class DestIterator, class DestShape, class DestAccessor,
635  class Functor>
636 void
637 transformMultiArrayReduceImpl(SrcIterator s, SrcShape const &, SrcAccessor src,
638  DestIterator d, DestShape const & dshape, DestAccessor dest,
639  SrcShape const & reduceShape,
640  Functor const & ff, MetaInt<0>)
641 {
642  DestIterator dend = d + dshape[0];
643  for(; d < dend; ++s.template dim<0>(), ++d)
644  {
645  Functor f = ff;
646  inspectMultiArray(s, reduceShape, src, f);
647  dest.set(f(), d);
648  }
649 }
650 
651 template <class SrcIterator, class SrcShape, class SrcAccessor,
652  class DestIterator, class DestShape, class DestAccessor,
653  class Functor, int N>
654 void
655 transformMultiArrayReduceImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
656  DestIterator d, DestShape const & dshape, DestAccessor dest,
657  SrcShape const & reduceShape,
658  Functor const & f, MetaInt<N>)
659 {
660  DestIterator dend = d + dshape[N];
661  for(; d < dend; ++s.template dim<N>(), ++d)
662  {
663  transformMultiArrayReduceImpl(s, sshape, src, d.begin(), dshape, dest,
664  reduceShape, f, MetaInt<N-1>());
665  }
666 }
667 
668 template <class SrcIterator, class SrcShape, class SrcAccessor,
669  class DestIterator, class DestShape, class DestAccessor,
670  class Functor>
671 void
672 transformMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
673  DestIterator d, DestShape const & dshape, DestAccessor dest,
674  Functor const & f, VigraTrueType)
675 {
676  // reduce mode
677  SrcShape reduceShape = sshape;
678  for(unsigned int i=0; i<dshape.size(); ++i)
679  {
680  vigra_precondition(dshape[i] == 1 || sshape[i] == dshape[i],
681  "transformMultiArray(): mismatch between source and destination shapes:\n"
682  "In 'reduce'-mode, the length of each destination dimension must either be 1\n"
683  "or equal to the corresponding source length.");
684  if(dshape[i] != 1)
685  reduceShape[i] = 1;
686  }
687  transformMultiArrayReduceImpl(s, sshape, src, d, dshape, dest, reduceShape,
688  f, MetaInt<SrcIterator::level>());
689 }
690 
691 template <class SrcIterator, class SrcShape, class SrcAccessor,
692  class DestIterator, class DestShape, class DestAccessor,
693  class Functor>
694 void
695 transformMultiArrayExpandImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
696  DestIterator d, DestShape const & dshape, DestAccessor dest,
697  Functor const & f, MetaInt<0>)
698 {
699  if(sshape[0] == 1)
700  {
701  initLine(d, d + dshape[0], dest, f(src(s)));
702  }
703  else
704  {
705  transformLine(s, s + sshape[0], src, d, dest, f);
706  }
707 }
708 
709 template <class SrcIterator, class SrcShape, class SrcAccessor,
710  class DestIterator, class DestShape, class DestAccessor,
711  class Functor, int N>
712 void
713 transformMultiArrayExpandImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
714  DestIterator d, DestShape const & dshape, DestAccessor dest,
715  Functor const & f, MetaInt<N>)
716 {
717  DestIterator dend = d + dshape[N];
718  if(sshape[N] == 1)
719  {
720  for(; d < dend; ++d)
721  {
722  transformMultiArrayExpandImpl(s.begin(), sshape, src, d.begin(), dshape, dest,
723  f, MetaInt<N-1>());
724  }
725  }
726  else
727  {
728  for(; d < dend; ++s, ++d)
729  {
730  transformMultiArrayExpandImpl(s.begin(), sshape, src, d.begin(), dshape, dest,
731  f, MetaInt<N-1>());
732  }
733  }
734 }
735 
736 template <class SrcIterator, class SrcShape, class SrcAccessor,
737  class DestIterator, class DestShape, class DestAccessor,
738  class Functor>
739 void
740 transformMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
741  DestIterator d, DestShape const & dshape, DestAccessor dest,
742  Functor const & f, VigraFalseType)
743 {
744  // expand mode
745  for(unsigned int i=0; i<sshape.size(); ++i)
746  vigra_precondition(sshape[i] == 1 || sshape[i] == dshape[i],
747  "transformMultiArray(): mismatch between source and destination shapes:\n"
748  "In 'expand'-mode, the length of each source dimension must either be 1\n"
749  "or equal to the corresponding destination length.");
750  transformMultiArrayExpandImpl(s, sshape, src, d, dshape, dest,
751  f, MetaInt<SrcIterator::level>());
752 }
753 
754 /** \brief Transform a multi-dimensional array with a unary function or functor.
755 
756  Note: The effect of this function can often be achieved in a simpler and
757  more readable way by means of \ref MultiMathModule "array expressions".
758 
759  This function can be applied in three modes:
760 
761  <DL>
762  <DT><b>Standard Mode:</b>
763  <DD>If the source and destination arrays have the same size,
764  the transformation given by the functor is applied to every source
765  element and the result written into the corresponding destination element.
766  Unary functions, unary functors from the STL and the functors specifically
767  defined in \ref TransformFunctor can be used in standard mode.
768  Creation of new functors is easiest by using \ref FunctorExpressions.
769  <DT><b>Expanding Mode:</b>
770  <DD>If the source array has length 1 along some (or even all) dimensions,
771  the source value at index 0 is used for all destination
772  elements in those dimensions. In other words, the source index is not
773  incremented along these dimensions, but the transformation functor
774  is applied as usual. So, we can expand a small array (e.g. a single row of data,
775  column length is 1), into a larger one (e.g. a 2D image with the same width):
776  the given values are simply reused as necessary (e.g. for every row of the
777  destination image). The same functors as in standard mode can be applied.
778  <DT><b>Reducing Mode:</b>
779  <DD>If the destination array has length 1 along some (or even all) dimensions,
780  the source values in these dimensions are reduced to single values by means
781  of a suitable functor (e.g. \ref vigra::ReduceFunctor), which supports two
782  function call operators: one
783  with a single argument to collect the values, and without argument to
784  obtain the final (reduced) result. This behavior is a multi-dimensional
785  generalization of the C++ standard function <tt>std::accumulate()</tt>.
786  </DL>
787 
788  The arrays must be represented by MultiArrayViews. If source and destination shapes
789  match, standard mode is applied. If the shapes differ, the size of corresponding
790  dimensions must either be equal, or the source length must be 1
791  (expand mode), or the destination length must be 1 (reduce mode). However,
792  reduction and expansion cannot be executed at the same time, so the latter
793  conditions are mutual exclusive, even if they apply to different dimensions.
794 
795  <b> Declarations:</b>
796 
797  <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
798  Namespace: vigra
799 
800  pass arbitrary-dimensional array views:
801  \code
802  namespace vigra {
803  template <unsigned int N, class T1, class S1,
804  class T2, class S2,
805  class Functor>
806  void
807  transformMultiArray(MultiArrayView<N, T1, S1> const & source,
808  MultiArrayView<N, T2, S2> dest, Functor const & f);
809  }
810  \endcode
811 
812  \deprecatedAPI{transformMultiArray}
813  pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
814  \code
815  namespace vigra {
816  template <class SrcIterator, class SrcShape, class SrcAccessor,
817  class DestIterator, class DestAccessor,
818  class Functor>
819  void
820  transformMultiArray(SrcIterator s, SrcShape const & shape, SrcAccessor src,
821  DestIterator d, DestAccessor dest, Functor const & f);
822 
823 
824  template <class SrcIterator, class SrcShape, class SrcAccessor,
825  class DestIterator, class DestShape, class DestAccessor,
826  class Functor>
827  void
828  transformMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
829  DestIterator d, DestShape const & dshape, DestAccessor dest,
830  Functor const & f);
831  }
832  \endcode
833  use argument objects in conjunction with \ref ArgumentObjectFactories :
834  \code
835  namespace vigra {
836  template <class SrcIterator, class SrcShape, class SrcAccessor,
837  class DestIterator, class DestAccessor,
838  class Functor>
839  void
840  transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
841  pair<DestIterator, DestAccessor> const & dest, Functor const & f);
842 
843 
844  template <class SrcIterator, class SrcShape, class SrcAccessor,
845  class DestIterator, class DestShape, class DestAccessor,
846  class Functor>
847  void
848  transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
849  triple<DestIterator, DestShape, DestAccessor> const & dest,
850  Functor const & f)
851  }
852  \endcode
853  \deprecatedEnd
854 
855  <b> Usage - Standard Mode:</b>
856 
857  Source and destination array have the same size.
858 
859  \code
860  #include <cmath> // for sqrt()
861 
862  MultiArray<3, float> src(Shape3(100, 200, 50)),
863  dest(Shape3(100, 200, 50));
864  ...
865 
866  transformMultiArray(src, dest, &std::sqrt );
867  \endcode
868 
869  <b> Usage - Expand Mode:</b>
870 
871  The source array is effectively only a 2D image(it has a 3D shape, but depth is a singleton dimension
872  with length 1). Thus, the destination will contain 50 identical copies of the transformed source image.
873 
874  \code
875  #include <cmath> // for sqrt()
876 
877  MultiArray<3, float> src(Shape3(100, 200, 1)),
878  dest(Shape3(100, 200, 50));
879  ...
880 
881  transformMultiArray(src, dest, &std::sqrt );
882  \endcode
883 
884  <b> Usage - Reduce Mode:</b>
885 
886  The destination array is effectively only 1D (it's width and height are singleton dimensions).
887  Thus, it will contain accumulated data for every slice of the source volume
888  (or for every frame, if the source is interpreted as an image sequence).
889  In the example, we use the functor \ref vigra::FindAverage to calculate
890  the average gray value of every slice.
891 
892  \code
893  MultiArray<3, float> src(Shape3(100, 200, 50)),
894  dest(Shape3(1, 1, 50));
895  ...
896 
897  transformMultiArray(src, dest,
898  FindAverage<float>() );
899  \endcode
900 
901  Note that the functor must define the appropriate traits described below in order to be
902  recognized as a reduce functor. This is most easily achieved by deriving from
903  <tt>UnaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
904 
905  \deprecatedUsage{transformMultiArray}
906  \code
907  #include <cmath> // for sqrt()
908 
909  typedef vigra::MultiArray<3, float> Array;
910  Array src(Shape3(100, 200, 50)),
911  dest(Shape3(100, 200, 50));
912  ...
913 
914  vigra::transformMultiArray(srcMultiArrayRange(src),
915  destMultiArray(dest),
916  (float(*)(float))&std::sqrt );
917 
918  \endcode
919  \deprecatedEnd
920 
921  <b> Required Interface:</b>
922 
923  In standard and expand mode, the functor must be a model of UnaryFunction
924  (i.e. support one-argument function call which accepts values of type
925  <tt>T1</tt> and a return value that is convertible into <tt>T2</tt>.
926 
927  In reduce mode, it must be a model of UnaryAnalyser (i.e. support function call
928  with one argument and no return value <tt>functor(arg)</tt>) and Initializer
929  (i.e. support function call with no argument, but return value
930  <tt>res = functor()</tt>). Internally, such functors are recognized by the
931  meta functions <tt>FunctorTraits<FUNCTOR>::isUnaryAnalyser</tt> and
932  <tt>FunctorTraits<FUNCTOR>::isInitializer</tt> which must both yield
933  <tt>VigraTrueType</tt>. Make sure that your functor correctly defines
934  <tt>FunctorTraits</tt> because otherwise reduce mode will not work.
935  This is most easily achieved by deriving the functor from
936  <tt>UnaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
937  In addition, the functor must be copy constructible in order to start each reduction
938  with a fresh functor.
939 
940  \see TransformFunctor, MultiMathModule, \ref FunctorExpressions
941 */
943 
944 template <class SrcIterator, class SrcShape, class SrcAccessor,
945  class DestIterator, class DestAccessor,
946  class Functor>
947 inline void
948 transformMultiArray(SrcIterator s, SrcShape const & shape, SrcAccessor src,
949  DestIterator d, DestAccessor dest, Functor const & f)
950 {
951  transformMultiArrayExpandImpl(s, shape, src, d, shape, dest,
952  f, MetaInt<SrcIterator::level>());
953 }
954 
955 template <class SrcIterator, class SrcShape, class SrcAccessor,
956  class DestIterator, class DestShape, class DestAccessor,
957  class Functor>
958 void
959 transformMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
960  DestIterator d, DestShape const & dshape, DestAccessor dest,
961  Functor const & f)
962 {
963  vigra_precondition(sshape.size() == dshape.size(),
964  "transformMultiArray(): dimensionality of source and destination array differ");
965  typedef FunctorTraits<Functor> FT;
966  typedef typename
967  And<typename FT::isInitializer, typename FT::isUnaryAnalyser>::result
968  isAnalyserInitializer;
969  transformMultiArrayImpl(s, sshape, src, d, dshape, dest,
970  f, isAnalyserInitializer());
971 }
972 
973 template <class SrcIterator, class SrcShape, class SrcAccessor,
974  class DestIterator, class DestAccessor,
975  class Functor>
976 inline void
977 transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
978  pair<DestIterator, DestAccessor> const & dest, Functor const & f)
979 {
980 
981  transformMultiArray(src.first, src.second, src.third,
982  dest.first, dest.second, f);
983 }
984 
985 template <class SrcIterator, class SrcShape, class SrcAccessor,
986  class DestIterator, class DestShape, class DestAccessor,
987  class Functor>
988 inline void
989 transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
990  triple<DestIterator, DestShape, DestAccessor> const & dest,
991  Functor const & f)
992 {
993  transformMultiArray(src.first, src.second, src.third,
994  dest.first, dest.second, dest.third, f);
995 }
996 
997 template <unsigned int N, class T1, class S1,
998  class T2, class S2,
999  class Functor>
1000 inline void
1001 transformMultiArrayImpl(MultiArrayView<N, T1, S1> const & source,
1002  MultiArrayView<N, T2, S2> dest,
1003  Functor const & f, VigraFalseType)
1004 {
1005  if(source.shape() == dest.shape())
1006  transformMultiArray(srcMultiArrayRange(source), destMultiArray(dest), f);
1007  else
1008  transformMultiArray(srcMultiArrayRange(source), destMultiArrayRange(dest), f);
1009 }
1010 
1011 template <unsigned int N, class T1, class S1,
1012  class T2, class S2,
1013  class Functor>
1014 inline void
1015 transformMultiArrayImpl(MultiArrayView<N, T1, S1> const & source,
1016  MultiArrayView<N, T2, S2> dest,
1017  Functor const & f, VigraTrueType)
1018 {
1019  transformMultiArray(srcMultiArrayRange(source), destMultiArrayRange(dest), f);
1020 }
1021 
1022 template <unsigned int N, class T1, class S1,
1023  class T2, class S2,
1024  class Functor>
1025 inline void
1026 transformMultiArray(MultiArrayView<N, T1, S1> const & source,
1027  MultiArrayView<N, T2, S2> dest, Functor const & f)
1028 {
1029  for(unsigned int k=0; k<N; ++k)
1030  vigra_precondition(source.shape(k) == dest.shape(k) || source.shape(k) == 1 || 1 == dest.shape(k),
1031  "transformMultiArray(): shape mismatch between input and output.");
1032 
1033  typedef FunctorTraits<Functor> FT;
1034  typedef typename
1035  And<typename FT::isInitializer, typename FT::isUnaryAnalyser>::result
1036  isAnalyserInitializer;
1037  transformMultiArrayImpl(source, dest, f, isAnalyserInitializer());
1038 }
1039 
1040 /********************************************************/
1041 /* */
1042 /* combineTwoMultiArrays */
1043 /* */
1044 /********************************************************/
1045 
1046 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1047  class SrcIterator2, class SrcAccessor2,
1048  class DestIterator, class DestShape, class DestAccessor,
1049  class Functor>
1050 void
1051 combineTwoMultiArraysReduceImpl(
1052  SrcIterator1 s1, SrcShape const & , SrcAccessor1 src1,
1053  SrcIterator2 s2, SrcAccessor2 src2,
1054  DestIterator d, DestShape const & dshape, DestAccessor dest,
1055  SrcShape const & reduceShape,
1056  Functor const & ff, MetaInt<0>)
1057 {
1058  DestIterator dend = d + dshape[0];
1059  for(; d < dend; ++s1.template dim<0>(), ++s2.template dim<0>(), ++d)
1060  {
1061  Functor f = ff;
1062  inspectTwoMultiArrays(s1, reduceShape, src1, s2, src2, f);
1063  dest.set(f(), d);
1064  }
1065 }
1066 
1067 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1068  class SrcIterator2, class SrcAccessor2,
1069  class DestIterator, class DestShape, class DestAccessor,
1070  class Functor, int N>
1071 void
1072 combineTwoMultiArraysReduceImpl(
1073  SrcIterator1 s1, SrcShape const & sshape, SrcAccessor1 src1,
1074  SrcIterator2 s2, SrcAccessor2 src2,
1075  DestIterator d, DestShape const & dshape, DestAccessor dest,
1076  SrcShape const & reduceShape,
1077  Functor const & f, MetaInt<N>)
1078 {
1079  DestIterator dend = d + dshape[N];
1080  for(; d < dend; ++s1.template dim<N>(), ++s2.template dim<N>(), ++d)
1081  {
1082  combineTwoMultiArraysReduceImpl(s1, sshape, src1, s2, src2,
1083  d.begin(), dshape, dest,
1084  reduceShape, f, MetaInt<N-1>());
1085  }
1086 }
1087 
1088 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
1089  class SrcIterator2, class SrcShape2, class SrcAccessor2,
1090  class DestIterator, class DestShape, class DestAccessor,
1091  class Functor>
1092 void
1093 combineTwoMultiArraysImpl(
1094  SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
1095  SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
1096  DestIterator d, DestShape const & dshape, DestAccessor dest,
1097  Functor const & f, VigraTrueType)
1098 {
1099  // reduce mode
1100  SrcShape1 reduceShape = sshape1;
1101  for(unsigned int i=0; i<dshape.size(); ++i)
1102  {
1103  vigra_precondition(sshape1[i] == sshape2[i] &&
1104  (dshape[i] == 1 || sshape1[i] == dshape[i]),
1105  "combineTwoMultiArrays(): mismatch between source and destination shapes:\n"
1106  "In 'reduce'-mode, the two source shapes must be equal, and\n"
1107  "the length of each destination dimension must either be 1\n"
1108  "or equal to the corresponding source length.");
1109  if(dshape[i] != 1)
1110  reduceShape[i] = 1;
1111  }
1112  combineTwoMultiArraysReduceImpl(s1, sshape1, src1, s2, src2,
1113  d, dshape, dest, reduceShape,
1114  f, MetaInt<SrcIterator1::level>());
1115 }
1116 
1117 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
1118  class SrcIterator2, class SrcShape2, class SrcAccessor2,
1119  class DestIterator, class DestShape, class DestAccessor,
1120  class Functor>
1121 void
1122 combineTwoMultiArraysExpandImpl(
1123  SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
1124  SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
1125  DestIterator d, DestShape const & dshape, DestAccessor dest,
1126  Functor const & f, MetaInt<0>)
1127 {
1128  DestIterator dend = d + dshape[0];
1129  if(sshape1[0] == 1 && sshape2[0] == 1)
1130  {
1131  initLine(d, dend, dest, f(src1(s1), src2(s2)));
1132  }
1133  else if(sshape1[0] == 1)
1134  {
1135  typename SrcAccessor1::value_type sv1 = src1(s1);
1136  for(; d < dend; ++d, ++s2)
1137  dest.set(f(sv1, src2(s2)), d);
1138  }
1139  else if(sshape2[0] == 1)
1140  {
1141  typename SrcAccessor2::value_type sv2 = src2(s2);
1142  for(; d < dend; ++d, ++s1)
1143  dest.set(f(src1(s1), sv2), d);
1144  }
1145  else
1146  {
1147  combineTwoLines(s1, s1 + sshape1[0], src1, s2, src2, d, dest, f);
1148  }
1149 }
1150 
1151 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
1152  class SrcIterator2, class SrcShape2, class SrcAccessor2,
1153  class DestIterator, class DestShape, class DestAccessor,
1154  class Functor, int N>
1155 void
1156 combineTwoMultiArraysExpandImpl(
1157  SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
1158  SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
1159  DestIterator d, DestShape const & dshape, DestAccessor dest,
1160  Functor const & f, MetaInt<N>)
1161 {
1162  DestIterator dend = d + dshape[N];
1163  int s1inc = sshape1[N] == 1
1164  ? 0
1165  : 1;
1166  int s2inc = sshape2[N] == 1
1167  ? 0
1168  : 1;
1169  for(; d < dend; ++d, s1 += s1inc, s2 += s2inc)
1170  {
1171  combineTwoMultiArraysExpandImpl(s1.begin(), sshape1, src1,
1172  s2.begin(), sshape2, src2,
1173  d.begin(), dshape, dest,
1174  f, MetaInt<N-1>());
1175  }
1176 }
1177 
1178 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
1179  class SrcIterator2, class SrcShape2, class SrcAccessor2,
1180  class DestIterator, class DestShape, class DestAccessor,
1181  class Functor>
1182 void
1183 combineTwoMultiArraysImpl(
1184  SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
1185  SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
1186  DestIterator d, DestShape const & dshape, DestAccessor dest,
1187  Functor const & f, VigraFalseType)
1188 {
1189  // expand mode
1190  for(unsigned int i=0; i<sshape1.size(); ++i)
1191  vigra_precondition((sshape1[i] == 1 || sshape1[i] == dshape[i]) &&
1192  (sshape2[i] == 1 || sshape2[i] == dshape[i]),
1193  "combineTwoMultiArrays(): mismatch between source and destination shapes:\n"
1194  "In 'expand'-mode, the length of each source dimension must either be 1\n"
1195  "or equal to the corresponding destination length.");
1196  combineTwoMultiArraysExpandImpl(s1, sshape1, src1, s2, sshape2, src2,
1197  d, dshape, dest,
1198  f, MetaInt<SrcIterator1::level>());
1199 }
1200 
1201 /** \brief Combine two multi-dimensional arrays into one using a binary function or functor.
1202 
1203  Note: The effect of this function can often be achieved in a simpler and
1204  more readable way by means of \ref MultiMathModule "array expressions".
1205 
1206  This function can be applied in three modes:
1207 
1208  <DL>
1209  <DT><b>Standard Mode:</b>
1210  <DD>If the source and destination arrays have the same size,
1211  the transformation given by the functor is applied to every pair of
1212  corresponding source elements and the result written into the corresponding
1213  destination element.
1214  Binary functions, binary functors from the STL and the functors specifically
1215  defined in \ref CombineFunctor can be used in standard mode.
1216  Creation of new functors is easiest by using \ref FunctorExpressions.
1217  <DT><b>Expanding Mode:</b>
1218  <DD>If the source arrays have length 1 along some (or even all) dimensions,
1219  the source values at index 0 are used for all destination
1220  elements in those dimensions. In other words, the source index is not
1221  incremented along those dimensions, but the transformation functor
1222  is applied as usual. So, we can expand small arrays (e.g. a single row of data,
1223  column length is 1), into larger ones (e.g. a 2D image with the same width):
1224  the given values are simply reused as necessary (e.g. for every row of the
1225  destination image). It is not even necessary that the source array shapes
1226  are equal. For example, we can combine a small array with one that
1227  hase the same size as the destination array.
1228  The same functors as in standard mode can be applied.
1229  <DT><b>Reducing Mode:</b>
1230  <DD>If the destination array has length 1 along some (or even all) dimensions,
1231  the source values in these dimensions are reduced to single values by means
1232  of a suitable functor which supports two function call operators: one
1233  with two arguments to collect the values, and one without argument to
1234  obtain the final (reduced) result. This behavior is a multi-dimensional
1235  generalization of the C++ standard function <tt>std::accumulate()</tt>.
1236  </DL>
1237 
1238  The arrays must be represented by MultiArrayViews. If all shapes are identical,
1239  standard mode is applied. If the shapes differ, the size of corresponding dimensions
1240  must either be equal, or the length of this dimension must be 1 in one or both source
1241  arrays (expand mode), or the destination length must be 1 (reduce mode). However,
1242  reduction and expansion cannot be executed at the same time, so the latter
1243  conditions are mutual exclusive, even if they apply to different dimensions.
1244 
1245  <b> Declarations:</b>
1246 
1247  <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
1248  Namespace: vigra
1249 
1250  pass arbitrary-dimensional array views:
1251  \code
1252  namespace vigra {
1253  template <unsigned int N, class T11, class S11,
1254  class T12, class S12,
1255  class T2, class S2,
1256  class Functor>
1257  void
1258  combineTwoMultiArrays(MultiArrayView<N, T11, S11> const & source1,
1259  MultiArrayView<N, T12, S12> const & source2,
1260  MultiArrayView<N, T2, S2> dest,
1261  Functor const & f);
1262  }
1263  \endcode
1264 
1265  \deprecatedAPI{combineTwoMultiArrays}
1266  pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
1267  \code
1268  namespace vigra {
1269  template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1270  class SrcIterator2, class SrcAccessor2,
1271  class DestIterator, class DestAccessor,
1272  class Functor>
1273  void combineTwoMultiArrays(
1274  SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
1275  SrcIterator2 s2, SrcAccessor2 src2,
1276  DestIterator d, DestAccessor dest, Functor const & f);
1277 
1278 
1279  template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
1280  class SrcIterator2, class SrcShape2, class SrcAccessor2,
1281  class DestIterator, class DestShape, class DestAccessor,
1282  class Functor>
1283  void combineTwoMultiArrays(
1284  SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
1285  SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
1286  DestIterator d, DestShape const & dshape, DestAccessor dest,
1287  Functor const & f);
1288  }
1289  \endcode
1290  use argument objects in conjunction with \ref ArgumentObjectFactories :
1291  \code
1292  namespace vigra {
1293  template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1294  class SrcIterator2, class SrcAccessor2,
1295  class DestIterator, class DestAccessor, class Functor>
1296  void combineTwoMultiArrays(
1297  triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
1298  pair<SrcIterator2, SrcAccessor2> const & src2,
1299  pair<DestIterator, DestAccessor> const & dest, Functor const & f);
1300 
1301 
1302  template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
1303  class SrcIterator2, class SrcShape2, class SrcAccessor2,
1304  class DestIterator, class DestShape, class DestAccessor,
1305  class Functor>
1306  void combineTwoMultiArrays(
1307  triple<SrcIterator1, SrcShape1, SrcAccessor1> const & src1,
1308  triple<SrcIterator2, SrcShape2, SrcAccessor2> const & src2,
1309  triple<DestIterator, DestShape, DestAccessor> const & dest,
1310  Functor const & f);
1311  }
1312  \endcode
1313  \deprecatedEnd
1314 
1315  <b> Usage - Standard Mode:</b>
1316 
1317  Source and destination arrays have the same size.
1318 
1319  \code
1320  #include <functional> // for std::plus
1321 
1322  MultiArray<3, int> src1(Shape3(100, 200, 50)),
1323  src2(Shape3(100, 200, 50)),
1324  dest(Shape3(100, 200, 50));
1325  ...
1326 
1327  combineTwoMultiArrays(src1, src2, dest,
1328  std::plus<int>());
1329  \endcode
1330 
1331  <b> Usage - Expand Mode:</b>
1332 
1333  One source array is effectively only a 2D image (it has depth 1). This image will be added
1334  to every slice of the other source array, and the result is written into the
1335  corresponding destination slice.
1336 
1337  \code
1338  #include <functional> // for std::plus
1339 
1340  MultiArray<3, int> src1(Shape3(100, 200, 1)),
1341  src2(Shape3(100, 200, 50)),
1342  dest(Shape3(100, 200, 50));
1343  ...
1344 
1345  combineTwoMultiArrays(src1, src2, dest,
1346  std::plus<int>());
1347  \endcode
1348 
1349  <b> Usage - Reduce Mode:</b>
1350 
1351  The destination array is only 1D (it's width and height are singleton dimensions).
1352  Thus, it will contain accumulated data for every slice of the source volumes
1353  (or for every frame, if the sources are interpreted as image sequences).
1354  In the example, we use \ref vigra::ReduceFunctor together with a functor
1355  expression (see \ref FunctorExpressions) to calculate the total absolute difference
1356  of the gray values in every pair of source slices.
1357 
1358  \code
1359  #include <vigra/functorexpression.hxx>
1360  using namespace vigra::functor;
1361 
1362  MultiArray<3, int> src1(Shape3(100, 200, 50)),
1363  src2(Shape3(100, 200, 50)),
1364  dest(Shape3(1, 1, 50));
1365  ...
1366 
1367  combineTwoMultiArrays(src1, src2, dest,
1368  reduceFunctor(Arg1() + abs(Arg2() - Arg3()), 0) );
1369  // Arg1() is the sum accumulated so far, initialized with 0
1370  \endcode
1371 
1372  Note that the functor must define the appropriate traits described below in order to be
1373  recognized as a reduce functor. This is most easily achieved by deriving from
1374  <tt>BinaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
1375 
1376  \deprecatedUsage{combineTwoMultiArrays}
1377  \code
1378  #include <functional> // for std::plus
1379 
1380  typedef vigra::MultiArray<3, int> Array;
1381  Array src1(Shape3(100, 200, 50)),
1382  src2(Shape3(100, 200, 50)),
1383  dest(Shape3(100, 200, 50));
1384  ...
1385 
1386  vigra::combineTwoMultiArrays(
1387  srcMultiArrayRange(src1),
1388  srcMultiArray(src2),
1389  destMultiArray(dest),
1390  std::plus<int>());
1391  \endcode
1392  \deprecatedEnd
1393 
1394  <b> Required Interface:</b>
1395 
1396  In standard and expand mode, the functor must be a model of BinaryFunction
1397  (i.e. support function call with two arguments and a return value which is convertible
1398  into <tt>T2</tt>: <tt>T2 res = functor(arg1, arg2)</tt>):
1399 
1400  In reduce mode, it must be a model of BinaryAnalyser (i.e. support function call
1401  with two arguments and no return value <tt>functor(arg1, arg2)</tt>) and Initializer
1402  (i.e. support function call with no argument, but return value
1403  <tt>res = functor()</tt>). Internally, such functors are recognized by the
1404  meta functions <tt>FunctorTraits<FUNCTOR>::isBinaryAnalyser</tt> and
1405  <tt>FunctorTraits<FUNCTOR>::isInitializer</tt> which must both yield
1406  <tt>VigraTrueType</tt>. Make sure that your functor correctly defines
1407  <tt>FunctorTraits</tt> because otherwise reduce mode will not work.
1408  This is most easily achieved by deriving the functor from
1409  <tt>BinaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
1410  In addition, the functor must be copy constructible in order to start each reduction
1411  with a fresh functor.
1412 
1413  \see TransformFunctor, MultiMathModule, \ref FunctorExpressions
1414 */
1416 
1417 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1418  class SrcIterator2, class SrcAccessor2,
1419  class DestIterator, class DestAccessor,
1420  class Functor>
1421 inline void
1422 combineTwoMultiArrays(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
1423  SrcIterator2 s2, SrcAccessor2 src2,
1424  DestIterator d, DestAccessor dest, Functor const & f)
1425 {
1426  combineTwoMultiArraysExpandImpl(s1, shape, src1, s2, shape, src2, d, shape, dest, f,
1427  MetaInt<SrcIterator1::level>());
1428 }
1429 
1430 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
1431  class SrcIterator2, class SrcShape2, class SrcAccessor2,
1432  class DestIterator, class DestShape, class DestAccessor,
1433  class Functor>
1434 void
1436  SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
1437  SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
1438  DestIterator d, DestShape const & dshape, DestAccessor dest,
1439  Functor const & f)
1440 {
1441  vigra_precondition(sshape1.size() == dshape.size() && sshape2.size() == dshape.size(),
1442  "combineTwoMultiArrays(): dimensionality of source and destination arrays differ");
1443 
1444  typedef FunctorTraits<Functor> FT;
1445  typedef typename
1446  And<typename FT::isInitializer, typename FT::isBinaryAnalyser>::result
1447  isAnalyserInitializer;
1448  combineTwoMultiArraysImpl(s1, sshape1, src1, s2, sshape2, src2, d, dshape, dest,
1449  f, isAnalyserInitializer());
1450 }
1451 
1452 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1453  class SrcIterator2, class SrcAccessor2,
1454  class DestIterator, class DestAccessor, class Functor>
1455 inline void
1456 combineTwoMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
1457  pair<SrcIterator2, SrcAccessor2> const & src2,
1458  pair<DestIterator, DestAccessor> const & dest,
1459  Functor const & f)
1460 {
1461 
1463  src1.first, src1.second, src1.third,
1464  src2.first, src2.second, dest.first, dest.second, f);
1465 }
1466 
1467 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
1468  class SrcIterator2, class SrcShape2, class SrcAccessor2,
1469  class DestIterator, class DestShape, class DestAccessor,
1470  class Functor>
1471 inline void
1472 combineTwoMultiArrays(triple<SrcIterator1, SrcShape1, SrcAccessor1> const & src1,
1473  triple<SrcIterator2, SrcShape2, SrcAccessor2> const & src2,
1474  triple<DestIterator, DestShape, DestAccessor> const & dest,
1475  Functor const & f)
1476 {
1477  combineTwoMultiArrays(src1.first, src1.second, src1.third,
1478  src2.first, src2.second, src2.third,
1479  dest.first, dest.second, dest.third, f);
1480 }
1481 
1482 template <unsigned int N, class T11, class S11,
1483  class T12, class S12,
1484  class T2, class S2,
1485  class Functor>
1486 inline void
1487 combineTwoMultiArraysImpl(MultiArrayView<N, T11, S11> const & source1,
1488  MultiArrayView<N, T12, S12> const & source2,
1489  MultiArrayView<N, T2, S2> dest,
1490  Functor const & f, VigraFalseType)
1491 {
1492 
1493  if(source1.shape() == source2.shape() && source1.shape() == dest.shape())
1494  combineTwoMultiArrays(srcMultiArrayRange(source1),
1495  srcMultiArray(source2), destMultiArray(dest), f);
1496  else
1497  combineTwoMultiArrays(srcMultiArrayRange(source1),
1498  srcMultiArrayRange(source2),
1499  destMultiArrayRange(dest), f);
1500 }
1501 
1502 template <unsigned int N, class T11, class S11,
1503  class T12, class S12,
1504  class T2, class S2,
1505  class Functor>
1506 inline void
1507 combineTwoMultiArraysImpl(MultiArrayView<N, T11, S11> const & source1,
1508  MultiArrayView<N, T12, S12> const & source2,
1509  MultiArrayView<N, T2, S2> dest,
1510  Functor const & f, VigraTrueType)
1511 {
1512 
1513  combineTwoMultiArrays(srcMultiArrayRange(source1),
1514  srcMultiArrayRange(source2),
1515  destMultiArrayRange(dest), f);
1516 }
1517 
1518 template <unsigned int N, class T11, class S11,
1519  class T12, class S12,
1520  class T2, class S2,
1521  class Functor>
1522 inline void
1523 combineTwoMultiArrays(MultiArrayView<N, T11, S11> const & source1,
1524  MultiArrayView<N, T12, S12> const & source2,
1525  MultiArrayView<N, T2, S2> dest,
1526  Functor const & f)
1527 {
1528  for(unsigned int k=0; k<N; ++k)
1529  vigra_precondition((source1.shape(k) == source2.shape(k) || source1.shape(k) == 1 || 1 == source2.shape(k)) &&
1530  (source1.shape(k) == dest.shape(k) || source1.shape(k) == 1 || 1 == dest.shape(k)),
1531  "combineTwoMultiArrays(): shape mismatch between inputs and/or output.");
1532 
1533  typedef FunctorTraits<Functor> FT;
1534  typedef typename
1535  And<typename FT::isInitializer, typename FT::isBinaryAnalyser>::result
1536  isAnalyserInitializer;
1537  combineTwoMultiArraysImpl(source1, source2, dest, f, isAnalyserInitializer());
1538 }
1539 
1540 /********************************************************/
1541 /* */
1542 /* combineThreeMultiArrays */
1543 /* */
1544 /********************************************************/
1545 
1546 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1547  class SrcIterator2, class SrcAccessor2,
1548  class SrcIterator3, class SrcAccessor3,
1549  class DestIterator, class DestAccessor,
1550  class Functor>
1551 inline void
1552 combineThreeMultiArraysImpl(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
1553  SrcIterator2 s2, SrcAccessor2 src2,
1554  SrcIterator3 s3, SrcAccessor3 src3,
1555  DestIterator d, DestAccessor dest, Functor const & f, MetaInt<0>)
1556 {
1557  combineThreeLines(s1, s1 + shape[0], src1, s2, src2, s3, src3, d, dest, f);
1558 }
1559 
1560 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1561  class SrcIterator2, class SrcAccessor2,
1562  class SrcIterator3, class SrcAccessor3,
1563  class DestIterator, class DestAccessor,
1564  class Functor, int N>
1565 void
1566 combineThreeMultiArraysImpl(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
1567  SrcIterator2 s2, SrcAccessor2 src2,
1568  SrcIterator3 s3, SrcAccessor3 src3,
1569  DestIterator d, DestAccessor dest,
1570  Functor const & f, MetaInt<N>)
1571 {
1572  SrcIterator1 s1end = s1 + shape[N];
1573  for(; s1 < s1end; ++s1, ++s2, ++s3, ++d)
1574  {
1575  combineThreeMultiArraysImpl(s1.begin(), shape, src1,
1576  s2.begin(), src2, s3.begin(), src3, d.begin(), dest,
1577  f, MetaInt<N-1>());
1578  }
1579 }
1580 
1581 
1582 /** \brief Combine three multi-dimensional arrays into one using a
1583  ternary function or functor.
1584 
1585  Note: The effect of this function can often be achieved in a simpler and
1586  more readable way by means of \ref MultiMathModule "array expressions".
1587 
1588  Except for the fact that it operates on three input arrays, this function is
1589  identical to the standard mode of \ref combineTwoMultiArrays() (reduce and expand
1590  modes are not supported).
1591 
1592  <b> Declarations:</b>
1593 
1594  pass arbitrary-dimensional array views:
1595  \code
1596  namespace vigra {
1597  template <unsigned int N, class T11, class S11,
1598  class T12, class S12,
1599  class T13, class S13,
1600  class T2, class S2,
1601  class Functor>
1602  void
1603  combineThreeMultiArrays(MultiArrayView<N, T11, S11> const & source1,
1604  MultiArrayView<N, T12, S12> const & source2,
1605  MultiArrayView<N, T13, S13> const & source3,
1606  MultiArrayView<N, T2, S2> dest,
1607  Functor const & f);
1608  }
1609  \endcode
1610 
1611  \deprecatedAPI{combineThreeMultiArrays}
1612  pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
1613  \code
1614  namespace vigra {
1615  template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1616  class SrcIterator2, class SrcAccessor2,
1617  class SrcIterator3, class SrcAccessor3,
1618  class DestIterator, class DestAccessor,
1619  class Functor>
1620  void
1621  combineThreeMultiArrays(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
1622  SrcIterator2 s2, SrcAccessor2 src2,
1623  SrcIterator3 s3, SrcAccessor3 src3,
1624  DestIterator d, DestAccessor dest, Functor const & f);
1625  }
1626  \endcode
1627  use argument objects in conjunction with \ref ArgumentObjectFactories :
1628  \code
1629  namespace vigra {
1630  template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1631  class SrcIterator2, class SrcAccessor2,
1632  class SrcIterator3, class SrcAccessor3,
1633  class DestIterator, class DestAccessor,
1634  class Functor>
1635  inline void
1636  combineThreeMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
1637  pair<SrcIterator2, SrcAccessor2> const & src2,
1638  pair<SrcIterator3, SrcAccessor3> const & src3,
1639  pair<DestIterator, DestAccessor> const & dest, Functor const & f);
1640  }
1641  \endcode
1642  \deprecatedEnd
1643 
1644  <b> Usage:</b>
1645 
1646  <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
1647  Namespace: vigra
1648 
1649  \code
1650  #include <vigra/functorexpression.hxx>
1651 
1652  MultiArray<3, int> src1(Shape3(100, 200, 50)),
1653  src2(Shape3(100, 200, 50)),
1654  src3(Shape3(100, 200, 50)),
1655  dest(Shape3(100, 200, 50));
1656  ...
1657 
1658  using namespace vigra::functor; // activate VIGRA's lambda library
1659 
1660  combineThreeMultiArrays(src1, src2, src3, dest,
1661  Arg1()*exp(-abs(Arg2()-Arg3())));
1662  \endcode
1663 
1664  \deprecatedUsage{combineThreeMultiArrays}
1665  \code
1666  #include <functional> // for plus
1667 
1668  typedef vigra::MultiArray<3, int> Array;
1669  Array src1(Shape3(100, 200, 50)),
1670  src2(Shape3(100, 200, 50)),
1671  src3(Shape3(100, 200, 50)),
1672  dest(Shape3(100, 200, 50));
1673  ...
1674 
1675  vigra::combineThreeMultiArrays(
1676  srcMultiArrayRange(src1),
1677  srcMultiArray(src2),
1678  srcMultiArray(src3),
1679  destMultiArray(dest),
1680  SomeThreeArgumentFunctor());
1681  \endcode
1682  \deprecatedEnd
1683 
1684  \see TransformFunctor, MultiMathModule, \ref FunctorExpressions
1685 */
1687 
1688 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1689  class SrcIterator2, class SrcAccessor2,
1690  class SrcIterator3, class SrcAccessor3,
1691  class DestIterator, class DestAccessor,
1692  class Functor>
1693 inline void
1694 combineThreeMultiArrays(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
1695  SrcIterator2 s2, SrcAccessor2 src2,
1696  SrcIterator3 s3, SrcAccessor3 src3,
1697  DestIterator d, DestAccessor dest, Functor const & f)
1698 {
1699  combineThreeMultiArraysImpl(s1, shape, src1, s2, src2, s3, src3, d, dest, f,
1700  MetaInt<SrcIterator1::level>());
1701 }
1702 
1703 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1704  class SrcIterator2, class SrcAccessor2,
1705  class SrcIterator3, class SrcAccessor3,
1706  class DestIterator, class DestAccessor,
1707  class Functor>
1708 inline void
1709 combineThreeMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
1710  pair<SrcIterator2, SrcAccessor2> const & src2,
1711  pair<SrcIterator3, SrcAccessor3> const & src3,
1712  pair<DestIterator, DestAccessor> const & dest, Functor const & f)
1713 {
1714 
1716  src1.first, src1.second, src1.third,
1717  src2.first, src2.second, src3.first, src3.second, dest.first, dest.second, f);
1718 }
1719 
1720 template <unsigned int N, class T11, class S11,
1721  class T12, class S12,
1722  class T13, class S13,
1723  class T2, class S2,
1724  class Functor>
1725 inline void
1726 combineThreeMultiArrays(MultiArrayView<N, T11, S11> const & source1,
1727  MultiArrayView<N, T12, S12> const & source2,
1728  MultiArrayView<N, T13, S13> const & source3,
1729  MultiArrayView<N, T2, S2> dest, Functor const & f)
1730 {
1731  vigra_precondition(source1.shape() == source2.shape() && source1.shape() == source3.shape() && source1.shape() == dest.shape(),
1732  "combineThreeMultiArrays(): shape mismatch between inputs and/or output.");
1733 
1735  srcMultiArrayRange(source1),
1736  srcMultiArray(source2), srcMultiArray(source3), destMultiArray(dest), f);
1737 }
1738 
1739 /********************************************************/
1740 /* */
1741 /* inspectMultiArray */
1742 /* */
1743 /********************************************************/
1744 
1745 template <class Iterator, class Shape, class Accessor, class Functor>
1746 inline void
1747 inspectMultiArrayImpl(Iterator s, Shape const & shape, Accessor a, Functor & f, MetaInt<0>)
1748 {
1749  inspectLine(s, s + shape[0], a, f);
1750 }
1751 
1752 template <class Iterator, class Shape, class Accessor, class Functor, int N>
1753 void
1754 inspectMultiArrayImpl(Iterator s, Shape const & shape, Accessor a, Functor & f, MetaInt<N>)
1755 {
1756  Iterator send = s + shape[N];
1757  for(; s < send; ++s)
1758  {
1759  inspectMultiArrayImpl(s.begin(), shape, a, f, MetaInt<N-1>());
1760  }
1761 }
1762 
1763 /** \brief Call an analyzing functor at every element of a multi-dimensional array.
1764 
1765  This function can be used to collect statistics of the array etc.
1766  The results must be stored in the functor, which serves as a return
1767  value (therefore, it is passed to the function by reference). The array must be
1768  represented as a MultiArrayView.
1769 
1770  For many common statistics, the use of \ref vigra::acc::extractFeatures() in combination with
1771  \ref FeatureAccumulators is more convenient.
1772 
1773  <b> Declarations:</b>
1774 
1775  pass arbitrary-dimensional array views:
1776  \code
1777  namespace vigra {
1778  template <unsigned int N, class T, class S,
1779  class Functor>
1780  void
1781  inspectMultiArray(MultiArrayView<N, T, S> const & s,
1782  Functor & f);
1783  }
1784  \endcode
1785 
1786  \deprecatedAPI{inspectMultiArray}
1787  pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
1788  \code
1789  namespace vigra {
1790  template <class Iterator, class Shape, class Accessor, class Functor>
1791  void
1792  inspectMultiArray(Iterator s, Shape const & shape, Accessor a, Functor & f);
1793  }
1794  \endcode
1795  use argument objects in conjunction with \ref ArgumentObjectFactories :
1796  \code
1797  namespace vigra {
1798  template <class Iterator, class Shape, class Accessor, class Functor>
1799  void
1800  inspectMultiArray(triple<Iterator, Shape, Accessor> const & s, Functor & f);
1801  }
1802  \endcode
1803  \deprecatedEnd
1804 
1805  <b> Usage:</b>
1806 
1807  <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
1808  Namespace: vigra
1809 
1810  \code
1811  MultiArray<3, int> array(Shape3(100, 200, 50));
1812  ... // fill array
1813 
1814  // init functor
1815  FindMinMax<int> minmax;
1816 
1817  inspectMultiArray(array, minmax);
1818 
1819  cout << "Min: " << minmax.min << " Max: " << minmax.max;
1820  \endcode
1821  The functor must support function call with one argument.
1822 
1823  \deprecatedUsage{inspectMultiArray}
1824  \code
1825  typedef vigra::MultiArray<3, int> Array;
1826  Array array(Shape3(100, 200, 50));
1827 
1828  // init functor
1829  vigra::FindMinMax<int> minmax;
1830 
1831  vigra::inspectMultiArray(srcMultiArrayRange(array), minmax);
1832 
1833  cout << "Min: " << minmax.min << " Max: " << minmax.max;
1834 
1835  \endcode
1836  <b> Required Interface:</b>
1837  \code
1838  MultiIterator src_begin;
1839 
1840  Accessor accessor;
1841  Functor functor;
1842 
1843  functor(accessor(src_begin));
1844  \endcode
1845  \deprecatedEnd
1846 */
1848 
1849 template <class Iterator, class Shape, class Accessor>
1850 struct inspectMultiArray_binder
1851 {
1852  Iterator s;
1853  const Shape & shape;
1854  Accessor a;
1855  inspectMultiArray_binder(Iterator s_, const Shape & shape_, Accessor a_)
1856  : s(s_), shape(shape_), a(a_) {}
1857  template <class Functor>
1858  void operator()(Functor & f)
1859  {
1860  inspectMultiArrayImpl(s, shape, a, f, MetaInt<Iterator::level>());
1861  }
1862 };
1863 
1864 template <class Iterator, class Shape, class Accessor, class Functor>
1865 inline void
1866 inspectMultiArray(Iterator s, Shape const & shape, Accessor a, Functor & f)
1867 {
1868  inspectMultiArray_binder<Iterator, Shape, Accessor> g(s, shape, a);
1869  detail::extra_passes_select(g, f);
1870 }
1871 
1872 template <class Iterator, class Shape, class Accessor, class Functor>
1873 inline void
1874 inspectMultiArray(triple<Iterator, Shape, Accessor> const & s, Functor & f)
1875 {
1876  inspectMultiArray(s.first, s.second, s.third, f);
1877 }
1878 
1879 template <unsigned int N, class T, class S, class Functor>
1880 inline void
1881 inspectMultiArray(MultiArrayView<N, T, S> const & s, Functor & f)
1882 {
1883  inspectMultiArray(srcMultiArrayRange(s), f);
1884 }
1885 
1886 /********************************************************/
1887 /* */
1888 /* inspectTwoMultiArrays */
1889 /* */
1890 /********************************************************/
1891 
1892 template <class Iterator1, class Shape, class Accessor1,
1893  class Iterator2, class Accessor2,
1894  class Functor>
1895 inline void
1896 inspectTwoMultiArraysImpl(Iterator1 s1, Shape const & shape, Accessor1 a1,
1897  Iterator2 s2, Accessor2 a2,
1898  Functor & f, MetaInt<0>)
1899 {
1900  inspectTwoLines(s1, s1 + shape[0], a1, s2, a2, f);
1901 }
1902 
1903 template <class Iterator1, class Shape, class Accessor1,
1904  class Iterator2, class Accessor2,
1905  class Functor, int N>
1906 void
1907 inspectTwoMultiArraysImpl(Iterator1 s1, Shape const & shape, Accessor1 a1,
1908  Iterator2 s2, Accessor2 a2,
1909  Functor & f, MetaInt<N>)
1910 {
1911  Iterator1 s1end = s1 + shape[N];
1912  for(; s1 < s1end; ++s1, ++s2)
1913  {
1914  inspectTwoMultiArraysImpl(s1.begin(), shape, a1,
1915  s2.begin(), a2, f, MetaInt<N-1>());
1916  }
1917 }
1918 
1919 /** \brief Call an analyzing functor at all corresponding elements of
1920  two multi-dimensional arrays.
1921 
1922  This function can be used to collect statistics over tow arrays.
1923  For example, one can holde data, and the other region labels or weights.
1924  The results must be stored in the functor, which serves as a return
1925  value (and is therefore passed by reference). The arrays must be represented by
1926  MultiArrayViews.
1927 
1928  For many common statistics, the use of \ref vigra::acc::extractFeatures() in combination with
1929  \ref FeatureAccumulators is more convenient.
1930 
1931  <b> Declarations:</b>
1932 
1933  pass arbitrary-dimensional array views:
1934  \code
1935  namespace vigra {
1936  template <unsigned int N, class T1, class S1,
1937  class T2, class S2,
1938  class Functor>
1939  void
1940  inspectTwoMultiArrays(MultiArrayView<N, T1, S1> const & s1,
1941  MultiArrayView<N, T2, S2> const & s2,
1942  Functor & f);
1943  }
1944  \endcode
1945 
1946  \deprecatedAPI{inspectTwoMultiArrays}
1947  pass \ref MultiIteratorPage "MultiIterators" and \ref DataAccessors :
1948  \code
1949  namespace vigra {
1950  template <class Iterator1, class Shape, class Accessor1,
1951  class Iterator2, class Accessor2,
1952  class Functor>
1953  void
1954  inspectTwoMultiArrays(Iterator1 s1, Shape const & shape, Accessor1 a1,
1955  Iterator2 s2, Accessor2 a2, Functor & f);
1956  }
1957  \endcode
1958  use argument objects in conjunction with \ref ArgumentObjectFactories :
1959  \code
1960  namespace vigra {
1961  template <class Iterator1, class Shape1, class Accessor1,
1962  class Iterator2, class Accessor2,
1963  class Functor>
1964  void
1965  inspectTwoMultiArrays(triple<Iterator1, Shape1, Accessor1> const & s1,
1966  pair<Iterator2, Accessor2> const & s2, Functor & f);
1967  }
1968  \endcode
1969  \deprecatedEnd
1970 
1971  <b> Usage:</b>
1972 
1973  <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
1974  Namespace: vigra
1975 
1976  \code
1977  MultiArray<3, int> array1(Shape3(100, 200, 50)),
1978  array2(Shape3(100, 200, 50));
1979 
1980  // init functor
1981  SomeStatisticsFunctor stats(..);
1982 
1983  inspectTwoMultiArrays(array1, array2, stats);
1984  \endcode
1985  The functor must support function call with two arguments.
1986 
1987  \deprecatedUsage{inspectTwoMultiArrays}
1988  \code
1989  MultiArray<3, int> array1(Shape3(100, 200, 50)),
1990  array2(Shape3(100, 200, 50));
1991 
1992  // init functor
1993  SomeStatisticsFunctor stats(..);
1994 
1995  vigra::inspectTwoMultiArrays(srcMultiArrayRange(array1), srcMultiArray(array2), stats);
1996  \endcode
1997  <b> Required Interface:</b>
1998  \code
1999  MultiIterator src1_begin, src2_begin;
2000 
2001  Accessor a1, a2;
2002  Functor functor;
2003 
2004  functor(a1(src1_begin), a2(src2_begin));
2005  \endcode
2006  \deprecatedEnd
2007 */
2009 
2010 template <class Iterator1, class Shape, class Accessor1,
2011  class Iterator2, class Accessor2>
2012 struct inspectTwoMultiArrays_binder
2013 {
2014  Iterator1 s1;
2015  const Shape & shape;
2016  Accessor1 a1;
2017  Iterator2 s2;
2018  Accessor2 a2;
2019  inspectTwoMultiArrays_binder(Iterator1 s1_, const Shape & shape_,
2020  Accessor1 a1_, Iterator2 s2_, Accessor2 a2_)
2021  : s1(s1_), shape(shape_), a1(a1_), s2(s2_), a2(a2_) {}
2022  template <class Functor>
2023  void operator()(Functor & f)
2024  {
2025  inspectTwoMultiArraysImpl(s1, shape, a1, s2, a2, f,
2026  MetaInt<Iterator1::level>());
2027  }
2028 };
2029 
2030 template <class Iterator1, class Shape, class Accessor1,
2031  class Iterator2, class Accessor2,
2032  class Functor>
2033 inline void
2034 inspectTwoMultiArrays(Iterator1 s1, Shape const & shape, Accessor1 a1,
2035  Iterator2 s2, Accessor2 a2, Functor & f)
2036 {
2037  inspectTwoMultiArrays_binder<Iterator1, Shape, Accessor1,
2038  Iterator2, Accessor2>
2039  g(s1, shape, a1, s2, a2);
2040  detail::extra_passes_select(g, f);
2041 }
2042 
2043 template <class Iterator1, class Shape, class Accessor1,
2044  class Iterator2, class Accessor2,
2045  class Functor>
2046 inline void
2047 inspectTwoMultiArrays(triple<Iterator1, Shape, Accessor1> const & s1,
2048  pair<Iterator2, Accessor2> const & s2, Functor & f)
2049 {
2050  inspectTwoMultiArrays(s1.first, s1.second, s1.third,
2051  s2.first, s2.second, f);
2052 }
2053 
2054 template <unsigned int N, class T1, class S1,
2055  class T2, class S2,
2056  class Functor>
2057 inline void
2058 inspectTwoMultiArrays(MultiArrayView<N, T1, S1> const & s1,
2059  MultiArrayView<N, T2, S2> const & s2, Functor & f)
2060 {
2061  vigra_precondition(s1.shape() == s2.shape(),
2062  "inspectTwoMultiArrays(): shape mismatch between inputs.");
2063 
2064  inspectTwoMultiArrays(srcMultiArrayRange(s1),
2065  srcMultiArray(s2), f);
2066 }
2067 
2068 //@}
2069 
2070 } //-- namespace vigra
2071 
2072 
2073 #endif //-- VIGRA_MULTI_POINTOPERATORS_H
void inspectTwoMultiArrays(...)
Call an analyzing functor at all corresponding elements of two multi-dimensional arrays.
void initMultiArrayBorder(...)
Write values to the specified border values in the array.
void combineThreeMultiArrays(...)
Combine three multi-dimensional arrays into one using a ternary function or functor.
std::ptrdiff_t MultiArrayIndex
Definition: multi_fwd.hxx:60
void initMultiArray(...)
Write a value to every element in a multi-dimensional array.
vigra::GridGraph< N, DirectedTag >::vertex_descriptor source(typename vigra::GridGraph< N, DirectedTag >::edge_descriptor const &e, vigra::GridGraph< N, DirectedTag > const &g)
Get a vertex descriptor for the start vertex of edge e in graph g (API: boost).
Definition: multi_gridgraph.hxx:2943
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
void copyMultiArray(...)
Copy a multi-dimensional array.
void combineTwoMultiArrays(...)
Combine two multi-dimensional arrays into one using a binary function or functor. ...
void transformMultiArray(...)
Transform a multi-dimensional array with a unary function or functor.
void inspectMultiArray(...)
Call an analyzing functor at every element of a multi-dimensional array.

© 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)