Skip to content

Commit 6370dde

Browse files
author
Nisse Knudsen
committed
Updated API to changed data set structure; simplified code by inheritance; updated README accordingly; added nisse+peter to authors
1 parent 71c625e commit 6370dde

File tree

8 files changed

+91
-125
lines changed

8 files changed

+91
-125
lines changed

README.md

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -50,35 +50,26 @@ seq002 = dataset['002']
5050

5151
#### Loading
5252
The devkit will automatically search the sequence directory for available sensor and meta data and prepare the path for a loading step. At this point no point clouds or images have been loaded into memory.
53-
To execute the loading of sensor and meta data into memory, we simply call the `load()` method on the sequence object. This will load all available sensor and meta data. If only specific sensors or meta data is required, there are more specific methods available.
53+
To execute the loading of sensor and meta data into memory, we simply call the `load()` method on the sequence object. This will load all available sensor and meta data. If only specific sensors or meta data is required, there are more specific methods available which can also be chained to each other.
5454
```python
5555
seq002.load()
5656

5757
# OR
5858

59-
seq002.load_lidar()
60-
seq002.load_camera()
61-
seq002.load_gps_poses()
62-
seq002.load_timestamps()
63-
seq002.load_cuboids()
64-
```
65-
66-
Since not everybody might want to work with full sampling rate, each of the `load()` methods accept a _3-tuple_ which serves as a slicing information. In the following example, we want every second frame between frame 10 and frame 50 loaded. It is equivalent to slicing a python array using `my_array[10:50:2]`.
67-
```python
68-
seq002.load((10, 50, 2))
59+
seq002.load_lidar().load_cuboids()
6960
```
7061

7162
#### Data Access
7263

