Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -2,132 +2,80 @@ import gradio as gr
|
|
| 2 |
from transformers import pipeline
|
| 3 |
from PIL import Image, ExifTags
|
| 4 |
import numpy as np
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
#
|
| 7 |
-
detector = pipeline("image-classification", model="
|
| 8 |
-
general = pipeline("image-classification", model="google/vit-base-patch16-224")
|
| 9 |
-
|
| 10 |
-
# --- Analisis tambahan ---
|
| 11 |
-
|
| 12 |
-
def estimate_blur(img):
|
| 13 |
-
gray = img.convert("L")
|
| 14 |
-
arr = np.array(gray)
|
| 15 |
-
gx, gy = np.gradient(arr)
|
| 16 |
-
return np.var(gx + gy)
|
| 17 |
|
|
|
|
| 18 |
def estimate_noise(img):
|
| 19 |
-
gray =
|
| 20 |
-
|
| 21 |
-
return np.var(arr - np.mean(arr))
|
| 22 |
-
|
| 23 |
-
def jpeg_artifacts(img):
|
| 24 |
-
# konversi ke numpy
|
| 25 |
-
arr = np.array(img.convert("L"))
|
| 26 |
-
# ambil perbedaan antar piksel
|
| 27 |
-
diff = np.abs(arr[:, 1:] - arr[:, :-1])
|
| 28 |
-
return np.mean(diff)
|
| 29 |
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
arr = np.array(gray)
|
| 33 |
-
gx, gy = np.gradient(arr)
|
| 34 |
-
edges = np.sqrt(gx**2 + gy**2)
|
| 35 |
-
return np.std(edges)
|
| 36 |
-
|
| 37 |
-
def has_exif(img):
|
| 38 |
try:
|
| 39 |
-
|
| 40 |
-
if
|
| 41 |
-
|
| 42 |
-
|
|
|
|
|
|
|
| 43 |
except:
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
# --- Penyesuaian AI score ---
|
| 47 |
-
def adjust_ai_score(img, ai_score):
|
| 48 |
-
blur = estimate_blur(img)
|
| 49 |
-
noise = estimate_noise(img)
|
| 50 |
-
jpeg = jpeg_artifacts(img)
|
| 51 |
-
edge_std = edge_inconsistency(img)
|
| 52 |
-
has_meta, meta = has_exif(img)
|
| 53 |
-
|
| 54 |
-
adjustment = 0
|
| 55 |
-
|
| 56 |
-
# Metadata kamera sangat penting
|
| 57 |
-
if not has_meta:
|
| 58 |
-
adjustment += 15
|
| 59 |
-
|
| 60 |
-
# Blur terlalu kecil → terlalu tajam → AI photorealistic
|
| 61 |
-
if blur < 80:
|
| 62 |
-
adjustment += 10
|
| 63 |
-
|
| 64 |
-
# Noise terlalu rendah → gambar terlalu bersih → AI
|
| 65 |
-
if noise < 50:
|
| 66 |
-
adjustment += 10
|
| 67 |
-
|
| 68 |
-
# JPEG artifact rendah → AI cenderung hasil render
|
| 69 |
-
if jpeg < 5:
|
| 70 |
-
adjustment += 10
|
| 71 |
-
|
| 72 |
-
# Edge terlalu konsisten → AI
|
| 73 |
-
if edge_std < 20:
|
| 74 |
-
adjustment += 10
|
| 75 |
|
| 76 |
-
|
| 77 |
-
return ai_score, blur, noise, jpeg, edge_std, has_meta
|
| 78 |
-
|
| 79 |
-
# --- Deteksi utama ---
|
| 80 |
def detect_image(img):
|
| 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 |
-
iface = gr.Interface(
|
| 125 |
fn=detect_image,
|
| 126 |
inputs=gr.Image(type="pil"),
|
| 127 |
-
outputs="
|
| 128 |
-
title="
|
| 129 |
-
description="Detektor gratis untuk membedakan foto asli vs AI photorealistic. Memakai model HuggingFace + analisis metadata kamera, blur, noise, artefak JPEG, dan pola tepi."
|
| 130 |
)
|
| 131 |
|
| 132 |
if __name__ == "__main__":
|
| 133 |
-
|
|
|
|
| 2 |
from transformers import pipeline
|
| 3 |
from PIL import Image, ExifTags
|
| 4 |
import numpy as np
|
| 5 |
+
import cv2
|
| 6 |
+
import io
|
| 7 |
|
| 8 |
+
# 1. Load model AI detector dari HuggingFace
|
| 9 |
+
detector = pipeline("image-classification", model="microsoft/resnet-50")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
+
# Fungsi hitung noise (variansi Laplacian)
|
| 12 |
def estimate_noise(img):
|
| 13 |
+
gray = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2GRAY)
|
| 14 |
+
return cv2.Laplacian(gray, cv2.CV_64F).var()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
+
# Fungsi cek metadata kamera
|
| 17 |
+
def has_camera_metadata(img):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
try:
|
| 19 |
+
exif = img._getexif()
|
| 20 |
+
if exif is not None:
|
| 21 |
+
for tag, value in exif.items():
|
| 22 |
+
tag_name = ExifTags.TAGS.get(tag, tag)
|
| 23 |
+
if "Model" in tag_name or "Make" in tag_name:
|
| 24 |
+
return True
|
| 25 |
except:
|
| 26 |
+
pass
|
| 27 |
+
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
+
# Fungsi utama deteksi hybrid
|
|
|
|
|
|
|
|
|
|
| 30 |
def detect_image(img):
|
| 31 |
+
# Resize ke 224x224 untuk model
|
| 32 |
+
img_resized = img.resize((224,224))
|
| 33 |
+
|
| 34 |
+
# Prediksi AI-detector HuggingFace
|
| 35 |
+
preds = detector(img_resized)
|
| 36 |
+
ai_score = 0
|
| 37 |
+
for p in preds:
|
| 38 |
+
if "artificial" in p['label'].lower() or "fake" in p['label'].lower():
|
| 39 |
+
ai_score += p['score'] * 100
|
| 40 |
+
elif "human" in p['label'].lower() or "real" in p['label'].lower():
|
| 41 |
+
ai_score += (1 - p['score']) * 100
|
| 42 |
+
|
| 43 |
+
ai_score = max(0, min(100, ai_score)) # jaga range
|
| 44 |
+
real_score = 100 - ai_score
|
| 45 |
+
|
| 46 |
+
# Hybrid Adjustment
|
| 47 |
+
# 1. Metadata kamera → tambah bobot real
|
| 48 |
+
if has_camera_metadata(img):
|
| 49 |
+
real_score += 30
|
| 50 |
+
ai_score -= 30
|
| 51 |
+
|
| 52 |
+
# 2. Noise → kalau noise tinggi berarti asli
|
| 53 |
+
noise = estimate_noise(img)
|
| 54 |
+
if noise > 500: # ambang noise
|
| 55 |
+
real_score += 20
|
| 56 |
+
ai_score -= 20
|
| 57 |
+
|
| 58 |
+
# Normalisasi agar tetap 0-100
|
| 59 |
+
real_score = max(0, min(100, real_score))
|
| 60 |
+
ai_score = 100 - real_score
|
| 61 |
+
|
| 62 |
+
# Final Output
|
| 63 |
+
if real_score == 100:
|
| 64 |
+
label = "🖼️ Gambar ini ASLI 100%"
|
| 65 |
+
elif ai_score == 100:
|
| 66 |
+
label = "🖼️ Gambar ini HASIL AI 100%"
|
| 67 |
+
else:
|
| 68 |
+
label = f"🖼️ Gambar ini {ai_score:.2f}% AI / {real_score:.2f}% Asli"
|
| 69 |
+
|
| 70 |
+
return label, f"Noise Score: {noise:.2f} | Metadata Kamera: {'Ada' if has_camera_metadata(img) else 'Tidak'}"
|
| 71 |
+
|
| 72 |
+
# Gradio UI
|
| 73 |
+
demo = gr.Interface(
|
|
|
|
| 74 |
fn=detect_image,
|
| 75 |
inputs=gr.Image(type="pil"),
|
| 76 |
+
outputs=[gr.Textbox(label="Hasil Deteksi"), gr.Textbox(label="Analisis Teknis")],
|
| 77 |
+
title="Hybrid AI vs Real Image Detector"
|
|
|
|
| 78 |
)
|
| 79 |
|
| 80 |
if __name__ == "__main__":
|
| 81 |
+
demo.launch()
|