Seniordev22 commited on
Commit
c7400ce
·
verified ·
1 Parent(s): 257adde

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +16 -47
app.py CHANGED
@@ -27,17 +27,11 @@ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
27
  logger.info(f"Using Device: {DEVICE}")
28
  logger.info(f"CUDA Available: {torch.cuda.is_available()}")
29
 
30
- # Strong CPU Optimization
31
  if DEVICE.type == "cpu":
32
  torch.set_num_threads(4)
33
  torch.set_num_interop_threads(1)
34
  cv2.setNumThreads(4)
35
- # Enable better CPU backend if available
36
- try:
37
- import torch.backends.mkldnn
38
- torch.backends.mkldnn.enabled = True
39
- except:
40
- pass
41
  else:
42
  torch.set_num_threads(1)
43
 
@@ -49,7 +43,6 @@ executor = ThreadPoolExecutor(max_workers=2)
49
  face_processor = None
50
  face_parser = None
51
  beard_model = None
52
- face_parser_compiled = None
53
 
54
  # ====================== TIMED DECORATOR ======================
55
  def timed(name: str):
@@ -65,7 +58,7 @@ def timed(name: str):
65
 
66
  # ====================== MODEL LOADING ======================
67
  def load_face_parser():
68
- global face_processor, face_parser, face_parser_compiled
69
  if face_parser is not None:
70
  return
71
  logger.info("Loading Segformer Face Parser...")
@@ -73,18 +66,6 @@ def load_face_parser():
73
  face_parser = SegformerForSemanticSegmentation.from_pretrained("jonathandinu/face-parsing")
74
  face_parser.to(DEVICE)
75
  face_parser.eval()
76
-
77
- # Try torch.compile for speedup (CPU pe bhi kaam karta hai PyTorch 2.0+)
78
- try:
79
- if DEVICE.type == "cpu":
80
- face_parser_compiled = torch.compile(face_parser, mode="default", fullgraph=False)
81
- logger.info("✅ Face parser compiled with torch.compile")
82
- else:
83
- face_parser_compiled = face_parser
84
- except Exception as e:
85
- logger.warning(f"torch.compile failed: {e}, using normal mode")
86
- face_parser_compiled = face_parser
87
-
88
  logger.info("✅ Face parser loaded")
89
 
90
  def load_beard_model():
@@ -99,26 +80,21 @@ def load_beard_model():
99
  def get_hair_and_exclude_masks(pil_image: Image.Image):
100
  load_face_parser()
101
  orig_w, orig_h = pil_image.size
102
-
103
- # Use 128x128 (already fast)
104
  img_small = pil_image.resize((128, 128), Image.BILINEAR)
105
 
106
  inputs = face_processor(images=img_small, return_tensors="pt").to(DEVICE)
107
 
108
  with torch.inference_mode():
109
- if face_parser_compiled is not None:
110
- out = face_parser_compiled(**inputs)
111
- else:
112
- out = face_parser(**inputs)
113
  logits = out.logits
114
  up = torch.nn.functional.interpolate(logits, size=(128, 128), mode="bilinear", align_corners=False)
115
  probs = torch.softmax(up, dim=1)[0]
116
 
117
- # Hair mask (optimized threshold)
118
- hair = (probs[13].cpu().numpy() > 0.04).astype(np.float32) # thoda loose for speed
119
- hair = cv2.GaussianBlur(hair, (3,3), 0.8)
120
 
121
- # Face exclude (simplified a bit)
122
  parsing = up.argmax(dim=1).squeeze(0).cpu().numpy()
123
  face_cls = list(range(1,6)) + list(range(8,13)) + [17,18]
124
  face_m = np.isin(parsing, face_cls).astype(np.float32)
@@ -128,17 +104,16 @@ def get_hair_and_exclude_masks(pil_image: Image.Image):
128
 
129
  h, w = face_m.shape
