Files
HSAP/platform/as_platform/labeling/cvat_config.py
Chengfang Lu 672ef61e17 feat: CVAT 标注引擎、我的标注收件箱与 ADAS Cuboid 送标
- 统一标注引擎为 CVAT:客户端/配置/格式转换、iframe 标注页、docker-compose.cvat.yml 与 no_auth 补丁
- 移除 Label Studio 相关配置与构建脚本,清理 embedded.bak 备份与误提交的 node_modules
- 新增「我的标注」:跨 Campaign 收件箱、逐张清单、CVAT frame 跳转
- 飞书任务分配:通讯录同步选人、按量分配、分配后 DM 通知(含 my-tasks 链接)
- ADAS cuboid_7cls 数据湖接入:workflow 路径、register-batch、开标上传与标注同步
- 数据湖挂载 AS_DATA_LAKE_ROOT、datasets/adas 符号链接、reset_labeling 运维脚本
- 补充 docs/HANDOVER.md 项目交接文档

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 17:25:28 +08:00

149 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""CVAT 标注配置:为 DMS / ADAS / Lane 生成 label schema唯一标注引擎"""
from __future__ import annotations
from typing import Any
from as_platform.config import WORKSPACE
from as_platform.labeling.scope import labeling_profile_key, load_dms_registry, load_labeling_registry
# Lane 车道线 — 折线
LANE_LABELS: list[dict[str, Any]] = [
{
"name": "lane_line",
"type": "polyline",
"attributes": [
{
"name": "type",
"mutable": False,
"input_type": "select",
"values": ["solid", "dashed", "double_solid", "double_dashed", "solid_dashed"],
"default_value": "solid",
},
{
"name": "color",
"mutable": False,
"input_type": "select",
"values": ["white", "yellow", "blue", "other"],
"default_value": "white",
},
],
},
{
"name": "curb",
"type": "polyline",
"attributes": [
{
"name": "type",
"mutable": False,
"input_type": "select",
"values": ["high", "low", "none"],
"default_value": "low",
},
],
},
{"name": "stop_line", "type": "polyline"},
]
# ADAS cuboid_7cls — 单目图像 cuboid
ADAS_CUBOID_7CLS_LABELS: list[dict[str, Any]] = [
{"name": "car", "type": "cuboid"},
{"name": "pedestrian", "type": "cuboid"},
{"name": "truck", "type": "cuboid"},
{"name": "bus", "type": "cuboid"},
{"name": "motorcycle", "type": "cuboid"},
{"name": "tricycle", "type": "cuboid"},
{"name": "traffic cone", "type": "cuboid"},
]
def _rect_label(name: str, **attrs: Any) -> dict[str, Any]:
lb: dict[str, Any] = {"name": name, "type": "rectangle"}
if attrs:
lb["attributes"] = attrs
return lb
def _dms_registry_task_config(task: str, mode: str | None) -> dict[str, Any]:
import sys
scripts = WORKSPACE / "datasets" / "dms" / "scripts"
if str(scripts) not in sys.path:
sys.path.insert(0, str(scripts))
from task_registry import get_mode_config, resolve_task_id
reg = load_dms_registry()
task_r, mode_r = resolve_task_id(task, mode)
return get_mode_config(task_r, mode_r, reg)
def _labels_from_class_names(names: list[str] | dict[int | str, str]) -> list[dict[str, Any]]:
if isinstance(names, dict):
ordered = [names[k] for k in sorted(names, key=lambda x: int(x))]
else:
ordered = list(names)
return [_rect_label(str(n)) for n in ordered]
def _dms_pose_labels() -> list[dict[str, Any]]:
labels: list[dict[str, Any]] = [_rect_label("face")]
labels.extend({"name": f"kp_{i:02d}", "type": "points"} for i in range(37))
return labels
def _dms_labels(task: str, mode: str | None) -> list[dict[str, Any]]:
tcfg = _dms_registry_task_config(task, mode)
ttype = tcfg.get("type") or "detect"
if ttype == "pose":
return _dms_pose_labels()
names = tcfg.get("names")
if names:
return _labels_from_class_names(names)
return [_rect_label("object")]
def _labels_from_registry_profile(project: str, task: str, mode: str | None) -> list[dict[str, Any]] | None:
reg = load_dms_registry() if project == "dms" else None
pk = labeling_profile_key(project, task, mode, reg)
prof = (load_labeling_registry().get("profiles") or {}).get(pk) or {}
cvat_names = prof.get("cvat_labels")
if cvat_names:
return [{"name": str(n), "type": "cuboid"} for n in cvat_names]
return None
def build_cvat_labels(
project: str,
task: str | None = None,
mode: str | None = None,
annotation_types: list[str] | None = None,
) -> list[dict[str, Any]]:
"""根据 HSAP project/task/mode 生成 CVAT Task 的 labels 定义。"""
task = task or ""
prof_labels = _labels_from_registry_profile(project, task, mode)
if prof_labels is not None:
return prof_labels
if project == "adas":
if task == "cuboid_7cls":
return ADAS_CUBOID_7CLS_LABELS
return ADAS_CUBOID_7CLS_LABELS
if project == "lane":
return LANE_LABELS
if project == "dms":
return _dms_labels(task, mode)
return [_rect_label("object")]
def resolve_annotation_types(project: str, task: str | None = None, mode: str | None = None) -> list[str]:
mapping = {
"dms": ["bbox", "keypoint"],
"adas": ["cuboid"],
"lane": ["polyline"],
}
if project == "adas" and task == "cuboid_7cls":
return ["cuboid"]
return mapping.get(project, ["bbox"])