Skip to content

feat: OpenCV extension with pure Python modules#20611

Merged
alalek merged 3 commits intoopencv:masterfrom
VadimLevin:dev/vlevin/pure-python-modules
Sep 18, 2021
Merged

feat: OpenCV extension with pure Python modules#20611
alalek merged 3 commits intoopencv:masterfrom
VadimLevin:dev/vlevin/pure-python-modules

Conversation

@VadimLevin
Copy link
Copy Markdown
Contributor

This patch adds an ability to extend OpenCV with pure Python modules and functions.

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or other license that is incompatible with OpenCV
  • The PR is proposed to proper branch
  • There is reference to original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake

Copy link
Copy Markdown
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to eliminate _extra_py_code somehow, but it conflicts with cv2 submodules from binary extension (not a misc case, but gapi)

@VadimLevin VadimLevin force-pushed the dev/vlevin/pure-python-modules branch from 14ccf91 to 7f5b8ee Compare September 13, 2021 20:12
@VadimLevin
Copy link
Copy Markdown
Contributor Author

It would be nice to eliminate _extra_py_code somehow, but it conflicts with cv2 submodules from binary extension (not a misc case, but gapi)

I succeed in eliminating _extra_py_code, but unfortunately it is not possible when there is names collision between cv2 represented as a package (with __init__.py) and cv2 represented as C extension module. To achieve the expected result - when there is cv2 package with all functions from cv2 C module I had to rename cv2 .so library to _cv2.*.so. The same thing is done in CPython CSV module

When there is no clashed names the only thing left is load required submodules and packages in a proper order:

  • Populate package symbols dictionary of the cv2 package from the cv2 module symbols (including submodules info)
  • Load Python submodules.
  • If there is a corresponding native submodule - extend loaded submodule with the native functions and classes.