130
  forehead = np.zeros_like(face_m, dtype=np.float32)
131
- forehead[:int(h*0.32)] = 1.0
132
  face_m = face_m * (1 - forehead * 0.45)
133
-
134
  hair = hair * (1 - face_m)
135
  hair = cv2.resize(hair, (orig_w, orig_h), interpolation=cv2.INTER_LINEAR)
136
 
137
- # Exclude mask (nose+lips) - fast path
138
- exclude = np.zeros((128,128), dtype=np.float32)
139
- exclude = np.maximum(exclude, (probs[2] > 0.5).cpu().numpy())
140
- exclude = np.maximum(exclude, (probs[11] > 0.5).cpu().numpy())
141
- exclude = np.maximum(exclude, (probs[12] > 0.5).cpu().numpy())
142
  exclude = cv2.resize(exclude, (orig_w, orig_h), interpolation=cv2.INTER_NEAREST)
143
  exclude = cv2.dilate(exclude, kernel, iterations=1)
144
 
@@ -149,21 +124,18 @@ def get_hair_and_exclude_masks(pil_image: Image.Image):
149
  def get_beard_mask_fast(pil_image: Image.Image, exclude_mask: np.ndarray):
150
  model = load_beard_model()
151
  orig_w, orig_h = pil_image.size
152
-
153
- # Use 128x128 with streaming for slight speedup
154
  img_small = pil_image.resize((128, 128), Image.BILINEAR)
155
  img_array = np.array(img_small)
156
 
157
  results = model.predict(
158
  img_array,
159
  device=DEVICE.type,
160
- conf=0.30, # thoda tight for speed
161
  iou=0.50,
162
  imgsz=128,
163
  half=(DEVICE.type == "cuda"),
164
  verbose=False,
165
- max_det=8,
166
- stream=True # helps in some cases
167
  )
168
 
169
  mask = np.zeros((orig_h, orig_w), dtype=np.float32)
@@ -184,11 +156,8 @@ def get_beard_mask_fast(pil_image: Image.Image, exclude_mask: np.ndarray):
184
  return mask
185
 
186
 
187
- # Color Transfer part same rakha hai (already fast hai, sirf minor clean)
188
-
189
  @timed("Color Transfer")
190
  def apply_strong_grey_hair(image: Image.Image, hair_mask: np.ndarray, beard_mask: np.ndarray):
191
- # (same as previous optimized version - no major change needed here)
192
  comb = np.maximum(hair_mask, beard_mask)
193
  if comb.sum() < 100:
194
  comb = cv2.GaussianBlur(comb, (5,5), 1.5)
