From: Alexander Mordvintesv Date: Tue, 7 Aug 2012 18:03:17 +0000 (+0300) Subject: work on #2100: pyopencv_to functions now can receive argument information through... X-Git-Tag: accepted/2.0/20130307.220821~364^2~272^2~24 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0adf68ae621a28cb196d6ef3c875ad02e83a9fee;p=profile%2Fivi%2Fopencv.git work on #2100: pyopencv_to functions now can receive argument information through ArgInfo structure. Non-contiguous input numpy arrays are copied. In case of non-contiguous output array the TypeError is thrown. --- diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index ad6555b..be759ec 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -45,6 +45,20 @@ static int failmsg(const char *fmt, ...) return 0; } +struct ArgInfo +{ + const char * name; + bool outputarg; + // more fields may be added if necessary + + ArgInfo(const char * name_, bool outputarg_) + : name(name_) + , outputarg(outputarg_) {} + + // to match with older pyopencv_to function signature + operator const char *() const { return name; } +}; + class PyAllowThreads { public: @@ -199,7 +213,8 @@ NumpyAllocator g_numpyAllocator; enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 }; -static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "", bool allowND=true) +// special case, when the convertor needs full ArgInfo structure +static int pyopencv_to(const PyObject* o, Mat& m, const ArgInfo info, bool allowND=true) { if(!o || o == Py_None) { @@ -210,7 +225,7 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "" if( !PyArray_Check(o) ) { - failmsg("%s is not a numpy array", name); + failmsg("%s is not a numpy array", info.name); return false; } @@ -223,14 +238,14 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "" if( type < 0 ) { - failmsg("%s data type = %d is not supported", name, typenum); + failmsg("%s data type = %d is not supported", info.name, typenum); return false; } int ndims = PyArray_NDIM(o); if(ndims >= CV_MAX_DIM) { - failmsg("%s dimensionality (=%d) is too high", name, ndims); + failmsg("%s dimensionality (=%d) is too high", info.name, ndims); return false; } @@ -238,7 +253,21 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "" size_t step[CV_MAX_DIM+1], elemsize = CV_ELEM_SIZE1(type); const npy_intp* _sizes = PyArray_DIMS(o); const npy_intp* _strides = PyArray_STRIDES(o); - bool transposed = false; + bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX; + + bool needcopy = (_strides[ndims-1] != elemsize) + || (ismultichannel && _strides[ndims-2] != elemsize*_sizes[ndims-1]); + + if (needcopy) + { + if (info.outputarg) + { + failmsg("output array %s is not row-contiguous (step[ndims-1] != elemsize)", info.name); + return false; + } + o = (PyObject*)PyArray_GETCONTIGUOUS((PyArrayObject*)o); + _strides = PyArray_STRIDES(o); + } for(int i = 0; i < ndims; i++) { @@ -246,20 +275,14 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "" step[i] = (size_t)_strides[i]; } - if( ndims == 0 || step[ndims-1] > elemsize ) { + // handle degenerate case + if( ndims == 0) { size[ndims] = 1; step[ndims] = elemsize; ndims++; } - if( ndims >= 2 && step[0] < step[1] ) - { - std::swap(size[0], size[1]); - std::swap(step[0], step[1]); - transposed = true; - } - - if( ndims == 3 && size[2] <= CV_CN_MAX && step[1] == elemsize*size[2] ) + if( ismultichannel ) { ndims--; type |= CV_MAKETYPE(0, size[2]); @@ -267,7 +290,7 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "" if( ndims > 2 && !allowND ) { - failmsg("%s has more than 2 dimensions", name); + failmsg("%s has more than 2 dimensions", info.name); return false; } @@ -276,18 +299,14 @@ static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "" if( m.data ) { m.refcount = refcountFromPyObject(o); - m.addref(); // protect the original numpy array from deallocation - // (since Mat destructor will decrement the reference counter) + if (!needcopy) + { + m.addref(); // protect the original numpy array from deallocation + // (since Mat destructor will decrement the reference counter) + } }; m.allocator = &g_numpyAllocator; - if( transposed ) - { - Mat tmp; - tmp.allocator = &g_numpyAllocator; - transpose(m, tmp); - m = tmp; - } return true; } @@ -593,7 +612,7 @@ static inline PyObject* pyopencv_from(const Point2d& p) template struct pyopencvVecConverter { - static bool to(PyObject* obj, vector<_Tp>& value, const char* name="") + static bool to(PyObject* obj, vector<_Tp>& value, const ArgInfo info) { typedef typename DataType<_Tp>::channel_type _Cp; if(!obj || obj == Py_None) @@ -601,12 +620,12 @@ template struct pyopencvVecConverter if (PyArray_Check(obj)) { Mat m; - pyopencv_to(obj, m, name); + pyopencv_to(obj, m, info); m.copyTo(value); } if (!PySequence_Check(obj)) return false; - PyObject *seq = PySequence_Fast(obj, name); + PyObject *seq = PySequence_Fast(obj, info.name); if (seq == NULL) return false; int i, j, n = (int)PySequence_Fast_GET_SIZE(seq); @@ -635,7 +654,7 @@ template struct pyopencvVecConverter if( PyArray_Check(item)) { Mat src; - pyopencv_to(item, src, name); + pyopencv_to(item, src, info); if( src.dims != 2 || src.channels() != 1 || ((src.cols != 1 || src.rows != channels) && (src.cols != channels || src.rows != 1))) @@ -647,7 +666,7 @@ template struct pyopencvVecConverter continue; } - seq_i = PySequence_Fast(item, name); + seq_i = PySequence_Fast(item, info.name); if( !seq_i || (int)PySequence_Fast_GET_SIZE(seq_i) != channels ) { Py_XDECREF(seq_i); @@ -694,9 +713,9 @@ template struct pyopencvVecConverter }; -template static inline bool pyopencv_to(PyObject* obj, vector<_Tp>& value, const char* name="") +template static inline bool pyopencv_to(PyObject* obj, vector<_Tp>& value, const ArgInfo info) { - return pyopencvVecConverter<_Tp>::to(obj, value, name); + return pyopencvVecConverter<_Tp>::to(obj, value, info); } template static inline PyObject* pyopencv_from(const vector<_Tp>& value) @@ -707,13 +726,13 @@ template static inline PyObject* pyopencv_from(const vector<_Tp>& static PyObject* pyopencv_from(const KeyPoint&); static PyObject* pyopencv_from(const DMatch&); -template static inline bool pyopencv_to_generic_vec(PyObject* obj, vector<_Tp>& value, const char* name="") +template static inline bool pyopencv_to_generic_vec(PyObject* obj, vector<_Tp>& value, const ArgInfo info) { if(!obj || obj == Py_None) return true; if (!PySequence_Check(obj)) return false; - PyObject *seq = PySequence_Fast(obj, name); + PyObject *seq = PySequence_Fast(obj, info.name); if (seq == NULL) return false; int i, n = (int)PySequence_Fast_GET_SIZE(seq); @@ -724,7 +743,7 @@ template static inline bool pyopencv_to_generic_vec(PyObject* obj, for( i = 0; i < n; i++ ) { PyObject* item = items[i]; - if(!pyopencv_to(item, value[i], name)) + if(!pyopencv_to(item, value[i], info)) break; } Py_DECREF(seq); @@ -766,9 +785,9 @@ template struct pyopencvVecConverter > template<> struct pyopencvVecConverter { - static bool to(PyObject* obj, vector& value, const char* name="") + static bool to(PyObject* obj, vector& value, const ArgInfo info) { - return pyopencv_to_generic_vec(obj, value, name); + return pyopencv_to_generic_vec(obj, value, info); } static PyObject* from(const vector& value) @@ -779,9 +798,9 @@ template<> struct pyopencvVecConverter template<> struct pyopencvVecConverter { - static bool to(PyObject* obj, vector& value, const char* name="") + static bool to(PyObject* obj, vector& value, const ArgInfo info) { - return pyopencv_to_generic_vec(obj, value, name); + return pyopencv_to_generic_vec(obj, value, info); } static PyObject* from(const vector& value) @@ -792,9 +811,9 @@ template<> struct pyopencvVecConverter template<> struct pyopencvVecConverter { - static bool to(PyObject* obj, vector& value, const char* name="") + static bool to(PyObject* obj, vector& value, const ArgInfo info) { - return pyopencv_to_generic_vec(obj, value, name); + return pyopencv_to_generic_vec(obj, value, info); } static PyObject* from(const vector& value) @@ -805,9 +824,9 @@ template<> struct pyopencvVecConverter template<> struct pyopencvVecConverter { - static bool to(PyObject* obj, vector& value, const char* name="") + static bool to(PyObject* obj, vector& value, const ArgInfo info) { - return pyopencv_to_generic_vec(obj, value, name); + return pyopencv_to_generic_vec(obj, value, info); } static PyObject* from(const vector& value) diff --git a/modules/python/src2/gen2.py b/modules/python/src2/gen2.py index c7ae066..b239f08 100644 --- a/modules/python/src2/gen2.py +++ b/modules/python/src2/gen2.py @@ -329,6 +329,9 @@ class ArgInfo(object): def isbig(self): return self.tp == "Mat" or self.tp == "vector_Mat"# or self.tp.startswith("vector") + def crepr(self): + return "ArgInfo(\"%s\", %d)" % (self.name, self.outputarg) + class FuncVariant(object): def __init__(self, classname, name, decl, isconstructor): @@ -561,7 +564,7 @@ class FuncInfo(object): if amapping[1] == "O": code_decl += " PyObject* pyobj_%s = NULL;\n" % (a.name,) parse_name = "pyobj_" + a.name - code_cvt_list.append("pyopencv_to(pyobj_%s, %s)" % (a.name, a.name)) + code_cvt_list.append("pyopencv_to(pyobj_%s, %s, %s)" % (a.name, a.name, a.crepr())) all_cargs.append([amapping, parse_name])