Astridkraft commited on
Commit
284f90e
·
verified ·
1 Parent(s): a40fa2d

Update sam_module.py

Browse files
Files changed (1) hide show
  1. sam_module.py +219 -1
sam_module.py CHANGED
@@ -36,6 +36,224 @@ def create_sam_mask(self, image, bbox_coords, mode):
36
  print("-" * 60)
37
  print("🌳 MODUS: ENVIRONMENT_CHANGE")
38
  print("-" * 60)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  # ... existierende environment_change Logik hier komplett ...
41
  # (wird aus dem Original übernommen, nicht verändert)
@@ -77,7 +295,7 @@ def create_sam_mask(self, image, bbox_coords, mode):
77
  mask = Image.fromarray(mask_array).convert("L")
78
  mask = mask.resize(original_image.size, Image.Resampling.NEAREST)
79
 
80
- return mask, mask # raw_mask gleiche wie finale Maske
81
 
82
  # ============================================================
83
  # BLOCK 2: FOCUS_CHANGE (KORRIGIERTE VERSION)
 
36
  print("-" * 60)
37
  print("🌳 MODUS: ENVIRONMENT_CHANGE")
38
  print("-" * 60)
39
+
40
+
41
+ # Bild für SAM vorbereiten
42
+ image_np = np.array(image.convert("RGB"))
43
+
44
+
45
+ # Immer nur eine BBox verwenden (SAM 2 erwartet genau 1)
46
+ input_boxes = [[[x1, y1, x2, y2]]]
47
+
48
+ # Aufruf des SAM-Prozessors mit den Variablen. Der Processor verpackt diese Rohdaten
49
+ # in die für das SAM-Modell erforderlichen Tensoren und speichert sie in inputs.
50
+ inputs = self.sam_processor(
51
+ image_np,
52
+ input_boxes=input_boxes,
53
+ return_tensors="pt"
54
+ ).to(self.device) # Ohne .to(self.device) werden die Tensoren standardmäßig im CPU-RAM erzeugt und gespeichert! Da GPU-Fehler!
55
+
56
+ print(f" - 'input_boxes' Shape: {inputs['input_boxes'].shape}")
57
+
58
+ # SAM2 Vorhersage
59
+ print("-" * 60)
60
+ print("🧠 SAM 2 INFERENZ (Vorhersage)")
61
+ with torch.no_grad():
62
+ print(" Führe Vorhersage durch...")
63
+ outputs = self.sam_model(**inputs)
64
+ print(f"✅ Vorhersage abgeschlossen")
65
+ print(f" Anzahl der Vorhersagemasken: {outputs.pred_masks.shape[2]}")
66
+
67
+ num_masks = outputs.pred_masks.shape[2]
68
+ print(f" SAM lieferte {num_masks} verschiedene Masken")
69
+
70
+ bbox_center = ((x1 + x2) // 2, (y1 + y2) // 2)
71
+ bbox_area = (x2 - x1) * (y2 - y1)
72
+ print(f" Erwartetes BBox-Zentrum: {bbox_center}")
73
+ print(f" Erwartete BBox-Fläche: {bbox_area:,} Pixel")
74
+
75
+ print("🤔 HEURISTIK: Beste Maske auswählen")
76
+ best_mask_idx = 0
77
+ best_score = -1
78
+
79
+ # Alle 3 Masken analysieren (OHNE sie alle zu skalieren!)
80
+ for i in range(3):
81
+ # Maske in Original-SAM-Größe (256x256) analysieren
82
+ mask_256 = outputs.pred_masks[:, :, i, :, :]
83
+ mask_np_256 = mask_256.sigmoid().squeeze().cpu().numpy()
84
+
85
+ # Für Heuristik: Temporär auf Bildgröße skalieren für Flächenverhältnis und Schwerpunktposition
86
+ temp_mask = F.interpolate(
87
+ mask_256,
88
+ size=(image.height, image.width),
89
+ mode='bilinear',
90
+ align_corners=False
91
+ ).squeeze()
92
+
93
+ mask_np_temp = temp_mask.sigmoid().cpu().numpy()
94
+
95
+ # Adaptive Vor-Filterung (prüft ob Maske überhaupt gültig ist)
96
+ mask_max = mask_np_temp.max()
97
+ if mask_max < 0.3:
98
+ continue # Maske überspringen
99
+
100
+ adaptive_threshold = max(0.3, mask_max * 0.7)
101
+ mask_binary = (mask_np_temp > adaptive_threshold).astype(np.uint8)
102
+
103
+ # wenn nur schwarze Pixel (keine Segmentierung) nimm die nächste Maske
104
+ if np.sum(mask_binary) == 0:
105
+ print(f" ❌ Maske {i+1}: Keine Pixel nach adaptive_threshold {adaptive_threshold:.3f}")
106
+ continue
107
+
108
+ # Heuristik-Berechnung
109
+ mask_area_pixels = np.sum(mask_binary)
110
+
111
+ bbox_mask = np.zeros((image.height, image.width), dtype=np.uint8)
112
+ bbox_mask[y1:y2, x1:x2] = 1
113
+
114
+ overlap = np.sum(mask_binary & bbox_mask)
115
+ bbox_overlap_ratio = overlap / np.sum(bbox_mask) if np.sum(bbox_mask) > 0 else 0
116
+
117
+ # Schwerpunkt berechnen
118
+ y_coords, x_coords = np.where(mask_binary > 0)
119
+ if len(y_coords) > 0:
120
+ centroid_y = np.mean(y_coords)
121
+ centroid_x = np.mean(x_coords)
122
+ centroid_distance = np.sqrt((centroid_x - bbox_center[0])**2 + (centroid_y - bbox_center[1])**2)
123
+ normalized_distance = centroid_distance / max(image.width, image.height)
124
+ else:
125
+ normalized_distance = 1.0
126
+
127
+ # Flächen-Ratio
128
+ area_ratio = mask_area_pixels / bbox_area
129
+ area_score = 1.0 - min(abs(area_ratio - 1.0), 1.0)
130
+
131
+ # Konfidenz
132
+ confidence_score = mask_max
133
+
134
+ # Standard-Score
135
+ score = (
136
+ bbox_overlap_ratio * 0.4 +
137
+ (1.0 - normalized_distance) * 0.25 +
138
+ area_score * 0.25 +
139
+ confidence_score * 0.1
140
+ )
141
+
142
+ print(f" 📊 STANDARD-SCORES für Maske {i+1}:")
143
+ print(f" • BBox-Überlappung: {bbox_overlap_ratio:.3f}")
144
+ print(f" • Zentrums-Distanz: {centroid_distance if 'centroid_distance' in locals() else 'N/A'}")
145
+ print(f" • Flächen-Ratio: {area_ratio:.3f}")
146
+ print(f" • GESAMTSCORE: {score:.3f}")
147
+
148
+ if score > best_score:
149
+ best_score = score
150
+ best_mask_idx = i
151
+ print(f" 🏆 Neue beste Maske: Nr. {i+1} mit Score {score:.3f}")
152
+
153
+ print(f"✅ Beste Maske ausgewählt: Nr. {best_mask_idx+1} mit Score {best_score:.3f}")
154
+
155
+ # Beste Maske verwenden
156
+ mask_np = all_masks[best_mask_idx]
157
+
158
+
159
+
160
+
161
+
162
+
163
+ # Für environment_change: Originalbildgröße beibehalten
164
+ if image.size != original_image.size:
165
+ print(f" ⚠️ Bildgröße angepasst: {image.size} → {original_image.size}")
166
+ temp_mask = Image.fromarray(mask_array).convert("L")
167
+ temp_mask = temp_mask.resize(original_image.size, Image.Resampling.NEAREST)
168
+ mask_array = np.array(temp_mask)
169
+ print(f" ✅ Maske auf Originalgröße skaliert: {mask_array.shape}")
170
+
171
+ # DEBUG: Zustand VOR der Invertierung
172
+ print("🔍 DEBUG VOR INVERTIERUNG:")
173
+ print(f" mask_array Min/Max: {mask_array.min()}/{mask_array.max()}")
174
+ print(f" Weiße Pixel (vorher): {np.sum(mask_array > 127)}")
175
+ print(f" Schwarze Pixel (vorher): {np.sum(mask_array <= 127)}")
176
+
177
+ # Maske invertieren (Person wird schwarz, Hintergrund weiß)
178
+ mask_array = 255 - mask_array
179
+ print(" ✅ Maske invertiert (Person schwarz, Hintergrund weiß)")
180
+
181
+ # DEBUG: Zustand NACH der Invertierung
182
+ print("🔍 DEBUG NACH INVERTIERUNG:")
183
+ print(f" mask_array Min/Max: {mask_array.min()}/{mask_array.max()}")
184
+ print(f" Weiße Pixel (Hintergrund): {np.sum(mask_array > 127)}")
185
+ print(f" Schwarze Pixel (Person): {np.sum(mask_array <= 127)}")
186
+
187
+ # Weiße Punkte in der Person (schwarz) entfernen
188
+ print("🧹 Entferne weiße Punkte in der Person...")
189
+ kernel_open = np.ones((3, 3), np.uint8)
190
+ mask_array = cv2.morphologyEx(mask_array, cv2.MORPH_OPEN, kernel_open, iterations=3)
191
+ print(" ✅ MORPH_OPEN entfernt weiße Punkte in der Person")
192
+
193
+ # DEBUG nach MORPH_OPEN
194
+ print(f" Nach MORPH_OPEN - Weiße Pixel: {np.sum(mask_array > 127)}")
195
+
196
+ # Morphologische Operationen für saubere Umgebung
197
+ print("🔧 Verbessere Umgebungsmaske...")
198
+ kernel_close = np.ones((5, 5), np.uint8)
199
+ mask_array = cv2.morphologyEx(mask_array, cv2.MORPH_CLOSE, kernel_close)
200
+ print(" ✅ MORPH_CLOSE für zusammenhängende Umgebung")
201
+
202
+ # DEBUG nach MORPH_CLOSE
203
+ print(f" Nach MORPH_CLOSE - Weiße Pixel: {np.sum(mask_array > 127)}")
204
+
205
+ # Weiche Ränder für bessere Integration der Person
206
+ print("🌈 Erstelle weiche Übergänge...")
207
+ mask_array = cv2.GaussianBlur(mask_array, (9, 9), 2.0)
208
+ print(" ✅ Gaussian Blur für weiche Übergänge")
209
+
210
+ # DEBUG nach Gaussian Blur
211
+ print(f" Nach Gaussian Blur - Min/Max: {mask_array.min()}/{mask_array.max()}")
212
+ print(f" Nach Gaussian Blur - dtype: {mask_array.dtype}")
213
+
214
+ # Gamma-Korrektur für präzisere Ränder
215
+ print("🎛️ Wende Gamma-Korrektur an...")
216
+ mask_array = mask_array.astype(np.float32) / 255.0
217
+ print(f" Konvertiert zu Float32: Min={mask_array.min():.3f}, Max={mask_array.max():.3f}")
218
+
219
+ mask_array = np.clip(mask_array, 0.0, 1.0)
220
+ mask_array = mask_array ** 0.85 # Gamma-Korrektur
221
+ print(f" Nach Gamma 0.85: Min={mask_array.min():.3f}, Max={mask_array.max():.3f}")
222
+
223
+ mask_array = (mask_array * 255).astype(np.uint8)
224
+ print(" ✅ Gamma-Korrektur (0.85) gegen milchige Ränder")
225
+
226
+ # FINALE QUALITÄTSKONTROLLE
227
+ print("-" * 60)
228
+ print("📊 FINALE MASKEN-STATISTIK (ENVIRONMENT_CHANGE)")
229
+
230
+ white_pixels = np.sum(mask_array > 127)
231
+ black_pixels = np.sum(mask_array <= 127)
232
+ total_pixels = mask_array.size
233
+
234
+ white_ratio = white_pixels / total_pixels * 100
235
+ black_ratio = black_pixels / total_pixels * 100
236
+
237
+ print(f" Weiße Pixel (HINTERGRUND - Veränderung): {white_pixels:,} ({white_ratio:.1f}%)")
238
+ print(f" Schwarze Pixel (PERSON - Erhaltung): {black_pixels:,} ({black_ratio:.1f}%)")
239
+ print(f" Gesamtpixel: {total_pixels:,}")
240
+
241
+ # Warnungen basierend auf Verhältnis
242
+ if white_ratio < 30:
243
+ print(f" ⚠️ WARNUNG: Sehr wenig Hintergrund ({white_ratio:.1f}%)")
244
+ print(f" ℹ️ Das könnte bedeuten, dass die Person zu groß segmentiert wurde")
245
+ elif white_ratio > 90:
246
+ print(f" ⚠️ WARNUNG: Sehr viel Hintergrund ({white_ratio:.1f}%)")
247
+ print(f" ℹ️ Das könnte bedeuten, dass die Person zu klein segmentiert wurde")
248
+ elif 50 <= white_ratio <= 80:
249
+ print(f" ✅ OPTIMALES Verhältnis ({white_ratio:.1f}%)")
250
+ else:
251
+ print(f" ℹ️ Normales Verhältnis ({white_ratio:.1f}%)")
252
+
253
+ # Zurück zu PIL Image
254
+ mask = Image.fromarray(mask_array).convert("L")
255
+ print(f" Finale Maskengröße: {mask.size}")
256
+ print("-" * 60)
257
 
258
  # ... existierende environment_change Logik hier komplett ...
259
  # (wird aus dem Original übernommen, nicht verändert)
 
295
  mask = Image.fromarray(mask_array).convert("L")
296
  mask = mask.resize(original_image.size, Image.Resampling.NEAREST)
297
 
298
+ return mask, raw_mask # raw_mask gleiche wie finale Maske
299
 
300
  # ============================================================
301
  # BLOCK 2: FOCUS_CHANGE (KORRIGIERTE VERSION)