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
fb41d7bf
Commit
fb41d7bf
authored
Aug 11, 2013
by
hbristow
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Commenting spree no.2
parent
bfa88384
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
251 additions
and
4 deletions
+251
-4
build_info.py
modules/matlab/generator/build_info.py
+22
-2
filters.py
modules/matlab/generator/filters.py
+34
-0
gen_matlab.py
modules/matlab/generator/gen_matlab.py
+54
-2
parse_tree.py
modules/matlab/generator/parse_tree.py
+141
-0
No files found.
modules/matlab/generator/build_info.py
View file @
fb41d7bf
#/usr/bin/env python
#
!
/usr/bin/env python
def
substitute
(
build
,
output_dir
):
...
...
@@ -18,12 +18,32 @@ def substitute(build, output_dir):
if
not
os
.
path
.
isdir
(
output_dir
):
os
.
mkdir
(
output_dir
)
# populate template
s
# populate template
populated
=
template
.
render
(
build
=
build
)
with
open
(
os
.
path
.
join
(
output_dir
,
'buildInformation.m'
),
'wb'
)
as
f
:
f
.
write
(
populated
)
if
__name__
==
"__main__"
:
"""
Usage: python build_info.py --os os_version_string
--arch [bitness processor]
--compiler [id version]
--mex_arch arch_string
--mex_script /path/to/mex/script
--cxx_flags [-list -of -flags -to -passthrough]
--opencv_version version_string
--commit commit_hash_if_using_git
--modules [core imgproc highgui etc]
--configuration Debug/Release
--outdir /path/to/write/build/info
build_info.py generates a Matlab function that can be invoked with a call to
>> cv.buildInformation();
This function prints a summary of the user's OS, OpenCV and Matlab build
given the information passed to this module. build_info.py invokes Jinja2
on the template_build_info.m template.
"""
# parse the input options
import
sys
,
re
,
os
...
...
modules/matlab/generator/filters.py
View file @
fb41d7bf
from
textwrap
import
TextWrapper
from
string
import
split
,
join
import
re
,
os
# precompile a URL matching regular expression
urlexpr
=
re
.
compile
(
r"((https?):((//)|(\\\\))+[\w\d:#@
%
/;$()~_?\+-=\\\.&]*)"
,
re
.
MULTILINE
|
re
.
UNICODE
)
def
inputs
(
args
):
...
...
@@ -35,9 +36,11 @@ def only(args):
return
d
def
void
(
arg
):
'''Is the input 'void' '''
return
arg
==
'void'
def
flip
(
arg
):
'''flip the sign of the input'''
return
not
arg
def
noutputs
(
fun
):
...
...
@@ -45,6 +48,7 @@ def noutputs(fun):
return
int
(
not
void
(
fun
.
rtp
))
+
len
(
outputs
(
fun
.
req
))
+
len
(
outputs
(
fun
.
opt
))
def
convertibleToInt
(
string
):
'''Can the input string be evaluated to an integer?'''
salt
=
'1+'
try
:
exec
(
salt
+
string
)
...
...
@@ -53,12 +57,21 @@ def convertibleToInt(string):
return
False
def
binaryToDecimal
(
string
):
'''Attempt to convert the input string to floating point representation'''
try
:
return
str
(
eval
(
string
))
except
:
return
string
def
formatMatlabConstant
(
string
,
table
):
'''
Given a string representing a Constant, and a table of all Constants,
attempt to resolve the Constant into a valid Matlab expression
For example, the input
DEPENDENT_VALUE = 1 << FIXED_VALUE
needs to be converted to
DEPENDENT_VALUE = bitshift(1, cv.FIXED_VALUE);
'''
# split the string into expressions
words
=
re
.
split
(
'(
\
W+)'
,
string
)
# add a 'cv' prefix if an expression is also a key in the lookup table
...
...
@@ -76,20 +89,33 @@ def matlabURL(string):
return
re
.
sub
(
urlexpr
,
'<a href="matlab: web(
\'\\
1
\'
,
\'
-browser
\'
)">
\\
1</a>'
,
string
)
def
capitalizeFirst
(
text
):
'''Capitalize only the first character of the text string'''
return
text
[
0
]
.
upper
()
+
text
[
1
:]
def
toUpperCamelCase
(
text
):
'''variable_name --> VariableName'''
return
''
.
join
([
capitalizeFirst
(
word
)
for
word
in
text
.
split
(
'_'
)])
def
toLowerCamelCase
(
text
):
'''variable_name --> variableName'''
upper_camel
=
toUpperCamelCase
(
test
)
return
upper_camel
[
0
]
.
lower
()
+
upper_camel
[
1
:]
def
toUnderCase
(
text
):
'''VariableName --> variable_name'''
s1
=
re
.
sub
(
'(.)([A-Z][a-z]+)'
,
r'\1_\2'
,
text
)
return
re
.
sub
(
'([a-z0-9])([A-Z])'
,
r'\1_\2'
,
s1
)
.
lower
()
def
stripTags
(
text
):
'''
strip or convert html tags from a text string
<code>content</code> --> content
<anything> --> ''
< --> <
> --> >
&le --> <=
&ge --> >=
'''
upper
=
lambda
pattern
:
pattern
.
group
(
1
)
.
upper
()
text
=
re
.
sub
(
'<code>(.*?)</code>'
,
upper
,
text
)
text
=
re
.
sub
(
'<([^=
\
s].*?)>'
,
''
,
text
)
...
...
@@ -100,18 +126,26 @@ def stripTags(text):
return
text
def
qualify
(
text
,
name
):
'''Adds uppercase 'CV.' qualification to any occurrences of name in text'''
return
re
.
sub
(
name
.
upper
(),
'CV.'
+
name
.
upper
(),
text
)
def
slugify
(
text
):
'''A_Function_name --> a-function-name'''
return
text
.
lower
()
.
replace
(
'_'
,
'-'
)
def
filename
(
fullpath
):
'''Returns only the filename without an extension from a file path
eg. /path/to/file.txt --> file
'''
return
os
.
path
.
splitext
(
os
.
path
.
basename
(
fullpath
))[
0
]
def
csv
(
items
,
sep
=
', '
):
'''format a list with a separator (comma if not specified)'''
return
sep
.
join
(
item
for
item
in
items
)
def
stripExtraSpaces
(
text
):
'''Removes superfluous whitespace from a string, including the removal
of all leading and trailing whitespace'''
return
' '
.
join
(
text
.
split
())
def
comment
(
text
,
wrap
=
80
,
escape
=
'
%
'
,
escape_first
=
''
,
escape_last
=
''
):
...
...
modules/matlab/generator/gen_matlab.py
View file @
fb41d7bf
#/usr/bin/env python
#
!
/usr/bin/env python
class
MatlabWrapperGenerator
(
object
):
"""
MatlabWrapperGenerator is a class for generating Matlab mex sources from
a set of C++ headers. MatlabWrapperGenerator objects can be default
constructed. Given an instance, the gen() method performs the translation.
"""
def
gen
(
self
,
module_root
,
modules
,
extras
,
output_dir
):
"""
Generate a set of Matlab mex source files by parsing exported symbols
in a set of C++ headers. The headers can be input in one (or both) of
two methods:
1. specify module_root and modules
Given a path to the OpenCV module root and a list of module names,
the headers to parse are implicitly constructed.
2. specifiy header locations explicitly in extras
Each element in the list of extras must be of the form:
'namespace=/full/path/to/extra/header.hpp' where 'namespace' is
the namespace in which the definitions should be added.
The output_dir specifies the directory to write the generated sources
to.
"""
# parse each of the files and store in a dictionary
# as a separate "namespace"
parser
=
CppHeaderParser
()
...
...
@@ -109,8 +128,41 @@ class MatlabWrapperGenerator(object):
f
.
write
(
populated
)
if
__name__
==
"__main__"
:
"""
Usage: python gen_matlab.py --hdrparser /path/to/hdr_parser/dir
--rstparser /path/to/rst_parser/dir
--moduleroot /path/to/opencv/modules
--modules [core imgproc objdetect etc]
--extra namespace=/path/to/extra/header.hpp
--outdir /path/to/output/generated/srcs
gen_matlab.py is the main control script for generating matlab source
files from given set of headers. Internally, gen_matlab:
1. constructs the headers to parse from the module root and list of modules
2. parses the headers using CppHeaderParser
3. refactors the definitions using ParseTree
4. parses .rst docs using RstParser
5. populates the templates for classes, function, enums and docs from the
definitions
gen_matlab.py requires the following inputs:
--hdrparser the path to the header parser directory
(opencv/modules/python/src2)
--rstparser the path to the rst parser directory
(opencv/modules/java/generator)
--moduleroot (optional) path to the opencv directory containing the modules
--modules (optional - required if --moduleroot specified) the modules
to produce bindings for. The path to the include directories
as well as the namespaces are constructed from the modules
and the moduleroot
--extra extra headers explicitly defined to parse. This must be in
the format "namepsace=/path/to/extra/header.hpp". For example,
the core module requires the extra header:
"core=/opencv/modules/core/include/opencv2/core/core/base.hpp"
--outdir the output directory to put the generated matlab sources. In
the OpenCV build this is "${CMAKE_CURRENT_BUILD_DIR}/src"
"""
# parse the input options
import
sys
,
re
,
os
,
time
...
...
modules/matlab/generator/parse_tree.py
View file @
fb41d7bf
...
...
@@ -3,6 +3,73 @@ from textwrap import fill
from
filters
import
*
class
ParseTree
(
object
):
"""
The ParseTree class produces a semantic tree of C++ definitions given
the output of the CppHeaderParser (from opencv/modules/python/src2/hdr_parser.py)
The full hierarchy is as follows:
Namespaces
|
|- name
|- Classes
|
|- name
|- Methods
|- Constants
|- Methods
|
|- name
|- static (T/F)
|- return type
|- required Arguments
|
|- name
|- const (T/F)
|- reference ('&'/'*')
|- type
|- input
|- output (pass return by reference)
|- default value
|- optional Arguments
|- Constants
|
|- name
|- const (T/F)
|- reference ('&'/'*')
|- type
|- value
The semantic tree contains substantial information for easily introspecting
information about objects. How many methods does the 'core' namespace have?
Does the 'randn' method have any return by reference (output) arguments?
How many required and optional arguments does the 'add' method have? Is the
variable passed by reference or raw pointer?
Individual definitions from the parse tree (Classes, Functions, Constants)
are passed to the Jinja2 template engine where they are manipulated to
produce Matlab mex sources.
A common call tree for constructing and using a ParseTree object is:
# parse a set of definitions into a dictionary of namespaces
parser = CppHeaderParser()
ns['core'] = parser.parse('path/to/opencv/core.hpp')
# refactor into a semantic tree
parse_tree = ParseTree()
parse_tree.build(ns)
# iterate over the tree
for namespace in parse_tree.namespaces:
for clss in namespace.classes:
# do stuff
for method in namespace.methods:
# do stuff
Calling 'print' on a ParseTree object will reconstruct the definitions
to produce an output resembling the original C++ code.
"""
def
__init__
(
self
,
namespaces
=
None
):
self
.
namespaces
=
namespaces
if
namespaces
else
[]
...
...
@@ -48,6 +115,15 @@ class ParseTree(object):
class
Translator
(
object
):
"""
The Translator class does the heavy lifting of translating the nested
list representation of the hdr_parser into individual definitions that
are inserted into the ParseTree.
Translator consists of a top-level method: translate()
along with a number of helper methods: translateClass(), translateMethod(),
translateArgument(), translateConstant(), translateName(), and
translateClassName()
"""
def
translate
(
self
,
defn
):
# --- class ---
# classes have 'class' prefixed on their name
...
...
@@ -116,6 +192,14 @@ class Translator(object):
class
Namespace
(
object
):
"""
Namespace
|
|- name
|- Constants
|- Methods
|- Constants
"""
def
__init__
(
self
,
name
=
''
,
constants
=
None
,
classes
=
None
,
methods
=
None
):
self
.
name
=
name
self
.
constants
=
constants
if
constants
else
[]
...
...
@@ -129,6 +213,13 @@ class Namespace(object):
(
join
((
o
.
__str__
()
for
o
in
self
.
classes
),
'
\n\n
'
)
if
self
.
classes
else
''
)
+
'
\n
};'
class
Class
(
object
):
"""
Class
|
|- name
|- Methods
|- Constants
"""
def
__init__
(
self
,
name
=
''
,
namespace
=
''
,
constants
=
None
,
methods
=
None
):
self
.
name
=
name
self
.
namespace
=
namespace
...
...
@@ -141,6 +232,21 @@ class Class(object):
(
join
((
f
.
__str__
()
for
f
in
self
.
methods
),
'
\n\t
'
)
if
self
.
methods
else
''
)
+
'
\n
};'
class
Method
(
object
):
"""
Method
int VideoWriter::read( cv::Mat& frame, const cv::Mat& mask=cv::Mat() );
--- ----- ---- -------- ----------------
rtp class name required optional
name the method name
clss the class the method belongs to ('' if free)
static static?
namespace the namespace the method belongs to ('' if free)
rtp the return type
const const?
req list of required arguments
opt list of optional arguments
"""
def
__init__
(
self
,
name
=
''
,
clss
=
''
,
static
=
False
,
namespace
=
''
,
rtp
=
''
,
const
=
False
,
req
=
None
,
opt
=
None
):
self
.
name
=
name
self
.
clss
=
clss
...
...
@@ -158,6 +264,20 @@ class Method(object):
')'
+
(
' const'
if
self
.
const
else
''
)
+
';'
class
Argument
(
object
):
"""
Argument
const cv::Mat& mask=cv::Mat()
----- ---- --- ---- -------
const tp ref name default
name the argument name
tp the argument type
const const?
I is the argument treated as an input?
O is the argument treated as an output (return by reference)
ref is the argument passed by reference? ('*'/'&')
default the default value of the argument ('' if required)
"""
def
__init__
(
self
,
name
=
''
,
tp
=
''
,
const
=
False
,
I
=
True
,
O
=
False
,
ref
=
''
,
default
=
''
):
self
.
name
=
name
self
.
tp
=
tp
...
...
@@ -172,6 +292,19 @@ class Argument(object):
' '
+
self
.
name
+
(
'='
+
self
.
default
if
self
.
default
else
''
)
class
Constant
(
object
):
"""
Constant
DFT_COMPLEX_OUTPUT = 12;
---- -------
name default
name the name of the constant
clss the class that the constant belongs to ('' if free)
tp the type of the constant ('' if int)
const const?
ref is the constant a reference? ('*'/'&')
default default value, required for constants
"""
def
__init__
(
self
,
name
=
''
,
clss
=
''
,
tp
=
''
,
const
=
False
,
ref
=
''
,
default
=
''
):
self
.
name
=
name
self
.
clss
=
clss
...
...
@@ -185,6 +318,10 @@ class Constant(object):
' '
+
self
.
name
+
(
'='
+
self
.
default
if
self
.
default
else
''
)
+
';'
def
constants
(
tree
):
"""
recursive generator to strip all Constant objects from the ParseTree
and place them into a flat dictionary of { name, value (default) }
"""
if
isinstance
(
tree
,
dict
)
and
'constants'
in
tree
and
isinstance
(
tree
[
'constants'
],
list
):
for
node
in
tree
[
'constants'
]:
yield
(
node
[
'name'
],
node
[
'default'
])
...
...
@@ -198,6 +335,10 @@ def constants(tree):
yield
gen
def
todict
(
obj
,
classkey
=
None
):
"""
Convert the ParseTree to a dictionary, stripping all objects of their
methods and converting class names to strings
"""
if
isinstance
(
obj
,
dict
):
for
k
in
obj
.
keys
():
obj
[
k
]
=
todict
(
obj
[
k
],
classkey
)
...
...
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