eyetracker-ng 0.1-1 documentation

eyetracker.gui.functional

Contents

Source code for eyetracker.gui.functional

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#    This file is part of eyetracker-ng.
#
#    eyetracker-ng is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    eyetracker-ng is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with eyetracker-ng. If not, see <http://www.gnu.org/licenses/>.

# authors: Sasza Kijek, Karol Augustin, Tomasz Spustek
# e-mails: saszasasha@gmail.com karol@augustin.pl tomasz@spustek.pl
# University of Warsaw 2013


from itertools import izip
from PyQt4 import QtCore, QtGui

import numpy as np

from ..analysis.processing import imageFlipMirror, runningAverage

from ..camera.display import drawPupil, drawGlint
from ..camera.camera import lookForCameras
from ..camera.camera import Camera

from .graphical import Ui_StartingWindow

import os

[docs]class MyForm(QtGui.QMainWindow): ''' Functional part of GUI interface. Class governing the functional part of the default graphical user interface. Defines ------- self.cameras : list all camera devices connected to the computer, self.algorithms : list all implemented algorithms for eyetracker programm, self.resolutions : list all possible image resolutions for eyetracer to operate on, self.w : int selected width of an image to start an eyetracker, self.h : int selected height of an image to start an eyetracker, self.selectedCamera : string selected camera name as chosen by the user (default is a name of the first avalaible device), self.timer_on : boolean flag showing wether timer is ticking or not, self.config : path dictionary with all configuration variables, self.configFileName : path path to the configuration file, self.ui : class encapsulating graphical part of an interface, as described in eyetracker/gui/graphical.py file, self.camera : class encapsulating a camera device as described in eyetracker/camera/camera.py. ''' def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) self.ui = Ui_StartingWindow() self.ui.setupUi(self) self.defaults = {} self.defaults['Mirrored'] = 0 self.defaults['Fliped'] = 0 self.defaults['Alpha'] = 6. self.defaults['ResolutionIndex'] = 1 self.defaults['PupilBar'] = 0 self.defaults['NumberOfGlints'] = 2 self.defaults['NumberOfPupils'] = 1 self.defaults['Sampling'] = 30.0 self.defaults['AlgorithmIndex'] = 0 self.defaults['Additional_1'] = 1. self.defaults['Additional_2'] = 1. self.tmp = 'notgo' self.cameras = lookForCameras() for i in self.cameras.iterkeys(): self.ui.cmb_setCamera.addItem(i) #self.algorithms = ['NESW' , 'Raw output'] self.algorithms = ['Raw output'] for algorithm in self.algorithms: self.ui.cmb_setAlgorithm.addItem(algorithm) self.resolutions_w = [160,320,640,1280] self.resolutions_h = [120,240,480,720] for w, h in izip(self.resolutions_w, self.resolutions_h): self.ui.cmb_setResolution.addItem(''.join([str(w), 'x', str(h)])) self.loadSettings() self.setWidgetsState() self.w = 320 self.h = 240 self.selectedCamera = str(self.ui.cmb_setCamera.currentText()) try: self.camera = Camera(self.cameras['Camera_1'], {3 : self.w, 4 : self.h}) except KeyError: print 'No camera device detected.' self.glints_stack = np.zeros([self.config['Alpha'],3]) self.pupils_stack = np.zeros([self.config['Alpha'],3]) self.ui.timer.start(1000/self.config['Sampling'], self) self.timer_on = False self.ui.cmb_setCamera.currentIndexChanged.connect(self.cameraChange) self.ui.cmb_setResolution.currentIndexChanged.connect(self.resolutionChange) self.ui.cmb_setAlgorithm.currentIndexChanged.connect(self.algorithmChange) self.ui.btn_start.clicked.connect(self.startButtonClicked) self.ui.btn_clear.clicked.connect(self.clearSettings) self.ui.btn_save.clicked.connect(self.saveSettings) self.ui.chb_flip.stateChanged.connect(self.imageFlip) self.ui.chb_mirror.stateChanged.connect(self.imageMirror) self.ui.hsb_pupil.valueChanged[int].connect(self.hsbPupil_Change) self.ui.hsb_pupil2.valueChanged[int].connect(self.hsbPupilNumber_Change) self.ui.hsb_glint.valueChanged[int].connect(self.hsbGlint_Change) self.ui.led_alpha.editingFinished.connect(self.alphaChange) self.ui.led_additional_1.editingFinished.connect(self.additional_1Change) self.ui.led_additional_2.editingFinished.connect(self.additional_2Change)
[docs] def timerEvent(self, event): ''' Function controlling the main flow of this gui. Function fires periodically (sampling rate), grabs frames from a camera, starts image processing and displays changes in the gui. Parameters ----------- event : object standard event handler as described in QT4 documentation. ''' im = self.camera.frame() im = imageFlipMirror(im, self.config['Mirrored'], self.config['Fliped']) if self.timer_on == False: self.im = im self.timer_on = True #self.im = runningAverage(im, self.im, self.config['Alpha']) self.im = im self.pupilUpdate(self.im) self.glintUpdate(self.im) #print self.where_pupil #print self.where_pupil.shape[0] self.runEyetracker() self.update()
[docs] def setDefaultSettings(self): ''' Set GUI defaul configuration. Function sets all gui parameters to its default values. ''' self.config['Mirrored'] = self.defaults['Mirrored'] self.config['Fliped'] = self.defaults['Fliped'] self.config['Alpha'] = self.defaults['Alpha'] self.config['ResolutionIndex'] = self.defaults['ResolutionIndex'] self.config['PupilBar'] = self.defaults['PupilBar'] self.config['NumberOfGlints'] = self.defaults['NumberOfGlints'] self.config['NumberOfPupils'] = self.defaults['NumberOfPupils'] self.config['Sampling'] = self.defaults['Sampling'] self.config['AlgorithmIndex'] = self.defaults['AlgorithmIndex'] self.config['Additional_1'] = self.defaults['Additional_1'] self.config['Additional_2'] = self.defaults['Additional_2']
[docs] def setWidgetsState(self): ''' Set state of gui widgets according to self.config variable. ''' warningFlag = False try: self.ui.cmb_setAlgorithm.setCurrentIndex(self.config['AlgorithmIndex'] ) except KeyError: self.config['AlgorithmIndex'] = self.defaults['AlgorithmIndex'] self.ui.cmb_setAlgorithm.setCurrentIndex(self.defaults['AlgorithmIndex']) print 'No AlgorithmIndex in configuration file present -- loading default value.' warningFlag = True try: self.ui.cmb_setResolution.setCurrentIndex(self.config['ResolutionIndex'] ) except KeyError: self.config['ResolutionIndex'] = self.defaults['ResolutionIndex'] self.ui.cmb_setResolution.setCurrentIndex(self.defaults['ResolutionIndex']) print 'No ResolutionIndex in configuration file present -- loading default value.' warningFlag = True try: self.ui.hsb_pupil.setValue(self.config['PupilBar']) self.ui.hsb_pupil2.setValue(self.config['NumberOfPupils']) self.ui.hsb_glint.setValue(self.config['NumberOfGlints']) except KeyError: self.config['PupilBar'] = self.defaults['PupilBar'] self.config['NumberOfGlints'] = self.defaults['NumberOfGlints'] self.config['NumberOfPupils'] = self.defaults['NumberOfPupils'] self.ui.hsb_pupil.setValue(self.defaults['PupilBar']) self.ui.hsb_glint.setValue(self.defaults['NumberOfGlints']) self.ui.hsb_pupil2.setValue(self.defaults['NumberOfPupils']) print 'Either NumberOfGlints, NumberOfPupils or PupilBar (or any combination of them) not present in configuration file -- loading default values.' warningFlag = True self.ui.lbl_pupil.setText(str(self.ui.hsb_pupil.value())) self.ui.lbl_pupil2.setText(str(self.ui.hsb_pupil2.value())) self.ui.lbl_glint.setText(str(self.ui.hsb_glint.value())) try: if self.config['Mirrored'] == 1: self.ui.chb_mirror.toggle() if self.config['Fliped'] == 1: self.ui.chb_flip.toggle() except KeyError: self.config['Mirrored'] == self.defaults['Mirrored'] self.config['Fliped'] == self.defaults['Fliped'] if self.config['Mirrored'] == 1: self.ui.chb_mirror.toggle() if self.config['Fliped'] == 1: self.ui.chb_flip.toggle() print 'Either Mirrored or Fliped (or both) not present in configuration file -- loading default values.' warningFlag = True try: self.ui.led_alpha.setText(str(self.config['Alpha'])) except KeyError: self.config['Alpha'] = self.defaults['Alpha'] self.ui.led_alpha.setText(str(self.config['Alpha'])) print 'Parameter for alpha smoothing not present in configuration file -- loading default values.' warningFlag = True try: self.ui.led_additional_1.setText(str(self.config['Additional_1'])) except KeyError: self.config['Additional_1'] = self.defaults['Additional_1'] self.ui.led_additional_1.setText(str(self.config['Additional_1'])) print 'Additional_1 parameter not present in configuration file -- loading default values.' warningFlag = True try: self.ui.led_additional_2.setText(str(self.config['Additional_2'])) except KeyError: self.config['Additional_2'] = self.defaults['Additional_2'] self.ui.led_additional_2.setText(str(self.config['Additional_2'])) print 'Additional_2 parameter not present in configuration file -- loading default values.' warningFlag = True if warningFlag == True: print 'Some variables were not present in configuration file. Saving current settings should solve this issue.'
[docs] def clearSettings(self): ''' Restore GUI default configuration. Function clears all parameters saved previously in a config file and set gui to a default state. ''' self.setDefaultSettings() self.saveSettings() self.setWidgetsState()
[docs] def saveSettings(self): ''' Save GUI settings. Saves GUI parameters specified file. ''' with open(self.configFileName , 'w') as f: for key in self.config.keys(): stringToWrite = key + ' ' + str(self.config[key]) + '\n' f.write(stringToWrite)
[docs] def loadSettings(self): ''' Load GUI settings from file. Loads parameters of a programm from a specified file. If file is not present, default parameters would be loaded. ''' self.config = {} self.configFileName = os.path.expanduser("~") + '/.config/eyetracker-ng/configFile.txt' directory = self.configFileName[0 : self.configFileName.find('configFile')] if not os.path.exists(directory): os.makedirs(directory) try: with open(self.configFileName , 'r') as configFile: for line in configFile: tmp = line.split() try: self.config[str(tmp[0])] = int(tmp[1]) except ValueError: self.config[str(tmp[0])] = float(tmp[1]) except IOError: print 'No config file yet -- using defaults' self.setDefaultSettings()
[docs] def algorithmChange(self): ''' Change eyetracker algorithm. Function changing algorithm for eyetracker. ''' ind = self.ui.cmb_setAlgorithm.currentIndex() self.config['AlgorithmIndex'] = ind
[docs] def cameraChange(self): ''' Change camera between avalaible devices. ''' self.ui.timer.stop() self.camera.close() self.glints_stack = np.zeros([self.config['Alpha'],3]) self.pupils_stack = np.zeros([self.config['Alpha'],3]) self.selectedCamera = str(self.ui.cmb_setCamera.currentText()) self.camera = Camera(self.cameras[self.selectedCamera], {3 : self.w, 4 : self.h}) self.ui.timer.start(1000/self.config['Sampling'], self)
[docs] def imageMirror(self): ''' Set a variable telling the gui to mirror incomming frames from a camera. ''' if self.config['Mirrored'] == 0: self.config['Mirrored'] = 1 else: self.config['Mirrored'] = 0 #self.glints_stack = np.zeros([self.config['Alpha'],3]) #self.pupils_stack = np.zeros([self.config['Alpha'],3])
[docs] def imageFlip(self): ''' Set a variable telling the gui to flip incomming frames from a camera. ''' if self.config['Fliped'] == 0: self.config['Fliped'] = 1 else: self.config['Fliped'] = 0 #self.glints_stack = np.zeros([self.config['Alpha'],3]) #self.pupils_stack = np.zeros([self.config['Alpha'],3])
[docs] def resolutionChange(self): ''' Set a chosen resolution of a camera. It does not change an image displayed in the gui, but sets variable for eyetracker programm. ''' ind = self.ui.cmb_setResolution.currentIndex() self.config['ResolutionIndex'] = ind
[docs] def alphaChange(self): ''' Set a chosen alpha parameter for smoothing purposes. Alpha is a control parameter of the running average. It describes how many previous glint and pupil positions should be averaged. By arbitrary alpha should not exceed 10 and could not be a negative number. value : string value to be assigned to alpha parameter. It would be converted to np.float32 ''' try: alpha = float(self.ui.led_alpha.text()) except ValueError: self.ui.led_alpha.setText( str(self.config['Alpha']) ) print 'Alpha should be a floating point number!' return if alpha < 0. or alpha > 10.: self.ui.led_alpha.setText( str(self.config['Alpha']) ) print 'Alpha should be between 0.0 and 10.0!' else: self.config['Alpha'] = alpha self.glints_stack = np.zeros([self.config['Alpha'],3]) self.pupils_stack = np.zeros([self.config['Alpha'],3])
[docs] def additional_1Change(self): ''' Set a chosen additional_1 parameter for some purposes. What is additional_1 --> Sasha value : string value to be assigned to additional_1 parameter. It would be converted to np.float32 ''' try: additional_1 = float(self.ui.led_additional_1.text()) except ValueError: self.ui.led_additional_1.setText( str(1) ) # for now... #self.ui.led_additional_1.setText( str(self.config['Alpha']) ) # in future print 'Additional_1 should be a floating point number!' return if additional_1 < 0. or additional_1 > 10.: self.ui.led_additional_1.setText( str(1) ) # for now... #self.ui.led_alpha.setText( str(self.config['Alpha']) ) # in future print 'Additional_1 should be between 0.0 and 10.0!' else: #self.config['Additional_1'] = alpha # in future pass
[docs] def additional_2Change(self): ''' Set a chosen additional_2 parameter for some purposes. What is additional_2 --> Sasha value : string value to be assigned to additional_1 parameter. It would be converted to np.float32 ''' try: additional_2 = float(self.ui.led_additional_2.text()) except ValueError: self.ui.led_additional_2.setText( str(1) ) # for now... #self.ui.led_additional_2.setText( str(self.config['Alpha']) ) # in future print 'Additional_1 should be a floating point number!' return if additional_2 < 0. or additional_2 > 10.: self.ui.led_additional_2.setText( str(1) ) # for now... #self.ui.led_alpha.setText( str(self.config['Alpha']) ) # in future print 'Additional_2 should be between 0.0 and 10.0!' else: #self.config['Additional_2'] = alpha # in future pass
[docs] def hsbPupil_Change(self, value): ''' Set a text in a gui according to the possition of a slider. Parameters ----------- value : int value to be displayed in an apriopriate label ''' self.ui.lbl_pupil.setText(str(value)) self.config['PupilBar'] = value
[docs] def hsbPupilNumber_Change(self, value): ''' Set a text in a gui according to the possition of a slider. Parameters ----------- value : int value to be displayed in an apriopriate label ''' self.ui.lbl_pupil2.setText(str(value)) self.config['NumberOfPupils'] = value
[docs] def hsbGlint_Change(self, value): ''' Set a text in a gui according to the possition of a slider. Parameters ----------- value : int value to be displayed in an apriopriate label ''' self.ui.lbl_glint.setText(str(value)) self.config['NumberOfGlints'] = value
[docs] def pupilUpdate(self, image): ''' Parameters ----------- image : np.array image on which pupil should be find and marked. ''' self.pupil , self.where_pupil , self.pupils_stack = drawPupil(image , self.config['PupilBar'] , self.pupils_stack , self.config['NumberOfPupils'])
[docs] def glintUpdate(self, image): ''' Parameters ----------- image : np.array image on which glints should be find and marked. ''' self.glint , self.where_glint , self.glints_stack = drawGlint(image , self.where_pupil , self.config['NumberOfGlints'] , self.glints_stack)
[docs] def paintEvent(self, event): ''' Parameters ----------- event : object standard event handler as described in QT4 documentation. ''' painter = QtGui.QPainter(self) if self.timer_on: result_pupil = QtGui.QImage(self.pupil, self.w, self.h, QtGui.QImage.Format_RGB888).rgbSwapped() result_glint = QtGui.QImage(self.glint, self.w, self.h, QtGui.QImage.Format_RGB888).rgbSwapped() painter.drawImage(QtCore.QPoint(5, 35), result_pupil) painter.drawImage(QtCore.QPoint(5, 300), result_glint) # def closeEvent(self, event): # ''' # # Parameters # ----------- # event : object # standard event handler as described in QT4 documentation. # # '''
[docs] def startButtonClicked(self): ''' Handles the behavior of the start/stop button, based on parameters picked from gui. ''' if self.tmp == 'notgo': self.tmp = 'go' self.ui.btn_start.setText('Stop') else: self.tmp = 'notgo' self.ui.btn_start.setText('Start')
[docs] def runEyetracker(self): ''' Starts eyetracker with parameters picked from gui. ''' if self.config['AlgorithmIndex'] == 1 and self.tmp == 'go': print 'Pupil coordinates: {}.'.format(self.where_pupil) print 'Glint coordinates: {}.'.format(self.where_glint)

Contents