コード例 #1
0
    def calibrate(self):
        # instantiate calibration object
        self.cal = tr.ScreenBasedCalibration(self.tracker)
        self.cal.enter_calibration_mode()  # enter calibration mode

        for row, col in list(zip(self.r, self.c)):
            img = np.zeros([self.ht, self.wd])  # initialize images with zeros
            img[row - self.point_size:row + self.point_size,
                col - self.point_size:col + self.point_size] = 255.

            row, col = float(row) / self.ht, float(
                col) / self.wd  # normalize the points for calibration

            cv2.namedWindow('test', cv2.WINDOW_NORMAL)
            cv2.imshow('test', img)
            cv2.waitKey(800)

            #if cal.collect_data(col, row) != tr.CALIBRATION_STATUS_SUCCESS:
            self.cal.collect_data(col, row)

        result = self.cal.compute_and_apply()

        print "Compute and apply returned {0} and collected at {1} points.".\
        format(result.status, len(result.calibration_points))

        self.cal.leave_calibration_mode()
        cv2.destroyAllWindows()

        return result.status, len(result.calibration_points)
コード例 #2
0
    def __init__(self, win, id=0, filename="gaze_TOBII_output.tsv"):
        self.eyetracker_id = id
        self.win = win
        self.filename = filename
        self.numkey_dict = self._default_numkey_dict
        self.calibration_dot_size = self._default_calibration_dot_size[
            self.win.units]
        self.calibration_disc_size = self._default_calibration_disc_size[
            self.win.units]

        eyetrackers = tr.find_all_eyetrackers()

        if len(eyetrackers) == 0:
            raise RuntimeError("No Tobii eyetrackers")

        try:
            self.eyetracker = eyetrackers[self.eyetracker_id]
        except:
            raise ValueError(
                "Invalid eyetracker ID {}\n({} eyetrackers found)".format(
                    self.eyetracker_id, len(eyetrackers)))

        self.calibration = tr.ScreenBasedCalibration(self.eyetracker)
        self.update_calibration = self._update_calibration_auto
        self.gaze_data = []
コード例 #3
0
def notifications(eyetracker):
    all_notifications = \
        (tr.EYETRACKER_NOTIFICATION_CONNECTION_LOST,
         tr.EYETRACKER_NOTIFICATION_CONNECTION_RESTORED,
         tr.EYETRACKER_NOTIFICATION_CALIBRATION_MODE_ENTERED,
         tr.EYETRACKER_NOTIFICATION_CALIBRATION_MODE_LEFT,
         tr.EYETRACKER_NOTIFICATION_CALIBRATION_CHANGED,
         tr.EYETRACKER_NOTIFICATION_TRACK_BOX_CHANGED,
         tr.EYETRACKER_NOTIFICATION_DISPLAY_AREA_CHANGED,
         tr.EYETRACKER_NOTIFICATION_GAZE_OUTPUT_FREQUENCY_CHANGED,
         tr.EYETRACKER_NOTIFICATION_EYE_TRACKING_MODE_CHANGED,
         tr.EYETRACKER_NOTIFICATION_DEVICE_FAULTS,
         tr.EYETRACKER_NOTIFICATION_DEVICE_WARNINGS)

    # Subscribe to all notifications.
    for notification in all_notifications:
        eyetracker.subscribe_to(notification,
                                lambda x, notification=notification:
                                notification_callback(notification, x))
        print(
            "Subscribed to {0} for eye tracker with serial number {1}.".format(
                notification, eyetracker.serial_number))

    # Trigger some notifications
    calibration = tr.ScreenBasedCalibration(eyetracker)

    calibration.enter_calibration_mode()

    calibration.leave_calibration_mode()

    # Unsubscribe from notifications.
    for notification in all_notifications:
        eyetracker.unsubscribe_from(notification)
        print("Unsubscribed from {0}.".format(notification))
コード例 #4
0
def execute(eyetracker):
    global time, tr

    if eyetracker is None:
        return

    # キャリブレーションモードに切り替える
    calibration = tr.ScreenBasedCalibration(eyetracker)
    calibration.enter_calibration_mode()
    print(('Entered calibration mode for eye tracker with serial number {0}.').format(
        eyetracker.serial_number))

    # キャリブレーションのための点を表示する座標
    points_to_calibrate = [(0.5, 0.5), (0.1, 0.1),
                           (0.1, 0.9), (0.9, 0.1), (0.9, 0.9)]

    for point in points_to_calibrate:
        print(('Show a point on screen at {0}.').format(point))
        draw_caribration_points(point)

        print(('Collecting data at {0}.').format(point))

        # 視線をキャリブレートする
        if calibration.collect_data(point[0], point[1]) != tr.CALIBRATION_STATUS_SUCCESS:
            calibration.collect_data(point[0], point[1])

    # キャリブレーションの結果を表示
    print('Computing and applying calibration.')
    calibration_result = calibration.compute_and_apply()
    print(('Compute and apply returned {0} and collected at {1} points.').
          format(calibration_result.status, len(calibration_result.calibration_points)))

    # キャリブレーションモードに終了
    calibration.leave_calibration_mode()
    print('Left calibration mode.')
コード例 #5
0
def execute(eyetracker):
    if eyetracker is None:
        return

    # <BeginExample>
    import time
    import tobii_research as tr

    calibration = tr.ScreenBasedCalibration(eyetracker)

    # Enter calibration mode.
    calibration.enter_calibration_mode()
    print("Entered calibration mode for eye tracker with serial number {0}.".
          format(eyetracker.serial_number))

    # Define the points on screen we should calibrate at.
    # The coordinates are normalized, i.e. (0.0, 0.0) is the upper left corner and (1.0, 1.0) is the lower right corner.
    points_to_calibrate = [(0.5, 0.5), (0.1, 0.1), (0.1, 0.9), (0.9, 0.1),
                           (0.9, 0.9)]

    for point in points_to_calibrate:
        print("Show a point on screen at {0}.".format(point))

        # Wait a little for user to focus.
        time.sleep(0.7)

        print("Collecting data at {0}.".format(point))
        if calibration.collect_data(point[0],
                                    point[1]) != tr.CALIBRATION_STATUS_SUCCESS:
            # Try again if it didn't go well the first time.
            # Not all eye tracker models will fail at this point, but instead fail on ComputeAndApply.
            calibration.collect_data(point[0], point[1])

    print("Computing and applying calibration.")
    calibration_result = calibration.compute_and_apply()
    print("Compute and apply returned {0} and collected at {1} points.".format(
        calibration_result.status, len(calibration_result.calibration_points)))

    # Analyze the data and maybe remove points that weren't good.
    recalibrate_point = (0.1, 0.1)
    print("Removing calibration point at {0}.".format(recalibrate_point))
    calibration.discard_data(recalibrate_point[0], recalibrate_point[1])

    # Redo collection at the discarded point
    print("Show a point on screen at {0}.".format(recalibrate_point))
    calibration.collect_data(recalibrate_point[0], recalibrate_point[1])

    # Compute and apply again.
    print("Computing and applying calibration.")
    calibration_result = calibration.compute_and_apply()
    print("Compute and apply returned {0} and collected at {1} points.".format(
        calibration_result.status, len(calibration_result.calibration_points)))

    # See that you're happy with the result.

    # The calibration is done. Leave calibration mode.
    calibration.leave_calibration_mode()

    print("Left calibration mode.")
