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

multi_pointoperators.hxx
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 
48 
49 
50 namespace vigra
51 {
52 
53 /** \addtogroup MultiPointoperators Point operators for multi-dimensional arrays.
54 
55  Copy, transform, and inspect arbitrary dimensional arrays which are represented
56  by iterators compatible to \ref MultiIteratorPage. Note that are range is here
57  specified by a pair: an iterator referring to the first point of the array
58  and a shape object specifying the size of the (rectangular) ROI.
59 
60  <b>\#include</b> <<a href="multi__pointoperators_8hxx-source.html">vigra/multi_pointoperators.hxx</a>>
61 */
62 //@{
63 
64 /********************************************************/
65 /* */
66 /* initMultiArray */
67 /* */
68 /********************************************************/
69 
70 template <class Iterator, class Shape, class Accessor,
71  class VALUETYPE>
72 inline void
73 initMultiArrayImpl(Iterator s, Shape const & shape, Accessor a, VALUETYPE const & v, MetaInt<0>)
74 {
75  initLine(s, s + shape[0], a, v);
76 }
77 
78 template <class Iterator, class Shape, class Accessor,
79  class VALUETYPE, int N>
80 void
81 initMultiArrayImpl(Iterator s, Shape const & shape, Accessor a,
82  VALUETYPE const & v, MetaInt<N>)
83 {
84  Iterator send = s + shape[N];
85  for(; s < send; ++s)
86  {
87  initMultiArrayImpl(s.begin(), shape, a, v, MetaInt<N-1>());
88  }
89 }
90 
91 /** \brief Write a value to every pixel in a multi-dimensional array.
92 
93  This function can be used to init the array which must be represented by
94  a pair of iterators compatible to \ref vigra::MultiIterator.
95  It uses an accessor to access the data alements. Note that the iterator range
96  must be specified by a shape object, because otherwise we could not control
97  the range simultaneously in all dimensions (this is a necessary consequence
98  of the \ref vigra::MultiIterator design).
99 
100  The initial value can either be a constant of appropriate type (compatible with
101  the destination's value_type), or a functor with compatible result_type. These two
102  cases are automatically distinguished when <tt>FunctorTraits<FUNCTOR>::isInitializer</tt>
103  yields <tt>VigraTrueType</tt>. Since the functor is passed by <tt>const</tt> reference, its
104  <tt>operator()</tt> must be const, and ist internal state may need to be <tt>mutable</tt>.
105 
106  <b> Declarations:</b>
107 
108  pass arguments explicitly:
109  \code
110  namespace vigra {
111  template <class Iterator, class Shape, class Accessor, class VALUETYPE>
112  void
113  initMultiArray(Iterator s, Shape const & shape, Accessor a, VALUETYPE const & v);
114 
115 
116  template <class Iterator, class Shape, class Accessor, class FUNCTOR>
117  void
118  initMultiArray(Iterator s, Shape const & shape, Accessor a, FUNCTOR const & f);
119  }
120  \endcode
121 
122  use argument objects in conjunction with \ref ArgumentObjectFactories :
123  \code
124  namespace vigra {
125  template <class Iterator, class Shape, class Accessor, class VALUETYPE>
126  void
127  initMultiArray(triple<Iterator, Shape, Accessor> const & s, VALUETYPE const & v);
128 
129 
130  template <class Iterator, class Shape, class Accessor, class FUNCTOR>
131  void
132  initMultiArray(triple<Iterator, Shape, Accessor> const & s, FUNCTOR const & f);
133  }
134  \endcode
135 
136  <b> Usage:</b>
137 
138  <b>\#include</b> <<a href="multi__pointoperators_8hxx-source.html">vigra/multi_pointoperators.hxx</a>><br>
139  Namespace: vigra
140 
141  \code
142  typedef vigra::MultiArray<3, int> Array;
143  Array array(Array::size_type(100, 200, 50));
144 
145  // zero the array
146  vigra::initMultiArray(destMultiArrayRange(array), 0);
147  \endcode
148 
149  <b> Required Interface:</b>
150 
151  The function accepts either a value that is copied into every destination element:
152 
153  \code
154  MultiIterator begin;
155 
156  Accessor accessor;
157  VALUETYPE v;
158 
159  accessor.set(v, begin);
160  \endcode
161 
162  or a functor that is called (without argument) at every location,
163  and the result is written into the current element. Internally,
164  functors are recognized by the meta function
165  <tt>FunctorTraits<FUNCTOR>::isInitializer</tt> yielding <tt>VigraTrueType</tt>.
166  Make sure that your functor correctly defines <tt>FunctorTraits</tt> because
167  otherwise the code will not compile.
168 
169  \code
170  MultiIterator begin;
171  Accessor accessor;
172 
173  FUNCTOR f;
174  assert(typeid(FunctorTraits<FUNCTOR>::isInitializer) == typeid(VigraTrueType));
175 
176  accessor.set(f(), begin);
177  \endcode
178 
179 
180 */
181 doxygen_overloaded_function(template <...> void initMultiArray)
182 
183 template <class Iterator, class Shape, class Accessor, class VALUETYPE>
184 inline void
185 initMultiArray(Iterator s, Shape const & shape, Accessor a, VALUETYPE const & v)
186 {
187  initMultiArrayImpl(s, shape, a, v, MetaInt<Iterator::level>());
188 }
189 
190 template <class Iterator, class Shape, class Accessor, class VALUETYPE>
191 inline
192 void
193 initMultiArray(triple<Iterator, Shape, Accessor> const & s, VALUETYPE const & v)
194 {
195  initMultiArray(s.first, s.second, s.third, v);
196 }
197 
198 /********************************************************/
199 /* */
200 /* initMultiArrayBorder */
201 /* */
202 /********************************************************/
203 
204 /** \brief Write value to the specified border values in the array.
205 
206 */template <class Iterator, class Diff_type, class Accessor, class VALUETYPE>
207 inline void initMultiArrayBorder( Iterator upperleft, Diff_type shape,
208  Accessor a, int border_width, VALUETYPE v)
209 {
210  Diff_type border(shape);
211  for(unsigned int dim=0; dim<shape.size(); dim++){
212  border[dim] = (border_width > shape[dim]) ? shape[dim] : border_width;
213  }
214 
215  for(unsigned int dim=0; dim<shape.size(); dim++){
216  Diff_type start(shape),
217  offset(shape);
218  start = start-shape;
219  offset[dim]=border[dim];
220 
221  initMultiArray(upperleft+start, offset, a, v);
222 
223  start[dim]=shape[dim]-border[dim];
224  initMultiArray(upperleft+start, offset, a, v);
225  }
226 }
227 
228 template <class Iterator, class Diff_type, class Accessor, class VALUETYPE>
229 inline void initMultiArrayBorder( triple<Iterator, Diff_type, Accessor> multiArray,
230  int border_width, VALUETYPE v)
231 {
232  initMultiArrayBorder(multiArray.first, multiArray.second, multiArray.third, border_width, v);
233 }
234 
235 
236 /********************************************************/
237 /* */
238 /* copyMultiArray */
239 /* */
240 /********************************************************/
241 
242 template <class SrcIterator, class SrcShape, class SrcAccessor,
243  class DestIterator, class DestShape, class DestAccessor>
244 void
245 copyMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
246  DestIterator d, DestShape const & dshape, DestAccessor dest, MetaInt<0>)
247 {
248  if(sshape[0] == 1)
249  {
250  initLine(d, d + dshape[0], dest, src(s));
251  }
252  else
253  {
254  copyLine(s, s + sshape[0], src, d, dest);
255  }
256 }
257 
258 template <class SrcIterator, class SrcShape, class SrcAccessor,
259  class DestIterator, class DestShape, class DestAccessor, int N>
260 void
261 copyMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
262  DestIterator d, DestShape const & dshape, DestAccessor dest, MetaInt<N>)
263 {
264  DestIterator dend = d + dshape[N];
265  if(sshape[N] == 1)
266  {
267  for(; d < dend; ++d)
268  {
269  copyMultiArrayImpl(s.begin(), sshape, src, d.begin(), dshape, dest, MetaInt<N-1>());
270  }
271  }
272  else
273  {
274  for(; d < dend; ++s, ++d)
275  {
276  copyMultiArrayImpl(s.begin(), sshape, src, d.begin(), dshape, dest, MetaInt<N-1>());
277  }
278  }
279 }
280 
281 /** \brief Copy a multi-dimensional array.
282 
283  This function can be applied in two modes:
284 
285  <DL>
286  <DT><b>Standard Mode:</b>
287  <DD>If the source and destination arrays have the same size,
288  the corresponding array elements are simply copied.
289  If necessary, type conversion takes place.
290  <DT><b>Expanding Mode:</b>
291  <DD>If the source array has length 1 along some (or even all) dimensions,
292  the source value at index 0 is used for all destination
293  elements in those dimensions. For example, if we have single row of data
294  (column length is 1), we can copy it into a 2D image of the same width:
295  The given row is automatically repeated for every row of the destination image.
296  Again, type conversion os performed if necessary.
297  </DL>
298 
299  The arrays must be represented by
300  iterators compatible with \ref vigra::MultiIterator, and the iteration range
301  is specified by means of shape objects. If only the source shape is given
302  the destination array is assumed to have the same shape, and standard mode
303  is applied. If two shapes are given, the size of corresponding dimensions
304  must be either equal (standard copy), or the source length must be 1
305  (expanding copy). The function uses accessors to access the data elements.
306 
307  <b> Declarations:</b>
308 
309  <b>\#include</b> <<a href="multi__pointoperators_8hxx-source.html">vigra/multi_pointoperators.hxx</a>><br>
310  Namespace: vigra
311 
312  pass arguments explicitly:
313  \code
314  namespace vigra {
315  template <class SrcIterator, class SrcShape, class SrcAccessor,
316  class DestIterator, class DestAccessor>
317  void
318  copyMultiArray(SrcIterator s,
319  SrcShape const & shape, SrcAccessor src,
320  DestIterator d, DestAccessor dest);
321 
322 
323  template <class SrcIterator, class SrcShape, class SrcAccessor,
324  class DestIterator, class DestShape, class DestAccessor>
325  void
326  copyMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
327  DestIterator d, DestShape const & dshape, DestAccessor dest);
328  }
329  \endcode
330 
331 
332  use argument objects in conjunction with \ref ArgumentObjectFactories :
333  \code
334  namespace vigra {
335  template <class SrcIterator, class SrcShape, class SrcAccessor,
336  class DestIterator, class DestAccessor>
337  void
338  copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
339  pair<DestIterator, DestAccessor> const & dest);
340 
341 
342  template <class SrcIterator, class SrcShape, class SrcAccessor,
343  class DestIterator, class DestShape, class DestAccessor>
344  void
345  copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
346  triple<DestIterator, DestShape, DestAccessor> const & dest);
347  }
348  \endcode
349 
350  <b> Usage - Standard Mode:</b>
351 
352  \code
353  typedef vigra::MultiArray<3, int> Array;
354  Array src(Array::size_type(100, 200, 50)),
355  dest(Array::size_type(100, 200, 50));
356  ...
357 
358  vigra::copyMultiArray(srcMultiArrayRange(src), destMultiArray(dest));
359  \endcode
360 
361  <b> Usage - Expanding Mode:</b>
362 
363  The source array is only 2D (it has depth 1). Thus, the destination
364  will contain 50 identical copies of this image. Note that the destination shape
365  must be passed to the algorithm for the expansion to work, so we use
366  <tt>destMultiArrayRange()</tt> rather than <tt>destMultiArray()</tt>.
367 
368  \code
369  typedef vigra::MultiArray<3, int> Array;
370  Array src(Array::size_type(100, 200, 1)),
371  dest(Array::size_type(100, 200, 50));
372  ...
373 
374  vigra::copyMultiArray(srcMultiArrayRange(src), destMultiArrayRange(dest));
375  \endcode
376 
377  <b> Required Interface:</b>
378 
379  \code
380  MultiIterator src_begin, dest_begin;
381 
382  SrcAccessor src_accessor;
383  DestAccessor dest_accessor;
384 
385  dest_accessor.set(src_accessor(src_begin), dest_begin);
386 
387  \endcode
388 
389 */
390 doxygen_overloaded_function(template <...> void copyMultiArray)
391 
392 template <class SrcIterator, class SrcShape, class SrcAccessor,
393  class DestIterator, class DestAccessor>
394 inline void
395 copyMultiArray(SrcIterator s,
396  SrcShape const & shape, SrcAccessor src,
397  DestIterator d, DestAccessor dest)
398 {
399  copyMultiArrayImpl(s, shape, src, d, shape, dest, MetaInt<SrcIterator::level>());
400 }
401 
402 template <class SrcIterator, class SrcShape, class SrcAccessor,
403  class DestIterator, class DestAccessor>
404 inline void
405 copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
406  pair<DestIterator, DestAccessor> const & dest)
407 {
408 
409  copyMultiArray(src.first, src.second, src.third, dest.first, dest.second);
410 }
411 
412 template <class SrcIterator, class SrcShape, class SrcAccessor,
413  class DestIterator, class DestShape, class DestAccessor>
414 void
415 copyMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
416  DestIterator d, DestShape const & dshape, DestAccessor dest)
417 {
418  vigra_precondition(sshape.size() == dshape.size(),
419  "copyMultiArray(): dimensionality of source and destination array differ");
420  for(unsigned int i=0; i<sshape.size(); ++i)
421  vigra_precondition(sshape[i] == 1 || sshape[i] == dshape[i],
422  "copyMultiArray(): mismatch between source and destination shapes:\n"
423  "length of each source dimension must either be 1 or equal to the corresponding "
424  "destination length.");
425  copyMultiArrayImpl(s, sshape, src, d, dshape, dest, MetaInt<SrcIterator::level>());
426 }
427 
428 template <class SrcIterator, class SrcShape, class SrcAccessor,
429  class DestIterator, class DestShape, class DestAccessor>
430 inline void
431 copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
432  triple<DestIterator, DestShape, DestAccessor> const & dest)
433 {
434 
435  copyMultiArray(src.first, src.second, src.third, dest.first, dest.second, dest.third);
436 }
437 
438 /********************************************************/
439 /* */
440 /* transformMultiArray */
441 /* */
442 /********************************************************/
443 
444 template <class SrcIterator, class SrcShape, class SrcAccessor,
445  class DestIterator, class DestShape, class DestAccessor,
446  class Functor>
447 void
448 transformMultiArrayReduceImpl(SrcIterator s, SrcShape const &, SrcAccessor src,
449  DestIterator d, DestShape const & dshape, DestAccessor dest,
450  SrcShape const & reduceShape,
451  Functor const & ff, MetaInt<0>)
452 {
453  DestIterator dend = d + dshape[0];
454  for(; d < dend; ++s.template dim<0>(), ++d)
455  {
456  Functor f = ff;
457  inspectMultiArray(s, reduceShape, src, f);
458  dest.set(f(), d);
459  }
460 }
461 
462 template <class SrcIterator, class SrcShape, class SrcAccessor,
463  class DestIterator, class DestShape, class DestAccessor,
464  class Functor, int N>
465 void
466 transformMultiArrayReduceImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
467  DestIterator d, DestShape const & dshape, DestAccessor dest,
468  SrcShape const & reduceShape,
469  Functor const & f, MetaInt<N>)
470 {
471  DestIterator dend = d + dshape[N];
472  for(; d < dend; ++s.template dim<N>(), ++d)
473  {
474  transformMultiArrayReduceImpl(s, sshape, src, d.begin(), dshape, dest,
475  reduceShape, f, MetaInt<N-1>());
476  }
477 }
478 
479 template <class SrcIterator, class SrcShape, class SrcAccessor,
480  class DestIterator, class DestShape, class DestAccessor,
481  class Functor>
482 void
483 transformMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
484  DestIterator d, DestShape const & dshape, DestAccessor dest,
485  Functor const & f, VigraTrueType)
486 {
487  // reduce mode
488  SrcShape reduceShape = sshape;
489  for(unsigned int i=0; i<dshape.size(); ++i)
490  {
491  vigra_precondition(dshape[i] == 1 || sshape[i] == dshape[i],
492  "transformMultiArray(): mismatch between source and destination shapes:\n"
493  "In 'reduce'-mode, the length of each destination dimension must either be 1\n"
494  "or equal to the corresponding source length.");
495  if(dshape[i] != 1)
496  reduceShape[i] = 1;
497  }
498  transformMultiArrayReduceImpl(s, sshape, src, d, dshape, dest, reduceShape,
499  f, MetaInt<SrcIterator::level>());
500 }
501 
502 template <class SrcIterator, class SrcShape, class SrcAccessor,
503  class DestIterator, class DestShape, class DestAccessor,
504  class Functor>
505 void
506 transformMultiArrayExpandImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
507  DestIterator d, DestShape const & dshape, DestAccessor dest,
508  Functor const & f, MetaInt<0>)
509 {
510  if(sshape[0] == 1)
511  {
512  initLine(d, d + dshape[0], dest, f(src(s)));
513  }
514  else
515  {
516  transformLine(s, s + sshape[0], src, d, dest, f);
517  }
518 }
519 
520 template <class SrcIterator, class SrcShape, class SrcAccessor,
521  class DestIterator, class DestShape, class DestAccessor,
522  class Functor, int N>
523 void
524 transformMultiArrayExpandImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
525  DestIterator d, DestShape const & dshape, DestAccessor dest,
526  Functor const & f, MetaInt<N>)
527 {
528  DestIterator dend = d + dshape[N];
529  if(sshape[N] == 1)
530  {
531  for(; d < dend; ++d)
532  {
533  transformMultiArrayExpandImpl(s.begin(), sshape, src, d.begin(), dshape, dest,
534  f, MetaInt<N-1>());
535  }
536  }
537  else
538  {
539  for(; d < dend; ++s, ++d)
540  {
541  transformMultiArrayExpandImpl(s.begin(), sshape, src, d.begin(), dshape, dest,
542  f, MetaInt<N-1>());
543  }
544  }
545 }
546 
547 template <class SrcIterator, class SrcShape, class SrcAccessor,
548  class DestIterator, class DestShape, class DestAccessor,
549  class Functor>
550 void
551 transformMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
552  DestIterator d, DestShape const & dshape, DestAccessor dest,
553  Functor const & f, VigraFalseType)
554 {
555  // expand mode
556  for(unsigned int i=0; i<sshape.size(); ++i)
557  vigra_precondition(sshape[i] == 1 || sshape[i] == dshape[i],
558  "transformMultiArray(): mismatch between source and destination shapes:\n"
559  "In 'expand'-mode, the length of each source dimension must either be 1\n"
560  "or equal to the corresponding destination length.");
561  transformMultiArrayExpandImpl(s, sshape, src, d, dshape, dest,
562  f, MetaInt<SrcIterator::level>());
563 }
564 
565 /** \brief Transform a multi-dimensional array with a unary function or functor.
566 
567  This function can be applied in three modes:
568 
569  <DL>
570  <DT><b>Standard Mode:</b>
571  <DD>If the source and destination arrays have the same size,
572  the transformation given by the functor is applied to every source
573  element and the result written into the corresponding destination element.
574  Unary functions, unary functors from the STL and the functors specifically
575  defined in \ref TransformFunctor can be used in standard mode.
576  Creation of new functors is easiest by using \ref FunctorExpressions.
577  <DT><b>Expanding Mode:</b>
578  <DD>If the source array has length 1 along some (or even all) dimensions,
579  the source value at index 0 is used for all destination
580  elements in those dimensions. In other words, the source index is not
581  incremented along these dimensions, but the transformation functor
582  is applied as usual. So, we can expand a small array (e.g. a single row of data,
583  column length is 1), into a larger one (e.g. a 2D image with the same width):
584  the given values are simply reused as necessary (e.g. for every row of the
585  destination image). The same functors as in standard mode can be applied.
586  <DT><b>Reducing Mode:</b>
587  <DD>If the destination array has length 1 along some (or even all) dimensions,
588  the source values in these dimensions are reduced to single values by means
589  of a suitable functor (e.g. \ref vigra::ReduceFunctor), which supports two
590  function call operators: one
591  with a single argument to collect the values, and without argument to
592  obtain the final (reduced) result. This behavior is a multi-dimensional
593  generalization of the C++ standard function <tt>std::accumulate()</tt>.
594  </DL>
595 
596  The arrays must be represented by
597  iterators compatible with \ref vigra::MultiIterator, and the iteration range
598  is specified by means of shape objects. If only the source shape is given
599  the destination array is assumed to have the same shape, and standard mode
600  is applied. If two shapes are given, the size of corresponding dimensions
601  must be either equal (standard copy), or the source length must be 1
602  (expand mode), or the destination length must be 1 (reduce mode). However,
603  reduction and expansion cannot be executed at the same time, so the latter
604  conditions are mutual exclusive, even if they apply to different dimensions.
605 
606  The function uses accessors to access the data elements.
607 
608  <b> Declarations:</b>
609 
610  <b>\#include</b> <<a href="multi__pointoperators_8hxx-source.html">vigra/multi_pointoperators.hxx</a>><br>
611  Namespace: vigra
612 
613  pass arguments explicitly:
614  \code
615  namespace vigra {
616  template <class SrcIterator, class SrcShape, class SrcAccessor,
617  class DestIterator, class DestAccessor,
618  class Functor>
619  void
620  transformMultiArray(SrcIterator s, SrcShape const & shape, SrcAccessor src,
621  DestIterator d, DestAccessor dest, Functor const & f);
622 
623 
624  template <class SrcIterator, class SrcShape, class SrcAccessor,
625  class DestIterator, class DestShape, class DestAccessor,
626  class Functor>
627  void
628  transformMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
629  DestIterator d, DestShape const & dshape, DestAccessor dest,
630  Functor const & f);
631  }
632  \endcode
633 
634 
635  use argument objects in conjunction with \ref ArgumentObjectFactories :
636  \code
637  namespace vigra {
638  template <class SrcIterator, class SrcShape, class SrcAccessor,
639  class DestIterator, class DestAccessor,
640  class Functor>
641  void
642  transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
643  pair<DestIterator, DestAccessor> const & dest, Functor const & f);
644 
645 
646  template <class SrcIterator, class SrcShape, class SrcAccessor,
647  class DestIterator, class DestShape, class DestAccessor,
648  class Functor>
649  void
650  transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
651  triple<DestIterator, DestShape, DestAccessor> const & dest,
652  Functor const & f)
653  }
654  \endcode
655 
656  <b> Usage - Standard Mode:</b>
657 
658  Source and destination array have the same size.
659 
660  \code
661  #include <cmath> // for sqrt()
662 
663  typedef vigra::MultiArray<3, float> Array;
664  Array src(Array::size_type(100, 200, 50)),
665  dest(Array::size_type(100, 200, 50));
666  ...
667 
668  vigra::transformMultiArray(srcMultiArrayRange(src),
669  destMultiArray(dest),
670  (float(*)(float))&std::sqrt );
671 
672  \endcode
673 
674  <b> Usage - Expand Mode:</b>
675 
676  The source array is only 2D (it has depth 1). Thus, the destination
677  will contain 50 identical copies of the transformed source array.
678  Note that the destination shape must be passed to the algorithm for
679  the expansion to work, so we use <tt>destMultiArrayRange()</tt>
680  rather than <tt>destMultiArray()</tt>.
681 
682  \code
683  #include <cmath> // for sqrt()
684 
685  typedef vigra::MultiArray<3, float> Array;
686  Array src(Array::size_type(100, 200, 1)),
687  dest(Array::size_type(100, 200, 50));
688  ...
689 
690  vigra::transformMultiArray(srcMultiArrayRange(src),
691  destMultiArrayRange(dest),
692  (float(*)(float))&std::sqrt );
693 
694  \endcode
695 
696  <b> Usage - Reduce Mode:</b>
697 
698  The destination array is only 1D (it's width and height are 1).
699  Thus, it will contain accumulated data for every slice of the source volume
700  (or for every frame, if the source is intepreted as an image sequence).
701  In the example, we use the functor \ref vigra::FindAverage to calculate
702  the average gray value of every slice. Note that the destination shape
703  must also be passed for the reduction to work, so we use
704  <tt>destMultiArrayRange()</tt> rather than <tt>destMultiArray()</tt>.
705 
706  \code
707  typedef vigra::MultiArray<3, float> Array;
708  Array src(Array::size_type(100, 200, 50)),
709  dest(Array::size_type(1, 1, 50));
710  ...
711 
712  vigra::transformMultiArray(srcMultiArrayRange(src),
713  destMultiArrayRange(dest),
714  vigra::FindAverage<float>() );
715 
716  \endcode
717 
718  Note that the functor must define the appropriate traits described below in order to be
719  recognized as a reduce functor. This is most easily achieved by deriving from
720  <tt>UnaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
721 
722  <b> Required Interface:</b>
723 
724  In standard and expand mode, the functor must be a model of UnaryFunction
725  (i.e. support function call with one argument and a return value
726  <tt>res = functor(arg)</tt>):
727 
728  \code
729  MultiIterator src_begin, src_end, dest_begin;
730 
731  SrcAccessor src_accessor;
732  DestAccessor dest_accessor;
733  Functor functor;
734 
735  dest_accessor.set(functor(src_accessor(src_begin)), dest_begin);
736  \endcode
737 
738  In reduce mode, it must be a model of UnaryAnalyser (i.e. support function call
739  with one argument and no return vakue <tt>functor(arg)</tt>) and Initializer
740  (i.e. support function call with no argument, but return value
741  <tt>res = functor()</tt>). Internally, such functors are recognized by the
742  meta functions <tt>FunctorTraits<FUNCTOR>::isUnaryAnalyser</tt> and
743  <tt>FunctorTraits<FUNCTOR>::isInitializer</tt> which must both yield
744  <tt>VigraTrueType</tt>. Make sure that your functor correctly defines
745  <tt>FunctorTraits</tt> because otherwise reduce mode will not work.
746  This is most easily achieved by deriving the functor from
747  <tt>UnaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
748  In addition, the functor must be copy constructible in order to start each reduction
749  with a fresh functor.
750 
751  \code
752  MultiIterator src_begin, src_end, dest_begin;
753 
754  SrcAccessor src_accessor;
755  DestAccessor dest_accessor;
756 
757  FUNCTOR initial_functor, functor(initial_functor);
758  assert(typeid(FunctorTraits<FUNCTOR>::isInitializer) == typeid(VigraTrueType));
759  assert(typeid(FunctorTraits<FUNCTOR>::isUnaryAnalyser) == typeid(VigraTrueType));
760 
761  functor(src_accessor(src_begin));
762  dest_accessor.set(functor(), dest_begin);
763  \endcode
764 
765 */
767 
768 template <class SrcIterator, class SrcShape, class SrcAccessor,
769  class DestIterator, class DestAccessor,
770  class Functor>
771 inline void
772 transformMultiArray(SrcIterator s, SrcShape const & shape, SrcAccessor src,
773  DestIterator d, DestAccessor dest, Functor const & f)
774 {
775  transformMultiArrayExpandImpl(s, shape, src, d, shape, dest,
776  f, MetaInt<SrcIterator::level>());
777 }
778 
779 template <class SrcIterator, class SrcShape, class SrcAccessor,
780  class DestIterator, class DestAccessor,
781  class Functor>
782 inline void
783 transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
784  pair<DestIterator, DestAccessor> const & dest, Functor const & f)
785 {
786 
787  transformMultiArray(src.first, src.second, src.third,
788  dest.first, dest.second, f);
789 }
790 
791 template <class SrcIterator, class SrcShape, class SrcAccessor,
792  class DestIterator, class DestShape, class DestAccessor,
793  class Functor>
794 void
795 transformMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
796  DestIterator d, DestShape const & dshape, DestAccessor dest,
797  Functor const & f)
798 {
799  vigra_precondition(sshape.size() == dshape.size(),
800  "transformMultiArray(): dimensionality of source and destination array differ");
801  typedef FunctorTraits<Functor> FT;
802  typedef typename
803  And<typename FT::isInitializer, typename FT::isUnaryAnalyser>::result
804  isAnalyserInitializer;
805  transformMultiArrayImpl(s, sshape, src, d, dshape, dest,
806  f, isAnalyserInitializer());
807 }
808 
809 template <class SrcIterator, class SrcShape, class SrcAccessor,
810  class DestIterator, class DestShape, class DestAccessor,
811  class Functor>
812 inline void
813 transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
814  triple<DestIterator, DestShape, DestAccessor> const & dest,
815  Functor const & f)
816 {
817  transformMultiArray(src.first, src.second, src.third,
818  dest.first, dest.second, dest.third, f);
819 }
820 
821 /********************************************************/
822 /* */
823 /* combineTwoMultiArrays */
824 /* */
825 /********************************************************/
826 
827 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
828  class SrcIterator2, class SrcAccessor2,
829  class DestIterator, class DestShape, class DestAccessor,
830  class Functor>
831 void
832 combineTwoMultiArraysReduceImpl(
833  SrcIterator1 s1, SrcShape const & , SrcAccessor1 src1,
834  SrcIterator2 s2, SrcAccessor2 src2,
835  DestIterator d, DestShape const & dshape, DestAccessor dest,
836  SrcShape const & reduceShape,
837  Functor const & ff, MetaInt<0>)
838 {
839  DestIterator dend = d + dshape[0];
840  for(; d < dend; ++s1.template dim<0>(), ++s2.template dim<0>(), ++d)
841  {
842  Functor f = ff;
843  inspectTwoMultiArrays(s1, reduceShape, src1, s2, src2, f);
844  dest.set(f(), d);
845  }
846 }
847 
848 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
849  class SrcIterator2, class SrcAccessor2,
850  class DestIterator, class DestShape, class DestAccessor,
851  class Functor, int N>
852 void
853 combineTwoMultiArraysReduceImpl(
854  SrcIterator1 s1, SrcShape const & sshape, SrcAccessor1 src1,
855  SrcIterator2 s2, SrcAccessor2 src2,
856  DestIterator d, DestShape const & dshape, DestAccessor dest,
857  SrcShape const & reduceShape,
858  Functor const & f, MetaInt<N>)
859 {
860  DestIterator dend = d + dshape[N];
861  for(; d < dend; ++s1.template dim<N>(), ++s2.template dim<N>(), ++d)
862  {
863  combineTwoMultiArraysReduceImpl(s1, sshape, src1, s2, src2,
864  d.begin(), dshape, dest,
865  reduceShape, f, MetaInt<N-1>());
866  }
867 }
868 
869 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
870  class SrcIterator2, class SrcShape2, class SrcAccessor2,
871  class DestIterator, class DestShape, class DestAccessor,
872  class Functor>
873 void
874 combineTwoMultiArraysImpl(
875  SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
876  SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
877  DestIterator d, DestShape const & dshape, DestAccessor dest,
878  Functor const & f, VigraTrueType)
879 {
880  // reduce mode
881  SrcShape1 reduceShape = sshape1;
882  for(unsigned int i=0; i<dshape.size(); ++i)
883  {
884  vigra_precondition(sshape1[i] == sshape2[i] &&
885  (dshape[i] == 1 || sshape1[i] == dshape[i]),
886  "combineTwoMultiArrays(): mismatch between source and destination shapes:\n"
887  "In 'reduce'-mode, the two source shapes must be equal, and\n"
888  "the length of each destination dimension must either be 1\n"
889  "or equal to the corresponding source length.");
890  if(dshape[i] != 1)
891  reduceShape[i] = 1;
892  }
893  combineTwoMultiArraysReduceImpl(s1, sshape1, src1, s2, src2,
894  d, dshape, dest, reduceShape,
895  f, MetaInt<SrcIterator1::level>());
896 }
897 
898 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
899  class SrcIterator2, class SrcShape2, class SrcAccessor2,
900  class DestIterator, class DestShape, class DestAccessor,
901  class Functor>
902 void
903 combineTwoMultiArraysExpandImpl(
904  SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
905  SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
906  DestIterator d, DestShape const & dshape, DestAccessor dest,
907  Functor const & f, MetaInt<0>)
908 {
909  DestIterator dend = d + dshape[0];
910  if(sshape1[0] == 1 && sshape2[0] == 1)
911  {
912  initLine(d, dend, dest, f(src1(s1), src2(s2)));
913  }
914  else if(sshape1[0] == 1)
915  {
916  typename SrcAccessor1::value_type sv1 = src1(s1);
917  for(; d < dend; ++d, ++s2)
918  dest.set(f(sv1, src2(s2)), d);
919  }
920  else if(sshape2[0] == 1)
921  {
922  typename SrcAccessor2::value_type sv2 = src2(s2);
923  for(; d < dend; ++d, ++s1)
924  dest.set(f(src1(s1), sv2), d);
925  }
926  else
927  {
928  combineTwoLines(s1, s1 + sshape1[0], src1, s2, src2, d, dest, f);
929  }
930 }
931 
932 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
933  class SrcIterator2, class SrcShape2, class SrcAccessor2,
934  class DestIterator, class DestShape, class DestAccessor,
935  class Functor, int N>
936 void
937 combineTwoMultiArraysExpandImpl(
938  SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
939  SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
940  DestIterator d, DestShape const & dshape, DestAccessor dest,
941  Functor const & f, MetaInt<N>)
942 {
943  DestIterator dend = d + dshape[N];
944  int s1inc = sshape1[N] == 1
945  ? 0
946  : 1;
947  int s2inc = sshape2[N] == 1
948  ? 0
949  : 1;
950  for(; d < dend; ++d, s1 += s1inc, s2 += s2inc)
951  {
952  combineTwoMultiArraysExpandImpl(s1.begin(), sshape1, src1,
953  s2.begin(), sshape2, src2,
954  d.begin(), dshape, dest,
955  f, MetaInt<N-1>());
956  }
957 }
958 
959 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
960  class SrcIterator2, class SrcShape2, class SrcAccessor2,
961  class DestIterator, class DestShape, class DestAccessor,
962  class Functor>
963 void
964 combineTwoMultiArraysImpl(
965  SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
966  SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
967  DestIterator d, DestShape const & dshape, DestAccessor dest,
968  Functor const & f, VigraFalseType)
969 {
970  // expand mode
971  for(unsigned int i=0; i<sshape1.size(); ++i)
972  vigra_precondition((sshape1[i] == 1 || sshape1[i] == dshape[i]) &&
973  (sshape2[i] == 1 || sshape2[i] == dshape[i]),
974  "combineTwoMultiArrays(): mismatch between source and destination shapes:\n"
975  "In 'expand'-mode, the length of each source dimension must either be 1\n"
976  "or equal to the corresponding destination length.");
977  combineTwoMultiArraysExpandImpl(s1, sshape1, src1, s2, sshape2, src2,
978  d, dshape, dest,
979  f, MetaInt<SrcIterator1::level>());
980 }
981 
982 /** \brief Combine two multi-dimensional arrays into one using a binary function or functor.
983 
984  This function can be applied in three modes:
985 
986  <DL>
987  <DT><b>Standard Mode:</b>
988  <DD>If the source and destination arrays have the same size,
989  the transformation given by the functor is applied to every pair of
990  corresponding source elements and the result written into the corresponding
991  destination element.
992  Binary functions, binary functors from the STL and the functors specifically
993  defined in \ref CombineFunctor can be used in standard mode.
994  Creation of new functors is easiest by using \ref FunctorExpressions.
995  <DT><b>Expanding Mode:</b>
996  <DD>If the source arrays have length 1 along some (or even all) dimensions,
997  the source values at index 0 are used for all destination
998  elements in those dimensions. In other words, the source index is not
999  incremented along those dimensions, but the transformation functor
1000  is applied as usual. So, we can expand small arrays (e.g. a single row of data,
1001  column length is 1), into larger ones (e.g. a 2D image with the same width):
1002  the given values are simply reused as necessary (e.g. for every row of the
1003  destination image). It is not even necessary that the source array shapes
1004  are equal. For example, we can combine a small array with one that
1005  hase the same size as the destination array.
1006  The same functors as in standard mode can be applied.
1007  <DT><b>Reducing Mode:</b>
1008  <DD>If the destination array has length 1 along some (or even all) dimensions,
1009  the source values in these dimensions are reduced to single values by means
1010  of a suitable functor which supports two function call operators: one
1011  with two arguments to collect the values, and one without argument to
1012  obtain the final (reduced) result. This behavior is a multi-dimensional
1013  generalization of the C++ standard function <tt>std::accumulate()</tt>.
1014  </DL>
1015 
1016  The arrays must be represented by
1017  iterators compatible with \ref vigra::MultiIterator, and the iteration range
1018  is specified by means of shape objects. If only a single source shape is given
1019  the destination array is assumed to have the same shape, and standard mode
1020  is applied. If three shapes are given, the size of corresponding dimensions
1021  must be either equal (standard copy), or the length of this dimension must
1022  be 1 in one or both source arrays
1023  (expand mode), or the destination length must be 1 (reduce mode). However,
1024  reduction and expansion cannot be executed at the same time, so the latter
1025  conditions are mutual exclusive, even if they apply to different dimensions.
1026 
1027  The function uses accessors to access the data elements.
1028 
1029  <b> Declarations:</b>
1030 
1031  <b>\#include</b> <<a href="multi__pointoperators_8hxx-source.html">vigra/multi_pointoperators.hxx</a>><br>
1032  Namespace: vigra
1033 
1034  pass arguments explicitly:
1035  \code
1036  namespace vigra {
1037  template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1038  class SrcIterator2, class SrcAccessor2,
1039  class DestIterator, class DestAccessor,
1040  class Functor>
1041  void combineTwoMultiArrays(
1042  SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
1043  SrcIterator2 s2, SrcAccessor2 src2,
1044  DestIterator d, DestAccessor dest, Functor const & f);
1045 
1046 
1047  template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
1048  class SrcIterator2, class SrcShape2, class SrcAccessor2,
1049  class DestIterator, class DestShape, class DestAccessor,
1050  class Functor>
1051  void combineTwoMultiArrays(
1052  SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
1053  SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
1054  DestIterator d, DestShape const & dshape, DestAccessor dest,
1055  Functor const & f);
1056  }
1057  \endcode
1058 
1059 
1060  use argument objects in conjunction with \ref ArgumentObjectFactories :
1061  \code
1062  namespace vigra {
1063  template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1064  class SrcIterator2, class SrcAccessor2,
1065  class DestIterator, class DestAccessor, class Functor>
1066  void combineTwoMultiArrays(
1067  triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
1068  pair<SrcIterator2, SrcAccessor2> const & src2,
1069  pair<DestIterator, DestAccessor> const & dest, Functor const & f);
1070 
1071 
1072  template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
1073  class SrcIterator2, class SrcShape2, class SrcAccessor2,
1074  class DestIterator, class DestShape, class DestAccessor,
1075  class Functor>
1076  void combineTwoMultiArrays(
1077  triple<SrcIterator1, SrcShape1, SrcAccessor1> const & src1,
1078  triple<SrcIterator2, SrcShape2, SrcAccessor2> const & src2,
1079  triple<DestIterator, DestShape, DestAccessor> const & dest,
1080  Functor const & f);
1081  }
1082  \endcode
1083 
1084  <b> Usage - Standard Mode:</b>
1085 
1086  Source and destination arrays have the same size.
1087 
1088  \code
1089  #include <functional> // for std::plus
1090 
1091  typedef vigra::MultiArray<3, int> Array;
1092  Array src1(Array::size_type(100, 200, 50)),
1093  src2(Array::size_type(100, 200, 50)),
1094  dest(Array::size_type(100, 200, 50));
1095  ...
1096 
1097  vigra::combineTwoMultiArrays(
1098  srcMultiArrayRange(src1),
1099  srcMultiArray(src2),
1100  destMultiArray(dest),
1101  std::plus<int>());
1102 
1103  \endcode
1104 
1105  <b> Usage - Expand Mode:</b>
1106 
1107  One source array is only 2D (it has depth 1). This image will be added
1108  to every slice of the other source array, and the result
1109  if written into the corresponding destination slice. Note that the shapes
1110  of all arrays must be passed to the algorithm, so we use
1111  <tt>srcMultiArrayRange()</tt> and <tt>destMultiArrayRange()</tt>
1112  rather than <tt>srcMultiArray()</tt> and <tt>destMultiArray()</tt>.
1113 
1114  \code
1115  #include <functional> // for std::plus
1116 
1117  typedef vigra::MultiArray<3, int> Array;
1118  Array src1(Array::size_type(100, 200, 1)),
1119  src2(Array::size_type(100, 200, 50)),
1120  dest(Array::size_type(100, 200, 50));
1121  ...
1122 
1123  vigra::combineTwoMultiArrays(
1124  srcMultiArrayRange(src1),
1125  srcMultiArray(src2),
1126  destMultiArray(dest),
1127  std::plus<int>());
1128 
1129  \endcode
1130 
1131  <b> Usage - Reduce Mode:</b>
1132 
1133  The destination array is only 1D (it's width and height are 1).
1134  Thus, it will contain accumulated data for every slice of the source volumes
1135  (or for every frame, if the sources are intepreted as image sequences).
1136  In the example, we use \ref vigra::ReduceFunctor together with a functor
1137  expression (see \ref FunctorExpressions)
1138  to calculate the total absolute difference of the gray values in every pair of
1139  source slices. Note that the shapes of all arrays must be passed
1140  to the algorithm in order for the reduction to work, so we use
1141  <tt>srcMultiArrayRange()</tt> and <tt>destMultiArrayRange()</tt>
1142  rather than <tt>srcMultiArray()</tt> and <tt>destMultiArray()</tt>.
1143 
1144  \code
1145  #include <vigra/functorexpression.hxx>
1146  using namespace vigra::functor;
1147 
1148  typedef vigra::MultiArray<3, int> Array;
1149  Array src1(Array::size_type(100, 200, 50)),
1150  src2(Array::size_type(100, 200, 50)),
1151  dest(Array::size_type(1, 1, 50));
1152  ...
1153 
1154  vigra::combineTwoMultiArrays(
1155  srcMultiArrayRange(src1),
1156  srcMultiArray(src2),
1157  destMultiArray(dest),
1158  reduceFunctor(Arg1() + abs(Arg2() - Arg3()), 0) );
1159  // Arg1() is the sum accumulated so far, initialzed with 0
1160 
1161  \endcode
1162 
1163  Note that the functor must define the appropriate traits described below in order to be
1164  recognized as a reduce functor. This is most easily achieved by deriving from
1165  <tt>BinaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
1166 
1167  <b> Required Interface:</b>
1168 
1169  In standard and expand mode, the functor must be a model of BinaryFunction
1170  (i.e. support function call with two arguments and a return value
1171  <tt>res = functor(arg1, arg2)</tt>):
1172 
1173  \code
1174  MultiIterator src1_begin, src2_begin, dest_begin;
1175 
1176  SrcAccessor1 src1_accessor;
1177  SrcAccessor2 src2_accessor;
1178  DestAccessor dest_accessor;
1179 
1180  Functor functor;
1181 
1182  dest_accessor.set(
1183  functor(src1_accessor(src1_begin), src2_accessor(src2_begin)),
1184  dest_begin);
1185 
1186  \endcode
1187 
1188  In reduce mode, it must be a model of BinaryAnalyser (i.e. support function call
1189  with two arguments and no return vakue <tt>functor(arg1, arg2)</tt>) and Initializer
1190  (i.e. support function call with no argument, but return value
1191  <tt>res = functor()</tt>). Internally, such functors are recognized by the
1192  meta functions <tt>FunctorTraits<FUNCTOR>::isBinaryAnalyser</tt> and
1193  <tt>FunctorTraits<FUNCTOR>::isInitializer</tt> which must both yield
1194  <tt>VigraTrueType</tt>. Make sure that your functor correctly defines
1195  <tt>FunctorTraits</tt> because otherwise reduce mode will not work.
1196  This is most easily achieved by deriving the functor from
1197  <tt>BinaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
1198  In addition, the functor must be copy constructible in order to start each reduction
1199  with a fresh functor.
1200 
1201  \code
1202  MultiIterator src1_begin, src2_begin, dest_begin;
1203 
1204  SrcAccessor1 src1_accessor;
1205  SrcAccessor2 src2_accessor;
1206  DestAccessor dest_accessor;
1207 
1208  FUNCTOR initial_functor, functor(initial_functor);
1209  assert(typeid(FunctorTraits<FUNCTOR>::isInitializer) == typeid(VigraTrueType));
1210  assert(typeid(FunctorTraits<FUNCTOR>::isBinaryAnalyser) == typeid(VigraTrueType));
1211 
1212  functor(src1_accessor(src1_begin), src2_accessor(src2_begin));
1213  dest_accessor.set(functor(), dest_begin);
1214  \endcode
1215 
1216 */
1218 
1219 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1220  class SrcIterator2, class SrcAccessor2,
1221  class DestIterator, class DestAccessor,
1222  class Functor>
1223 inline void
1224 combineTwoMultiArrays(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
1225  SrcIterator2 s2, SrcAccessor2 src2,
1226  DestIterator d, DestAccessor dest, Functor const & f)
1227 {
1228  combineTwoMultiArraysExpandImpl(s1, shape, src1, s2, shape, src2, d, shape, dest, f,
1229  MetaInt<SrcIterator1::level>());
1230 }
1231 
1232 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1233  class SrcIterator2, class SrcAccessor2,
1234  class DestIterator, class DestAccessor, class Functor>
1235 inline void
1236 combineTwoMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
1237  pair<SrcIterator2, SrcAccessor2> const & src2,
1238  pair<DestIterator, DestAccessor> const & dest, Functor const & f)
1239 {
1240 
1242  src1.first, src1.second, src1.third,
1243  src2.first, src2.second, dest.first, dest.second, f);
1244 }
1245 
1246 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
1247  class SrcIterator2, class SrcShape2, class SrcAccessor2,
1248  class DestIterator, class DestShape, class DestAccessor,
1249  class Functor>
1250 void
1252  SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
1253  SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
1254  DestIterator d, DestShape const & dshape, DestAccessor dest,
1255  Functor const & f)
1256 {
1257  vigra_precondition(sshape1.size() == dshape.size() && sshape2.size() == dshape.size(),
1258  "combineTwoMultiArrays(): dimensionality of source and destination arrays differ");
1259 
1260  typedef FunctorTraits<Functor> FT;
1261  typedef typename
1262  And<typename FT::isInitializer, typename FT::isBinaryAnalyser>::result
1263  isAnalyserInitializer;
1264  combineTwoMultiArraysImpl(s1, sshape1, src1, s2, sshape2, src2, d, dshape, dest,
1265  f, isAnalyserInitializer());
1266 }
1267 
1268 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
1269  class SrcIterator2, class SrcShape2, class SrcAccessor2,
1270  class DestIterator, class DestShape, class DestAccessor,
1271  class Functor>
1272 inline void
1274  triple<SrcIterator1, SrcShape1, SrcAccessor1> const & src1,
1275  triple<SrcIterator2, SrcShape2, SrcAccessor2> const & src2,
1276  triple<DestIterator, DestShape, DestAccessor> const & dest,
1277  Functor const & f)
1278 {
1279  combineTwoMultiArrays(src1.first, src1.second, src1.third,
1280  src2.first, src2.second, src2.third,
1281  dest.first, dest.second, dest.third, f);
1282 }
1283 
1284 /********************************************************/
1285 /* */
1286 /* combineThreeMultiArrays */
1287 /* */
1288 /********************************************************/
1289 
1290 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1291  class SrcIterator2, class SrcAccessor2,
1292  class SrcIterator3, class SrcAccessor3,
1293  class DestIterator, class DestAccessor,
1294  class Functor>
1295 inline void
1296 combineThreeMultiArraysImpl(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
1297  SrcIterator2 s2, SrcAccessor2 src2,
1298  SrcIterator3 s3, SrcAccessor3 src3,
1299  DestIterator d, DestAccessor dest, Functor const & f, MetaInt<0>)
1300 {
1301  combineThreeLines(s1, s1 + shape[0], src1, s2, src2, s3, src3, d, dest, f);
1302 }
1303 
1304 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1305  class SrcIterator2, class SrcAccessor2,
1306  class SrcIterator3, class SrcAccessor3,
1307  class DestIterator, class DestAccessor,
1308  class Functor, int N>
1309 void
1310 combineThreeMultiArraysImpl(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
1311  SrcIterator2 s2, SrcAccessor2 src2,
1312  SrcIterator3 s3, SrcAccessor3 src3,
1313  DestIterator d, DestAccessor dest,
1314  Functor const & f, MetaInt<N>)
1315 {
1316  SrcIterator1 s1end = s1 + shape[N];
1317  for(; s1 < s1end; ++s1, ++s2, ++s3, ++d)
1318  {
1319  combineThreeMultiArraysImpl(s1.begin(), shape, src1,
1320  s2.begin(), src2, s3.begin(), src3, d.begin(), dest,
1321  f, MetaInt<N-1>());
1322  }
1323 }
1324 
1325 
1326 /** \brief Combine three multi-dimensional arrays into one using a
1327  ternary function or functor.
1328 
1329  Except for the fact that it operates on three input arrays, this function is
1330  identical to \ref combineTwoMultiArrays().
1331 
1332  <b> Declarations:</b>
1333 
1334  pass arguments explicitly:
1335  \code
1336  namespace vigra {
1337  template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1338  class SrcIterator2, class SrcAccessor2,
1339  class SrcIterator3, class SrcAccessor3,
1340  class DestIterator, class DestAccessor,
1341  class Functor>
1342  void
1343  combineThreeMultiArrays(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
1344  SrcIterator2 s2, SrcAccessor2 src2,
1345  SrcIterator3 s3, SrcAccessor3 src3,
1346  DestIterator d, DestAccessor dest, Functor const & f);
1347  }
1348  \endcode
1349 
1350 
1351  use argument objects in conjunction with \ref ArgumentObjectFactories :
1352  \code
1353  namespace vigra {
1354  template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1355  class SrcIterator2, class SrcAccessor2,
1356  class SrcIterator3, class SrcAccessor3,
1357  class DestIterator, class DestAccessor,
1358  class Functor>
1359  inline void
1360  combineThreeMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
1361  pair<SrcIterator2, SrcAccessor2> const & src2,
1362  pair<SrcIterator3, SrcAccessor3> const & src3,
1363  pair<DestIterator, DestAccessor> const & dest, Functor const & f);
1364  }
1365  \endcode
1366 
1367  <b> Usage:</b>
1368 
1369  <b>\#include</b> <<a href="multi__pointoperators_8hxx-source.html">vigra/multi_pointoperators.hxx</a>><br>
1370  Namespace: vigra
1371 
1372  \code
1373  #include <functional> // for plus
1374 
1375  typedef vigra::MultiArray<3, int> Array;
1376  Array src1(Array::size_type(100, 200, 50)),
1377  src2(Array::size_type(100, 200, 50)),
1378  src3(Array::size_type(100, 200, 50)),
1379  dest(Array::size_type(100, 200, 50));
1380  ...
1381 
1382  vigra::combineThreeMultiArrays(
1383  srcMultiArrayRange(src1),
1384  srcMultiArray(src2),
1385  srcMultiArray(src3),
1386  destMultiArray(dest),
1387  SomeThreeArgumentFunctor());
1388 
1389  \endcode
1390 */
1392 
1393 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1394  class SrcIterator2, class SrcAccessor2,
1395  class SrcIterator3, class SrcAccessor3,
1396  class DestIterator, class DestAccessor,
1397  class Functor>
1398 inline void
1399 combineThreeMultiArrays(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
1400  SrcIterator2 s2, SrcAccessor2 src2,
1401  SrcIterator3 s3, SrcAccessor3 src3,
1402  DestIterator d, DestAccessor dest, Functor const & f)
1403 {
1404  combineThreeMultiArraysImpl(s1, shape, src1, s2, src2, s3, src3, d, dest, f,
1405  MetaInt<SrcIterator1::level>());
1406 }
1407 
1408 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
1409  class SrcIterator2, class SrcAccessor2,
1410  class SrcIterator3, class SrcAccessor3,
1411  class DestIterator, class DestAccessor,
1412  class Functor>
1413 inline void
1414 combineThreeMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
1415  pair<SrcIterator2, SrcAccessor2> const & src2,
1416  pair<SrcIterator3, SrcAccessor3> const & src3,
1417  pair<DestIterator, DestAccessor> const & dest, Functor const & f)
1418 {
1419 
1421  src1.first, src1.second, src1.third,
1422  src2.first, src2.second, src3.first, src3.second, dest.first, dest.second, f);
1423 }
1424 
1425 /********************************************************/
1426 /* */
1427 /* inspectMultiArray */
1428 /* */
1429 /********************************************************/
1430 
1431 template <class Iterator, class Shape, class Accessor, class Functor>
1432 inline void
1433 inspectMultiArrayImpl(Iterator s, Shape const & shape, Accessor a, Functor & f, MetaInt<0>)
1434 {
1435  inspectLine(s, s + shape[0], a, f);
1436 }
1437 
1438 template <class Iterator, class Shape, class Accessor, class Functor, int N>
1439 void
1440 inspectMultiArrayImpl(Iterator s, Shape const & shape, Accessor a, Functor & f, MetaInt<N>)
1441 {
1442  Iterator send = s + shape[N];
1443  for(; s < send; ++s)
1444  {
1445  inspectMultiArrayImpl(s.begin(), shape, a, f, MetaInt<N-1>());
1446  }
1447 }
1448 
1449 /** \brief Call an analyzing functor at every element of a multi-dimensional array.
1450 
1451  This function can be used to collect statistics of the array etc.
1452  The results must be stored in the functor, which serves as a return
1453  value. The arrays must be represented by
1454  iterators compatible with \ref vigra::MultiIterator.
1455  The function uses an accessor to access the pixel data. Note that the iterator range
1456  must be specified by a shape object, because otherwise we could not control
1457  the range simultaneously in all dimensions (this is a necessary consequence
1458  of the \ref vigra::MultiIterator design).
1459 
1460  <b> Declarations:</b>
1461 
1462  pass arguments explicitly:
1463  \code
1464  namespace vigra {
1465  template <class Iterator, class Shape, class Accessor, class Functor>
1466  void
1467  inspectMultiArray(Iterator s, Shape const & shape, Accessor a, Functor & f);
1468  }
1469  \endcode
1470 
1471  use argument objects in conjunction with \ref ArgumentObjectFactories :
1472  \code
1473  namespace vigra {
1474  template <class Iterator, class Shape, class Accessor, class Functor>
1475  void
1476  inspectMultiArray(triple<Iterator, Shape, Accessor> const & s, Functor & f);
1477  }
1478  \endcode
1479 
1480  <b> Usage:</b>
1481 
1482  <b>\#include</b> <<a href="multi__pointoperators_8hxx-source.html">vigra/multi_pointoperators.hxx</a>><br>
1483  Namespace: vigra
1484 
1485  \code
1486  typedef vigra::MultiArray<3, int> Array;
1487  Array array(Array::size_type(100, 200, 50));
1488 
1489  // init functor
1490  vigra::FindMinMax<int> minmax;
1491 
1492  vigra::inspectMultiArray(srcMultiArrayRange(array), minmax);
1493 
1494  cout << "Min: " << minmax.min << " Max: " << minmax.max;
1495 
1496  \endcode
1497 
1498  <b> Required Interface:</b>
1499 
1500  \code
1501  MultiIterator src_begin;
1502 
1503  Accessor accessor;
1504  Functor functor;
1505 
1506  functor(accessor(src_begin));
1507  \endcode
1508 
1509 */
1511 
1512 template <class Iterator, class Shape, class Accessor, class Functor>
1513 inline void
1514 inspectMultiArray(Iterator s, Shape const & shape, Accessor a, Functor & f)
1515 {
1516  inspectMultiArrayImpl(s, shape, a, f, MetaInt<Iterator::level>());
1517 }
1518 
1519 template <class Iterator, class Shape, class Accessor, class Functor>
1520 inline void
1521 inspectMultiArray(triple<Iterator, Shape, Accessor> const & s, Functor & f)
1522 {
1523  inspectMultiArray(s.first, s.second, s.third, f);
1524 }
1525 
1526 /********************************************************/
1527 /* */
1528 /* inspectTwoMultiArrays */
1529 /* */
1530 /********************************************************/
1531 
1532 template <class Iterator1, class Shape, class Accessor1,
1533  class Iterator2, class Accessor2,
1534  class Functor>
1535 inline void
1536 inspectTwoMultiArraysImpl(Iterator1 s1, Shape const & shape, Accessor1 a1,
1537  Iterator2 s2, Accessor2 a2,
1538  Functor & f, MetaInt<0>)
1539 {
1540  inspectTwoLines(s1, s1 + shape[0], a1, s2, a2, f);
1541 }
1542 
1543 template <class Iterator1, class Shape, class Accessor1,
1544  class Iterator2, class Accessor2,
1545  class Functor, int N>
1546 void
1547 inspectTwoMultiArraysImpl(Iterator1 s1, Shape const & shape, Accessor1 a1,
1548  Iterator2 s2, Accessor2 a2,
1549  Functor & f, MetaInt<N>)
1550 {
1551  Iterator1 s1end = s1 + shape[N];
1552  for(; s1 < s1end; ++s1, ++s2)
1553  {
1554  inspectTwoMultiArraysImpl(s1.begin(), shape, a1,
1555  s2.begin(), a2, f, MetaInt<N-1>());
1556  }
1557 }
1558 
1559 /** \brief Call an analyzing functor at all corresponding elements of
1560  two multi-dimensional arrays.
1561 
1562  This function can be used to collect statistics of the array etc.
1563  The results must be stored in the functor, which serves as a return
1564  value. The arrays must be represented by
1565  iterators compatible with \ref vigra::MultiIterator.
1566  The function uses an accessor to access the pixel data. Note that the iterator range
1567  must be specified by a shape object, because otherwise we could not control
1568  the range simultaneously in all dimensions (this is a necessary consequence
1569  of the \ref vigra::MultiIterator design).
1570 
1571  <b> Declarations:</b>
1572 
1573  pass arguments explicitly:
1574  \code
1575  namespace vigra {
1576  template <class Iterator1, class Shape, class Accessor1,
1577  class Iterator2, class Accessor2,
1578  class Functor>
1579  void
1580  inspectTwoMultiArrays(Iterator1 s1, Shape const & shape, Accessor1 a1,
1581  Iterator2 s2, Accessor2 a2, Functor & f);
1582  }
1583  \endcode
1584 
1585  use argument objects in conjunction with \ref ArgumentObjectFactories :
1586  \code
1587  namespace vigra {
1588  template <class Iterator1, class Shape1, class Accessor1,
1589  class Iterator2, class Accessor2,
1590  class Functor>
1591  void
1592  inspectTwoMultiArrays(triple<Iterator1, Shape1, Accessor1> const & s1,
1593  pair<Iterator2, Accessor2> const & s2, Functor & f);
1594  }
1595  \endcode
1596 
1597  <b> Usage:</b>
1598 
1599  <b>\#include</b> <<a href="multi__pointoperators_8hxx-source.html">vigra/multi_pointoperators.hxx</a>><br>
1600  Namespace: vigra
1601 
1602  \code
1603  typedef vigra::MultiArray<3, int> Array;
1604  Array array1(Array::size_type(100, 200, 50)),
1605  array2(Array::size_type(100, 200, 50));
1606 
1607  // init functor
1608  SomeStatisticsFunctor stats(..);
1609 
1610  vigra::inspectTwoMultiArrays(srcMultiArrayRange(array1), srcMultiArray(array2), stats);
1611 
1612  \endcode
1613 
1614  <b> Required Interface:</b>
1615 
1616  \code
1617  MultiIterator src1_begin, src2_begin;
1618 
1619  Accessor a1, a2;
1620  Functor functor;
1621 
1622  functor(a1(src1_begin), a2(src2_begin));
1623  \endcode
1624 
1625 */
1627 
1628 template <class Iterator1, class Shape, class Accessor1,
1629  class Iterator2, class Accessor2,
1630  class Functor>
1631 inline void
1632 inspectTwoMultiArrays(Iterator1 s1, Shape const & shape, Accessor1 a1,
1633  Iterator2 s2, Accessor2 a2, Functor & f)
1634 {
1635  inspectTwoMultiArraysImpl(s1, shape, a1, s2, a2, f, MetaInt<Iterator1::level>());
1636 }
1637 
1638 template <class Iterator1, class Shape, class Accessor1,
1639  class Iterator2, class Accessor2,
1640  class Functor>
1641 inline
1642 void
1643 inspectTwoMultiArrays(triple<Iterator1, Shape, Accessor1> const & s1,
1644  pair<Iterator2, Accessor2> const & s2, Functor & f)
1645 {
1646  inspectTwoMultiArrays(s1.first, s1.second, s1.third,
1647  s2.first, s2.second, f);
1648 }
1649 
1650 //@}
1651 
1652 } //-- namespace vigra
1653 
1654 
1655 #endif //-- VIGRA_MULTI_POINTOPERATORS_H

© 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.7.1 (Tue Jul 10 2012)