36 #ifndef VIGRA_NUMPY_ARRAY_HXX
37 #define VIGRA_NUMPY_ARRAY_HXX
46 #include <vigra/multi_array.hxx>
47 #include <vigra/array_vector.hxx>
48 #include <vigra/sized_int.hxx>
49 #include <vigra/python_utility.hxx>
50 #include <numpy/arrayobject.h>
62 typedef float NumpyValueType;
77 struct NumericTraits<Singleband<T> >
78 :
public NumericTraits<T>
82 struct NumericTraits<Multiband<T> >
84 typedef Multiband<T> Type;
91 typedef Type ValueType;
93 typedef typename NumericTraits<T>::isIntegral isIntegral;
94 typedef VigraFalseType isScalar;
95 typedef typename NumericTraits<T>::isSigned isSigned;
96 typedef typename NumericTraits<T>::isSigned isOrdered;
97 typedef typename NumericTraits<T>::isSigned isComplex;
130 class MultibandVectorAccessor
141 typedef Multiband<T> value_type;
145 typedef T component_type;
147 typedef VectorElementAccessor<MultibandVectorAccessor<T> > ElementAccessor;
152 template <
class ITERATOR>
153 component_type
const & getComponent(ITERATOR
const & i,
int idx)
const
155 return *(&*i+idx*stride_);
163 template <
class V,
class ITERATOR>
164 void setComponent(V
const & value, ITERATOR
const & i,
int idx)
const
166 *(&*i+idx*stride_) = detail::RequiresExplicitCast<component_type>::cast(value);
172 template <
class ITERATOR,
class DIFFERENCE>
173 component_type
const & getComponent(ITERATOR
const & i, DIFFERENCE
const & diff,
int idx)
const
175 return *(&i[diff]+idx*stride_);
183 template <
class V,
class ITERATOR,
class DIFFERENCE>
185 setComponent(V
const & value, ITERATOR
const & i, DIFFERENCE
const & diff,
int idx)
const
187 *(&i[diff]+idx*stride_) = detail::RequiresExplicitCast<component_type>::cast(value);
205 inline long spatialDimensions(PyObject * obj)
207 static python_ptr key(PyString_FromString(
"spatialDimensions"), python_ptr::keep_count);
208 python_ptr pres(PyObject_GetAttr(obj, key), python_ptr::keep_count);
209 long res = pres && PyInt_Check(pres)
230 typedef std::map<std::string, std::pair<python_ptr, python_ptr> > ArrayTypeMap;
232 VIGRA_EXPORT ArrayTypeMap * getArrayTypeMap();
234 #define NUMPY_ARRAY_INITIALIZE_REGISTRY \
235 namespace vigra { namespace detail { \
236 ArrayTypeMap * getArrayTypeMap() \
238 static ArrayTypeMap arrayTypeMap; \
239 return &arrayTypeMap; \
241 }} // namespace vigra::detail
243 #define NUMPY_ARRAY_DUMMY_REGISTRY \
244 namespace vigra { namespace detail { \
245 ArrayTypeMap * getArrayTypeMap() \
249 }} // namespace vigra::detail
252 void registerPythonArrayType(std::string
const & name, PyObject * obj, PyObject * typecheck)
254 ArrayTypeMap *types = getArrayTypeMap();
257 "registerPythonArrayType(): module was compiled without array type registry.");
259 obj && PyType_Check(obj) && PyType_IsSubtype((PyTypeObject *)obj, &PyArray_Type),
260 "registerPythonArrayType(obj): obj is not a subtype of numpy.ndarray.");
261 if(typecheck && PyCallable_Check(typecheck))
262 (*types)[name] = std::make_pair(python_ptr(obj), python_ptr(typecheck));
264 (*types)[name] = std::make_pair(python_ptr(obj), python_ptr());
269 python_ptr getArrayTypeObject(std::string
const & name, PyTypeObject * def = 0)
271 ArrayTypeMap *types = getArrayTypeMap();
274 return python_ptr((PyObject *)def);
277 ArrayTypeMap::iterator i = types->find(name);
278 if(i != types->end())
279 res = i->second.first;
281 res = python_ptr((PyObject *)def);
291 getArrayTypecheckFunction(std::string
const & keyFull, std::string
const & key)
294 ArrayTypeMap *types = getArrayTypeMap();
297 ArrayTypeMap::iterator i = types->find(keyFull);
298 if(i == types->end())
299 i = types->find(key);
300 if(i != types->end())
301 res = i->second.second;
307 performCustomizedArrayTypecheck(PyObject * obj, std::string
const & keyFull, std::string
const & key)
309 if(obj == 0 || !PyArray_Check(obj))
311 python_ptr typecheck = getArrayTypecheckFunction(keyFull, key);
314 python_ptr args(PyTuple_Pack(1, obj), python_ptr::keep_count);
315 pythonToCppException(args);
316 python_ptr res(PyObject_Call(typecheck.get(), args.get(), 0), python_ptr::keep_count);
317 pythonToCppException(res);
318 vigra_precondition(PyBool_Check(res),
319 "NumpyArray conversion: registered typecheck function did not return a boolean.");
320 return (
void*)res.get() == (
void*)Py_True;
324 python_ptr constructNumpyArrayImpl(
326 ArrayVector<npy_intp>
const & shape, npy_intp *strides,
327 NPY_TYPES typeCode,
bool init)
333 array = python_ptr(PyArray_New(type, shape.size(), (npy_intp *)shape.begin(), typeCode, 0, 0, 0, 1 , 0),
334 python_ptr::keep_count);
338 int N = shape.size();
339 ArrayVector<npy_intp> pshape(N);
340 for(
int k=0; k<N; ++k)
341 pshape[strides[k]] = shape[k];
343 array = python_ptr(PyArray_New(type, N, pshape.begin(), typeCode, 0, 0, 0, 1 , 0),
344 python_ptr::keep_count);
345 pythonToCppException(array);
347 PyArray_Dims permute = { strides, N };
348 array = python_ptr(PyArray_Transpose((PyArrayObject*)array.get(), &permute), python_ptr::keep_count);
350 pythonToCppException(array);
353 PyArray_FILLWBYTE((PyArrayObject *)array.get(), 0);
362 constructNumpyArrayImpl(PyTypeObject * type, ArrayVector<npy_intp>
const & shape,
363 unsigned int spatialDimensions,
unsigned int channels,
364 NPY_TYPES typeCode, std::string order,
bool init,
365 ArrayVector<npy_intp> strideOrdering = ArrayVector<npy_intp>())
368 vigra_precondition(shape.size() == spatialDimensions || shape.size() == spatialDimensions + 1,
369 "constructNumpyArray(type, shape, ...): shape has wrong length.");
373 vigra_precondition(strideOrdering.size() == 0 || strideOrdering.size() == spatialDimensions ||
374 strideOrdering.size() == spatialDimensions + 1,
375 "constructNumpyArray(type, ..., strideOrdering): strideOrdering has wrong length.");
380 if(shape.size() == spatialDimensions)
383 channels = shape.back();
388 if(shape.size() > spatialDimensions)
389 vigra_precondition(channels == (
unsigned int)shape[spatialDimensions],
390 "constructNumpyArray(type, ...): shape contradicts requested number of channels.");
394 unsigned int shapeSize = channels == 1
396 : spatialDimensions + 1;
399 ArrayVector<npy_intp> pshape(shapeSize);
400 std::copy(shape.begin(), shape.begin()+std::min(shape.size(), pshape.size()), pshape.begin());
401 if(shapeSize > spatialDimensions)
402 pshape[spatialDimensions] = channels;
409 if(strideOrdering.size() == 0)
413 else if(strideOrdering.size() > shapeSize)
416 ArrayVector<npy_intp> pstride(strideOrdering.begin(), strideOrdering.begin()+shapeSize);
419 if(strideOrdering[shapeSize] == 0)
420 for(
unsigned int k=0; k<shapeSize; ++k)
422 pstride.swap(strideOrdering);
424 else if(strideOrdering.size() < shapeSize)
427 ArrayVector<npy_intp> pstride(shapeSize);
430 for(
unsigned int k=0; k<shapeSize-1; ++k)
431 pstride[k] = strideOrdering[k] + 1;
432 pstride[shapeSize-1] = 0;
433 pstride.swap(strideOrdering);
441 strideOrdering.resize(shapeSize);
442 for(
unsigned int k=0; k<shapeSize; ++k)
443 strideOrdering[k] = shapeSize-1-k;
445 else if(order ==
"F" || (order ==
"V" && channels == 1))
447 strideOrdering.resize(shapeSize);
448 for(
unsigned int k=0; k<shapeSize; ++k)
449 strideOrdering[k] = k;
451 else if(order ==
"V")
453 strideOrdering.resize(shapeSize);
454 for(
unsigned int k=0; k<shapeSize-1; ++k)
455 strideOrdering[k] = k+1;
456 strideOrdering[shapeSize-1] = 0;
459 return constructNumpyArrayImpl(type, pshape, strideOrdering.begin(), typeCode, init);
462 template <
class TINY_VECTOR>
464 python_ptr constructNumpyArrayFromData(
465 std::string
const & typeKeyFull,
466 std::string
const & typeKey,
467 TINY_VECTOR
const & shape, npy_intp *strides,
468 NPY_TYPES typeCode,
void *data)
470 ArrayVector<npy_intp> pyShape(shape.begin(), shape.end());
472 python_ptr type = detail::getArrayTypeObject(typeKeyFull);
474 type = detail::getArrayTypeObject(typeKey, &PyArray_Type);
476 python_ptr array(PyArray_New((PyTypeObject *)type.ptr(), shape.size(), pyShape.begin(), typeCode, strides, data, 0, NPY_WRITEABLE, 0),
477 python_ptr::keep_count);
478 pythonToCppException(array);
492 template<
class ValueType>
493 struct ERROR_NumpyArrayValuetypeTraits_not_specialized_for_ { };
495 template<
class ValueType>
496 struct NumpyArrayValuetypeTraits
498 static bool isValuetypeCompatible(PyArrayObject
const * obj)
500 return ERROR_NumpyArrayValuetypeTraits_not_specialized_for_<ValueType>();
503 static ERROR_NumpyArrayValuetypeTraits_not_specialized_for_<ValueType> typeCode;
505 static std::string typeName()
507 return std::string(
"ERROR: NumpyArrayValuetypeTraits not specialized for this case");
510 static std::string typeNameImpex()
512 return std::string(
"ERROR: NumpyArrayValuetypeTraits not specialized for this case");
515 static PyObject * typeObject()
517 return (PyObject *)0;
521 template<
class ValueType>
522 ERROR_NumpyArrayValuetypeTraits_not_specialized_for_<ValueType> NumpyArrayValuetypeTraits<ValueType>::typeCode;
524 #define VIGRA_NUMPY_VALUETYPE_TRAITS(type, typeID, numpyTypeName, impexTypeName) \
526 struct NumpyArrayValuetypeTraits<type > \
528 static bool isValuetypeCompatible(PyArrayObject const * obj) \
530 return PyArray_EquivTypenums(typeID, PyArray_DESCR((PyObject *)obj)->type_num) && \
531 PyArray_ITEMSIZE((PyObject *)obj) == sizeof(type); \
534 static NPY_TYPES const typeCode = typeID; \
536 static std::string typeName() \
538 return #numpyTypeName; \
541 static std::string typeNameImpex() \
543 return impexTypeName; \
546 static PyObject * typeObject() \
548 return PyArray_TypeObjectFromType(typeID); \
552 VIGRA_NUMPY_VALUETYPE_TRAITS(
bool, NPY_BOOL,
bool,
"UINT8")
553 VIGRA_NUMPY_VALUETYPE_TRAITS(
signed char, NPY_INT8, int8, "INT16")
554 VIGRA_NUMPY_VALUETYPE_TRAITS(
unsigned char, NPY_UINT8, uint8, "UINT8")
555 VIGRA_NUMPY_VALUETYPE_TRAITS(
short, NPY_INT16, int16, "INT16")
556 VIGRA_NUMPY_VALUETYPE_TRAITS(
unsigned short, NPY_UINT16, uint16, "UINT16")
558 #if VIGRA_BITSOF_LONG == 32
559 VIGRA_NUMPY_VALUETYPE_TRAITS(
long, NPY_INT32, int32,
"INT32")
560 VIGRA_NUMPY_VALUETYPE_TRAITS(
unsigned long, NPY_UINT32, uint32, "UINT32")
561 #elif VIGRA_BITSOF_LONG == 64
562 VIGRA_NUMPY_VALUETYPE_TRAITS(
long, NPY_INT64, int64,
"DOUBLE")
563 VIGRA_NUMPY_VALUETYPE_TRAITS(
unsigned long, NPY_UINT64, uint64, "DOUBLE")
566 #if VIGRA_BITSOF_INT == 32
567 VIGRA_NUMPY_VALUETYPE_TRAITS(
int, NPY_INT32, int32,
"INT32")
568 VIGRA_NUMPY_VALUETYPE_TRAITS(
unsigned int, NPY_UINT32, uint32, "UINT32")
569 #elif VIGRA_BITSOF_INT == 64
570 VIGRA_NUMPY_VALUETYPE_TRAITS(
int, NPY_INT64, int64,
"DOUBLE")
571 VIGRA_NUMPY_VALUETYPE_TRAITS(
unsigned int, NPY_UINT64, uint64, "DOUBLE")
575 # if VIGRA_BITSOF_LONG_LONG == 32
576 VIGRA_NUMPY_VALUETYPE_TRAITS(
long long, NPY_INT32, int32,
"INT32")
577 VIGRA_NUMPY_VALUETYPE_TRAITS(
unsigned long long, NPY_UINT32, uint32, "UINT32")
578 # elif VIGRA_BITSOF_LONG_LONG == 64
579 VIGRA_NUMPY_VALUETYPE_TRAITS(
long long, NPY_INT64, int64,
"DOUBLE")
580 VIGRA_NUMPY_VALUETYPE_TRAITS(
unsigned long long, NPY_UINT64, uint64, "DOUBLE")
584 VIGRA_NUMPY_VALUETYPE_TRAITS(npy_float32, NPY_FLOAT32, float32,
"FLOAT")
585 VIGRA_NUMPY_VALUETYPE_TRAITS(npy_float64, NPY_FLOAT64, float64, "DOUBLE")
586 #if NPY_SIZEOF_LONGDOUBLE != NPY_SIZEOF_DOUBLE
587 VIGRA_NUMPY_VALUETYPE_TRAITS(npy_longdouble, NPY_LONGDOUBLE, longdouble,
"")
589 VIGRA_NUMPY_VALUETYPE_TRAITS(npy_cfloat, NPY_CFLOAT, complex64,
"")
590 VIGRA_NUMPY_VALUETYPE_TRAITS(std::complex<npy_float>, NPY_CFLOAT, complex64, "")
591 VIGRA_NUMPY_VALUETYPE_TRAITS(npy_cdouble, NPY_CDOUBLE, complex128, "")
592 VIGRA_NUMPY_VALUETYPE_TRAITS(std::complex<npy_double>, NPY_CDOUBLE, complex128, "")
593 VIGRA_NUMPY_VALUETYPE_TRAITS(npy_clongdouble, NPY_CLONGDOUBLE, clongdouble, "")
594 #if NPY_SIZEOF_LONGDOUBLE != NPY_SIZEOF_DOUBLE
595 VIGRA_NUMPY_VALUETYPE_TRAITS(std::complex<npy_longdouble>, NPY_CLONGDOUBLE, clongdouble,
"")
598 #undef VIGRA_NUMPY_VALUETYPE_TRAITS
606 template <
class U,
int N>
607 bool stridesAreAscending(TinyVector<U, N>
const & strides)
609 for(
int k=1; k<N; ++k)
610 if(strides[k] < strides[k-1])
615 template<
unsigned int N,
class T,
class Str
ide>
616 struct NumpyArrayTraits;
618 template<
unsigned int N,
class T>
619 struct NumpyArrayTraits<N, T, StridedArrayTag>
622 typedef T value_type;
623 typedef NumpyArrayValuetypeTraits<T> ValuetypeTraits;
624 static NPY_TYPES
const typeCode = ValuetypeTraits::typeCode;
626 enum { spatialDimensions = N, channels = 1 };
628 static bool isArray(PyObject * obj)
630 return obj && PyArray_Check(obj);
633 static bool isClassCompatible(PyObject * obj)
635 return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(), typeKey());
638 static bool isValuetypeCompatible(PyArrayObject * obj)
640 return ValuetypeTraits::isValuetypeCompatible(obj);
643 static bool isShapeCompatible(PyArrayObject * obj)
645 return PyArray_NDIM((PyObject *)obj) == N-1 ||
646 PyArray_NDIM((PyObject *)obj) == N ||
647 (PyArray_NDIM((PyObject *)obj) == N+1 && PyArray_DIM((PyObject *)obj, N) == 1);
650 static bool isPropertyCompatible(PyArrayObject * obj)
652 return ValuetypeTraits::isValuetypeCompatible(obj) &&
653 isShapeCompatible(obj);
657 static python_ptr constructor(TinyVector<U, N>
const & shape,
658 T *data, TinyVector<U, N>
const & stride)
660 TinyVector<npy_intp, N> npyStride(stride *
sizeof(T));
661 return detail::constructNumpyArrayFromData(typeKeyFull(), typeKey(), shape, npyStride.begin(), ValuetypeTraits::typeCode, data);
664 static std::string typeKey()
666 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
", *>";
670 static std::string typeKeyFull()
672 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
", " +
673 ValuetypeTraits::typeName() +
", StridedArrayTag>";
680 template<
unsigned int N,
class T>
681 struct NumpyArrayTraits<N, T, UnstridedArrayTag>
682 :
public NumpyArrayTraits<N, T, StridedArrayTag>
684 typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType;
685 typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
687 static bool isShapeCompatible(PyArrayObject * obj)
689 return BaseType::isShapeCompatible(obj) &&
690 PyArray_STRIDES((PyObject *)obj)[0] == PyArray_ITEMSIZE((PyObject *)obj);
693 static bool isPropertyCompatible(PyArrayObject * obj)
695 return BaseType::isValuetypeCompatible(obj) &&
696 isShapeCompatible(obj);
700 static python_ptr constructor(TinyVector<U, N>
const & shape,
701 T *data, TinyVector<U, N>
const & stride)
703 TinyVector<npy_intp, N> npyStride(stride *
sizeof(T));
704 return detail::constructNumpyArrayFromData(typeKeyFull(), BaseType::typeKey(), shape, npyStride.begin(), ValuetypeTraits::typeCode, data);
707 static std::string typeKeyFull()
709 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
", " +
710 ValuetypeTraits::typeName() +
", UnstridedArrayTag>";
717 template<
unsigned int N,
class T>
718 struct NumpyArrayTraits<N, Singleband<T>, StridedArrayTag>
719 :
public NumpyArrayTraits<N, T, StridedArrayTag>
721 typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType;
722 typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
724 static bool isClassCompatible(PyObject * obj)
726 return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(), typeKey());
730 static python_ptr constructor(TinyVector<U, N>
const & shape,
731 T *data, TinyVector<U, N>
const & stride)
733 TinyVector<npy_intp, N> npyStride(stride *
sizeof(T));
734 return detail::constructNumpyArrayFromData(typeKeyFull(), typeKey(), shape, npyStride.begin(), ValuetypeTraits::typeCode, data);
737 static std::string typeKey()
739 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
", Singleband<*> >";
743 static std::string typeKeyFull()
745 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
", Singleband<" +
746 ValuetypeTraits::typeName() +
">, StridedArrayTag>";
753 template<
unsigned int N,
class T>
754 struct NumpyArrayTraits<N, Singleband<T>, UnstridedArrayTag>
755 :
public NumpyArrayTraits<N, Singleband<T>, StridedArrayTag>
757 typedef NumpyArrayTraits<N, T, UnstridedArrayTag> UnstridedTraits;
758 typedef NumpyArrayTraits<N, Singleband<T>, StridedArrayTag> BaseType;
759 typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
761 static bool isShapeCompatible(PyArrayObject * obj)
763 return UnstridedTraits::isShapeCompatible(obj);
766 static bool isPropertyCompatible(PyArrayObject * obj)
768 return UnstridedTraits::isPropertyCompatible(obj);
772 static python_ptr constructor(TinyVector<U, N>
const & shape,
773 T *data, TinyVector<U, N>
const & stride)
775 TinyVector<npy_intp, N> npyStride(stride *
sizeof(T));
776 return detail::constructNumpyArrayFromData(typeKeyFull(), BaseType::typeKey(), shape, npyStride.begin(), ValuetypeTraits::typeCode, data);
779 static std::string typeKeyFull()
781 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
", Singleband<" +
782 ValuetypeTraits::typeName() +
">, UnstridedArrayTag>";
789 template<
unsigned int N,
class T>
790 struct NumpyArrayTraits<N, Multiband<T>, StridedArrayTag>
791 :
public NumpyArrayTraits<N, T, StridedArrayTag>
793 typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType;
794 typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
796 enum { spatialDimensions = N-1, channels = 0 };
798 static bool isClassCompatible(PyObject * obj)
800 return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(), typeKey());
803 static bool isShapeCompatible(PyArrayObject * obj)
805 return PyArray_NDIM(obj) == N || PyArray_NDIM(obj) == N-1;
808 static bool isPropertyCompatible(PyArrayObject * obj)
810 return ValuetypeTraits::isValuetypeCompatible(obj) &&
811 isShapeCompatible(obj);
815 static python_ptr constructor(TinyVector<U, N>
const & shape,
816 T *data, TinyVector<U, N>
const & stride)
818 TinyVector<npy_intp, N> npyStride(stride *
sizeof(T));
819 return detail::constructNumpyArrayFromData(typeKeyFull(), typeKey(), shape, npyStride.begin(), ValuetypeTraits::typeCode, data);
822 static std::string typeKey()
824 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
", Multiband<*> >";
828 static std::string typeKeyFull()
830 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
", Multiband<" +
831 ValuetypeTraits::typeName() +
">, StridedArrayTag>";
838 template<
unsigned int N,
class T>
839 struct NumpyArrayTraits<N, Multiband<T>, UnstridedArrayTag>
840 :
public NumpyArrayTraits<N, Multiband<T>, StridedArrayTag>
842 typedef NumpyArrayTraits<N, Multiband<T>, StridedArrayTag> BaseType;
843 typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
845 static bool isShapeCompatible(PyArrayObject * obj)
847 return BaseType::isShapeCompatible(obj) &&
848 PyArray_STRIDES((PyObject *)obj)[0] == PyArray_ITEMSIZE((PyObject *)obj);
851 static bool isPropertyCompatible(PyArrayObject * obj)
853 return BaseType::isValuetypeCompatible(obj) &&
854 isShapeCompatible(obj);
858 static python_ptr constructor(TinyVector<U, N>
const & shape,
859 T *data, TinyVector<U, N>
const & stride)
861 TinyVector<npy_intp, N> npyStride(stride *
sizeof(T));
862 return detail::constructNumpyArrayFromData(typeKeyFull(), BaseType::typeKey(), shape, npyStride.begin(), ValuetypeTraits::typeCode, data);
865 static std::string typeKeyFull()
867 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
", Multiband<" +
868 ValuetypeTraits::typeName() +
">, UnstridedArrayTag>";
875 template<
unsigned int N,
int M,
class T>
876 struct NumpyArrayTraits<N, TinyVector<T, M>, StridedArrayTag>
879 typedef TinyVector<T, M> value_type;
880 typedef NumpyArrayValuetypeTraits<T> ValuetypeTraits;
881 static NPY_TYPES
const typeCode = ValuetypeTraits::typeCode;
883 enum { spatialDimensions = N, channels = M };
885 static bool isArray(PyObject * obj)
887 return obj && PyArray_Check(obj);
890 static bool isClassCompatible(PyObject * obj)
892 return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(), typeKey());
895 static bool isValuetypeCompatible(PyArrayObject * obj)
897 return ValuetypeTraits::isValuetypeCompatible(obj);
900 static bool isShapeCompatible(PyArrayObject * obj)
902 return PyArray_NDIM((PyObject *)obj) == N+1 &&
903 PyArray_DIM((PyObject *)obj, N) == M &&
904 PyArray_STRIDES((PyObject *)obj)[N] == PyArray_ITEMSIZE((PyObject *)obj);
907 static bool isPropertyCompatible(PyArrayObject * obj)
909 return ValuetypeTraits::isValuetypeCompatible(obj) &&
910 isShapeCompatible(obj);
914 static python_ptr constructor(TinyVector<U, N>
const & shape,
915 T *data, TinyVector<U, N>
const & stride)
917 TinyVector<npy_intp, N+1> npyShape;
918 std::copy(shape.begin(), shape.end(), npyShape.begin());
921 TinyVector<npy_intp, N+1> npyStride;
923 stride.begin(), stride.end(), npyStride.begin(),
924 std::bind2nd(std::multiplies<npy_intp>(),
sizeof(value_type)));
925 npyStride[N] =
sizeof(T);
927 return detail::constructNumpyArrayFromData(
928 typeKeyFull(), typeKey(), npyShape,
929 npyStride.begin(), ValuetypeTraits::typeCode, data);
932 static std::string typeKey()
934 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
", TinyVector<*, " +
asString(M) +
"> >";
938 static std::string typeKeyFull()
940 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
941 ", TinyVector<" + ValuetypeTraits::typeName() +
", " +
asString(M) +
">, StridedArrayTag>";
948 template<
unsigned int N,
int M,
class T>
949 struct NumpyArrayTraits<N, TinyVector<T, M>, UnstridedArrayTag>
950 :
public NumpyArrayTraits<N, TinyVector<T, M>, StridedArrayTag>
952 typedef NumpyArrayTraits<N, TinyVector<T, M>, StridedArrayTag> BaseType;
953 typedef typename BaseType::value_type value_type;
954 typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
956 static bool isShapeCompatible(PyArrayObject * obj)
958 return BaseType::isShapeCompatible(obj) &&
959 PyArray_STRIDES((PyObject *)obj)[0] ==
sizeof(TinyVector<T, M>);
962 static bool isPropertyCompatible(PyArrayObject * obj)
964 return BaseType::isValuetypeCompatible(obj) &&
965 isShapeCompatible(obj);
969 static python_ptr constructor(TinyVector<U, N>
const & shape,
970 T *data, TinyVector<U, N>
const & stride)
972 TinyVector<npy_intp, N+1> npyShape;
973 std::copy(shape.begin(), shape.end(), npyShape.begin());
976 TinyVector<npy_intp, N+1> npyStride;
978 stride.begin(), stride.end(), npyStride.begin(),
979 std::bind2nd(std::multiplies<npy_intp>(),
sizeof(value_type)));
980 npyStride[N] =
sizeof(T);
982 return detail::constructNumpyArrayFromData(
983 typeKeyFull(), BaseType::typeKey(), npyShape,
984 npyStride.begin(), ValuetypeTraits::typeCode, data);
987 static std::string typeKeyFull()
989 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
990 ", TinyVector<" + ValuetypeTraits::typeName() +
", " +
asString(M) +
">, UnstridedArrayTag>";
997 template<
unsigned int N,
class T>
998 struct NumpyArrayTraits<N, RGBValue<T>, StridedArrayTag>
999 :
public NumpyArrayTraits<N, TinyVector<T, 3>, StridedArrayTag>
1002 typedef RGBValue<T> value_type;
1003 typedef NumpyArrayValuetypeTraits<T> ValuetypeTraits;
1005 static bool isClassCompatible(PyObject * obj)
1007 return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(), typeKey());
1011 static python_ptr constructor(TinyVector<U, N>
const & shape,
1012 T *data, TinyVector<U, N>
const & stride)
1014 TinyVector<npy_intp, N+1> npyShape;
1015 std::copy(shape.begin(), shape.end(), npyShape.begin());
1018 TinyVector<npy_intp, N+1> npyStride;
1020 stride.begin(), stride.end(), npyStride.begin(),
1021 std::bind2nd(std::multiplies<npy_intp>(),
sizeof(value_type)));
1022 npyStride[N] =
sizeof(T);
1024 return detail::constructNumpyArrayFromData(
1025 typeKeyFull(), typeKey(), npyShape,
1026 npyStride.begin(), ValuetypeTraits::typeCode, data);
1029 static std::string typeKey()
1031 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
", RGBValue<*> >";
1035 static std::string typeKeyFull()
1037 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
1038 ", RGBValue<" + ValuetypeTraits::typeName() +
">, StridedArrayTag>";
1045 template<
unsigned int N,
class T>
1046 struct NumpyArrayTraits<N, RGBValue<T>, UnstridedArrayTag>
1047 :
public NumpyArrayTraits<N, RGBValue<T>, StridedArrayTag>
1049 typedef NumpyArrayTraits<N, TinyVector<T, 3>, UnstridedArrayTag> UnstridedTraits;
1050 typedef NumpyArrayTraits<N, RGBValue<T>, StridedArrayTag> BaseType;
1051 typedef typename BaseType::value_type value_type;
1052 typedef typename BaseType::ValuetypeTraits ValuetypeTraits;
1054 static bool isShapeCompatible(PyArrayObject * obj)
1056 return UnstridedTraits::isShapeCompatible(obj);
1059 static bool isPropertyCompatible(PyArrayObject * obj)
1061 return UnstridedTraits::isPropertyCompatible(obj);
1065 static python_ptr constructor(TinyVector<U, N>
const & shape,
1066 T *data, TinyVector<U, N>
const & stride)
1068 TinyVector<npy_intp, N+1> npyShape;
1069 std::copy(shape.begin(), shape.end(), npyShape.begin());
1072 TinyVector<npy_intp, N+1> npyStride;
1074 stride.begin(), stride.end(), npyStride.begin(),
1075 std::bind2nd(std::multiplies<npy_intp>(),
sizeof(value_type)));
1076 npyStride[N] =
sizeof(T);
1078 return detail::constructNumpyArrayFromData(
1079 typeKeyFull(), BaseType::typeKey(), npyShape,
1080 npyStride.begin(), ValuetypeTraits::typeCode, data);
1083 static std::string typeKeyFull()
1085 static std::string key = std::string(
"NumpyArray<") +
asString(N) +
1086 ", RGBValue<" + ValuetypeTraits::typeName() +
">, UnstridedArrayTag>";
1111 python_ptr pyArray_;
1120 for(
int k=0; k<M; ++k)
1121 permutation[k] = M-1-k;
1127 PyArray_Dims permute = { permutation.
begin(), (int) M };
1128 python_ptr array(PyArray_Transpose(
pyArray(), &permute), python_ptr::keep_count);
1129 pythonToCppException(array);
1145 explicit NumpyAnyArray(PyObject * obj = 0,
bool createCopy =
false, PyTypeObject * type = 0)
1149 vigra_precondition(type == 0 || PyType_IsSubtype(type, &PyArray_Type),
1150 "NumpyAnyArray(obj, createCopy, type): type must be numpy.ndarray or a subclass thereof.");
1154 vigra_precondition(
makeReference(obj, type),
"NumpyAnyArray(obj): obj isn't a numpy array.");
1166 vigra_precondition(type == 0 || PyType_IsSubtype(type, &PyArray_Type),
1167 "NumpyAnyArray(obj, createCopy, type): type must be numpy.ndarray or a subclass thereof.");
1190 vigra_precondition(other.
hasData(),
1191 "NumpyArray::operator=(): Cannot assign from empty array.");
1192 if(PyArray_CopyInto(permuteChannelsToFront().
pyArray(), other.permuteChannelsToFront().
pyArray()) == -1)
1193 pythonToCppException(0);
1197 pyArray_ = other.pyArray_;
1248 difference_type stride(PyArray_STRIDES(
pyObject()), PyArray_STRIDES(
pyObject()) + N),
1257 if(stride[j] < stride[smallest])
1262 std::swap(stride[k], stride[smallest]);
1263 std::swap(permutation[k], permutation[smallest]);
1266 difference_type ordering(N);
1268 ordering[permutation[k]] = k;
1279 return PyArray_DESCR(
pyObject())->type_num;
1288 return (PyArrayObject *)pyArray_.get();
1297 return pyArray_.get();
1310 if(obj == 0 || !PyArray_Check(obj))
1314 vigra_precondition(PyType_IsSubtype(type, &PyArray_Type) != 0,
1315 "NumpyAnyArray::makeReference(obj, type): type must be numpy.ndarray or a subclass thereof.");
1316 obj = PyArray_View((PyArrayObject*)obj, 0, type);
1317 pythonToCppException(obj);
1319 pyArray_.reset(obj);
1331 vigra_precondition(obj && PyArray_Check(obj),
1332 "NumpyAnyArray::makeCopy(obj): obj is not an array.");
1333 vigra_precondition(type == 0 || PyType_IsSubtype(type, &PyArray_Type),
1334 "NumpyAnyArray::makeCopy(obj, type): type must be numpy.ndarray or a subclass thereof.");
1335 python_ptr array(PyArray_NewCopy((PyArrayObject*)obj, NPY_ANYORDER), python_ptr::keep_count);
1336 pythonToCppException(array);
1345 return pyArray_ != 0;
1363 template <
unsigned int N,
class T,
class Str
ide = Str
idedArrayTag>
1365 :
public MultiArrayView<N, typename NumpyArrayTraits<N, T, Stride>::value_type, Stride>,
1369 typedef NumpyArrayTraits<N, T, Stride> ArrayTraits;
1370 typedef typename ArrayTraits::dtype
dtype;
1371 typedef T pseudo_value_type;
1373 static NPY_TYPES
const typeCode = ArrayTraits::typeCode;
1379 enum { actual_dimension = view_type::actual_dimension };
1436 void setupArrayView();
1438 static python_ptr getArrayTypeObject()
1440 python_ptr type = detail::getArrayTypeObject(ArrayTraits::typeKeyFull());
1442 type = detail::getArrayTypeObject(ArrayTraits::typeKey(), &PyArray_Type);
1446 static python_ptr init(
difference_type const & shape,
bool init =
true)
1449 return detail::constructNumpyArrayImpl((PyTypeObject *)getArrayTypeObject().ptr(), pshape,
1450 ArrayTraits::spatialDimensions, ArrayTraits::channels,
1451 typeCode,
"V", init);
1456 ArrayVector<npy_intp> pshape(shape.begin(), shape.end()),
1457 pstrideOrdering(strideOrdering.begin(), strideOrdering.end());
1458 return detail::constructNumpyArrayImpl((PyTypeObject *)getArrayTypeObject().ptr(), pshape,
1459 ArrayTraits::spatialDimensions, ArrayTraits::channels,
1460 typeCode,
"A", init, pstrideOrdering);
1465 using view_type::init;
1488 "NumpyArray(obj): Cannot construct from incompatible array.");
1507 makeReferenceUnchecked(other.
pyObject());
1518 "NumpyArray(view_type): Python constructor did not produce a compatible array.");
1519 static_cast<view_type &
>(*this) = other;
1532 "NumpyArray(shape): Python constructor did not produce a compatible array.");
1544 vigra_postcondition(
makeReference(init(shape, strideOrdering)),
1545 "NumpyArray(shape): Python constructor did not produce a compatible array.");
1560 "NumpyArray(NumpyAnyArray): Cannot construct from incompatible or empty array.");
1576 makeReferenceUnchecked(other.
pyObject());
1594 else if(isStrictlyCompatible(other.
pyObject()))
1596 makeReferenceUnchecked(other.
pyObject());
1600 vigra_precondition(
false,
1601 "NumpyArray::operator=(): Cannot assign from incompatible array.");
1612 static bool isCopyCompatible(PyObject *obj)
1614 return ArrayTraits::isArray(obj) &&
1615 ArrayTraits::isShapeCompatible((PyArrayObject *)obj);
1624 static bool isReferenceCompatible(PyObject *obj)
1626 return ArrayTraits::isArray(obj) &&
1627 ArrayTraits::isPropertyCompatible((PyArrayObject *)obj);
1638 static bool isStrictlyCompatible(PyObject *obj)
1640 #if VIGRA_CONVERTER_DEBUG
1641 std::cerr <<
"class " <<
typeid(
NumpyArray).name() <<
" got " << obj->ob_type->tp_name <<
"\n";
1642 bool isClassCompatible=ArrayTraits::isClassCompatible(obj);
1643 bool isPropertyCompatible((PyArrayObject *)obj);
1644 std::cerr<<
"isClassCompatible: "<<isClassCompatible<<std::endl;
1645 std::cerr<<
"isPropertyCompatible: "<<isPropertyCompatible<<std::endl;
1647 return ArrayTraits::isClassCompatible(obj) &&
1648 ArrayTraits::isPropertyCompatible((PyArrayObject *)obj);
1659 for(
unsigned int k=0; k<N; ++k)
1660 strideOrdering[k] = k;
1669 void makeReferenceUnchecked(PyObject *obj)
1686 if(!isStrictlyCompatible(obj))
1691 if(!isReferenceCompatible(obj))
1694 makeReferenceUnchecked(obj);
1720 vigra_precondition(!
hasData(),
"makeReference(): cannot replace existing view with given buffer");
1723 python_ptr array(ArrayTraits::constructor(multiArrayView.
shape(), multiArrayView.
data(), multiArrayView.
stride()));
1737 vigra_precondition(strict ? isStrictlyCompatible(obj) : isCopyCompatible(obj),
1738 "NumpyArray::makeCopy(obj): Cannot copy an incompatible array.");
1740 int M = PyArray_NDIM(obj);
1742 std::copy(PyArray_DIMS(obj), PyArray_DIMS(obj)+M, shape.
begin());
1746 "NumpyArray::makeCopy(obj): Copy created an incompatible array.");
1763 vigra_postcondition(
makeReference(init(shape, strideOrdering)),
1764 "NumpyArray(shape): Python constructor did not produce a compatible array.");
1774 reshapeIfEmpty(shape, standardStrideOrdering(), message);
1784 std::string message =
"",
bool strict =
false)
1791 message =
"NumpyArray::reshapeIfEmpty(shape): array was not empty, and shape or stride ordering did not match.";
1792 vigra_precondition(shape == this->
shape() && strideOrdering == this->
strideOrdering(), message.c_str());
1797 message =
"NumpyArray::reshapeIfEmpty(shape): array was not empty, and shape did not match.";
1798 vigra_precondition(shape == this->
shape(), message.c_str());
1803 reshape(shape, strideOrdering);
1809 template <
unsigned int N,
class T,
class Str
ide>
1810 void NumpyArray<N, T, Stride>::setupArrayView()
1814 unsigned int dimension = std::min<unsigned int>(actual_dimension,
pyArray()->nd);
1815 std::copy(
pyArray()->dimensions,
pyArray()->dimensions + dimension, this->m_shape.begin());
1816 std::copy(
pyArray()->strides,
pyArray()->strides + dimension, this->m_stride.begin());
1817 if(
pyArray()->nd < actual_dimension)
1819 this->m_shape[dimension] = 1;
1820 this->m_stride[dimension] =
sizeof(value_type);
1822 this->m_stride /=
sizeof(value_type);
1823 this->m_ptr =
reinterpret_cast<pointer
>(
pyArray()->data);
1832 typedef NumpyArray<2, float > NumpyFArray2;
1833 typedef NumpyArray<3, float > NumpyFArray3;
1834 typedef NumpyArray<4, float > NumpyFArray4;
1835 typedef NumpyArray<2, Singleband<float> > NumpyFImage;
1836 typedef NumpyArray<3, Singleband<float> > NumpyFVolume;
1837 typedef NumpyArray<2, RGBValue<float> > NumpyFRGBImage;
1838 typedef NumpyArray<3, RGBValue<float> > NumpyFRGBVolume;
1839 typedef NumpyArray<3, Multiband<float> > NumpyFMultibandImage;
1840 typedef NumpyArray<4, Multiband<float> > NumpyFMultibandVolume;
1842 inline void import_vigranumpy()
1844 if(_import_array() < 0)
1845 pythonToCppException(0);
1846 python_ptr module(PyImport_ImportModule(
"vigra.vigranumpycore"), python_ptr::keep_count);
1847 pythonToCppException(module);
1856 template <
class PixelType,
class Str
ide>
1857 inline triple<ConstStridedImageIterator<PixelType>,
1858 ConstStridedImageIterator<PixelType>,
1859 MultibandVectorAccessor<PixelType> >
1860 srcImageRange(NumpyArray<3, Multiband<PixelType>, Stride>
const & img)
1862 ConstStridedImageIterator<PixelType>
1863 ul(img.data(), 1, img.stride(0), img.stride(1));
1864 return triple<ConstStridedImageIterator<PixelType>,
1865 ConstStridedImageIterator<PixelType>,
1866 MultibandVectorAccessor<PixelType> >
1867 (ul, ul + Size2D(img.shape(0), img.shape(1)), MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2)));
1870 template <
class PixelType,
class Str
ide>
1871 inline pair< ConstStridedImageIterator<PixelType>,
1872 MultibandVectorAccessor<PixelType> >
1873 srcImage(NumpyArray<3, Multiband<PixelType>, Stride>
const & img)
1875 ConstStridedImageIterator<PixelType>
1876 ul(img.data(), 1, img.stride(0), img.stride(1));
1877 return pair<ConstStridedImageIterator<PixelType>, MultibandVectorAccessor<PixelType> >
1878 (ul, MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2)));
1881 template <
class PixelType,
class Str
ide>
1882 inline triple< StridedImageIterator<PixelType>,
1883 StridedImageIterator<PixelType>,
1884 MultibandVectorAccessor<PixelType> >
1885 destImageRange(NumpyArray<3, Multiband<PixelType>, Stride> & img)
1887 StridedImageIterator<PixelType>
1888 ul(img.data(), 1, img.stride(0), img.stride(1));
1889 typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
1890 return triple<StridedImageIterator<PixelType>,
1891 StridedImageIterator<PixelType>,
1892 MultibandVectorAccessor<PixelType> >
1893 (ul, ul + Size2D(img.shape(0), img.shape(1)),
1894 MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2)));
1897 template <
class PixelType,
class Str
ide>
1898 inline pair< StridedImageIterator<PixelType>,
1899 MultibandVectorAccessor<PixelType> >
1900 destImage(NumpyArray<3, Multiband<PixelType>, Stride> & img)
1902 StridedImageIterator<PixelType>
1903 ul(img.data(), 1, img.stride(0), img.stride(1));
1904 return pair<StridedImageIterator<PixelType>, MultibandVectorAccessor<PixelType> >
1905 (ul, MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2)));
1908 template <
class PixelType,
class Str
ide>
1909 inline pair< ConstStridedImageIterator<PixelType>,
1910 MultibandVectorAccessor<PixelType> >
1911 maskImage(NumpyArray<3, Multiband<PixelType>, Stride>
const & img)
1913 ConstStridedImageIterator<PixelType>
1914 ul(img.data(), 1, img.stride(0), img.stride(1));
1915 typedef typename AccessorTraits<PixelType>::default_accessor Accessor;
1916 return pair<ConstStridedImageIterator<PixelType>, MultibandVectorAccessor<PixelType> >
1917 (ul, MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2)));
1922 #endif // VIGRA_NUMPY_ARRAY_HXX