Skip to main content

Butteraugli

Help Wanted

This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!

Butteraugli is a perceptual distance metric that estimates the psychovisual similarity of two images. It is capable of outputting a heatmap containing differences between two input clips.

While a reference implementation by Google exists, most people will want to use the HIP/CUDA implementation vship.
Vship is intended for use in Vapoursynth scripts or as a standalone CLI tool without Vapoursynth and runs on GPU (Nvidia and AMD Radeon).

Installing​

The Release page of the repository provides up-to-date binaries for Windows users.

To compile Vship, follow the instructions on the repository.

Running​

Using the standalone FFVship library​

usage: ./FFVship [-h] [--source SOURCE] [--encoded ENCODED]
[-m {SSIMULACRA2, Butteraugli}]
[--start start] [--end end] [-e --every every]
[-t THREADS] [-g gpuThreads] [--gpu-id gpu_id]
[--json OUTPUT]
[--list-gpu]
Specific to Butteraugli:
[--intensity-target Intensity(nits)]

In Vapoursynth scripts​

Example script:

import vapoursynth as vs
core = vs.core

# Load reference and distorted clips
ref = core.bs.VideoSource("reference.mp4")
dist = core.bs.VideoSource("distorted.mp4")

# Calculate Butteraugli scores
# intensity_multiplier controls sensitivity
result = ref.vship.BUTTERAUGLI(dist, distmap=0, numStream = 4)

# Extract scores from frame properties (three different norms available)
scores_2norm = [frame.props["_BUTTERAUGLI_2Norm"] for frame in result.frames()]
scores_3norm = [frame.props["_BUTTERAUGLI_3Norm"] for frame in result.frames()]
scores_infnorm = [frame.props["_BUTTERAUGLI_INFNorm"] for frame in result.frames()]

# Get all scores in one pass
all_scores = [[frame.props["_BUTTERAUGLI_2Norm"],
frame.props["_BUTTERAUGLI_3Norm"],
frame.props["_BUTTERAUGLI_INFNorm"]]
for frame in result.frames()]

# Print average scores
print(f"Average Butteraugli 3Norm distance: {sum(scores_3norm) / len(scores_3norm)})
print(f"Average Butteraugli 2Norm distance: {sum(scores_2norm) / len(scores_2norm)})
print(f"Average Butteraugli MaxNorm distance: {sum(scores_infnorm) / len(scores_infnorm)})
Graphical visualization

You can optionally generate visual distortion maps with:

# Set distmap=1 to visualize distortion
distmap_result = ref.vship.BUTTERAUGLI(dist, distmap=1)

# The resulting clip is a grayscale visualization of distortions
distmap_result.set_output()

Scoring​

Butteraugli outputs score in the range 0..inf with lower being better (closer to the source). A score below 1.0 is usually considered very good.