ethix's picture
Initial commit for XAI Space
ebcb290
Raw
History Blame Contribute Delete
2.51 kB
"""
Unified runner for classic digital forensics tools.
Wraps ELA, Spatial Gradient, Bit Plane, MinMax Deviation, and Wavelet Noise.
"""
import time
import numpy as np
from PIL import Image
from .ela import ELA
from .gradient import gradient_processing
from .bitplane import bit_plane_extractor
from .minmax import minmax_process
from .wavelet import noise_estimation
from xai_engine.viz import to_b64_png
def run_forensic_tool(
image: Image.Image,
tool_name: str,
quality: int = 75,
scale: int = 50,
contrast: int = 20,
gradient_intensity: int = 90,
blue_mode: str = "Abs",
channel: str = "Luminance",
bit: int = 0,
minmax_radius: int = 2,
) -> dict:
"""
Execute selected forensic tool on input image.
Returns dict: {
"tool": str,
"result_b64": str,
"info": str,
"compute_time_ms": float
}
"""
t0 = time.perf_counter()
img_np = np.array(image.convert("RGB"))
info_text = ""
if tool_name == "ela":
name = "Error Level Analysis (ELA)"
res_img = ELA(img_np, quality=quality, scale=scale, contrast=contrast)
info_text = f"JPEG Compression Quality: {quality}%, Scale: {scale}, Contrast: {contrast}%"
elif tool_name == "gradient":
name = "Spatial Gradient Analysis"
res_img = gradient_processing(image, intensity=gradient_intensity, blue_mode=blue_mode)
info_text = f"Gradient Intensity: {gradient_intensity}%, Blue Mode: {blue_mode}"
elif tool_name == "bitplane":
name = "Bit Plane Extractor"
res_img = bit_plane_extractor(image, channel=channel, bit=bit)
info_text = f"Channel: {channel}, Bit Plane: {bit} (0=LSB, 7=MSB)"
elif tool_name == "minmax":
name = "MinMax Local Deviation"
res_img = minmax_process(img_np, channel=4, radius=minmax_radius)
info_text = f"Local Block Radius: {minmax_radius} px"
elif tool_name == "wavelet":
name = "Wavelet Noise Estimation"
noise_var = noise_estimation(img_np)
info_text = f"Estimated High-Frequency Noise Variance: {noise_var:.4f}"
res_img = image.convert("RGB") # Return original with overlay text or noise metric
else:
raise ValueError(f"Unknown forensic tool: {tool_name}")
elapsed_ms = (time.perf_counter() - t0) * 1000
return {
"tool": name,
"result_b64": to_b64_png(res_img),
"info": info_text,
"compute_time_ms": round(elapsed_ms, 1),
}