Pujan-Dev's picture
feat: updated detector using Ela fft and meta
0b8f50d

Fast Fourier Transform (FFT) Detector

def run_fft(image: Image.Image, threshold: float = 0.92) -> bool:

Overview

The run_fft function performs a frequency domain analysis on an image using the Fast Fourier Transform (FFT) to detect possible AI generation or digital manipulation. It leverages the fact that artificially generated or heavily edited images often exhibit a distinct high-frequency pattern.


Parameters

Parameter Type Description
image PIL.Image.Image Input image to analyze. It will be converted to grayscale and resized.
threshold float Proportion threshold of high-frequency components to flag the image. Default is 0.92.

Returns

Type Description
bool True if image is likely AI-generated/manipulated; otherwise False.

Step-by-Step Explanation

1. Grayscale Conversion

All images are converted to grayscale:

gray_image = image.convert("L")

2. Resize

The image is resized to a fixed $512 \times 512$ for uniformity:

resized_image = gray_image.resize((512, 512))

3. FFT Calculation

Compute the 2D Discrete Fourier Transform:

F(u,v)=βˆ‘x=0Mβˆ’1βˆ‘y=0Nβˆ’1f(x,y)β‹…eβˆ’2Ο€i(uxM+vyN) F(u, v) = \sum_{x=0}^{M-1} \sum_{y=0}^{N-1} f(x, y) \cdot e^{-2\pi i \left( \frac{ux}{M} + \frac{vy}{N} \right)}

fft_result = fft2(image_array)

4. Shift Zero Frequency to Center

Use fftshift to center the zero-frequency component:

fft_shifted = fftshift(fft_result)

5. Magnitude Spectrum

∣F(u,v)∣=β„œ2+β„‘2 |F(u, v)| = \sqrt{\Re^2 + \Im^2}

magnitude_spectrum = np.abs(fft_shifted)

6. Normalization

Normalize the spectrum to avoid scale issues:

Normalized(u,v)=∣F(u,v)∣max⁑(∣F(u,v)∣) \text{Normalized}(u,v) = \frac{|F(u,v)|}{\max(|F(u,v)|)}

normalized_spectrum = magnitude_spectrum / max_magnitude

7. High-Frequency Detection

High-frequency components are defined as:

Mask(u,v)={1if Normalized(u,v)>0.50otherwise \text{Mask}(u,v) = \begin{cases} 1 & \text{if } \text{Normalized}(u,v) > 0.5 \\ 0 & \text{otherwise} \end{cases}

high_freq_mask = normalized_spectrum > 0.5

8. Proportion Calculation

Ratio=βˆ‘MaskTotal pixels \text{Ratio} = \frac{\sum \text{Mask}}{\text{Total pixels}}

high_freq_ratio = np.sum(high_freq_mask) / normalized_spectrum.size

9. Threshold Decision

If the ratio exceeds the threshold:

is_fake=(Ratio>Threshold) \text{is\_fake} = (\text{Ratio} > \text{Threshold})

is_fake = high_freq_ratio > threshold

it is implemented in the api

Running Locally

Just put the function in a notebook or script file and run it with your image. It works well for basic images.

Worked By

Pujan Neupane