How to overlay transparent image on qt camera? - qt

Im trying to overlay an image with transparency on QCameraViewfinder. The following code works fine on windows, but ignores the transparency on raspberry pi.
Im using pyside2 version 5.11.2 on RPI4 and tried tranparent PNG and SVG files.
As an alternative, if Im using paintEvent to draw shapes, the viewfinder doesnt show video. My QPainter code is attached too.
from PySide2.QtMultimedia import QCamera, QCameraInfo
from PySide2.QtMultimediaWidgets import QCameraViewfinder
from PySide2 import QtCore, QtGui
from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import *
import sys
class ExampleWindow(QMainWindow):
def __init__(self, windowsize):
super().__init__()
self.windowsize = windowsize
self.initUI()
def initUI(self):
self.setFixedSize(self.windowsize)
widget = QWidget()
self.setCentralWidget(widget)
self.view_finder = QCameraViewfinder()
camerainfo = QCameraInfo.availableCameras()[0]
self.camera = QCamera(camerainfo)
self.camera.setViewfinder(self.view_finder)
self.camera.start()
layout_box = QHBoxLayout(widget)
layout_box.setContentsMargins(0, 0, 0, 0)
layout_box.addWidget(self.view_finder)
pixmap = QPixmap('crosshair3.png')
self.image = QLabel(widget)
self.image.setPixmap(pixmap)
self.image.setFixedSize(pixmap.size())
hw = pixmap.size().width()/2
hh = pixmap.size().height()/2
self.image.move(self.rect().center().x()-hw, self.rect().center().y()-hh)
if __name__ == '__main__':
app = QApplication(sys.argv)
screensize = app.desktop().availableGeometry().size()
ex = ExampleWindow(screensize)
ex.show()
sys.exit(app.exec_())
When using QPainter there is no video on the viewfinder:
class MyQCameraViewfinder(QCameraViewfinder):
def __init__(self, parent=None):
super().__init__(parent)
def paintEvent(self, event):
paint = QtGui.QPainter()
paint.begin(self)
paint.setRenderHint(QtGui.QPainter.Antialiasing)
paint.setPen(QtCore.Qt.black)
paint.setBrush(QtCore.Qt.white)
paint.drawEllipse(QtCore.QRect(17, 22, 50, 50))
paint.end()
on windows 11:
on rpi 4:

Related

Qt: QMediaPlayer.setSource() was blocking the GUI so I moved it to a separate thread; am I doing this right?

Running this code:
from PySide6 import QtWidgets as qtw
from PySide6 import QtMultimedia as qtm
from PySide6 import QtMultimediaWidgets as qtmw
from PySide6 import QtCore as qtc
app = qtw.QApplication()
path = "video.mp4"
video_widget = qtmw.QVideoWidget()
video_widget.show()
media_player = qtm.QMediaPlayer()
media_player.setVideoOutput(video_widget)
media_player.mediaStatusChanged.connect(media_player.play)
media_player.setSource(path)
qtc.QTimer.singleShot(2000, lambda: media_player.setSource(''))
app.exec()
, you will notice that when media_player.setSource('') is called after 2000 milliseconds, the GUI becomes unresponsive for a good second or so. And it seems like it is not possible to move only the setSource() call to a separate thread, I get a warning saying QObject::killTimer: Timers cannot be stopped from another thread (you can replicate this by replacing qtc.QTimer... call with qtc.QThreadPool.globalInstance().start(lambda: media_player.setSource(''))). So, after hours of pondering, as a work around, I moved the entire QMediaPlayer instance and all objects related to it to a thread of its own and used QVideoSink's videoFrameChanged signal to update the video on the video widget:
from PySide6 import QtWidgets as qtw
from PySide6 import QtMultimedia as qtm
from PySide6 import QtMultimediaWidgets as qtmw
from PySide6 import QtCore as qtc
path = "video.mp4"
class VideoPlayer(qtmw.QVideoWidget):
_stop_worker_signal = qtc.Signal()
_initialize_media_player_signal = qtc.Signal()
_set_media_source_signal = qtc.Signal(str)
_play_media_signal = qtc.Signal()
_stop_media_signal = qtc.Signal()
_pause_media_signal = qtc.Signal()
def __init__(self) -> None:
super().__init__()
self._worker = Worker()
self._worker_thread = qtc.QThread()
self._worker.moveToThread(self._worker_thread)
self._stop_worker_signal.connect(self._worker.stop)
self._initialize_media_player_signal.connect(self._worker.create_media_player)
self._worker.video_sink_frame_changed_signal.connect(lambda frame: self.videoSink().setVideoFrame(frame))
self._set_media_source_signal.connect(self._worker.set_media_source)
self._stop_media_signal.connect(self._worker.stop_media)
self._worker_thread.start()
self._initialize_media_player_signal.emit()
self._set_media_source_signal.emit(path)
self.show()
def keyPressEvent(self, event):
if event.key() == qtc.Qt.Key.Key_Q:
self._set_media_source_signal.emit('')
def closeEvent(self, event: qtc.QEvent):
loop = qtc.QEventLoop()
self._worker.stopped_signal.connect(loop.exit)
self._stop_worker_signal.emit()
loop.exec()
self._worker_thread.exit()
class Worker(qtc.QObject):
video_sink_frame_changed_signal = qtc.Signal(qtm.QVideoFrame)
stopped_signal = qtc.Signal()
def create_media_player(self):
self._audio_output = qtm.QAudioOutput(qtm.QMediaDevices.defaultAudioOutput())
self._video_sink = qtm.QVideoSink()
self._video_sink.videoFrameChanged.connect(self.video_sink_frame_changed_signal)
self._media_player = qtm.QMediaPlayer()
self._media_player.setAudioOutput(self._audio_output)
self._media_player.setVideoSink(self._video_sink)
self._media_player.mediaStatusChanged.connect(self._media_player.play)
def set_media_source(self, source: str) -> None:
self._media_player.setSource(source)
def stop_media(self) -> None:
if not self._media_player.playbackState() == qtm.QMediaPlayer.PlaybackState.StoppedState:
self._media_player.stop()
def stop(self):
self._media_player.stop()
self._audio_output.deleteLater()
self._video_sink.deleteLater()
self._media_player.deleteLater()
self.stopped_signal.emit()
app = qtw.QApplication()
vp = VideoPlayer()
app.exec()
Now, there's no unresponsiveness in the GUI when setSource() is called but, as one can see, it's a pretty convoluted way to do this. Is there a better way?

