Highlight Video Differences Using FFmpeg lut2
This article explains how to visual inspect and highlight pixel-level
differences between two similar video files using FFmpeg's powerful
lut2 filter. You will learn the mechanics behind the
dual-input lookup table, the command-line syntax required to compute
differences, and techniques to amplify subtle compression artifacts or
color shifts so they become clearly visible.
Understanding the
lut2 Filter
The lut2 filter takes two video inputs of the exact same
dimensions and pixel format, evaluates an expression for each
corresponding pixel component, and outputs a single composite video.
In lut2 expressions:
xrepresents the pixel value from the first input (stream 0).yrepresents the pixel value from the second input (stream 1).c0,c1,c2, andc3correspond to each plane of the video format (e.g., Y, U, V in YUV, or R, G, B in RGB).
To highlight differences, you compute the absolute difference between
x and y using the mathematical function
abs(x-y).
Basic Difference Command (RGB Space)
When comparing two videos in the RGB color space, calculate the absolute difference across all three color channels:
ffmpeg -i original.mp4 -i encoded.mp4 -filter_complex \
"[0:v]format=rgb24[v0]; \
[1:v]format=rgb24[v1]; \
[v0][v1]lut2=c0='abs(x-y)':c1='abs(x-y)':c2='abs(x-y)'" \
-c:v libx264 -crf 18 diff.mp4In this output:
- Identical pixels result in
0(completely black). - Differing pixels appear brighter depending on the magnitude of the discrepancy.
Amplifying Subtle Differences
Compression artifacts or minor color grades often result in
differences of only 1 to 5 values per pixel, which are almost invisible
to the human eye on a standard monitor. To make these variations
immediately apparent, multiply the difference by an amplification factor
(for example, 10 or 20):
ffmpeg -i original.mp4 -i encoded.mp4 -filter_complex \
"[0:v]format=rgb24[v0]; \
[1:v]format=rgb24[v1]; \
[v0][v1]lut2=c0='clip(abs(x-y)*10,0,255)':c1='clip(abs(x-y)*10,0,255)':c2='clip(abs(x-y)*10,0,255)'" \
-c:v libx264 -crf 18 amplified_diff.mp4The clip(val, min, max) function prevents values from
overflowing beyond standard 8-bit limits (0 to
255).
Highlighting Differences in YUV Space
If you want to keep the process in standard YUV video format (such as
yuv420p), evaluate luminance (Y) and chrominance (U/V)
independently.
For standard 8-bit YUV:
- Luma (Y /
c0) ranges from 0 to 255. - Chroma (U /
c1, V /c2) centers at 128 (neutral/gray).
To show luma differences on a neutral gray canvas:
ffmpeg -i original.mp4 -i encoded.mp4 -filter_complex \
"[0:v][1:v]lut2=c0='clip(abs(x-y)*10,0,255)':c1='128':c2='128'" \
-c:v libx264 -crf 18 yuv_diff.mp4Binary Masking (Thresholding)
If you only want to know whether a difference exists regardless of magnitude, apply a threshold condition:
ffmpeg -i original.mp4 -i encoded.mp4 -filter_complex \
"[0:v]format=rgb24[v0]; \
[1:v]format=rgb24[v1]; \
[v0][v1]lut2=c0='if(gt(abs(x-y),2),255,0)':c1='if(gt(abs(x-y),2),255,0)':c2='if(gt(abs(x-y),2),255,0)'" \
-c:v libx264 -crf 18 mask_diff.mp4This expression evaluates whether the absolute difference between
x and y is greater than 2. If
true, it outputs full white (255); otherwise, it outputs
full black (0).