7364
##### LiDAR
7465
The LiDAR point clouds are stored as [pandas.DataFrames](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html#pandas.DataFrame) and therefore allow to leverage their extensive API for data manipulation. This includes the simple return as a [numpy.ndarray](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html).
7566
```python
76-
pc0 = seq002.lidar.data[0]
67+
pc0 = seq002.lidar[0]
7768
print(pc0.columns) # Index(['x', 'y', 'z', 'i', 't', 'd'], dtype='object')
7869

79-
pc0_np = seq002.lidar.data[0].to_numpy()
70+
pc0_np = seq002.lidar[0].to_numpy()
8071
# OR
81-
pc0_np = seq002.lidar.data[0].values
72+
pc0_np = seq002.lidar[0].values
8273
```
8374

8475
##### Cameras
@@ -89,7 +80,7 @@ print(seq002.camera.keys()) # ['front_camera', 'left_camera', 'back_camera', 'r
8980
Each camera name has its recordings loaded as [Pillow Image](https://pillow.readthedocs.io/en/stable/reference/Image.html) object, and can be accessed via normal list slicing. In the following example, we select the first image from the front camera and display it using the Pillow library in Python.
9081
```python
9182
front_camera = seq002.camera['front_camera']
92-
img0 = front_camera.data[0]
83+
img0 = front_camera[0]
9384
img0.show()
9485
```
9586
Afterwards the extensive Pillow Image API can be used for image manipulation, conversion or export.
@@ -101,18 +92,18 @@ In addition to the sensor data, the loaded data set also contains the following
10192

10293
These can be directly accessed through the known list slicing operations, and read in their dict format. For example, the following example shows how to get the GPS coordinates of the vehicle on the first frame.
10394
```python
104-
pose0 = seq002.gps_poses.data[0]
95+
pose0 = seq002.gps[0]
10596
lat0 = pose0['lat']
10697
long0 = pose0['long']
10798
```
10899

109100
#### Annotations
110101

111102
The LiDAR Cuboid annotations are also stored inside the sequence object as a [pandas.DataFrames](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html#pandas.DataFrame) for each timestamp.
112-
The position coordinates (`positin.x`,`position.y`,`position.z`) are located at the center of a cuboid. `dimensions.x` is the width of the cuboid from left to right, `dimensions.y` is the length of the cuboid from front to back and `dimensions.z` is the height of the cuboid from top to bottom.
103+
The position coordinates (`position.x`,`position.y`,`position.z`) are located at the center of a cuboid. `dimensions.x` is the width of the cuboid from left to right, `dimensions.y` is the length of the cuboid from front to back and `dimensions.z` is the height of the cuboid from top to bottom.
113104

114105
```python
115-
cuboids0 = seq002.cuboids.data[0]
106+
cuboids0 = seq002.cuboids[0]
116107
print(cuboids0.columns) # Index(['uuid', 'label', 'yaw', 'stationary', 'camera_used', 'position.x', 'position.y', 'position.z', 'dimensions.x', 'dimensions.y', 'dimensions.z', 'attributes.Object Motion', 'attributes.Rider Status', 'attributes.Pedestrian Behavior', 'attributes.Pedestrian Age'], dtype='object')
117108
```
118109

python/pandaset/annotations.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import glob
2+
23
import pandas as pd
34

45

@@ -9,6 +10,9 @@ def __init__(self, directory):
910
self.data = None
1011
self._load_data_structure()
1112

13+
def __getitem__(self, item):
14+
return self.data[item]
15+
1216
def _load_data_structure(self):
1317
self._data_structure = sorted(glob.glob(f'{self._directory}/*.pkl.gz'))
1418

python/pandaset/dataset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from .utils import subdirectories
21
from .sequence import Sequence
2+
from .utils import subdirectories
33

44

55
class DataSet:

python/pandaset/meta.py

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,40 @@
1-
import os.path
21
import json
2+
import os.path
33

44

5-
class GPSPoses:
6-
def __init__(self, directory):
5+
class Meta:
6+
def __init__(self, directory, filename):
77
self._directory = directory
88
self._data_structure = None
99
self.data = None
1010
self._load_data_structure()
1111

12+
def __getitem__(self, item):
13+
return self.data[item]
14+
15+
def load(self):
16+
self._load_data()
17+
1218
def _load_data_structure(self):
13-
meta_file = f'{self._directory}/gps_poses.json'
19+
meta_file = f'{self._directory}/{self.filename}'
1420
if os.path.isfile(meta_file):
1521
self._data_structure = meta_file
1622

17-
def load_data(self, sl):
23+
def _load_data(self):
1824
self.data = []
1925
with open(self._data_structure, 'r') as f:
2026
file_data = json.load(f)
21-
for entry in file_data[sl]:
27+
for entry in file_data:
2228
self.data.append(
2329
entry
2430
)
2531

2632

27-
class Timestamps:
33+
class GPS(Meta):
2834
def __init__(self, directory):
29-
self._directory = directory
30-
self._data_structure = None
31-
self.data = None
32-
self._load_data_structure()
35+
Meta.__init__(self, directory, 'gps.json')
3336

34-
def _load_data_structure(self):
35-
meta_file = f'{self._directory}/timestamps.json'
36-
if os.path.isfile(meta_file):
37-
self._data_structure = meta_file
3837

39-
def load_data(self, sl):
40-
self.data = []
41-
with open(self._data_structure, 'r') as f:
42-
file_data = json.load(f)
43-
for entry in file_data[sl]:
44-
self.data.append(
45-
entry
46-
)
38+
class Timestamps(Meta):
39+
def __init__(self, directory):
40+
Meta.__init__(self, directory, 'timestamps.json')

python/pandaset/sensors.py

Lines changed: 31 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import glob
2+
import json
3+
import os.path
4+
25
import pandas as pd
36
from PIL import Image
4-
import os.path
5-
import json
67

78

89
class Sensor:
@@ -11,7 +12,7 @@ def __init__(self, directory, data_file_extension):
1112
self._data_file_extension = data_file_extension
1213
self._data_structure = None
1314
self.data = None
14-
self._pose_structure = None
15+
self._poses_structure = None
1516
self.poses = None
1617
self._timestamps_structure = None
1718
self.timestamps = None
@@ -23,86 +24,60 @@ def __getitem__(self, item):
2324
def _load_data_structure(self):
2425
self._data_structure = sorted(glob.glob(f'{self._directory}/*.{self._data_file_extension}'))
2526

26-
positions_file = f'{self._directory}/positions.json'
27-
if os.path.isfile(positions_file):
28-
self._pose_structure = positions_file
27+
poses_file = f'{self._directory}/poses.json'
28+
if os.path.isfile(poses_file):
29+
self._poses_structure = poses_file
2930

3031
timestamps_file = f'{self._directory}/timestamps.json'
3132
if os.path.isfile(timestamps_file):
3233
self._timestamps_structure = timestamps_file
3334

35+
def load(self):
36+
self._load_data()
37+
self._load_poses()
38+
self._load_timestamps()
3439

35-
class Lidar(Sensor):
36-
37-
def __init__(self, directory):
38-
Sensor.__init__(self, directory, 'pkl.gz')
39-
40-
def load_data(self, sl):
40+
def _load_data(self):
4141
self.data = []
42-
for fp in self._data_structure[sl]:
42+
for fp in self._data_structure:
4343
self.data.append(
44-
pd.read_pickle(fp)
44+
self._load_data_file(fp)
4545
)
46-
self.load_positions(sl)
47-
self.load_timestamps(sl)
4846

49-
def load_positions(self, sl):
47+
def _load_poses(self):
5048
self.poses = []
51-
with open(self._pose_structure, 'r') as f:
49+
with open(self._poses_structure, 'r') as f:
5250
file_data = json.load(f)
53-
for entry in file_data[sl]:
51+
for entry in file_data:
5452
self.poses.append(
5553
entry
5654
)
5755

58-
def load_timestamps(self, sl):
56+
def _load_timestamps(self):
5957
self.timestamps = []
6058
with open(self._timestamps_structure, 'r') as f:
6159
file_data = json.load(f)
62-
for entry in file_data[sl]:
60+
for entry in file_data:
6361
self.timestamps.append(
6462
entry
6563
)
6664

65+
def _load_data_file(self, fp):
66+
return None
6767

68-
class Camera(Sensor):
69-
def __init__(self, directory):
70-
Sensor.__init__(self, directory, 'jpg')
7168

72-
def _load_data_structure(self):
73-
self._data_structure = sorted(glob.glob(f'{self._directory}/*.jpg'))
69+
class Lidar(Sensor):
7470

75-
positions_file = f'{self._directory}/positions.json'
76-
if os.path.isfile(positions_file):
77-
self._pose_structure = positions_file
71+
def __init__(self, directory):
72+
Sensor.__init__(self, directory, 'pkl.gz')
7873

79-
timestamps_file = f'{self._directory}/timestamps.json'
80-
if os.path.isfile(timestamps_file):
81-
self._timestamps_structure = timestamps_file
74+
def _load_data_file(self, fp):
75+
return pd.read_pickle(fp)
8276

83-
def load_data(self, sl):
84-
self.data = []
85-
for fp in self._data_structure[sl]:
86-
self.data.append(
87-
Image.open(fp)
88-
)
89-
self.load_positions(sl)
90-
self.load_timestamps(sl)
9177

92-
def load_positions(self, sl):
93-
self.poses = []
94-
with open(self._pose_structure, 'r') as f:
95-
file_data = json.load(f)
96-
for entry in file_data[sl]:
97-
self.poses.append(
98-
entry
99-
)
78+
class Camera(Sensor):
79+
def __init__(self, directory):
80+
Sensor.__init__(self, directory, 'jpg')
10081

101-
def load_timestamps(self, sl):
102-
self.timestamps = []
103-
with open(self._timestamps_structure, 'r') as f:
104-
file_data = json.load(f)
105-
for entry in file_data[sl]:
106-
self.timestamps.append(
107-
entry
108-
)
82+
def _load_data_file(self, fp):
83+
return Image.open(fp)

python/pandaset/sequence.py

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from .utils import subdirectories
22
from .sensors import Lidar
33
from .sensors import Camera
4-
from .meta import GPSPoses
4+
from .meta import GPS
55
from .meta import Timestamps
66
from .annotations import Cuboids
77

@@ -11,7 +11,7 @@ def __init__(self, directory):
1111
self._directory = directory
1212
self.lidar = None
1313
self.camera = None
14-
self.gps_poses = None
14+
self.gps = None
1515
self.timestamps = None
1616
self.cuboids = None
1717
self._load_data_structure()
@@ -29,33 +29,38 @@ def _load_data_structure(self):
2929
camera_name = cd.split('/')[-1]
3030
self.camera[camera_name] = Camera(cd)
3131
if dd.endswith('meta'):
32-
self.gps_poses = GPSPoses(dd)
32+
self.gps = GPS(dd)
3333
self.timestamps = Timestamps(dd)
3434
if dd.endswith('annotations'):
3535
annotation_directories = subdirectories(dd)
3636
for ad in annotation_directories:
3737
if ad.endswith('cuboids'):
3838
self.cuboids = Cuboids(ad)
3939

40-
def load(self, sl=(None, None, None)):
41-
self.load_lidar(sl)
42-
self.load_camera(sl)
43-
self.load_gps_poses(sl)
44-
self.load_timestamps(sl)
45-
self.load_cuboids(sl)
40+
def load(self):
41+
self.load_lidar()
42+
self.load_camera()
43+
self.load_gps()
44+
self.load_timestamps()
45+
self.load_cuboids()
4646

47-
def load_lidar(self, sl=(None, None, None)):
48-
self.lidar.load_data(slice(*sl))
47+
def load_lidar(self):
48+
self.lidar.load()
49+
return self
4950

50-
def load_camera(self, sl=(None, None, None)):
51-
for c in self.camera.values():
52-
c.load_data(slice(*sl))
51+
def load_camera(self):
52+
for cam in self.camera.values():
53+
cam.load()
54+
return self
5355

54-
def load_gps_poses(self, sl=(None, None, None)):
55-
self.gps_poses.load_data(slice(*sl))
56+
def load_gps(self):
57+
self.gps.load()
58+
return self
5659

57-
def load_timestamps(self, sl=(None, None, None)):
58-
self.timestamps.load_data(slice(*sl))
60+
def load_timestamps(self):
61+
self.timestamps.load()
62+
return self
5963

60-
def load_cuboids(self, sl=(None, None, None)):
61-
self.cuboids.load_data(slice(*sl))
64+
def load_cuboids(self):
65+
self.cuboids.load()
66+
return self

python/pandaset/utils.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,3 @@
33

44
def subdirectories(directory):
55
return [d.path for d in os.scandir(directory) if d.is_dir()]
6-
7-
'''
8-
def relative_paths(full_paths, base_path):
9-
return [os.path.relpath(fp, base_path) for fp in full_paths]
10-
'''

python/setup.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55

66
setup(
77
name='pandaset',
8-
version='0.1dev',
8+
version='0.2dev',
9+
author='Nisse Knudsen, Pengchuan Xiao',
10+
author_email='nisse@scale.com, xiaopengchuan_intern@hesaitech.com',
911
packages=['pandaset'],
1012
python_requires='>=3.6',
1113
long_description='Pandaset Devkit for Python3',
1214
install_requires=requirements
13-
)
15+
)

0 commit comments

Comments
 (0)