Limited API support for Python3
authorMaksim Shabunin <maksim.shabunin@gmail.com>
Thu, 21 Mar 2019 07:45:02 +0000 (10:45 +0300)
committerMaksim Shabunin <maksim.shabunin@gmail.com>
Tue, 11 Jun 2019 12:20:43 +0000 (15:20 +0300)
modules/dnn/misc/python/pyopencv_dnn.hpp
modules/flann/misc/python/pyopencv_flann.hpp
modules/python/bindings/CMakeLists.txt
modules/python/common.cmake
modules/python/python3/CMakeLists.txt
modules/python/src2/cv2.cpp
modules/python/src2/gen2.py
modules/python/src2/pycompat.hpp

index 03728f6..b1cc7c7 100644 (file)
@@ -21,16 +21,19 @@ bool pyopencv_to(PyObject *o, dnn::DictValue &dv, const char *name)
     }
     else if (PyFloat_Check(o))
     {
-        dv = dnn::DictValue(PyFloat_AS_DOUBLE(o));
+        dv = dnn::DictValue(PyFloat_AsDouble(o));
         return true;
     }
-    else if (PyString_Check(o))
+    else
     {
-        dv = dnn::DictValue(String(PyString_AsString(o)));
-        return true;
+        std::string str;
+        if (getUnicodeString(o, str))
+        {
+            dv = dnn::DictValue(str);
+            return true;
+        }
     }
-    else
-        return false;
+    return false;
 }
 
 template<>
@@ -134,7 +137,7 @@ public:
 
         PyObject* args = PyList_New(inputs.size());
         for(size_t i = 0; i < inputs.size(); ++i)
-            PyList_SET_ITEM(args, i, pyopencv_from_generic_vec(inputs[i]));
+            PyList_SetItem(args, i, pyopencv_from_generic_vec(inputs[i]));
 
         PyObject* res = PyObject_CallMethodObjArgs(o, PyString_FromString("getMemoryShapes"), args, NULL);
         Py_DECREF(args);
index 91e0564..2f56afb 100644 (file)
@@ -27,20 +27,20 @@ bool pyopencv_to(PyObject *o, cv::flann::IndexParams& p, const char *name)
         return true;
 
     if(PyDict_Check(o)) {
-        while(PyDict_Next(o, &pos, &key, &item)) {
-            if( !PyString_Check(key) ) {
+        while(PyDict_Next(o, &pos, &key, &item))
+        {
+            // get key
+            std::string k;
+            if (!getUnicodeString(key, k))
+            {
                 ok = false;
                 break;
             }
-
-            String k = PyString_AsString(key);
-            if( PyString_Check(item) )
+            // get value
+            if( !!PyBool_Check(item) )
             {
-                const char* value = PyString_AsString(item);
-                p.setString(k, value);
-            }
-            else if( !!PyBool_Check(item) )
                 p.setBool(k, item == Py_True);
+            }
             else if( PyInt_Check(item) )
             {
                 int value = (int)PyInt_AsLong(item);
@@ -56,8 +56,13 @@ bool pyopencv_to(PyObject *o, cv::flann::IndexParams& p, const char *name)
             }
             else
             {
-                ok = false;
-                break;
+                std::string val_str;
+                if (!getUnicodeString(item, val_str))
+                {
+                    ok = false;
+                    break;
+                }
+                p.setString(k, val_str);
             }
         }
     }
@@ -79,4 +84,4 @@ bool pyopencv_to(PyObject *o, cvflann::flann_distance_t& dist, const char *name)
     dist = (cvflann::flann_distance_t)d;
     return ok;
 }
-#endif
\ No newline at end of file
+#endif
index d96d7e8..4ad3d0c 100644 (file)
@@ -51,11 +51,13 @@ if(NOT HAVE_CUDA)
 endif()
 
 set(cv2_generated_files
-    "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_include.h"
+    "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_enums.h"
     "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_funcs.h"
+    "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_include.h"
+    "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_modules.h"
+    "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_modules_content.h"
     "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_types.h"
-    "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_type_reg.h"
-    "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_ns_reg.h"
+    "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_types_content.h"
     "${OPENCV_PYTHON_SIGNATURES_FILE}"
 )
 
index 17503c0..6a9d32d 100644 (file)
@@ -24,6 +24,22 @@ if(TARGET gen_opencv_python_source)
   add_dependencies(${the_module} gen_opencv_python_source)
 endif()
 
