diff --git a/modules/matlab/generator/filters.py b/modules/matlab/generator/filters.py index 9b0f7074f8..1d877b36ca 100644 --- a/modules/matlab/generator/filters.py +++ b/modules/matlab/generator/filters.py @@ -7,11 +7,10 @@ def inputs(args): In OpenCV input arguments are all arguments with names not beginning with 'dst' ''' - out = [] - for arg in args: - if not arg.name.startswith('dst'): - out.append(arg) - return out + try: + return [arg for arg in args['only'] if arg.I and not arg.O] + except: + return [arg for arg in args if arg.I] def ninputs(args): '''Counts the number of input arguments in the input list''' @@ -22,15 +21,24 @@ def outputs(args): reference, and returns a list of only those elements. In OpenCV, output references are preceeded by 'dst' ''' - out = [] - for arg in args: - if arg.name.startswith('dst'): - out.append(arg) - return out + try: + return [arg for arg in args['only'] if arg.O and not arg.I] + except: + return [arg for arg in args if arg.O] + +def only(args): + '''Returns exclusively the arguments which are only inputs + or only outputs''' + d = {}; + d['only'] = args + return d + +def void(arg): + return arg == 'void' + +def flip(arg): + return not arg -def output(arg): - return True if arg.name.startswith('dst') else False - def noutputs(args): '''Counts the number of output arguments in the input list''' return len(outputs(args)) diff --git a/modules/matlab/generator/gen_matlab.py b/modules/matlab/generator/gen_matlab.py index 3f2858e7a9..49c60d47db 100644 --- a/modules/matlab/generator/gen_matlab.py +++ b/modules/matlab/generator/gen_matlab.py @@ -32,10 +32,13 @@ class MatlabWrapperGenerator(object): jtemplate.filters['toUnderCase'] = toUnderCase jtemplate.filters['comment'] = comment jtemplate.filters['inputs'] = inputs + jtemplate.filters['ninputs'] = ninputs jtemplate.filters['outputs'] = outputs - jtemplate.filters['output'] = output jtemplate.filters['noutputs'] = noutputs - jtemplate.filters['ninputs'] = ninputs + jtemplate.filters['only'] = only + jtemplate.filters['void'] = void + jtemplate.filters['not'] = flip + # load the templates tfunction = jtemplate.get_template('template_function_base.cpp') diff --git a/modules/matlab/generator/parse_tree.py b/modules/matlab/generator/parse_tree.py index f922bd4d72..598fd17719 100644 --- a/modules/matlab/generator/parse_tree.py +++ b/modules/matlab/generator/parse_tree.py @@ -65,6 +65,7 @@ class Translator(object): name = self.translateName(defn[0]) clss = self.translateClassName(defn[0]) rtp = defn[1] + static = True if 'S' in ''.join(defn[2]) else False args = defn[3] req = [] opt = [] @@ -72,7 +73,7 @@ class Translator(object): if arg: a = self.translateArgument(arg) opt.append(a) if a.default else req.append(a) - return Function(name, clss, '', rtp, False, req, opt) + return Function(name, clss, static, '', rtp, False, req, opt) def translateConstant(self, defn): const = True if 'const' in defn[0] else False @@ -83,10 +84,16 @@ class Translator(object): return Constant(name, clss, tp, const, '', val) def translateArgument(self, defn): - tp = defn[0] + ref = '*' if '*' in defn[0] else '' + ref = '&' if '&' in defn[0] else ref + const = ' const ' in ' '+defn[0]+' ' + tp = " ".join([word for word in defn[0].replace(ref, '').split() if not ' const ' in ' '+word+' ']) name = defn[1] default = defn[2] if defn[2] else '' - return Argument(name, tp, False, '', default) + modifiers = ''.join(defn[3]) + I = True if not modifiers or 'I' in modifiers else False + O = True if 'O' in modifiers else False + return Argument(name, tp, const, I, O, ref, default) def translateName(self, name): return name.split(' ')[-1].split('.')[-1] @@ -123,9 +130,10 @@ class Class(object): (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): + def __init__(self, name='', clss='', static=False, namespace='', rtp='', const=False, req=None, opt=None): self.name = name self.clss = clss + self.static = static self.const = const self.namespace = namespace self.rtp = rtp @@ -138,10 +146,12 @@ class Function(object): ')'+(' const' if self.const else '')+';' class Argument(object): - def __init__(self, name='', tp='', const=False, ref='', default=''): + def __init__(self, name='', tp='', const=False, I=True, O=False, ref='', default=''): self.name = name self.tp = tp self.ref = ref + self.I = I + self.O = O self.const = const self.default = default diff --git a/modules/matlab/generator/templates/functional.cpp b/modules/matlab/generator/templates/functional.cpp index f928780ab1..143783358e 100644 --- a/modules/matlab/generator/templates/functional.cpp +++ b/modules/matlab/generator/templates/functional.cpp @@ -1,13 +1,24 @@ -// compose a function -{% macro compose(fun, retname="ret") %} - {%- if not fun.rtp == "void" -%} {{fun.rtp}} retname = {% endif -%} - {{fun.name}}( +/* + * compose + * compose a function call + * This macro takes as input a Function object and composes + * a function call by inspecting the types and argument names + */ +/ +{% macro compose(fun) %} + {# ----------- Return type ------------- #} + {%- if not fun.rtp|void -%} {{fun.rtp}} retval = {% endif -%} + cv::{{fun.name}}( + {#- ----------- Required ------------- -#} {%- for arg in fun.req -%} + {%- if arg.ref == '*' -%}&{%- endif -%} {{arg.name}} {%- if not loop.last %}, {% endif %} {% endfor %} + {#- ----------- Optional ------------- -#} {% if fun.req and fun.opt %}, {% endif %} {%- for opt in fun.opt -%} + {%- if opt.ref == '*' -%}&{%- endif -%} {{opt.name}} {%- if not loop.last -%}, {% endif %} {%- endfor -%} @@ -18,19 +29,18 @@ {%- macro generate(fun) -%} // unpack the arguments - // inputs + {# ----------- Inputs ------------- #} {% for arg in fun.req|inputs %} {{arg.tp}} {{arg.name}} = inputs[{{ loop.index0 }}]; {% endfor %} {% for opt in fun.opt|inputs %} - {{opt.tp}} {{opt.name}} = (nrhs > {{loop.index0 + fun.req|ninputs}}) ? inputs[{{loop.index0 + fun.req|ninputs}}] : {{opt.default}}; + {{opt.tp}} {{opt.name}} = (nrhs > {{loop.index0 + fun.req|inputs|length}}) ? inputs[{{loop.index0 + fun.req|inputs|length}}] : {{opt.default}}; {% endfor %} - - // outputs - {% for arg in fun.req|outputs %} + {# ----------- Outputs ------------ #} + {% for arg in fun.req|only|outputs %} {{arg.tp}} {{arg.name}}; {% endfor %} - {% for opt in fun.opt|outputs %} + {% for opt in fun.opt|only|outputs %} {{opt.tp}} {{opt.name}}; {% endfor %} @@ -47,11 +57,14 @@ } // assign the outputs into the bridge + {% if not fun.rtp|void %} + outputs[0] = retval; + {% endif %} {% for arg in fun.req|outputs %} - outputs[{{loop.index0}}] = {{arg.name}}; + outputs[{{loop.index0 + fun.rtp|void|not}}] = {{arg.name}}; {% endfor %} {% for opt in fun.opt|outputs %} - outputs[{{loop.index0 + fun.req|noutputs}}] = {{opt.name}}; + outputs[{{loop.index0 + fun.rtp|void|not + fun.req|outputs|length}}] = {{opt.name}}; {% endfor %} {%- endmacro -%} diff --git a/modules/matlab/generator/templates/template_function_base.cpp b/modules/matlab/generator/templates/template_function_base.cpp index b7fcc3195d..8ec5703f6a 100644 --- a/modules/matlab/generator/templates/template_function_base.cpp +++ b/modules/matlab/generator/templates/template_function_base.cpp @@ -13,14 +13,13 @@ #include #include #include -#include +#include {% block includes %} {% endblock %} -using namespace std; -using namespace cv; /* * {{ fun.name }} + * {{ fun }} * Gateway routine * nlhs - number of return arguments * plhs - pointers to return arguments @@ -31,15 +30,13 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { // assertions - mxAssert(nrhs >= {{fun.req|length - fun.req|noutputs}}, "Too few required input arguments specified"); - mxAssert(nrhs <= {{fun.req|length + fun.opt|length - fun.req|noutputs - fun.opt|noutputs}}, "Too many input arguments specified"); - mxAssert(nlhs <= {{fun.ret|length + fun.req|noutputs + fun.opt|noutputs}}, "Too many output arguments specified"); + mxAssert(nrhs >= {{fun.req|length - fun.req|outputs|length}}, "Too few required input arguments specified"); + mxAssert(nrhs <= {{fun.req|length + fun.opt|length - fun.req|outputs|length - fun.opt|outputs|length}}, "Too many input arguments specified"); + mxAssert(nlhs <= {{ fun.rtp|void|not + fun.req|outputs|length + fun.opt|outputs|length}}, "Too many output arguments specified"); // setup - vector inputs(plhs, plhs+nrhs); - vector outputs(nlhs); - - {{ fun }} + std::vector inputs(plhs, plhs+nrhs); + std::vector outputs(nlhs); {{ functional.generate(fun) }}