feat(lidar): add point-aligned ground review
This commit is contained in:
+69
-11
@@ -12,6 +12,7 @@ from fastapi.routing import APIRoute
|
||||
from k1link.compute import (
|
||||
DEFAULT_GROUND_BENCHMARK_PROFILE,
|
||||
K1_LIDAR_PACK_V2_PROFILE,
|
||||
GroundBenchmarkProfile,
|
||||
GroundSegmentation,
|
||||
LidarGroundBenchmarkV1,
|
||||
LidarGroundError,
|
||||
@@ -21,6 +22,7 @@ from k1link.compute import (
|
||||
PatchworkPPGroundSegmenter,
|
||||
build_lidar_ground_annotation_template,
|
||||
build_lidar_ground_benchmark,
|
||||
lidar_ground_frame_detail,
|
||||
score_ground_labels,
|
||||
)
|
||||
from k1link.web.lidar_api import build_lidar_router
|
||||
@@ -147,9 +149,7 @@ def test_local_percentile_ground_is_point_aligned_and_non_mutating() -> None:
|
||||
xyzi = np.column_stack((xyz, np.ones(xyz.shape[0]))).astype(np.float32)
|
||||
unchanged = xyzi.copy()
|
||||
|
||||
result = LocalPercentileGroundSegmenter(
|
||||
profile=DEFAULT_GROUND_BENCHMARK_PROFILE
|
||||
).segment(xyzi)
|
||||
result = LocalPercentileGroundSegmenter(profile=DEFAULT_GROUND_BENCHMARK_PROFILE).segment(xyzi)
|
||||
|
||||
assert result.ground_mask.shape == (10,)
|
||||
assert result.assigned_mask.all()
|
||||
@@ -169,10 +169,7 @@ def test_ground_benchmark_is_immutable_diagnostic_evidence(tmp_path: Path) -> No
|
||||
assert result.report["status"] == "diagnostic-only"
|
||||
assert result.report["input_domain"]["accepted"] is False
|
||||
assert result.report["labels"]["metrics_available"] is False
|
||||
assert (
|
||||
result.report["decision"]["status"]
|
||||
== "do-not-promote-on-current-vendor-map"
|
||||
)
|
||||
assert result.report["decision"]["status"] == "do-not-promote-on-current-vendor-map"
|
||||
assert result.arrays["current_ground"].shape == (20,)
|
||||
assert result.arrays["candidate_ground"].shape == (20,)
|
||||
finally:
|
||||
@@ -195,6 +192,66 @@ def test_ground_benchmark_is_immutable_diagnostic_evidence(tmp_path: Path) -> No
|
||||
LidarGroundBenchmarkV1(output)
|
||||
|
||||
|
||||
def test_operator_height_correction_is_explicit_and_stays_diagnostic(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
replay = _Replay()
|
||||
observed_z: list[np.ndarray] = []
|
||||
|
||||
class RecordingCandidate(_Candidate):
|
||||
def segment(self, xyzi: np.ndarray) -> GroundSegmentation:
|
||||
observed_z.append(xyzi[:, 2].copy())
|
||||
return super().segment(xyzi)
|
||||
|
||||
profile = GroundBenchmarkProfile(
|
||||
profile_id="k1-handheld-operator-height-ground-ab/v1",
|
||||
patchwork_sensor_height_proxy_m=1.27,
|
||||
patchwork_map_vertical_origin_offset_m=1.27,
|
||||
patchwork_height_evidence="operator-estimated",
|
||||
)
|
||||
output = build_lidar_ground_benchmark(
|
||||
replay, # type: ignore[arg-type]
|
||||
tmp_path / "benchmarks",
|
||||
patchwork=RecordingCandidate(),
|
||||
profile=profile,
|
||||
)
|
||||
result = LidarGroundBenchmarkV1(output)
|
||||
try:
|
||||
normalization = result.report["input_domain"]["normalization"]
|
||||
assert normalization == {
|
||||
"height_evidence": "operator-estimated",
|
||||
"map_vertical_origin_offset_m": 1.27,
|
||||
"sensor_height_m": 1.27,
|
||||
}
|
||||
assert result.report["input_domain"]["physical_sensor_height_known"] is False
|
||||
frame = lidar_ground_frame_detail(
|
||||
result,
|
||||
replay, # type: ignore[arg-type]
|
||||
0,
|
||||
)
|
||||
finally:
|
||||
result.close()
|
||||
|
||||
np.testing.assert_allclose(
|
||||
observed_z[0],
|
||||
replay._points[0][:, 2] - 1.27,
|
||||
atol=1e-6,
|
||||
)
|
||||
assert frame["schema_version"] == "missioncore.lidar-ground-frame/v1"
|
||||
assert frame["point_count"] == 10
|
||||
assert frame["coordinate_frame"] == "map"
|
||||
assert frame["ground_truth"] is False
|
||||
assert frame["masks"]["disagreement"]
|
||||
assert str(tmp_path) not in repr(frame)
|
||||
|
||||
|
||||
def test_ground_profile_rejects_unattested_height_configuration() -> None:
|
||||
with pytest.raises(LidarGroundError, match="without height evidence"):
|
||||
GroundBenchmarkProfile(patchwork_sensor_height_proxy_m=1.27)
|
||||
with pytest.raises(LidarGroundError, match="positive sensor height"):
|
||||
GroundBenchmarkProfile(patchwork_height_evidence="operator-estimated")
|
||||
|
||||
|
||||
def test_annotation_template_starts_all_ignore_and_never_ground_truth(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
@@ -234,6 +291,10 @@ def test_ground_api_is_read_only_path_free_and_pack_filtered(
|
||||
router,
|
||||
"/api/v1/lidar/ground-benchmarks/{benchmark_id}",
|
||||
)
|
||||
_endpoint(
|
||||
router,
|
||||
"/api/v1/lidar/ground-benchmarks/{benchmark_id}/frames/{frame_index}",
|
||||
)
|
||||
|
||||
catalog = catalog_route( # type: ignore[operator]
|
||||
pack_id=replay.pack_id,
|
||||
@@ -241,10 +302,7 @@ def test_ground_api_is_read_only_path_free_and_pack_filtered(
|
||||
)
|
||||
detail = detail_route(benchmark_id=output.name) # type: ignore[operator]
|
||||
|
||||
assert (
|
||||
catalog["schema_version"]
|
||||
== "missioncore.lidar-ground-benchmark-catalog/v1"
|
||||
)
|
||||
assert catalog["schema_version"] == "missioncore.lidar-ground-benchmark-catalog/v1"
|
||||
assert catalog["valid_total"] == 1
|
||||
assert catalog["items"][0]["decision"]["production_promotion"] is False
|
||||
assert detail["benchmark"]["benchmark_id"] == output.name
|
||||
|
||||
Reference in New Issue
Block a user