x4d-devkit 0.3.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {x4d_devkit-0.3.0/x4d_devkit.egg-info → x4d_devkit-0.4.0}/PKG-INFO +1 -1
  2. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/pyproject.toml +1 -1
  3. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/tests/test_coordinate_frames.py +6 -2
  4. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/tests/test_models.py +8 -4
  5. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/tests/test_nuscenes_converter.py +8 -7
  6. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/tests/test_validation.py +3 -3
  7. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/converters/nuscenes.py +21 -14
  8. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/core/loader.py +4 -2
  9. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/core/models.py +7 -3
  10. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0/x4d_devkit.egg-info}/PKG-INFO +1 -1
  11. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/LICENSE +0 -0
  12. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/README.md +0 -0
  13. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/setup.cfg +0 -0
  14. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/tests/test_detection_eval.py +0 -0
  15. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/tests/test_fusion.py +0 -0
  16. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/tests/test_loader.py +0 -0
  17. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/tests/test_matching.py +0 -0
  18. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/tests/test_metrics.py +0 -0
  19. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/tests/test_token.py +0 -0
  20. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/tests/test_transform.py +0 -0
  21. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/tests/test_transform_chain.py +0 -0
  22. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/__init__.py +0 -0
  23. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/cli.py +0 -0
  24. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/client/__init__.py +0 -0
  25. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/client/checkpoints.py +0 -0
  26. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/client/client.py +0 -0
  27. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/client/clips.py +0 -0
  28. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/client/projects.py +0 -0
  29. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/client/test_sets.py +0 -0
  30. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/converters/__init__.py +0 -0
  31. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/core/__init__.py +0 -0
  32. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/core/token.py +0 -0
  33. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/core/transform.py +0 -0
  34. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/eval/__init__.py +0 -0
  35. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/eval/detection.py +0 -0
  36. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/eval/matching.py +0 -0
  37. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/eval/metrics.py +0 -0
  38. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/fusion.py +0 -0
  39. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/validation/__init__.py +0 -0
  40. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/validation/report.py +0 -0
  41. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit/validation/validator.py +0 -0
  42. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit.egg-info/SOURCES.txt +0 -0
  43. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit.egg-info/dependency_links.txt +0 -0
  44. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit.egg-info/entry_points.txt +0 -0
  45. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit.egg-info/requires.txt +0 -0
  46. {x4d_devkit-0.3.0 → x4d_devkit-0.4.0}/x4d_devkit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: x4d-devkit
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: X-4D dataset format SDK — load, validate, evaluate, and convert autonomous driving datasets
5
5
  Author: windzu
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "x4d-devkit"
7
- version = "0.3.0"
7
+ version = "0.4.0"
8
8
  description = "X-4D dataset format SDK — load, validate, evaluate, and convert autonomous driving datasets"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -56,14 +56,18 @@ def _make_synthetic_clip(tmp_path: Path) -> Path:
56
56
  "channel": "LIDAR_TOP",
57
57
  "translation": {"x": 0.0, "y": 0.0, "z": 1.0},
58
58
  "rotation": {"qx": 0.0, "qy": 0.0, "qz": 0.0, "qw": 1.0},
59
- "camera_intrinsic": None,
59
+ "intrinsics": None,
60
+ "distortion": None,
60
61
  },
61
62
  {
62
63
  "calibrated_sensor_token": "cs-cam",
63
64
  "channel": "CAM_FRONT",
64
65
  "translation": {"x": 0.5, "y": 0.0, "z": 0.8},
65
66
  "rotation": {"qx": 0.0, "qy": 0.0, "qz": 0.0, "qw": 1.0},
66
- "camera_intrinsic": {"fx": 1000, "fy": 1000, "cx": 320, "cy": 240},
67
+ "intrinsics": {"camera_model": "pinhole",
68
+ "fx": 1000, "fy": 1000, "cx": 320, "cy": 240,
69
+ "image_width": 640, "image_height": 480},
70
+ "distortion": None,
67
71
  },
68
72
  ]))
69
73
 
@@ -82,13 +82,17 @@ class TestSampleData:
82
82
  class TestCalibratedSensor:
83
83
  def test_construction(self):
