blazediff-interpret
Structured region analysis for image diffs. Given two images and a set of changed regions, it says what changed in each one — not just where.
use ;
// From a pixel diff — what `blazediff` does.
let result = interpret?;
// From a similarity map — what `blazediff-ssim` does.
let result = interpret?;
// From boxes you already have.
let result = interpret?;
println!;
for region in &result.regions
Why it's a separate crate
The classifier is deliberately independent of whatever found the regions. Three producers feed it today:
| Producer | ChangeSource |
How it finds regions |
|---|---|---|
blazediff |
Diff |
connected components over a pixel-diff mask |
blazediff-ssim |
ScoreMap |
thresholding a local SSIM score map |
| your code | Regions |
DOM rectangles, a JS-side diff, a crop list — anything |
All three call the same function and get identical treatment; only the description of where
differs. blazediff and blazediff-ssim are independent of each other, so a classifier living in
either would be unreachable from the other. It sits below both instead.
Coarse regions are fine
A producer only has to know roughly where something changed. Before any statistic is computed, the supplied boxes are refined against the source pixels — every pixel whose YIQ delta falls below the noise floor is dropped — so shape, colour and gradient analysis stay per-pixel no matter how blocky the input was. (If a claimed box refines to nothing but the content does differ — a sub-threshold edit such as a subtle uniform recolor — the box is kept as-is so the region still gets meaningful statistics.)
// An 8x8 change, described exactly and then quantized to a 16px grid.
let exact = interpret?;
let coarse = interpret?;
assert_eq!; // both 64
That is what makes an SSIM window map a usable region source: its grid is coarse, but the
statistics derived from it are not. diff_count therefore means the same thing on every path —
actually-changed pixels, never windows.
API
| Item | Purpose |
|---|---|
interpret |
the entry point: a ChangeSource in, a full InterpretResult out |
ChangeSource |
Diff (a pixel diff's output + counts), ScoreMap (a similarity map), or Regions |
classify_region / classify_regions |
classify against a mask you already hold |
detect_regions |
connected components over a boolean mask |
merge_overlapping_components |
fuse fragmented components whose bboxes overlap or nearly touch |
extract_change_mask |
recover a mask from an RGBA diff visualization |
detect_shifts |
the shift-relabeling pass, for producers holding an exact mask |
classify_severity, build_summary |
the pooling steps, exposed for custom pipelines |
Regions arriving from a caller are validated: a box outside the image is an
InterpretError::RegionOutOfBounds, not an out-of-bounds panic. That matters now that regions
cross the wasm and N-API boundaries.
Python - blazediff-interpret
PyO3 bindings shipped as abi3-py38 wheels for CPython ≥ 3.8 (macOS, Linux
manylinux, Windows; arm64 + x86_64). Built from this crate's python Cargo
feature.
=
# Also: interpret_buffers(bytes, bytes), interpret_ssim(base, compare,
# metric=...) and interpret_regions(base, compare, regions).
The result crosses as a plain dict with camelCase keys, matching the N-API
binding and the CLI's --json. interpret_regions takes (x, y, width, height) tuples or mappings with those keys, so a bbox from a prior result
feeds straight back in.
What it classifies
Each region gets a change type, a shape, a position, a confidence, and the statistics behind them — colour delta, gradient/edge correlation, luminance correlation, chroma-plane movement (hue rotation, saturation, delta smoothness), fill ratios, and the signals the classifier used. See INTERPRET.md for the full algorithm: pipeline stages, formulas, and classification rules.
License
MIT