コード例 #6
0
    def __init__(self, win, id=0, filename='gaze_TOBII_output.tsv'):
        """Tobii controller for PsychoPy.

            tobii_research are required for this module.

        Args:
            win: psychopy.visual.Window object.
            id: the id of eyetracker.
            filename: the name of the data file.

        Attributes:
            shrink_speed: the shrinking speed of target in calibration.
                Defaults to 1.5.
            calibration_dot_size: the size of the central dot in the
                calibration target. Defaults to default_calibration_dot_size
                according to the units of self.win.
            calibration_dot_color: the color of the central dot in the
                calibration target. Defaults to grey.
            calibration_disc_size: the size of the disc in the
                calibration target. Defaults to default_calibration_disc_size
                according to the units of self.win.
            calibration_disc_color: the color of the disc in the
                calibration target. Defaults to deep blue.
            calibration_target_min: the minimum size of the calibration target.
                Defaults to 0.2.
            numkey_dict: keys used for calibration. Defaults to the number pad.
            update_calibration: the presentation of calibration target.
                Defaults to auto calibration.
        """
        self.eyetracker_id = id
        self.win = win
        self.filename = filename
        self._calibration_dot_size = default_calibration_dot_size[self.win.
                                                                  units]
        self._calibration_disc_size = default_calibration_disc_size[self.win.
                                                                    units]
        self.calibration_dot_size = self._calibration_dot_size
        self.calibration_disc_size = self._calibration_disc_size
        self.calibration_dot_color = self._calibration_dot_color
        self.calibration_disc_color = self._calibration_disc_color
        self.calibration_target_min = self._calibration_target_min

        eyetrackers = tr.find_all_eyetrackers()

        if len(eyetrackers) == 0:
            raise RuntimeError('No Tobii eyetrackers')

        try:
            self.eyetracker = eyetrackers[self.eyetracker_id]
        except:
            raise ValueError(
                'Invalid eyetracker ID {}\n({} eyetrackers found)'.format(
                    self.eyetracker_id, len(eyetrackers)))

        self.calibration = tr.ScreenBasedCalibration(self.eyetracker)
        self.update_calibration = self._update_calibration_auto
        self.gaze_data = []
コード例 #7
0
ファイル: __init__.py プロジェクト: savuzmir/psxeff
    def __init__(self, win, id=0):
        """
        Initialize tobii_controller object.
        
        :param win: PsychoPy Window object.
        :param int id: ID of Tobii unit to connect with.
            Default value is 0.
        """

        self.eyetracker_id = id
        self.win = win

        self.calibration_target_dot_size = default_calibration_target_dot_size[
            self.win.units]
        self.calibration_target_disc_size = default_calibration_target_disc_size[
            self.win.units]
        self.calibration_target_dot = psychopy.visual.Circle(
            self.win,
            radius=self.calibration_target_dot_size,
            fillColor='white',
            lineColor=None,
            lineWidth=1,
            autoLog=False)
        self.calibration_target_disc = psychopy.visual.Circle(
            self.win,
            radius=self.calibration_target_disc_size,
            fillColor='lime',
            lineColor='white',
            lineWidth=1,
            autoLog=False)
        self.update_calibration = self.update_calibration_default
        if self.win.units == 'norm':  # fix oval
            self.calibration_target_dot.setSize(
                [float(self.win.size[1]) / self.win.size[0], 1.0])
            self.calibration_target_disc.setSize(
                [float(self.win.size[1]) / self.win.size[0], 1.0])

        eyetrackers = tobii_research.find_all_eyetrackers()

        if len(eyetrackers) == 0:
            raise RuntimeError('No Tobii eyetrackers')

        try:
            self.eyetracker = eyetrackers[self.eyetracker_id]
        except:
            raise ValueError(
                'Invalid eyetracker ID {}\n({} eyetrackers found)'.format(
                    self.eyetracker_id, len(eyetrackers)))

        self.calibration = tobii_research.ScreenBasedCalibration(
            self.eyetracker)
コード例 #8
0
def execute (eyetracker):
    if eyetracker is None:"
        return
    
    import time
    import tobii_research as tr

    calibration = tr.ScreenBasedCalibration(eyetracker)

    #Inicia calibragem
    calibration.enter_calibration_mode()
    print("Serial Number do disposítivo Eye Tracker{0}.".format(eyetracker.serial_number))

    #Define os pontos da tela onde devemos calibrar
    #As coordenadas padrão são (0.0 , 0.0) sendo o lado superior esquero e (1.0 , 1.0) o lado inferior direito
    points_to_calibrate = [(0.5, 0.5), (0.1, 0.1), (0.1, 0.9), (0.9, 0.1), (0.9, 0.9)]

    for point in points_to_calibrate:
    print("Mostre um ponto na tela em {0}.".format(point))

    #Esperar um pouco para o usuário focar no ponto
    time.sleep(0.7)

    print("Coletando dados em {0}.".format(point) )
    if calibration.collect_data(point[0], point[1]) != tr.CALIBRATION_STATUS_SUCCESS:
    #Tente novamente se não deu certo na primeira vez
    #Nem todos os eye trackers irão falhar nesse ponto, porém, é bom fazer um fail safe
        calibration.collect_data(point[0], point[1])

        print("Calculando e aplicando calibragem.")
        calibration_result = calibration.compute_and_apply()
        print("Calculado e aplicado retornado em {0} e colletado em {1} pontos.".format(calibration_result.status, len(calibration_result.calibration_points)))

    #Analise os dados e talvez remova os pontos que não são bons.
    recalibrate_point = (0.1. 0.1)
    print ("Removendo pontos de calibração em {0}.".format(recalibrate_point))
    calibration.discard_data(recalibrate_point[0], recalibrate_point[1])

    #Calcule e aplique novamente
    print("Calculando e aplicando calibragem.")
    calibration_result = calibration.compute_and_apply()
    print("Calculado e aplicado retornado em {0} e colletado em {1} pontos.".format(calibration_result.status, len(calibration_result.calibration_points)))

    #verifique se você está satisfeito com o resultado

    #Agora que a calibragem está completa, saia do modo de calibragem.
    calibragem.leave_calibration_mode()

    print("Saindo no modo de Calibragem.")
