66 lines
2.6 KiB
Python
66 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
||
r"""golden_compare.py — C 档黄金图对比(迭代 9 卡⑰b 2026-09-30;呈现层测试分级·周期重闸件)。
|
||
|
||
用法: python tools/golden_compare.py <黄金图目录> <新截图目录> [屏清单...]
|
||
默认屏清单 = shot_menu.png shot_camp.png shot_level.png shot_battle.png。
|
||
|
||
判据(容差口径,v1 冻结):
|
||
① 四屏存在且尺寸一致(与黄金图逐屏比对);
|
||
② 逐像素灰度差 >16 的像素占比 ≤2%(抗锯齿/微噪声容差带——结构级变化必超带);
|
||
③ changed 占比 >2% 即 FAIL(视觉回归信号——逐屏列差异热区提示)。
|
||
基准冻结=2026-09-30(v3.5 视觉落码+营地终稿+分辨率案甲后);资产升档批换代时显式重制基准。
|
||
退出码: 0 = 全过 / 1 = 有失败。
|
||
"""
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
from PIL import Image, ImageChops
|
||
|
||
TOLERANCE = 16 # 灰度差容差(单通道)
|
||
FAIL_RATIO = 0.02 # changed 占比失败线
|
||
|
||
|
||
def compare(base: Path, curr: Path, name: str, failures: list) -> None:
|
||
pb, pc = base / name, curr / name
|
||
if not pb.exists():
|
||
failures.append("%s: 黄金图缺失(基准未建)" % name)
|
||
return
|
||
if not pc.exists():
|
||
failures.append("%s: 新截图缺失" % name)
|
||
return
|
||
a = Image.open(pb).convert("L")
|
||
b = Image.open(pc).convert("L")
|
||
if a.size != b.size:
|
||
failures.append("%s: 尺寸 %s != 基准 %s" % (name, b.size, a.size))
|
||
return
|
||
diff = ImageChops.difference(a, b)
|
||
hist = diff.histogram()
|
||
total = a.size[0] * a.size[1]
|
||
changed = sum(hist[TOLERANCE + 1:]) / total
|
||
print("[golden] %s — changed=%.2f%%(容差 ≤%.0f 差/≤%.0f%%)%s" % (
|
||
name, changed * 100, TOLERANCE, FAIL_RATIO * 100, "OK" if changed <= FAIL_RATIO else "FAIL"))
|
||
if changed > FAIL_RATIO:
|
||
failures.append("%s: changed %.2f%% > %.0f%%(视觉回归——核对热区后重制或修复)" % (name, changed * 100, FAIL_RATIO * 100))
|
||
|
||
|
||
def main() -> int:
|
||
if len(sys.argv) < 3:
|
||
print("用法: python tools/golden_compare.py <黄金图目录> <新截图目录> [屏清单...]")
|
||
return 1
|
||
base, curr = Path(sys.argv[1]), Path(sys.argv[2])
|
||
shots = sys.argv[3:] or ["shot_menu.png", "shot_camp.png", "shot_level.png", "shot_battle.png"]
|
||
failures = []
|
||
for name in shots:
|
||
compare(base, curr, name, failures)
|
||
if failures:
|
||
print("[golden] FAIL——")
|
||
for f in failures:
|
||
print(" - %s" % f)
|
||
return 1
|
||
print("[golden] PASS(%d 屏黄金图对比全过)" % len(shots))
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|