Add a script I used to check that my tag spacing changes
Signed-off-by: Danila Fedorin <danila.fedorin@gmail.com>
This commit is contained in:
118
scripts/chatgpt-check-offset-diff.py
Normal file
118
scripts/chatgpt-check-offset-diff.py
Normal file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from pathlib import Path
|
||||
from PIL import Image, ImageChops
|
||||
import argparse
|
||||
import re
|
||||
|
||||
def load_rgb(path: Path) -> Image.Image:
|
||||
return Image.open(path).convert("RGB")
|
||||
|
||||
def mse(img: Image.Image) -> float:
|
||||
hist = img.histogram()
|
||||
sq = sum(v * ((i % 256) ** 2) for i, v in enumerate(hist))
|
||||
return sq / (img.width * img.height * 3)
|
||||
|
||||
def crop_pair(expected, actual, shift):
|
||||
# shift > 0 means actual content is lower than expected.
|
||||
w = min(expected.width, actual.width)
|
||||
|
||||
if shift >= 0:
|
||||
e_box = (0, 0, w, min(expected.height, actual.height - shift))
|
||||
a_box = (0, shift, w, shift + (e_box[3] - e_box[1]))
|
||||
else:
|
||||
s = -shift
|
||||
a_box = (0, 0, w, min(actual.height, expected.height - s))
|
||||
e_box = (0, s, w, s + (a_box[3] - a_box[1]))
|
||||
|
||||
return expected.crop(e_box), actual.crop(a_box)
|
||||
|
||||
def best_vertical_shift(expected, actual, max_shift=100):
|
||||
best = None
|
||||
|
||||
for shift in range(18, 19):
|
||||
e, a = crop_pair(expected, actual, shift)
|
||||
if e.height <= 0:
|
||||
continue
|
||||
|
||||
score = mse(ImageChops.difference(e, a))
|
||||
if best is None or score < best[1]:
|
||||
best = (shift, score)
|
||||
|
||||
return best
|
||||
|
||||
def changed_until_y(expected, actual, threshold=5, min_changed_pixels=10):
|
||||
diff = ImageChops.difference(expected, actual)
|
||||
last_changed = None
|
||||
|
||||
for y in range(diff.height):
|
||||
row = diff.crop((0, y, diff.width, y + 1)).convert("L")
|
||||
changed = sum(1 for px in row.getdata() if px > threshold)
|
||||
|
||||
if changed >= min_changed_pixels:
|
||||
last_changed = y
|
||||
|
||||
return {
|
||||
"last_changed_y": last_changed,
|
||||
"clean_after_y": 0 if last_changed is None else last_changed + 1,
|
||||
}
|
||||
|
||||
def find_pairs(root: Path):
|
||||
expected_files = sorted(root.rglob("*-expected.png"))
|
||||
|
||||
for expected in expected_files:
|
||||
actual = expected.with_name(
|
||||
expected.name.replace("-expected.png", "-actual.png")
|
||||
)
|
||||
if actual.exists():
|
||||
yield expected, actual
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("root", type=Path, nargs="?", default=Path("test-results"))
|
||||
ap.add_argument("--max-shift", type=int, default=100)
|
||||
ap.add_argument("--make-diffs", action="store_true")
|
||||
args = ap.parse_args()
|
||||
|
||||
failed = False
|
||||
|
||||
for expected_path, actual_path in find_pairs(args.root):
|
||||
expected = load_rgb(expected_path)
|
||||
actual = load_rgb(actual_path)
|
||||
|
||||
raw_score = mse(ImageChops.difference(
|
||||
expected.crop((0, 0, min(expected.width, actual.width), min(expected.height, actual.height))),
|
||||
actual.crop((0, 0, min(expected.width, actual.width), min(expected.height, actual.height))),
|
||||
))
|
||||
|
||||
shift, shifted_score = best_vertical_shift(
|
||||
expected, actual, max_shift=args.max_shift
|
||||
)
|
||||
|
||||
status = "OK" if shifted_score < raw_score * 0.05 else "CHECK"
|
||||
if status == "CHECK":
|
||||
failed = True
|
||||
|
||||
rel = expected_path.relative_to(args.root)
|
||||
print(f"{status} {rel}")
|
||||
print(f" expected: {expected.size}, actual: {actual.size}")
|
||||
print(f" best shift: {shift:+d}px")
|
||||
print(f" raw mse: {raw_score:.3f}")
|
||||
print(f" shifted mse: {shifted_score:.3f}")
|
||||
|
||||
if args.make_diffs:
|
||||
e, a = crop_pair(expected, actual, shift)
|
||||
change_info = changed_until_y(e, a, threshold=2)
|
||||
print(f" last changed y after shift: {change_info['last_changed_y']}")
|
||||
print(f" clean after y after shift: {change_info['clean_after_y']}")
|
||||
diff = ImageChops.difference(e, a)
|
||||
out = expected_path.with_name(
|
||||
expected_path.name.replace("-expected.png", f"-shift-{shift:+d}-diff.png")
|
||||
)
|
||||
diff.save(out)
|
||||
print(f" wrote: {out}")
|
||||
|
||||
raise SystemExit(1 if failed else 0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user