Python 如何在播放视频时通过PyQt从眼动跟踪器中提取眼睛注视数据

Python 如何在播放视频时通过PyQt从眼动跟踪器中提取眼睛注视数据,python,pyqt,pyqt5,eye-tracking,Python,Pyqt,Pyqt5,Eye Tracking,我正在开发一个眼睛注视可视化工具,就像PyQt5一样,我也检查了这个。 下面是修改上述链接的代码。 结果证明它是有效的,但视频总是在某些时候被卡住(音频是正常的,帧被卡住了,视频内容和椭圆,就像这样),有人能帮忙吗 import os import time from PyQt5 import QtCore, QtGui, QtWidgets, QtMultimedia, QtMultimediaWidgets import tobii_research as tr import numpy

我正在开发一个眼睛注视可视化工具,就像PyQt5一样,我也检查了这个。 下面是修改上述链接的代码。 结果证明它是有效的,但视频总是在某些时候被卡住(音频是正常的,帧被卡住了,视频内容和椭圆,就像这样),有人能帮忙吗

import os
import time

from PyQt5 import QtCore, QtGui, QtWidgets, QtMultimedia, QtMultimediaWidgets
import tobii_research as tr
import numpy as np

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)))
        print(f"self._videoitem::{self._videoitem.size()}")

        #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(0, 300))), float(np.random.choice(range(0, 240))))
        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._gv.resize(720,720)
        self._gv.show()
        self._player.play()


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())
cmd打印输出信息在这里


根据警告信息:

QObject::startTimer: Timers can only be used with threads started with QThread
可以推断,与“my_eyetracker”关联的回调是在辅助线程中执行的,因此项目从不同线程到主线程的位置将被更新,这可能会产生OP描述的问题

解决方案是通过信号向向导发送回调信息

导入操作系统
导入时间
从PyQt5导入QtCore、QtGui、QtWidgets、QtMultimedia、QtMultimediaWidgets
将tobii_研究作为tr导入
将numpy作为np导入
类眼动跟踪器(QtCore.QObject):
位置更改=QtCore.pyqtSignal(浮动,浮动)
def uuu init uuuu(self,tracker,parent=None):
超级(眼睛跟踪器,自我)。\uuuuu初始化\uuuuuuuuu(父级)
self.\u tracker=跟踪器
@财产
def跟踪器(自身):
返回自我
def启动(自):
self.tracker.subscribe\u(
tr.EYETRACKER\u GAZE\u DATA,self.\u回调,as\u dictionary=True
)
def_回调(自身、凝视_数据):
self.positionChanged.emit(
浮动(np.随机选择(范围(0,300)),
浮动(np.随机选择(范围(0240)),
)
打印(“time.time():{}”。格式(time.time())
类小部件(qtwidts.QWidget):
def uuu init uuu(self,parent=None):
超级(小部件,自我)。\uuuuu初始化\uuuuuuu(父级)
#第一个窗口,只有一个播放视频的按钮
自我调整大小(256256)
self.btn_play=qtwidts.QPushButton(self)
self.btn_play.setGeometry(QtCore.QRect(10010028))
self.btn_play.setObjectName(“btn_打开”)
self.btn_play.setText(“play”)
self.btn_play.clicked.connect(self.play_video)#单击播放视频
#
self.\u scene=qtwidts.qgraphicscene(self)
self.\u gv=qtwidts.QGraphicsView(self.\u场景)
#构建用于显示视频的视频项
self.\u videoitem=QtMultimediaWidgets.QGraphicsVideoItem()
#将其添加到场景中
self.\u场景.附加项(self.\u视频项)
#assign _ellipse _item是凝视数据,并将其嵌入到videoitem中,以便它可以显示在视频上方。
self.\u ellipse\u item=QtWidgets.qGraphicsSellipseitem(
QtCore.QRectF(0,0,40,40),self.\u videoitem
)
self._椭圆_item.setBrush(QtGui.QBrush(QtCore.Qt.black))
self._椭圆_item.setPen(QtGui.QPen(QtCore.Qt.red))
#self.\u scene.addItem(self.\u椭圆\u项)
自装配视图(自装配项目)
self.\u player=qtmedia.QMediaPlayer(
self,qtmedia.QMediaPlayer.VideoSurface
)
self.\u player.setVideoOutput(self.\u videoitem)
file=os.path.join(
os.path.dirname(_文件__),“video.mp4”
)#video.mp4位于同一目录下
self.\u player.setMedia(
qtmedia.QMediaContent(QtCore.QUrl.fromLocalFile(文件))
)
打印(f“self.\u videoitem::{self.\u videoitem.size()}”)
#获取眼动跟踪器
eyetrackers=tr.find_all_eyetrackers()
self.tracker=EyeTracker(eyetrackers[0])
self.tracker.positionChanged.connect(self.\u eliple\u item.setPos)
def播放视频(自):
self.tracker.start()
#size=QtCore.QSizeF(1920.01080.0)#我希望它能全屏显示视频
#自身项目设置大小(尺寸)
#self._gv.showFullScreen()
自我调整大小(720720)
self._gv.show()
self.\u player.play()
如果名称=“\uuuuu main\uuuuuuuu”:
导入系统
app=qtwidts.QApplication(sys.argv)
w=Widget()
w、 show()
sys.exit(app.exec_())

根据警告信息:

QObject::startTimer: Timers can only be used with threads started with QThread
可以推断,与“my_eyetracker”关联的回调是在辅助线程中执行的,因此项目从不同线程到主线程的位置将被更新,这可能会产生OP描述的问题

解决方案是通过信号向向导发送回调信息

导入操作系统
导入时间
从PyQt5导入QtCore、QtGui、QtWidgets、QtMultimedia、QtMultimediaWidgets
将tobii_研究作为tr导入
将numpy作为np导入
类眼动跟踪器(QtCore.QObject):
位置更改=QtCore.pyqtSignal(浮动,浮动)
def uuu init uuuu(self,tracker,parent=None):
超级(眼睛跟踪器,自我)。\uuuuu初始化\uuuuuuuuu(父级)
self.\u tracker=跟踪器
@财产
def跟踪器(自身):
返回自我
def启动(自):
self.tracker.subscribe\u(
tr.EYETRACKER\u GAZE\u DATA,self.\u回调,as\u dictionary=True
)
def_回调(自身、凝视_数据):
self.positionChanged.emit(
浮动(np.随机选择(范围(0,300)),
浮动(np.随机选择(范围(0240)),
)
打印(“time.time():{}”。格式(time.time())
类小部件(qtwidts.QWidget):
def uuu init uuu(self,parent=None):
超级(小部件,自我)。\uuuuu初始化\uuuuuuu(父级)
#第一个窗口,只有一个播放视频的按钮
自我调整大小(256256)
self.btn_play=qtwidts.QPushButton(self)
self.btn_play.setGeometry(QtCore.QRect(10010028))
self.btn_play.setObjectName(“btn_打开”)
self.btn_play.setText(“play”)
self.btn_play.clicked.connect(self.play_video)#单击播放视频
#
self.\u scene=qtwidts.qgraphicscene(self)
self.\u gv=qtwidts.QGraphicsView(self.\u场景)
#构建用于显示视频的视频项
self.\u videoitem=QtMultimediaWidgets.QGraphicsVideoItem()
#将其添加到场景中
self.\u scene.addI