dibend commited on
Commit
ce8d5bc
·
verified ·
1 Parent(s): 955e31b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -105
app.py CHANGED
@@ -193,17 +193,45 @@ def apply_dreamy_glow(img_np):
193
  return cv2.addWeighted(img_np, 1.0, blurred, 0.6, 0)
194
 
195
 
196
- # --- Face Effect Functions ---
197
- def _create_sunglasses_mask():
198
- sunglasses = Image.new('RGBA', (300, 100), (0, 0, 0, 0))
 
199
  draw = ImageDraw.Draw(sunglasses)
200
- draw.polygon([(20, 20), (130, 20), (130, 80), (20, 80)], fill=(20, 20, 20, 200), outline='gray', width=5)
201
- draw.polygon([(170, 20), (280, 20), (280, 80), (170, 80)], fill=(20, 20, 20, 200), outline='gray', width=5)
202
- draw.line((130, 50, 170, 50), fill='gray', width=8)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  return sunglasses
204
 
205
- def apply_sunglasses(img_np):
206
- """Applies sunglasses to all detected faces (up to 2)."""
207
  if img_np is None: return img_np
208
  results = face_mesh.process(img_np)
209
  pil_image = Image.fromarray(img_np)
@@ -214,103 +242,18 @@ def apply_sunglasses(img_np):
214
  eye_center = (left_eye + right_eye) / 2
215
  eye_width = np.linalg.norm(left_eye - right_eye)
216
  angle = math.degrees(math.atan2(right_eye[1] - left_eye[1], right_eye[0] - left_eye[0]))
217
- sunglasses_img = _create_sunglasses_mask()
218
- w, h = int(eye_width * 1.6), int(eye_width * 1.6 * sunglasses_img.height / sunglasses_img.width)
 
 
219
  resized_sunglasses = sunglasses_img.resize((w, h), Image.Resampling.LANCZOS)
220
  rotated_sunglasses = resized_sunglasses.rotate(angle, expand=True, resample=Image.Resampling.BICUBIC)
221
  pos_x, pos_y = int(eye_center[0] - rotated_sunglasses.width / 2), int(eye_center[1] - rotated_sunglasses.height / 2)
 
222
  pil_image.paste(rotated_sunglasses, (pos_x, pos_y), rotated_sunglasses)
 
223
  return np.array(pil_image)
224
 
225
- def _draw_low_poly_accessories(draw, landmarks, wearable_type):
226
- """Draws a single piece of headwear or accessory using low-poly polygons."""
227
- chin, forehead_top, left_cheek, right_cheek = landmarks[152], landmarks[10], landmarks[234], landmarks[454]
228
- nose_tip = landmarks[1]
229
- upper_lip = landmarks[13]
230
- left_ear = landmarks[234]
231
- right_ear = landmarks[454]
232
-
233
- face_width, face_height = np.linalg.norm(left_cheek - right_cheek), np.linalg.norm(forehead_top - chin)
234
-
235
- # Improved hat positioning: find the "true" top of the head
236
- top_of_head_y = forehead_top[1] - (face_height * 0.2)
237
-
238
- if wearable_type == "Plumber":
239
- hat_color = "#E62E21" # Red
240
- mustache_color = "#4E2700" # Brown
241
- hat_width, hat_height = face_width * 1.1, face_height * 0.4
242
- hat_center_x = forehead_top[0]
243
- hat_brim_y = top_of_head_y + hat_height * 0.5
244
- # Brim (as a polygon)
245
- draw.polygon([
246
- (hat_center_x - hat_width/2, hat_brim_y), (hat_center_x + hat_width/2, hat_brim_y),
247
- (hat_center_x + hat_width/2.1, hat_brim_y + hat_height*0.1), (hat_center_x - hat_width/2.1, hat_brim_y + hat_height*0.1)
248
- ], fill=hat_color)
249
- # Top part (as a polygon)
250
- draw.polygon([
251
- (hat_center_x - hat_width/2.2, hat_brim_y), (hat_center_x + hat_width/2.2, hat_brim_y),
252
- (hat_center_x + hat_width/2.3, top_of_head_y), (hat_center_x - hat_width/2.3, top_of_head_y)
253
- ], fill=hat_color)
254
- # Mustache
255
- mustache_y = upper_lip[1]
256
- mustache_w, mustache_h = face_width * 0.4, face_height * 0.1
257
- draw.polygon([
258
- (nose_tip[0] - mustache_w/2, mustache_y), (nose_tip[0] + mustache_w/2, mustache_y),
259
- (nose_tip[0] + mustache_w/2.2, mustache_y + mustache_h), (nose_tip[0] - mustache_w/2.2, mustache_y + mustache_h)
260
- ], fill=mustache_color)
261
-
262
- elif wearable_type == "Elf Hero":
263
- hat_color = "#008000" # Green
264
- ear_color = "#FFDAB9" # Skin tone
265
- # Hat
266
- pts = [(forehead_top[0], top_of_head_y - face_height*0.5), (left_cheek[0], top_of_head_y + face_height*0.2), (right_cheek[0], top_of_head_y + face_height*0.2)]
267
- draw.polygon(pts, fill=hat_color)
268
- # Elf Ears
269
- ear_w, ear_h = face_width * 0.2, face_height * 0.3
270
- # Left Ear
271
- draw.polygon([(left_ear[0], left_ear[1]), (left_ear[0] - ear_w, left_ear[1] - ear_h*0.2), (left_ear[0] - ear_w*0.2, left_ear[1] + ear_h*0.8)], fill=ear_color, outline="black")
272
- # Right Ear
273
- draw.polygon([(right_ear[0], right_ear[1]), (right_ear[0] + ear_w, right_ear[1] - ear_h*0.2), (right_ear[0] + ear_w*0.2, right_ear[1] + ear_h*0.8)], fill=ear_color, outline="black")
274
-
275
- elif wearable_type == "Cowboy Hat":
276
- hat_color = "#634519" # Brown
277
- hat_width, hat_height = face_width * 1.5, face_height * 0.5
278
- hat_center_x, brim_center_y = int(forehead_top[0]), int(top_of_head_y + hat_height * 0.7)
279
- # Brim
280
- draw.polygon([
281
- (hat_center_x - hat_width/2, brim_center_y), (hat_center_x + hat_width/2, brim_center_y),
282
- (hat_center_x + hat_width/2.2, brim_center_y + hat_height*0.2), (hat_center_x - hat_width/2.2, brim_center_y + hat_height*0.2)
283
- ], fill=hat_color)
284
- # Crown
285
- draw.polygon([
286
- (hat_center_x - hat_width/3, brim_center_y), (hat_center_x + hat_width/3, brim_center_y),
287
- (hat_center_x + hat_width/3.5, top_of_head_y), (hat_center_x - hat_width/3.5, top_of_head_y)
288
- ], fill=hat_color)
289
-
290
- elif wearable_type == "Crown":
291
- hat_color = "#FFD700" # Gold
292
- hat_width, hat_height = face_width * 1.1, face_height * 0.25
293
- base_y = int(top_of_head_y)
294
- base_x_start = int(forehead_top[0] - hat_width/2)
295
- draw.polygon([base_x_start, base_y, base_x_start + hat_width, base_y, base_x_start + hat_width, base_y + hat_height * 0.3, base_x_start, base_y + hat_height * 0.3], fill=hat_color)
296
- for i in range(5):
297
- spike_base_x = base_x_start + (i * hat_width/4)
298
- pts = [(spike_base_x - hat_width*0.05, base_y), (spike_base_x + hat_width*0.05, base_y), (spike_base_x, base_y - hat_height)]
299
- draw.polygon(pts, fill=hat_color)
300
-
301
- def apply_accessories(img_np, wearable_type):
302
- """Applies low-poly accessories to all detected faces (up to 2)."""
303
- if img_np is None: return img_np
304
- results = face_mesh.process(img_np)
305
- pil_image = Image.fromarray(img_np)
306
- if results.multi_face_landmarks:
307
- overlay = Image.new('RGBA', pil_image.size, (0, 0, 0, 0))
308
- draw = ImageDraw.Draw(overlay)
309
- for face_landmarks in results.multi_face_landmarks:
310
- landmarks = np.array([(lm.x * img_np.shape[1], lm.y * img_np.shape[0]) for lm in face_landmarks.landmark])
311
- _draw_low_poly_accessories(draw, landmarks, wearable_type)
312
- pil_image.paste(overlay, (0, 0), overlay)
313
- return np.array(pil_image)
314
 
315
  # --- Main Processing Function ---
316
  def process_image(image, filter_name, splash_color):
@@ -326,11 +269,9 @@ def process_image(image, filter_name, splash_color):
326
  "HDR Effect": apply_hdr_effect, "Sunburst Glow": apply_sunburst_glow,
327
  "Dreamy Glow": apply_dreamy_glow,
328
  "Color Splash": lambda img: apply_color_splash(img, splash_color),
329
- "Sunglasses": apply_sunglasses,
330
- "Plumber": lambda img: apply_accessories(img, "Plumber"),
331
- "Elf Hero": lambda img: apply_accessories(img, "Elf Hero"),
332
- "Cowboy Hat": lambda img: apply_accessories(img, "Cowboy Hat"),
333
- "Crown": lambda img: apply_accessories(img, "Crown"),
334
  "None": lambda img: img
335
  }
336
 
@@ -351,7 +292,7 @@ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
351
  filters_standard = ["Grayscale", "Sepia", "Invert", "Posterize", "Solarize", "Vignette", "Contour", "Sharpen"]
352
  filters_artistic = ["Cartoon", "Sketch", "Pixelate"]
353
  filters_advanced = ["N64-ify (Triangles)", "HDR Effect", "Color Splash", "Sunburst Glow", "Dreamy Glow"]
354
- filters_face = ["Sunglasses", "Plumber", "Elf Hero", "Cowboy Hat", "Crown"]
355
 
356
  all_filters = ["None"] + filters_standard + filters_artistic + filters_advanced + filters_face
357
 
 
193
  return cv2.addWeighted(img_np, 1.0, blurred, 0.6, 0)
194
 
195
 
196
+ # --- Sunglasses Functions ---
197
+ def _create_sunglasses_mask(style="aviator"):
198
+ """Creates a PIL image mask for a given sunglass style."""
199
+ sunglasses = Image.new('RGBA', (300, 150), (0, 0, 0, 0))
200
  draw = ImageDraw.Draw(sunglasses)
201
+
202
+ if style == "aviator":
203
+ # Left Lens
204
+ draw.polygon([(20, 50), (130, 40), (120, 110), (30, 110)], fill=(20, 20, 20, 200), outline='gold', width=3)
205
+ # Right Lens
206
+ draw.polygon([(170, 40), (280, 50), (270, 110), (180, 110)], fill=(20, 20, 20, 200), outline='gold', width=3)
207
+ # Bridge
208
+ draw.line((130, 45, 170, 45), fill='gold', width=5)
209
+ draw.line((130, 55, 170, 55), fill='gold', width=5)
210
+
211
+ elif style == "retro_square":
212
+ # Left Lens
213
+ draw.rectangle((20, 40, 130, 110), fill=(10, 10, 10, 210), outline='white', width=6)
214
+ # Right Lens
215
+ draw.rectangle((170, 40, 280, 110), fill=(10, 10, 10, 210), outline='white', width=6)
216
+ # Bridge
217
+ draw.rectangle((130, 60, 170, 75), fill='white')
218
+
219
+ elif style == "heart_shaped":
220
+ # Left Heart
221
+ draw.polygon([
222
+ (75, 40), (125, 60), (75, 120), (25, 60)
223
+ ], fill='deeppink', outline='hotpink', width=4)
224
+ # Right Heart
225
+ draw.polygon([
226
+ (225, 40), (275, 60), (225, 120), (175, 60)
227
+ ], fill='deeppink', outline='hotpink', width=4)
228
+ # Bridge
229
+ draw.line((125, 70, 175, 70), fill='hotpink', width=6)
230
+
231
  return sunglasses
232
 
233
+ def apply_sunglasses(img_np, style="aviator"):
234
+ """Applies a specific style of sunglasses to all detected faces (up to 2)."""
235
  if img_np is None: return img_np
236
  results = face_mesh.process(img_np)
237
  pil_image = Image.fromarray(img_np)
 
242
  eye_center = (left_eye + right_eye) / 2
243
  eye_width = np.linalg.norm(left_eye - right_eye)
244
  angle = math.degrees(math.atan2(right_eye[1] - left_eye[1], right_eye[0] - left_eye[0]))
245
+
246
+ sunglasses_img = _create_sunglasses_mask(style)
247
+
248
+ w, h = int(eye_width * 1.8), int(eye_width * 1.8 * sunglasses_img.height / sunglasses_img.width)
249
  resized_sunglasses = sunglasses_img.resize((w, h), Image.Resampling.LANCZOS)
250
  rotated_sunglasses = resized_sunglasses.rotate(angle, expand=True, resample=Image.Resampling.BICUBIC)
251
  pos_x, pos_y = int(eye_center[0] - rotated_sunglasses.width / 2), int(eye_center[1] - rotated_sunglasses.height / 2)
252
+
253
  pil_image.paste(rotated_sunglasses, (pos_x, pos_y), rotated_sunglasses)
254
+
255
  return np.array(pil_image)
256
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
 
258
  # --- Main Processing Function ---
259
  def process_image(image, filter_name, splash_color):
 
269
  "HDR Effect": apply_hdr_effect, "Sunburst Glow": apply_sunburst_glow,
270
  "Dreamy Glow": apply_dreamy_glow,
271
  "Color Splash": lambda img: apply_color_splash(img, splash_color),
272
+ "Aviator Sunglasses": lambda img: apply_sunglasses(img, style="aviator"),
273
+ "Retro Square Sunglasses": lambda img: apply_sunglasses(img, style="retro_square"),
274
+ "Heart-Shaped Sunglasses": lambda img: apply_sunglasses(img, style="heart_shaped"),
 
 
275
  "None": lambda img: img
276
  }
277
 
 
292
  filters_standard = ["Grayscale", "Sepia", "Invert", "Posterize", "Solarize", "Vignette", "Contour", "Sharpen"]
293
  filters_artistic = ["Cartoon", "Sketch", "Pixelate"]
294
  filters_advanced = ["N64-ify (Triangles)", "HDR Effect", "Color Splash", "Sunburst Glow", "Dreamy Glow"]
295
+ filters_face = ["Aviator Sunglasses", "Retro Square Sunglasses", "Heart-Shaped Sunglasses"]
296
 
297
  all_filters = ["None"] + filters_standard + filters_artistic + filters_advanced + filters_face
298