butteraugli
Pure Rust implementation of Google's butteraugli perceptual image quality metric from libjxl.
What is Butteraugli?
Butteraugli estimates the perceived difference between two images using a model of human vision. Unlike simple pixel-wise metrics (PSNR, MSE), butteraugli accounts for:
- Opsin dynamics: Photosensitive chemical responses in the retina
- XYB color space: Hybrid opponent/trichromatic representation
- Visual masking: How image features hide or reveal differences
- Multi-scale analysis: UHF, HF, MF, LF frequency bands
Quality Thresholds
| Score | Interpretation |
|---|---|
| < 1.0 | Images appear identical to most viewers |
| 1.0 - 2.0 | Subtle differences may be noticeable |
| > 2.0 | Visible differences between images |
Command-Line Tool
Usage
# Compare two images
# Output: Butteraugli score: 1.2345
# Quality rating
# JSON output
# Save difference heatmap
# Just the score
Options
Library Usage
[]
= "0.4"
Input Formats
| Function | Input Type | Color Space | Use Case |
|---|---|---|---|
butteraugli |
ImgRef<RGB8> |
sRGB (gamma-encoded) | Standard 8-bit images |
butteraugli_linear |
ImgRef<RGB<f32>> |
Linear RGB (0.0-1.0) | HDR, 16-bit, float pipelines |
Both APIs support stride (padding) and require minimum 8x8 images.
Example
use ;
let original: = load_image;
let compressed: = load_compressed;
let img1 = new;
let img2 = new;
let result = butteraugli?;
println!;
Difference Map
let params = default.with_compute_diffmap;
let result = butteraugli?;
if let Some = result.diffmap
Custom Parameters
let params = new
.with_hf_asymmetry // Penalize artifacts > blur
.with_intensity_target // HDR display (nits)
.with_compute_diffmap;
Features
cli: Command-line tool (addsclap,image,serde_json)internals: Expose internal modules for testing/benchmarking (unstable API)
Performance
SIMD-optimized via wide with runtime dispatch to the best available instruction set:
| Target | CPU Support |
|---|---|
| x86-64-v4 | AVX-512 (Skylake-X, Zen 4+) |
| x86-64-v3 | AVX2/FMA (Haswell+, Zen 1+) |
| x86-64-v2 | SSE4.2 (Nehalem+) |
| ARM64 | NEON (Apple Silicon, Cortex-A75+) |
100% safe Rust with no C dependencies.
Accuracy
Validated against C++ libjxl butteraugli via FFI bindings:
| Test Type | Difference |
|---|---|
| sRGB/linear conversion | Exact |
| Gamma function | Exact |
| Frequency bands | <0.01% |
| Real images | ~1-2% |
| Uniform/checkerboard | <0.1% |
| Gradient patterns | ~0.3% |
Reference Tests: 185 passed, 6 failed (20% tolerance)
Six edge cases with blur distortions show ~20-32% divergence, but these don't affect typical image comparisons.
API Comparison with C++ libjxl
| Feature | C++ butteraugli | This crate |
|---|---|---|
| Input format | Linear RGB float | sRGB u8 or linear RGB f32 |
| Color space | Linear RGB only | sRGB (auto-converted) or linear |
| Channel layout | Planar | Interleaved RGB via imgref |
| Stride support | Manual | Built-in via ImgRef::new_stride() |
XYB Note
Butteraugli's internal XYB differs from jpegli's XYB (different nonlinearity, matrix coefficients, and formulas). Always provide RGB input; butteraugli handles the conversion internally.
References
Development
AI-Generated Code Notice
Developed with Claude (Anthropic). Tested against C++ libjxl with ~1-2% difference for real images. Review critical paths before production use.
License
BSD-3-Clause (same as libjxl)