CVVDP
37c3317fd058; modified for Encode Wiki · CC BY-SA 4.0ColorVideoVDP (CVVDP) is a full-reference visual difference predictor from the University of Cambridge, published at SIGGRAPH 2024. It models colour vision and spatial and temporal sensitivity together, and it takes the display and viewing conditions as input: size, resolution, viewing distance, peak brightness and room light. That makes it one of the few metrics that is genuinely video-aware and works for HDR.
Scores and when to use it
Section titled “Scores and when to use it”CVVDP reports quality in JOD (just-objectionable-difference) units. 10 means no visible difference from the reference; lower is worse, and very strong distortion can go below 0. A difference of 1 JOD means about 75% of viewers would pick the higher-scoring version.
Use it when motion, colour or HDR matter, or when you care about a particular kind of screen. It complements SSIMULACRA2 and Butteraugli, which score frames independently, and unlike VMAF, which has no HDR model, it handles HDR properly.
The score depends on the display model, so always say which one you used. The reference tool prints a line such as ColorVideoVDP v0.5.7, 37.84 [pix/deg], Lpeak=200, ... (standard_fhd) for exactly that purpose.
Run the reference implementation
Section titled “Run the reference implementation”The reference implementation is a Python/PyTorch package. Install PyTorch with CUDA support first if you have an NVIDIA GPU (on a CPU it works, but video is slow), plus FFmpeg for video input, then:
pip install cvvdpcvvdp --test distorted.mkv --ref reference.mkv --display standard_fhdIt prints the result as cvvdp=9.3584 [JOD]. Several --test files can be compared against one reference in one run.
| Option | Use |
|---|---|
--display NAME | Display and viewing model; --display '?' lists them |
--full-screen-resize bicubic | Scale both videos to the display’s resolution (video only) |
--heatmap threshold | Write a heatmap video of where differences are visible (supra-threshold for large ones) |
--distogram | Plot the differences per channel and per frame |
--result results.csv | Write scores to a CSV file |
--device cuda | Pick the PyTorch device (cpu, cuda, mps) |
Choose a display model
Section titled “Choose a display model”| Model | Display and viewing conditions |
|---|---|
standard_fhd | 24-inch 1080p monitor, 200 cd/m², office lighting, 2× display height |
standard_4k | 30-inch 4K monitor, 200 cd/m², office lighting, 2× display height |
standard_hdr_pq | 30-inch 4K HDR monitor, 1500 cd/m², dim room, PQ input |
standard_hdr_hlg | As above, HLG input |
standard_hdr_linear | As above, for linear OpenEXR images in absolute units |
standard_phone | 6-inch 2400×1080 phone, 500 cd/m², office lighting, 40 cm away |
The display model also sets how the input is decoded, so HDR video must use standard_hdr_pq or standard_hdr_hlg. For your own screen, copy display_models.json, add an entry, and pass its folder with --config-paths.
Run it with Vship
Section titled “Run it with Vship”Vship has a faster GPU implementation. With FFVship:
FFVship --source reference.mkv --encoded distorted.mkv -m CVVDP --displayModel standard_fhd--resizeToDisplay does the same job as --full-screen-resize. In VapourSynth, core.vship.CVVDP(ref, dist, model_name="standard_fhd") stores a _CVVDP score on every frame, but the score on frame i covers frames 0 to i: request the frames in order and use the last one as the video’s score.
Vship uses the same names for the standard displays (standard_fhd, standard_4k, standard_hdr_pq, standard_hdr_hlg), and its scores are close to, but not identical with, the reference implementation’s. fcvvdp is a separate C implementation for CPUs. Use one implementation throughout a comparison, and note its version, since bug fixes have changed CVVDP scores in both Vship and the reference package.
How it works
Section titled “How it works”- The display model converts the input to absolute light, including black level and reflected room light.
- Colour is converted to an opponent space with one achromatic and two chromatic channels.
- Temporal filters split the signal into sustained channels and a transient (flicker and motion) luminance channel.
- A multi-scale pyramid splits each channel into spatial frequency bands, and contrast in each band is weighted by a contrast sensitivity model (castleCSF) that depends on frequency, luminance and colour.
- Visual masking reduces the weight of differences in busy areas, then the differences are pooled over space, bands, channels and time and mapped to JOD.
Details are in the paper and the project page.