Files
Pre_Seg_Server/backend/tests/test_sam2_engine.py
admin 8a9247075e feat: 完善 AI 分割与工作区标注闭环
功能增加:

- 将视频导入和生成帧拆成两个明确动作,项目库生成帧时选择 FPS,工作区不再自动触发拆帧。

- 为工作区新增调整多边形工具,支持选中 mask、拖动顶点、边中点插点、双击边界按位置插点,并保留多 polygon 子区域编辑。

- 打通 AI 页 SAM2/SAM3 结果到工作区的联动,生成 mask 后自动选中,可在右侧分类树换标签,并推送到工作区继续编辑。

- 增强 Dashboard WebSocket 连接状态与心跳,使用真实 onopen/onclose/onerror 状态驱动前端显示。

- 完善 SAM3 external worker 适配,支持 box prompt、semantic 请求级阈值和 video tracker 路径。

bugfix:

- 修复 SAM2 文本语义误走自动分割的问题,改为提示使用点提示或切换 SAM3。

- 修复 SAM2 多候选重叠显示的问题,点提示和 auto fallback 默认只采用最高分候选。

- 修复 SAM2 反向点看起来无效的问题,带负点时启用背景过滤,过滤为空时移除旧候选。

- 修复 SAM3 单个 2D mask 结果无法转 polygon、低阈值 semantic 返回被默认阈值吞掉的问题。

- 修复 AI 页 mask 未选中导致分类树无法修改 SAM2 结果标签的问题。

测试和文档:

- 补充 CanvasArea、AISegmentation、ProjectLibrary、VideoWorkspace、Dashboard、websocket 和 SAM engine/API 测试。

- 新增 backend/tests/test_sam2_engine.py,覆盖 SAM2 单候选请求和 auto fallback 行为。

- 更新 README、AGENTS 和 doc 需求/设计/接口/测试矩阵,按当前实现冻结功能状态。
2026-05-01 21:50:17 +08:00

64 lines
1.7 KiB
Python

import numpy as np
from services.sam2_engine import SAM2Engine
class _FakePredictor:
def __init__(self, masks, scores):
self.masks = masks
self.scores = scores
self.calls = []
def set_image(self, _image):
pass
def predict(self, **kwargs):
self.calls.append(kwargs)
return self.masks, self.scores, None
def _mask(offset=0):
mask = np.zeros((32, 32), dtype=np.uint8)
mask[4 + offset:20 + offset, 5 + offset:22 + offset] = 1
return mask
def _ready_engine(monkeypatch, predictor):
monkeypatch.setattr("services.sam2_engine.SAM2_AVAILABLE", True)
engine = SAM2Engine()
engine._model_loaded = True
engine._predictor = predictor
return engine
def test_sam2_point_prediction_requests_single_best_mask(monkeypatch):
predictor = _FakePredictor(
np.array([_mask()], dtype=np.uint8),
np.array([0.92], dtype=np.float32),
)
engine = _ready_engine(monkeypatch, predictor)
polygons, scores = engine.predict_points(
np.zeros((32, 32, 3), dtype=np.uint8),
[[0.5, 0.5]],
[1],
)
assert predictor.calls[0]["multimask_output"] is False
assert len(polygons) == 1
assert scores == [0.9200000166893005]
def test_sam2_auto_prediction_keeps_single_best_mask(monkeypatch):
predictor = _FakePredictor(
np.array([_mask(0), _mask(2), _mask(4)], dtype=np.uint8),
np.array([0.8, 0.7, 0.6], dtype=np.float32),
)
engine = _ready_engine(monkeypatch, predictor)
polygons, scores = engine.predict_auto(np.zeros((32, 32, 3), dtype=np.uint8))
assert predictor.calls[0]["multimask_output"] is False
assert len(polygons) == 1
assert scores == [0.800000011920929]