QVideoFilterRunnable causes Segmentation Fault with PySide2 - python

I am attempting to show a video feed while processing the image with OpenCV. I already have a script that does the image processing using OpenCV and Python, but attempting to add any filter to the VideoOutput results in a segmentation fault. The documentation only has examples for C++, but I have tried to replicate it exactly in Python.
Here is my Python file (example.py):
from PySide2.QtWidgets import QApplication
from PySide2.QtQml import qmlRegisterType
from PySide2.QtQuick import QQuickView
from PySide2.QtMultimedia import QAbstractVideoFilter, QVideoFilterRunnable
from PySide2.QtCore import QUrl
class ExampleFilterRunnable(QVideoFilterRunnable):
def run(self, frame, surfaceFormat, flags):
return frame
class ExampleFilter(QAbstractVideoFilter):
def createFilterRunnable(self):
return ExampleFilterRunnable()
app = QApplication([])
qmlRegisterType(ExampleFilter, "ExampleFilter", 1, 0, "ExampleFilter")
view = QQuickView()
url = QUrl("example.qml")
view.setSource(url)
view.setResizeMode(view.SizeRootObjectToView)
view.show()
app.exec_()
And the QML (example.qml):
import QtQuick 2.0
import QtQuick.Controls 2.3
import QtMultimedia 5.8
import ExampleFilter 1.0
Rectangle {
id: rectangle
width: 800
height: 600
color: "black"
ExampleFilter {
id: filter
}
MediaPlayer {
id: player
source: "https://archive.org/download/Mario1_500/Mario1_500_LQ.avi"
autoPlay: true
}
VideoOutput {
id: videoOutput
source: player
filters: [filter]
anchors.fill: parent
}
}
I added debug output to try to understand what was happening, as no errors are printed beside "Segmentation fault (core dumped)". The segmentation fault occurs sometime after the ExampleFilterRunnable is instantiated in createFilterRunnable and before ExampleFilterRunnable::run is called.
I have run it on different computers with different video cards, and with different types of videos and camera feeds, and the result is the same. If I comment out the filters: [filter] line in VideoOutput, the video plays.

It appears that this might actually be a bug in PySide2: https://bugreports.qt.io/browse/PYSIDE-785

Related

Unable to create a CircularGuage in Python qt with qml using QQuickWidget on windows

I am trying to create a circular guage using Qml in Python as a QQuickWidget.
I am unable to do so as I receive the Error CircularGauge.qml:18:9: NumberAnimation is not a type
I am working on windows, where I have added C:\Qt\Tools\QtCreator\bin\qml to my path.
I have copied CircularGauge.qml exactly as is from example found on the Qt site doc.qt.io
to solve this issue I tried adding import QtQuick 2.0 to the CircularGauge.qml file, but then I receive the error CircularGauge is instantiated recursively
My python code is as follows:
import sys
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout
from PySide6.QtQuick import QQuickView, QQuickWindow, QSGRendererInterface
from PySide6.QtQuickWidgets import QQuickWidget
if __name__ == '__main__':
app = QApplication()
QQuickWindow.setGraphicsApi(QSGRendererInterface.OpenGL)
widget = QQuickWidget()
widget.setSource('CircularGauge.qml')
layout = QVBoxLayout(widget)
widget.show()
sys.exit(app.exec())
I have confirmed this works with other qml exampls,
for example if I replace widget.setSource('CircularGauge.qml') with widget.setSource('view.qml')
where view.qml is:
import QtQuick
Rectangle {
id: main
width: 200
height: 200
color: "green"
Text {
text: "Hello World"
anchors.centerIn: main
}
}
I get the desired result of a qml file loaded into a QQuickWidget
How can I load the CircularGauge in the same way?

Custom QQuickItem is not painted

