samuelolubukun commited on
Commit
72da25c
Β·
verified Β·
1 Parent(s): 848d12a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +810 -414
app.py CHANGED
@@ -1,414 +1,810 @@
1
- import streamlit as st
2
- from PIL import Image, ImageChops, ImageEnhance
3
- import numpy as np
4
- import matplotlib.pyplot as plt
5
- import cv2
6
- import os
7
- import cv2 as cv
8
- from mtcnn import MTCNN
9
- from tensorflow.keras.models import load_model
10
- from tensorflow.keras.preprocessing import image as keras_image
11
- import keras
12
-
13
- # Load models
14
- @st.cache_resource
15
- def load_image_forgery_model():
16
- return load_model("imageforgerydetection.h5")
17
-
18
- @st.cache_resource
19
- def load_deepfake_image_model():
20
- return load_model("deepfake_image_detection.h5")
21
-
22
- @st.cache_resource
23
- def load_video_forgery_model():
24
- return load_model("videoforgerydetection.keras")
25
-
26
- # Constants
27
- IMG_SIZE = 224
28
- MAX_SEQ_LENGTH = 20
29
- NUM_FEATURES = 2048
30
-
31
- @st.cache_resource
32
- def load_deepfake_model():
33
- return load_model('video_classifier_full_model.h5')
34
-
35
- # Load pre-trained models and processor
36
- deepfake_model = load_deepfake_model()
37
- vocabulary2 = np.load('label_processor_vocabulary.npy', allow_pickle=True)
38
- label_processor2 = keras.layers.StringLookup(num_oov_indices=0, vocabulary=vocabulary2.tolist())
39
-
40
-
41
- # Helper functions
42
- # Image Forgery Detection
43
- def convert_to_ela_image(image, quality=90):
44
- temp_filename = 'temp_file_name.jpg'
45
- ela_filename = 'temp_ela.png'
46
-
47
- if image.mode != 'RGB':
48
- image = image.convert('RGB')
49
-
50
- image.save(temp_filename, 'JPEG', quality=quality)
51
- temp_image = Image.open(temp_filename)
52
-
53
- ela_image = ImageChops.difference(image, temp_image)
54
- extrema = ela_image.getextrema()
55
- max_diff = max([ex[1] for ex in extrema])
56
- max_diff = max_diff if max_diff != 0 else 1
57
- scale = 255.0 / max_diff
58
-
59
- ela_image = ImageEnhance.Brightness(ela_image).enhance(scale)
60
- return ela_image
61
-
62
- def prepare_image_for_forgery(image):
63
- ela_image = convert_to_ela_image(image, 90).resize((128, 128))
64
- return np.array(ela_image).flatten() / 255.0
65
-
66
- # Deepfake Image Detection
67
- def predict_deepfake_image(image_path, model):
68
- img = keras_image.load_img(image_path, target_size=(256, 256))
69
- img_array = keras_image.img_to_array(img) / 255.0
70
- img_array = np.expand_dims(img_array, axis=0)
71
- prediction = model.predict(img_array)
72
- return 'Real' if prediction[0] > 0.5 else 'Fake'
73
-
74
- # Video Forgery Detection
75
- # Configuration
76
- target_height, target_width = 240, 320
77
- threshold = 30 # Threshold for freeze/duplicate detection
78
-
79
- def predict_video_forgery_cnn(video_path, model):
80
- """CNN-based video forgery detection"""
81
- vid = []
82
- sumframes = 0
83
- cap = cv2.VideoCapture(video_path)
84
-
85
- while cap.isOpened():
86
- ret, frame = cap.read()
87
- if not ret:
88
- break
89
-
90
- # Resize frame to target dimensions
91
- frame = cv2.resize(frame, (target_width, target_height))
92
- sumframes += 1
93
- vid.append(frame)
94
-
95
- cap.release()
96
-
97
- if sumframes == 0:
98
- return False, 0, 0
99
-
100
- Xtest = np.array(vid)
101
- output = model.predict(Xtest)
102
- output = output.reshape((-1))
103
-
104
- # Check if any frame is predicted as forged
105
- forged_frames = sum(1 for i in output if i > 0.5)
106
- is_forged = any(i > 0.5 for i in output)
107
-
108
- return is_forged, forged_frames, sumframes
109
-
110
- def analyze_video_tampering(video_path):
111
- """Frame difference analysis for tampering detection"""
112
- cap = cv2.VideoCapture(video_path)
113
- if not cap.isOpened():
114
- return False, [], []
115
-
116
- prev_frame = None
117
- frame_differences = []
118
- suspected_frames = []
119
-
120
- while cap.isOpened():
121
- ret, frame = cap.read()
122
- if not ret:
123
- break
124
-
125
- gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
126
-
127
- if prev_frame is not None:
128
- diff = cv2.absdiff(gray, prev_frame)
129
- non_zero = np.count_nonzero(diff)
130
- frame_differences.append(non_zero)
131
-
132
- if non_zero < threshold:
133
- current_frame = int(cap.get(cv2.CAP_PROP_POS_FRAMES))
134
- suspected_frames.append(current_frame)
135
-
136
- prev_frame = gray
137
-
138
- cap.release()
139
-
140
- # Simple rule: if any frame is suspected, flag as tampered
141
- is_tampered = len(suspected_frames) > 0
142
-
143
- return is_tampered, frame_differences, suspected_frames
144
-
145
- def plot_frame_analysis(frame_differences):
146
- """Create a simple plot of frame differences"""
147
- plt.figure(figsize=(10, 4))
148
- plt.plot(frame_differences, color='blue', linewidth=1)
149
- plt.axhline(y=threshold, color='red', linestyle='--', label=f"Threshold ({threshold})")
150
- plt.xlabel("Frame Number")
151
- plt.ylabel("Pixel Differences")
152
- plt.title("Frame Difference Analysis")
153
- plt.legend()
154
- plt.grid(True, alpha=0.3)
155
-
156
- # Add statistics
157
- if frame_differences:
158
- mean_val = np.mean(frame_differences)
159
- std_val = np.std(frame_differences)
160
- plt.text(0.02, 0.98, f"Mean: {mean_val:.1f}\nStd: {std_val:.1f}",
161
- transform=plt.gca().transAxes, verticalalignment='top',
162
- bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
163
-
164
- return plt
165
-
166
- def combined_video_forgery_detection(video_path, model):
167
- """Combined detection using both CNN and frame analysis"""
168
-
169
- # Method 1: CNN-based detection
170
- cnn_forged, cnn_forged_frames, total_frames = predict_video_forgery_cnn(video_path, model)
171
-
172
- # Method 2: Frame analysis tampering detection
173
- frame_tampered, frame_differences, suspected_frames = analyze_video_tampering(video_path)
174
-
175
- # Results
176
- results = {
177
- 'cnn_forged': cnn_forged,
178
- 'cnn_forged_frames': cnn_forged_frames,
179
- 'frame_tampered': frame_tampered,
180
- 'suspected_frames': len(suspected_frames),
181
- 'total_frames': total_frames,
182
- 'frame_differences': frame_differences
183
- }
184
-
185
- # Simple decision logic
186
- if cnn_forged and frame_tampered:
187
- verdict = "FORGED - Detected by both CNN and Frame Analysis"
188
- confidence = "High"
189
- elif cnn_forged:
190
- verdict = "FORGED - Detected by CNN"
191
- confidence = "Medium"
192
- elif frame_tampered:
193
- verdict = "FORGED - Detected by Frame Analysis"
194
- confidence = "Medium"
195
- else:
196
- verdict = "NOT TAMPERED - No Forgery detected"
197
- confidence = "High"
198
-
199
- return verdict, confidence, results
200
-
201
- # Deepfake Video Detection
202
- def build_feature_extractor():
203
- feature_extractor = keras.applications.InceptionV3(
204
- weights="imagenet",
205
- include_top=False,
206
- pooling="avg",
207
- input_shape=(IMG_SIZE, IMG_SIZE, 3),
208
- )
209
- preprocess_input = keras.applications.inception_v3.preprocess_input
210
-
211
- inputs = keras.Input((IMG_SIZE, IMG_SIZE, 3))
212
- preprocessed = preprocess_input(inputs)
213
- outputs = feature_extractor(preprocessed)
214
- return keras.Model(inputs, outputs, name="feature_extractor")
215
-
216
- feature_extractor = build_feature_extractor()
217
- detector = MTCNN()
218
-
219
- def load_video(path, max_frames=0, resize=(IMG_SIZE, IMG_SIZE), skip_frames=2):
220
- cap = cv.VideoCapture(path)
221
- frames = []
222
- frame_count = 0
223
- previous_box = None
224
-
225
- while True:
226
- ret, frame = cap.read()
227
- if not ret:
228
- break
229
-
230
- if frame_count % skip_frames == 0:
231
- frame, previous_box = get_face_region_first_frame(frame, previous_box)
232
- if frame is not None:
233
- frame = cv.resize(frame, resize)
234
- frame = frame[:, :, [2, 1, 0]]
235
- frames.append(frame)
236
-
237
- if len(frames) == max_frames:
238
- break
239
- frame_count += 1
240
-
241
- while len(frames) < max_frames and frames:
242
- frames.append(frames[-1])
243
-
244
- cap.release()
245
- return np.array(frames)
246
-
247
- def get_face_region_first_frame(frame, previous_box=None):
248
- if previous_box is None:
249
- detections = detector.detect_faces(frame)
250
- if detections:
251
- x, y, width, height = detections[0]['box']
252
- previous_box = (x, y, width, height)
253
- else:
254
- return None, None
255
- else:
256
- x, y, width, height = previous_box
257
-
258
- face_region = frame[y:y+height, x:x+width]
259
- return face_region, previous_box
260
-
261
- def prepare_single_video(frames):
262
- frames = frames[None, ...]
263
- frame_mask = np.zeros(shape=(1, MAX_SEQ_LENGTH,), dtype="bool")
264
- frame_features = np.zeros(shape=(1, MAX_SEQ_LENGTH, NUM_FEATURES), dtype="float32")
265
-
266
- for i, batch in enumerate(frames):
267
- video_length = batch.shape[0]
268
- length = min(MAX_SEQ_LENGTH, video_length)
269
- for j in range(length):
270
- frame_features[i, j, :] = feature_extractor.predict(batch[None, j, :])
271
- frame_mask[i, :length] = 1
272
-
273
- return frame_features, frame_mask
274
-
275
- def sequence_prediction(video_path):
276
- class_vocab = label_processor2.get_vocabulary()
277
- frames = load_video(video_path)
278
- if len(frames) == 0:
279
- st.error("Could not process video. Please try another file.")
280
- return None
281
-
282
- frame_features, frame_mask = prepare_single_video(frames)
283
- probabilities = deepfake_model.predict([frame_features, frame_mask])[0]
284
-
285
- predictions = {class_vocab[i]: probabilities[i] * 100 for i in np.argsort(probabilities)[::-1]}
286
- return predictions
287
-
288
-
289
- # Streamlit App
290
- st.title("Fraudulent Image and Video Detection System")
291
-
292
- # Sidebar for model selection
293
- task = st.sidebar.selectbox("Choose a detection task:", [
294
- "Image Forgery Detection",
295
- "Deepfake Image Detection",
296
- "Video Forgery Detection",
297
- "Deepfake Video Detection"
298
- ])
299
-
300
- if task == "Image Forgery Detection":
301
- uploaded_file = st.file_uploader("Upload an image", type=['jpg', 'jpeg', 'png'])
302
- if uploaded_file:
303
- image = Image.open(uploaded_file)
304
- st.image(image, caption="Uploaded Image", use_container_width=True)
305
-
306
- prepared_image = prepare_image_for_forgery(image).reshape(-1, 128, 128, 3)
307
- model = load_image_forgery_model()
308
- prediction = model.predict(prepared_image)
309
- confidence_real = prediction[0][1] * 100
310
- confidence_fake = prediction[0][0] * 100
311
-
312
- if confidence_real > confidence_fake:
313
- st.success(f"Result: Real Image with {confidence_real:.2f}% confidence")
314
- else:
315
- st.error(f"Result: Forged Image with {confidence_fake:.2f}% confidence")
316
-
317
- elif task == "Deepfake Image Detection":
318
- uploaded_file = st.file_uploader("Upload an image", type=['jpg', 'jpeg', 'png'])
319
- if uploaded_file:
320
- with open("temp_image.jpg", "wb") as f:
321
- f.write(uploaded_file.getbuffer())
322
-
323
- st.image(uploaded_file, caption="Uploaded Image", use_container_width=True)
324
- model = load_deepfake_image_model()
325
- result = predict_deepfake_image("temp_image.jpg", model)
326
-
327
- if result == 'Real':
328
- st.success("Prediction: Real")
329
- else:
330
- st.error("Prediction: Fake")
331
-
332
- os.remove("temp_image.jpg")
333
-
334
- if task == "Video Forgery Detection":
335
- uploaded_file = st.file_uploader("Upload a video", type=['mp4', 'avi', 'mov', 'mkv'])
336
-
337
- if uploaded_file:
338
- # Save uploaded file
339
- with open("temp_video.mp4", "wb") as f:
340
- f.write(uploaded_file.getbuffer())
341
-
342
- st.video("temp_video.mp4")
343
- st.write("Analyzing the video for forgery...")
344
-
345
- # Load model and run combined detection
346
- model = load_video_forgery_model()
347
- verdict, confidence, results = combined_video_forgery_detection("temp_video.mp4", model)
348
-
349
- # Display results
350
- if "FORGED" in verdict:
351
- st.error(f"🚨 {verdict}")
352
- else:
353
- st.success(f"βœ… {verdict}")
354
-
355
- st.write(f"**Confidence Level:** {confidence}")
356
-
357
- # Show detailed results
358
- col1, col2 = st.columns(2)
359
-
360
- with col1:
361
- st.write("**CNN Analysis:**")
362
- if results['cnn_forged']:
363
- st.write(f"- Status: Forged ❌")
364
- st.write(f"- Forged Frames: {results['cnn_forged_frames']}/{results['total_frames']}")
365
- else:
366
- st.write(f"- Status: Not Forged βœ…")
367
-
368
- with col2:
369
- st.write("**Frame Analysis:**")
370
- if results['frame_tampered']:
371
- st.write(f"- Status: Tampered ❌")
372
- st.write(f"- Suspected Frames: {results['suspected_frames']}")
373
- else:
374
- st.write(f"- Status: Not Tampered βœ…")
375
-
376
- # Plot frame differences if available
377
- if results['frame_differences']:
378
- st.write("**Frame Difference Analysis:**")
379
- fig = plot_frame_analysis(results['frame_differences'])
380
- st.pyplot(fig)
381
- plt.close()
382
-
383
- # Cleanup
384
- os.remove("temp_video.mp4")
385
-
386
-
387
- elif task == "Deepfake Video Detection":
388
- uploaded_file = st.file_uploader("Upload a video", type=["mp4", "avi", "mov"])
389
- if uploaded_file is not None:
390
- with open("temp_video.mp4", "wb") as f:
391
- f.write(uploaded_file.read())
392
-
393
- st.video("temp_video.mp4")
394
- st.write("Analyzing the video...")
395
-
396
- frames = load_video("temp_video.mp4")
397
- if len(frames) == 0:
398
- st.error("Could not process video. Please try another file.")
399
- else:
400
- frame_features, frame_mask = prepare_single_video(frames)
401
- probabilities = deepfake_model.predict([frame_features, frame_mask])[0]
402
-
403
- predictions = {label_processor2.get_vocabulary()[i]: probabilities[i] * 100 for i in np.argsort(probabilities)[::-1]}
404
-
405
- if predictions:
406
- highest_label = max(predictions, key=predictions.get)
407
- highest_prob = predictions[highest_label]
408
-
409
- if highest_label.lower() == "real":
410
- st.success(f"The video is real with a confidence of {highest_prob:.2f}%.")
411
- elif highest_label.lower() == "fake":
412
- st.error(f"This video is a deepfake with a confidence of {highest_prob:.2f}%.")
413
- else:
414
- st.warning(f"Uncertain prediction: {highest_label} with {highest_prob:.2f}% confidence.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from PIL import Image, ImageChops, ImageEnhance, ImageDraw, ImageFilter
3
+ import numpy as np
4
+ import matplotlib.pyplot as plt
5
+ import matplotlib.pyplot as plt
6
+ import matplotlib.patches as patches
7
+ from scipy import ndimage
8
+ from skimage import feature, measure
9
+ import io
10
+ import cv2
11
+ import os
12
+ import cv2 as cv
13
+ from mtcnn import MTCNN
14
+ from tensorflow.keras.models import load_model
15
+ from tensorflow.keras.preprocessing import image as keras_image
16
+ import keras
17
+
18
+ # Load models
19
+ @st.cache_resource
20
+ def load_image_forgery_model():
21
+ return load_model("imageforgerydetection.h5")
22
+
23
+ @st.cache_resource
24
+ def load_deepfake_image_model():
25
+ return load_model("deepfake_image_detection.h5")
26
+
27
+ @st.cache_resource
28
+ def load_video_forgery_model():
29
+ return load_model("videoforgerydetection.keras")
30
+
31
+ # Constants
32
+ IMG_SIZE = 224
33
+ MAX_SEQ_LENGTH = 20
34
+ NUM_FEATURES = 2048
35
+
36
+ @st.cache_resource
37
+ def load_deepfake_model():
38
+ return load_model('video_classifier_full_model.h5')
39
+
40
+ # Load pre-trained models and processor
41
+ deepfake_model = load_deepfake_model()
42
+ vocabulary2 = np.load('label_processor_vocabulary.npy', allow_pickle=True)
43
+ label_processor2 = keras.layers.StringLookup(num_oov_indices=0, vocabulary=vocabulary2.tolist())
44
+
45
+
46
+ # Helper functions
47
+ # Image Forgery Detection Functions
48
+ def convert_to_ela_image(image, quality=90):
49
+ temp_filename = 'temp_file_name.jpg'
50
+ ela_filename = 'temp_ela.png'
51
+
52
+ if image.mode != 'RGB':
53
+ image = image.convert('RGB')
54
+
55
+ image.save(temp_filename, 'JPEG', quality=quality)
56
+ temp_image = Image.open(temp_filename)
57
+
58
+ ela_image = ImageChops.difference(image, temp_image)
59
+ extrema = ela_image.getextrema()
60
+ max_diff = max([ex[1] for ex in extrema])
61
+ max_diff = max_diff if max_diff != 0 else 1
62
+ scale = 255.0 / max_diff
63
+
64
+ ela_image = ImageEnhance.Brightness(ela_image).enhance(scale)
65
+ return ela_image
66
+
67
+ def prepare_image_for_forgery(image):
68
+ ela_image = convert_to_ela_image(image, 90).resize((128, 128))
69
+ return np.array(ela_image).flatten() / 255.0
70
+
71
+ # Advanced Analysis Functions
72
+ def detect_copy_move_forgery_advanced(image):
73
+ """Advanced copy-move forgery detection using multiple techniques"""
74
+ # Convert to grayscale
75
+ gray = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2GRAY)
76
+
77
+ # Parameters
78
+ block_size = 16
79
+ overlap_threshold = 8
80
+ correlation_threshold = 0.85
81
+ min_distance = 32 # Minimum distance between blocks to avoid self-matching
82
+
83
+ h, w = gray.shape
84
+ matches = []
85
+
86
+ # Extract overlapping blocks with their descriptors
87
+ blocks = []
88
+ positions = []
89
+
90
+ for i in range(0, h - block_size, overlap_threshold):
91
+ for j in range(0, w - block_size, overlap_threshold):
92
+ block = gray[i:i+block_size, j:j+block_size]
93
+
94
+ # Multiple feature descriptors for better matching
95
+ # 1. Raw block data
96
+ block_flat = block.flatten()
97
+
98
+ # 2. DCT coefficients (frequency domain)
99
+ dct_block = cv2.dct(np.float32(block))
100
+ dct_flat = dct_block.flatten()
101
+
102
+ # 3. LBP (Local Binary Pattern) for texture
103
+ lbp = feature.local_binary_pattern(block, 8, 1, method='uniform')
104
+ lbp_hist, _ = np.histogram(lbp.ravel(), bins=10, range=(0, 10))
105
+
106
+ # Combine features
107
+ descriptor = np.concatenate([
108
+ block_flat / 255.0, # Normalized pixel values
109
+ dct_flat / np.max(np.abs(dct_flat)) if np.max(np.abs(dct_flat)) > 0 else dct_flat, # Normalized DCT
110
+ lbp_hist / np.sum(lbp_hist) if np.sum(lbp_hist) > 0 else lbp_hist # LBP histogram
111
+ ])
112
+
113
+ blocks.append(descriptor)
114
+ positions.append((j + block_size//2, i + block_size//2))
115
+
116
+ # Advanced matching using multiple similarity metrics
117
+ for idx1, (block1, pos1) in enumerate(zip(blocks, positions)):
118
+ for idx2, (block2, pos2) in enumerate(zip(blocks[idx1+1:], positions[idx1+1:]), idx1+1):
119
+ # Skip if blocks are too close (likely same region)
120
+ distance = np.sqrt((pos1[0] - pos2[0])**2 + (pos1[1] - pos2[1])**2)
121
+ if distance < min_distance:
122
+ continue
123
+
124
+ # Multiple similarity measures
125
+ # 1. Normalized Cross Correlation
126
+ correlation = np.corrcoef(block1[:block_size*block_size], block2[:block_size*block_size])[0, 1]
127
+
128
+ # 2. Structural Similarity (simplified)
129
+ ssim = 1 - np.mean((block1 - block2)**2) / (np.var(block1) + np.var(block2) + 1e-10)
130
+
131
+ # 3. Cosine similarity
132
+ cosine_sim = np.dot(block1, block2) / (np.linalg.norm(block1) * np.linalg.norm(block2) + 1e-10)
133
+
134
+ # Combined similarity score
135
+ combined_score = (correlation + ssim + cosine_sim) / 3
136
+
137
+ if combined_score > correlation_threshold and not np.isnan(combined_score):
138
+ matches.append((pos1, pos2, combined_score))
139
+
140
+ # Post-processing: Remove duplicate matches and cluster nearby matches
141
+ filtered_matches = []
142
+ for match in sorted(matches, key=lambda x: x[2], reverse=True):
143
+ pos1, pos2, score = match
144
+
145
+ # Check if this match is too similar to existing ones
146
+ is_duplicate = False
147
+ for existing_match in filtered_matches:
148
+ existing_pos1, existing_pos2, _ = existing_match
149
+ if (abs(pos1[0] - existing_pos1[0]) < 20 and abs(pos1[1] - existing_pos1[1]) < 20 and
150
+ abs(pos2[0] - existing_pos2[0]) < 20 and abs(pos2[1] - existing_pos2[1]) < 20):
151
+ is_duplicate = True
152
+ break
153
+
154
+ if not is_duplicate:
155
+ filtered_matches.append(match)
156
+ if len(filtered_matches) >= 20: # Limit to top 20 matches
157
+ break
158
+
159
+ return filtered_matches
160
+
161
+ def detect_splicing_regions(image):
162
+ """Detect potential splicing/tampering regions using edge inconsistencies"""
163
+ # Convert to grayscale
164
+ gray = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2GRAY)
165
+
166
+ # Apply different edge detection methods
167
+ edges_canny = cv2.Canny(gray, 50, 150)
168
+ edges_sobel = cv2.Sobel(gray, cv2.CV_64F, 1, 1, ksize=3)
169
+ edges_sobel = np.uint8(np.absolute(edges_sobel))
170
+
171
+ # Find inconsistent regions
172
+ diff = cv2.absdiff(edges_canny, edges_sobel)
173
+
174
+ # Threshold and find contours
175
+ _, thresh = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY)
176
+ contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
177
+
178
+ # Filter contours by area
179
+ suspicious_regions = []
180
+ for contour in contours:
181
+ area = cv2.contourArea(contour)
182
+ if area > 100: # Minimum area threshold
183
+ x, y, w, h = cv2.boundingRect(contour)
184
+ suspicious_regions.append((x, y, w, h))
185
+
186
+ return suspicious_regions
187
+
188
+ def analyze_noise_patterns(image):
189
+ """Analyze noise patterns to detect inconsistencies"""
190
+ # Convert to grayscale
191
+ gray = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2GRAY)
192
+
193
+ # Apply Gaussian blur and subtract to get noise
194
+ blurred = cv2.GaussianBlur(gray, (3, 3), 0)
195
+ noise = cv2.absdiff(gray, blurred)
196
+
197
+ # Divide image into blocks and calculate noise variance
198
+ block_size = 32
199
+ h, w = gray.shape
200
+ noise_map = np.zeros((h//block_size, w//block_size))
201
+
202
+ for i in range(0, h - block_size, block_size):
203
+ for j in range(0, w - block_size, block_size):
204
+ block = noise[i:i+block_size, j:j+block_size]
205
+ noise_map[i//block_size, j//block_size] = np.var(block)
206
+
207
+ return noise_map, noise
208
+
209
+ # Individual Analysis Functions
210
+ def create_ela_analysis(image):
211
+ """Create ELA analysis visualization"""
212
+ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))
213
+ fig.suptitle('Error Level Analysis (ELA)', fontsize=14, fontweight='bold')
214
+
215
+ # Original image
216
+ ax1.imshow(image)
217
+ ax1.set_title('Original Image')
218
+ ax1.axis('off')
219
+
220
+ # ELA image
221
+ ela_image = convert_to_ela_image(image, 90)
222
+ ax2.imshow(ela_image)
223
+ ax2.set_title('ELA Result (Bright areas indicate potential editing)')
224
+ ax2.axis('off')
225
+
226
+ plt.tight_layout()
227
+
228
+ buffer = io.BytesIO()
229
+ plt.savefig(buffer, format='png', dpi=150, bbox_inches='tight')
230
+ buffer.seek(0)
231
+ plt.close()
232
+
233
+ return buffer
234
+
235
+ def create_copy_move_analysis(image):
236
+ """Create copy-move detection visualization"""
237
+ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))
238
+ fig.suptitle('Advanced Copy-Move Forgery Detection', fontsize=14, fontweight='bold')
239
+
240
+ # Original image
241
+ ax1.imshow(image)
242
+ ax1.set_title('Original Image')
243
+ ax1.axis('off')
244
+
245
+ # Copy-move detection
246
+ copy_move_matches = detect_copy_move_forgery_advanced(image)
247
+ ax2.imshow(image)
248
+ ax2.set_title(f'Copy-Move Detection ({len(copy_move_matches)} matches found)')
249
+
250
+ # Draw copy-move connections with confidence scores
251
+ colors = plt.cm.RdYlGn(np.linspace(0.3, 1, len(copy_move_matches)))
252
+
253
+ for i, (match, color) in enumerate(zip(copy_move_matches, colors)):
254
+ if len(match) == 3: # Advanced version with score
255
+ point1, point2, score = match
256
+ # Red dot for source
257
+ ax2.plot(point1[0], point1[1], 'o', color='red', markersize=5)
258
+ # Green dot for destination
259
+ ax2.plot(point2[0], point2[1], 'o', color='lime', markersize=5)
260
+ # Line with color based on confidence
261
+ ax2.plot([point1[0], point2[0]], [point1[1], point2[1]],
262
+ color=color, linewidth=2, alpha=0.8)
263
+ # Add confidence score as text
264
+ mid_x, mid_y = (point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2
265
+ ax2.text(mid_x, mid_y, f'{score:.2f}', fontsize=8,
266
+ bbox=dict(boxstyle="round,pad=0.1", facecolor='white', alpha=0.7))
267
+ else: # Simple version
268
+ point1, point2 = match
269
+ ax2.plot(point1[0], point1[1], 'ro', markersize=4)
270
+ ax2.plot(point2[0], point2[1], 'go', markersize=4)
271
+ ax2.plot([point1[0], point2[0]], [point1[1], point2[1]], 'g-', linewidth=1, alpha=0.7)
272
+
273
+ ax2.axis('off')
274
+
275
+ plt.tight_layout()
276
+
277
+ buffer = io.BytesIO()
278
+ plt.savefig(buffer, format='png', dpi=150, bbox_inches='tight')
279
+ buffer.seek(0)
280
+ plt.close()
281
+
282
+ return buffer
283
+
284
+ def create_tampering_analysis(image):
285
+ """Create tampering/splicing detection visualization"""
286
+ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))
287
+ fig.suptitle('Tampering/Splicing Detection', fontsize=14, fontweight='bold')
288
+
289
+ # Original image
290
+ ax1.imshow(image)
291
+ ax1.set_title('Original Image')
292
+ ax1.axis('off')
293
+
294
+ # Tampering detection
295
+ suspicious_regions = detect_splicing_regions(image)
296
+ ax2.imshow(image)
297
+ ax2.set_title(f'Suspicious Regions ({len(suspicious_regions)} found)')
298
+
299
+ # Highlight suspicious regions with different colors
300
+ colors = ['red', 'orange', 'yellow', 'purple', 'pink']
301
+ for i, region in enumerate(suspicious_regions):
302
+ x, y, w, h = region
303
+ color = colors[i % len(colors)]
304
+ rect = patches.Rectangle((x, y), w, h, linewidth=2,
305
+ edgecolor=color, facecolor='none', alpha=0.8)
306
+ ax2.add_patch(rect)
307
+ # Add region number
308
+ ax2.text(x, y-5, f'R{i+1}', fontsize=10, color=color, fontweight='bold')
309
+
310
+ ax2.axis('off')
311
+
312
+ plt.tight_layout()
313
+
314
+ buffer = io.BytesIO()
315
+ plt.savefig(buffer, format='png', dpi=150, bbox_inches='tight')
316
+ buffer.seek(0)
317
+ plt.close()
318
+
319
+ return buffer
320
+
321
+ def create_noise_analysis(image):
322
+ """Create noise pattern analysis visualization"""
323
+ fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(12, 10))
324
+ fig.suptitle('Noise Pattern Analysis', fontsize=14, fontweight='bold')
325
+
326
+ # Original image
327
+ ax1.imshow(image)
328
+ ax1.set_title('Original Image')
329
+ ax1.axis('off')
330
+
331
+ # Noise analysis
332
+ noise_map, noise = analyze_noise_patterns(image)
333
+
334
+ # Noise map
335
+ im1 = ax2.imshow(noise_map, cmap='hot', interpolation='nearest')
336
+ ax2.set_title('Noise Variance Map')
337
+ ax2.axis('off')
338
+ plt.colorbar(im1, ax=ax2, shrink=0.8)
339
+
340
+ # Raw noise
341
+ ax3.imshow(noise, cmap='gray')
342
+ ax3.set_title('Extracted Noise')
343
+ ax3.axis('off')
344
+
345
+ # Noise histogram
346
+ ax4.hist(noise.flatten(), bins=50, alpha=0.7, color='blue')
347
+ ax4.set_title('Noise Distribution')
348
+ ax4.set_xlabel('Noise Level')
349
+ ax4.set_ylabel('Frequency')
350
+ ax4.grid(True, alpha=0.3)
351
+
352
+ plt.tight_layout()
353
+
354
+ buffer = io.BytesIO()
355
+ plt.savefig(buffer, format='png', dpi=150, bbox_inches='tight')
356
+ buffer.seek(0)
357
+ plt.close()
358
+
359
+ return buffer
360
+
361
+
362
+ # Deepfake Image Detection
363
+ def predict_deepfake_image(image_path, model):
364
+ img = keras_image.load_img(image_path, target_size=(256, 256))
365
+ img_array = keras_image.img_to_array(img) / 255.0
366
+ img_array = np.expand_dims(img_array, axis=0)
367
+ prediction = model.predict(img_array)
368
+ return 'Real' if prediction[0] > 0.5 else 'Fake'
369
+
370
+ # Video Forgery Detection
371
+ # Configuration
372
+ target_height, target_width = 240, 320
373
+ threshold = 30 # Threshold for freeze/duplicate detection
374
+
375
+ def predict_video_forgery_cnn(video_path, model):
376
+ """CNN-based video forgery detection"""
377
+ vid = []
378
+ sumframes = 0
379
+ cap = cv2.VideoCapture(video_path)
380
+
381
+ while cap.isOpened():
382
+ ret, frame = cap.read()
383
+ if not ret:
384
+ break
385
+
386
+ # Resize frame to target dimensions
387
+ frame = cv2.resize(frame, (target_width, target_height))
388
+ sumframes += 1
389
+ vid.append(frame)
390
+
391
+ cap.release()
392
+
393
+ if sumframes == 0:
394
+ return False, 0, 0
395
+
396
+ Xtest = np.array(vid)
397
+ output = model.predict(Xtest)
398
+ output = output.reshape((-1))
399
+
400
+ # Check if any frame is predicted as forged
401
+ forged_frames = sum(1 for i in output if i > 0.5)
402
+ is_forged = any(i > 0.5 for i in output)
403
+
404
+ return is_forged, forged_frames, sumframes
405
+
406
+ def analyze_video_tampering(video_path):
407
+ """Frame difference analysis for tampering detection"""
408
+ cap = cv2.VideoCapture(video_path)
409
+ if not cap.isOpened():
410
+ return False, [], []
411
+
412
+ prev_frame = None
413
+ frame_differences = []
414
+ suspected_frames = []
415
+
416
+ while cap.isOpened():
417
+ ret, frame = cap.read()
418
+ if not ret:
419
+ break
420
+
421
+ gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
422
+
423
+ if prev_frame is not None:
424
+ diff = cv2.absdiff(gray, prev_frame)
425
+ non_zero = np.count_nonzero(diff)
426
+ frame_differences.append(non_zero)
427
+
428
+ if non_zero < threshold:
429
+ current_frame = int(cap.get(cv2.CAP_PROP_POS_FRAMES))
430
+ suspected_frames.append(current_frame)
431
+
432
+ prev_frame = gray
433
+
434
+ cap.release()
435
+
436
+ # Simple rule: if any frame is suspected, flag as tampered
437
+ is_tampered = len(suspected_frames) > 0
438
+
439
+ return is_tampered, frame_differences, suspected_frames
440
+
441
+ def plot_frame_analysis(frame_differences):
442
+ """Create a simple plot of frame differences"""
443
+ plt.figure(figsize=(10, 4))
444
+ plt.plot(frame_differences, color='blue', linewidth=1)
445
+ plt.axhline(y=threshold, color='red', linestyle='--', label=f"Threshold ({threshold})")
446
+ plt.xlabel("Frame Number")
447
+ plt.ylabel("Pixel Differences")
448
+ plt.title("Frame Difference Analysis")
449
+ plt.legend()
450
+ plt.grid(True, alpha=0.3)
451
+
452
+ # Add statistics
453
+ if frame_differences:
454
+ mean_val = np.mean(frame_differences)
455
+ std_val = np.std(frame_differences)
456
+ plt.text(0.02, 0.98, f"Mean: {mean_val:.1f}\nStd: {std_val:.1f}",
457
+ transform=plt.gca().transAxes, verticalalignment='top',
458
+ bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
459
+
460
+ return plt
461
+
462
+ def combined_video_forgery_detection(video_path, model):
463
+ """Combined detection using both CNN and frame analysis"""
464
+
465
+ # Method 1: CNN-based detection
466
+ cnn_forged, cnn_forged_frames, total_frames = predict_video_forgery_cnn(video_path, model)
467
+
468
+ # Method 2: Frame analysis tampering detection
469
+ frame_tampered, frame_differences, suspected_frames = analyze_video_tampering(video_path)
470
+
471
+ # Results
472
+ results = {
473
+ 'cnn_forged': cnn_forged,
474
+ 'cnn_forged_frames': cnn_forged_frames,
475
+ 'frame_tampered': frame_tampered,
476
+ 'suspected_frames': len(suspected_frames),
477
+ 'total_frames': total_frames,
478
+ 'frame_differences': frame_differences
479
+ }
480
+
481
+ # Simple decision logic
482
+ if cnn_forged and frame_tampered:
483
+ verdict = "FORGED - Detected by both CNN and Frame Analysis"
484
+ confidence = "High"
485
+ elif cnn_forged:
486
+ verdict = "FORGED - Detected by CNN"
487
+ confidence = "Medium"
488
+ elif frame_tampered:
489
+ verdict = "FORGED - Detected by Frame Analysis"
490
+ confidence = "Medium"
491
+ else:
492
+ verdict = "NOT TAMPERED - No Forgery detected"
493
+ confidence = "High"
494
+
495
+ return verdict, confidence, results
496
+
497
+ # Deepfake Video Detection
498
+ def build_feature_extractor():
499
+ feature_extractor = keras.applications.InceptionV3(
500
+ weights="imagenet",
501
+ include_top=False,
502
+ pooling="avg",
503
+ input_shape=(IMG_SIZE, IMG_SIZE, 3),
504
+ )
505
+ preprocess_input = keras.applications.inception_v3.preprocess_input
506
+
507
+ inputs = keras.Input((IMG_SIZE, IMG_SIZE, 3))
508
+ preprocessed = preprocess_input(inputs)
509
+ outputs = feature_extractor(preprocessed)
510
+ return keras.Model(inputs, outputs, name="feature_extractor")
511
+
512
+ feature_extractor = build_feature_extractor()
513
+ detector = MTCNN()
514
+
515
+ def load_video(path, max_frames=0, resize=(IMG_SIZE, IMG_SIZE), skip_frames=2):
516
+ cap = cv.VideoCapture(path)
517
+ frames = []
518
+ frame_count = 0
519
+ previous_box = None
520
+
521
+ while True:
522
+ ret, frame = cap.read()
523
+ if not ret:
524
+ break
525
+
526
+ if frame_count % skip_frames == 0:
527
+ frame, previous_box = get_face_region_first_frame(frame, previous_box)
528
+ if frame is not None:
529
+ frame = cv.resize(frame, resize)
530
+ frame = frame[:, :, [2, 1, 0]]
531
+ frames.append(frame)
532
+
533
+ if len(frames) == max_frames:
534
+ break
535
+ frame_count += 1
536
+
537
+ while len(frames) < max_frames and frames:
538
+ frames.append(frames[-1])
539
+
540
+ cap.release()
541
+ return np.array(frames)
542
+
543
+ def get_face_region_first_frame(frame, previous_box=None):
544
+ if previous_box is None:
545
+ detections = detector.detect_faces(frame)
546
+ if detections:
547
+ x, y, width, height = detections[0]['box']
548
+ previous_box = (x, y, width, height)
549
+ else:
550
+ return None, None
551
+ else:
552
+ x, y, width, height = previous_box
553
+
554
+ face_region = frame[y:y+height, x:x+width]
555
+ return face_region, previous_box
556
+
557
+ def prepare_single_video(frames):
558
+ frames = frames[None, ...]
559
+ frame_mask = np.zeros(shape=(1, MAX_SEQ_LENGTH,), dtype="bool")
560
+ frame_features = np.zeros(shape=(1, MAX_SEQ_LENGTH, NUM_FEATURES), dtype="float32")
561
+
562
+ for i, batch in enumerate(frames):
563
+ video_length = batch.shape[0]
564
+ length = min(MAX_SEQ_LENGTH, video_length)
565
+ for j in range(length):
566
+ frame_features[i, j, :] = feature_extractor.predict(batch[None, j, :])
567
+ frame_mask[i, :length] = 1
568
+
569
+ return frame_features, frame_mask
570
+
571
+ def sequence_prediction(video_path):
572
+ class_vocab = label_processor2.get_vocabulary()
573
+ frames = load_video(video_path)
574
+ if len(frames) == 0:
575
+ st.error("Could not process video. Please try another file.")
576
+ return None
577
+
578
+ frame_features, frame_mask = prepare_single_video(frames)
579
+ probabilities = deepfake_model.predict([frame_features, frame_mask])[0]
580
+
581
+ predictions = {class_vocab[i]: probabilities[i] * 100 for i in np.argsort(probabilities)[::-1]}
582
+ return predictions
583
+
584
+
585
+ # Streamlit App
586
+ st.title("Fraudulent Image and Video Detection System")
587
+
588
+ # Sidebar for model selection
589
+ task = st.sidebar.selectbox("Choose a detection task:", [
590
+ "Image Forgery Detection",
591
+ "Deepfake Image Detection",
592
+ "Video Forgery Detection",
593
+ "Deepfake Video Detection"
594
+ ])
595
+
596
+ # Main Streamlit App
597
+ if task == "Image Forgery Detection":
598
+ uploaded_file = st.file_uploader("Upload an image", type=['jpg', 'jpeg', 'png'])
599
+
600
+ if uploaded_file:
601
+ image = Image.open(uploaded_file)
602
+ st.image(image, caption="Uploaded Image", use_container_width=True)
603
+
604
+ # Original prediction
605
+ prepared_image = prepare_image_for_forgery(image).reshape(-1, 128, 128, 3)
606
+ model = load_image_forgery_model()
607
+ prediction = model.predict(prepared_image)
608
+ confidence_real = prediction[0][1] * 100
609
+ confidence_fake = prediction[0][0] * 100
610
+
611
+ if confidence_real > confidence_fake:
612
+ st.success(f"Result: Real Image with {confidence_real:.2f}% confidence")
613
+ else:
614
+ st.error(f"Result: Forged Image with {confidence_fake:.2f}% confidence")
615
+
616
+ # Add analysis options
617
+ st.markdown("---")
618
+ st.subheader("πŸ” Detailed Forgery Analysis")
619
+
620
+ # Analysis type selection
621
+ analysis_type = st.selectbox(
622
+ "Choose Analysis Type:",
623
+ ["Error Level Analysis (ELA)", "Copy-Move Detection", "Tampering Detection", "Noise Analysis"],
624
+ index=0
625
+ )
626
+
627
+ col1, col2 = st.columns([1, 3])
628
+
629
+ with col1:
630
+ analyze_button = st.button("Run Analysis", type="primary", use_container_width=True)
631
+
632
+ with col2:
633
+ st.markdown("### Analysis Guide:")
634
+ if analysis_type == "Error Level Analysis (ELA)":
635
+ st.info("**ELA**: Reveals compression artifacts. Bright areas indicate potential editing or manipulation.")
636
+ elif analysis_type == "Copy-Move Detection":
637
+ st.info("**Copy-Move**: Finds duplicated regions. Red dots show source, green dots show destination, lines show confidence.")
638
+ elif analysis_type == "Tampering Detection":
639
+ st.info("**Tampering**: Detects edge inconsistencies. Colored rectangles highlight suspicious regions.")
640
+ elif analysis_type == "Noise Analysis":
641
+ st.info("**Noise**: Analyzes noise patterns. Hot spots in variance map indicate inconsistent noise.")
642
+
643
+ if analyze_button:
644
+ with st.spinner(f"Running {analysis_type}..."):
645
+ try:
646
+ if analysis_type == "Error Level Analysis (ELA)":
647
+ analysis_buffer = create_ela_analysis(image)
648
+ filename = "ela_analysis.png"
649
+
650
+ elif analysis_type == "Copy-Move Detection":
651
+ analysis_buffer = create_copy_move_analysis(image)
652
+ filename = "copy_move_analysis.png"
653
+
654
+ elif analysis_type == "Tampering Detection":
655
+ analysis_buffer = create_tampering_analysis(image)
656
+ filename = "tampering_analysis.png"
657
+
658
+ elif analysis_type == "Noise Analysis":
659
+ analysis_buffer = create_noise_analysis(image)
660
+ filename = "noise_analysis.png"
661
+
662
+ st.image(analysis_buffer, caption=f"{analysis_type} Results", use_container_width=True)
663
+
664
+ # Detailed results based on analysis type
665
+ if analysis_type == "Copy-Move Detection":
666
+ matches = detect_copy_move_forgery_advanced(image)
667
+ if matches:
668
+ st.success(f"Found {len(matches)} potential copy-move regions")
669
+ with st.expander("Detailed Match Information"):
670
+ for i, match in enumerate(matches[:5]): # Show top 5
671
+ if len(match) == 3:
672
+ pos1, pos2, score = match
673
+ st.write(f"**Match {i+1}**: Confidence {score:.3f}")
674
+ st.write(f" Source: ({pos1[0]}, {pos1[1]}) β†’ Destination: ({pos2[0]}, {pos2[1]})")
675
+ else:
676
+ st.success("No copy-move forgery detected")
677
+
678
+ elif analysis_type == "Tampering Detection":
679
+ regions = detect_splicing_regions(image)
680
+ if regions:
681
+ st.warning(f"Found {len(regions)} suspicious regions")
682
+ with st.expander("Region Details"):
683
+ for i, (x, y, w, h) in enumerate(regions):
684
+ st.write(f"**Region {i+1}**: Position ({x}, {y}), Size {w}Γ—{h}")
685
+ else:
686
+ st.success("No suspicious tampering regions detected")
687
+
688
+ elif analysis_type == "Noise Analysis":
689
+ noise_map, _ = analyze_noise_patterns(image)
690
+ avg_noise = np.mean(noise_map)
691
+ std_noise = np.std(noise_map)
692
+ st.info(f"Average noise variance: {avg_noise:.3f}")
693
+ st.info(f"Noise variance std: {std_noise:.3f}")
694
+ if std_noise > avg_noise * 0.5:
695
+ st.warning("High noise variance detected - possible inconsistent editing")
696
+ else:
697
+ st.success("Noise patterns appear consistent")
698
+
699
+ # Download button
700
+ st.download_button(
701
+ label=f"Download {analysis_type} Results",
702
+ data=analysis_buffer.getvalue(),
703
+ file_name=filename,
704
+ mime="image/png",
705
+ use_container_width=True
706
+ )
707
+
708
+ except Exception as e:
709
+ st.error(f"Error during {analysis_type}: {str(e)}")
710
+ st.info("Some analysis methods may not work with all image types. Try with a different image if needed.")
711
+
712
+
713
+ elif task == "Deepfake Image Detection":
714
+ uploaded_file = st.file_uploader("Upload an image", type=['jpg', 'jpeg', 'png'])
715
+ if uploaded_file:
716
+ with open("temp_image.jpg", "wb") as f:
717
+ f.write(uploaded_file.getbuffer())
718
+
719
+ st.image(uploaded_file, caption="Uploaded Image", use_container_width=True)
720
+ model = load_deepfake_image_model()
721
+ result = predict_deepfake_image("temp_image.jpg", model)
722
+
723
+ if result == 'Real':
724
+ st.success("Prediction: Real")
725
+ else:
726
+ st.error("Prediction: Fake")
727
+
728
+ os.remove("temp_image.jpg")
729
+
730
+ if task == "Video Forgery Detection":
731
+ uploaded_file = st.file_uploader("Upload a video", type=['mp4', 'avi', 'mov', 'mkv'])
732
+
733
+ if uploaded_file:
734
+ # Save uploaded file
735
+ with open("temp_video.mp4", "wb") as f:
736
+ f.write(uploaded_file.getbuffer())
737
+
738
+ st.video("temp_video.mp4")
739
+ st.write("Analyzing the video for forgery...")
740
+
741
+ # Load model and run combined detection
742
+ model = load_video_forgery_model()
743
+ verdict, confidence, results = combined_video_forgery_detection("temp_video.mp4", model)
744
+
745
+ # Display results
746
+ if "FORGED" in verdict:
747
+ st.error(f"🚨 {verdict}")
748
+ else:
749
+ st.success(f"βœ… {verdict}")
750
+
751
+ st.write(f"**Confidence Level:** {confidence}")
752
+
753
+ # Show detailed results
754
+ col1, col2 = st.columns(2)
755
+
756
+ with col1:
757
+ st.write("**CNN Analysis:**")
758
+ if results['cnn_forged']:
759
+ st.write(f"- Status: Forged ❌")
760
+ st.write(f"- Forged Frames: {results['cnn_forged_frames']}/{results['total_frames']}")
761
+ else:
762
+ st.write(f"- Status: Not Forged βœ…")
763
+
764
+ with col2:
765
+ st.write("**Frame Analysis:**")
766
+ if results['frame_tampered']:
767
+ st.write(f"- Status: Tampered ❌")
768
+ st.write(f"- Suspected Frames: {results['suspected_frames']}")
769
+ else:
770
+ st.write(f"- Status: Not Tampered βœ…")
771
+
772
+ # Plot frame differences if available
773
+ if results['frame_differences']:
774
+ st.write("**Frame Difference Analysis:**")
775
+ fig = plot_frame_analysis(results['frame_differences'])
776
+ st.pyplot(fig)
777
+ plt.close()
778
+
779
+ # Cleanup
780
+ os.remove("temp_video.mp4")
781
+
782
+
783
+ elif task == "Deepfake Video Detection":
784
+ uploaded_file = st.file_uploader("Upload a video", type=["mp4", "avi", "mov"])
785
+ if uploaded_file is not None:
786
+ with open("temp_video.mp4", "wb") as f:
787
+ f.write(uploaded_file.read())
788
+
789
+ st.video("temp_video.mp4")
790
+ st.write("Analyzing the video...")
791
+
792
+ frames = load_video("temp_video.mp4")
793
+ if len(frames) == 0:
794
+ st.error("Could not process video. Please try another file.")
795
+ else:
796
+ frame_features, frame_mask = prepare_single_video(frames)
797
+ probabilities = deepfake_model.predict([frame_features, frame_mask])[0]
798
+
799
+ predictions = {label_processor2.get_vocabulary()[i]: probabilities[i] * 100 for i in np.argsort(probabilities)[::-1]}
800
+
801
+ if predictions:
802
+ highest_label = max(predictions, key=predictions.get)
803
+ highest_prob = predictions[highest_label]
804
+
805
+ if highest_label.lower() == "real":
806
+ st.success(f"The video is real with a confidence of {highest_prob:.2f}%.")
807
+ elif highest_label.lower() == "fake":
808
+ st.error(f"This video is a deepfake with a confidence of {highest_prob:.2f}%.")
809
+ else:
810
+ st.warning(f"Uncertain prediction: {highest_label} with {highest_prob:.2f}% confidence.")