MogensR commited on
Commit
0197715
·
1 Parent(s): 9f555b8

Update utilities.py

Browse files
Files changed (1) hide show
  1. utilities.py +24 -15
utilities.py CHANGED
@@ -4,6 +4,7 @@
4
  Contains all the utility functions, background creation functions
5
  UPDATED: Models passed as parameters instead of globals
6
  CRITICAL FIX: Fixed transparency issue in replace_background_hq function
 
7
  """
8
 
9
  import os
@@ -255,10 +256,10 @@ def create_green_screen_background(frame):
255
  return green_screen
256
 
257
  # ============================================================================ #
258
- # CRITICAL FIX: REPLACE THIS ENTIRE FUNCTION TO FIX TRANSPARENCY ISSUE
259
  # ============================================================================ #
260
  def replace_background_hq(frame, mask, background):
261
- """High-quality background replacement with FIXED binary masking - NO TRANSPARENCY"""
262
  try:
263
  # Resize background to match frame
264
  background = cv2.resize(background, (frame.shape[1], frame.shape[0]), interpolation=cv2.INTER_LANCZOS4)
@@ -267,30 +268,36 @@ def replace_background_hq(frame, mask, background):
267
  if len(mask.shape) == 3:
268
  mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
269
 
270
- # ===== CRITICAL FIX: BINARIZE THE MASK TO PREVENT TRANSPARENCY =====
271
- # This is the key change - force mask to be either 0 or 1, no in-between values
272
- threshold = 128 # You can adjust this value between 100-200 if needed
273
  _, mask_binary = cv2.threshold(mask, threshold, 255, cv2.THRESH_BINARY)
274
 
 
 
 
 
 
 
 
 
 
275
  # Convert to float and normalize
276
  mask_float = mask_binary.astype(np.float32) / 255.0
277
 
278
- # Optional: Apply MINIMAL edge feathering AFTER binarization
279
- # This gives smooth edges without making the whole person transparent
280
- feather_radius = 2 # Reduced from 3 to minimize transparency
281
  kernel_size = feather_radius * 2 + 1
282
  mask_feathered = cv2.GaussianBlur(mask_float, (kernel_size, kernel_size), feather_radius/3)
283
 
284
- # Ensure strong opacity in the center (prevent ghosting)
285
- # Boost high values and reduce low values to maintain solid appearance
286
  mask_feathered = np.where(mask_feathered > 0.5,
287
- np.minimum(mask_feathered * 1.2, 1.0), # Boost high values (but cap at 1.0)
288
  mask_feathered * 0.8) # Reduce low values
289
 
290
  # Create 3-channel mask
291
  mask_3channel = np.stack([mask_feathered] * 3, axis=2)
292
 
293
- # Simple compositing (skip gamma correction for now to ensure solidity)
294
  result = frame * mask_3channel + background * (1 - mask_3channel)
295
  result = np.clip(result, 0, 255).astype(np.uint8)
296
 
@@ -298,13 +305,15 @@ def replace_background_hq(frame, mask, background):
298
 
299
  except Exception as e:
300
  logger.error(f"Background replacement error: {e}")
301
- # Fallback to simple replacement - ALSO FIXED WITH BINARY MASK
302
  try:
303
  if len(mask.shape) == 3:
304
  mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
305
  background = cv2.resize(background, (frame.shape[1], frame.shape[0]))
306
- # Also fix the fallback with binary threshold
307
- _, mask_binary = cv2.threshold(mask, 128, 255, cv2.THRESH_BINARY)
 
 
308
  mask_normalized = mask_binary.astype(np.float32) / 255.0
309
  mask_3channel = np.stack([mask_normalized] * 3, axis=2)
310
  result = frame * mask_3channel + background * (1 - mask_3channel)
 
4
  Contains all the utility functions, background creation functions
5
  UPDATED: Models passed as parameters instead of globals
6
  CRITICAL FIX: Fixed transparency issue in replace_background_hq function
7
+ EDGE IMPROVEMENT: Added morphological operations and adjusted threshold
8
  """
9
 
10
  import os
 
256
  return green_screen
257
 
258
  # ============================================================================ #
259
+ # IMPROVED EDGE HANDLING: Enhanced background replacement function
260
  # ============================================================================ #
261
  def replace_background_hq(frame, mask, background):
262
+ """High-quality background replacement with improved edge handling"""
263
  try:
264
  # Resize background to match frame
265
  background = cv2.resize(background, (frame.shape[1], frame.shape[0]), interpolation=cv2.INTER_LANCZOS4)
 
268
  if len(mask.shape) == 3:
269
  mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
270
 
271
+ # IMPROVED EDGE HANDLING: Adjusted threshold and morphological operations
272
+ threshold = 140 # Increased from 128 for tighter mask
 
273
  _, mask_binary = cv2.threshold(mask, threshold, 255, cv2.THRESH_BINARY)
274
 
275
+ # Clean up edges with morphological operations
276
+ kernel = np.ones((3,3), np.uint8)
277
+ mask_binary = cv2.morphologyEx(mask_binary, cv2.MORPH_CLOSE, kernel) # Fill small holes
278
+ mask_binary = cv2.morphologyEx(mask_binary, cv2.MORPH_OPEN, kernel) # Remove small noise
279
+
280
+ # Optional: Apply erosion then dilation for cleaner edges
281
+ # mask_binary = cv2.erode(mask_binary, kernel, iterations=1)
282
+ # mask_binary = cv2.dilate(mask_binary, kernel, iterations=1)
283
+
284
  # Convert to float and normalize
285
  mask_float = mask_binary.astype(np.float32) / 255.0
286
 
287
+ # Minimal edge feathering for smooth but sharp edges
288
+ feather_radius = 1 # Reduced from 2 for sharper edges
 
289
  kernel_size = feather_radius * 2 + 1
290
  mask_feathered = cv2.GaussianBlur(mask_float, (kernel_size, kernel_size), feather_radius/3)
291
 
292
+ # Ensure strong opacity in the center
 
293
  mask_feathered = np.where(mask_feathered > 0.5,
294
+ np.minimum(mask_feathered * 1.2, 1.0), # Boost high values
295
  mask_feathered * 0.8) # Reduce low values
296
 
297
  # Create 3-channel mask
298
  mask_3channel = np.stack([mask_feathered] * 3, axis=2)
299
 
300
+ # Simple compositing
301
  result = frame * mask_3channel + background * (1 - mask_3channel)
302
  result = np.clip(result, 0, 255).astype(np.uint8)
303
 
 
305
 
306
  except Exception as e:
307
  logger.error(f"Background replacement error: {e}")
308
+ # Fallback with same improvements
309
  try:
310
  if len(mask.shape) == 3:
311
  mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
312
  background = cv2.resize(background, (frame.shape[1], frame.shape[0]))
313
+ _, mask_binary = cv2.threshold(mask, 140, 255, cv2.THRESH_BINARY)
314
+ kernel = np.ones((3,3), np.uint8)
315
+ mask_binary = cv2.morphologyEx(mask_binary, cv2.MORPH_CLOSE, kernel)
316
+ mask_binary = cv2.morphologyEx(mask_binary, cv2.MORPH_OPEN, kernel)
317
  mask_normalized = mask_binary.astype(np.float32) / 255.0
318
  mask_3channel = np.stack([mask_normalized] * 3, axis=2)
319
  result = frame * mask_3channel + background * (1 - mask_3channel)