| import os
|
| import cv2
|
| import torch
|
| import zipfile
|
| import librosa
|
| import numpy as np
|
| import tensorflow as tf
|
| from facenet_pytorch import MTCNN
|
| from rawnet import RawNet
|
|
|
|
|
|
|
|
|
| tf.random.set_seed(42)
|
|
|
|
|
| if not os.path.exists("efficientnet-b0"):
|
| local_zip = "./efficientnet-b0.zip"
|
| if os.path.exists(local_zip):
|
| zip_ref = zipfile.ZipFile(local_zip, 'r')
|
| zip_ref.extractall()
|
| zip_ref.close()
|
| print("Model extracted successfully!")
|
|
|
|
|
|
|
| model = tf.keras.models.load_model("efficientnet-b0/", compile=False)
|
|
|
|
|
|
|
| class DetectionPipeline:
|
| """Pipeline class for detecting faces in the frames of a video file."""
|
|
|
| def __init__(self, n_frames=None, batch_size=60, resize=None, input_modality = 'video'):
|
| """Constructor for DetectionPipeline class.
|
|
|
| Keyword Arguments:
|
| n_frames {int} -- Total number of frames to load. These will be evenly spaced
|
| throughout the video. If not specified (i.e., None), all frames will be loaded.
|
| (default: {None})
|
| batch_size {int} -- Batch size to use with MTCNN face detector. (default: {32})
|
| resize {float} -- Fraction by which to resize frames from original prior to face
|
| detection. A value less than 1 results in downsampling and a value greater than
|
| 1 result in upsampling. (default: {None})
|
| """
|
| self.n_frames = n_frames
|
| self.batch_size = batch_size
|
| self.resize = resize
|
| self.input_modality = input_modality
|
|
|
| def __call__(self, filename):
|
| """Load frames from an MP4 video and detect faces.
|
|
|
| Arguments:
|
| filename {str} -- Path to video.
|
| """
|
|
|
| if self.input_modality == 'video':
|
| print('Input modality is video.')
|
| v_cap = cv2.VideoCapture(filename)
|
| v_len = int(v_cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
|
|
|
|
| if self.n_frames is None:
|
| sample = np.arange(0, v_len)
|
| else:
|
| sample = np.linspace(0, v_len - 1, self.n_frames).astype(int)
|
|
|
|
|
| faces = []
|
| frames = []
|
| for j in range(v_len):
|
| success = v_cap.grab()
|
| if j in sample:
|
|
|
| success, frame = v_cap.retrieve()
|
| if not success:
|
| continue
|
| frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
|
|
|
| if self.resize is not None:
|
| frame = frame.resize([int(d * self.resize) for d in frame.size])
|
| frames.append(frame)
|
|
|
|
|
| if len(frames) % self.batch_size == 0 or j == sample[-1]:
|
| face2 = cv2.resize(frame, (224, 224))
|
| faces.append(face2)
|
|
|
| v_cap.release()
|
| return faces
|
|
|
| elif self.input_modality == 'image':
|
| print('Input modality is image.')
|
|
|
| print('Reading image')
|
|
|
| image = cv2.cvtColor(filename, cv2.COLOR_BGR2RGB)
|
| image = cv2.resize(image, (224, 224))
|
|
|
|
|
|
|
|
|
| return image
|
|
|
| elif self.input_modality == 'audio':
|
| print("INput modality is audio.")
|
|
|
|
|
| x, sr = librosa.load(filename)
|
| x_pt = torch.Tensor(x)
|
| x_pt = torch.unsqueeze(x_pt, dim = 0)
|
| return x_pt
|
|
|
| else:
|
| raise ValueError("Invalid input modality. Must be either 'video' or image")
|
|
|
| detection_video_pipeline = DetectionPipeline(n_frames=5, batch_size=1, input_modality='video')
|
| detection_image_pipeline = DetectionPipeline(batch_size = 1, input_modality = 'image')
|
|
|
| def deepfakes_video_predict(input_video):
|
|
|
| faces = detection_video_pipeline(input_video)
|
| total = 0
|
| real_res = []
|
| fake_res = []
|
|
|
| for face in faces:
|
|
|
| face2 = face/255
|
| pred = model.predict(np.expand_dims(face2, axis=0))[0]
|
| real, fake = pred[0], pred[1]
|
| real_res.append(real)
|
| fake_res.append(fake)
|
|
|
| total+=1
|
|
|
| pred2 = pred[1]
|
|
|
| if pred2 > 0.5:
|
| fake+=1
|
| else:
|
| real+=1
|
| real_mean = np.mean(real_res)
|
| fake_mean = np.mean(fake_res)
|
| print(f"Real Faces: {real_mean}")
|
| print(f"Fake Faces: {fake_mean}")
|
| text = ""
|
|
|
| if real_mean >= 0.5:
|
| text = "The video is REAL. \n Deepfakes Confidence: " + str(round(100 - (real_mean*100), 3)) + "%"
|
| else:
|
| text = "The video is FAKE. \n Deepfakes Confidence: " + str(round(fake_mean*100, 3)) + "%"
|
|
|
| return text
|
|
|
|
|
| def deepfakes_image_predict(input_image):
|
| faces = detection_image_pipeline(input_image)
|
| face2 = faces/255
|
| pred = model.predict(np.expand_dims(face2, axis = 0))[0]
|
| real, fake = pred[0], pred[1]
|
| if real > 0.5:
|
| text2 = "The image is REAL. \n Deepfakes Confidence: " + str(round(100 - (real*100), 3)) + "%"
|
| else:
|
| text2 = "The image is FAKE. \n Deepfakes Confidence: " + str(round(fake*100, 3)) + "%"
|
| return text2
|
|
|
| def load_audio_model():
|
| d_args = {
|
| "nb_samp": 64600,
|
| "first_conv": 1024,
|
| "in_channels": 1,
|
| "filts": [20, [20, 20], [20, 128], [128, 128]],
|
| "blocks": [2, 4],
|
| "nb_fc_node": 1024,
|
| "gru_node": 1024,
|
| "nb_gru_layer": 3,
|
| "nb_classes": 2}
|
|
|
| model = RawNet(d_args = d_args, device='cpu')
|
|
|
|
|
| model_dict = model.state_dict()
|
| ckpt = torch.load('RawNet2.pth', map_location=torch.device('cpu'))
|
| model.load_state_dict(ckpt, model_dict)
|
| return model
|
|
|
| audio_label_map = {
|
| 0: "Real audio",
|
| 1: "Fake audio"
|
| }
|
|
|
| def deepfakes_audio_predict(input_audio):
|
|
|
| x, sr = input_audio
|
| x_pt = torch.Tensor(x)
|
| x_pt = torch.unsqueeze(x_pt, dim = 0)
|
|
|
|
|
| model = load_audio_model()
|
|
|
|
|
| grads = model(x_pt)
|
|
|
|
|
| grads_np = grads.detach().numpy()
|
| result = np.argmax(grads_np)
|
|
|
| return audio_label_map[result]
|
|
|