primerz commited on
Commit
7d45542
·
verified ·
1 Parent(s): a781ddc

Update utils.py

Browse files
Files changed (1) hide show
  1. utils.py +29 -71
utils.py CHANGED
@@ -9,40 +9,18 @@ from PIL import Image, ImageEnhance, ImageFilter, ImageDraw
9
  from config import COLOR_MATCH_CONFIG, FACE_MASK_CONFIG, AGE_BRACKETS
10
 
11
 
12
- # ============================================
13
- # NEW: Type Safety Helpers
14
- # ============================================
15
-
16
  def ensure_int(value):
17
- """
18
- Convert numpy.int64 or similar to Python int.
19
- Prevents tensor construction errors with PIL dimensions.
20
- """
21
  if isinstance(value, (int, float)):
22
  return int(value)
23
- if hasattr(value, 'item'):
24
- return int(value.item())
25
- return int(value)
26
 
27
 
28
  def safe_image_size(image):
29
- """
30
- Get image size as pure Python ints (not numpy.int64).
31
- Prevents errors when using PIL dimensions in tensor operations.
32
-
33
- Args:
34
- image: PIL Image
35
-
36
- Returns:
37
- Tuple of (width, height) as Python ints
38
- """
39
  return (ensure_int(image.width), ensure_int(image.height))
40
 
41
 
42
- # ============================================
43
- # Original Utility Functions
44
- # ============================================
45
-
46
  def sanitize_text(text):
47
  """
48
  Remove or replace problematic characters (emojis, special unicode)
@@ -253,29 +231,15 @@ def create_face_mask(image, face_bbox, feather=None):
253
  return mask
254
 
255
 
256
- def draw_kps(image_pil, kps, color_list=[(255,0,0), (0,255,0), (0,0,255), (255,255,0), (255,0,255)]):
257
- """
258
- Draw facial keypoints on image.
259
-
260
- Args:
261
- image_pil: PIL Image
262
- kps: Keypoints array from InsightFace
263
- color_list: List of colors for different keypoints
264
-
265
- Returns:
266
- PIL Image with keypoints drawn
267
- """
268
- import cv2
269
- import numpy as np
270
- from PIL import Image
271
-
272
  stickwidth = 4
273
  limbSeq = np.array([[0, 2], [1, 2], [3, 2], [4, 2]])
274
  kps = np.array(kps)
275
 
276
- # Convert PIL to OpenCV
277
- out_img = np.array(image_pil)
278
-
279
  for i in range(len(limbSeq)):
280
  index = limbSeq[i]
281
  color = color_list[index[0]]
@@ -284,9 +248,10 @@ def draw_kps(image_pil, kps, color_list=[(255,0,0), (0,255,0), (0,0,255), (255,2
284
  y = kps[index][:, 1]
285
  length = ((x[0] - x[1]) ** 2 + (y[0] - y[1]) ** 2) ** 0.5
286
  angle = math.degrees(math.atan2(y[0] - y[1], x[0] - x[1]))
287
- polygon = cv2.ellipse2Poly((int(np.mean(x)), int(np.mean(y))), (int(length / 2), stickwidth), int(angle), 0, 360, 1)
 
 
288
  out_img = cv2.fillConvexPoly(out_img.copy(), polygon, color)
289
-
290
  out_img = (out_img * 0.6).astype(np.uint8)
291
 
292
  for idx_kp, kp in enumerate(kps):
@@ -294,56 +259,49 @@ def draw_kps(image_pil, kps, color_list=[(255,0,0), (0,255,0), (0,0,255), (255,2
294
  x, y = kp
295
  out_img = cv2.circle(out_img.copy(), (int(x), int(y)), 10, color, -1)
296
 
297
- # Convert back to PIL
298
- return Image.fromarray(out_img.astype(np.uint8))
299
 
300
 
301
  def get_facial_attributes(face):
302
  """
303
- Extract facial attributes from InsightFace detection.
304
-
305
- Args:
306
- face: InsightFace face detection object
307
-
308
- Returns:
309
- Dictionary of facial attributes
310
  """
311
  attributes = {
312
- 'description': [],
313
  'age': None,
314
  'gender': None,
315
  'expression': None,
316
- 'pose_angle': None,
317
- 'quality': None
 
318
  }
319
 
320
- # Age
321
  try:
322
  if hasattr(face, 'age'):
323
  age = int(face.age)
324
  attributes['age'] = age
325
-
326
- # Age bracket
327
  for min_age, max_age, label in AGE_BRACKETS:
328
  if min_age <= age < max_age:
329
  attributes['description'].append(label)
330
  break
331
- except (ValueError, TypeError, AttributeError):
332
- pass
333
 
334
- # Gender
335
  try:
336
  if hasattr(face, 'gender'):
337
  gender_code = int(face.gender)
338
  attributes['gender'] = gender_code
339
  if gender_code == 1:
340
- attributes['description'].append('male')
341
  elif gender_code == 0:
342
- attributes['description'].append('female')
343
- except (ValueError, TypeError, AttributeError):
344
- pass
345
 
346
- # Expression
347
  try:
348
  if hasattr(face, 'emotion'):
349
  # Some InsightFace models provide emotion
@@ -464,7 +422,7 @@ def calculate_optimal_size(original_width, original_height, recommended_sizes=No
464
  Returns:
465
  Tuple of (optimal_width, optimal_height) as multiples of 64
466
  """
