NihalGazi commited on
Commit
e189340
·
verified ·
1 Parent(s): a030e65

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +42 -40
app.py CHANGED
@@ -4,90 +4,92 @@ import numpy as np
4
  from PIL import Image
5
  import mediapipe as mp
6
 
7
- # MediaPipe face mesh setup
8
  mp_face_mesh = mp.solutions.face_mesh
9
- face_mesh = mp_face_mesh.FaceMesh(static_image_mode=True)
10
 
11
- # Get facial landmarks
12
  def get_landmarks(image):
13
- rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
14
- results = face_mesh.process(rgb)
15
- h, w, _ = image.shape
16
-
17
- if results.multi_face_landmarks:
18
- landmarks = []
19
- for pt in results.multi_face_landmarks[0].landmark:
20
- x, y = int(pt.x * w), int(pt.y * h)
21
- landmarks.append((x, y))
22
- return np.array(landmarks, dtype=np.int32)
 
23
  return None
24
 
25
- # Morph images based on landmarks and alpha
26
  def morph_images(img1, img2, alpha):
27
  lm1 = get_landmarks(img1)
28
  lm2 = get_landmarks(img2)
29
 
30
  if lm1 is None or lm2 is None:
31
- return Image.fromarray(img1) # fallback
32
 
33
  lm_avg = ((1 - alpha) * lm1 + alpha * lm2).astype(np.int32)
34
 
35
- # Triangulation
36
  rect = (0, 0, img1.shape[1], img1.shape[0])
37
  subdiv = cv2.Subdiv2D(rect)
38
  for p in lm_avg:
39
- subdiv.insert((p[0], p[1]))
40
  triangles = subdiv.getTriangleList().astype(np.int32)
41
 
42
- def get_indices(tri, points):
43
  idxs = []
44
- for p in tri:
45
- for i, pt in enumerate(points):
46
- if np.linalg.norm(np.array(p) - np.array(pt)) < 1.0:
47
  idxs.append(i)
 
48
  return idxs if len(idxs) == 3 else None
49
 
50
- morphed = np.zeros_like(img1)
51
  for tri in triangles:
52
  pts = [(tri[0], tri[1]), (tri[2], tri[3]), (tri[4], tri[5])]
53
  idxs = get_indices(pts, lm_avg.tolist())
54
- if idxs is None: continue
 
55
 
56
  t1 = np.float32([lm1[i] for i in idxs])
57
  t2 = np.float32([lm2[i] for i in idxs])
58
  t = np.float32([lm_avg[i] for i in idxs])
59
 
60
  def warp_triangle(src, t_src, t_dst):
61
- rect_src = cv2.boundingRect(t_src)
62
- rect_dst = cv2.boundingRect(t_dst)
63
 
64
- t_src_offset = np.array([[pt[0]-rect_src[0], pt[1]-rect_src[1]] for pt in t_src], np.float32)
65
- t_dst_offset = np.array([[pt[0]-rect_dst[0], pt[1]-rect_dst[1]] for pt in t_dst], np.float32)
66
 
67
- mask = np.zeros((rect_dst[3], rect_dst[2], 3), dtype=np.float32)
68
  cv2.fillConvexPoly(mask, np.int32(t_dst_offset), (1.0, 1.0, 1.0), 16, 0)
69
 
70
- src_crop = src[rect_src[1]:rect_src[1]+rect_src[3], rect_src[0]:rect_src[0]+rect_src[2]]
71
  warp_mat = cv2.getAffineTransform(t_src_offset, t_dst_offset)
72
- dst_crop = cv2.warpAffine(src_crop, warp_mat, (rect_dst[2], rect_dst[3]), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101)
73
- morphed[rect_dst[1]:rect_dst[1]+rect_dst[3], rect_dst[0]:rect_dst[0]+rect_dst[2]] *= (1 - mask)
74
- morphed[rect_dst[1]:rect_dst[1]+rect_dst[3], rect_dst[0]:rect_dst[0]+rect_dst[2]] += dst_crop * mask
 
75
 
76
  warp_triangle(img1, t1, t)
77
  warp_triangle(img2, t2, t)
78
 
79
- return Image.fromarray(np.uint8(morphed))
80
 
81
  def process(mm_image, aa_image, ee_image, oo_image, ww_image, na_image, slider_aa, slider_oo, slider_ee, slider_ww, slider_na):
82
- def load(img): return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
 
 
 
 
83
 
84
- img = load(mm_image)
85
- for s, phoneme in [(slider_aa, aa_image), (slider_oo, oo_image), (slider_ee, ee_image), (slider_ww, ww_image), (slider_na, na_image)]:
86
- if s > 0.0:
87
- target = load(phoneme)
88
- img = np.array(morph_images(img, target, s))
89
 
90
- return Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
91
 
