Siyun He commited on
Commit
58a86d0
·
1 Parent(s): de3be89

make the face detection 3D and add comments

Browse files
Files changed (1) hide show
  1. app.py +19 -13
app.py CHANGED
@@ -32,9 +32,12 @@ def count_files_in_directory(directory):
32
  return file_count
33
 
34
  # Determine face shape
35
- def determine_face_shape(landmarks):
 
36
  jaw_width = np.linalg.norm(landmarks[0] - landmarks[16])
37
  face_height = np.linalg.norm(landmarks[8] - landmarks[27])
 
 
38
  if jaw_width / face_height > 1.5:
39
  return "Round"
40
  elif jaw_width / face_height < 1.2:
@@ -169,10 +172,12 @@ def change_lip_color(frame, color_name='none'):
169
  return frame
170
 
171
  # Process frame for overlay and face shape detection
172
- def process_frame(frame):
173
  global overlay
 
174
  frame = np.array(frame, copy=True)
175
  height, width = frame.shape[:2]
 
176
  face_detector.setInputSize((width, height))
177
  _, faces = face_detector.detect(frame)
178
 
@@ -215,8 +220,9 @@ def process_frame(frame):
215
  print(f"Error overlaying glasses: {e}")
216
 
217
  for face_landmarks_mp in results.multi_face_landmarks:
218
- landmarks = np.array([(lm.x * frame.shape[1], lm.y * frame.shape[0]) for lm in face_landmarks_mp.landmark])
219
- face_shape = determine_face_shape(landmarks)
 
220
  glass_shape = recommend_glass_shape(face_shape)
221
 
222
  return frame, face_shape, glass_shape
@@ -225,13 +231,13 @@ def process_frame(frame):
225
  def transform_cv2(frame, transform):
226
  if transform == "cartoon":
227
  # prepare color
228
- img_color = cv2.pyrDown(cv2.pyrDown(frame))
229
  for _ in range(6):
230
- img_color = cv2.bilateralFilter(img_color, 9, 9, 7)
231
- img_color = cv2.pyrUp(cv2.pyrUp(img_color))
232
 
233
  # prepare edges
234
- img_edges = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
235
  img_edges = cv2.adaptiveThreshold(
236
  cv2.medianBlur(img_edges, 7),
237
  255,
@@ -239,11 +245,12 @@ def transform_cv2(frame, transform):
239
  cv2.THRESH_BINARY,
240
  9,
241
  2,
242
- )
243
- img_edges = cv2.cvtColor(img_edges, cv2.COLOR_GRAY2RGB)
244
  # combine color and edges
245
  img = cv2.bitwise_and(img_color, img_edges)
246
- return img
 
247
  elif transform == "edges":
248
  # perform edge detection
249
  img = cv2.cvtColor(cv2.Canny(frame, 100, 200), cv2.COLOR_GRAY2BGR)
@@ -256,7 +263,6 @@ def transform_cv2(frame, transform):
256
  [0.393, 0.769, 0.189]])
257
  img = cv2.transform(frame, kernel)
258
  img = np.clip(img, 0, 255) # ensure values are within byte range
259
- # Convert BGR to RGB if necessary (for display purposes)
260
  img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
261
  return img_rgb
262
 
@@ -301,7 +307,7 @@ def save_frame(frame):
301
  return filename
302
 
303
  def webcam_input(frame, transform, lip_color):
304
- frame, face_shape, glass_shape = process_frame(frame)
305
  if transform != "none" and lip_color == "none":
306
  frame = transform_cv2(frame, transform)
307
  elif lip_color != "none" and transform == "none":
 
32
  return file_count
33
 
34
  # Determine face shape
35
+ def determine_face_shape_3d(landmarks):
36
+ # Calculate 3D distances
37
  jaw_width = np.linalg.norm(landmarks[0] - landmarks[16])
38
  face_height = np.linalg.norm(landmarks[8] - landmarks[27])
39
+
40
+ # Determine face shape based on 3D proportions
41
  if jaw_width / face_height > 1.5:
42
  return "Round"
43
  elif jaw_width / face_height < 1.2:
 
172
  return frame
173
 
174
  # Process frame for overlay and face shape detection
175
+ def process_frame_3d(frame):
176
  global overlay
177
+
178
  frame = np.array(frame, copy=True)
179
  height, width = frame.shape[:2]
180
+
181
  face_detector.setInputSize((width, height))
182
  _, faces = face_detector.detect(frame)
183
 
 
220
  print(f"Error overlaying glasses: {e}")
221
 
222
  for face_landmarks_mp in results.multi_face_landmarks:
223
+ # Convert landmarks to 3D coordinates
224
+ landmarks = np.array([(lm.x * frame.shape[1], lm.y * frame.shape[0], lm.z * frame.shape[1]) for lm in face_landmarks_mp.landmark])
225
+ face_shape = determine_face_shape_3d(landmarks)
226
  glass_shape = recommend_glass_shape(face_shape)
227
 
228
  return frame, face_shape, glass_shape
 
231
  def transform_cv2(frame, transform):
232
  if transform == "cartoon":
233
  # prepare color
234
+ img_color = cv2.pyrDown(cv2.pyrDown(frame)) # Reduce the resolution
235
  for _ in range(6):
236
+ img_color = cv2.bilateralFilter(img_color, 9, 9, 7) # Smoothen the image while preserving the edges
237
+ img_color = cv2.pyrUp(cv2.pyrUp(img_color)) # Scale back to the original resolution
238
 
239
  # prepare edges
240
+ img_edges = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY) # Convert to grayscale
241
  img_edges = cv2.adaptiveThreshold(
242
  cv2.medianBlur(img_edges, 7),
243
  255,
 
245
  cv2.THRESH_BINARY,
246
  9,
247
  2,
248
+ ) # Apply adaptive thresholding to get the edges
249
+ img_edges = cv2.cvtColor(img_edges, cv2.COLOR_GRAY2RGB) # Convert back to color
250
  # combine color and edges
251
  img = cv2.bitwise_and(img_color, img_edges)
252
+ return img # Combine the color and edges
253
+
254
  elif transform == "edges":
255
  # perform edge detection
256
  img = cv2.cvtColor(cv2.Canny(frame, 100, 200), cv2.COLOR_GRAY2BGR)
 
263
  [0.393, 0.769, 0.189]])
264
  img = cv2.transform(frame, kernel)
265
  img = np.clip(img, 0, 255) # ensure values are within byte range
 
266
  img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
267
  return img_rgb
268
 
 
307
  return filename
308
 
309
  def webcam_input(frame, transform, lip_color):
310
+ frame, face_shape, glass_shape = process_frame_3d(frame)
311
  if transform != "none" and lip_color == "none":
312
  frame = transform_cv2(frame, transform)
313
  elif lip_color != "none" and transform == "none":