summaryrefslogtreecommitdiff
path: root/scripts/check-p40-night-boat-contrast.py
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-28 18:15:23 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-28 18:15:23 +0800
commite32e288358ffcf35d45bd1c6f1912746cdbc3d37 (patch)
tree58d4c33a066877b53894a3c7e03e0cb0f6540fde /scripts/check-p40-night-boat-contrast.py
parent72cb75848dd56e2cb766cbf1df97dc1891667e1e (diff)
downloadliving-village-e32e288358ffcf35d45bd1c6f1912746cdbc3d37.tar.gz
feat(p41): 夜帧船篷对比暗化
- VillageArt.drawCc0BoatOverlay 增加夜层专用暗化系数 0.7(仅夜光晕层生效, 白天不调用 overlay,p40-day/p40-boat 逐字节不变) - P40ArtTests 新增 NightBoatAwningIsAtLeast40GreyDarkerThanSurroundingGlow: 内嵌 PNG 解码读取夜帧,断言船 2 瓦包围盒比 24px 光晕环至少暗 40 灰阶 - 新增 scripts/check-p40-night-boat-contrast.py 独立像素守卫 - 重出 docs/evidence/p40-night.png(contrast 103.2 >= 40)
Diffstat (limited to 'scripts/check-p40-night-boat-contrast.py')
-rw-r--r--scripts/check-p40-night-boat-contrast.py59
1 files changed, 59 insertions, 0 deletions
diff --git a/scripts/check-p40-night-boat-contrast.py b/scripts/check-p40-night-boat-contrast.py
new file mode 100644
index 0000000..c6375a9
--- /dev/null
+++ b/scripts/check-p40-night-boat-contrast.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+"""Fail if the p40-night frame's Wu Peng boat is not dark enough against its glow.
+
+The `LV_P40_SHOT=1` night hook centers tile (234,50) in a 1280x720 viewport; the
+two-tile boat occupies tiles (234,50)-(235,50), so its screen box and the ring of
+lantern glow around it are pure functions of those constants. The regression
+budget is: mean luma of the boat box must be at least 40 grey below the mean luma
+of a 24px ring around it.
+
+Usage:
+ python3 scripts/check-p40-night-boat-contrast.py [p40-night.png]
+
+Defaults to docs/evidence/p40-night.png. Exit 0 clean, 1 below budget, 2 on
+usage/read error.
+"""
+
+import sys
+from pathlib import Path
+
+import numpy as np
+from PIL import Image
+
+MIN_CONTRAST = 40.0
+TILE = 32
+VIEW_W, VIEW_H = 1280, 720
+BOAT_TX, BOAT_TY = 234, 50
+RING = 24
+
+
+def measure(path):
+ rgba = np.asarray(Image.open(path).convert("RGB"), dtype=np.float64)
+ luma = 0.299 * rgba[:, :, 0] + 0.587 * rgba[:, :, 1] + 0.114 * rgba[:, :, 2]
+ cam_x = BOAT_TX * TILE + TILE // 2 - VIEW_W // 2
+ cam_y = BOAT_TY * TILE + TILE // 2 - VIEW_H // 2
+ x0 = BOAT_TX * TILE - cam_x
+ y0 = BOAT_TY * TILE - cam_y
+ x1 = x0 + 2 * TILE
+ y1 = y0 + TILE
+ boat = float(luma[y0:y1, x0:x1].mean())
+ patch = luma[y0 - RING:y1 + RING, x0 - RING:x1 + RING].copy()
+ patch[RING:RING + TILE, RING:RING + 2 * TILE] = np.nan
+ ring = float(np.nanmean(patch))
+ return boat, ring
+
+
+def main(argv):
+ target = Path(argv[1]) if len(argv) > 1 else Path("docs/evidence/p40-night.png")
+ if not target.is_file():
+ sys.stderr.write(f"missing frame: {target}\n")
+ return 2
+ boat, ring = measure(target)
+ contrast = ring - boat
+ status = "OK" if contrast >= MIN_CONTRAST else "FAIL"
+ print(f"p40-night boat={boat:.1f} ring={ring:.1f} contrast={contrast:.1f} (>= {MIN_CONTRAST:.0f}) {status}")
+ return 0 if contrast >= MIN_CONTRAST else 1
+
+
+if __name__ == "__main__":
+ raise SystemExit(main(sys.argv))