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

vigra/multi_pointoperators.hxx VIGRA

00001 //-- -*- c++ -*-
00002 /************************************************************************/
00003 /*                                                                      */
00004 /*      Copyright 2003 by Ullrich Koethe, B. Seppke, F. Heinrich        */
00005 /*                                                                      */
00006 /*    This file is part of the VIGRA computer vision library.           */
00007 /*    The VIGRA Website is                                              */
00008 /*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
00009 /*    Please direct questions, bug reports, and contributions to        */
00010 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
00011 /*        vigra@informatik.uni-hamburg.de                               */
00012 /*                                                                      */
00013 /*    Permission is hereby granted, free of charge, to any person       */
00014 /*    obtaining a copy of this software and associated documentation    */
00015 /*    files (the "Software"), to deal in the Software without           */
00016 /*    restriction, including without limitation the rights to use,      */
00017 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
00018 /*    sell copies of the Software, and to permit persons to whom the    */
00019 /*    Software is furnished to do so, subject to the following          */
00020 /*    conditions:                                                       */
00021 /*                                                                      */
00022 /*    The above copyright notice and this permission notice shall be    */
00023 /*    included in all copies or substantial portions of the             */
00024 /*    Software.                                                         */
00025 /*                                                                      */
00026 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
00027 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
00028 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
00029 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
00030 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
00031 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
00032 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
00033 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
00034 /*                                                                      */
00035 /************************************************************************/
00036 
00037 #ifndef VIGRA_MULTI_POINTOPERATORS_H
00038 #define VIGRA_MULTI_POINTOPERATORS_H
00039 
00040 #include "initimage.hxx"
00041 #include "copyimage.hxx"
00042 #include "transformimage.hxx"
00043 #include "combineimages.hxx"
00044 #include "inspectimage.hxx"
00045 #include "multi_array.hxx"
00046 #include "metaprogramming.hxx"
00047 
00048 
00049 
00050 namespace vigra
00051 {
00052 
00053 /** \addtogroup MultiPointoperators Point operators for multi-dimensional arrays.
00054 
00055     Copy, transform, and inspect arbitrary dimensional arrays which are represented
00056     by iterators compatible to \ref MultiIteratorPage. Note that are range is here
00057     specified by a pair: an iterator referring to the first point of the array 
00058     and a shape object specifying the size of the (rectangular) ROI.
00059 
00060     <b>\#include</b> <vigra/multi_pointoperators.hxx>
00061 */
00062 //@{
00063 
00064 /********************************************************/
00065 /*                                                      */
00066 /*                    initMultiArray                    */
00067 /*                                                      */
00068 /********************************************************/
00069 
00070 template <class Iterator, class Shape, class Accessor, 
00071           class VALUETYPE>
00072 inline void
00073 initMultiArrayImpl(Iterator s, Shape const & shape, Accessor a,  VALUETYPE const & v, MetaInt<0>)
00074 {
00075     initLine(s, s + shape[0], a, v);
00076 }
00077     
00078 template <class Iterator, class Shape, class Accessor, 
00079           class VALUETYPE, int N>
00080 void
00081 initMultiArrayImpl(Iterator s, Shape const & shape, Accessor a,  
00082                    VALUETYPE const & v, MetaInt<N>)
00083 {
00084     Iterator send = s + shape[N];
00085     for(; s < send; ++s)
00086     {
00087         initMultiArrayImpl(s.begin(), shape, a, v, MetaInt<N-1>());
00088     }
00089 }
00090     
00091 /** \brief Write a value to every pixel in a multi-dimensional array.
00092 
00093     This function can be used to init the array which must be represented by
00094     a pair of iterators compatible to \ref vigra::MultiIterator.
00095     It uses an accessor to access the data elements. Note that the iterator range 
00096     must be specified by a shape object, because otherwise we could not control
00097     the range simultaneously in all dimensions (this is a necessary consequence
00098     of the \ref vigra::MultiIterator design).
00099     
00100     The initial value can either be a constant of appropriate type (compatible with 
00101     the destination's value_type), or a functor with compatible result_type. These two 
00102     cases are automatically distinguished when <tt>FunctorTraits<FUNCTOR>::isInitializer</tt>
00103     yields <tt>VigraTrueType</tt>. Since the functor is passed by <tt>const</tt> reference, its 
00104     <tt>operator()</tt> must be const, and its internal state may need to be <tt>mutable</tt>.
00105     
00106     <b> Declarations:</b>
00107     
00108     pass arguments explicitly:
00109     \code
00110     namespace vigra {
00111         template <class Iterator, class Shape, class Accessor, class VALUETYPE>
00112         void
00113         initMultiArray(Iterator s, Shape const & shape, Accessor a,  VALUETYPE const & v);
00114 
00115 
00116         template <class Iterator, class Shape, class Accessor, class FUNCTOR>
00117         void
00118         initMultiArray(Iterator s, Shape const & shape, Accessor a,  FUNCTOR const & f);
00119     }
00120     \endcode
00121 
00122     use argument objects in conjunction with \ref ArgumentObjectFactories :
00123     \code
00124     namespace vigra {
00125         template <class Iterator, class Shape, class Accessor, class VALUETYPE>
00126         void
00127         initMultiArray(triple<Iterator, Shape, Accessor> const & s, VALUETYPE const & v);
00128 
00129 
00130         template <class Iterator, class Shape, class Accessor, class FUNCTOR>
00131         void
00132         initMultiArray(triple<Iterator, Shape, Accessor> const & s, FUNCTOR const & f);
00133     }
00134     \endcode
00135     
00136     <b> Usage:</b>
00137     
00138     <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
00139     Namespace: vigra
00140     
00141     \code
00142     typedef vigra::MultiArray<3, int> Array;
00143     Array array(Array::size_type(100, 200, 50));
00144     
00145     // zero the array
00146     vigra::initMultiArray(destMultiArrayRange(array), 0);
00147     \endcode
00148 
00149     <b> Required Interface:</b>
00150     
00151     The function accepts either a value that is copied into every destination element: 
00152     
00153     \code
00154     MultiIterator begin;
00155     
00156     Accessor accessor;
00157     VALUETYPE v;
00158     
00159     accessor.set(v, begin); 
00160     \endcode
00161     
00162     or a functor that is called (without argument) at every location,
00163     and the result is written into the current element. Internally,
00164     functors are recognized by the meta function 
00165     <tt>FunctorTraits<FUNCTOR>::isInitializer</tt> yielding <tt>VigraTrueType</tt>.
00166     Make sure that your functor correctly defines <tt>FunctorTraits</tt> because
00167     otherwise the code will not compile.
00168     
00169     \code
00170     MultiIterator begin;    
00171     Accessor accessor;
00172     
00173     FUNCTOR f;
00174     assert(typeid(FunctorTraits<FUNCTOR>::isInitializer) == typeid(VigraTrueType));
00175     
00176     accessor.set(f(), begin); 
00177     \endcode
00178     
00179     
00180 */
00181 doxygen_overloaded_function(template <...> void initMultiArray)
00182 
00183 template <class Iterator, class Shape, class Accessor, class VALUETYPE>
00184 inline void
00185 initMultiArray(Iterator s, Shape const & shape, Accessor a,  VALUETYPE const & v)
00186 {
00187     initMultiArrayImpl(s, shape, a, v, MetaInt<Iterator::level>());
00188 }
00189     
00190 template <class Iterator, class Shape, class Accessor, class VALUETYPE>
00191 inline 
00192 void
00193 initMultiArray(triple<Iterator, Shape, Accessor> const & s, VALUETYPE const & v)
00194 {
00195     initMultiArray(s.first, s.second, s.third, v);
00196 }
00197 
00198 /********************************************************/
00199 /*                                                      */
00200 /*                  initMultiArrayBorder                */
00201 /*                                                      */
00202 /********************************************************/
00203 
00204 /** \brief Write value to the specified border values in the array.
00205 
00206 */template <class Iterator, class Diff_type, class Accessor, class VALUETYPE>
00207 inline void initMultiArrayBorder( Iterator upperleft, Diff_type shape, 
00208                                   Accessor a,  int border_width, VALUETYPE v)
00209 {
00210     Diff_type border(shape);
00211     for(unsigned int dim=0; dim<shape.size(); dim++){
00212         border[dim] = (border_width > shape[dim]) ? shape[dim] : border_width;
00213     }
00214 
00215     for(unsigned int dim=0; dim<shape.size(); dim++){
00216         Diff_type  start(shape),
00217                    offset(shape);
00218         start = start-shape;
00219         offset[dim]=border[dim];
00220 
00221         initMultiArray(upperleft+start, offset, a, v);
00222  
00223         start[dim]=shape[dim]-border[dim];
00224         initMultiArray(upperleft+start, offset, a, v);
00225     }
00226 }
00227     
00228 template <class Iterator, class Diff_type, class Accessor, class VALUETYPE>
00229 inline void initMultiArrayBorder( triple<Iterator, Diff_type, Accessor> multiArray, 
00230                                   int border_width, VALUETYPE v)
00231 {
00232     initMultiArrayBorder(multiArray.first, multiArray.second, multiArray.third, border_width, v);
00233 }
00234 
00235 
00236 /********************************************************/
00237 /*                                                      */
00238 /*                    copyMultiArray                    */
00239 /*                                                      */
00240 /********************************************************/
00241 
00242 template <class SrcIterator, class SrcShape, class SrcAccessor,
00243           class DestIterator, class DestShape, class DestAccessor>
00244 void
00245 copyMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
00246                DestIterator d, DestShape const & dshape, DestAccessor dest, MetaInt<0>)
00247 {
00248     if(sshape[0] == 1)
00249     {
00250         initLine(d, d + dshape[0], dest, src(s));
00251     }
00252     else
00253     {
00254         copyLine(s, s + sshape[0], src, d, dest);
00255     }
00256 }
00257     
00258 template <class SrcIterator, class SrcShape, class SrcAccessor,
00259           class DestIterator, class DestShape, class DestAccessor, int N>
00260 void
00261 copyMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
00262                    DestIterator d, DestShape const & dshape, DestAccessor dest, MetaInt<N>)
00263 {
00264     DestIterator dend = d + dshape[N];
00265     if(sshape[N] == 1)
00266     {
00267         for(; d < dend; ++d)
00268         {
00269             copyMultiArrayImpl(s.begin(), sshape, src, d.begin(), dshape, dest, MetaInt<N-1>());
00270         }
00271     }
00272     else
00273     {
00274         for(; d < dend; ++s, ++d)
00275         {
00276             copyMultiArrayImpl(s.begin(), sshape, src, d.begin(), dshape, dest, MetaInt<N-1>());
00277         }
00278     }
00279 }
00280     
00281 /** \brief Copy a multi-dimensional array.
00282 
00283     This function can be applied in two modes:
00284     
00285     <DL>
00286     <DT><b>Standard Mode:</b>
00287         <DD>If the source and destination arrays have the same size, 
00288         the corresponding array elements are simply copied.
00289         If necessary, type conversion takes place.
00290     <DT><b>Expanding Mode:</b>
00291         <DD>If the source array has length 1 along some (or even all) dimensions,
00292         the source value at index 0 is used for all destination
00293         elements in those dimensions. For example, if we have single row of data
00294         (column length is 1), we can copy it into a 2D image of the same width:
00295         The given row is automatically repeated for every row of the destination image.
00296         Again, type conversion os performed if necessary.
00297     </DL>
00298         
00299     The arrays must be represented by
00300     iterators compatible with \ref vigra::MultiIterator, and the iteration range 
00301     is specified by means of shape objects. If only the source shape is given
00302     the destination array is assumed to have the same shape, and standard mode
00303     is applied. If two shapes are given, the size of corresponding dimensions
00304     must be either equal (standard copy), or the source length must be 1 
00305     (expanding copy). The function uses accessors to access the data elements. 
00306     
00307     <b> Declarations:</b>
00308     
00309     <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
00310     Namespace: vigra
00311     
00312     pass arguments explicitly:
00313     \code
00314     namespace vigra {
00315         template <class SrcIterator, class SrcShape, class SrcAccessor,
00316                   class DestIterator, class DestAccessor>
00317         void
00318         copyMultiArray(SrcIterator s, 
00319                        SrcShape const & shape, SrcAccessor src,
00320                        DestIterator d, DestAccessor dest);
00321 
00322 
00323         template <class SrcIterator, class SrcShape, class SrcAccessor,
00324                   class DestIterator, class DestShape, class DestAccessor>
00325         void
00326         copyMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
00327                        DestIterator d, DestShape const & dshape, DestAccessor dest);
00328     }
00329     \endcode
00330     
00331     
00332     use argument objects in conjunction with \ref ArgumentObjectFactories :
00333     \code
00334     namespace vigra {
00335         template <class SrcIterator, class SrcShape, class SrcAccessor,
00336                   class DestIterator, class DestAccessor>
00337         void
00338         copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
00339                        pair<DestIterator, DestAccessor> const & dest);
00340                        
00341                        
00342         template <class SrcIterator, class SrcShape, class SrcAccessor,
00343                   class DestIterator, class DestShape, class DestAccessor>
00344         void
00345         copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
00346                        triple<DestIterator, DestShape, DestAccessor> const & dest);
00347     }
00348     \endcode
00349     
00350     <b> Usage - Standard Mode:</b>
00351     
00352     \code
00353     typedef vigra::MultiArray<3, int> Array;
00354     Array src(Array::size_type(100, 200, 50)),
00355           dest(Array::size_type(100, 200, 50));
00356     ...
00357     
00358     vigra::copyMultiArray(srcMultiArrayRange(src), destMultiArray(dest));
00359     \endcode
00360 
00361     <b> Usage - Expanding Mode:</b>
00362     
00363     The source array is only 2D (it has depth 1). Thus, the destination
00364     will contain 50 identical copies of this image. Note that the destination shape
00365     must be passed to the algorithm for the expansion to work, so we use 
00366     <tt>destMultiArrayRange()</tt> rather than <tt>destMultiArray()</tt>.
00367     
00368     \code
00369     typedef vigra::MultiArray<3, int> Array;
00370     Array src(Array::size_type(100, 200, 1)),
00371           dest(Array::size_type(100, 200, 50));
00372     ...
00373     
00374     vigra::copyMultiArray(srcMultiArrayRange(src), destMultiArrayRange(dest));
00375     \endcode
00376 
00377     <b> Required Interface:</b>
00378     
00379     \code
00380     MultiIterator src_begin, dest_begin;
00381     
00382     SrcAccessor src_accessor;
00383     DestAccessor dest_accessor;
00384 
00385     dest_accessor.set(src_accessor(src_begin), dest_begin);
00386 
00387     \endcode
00388     
00389 */
00390 doxygen_overloaded_function(template <...> void copyMultiArray)
00391 
00392 template <class SrcIterator, class SrcShape, class SrcAccessor,
00393           class DestIterator, class DestAccessor>
00394 inline void
00395 copyMultiArray(SrcIterator s, 
00396                SrcShape const & shape, SrcAccessor src,
00397                DestIterator d, DestAccessor dest)
00398 {    
00399     copyMultiArrayImpl(s, shape, src, d, shape, dest, MetaInt<SrcIterator::level>());
00400 }
00401 
00402 template <class SrcIterator, class SrcShape, class SrcAccessor,
00403           class DestIterator, class DestAccessor>
00404 inline void
00405 copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
00406                pair<DestIterator, DestAccessor> const & dest)
00407 {
00408     
00409     copyMultiArray(src.first, src.second, src.third, dest.first, dest.second);
00410 }
00411 
00412 template <class SrcIterator, class SrcShape, class SrcAccessor,
00413           class DestIterator, class DestShape, class DestAccessor>
00414 void
00415 copyMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
00416                DestIterator d, DestShape const & dshape, DestAccessor dest)
00417 {    
00418     vigra_precondition(sshape.size() == dshape.size(),
00419         "copyMultiArray(): dimensionality of source and destination array differ");
00420     for(unsigned int i=0; i<sshape.size(); ++i)
00421         vigra_precondition(sshape[i] == 1 || sshape[i] == dshape[i],
00422             "copyMultiArray(): mismatch between source and destination shapes:\n"
00423             "length of each source dimension must either be 1 or equal to the corresponding "
00424             "destination length.");
00425     copyMultiArrayImpl(s, sshape, src, d, dshape, dest, MetaInt<SrcIterator::level>());
00426 }
00427 
00428 template <class SrcIterator, class SrcShape, class SrcAccessor,
00429           class DestIterator, class DestShape, class DestAccessor>
00430 inline void
00431 copyMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
00432                triple<DestIterator, DestShape, DestAccessor> const & dest)
00433 {
00434     
00435     copyMultiArray(src.first, src.second, src.third, dest.first, dest.second, dest.third);
00436 }
00437 
00438 /********************************************************/
00439 /*                                                      */
00440 /*                 transformMultiArray                  */
00441 /*                                                      */
00442 /********************************************************/
00443 
00444 template <class SrcIterator, class SrcShape, class SrcAccessor,
00445           class DestIterator, class DestShape, class DestAccessor, 
00446           class Functor>
00447 void
00448 transformMultiArrayReduceImpl(SrcIterator s, SrcShape const &, SrcAccessor src,
00449                DestIterator d, DestShape const & dshape, DestAccessor dest, 
00450                SrcShape const & reduceShape,
00451                Functor const & ff, MetaInt<0>)
00452 {
00453     DestIterator dend = d + dshape[0];
00454     for(; d < dend; ++s.template dim<0>(), ++d)
00455     {
00456         Functor f = ff;
00457         inspectMultiArray(s, reduceShape, src, f);
00458         dest.set(f(), d);
00459     }
00460 }
00461     
00462 template <class SrcIterator, class SrcShape, class SrcAccessor,
00463           class DestIterator, class DestShape, class DestAccessor, 
00464           class Functor, int N>
00465 void
00466 transformMultiArrayReduceImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
00467                    DestIterator d, DestShape const & dshape, DestAccessor dest, 
00468                    SrcShape const & reduceShape,
00469                    Functor const & f, MetaInt<N>)
00470 {
00471     DestIterator dend = d + dshape[N];
00472     for(; d < dend; ++s.template dim<N>(), ++d)
00473     {
00474         transformMultiArrayReduceImpl(s, sshape, src, d.begin(), dshape, dest,
00475                                       reduceShape, f, MetaInt<N-1>());
00476     }
00477 }
00478 
00479 template <class SrcIterator, class SrcShape, class SrcAccessor,
00480           class DestIterator, class DestShape, class DestAccessor, 
00481           class Functor>
00482 void
00483 transformMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
00484                DestIterator d, DestShape const & dshape, DestAccessor dest, 
00485                Functor const & f, VigraTrueType)
00486 {
00487     // reduce mode
00488     SrcShape reduceShape = sshape;
00489     for(unsigned int i=0; i<dshape.size(); ++i)
00490     {
00491         vigra_precondition(dshape[i] == 1 || sshape[i] == dshape[i],
00492             "transformMultiArray(): mismatch between source and destination shapes:\n"
00493             "In 'reduce'-mode, the length of each destination dimension must either be 1\n"
00494             "or equal to the corresponding source length.");
00495         if(dshape[i] != 1)
00496             reduceShape[i] = 1;
00497     }
00498     transformMultiArrayReduceImpl(s, sshape, src, d, dshape, dest, reduceShape,
00499                                   f, MetaInt<SrcIterator::level>());
00500 }
00501     
00502 template <class SrcIterator, class SrcShape, class SrcAccessor,
00503           class DestIterator, class DestShape, class DestAccessor, 
00504           class Functor>
00505 void
00506 transformMultiArrayExpandImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
00507                DestIterator d, DestShape const & dshape, DestAccessor dest, 
00508                Functor const & f, MetaInt<0>)
00509 {
00510     if(sshape[0] == 1)
00511     {
00512         initLine(d, d + dshape[0], dest, f(src(s)));
00513     }
00514     else
00515     {
00516         transformLine(s, s + sshape[0], src, d, dest, f);
00517     }
00518 }
00519     
00520 template <class SrcIterator, class SrcShape, class SrcAccessor,
00521           class DestIterator, class DestShape, class DestAccessor, 
00522           class Functor, int N>
00523 void
00524 transformMultiArrayExpandImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
00525                    DestIterator d, DestShape const & dshape, DestAccessor dest, 
00526                    Functor const & f, MetaInt<N>)
00527 {
00528     DestIterator dend = d + dshape[N];
00529     if(sshape[N] == 1)
00530     {
00531         for(; d < dend; ++d)
00532         {
00533             transformMultiArrayExpandImpl(s.begin(), sshape, src, d.begin(), dshape, dest,
00534                                           f, MetaInt<N-1>());
00535         }
00536     }
00537     else
00538     {
00539         for(; d < dend; ++s, ++d)
00540         {
00541             transformMultiArrayExpandImpl(s.begin(), sshape, src, d.begin(), dshape, dest,
00542                                           f, MetaInt<N-1>());
00543         }
00544     }
00545 }
00546 
00547 template <class SrcIterator, class SrcShape, class SrcAccessor,
00548           class DestIterator, class DestShape, class DestAccessor, 
00549           class Functor>
00550 void
00551 transformMultiArrayImpl(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
00552                DestIterator d, DestShape const & dshape, DestAccessor dest, 
00553                Functor const & f, VigraFalseType)
00554 {
00555     // expand mode
00556     for(unsigned int i=0; i<sshape.size(); ++i)
00557         vigra_precondition(sshape[i] == 1 || sshape[i] == dshape[i],
00558             "transformMultiArray(): mismatch between source and destination shapes:\n"
00559             "In 'expand'-mode, the length of each source dimension must either be 1\n"
00560             "or equal to the corresponding destination length.");
00561     transformMultiArrayExpandImpl(s, sshape, src, d, dshape, dest, 
00562                                   f, MetaInt<SrcIterator::level>());
00563 }
00564     
00565 /** \brief Transform a multi-dimensional array with a unary function or functor.
00566 
00567     This function can be applied in three modes:
00568     
00569     <DL>
00570     <DT><b>Standard Mode:</b>
00571         <DD>If the source and destination arrays have the same size, 
00572         the transformation given by the functor is applied to every source
00573         element and the result written into the corresponding destination element.
00574         Unary functions, unary functors from the STL and the functors specifically 
00575         defined in \ref TransformFunctor can be used in standard mode.
00576         Creation of new functors is easiest by using \ref FunctorExpressions. 
00577     <DT><b>Expanding Mode:</b>
00578         <DD>If the source array has length 1 along some (or even all) dimensions,
00579         the source value at index 0 is used for all destination
00580         elements in those dimensions. In other words, the source index is not
00581         incremented along these dimensions, but the transformation functor
00582         is applied as usual. So, we can expand a small array (e.g. a single row of data,
00583         column length is 1), into a larger one (e.g. a 2D image with the same width): 
00584         the given values are simply reused as necessary (e.g. for every row of the 
00585         destination image). The same functors as in standard mode can be applied.
00586     <DT><b>Reducing Mode:</b>
00587         <DD>If the destination array has length 1 along some (or even all) dimensions,
00588         the source values in these dimensions are reduced to single values by means
00589         of a suitable functor (e.g. \ref vigra::ReduceFunctor), which supports two 
00590         function call operators: one
00591         with a single argument to collect the values, and without argument to 
00592         obtain the final (reduced) result. This behavior is a multi-dimensional
00593         generalization of the C++ standard function <tt>std::accumulate()</tt>.
00594     </DL>
00595         
00596     The arrays must be represented by
00597     iterators compatible with \ref vigra::MultiIterator, and the iteration range 
00598     is specified by means of shape objects. If only the source shape is given
00599     the destination array is assumed to have the same shape, and standard mode
00600     is applied. If two shapes are given, the size of corresponding dimensions
00601     must be either equal (standard copy), or the source length must be 1 
00602     (expand mode), or the destination length must be 1 (reduce mode). However,
00603     reduction and expansion cannot be executed at the same time, so the latter
00604     conditions are mutual exclusive, even if they apply to different dimensions.
00605     
00606     The function uses accessors to access the data elements. 
00607     
00608     <b> Declarations:</b>
00609 
00610     <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
00611     Namespace: vigra
00612     
00613     pass arguments explicitly:
00614     \code
00615     namespace vigra {
00616         template <class SrcIterator, class SrcShape, class SrcAccessor,
00617                   class DestIterator, class DestAccessor, 
00618                   class Functor>
00619         void
00620         transformMultiArray(SrcIterator s, SrcShape const & shape, SrcAccessor src,
00621                             DestIterator d, DestAccessor dest, Functor const & f);
00622 
00623 
00624         template <class SrcIterator, class SrcShape, class SrcAccessor,
00625                   class DestIterator, class DestShape, class DestAccessor, 
00626                   class Functor>
00627         void
00628         transformMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
00629                             DestIterator d, DestShape const & dshape, DestAccessor dest, 
00630                             Functor const & f);
00631     }
00632     \endcode
00633 
00634 
00635     use argument objects in conjunction with \ref ArgumentObjectFactories :
00636     \code
00637     namespace vigra {
00638         template <class SrcIterator, class SrcShape, class SrcAccessor,
00639                   class DestIterator, class DestAccessor, 
00640                   class Functor>
00641         void
00642         transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
00643                             pair<DestIterator, DestAccessor> const & dest, Functor const & f);
00644 
00645 
00646         template <class SrcIterator, class SrcShape, class SrcAccessor,
00647                   class DestIterator, class DestShape, class DestAccessor, 
00648                   class Functor>
00649         void
00650         transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
00651                             triple<DestIterator, DestShape, DestAccessor> const & dest, 
00652                             Functor const & f)
00653     }
00654     \endcode
00655 
00656     <b> Usage - Standard Mode:</b>
00657 
00658     Source and destination array have the same size.
00659     
00660     \code
00661     #include <cmath>         // for sqrt()
00662 
00663     typedef vigra::MultiArray<3, float> Array;
00664     Array src(Array::size_type(100, 200, 50)),
00665           dest(Array::size_type(100, 200, 50));
00666     ...
00667     
00668     vigra::transformMultiArray(srcMultiArrayRange(src),
00669                                destMultiArray(dest),
00670                                (float(*)(float))&std::sqrt );
00671 
00672     \endcode
00673 
00674     <b> Usage - Expand Mode:</b>
00675 
00676     The source array is only 2D (it has depth 1). Thus, the destination
00677     will contain 50 identical copies of the transformed source array. 
00678     Note that the destination shape must be passed to the algorithm for 
00679     the expansion to work, so we use <tt>destMultiArrayRange()</tt> 
00680     rather than <tt>destMultiArray()</tt>.
00681     
00682     \code
00683     #include <cmath>         // for sqrt()
00684 
00685     typedef vigra::MultiArray<3, float> Array;
00686     Array src(Array::size_type(100, 200, 1)),
00687           dest(Array::size_type(100, 200, 50));
00688     ...
00689     
00690     vigra::transformMultiArray(srcMultiArrayRange(src),
00691                                destMultiArrayRange(dest),
00692                                (float(*)(float))&std::sqrt );
00693 
00694     \endcode
00695 
00696     <b> Usage - Reduce Mode:</b>
00697 
00698     The destination array is only 1D (it's width and height are 1). 
00699     Thus, it will contain accumulated data for every slice of the source volume
00700     (or for every frame, if the source is interpreted as an image sequence).
00701     In the example, we use the functor \ref vigra::FindAverage to calculate
00702     the average gray value of every slice. Note that the destination shape
00703     must also be passed for the reduction to work, so we use 
00704     <tt>destMultiArrayRange()</tt> rather than <tt>destMultiArray()</tt>.
00705     
00706     \code
00707     typedef vigra::MultiArray<3, float> Array;
00708     Array src(Array::size_type(100, 200, 50)),
00709           dest(Array::size_type(1, 1, 50));
00710     ...
00711     
00712     vigra::transformMultiArray(srcMultiArrayRange(src),
00713                                destMultiArrayRange(dest),
00714                                vigra::FindAverage<float>() );
00715 
00716     \endcode
00717     
00718     Note that the functor must define the appropriate traits described below in order to be 
00719     recognized as a reduce functor. This is most easily achieved by deriving from 
00720     <tt>UnaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
00721 
00722     <b> Required Interface:</b>
00723 
00724     In standard and expand mode, the functor must be a model of UnaryFunction
00725     (i.e. support function call with one argument and a return value
00726     <tt>res = functor(arg)</tt>):
00727     
00728     \code
00729     MultiIterator src_begin, src_end, dest_begin;
00730     
00731     SrcAccessor src_accessor;
00732     DestAccessor dest_accessor;
00733     Functor functor;
00734 
00735     dest_accessor.set(functor(src_accessor(src_begin)), dest_begin);
00736     \endcode
00737     
00738     In reduce mode, it must be a model of UnaryAnalyser (i.e. support function call
00739     with one argument and no return value <tt>functor(arg)</tt>) and Initializer
00740     (i.e. support function call with no argument, but return value 
00741     <tt>res = functor()</tt>). Internally, such functors are recognized by the 
00742     meta functions <tt>FunctorTraits<FUNCTOR>::isUnaryAnalyser</tt> and
00743     <tt>FunctorTraits<FUNCTOR>::isInitializer</tt> which must both yield 
00744     <tt>VigraTrueType</tt>. Make sure that your functor correctly defines 
00745     <tt>FunctorTraits</tt> because otherwise reduce mode will not work. 
00746     This is most easily achieved by deriving the functor from 
00747     <tt>UnaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
00748     In addition, the functor must be copy constructible in order to start each reduction
00749     with a fresh functor.
00750     
00751     \code
00752     MultiIterator src_begin, src_end, dest_begin;
00753     
00754     SrcAccessor src_accessor;
00755     DestAccessor dest_accessor;
00756     
00757     FUNCTOR initial_functor, functor(initial_functor);
00758     assert(typeid(FunctorTraits<FUNCTOR>::isInitializer) == typeid(VigraTrueType));
00759     assert(typeid(FunctorTraits<FUNCTOR>::isUnaryAnalyser) == typeid(VigraTrueType));
00760     
00761     functor(src_accessor(src_begin));
00762     dest_accessor.set(functor(), dest_begin);
00763     \endcode
00764 
00765 */
00766 doxygen_overloaded_function(template <...> void transformMultiArray)
00767 
00768 template <class SrcIterator, class SrcShape, class SrcAccessor,
00769           class DestIterator, class DestAccessor, 
00770           class Functor>
00771 inline void
00772 transformMultiArray(SrcIterator s, SrcShape const & shape, SrcAccessor src,
00773                     DestIterator d, DestAccessor dest, Functor const & f)
00774 {    
00775     transformMultiArrayExpandImpl(s, shape, src, d, shape, dest, 
00776                                   f, MetaInt<SrcIterator::level>());
00777 }
00778 
00779 template <class SrcIterator, class SrcShape, class SrcAccessor,
00780           class DestIterator, class DestAccessor, 
00781           class Functor>
00782 inline void
00783 transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
00784                pair<DestIterator, DestAccessor> const & dest, Functor const & f)
00785 {
00786     
00787     transformMultiArray(src.first, src.second, src.third, 
00788                         dest.first, dest.second, f);
00789 }
00790 
00791 template <class SrcIterator, class SrcShape, class SrcAccessor,
00792           class DestIterator, class DestShape, class DestAccessor, 
00793           class Functor>
00794 void
00795 transformMultiArray(SrcIterator s, SrcShape const & sshape, SrcAccessor src,
00796                DestIterator d, DestShape const & dshape, DestAccessor dest, 
00797                Functor const & f)
00798 {    
00799     vigra_precondition(sshape.size() == dshape.size(),
00800         "transformMultiArray(): dimensionality of source and destination array differ");
00801     typedef FunctorTraits<Functor> FT;
00802     typedef typename 
00803         And<typename FT::isInitializer, typename FT::isUnaryAnalyser>::result
00804         isAnalyserInitializer;
00805     transformMultiArrayImpl(s, sshape, src, d, dshape, dest, 
00806                             f, isAnalyserInitializer());
00807 }
00808 
00809 template <class SrcIterator, class SrcShape, class SrcAccessor,
00810           class DestIterator, class DestShape, class DestAccessor, 
00811           class Functor>
00812 inline void
00813 transformMultiArray(triple<SrcIterator, SrcShape, SrcAccessor> const & src,
00814                triple<DestIterator, DestShape, DestAccessor> const & dest, 
00815                Functor const & f)
00816 {
00817     transformMultiArray(src.first, src.second, src.third, 
00818                         dest.first, dest.second, dest.third, f);
00819 }
00820 
00821 /********************************************************/
00822 /*                                                      */
00823 /*                combineTwoMultiArrays                 */
00824 /*                                                      */
00825 /********************************************************/
00826 
00827 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
00828           class SrcIterator2, class SrcAccessor2,
00829           class DestIterator, class DestShape, class DestAccessor, 
00830           class Functor>
00831 void
00832 combineTwoMultiArraysReduceImpl(
00833                SrcIterator1 s1, SrcShape const & , SrcAccessor1 src1,
00834                SrcIterator2 s2, SrcAccessor2 src2,
00835                DestIterator d,  DestShape const & dshape, DestAccessor dest, 
00836                SrcShape const & reduceShape,
00837                Functor const & ff, MetaInt<0>)
00838 {
00839     DestIterator dend = d + dshape[0];
00840     for(; d < dend; ++s1.template dim<0>(), ++s2.template dim<0>(), ++d)
00841     {
00842         Functor f = ff;
00843         inspectTwoMultiArrays(s1, reduceShape, src1, s2, src2, f);
00844         dest.set(f(), d);
00845     }
00846 }
00847     
00848 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
00849           class SrcIterator2, class SrcAccessor2,
00850           class DestIterator, class DestShape, class DestAccessor, 
00851           class Functor, int N>
00852 void
00853 combineTwoMultiArraysReduceImpl(
00854                SrcIterator1 s1, SrcShape const & sshape, SrcAccessor1 src1,
00855                SrcIterator2 s2, SrcAccessor2 src2,
00856                DestIterator d,  DestShape const & dshape, DestAccessor dest, 
00857                SrcShape const & reduceShape,
00858                Functor const & f, MetaInt<N>)
00859 {
00860     DestIterator dend = d + dshape[N];
00861     for(; d < dend; ++s1.template dim<N>(), ++s2.template dim<N>(), ++d)
00862     {
00863         combineTwoMultiArraysReduceImpl(s1, sshape, src1, s2, src2, 
00864                                         d.begin(), dshape, dest,
00865                                         reduceShape, f, MetaInt<N-1>());
00866     }
00867 }
00868 
00869 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
00870           class SrcIterator2, class SrcShape2, class SrcAccessor2,
00871           class DestIterator, class DestShape, class DestAccessor, 
00872           class Functor>
00873 void
00874 combineTwoMultiArraysImpl(
00875                SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
00876                SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
00877                DestIterator d, DestShape const & dshape, DestAccessor dest, 
00878                Functor const & f, VigraTrueType)
00879 {
00880     // reduce mode
00881     SrcShape1 reduceShape = sshape1;
00882     for(unsigned int i=0; i<dshape.size(); ++i)
00883     {
00884         vigra_precondition(sshape1[i] == sshape2[i] && 
00885                            (dshape[i] == 1 || sshape1[i] == dshape[i]),
00886             "combineTwoMultiArrays(): mismatch between source and destination shapes:\n"
00887             "In 'reduce'-mode, the two source shapes must be equal, and\n"
00888             "the length of each destination dimension must either be 1\n"
00889             "or equal to the corresponding source length.");
00890         if(dshape[i] != 1)
00891             reduceShape[i] = 1;
00892     }
00893     combineTwoMultiArraysReduceImpl(s1, sshape1, src1, s2, src2, 
00894                                     d, dshape, dest, reduceShape,
00895                                     f, MetaInt<SrcIterator1::level>());
00896 }
00897     
00898 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
00899           class SrcIterator2, class SrcShape2, class SrcAccessor2,
00900           class DestIterator, class DestShape, class DestAccessor, 
00901           class Functor>
00902 void
00903 combineTwoMultiArraysExpandImpl(
00904                SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
00905                SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
00906                DestIterator d, DestShape const & dshape, DestAccessor dest, 
00907                Functor const & f, MetaInt<0>)
00908 {
00909     DestIterator dend = d + dshape[0];
00910     if(sshape1[0] == 1 && sshape2[0] == 1)
00911     {
00912         initLine(d, dend, dest, f(src1(s1), src2(s2)));
00913     }
00914     else if(sshape1[0] == 1)
00915     {
00916         typename SrcAccessor1::value_type sv1 = src1(s1);
00917         for(; d < dend; ++d, ++s2)
00918             dest.set(f(sv1, src2(s2)), d);
00919     }
00920     else if(sshape2[0] == 1)
00921     {
00922         typename SrcAccessor2::value_type sv2 = src2(s2);
00923         for(; d < dend; ++d, ++s1)
00924             dest.set(f(src1(s1), sv2), d);
00925     }
00926     else
00927     {
00928         combineTwoLines(s1, s1 + sshape1[0], src1, s2, src2, d, dest, f);
00929     }
00930 }
00931     
00932 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
00933           class SrcIterator2, class SrcShape2, class SrcAccessor2,
00934           class DestIterator, class DestShape, class DestAccessor, 
00935           class Functor, int N>
00936 void
00937 combineTwoMultiArraysExpandImpl(
00938                SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
00939                SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
00940                DestIterator d, DestShape const & dshape, DestAccessor dest, 
00941                Functor const & f, MetaInt<N>)
00942 {
00943     DestIterator dend = d + dshape[N];
00944     int s1inc = sshape1[N] == 1
00945                     ? 0 
00946                     : 1;
00947     int s2inc = sshape2[N] == 1
00948                     ? 0 
00949                     : 1;
00950     for(; d < dend; ++d, s1 += s1inc, s2 += s2inc)
00951     {
00952         combineTwoMultiArraysExpandImpl(s1.begin(), sshape1, src1, 
00953                                         s2.begin(), sshape2, src2, 
00954                                         d.begin(), dshape, dest,
00955                                         f, MetaInt<N-1>());
00956     }
00957 }
00958 
00959 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
00960           class SrcIterator2, class SrcShape2, class SrcAccessor2,
00961           class DestIterator, class DestShape, class DestAccessor, 
00962           class Functor>
00963 void
00964 combineTwoMultiArraysImpl(
00965                SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
00966                SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
00967                DestIterator d, DestShape const & dshape, DestAccessor dest, 
00968                Functor const & f, VigraFalseType)
00969 {
00970     // expand mode
00971     for(unsigned int i=0; i<sshape1.size(); ++i)
00972         vigra_precondition((sshape1[i] == 1 || sshape1[i] == dshape[i]) &&
00973                            (sshape2[i] == 1 || sshape2[i] == dshape[i]),
00974             "combineTwoMultiArrays(): mismatch between source and destination shapes:\n"
00975             "In 'expand'-mode, the length of each source dimension must either be 1\n"
00976             "or equal to the corresponding destination length.");
00977     combineTwoMultiArraysExpandImpl(s1, sshape1, src1, s2, sshape2, src2, 
00978                                     d, dshape, dest, 
00979                                     f, MetaInt<SrcIterator1::level>());
00980 }
00981 
00982 /** \brief Combine two multi-dimensional arrays into one using a binary function or functor.
00983 
00984     This function can be applied in three modes:
00985     
00986     <DL>
00987     <DT><b>Standard Mode:</b>
00988         <DD>If the source and destination arrays have the same size, 
00989         the transformation given by the functor is applied to every pair of
00990         corresponding source elements and the result written into the corresponding 
00991         destination element.
00992         Binary functions, binary functors from the STL and the functors specifically 
00993         defined in \ref CombineFunctor can be used in standard mode.
00994         Creation of new functors is easiest by using \ref FunctorExpressions. 
00995     <DT><b>Expanding Mode:</b>
00996         <DD>If the source arrays have length 1 along some (or even all) dimensions,
00997         the source values at index 0 are used for all destination
00998         elements in those dimensions. In other words, the source index is not
00999         incremented along those dimensions, but the transformation functor
01000         is applied as usual. So, we can expand small arrays (e.g. a single row of data,
01001         column length is 1), into larger ones (e.g. a 2D image with the same width): 
01002         the given values are simply reused as necessary (e.g. for every row of the 
01003         destination image). It is not even necessary that the source array shapes
01004         are equal. For example, we can combine a small array with one that
01005         hase the same size as the destination array. 
01006         The same functors as in standard mode can be applied.
01007     <DT><b>Reducing Mode:</b>
01008         <DD>If the destination array has length 1 along some (or even all) dimensions,
01009         the source values in these dimensions are reduced to single values by means
01010         of a suitable functor which supports two function call operators: one
01011         with two arguments to collect the values, and one without argument to 
01012         obtain the final (reduced) result. This behavior is a multi-dimensional
01013         generalization of the C++ standard function <tt>std::accumulate()</tt>.
01014     </DL>
01015         
01016     The arrays must be represented by
01017     iterators compatible with \ref vigra::MultiIterator, and the iteration range 
01018     is specified by means of shape objects. If only a single source shape is given
01019     the destination array is assumed to have the same shape, and standard mode
01020     is applied. If three shapes are given, the size of corresponding dimensions
01021     must be either equal (standard copy), or the length of this dimension must
01022     be 1 in one or both source arrays
01023     (expand mode), or the destination length must be 1 (reduce mode). However,
01024     reduction and expansion cannot be executed at the same time, so the latter
01025     conditions are mutual exclusive, even if they apply to different dimensions.
01026     
01027     The function uses accessors to access the data elements. 
01028     
01029     <b> Declarations:</b>
01030     
01031     <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
01032     Namespace: vigra
01033     
01034     pass arguments explicitly:
01035     \code
01036     namespace vigra {
01037         template <class SrcIterator1, class SrcShape, class SrcAccessor1,
01038                   class SrcIterator2, class SrcAccessor2,
01039                   class DestIterator, class DestAccessor, 
01040                   class Functor>
01041         void combineTwoMultiArrays(
01042                        SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
01043                        SrcIterator2 s2, SrcAccessor2 src2,
01044                        DestIterator d, DestAccessor dest, Functor const & f);
01045 
01046 
01047         template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
01048                   class SrcIterator2, class SrcShape2, class SrcAccessor2,
01049                   class DestIterator, class DestShape, class DestAccessor, 
01050                   class Functor>
01051         void combineTwoMultiArrays(
01052                        SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
01053                        SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
01054                        DestIterator d, DestShape const & dshape, DestAccessor dest, 
01055                        Functor const & f);
01056             }
01057     \endcode
01058     
01059     
01060     use argument objects in conjunction with \ref ArgumentObjectFactories :
01061     \code
01062     namespace vigra {
01063         template <class SrcIterator1, class SrcShape, class SrcAccessor1,
01064                   class SrcIterator2, class SrcAccessor2,
01065                   class DestIterator, class DestAccessor, class Functor>
01066         void combineTwoMultiArrays(
01067                        triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
01068                        pair<SrcIterator2, SrcAccessor2> const & src2,
01069                        pair<DestIterator, DestAccessor> const & dest, Functor const & f);
01070 
01071 
01072         template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
01073                   class SrcIterator2, class SrcShape2, class SrcAccessor2,
01074                   class DestIterator, class DestShape, class DestAccessor, 
01075                   class Functor>
01076         void combineTwoMultiArrays(
01077                        triple<SrcIterator1, SrcShape1, SrcAccessor1> const & src1,
01078                        triple<SrcIterator2, SrcShape2, SrcAccessor2> const & src2,
01079                        triple<DestIterator, DestShape, DestAccessor> const & dest, 
01080                        Functor const & f);
01081     }
01082     \endcode
01083     
01084     <b> Usage - Standard Mode:</b>
01085     
01086     Source and destination arrays have the same size.
01087     
01088     \code
01089     #include <functional>     // for std::plus
01090 
01091     typedef vigra::MultiArray<3, int> Array;
01092     Array src1(Array::size_type(100, 200, 50)),
01093           src2(Array::size_type(100, 200, 50)),
01094           dest(Array::size_type(100, 200, 50));
01095     ...
01096     
01097     vigra::combineTwoMultiArrays(
01098                 srcMultiArrayRange(src1), 
01099                 srcMultiArray(src2), 
01100                 destMultiArray(dest),  
01101                 std::plus<int>());
01102     
01103     \endcode
01104     
01105     <b> Usage - Expand Mode:</b>
01106 
01107     One source array is only 2D (it has depth 1). This image will be added
01108     to every slice of the other source array, and the result
01109     if written into the corresponding destination slice. Note that the shapes
01110     of all arrays must be passed to the algorithm, so we use 
01111     <tt>srcMultiArrayRange()</tt> and <tt>destMultiArrayRange()</tt> 
01112     rather than <tt>srcMultiArray()</tt> and <tt>destMultiArray()</tt>.
01113     
01114     \code
01115     #include <functional>     // for std::plus
01116 
01117     typedef vigra::MultiArray<3, int> Array;
01118     Array src1(Array::size_type(100, 200, 1)),
01119           src2(Array::size_type(100, 200, 50)),
01120           dest(Array::size_type(100, 200, 50));
01121     ...
01122     
01123     vigra::combineTwoMultiArrays(
01124                 srcMultiArrayRange(src1), 
01125                 srcMultiArray(src2), 
01126                 destMultiArray(dest),  
01127                 std::plus<int>());
01128 
01129     \endcode
01130 
01131     <b> Usage - Reduce Mode:</b>
01132 
01133     The destination array is only 1D (it's width and height are 1). 
01134     Thus, it will contain accumulated data for every slice of the source volumes
01135     (or for every frame, if the sources are interpreted as image sequences).
01136     In the example, we use \ref vigra::ReduceFunctor together with a functor 
01137     expression (see \ref FunctorExpressions)
01138     to calculate the total absolute difference of the gray values in every pair of 
01139     source slices. Note that the shapes of all arrays must be passed 
01140     to the algorithm in order for the reduction to work, so we use 
01141     <tt>srcMultiArrayRange()</tt> and <tt>destMultiArrayRange()</tt> 
01142     rather than <tt>srcMultiArray()</tt> and <tt>destMultiArray()</tt>.
01143     
01144     \code
01145     #include <vigra/functorexpression.hxx>
01146     using namespace vigra::functor;
01147         
01148     typedef vigra::MultiArray<3, int> Array;
01149     Array src1(Array::size_type(100, 200, 50)),
01150           src2(Array::size_type(100, 200, 50)),
01151           dest(Array::size_type(1, 1, 50));
01152     ...
01153     
01154     vigra::combineTwoMultiArrays(
01155                 srcMultiArrayRange(src1), 
01156                 srcMultiArray(src2), 
01157                 destMultiArray(dest),  
01158                 reduceFunctor(Arg1() + abs(Arg2() - Arg3()), 0) );
01159                 // Arg1() is the sum accumulated so far, initialized with 0
01160 
01161     \endcode
01162 
01163     Note that the functor must define the appropriate traits described below in order to be 
01164     recognized as a reduce functor. This is most easily achieved by deriving from 
01165     <tt>BinaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
01166 
01167     <b> Required Interface:</b>
01168     
01169     In standard and expand mode, the functor must be a model of BinaryFunction
01170     (i.e. support function call with two arguments and a return value
01171     <tt>res = functor(arg1, arg2)</tt>):
01172     
01173     \code
01174     MultiIterator src1_begin, src2_begin, dest_begin;
01175     
01176     SrcAccessor1 src1_accessor;
01177     SrcAccessor2 src2_accessor;
01178     DestAccessor dest_accessor;
01179     
01180     Functor functor;
01181 
01182     dest_accessor.set(
01183           functor(src1_accessor(src1_begin), src2_accessor(src2_begin)), 
01184           dest_begin);
01185 
01186     \endcode
01187         
01188     In reduce mode, it must be a model of BinaryAnalyser (i.e. support function call
01189     with two arguments and no return value <tt>functor(arg1, arg2)</tt>) and Initializer
01190     (i.e. support function call with no argument, but return value 
01191     <tt>res = functor()</tt>). Internally, such functors are recognized by the 
01192     meta functions <tt>FunctorTraits<FUNCTOR>::isBinaryAnalyser</tt> and
01193     <tt>FunctorTraits<FUNCTOR>::isInitializer</tt> which must both yield 
01194     <tt>VigraTrueType</tt>. Make sure that your functor correctly defines 
01195     <tt>FunctorTraits</tt> because otherwise reduce mode will not work. 
01196     This is most easily achieved by deriving the functor from 
01197     <tt>BinaryReduceFunctorTag</tt> (see \ref vigra::FunctorTraits).
01198     In addition, the functor must be copy constructible in order to start each reduction
01199     with a fresh functor.
01200     
01201     \code
01202     MultiIterator src1_begin, src2_begin, dest_begin;
01203     
01204     SrcAccessor1 src1_accessor;
01205     SrcAccessor2 src2_accessor;
01206     DestAccessor dest_accessor;
01207     
01208     FUNCTOR initial_functor, functor(initial_functor);
01209     assert(typeid(FunctorTraits<FUNCTOR>::isInitializer) == typeid(VigraTrueType));
01210     assert(typeid(FunctorTraits<FUNCTOR>::isBinaryAnalyser) == typeid(VigraTrueType));
01211     
01212     functor(src1_accessor(src1_begin), src2_accessor(src2_begin));
01213     dest_accessor.set(functor(), dest_begin);
01214     \endcode
01215     
01216 */
01217 doxygen_overloaded_function(template <...> void combineTwoMultiArrays)
01218 
01219 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
01220           class SrcIterator2, class SrcAccessor2,
01221           class DestIterator, class DestAccessor, 
01222           class Functor>
01223 inline void
01224 combineTwoMultiArrays(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
01225                SrcIterator2 s2, SrcAccessor2 src2,
01226                DestIterator d, DestAccessor dest, Functor const & f)
01227 {    
01228     combineTwoMultiArraysExpandImpl(s1, shape, src1, s2, shape, src2, d, shape, dest, f, 
01229                                     MetaInt<SrcIterator1::level>());
01230 }
01231 
01232 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
01233           class SrcIterator2, class SrcAccessor2,
01234           class DestIterator, class DestAccessor, class Functor>
01235 inline void
01236 combineTwoMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
01237                pair<SrcIterator2, SrcAccessor2> const & src2,
01238                pair<DestIterator, DestAccessor> const & dest, Functor const & f)
01239 {
01240     
01241     combineTwoMultiArrays(
01242            src1.first, src1.second, src1.third, 
01243            src2.first, src2.second, dest.first, dest.second, f);
01244 }
01245 
01246 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
01247           class SrcIterator2, class SrcShape2, class SrcAccessor2,
01248           class DestIterator, class DestShape, class DestAccessor, 
01249           class Functor>
01250 void
01251 combineTwoMultiArrays(
01252                SrcIterator1 s1, SrcShape1 const & sshape1, SrcAccessor1 src1,
01253                SrcIterator2 s2, SrcShape2 const & sshape2, SrcAccessor2 src2,
01254                DestIterator d, DestShape const & dshape, DestAccessor dest, 
01255                Functor const & f)
01256 {    
01257     vigra_precondition(sshape1.size() == dshape.size() && sshape2.size() == dshape.size(),
01258         "combineTwoMultiArrays(): dimensionality of source and destination arrays differ");
01259     
01260     typedef FunctorTraits<Functor> FT;
01261     typedef typename 
01262         And<typename FT::isInitializer, typename FT::isBinaryAnalyser>::result
01263         isAnalyserInitializer;
01264     combineTwoMultiArraysImpl(s1, sshape1, src1, s2, sshape2, src2, d, dshape, dest, 
01265                               f, isAnalyserInitializer());
01266 }
01267 
01268 template <class SrcIterator1, class SrcShape1, class SrcAccessor1,
01269           class SrcIterator2, class SrcShape2, class SrcAccessor2,
01270           class DestIterator, class DestShape, class DestAccessor, 
01271           class Functor>
01272 inline void
01273 combineTwoMultiArrays(
01274                triple<SrcIterator1, SrcShape1, SrcAccessor1> const & src1,
01275                triple<SrcIterator2, SrcShape2, SrcAccessor2> const & src2,
01276                triple<DestIterator, DestShape, DestAccessor> const & dest, 
01277                Functor const & f)
01278 {
01279     combineTwoMultiArrays(src1.first, src1.second, src1.third, 
01280                           src2.first, src2.second, src2.third, 
01281                           dest.first, dest.second, dest.third, f);
01282 }
01283 
01284 /********************************************************/
01285 /*                                                      */
01286 /*               combineThreeMultiArrays                */
01287 /*                                                      */
01288 /********************************************************/
01289 
01290 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
01291           class SrcIterator2, class SrcAccessor2,
01292           class SrcIterator3, class SrcAccessor3,
01293           class DestIterator, class DestAccessor, 
01294           class Functor>
01295 inline void
01296 combineThreeMultiArraysImpl(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
01297                SrcIterator2 s2, SrcAccessor2 src2,
01298                SrcIterator3 s3, SrcAccessor3 src3,
01299                DestIterator d, DestAccessor dest, Functor const & f, MetaInt<0>)
01300 {
01301     combineThreeLines(s1, s1 + shape[0], src1, s2, src2, s3, src3, d, dest, f);
01302 }
01303     
01304 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
01305           class SrcIterator2, class SrcAccessor2,
01306           class SrcIterator3, class SrcAccessor3,
01307           class DestIterator, class DestAccessor, 
01308           class Functor, int N>
01309 void
01310 combineThreeMultiArraysImpl(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
01311                SrcIterator2 s2, SrcAccessor2 src2,
01312                SrcIterator3 s3, SrcAccessor3 src3,
01313                DestIterator d, DestAccessor dest, 
01314                    Functor const & f, MetaInt<N>)
01315 {
01316     SrcIterator1 s1end = s1 + shape[N];
01317     for(; s1 < s1end; ++s1, ++s2, ++s3, ++d)
01318     {
01319         combineThreeMultiArraysImpl(s1.begin(), shape, src1, 
01320                                   s2.begin(), src2, s3.begin(), src3, d.begin(), dest, 
01321                                   f, MetaInt<N-1>());
01322     }
01323 }
01324     
01325     
01326 /** \brief Combine three multi-dimensional arrays into one using a 
01327            ternary function or functor.
01328 
01329     Except for the fact that it operates on three input arrays, this function is
01330     identical to \ref combineTwoMultiArrays().
01331     
01332     <b> Declarations:</b>
01333     
01334     pass arguments explicitly:
01335     \code
01336     namespace vigra {
01337         template <class SrcIterator1, class SrcShape, class SrcAccessor1,
01338                   class SrcIterator2, class SrcAccessor2,
01339                   class SrcIterator3, class SrcAccessor3,
01340                   class DestIterator, class DestAccessor, 
01341                   class Functor>
01342         void
01343         combineThreeMultiArrays(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
01344                        SrcIterator2 s2, SrcAccessor2 src2,
01345                        SrcIterator3 s3, SrcAccessor3 src3,
01346                        DestIterator d, DestAccessor dest, Functor const & f);
01347                     }
01348     \endcode
01349     
01350     
01351     use argument objects in conjunction with \ref ArgumentObjectFactories :
01352     \code
01353     namespace vigra {
01354         template <class SrcIterator1, class SrcShape, class SrcAccessor1,
01355                   class SrcIterator2, class SrcAccessor2,
01356                   class SrcIterator3, class SrcAccessor3,
01357                   class DestIterator, class DestAccessor, 
01358                   class Functor>
01359         inline void
01360         combineThreeMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
01361                        pair<SrcIterator2, SrcAccessor2> const & src2,
01362                        pair<SrcIterator3, SrcAccessor3> const & src3,
01363                        pair<DestIterator, DestAccessor> const & dest, Functor const & f);
01364     }
01365     \endcode
01366     
01367     <b> Usage:</b>
01368     
01369     <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
01370     Namespace: vigra
01371     
01372     \code
01373     #include <functional>     // for plus
01374 
01375     typedef vigra::MultiArray<3, int> Array;
01376     Array src1(Array::size_type(100, 200, 50)),
01377           src2(Array::size_type(100, 200, 50)),
01378           src3(Array::size_type(100, 200, 50)),
01379           dest(Array::size_type(100, 200, 50));
01380     ...
01381     
01382     vigra::combineThreeMultiArrays(
01383                 srcMultiArrayRange(src1), 
01384                 srcMultiArray(src2), 
01385                 srcMultiArray(src3), 
01386                 destMultiArray(dest),  
01387                 SomeThreeArgumentFunctor());
01388     
01389     \endcode
01390 */
01391 doxygen_overloaded_function(template <...> void combineThreeMultiArrays)
01392 
01393 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
01394           class SrcIterator2, class SrcAccessor2,
01395           class SrcIterator3, class SrcAccessor3,
01396           class DestIterator, class DestAccessor, 
01397           class Functor>
01398 inline void
01399 combineThreeMultiArrays(SrcIterator1 s1, SrcShape const & shape, SrcAccessor1 src1,
01400                SrcIterator2 s2, SrcAccessor2 src2,
01401                SrcIterator3 s3, SrcAccessor3 src3,
01402                DestIterator d, DestAccessor dest, Functor const & f)
01403 {    
01404     combineThreeMultiArraysImpl(s1, shape, src1, s2, src2, s3, src3, d, dest, f, 
01405                               MetaInt<SrcIterator1::level>());
01406 }
01407 
01408 template <class SrcIterator1, class SrcShape, class SrcAccessor1,
01409           class SrcIterator2, class SrcAccessor2,
01410           class SrcIterator3, class SrcAccessor3,
01411           class DestIterator, class DestAccessor, 
01412           class Functor>
01413 inline void
01414 combineThreeMultiArrays(triple<SrcIterator1, SrcShape, SrcAccessor1> const & src1,
01415                pair<SrcIterator2, SrcAccessor2> const & src2,
01416                pair<SrcIterator3, SrcAccessor3> const & src3,
01417                pair<DestIterator, DestAccessor> const & dest, Functor const & f)
01418 {
01419     
01420     combineThreeMultiArrays(
01421            src1.first, src1.second, src1.third, 
01422            src2.first, src2.second, src3.first, src3.second, dest.first, dest.second, f);
01423 }
01424 
01425 /********************************************************/
01426 /*                                                      */
01427 /*                  inspectMultiArray                   */
01428 /*                                                      */
01429 /********************************************************/
01430 
01431 template <class Iterator, class Shape, class Accessor, class Functor>
01432 inline void
01433 inspectMultiArrayImpl(Iterator s, Shape const & shape, Accessor a,  Functor & f, MetaInt<0>)
01434 {
01435     inspectLine(s, s + shape[0], a, f);
01436 }
01437     
01438 template <class Iterator, class Shape, class Accessor, class Functor, int N>
01439 void
01440 inspectMultiArrayImpl(Iterator s, Shape const & shape, Accessor a,  Functor & f, MetaInt<N>)
01441 {
01442     Iterator send = s + shape[N];
01443     for(; s < send; ++s)
01444     {
01445         inspectMultiArrayImpl(s.begin(), shape, a, f, MetaInt<N-1>());
01446     }
01447 }
01448     
01449 /** \brief Call an analyzing functor at every element of a multi-dimensional array.
01450 
01451     This function can be used to collect statistics of the array etc.
01452     The results must be stored in the functor, which serves as a return
01453     value. The arrays must be represented by
01454     iterators compatible with \ref vigra::MultiIterator.
01455     The function uses an accessor to access the pixel data. Note that the iterator range 
01456     must be specified by a shape object, because otherwise we could not control
01457     the range simultaneously in all dimensions (this is a necessary consequence
01458     of the \ref vigra::MultiIterator design).
01459 
01460     <b> Declarations:</b>
01461 
01462     pass arguments explicitly:
01463     \code
01464     namespace vigra {
01465         template <class Iterator, class Shape, class Accessor, class Functor>
01466         void
01467         inspectMultiArray(Iterator s, Shape const & shape, Accessor a,  Functor & f);
01468     }
01469     \endcode
01470 
01471     use argument objects in conjunction with \ref ArgumentObjectFactories :
01472     \code
01473     namespace vigra {
01474         template <class Iterator, class Shape, class Accessor, class Functor>
01475         void
01476         inspectMultiArray(triple<Iterator, Shape, Accessor> const & s, Functor & f);
01477     }
01478     \endcode
01479 
01480     <b> Usage:</b>
01481 
01482     <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
01483     Namespace: vigra
01484 
01485     \code
01486     typedef vigra::MultiArray<3, int> Array;
01487     Array array(Array::size_type(100, 200, 50));
01488 
01489     // init functor
01490     vigra::FindMinMax<int> minmax;
01491 
01492     vigra::inspectMultiArray(srcMultiArrayRange(array), minmax);
01493 
01494     cout << "Min: " << minmax.min << " Max: " << minmax.max;
01495 
01496     \endcode
01497 
01498     <b> Required Interface:</b>
01499 
01500     \code
01501     MultiIterator src_begin;
01502 
01503     Accessor accessor;
01504     Functor functor;
01505 
01506     functor(accessor(src_begin)); 
01507     \endcode
01508 
01509 */
01510 doxygen_overloaded_function(template <...> void inspectMultiArray)
01511 
01512 template <class Iterator, class Shape, class Accessor, class Functor>
01513 inline void
01514 inspectMultiArray(Iterator s, Shape const & shape, Accessor a,  Functor & f)
01515 {
01516     inspectMultiArrayImpl(s, shape, a, f, MetaInt<Iterator::level>());
01517 }
01518     
01519 template <class Iterator, class Shape, class Accessor, class Functor>
01520 inline void
01521 inspectMultiArray(triple<Iterator, Shape, Accessor> const & s, Functor & f)
01522 {
01523     inspectMultiArray(s.first, s.second, s.third, f);
01524 }
01525     
01526 /********************************************************/
01527 /*                                                      */
01528 /*                  inspectTwoMultiArrays               */
01529 /*                                                      */
01530 /********************************************************/
01531 
01532 template <class Iterator1, class Shape, class Accessor1, 
01533           class Iterator2, class Accessor2, 
01534           class Functor>
01535 inline void
01536 inspectTwoMultiArraysImpl(Iterator1 s1, Shape const & shape, Accessor1 a1,
01537                           Iterator2 s2, Accessor2 a2,
01538                           Functor & f, MetaInt<0>)
01539 {
01540     inspectTwoLines(s1, s1 + shape[0], a1, s2, a2, f);
01541 }
01542     
01543 template <class Iterator1, class Shape, class Accessor1, 
01544           class Iterator2, class Accessor2, 
01545           class Functor, int N>
01546 void
01547 inspectTwoMultiArraysImpl(Iterator1 s1, Shape const & shape, Accessor1 a1,
01548                           Iterator2 s2, Accessor2 a2,
01549                           Functor & f, MetaInt<N>)
01550 {
01551     Iterator1 s1end = s1 + shape[N];
01552     for(; s1 < s1end; ++s1, ++s2)
01553     {
01554         inspectTwoMultiArraysImpl(s1.begin(), shape, a1, 
01555                                   s2.begin(), a2, f, MetaInt<N-1>());
01556     }
01557 }
01558     
01559 /** \brief Call an analyzing functor at all corresponding elements of 
01560            two multi-dimensional arrays.
01561 
01562     This function can be used to collect statistics of the array etc.
01563     The results must be stored in the functor, which serves as a return
01564     value. The arrays must be represented by
01565     iterators compatible with \ref vigra::MultiIterator.
01566     The function uses an accessor to access the pixel data. Note that the iterator range 
01567     must be specified by a shape object, because otherwise we could not control
01568     the range simultaneously in all dimensions (this is a necessary consequence
01569     of the \ref vigra::MultiIterator design).
01570 
01571     <b> Declarations:</b>
01572 
01573     pass arguments explicitly:
01574     \code
01575     namespace vigra {
01576         template <class Iterator1, class Shape, class Accessor1, 
01577                   class Iterator2, class Accessor2, 
01578                   class Functor>
01579         void
01580         inspectTwoMultiArrays(Iterator1 s1, Shape const & shape, Accessor1 a1,
01581                               Iterator2 s2, Accessor2 a2, Functor & f);
01582     }
01583     \endcode
01584 
01585     use argument objects in conjunction with \ref ArgumentObjectFactories :
01586     \code
01587     namespace vigra {
01588         template <class Iterator1, class Shape1, class Accessor1, 
01589                   class Iterator2, class Accessor2, 
01590                   class Functor>
01591         void
01592         inspectTwoMultiArrays(triple<Iterator1, Shape1, Accessor1> const & s1, 
01593                               pair<Iterator2, Accessor2> const & s2, Functor & f);
01594     }
01595     \endcode
01596 
01597     <b> Usage:</b>
01598 
01599     <b>\#include</b> <vigra/multi_pointoperators.hxx><br>
01600     Namespace: vigra
01601 
01602     \code
01603     typedef vigra::MultiArray<3, int> Array;
01604     Array array1(Array::size_type(100, 200, 50)),
01605           array2(Array::size_type(100, 200, 50));
01606 
01607     // init functor
01608     SomeStatisticsFunctor stats(..);
01609 
01610     vigra::inspectTwoMultiArrays(srcMultiArrayRange(array1), srcMultiArray(array2), stats);
01611 
01612     \endcode
01613 
01614     <b> Required Interface:</b>
01615 
01616     \code
01617     MultiIterator src1_begin, src2_begin;
01618 
01619     Accessor a1, a2;
01620     Functor functor;
01621 
01622     functor(a1(src1_begin), a2(src2_begin)); 
01623     \endcode
01624 
01625 */
01626 doxygen_overloaded_function(template <...> void inspectTwoMultiArrays)
01627 
01628 template <class Iterator1, class Shape, class Accessor1, 
01629           class Iterator2, class Accessor2, 
01630           class Functor>
01631 inline void
01632 inspectTwoMultiArrays(Iterator1 s1, Shape const & shape, Accessor1 a1,
01633                       Iterator2 s2, Accessor2 a2, Functor & f)
01634 {
01635     inspectTwoMultiArraysImpl(s1, shape, a1, s2, a2, f, MetaInt<Iterator1::level>());
01636 }
01637     
01638 template <class Iterator1, class Shape, class Accessor1, 
01639           class Iterator2, class Accessor2, 
01640           class Functor>
01641 inline 
01642 void
01643 inspectTwoMultiArrays(triple<Iterator1, Shape, Accessor1> const & s1, 
01644                       pair<Iterator2, Accessor2> const & s2, Functor & f)
01645 {
01646     inspectTwoMultiArrays(s1.first, s1.second, s1.third, 
01647                           s2.first, s2.second, f);
01648 }
01649     
01650 //@}
01651 
01652 }  //-- namespace vigra
01653 
01654 
01655 #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.8.0 (20 Sep 2011)