92
  iface = gr.Interface(
93
  fn=process,
 
4
  from PIL import Image
5
  import mediapipe as mp
6
 
7
+ # Setup MediaPipe
8
  mp_face_mesh = mp.solutions.face_mesh
 
9
 
 
10
  def get_landmarks(image):
11
+ with mp_face_mesh.FaceMesh(static_image_mode=True) as face_mesh:
12
+ rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
13
+ results = face_mesh.process(rgb)
14
+ h, w, _ = image.shape
15
+
16
+ if results.multi_face_landmarks:
17
+ landmarks = []
18
+ for pt in results.multi_face_landmarks[0].landmark:
19
+ x, y = int(pt.x * w), int(pt.y * h)
20
+ landmarks.append((x, y))
21
+ return np.array(landmarks, dtype=np.int32)
22
  return None
23
 
 
24
  def morph_images(img1, img2, alpha):
25
  lm1 = get_landmarks(img1)
26
  lm2 = get_landmarks(img2)
27
 
28
  if lm1 is None or lm2 is None:
29
+ return Image.fromarray(cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)) # fallback
30
 
31
  lm_avg = ((1 - alpha) * lm1 + alpha * lm2).astype(np.int32)
32
 
 
33
  rect = (0, 0, img1.shape[1], img1.shape[0])
34
  subdiv = cv2.Subdiv2D(rect)
35
  for p in lm_avg:
36
+ subdiv.insert((float(p[0]), float(p[1])))
37
  triangles = subdiv.getTriangleList().astype(np.int32)
38
 
39
+ def get_indices(tri_pts, ref_pts):
40
  idxs = []
41
+ for tp in tri_pts:
42
+ for i, pt in enumerate(ref_pts):
43
+ if abs(tp[0] - pt[0]) < 2 and abs(tp[1] - pt[1]) < 2:
44
  idxs.append(i)
45
+ break
46
  return idxs if len(idxs) == 3 else None
47
 
48
+ morphed = np.zeros_like(img1, dtype=np.float32)
49
  for tri in triangles:
50
  pts = [(tri[0], tri[1]), (tri[2], tri[3]), (tri[4], tri[5])]
51
  idxs = get_indices(pts, lm_avg.tolist())
52
+ if idxs is None:
53
+ continue
54
 
55
  t1 = np.float32([lm1[i] for i in idxs])
56
  t2 = np.float32([lm2[i] for i in idxs])
57
  t = np.float32([lm_avg[i] for i in idxs])
58
 
59
  def warp_triangle(src, t_src, t_dst):
60
+ r_src = cv2.boundingRect(t_src)
61
+ r_dst = cv2.boundingRect(t_dst)
62
 
63
+ t_src_offset = np.array([[pt[0] - r_src[0], pt[1] - r_src[1]] for pt in t_src], np.float32)
64
+ t_dst_offset = np.array([[pt[0] - r_dst[0], pt[1] - r_dst[1]] for pt in t_dst], np.float32)
65
 
66
+ mask = np.zeros((r_dst[3], r_dst[2], 3), dtype=np.float32)
67
  cv2.fillConvexPoly(mask, np.int32(t_dst_offset), (1.0, 1.0, 1.0), 16, 0)
68
 
69
+ src_crop = src[r_src[1]:r_src[1]+r_src[3], r_src[0]:r_src[0]+r_src[2]]
70
  warp_mat = cv2.getAffineTransform(t_src_offset, t_dst_offset)
71
+ dst_crop = cv2.warpAffine(src_crop, warp_mat, (r_dst[2], r_dst[3]), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101)
72
+
73
+ morphed[r_dst[1]:r_dst[1]+r_dst[3], r_dst[0]:r_dst[0]+r_dst[2]] *= (1 - mask)
74
+ morphed[r_dst[1]:r_dst[1]+r_dst[3], r_dst[0]:r_dst[0]+r_dst[2]] += dst_crop * mask
75
 
76
  warp_triangle(img1, t1, t)
77
  warp_triangle(img2, t2, t)
78
 
79
+ return Image.fromarray(cv2.cvtColor(np.uint8(morphed), cv2.COLOR_BGR2RGB))
80
 
81
  def process(mm_image, aa_image, ee_image, oo_image, ww_image, na_image, slider_aa, slider_oo, slider_ee, slider_ww, slider_na):
82
+ def to_bgr(img): return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
83
+
84
+ base = to_bgr(mm_image)
85
+ morph_order = [(slider_aa, aa_image), (slider_oo, oo_image), (slider_ee, ee_image),
86
+ (slider_ww, ww_image), (slider_na, na_image)]
87
 
88
+ for strength, image in morph_order:
89
+ if strength > 0:
90
+ base = cv2.cvtColor(np.array(morph_images(base, to_bgr(image), strength)), cv2.COLOR_RGB2BGR)
 
 
91
 
92
+ return Image.fromarray(cv2.cvtColor(base, cv2.COLOR_BGR2RGB))
93
 
94
  iface = gr.Interface(
95
  fn=process,