I am trying to write my own QQuickItems that use the SceneGraph to draw shapes as if it the parent Item was a Canvas. I am using PySide6 and Python. During my attempts I found a bug in PySide6, which was earlier reported. I downloaded the patch that fixed it and it seems to be ok now (https://bugreports.qt.io/browse/PYSIDE-1345).
My program now compiles and runs, but the node is not painted. If I understand the documentation correctly, I need to do three things to have a custom QQuickItem painted:
Inherit from QQuickItem
Override updatePaintNode
Set the ItemHasContents flag
I did all that, registered my type, added it in QML and made sure it has non-zero dimensions. Unfortunately, it still does not get paited. I do not know what to do next.
Here's the minimal working example:
main.py
# This Python file uses the following encoding: utf-8
import os
from pathlib import Path
import sys
from PySide6.QtGui import QGuiApplication, QColor
from PySide6.QtQml import QQmlApplicationEngine, qmlRegisterType
from PySide6.QtQuick import QQuickItem, QSGGeometryNode, QSGGeometry, QSGFlatColorMaterial
class JustItem(QQuickItem):
def __init__(self, parent=None):
super().__init__(parent)
self.setFlag(QQuickItem.ItemHasContents)
def updatePaintNode(self, node, update_data):
if node is None:
node = QSGGeometryNode()
geometry = QSGGeometry(QSGGeometry.defaultAttributes_Point2D(), 4)
geometry.setDrawingMode(QSGGeometry.DrawTriangles)
vertex_data = geometry.vertexDataAsPoint2D()
vertex_data[0].set(10, 10)
vertex_data[1].set(100, 10)
vertex_data[2].set(100, 100)
vertex_data[3].set(10, 100)
material = QSGFlatColorMaterial()
material.setColor(QColor(255, 0, 0, 127))
node.setGeometry(geometry)
node.setMaterial(material)
return node
if __name__ == "__main__":
qmlRegisterType(JustItem, "PythonTypes", 1, 0, "JustItem")
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml"))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec())
And QML:
import QtQuick
import QtQuick.Window
import PythonTypes 1.0
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
JustItem {
}
}
The result is an empty white window. When I resize it, it segfaults.
This is a bug in PySide 2. Currently it is not possible to draw your custom QQuickItems in PySide 2.
The bug is discussed in more detail here: https://forum.qt.io/topic/116585/qsggeometry-does-not-work-on-pyside2/16
There's also a bug report, which has a proposed fix. The fix causes segmentation fault: https://bugreports.qt.io/browse/PYSIDE-1345
Unfortunately, if you want to draw custom QQuickItems you either need to write them in C++ or use another GUI framework entirely.

Different screen between qmlscene and Python : Toolbar