コード例 #9
0
    def exec_calibration(self):
        calibration = tr.ScreenBasedCalibration(self.eyetracker)
        calibration.enter_validation_mode()
        points = [(0.5, 0.5), (0.1, 0.1), (0.1, 0.9), (0.9, 0.1), (0.9, 0.9)]

        for point in points:
            print("Show a point on screen at {0}.".format(point))
            time.sleep(0.7)
            if calibration.compute_and_apply(
            ).status != tr.CALIBRATION_STATUS_SUCCESS:
                calibration.collect_data(point[0], point[1])
        print("Apply calibration.")
        result = calibration.compute()
        print("result:{}".format(result.status))
        calibration.leave_validation_mode()
        print("Completed calibration.")
コード例 #10
0
    def calibrate(self):
        """
        画面上5点でキャリブレーションを行う.
        :return:
        """
        calibrator = tb.ScreenBasedCalibration(self.eye_tracker)
        calibrator.enter_calibration_mode()

        if tb.EYETRACKER_NOTIFICATION_CALIBRATION_MODE_ENTERED:
            print("calibration mode")
        else:
            print("oops, something occurred. terminating the program")

        is_data_collected = False
        for i in range(5):
            while not is_data_collected:
                print("Calibration at the point " + str(i + 1))
                self.screen.fill((0, 0, 0))
                x, y = self.calibration_points[i]
                # pygame.draw.circle(self.screen, color=(255, 255, 255), center=(20, 20), radius=10)
                # pygame.draw.circle(self.screen, color=(255, 255, 255), center=(1900, 1080), radius=10)
                pygame.draw.circle(self.screen,
                                   color=(255, 255, 255),
                                   center=(x, y),
                                   radius=10)
                pygame.display.update()
                time.sleep(1.0)
                calibration_status = calibrator.collect_data(x, y)
                time.sleep(2.0)

                is_data_collected = calibration_status == "calibration_status_success"
            is_data_collected = False
            #TODO: 画面上の点を見るように指示をだす
        calibration_result = calibrator.compute_and_apply()
        if calibration_result is None:
            print("calibration failed")
        else:
            print("probably went well")
        pygame.quit()
        calibrator.leave_calibration_mode()
コード例 #11
0
    def cali_start(self):
        global EYE_TRACKER

        if EYE_TRACKER is None:
            self.finish_cali = True
            return

        time.sleep(1.0)

        calibration = tr.ScreenBasedCalibration(EYE_TRACKER)

        # Enter calibration mode.
        calibration.enter_calibration_mode()
        logging.info(
            "Entered calibration mode for eye tracker with serial number {0}.".
            format(EYE_TRACKER.serial_number))

        for (x, y) in zip(
            [0.2, 0.2, 0.5, 0.8, 0.8], [0.2, 0.8, 0.5, 0.2, 0.8]
        ):  # for (x, y) in zip([0.1, 0.1, 0.5, 0.9, 0.9], [0.1, 0.9, 0.5, 0.1, 0.9]):
            self.show_point(x * SCREEN_X, y * SCREEN_Y)

            time.sleep(0.7)
            if calibration.collect_data(x, y) != tr.CALIBRATION_STATUS_SUCCESS:
                # Try again if it didn't go well the first time.
                calibration.collect_data(x, y)
            time.sleep(0.3)

        try:
            self.cali_result = calibration.compute_and_apply()
            logging.info(
                "Compute and apply returned {0} and collected at {1} points.".
                format(self.cali_result.status,
                       len(self.cali_result.calibration_points)))

        except ValueError:
            logging.error("Calibration failed")

        calibration.leave_calibration_mode()
        self.finish_cali = True
コード例 #12
0
# Find Eye Tracker
ft = tr.find_all_eyetrackers()
#if len(ft) == 0:
#    print "No Eye Trackers found!?"
#    exit(1)

while len(ft) == 0:
    print "No Eye Trackers found!? - retry in 5 seconds..."
    time.sleep(5)
    ft = tr.find_all_eyetrackers()

# Pick first tracker
mt = ft[0]
print "Found Tobii Tracker at '%s'" % (mt.address)

calibration = tr.ScreenBasedCalibration(mt)

# Enter calibration mode.
calibration.enter_calibration_mode()
print "Enter Calibration for EyeTracker at '%s'" % (mt.address)

# Define the points on screen we should calibrate at.
# The coordinates are normalized, i.e. (0.0, 0.0) is the upper left corner and (1.0, 1.0) is the lower right corner.
points_to_calibrate = [(0.5, 0.5), (0.1, 0.1), (0.1, 0.9), (0.9, 0.1),
                       (0.9, 0.9)]

for point in points_to_calibrate:
    print("Show a point on screen at {0}.".format(point))

    # Wait a little for user to focus.
    time.sleep(1)