@@ -237,7 +206,7 @@ def apply_strong_grey_hair(image: Image.Image, hair_mask: np.ndarray, beard_mask
237
  return result
238
 
239
 
240
- # ====================== MAIN ======================
241
  @timed("Total Processing")
242
  def process_face_whitening(input_image: Image.Image):
243
  orig = input_image.convert("RGB")
 
27
  logger.info(f"Using Device: {DEVICE}")
28
  logger.info(f"CUDA Available: {torch.cuda.is_available()}")
29
 
30
+ # CPU Optimization (stable settings)
31
  if DEVICE.type == "cpu":
32
  torch.set_num_threads(4)
33
  torch.set_num_interop_threads(1)
34
  cv2.setNumThreads(4)
 
 
 
 
 
 
35
  else:
36
  torch.set_num_threads(1)
37
 
 
43
  face_processor = None
44
  face_parser = None
45
  beard_model = None
 
46
 
47
  # ====================== TIMED DECORATOR ======================
48
  def timed(name: str):
 
58
 
59
  # ====================== MODEL LOADING ======================
60
  def load_face_parser():
61
+ global face_processor, face_parser
62
  if face_parser is not None:
63
  return
64
  logger.info("Loading Segformer Face Parser...")
 
66
  face_parser = SegformerForSemanticSegmentation.from_pretrained("jonathandinu/face-parsing")
67
  face_parser.to(DEVICE)
68
  face_parser.eval()
 
 
 
 
 
 
 
 
 
 
 
 
69
  logger.info("✅ Face parser loaded")
70
 
71
  def load_beard_model():
 
80
  def get_hair_and_exclude_masks(pil_image: Image.Image):
81
  load_face_parser()
82
  orig_w, orig_h = pil_image.size
 
 
83
  img_small = pil_image.resize((128, 128), Image.BILINEAR)
84
 
85
  inputs = face_processor(images=img_small, return_tensors="pt").to(DEVICE)
86
 
87
  with torch.inference_mode():
88
+ out = face_parser(**inputs)
 
 
 
89
  logits = out.logits
90
  up = torch.nn.functional.interpolate(logits, size=(128, 128), mode="bilinear", align_corners=False)
91
  probs = torch.softmax(up, dim=1)[0]
92
 
93
+ # Optimized hair mask
94
+ hair = (probs[13].cpu().numpy() > 0.04).astype(np.float32)
95
+ hair = cv2.GaussianBlur(hair, (3, 3), 0.8)
96
 
97
+ # Face exclude
98
  parsing = up.argmax(dim=1).squeeze(0).cpu().numpy()
99
  face_cls = list(range(1,6)) + list(range(8,13)) + [17,18]
100
  face_m = np.isin(parsing, face_cls).astype(np.float32)
 
104
 
105
  h, w = face_m.shape
106
  forehead = np.zeros_like(face_m, dtype=np.float32)
107
+ forehead[:int(h * 0.32)] = 1.0
108
  face_m = face_m * (1 - forehead * 0.45)
 
109
  hair = hair * (1 - face_m)
110
  hair = cv2.resize(hair, (orig_w, orig_h), interpolation=cv2.INTER_LINEAR)
111
 
112
+ # Exclude mask (nose + lips)
113
+ exclude = np.zeros((128, 128), dtype=np.float32)
114
+ exclude = np.maximum(exclude, (probs[2] > 0.5).cpu().numpy().astype(np.float32))
115
+ exclude = np.maximum(exclude, (probs[11] > 0.5).cpu().numpy().astype(np.float32))
116
+ exclude = np.maximum(exclude, (probs[12] > 0.5).cpu().numpy().astype(np.float32))
117
  exclude = cv2.resize(exclude, (orig_w, orig_h), interpolation=cv2.INTER_NEAREST)
118
  exclude = cv2.dilate(exclude, kernel, iterations=1)
119
 
 
124
  def get_beard_mask_fast(pil_image: Image.Image, exclude_mask: np.ndarray):
125
  model = load_beard_model()
126
  orig_w, orig_h = pil_image.size
 
 
127
  img_small = pil_image.resize((128, 128), Image.BILINEAR)
128
  img_array = np.array(img_small)
129
 
130
  results = model.predict(
131
  img_array,
132
  device=DEVICE.type,
133
+ conf=0.30,
134
  iou=0.50,
135
  imgsz=128,
136
  half=(DEVICE.type == "cuda"),
137
  verbose=False,
138
+ max_det=8
 
139
  )
140
 
141
  mask = np.zeros((orig_h, orig_w), dtype=np.float32)
 
156
  return mask
157
 
158
 
 
 
159
  @timed("Color Transfer")
160
  def apply_strong_grey_hair(image: Image.Image, hair_mask: np.ndarray, beard_mask: np.ndarray):
 
161
  comb = np.maximum(hair_mask, beard_mask)
162
  if comb.sum() < 100:
163
  comb = cv2.GaussianBlur(comb, (5,5), 1.5)
 
206
  return result
207
 
208
 
209
+ # ====================== MAIN PROCESSING ======================
210
  @timed("Total Processing")
211
  def process_face_whitening(input_image: Image.Image):
212
  orig = input_image.convert("RGB")