aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/argaze/TobiiGlassesPro2/README.md5
-rw-r--r--src/argaze/TobiiGlassesPro2/TobiiEntities.py67
-rw-r--r--src/argaze/utils/analyse_tobii_segment_fixations.py19
-rw-r--r--src/argaze/utils/map_tobii_gaze_on_camera.py0
4 files changed, 62 insertions, 29 deletions
diff --git a/src/argaze/TobiiGlassesPro2/README.md b/src/argaze/TobiiGlassesPro2/README.md
index 4ede0d6..d26f066 100644
--- a/src/argaze/TobiiGlassesPro2/README.md
+++ b/src/argaze/TobiiGlassesPro2/README.md
@@ -1,6 +1,7 @@
Class interface to handle Tobbi Glasses Pro 2 device.
-It is based on [TobiiGlassesPySuite package](https://github.com/ddetommaso/TobiiGlassesPySuite):
-* [Article that describes the package features](https://arxiv.org/pdf/1912.09142.pdf).
+This work is greatly inspired by the features available throught David de Tommaso and Agnieszka Wykowska [TobiiGlassesPySuite package](https://github.com/ddetommaso/TobiiGlassesPySuite) as TobiiController class directly inherits from tobiiglassesctrl.TobiiGlassesController class.
+
+* [Article that describes TobiiGlassesPySuite package features](https://arxiv.org/pdf/1912.09142.pdf).
* [Tobii Glasses Pro 2 device user manual](https://www.tobiipro.com/siteassets/tobii-pro/user-manuals/tobii-pro-glasses-2-user-manual.pdf).
## Utils
diff --git a/src/argaze/TobiiGlassesPro2/TobiiEntities.py b/src/argaze/TobiiGlassesPro2/TobiiEntities.py
index 5483233..96fd0af 100644
--- a/src/argaze/TobiiGlassesPro2/TobiiEntities.py
+++ b/src/argaze/TobiiGlassesPro2/TobiiEntities.py
@@ -7,6 +7,7 @@ import os
from argaze import DataStructures
+import av
import cv2 as cv
TOBII_DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S+%f'
@@ -25,20 +26,15 @@ TOBII_SEGMENT_INFO_FILENAME = "segment.json"
TOBII_SEGMENT_VIDEO_FILENAME = "fullstream.mp4"
TOBII_SEGMENT_DATA_FILENAME = "livedata.json.gz"
-class TobiiSegmentData:
+class TobiiSegmentData(DataStructures.DictObject):
"""Handle Tobii Glasses Pro 2 segment data file."""
def __init__(self, segment_data_path):
- """Load segment data from segment directory."""
+ """Load segment data from segment directory then parse and register each recorded dataflow as a TimeStampedBuffer member of the TobiiSegmentData instance."""
self.__segment_data_path = segment_data_path
self.__ts_start = 0
- def get_path(self):
- return self.__segment_data_path
-
- def load(self):
-
ts_data_buffer_dict = {}
# define a decoder function
@@ -77,33 +73,60 @@ class TobiiSegmentData:
for item in f:
json.loads(item.decode('utf-8'), object_hook=decode)
- return ts_data_buffer_dict
+ super().__init__(type(self).__name__, **ts_data_buffer_dict)
+
+ def keys(self):
+ """Get all registered data keys"""
+ return list(self.__dict__.keys())[2:-1]
+
+ def get_path(self):
+ return self.__segment_data_path
+
+class TobiiVideoFrame(DataStructures.DictObject):
+ """Define tobii video frame"""
-class TobiiSegmentVideo:
+ def __init__(self, matrix, width, height, pts):
+
+ super().__init__(type(self).__name__, **{'matrix': matrix, 'width': width, 'height': height, 'pts': pts})
+
+class TobiiSegmentVideo():
"""Handle Tobii Glasses Pro 2 segment video file."""
def __init__(self, segment_video_path):
- """Load segment video from segment directory."""
+ """Load segment video from segment directory"""
self.__segment_video_path = segment_video_path
-
- video = cv.VideoCapture(self.__segment_video_path)
-
- self.__width = int(video.get(cv.CAP_PROP_FRAME_WIDTH))
- self.__height = int(video.get(cv.CAP_PROP_FRAME_HEIGHT))
- self.__fps = int(video.get(cv.CAP_PROP_FPS))
+ self.__container = av.open(self.__segment_video_path)
+ self.__stream = self.__container.streams.video[0]
+ self.__width = int(cv.VideoCapture(self.__segment_video_path).get(cv.CAP_PROP_FRAME_WIDTH))
+ self.__height = int(cv.VideoCapture(self.__segment_video_path).get(cv.CAP_PROP_FRAME_HEIGHT))
+
def get_path(self):
return self.__segment_video_path
- def get_height(self):
- return self.__height
+ def get_duration(self):
+ return self.__stream.duration
+
+ def get_frame_number(self):
+ return self.__stream.frames
def get_width(self):
return self.__width
- def get_fps(self):
- return self.__fps
+ def get_height(self):
+ return self.__height
+
+ def __iter__(self):
+
+ # start decoding
+ self.__container.decode(self.__stream)
+ return self
+
+ def __next__(self):
+
+ frame = self.__container.decode(self.__stream).__next__()
+ return frame.time, TobiiVideoFrame(frame.to_ndarray(format='bgr24'), frame.width, frame.height, frame.pts)
class TobiiSegment:
"""Handle Tobii Glasses Pro 2 segment info."""
@@ -143,10 +166,10 @@ class TobiiSegment:
def is_calibrated(self):
return self.__calibrated
- def get_data(self):
+ def load_data(self):
return TobiiSegmentData(os.path.join(self.__segment_path, TOBII_SEGMENT_DATA_FILENAME))
- def get_video(self):
+ def load_video(self):
return TobiiSegmentVideo(os.path.join(self.__segment_path, TOBII_SEGMENT_VIDEO_FILENAME))
class TobiiRecording:
diff --git a/src/argaze/utils/analyse_tobii_segment_fixations.py b/src/argaze/utils/analyse_tobii_segment_fixations.py
index 32fa32d..26f0838 100644
--- a/src/argaze/utils/analyse_tobii_segment_fixations.py
+++ b/src/argaze/utils/analyse_tobii_segment_fixations.py
@@ -24,11 +24,15 @@ def main():
tobii_segment = TobiiEntities.TobiiSegment(args.segment_path)
# Load a tobii segment video
- tobii_segment_video = tobii_segment.get_video()
- print(f'Video width: {tobii_segment_video.get_width()}, height: {tobii_segment_video.get_height()}, fps: {tobii_segment_video.get_fps()}')
-
- # Load a tobii segment timestamped gaze position data buffer
- tobii_ts_gaze_position_buffer = tobii_segment.get_data().load()['gidx-l-gp']
+ tobii_segment_video = tobii_segment.load_video()
+ print(f'Video duration: {tobii_segment_video.get_duration()}, frame number: {tobii_segment_video.get_frame_number()}, width: {tobii_segment_video.get_width()}, height: {tobii_segment_video.get_height()}')
+
+ # Load a tobii segment data
+ tobii_segment_data = tobii_segment.load_data()
+ print(f'Data keys: {tobii_segment_data.keys()}')
+
+ # Access to timestamped gaze position data buffer
+ tobii_ts_gaze_position_buffer = tobii_segment_data['gidx-l-gp']
print(f'{len(tobii_ts_gaze_position_buffer)} gaze positions loaded')
@@ -49,6 +53,11 @@ def main():
for ts, f in fixation_analyser.fixations.items():
print(f'start time = {ts}, duration = {f.duration}, dispertion = {f.dispersion}, centroid = {f.centroid}')
+ # TODO : synchronise video and gaze
+ #for ts, frame in tobii_segment_video:
+
+ #print(ts)
+
if __name__ == '__main__':
main() \ No newline at end of file
diff --git a/src/argaze/utils/map_tobii_gaze_on_camera.py b/src/argaze/utils/map_tobii_gaze_on_camera.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/argaze/utils/map_tobii_gaze_on_camera.py