vigra - vigra/numpy_array.hxx Source File

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

numpy_array.hxx |

1 /************************************************************************/
2 /* */
3 /* Copyright 2009 by Ullrich Koethe and Hans Meine */
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 #ifndef VIGRA_NUMPY_ARRAY_HXX
37 #define VIGRA_NUMPY_ARRAY_HXX
38
39 #ifndef NPY_NO_DEPRECATED_API
40 # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
41 #endif
42
43 #include <Python.h>
44 #include <string>
45 #include <iostream>
46 #include <numpy/arrayobject.h>
47 #include "multi_array.hxx"
48 #include "array_vector.hxx"
49 #include "python_utility.hxx"
50 #include "numpy_array_traits.hxx"
51 #include "numpy_array_taggedshape.hxx"
52
53 // NumPy function called by NumPy's import_array() macro (and our import_vigranumpy() below)
54 int _import_array();
55
56 namespace vigra {
57
58 static inline void import_vigranumpy()
59 {
60 // roughly equivalent to import_array():
61 if(_import_array() < 0)
62 pythonToCppException(0);
63
64 // Import vigra to activate the numpy array converters, but ensure that
65 // cyclic imports (from within vigra itself) are avoided.
66 char const * load_vigra =
67 "import sys\n"
68 "if 'vigra.vigranumpycore' not in sys.modules:\n"
69 " import vigra\n";
70 pythonToCppException(PyRun_SimpleString(load_vigra) == 0);
71 }
72
73 /********************************************************/
74 /* */
75 /* MultibandVectorAccessor */
76 /* */
77 /********************************************************/
78
79 template <class T>
80 class MultibandVectorAccessor
81 {
82 MultiArrayIndex size_, stride_;
83
84 public:
85 MultibandVectorAccessor(MultiArrayIndex size, MultiArrayIndex stride)
86 : size_(size),
87 stride_(stride)
88 {}
89
90
91 typedef Multiband<T> value_type;
92
93 /** the vector's value_type
94 */
95 typedef T component_type;
96
97 typedef VectorElementAccessor<MultibandVectorAccessor<T> > ElementAccessor;
98
99 /** Read the component data at given vector index
100 at given iterator position
101 */
102 template <class ITERATOR>
103 component_type const & getComponent(ITERATOR const & i, int idx) const
104 {
105 return *(&*i+idx*stride_);
106 }
107
108 /** Set the component data at given vector index
109 at given iterator position. The type <TT>V</TT> of the passed
110 in <TT>value</TT> is automatically converted to <TT>component_type</TT>.
111 In case of a conversion floating point -> integral this includes rounding and clipping.
112 */
113 template <class V, class ITERATOR>
114 void setComponent(V const & value, ITERATOR const & i, int idx) const
115 {
116 *(&*i+idx*stride_) = detail::RequiresExplicitCast<component_type>::cast(value);
117 }
118
119 /** Read the component data at given vector index
120 at an offset of given iterator position
121 */
122 template <class ITERATOR, class DIFFERENCE>
123 component_type const & getComponent(ITERATOR const & i, DIFFERENCE const & diff, int idx) const
124 {
125 return *(&i[diff]+idx*stride_);
126 }
127
128 /** Set the component data at given vector index
129 at an offset of given iterator position. The type <TT>V</TT> of the passed
130 in <TT>value</TT> is automatically converted to <TT>component_type</TT>.
131 In case of a conversion floating point -> integral this includes rounding and clipping.
132 */
133 template <class V, class ITERATOR, class DIFFERENCE>
134 void
135 setComponent(V const & value, ITERATOR const & i, DIFFERENCE const & diff, int idx) const
136 {
137 *(&i[diff]+idx*stride_) = detail::RequiresExplicitCast<component_type>::cast(value);
138 }
139
140 template <class U>
141 MultiArrayIndex size(U) const
142 {
143 return size_;
144 }
145 };
146
147 /********************************************************/
148
149 template <class TYPECODE> // pseudo-template to avoid inline expansion of the function
150 // will always be NPY_TYPES
151 PyObject *
152 constructArray(TaggedShape tagged_shape, TYPECODE typeCode, bool init,
153 python_ptr arraytype = python_ptr());
154
155 /********************************************************/
156
157 template <class Shape>
158 void numpyParseSlicing(Shape const & shape, PyObject * idx, Shape & start, Shape & stop)
159 {
160 int N = shape.size();
161 for(int k=0; k<N; ++k)
162 {
163 start[k] = 0;
164 stop[k] = shape[k];
165 }
166
167 python_ptr index(idx);
168 if(!PySequence_Check(index))
169 {
170 index = python_ptr(PyTuple_Pack(1, index.ptr()), python_ptr::new_nonzero_reference);
171 }
172 int lindex = PyTuple_Size(index);
173 int kindex = 0;
174 for(; kindex<lindex; ++kindex)
175 {
176 if(PyTuple_GET_ITEM((PyTupleObject *)index.ptr(), kindex) == Py_Ellipsis)
177 break;
178 }
179 if(kindex == lindex && lindex < N)
180 {
181 python_ptr ellipsis = python_ptr(PyTuple_Pack(1, Py_Ellipsis), python_ptr::new_nonzero_reference);
182 index = python_ptr(PySequence_Concat(index, ellipsis), python_ptr::new_nonzero_reference);
183 ++lindex;
184 }
185 kindex = 0;
186 for(int k=0; k < N; ++k)
187 {
188 PyObject * item = PyTuple_GET_ITEM((PyTupleObject *)index.ptr(), kindex);
189 #if PY_MAJOR_VERSION < 3
190 if(PyInt_Check(item))
191 {
192 MultiArrayIndex i = PyInt_AsLong(item);
193 #else
194 if(PyLong_Check(item))
195 {
196 MultiArrayIndex i = PyLong_AsLong(item);
197 #endif
198 start[k] = i;
199 if(start[k] < 0)
200 start[k] += shape[k];
201 stop[k] = start[k];
202 ++kindex;
203 }
204 else if(PySlice_Check(item))
205 {
206 Py_ssize_t sstart, sstop, step;
207 #if PY_MAJOR_VERSION < 3
208 if(PySlice_GetIndices((PySliceObject *)item, shape[k], &sstart, &sstop, &step) != 0)
209 #else
210 if(PySlice_GetIndices(item, shape[k], &sstart, &sstop, &step) != 0)
211 #endif
212 pythonToCppException(0);
213 vigra_precondition(step == 1,
214 "numpyParseSlicing(): only unit steps are supported.");
215 start[k] = sstart;
216 stop[k] = sstop;
217 ++kindex;
218 }
219 else if(item == Py_Ellipsis)
220 {
221 if(lindex == N)
222 ++kindex;
223 else
224 ++lindex;
225 }
226 else
227 {
228 vigra_precondition(false,
229 "numpyParseSlicing(): unsupported index object.");
230 }
231 }
232 }
233
234
235 /********************************************************/
236 /* */
237 /* NumpyAnyArray */
238 /* */
239 /********************************************************/
240
241 /** Wrapper class for a Python array.
242
243 This class stores a reference-counted pointer to an Python numpy array object,
244 i.e. an object where <tt>PyArray_Check(object)</tt> returns true (in Python, the
245 object is then a subclass of <tt>numpy.ndarray</tt>). This class is mainly used
246 as a smart pointer to these arrays, but some basic access and conversion functions
247 are also provided.
248
249 <b>\#include</b> <vigra/numpy_array.hxx><br>
250 Namespace: vigra
251 */
252 class NumpyAnyArray
253 {
254 protected:
255 python_ptr pyArray_;
256
257 public:
258
259 /// difference type
260 typedef ArrayVector<npy_intp> difference_type;
261
262 static python_ptr getArrayTypeObject()
263 {
264 return detail::getArrayTypeObject();
265 }
266
267 static std::string defaultOrder(std::string defaultValue = "C")
268 {
269 return detail::defaultOrder(defaultValue);
270 }
271
272 static python_ptr defaultAxistags(int ndim, std::string order = "")
273 {
274 return detail::defaultAxistags(ndim, order);
275 }
276
277 static python_ptr emptyAxistags(int ndim)
278 {
279 return detail::emptyAxistags(ndim);
280 }
281
282 /**
283 Construct from a Python object. If \a obj is NULL, or is not a subclass
284 of numpy.ndarray, the resulting NumpyAnyArray will have no data (i.e.
285 hasData() returns false). Otherwise, it creates a new reference to the array
286 \a obj, unless \a createCopy is true, where a new array is created by calling
287 the C-equivalent of obj->copy().
288 */
289 explicit NumpyAnyArray(PyObject * obj = 0, bool createCopy = false, PyTypeObject * type = 0)
290 {
291 if(obj == 0)
292 return;
293 vigra_precondition(type == 0 || PyType_IsSubtype(type, &PyArray_Type),
294 "NumpyAnyArray(obj, createCopy, type): type must be numpy.ndarray or a subclass thereof.");
295 if(createCopy)
296 makeCopy(obj, type);
297 else
298 vigra_precondition(makeReference(obj, type), "NumpyAnyArray(obj): obj isn't a numpy array.");
299 }
300
301 /**
302 Copy constructor. By default, it creates a new reference to the array
303 \a other. When \a createCopy is true, a new array is created by calling
304 the C-equivalent of other.copy().
305 */
306 NumpyAnyArray(NumpyAnyArray const & other, bool createCopy = false, PyTypeObject * type = 0)
307 {
308 if(!other.hasData())
309 return;
310 vigra_precondition(type == 0 || PyType_IsSubtype(type, &PyArray_Type),
311 "NumpyAnyArray(obj, createCopy, type): type must be numpy.ndarray or a subclass thereof.");
312 if(createCopy)
313 makeCopy(other.pyObject(), type);
314 else
315 makeReference(other.pyObject(), type);
316 }
317
318 // auto-generated destructor is ok
319
320 /**
321 * Assignment operator. If this is already a view with data
322 * (i.e. hasData() is true) and the shapes match, the RHS
323 * array contents are copied via the C-equivalent of
324 * 'self[...] = other[...]'. If the shapes don't matched,
325 * broadcasting is tried on the trailing (i.e. channel)
326 * dimension.
327 * If the LHS is an empty view, assignment is identical to
328 * makeReference(other.pyObject()).
329 */
330 NumpyAnyArray & operator=(NumpyAnyArray const & other)
331 {
332 if(hasData())
333 {
334 vigra_precondition(other.hasData(),
335 "NumpyArray::operator=(): Cannot assign from empty array.");
336
337 python_ptr arraytype = getArrayTypeObject();
338 python_ptr f(pythonFromData("_copyValuesImpl"));
339 if(PyObject_HasAttr(arraytype, f))
340 {
341 python_ptr res(PyObject_CallMethodObjArgs(arraytype, f.get(),
342 pyArray_.get(), other.pyArray_.get(), NULL),
343 python_ptr::keep_count);
344 vigra_postcondition(res.get() != 0,
345 "NumpyArray::operator=(): VigraArray._copyValuesImpl() failed.");
346 }
347 else
348 {
349 PyArrayObject * sarray = (PyArrayObject *)pyArray_.get();
350 PyArrayObject * tarray = (PyArrayObject *)other.pyArray_.get();
351
352 if(PyArray_CopyInto(tarray, sarray) == -1)
353 pythonToCppException(0);
354 }
355 }
356 else
357 {
358 pyArray_ = other.pyArray_;
359 }
360 return *this;
361 }
362
363 /**
364 Returns the number of dimensions of this array, or 0 if
365 hasData() is false.
366 */
367 MultiArrayIndex ndim() const
368 {
369 if(hasData())
370 return PyArray_NDIM(pyArray());
371 return 0;
372 }
373
374 /**
375 Returns the number of spatial dimensions of this array, or 0 if
376 hasData() is false. If the enclosed Python array does not define
377 the attribute spatialDimensions, ndim() is returned.
378 */
379 MultiArrayIndex spatialDimensions() const
380 {
381 if(!hasData())
382 return 0;
383 return pythonGetAttr(pyObject(), "spatialDimensions", ndim());
384 }
385
386 bool hasChannelAxis() const
387 {
388 if(!hasData())
389 return false;
390 return channelIndex() == ndim();
391 }
392
393 MultiArrayIndex channelIndex() const
394 {
395 if(!hasData())
396 return 0;
397 return pythonGetAttr(pyObject(), "channelIndex", ndim());
398 }
399
400 MultiArrayIndex innerNonchannelIndex() const
401 {
402 if(!hasData())
403 return 0;
404 return pythonGetAttr(pyObject(), "innerNonchannelIndex", ndim());
405 }
406
407 /**
408 Returns the shape of this array. The size of
409 the returned shape equals ndim().
410 */
411 difference_type shape() const
412 {
413 if(hasData())
414 return difference_type(PyArray_DIMS(pyArray()), PyArray_DIMS(pyArray()) + ndim());
415 return difference_type();
416 }
417
418 /** Compute the ordering of the strides of this array.
419 The result is describes the current permutation of the axes relative
420 to an ascending stride order.
421 */
422 difference_type strideOrdering() const
423 {
424 if(!hasData())
425 return difference_type();
426 MultiArrayIndex N = ndim();
427 difference_type stride(PyArray_STRIDES(pyArray()), PyArray_STRIDES(pyArray()) + N),
428 permutation(N);
429 for(MultiArrayIndex k=0; k<N; ++k)
430 permutation[k] = k;
431 for(MultiArrayIndex k=0; k<N-1; ++k)
432 {
433 MultiArrayIndex smallest = k;
434 for(MultiArrayIndex j=k+1; j<N; ++j)
435 {
436 if(stride[j] < stride[smallest])
437 smallest = j;
438 }
439 if(smallest != k)
440 {
441 std::swap(stride[k], stride[smallest]);
442 std::swap(permutation[k], permutation[smallest]);
443 }
444 }
445 difference_type ordering(N);
446 for(MultiArrayIndex k=0; k<N; ++k)
447 ordering[permutation[k]] = k;
448 return ordering;
449 }
450
451 // /**
452 // Returns the the permutation that will transpose this array into
453 // canonical ordering (currently: F-order). The size of
454 // the returned permutation equals ndim().
455 // */
456 // difference_type permutationToNormalOrder() const
457 // {
458 // if(!hasData())
459 // return difference_type();
460
461 // // difference_type res(detail::getAxisPermutationImpl(pyArray_,
462 // // "permutationToNormalOrder", true));
463 // difference_type res;
464 // detail::getAxisPermutationImpl(res, pyArray_, "permutationToNormalOrder", true);
465 // if(res.size() == 0)
466 // {
467 // res.resize(ndim());
468 // linearSequence(res.begin(), res.end(), ndim()-1, MultiArrayIndex(-1));
469 // }
470 // return res;
471 // }
472
473 /**
474 Returns the value type of the elements in this array, or -1
475 when hasData() is false.
476 */
477 int dtype() const
478 {
479 if(hasData())
480 return PyArray_DESCR(pyArray())->type_num;
481 return -1;
482 }
483
484 /**
485 Constructs a slicing from the given shape objects and calls '__getitem__'.
486 */
487 template <class Shape>
488 NumpyAnyArray
489 getitem(Shape start, Shape stop) const
490 {
491 unsigned int size = ndim();
492 vigra_precondition(start.size() == size && stop.size() == size,
493 "NumpyAnyArray::getitem(): shape has wrong dimension.");
494
495 difference_type s(this->shape());
496
497 python_ptr index(PyTuple_New(size), python_ptr::new_nonzero_reference);
498 for(unsigned int k=0; k<size; ++k)
499 {
500 if(start[k] < 0)
501 start[k] += s[k];
502 if(stop[k] < 0)
503 stop[k] += s[k];
504 vigra_precondition(0 <= start[k] && start[k] <= stop[k] && stop[k] <= s[k],
505 "NumpyAnyArray::getitem(): slice out of bounds.");
506 PyObject * item = 0;
507 if(start[k] == stop[k])
508 {
509 item = pythonFromData(start[k]);
510 }
511 else
512 {
513 python_ptr s0(pythonFromData(start[k]));
514 python_ptr s1(pythonFromData(stop[k]));
515 item = PySlice_New(s0, s1, 0);
516 }
517 pythonToCppException(item);
518 PyTuple_SET_ITEM((PyTupleObject *)index.ptr(), k, item); // steals reference to item
519 }
520 python_ptr func(pythonFromData("__getitem__"));
521 python_ptr res(PyObject_CallMethodObjArgs(pyObject(), func.ptr(), index.ptr(), NULL),
522 python_ptr::new_nonzero_reference);
523 return NumpyAnyArray(res.ptr());
524 }
525
526
527 /**
528 * Return the AxisTags of this array or a NULL pointer when the attribute
529 'axistags' is missing in the Python object or this array has no data.
530 */
531 python_ptr axistags() const
532 {
533 python_ptr axistags;
534 if(pyObject())
535 {
536 python_ptr key(pythonFromData("axistags"));
537 axistags.reset(PyObject_GetAttr(pyObject(), key), python_ptr::keep_count);
538 if(!axistags)
539 PyErr_Clear();
540 }
541 return axistags;
542 }
543
544 /**
545 * Return a borrowed reference to the internal PyArrayObject.
546 */
547 PyArrayObject * pyArray() const
548 {
549 return (PyArrayObject *)pyArray_.get();
550 }
551
552 /**
553 * Return a borrowed reference to the internal PyArrayObject
554 * (see pyArray()), cast to PyObject for your convenience.
555 */
556 PyObject * pyObject() const
557 {
558 return pyArray_.get();
559 }
560
561 /**
562 Reset the NumpyAnyArray to the given object. If \a obj is a numpy array object,
563 a new reference to that array is created, and the function returns
564 true. Otherwise, it returns false and the NumpyAnyArray remains unchanged.
565 If \a type is given, the new reference will be a view with that type, provided
566 that \a type is a numpy ndarray or a subclass thereof. Otherwise, an
567 exception is thrown.
568 */
569 bool makeReference(PyObject * obj, PyTypeObject * type = 0)
570 {
571 if(obj == 0 || !PyArray_Check(obj))
572 return false;
573 if(type != 0)
574 {
575 vigra_precondition(PyType_IsSubtype(type, &PyArray_Type) != 0,
576 "NumpyAnyArray::makeReference(obj, type): type must be numpy.ndarray or a subclass thereof.");
577 obj = PyArray_View((PyArrayObject*)obj, 0, type);
578 pythonToCppException(obj);
579 }
580 pyArray_.reset(obj);
581 return true;
582 }
583
584 /**
585 Create a copy of the given array object. If \a obj is a numpy array object,
586 a copy is created via the C-equivalent of 'obj->copy()'. If
587 this call fails, or obj was not an array, an exception is thrown
588 and the NumpyAnyArray remains unchanged.
589 */
590 void makeCopy(PyObject * obj, PyTypeObject * type = 0)
591 {
592 vigra_precondition(obj && PyArray_Check(obj),
593 "NumpyAnyArray::makeCopy(obj): obj is not an array.");
594 vigra_precondition(type == 0 || PyType_IsSubtype(type, &PyArray_Type),
595 "NumpyAnyArray::makeCopy(obj, type): type must be numpy.ndarray or a subclass thereof.");
596 python_ptr array(PyArray_NewCopy((PyArrayObject*)obj, NPY_ANYORDER), python_ptr::keep_count);
597 pythonToCppException(array);
598 makeReference(array, type);
599 }
600
601 /**
602 Check whether this NumpyAnyArray actually points to a Python array.
603 */
604 bool hasData() const
605 {
606 return pyArray_ != 0;
607 }
608 };
609
610 /********************************************************/
611 /* */
612 /* constructArray */
613 /* */
614 /********************************************************/
615
616 namespace detail {
617
618 inline bool
619 nontrivialPermutation(ArrayVector<npy_intp> const & p)
620 {
621 for(unsigned int k=0; k<p.size(); ++k)
622 if(p[k] != k)
623 return true;
624 return false;
625 }
626
627 } // namespace detail
628
629 template <class TYPECODE> // pseudo-template to avoid inline expansion of the function
630 // will always be NPY_TYPES
631 PyObject *
632 constructArray(TaggedShape tagged_shape, TYPECODE typeCode, bool init, python_ptr arraytype)
633 {
634 ArrayVector<npy_intp> shape = finalizeTaggedShape(tagged_shape);
635 PyAxisTags axistags(tagged_shape.axistags);
636
637 int ndim = (int)shape.size();
638 ArrayVector<npy_intp> inverse_permutation;
639 int order = 1; // Fortran order
640
641 if(axistags)
642 {
643 if(!arraytype)
644 arraytype = NumpyAnyArray::getArrayTypeObject();
645
646 inverse_permutation = axistags.permutationFromNormalOrder();
647 vigra_precondition(ndim == (int)inverse_permutation.size(),
648 "axistags.permutationFromNormalOrder(): permutation has wrong size.");
649 }
650 else
651 {
652 arraytype = python_ptr((PyObject*)&PyArray_Type);
653 order = 0; // C order
654 }
655
656 // std::cerr << "constructArray: " << shape << "\n" << inverse_permutation << "\n";
657
658 python_ptr array(PyArray_New((PyTypeObject *)arraytype.get(), ndim, shape.begin(),
659 typeCode, 0, 0, 0, order, 0),
660 python_ptr::keep_count);
661 pythonToCppException(array);
662
663 if(detail::nontrivialPermutation(inverse_permutation))
664 {
665 PyArray_Dims permute = { inverse_permutation.begin(), ndim };
666 array = python_ptr(PyArray_Transpose((PyArrayObject*)array.get(), &permute),
667 python_ptr::keep_count);
668 pythonToCppException(array);
669 }
670
671 if(arraytype != (PyObject*)&PyArray_Type && axistags)
672 pythonToCppException(PyObject_SetAttrString(array, "axistags", axistags.axistags) != -1);
673
674 if(init)
675 PyArray_FILLWBYTE((PyArrayObject *)array.get(), 0);
676
677 return array.release();
678 }
679
680 // FIXME: reimplement in terms of TaggedShape?
681 template <class TINY_VECTOR>
682 inline
683 python_ptr constructNumpyArrayFromData(
684 TINY_VECTOR const & shape, npy_intp *strides,
685 NPY_TYPES typeCode, void *data)
686 {
687 ArrayVector<npy_intp> pyShape(shape.begin(), shape.end());
688
689 #ifndef NPY_ARRAY_WRITEABLE
690 # define NPY_ARRAY_WRITEABLE NPY_WRITEABLE // old API compatibility
691 #endif
692
693 python_ptr array(PyArray_New(&PyArray_Type, shape.size(), pyShape.begin(),
694 typeCode, strides, data, 0, NPY_ARRAY_WRITEABLE, 0),
695 python_ptr::keep_count);
696 pythonToCppException(array);
697
698 return array;
699 }
700
701 /********************************************************/
702 /* */
703 /* NumpyArray */
704 /* */
705 /********************************************************/
706
707 /** Provide the MultiArrayView interface for a Python array.
708
709 This class inherits from both \ref vigra::MultiArrayView and \ref vigra::NumpyAnyArray
710 in order to support easy and safe application of VIGRA functions to Python arrays.
711
712 <b>\#include</b> <vigra/numpy_array.hxx><br>
713 Namespace: vigra
714 */
715 template <unsigned int N, class T, class Stride = StridedArrayTag>
716 class NumpyArray
717 : public MultiArrayView<N, typename NumpyArrayTraits<N, T, Stride>::value_type, Stride>,
718 public NumpyAnyArray
719 {
720 public:
721 typedef NumpyArrayTraits<N, T, Stride> ArrayTraits;
722 typedef typename ArrayTraits::dtype dtype;
723 typedef T pseudo_value_type;
724
725 static NPY_TYPES const typeCode = ArrayTraits::typeCode;
726
727 /** the view type associated with this array.
728 */
729 typedef MultiArrayView<N, typename ArrayTraits::value_type, Stride> view_type;
730
731 enum { actual_dimension = view_type::actual_dimension };
732
733 /** the array's value type
734 */
735 typedef typename view_type::value_type value_type;
736
737 /** pointer type
738 */
739 typedef typename view_type::pointer pointer;
740
741 /** const pointer type
742 */
743 typedef typename view_type::const_pointer const_pointer;
744
745 /** reference type (result of operator[])
746 */
747 typedef typename view_type::reference reference;
748
749 /** const reference type (result of operator[] const)
750 */
751 typedef typename view_type::const_reference const_reference;
752
753 /** size type
754 */
755 typedef typename view_type::size_type size_type;
756
757 /** difference type (used for multi-dimensional offsets and indices)
758 */
759 typedef typename view_type::difference_type difference_type;
760
761 /** difference and index type for a single dimension
762 */
763 typedef typename view_type::difference_type_1 difference_type_1;
764
765 /** type of an array specifying an axis permutation
766 */
767 typedef typename NumpyAnyArray::difference_type permutation_type;
768
769 /** traverser type
770 */
771 typedef typename view_type::traverser traverser;
772
773 /** traverser type to const data
774 */
775 typedef typename view_type::const_traverser const_traverser;
776
777 /** sequential (random access) iterator type
778 */
779 typedef typename view_type::iterator iterator;
780
781 /** sequential (random access) const iterator type
782 */
783 typedef typename view_type::const_iterator const_iterator;
784
785 using view_type::shape; // resolve ambiguity of multiple inheritance
786 using view_type::hasData; // resolve ambiguity of multiple inheritance
787 using view_type::strideOrdering; // resolve ambiguity of multiple inheritance
788
789 protected:
790
791 // this function assumes that pyArray_ has already been set, and compatibility been checked
792 void setupArrayView();
793
794 static python_ptr init(difference_type const & shape, bool init = true,
795 std::string const & order = "")
796 {
797 vigra_precondition(order == "" || order == "C" || order == "F" ||
798 order == "V" || order == "A",
799 "NumpyArray.init(): order must be in ['C', 'F', 'V', 'A', ''].");
800 return python_ptr(constructArray(ArrayTraits::taggedShape(shape, order), typeCode, init),
801 python_ptr::keep_count);
802 }
803
804 public:
805
806 using view_type::init;
807
808 /**
809 * Construct from a given PyObject pointer. When the given
810 * python object is NULL, the internal python array will be
811 * NULL and hasData() will return false.
812 *
813 * Otherwise, the function attempts to create a
814 * new reference to the given Python object, unless
815 * copying is forced by setting \a createCopy to true.
816 * If either of this fails, the function throws an exception.
817 * This will not happen if isReferenceCompatible(obj) (in case
818 * of creating a new reference) or isCopyCompatible(obj)
819 * (in case of copying) have returned true beforehand.
820 */
821 explicit NumpyArray(PyObject *obj = 0, bool createCopy = false)
822 {
823 if(obj == 0)
824 return;
825 if(createCopy)
826 makeCopy(obj);
827 else
828 vigra_precondition(makeReference(obj),
829 "NumpyArray(obj): Cannot construct from incompatible array.");
830 }
831
832 /**
833 * Copy constructor; does not copy the memory, but creates a
834 * new reference to the same underlying python object, unless
835 * a copy is forced by setting \a createCopy to true.
836 * (If the source object has no data, this one will have
837 * no data, too.)
838 */
839 NumpyArray(const NumpyArray &other, bool createCopy = false)
840 : view_type(),
841 NumpyAnyArray()
842 {
843 if(!other.hasData())
844 return;
845 if(createCopy)
846 makeCopy(other.pyObject());
847 else
848 makeReferenceUnchecked(other.pyObject());
849 }
850
851 /**
852 * Allocate new memory and copy data from a MultiArrayView.
853 */
854 template <class U, class S>
855 explicit NumpyArray(const MultiArrayView<N, U, S> &other)
856 {
857 if(!other.hasData())
858 return;
859 vigra_postcondition(makeReference(init(other.shape(), false)),
860 "NumpyArray(MultiArrayView): Python constructor did not produce a compatible array.");
861 view_type::operator=(other);
862 }
863
864 /**
865 * Construct a new array object, allocating an internal python
866 * ndarray of the given shape in the given order (default: VIGRA order), initialized
867 * with zeros.
868 *
869 * An exception is thrown when construction fails.
870 */
871 explicit NumpyArray(difference_type const & shape, std::string const & order = "")
872 {
873 vigra_postcondition(makeReference(init(shape, true, order)),
874 "NumpyArray(shape): Python constructor did not produce a compatible array.");
875 }
876
877 /**
878 * Construct a new array object, allocating an internal python
879 * ndarray according to the given tagged shape, initialized with zeros.
880 *
881 * An exception is thrown when construction fails.
882 */
883 explicit NumpyArray(TaggedShape const & tagged_shape)
884 {
885 reshapeIfEmpty(tagged_shape,
886 "NumpyArray(tagged_shape): Python constructor did not produce a compatible array.");
887 }
888
889 /**
890 * Constructor from NumpyAnyArray.
891 * Equivalent to NumpyArray(other.pyObject())
892 */
893 explicit NumpyArray(const NumpyAnyArray &other, bool createCopy = false)
894 {
895 if(!other.hasData())
896 return;
897 if(createCopy)
898 makeCopy(other.pyObject());
899 else
900 vigra_precondition(makeReference(other.pyObject()), //, false),
901 "NumpyArray(NumpyAnyArray): Cannot construct from incompatible or empty array.");
902 }
903
904 /**
905 * Assignment operator. If this is already a view with data
906 * (i.e. hasData() is true) and the shapes match, the RHS
907 * array contents are copied. If this is an empty view,
908 * assignment is identical to makeReferenceUnchecked(other.pyObject()).
909 * See MultiArrayView::operator= for further information on
910 * semantics.
911 */
912 NumpyArray &operator=(const NumpyArray &other)
913 {
914 if(hasData())
915 view_type::operator=(other);
916 else
917 makeReferenceUnchecked(other.pyObject());
918 return *this;
919 }
920
921 /**
922 * Assignment operator. If this is already a view with data
923 * (i.e. hasData() is true) and the shapes match, the RHS
924 * array contents are copied. If this is an empty view,
925 * assignment is identical to makeReferenceUnchecked(other.pyObject()).
926 * See MultiArrayView::operator= for further information on
927 * semantics.
928 */
929 template <class U, class S>
930 NumpyArray &operator=(const NumpyArray<N, U, S> &other)
931 {
932 if(hasData())
933 {
934 vigra_precondition(shape() == other.shape(),
935 "NumpyArray::operator=(): shape mismatch.");
936 view_type::operator=(other);
937 }
938 else if(other.hasData())
939 {
940 NumpyArray copy;
941 copy.reshapeIfEmpty(other.taggedShape(),
942 "NumpyArray::operator=(): reshape failed unexpectedly.");
943 copy = other;
944 makeReferenceUnchecked(copy.pyObject());
945 }
946 return *this;
947 }
948
949 /**
950 * Assignment operator. If this is already a view with data
951 * (i.e. hasData() is true) and the shapes match, the RHS
952 * array contents are copied. If this is an empty view,
953 * a new buffer with the RHS shape is allocated before copying.
954 */
955 template <class U, class S>
956 NumpyArray &operator=(const MultiArrayView<N, U, S> &other)
957 {
958 if(hasData())
959 {
960 vigra_precondition(shape() == other.shape(),
961 "NumpyArray::operator=(): shape mismatch.");
962 view_type::operator=(other);
963 }
964 else if(other.hasData())
965 {
966 NumpyArray copy;
967 copy.reshapeIfEmpty(other.shape(),
968 "NumpyArray::operator=(): reshape failed unexpectedly.");
969 copy = other;
970 makeReferenceUnchecked(copy.pyObject());
971 }
972 return *this;
973 }
974
975 /**
976 * Assignment operator. If this is already a view with data
977 * (i.e. hasData() is true) and the shapes match, the RHS
978 * array contents are copied.
979 * If this is an empty view, assignment is identical to
980 * makeReference(other.pyObject()).
981 * Otherwise, an exception is thrown.
982 */
983 NumpyArray &operator=(const NumpyAnyArray &other)
984 {
985 if(hasData())
986 {
987 NumpyAnyArray::operator=(other);
988 }
989 else if(isReferenceCompatible(other.pyObject()))
990 {
991 makeReferenceUnchecked(other.pyObject());
992 }
993 else
994 {
995 vigra_precondition(false,
996 "NumpyArray::operator=(): Cannot assign from incompatible array.");
997 }
998 return *this;
999 }
1000
1001 /**
1002 Permute the entries of the given array \a data exactly like the axes of this NumpyArray
1003 were permuted upon conversion from numpy.
1004 */
1005 template <class U>
1006 ArrayVector<U>
1007 permuteLikewise(ArrayVector<U> const & data) const
1008 {
1009 vigra_precondition(hasData(),
1010 "NumpyArray::permuteLikewise(): array has no data.");
1011
1012 ArrayVector<U> res(data.size());
1013 ArrayTraits::permuteLikewise(this->pyArray_, data, res);
1014 return res;
1015 }
1016
1017 /**
1018 Permute the entries of the given array \a data exactly like the axes of this NumpyArray
1019 were permuted upon conversion from numpy.
1020 */
1021 template <class U, int K>
1022 TinyVector<U, K>
1023 permuteLikewise(TinyVector<U, K> const & data) const
1024 {
1025 vigra_precondition(hasData(),
1026 "NumpyArray::permuteLikewise(): array has no data.");
1027
1028 TinyVector<U, K> res;
1029 ArrayTraits::permuteLikewise(this->pyArray_, data, res);
1030 return res;
1031 }
1032
1033 /**
1034 Get the permutation of the axes of this NumpyArray
1035 that was performed upon conversion from numpy.
1036 */
1037 template <int K>
1038 TinyVector<npy_intp, K>
1039 permuteLikewise() const
1040 {
1041 vigra_precondition(hasData(),
1042 "NumpyArray::permuteLikewise(): array has no data.");
1043
1044 TinyVector<npy_intp, K> data, res;
1045 linearSequence(data.begin(), data.end());
1046 ArrayTraits::permuteLikewise(this->pyArray_, data, res);
1047 return res;
1048 }
1049
1050 /**
1051 * Test whether a given python object is a numpy array that can be
1052 * converted (copied) into an array compatible to this NumpyArray type.
1053 * This means that the array's shape conforms to the requirements of
1054 * makeCopy().
1055 */
1056 static bool isCopyCompatible(PyObject *obj)
1057 {
1058 #if VIGRA_CONVERTER_DEBUG
1059 std::cerr << "class " << typeid(NumpyArray).name() << " got " << obj->ob_type->tp_name << "\n";
1060 std::cerr << "using traits " << typeid(ArrayTraits).name() << "\n";
1061 std::cerr<<"isArray: "<< ArrayTraits::isArray(obj)<<std::endl;
1062 std::cerr<<"isShapeCompatible: "<< ArrayTraits::isShapeCompatible((PyArrayObject *)obj)<<std::endl;
1063 #endif
1064
1065 return ArrayTraits::isArray(obj) &&
1066 ArrayTraits::isShapeCompatible((PyArrayObject *)obj);
1067 }
1068
1069 /**
1070 * Test whether a given python object is a numpy array with a
1071 * compatible dtype and the correct shape and strides, so that it
1072 * can be referenced as a view by this NumpyArray type (i.e.
1073 * it conforms to the requirements of makeReference()).
1074 */
1075 static bool isReferenceCompatible(PyObject *obj)
1076 {
1077 return ArrayTraits::isArray(obj) &&
1078 ArrayTraits::isPropertyCompatible((PyArrayObject *)obj);
1079 }
1080
1081 /**
1082 * Deprecated, use isReferenceCompatible(obj) instead.
1083 */
1084 static bool isStrictlyCompatible(PyObject *obj)
1085 {
1086 return isReferenceCompatible(obj);
1087 }
1088
1089 /**
1090 * Create a vector representing the standard stride ordering of a NumpyArray.
1091 * That is, we get a vector representing the range [0,...,N-1], which
1092 * denotes the stride ordering for Fortran order.
1093 */
1094 static difference_type standardStrideOrdering()
1095 {
1096 difference_type strideOrdering;
1097 for(unsigned int k=0; k<N; ++k)
1098 strideOrdering[k] = k;
1099 return strideOrdering;
1100 }
1101
1102 /**
1103 * Set up a view to the given object without checking compatibility.
1104 * This function must not be used unless isReferenceCompatible(obj) returned
1105 * true on the given object (otherwise, a crash is likely).
1106 */
1107 void makeReferenceUnchecked(PyObject *obj)
1108 {
1109 NumpyAnyArray::makeReference(obj);
1110 setupArrayView();
1111 }
1112
1113 /**
1114 * Try to set up a view referencing the given PyObject.
1115 * Returns false if the python object is not a compatible
1116 * numpy array (see isReferenceCompatible()).
1117 *
1118 * The second parameter ('strict') is deprecated and will be ignored.
1119 */
1120 bool makeReference(PyObject *obj, bool /* strict */ = false)
1121 {
1122 if(!isReferenceCompatible(obj))
1123 return false;
1124 makeReferenceUnchecked(obj);
1125 return true;
1126 }
1127
1128 /**
1129 * Try to set up a view referencing the same data as the given
1130 * NumpyAnyArray. This overloaded variant simply calls
1131 * makeReference() on array.pyObject(). The parameter \a strict
1132 * is deprecated and will be ignored.
1133 */
1134 bool makeReference(const NumpyAnyArray &array, bool strict = false)
1135 {
1136 return makeReference(array.pyObject(), strict);
1137 }
1138
1139 /**
1140 * Set up an unsafe reference to the given MultiArrayView.
1141 * ATTENTION: This creates a numpy.ndarray that points to the
1142 * same data, but does not own it, so it must be ensured by
1143 * other means that the memory does not get freed before the
1144 * end of the ndarray's lifetime! (One elegant way would be
1145 * to set the 'base' attribute of the resulting ndarray to a
1146 * python object which directly or indirectly holds the memory
1147 * of the given MultiArrayView.)
1148 */
1149 void makeUnsafeReference(const view_type &multiArrayView)
1150 {
1151 vigra_precondition(!hasData(),
1152 "makeUnsafeReference(): cannot replace existing view with given buffer");
1153
1154 // construct an ndarray that points to our data (taking strides into account):
1155 python_ptr array(ArrayTraits::unsafeConstructorFromData(multiArrayView.shape(),
1156 multiArrayView.data(), multiArrayView.stride()));
1157
1158 view_type::operator=(multiArrayView);
1159 pyArray_ = array;
1160 }
1161
1162 /**
1163 Try to create a copy of the given PyObject.
1164 Raises an exception when obj is not a compatible array
1165 (see isCopyCompatible() or isReferenceCompatible(), according to the
1166 parameter \a strict) or the Python constructor call failed.
1167 */
1168 void makeCopy(PyObject *obj, bool strict = false)
1169 {
1170 #if VIGRA_CONVERTER_DEBUG
1171 int ndim = PyArray_NDIM((PyArrayObject *)obj);
1172 npy_intp * s = PyArray_DIMS((PyArrayObject *)obj);
1173 std::cerr << "makeCopy: " << ndim << " " << ArrayVectorView<npy_intp>(ndim, s) <<
1174 ", strides " << ArrayVectorView<npy_intp>(ndim, PyArray_STRIDES((PyArrayObject *)obj)) << "\n";
1175 std::cerr << "for " << typeid(*this).name() << "\n";
1176 #endif
1177 vigra_precondition(strict ? isReferenceCompatible(obj) : isCopyCompatible(obj),
1178 "NumpyArray::makeCopy(obj): Cannot copy an incompatible array.");
1179
1180 NumpyAnyArray copy(obj, true);
1181 makeReferenceUnchecked(copy.pyObject());
1182 }
1183
1184 /**
1185 Allocate new memory with the given shape and initialize with zeros.<br>
1186 If a stride ordering is given, the resulting array will have this stride
1187 ordering, when it is compatible with the array's memory layout (unstrided
1188 arrays only permit the standard ascending stride ordering).
1189
1190 <em>Note:</em> this operation invalidates dependent objects
1191 (MultiArrayViews and iterators)
1192 */
1193 void reshape(difference_type const & shape)
1194 {
1195 vigra_postcondition(makeReference(init(shape)),
1196 "NumpyArray.reshape(shape): Python constructor did not produce a compatible array.");
1197 }
1198
1199 /**
1200 When this array has no data, allocate new memory with the given \a shape and
1201 initialize with zeros. Otherwise, check if the new shape matches the old shape
1202 and throw a precondition exception with the given \a message if not.
1203 */
1204 void reshapeIfEmpty(difference_type const & shape, std::string message = "")
1205 {
1206 // FIXME: is this really a good replacement?
1207 // reshapeIfEmpty(shape, standardStrideOrdering(), message);
1208 reshapeIfEmpty(TaggedShape(shape), message);
1209 }
1210
1211 /**
1212 When this array has no data, allocate new memory with the given \a shape and
1213 initialize with zeros. Otherwise, check if the new shape matches the old shape
1214 and throw a precondition exception with the given \a message if not.
1215 */
1216 void reshapeIfEmpty(TaggedShape tagged_shape, std::string message = "")
1217 {
1218 ArrayTraits::finalizeTaggedShape(tagged_shape);
1219
1220 if(hasData())
1221 {
1222 vigra_precondition(tagged_shape.compatible(taggedShape()), message.c_str());
1223 }
1224 else
1225 {
1226 python_ptr array(constructArray(tagged_shape, typeCode, true),
1227 python_ptr::keep_count);
1228 vigra_postcondition(makeReference(NumpyAnyArray(array.get())),
1229 "NumpyArray.reshapeIfEmpty(): Python constructor did not produce a compatible array.");
1230 }
1231 }
1232
1233 TaggedShape taggedShape() const
1234 {
1235 return ArrayTraits::taggedShape(this->shape(), PyAxisTags(this->axistags(), true));
1236 }
1237 };
1238
1239 // this function assumes that pyArray_ has already been set, and compatibility been checked
1240 template <unsigned int N, class T, class Stride>
1241 void NumpyArray<N, T, Stride>::setupArrayView()
1242 {
1243 if(NumpyAnyArray::hasData())
1244 {
1245 permutation_type permute;
1246 ArrayTraits::permutationToSetupOrder(this->pyArray_, permute);
1247
1248 vigra_precondition(abs((int)permute.size() - actual_dimension) <= 1,
1249 "NumpyArray::setupArrayView(): got array of incompatible shape (should never happen).");
1250
1251 applyPermutation(permute.begin(), permute.end(),
1252 PyArray_DIMS(pyArray()), this->m_shape.begin());
1253 applyPermutation(permute.begin(), permute.end(),
1254 PyArray_STRIDES(pyArray()), this->m_stride.begin());
1255
1256 if((int)permute.size() == actual_dimension - 1)
1257 {
1258 this->m_shape[actual_dimension-1] = 1;
1259 this->m_stride[actual_dimension-1] = sizeof(value_type);
1260 }
1261
1262 this->m_stride /= sizeof(value_type);
1263 // make sure that singleton axes have non-zero stride
1264 for(int k=0; k<actual_dimension; ++k)
1265 {
1266 if(this->m_stride[k] == 0)
1267 {
1268 vigra_precondition(this->m_shape[k] == 1,
1269 "NumpyArray::setupArrayView(): only singleton axes may have zero stride.");
1270 this->m_stride[k] = 1;
1271 }
1272 }
1273
1274 this->m_ptr = reinterpret_cast<pointer>(PyArray_DATA(pyArray()));
1275 vigra_precondition(this->checkInnerStride(Stride()),
1276 "NumpyArray<..., UnstridedArrayTag>::setupArrayView(): First dimension of given array is not unstrided (should never happen).");
1277
1278 }
1279 else
1280 {
1281 this->m_ptr = 0;
1282 }
1283 }
1284
1285
1286 typedef NumpyArray<2, float > NumpyFArray2;
1287 typedef NumpyArray<3, float > NumpyFArray3;
1288 typedef NumpyArray<4, float > NumpyFArray4;
1289 typedef NumpyArray<2, Singleband<float> > NumpyFImage;
1290 typedef NumpyArray<3, Singleband<float> > NumpyFVolume;
1291 typedef NumpyArray<2, RGBValue<float> > NumpyFRGBImage;
1292 typedef NumpyArray<3, RGBValue<float> > NumpyFRGBVolume;
1293 typedef NumpyArray<3, Multiband<float> > NumpyFMultibandImage;
1294 typedef NumpyArray<4, Multiband<float> > NumpyFMultibandVolume;
1295
1296 /********************************************************/
1297 /* */
1298 /* NumpyArray Multiband Argument Object Factories */
1299 /* */
1300 /********************************************************/
1301
1302 template <class PixelType, class Stride>
1303 inline triple<ConstStridedImageIterator<PixelType>,
1304 ConstStridedImageIterator<PixelType>,
1305 MultibandVectorAccessor<PixelType> >
1306 srcImageRange(NumpyArray<3, Multiband<PixelType>, Stride> const & img)
1307 {
1308 ConstStridedImageIterator<PixelType>
1309 ul(img.data(), 1, img.stride(0), img.stride(1));
1310 return triple<ConstStridedImageIterator<PixelType>,
1311 ConstStridedImageIterator<PixelType>,
1312 MultibandVectorAccessor<PixelType> >
1313 (ul, ul + Size2D(img.shape(0), img.shape(1)), MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2)));
1314 }
1315
1316 template <class PixelType, class Stride>
1317 inline pair< ConstStridedImageIterator<PixelType>,
1318 MultibandVectorAccessor<PixelType> >
1319 srcImage(NumpyArray<3, Multiband<PixelType>, Stride> const & img)
1320 {
1321 ConstStridedImageIterator<PixelType>
1322 ul(img.data(), 1, img.stride(0), img.stride(1));
1323 return pair<ConstStridedImageIterator<PixelType>, MultibandVectorAccessor<PixelType> >
1324 (ul, MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2)));
1325 }
1326
1327 template <class PixelType, class Stride>
1328 inline triple< StridedImageIterator<PixelType>,
1329 StridedImageIterator<PixelType>,
1330 MultibandVectorAccessor<PixelType> >
1331 destImageRange(NumpyArray<3, Multiband<PixelType>, Stride> & img)
1332 {
1333 StridedImageIterator<PixelType>
1334 ul(img.data(), 1, img.stride(0), img.stride(1));
1335 return triple<StridedImageIterator<PixelType>,
1336 StridedImageIterator<PixelType>,
1337 MultibandVectorAccessor<PixelType> >
1338 (ul, ul + Size2D(img.shape(0), img.shape(1)),
1339 MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2)));
1340 }
1341
1342 template <class PixelType, class Stride>
1343 inline pair< StridedImageIterator<PixelType>,
1344 MultibandVectorAccessor<PixelType> >
1345 destImage(NumpyArray<3, Multiband<PixelType>, Stride> & img)
1346 {
1347 StridedImageIterator<PixelType>
1348 ul(img.data(), 1, img.stride(0), img.stride(1));
1349 return pair<StridedImageIterator<PixelType>, MultibandVectorAccessor<PixelType> >
1350 (ul, MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2)));
1351 }
1352
1353 template <class PixelType, class Stride>
1354 inline pair< ConstStridedImageIterator<PixelType>,
1355 MultibandVectorAccessor<PixelType> >
1356 maskImage(NumpyArray<3, Multiband<PixelType>, Stride> const & img)
1357 {
1358 ConstStridedImageIterator<PixelType>
1359 ul(img.data(), 1, img.stride(0), img.stride(1));
1360 return pair<ConstStridedImageIterator<PixelType>, MultibandVectorAccessor<PixelType> >
1361 (ul, MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2)));
1362 }
1363
1364 } // namespace vigra
1365
1366 #endif // VIGRA_NUMPY_ARRAY_HXX
vigra::MultiArrayView::const_reference
const value_type & const_reference
Definition: multi_array.hxx:727
vigra::NumpyAnyArray
Definition: numpy_array.hxx:252
vigra::StridedScanOrderIterator
Sequential iterator for MultiArrayView.
Definition: multi_fwd.hxx:161
vigra::applyPermutation
void applyPermutation(IndexIterator index_first, IndexIterator index_last, InIterator in, OutIterator out)
Sort an array according to the given index permutation.
Definition: algorithm.hxx:456
vigra::NumpyAnyArray::makeReference
bool makeReference(PyObject *obj, PyTypeObject *type=0)
Definition: numpy_array.hxx:569
vigra::MultiArrayView::difference_type
MultiArrayShape< actual_dimension >::type difference_type
Definition: multi_array.hxx:739
vigra::NumpyArray::permutation_type
NumpyAnyArray::difference_type permutation_type
Definition: numpy_array.hxx:767
vigra::NumpyArray::NumpyArray
NumpyArray(const NumpyAnyArray &other, bool createCopy=false)
Definition: numpy_array.hxx:893
vigra::NumpyArray::makeUnsafeReference
void makeUnsafeReference(const view_type &multiArrayView)
Definition: numpy_array.hxx:1149
vigra::NumpyAnyArray::NumpyAnyArray
NumpyAnyArray(PyObject *obj=0, bool createCopy=false, PyTypeObject *type=0)
Definition: numpy_array.hxx:289
vigra::NumpyArray::reshapeIfEmpty
void reshapeIfEmpty(TaggedShape tagged_shape, std::string message="")
Definition: numpy_array.hxx:1216
vigra::NumpyAnyArray::pyObject
PyObject * pyObject() const
Definition: numpy_array.hxx:556
vigra::NumpyArray::NumpyArray
NumpyArray(const MultiArrayView< N, U, S > &other)
Definition: numpy_array.hxx:855
vigra::NumpyArray::isReferenceCompatible
static bool isReferenceCompatible(PyObject *obj)
Definition: numpy_array.hxx:1075
vigra::MultiArrayView::shape
const difference_type & shape() const
Definition: multi_array.hxx:1648
vigra::NumpyAnyArray::spatialDimensions
MultiArrayIndex spatialDimensions() const
Definition: numpy_array.hxx:379
vigra::NumpyArray::difference_type_1
view_type::difference_type_1 difference_type_1
Definition: numpy_array.hxx:763
vigra::NumpyAnyArray::shape
difference_type shape() const
Definition: numpy_array.hxx:411
vigra::linearSequence
void linearSequence(Iterator first, Iterator last, Value start, Value step)
Fill an array with a sequence of numbers.
Definition: algorithm.hxx:208
vigra::ArrayVectorView< npy_intp >
vigra::NumpyArray::const_traverser
view_type::const_traverser const_traverser
Definition: numpy_array.hxx:775
vigra::NumpyArray::size_type
view_type::size_type size_type
Definition: numpy_array.hxx:755
vigra::MultiArrayView::size_type
difference_type size_type
Definition: multi_array.hxx:747
vigra::MultiArrayView< N, NumpyArrayTraits< N, T, Stride >::value_type, Stride >::data
pointer data() const
Definition: multi_array.hxx:1898
vigra::NumpyArray::NumpyArray
NumpyArray(difference_type const &shape, std::string const &order="")
Definition: numpy_array.hxx:871
vigra::TinyVectorBase< T, SIZE, T[SIZE], TinyVector< T, SIZE > >::end
iterator end()
Definition: tinyvector.hxx:864
vigra::NumpyArray::isStrictlyCompatible
static bool isStrictlyCompatible(PyObject *obj)
Definition: numpy_array.hxx:1084
vigra::NumpyArray::pointer
view_type::pointer pointer
Definition: numpy_array.hxx:739
vigra::MultiArrayIndex
std::ptrdiff_t MultiArrayIndex
Definition: multi_fwd.hxx:60
vigra::NumpyArray::const_iterator
view_type::const_iterator const_iterator
Definition: numpy_array.hxx:783
vigra::NumpyArray::traverser
view_type::traverser traverser
Definition: numpy_array.hxx:771
vigra::NumpyArray::NumpyArray
NumpyArray(PyObject *obj=0, bool createCopy=false)
Definition: numpy_array.hxx:821
vigra::MultiArrayView::const_traverser
vigra::detail::MultiIteratorChooser< StrideTag >::template Traverser< actual_dimension, T, T const &, T const * >::type const_traverser
Definition: multi_array.hxx:769
vigra::NumpyAnyArray::pyArray
PyArrayObject * pyArray() const
Definition: numpy_array.hxx:547
vigra::NumpyAnyArray::difference_type
ArrayVector< npy_intp > difference_type
difference type
Definition: numpy_array.hxx:260
vigra::NumpyAnyArray::operator=
NumpyAnyArray & operator=(NumpyAnyArray const &other)
Definition: numpy_array.hxx:330
vigra::NumpyArray::permuteLikewise
TinyVector< U, K > permuteLikewise(TinyVector< U, K > const &data) const
Definition: numpy_array.hxx:1023
vigra::NumpyArray::permuteLikewise
TinyVector< npy_intp, K > permuteLikewise() const
Definition: numpy_array.hxx:1039
vigra::NumpyAnyArray::strideOrdering
difference_type strideOrdering() const
Definition: numpy_array.hxx:422
vigra::NumpyArray::operator=
NumpyArray & operator=(const MultiArrayView< N, U, S > &other)
Definition: numpy_array.hxx:956
vigra::MultiArrayView::traverser
vigra::detail::MultiIteratorChooser< StrideTag >::template Traverser< actual_dimension, T, T &, T * >::type traverser
Definition: multi_array.hxx:764
vigra::NumpyAnyArray::hasData
bool hasData() const
Definition: numpy_array.hxx:604
vigra::NumpyArray::value_type
view_type::value_type value_type
Definition: numpy_array.hxx:735
vigra::ArrayVector< npy_intp >
vigra::NumpyArray::view_type
MultiArrayView< N, typename ArrayTraits::value_type, Stride > view_type
Definition: numpy_array.hxx:729
vigra::MultiArrayView::difference_type_1
MultiArrayIndex difference_type_1
Definition: multi_array.hxx:751
vigra::NumpyArray::standardStrideOrdering
static difference_type standardStrideOrdering()
Definition: numpy_array.hxx:1094
vigra::MultiArrayView::stride
const difference_type & stride() const
Definition: multi_array.hxx:1684
vigra::MultiArrayView::reference
value_type & reference
Definition: multi_array.hxx:723
vigra::NumpyArray::difference_type
view_type::difference_type difference_type
Definition: numpy_array.hxx:759
vigra::NumpyAnyArray::dtype
int dtype() const
Definition: numpy_array.hxx:477
vigra::TinyVectorBase< T, SIZE, T[SIZE], TinyVector< T, SIZE > >::begin
iterator begin()
Definition: tinyvector.hxx:861
vigra::NumpyAnyArray::getitem
NumpyAnyArray getitem(Shape start, Shape stop) const
Definition: numpy_array.hxx:489
vigra::NumpyArray::iterator
view_type::iterator iterator
Definition: numpy_array.hxx:779
vigra::NumpyArray::const_reference
view_type::const_reference const_reference
Definition: numpy_array.hxx:751
vigra::NumpyArray::NumpyArray
NumpyArray(TaggedShape const &tagged_shape)
Definition: numpy_array.hxx:883
vigra::MultiArrayView< N, NumpyArrayTraits< N, T, Stride >::value_type, Stride >::copy
void copy(const MultiArrayView &rhs)
Definition: multi_array.hxx:1216
vigra::NumpyArray::makeReference
bool makeReference(const NumpyAnyArray &array, bool strict=false)
Definition: numpy_array.hxx:1134
vigra::TinyVector
Class for fixed size vectors.This class contains an array of size SIZE of the specified VALUETYPE...
Definition: accessor.hxx:940
vigra::MultiArrayView::value_type
T value_type
Definition: multi_array.hxx:719
vigra::NumpyArray::reshape
void reshape(difference_type const &shape)
Definition: numpy_array.hxx:1193
vigra::NumpyAnyArray::ndim
MultiArrayIndex ndim() const
Definition: numpy_array.hxx:367
vigra::NumpyArray::isCopyCompatible
static bool isCopyCompatible(PyObject *obj)
Definition: numpy_array.hxx:1056
vigra::NumpyArray::makeReference
bool makeReference(PyObject *obj, bool=false)
Definition: numpy_array.hxx:1120
vigra::MultiArrayView::hasData
bool hasData() const
Definition: multi_array.hxx:1913
vigra::NumpyArray::reference
view_type::reference reference
Definition: numpy_array.hxx:747
vigra::abs
FFTWComplex< R >::NormType abs(const FFTWComplex< R > &a)
absolute value (= magnitude)
Definition: fftw3.hxx:1002
vigra::MultiArrayView
Base class for, and view to, vigra::MultiArray.
Definition: multi_array.hxx:704
vigra::NumpyArray::operator=
NumpyArray & operator=(const NumpyAnyArray &other)
Definition: numpy_array.hxx:983
vigra::MultiArrayView::init
MultiArrayView & init(const U &init)
Definition: multi_array.hxx:1206
vigra::MultiArrayView::pointer
value_type * pointer
Definition: multi_array.hxx:731
vigra::ArrayVectorView::size
size_type size() const
Definition: array_vector.hxx:358
vigra::NumpyAnyArray::NumpyAnyArray
NumpyAnyArray(NumpyAnyArray const &other, bool createCopy=false, PyTypeObject *type=0)
Definition: numpy_array.hxx:306
vigra::NumpyArray::operator=
NumpyArray & operator=(const NumpyArray< N, U, S > &other)
Definition: numpy_array.hxx:930
vigra::NumpyAnyArray::axistags
python_ptr axistags() const
Definition: numpy_array.hxx:531
vigra::NumpyArray
Definition: numpy_array.hxx:716
vigra::NumpyArray::makeReferenceUnchecked
void makeReferenceUnchecked(PyObject *obj)
Definition: numpy_array.hxx:1107
vigra::NumpyArray::makeCopy
void makeCopy(PyObject *obj, bool strict=false)
Definition: numpy_array.hxx:1168
vigra::MultiArrayView::operator=
MultiArrayView & operator=(MultiArrayView const &rhs)
Definition: multi_array.hxx:907
vigra::NumpyArray::reshapeIfEmpty
void reshapeIfEmpty(difference_type const &shape, std::string message="")
Definition: numpy_array.hxx:1204
vigra::MultiArrayView::const_pointer
const value_type * const_pointer
Definition: multi_array.hxx:735
vigra::NumpyArray::operator=
NumpyArray & operator=(const NumpyArray &other)
Definition: numpy_array.hxx:912
vigra::NumpyArray::const_pointer
view_type::const_pointer const_pointer
Definition: numpy_array.hxx:743
vigra::NumpyArray::permuteLikewise
ArrayVector< U > permuteLikewise(ArrayVector< U > const &data) const
Definition: numpy_array.hxx:1007
vigra::NumpyArray::NumpyArray
NumpyArray(const NumpyArray &other, bool createCopy=false)
Definition: numpy_array.hxx:839
vigra::MultiArrayView::strideOrdering
difference_type strideOrdering() const
Definition: multi_array.hxx:1617
vigra::NumpyAnyArray::makeCopy
void makeCopy(PyObject *obj, PyTypeObject *type=0)
Definition: numpy_array.hxx:590

© 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.11.0 (Fri May 19 2017)