コード例 #13
0
    def initCalibration(self, Visu):

        self.RecSound = libsound.Sound(
            soundfile='/home/eyetracker/Downloads/2.wav')

        self.calibrated_point = []
        self._write_enabled = False
        self.start_recording()
        self.screen.set_background_colour(colour=(0, 0, 0))
        origin = (int(self.disp.dispsize[0] / 4),
                  int(self.disp.dispsize[1] / 4))
        size = (int(2 * self.disp.dispsize[0] / 4),
                int(2 * self.disp.dispsize[1] / 4))

        while not self.kb.get_key(keylist=['space'], flush=False)[0]:
            gaze_sample = copy.copy(self.gaze[-1])

            self.screen.clear()

            validity_colour = (255, 0, 0)
            col = 'red'
            Visu.effacer_mouvement()

            if gaze_sample['right_gaze_origin_validity'] and gaze_sample[
                    'left_gaze_origin_validity']:
                left_validity = 0.15 < gaze_sample[
                    'left_gaze_origin_in_trackbox_coordinate_system'][2] < 0.85
                right_validity = 0.15 < gaze_sample[
                    'right_gaze_origin_in_trackbox_coordinate_system'][2] < 0.85
                if left_validity and right_validity:
                    validity_colour = (0, 255, 0)
                    col = 'green'
            self.screen.draw_line(colour=validity_colour,
                                  spos=origin,
                                  epos=(origin[0] + size[0], origin[1]),
                                  pw=1)
            self.screen.draw_line(colour=validity_colour,
                                  spos=origin,
                                  epos=(origin[0], origin[1] + size[1]),
                                  pw=1)
            self.screen.draw_line(colour=validity_colour,
                                  spos=(origin[0], origin[1] + size[1]),
                                  epos=(origin[0] + size[0],
                                        origin[1] + size[1]),
                                  pw=1)

            self.screen.draw_line(colour=validity_colour,
                                  spos=(origin[0] + size[0],
                                        origin[1] + size[1]),
                                  epos=(origin[0] + size[0], origin[1]),
                                  pw=1)

            right_eye, left_eye, distance = None, None, []
            if gaze_sample['right_gaze_origin_validity']:
                right_eye = (
                    (1 - gaze_sample[
                        'right_gaze_origin_in_trackbox_coordinate_system'][0])
                    * size[0] + origin[0], gaze_sample[
                        'right_gaze_origin_in_trackbox_coordinate_system'][1] *
                    size[1] + origin[1])
                self.screen.draw_circle(colour=validity_colour,
                                        pos=right_eye,
                                        r=int(self.disp.dispsize[0] / 100),
                                        pw=5,
                                        fill=True)
                Visu.Show_droit(right_eye[0], right_eye[1], col,
                                int(self.disp.dispsize[0] / 200))

            if gaze_sample['left_gaze_origin_validity']:
                left_eye = (
                    (1 - gaze_sample[
                        'left_gaze_origin_in_trackbox_coordinate_system'][0]) *
                    size[0] + origin[0], gaze_sample[
                        'left_gaze_origin_in_trackbox_coordinate_system'][1] *
                    size[1] + origin[1])
                self.screen.draw_circle(colour=validity_colour,
                                        pos=left_eye,
                                        r=int(self.disp.dispsize[0] / 100),
                                        pw=5,
                                        fill=True)
                Visu.Show_gauche(left_eye[0], left_eye[1], col,
                                 int(self.disp.dispsize[0] / 200))

            Visu.VisuShow()
            self.disp.fill(self.screen)
            self.disp.show()

            if self.kb.get_key(keylist=['tab'], flush=False)[0]:
                self.screen.clear()
                self.disp.fill(self.screen)
                self.disp.show()
                Visu.effacer_mouvement()
                Visu.VisuShow()
                return ()
        Visu.effacer_mouvement()
        Visu.VisuShow()

        # # # # # #
        # # calibration
        self.screen.clear()

        if not self.eyetracker:

            print(
                "WARNING! libtobii.TobiiProTracker.calibrate: no eye trackers found for the calibration!"
            )
            self.stop_recording()

            return False

        self.calibration = tr.ScreenBasedCalibration(self.eyetracker)
        self.disp.show()
        self.calibration.enter_calibration_mode()
        self.RecSound.play()