467
- # Ensure pure Python ints
468
  original_width = ensure_int(original_width)
469
  original_height = ensure_int(original_height)
470
 
@@ -565,4 +523,4 @@ def enhance_face_crop(face_crop):
565
  return face_crop_final
566
 
567
 
568
- print("[OK] Utilities loaded with type safety helpers")
 
9
  from config import COLOR_MATCH_CONFIG, FACE_MASK_CONFIG, AGE_BRACKETS
10
 
11
 
 
 
 
 
12
  def ensure_int(value):
13
+ """Convert numpy.int64 or similar to Python int"""
 
 
 
14
  if isinstance(value, (int, float)):
15
  return int(value)
16
+ return int(value.item()) if hasattr(value, 'item') else int(value)
 
 
17
 
18
 
19
  def safe_image_size(image):
20
+ """Get image size as pure Python ints to avoid numpy.int64 issues"""
 
 
 
 
 
 
 
 
 
21
  return (ensure_int(image.width), ensure_int(image.height))
22
 
23
 
 
 
 
 
24
  def sanitize_text(text):
25
  """
26
  Remove or replace problematic characters (emojis, special unicode)
 
231
  return mask
232
 
233
 
234
+ def draw_kps(image_pil, kps, color_list=[(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 0, 255)]):
235
+ """Draw facial keypoints on image for InstantID ControlNet"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  stickwidth = 4
237
  limbSeq = np.array([[0, 2], [1, 2], [3, 2], [4, 2]])
238
  kps = np.array(kps)
239
 
240
+ w, h = image_pil.size
241
+ out_img = np.zeros([h, w, 3])
242
+
243
  for i in range(len(limbSeq)):
244
  index = limbSeq[i]
245
  color = color_list[index[0]]
 
248
  y = kps[index][:, 1]
249
  length = ((x[0] - x[1]) ** 2 + (y[0] - y[1]) ** 2) ** 0.5
250
  angle = math.degrees(math.atan2(y[0] - y[1], x[0] - x[1]))
251
+ polygon = cv2.ellipse2Poly(
252
+ (int(np.mean(x)), int(np.mean(y))), (int(length / 2), stickwidth), int(angle), 0, 360, 1
253
+ )
254
  out_img = cv2.fillConvexPoly(out_img.copy(), polygon, color)
 
255
  out_img = (out_img * 0.6).astype(np.uint8)
256
 
257
  for idx_kp, kp in enumerate(kps):
 
259
  x, y = kp
260
  out_img = cv2.circle(out_img.copy(), (int(x), int(y)), 10, color, -1)
261
 
262
+ out_img_pil = Image.fromarray(out_img.astype(np.uint8))
263
+ return out_img_pil
264
 
265
 
266
  def get_facial_attributes(face):
267
  """
268
+ Extract comprehensive facial attributes.
269
+ Returns dict with age, gender, expression, quality metrics.
 
 
 
 
 
270
  """
271
  attributes = {
 
272
  'age': None,
273
  'gender': None,
274
  'expression': None,
275
+ 'quality': 1.0,
276
+ 'pose_angle': 0,
277
+ 'description': []
278
  }
279
 
280
+ # Age extraction
281
  try:
282
  if hasattr(face, 'age'):
283
  age = int(face.age)
284
  attributes['age'] = age
 
 
285
  for min_age, max_age, label in AGE_BRACKETS:
286
  if min_age <= age < max_age:
287
  attributes['description'].append(label)
288
  break
289
+ except (ValueError, TypeError, AttributeError) as e:
290
+ print(f"[WARNING] Age extraction failed: {e}")
291
 
292
+ # Gender extraction
293
  try:
294
  if hasattr(face, 'gender'):
295
  gender_code = int(face.gender)
296
  attributes['gender'] = gender_code
297
  if gender_code == 1:
298
+ attributes['description'].append("male")
299
  elif gender_code == 0:
300
+ attributes['description'].append("female")
301
+ except (ValueError, TypeError, AttributeError) as e:
302
+ print(f"[WARNING] Gender extraction failed: {e}")
303
 
304
+ # Expression/emotion detection (if available)
305
  try:
306
  if hasattr(face, 'emotion'):
307
  # Some InsightFace models provide emotion
 
422
  Returns:
423
  Tuple of (optimal_width, optimal_height) as multiples of 64
424
  """
425
+ # Ensure pure Python ints to avoid numpy.int64 issues
426
  original_width = ensure_int(original_width)
427
  original_height = ensure_int(original_height)
428
 
 
523
  return face_crop_final
524
 
525
 
526
+ print("[OK] Utilities loaded")