mirror of
https://github.com/opencv/opencv.git
synced 2025-06-11 03:33:28 +08:00
Improved parse tree, now building within main opencv build system
This commit is contained in:
parent
5d1944bace
commit
808f9dbc93
@ -2,8 +2,8 @@
|
|||||||
# CMake file for Matlab/Octave support
|
# CMake file for Matlab/Octave support
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
# make sure we're on a supported architecture with Matlab installed
|
# make sure we're on a supported architecture with Matlab and python installed
|
||||||
if (IOS OR ANDROID OR NOT MATLAB_FOUND)
|
if (IOS OR ANDROID OR NOT MATLAB_FOUND OR NOT PYTHONLIBS_FOUND)
|
||||||
ocv_module_disable(matlab)
|
ocv_module_disable(matlab)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -13,4 +13,43 @@ ocv_add_module(matlab BINDINGS opencv_core opencv_imgproc
|
|||||||
opencv_highgui opencv_ml opencv_calib3d opencv_photo
|
opencv_highgui opencv_ml opencv_calib3d opencv_photo
|
||||||
opencv_nonfree opencv_calib)
|
opencv_nonfree opencv_calib)
|
||||||
|
|
||||||
add_subdirectory(test)
|
# Add all of the headers we wish to parse
|
||||||
|
set(opencv_hdrs
|
||||||
|
"${OPENCV_MODULE_opencv_core_LOCATION}/include/opencv2/core/core.hpp"
|
||||||
|
"${OPENCV_MODULE_opencv_flann_LOCATION}/include/opencv2/flann/miniflann.hpp"
|
||||||
|
"${OPENCV_MODULE_opencv_imgproc_LOCATION}/include/opencv2/imgproc/imgproc.hpp"
|
||||||
|
"${OPENCV_MODULE_opencv_video_LOCATION}/include/opencv2/video/background_segm.hpp"
|
||||||
|
"${OPENCV_MODULE_opencv_video_LOCATION}/include/opencv2/video/tracking.hpp"
|
||||||
|
"${OPENCV_MODULE_opencv_photo_LOCATION}/include/opencv2/photo/photo.hpp"
|
||||||
|
"${OPENCV_MODULE_opencv_highgui_LOCATION}/include/opencv2/highgui/highgui.hpp"
|
||||||
|
"${OPENCV_MODULE_opencv_ml_LOCATION}/include/opencv2/ml/ml.hpp"
|
||||||
|
"${OPENCV_MODULE_opencv_features2d_LOCATION}/include/opencv2/features2d/features2d.hpp"
|
||||||
|
"${OPENCV_MODULE_opencv_calib3d_LOCATION}/include/opencv2/calib3d/calib3d.hpp"
|
||||||
|
"${OPENCV_MODULE_opencv_objdetect_LOCATION}/include/opencv2/objdetect/objdetect.hpp"
|
||||||
|
"${OPENCV_MODULE_opencv_softcascade_LOCATION}/include/opencv2/softcascade/softcascade.hpp"
|
||||||
|
"${OPENCV_MODULE_opencv_contrib_LOCATION}/include/opencv2/contrib/contrib.hpp")
|
||||||
|
|
||||||
|
if(HAVE_opencv_nonfree)
|
||||||
|
list(APPEND opencv_hdrs "${OPENCV_MODULE_opencv_nonfree_LOCATION}/include/opencv2/nonfree/features2d.hpp"
|
||||||
|
"${OPENCV_MODULE_opencv_nonfree_LOCATION}/include/opencv2/nonfree/nonfree.hpp")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# add the python generator to the python path
|
||||||
|
set(PYPATH_CACHE $ENV{PYTHONPATH})
|
||||||
|
set(ENV{PYTHONPATH} ${OPENCV_MODULE_opencv_python_LOCATION}/src2 $ENV{PYTHONPATH})
|
||||||
|
|
||||||
|
# synthesise the matlab sources
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/generator/gen_matlab_caller.py
|
||||||
|
${opencv_hdrs} ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||||
|
|
||||||
|
# compile the matlab sources
|
||||||
|
file(GLOB SOURCE_FILES ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||||
|
foreach(SOURCE_FILE ${SOURCE_FILES})
|
||||||
|
# compile the source file using mex
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# restore the pythonpath
|
||||||
|
set(ENV{PYTHONPATH} ${PYPATH_CACHE})
|
||||||
|
@ -2,6 +2,18 @@ from textwrap import TextWrapper
|
|||||||
from string import split, join
|
from string import split, join
|
||||||
|
|
||||||
def comment(text, wrap=80, escape='% ', escape_first='', escape_last=''):
|
def comment(text, wrap=80, escape='% ', escape_first='', escape_last=''):
|
||||||
|
'''comment filter
|
||||||
|
Takes a string in text, and wraps it to wrap characters in length with
|
||||||
|
preceding comment escape sequence on each line. escape_first and
|
||||||
|
escape_last can be used for languages which define block comments.
|
||||||
|
Examples:
|
||||||
|
C++ inline comment comment(80, '// ')
|
||||||
|
C block comment: comment(80, ' * ', '/*', ' */')
|
||||||
|
Matlab comment: comment(80, '% ')
|
||||||
|
Matlab block comment: comment(80, '', '%{', '%}')
|
||||||
|
Python docstrings: comment(80, '', '\'\'\'', '\'\'\'')
|
||||||
|
'''
|
||||||
|
|
||||||
tw = TextWrapper(width=wrap-len(escape))
|
tw = TextWrapper(width=wrap-len(escape))
|
||||||
if escape_first:
|
if escape_first:
|
||||||
escape_first = escape_first+'\n'
|
escape_first = escape_first+'\n'
|
||||||
|
@ -2,3 +2,23 @@
|
|||||||
|
|
||||||
import sys, re, os.path
|
import sys, re, os.path
|
||||||
from string import Template
|
from string import Template
|
||||||
|
from hdr_parser import CppHeaderParser
|
||||||
|
from parse_tree import ParseTree, todict
|
||||||
|
|
||||||
|
class MatlabWrapperGenerator(object):
|
||||||
|
|
||||||
|
def gen(self, input_files, output_files):
|
||||||
|
# parse each of the files and store in a dictionary
|
||||||
|
# as a separate "namespace"
|
||||||
|
parser = CppHeaderParser()
|
||||||
|
ns = {}
|
||||||
|
for file in input_files:
|
||||||
|
# get the file name
|
||||||
|
name = os.path.splitext(os.path.basename(file))[0]
|
||||||
|
ns[name] = parser.parse(file)
|
||||||
|
|
||||||
|
# cleanify the parser output
|
||||||
|
parse_tree = ParseTree()
|
||||||
|
parse_tree.build(ns)
|
||||||
|
|
||||||
|
print parse_tree
|
||||||
|
12
modules/matlab/generator/gen_matlab_caller.py
Normal file
12
modules/matlab/generator/gen_matlab_caller.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#/usr/bin/env python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from gen_matlab import MatlabWrapperGenerator
|
||||||
|
|
||||||
|
# get the IO from the command line arguments
|
||||||
|
input_files = sys.argv[1:-1]
|
||||||
|
output_dir = sys.argv[-1]
|
||||||
|
|
||||||
|
# create the generator
|
||||||
|
mwg = MatlabWrapperGenerator()
|
||||||
|
mwg.gen(input_files, output_dir)
|
182
modules/matlab/generator/parse_tree.py
Normal file
182
modules/matlab/generator/parse_tree.py
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
from string import join
|
||||||
|
from textwrap import fill
|
||||||
|
|
||||||
|
class ParseTree(object):
|
||||||
|
def __init__(self, namespaces=[]):
|
||||||
|
self.namespaces = namespaces
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return join((ns.__str__() for ns in self.namespaces), '\n\n\n')
|
||||||
|
|
||||||
|
def build(self, namespaces):
|
||||||
|
babel = Translator()
|
||||||
|
for name, definitions in namespaces.items():
|
||||||
|
class_tree = {}
|
||||||
|
functions = []
|
||||||
|
constants = []
|
||||||
|
for defn in definitions:
|
||||||
|
obj = babel.translate(defn)
|
||||||
|
if type(obj) is Class or obj.clss:
|
||||||
|
self.insertIntoClassTree(obj, class_tree)
|
||||||
|
elif type(obj) is Function:
|
||||||
|
functions.append(obj)
|
||||||
|
elif type(obj) is Constant:
|
||||||
|
constants.append(obj)
|
||||||
|
else:
|
||||||
|
raise TypeError('Unexpected object type: '+str(type(obj)))
|
||||||
|
self.namespaces.append(Namespace(name, class_tree.values(), functions, constants))
|
||||||
|
|
||||||
|
def insertIntoClassTree(self, obj, class_tree):
|
||||||
|
cname = obj.name if type(obj) is Class else obj.clss
|
||||||
|
if not cname:
|
||||||
|
return
|
||||||
|
if not cname in class_tree:
|
||||||
|
# add a new class to the tree
|
||||||
|
class_tree[cname] = Class(cname)
|
||||||
|
# insert the definition into the class
|
||||||
|
val = class_tree[cname]
|
||||||
|
if type(obj) is Function:
|
||||||
|
val.functions.append(obj)
|
||||||
|
elif type(obj) is Constant:
|
||||||
|
val.constants.append(obj)
|
||||||
|
else:
|
||||||
|
raise TypeError('Unexpected object type: '+str(type(obj)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Translator(object):
|
||||||
|
def translate(self, defn):
|
||||||
|
# --- class ---
|
||||||
|
# classes have 'class' prefixed on their name
|
||||||
|
if 'class' in defn[0]:
|
||||||
|
return self.translateClass(defn)
|
||||||
|
# --- function ---
|
||||||
|
# functions either need to have input arguments, or not uppercase names
|
||||||
|
elif defn[3] or not self.translateName(defn[0]).isupper():
|
||||||
|
return self.translateFunction(defn)
|
||||||
|
# --- constant ---
|
||||||
|
else:
|
||||||
|
return self.translateConstant(defn)
|
||||||
|
|
||||||
|
def translateClass(self, defn):
|
||||||
|
return Class()
|
||||||
|
|
||||||
|
def translateFunction(self, defn, class_tree=None):
|
||||||
|
name = self.translateName(defn[0])
|
||||||
|
clss = self.translateClassName(defn[0])
|
||||||
|
rtp = defn[1]
|
||||||
|
args = defn[3]
|
||||||
|
req = []
|
||||||
|
opt = []
|
||||||
|
for arg in args:
|
||||||
|
if arg:
|
||||||
|
a = self.translateArgument(arg)
|
||||||
|
opt.append(a) if a.default else req.append(a)
|
||||||
|
return Function(name, clss, '', rtp, False, req, opt)
|
||||||
|
|
||||||
|
def translateConstant(self, defn):
|
||||||
|
const = True if 'const' in defn[0] else False
|
||||||
|
name = self.translateName(defn[0])
|
||||||
|
clss = self.translateClassName(defn[0])
|
||||||
|
tp = 'int'
|
||||||
|
val = defn[1]
|
||||||
|
return Constant(name, clss, tp, const, '', val)
|
||||||
|
|
||||||
|
def translateArgument(self, defn):
|
||||||
|
tp = defn[0]
|
||||||
|
name = defn[1]
|
||||||
|
default = tp+'()' if defn[2] else ''
|
||||||
|
return Argument(name, tp, False, '', default)
|
||||||
|
|
||||||
|
def translateName(self, name):
|
||||||
|
return name.split(' ')[-1].split('.')[-1]
|
||||||
|
|
||||||
|
def translateClassName(self, name):
|
||||||
|
parts = name.split('.')
|
||||||
|
return parts[1] if len(parts) == 3 else ''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Namespace(object):
|
||||||
|
def __init__(self, name='', constants=None, classes=None, functions=None):
|
||||||
|
self.name = name
|
||||||
|
self.constants = constants if constants else []
|
||||||
|
self.classes = classes if classes else []
|
||||||
|
self.functions = functions if functions else []
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'namespace '+self.name+' {\n\n'+\
|
||||||
|
(join((c.__str__() for c in self.constants), '\n')+'\n\n' if self.constants else '')+\
|
||||||
|
(join((f.__str__() for f in self.functions), '\n')+'\n\n' if self.functions else '')+\
|
||||||
|
(join((c.__str__() for c in self.classes), '\n\n') if self.classes else '')+'\n};'
|
||||||
|
|
||||||
|
class Class(object):
|
||||||
|
def __init__(self, name='', namespace='', constants=None, functions=None):
|
||||||
|
self.name = name
|
||||||
|
self.namespace = namespace
|
||||||
|
self.constants = constants if constants else []
|
||||||
|
self.functions = functions if functions else []
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'class '+self.name+' {\n\t'+\
|
||||||
|
(join((c.__str__() for c in self.constants), '\n\t')+'\n\n\t' if self.constants else '')+\
|
||||||
|
(join((f.__str__() for f in self.functions), '\n\t') if self.functions else '')+'\n};'
|
||||||
|
|
||||||
|
class Function(object):
|
||||||
|
def __init__(self, name='', clss='', namespace='', rtp='', const=False, req=None, opt=None):
|
||||||
|
self.name = name
|
||||||
|
self.clss = clss
|
||||||
|
self.const = const
|
||||||
|
self.namespace = namespace
|
||||||
|
self.rtp = rtp
|
||||||
|
self.req = req if req else []
|
||||||
|
self.opt = opt if opt else []
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return fill((self.rtp+' ' if self.rtp else '')+(self.clss+'::' if self.clss else '')+self.name+'('+\
|
||||||
|
join((arg.__str__() for arg in self.req+self.opt), ', ')+\
|
||||||
|
')'+(' const' if self.const else '')+';', 80, subsequent_indent=('\t\t' if self.clss else '\t'))
|
||||||
|
|
||||||
|
class Argument(object):
|
||||||
|
def __init__(self, name='', tp='', const=False, ref='', default=''):
|
||||||
|
self.name = name
|
||||||
|
self.tp = tp
|
||||||
|
self.ref = ref
|
||||||
|
self.const = const
|
||||||
|
self.default = default
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ('const ' if self.const else '')+self.tp+self.ref+\
|
||||||
|
' '+self.name+('='+self.default if self.default else '')
|
||||||
|
|
||||||
|
class Constant(object):
|
||||||
|
def __init__(self, name='', clss='', tp='', const=False, ref='', default=''):
|
||||||
|
self.name = name
|
||||||
|
self.clss = clss
|
||||||
|
self.tp = tp
|
||||||
|
self.ref = ref
|
||||||
|
self.const = const
|
||||||
|
self.default = default
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ('const ' if self.const else '')+self.tp+self.ref+\
|
||||||
|
' '+self.name+('='+self.default if self.default else '')+';'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def todict(obj, classkey=None):
|
||||||
|
if isinstance(obj, dict):
|
||||||
|
for k in obj.keys():
|
||||||
|
obj[k] = todict(obj[k], classkey)
|
||||||
|
return obj
|
||||||
|
elif hasattr(obj, "__iter__"):
|
||||||
|
return [todict(v, classkey) for v in obj]
|
||||||
|
elif hasattr(obj, "__dict__"):
|
||||||
|
data = dict([(key, todict(value, classkey))
|
||||||
|
for key, value in obj.__dict__.iteritems()
|
||||||
|
if not callable(value) and not key.startswith('_')])
|
||||||
|
if classkey is not None and hasattr(obj, "__class__"):
|
||||||
|
data[classkey] = obj.__class__.__name__
|
||||||
|
return data
|
||||||
|
else:
|
||||||
|
return obj
|
Loading…
Reference in New Issue
Block a user