Solved pyqt5 draw above videowidget?
-
Hi guys:
I want to Know if it's possible I draw a block above a video, like two layers, the drawing layer is above the video layer.
Thanks a lot! -
Hey guys:
I solved my problem.
The solution is send a signal to change the item position in callback function of eyetracker rather than directly change it in call callback function of eyetracker which is in secondary thread.
Details in this Link
cheers! -
What did your google web search tell you about it?
-
@Kent-Dorfman
Hi kent:
sorry for late reply.
I do googled it before, and I find some an example.
What I want to do is visualize the gaze data(where the user is looking at) from a eye tracker(60hz) while watching a video.
it works, but the video always get stuck sometime (the audio is normal, the the frames stuck, both video content and ellipse), can you help me out here?
Thank you a lot!import os import time from PyQt5 import QtCore, QtGui, QtWidgets, QtMultimedia, QtMultimediaWidgets import tobii_research as tr import numpy as np """ code from https://stackoverflow.com/questions/53899740/how-to-draw-qtgraphicsview-on-top-of-qvideowidget-with-transparency """ class Widget(QtWidgets.QWidget): def __init__(self, parent=None): super(Widget, self).__init__(parent) #first window,just have a single button for play the video self.resize(256, 256) self.btn_play = QtWidgets.QPushButton(self) self.btn_play.setGeometry(QtCore.QRect(100, 100, 28, 28)) self.btn_play.setObjectName("btn_open") self.btn_play.setText("Play") self.btn_play.clicked.connect(self.Play_video)#click to play video # self._scene = QtWidgets.QGraphicsScene(self) self._gv = QtWidgets.QGraphicsView(self._scene) #construct a videoitem for showing the video self._videoitem = QtMultimediaWidgets.QGraphicsVideoItem() #add it into the scene self._scene.addItem(self._videoitem) # assign _ellipse_item is the gaze data, and embed it into videoitem,so it can show above the video. self._ellipse_item = QtWidgets.QGraphicsEllipseItem(QtCore.QRectF(0, 0, 40, 40), self._videoitem) self._ellipse_item.setBrush(QtGui.QBrush(QtCore.Qt.black)) self._ellipse_item.setPen(QtGui.QPen(QtCore.Qt.red)) self._scene.addItem(self._ellipse_item) self._gv.fitInView(self._videoitem) self._player = QtMultimedia.QMediaPlayer(self, QtMultimedia.QMediaPlayer.VideoSurface) self._player.setVideoOutput(self._videoitem) file = os.path.join(os.path.dirname(__file__), "video.mp4")#video.mp4 is under the same dirctory self._player.setMedia(QtMultimedia.QMediaContent(QtCore.QUrl.fromLocalFile(file))) #get eye tracker self.eyetrackers = tr.find_all_eyetrackers() self.my_eyetracker = self.eyetrackers[0] def gaze_data_callback(self, gaze_data_): #for now, I don't know the coordinate system,just randomly assign the gaze data to test the functionality self._ellipse_item.setPos(float(np.random.choice(range(300, 500))), float(np.random.choice(range(400, 500)))) print("time.time()::{}".format(time.time())) def Play_video(self): self.my_eyetracker.subscribe_to(tr.EYETRACKER_GAZE_DATA, self.gaze_data_callback, as_dictionary=True) size = QtCore.QSizeF(1920.0, 1080.0)#I hope it can fullscreen the video self._videoitem.setSize(size) self._gv.showFullScreen() self._player.play() if __name__ == '__main__': import sys app = QtWidgets.QApplication(sys.argv) w = Widget() w.show() sys.exit(app.exec_())
-
@fsluckyM said in pyqt5 draw above videowidget?:
it works, but the video always get stuck sometime
Why are you adding a video to graphics scene, and not playing the video into a widget?
You then modify that graphics scene with you gaze handler?
How does it know layering if they both go into the same graphics scene?If it were me:
- I'd use an overlay layout manager where the video is on the bottom layer in a basic widget, and the gaze drawing is done in an overlayed widget in the same layout manager.
- I'd do this in C++ and not in python. Your ability to optimize for speed increases if you use C++.
-
@Kent-Dorfman
Hi Kent:
I have not much qt experience, is there a overlay layout exist?
I only know QBoxLayout,QStackedLayout.Thanks a lot
-
Hi Kent:
I simplified my task, every time eye tracker return data, I update the position of ellipse. when I run this code by cmd, it warn me this "QObject::startTimer: Timers cannot be started from another thread". The whole test process is like this video, any hint?
Thank you!import os import time from PyQt5 import QtCore, QtGui, QtWidgets, QtMultimedia, QtMultimediaWidgets import tobii_research as tr import config import numpy as np from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import * class Widget(QtWidgets.QWidget): def __init__(self, parent=None): super(Widget, self).__init__(parent) self.btn_open = QtWidgets.QPushButton(self) self.btn_open.setGeometry(QtCore.QRect(100, 100, 100, 100)) self.btn_open.setObjectName("btn_open") self.btn_open.setText("Play") self.btn_open.clicked.connect(self.Play_video_2) self._scene = QtWidgets.QGraphicsScene() self.MainWindow=QMainWindow() self._gv = QtWidgets.QGraphicsView(self._scene,self.MainWindow) self.MainWindow.setCentralWidget(self._gv) self._ellipse_item=QtWidgets.QGraphicsEllipseItem(QtCore.QRectF(0, 0, 40, 40)) self._ellipse_item.setBrush(QtGui.QBrush(QtCore.Qt.black)) self._ellipse_item.setPen(QtGui.QPen(QtCore.Qt.red)) self._scene.addItem(self._ellipse_item) self.eyetrackers = tr.find_all_eyetrackers() self.my_eyetracker = self.eyetrackers[0] self.flag=1 def gaze_data_callback(self, gaze_data_): self._ellipse_item.setPos(self.flag,self.flag) self.flag+=1 def Play_video_2(self): self.my_eyetracker.subscribe_to(tr.EYETRACKER_GAZE_DATA, self.gaze_data_callback, as_dictionary=True) #self.MainWindow.showFullScreen() self.MainWindow.resize(512,512) self.MainWindow.show() if __name__ == '__main__': import sys app = QtWidgets.QApplication(sys.argv) w = Widget() w.show() sys.exit(app.exec_()) #w.my_eyetracker.unsubscribe_from(tr.EYETRACKER_GAZE_DATA, w.gaze_data_callback)
-
@Denni-0
Hi Denni:
I am sorry I didn't post in very clean way, I am in quite hurry.
I am using tobii eye tracker for get gaze data. the
GazeDataCallback is the callback function from tobii_research package, it will be called every time when eyetracker return a data, the frequency of tracker is 60hz, which mean this function will be called about every 16.7milliseconds (may slightly change because of the lantency). It is controled by subscribe_to() and unsubscribe_from() function.Thank you for you help.(taking a nap now, 4.am here. sorry for late reply in advance)
-
Hey guys:
I solved my problem.
The solution is send a signal to change the item position in callback function of eyetracker rather than directly change it in call callback function of eyetracker which is in secondary thread.
Details in this Link
cheers! -
Hi Denni:
Thank you for you reply.
Wow, I didn't realize there are many potential problem out there. I am beginner in Qt, Can you point out where should I modify my code effectively and reasonably?
I am not using the code from eyllanesc verbatim, but I do use the idea he told me — "send signal of change the QgraphicsItem position in callback function which is in eyetracker built-in thread (I don't know term of "eyetracker built-in thread" is correct or not, but I think eyetracker is a hardware which work in it's own way)"
Thank you!