aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThéo de la Hogue2022-05-11 10:48:10 +0200
committerThéo de la Hogue2022-05-11 10:48:10 +0200
commit346c9d18d4d6e90bf871adbd56eecf3c613f1164 (patch)
treecf70be034042e821ed65660958060272149ffdd9
parente716c1e60d175a8f40617247d437d47c9348ba42 (diff)
downloadargaze-346c9d18d4d6e90bf871adbd56eecf3c613f1164.zip
argaze-346c9d18d4d6e90bf871adbd56eecf3c613f1164.tar.gz
argaze-346c9d18d4d6e90bf871adbd56eecf3c613f1164.tar.bz2
argaze-346c9d18d4d6e90bf871adbd56eecf3c613f1164.tar.xz
Improving export scripts arguments and console outputs.
-rw-r--r--src/argaze/ArUcoMarkers/ArUcoTracker.py27
-rw-r--r--src/argaze/utils/export_tobii_segment_aruco_visual_scan.py89
-rw-r--r--src/argaze/utils/export_tobii_segment_movements.py36
3 files changed, 105 insertions, 47 deletions
diff --git a/src/argaze/ArUcoMarkers/ArUcoTracker.py b/src/argaze/ArUcoMarkers/ArUcoTracker.py
index 19f4643..363a5bb 100644
--- a/src/argaze/ArUcoMarkers/ArUcoTracker.py
+++ b/src/argaze/ArUcoMarkers/ArUcoTracker.py
@@ -58,7 +58,8 @@ class ArUcoTracker():
# setup ArUco detection parameters
self.__detector_parameters = aruco.DetectorParameters_create()
- self.__detector_parameters.cornerRefinementMethod = aruco.CORNER_REFINE_CONTOUR
+ self.__detector_parameters.cornerRefinementMethod = aruco.CORNER_REFINE_CONTOUR # to get a better pose estimation
+ self.__detector_parameters_loaded = {}
# define tracked markers data
self.__markers_corners = []
@@ -74,29 +75,29 @@ class ArUcoTracker():
self.__board_corners_ids = []
def load_configuration_file(self, configuration_filepath):
- """Load aruco detection parameters from .json file.
- """
- print(f'ArUcoTracker configuration for {self.__aruco_dict.get_markers_format()} markers detection:')
+ """Load aruco detection parameters from .json file."""
+
with open(configuration_filepath) as configuration_file:
- configuration = json.load(configuration_file)
+ self.__detector_parameters_loaded = json.load(configuration_file)
- for key, value in configuration.items():
+ for key, value in self.__detector_parameters_loaded.items():
try:
setattr(self.__detector_parameters, key, value)
- print(f'\t{key}: {getattr(self.__detector_parameters, key)}')
except AttributeError as error:
print(error)
- def print_configuration(self):
+ def print_configuration(self, print_all=False):
"""Print aruco detection parameters."""
- print(f'ArUcoTracker configuration for {self.__aruco_dict.get_markers_format()} markers detection:')
- for parameters in ArUcoTrackerParameters:
- print(f'\t{parameters}: {getattr(self.__detector_parameters, parameters)}')
+ for parameter in ArUcoTrackerParameters:
+ if parameter in self.__detector_parameters_loaded.keys():
+ print(f'\t*{parameter}: {getattr(self.__detector_parameters, parameter)}')
+ elif print_all:
+ print(f'\t{parameter}: {getattr(self.__detector_parameters, parameter)}')
def track(self, frame, estimate_pose = True):
"""Track ArUco markers in frame."""
@@ -162,6 +163,10 @@ class ArUcoTracker():
cv.drawChessboardCorners(frame, ((self.__board.get_size()[0] - 1 ), (self.__board.get_size()[1] - 1)), self.__board_corners, True)
+ def get_markers_dictionay(self):
+ """Get tracked aruco markers dictionary."""
+ return self.__aruco_dict
+
def get_markers_number(self):
"""Get tracked markers number."""
return len(self.__markers_corners)
diff --git a/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py b/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py
index 52103fe..7a270f3 100644
--- a/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py
+++ b/src/argaze/utils/export_tobii_segment_aruco_visual_scan.py
@@ -25,16 +25,19 @@ def main():
parser = argparse.ArgumentParser(description=main.__doc__.split('-')[0])
parser.add_argument('-s', '--segment_path', metavar='SEGMENT_PATH', type=str, default=None, help='segment path')
parser.add_argument('-r', '--time_range', metavar=('START_TIME', 'END_TIME'), nargs=2, type=float, default=(0., None), help='start and end time (in second)')
- parser.add_argument('-c', '--camera_calibration', metavar='CAM_CALIB', type=str, default='tobii_camera.json', help='json camera calibration filepath')
- parser.add_argument('-a', '--aoi_scene', metavar='AOI_SCENE', type=str, default='aoi3D_scene.obj', help='obj aoi scene filepath')
+ parser.add_argument('-c', '--camera_calibration', metavar='CAM_CALIB', type=str, default=None, help='json camera calibration filepath')
+ parser.add_argument('-p', '--aruco_tracker_configuration', metavar='TRACK_CONFIG', type=str, default=None, help='json aruco tracker configuration filepath')
+ parser.add_argument('-a', '--aoi_scene', metavar='AOI_SCENE', type=str, default=None, help='obj aoi scene filepath')
parser.add_argument('-d', '--dictionary', metavar='DICT', type=str, default='DICT_ARUCO_ORIGINAL', help='aruco marker dictionnary (DICT_4X4_50, DICT_4X4_100, DICT_4X4_250, DICT_4X4_1000, DICT_5X5_50, DICT_5X5_100, DICT_5X5_250, DICT_5X5_1000, DICT_6X6_50, DICT_6X6_100, DICT_6X6_250, DICT_6X6_1000, DICT_7X7_50, DICT_7X7_100, DICT_7X7_250, DICT_7X7_1000, DICT_ARUCO_ORIGINAL,DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, DICT_APRILTAG_36h10, DICT_APRILTAG_36h11)')
parser.add_argument('-m', '--marker_size', metavar='MARKER_SIZE', type=float, default=6, help='aruco marker size (cm)')
parser.add_argument('-i', '--markers_id', metavar='MARKERS_ID', nargs='*', type=int, default=[], help='markers id to track')
parser.add_argument('-o', '--output', metavar='OUT', type=str, default=None, help='destination folder path (segment folder by default)')
+ parser.add_argument('-w', '--window', metavar='DISPLAY', type=bool, default=True, help='enable window display', action=argparse.BooleanOptionalAction)
args = parser.parse_args()
if args.segment_path != None:
+ # Manage markers id to track
empty_marker_set = len(args.markers_id) == 0
if empty_marker_set:
print(f'Track any Aruco markers from the {args.dictionary} dictionary')
@@ -42,6 +45,7 @@ def main():
print(f'Track Aruco markers {args.markers_id} from the {args.dictionary} dictionary')
# Manage destination path
+ destination_path = '.'
if args.output != None:
if not os.path.exists(os.path.dirname(args.output)):
@@ -49,26 +53,29 @@ def main():
os.makedirs(os.path.dirname(args.output))
print(f'{os.path.dirname(args.output)} folder created')
- vs_data_filepath = f'{args.output}/visual_scan.csv'
- vs_visu_filepath = f'{args.output}/visual_scan.jpg'
- vs_video_filepath = f'{args.output}/visual_scan.mp4'
+ destination_path = args.output
else:
- vs_data_filepath = f'{args.segment_path}/visual_scan.csv'
- vs_visu_filepath = f'{args.segment_path}/visual_scan.jpg'
- vs_video_filepath = f'{args.segment_path}/visual_scan.mp4'
+ destination_path = args.segment_path
+
+ vs_data_filepath = f'{destination_path}/visual_scan.csv'
+ vs_visu_filepath = f'{destination_path}/visual_scan.jpg'
+ vs_video_filepath = f'{destination_path}/visual_scan.mp4'
# Load a tobii segment
tobii_segment = TobiiEntities.TobiiSegment(args.segment_path, int(args.time_range[0] * 1000000), int(args.time_range[1] * 1000000) if args.time_range[1] != None else None)
# Load a tobii segment video
tobii_segment_video = tobii_segment.load_video()
- print(f'Video duration: {tobii_segment_video.get_duration()/1000000}, width: {tobii_segment_video.get_width()}, height: {tobii_segment_video.get_height()}')
+ print(f'Video properties:\n\tduration: {tobii_segment_video.get_duration()/1000000} s\n\twidth: {tobii_segment_video.get_width()} px\n\theight: {tobii_segment_video.get_height()} px')
# Load a tobii segment data
tobii_segment_data = tobii_segment.load_data()
- print(f'Data keys: {tobii_segment_data.keys()}')
+
+ print(f'Data keys:')
+ for name in tobii_segment_data.keys():
+ print(f'\t{name}')
# Access to timestamped gaze positions data buffer
tobii_ts_gaze_positions = tobii_segment_data.gidx_l_gp
@@ -83,15 +90,42 @@ def main():
# Create aruco camera
aruco_camera = ArUcoCamera.ArUcoCamera()
- aruco_camera.load_calibration_file(args.camera_calibration)
+
+ # Load calibration file
+ if args.camera_calibration != None:
+
+ aruco_camera.load_calibration_file(args.camera_calibration)
+
+ else:
+
+ raise ValueError('.json camera calibration filepath required. Use -c option.')
# Create aruco tracker
aruco_tracker = ArUcoTracker.ArUcoTracker(args.dictionary, args.marker_size, aruco_camera)
+ # Load specific configuration file
+ if args.aruco_tracker_configuration != None:
+
+ aruco_tracker.load_configuration_file(args.aruco_tracker_configuration)
+
+ print(f'ArUcoTracker configuration for {aruco_tracker.get_markers_dictionay().get_markers_format()} markers detection:')
+ aruco_tracker.print_configuration()
+
# Create AOIs 3D scene
aoi3D_scene = AOI3DScene.AOI3DScene()
- aoi3D_scene.load(args.aoi_scene)
- print(f'AOIs names: {aoi3D_scene.keys()}')
+
+ # Load AOI 3D scene file
+ if args.aoi_scene != None:
+
+ aoi3D_scene.load(args.aoi_scene)
+
+ print(f'AOI names:')
+ for name in aoi3D_scene.keys():
+ print(f'\t{name}')
+
+ else:
+
+ raise ValueError('.json AOI scene filepath required. Use -a option.')
# Create timestamped buffer to store AOIs scene in time
ts_aois_scenes = AOIFeatures.TimeStampedAOIScenes()
@@ -105,6 +139,8 @@ def main():
visu_ratio = visu_height
visu_frame = numpy.full((visu_height, visu_width, 3), 255, dtype=numpy.uint8)
+ cv.putText(visu_frame, f'Segment time range: {int(args.time_range[0] * 1000)} - {int(args.time_range[1] * 1000)} ms', (20, 40), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 1, cv.LINE_AA)
+
# Project 3D scene on the reference frame
# TODO : center projection on a reference AOI
ref_aoi = 'Scene_Plan'
@@ -130,6 +166,11 @@ def main():
# Iterate on video frames
for video_ts, video_frame in tobii_segment_video.frames():
+ video_ts_ms = video_ts / 1000
+
+ # write segment timing
+ cv.putText(video_frame.matrix, f'Segment time: {int(video_ts_ms)} ms', (20, 40), cv.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 1, cv.LINE_AA)
+
try:
# Get closest gaze position before video timestamp and remove all gaze positions before
@@ -140,7 +181,7 @@ def main():
cv.circle(video_frame.matrix, video_gaze_pixel, 4, (0, 255, 255), -1)
# Store gaze position at this time in millisecond
- ts_gaze_positions[round(video_ts/1000)] = video_gaze_pixel
+ ts_gaze_positions[round(video_ts_ms)] = video_gaze_pixel
# Wait for gaze position
except ValueError:
@@ -173,7 +214,7 @@ def main():
aoi2D_video_scene.draw(video_frame.matrix, video_gaze_pixel)
# Store 2D scene at this time in millisecond
- ts_aois_scenes[round(video_ts/1000)] = aoi2D_video_scene
+ ts_aois_scenes[round(video_ts_ms)] = aoi2D_video_scene
# Draw gaze path
look_at = aoi2D_video_scene[ref_aoi].look_at(video_gaze_pixel)
@@ -181,21 +222,23 @@ def main():
visu_gaze_pixel = aoi2D_visu_scene[ref_aoi].looked_pixel(look_at)
cv.circle(visu_frame, visu_gaze_pixel, 4, (0, 0, 255), -1)
- # Close window using 'Esc' key
- if cv.waitKey(1) == 27:
- break
+ if args.window:
+
+ # Close window using 'Esc' key
+ if cv.waitKey(1) == 27:
+ break
- # Display video
- cv.imshow(f'Segment {tobii_segment.get_id()} video', video_frame.matrix)
+ # Display video
+ cv.imshow(f'Segment {tobii_segment.get_id()} ArUco AOI', video_frame.matrix)
- # Display visual scan frame
- cv.imshow(f'Segment {tobii_segment.get_id()} visual scan', visu_frame)
+ # Display visual scan frame
+ cv.imshow(f'Segment {tobii_segment.get_id()} visual scan', visu_frame)
# Write video
output_video.write(video_frame.matrix)
# Update Progress Bar
- progress = video_ts - int(args.time_range[0] * 1000000)
+ progress = video_ts_ms - int(args.time_range[0] * 1000)
MiscFeatures.printProgressBar(progress, tobii_segment_video.get_duration(), prefix = 'Progress:', suffix = 'Complete', length = 100)
# Exit on 'ctrl+C' interruption
diff --git a/src/argaze/utils/export_tobii_segment_movements.py b/src/argaze/utils/export_tobii_segment_movements.py
index 8ae074a..0b0d867 100644
--- a/src/argaze/utils/export_tobii_segment_movements.py
+++ b/src/argaze/utils/export_tobii_segment_movements.py
@@ -21,11 +21,13 @@ def main():
parser.add_argument('-d', '--dispersion_threshold', metavar='DISPERSION_THRESHOLD', type=int, default=10, help='dispersion threshold in pixel')
parser.add_argument('-t', '--duration_threshold', metavar='DURATION_THRESHOLD', type=int, default=100, help='duration threshold in millisecond')
parser.add_argument('-o', '--output', metavar='OUT', type=str, default=None, help='destination folder path (segment folder by default)')
+ parser.add_argument('-w', '--window', metavar='DISPLAY', type=bool, default=True, help='enable window display', action=argparse.BooleanOptionalAction)
args = parser.parse_args()
if args.segment_path != None:
# Manage destination path
+ destination_path = '.'
if args.output != None:
if not os.path.exists(os.path.dirname(args.output)):
@@ -33,28 +35,30 @@ def main():
os.makedirs(os.path.dirname(args.output))
print(f'{os.path.dirname(args.output)} folder created')
- gaze_video_filepath = f'{args.output}/movements.mp4'
- fixations_filepath = f'{args.output}/movements_fixations.csv'
- saccades_filepath = f'{args.output}/movements_saccades.csv'
- movements_filepath = f'{args.output}/movements.csv'
+ destination_path = args.output
else:
- gaze_video_filepath = f'{args.segment_path}/movements.mp4'
- fixations_filepath = f'{args.segment_path}/movements_fixations.csv'
- saccades_filepath = f'{args.segment_path}/movements_saccades.csv'
- movements_filepath = f'{args.segment_path}/movements.csv'
+ destination_path = args.segment_path
+
+ gaze_video_filepath = f'{destination_path}/movements.mp4'
+ fixations_filepath = f'{destination_path}/movements_fixations.csv'
+ saccades_filepath = f'{destination_path}/movements_saccades.csv'
+ movements_filepath = f'{destination_path}/movements.csv'
# Load a tobii segment
tobii_segment = TobiiEntities.TobiiSegment(args.segment_path, int(args.time_range[0] * 1000000), int(args.time_range[1] * 1000000) if args.time_range[1] != None else None)
# Load a tobii segment video
tobii_segment_video = tobii_segment.load_video()
- print(f'Video duration: {tobii_segment_video.get_duration()/1000000}, width: {tobii_segment_video.get_width()}, height: {tobii_segment_video.get_height()}')
+ print(f'Video properties:\n\tduration: {tobii_segment_video.get_duration()/1000000} s\n\twidth: {tobii_segment_video.get_width()} px\n\theight: {tobii_segment_video.get_height()} px')
# Load a tobii segment data
tobii_segment_data = tobii_segment.load_data()
- print(f'Data keys: {tobii_segment_data.keys()}')
+
+ print(f'Data keys:')
+ for name in tobii_segment_data.keys():
+ print(f'\t{name}')
# Access to timestamped gaze position data buffer
tobii_ts_gaze_positions = tobii_segment_data.gidx_l_gp
@@ -131,7 +135,6 @@ def main():
current_saccade_ts, current_saccade = saccades.pop_first()
-
# Iterate on video frames
for video_ts, video_frame in tobii_segment_video.frames():
@@ -179,6 +182,15 @@ def main():
except ValueError:
pass
+ if args.window:
+
+ # Close window using 'Esc' key
+ if cv.waitKey(1) == 27:
+ break
+
+ # Display video
+ cv.imshow(f'Segment {tobii_segment.get_id()} movements', video_frame.matrix)
+
# Write video
output_video.write(video_frame.matrix)
@@ -194,8 +206,6 @@ def main():
output_video.close()
print(f'\nVideo with movements saved into {gaze_video_filepath}')
-
-
if __name__ == '__main__':
main() \ No newline at end of file