File size: 3,339 Bytes
3a2cd79
 
 
 
 
 
 
 
 
fac7f40
3a2cd79
fac7f40
3a2cd79
 
 
 
 
fac7f40
3a2cd79
 
 
 
 
 
 
fac7f40
 
3a2cd79
 
 
 
 
 
 
 
 
 
 
 
 
eaa1a24
eb801fa
 
eaa1a24
3a2cd79
eb801fa
fac7f40
3a2cd79
 
 
 
 
 
 
 
 
eaa1a24
eb801fa
fac7f40
 
3a2cd79
 
 
fac7f40
3a2cd79
fac7f40
3a2cd79
 
 
 
 
 
 
 
 
 
fac7f40
3a2cd79
 
 
 
fac7f40
3a2cd79
 
 
 
 
fac7f40
3a2cd79
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
import gradio as gr
import numpy as np
import cv2
import tensorflow as tf
from tensorflow.keras.models import load_model, Model
from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.applications.xception import preprocess_input as xcp_pre
from tensorflow.keras.applications.efficientnet import preprocess_input as eff_pre
from huggingface_hub import hf_hub_download
from PIL import Image

# Load models from Hugging Face Hub
xcp_path = hf_hub_download(repo_id="Zeyadd-Mostaffa/deepfake-image-detector", filename="xception_model.h5")
eff_path = hf_hub_download(repo_id="Zeyadd-Mostaffa/deepfake-image-detector", filename="efficientnet_model.h5")
xcp_model = load_model(xcp_path)
eff_model = load_model(eff_path)

# Face detection using OpenCV
def detect_face_opencv(pil_image):
    cv_img = np.array(pil_image.convert("RGB"))
    cv_img = cv_img[:, :, ::-1]  # RGB to BGR
    face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
    gray = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=4)
    if len(faces) == 0:
        return pil_image  # fallback to original
    (x, y, w, h) = max(faces, key=lambda b: b[2]*b[3])
    return pil_image.crop((x, y, x+w, y+h))

def grad_cam(model, img, size, preprocess_func):
    img_resized = img.resize(size)
    x = img_to_array(img_resized)
    x = np.expand_dims(x, axis=0)
    x = preprocess_func(x)
    x_tensor = tf.convert_to_tensor(x)

    grad_model = Model([model.inputs], [model.layers[-3].output, model.output])
    with tf.GradientTape() as tape:
        conv_outputs, predictions = grad_model(x_tensor)
        loss = predictions[:, 0]
    grads = tape.gradient(loss, conv_outputs)
    cam = tf.reduce_mean(grads, axis=-1).numpy()
    cam = np.squeeze(cam)

    cam = np.maximum(cam, 0)
    cam = cam / cam.max() if cam.max() != 0 else cam
    heatmap = cv2.resize(cam, size)
    heatmap = np.uint8(255 * heatmap)
    heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)

    img_np = np.array(img_resized)
    if img_np.shape[-1] == 4:
        img_np = img_np[:, :, :3]
    superimposed = cv2.addWeighted(img_np, 0.6, heatmap, 0.4, 0)
    return Image.fromarray(cv2.cvtColor(superimposed, cv2.COLOR_BGR2RGB))



# Preprocessing helper
def preprocess(img, size, func):
    img = img.resize(size)
    arr = img_to_array(img)
    arr = np.expand_dims(arr, axis=0)
    return func(arr)

# Prediction function
def predict(image):
    face = detect_face_opencv(image)

    xcp_input = preprocess(face, (299, 299), xcp_pre)
    eff_input = preprocess(face, (224, 224), eff_pre)

    xcp_pred = xcp_model.predict(xcp_input)[0][0]
    eff_pred = eff_model.predict(eff_input)[0][0]
    ensemble_prob = (xcp_pred + eff_pred) / 2

    label = "REAL" if ensemble_prob > 0.5 else "FAKE"
    cam_img = grad_cam(xcp_model, face, (299, 299), xcp_pre)

    return f"{label} ({ensemble_prob:.2%} confidence)", cam_img

# Gradio UI
gr.Interface(
    fn=predict,
    inputs=gr.Image(type="pil"),
    outputs=["text", "image"],
    title="Deepfake Image Detector (with Grad-CAM)",
    description="Upload an image. We detect the face, classify using an ensemble (Xception + EfficientNetB4), and explain the prediction using Grad-CAM on Xception."
).launch()