#ifndef CV2_NUMPY_HPP #define CV2_NUMPY_HPP #include "cv2.hpp" #include "opencv2/core.hpp" class NumpyAllocator : public cv::MatAllocator { public: NumpyAllocator() { stdAllocator = cv::Mat::getStdAllocator(); } ~NumpyAllocator() {} cv::UMatData* allocate(PyObject* o, int dims, const int* sizes, int type, size_t* step) const; cv::UMatData* allocate(int dims0, const int* sizes, int type, void* data, size_t* step, cv::AccessFlag flags, cv::UMatUsageFlags usageFlags) const CV_OVERRIDE; bool allocate(cv::UMatData* u, cv::AccessFlag accessFlags, cv::UMatUsageFlags usageFlags) const CV_OVERRIDE; void deallocate(cv::UMatData* u) const CV_OVERRIDE; const cv::MatAllocator* stdAllocator; }; extern NumpyAllocator g_numpyAllocator; //====================================================================================================================== // HACK(?): function from cv2_util.hpp extern int failmsg(const char *fmt, ...); namespace { template NPY_TYPES asNumpyType() { return NPY_OBJECT; } template<> NPY_TYPES asNumpyType() { return NPY_BOOL; } #define CV_GENERATE_INTEGRAL_TYPE_NPY_CONVERSION(src, dst) \ template<> \ NPY_TYPES asNumpyType() \ { \ return NPY_##dst; \ } \ template<> \ NPY_TYPES asNumpyType() \ { \ return NPY_U##dst; \ } CV_GENERATE_INTEGRAL_TYPE_NPY_CONVERSION(int8_t, INT8) CV_GENERATE_INTEGRAL_TYPE_NPY_CONVERSION(int16_t, INT16) CV_GENERATE_INTEGRAL_TYPE_NPY_CONVERSION(int32_t, INT32) CV_GENERATE_INTEGRAL_TYPE_NPY_CONVERSION(int64_t, INT64) #undef CV_GENERATE_INTEGRAL_TYPE_NPY_CONVERSION template<> NPY_TYPES asNumpyType() { return NPY_FLOAT; } template<> NPY_TYPES asNumpyType() { return NPY_DOUBLE; } template PyArray_Descr* getNumpyTypeDescriptor() { return PyArray_DescrFromType(asNumpyType()); } template <> PyArray_Descr* getNumpyTypeDescriptor() { #if SIZE_MAX == ULONG_MAX return PyArray_DescrFromType(NPY_ULONG); #elif SIZE_MAX == ULLONG_MAX return PyArray_DescrFromType(NPY_ULONGLONG); #else return PyArray_DescrFromType(NPY_UINT); #endif } template bool isRepresentable(U value) { return (std::numeric_limits::min() <= value) && (value <= std::numeric_limits::max()); } template bool canBeSafelyCasted(PyObject* obj, PyArray_Descr* to) { return PyArray_CanCastTo(PyArray_DescrFromScalar(obj), to) != 0; } template<> bool canBeSafelyCasted(PyObject* obj, PyArray_Descr* to) { PyArray_Descr* from = PyArray_DescrFromScalar(obj); if (PyArray_CanCastTo(from, to)) { return true; } else { // False negative scenarios: // - Signed input is positive so it can be safely cast to unsigned output // - Input has wider limits but value is representable within output limits // - All the above if (PyDataType_ISSIGNED(from)) { int64_t input = 0; PyArray_CastScalarToCtype(obj, &input, getNumpyTypeDescriptor()); return (input >= 0) && isRepresentable(static_cast(input)); } else { uint64_t input = 0; PyArray_CastScalarToCtype(obj, &input, getNumpyTypeDescriptor()); return isRepresentable(input); } return false; } } template bool parseNumpyScalar(PyObject* obj, T& value) { if (PyArray_CheckScalar(obj)) { // According to the numpy documentation: // There are 21 statically-defined PyArray_Descr objects for the built-in data-types // So descriptor pointer is not owning. PyArray_Descr* to = getNumpyTypeDescriptor(); if (canBeSafelyCasted(obj, to)) { PyArray_CastScalarToCtype(obj, &value, to); return true; } } return false; } struct SafeSeqItem { PyObject * item; SafeSeqItem(PyObject *obj, size_t idx) { item = PySequence_GetItem(obj, idx); } ~SafeSeqItem() { Py_XDECREF(item); } private: SafeSeqItem(const SafeSeqItem&); // = delete SafeSeqItem& operator=(const SafeSeqItem&); // = delete }; template class RefWrapper { public: RefWrapper(T& item) : item_(item) {} T& get() CV_NOEXCEPT { return item_; } private: T& item_; }; // In order to support this conversion on 3.x branch - use custom reference_wrapper // and C-style array instead of std::array template bool parseSequence(PyObject* obj, RefWrapper (&value)[N], const ArgInfo& info) { if (!obj || obj == Py_None) { return true; } if (!PySequence_Check(obj)) { failmsg("Can't parse '%s'. Input argument doesn't provide sequence " "protocol", info.name); return false; } const std::size_t sequenceSize = PySequence_Size(obj); if (sequenceSize != N) { failmsg("Can't parse '%s'. Expected sequence length %lu, got %lu", info.name, N, sequenceSize); return false; } for (std::size_t i = 0; i < N; ++i) { SafeSeqItem seqItem(obj, i); if (!pyopencv_to(seqItem.item, value[i].get(), info)) { failmsg("Can't parse '%s'. Sequence item with index %lu has a " "wrong type", info.name, i); return false; } } return true; } } // namespace #endif // CV2_NUMPY_HPP