mirror of
https://github.com/opencv/opencv.git
synced 2024-11-25 03:30:34 +08:00
Merge pull request #19156 from vpisarev:named_args1
This commit is contained in:
commit
71be47e04a
@ -445,6 +445,7 @@ Cv64suf;
|
||||
#define CV_EXPORTS_W_SIMPLE CV_EXPORTS
|
||||
#define CV_EXPORTS_AS(synonym) CV_EXPORTS
|
||||
#define CV_EXPORTS_W_MAP CV_EXPORTS
|
||||
#define CV_EXPORTS_W_PARAMS CV_EXPORTS
|
||||
#define CV_IN_OUT
|
||||
#define CV_OUT
|
||||
#define CV_PROP
|
||||
|
@ -1508,6 +1508,21 @@ CV_EXPORTS_W void filter2D( InputArray src, OutputArray dst, int ddepth,
|
||||
InputArray kernel, Point anchor = Point(-1,-1),
|
||||
double delta = 0, int borderType = BORDER_DEFAULT );
|
||||
|
||||
class CV_EXPORTS_W_PARAMS Filter2DParams
|
||||
{
|
||||
public:
|
||||
CV_PROP_RW int anchorX = -1;
|
||||
CV_PROP_RW int anchorY = -1;
|
||||
CV_PROP_RW int borderType = BORDER_DEFAULT;
|
||||
CV_PROP_RW Scalar borderValue = Scalar();
|
||||
CV_PROP_RW int ddepth = -1;
|
||||
CV_PROP_RW double scale = 1.;
|
||||
CV_PROP_RW double shift = 0.;
|
||||
};
|
||||
|
||||
CV_EXPORTS_AS(filter2Dp) void filter2D( InputArray src, OutputArray dst, InputArray kernel,
|
||||
const Filter2DParams& params=Filter2DParams());
|
||||
|
||||
/** @brief Applies a separable linear filter to an image.
|
||||
|
||||
The function applies a separable linear filter to the image. That is, first, every row of src is
|
||||
|
@ -1555,6 +1555,22 @@ void filter2D(InputArray _src, OutputArray _dst, int ddepth,
|
||||
delta, borderType, src.isSubmatrix());
|
||||
}
|
||||
|
||||
void filter2D( InputArray src, OutputArray dst, InputArray kernel,
|
||||
const Filter2DParams& params)
|
||||
{
|
||||
Mat K = kernel.getMat(), tempK;
|
||||
if (params.scale != 1) {
|
||||
int kdepth = K.depth();
|
||||
K.convertTo(tempK,
|
||||
kdepth == CV_32F || kdepth == CV_64F ? kdepth : CV_32F,
|
||||
params.scale, 0);
|
||||
K = tempK;
|
||||
}
|
||||
CV_Assert(params.borderValue == Scalar());
|
||||
filter2D(src, dst, params.ddepth, K, Point(params.anchorX, params.anchorY),
|
||||
params.shift, params.borderType);
|
||||
}
|
||||
|
||||
void sepFilter2D(InputArray _src, OutputArray _dst, int ddepth,
|
||||
InputArray _kernelX, InputArray _kernelY, Point anchor,
|
||||
double delta, int borderType)
|
||||
|
@ -221,6 +221,7 @@ class ClassProp(object):
|
||||
def __init__(self, decl):
|
||||
self.tp = decl[0].replace("*", "_ptr")
|
||||
self.name = decl[1]
|
||||
self.defval = decl[2]
|
||||
self.readonly = True
|
||||
if "/RW" in decl[3]:
|
||||
self.readonly = False
|
||||
@ -233,6 +234,7 @@ class ClassInfo(object):
|
||||
self.ismap = False
|
||||
self.issimple = False
|
||||
self.isalgorithm = False
|
||||
self.isparams = False
|
||||
self.methods = {}
|
||||
self.props = []
|
||||
self.mappables = []
|
||||
@ -264,6 +266,8 @@ class ClassInfo(object):
|
||||
self.ismap = True
|
||||
elif m == "/Simple":
|
||||
self.issimple = True
|
||||
elif m == "/Params":
|
||||
self.isparams = True
|
||||
self.props = [ClassProp(p) for p in decl[3]]
|
||||
|
||||
if not customname and self.wname.startswith("Cv"):
|
||||
@ -352,6 +356,18 @@ def handle_ptr(tp):
|
||||
return tp
|
||||
|
||||
|
||||
def get_named_params_info(all_classes, args):
|
||||
extra_named_params = []
|
||||
params_arg_name = ""
|
||||
if args:
|
||||
last_arg = args[-1]
|
||||
if ("Params" in last_arg.tp) and (last_arg.tp in all_classes):
|
||||
arg_classinfo = all_classes[last_arg.tp]
|
||||
if arg_classinfo.isparams:
|
||||
params_arg_name = last_arg.name
|
||||
extra_named_params = arg_classinfo.props
|
||||
return (params_arg_name, extra_named_params)
|
||||
|
||||
class ArgInfo(object):
|
||||
def __init__(self, arg_tuple):
|
||||
self.tp = handle_ptr(arg_tuple[0])
|
||||
@ -392,7 +408,7 @@ class ArgInfo(object):
|
||||
|
||||
|
||||
class FuncVariant(object):
|
||||
def __init__(self, classname, name, decl, isconstructor, isphantom=False):
|
||||
def __init__(self, all_classes, classname, name, decl, isconstructor, isphantom=False):
|
||||
self.classname = classname
|
||||
self.name = self.wname = name
|
||||
self.isconstructor = isconstructor
|
||||
@ -415,9 +431,9 @@ class FuncVariant(object):
|
||||
else:
|
||||
self.array_counters[c] = [ainfo.name]
|
||||
self.args.append(ainfo)
|
||||
self.init_pyproto()
|
||||
self.init_pyproto(all_classes)
|
||||
|
||||
def init_pyproto(self):
|
||||
def init_pyproto(self, all_classes):
|
||||
# string representation of argument list, with '[', ']' symbols denoting optional arguments, e.g.
|
||||
# "src1, src2[, dst[, mask]]" for cv.add
|
||||
argstr = ""
|
||||
@ -430,6 +446,7 @@ class FuncVariant(object):
|
||||
# become the first optional input parameters of the Python function, and thus they are placed right after
|
||||
# non-optional input parameters)
|
||||
arglist = []
|
||||
proto_arglist = []
|
||||
|
||||
# the list of "heavy" output parameters. Heavy parameters are the parameters
|
||||
# that can be expensive to allocate each time, such as vectors and matrices (see isbig).
|
||||
@ -456,25 +473,39 @@ class FuncVariant(object):
|
||||
continue
|
||||
if not a.defval:
|
||||
arglist.append((a.name, argno))
|
||||
proto_arglist.append((a.name, argno))
|
||||
else:
|
||||
firstoptarg = min(firstoptarg, len(arglist))
|
||||
# if there are some array output parameters before the first default parameter, they
|
||||
# are added as optional parameters before the first optional parameter
|
||||
if outarr_list:
|
||||
arglist += outarr_list
|
||||
proto_arglist += [(aname_+"=None",argno_) for (aname_, argno_) in outarr_list]
|
||||
outarr_list = []
|
||||
arglist.append((a.name, argno))
|
||||
proto_arglist.append((a.name+"="+a.defval, argno))
|
||||
|
||||
# exclude "params" from Python func parameters ==>
|
||||
params_arg_name, extra_named_params = get_named_params_info(all_classes, self.args)
|
||||
if params_arg_name:
|
||||
arglist = arglist[:-1]
|
||||
proto_arglist = proto_arglist[:-1]
|
||||
|
||||
if outarr_list:
|
||||
firstoptarg = min(firstoptarg, len(arglist))
|
||||
proto_arglist += [(aname+"=None",argno) for (aname, argno) in outarr_list]
|
||||
arglist += outarr_list
|
||||
|
||||
firstoptarg = min(firstoptarg, len(arglist))
|
||||
|
||||
noptargs = len(arglist) - firstoptarg
|
||||
argnamelist = [aname for aname, argno in arglist]
|
||||
argnamelist = [aname for aname, argno in proto_arglist]
|
||||
noptargs = len(argnamelist) - firstoptarg
|
||||
if params_arg_name:
|
||||
# ==> instead, add the individual parameters one by one
|
||||
argnamelist += ["%s=%s" % (a.name, a.defval) for a in extra_named_params]
|
||||
argstr = ", ".join(argnamelist[:firstoptarg])
|
||||
argstr = "[, ".join([argstr] + argnamelist[firstoptarg:])
|
||||
argstr += "]" * noptargs
|
||||
argstr += "[, " + (", ".join(argnamelist[firstoptarg:]))
|
||||
argstr += "]"
|
||||
if self.rettype:
|
||||
outlist = [("retval", -1)] + outlist
|
||||
elif self.isconstructor:
|
||||
@ -513,8 +544,8 @@ class FuncInfo(object):
|
||||
self.is_static = is_static
|
||||
self.variants = []
|
||||
|
||||
def add_variant(self, decl, isphantom=False):
|
||||
self.variants.append(FuncVariant(self.classname, self.name, decl, self.isconstructor, isphantom))
|
||||
def add_variant(self, all_classes, decl, isphantom=False):
|
||||
self.variants.append(FuncVariant(all_classes, self.classname, self.name, decl, self.isconstructor, isphantom))
|
||||
|
||||
def get_wrapper_name(self):
|
||||
name = self.name
|
||||
@ -570,20 +601,20 @@ class FuncInfo(object):
|
||||
# their relevant doxygen comment
|
||||
full_docstring = ""
|
||||
for prototype, body in zip(prototype_list, docstring_list):
|
||||
full_docstring += Template("$prototype\n$docstring\n\n\n\n").substitute(
|
||||
prototype=prototype,
|
||||
docstring='\n'.join(
|
||||
['. ' + line
|
||||
full_docstring += Template("$prototype\n$docstring").substitute(
|
||||
prototype="\"" + prototype.replace("\\", "\\\\").replace("\"", "\\\"") + "\\n\\n\"",
|
||||
docstring="\n".join(
|
||||
[" \"" + line.replace("\\", "\\\\").replace("\"", "\\\"") + "\\n\""
|
||||
for line in body.split('\n')]
|
||||
)
|
||||
)
|
||||
|
||||
# Escape backslashes, newlines, and double quotes
|
||||
full_docstring = full_docstring.strip().replace("\\", "\\\\").replace('\n', '\\n').replace("\"", "\\\"")
|
||||
#full_docstring = full_docstring.strip().replace("\\", "\\\\").replace("\"", "\\\"")
|
||||
# Convert unicode chars to xml representation, but keep as string instead of bytes
|
||||
full_docstring = full_docstring.encode('ascii', errors='xmlcharrefreplace').decode()
|
||||
|
||||
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),\n $py_docstring},\n'
|
||||
).substitute(py_funcname = self.variants[0].wname, wrap_funcname=self.get_wrapper_name(),
|
||||
flags = 'METH_STATIC' if self.is_static else '0', py_docstring = full_docstring)
|
||||
|
||||
@ -623,6 +654,8 @@ class FuncInfo(object):
|
||||
if v.isphantom and ismethod and not self.is_static:
|
||||
code_args += "_self_"
|
||||
|
||||
params_arg_name, extra_named_params = get_named_params_info(all_classes, v.args)
|
||||
|
||||
# declare all the C function arguments,
|
||||
# add necessary conversions from Python objects to code_cvt_list,
|
||||
# form the function/method call,
|
||||
@ -692,6 +725,15 @@ class FuncInfo(object):
|
||||
|
||||
code_args += amp + a.name
|
||||
|
||||
if params_arg_name:
|
||||
for a in extra_named_params:
|
||||
code_decl += " PyObject* pyobj_kw_%s = NULL;\n" % (a.name,)
|
||||
ainfo = "ArgInfo(\"params.%s\", %d)" % (a.name, 0)
|
||||
if a.tp == 'char':
|
||||
code_cvt_list.append("convert_to_char(pyobj_kw_%s, ¶ms.%s, %s)" % (a.name, a.name, ainfo))
|
||||
else:
|
||||
code_cvt_list.append("pyopencv_to(pyobj_kw_%s, params.%s, %s)" % (a.name, a.name, ainfo))
|
||||
|
||||
code_args += ")"
|
||||
|
||||
if self.isconstructor:
|
||||
@ -740,16 +782,22 @@ class FuncInfo(object):
|
||||
])
|
||||
if v.py_noptargs > 0:
|
||||
fmtspec = fmtspec[:-v.py_noptargs] + "|" + fmtspec[-v.py_noptargs:]
|
||||
fmtspec += "O" * len(extra_named_params)
|
||||
fmtspec += ":" + fullname
|
||||
|
||||
# form the argument parse code that:
|
||||
# - declares the list of keyword parameters
|
||||
# - calls PyArg_ParseTupleAndKeywords
|
||||
# - converts complex arguments from PyObject's to native OpenCV types
|
||||
kw_list = ['"' + aname + '"' for aname, argno in v.py_arglist]
|
||||
kw_list += ['"' + a.name + '"' for a in extra_named_params]
|
||||
parse_arglist = ["&" + all_cargs[argno][1] for aname, argno in v.py_arglist]
|
||||
parse_arglist += ["&pyobj_kw_" + a.name for a in extra_named_params]
|
||||
|
||||
code_parse = gen_template_parse_args.substitute(
|
||||
kw_list = ", ".join(['"' + aname + '"' for aname, argno in v.py_arglist]),
|
||||
kw_list = ", ".join(kw_list),
|
||||
fmtspec = fmtspec,
|
||||
parse_arglist = ", ".join(["&" + all_cargs[argno][1] for aname, argno in v.py_arglist]),
|
||||
parse_arglist = ", ".join(parse_arglist),
|
||||
code_cvt = " &&\n ".join(code_cvt_list))
|
||||
else:
|
||||
code_parse = "if(PyObject_Size(py_args) == 0 && (!kw || PyObject_Size(kw) == 0))"
|
||||
@ -933,13 +981,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, is_static))
|
||||
func.add_variant(decl, isphantom)
|
||||
func.add_variant(self.classes, 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, isphantom)
|
||||
func.add_variant(self.classes, decl, isphantom)
|
||||
else:
|
||||
if classname and not isconstructor:
|
||||
if not isphantom:
|
||||
@ -949,7 +997,7 @@ class PythonWrapperGenerator(object):
|
||||
func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
|
||||
|
||||
func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace, is_static))
|
||||
func.add_variant(decl, isphantom)
|
||||
func.add_variant(self.classes, decl, isphantom)
|
||||
|
||||
if classname and isconstructor:
|
||||
self.classes[classname].constructor = func
|
||||
@ -1130,7 +1178,7 @@ class PythonWrapperGenerator(object):
|
||||
|
||||
if __name__ == "__main__":
|
||||
srcfiles = hdr_parser.opencv_hdr_list
|
||||
dstdir = "/Users/vp/tmp"
|
||||
dstdir = "."
|
||||
if len(sys.argv) > 1:
|
||||
dstdir = sys.argv[1]
|
||||
if len(sys.argv) > 2:
|
||||
|
@ -258,6 +258,10 @@ class CppHeaderParser(object):
|
||||
if "CV_EXPORTS_W_MAP" in l:
|
||||
l = l.replace("CV_EXPORTS_W_MAP", "")
|
||||
modlist.append("/Map")
|
||||
if "CV_EXPORTS_W_PARAMS" in l:
|
||||
l = l.replace("CV_EXPORTS_W_PARAMS", "")
|
||||
modlist.append("/Map")
|
||||
modlist.append("/Params")
|
||||
if "CV_EXPORTS_W_SIMPLE" in l:
|
||||
l = l.replace("CV_EXPORTS_W_SIMPLE", "")
|
||||
modlist.append("/Simple")
|
||||
@ -769,7 +773,12 @@ class CppHeaderParser(object):
|
||||
var_list = [var_name1] + [i.strip() for i in var_list[1:]]
|
||||
|
||||
for v in var_list:
|
||||
class_decl[3].append([var_type, v, "", var_modlist])
|
||||
vv = v.split("=")
|
||||
vname = vv[0].strip()
|
||||
vdefval = ""
|
||||
if len(vv) > 1:
|
||||
vdefval = vv[1].strip()
|
||||
class_decl[3].append([var_type, vname, vdefval, var_modlist])
|
||||
return stmt_type, "", False, None
|
||||
|
||||
# something unknown
|
||||
|
27
modules/python/test/test_imgproc.py
Executable file
27
modules/python/test/test_imgproc.py
Executable file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
Test for disctrete fourier transform (dft)
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
import sys
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
class imgproc_test(NewOpenCVTests):
|
||||
def test_filter2d(self):
|
||||
img = self.get_sample('samples/data/lena.jpg', 1)
|
||||
eps = 0.001
|
||||
# compare 2 ways of computing 3x3 blur using the same function
|
||||
kernel = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]], dtype='float32')
|
||||
img_blur0 = cv.filter2D(img, cv.CV_32F, kernel*(1./9))
|
||||
img_blur1 = cv.filter2Dp(img, kernel, ddepth=cv.CV_32F, scale=1./9)
|
||||
self.assertLess(cv.norm(img_blur0 - img_blur1, cv.NORM_INF), eps)
|
||||
|
||||
if __name__ == '__main__':
|
||||
NewOpenCVTests.bootstrap()
|
Loading…
Reference in New Issue
Block a user