ai-detect / frequency_analysis.py
maddyrox's picture
Upload 23 files
d3e1b7a verified
import numpy as np
import numpy as np
from PIL import Image, ImageFilter, ImageOps
import io
import base64
class FrequencyAnalyzer:
def __init__(self):
pass
def generate_spectrum(self, image: Image.Image) -> str:
"""
Generates a 2D Frequency Spectrum (Magnitude Plot) from a PIL Image.
Returns a base64 encoded PNG string of the spectrum.
"""
try:
# 1. Convert to Grayscale
img_gray = image.convert('L')
# 2. Convert to Numpy Array
img_array = np.array(img_gray)
# 3. Compute FFT (Fast Fourier Transform)
# f = np.fft.fft2(img_array)
# fshift = np.fft.fftshift(f)
# magnitude_spectrum = 20 * np.log(np.abs(fshift))
# Use a slightly more robust method for visualization
f = np.fft.fft2(img_array)
fshift = np.fft.fftshift(f)
# Add epsilon to avoid log(0)
magnitude_spectrum = 20 * np.log(np.abs(fshift) + 1e-9)
# 4. Normalize to 0-255 for standard image display
mag_min = magnitude_spectrum.min()
mag_max = magnitude_spectrum.max()
# Avoid division by zero if image is blank
if mag_max == mag_min:
normalized = np.zeros_like(magnitude_spectrum, dtype=np.uint8)
else:
normalized = 255 * (magnitude_spectrum - mag_min) / (mag_max - mag_min)
normalized = np.uint8(normalized)
# 5. Convert back to PIL Image
spectrum_img = Image.fromarray(normalized)
# 6. Encode to Base64
buffered = io.BytesIO()
spectrum_img.save(buffered, format="PNG")
img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
return img_str
except Exception as e:
print(f"Error generating frequency spectrum: {e}")
return ""
def generate_pattern_map(self, image: Image.Image) -> str:
"""
Generates a Noise Pattern Map (High-Pass/Laplacian) to visualize
checkerboard artifacts.
"""
try:
# 1. Convert to Grayscale
img_gray = image.convert('L')
# 2. Apply Laplacian Filter (High-Pass)
# This removes smooth areas and keeps edges/noise
noise_map = img_gray.filter(ImageFilter.FIND_EDGES)
# Note: FIND_EDGES is a simple approximation. For better grid visualization,
# we can use a Kernel, but this is usually sufficient for "seeing" the grid.
# 3. Invert to make lines black on white (easier to see)
# noise_map = ImageOps.invert(noise_map)
# Actually, white on black (default) effectively shows the "glowing" grid lines.
# 4. Enhance Contrast/Brightness to make faint artifacts visible
# We convert to numpy to scale
arr = np.array(noise_map).astype(float)
# Amplify
arr = arr * 5.0 # Boost signal
arr = np.clip(arr, 0, 255).astype(np.uint8)
enhanced_map = Image.fromarray(arr)
# 5. Encode
buffered = io.BytesIO()
enhanced_map.save(buffered, format="PNG")
img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
return img_str
except Exception as e:
print(f"Error generating pattern map: {e}")
return ""