Commit 89c106b2 authored by Alexander Alekhin's avatar Alexander Alekhin

Merge pull request #13945 from alalek:backport_bindings_generator

parents 45c4d3a6 0a98bc0e
#ifdef HAVE_OPENCV_CORE
#include "opencv2/core/mat.hpp"
typedef std::vector<Range> vector_Range;
CV_PY_TO_CLASS(UMat);
CV_PY_FROM_CLASS(UMat);
static bool cv_mappable_to(const Ptr<Mat>& src, Ptr<UMat>& dst)
{
//dst.reset(new UMat(src->getUMat(ACCESS_RW)));
dst.reset(new UMat());
src->copyTo(*dst);
return true;
}
static void* cv_UMat_queue()
{
return cv::ocl::Queue::getDefault().ptr();
}
static void* cv_UMat_context()
{
return cv::ocl::Context::getDefault().ptr();
}
static Mat cv_UMat_get(const UMat* _self)
{
Mat m;
m.allocator = &g_numpyAllocator;
_self->copyTo(m);
return m;
}
#endif
#error This is a shadow header file, which is not intended for processing by any compiler. \
Only bindings parser should handle this file.
namespace cv
{
class CV_EXPORTS_W UMat
{
public:
//! default constructor
CV_WRAP UMat(UMatUsageFlags usageFlags = USAGE_DEFAULT);
//! constructs 2D matrix of the specified size and type
// (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.)
CV_WRAP UMat(int rows, int cols, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT);
CV_WRAP UMat(Size size, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT);
//! constucts 2D matrix and fills it with the specified value _s.
CV_WRAP UMat(int rows, int cols, int type, const Scalar& s, UMatUsageFlags usageFlags = USAGE_DEFAULT);
CV_WRAP UMat(Size size, int type, const Scalar& s, UMatUsageFlags usageFlags = USAGE_DEFAULT);
//! Mat is mappable to UMat
CV_WRAP_MAPPABLE(Ptr<Mat>);
//! returns the OpenCL queue used by OpenCV UMat
CV_WRAP_PHANTOM(static void* queue());
//! returns the OpenCL context used by OpenCV UMat
CV_WRAP_PHANTOM(static void* context());
//! copy constructor
CV_WRAP UMat(const UMat& m);
//! creates a matrix header for a part of the bigger matrix
CV_WRAP UMat(const UMat& m, const Range& rowRange, const Range& colRange = Range::all());
CV_WRAP UMat(const UMat& m, const Rect& roi);
CV_WRAP UMat(const UMat& m, const std::vector<Range>& ranges);
//CV_WRAP_AS(get) Mat getMat(int flags CV_WRAP_DEFAULT(ACCESS_RW)) const;
//! returns a numpy matrix
CV_WRAP_PHANTOM(Mat get() const);
//! returns true iff the matrix data is continuous
// (i.e. when there are no gaps between successive rows).
// similar to CV_IS_MAT_CONT(cvmat->type)
CV_WRAP bool isContinuous() const;
//! returns true if the matrix is a submatrix of another matrix
CV_WRAP bool isSubmatrix() const;
/*! Returns the OpenCL buffer handle on which UMat operates on.
The UMat instance should be kept alive during the use of the handle to prevent the buffer to be
returned to the OpenCV buffer pool.
*/
CV_WRAP void* handle(int/*AccessFlag*/ accessFlags) const;
// offset of the submatrix (or 0)
CV_PROP_RW size_t offset;
};
} // namespace cv
...@@ -140,17 +140,18 @@ class GeneralInfo(): ...@@ -140,17 +140,18 @@ class GeneralInfo():
def fullName(self, isCPP=False): def fullName(self, isCPP=False):
result = ".".join([self.fullClass(), self.name]) result = ".".join([self.fullClass(), self.name])
return result if not isCPP else result.replace(".", "::") return result if not isCPP else get_cname(result)
def fullClass(self, isCPP=False): def fullClass(self, isCPP=False):
result = ".".join([f for f in [self.namespace] + self.classpath.split(".") if len(f)>0]) result = ".".join([f for f in [self.namespace] + self.classpath.split(".") if len(f)>0])
return result if not isCPP else result.replace(".", "::") return result if not isCPP else get_cname(result)
class ConstInfo(GeneralInfo): class ConstInfo(GeneralInfo):
def __init__(self, decl, addedManually=False, namespaces=[]): def __init__(self, decl, addedManually=False, namespaces=[], enumType=None):
GeneralInfo.__init__(self, "const", decl, namespaces) GeneralInfo.__init__(self, "const", decl, namespaces)
self.cname = self.name.replace(".", "::") self.cname = get_cname(self.name)
self.value = decl[1] self.value = decl[1]
self.enumType = enumType
self.addedManually = addedManually self.addedManually = addedManually
if self.namespace in namespaces_dict: if self.namespace in namespaces_dict:
self.name = '%s_%s' % (namespaces_dict[self.namespace], self.name) self.name = '%s_%s' % (namespaces_dict[self.namespace], self.name)
...@@ -166,6 +167,25 @@ class ConstInfo(GeneralInfo): ...@@ -166,6 +167,25 @@ class ConstInfo(GeneralInfo):
return True return True
return False return False
def normalize_field_name(name):
return name.replace(".","_").replace("[","").replace("]","").replace("_getNativeObjAddr()","_nativeObj")
def normalize_class_name(name):
return re.sub(r"^cv\.", "", name).replace(".", "_")
def get_cname(name):
return name.replace(".", "::")
def cast_from(t):
if t in type_dict and "cast_from" in type_dict[t]:
return type_dict[t]["cast_from"]
return t
def cast_to(t):
if t in type_dict and "cast_to" in type_dict[t]:
return type_dict[t]["cast_to"]
return t
class ClassPropInfo(): class ClassPropInfo():
def __init__(self, decl): # [f_ctype, f_name, '', '/RW'] def __init__(self, decl): # [f_ctype, f_name, '', '/RW']
self.ctype = decl[0] self.ctype = decl[0]
...@@ -178,7 +198,7 @@ class ClassPropInfo(): ...@@ -178,7 +198,7 @@ class ClassPropInfo():
class ClassInfo(GeneralInfo): class ClassInfo(GeneralInfo):
def __init__(self, decl, namespaces=[]): # [ 'class/struct cname', ': base', [modlist] ] def __init__(self, decl, namespaces=[]): # [ 'class/struct cname', ': base', [modlist] ]
GeneralInfo.__init__(self, "class", decl, namespaces) GeneralInfo.__init__(self, "class", decl, namespaces)
self.cname = self.name.replace(".", "::") self.cname = get_cname(self.name)
self.methods = [] self.methods = []
self.methods_suffixes = {} self.methods_suffixes = {}
self.consts = [] # using a list to save the occurrence order self.consts = [] # using a list to save the occurrence order
...@@ -303,7 +323,7 @@ class ArgInfo(): ...@@ -303,7 +323,7 @@ class ArgInfo():
class FuncInfo(GeneralInfo): class FuncInfo(GeneralInfo):
def __init__(self, decl, namespaces=[]): # [ funcname, return_ctype, [modifiers], [args] ] def __init__(self, decl, namespaces=[]): # [ funcname, return_ctype, [modifiers], [args] ]
GeneralInfo.__init__(self, "func", decl, namespaces) GeneralInfo.__init__(self, "func", decl, namespaces)
self.cname = decl[0].replace(".", "::") self.cname = get_cname(decl[0])
self.jname = self.name self.jname = self.name
self.isconstructor = self.name == self.classname self.isconstructor = self.name == self.classname
if "[" in self.name: if "[" in self.name:
...@@ -403,13 +423,16 @@ class JavaWrapperGenerator(object): ...@@ -403,13 +423,16 @@ class JavaWrapperGenerator(object):
) )
logging.info('ok: class %s, name: %s, base: %s', classinfo, name, classinfo.base) logging.info('ok: class %s, name: %s, base: %s', classinfo, name, classinfo.base)
def add_const(self, decl): # [ "const cname", val, [], [] ] def add_const(self, decl, enumType=None): # [ "const cname", val, [], [] ]
constinfo = ConstInfo(decl, namespaces=self.namespaces) constinfo = ConstInfo(decl, namespaces=self.namespaces, enumType=enumType)
if constinfo.isIgnored(): if constinfo.isIgnored():
logging.info('ignored: %s', constinfo) logging.info('ignored: %s', constinfo)
elif not self.isWrapped(constinfo.classname):
logging.info('class not found: %s', constinfo)
else: else:
if not self.isWrapped(constinfo.classname):
logging.info('class not found: %s', constinfo)
constinfo.name = constinfo.classname + '_' + constinfo.name
constinfo.classname = ''
ci = self.getClass(constinfo.classname) ci = self.getClass(constinfo.classname)
duplicate = ci.getConst(constinfo.name) duplicate = ci.getConst(constinfo.name)
if duplicate: if duplicate:
...@@ -421,6 +444,18 @@ class JavaWrapperGenerator(object): ...@@ -421,6 +444,18 @@ class JavaWrapperGenerator(object):
ci.addConst(constinfo) ci.addConst(constinfo)
logging.info('ok: %s', constinfo) logging.info('ok: %s', constinfo)
def add_enum(self, decl): # [ "enum cname", "", [], [] ]
enumType = decl[0].rsplit(" ", 1)[1]
if enumType.endswith("<unnamed>"):
enumType = None
else:
ctype = normalize_class_name(enumType)
type_dict[ctype] = { "cast_from" : "int", "cast_to" : get_cname(enumType), "j_type" : "int", "jn_type" : "int", "jni_type" : "jint", "suffix" : "I" }
const_decls = decl[3]
for decl in const_decls:
self.add_const(decl, enumType)
def add_func(self, decl): def add_func(self, decl):
fi = FuncInfo(decl, namespaces=self.namespaces) fi = FuncInfo(decl, namespaces=self.namespaces)
classname = fi.classname or self.Module classname = fi.classname or self.Module
...@@ -479,6 +514,9 @@ class JavaWrapperGenerator(object): ...@@ -479,6 +514,9 @@ class JavaWrapperGenerator(object):
self.add_class(decl) self.add_class(decl)
elif name.startswith("const"): elif name.startswith("const"):
self.add_const(decl) self.add_const(decl)
elif name.startswith("enum"):
# enum
self.add_enum(decl)
else: # function else: # function
self.add_func(decl) self.add_func(decl)
...@@ -518,7 +556,7 @@ class JavaWrapperGenerator(object): ...@@ -518,7 +556,7 @@ class JavaWrapperGenerator(object):
if self.isWrapped(t): if self.isWrapped(t):
return self.getClass(t).fullName(isCPP=True) return self.getClass(t).fullName(isCPP=True)
else: else:
return t return cast_from(t)
def gen_func(self, ci, fi, prop_name=''): def gen_func(self, ci, fi, prop_name=''):
logging.info("%s", fi) logging.info("%s", fi)
...@@ -551,7 +589,7 @@ class JavaWrapperGenerator(object): ...@@ -551,7 +589,7 @@ class JavaWrapperGenerator(object):
msg = "// Return type '%s' is not supported, skipping the function\n\n" % fi.ctype msg = "// Return type '%s' is not supported, skipping the function\n\n" % fi.ctype
self.skipped_func_list.append(c_decl + "\n" + msg) self.skipped_func_list.append(c_decl + "\n" + msg)
j_code.write( " "*4 + msg ) j_code.write( " "*4 + msg )
logging.warning("SKIP:" + c_decl.strip() + "\t due to RET type" + fi.ctype) logging.warning("SKIP:" + c_decl.strip() + "\t due to RET type " + fi.ctype)
return return
for a in fi.args: for a in fi.args:
if a.ctype not in type_dict: if a.ctype not in type_dict:
...@@ -563,7 +601,7 @@ class JavaWrapperGenerator(object): ...@@ -563,7 +601,7 @@ class JavaWrapperGenerator(object):
msg = "// Unknown type '%s' (%s), skipping the function\n\n" % (a.ctype, a.out or "I") msg = "// Unknown type '%s' (%s), skipping the function\n\n" % (a.ctype, a.out or "I")
self.skipped_func_list.append(c_decl + "\n" + msg) self.skipped_func_list.append(c_decl + "\n" + msg)
j_code.write( " "*4 + msg ) j_code.write( " "*4 + msg )
logging.warning("SKIP:" + c_decl.strip() + "\t due to ARG type" + a.ctype + "/" + (a.out or "I")) logging.warning("SKIP:" + c_decl.strip() + "\t due to ARG type " + a.ctype + "/" + (a.out or "I"))
return return
self.ported_func_list.append(c_decl) self.ported_func_list.append(c_decl)
...@@ -642,7 +680,7 @@ class JavaWrapperGenerator(object): ...@@ -642,7 +680,7 @@ class JavaWrapperGenerator(object):
if "I" in a.out or not a.out or self.isWrapped(a.ctype): # input arg, pass by primitive fields if "I" in a.out or not a.out or self.isWrapped(a.ctype): # input arg, pass by primitive fields
for f in fields: for f in fields:
jn_args.append ( ArgInfo([ f[0], a.name + f[1], "", [], "" ]) ) jn_args.append ( ArgInfo([ f[0], a.name + f[1], "", [], "" ]) )
jni_args.append( ArgInfo([ f[0], a.name + f[1].replace(".","_").replace("[","").replace("]","").replace("_getNativeObjAddr()","_nativeObj"), "", [], "" ]) ) jni_args.append( ArgInfo([ f[0], a.name + normalize_field_name(f[1]), "", [], "" ]) )
if "O" in a.out and not self.isWrapped(a.ctype): # out arg, pass as double[] if "O" in a.out and not self.isWrapped(a.ctype): # out arg, pass as double[]
jn_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) ) jn_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) )
jni_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) ) jni_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) )
...@@ -690,7 +728,7 @@ class JavaWrapperGenerator(object): ...@@ -690,7 +728,7 @@ class JavaWrapperGenerator(object):
" private static native $type $name($args);\n").substitute(\ " private static native $type $name($args);\n").substitute(\
type = type_dict[fi.ctype].get("jn_type", "double[]"), \ type = type_dict[fi.ctype].get("jn_type", "double[]"), \
name = fi.jname + '_' + str(suffix_counter), \ name = fi.jname + '_' + str(suffix_counter), \
args = ", ".join(["%s %s" % (type_dict[a.ctype]["jn_type"], a.name.replace(".","_").replace("[","").replace("]","").replace("_getNativeObjAddr()","_nativeObj")) for a in jn_args]) args = ", ".join(["%s %s" % (type_dict[a.ctype]["jn_type"], normalize_field_name(a.name)) for a in jn_args])
) ); ) );
# java part: # java part:
...@@ -848,7 +886,7 @@ class JavaWrapperGenerator(object): ...@@ -848,7 +886,7 @@ class JavaWrapperGenerator(object):
if not a.out and not "jni_var" in type_dict[a.ctype]: if not a.out and not "jni_var" in type_dict[a.ctype]:
# explicit cast to C type to avoid ambiguous call error on platforms (mingw) # explicit cast to C type to avoid ambiguous call error on platforms (mingw)
# where jni types are different from native types (e.g. jint is not the same as int) # where jni types are different from native types (e.g. jint is not the same as int)
jni_name = "(%s)%s" % (a.ctype, jni_name) jni_name = "(%s)%s" % (cast_to(a.ctype), jni_name)
if not a.ctype: # hidden if not a.ctype: # hidden
jni_name = a.defval jni_name = a.defval
cvargs.append( type_dict[a.ctype].get("jni_name", jni_name) % {"n" : a.name}) cvargs.append( type_dict[a.ctype].get("jni_name", jni_name) % {"n" : a.name})
...@@ -915,18 +953,50 @@ JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname ...@@ -915,18 +953,50 @@ JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname
def gen_class(self, ci): def gen_class(self, ci):
logging.info("%s", ci) logging.info("%s", ci)
# constants # constants
consts_map = {c.name: c for c in ci.private_consts}
consts_map.update({c.name: c for c in ci.consts})
def const_value(v):
if v in consts_map:
target = consts_map[v]
assert target.value != v
return const_value(target.value)
return v
if ci.private_consts: if ci.private_consts:
logging.info("%s", ci.private_consts) logging.info("%s", ci.private_consts)
ci.j_code.write(""" ci.j_code.write("""
private static final int private static final int
%s;\n\n""" % (",\n"+" "*12).join(["%s = %s" % (c.name, c.value) for c in ci.private_consts]) %s;\n\n""" % (",\n"+" "*12).join(["%s = %s" % (c.name, const_value(c.value)) for c in ci.private_consts])
) )
if ci.consts: if ci.consts:
logging.info("%s", ci.consts) enumTypes = set(map(lambda c: c.enumType, ci.consts))
ci.j_code.write(""" grouped_consts = {enumType: [c for c in ci.consts if c.enumType == enumType] for enumType in enumTypes}
for typeName, consts in grouped_consts.items():
logging.info("%s", consts)
if typeName:
typeName = typeName.rsplit(".", 1)[-1]
###################### Utilize Java enums ######################
# ci.j_code.write("""
# public enum {1} {{
# {0};
#
# private final int id;
# {1}(int id) {{ this.id = id; }}
# {1}({1} _this) {{ this.id = _this.id; }}
# public int getValue() {{ return id; }}
# }}\n\n""".format((",\n"+" "*8).join(["%s(%s)" % (c.name, const_value(c.value)) for c in consts]), typeName)
# )
################################################################
ci.j_code.write("""
// C++: enum {1}
public static final int public static final int
%s;\n\n""" % (",\n"+" "*12).join(["%s = %s" % (c.name, c.value) for c in ci.consts]) {0};\n\n""".format((",\n"+" "*12).join(["%s = %s" % (c.name, const_value(c.value)) for c in consts]), typeName)
) )
else:
ci.j_code.write("""
// C++: enum <unnamed>
public static final int
{0};\n\n""".format((",\n"+" "*12).join(["%s = %s" % (c.name, const_value(c.value)) for c in consts]))
)
# methods # methods
for fi in ci.getAllMethods(): for fi in ci.getAllMethods():
self.gen_func(ci, fi) self.gen_func(ci, fi)
...@@ -1123,7 +1193,7 @@ if __name__ == "__main__": ...@@ -1123,7 +1193,7 @@ if __name__ == "__main__":
with open(srcfiles_fname) as f: with open(srcfiles_fname) as f:
srcfiles = [os.path.join(module_location, str(l).strip()) for l in f.readlines() if str(l).strip()] srcfiles = [os.path.join(module_location, str(l).strip()) for l in f.readlines() if str(l).strip()]
else: else:
re_bad = re.compile(r'(private|.inl.hpp$|_inl.hpp$|.details.hpp$|_winrt.hpp$|/cuda/)') re_bad = re.compile(r'(private|.inl.hpp$|_inl.hpp$|.details.hpp$|_winrt.hpp$|/cuda/|/legacy/)')
# .h files before .hpp # .h files before .hpp
h_files = [] h_files = []
hpp_files = [] hpp_files = []
......
...@@ -26,15 +26,15 @@ foreach(m ${OPENCV_PYTHON_MODULES}) ...@@ -26,15 +26,15 @@ foreach(m ${OPENCV_PYTHON_MODULES})
list(APPEND opencv_hdrs "${hdr}") list(APPEND opencv_hdrs "${hdr}")
endif() endif()
endforeach() endforeach()
file(GLOB hdr ${OPENCV_MODULE_${m}_LOCATION}/misc/python/shadow*.hpp)
list(APPEND opencv_hdrs ${hdr})
file(GLOB userdef_hdrs ${OPENCV_MODULE_${m}_LOCATION}/misc/python/pyopencv*.hpp) file(GLOB userdef_hdrs ${OPENCV_MODULE_${m}_LOCATION}/misc/python/pyopencv*.hpp)
list(APPEND opencv_userdef_hdrs ${userdef_hdrs}) list(APPEND opencv_userdef_hdrs ${userdef_hdrs})
endforeach(m) endforeach(m)
# header blacklist # header blacklist
ocv_list_filterout(opencv_hdrs "modules/.*\\\\.h$") ocv_list_filterout(opencv_hdrs "modules/.*\\\\.h$")
ocv_list_filterout(opencv_hdrs "modules/core/.*/cuda") ocv_list_filterout(opencv_hdrs "modules/core/.*/cuda/")
ocv_list_filterout(opencv_hdrs "modules/cuda.*")
ocv_list_filterout(opencv_hdrs "modules/cudev")
ocv_list_filterout(opencv_hdrs "modules/core/.*/hal/") ocv_list_filterout(opencv_hdrs "modules/core/.*/hal/")
ocv_list_filterout(opencv_hdrs "modules/core/.*/opencl/") ocv_list_filterout(opencv_hdrs "modules/core/.*/opencl/")
ocv_list_filterout(opencv_hdrs "modules/.+/utils/.*") ocv_list_filterout(opencv_hdrs "modules/.+/utils/.*")
...@@ -43,7 +43,12 @@ ocv_list_filterout(opencv_hdrs "modules/.*_inl\\\\.h*") ...@@ -43,7 +43,12 @@ ocv_list_filterout(opencv_hdrs "modules/.*_inl\\\\.h*")
ocv_list_filterout(opencv_hdrs "modules/.*\\\\.details\\\\.h*") ocv_list_filterout(opencv_hdrs "modules/.*\\\\.details\\\\.h*")
ocv_list_filterout(opencv_hdrs "modules/.*\\\\.private\\\\.h*") ocv_list_filterout(opencv_hdrs "modules/.*\\\\.private\\\\.h*")
ocv_list_filterout(opencv_hdrs "modules/.*/private\\\\.h*") ocv_list_filterout(opencv_hdrs "modules/.*/private\\\\.h*")
ocv_list_filterout(opencv_hdrs "modules/.*/legacy/.*")
ocv_list_filterout(opencv_hdrs "modules/.*/detection_based_tracker\\\\.hpp") # Conditional compilation ocv_list_filterout(opencv_hdrs "modules/.*/detection_based_tracker\\\\.hpp") # Conditional compilation
if(NOT HAVE_CUDA)
ocv_list_filterout(opencv_hdrs "modules/cuda.*")
ocv_list_filterout(opencv_hdrs "modules/cudev")
endif()
set(cv2_generated_files set(cv2_generated_files
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_include.h" "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_include.h"
......
...@@ -11,6 +11,20 @@ ...@@ -11,6 +11,20 @@
#pragma warning(pop) #pragma warning(pop)
#endif #endif
template<typename T, class TEnable = void> // TEnable is used for SFINAE checks
struct PyOpenCV_Converter
{
//static inline bool to(PyObject* obj, T& p, const char* name);
//static inline PyObject* from(const T& src);
};
template<typename T> static
bool pyopencv_to(PyObject* obj, T& p, const char* name = "<unknown>") { return PyOpenCV_Converter<T>::to(obj, p, name); }
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_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_NOARGS_(fn, flags) (PyCFunction)(fn), (flags) | METH_NOARGS
...@@ -28,6 +42,68 @@ ...@@ -28,6 +42,68 @@
# define CV_PYTHON_TYPE_HEAD_INIT() PyObject_HEAD_INIT(&PyType_Type) 0, # define CV_PYTHON_TYPE_HEAD_INIT() PyObject_HEAD_INIT(&PyType_Type) 0,
#endif #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 "pyopencv_generated_include.h"
#include "opencv2/core/types_c.h" #include "opencv2/core/types_c.h"
...@@ -37,7 +113,7 @@ ...@@ -37,7 +113,7 @@
#include <map> #include <map>
static PyObject* opencv_error = 0; static PyObject* opencv_error = NULL;
static int failmsg(const char *fmt, ...) static int failmsg(const char *fmt, ...)
{ {
...@@ -98,6 +174,12 @@ try \ ...@@ -98,6 +174,12 @@ try \
} \ } \
catch (const cv::Exception &e) \ catch (const cv::Exception &e) \
{ \ { \
PyObject_SetAttrString(opencv_error, "file", PyString_FromString(e.file.c_str())); \
PyObject_SetAttrString(opencv_error, "func", PyString_FromString(e.func.c_str())); \
PyObject_SetAttrString(opencv_error, "line", PyInt_FromLong(e.line)); \
PyObject_SetAttrString(opencv_error, "code", PyInt_FromLong(e.code)); \
PyObject_SetAttrString(opencv_error, "msg", PyString_FromString(e.msg.c_str())); \
PyObject_SetAttrString(opencv_error, "err", PyString_FromString(e.err.c_str())); \
PyErr_SetString(opencv_error, e.what()); \ PyErr_SetString(opencv_error, e.what()); \
return 0; \ return 0; \
} }
...@@ -113,6 +195,7 @@ typedef std::vector<size_t> vector_size_t; ...@@ -113,6 +195,7 @@ typedef std::vector<size_t> vector_size_t;
typedef std::vector<Point> vector_Point; typedef std::vector<Point> vector_Point;
typedef std::vector<Point2f> vector_Point2f; typedef std::vector<Point2f> vector_Point2f;
typedef std::vector<Point3f> vector_Point3f; typedef std::vector<Point3f> vector_Point3f;
typedef std::vector<Size> vector_Size;
typedef std::vector<Vec2f> vector_Vec2f; typedef std::vector<Vec2f> vector_Vec2f;
typedef std::vector<Vec3f> vector_Vec3f; typedef std::vector<Vec3f> vector_Vec3f;
typedef std::vector<Vec4f> vector_Vec4f; typedef std::vector<Vec4f> vector_Vec4f;
...@@ -223,12 +306,6 @@ public: ...@@ -223,12 +306,6 @@ public:
NumpyAllocator g_numpyAllocator; NumpyAllocator g_numpyAllocator;
template<typename T> static
bool pyopencv_to(PyObject* obj, T& p, const char* name = "<unknown>");
template<typename T> static
PyObject* pyopencv_from(const T& src);
enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 }; enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 };
// special case, when the converter needs full ArgInfo structure // special case, when the converter needs full ArgInfo structure
...@@ -435,15 +512,6 @@ bool pyopencv_to(PyObject* o, Matx<_Tp, m, n>& mx, const char* name) ...@@ -435,15 +512,6 @@ bool pyopencv_to(PyObject* o, Matx<_Tp, m, n>& mx, const char* name)
return pyopencv_to(o, mx, ArgInfo(name, 0)); return pyopencv_to(o, mx, ArgInfo(name, 0));
} }
template <typename T>
bool pyopencv_to(PyObject *o, Ptr<T>& p, const char *name)
{
if (!o || o == Py_None)
return true;
p = makePtr<T>();
return pyopencv_to(o, *p, name);
}
template<> template<>
PyObject* pyopencv_from(const Mat& m) PyObject* pyopencv_from(const Mat& m)
{ {
...@@ -468,279 +536,39 @@ PyObject* pyopencv_from(const Matx<_Tp, m, n>& matx) ...@@ -468,279 +536,39 @@ PyObject* pyopencv_from(const Matx<_Tp, m, n>& matx)
} }
template<typename T> template<typename T>
PyObject* pyopencv_from(const cv::Ptr<T>& p) struct PyOpenCV_Converter< cv::Ptr<T> >
{
if (!p)
Py_RETURN_NONE;
return pyopencv_from(*p);
}
typedef struct {
PyObject_HEAD
UMat* um;
} cv2_UMatWrapperObject;
static bool PyObject_IsUMat(PyObject *o);
// UMatWrapper init - try to map arguments from python to UMat constructors
static int UMatWrapper_init(PyObject* self_, PyObject *args, PyObject *kwds)
{ {
cv2_UMatWrapperObject* self = (cv2_UMatWrapperObject*)self_; static PyObject* from(const cv::Ptr<T>& p)
if (self == NULL)
{
PyErr_SetString(PyExc_TypeError, "Internal error");
return -1;
}
self->um = NULL;
{
// constructor ()
const char *kwlist[] = {NULL};
if (PyArg_ParseTupleAndKeywords(args, kwds, "", (char**) kwlist)) {
self->um = new UMat();
return 0;
}
PyErr_Clear();
}
{
// constructor (rows, cols, type)
const char *kwlist[] = {"rows", "cols", "type", NULL};
int rows, cols, type;
if (PyArg_ParseTupleAndKeywords(args, kwds, "iii", (char**) kwlist, &rows, &cols, &type)) {
self->um = new UMat(rows, cols, type);
return 0;
}
PyErr_Clear();
}
{ {
// constructor (m, rowRange, colRange) if (!p)
const char *kwlist[] = {"m", "rowRange", "colRange", NULL}; Py_RETURN_NONE;
PyObject *obj = NULL; return pyopencv_from(*p);
int y0 = -1, y1 = -1, x0 = -1, x1 = -1;
if (PyArg_ParseTupleAndKeywords(args, kwds, "O(ii)|(ii)", (char**) kwlist, &obj, &y0, &y1, &x0, &x1) && PyObject_IsUMat(obj)) {
UMat *um_other = ((cv2_UMatWrapperObject *) obj)->um;
Range rowRange(y0, y1);
Range colRange = (x0 >= 0 && x1 >= 0) ? Range(x0, x1) : Range::all();
self->um = new UMat(*um_other, rowRange, colRange);
return 0;
}
PyErr_Clear();
} }
static bool to(PyObject *o, Ptr<T>& p, const char *name)
{ {
// constructor (m) if (!o || o == Py_None)
const char *kwlist[] = {"m", NULL}; return true;
PyObject *obj = NULL; p = makePtr<T>();
if (PyArg_ParseTupleAndKeywords(args, kwds, "O", (char**) kwlist, &obj)) { return pyopencv_to(o, *p, name);
// constructor (UMat m)
if (PyObject_IsUMat(obj)) {
UMat *um_other = ((cv2_UMatWrapperObject *) obj)->um;
self->um = new UMat(*um_other);
return 0;
}
// python specific constructor from array like object
Mat m;
if (pyopencv_to(obj, m, ArgInfo("UMatWrapper.np_mat", 0))) {
self->um = new UMat();
m.copyTo(*self->um);
return 0;
}
}
PyErr_Clear();
} }
PyErr_SetString(PyExc_TypeError, "no matching UMat constructor found/supported");
return -1;
}
static void UMatWrapper_dealloc(cv2_UMatWrapperObject* self)
{
if (self->um)
delete self->um;
#if PY_MAJOR_VERSION >= 3
Py_TYPE(self)->tp_free((PyObject*)self);
#else
self->ob_type->tp_free((PyObject*)self);
#endif
}
// UMatWrapper.get() - returns numpy array by transferring UMat data to Mat and than wrapping it to numpy array
// (using numpy allocator - and so without unnecessary copy)
static PyObject * UMatWrapper_get(PyObject* self_, PyObject * /*args*/)
{
cv2_UMatWrapperObject* self = (cv2_UMatWrapperObject*)self_;
if (self == NULL)
return failmsgp("Incorrect type of self (must be 'cv2_UMatWrapperObject')");
Mat m;
m.allocator = &g_numpyAllocator;
self->um->copyTo(m);
return pyopencv_from(m);
}
// UMatWrapper.handle() - returns the OpenCL handle of the UMat object
static PyObject * UMatWrapper_handle(PyObject* self_, PyObject *args, PyObject *kwds)
{
cv2_UMatWrapperObject* self = (cv2_UMatWrapperObject*)self_;
if (self == NULL)
return failmsgp("Incorrect type of self (must be 'cv2_UMatWrapperObject')");
const char *kwlist[] = {"accessFlags", NULL};
int accessFlags;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", (char**) kwlist, &accessFlags))
return 0;
return PyLong_FromVoidPtr(self->um->handle(accessFlags));
}
// UMatWrapper.isContinuous() - returns true if the matrix data is continuous
static PyObject * UMatWrapper_isContinuous(PyObject* self_, PyObject * /*args*/)
{
cv2_UMatWrapperObject* self = (cv2_UMatWrapperObject*)self_;
if (self == NULL)
return failmsgp("Incorrect type of self (must be 'cv2_UMatWrapperObject')");
return PyBool_FromLong(self->um->isContinuous());
}
// UMatWrapper.isContinuous() - returns true if the matrix is a submatrix of another matrix
static PyObject * UMatWrapper_isSubmatrix(PyObject* self_, PyObject * /*args*/)
{
cv2_UMatWrapperObject* self = (cv2_UMatWrapperObject*)self_;
if (self == NULL)
return failmsgp("Incorrect type of self (must be 'cv2_UMatWrapperObject')");
return PyBool_FromLong(self->um->isSubmatrix());
}
// UMatWrapper.context() - returns the OpenCL context used by OpenCV UMat
static PyObject * UMatWrapper_context(PyObject* /*self_*/, PyObject * /*args*/)
{
return PyLong_FromVoidPtr(cv::ocl::Context::getDefault().ptr());
}
// UMatWrapper.context() - returns the OpenCL queue used by OpenCV UMat
static PyObject * UMatWrapper_queue(PyObject* /*self_*/, PyObject * /*args*/)
{
return PyLong_FromVoidPtr(cv::ocl::Queue::getDefault().ptr());
}
static PyObject * UMatWrapper_offset_getter(PyObject* self_, void*)
{
cv2_UMatWrapperObject* self = (cv2_UMatWrapperObject*)self_;
if (self == NULL)
return failmsgp("Incorrect type of self (must be 'cv2_UMatWrapperObject')");
return PyLong_FromSsize_t(self->um->offset);
}
static PyMethodDef UMatWrapper_methods[] = {
{"get", CV_PY_FN_NOARGS(UMatWrapper_get),
"Returns numpy array"
},
{"handle", CV_PY_FN_WITH_KW(UMatWrapper_handle),
"Returns UMat native handle"
},
{"isContinuous", CV_PY_FN_NOARGS(UMatWrapper_isContinuous),
"Returns true if the matrix data is continuous"
},
{"isSubmatrix", CV_PY_FN_NOARGS(UMatWrapper_isSubmatrix),
"Returns true if the matrix is a submatrix of another matrix"
},
{"context", CV_PY_FN_NOARGS_(UMatWrapper_context, METH_STATIC),
"Returns OpenCL context handle"
},
{"queue", CV_PY_FN_NOARGS_(UMatWrapper_queue, METH_STATIC),
"Returns OpenCL queue handle"
},
{NULL, NULL, 0, NULL} /* Sentinel */
};
static PyGetSetDef UMatWrapper_getset[] = {
{(char*) "offset", (getter) UMatWrapper_offset_getter, NULL, NULL, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
}; };
static PyTypeObject cv2_UMatWrapperType = { template<>
#if PY_MAJOR_VERSION >= 3 bool pyopencv_to(PyObject* obj, void*& ptr, const char* name)
PyVarObject_HEAD_INIT(NULL, 0) {
#else CV_UNUSED(name);
PyObject_HEAD_INIT(NULL) if (!obj || obj == Py_None)
0, /*ob_size*/
#endif
"cv2.UMat", /* tp_name */
sizeof(cv2_UMatWrapperObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)UMatWrapper_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"OpenCV 3 UMat wrapper. Used for T-API support.", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
UMatWrapper_methods, /* tp_methods */
0, /* tp_members */
UMatWrapper_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)UMatWrapper_init, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
0, /* tp_free */
0, /* tp_is_gc */
0, /* tp_bases */
0, /* tp_mro */
0, /* tp_cache */
0, /* tp_subclasses */
0, /* tp_weaklist */
0, /* tp_del */
0, /* tp_version_tag */
#if PY_MAJOR_VERSION >= 3
0, /* tp_finalize */
#endif
};
static bool PyObject_IsUMat(PyObject *o) {
return (o != NULL) && PyObject_TypeCheck(o, &cv2_UMatWrapperType);
}
static bool pyopencv_to(PyObject* o, UMat& um, const ArgInfo info) {
if (PyObject_IsUMat(o)) {
um = *((cv2_UMatWrapperObject *) o)->um;
return true; return true;
}
Mat m; if (!PyLong_Check(obj))
if (!pyopencv_to(o, m, info)) {
return false; return false;
} ptr = PyLong_AsVoidPtr(obj);
return ptr != NULL && !PyErr_Occurred();
m.copyTo(um);
return true;
} }
template<> static PyObject* pyopencv_from(void*& ptr)
bool pyopencv_to(PyObject* o, UMat& um, const char* name)
{ {
return pyopencv_to(o, um, ArgInfo(name, 0)); return PyLong_FromVoidPtr(ptr);
}
template<>
PyObject* pyopencv_from(const UMat& m) {
PyObject *o = PyObject_CallObject((PyObject *) &cv2_UMatWrapperType, NULL);
*((cv2_UMatWrapperObject *) o)->um = m;
return o;
} }
static bool pyopencv_to(PyObject *o, Scalar& s, const ArgInfo info) static bool pyopencv_to(PyObject *o, Scalar& s, const ArgInfo info)
...@@ -991,6 +819,40 @@ bool pyopencv_to(PyObject* obj, Range& r, const char* name) ...@@ -991,6 +819,40 @@ bool pyopencv_to(PyObject* obj, Range& r, const char* name)
CV_UNUSED(name); CV_UNUSED(name);
if(!obj || obj == Py_None) if(!obj || obj == Py_None)
return true; return true;
while (PySequence_Check(obj))
{
PyObject *fi = PySequence_Fast(obj, name);
if (fi == NULL)
break;
if (2 != PySequence_Fast_GET_SIZE(fi))
{
failmsg("Range value for argument '%s' is longer than 2", name);
Py_DECREF(fi);
return false;
}
{
PyObject *item = PySequence_Fast_GET_ITEM(fi, 0);
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);
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) if(PyObject_Size(obj) == 0)
{ {
r = Range::all(); r = Range::all();
...@@ -1483,6 +1345,19 @@ template<> struct pyopencvVecConverter<Mat> ...@@ -1483,6 +1345,19 @@ template<> struct pyopencvVecConverter<Mat>
} }
}; };
template<> struct pyopencvVecConverter<UMat>
{
static bool to(PyObject* obj, std::vector<UMat>& value, const ArgInfo info)
{
return pyopencv_to_generic_vec(obj, value, info);
}
static PyObject* from(const std::vector<UMat>& value)
{
return pyopencv_from_generic_vec(value);
}
};
template<> struct pyopencvVecConverter<KeyPoint> template<> struct pyopencvVecConverter<KeyPoint>
{ {
static bool to(PyObject* obj, std::vector<KeyPoint>& value, const ArgInfo info) static bool to(PyObject* obj, std::vector<KeyPoint>& value, const ArgInfo info)
...@@ -1814,6 +1689,7 @@ static int convert_to_char(PyObject *o, char *dst, const char *name = "no_name") ...@@ -1814,6 +1689,7 @@ static int convert_to_char(PyObject *o, char *dst, const char *name = "no_name")
# pragma GCC diagnostic ignored "-Wmissing-field-initializers" # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif #endif
#include "pyopencv_generated_enums.h"
#include "pyopencv_custom_headers.h" #include "pyopencv_custom_headers.h"
#include "pyopencv_generated_types.h" #include "pyopencv_generated_types.h"
#include "pyopencv_generated_funcs.h" #include "pyopencv_generated_funcs.h"
...@@ -1927,18 +1803,17 @@ void initcv2() ...@@ -1927,18 +1803,17 @@ void initcv2()
PyDict_SetItemString(d, "__version__", PyString_FromString(CV_VERSION)); PyDict_SetItemString(d, "__version__", PyString_FromString(CV_VERSION));
opencv_error = PyErr_NewException((char*)MODULESTR".error", NULL, NULL); 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); PyDict_SetItemString(d, "error", opencv_error);
//Registering UMatWrapper python class in cv2 module:
if (PyType_Ready(&cv2_UMatWrapperType) < 0)
#if PY_MAJOR_VERSION >= 3
return NULL;
#else
return;
#endif
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
#define PUBLISH_OBJECT(name, type) Py_INCREF(&type);\ #define PUBLISH_OBJECT(name, type) Py_INCREF(&type);\
PyModule_AddObject(m, name, (PyObject *)&type); PyModule_AddObject(m, name, (PyObject *)&type);
...@@ -1949,8 +1824,6 @@ void initcv2() ...@@ -1949,8 +1824,6 @@ void initcv2()
PyModule_AddObject(m, name, (PyObject *)&type); PyModule_AddObject(m, name, (PyObject *)&type);
#endif #endif
PUBLISH_OBJECT("UMat", cv2_UMatWrapperType);
#include "pyopencv_generated_type_publish.h" #include "pyopencv_generated_type_publish.h"
#define PUBLISH(I) PyDict_SetItemString(d, #I, PyInt_FromLong(I)) #define PUBLISH(I) PyDict_SetItemString(d, #I, PyInt_FromLong(I))
......
...@@ -10,19 +10,23 @@ if sys.version_info[0] >= 3: ...@@ -10,19 +10,23 @@ if sys.version_info[0] >= 3:
else: else:
from cStringIO import StringIO from cStringIO import StringIO
forbidden_arg_types = ["void*"]
ignored_arg_types = ["RNG*"] ignored_arg_types = ["RNG*"]
pass_by_val_types = ["Point*", "Point2f*", "Rect*", "String*", "double*", "float*", "int*"]
gen_template_check_self = Template(""" $cname* _self_ = NULL; gen_template_check_self = Template(""" $cname* _self_ = NULL;
if(PyObject_TypeCheck(self, &pyopencv_${name}_Type)) if(PyObject_TypeCheck(self, &pyopencv_${name}_Type))
_self_ = ${amp}((pyopencv_${name}_t*)self)->v${get}; _self_ = ${amp}((pyopencv_${name}_t*)self)->v${get};
if (_self_ == NULL) if (!_self_)
return failmsgp("Incorrect type of self (must be '${name}' or its derivative)"); return failmsgp("Incorrect type of self (must be '${name}' or its derivative)");
""") """)
gen_template_check_self_algo = Template(""" $cname* _self_ = NULL; gen_template_check_self_algo = Template(""" $cname* _self_ = NULL;
if(PyObject_TypeCheck(self, &pyopencv_${name}_Type)) if(PyObject_TypeCheck(self, &pyopencv_${name}_Type))
_self_ = dynamic_cast<$cname*>(${amp}((pyopencv_${name}_t*)self)->v.get()); _self_ = dynamic_cast<$cname*>(${amp}((pyopencv_${name}_t*)self)->v.get());
if (_self_ == NULL) if (!_self_)
return failmsgp("Incorrect type of self (must be '${name}' or its derivative)"); return failmsgp("Incorrect type of self (must be '${name}' or its derivative)");
""") """)
...@@ -68,27 +72,40 @@ static void pyopencv_${name}_dealloc(PyObject* self) ...@@ -68,27 +72,40 @@ static void pyopencv_${name}_dealloc(PyObject* self)
PyObject_Del(self); PyObject_Del(self);
} }
template<> PyObject* pyopencv_from(const ${cname}& r) template<>
struct PyOpenCV_Converter< ${cname} >
{ {
pyopencv_${name}_t *m = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type); static PyObject* from(const ${cname}& r)
new (&m->v) ${cname}(r); //Copy constructor {
return (PyObject*)m; pyopencv_${name}_t *m = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
} new (&m->v) ${cname}(r); //Copy constructor
return (PyObject*)m;
}
template<> bool pyopencv_to(PyObject* src, ${cname}& dst, const char* name) static bool to(PyObject* src, ${cname}& dst, const char* name)
{
if( src == NULL || src == Py_None )
return true;
if(!PyObject_TypeCheck(src, &pyopencv_${name}_Type))
{ {
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); failmsg("Expected ${cname} for argument '%%s'", name);
return false; return false;
} }
dst = ((pyopencv_${name}_t*)src)->v; };
return true;
}
""" % head_init_str) """ % head_init_str)
gen_template_mappable = Template("""
{
${mappable} _src;
if (pyopencv_to(src, _src, name))
{
return cv_mappable_to(_src, dst);
}
}
""")
gen_template_type_decl = Template(""" gen_template_type_decl = Template("""
struct pyopencv_${name}_t struct pyopencv_${name}_t
...@@ -110,26 +127,31 @@ static void pyopencv_${name}_dealloc(PyObject* self) ...@@ -110,26 +127,31 @@ static void pyopencv_${name}_dealloc(PyObject* self)
PyObject_Del(self); PyObject_Del(self);
} }
template<> PyObject* pyopencv_from(const Ptr<${cname}>& r) template<>
struct PyOpenCV_Converter< Ptr<${cname}> >
{ {
pyopencv_${name}_t *m = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type); static PyObject* from(const Ptr<${cname}>& r)
new (&(m->v)) Ptr<$cname1>(); // init Ptr with placement new {
m->v = r; pyopencv_${name}_t *m = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
return (PyObject*)m; new (&(m->v)) Ptr<$cname1>(); // init Ptr with placement new
} m->v = r;
return (PyObject*)m;
}
template<> bool pyopencv_to(PyObject* src, Ptr<${cname}>& dst, const char* name) static bool to(PyObject* src, Ptr<${cname}>& dst, const char* name)
{
if( src == NULL || src == Py_None )
return true;
if(!PyObject_TypeCheck(src, &pyopencv_${name}_Type))
{ {
if(!src || src == Py_None)
return true;
if(PyObject_TypeCheck(src, &pyopencv_${name}_Type))
{
dst = ((pyopencv_${name}_t*)src)->v.dynamicCast<${cname}>();
return true;
}
${mappable_code}
failmsg("Expected ${cname} for argument '%%s'", name); failmsg("Expected ${cname} for argument '%%s'", name);
return false; return false;
} }
dst = ((pyopencv_${name}_t*)src)->v.dynamicCast<${cname}>(); };
return true;
}
""" % head_init_str) """ % head_init_str)
...@@ -192,7 +214,7 @@ gen_template_get_prop_algo = Template(""" ...@@ -192,7 +214,7 @@ gen_template_get_prop_algo = Template("""
static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *closure) static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *closure)
{ {
$cname* _self_ = dynamic_cast<$cname*>(p->v.get()); $cname* _self_ = dynamic_cast<$cname*>(p->v.get());
if (_self_ == NULL) if (!_self_)
return failmsgp("Incorrect type of object (must be '${name}' or its derivative)"); return failmsgp("Incorrect type of object (must be '${name}' or its derivative)");
return pyopencv_from(_self_${access}${member}); return pyopencv_from(_self_${access}${member});
} }
...@@ -201,7 +223,7 @@ static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *clo ...@@ -201,7 +223,7 @@ static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *clo
gen_template_set_prop = Template(""" gen_template_set_prop = Template("""
static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value, void *closure) static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value, void *closure)
{ {
if (value == NULL) if (!value)
{ {
PyErr_SetString(PyExc_TypeError, "Cannot delete the ${member} attribute"); PyErr_SetString(PyExc_TypeError, "Cannot delete the ${member} attribute");
return -1; return -1;
...@@ -213,13 +235,13 @@ static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value ...@@ -213,13 +235,13 @@ static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value
gen_template_set_prop_algo = Template(""" gen_template_set_prop_algo = Template("""
static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value, void *closure) static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value, void *closure)
{ {
if (value == NULL) if (!value)
{ {
PyErr_SetString(PyExc_TypeError, "Cannot delete the ${member} attribute"); PyErr_SetString(PyExc_TypeError, "Cannot delete the ${member} attribute");
return -1; return -1;
} }
$cname* _self_ = dynamic_cast<$cname*>(p->v.get()); $cname* _self_ = dynamic_cast<$cname*>(p->v.get());
if (_self_ == NULL) if (!_self_)
{ {
failmsgp("Incorrect type of object (must be '${name}' or its derivative)"); failmsgp("Incorrect type of object (must be '${name}' or its derivative)");
return -1; return -1;
...@@ -265,6 +287,7 @@ class ClassInfo(object): ...@@ -265,6 +287,7 @@ class ClassInfo(object):
self.isalgorithm = False self.isalgorithm = False
self.methods = {} self.methods = {}
self.props = [] self.props = []
self.mappables = []
self.consts = {} self.consts = {}
self.base = None self.base = None
self.constructor = None self.constructor = None
...@@ -402,7 +425,7 @@ class ArgInfo(object): ...@@ -402,7 +425,7 @@ class ArgInfo(object):
self.py_outputarg = False self.py_outputarg = False
def isbig(self): def isbig(self):
return self.tp == "Mat" or self.tp == "vector_Mat"\ return self.tp == "Mat" or self.tp == "vector_Mat" or self.tp == "cuda::GpuMat"\
or self.tp == "UMat" or self.tp == "vector_UMat" # or self.tp.startswith("vector") or self.tp == "UMat" or self.tp == "vector_UMat" # or self.tp.startswith("vector")
def crepr(self): def crepr(self):
...@@ -410,10 +433,11 @@ class ArgInfo(object): ...@@ -410,10 +433,11 @@ class ArgInfo(object):
class FuncVariant(object): class FuncVariant(object):
def __init__(self, classname, name, decl, isconstructor): def __init__(self, classname, name, decl, isconstructor, isphantom=False):
self.classname = classname self.classname = classname
self.name = self.wname = name self.name = self.wname = name
self.isconstructor = isconstructor self.isconstructor = isconstructor
self.isphantom = isphantom
self.docstring = decl[5] self.docstring = decl[5]
...@@ -461,6 +485,7 @@ class FuncVariant(object): ...@@ -461,6 +485,7 @@ class FuncVariant(object):
argno += 1 argno += 1
if a.name in self.array_counters: if a.name in self.array_counters:
continue continue
assert not a.tp in forbidden_arg_types, 'Forbidden type "{}" for argument "{}" in "{}" ("{}")'.format(a.tp, a.name, self.name, self.classname)
if a.tp in ignored_arg_types: if a.tp in ignored_arg_types:
continue continue
if a.returnarg: if a.returnarg:
...@@ -520,17 +545,17 @@ class FuncVariant(object): ...@@ -520,17 +545,17 @@ class FuncVariant(object):
class FuncInfo(object): class FuncInfo(object):
def __init__(self, classname, name, cname, isconstructor, namespace, isclassmethod): def __init__(self, classname, name, cname, isconstructor, namespace, is_static):
self.classname = classname self.classname = classname
self.name = name self.name = name
self.cname = cname self.cname = cname
self.isconstructor = isconstructor self.isconstructor = isconstructor
self.namespace = namespace self.namespace = namespace
self.isclassmethod = isclassmethod self.is_static = is_static
self.variants = [] self.variants = []
def add_variant(self, decl): def add_variant(self, decl, isphantom=False):
self.variants.append(FuncVariant(self.classname, self.name, decl, self.isconstructor)) self.variants.append(FuncVariant(self.classname, self.name, decl, self.isconstructor, isphantom))
def get_wrapper_name(self): def get_wrapper_name(self):
name = self.name name = self.name
...@@ -541,8 +566,8 @@ class FuncInfo(object): ...@@ -541,8 +566,8 @@ class FuncInfo(object):
else: else:
classname = "" classname = ""
if self.isclassmethod: if self.is_static:
name += "_cls" name += "_static"
return "pyopencv_" + self.namespace.replace('.','_') + '_' + classname + name return "pyopencv_" + self.namespace.replace('.','_') + '_' + classname + name
...@@ -601,7 +626,7 @@ class FuncInfo(object): ...@@ -601,7 +626,7 @@ class FuncInfo(object):
return Template(' {"$py_funcname", CV_PY_FN_WITH_KW_($wrap_funcname, $flags), "$py_docstring"},\n' return Template(' {"$py_funcname", CV_PY_FN_WITH_KW_($wrap_funcname, $flags), "$py_docstring"},\n'
).substitute(py_funcname = self.variants[0].wname, wrap_funcname=self.get_wrapper_name(), ).substitute(py_funcname = self.variants[0].wname, wrap_funcname=self.get_wrapper_name(),
flags = 'METH_CLASS' if self.isclassmethod else '0', py_docstring = full_docstring) flags = 'METH_STATIC' if self.is_static else '0', py_docstring = full_docstring)
def gen_code(self, codegen): def gen_code(self, codegen):
all_classes = codegen.classes all_classes = codegen.classes
...@@ -618,7 +643,7 @@ class FuncInfo(object): ...@@ -618,7 +643,7 @@ class FuncInfo(object):
selfinfo = all_classes[self.classname] selfinfo = all_classes[self.classname]
if not self.isconstructor: if not self.isconstructor:
amp = "&" if selfinfo.issimple else "" amp = "&" if selfinfo.issimple else ""
if self.isclassmethod: if self.is_static:
pass pass
elif selfinfo.isalgorithm: elif selfinfo.isalgorithm:
code += gen_template_check_self_algo.substitute(name=selfinfo.name, cname=selfinfo.cname, amp=amp) code += gen_template_check_self_algo.substitute(name=selfinfo.name, cname=selfinfo.cname, amp=amp)
...@@ -638,6 +663,9 @@ class FuncInfo(object): ...@@ -638,6 +663,9 @@ class FuncInfo(object):
all_cargs = [] all_cargs = []
parse_arglist = [] parse_arglist = []
if v.isphantom and ismethod and not self.is_static:
code_args += "_self_"
# declare all the C function arguments, # declare all the C function arguments,
# add necessary conversions from Python objects to code_cvt_list, # add necessary conversions from Python objects to code_cvt_list,
# form the function/method call, # form the function/method call,
...@@ -646,7 +674,7 @@ class FuncInfo(object): ...@@ -646,7 +674,7 @@ class FuncInfo(object):
if a.tp in ignored_arg_types: if a.tp in ignored_arg_types:
defval = a.defval defval = a.defval
if not defval and a.tp.endswith("*"): if not defval and a.tp.endswith("*"):
defval = 0 defval = "0"
assert defval assert defval
if not code_args.endswith("("): if not code_args.endswith("("):
code_args += ", " code_args += ", "
...@@ -656,15 +684,15 @@ class FuncInfo(object): ...@@ -656,15 +684,15 @@ class FuncInfo(object):
tp1 = tp = a.tp tp1 = tp = a.tp
amp = "" amp = ""
defval0 = "" defval0 = ""
if tp.endswith("*"): if tp in pass_by_val_types:
tp = tp1 = tp[:-1] tp = tp1 = tp[:-1]
amp = "&" amp = "&"
if tp.endswith("*"): if tp.endswith("*"):
defval0 = "0" defval0 = "0"
tp1 = tp.replace("*", "_ptr") tp1 = tp.replace("*", "_ptr")
if tp1.endswith("*"): tp_candidates = [a.tp, normalize_class_name(self.namespace + "." + a.tp)]
print("Error: type with star: a.tp=%s, tp=%s, tp1=%s" % (a.tp, tp, tp1)) if any(tp in codegen.enums.keys() for tp in tp_candidates):
sys.exit(-1) defval0 = "static_cast<%s>(%d)" % (a.tp, 0)
amapping = simple_argtype_mapping.get(tp, (tp, "O", defval0)) amapping = simple_argtype_mapping.get(tp, (tp, "O", defval0))
parse_name = a.name parse_name = a.name
...@@ -686,6 +714,9 @@ class FuncInfo(object): ...@@ -686,6 +714,9 @@ class FuncInfo(object):
if "UMat" in tp: if "UMat" in tp:
if "Mat" in defval and "UMat" not in defval: if "Mat" in defval and "UMat" not in defval:
defval = defval.replace("Mat", "UMat") defval = defval.replace("Mat", "UMat")
if "cuda::GpuMat" in tp:
if "Mat" in defval and "GpuMat" not in defval:
defval = defval.replace("Mat", "cuda::GpuMat")
# "tp arg = tp();" is equivalent to "tp arg;" in the case of complex types # "tp arg = tp();" is equivalent to "tp arg;" in the case of complex types
if defval == tp + "()" and amapping[1] == "O": if defval == tp + "()" and amapping[1] == "O":
defval = "" defval = ""
...@@ -712,13 +743,15 @@ class FuncInfo(object): ...@@ -712,13 +743,15 @@ class FuncInfo(object):
code_prelude = templ_prelude.substitute(name=selfinfo.name, cname=selfinfo.cname) code_prelude = templ_prelude.substitute(name=selfinfo.name, cname=selfinfo.cname)
code_fcall = templ.substitute(name=selfinfo.name, cname=selfinfo.cname, args=code_args) code_fcall = templ.substitute(name=selfinfo.name, cname=selfinfo.cname, args=code_args)
if v.isphantom:
code_fcall = code_fcall.replace("new " + selfinfo.cname, self.cname.replace("::", "_"))
else: else:
code_prelude = "" code_prelude = ""
code_fcall = "" code_fcall = ""
if v.rettype: if v.rettype:
code_decl += " " + v.rettype + " retval;\n" code_decl += " " + v.rettype + " retval;\n"
code_fcall += "retval = " code_fcall += "retval = "
if ismethod and not self.isclassmethod: if not v.isphantom and ismethod and not self.is_static:
code_fcall += "_self_->" + self.cname code_fcall += "_self_->" + self.cname
else: else:
code_fcall += self.cname code_fcall += self.cname
...@@ -754,7 +787,7 @@ class FuncInfo(object): ...@@ -754,7 +787,7 @@ class FuncInfo(object):
parse_arglist = ", ".join(["&" + all_cargs[argno][1] for aname, argno in v.py_arglist]), parse_arglist = ", ".join(["&" + all_cargs[argno][1] for aname, argno in v.py_arglist]),
code_cvt = " &&\n ".join(code_cvt_list)) code_cvt = " &&\n ".join(code_cvt_list))
else: else:
code_parse = "if(PyObject_Size(args) == 0 && (kw == NULL || PyObject_Size(kw) == 0))" code_parse = "if(PyObject_Size(args) == 0 && (!kw || PyObject_Size(kw) == 0))"
if len(v.py_outlist) == 0: if len(v.py_outlist) == 0:
code_ret = "Py_RETURN_NONE" code_ret = "Py_RETURN_NONE"
...@@ -799,7 +832,7 @@ class FuncInfo(object): ...@@ -799,7 +832,7 @@ class FuncInfo(object):
#if dump: pprint(vars(classinfo)) #if dump: pprint(vars(classinfo))
if self.isconstructor: if self.isconstructor:
py_name = 'cv.' + classinfo.wname py_name = 'cv.' + classinfo.wname
elif self.isclassmethod: elif self.is_static:
py_name = '.'.join([self.namespace, classinfo.sname + '_' + self.variants[0].wname]) py_name = '.'.join([self.namespace, classinfo.sname + '_' + self.variants[0].wname])
else: else:
cname = classinfo.cname + '::' + cname cname = classinfo.cname + '::' + cname
...@@ -833,7 +866,9 @@ class PythonWrapperGenerator(object): ...@@ -833,7 +866,9 @@ class PythonWrapperGenerator(object):
self.classes = {} self.classes = {}
self.namespaces = {} self.namespaces = {}
self.consts = {} self.consts = {}
self.enums = {}
self.code_include = StringIO() self.code_include = StringIO()
self.code_enums = StringIO()
self.code_types = StringIO() self.code_types = StringIO()
self.code_funcs = StringIO() self.code_funcs = StringIO()
self.code_type_reg = StringIO() self.code_type_reg = StringIO()
...@@ -890,6 +925,18 @@ class PythonWrapperGenerator(object): ...@@ -890,6 +925,18 @@ class PythonWrapperGenerator(object):
py_signatures.append(dict(name=py_name, value=value)) py_signatures.append(dict(name=py_name, value=value))
#print(cname + ' => ' + str(py_name) + ' (value=' + value + ')') #print(cname + ' => ' + str(py_name) + ' (value=' + value + ')')
def add_enum(self, name, decl):
wname = normalize_class_name(name)
if wname.endswith("<unnamed>"):
wname = None
else:
self.enums[wname] = name
const_decls = decl[3]
for decl in const_decls:
name = decl[0]
self.add_const(name.replace("const ", "").strip(), decl)
def add_func(self, decl): def add_func(self, decl):
namespace, classes, barename = self.split_decl_name(decl[0]) namespace, classes, barename = self.split_decl_name(decl[0])
cname = "::".join(namespace+classes+[barename]) cname = "::".join(namespace+classes+[barename])
...@@ -902,35 +949,46 @@ class PythonWrapperGenerator(object): ...@@ -902,35 +949,46 @@ class PythonWrapperGenerator(object):
namespace = '.'.join(namespace) namespace = '.'.join(namespace)
isconstructor = name == bareclassname isconstructor = name == bareclassname
isclassmethod = False is_static = False
isphantom = False
mappable = None
for m in decl[2]: for m in decl[2]:
if m == "/S": if m == "/S":
isclassmethod = True is_static = True
elif m == "/phantom":
isphantom = True
cname = cname.replace("::", "_")
elif m.startswith("="): elif m.startswith("="):
name = m[1:] name = m[1:]
elif m.startswith("/mappable="):
mappable = m[10:]
self.classes[classname].mappables.append(mappable)
return
if isconstructor: if isconstructor:
name = "_".join(classes[:-1]+[name]) name = "_".join(classes[:-1]+[name])
if isclassmethod: if is_static:
# Add it as a method to the class # Add it as a method to the class
func_map = self.classes[classname].methods func_map = self.classes[classname].methods
func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace, isclassmethod)) func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace, is_static))
func.add_variant(decl) func.add_variant(decl, isphantom)
# Add it as global function # Add it as global function
g_name = "_".join(classes+[name]) g_name = "_".join(classes+[name])
func_map = self.namespaces.setdefault(namespace, Namespace()).funcs func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
func = func_map.setdefault(g_name, FuncInfo("", g_name, cname, isconstructor, namespace, False)) func = func_map.setdefault(g_name, FuncInfo("", g_name, cname, isconstructor, namespace, False))
func.add_variant(decl) func.add_variant(decl, isphantom)
else: else:
if classname and not isconstructor: if classname and not isconstructor:
cname = barename if not isphantom:
cname = barename
func_map = self.classes[classname].methods func_map = self.classes[classname].methods
else: else:
func_map = self.namespaces.setdefault(namespace, Namespace()).funcs func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace, isclassmethod)) func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace, is_static))
func.add_variant(decl) func.add_variant(decl, isphantom)
if classname and isconstructor: if classname and isconstructor:
self.classes[classname].constructor = func self.classes[classname].constructor = func
...@@ -949,10 +1007,10 @@ class PythonWrapperGenerator(object): ...@@ -949,10 +1007,10 @@ class PythonWrapperGenerator(object):
self.code_ns_reg.write('static ConstDef consts_%s[] = {\n'%wname) self.code_ns_reg.write('static ConstDef consts_%s[] = {\n'%wname)
for name, cname in sorted(ns.consts.items()): for name, cname in sorted(ns.consts.items()):
self.code_ns_reg.write(' {"%s", %s},\n'%(name, cname)) self.code_ns_reg.write(' {"%s", static_cast<long>(%s)},\n'%(name, cname))
compat_name = re.sub(r"([a-z])([A-Z])", r"\1_\2", name).upper() compat_name = re.sub(r"([a-z])([A-Z])", r"\1_\2", name).upper()
if name != compat_name: if name != compat_name:
self.code_ns_reg.write(' {"%s", %s},\n'%(compat_name, cname)) self.code_ns_reg.write(' {"%s", static_cast<long>(%s)},\n'%(compat_name, cname))
self.code_ns_reg.write(' {NULL, 0}\n};\n\n') self.code_ns_reg.write(' {NULL, 0}\n};\n\n')
def gen_namespaces_reg(self): def gen_namespaces_reg(self):
...@@ -963,6 +1021,21 @@ class PythonWrapperGenerator(object): ...@@ -963,6 +1021,21 @@ class PythonWrapperGenerator(object):
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(' init_submodule(root, MODULESTR"%s", methods_%s, consts_%s);\n' % (ns_name[2:], wname, wname))
self.code_ns_reg.write('};\n') self.code_ns_reg.write('};\n')
def gen_enum_reg(self, enum_name):
name_seg = enum_name.split(".")
is_enum_class = False
if len(name_seg) >= 2 and name_seg[-1] == name_seg[-2]:
enum_name = ".".join(name_seg[:-1])
is_enum_class = True
wname = normalize_class_name(enum_name)
cname = enum_name.replace(".", "::")
code = ""
if re.sub(r"^cv\.", "", enum_name) != wname:
code += "typedef enum {0} {1};\n".format(cname, wname)
code += "CV_PY_FROM_ENUM({0});\nCV_PY_TO_ENUM({0});\n\n".format(wname)
self.code_enums.write(code)
def save(self, path, name, buf): def save(self, path, name, buf):
with open(path + "/" + name, "wt") as f: with open(path + "/" + name, "wt") as f:
...@@ -975,14 +1048,15 @@ class PythonWrapperGenerator(object): ...@@ -975,14 +1048,15 @@ class PythonWrapperGenerator(object):
def gen(self, srcfiles, output_path): def gen(self, srcfiles, output_path):
self.clear() self.clear()
self.parser = hdr_parser.CppHeaderParser(generate_umat_decls=True) self.parser = hdr_parser.CppHeaderParser(generate_umat_decls=True, generate_gpumat_decls=False)
# step 1: scan the headers and build more descriptive maps of classes, consts, functions # step 1: scan the headers and build more descriptive maps of classes, consts, functions
for hdr in srcfiles: for hdr in srcfiles:
decls = self.parser.parse(hdr) decls = self.parser.parse(hdr)
if len(decls) == 0: if len(decls) == 0:
continue continue
self.code_include.write( '#include "{0}"\n'.format(hdr[hdr.rindex('opencv2/'):]) ) if hdr.find('opencv2/') >= 0: #Avoid including the shadow files
self.code_include.write( '#include "{0}"\n'.format(hdr[hdr.rindex('opencv2/'):]) )
for decl in decls: for decl in decls:
name = decl[0] name = decl[0]
if name.startswith("struct") or name.startswith("class"): if name.startswith("struct") or name.startswith("class"):
...@@ -994,6 +1068,9 @@ class PythonWrapperGenerator(object): ...@@ -994,6 +1068,9 @@ class PythonWrapperGenerator(object):
elif name.startswith("const"): elif name.startswith("const"):
# constant # constant
self.add_const(name.replace("const ", "").strip(), decl) self.add_const(name.replace("const ", "").strip(), decl)
elif name.startswith("enum"):
# enum
self.add_enum(name.rsplit(" ", 1)[1], decl)
else: else:
# function # function
self.add_func(decl) self.add_func(decl)
...@@ -1043,8 +1120,11 @@ class PythonWrapperGenerator(object): ...@@ -1043,8 +1120,11 @@ class PythonWrapperGenerator(object):
templ = gen_template_simple_type_decl templ = gen_template_simple_type_decl
else: else:
templ = gen_template_type_decl 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, 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))) cname1=("cv::Algorithm" if classinfo.isalgorithm else classinfo.cname), mappable_code=mappable_code))
# register classes in the same order as they have been declared. # register classes in the same order as they have been declared.
# this way, base classes will be registered in Python before their derivatives. # this way, base classes will be registered in Python before their derivatives.
...@@ -1070,7 +1150,13 @@ class PythonWrapperGenerator(object): ...@@ -1070,7 +1150,13 @@ class PythonWrapperGenerator(object):
self.gen_namespace(ns_name) self.gen_namespace(ns_name)
self.gen_namespaces_reg() self.gen_namespaces_reg()
# step 4: generate the code for constants # step 4: generate the code for enum types
enumlist = list(self.enums.values())
enumlist.sort()
for name in enumlist:
self.gen_enum_reg(name)
# step 5: generate the code for constants
constlist = list(self.consts.items()) constlist = list(self.consts.items())
constlist.sort() constlist.sort()
for name, constinfo in constlist: for name, constinfo in constlist:
...@@ -1079,6 +1165,7 @@ class PythonWrapperGenerator(object): ...@@ -1079,6 +1165,7 @@ class PythonWrapperGenerator(object):
# That's it. Now save all the files # That's it. Now save all the files
self.save(output_path, "pyopencv_generated_include.h", self.code_include) 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_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_types.h", self.code_types)
self.save(output_path, "pyopencv_generated_type_reg.h", self.code_type_reg) 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_ns_reg.h", self.code_ns_reg)
......
...@@ -6,6 +6,7 @@ import os, sys, re, string, io ...@@ -6,6 +6,7 @@ import os, sys, re, string, io
# the list only for debugging. The real list, used in the real OpenCV build, is specified in CMakeLists.txt # the list only for debugging. The real list, used in the real OpenCV build, is specified in CMakeLists.txt
opencv_hdr_list = [ opencv_hdr_list = [
"../../core/include/opencv2/core.hpp", "../../core/include/opencv2/core.hpp",
"../../core/include/opencv2/core/mat.hpp",
"../../core/include/opencv2/core/ocl.hpp", "../../core/include/opencv2/core/ocl.hpp",
"../../flann/include/opencv2/flann/miniflann.hpp", "../../flann/include/opencv2/flann/miniflann.hpp",
"../../ml/include/opencv2/ml.hpp", "../../ml/include/opencv2/ml.hpp",
...@@ -32,8 +33,9 @@ original_return_type is None if the original_return_type is the same as return_v ...@@ -32,8 +33,9 @@ original_return_type is None if the original_return_type is the same as return_v
class CppHeaderParser(object): class CppHeaderParser(object):
def __init__(self, generate_umat_decls=False): def __init__(self, generate_umat_decls=False, generate_gpumat_decls=False):
self._generate_umat_decls = generate_umat_decls self._generate_umat_decls = generate_umat_decls
self._generate_gpumat_decls = generate_gpumat_decls
self.BLOCK_TYPE = 0 self.BLOCK_TYPE = 0
self.BLOCK_NAME = 1 self.BLOCK_NAME = 1
...@@ -375,11 +377,9 @@ class CppHeaderParser(object): ...@@ -375,11 +377,9 @@ class CppHeaderParser(object):
decl[2].append("/A") decl[2].append("/A")
if bool(re.match(r".*\)\s*const(\s*=\s*0)?", decl_str)): if bool(re.match(r".*\)\s*const(\s*=\s*0)?", decl_str)):
decl[2].append("/C") decl[2].append("/C")
if "virtual" in decl_str:
print(decl_str)
return decl return decl
def parse_func_decl(self, decl_str, use_umat=False, docstring=""): def parse_func_decl(self, decl_str, mat="Mat", docstring=""):
""" """
Parses the function or method declaration in the form: Parses the function or method declaration in the form:
[([CV_EXPORTS] <rettype>) | CVAPI(rettype)] [([CV_EXPORTS] <rettype>) | CVAPI(rettype)]
...@@ -392,8 +392,7 @@ class CppHeaderParser(object): ...@@ -392,8 +392,7 @@ class CppHeaderParser(object):
""" """
if self.wrap_mode: if self.wrap_mode:
if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or \ if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or ("CV_WRAP" in decl_str)):
("CV_WRAP" in decl_str) or ("CV_WRAP_AS" in decl_str)):
return [] return []
# ignore old API in the documentation check (for now) # ignore old API in the documentation check (for now)
...@@ -413,6 +412,16 @@ class CppHeaderParser(object): ...@@ -413,6 +412,16 @@ class CppHeaderParser(object):
arg, npos3 = self.get_macro_arg(decl_str, npos) arg, npos3 = self.get_macro_arg(decl_str, npos)
func_modlist.append("="+arg) func_modlist.append("="+arg)
decl_str = decl_str[:npos] + decl_str[npos3+1:] decl_str = decl_str[:npos] + decl_str[npos3+1:]
npos = decl_str.find("CV_WRAP_PHANTOM")
if npos >= 0:
decl_str, _ = self.get_macro_arg(decl_str, npos)
func_modlist.append("/phantom")
npos = decl_str.find("CV_WRAP_MAPPABLE")
if npos >= 0:
mappable, npos3 = self.get_macro_arg(decl_str, npos)
func_modlist.append("/mappable="+mappable)
classname = top[1]
return ['.'.join([classname, classname]), None, func_modlist, [], None, None]
virtual_method = False virtual_method = False
pure_virtual_method = False pure_virtual_method = False
...@@ -526,8 +535,6 @@ class CppHeaderParser(object): ...@@ -526,8 +535,6 @@ class CppHeaderParser(object):
t, npos = self.find_next_token(decl_str, ["(", ")", ",", "<", ">"], npos) t, npos = self.find_next_token(decl_str, ["(", ")", ",", "<", ">"], npos)
if not t: if not t:
print("Error: no closing ')' at %d" % (self.lineno,)) print("Error: no closing ')' at %d" % (self.lineno,))
print(decl_str)
print(decl_str[arg_start:])
sys.exit(-1) sys.exit(-1)
if t == "<": if t == "<":
angle_balance += 1 angle_balance += 1
...@@ -563,8 +570,6 @@ class CppHeaderParser(object): ...@@ -563,8 +570,6 @@ class CppHeaderParser(object):
a = a[:eqpos].strip() a = a[:eqpos].strip()
arg_type, arg_name, modlist, argno = self.parse_arg(a, argno) arg_type, arg_name, modlist, argno = self.parse_arg(a, argno)
if self.wrap_mode: if self.wrap_mode:
mat = "UMat" if use_umat else "Mat"
# TODO: Vectors should contain UMat, but this is not very easy to support and not very needed # TODO: Vectors should contain UMat, but this is not very easy to support and not very needed
vector_mat = "vector_{}".format("Mat") vector_mat = "vector_{}".format("Mat")
vector_mat_template = "vector<{}>".format("Mat") vector_mat_template = "vector<{}>".format("Mat")
...@@ -629,8 +634,10 @@ class CppHeaderParser(object): ...@@ -629,8 +634,10 @@ class CppHeaderParser(object):
block_type, block_name = b[self.BLOCK_TYPE], b[self.BLOCK_NAME] block_type, block_name = b[self.BLOCK_TYPE], b[self.BLOCK_NAME]
if block_type in ["file", "enum"]: if block_type in ["file", "enum"]:
continue continue
if block_type not in ["struct", "class", "namespace"]: if block_type in ["enum struct", "enum class"] and block_name == name:
print("Error at %d: there are non-valid entries in the current block stack " % (self.lineno, self.block_stack)) continue
if block_type not in ["struct", "class", "namespace", "enum struct", "enum class"]:
print("Error at %d: there are non-valid entries in the current block stack %s" % (self.lineno, self.block_stack))
sys.exit(-1) sys.exit(-1)
if block_name and (block_type == "namespace" or not qualified_name): if block_name and (block_type == "namespace" or not qualified_name):
n += block_name + "." n += block_name + "."
...@@ -639,7 +646,7 @@ class CppHeaderParser(object): ...@@ -639,7 +646,7 @@ class CppHeaderParser(object):
n = "cv.Algorithm" n = "cv.Algorithm"
return n return n
def parse_stmt(self, stmt, end_token, use_umat=False, docstring=""): def parse_stmt(self, stmt, end_token, mat="Mat", docstring=""):
""" """
parses the statement (ending with ';' or '}') or a block head (ending with '{') parses the statement (ending with ';' or '}') or a block head (ending with '{')
...@@ -706,20 +713,19 @@ class CppHeaderParser(object): ...@@ -706,20 +713,19 @@ class CppHeaderParser(object):
decl[1] = ": " + ", ".join([self.get_dotted_name(b).replace(".","::") for b in bases]) decl[1] = ": " + ", ".join([self.get_dotted_name(b).replace(".","::") for b in bases])
return stmt_type, classname, True, decl return stmt_type, classname, True, decl
if stmt.startswith("enum"): if stmt.startswith("enum") or stmt.startswith("namespace"):
return "enum", "", True, None stmt_list = stmt.rsplit(" ", 1)
if stmt.startswith("namespace"):
stmt_list = stmt.split()
if len(stmt_list) < 2: if len(stmt_list) < 2:
stmt_list.append("<unnamed>") stmt_list.append("<unnamed>")
return stmt_list[0], stmt_list[1], True, None return stmt_list[0], stmt_list[1], True, None
if stmt.startswith("extern") and "\"C\"" in stmt: if stmt.startswith("extern") and "\"C\"" in stmt:
return "namespace", "", True, None return "namespace", "", True, None
if end_token == "}" and context == "enum": if end_token == "}" and context.startswith("enum"):
decl = self.parse_enum(stmt) decl = self.parse_enum(stmt)
return "enum", "", False, decl name = stack_top[self.BLOCK_NAME]
return context, name, False, decl
if end_token == ";" and stmt.startswith("typedef"): if end_token == ";" and stmt.startswith("typedef"):
# TODO: handle typedef's more intelligently # TODO: handle typedef's more intelligently
...@@ -731,7 +737,7 @@ class CppHeaderParser(object): ...@@ -731,7 +737,7 @@ class CppHeaderParser(object):
# since we filtered off the other places where '(' can normally occur: # since we filtered off the other places where '(' can normally occur:
# - code blocks # - code blocks
# - function pointer typedef's # - function pointer typedef's
decl = self.parse_func_decl(stmt, use_umat=use_umat, docstring=docstring) decl = self.parse_func_decl(stmt, mat=mat, docstring=docstring)
# we return parse_flag == False to prevent the parser to look inside function/method bodies # we return parse_flag == False to prevent the parser to look inside function/method bodies
# (except for tracking the nested blocks) # (except for tracking the nested blocks)
return stmt_type, "", False, decl return stmt_type, "", False, decl
...@@ -827,7 +833,7 @@ class CppHeaderParser(object): ...@@ -827,7 +833,7 @@ class CppHeaderParser(object):
l = l[pos+2:] l = l[pos+2:]
state = SCAN state = SCAN
if l.startswith('CV__'): # just ignore this lines if l.startswith('CV__') or l.startswith('__CV_'): # just ignore these lines
#print('IGNORE: ' + l) #print('IGNORE: ' + l)
state = SCAN state = SCAN
continue continue
...@@ -841,11 +847,17 @@ class CppHeaderParser(object): ...@@ -841,11 +847,17 @@ class CppHeaderParser(object):
if not token: if not token:
block_head += " " + l block_head += " " + l
break block_head = block_head.strip()
if len(block_head) > 0 and block_head[-1] == ')' and block_head.startswith('CV_ENUM_FLAGS('):
l = ''
token = ';'
else:
break
if token == "//": if token == "//":
block_head += " " + l[:pos] block_head += " " + l[:pos]
break l = ''
continue
if token == "/*": if token == "/*":
block_head += " " + l[:pos] block_head += " " + l[:pos]
...@@ -896,20 +908,29 @@ class CppHeaderParser(object): ...@@ -896,20 +908,29 @@ class CppHeaderParser(object):
docstring = docstring.strip() docstring = docstring.strip()
stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token, docstring=docstring) stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token, docstring=docstring)
if decl: if decl:
if stmt_type == "enum": if stmt_type.startswith("enum"):
for d in decl: decls.append([stmt_type + " " + self.get_dotted_name(name), "", [], decl, None, ""])
decls.append(d)
else: else:
decls.append(decl) decls.append(decl)
if self._generate_gpumat_decls and "cv.cuda." in decl[0]:
# If function takes as one of arguments Mat or vector<Mat> - we want to create the
# same declaration working with GpuMat (this is important for T-Api access)
args = decl[3]
has_mat = len(list(filter(lambda x: x[0] in {"Mat", "vector_Mat"}, args))) > 0
if has_mat:
_, _, _, gpumat_decl = self.parse_stmt(stmt, token, mat="cuda::GpuMat", docstring=docstring)
decls.append(gpumat_decl)
if self._generate_umat_decls: if self._generate_umat_decls:
# If function takes as one of arguments Mat or vector<Mat> - we want to create the # If function takes as one of arguments Mat or vector<Mat> - we want to create the
# same declaration working with UMat (this is important for T-Api access) # same declaration working with UMat (this is important for T-Api access)
args = decl[3] args = decl[3]
has_mat = len(list(filter(lambda x: x[0] in {"Mat", "vector_Mat"}, args))) > 0 has_mat = len(list(filter(lambda x: x[0] in {"Mat", "vector_Mat"}, args))) > 0
if has_mat: if has_mat:
_, _, _, umat_decl = self.parse_stmt(stmt, token, use_umat=True, docstring=docstring) _, _, _, umat_decl = self.parse_stmt(stmt, token, mat="UMat", docstring=docstring)
decls.append(umat_decl) decls.append(umat_decl)
docstring = "" docstring = ""
if stmt_type == "namespace": if stmt_type == "namespace":
chunks = [block[1] for block in self.block_stack if block[0] == 'namespace'] + [name] chunks = [block[1] for block in self.block_stack if block[0] == 'namespace'] + [name]
...@@ -952,7 +973,7 @@ class CppHeaderParser(object): ...@@ -952,7 +973,7 @@ class CppHeaderParser(object):
print() print()
if __name__ == '__main__': if __name__ == '__main__':
parser = CppHeaderParser(generate_umat_decls=True) parser = CppHeaderParser(generate_umat_decls=True, generate_gpumat_decls=False)
decls = [] decls = []
for hname in opencv_hdr_list: for hname in opencv_hdr_list:
decls += parser.parse(hname) decls += parser.parse(hname)
......
#ifdef HAVE_OPENCV_STITCHING #ifdef HAVE_OPENCV_STITCHING
typedef Stitcher::Status Status; typedef Stitcher::Status Status;
#endif
template<>
PyObject* pyopencv_from(const Status& value)
{
return PyInt_FromLong(value);
}
#endif
\ No newline at end of file
#ifdef HAVE_OPENCV_VIDEOIO #ifdef HAVE_OPENCV_VIDEOIO
typedef std::vector<VideoCaptureAPIs> vector_VideoCaptureAPIs; typedef std::vector<VideoCaptureAPIs> vector_VideoCaptureAPIs;
template<>
bool pyopencv_to(PyObject *o, cv::VideoCaptureAPIs &v, const char *name)
{
(void)name;
v = CAP_ANY;
if (!o || o == Py_None)
return false;
else if (PyLong_Check(o))
{
v = VideoCaptureAPIs((int64)PyLong_AsLongLong(o));
return true;
}
else if (PyInt_Check(o))
{
v = VideoCaptureAPIs((int64)PyInt_AS_LONG(o));
return true;
}
else
return false;
}
template<>
PyObject* pyopencv_from(const cv::VideoCaptureAPIs &v)
{
return pyopencv_from((int)(v));
}
template<> struct pyopencvVecConverter<cv::VideoCaptureAPIs> template<> struct pyopencvVecConverter<cv::VideoCaptureAPIs>
{ {
static bool to(PyObject* obj, std::vector<cv::VideoCaptureAPIs>& value, const ArgInfo info) static bool to(PyObject* obj, std::vector<cv::VideoCaptureAPIs>& value, const ArgInfo info)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment