Spaces:
Sleeping
Sleeping
Siyun He
commited on
Commit
·
58a86d0
1
Parent(s):
de3be89
make the face detection 3D and add comments
Browse files
app.py
CHANGED
@@ -32,9 +32,12 @@ def count_files_in_directory(directory):
|
|
32 |
return file_count
|
33 |
|
34 |
# Determine face shape
|
35 |
-
def
|
|
|
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
|
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 |
-
|
219 |
-
|
|
|
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 =
|
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":
|