Vinh Vu commited on
Commit
0bccca4
·
1 Parent(s): 04a8c82

Update crop faces with mtcnn

Browse files
01-crop_faces_with_mtcnn.py CHANGED
@@ -12,67 +12,88 @@ print(physical_devices)
12
  if physical_devices:
13
  tf.config.experimental.set_memory_growth(physical_devices[0], True)
14
 
15
- base_path = '.\\train_sample_videos\\'
16
- videos_path = os.path.join(base_path, 'Deepfakes')
17
 
18
  def get_filename_only(file_path):
19
  file_basename = os.path.basename(file_path)
20
  filename_only = file_basename.split('.')[0]
21
  return filename_only
22
 
23
- with open(os.path.join(base_path, 'csv', 'Deepfakes.csv'), newline='', encoding='utf-8') as csvfile:
24
- reader = csv.DictReader(csvfile)
25
- metadata = {}
26
- for row in reader:
27
- metadata[row['File Path']] = row['Label'].strip().upper()
28
- print(len(metadata))
29
 
30
- for filename in metadata.keys():
31
- video_basename = os.path.basename(filename)
32
- tmp_path = os.path.join(videos_path, get_filename_only(video_basename))
33
- print('Processing Directory: ' + tmp_path)
34
- faces_path = os.path.join(tmp_path, 'faces')
35
- if os.path.isdir(faces_path) and len(os.listdir(faces_path)) > 0:
36
- print('Skipping (faces already exist): ' + faces_path)
37
  continue
38
- frame_images = [x for x in os.listdir(tmp_path) if os.path.isfile(os.path.join(tmp_path, x))]
39
- print('Creating Directory: ' + faces_path)
40
- os.makedirs(faces_path, exist_ok=True)
41
- print('Cropping Faces from Images...')
42
 
43
- for frame in frame_images:
44
- print('Processing ', frame)
45
- detector = MTCNN()
46
- image = cv2.cvtColor(cv2.imread(os.path.join(tmp_path, frame)), cv2.COLOR_BGR2RGB)
47
- results = detector.detect_faces(image)
48
- print('Face Detected: ', len(results))
49
- count = 0
50
-
51
- for result in results:
52
- bounding_box = result['box']
53
- print(bounding_box)
54
- confidence = result['confidence']
55
- print(confidence)
56
- if len(results) < 2 or confidence > 0.95:
57
- margin_x = bounding_box[2] * 0.3 # 30% as the margin
58
- margin_y = bounding_box[3] * 0.3 # 30% as the margin
59
- x1 = int(bounding_box[0] - margin_x)
60
- if x1 < 0:
61
- x1 = 0
62
- x2 = int(bounding_box[0] + bounding_box[2] + margin_x)
63
- if x2 > image.shape[1]:
64
- x2 = image.shape[1]
65
- y1 = int(bounding_box[1] - margin_y)
66
- if y1 < 0:
67
- y1 = 0
68
- y2 = int(bounding_box[1] + bounding_box[3] + margin_y)
69
- if y2 > image.shape[0]:
70
- y2 = image.shape[0]
71
- print(x1, y1, x2, y2)
72
- crop_image = image[y1:y2, x1:x2]
73
- new_filename = '{}-{:02d}.png'.format(os.path.join(faces_path, get_filename_only(frame)), count)
74
- count = count + 1
75
- cv2.imwrite(new_filename, cv2.cvtColor(crop_image, cv2.COLOR_RGB2BGR))
76
- else:
77
- print('Skipped a face..')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
 
12
  if physical_devices:
13
  tf.config.experimental.set_memory_growth(physical_devices[0], True)
14
 
15
+ base_path = '.\\train_sample_videos\\FaceForensics++_C23\\'
 
16
 
17
  def get_filename_only(file_path):
18
  file_basename = os.path.basename(file_path)
19
  filename_only = file_basename.split('.')[0]
20
  return filename_only
21
 
22
+ # Iterate over all subfolders in base_path (excluding 'csv')
23
+ for folder_name in sorted(os.listdir(base_path)):
24
+ folder_path = os.path.join(base_path, folder_name)
25
+ if not os.path.isdir(folder_path) or folder_name == 'csv':
26
+ continue
 
27
 
