MogensR commited on
Commit
a6e89c1
·
1 Parent(s): 880475f

Update processing/two_stage/two_stage_processor.py

Browse files
processing/two_stage/two_stage_processor.py CHANGED
@@ -8,12 +8,13 @@
8
  - New: Return green screen path for monitoring
9
  - Fix: Force green key color
10
  - Fix: Use RobustVideoWriter to prevent frame loss
 
11
  """
12
  from __future__ import annotations
13
  import cv2, numpy as np, os, gc, pickle, logging, tempfile, traceback, threading
14
  from pathlib import Path
15
  from utils.cv_processing import segment_person_hq, refine_mask_hq
16
- from quality_manager import quality_manager # New quality manager import
17
  # Project logger if available
18
  try:
19
  from utils.logger import get_logger
@@ -52,22 +53,22 @@ def create_video_writer(output_path: str, fps: float, width: int, height: int, p
52
  # ---------------------------------------------------------------------------
53
  class RobustVideoWriter:
54
  """Wrapper that ensures all frames are written"""
55
-
56
  def __init__(self, writer, output_path: str):
57
  self.writer = writer
58
  self.output_path = output_path
59
  self.frame_buffer = []
60
  self.frames_written = 0
61
  self.frames_attempted = 0
62
-
63
  def write(self, frame):
64
  """Buffer and write frame"""
65
  if frame is None:
66
  return False
67
-
68
  self.frames_attempted += 1
69
  self.frame_buffer.append(frame.copy())
70
-
71
  # Try to write buffered frames
72
  while self.frame_buffer and self.writer:
73
  try:
@@ -78,7 +79,7 @@ def write(self, frame):
78
  logger.warning(f"Frame write failed: {e}")
79
  return False
80
  return True
81
-
82
  def release(self):
83
  """Flush remaining frames and close"""
84
  # Write any remaining buffered frames
@@ -89,7 +90,7 @@ def release(self):
89
  self.frames_written += 1
90
  except Exception:
91
  break
92
-
93
  # Duplicate last frame 3 times to force flush
94
  if self.frames_written > 0 and self.writer:
95
  last_frame = self.frame_buffer[-1] if self.frame_buffer else None
@@ -106,14 +107,14 @@ def release(self):
106
  for _ in range(3):
107
  self.writer.write(last_frame)
108
  self.frames_written += 1
109
-
110
  # Close writer
111
  if self.writer:
112
  self.writer.release()
113
-
114
  # Log statistics
115
  logger.info(f"Video writer closed: {self.frames_written}/{self.frames_attempted} frames written")
116
-
117
  # Verify output exists
118
  if os.path.exists(self.output_path):
119
  size = os.path.getsize(self.output_path)
@@ -178,11 +179,11 @@ def __init__(self, sam2_predictor=None, matanyone_model=None):
178
  # Internal flags/state
179
  self._mat_bootstrapped = False
180
  self._alpha_prev: Optional[np.ndarray] = None # temporal smoothing
181
-
182
  # Frame tracking
183
  self.total_frames_processed = 0
184
  self.frames_refined = 0
185
-
186
  # Load quality profile
187
  self.q = quality_manager.get_params()
188
  logger.info(f"TwoStageProcessor init – SAM2: {self.sam2 is not None} | MatAnyOne: {self.matanyone is not None}")
@@ -307,11 +308,11 @@ def _should_refine_frame(self, frame_idx: int) -> bool:
307
  """Check if current frame should be refined based on quality profile"""
308
  if not self.matanyone:
309
  return False
310
-
311
  # Always refine first frame for bootstrap
312
  if frame_idx == 0:
313
  return True
314
-
315
  return quality_manager.should_refine_frame(frame_idx)
316
  # ---------------------------------------------------------------------
317
  # Stage 1 – Original → keyed (green/blue/…) -- chooses colour on 1st frame
@@ -333,7 +334,7 @@ def _prog(p, d):
333
  pass
334
  try:
335
  # pick up any new quality selection
336
- quality_manager.load_profile() # Refresh
337
  self.q = quality_manager.get_params()
338
  _prog(0.0, "Stage 1: opening video…")
339
  cap = cv2.VideoCapture(video_path)
@@ -347,7 +348,7 @@ def _prog(p, d):
347
  if base_writer is None:
348
  cap.release()
349
  return None, "Could not create output writer"
350
-
351
  # Use robust wrapper
352
  writer = RobustVideoWriter(base_writer, out_path)
353
  key_info: dict | None = None
@@ -414,11 +415,11 @@ def _prog(p, d):
414
  except Exception as e:
415
  logger.warning(f"mask cache save fail: {e}")
416
  _prog(1.0, "Stage 1: complete")
417
-
418
  # Log quality impact
419
  logger.info(f"Stage 1 complete: {frame_idx} frames, {self.frames_refined} refined "
420
  f"({100*self.frames_refined/max(1,frame_idx):.1f}%)")
421
-
422
  return (
423
  {"path": out_path, "frames": frame_idx, "key_bgr": chosen_bgr.tolist()},
424
  f"Green-screen video created ({frame_idx} frames, {self.frames_refined} refined)"
@@ -462,8 +463,9 @@ def _prog(p, d):
462
  if isinstance(background, str):
463
  bg = cv2.imread(background)
464
  if bg is None:
 
465
  cap.release()
466
- return None, "Could not load background image"
467
  bg = cv2.resize(bg, (w, h))
468
  else:
469
  bg = cv2.resize(background, (w, h))
@@ -476,7 +478,7 @@ def _prog(p, d):
476
  if base_writer is None:
477
  cap.release()
478
  return None, "Could not create output writer"
479
-
480
  # Use robust wrapper
481
  writer = RobustVideoWriter(base_writer, out_path)
482
  # Load cached masks if available
@@ -532,11 +534,11 @@ def _prog(p, d):
532
  cap.release()
533
  writer.release()
534
  _prog(1.0, "Stage 2: complete")
535
-
536
  # Verify frame counts match
537
  if total > 0 and frame_idx != total:
538
  logger.warning(f"Frame count mismatch: processed {frame_idx}, expected {total}")
539
-
540
  return out_path, f"Final composite created ({frame_idx} frames)"
541
  except Exception as e:
542
  logger.error(f"Stage 2 error: {e}\n{traceback.format_exc()}")
@@ -631,7 +633,7 @@ def _combined_progress(pct, desc):
631
  self._alpha_prev = None
632
  self.total_frames_processed = 0
633
  self.frames_refined = 0
634
-
635
  if self.matanyone is not None and hasattr(self.matanyone, "reset"):
636
  try:
637
  self.matanyone.reset()
 
8
  - New: Return green screen path for monitoring
9
  - Fix: Force green key color
10
  - Fix: Use RobustVideoWriter to prevent frame loss
11
+ - Fix: Add logging for background preparation issue
12
  """
