[ 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)
54int _import_array();
55
56namespace vigra {
57
58static 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
79template <class T>
80class 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
149template <class TYPECODE> // pseudo-template to avoid inline expansion of the function
150 // will always be NPY_TYPES
151PyObject *
152constructArray(TaggedShape tagged_shape, TYPECODE typeCode, bool init,
153 python_ptr arraytype = python_ptr());
154
155/********************************************************/
156
157template <class Shape>
158void 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*/
253{
254 protected:
255 python_ptr pyArray_;
256
257 public:
258
259 /// 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 */
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 */
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 */
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 */
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 */
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>
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
616namespace detail {
617
618inline bool
619nontrivialPermutation(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
629template <class TYPECODE> // pseudo-template to avoid inline expansion of the function
630 // will always be NPY_TYPES
631PyObject *
632constructArray(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?
681template <class TINY_VECTOR>
682inline
683python_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*/
715template <unsigned int N, class T, class Stride = StridedArrayTag>
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 */
730
731 enum { actual_dimension = view_type::actual_dimension };
732
733 /** the array's value type
734 */
736
737 /** pointer type
738 */
739 typedef typename view_type::pointer pointer;
740
741 /** const pointer type
742 */
744
745 /** reference type (result of operator[])
746 */
748
749 /** const reference type (result of operator[] const)
750 */
752
753 /** size type
754 */
756
757 /** difference type (used for multi-dimensional offsets and indices)
758 */
760
761 /** difference and index type for a single dimension
762 */
764
765 /** type of an array specifying an axis permutation
766 */
768
769 /** traverser type
770 */
772
773 /** traverser type to const data
774 */
776
777 /** sequential (random access) iterator type
778 */
780
781 /** sequential (random access) const iterator type
782 */
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(),
842 {
843 if(!other.hasData())
844 return;
845 if(createCopy)
846 makeCopy(other.pyObject());
847 else
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 */
913 {
914 if(hasData())
915 view_type::operator=(other);
916 else
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>
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 {
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>
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 {
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 */
984 {
985 if(hasData())
986 {
988 }
989 else if(isReferenceCompatible(other.pyObject()))
990 {
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>
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>
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>
1040 {
1041 vigra_precondition(hasData(),
1042 "NumpyArray::permuteLikewise(): array has no data.");
1043
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 */
1095 {
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 {
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;
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 */
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
1240template <unsigned int N, class T, class Stride>
1241void NumpyArray<N, T, Stride>::setupArrayView()
1242{
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
1286typedef NumpyArray<2, float > NumpyFArray2;
1287typedef NumpyArray<3, float > NumpyFArray3;
1288typedef NumpyArray<4, float > NumpyFArray4;
1289typedef NumpyArray<2, Singleband<float> > NumpyFImage;
1290typedef NumpyArray<3, Singleband<float> > NumpyFVolume;
1291typedef NumpyArray<2, RGBValue<float> > NumpyFRGBImage;
1292typedef NumpyArray<3, RGBValue<float> > NumpyFRGBVolume;
1293typedef NumpyArray<3, Multiband<float> > NumpyFMultibandImage;
1294typedef NumpyArray<4, Multiband<float> > NumpyFMultibandVolume;
1295
1296/********************************************************/
1297/* */
1298/* NumpyArray Multiband Argument Object Factories */
1299/* */
1300/********************************************************/
1301
1302template <class PixelType, class Stride>
1303inline triple<ConstStridedImageIterator<PixelType>,
1305 MultibandVectorAccessor<PixelType> >
1306srcImageRange(NumpyArray<3, Multiband<PixelType>, Stride> const & img)
1307{
1309 ul(img.data(), 1, img.stride(0), img.stride(1));
1310 return triple<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
1316template <class PixelType, class Stride>
1317inline pair< ConstStridedImageIterator<PixelType>,
1318 MultibandVectorAccessor<PixelType> >
1319srcImage(NumpyArray<3, Multiband<PixelType>, Stride> const & img)
1320{
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
1327template <class PixelType, class Stride>
1328inline triple< StridedImageIterator<PixelType>,
1330 MultibandVectorAccessor<PixelType> >
1331destImageRange(NumpyArray<3, Multiband<PixelType>, Stride> & img)
1332{
1334 ul(img.data(), 1, img.stride(0), img.stride(1));
1335 return triple<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
1342template <class PixelType, class Stride>
1343inline pair< StridedImageIterator<PixelType>,
1344 MultibandVectorAccessor<PixelType> >
1345destImage(NumpyArray<3, Multiband<PixelType>, Stride> & img)
1346{
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
1353template <class PixelType, class Stride>
1354inline pair< ConstStridedImageIterator<PixelType>,
1355 MultibandVectorAccessor<PixelType> >
1356maskImage(NumpyArray<3, Multiband<PixelType>, Stride> const & img)
1357{
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
Definition array_vector.hxx:77
Definition array_vector.hxx:514
Const iterator to be used when pixels are to be skipped.
Definition imageiterator.hxx:1030
difference_type strideOrdering() const
Definition multi_array.hxx:1619
vigra::detail::MultiIteratorChooser< Stride >::template Traverser< actual_dimension, typename ArrayTraits::value_type, Tconst &, Tconst * >::type const_traverser
Definition multi_array.hxx:769
const value_type * const_pointer
Definition multi_array.hxx:735
MultiArrayIndex difference_type_1
Definition multi_array.hxx:751
typename ArrayTraits::value_type value_type
Definition multi_array.hxx:719
const difference_type & shape() const
Definition multi_array.hxx:1650
StridedScanOrderIterator< actual_dimension, typename ArrayTraits::value_type, typename ArrayTraits::value_type const &, typename ArrayTraits::value_type const * > const_iterator
Definition multi_array.hxx:759
MultiArrayView & init(const U &init)
Definition multi_array.hxx:1208
MultiArrayShape< actual_dimension >::type difference_type
Definition multi_array.hxx:739
void copy(const MultiArrayView &rhs)
Definition multi_array.hxx:1218
difference_type size_type
Definition multi_array.hxx:747
const difference_type & stride() const
Definition multi_array.hxx:1686
pointer data() const
Definition multi_array.hxx:1900
vigra::detail::MultiIteratorChooser< Stride >::template Traverser< actual_dimension, typename ArrayTraits::value_type, typename ArrayTraits::value_type &, typename ArrayTraits::value_type * >::type traverser
Definition multi_array.hxx:764
StridedScanOrderIterator< actual_dimension, typename ArrayTraits::value_type, typename ArrayTraits::value_type &, typename ArrayTraits::value_type * > iterator
Definition multi_array.hxx:755
const value_type & const_reference
Definition multi_array.hxx:727
Definition numpy_array.hxx:253
difference_type strideOrdering() const
Definition numpy_array.hxx:422
difference_type shape() const
Definition numpy_array.hxx:411
NumpyAnyArray getitem(Shape start, Shape stop) const
Definition numpy_array.hxx:489
bool hasData() const
Definition numpy_array.hxx:604
ArrayVector< npy_intp > difference_type
difference type
Definition numpy_array.hxx:260
PyObject * pyObject() const
Definition numpy_array.hxx:556
MultiArrayIndex ndim() const
Definition numpy_array.hxx:367
NumpyAnyArray & operator=(NumpyAnyArray const &other)
Definition numpy_array.hxx:330
void makeCopy(PyObject *obj, PyTypeObject *type=0)
Definition numpy_array.hxx:590
python_ptr axistags() const
Definition numpy_array.hxx:531
int dtype() const
Definition numpy_array.hxx:477
PyArrayObject * pyArray() const
Definition numpy_array.hxx:547
NumpyAnyArray(NumpyAnyArray const &other, bool createCopy=false, PyTypeObject *type=0)
Definition numpy_array.hxx:306
bool makeReference(PyObject *obj, PyTypeObject *type=0)
Definition numpy_array.hxx:569
MultiArrayIndex spatialDimensions() const
Definition numpy_array.hxx:379
NumpyAnyArray(PyObject *obj=0, bool createCopy=false, PyTypeObject *type=0)
Definition numpy_array.hxx:289
Definition numpy_array.hxx:719
difference_type strideOrdering() const
void makeUnsafeReference(const view_type &multiArrayView)
Definition numpy_array.hxx:1149
static bool isStrictlyCompatible(PyObject *obj)
Definition numpy_array.hxx:1084
view_type::const_traverser const_traverser
Definition numpy_array.hxx:775
view_type::const_reference const_reference
Definition numpy_array.hxx:751
ArrayVector< U > permuteLikewise(ArrayVector< U > const &data) const
Definition numpy_array.hxx:1007
bool hasData() const
Definition multi_array.hxx:1915
static difference_type standardStrideOrdering()
Definition numpy_array.hxx:1094
TinyVector< npy_intp, K > permuteLikewise() const
Definition numpy_array.hxx:1039
NumpyArray(const MultiArrayView< N, U, S > &other)
Definition numpy_array.hxx:855
NumpyArray & operator=(const NumpyAnyArray &other)
Definition numpy_array.hxx:983
NumpyArray(PyObject *obj=0, bool createCopy=false)
Definition numpy_array.hxx:821
view_type::size_type size_type
Definition numpy_array.hxx:755
void reshapeIfEmpty(difference_type const &shape, std::string message="")
Definition numpy_array.hxx:1204
static bool isCopyCompatible(PyObject *obj)
Definition numpy_array.hxx:1056
static bool isReferenceCompatible(PyObject *obj)
Definition numpy_array.hxx:1075
NumpyArray & operator=(const NumpyArray< N, U, S > &other)
Definition numpy_array.hxx:930
bool makeReference(PyObject *obj, bool=false)
Definition numpy_array.hxx:1120
view_type::iterator iterator
Definition numpy_array.hxx:779
view_type::difference_type_1 difference_type_1
Definition numpy_array.hxx:763
view_type::const_pointer const_pointer
Definition numpy_array.hxx:743
const difference_type & shape() const
Definition multi_array.hxx:1650
TinyVector< U, K > permuteLikewise(TinyVector< U, K > const &data) const
Definition numpy_array.hxx:1023
view_type::difference_type difference_type
Definition numpy_array.hxx:759
view_type::pointer pointer
Definition numpy_array.hxx:739
view_type::reference reference
Definition numpy_array.hxx:747
void reshape(difference_type const &shape)
Definition numpy_array.hxx:1193
void makeReferenceUnchecked(PyObject *obj)
Definition numpy_array.hxx:1107
MultiArrayView< N, typename ArrayTraits::value_type, Stride > view_type
Definition numpy_array.hxx:729
NumpyArray(difference_type const &shape, std::string const &order="")
Definition numpy_array.hxx:871
void makeCopy(PyObject *obj, bool strict=false)
Definition numpy_array.hxx:1168
view_type::const_iterator const_iterator
Definition numpy_array.hxx:783
NumpyAnyArray::difference_type permutation_type
Definition numpy_array.hxx:767
NumpyArray(TaggedShape const &tagged_shape)
Definition numpy_array.hxx:883
void reshapeIfEmpty(TaggedShape tagged_shape, std::string message="")
Definition numpy_array.hxx:1216
bool makeReference(const NumpyAnyArray &array, bool strict=false)
Definition numpy_array.hxx:1134
NumpyArray & operator=(const MultiArrayView< N, U, S > &other)
Definition numpy_array.hxx:956
NumpyArray(const NumpyAnyArray &other, bool createCopy=false)
Definition numpy_array.hxx:893
view_type::traverser traverser
Definition numpy_array.hxx:771
view_type::value_type value_type
Definition numpy_array.hxx:735
NumpyArray(const NumpyArray &other, bool createCopy=false)
Definition numpy_array.hxx:839
NumpyArray & operator=(const NumpyArray &other)
Definition numpy_array.hxx:912
Two dimensional size object.
Definition diff2d.hxx:483
Iterator to be used when pixels are to be skipped.
Definition imageiterator.hxx:969
Class for fixed size vectors.
Definition tinyvector.hxx:1008
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 abs(const FFTWComplex< R > &a)
absolute value (= magnitude)
Definition fftw3.hxx:1002
std::ptrdiff_t MultiArrayIndex
Definition multi_fwd.hxx:60
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

© 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)