コード例 #14
0
    def calibrate(self, calibrate=True, validate=True):
        self.start_recording()
        self.screen.set_background_colour(colour=(0, 0, 0))

        if calibrate:
            origin = (int(self.disp.dispsize[0] / 4),
                      int(self.disp.dispsize[1] / 4))
            size = (int(2 * self.disp.dispsize[0] / 4),
                    int(2 * self.disp.dispsize[1] / 4))

            while not self.kb.get_key(keylist=['space'], flush=False)[0]:
                # TODO: What should we do when there are no gaze samples yet?
                # Should we wait or raise an Exception to indicate that
                # something went wrong.
                if not self.gaze_data:
                    continue
                gaze_sample = self.gaze_data[-1]

                self.screen.clear()

                validity_colour = (255, 0, 0)

                if gaze_sample['right_gaze_origin_validity'] and gaze_sample[
                        'left_gaze_origin_validity']:
                    left_validity = 0.15 < gaze_sample[
                        'left_gaze_origin_in_trackbox_coordinate_system'][
                            2] < 0.85
                    right_validity = 0.15 < gaze_sample[
                        'right_gaze_origin_in_trackbox_coordinate_system'][
                            2] < 0.85
                    if left_validity and right_validity:
                        validity_colour = (0, 255, 0)

                self.screen.draw_text(
                    text=
                    "When correctly positioned press \'space\' to start the calibration.",
                    pos=(int(self.disp.dispsize[0] / 2),
                         int(self.disp.dispsize[1] * 0.1)),
                    colour=(255, 255, 255),
                    fontsize=20)
                self.screen.draw_line(colour=validity_colour,
                                      spos=origin,
                                      epos=(origin[0] + size[0], origin[1]),
                                      pw=1)
                self.screen.draw_line(colour=validity_colour,
                                      spos=origin,
                                      epos=(origin[0], origin[1] + size[1]),
                                      pw=1)
                self.screen.draw_line(colour=validity_colour,
                                      spos=(origin[0], origin[1] + size[1]),
                                      epos=(origin[0] + size[0],
                                            origin[1] + size[1]),
                                      pw=1)
                self.screen.draw_line(colour=validity_colour,
                                      spos=(origin[0] + size[0],
                                            origin[1] + size[1]),
                                      epos=(origin[0] + size[0], origin[1]),
                                      pw=1)

                right_eye, left_eye, distance = None, None, []
                if gaze_sample['right_gaze_origin_validity']:
                    distance.append(
                        round(
                            gaze_sample[
                                'right_gaze_origin_in_user_coordinate_system']
                            [2] / 10, 1))
                    right_pos = gaze_sample[
                        'right_gaze_origin_in_trackbox_coordinate_system']
                    right_eye = ((1 - right_pos[0]) * size[0] + origin[0],
                                 right_pos[1] * size[1] + origin[1])
                    self.screen.draw_circle(colour=validity_colour,
                                            pos=right_eye,
                                            r=int(self.disp.dispsize[0] / 100),
                                            pw=5,
                                            fill=True)

                if gaze_sample['left_gaze_origin_validity']:
                    distance.append(
                        round(
                            gaze_sample[
                                'left_gaze_origin_in_user_coordinate_system']
                            [2] / 10, 1))
                    left_pos = gaze_sample[
                        'left_gaze_origin_in_trackbox_coordinate_system']
                    left_eye = ((1 - left_pos[0]) * size[0] + origin[0],
                                left_pos[1] * size[1] + origin[1])
                    self.screen.draw_circle(colour=validity_colour,
                                            pos=left_eye,
                                            r=int(self.disp.dispsize[0] / 100),
                                            pw=5,
                                            fill=True)

                self.screen.draw_text(
                    text="Current distance to the eye tracker: {0} cm.".format(
                        self._mean(distance)),
                    pos=(int(self.disp.dispsize[0] / 2),
                         int(self.disp.dispsize[1] * 0.9)),
                    colour=(255, 255, 255),
                    fontsize=20)

                self.disp.fill(self.screen)
                self.disp.show()

            # # # # # #
            # # calibration

            if not self.eyetracker:
                if DEBUG:
                    print(
                        "WARNING! libtobii.TobiiProTracker.calibrate: no eye trackers found for the calibration!"
                    )
                self.stop_recording()
                return False

            calibration = tr.ScreenBasedCalibration(self.eyetracker)
            calibrating = True

            while calibrating:
                calibration.enter_calibration_mode()

                for point in self.points_to_calibrate:
                    self.screen.clear()
                    self.screen.draw_circle(colour=(255, 255, 255),
                                            pos=point,
                                            r=int(self.disp.dispsize[0] /
                                                  100.0),
                                            pw=5,
                                            fill=True)
                    self.screen.draw_circle(colour=(255, 0, 0),
                                            pos=point,
                                            r=int(self.disp.dispsize[0] /
                                                  400.0),
                                            pw=5,
                                            fill=True)
                    self.disp.fill(self.screen)
                    self.disp.show()

                    # Wait a little for user to focus.
                    time.sleep(1)

                    normalized_point = self._px_2_norm(point)

                    collect_result = calibration.collect_data(
                        normalized_point[0], normalized_point[1])

                    if collect_result != tr.CALIBRATION_STATUS_SUCCESS:
                        # Try again if it didn't go well the first time.
                        # Not all eye tracker models will fail at this point, but instead fail on ComputeAndApply.
                        calibration.collect_data(normalized_point[0],
                                                 normalized_point[1])

                self.screen.clear()
                self.screen.draw_text("Calculating calibration result....",
                                      colour=(255, 255, 255),
                                      fontsize=20)
                self.disp.fill(self.screen)
                self.disp.show()

                calibration_result = calibration.compute_and_apply()

                calibration.leave_calibration_mode()

                if DEBUG:
                    print(
                        "Compute and apply returned {0} and collected at {1} points."
                        .format(calibration_result.status,
                                len(calibration_result.calibration_points)))

                if calibration_result.status != tr.CALIBRATION_STATUS_SUCCESS:
                    self.stop_recording()
                    if DEBUG:
                        print(
                            "WARNING! libtobii.TobiiProTracker.calibrate: Calibration was unsuccessful!"
                        )
                    return False

                self.screen.clear()
                for point in calibration_result.calibration_points:
                    self.screen.draw_circle(
                        colour=(255, 255, 255),
                        pos=self._norm_2_px(point.position_on_display_area),
                        r=self.disp.dispsize[0] / 200,
                        pw=1,
                        fill=False)
                    for sample in point.calibration_samples:
                        if sample.left_eye.validity == tr.VALIDITY_VALID_AND_USED:
                            self.screen.draw_circle(
                                colour=(255, 0, 0),
                                pos=self._norm_2_px(
                                    sample.left_eye.position_on_display_area),
                                r=self.disp.dispsize[0] / 450,
                                pw=self.disp.dispsize[0] / 450,
                                fill=False)
                            self.screen.draw_line(
                                colour=(255, 0, 0),
                                spos=self._norm_2_px(
                                    point.position_on_display_area),
                                epos=self._norm_2_px(
                                    sample.left_eye.position_on_display_area),
                                pw=1)
                        if sample.right_eye.validity == tr.VALIDITY_VALID_AND_USED:
                            self.screen.draw_circle(
                                colour=(0, 0, 255),
                                pos=self._norm_2_px(
                                    sample.right_eye.position_on_display_area),
                                r=self.disp.dispsize[0] / 450,
                                pw=self.disp.dispsize[0] / 450,
                                fill=False)
                            self.screen.draw_line(
                                colour=(0, 0, 255),
                                spos=self._norm_2_px(
                                    point.position_on_display_area),
                                epos=self._norm_2_px(
                                    sample.right_eye.position_on_display_area),
                                pw=1)

                self.screen.draw_text(
                    "Press the \'R\' key to recalibrate or \'Space\' to continue....",
                    pos=(0.5 * self.disp.dispsize[0],
                         0.95 * self.disp.dispsize[1]),
                    colour=(255, 255, 255),
                    fontsize=20)

                self.screen.draw_text("Left Eye",
                                      pos=(0.5 * self.disp.dispsize[0],
                                           0.01 * self.disp.dispsize[1]),
                                      colour=(255, 0, 0),
                                      fontsize=20)
                self.screen.draw_text("Right Eye",
                                      pos=(0.5 * self.disp.dispsize[0],
                                           0.03 * self.disp.dispsize[1]),
                                      colour=(0, 0, 255),
                                      fontsize=20)

                self.disp.fill(self.screen)
                self.disp.show()

                pressed_key = self.kb.get_key(keylist=['space', 'r'],
                                              flush=True,
                                              timeout=None)

                if pressed_key[0] == 'space':
                    calibrating = False

        if validate:
            # # # show menu
            self.screen.clear()
            self.screen.draw_text(text="Press space to start validation",
                                  colour=(255, 255, 255),
                                  fontsize=20)
            self.disp.fill(self.screen)
            self.disp.show()

            # # # wait for spacepress
            self.kb.get_key(keylist=['space'], flush=True, timeout=None)

            # # # # # #
            # # validation

            # # # arrays for data storage
            lxacc, lyacc, rxacc, ryacc = [], [], [], []

            # # loop through all calibration positions
            for pos in self.points_to_calibrate:
                # show validation point
                self.screen.clear()
                self.screen.draw_fixation(fixtype='dot',
                                          pos=pos,
                                          colour=(255, 255, 255))
                self.disp.fill(self.screen)
                self.disp.show()

                # allow user some time to gaze at dot
                time.sleep(1)

                lxsamples, lysamples, rxsamples, rysamples = [], [], [], []
                for sample in self.gaze_data:
                    if sample["left_gaze_point_validity"]:
                        gaze_point = self._norm_2_px(
                            sample["left_gaze_point_on_display_area"])
                        lxsamples.append(abs(gaze_point[0] - pos[0]))
                        lysamples.append(abs(gaze_point[1] - pos[1]))
                    if sample["right_gaze_point_validity"]:
                        gaze_point = self._norm_2_px(
                            sample["right_gaze_point_on_display_area"])
                        rxsamples.append(abs(gaze_point[0] - pos[0]))
                        rysamples.append(abs(gaze_point[1] - pos[1]))

                # calculate mean deviation
                lxacc.append(self._mean(lxsamples))
                lyacc.append(self._mean(lysamples))
                rxacc.append(self._mean(rxsamples))
                ryacc.append(self._mean(rysamples))

                # wait for a bit to slow down validation process a bit
                time.sleep(1)

            # calculate mean accuracy
            self.pxaccuracy = [(self._mean(lxacc), self._mean(lyacc)),
                               (self._mean(rxacc), self._mean(ryacc))]

            # sample rate
            # calculate intersample times
            timestamps = []
            gaze_samples = self.gaze_data
            for i in range(0, len(gaze_samples) - 1):
                next_sample = gaze_samples[i + 1]['system_time_stamp']
                current_sample = gaze_samples[i]['system_time_stamp']
                timestamps.append((next_sample - current_sample) / 1000.0)

            # mean intersample time
            self.sampletime = self._mean(timestamps)
            self.samplerate = int(1000.0 / self.sampletime)

            # # # # # #
            # # RMS noise

            # # present instructions
            self.screen.clear()
            self.screen.draw_text(
                text=
                "Noise calibration: please look at the dot\n\n(press space to start)",
                pos=(self.disp.dispsize[0] / 2,
                     int(self.disp.dispsize[1] * 0.2)),
                colour=(255, 255, 255),
                fontsize=20)
            self.screen.draw_fixation(fixtype='dot', colour=(255, 255, 255))
            self.disp.fill(self.screen)
            self.disp.show()

            # # wait for spacepress
            self.kb.get_key(keylist=['space'], flush=True, timeout=None)

            # # show fixation
            self.screen.draw_fixation(fixtype='dot', colour=(255, 255, 255))
            self.disp.fill(self.screen)
            self.disp.show()
            self.screen.clear()

            # # wait for a bit, to allow participant to fixate
            time.sleep(1)

            # # get samples
            # samplelist, prefilled with 1 sample to prevent sl[-1] from producing an error
            # first sample will be ignored for RMS calculation
            sl = [self.sample()]
            t0 = self.millis()  # starting time
            while self.millis() - t0 < 1000:
                s = self.sample()  # sample
                if s != sl[-1] and self.is_valid_sample(s) and s != (0, 0):
                    sl.append(s)

            # # calculate RMS noise
            Xvar, Yvar = [], []
            for i in range(2, len(sl)):
                Xvar.append((sl[i][0] - sl[i - 1][0])**2)
                Yvar.append((sl[i][1] - sl[i - 1][1])**2)
            XRMS = (self._mean(Xvar))**0.5
            YRMS = (self._mean(Yvar))**0.5
            self.pxdsttresh = (XRMS, YRMS)

            # # # # # # #
            # # # calibration report

            # # # # recalculate thresholds (degrees to pixels)
            self.pxfixtresh = self._deg2pix(self.screendist, self.fixtresh,
                                            self.pixpercm)
            # in pixels per millisecons
            self.pxspdtresh = self._deg2pix(self.screendist,
                                            self.spdtresh / 1000.0,
                                            self.pixpercm)
            # in pixels per millisecond**2
            self.pxacctresh = self._deg2pix(self.screendist,
                                            self.accthresh / 1000.0,
                                            self.pixpercm)

            data_to_write = ''
            data_to_write += "pygaze calibration report start\n"
            data_to_write += "samplerate: %s Hz\n" % self.samplerate
            data_to_write += "sampletime: %s ms\n" % self.sampletime
            data_to_write += "accuracy (in pixels): LX=%s, LY=%s, RX=%s, RY=%s\n" % (
                self.pxaccuracy[0][0], self.pxaccuracy[0][1],
                self.pxaccuracy[1][0], self.pxaccuracy[1][1])
            data_to_write += "precision (RMS noise in pixels): X=%s, Y=%s\n" % (
                self.pxdsttresh[0], self.pxdsttresh[1])
            data_to_write += "fixation threshold: %s pixels\n" % self.pxfixtresh
            data_to_write += "speed threshold: %s pixels/ms\n" % self.pxspdtresh
            data_to_write += "accuracy threshold: %s pixels/ms**2\n" % self.pxacctresh
            data_to_write += "pygaze calibration report end\n"

            self.screen.clear()
            self.screen.draw_text(text=data_to_write,
                                  pos=(self.disp.dispsize[0] / 2,
                                       int(self.disp.dispsize[1] / 2)),
                                  colour=(255, 255, 255),
                                  fontsize=20)
            self.disp.fill(self.screen)
            self.disp.show()

            self.kb.get_key(keylist=['space'], flush=True, timeout=None)

        self.stop_recording()
        self.disp.close()

        return True
