-
-
Notifications
You must be signed in to change notification settings - Fork 56.2k
G-API: New python operations API #19982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
G-API: New python operations API #19982
Conversation
…-python-operation-api
4aa708c
to
3d77c27
Compare
@@ -496,6 +509,14 @@ static cv::GRunArgs run_py_kernel(PyObject* kernel, | |||
} | |||
|
|||
PyObject* result = PyObject_CallObject(kernel, args); | |||
if (PyErr_Occurred()) { | |||
PyErr_PrintEx(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Always print traceback even if exception is handled in python code. Can be changed later, because retrieving traceback from python exception in c++ is not-trivial
Looks like this patch is not compatible with Python limited API build option:
Perhaps lower level Py_CompileString + PyEval_EvalCode must be used instead of See also: |
I believe this line should removed at all during integration @alalek |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Straightforward import of provided code as cv2.gapi
doesn't work because this submodule is already defined by binaries extension.
Investigating other paths (for Python 3.x+ only).
Updates will be added later.
class GAddImpl: | ||
@staticmethod | ||
def run(img0, img1): | ||
raise 'Error' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not correct:
raise 'Error'
TypeError: exceptions must derive from BaseException
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean ? Just derive it from BaseException
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a Python error message.
Use proper classes for raising exceptions in Python, e.g. Exception
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -522,5 +375,288 @@ def test_custom_op_goodFeaturesToTrack(self): | |||
np.array(actual, dtype=np.float32).flatten(), cv.NORM_INF)) | |||
|
|||
|
|||
def test_invalid_op(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With fixed absolute path I'm observing sporadic crashed on this test case or tests cleanup.
Stacktrace is not really useful (python-only runtime code).
Ran 17 tests in 0.064s
OK
Segmentation fault (core dumped)
test_invalid_op (test_gapi_sample_pipelines.gapi_sample_pipelines) ... Segmentation fault (core dumped)
Launch command example:
OPENCV_PYTEST_FILTER=test_gapi_sample* ./setup_vars.sh python3 ../opencv/modules/python/test/test.py -v --repo ../opencv
Please confirm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works fine for me:
atalaman@nnlicv179:~/workspace/opencv-python/build$ OPENCV_PYTEST_FILTER=test_gapi_sample* ./setup_vars.sh python3 ../../opencv-python/modules/python/test/test.py -v --repo ../../opencv-python
Setting vars for OpenCV 4.5.2-dev
Append PYTHONPATH: /home/atalaman/workspace/opencv-python/build/python_loader
Testing OpenCV 4.5.2-dev
Local repo path: ../../opencv-python
Tests filter: test_gapi_sample*.py
Discovering python tests from: /home/atalaman/workspace/opencv-python/build
found 0 tests
Discovering python tests from: /home/atalaman/workspace/opencv-python/modules/python/test
found 0 tests
Discovering python tests from: /home/atalaman/workspace/opencv-python/modules/ml/misc/python/test
found 0 tests
Discovering python tests from: /home/atalaman/workspace/opencv-python/modules/dnn/misc/python/test
found 0 tests
Discovering python tests from: /home/atalaman/workspace/opencv-python/modules/features2d/misc/python/test
found 0 tests
Discovering python tests from: /home/atalaman/workspace/opencv-python/modules/videoio/misc/python/test
found 0 tests
Discovering python tests from: /home/atalaman/workspace/opencv-python/modules/calib3d/misc/python/test
found 0 tests
Discovering python tests from: /home/atalaman/workspace/opencv-python/modules/objdetect/misc/python/test
found 0 tests
Discovering python tests from: /home/atalaman/workspace/opencv-python/modules/stitching/misc/python/test
found 0 tests
Discovering python tests from: /home/atalaman/workspace/opencv-python/modules/video/misc/python/test
found 0 tests
Discovering python tests from: /home/atalaman/workspace/opencv-python/modules/gapi/misc/python/test
found 17 tests
test_array_with_custom_type (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_custom_op_add (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_custom_op_addC (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_custom_op_boundingRect (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_custom_op_goodFeaturesToTrack (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_custom_op_mean (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_custom_op_size (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_custom_op_sizeR (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_custom_op_split3 (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_invalid_op (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_invalid_op_input (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_invalid_outMeta (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_opaq_with_custom_type (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_pipeline_with_custom_kernels (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_raise_in_kernel (test_gapi_sample_pipelines.gapi_sample_pipelines) ... /usr/lib/python3/dist-packages/apport/report.py:13: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
import fnmatch, glob, traceback, errno, sys, atexit, locale, imp, stat
Traceback (most recent call last):
File "/home/atalaman/workspace/opencv-python/modules/gapi/misc/python/test/test_gapi_sample_pipelines.py", line 540, in run
raise Exception('Error')
Exception: Error
ok
test_raise_in_outMeta (test_gapi_sample_pipelines.gapi_sample_pipelines) ... Traceback (most recent call last):
File "/home/atalaman/workspace/opencv-python/modules/gapi/misc/python/test/test_gapi_sample_pipelines.py", line 562, in outMeta
raise 'Error'
TypeError: exceptions must derive from BaseException
ok
test_stateful_kernel (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
----------------------------------------------------------------------
Ran 17 tests in 0.044s
OK
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stack trace dump of crashes from gdb and Python 3.9:
...
Discovering python tests from: /home/alalek/projects/opencv/dev/modules/gapi/misc/python/test
found 17 tests
test_array_with_custom_type (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_custom_op_add (test_gapi_sample_pipelines.gapi_sample_pipelines) ... [ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
[ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
ok
test_custom_op_addC (test_gapi_sample_pipelines.gapi_sample_pipelines) ... [ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
[ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
ok
test_custom_op_boundingRect (test_gapi_sample_pipelines.gapi_sample_pipelines) ... [ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
[ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
ok
test_custom_op_goodFeaturesToTrack (test_gapi_sample_pipelines.gapi_sample_pipelines) ... [ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
[ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
ok
test_custom_op_mean (test_gapi_sample_pipelines.gapi_sample_pipelines) ... [ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Expected cv::GProtoInputArgs for argument 'ins'
[ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Expected cv::GMat for argument 'out'
ok
test_custom_op_size (test_gapi_sample_pipelines.gapi_sample_pipelines) ... [ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
[ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
ok
test_custom_op_sizeR (test_gapi_sample_pipelines.gapi_sample_pipelines) ... [ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
[ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
ok
test_custom_op_split3 (test_gapi_sample_pipelines.gapi_sample_pipelines) ... [ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
[ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
[ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
[ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
[ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
[ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
ok
test_invalid_op (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_invalid_op_input (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_invalid_outMeta (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_opaq_with_custom_type (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
test_pipeline_with_custom_kernels (test_gapi_sample_pipelines.gapi_sample_pipelines) ... [ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
[ WARN:0] global /home/alalek/projects/opencv/dev/modules/python/src2/cv2.cpp (110) emit_failmsg Bindings conversion failed: Argument 'normType' is required to be an integer
ok
test_raise_in_kernel (test_gapi_sample_pipelines.gapi_sample_pipelines) ... Traceback (most recent call last):
File "/home/alalek/projects/opencv/dev/modules/gapi/misc/python/test/test_gapi_sample_pipelines.py", line 540, in run
raise Exception('Error')
Exception: Error
ok
test_raise_in_outMeta (test_gapi_sample_pipelines.gapi_sample_pipelines) ... Traceback (most recent call last):
File "/home/alalek/projects/opencv/dev/modules/gapi/misc/python/test/test_gapi_sample_pipelines.py", line 562, in outMeta
raise NotImplementedError("outMeta ins't implemented")
NotImplementedError: outMeta ins't implemented
ok
test_stateful_kernel (test_gapi_sample_pipelines.gapi_sample_pipelines) ... ok
----------------------------------------------------------------------
Ran 17 tests in 0.023s
OK
Thread 1 "python3" received signal SIGSEGV, Segmentation fault.
0x00007fffe9898ba0 in PyFloatArrType_Type () from /home/alalek/penv3/lib64/python3.9/site-packages/numpy/core/_multiarray_umath.cpython-39-x86_64-linux-gnu.so
(gdb) bt
#0 0x00007fffe9898ba0 in PyFloatArrType_Type () at /home/alalek/penv3/lib64/python3.9/site-packages/numpy/core/_multiarray_umath.cpython-39-x86_64-linux-gnu.so
#1 0x00007ffff7d3ffdf in tupletraverse () at /lib64/libpython3.9.so.1.0
#2 0x00007ffff7d3fc65 in deduce_unreachable () at /lib64/libpython3.9.so.1.0
#3 0x00007ffff7d3f97d in collect () at /lib64/libpython3.9.so.1.0
#4 0x00007ffff7dc2a0e in collect_with_callback () at /lib64/libpython3.9.so.1.0
#5 0x00007ffff7df3a0e in PyGC_Collect () at /lib64/libpython3.9.so.1.0
#6 0x00007ffff7df3427 in Py_FinalizeEx () at /lib64/libpython3.9.so.1.0
#7 0x00007ffff7df379c in Py_Exit () at /lib64/libpython3.9.so.1.0
#8 0x00007ffff7df0f3b in handle_system_exit () at /lib64/libpython3.9.so.1.0
#9 0x00007ffff7df0c6d in PyErr_PrintEx () at /lib64/libpython3.9.so.1.0
#10 0x00007ffff7de962e in PyRun_SimpleFileExFlags () at /lib64/libpython3.9.so.1.0
#11 0x00007ffff7de6aa6 in Py_RunMain () at /lib64/libpython3.9.so.1.0
#12 0x00007ffff7db8f8d in Py_BytesMain () at /lib64/libpython3.9.so.1.0
#13 0x00007ffff7a9b1e2 in __libc_start_main () at /lib64/libc.so.6
#14 0x000055555555509e in _start ()
(gdb)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alalek Could you try it once again ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@dmatveev Have a look, please |
@alalek Have a look, once again, please, looks like all work. |
670e281
to
4a0ffc8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a python expert, but have some general concerns. Experts please correct me. Like the solution overall
|
||
class Any(): | ||
def __new__(self): | ||
return cv.GArray(cv.gapi.CV_ANY) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I believe the idea of this file was to define everything in Python but... can it be auto-generated from our C++ definitions? At least these parts with types and enums..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right the idea is correct, but there are some difficulties, let me explain:
cv.GArray.Any
and others should be really types.
I mean, user use it astypes
in kernel definitions:
@cv.gapi.op('custom.op', in_types=[cv.GOpaque.Any, cv.GOpaque.String], out_types=[cv.GOpaque.Any])
....
It would be clear to create object
the same way
g_any = cv.GOpaque.Any() // instead of cv.GOpaqueT(cv.gapi.CV_ANY)
You can't achieve that by using enums
in c++, right ?
- The second problem is that in c++ it should be looks like:
class GArrayT {
...
GAPI_EXPORTS_W_SIMPLE Any {
...
};
};
Unfortunately generator
doesn't support such syntax
My point is that if there is no difference where it will be defined it is better to go the simplest way and do it in python
('ocl' , cv.gapi.core.ocl.kernels()), | ||
('cpu' , cv.gapi.core.cpu.kernels()), | ||
('fluid' , cv.gapi.core.fluid.kernels()) | ||
# ('plaidml', cv.gapi.core.plaidml.kernels()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW it'd be a nice-to-have feature - test particular G-API capabilities which are available in this particular build, and cal functions like this plaidml.kernels()
conditionally, if the capability exist (like, you know, #ifdef
in runtime)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll file a ticket
list(SORT extra_py_files) | ||
foreach(f ${extra_py_files}) | ||
configure_file("${__base}/${f}" "${__loader_path}/cv2/_extra_py_code/${f}" COPYONLY) | ||
install(FILES "${__base}/${f}" DESTINATION "${OPENCV_PYTHON_INSTALL_PATH}/cv2/_extra_py_code/${f}" COMPONENT python) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So does it go to the target FS like this? Can it be.. compromised? Can we execute some privileged code while loading those scripts? If I get this right...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It goes into subdirectories (so these files can be modified iff all OpenCV files can be modified).
PYTHONPATH
/ sys.path
may affect loaded scripts too, but this also can break import cv2
in the same way.
@mshabunin Please take a look on Python integration part. |
We've already enabled python loader in OpenCV for OpenVINO, but what about other distributions (conda, pip), will they work? I believe they do not use python loader. Maybe previous mechanism with C implementation in cv2.cpp should be restored? Or can it be done later? |
@alalek @mshabunin What's the current status of this ? Can it be merged ? |
8e771c1
to
8a55ab0
Compare
for (int i = 0; i < size; ++i) | ||
{ | ||
PyObject* pair = PyTuple_GetItem(py_args, i); | ||
PyObject* kernel = PyTuple_GetItem(pair, 0); | ||
PyObject* user_kernel = PyTuple_GetItem(py_args, i); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need to care about user_kernel
utilization in case exception because PyTuple_GetItem
return borrowed reference.
8a55ab0
to
1f44715
Compare
…ration-api G-API: New python operations API * Reimplement test using decorators * Custom python operation API * Remove wip status * python: support Python code in bindings (through loader only) * cleanup, skip tests for Python 2.x (not supported) * python 2.x can't skip unittest modules * Clean up * Clean up * Fix segfault python3.9 Co-authored-by: Alexander Alekhin <[email protected]>
Pull Request Readiness Checklist
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request
Patch to opencv_extra has the same branch name.