work on #2100: pyopencv_to functions now can receive argument information through...
authorAlexander Mordvintesv <zzznah@gmail.com>
Tue, 7 Aug 2012 18:03:17 +0000 (21:03 +0300)
committerAlexander Mordvintesv <zzznah@gmail.com>
Tue, 7 Aug 2012 18:03:17 +0000 (21:03 +0300)
modules/python/src2/cv2.cpp
modules/python/src2/gen2.py

index ad6555b..be759ec 100644 (file)
@@ -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 = "<unknown>", 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 = "<unknown>"
 
     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 = "<unknown>"
 
     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 = "<unknown>"
     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 = "<unknown>"
         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 = "<unknown>"
 
     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 = "<unknown>"
     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<typename _Tp> struct pyopencvVecConverter
 {
-    static bool to(PyObject* obj, vector<_Tp>& value, const char* name="<unknown>")
+    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<typename _Tp> 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<typename _Tp> 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<typename _Tp> 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<typename _Tp> struct pyopencvVecConverter
 };
 
 
-template<typename _Tp> static inline bool pyopencv_to(PyObject* obj, vector<_Tp>& value, const char* name="<unknown>")
+template<typename _Tp> 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<typename _Tp> static inline PyObject* pyopencv_from(const vector<_Tp>& value)
@@ -707,13 +726,13 @@ template<typename _Tp> static inline PyObject* pyopencv_from(const vector<_Tp>&
 static PyObject* pyopencv_from(const KeyPoint&);
 static PyObject* pyopencv_from(const DMatch&);
 
-template<typename _Tp> static inline bool pyopencv_to_generic_vec(PyObject* obj, vector<_Tp>& value, const char* name="<unknown>")
+template<typename _Tp> 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<typename _Tp> 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<typename _Tp> struct pyopencvVecConverter<vector<_Tp> >
 
 template<> struct pyopencvVecConverter<Mat>
 {
-    static bool to(PyObject* obj, vector<Mat>& value, const char* name="<unknown>")
+    static bool to(PyObject* obj, vector<Mat>& 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<Mat>& value)
@@ -779,9 +798,9 @@ template<> struct pyopencvVecConverter<Mat>
 
 template<> struct pyopencvVecConverter<KeyPoint>
 {
-    static bool to(PyObject* obj, vector<KeyPoint>& value, const char* name="<unknown>")
+    static bool to(PyObject* obj, vector<KeyPoint>& 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<KeyPoint>& value)
@@ -792,9 +811,9 @@ template<> struct pyopencvVecConverter<KeyPoint>
 
 template<> struct pyopencvVecConverter<DMatch>
 {
-    static bool to(PyObject* obj, vector<DMatch>& value, const char* name="<unknown>")
+    static bool to(PyObject* obj, vector<DMatch>& 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<DMatch>& value)
@@ -805,9 +824,9 @@ template<> struct pyopencvVecConverter<DMatch>
 
 template<> struct pyopencvVecConverter<string>
 {
-    static bool to(PyObject* obj, vector<string>& value, const char* name="<unknown>")
+    static bool to(PyObject* obj, vector<string>& 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<string>& value)
index c7ae066..b239f08 100644 (file)
@@ -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])