MogensR commited on
Commit
6d91182
·
1 Parent(s): 39171fb

Create processing/two_stage/quality_profiles.py

Browse files
processing/two_stage/quality_profiles.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Enhanced Quality Profile Manager for Two-Stage Processing
3
+ THIS IS A NEW FILE - Create this to separate quality management logic
4
+ """
5
+ import os
6
+ import logging
7
+ from typing import Dict, Any, Optional
8
+ from dataclasses import dataclass, asdict
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ @dataclass
13
+ class QualityProfile:
14
+ """Quality profile with all tunable parameters"""
15
+ # MatAnyone refinement
16
+ refine_enabled: bool = True
17
+ refine_cadence: int = 3 # Process every N frames (1=every frame)
18
+ refine_start_frame: int = 0 # Start refinement from this frame
19
+
20
+ # Mask processing
21
+ mask_dilate: int = 5 # Morphological dilation radius
22
+ mask_blur: int = 3 # Gaussian blur for feathering
23
+ mask_threshold: float = 0.5 # Binary threshold
24
+
25
+ # Chroma keying
26
+ chroma_tolerance: float = 30.0 # Color distance tolerance
27
+ chroma_softness: float = 10.0 # Edge softness
28
+ spill_suppression: float = 0.3 # Green/blue spill removal strength
29
+
30
+ # Hybrid mixing
31
+ hybrid_mix: float = 0.7 # 0=pure chroma, 1=pure segmentation
32
+ temporal_smooth: float = 0.2 # Temporal consistency weight
33
+
34
+ # Edge refinement
35
+ edge_feather: int = 5 # Edge feathering radius
36
+ edge_contrast: float = 1.2 # Edge contrast enhancement
37
+
38
+ # Background
39
+ bg_blur_sigma: float = 1.0 # Background blur strength
40
+
41
+ # Performance
42
+ max_resolution: int = 1080 # Max processing resolution
43
+ batch_size: int = 1 # Frames to process in parallel
44
+
45
+ # Define quality presets with VISIBLE differentiation
46
+ QUALITY_PRESETS = {
47
+ "speed": QualityProfile(
48
+ refine_enabled=True,
49
+ refine_cadence=10, # Refine every 10th frame only
50
+ refine_start_frame=0,
51
+ mask_dilate=3,
52
+ mask_blur=1,
53
+ mask_threshold=0.5,
54
+ chroma_tolerance=40.0, # Less precise
55
+ chroma_softness=15.0,
56
+ spill_suppression=0.1, # Minimal spill work
57
+ hybrid_mix=0.5, # Balanced mix
58
+ temporal_smooth=0.1,
59
+ edge_feather=2,
60
+ edge_contrast=1.0,
61
+ bg_blur_sigma=0.5,
62
+ max_resolution=720,
63
+ batch_size=2
64
+ ),
65
+ "balanced": QualityProfile(
66
+ refine_enabled=True,
67
+ refine_cadence=3, # Refine every 3rd frame
68
+ refine_start_frame=0,
69
+ mask_dilate=5,
70
+ mask_blur=3,
71
+ mask_threshold=0.5,
72
+ chroma_tolerance=30.0,
73
+ chroma_softness=10.0,
74
+ spill_suppression=0.3,
75
+ hybrid_mix=0.7, # Favor segmentation
76
+ temporal_smooth=0.2,
77
+ edge_feather=5,
78
+ edge_contrast=1.2,
79
+ bg_blur_sigma=1.0,
80
+ max_resolution=1080,
81
+ batch_size=1
82
+ ),
83
+ "max": QualityProfile(
84
+ refine_enabled=True,
85
+ refine_cadence=1, # Refine EVERY frame
86
+ refine_start_frame=0,
87
+ mask_dilate=7, # Stronger hole filling
88
+ mask_blur=5, # Smoother edges
89
+ mask_threshold=0.45,
90
+ chroma_tolerance=20.0, # More precise
91
+ chroma_softness=5.0, # Sharper edges
92
+ spill_suppression=0.6, # Strong spill removal
93
+ hybrid_mix=0.85, # Heavy favor to segmentation
94
+ temporal_smooth=0.3, # More temporal consistency
95
+ edge_feather=7,
96
+ edge_contrast=1.5, # Stronger edge enhancement
97
+ bg_blur_sigma=2.0, # More background blur
98
+ max_resolution=1920, # Full HD+
99
+ batch_size=1
100
+ )
101
+ }
102
+
103
+ class QualityManager:
104
+ """Manages quality profiles and settings"""
105
+
106
+ def __init__(self):
107
+ self.current_profile: Optional[QualityProfile] = None
108
+ self.profile_name: str = "balanced"
109
+
110
+ def load_profile(self, profile_name: Optional[str] = None) -> QualityProfile:
111
+ """Load quality profile from environment or parameter"""
112
+ # Check environment variable first
113
+ if profile_name is None:
114
+ profile_name = os.environ.get("BFX_QUALITY", "balanced").lower()
115
+
116
+ # Validate and load profile
117
+ if profile_name not in QUALITY_PRESETS:
118
+ logger.warning(f"Unknown quality profile '{profile_name}', using 'balanced'")
119
+ profile_name = "balanced"
120
+
121
+ self.profile_name = profile_name
122
+ self.current_profile = QUALITY_PRESETS[profile_name]
123
+
124
+ # Log the switch with details
125
+ logger.info(f"Quality switched to '{profile_name}' ⇒ {self._profile_summary()}")
126
+
127
+ return self.current_profile
128
+
129
+ def _profile_summary(self) -> str:
130
+ """Generate a summary of key profile parameters"""
131
+ if not self.current_profile:
132
+ return "No profile loaded"
133
+
134
+ p = self.current_profile
135
+ return (
136
+ f"refine_every={p.refine_cadence} frames, "
137
+ f"spill={p.spill_suppression:.1f}, "
138
+ f"hybrid_mix={p.hybrid_mix:.1f}, "
139
+ f"edge_feather={p.edge_feather}, "
140
+ f"bg_blur={p.bg_blur_sigma:.1f}"
141
+ )
142
+
143
+ def should_refine_frame(self, frame_idx: int) -> bool:
144
+ """Check if current frame should be refined with MatAnyone"""
145
+ if not self.current_profile or not self.current_profile.refine_enabled:
146
+ return False
147
+
148
+ if frame_idx < self.current_profile.refine_start_frame:
149
+ return False
150
+
151
+ # Always refine first frame for bootstrap
152
+ if frame_idx == 0:
153
+ return True
154
+
155
+ # Check cadence
156
+ return (frame_idx % self.current_profile.refine_cadence) == 0
157
+
158
+ def get_params(self) -> Dict[str, Any]:
159
+ """Get current profile as dictionary"""
160
+ if not self.current_profile:
161
+ self.load_profile()
162
+ return asdict(self.current_profile)
163
+
164
+ def log_quality_impact(self, frame_idx: int, processing_time: float):
165
+ """Log quality impact for monitoring"""
166
+ if self.should_refine_frame(frame_idx):
167
+ logger.debug(
168
+ f"Frame {frame_idx}: Refined (quality={self.profile_name}, "
169
+ f"time={processing_time:.3f}s)"
170
+ )
171
+ else:
172
+ logger.debug(
173
+ f"Frame {frame_idx}: Skipped refinement (quality={self.profile_name}, "
174
+ f"time={processing_time:.3f}s)"
175
+ )
176
+
177
+ # Global instance
178
+ quality_manager = QualityManager()
179
+
180
+ def get_quality_profile(profile_name: Optional[str] = None) -> QualityProfile:
181
+ """Get quality profile (convenience function)"""
182
+ return quality_manager.load_profile(profile_name)
183
+
184
+ def should_refine_frame(frame_idx: int) -> bool:
185
+ """Check if frame should be refined (convenience function)"""
186
+ return quality_manager.should_refine_frame(frame_idx)