MogensR commited on
Commit
c6741c9
·
1 Parent(s): 5155650

Update utils/utils.py

Browse files
Files changed (1) hide show
  1. utils/utils.py +215 -1
utils/utils.py CHANGED
@@ -1479,4 +1479,218 @@ def _advanced_compositing(frame: np.ndarray, mask: np.ndarray, background: np.nd
1479
  raise
1480
 
1481
  def _color_match_edges(frame: np.ndarray, background: np.ndarray, alpha: np.ndarray) -> np.ndarray:
1482
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1479
  raise
1480
 
1481
  def _color_match_edges(frame: np.ndarray, background: np.ndarray, alpha: np.ndarray) -> np.ndarray:
1482
+ """Subtle color matching at edges to reduce halos"""
1483
+ try:
1484
+ edge_mask = cv2.Sobel(alpha, cv2.CV_64F, 1, 1, ksize=3)
1485
+ edge_mask = np.abs(edge_mask)
1486
+ edge_mask = (edge_mask > 0.1).astype(np.float32)
1487
+
1488
+ edge_areas = edge_mask > 0
1489
+ if not np.any(edge_areas):
1490
+ return frame
1491
+
1492
+ frame_adjusted = frame.copy().astype(np.float32)
1493
+ background_float = background.astype(np.float32)
1494
+
1495
+ adjustment_strength = 0.1
1496
+ for c in range(3):
1497
+ frame_adjusted[:, :, c] = np.where(
1498
+ edge_areas,
1499
+ frame_adjusted[:, :, c] * (1 - adjustment_strength) +
1500
+ background_float[:, :, c] * adjustment_strength,
1501
+ frame_adjusted[:, :, c]
1502
+ )
1503
+
1504
+ return np.clip(frame_adjusted, 0, 255).astype(np.uint8)
1505
+
1506
+ except Exception as e:
1507
+ logger.warning(f"Color matching failed: {e}")
1508
+ return frame
1509
+
1510
+ def _simple_compositing(frame: np.ndarray, mask: np.ndarray, background: np.ndarray) -> np.ndarray:
1511
+ """Simple fallback compositing method"""
1512
+ try:
1513
+ logger.info("Using simple compositing fallback")
1514
+
1515
+ background = cv2.resize(background, (frame.shape[1], frame.shape[0]))
1516
+
1517
+ if len(mask.shape) == 3:
1518
+ mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
1519
+ if mask.max() <= 1.0:
1520
+ mask = (mask * 255).astype(np.uint8)
1521
+
1522
+ _, mask_binary = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)
1523
+
1524
+ mask_norm = mask_binary.astype(np.float32) / 255.0
1525
+ mask_3ch = np.stack([mask_norm] * 3, axis=2)
1526
+
1527
+ result = frame * mask_3ch + background * (1 - mask_3ch)
1528
+ return result.astype(np.uint8)
1529
+
1530
+ except Exception as e:
1531
+ logger.error(f"Simple compositing failed: {e}")
1532
+ return frame
1533
+
1534
+ def _create_solid_background(bg_config: Dict[str, Any], width: int, height: int) -> np.ndarray:
1535
+ """Create solid color background"""
1536
+ color_hex = bg_config["colors"][0].lstrip('#')
1537
+ color_rgb = tuple(int(color_hex[i:i+2], 16) for i in (0, 2, 4))
1538
+ color_bgr = color_rgb[::-1]
1539
+ return np.full((height, width, 3), color_bgr, dtype=np.uint8)
1540
+
1541
+ def _create_gradient_background_enhanced(bg_config: Dict[str, Any], width: int, height: int) -> np.ndarray:
1542
+ """Create enhanced gradient background with better quality"""
1543
+ try:
1544
+ colors = bg_config["colors"]
1545
+ direction = bg_config.get("direction", "vertical")
1546
+
1547
+ rgb_colors = []
1548
+ for color_hex in colors:
1549
+ color_hex = color_hex.lstrip('#')
1550
+ rgb = tuple(int(color_hex[i:i+2], 16) for i in (0, 2, 4))
1551
+ rgb_colors.append(rgb)
1552
+
1553
+ if not rgb_colors:
1554
+ rgb_colors = [(128, 128, 128)]
1555
+
1556
+ if direction == "vertical":
1557
+ background = _create_vertical_gradient(rgb_colors, width, height)
1558
+ elif direction == "horizontal":
1559
+ background = _create_horizontal_gradient(rgb_colors, width, height)
1560
+ elif direction == "diagonal":
1561
+ background = _create_diagonal_gradient(rgb_colors, width, height)
1562
+ elif direction in ["radial", "soft_radial"]:
1563
+ background = _create_radial_gradient(rgb_colors, width, height, direction == "soft_radial")
1564
+ else:
1565
+ background = _create_vertical_gradient(rgb_colors, width, height)
1566
+
1567
+ return cv2.cvtColor(background, cv2.COLOR_RGB2BGR)
1568
+
1569
+ except Exception as e:
1570
+ logger.error(f"Gradient creation error: {e}")
1571
+ return np.full((height, width, 3), (128, 128, 128), dtype=np.uint8)
1572
+
1573
+ def _create_vertical_gradient(colors: list, width: int, height: int) -> np.ndarray:
1574
+ """Create vertical gradient using NumPy for performance"""
1575
+ gradient = np.zeros((height, width, 3), dtype=np.uint8)
1576
+
1577
+ for y in range(height):
1578
+ progress = y / height if height > 0 else 0
1579
+ color = _interpolate_color(colors, progress)
1580
+ gradient[y, :] = color
1581
+
1582
+ return gradient
1583
+
1584
+ def _create_horizontal_gradient(colors: list, width: int, height: int) -> np.ndarray:
1585
+ """Create horizontal gradient using NumPy for performance"""
1586
+ gradient = np.zeros((height, width, 3), dtype=np.uint8)
1587
+
1588
+ for x in range(width):
1589
+ progress = x / width if width > 0 else 0
1590
+ color = _interpolate_color(colors, progress)
1591
+ gradient[:, x] = color
1592
+
1593
+ return gradient
1594
+
1595
+ def _create_diagonal_gradient(colors: list, width: int, height: int) -> np.ndarray:
1596
+ """Create diagonal gradient using vectorized operations"""
1597
+ y_coords, x_coords = np.mgrid[0:height, 0:width]
1598
+ max_distance = width + height
1599
+ progress = (x_coords + y_coords) / max_distance
1600
+ progress = np.clip(progress, 0, 1)
1601
+
1602
+ gradient = np.zeros((height, width, 3), dtype=np.uint8)
1603
+ for c in range(3):
1604
+ gradient[:, :, c] = _vectorized_color_interpolation(colors, progress, c)
1605
+
1606
+ return gradient
1607
+
1608
+ def _create_radial_gradient(colors: list, width: int, height: int, soft: bool = False) -> np.ndarray:
1609
+ """Create radial gradient using vectorized operations"""
1610
+ center_x, center_y = width // 2, height // 2
1611
+ max_distance = np.sqrt(center_x**2 + center_y**2)
1612
+
1613
+ y_coords, x_coords = np.mgrid[0:height, 0:width]
1614
+ distances = np.sqrt((x_coords - center_x)**2 + (y_coords - center_y)**2)
1615
+ progress = distances / max_distance
1616
+ progress = np.clip(progress, 0, 1)
1617
+
1618
+ if soft:
1619
+ progress = np.power(progress, 0.7)
1620
+
1621
+ gradient = np.zeros((height, width, 3), dtype=np.uint8)
1622
+ for c in range(3):
1623
+ gradient[:, :, c] = _vectorized_color_interpolation(colors, progress, c)
1624
+
1625
+ return gradient
1626
+
1627
+ def _vectorized_color_interpolation(colors: list, progress: np.ndarray, channel: int) -> np.ndarray:
1628
+ """Vectorized color interpolation for performance"""
1629
+ if len(colors) == 1:
1630
+ return np.full_like(progress, colors[0][channel], dtype=np.uint8)
1631
+
1632
+ num_segments = len(colors) - 1
1633
+ segment_progress = progress * num_segments
1634
+ segment_indices = np.floor(segment_progress).astype(int)
1635
+ segment_indices = np.clip(segment_indices, 0, num_segments - 1)
1636
+ local_progress = segment_progress - segment_indices
1637
+
1638
+ start_colors = np.array([colors[i][channel] for i in range(len(colors))])
1639
+ end_colors = np.array([colors[min(i + 1, len(colors) - 1)][channel] for i in range(len(colors))])
1640
+
1641
+ start_vals = start_colors[segment_indices]
1642
+ end_vals = end_colors[segment_indices]
1643
+
1644
+ result = start_vals + (end_vals - start_vals) * local_progress
1645
+ return np.clip(result, 0, 255).astype(np.uint8)
1646
+
1647
+ def _interpolate_color(colors: list, progress: float) -> tuple:
1648
+ """Interpolate between multiple colors"""
1649
+ if len(colors) == 1:
1650
+ return colors[0]
1651
+ elif len(colors) == 2:
1652
+ r = int(colors[0][0] + (colors[1][0] - colors[0][0]) * progress)
1653
+ g = int(colors[0][1] + (colors[1][1] - colors[0][1]) * progress)
1654
+ b = int(colors[0][2] + (colors[1][2] - colors[0][2]) * progress)
1655
+ return (r, g, b)
1656
+ else:
1657
+ segment = progress * (len(colors) - 1)
1658
+ idx = int(segment)
1659
+ local_progress = segment - idx
1660
+ if idx >= len(colors) - 1:
1661
+ return colors[-1]
1662
+ c1, c2 = colors[idx], colors[idx + 1]
1663
+ r = int(c1[0] + (c2[0] - c1[0]) * local_progress)
1664
+ g = int(c1[1] + (c2[1] - c1[1]) * local_progress)
1665
+ b = int(c1[2] + (c2[2] - c1[2]) * local_progress)
1666
+ return (r, g, b)
1667
+
1668
+ def _apply_background_adjustments(background: np.ndarray, bg_config: Dict[str, Any]) -> np.ndarray:
1669
+ """Apply brightness and contrast adjustments to background"""
1670
+ try:
1671
+ brightness = bg_config.get("brightness", 1.0)
1672
+ contrast = bg_config.get("contrast", 1.0)
1673
+
1674
+ if brightness != 1.0 or contrast != 1.0:
1675
+ background = background.astype(np.float32)
1676
+ background = background * contrast * brightness
1677
+ background = np.clip(background, 0, 255).astype(np.uint8)
1678
+
1679
+ return background
1680
+
1681
+ except Exception as e:
1682
+ logger.warning(f"Background adjustment failed: {e}")
1683
+ return background
1684
+
1685
+ # ============================================================================
1686
+ # DEFAULT INSTANCES
1687
+ # ============================================================================
1688
+
1689
+ _default_file_manager = None
1690
+
1691
+ def get_file_manager(base_dir: Optional[str] = None) -> FileManager:
1692
+ """Get or create the default FileManager instance"""
1693
+ global _default_file_manager
1694
+ if _default_file_manager is None or base_dir is not None:
1695
+ _default_file_manager = FileManager(base_dir)
1696
+ return _default_file_manager