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

Update utilities.py

Browse files
Files changed (1) hide show
  1. utilities.py +27 -16
utilities.py CHANGED
@@ -3,6 +3,7 @@
3
  utilities.py - Helper functions and utilities for Video Background Replacement
4
  Contains all the utility functions, background creation functions
5
  UPDATED: Models passed as parameters instead of globals
 
6
  """
7
 
8
  import os
@@ -253,8 +254,11 @@ def create_green_screen_background(frame):
253
  green_screen = np.full((h, w, 3), (0, 177, 64), dtype=np.uint8)
254
  return green_screen
255
 
 
 
 
256
  def replace_background_hq(frame, mask, background):
257
- """High-quality background replacement with advanced compositing"""
258
  try:
259
  # Resize background to match frame
260
  background = cv2.resize(background, (frame.shape[1], frame.shape[0]), interpolation=cv2.INTER_LANCZOS4)
@@ -263,38 +267,45 @@ def replace_background_hq(frame, mask, background):
263
  if len(mask.shape) == 3:
264
  mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
265
 
266
- # Normalize mask to 0-1 range
267
- mask_float = mask.astype(np.float32) / 255.0
 
 
268
 
269
- # Edge feathering for smooth transitions
270
- feather_radius = 3
 
 
 
 
271
  kernel_size = feather_radius * 2 + 1
272
  mask_feathered = cv2.GaussianBlur(mask_float, (kernel_size, kernel_size), feather_radius/3)
273
 
 
 
 
 
 
 
274
  # Create 3-channel mask
275
  mask_3channel = np.stack([mask_feathered] * 3, axis=2)
276
 
277
- # Linear gamma correction for proper compositing
278
- frame_linear = np.power(frame.astype(np.float32) / 255.0, 2.2)
279
- background_linear = np.power(background.astype(np.float32) / 255.0, 2.2)
280
-
281
- # Composite in linear space
282
- result_linear = frame_linear * mask_3channel + background_linear * (1 - mask_3channel)
283
-
284
- # Convert back to gamma space
285
- result = np.power(result_linear, 1/2.2) * 255.0
286
  result = np.clip(result, 0, 255).astype(np.uint8)
287
 
288
  return result
289
 
290
  except Exception as e:
291
  logger.error(f"Background replacement error: {e}")
292
- # Fallback to simple replacement
293
  try:
294
  if len(mask.shape) == 3:
295
  mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
296
  background = cv2.resize(background, (frame.shape[1], frame.shape[0]))
297
- mask_normalized = mask.astype(np.float32) / 255.0
 
 
298
  mask_3channel = np.stack([mask_normalized] * 3, axis=2)
299
  result = frame * mask_3channel + background * (1 - mask_3channel)
300
  return result.astype(np.uint8)
 
3
  utilities.py - Helper functions and utilities for Video Background Replacement
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
 
254
  green_screen = np.full((h, w, 3), (0, 177, 64), dtype=np.uint8)
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
  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
 
297
  return result
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)
311
  return result.astype(np.uint8)