I have a problem with Toolbar when I use the qml file with PyQt5. The result is not the seem : no background image when mouse is over, image no resize automatically.
I want to know if it's normal.
How can I do for have the same result with PyQt5
The result with qmlscene:
The result with Python:
Thanks you for your help.
File : _test.py
from PyQt5.QtCore import (
pyqtProperty,
pyqtSignal,
pyqtSlot,
QAbstractListModel,
QModelIndex,
QObject,
Qt,
QTimer,
)
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine
from PyQt5.QtQuick import QQuickView
class MainWindow(QObject):
def __init__(self, parent=None):
super().__init__(parent)
if __name__ == "__main__":
import sys
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.quit.connect(app.quit)
main_window = MainWindow()
engine.load("_test.qml")
if not engine.rootObjects():
sys.exit(app.exec_())
sys.exit(app.exec())
File : _test.qml
import QtQuick 2.4
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3
ApplicationWindow {
width: 500
height: 200
visible: true
ToolBar {
Layout.fillWidth: true
RowLayout {
anchors.fill: parent
ToolButton {
//width: parent.height
anchors.margins: 4
iconSource: "ico/abacus.png"
}
ToolButton {
width: parent.height
Image {
source: "ico/quitter.png"
anchors.fill: parent
anchors.margins: 4
}
}
ToolButton {
width: parent.height
iconSource: "ico/start.png"
anchors.margins: 4
}
ToolButton {
width: parent.height
Image {
source: "ico/stop.png"
anchors.fill: parent
anchors.margins: 4
}
}
}
}
}
Analyzing the source code of qmlscene and testing with the --apptype option I get the following:
qmlscene _test.qml --apptype gui
qmlscene _test.qml --apptype widgets
So analyzing the fundamental difference is that QApplicacion is being used and not QGuiApplication, so internally it should activate some flag that scales the icons.
Considering the above, the solution is:
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQml import QQmlApplicationEngine
if __name__ == "__main__":
import os
import sys
app = QApplication(sys.argv)
engine = QQmlApplicationEngine()
current_dir = os.path.dirname(os.path.realpath(__file__))
file = os.path.join(current_dir, "_test.qml")
engine.load(QUrl.fromLocalFile(file))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
According to the docs of Qt Quick Controls 1:
Note: We are using QApplication and not QGuiApplication in this
example. Though you can use QGuiApplication instead, doing this will
eliminate platform-dependent styling. This is because it is relying on
the widget module to provide the native look and feel.
So it seems that the scaling of the icons is part of the style of the platform.
Each type of project requires a QXApplication:
Console application: You can use any of the 3 types of QXApplication, but using QCoreApplication is the most optimal since the other QXApplication require that they have a window system that in that case is an unnecessary requirement.
QML Application: It requires at least one QGuiApplication, but for certain ones such as the need to use the styles of each platform it is necessary to use QApplication.
Qt Widgets Application: A QApplication is necessary because QWidgets use the styles of each platform.
The fact that sizes change, is this a problem of QtQuick.Controls 1?
Yes, one of the main differences between QQC1 and QQC2 is that the first one is developed to support desktop platforms so you use the styles, unlike the second one that is designed for embedded systems where the main objective is performance. For more information read Differences with Qt Quick Controls 1
Conclusions:
If you want your GUI made with QML to respect the styles of your desktop platform then you must use QQC1 with QApplication.
If your goal is that the style of your application does not respect the style of the desktop in addition to wanting more performance you should use QQC2 with QGuiApplication.

Injecting Properties into QML-Component

