[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]
vigra/multi_pointoperators.hxx | ![]() |
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) |
html generated using doxygen and Python
|