Support Python binding for CUDA functionalities
This commit is contained in:
@@ -32,9 +32,7 @@ endforeach(m)
|
||||
|
||||
# header blacklist
|
||||
ocv_list_filterout(opencv_hdrs "modules/.*\\\\.h$")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/.*/cuda")
|
||||
ocv_list_filterout(opencv_hdrs "modules/cuda.*")
|
||||
ocv_list_filterout(opencv_hdrs "modules/cudev")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/.*/cuda/")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/.*/hal/")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/.*/opencl/")
|
||||
ocv_list_filterout(opencv_hdrs "modules/.+/utils/.*")
|
||||
@@ -43,6 +41,10 @@ ocv_list_filterout(opencv_hdrs "modules/.*_inl\\\\.h*")
|
||||
ocv_list_filterout(opencv_hdrs "modules/.*\\\\.details\\\\.h*")
|
||||
ocv_list_filterout(opencv_hdrs "modules/.*\\\\.private\\\\.h*")
|
||||
ocv_list_filterout(opencv_hdrs "modules/.*/detection_based_tracker\\\\.hpp") # Conditional compilation
|
||||
if(NOT HAVE_CUDA)
|
||||
ocv_list_filterout(opencv_hdrs "modules/cuda.*")
|
||||
ocv_list_filterout(opencv_hdrs "modules/cudev")
|
||||
endif()
|
||||
|
||||
set(cv2_generated_files
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_include.h"
|
||||
|
||||
+17
-15
@@ -12,17 +12,19 @@ else:
|
||||
|
||||
ignored_arg_types = ["RNG*"]
|
||||
|
||||
pass_by_val_types = ["Point*", "Point2f*", "Rect*", "String*", "double*", "float*", "int*"]
|
||||
|
||||
gen_template_check_self = Template(""" $cname* _self_ = NULL;
|
||||
if(PyObject_TypeCheck(self, &pyopencv_${name}_Type))
|
||||
_self_ = ${amp}((pyopencv_${name}_t*)self)->v${get};
|
||||
if (_self_ == NULL)
|
||||
if (!_self_)
|
||||
return failmsgp("Incorrect type of self (must be '${name}' or its derivative)");
|
||||
""")
|
||||
|
||||
gen_template_check_self_algo = Template(""" $cname* _self_ = NULL;
|
||||
if(PyObject_TypeCheck(self, &pyopencv_${name}_Type))
|
||||
_self_ = dynamic_cast<$cname*>(${amp}((pyopencv_${name}_t*)self)->v.get());
|
||||
if (_self_ == NULL)
|
||||
if (!_self_)
|
||||
return failmsgp("Incorrect type of self (must be '${name}' or its derivative)");
|
||||
""")
|
||||
|
||||
@@ -77,7 +79,7 @@ template<> PyObject* pyopencv_from(const ${cname}& r)
|
||||
|
||||
template<> bool pyopencv_to(PyObject* src, ${cname}& dst, const char* name)
|
||||
{
|
||||
if( src == NULL || src == Py_None )
|
||||
if(!src || src == Py_None)
|
||||
return true;
|
||||
if(!PyObject_TypeCheck(src, &pyopencv_${name}_Type))
|
||||
{
|
||||
@@ -120,7 +122,7 @@ template<> PyObject* pyopencv_from(const Ptr<${cname}>& r)
|
||||
|
||||
template<> bool pyopencv_to(PyObject* src, Ptr<${cname}>& dst, const char* name)
|
||||
{
|
||||
if( src == NULL || src == Py_None )
|
||||
if(!src || src == Py_None)
|
||||
return true;
|
||||
if(!PyObject_TypeCheck(src, &pyopencv_${name}_Type))
|
||||
{
|
||||
@@ -192,7 +194,7 @@ gen_template_get_prop_algo = Template("""
|
||||
static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *closure)
|
||||
{
|
||||
$cname* _self_ = dynamic_cast<$cname*>(p->v.get());
|
||||
if (_self_ == NULL)
|
||||
if (!_self_)
|
||||
return failmsgp("Incorrect type of object (must be '${name}' or its derivative)");
|
||||
return pyopencv_from(_self_${access}${member});
|
||||
}
|
||||
@@ -201,7 +203,7 @@ static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *clo
|
||||
gen_template_set_prop = Template("""
|
||||
static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value, void *closure)
|
||||
{
|
||||
if (value == NULL)
|
||||
if (!value)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Cannot delete the ${member} attribute");
|
||||
return -1;
|
||||
@@ -213,13 +215,13 @@ static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value
|
||||
gen_template_set_prop_algo = Template("""
|
||||
static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value, void *closure)
|
||||
{
|
||||
if (value == NULL)
|
||||
if (!value)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Cannot delete the ${member} attribute");
|
||||
return -1;
|
||||
}
|
||||
$cname* _self_ = dynamic_cast<$cname*>(p->v.get());
|
||||
if (_self_ == NULL)
|
||||
if (!_self_)
|
||||
{
|
||||
failmsgp("Incorrect type of object (must be '${name}' or its derivative)");
|
||||
return -1;
|
||||
@@ -402,7 +404,7 @@ class ArgInfo(object):
|
||||
self.py_outputarg = False
|
||||
|
||||
def isbig(self):
|
||||
return self.tp == "Mat" or self.tp == "vector_Mat"\
|
||||
return self.tp == "Mat" or self.tp == "vector_Mat" or self.tp == "cuda::GpuMat"\
|
||||
or self.tp == "UMat" or self.tp == "vector_UMat" # or self.tp.startswith("vector")
|
||||
|
||||
def crepr(self):
|
||||
@@ -656,15 +658,12 @@ class FuncInfo(object):
|
||||
tp1 = tp = a.tp
|
||||
amp = ""
|
||||
defval0 = ""
|
||||
if tp.endswith("*"):
|
||||
if tp in pass_by_val_types:
|
||||
tp = tp1 = tp[:-1]
|
||||
amp = "&"
|
||||
if tp.endswith("*"):
|
||||
defval0 = "0"
|
||||
tp1 = tp.replace("*", "_ptr")
|
||||
if tp1.endswith("*"):
|
||||
print("Error: type with star: a.tp=%s, tp=%s, tp1=%s" % (a.tp, tp, tp1))
|
||||
sys.exit(-1)
|
||||
|
||||
amapping = simple_argtype_mapping.get(tp, (tp, "O", defval0))
|
||||
parse_name = a.name
|
||||
@@ -686,6 +685,9 @@ class FuncInfo(object):
|
||||
if "UMat" in tp:
|
||||
if "Mat" in defval and "UMat" not in defval:
|
||||
defval = defval.replace("Mat", "UMat")
|
||||
if "cuda::GpuMat" in tp:
|
||||
if "Mat" in defval and "GpuMat" not in defval:
|
||||
defval = defval.replace("Mat", "cuda::GpuMat")
|
||||
# "tp arg = tp();" is equivalent to "tp arg;" in the case of complex types
|
||||
if defval == tp + "()" and amapping[1] == "O":
|
||||
defval = ""
|
||||
@@ -754,7 +756,7 @@ class FuncInfo(object):
|
||||
parse_arglist = ", ".join(["&" + all_cargs[argno][1] for aname, argno in v.py_arglist]),
|
||||
code_cvt = " &&\n ".join(code_cvt_list))
|
||||
else:
|
||||
code_parse = "if(PyObject_Size(args) == 0 && (kw == NULL || PyObject_Size(kw) == 0))"
|
||||
code_parse = "if(PyObject_Size(args) == 0 && (!kw || PyObject_Size(kw) == 0))"
|
||||
|
||||
if len(v.py_outlist) == 0:
|
||||
code_ret = "Py_RETURN_NONE"
|
||||
@@ -975,7 +977,7 @@ class PythonWrapperGenerator(object):
|
||||
|
||||
def gen(self, srcfiles, output_path):
|
||||
self.clear()
|
||||
self.parser = hdr_parser.CppHeaderParser(generate_umat_decls=True)
|
||||
self.parser = hdr_parser.CppHeaderParser(generate_umat_decls=True, generate_gpumat_decls=True)
|
||||
|
||||
# step 1: scan the headers and build more descriptive maps of classes, consts, functions
|
||||
for hdr in srcfiles:
|
||||
|
||||
@@ -32,8 +32,9 @@ original_return_type is None if the original_return_type is the same as return_v
|
||||
|
||||
class CppHeaderParser(object):
|
||||
|
||||
def __init__(self, generate_umat_decls=False):
|
||||
def __init__(self, generate_umat_decls=False, generate_gpumat_decls=False):
|
||||
self._generate_umat_decls = generate_umat_decls
|
||||
self._generate_gpumat_decls = generate_gpumat_decls
|
||||
|
||||
self.BLOCK_TYPE = 0
|
||||
self.BLOCK_NAME = 1
|
||||
@@ -379,7 +380,7 @@ class CppHeaderParser(object):
|
||||
print(decl_str)
|
||||
return decl
|
||||
|
||||
def parse_func_decl(self, decl_str, use_umat=False, docstring=""):
|
||||
def parse_func_decl(self, decl_str, mat="Mat", docstring=""):
|
||||
"""
|
||||
Parses the function or method declaration in the form:
|
||||
[([CV_EXPORTS] <rettype>) | CVAPI(rettype)]
|
||||
@@ -563,8 +564,6 @@ class CppHeaderParser(object):
|
||||
a = a[:eqpos].strip()
|
||||
arg_type, arg_name, modlist, argno = self.parse_arg(a, argno)
|
||||
if self.wrap_mode:
|
||||
mat = "UMat" if use_umat else "Mat"
|
||||
|
||||
# TODO: Vectors should contain UMat, but this is not very easy to support and not very needed
|
||||
vector_mat = "vector_{}".format("Mat")
|
||||
vector_mat_template = "vector<{}>".format("Mat")
|
||||
@@ -639,7 +638,7 @@ class CppHeaderParser(object):
|
||||
n = "cv.Algorithm"
|
||||
return n
|
||||
|
||||
def parse_stmt(self, stmt, end_token, use_umat=False, docstring=""):
|
||||
def parse_stmt(self, stmt, end_token, mat="Mat", docstring=""):
|
||||
"""
|
||||
parses the statement (ending with ';' or '}') or a block head (ending with '{')
|
||||
|
||||
@@ -731,7 +730,7 @@ class CppHeaderParser(object):
|
||||
# since we filtered off the other places where '(' can normally occur:
|
||||
# - code blocks
|
||||
# - function pointer typedef's
|
||||
decl = self.parse_func_decl(stmt, use_umat=use_umat, docstring=docstring)
|
||||
decl = self.parse_func_decl(stmt, mat=mat, docstring=docstring)
|
||||
# we return parse_flag == False to prevent the parser to look inside function/method bodies
|
||||
# (except for tracking the nested blocks)
|
||||
return stmt_type, "", False, decl
|
||||
@@ -902,14 +901,24 @@ class CppHeaderParser(object):
|
||||
else:
|
||||
decls.append(decl)
|
||||
|
||||
if self._generate_gpumat_decls and "cv.cuda." in decl[0]:
|
||||
# If function takes as one of arguments Mat or vector<Mat> - we want to create the
|
||||
# same declaration working with GpuMat (this is important for T-Api access)
|
||||
args = decl[3]
|
||||
has_mat = len(list(filter(lambda x: x[0] in {"Mat", "vector_Mat"}, args))) > 0
|
||||
if has_mat:
|
||||
_, _, _, gpumat_decl = self.parse_stmt(stmt, token, mat="cuda::GpuMat", docstring=docstring)
|
||||
decls.append(gpumat_decl)
|
||||
|
||||
if self._generate_umat_decls:
|
||||
# If function takes as one of arguments Mat or vector<Mat> - we want to create the
|
||||
# same declaration working with UMat (this is important for T-Api access)
|
||||
args = decl[3]
|
||||
has_mat = len(list(filter(lambda x: x[0] in {"Mat", "vector_Mat"}, args))) > 0
|
||||
if has_mat:
|
||||
_, _, _, umat_decl = self.parse_stmt(stmt, token, use_umat=True, docstring=docstring)
|
||||
_, _, _, umat_decl = self.parse_stmt(stmt, token, mat="UMat", docstring=docstring)
|
||||
decls.append(umat_decl)
|
||||
|
||||
docstring = ""
|
||||
if stmt_type == "namespace":
|
||||
chunks = [block[1] for block in self.block_stack if block[0] == 'namespace'] + [name]
|
||||
@@ -952,7 +961,7 @@ class CppHeaderParser(object):
|
||||
print()
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = CppHeaderParser(generate_umat_decls=True)
|
||||
parser = CppHeaderParser(generate_umat_decls=True, generate_gpumat_decls=True)
|
||||
decls = []
|
||||
for hname in opencv_hdr_list:
|
||||
decls += parser.parse(hname)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
CUDA-accelerated Computer Vision functions
|
||||
'''
|
||||
|
||||
# Python 2/3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
class cuda_test(NewOpenCVTests):
|
||||
def setUp(self):
|
||||
if not cv.cuda.getCudaEnabledDeviceCount():
|
||||
self.skipTest("No CUDA-capable device is detected")
|
||||
|
||||
def test_cuda_upload_download(self):
|
||||
npMat = (np.random.random((200, 200, 3)) * 255).astype(np.uint8)
|
||||
gpuMat = cv.cuda_GpuMat()
|
||||
gpuMat.upload(npMat)
|
||||
|
||||
self.assertTrue(np.allclose(gpuMat.download(), npMat))
|
||||
|
||||
def test_cuda_imgproc_cvtColor(self):
|
||||
npMat = (np.random.random((200, 200, 3)) * 255).astype(np.uint8)
|
||||
gpuMat = cv.cuda_GpuMat()
|
||||
gpuMat.upload(npMat)
|
||||
gpuMat2 = cv.cuda.cvtColor(gpuMat, cv.COLOR_BGR2HSV)
|
||||
|
||||
self.assertTrue(np.allclose(gpuMat2.download(), cv.cvtColor(npMat, cv.COLOR_BGR2HSV)))
|
||||
|
||||
def test_cuda_filter_laplacian(self):
|
||||
npMat = (np.random.random((200, 200)) * 255).astype(np.uint16)
|
||||
gpuMat = cv.cuda_GpuMat()
|
||||
gpuMat.upload(npMat)
|
||||
gpuMat = cv.cuda.createLaplacianFilter(cv.CV_16UC1, -1, ksize=3).apply(gpuMat)
|
||||
|
||||
self.assertTrue(np.allclose(gpuMat.download(), cv.Laplacian(npMat, cv.CV_16UC1, ksize=3)))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
NewOpenCVTests.bootstrap()
|
||||
Reference in New Issue
Block a user