NihalGazi commited on
Commit
8d39328
Β·
verified Β·
1 Parent(s): 99404e3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +26 -20
app.py CHANGED
@@ -24,7 +24,7 @@ except (ImportError, AttributeError):
24
 
25
 
26
 
27
- def get_face_mask_box(img, feather):
28
  h, w = img.shape[:2]
29
  mask = np.zeros((h, w), dtype=np.uint8)
30
  results = face_mesh.process(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
@@ -34,11 +34,17 @@ def get_face_mask_box(img, feather):
34
  hull = cv2.convexHull(pts)
35
  cv2.fillConvexPoly(mask, hull, 255)
36
  x, y, bw, bh = cv2.boundingRect(hull)
37
- mask_roi = mask[y:y+bh, x:x+bw]
 
 
 
 
 
 
38
  if feather > 0 and mask_roi.size > 0:
39
  k = int(feather)
40
  mask_roi = cv2.GaussianBlur(mask_roi, (k*2+1, k*2+1), 0)
41
- return mask_roi, (x, y, bw, bh)
42
 
43
 
44
  def cut_and_feather(img, feather):
@@ -160,14 +166,14 @@ def morph_faces(img1, img2, alpha, dim, step):
160
  return (out*255).astype(np.uint8)
161
 
162
 
163
- def process_video(video_path, ref_img, trans, res, step, feather):
164
  cap = cv2.VideoCapture(video_path)
165
  fps = cap.get(cv2.CAP_PROP_FPS) or 24
166
  total = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
167
 
168
  # Prepare masked reference
169
  ref_bgr = cv2.cvtColor(ref_img, cv2.COLOR_RGB2BGR)
170
- mask_ref, ref_box = get_face_mask_box(ref_bgr, feather)
171
  if mask_ref is None:
172
  return None, None, None, None
173
  x_r, y_r, w_r, h_r = ref_box
@@ -190,7 +196,7 @@ def process_video(video_path, ref_img, trans, res, step, feather):
190
  for i in range(total):
191
  ret, frame = cap.read()
192
  if not ret: break
193
- mask_roi, box = get_face_mask_box(frame, feather)
194
  if mask_roi is None:
195
  out_vid.write(frame)
196
  continue
@@ -233,31 +239,31 @@ def process_video(video_path, ref_img, trans, res, step, feather):
233
  # --- Gradio App ---
234
  css = """video, img { object-fit: contain !important; }"""
235
  with gr.Blocks(css=css) as iface:
236
- gr.Markdown("# Enhanced Face Morph with Composite Placement")
237
  with gr.Row():
238
  vid = gr.Video(label='Input Video')
239
- ref = gr.Image(type='numpy', label='Reference Face Image')
240
  with gr.Row():
241
- res = gr.Dropdown([256, 384, 512, 768], value=512, label='Morph Resolution')
242
- step = gr.Slider(1, 4, value=1, step=1, label='Landmark Sub-sampling')
243
- feather = gr.Slider(0, 50, value=10, step=1, label='Feather Radius')
244
- trans = gr.Slider(-1.0, 1.0, value=0.0, step=0.05, label='Transition Level')
 
245
  btn = gr.Button('Generate Morph πŸš€')
246
  out_vid = gr.Video(label='Morphed Video')
247
- out_central = gr.Image(label='Centralized Frame[0]')
248
- out_ref = gr.Image(label='Cropped Reference')
249
- out_morph0 = gr.Image(label='Morphed Frame[0]')
250
 
251
  btn.click(
252
  fn=process_video,
253
- inputs=[vid, ref, trans, res, step, feather],
254
- outputs=[out_vid, out_central, out_ref, out_morph0],
255
  show_progress=True
256
  )
257
- gr.Markdown("---\n*Now the Frame[0] crop fits the face before resizing.*")
258
 
259
- if __name__ == '__main__':
260
  iface.launch(debug=True)
261
 
262
 
263
-
 
24
 
25
 
26
 
27
+ def get_face_mask_box(img, feather, padding=0):
28
  h, w = img.shape[:2]
29
  mask = np.zeros((h, w), dtype=np.uint8)
30
  results = face_mesh.process(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
 
34
  hull = cv2.convexHull(pts)
35
  cv2.fillConvexPoly(mask, hull, 255)
36
  x, y, bw, bh = cv2.boundingRect(hull)
37
+ # apply padding
38
+ x_pad = max(x - padding, 0)
39
+ y_pad = max(y - padding, 0)
40
+ x2 = min(x + bw + padding, w)
41
+ y2 = min(y + bh + padding, h)
42
+ mask_roi = mask[y_pad:y2, x_pad:x2]
43
+ # inside feather
44
  if feather > 0 and mask_roi.size > 0:
45
  k = int(feather)
46
  mask_roi = cv2.GaussianBlur(mask_roi, (k*2+1, k*2+1), 0)
47
+ return mask_roi, (x_pad, y_pad, x2 - x_pad, y2 - y_pad)
48
 
49
 
50
  def cut_and_feather(img, feather):
 
166
  return (out*255).astype(np.uint8)
167
 
168
 
169
+ def process_video(video_path, ref_img, trans, res, step, feather, padding):
170
  cap = cv2.VideoCapture(video_path)
171
  fps = cap.get(cv2.CAP_PROP_FPS) or 24
172
  total = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
173
 
174
  # Prepare masked reference
175
  ref_bgr = cv2.cvtColor(ref_img, cv2.COLOR_RGB2BGR)
176
+ mask_ref, ref_box = get_face_mask_box(ref_bgr, feather, padding)
177
  if mask_ref is None:
178
  return None, None, None, None
179
  x_r, y_r, w_r, h_r = ref_box
 
196
  for i in range(total):
197
  ret, frame = cap.read()
198
  if not ret: break
199
+ mask_roi, box = get_face_mask_box(frame, feather, padding)
200
  if mask_roi is None:
201
  out_vid.write(frame)
202
  continue
 
239
  # --- Gradio App ---
240
  css = """video, img { object-fit: contain !important; }"""
241
  with gr.Blocks(css=css) as iface:
242
+ gr.Markdown("# Morph with Face-Shaped Composite and Padding")
243
  with gr.Row():
244
  vid = gr.Video(label='Input Video')
245
+ ref = gr.Image(type='numpy', label='Reference Image')
246
  with gr.Row():
247
+ res = gr.Dropdown([256,384,512,768], value=512, label='Resolution')
248
+ step = gr.Slider(1,4,value=1,step=1,label='Landmark Sub-sampling')
249
+ feather = gr.Slider(0,50,value=10,step=1,label='Feather Radius')
250
+ padding = gr.Slider(0,100,value=10,step=1,label='Crop Padding (px)')
251
+ trans = gr.Slider(-1.0,1.0,value=0.0,step=0.05,label='Transition Level')
252
  btn = gr.Button('Generate Morph πŸš€')
253
  out_vid = gr.Video(label='Morphed Video')
254
+ out_crop = gr.Image(label='First Frame Crop')
255
+ out_ref = gr.Image(label='Masked Reference')
256
+ out_morph = gr.Image(label='Masked Morphed First Frame')
257
 
258
  btn.click(
259
  fn=process_video,
260
+ inputs=[vid,ref,trans,res,step,feather,padding],
261
+ outputs=[out_vid,out_crop,out_ref,out_morph],
262
  show_progress=True
263
  )
264
+ gr.Markdown("---\n*Added padding to the face crop for better framing.*")
265
 
266
+ if __name__=='__main__':
267
  iface.launch(debug=True)
268
 
269