28
+ csv_file = os.path.join(base_path, 'csv', folder_name + '.csv')
29
+ if not os.path.isfile(csv_file):
30
+ print(f'CSV not found for {folder_name}, skipping: {csv_file}')
 
 
 
 
31
  continue
 
 
 
 
32
 
33
+ print(f'\n{"="*60}')
34
+ print(f'Processing folder: {folder_name}')
35
+ print(f'{"="*60}')
36
+
37
+ with open(csv_file, newline='', encoding='utf-8') as csvfile:
38
+ reader = csv.DictReader(csvfile)
39
+ metadata = {}
40
+ for row in reader:
41
+ metadata[row['File Path']] = row['Label'].strip().upper()
42
+ print(f'{folder_name}: {len(metadata)} entries')
43
+
44
+ for filename in metadata.keys():
45
+ video_basename = os.path.basename(filename)
46
+ tmp_path = os.path.join(folder_path, get_filename_only(video_basename))
47
+ print('Processing Directory: ' + tmp_path)
48
+ faces_path = os.path.join(tmp_path, 'faces')
49
+ if os.path.isdir(faces_path) and len(os.listdir(faces_path)) > 0:
50
+ print('Skipping (faces already exist): ' + faces_path)
51
+ continue
52
+ if not os.path.isdir(tmp_path):
53
+ print('Directory not found, skipping: ' + tmp_path)
54
+ continue
55
+ frame_images = [x for x in os.listdir(tmp_path) if os.path.isfile(os.path.join(tmp_path, x))]
56
+ print('Creating Directory: ' + faces_path)
57
+ os.makedirs(faces_path, exist_ok=True)
58
+ print('Cropping Faces from Images...')
59
+
60
+ for frame in frame_images:
61
+ print('Processing ', frame)
62
+ try:
63
+ detector = MTCNN()
64
+ image = cv2.cvtColor(cv2.imread(os.path.join(tmp_path, frame)), cv2.COLOR_BGR2RGB)
65
+ results = detector.detect_faces(image)
66
+ except Exception as e:
67
+ print(f'Error detecting faces in {frame}: {e}')
68
+ continue
69
+ print('Face Detected: ', len(results))
70
+ count = 0
71
+
72
+ for result in results:
73
+ bounding_box = result['box']
74
+ print(bounding_box)
75
+ confidence = result['confidence']
76
+ print(confidence)
77
+ if len(results) < 2 or confidence > 0.95:
78
+ margin_x = bounding_box[2] * 0.3 # 30% as the margin
79
+ margin_y = bounding_box[3] * 0.3 # 30% as the margin
80
+ x1 = int(bounding_box[0] - margin_x)
81
+ if x1 < 0:
82
+ x1 = 0
83
+ x2 = int(bounding_box[0] + bounding_box[2] + margin_x)
84
+ if x2 > image.shape[1]:
85
+ x2 = image.shape[1]
86
+ y1 = int(bounding_box[1] - margin_y)
87
+ if y1 < 0:
88
+ y1 = 0
89
+ y2 = int(bounding_box[1] + bounding_box[3] + margin_y)
90
+ if y2 > image.shape[0]:
91
+ y2 = image.shape[0]
92
+ print(x1, y1, x2, y2)
93
+ crop_image = image[y1:y2, x1:x2]
94
+ new_filename = '{}-{:02d}.png'.format(os.path.join(faces_path, get_filename_only(frame)), count)
95
+ count = count + 1
96
+ cv2.imwrite(new_filename, cv2.cvtColor(crop_image, cv2.COLOR_RGB2BGR))
97
+ else:
98
+ print('Skipped a face..')
99
 
App/app.py CHANGED
@@ -8,9 +8,7 @@ import subprocess
8
  import cv2
9
  import numpy as np
10
  import imageio_ffmpeg
11
- import mediapipe as mp
12
- from mediapipe.tasks.python import BaseOptions
13
- from mediapipe.tasks.python.vision import FaceDetector, FaceDetectorOptions
14
  from flask import Flask, request, render_template, send_from_directory, jsonify
15
  from werkzeug.utils import secure_filename
16
  import uuid
@@ -42,14 +40,11 @@ sys.stderr = _stderr
42
  logger.info('Model loaded successfully')
43
  INPUT_SIZE = 128
44
 
45
- # Initialize MediaPipe face detector
46
- logger.info('Initializing MediaPipe face detector')
47
- FACE_MODEL_PATH = os.path.join(os.path.dirname(__file__), 'blaze_face_short_range.tflite')
48
- face_detector_options = FaceDetectorOptions(
49
- base_options=BaseOptions(model_asset_path=FACE_MODEL_PATH),
50
- min_detection_confidence=0.5
51
- )
52
- logger.info('MediaPipe face detector ready')
53
 
54
  # In-memory job store: job_id -> {status, result, ...}
55
  jobs = {}
@@ -103,32 +98,30 @@ def extract_faces_from_video(video_path):
103
  cap.release()
104
  return faces
105
 
106
- with FaceDetector.create_from_options(face_detector_options) as face_det:
107
- while cap.isOpened():
108
- frame_id = cap.get(cv2.CAP_PROP_POS_FRAMES)
109
- ret, frame = cap.read()
110
- if not ret:
111
- break
112
- if frame_id % math.floor(frame_rate) == 0:
113
- image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
114
- mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=image_rgb)
115
- results = face_det.detect(mp_image)
116
- for detection in results.detections:
117
- score = detection.categories[0].score
118
- if score > 0.5:
119
- bbox = detection.bounding_box
120
- bx, by, bw, bh = bbox.origin_x, bbox.origin_y, bbox.width, bbox.height
121
- h, w = image_rgb.shape[:2]
122
- margin_x = int(bw * 0.3)
123
- margin_y = int(bh * 0.3)
124
- x1 = max(0, bx - margin_x)
125
- x2 = min(w, bx + bw + margin_x)
126
- y1 = max(0, by - margin_y)
127
- y2 = min(h, by + bh + margin_y)
128
- crop = image_rgb[y1:y2, x1:x2]
129
- if crop.size > 0:
130
- crop_resized = cv2.resize(crop, (INPUT_SIZE, INPUT_SIZE))
131
- faces.append(crop_resized)
132
 
133
  cap.release()
134
  logger.info('Face extraction complete — %d faces found', len(faces))
@@ -155,45 +148,43 @@ def create_processed_video(video_path, output_path, face_scores=None):
155
  return
156
 
157
  frame_count = 0
158
- with FaceDetector.create_from_options(face_detector_options) as face_det:
159
- while cap.isOpened():
160
- ret, frame = cap.read()
161
- if not ret:
162
- break
163
- image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
164
- mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=image_rgb)
165
- results = face_det.detect(mp_image)
166
- for detection in results.detections:
167
- det_score = detection.categories[0].score
168
- if det_score > 0.5:
169
- bbox = detection.bounding_box
170
- bx, by, bw, bh = bbox.origin_x, bbox.origin_y, bbox.width, bbox.height
171
- x, y = max(0, bx), max(0, by)
172
-
173
- # Crop and predict this face individually
174
- margin_x = int(bw * 0.3)
175
- margin_y = int(bh * 0.3)
176
- x1 = max(0, bx - margin_x)
177
- x2 = min(w, bx + bw + margin_x)
178
- y1 = max(0, by - margin_y)
179
- y2 = min(h, by + bh + margin_y)
180
- crop = image_rgb[y1:y2, x1:x2]
181
- if crop.size > 0:
182
- crop_resized = cv2.resize(crop, (INPUT_SIZE, INPUT_SIZE))
183
- face_input = np.array([crop_resized], dtype='float32') / 255.0
184
- score = float(model.predict(face_input, verbose=0)[0][0])
185
- else:
186
- score = 0.0
187
-
188
- is_real = score > 0.5
189
- label = 'REAL' if is_real else 'FAKE'
190
- color = (0, 255, 0) if is_real else (0, 0, 255)
191
- cv2.rectangle(frame, (x, y), (x + bw, y + bh), color, 2)
192
- text = f'{label} {score:.2f}'
193
- cv2.putText(frame, text, (x, y - 10),
194
- cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2)
195
- out.write(frame)
196
- frame_count += 1
197
 
198
  cap.release()
199
  out.release()
 
8
  import cv2
9
  import numpy as np
10
  import imageio_ffmpeg
11
+ from ultralytics import YOLO
 
 
12
  from flask import Flask, request, render_template, send_from_directory, jsonify
13
  from werkzeug.utils import secure_filename
14
  import uuid
 
40
  logger.info('Model loaded successfully')
41
  INPUT_SIZE = 128
42
 
43
+ # Initialize YOLO face detector
44
+ logger.info('Initializing YOLO face detector')
45
+ FACE_MODEL_PATH = os.path.join(os.path.dirname(__file__), 'yolov8n-face.pt')
46
+ face_detector = YOLO(FACE_MODEL_PATH)
47
+ logger.info('YOLO face detector ready')
 
 
 
48
 
49
  # In-memory job store: job_id -> {status, result, ...}
50
  jobs = {}
 
98
  cap.release()
99
  return faces
100
 
101
+ while cap.isOpened():
102
+ frame_id = cap.get(cv2.CAP_PROP_POS_FRAMES)
103
+ ret, frame = cap.read()
104
+ if not ret:
105
+ break
106
+ if frame_id % math.floor(frame_rate) == 0:
107
+ image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
108
+ h, w = image_rgb.shape[:2]
109
+ results = face_detector(frame, verbose=False)[0]
110
+ for box in results.boxes:
111
+ if box.conf[0] > 0.5:
112
+ bx1, by1, bx2, by2 = map(int, box.xyxy[0])
113
+ bw = bx2 - bx1
114
+ bh = by2 - by1
115
+ margin_x = int(bw * 0.3)
116
+ margin_y = int(bh * 0.3)
117
+ x1 = max(0, bx1 - margin_x)
118
+ x2 = min(w, bx2 + margin_x)
119
+ y1 = max(0, by1 - margin_y)
120
+ y2 = min(h, by2 + margin_y)
121
+ crop = image_rgb[y1:y2, x1:x2]
122
+ if crop.size > 0:
123
+ crop_resized = cv2.resize(crop, (INPUT_SIZE, INPUT_SIZE))
124
+ faces.append(crop_resized)
 
 
125
 
126
  cap.release()
127
  logger.info('Face extraction complete — %d faces found', len(faces))
 
148
  return
149
 
150
  frame_count = 0
151
+ while cap.isOpened():
152
+ ret, frame = cap.read()
153
+ if not ret:
154
+ break
155
+ image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
156
+ results = face_detector(frame, verbose=False)[0]
157
+ for box in results.boxes:
158
+ if box.conf[0] > 0.5:
159
+ bx1, by1, bx2, by2 = map(int, box.xyxy[0])
160
+ bw = bx2 - bx1
161
+ bh = by2 - by1
162
+ x, y = max(0, bx1), max(0, by1)
163
+
164
+ # Crop and predict this face individually
165
+ margin_x = int(bw * 0.3)
166
+ margin_y = int(bh * 0.3)
167
+ x1 = max(0, bx1 - margin_x)
168
+ x2 = min(w, bx2 + margin_x)
169
+ y1 = max(0, by1 - margin_y)
170
+ y2 = min(h, by2 + margin_y)
171
+ crop = image_rgb[y1:y2, x1:x2]
172
+ if crop.size > 0:
173
+ crop_resized = cv2.resize(crop, (INPUT_SIZE, INPUT_SIZE))
174
+ face_input = np.array([crop_resized], dtype='float32') / 255.0
175
+ score = float(model.predict(face_input, verbose=0)[0][0])
176
+ else:
177
+ score = 0.0
178
+
179
+ is_real = score > 0.5
180
+ label = 'REAL' if is_real else 'FAKE'
181
+ color = (0, 255, 0) if is_real else (0, 0, 255)
182
+ cv2.rectangle(frame, (x, y), (bx2, by2), color, 2)
183
+ text = f'{label} {score:.2f}'
184
+ cv2.putText(frame, text, (x, y - 10),
185
+ cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2)
186
+ out.write(frame)
187
+ frame_count += 1
 
 
188
 
189
  cap.release()
190
  out.release()
App/yolov8n-face.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d545bf1add5aa736a4febac4f4f9245a6d596cd0fe70d5d57989fe0cb9e626ca
3
+ size 6389512
requirements.txt CHANGED
@@ -8,6 +8,6 @@ h5py
8
  split_folders
9
  flask
10
  werkzeug
11
- mediapipe
12
  imageio-ffmpeg
13
  pillow
 
8
  split_folders
9
  flask
10
  werkzeug
11
+ ultralytics
12
  imageio-ffmpeg
13
  pillow