Nuitka
Nuitka copied to clipboard
OpenCV High-level GUI
I'm trying to run a simple program using the OpenCV High-level GUI.
This is a minimal example:
import numpy as np
import cv2
if __name__ == '__main__':
img = np.zeros((300, 300, 3))
cv2.imshow("img", img)
cv2.waitKey(0)
Compiling the code works but when running the executable I get the following error:
➜ (nuitka) ./main.dist/main
qt.qpa.plugin: Could not find the Qt platform plugin "xcb" in "/path/to/main.dist/cv2/qt/plugins"
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
However the folder main.dist/cv2/qt does not exist. Apparently opencv sets the following environment variables: QT_QPA_PLATFORM_PLUGIN_PATH, QT_QPA_FONTDIR Thus if I add the following to the python example the compiled program works but of course this is less than ideal.
import os
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = '/home/user/.virtualenvs/nuitka/lib/python3.9/site-packages/cv2/qt/plugins'
os.environ['QT_QPA_FONTDIR'] = '/home/user/.virtualenvs/nuitka/lib/python3.9/site-packages/cv2/qt/fonts'
I would appreciate any help regarding how to make sure the plugins can be included in the executable.
Here is my environment:
python -m nuitka --version 1.0.6 Commercial: None Python: 3.9.13 (main, May 23 2022, 22:01:06) Flavor: Debian Python Executable: /home/user/.virtualenvs/nuitka/bin/python OS: Linux Arch: x86_64 Distribution: Ubuntu (based on Debian) 20.04.5
- How did you install Nuitka and Python: pip+virtualenv
python -m pip freeze Nuitka==1.0.6 numpy==1.23.2 opencv-python==4.6.0.66
- Nuitka command
python -m nuitka --standalone --enable-plugin=numpy main.py
Have you tried adding the pyqt5 plugin with --enable-plugin=pyqt5 --include-qt-plugins=xcb
?
Have you tried adding the pyqt5 plugin with
--enable-plugin=pyqt5 --include-qt-plugins=xcb
?
With this I get the following error:
(nuitka) ➜ python -m nuitka --standalone --enable-plugin=numpy,pyqt5 --include-qt-plugins=xcb main.py
Nuitka-Options:INFO: Used command line options: --standalone --enable-plugin=numpy,pyqt5 --include-qt-plugins=xcb main.py
Nuitka:WARNING: Using very slow fallback for ordered sets, please install 'orderedset' PyPI package for best Python compile time performance.
Nuitka:INFO: Starting Python compilation with Nuitka '1.0.6' on Python '3.9' commercial grade 'not installed'.
Nuitka-Plugins:INFO: multiprocessing: Injecting pre-module load code for module 'multiprocessing':
Nuitka-Plugins:INFO: multiprocessing: Monkey patching "multiprocessing" load environment.
Nuitka-Plugins:INFO: multiprocessing: Injecting post-module load code for module 'multiprocessing':
Nuitka-Plugins:INFO: multiprocessing: Monkey patching "multiprocessing" for compiled methods.
Nuitka:INFO: Completed Python level compilation and optimization.
Nuitka:INFO: Generating source code for C backend compiler.
Nuitka:INFO: Running data composer tool for optimal constant value handling.
Nuitka:INFO: Running C compilation via Scons.
Nuitka-Scons:INFO: Backend C compiler: gcc (gcc).
Nuitka-Scons:INFO: Backend linking program with 107 files (no progress information available).
Nuitka-Scons:WARNING: You are not using ccache.
FATAL: pyqt5: Error, it seems 'PyQt5' is not installed or broken.
After installing PyQT5 the command works but when running the executable the error is the same as before
The file libxcb.so.1 exists in ./main.dist/ but not in ./main.dist/cv2/qt/plugins/platforms
It seems that cv2
also has Qt plugins of its own. It probably can be dealt with by similar code, but it will have to be created, and it would be sweet if it indeed coexisted with Qt bindings nicely, but do not have it installed, that makes no sense. The way you specified Qt plugins there, is outright unlikely to work at all, because you are not including mandatory plugins.
If anyone wants to help, checkout the nuitka/plugins/standard/PySidePyQtPlugin.py
file and try to have a cv2
plugin, that allows to do similar stuff. The setting of environment variables, that point into the dist, is also done in that plugin, and largely you have to do only what it does. I do not know when I will have to time to look at this.
Just copy files (qt-plugins) from the folder main.dist/pyqt5/qt-plugins (or main.dist/pyside6/qt-plugins) into the new created folder "qt/plugins" in main.dist/cv2/qt/plugins. Or simply copy one file "libqxcb" from main.dist/pyside6/qt-plugins/platforms/libqxcb to get the final dir: main.dist/cv2/qt/plugins/platforms/libqxcb
If at all under your control, make sure to use PySide6, it's far better supported.
Plus the copying is not really enough in the general cased, esp. outside of Windows, we will have to make a plugin update there, but as you know @OualidSai I am busy with something else ;-)
I will be happy @kayhayen because the new stuff will be working :-)
I am confused about this one, I assumed this was about Qt plugins in the cv2 wheel, but I did not immediately see them now. Is this using a Qt binding like PySide or PyQt or is this something I have no yet seen?
Ah, got it, this is only done on Linux, and it is only the platforms plugin for X11. One weakness of my WSL setup is that I have no GUI available, so I will need help to test this one, but basically we just need to set the environment variable and include this as a DLL. Mixing with PySide and PyQt wouldn't work well this way, but probably does not with standard Python either.
Thanks for the pretty much perfect report. Turns out, 3 things had to be done, which are all encapsulated in this yaml and are also part of the original report:
- module-name: 'cv2'
data-files:
dirs:
- 'qt/fonts'
dlls:
- from_filenames:
relative_path: 'qt/plugins/platforms'
prefixes:
- 'lib'
when: 'linux'
implicit-imports:
- pre-import-code:
- |
import os
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = os.path.join(os.path.dirname(__file__), 'qt/plugins')
os.environ['QT_QPA_FONTDIR'] = os.path.join(os.path.dirname(__file__), 'qt/fonts')
when: 'linux and standalone'
In the old days, this would have needed a dedicated plugin, but it's pretty powerful now.
I got report, that this doesn't work with Anaconda on Linux yet, but only PyPI package so far. I will try and add that as well.
This is part of the stable release 1.1 that I just made, but Anaconda will need more work, shifted to 1.1 hotfix.
It works perfectly with Nuitka 1.1 with virtualenv.