FFmpeg fftfilt Custom Expression for High-Pass Filter

This article explains how to configure the fftfilt (Fast Fourier Transform) filter in FFmpeg to function as a custom high-pass image filter. By utilizing custom math expressions within the frequency domain, you can isolate high-frequency details, such as edges and fine textures, while attenuating low-frequency background information in videos or images.

To create a high-pass filter using the fftfilt filter, you must define an expression for the luma weight parameter (weight_Y). In the frequency domain representation used by FFmpeg, the low-frequency (DC) components are located at the corners of the transform block, while high-frequency components are located toward the center.

The Ideal High-Pass Filter Expression

An ideal high-pass filter blocks all frequencies below a certain threshold radius and passes all frequencies above it. The following FFmpeg command applies a sharp high-pass filter with a cutoff radius of 15 pixels:

ffmpeg -i input.png -vf "fftfilt=dc_Y=0:weight_Y='gt(sqrt(pow(min(X,W-X),2)+pow(min(Y,H-Y),2)), 15)'" output.png

How the Expression Works

  • dc_Y=0: This setting zeroes out the DC coefficient of the Y (luminance) channel. The DC coefficient represents the average brightness of the block. Setting it to 0 removes the overall brightness, leaving only the directional changes (edges).
  • min(X, W-X) and min(Y, H-Y): Because the 2D Fourier Transform is periodic, the low frequencies are centered at the four corners of the block. These expressions measure the shortest distance from the current coordinate (X, Y) to the nearest corner of the block of width W and height H.
  • sqrt(pow(..., 2) + pow(..., 2)): This calculates the Euclidean distance of the current frequency coefficient from the nearest low-frequency origin.
  • gt(..., 15): The "greater than" function acts as a threshold. If the distance (frequency) is greater than 15, the expression returns 1 (allowing the frequency to pass). If it is less than or equal to 15, it returns 0 (blocking the frequency).

Gaussian High-Pass Filter for Smoother Results

Sharp threshold filters can introduce unwanted "ringing" artifacts around edges. To prevent this, you can use a Gaussian high-pass filter, which smoothly transitions from blocking low frequencies to passing high frequencies.

The mathematical expression for a Gaussian high-pass filter is:

\[\text{Weight} = 1 - e^{-\frac{d^2}{2\sigma^2}}\]

Where \(d\) is the frequency distance and \(\sigma\) (sigma) is the cutoff frequency. In FFmpeg, this is written as:

ffmpeg -i input.png -vf "fftfilt=dc_Y=0:weight_Y='1-exp(-(pow(min(X,W-X),2)+pow(min(Y,H-Y),2))/(2*pow(10,2)))'" output.png

In this command, pow(10,2) represents a \(\sigma\) value of 10. Increasing this value will block more low-frequency data, resulting in a harsher high-pass effect that only preserves the sharpest edges. Decreasing it will allow mid-range frequencies to pass, preserving more of the original image structure.