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

multi_array.hxx
1/************************************************************************/
2/* */
3/* Copyright 2003-2008 by Gunnar Kedenburg and Ullrich Koethe */
4/* */
5/* This file is part of the VIGRA computer vision library. */
6/* The VIGRA Website is */
7/* http://hci.iwr.uni-heidelberg.de/vigra/ */
8/* Please direct questions, bug reports, and contributions to */
9/* ullrich.koethe@iwr.uni-heidelberg.de or */
10/* vigra@informatik.uni-hamburg.de */
11/* */
12/* Permission is hereby granted, free of charge, to any person */
13/* obtaining a copy of this software and associated documentation */
14/* files (the "Software"), to deal in the Software without */
15/* restriction, including without limitation the rights to use, */
16/* copy, modify, merge, publish, distribute, sublicense, and/or */
17/* sell copies of the Software, and to permit persons to whom the */
18/* Software is furnished to do so, subject to the following */
19/* conditions: */
20/* */
21/* The above copyright notice and this permission notice shall be */
22/* included in all copies or substantial portions of the */
23/* Software. */
24/* */
25/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32/* OTHER DEALINGS IN THE SOFTWARE. */
33/* */
34/************************************************************************/
35
36
37#ifndef VIGRA_MULTI_ARRAY_HXX
38#define VIGRA_MULTI_ARRAY_HXX
39
40#include <memory>
41#include <algorithm>
42#include "accessor.hxx"
43#include "tinyvector.hxx"
44#include "rgbvalue.hxx"
45#include "basicimage.hxx"
46#include "imageiterator.hxx"
47#include "numerictraits.hxx"
48#include "multi_iterator.hxx"
49#include "multi_pointoperators.hxx"
50#include "metaprogramming.hxx"
51#include "mathutil.hxx"
52#include "algorithm.hxx"
53
54// Bounds checking Macro used if VIGRA_CHECK_BOUNDS is defined.
55#ifdef VIGRA_CHECK_BOUNDS
56#define VIGRA_ASSERT_INSIDE(diff) \
57 vigra_precondition(this->isInside(diff), "Index out of bounds")
58#else
59#define VIGRA_ASSERT_INSIDE(diff)
60#endif
61
62namespace vigra
63{
64
65namespace detail
66{
67
68/********************************************************/
69/* */
70/* MaybeStrided */
71/* */
72/********************************************************/
73
74/* metatag implementing a test for marking MultiArrays that were
75 indexed at the zero'th dimension as strided, and all others as
76 unstrided.
77
78 <b>\#include</b> <vigra/multi_array.hxx> <br/>
79 Namespace: vigra::detail
80*/
81template <class StrideTag, unsigned int N>
82struct MaybeStrided
83{
84 typedef StrideTag type;
85};
86
87template <class StrideTag>
88struct MaybeStrided <StrideTag, 0>
89{
90 typedef StridedArrayTag type;
91};
92
93/********************************************************/
94/* */
95/* MultiIteratorChooser */
96/* */
97/********************************************************/
98
99/* metatag implementing a test (by pattern matching) for marking
100 MultiArrays that were indexed at the zero'th dimension as strided.
101
102 <b>\#include</b> <vigra/multi_array.hxx> <br/>
103 Namespace: vigra::detail
104*/
105template <class O>
106struct MultiIteratorChooser;
107
108/********************************************************/
109/* */
110/* MultiIteratorChooser <StridedArrayTag> */
111/* */
112/********************************************************/
113
114/* specialization of the MultiIteratorChooser for strided arrays.
115
116 <b>\#include</b> <vigra/multi_array.hxx> <br/>
117 Namespace: vigra::detail
118*/
119template <>
120struct MultiIteratorChooser <StridedArrayTag>
121{
122 template <unsigned int N, class T, class REFERENCE, class POINTER>
123 struct Traverser
124 {
125 typedef StridedMultiIterator <N, T, REFERENCE, POINTER> type;
126 };
127
128 template <unsigned int N, class T, class REFERENCE, class POINTER>
129 struct Iterator
130 {
131 typedef StridedScanOrderIterator <N, T, REFERENCE, POINTER> type;
132 };
133
134 template <class Iter, class View>
135 static Iter constructIterator(View * v)
136 {
137 return v->begin();
138 }
139};
140
141/********************************************************/
142/* */
143/* MultiIteratorChooser <UnstridedArrayTag> */
144/* */
145/********************************************************/
146
147/* specialization of the MultiIteratorChooser for unstrided arrays.
148
149 <b>\#include</b> <vigra/multi_array.hxx> <br/>
150 Namespace: vigra::detail
151*/
152template <>
153struct MultiIteratorChooser <UnstridedArrayTag>
154{
155 template <unsigned int N, class T, class REFERENCE, class POINTER>
156 struct Traverser
157 {
158 typedef MultiIterator <N, T, REFERENCE, POINTER> type;
159 };
160
161 template <unsigned int N, class T, class REFERENCE, class POINTER>
162 struct Iterator
163 {
164 typedef POINTER type;
165 };
166
167 template <class Iter, class View>
168 static Iter constructIterator(View * v)
169 {
170 return v->data();
171 }
172};
173
174/********************************************************/
175/* */
176/* helper functions */
177/* */
178/********************************************************/
179
180template <class DestIterator, class Shape, class T>
181inline void
182initMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<0>)
183{
184 DestIterator dend = d + shape[0];
185 for(; d < dend; ++d)
186 {
187 *d = init;
188 }
189}
190
191template <class DestIterator, class Shape, class T, int N>
192void
193initMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<N>)
194{
195 DestIterator dend = d + shape[N];
196 for(; d < dend; ++d)
197 {
198 initMultiArrayData(d.begin(), shape, init, MetaInt<N-1>());
199 }
200}
201
202// FIXME: the explicit overload for MultiIterator<1, UInt8, ... > works around a compiler crash in VisualStudio 2010
203#define VIGRA_COPY_MULTI_ARRAY_DATA(name, op) \
204template <class SrcIterator, class Shape, class DestIterator> \
205inline void \
206name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<0>) \
207{ \
208 for(MultiArrayIndex i=0; i < shape[0]; ++i, ++s, ++d) \
209 { \
210 *d op detail::RequiresExplicitCast<typename DestIterator::value_type>::cast(*s); \
211 } \
212} \
213 \
214template <class Ref, class Ptr, class Shape, class DestIterator> \
215inline void \
216name##MultiArrayData(MultiIterator<1, UInt8, Ref, Ptr> si, Shape const & shape, DestIterator d, MetaInt<0>) \
217{ \
218 Ptr s = &(*si); \
219 for(MultiArrayIndex i=0; i < shape[0]; ++i, ++s, ++d) \
220 { \
221 *d op detail::RequiresExplicitCast<typename DestIterator::value_type>::cast(*s); \
222 } \
223} \
224\
225template <class SrcIterator, class Shape, class DestIterator, int N> \
226void \
227name##MultiArrayData(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<N>) \
228{ \
229 for(MultiArrayIndex i=0; i < shape[N]; ++i, ++s, ++d) \
230 { \
231 name##MultiArrayData(s.begin(), shape, d.begin(), MetaInt<N-1>()); \
232 } \
233} \
234\
235template <class DestIterator, class Shape, class T> \
236inline void \
237name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<0>) \
238{ \
239 for(MultiArrayIndex i=0; i < shape[0]; ++i, ++d) \
240 { \
241 *d op detail::RequiresExplicitCast<typename DestIterator::value_type>::cast(init); \
242 } \
243} \
244 \
245template <class DestIterator, class Shape, class T, int N> \
246void \
247name##ScalarMultiArrayData(DestIterator d, Shape const & shape, T const & init, MetaInt<N>) \
248{ \
249 for(MultiArrayIndex i=0; i < shape[N]; ++i, ++d) \
250 { \
251 name##ScalarMultiArrayData(d.begin(), shape, init, MetaInt<N-1>()); \
252 } \
253}
254
255VIGRA_COPY_MULTI_ARRAY_DATA(copy, =)
256VIGRA_COPY_MULTI_ARRAY_DATA(copyAdd, +=)
257VIGRA_COPY_MULTI_ARRAY_DATA(copySub, -=)
258VIGRA_COPY_MULTI_ARRAY_DATA(copyMul, *=)
259VIGRA_COPY_MULTI_ARRAY_DATA(copyDiv, /=)
260
261#undef VIGRA_COPY_MULTI_ARRAY_DATA
262
263template <class SrcIterator, class Shape, class T, class ALLOC>
264inline void
265uninitializedCopyMultiArrayData(SrcIterator s, Shape const & shape, T * & d, ALLOC & a, MetaInt<0>)
266{
267 SrcIterator send = s + shape[0];
268 for(; s < send; ++s, ++d)
269 {
270 std::allocator_traits<ALLOC>::construct(a, d, static_cast<T const &>(*s));
271 }
272}
273
274// FIXME: this overload works around a compiler crash in VisualStudio 2010
275template <class Ref, class Ptr, class Shape, class T, class ALLOC>
276inline void
277uninitializedCopyMultiArrayData(MultiIterator<1, UInt8, Ref, Ptr> si, Shape const & shape, T * & d, ALLOC & a, MetaInt<0>)
278{
279 Ptr s = &(*si), send = s + shape[0];
280 for(; s < send; ++s, ++d)
281 {
282 std::allocator_traits<ALLOC>::construct(a, d, static_cast<T const &>(*s));
283 }
284}
285
286template <class SrcIterator, class Shape, class T, class ALLOC, int N>
287void
288uninitializedCopyMultiArrayData(SrcIterator s, Shape const & shape, T * & d, ALLOC & a, MetaInt<N>)
289{
290 SrcIterator send = s + shape[N];
291 for(; s < send; ++s)
292 {
293 uninitializedCopyMultiArrayData(s.begin(), shape, d, a, MetaInt<N-1>());
294 }
295}
296
297template <class SrcIterator, class Shape, class T, class Functor>
298inline void
299reduceOverMultiArray(SrcIterator s, Shape const & shape, T & result, Functor const & f, MetaInt<0>)
300{
301 SrcIterator send = s + shape[0];
302 for(; s < send; ++s)
303 {
304 f(result, *s);
305 }
306}
307
308template <class SrcIterator, class Shape, class T, class Functor, int N>
309void
310reduceOverMultiArray(SrcIterator s, Shape const & shape, T & result, Functor const & f, MetaInt<N>)
311{
312 SrcIterator send = s + shape[N];
313 for(; s < send; ++s)
314 {
315 reduceOverMultiArray(s.begin(), shape, result, f, MetaInt<N-1>());
316 }
317}
318
319struct MaxNormReduceFunctor
320{
321 template <class T, class U>
322 void operator()(T & result, U const & u) const
323 {
324 T v = norm(u);
325 if(result < v)
326 result = v;
327 }
328};
329
330struct L1NormReduceFunctor
331{
332 template <class T, class U>
333 void operator()(T & result, U const & u) const
334 {
335 result += norm(u);
336 }
337};
338
339struct SquaredL2NormReduceFunctor
340{
341 template <class T, class U>
342 void operator()(T & result, U const & u) const
343 {
344 result += squaredNorm(u);
345 }
346};
347
348template <class T>
349struct WeightedL2NormReduceFunctor
350{
351 T scale;
352
353 WeightedL2NormReduceFunctor(T s)
354 : scale(s)
355 {}
356
357 template <class U>
358 void operator()(T & result, U const & u) const
359 {
360 result += squaredNorm(u * scale);
361 }
362};
363
364struct SumReduceFunctor
365{
366 template <class T, class U>
367 void operator()(T & result, U const & u) const
368 {
369 result += u;
370 }
371};
372
373struct ProdReduceFunctor
374{
375 template <class T, class U>
376 void operator()(T & result, U const & u) const
377 {
378 result *= u;
379 }
380};
381
382struct MinmaxReduceFunctor
383{
384 template <class T, class U>
385 void operator()(T & result, U const & u) const
386 {
387 if(u < result.first)
388 result.first = u;
389 if(result.second < u)
390 result.second = u;
391 }
392};
393
394struct MeanVarianceReduceFunctor
395{
396 template <class T, class U>
397 void operator()(T & result, U const & u) const
398 {
399 ++result.first;
400 typename T::second_type t1 = u - result.second;
401 typename T::second_type t2 = t1 / result.first;
402 result.second += t2;
403 result.third += (result.first-1.0)*t1*t2;
404 }
405};
406
407struct AllTrueReduceFunctor
408{
409 template <class T, class U>
410 void operator()(T & result, U const & u) const
411 {
412 result = result && (u != NumericTraits<U>::zero());
413 }
414};
415
416struct AnyTrueReduceFunctor
417{
418 template <class T, class U>
419 void operator()(T & result, U const & u) const
420 {
421 result = result || (u != NumericTraits<U>::zero());
422 }
423};
424
425template <class SrcIterator, class Shape, class DestIterator>
426inline bool
427equalityOfMultiArrays(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<0>)
428{
429 SrcIterator send = s + shape[0];
430 for(; s < send; ++s, ++d)
431 {
432 if(!(*s == *d))
433 return false;
434 }
435 return true;
436}
437
438template <class SrcIterator, class Shape, class DestIterator, int N>
439bool
440equalityOfMultiArrays(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<N>)
441{
442 SrcIterator send = s + shape[N];
443 for(; s < send; ++s, ++d)
444 {
445 if(!equalityOfMultiArrays(s.begin(), shape, d.begin(), MetaInt<N-1>()))
446 return false;
447 }
448 return true;
449}
450
451
452template <class SrcIterator, class Shape, class DestIterator>
453inline void
454swapDataImpl(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<0>)
455{
456 SrcIterator send = s + shape[0];
457 for(; s < send; ++s, ++d)
458 std::swap(*s, *d);
459}
460
461template <class SrcIterator, class Shape, class DestIterator, int N>
462void
463swapDataImpl(SrcIterator s, Shape const & shape, DestIterator d, MetaInt<N>)
464{
465 SrcIterator send = s + shape[N];
466 for(; s < send; ++s, ++d)
467 swapDataImpl(s.begin(), shape, d.begin(), MetaInt<N-1>());
468}
469
470} // namespace detail
471
472/********************************************************/
473/* */
474/* namespace multi_math forward declarations */
475/* */
476/********************************************************/
477
478/** \brief Arithmetic and algebraic functions for multi-dimensional arrays.
479
480 \defgroup MultiMathModule vigra::multi_math
481
482 Namespace <tt>vigra::multi_math</tt> holds VIGRA's support for efficient arithmetic and algebraic functions on multi-dimensional arrays (that is, \ref MultiArrayView and its subclasses). All <tt>multi_math</tt> functions operate element-wise. If you need matrix multiplication, use \ref LinearAlgebraModule instead.
483
484 In order to avoid overload ambiguities, multi-array arithmetic must be explicitly activated by
485 \code
486 using namespace vigra::multi_math;
487 \endcode
488 (this should not be done globally, but only in the scope where the functionality is actually used).
489
490 You can then use the standard operators in the expected way:
491 \code
492 MultiArray<2, float> i(Shape2(100, 100)), j(Shape2(100, 100));
493
494 MultiArray<2, float> h = i + 4.0 * j;
495 h += (i.transpose() - j) / 2.0;
496 \endcode
497 etc. (supported operators are <tt>+ - * / ! ~ % && || == != &lt; &lt;= &gt; &gt;= &lt;&lt; &gt;&gt; & | ^ = += -= *= /=</tt>, with both scalar and array arguments).
498
499 Algebraic functions are available as well:
500 \code
501 h = exp(-(sq(i) + sq(j)));
502 h *= atan2(-i, j);
503 \endcode
504 The following functions are implemented: <tt>abs, erf, even, odd, sign, signi, round, roundi, sqrt, sqrti, sq,
505 norm, squaredNorm, gamma, loggamma, exp, log, log10, sin, sin_pi, cos, cos_pi, asin, acos, tan, atan,
506 floor, ceil, conj, real, imag, arg, atan2, pow, fmod, min, max</tt>,
507 provided the array's element type supports the respective function.
508
509 Supported element types currently include the built-in numeric types, \ref TinyVector, \ref RGBValue,
510 <tt>std::complex</tt>, and \ref FFTWComplex.
511
512 In addition, <tt>multi_math</tt> supports a number of functions that reduce arrays to scalars:
513 \code
514 double s = sum<double>(i); // compute the sum of the elements, using 'double' as accumulator type
515 double p = product<double>(abs(i)); // compute the product of the elements' absolute values
516
517 bool a = any(i < 0.0); // check if any element of i is negative
518 bool b = all(i > 0.0); // check if all elements of i are positive
519 \endcode
520
521 Expressions are expanded so that no temporary arrays have to be created. To optimize cache locality,
522 loops are executed in the stride ordering of the left-hand-side array.
523
524 <b>\#include</b> <vigra/multi_math.hxx>
525
526 Namespace: vigra::multi_math
527*/
528namespace multi_math {
529
530template <class T>
531struct MultiMathOperand;
532
533namespace math_detail {
534
535template <unsigned int N, class T, class C, class E>
536void assign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
537
538template <unsigned int N, class T, class C, class E>
539void plusAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
540
541template <unsigned int N, class T, class C, class E>
542void minusAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
543
544template <unsigned int N, class T, class C, class E>
545void multiplyAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
546
547template <unsigned int N, class T, class C, class E>
548void divideAssign(MultiArrayView<N, T, C>, MultiMathOperand<E> const &);
549
550template <unsigned int N, class T, class A, class E>
551void assignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &);
552
553template <unsigned int N, class T, class A, class E>
554void plusAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &);
555
556template <unsigned int N, class T, class A, class E>
557void minusAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &);
558
559template <unsigned int N, class T, class A, class E>
560void multiplyAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &);
561
562template <unsigned int N, class T, class A, class E>
563void divideAssignOrResize(MultiArray<N, T, A> &, MultiMathOperand<E> const &);
564
565} // namespace math_detail
566
567} // namespace multi_math
568
569template <class T> class FindSum;
570
571struct UnsuitableTypeForExpandElements {};
572
573template <class T>
574struct ExpandElementResult
575{
576 typedef UnsuitableTypeForExpandElements type;
577};
578
579template <class T>
580struct ExpandElementResult<std::complex<T> >
581{
582 typedef T type;
583 enum { size = 2 };
584};
585
586template <class T>
587class FFTWComplex;
588
589template <class T>
590struct ExpandElementResult<FFTWComplex<T> >
591{
592 typedef T type;
593 enum { size = 2 };
594};
595
596template <class T, int SIZE>
597struct ExpandElementResult<TinyVector<T, SIZE> >
598{
599 typedef T type;
600 enum { size = SIZE };
601};
602
603template <class T, unsigned int R, unsigned int G, unsigned int B>
604struct ExpandElementResult<RGBValue<T, R, G, B> >
605{
606 typedef T type;
607 enum { size = 3 };
608};
609
610#define VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(TYPE) \
611template <> \
612struct ExpandElementResult<TYPE> \
613{ \
614 typedef TYPE type; \
615 enum { size = 1 }; \
616}; \
617
618VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(bool)
619VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(char)
620VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed char)
621VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed short)
622VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed int)
623VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed long)
624VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(signed long long)
625VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned char)
626VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned short)
627VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned int)
628VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned long)
629VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(unsigned long long)
630VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(float)
631VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(double)
632VIGRA_DEFINE_EXPAND_ELEMENT_RESULT(long double)
633
634#undef VIGRA_DEFINE_EXPAND_ELEMENT_RESULT
635
636
637/********************************************************/
638/* */
639/* NormTraits */
640/* */
641/********************************************************/
642
643template <unsigned int N, class T, class C>
644struct NormTraits<MultiArrayView<N, T, C> >
645{
646 typedef MultiArrayView<N, T, C> Type;
647 typedef typename NormTraits<T>::SquaredNormType SquaredNormType;
648 typedef typename SquareRootTraits<SquaredNormType>::SquareRootResult NormType;
649};
650
651template <unsigned int N, class T, class A>
652struct NormTraits<MultiArray<N, T, A> >
653: public NormTraits<typename MultiArray<N, T, A>::view_type>
654{
655 typedef NormTraits<typename MultiArray<N, T, A>::view_type> BaseType;
656 typedef MultiArray<N, T, A> Type;
657 typedef typename BaseType::SquaredNormType SquaredNormType;
658 typedef typename BaseType::NormType NormType;
659};
660
661/********************************************************/
662/* */
663/* MultiArrayView */
664/* */
665/********************************************************/
666
667/** \brief Base class for, and view to, \ref vigra::MultiArray.
668
669This class implements the interface of both MultiArray and
670MultiArrayView. By default, MultiArrayViews are tagged as
671strided (using <tt>StridedArrayTag</tt> as third template parameter).
672This means that the array elements need not be consecutive in memory,
673making the view flexible to represent all kinds of subarrays and slices.
674In certain cases (which have become rare due to improvements of
675optimizer and processor technology), an array may be tagged with
676<tt>UnstridedArrayTag</tt> which indicates that the first array dimension
677is guaranteed to be unstrided, i.e. has consecutive elements in memory.
678
679In addition to the member functions described here, <tt>MultiArrayView</tt>
680and its subclasses support arithmetic and algebraic functions via the
681module \ref MultiMathModule.
682
683If you want to apply an algorithm requiring an image to a
684<tt>MultiArrayView</tt> of appropriate (2-dimensional) shape, you can
685create a \ref vigra::BasicImageView that acts as a wrapper with the
686necessary interface -- see \ref MultiArrayToImage.
687
688The template parameter are as follows
689\code
690 N: the array dimension
691
692 T: the type of the array elements
693
694 C: a tag determining if the array's inner dimension is strided
695 (the tag can be used to specialize algorithms for different memory
696 layouts, see \ref MultiArrayTags for details). Users normally need
697 not care about this parameter.
698\endcode
699
700<b>\#include</b> <vigra/multi_array.hxx> <br/>
701Namespace: vigra
702*/
703template <unsigned int N, class T, class StrideTag>
705{
706public:
707
708 /** the array's actual dimensionality.
709 This ensures that MultiArrayView can also be used for
710 scalars (that is, when <tt>N == 0</tt>). Calculated as:<br>
711 \code
712 actual_dimension = (N==0) ? 1 : N
713 \endcode
714 */
715 enum ActualDimension { actual_dimension = (N==0) ? 1 : N };
716
717 /** the array's value type
718 */
719 typedef T value_type;
720
721 /** reference type (result of operator[])
722 */
724
725 /** const reference type (result of operator[] const)
726 */
728
729 /** pointer type
730 */
732
733 /** const pointer type
734 */
735 typedef const value_type *const_pointer;
736
737 /** difference type (used for multi-dimensional offsets and indices)
738 */
740
741 /** key type (argument of index operator array[i] -- same as difference_type)
742 */
744
745 /** size type
746 */
748
749 /** difference and index type for a single dimension
750 */
752
753 /** scan-order iterator (StridedScanOrderIterator) type
754 */
756
757 /** const scan-order iterator (StridedScanOrderIterator) type
758 */
760
761 /** traverser (MultiIterator) type
762 */
763 typedef typename vigra::detail::MultiIteratorChooser <
764 StrideTag>::template Traverser <actual_dimension, T, T &, T *>::type traverser;
765
766 /** const traverser (MultiIterator) type
767 */
768 typedef typename vigra::detail::MultiIteratorChooser <
769 StrideTag>::template Traverser <actual_dimension, T, T const &, T const *>::type const_traverser;
770
771 /** the view type associated with this array.
772 */
774
775 /** the matrix type associated with this array.
776 */
777 typedef MultiArray <N, T> matrix_type;
778
779 bool checkInnerStride(UnstridedArrayTag) const
780 {
781 return m_stride[0] <= 1;
782 }
783
784 bool checkInnerStride(StridedArrayTag) const
786 return true;
788
789 protected:
790
791 typedef typename difference_type::value_type diff_zero_t;
792
793 /** the shape of the image pointed to is stored here.
794 */
796
797 /** the strides (offset of a sample to the next) for every dimension
798 are stored here.
799 */
801
802 /** pointer to the image.
803 */
805
806 template <class CN>
807 void assignImpl(const MultiArrayView <N, T, CN>& rhs);
808
809 template <class U, class CN>
810 void copyImpl(const MultiArrayView <N, U, CN>& rhs);
811
812 template <class U, class CN>
813 void swapDataImpl(MultiArrayView <N, U, CN> rhs);
814
815 template <class CN>
816 bool arraysOverlap(const MultiArrayView <N, T, CN>& rhs) const;
817
818 template <class U, class CN>
819 bool arraysOverlap(const MultiArrayView <N, U, CN>&) const
820 {
821 return false;
822 }
823
824public:
825
826 /** default constructor: create an invalid view,
827 * i.e. hasData() returns false and size() is zero.
828 */
830 : m_shape (diff_zero_t(0)), m_stride (diff_zero_t(0)), m_ptr (0)
831 {}
832
833 /** construct from another array view.
834 Throws a precondition error if this array has UnstridedArrayTag, but the
835 innermost dimension of \a other is strided.
836 */
837 template <class Stride>
839 : m_shape (other.shape()),
840 m_stride (other.stride()),
841 m_ptr (other.data())
842 {
843 vigra_precondition(other.checkInnerStride(StrideTag()),
844 "MultiArrayView<..., UnstridedArrayTag>(MultiArrayView const &): cannot create unstrided view from strided array.");
845 }
846
847 /** construct from shape and pointer
848 */
850 : m_shape (shape),
851 m_stride (detail::defaultStride<actual_dimension>(shape)),
852 m_ptr (const_cast<pointer>(ptr))
853 {}
854
855 /** Construct from shape, strides (offset of a sample to the
856 next) for every dimension, and pointer. (Note that
857 strides are not given in bytes, but in offset steps of the
858 respective pointer type.)
859 */
861 const difference_type &stride,
862 const_pointer ptr)
863 : m_shape (shape),
865 m_ptr (const_cast<pointer>(ptr))
866 {
867 vigra_precondition(checkInnerStride(StrideTag()),
868 "MultiArrayView<..., UnstridedArrayTag>::MultiArrayView(): First dimension of given array is not unstrided.");
869 }
870
871 /** Construct from an old-style BasicImage.
872 */
873 template <class ALLOC>
875 : m_shape (Shape2(image.width(), image.height())),
876 m_stride (detail::defaultStride<actual_dimension>(m_shape)),
877 m_ptr (const_cast<pointer>(image.data()))
878 {}
879
880 /** Conversion to a strided view.
881 */
886
887 /** Reset this <tt>MultiArrayView</tt> to an invalid state (as after default construction).
888 Can e.g. be used prior to assignment to make a view object point to new data.
889 */
890 void reset() {
891 m_shape = diff_zero_t(0);
892 m_stride = diff_zero_t(0);
893 m_ptr = 0;
894 }
895
896
897 /** Assignment. There are 3 cases:
898
899 <ul>
900 <li> When this <tt>MultiArrayView</tt> does not point to valid data
901 (e.g. after default construction), it becomes a new view of \a rhs.
902 <li> Otherwise, when the shapes of the two arrays match, the contents
903 (i.e. the elements) of \a rhs are copied.
904 <li> Otherwise, a <tt>PreconditionViolation</tt> exception is thrown.
905 </ul>
906 */
907 MultiArrayView(MultiArrayView const & rhs) = default;
908
909 MultiArrayView & operator=(MultiArrayView const & rhs)
910 {
911 if(this != &rhs)
912 assignImpl(rhs);
913 return *this;
914 }
915
916 template<class Stride2>
917 MultiArrayView & operator=(MultiArrayView<N, T, Stride2> const & rhs)
918 {
919 assignImpl(rhs);
920 return *this;
921 }
922
923 /** Assignment of a differently typed MultiArrayView. It copies the elements
924 of\a rhs or fails with <tt>PreconditionViolation</tt> exception when
925 the shapes do not match.
926 */
927 template<class U, class C1>
929 {
930 vigra_precondition(this->shape() == rhs.shape(),
931 "MultiArrayView::operator=(): shape mismatch.");
932 this->copyImpl(rhs);
933 return *this;
934 }
935
936 /** Assignment of a scalar. Equivalent to MultiArrayView::init(v).
937 */
939 {
940 return init(v);
941 }
942
943 /** Add-assignment of a compatible MultiArrayView. Fails with
944 <tt>PreconditionViolation</tt> exception when the shapes do not match.
945 */
946 template<class U, class C1>
948
949 /** Subtract-assignment of a compatible MultiArrayView. Fails with
950 <tt>PreconditionViolation</tt> exception when the shapes do not match.
951 */
952 template<class U, class C1>
954
955 /** Multiply-assignment of a compatible MultiArrayView. Fails with
956 <tt>PreconditionViolation</tt> exception when the shapes do not match.
957 */
958 template<class U, class C1>
960
961 /** Divide-assignment of a compatible MultiArrayView. Fails with
962 <tt>PreconditionViolation</tt> exception when the shapes do not match.
963 */
964 template<class U, class C1>
966
967 /** Add-assignment of a scalar.
968 */
969 MultiArrayView & operator+=(T const & rhs)
970 {
971 detail::copyAddScalarMultiArrayData(traverser_begin(), shape(), rhs, MetaInt<actual_dimension-1>());
972 return *this;
973 }
974
975 /** Subtract-assignment of a scalar.
976 */
977 MultiArrayView & operator-=(T const & rhs)
978 {
979 detail::copySubScalarMultiArrayData(traverser_begin(), shape(), rhs, MetaInt<actual_dimension-1>());
980 return *this;
981 }
982
983 /** Multiply-assignment of a scalar.
984 */
985 MultiArrayView & operator*=(T const & rhs)
986 {
987 detail::copyMulScalarMultiArrayData(traverser_begin(), shape(), rhs, MetaInt<actual_dimension-1>());
988 return *this;
989 }
990
991 /** Divide-assignment of a scalar.
992 */
993 MultiArrayView & operator/=(T const & rhs)
994 {
995 detail::copyDivScalarMultiArrayData(traverser_begin(), shape(), rhs, MetaInt<actual_dimension-1>());
996 return *this;
997 }
998
999 /** Assignment of an array expression. Fails with
1000 <tt>PreconditionViolation</tt> exception when the shapes do not match.
1001 */
1002 template<class Expression>
1003 MultiArrayView & operator=(multi_math::MultiMathOperand<Expression> const & rhs)
1004 {
1005 multi_math::math_detail::assign(*this, rhs);
1006 return *this;
1007 }
1008
1009 /** Add-assignment of an array expression. Fails with
1010 <tt>PreconditionViolation</tt> exception when the shapes do not match.
1011 */
1012 template<class Expression>
1013 MultiArrayView & operator+=(multi_math::MultiMathOperand<Expression> const & rhs)
1014 {
1015 multi_math::math_detail::plusAssign(*this, rhs);
1016 return *this;
1017 }
1018
1019 /** Subtract-assignment of an array expression. Fails with
1020 <tt>PreconditionViolation</tt> exception when the shapes do not match.
1021 */
1022 template<class Expression>
1023 MultiArrayView & operator-=(multi_math::MultiMathOperand<Expression> const & rhs)
1024 {
1025 multi_math::math_detail::minusAssign(*this, rhs);
1026 return *this;
1027 }
1028
1029 /** Multiply-assignment of an array expression. Fails with
1030 <tt>PreconditionViolation</tt> exception when the shapes do not match.
1031 */
1032 template<class Expression>
1033 MultiArrayView & operator*=(multi_math::MultiMathOperand<Expression> const & rhs)
1034 {
1035 multi_math::math_detail::multiplyAssign(*this, rhs);
1036 return *this;
1037 }
1038
1039 /** Divide-assignment of an array expression. Fails with
1040 <tt>PreconditionViolation</tt> exception when the shapes do not match.
1041 */
1042 template<class Expression>
1043 MultiArrayView & operator/=(multi_math::MultiMathOperand<Expression> const & rhs)
1044 {
1045 multi_math::math_detail::divideAssign(*this, rhs);
1046 return *this;
1047 }
1048
1049 /** array access.
1050 */
1052 {
1053 VIGRA_ASSERT_INSIDE(d);
1054 return m_ptr [dot (d, m_stride)];
1055 }
1056
1057 /** array access.
1058 */
1060 {
1061 VIGRA_ASSERT_INSIDE(d);
1062 return m_ptr [dot (d, m_stride)];
1063 }
1064
1065 /** equivalent to bindInner(), when M < N.
1066 */
1067 template <int M>
1069 {
1070 return bindInner(d);
1071 }
1072
1073 /** Array access in scan-order sense.
1074 Mostly useful to support standard indexing for 1-dimensional multi-arrays,
1075 but works for any N. Use scanOrderIndexToCoordinate() and
1076 coordinateToScanOrderIndex() for conversion between indices and coordinates.
1077
1078 <b>Note:</b> This function should not be used in the inner loop, because the
1079 conversion of the scan order index into a memory address is expensive
1080 (it must take into account that memory may not be consecutive for subarrays
1081 and/or strided arrays). Always prefer operator() if possible.
1082 */
1084 {
1085 VIGRA_ASSERT_INSIDE(scanOrderIndexToCoordinate(d));
1086 return m_ptr [detail::ScanOrderToOffset<actual_dimension>::exec(d, m_shape, m_stride)];
1087 }
1088
1089 /** Array access in scan-order sense.
1090 Mostly useful to support standard indexing for 1-dimensional multi-arrays,
1091 but works for any N. Use scanOrderIndexToCoordinate() and
1092 coordinateToScanOrderIndex() for conversion between indices and coordinates.
1093
1094 <b>Note:</b> This function should not be used in the inner loop, because the
1095 conversion of the scan order index into a memory address is expensive
1096 (it must take into account that memory may not be consecutive for subarrays
1097 and/or strided arrays). Always prefer operator() if possible.
1098 */
1100 {
1101 VIGRA_ASSERT_INSIDE(scanOrderIndexToCoordinate(d));
1102 return m_ptr [detail::ScanOrderToOffset<actual_dimension>::exec(d, m_shape, m_stride)];
1103 }
1104
1105 /** convert scan-order index to coordinate.
1106 */
1108 {
1109 difference_type result;
1110 detail::ScanOrderToCoordinate<actual_dimension>::exec(d, m_shape, result);
1111 return result;
1112 }
1113
1114 /** convert coordinate to scan-order index.
1115 */
1117 {
1118 return detail::CoordinateToScanOrder<actual_dimension>::exec(m_shape, d);
1119 }
1120
1121 /** 1D array access. Use only if N == 1.
1122 */
1124 {
1125 VIGRA_ASSERT_INSIDE(difference_type(x));
1126 return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride, x)];
1127 }
1128
1129 /** 2D array access. Use only if N == 2.
1130 */
1132 {
1133 VIGRA_ASSERT_INSIDE(difference_type(x, y));
1134 return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride, x, y)];
1135 }
1136
1137 /** 3D array access. Use only if N == 3.
1138 */
1140 {
1141 VIGRA_ASSERT_INSIDE(difference_type(x, y, z));
1142 return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z];
1143 }
1144
1145 /** 4D array access. Use only if N == 4.
1146 */
1149 {
1150 VIGRA_ASSERT_INSIDE(difference_type(x, y, z, u));
1151 return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u];
1152 }
1153
1154 /** 5D array access. Use only if N == 5.
1155 */
1158 {
1159 VIGRA_ASSERT_INSIDE(difference_type(x, y,z, u,v));
1160 return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u + m_stride[4]*v];
1161 }
1162
1163 /** 1D const array access. Use only if N == 1.
1164 */
1166 {
1167 VIGRA_ASSERT_INSIDE(difference_type(x));
1168 return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride, x)];
1169 }
1170
1171 /** 2D const array access. Use only if N == 2.
1172 */
1174 {
1175 VIGRA_ASSERT_INSIDE(difference_type(x, y));
1176 return m_ptr [detail::CoordinatesToOffest<StrideTag>::exec(m_stride, x, y)];
1177 }
1178
1179 /** 3D const array access. Use only if N == 3.
1180 */
1182 {
1183 VIGRA_ASSERT_INSIDE(difference_type(x,y,z));
1184 return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z];
1185 }
1186
1187 /** 4D const array access. Use only if N == 4.
1188 */
1191 {
1192 VIGRA_ASSERT_INSIDE(difference_type(x,y,z,u));
1193 return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u];
1194 }
1195
1196 /** 5D const array access. Use only if N == 5.
1197 */
1200 {
1201 VIGRA_ASSERT_INSIDE(difference_type(x,y,z,u,v));
1202 return m_ptr [m_stride[0]*x + m_stride[1]*y + m_stride[2]*z + m_stride[3]*u + m_stride[4]*v];
1203 }
1204
1205 /** Init with a constant.
1206 */
1207 template <class U>
1209 {
1210 if(hasData())
1211 detail::copyScalarMultiArrayData(traverser_begin(), shape(), init, MetaInt<actual_dimension-1>());
1212 return *this;
1213 }
1214
1215
1216 /** Copy the data of the right-hand array (array shapes must match).
1217 */
1218 void copy(const MultiArrayView & rhs)
1219 {
1220 if(this == &rhs)
1221 return;
1222 this->copyImpl(rhs);
1223 }
1224
1225 /** Copy the data of the right-hand array (array shapes must match).
1226 */
1227 template <class U, class CN>
1229 {
1230 this->copyImpl(rhs);
1231 }
1232
1233 /** Swap the pointers, shaes and strides between two array views.
1234
1235 This function must be used with care. Never swap a MultiArray
1236 (which owns data) with a MultiArrayView:
1237 \code
1238 MultiArray<2, int> a(3,2), b(3,2);
1239 MultiArrayView<2, int> va(a);
1240
1241 va.swap(b); // danger!
1242 \endcode
1243 Now, <tt>a</tt> and <tt>b</tt> refer to the same memory. This may lead
1244 to a crash in their destructor, and in any case leaks <tt>b</tt>'s original
1245 memory. Only use swap() on copied MultiArrayViews:
1246 \code
1247 MultiArray<2, int> a(3,2), b(3,2);
1248 MultiArrayView<2, int> va(a), vb(b);
1249
1250 va.swap(vb); // OK
1251 \endcode
1252 */
1253 void swap(MultiArrayView & other)
1254 {
1255 if (this == &other)
1256 return;
1257 std::swap(this->m_shape, other.m_shape);
1258 std::swap(this->m_stride, other.m_stride);
1259 std::swap(this->m_ptr, other.m_ptr);
1260 }
1261
1262 /** swap the data between two MultiArrayView objects.
1263
1264 The shapes of the two array must match.
1265 */
1267 {
1268 if(this != &rhs)
1269 swapDataImpl(rhs);
1270 }
1271
1272 /** swap the data between two MultiArrayView objects.
1273
1274 The shapes of the two array must match.
1275 */
1276 template <class T2, class C2>
1278 {
1279 swapDataImpl(rhs);
1280 }
1281
1282 /** check whether the array is unstrided (i.e. has consecutive memory) up
1283 to the given dimension.
1284
1285 \a dimension can range from 0 ... N-1. If a certain dimension is unstrided,
1286 all lower dimensions are also unstrided.
1287 */
1288 bool isUnstrided(unsigned int dimension = N-1) const
1289 {
1290 difference_type s = vigra::detail::defaultStride<actual_dimension>(shape());
1291 for(unsigned int k = 0; k <= dimension; ++k)
1292 if(stride(k) != s[k])
1293 return false;
1294 return true;
1295 }
1296
1297 /** bind the M outmost dimensions to certain indices.
1298 this reduces the dimensionality of the image to
1299 max { 1, N-M }.
1300
1301 <b>Usage:</b>
1302 \code
1303 // create a 3D array of size 40x30x20
1304 typedef MultiArray<3, double>::difference_type Shape;
1305 MultiArray<3, double> array3(Shape(40, 30, 20));
1306
1307 // get a 1D array by fixing index 1 to 12, and index 2 to 10
1308 MultiArrayView <1, double> array1 = array3.bindOuter(TinyVector<MultiArrayIndex, 2>(12, 10));
1309 \endcode
1310 */
1311 template <int M, class Index>
1312 MultiArrayView <N-M, T, StrideTag> bindOuter(const TinyVector <Index, M> &d) const;
1313
1314 /** bind the M innermost dimensions to certain indices.
1315 this reduces the dimensionality of the image to
1316 max { 1, N-M }.
1317
1318 <b>Usage:</b>
1319 \code
1320 // create a 3D array of size 40x30x20
1321 typedef MultiArray<3, double>::difference_type Shape;
1322 MultiArray<3, double> array3(Shape(40, 30, 20));
1323
1324 // get a 1D array by fixing index 0 to 12, and index 1 to 10
1325 MultiArrayView <1, double, StridedArrayTag> array1 = array3.bindInner(TinyVector<MultiArrayIndex, 2>(12, 10));
1326 \endcode
1327 */
1328 template <int M, class Index>
1329 MultiArrayView <N-M, T, StridedArrayTag> bindInner(const TinyVector <Index, M> &d) const;
1330
1331 /** bind dimension M to index d.
1332 this reduces the dimensionality of the image to
1333 max { 1, N-1 }.
1334
1335 <b>Usage:</b>
1336 \code
1337 // create a 3D array of size 40x30x20
1338 typedef MultiArray<3, double>::difference_type Shape;
1339 MultiArray<3, double> array3(Shape(40, 30, 20));
1340
1341 // get a 2D array by fixing index 1 to 12
1342 MultiArrayView <2, double> array2 = array3.bind<1>(12);
1343
1344 // get a 2D array by fixing index 0 to 23
1345 MultiArrayView <2, double, StridedArrayTag> array2a = array3.bind<0>(23);
1346 \endcode
1347 */
1348 template <unsigned int M>
1349 MultiArrayView <N-1, T, typename vigra::detail::MaybeStrided<StrideTag, M>::type >
1351
1352 /** bind the outmost dimension to a certain index.
1353 this reduces the dimensionality of the image to
1354 max { 1, N-1 }.
1355
1356 <b>Usage:</b>
1357 \code
1358 // create a 3D array of size 40x30x20
1359 typedef MultiArray<3, double>::difference_type Shape;
1360 MultiArray<3, double> array3(Shape(40, 30, 20));
1361
1362 // get a 2D array by fixing the outermost index (i.e. index 2) to 12
1363 MultiArrayView <2, double> array2 = array3.bindOuter(12);
1364 \endcode
1365 */
1366 MultiArrayView <N-1, T, StrideTag> bindOuter (difference_type_1 d) const;
1367
1368 /** bind the innermost dimension to a certain index.
1369 this reduces the dimensionality of the image to
1370 max { 1, N-1 }.
1371
1372 <b>Usage:</b>
1373 \code
1374 // create a 3D array of size 40x30x20
1375 typedef MultiArray<3, double>::difference_type Shape;
1376 MultiArray<3, double> array3(Shape(40, 30, 20));
1377
1378 // get a 2D array by fixing the innermost index (i.e. index 0) to 23
1379 MultiArrayView <2, double, StridedArrayTag> array2 = array3.bindInner(23);
1380 \endcode
1381 */
1383
1384 /** bind dimension m to index d.
1385 this reduces the dimensionality of the image to
1386 max { 1, N-1 }.
1387
1388 <b>Usage:</b>
1389 \code
1390 // create a 3D array of size 40x30x20
1391 typedef MultiArray<3, double>::difference_type Shape;
1392 MultiArray<3, double> array3(Shape(40, 30, 20));
1393
1394 // get a 2D array by fixing index 2 to 15
1395 MultiArrayView <2, double, StridedArrayTag> array2 = array3.bindAt(2, 15);
1396 \endcode
1397 */
1400
1401 /** Create a view to channel 'i' of a vector-like value type. Possible value types
1402 (of the original array) are: \ref TinyVector, \ref RGBValue, \ref FFTWComplex,
1403 and <tt>std::complex</tt>. The list can be extended to any type whose memory
1404 layout is equivalent to a fixed-size C array, by specializing
1405 <tt>ExpandElementResult</tt>.
1406
1407 <b>Usage:</b>
1408 \code
1409 MultiArray<2, RGBValue<float> > rgb_image(Shape2(w, h));
1410
1411 MultiArrayView<2, float, StridedArrayTag> red = rgb_image.bindElementChannel(0);
1412 MultiArrayView<2, float, StridedArrayTag> green = rgb_image.bindElementChannel(1);
1413 MultiArrayView<2, float, StridedArrayTag> blue = rgb_image.bindElementChannel(2);
1414 \endcode
1415 */
1416 MultiArrayView <N, typename ExpandElementResult<T>::type, StridedArrayTag>
1418 {
1419 vigra_precondition(0 <= i && i < ExpandElementResult<T>::size,
1420 "MultiArrayView::bindElementChannel(i): 'i' out of range.");
1421 return expandElements(0).bindInner(i);
1422 }
1423
1424 /** Create a view where a vector-like element type is expanded into a new
1425 array dimension. The new dimension is inserted at index position 'd',
1426 which must be between 0 and N inclusive.
1427
1428 Possible value types of the original array are: \ref TinyVector, \ref RGBValue,
1429 \ref FFTWComplex, <tt>std::complex</tt>, and the built-in number types (in this
1430 case, <tt>expandElements</tt> is equivalent to <tt>insertSingletonDimension</tt>).
1431 The list of supported types can be extended to any type whose memory
1432 layout is equivalent to a fixed-size C array, by specializing
1433 <tt>ExpandElementResult</tt>.
1434
1435 <b>Usage:</b>
1436 \code
1437 MultiArray<2, RGBValue<float> > rgb_image(Shape2(w, h));
1438
1439 MultiArrayView<3, float, StridedArrayTag> multiband_image = rgb_image.expandElements(2);
1440 \endcode
1441 */
1442 MultiArrayView <N+1, typename ExpandElementResult<T>::type, StridedArrayTag>
1444
1445 /** Add a singleton dimension (dimension of length 1).
1446
1447 Singleton dimensions don't change the size of the data, but introduce
1448 a new index that can only take the value 0. This is mainly useful for
1449 the 'reduce mode' of transformMultiArray() and combineTwoMultiArrays(),
1450 because these functions require the source and destination arrays to
1451 have the same number of dimensions.
1452
1453 The range of \a i must be <tt>0 <= i <= N</tt>. The new dimension will become
1454 the i'th index, and the old indices from i upwards will shift one
1455 place to the right.
1456
1457 <b>Usage:</b>
1458
1459 Suppose we want have a 2D array and want to create a 1D array that contains
1460 the row average of the first array.
1461 \code
1462 typedef MultiArrayShape<2>::type Shape2;
1463 MultiArray<2, double> original(Shape2(40, 30));
1464
1465 typedef MultiArrayShape<1>::type Shape1;
1466 MultiArray<1, double> rowAverages(Shape1(30));
1467
1468 // temporarily add a singleton dimension to the destination array
1469 transformMultiArray(srcMultiArrayRange(original),
1470 destMultiArrayRange(rowAverages.insertSingletonDimension(0)),
1471 FindAverage<double>());
1472 \endcode
1473 */
1476
1477 /** create a multiband view for this array.
1478
1479 The type <tt>MultiArrayView<N, Multiband<T> ></tt> tells VIGRA
1480 algorithms which recognize the <tt>Multiband</tt> modifier to
1481 interpret the outermost (last) dimension as a channel dimension.
1482 In effect, these algorithms will treat the data as a set of
1483 (N-1)-dimensional arrays instead of a single N-dimensional array.
1484 */
1486 {
1487 return MultiArrayView<N, Multiband<value_type>, StrideTag>(*this);
1488 }
1489
1490 /** Create a view to the diagonal elements of the array.
1491
1492 This produces a 1D array view whose size equals the size
1493 of the shortest dimension of the original array.
1494
1495 <b>Usage:</b>
1496 \code
1497 // create a 3D array of size 40x30x20
1498 typedef MultiArray<3, double>::difference_type Shape;
1499 MultiArray<3, double> array3(Shape(40, 30, 20));
1500
1501 // get a view to the diagonal elements
1502 MultiArrayView <1, double, StridedArrayTag> diagonal = array3.diagonal();
1503 assert(diagonal.shape(0) == 20);
1504 \endcode
1505 */
1507 {
1508 return MultiArrayView<1, T, StridedArrayTag>(Shape1(vigra::min(m_shape)),
1509 Shape1(vigra::sum(m_stride)), m_ptr);
1510 }
1511
1512 /** create a rectangular subarray that spans between the
1513 points p and q, where p is in the subarray, q not.
1514 If an element of p or q is negative, it is subtracted
1515 from the correspongng shape.
1516
1517 <b>Usage:</b>
1518 \code
1519 // create a 3D array of size 40x30x20
1520 typedef MultiArray<3, double>::difference_type Shape;
1521 MultiArray<3, double> array3(Shape(40, 30, 20));
1522
1523 // get a subarray set is smaller by one element at all sides
1524 MultiArrayView <3, double> subarray = array3.subarray(Shape(1,1,1), Shape(39, 29, 19));
1525
1526 // specifying the end point with a vector of '-1' is equivalent
1527 MultiArrayView <3, double> subarray2 = array3.subarray(Shape(1,1,1), Shape(-1, -1, -1));
1528 \endcode
1529 */
1531 {
1532 detail::RelativeToAbsoluteCoordinate<actual_dimension-1>::exec(shape(), p);
1533 detail::RelativeToAbsoluteCoordinate<actual_dimension-1>::exec(shape(), q);
1534 const difference_type_1 offset = dot (m_stride, p);
1535 return MultiArrayView (q - p, m_stride, m_ptr + offset);
1536 }
1537
1538 /** apply an additional striding to the image, thereby reducing
1539 the shape of the array.
1540 for example, multiplying the stride of dimension one by three
1541 turns an appropriately laid out (interleaved) rgb image into
1542 a single band image.
1543 */
1546 {
1548 for (unsigned int i = 0; i < actual_dimension; ++i)
1549 shape[i] = (shape[i] + s[i] - 1) / s[i];
1551 }
1552
1553 /** Transpose an array. If N==2, this implements the usual matrix transposition.
1554 For N > 2, it reverses the order of the indices.
1555
1556 <b>Usage:</b><br>
1557 \code
1558 typedef MultiArray<2, double>::difference_type Shape;
1559 MultiArray<2, double> array(10, 20);
1560
1561 MultiArrayView<2, double, StridedArrayTag> transposed = array.transpose();
1562
1563 for(int i=0; i<array.shape(0), ++i)
1564 for(int j=0; j<array.shape(1); ++j)
1565 assert(array(i, j) == transposed(j, i));
1566 \endcode
1567 */
1569 transpose () const
1570 {
1571 difference_type shape(m_shape.begin(), ReverseCopy),
1572 stride(m_stride.begin(), ReverseCopy);
1574 }
1575
1576 /** Permute the dimensions of the array.
1577 The function exchanges the orer of the array's axes without copying the data.
1578 Argument\a permutation specifies the desired order such that
1579 <tt>permutation[k] = j</tt> means that axis <tt>j</tt> in the original array
1580 becomes axis <tt>k</tt> in the transposed array.
1581
1582 <b>Usage:</b><br>
1583 \code
1584 typedef MultiArray<2, double>::difference_type Shape;
1585 MultiArray<2, double> array(10, 20);
1586
1587 MultiArrayView<2, double, StridedArrayTag> transposed = array.transpose(Shape(1,0));
1588
1589 for(int i=0; i<array.shape(0), ++i)
1590 for(int j=0; j<array.shape(1); ++j)
1591 assert(array(i, j) == transposed(j, i));
1592 \endcode
1593 */
1595 transpose(const difference_type &permutation) const
1596 {
1597 return permuteDimensions(permutation);
1598 }
1599
1601 permuteDimensions (const difference_type &s) const;
1602
1603 /** Permute the dimensions of the array so that the strides are in ascending order.
1604 Determines the appropriate permutation and then calls permuteDimensions().
1605 */
1608
1609 /** Permute the dimensions of the array so that the strides are in descending order.
1610 Determines the appropriate permutation and then calls permuteDimensions().
1611 */
1614
1615 /** Compute the ordering of the strides in this array.
1616 The result is describes the current permutation of the axes relative
1617 to the standard ascending stride order.
1618 */
1620 {
1621 return strideOrdering(m_stride);
1622 }
1623
1624 /** Compute the ordering of the given strides.
1625 The result is describes the current permutation of the axes relative
1626 to the standard ascending stride order.
1627 */
1629
1630 /** number of the elements in the array.
1631 */
1633 {
1634 difference_type_1 ret = m_shape[0];
1635 for(int i = 1; i < actual_dimension; ++i)
1636 ret *= m_shape[i];
1637 return ret;
1638 }
1639
1640 /** number of the elements in the array.
1641 Same as <tt>elementCount()</tt>. Mostly useful to support the std::vector interface.
1642 */
1644 {
1645 return elementCount();
1646 }
1647
1648 /** return the array's shape.
1649 */
1650 const difference_type & shape () const
1651 {
1652 return m_shape;
1653 }
1654
1655 /** return the array's size at a certain dimension.
1656 */
1658 {
1659 return m_shape [n];
1660 }
1661
1662 /** return the array's shape at a certain dimension
1663 (same as <tt>size(n)</tt>).
1664 */
1666 {
1667 return m_shape [n];
1668 }
1669
1670 /** return the array's width (same as <tt>shape(0)</tt>).
1671 */
1673 {
1674 return m_shape [0];
1675 }
1676
1677 /** return the array's height (same as <tt>shape(1)</tt>).
1678 */
1680 {
1681 return m_shape [1];
1682 }
1683
1684 /** return the array's stride for every dimension.
1685 */
1686 const difference_type & stride () const
1687 {
1688 return m_stride;
1689 }
1690
1691 /** return the array's stride at a certain dimension.
1692 */
1694 {
1695 return m_stride [n];
1696 }
1697
1698 /** check whether two arrays are elementwise equal.
1699 */
1700 template <class U, class C1>
1701 bool operator==(MultiArrayView<N, U, C1> const & rhs) const
1702 {
1703 if(this->shape() != rhs.shape())
1704 return false;
1705 return detail::equalityOfMultiArrays(traverser_begin(), shape(), rhs.traverser_begin(), MetaInt<actual_dimension-1>());
1706 }
1707
1708 /** check whether two arrays are not elementwise equal.
1709 Also true when the two arrays have different shapes.
1710 */
1711 template <class U, class C1>
1712 bool operator!=(MultiArrayView<N, U, C1> const & rhs) const
1713 {
1714 return !operator==(rhs);
1715 }
1716
1717 /** check whether the given point is in the array range.
1718 */
1719 bool isInside (difference_type const & p) const
1720 {
1721 for(int d=0; d<actual_dimension; ++d)
1722 if(p[d] < 0 || p[d] >= shape(d))
1723 return false;
1724 return true;
1725 }
1726 /** check whether the given point is not in the array range.
1727 */
1728 bool isOutside (difference_type const & p) const
1729 {
1730 for(int d=0; d<actual_dimension; ++d)
1731 if(p[d] < 0 || p[d] >= shape(d))
1732 return true;
1733 return false;
1734 }
1735
1736 /** Check if the array contains only non-zero elements (or if all elements
1737 are 'true' if the value type is 'bool').
1738 */
1739 bool all() const
1740 {
1741 bool res = true;
1742 detail::reduceOverMultiArray(traverser_begin(), shape(),
1743 res,
1744 detail::AllTrueReduceFunctor(),
1745 MetaInt<actual_dimension-1>());
1746 return res;
1747 }
1748
1749 /** Check if the array contains a non-zero element (or an element
1750 that is 'true' if the value type is 'bool').
1751 */
1752 bool any() const
1753 {
1754 bool res = false;
1755 detail::reduceOverMultiArray(traverser_begin(), shape(),
1756 res,
1757 detail::AnyTrueReduceFunctor(),
1758 MetaInt<actual_dimension-1>());
1759 return res;
1760 }
1761
1762 /** Find the minimum and maximum element in this array.
1763 See \ref FeatureAccumulators for a general feature
1764 extraction framework.
1765 */
1766 void minmax(T * minimum, T * maximum) const
1767 {
1768 std::pair<T, T> res(NumericTraits<T>::max(), NumericTraits<T>::min());
1769 detail::reduceOverMultiArray(traverser_begin(), shape(),
1770 res,
1771 detail::MinmaxReduceFunctor(),
1772 MetaInt<actual_dimension-1>());
1773 *minimum = res.first;
1774 *maximum = res.second;
1775 }
1776
1777 /** Compute the mean and variance of the values in this array.
1778 See \ref FeatureAccumulators for a general feature
1779 extraction framework.
1780 */
1781 template <class U>
1782 void meanVariance(U * mean, U * variance) const
1783 {
1784 typedef typename NumericTraits<U>::RealPromote R;
1785 R zero = R();
1786 triple<double, R, R> res(0.0, zero, zero);
1787 detail::reduceOverMultiArray(traverser_begin(), shape(),
1788 res,
1789 detail::MeanVarianceReduceFunctor(),
1790 MetaInt<actual_dimension-1>());
1791 *mean = res.second;
1792 *variance = res.third / res.first;
1793 }
1794
1795 /** Compute the sum of the array elements.
1796
1797 You must provide the type of the result by an explicit template parameter:
1798 \code
1799 MultiArray<2, UInt8> A(width, height);
1800
1801 double sum = A.sum<double>();
1802 \endcode
1803 */
1804 template <class U>
1805 U sum() const
1806 {
1807 U res = NumericTraits<U>::zero();
1808 detail::reduceOverMultiArray(traverser_begin(), shape(),
1809 res,
1810 detail::SumReduceFunctor(),
1811 MetaInt<actual_dimension-1>());
1812 return res;
1813 }
1814
1815 /** Compute the sum of the array elements over selected axes.
1816
1817 \arg sums must have the same shape as this array, except for the
1818 axes along which the sum is to be accumulated. These axes must be
1819 singletons. Note that you must include <tt>multi_pointoperators.hxx</tt>
1820 for this function to work.
1821
1822 <b>Usage:</b>
1823 \code
1824 #include <vigra/multi_array.hxx>
1825 #include <vigra/multi_pointoperators.hxx>
1826
1827 MultiArray<2, double> A(Shape2(rows, cols));
1828 ... // fill A
1829
1830 // make the first axis a singleton to sum over the first index
1831 MultiArray<2, double> rowSums(Shape2(1, cols));
1832 A.sum(rowSums);
1833
1834 // this is equivalent to
1835 transformMultiArray(srcMultiArrayRange(A),
1836 destMultiArrayRange(rowSums),
1837 FindSum<double>());
1838 \endcode
1839 */
1840 template <class U, class S>
1842 {
1843 transformMultiArray(srcMultiArrayRange(*this),
1844 destMultiArrayRange(sums),
1845 FindSum<U>());
1846 }
1847
1848 /** Compute the product of the array elements.
1849
1850 You must provide the type of the result by an explicit template parameter:
1851 \code
1852 MultiArray<2, UInt8> A(width, height);
1853
1854 double prod = A.product<double>();
1855 \endcode
1856 */
1857 template <class U>
1858 U product() const
1859 {
1860 U res = NumericTraits<U>::one();
1861 detail::reduceOverMultiArray(traverser_begin(), shape(),
1862 res,
1863 detail::ProdReduceFunctor(),
1864 MetaInt<actual_dimension-1>());
1865 return res;
1866 }
1867
1868 /** Compute the squared Euclidean norm of the array (sum of squares of the array elements).
1869 */
1870 typename NormTraits<MultiArrayView>::SquaredNormType
1872 {
1873 typedef typename NormTraits<MultiArrayView>::SquaredNormType SquaredNormType;
1874 SquaredNormType res = NumericTraits<SquaredNormType>::zero();
1875 detail::reduceOverMultiArray(traverser_begin(), shape(),
1876 res,
1877 detail::SquaredL2NormReduceFunctor(),
1878 MetaInt<actual_dimension-1>());
1879 return res;
1880 }
1881
1882 /** Compute various norms of the array.
1883 The norm is determined by parameter \a type:
1884
1885 <ul>
1886 <li> type == 0: maximum norm (L-infinity): maximum of absolute values of the array elements
1887 <li> type == 1: Manhattan norm (L1): sum of absolute values of the array elements
1888 <li> type == 2: Euclidean norm (L2): square root of <tt>squaredNorm()</tt> when \a useSquaredNorm is <tt>true</tt>,<br>
1889 or direct algorithm that avoids underflow/overflow otherwise.
1890 </ul>
1891
1892 Parameter \a useSquaredNorm has no effect when \a type != 2. Defaults: compute L2 norm as square root of
1893 <tt>squaredNorm()</tt>.
1894 */
1895 typename NormTraits<MultiArrayView>::NormType
1896 norm(int type = 2, bool useSquaredNorm = true) const;
1897
1898 /** return the pointer to the image data
1899 */
1900 pointer data () const
1901 {
1902 return m_ptr;
1903 }
1904
1905 pointer & unsafePtr()
1906 {
1907 return m_ptr;
1908 }
1909
1910 /**
1911 * returns true iff this view refers to valid data,
1912 * i.e. data() is not a NULL pointer. (this is false after
1913 * default construction.)
1914 */
1915 bool hasData () const
1916 {
1917 return m_ptr != 0;
1918 }
1919
1920 /** returns a scan-order iterator pointing
1921 to the first array element.
1922 */
1924 {
1925 return iterator(*this);
1926 }
1927
1928 /** returns a const scan-order iterator pointing
1929 to the first array element.
1930 */
1932 {
1933 return const_iterator(*this);
1934 }
1935
1936 /** returns a scan-order iterator pointing
1937 beyond the last array element.
1938 */
1940 {
1941 return begin().getEndIterator();
1942 }
1943
1944 /** returns a const scan-order iterator pointing
1945 beyond the last array element.
1946 */
1948 {
1949 return begin().getEndIterator();
1950 }
1951
1952 /** returns the N-dimensional MultiIterator pointing
1953 to the first element in every dimension.
1954 */
1956 {
1957 traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
1958 return ret;
1959 }
1960
1961 /** returns the N-dimensional MultiIterator pointing
1962 to the const first element in every dimension.
1963 */
1965 {
1966 const_traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
1967 return ret;
1968 }
1969
1970 /** returns the N-dimensional MultiIterator pointing
1971 beyond the last element in dimension N, and to the
1972 first element in every other dimension.
1973 */
1975 {
1976 traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
1977 ret += m_shape [actual_dimension-1];
1978 return ret;
1979 }
1980
1981 /** returns the N-dimensional const MultiIterator pointing
1982 beyond the last element in dimension N, and to the
1983 first element in every other dimension.
1984 */
1986 {
1987 const_traverser ret (m_ptr, m_stride.begin (), m_shape.begin ());
1988 ret += m_shape [actual_dimension-1];
1989 return ret;
1990 }
1991
1992 view_type view () const
1993 {
1994 return *this;
1995 }
1996};
1997
1998template <unsigned int N, class T, class StrideTag>
1999class MultiArrayView<N, Multiband<T>, StrideTag>
2000: public MultiArrayView<N, T, StrideTag>
2001{
2002 public:
2004 : MultiArrayView<N, T, StrideTag>(v)
2005 {}
2006};
2007
2008
2009template <unsigned int N, class T, class Stride1>
2010template <class Stride2>
2011void
2012MultiArrayView <N, T, Stride1>::assignImpl(MultiArrayView<N, T, Stride2> const & rhs)
2013{
2014 if(m_ptr == 0)
2015 {
2016 vigra_precondition(rhs.checkInnerStride(Stride1()),
2017 "MultiArrayView<..., UnstridedArrayTag>::operator=(MultiArrayView const &): cannot create unstrided view from strided array.");
2018
2019 m_shape = rhs.shape();
2020 m_stride = rhs.stride();
2021 m_ptr = rhs.data();
2022 }
2023 else
2024 {
2025 vigra_precondition(this->shape() == rhs.shape(),
2026 "MultiArrayView::operator=(MultiArrayView const &): shape mismatch.");
2027 this->copyImpl(rhs);
2028 }
2029}
2030
2031template <unsigned int N, class T, class StrideTag>
2032template <class CN>
2033bool
2034MultiArrayView <N, T, StrideTag>::arraysOverlap(const MultiArrayView <N, T, CN>& rhs) const
2035{
2036 vigra_precondition (shape () == rhs.shape (),
2037 "MultiArrayView::arraysOverlap(): shape mismatch.");
2038 const_pointer first_element = this->m_ptr,
2039 last_element = first_element + dot(this->m_shape - difference_type(1), this->m_stride);
2041 rhs_first_element = rhs.data(),
2042 rhs_last_element = rhs_first_element + dot(rhs.shape() - difference_type(1), rhs.stride());
2043 return !(last_element < rhs_first_element || rhs_last_element < first_element);
2044}
2045
2046template <unsigned int N, class T, class StrideTag>
2047template <class U, class CN>
2048void
2049MultiArrayView <N, T, StrideTag>::copyImpl(const MultiArrayView <N, U, CN>& rhs)
2050{
2051 if(!arraysOverlap(rhs))
2052 {
2053 // no overlap -- can copy directly
2054 detail::copyMultiArrayData(rhs.traverser_begin(), shape(), traverser_begin(), MetaInt<actual_dimension-1>());
2055 }
2056 else
2057 {
2058 // overlap: we got different views to the same data -- copy to intermediate memory in order to avoid
2059 // overwriting elements that are still needed on the rhs.
2060 MultiArray<N, T> tmp(rhs);
2061 detail::copyMultiArrayData(tmp.traverser_begin(), shape(), traverser_begin(), MetaInt<actual_dimension-1>());
2062 }
2063}
2064
2065#define VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(name, op) \
2066template <unsigned int N, class T, class StrideTag> \
2067template<class U, class C1> \
2068MultiArrayView<N, T, StrideTag> & \
2069MultiArrayView <N, T, StrideTag>::operator op(MultiArrayView<N, U, C1> const & rhs) \
2070{ \
2071 vigra_precondition(this->shape() == rhs.shape(), "MultiArrayView::operator" #op "() size mismatch."); \
2072 if(!arraysOverlap(rhs)) \
2073 { \
2074 detail::name##MultiArrayData(rhs.traverser_begin(), shape(), traverser_begin(), MetaInt<actual_dimension-1>()); \
2075 } \
2076 else \
2077 { \
2078 MultiArray<N, T> tmp(rhs); \
2079 detail::name##MultiArrayData(tmp.traverser_begin(), shape(), traverser_begin(), MetaInt<actual_dimension-1>()); \
2080 } \
2081 return *this; \
2082}
2083
2084VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(copyAdd, +=)
2085VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(copySub, -=)
2086VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(copyMul, *=)
2087VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT(copyDiv, /=)
2088
2089#undef VIGRA_MULTI_ARRAY_COMPUTED_ASSIGNMENT
2090
2091template <unsigned int N, class T, class StrideTag>
2092template <class U, class CN>
2093void
2094MultiArrayView <N, T, StrideTag>::swapDataImpl(MultiArrayView <N, U, CN> rhs)
2095{
2096 vigra_precondition (shape () == rhs.shape (),
2097 "MultiArrayView::swapData(): shape mismatch.");
2098
2099 // check for overlap of this and rhs
2100 const_pointer first_element = this->m_ptr,
2101 last_element = first_element + dot(this->m_shape - difference_type(1), this->m_stride);
2103 rhs_first_element = rhs.data(),
2104 rhs_last_element = rhs_first_element + dot(rhs.shape() - difference_type(1), rhs.stride());
2105 if(last_element < rhs_first_element || rhs_last_element < first_element)
2106 {
2107 // no overlap -- can swap directly
2108 detail::swapDataImpl(traverser_begin(), shape(), rhs.traverser_begin(), MetaInt<actual_dimension-1>());
2109 }
2110 else
2111 {
2112 // overlap: we got different views to the same data -- copy to intermediate memory in order to avoid
2113 // overwriting elements that are still needed.
2114 MultiArray<N, T> tmp(*this);
2115 copy(rhs);
2116 rhs.copy(tmp);
2117 }
2118}
2119
2120template <unsigned int N, class T, class StrideTag>
2121MultiArrayView <N, T, StridedArrayTag>
2122MultiArrayView <N, T, StrideTag>::permuteDimensions (const difference_type &s) const
2123{
2124 difference_type shape, stride, check((typename difference_type::value_type)0);
2125 for (unsigned int i = 0; i < actual_dimension; ++i)
2126 {
2127 shape[i] = m_shape[s[i]];
2128 stride[i] = m_stride[s[i]];
2129 ++check[s[i]];
2130 }
2131 vigra_precondition(check == difference_type(1),
2132 "MultiArrayView::transpose(): every dimension must occur exactly once.");
2133 return MultiArrayView <N, T, StridedArrayTag>(shape, stride, m_ptr);
2134}
2135
2136template <unsigned int N, class T, class StrideTag>
2139{
2140 difference_type permutation;
2141 for(int k=0; k<(int)N; ++k)
2142 permutation[k] = k;
2143 for(int k=0; k<(int)N-1; ++k)
2144 {
2145 int smallest = k;
2146 for(int j=k+1; j<(int)N; ++j)
2147 {
2148 if(stride[j] < stride[smallest])
2149 smallest = j;
2150 }
2151 if(smallest != k)
2152 {
2153 std::swap(stride[k], stride[smallest]);
2154 std::swap(permutation[k], permutation[smallest]);
2155 }
2156 }
2157 difference_type ordering;
2158 for(unsigned int k=0; k<N; ++k)
2159 ordering[permutation[k]] = k;
2160 return ordering;
2161}
2162
2163template <unsigned int N, class T, class StrideTag>
2164MultiArrayView <N, T, StridedArrayTag>
2166{
2167 difference_type ordering(strideOrdering(m_stride)), permutation;
2168 for(MultiArrayIndex k=0; k<N; ++k)
2169 permutation[ordering[k]] = k;
2170 return permuteDimensions(permutation);
2171}
2172
2173template <unsigned int N, class T, class StrideTag>
2174MultiArrayView <N, T, StridedArrayTag>
2176{
2177 difference_type ordering(strideOrdering(m_stride)), permutation;
2178 for(MultiArrayIndex k=0; k<N; ++k)
2179 permutation[N-1-ordering[k]] = k;
2180 return permuteDimensions(permutation);
2181}
2182
2183template <unsigned int N, class T, class StrideTag>
2184template <int M, class Index>
2185MultiArrayView <N-M, T, StrideTag>
2186MultiArrayView <N, T, StrideTag>::bindOuter (const TinyVector <Index, M> &d) const
2187{
2188 TinyVector <MultiArrayIndex, M> stride;
2189 stride.init (m_stride.begin () + N-M, m_stride.end ());
2190 pointer ptr = m_ptr + dot (d, stride);
2191 static const int NNew = (N-M == 0) ? 1 : N-M;
2192 TinyVector <MultiArrayIndex, NNew> inner_shape, inner_stride;
2193 if (N-M == 0)
2194 {
2195 inner_shape [0] = 1;
2196 inner_stride [0] = 1;
2197 }
2198 else
2199 {
2200 inner_shape.init (m_shape.begin (), m_shape.end () - M);
2201 inner_stride.init (m_stride.begin (), m_stride.end () - M);
2202 }
2203 return MultiArrayView <N-M, T, StrideTag> (inner_shape, inner_stride, ptr);
2204}
2205
2206template <unsigned int N, class T, class StrideTag>
2207template <int M, class Index>
2209MultiArrayView <N, T, StrideTag>::bindInner (const TinyVector <Index, M> &d) const
2210{
2211 TinyVector <MultiArrayIndex, M> stride;
2212 stride.init (m_stride.begin (), m_stride.end () - N + M);
2213 pointer ptr = m_ptr + dot (d, stride);
2214 static const int NNew = (N-M == 0) ? 1 : N-M;
2215 TinyVector <MultiArrayIndex, NNew> outer_shape, outer_stride;
2216 if (N-M == 0)
2217 {
2218 outer_shape [0] = 1;
2219 outer_stride [0] = 1;
2220 }
2221 else
2222 {
2223 outer_shape.init (m_shape.begin () + M, m_shape.end ());
2224 outer_stride.init (m_stride.begin () + M, m_stride.end ());
2225 }
2226 return MultiArrayView <N-M, T, StridedArrayTag>
2227 (outer_shape, outer_stride, ptr);
2228}
2229
2230template <unsigned int N, class T, class StrideTag>
2231template <unsigned int M>
2232MultiArrayView <N-1, T, typename detail::MaybeStrided<StrideTag, M>::type >
2233MultiArrayView <N, T, StrideTag>::bind (difference_type_1 d) const
2234{
2235 static const int NNew = (N-1 == 0) ? 1 : N-1;
2236 TinyVector <MultiArrayIndex, NNew> shape, stride;
2237 // the remaining dimensions are 0..n-1,n+1..N-1
2238 if (N-1 == 0)
2239 {
2240 shape[0] = 1;
2241 stride[0] = 1;
2242 }
2243 else
2244 {
2245 std::copy (m_shape.begin (), m_shape.begin () + M, shape.begin ());
2246 std::copy (m_shape.begin () + M+1, m_shape.end (),
2247 shape.begin () + M);
2248 std::copy (m_stride.begin (), m_stride.begin () + M, stride.begin ());
2249 std::copy (m_stride.begin () + M+1, m_stride.end (),
2250 stride.begin () + M);
2251 }
2252 return MultiArrayView <N-1, T, typename detail::MaybeStrided<StrideTag, M>::type>
2253 (shape, stride, m_ptr + d * m_stride[M]);
2254}
2255
2256template <unsigned int N, class T, class StrideTag>
2257MultiArrayView <N - 1, T, StrideTag>
2259{
2260 static const int NNew = (N-1 == 0) ? 1 : N-1;
2261 TinyVector <MultiArrayIndex, NNew> inner_shape, inner_stride;
2262 if (N-1 == 0)
2263 {
2264 inner_shape [0] = 1;
2265 inner_stride [0] = 1;
2266 }
2267 else
2268 {
2269 inner_shape.init (m_shape.begin (), m_shape.end () - 1);
2270 inner_stride.init (m_stride.begin (), m_stride.end () - 1);
2271 }
2272 return MultiArrayView <N-1, T, StrideTag> (inner_shape, inner_stride,
2273 m_ptr + d * m_stride [N-1]);
2274}
2275
2276template <unsigned int N, class T, class StrideTag>
2279{
2280 static const int NNew = (N-1 == 0) ? 1 : N-1;
2281 TinyVector <MultiArrayIndex, NNew> outer_shape, outer_stride;
2282 if (N-1 == 0)
2283 {
2284 outer_shape [0] = 1;
2285 outer_stride [0] = 1;
2286 }
2287 else
2288 {
2289 outer_shape.init (m_shape.begin () + 1, m_shape.end ());
2290 outer_stride.init (m_stride.begin () + 1, m_stride.end ());
2291 }
2292 return MultiArrayView <N-1, T, StridedArrayTag>
2293 (outer_shape, outer_stride, m_ptr + d * m_stride [0]);
2294}
2295
2296template <unsigned int N, class T, class StrideTag>
2299{
2300 vigra_precondition (
2301 n < static_cast <int> (N),
2302 "MultiArrayView <N, T, StrideTag>::bindAt(): dimension out of range.");
2303 static const int NNew = (N-1 == 0) ? 1 : N-1;
2304 TinyVector <MultiArrayIndex, NNew> shape, stride;
2305 // the remaining dimensions are 0..n-1,n+1..N-1
2306 if (N-1 == 0)
2307 {
2308 shape [0] = 1;
2309 stride [0] = 1;
2310 }
2311 else
2312 {
2313 std::copy (m_shape.begin (), m_shape.begin () + n, shape.begin ());
2314 std::copy (m_shape.begin () + n+1, m_shape.end (),
2315 shape.begin () + n);
2316 std::copy (m_stride.begin (), m_stride.begin () + n, stride.begin ());
2317 std::copy (m_stride.begin () + n+1, m_stride.end (),
2318 stride.begin () + n);
2319 }
2320 return MultiArrayView <N-1, T, StridedArrayTag>
2321 (shape, stride, m_ptr + d * m_stride[n]);
2322}
2323
2324
2325template <unsigned int N, class T, class StrideTag>
2326MultiArrayView <N+1, typename ExpandElementResult<T>::type, StridedArrayTag>
2328{
2329 vigra_precondition(0 <= d && d <= static_cast <difference_type_1> (N),
2330 "MultiArrayView<N, ...>::expandElements(d): 0 <= 'd' <= N required.");
2331
2332 int elementSize = ExpandElementResult<T>::size;
2333 typename MultiArrayShape<N+1>::type newShape, newStrides;
2334 for(int k=0; k<d; ++k)
2335 {
2336 newShape[k] = m_shape[k];
2337 newStrides[k] = m_stride[k]*elementSize;
2338 }
2339
2340 newShape[d] = elementSize;
2341 newStrides[d] = 1;
2342
2343 for(unsigned k=d; k<N; ++k)
2344 {
2345 newShape[k+1] = m_shape[k];
2346 newStrides[k+1] = m_stride[k]*elementSize;
2347 }
2348
2349 typedef typename ExpandElementResult<T>::type U;
2351 newShape, newStrides, reinterpret_cast<U*>(m_ptr));
2352}
2353
2354template <unsigned int N, class T, class StrideTag>
2355MultiArrayView <N+1, T, StrideTag>
2357{
2358 vigra_precondition (
2359 0 <= i && i <= static_cast <difference_type_1> (N),
2360 "MultiArrayView <N, T, StrideTag>::insertSingletonDimension(): index out of range.");
2361 TinyVector <MultiArrayIndex, N+1> shape, stride;
2362 std::copy (m_shape.begin (), m_shape.begin () + i, shape.begin ());
2363 std::copy (m_shape.begin () + i, m_shape.end (), shape.begin () + i + 1);
2364 std::copy (m_stride.begin (), m_stride.begin () + i, stride.begin ());
2365 std::copy (m_stride.begin () + i, m_stride.end (), stride.begin () + i + 1);
2366 shape[i] = 1;
2367 stride[i] = 1;
2368
2369 return MultiArrayView <N+1, T, StrideTag>(shape, stride, m_ptr);
2370}
2371
2372template <unsigned int N, class T, class StrideTag>
2373typename NormTraits<MultiArrayView <N, T, StrideTag> >::NormType
2374MultiArrayView <N, T, StrideTag>::norm(int type, bool useSquaredNorm) const
2375{
2376 typedef typename NormTraits<MultiArrayView>::NormType NormType;
2377
2378 switch(type)
2379 {
2380 case 0:
2381 {
2382 NormType res = NumericTraits<NormType>::zero();
2383 detail::reduceOverMultiArray(traverser_begin(), shape(),
2384 res,
2385 detail::MaxNormReduceFunctor(),
2386 MetaInt<actual_dimension-1>());
2387 return res;
2388 }
2389 case 1:
2390 {
2391 NormType res = NumericTraits<NormType>::zero();
2392 detail::reduceOverMultiArray(traverser_begin(), shape(),
2393 res,
2394 detail::L1NormReduceFunctor(),
2395 MetaInt<actual_dimension-1>());
2396 return res;
2397 }
2398 case 2:
2399 {
2400 if(useSquaredNorm)
2401 {
2402 return sqrt((NormType)squaredNorm());
2403 }
2404 else
2405 {
2406 NormType normMax = NumericTraits<NormType>::zero();
2407 detail::reduceOverMultiArray(traverser_begin(), shape(),
2408 normMax,
2409 detail::MaxNormReduceFunctor(),
2410 MetaInt<actual_dimension-1>());
2411 if(normMax == NumericTraits<NormType>::zero())
2412 return normMax;
2413 NormType res = NumericTraits<NormType>::zero();
2414 detail::reduceOverMultiArray(traverser_begin(), shape(),
2415 res,
2416 detail::WeightedL2NormReduceFunctor<NormType>(1.0/normMax),
2417 MetaInt<actual_dimension-1>());
2418 return sqrt(res)*normMax;
2419 }
2420 }
2421 default:
2422 vigra_precondition(false, "MultiArrayView::norm(): Unknown norm type.");
2423 return NumericTraits<NormType>::zero(); // unreachable
2424 }
2425}
2426
2427
2428/********************************************************/
2429/* */
2430/* norm */
2431/* */
2432/********************************************************/
2433
2434template <unsigned int N, class T, class StrideTag>
2435inline typename NormTraits<MultiArrayView <N, T, StrideTag> >::SquaredNormType
2436squaredNorm(MultiArrayView <N, T, StrideTag> const & a)
2437{
2438 return a.squaredNorm();
2439}
2440
2441template <unsigned int N, class T, class StrideTag>
2442inline typename NormTraits<MultiArrayView <N, T, StrideTag> >::NormType
2443norm(MultiArrayView <N, T, StrideTag> const & a)
2444{
2445 return a.norm();
2446}
2447
2448/********************************************************/
2449/* */
2450/* MultiArray */
2451/* */
2452/********************************************************/
2453
2454/** \brief Main <TT>MultiArray</TT> class containing the memory
2455 management.
2456
2457This class inherits the interface of MultiArrayView, and implements
2458the memory ownership.
2459MultiArray's are always unstrided, striding them creates a MultiArrayView.
2460
2461
2462The template parameters are as follows
2463\code
2464 N: the array dimension
2465
2466 T: the type of the array elements
2467
2468 A: the allocator used for internal storage management
2469 (default: std::allocator<T>)
2470\endcode
2471
2472<b>\#include</b> <vigra/multi_array.hxx> <br/>
2473Namespace: vigra
2474*/
2475template <unsigned int N, class T, class A /* default already declared above */>
2477: public MultiArrayView <N, typename vigra::detail::ResolveMultiband<T>::type,
2478 typename vigra::detail::ResolveMultiband<T>::Stride>
2479{
2480 public:
2481 typedef typename vigra::detail::ResolveMultiband<T>::Stride actual_stride;
2482
2483 /** the view type associated with this array.
2484 */
2485 typedef MultiArrayView <N, typename vigra::detail::ResolveMultiband<T>::type,
2486 typename vigra::detail::ResolveMultiband<T>::Stride> view_type;
2487
2488 using view_type::actual_dimension;
2489
2490 /** the allocator type used to allocate the memory
2491 */
2493
2494 /** the matrix type associated with this array.
2495 */
2497
2498 /** the array's value type
2499 */
2501
2502 /** pointer type
2503 */
2504 typedef typename view_type::pointer pointer;
2505
2506 /** const pointer type
2507 */
2509
2510 /** reference type (result of operator[])
2511 */
2513
2514 /** const reference type (result of operator[] const)
2515 */
2517
2518 /** size type
2519 */
2521
2522 /** difference type (used for multi-dimensional offsets and indices)
2523 */
2525
2526 /** difference and index type for a single dimension
2527 */
2529
2530 /** traverser type
2531 */
2533
2534 /** traverser type to const data
2535 */
2537
2538 // /** sequential (random access) iterator type
2539 // */
2540 // typedef typename vigra::detail::MultiIteratorChooser<actual_stride>::template Iterator<N, value_type, reference, pointer>::type
2541 // iterator;
2542
2543 // /** sequential (random access) const iterator type
2544 // */
2545 // typedef typename vigra::detail::MultiIteratorChooser<actual_stride>::template Iterator<N, value_type, const_reference, const_pointer>::type
2546 // const_iterator;
2547
2548 /** sequential (random access) iterator type
2549 */
2551
2552 /** sequential (random access) const iterator type
2553 */
2555
2556protected:
2557
2558 typedef typename difference_type::value_type diff_zero_t;
2559
2560 /** the allocator used to allocate the memory
2561 */
2563
2564 /** allocate memory for s pixels, write its address into the given
2565 pointer and initialize the pixels with init.
2566 */
2568
2569 /** allocate memory for s pixels, write its address into the given
2570 pointer and initialize the linearized pixels to the values of init.
2571 */
2572 template <class U>
2573 void allocate (pointer &ptr, difference_type_1 s, U const * init);
2574
2575 /** allocate memory, write its address into the given
2576 pointer and initialize it by copying the data from the given MultiArrayView.
2577 */
2578 template <class U, class StrideTag>
2580
2581 /** deallocate the memory (of length s) starting at the given address.
2582 */
2584
2585 template <class U, class StrideTag>
2586 void copyOrReshape (const MultiArrayView<N, U, StrideTag> &rhs);
2587public:
2588 /** default constructor
2589 */
2591 : view_type (difference_type (diff_zero_t(0)),
2592 difference_type (diff_zero_t(0)), 0)
2593 {}
2594
2595 /** construct with given allocator
2596 */
2598 : view_type(difference_type (diff_zero_t(0)),
2599 difference_type (diff_zero_t(0)), 0),
2600 m_alloc(alloc)
2601 {}
2602
2603 /** construct with given length
2604
2605 Use only for 1-dimensional arrays (<tt>N==1</tt>).
2606 */
2608 allocator_type const & alloc = allocator_type());
2609
2610
2611 /** construct with given width and height
2612
2613 Use only for 2-dimensional arrays (<tt>N==2</tt>).
2614 */
2616 allocator_type const & alloc = allocator_type());
2617
2618 /** construct with given shape
2619 */
2621 allocator_type const & alloc = allocator_type());
2622
2623 /** construct from shape with an initial value
2624 */
2626 allocator_type const & alloc = allocator_type());
2627
2628 /** construct from shape and initialize with a linear sequence in scan order
2629 (i.e. first pixel gets value 0, second on gets value 1 and so on).
2630 */
2632 allocator_type const & alloc = allocator_type());
2633
2634 /** construct from shape and copy values from the given array
2635 */
2637 allocator_type const & alloc = allocator_type());
2638
2639 /** copy constructor
2640 */
2642 : view_type(rhs.m_shape, rhs.m_stride, 0),
2643 m_alloc (rhs.m_alloc)
2644 {
2645 allocate (this->m_ptr, this->elementCount (), rhs.data ());
2646 }
2647
2648 /** constructor from an array expression
2649 */
2650 template<class Expression>
2651 MultiArray (multi_math::MultiMathOperand<Expression> const & rhs,
2652 allocator_type const & alloc = allocator_type())
2653 : view_type(difference_type (diff_zero_t(0)),
2654 difference_type (diff_zero_t(0)), 0),
2655 m_alloc (alloc)
2656 {
2657 multi_math::math_detail::assignOrResize(*this, rhs);
2658 }
2659
2660 /** construct by copying from a MultiArrayView
2661 */
2662 template <class U, class StrideTag>
2664 allocator_type const & alloc = allocator_type());
2665
2666 /** assignment.<br>
2667 If the size of \a rhs is the same as the left-hand side arrays's old size, only
2668 the data are copied. Otherwise, new storage is allocated, which invalidates all
2669 objects (array views, iterators) depending on the lhs array.
2670 */
2672 {
2673 if (this != &rhs)
2674 this->copyOrReshape(rhs);
2675 return *this;
2676 }
2677
2678 /** assignment from arbitrary MultiArrayView.<br>
2679 If the size of \a rhs is the same as the left-hand side arrays's old size, only
2680 the data are copied. Otherwise, new storage is allocated, which invalidates all
2681 objects (array views, iterators) depending on the lhs array.
2682 */
2683 template <class U, class StrideTag>
2685 {
2686 this->copyOrReshape(rhs);
2687 return *this;
2688 }
2689
2690 /** assignment from scalar.<br>
2691 Equivalent to MultiArray::init(v).
2692 */
2694 {
2695 return this->init(v);
2696 }
2697
2698 /** Add-assignment from arbitrary MultiArrayView. Fails with
2699 <tt>PreconditionViolation</tt> exception when the shapes do not match.
2700 If the left array has no data (hasData() is false), this function is
2701 equivalent to a normal assignment (i.e. an empty
2702 array is interpreted as a zero-array of appropriate size).
2703 */
2704 template <class U, class StrideTag>
2706 {
2707 if(this->hasData())
2709 else
2710 *this = rhs;
2711 return *this;
2712 }
2713
2714 /** Subtract-assignment from arbitrary MultiArrayView. Fails with
2715 <tt>PreconditionViolation</tt> exception when the shapes do not match.
2716 If the left array has no data (hasData() is false), this function is
2717 equivalent to an assignment of the negated rhs (i.e. an empty
2718 array is interpreted as a zero-array of appropriate size).
2719 */
2720 template <class U, class StrideTag>
2722 {
2723 if(!this->hasData())
2724 this->reshape(rhs.shape());
2726 return *this;
2727 }
2728
2729 /** Multiply-assignment from arbitrary MultiArrayView. Fails with
2730 <tt>PreconditionViolation</tt> exception when the shapes do not match.
2731 If the left array has no data (hasData() is false), this function is
2732 equivalent to reshape(rhs.shape()) with zero initialisation (i.e. an empty
2733 array is interpreted as a zero-array of appropriate size).
2734 */
2735 template <class U, class StrideTag>
2737 {
2738 if(this->hasData())
2740 else
2741 this->reshape(rhs.shape());
2742 return *this;
2743 }
2744
2745 /** Divide-assignment from arbitrary MultiArrayView. Fails with
2746 <tt>PreconditionViolation</tt> exception when the shapes do not match.
2747 If the left array has no data (hasData() is false), this function is
2748 equivalent to reshape(rhs.shape()) with zero initialisation (i.e. an empty
2749 array is interpreted as a zero-array of appropriate size).
2750 */
2751 template <class U, class StrideTag>
2753 {
2754 if(this->hasData())
2756 else
2757 this->reshape(rhs.shape());
2758 return *this;
2759 }
2760
2761 /** Add-assignment of a scalar.
2762 */
2764 {
2766 return *this;
2767 }
2768
2769 /** Subtract-assignment of a scalar.
2770 */
2772 {
2774 return *this;
2775 }
2776
2777 /** Multiply-assignment of a scalar.
2778 */
2780 {
2782 return *this;
2783 }
2784
2785 /** Divide-assignment of a scalar.
2786 */
2788 {
2790 return *this;
2791 }
2792 /** Assignment of an array expression. Fails with
2793 <tt>PreconditionViolation</tt> exception when the shapes do not match.
2794 */
2795 template<class Expression>
2796 MultiArray & operator=(multi_math::MultiMathOperand<Expression> const & rhs)
2797 {
2798 multi_math::math_detail::assignOrResize(*this, rhs);
2799 return *this;
2800 }
2801
2802 /** Add-assignment of an array expression. Fails with
2803 <tt>PreconditionViolation</tt> exception when the shapes do not match.
2804 */
2805 template<class Expression>
2806 MultiArray & operator+=(multi_math::MultiMathOperand<Expression> const & rhs)
2807 {
2808 multi_math::math_detail::plusAssignOrResize(*this, rhs);
2809 return *this;
2810 }
2811
2812 /** Subtract-assignment of an array expression. Fails with
2813 <tt>PreconditionViolation</tt> exception when the shapes do not match.
2814 */
2815 template<class Expression>
2816 MultiArray & operator-=(multi_math::MultiMathOperand<Expression> const & rhs)
2817 {
2818 multi_math::math_detail::minusAssignOrResize(*this, rhs);
2819 return *this;
2820 }
2821
2822 /** Multiply-assignment of an array expression. Fails with
2823 <tt>PreconditionViolation</tt> exception when the shapes do not match.
2824 */
2825 template<class Expression>
2826 MultiArray & operator*=(multi_math::MultiMathOperand<Expression> const & rhs)
2827 {
2828 multi_math::math_detail::multiplyAssignOrResize(*this, rhs);
2829 return *this;
2830 }
2831
2832 /** Divide-assignment of an array expression. Fails with
2833 <tt>PreconditionViolation</tt> exception when the shapes do not match.
2834 */
2835 template<class Expression>
2836 MultiArray & operator/=(multi_math::MultiMathOperand<Expression> const & rhs)
2837 {
2838 multi_math::math_detail::divideAssignOrResize(*this, rhs);
2839 return *this;
2840 }
2841
2842 /** destructor
2843 */
2845 {
2846 deallocate (this->m_ptr, this->elementCount ());
2847 }
2848
2849
2850 /** init elements with a constant
2851 */
2852 template <class U>
2853 MultiArray & init(const U & init)
2854 {
2856 return *this;
2857 }
2858
2859 /** Allocate new memory with the given shape and initialize with zeros.<br>
2860 <em>Note:</em> this operation invalidates all dependent objects
2861 (array views and iterators)
2862 */
2864 {
2866 }
2867
2868 /** Allocate new memory with the given shape and initialize it
2869 with the given value.<br>
2870 <em>Note:</em> this operation invalidates all dependent objects
2871 (array views and iterators)
2872 */
2874
2875 /** Swap the contents with another MultiArray. This is fast,
2876 because no data are copied, but only pointers and shapes swapped.
2877 <em>Note:</em> this operation invalidates all dependent objects
2878 (array views and iterators)
2879 */
2880 void swap (MultiArray & other);
2881
2882 // /** sequential iterator pointing to the first array element.
2883 // */
2884 // iterator begin ()
2885 // {
2886 // return vigra::detail::MultiIteratorChooser<actual_stride>::template constructIterator<iterator>((view_type *)this);
2887 // }
2888
2889 // /** sequential iterator pointing beyond the last array element.
2890 // */
2891 // iterator end ()
2892 // {
2893 // return begin() + this->elementCount();
2894 // }
2895
2896 // /** sequential const iterator pointing to the first array element.
2897 // */
2898 // const_iterator begin () const
2899 // {
2900 // return vigra::detail::MultiIteratorChooser<actual_stride>::template constructIterator<iterator>((view_type const *)this);
2901 // }
2902
2903 // /** sequential const iterator pointing beyond the last array element.
2904 // */
2905 // const_iterator end () const
2906 // {
2907 // return begin() + this->elementCount();
2908 // }
2909
2910 /** get the allocator.
2911 */
2912 allocator_type const & allocator () const
2913 {
2914 return m_alloc;
2915 }
2916
2917 static difference_type defaultStride(difference_type const & shape)
2918 {
2919 return vigra::detail::ResolveMultiband<T>::defaultStride(shape);
2920 }
2921};
2922
2923template <unsigned int N, class T, class A>
2925 allocator_type const & alloc)
2926: view_type(difference_type(length),
2927 defaultStride(difference_type(length)),
2928 0),
2929 m_alloc(alloc)
2930{
2931 allocate (this->m_ptr, this->elementCount (), value_type());
2932}
2933
2934template <unsigned int N, class T, class A>
2936 allocator_type const & alloc)
2938 defaultStride(difference_type(width, height)),
2939 0),
2940 m_alloc(alloc)
2941{
2942 allocate (this->m_ptr, this->elementCount (), value_type());
2943}
2944
2945template <unsigned int N, class T, class A>
2947 allocator_type const & alloc)
2949 defaultStride(shape),
2950 0),
2951 m_alloc(alloc)
2952{
2953 if (N == 0)
2954 {
2955 this->m_shape [0] = 1;
2956 this->m_stride [0] = 1;
2957 }
2958 allocate (this->m_ptr, this->elementCount (), value_type());
2959}
2960
2961template <unsigned int N, class T, class A>
2963 allocator_type const & alloc)
2965 defaultStride(shape),
2966 0),
2967 m_alloc(alloc)
2968{
2969 if (N == 0)
2970 {
2971 this->m_shape [0] = 1;
2972 this->m_stride [0] = 1;
2973 }
2974 allocate (this->m_ptr, this->elementCount (), init);
2975}
2976
2977template <unsigned int N, class T, class A>
2979 allocator_type const & alloc)
2981 defaultStride(shape),
2982 0),
2983 m_alloc(alloc)
2984{
2985 if (N == 0)
2986 {
2987 this->m_shape [0] = 1;
2988 this->m_stride [0] = 1;
2989 }
2990 allocate (this->m_ptr, this->elementCount (), value_type());
2991 switch(init)
2992 {
2993 case LinearSequence:
2994 linearSequence(this->begin(), this->end());
2995 break;
2996 default:
2997 vigra_precondition(false,
2998 "MultiArray(): invalid MultiArrayInitializationTag.");
2999 }
3000}
3001
3002template <unsigned int N, class T, class A>
3004 allocator_type const & alloc)
3006 defaultStride(shape),
3007 0),
3008 m_alloc(alloc)
3009{
3010 if (N == 0)
3011 {
3012 this->m_shape [0] = 1;
3013 this->m_stride [0] = 1;
3014 }
3015 allocate (this->m_ptr, this->elementCount (), init);
3016}
3017
3018template <unsigned int N, class T, class A>
3019template <class U, class StrideTag>
3021 allocator_type const & alloc)
3022: view_type(rhs.shape(),
3023 defaultStride(rhs.shape()),
3024 0),
3025 m_alloc (alloc)
3026{
3027 allocate (this->m_ptr, rhs);
3028}
3029
3030template <unsigned int N, class T, class A>
3031template <class U, class StrideTag>
3032void
3033MultiArray <N, T, A>::copyOrReshape(const MultiArrayView<N, U, StrideTag> &rhs)
3034{
3035 if (this->shape() == rhs.shape())
3036 this->copy(rhs);
3037 else
3038 {
3039 MultiArray t(rhs);
3040 this->swap(t);
3041 }
3042}
3043
3044template <unsigned int N, class T, class A>
3046 const_reference initial)
3047{
3048 if (N == 0)
3049 {
3050 return;
3051 }
3052 else if(new_shape == this->shape())
3053 {
3054 this->init(initial);
3055 }
3056 else
3057 {
3058 difference_type new_stride = defaultStride(new_shape);
3059 difference_type_1 new_size = prod(new_shape);
3060 pointer new_ptr = pointer();
3061 allocate (new_ptr, new_size, initial);
3062 deallocate (this->m_ptr, this->elementCount ());
3063 this->m_ptr = new_ptr;
3064 this->m_shape = new_shape;
3065 this->m_stride = new_stride;
3066 }
3067}
3068
3069
3070template <unsigned int N, class T, class A>
3071inline void
3073{
3074 if (this == &other)
3075 return;
3076 this->view_type::swap(other);
3077 std::swap(this->m_alloc, other.m_alloc);
3078}
3079
3080template <unsigned int N, class T, class A>
3083{
3084 if(s == 0)
3085 {
3086 ptr = 0;
3087 return;
3088 }
3089 ptr = m_alloc.allocate ((typename A::size_type)s);
3090 difference_type_1 i = 0;
3091 try {
3092 for (; i < s; ++i)
3093 std::allocator_traits<allocator_type>::construct (m_alloc, ptr + i, init);
3094 }
3095 catch (...) {
3096 for (difference_type_1 j = 0; j < i; ++j)
3097 std::allocator_traits<allocator_type>::destroy (m_alloc, ptr + j);
3098 m_alloc.deallocate (ptr, (typename A::size_type)s);
3099 throw;
3100 }
3101}
3102
3103template <unsigned int N, class T, class A>
3104template <class U>
3106 U const * init)
3107{
3108 if(s == 0)
3109 {
3110 ptr = 0;
3111 return;
3112 }
3113 ptr = m_alloc.allocate ((typename A::size_type)s);
3114 difference_type_1 i = 0;
3115 try {
3116 for (; i < s; ++i, ++init)
3117 std::allocator_traits<allocator_type>::construct(m_alloc, ptr + i, *init);
3118 }
3119 catch (...) {
3120 for (difference_type_1 j = 0; j < i; ++j)
3121 std::allocator_traits<allocator_type>::destroy (m_alloc, ptr + j);
3122 m_alloc.deallocate (ptr, (typename A::size_type)s);
3123 throw;
3124 }
3125}
3126
3127template <unsigned int N, class T, class A>
3128template <class U, class StrideTag>
3130{
3131 difference_type_1 s = init.elementCount();
3132 if(s == 0)
3133 {
3134 ptr = 0;
3135 return;
3136 }
3137 ptr = m_alloc.allocate ((typename A::size_type)s);
3138 pointer p = ptr;
3139 try {
3140 detail::uninitializedCopyMultiArrayData(init.traverser_begin(), init.shape(),
3141 p, m_alloc, MetaInt<actual_dimension-1>());
3142 }
3143 catch (...) {
3144 for (pointer pp = ptr; pp < p; ++pp)
3145 std::allocator_traits<allocator_type>::destroy (m_alloc, pp);
3146 m_alloc.deallocate (ptr, (typename A::size_type)s);
3147 throw;
3148 }
3149}
3150
3151template <unsigned int N, class T, class A>
3153{
3154 if (ptr == 0)
3155 return;
3156 for (difference_type_1 i = 0; i < s; ++i)
3157 std::allocator_traits<allocator_type>::destroy (m_alloc, ptr + i);
3158 m_alloc.deallocate (ptr, (typename A::size_type)s);
3159 ptr = 0;
3160}
3161
3162/********************************************************/
3163/* */
3164/* argument object factories */
3165/* */
3166/********************************************************/
3167
3168template <unsigned int N, class T, class StrideTag>
3169inline triple<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3171 typename AccessorTraits<T>::default_const_accessor >
3172srcMultiArrayRange( MultiArrayView<N,T,StrideTag> const & array )
3173{
3174 return triple<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3176 typename AccessorTraits<T>::default_const_accessor >
3177 ( array.traverser_begin(),
3178 array.shape(),
3179 typename AccessorTraits<T>::default_const_accessor() );
3180}
3181
3182template <unsigned int N, class T, class StrideTag, class Accessor>
3183inline triple<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3185 Accessor >
3186srcMultiArrayRange( MultiArrayView<N,T,StrideTag> const & array, Accessor a )
3187{
3188 return triple<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3190 Accessor >
3191 ( array.traverser_begin(),
3192 array.shape(),
3193 a);
3194}
3195
3196template <unsigned int N, class T, class StrideTag>
3197inline pair<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3198 typename AccessorTraits<T>::default_const_accessor >
3199srcMultiArray( MultiArrayView<N,T,StrideTag> const & array )
3200{
3201 return pair<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3202 typename AccessorTraits<T>::default_const_accessor >
3203 ( array.traverser_begin(),
3204 typename AccessorTraits<T>::default_const_accessor() );
3205}
3206
3207template <unsigned int N, class T, class StrideTag, class Accessor>
3208inline pair<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3209 Accessor >
3210srcMultiArray( MultiArrayView<N,T,StrideTag> const & array, Accessor a )
3211{
3212 return pair<typename MultiArrayView<N,T,StrideTag>::const_traverser,
3213 Accessor >
3214 ( array.traverser_begin(), a );
3215}
3216
3217template <unsigned int N, class T, class StrideTag>
3218inline triple<typename MultiArrayView<N,T,StrideTag>::traverser,
3220 typename AccessorTraits<T>::default_accessor >
3221destMultiArrayRange( MultiArrayView<N,T,StrideTag> & array )
3222{
3223 return triple<typename MultiArrayView<N,T,StrideTag>::traverser,
3225 typename AccessorTraits<T>::default_accessor >
3226 ( array.traverser_begin(),
3227 array.shape(),
3228 typename AccessorTraits<T>::default_accessor() );
3229}
3230
3231template <unsigned int N, class T, class StrideTag, class Accessor>
3232inline triple<typename MultiArrayView<N,T,StrideTag>::traverser,
3234 Accessor >
3235destMultiArrayRange( MultiArrayView<N,T,StrideTag> & array, Accessor a )
3236{
3237 return triple<typename MultiArrayView<N,T,StrideTag>::traverser,
3239 Accessor >
3240 ( array.traverser_begin(),
3241 array.shape(),
3242 a );
3243}
3244
3245template <unsigned int N, class T, class StrideTag>
3246inline pair<typename MultiArrayView<N,T,StrideTag>::traverser,
3247 typename AccessorTraits<T>::default_accessor >
3248destMultiArray( MultiArrayView<N,T,StrideTag> & array )
3249{
3250 return pair<typename MultiArrayView<N,T,StrideTag>::traverser,
3251 typename AccessorTraits<T>::default_accessor >
3252 ( array.traverser_begin(),
3253 typename AccessorTraits<T>::default_accessor() );
3254}
3255
3256template <unsigned int N, class T, class StrideTag, class Accessor>
3257inline pair<typename MultiArrayView<N,T,StrideTag>::traverser,
3258 Accessor >
3259destMultiArray( MultiArrayView<N,T,StrideTag> & array, Accessor a )
3260{
3261 return pair<typename MultiArrayView<N,T,StrideTag>::traverser,
3262 Accessor >
3263 ( array.traverser_begin(), a );
3264}
3265
3266/********************************************************************/
3267
3268template <class PixelType, class Accessor>
3269inline triple<ConstStridedImageIterator<PixelType>,
3271srcImageRange(const MultiArrayView<2, PixelType, StridedArrayTag> & img, Accessor a)
3272{
3274 ul(img.data(), 1, img.stride(0), img.stride(1));
3275 return triple<ConstStridedImageIterator<PixelType>,
3277 Accessor>(
3278 ul, ul + Size2D(img.shape(0), img.shape(1)), a);
3279}
3280
3281template <class PixelType, class Accessor>
3282inline pair<ConstStridedImageIterator<PixelType>, Accessor>
3284{
3286 ul(img.data(), 1, img.stride(0), img.stride(1));
3287 return pair<ConstStridedImageIterator<PixelType>, Accessor>
3288 (ul, a);
3289}
3290
3291template <class PixelType, class Accessor>
3292inline triple<StridedImageIterator<PixelType>,
3295{
3297 ul(img.data(), 1, img.stride(0), img.stride(1));
3298 return triple<StridedImageIterator<PixelType>,
3300 Accessor>(
3301 ul, ul + Size2D(img.shape(0), img.shape(1)), a);
3302}
3303
3304template <class PixelType, class Accessor>
3305inline pair<StridedImageIterator<PixelType>, Accessor>
3307{
3309 ul(img.data(), 1, img.stride(0), img.stride(1));
3310 return pair<StridedImageIterator<PixelType>, Accessor>
3311 (ul, a);
3312}
3313
3314template <class PixelType, class Accessor>
3315inline pair<StridedImageIterator<PixelType>, Accessor>
3317{
3319 ul(img.data(), 1, img.stride(0), img.stride(1));
3320 return pair<StridedImageIterator<PixelType>, Accessor>
3321 (ul, a);
3322}
3323
3324// -------------------------------------------------------------------
3325
3326template <class PixelType>
3327inline triple<ConstStridedImageIterator<PixelType>,
3329 typename AccessorTraits<PixelType>::default_const_accessor>
3330srcImageRange(MultiArrayView<2, PixelType, StridedArrayTag> const & img)
3331{
3333 ul(img.data(), 1, img.stride(0), img.stride(1));
3334 typedef typename AccessorTraits<PixelType>::default_const_accessor Accessor;
3335 return triple<ConstStridedImageIterator<PixelType>,
3337 Accessor>
3338 (ul, ul + Size2D(img.shape(0), img.shape(1)), Accessor());
3339}
3340
3341template <class PixelType>
3342inline triple<ConstImageIterator<PixelType>,
3344 typename AccessorTraits<PixelType>::default_const_accessor>
3345srcImageRange(MultiArrayView<2, PixelType, UnstridedArrayTag> const & img)
3346{
3348 ul(img.data(), img.stride(1));
3349 typedef typename AccessorTraits<PixelType>::default_const_accessor Accessor;
3350 return triple<ConstImageIterator<PixelType>,
3352 Accessor>
3353 (ul, ul + Size2D(img.shape(0), img.shape(1)), Accessor());
3354}
3355
3356template <class PixelType>
3357inline pair< ConstStridedImageIterator<PixelType>,
3358 typename AccessorTraits<PixelType>::default_const_accessor>
3360{
3362 ul(img.data(), 1, img.stride(0), img.stride(1));
3363 typedef typename AccessorTraits<PixelType>::default_const_accessor Accessor;
3364 return pair<ConstStridedImageIterator<PixelType>,
3365 Accessor>
3366 (ul, Accessor());
3367}
3368
3369template <class PixelType>
3370inline pair< ConstImageIterator<PixelType>,
3371 typename AccessorTraits<PixelType>::default_const_accessor>
3373{
3375 ul(img.data(), img.stride(1));
3376 typedef typename AccessorTraits<PixelType>::default_const_accessor Accessor;
3377 return pair<ConstImageIterator<PixelType>,
3378 Accessor>
3379 (ul, Accessor());
3380}
3381
3382template <class PixelType>
3383inline triple< StridedImageIterator<PixelType>,
3385 typename AccessorTraits<PixelType>::default_accessor>
3387{
3389 ul(img.data(), 1, img.stride(0), img.stride(1));
3390 typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
3391 return triple<StridedImageIterator<PixelType>,
3393 Accessor>
3394 (ul, ul + Size2D(img.shape(0), img.shape(1)), Accessor());
3395}
3396
3397template <class PixelType>
3398inline triple< ImageIterator<PixelType>,
3400 typename AccessorTraits<PixelType>::default_accessor>
3402{
3404 ul(img.data(), img.stride(1));
3405 typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
3406 return triple<ImageIterator<PixelType>,
3408 Accessor>
3409 (ul, ul + Size2D(img.shape(0), img.shape(1)), Accessor());
3410}
3411
3412template <class PixelType>
3413inline pair< StridedImageIterator<PixelType>,
3414 typename AccessorTraits<PixelType>::default_accessor>
3416{
3418 ul(img.data(), 1, img.stride(0), img.stride(1));
3419 typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
3420 return pair<StridedImageIterator<PixelType>, Accessor>
3421 (ul, Accessor());
3422}
3423
3424template <class PixelType>
3425inline pair< ImageIterator<PixelType>,
3426 typename AccessorTraits<PixelType>::default_accessor>
3428{
3429 ImageIterator<PixelType> ul(img.data(), img.stride(1));
3430 typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
3431 return pair<ImageIterator<PixelType>, Accessor>(ul, Accessor());
3432}
3433
3434template <class PixelType>
3435inline pair< ConstStridedImageIterator<PixelType>,
3436 typename AccessorTraits<PixelType>::default_accessor>
3438{
3440 ul(img.data(), 1, img.stride(0), img.stride(1));
3441 typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
3442 return pair<ConstStridedImageIterator<PixelType>, Accessor>
3443 (ul, Accessor());
3444}
3445
3446template <class PixelType>
3447inline pair< ConstImageIterator<PixelType>,
3448 typename AccessorTraits<PixelType>::default_accessor>
3450{
3452 ul(img.data(), img.stride(1));
3453 typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
3454 return pair<ConstImageIterator<PixelType>, Accessor>
3455 (ul, Accessor());
3456}
3457
3458/********************************************************/
3459/* */
3460/* makeBasicImageView */
3461/* */
3462/********************************************************/
3463
3464/** \addtogroup MultiArrayToImage Create BasicImageView from MultiArrayViews
3465
3466 Some convenience functions for wrapping a \ref vigra::MultiArrayView's
3467 data in a \ref vigra::BasicImageView.
3468*/
3469//@{
3470/** Create a \ref vigra::BasicImageView from an unstrided 2-dimensional
3471 \ref vigra::MultiArrayView.
3472
3473 The \ref vigra::BasicImageView will have the same <tt>value_type </tt>
3474 as the original \ref vigra::MultiArrayView.
3475*/
3476template <class T, class Stride>
3477BasicImageView <T>
3478makeBasicImageView (MultiArrayView <2, T, Stride> const &array)
3479{
3480 vigra_precondition(array.isUnstrided(0),
3481 "makeBasicImageView(array): array must be unstrided along x (i.e. array.isUnstrided(0) == true).");
3482 return BasicImageView <T> (array.data (), array.shape (0),
3483 array.shape (1), array.stride(1));
3484}
3485
3486/** Create a \ref vigra::BasicImageView from a 3-dimensional
3487 \ref vigra::MultiArray.
3488
3489 This wrapper flattens the two innermost dimensions of the array
3490 into single rows of the resulting image.
3491 The \ref vigra::BasicImageView will have the same <tt>value_type </tt>
3492 as the original \ref vigra::MultiArray.
3493*/
3494template <class T>
3495BasicImageView <T>
3496makeBasicImageView (MultiArray <3, T> const &array)
3497{
3498 vigra_precondition(array.stride(1) == array.shape(0),
3499 "makeBasicImageView(): cannot join strided dimensions");
3500 return BasicImageView <T> (array.data (),
3501 array.shape (0)*array.shape (1), array.shape (2), array.stride(2));
3502}
3503
3504/** Create a \ref vigra::BasicImageView from a 3-dimensional
3505 \ref vigra::MultiArray.
3506
3507 This wrapper only works if <tt>T</tt> is a scalar type and the
3508 array's innermost dimension has size 3. It then re-interprets
3509 the data array as a 2-dimensional array with value_type
3510 <tt>RGBValue<T></tt>.
3511*/
3512template <class T, class Stride>
3513BasicImageView <RGBValue<T> >
3515{
3516 vigra_precondition(array.shape (0) == 3,
3517 "makeRGBImageView(): array.shape(0) must be 3.");
3518 vigra_precondition(array.isUnstrided(),
3519 "makeRGBImageView(array): array must be unstrided (i.e. array.isUnstrided() == true).");
3520 return BasicImageView <RGBValue<T> > (
3521 reinterpret_cast <RGBValue <T> *> (array.data ()),
3522 array.shape (1), array.shape (2));
3523}
3524
3525//@}
3526
3527} // namespace vigra
3528
3529#undef VIGRA_ASSERT_INSIDE
3530
3531#endif // VIGRA_MULTI_ARRAY_HXX
Fundamental class template for images.
Definition basicimage.hxx:476
Standard 2D random access const iterator for images that store the data as a linear array.
Definition imageiterator.hxx:896
Const iterator to be used when pixels are to be skipped.
Definition imageiterator.hxx:1030
Wrapper class for the FFTW complex types 'fftw_complex'.
Definition fftw3.hxx:132
Find the sum of the pixel values in an image or ROI.
Definition inspectimage.hxx:1145
Standard 2D random access iterator for images that store the data in a linear array.
Definition imageiterator.hxx:851
TinyVector< MultiArrayIndex, N > type
Definition multi_shape.hxx:272
Base class for, and view to, MultiArray.
Definition multi_array.hxx:705
difference_type strideOrdering() const
Definition multi_array.hxx:1619
vigra::detail::MultiIteratorChooser< Stride >::template Traverser< actual_dimension, T, Tconst &, Tconst * >::type const_traverser
Definition multi_array.hxx:769
MultiArrayView< N-1, T, StridedArrayTag > bindAt(difference_type_1 m, difference_type_1 d) const
Definition multi_array.hxx:2298
MultiArrayView< N, T, StridedArrayTag > transpose(const difference_type &permutation) const
Definition multi_array.hxx:1595
MultiArrayView< 1, T, StridedArrayTag > diagonal() const
Definition multi_array.hxx:1506
MultiArrayView & operator/=(T const &rhs)
Definition multi_array.hxx:993
MultiArrayView< N, T, Stride > view_type
Definition multi_array.hxx:773
const value_type * const_pointer
Definition multi_array.hxx:735
const_reference operator[](difference_type_1 d) const
Definition multi_array.hxx:1099
NormTraits< MultiArrayView >::SquaredNormType squaredNorm() const
Definition multi_array.hxx:1871
MultiArrayIndex difference_type_1
Definition multi_array.hxx:751
void swapData(MultiArrayView rhs)
Definition multi_array.hxx:1266
MultiArrayView(MultiArrayView const &rhs)=default
void sum(MultiArrayView< N, U, S > sums) const
Definition multi_array.hxx:1841
T value_type
Definition multi_array.hxx:719
difference_type_1 size(difference_type_1 n) const
Definition multi_array.hxx:1657
difference_type_1 coordinateToScanOrderIndex(const difference_type &d) const
Definition multi_array.hxx:1116
const_iterator begin() const
Definition multi_array.hxx:1931
MultiArrayView< N, T, StridedArrayTag > permuteStridesAscending() const
Definition multi_array.hxx:2165
MultiArrayView subarray(difference_type p, difference_type q) const
Definition multi_array.hxx:1530
bool hasData() const
Definition multi_array.hxx:1915
const_traverser traverser_begin() const
Definition multi_array.hxx:1964
NormTraits< MultiArrayView >::NormType norm(int type=2, bool useSquaredNorm=true) const
Definition multi_array.hxx:2374
void swapData(MultiArrayView< N, T2, C2 > rhs)
Definition multi_array.hxx:1277
MultiArrayView & operator-=(MultiArrayView< N, U, C1 > const &rhs)
difference_type_1 stride(int n) const
Definition multi_array.hxx:1693
difference_type scanOrderIndexToCoordinate(difference_type_1 d) const
Definition multi_array.hxx:1107
MultiArrayView< N+1, typename ExpandElementResult< T >::type, StridedArrayTag > expandElements(difference_type_1 d) const
Definition multi_array.hxx:2327
MultiArrayView< N-1, T, typename vigra::detail::MaybeStrided< StrideTag, M >::type > bind(difference_type_1 d) const
MultiArrayView< N-1, T, StridedArrayTag > bindInner(difference_type_1 d) const
Definition multi_array.hxx:2278
bool isInside(difference_type const &p) const
Definition multi_array.hxx:1719
bool operator!=(MultiArrayView< N, U, C1 > const &rhs) const
Definition multi_array.hxx:1712
MultiArrayView< N+1, T, StrideTag > insertSingletonDimension(difference_type_1 i) const
Definition multi_array.hxx:2356
MultiArrayView(const difference_type &shape, const_pointer ptr)
Definition multi_array.hxx:849
traverser traverser_begin()
Definition multi_array.hxx:1955
const difference_type & shape() const
Definition multi_array.hxx:1650
difference_type m_shape
Definition multi_array.hxx:795
MultiArrayView< N, T, StridedArrayTag > stridearray(const difference_type &s) const
Definition multi_array.hxx:1545
MultiArrayView & operator/=(MultiArrayView< N, U, C1 > const &rhs)
static difference_type strideOrdering(difference_type strides)
Definition multi_array.hxx:2138
MultiArrayView & operator+=(MultiArrayView< N, U, C1 > const &rhs)
MultiArrayView(const MultiArrayView< N, T, Stride > &other)
Definition multi_array.hxx:838
pointer m_ptr
Definition multi_array.hxx:804
MultiArrayView & operator=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition multi_array.hxx:1003
StridedScanOrderIterator< actual_dimension, T, T const &, T const * > const_iterator
Definition multi_array.hxx:759
MultiArrayView & operator-=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition multi_array.hxx:1023
MultiArrayView & init(const U &init)
Definition multi_array.hxx:1208
bool all() const
Definition multi_array.hxx:1739
MultiArrayView< N-M, T, StrideTag > bindOuter(const TinyVector< Index, M > &d) const
Definition multi_array.hxx:2186
bool isOutside(difference_type const &p) const
Definition multi_array.hxx:1728
MultiArrayShape< actual_dimension >::type difference_type
Definition multi_array.hxx:739
traverser traverser_end()
Definition multi_array.hxx:1974
reference operator()(difference_type_1 x)
Definition multi_array.hxx:1123
MultiArrayView & operator+=(T const &rhs)
Definition multi_array.hxx:969
void copy(const MultiArrayView &rhs)
Definition multi_array.hxx:1218
void copy(const MultiArrayView< N, U, CN > &rhs)
Definition multi_array.hxx:1228
MultiArrayView & operator*=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition multi_array.hxx:1033
difference_type_1 width() const
Definition multi_array.hxx:1672
const_traverser traverser_end() const
Definition multi_array.hxx:1985
difference_type_1 shape(difference_type_1 n) const
Definition multi_array.hxx:1665
reference operator[](difference_type_1 d)
Definition multi_array.hxx:1083
MultiArrayView & operator-=(T const &rhs)
Definition multi_array.hxx:977
void minmax(T *minimum, T *maximum) const
Definition multi_array.hxx:1766
difference_type size_type
Definition multi_array.hxx:747
bool isUnstrided(unsigned int dimension=N-1) const
Definition multi_array.hxx:1288
MultiArrayView & operator*=(MultiArrayView< N, U, C1 > const &rhs)
MultiArrayView & operator/=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition multi_array.hxx:1043
difference_type key_type
Definition multi_array.hxx:743
MultiArrayView< N-M, T, StridedArrayTag > bindInner(const TinyVector< Index, M > &d) const
MultiArrayView & operator*=(T const &rhs)
Definition multi_array.hxx:985
MultiArrayView(const difference_type &shape, const difference_type &stride, const_pointer ptr)
Definition multi_array.hxx:860
bool operator==(MultiArrayView< N, U, C1 > const &rhs) const
Definition multi_array.hxx:1701
value_type & reference
Definition multi_array.hxx:723
MultiArrayView(BasicImage< T, ALLOC > const &image)
Definition multi_array.hxx:874
const difference_type & stride() const
Definition multi_array.hxx:1686
pointer data() const
Definition multi_array.hxx:1900
difference_type_1 elementCount() const
Definition multi_array.hxx:1632
void swap(MultiArrayView &other)
Definition multi_array.hxx:1253
MultiArrayView< N, T, StridedArrayTag > permuteStridesDescending() const
Definition multi_array.hxx:2175
iterator end()
Definition multi_array.hxx:1939
void meanVariance(U *mean, U *variance) const
Definition multi_array.hxx:1782
const_iterator end() const
Definition multi_array.hxx:1947
MultiArrayView()
Definition multi_array.hxx:829
difference_type m_stride
Definition multi_array.hxx:800
MultiArrayView< N-1, T, StrideTag > bindOuter(difference_type_1 d) const
Definition multi_array.hxx:2258
vigra::detail::MultiIteratorChooser< Stride >::template Traverser< actual_dimension, T, T &, T * >::type traverser
Definition multi_array.hxx:764
ActualDimension
Definition multi_array.hxx:715
void reset()
Definition multi_array.hxx:890
value_type * pointer
Definition multi_array.hxx:731
iterator begin()
Definition multi_array.hxx:1923
U product() const
Definition multi_array.hxx:1858
MultiArrayView< N, Multiband< value_type >, StrideTag > multiband() const
Definition multi_array.hxx:1485
difference_type_1 height() const
Definition multi_array.hxx:1679
MultiArrayView & operator=(MultiArrayView< N, U, C1 > const &rhs)
Definition multi_array.hxx:928
MultiArrayView< N, typename ExpandElementResult< T >::type, StridedArrayTag > bindElementChannel(difference_type_1 i) const
Definition multi_array.hxx:1417
MultiArray< N, T > matrix_type
Definition multi_array.hxx:777
bool any() const
Definition multi_array.hxx:1752
reference operator[](const difference_type &d)
Definition multi_array.hxx:1051
StridedScanOrderIterator< actual_dimension, T, T &, T * > iterator
Definition multi_array.hxx:755
U sum() const
Definition multi_array.hxx:1805
MultiArrayView & operator+=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition multi_array.hxx:1013
difference_type_1 size() const
Definition multi_array.hxx:1643
MultiArrayView< N, T, StridedArrayTag > transpose() const
Definition multi_array.hxx:1569
MultiArrayView & operator=(value_type const &v)
Definition multi_array.hxx:938
const value_type & const_reference
Definition multi_array.hxx:727
Main MultiArray class containing the memory management.
Definition multi_array.hxx:2479
MultiArray & operator*=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition multi_array.hxx:2826
view_type::const_traverser const_traverser
Definition multi_array.hxx:2536
view_type::const_reference const_reference
Definition multi_array.hxx:2516
allocator_type m_alloc
Definition multi_array.hxx:2562
MultiArray(multi_math::MultiMathOperand< Expression > const &rhs, allocator_type const &alloc=allocator_type())
Definition multi_array.hxx:2651
void allocate(pointer &ptr, difference_type_1 s, U const *init)
Definition multi_array.hxx:3105
void swap(MultiArray &other)
Definition multi_array.hxx:3072
MultiArray(const difference_type &shape, allocator_type const &alloc=allocator_type())
Definition multi_array.hxx:2946
view_type::size_type size_type
Definition multi_array.hxx:2520
void reshape(const difference_type &shape)
Definition multi_array.hxx:2863
MultiArray(const difference_type &shape, const_pointer init, allocator_type const &alloc=allocator_type())
Definition multi_array.hxx:3003
MultiArray & operator=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition multi_array.hxx:2796
MultiArray()
Definition multi_array.hxx:2590
MultiArray & operator+=(const MultiArrayView< N, U, StrideTag > &rhs)
Definition multi_array.hxx:2705
MultiArray(const difference_type &shape, MultiArrayInitializationTag init, allocator_type const &alloc=allocator_type())
Definition multi_array.hxx:2978
MultiArray(const MultiArray &rhs)
Definition multi_array.hxx:2641
allocator_type const & allocator() const
Definition multi_array.hxx:2912
MultiArrayView< N, typename vigra::detail::ResolveMultiband< T >::type, typename vigra::detail::ResolveMultiband< T >::Stride > view_type
Definition multi_array.hxx:2486
view_type::iterator iterator
Definition multi_array.hxx:2550
view_type::difference_type_1 difference_type_1
Definition multi_array.hxx:2528
view_type::const_pointer const_pointer
Definition multi_array.hxx:2508
MultiArray & operator/=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition multi_array.hxx:2836
view_type::difference_type difference_type
Definition multi_array.hxx:2524
MultiArray(allocator_type const &alloc)
Definition multi_array.hxx:2597
view_type::pointer pointer
Definition multi_array.hxx:2504
view_type::reference reference
Definition multi_array.hxx:2512
MultiArray & operator-=(const MultiArrayView< N, U, StrideTag > &rhs)
Definition multi_array.hxx:2721
A allocator_type
Definition multi_array.hxx:2492
MultiArray & init(const U &init)
Definition multi_array.hxx:2853
MultiArray(const MultiArrayView< N, U, StrideTag > &rhs, allocator_type const &alloc=allocator_type())
Definition multi_array.hxx:3020
void allocate(pointer &ptr, MultiArrayView< N, U, StrideTag > const &init)
Definition multi_array.hxx:3129
void allocate(pointer &ptr, difference_type_1 s, const_reference init)
Definition multi_array.hxx:3081
view_type::const_iterator const_iterator
Definition multi_array.hxx:2554
MultiArray & operator-=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition multi_array.hxx:2816
MultiArray(difference_type_1 length, allocator_type const &alloc=allocator_type())
Definition multi_array.hxx:2924
MultiArray & operator=(const MultiArray &rhs)
Definition multi_array.hxx:2671
MultiArray(const difference_type &shape, const_reference init, allocator_type const &alloc=allocator_type())
Definition multi_array.hxx:2962
MultiArray(difference_type_1 width, difference_type_1 height, allocator_type const &alloc=allocator_type())
Definition multi_array.hxx:2935
MultiArray< N, T, A > matrix_type
Definition multi_array.hxx:2496
view_type::traverser traverser
Definition multi_array.hxx:2532
void deallocate(pointer &ptr, difference_type_1 s)
Definition multi_array.hxx:3152
MultiArray & operator/=(const MultiArrayView< N, U, StrideTag > &rhs)
Definition multi_array.hxx:2752
view_type::value_type value_type
Definition multi_array.hxx:2500
void reshape(const difference_type &shape, const_reference init)
Definition multi_array.hxx:3045
~MultiArray()
Definition multi_array.hxx:2844
MultiArray & operator*=(const MultiArrayView< N, U, StrideTag > &rhs)
Definition multi_array.hxx:2736
MultiArray & operator+=(multi_math::MultiMathOperand< Expression > const &rhs)
Definition multi_array.hxx:2806
MultiArray & operator=(value_type const &v)
Definition multi_array.hxx:2693
Class for a single RGB value.
Definition rgbvalue.hxx:128
Two dimensional size object.
Definition diff2d.hxx:483
Iterator to be used when pixels are to be skipped.
Definition imageiterator.hxx:969
Sequential iterator for MultiArrayView.
Definition multi_iterator.hxx:273
void init(Iterator i, Iterator end)
Definition tinyvector.hxx:708
Class for fixed size vectors.
Definition tinyvector.hxx:1008
Definition fftw3.hxx:623
BasicImageView< T > makeBasicImageView(MultiArrayView< 2, T, Stride > const &array)
Definition multi_array.hxx:3478
MultiArrayInitializationTag
Initialize a MultiArray in a standard way.
Definition multi_fwd.hxx:104
@ LinearSequence
Initialize array by a linear sequence in scan order.
Definition multi_fwd.hxx:105
void linearSequence(Iterator first, Iterator last, Value start, Value step)
Fill an array with a sequence of numbers.
Definition algorithm.hxx:208
FFTWComplex< R >::NormType norm(const FFTWComplex< R > &a)
norm (= magnitude)
Definition fftw3.hxx:1037
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition fixedpoint.hxx:616
NumericTraits< V >::Promote sum(TinyVectorBase< V, SIZE, D1, D2 > const &l)
sum of the vector's elements
Definition tinyvector.hxx:2073
void transformMultiArray(...)
Transform a multi-dimensional array with a unary function or functor.
NumericTraits< V >::Promote prod(TinyVectorBase< V, SIZE, D1, D2 > const &l)
product of the vector's elements
Definition tinyvector.hxx:2097
FFTWComplex< R >::SquaredNormType squaredNorm(const FFTWComplex< R > &a)
squared norm (= squared magnitude)
Definition fftw3.hxx:1044
std::ptrdiff_t MultiArrayIndex
Definition multi_fwd.hxx:60
BasicImageView< RGBValue< T > > makeRGBImageView(MultiArrayView< 3, T, Stride > const &array)
Definition multi_array.hxx:3514
PromoteTraits< V1, V2 >::Promote dot(RGBValue< V1, RIDX1, GIDX1, BIDX1 > const &r1, RGBValue< V2, RIDX2, GIDX2, BIDX2 > const &r2)
dot product
Definition rgbvalue.hxx:906
Definition metaprogramming.hxx:116
Definition metaprogramming.hxx:123

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.12.1 (Thu Feb 27 2025)