# Butteraugli

Canonical URL: https://encode.wiki/reference/metrics/butteraugli/
Content version: ca42e61ede0a24f789d7287a0001244ad22f4abf
Status: current
License: CC BY-SA 4.0
Checksum (SHA-256): a4fe05c8c1579a4e011f203087bbfdbb0b3fe0ddce4e0aee0c058c6001c9cb94

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](https://github.com/libjxl/libjxl), whose encoder uses it; the original standalone Google repository is archived.

## What it is good for

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](/reference/metrics/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.

## Distance and norms

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

| Norm         | What it measures                                                       | Where you see it                                                                    |
| ------------ | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| Max (∞-norm) | The single worst spot in the image                                     | First line of libjxl's `butteraugli_main`; Vship `_BUTTERAUGLI_INFNorm`             |
| 3-norm       | A mean over the whole map that weights larger errors more heavily      | Second line of `butteraugli_main` (default `--pnorm 3`); Vship `_BUTTERAUGLI_3Norm` |
| q-norm       | Any other p-norm you choose                                            | `butteraugli_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.

## Score images

`butteraugli_main` is included in the [libjxl release archives](https://github.com/libjxl/libjxl/releases) for Linux and Windows, next to `ssimulacra2`:

```sh
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.

## Score video

Butteraugli is slow on a CPU, so for video most people use [Vship](/tools/utilities/vship/) on a GPU. With FFVship:

```sh
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`:

```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](/guides/compare-encoding-quality/) for the rest of the workflow.
