Vinh.Vu commited on
Commit
c9d361f
·
1 Parent(s): 88c1060

Improve the web app

Browse files
Files changed (2) hide show
  1. App/app.py +67 -33
  2. requirements.txt +2 -3
App/app.py CHANGED
@@ -12,12 +12,28 @@ from werkzeug.utils import secure_filename
12
  import uuid
13
  import threading
14
  from tensorflow.keras.models import load_model
 
 
15
 
16
  logging.basicConfig(
17
  level=logging.INFO,
18
  format='%(asctime)s [%(levelname)s] %(message)s',
19
  datefmt='%Y-%m-%d %H:%M:%S'
20
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  logger = logging.getLogger(__name__)
22
 
23
  app = Flask(__name__)
@@ -32,7 +48,7 @@ MODEL_PATH = os.path.join(os.path.dirname(__file__), '..', 'tmp_checkpoint', 'be
32
  logger.info('Loading model from %s', MODEL_PATH)
33
  model = load_model(MODEL_PATH)
34
  logger.info('Model loaded successfully')
35
- INPUT_SIZE = 128
36
 
37
  # Initialize YOLO face detector
38
  logger.info('Initializing YOLO face detector')
@@ -141,42 +157,60 @@ def create_processed_video(video_path, output_path, face_scores=None):
141
  cap.release()
142
  return
143
 
 
 
144
  frame_count = 0
 
 
145
  while cap.isOpened():
146
  ret, frame = cap.read()
147
  if not ret:
148
  break
149
- image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
150
- results = face_detector(frame, verbose=False)[0]
151
- for box in results.boxes:
152
- if box.conf[0] > 0.5:
153
- bx1, by1, bx2, by2 = map(int, box.xyxy[0])
154
- bw = bx2 - bx1
155
- bh = by2 - by1
156
- x, y = max(0, bx1), max(0, by1)
157
-
158
- # Crop and predict this face individually
159
- margin_x = int(bw * 0.3)
160
- margin_y = int(bh * 0.3)
161
- x1 = max(0, bx1 - margin_x)
162
- x2 = min(w, bx2 + margin_x)
163
- y1 = max(0, by1 - margin_y)
164
- y2 = min(h, by2 + margin_y)
165
- crop = image_rgb[y1:y2, x1:x2]
166
- if crop.size > 0:
167
- crop_resized = cv2.resize(crop, (INPUT_SIZE, INPUT_SIZE))
168
- face_input = np.array([crop_resized], dtype='float32') / 255.0
169
- score = float(model.predict(face_input, verbose=0)[0][0])
170
- else:
171
- score = 0.0
172
-
173
- is_real = score > 0.5
174
- label = 'REAL' if is_real else 'FAKE'
175
- color = (0, 255, 0) if is_real else (0, 0, 255)
176
- cv2.rectangle(frame, (x, y), (bx2, by2), color, 2)
177
- text = f'{label} {score:.2f}'
178
- cv2.putText(frame, text, (x, y - 10),
179
- cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  out.write(frame)
181
  frame_count += 1
182
 
@@ -204,7 +238,7 @@ def predict_deepfake(faces):
204
 
205
  logger.info('Running prediction on %d face(s)', len(faces))
206
 
207
- face_array = np.array(faces, dtype='float32') / 255.0
208
  predictions = model.predict(face_array, verbose=0)
209
  avg_prediction = float(np.mean(predictions))
210
 
 
12
  import uuid
13
  import threading
14
  from tensorflow.keras.models import load_model
15
+ from tensorflow.keras.applications.efficientnet import preprocess_input
16
+ import keras.src.layers.normalization.batch_normalization as _bn_module
17
 
18
  logging.basicConfig(
19
  level=logging.INFO,
20
  format='%(asctime)s [%(levelname)s] %(message)s',
21
  datefmt='%Y-%m-%d %H:%M:%S'
22
  )
23
+
24
+ # Monkey-patch BatchNormalization to accept legacy renorm kwargs
25
+ _OrigBN = _bn_module.BatchNormalization
26
+ _orig_bn_init = _OrigBN.__init__
27
+
28
+
29
+ def _patched_bn_init(self, *args, **kwargs):
30
+ kwargs.pop('renorm', None)
31
+ kwargs.pop('renorm_clipping', None)
32
+ kwargs.pop('renorm_momentum', None)
33
+ _orig_bn_init(self, *args, **kwargs)
34
+
35
+
36
+ _OrigBN.__init__ = _patched_bn_init
37
  logger = logging.getLogger(__name__)
38
 
39
  app = Flask(__name__)
 
48
  logger.info('Loading model from %s', MODEL_PATH)
49
  model = load_model(MODEL_PATH)
50
  logger.info('Model loaded successfully')
51
+ INPUT_SIZE = 224
52
 
53
  # Initialize YOLO face detector
54
  logger.info('Initializing YOLO face detector')
 
157
  cap.release()
158
  return
159
 
160
+ # Only run detection every N frames; reuse cached overlays in between
161
+ detect_interval = max(1, int(fps // 3)) # ~3 detections per second
162
  frame_count = 0
163
+ cached_overlays = [] # list of (x, y, bx2, by2, label, score, color)
164
+
165
  while cap.isOpened():
166
  ret, frame = cap.read()
167
  if not ret:
168
  break
169
+
170
+ if frame_count % detect_interval == 0:
171
+ image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
172
+ results = face_detector(frame, verbose=False)[0]
173
+ cached_overlays = []
174
+ face_crops = []
175
+ box_coords = []
176
+
177
+ for box in results.boxes:
178
+ if box.conf[0] > 0.5:
179
+ bx1, by1, bx2, by2 = map(int, box.xyxy[0])
180
+ bw = bx2 - bx1
181
+ bh = by2 - by1
182
+ x, y = max(0, bx1), max(0, by1)
183
+
184
+ margin_x = int(bw * 0.3)
185
+ margin_y = int(bh * 0.3)
186
+ x1 = max(0, bx1 - margin_x)
187
+ x2 = min(w, bx2 + margin_x)
188
+ y1 = max(0, by1 - margin_y)
189
+ y2 = min(h, by2 + margin_y)
190
+ crop = image_rgb[y1:y2, x1:x2]
191
+ if crop.size > 0:
192
+ crop_resized = cv2.resize(crop, (INPUT_SIZE, INPUT_SIZE))
193
+ face_crops.append(crop_resized)
194
+ box_coords.append((x, y, bx2, by2))
195
+
196
+ # Batch-predict all faces at once
197
+ if face_crops:
198
+ batch = preprocess_input(np.array(face_crops, dtype='float32'))
199
+ scores = model.predict(batch, verbose=0).flatten()
200
+ for (x, y, bx2, by2), score in zip(box_coords, scores):
201
+ score = float(score)
202
+ is_real = score > 0.5
203
+ label = 'REAL' if is_real else 'FAKE'
204
+ color = (0, 255, 0) if is_real else (0, 0, 255)
205
+ cached_overlays.append((x, y, bx2, by2, label, score, color))
206
+
207
+ # Draw cached overlays on every frame
208
+ for (x, y, bx2, by2, label, score, color) in cached_overlays:
209
+ cv2.rectangle(frame, (x, y), (bx2, by2), color, 2)
210
+ text = f'{label} {score:.2f}'
211
+ cv2.putText(frame, text, (x, y - 10),
212
+ cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2)
213
+
214
  out.write(frame)
215
  frame_count += 1
216
 
 
238
 
239
  logger.info('Running prediction on %d face(s)', len(faces))
240
 
241
+ face_array = preprocess_input(np.array(faces, dtype='float32'))
242
  predictions = model.predict(face_array, verbose=0)
243
  avg_prediction = float(np.mean(predictions))
244
 
requirements.txt CHANGED
@@ -1,13 +1,12 @@
1
  numpy
2
  pandas
3
  tensorflow
4
- keras>=2.2.0
5
  opencv-python>=4.1.0
6
  mtcnn>=0.1.0
7
- h5py
8
  split_folders
9
  flask
10
  werkzeug
11
  ultralytics
12
  imageio-ffmpeg
13
- pillow
 
 
1
  numpy
2
  pandas
3
  tensorflow
 
4
  opencv-python>=4.1.0
5
  mtcnn>=0.1.0
 
6
  split_folders
7
  flask
8
  werkzeug
9
  ultralytics
10
  imageio-ffmpeg
11
+ pillow
12
+ scikit-learn