James040 commited on
Commit
980761c
·
verified ·
1 Parent(s): c34c17a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -27
app.py CHANGED
@@ -46,51 +46,77 @@ def upscale_bg_tiled(frame, tile_size=128, overlap=16):
46
  return upscaled_img
47
 
48
  def restore_face_core(img, fidelity=0.5):
49
- """CodeFormer Face Restoration with Dynamic Input & Type Support"""
50
- # 1. Pre-process (CodeFormer expects 512x512)
51
  img_512 = cv2.resize(img, (512, 512), interpolation=cv2.INTER_LINEAR)
52
- img_in = np.transpose(cv2.cvtColor(img_512, cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0, (2, 0, 1))[np.newaxis, :]
53
 
54
- # 2. Map Inputs and Match Data Types Dynamically
55
- inputs_info = face_session.get_inputs()
56
- input_feed = {}
57
-
58
- # Map the main image input (index 0)
59
- input_feed[inputs_info[0].name] = img_in
60
 
61
- # Handle the auxiliary inputs (like 'weight')
 
 
62
  for i in range(1, len(inputs_info)):
63
- input_name = inputs_info[i].name
64
- input_type = inputs_info[i].type
65
-
66
- # Check if the model explicitly wants a double-precision float
67
- dt = np.float64 if 'double' in input_type else np.float32
68
-
69
- input_feed[input_name] = np.array([fidelity], dtype=dt)
70
 
71
- # 3. AI Inference
72
  out = face_session.run(None, input_feed)[0]
73
 
74
- # 4. Post-process
75
- res = cv2.cvtColor((np.clip(np.squeeze(out), 0, 1).transpose(1, 2, 0) * 255.0).astype(np.uint8), cv2.COLOR_RGB2BGR)
 
 
76
  return cv2.resize(res, (img.shape[1], img.shape[0]), interpolation=cv2.INTER_LANCZOS4)
77
 
 
78
  def hybrid_enhancer(img_data, mode, face_strength, progress=gr.Progress()):
79
  if img_data is None: return None
80
  img = img_data["composite"]
81
  if img.shape[2] == 4: img = cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
82
 
 
83
  if mode == "Full Image (BG + Face)":
84
  progress(0, desc="Stage 1: Upscaling Background...")
85
- bg_upscaled = upscale_bg_tiled(img)
86
- progress(0.5, desc="Stage 2: Restoring Face Details...")
87
- # Use the strength slider as the internal model weight too
88
- face_restored = restore_face_core(bg_upscaled, fidelity=face_strength)
89
- return cv2.addWeighted(face_restored, face_strength, bg_upscaled, 1 - face_strength, 0)
90
  else:
91
- # Just Face Restoration
92
- return restore_face_core(img, fidelity=face_strength)
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  # --- UI ---
95
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo")) as demo:
96
  gr.Markdown("# 🏆 Hybrid Face & Background Enhancer")
 
46
  return upscaled_img
47
 
48
  def restore_face_core(img, fidelity=0.5):
49
+ """CodeFormer Face Restoration with Correct Math Normalization"""
 
50
  img_512 = cv2.resize(img, (512, 512), interpolation=cv2.INTER_LINEAR)
51
+ img_rgb = cv2.cvtColor(img_512, cv2.COLOR_BGR2RGB).astype(np.float32)
52
 
53
+ # --- MATH FIX: Map colors from [0, 255] to [-1.0, 1.0] ---
54
+ img_in = (img_rgb / 127.5) - 1.0
55
+ img_in = np.transpose(img_in, (2, 0, 1))[np.newaxis, :]
 
 
 
56
 
57
+ # Map Inputs
58
+ inputs_info = face_session.get_inputs()
59
+ input_feed = {inputs_info[0].name: img_in}
60
  for i in range(1, len(inputs_info)):
61
+ dt = np.float64 if 'double' in inputs_info[i].type else np.float32
62
+ input_feed[inputs_info[i].name] = np.array([fidelity], dtype=dt)
 
 
 
 
 
63
 
64
+ # AI Inference
65
  out = face_session.run(None, input_feed)[0]
66
 
67
+ # --- MATH FIX: Map colors back from [-1.0, 1.0] to [0, 1] ---
68
+ out = (np.squeeze(out) + 1.0) / 2.0
69
+ res = cv2.cvtColor((np.clip(out, 0, 1).transpose(1, 2, 0) * 255.0).astype(np.uint8), cv2.COLOR_RGB2BGR)
70
+
71
  return cv2.resize(res, (img.shape[1], img.shape[0]), interpolation=cv2.INTER_LANCZOS4)
72
 
73
+
74
  def hybrid_enhancer(img_data, mode, face_strength, progress=gr.Progress()):
75
  if img_data is None: return None
76
  img = img_data["composite"]
77
  if img.shape[2] == 4: img = cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
78
 
79
+ # Stage 1: Background
80
  if mode == "Full Image (BG + Face)":
81
  progress(0, desc="Stage 1: Upscaling Background...")
82
+ final_img = upscale_bg_tiled(img)
 
 
 
 
83
  else:
84
+ final_img = img.copy()
 
85
 
86
+ # Stage 2: Smart Face Detection
87
+ progress(0.5, desc="Stage 2: Scanning for Faces...")
88
+
89
+ # Use OpenCV's built-in AI to find where the face actually is
90
+ face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
91
+ gray = cv2.cvtColor(final_img, cv2.COLOR_BGR2GRAY)
92
+ faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(64, 64))
93
+
94
+ if len(faces) == 0:
95
+ print("No face detected! Running on whole image as fallback.")
96
+ restored = restore_face_core(final_img, fidelity=face_strength)
97
+ final_img = cv2.addWeighted(restored, face_strength, final_img, 1 - face_strength, 0)
98
+ else:
99
+ # Process each face found
100
+ for (x, y, w, h) in faces:
101
+ # Add some padding around the face so the AI sees the jawline/hair
102
+ pad_x = int(w * 0.2)
103
+ pad_y = int(h * 0.2)
104
+ x1 = max(0, x - pad_x)
105
+ y1 = max(0, y - int(pad_y * 1.5)) # Extra room at the top for hair
106
+ x2 = min(final_img.shape[1], x + w + pad_x)
107
+ y2 = min(final_img.shape[0], y + h + pad_y)
108
+
109
+ # Extract just the face box
110
+ face_crop = final_img[y1:y2, x1:x2]
111
+
112
+ # Restore the face perfectly
113
+ restored_face = restore_face_core(face_crop, fidelity=face_strength)
114
+
115
+ # Paste it seamlessly back into the high-res background
116
+ final_img[y1:y2, x1:x2] = cv2.addWeighted(restored_face, face_strength, face_crop, 1 - face_strength, 0)
117
+
118
+ progress(1.0, desc="Done!")
119
+ return final_img
120
  # --- UI ---
121
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo")) as demo:
122
  gr.Markdown("# 🏆 Hybrid Face & Background Enhancer")