File size: 10,623 Bytes
cbd65bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9bc9b0d
 
 
 
 
 
 
 
cbd65bc
 
1ee3c01
cbd65bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9bc9b0d
cbd65bc
9bc9b0d
cbd65bc
 
 
 
9bc9b0d
cbd65bc
 
 
 
 
 
 
9bc9b0d
cbd65bc
 
9bc9b0d
 
cbd65bc
9bc9b0d
 
cbd65bc
 
9bc9b0d
cbd65bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9bc9b0d
 
 
 
cbd65bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9bc9b0d
cbd65bc
9bc9b0d
cbd65bc
 
9bc9b0d
cbd65bc
 
 
 
 
9bc9b0d
 
 
 
 
 
 
 
 
 
cbd65bc
 
 
9bc9b0d
cbd65bc
 
 
 
 
 
 
 
 
 
 
 
9bc9b0d
 
 
 
cbd65bc
9bc9b0d
cbd65bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9bc9b0d
cbd65bc
 
 
9bc9b0d
 
 
 
 
 
cbd65bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9bc9b0d
 
 
 
 
 
 
 
 
cbd65bc
 
 
 
 
 
9bc9b0d
 
 
cbd65bc
9bc9b0d
cbd65bc
9bc9b0d
cbd65bc
 
 
9bc9b0d
cbd65bc
 
 
 
9bc9b0d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cbd65bc
9bc9b0d
 
cbd65bc
9bc9b0d
cbd65bc
 
9bc9b0d
a745881
9bc9b0d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cbd65bc
9bc9b0d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
import streamlit as st
import os
import numpy as np
import cv2
from PIL import Image
import tensorflow as tf
from tensorflow.keras import layers
from tensorflow.keras.applications.xception import preprocess_input
from mtcnn import MTCNN
import time
import pandas as pd
import matplotlib.pyplot as plt
import base64
# TensorFlow log level
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'

# Parameters
TIME_STEPS = 30  # Frames per video
HEIGHT, WIDTH = 299, 299

# Model builder
def build_model(lstm_hidden_size=256, num_classes=2, dropout_rate=0.5):
    inputs = layers.Input(shape=(TIME_STEPS, HEIGHT, WIDTH, 3))
    base_model = tf.keras.applications.Xception(weights='imagenet', include_top=False, pooling='avg')
    x = layers.TimeDistributed(base_model)(inputs)
    x = layers.LSTM(lstm_hidden_size)(x)
    x = layers.Dropout(dropout_rate)(x)
    outputs = layers.Dense(num_classes, activation='softmax')(x)
    model = tf.keras.Model(inputs, outputs)
    return model

# Load model
model_path = r'COMBINED_best_Phase1.keras'
model = build_model()
model.load_weights(model_path)

def preprocess_image(image):
    """
    Preprocess image for model input
    
    Args:
        image (PIL.Image or numpy.ndarray): Input image
    
    Returns:
        numpy.ndarray: Preprocessed image
    """
    # Convert to numpy array if it's a PIL Image
    if isinstance(image, Image.Image):
        image = np.array(image)
    
    # Resize to expected input size
    image = cv2.resize(image, (WIDTH, HEIGHT))
    
    # Preprocess for Xception model
    image = preprocess_input(image)
    
    return image

def extract_faces_from_video(video_path, num_frames=TIME_STEPS, skip_frames=0):
    """
    Extract faces from video with more robust frame selection
    
    Args:
        video_path (str): Path to the video file
        num_frames (int): Number of frames to extract
        skip_frames (int): Number of initial frames to skip
    
    Returns:
        tuple: (video_array, frames) or (None, None) if no faces detected
    """
    detector = MTCNN()
    cap = cv2.VideoCapture(video_path)
    
    # Get total frame count
    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    
    # Validate input parameters
    skip_frames = max(0, min(skip_frames, frame_count - num_frames))
    
    # Calculate frame indices to sample
    frame_indices = np.linspace(skip_frames, frame_count - 1, num_frames, dtype=int)
    
    frames = []
    processed_frames = []
    
    for idx in range(frame_count):
        success, frame = cap.read()
        if not success:
            break
        
        # Check if this frame should be processed
        if idx in frame_indices:
            # Convert to RGB
            frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            
            # Detect faces
            detections = detector.detect_faces(frame_rgb)
            
            if detections:
                # Get the first detected face
                x, y, width, height = detections[0]['box']
                x, y = max(0, x), max(0, y)
                x2, y2 = x + width, y + height
                
                # Extract face
                face = frame_rgb[y:y2, x:x2]
                
                # Convert to PIL Image and preprocess
                face_image = Image.fromarray(face)
                processed_face = preprocess_image(face_image)
                
                frames.append(processed_face)
            else:
                # If no face detected, use a zero array
                frames.append(np.zeros((HEIGHT, WIDTH, 3), dtype=np.float32))
            
            # Stop if we have collected enough frames
            if len(frames) == num_frames:
                break
    
    cap.release()
    
    # If not enough frames were found, pad with the last frame or zeros
    while len(frames) < num_frames:
        if frames:
            frames.append(frames[-1])  # Pad with the last frame
        else:
            frames.append(np.zeros((HEIGHT, WIDTH, 3), dtype=np.float32))
    
    # Convert to numpy array and expand dimensions
    video_array = np.expand_dims(np.array(frames), axis=0)
    
    return video_array, frames