sys.modules after `cv2 is loaded:

>>> import cv2
>>> import sys
>>> {m: sys.modules[m] for m in filter(lambda k: "cv2" in k, sys.modules)}
{
'cv2.load_config_py3': <module 'cv2.load_config_py3' from '/opencv-dev/build/python_loader/cv2/load_config_py3.py'>, 
'_cv2.Error': <module '_cv2.Error'>, 
'_cv2.cuda': <module '_cv2.cuda'>, 
'_cv2.detail': <module '_cv2.detail'>, 
'_cv2.dnn': <module '_cv2.dnn'>, 
'_cv2.fisheye': <module '_cv2.fisheye'>, 
'_cv2.flann': <module '_cv2.flann'>, 
'_cv2.gapi': <module '_cv2.gapi'>, 
'_cv2.gapi.core': <module '_cv2.gapi.core'>,
 '_cv2.gapi.core.cpu': <module '_cv2.gapi.core.cpu'>,
 '_cv2.gapi.core.fluid': <module '_cv2.gapi.core.fluid'>, 
'_cv2.gapi.core.ocl': <module '_cv2.gapi.core.ocl'>,
 '_cv2.gapi.ie': <module '_cv2.gapi.ie'>,
 '_cv2.gapi.ie.detail': <module '_cv2.gapi.ie.detail'>, 
'_cv2.gapi.onnx': <module '_cv2.gapi.onnx'>, 
'_cv2.gapi.own': <module '_cv2.gapi.own'>, 
'_cv2.gapi.own.detail': <module '_cv2.gapi.own.detail'>, 
'_cv2.gapi.render': <module '_cv2.gapi.render'>,
 '_cv2.gapi.render.ocv': <module '_cv2.gapi.render.ocv'>,
 '_cv2.gapi.streaming': <module '_cv2.gapi.streaming'>, 
'_cv2.gapi.video': <module '_cv2.gapi.video'>, 
'_cv2.gapi.wip': <module '_cv2.gapi.wip'>, 
'_cv2.gapi.wip.draw': <module '_cv2.gapi.wip.draw'>,
 '_cv2.ipp': <module '_cv2.ipp'>, 
'_cv2.ml': <module '_cv2.ml'>,
 '_cv2.ocl': <module '_cv2.ocl'>,
 '_cv2.ogl': <module '_cv2.ogl'>,
 '_cv2.parallel': <module '_cv2.parallel'>,
 '_cv2.samples': <module '_cv2.samples'>, 
'_cv2.segmentation': <module '_cv2.segmentation'>, 
'_cv2.utils': <module '_cv2.utils'>,
 '_cv2.utils.fs': <module '_cv2.utils.fs'>,
 '_cv2.videoio_registry': <module '_cv2.videoio_registry'>, 
'_cv2': <module '_cv2' from '/opencv-dev/build/lib/python3/_cv2.cpython-38-x86_64-linux-gnu.so'>, 
'cv2.gapi': <module '_cv2.gapi' from '/opencv-dev/build/python_loader/cv2/gapi/__init__.py'>, 
'cv2.misc.version': <module 'cv2.misc.version' from '/opencv-dev/build/python_loader/cv2/misc/version.py'>, 
'cv2.misc': <module 'cv2.misc' from '/opencv-dev/build/python_loader/cv2/misc/__init__.py'>,
 'cv2': <module 'cv2' from '/opencv-dev/build/python_loader/cv2/__init__.py'>
}

@VadimLevin VadimLevin force-pushed the dev/vlevin/pure-python-modules branch from 7f5b8ee to ba70421 Compare September 13, 2021 20:32
Copy link
Copy Markdown
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should move forward through small harmless steps

#endif

#define MODULESTR "cv2"
#define MODULESTR "_cv2"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This renaming is not harmless in general.
It makes sense to keep existed flow for current release series.

I believe it is not a problem to load whole package at once. No need to support on-demand loading of submodules for conflict "subnames" already existed in C binary extension.

BTW, we have discussions about "opencv" name for package in 5.0 scope.

raise unittest.SkipTest('Python 2.x is not supported')

self.assertEqual(cv.misc.get_ocv_version(), cv.__version__,
"Can't get package version using Python misc module")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is still not clear to me that problem we want to resolve here (except loading from filesystem).

See here: https://github.com/alalek/opencv/commits/test_20611

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand this comment

Python package cv2 now can handle both Python and C extension modules
properly without additional "subfolders" like "_extra_py_code".
@VadimLevin VadimLevin force-pushed the dev/vlevin/pure-python-modules branch from ba70421 to 15669fb Compare September 14, 2021 05:38
@VadimLevin
Copy link
Copy Markdown
Contributor Author

VadimLevin commented Sep 14, 2021

I've done some juggling with native modules and Python packages and looks like I achieved the desired result without renaming the .so library.
@alalek have a look, please.

After OpenCV package is loaded:

>>> import cv2
>>> import sys
>>> {m: sys.modules[m] for m in filter(lambda k: "cv2" in k, sys.modules)}
{
'cv2.load_config_py3': <module 'cv2.load_config_py3' from '/opencv-dev/build/python_loader/cv2/load_config_py3.py'>,
'cv2.Error': <module 'cv2.Error'>,
'cv2.cuda': <module 'cv2.cuda'>
'cv2.detail': <module 'cv2.detail'>,
'cv2.dnn': <module 'cv2.dnn'>,
'cv2.fisheye': <module 'cv2.fisheye'>,
'cv2.flann': <module 'cv2.flann'>,
 'cv2.gapi.core': <module 'cv2.gapi.core'>, 
'cv2.gapi.core.cpu': <module 'cv2.gapi.core.cpu'>,
 'cv2.gapi.core.fluid': <module 'cv2.gapi.core.fluid'>,
 'cv2.gapi.core.ocl': <module 'cv2.gapi.core.ocl'>,
 'cv2.gapi.ie': <module 'cv2.gapi.ie'>,
 'cv2.gapi.ie.detail': <module 'cv2.gapi.ie.detail'>,
 'cv2.gapi.onnx': <module 'cv2.gapi.onnx'>, 
'cv2.gapi.own': <module 'cv2.gapi.own'>, 
'cv2.gapi.own.detail': <module 'cv2.gapi.own.detail'>, 
'cv2.gapi.render': <module 'cv2.gapi.render'>,
 'cv2.gapi.render.ocv': <module 'cv2.gapi.render.ocv'>, 
'cv2.gapi.streaming': <module 'cv2.gapi.streaming'>, 
'cv2.gapi.video': <module 'cv2.gapi.video'>, 
'cv2.gapi.wip': <module 'cv2.gapi.wip'>,
 'cv2.gapi.wip.draw': <module 'cv2.gapi.wip.draw'>, 
'cv2.ipp': <module 'cv2.ipp'>, 
'cv2.ml': <module 'cv2.ml'>,
 'cv2.ocl': <module 'cv2.ocl'>, 
'cv2.ogl': <module 'cv2.ogl'>,
 'cv2.parallel': <module 'cv2.parallel'>,
 'cv2.samples': <module 'cv2.samples'>, 
'cv2.segmentation': <module 'cv2.segmentation'>,
 'cv2.utils': <module 'cv2.utils'>, 
'cv2.utils.fs': <module 'cv2.utils.fs'>,
 'cv2.videoio_registry': <module 'cv2.videoio_registry'>,
 'cv2.gapi': <module 'cv2.gapi' from '/opencv-dev/build/python_loader/cv2/gapi/__init__.py'>,
 'cv2.misc.version': <module 'cv2.misc.version' from '/opencv-dev/build/python_loader/cv2/misc/version.py'>, 
'cv2.misc': <module 'cv2.misc' from '/opencv-dev/build/python_loader/cv2/misc/__init__.py'>,
 'cv2': <module 'cv2' from '/opencv-dev/build/python_loader/cv2/__init__.py'>
}

@VadimLevin
Copy link
Copy Markdown
Contributor Author

Something wrong with Win32 DNN tests: link . Are they flapping?

Copy link
Copy Markdown
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well done! Thank you 👍

@alalek alalek merged commit 3c89a28 into opencv:master Sep 18, 2021
a-sajjad72 pushed a commit to a-sajjad72/opencv that referenced this pull request Mar 30, 2023
…n-modules

* feat: OpenCV extension with pure Python modules

* feat: cv2 is now a Python package instead of extension module

Python package cv2 now can handle both Python and C extension modules
properly without additional "subfolders" like "_extra_py_code".

* feat: can call native function from its reimplementation in Python
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants