保持传播多区域结果为单个遮罩
- 后端传播落库时将同一 seed 在同一目标帧的多个不连通 polygon 保存到同一 annotation - 同步任务传播和兼容同步传播接口的多 polygon 保存逻辑 - 传播结果 bbox 改为覆盖全部不连通 polygon,并保留多 polygon scores 与 holes - 前端回显单条多 polygon annotation 时使用组合 bbox 和真实 polygon 面积 - 补充后端传播 worker 回归测试,验证不连通结果只生成一个 annotation - 补充前端 API 回归测试,验证多 polygon annotation 回显为一个 mask - 更新项目指南和设计冻结文档
This commit is contained in:
@@ -83,6 +83,17 @@ def _polygon_bbox(polygon: list[list[float]]) -> list[float]:
|
||||
return [left, top, max(right - left, 0.0), max(bottom - top, 0.0)]
|
||||
|
||||
|
||||
def _polygons_bbox(polygons: list[list[list[float]]]) -> list[float]:
|
||||
points = [point for polygon in polygons for point in polygon if len(point) >= 2]
|
||||
if not points:
|
||||
return [0.0, 0.0, 0.0, 0.0]
|
||||
xs = [_clamp01(point[0]) for point in points]
|
||||
ys = [_clamp01(point[1]) for point in points]
|
||||
left, right = min(xs), max(xs)
|
||||
top, bottom = min(ys), max(ys)
|
||||
return [left, top, max(right - left, 0.0), max(bottom - top, 0.0)]
|
||||
|
||||
|
||||
def _normalize_polygon(polygon: list[list[float]]) -> list[list[float]]:
|
||||
return [[_clamp01(point[0]), _clamp01(point[1])] for point in polygon if len(point) >= 2]
|
||||
|
||||
@@ -520,36 +531,49 @@ def _save_propagated_annotations(
|
||||
polygon=cleanup_polygon,
|
||||
)
|
||||
cleaned_frame_ids.add(int(frame.id))
|
||||
polygons_to_save: list[list[list[float]]] = []
|
||||
holes_to_save: list[list[list[list[float]]]] = []
|
||||
score_values: list[float] = []
|
||||
for polygon_index, polygon in prepared_polygons:
|
||||
if len(polygon) < 3:
|
||||
continue
|
||||
polygons_to_save.append(polygon)
|
||||
hole_group = result_holes[polygon_index] if polygon_index < len(result_holes) and isinstance(result_holes[polygon_index], list) else []
|
||||
annotation = Annotation(
|
||||
project_id=int(payload["project_id"]),
|
||||
frame_id=frame.id,
|
||||
template_id=template_id,
|
||||
mask_data={
|
||||
"polygons": [polygon],
|
||||
**({"holes": [hole_group], "hasHoles": True} if hole_group else {}),
|
||||
"label": label,
|
||||
"color": color,
|
||||
"source": f"{model_id}_propagation",
|
||||
"propagated_from_frame_id": source_frame.id,
|
||||
"propagated_from_frame_index": source_frame.frame_index,
|
||||
"propagation_seed_key": seed_key,
|
||||
"propagation_seed_signature": seed_signature,
|
||||
"propagation_direction": direction,
|
||||
"source_annotation_id": source_annotation_id,
|
||||
"source_mask_id": source_mask_id,
|
||||
"score": scores[polygon_index] if polygon_index < len(scores) else None,
|
||||
**({"geometry_smoothing": smoothing} if smoothing else {}),
|
||||
**({"class": class_metadata} if class_metadata else {}),
|
||||
},
|
||||
points=None,
|
||||
bbox=_polygon_bbox(polygon),
|
||||
)
|
||||
db.add(annotation)
|
||||
created.append(annotation)
|
||||
holes_to_save.append(hole_group if isinstance(hole_group, list) else [])
|
||||
if polygon_index < len(scores):
|
||||
try:
|
||||
score_values.append(float(scores[polygon_index]))
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if not polygons_to_save:
|
||||
continue
|
||||
annotation = Annotation(
|
||||
project_id=int(payload["project_id"]),
|
||||
frame_id=frame.id,
|
||||
template_id=template_id,
|
||||
mask_data={
|
||||
"polygons": polygons_to_save,
|
||||
**({"holes": holes_to_save, "hasHoles": True} if any(holes_to_save) else {}),
|
||||
"label": label,
|
||||
"color": color,
|
||||
"source": f"{model_id}_propagation",
|
||||
"propagated_from_frame_id": source_frame.id,
|
||||
"propagated_from_frame_index": source_frame.frame_index,
|
||||
"propagation_seed_key": seed_key,
|
||||
"propagation_seed_signature": seed_signature,
|
||||
"propagation_direction": direction,
|
||||
"source_annotation_id": source_annotation_id,
|
||||
"source_mask_id": source_mask_id,
|
||||
"score": max(score_values) if score_values else None,
|
||||
**({"scores": score_values} if len(score_values) > 1 else {}),
|
||||
**({"geometry_smoothing": smoothing} if smoothing else {}),
|
||||
**({"class": class_metadata} if class_metadata else {}),
|
||||
},
|
||||
points=None,
|
||||
bbox=_polygons_bbox(polygons_to_save),
|
||||
)
|
||||
db.add(annotation)
|
||||
created.append(annotation)
|
||||
|
||||
db.commit()
|
||||
for annotation in created:
|
||||
|
||||
Reference in New Issue
Block a user