コード例 #15
0
 def calibrate_start(self):
     self.calibration = tr.ScreenBasedCalibration(self.eyetracker)
     self.calibration.enter_calibration_mode()
    def calibrate(self, eventlog, calibrate=True):
        """Calibrates the eye tracker with custom child-friendly screens.
        arguments
            eventlog          --    logfile instance
        keyword arguments
            calibrate    --    Boolean indicating if calibration should be
                        performed (default = True).
        returns
            success    --     nowt, but a calibration log is added to the
                        log file and some properties are updated (i.e. the
                        thresholds for detection algorithms)
        """

        # # # #calculate thresholds (degrees to pixels) # NOT USED
        self.pxfixtresh = self._deg2pix(self.screendist, self.fixtresh,
                                        self.pixpercm)
        # in pixels per millisecons
        self.pxspdtresh = self._deg2pix(self.screendist,
                                        self.spdtresh / 1000.0, self.pixpercm)
        # in pixels per millisecond**2
        self.pxacctresh = self._deg2pix(self.screendist,
                                        self.accthresh / 1000.0, self.pixpercm)

        # calibration image file
        calibImg = c.CALIBIMG

        # initialize a sound
        snd = sound.Sound(value=c.CALIBSOUNDFILE)
        snd.setVolume(0.5)

        # image scaling range
        bit = 0.02
        scale_range = ([x / 100.0 for x in range(60, 30, -2)] +
                       [x / 100.0 for x in range(30, 60, 2)])

        if calibrate:

            if not self.eyetracker:
                print(
                    "WARNING! libtobii.TobiiProTracker.calibrate: no eye trackers found for the calibration!"
                )
                self.stop_recording()
                return False

            # Tobii calibration object
            calibration = tr.ScreenBasedCalibration(self.eyetracker)

            calibrating = True
            calibration.enter_calibration_mode()

            while calibrating:

                eventlog.write(["Calibration started at ", clock.get_time()])

                # original (normalised) points_to_calibrate = [(0.5, 0.5), (0.9, 0.1), (0.1, 0.1), (0.9, 0.9), (0.1, 0.9)]
                # pixel values are calculated ( based on the normalised points, with (1920,1200) (see __init__).
                # self.points_to_calibrate calculated values: [(960, 600), (192, 1080), (192, 120), (1728, 1080), (1728, 120)]

                # calibration for all calibration points
                for i in range(0, len(self.points_to_calibrate)):

                    point = self.points_to_calibrate[i]

                    eventlog.write([
                        "\nCalibrating point {0} at: ".format(point),
                        clock.get_time()
                    ])
                    #                    print "----------> Calibrating at point ", point

                    # play the soundfile
                    snd.play()

                    # shrink
                    scale = 1
                    for frameN in range(
                            20):  # 20 frames -> 1/3 sec shrinking (180 to 108)

                        self.c_screen.clear()
                        self.c_screen.draw_image(calibImg,
                                                 pos=point,
                                                 scale=scale)
                        drawCoreImage(self.c_screen, point, i)
                        self.disp.fill(self.c_screen)
                        self.disp.show()
                        scale = scale - bit

                    # grow and shrink until 'space' is pressed
                    s = 0
                    for frameN in range(
                            12000
                    ):  # scale down from 108 to 54, (15 frames) and back up, according to scale_range list

                        s = frameN % 30
                        scale = scale_range[s]
                        self.c_screen.clear()
                        self.c_screen.draw_image(calibImg,
                                                 pos=point,
                                                 scale=scale)
                        drawCoreImage(self.c_screen, point, i)
                        self.disp.fill(self.c_screen)
                        self.disp.show()

                        if self.kb.get_key(keylist=['space'],
                                           timeout=10,
                                           flush=False)[0] == 'space':
                            break

                    # collect results for point (Tobii)
                    normalized_point = self._px_2_norm(point)
                    collect_result = calibration.collect_data(
                        normalized_point[0], normalized_point[1])
                    eventlog.write([
                        "Collecting result for point {0} at: ".format(point),
                        clock.get_time()
                    ])

                    if collect_result != tr.CALIBRATION_STATUS_SUCCESS:
                        eventlog.write([
                            "Recollecting result for point {0} at: ".format(
                                point),
                            clock.get_time()
                        ])
                        # Try again if it didn't go well the first time.
                        # Not all eye tracker models will fail at this point, but instead fail on ComputeAndApply.
                        calibration.collect_data(normalized_point[0],
                                                 normalized_point[1])

                    # grow back to original size
                    up_scale = [
                        x / 100.0 for x in range(int(scale * 100), 100, 2)
                    ]
                    for scale in up_scale:
                        self.c_screen.clear()
                        self.c_screen.draw_image(calibImg,
                                                 pos=point,
                                                 scale=scale)
                        drawCoreImage(self.c_screen, point, i)
                        self.disp.fill(self.c_screen)
                        self.disp.show()

                    # image rolling to next point
                    # pixelised self.points_to_calibrate = [(960, 600), (192, 1080), (192, 120), (1728, 1080), (1728, 120)]
                    if (i < len(self.points_to_calibrate) - 1):
                        """
                        screen ratio: 16/10
                        -> the steps for moving the images should be (16, 10) or (8, 5)
                        """
                        # center -> bottom left / (960, 600) -> (192, 1080) - 48 frames
                        while point[0] >= self.points_to_calibrate[i + 1][0]:
                            self.c_screen.clear()
                            point = (point[0] - 16, point[1] + 10)
                            self.c_screen.draw_image(calibImg, pos=point)
                            self.disp.fill(self.c_screen)
                            self.disp.show()

                        # bottom-left -> top-left / (192, 1080) -> (192, 120)
                        # AND
                        # bottom-right -> top-right / (1728, 1080) -> (1728, 120) - 80 frames
                        while point[1] > self.points_to_calibrate[i + 1][1]:
                            self.c_screen.clear()
                            point = (point[0], point[1] - 12)
                            self.c_screen.draw_image(calibImg, pos=point)
                            self.disp.fill(self.c_screen)
                            self.disp.show()

                        # top-left -> bottom-right / (192, 120) -> (1728, 1080) - 96 frames
                        while point[0] < self.points_to_calibrate[
                                i + 1][0] and not point[
                                    1] == self.points_to_calibrate[i + 1][1]:
                            self.c_screen.clear()
                            point = (point[0] + 16, point[1] + 10)
                            self.c_screen.draw_image(calibImg, pos=point)
                            self.disp.fill(self.c_screen)
                            self.disp.show()

                # Tobii
                calibration_result = calibration.compute_and_apply()

                eventlog.write([
                    "\nCompute and apply returned {0} and collected at {1} points.\n"
                    .format(calibration_result.status,
                            len(calibration_result.calibration_points))
                ])
                print("\tCalibration: {0} - collected at {1} points.".format(
                    calibration_result.status,
                    len(calibration_result.calibration_points)))

                # Post-calibration image (while control monitor shows calibration results)
                self.c_screen.clear()
                self.c_screen.draw_image(c.ATT_IMG)
                self.disp.fill(self.c_screen)
                self.disp.show()

                if calibration_result.status != tr.CALIBRATION_STATUS_SUCCESS:
                    eventlog.write([
                        "\n\nWARNING! libtobii.TobiiProTracker.calibrate: Calibration was unsuccessful!\n\n"
                    ])
                    print("""\tCalibration was unsuccessful.\n
                          ->Press 'R' to recalibrate all points
                          ->or 'SPACE' to continue without calibration\n""")
                    key = self.kb.get_key(keylist=['space', 'r'],
                                          timeout=None)[0]
                    if key == 'r':
                        recalibration_points = [0]
                    elif key == 'space':
                        recalibration_points = []

                else:
                    # call showCalibrationResults function to present the results on screen 0. The function returns a list of recalibration points
                    logfile_dir = os.path.dirname(
                        os.path.abspath(self.datafilepath))
                    recalibration_points = showCalibrationResults(
                        logfile_dir, calibration_result)

                # if the list is empty, calibration is finished
                if len(recalibration_points) == 0:
                    eventlog.write(
                        ["\nCalibration finished at ",
                         clock.get_time()])
                    calibrating = False

                # if the list contains only '0', the calibration was unsuccessful, relalibrate all points
                elif (recalibration_points[0] == 0):
                    eventlog.write(["\nRecalibrating all points..."])
                    calibrating = True

                # if the list contains only '1', recalibrate all points despite successful calibration
                elif (recalibration_points[0] == 1):
                    eventlog.write(["\nRecalibrating all points..."])
                    for point in self.points_to_calibrate:
                        calibration.discard_data(point[0], point[1])
                    calibrating = True

                # relalibrate the returned points
                else:
                    eventlog.write([
                        "\nRecalibrating {0} points...".format(
                            len(recalibration_points))
                    ])
                    self.points_to_calibrate = [
                        self._norm_2_px(p) for p in recalibration_points
                    ]
                    for point in self.points_to_calibrate:
                        calibration.discard_data(point[0], point[1])
                    calibrating = True

        calibration.leave_calibration_mode()
        eventlog.write([" Leaving calibration mode...", clock.get_time()])
        self.stop_recording()
        self._write_enabled = True
        self.disp.close()  # leaving pygaze display
