Structural Image Comparison
Pixel-by-pixel diffing answers βhow many pixels changedβ. Structural metrics answer βhow different do these lookβ - they tolerate imperceptible noise (compression artifacts, sub-pixel shifts) and score perceived similarity instead. Reach for them when an exact pixel match is too strict.
BlazeDiff ships two: GMSD (gradient-based, fast) and SSIM (the classic structural index, with a 4Γ faster Hitchhikerβs variant).
New to these metrics? Start with what SSIM is, how GMSD works, or which one to pick.
Installation
npm install @blazediff/gmsd @blazediff/ssimGMSD (Gradient Magnitude Similarity Deviation)
Scores gradient (edge) similarity. Returns 0 for identical images; lower is
better, typically in the 0β0.35 range.
Basic Comparison

Image 1

Image 2
Result
import gmsd from "@blazediff/gmsd";
const img1 = await loadImage(
"https://raw.githubusercontent.com/teimurjan/blazediff/refs/heads/main/fixtures/blazediff/3a.png"
);
const img2 = await loadImage(
"https://raw.githubusercontent.com/teimurjan/blazediff/refs/heads/main/fixtures/blazediff/3b.png"
);
const width = img1.width;
const height = img1.height;
const score = gmsd(img1, img2, undefined, width, height);See the GMSD API reference β.
SSIM (Structural Similarity Index)
Scores luminance, contrast, and structure. Returns 1 for identical images;
higher is better, in the 0β1 range. The Hitchhikerβs variant uses
non-overlapping windows for ~4Γ the throughput at near-identical accuracy.
Original SSIM

Image 1

Image 2
SSIM Map
import ssim from "@blazediff/ssim/ssim";
const img1 = await loadImage(
"https://raw.githubusercontent.com/teimurjan/blazediff/refs/heads/main/fixtures/blazediff/3a.png"
);
const img2 = await loadImage(
"https://raw.githubusercontent.com/teimurjan/blazediff/refs/heads/main/fixtures/blazediff/3b.png"
);
const output = new Uint8Array(img1.width * img1.height * 4);
const width = img1.width;
const height = img1.height;
const score = ssim(img1, img2, output, width, height);See the SSIM API reference β.