-
-
Save papr/d3ec18dd40899353bb52b506e3cfb433 to your computer and use it in GitHub Desktop.
Offset Corrected Gaze From Recording
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from pyglui import ui | |
import file_methods as fm | |
import player_methods as pm | |
from gaze_producer.gaze_producer_base import GazeProducerBase | |
from methods import denormalize | |
from player_methods import transparent_circle | |
class GazeFromRecordingWithOffsetCorrection(GazeProducerBase): | |
@classmethod | |
def plugin_menu_label(cls) -> str: | |
return "Offset Corrected Gaze Data" | |
@classmethod | |
def gaze_data_source_selection_order(cls) -> float: | |
return 3.0 | |
def __init__(self, g_pool, *, x_offset=0.0, y_offset=0.0): | |
super().__init__(g_pool) | |
self.__x_offset = x_offset | |
self.__y_offset = y_offset | |
self.__active_offset = (x_offset, y_offset) | |
self.__gaze_from_recording = fm.load_pldata_file(self.g_pool.rec_dir, "gaze") | |
self.__publish_with_offsets() | |
def get_init_dict(self): | |
return { | |
**super().get_init_dict(), | |
"x_offset": self.__x_offset, | |
"y_offset": self.__y_offset, | |
} | |
def recent_events(self, events): | |
super().recent_events(events) | |
if self.__active_offset == (self.x_offset, self.y_offset): | |
return | |
frame = events.get("frame") | |
if not frame: | |
return | |
frame_width_height = frame.img.shape[:-1][::-1] | |
points = [] | |
for datum in events.get("gaze", []): | |
if datum["confidence"] < self.g_pool.min_data_confidence: | |
continue | |
x, y = datum["norm_pos"] | |
active_x, active_y = self.__active_offset | |
mapped = (x - active_x + self.x_offset, y - active_y + self.y_offset) | |
points.append(denormalize(mapped, frame_width_height, flip_y=True)) | |
for pt in points: | |
transparent_circle( | |
frame.img, pt, radius=20, color=(0.0, 0.3, 1.0, 0.1), thickness=-1, | |
) | |
transparent_circle( | |
frame.img, pt, radius=20, color=(0.0, 0.3, 1.0, 0.5), thickness=1, | |
) | |
def __publish_with_offsets(self): | |
mutable_data = [ | |
data._deep_copy_dict() for data in self.__gaze_from_recording.data | |
] | |
for datum in mutable_data: | |
datum["norm_pos"] = ( | |
datum["norm_pos"][0] + self.x_offset, | |
datum["norm_pos"][1] + self.y_offset, | |
) | |
serialized_data = [fm.Serialized_Dict(data) for data in mutable_data] | |
self.g_pool.gaze_positions = pm.Bisector( | |
serialized_data, self.__gaze_from_recording.timestamps | |
) | |
self._gaze_changed_announcer.announce_new() | |
self.__active_offset = (self.x_offset, self.y_offset) | |
def init_ui(self): | |
super().init_ui() | |
self.menu.append( | |
ui.Info_Text("Using recorded gaze data with a manual offset correction") | |
) | |
self.menu.append( | |
ui.Slider( | |
"x_offset", | |
self, | |
min=-0.5, | |
step=0.01, | |
max=0.5, | |
label="Manual Correction X", | |
) | |
) | |
self.menu.append( | |
ui.Slider( | |
"y_offset", | |
self, | |
min=-0.5, | |
step=0.01, | |
max=0.5, | |
label="Manual Correction Y", | |
) | |
) | |
self.menu.append(ui.Button("Apply Offset", self.__publish_with_offsets)) | |
@property | |
def x_offset(self): | |
return self.__x_offset | |
@x_offset.setter | |
def x_offset(self, val): | |
if val != self.__x_offset: | |
self.__x_offset = val | |
@property | |
def y_offset(self): | |
return self.__y_offset | |
@y_offset.setter | |
def y_offset(self, val): | |
if val != self.__y_offset: | |
self.__y_offset = val | |
# need to delete this, otherwise the GazeProducerBase gets loaded as user plugin, which | |
# fails because it is an abstract class | |
del GazeProducerBase |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment