x4d-devkit 0.7.0__tar.gz → 0.9.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.
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/PKG-INFO +1 -1
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/pyproject.toml +1 -1
- x4d_devkit-0.9.0/tests/test_box.py +121 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/tests/test_coordinate_frames.py +1 -1
- x4d_devkit-0.9.0/tests/test_evaluate.py +154 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/tests/test_matching.py +11 -10
- x4d_devkit-0.9.0/tests/test_v06_schema.py +414 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/__init__.py +6 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/core/loader.py +101 -19
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/core/models.py +28 -11
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/core/transform.py +35 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/eval/__init__.py +5 -0
- x4d_devkit-0.9.0/x4d_devkit/eval/api.py +205 -0
- x4d_devkit-0.9.0/x4d_devkit/eval/box.py +124 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/eval/detection.py +8 -114
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/eval/matching.py +28 -33
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/validation/validator.py +51 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit.egg-info/PKG-INFO +1 -1
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit.egg-info/SOURCES.txt +5 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/LICENSE +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/README.md +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/setup.cfg +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/tests/test_detection_eval.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/tests/test_fusion.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/tests/test_loader.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/tests/test_metrics.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/tests/test_models.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/tests/test_nuscenes_converter.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/tests/test_token.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/tests/test_transform.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/tests/test_transform_chain.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/tests/test_v06_api_additions.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/tests/test_validation.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/cli.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/client/__init__.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/client/checkpoints.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/client/client.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/client/clips.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/client/projects.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/client/test_sets.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/converters/__init__.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/converters/nuscenes.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/core/__init__.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/core/token.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/eval/metrics.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/fusion.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/validation/__init__.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit/validation/report.py +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit.egg-info/dependency_links.txt +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit.egg-info/entry_points.txt +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit.egg-info/requires.txt +0 -0
- {x4d_devkit-0.7.0 → x4d_devkit-0.9.0}/x4d_devkit.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "x4d-devkit"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.9.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"
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Unit tests for the Box detection dataclass."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from x4d_devkit.eval import Box
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestBoxConstruction:
|
|
10
|
+
def test_minimal_gt(self):
|
|
11
|
+
b = Box(
|
|
12
|
+
translation=[1.0, 2.0, 3.0],
|
|
13
|
+
size=[4.0, 2.0, 1.5],
|
|
14
|
+
rotation=[0.0, 0.0, 0.0, 1.0],
|
|
15
|
+
category="car",
|
|
16
|
+
)
|
|
17
|
+
assert b.translation.dtype == np.float64
|
|
18
|
+
assert b.translation.shape == (3,)
|
|
19
|
+
assert b.size.shape == (3,)
|
|
20
|
+
assert b.rotation.shape == (4,)
|
|
21
|
+
assert b.category == "car"
|
|
22
|
+
assert b.score is None
|
|
23
|
+
assert b.velocity is None
|
|
24
|
+
assert b.attributes == []
|
|
25
|
+
|
|
26
|
+
def test_prediction_with_score_and_velocity(self):
|
|
27
|
+
b = Box(
|
|
28
|
+
translation=np.array([10.0, 20.0, 1.0]),
|
|
29
|
+
size=np.array([4.5, 1.8, 1.5]),
|
|
30
|
+
rotation=np.array([0.0, 0.0, 0.0, 1.0]),
|
|
31
|
+
category="car",
|
|
32
|
+
score=0.85,
|
|
33
|
+
velocity=[1.0, 0.5, 0.0],
|
|
34
|
+
attributes=["vehicle.moving"],
|
|
35
|
+
)
|
|
36
|
+
assert b.score == 0.85
|
|
37
|
+
assert b.velocity.dtype == np.float64
|
|
38
|
+
assert b.velocity.tolist() == [1.0, 0.5, 0.0]
|
|
39
|
+
assert b.attributes == ["vehicle.moving"]
|
|
40
|
+
|
|
41
|
+
def test_frozen(self):
|
|
42
|
+
b = Box(
|
|
43
|
+
translation=[0, 0, 0], size=[1, 1, 1],
|
|
44
|
+
rotation=[0, 0, 0, 1], category="car",
|
|
45
|
+
)
|
|
46
|
+
with pytest.raises((AttributeError, Exception)):
|
|
47
|
+
b.category = "truck"
|
|
48
|
+
|
|
49
|
+
def test_rejects_wrong_translation_shape(self):
|
|
50
|
+
with pytest.raises(ValueError, match="translation"):
|
|
51
|
+
Box(translation=[1, 2], size=[1, 1, 1],
|
|
52
|
+
rotation=[0, 0, 0, 1], category="car")
|
|
53
|
+
|
|
54
|
+
def test_rejects_wrong_rotation_shape(self):
|
|
55
|
+
with pytest.raises(ValueError, match="rotation"):
|
|
56
|
+
Box(translation=[1, 2, 3], size=[1, 1, 1],
|
|
57
|
+
rotation=[0, 0, 0], category="car")
|
|
58
|
+
|
|
59
|
+
def test_rejects_wrong_size_shape(self):
|
|
60
|
+
with pytest.raises(ValueError, match="size"):
|
|
61
|
+
Box(translation=[1, 2, 3], size=[1, 1],
|
|
62
|
+
rotation=[0, 0, 0, 1], category="car")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class TestFromXyzlwhyawVxvy:
|
|
66
|
+
def test_yaw_zero_gives_identity_quat(self):
|
|
67
|
+
b = Box.from_xyzlwhyaw_vxvy(
|
|
68
|
+
[0, 0, 0, 4, 2, 1.5, 0.0, 0, 0], category="car", score=0.9,
|
|
69
|
+
)
|
|
70
|
+
assert b.rotation[0] == 0.0
|
|
71
|
+
assert b.rotation[1] == 0.0
|
|
72
|
+
assert b.rotation[2] == pytest.approx(0.0)
|
|
73
|
+
assert b.rotation[3] == pytest.approx(1.0)
|
|
74
|
+
|
|
75
|
+
def test_yaw_pi_half_gives_z_quat(self):
|
|
76
|
+
b = Box.from_xyzlwhyaw_vxvy(
|
|
77
|
+
[0, 0, 0, 4, 2, 1.5, np.pi / 2, 0, 0], category="car",
|
|
78
|
+
)
|
|
79
|
+
assert b.rotation[2] == pytest.approx(np.sin(np.pi / 4))
|
|
80
|
+
assert b.rotation[3] == pytest.approx(np.cos(np.pi / 4))
|
|
81
|
+
|
|
82
|
+
def test_yaw_round_trip_via_quaternion_yaw(self):
|
|
83
|
+
from x4d_devkit.eval.metrics import quaternion_yaw
|
|
84
|
+
|
|
85
|
+
for yaw in [-2.5, -1.0, 0.0, 0.7, np.pi - 0.01]:
|
|
86
|
+
b = Box.from_xyzlwhyaw_vxvy(
|
|
87
|
+
[1, 2, 3, 4, 2, 1.5, yaw, 0, 0], category="car",
|
|
88
|
+
)
|
|
89
|
+
recovered = quaternion_yaw(b.rotation)
|
|
90
|
+
assert recovered == pytest.approx(yaw, abs=1e-6)
|
|
91
|
+
|
|
92
|
+
def test_velocity_lifts_to_3d(self):
|
|
93
|
+
b = Box.from_xyzlwhyaw_vxvy(
|
|
94
|
+
[0, 0, 0, 4, 2, 1.5, 0, 1.5, -0.5], category="car",
|
|
95
|
+
)
|
|
96
|
+
assert b.velocity.shape == (3,)
|
|
97
|
+
assert b.velocity.tolist() == [1.5, -0.5, 0.0]
|
|
98
|
+
|
|
99
|
+
def test_translation_and_size_preserved(self):
|
|
100
|
+
b = Box.from_xyzlwhyaw_vxvy(
|
|
101
|
+
[10, 20, 1, 4.5, 1.8, 1.5, 0.0, 0, 0], category="car",
|
|
102
|
+
)
|
|
103
|
+
assert b.translation.tolist() == [10.0, 20.0, 1.0]
|
|
104
|
+
assert b.size.tolist() == [4.5, 1.8, 1.5]
|
|
105
|
+
|
|
106
|
+
def test_rejects_wrong_shape(self):
|
|
107
|
+
with pytest.raises(ValueError, match="bbox must be shape"):
|
|
108
|
+
Box.from_xyzlwhyaw_vxvy([1, 2, 3], category="car")
|
|
109
|
+
|
|
110
|
+
def test_attributes_default_empty(self):
|
|
111
|
+
b = Box.from_xyzlwhyaw_vxvy(
|
|
112
|
+
[0, 0, 0, 4, 2, 1.5, 0, 0, 0], category="car",
|
|
113
|
+
)
|
|
114
|
+
assert b.attributes == []
|
|
115
|
+
|
|
116
|
+
def test_attributes_passthrough(self):
|
|
117
|
+
b = Box.from_xyzlwhyaw_vxvy(
|
|
118
|
+
[0, 0, 0, 4, 2, 1.5, 0, 0, 0], category="car",
|
|
119
|
+
attributes=["vehicle.moving"],
|
|
120
|
+
)
|
|
121
|
+
assert b.attributes == ["vehicle.moving"]
|
|
@@ -331,7 +331,7 @@ class TestAnnotationsForSampleFrames:
|
|
|
331
331
|
assert not np.allclose(anns_world[0].translation, anns_ego[0].translation, atol=0.1)
|
|
332
332
|
|
|
333
333
|
def test_sensor_frame_raises(self, loader):
|
|
334
|
-
with pytest.raises(ValueError, match="
|
|
334
|
+
with pytest.raises(ValueError, match="ambiguous"):
|
|
335
335
|
loader.annotations_for_sample("s-0", frame="sensor")
|
|
336
336
|
|
|
337
337
|
def test_invalid_frame_raises(self, loader):
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""Unit tests for the in-memory evaluate() pure function."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from x4d_devkit.eval import (
|
|
7
|
+
Box,
|
|
8
|
+
DetectionConfig,
|
|
9
|
+
DetectionResult,
|
|
10
|
+
evaluate,
|
|
11
|
+
nusc_detection_config,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _gt_box(x, y, z, category="car"):
|
|
16
|
+
return Box(
|
|
17
|
+
translation=[x, y, z], size=[4.0, 2.0, 1.5],
|
|
18
|
+
rotation=[0.0, 0.0, 0.0, 1.0], category=category,
|
|
19
|
+
velocity=[0.0, 0.0, 0.0], attributes=[],
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _pred_box(x, y, z, score, category="car"):
|
|
24
|
+
return Box(
|
|
25
|
+
translation=[x, y, z], size=[4.0, 2.0, 1.5],
|
|
26
|
+
rotation=[0.0, 0.0, 0.0, 1.0], category=category,
|
|
27
|
+
score=score, velocity=[0.0, 0.0, 0.0], attributes=[],
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _tiny_config(class_names=("car",)) -> DetectionConfig:
|
|
32
|
+
"""Single-class config with NUSC-style thresholds, no traffic_cone/barrier
|
|
33
|
+
special cases hitting our class."""
|
|
34
|
+
cn = list(class_names)
|
|
35
|
+
return DetectionConfig(
|
|
36
|
+
class_names=cn,
|
|
37
|
+
dist_thresholds=[0.5, 1.0, 2.0, 4.0],
|
|
38
|
+
dist_th_tp=2.0,
|
|
39
|
+
min_recall=0.1,
|
|
40
|
+
min_precision=0.1,
|
|
41
|
+
max_boxes_per_sample=500,
|
|
42
|
+
class_range={c: 50.0 for c in cn},
|
|
43
|
+
category_map={},
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class TestEvaluatePerfect:
|
|
48
|
+
def test_perfect_single_class_single_sample(self):
|
|
49
|
+
cfg = _tiny_config()
|
|
50
|
+
gt = {"s1": [_gt_box(10, 20, 1)]}
|
|
51
|
+
pred = {"s1": [_pred_box(10, 20, 1, score=0.9)]}
|
|
52
|
+
result = evaluate(gt, pred, cfg)
|
|
53
|
+
assert isinstance(result, DetectionResult)
|
|
54
|
+
assert result.mean_ap == pytest.approx(1.0)
|
|
55
|
+
assert result.mean_dist_aps["car"] == pytest.approx(1.0)
|
|
56
|
+
assert result.label_tp_errors["car"]["trans_err"] < 1e-6
|
|
57
|
+
assert result.label_tp_errors["car"]["scale_err"] < 1e-6
|
|
58
|
+
assert result.nd_score > 0.9
|
|
59
|
+
|
|
60
|
+
def test_perfect_multi_sample(self):
|
|
61
|
+
cfg = _tiny_config()
|
|
62
|
+
gt = {f"s{i}": [_gt_box(10 + i, 0, 0)] for i in range(5)}
|
|
63
|
+
pred = {f"s{i}": [_pred_box(10 + i, 0, 0, score=0.9)] for i in range(5)}
|
|
64
|
+
result = evaluate(gt, pred, cfg)
|
|
65
|
+
assert result.mean_ap == pytest.approx(1.0)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class TestEvaluateNoisy:
|
|
69
|
+
def test_translation_noise_increases_trans_err(self):
|
|
70
|
+
cfg = _tiny_config()
|
|
71
|
+
rng = np.random.default_rng(7)
|
|
72
|
+
gt = {f"s{i}": [_gt_box(10.0 * i, 0, 0)] for i in range(20)}
|
|
73
|
+
pred = {
|
|
74
|
+
f"s{i}": [_pred_box(10.0 * i + rng.normal(0, 0.5), 0, 0, score=0.9)]
|
|
75
|
+
for i in range(20)
|
|
76
|
+
}
|
|
77
|
+
result = evaluate(gt, pred, cfg)
|
|
78
|
+
assert result.label_tp_errors["car"]["trans_err"] > 0.1
|
|
79
|
+
assert result.label_tp_errors["car"]["trans_err"] < 2.0
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class TestEvaluateEmpty:
|
|
83
|
+
def test_empty_predictions_zero_ap(self):
|
|
84
|
+
cfg = _tiny_config()
|
|
85
|
+
gt = {"s1": [_gt_box(10, 20, 1)]}
|
|
86
|
+
pred = {"s1": []}
|
|
87
|
+
result = evaluate(gt, pred, cfg)
|
|
88
|
+
assert result.mean_ap == pytest.approx(0.0)
|
|
89
|
+
|
|
90
|
+
def test_no_gt_for_class_zero_ap(self):
|
|
91
|
+
cfg = _tiny_config()
|
|
92
|
+
gt = {"s1": []}
|
|
93
|
+
pred = {"s1": [_pred_box(10, 20, 1, score=0.9)]}
|
|
94
|
+
result = evaluate(gt, pred, cfg)
|
|
95
|
+
assert result.mean_ap == pytest.approx(0.0)
|
|
96
|
+
|
|
97
|
+
def test_pred_sample_missing_from_gt_treated_as_empty_gt(self):
|
|
98
|
+
cfg = _tiny_config()
|
|
99
|
+
gt = {"s1": [_gt_box(10, 20, 1)]}
|
|
100
|
+
pred = {"s2": [_pred_box(10, 20, 1, score=0.9)]}
|
|
101
|
+
result = evaluate(gt, pred, cfg)
|
|
102
|
+
assert result.mean_ap == pytest.approx(0.0)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class TestEvaluateClassRangeFilter:
|
|
106
|
+
def test_filters_far_boxes(self):
|
|
107
|
+
cfg = _tiny_config()
|
|
108
|
+
cfg = DetectionConfig(
|
|
109
|
+
class_names=["car"],
|
|
110
|
+
dist_thresholds=cfg.dist_thresholds,
|
|
111
|
+
dist_th_tp=cfg.dist_th_tp,
|
|
112
|
+
min_recall=cfg.min_recall,
|
|
113
|
+
min_precision=cfg.min_precision,
|
|
114
|
+
max_boxes_per_sample=cfg.max_boxes_per_sample,
|
|
115
|
+
class_range={"car": 10.0},
|
|
116
|
+
category_map={},
|
|
117
|
+
)
|
|
118
|
+
gt = {"s1": [_gt_box(100, 0, 0), _gt_box(5, 0, 0)]}
|
|
119
|
+
pred = {"s1": [_pred_box(5, 0, 0, score=0.9)]}
|
|
120
|
+
result = evaluate(gt, pred, cfg)
|
|
121
|
+
# The far GT box is filtered out, near GT matches → AP = 1.0.
|
|
122
|
+
assert result.mean_ap == pytest.approx(1.0)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class TestEvaluateMaxBoxesPerSample:
|
|
126
|
+
def test_low_score_predictions_dropped_when_capped(self):
|
|
127
|
+
cfg = DetectionConfig(
|
|
128
|
+
class_names=["car"],
|
|
129
|
+
dist_thresholds=[0.5, 1.0, 2.0, 4.0],
|
|
130
|
+
dist_th_tp=2.0,
|
|
131
|
+
min_recall=0.1, min_precision=0.1,
|
|
132
|
+
max_boxes_per_sample=1,
|
|
133
|
+
class_range={"car": 50.0},
|
|
134
|
+
category_map={},
|
|
135
|
+
)
|
|
136
|
+
gt = {"s1": [_gt_box(10, 0, 0)]}
|
|
137
|
+
pred = {"s1": [
|
|
138
|
+
_pred_box(40, 0, 0, score=0.95), # high-score FP, kept by cap
|
|
139
|
+
_pred_box(10, 0, 0, score=0.10), # low-score TP, dropped by cap
|
|
140
|
+
]}
|
|
141
|
+
result = evaluate(gt, pred, cfg)
|
|
142
|
+
# The TP was dropped, only FP remains → mAP near 0.
|
|
143
|
+
assert result.mean_ap < 0.1
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class TestEvaluateMatchesDetectionEval:
|
|
147
|
+
"""evaluate() is what DetectionEval.evaluate() delegates to — sanity-check
|
|
148
|
+
they produce identical numbers when fed equivalent inputs."""
|
|
149
|
+
|
|
150
|
+
def test_no_gt_no_pred_zero(self):
|
|
151
|
+
cfg = _tiny_config()
|
|
152
|
+
result = evaluate({}, {}, cfg)
|
|
153
|
+
assert result.mean_ap == 0.0
|
|
154
|
+
assert result.label_aps["car"]["0.5"] == 0.0
|
|
@@ -4,21 +4,22 @@
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
import pytest
|
|
6
6
|
|
|
7
|
+
from x4d_devkit.eval import Box
|
|
7
8
|
from x4d_devkit.eval.matching import MetricData, accumulate
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
def _make_box(translation, size, rotation, category, score=None,
|
|
11
12
|
velocity=None, attributes=None):
|
|
12
|
-
"""Helper to
|
|
13
|
-
return
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
"""Helper to construct a Box matching what accumulate() expects."""
|
|
14
|
+
return Box(
|
|
15
|
+
translation=np.asarray(translation, dtype=float),
|
|
16
|
+
size=np.asarray(size, dtype=float),
|
|
17
|
+
rotation=np.asarray(rotation, dtype=float),
|
|
18
|
+
category=category,
|
|
19
|
+
score=score,
|
|
20
|
+
velocity=np.asarray(velocity, dtype=float) if velocity is not None else None,
|
|
21
|
+
attributes=attributes or [],
|
|
22
|
+
)
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class TestMetricData:
|