feat(ceus): 两半坐标换算改为每段视频配准,加目视核对脚本
- 第 1 步分屏后在两半扇形区内用边缘图归一化互相关估 (dx, dy),再用逐帧多块模板匹配的中位数独立核对; 两者各分量之差超过门槛(15 像素)这一例第 1 步失败。删掉「两个视图左上角相减」的实现与测试。 - 门槛依据:34 例中走完第 1 步的 29 例,差值中位 2、95 分位 6.2、最大 13;参数与门槛在同一批视频上调出。 - scripts/ceus_align_review.py:只做第 1 步,出扇形区棋盘图与边缘叠加图,混入错开 15–30 像素的 阴性对照、随机编号;计分时任一对照未被判「没对齐」即作废。 - ceus_quant 读 review.csv:不通过的病例第 1 步失败;表里没有这段视频或平移对不上即停。 - 配准与紫圈颜色参数进分割缓存键。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+24
-24
@@ -1,5 +1,5 @@
|
||||
"""polygons 的单元测试(照搬旧项目 test_ceus_polygons.py;坐标换算改为两个视图矩形,
|
||||
去掉旧的有效区矩形和映射锚点参数)。
|
||||
"""polygons 的单元测试(照搬旧项目 test_ceus_polygons.py;坐标换算改为配准得到的平移 `offset`,
|
||||
去掉旧的有效区矩形和映射锚点参数。旧用例里两个视图左上角相同,平移取 (0, 0),断言不变)。
|
||||
|
||||
旧标题:B6 polygons.py 的单元测试:mask→平滑多边形 + 位置约束 + 绿框先验融合。
|
||||
|
||||
@@ -104,7 +104,7 @@ def test_masks_to_smoothed_polygons_all_empty_raises() -> None:
|
||||
def test_position_constraint_pulls_center_to_keyframe_track_without_area_change() -> None:
|
||||
"""strength=1.0 把每帧质心拉到 keyframe 中心插值轨迹,且整体平移不改面积。"""
|
||||
target_eff = ViewRect(0, 0, 200, 200)
|
||||
source_view = ViewRect(0, 0, 200, 200)
|
||||
offset = (0, 0)
|
||||
|
||||
# 两个 keyframe:source mask 中心分别在 (40, 100) 与 (160, 100)
|
||||
keyframes = [
|
||||
@@ -118,7 +118,7 @@ def test_position_constraint_pulls_center_to_keyframe_track_without_area_change(
|
||||
corrected = apply_prompt_frame_position_constraints(
|
||||
polygons,
|
||||
keyframes,
|
||||
source_view,
|
||||
offset,
|
||||
target_eff,
|
||||
_CONFIG.constraints.keyframe_position, # enabled、center_interpolation、strength=1.0
|
||||
)
|
||||
@@ -138,14 +138,14 @@ def test_position_constraint_pulls_center_to_keyframe_track_without_area_change(
|
||||
def test_position_constraint_disabled_returns_input() -> None:
|
||||
"""enabled=False 时原样返回输入(门关)。"""
|
||||
target_eff = ViewRect(0, 0, 100, 100)
|
||||
source_view = ViewRect(0, 0, 100, 100)
|
||||
offset = (0, 0)
|
||||
polygons = [_circle_polygon((50.0, 50.0), 10.0, 64)]
|
||||
keyframes = [{"frame_index": 0, "mask": _disk_mask(100, 100, (50, 50), 10)}]
|
||||
|
||||
out = apply_prompt_frame_position_constraints(
|
||||
polygons,
|
||||
keyframes,
|
||||
source_view,
|
||||
offset,
|
||||
target_eff,
|
||||
_CONFIG.constraints.keyframe_position.model_copy(update={"enabled": False}),
|
||||
)
|
||||
@@ -156,14 +156,14 @@ def test_position_constraint_disabled_returns_input() -> None:
|
||||
def test_fusion_gate_closed_returns_pure_medsam() -> None:
|
||||
"""roi_shape.source != 'prompt_prior' → 直接返回纯 medsam(门关,findings §3.7)。"""
|
||||
target_eff = ViewRect(0, 0, 100, 100)
|
||||
source_view = ViewRect(0, 0, 100, 100)
|
||||
offset = (0, 0)
|
||||
medsam = [_circle_polygon((50.0, 50.0), 10.0, 64)]
|
||||
keyframes = [{"frame_index": 0, "mask": _disk_mask(100, 100, (50, 50), 10)}]
|
||||
|
||||
out = fuse_prompt_prior_with_medsam(
|
||||
medsam,
|
||||
keyframes,
|
||||
source_view,
|
||||
offset,
|
||||
target_eff,
|
||||
_CONFIG.roi_shape.model_copy(update={"source": "medsam2"}),
|
||||
_CONFIG.smoothing,
|
||||
@@ -175,7 +175,7 @@ def test_fusion_gate_closed_returns_pure_medsam() -> None:
|
||||
def test_fusion_keyframe_strength_one_yields_prior_shape() -> None:
|
||||
"""keyframe 帧 strength=1.0:融合结果几何上贴近绿框先验(逐顶点混合 s=1)。"""
|
||||
target_eff = ViewRect(0, 0, 200, 200)
|
||||
source_view = ViewRect(0, 0, 200, 200)
|
||||
offset = (0, 0)
|
||||
|
||||
# 绿框先验中心 (100, 100) 半径 30;medsam 偏移到 (130, 130) 半径 30
|
||||
keyframes = [{"frame_index": 0, "mask": _disk_mask(200, 200, (100, 100), 30)}]
|
||||
@@ -184,7 +184,7 @@ def test_fusion_keyframe_strength_one_yields_prior_shape() -> None:
|
||||
fused = fuse_prompt_prior_with_medsam(
|
||||
medsam,
|
||||
keyframes,
|
||||
source_view,
|
||||
offset,
|
||||
target_eff,
|
||||
_CONFIG.roi_shape.model_copy(update={"keyframe_shape_strength": 1.0}),
|
||||
_CONFIG.smoothing,
|
||||
@@ -200,7 +200,7 @@ def test_fusion_keyframe_strength_one_yields_prior_shape() -> None:
|
||||
def test_fusion_area_clamped_to_prior_band() -> None:
|
||||
"""融合面积超过 max_area_ratio_to_prompt 时按 sqrt 绕先验质心缩放回界(findings §3.7)。"""
|
||||
target_eff = ViewRect(0, 0, 400, 400)
|
||||
source_view = ViewRect(0, 0, 400, 400)
|
||||
offset = (0, 0)
|
||||
|
||||
# 关键帧只在 frame 0;frame 1 为传播帧(非 keyframe),用 propagation_shape_strength=0
|
||||
# 让 medsam 形状主导,从而触发面积收紧。先验半径 30,medsam 半径 80(面积远超 1.25×)。
|
||||
@@ -222,7 +222,7 @@ def test_fusion_area_clamped_to_prior_band() -> None:
|
||||
fused = fuse_prompt_prior_with_medsam(
|
||||
medsam,
|
||||
keyframes,
|
||||
source_view,
|
||||
offset,
|
||||
target_eff,
|
||||
shape_cfg,
|
||||
_CONFIG.smoothing,
|
||||
@@ -246,7 +246,7 @@ def test_fusion_propagation_frame_linear_blend_without_tightening() -> None:
|
||||
使逐顶点线性混合的几何结果可被精确预测(绕开起点对齐 / 收紧的扰动)。
|
||||
"""
|
||||
target_eff = ViewRect(0, 0, 400, 400)
|
||||
source_view = ViewRect(0, 0, 400, 400)
|
||||
offset = (0, 0)
|
||||
|
||||
# 单关键帧(frame 0),frame 1 为传播帧;先验半径 50,medsam 半径 60(面积比≈1.44,
|
||||
# 但 max_ratio 放宽到 2.0 → 不触发收紧),中心同在 (200, 200)
|
||||
@@ -267,7 +267,7 @@ def test_fusion_propagation_frame_linear_blend_without_tightening() -> None:
|
||||
fused = fuse_prompt_prior_with_medsam(
|
||||
medsam,
|
||||
keyframes,
|
||||
source_view,
|
||||
offset,
|
||||
target_eff,
|
||||
shape_cfg,
|
||||
_CONFIG.smoothing,
|
||||
@@ -297,7 +297,7 @@ def test_fusion_propagation_frame_linear_blend_without_tightening() -> None:
|
||||
def test_fusion_lower_bound_tightening_expands_area() -> None:
|
||||
"""下界收紧:medsam 面积 < min_ratio × prior 面积 → 被放大到 ≈ min_ratio × prior。"""
|
||||
target_eff = ViewRect(0, 0, 400, 400)
|
||||
source_view = ViewRect(0, 0, 400, 400)
|
||||
offset = (0, 0)
|
||||
|
||||
# 先验半径 60;medsam 传播帧半径 20(面积比≈0.11 < min_ratio 0.70 → 触发下界放大)
|
||||
keyframes = [{"frame_index": 0, "mask": _disk_mask(400, 400, (200, 200), 60)}]
|
||||
@@ -316,7 +316,7 @@ def test_fusion_lower_bound_tightening_expands_area() -> None:
|
||||
fused = fuse_prompt_prior_with_medsam(
|
||||
medsam,
|
||||
keyframes,
|
||||
source_view,
|
||||
offset,
|
||||
target_eff,
|
||||
shape_cfg,
|
||||
_CONFIG.smoothing,
|
||||
@@ -336,7 +336,7 @@ def test_fusion_start_point_misalignment_does_not_distort_shape() -> None:
|
||||
若不先对齐起点,逐顶点混合会把不同角度的点平均出来导致半径塌缩;align 后应保形。
|
||||
"""
|
||||
target_eff = ViewRect(0, 0, 400, 400)
|
||||
source_view = ViewRect(0, 0, 400, 400)
|
||||
offset = (0, 0)
|
||||
|
||||
radius = 50.0
|
||||
keyframes = [{"frame_index": 0, "mask": _disk_mask(400, 400, (200, 200), int(radius))}]
|
||||
@@ -357,7 +357,7 @@ def test_fusion_start_point_misalignment_does_not_distort_shape() -> None:
|
||||
fused = fuse_prompt_prior_with_medsam(
|
||||
medsam,
|
||||
keyframes,
|
||||
source_view,
|
||||
offset,
|
||||
target_eff,
|
||||
shape_cfg,
|
||||
_CONFIG.smoothing,
|
||||
@@ -374,7 +374,7 @@ def test_fusion_start_point_misalignment_does_not_distort_shape() -> None:
|
||||
def test_fusion_propagation_strength_clipped_to_unit_interval() -> None:
|
||||
"""传播权重越界(1.5 / −0.5)经函数内部 np.clip → 行为等价 1.0 / 0.0。"""
|
||||
target_eff = ViewRect(0, 0, 400, 400)
|
||||
source_view = ViewRect(0, 0, 400, 400)
|
||||
offset = (0, 0)
|
||||
|
||||
keyframes = [{"frame_index": 0, "mask": _disk_mask(400, 400, (200, 200), 40)}]
|
||||
medsam = [
|
||||
@@ -392,7 +392,7 @@ def test_fusion_propagation_strength_clipped_to_unit_interval() -> None:
|
||||
return fuse_prompt_prior_with_medsam(
|
||||
medsam,
|
||||
keyframes,
|
||||
source_view,
|
||||
offset,
|
||||
target_eff,
|
||||
shape_cfg,
|
||||
_CONFIG.smoothing,
|
||||
@@ -465,7 +465,7 @@ def test_temporal_smoothing_no_vertex_crossing_distortion() -> None:
|
||||
def test_position_constraint_invalid_mode_raises() -> None:
|
||||
"""mode != 'center_interpolation' → RuntimeError(当前仅支持该模式,纵深防御)。"""
|
||||
target_eff = ViewRect(0, 0, 200, 200)
|
||||
source_view = ViewRect(0, 0, 200, 200)
|
||||
offset = (0, 0)
|
||||
polygons = [_circle_polygon((100.0, 100.0), 20.0, 64)]
|
||||
keyframes = [{"frame_index": 0, "mask": _disk_mask(200, 200, (100, 100), 20)}]
|
||||
|
||||
@@ -473,7 +473,7 @@ def test_position_constraint_invalid_mode_raises() -> None:
|
||||
apply_prompt_frame_position_constraints(
|
||||
polygons,
|
||||
keyframes,
|
||||
source_view,
|
||||
offset,
|
||||
target_eff,
|
||||
_RawConstraintCfg(mode="affine"),
|
||||
)
|
||||
@@ -482,7 +482,7 @@ def test_position_constraint_invalid_mode_raises() -> None:
|
||||
def test_position_constraint_strength_clipped_to_unit_interval() -> None:
|
||||
"""strength 越界(1.5 / −0.5)经函数内部 np.clip → 行为等价 1.0 / 0.0。"""
|
||||
target_eff = ViewRect(0, 0, 200, 200)
|
||||
source_view = ViewRect(0, 0, 200, 200)
|
||||
offset = (0, 0)
|
||||
keyframes = [
|
||||
{"frame_index": 0, "mask": _disk_mask(200, 200, (40, 100), 15)},
|
||||
{"frame_index": 2, "mask": _disk_mask(200, 200, (160, 100), 15)},
|
||||
@@ -493,7 +493,7 @@ def test_position_constraint_strength_clipped_to_unit_interval() -> None:
|
||||
corrected = apply_prompt_frame_position_constraints(
|
||||
[poly.copy() for poly in base_polys],
|
||||
keyframes,
|
||||
source_view,
|
||||
offset,
|
||||
target_eff,
|
||||
_RawConstraintCfg(strength=strength),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user