[ 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 #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) |
html generated using doxygen and Python
|