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