Image Quality Scoring (sharpness / contrast / brightness gate)

OCR and template matching quietly fail on a blurry, washed-out or too-dark capture — the locate returns nothing and the caller can’t tell a missing element from an unreadable one. image_quality measures the three things that wreck recognition and gates on them:

  • sharpness — variance of the Laplacian (low = blurry / out of focus),

  • contrast — standard deviation of the grayscale (low = washed out),

  • brightness — mean grayscale 0–255 (too low = dark, too high = blown out).

image_quality() returns the raw metrics, is_blurry() is the common one-liner, and quality_gate() turns the metrics into a pass / fail verdict with named issues, so a script can refuse to OCR a bad frame (or pre-process it first). It reuses visual_match’s grayscale loader, so the source is any ndarray / path / PIL image (or the live screen when omitted); cv2 / numpy are lazily imported. Imports no PySide6.

Headless API

from je_auto_control import image_quality, is_blurry, quality_gate

image_quality("frame.png")
# {"sharpness": 842.1, "contrast": 58.3, "brightness": 131.0}

if is_blurry("frame.png", threshold=100):
    ...  # capture again / sharpen before OCR

gate = quality_gate("frame.png", min_sharpness=100, min_contrast=12)
# {"sharpness": .., "contrast": .., "brightness": .., "passed": False,
#  "issues": ["blurry", "too_dark"]}

quality_gate flags blurry / low_contrast / too_dark / too_bright; passed is True only when no issue fires. region applies to a live-screen grab (omit source to grade the screen). Thresholds are tunable; the defaults suit typical UI screenshots.

Executor commands

AC_image_quality (source / region) and AC_quality_gate (plus min_sharpness / min_contrast). They are exposed as read-only ac_* MCP tools and as Script Builder commands under Image.