修正GT未知类别导入为待分类
- GT Mask 未知 maskid 选择保留时落到黑色 maskid:0 的待分类类别,而不是绿色未定义类别。 - 前端导入预览中未知 maskid 使用黑色待分类覆盖色,并把按钮文案改为导入为待分类。 - 待分类兜底颜色统一为 #000000,和模板保留类、GT_label/Pro_label 导出规则一致。 - 补充后端回归断言并更新 AGENTS 与文档说明,保留 gt_unknown_class 和原始 gt_label_value 供后续重命名追溯。
This commit is contained in:
@@ -43,6 +43,14 @@ GT_MASK_EMPTY_DETAIL = "GT Mask 图片中没有非背景 maskid 区域。"
|
||||
GT_IMPORT_MAX_CONTOUR_POINTS = 2048
|
||||
GT_IMPORT_CONTOUR_EPSILON_RATIO = 0.00075
|
||||
GT_IMPORT_MIN_CONTOUR_EPSILON = 0.35
|
||||
RESERVED_UNCLASSIFIED_CLASS = {
|
||||
"id": "reserved-unclassified",
|
||||
"name": "待分类",
|
||||
"color": "#000000",
|
||||
"zIndex": 0,
|
||||
"maskId": 0,
|
||||
"category": "系统保留",
|
||||
}
|
||||
|
||||
|
||||
def _shared_project_or_404(project_id: int, db: Session, current_user: User) -> Project:
|
||||
@@ -107,10 +115,11 @@ def _rgb_tuple_to_hex(rgb: tuple[int, int, int]) -> str:
|
||||
return f"#{values[0]:02x}{values[1]:02x}{values[2]:02x}"
|
||||
|
||||
|
||||
def _template_class_maps(template: Template | None) -> tuple[dict[int, dict[str, Any]], dict[str, dict[str, Any]]]:
|
||||
def _template_class_maps(template: Template | None) -> tuple[dict[int, dict[str, Any]], dict[str, dict[str, Any]], dict[str, Any]]:
|
||||
classes = ((template.mapping_rules or {}).get("classes") if template else None) or []
|
||||
by_maskid: dict[int, dict[str, Any]] = {}
|
||||
by_color: dict[str, dict[str, Any]] = {}
|
||||
unclassified = dict(RESERVED_UNCLASSIFIED_CLASS)
|
||||
for index, item in enumerate(classes):
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
@@ -128,16 +137,13 @@ def _template_class_maps(template: Template | None) -> tuple[dict[int, dict[str,
|
||||
"maskId": maskid,
|
||||
**({"category": item.get("category")} if item.get("category") else {}),
|
||||
}
|
||||
if maskid == 0 or class_meta["id"] == RESERVED_UNCLASSIFIED_CLASS["id"] or class_meta["name"] == RESERVED_UNCLASSIFIED_CLASS["name"]:
|
||||
unclassified = dict(RESERVED_UNCLASSIFIED_CLASS)
|
||||
continue
|
||||
if maskid > 0:
|
||||
by_maskid[maskid] = class_meta
|
||||
by_color[color] = class_meta
|
||||
return by_maskid, by_color
|
||||
|
||||
|
||||
def _gt_unknown_label(token: int | str) -> str:
|
||||
if isinstance(token, int):
|
||||
return f"未定义类别 {token}"
|
||||
return f"未定义颜色 {token}"
|
||||
return by_maskid, by_color, unclassified
|
||||
|
||||
|
||||
def _load_frame_image(frame: Frame) -> np.ndarray:
|
||||
@@ -1048,7 +1054,7 @@ async def import_gt_mask(
|
||||
if resized_to_frame:
|
||||
label_image = cv2.resize(label_image, (width, height), interpolation=cv2.INTER_NEAREST)
|
||||
|
||||
by_maskid, _by_color = _template_class_maps(template)
|
||||
by_maskid, _by_color, unclassified_class = _template_class_maps(template)
|
||||
has_template_classes = bool(by_maskid)
|
||||
fallback_color = _normalize_hex_color(color) or "#22c55e"
|
||||
|
||||
@@ -1065,8 +1071,9 @@ async def import_gt_mask(
|
||||
annotation_label = class_meta["name"]
|
||||
annotation_color = class_meta["color"]
|
||||
elif is_unknown:
|
||||
annotation_label = _gt_unknown_label(label_value)
|
||||
annotation_color = fallback_color
|
||||
annotation_label = unclassified_class["name"]
|
||||
annotation_color = unclassified_class["color"]
|
||||
class_meta = unclassified_class
|
||||
else:
|
||||
annotation_label = f"{label} {label_value}" if len(label_values) > 1 else label
|
||||
annotation_color = fallback_color
|
||||
|
||||
@@ -1664,8 +1664,17 @@ def test_import_gt_mask_handles_unknown_maskid_policy_and_resizes_to_frame(clien
|
||||
|
||||
assert undefined_response.status_code == 201
|
||||
labels = {item["mask_data"]["label"] for item in undefined_response.json()}
|
||||
assert labels == {"已定义", "未定义类别 2"}
|
||||
unknown = next(item for item in undefined_response.json() if item["mask_data"]["label"].startswith("未定义"))
|
||||
assert labels == {"已定义", "待分类"}
|
||||
unknown = next(item for item in undefined_response.json() if item["mask_data"]["label"] == "待分类")
|
||||
assert unknown["mask_data"]["color"] == "#000000"
|
||||
assert unknown["mask_data"]["class"] == {
|
||||
"id": "reserved-unclassified",
|
||||
"name": "待分类",
|
||||
"color": "#000000",
|
||||
"zIndex": 0,
|
||||
"maskId": 0,
|
||||
"category": "系统保留",
|
||||
}
|
||||
assert unknown["mask_data"]["gt_unknown_class"] is True
|
||||
assert unknown["mask_data"]["gt_label_value"] == 2
|
||||
assert unknown["mask_data"]["gt_resized_to_frame"] is True
|
||||
|
||||
Reference in New Issue
Block a user