Skip to content

Instantly share code, notes, and snippets.

@papr
Last active July 18, 2022 07:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save papr/5e1f0fc9ef464691588b3f3e0e95f350 to your computer and use it in GitHub Desktop.
Save papr/5e1f0fc9ef464691588b3f3e0e95f350 to your computer and use it in GitHub Desktop.
Dual-monocular Gazer for Pupil Capture, Service, and Player
import logging
from gaze_mapping import Gazer3D, Gazer2D
from gaze_mapping.gazer_base import (
NotEnoughPupilDataError,
NotEnoughReferenceDataError,
NotEnoughDataError,
)
from gaze_mapping.gazer_2d import Model2D_Monocular, Model2D_Binocular
logger = logging.getLogger(__name__)
class GazerDualMonocular3D(Gazer3D):
label = "Dual-monocular 3D"
def init_matcher(self):
self.matcher = DummyMatcher()
def fit_on_calib_data(self, calib_data):
# extract reference data
ref_data = calib_data["ref_list"]
# extract and filter pupil data
pupil_data = calib_data["pupil_list"]
pupil_data = self.filter_pupil_data(
pupil_data, self.g_pool.min_calibration_confidence
)
if not pupil_data:
raise NotEnoughPupilDataError
if not ref_data:
raise NotEnoughReferenceDataError
# match pupil to reference data (left, right, and binocular)
matches = self.match_pupil_to_ref(pupil_data, ref_data)
if matches.right[0]:
self._fit_monocular_model(self.right_model, matches.right)
else:
logger.warning("Not enough matching data to fit right model")
if matches.left[0]:
self._fit_monocular_model(self.left_model, matches.left)
else:
logger.warning("Not enough matching data to fit left model")
if not self.right_model.is_fitted and not self.left_model.is_fitted:
raise NotEnoughDataError
class GazerDualMonocular2D(Gazer2D):
label = "Dual-monocular 2D"
def init_matcher(self):
self.matcher = DummyMatcher()
def fit_on_calib_data(self, calib_data):
# extract reference data
ref_data = calib_data["ref_list"]
# extract and filter pupil data
pupil_data = calib_data["pupil_list"]
pupil_data = self.filter_pupil_data(
pupil_data, self.g_pool.min_calibration_confidence
)
if not pupil_data:
raise NotEnoughPupilDataError
if not ref_data:
raise NotEnoughReferenceDataError
# match pupil to reference data (left, right, and binocular)
matches = self.match_pupil_to_ref(pupil_data, ref_data)
if matches.right[0]:
self._fit_monocular_model(self.right_model, matches.right)
else:
logger.warning("Not enough matching data to fit right model")
if matches.left[0]:
self._fit_monocular_model(self.left_model, matches.left)
else:
logger.warning("Not enough matching data to fit left model")
if not self.right_model.is_fitted and not self.left_model.is_fitted:
raise NotEnoughDataError
# overwrite model init functions in case frame size is not available,
# e.g. external HMD use case
def _init_left_model(self):
try:
screen_size = self.g_pool.capture.frame_size
except AttributeError:
screen_size = (1.0, 1.0)
return Model2D_Monocular(screen_size=screen_size)
def _init_right_model(self):
try:
screen_size = self.g_pool.capture.frame_size
except AttributeError:
screen_size = (1.0, 1.0)
return Model2D_Monocular(screen_size=screen_size)
def _init_binocular_model(self):
try:
screen_size = self.g_pool.capture.frame_size
except AttributeError:
screen_size = (1.0, 1.0)
return Model2D_Binocular(screen_size=screen_size)
class DummyMatcher:
"""Dummy matcher that simply returns the input pupil datum.
Matching is only required if you want to build binocular pairs.
"""
def map_batch(self, pupil_list):
results = []
for p in pupil_list:
results.extend(self.on_pupil_datum(p))
return results
def on_pupil_datum(self, p):
yield [p]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment