dappai's picture
Initial upload
662cb28
Raw
History Blame Contribute Delete
5.47 kB
import torch
import cv2
import numpy as np
import torchvision.transforms as T
from collections import OrderedDict
import base64
from model import DeepfakeModel
from cam import GradCAM, overlay_heatmap
# CONFIG
IMG_SIZE = 240
NUM_FRAMES = 10
device = torch.device(
"cuda" if torch.cuda.is_available() else "cpu"
)
# LOAD MODEL
model = DeepfakeModel()
state_dict = torch.load(
"best_model.pth",
map_location="cpu"
)
new_state = OrderedDict()
for k, v in state_dict.items():
name = k.replace(
"module.",
""
)
new_state[name] = v
model.load_state_dict(
new_state
)
model = model.to(device)
model.eval()
print("Model loaded successfully")
# GRADCAM
target_layer = model.cnn.blocks[-1]
grad_cam = GradCAM(
model,
target_layer
)
# FACE DETECTOR
face_detector = cv2.CascadeClassifier(
cv2.data.haarcascades +
"haarcascade_frontalface_default.xml"
)
# CACHE
LAST_FRAMES = []
# TRANSFORM
transform = T.Compose([
T.ToPILImage(),
T.Resize(
(IMG_SIZE, IMG_SIZE)
),
T.ToTensor(),
T.Normalize(
mean=[0.5, 0.5, 0.5],
std=[0.5, 0.5, 0.5]
)
])
# FRAME EXTRACTION
def extract_and_crop(
video_path,
num_frames=NUM_FRAMES
):
cap = cv2.VideoCapture(
video_path
)
total_frames = int(
cap.get(
cv2.CAP_PROP_FRAME_COUNT
)
)
if total_frames <= 0:
cap.release()
return []
idx = np.linspace(
0,
total_frames - 1,
num_frames,
dtype=int
)
frames = []
for i in idx:
cap.set(
cv2.CAP_PROP_POS_FRAMES,
int(i)
)
ret, frame = cap.read()
if not ret:
continue
gray = cv2.cvtColor(
frame,
cv2.COLOR_BGR2GRAY
)
faces = face_detector.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(80, 80)
)
if len(faces) > 0:
x, y, w, h = max(
faces,
key=lambda f: f[2] * f[3]
)
pad = int(
0.15 * max(w, h)
)
x1 = max(0, x - pad)
y1 = max(0, y - pad)
x2 = min(
frame.shape[1],
x + w + pad
)
y2 = min(
frame.shape[0],
y + h + pad
)
face = frame[
y1:y2,
x1:x2
]
else:
face = frame
face = cv2.resize(
face,
(IMG_SIZE, IMG_SIZE)
)
face = cv2.cvtColor(
face,
cv2.COLOR_BGR2RGB
)
frames.append(
face
)
cap.release()
if len(frames) == 0:
return []
while len(frames) < num_frames:
frames.append(
frames[-1]
)
return frames
# INFERENCE
def run_inference(video_path):
global LAST_FRAMES
frames = extract_and_crop(
video_path
)
LAST_FRAMES = frames
if len(frames) == 0:
return {
"label": "Video tidak terbaca",
"confidence": 0,
"frames": []
}
imgs = []
for frame in frames:
imgs.append(
transform(frame)
)
imgs = torch.stack(
imgs
)
imgs = imgs.unsqueeze(0)
imgs = imgs.to(device)
with torch.no_grad():
outputs = model(
imgs
)
probs = torch.softmax(
outputs,
dim=1
)[0]
pred = torch.argmax(
probs
).item()
confidence = float(
probs[pred].item() * 100
)
label = (
"Real"
if pred == 0
else "Fake"
)
encoded_frames = []
for frame in frames:
_, buffer = cv2.imencode(
".jpg",
cv2.cvtColor(
frame,
cv2.COLOR_RGB2BGR
)
)
encoded_frames.append(
base64.b64encode(
buffer
).decode("utf-8")
)
return {
"label": label,
"confidence": confidence,
"frames": encoded_frames
}
# REGION ANALYSIS
def compute_regions(cam):
regions = {
"Forehead": cam[0:60, :].mean(),
"Eyes": cam[60:110, :].mean(),
"Cheeks": cam[110:170, :].mean(),
"Mouth": cam[170:220, :].mean(),
"Chin": cam[220:240, :].mean()
}
total = (
sum(regions.values()) +
1e-8
)
result = []
for k, v in regions.items():
result.append({
"name": k,
"value": float(v / total)
})
return result
# HEATMAP
def generate_heatmap(frame_index):
global LAST_FRAMES
if frame_index >= len(LAST_FRAMES):
return None, None
frame = LAST_FRAMES[
frame_index
]
img = transform(
frame
)
seq = torch.stack(
[img] * NUM_FRAMES
)
seq = seq.unsqueeze(0)
seq = seq.to(device)
cam = grad_cam.generate(
seq
)
regions = compute_regions(
cam
)
heatmap = overlay_heatmap(
cv2.cvtColor(
frame,
cv2.COLOR_RGB2BGR
),
cam
)
return heatmap, regions