feat: HSAP platform v2 — modular navigation, quality review, audit log, world model simulation
Major changes: - New frontend (platform/web/): Vite + React 18 + TypeScript + Tailwind - 4-module navigation: 数据送标 / 模型管理 / 车队管理 / 系统管理 - Data catalog with charts (DMS/ADAS/Lane 3-tab view) - Quality review workflow (标注质检): Good/Fine/Bad scoring with auto-advance - Audit enhancements: batch operations, rejection categories, Feishu notifications - Operation audit log (操作日志) - World model simulation studio (仿真工坊) - Dataset version management with snapshots and diff - ADAS 7-class dataset integration (138K images organized + compressed) - User management with Feishu integration and pagination - CRUD/search/filter on all pages, card layout redesign - PIL-optimized image overlay rendering - Auto-snapshot on build, in_review workflow stage - Removed embedded algorithm code (now in workspace)
This commit is contained in:
143
datasets/dms/scripts/test_export_ls_to_yolo.py
Normal file
143
datasets/dms/scripts/test_export_ls_to_yolo.py
Normal file
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3
|
||||
"""export_ls_to_yolo 单元测试(无 pytest 依赖)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
sys.path.insert(0, str(SCRIPT_DIR))
|
||||
|
||||
from export_ls_to_yolo import ( # noqa: E402
|
||||
convert_regions_to_yolo_lines,
|
||||
export_batch,
|
||||
)
|
||||
from ingest_incremental import validate_detect_label, validate_pose_label # noqa: E402
|
||||
|
||||
|
||||
def _task_id(rel: str) -> str:
|
||||
return hashlib.sha256(rel.encode()).hexdigest()[:16]
|
||||
|
||||
|
||||
def test_detect_conversion() -> None:
|
||||
regions = [
|
||||
{
|
||||
"type": "rectanglelabels",
|
||||
"value": {
|
||||
"x": 10.0,
|
||||
"y": 20.0,
|
||||
"width": 30.0,
|
||||
"height": 40.0,
|
||||
"rectanglelabels": ["face"],
|
||||
},
|
||||
}
|
||||
]
|
||||
lines = convert_regions_to_yolo_lines(
|
||||
regions,
|
||||
mode="detect",
|
||||
class_map={"face": 0, "eye_open": 1},
|
||||
)
|
||||
assert len(lines) == 1
|
||||
parts = lines[0].split()
|
||||
assert len(parts) == 5
|
||||
assert parts[0] == "0"
|
||||
assert abs(float(parts[1]) - 0.25) < 1e-5 # cx = (10+15)/100
|
||||
assert abs(float(parts[2]) - 0.40) < 1e-5 # cy = (20+20)/100
|
||||
err = validate_detect_label("\n".join(lines), 4)
|
||||
assert err is None, err
|
||||
|
||||
|
||||
def test_pose_conversion() -> None:
|
||||
regions = [
|
||||
{
|
||||
"type": "rectanglelabels",
|
||||
"value": {
|
||||
"x": 10.0,
|
||||
"y": 20.0,
|
||||
"width": 30.0,
|
||||
"height": 40.0,
|
||||
"rectanglelabels": ["face"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "keypointlabels",
|
||||
"value": {"x": 35.6, "y": 52.9, "width": 0.5, "keypointlabels": ["kp_01"]},
|
||||
},
|
||||
{
|
||||
"type": "keypointlabels",
|
||||
"value": {"x": 50.0, "y": 50.0, "width": 0.5, "keypointlabels": ["kp_10"]},
|
||||
},
|
||||
]
|
||||
kpt_map = {f"kp_{i:02d}": i for i in range(37)}
|
||||
lines = convert_regions_to_yolo_lines(
|
||||
regions,
|
||||
mode="pose",
|
||||
class_map={"face": 0},
|
||||
kpt_map=kpt_map,
|
||||
kpt_shape=[37, 3],
|
||||
)
|
||||
assert len(lines) == 1
|
||||
parts = lines[0].split()
|
||||
assert len(parts) == 116
|
||||
assert parts[0] == "0"
|
||||
# kp_01 at index 1 -> fields 5+3..5+5
|
||||
assert abs(float(parts[8]) - 0.356) < 1e-3
|
||||
assert abs(float(parts[9]) - 0.529) < 1e-3
|
||||
assert parts[10] == "2.000000"
|
||||
err = validate_pose_label("\n".join(lines), [37, 3])
|
||||
assert err is None, err
|
||||
|
||||
|
||||
def test_export_batch_end_to_end() -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
batch = Path(tmp)
|
||||
img_rel = "images/train/sample.jpg"
|
||||
img_path = batch / img_rel
|
||||
img_path.parent.mkdir(parents=True)
|
||||
img_path.write_bytes(b"\xff\xd8\xff")
|
||||
|
||||
tid = _task_id(img_rel)
|
||||
ann = {
|
||||
"task_id": tid,
|
||||
"result": [
|
||||
{
|
||||
"type": "rectanglelabels",
|
||||
"value": {
|
||||
"x": 10.0,
|
||||
"y": 20.0,
|
||||
"width": 30.0,
|
||||
"height": 40.0,
|
||||
"rectanglelabels": ["face"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "keypointlabels",
|
||||
"value": {"x": 25.0, "y": 40.0, "width": 0.5, "keypointlabels": ["kp_00"]},
|
||||
},
|
||||
],
|
||||
}
|
||||
ann_dir = batch / "labels" / "ls_annotations"
|
||||
ann_dir.mkdir(parents=True)
|
||||
(ann_dir / f"{tid}.json").write_text(json.dumps(ann), encoding="utf-8")
|
||||
|
||||
result = export_batch(batch, "addw_face", mode="pose")
|
||||
assert result["written"] == 1
|
||||
out = batch / "labels" / "train" / "sample.txt"
|
||||
assert out.is_file()
|
||||
parts = out.read_text().strip().split()
|
||||
assert len(parts) == 116
|
||||
|
||||
|
||||
def main() -> int:
|
||||
test_detect_conversion()
|
||||
test_pose_conversion()
|
||||
test_export_batch_end_to_end()
|
||||
print("OK export_ls_to_yolo tests")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user