Spaces:
Sleeping
Sleeping
File size: 5,383 Bytes
b1f86ad 3d0e83d b1f86ad 3d0e83d b1f86ad 3d0e83d b1f86ad 3d0e83d b1f86ad 3d0e83d b1f86ad 3d0e83d 07bc192 b1f86ad 3d0e83d b1f86ad 3d0e83d 07bc192 b1f86ad 3d0e83d b1f86ad 3d0e83d b1f86ad 3d0e83d b1f86ad 3d0e83d b1f86ad 3d0e83d 07bc192 3d0e83d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | import io
import cv2
import numpy as np
import torch
from PIL import Image
import spaces
from transformers import AutoImageProcessor, AutoModelForImageClassification
import gradio as gr
# 1. Inisialisasi Model & Processor
RESNET_MODEL_ID = "prithivMLmods/Deep-Fake-Detector-Model"
print(f"[*] Inisialisasi arsitektur forensik: {RESNET_MODEL_ID}")
processor = AutoImageProcessor.from_pretrained(RESNET_MODEL_ID)
resnet_model = AutoModelForImageClassification.from_pretrained(RESNET_MODEL_ID).eval()
# 2. Analisis Spektral 2D FFT (CPU)
def analyze_phase_spectrum(img_pil: Image.Image) -> float:
gray_img = img_pil.convert("L")
w, h = gray_img.size
crop_size = 256
if w >= crop_size and h >= crop_size:
left = (w - crop_size) // 2
top = (h - crop_size) // 2
gray_crop = gray_img.crop((left, top, left + crop_size, top + crop_size))
gray = np.array(gray_crop, dtype=np.float32) / 255.0
else:
gray = np.array(gray_img.resize((256, 256)), dtype=np.float32) / 255.0
f = np.fft.fft2(gray)
fshift = np.fft.fftshift(f)
mag = np.abs(fshift)
cy, cx = 128, 128
y, x = np.ogrid[:256, :256]
low_freq_mask = ((x - cx)**2 + (y - cy)**2) <= (32**2)
low_energy = float(np.mean(mag[low_freq_mask]) + 1e-5)
high_energy = float(np.mean(mag[~low_freq_mask]) + 1e-5)
spectral_ratio = high_energy / low_energy
score = 1.0 / (1.0 + np.exp(-40.0 * (spectral_ratio - 0.045)))
return float(np.clip(score, 0.05, 0.95))
# 3. Pipeline Forensik Lengkap (Terdaftar Langsung di ZeroGPU)
@spaces.GPU
def predict_forensic(input_image):
if input_image is None:
return {
"verdict": "INCONCLUSIVE",
"calibrated_confidence": 0.0,
"reason": "Payload gambar kosong."
}
pil_img = Image.fromarray(input_image).convert("RGB")
# Profiler Degradasi
gray_np = np.array(pil_img.convert("L"))
laplacian_var = float(cv2.Laplacian(gray_np, cv2.CV_64F).var())
w, h = pil_img.size
is_downscaled = bool((w * h) < (720 * 1280))
quality_score = float(np.clip(laplacian_var / 100.0, 0.05, 1.0))
if laplacian_var < 5.0 or (laplacian_var < 35.0 and is_downscaled):
return {
"verdict": "INCONCLUSIVE",
"calibrated_confidence": 0.50,
"reason": "Severe physical degradation outside safe forensic envelope.",
"metrics": {"sharpness": round(laplacian_var, 2), "dimensions": f"{w}x{h}", "quality": quality_score}
}
# Inferensi Akselerasi ZeroGPU (A100)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
resnet_model.to(device)
inputs = processor(images=pil_img, return_tensors="pt").to(device)
with torch.inference_mode():
outputs = resnet_model(**inputs)
probs = torch.softmax(outputs.logits, dim=-1)[0]
prob_real = float(probs[0].item())
score_visual = float(np.clip(1.0 - prob_real, 0.01, 0.99))
score_phase = analyze_phase_spectrum(pil_img)
# Kalibrasi Fusi Bukti
w_visual = max(0.4, 0.8 * quality_score)
w_phase = 0.2
combined_score = (score_visual * w_visual + score_phase * w_phase) / (w_visual + w_phase)
disagreement = abs(score_visual - score_phase)
if combined_score <= 0.35 and score_visual < 0.15:
verdict = "LIKELY NATURAL CAPTURE"
confidence = round(1.0 - combined_score, 3)
reason = "Optical sensor texture and visual residuals indicate natural capture."
elif disagreement > 0.55 and quality_score < 0.25 and combined_score > 0.35:
verdict = "INCONCLUSIVE"
confidence = 0.50
reason = "Visual channel and spectral phase exhibit acute divergence under heavy compression."
elif combined_score >= 0.55:
verdict = "LIKELY AI-GENERATED"
confidence = round(min(combined_score, 0.70 + (0.28 * quality_score)), 3)
reason = "Forensic visual patterns and high-frequency spectral phase reflect synthetic artifacts."
elif combined_score <= 0.45:
verdict = "LIKELY NATURAL CAPTURE"
confidence = round(1.0 - combined_score, 3)
reason = "Visual features and phase distributions remain consistent with standard optical capture."
else:
verdict = "INCONCLUSIVE"
confidence = 0.50
reason = "Technical ambiguity margin (0.45 - 0.55)."
return {
"verdict": verdict,
"calibrated_confidence": round(confidence, 3),
"reason": reason,
"metrics": {
"dimensions": f"{w}x{h}",
"sharpness": round(laplacian_var, 2),
"quality_index": round(quality_score, 2),
"score_visual": round(score_visual, 3),
"score_phase": round(score_phase, 3),
"combined_score": round(combined_score, 3)
}
}
# 4. Antarmuka Gradio Resmi (Memenuhi Spesifikasi ZeroGPU HF)
with gr.Blocks(title="SecurePixel Engine") as demo:
gr.Markdown("# 🛡️ SecurePixel Forensics Engine (ZeroGPU)")
with gr.Row():
image_input = gr.Image(type="numpy", label="Input Frame")
result_output = gr.JSON(label="Forensic Result")
btn_predict = gr.Button("Analyze Frame", variant="primary")
btn_predict.click(
fn=predict_forensic,
inputs=image_input,
outputs=result_output,
api_name="predict"
)
demo.launch() |