From 5e68506aba8e9b8f3b4578dd94570a0ae113f68c Mon Sep 17 00:00:00 2001 From: Mihai Dusmanu Date: Mon, 27 Feb 2023 10:33:57 +0100 Subject: [PATCH 1/5] Updated data format. --- CAPTURE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CAPTURE.md b/CAPTURE.md index c3b4c73..07c9e61 100644 --- a/CAPTURE.md +++ b/CAPTURE.md @@ -76,7 +76,7 @@ A Python interface that mirrors this file structure is available in `scantools.c ### 1. Session data - `sensors.txt`, `rigs.txt`, `trajectories.txt` follow [the Kapture format](https://github.com/naver/kapture/blob/main/kapture_format.adoc#2--sensors). However, the pose convention is reverted: `rigs.txt` contains camera-to-rig transformations and `trajectories.txt` contains sensor-to-world transformations. -- `images.txt`, `pointclouds.txt`, `depths.txt`, `wifi.txt`, and `bt.txt` follow the specifications of their corresponding `records_*.txt` in Kapture. +- `images.txt`, `pointclouds.txt`, `depths.txt`, `bt.txt`, `wifi.txt`, `accel.txt`, `gravity.txt`, `gyro.txt`, and `mag.txt` follow the specifications of their corresponding `records_*.txt` in Kapture. `gravity.txt` contains gravity direction estimates (down vector in sensor frame at each timestamp) from the onboard VIO system. ### 2. Processed files From 95c50903f2a6c3b74bc4a7047aa282a663011881 Mon Sep 17 00:00:00 2001 From: Mihai Dusmanu Date: Mon, 27 Feb 2023 10:34:41 +0100 Subject: [PATCH 2/5] Records. --- scantools/capture/records.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/scantools/capture/records.py b/scantools/capture/records.py index e5a7a8e..102928f 100644 --- a/scantools/capture/records.py +++ b/scantools/capture/records.py @@ -143,6 +143,40 @@ class RecordsLidar(RecordsFilePath): field_names = ['point_cloud_path'] +# IMU data. +class RecordsVector3f(RecordsBase[np.ndarray]): + record_type = np.ndarray + field_names = ['x', 'y', 'z'] + + def record_to_list(self, record: np.ndarray) -> List[str]: + return list(map(str, record)) + + @classmethod + def load(cls, path: Path) -> 'RecordsVector3f': + table = read_csv(path) + records = cls() + for timestamp, sensor_id, *data in table: + assert len(data) == 3 + records[int(timestamp), sensor_id] = np.array( + list(map(float, data))) + return records + + +class RecordsAccelerometer(RecordsVector3f): + field_names = ['accel_x', 'accel_y', 'accel_z'] + + +class RecordsGravity(RecordsVector3f): + field_names = ['g_x', 'g_y', 'g_z'] + + +class RecordsGyroscope(RecordsVector3f): + field_names = ['gyro_x', 'gyro_y', 'gyro_z'] + + +class RecordsMagnetometer(RecordsVector3f): + field_names = ['mag_x', 'mag_y', 'mag_z'] + # New data types inherit from RecordEntry (a record) and RecordsArray (mapping of records) @dataclass From 8aca8e46a022e436711e57dcfcd4ed0216c976e7 Mon Sep 17 00:00:00 2001 From: Mihai Dusmanu Date: Mon, 27 Feb 2023 10:35:07 +0100 Subject: [PATCH 3/5] Session. --- scantools/capture/session.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/scantools/capture/session.py b/scantools/capture/session.py index 2bf0b2d..c4f6856 100644 --- a/scantools/capture/session.py +++ b/scantools/capture/session.py @@ -7,7 +7,9 @@ from .sensors import Sensors, Camera from .rigs import Rigs from .trajectories import Trajectories -from .records import RecordsBluetooth, RecordsCamera, RecordsDepth, RecordsLidar, RecordsWifi +from .records import ( + RecordsAccelerometer, RecordsBluetooth, RecordsCamera, RecordsDepth, RecordsGravity, + RecordsGyroscope, RecordsLidar, RecordsMagnetometer, RecordsWifi) from .proc import Proc from .pose import Pose @@ -41,6 +43,10 @@ class Session: pointclouds: Optional[RecordsLidar] = None wifi: Optional[RecordsWifi] = None bt: Optional[RecordsBluetooth] = None + accel: Optional[RecordsAccelerometer] = None + gravity: Optional[RecordsGravity] = None + gyro: Optional[RecordsGyroscope] = None + mag: Optional[RecordsMagnetometer] = None proc: Optional[Proc] = None id: Optional[str] = None @@ -52,7 +58,8 @@ def __post_init__(self): all_devices = set(self.sensors.keys()) if self.rigs is not None: assert len(self.sensors.keys() & self.rigs.keys()) == 0 - assert len(self.rigs.sensor_ids - self.sensors.keys()) == 0 + # TODO: Fix me - currently missing calibration for IMUs. + # assert len(self.rigs.sensor_ids - self.sensors.keys()) == 0 all_devices |= self.rigs.keys() if self.trajectories is not None: assert len(self.trajectories.device_ids - all_devices) == 0 @@ -75,7 +82,7 @@ def filename(cls, attr: Union[Field, str]) -> str: return f'{name}.txt' @classmethod - def load(cls, path: Path, wireless=True) -> 'Session': + def load(cls, path: Path, wireless=True, imu=True) -> 'Session': if not path.exists(): raise IOError(f'Session directory does not exists: {path}') data = {} @@ -95,6 +102,8 @@ def load(cls, path: Path, wireless=True) -> 'Session': else: if attr.name in ['bt', 'wifi'] and not wireless: continue + if attr.name in ['accel', 'gravity', 'gyro', 'mag'] and not imu: + continue obj = type_.load(filepath) data[attr.name] = obj if 'sensors' not in data: From 97dcd07e0ba40f56b1ac475510ab81188c2a15f9 Mon Sep 17 00:00:00 2001 From: Mihai Dusmanu Date: Tue, 21 Mar 2023 10:13:53 +0100 Subject: [PATCH 4/5] Single. --- CAPTURE.md | 2 +- scantools/capture/records.py | 20 ++------------------ scantools/capture/session.py | 9 +++------ 3 files changed, 6 insertions(+), 25 deletions(-) diff --git a/CAPTURE.md b/CAPTURE.md index 07c9e61..7348375 100644 --- a/CAPTURE.md +++ b/CAPTURE.md @@ -76,7 +76,7 @@ A Python interface that mirrors this file structure is available in `scantools.c ### 1. Session data - `sensors.txt`, `rigs.txt`, `trajectories.txt` follow [the Kapture format](https://github.com/naver/kapture/blob/main/kapture_format.adoc#2--sensors). However, the pose convention is reverted: `rigs.txt` contains camera-to-rig transformations and `trajectories.txt` contains sensor-to-world transformations. -- `images.txt`, `pointclouds.txt`, `depths.txt`, `bt.txt`, `wifi.txt`, `accel.txt`, `gravity.txt`, `gyro.txt`, and `mag.txt` follow the specifications of their corresponding `records_*.txt` in Kapture. `gravity.txt` contains gravity direction estimates (down vector in sensor frame at each timestamp) from the onboard VIO system. +- `images.txt`, `pointclouds.txt`, `depths.txt`, `bt.txt`, `wifi.txt`, `imu.txt`, and `gravity.txt` follow the specifications of their corresponding `records_*.txt` in Kapture. `gravity.txt` contains gravity direction estimates (down vector in sensor frame at each timestamp) from the onboard VIO system. ### 2. Processed files diff --git a/scantools/capture/records.py b/scantools/capture/records.py index 102928f..902c2ca 100644 --- a/scantools/capture/records.py +++ b/scantools/capture/records.py @@ -144,7 +144,7 @@ class RecordsLidar(RecordsFilePath): # IMU data. -class RecordsVector3f(RecordsBase[np.ndarray]): +class RecordsIMU(RecordsBase[np.ndarray]): record_type = np.ndarray field_names = ['x', 'y', 'z'] @@ -152,7 +152,7 @@ def record_to_list(self, record: np.ndarray) -> List[str]: return list(map(str, record)) @classmethod - def load(cls, path: Path) -> 'RecordsVector3f': + def load(cls, path: Path) -> 'RecordsIMU': table = read_csv(path) records = cls() for timestamp, sensor_id, *data in table: @@ -162,22 +162,6 @@ def load(cls, path: Path) -> 'RecordsVector3f': return records -class RecordsAccelerometer(RecordsVector3f): - field_names = ['accel_x', 'accel_y', 'accel_z'] - - -class RecordsGravity(RecordsVector3f): - field_names = ['g_x', 'g_y', 'g_z'] - - -class RecordsGyroscope(RecordsVector3f): - field_names = ['gyro_x', 'gyro_y', 'gyro_z'] - - -class RecordsMagnetometer(RecordsVector3f): - field_names = ['mag_x', 'mag_y', 'mag_z'] - - # New data types inherit from RecordEntry (a record) and RecordsArray (mapping of records) @dataclass class RecordEntry: diff --git a/scantools/capture/session.py b/scantools/capture/session.py index c4f6856..7cccc7b 100644 --- a/scantools/capture/session.py +++ b/scantools/capture/session.py @@ -8,8 +8,7 @@ from .rigs import Rigs from .trajectories import Trajectories from .records import ( - RecordsAccelerometer, RecordsBluetooth, RecordsCamera, RecordsDepth, RecordsGravity, - RecordsGyroscope, RecordsLidar, RecordsMagnetometer, RecordsWifi) + RecordsBluetooth, RecordsCamera, RecordsDepth, RecordsIMU, RecordsLidar, RecordsWifi) from .proc import Proc from .pose import Pose @@ -43,10 +42,8 @@ class Session: pointclouds: Optional[RecordsLidar] = None wifi: Optional[RecordsWifi] = None bt: Optional[RecordsBluetooth] = None - accel: Optional[RecordsAccelerometer] = None - gravity: Optional[RecordsGravity] = None - gyro: Optional[RecordsGyroscope] = None - mag: Optional[RecordsMagnetometer] = None + imu: Optional[RecordsIMU] = None + gravity: Optional[RecordsIMU] = None proc: Optional[Proc] = None id: Optional[str] = None From 37bc7ad09561d075db5ae8cf076cf0227aecd50e Mon Sep 17 00:00:00 2001 From: Mihai Dusmanu Date: Tue, 21 Mar 2023 10:59:44 +0100 Subject: [PATCH 5/5] Bugfix. --- scantools/capture/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scantools/capture/session.py b/scantools/capture/session.py index 7cccc7b..897d6bb 100644 --- a/scantools/capture/session.py +++ b/scantools/capture/session.py @@ -99,7 +99,7 @@ def load(cls, path: Path, wireless=True, imu=True) -> 'Session': else: if attr.name in ['bt', 'wifi'] and not wireless: continue - if attr.name in ['accel', 'gravity', 'gyro', 'mag'] and not imu: + if attr.name in ['gravity', 'imu'] and not imu: continue obj = type_.load(filepath) data[attr.name] = obj