Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
335e61dc
Commit
335e61dc
authored
Aug 24, 2018
by
Alexander Alekhin
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #12269 from cv3d:improvements/binding_python
parents
d8cd1d8f
64380baa
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
282 additions
and
56 deletions
+282
-56
Doxyfile.in
doc/Doxyfile.in
+3
-0
py_bindings_basics.markdown
...y_bindings/py_bindings_basics/py_bindings_basics.markdown
+57
-23
cvdef.h
modules/core/include/opencv2/core/cvdef.h
+3
-0
gen_java.py
modules/java/generator/gen_java.py
+8
-0
cv2.cpp
modules/python/src2/cv2.cpp
+134
-3
gen2.py
modules/python/src2/gen2.py
+58
-17
hdr_parser.py
modules/python/src2/hdr_parser.py
+19
-13
No files found.
doc/Doxyfile.in
View file @
335e61dc
...
...
@@ -241,6 +241,9 @@ PREDEFINED = __cplusplus=1 \
CV_PROP_RW= \
CV_WRAP= \
CV_WRAP_AS(x)= \
CV_WRAP_MAPPABLE(x)= \
CV_WRAP_PHANTOM(x)= \
CV_WRAP_DEFAULT(x)= \
CV_CDECL= \
CV_Func = \
CV_DO_PRAGMA(x)= \
...
...
doc/py_tutorials/py_bindings/py_bindings_basics/py_bindings_basics.markdown
View file @
335e61dc
...
...
@@ -20,20 +20,20 @@ A simple example on extending C++ functions to Python can be found in official P
documentation
[
1
]
. So extending all functions in OpenCV to Python by writing their wrapper functions
manually is a time-consuming task. So OpenCV does it in a more intelligent way. OpenCV generates
these wrapper functions automatically from the C++ headers using some Python scripts which are
located in
modules/python/src2
. We will look into what they do.
located in
`modules/python/src2`
. We will look into what they do.
First,
modules/python/CMakeFiles.txt
is a CMake script which checks the modules to be extended to
First,
`modules/python/CMakeFiles.txt`
is a CMake script which checks the modules to be extended to
Python. It will automatically check all the modules to be extended and grab their header files.
These header files contain list of all classes, functions, constants etc. for that particular
modules.
Second, these header files are passed to a Python script,
modules/python/src2/gen2.py
. This is the
Python bindings generator script. It calls another Python script
modules/python/src2/hdr_parser.py
.
Second, these header files are passed to a Python script,
`modules/python/src2/gen2.py`
. This is the
Python bindings generator script. It calls another Python script
`modules/python/src2/hdr_parser.py`
.
This is the header parser script. This header parser splits the complete header file into small
Python lists. So these lists contain all details about a particular function, class etc. For
example, a function will be parsed to get a list containing function name, return type, input
arguments, argument types etc. Final list contains details of all the functions,
structs, classes
etc. in that header file.
arguments, argument types etc. Final list contains details of all the functions,
enums, structs,
classes
etc. in that header file.
But header parser doesn't parse all the functions/classes in the header file. The developer has to
specify which functions should be exported to Python. For that, there are certain macros added to
...
...
@@ -44,15 +44,15 @@ macros will be given in next session.
So header parser returns a final big list of parsed functions. Our generator script (gen2.py) will
create wrapper functions for all the functions/classes/enums/structs parsed by header parser (You
can find these header files during compilation in the
build/modules/python/
folder as
can find these header files during compilation in the
`build/modules/python/`
folder as
pyopencv_generated_
\*
.h files). But there may be some basic OpenCV datatypes like Mat, Vec4i,
Size. They need to be extended manually. For example, a Mat type should be extended to Numpy array,
Size should be extended to a tuple of two integers etc. Similarly, there may be some complex
structs/classes/functions etc. which need to be extended manually. All such manual wrapper functions
are placed in
modules/python/src2/cv2.cpp
.
are placed in
`modules/python/src2/cv2.cpp`
.
So now only thing left is the compilation of these wrapper files which gives us
**cv2**
module. So
when you call a function, say
res = equalizeHist(img1,img2)
in Python, you pass two numpy arrays and
when you call a function, say
`res = equalizeHist(img1,img2)`
in Python, you pass two numpy arrays and
you expect another numpy array as the output. So these numpy arrays are converted to cv::Mat and
then calls the equalizeHist() function in C++. Final result, res will be converted back into a Numpy
array. So in short, almost all operations are done in C++ which gives us almost same speed as that
...
...
@@ -67,19 +67,19 @@ Header parser parse the header files based on some wrapper macros added to funct
Enumeration constants don't need any wrapper macros. They are automatically wrapped. But remaining
functions, classes etc. need wrapper macros.
Functions are extended using
CV_EXPORTS_W
macro. An example is shown below.
Functions are extended using
`CV_EXPORTS_W`
macro. An example is shown below.
@code{.cpp}
CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst );
@endcode
Header parser can understand the input and output arguments from keywords like
InputArray, OutputArray etc. But sometimes, we may need to hardcode inputs and outputs. For that,
macros like
CV_OUT, CV_IN_OUT
etc. are used.
macros like
`CV_OUT`
,
`CV_IN_OUT`
etc. are used.
@code{.cpp}
CV_EXPORTS_W void minEnclosingCircle( InputArray points,
CV_OUT Point2f& center, CV_OUT float& radius );
@endcode
For large classes also,
CV_EXPORTS_W is used. To extend class methods, CV_WRAP
is used.
Similarly,
CV_PROP
is used for class fields.
For large classes also,
`CV_EXPORTS_W`
is used. To extend class methods,
`CV_WRAP`
is used.
Similarly,
`CV_PROP`
is used for class fields.
@code{.cpp}
class CV_EXPORTS_W CLAHE : public Algorithm
{
...
...
@@ -90,9 +90,9 @@ public:
CV_WRAP virtual double getClipLimit() const = 0;
}
@endcode
Overloaded functions can be extended using
CV_EXPORTS_AS
. But we need to pass a new name so that
Overloaded functions can be extended using
`CV_EXPORTS_AS`
. But we need to pass a new name so that
each function will be called by that name in Python. Take the case of integral function below. Three
functions are available, so each one is named with a suffix in Python. Similarly
CV_WRAP_AS
can be
functions are available, so each one is named with a suffix in Python. Similarly
`CV_WRAP_AS`
can be
used to wrap overloaded methods.
@code{.cpp}
//! computes the integral image
...
...
@@ -107,9 +107,9 @@ CV_EXPORTS_AS(integral3) void integral( InputArray src, OutputArray sum,
OutputArray sqsum, OutputArray tilted,
int sdepth = -1, int sqdepth = -1 );
@endcode
Small classes/structs are extended using
CV_EXPORTS_W_SIMPLE
. These structs are passed by value
to C++ functions. Examples are
KeyPoint, Match etc. Their methods are extended by CV_WRAP
and
fields are extended by
CV_PROP_RW
.
Small classes/structs are extended using
`CV_EXPORTS_W_SIMPLE`
. These structs are passed by value
to C++ functions. Examples are
`KeyPoint`
,
`Match`
etc. Their methods are extended by
`CV_WRAP`
and
fields are extended by
`CV_PROP_RW`
.
@code{.cpp}
class CV_EXPORTS_W_SIMPLE DMatch
{
...
...
@@ -125,8 +125,8 @@ public:
CV_PROP_RW float distance;
};
@endcode
Some other small classes/structs can be exported using
CV_EXPORTS_W_MAP
where it is exported to a
Python native dictionary.
Moments()
is an example of it.
Some other small classes/structs can be exported using
`CV_EXPORTS_W_MAP`
where it is exported to a
Python native dictionary.
`Moments()`
is an example of it.
@code{.cpp}
class CV_EXPORTS_W_MAP Moments
{
...
...
@@ -142,6 +142,41 @@ public:
So these are the major extension macros available in OpenCV. Typically, a developer has to put
proper macros in their appropriate positions. Rest is done by generator scripts. Sometimes, there
may be an exceptional cases where generator scripts cannot create the wrappers. Such functions need
to be handled manually, to do this write your own
pyopencv_
*
.hpp
extending headers and put them into
to be handled manually, to do this write your own
`pyopencv_*.hpp`
extending headers and put them into
misc/python subdirectory of your module. But most of the time, a code written according to OpenCV
coding guidelines will be automatically wrapped by generator scripts.
\ No newline at end of file
coding guidelines will be automatically wrapped by generator scripts.
More advanced cases involves providing Python with additional features that does not exist
in the C++ interface such as extra methods, type mappings, or to provide default arguments.
We will take
`UMat`
datatype as an example of such cases later on.
First, to provide Python-specific methods,
`CV_WRAP_PHANTOM`
is utilized in a similar manner to
`CV_WRAP`
, except that it takes the method header as its argument, and you would need to provide
the method body in your own
`pyopencv_*.hpp`
extension.
`UMat::queue()`
and
`UMat::context()`
are
an example of such phantom methods that does not exist in C++ interface, but are needed to handle
OpenCL functionalities at the Python side.
Second, if an already-existing datatype(s) is mappable to your class, it is highly preferable to
indicate such capacity using
`CV_WRAP_MAPPABLE`
with the source type as its argument,
rather than crafting your own binding function(s). This is the case of
`UMat`
which maps from
`Mat`
.
Finally, if a default argument is needed, but it is not provided in the native C++ interface,
you can provide it for Python side as the argument of
`CV_WRAP_DEFAULT`
. As per the
`UMat::getMat`
example below:
@code{.cpp}
class CV_EXPORTS_W UMat
{
public:
//! Mat is mappable to UMat.
// You would need to provide
`static bool cv_mappable_to(const Ptr<Mat>& src, Ptr<UMat>& dst)`
CV_WRAP_MAPPABLE(Ptr
<Mat>
);
/! returns the OpenCL queue used by OpenCV UMat.
// You would need to provide the method body in the binder code
CV_WRAP_PHANTOM(static void* queue());
//! returns the OpenCL context used by OpenCV UMat
// You would need to provide the method body in the binder code
CV_WRAP_PHANTOM(static void* context());
//! The wrapped method become equvalent to `get(int flags = ACCESS_RW)`
CV_WRAP_AS(get) Mat getMat(int flags CV_WRAP_DEFAULT(ACCESS_RW)) const;
};
@endcode
modules/core/include/opencv2/core/cvdef.h
View file @
335e61dc
...
...
@@ -307,6 +307,9 @@ Cv64suf;
#define CV_PROP_RW
#define CV_WRAP
#define CV_WRAP_AS(synonym)
#define CV_WRAP_MAPPABLE(mappable)
#define CV_WRAP_PHANTOM(phantom_header)
#define CV_WRAP_DEFAULT(val)
/****************************************************************************************\
* Matrix type (Mat) *
...
...
modules/java/generator/gen_java.py
View file @
335e61dc
...
...
@@ -341,6 +341,7 @@ class JavaWrapperGenerator(object):
self
.
classes
=
{
"Mat"
:
ClassInfo
([
'class Mat'
,
''
,
[],
[]
],
self
.
namespaces
)
}
self
.
module
=
""
self
.
Module
=
""
self
.
enum_types
=
[]
self
.
ported_func_list
=
[]
self
.
skipped_func_list
=
[]
self
.
def_args_hist
=
{}
# { def_args_cnt : funcs_cnt }
...
...
@@ -421,6 +422,10 @@ class JavaWrapperGenerator(object):
ci
.
addConst
(
constinfo
)
logging
.
info
(
'ok:
%
s'
,
constinfo
)
def
add_enum
(
self
,
decl
):
# [ "enum cname", "", [], [] ]
enumname
=
decl
[
0
]
.
replace
(
"enum "
,
""
)
.
strip
()
self
.
enum_types
.
append
(
enumname
)
def
add_func
(
self
,
decl
):
fi
=
FuncInfo
(
decl
,
namespaces
=
self
.
namespaces
)
classname
=
fi
.
classname
or
self
.
Module
...
...
@@ -479,6 +484,9 @@ class JavaWrapperGenerator(object):
self
.
add_class
(
decl
)
elif
name
.
startswith
(
"const"
):
self
.
add_const
(
decl
)
elif
name
.
startswith
(
"enum"
):
# enum
self
.
add_enum
(
decl
)
else
:
# function
self
.
add_func
(
decl
)
...
...
modules/python/src2/cv2.cpp
View file @
335e61dc
...
...
@@ -27,6 +27,80 @@
# 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, Ptr<TYPE>& src, const char* name); \
\
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 Ptr<TYPE>& src); \
\
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, Ptr<TYPE>& src, const char* name); \
\
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) \
template<> PyObject* pyopencv_from(const Ptr<TYPE>& src); \
\
static PyObject* pyopencv_from(TYPE*& src) \
{ \
return pyopencv_from(Ptr<TYPE>(src)); \
}
#define CV_PY_TO_ENUM(TYPE) \
template<> bool pyopencv_to(PyObject* dst, std::underlying_type<TYPE>::type& src, const char* name); \
\
template<> \
bool pyopencv_to(PyObject* dst, TYPE& src, const char* name) \
{ \
if (!dst || dst == Py_None) \
return true; \
std::underlying_type<TYPE>::type underlying; \
\
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 std::underlying_type<TYPE>::type& src); \
\
template<> \
PyObject* pyopencv_from(const TYPE& src) \
{ \
return pyopencv_from(static_cast<std::underlying_type<TYPE>::type>(src)); \
}
#include "pyopencv_generated_include.h"
#include "opencv2/core/types_c.h"
...
...
@@ -36,7 +110,7 @@
#include <map>
static
PyObject
*
opencv_error
=
0
;
static
PyObject
*
opencv_error
=
NULL
;
static
int
failmsg
(
const
char
*
fmt
,
...)
{
...
...
@@ -97,6 +171,12 @@ try \
} \
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()); \
return 0; \
}
...
...
@@ -735,12 +815,31 @@ bool pyopencv_to(PyObject* o, UMat& um, const char* name)
}
template
<>
PyObject
*
pyopencv_from
(
const
UMat
&
m
)
{
PyObject
*
pyopencv_from
(
const
UMat
&
m
)
{
PyObject
*
o
=
PyObject_CallObject
((
PyObject
*
)
&
cv2_UMatWrapperType
,
NULL
);
*
((
cv2_UMatWrapperObject
*
)
o
)
->
um
=
m
;
return
o
;
}
template
<>
bool
pyopencv_to
(
PyObject
*
obj
,
void
*&
ptr
,
const
char
*
name
)
{
(
void
)
name
;
if
(
!
obj
||
obj
==
Py_None
)
return
true
;
if
(
!
PyLong_Check
(
obj
))
return
false
;
ptr
=
PyLong_AsVoidPtr
(
obj
);
return
ptr
!=
NULL
&&
!
PyErr_Occurred
();
}
static
PyObject
*
pyopencv_from
(
void
*&
ptr
)
{
return
PyLong_FromVoidPtr
(
ptr
);
}
static
bool
pyopencv_to
(
PyObject
*
o
,
Scalar
&
s
,
const
ArgInfo
info
)
{
if
(
!
o
||
o
==
Py_None
)
...
...
@@ -843,6 +942,30 @@ bool pyopencv_to(PyObject* obj, int& value, const char* name)
return
value
!=
-
1
||
!
PyErr_Occurred
();
}
#if defined (_M_AMD64) || defined (__x86_64__)
template
<>
PyObject
*
pyopencv_from
(
const
unsigned
int
&
value
)
{
return
PyLong_FromUnsignedLong
(
value
);
}
template
<>
bool
pyopencv_to
(
PyObject
*
obj
,
unsigned
int
&
value
,
const
char
*
name
)
{
(
void
)
name
;
if
(
!
obj
||
obj
==
Py_None
)
return
true
;
if
(
PyInt_Check
(
obj
))
value
=
(
unsigned
int
)
PyInt_AsLong
(
obj
);
else
if
(
PyLong_Check
(
obj
))
value
=
(
unsigned
int
)
PyLong_AsLong
(
obj
);
else
return
false
;
return
value
!=
(
unsigned
int
)
-
1
||
!
PyErr_Occurred
();
}
#endif
template
<>
PyObject
*
pyopencv_from
(
const
uchar
&
value
)
{
...
...
@@ -1913,7 +2036,15 @@ void initcv2()
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
);
//Registering UMatWrapper python class in cv2 module:
...
...
modules/python/src2/gen2.py
View file @
335e61dc
...
...
@@ -81,16 +81,25 @@ template<> bool pyopencv_to(PyObject* src, ${cname}& dst, const char* name)
{
if(!src || src == Py_None)
return true;
if(
!
PyObject_TypeCheck(src, &pyopencv_${name}_Type))
if(PyObject_TypeCheck(src, &pyopencv_${name}_Type))
{
failmsg("Expected ${cname} for argument '
%%
s'", name)
;
return
fals
e;
dst = ((pyopencv_${name}_t*)src)->v
;
return
tru
e;
}
dst = ((pyopencv_${name}_t*)src)->v
;
return
tru
e;
failmsg("Expected ${cname} for argument '
%%
s'", name)
;
return
fals
e;
}
"""
%
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
(
"""
struct pyopencv_${name}_t
...
...
@@ -124,13 +133,14 @@ template<> bool pyopencv_to(PyObject* src, Ptr<${cname}>& dst, const char* name)
{
if(!src || src == Py_None)
return true;
if(
!
PyObject_TypeCheck(src, &pyopencv_${name}_Type))
if(PyObject_TypeCheck(src, &pyopencv_${name}_Type))
{
failmsg("Expected ${cname} for argument '
%%
s'", name
);
return
fals
e;
dst = ((pyopencv_${name}_t*)src)->v.dynamicCast<${cname}>(
);
return
tru
e;
}
dst = ((pyopencv_${name}_t*)src)->v.dynamicCast<${cname}>();
return true;
${mappable_code}
failmsg("Expected ${cname} for argument '
%%
s'", name);
return false;
}
"""
%
head_init_str
)
...
...
@@ -267,6 +277,7 @@ class ClassInfo(object):
self
.
isalgorithm
=
False
self
.
methods
=
{}
self
.
props
=
[]
self
.
mappables
=
[]
self
.
consts
=
{}
self
.
base
=
None
self
.
constructor
=
None
...
...
@@ -412,10 +423,11 @@ class ArgInfo(object):
class
FuncVariant
(
object
):
def
__init__
(
self
,
classname
,
name
,
decl
,
isconstructor
):
def
__init__
(
self
,
classname
,
name
,
decl
,
isconstructor
,
isphantom
=
False
):
self
.
classname
=
classname
self
.
name
=
self
.
wname
=
name
self
.
isconstructor
=
isconstructor
self
.
isphantom
=
isphantom
self
.
docstring
=
decl
[
5
]
...
...
@@ -531,8 +543,8 @@ class FuncInfo(object):
self
.
isclassmethod
=
isclassmethod
self
.
variants
=
[]
def
add_variant
(
self
,
decl
):
self
.
variants
.
append
(
FuncVariant
(
self
.
classname
,
self
.
name
,
decl
,
self
.
isconstructor
))
def
add_variant
(
self
,
decl
,
isphantom
=
False
):
self
.
variants
.
append
(
FuncVariant
(
self
.
classname
,
self
.
name
,
decl
,
self
.
isconstructor
,
isphantom
))
def
get_wrapper_name
(
self
):
name
=
self
.
name
...
...
@@ -640,6 +652,9 @@ class FuncInfo(object):
all_cargs
=
[]
parse_arglist
=
[]
if
v
.
isphantom
and
ismethod
and
not
self
.
isclassmethod
:
code_args
+=
"_self_"
# declare all the C function arguments,
# add necessary conversions from Python objects to code_cvt_list,
# form the function/method call,
...
...
@@ -664,6 +679,9 @@ class FuncInfo(object):
if
tp
.
endswith
(
"*"
):
defval0
=
"0"
tp1
=
tp
.
replace
(
"*"
,
"_ptr"
)
tp_candidates
=
[
a
.
tp
,
normalize_class_name
(
self
.
namespace
+
"."
+
a
.
tp
)]
if
any
(
tp
in
codegen
.
enum_types
for
tp
in
tp_candidates
):
defval0
=
"static_cast<
%
s>(
%
d)"
%
(
a
.
tp
,
0
)
amapping
=
simple_argtype_mapping
.
get
(
tp
,
(
tp
,
"O"
,
defval0
))
parse_name
=
a
.
name
...
...
@@ -714,6 +732,8 @@ class FuncInfo(object):
code_prelude
=
templ_prelude
.
substitute
(
name
=
selfinfo
.
name
,
cname
=
selfinfo
.
cname
)
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
:
code_prelude
=
""
code_fcall
=
""
...
...
@@ -835,6 +855,7 @@ class PythonWrapperGenerator(object):
self
.
classes
=
{}
self
.
namespaces
=
{}
self
.
consts
=
{}
self
.
enum_types
=
[]
self
.
code_include
=
StringIO
()
self
.
code_types
=
StringIO
()
self
.
code_funcs
=
StringIO
()
...
...
@@ -892,6 +913,10 @@ class PythonWrapperGenerator(object):
py_signatures
.
append
(
dict
(
name
=
py_name
,
value
=
value
))
#print(cname + ' => ' + str(py_name) + ' (value=' + value + ')')
def
add_enum
(
self
,
name
,
decl
):
enumname
=
normalize_class_name
(
name
)
self
.
enum_types
.
append
(
enumname
)
def
add_func
(
self
,
decl
):
namespace
,
classes
,
barename
=
self
.
split_decl_name
(
decl
[
0
])
cname
=
"::"
.
join
(
namespace
+
classes
+
[
barename
])
...
...
@@ -905,11 +930,21 @@ class PythonWrapperGenerator(object):
isconstructor
=
name
==
bareclassname
isclassmethod
=
False
isphantom
=
False
mappable
=
None
for
m
in
decl
[
2
]:
if
m
==
"/S"
:
isclassmethod
=
True
elif
m
==
"/phantom"
:
isphantom
=
True
cname
=
cname
.
replace
(
"::"
,
"_"
)
elif
m
.
startswith
(
"="
):
name
=
m
[
1
:]
elif
m
.
startswith
(
"/mappable="
):
mappable
=
m
[
10
:]
self
.
classes
[
classname
]
.
mappables
.
append
(
mappable
)
return
if
isconstructor
:
name
=
"_"
.
join
(
classes
[:
-
1
]
+
[
name
])
...
...
@@ -917,13 +952,13 @@ class PythonWrapperGenerator(object):
# Add it as a method to the class
func_map
=
self
.
classes
[
classname
]
.
methods
func
=
func_map
.
setdefault
(
name
,
FuncInfo
(
classname
,
name
,
cname
,
isconstructor
,
namespace
,
isclassmethod
))
func
.
add_variant
(
decl
)
func
.
add_variant
(
decl
,
isphantom
)
# Add it as global function
g_name
=
"_"
.
join
(
classes
+
[
name
])
func_map
=
self
.
namespaces
.
setdefault
(
namespace
,
Namespace
())
.
funcs
func
=
func_map
.
setdefault
(
g_name
,
FuncInfo
(
""
,
g_name
,
cname
,
isconstructor
,
namespace
,
False
))
func
.
add_variant
(
decl
)
func
.
add_variant
(
decl
,
isphantom
)
else
:
if
classname
and
not
isconstructor
:
cname
=
barename
...
...
@@ -932,7 +967,7 @@ class PythonWrapperGenerator(object):
func_map
=
self
.
namespaces
.
setdefault
(
namespace
,
Namespace
())
.
funcs
func
=
func_map
.
setdefault
(
name
,
FuncInfo
(
classname
,
name
,
cname
,
isconstructor
,
namespace
,
isclassmethod
))
func
.
add_variant
(
decl
)
func
.
add_variant
(
decl
,
isphantom
)
if
classname
and
isconstructor
:
self
.
classes
[
classname
]
.
constructor
=
func
...
...
@@ -996,6 +1031,9 @@ class PythonWrapperGenerator(object):
elif
name
.
startswith
(
"const"
):
# constant
self
.
add_const
(
name
.
replace
(
"const "
,
""
)
.
strip
(),
decl
)
elif
name
.
startswith
(
"enum"
):
# enum
self
.
add_enum
(
name
.
replace
(
"enum "
,
""
)
.
strip
(),
decl
)
else
:
# function
self
.
add_func
(
decl
)
...
...
@@ -1045,8 +1083,11 @@ class PythonWrapperGenerator(object):
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
)))
cname1
=
(
"cv::Algorithm"
if
classinfo
.
isalgorithm
else
classinfo
.
cname
)
,
mappable_code
=
mappable_code
))
# register classes in the same order as they have been declared.
# this way, base classes will be registered in Python before their derivatives.
...
...
modules/python/src2/hdr_parser.py
View file @
335e61dc
...
...
@@ -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
opencv_hdr_list
=
[
"../../core/include/opencv2/core.hpp"
,
"../../core/include/opencv2/core/mat.hpp"
,
"../../core/include/opencv2/core/ocl.hpp"
,
"../../flann/include/opencv2/flann/miniflann.hpp"
,
"../../ml/include/opencv2/ml.hpp"
,
...
...
@@ -376,8 +377,6 @@ class CppHeaderParser(object):
decl
[
2
]
.
append
(
"/A"
)
if
bool
(
re
.
match
(
r".*\)\s*const(\s*=\s*0)?"
,
decl_str
)):
decl
[
2
]
.
append
(
"/C"
)
if
"virtual"
in
decl_str
:
print
(
decl_str
)
return
decl
def
parse_func_decl
(
self
,
decl_str
,
mat
=
"Mat"
,
docstring
=
""
):
...
...
@@ -393,8 +392,7 @@ class CppHeaderParser(object):
"""
if
self
.
wrap_mode
:
if
not
((
"CV_EXPORTS_AS"
in
decl_str
)
or
(
"CV_EXPORTS_W"
in
decl_str
)
or
\
(
"CV_WRAP"
in
decl_str
)
or
(
"CV_WRAP_AS"
in
decl_str
)):
if
not
((
"CV_EXPORTS_AS"
in
decl_str
)
or
(
"CV_EXPORTS_W"
in
decl_str
)
or
(
"CV_WRAP"
in
decl_str
)):
return
[]
# ignore old API in the documentation check (for now)
...
...
@@ -414,6 +412,16 @@ class CppHeaderParser(object):
arg
,
npos3
=
self
.
get_macro_arg
(
decl_str
,
npos
)
func_modlist
.
append
(
"="
+
arg
)
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
pure_virtual_method
=
False
...
...
@@ -527,8 +535,6 @@ class CppHeaderParser(object):
t
,
npos
=
self
.
find_next_token
(
decl_str
,
[
"("
,
")"
,
","
,
"<"
,
">"
],
npos
)
if
not
t
:
print
(
"Error: no closing ')' at
%
d"
%
(
self
.
lineno
,))
print
(
decl_str
)
print
(
decl_str
[
arg_start
:])
sys
.
exit
(
-
1
)
if
t
==
"<"
:
angle_balance
+=
1
...
...
@@ -705,20 +711,19 @@ class CppHeaderParser(object):
decl
[
1
]
=
": "
+
", "
.
join
([
self
.
get_dotted_name
(
b
)
.
replace
(
"."
,
"::"
)
for
b
in
bases
])
return
stmt_type
,
classname
,
True
,
decl
if
stmt
.
startswith
(
"enum"
):
return
"enum"
,
""
,
True
,
None
if
stmt
.
startswith
(
"namespace"
):
if
stmt
.
startswith
(
"enum"
)
or
stmt
.
startswith
(
"namespace"
):
stmt_list
=
stmt
.
split
()
if
len
(
stmt_list
)
<
2
:
stmt_list
.
append
(
"<unnamed>"
)
return
stmt_list
[
0
],
stmt_list
[
1
],
True
,
None
if
stmt
.
startswith
(
"extern"
)
and
"
\"
C
\"
"
in
stmt
:
return
"namespace"
,
""
,
True
,
None
if
end_token
==
"}"
and
context
==
"enum"
:
decl
=
self
.
parse_enum
(
stmt
)
return
"enum"
,
""
,
False
,
decl
name
=
stack_top
[
self
.
BLOCK_NAME
]
return
"enum"
,
name
,
False
,
decl
if
end_token
==
";"
and
stmt
.
startswith
(
"typedef"
):
# TODO: handle typedef's more intelligently
...
...
@@ -896,8 +901,9 @@ class CppHeaderParser(object):
stmt_type
,
name
,
parse_flag
,
decl
=
self
.
parse_stmt
(
stmt
,
token
,
docstring
=
docstring
)
if
decl
:
if
stmt_type
==
"enum"
:
for
d
in
decl
:
decls
.
append
(
d
)
if
name
!=
"<unnamed>"
:
decls
.
append
([
"enum "
+
self
.
get_dotted_name
(
name
),
""
,
[],
[],
None
,
""
])
decls
.
extend
(
decl
)
else
:
decls
.
append
(
decl
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment