0

I am involving in a gaze-contingent display project, and need to customize a blur style Qbrush. I have tried using QGraphicsBlurEffect to achieve my purpose, However, when using QGraphicsBlurEffect to a huge QGraphicsEllipseItem (circle, radius>2500px), the rendering delay becomes obvious, I have tested QGraphicsBlurEffect to relatively small QGraphicsItem, It's work well. so I want to define my own blur style Qbrush. Below is Demo Code.

import sys
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QGraphicsBlurEffect
import tobii_research as tr

class Demo(QWidget):
    GazepositionChanged = QtCore.pyqtSignal(float, float)
    def __init__(self):
        super(QWidget,self).__init__()
        self.eyetrackers = tr.find_all_eyetrackers()
        self.my_eyetracker = self.eyetrackers[0]
        self.initUI()

    def initUI(self):

        self.setGeometry(300, 300, 680, 480)#ignore
        self.setWindowTitle('DEMO')
        self.videosize = QtCore.QSizeF(1920 - 3, 1080 - 3)

        self._gv = QtWidgets.QGraphicsView()
        self._scene = QtWidgets.QGraphicsScene(0, 0, self.videosize.width(), self.videosize.height(), self._gv)
        self._gv.setScene(self._scene)

        #button setup
        self.pushButton_Start = QtWidgets.QPushButton(self._gv)
        self.pushButton_Start.setText("Start Test")
        self.pushButton_Start.move(1920/2-150, 540)
        self.pushButton_END = QtWidgets.QPushButton(self._gv)
        self.pushButton_END.setText("END Test")
        self.pushButton_END.move(1920/2+70, 540)
        self.pushButton_Start.clicked.connect(self.Start)
        self.pushButton_END.clicked.connect(self.END)

        #denote where is watching on display
        self.GazeItem = QtWidgets.QGraphicsEllipseItem(QtCore.QRectF(0,0, 500, 500))
        self.GazeItem.setPen(QtGui.QPen(QtCore.Qt.gray))
        # Blur effect, Not good for large GraphicsItem
        # blureffect=QGraphicsBlurEffect()
        # blureffect.setBlurRadius(10)
        # blureffect.setBlurHints(QGraphicsBlurEffect.AnimationHint)
        # self.GazeItem.setGraphicsEffect(blureffect)
        self._scene.addItem(self.GazeItem)

        #TODO:I want to customize a Brushstyle with blureffect here.
        ##
        QCustomized_Brush = self.Create_BrushStyle()
        self.GazeItem.setBrush(QCustomized_Brush)
        ###

        self.GazepositionChanged.connect(self.GazeItem.setPos)
        self._gv.showFullScreen()

    def gaze_data_callback(self, gaze_data_):
        #callback function, 60 times per second.
        gaze_left_eye = gaze_data_['left_gaze_point_on_display_area']
        leftx_Oringinal = gaze_left_eye[0]
        lefty_Oringinal = gaze_left_eye[1]
        Gaze = [leftx_Oringinal, lefty_Oringinal]
        Screensize = [1920, 1080]
        self.GazepositionChanged.emit(Gaze[0] * Screensize[0] - 250, Gaze[1] * Screensize[1] - 250)#update QGraphicItem position


    def Start(self):
        self.my_eyetracker.subscribe_to(tr.EYETRACKER_GAZE_DATA, self.gaze_data_callback, as_dictionary=True)
        self.pushButton_Start.setEnabled(False)
        self.pushButton_END.setEnabled(True)

    def END(self):
        self.my_eyetracker.unsubscribe_from(tr.EYETRACKER_GAZE_DATA, self.gaze_data_callback)
        self.pushButton_Start.setEnabled(True)
        self.pushButton_END.setEnabled(False)

    def Create_Brush(self):
        #Create Qbrush with blur style
        #return brush
        pass

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Demo()
    sys.exit(app.exec_())

The Low-performance case is show below:

import sys
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QGraphicsBlurEffect
import tobii_research as tr

class Demo(QWidget):
    GazepositionChanged = QtCore.pyqtSignal(float, float)
    def __init__(self):
        super(QWidget,self).__init__()
        self.eyetrackers = tr.find_all_eyetrackers()
        self.my_eyetracker = self.eyetrackers[0]
        self.initUI()

    def initUI(self):

        self.setGeometry(300, 300, 680, 480)#ignore
        self.setWindowTitle('DEMO')
        self.videosize = QtCore.QSizeF(1920 - 3, 1080 - 3)

        self._gv = QtWidgets.QGraphicsView()
        self._scene = QtWidgets.QGraphicsScene(0, 0, self.videosize.width(), self.videosize.height(), self._gv)
        self._gv.setScene(self._scene)

        #button setup
        self.pushButton_Start = QtWidgets.QPushButton(self._gv)
        self.pushButton_Start.setText("Start Test")
        self.pushButton_Start.move(1920/2-150, 540)
        self.pushButton_END = QtWidgets.QPushButton(self._gv)
        self.pushButton_END.setText("END Test")
        self.pushButton_END.move(1920/2+70, 540)
        self.pushButton_Start.clicked.connect(self.Start)
        self.pushButton_END.clicked.connect(self.END)

        #denote where is watching on display
        self.GazeItem = QtWidgets.QGraphicsEllipseItem(QtCore.QRectF(0,0, 5500, 5500))
        self.GazeItem.setPen(QtGui.QPen(QtCore.Qt.gray))
        self.GazeItem.setStartAngle(180 * 16)
        self.GazeItem.setSpanAngle(180 * 16)
        blureffect=QGraphicsBlurEffect()
        blureffect.setBlurRadius(10)
        blureffect.setBlurHints(QGraphicsBlurEffect.AnimationHint)
        self.GazeItem.setGraphicsEffect(blureffect)
        self._scene.addItem(self.GazeItem)
        self.GazeItem.setBrush(QtGui.QBrush(QtCore.Qt.gray))

        self.GazepositionChanged.connect(self.GazeItem.setPos)
        self._gv.showFullScreen()

    def gaze_data_callback(self, gaze_data_):
        #callback function, 60 times per second.
        gaze_left_eye = gaze_data_['left_gaze_point_on_display_area']
        leftx_Oringinal = gaze_left_eye[0]
        lefty_Oringinal = gaze_left_eye[1]
        Gaze = [leftx_Oringinal, lefty_Oringinal]
        Screensize = [1920, 1080]
        self.GazepositionChanged.emit(Gaze[0] * Screensize[0] - 2750, Gaze[1] * Screensize[1] - 2750)#update QGraphicItem position

    def Start(self):
        self.my_eyetracker.subscribe_to(tr.EYETRACKER_GAZE_DATA, self.gaze_data_callback, as_dictionary=True)
        self.pushButton_Start.setEnabled(False)
        self.pushButton_END.setEnabled(True)

    def END(self):
        self.my_eyetracker.unsubscribe_from(tr.EYETRACKER_GAZE_DATA, self.gaze_data_callback)
        self.pushButton_Start.setEnabled(True)
        self.pushButton_END.setEnabled(False)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Demo()
    sys.exit(app.exec_())
M conrey
  • 45
  • 5
  • Is it necessary that you use "tobii_research" in your MRE ?, I think not because it only complicates your example, I recommend you delete everything related to it. On the other hand you point out that your brush-style does not work for certain cases, you could show an example of that – eyllanesc Jul 09 '20 at 14:36
  • Like I mentioned, I used Gaze-Contingent paradigm, tobii_research is the package to access data returned by eye-tracker ,in my case, the QGraphicsEllipseItem will update position 60 times per second according to gaze data. I thought for large Qgraphicsitem, the blureffect increase the rendering latency, thereby result in the rendering time greater than the refresh time, which finally lead to lag movement of Qgraphicsitem.(i.e. not work well). The low-performance code is added to question. Thank you. – M conrey Jul 09 '20 at 15:12
  • As he points out: I don't think "eyetrackers" is necessary since it complicates the reproducibility of your code. Why don't you create a class that generates the positions (randomly) every T sec using a QTimer? – eyllanesc Jul 09 '20 at 15:15

0 Answers0