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