Skip to content

Butteraugli

currentMigrated from docs/metrics/butteraugli.mdx at 37c3317fd058; modified for Encode Wiki · CC BY-SA 4.0

Butteraugli is a psychovisual image difference metric from Google. It models how the eye’s colour receptors and early visual processing respond to an image, and outputs both a per-pixel difference map and a single distance: 0 for identical images, higher for more visible differences. It is maintained in libjxl, whose encoder uses it; the original standalone Google repository is archived.

Butteraugli is designed for the high-fidelity range. Its authors describe it as reliable “in the domain of barely noticeable differences”, tuned mostly around JPEG quality 90–95, and say they don’t know how well it handles major distortions. libjxl’s distance setting is defined as a target maximum Butteraugli distance, with 1.0 described as visually lossless, which gives a feel for the scale.

That makes it a good check when you are comparing high-quality or near-transparent encodes, alongside SSIMULACRA2, which covers a wider quality range. The correlation tables in the SSIMULACRA2 README show the split: on the near-threshold KonFiG-IQA set the Butteraugli 3-norm is among the best metrics, while on TID2013 and KADID-10k, which are full of heavy distortions, it does no better than PSNR. It is strict: Vship’s documentation notes that it rarely calls a frame good when it isn’t, but it does flag differences a typical viewer wouldn’t see. Like SSIMULACRA2 it is an image metric, so on video it scores frames independently.

The difference map has a value for every pixel, so a single score needs a pooling rule. Always say which one you report.

NormWhat it measuresWhere you see it
Max (∞-norm)The single worst spot in the imageFirst line of libjxl’s butteraugli_main; Vship _BUTTERAUGLI_INFNorm
3-normA mean over the whole map that weights larger errors more heavilySecond line of butteraugli_main (default --pnorm 3); Vship _BUTTERAUGLI_3Norm
q-normAny other p-norm you choosebutteraugli_main --pnorm; Vship qnorm (default 2), _BUTTERAUGLI_QNorm

The max norm is the classic Butteraugli score, but one bad block decides it, so it is noisy for comparing encodes. The 3-norm is the figure commonly used for comparisons, including the correlation tables in the SSIMULACRA2 README and Av1an’s butteraugli-3 target.

Butteraugli also assumes a display brightness, the intensity target in nits. A brighter display makes artifacts more visible and raises the distance. libjxl’s tool uses 80 nits for SDR input by default, while Vship uses 203 nits, so the two give different numbers for the same images unless you set the same value.

butteraugli_main is included in the libjxl release archives for Linux and Windows, next to ssimulacra2:

Terminal window
butteraugli_main reference.png distorted.png --distmap diff.png

It prints the max-norm distance, then the 3-norm. --distmap writes a heatmap of where the differences are; --pnorm and --intensity_target change the pooling and display brightness. Images without an embedded colour profile are read as sRGB.

Butteraugli is slow on a CPU, so for video most people use Vship on a GPU. With FFVship:

Terminal window
FFVship --source reference.mkv --encoded distorted.mkv -m Butteraugli --json butteraugli.json

FFVship prints the mean, percentiles, minimum and maximum for the 2-norm, 3-norm and max norm. The JSON holds [q-norm, 3-norm, max-norm] for every frame. --qnorm and --intensity-target change the extra norm and the display brightness.

In VapourSynth, run with python:

import vapoursynth as vs
core = vs.core
ref = core.bs.VideoSource("reference.mkv")
dist = core.bs.VideoSource("distorted.mkv")
clip = core.vship.BUTTERAUGLI(ref, dist)
d = sorted(f.props["_BUTTERAUGLI_3Norm"] for f in clip.frames())
print(f"3-norm mean {sum(d) / len(d):.3f} 95th percentile {d[len(d) * 19 // 20]:.3f} worst {d[-1]:.3f}")

Lower is better here, so the bad tail is the high end: report the mean, a high percentile and the worst frames. With distmap=1, core.vship.BUTTERAUGLI(ref, dist, distmap=1) returns a greyscale clip of the difference map that you can step through in a previewer to see where an encode falls apart. The old _BUTTERAUGLI_2Norm property is a deprecated alias of _BUTTERAUGLI_QNorm.

Both clips must have the same dimensions and frame count; scale the encode to the reference size first if needed. See Compare encoding quality for the rest of the workflow.