def make_prediction(video_file):
    """
    Make prediction on the uploaded video file
    
    Args:
        video_file: Uploaded video file object
    
    Returns:
        tuple: (predicted_class, probabilities, frames) or (None, None, None) if error
    """
    try:
        # Ensure the directory exists
        os.makedirs('temp', exist_ok=True)
        
        # Save the uploaded file
        temp_video_path = os.path.join('temp', 'temp_video.mp4')
        with open(temp_video_path, "wb") as f:
            f.write(video_file.read())
        
        # Extract faces and video array
        video_array, frames = extract_faces_from_video(temp_video_path)
        
        # Validate the video array
        if video_array is None or video_array.shape[1] != TIME_STEPS:
            st.error("Unable to process video. Please ensure the video contains clear, visible faces.")
            return None, None, None
        
        # Make prediction
        predictions = model.predict(video_array)
        predicted_class = np.argmax(predictions, axis=1)[0]
        probabilities = predictions[0]
        
        return predicted_class, probabilities, frames
    
    except Exception as e:
        st.error(f"An error occurred while processing the video: {str(e)}")
        return None, None, None
    finally:
        # Clean up temporary file
        if os.path.exists(temp_video_path):
            os.remove(temp_video_path)

# (Keep all the previous imports and functions)

# Streamlit UI
st.set_page_config(page_title="Not Ur Face", layout="wide")
st.markdown("<style>h1{font-size: 45px !important;}</style>", unsafe_allow_html=True)

# Create two columns for header and main content
header_col1, header_col2 = st.columns([1, 1])

def get_base64_image(file_path):
    with open(file_path, "rb") as img_file:
        return base64.b64encode(img_file.read()).decode()

# Path to the uploaded image
image_path = "Image2.png"  # Ensure this is the correct path to your saved image

# Convert image to Base64
image_base64 = get_base64_image(image_path)

# Header Section with Image
with header_col1:
    image = Image.open("Image2.png")
    desired_height = 300  # Reduced height
    aspect_ratio = image.width / image.height
    new_width = int(desired_height * aspect_ratio)
    resized_image = image.resize((new_width, desired_height))
    # st.image(resized_image, use_container_width=True)

# Title and Description
with header_col2:
    st.markdown(
    """
    <style>
    .header-container {
        position: relative;
        text-align: center;
        color: white;
        font-family: 'Arial', sans-serif;
    }
    .header-image {
        width: 100%;
        height: 300px;
        object-fit: cover;
    }
    .header-text {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        font-size: 50px;
        font-weight: bold;
        text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.7);
    }
    </style>
    """,
    unsafe_allow_html=True,
)

# HTML content for the header
st.markdown(
    f"""
    <div class="header-container">
        <img src="data:image/png;base64,{image_base64}" class="header-image" />
        <div class="header-text">NOT UR FACE: Video Analysis for Real & Synthetic Detection</div>
    </div>
    """,
    unsafe_allow_html=True,
)

# Sidebar
st.sidebar.title("How It Works")
st.sidebar.markdown(
    """
1. πŸ“€ **Upload Video:** 
   - Choose a video file (mp4, mov, avi) 
   (Disclaimer: this is a test project so it only works for a video with DeepFake within the first 1.5 seconds of the videos so upload the video such that suspected deepfake is within 2 seconds and also not trained on videos fully generated by AI)
2. πŸ” **Process Frames:** 
   - Detect and analyze faces
3. πŸ€– **AI Analysis:** 
   - Predict 'Real' or 'Fake'
4. πŸ“Š **Detailed Results:** 
   - View probabilities and insights
"""
)
st.sidebar.info("My github: sarvansh30")

# Upload video
st.subheader("πŸŽ₯ Upload Your Video")
video_file = st.file_uploader("Choose a video file", type=["mp4", "mov", "avi"], label_visibility="collapsed")
st.markdown(
    """
    <style>
    .fixed-height-col {
        height: 500px; /* Set the height you want */
        display: flex;
        justify-content: center;
        align-items: center;
        border: 1px solid #ccc; /* Optional: Adds a border for visual distinction */
        padding: 10px; /* Optional: Adds padding */
    }
    </style>
    """,
    unsafe_allow_html=True,
)
if video_file is not None:
    # Create columns to make the layout more compact
    video_col, results_col = st.columns([1, 1])
    
    # Video Display
    with video_col:
        st.subheader("Uploaded Video")
        st.video(video_file)
    
    # Processing and Results
    with results_col:
        st.subheader("Analysis")
        start_time = time.time()

        # Loading animation
        with st.spinner("πŸš€ Processing video... Please wait!"):
            predicted_class, probabilities, frames = make_prediction(video_file)

        if predicted_class is None:  # No faces detected
            st.error("No faces detected in the uploaded video. Please upload a different video.")
        else:
            end_time = time.time()
            processing_time = end_time - start_time

            # Display results
            if predicted_class == 0:
                st.success("The video is classified as **Real**!")
            else:
                st.error("The video is classified as **Fake**!")

            st.write(f"**Prediction Confidence:**")
            st.progress(int(probabilities[predicted_class] * 100))

    # Detailed Results Tabs
    tab1, tab2, tab3 = st.tabs(["πŸ“Š Probabilities", "πŸ–ΌοΈ Frame Previews", "⏱️ Processing Time"])

    with tab1:
        st.subheader("Class Probabilities")
        st.bar_chart({"Real": [probabilities[0]], "Fake": [probabilities[1]]})

    with tab2:
        st.subheader("Frame Previews")
        st.write("Key frames analyzed during the process:")
        cols = st.columns(5)
        for i, frame in enumerate(frames[:10]):
            frame = np.clip(frame, 0, 1)
            frame = (frame * 255).astype(np.uint8)
            with cols[i % 5]:
                st.image(frame, caption=f"Frame {i+1}", use_container_width=True)

    with tab3:
        st.subheader("Processing Details")
        st.write(f"**Time Taken:** {processing_time:.2f} seconds")