PyQt5 treeview and mediaplayer crash

this is code with player only work fine ; with treeview only also work but together the app crash immediately if i click on radio button to show the treeview.
But if i click open button and the file explorer appear than it work and i can use radiobutton without problem ; i don't know why.
import sys
from PyQt5 import QtGui, QtWidgets, QtCore, uic
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import *
from PyQt5.uic import loadUi
class MyApp(QMainWindow):
def __init__(self):
super(MyApp, self).__init__()
loadUi("window.ui", self)
#########################################################################
self.model = QFileSystemModel(self)
self.model.setRootPath(self.model.myComputer())
self.treeview.setModel(self.model)
self.treeview.clicked.connect(self.on_treeView_clicked)
self.folder_open.toggled.connect(self.HideShow) # show/hide treeview
#########################################################################
self.media = QMediaPlayer()
video = QVideoWidget(self.videoShow)
video.setGeometry(QtCore.QRect(0, 0, 439, 282))
self.playButton.clicked.connect(self.playVideo)
self.openbtn.clicked.connect(self.openFile)
self.media.setVideoOutput(video)
#########################################################################
#QtCore.pyqtSlot(QtCore.QModelIndex)
def on_treeView_clicked(self, index):
indexItem = self.model.index(index.row(), 0, index.parent())
filePath = self.model.filePath(indexItem)
self.choice.setText(filePath)
def HideShow(self):
if self.folder_open.isChecked() == True:
self.showTree()
if self.folder_open.isChecked() == False:
self.hideTree()
def showTree(self):
self.list.setFixedSize(443, 310)
window.setFixedSize(1200, 320)
def hideTree(self):
self.list.setFixedSize(0, 310)
window.setFixedSize(750, 320)
###########################################################################
def openFile(self):
fileName, _ = QFileDialog.getOpenFileName(self, "Open Movie",QDir.homePath())
if fileName != '':
self.media.setMedia(QMediaContent(QUrl.fromLocalFile(fileName)))
def playVideo(self):
fileName = self.choice.text()
self.media.setMedia(QMediaContent(QUrl.fromLocalFile(fileName)))
self.media.play()
#if self.media.state() == QMediaPlayer.PlayingState:
#self.media.pause()
#else:
#self.media.play()
###########################################################################
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyApp()
window.setFixedSize(750, 320)
window.show()
sys.exit(app.exec_())
window.ui used : download here

QWidget painter

I have this code:
import sys, random, pprint
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5 import QtGui
from PyQt5.QtCore import Qt
class Window(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(QtCore.QRect(200, 200, 700, 700))
self.widget = QtWidgets.QWidget(self)
self.widget.setGeometry(QtCore.QRect(10, 10, 400, 200))
self.widget.setObjectName("widget")
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self.widget)
self.drawPoints(painter)
painter.end()
def drawPoints(self, painter):
#drawing code
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = Window()
ex.show()
sys.exit(app.exec_())
What do i expect: area (400x200) which would be painted by drawPoints(). QWidget inherits QPaintDevice. So this code should work. But console says:
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::end: Painter not active, aborted
Could you help me, please.
It looks like you are attempting to replicate this example, correct?
The major difference appears to be that you are defining paintEvent() for the main window, rather than the widget you are actually trying to paint. It would work if you created a custom subclass of QWidget, defined paintEvent() there, and then inserted that into a standard QMainWindow instance, like this:
class MyWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent=parent)
self.initUI()
def initUI(self):
self.setGeometry(QtCore.QRect(10, 10, 400, 200))
self.setObjectName("widget")
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
self.drawPoints(painter)
painter.end()
def drawPoints(self, painter):
pass
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
my_window = QtWidgets.QMainWindow()
my_window.setGeometry(QtCore.QRect(200, 200, 700, 700))
my_window.setCentralWidget(MyWidget(my_window))
my_window.show()
sys.exit(app.exec_())
At the very least, it isn't printing that error message anymore.

