[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]
vigra/numpy_array.hxx | ![]() |
00001 /************************************************************************/ 00002 /* */ 00003 /* Copyright 2009 by Ullrich Koethe and Hans Meine */ 00004 /* */ 00005 /* This file is part of the VIGRA computer vision library. */ 00006 /* The VIGRA Website is */ 00007 /* http://hci.iwr.uni-heidelberg.de/vigra/ */ 00008 /* Please direct questions, bug reports, and contributions to */ 00009 /* ullrich.koethe@iwr.uni-heidelberg.de or */ 00010 /* vigra@informatik.uni-hamburg.de */ 00011 /* */ 00012 /* Permission is hereby granted, free of charge, to any person */ 00013 /* obtaining a copy of this software and associated documentation */ 00014 /* files (the "Software"), to deal in the Software without */ 00015 /* restriction, including without limitation the rights to use, */ 00016 /* copy, modify, merge, publish, distribute, sublicense, and/or */ 00017 /* sell copies of the Software, and to permit persons to whom the */ 00018 /* Software is furnished to do so, subject to the following */ 00019 /* conditions: */ 00020 /* */ 00021 /* The above copyright notice and this permission notice shall be */ 00022 /* included in all copies or substantial portions of the */ 00023 /* Software. */ 00024 /* */ 00025 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */ 00026 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ 00027 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 00028 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ 00029 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ 00030 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ 00031 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ 00032 /* OTHER DEALINGS IN THE SOFTWARE. */ 00033 /* */ 00034 /************************************************************************/ 00035 00036 #ifndef VIGRA_NUMPY_ARRAY_HXX 00037 #define VIGRA_NUMPY_ARRAY_HXX 00038 00039 #include <iostream> 00040 #include <algorithm> 00041 #include <complex> 00042 #include <string> 00043 #include <sstream> 00044 #include <map> 00045 #include <vigra/multi_array.hxx> 00046 #include <vigra/array_vector.hxx> 00047 #include <vigra/sized_int.hxx> 00048 #include <vigra/python_utility.hxx> 00049 #include <Python.h> 00050 #include <numpy/arrayobject.h> 00051 00052 int _import_array(); 00053 00054 namespace vigra { 00055 00056 /********************************************************/ 00057 /* */ 00058 /* Singleband and Multiband */ 00059 /* */ 00060 /********************************************************/ 00061 00062 typedef float NumpyValueType; 00063 00064 template <class T> 00065 struct Singleband // the last array dimension is not to be interpreted as a channel dimension 00066 { 00067 typedef T value_type; 00068 }; 00069 00070 template <class T> 00071 struct Multiband // the last array dimension is a channel dimension 00072 { 00073 typedef T value_type; 00074 }; 00075 00076 template<class T> 00077 struct NumericTraits<Singleband<T> > 00078 : public NumericTraits<T> 00079 {}; 00080 00081 template<class T> 00082 struct NumericTraits<Multiband<T> > 00083 { 00084 typedef Multiband<T> Type; 00085 /* 00086 typedef int Promote; 00087 typedef unsigned int UnsignedPromote; 00088 typedef double RealPromote; 00089 typedef std::complex<RealPromote> ComplexPromote; 00090 */ 00091 typedef Type ValueType; 00092 00093 typedef typename NumericTraits<T>::isIntegral isIntegral; 00094 typedef VigraFalseType isScalar; 00095 typedef typename NumericTraits<T>::isSigned isSigned; 00096 typedef typename NumericTraits<T>::isSigned isOrdered; 00097 typedef typename NumericTraits<T>::isSigned isComplex; 00098 /* 00099 static signed char zero() { return 0; } 00100 static signed char one() { return 1; } 00101 static signed char nonZero() { return 1; } 00102 static signed char min() { return SCHAR_MIN; } 00103 static signed char max() { return SCHAR_MAX; } 00104 00105 #ifdef NO_INLINE_STATIC_CONST_DEFINITION 00106 enum { minConst = SCHAR_MIN, maxConst = SCHAR_MIN }; 00107 #else 00108 static const signed char minConst = SCHAR_MIN; 00109 static const signed char maxConst = SCHAR_MIN; 00110 #endif 00111 00112 static Promote toPromote(signed char v) { return v; } 00113 static RealPromote toRealPromote(signed char v) { return v; } 00114 static signed char fromPromote(Promote v) { 00115 return ((v < SCHAR_MIN) ? SCHAR_MIN : (v > SCHAR_MAX) ? SCHAR_MAX : v); 00116 } 00117 static signed char fromRealPromote(RealPromote v) { 00118 return ((v < 0.0) 00119 ? ((v < (RealPromote)SCHAR_MIN) 00120 ? SCHAR_MIN 00121 : static_cast<signed char>(v - 0.5)) 00122 : (v > (RealPromote)SCHAR_MAX) 00123 ? SCHAR_MAX 00124 : static_cast<signed char>(v + 0.5)); 00125 } 00126 */ 00127 }; 00128 00129 template <class T> 00130 class MultibandVectorAccessor 00131 { 00132 MultiArrayIndex size_, stride_; 00133 00134 public: 00135 MultibandVectorAccessor(MultiArrayIndex size, MultiArrayIndex stride) 00136 : size_(size), 00137 stride_(stride) 00138 {} 00139 00140 00141 typedef Multiband<T> value_type; 00142 00143 /** the vector's value_type 00144 */ 00145 typedef T component_type; 00146 00147 typedef VectorElementAccessor<MultibandVectorAccessor<T> > ElementAccessor; 00148 00149 /** Read the component data at given vector index 00150 at given iterator position 00151 */ 00152 template <class ITERATOR> 00153 component_type const & getComponent(ITERATOR const & i, int idx) const 00154 { 00155 return *(&*i+idx*stride_); 00156 } 00157 00158 /** Set the component data at given vector index 00159 at given iterator position. The type <TT>V</TT> of the passed 00160 in <TT>value</TT> is automatically converted to <TT>component_type</TT>. 00161 In case of a conversion floating point -> intergral this includes rounding and clipping. 00162 */ 00163 template <class V, class ITERATOR> 00164 void setComponent(V const & value, ITERATOR const & i, int idx) const 00165 { 00166 *(&*i+idx*stride_) = detail::RequiresExplicitCast<component_type>::cast(value); 00167 } 00168 00169 /** Read the component data at given vector index 00170 at an offset of given iterator position 00171 */ 00172 template <class ITERATOR, class DIFFERENCE> 00173 component_type const & getComponent(ITERATOR const & i, DIFFERENCE const & diff, int idx) const 00174 { 00175 return *(&i[diff]+idx*stride_); 00176 } 00177 00178 /** Set the component data at given vector index 00179 at an offset of given iterator position. The type <TT>V</TT> of the passed 00180 in <TT>value</TT> is automatically converted to <TT>component_type</TT>. 00181 In case of a conversion floating point -> intergral this includes rounding and clipping. 00182 */ 00183 template <class V, class ITERATOR, class DIFFERENCE> 00184 void 00185 setComponent(V const & value, ITERATOR const & i, DIFFERENCE const & diff, int idx) const 00186 { 00187 *(&i[diff]+idx*stride_) = detail::RequiresExplicitCast<component_type>::cast(value); 00188 } 00189 00190 template <class U> 00191 MultiArrayIndex size(U) const 00192 { 00193 return size_; 00194 } 00195 }; 00196 00197 /********************************************************/ 00198 /* */ 00199 /* a few Python utilities */ 00200 /* */ 00201 /********************************************************/ 00202 00203 namespace detail { 00204 00205 inline long spatialDimensions(PyObject * obj) 00206 { 00207 static python_ptr key(PyString_FromString("spatialDimensions"), python_ptr::keep_count); 00208 python_ptr pres(PyObject_GetAttr(obj, key), python_ptr::keep_count); 00209 long res = pres && PyInt_Check(pres) 00210 ? PyInt_AsLong(pres) 00211 : -1; 00212 return res; 00213 } 00214 00215 /* 00216 * The registry is used to optionally map specific C++ types to 00217 * specific python sub-classes of numpy.ndarray (for example, 00218 * MultiArray<2, Singleband<int> > to a user-defined Python class 'ScalarImage'). 00219 * 00220 * One needs to use NUMPY_ARRAY_INITIALIZE_REGISTRY once in a python 00221 * extension module using this technique, in order to actually provide 00222 * the registry (this is done by vigranumpycmodule and will then be 00223 * available for other modules, too). Alternatively, 00224 * NUMPY_ARRAY_DUMMY_REGISTRY may be used to disable this feature 00225 * completely. In both cases, the macro must not be enclosed by any 00226 * namespace, so it is best put right at the beginning of the file 00227 * (e.g. below the #includes). 00228 */ 00229 00230 typedef std::map<std::string, std::pair<python_ptr, python_ptr> > ArrayTypeMap; 00231 00232 VIGRA_EXPORT ArrayTypeMap * getArrayTypeMap(); 00233 00234 #define NUMPY_ARRAY_INITIALIZE_REGISTRY \ 00235 namespace vigra { namespace detail { \ 00236 ArrayTypeMap * getArrayTypeMap() \ 00237 { \ 00238 static ArrayTypeMap arrayTypeMap; \ 00239 return &arrayTypeMap; \ 00240 } \ 00241 }} // namespace vigra::detail 00242 00243 #define NUMPY_ARRAY_DUMMY_REGISTRY \ 00244 namespace vigra { namespace detail { \ 00245 ArrayTypeMap * getArrayTypeMap() \ 00246 { \ 00247 return NULL; \ 00248 } \ 00249 }} // namespace vigra::detail 00250 00251 inline 00252 void registerPythonArrayType(std::string const & name, PyObject * obj, PyObject * typecheck) 00253 { 00254 ArrayTypeMap *types = getArrayTypeMap(); 00255 vigra_precondition( 00256 types != NULL, 00257 "registerPythonArrayType(): module was compiled without array type registry."); 00258 vigra_precondition( 00259 obj && PyType_Check(obj) && PyType_IsSubtype((PyTypeObject *)obj, &PyArray_Type), 00260 "registerPythonArrayType(obj): obj is not a subtype of numpy.ndarray."); 00261 if(typecheck && PyCallable_Check(typecheck)) 00262 (*types)[name] = std::make_pair(python_ptr(obj), python_ptr(typecheck)); 00263 else 00264 (*types)[name] = std::make_pair(python_ptr(obj), python_ptr()); 00265 // std::cerr << "Registering " << ((PyTypeObject *)obj)->tp_name << " for " << name << "\n"; 00266 } 00267 00268 inline 00269 python_ptr getArrayTypeObject(std::string const & name, PyTypeObject * def = 0) 00270 { 00271 ArrayTypeMap *types = getArrayTypeMap(); 00272 if(!types) 00273 // dummy registry -> handle like empty registry 00274 return python_ptr((PyObject *)def); 00275 00276 python_ptr res; 00277 ArrayTypeMap::iterator i = types->find(name); 00278 if(i != types->end()) 00279 res = i->second.first; 00280 else 00281 res = python_ptr((PyObject *)def); 00282 // std::cerr << "Requested " << name << ", got " << ((PyTypeObject *)res.get())->tp_name << "\n"; 00283 return res; 00284 } 00285 00286 // there are two cases for the return: 00287 // * if a typecheck function was registered, it is returned 00288 // * a null pointer is returned if nothing was registered for either key, or if 00289 // a type was registered without typecheck function 00290 inline python_ptr 00291 getArrayTypecheckFunction(std::string const & keyFull, std::string const & key) 00292 { 00293 python_ptr res; 00294 ArrayTypeMap *types = getArrayTypeMap(); 00295 if(types) 00296 { 00297 ArrayTypeMap::iterator i = types->find(keyFull); 00298 if(i == types->end()) 00299 i = types->find(key); 00300 if(i != types->end()) 00301 res = i->second.second; 00302 } 00303 return res; 00304 } 00305 00306 inline bool 00307 performCustomizedArrayTypecheck(PyObject * obj, std::string const & keyFull, std::string const & key) 00308 { 00309 if(obj == 0 || !PyArray_Check(obj)) 00310 return false; 00311 python_ptr typecheck = getArrayTypecheckFunction(keyFull, key); 00312 if(typecheck == 0) 00313 return true; // no custom test registered 00314 python_ptr args(PyTuple_Pack(1, obj), python_ptr::keep_count); 00315 pythonToCppException(args); 00316 python_ptr res(PyObject_Call(typecheck.get(), args.get(), 0), python_ptr::keep_count); 00317 pythonToCppException(res); 00318 vigra_precondition(PyBool_Check(res), 00319 "NumpyArray conversion: registered typecheck function did not return a boolean."); 00320 return res.get() == Py_True; 00321 } 00322 00323 inline 00324 python_ptr constructNumpyArrayImpl( 00325 PyTypeObject * type, 00326 ArrayVector<npy_intp> const & shape, npy_intp *strides, 00327 NPY_TYPES typeCode, bool init) 00328 { 00329 python_ptr array; 00330 00331 if(strides == 0) 00332 { 00333 array = python_ptr(PyArray_New(type, shape.size(), (npy_intp *)shape.begin(), typeCode, 0, 0, 0, 1 /* Fortran order */, 0), 00334 python_ptr::keep_count); 00335 } 00336 else 00337 { 00338 int N = shape.size(); 00339 ArrayVector<npy_intp> pshape(N); 00340 for(int k=0; k<N; ++k) 00341 pshape[strides[k]] = shape[k]; 00342 00343 array = python_ptr(PyArray_New(type, N, pshape.begin(), typeCode, 0, 0, 0, 1 /* Fortran order */, 0), 00344 python_ptr::keep_count); 00345 pythonToCppException(array); 00346 00347 PyArray_Dims permute = { strides, N }; 00348 array = python_ptr(PyArray_Transpose((PyArrayObject*)array.get(), &permute), python_ptr::keep_count); 00349 } 00350 pythonToCppException(array); 00351 00352 if(init) 00353 PyArray_FILLWBYTE((PyArrayObject *)array.get(), 0); 00354 00355 return array; 00356 } 00357 00358 // strideOrdering will be ignored unless order == "A" 00359 // TODO: this function should receive some refactoring in order to make 00360 // the rules clear from the code rather than from comments 00361 inline python_ptr 00362 constructNumpyArrayImpl(PyTypeObject * type, ArrayVector<npy_intp> const & shape, 00363 unsigned int spatialDimensions, unsigned int channels, 00364 NPY_TYPES typeCode, std::string order, bool init, 00365 ArrayVector<npy_intp> strideOrdering = ArrayVector<npy_intp>()) 00366 { 00367 // shape must have at least length spatialDimensions, but can also have a channel dimension 00368 vigra_precondition(shape.size() == spatialDimensions || shape.size() == spatialDimensions + 1, 00369 "constructNumpyArray(type, shape, ...): shape has wrong length."); 00370 00371 // if strideOrdering is given, it must have at least length spatialDimensions, 00372 // but can also have a channel dimension 00373 vigra_precondition(strideOrdering.size() == 0 || strideOrdering.size() == spatialDimensions || 00374 strideOrdering.size() == spatialDimensions + 1, 00375 "constructNumpyArray(type, ..., strideOrdering): strideOrdering has wrong length."); 00376 00377 if(channels == 0) // if the requested number of channels is not given ... 00378 { 00379 // ... deduce it 00380 if(shape.size() == spatialDimensions) 00381 channels = 1; 00382 else 00383 channels = shape.back(); 00384 } 00385 else 00386 { 00387 // otherwise, if the shape object also contains a channel dimension, they must be consistent 00388 if(shape.size() > spatialDimensions) 00389 vigra_precondition(channels == (unsigned int)shape[spatialDimensions], 00390 "constructNumpyArray(type, ...): shape contradicts requested number of channels."); 00391 } 00392 00393 // if we have only one channel, no explicit channel dimension should be in the shape 00394 unsigned int shapeSize = channels == 1 00395 ? spatialDimensions 00396 : spatialDimensions + 1; 00397 00398 // create the shape object with optional channel dimension 00399 ArrayVector<npy_intp> pshape(shapeSize); 00400 std::copy(shape.begin(), shape.begin()+std::min(shape.size(), pshape.size()), pshape.begin()); 00401 if(shapeSize > spatialDimensions) 00402 pshape[spatialDimensions] = channels; 00403 00404 // order "A" means "preserve order" when an array is copied, and 00405 // defaults to "V" when a new array is created without explicit strideOrdering 00406 // 00407 if(order == "A") 00408 { 00409 if(strideOrdering.size() == 0) 00410 { 00411 order = "V"; 00412 } 00413 else if(strideOrdering.size() > shapeSize) 00414 { 00415 // make sure that strideOrdering length matches shape length 00416 ArrayVector<npy_intp> pstride(strideOrdering.begin(), strideOrdering.begin()+shapeSize); 00417 00418 // adjust the ordering when the channel dimension has been dropped because channel == 1 00419 if(strideOrdering[shapeSize] == 0) 00420 for(unsigned int k=0; k<shapeSize; ++k) 00421 pstride[k] -= 1; 00422 pstride.swap(strideOrdering); 00423 } 00424 else if(strideOrdering.size() < shapeSize) 00425 { 00426 // make sure that strideOrdering length matches shape length 00427 ArrayVector<npy_intp> pstride(shapeSize); 00428 00429 // adjust the ordering when the channel dimension has been dropped because channel == 1 00430 for(unsigned int k=0; k<shapeSize-1; ++k) 00431 pstride[k] = strideOrdering[k] + 1; 00432 pstride[shapeSize-1] = 0; 00433 pstride.swap(strideOrdering); 00434 } 00435 } 00436 00437 // create the appropriate strideOrdering objects for the other memory orders 00438 // (when strideOrdering already contained data, it is ignored because order != "A") 00439 if(order == "C") 00440 { 00441 strideOrdering.resize(shapeSize); 00442 for(unsigned int k=0; k<shapeSize; ++k) 00443 strideOrdering[k] = shapeSize-1-k; 00444 } 00445 else if(order == "F" || (order == "V" && channels == 1)) 00446 { 00447 strideOrdering.resize(shapeSize); 00448 for(unsigned int k=0; k<shapeSize; ++k) 00449 strideOrdering[k] = k; 00450 } 00451 else if(order == "V") 00452 { 00453 strideOrdering.resize(shapeSize); 00454 for(unsigned int k=0; k<shapeSize-1; ++k) 00455 strideOrdering[k] = k+1; 00456 strideOrdering[shapeSize-1] = 0; 00457 } 00458 00459 return constructNumpyArrayImpl(type, pshape, strideOrdering.begin(), typeCode, init); 00460 } 00461 00462 inline 00463 python_ptr constructNumpyArrayFromData( 00464 PyTypeObject * type, 00465 ArrayVector<npy_intp> const & shape, npy_intp *strides, 00466 NPY_TYPES typeCode, void *data) 00467 { 00468 python_ptr array(PyArray_New(type, shape.size(), (npy_intp *)shape.begin(), typeCode, strides, data, 0, NPY_WRITEABLE, 0), 00469 python_ptr::keep_count); 00470 pythonToCppException(array); 00471 00472 return array; 00473 } 00474 00475 00476 } // namespace detail 00477 00478 /********************************************************/ 00479 /* */ 00480 /* NumpyArrayValuetypeTraits */ 00481 /* */ 00482 /********************************************************/ 00483 00484 template<class ValueType> 00485 struct ERROR_NumpyArrayValuetypeTraits_not_specialized_for_ { }; 00486 00487 template<class ValueType> 00488 struct NumpyArrayValuetypeTraits 00489 { 00490 static bool isValuetypeCompatible(PyArrayObject const * obj) 00491 { 00492 return ERROR_NumpyArrayValuetypeTraits_not_specialized_for_<ValueType>(); 00493 } 00494 00495 static ERROR_NumpyArrayValuetypeTraits_not_specialized_for_<ValueType> typeCode; 00496 00497 static std::string typeName() 00498 { 00499 return std::string("ERROR: NumpyArrayValuetypeTraits not specialized for this case"); 00500 } 00501 00502 static std::string typeNameImpex() 00503 { 00504 return std::string("ERROR: NumpyArrayValuetypeTraits not specialized for this case"); 00505 } 00506 00507 static PyObject * typeObject() 00508 { 00509 return (PyObject *)0; 00510 } 00511 }; 00512 00513 template<class ValueType> 00514 ERROR_NumpyArrayValuetypeTraits_not_specialized_for_<ValueType> NumpyArrayValuetypeTraits<ValueType>::typeCode; 00515 00516 #define VIGRA_NUMPY_VALUETYPE_TRAITS(type, typeID, numpyTypeName, impexTypeName) \ 00517 template <> \ 00518 struct NumpyArrayValuetypeTraits<type > \ 00519 { \ 00520 static bool isValuetypeCompatible(PyArrayObject const * obj) /* obj must not be NULL */ \ 00521 { \ 00522 return PyArray_EquivTypenums(typeID, PyArray_DESCR((PyObject *)obj)->type_num) && \ 00523 PyArray_ITEMSIZE((PyObject *)obj) == sizeof(type); \ 00524 } \ 00525 \ 00526 static NPY_TYPES const typeCode = typeID; \ 00527 \ 00528 static std::string typeName() \ 00529 { \ 00530 return #numpyTypeName; \ 00531 } \ 00532 \ 00533 static std::string typeNameImpex() \ 00534 { \ 00535 return impexTypeName; \ 00536 } \ 00537 \ 00538 static PyObject * typeObject() \ 00539 { \ 00540 return PyArray_TypeObjectFromType(typeID); \ 00541 } \ 00542 }; 00543 00544 VIGRA_NUMPY_VALUETYPE_TRAITS(bool, NPY_BOOL, bool, "UINT8") 00545 VIGRA_NUMPY_VALUETYPE_TRAITS(signed char, NPY_INT8, int8, "INT16") 00546 VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned char, NPY_UINT8, uint8, "UINT8") 00547 VIGRA_NUMPY_VALUETYPE_TRAITS(short, NPY_INT16, int16, "INT16") 00548 VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned short, NPY_UINT16, uint16, "UINT16") 00549 00550 #if VIGRA_BITSOF_LONG == 32 00551 VIGRA_NUMPY_VALUETYPE_TRAITS(long, NPY_INT32, int32, "INT32") 00552 VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned long, NPY_UINT32, uint32, "UINT32") 00553 #elif VIGRA_BITSOF_LONG == 64 00554 VIGRA_NUMPY_VALUETYPE_TRAITS(long, NPY_INT64, int64, "DOUBLE") 00555 VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned long, NPY_UINT64, uint64, "DOUBLE") 00556 #endif 00557 00558 #if VIGRA_BITSOF_INT == 32 00559 VIGRA_NUMPY_VALUETYPE_TRAITS(int, NPY_INT32, int32, "INT32") 00560 VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned int, NPY_UINT32, uint32, "UINT32") 00561 #elif VIGRA_BITSOF_INT == 64 00562 VIGRA_NUMPY_VALUETYPE_TRAITS(int, NPY_INT64, int64, "DOUBLE") 00563 VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned int, NPY_UINT64, uint64, "DOUBLE") 00564 #endif 00565 00566 #ifdef PY_LONG_LONG 00567 # if VIGRA_BITSOF_LONG_LONG == 32 00568 VIGRA_NUMPY_VALUETYPE_TRAITS(long long, NPY_INT32, int32, "INT32") 00569 VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned long long, NPY_UINT32, uint32, "UINT32") 00570 # elif VIGRA_BITSOF_LONG_LONG == 64 00571 VIGRA_NUMPY_VALUETYPE_TRAITS(long long, NPY_INT64, int64, "DOUBLE") 00572 VIGRA_NUMPY_VALUETYPE_TRAITS(unsigned long long, NPY_UINT64, uint64, "DOUBLE") 00573 # endif 00574 #endif 00575 00576 VIGRA_NUMPY_VALUETYPE_TRAITS(npy_float32, NPY_FLOAT32, float32, "FLOAT") 00577 VIGRA_NUMPY_VALUETYPE_TRAITS(npy_float64, NPY_FLOAT64, float64, "DOUBLE") 00578 VIGRA_NUMPY_VALUETYPE_TRAITS(npy_longdouble, NPY_LONGDOUBLE, longdouble, "") 00579 VIGRA_NUMPY_VALUETYPE_TRAITS(npy_cfloat, NPY_CFLOAT, complex64, "") 00580 VIGRA_NUMPY_VALUETYPE_TRAITS(std::complex<npy_float>, NPY_CFLOAT, complex64, "") 00581 VIGRA_NUMPY_VALUETYPE_TRAITS(npy_cdouble, NPY_CDOUBLE, complex128, "") 00582 VIGRA_NUMPY_VALUETYPE_TRAITS(std::complex<npy_double>, NPY_CDOUBLE, complex128, "") 00583 VIGRA_NUMPY_VALUETYPE_TRAITS(npy_clongdouble, NPY_CLONGDOUBLE, clongdouble, "") 00584 VIGRA_NUMPY_VALUETYPE_TRAITS(std::complex<npy_longdouble>, NPY_CLONGDOUBLE, clongdouble, "") 00585 00586 #undef VIGRA_NUMPY_VALUETYPE_TRAITS 00587 00588 /********************************************************/ 00589 /* */ 00590 /* NumpyArrayTraits */ 00591 /* */ 00592 /********************************************************/ 00593 00594 template <class U, int N> 00595 bool stridesAreAscending(TinyVector<U, N> const & strides) 00596 { 00597 for(int k=1; k<N; ++k) 00598 if(strides[k] < strides[k-1]) 00599 return false; 00600 return true; 00601 } 00602 00603 template<unsigned int N, class T, class Stride> 00604 struct NumpyArrayTraits; 00605 00606 template<unsigned int N, class T> 00607 struct NumpyArrayTraits<N, T, StridedArrayTag> 00608 { 00609 typedef T dtype; 00610 typedef T value_type; 00611 typedef NumpyArrayValuetypeTraits<T> ValuetypeTraits; 00612 static NPY_TYPES const typeCode = ValuetypeTraits::typeCode; 00613 00614 enum { spatialDimensions = N, channels = 1 }; 00615 00616 static bool isArray(PyObject * obj) 00617 { 00618 return obj && PyArray_Check(obj); 00619 } 00620 00621 static bool isClassCompatible(PyObject * obj) 00622 { 00623 return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(), typeKey()); 00624 } 00625 00626 static bool isValuetypeCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00627 { 00628 return ValuetypeTraits::isValuetypeCompatible(obj); 00629 } 00630 00631 static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00632 { 00633 return PyArray_NDIM((PyObject *)obj) == N-1 || 00634 PyArray_NDIM((PyObject *)obj) == N || 00635 (PyArray_NDIM((PyObject *)obj) == N+1 && PyArray_DIM((PyObject *)obj, N) == 1); 00636 } 00637 00638 static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00639 { 00640 return ValuetypeTraits::isValuetypeCompatible(obj) && 00641 isShapeCompatible(obj); 00642 } 00643 00644 template <class U> 00645 static python_ptr constructor(TinyVector<U, N> const & shape, 00646 T *data, TinyVector<U, N> const & stride) 00647 { 00648 TinyVector<npy_intp, N> npyStride(stride * sizeof(T)); 00649 return detail::constructNumpyArrayFromData(typeKeyFull(), typeKey(), shape, ValuetypeTraits::typeCode, data, npyStride.begin()); 00650 } 00651 00652 static std::string typeKey() 00653 { 00654 static std::string key = std::string("NumpyArray<") + asString(N) + ", *>"; 00655 return key; 00656 } 00657 00658 static std::string typeKeyFull() 00659 { 00660 static std::string key = std::string("NumpyArray<") + asString(N) + ", " + 00661 ValuetypeTraits::typeName() + ", StridedArrayTag>"; 00662 return key; 00663 } 00664 }; 00665 00666 /********************************************************/ 00667 00668 template<unsigned int N, class T> 00669 struct NumpyArrayTraits<N, T, UnstridedArrayTag> 00670 : public NumpyArrayTraits<N, T, StridedArrayTag> 00671 { 00672 typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType; 00673 typedef typename BaseType::ValuetypeTraits ValuetypeTraits; 00674 00675 static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00676 { 00677 return BaseType::isShapeCompatible(obj) && 00678 PyArray_STRIDES((PyObject *)obj)[0] == PyArray_ITEMSIZE((PyObject *)obj); 00679 } 00680 00681 static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00682 { 00683 return BaseType::isValuetypeCompatible(obj) && 00684 isShapeCompatible(obj); 00685 } 00686 00687 template <class U> 00688 static python_ptr constructor(TinyVector<U, N> const & shape, 00689 T *data, TinyVector<U, N> const & stride) 00690 { 00691 TinyVector<npy_intp, N> npyStride(stride * sizeof(T)); 00692 return detail::constructNumpyArrayFromData(typeKeyFull(), BaseType::typeKey(), shape, ValuetypeTraits::typeCode, data, npyStride.begin()); 00693 } 00694 00695 static std::string typeKeyFull() 00696 { 00697 static std::string key = std::string("NumpyArray<") + asString(N) + ", " + 00698 ValuetypeTraits::typeName() + ", UnstridedArrayTag>"; 00699 return key; 00700 } 00701 }; 00702 00703 /********************************************************/ 00704 00705 template<unsigned int N, class T> 00706 struct NumpyArrayTraits<N, Singleband<T>, StridedArrayTag> 00707 : public NumpyArrayTraits<N, T, StridedArrayTag> 00708 { 00709 typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType; 00710 typedef typename BaseType::ValuetypeTraits ValuetypeTraits; 00711 00712 static bool isClassCompatible(PyObject * obj) 00713 { 00714 return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(), typeKey()); 00715 } 00716 00717 template <class U> 00718 static python_ptr constructor(TinyVector<U, N> const & shape, 00719 T *data, TinyVector<U, N> const & stride) 00720 { 00721 TinyVector<npy_intp, N> npyStride(stride * sizeof(T)); 00722 return detail::constructNumpyArrayFromData(typeKeyFull(), typeKey(), shape, ValuetypeTraits::typeCode, data, npyStride.begin()); 00723 } 00724 00725 static std::string typeKey() 00726 { 00727 static std::string key = std::string("NumpyArray<") + asString(N) + ", Singleband<*> >"; 00728 return key; 00729 } 00730 00731 static std::string typeKeyFull() 00732 { 00733 static std::string key = std::string("NumpyArray<") + asString(N) + ", Singleband<" + 00734 ValuetypeTraits::typeName() + ">, StridedArrayTag>"; 00735 return key; 00736 } 00737 }; 00738 00739 /********************************************************/ 00740 00741 template<unsigned int N, class T> 00742 struct NumpyArrayTraits<N, Singleband<T>, UnstridedArrayTag> 00743 : public NumpyArrayTraits<N, Singleband<T>, StridedArrayTag> 00744 { 00745 typedef NumpyArrayTraits<N, T, UnstridedArrayTag> UnstridedTraits; 00746 typedef NumpyArrayTraits<N, Singleband<T>, StridedArrayTag> BaseType; 00747 typedef typename BaseType::ValuetypeTraits ValuetypeTraits; 00748 00749 static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00750 { 00751 return UnstridedTraits::isShapeCompatible(obj); 00752 } 00753 00754 static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00755 { 00756 return UnstridedTraits::isPropertyCompatible(obj); 00757 } 00758 00759 template <class U> 00760 static python_ptr constructor(TinyVector<U, N> const & shape, 00761 T *data, TinyVector<U, N> const & stride) 00762 { 00763 TinyVector<npy_intp, N> npyStride(stride * sizeof(T)); 00764 return detail::constructNumpyArrayFromData(typeKeyFull(), BaseType::typeKey(), shape, ValuetypeTraits::typeCode, data, npyStride.begin()); 00765 } 00766 00767 static std::string typeKeyFull() 00768 { 00769 static std::string key = std::string("NumpyArray<") + asString(N) + ", Singleband<" + 00770 ValuetypeTraits::typeName() + ">, UnstridedArrayTag>"; 00771 return key; 00772 } 00773 }; 00774 00775 /********************************************************/ 00776 00777 template<unsigned int N, class T> 00778 struct NumpyArrayTraits<N, Multiband<T>, StridedArrayTag> 00779 : public NumpyArrayTraits<N, T, StridedArrayTag> 00780 { 00781 typedef NumpyArrayTraits<N, T, StridedArrayTag> BaseType; 00782 typedef typename BaseType::ValuetypeTraits ValuetypeTraits; 00783 00784 enum { spatialDimensions = N-1, channels = 0 }; 00785 00786 static bool isClassCompatible(PyObject * obj) 00787 { 00788 return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(), typeKey()); 00789 } 00790 00791 static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00792 { 00793 return PyArray_NDIM(obj) == N || PyArray_NDIM(obj) == N-1; 00794 } 00795 00796 static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00797 { 00798 return ValuetypeTraits::isValuetypeCompatible(obj) && 00799 isShapeCompatible(obj); 00800 } 00801 00802 template <class U> 00803 static python_ptr constructor(TinyVector<U, N> const & shape, 00804 T *data, TinyVector<U, N> const & stride) 00805 { 00806 TinyVector<npy_intp, N> npyStride(stride * sizeof(T)); 00807 return detail::constructNumpyArrayFromData(typeKeyFull(), typeKey(), shape, ValuetypeTraits::typeCode, data, npyStride.begin()); 00808 } 00809 00810 static std::string typeKey() 00811 { 00812 static std::string key = std::string("NumpyArray<") + asString(N) + ", Multiband<*> >"; 00813 return key; 00814 } 00815 00816 static std::string typeKeyFull() 00817 { 00818 static std::string key = std::string("NumpyArray<") + asString(N) + ", Multiband<" + 00819 ValuetypeTraits::typeName() + ">, StridedArrayTag>"; 00820 return key; 00821 } 00822 }; 00823 00824 /********************************************************/ 00825 00826 template<unsigned int N, class T> 00827 struct NumpyArrayTraits<N, Multiband<T>, UnstridedArrayTag> 00828 : public NumpyArrayTraits<N, Multiband<T>, StridedArrayTag> 00829 { 00830 typedef NumpyArrayTraits<N, Multiband<T>, StridedArrayTag> BaseType; 00831 typedef typename BaseType::ValuetypeTraits ValuetypeTraits; 00832 00833 static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00834 { 00835 return BaseType::isShapeCompatible(obj) && 00836 PyArray_STRIDES((PyObject *)obj)[0] == PyArray_ITEMSIZE((PyObject *)obj); 00837 } 00838 00839 static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00840 { 00841 return BaseType::isValuetypeCompatible(obj) && 00842 isShapeCompatible(obj); 00843 } 00844 00845 template <class U> 00846 static python_ptr constructor(TinyVector<U, N> const & shape, 00847 T *data, TinyVector<U, N> const & stride) 00848 { 00849 TinyVector<npy_intp, N> npyStride(stride * sizeof(T)); 00850 return detail::constructNumpyArrayFromData(typeKeyFull(), BaseType::typeKey(), shape, ValuetypeTraits::typeCode, data, npyStride.begin()); 00851 } 00852 00853 static std::string typeKeyFull() 00854 { 00855 static std::string key = std::string("NumpyArray<") + asString(N) + ", Multiband<" + 00856 ValuetypeTraits::typeName() + ">, UnstridedArrayTag>"; 00857 return key; 00858 } 00859 }; 00860 00861 /********************************************************/ 00862 00863 template<unsigned int N, int M, class T> 00864 struct NumpyArrayTraits<N, TinyVector<T, M>, StridedArrayTag> 00865 { 00866 typedef T dtype; 00867 typedef TinyVector<T, M> value_type; 00868 typedef NumpyArrayValuetypeTraits<T> ValuetypeTraits; 00869 static NPY_TYPES const typeCode = ValuetypeTraits::typeCode; 00870 00871 enum { spatialDimensions = N, channels = M }; 00872 00873 static bool isArray(PyObject * obj) 00874 { 00875 return obj && PyArray_Check(obj); 00876 } 00877 00878 static bool isClassCompatible(PyObject * obj) 00879 { 00880 return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(), typeKey()); 00881 } 00882 00883 static bool isValuetypeCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00884 { 00885 return ValuetypeTraits::isValuetypeCompatible(obj); 00886 } 00887 00888 static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00889 { 00890 return PyArray_NDIM((PyObject *)obj) == N+1 && 00891 PyArray_DIM((PyObject *)obj, N) == M && 00892 PyArray_STRIDES((PyObject *)obj)[N] == PyArray_ITEMSIZE((PyObject *)obj); 00893 } 00894 00895 static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00896 { 00897 return ValuetypeTraits::isValuetypeCompatible(obj) && 00898 isShapeCompatible(obj); 00899 } 00900 00901 template <class U> 00902 static python_ptr constructor(TinyVector<U, N> const & shape, 00903 T *data, TinyVector<U, N> const & stride) 00904 { 00905 TinyVector<npy_intp, N+1> npyShape; 00906 std::copy(shape.begin(), shape.end(), npyShape.begin()); 00907 npyShape[N] = M; 00908 00909 TinyVector<npy_intp, N+1> npyStride; 00910 std::transform( 00911 stride.begin(), stride.end(), npyStride.begin(), 00912 std::bind2nd(std::multiplies<npy_intp>(), sizeof(value_type))); 00913 npyStride[N] = sizeof(T); 00914 00915 return detail::constructNumpyArrayFromData( 00916 typeKeyFull(), typeKey(), npyShape, 00917 ValuetypeTraits::typeCode, data, npyStride.begin()); 00918 } 00919 00920 static std::string typeKey() 00921 { 00922 static std::string key = std::string("NumpyArray<") + asString(N) + ", TinyVector<*, " + asString(M) + "> >"; 00923 return key; 00924 } 00925 00926 static std::string typeKeyFull() 00927 { 00928 static std::string key = std::string("NumpyArray<") + asString(N) + 00929 ", TinyVector<" + ValuetypeTraits::typeName() + ", " + asString(M) + ">, StridedArrayTag>"; 00930 return key; 00931 } 00932 }; 00933 00934 /********************************************************/ 00935 00936 template<unsigned int N, int M, class T> 00937 struct NumpyArrayTraits<N, TinyVector<T, M>, UnstridedArrayTag> 00938 : public NumpyArrayTraits<N, TinyVector<T, M>, StridedArrayTag> 00939 { 00940 typedef NumpyArrayTraits<N, TinyVector<T, M>, StridedArrayTag> BaseType; 00941 typedef typename BaseType::value_type value_type; 00942 typedef typename BaseType::ValuetypeTraits ValuetypeTraits; 00943 00944 static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00945 { 00946 return BaseType::isShapeCompatible(obj) && 00947 PyArray_STRIDES((PyObject *)obj)[0] == sizeof(TinyVector<T, M>); 00948 } 00949 00950 static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not be NULL */ 00951 { 00952 return BaseType::isValuetypeCompatible(obj) && 00953 isShapeCompatible(obj); 00954 } 00955 00956 template <class U> 00957 static python_ptr constructor(TinyVector<U, N> const & shape, 00958 T *data, TinyVector<U, N> const & stride) 00959 { 00960 TinyVector<npy_intp, N+1> npyShape; 00961 std::copy(shape.begin(), shape.end(), npyShape.begin()); 00962 npyShape[N] = M; 00963 00964 TinyVector<npy_intp, N+1> npyStride; 00965 std::transform( 00966 stride.begin(), stride.end(), npyStride.begin(), 00967 std::bind2nd(std::multiplies<npy_intp>(), sizeof(value_type))); 00968 npyStride[N] = sizeof(T); 00969 00970 return detail::constructNumpyArrayFromData( 00971 typeKeyFull(), BaseType::typeKey(), npyShape, 00972 ValuetypeTraits::typeCode, data, npyStride.begin()); 00973 } 00974 00975 static std::string typeKeyFull() 00976 { 00977 static std::string key = std::string("NumpyArray<") + asString(N) + 00978 ", TinyVector<" + ValuetypeTraits::typeName() + ", " + asString(M) + ">, UnstridedArrayTag>"; 00979 return key; 00980 } 00981 }; 00982 00983 /********************************************************/ 00984 00985 template<unsigned int N, class T> 00986 struct NumpyArrayTraits<N, RGBValue<T>, StridedArrayTag> 00987 : public NumpyArrayTraits<N, TinyVector<T, 3>, StridedArrayTag> 00988 { 00989 typedef T dtype; 00990 typedef RGBValue<T> value_type; 00991 typedef NumpyArrayValuetypeTraits<T> ValuetypeTraits; 00992 00993 static bool isClassCompatible(PyObject * obj) 00994 { 00995 return detail::performCustomizedArrayTypecheck(obj, typeKeyFull(), typeKey()); 00996 } 00997 00998 template <class U> 00999 static python_ptr constructor(TinyVector<U, N> const & shape, 01000 T *data, TinyVector<U, N> const & stride) 01001 { 01002 TinyVector<npy_intp, N+1> npyShape; 01003 std::copy(shape.begin(), shape.end(), npyShape.begin()); 01004 npyShape[N] = 3; 01005 01006 TinyVector<npy_intp, N+1> npyStride; 01007 std::transform( 01008 stride.begin(), stride.end(), npyStride.begin(), 01009 std::bind2nd(std::multiplies<npy_intp>(), sizeof(value_type))); 01010 npyStride[N] = sizeof(T); 01011 01012 return detail::constructNumpyArrayFromData( 01013 typeKeyFull(), typeKey(), npyShape, 01014 ValuetypeTraits::typeCode, data, npyStride.begin()); 01015 } 01016 01017 static std::string typeKey() 01018 { 01019 static std::string key = std::string("NumpyArray<") + asString(N) + ", RGBValue<*> >"; 01020 return key; 01021 } 01022 01023 static std::string typeKeyFull() 01024 { 01025 static std::string key = std::string("NumpyArray<") + asString(N) + 01026 ", RGBValue<" + ValuetypeTraits::typeName() + ">, StridedArrayTag>"; 01027 return key; 01028 } 01029 }; 01030 01031 /********************************************************/ 01032 01033 template<unsigned int N, class T> 01034 struct NumpyArrayTraits<N, RGBValue<T>, UnstridedArrayTag> 01035 : public NumpyArrayTraits<N, RGBValue<T>, StridedArrayTag> 01036 { 01037 typedef NumpyArrayTraits<N, TinyVector<T, 3>, UnstridedArrayTag> UnstridedTraits; 01038 typedef NumpyArrayTraits<N, RGBValue<T>, StridedArrayTag> BaseType; 01039 typedef typename BaseType::value_type value_type; 01040 typedef typename BaseType::ValuetypeTraits ValuetypeTraits; 01041 01042 static bool isShapeCompatible(PyArrayObject * obj) /* obj must not be NULL */ 01043 { 01044 return UnstridedTraits::isShapeCompatible(obj); 01045 } 01046 01047 static bool isPropertyCompatible(PyArrayObject * obj) /* obj must not be NULL */ 01048 { 01049 return UnstridedTraits::isPropertyCompatible(obj); 01050 } 01051 01052 template <class U> 01053 static python_ptr constructor(TinyVector<U, N> const & shape, 01054 T *data, TinyVector<U, N> const & stride) 01055 { 01056 TinyVector<npy_intp, N+1> npyShape; 01057 std::copy(shape.begin(), shape.end(), npyShape.begin()); 01058 npyShape[N] = 3; 01059 01060 TinyVector<npy_intp, N+1> npyStride; 01061 std::transform( 01062 stride.begin(), stride.end(), npyStride.begin(), 01063 std::bind2nd(std::multiplies<npy_intp>(), sizeof(value_type))); 01064 npyStride[N] = sizeof(T); 01065 01066 return detail::constructNumpyArrayFromData( 01067 typeKeyFull(), BaseType::typeKey(), npyShape, 01068 ValuetypeTraits::typeCode, data, npyStride.begin()); 01069 } 01070 01071 static std::string typeKeyFull() 01072 { 01073 static std::string key = std::string("NumpyArray<") + asString(N) + 01074 ", RGBValue<" + ValuetypeTraits::typeName() + ">, UnstridedArrayTag>"; 01075 return key; 01076 } 01077 }; 01078 01079 /********************************************************/ 01080 /* */ 01081 /* NumpyAnyArray */ 01082 /* */ 01083 /********************************************************/ 01084 01085 /** Wrapper class for a Python array. 01086 01087 This class stores a reference-counted pointer to an Python numpy array object, 01088 i.e. an object where <tt>PyArray_Check(object)</tt> returns true (in Python, the 01089 object is then a subclass of <tt>numpy.ndarray</tt>). This class is mainly used 01090 as a smart pointer to these arrays, but some basic access and conversion functions 01091 are also provided. 01092 01093 <b>\#include</b> <<a href="numpy__array_8hxx-source.html">vigra/numpy_array.hxx</a>><br> 01094 Namespace: vigra 01095 */ 01096 class NumpyAnyArray 01097 { 01098 protected: 01099 python_ptr pyArray_; 01100 01101 // We want to apply broadcasting to the channel dimension. 01102 // Since only leading dimensions can be added during numpy 01103 // broadcasting, we permute the array accordingly. 01104 NumpyAnyArray permuteChannelsToFront() const 01105 { 01106 MultiArrayIndex M = ndim(); 01107 ArrayVector<npy_intp> permutation(M); 01108 for(int k=0; k<M; ++k) 01109 permutation[k] = M-1-k; 01110 // explicit cast to int is neede here to avoid gcc c++0x compilation 01111 // error: narrowing conversion of ‘M’ from ‘vigra::MultiArrayIndex’ 01112 // to ‘int’ inside { } 01113 // int overflow should not occur here because PyArray_NDIM returns 01114 // an integer which is converted to long in NumpyAnyArray::ndim() 01115 PyArray_Dims permute = { permutation.begin(), (int) M }; 01116 python_ptr array(PyArray_Transpose(pyArray(), &permute), python_ptr::keep_count); 01117 pythonToCppException(array); 01118 return NumpyAnyArray(array.ptr()); 01119 } 01120 01121 public: 01122 01123 /// difference type 01124 typedef ArrayVector<npy_intp> difference_type; 01125 01126 /** 01127 Construct from a Python object. If \a obj is NULL, or is not a subclass 01128 of numpy.ndarray, the resulting NumpyAnyArray will have no data (i.e. 01129 hasData() returns false). Otherwise, it creates a new reference to the array 01130 \a obj, unless \a createCopy is true, where a new array is created by calling 01131 the C-equivalent of obj->copy(). 01132 */ 01133 explicit NumpyAnyArray(PyObject * obj = 0, bool createCopy = false, PyTypeObject * type = 0) 01134 { 01135 if(obj == 0) 01136 return; 01137 vigra_precondition(type == 0 || PyType_IsSubtype(type, &PyArray_Type), 01138 "NumpyAnyArray(obj, createCopy, type): type must be numpy.ndarray or a subclass thereof."); 01139 if(createCopy) 01140 makeCopy(obj, type); 01141 else 01142 vigra_precondition(makeReference(obj, type), "NumpyAnyArray(obj): obj isn't a numpy array."); 01143 } 01144 01145 /** 01146 Copy constructor. By default, it creates a new reference to the array 01147 \a other. When \a createCopy is true, a new array is created by calling 01148 the C-equivalent of other.copy(). 01149 */ 01150 NumpyAnyArray(NumpyAnyArray const & other, bool createCopy = false, PyTypeObject * type = 0) 01151 { 01152 if(!other.hasData()) 01153 return; 01154 vigra_precondition(type == 0 || PyType_IsSubtype(type, &PyArray_Type), 01155 "NumpyAnyArray(obj, createCopy, type): type must be numpy.ndarray or a subclass thereof."); 01156 if(createCopy) 01157 makeCopy(other.pyObject(), type); 01158 else 01159 makeReference(other.pyObject(), type); 01160 } 01161 01162 // auto-generated destructor is ok 01163 01164 /** 01165 * Assignment operator. If this is already a view with data 01166 * (i.e. hasData() is true) and the shapes match, the RHS 01167 * array contents are copied via the C-equivalent of 01168 * 'self[...] = other[...]'. If the shapes don't matched, 01169 * broadcasting is tried on the trailing (i.e. channel) 01170 * dimension. 01171 * If the LHS is an empty view, assignment is identical to 01172 * makeReference(other.pyObject()). 01173 */ 01174 NumpyAnyArray & operator=(NumpyAnyArray const & other) 01175 { 01176 if(hasData()) 01177 { 01178 vigra_precondition(other.hasData(), 01179 "NumpyArray::operator=(): Cannot assign from empty array."); 01180 if(PyArray_CopyInto(permuteChannelsToFront().pyArray(), other.permuteChannelsToFront().pyArray()) == -1) 01181 pythonToCppException(0); 01182 } 01183 else 01184 { 01185 pyArray_ = other.pyArray_; 01186 } 01187 return *this; 01188 } 01189 01190 /** 01191 Returns the number of dimensions of this array, or 0 if 01192 hasData() is false. 01193 */ 01194 MultiArrayIndex ndim() const 01195 { 01196 if(hasData()) 01197 return PyArray_NDIM(pyObject()); 01198 return 0; 01199 } 01200 01201 /** 01202 Returns the number of spatial dimensions of this array, or 0 if 01203 hasData() is false. If the enclosed Python array does not define 01204 the attribute spatialDimensions, ndim() is returned. 01205 */ 01206 MultiArrayIndex spatialDimensions() const 01207 { 01208 if(!hasData()) 01209 return 0; 01210 MultiArrayIndex s = detail::spatialDimensions(pyObject()); 01211 if(s == -1) 01212 s = ndim(); 01213 return s; 01214 } 01215 01216 /** 01217 Returns the shape of this array. The size of 01218 the returned shape equals ndim(). 01219 */ 01220 difference_type shape() const 01221 { 01222 if(hasData()) 01223 return difference_type(PyArray_DIMS(pyObject()), PyArray_DIMS(pyObject()) + ndim()); 01224 return difference_type(); 01225 } 01226 01227 /** Compute the ordering of the strides of this array. 01228 The result is describes the current permutation of the axes relative 01229 to an ascending stride order. 01230 */ 01231 difference_type strideOrdering() const 01232 { 01233 if(!hasData()) 01234 return difference_type(); 01235 MultiArrayIndex N = ndim(); 01236 difference_type stride(PyArray_STRIDES(pyObject()), PyArray_STRIDES(pyObject()) + N), 01237 permutation(N); 01238 for(MultiArrayIndex k=0; k<N; ++k) 01239 permutation[k] = k; 01240 for(MultiArrayIndex k=0; k<N-1; ++k) 01241 { 01242 MultiArrayIndex smallest = k; 01243 for(MultiArrayIndex j=k+1; j<N; ++j) 01244 { 01245 if(stride[j] < stride[smallest]) 01246 smallest = j; 01247 } 01248 if(smallest != k) 01249 { 01250 std::swap(stride[k], stride[smallest]); 01251 std::swap(permutation[k], permutation[smallest]); 01252 } 01253 } 01254 difference_type ordering(N); 01255 for(MultiArrayIndex k=0; k<N; ++k) 01256 ordering[permutation[k]] = k; 01257 return ordering; 01258 } 01259 01260 /** 01261 Returns the value type of the elements in this array, or -1 01262 when hasData() is false. 01263 */ 01264 int dtype() const 01265 { 01266 if(hasData()) 01267 return PyArray_DESCR(pyObject())->type_num; 01268 return -1; 01269 } 01270 01271 /** 01272 * Return a borrowed reference to the internal PyArrayObject. 01273 */ 01274 PyArrayObject * pyArray() const 01275 { 01276 return (PyArrayObject *)pyArray_.get(); 01277 } 01278 01279 /** 01280 * Return a borrowed reference to the internal PyArrayObject 01281 * (see pyArray()), cast to PyObject for your convenience. 01282 */ 01283 PyObject * pyObject() const 01284 { 01285 return pyArray_.get(); 01286 } 01287 01288 /** 01289 Reset the NumpyAnyArray to the given object. If \a obj is a numpy array object, 01290 a new reference to that array is created, and the function returns 01291 true. Otherwise, it returns false and the NumpyAnyArray remains unchanged. 01292 If \a type is given, the new reference will be a view with that type, provided 01293 that \a type is a numpy ndarray or a subclass thereof. Otherwise, an 01294 exception is thrown. 01295 */ 01296 bool makeReference(PyObject * obj, PyTypeObject * type = 0) 01297 { 01298 if(obj == 0 || !PyArray_Check(obj)) 01299 return false; 01300 if(type != 0) 01301 { 01302 vigra_precondition(PyType_IsSubtype(type, &PyArray_Type) != 0, 01303 "NumpyAnyArray::makeReference(obj, type): type must be numpy.ndarray or a subclass thereof."); 01304 obj = PyArray_View((PyArrayObject*)obj, 0, type); 01305 pythonToCppException(obj); 01306 } 01307 pyArray_.reset(obj); 01308 return true; 01309 } 01310 01311 /** 01312 Create a copy of the given array object. If \a obj is a numpy array object, 01313 a copy is created via the C-equivalent of 'obj->copy()'. If 01314 this call fails, or obj was not an array, an exception is thrown 01315 and the NumpyAnyArray remains unchanged. 01316 */ 01317 void makeCopy(PyObject * obj, PyTypeObject * type = 0) 01318 { 01319 vigra_precondition(obj && PyArray_Check(obj), 01320 "NumpyAnyArray::makeCopy(obj): obj is not an array."); 01321 vigra_precondition(type == 0 || PyType_IsSubtype(type, &PyArray_Type), 01322 "NumpyAnyArray::makeCopy(obj, type): type must be numpy.ndarray or a subclass thereof."); 01323 python_ptr array(PyArray_NewCopy((PyArrayObject*)obj, NPY_ANYORDER), python_ptr::keep_count); 01324 pythonToCppException(array); 01325 makeReference(array, type); 01326 } 01327 01328 /** 01329 Check whether this NumpyAnyArray actually points to a Python array. 01330 */ 01331 bool hasData() const 01332 { 01333 return pyArray_ != 0; 01334 } 01335 }; 01336 01337 /********************************************************/ 01338 /* */ 01339 /* NumpyArray */ 01340 /* */ 01341 /********************************************************/ 01342 01343 /** Provide the MultiArrayView interface for a Python array. 01344 01345 This class inherits from both \ref vigra::MultiArrayView and \ref vigra::NumpyAnyArray 01346 in order to support easy and save application of VIGRA functions to Python arrays. 01347 01348 <b>\#include</b> <<a href="numpy__array_8hxx-source.html">vigra/numpy_array.hxx</a>><br> 01349 Namespace: vigra 01350 */ 01351 template <unsigned int N, class T, class Stride = StridedArrayTag> 01352 class NumpyArray 01353 : public MultiArrayView<N, typename NumpyArrayTraits<N, T, Stride>::value_type, Stride>, 01354 public NumpyAnyArray 01355 { 01356 public: 01357 typedef NumpyArrayTraits<N, T, Stride> ArrayTraits; 01358 typedef typename ArrayTraits::dtype dtype; 01359 typedef T pseudo_value_type; 01360 01361 static NPY_TYPES const typeCode = ArrayTraits::typeCode; 01362 01363 /** the view type associated with this array. 01364 */ 01365 typedef MultiArrayView<N, typename ArrayTraits::value_type, Stride> view_type; 01366 01367 enum { actual_dimension = view_type::actual_dimension }; 01368 01369 /** the array's value type 01370 */ 01371 typedef typename view_type::value_type value_type; 01372 01373 /** pointer type 01374 */ 01375 typedef typename view_type::pointer pointer; 01376 01377 /** const pointer type 01378 */ 01379 typedef typename view_type::const_pointer const_pointer; 01380 01381 /** reference type (result of operator[]) 01382 */ 01383 typedef typename view_type::reference reference; 01384 01385 /** const reference type (result of operator[] const) 01386 */ 01387 typedef typename view_type::const_reference const_reference; 01388 01389 /** size type 01390 */ 01391 typedef typename view_type::size_type size_type; 01392 01393 /** difference type (used for multi-dimensional offsets and indices) 01394 */ 01395 typedef typename view_type::difference_type difference_type; 01396 01397 /** difference and index type for a single dimension 01398 */ 01399 typedef typename view_type::difference_type_1 difference_type_1; 01400 01401 /** traverser type 01402 */ 01403 typedef typename view_type::traverser traverser; 01404 01405 /** traverser type to const data 01406 */ 01407 typedef typename view_type::const_traverser const_traverser; 01408 01409 /** sequential (random access) iterator type 01410 */ 01411 typedef value_type * iterator; 01412 01413 /** sequential (random access) const iterator type 01414 */ 01415 typedef value_type * const_iterator; 01416 01417 using view_type::shape; // resolve ambiguity of multiple inheritance 01418 using view_type::hasData; // resolve ambiguity of multiple inheritance 01419 using view_type::strideOrdering; // resolve ambiguity of multiple inheritance 01420 01421 protected: 01422 01423 // this function assumes that pyArray_ has already been set, and compatibility been checked 01424 void setupArrayView(); 01425 01426 static python_ptr getArrayTypeObject() 01427 { 01428 python_ptr type = detail::getArrayTypeObject(ArrayTraits::typeKeyFull()); 01429 if(type == 0) 01430 type = detail::getArrayTypeObject(ArrayTraits::typeKey(), &PyArray_Type); 01431 return type; 01432 } 01433 01434 static python_ptr init(difference_type const & shape, bool init = true) 01435 { 01436 ArrayVector<npy_intp> pshape(shape.begin(), shape.end()); 01437 return detail::constructNumpyArrayImpl((PyTypeObject *)getArrayTypeObject().ptr(), pshape, 01438 ArrayTraits::spatialDimensions, ArrayTraits::channels, 01439 typeCode, "V", init); 01440 } 01441 01442 static python_ptr init(difference_type const & shape, difference_type const & strideOrdering, bool init = true) 01443 { 01444 ArrayVector<npy_intp> pshape(shape.begin(), shape.end()), 01445 pstrideOrdering(strideOrdering.begin(), strideOrdering.end()); 01446 return detail::constructNumpyArrayImpl((PyTypeObject *)getArrayTypeObject().ptr(), pshape, 01447 ArrayTraits::spatialDimensions, ArrayTraits::channels, 01448 typeCode, "A", init, pstrideOrdering); 01449 } 01450 01451 public: 01452 01453 using view_type::init; 01454 01455 /** 01456 * Construct from a given PyObject pointer. When the given 01457 * python object is NULL, the internal python array will be 01458 * NULL and hasData() will return false. 01459 * 01460 * Otherwise, the function attempts to create a 01461 * new reference to the given Python object, unless 01462 * copying is forced by setting \a createCopy to true. 01463 * If either of this fails, the function throws an exception. 01464 * This will not happen if isStrictlyCompatible(obj) (in case 01465 * of creating a new reference) or isCopyCompatible(obj) 01466 * (in case of copying) have returned true beforehand. 01467 */ 01468 explicit NumpyArray(PyObject *obj = 0, bool createCopy = false) 01469 { 01470 if(obj == 0) 01471 return; 01472 if(createCopy) 01473 makeCopy(obj); 01474 else 01475 vigra_precondition(makeReference(obj), 01476 "NumpyArray(obj): Cannot construct from incompatible array."); 01477 } 01478 01479 /** 01480 * Copy constructor; does not copy the memory, but creates a 01481 * new reference to the same underlying python object, unless 01482 * a copy is forced by setting \a createCopy to true. 01483 * (If the source object has no data, this one will have 01484 * no data, too.) 01485 */ 01486 NumpyArray(const NumpyArray &other, bool createCopy = false) : 01487 MultiArrayView<N, typename NumpyArrayTraits<N, T, Stride>::value_type, Stride>(other), 01488 NumpyAnyArray(other, createCopy) 01489 { 01490 if(!other.hasData()) 01491 return; 01492 if(createCopy) 01493 makeCopy(other.pyObject()); 01494 else 01495 makeReferenceUnchecked(other.pyObject()); 01496 } 01497 01498 /** 01499 * Allocate new memory and copy data from a MultiArrayView. 01500 */ 01501 explicit NumpyArray(const view_type &other) 01502 { 01503 if(!other.hasData()) 01504 return; 01505 vigra_postcondition(makeReference(init(other.shape(), false)), 01506 "NumpyArray(view_type): Python constructor did not produce a compatible array."); 01507 static_cast<view_type &>(*this) = other; 01508 } 01509 01510 /** 01511 * Construct a new array object, allocating an internal python 01512 * ndarray of the given shape (in fortran order), initialized 01513 * with zeros. 01514 * 01515 * An exception is thrown when construction fails. 01516 */ 01517 explicit NumpyArray(difference_type const & shape) 01518 { 01519 vigra_postcondition(makeReference(init(shape)), 01520 "NumpyArray(shape): Python constructor did not produce a compatible array."); 01521 } 01522 01523 /** 01524 * Construct a new array object, allocating an internal python 01525 * ndarray of the given shape and given stride ordering, initialized 01526 * with zeros. 01527 * 01528 * An exception is thrown when construction fails. 01529 */ 01530 NumpyArray(difference_type const & shape, difference_type const & strideOrdering) 01531 { 01532 vigra_postcondition(makeReference(init(shape, strideOrdering)), 01533 "NumpyArray(shape): Python constructor did not produce a compatible array."); 01534 } 01535 01536 /** 01537 * Constructor from NumpyAnyArray. 01538 * Equivalent to NumpyArray(other.pyObject()) 01539 */ 01540 NumpyArray(const NumpyAnyArray &other, bool createCopy = false) 01541 { 01542 if(!other.hasData()) 01543 return; 01544 if(createCopy) 01545 makeCopy(other.pyObject()); 01546 else 01547 vigra_precondition(makeReference(other.pyObject()), //, false), 01548 "NumpyArray(NumpyAnyArray): Cannot construct from incompatible or empty array."); 01549 } 01550 01551 /** 01552 * Assignment operator. If this is already a view with data 01553 * (i.e. hasData() is true) and the shapes match, the RHS 01554 * array contents are copied. If this is an empty view, 01555 * assignment is identical to makeReferenceUnchecked(other.pyObject()). 01556 * See MultiArrayView::operator= for further information on 01557 * semantics. 01558 */ 01559 NumpyArray &operator=(const NumpyArray &other) 01560 { 01561 if(hasData()) 01562 view_type::operator=(other); 01563 else 01564 makeReferenceUnchecked(other.pyObject()); 01565 return *this; 01566 } 01567 01568 /** 01569 * Assignment operator. If this is already a view with data 01570 * (i.e. hasData() is true) and the shapes match, the RHS 01571 * array contents are copied. 01572 * If this is an empty view, assignment is identical to 01573 * makeReference(other.pyObject()). 01574 * Otherwise, an exception is thrown. 01575 */ 01576 NumpyArray &operator=(const NumpyAnyArray &other) 01577 { 01578 if(hasData()) 01579 { 01580 NumpyAnyArray::operator=(other); 01581 } 01582 else if(isStrictlyCompatible(other.pyObject())) 01583 { 01584 makeReferenceUnchecked(other.pyObject()); 01585 } 01586 else 01587 { 01588 vigra_precondition(false, 01589 "NumpyArray::operator=(): Cannot assign from incompatible array."); 01590 } 01591 return *this; 01592 } 01593 01594 /** 01595 * Test whether a given python object is a numpy array that can be 01596 * converted (copied) into an array compatible to this NumpyArray type. 01597 * This means that the array's shape conforms to the requirements of 01598 * makeCopy(). 01599 */ 01600 static bool isCopyCompatible(PyObject *obj) 01601 { 01602 return ArrayTraits::isArray(obj) && 01603 ArrayTraits::isShapeCompatible((PyArrayObject *)obj); 01604 } 01605 01606 /** 01607 * Test whether a given python object is a numpy array with a 01608 * compatible dtype and the correct shape and strides, so that it 01609 * can be referenced as a view by this NumpyArray type (i.e. 01610 * it conforms to the requirements of makeReference()). 01611 */ 01612 static bool isReferenceCompatible(PyObject *obj) 01613 { 01614 return ArrayTraits::isArray(obj) && 01615 ArrayTraits::isPropertyCompatible((PyArrayObject *)obj); 01616 } 01617 01618 /** 01619 * Like isReferenceCompatible(obj), but also executes a customized type compatibility 01620 * check when such a check has been registered for this class via 01621 * registerPythonArrayType(). 01622 * 01623 * This facilitates proper overload resolution between 01624 * NumpyArray<3, Multiband<T> > (a multiband image) and NumpyArray<3, Singleband<T> > (a scalar volume). 01625 */ 01626 static bool isStrictlyCompatible(PyObject *obj) 01627 { 01628 #if VIGRA_CONVERTER_DEBUG 01629 std::cerr << "class " << typeid(NumpyArray).name() << " got " << obj->ob_type->tp_name << "\n"; 01630 bool isClassCompatible=ArrayTraits::isClassCompatible(obj); 01631 bool isPropertyCompatible((PyArrayObject *)obj); 01632 std::cerr<<"isClassCompatible: "<<isClassCompatible<<std::endl; 01633 std::cerr<<"isPropertyCompatible: "<<isPropertyCompatible<<std::endl; 01634 #endif 01635 return ArrayTraits::isClassCompatible(obj) && 01636 ArrayTraits::isPropertyCompatible((PyArrayObject *)obj); 01637 } 01638 01639 /** 01640 * Create a vector representing the standard stride ordering of a NumpyArray. 01641 * That is, we get a vector representing the range [0,...,N-1], which 01642 * denotes the stride ordering for Fortran order. 01643 */ 01644 static difference_type standardStrideOrdering() 01645 { 01646 difference_type strideOrdering; 01647 for(unsigned int k=0; k<N; ++k) 01648 strideOrdering[k] = k; 01649 return strideOrdering; 01650 } 01651 01652 /** 01653 * Set up a view to the given object without checking compatibility. 01654 * This function must not be used unless isReferenceCompatible(obj) returned 01655 * true on the given object (otherwise, a crash is likely). 01656 */ 01657 void makeReferenceUnchecked(PyObject *obj) 01658 { 01659 NumpyAnyArray::makeReference(obj); 01660 setupArrayView(); 01661 } 01662 01663 /** 01664 * Try to set up a view referencing the given PyObject. 01665 * Returns false if the python object is not a compatible 01666 * numpy array (see isReferenceCompatible() or 01667 * isStrictlyCompatible(), according to the parameter \a 01668 * strict). 01669 */ 01670 bool makeReference(PyObject *obj, bool strict = true) 01671 { 01672 if(strict) 01673 { 01674 if(!isStrictlyCompatible(obj)) 01675 return false; 01676 } 01677 else 01678 { 01679 if(!isReferenceCompatible(obj)) 01680 return false; 01681 } 01682 makeReferenceUnchecked(obj); 01683 return true; 01684 } 01685 01686 /** 01687 * Try to set up a view referencing the same data as the given 01688 * NumpyAnyArray. This overloaded variant simply calls 01689 * makeReference() on array.pyObject(). 01690 */ 01691 bool makeReference(const NumpyAnyArray &array, bool strict = true) 01692 { 01693 return makeReference(array.pyObject(), strict); 01694 } 01695 01696 /** 01697 * Set up an unsafe reference to the given MultiArrayView. 01698 * ATTENTION: This creates a numpy.ndarray that points to the 01699 * same data, but does not own it, so it must be ensured by 01700 * other means that the memory does not get freed before the 01701 * end of the ndarray's lifetime! (One elegant way would be 01702 * to set the 'base' attribute of the resulting ndarray to a 01703 * python object which directly or indirectly holds the memory 01704 * of the given MultiArrayView.) 01705 */ 01706 void makeReference(const view_type &multiArrayView) 01707 { 01708 vigra_precondition(!hasData(), "makeReference(): cannot replace existing view with given buffer"); 01709 01710 // construct an ndarray that points to our data (taking strides into account): 01711 python_ptr array(ArrayTraits::constructor(multiArrayView.shape(), multiArrayView.data(), multiArrayView.stride())); 01712 01713 view_type::operator=(multiArrayView); 01714 pyArray_ = array; 01715 } 01716 01717 /** 01718 Try to create a copy of the given PyObject. 01719 Raises an exception when obj is not a compatible array 01720 (see isCopyCompatible() or isStrictlyCompatible(), according to the 01721 parameter \a strict) or the Python constructor call failed. 01722 */ 01723 void makeCopy(PyObject *obj, bool strict = false) 01724 { 01725 vigra_precondition(strict ? isStrictlyCompatible(obj) : isCopyCompatible(obj), 01726 "NumpyArray::makeCopy(obj): Cannot copy an incompatible array."); 01727 01728 int M = PyArray_NDIM(obj); 01729 TinyVector<npy_intp, N> shape; 01730 std::copy(PyArray_DIMS(obj), PyArray_DIMS(obj)+M, shape.begin()); 01731 if(M == N-1) 01732 shape[M] = 1; 01733 vigra_postcondition(makeReference(init(shape, false)), 01734 "NumpyArray::makeCopy(obj): Copy created an incompatible array."); 01735 NumpyAnyArray::operator=(NumpyAnyArray(obj)); 01736 // if(PyArray_CopyInto(pyArray(), (PyArrayObject*)obj) == -1) 01737 // pythonToCppException(0); 01738 } 01739 01740 /** 01741 Allocate new memory with the given shape and initialize with zeros.<br> 01742 If a stride ordering is given, the resulting array will have this stride 01743 ordering, when it is compatible with the array's memory layout (unstrided 01744 arrays only permit the standard ascending stride ordering). 01745 01746 <em>Note:</em> this operation invalidates dependent objects 01747 (MultiArrayViews and iterators) 01748 */ 01749 void reshape(difference_type const & shape, difference_type const & strideOrdering = standardStrideOrdering()) 01750 { 01751 vigra_postcondition(makeReference(init(shape, strideOrdering)), 01752 "NumpyArray(shape): Python constructor did not produce a compatible array."); 01753 } 01754 01755 /** 01756 When this array has no data, allocate new memory with the given \a shape and 01757 initialize with zeros. Otherwise, check if the new shape matches the old shape 01758 and throw a precondition exception with the given \a message if not. 01759 */ 01760 void reshapeIfEmpty(difference_type const & shape, std::string message = "") 01761 { 01762 reshapeIfEmpty(shape, standardStrideOrdering(), message); 01763 } 01764 01765 /** 01766 When this array has no data, allocate new memory with the given \a shape and 01767 initialize with zeros. Otherwise, check if the new shape matches the old shape 01768 and throw a precondition exception with the given \a message if not. If strict 01769 is true, the given stride ordering must also match that of the existing data. 01770 */ 01771 void reshapeIfEmpty(difference_type const & shape, difference_type const & strideOrdering, 01772 std::string message = "", bool strict = false) 01773 { 01774 if(hasData()) 01775 { 01776 if(strict) 01777 { 01778 if(message == "") 01779 message = "NumpyArray::reshapeIfEmpty(shape): array was not empty, and shape or stride ordering did not match."; 01780 vigra_precondition(shape == this->shape() && strideOrdering == this->strideOrdering(), message.c_str()); 01781 } 01782 else 01783 { 01784 if(message == "") 01785 message = "NumpyArray::reshapeIfEmpty(shape): array was not empty, and shape did not match."; 01786 vigra_precondition(shape == this->shape(), message.c_str()); 01787 } 01788 } 01789 else 01790 { 01791 reshape(shape, strideOrdering); 01792 } 01793 } 01794 }; 01795 01796 // this function assumes that pyArray_ has already been set, and compatibility been checked 01797 template <unsigned int N, class T, class Stride> 01798 void NumpyArray<N, T, Stride>::setupArrayView() 01799 { 01800 if(NumpyAnyArray::hasData()) 01801 { 01802 unsigned int dimension = std::min<unsigned int>(actual_dimension, pyArray()->nd); 01803 std::copy(pyArray()->dimensions, pyArray()->dimensions + dimension, this->m_shape.begin()); 01804 std::copy(pyArray()->strides, pyArray()->strides + dimension, this->m_stride.begin()); 01805 if(pyArray()->nd < actual_dimension) 01806 { 01807 this->m_shape[dimension] = 1; 01808 this->m_stride[dimension] = sizeof(value_type); 01809 } 01810 this->m_stride /= sizeof(value_type); 01811 this->m_ptr = reinterpret_cast<pointer>(pyArray()->data); 01812 } 01813 else 01814 { 01815 this->m_ptr = 0; 01816 } 01817 } 01818 01819 01820 typedef NumpyArray<2, float > NumpyFArray2; 01821 typedef NumpyArray<3, float > NumpyFArray3; 01822 typedef NumpyArray<4, float > NumpyFArray4; 01823 typedef NumpyArray<2, Singleband<float> > NumpyFImage; 01824 typedef NumpyArray<3, Singleband<float> > NumpyFVolume; 01825 typedef NumpyArray<2, RGBValue<float> > NumpyFRGBImage; 01826 typedef NumpyArray<3, RGBValue<float> > NumpyFRGBVolume; 01827 typedef NumpyArray<3, Multiband<float> > NumpyFMultibandImage; 01828 typedef NumpyArray<4, Multiband<float> > NumpyFMultibandVolume; 01829 01830 inline void import_vigranumpy() 01831 { 01832 if(_import_array() < 0) 01833 pythonToCppException(0); 01834 python_ptr module(PyImport_ImportModule("vigra.vigranumpycore"), python_ptr::keep_count); 01835 pythonToCppException(module); 01836 } 01837 01838 /********************************************************/ 01839 /* */ 01840 /* NumpyArray Multiband Argument Object Factories */ 01841 /* */ 01842 /********************************************************/ 01843 01844 template <class PixelType, class Stride> 01845 inline triple<ConstStridedImageIterator<PixelType>, 01846 ConstStridedImageIterator<PixelType>, 01847 MultibandVectorAccessor<PixelType> > 01848 srcImageRange(NumpyArray<3, Multiband<PixelType>, Stride> const & img) 01849 { 01850 ConstStridedImageIterator<PixelType> 01851 ul(img.data(), 1, img.stride(0), img.stride(1)); 01852 return triple<ConstStridedImageIterator<PixelType>, 01853 ConstStridedImageIterator<PixelType>, 01854 MultibandVectorAccessor<PixelType> > 01855 (ul, ul + Size2D(img.shape(0), img.shape(1)), MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2))); 01856 } 01857 01858 template <class PixelType, class Stride> 01859 inline pair< ConstStridedImageIterator<PixelType>, 01860 MultibandVectorAccessor<PixelType> > 01861 srcImage(NumpyArray<3, Multiband<PixelType>, Stride> const & img) 01862 { 01863 ConstStridedImageIterator<PixelType> 01864 ul(img.data(), 1, img.stride(0), img.stride(1)); 01865 return pair<ConstStridedImageIterator<PixelType>, MultibandVectorAccessor<PixelType> > 01866 (ul, MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2))); 01867 } 01868 01869 template <class PixelType, class Stride> 01870 inline triple< StridedImageIterator<PixelType>, 01871 StridedImageIterator<PixelType>, 01872 MultibandVectorAccessor<PixelType> > 01873 destImageRange(NumpyArray<3, Multiband<PixelType>, Stride> & img) 01874 { 01875 StridedImageIterator<PixelType> 01876 ul(img.data(), 1, img.stride(0), img.stride(1)); 01877 typedef typename AccessorTraits<PixelType>::default_accessor Accessor; 01878 return triple<StridedImageIterator<PixelType>, 01879 StridedImageIterator<PixelType>, 01880 MultibandVectorAccessor<PixelType> > 01881 (ul, ul + Size2D(img.shape(0), img.shape(1)), 01882 MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2))); 01883 } 01884 01885 template <class PixelType, class Stride> 01886 inline pair< StridedImageIterator<PixelType>, 01887 MultibandVectorAccessor<PixelType> > 01888 destImage(NumpyArray<3, Multiband<PixelType>, Stride> & img) 01889 { 01890 StridedImageIterator<PixelType> 01891 ul(img.data(), 1, img.stride(0), img.stride(1)); 01892 return pair<StridedImageIterator<PixelType>, MultibandVectorAccessor<PixelType> > 01893 (ul, MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2))); 01894 } 01895 01896 template <class PixelType, class Stride> 01897 inline pair< ConstStridedImageIterator<PixelType>, 01898 MultibandVectorAccessor<PixelType> > 01899 maskImage(NumpyArray<3, Multiband<PixelType>, Stride> const & img) 01900 { 01901 ConstStridedImageIterator<PixelType> 01902 ul(img.data(), 1, img.stride(0), img.stride(1)); 01903 typedef typename AccessorTraits<PixelType>::default_accessor Accessor; 01904 return pair<ConstStridedImageIterator<PixelType>, MultibandVectorAccessor<PixelType> > 01905 (ul, MultibandVectorAccessor<PixelType>(img.shape(2), img.stride(2))); 01906 } 01907 01908 } // namespace vigra 01909 01910 #endif // VIGRA_NUMPY_ARRAY_HXX
© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) |
html generated using doxygen and Python
|