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

© 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.10.0