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

numpy_array.hxx VIGRA

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 */
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 
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>
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  */
747  typedef typename view_type::reference reference;
748 
749  /** const reference type (result of operator[] const)
750  */
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  */
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  */
771  typedef typename view_type::traverser traverser;
772 
773  /** traverser type to const data
774  */
776 
777  /** sequential (random access) iterator type
778  */
779  typedef typename view_type::iterator iterator;
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(),
841  NumpyAnyArray()
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;
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;
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>
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>
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>
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);
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 {
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
const value_type & const_reference
Definition: multi_array.hxx:727
Definition: numpy_array.hxx:252
Sequential iterator for MultiArrayView.
Definition: multi_fwd.hxx:161
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
bool makeReference(PyObject *obj, PyTypeObject *type=0)
Definition: numpy_array.hxx:569
MultiArrayShape< actual_dimension >::type difference_type
Definition: multi_array.hxx:739
NumpyAnyArray::difference_type permutation_type
Definition: numpy_array.hxx:767
NumpyArray(const NumpyAnyArray &other, bool createCopy=false)
Definition: numpy_array.hxx:893
void makeUnsafeReference(const view_type &multiArrayView)
Definition: numpy_array.hxx:1149
NumpyAnyArray(PyObject *obj=0, bool createCopy=false, PyTypeObject *type=0)
Definition: numpy_array.hxx:289
void reshapeIfEmpty(TaggedShape tagged_shape, std::string message="")
Definition: numpy_array.hxx:1216
PyObject * pyObject() const
Definition: numpy_array.hxx:556
NumpyArray(const MultiArrayView< N, U, S > &other)
Definition: numpy_array.hxx:855
static bool isReferenceCompatible(PyObject *obj)
Definition: numpy_array.hxx:1075
const difference_type & shape() const
Definition: multi_array.hxx:1648
MultiArrayIndex spatialDimensions() const
Definition: numpy_array.hxx:379
view_type::difference_type_1 difference_type_1
Definition: numpy_array.hxx:763
difference_type shape() const
Definition: numpy_array.hxx:411
void linearSequence(Iterator first, Iterator last, Value start, Value step)
Fill an array with a sequence of numbers.
Definition: algorithm.hxx:208
view_type::const_traverser const_traverser
Definition: numpy_array.hxx:775
view_type::size_type size_type
Definition: numpy_array.hxx:755
difference_type size_type
Definition: multi_array.hxx:747
NumpyArray(difference_type const &shape, std::string const &order="")
Definition: numpy_array.hxx:871
static bool isStrictlyCompatible(PyObject *obj)
Definition: numpy_array.hxx:1084
view_type::pointer pointer
Definition: numpy_array.hxx:739
std::ptrdiff_t MultiArrayIndex
Definition: multi_fwd.hxx:60
view_type::const_iterator const_iterator
Definition: numpy_array.hxx:783
view_type::traverser traverser
Definition: numpy_array.hxx:771
NumpyArray(PyObject *obj=0, bool createCopy=false)
Definition: numpy_array.hxx:821
vigra::detail::MultiIteratorChooser< StrideTag >::template Traverser< actual_dimension, T, T const &, T const * >::type const_traverser
Definition: multi_array.hxx:769
PyArrayObject * pyArray() const
Definition: numpy_array.hxx:547
ArrayVector< npy_intp > difference_type
difference type
Definition: numpy_array.hxx:260
NumpyAnyArray & operator=(NumpyAnyArray const &other)
Definition: numpy_array.hxx:330
TinyVector< U, K > permuteLikewise(TinyVector< U, K > const &data) const
Definition: numpy_array.hxx:1023
TinyVector< npy_intp, K > permuteLikewise() const
Definition: numpy_array.hxx:1039
difference_type strideOrdering() const
Definition: numpy_array.hxx:422
NumpyArray & operator=(const MultiArrayView< N, U, S > &other)
Definition: numpy_array.hxx:956
vigra::detail::MultiIteratorChooser< StrideTag >::template Traverser< actual_dimension, T, T &, T * >::type traverser
Definition: multi_array.hxx:764
bool hasData() const
Definition: numpy_array.hxx:604
view_type::value_type value_type
Definition: numpy_array.hxx:735
MultiArrayView< N, typename ArrayTraits::value_type, Stride > view_type
Definition: numpy_array.hxx:729
MultiArrayIndex difference_type_1
Definition: multi_array.hxx:751
static difference_type standardStrideOrdering()
Definition: numpy_array.hxx:1094
const difference_type & stride() const
Definition: multi_array.hxx:1684
value_type & reference
Definition: multi_array.hxx:723
view_type::difference_type difference_type
Definition: numpy_array.hxx:759
int dtype() const
Definition: numpy_array.hxx:477
NumpyAnyArray getitem(Shape start, Shape stop) const
Definition: numpy_array.hxx:489
view_type::iterator iterator
Definition: numpy_array.hxx:779
view_type::const_reference const_reference
Definition: numpy_array.hxx:751
NumpyArray(TaggedShape const &tagged_shape)
Definition: numpy_array.hxx:883
void copy(const MultiArrayView &rhs)
Definition: multi_array.hxx:1216
bool makeReference(const NumpyAnyArray &array, bool strict=false)
Definition: numpy_array.hxx:1134
Class for fixed size vectors.This class contains an array of size SIZE of the specified VALUETYPE...
Definition: accessor.hxx:940
T value_type
Definition: multi_array.hxx:719
void reshape(difference_type const &shape)
Definition: numpy_array.hxx:1193
MultiArrayIndex ndim() const
Definition: numpy_array.hxx:367
static bool isCopyCompatible(PyObject *obj)
Definition: numpy_array.hxx:1056
bool makeReference(PyObject *obj, bool=false)
Definition: numpy_array.hxx:1120
bool hasData() const
Definition: multi_array.hxx:1913
view_type::reference reference
Definition: numpy_array.hxx:747
FFTWComplex< R >::NormType abs(const FFTWComplex< R > &a)
absolute value (= magnitude)
Definition: fftw3.hxx:1002
Base class for, and view to, vigra::MultiArray.
Definition: multi_array.hxx:704
NumpyArray & operator=(const NumpyAnyArray &other)
Definition: numpy_array.hxx:983
MultiArrayView & init(const U &init)
Definition: multi_array.hxx:1206
value_type * pointer
Definition: multi_array.hxx:731
size_type size() const
Definition: array_vector.hxx:358
NumpyAnyArray(NumpyAnyArray const &other, bool createCopy=false, PyTypeObject *type=0)
Definition: numpy_array.hxx:306
NumpyArray & operator=(const NumpyArray< N, U, S > &other)
Definition: numpy_array.hxx:930
python_ptr axistags() const
Definition: numpy_array.hxx:531
Definition: numpy_array.hxx:716
void makeReferenceUnchecked(PyObject *obj)
Definition: numpy_array.hxx:1107
void makeCopy(PyObject *obj, bool strict=false)
Definition: numpy_array.hxx:1168
MultiArrayView & operator=(MultiArrayView const &rhs)
Definition: multi_array.hxx:907
void reshapeIfEmpty(difference_type const &shape, std::string message="")
Definition: numpy_array.hxx:1204
const value_type * const_pointer
Definition: multi_array.hxx:735
NumpyArray & operator=(const NumpyArray &other)
Definition: numpy_array.hxx:912
view_type::const_pointer const_pointer
Definition: numpy_array.hxx:743
ArrayVector< U > permuteLikewise(ArrayVector< U > const &data) const
Definition: numpy_array.hxx:1007
NumpyArray(const NumpyArray &other, bool createCopy=false)
Definition: numpy_array.hxx:839
difference_type strideOrdering() const
Definition: multi_array.hxx:1617
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.1 (Fri May 19 2017)