Krish Patel commited on
Commit ·
e728bee
1
Parent(s): f3daa92
Uploaded model and UI
Browse files- .gitignore +1 -0
- app.py +111 -0
- deepfake2.py +207 -0
- deepfake_detector.h5 +3 -0
- testing2.py +174 -0
.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
__pycache__/
|
app.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import cv2
|
| 3 |
+
import numpy as np
|
| 4 |
+
from tensorflow.keras.models import load_model
|
| 5 |
+
from PIL import Image
|
| 6 |
+
import io
|
| 7 |
+
import os
|
| 8 |
+
from testing2 import combined_prediction, predict_video
|
| 9 |
+
|
| 10 |
+
# Load the model
|
| 11 |
+
model = load_model("deepfake_detector.h5")
|
| 12 |
+
|
| 13 |
+
st.set_page_config(page_title="Deepfake Detection System", layout="wide")
|
| 14 |
+
|
| 15 |
+
def process_image_in_memory(file):
|
| 16 |
+
image = Image.open(file)
|
| 17 |
+
# Convert PIL Image to bytes
|
| 18 |
+
img_byte_arr = io.BytesIO()
|
| 19 |
+
image.save(img_byte_arr, format='JPEG')
|
| 20 |
+
img_byte_arr = img_byte_arr.getvalue()
|
| 21 |
+
|
| 22 |
+
# Create temporary file, process it, and delete immediately
|
| 23 |
+
temp_path = "temp_image.jpg"
|
| 24 |
+
with open(temp_path, "wb") as f:
|
| 25 |
+
f.write(img_byte_arr)
|
| 26 |
+
|
| 27 |
+
results = combined_prediction(temp_path)
|
| 28 |
+
|
| 29 |
+
# Clean up
|
| 30 |
+
if os.path.exists(temp_path):
|
| 31 |
+
os.remove(temp_path)
|
| 32 |
+
|
| 33 |
+
return results, image
|
| 34 |
+
|
| 35 |
+
def process_video_in_memory(file):
|
| 36 |
+
temp_path = "temp_video.mp4"
|
| 37 |
+
|
| 38 |
+
# Save temporarily for processing
|
| 39 |
+
with open(temp_path, "wb") as f:
|
| 40 |
+
f.write(file.read())
|
| 41 |
+
|
| 42 |
+
results = predict_video(temp_path)
|
| 43 |
+
|
| 44 |
+
# Clean up
|
| 45 |
+
if os.path.exists(temp_path):
|
| 46 |
+
os.remove(temp_path)
|
| 47 |
+
|
| 48 |
+
return results
|
| 49 |
+
|
| 50 |
+
def display_detailed_analysis(results):
|
| 51 |
+
st.subheader("🔍 Detailed Analysis")
|
| 52 |
+
|
| 53 |
+
# Main Metrics
|
| 54 |
+
col1, col2 = st.columns(2)
|
| 55 |
+
with col1:
|
| 56 |
+
st.metric("Final Verdict", results["Final Prediction"])
|
| 57 |
+
st.metric("CNN Analysis", results["CNN Prediction"])
|
| 58 |
+
with col2:
|
| 59 |
+
st.metric("Confidence Score", f"{results['Confidence Score']*100:.1f}%")
|
| 60 |
+
st.metric("Metadata Check", results["Metadata Analysis"])
|
| 61 |
+
|
| 62 |
+
# Technical Analysis
|
| 63 |
+
st.write("📊 Technical Analysis:")
|
| 64 |
+
st.write(f"- **Artifact Detection**: {results['Artifact Analysis']}")
|
| 65 |
+
st.write(f"- **Noise Pattern Analysis**: {results['Noise Pattern Analysis']}")
|
| 66 |
+
|
| 67 |
+
# Symmetry Analysis if available
|
| 68 |
+
if "Symmetry Analysis" in results:
|
| 69 |
+
st.write("🎯 Symmetry Measurements:")
|
| 70 |
+
symmetry = results["Symmetry Analysis"]
|
| 71 |
+
st.write(f"- **Vertical Symmetry**: {symmetry['Vertical Symmetry']*100:.1f}%")
|
| 72 |
+
st.write(f"- **Horizontal Symmetry**: {symmetry['Horizontal Symmetry']*100:.1f}%")
|
| 73 |
+
|
| 74 |
+
def main():
|
| 75 |
+
st.title("Deepfake Detection System")
|
| 76 |
+
st.write("Upload an image or video to detect if it's real or manipulated")
|
| 77 |
+
|
| 78 |
+
file = st.file_uploader("Choose a file", type=['jpg', 'jpeg', 'png', 'mp4', 'avi'])
|
| 79 |
+
|
| 80 |
+
if file:
|
| 81 |
+
file_type = file.type.split('/')[0]
|
| 82 |
+
|
| 83 |
+
if file_type == 'image':
|
| 84 |
+
results, image = process_image_in_memory(file)
|
| 85 |
+
st.image(image, caption="Uploaded Image", use_container_width=True, width=100)
|
| 86 |
+
|
| 87 |
+
display_detailed_analysis(results)
|
| 88 |
+
|
| 89 |
+
elif file_type == 'video':
|
| 90 |
+
st.video(file)
|
| 91 |
+
|
| 92 |
+
if st.button("Analyze Video"):
|
| 93 |
+
with st.spinner("Analyzing video frames..."):
|
| 94 |
+
results = process_video_in_memory(file)
|
| 95 |
+
|
| 96 |
+
# Display results
|
| 97 |
+
st.subheader("Video Analysis Results")
|
| 98 |
+
col1, col2 = st.columns(2)
|
| 99 |
+
|
| 100 |
+
with col1:
|
| 101 |
+
st.metric("Final Prediction", results["Final Video Prediction"])
|
| 102 |
+
st.metric("Confidence Score", f"{results['Confidence Score']*100:.2f}%")
|
| 103 |
+
|
| 104 |
+
with col2:
|
| 105 |
+
st.metric("Fake Frames", results["Fake Frames"])
|
| 106 |
+
st.metric("Real Frames", results["Real Frames"])
|
| 107 |
+
|
| 108 |
+
display_detailed_analysis(results)
|
| 109 |
+
|
| 110 |
+
if __name__ == "__main__":
|
| 111 |
+
main()
|
deepfake2.py
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import shutil
|
| 3 |
+
import cv2
|
| 4 |
+
import numpy as np
|
| 5 |
+
from tensorflow.keras.models import Sequential
|
| 6 |
+
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
|
| 7 |
+
from tensorflow.keras.preprocessing.image import ImageDataGenerator
|
| 8 |
+
from tensorflow.keras.models import load_model
|
| 9 |
+
from tensorflow.keras.preprocessing import image
|
| 10 |
+
import random
|
| 11 |
+
|
| 12 |
+
# Paths to dataset directories
|
| 13 |
+
data_dir = "C:/Users/ramya/OneDrive - iiit-b/Desktop/data_deepfake/Dataset/"
|
| 14 |
+
train_dir = os.path.join(data_dir, "Train")
|
| 15 |
+
val_dir = os.path.join(data_dir, "Validation")
|
| 16 |
+
temp_train_dir = os.path.join(data_dir, "Temp_Train")
|
| 17 |
+
temp_val_dir = os.path.join(data_dir, "Temp_Validation")
|
| 18 |
+
|
| 19 |
+
# Image dimensions
|
| 20 |
+
img_height, img_width = 128, 128
|
| 21 |
+
|
| 22 |
+
# Limit the number of images for training and validation
|
| 23 |
+
max_images_per_class = 12000 # Adjust as needed
|
| 24 |
+
|
| 25 |
+
def count_images(directory):
|
| 26 |
+
"""Count the number of real and fake images in a directory."""
|
| 27 |
+
real_count = len(os.listdir(os.path.join(directory, 'Real')))
|
| 28 |
+
fake_count = len(os.listdir(os.path.join(directory, 'Fake')))
|
| 29 |
+
return real_count, fake_count
|
| 30 |
+
|
| 31 |
+
def prepare_limited_dataset(source_dir, target_dir, max_images):
|
| 32 |
+
"""Create a temporary dataset with a limited number of images per class."""
|
| 33 |
+
if os.path.exists(target_dir):
|
| 34 |
+
shutil.rmtree(target_dir)
|
| 35 |
+
os.makedirs(os.path.join(target_dir, 'Real'), exist_ok=True)
|
| 36 |
+
os.makedirs(os.path.join(target_dir, 'Fake'), exist_ok=True)
|
| 37 |
+
|
| 38 |
+
for class_dir in ['Real', 'Fake']:
|
| 39 |
+
class_path = os.path.join(source_dir, class_dir)
|
| 40 |
+
target_class_path = os.path.join(target_dir, class_dir)
|
| 41 |
+
all_images = os.listdir(class_path)
|
| 42 |
+
random.shuffle(all_images)
|
| 43 |
+
selected_images = all_images[:max_images]
|
| 44 |
+
|
| 45 |
+
for image_name in selected_images:
|
| 46 |
+
shutil.copy(os.path.join(class_path, image_name), target_class_path)
|
| 47 |
+
|
| 48 |
+
def get_processed_images_info(generator):
|
| 49 |
+
"""Calculate information about processed images from a generator."""
|
| 50 |
+
n_samples = generator.n
|
| 51 |
+
n_classes = len(generator.class_indices)
|
| 52 |
+
batch_size = generator.batch_size
|
| 53 |
+
steps_per_epoch = int(np.ceil(n_samples / batch_size))
|
| 54 |
+
|
| 55 |
+
class_distribution = {}
|
| 56 |
+
for class_name, class_index in generator.class_indices.items():
|
| 57 |
+
class_count = len(generator.classes[generator.classes == class_index])
|
| 58 |
+
class_distribution[class_name] = class_count
|
| 59 |
+
|
| 60 |
+
return {
|
| 61 |
+
'total_samples': n_samples,
|
| 62 |
+
'batch_size': batch_size,
|
| 63 |
+
'steps_per_epoch': steps_per_epoch,
|
| 64 |
+
'class_distribution': class_distribution
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
# Print initial image counts
|
| 68 |
+
print("\nInitial image counts:")
|
| 69 |
+
train_real, train_fake = count_images(train_dir)
|
| 70 |
+
val_real, val_fake = count_images(val_dir)
|
| 71 |
+
print(f"Training - Real: {train_real}, Fake: {train_fake}")
|
| 72 |
+
print(f"Validation - Real: {val_real}, Fake: {val_fake}")
|
| 73 |
+
|
| 74 |
+
# Prepare temporary directories with limited images
|
| 75 |
+
prepare_limited_dataset(train_dir, temp_train_dir, max_images_per_class)
|
| 76 |
+
prepare_limited_dataset(val_dir, temp_val_dir, max_images_per_class)
|
| 77 |
+
|
| 78 |
+
# Print filtered image counts
|
| 79 |
+
print("\nAfter filtering:")
|
| 80 |
+
train_real, train_fake = count_images(temp_train_dir)
|
| 81 |
+
val_real, val_fake = count_images(temp_val_dir)
|
| 82 |
+
print(f"Training - Real: {train_real}, Fake: {train_fake}")
|
| 83 |
+
print(f"Validation - Real: {val_real}, Fake: {val_fake}")
|
| 84 |
+
|
| 85 |
+
# Data generators for training and validation
|
| 86 |
+
datagen = ImageDataGenerator(rescale=1./255)
|
| 87 |
+
|
| 88 |
+
train_gen = datagen.flow_from_directory(
|
| 89 |
+
temp_train_dir,
|
| 90 |
+
target_size=(img_height, img_width),
|
| 91 |
+
batch_size=32,
|
| 92 |
+
class_mode='binary',
|
| 93 |
+
classes=['Real', 'Fake']
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
val_gen = datagen.flow_from_directory(
|
| 97 |
+
temp_val_dir,
|
| 98 |
+
target_size=(img_height, img_width),
|
| 99 |
+
batch_size=32,
|
| 100 |
+
class_mode='binary',
|
| 101 |
+
classes=['Real', 'Fake']
|
| 102 |
+
)
|
| 103 |
+
|
| 104 |
+
# Get training and validation information
|
| 105 |
+
train_info = get_processed_images_info(train_gen)
|
| 106 |
+
val_info = get_processed_images_info(val_gen)
|
| 107 |
+
|
| 108 |
+
print("\nTraining Data Processing Info:")
|
| 109 |
+
print(f"Total training samples: {train_info['total_samples']}")
|
| 110 |
+
print(f"Batch size: {train_info['batch_size']}")
|
| 111 |
+
print(f"Steps per epoch: {train_info['steps_per_epoch']}")
|
| 112 |
+
print("\nClass distribution in training:")
|
| 113 |
+
for class_name, count in train_info['class_distribution'].items():
|
| 114 |
+
print(f"{class_name}: {count} images")
|
| 115 |
+
|
| 116 |
+
print("\nValidation Data Processing Info:")
|
| 117 |
+
print(f"Total validation samples: {val_info['total_samples']}")
|
| 118 |
+
print(f"Batch size: {val_info['batch_size']}")
|
| 119 |
+
print(f"Steps per epoch: {val_info['steps_per_epoch']}")
|
| 120 |
+
print("\nClass distribution in validation:")
|
| 121 |
+
for class_name, count in val_info['class_distribution'].items():
|
| 122 |
+
print(f"{class_name}: {count} images")
|
| 123 |
+
|
| 124 |
+
# Define the CNN model
|
| 125 |
+
model = Sequential([
|
| 126 |
+
Conv2D(32, (3, 3), activation='relu', input_shape=(img_height, img_width, 3)),
|
| 127 |
+
MaxPooling2D((2, 2)),
|
| 128 |
+
Conv2D(64, (3, 3), activation='relu'),
|
| 129 |
+
MaxPooling2D((2, 2)),
|
| 130 |
+
Conv2D(128, (3, 3), activation='relu'),
|
| 131 |
+
MaxPooling2D((2, 2)),
|
| 132 |
+
Flatten(),
|
| 133 |
+
Dense(128, activation='relu'),
|
| 134 |
+
Dropout(0.5),
|
| 135 |
+
Dense(1, activation='sigmoid')
|
| 136 |
+
])
|
| 137 |
+
|
| 138 |
+
# Compile the model
|
| 139 |
+
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
|
| 140 |
+
|
| 141 |
+
# Train the model
|
| 142 |
+
history = model.fit(
|
| 143 |
+
train_gen,
|
| 144 |
+
steps_per_epoch=train_info['steps_per_epoch'],
|
| 145 |
+
validation_data=val_gen,
|
| 146 |
+
validation_steps=val_info['steps_per_epoch'],
|
| 147 |
+
epochs=10
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
# Calculate total images processed
|
| 151 |
+
total_training_images_processed = train_info['total_samples'] * 10 # 10 epochs
|
| 152 |
+
total_validation_images_processed = val_info['total_samples'] * 10 # 10 epochs
|
| 153 |
+
|
| 154 |
+
print(f"\nTotal images processed during training: {total_training_images_processed}")
|
| 155 |
+
print(f"Total images processed during validation: {total_validation_images_processed}")
|
| 156 |
+
print(f"Combined total processed: {total_training_images_processed + total_validation_images_processed}")
|
| 157 |
+
|
| 158 |
+
# Save the model
|
| 159 |
+
model.save("deepfake_detector.h5")
|
| 160 |
+
|
| 161 |
+
# Functions for prediction
|
| 162 |
+
def predict_image(img_path):
|
| 163 |
+
"""Predict whether a single image is real or fake."""
|
| 164 |
+
img = image.load_img(img_path, target_size=(img_height, img_width))
|
| 165 |
+
img_array = image.img_to_array(img) / 255.0
|
| 166 |
+
img_array = np.expand_dims(img_array, axis=0)
|
| 167 |
+
prediction = model.predict(img_array)
|
| 168 |
+
return "Fake" if prediction[0][0] > 0.5 else "Real"
|
| 169 |
+
|
| 170 |
+
def predict_video(video_path):
|
| 171 |
+
"""Predict whether a video is real or fake by analyzing frames."""
|
| 172 |
+
cap = cv2.VideoCapture(video_path)
|
| 173 |
+
fake_count, real_count = 0, 0
|
| 174 |
+
|
| 175 |
+
while cap.isOpened():
|
| 176 |
+
ret, frame = cap.read()
|
| 177 |
+
if not ret:
|
| 178 |
+
break
|
| 179 |
+
|
| 180 |
+
# Preprocess the frame
|
| 181 |
+
frame_resized = cv2.resize(frame, (img_height, img_width))
|
| 182 |
+
frame_array = np.array(frame_resized) / 255.0
|
| 183 |
+
frame_array = np.expand_dims(frame_array, axis=0)
|
| 184 |
+
|
| 185 |
+
# Predict
|
| 186 |
+
prediction = model.predict(frame_array)
|
| 187 |
+
if prediction[0][0] > 0.5:
|
| 188 |
+
fake_count += 1
|
| 189 |
+
else:
|
| 190 |
+
real_count += 1
|
| 191 |
+
|
| 192 |
+
cap.release()
|
| 193 |
+
return "Fake" if fake_count > real_count else "Real"
|
| 194 |
+
|
| 195 |
+
# Example usage
|
| 196 |
+
if __name__ == "__main__":
|
| 197 |
+
# Test an image
|
| 198 |
+
test_image_path = "C:/Users/ramya/OneDrive - iiit-b/Desktop/test1.jpg"
|
| 199 |
+
if os.path.exists(test_image_path):
|
| 200 |
+
image_result = predict_image(test_image_path)
|
| 201 |
+
print(f"\nTest image prediction: {image_result}")
|
| 202 |
+
|
| 203 |
+
# Test a video (uncomment and modify path as needed)
|
| 204 |
+
# test_video_path = "example_video.mp4"
|
| 205 |
+
# if os.path.exists(test_video_path):
|
| 206 |
+
# video_result = predict_video(test_video_path)
|
| 207 |
+
# print(f"Test video prediction: {video_result}")
|
deepfake_detector.h5
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1fb63513282ef336b9bd11ab762da260a4789913a6268246ff9e96a08344009e
|
| 3 |
+
size 39704352
|
testing2.py
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import cv2
|
| 3 |
+
import numpy as np
|
| 4 |
+
import imghdr
|
| 5 |
+
from tensorflow.keras.models import load_model
|
| 6 |
+
from tensorflow.keras.preprocessing import image
|
| 7 |
+
from PIL import Image
|
| 8 |
+
from PIL.ExifTags import TAGS
|
| 9 |
+
|
| 10 |
+
# Load the saved model
|
| 11 |
+
model_path = "deepfake_detector.h5"
|
| 12 |
+
model = load_model(model_path)
|
| 13 |
+
|
| 14 |
+
# Image dimensions
|
| 15 |
+
img_height, img_width = 128, 128
|
| 16 |
+
|
| 17 |
+
# Trained model prediction
|
| 18 |
+
def predict_image(img_path):
|
| 19 |
+
if not os.path.exists(img_path):
|
| 20 |
+
return "Image path does not exist."
|
| 21 |
+
img = image.load_img(img_path, target_size=(img_height, img_width))
|
| 22 |
+
img_array = image.img_to_array(img) / 255.0
|
| 23 |
+
img_array = np.expand_dims(img_array, axis=0)
|
| 24 |
+
prediction = model.predict(img_array)
|
| 25 |
+
return "Fake" if prediction[0][0] > 0.5 else "Real"
|
| 26 |
+
|
| 27 |
+
def predict_video(video_path):
|
| 28 |
+
"""Predict whether a video is real or fake by analyzing frames."""
|
| 29 |
+
try:
|
| 30 |
+
cap = cv2.VideoCapture(video_path)
|
| 31 |
+
fake_count, real_count = 0, 0
|
| 32 |
+
total_frames = 0
|
| 33 |
+
results = {}
|
| 34 |
+
|
| 35 |
+
while cap.isOpened():
|
| 36 |
+
ret, frame = cap.read()
|
| 37 |
+
if not ret:
|
| 38 |
+
break
|
| 39 |
+
|
| 40 |
+
# Process every 5th frame to improve performance
|
| 41 |
+
if total_frames % 5 == 0:
|
| 42 |
+
# Analyze frame using all detection methods
|
| 43 |
+
frame_path = f"temp_frame_{total_frames}.jpg"
|
| 44 |
+
cv2.imwrite(frame_path, frame)
|
| 45 |
+
|
| 46 |
+
frame_results = combined_prediction(frame_path)
|
| 47 |
+
if frame_results["Final Prediction"] == "Fake":
|
| 48 |
+
fake_count += 1
|
| 49 |
+
else:
|
| 50 |
+
real_count += 1
|
| 51 |
+
|
| 52 |
+
os.remove(frame_path)
|
| 53 |
+
|
| 54 |
+
total_frames += 1
|
| 55 |
+
|
| 56 |
+
cap.release()
|
| 57 |
+
|
| 58 |
+
# Calculate final results
|
| 59 |
+
total_analyzed_frames = fake_count + real_count
|
| 60 |
+
fake_percentage = (fake_count / total_analyzed_frames * 100) if total_analyzed_frames > 0 else 0
|
| 61 |
+
|
| 62 |
+
results["Total Frames Analyzed"] = total_analyzed_frames
|
| 63 |
+
results["Fake Frames"] = fake_count
|
| 64 |
+
results["Real Frames"] = real_count
|
| 65 |
+
results["Fake Percentage"] = round(fake_percentage, 2)
|
| 66 |
+
results["Final Video Prediction"] = "Fake" if fake_percentage > 50 else "Real"
|
| 67 |
+
results["Confidence Score"] = round(abs(50 - fake_percentage) / 50, 2)
|
| 68 |
+
|
| 69 |
+
return results
|
| 70 |
+
|
| 71 |
+
except Exception as e:
|
| 72 |
+
return {"Error": f"Error analyzing video: {str(e)}"}
|
| 73 |
+
|
| 74 |
+
# Metadata analysis
|
| 75 |
+
def check_metadata(img_path):
|
| 76 |
+
try:
|
| 77 |
+
img = Image.open(img_path)
|
| 78 |
+
exif_data = img._getexif()
|
| 79 |
+
if not exif_data:
|
| 80 |
+
return "Fake (missing metadata)"
|
| 81 |
+
metadata = {TAGS.get(tag): value for tag, value in exif_data.items() if tag in TAGS}
|
| 82 |
+
return "Real (metadata present)" if metadata else "Fake (missing metadata)"
|
| 83 |
+
except Exception as e:
|
| 84 |
+
return f"Error analyzing metadata: {str(e)}"
|
| 85 |
+
|
| 86 |
+
# Artifact density analysis
|
| 87 |
+
def analyze_artifacts(img_path):
|
| 88 |
+
try:
|
| 89 |
+
img = cv2.imread(img_path)
|
| 90 |
+
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
| 91 |
+
laplacian = cv2.Laplacian(img_gray, cv2.CV_64F)
|
| 92 |
+
mean_var = np.mean(np.var(laplacian))
|
| 93 |
+
return "Fake (high artifact density)" if mean_var > 10 else "Real"
|
| 94 |
+
except Exception as e:
|
| 95 |
+
return f"Error analyzing artifacts: {str(e)}"
|
| 96 |
+
|
| 97 |
+
# Noise pattern detection
|
| 98 |
+
def detect_noise_patterns(img_path):
|
| 99 |
+
try:
|
| 100 |
+
img = cv2.imread(img_path)
|
| 101 |
+
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
| 102 |
+
noise_std = np.std(img_gray)
|
| 103 |
+
return "Fake (unnatural noise patterns)" if noise_std < 5 else "Real"
|
| 104 |
+
except Exception as e:
|
| 105 |
+
return f"Error analyzing noise patterns: {str(e)}"
|
| 106 |
+
|
| 107 |
+
# Symmetry analysis
|
| 108 |
+
def calculate_symmetry(img_path):
|
| 109 |
+
try:
|
| 110 |
+
img = cv2.imread(img_path)
|
| 111 |
+
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
| 112 |
+
img_flipped_v = cv2.flip(img_gray, 1)
|
| 113 |
+
img_flipped_h = cv2.flip(img_gray, 0)
|
| 114 |
+
vertical_symmetry = 1 - np.mean(np.abs(img_gray - img_flipped_v)) / 255
|
| 115 |
+
horizontal_symmetry = 1 - np.mean(np.abs(img_gray - img_flipped_h)) / 255
|
| 116 |
+
return {
|
| 117 |
+
"Vertical Symmetry": round(vertical_symmetry, 2),
|
| 118 |
+
"Horizontal Symmetry": round(horizontal_symmetry, 2)
|
| 119 |
+
}
|
| 120 |
+
except Exception as e:
|
| 121 |
+
return {"Error": str(e)}
|
| 122 |
+
|
| 123 |
+
# Combine all methods
|
| 124 |
+
def combined_prediction(img_path):
|
| 125 |
+
results = {}
|
| 126 |
+
cnn_prediction = predict_image(img_path)
|
| 127 |
+
results["CNN Prediction"] = cnn_prediction
|
| 128 |
+
cnn_score = 1 if cnn_prediction == "Fake" else 0
|
| 129 |
+
metadata_result = check_metadata(img_path)
|
| 130 |
+
results["Metadata Analysis"] = metadata_result
|
| 131 |
+
metadata_score = 1 if "Fake" in metadata_result else 0
|
| 132 |
+
artifact_result = analyze_artifacts(img_path)
|
| 133 |
+
results["Artifact Analysis"] = artifact_result
|
| 134 |
+
artifact_score = 1 if "Fake" in artifact_result else 0
|
| 135 |
+
noise_result = detect_noise_patterns(img_path)
|
| 136 |
+
results["Noise Pattern Analysis"] = noise_result
|
| 137 |
+
noise_score = 1 if "Fake" in noise_result else 0
|
| 138 |
+
symmetry_results = calculate_symmetry(img_path)
|
| 139 |
+
results["Symmetry Analysis"] = symmetry_results
|
| 140 |
+
vertical_symmetry = symmetry_results.get("Vertical Symmetry", 0)
|
| 141 |
+
horizontal_symmetry = symmetry_results.get("Horizontal Symmetry", 0)
|
| 142 |
+
symmetry_score = 0
|
| 143 |
+
if vertical_symmetry != "Unknown" and horizontal_symmetry != "Unknown":
|
| 144 |
+
if vertical_symmetry > 0.9 or horizontal_symmetry > 0.9:
|
| 145 |
+
symmetry_score = 1
|
| 146 |
+
total_score = (cnn_score * 0.4 + metadata_score * 0.1 +
|
| 147 |
+
artifact_score * 0.15 + noise_score * 0.15 +
|
| 148 |
+
symmetry_score * 0.2)
|
| 149 |
+
results["Final Prediction"] = "Fake" if total_score > 0.5 else "Real"
|
| 150 |
+
results["Confidence Score"] = round(total_score, 2)
|
| 151 |
+
return results
|
| 152 |
+
|
| 153 |
+
# Main function
|
| 154 |
+
if __name__ == "__main__":
|
| 155 |
+
test_image_path = "C:/Users/ramya/OneDrive - iiit-b/Desktop/test1.jpg"
|
| 156 |
+
if os.path.exists(test_image_path):
|
| 157 |
+
final_results = combined_prediction(test_image_path)
|
| 158 |
+
print("\nCombined Prediction Results:")
|
| 159 |
+
for key, value in final_results.items():
|
| 160 |
+
if isinstance(value, dict):
|
| 161 |
+
print(f"{key}:")
|
| 162 |
+
for sub_key, sub_value in value.items():
|
| 163 |
+
print(f" {sub_key}: {sub_value}")
|
| 164 |
+
else:
|
| 165 |
+
print(f"{key}: {value}")
|
| 166 |
+
|
| 167 |
+
# if __name__ == "__main__":
|
| 168 |
+
# # Test video
|
| 169 |
+
# test_video_path = "path/to/your/video.mp4"
|
| 170 |
+
# if os.path.exists(test_video_path):
|
| 171 |
+
# video_results = predict_video(test_video_path)
|
| 172 |
+
# print("\nVideo Analysis Results:")
|
| 173 |
+
# for key, value in video_results.items():
|
| 174 |
+
# print(f"{key}: {value}")
|