File size: 6,336 Bytes
cbbb966 096a01b cbbb966 096a01b cbbb966 096a01b cbbb966 096a01b cbbb966 096a01b cbbb966 5c4efa2 cbbb966 5c4efa2 cbbb966 096a01b cbbb966 5c4efa2 cbbb966 5c4efa2 cbbb966 5c4efa2 cbbb966 5c4efa2 cbbb966 5c4efa2 cbbb966 5c4efa2 cbbb966 5c4efa2 cbbb966 |
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 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
import spaces
from flask import Flask, request, jsonify
import os
from werkzeug.utils import secure_filename
import cv2
import torch
import torch.nn.functional as F
from facenet_pytorch import MTCNN, InceptionResnetV1
import numpy as np
from pytorch_grad_cam import GradCAM
from pytorch_grad_cam.utils.model_targets import ClassifierOutputTarget
from pytorch_grad_cam.utils.image import show_cam_on_image
import base64
app = Flask(__name__)
# Configuration
UPLOAD_FOLDER = 'uploads'
ALLOWED_EXTENSIONS = {'mp4', 'avi', 'mov', 'webm'}
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
# Device configuration
DEVICE = 'cuda:0' if torch.cuda.is_available() else 'cpu'
# Configure MTCNN with adjusted thresholds
mtcnn = MTCNN(select_largest=False, post_process=False, device=DEVICE,
thresholds=[0.7, 0.8, 0.8], # Adjust these thresholds for P-Net, R-Net, O-Net
margin=20, min_face_size=50).to(DEVICE).eval()
model = InceptionResnetV1(pretrained="vggface2", classify=True, num_classes=1, device=DEVICE)
checkpoint = torch.load("resnetinceptionv1_epoch_32.pth", map_location=torch.device('cpu'))
model.load_state_dict(checkpoint['model_state_dict'])
model.to(DEVICE)
model.eval()
# GradCAM setup
target_layers = [model.block8.branch1[-1]]
cam = GradCAM(model=model, target_layers=target_layers)
targets = [ClassifierOutputTarget(0)]
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def filter_low_quality_detections(detection, min_size=(50, 50)):
if detection is None or detection[0] is None:
return None
for i, (box, prob) in enumerate(zip(detection[0], detection[1])):
if prob < 0.9: # Filter out detections with low confidence
continue
if (box[2] - box[0] < min_size[0]) or (box[3] - box[1] < min_size[1]): # Check size
continue
return box # Return the first valid detection
return None
@spaces.GPU
def process_frame(frame):
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
detection = mtcnn.detect(rgb_frame)
face_box = filter_low_quality_detections(detection)
if face_box is None:
return None, None, None
x1, y1, x2, y2 = map(int, face_box)
h, w, _ = rgb_frame.shape
if x1 < 0 or y1 < 0 or x2 > w or y2 > h:
return None, None, None
face = rgb_frame[y1:y2, x1:x2]
if face.size == 0:
return None, None, None
face = cv2.resize(face, (256, 256))
face = torch.from_numpy(face).permute(2, 0, 1).unsqueeze(0).to(DEVICE)
face = face.to(torch.float32) / 255.0
with torch.no_grad():
output = torch.sigmoid(model(face).squeeze(0))
prediction = "fake" if output.item() >= 0.5 else "real"
# Generate GradCAM
grayscale_cam = cam(input_tensor=face, targets=targets, eigen_smooth=True)
grayscale_cam = grayscale_cam[0, :]
face_image_to_plot = face.squeeze(0).permute(1, 2, 0).cpu().detach().numpy()
visualization = show_cam_on_image(face_image_to_plot, grayscale_cam, use_rgb=True)
return prediction, output.item(), visualization
@spaces.GPU
def analyze_video(video_path, sample_rate=30, top_n=5, detection_threshold=0.5):
cap = cv2.VideoCapture(video_path)
frame_count = 0
fake_count = 0
total_processed = 0
frames_info = []
confidence_scores = []
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
if frame_count % sample_rate == 0:
prediction, confidence, visualization = process_frame(frame)
if prediction is not None:
total_processed += 1
confidence_scores.append(confidence)
if prediction == "fake":
fake_count += 1
frames_info.append({
'frame_number': frame_count,
'prediction': prediction,
'confidence': confidence,
'visualization': visualization
})
frame_count += 1
cap.release()
if total_processed > 0:
fake_percentage = (fake_count / total_processed) * 100
average_confidence = sum(confidence_scores) / len(confidence_scores)
model_confidence = 1 - (sum((score - average_confidence) ** 2 for score in confidence_scores) / len(confidence_scores))
frames_info.sort(key=lambda x: x['confidence'], reverse=True)
top_frames = frames_info[:top_n]
return {
'fake_percentage': fake_percentage,
'is_likely_deepfake': fake_percentage >= 60,
'top_frames': top_frames,
'model_confidence': model_confidence,
'total_frames_analyzed': total_processed,
'average_confidence_score': average_confidence,
'detection_threshold': detection_threshold
}
else:
return None
@app.route('/analyze', methods=['POST'])
def analyze_video_api():
if 'video' not in request.files:
return jsonify({'error': 'No video file provided'}), 400
file = request.files['video']
if file.filename == '':
return jsonify({'error': 'No selected file'}), 400
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(filepath)
try:
result = analyze_video(filepath)
os.remove(filepath) # Remove the file after analysis
if result:
# Convert numpy arrays to base64 encoded strings
for frame in result['top_frames']:
frame['visualization'] = base64.b64encode(cv2.imencode('.png', frame['visualization'])[1]).decode('utf-8')
return jsonify(result), 200
else:
return jsonify({'error': 'No frames could be processed'}), 400
except Exception as e:
os.remove(filepath) # Remove the file if an error occurs
return jsonify({'error': str(e)}), 500
else:
return jsonify({'error': f'Invalid file type: {file.filename}'}), 400
if __name__ == '__main__':
app.run(host='0.0.0.0', port=7860) |