Set splitter handle as QScrollArea corner widget?

I'm trying to display files and folders like column view in Mac finder.
I was able get the basic structure with the help of ListViews and QFileSystemModel. Then I set the splitter handle as a corner widget for the scroll area. I have two issues here
When I resize the listview, the splitter handle disappears.
Even after setting the splitter handle width to 0, I see spacing between
listviews.
# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui
import os
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class PopulateList(QtGui.QDialog):
def __init__(self,parent=None):
super().__init__(parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
self.setModel()
self.show()
self.ui.splitter.setHandleWidth(0)#not working
self.ui.listView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.ui.listView.setCornerWidget(self.getCornerWidget(self.ui.splitter))
self.ui.closePushButton.clicked.connect(self.close)
self.ui.listView.clicked.connect(self.showSubFiles)
def getCornerWidget(self, splitter):
self.handle=splitter.handle(1)
layout=QtGui.QHBoxLayout(self.handle)
layout.setSpacing(0)
layout.setMargin(0)
for i in range(0,2):
line = QtGui.QFrame(self.handle)
line.setFrameShape(QtGui.QFrame.VLine)
layout.addWidget(line)
return self.handle
def showSubFiles(self, index):
root_path = self.model.fileInfo(index).absoluteFilePath()
self.model1=QtGui.QFileSystemModel()
self.model1.setRootPath(root_path)
self.ui.listView_1.setModel(self.model1)
self.ui.listView_1.setRootIndex(self.model1.index(root_path))
def setModel(self):
root_path=os.path.expanduser("~")
self.model=QtGui.QFileSystemModel()
self.model.setRootPath(root_path)
self.model.setFilter(QtCore.QDir.NoDotAndDotDot | QtCore.QDir.Dirs)
self.ui.listView.setModel(self.model)
self.ui.listView.setRootIndex(self.model.index(root_path))
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(602, 365)
self.verticalLayout = QtGui.QVBoxLayout(Form)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.splitter = QtGui.QSplitter(Form)
self.splitter.setOrientation(QtCore.Qt.Horizontal)
self.splitter.setObjectName(_fromUtf8("splitter"))
self.listView = QtGui.QListView(self.splitter)
self.listView.setObjectName(_fromUtf8("listView"))
self.listView_1 = QtGui.QListView(self.splitter)
self.listView_1.setObjectName(_fromUtf8("listView_1"))
self.verticalLayout.addWidget(self.splitter)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.closePushButton = QtGui.QPushButton(Form)
self.closePushButton.setObjectName(_fromUtf8("closePushButton"))
self.horizontalLayout.addWidget(self.closePushButton)
self.verticalLayout.addLayout(self.horizontalLayout)
self.verticalLayout.setStretch(0, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
self.closePushButton.setText(_translate("Form", "Close", None))
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
listView=PopulateList()
sys.exit(app.exec_())
Are you able to use QColumnView? It is exactly this.
http://doc.qt.io/qt-5/qcolumnview.html
import sys
from PyQt5 import QtWidgets, QtCore
app = QtWidgets.QApplication(sys.argv)
model = QtWidgets.QFileSystemModel()
view = QtWidgets.QColumnView()
view.setModel(model)
model.setRootPath("/")
view.show()
sys.exit(app.exec())

Animating a window on startup

I am trying to animate the window in startup but it doesn't seem to work, I have written the code below.
from PyQt4 import QtCore,QtGui
import sys
class AnimatedWindow(QtGui.QMainWindow):
"""docstring for AnimatedWindow"""
def __init__(self):
super(AnimatedWindow, self).__init__()
animation = QtCore.QPropertyAnimation(self, "geometry")
animation.setDuration(10000);
animation.setStartValue(QtCore.QRect(0, 0, 100, 30));
animation.setEndValue(QtCore.QRect(250, 250, 100, 30));
animation.start();
if __name__ == "__main__":
application = QtGui.QApplication(sys.argv)
main = AnimatedWindow()
main.show()
sys.exit(application.exec_())
The problem with this code is, when you create an object of QPropertyAnimation it is destroyed by the python garbage collector after animation.start() statement as animation variable is a local variable, hence the animation does not take place. To overcome this problem you need to make the animation as member variable (self.animation)
Here is the updated code which works fine:
from PyQt4 import QtCore,QtGui
import sys
class AnimatedWindow(QtGui.QMainWindow):
"""docstring for AnimatedWindow"""
def __init__(self):
super(AnimatedWindow, self).__init__()
self.animation = QtCore.QPropertyAnimation(self, "geometry")
self.animation.setDuration(1000);
self.animation.setStartValue(QtCore.QRect(50, 50, 100, 30));
self.animation.setEndValue(QtCore.QRect(250, 250, 500, 530));
self.animation.start();
if __name__ == "__main__":
application = QtGui.QApplication(sys.argv)
main = AnimatedWindow()
main.show()
sys.exit(application.exec_())

Resources