13
  from __future__ import annotations
14
  import cv2, numpy as np, os, gc, pickle, logging, tempfile, traceback, threading
15
  from pathlib import Path
16
  from utils.cv_processing import segment_person_hq, refine_mask_hq
17
+ from quality_manager import quality_manager # New quality manager import
18
  # Project logger if available
19
  try:
20
  from utils.logger import get_logger
 
53
  # ---------------------------------------------------------------------------
54
  class RobustVideoWriter:
55
  """Wrapper that ensures all frames are written"""
56
+
57
  def __init__(self, writer, output_path: str):
58
  self.writer = writer
59
  self.output_path = output_path
60
  self.frame_buffer = []
61
  self.frames_written = 0
62
  self.frames_attempted = 0
63
+
64
  def write(self, frame):
65
  """Buffer and write frame"""
66
  if frame is None:
67
  return False
68
+
69
  self.frames_attempted += 1
70
  self.frame_buffer.append(frame.copy())
71
+
72
  # Try to write buffered frames
73
  while self.frame_buffer and self.writer:
74
  try:
 
79
  logger.warning(f"Frame write failed: {e}")
80
  return False
81
  return True
82
+
83
  def release(self):
84
  """Flush remaining frames and close"""
85
  # Write any remaining buffered frames
 
90
  self.frames_written += 1
