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