コード例 #17
0
import time
import tobii_research as tr
import tkinter as tk
import random
import os
import sys

# Connection eyetracker

found_eyetrackers = tr.find_all_eyetrackers()
eyetracker = found_eyetrackers[0]

calibration = tr.ScreenBasedCalibration(eyetracker)
# Enter calibration mode.
calibration.enter_calibration_mode()
print "Entered calibration mode for eye tracker with serial number {0}.".format(
    eyetracker.serial_number)

# Define the points on screen we should calibrate at.
# The coordinates are normalized, i.e. (0.0, 0.0) is the upper left corner and (1.0, 1.0) is the lower right corner.
points_to_calibrate = [(0.5, 0.5), (0.1, 0.1), (0.1, 0.9), (0.9, 0.1),
                       (0.9, 0.9)]

for point in points_to_calibrate:
    time.sleep(1)
    print "Show a point on screen at {0}.".format(point)
    print "Collecting data at {0}.".format(point)
    if calibration.collect_data(point[0],
                                point[1]) != tr.CALIBRATION_STATUS_SUCCESS:
        # Try again if it didn't go well the first time.
        # Not all eye tracker models will fail at this point, but instead fail on ComputeAndApply.
コード例 #18
0
 def newScreenCalibration(self):
     if self._eyetracker:
         return tobii_research.ScreenBasedCalibration(self._eyetracker)