91
  except Exception:
92
  break
93
+
94
  # Duplicate last frame 3 times to force flush
95
  if self.frames_written > 0 and self.writer:
96
  last_frame = self.frame_buffer[-1] if self.frame_buffer else None
 
107
  for _ in range(3):
108
  self.writer.write(last_frame)
109
  self.frames_written += 1
110
+
111
  # Close writer
112
  if self.writer:
113
  self.writer.release()
114
+
115
  # Log statistics
116
  logger.info(f"Video writer closed: {self.frames_written}/{self.frames_attempted} frames written")
117
+
118
  # Verify output exists
119
  if os.path.exists(self.output_path):
120
  size = os.path.getsize(self.output_path)
 
179
  # Internal flags/state
180
  self._mat_bootstrapped = False
181
  self._alpha_prev: Optional[np.ndarray] = None # temporal smoothing
182
+
183
  # Frame tracking
184
  self.total_frames_processed = 0
185
  self.frames_refined = 0
186
+
187
  # Load quality profile
188
  self.q = quality_manager.get_params()
189
  logger.info(f"TwoStageProcessor init – SAM2: {self.sam2 is not None} | MatAnyOne: {self.matanyone is not None}")
 
308
  """Check if current frame should be refined based on quality profile"""
309
  if not self.matanyone:
310
  return False
311
+
312
  # Always refine first frame for bootstrap
313
  if frame_idx == 0:
314
  return True
315
+
316
  return quality_manager.should_refine_frame(frame_idx)
317
  # ---------------------------------------------------------------------
318
  # Stage 1 – Original → keyed (green/blue/…) -- chooses colour on 1st frame
 
334
  pass
335
  try:
336
  # pick up any new quality selection
337
+ quality_manager.load_profile() # Refresh
338
  self.q = quality_manager.get_params()
339
  _prog(0.0, "Stage 1: opening video…")
340
  cap = cv2.VideoCapture(video_path)
 
348
  if base_writer is None:
349
  cap.release()
350
  return None, "Could not create output writer"
351
+
352
  # Use robust wrapper
353
  writer = RobustVideoWriter(base_writer, out_path)
354
  key_info: dict | None = None
 
415
  except Exception as e:
416
  logger.warning(f"mask cache save fail: {e}")
417
  _prog(1.0, "Stage 1: complete")
418
+
419
  # Log quality impact
420
  logger.info(f"Stage 1 complete: {frame_idx} frames, {self.frames_refined} refined "
421
  f"({100*self.frames_refined/max(1,frame_idx):.1f}%)")
422
+
423
  return (
424
  {"path": out_path, "frames": frame_idx, "key_bgr": chosen_bgr.tolist()},
425
  f"Green-screen video created ({frame_idx} frames, {self.frames_refined} refined)"
 
463
  if isinstance(background, str):
464
  bg = cv2.imread(background)
465
  if bg is None:
466
+ logger.error(f"Failed to load background image from {background}")
467
  cap.release()
468
+ return None, "Could not load background image - check file path and permissions"
469
  bg = cv2.resize(bg, (w, h))
470
  else:
471
  bg = cv2.resize(background, (w, h))
 
478
  if base_writer is None:
479
  cap.release()
480
  return None, "Could not create output writer"
481
+
482
  # Use robust wrapper
483
  writer = RobustVideoWriter(base_writer, out_path)
484
  # Load cached masks if available
 
534
  cap.release()
535
  writer.release()
536
  _prog(1.0, "Stage 2: complete")
537
+
538
  # Verify frame counts match
539
  if total > 0 and frame_idx != total:
540
  logger.warning(f"Frame count mismatch: processed {frame_idx}, expected {total}")
541
+
542
  return out_path, f"Final composite created ({frame_idx} frames)"
543
  except Exception as e:
544
  logger.error(f"Stage 2 error: {e}\n{traceback.format_exc()}")
 
633
  self._alpha_prev = None
634
  self.total_frames_processed = 0
635
  self.frames_refined = 0
636
+
637
  if self.matanyone is not None and hasattr(self.matanyone, "reset"):
638
  try:
639
  self.matanyone.reset()