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

© 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