84
84
  cs = CalibratedSensor(
85
- token="cs1", channel="CAM_FRONT", modality="camera",
85
+ token="cs1", channel="cam_front", modality="camera",
86
86
  translation=np.zeros(3), rotation=np.array([0, 0, 0, 1.0]),
87
- camera_intrinsic={"fx": 1266.4, "fy": 1266.4, "cx": 816.3, "cy": 491.5,
88
- "k1": 0.0, "k2": 0.0, "k3": 0.0, "p1": 0.0, "p2": 0.0},
87
+ intrinsics={"camera_model": "pinhole",
88
+ "fx": 1266.4, "fy": 1266.4, "cx": 816.3, "cy": 491.5,
89
+ "image_width": 1600, "image_height": 900},
90
+ distortion={"model": "plumb_bob",
91
+ "k1": 0.0, "k2": 0.0, "k3": 0.0, "p1": 0.0, "p2": 0.0},
89
92
  )
90
93
  assert cs.modality == "camera"
91
- assert cs.camera_intrinsic["fx"] == 1266.4
94
+ assert cs.intrinsics["fx"] == 1266.4
95
+ assert cs.distortion["model"] == "plumb_bob"
92
96
 
93
97
 
94
98
  class TestAnnotation:
@@ -108,11 +108,10 @@ class TestIntrinsicConversion:
108
108
  assert result["fy"] == pytest.approx(1266.4)
109
109
  assert result["cx"] == pytest.approx(816.3)
110
110
  assert result["cy"] == pytest.approx(491.5)
111
- assert result["k1"] == 0.0
112
- assert result["k2"] == 0.0
113
- assert result["k3"] == 0.0
114
- assert result["p1"] == 0.0
115
- assert result["p2"] == 0.0
111
+ assert result["camera_model"] == "pinhole"
112
+ # Image dimensions default to nuScenes standard 1600x900 when not given.
113
+ assert result["image_width"] == 1600
114
+ assert result["image_height"] == 900
116
115
 
117
116
  def test_empty_intrinsic(self):
118
117
  """nuScenes uses empty list for non-camera sensors."""
@@ -185,8 +184,10 @@ class TestNuScenesConverterExtraction:
185
184
  # Check named fields
186
185
  assert "x" in cam_front["translation"]
187
186
  assert "qx" in cam_front["rotation"]
188
- assert cam_front["camera_intrinsic"] is not None
189
- assert "fx" in cam_front["camera_intrinsic"]
187
+ assert cam_front["intrinsics"] is not None
188
+ assert "fx" in cam_front["intrinsics"]
189
+ assert cam_front["intrinsics"]["camera_model"] == "pinhole"
190
+ assert "child_frame" not in cam_front # dropped in v0.4
190
191
 
191
192
  def test_ego_poses_local_coordinates(self, converter):
192
193
  scene = converter.nusc.scene[0]
@@ -55,12 +55,12 @@ def valid_clip(tmp_path):
55
55
  [
56
56
  {
57
57
  "calibrated_sensor_token": "cs_lidar",
58
- "channel": "LIDAR_TOP",
58
+ "channel": "lidar_top",
59
59
  "parent_frame": "base_link",
60
- "child_frame": "lidar_top",
61
60
  "translation": {"x": 0, "y": 0, "z": 1.8},
62
61
  "rotation": {"qx": 0, "qy": 0, "qz": 0, "qw": 1},
63
- "camera_intrinsic": None,
62
+ "intrinsics": None,
63
+ "distortion": None,
64
64
  }
65
65
  ]
66
66
  )
@@ -32,20 +32,26 @@ def size_wlh_to_named(size: list[float]) -> dict[str, float]:
32
32
  return {"length": size[1], "width": size[0], "height": size[2]}
33
33
 
34
34
 
35
- def intrinsic_matrix_to_named(matrix: list[list[float]]) -> dict[str, float] | None:
36
- """Convert 3x3 intrinsic matrix to X4D named fields. Returns None for empty."""
35
+ def intrinsic_matrix_to_named(
36
+ matrix: list[list[float]],
37
+ image_width: int | None = None,
38
+ image_height: int | None = None,
39
+ ) -> dict[str, float] | None:
40
+ """Convert 3x3 intrinsic matrix to X4D v0.4 intrinsics dict. Returns None for empty.
41
+
42
+ nuScenes does not record image dimensions per-sensor; they default to the
43
+ standard 1600x900 used by the dataset when not provided.
44
+ """
37
45
  if not matrix:
38
46
  return None
