Perceptual (YIQ) Image Diff with Anti-Alias Suppression
visual_regression.image_difference counts raw per-channel max-delta pixels and
ssim_compare gives a global structural score. Neither uses a perceptual colour
metric, and neither ignores anti-aliased edges — the #1 source of false-positive
visual-diff failures across DPI and font-hinting. perceptual_diff compares pixels
in YIQ space (the pixelmatch colour metric, far closer to human perception than RGB)
and, by default, removes the thin one-pixel edge differences that anti-aliasing
produces (a morphological open), so only solid changed regions count.
Runs on an injectable image pair (ndarray / path / PIL), so it is headless-testable on
synthetic arrays. OpenCV + NumPy come in via je_open_cv; reuses the shared
connected-component helper and RGB loader. Imports no PySide6.
Headless API
from je_auto_control import perceptual_diff, assert_perceptual
result = perceptual_diff("actual.png", "golden.png", threshold=0.1)
print(result.diff_pixels, result.diff_ratio, result.regions)
# Gate a visual-regression test (raises if the ratio is exceeded).
assert_perceptual("actual.png", "golden.png", max_diff_ratio=0.01)
perceptual_diff returns a PerceptualDiffResult (diff_pixels,
total_pixels, diff_ratio, and the regions boxes of the changed clusters).
threshold (0..1) is the pixelmatch sensitivity. include_aa=True keeps the thin
edge differences instead of suppressing them. assert_perceptual raises
AutoControlActionException when diff_ratio exceeds max_diff_ratio. Images of
different sizes raise ValueError.
Executor command
AC_perceptual_diff (actual / expected / threshold / include_aa /
max_diff_ratio → {diff_pixels, total_pixels, diff_ratio, regions}; raises when
max_diff_ratio is given and exceeded). It is exposed as the MCP tool
ac_perceptual_diff and as a Script Builder command under Image.