I am fairly new to Qt/PyQt and currently struggling with some basic functionality. What I'm trying to do is, to dynamically load QML-Views (*.qml) files from python and replace specific content on the fly. For example a checkbox gets checked and part of my current view is replaced with another qml file. First I wanted to provide this logic via PyQt, but it seems a StackView is a better idea (multiple qml files in pyqt).
However, in this case I am not able to inject properties into my QML files. I am only able to inject a property into the rootContext. That however limits the usage of my QML-Views since I can only use one view (of the same type) at once. I would like to inject properties dynamically into QML-Views and make them only visible to this particular view. In this case I can use the same view more than once with more than one object in the back-end to catch the signals.
Here is my SimpleMainWindow.qml file (the main view:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.3
import QtQuick.Controls 1.4
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
title: qsTr("Hello World")
objectName : "WINDOW"
property ApplicationWindow appWindow : window
}
And here the file I try to load (TestViewButton.qml):
import QtQuick 2.9
import QtQuick.Controls 1.4
Button {
id: test
text: "test"
objectName : "Button"
onClicked: {
configurator.sum(1, 2)
configurator.info("TestOutput")
}
}
Python file loading QML-View (Component)
from PyQt5.QtCore import QObject, QUrl
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine, QQmlComponent
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.load("qml/SimpleMainWindow.qml")
engine.quit.connect(app.quit)
rootWindow = engine.rootObjects()[0].children()[0].parent()
# create component
component = QQmlComponent(engine)
component.loadUrl(QUrl("qml/TestViewButton.qml"))
configurator = SignalHandler()
component.setProperty("configurator", configurator)
itm = component.create()
itm.setParentItem(rootWindow.children()[0])
itm.setProperty("configurator", configurator)
app.exec_()
And the python object that I use to handle the signals from the view (SignalHandler.py):
from PyQt5.QtCore import QObject, pyqtSlot
class SignalHandler(QObject):
#pyqtSlot(int, int)
def sum(self, arg1, arg2):
print("Adding two numbers")
#pyqtSlot(str)
def info(self, arg1):
print("STR " + arg1)
The button loads fine (by the way, is there a better way to identify the parent I want to add my button to, wasn't having any look with findChild). What is not working is the component.setProperty.... part. If I set the property in the rootContext of the engine it works fine (the SignalHandler methods are called). Already checked similar topics (like Load a qml component from another qml file dynamically and access that component's qml type properties ...)
Is this possible, or am I getting something wrong here?
thanks
From what I understand, you want to load the configuration object only in TestViewButton.qml and it is not visible in SimpleMainWindow.qml.
To do this TestViewButton.qml must have its own QQmlContext when it is loaded and is not the rootContext().
To test my response and observe that behavior we will create a similar button that tries to use the configurator, if this is pressed it should throw an error noting that the property does not exist but if the button loaded is pressed by the QQmlComponent should do its job normally.
qml/SimpleMainWindow.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.3
import QtQuick.Controls 1.4
ApplicationWindow {
id: window
visible: true
width: 640
color: "red"
height: 480
title: qsTr("Hello World")
Button {
x: 100
y: 100
text: "ApplicationWindow"
onClicked: {
console.log("ApplicationWindow")
configurator.sum(1, 2)
configurator.info("TestOutput")
}
}
}
As I commented previously I added the component with a new context:
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
configurator = SignalHandler()
engine.load("qml/SimpleMainWindow.qml")
engine.quit.connect(app.quit)
rootWindow = engine.rootObjects()[0]
content_item = rootWindow.property("contentItem")
context = QQmlContext(engine)
component = QQmlComponent(engine)
component.loadUrl(QUrl("qml/TestViewButton.qml"))
itm = component.create(context)
context.setContextProperty("configurator", configurator)
itm.setProperty("parent", content_item)
sys.exit(app.exec_())
At the end we get the following output:
qml: Component
Adding two numbers
STR TestOutput
qml: ApplicationWindow
file:///xxx/qml/SimpleMainWindow.qml:20: ReferenceError: configurator is not defined
qml: Component
Adding two numbers
STR TestOutput
qml: ApplicationWindow
file:///xxx/qml/SimpleMainWindow.qml:20: ReferenceError: configurator is not defined
Where we observe the desired behavior. The complete example can be found in the following link.

QML Image not displaying in Application

I am having trouble displaying a simple image into my application.
Here's the main.py:
import sys
from PyQt5.QtQml import QQmlApplicationEngine
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtCore import QObject, QUrl
if __name__ == '__main__':
sys.argv += ['--style', 'material']
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine('basic.qml')
sys.exit(app.exec_())
And the basic.qml:
import QtQuick 2.0
import QtQuick.Controls 2.1
import QtQuick.Controls.Material 2.1
ApplicationWindow {
visible: true
width: 200
height: 400
title: qsTr("Hello World")
Material.theme: Material.Light
Material.accent: Material.Orange
Column {
anchors.centerIn: parent
Button {
width: 200; height:50;
font.capitalization: Font.MixedCase
text: qsTr("Button Name")
objectName: "button_obj_name"
highlighted: true
Material.background: Material.Orange
}
Image{
width: 100; height: 100
fillMode: Image.PreserveAspectFit
source: "logo_name.jpg"
}
}
}
In the application window it seems that space is allocated but nothing is displaying.
[logo_name.jpg is located in the same folder where basic.qml and main.py are in ]
Your code looks right. I was having a similar problem on my windows box. Code that worked on the raspberry did not work on the windows machine. Removing and reinstalling PyQt5 go it working again.
pip3 uninstall pyqt5
It had something to do with the image I was trying to display(as #Jason R. Mick mentioned),I believe that the image I was trying to use was converted by changing it's extension name.
As a sanity check can you please post the image you're trying to
display & image/listing of folder contents? – Jason R. Mick
You should better check current path.
You can print out the current path with sys.argv[0].
After getting the path, copy your image file to that path.
Then, run again.
I also think this is not a problem of source code, but development environment.

Categories

Resources