36 #ifndef VIGRA_NUMPY_ARRAY_HXX
37 #define VIGRA_NUMPY_ARRAY_HXX
39 #ifndef NPY_NO_DEPRECATED_API
40 # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
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"
58 static inline void import_vigranumpy()
61 if(_import_array() < 0)
62 pythonToCppException(0);
66 char const * load_vigra =
68 "if not sys.modules.has_key('vigra.vigranumpycore'):\n"
70 pythonToCppException(PyRun_SimpleString(load_vigra) == 0);
80 class MultibandVectorAccessor
91 typedef Multiband<T> value_type;
95 typedef T component_type;
97 typedef VectorElementAccessor<MultibandVectorAccessor<T> > ElementAccessor;
102 template <
class ITERATOR>
103 component_type
const & getComponent(ITERATOR
const & i,
int idx)
const
105 return *(&*i+idx*stride_);
113 template <
class V,
class ITERATOR>
114 void setComponent(V
const & value, ITERATOR
const & i,
int idx)
const
116 *(&*i+idx*stride_) = detail::RequiresExplicitCast<component_type>::cast(value);
122 template <
class ITERATOR,
class DIFFERENCE>
123 component_type
const & getComponent(ITERATOR
const & i, DIFFERENCE
const & diff,
int idx)
const
125 return *(&i[diff]+idx*stride_);
133 template <
class V,
class ITERATOR,
class DIFFERENCE>
135 setComponent(V
const & value, ITERATOR
const & i, DIFFERENCE
const & diff,
int idx)
const
137 *(&i[diff]+idx*stride_) = detail::RequiresExplicitCast<component_type>::cast(value);
149 template <
class TYPECODE>
152 constructArray(TaggedShape tagged_shape, TYPECODE typeCode,
bool init,
153 python_ptr arraytype = python_ptr());
182 static python_ptr getArrayTypeObject()
184 return detail::getArrayTypeObject();
187 static std::string defaultOrder(std::string defaultValue =
"C")
189 return detail::defaultOrder(defaultValue);
192 static python_ptr defaultAxistags(
int ndim, std::string order =
"")
194 return detail::defaultAxistags(ndim, order);
197 static python_ptr emptyAxistags(
int ndim)
199 return detail::emptyAxistags(ndim);
209 explicit NumpyAnyArray(PyObject * obj = 0,
bool createCopy =
false, PyTypeObject * type = 0)
213 vigra_precondition(type == 0 || PyType_IsSubtype(type, &PyArray_Type),
214 "NumpyAnyArray(obj, createCopy, type): type must be numpy.ndarray or a subclass thereof.");
218 vigra_precondition(
makeReference(obj, type),
"NumpyAnyArray(obj): obj isn't a numpy array.");
230 vigra_precondition(type == 0 || PyType_IsSubtype(type, &PyArray_Type),
231 "NumpyAnyArray(obj, createCopy, type): type must be numpy.ndarray or a subclass thereof.");
254 vigra_precondition(other.
hasData(),
255 "NumpyArray::operator=(): Cannot assign from empty array.");
257 python_ptr arraytype = getArrayTypeObject();
258 python_ptr f(PyString_FromString(
"_copyValuesImpl"), python_ptr::keep_count);
259 if(PyObject_HasAttr(arraytype, f))
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.");
269 PyArrayObject * sarray = (PyArrayObject *)pyArray_.get();
270 PyArrayObject * tarray = (PyArrayObject *)other.pyArray_.get();
272 if(PyArray_CopyInto(tarray, sarray) == -1)
273 pythonToCppException(0);
278 pyArray_ = other.pyArray_;
290 return PyArray_NDIM(
pyArray());
303 return pythonGetAttr(
pyObject(),
"spatialDimensions",
ndim());
306 bool hasChannelAxis()
const
310 return channelIndex() ==
ndim();
317 return pythonGetAttr(
pyObject(),
"channelIndex",
ndim());
324 return pythonGetAttr(
pyObject(),
"innerNonchannelIndex",
ndim());
356 if(stride[j] < stride[smallest])
361 std::swap(stride[k], stride[smallest]);
362 std::swap(permutation[k], permutation[smallest]);
367 ordering[permutation[k]] = k;
400 return PyArray_DESCR(
pyArray())->type_num;
413 python_ptr key(PyString_FromString(
"axistags"), python_ptr::keep_count);
414 axistags.reset(PyObject_GetAttr(
pyObject(), key), python_ptr::keep_count);
426 return (PyArrayObject *)pyArray_.get();
435 return pyArray_.get();
448 if(obj == 0 || !PyArray_Check(obj))
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);
467 void makeCopy(PyObject * obj, PyTypeObject * type = 0)
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);
483 return pyArray_ != 0;
496 nontrivialPermutation(ArrayVector<npy_intp>
const & p)
498 for(
unsigned int k=0; k<p.size(); ++k)
506 template <
class TYPECODE>
509 constructArray(TaggedShape tagged_shape, TYPECODE typeCode,
bool init, python_ptr arraytype)
511 ArrayVector<npy_intp> shape = finalizeTaggedShape(tagged_shape);
512 PyAxisTags axistags(tagged_shape.axistags);
514 int ndim = (int)shape.size();
515 ArrayVector<npy_intp> inverse_permutation;
521 arraytype = NumpyAnyArray::getArrayTypeObject();
523 inverse_permutation = axistags.permutationFromNormalOrder();
524 vigra_precondition(ndim == (
int)inverse_permutation.size(),
525 "axistags.permutationFromNormalOrder(): permutation has wrong size.");
529 arraytype = python_ptr((PyObject*)&PyArray_Type);
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);
540 if(detail::nontrivialPermutation(inverse_permutation))
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);
548 if(arraytype != (PyObject*)&PyArray_Type && axistags)
549 pythonToCppException(PyObject_SetAttrString(array,
"axistags", axistags.axistags) != -1);
552 PyArray_FILLWBYTE((PyArrayObject *)array.get(), 0);
554 return array.release();
558 template <
class TINY_VECTOR>
560 python_ptr constructNumpyArrayFromData(
561 TINY_VECTOR
const & shape, npy_intp *strides,
562 NPY_TYPES typeCode,
void *data)
564 ArrayVector<npy_intp> pyShape(shape.begin(), shape.end());
566 #ifndef NPY_ARRAY_WRITEABLE
567 # define NPY_ARRAY_WRITEABLE NPY_WRITEABLE // old API compatibility
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);
592 template <
unsigned int N,
class T,
class Str
ide = Str
idedArrayTag>
594 :
public MultiArrayView<N, typename NumpyArrayTraits<N, T, Stride>::value_type, Stride>,
598 typedef NumpyArrayTraits<N, T, Stride> ArrayTraits;
599 typedef typename ArrayTraits::dtype
dtype;
600 typedef T pseudo_value_type;
602 static NPY_TYPES
const typeCode = ArrayTraits::typeCode;
608 enum { actual_dimension = view_type::actual_dimension };
669 void setupArrayView();
671 static python_ptr init(
difference_type const & shape,
bool init =
true,
672 std::string
const & order =
"")
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);
698 explicit NumpyArray(PyObject *obj = 0,
bool createCopy =
false)
706 "NumpyArray(obj): Cannot construct from incompatible array.");
731 template <
class U,
class S>
737 "NumpyArray(MultiArrayView): Python constructor did not produce a compatible array.");
751 "NumpyArray(shape): Python constructor did not produce a compatible array.");
763 "NumpyArray(tagged_shape): Python constructor did not produce a compatible array.");
778 "NumpyArray(NumpyAnyArray): Cannot construct from incompatible or empty array.");
806 template <
class U,
class S>
812 "NumpyArray::operator=(): shape mismatch.");
819 "NumpyArray::operator=(): reshape failed unexpectedly.");
832 template <
class U,
class S>
838 "NumpyArray::operator=(): shape mismatch.");
845 "NumpyArray::operator=(): reshape failed unexpectedly.");
872 vigra_precondition(
false,
873 "NumpyArray::operator=(): Cannot assign from incompatible array.");
887 "NumpyArray::permuteLikewise(): array has no data.");
890 ArrayTraits::permuteLikewise(this->pyArray_, data, res);
898 template <
class U,
int K>
903 "NumpyArray::permuteLikewise(): array has no data.");
906 ArrayTraits::permuteLikewise(this->pyArray_, data, res);
919 "NumpyArray::permuteLikewise(): array has no data.");
923 ArrayTraits::permuteLikewise(this->pyArray_, data, res);
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;
942 return ArrayTraits::isArray(obj) &&
943 ArrayTraits::isShapeCompatible((PyArrayObject *)obj);
954 return ArrayTraits::isArray(obj) &&
955 ArrayTraits::isPropertyCompatible((PyArrayObject *)obj);
974 for(
unsigned int k=0; k<N; ++k)
975 strideOrdering[k] = k;
1028 vigra_precondition(!
hasData(),
1029 "makeUnsafeReference(): cannot replace existing view with given buffer");
1032 python_ptr array(ArrayTraits::unsafeConstructorFromData(multiArrayView.
shape(),
1033 multiArrayView.
data(), multiArrayView.
stride()));
1047 #if VIGRA_CONVERTER_DEBUG
1048 int ndim = PyArray_NDIM((PyArrayObject *)obj);
1049 npy_intp * s = PyArray_DIMS((PyArrayObject *)obj);
1052 std::cerr <<
"for " <<
typeid(*this).name() <<
"\n";
1055 "NumpyArray::makeCopy(obj): Cannot copy an incompatible array.");
1073 "NumpyArray.reshape(shape): Python constructor did not produce a compatible array.");
1095 ArrayTraits::finalizeTaggedShape(tagged_shape);
1099 vigra_precondition(tagged_shape.compatible(taggedShape()), message.c_str());
1103 python_ptr array(constructArray(tagged_shape, typeCode,
true),
1104 python_ptr::keep_count);
1106 "NumpyArray.reshapeIfEmpty(): Python constructor did not produce a compatible array.");
1110 TaggedShape taggedShape()
const
1112 return ArrayTraits::taggedShape(this->
shape(), PyAxisTags(this->
axistags(),
true));
1117 template <
unsigned int N,
class T,
class Str
ide>
1118 void NumpyArray<N, T, Stride>::setupArrayView()
1122 permutation_type permute;
1123 ArrayTraits::permutationToSetupOrder(this->pyArray_, permute);
1125 vigra_precondition(
abs((
int)permute.size() - actual_dimension) <= 1,
1126 "NumpyArray::setupArrayView(): got array of incompatible shape (should never happen).");
1129 PyArray_DIMS(pyArray()), this->m_shape.begin());
1131 PyArray_STRIDES(pyArray()), this->m_stride.begin());
1133 if((
int)permute.size() == actual_dimension - 1)
1135 this->m_shape[actual_dimension-1] = 1;
1136 this->m_stride[actual_dimension-1] =
sizeof(value_type);
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).");
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;
1168 template <
class PixelType,
class Str
ide>
1169 inline triple<ConstStridedImageIterator<PixelType>,
1170 ConstStridedImageIterator<PixelType>,
1171 MultibandVectorAccessor<PixelType> >
1172 srcImageRange(NumpyArray<3, Multiband<PixelType>, Stride>
const & img)
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)));
1182 template <
class PixelType,
class Str
ide>
1183 inline pair< ConstStridedImageIterator<PixelType>,
1184 MultibandVectorAccessor<PixelType> >
1185 srcImage(NumpyArray<3, Multiband<PixelType>, Stride>
const & img)
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)));
1193 template <
class PixelType,
class Str
ide>
1194 inline triple< StridedImageIterator<PixelType>,
1195 StridedImageIterator<PixelType>,
1196 MultibandVectorAccessor<PixelType> >
1197 destImageRange(NumpyArray<3, Multiband<PixelType>, Stride> & img)
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)));
1208 template <
class PixelType,
class Str
ide>
1209 inline pair< StridedImageIterator<PixelType>,
1210 MultibandVectorAccessor<PixelType> >
1211 destImage(NumpyArray<3, Multiband<PixelType>, Stride> & img)
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)));
1219 template <
class PixelType,
class Str
ide>
1220 inline pair< ConstStridedImageIterator<PixelType>,
1221 MultibandVectorAccessor<PixelType> >
1222 maskImage(NumpyArray<3, Multiband<PixelType>, Stride>
const & img)
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)));
1232 #endif // VIGRA_NUMPY_ARRAY_HXX