コード例 #19
0
def phase06_calibration():
    
        button_quit.autoDraw = False
    
        calibration = tr.ScreenBasedCalibration(eyetracker)
        
        # Enter calibration mode.
        calibration.enter_calibration_mode()
        print(f"Entered calibration mode for eye tracker with serial number {eyetracker.serial_number}.")
    
        # Define the points on screen
        # Normalized coordinates! i.e. (0.0, 0.0) is the upper left corner and (1.0, 1.0) is the lower right corner.
        points_to_calibrate = [(0.5, 0.5), (0.1, 0.1), (0.1, 0.9), (0.9, 0.1), (0.9, 0.9)]
        points_to_calibrate_psySpace = toPPnorm(np.array(points_to_calibrate)) 

        fixDisc = visual.ImageStim(win, os.path.join(cfg.stimDir, 'fixationDisc.png'), size=[.01, .01*win.aspect])
        
        win.flip()

        for point_idx in range(len(points_to_calibrate)):
            point = points_to_calibrate[point_idx]
            point_psy = points_to_calibrate_psySpace[point_idx]
            print(f"Show a point on screen at {point}")

            for i in range(1,150):
                scalingFactor = .98
                fixDisc.size *= [1/scalingFactor,1/scalingFactor]
                fixDisc.draw()
                win.flip()
                time.sleep(.01)
            
            for i in range(1,150):
                fixDisc.size *= [scalingFactor,scalingFactor]
                now = np.array(fixDisc.pos)
                tarPos = np.array(point_psy)
                fixDisc.pos += tuple((tarPos-now)*i/149)
                fixDisc.draw()
                win.flip()
                time.sleep(.01)
            
            # let user focus
            time.sleep(.5)
    
            print("Collecting data at {0}.".format(point))
            
            if calibration.collect_data(point[0], point[1]) != tr.CALIBRATION_STATUS_SUCCESS: 
                print('not successfull, trying a second time')
                # Tobii API suggests to try again if it didn't go well the first time.
                calibration.collect_data(point[0], point[1])
                
        
        calibration_result = calibration.compute_and_apply()
        print(f"Computed and applied calibration: returned {calibration_result.status} and \
              collected at {len(calibration_result.calibration_points)} points.")
    
        # here or later after validation we could think of running points through calibration.discard_data(x,y)
    
        # The calibration done
        calibration.leave_calibration_mode()
        
        updatePhase()
コード例 #20
0
def calibrate():
    global tracker
    root = Tk()

    calibrator = tobii_research.ScreenBasedCalibration(tracker)
    calibrator.enter_calibration_mode()

    calibration_points = [(.1, .1), (.9, .1), (.1, .9), (.9, .9), (.1, .5),
                          (.9, .5), (.5, .1), (.5, .9), (.5, .5)]
    random.shuffle(calibration_points)
    root.overrideredirect(1)
    root.geometry("%dx%d+0+0" % (width, height))
    root.focus_set()  # <-- move focus to this widget
    root.bind("<Escape>", lambda e: e.widget.quit())
    canvas = Canvas(root,
                    width=width,
                    height=height,
                    scrollregion=(0, 0, width, height))
    canvas.pack()
    canvas.create_text(width / 2,
                       height / 2,
                       text="Calibration is about to begin.",
                       font=('Times', '28'))
    root.update_idletasks()
    root.update()
    time.sleep(5)
    canvas.delete("all")
    for pos in calibration_points:
        x, y = pos
        point = canvas.create_oval(x * width - 10,
                                   y * height - 10,
                                   x * width + 10,
                                   y * height + 10,
                                   fill="blue")
        root.update_idletasks()
        root.update()
        print(x, y)
        time.sleep(.7)
        if calibrator.collect_data(
                x, y) != tobii_research.CALIBRATION_STATUS_SUCCESS:
            # Try again if first try was not successful.
            calibrator.collect_data(x, y)
        canvas.delete(point)
    canvas.create_text(width / 2,
                       height / 2,
                       text="Calibration finished. Please wait for results.",
                       font=('Times', '28'))
    root.update_idletasks()
    root.update()

    calibration_result = calibrator.compute_and_apply()
    print("Compute and apply returned %s and collected at %s points" %
          (calibration_result.status, len(
              calibration_result.calibration_points)))
    if calibration_result.status == tobii_research.CALIBRATION_STATUS_SUCCESS:
        w = QMessageBox(QMessageBox.Information, "Calibration Result",
                        "Calibration successful!")
        w.exec_()

    calibrator.leave_calibration_mode()

    root.destroy()