123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- #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<class T>
- NPY_TYPES asNumpyType()
- {
- return NPY_OBJECT;
- }
- template<>
- NPY_TYPES asNumpyType<bool>()
- {
- return NPY_BOOL;
- }
- #define CV_GENERATE_INTEGRAL_TYPE_NPY_CONVERSION(src, dst) \
- template<> \
- NPY_TYPES asNumpyType<src>() \
- { \
- return NPY_##dst; \
- } \
- template<> \
- NPY_TYPES asNumpyType<u##src>() \
- { \
- 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<float>()
- {
- return NPY_FLOAT;
- }
- template<>
- NPY_TYPES asNumpyType<double>()
- {
- return NPY_DOUBLE;
- }
- template <class T>
- PyArray_Descr* getNumpyTypeDescriptor()
- {
- return PyArray_DescrFromType(asNumpyType<T>());
- }
- template <>
- PyArray_Descr* getNumpyTypeDescriptor<size_t>()
- {
- #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 <class T, class U>
- bool isRepresentable(U value) {
- return (std::numeric_limits<T>::min() <= value) && (value <= std::numeric_limits<T>::max());
- }
- template<class T>
- bool canBeSafelyCasted(PyObject* obj, PyArray_Descr* to)
- {
- return PyArray_CanCastTo(PyArray_DescrFromScalar(obj), to) != 0;
- }
- template<>
- bool canBeSafelyCasted<size_t>(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<int64_t>());
- return (input >= 0) && isRepresentable<size_t>(static_cast<uint64_t>(input));
- }
- else
- {
- uint64_t input = 0;
- PyArray_CastScalarToCtype(obj, &input, getNumpyTypeDescriptor<uint64_t>());
- return isRepresentable<size_t>(input);
- }
- return false;
- }
- }
- template<class T>
- 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<T>();
- if (canBeSafelyCasted<T>(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 T>
- 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<T, N>
- template <class T, std::size_t N>
- bool parseSequence(PyObject* obj, RefWrapper<T> (&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
|