+ocv_assert(${PYTHON}_VERSION_MAJOR)
+ocv_assert(${PYTHON}_VERSION_MINOR)
+
+if(${PYTHON}_LIMITED_API)
+  # support only python3.3+
+  ocv_assert(${PYTHON}_VERSION_MAJOR EQUAL 3 AND ${PYTHON}_VERSION_MINOR GREATER 2)
+  target_compile_definitions(${the_module} PRIVATE CVPY_DYNAMIC_INIT)
+  if(WIN32)
+    string(REPLACE
+      "python${${PYTHON}_VERSION_MAJOR}${${PYTHON}_VERSION_MINOR}.lib"
+      "python${${PYTHON}_VERSION_MAJOR}.lib"
+      ${PYTHON}_LIBRARIES
+      "${${PYTHON}_LIBRARIES}")
+  endif()
+endif()
+
 if(APPLE)
   set_target_properties(${the_module} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
 elseif(WIN32 OR OPENCV_FORCE_PYTHON_LIBS)
@@ -54,6 +70,13 @@ else()
   if(NOT PYTHON_CVPY_PROCESS EQUAL 0)
     set(CVPY_SUFFIX ".so")
   endif()
+  if(${PYTHON}_LIMITED_API)
+    if(WIN32)
+      string(REGEX REPLACE "\\.[^\\.]*\\." "." CVPY_SUFFIX "${CVPY_SUFFIX}")
+    else()
+      string(REGEX REPLACE "\\.[^\\.]*\\." ".abi${${PYTHON}_VERSION_MAJOR}." CVPY_SUFFIX "${CVPY_SUFFIX}")
+    endif()
+  endif()
 endif()
 
 ocv_update(OPENCV_PYTHON_EXTENSION_BUILD_PATH "${LIBRARY_OUTPUT_PATH}/${MODULE_INSTALL_SUBDIR}")
@@ -111,9 +134,6 @@ else()
   set(PYTHON_INSTALL_ARCHIVE ARCHIVE DESTINATION ${${PYTHON}_PACKAGES_PATH} COMPONENT python)
 endif()
 
-ocv_assert(${PYTHON}_VERSION_MAJOR)
-ocv_assert(${PYTHON}_VERSION_MINOR)
-
 set(__python_loader_subdir "")
 if(NOT OPENCV_SKIP_PYTHON_LOADER)
   set(__python_loader_subdir "cv2/")
index da86ba5..ae1f989 100644 (file)
@@ -2,6 +2,14 @@ if(NOT PYTHON3_INCLUDE_PATH OR NOT PYTHON3_NUMPY_INCLUDE_DIRS)
   ocv_module_disable(python3)
 endif()
 
+# Problem in numpy >=1.15 <1.17
+if(PYTHON3_LIMITED_API
+    AND NOT PYTHON3_NUMPY_VERSION VERSION_LESS "1.15"
+    AND PYTHON3_NUMPY_VERSION VERSION_LESS "1.17"
+  )
+  set(PYTHON3_LIMITED_API OFF)
+endif()
+
 set(the_description "The python3 bindings")
 set(MODULE_NAME python3)
 set(MODULE_INSTALL_SUBDIR python3)
index a00398f..ff37cfe 100644 (file)
@@ -5,12 +5,36 @@
 #pragma warning(push)
 #pragma warning(disable:5033)  // 'register' is no longer a supported storage class
 #endif
+
+// #define CVPY_DYNAMIC_INIT
+// #define Py_DEBUG
+
+#if defined(CVPY_DYNAMIC_INIT) && !defined(Py_DEBUG)
+#   define Py_LIMITED_API 0x03030000
+#endif
+
 #include <math.h>
 #include <Python.h>
+
+#if PY_MAJOR_VERSION < 3
+#undef CVPY_DYNAMIC_INIT
+#endif
+
 #if defined(_MSC_VER) && (_MSC_VER > 1800)
 #pragma warning(pop)
 #endif
 
+#define MODULESTR "cv2"
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+
+#include <numpy/ndarrayobject.h>
+
+#include "pyopencv_generated_include.h"
+#include "opencv2/core/types_c.h"
+#include "opencv2/opencv_modules.hpp"
+#include "pycompat.hpp"
+#include <map>
+
 #include <type_traits>  // std::enable_if
 
 template<typename T, class TEnable = void>  // TEnable is used for SFINAE checks
@@ -26,95 +50,6 @@ bool pyopencv_to(PyObject* obj, T& p, const char* name = "<unknown>") { return P
 template<typename T> static
 PyObject* pyopencv_from(const T& src) { return PyOpenCV_Converter<T>::from(src); }
 
-
-#define CV_PY_FN_WITH_KW_(fn, flags) (PyCFunction)(void*)(PyCFunctionWithKeywords)(fn), (flags) | METH_VARARGS | METH_KEYWORDS
-#define CV_PY_FN_NOARGS_(fn, flags) (PyCFunction)(fn), (flags) | METH_NOARGS
-
-#define CV_PY_FN_WITH_KW(fn) CV_PY_FN_WITH_KW_(fn, 0)
-#define CV_PY_FN_NOARGS(fn) CV_PY_FN_NOARGS_(fn, 0)
-
-
-#define MODULESTR "cv2"
-#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
-#include <numpy/ndarrayobject.h>
-
-#if PY_MAJOR_VERSION >= 3
-#  define CV_PYTHON_TYPE_HEAD_INIT() PyVarObject_HEAD_INIT(&PyType_Type, 0)
-#else
-#  define CV_PYTHON_TYPE_HEAD_INIT() PyObject_HEAD_INIT(&PyType_Type) 0,
-#endif
-
-#define CV_PY_TO_CLASS(TYPE)                                                                          \
-template<>                                                                                            \
-bool pyopencv_to(PyObject* dst, TYPE& src, const char* name)                                          \
-{                                                                                                     \
-    if (!dst || dst == Py_None)                                                                       \
-        return true;                                                                                  \
-    Ptr<TYPE> ptr;                                                                                    \
-                                                                                                      \
-    if (!pyopencv_to(dst, ptr, name)) return false;                                                   \
-    src = *ptr;                                                                                       \
-    return true;                                                                                      \
-}
-
-#define CV_PY_FROM_CLASS(TYPE)                                                                        \
-template<>                                                                                            \
-PyObject* pyopencv_from(const TYPE& src)                                                              \
-{                                                                                                     \
-    Ptr<TYPE> ptr(new TYPE());                                                                        \
-                                                                                                      \
-    *ptr = src;                                                                                       \
-    return pyopencv_from(ptr);                                                                        \
-}
-
-#define CV_PY_TO_CLASS_PTR(TYPE)                                                                      \
-template<>                                                                                            \
-bool pyopencv_to(PyObject* dst, TYPE*& src, const char* name)                                         \
-{                                                                                                     \
-    if (!dst || dst == Py_None)                                                                       \
-        return true;                                                                                  \
-    Ptr<TYPE> ptr;                                                                                    \
-                                                                                                      \
-    if (!pyopencv_to(dst, ptr, name)) return false;                                                   \
-    src = ptr;                                                                                        \
-    return true;                                                                                      \
-}
-
-#define CV_PY_FROM_CLASS_PTR(TYPE)                                                                    \
-static PyObject* pyopencv_from(TYPE*& src)                                                            \
-{                                                                                                     \
-    return pyopencv_from(Ptr<TYPE>(src));                                                             \
-}
-
-#define CV_PY_TO_ENUM(TYPE)                                                                           \
-template<>                                                                                            \
-bool pyopencv_to(PyObject* dst, TYPE& src, const char* name)                                          \
-{                                                                                                     \
-    if (!dst || dst == Py_None)                                                                       \
-        return true;                                                                                  \
-    int underlying = 0;                                                  \
-                                                                                                      \
-    if (!pyopencv_to(dst, underlying, name)) return false;                                            \
-    src = static_cast<TYPE>(underlying);                                                              \
-    return true;                                                                                      \
-}
-
-#define CV_PY_FROM_ENUM(TYPE)                                                                         \
-template<>                                                                                            \
-PyObject* pyopencv_from(const TYPE& src)                                                              \
-{                                                                                                     \
-    return pyopencv_from(static_cast<int>(src));                         \
-}
-
-#include "pyopencv_generated_include.h"
-#include "opencv2/core/types_c.h"
-
-#include "opencv2/opencv_modules.hpp"
-
-#include "pycompat.hpp"
-
-#include <map>
-
 static PyObject* opencv_error = NULL;
 
 static int failmsg(const char *fmt, ...)
@@ -339,7 +274,7 @@ static bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo info)
         m = Mat(sz, 1, CV_64F);
         for( i = 0; i < sz; i++ )
         {
-            PyObject* oi = PyTuple_GET_ITEM(o, i);
+            PyObject* oi = PyTuple_GetItem(o, i);
             if( PyInt_Check(oi) )
                 m.at<double>(i) = (double)PyInt_AsLong(oi);
             else if( PyFloat_Check(oi) )
@@ -573,21 +508,26 @@ static PyObject* pyopencv_from(void*& ptr)
     return PyLong_FromVoidPtr(ptr);
 }
 
+struct SafeSeqItem
+{
+    PyObject * item;
+    SafeSeqItem(PyObject *obj, size_t idx) { item = PySequence_GetItem(obj, idx); }
+    ~SafeSeqItem() { Py_XDECREF(item); }
+};
+
 static bool pyopencv_to(PyObject *o, Scalar& s, const ArgInfo info)
 {
     if(!o || o == Py_None)
         return true;
     if (PySequence_Check(o)) {
-        PyObject *fi = PySequence_Fast(o, info.name);
-        if (fi == NULL)
-            return false;
-        if (4 < PySequence_Fast_GET_SIZE(fi))
+        if (4 < PySequence_Size(o))
         {
             failmsg("Scalar value for argument '%s' is longer than 4", info.name);
             return false;
         }
-        for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(fi); i++) {
-            PyObject *item = PySequence_Fast_GET_ITEM(fi, i);
+        for (Py_ssize_t i = 0; i < PySequence_Size(o); i++) {
+            SafeSeqItem item_wrap(o, i);
+            PyObject *item = item_wrap.item;
             if (PyFloat_Check(item) || PyInt_Check(item)) {
                 s[(int)i] = PyFloat_AsDouble(item);
             } else {
@@ -595,7 +535,6 @@ static bool pyopencv_to(PyObject *o, Scalar& s, const ArgInfo info)
                 return false;
             }
         }
-        Py_DECREF(fi);
     } else {
         if (PyFloat_Check(o) || PyInt_Check(o)) {
             s[0] = PyFloat_AsDouble(o);
@@ -769,16 +708,18 @@ PyObject* pyopencv_from(const String& value)
 }
 
 template<>
-bool pyopencv_to(PyObject* obj, Stringvalue, const char* name)
+bool pyopencv_to(PyObject* obj, String &value, const char* name)
 {
     CV_UNUSED(name);
     if(!obj || obj == Py_None)
         return true;
-    const char* str = PyString_AsString(obj);
-    if(!str)
-        return false;
-    value = String(str);
-    return true;
+    std::string str;
+    if (getUnicodeString(obj, str))
+    {
+        value = str;
+        return true;
+    }
+    return false;
 }
 
 template<>
@@ -849,36 +790,31 @@ bool pyopencv_to(PyObject* obj, Range& r, const char* name)
         return true;
     while (PySequence_Check(obj))
     {
-        PyObject *fi = PySequence_Fast(obj, name);
-        if (fi == NULL)
-            break;
-        if (2 != PySequence_Fast_GET_SIZE(fi))
+        if (2 != PySequence_Size(obj))
         {
             failmsg("Range value for argument '%s' is longer than 2", name);
-            Py_DECREF(fi);
             return false;
         }
         {
-            PyObject *item = PySequence_Fast_GET_ITEM(fi, 0);
+            SafeSeqItem item_wrap(obj, 0);
+            PyObject *item = item_wrap.item;
             if (PyInt_Check(item)) {
                 r.start = (int)PyInt_AsLong(item);
             } else {
                 failmsg("Range.start value for argument '%s' is not integer", name);
-                Py_DECREF(fi);
                 break;
             }
         }
         {
-            PyObject *item = PySequence_Fast_GET_ITEM(fi, 1);
+            SafeSeqItem item_wrap(obj, 1);
+            PyObject *item = item_wrap.item;
             if (PyInt_Check(item)) {
                 r.end = (int)PyInt_AsLong(item);
             } else {
                 failmsg("Range.end value for argument '%s' is not integer", name);
-                Py_DECREF(fi);
                 break;
             }
         }
-        Py_DECREF(fi);
         return true;
     }
     if(PyObject_Size(obj) == 0)
@@ -901,11 +837,10 @@ bool pyopencv_to(PyObject* obj, Point& p, const char* name)
     CV_UNUSED(name);
     if(!obj || obj == Py_None)
         return true;
-    if(!!PyComplex_CheckExact(obj))
+    if(PyComplex_Check(obj))
     {
-        Py_complex c = PyComplex_AsCComplex(obj);
-        p.x = saturate_cast<int>(c.real);
-        p.y = saturate_cast<int>(c.imag);
+        p.x = saturate_cast<int>(PyComplex_RealAsDouble(obj));
+        p.y = saturate_cast<int>(PyComplex_ImagAsDouble(obj));
         return true;
     }
     return PyArg_ParseTuple(obj, "ii", &p.x, &p.y) > 0;
@@ -917,11 +852,10 @@ bool pyopencv_to(PyObject* obj, Point2f& p, const char* name)
     CV_UNUSED(name);
     if(!obj || obj == Py_None)
         return true;
-    if(!!PyComplex_CheckExact(obj))
+    if (PyComplex_Check(obj))
     {
-        Py_complex c = PyComplex_AsCComplex(obj);
-        p.x = saturate_cast<float>(c.real);
-        p.y = saturate_cast<float>(c.imag);
+        p.x = saturate_cast<float>(PyComplex_RealAsDouble(obj));
+        p.y = saturate_cast<float>(PyComplex_ImagAsDouble(obj));
         return true;
     }
     return PyArg_ParseTuple(obj, "ff", &p.x, &p.y) > 0;
@@ -933,11 +867,10 @@ bool pyopencv_to(PyObject* obj, Point2d& p, const char* name)
     CV_UNUSED(name);
     if(!obj || obj == Py_None)
         return true;
-    if(!!PyComplex_CheckExact(obj))
+    if(PyComplex_Check(obj))
     {
-        Py_complex c = PyComplex_AsCComplex(obj);
-        p.x = saturate_cast<double>(c.real);
-        p.y = saturate_cast<double>(c.imag);
+        p.x = PyComplex_RealAsDouble(obj);
+        p.y = PyComplex_ImagAsDouble(obj);
         return true;
     }
     return PyArg_ParseTuple(obj, "dd", &p.x, &p.y) > 0;
@@ -1164,9 +1097,41 @@ PyObject* pyopencv_from(const Point3d& p)
 
 template<typename _Tp> struct pyopencvVecConverter
 {
+    typedef typename DataType<_Tp>::channel_type _Cp;
+    static inline bool copyOneItem(PyObject *obj, size_t start, int channels, _Cp * data)
+    {
+        for(size_t j = 0; (int)j < channels; j++ )
+        {
+            SafeSeqItem sub_item_wrap(obj, start + j);
+            PyObject* item_ij = sub_item_wrap.item;
+            if( PyInt_Check(item_ij))
+            {
+                int v = (int)PyInt_AsLong(item_ij);
+                if( v == -1 && PyErr_Occurred() )
+                    return false;
+                data[j] = saturate_cast<_Cp>(v);
+            }
+            else if( PyLong_Check(item_ij))
+            {
+                int v = (int)PyLong_AsLong(item_ij);
+                if( v == -1 && PyErr_Occurred() )
+                    return false;
+                data[j] = saturate_cast<_Cp>(v);
+            }
+            else if( PyFloat_Check(item_ij))
+            {
+                double v = PyFloat_AsDouble(item_ij);
+                if( PyErr_Occurred() )
+                    return false;
+                data[j] = saturate_cast<_Cp>(v);
+            }
+            else
+                return false;
+        }
+        return true;
+    }
     static bool to(PyObject* obj, std::vector<_Tp>& value, const ArgInfo info)
     {
-        typedef typename DataType<_Tp>::channel_type _Cp;
         if(!obj || obj == Py_None)
             return true;
         if (PyArray_Check(obj))
@@ -1174,92 +1139,63 @@ template<typename _Tp> struct pyopencvVecConverter
             Mat m;
             pyopencv_to(obj, m, info);
             m.copyTo(value);
+            return true;
         }
-        if (!PySequence_Check(obj))
-            return false;
-        PyObject *seq = PySequence_Fast(obj, info.name);
-        if (seq == NULL)
-            return false;
-        int i, j, n = (int)PySequence_Fast_GET_SIZE(seq);
-        value.resize(n);
-
-        int type = traits::Type<_Tp>::value;
-        int depth = CV_MAT_DEPTH(type), channels = CV_MAT_CN(type);
-        PyObject** items = PySequence_Fast_ITEMS(seq);
-
-        for( i = 0; i < n; i++ )
+        else if (PySequence_Check(obj))
         {
-            PyObject* item = items[i];
-            PyObject* seq_i = 0;
-            PyObject** items_i = &item;
-            _Cp* data = (_Cp*)&value[i];
-
-            if( channels == 2 && PyComplex_CheckExact(item) )
+            const int type = traits::Type<_Tp>::value;
+            const int depth = CV_MAT_DEPTH(type), channels = CV_MAT_CN(type);
+            size_t i, n = PySequence_Size(obj);
+            value.resize(n);
+            for (i = 0; i < n; i++ )
             {
-                Py_complex c = PyComplex_AsCComplex(obj);
-                data[0] = saturate_cast<_Cp>(c.real);
-                data[1] = saturate_cast<_Cp>(c.imag);
-                continue;
-            }
-            if( channels > 1 )
-            {
-                if( PyArray_Check(item))
-                {
-                    Mat src;
-                    pyopencv_to(item, src, info);
-                    if( src.dims != 2 || src.channels() != 1 ||
-                       ((src.cols != 1 || src.rows != channels) &&
-                        (src.cols != channels || src.rows != 1)))
-                        break;
-                    Mat dst(src.rows, src.cols, depth, data);
-                    src.convertTo(dst, type);
-                    if( dst.data != (uchar*)data )
-                        break;
-                    continue;
-                }
-
-                seq_i = PySequence_Fast(item, info.name);
-                if( !seq_i || (int)PySequence_Fast_GET_SIZE(seq_i) != channels )
-                {
-                    Py_XDECREF(seq_i);
-                    break;
-                }
-                items_i = PySequence_Fast_ITEMS(seq_i);
-            }
+                SafeSeqItem item_wrap(obj, i);
+                PyObject* item = item_wrap.item;
+                _Cp* data = (_Cp*)&value[i];
 
-            for( j = 0; j < channels; j++ )
-            {
-                PyObject* item_ij = items_i[j];
-                if( PyInt_Check(item_ij))
+                if( channels == 2 && PyComplex_Check(item) )
                 {
-                    int v = (int)PyInt_AsLong(item_ij);
-                    if( v == -1 && PyErr_Occurred() )
-                        break;
-                    data[j] = saturate_cast<_Cp>(v);
+                    data[0] = saturate_cast<_Cp>(PyComplex_RealAsDouble(item));
+                    data[1] = saturate_cast<_Cp>(PyComplex_ImagAsDouble(item));
                 }
-                else if( PyLong_Check(item_ij))
+                else if( channels > 1 )
                 {
-                    int v = (int)PyLong_AsLong(item_ij);
-                    if( v == -1 && PyErr_Occurred() )
+                    if( PyArray_Check(item))
+                    {
+                        Mat src;
+                        pyopencv_to(item, src, info);
+                        if( src.dims != 2 || src.channels() != 1 ||
+                           ((src.cols != 1 || src.rows != channels) &&
+                            (src.cols != channels || src.rows != 1)))
+                            break;
+                        Mat dst(src.rows, src.cols, depth, data);
+                        src.convertTo(dst, type);
+                        if( dst.data != (uchar*)data )
+                            break;
+                    }
+                    else if (PySequence_Check(item))
+                    {
+                        if (!copyOneItem(item, 0, channels, data))
+                            break;
+                    }
+                    else
+                    {
                         break;
-                    data[j] = saturate_cast<_Cp>(v);
+                    }
                 }
-                else if( PyFloat_Check(item_ij))
+                else if (channels == 1)
                 {
-                    double v = PyFloat_AsDouble(item_ij);
-                    if( PyErr_Occurred() )
+                    if (!copyOneItem(obj, i, channels, data))
                         break;
-                    data[j] = saturate_cast<_Cp>(v);
                 }
                 else
+                {
                     break;
+                }
             }
-            Py_XDECREF(seq_i);
-            if( j < channels )
-                break;
+            return i == n;
         }
-        Py_DECREF(seq);
-        return i == n;
+        return false;
     }
 
     static PyObject* from(const std::vector<_Tp>& value)
@@ -1291,22 +1227,15 @@ template<typename _Tp> static inline bool pyopencv_to_generic_vec(PyObject* obj,
        return true;
     if (!PySequence_Check(obj))
         return false;
-    PyObject *seq = PySequence_Fast(obj, info.name);
-    if (seq == NULL)
-        return false;
-    int i, n = (int)PySequence_Fast_GET_SIZE(seq);
+    size_t n = PySequence_Size(obj);
     value.resize(n);
-
-    PyObject** items = PySequence_Fast_ITEMS(seq);
-
-    for( i = 0; i < n; i++ )
+    for(size_t i = 0; i < n; i++ )
     {
-        PyObject* item = items[i];
-        if(!pyopencv_to(item, value[i], info))
-            break;
+        SafeSeqItem item_wrap(obj, i);
+        if(!pyopencv_to(item_wrap.item, value[i], info))
+            return false;
     }
-    Py_DECREF(seq);
-    return i == n;
+    return true;
 }
 
 template<typename _Tp> static inline PyObject* pyopencv_from_generic_vec(const std::vector<_Tp>& value)
@@ -1318,7 +1247,7 @@ template<typename _Tp> static inline PyObject* pyopencv_from_generic_vec(const s
         PyObject* item = pyopencv_from(value[i]);
         if(!item)
             break;
-        PyList_SET_ITEM(seq, i, item);
+        PyList_SetItem(seq, i, item);
     }
     if( i < n )
     {
@@ -1697,31 +1626,37 @@ static PyObject *pycvCreateButton(PyObject*, PyObject *args, PyObject *kw)
 
 static int convert_to_char(PyObject *o, char *dst, const char *name = "no_name")
 {
-  if (PyString_Check(o) && PyString_Size(o) == 1) {
-    *dst = PyString_AsString(o)[0];
-    return 1;
-  } else {
+    std::string str;
+    if (getUnicodeString(o, str))
+    {
+        *dst = str[0];
+        return 1;
+    }
     (*dst) = 0;
     return failmsg("Expected single character string for argument '%s'", name);
-  }
 }
 
-#if PY_MAJOR_VERSION >= 3
-#define MKTYPE2(NAME) pyopencv_##NAME##_specials(); if (!to_ok(&pyopencv_##NAME##_Type)) return NULL;
-#else
-#define MKTYPE2(NAME) pyopencv_##NAME##_specials(); if (!to_ok(&pyopencv_##NAME##_Type)) return
-#endif
-
 #ifdef __GNUC__
 #  pragma GCC diagnostic ignored "-Wunused-parameter"
 #  pragma GCC diagnostic ignored "-Wmissing-field-initializers"
 #endif
 
+
 #include "pyopencv_generated_enums.h"
 #include "pyopencv_custom_headers.h"
+
+#ifdef CVPY_DYNAMIC_INIT
+#define CVPY_TYPE(NAME, STORAGE, SNAME, _1, _2) CVPY_TYPE_DECLARE_DYNAMIC(NAME, STORAGE, SNAME)
+#else
+#define CVPY_TYPE(NAME, STORAGE, SNAME, _1, _2) CVPY_TYPE_DECLARE(NAME, STORAGE, SNAME)
+#endif
 #include "pyopencv_generated_types.h"
+#undef CVPY_TYPE
+
+#include "pyopencv_generated_types_content.h"
 #include "pyopencv_generated_funcs.h"
 
+
 static PyMethodDef special_methods[] = {
   {"redirectError", CV_PY_FN_WITH_KW(pycvRedirectError), "redirectError(onError) -> None"},
 #ifdef HAVE_OPENCV_HIGHGUI
@@ -1786,23 +1721,90 @@ static void init_submodule(PyObject * root, const char * name, PyMethodDef * met
 
 }
 
-#include "pyopencv_generated_ns_reg.h"
+#include "pyopencv_generated_modules_content.h"
 
-static int to_ok(PyTypeObject *to)
+static bool init_body(PyObject * m)
 {
-  to->tp_alloc = PyType_GenericAlloc;
-  to->tp_new = PyType_GenericNew;
-  to->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
-  return (PyType_Ready(to) == 0);
-}
+#define CVPY_MODULE(NAMESTR, NAME) \
+    init_submodule(m, MODULESTR NAMESTR, methods_##NAME, consts_##NAME)
+    #include "pyopencv_generated_modules.h"
+#undef CVPY_MODULE
+
+#ifdef CVPY_DYNAMIC_INIT
+#define CVPY_TYPE(NAME, _1, _2, BASE, CONSTRUCTOR) CVPY_TYPE_INIT_DYNAMIC(NAME, return false, BASE, CONSTRUCTOR)
+    PyObject * pyopencv_NoBase_TypePtr = NULL;
+#else
+#define CVPY_TYPE(NAME, _1, _2, BASE, CONSTRUCTOR) CVPY_TYPE_INIT_STATIC(NAME, return false, BASE, CONSTRUCTOR)
+    PyTypeObject * pyopencv_NoBase_TypePtr = NULL;
+#endif
+    #include "pyopencv_generated_types.h"
+#undef CVPY_TYPE
 
+    PyObject* d = PyModule_GetDict(m);
+
+
+    PyDict_SetItemString(d, "__version__", PyString_FromString(CV_VERSION));
+
+    PyObject *opencv_error_dict = PyDict_New();
+    PyDict_SetItemString(opencv_error_dict, "file", Py_None);
+    PyDict_SetItemString(opencv_error_dict, "func", Py_None);
+    PyDict_SetItemString(opencv_error_dict, "line", Py_None);
+    PyDict_SetItemString(opencv_error_dict, "code", Py_None);
+    PyDict_SetItemString(opencv_error_dict, "msg", Py_None);
+    PyDict_SetItemString(opencv_error_dict, "err", Py_None);
+    opencv_error = PyErr_NewException((char*)MODULESTR".error", NULL, opencv_error_dict);
+    Py_DECREF(opencv_error_dict);
+    PyDict_SetItemString(d, "error", opencv_error);
+
+
+#define PUBLISH(I) PyDict_SetItemString(d, #I, PyInt_FromLong(I))
+    PUBLISH(CV_8U);
+    PUBLISH(CV_8UC1);
+    PUBLISH(CV_8UC2);
+    PUBLISH(CV_8UC3);
+    PUBLISH(CV_8UC4);
+    PUBLISH(CV_8S);
+    PUBLISH(CV_8SC1);
+    PUBLISH(CV_8SC2);
+    PUBLISH(CV_8SC3);
+    PUBLISH(CV_8SC4);
+    PUBLISH(CV_16U);
+    PUBLISH(CV_16UC1);
+    PUBLISH(CV_16UC2);
+    PUBLISH(CV_16UC3);
+    PUBLISH(CV_16UC4);
+    PUBLISH(CV_16S);
+    PUBLISH(CV_16SC1);
+    PUBLISH(CV_16SC2);
+    PUBLISH(CV_16SC3);
+    PUBLISH(CV_16SC4);
+    PUBLISH(CV_32S);
+    PUBLISH(CV_32SC1);
+    PUBLISH(CV_32SC2);
+    PUBLISH(CV_32SC3);
+    PUBLISH(CV_32SC4);
+    PUBLISH(CV_32F);
+    PUBLISH(CV_32FC1);
+    PUBLISH(CV_32FC2);
+    PUBLISH(CV_32FC3);
+    PUBLISH(CV_32FC4);
+    PUBLISH(CV_64F);
+    PUBLISH(CV_64FC1);
+    PUBLISH(CV_64FC2);
+    PUBLISH(CV_64FC3);
+    PUBLISH(CV_64FC4);
+#undef PUBLISH
+
+    return true;
+}
 
 #if defined(__GNUC__)
 #pragma GCC visibility push(default)
 #endif
 
 #if PY_MAJOR_VERSION >= 3
-PyMODINIT_FUNC PyInit_cv2();
+// === Python 3
+
 static struct PyModuleDef cv2_moduledef =
 {
     PyModuleDef_HEAD_INIT,
@@ -1813,92 +1815,24 @@ static struct PyModuleDef cv2_moduledef =
     special_methods
 };
 
+PyMODINIT_FUNC PyInit_cv2();
 PyObject* PyInit_cv2()
+{
+    import_array(); // from numpy
+    PyObject* m = PyModule_Create(&cv2_moduledef);
+    if (!init_body(m))
+        return NULL;
+    return m;
+}
+
 #else
+// === Python 2
 PyMODINIT_FUNC initcv2();
-
 void initcv2()
-#endif
 {
-  import_array();
-
-#include "pyopencv_generated_type_reg.h"
-
-#if PY_MAJOR_VERSION >= 3
-  PyObject* m = PyModule_Create(&cv2_moduledef);
-#else
-  PyObject* m = Py_InitModule(MODULESTR, special_methods);
-#endif
-  init_submodules(m); // from "pyopencv_generated_ns_reg.h"
-
-  PyObject* d = PyModule_GetDict(m);
-
-  PyDict_SetItemString(d, "__version__", PyString_FromString(CV_VERSION));
-
-  PyObject *opencv_error_dict = PyDict_New();
-  PyDict_SetItemString(opencv_error_dict, "file", Py_None);
-  PyDict_SetItemString(opencv_error_dict, "func", Py_None);
-  PyDict_SetItemString(opencv_error_dict, "line", Py_None);
-  PyDict_SetItemString(opencv_error_dict, "code", Py_None);
-  PyDict_SetItemString(opencv_error_dict, "msg", Py_None);
-  PyDict_SetItemString(opencv_error_dict, "err", Py_None);
-  opencv_error = PyErr_NewException((char*)MODULESTR".error", NULL, opencv_error_dict);
-  Py_DECREF(opencv_error_dict);
-  PyDict_SetItemString(d, "error", opencv_error);
-
-#if PY_MAJOR_VERSION >= 3
-#define PUBLISH_OBJECT(name, type) Py_INCREF(&type);\
-  PyModule_AddObject(m, name, (PyObject *)&type);
-#else
-// Unrolled Py_INCREF(&type) without (PyObject*) cast
-// due to "warning: dereferencing type-punned pointer will break strict-aliasing rules"
-#define PUBLISH_OBJECT(name, type) _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA (&type)->ob_refcnt++;\
-  PyModule_AddObject(m, name, (PyObject *)&type);
-#endif
-
-#include "pyopencv_generated_type_publish.h"
-
-#define PUBLISH(I) PyDict_SetItemString(d, #I, PyInt_FromLong(I))
-//#define PUBLISHU(I) PyDict_SetItemString(d, #I, PyLong_FromUnsignedLong(I))
-#define PUBLISH2(I, value) PyDict_SetItemString(d, #I, PyLong_FromLong(value))
-
-  PUBLISH(CV_8U);
-  PUBLISH(CV_8UC1);
-  PUBLISH(CV_8UC2);
-  PUBLISH(CV_8UC3);
-  PUBLISH(CV_8UC4);
-  PUBLISH(CV_8S);
-  PUBLISH(CV_8SC1);
-  PUBLISH(CV_8SC2);
-  PUBLISH(CV_8SC3);
-  PUBLISH(CV_8SC4);
-  PUBLISH(CV_16U);
-  PUBLISH(CV_16UC1);
-  PUBLISH(CV_16UC2);
-  PUBLISH(CV_16UC3);
-  PUBLISH(CV_16UC4);
-  PUBLISH(CV_16S);
-  PUBLISH(CV_16SC1);
-  PUBLISH(CV_16SC2);
-  PUBLISH(CV_16SC3);
-  PUBLISH(CV_16SC4);
-  PUBLISH(CV_32S);
-  PUBLISH(CV_32SC1);
-  PUBLISH(CV_32SC2);
-  PUBLISH(CV_32SC3);
-  PUBLISH(CV_32SC4);
-  PUBLISH(CV_32F);
-  PUBLISH(CV_32FC1);
-  PUBLISH(CV_32FC2);
-  PUBLISH(CV_32FC3);
-  PUBLISH(CV_32FC4);
-  PUBLISH(CV_64F);
-  PUBLISH(CV_64FC1);
-  PUBLISH(CV_64FC2);
-  PUBLISH(CV_64FC3);
-  PUBLISH(CV_64FC4);
+    import_array(); // from numpy
+    PyObject* m = Py_InitModule(MODULESTR, special_methods);
+    init_body(m);
+}
 
-#if PY_MAJOR_VERSION >= 3
-    return m;
 #endif
-}
index 0e962b3..81cfe15 100755 (executable)
@@ -16,20 +16,12 @@ ignored_arg_types = ["RNG*"]
 
 pass_by_val_types = ["Point*", "Point2f*", "Rect*", "String*", "double*", "float*", "int*"]
 
-gen_template_check_self = Template("""    $cname* _self_ = NULL;
-    if(PyObject_TypeCheck(self, &pyopencv_${name}_Type))
-        _self_ = ${amp}((pyopencv_${name}_t*)self)->v${get};
-    if (!_self_)
-        return failmsgp("Incorrect type of self (must be '${name}' or its derivative)");
-""")
-
-gen_template_check_self_algo = Template("""    $cname* _self_ = NULL;
-    if(PyObject_TypeCheck(self, &pyopencv_${name}_Type))
-        _self_ = dynamic_cast<$cname*>(${amp}((pyopencv_${name}_t*)self)->v.get());
-    if (!_self_)
+gen_template_check_self = Template("""
+    ${cname} * self1 = 0;
+    if (!pyopencv_${name}_getp(self, self1))
         return failmsgp("Incorrect type of self (must be '${name}' or its derivative)");
+    ${pname} _self_ = ${cvt}(self1);
 """)
-
 gen_template_call_constructor_prelude = Template("""new (&(self->v)) Ptr<$cname>(); // init Ptr with placement new
         if(self) """)
 
@@ -50,53 +42,6 @@ gen_template_func_body = Template("""$code_decl
     }
 """)
 
-head_init_str = "CV_PYTHON_TYPE_HEAD_INIT()"
-
-gen_template_simple_type_decl = Template("""
-struct pyopencv_${name}_t
-{
-    PyObject_HEAD
-    ${cname} v;
-};
-
-static PyTypeObject pyopencv_${name}_Type =
-{
-    %s
-    MODULESTR".$wname",
-    sizeof(pyopencv_${name}_t),
-};
-
-static void pyopencv_${name}_dealloc(PyObject* self)
-{
-    ((pyopencv_${name}_t*)self)->v.${cname}::~${sname}();
-    PyObject_Del(self);
-}
-
-template<>
-struct PyOpenCV_Converter< ${cname} >
-{
-    static PyObject* from(const ${cname}& r)
-    {
-        pyopencv_${name}_t *m = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
-        new (&m->v) ${cname}(r); //Copy constructor
-        return (PyObject*)m;
-    }
-
-    static bool to(PyObject* src, ${cname}& dst, const char* name)
-    {
-        if(!src || src == Py_None)
-            return true;
-        if(PyObject_TypeCheck(src, &pyopencv_${name}_Type))
-        {
-            dst = ((pyopencv_${name}_t*)src)->v;
-            return true;
-        }
-        failmsg("Expected ${cname} for argument '%%s'", name);
-        return false;
-    }
-};
-""" % head_init_str)
-
 gen_template_mappable = Template("""
     {
         ${mappable} _src;
@@ -108,43 +53,23 @@ gen_template_mappable = Template("""
 """)
 
 gen_template_type_decl = Template("""
-struct pyopencv_${name}_t
-{
-    PyObject_HEAD
-    Ptr<${cname1}> v;
-};
-
-static PyTypeObject pyopencv_${name}_Type =
-{
-    %s
-    MODULESTR".$wname",
-    sizeof(pyopencv_${name}_t),
-};
-
-static void pyopencv_${name}_dealloc(PyObject* self)
-{
-    ((pyopencv_${name}_t*)self)->v.release();
-    PyObject_Del(self);
-}
+// Converter (${name})
 
 template<>
-struct PyOpenCV_Converter< Ptr<${cname}> >
+struct PyOpenCV_Converter< ${cname} >
 {
-    static PyObject* from(const Ptr<${cname}>& r)
+    static PyObject* from(const ${cname}& r)
     {
-        pyopencv_${name}_t *m = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
-        new (&(m->v)) Ptr<$cname1>(); // init Ptr with placement new
-        m->v = r;
-        return (PyObject*)m;
+        return pyopencv_${name}_Instance(r);
     }
-
-    static bool to(PyObject* src, Ptr<${cname}>& dst, const char* name)
+    static bool to(PyObject* src, ${cname}& dst, const char* name)
     {
         if(!src || src == Py_None)
             return true;
-        if(PyObject_TypeCheck(src, &pyopencv_${name}_Type))
+        ${cname} * dst_;
+        if (pyopencv_${name}_getp(src, dst_))
         {
-            dst = ((pyopencv_${name}_t*)src)->v.dynamicCast<${cname}>();
+            dst = *dst_;
             return true;
         }
         ${mappable_code}
@@ -153,10 +78,11 @@ struct PyOpenCV_Converter< Ptr<${cname}> >
     }
 };
 
-""" % head_init_str)
+""")
 
 gen_template_map_type_cvt = Template("""
 template<> bool pyopencv_to(PyObject* src, ${cname}& dst, const char* name);
+
 """)
 
 gen_template_set_prop_from_map = Template("""
@@ -169,37 +95,26 @@ gen_template_set_prop_from_map = Template("""
     }""")
 
 gen_template_type_impl = Template("""
-static PyObject* pyopencv_${name}_repr(PyObject* self)
-{
-    char str[1000];
-    sprintf(str, "<$wname %p>", self);
-    return PyString_FromString(str);
-}
+// GetSet (${name})
 
 ${getset_code}
 
+// Methods (${name})
+
+${methods_code}
+
+// Tables (${name})
+
 static PyGetSetDef pyopencv_${name}_getseters[] =
 {${getset_inits}
     {NULL}  /* Sentinel */
 };
 
-${methods_code}
-
 static PyMethodDef pyopencv_${name}_methods[] =
 {
 ${methods_inits}
     {NULL,          NULL}
 };
-
-static void pyopencv_${name}_specials(void)
-{
-    pyopencv_${name}_Type.tp_base = ${baseptr};
-    pyopencv_${name}_Type.tp_dealloc = pyopencv_${name}_dealloc;
-    pyopencv_${name}_Type.tp_repr = pyopencv_${name}_repr;
-    pyopencv_${name}_Type.tp_getset = pyopencv_${name}_getseters;
-    pyopencv_${name}_Type.tp_init = (initproc)${constructor};
-    pyopencv_${name}_Type.tp_methods = pyopencv_${name}_methods;${extra_specials}
-}
 """)
 
 
@@ -373,20 +288,29 @@ class ClassInfo(object):
             methods_code.write(m.gen_code(codegen))
             methods_inits.write(m.get_tab_entry())
 
-        baseptr = "NULL"
+        code = gen_template_type_impl.substitute(name=self.name, wname=self.wname, cname=self.cname,
+            getset_code=getset_code.getvalue(), getset_inits=getset_inits.getvalue(),
+            methods_code=methods_code.getvalue(), methods_inits=methods_inits.getvalue())
+
+        return code
+
+    def gen_def(self, codegen):
+        all_classes = codegen.classes
+        baseptr = "NoBase"
         if self.base and self.base in all_classes:
-            baseptr = "&pyopencv_" + all_classes[self.base].name + "_Type"
+            baseptr = all_classes[self.base].name
 
         constructor_name = "0"
         if self.constructor is not None:
             constructor_name = self.constructor.get_wrapper_name()
 
-        code = gen_template_type_impl.substitute(name=self.name, wname=self.wname, cname=self.cname,
-            getset_code=getset_code.getvalue(), getset_inits=getset_inits.getvalue(),
-            methods_code=methods_code.getvalue(), methods_inits=methods_inits.getvalue(),
-            baseptr=baseptr, constructor=constructor_name, extra_specials="")
-
-        return code
+        return "CVPY_TYPE({}, {}, {}, {}, {});\n".format(
+            self.name,
+            self.cname if self.issimple else "Ptr<{}>".format(self.cname),
+            self.sname if self.issimple else "Ptr",
+            baseptr,
+            constructor_name
+        )
 
 
 def handle_ptr(tp):
@@ -634,7 +558,7 @@ class FuncInfo(object):
         code = "%s\n{\n" % (proto,)
         code += "    using namespace %s;\n\n" % self.namespace.replace('.', '::')
 
-        selfinfo = ClassInfo("")
+        selfinfo = None
         ismethod = self.classname != "" and not self.isconstructor
         # full name is needed for error diagnostic in PyArg_ParseTupleAndKeywords
         fullname = self.name
@@ -642,14 +566,13 @@ class FuncInfo(object):
         if self.classname:
             selfinfo = all_classes[self.classname]
             if not self.isconstructor:
-                amp = "&" if selfinfo.issimple else ""
-                if self.is_static:
-                    pass
-                elif selfinfo.isalgorithm:
-                    code += gen_template_check_self_algo.substitute(name=selfinfo.name, cname=selfinfo.cname, amp=amp)
-                else:
-                    get = "" if selfinfo.issimple else ".get()"
-                    code += gen_template_check_self.substitute(name=selfinfo.name, cname=selfinfo.cname, amp=amp, get=get)
+                if not self.is_static:
+                    code += gen_template_check_self.substitute(
+                        name=selfinfo.name,
+                        cname=selfinfo.cname if selfinfo.issimple else "Ptr<{}>".format(selfinfo.cname),
+                        pname=(selfinfo.cname + '*') if selfinfo.issimple else "Ptr<{}>".format(selfinfo.cname),
+                        cvt='' if selfinfo.issimple else '*'
+                    )
                 fullname = selfinfo.wname + "." + fullname
 
         all_code_variants = []
@@ -871,8 +794,8 @@ class PythonWrapperGenerator(object):
         self.code_enums = StringIO()
         self.code_types = StringIO()
         self.code_funcs = StringIO()
-        self.code_type_reg = StringIO()
         self.code_ns_reg = StringIO()
+        self.code_ns_init = StringIO()
         self.code_type_publish = StringIO()
         self.py_signatures = dict()
         self.class_idx = 0
@@ -1013,14 +936,6 @@ class PythonWrapperGenerator(object):
                 self.code_ns_reg.write('    {"%s", static_cast<long>(%s)},\n'%(compat_name, cname))
         self.code_ns_reg.write('    {NULL, 0}\n};\n\n')
 
-    def gen_namespaces_reg(self):
-        self.code_ns_reg.write('static void init_submodules(PyObject * root) \n{\n')
-        for ns_name in sorted(self.namespaces):
-            if ns_name.split('.')[0] == 'cv':
-                wname = normalize_class_name(ns_name)
-                self.code_ns_reg.write('  init_submodule(root, MODULESTR"%s", methods_%s, consts_%s);\n' % (ns_name[2:], wname, wname))
-        self.code_ns_reg.write('};\n')
-
     def gen_enum_reg(self, enum_name):
         name_seg = enum_name.split(".")
         is_enum_class = False
@@ -1113,18 +1028,22 @@ class PythonWrapperGenerator(object):
         classlist = list(self.classes.items())
         classlist.sort()
         for name, classinfo in classlist:
+            self.code_types.write("//{}\n".format(80*"="))
+            self.code_types.write("// {} ({})\n".format(name, 'Map' if classinfo.ismap else 'Generic'))
+            self.code_types.write("//{}\n".format(80*"="))
+            self.code_types.write(classinfo.gen_code(self))
             if classinfo.ismap:
-                self.code_types.write(gen_template_map_type_cvt.substitute(name=name, cname=classinfo.cname))
+                self.code_types.write(gen_template_map_type_cvt.substitute(name=classinfo.name, cname=classinfo.cname))
             else:
-                if classinfo.issimple:
-                    templ = gen_template_simple_type_decl
-                else:
-                    templ = gen_template_type_decl
                 mappable_code = "\n".join([
                                       gen_template_mappable.substitute(cname=classinfo.cname, mappable=mappable)
                                           for mappable in classinfo.mappables])
-                self.code_types.write(templ.substitute(name=name, wname=classinfo.wname, cname=classinfo.cname, sname=classinfo.sname,
-                                      cname1=("cv::Algorithm" if classinfo.isalgorithm else classinfo.cname), mappable_code=mappable_code))
+                code = gen_template_type_decl.substitute(
+                    name=classinfo.name,
+                    cname=classinfo.cname if classinfo.issimple else "Ptr<{}>".format(classinfo.cname),
+                    mappable_code=mappable_code
+                )
+                self.code_types.write(code)
 
         # register classes in the same order as they have been declared.
         # this way, base classes will be registered in Python before their derivatives.
@@ -1132,11 +1051,10 @@ class PythonWrapperGenerator(object):
         classlist1.sort()
 
         for decl_idx, name, classinfo in classlist1:
-            code = classinfo.gen_code(self)
-            self.code_types.write(code)
-            if not classinfo.ismap:
-                self.code_type_reg.write("MKTYPE2(%s);\n" % (classinfo.name,) )
-                self.code_type_publish.write("PUBLISH_OBJECT(\"{name}\", pyopencv_{name}_Type);\n".format(name=classinfo.name))
+            if classinfo.ismap:
+                continue
+            self.code_type_publish.write(classinfo.gen_def(self))
+
 
         # step 3: generate the code for all the global functions
         for ns_name, ns in sorted(self.namespaces.items()):
@@ -1148,7 +1066,7 @@ class PythonWrapperGenerator(object):
                 code = func.gen_code(self)
                 self.code_funcs.write(code)
             self.gen_namespace(ns_name)
-        self.gen_namespaces_reg()
+            self.code_ns_init.write('CVPY_MODULE("{}", {});\n'.format(ns_name[2:], normalize_class_name(ns_name)))
 
         # step 4: generate the code for enum types
         enumlist = list(self.enums.values())
@@ -1166,10 +1084,10 @@ class PythonWrapperGenerator(object):
         self.save(output_path, "pyopencv_generated_include.h", self.code_include)
         self.save(output_path, "pyopencv_generated_funcs.h", self.code_funcs)
         self.save(output_path, "pyopencv_generated_enums.h", self.code_enums)
-        self.save(output_path, "pyopencv_generated_types.h", self.code_types)
-        self.save(output_path, "pyopencv_generated_type_reg.h", self.code_type_reg)
-        self.save(output_path, "pyopencv_generated_ns_reg.h", self.code_ns_reg)
-        self.save(output_path, "pyopencv_generated_type_publish.h", self.code_type_publish)
+        self.save(output_path, "pyopencv_generated_types.h", self.code_type_publish)
+        self.save(output_path, "pyopencv_generated_types_content.h", self.code_types)
+        self.save(output_path, "pyopencv_generated_modules.h", self.code_ns_init)
+        self.save(output_path, "pyopencv_generated_modules_content.h", self.code_ns_reg)
         self.save_json(output_path, "pyopencv_signatures.json", self.py_signatures)
 
 if __name__ == "__main__":
index f4ebea6..8ba0500 100644 (file)
@@ -45,6 +45,7 @@
 #define __PYCOMPAT_HPP__
 
 #if PY_MAJOR_VERSION >= 3
+
 // Python3 treats all ints as longs, PyInt_X functions have been removed.
 #define PyInt_Check PyLong_Check
 #define PyInt_CheckExact PyLong_CheckExact
 #define PyInt_FromLong PyLong_FromLong
 #define PyNumber_Int PyNumber_Long
 
-// Python3 strings are unicode, these defines mimic the Python2 functionality.
-#define PyString_Check PyUnicode_Check
+
 #define PyString_FromString PyUnicode_FromString
 #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
-#define PyString_Size PyUnicode_GET_SIZE
 
-// PyUnicode_AsUTF8 isn't available until Python 3.3
-#if (PY_VERSION_HEX < 0x03030000)
-#define PyString_AsString _PyUnicode_AsString
-#else
-#define PyString_AsString PyUnicode_AsUTF8
+#endif // PY_MAJOR >=3
+
+static inline bool getUnicodeString(PyObject * obj, std::string &str)
+{
+    bool res = false;
+    if (PyUnicode_Check(obj))
+    {
+        PyObject * bytes = PyUnicode_AsUTF8String(obj);
+        if (PyBytes_Check(bytes))
+        {
+            const char * raw = PyBytes_AsString(bytes);
+            if (raw)
+            {
+                str = std::string(raw);
+                res = true;
+            }
+        }
+        Py_XDECREF(bytes);
+    }
+#if PY_MAJOR_VERSION < 3
+    else if (PyString_Check(obj))
+    {
+        const char * raw = PyString_AsString(obj);
+        if (raw)
+        {
+            str = std::string(raw);
+            res = true;
+        }
+    }
 #endif
+    return res;
+}
+
+//==================================================================================================
+
+#define CV_PY_FN_WITH_KW_(fn, flags) (PyCFunction)(void*)(PyCFunctionWithKeywords)(fn), (flags) | METH_VARARGS | METH_KEYWORDS
+#define CV_PY_FN_NOARGS_(fn, flags) (PyCFunction)(fn), (flags) | METH_NOARGS
+
+#define CV_PY_FN_WITH_KW(fn) CV_PY_FN_WITH_KW_(fn, 0)
+#define CV_PY_FN_NOARGS(fn) CV_PY_FN_NOARGS_(fn, 0)
+
+#define CV_PY_TO_CLASS(TYPE)                                                                          \
+template<>                                                                                            \
+bool pyopencv_to(PyObject* dst, TYPE& src, const char* name)                                          \
+{                                                                                                     \
+    if (!dst || dst == Py_None)                                                                       \
+        return true;                                                                                  \
+    Ptr<TYPE> ptr;                                                                                    \
+                                                                                                      \
+    if (!pyopencv_to(dst, ptr, name)) return false;                                                   \
+    src = *ptr;                                                                                       \
+    return true;                                                                                      \
+}
+
+#define CV_PY_FROM_CLASS(TYPE)                                                                        \
+template<>                                                                                            \
+PyObject* pyopencv_from(const TYPE& src)                                                              \
+{                                                                                                     \
+    Ptr<TYPE> ptr(new TYPE());                                                                        \
+                                                                                                      \
+    *ptr = src;                                                                                       \
+    return pyopencv_from(ptr);                                                                        \
+}
+
+#define CV_PY_TO_CLASS_PTR(TYPE)                                                                      \
+template<>                                                                                            \
+bool pyopencv_to(PyObject* dst, TYPE*& src, const char* name)                                         \
+{                                                                                                     \
+    if (!dst || dst == Py_None)                                                                       \
+        return true;                                                                                  \
+    Ptr<TYPE> ptr;                                                                                    \
+                                                                                                      \
+    if (!pyopencv_to(dst, ptr, name)) return false;                                                   \
+    src = ptr;                                                                                        \
+    return true;                                                                                      \
+}
+
+#define CV_PY_FROM_CLASS_PTR(TYPE)                                                                    \
+static PyObject* pyopencv_from(TYPE*& src)                                                            \
+{                                                                                                     \
+    return pyopencv_from(Ptr<TYPE>(src));                                                             \
+}
+
+#define CV_PY_TO_ENUM(TYPE)                                                                           \
+template<>                                                                                            \
+bool pyopencv_to(PyObject* dst, TYPE& src, const char* name)                                          \
+{                                                                                                     \
+    if (!dst || dst == Py_None)                                                                       \
+        return true;                                                                                  \
+    int underlying = 0;                                                  \
+                                                                                                      \
+    if (!pyopencv_to(dst, underlying, name)) return false;                                            \
+    src = static_cast<TYPE>(underlying);                                                              \
+    return true;                                                                                      \
+}
+
+#define CV_PY_FROM_ENUM(TYPE)                                                                         \
+template<>                                                                                            \
+PyObject* pyopencv_from(const TYPE& src)                                                              \
+{                                                                                                     \
+    return pyopencv_from(static_cast<int>(src));                         \
+}
+
+//==================================================================================================
+
+#if PY_MAJOR_VERSION >= 3
+#define CVPY_TYPE_HEAD PyVarObject_HEAD_INIT(&PyType_Type, 0)
+#define CVPY_TYPE_INCREF(T) Py_INCREF(T)
+#else
+#define CVPY_TYPE_HEAD PyObject_HEAD_INIT(&PyType_Type) 0,
+#define CVPY_TYPE_INCREF(T) _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA (T)->ob_refcnt++
 #endif
 
+
+#define CVPY_TYPE_DECLARE(NAME, STORAGE, SNAME) \
+    struct pyopencv_##NAME##_t \
+    { \
+        PyObject_HEAD \
+        STORAGE v; \
+    }; \
+    static PyTypeObject pyopencv_##NAME##_TypeXXX = \
+    { \
+        CVPY_TYPE_HEAD \
+        MODULESTR"."#NAME, \
+        sizeof(pyopencv_##NAME##_t), \
+    }; \
+    static PyTypeObject * pyopencv_##NAME##_TypePtr = &pyopencv_##NAME##_TypeXXX; \
+    static bool pyopencv_##NAME##_getp(PyObject * self, STORAGE * & dst) \
+    { \
+        if (PyObject_TypeCheck(self, pyopencv_##NAME##_TypePtr)) \
+        { \
+            dst = &(((pyopencv_##NAME##_t*)self)->v); \
+            return true; \
+        } \
+        return false; \
+    } \
+    static PyObject * pyopencv_##NAME##_Instance(const STORAGE &r) \
+    { \
+        pyopencv_##NAME##_t *m = PyObject_NEW(pyopencv_##NAME##_t, pyopencv_##NAME##_TypePtr); \
+        new (&(m->v)) STORAGE(r); \
+        return (PyObject*)m; \
+    } \
+    static void pyopencv_##NAME##_dealloc(PyObject* self) \
+    { \
+        ((pyopencv_##NAME##_t*)self)->v.STORAGE::~SNAME(); \
+        PyObject_Del(self); \
+    } \
+    static PyObject* pyopencv_##NAME##_repr(PyObject* self) \
+    { \
+        char str[1000]; \
+        sprintf(str, "<"#NAME" %p>", self); \
+        return PyString_FromString(str); \
+    }
+
+
+#define CVPY_TYPE_INIT_STATIC(NAME, ERROR_HANDLER, BASE, CONSTRUCTOR) \
+    { \
+        pyopencv_##NAME##_TypePtr->tp_base = pyopencv_##BASE##_TypePtr; \
+        pyopencv_##NAME##_TypePtr->tp_dealloc = pyopencv_##NAME##_dealloc; \
+        pyopencv_##NAME##_TypePtr->tp_repr = pyopencv_##NAME##_repr; \
+        pyopencv_##NAME##_TypePtr->tp_getset = pyopencv_##NAME##_getseters; \
+        pyopencv_##NAME##_TypePtr->tp_init = (initproc) CONSTRUCTOR; \
+        pyopencv_##NAME##_TypePtr->tp_methods = pyopencv_##NAME##_methods; \
+        pyopencv_##NAME##_TypePtr->tp_alloc = PyType_GenericAlloc; \
+        pyopencv_##NAME##_TypePtr->tp_new = PyType_GenericNew; \
+        pyopencv_##NAME##_TypePtr->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; \
+        if (PyType_Ready(pyopencv_##NAME##_TypePtr) != 0) \
+        { \
+            ERROR_HANDLER; \
+        } \
+        CVPY_TYPE_INCREF(pyopencv_##NAME##_TypePtr); \
+        PyModule_AddObject(m, #NAME, (PyObject *)pyopencv_##NAME##_TypePtr); \
+    }
+
+//==================================================================================================
+
+#define CVPY_TYPE_DECLARE_DYNAMIC(NAME, STORAGE, SNAME) \
+    struct pyopencv_##NAME##_t \
+    { \
+        PyObject_HEAD \
+        STORAGE v; \
+    }; \
+    static PyObject * pyopencv_##NAME##_TypePtr = 0; \
+    static bool pyopencv_##NAME##_getp(PyObject * self, STORAGE * & dst) \
+    { \
+        if (PyObject_TypeCheck(self, (PyTypeObject*)pyopencv_##NAME##_TypePtr)) \
+        { \
+            dst = &(((pyopencv_##NAME##_t*)self)->v); \
+            return true; \
+        } \
+        return false; \
+    } \
+    static PyObject * pyopencv_##NAME##_Instance(const STORAGE &r) \
+    { \
+        pyopencv_##NAME##_t *m = PyObject_New(pyopencv_##NAME##_t, (PyTypeObject*)pyopencv_##NAME##_TypePtr); \
+        new (&(m->v)) STORAGE(r); \
+        return (PyObject*)m; \
+    } \
+    static void pyopencv_##NAME##_dealloc(PyObject* self) \
+    { \
+        ((pyopencv_##NAME##_t*)self)->v.STORAGE::~SNAME(); \
+        PyObject_Del(self); \
+    } \
+    static PyObject* pyopencv_##NAME##_repr(PyObject* self) \
+    { \
+        char str[1000]; \
+        sprintf(str, "<"#NAME" %p>", self); \
+        return PyString_FromString(str); \
+    } \
+    static PyType_Slot pyopencv_##NAME##_Slots[] =  \
+    { \
+        {Py_tp_dealloc, 0}, \
+        {Py_tp_repr, 0}, \
+        {Py_tp_getset, 0}, \
+        {Py_tp_init, 0}, \
+        {Py_tp_methods, 0}, \
+        {Py_tp_alloc, 0}, \
+        {Py_tp_new, 0}, \
+        {0, 0} \
+    }; \
+    static PyType_Spec pyopencv_##NAME##_Spec = \
+    { \
+        MODULESTR"."#NAME, \
+        sizeof(pyopencv_##NAME##_t), \
+        0, \
+        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, \
+        pyopencv_##NAME##_Slots  \
+    };
+
+#define CVPY_TYPE_INIT_DYNAMIC(NAME, ERROR_HANDLER, BASE, CONSTRUCTOR) \
+    { \
+        pyopencv_##NAME##_Slots[0].pfunc /*tp_dealloc*/ = (void*)pyopencv_##NAME##_dealloc; \
+        pyopencv_##NAME##_Slots[1].pfunc /*tp_repr*/ = (void*)pyopencv_##NAME##_repr; \
+        pyopencv_##NAME##_Slots[2].pfunc /*tp_getset*/ = (void*)pyopencv_##NAME##_getseters; \
+        pyopencv_##NAME##_Slots[3].pfunc /*tp_init*/ = (void*) CONSTRUCTOR; \
+        pyopencv_##NAME##_Slots[4].pfunc /*tp_methods*/ = pyopencv_##NAME##_methods; \
+        pyopencv_##NAME##_Slots[5].pfunc /*tp_alloc*/ = (void*)PyType_GenericAlloc; \
+        pyopencv_##NAME##_Slots[6].pfunc /*tp_new*/ = (void*)PyType_GenericNew; \
+        PyObject * bases = 0; \
+        if (pyopencv_##BASE##_TypePtr) \
+            bases = PyTuple_Pack(1, pyopencv_##BASE##_TypePtr); \
+        pyopencv_##NAME##_TypePtr = PyType_FromSpecWithBases(&pyopencv_##NAME##_Spec, bases); \
+        if (!pyopencv_##NAME##_TypePtr) \
+        { \
+            printf("Failed to init: " #NAME ", base (" #BASE ")" "\n"); \
+            ERROR_HANDLER; \
+        } \
+        PyModule_AddObject(m, #NAME, (PyObject *)pyopencv_##NAME##_TypePtr); \
+    }
+
+// Debug module load:
+//
+// else \
+// { \
+//     printf("Init: " #NAME ", base (" #BASE ") -> %p" "\n", pyopencv_##NAME##_TypePtr); \
+// } \
+
+
 #endif // END HEADER GUARD