39
47
  return {
48
+ "camera_model": "pinhole",
40
49
  "fx": matrix[0][0],
41
50
  "fy": matrix[1][1],
42
51
  "cx": matrix[0][2],
43
52
  "cy": matrix[1][2],
44
- "k1": 0.0,
45
- "k2": 0.0,
46
- "k3": 0.0,
47
- "p1": 0.0,
48
- "p2": 0.0,
53
+ "image_width": int(image_width) if image_width is not None else 1600,
54
+ "image_height": int(image_height) if image_height is not None else 900,
49
55
  }
50
56
 
51
57
 
@@ -238,21 +244,22 @@ class NuScenesConverter:
238
244
  sensor = self._sensor_by_token[cs["sensor_token"]]
239
245
 
240
246
  parent_frame = "base_link"
241
- child_frame = channel.lower()
247
+
248
+ intrinsics = (
249
+ intrinsic_matrix_to_named(cs["camera_intrinsic"])
250
+ if sensor["modality"] == "camera"
251
+ else None
252
+ )
242
253
 
243
254
  records.append(
244
255
  {
245
256
  "calibrated_sensor_token": generate_token(clip_id, f"cs:{channel}"),
246
257
  "channel": channel,
247
258
  "parent_frame": parent_frame,
248
- "child_frame": child_frame,
249
259
  "translation": translation_to_named(cs["translation"]),
250
260
  "rotation": quat_wxyz_to_named(cs["rotation"]),
251
- "camera_intrinsic": intrinsic_matrix_to_named(
252
- cs["camera_intrinsic"]
253
- )
254
- if sensor["modality"] == "camera"
255
- else None,
261
+ "intrinsics": intrinsics,
262
+ "distortion": None,
256
263
  }
257
264
  )
258
265
  return records
@@ -115,13 +115,15 @@ class ClipLoader:
115
115
  for r in records:
116
116
  t = r["translation"]
117
117
  q = r["rotation"]
118
+ intr = r.get("intrinsics")
118
119
  result.append(CalibratedSensor(
119
120
  token=r["calibrated_sensor_token"],
120
121
  channel=r["channel"],
121
- modality="lidar" if r["camera_intrinsic"] is None else "camera",
122
+ modality="camera" if intr is not None else "lidar",
122
123
  translation=[t["x"], t["y"], t["z"]],
123
124
  rotation=[q["qx"], q["qy"], q["qz"], q["qw"]],
124
- camera_intrinsic=r["camera_intrinsic"],
125
+ intrinsics=intr,
126
+ distortion=r.get("distortion"),
125
127
  ))
126
128
  return result
127
129
 
@@ -53,11 +53,14 @@ class CalibratedSensor:
53
53
 
54
54
  Attributes:
55
55
  token: Unique token for this calibrated sensor record.
56
- channel: Sensor channel name (e.g. "LIDAR_TOP", "CAM_FRONT").
56
+ channel: Sensor channel name equals the ROS frame_id of the sensor
57
+ (e.g. "lidar_top", "cam_front_left").
57
58
  modality: "lidar" or "camera".
58
59
  translation: (3,) float64 array — sensor position in ego frame [x, y, z] meters.
59
60
  rotation: (4,) float64 array — sensor orientation as quaternion [qx, qy, qz, qw].
60
- camera_intrinsic: Camera intrinsic parameters (fx, fy, cx, cy), or None for LiDAR.
61
+ intrinsics: Full camera intrinsics dict (camera_model, fx, fy, cx, cy,
62
+ image_width, image_height) or None for LiDAR.
63
+ distortion: Distortion model dict (model + coefficients) or None.
61
64
  """
62
65
 
63
66
  token: str
@@ -65,7 +68,8 @@ class CalibratedSensor:
65
68
  modality: str
66
69
  translation: np.ndarray
67
70
  rotation: np.ndarray
68
- camera_intrinsic: dict[str, float] | None
71
+ intrinsics: dict | None
72
+ distortion: dict | None
69
73
 
70
74
  def __post_init__(self) -> None:
71
75
  object.__setattr__(self, "translation", np.asarray(self.translation, dtype=np.float64))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: x4d-devkit
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: X-4D dataset format SDK — load, validate, evaluate, and convert autonomous driving datasets
5
5
  Author: windzu
6
6
  License-Expression: Apache-2.0
File without changes
File without changes
File without changes
File without changes