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

Update sam_module.py

Browse files
Files changed (1) hide show
  1. sam_module.py +137 -147
sam_module.py CHANGED
@@ -111,33 +111,33 @@ def create_sam_mask(self, image, bbox_coords, mode):
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}")
@@ -152,150 +152,140 @@ def create_sam_mask(self, image, bbox_coords, mode):
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)
260
-
261
- # WICHTIG: Du musst den environment_change Code hier einfügen
262
- # von Zeile ~175 bis ~250 aus dem Original
263
-
264
- # Beispiel-Struktur (vereinfacht):
265
- image_np = np.array(image.convert("RGB"))
266
- input_boxes = [[[x1, y1, x2, y2]]]
267
-
268
- # KEINE Punkte für environment_change
269
- inputs = self.sam_processor(
270
- image_np,
271
- input_boxes=input_boxes,
272
- return_tensors="pt"
273
- ).to(self.device)
274
-
275
- with torch.no_grad():
276
- outputs = self.sam_model(**inputs)
277
-
278
- # Nur beste Maske verwenden und auf 512x512 skalieren
279
- best_mask = outputs.pred_masks[:, :, 0, :, :] # Erste Maske nehmen
280
- resized_mask = F.interpolate(
281
- best_mask,
282
- size=(512, 512), # Direkt auf ControlNet-Zielgröße
283
- mode='bilinear',
284
- align_corners=False
285
- ).squeeze()
286
-
287
- mask_np = resized_mask.sigmoid().cpu().numpy()
288
-
289
- # Invertieren für environment_change
290
- threshold = 0.5
291
- mask_array = (mask_np > threshold).astype(np.uint8) * 255
292
- mask_array = 255 - mask_array # Invertieren
293
-
294
- # Auf Originalgröße für Rückgabe
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)
 
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}")
 
152
 
153
  print(f"✅ Beste Maske ausgewählt: Nr. {best_mask_idx+1} mit Score {best_score:.3f}")
154
 
155
+ # Beste Maske verwenden - mask_np beste Maske
156
  mask_np = all_masks[best_mask_idx]
 
157
 
158
+ max_val = mask_np.max()
159
+ print(f" 🔍 Maximaler SAM-Konfidenzwert der besten Maske: {max_val:.3f}")
160
 
161
 
162
+ if max_val < 0.6:
163
+ dynamic_threshold = 0.3
164
+ print(f" ⚠️ SAM ist unsicher (max_val={max_val:.3f} < 0.6)")
165
+ else:
166
+ dynamic_threshold = max_val * 0.8
167
+ print(f" ✅ SAM ist sicher (max_val={max_val:.3f} >= 0.6)")
168
+
169
+
170
+ # Binärmaske erstellen (256x256)
171
+ mask_array = (mask_np > dynamic_threshold).astype(np.uint8) * 255
172
+
173
+
174
+ # Fallback bei leerer Maske, der höchste Wert ist 0 also schwarz
175
+ if mask_array.max() == 0:
176
+ print(" ⚠️ Maske leer, erstelle rechteckige Fallback-Maske")
177
+ mask_array = np.zeros((512, 512), dtype=np.uint8)
178
+ # BBox auf 512x512 skalieren für Fallback
179
+ scale_x = 512 / image.width
180
+ scale_y = 512 / image.height
181
+ fb_x1 = int(x1 * scale_x)
182
+ fb_y1 = int(y1 * scale_y)
183
+ fb_x2 = int(x2 * scale_x)
184
+ fb_y2 = int(y2 * scale_y)
185
+ cv2.rectangle(mask_array, (fb_x1, fb_y1), (fb_x2, fb_y2), 255, -1)
186
+
187
+ # Damit wird die Rohmaske für die UI-Anzeige gespeichert
188
+ raw_mask_array = mask_array.copy()
189
+
190
+
191
+ print("🌳 ENVIRONMENT-CHANGE POSTPROCESSING")
192
 
193
+ # Originalbildgröße beibehalten
194
+ if image.size != original_image.size:
195
+ print(f" ⚠️ Bildgröße angepasst: {image.size} → {original_image.size}")
196
+ temp_mask = Image.fromarray(mask_array).convert("L")
197
+ temp_mask = temp_mask.resize(original_image.size, Image.Resampling.NEAREST)
198
+ mask_array = np.array(temp_mask)
199
+ print(f" ✅ Maske auf Originalgröße skaliert: {mask_array.shape}")
200
+
201
 
202
+ # Maske invertieren (Person wird schwarz, Hintergrund weiß)
203
+ threshold = 0.5
204
+ mask_array = (mask_np > threshold).astype(np.uint8) * 255
205
+ mask_array = 255 - mask_array
206
+ print(" ✅ Maske invertiert (Person schwarz, Hintergrund
207
+
208
+
209
+ # Weiße Punkte in der Person (schwarz) entfernen
210
+ print("🧹 Entferne weiße Punkte in der Person...")
211
+ kernel_open = np.ones((3, 3), np.uint8)
212
+ mask_array = cv2.morphologyEx(mask_array, cv2.MORPH_OPEN, kernel_open, iterations=3)
213
+ print(" MORPH_OPEN entfernt weiße Punkte in der Person")
214
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
 
216
+ # DEBUG nach MORPH_OPEN
217
+ print(f" Nach MORPH_OPEN - Weiße Pixel: {np.sum(mask_array > 127)}")
 
 
 
218
 
219
+ # Morphologische Operationen für saubere Umgebung
220
+ print("🔧 Verbessere Umgebungsmaske...")
221
+ kernel_close = np.ones((5, 5), np.uint8)
222
+ mask_array = cv2.morphologyEx(mask_array, cv2.MORPH_CLOSE, kernel_close)
223
+ print(" ✅ MORPH_CLOSE für zusammenhängende Umgebung")
224
 
225
+ # DEBUG nach MORPH_CLOSE
226
+ print(f" Nach MORPH_CLOSE - Weiße Pixel: {np.sum(mask_array > 127)}")
 
 
227
 
228
+ # Weiche Ränder für bessere Integration der Person
229
+ print("🌈 Erstelle weiche Übergänge...")
230
+ mask_array = cv2.GaussianBlur(mask_array, (9, 9), 2.0)
231
+ print(" ✅ Gaussian Blur für weiche Übergänge")
232
 
233
+ # DEBUG nach Gaussian Blur
234
+ print(f" Nach Gaussian Blur - Min/Max: {mask_array.min()}/{mask_array.max()}")
235
+ print(f" Nach Gaussian Blur - dtype: {mask_array.dtype}")
 
236
 
237
+ # Gamma-Korrektur für präzisere Ränder
238
+ print("🎛️ Wende Gamma-Korrektur an...")
239
+ mask_array = mask_array.astype(np.float32) / 255.0
240
+ print(f" Konvertiert zu Float32: Min={mask_array.min():.3f}, Max={mask_array.max():.3f}")
241
 
242
+ mask_array = np.clip(mask_array, 0.0, 1.0)
243
+ mask_array = mask_array ** 0.85 # Gamma-Korrektur
244
+ print(f" Nach Gamma 0.85: Min={mask_array.min():.3f}, Max={mask_array.max():.3f}")
245
 
246
+ mask_array = (mask_array * 255).astype(np.uint8)
247
+ print(" ✅ Gamma-Korrektur (0.85) gegen milchige Ränder")
 
248
 
249
+ # FINALE QUALITÄTSKONTROLLE
250
+ print("-" * 60)
251
+ print("📊 FINALE MASKEN-STATISTIK (ENVIRONMENT_CHANGE)")
252
 
253
+ white_pixels = np.sum(mask_array > 127)
254
+ black_pixels = np.sum(mask_array <= 127)
255
+ total_pixels = mask_array.size
256
 
257
+ white_ratio = white_pixels / total_pixels * 100
258
+ black_ratio = black_pixels / total_pixels * 100
 
259
 
260
+ print(f" Weiße Pixel (HINTERGRUND - Veränderung): {white_pixels:,} ({white_ratio:.1f}%)")
261
+ print(f" Schwarze Pixel (PERSON - Erhaltung): {black_pixels:,} ({black_ratio:.1f}%)")
262
+ print(f" Gesamtpixel: {total_pixels:,}")
263
+
264
+
265
+ # Warnungen basierend auf Verhältnis
266
+ if white_ratio < 30:
267
+ print(f" ⚠️ WARNUNG: Sehr wenig Hintergrund ({white_ratio:.1f}%)")
268
+ print(f" ℹ️ Das könnte bedeuten, dass die Person zu groß segmentiert wurde")
269
+ elif white_ratio > 90:
270
+ print(f" ⚠️ WARNUNG: Sehr viel Hintergrund ({white_ratio:.1f}%)")
271
+ print(f" ℹ️ Das könnte bedeuten, dass die Person zu klein segmentiert wurde")
272
+ elif 50 <= white_ratio <= 80:
273
+ print(f" ✅ OPTIMALES Verhältnis ({white_ratio:.1f}%)")
274
+ else:
275
+ print(f" ℹ️ Normales Verhältnis ({white_ratio:.1f}%)")
276
+
277
 
278
+ # Zurück zu PIL Image
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
  mask = Image.fromarray(mask_array).convert("L")
280
+ raw_mask = Image.fromarray(raw_mask_array).convert("L")
281
+
282
+ print("#" * 80)
283
+ print(f"✅ SAM 2 SEGMENTIERUNG ABGESCHLOSSEN")
284
+ print(f"📐 Finale Maskengröße: {mask.size}")
285
+ print(f"🎛️ Verwendeter Modus: {mode}")
286
+ print("#" * 80)
287
+
288
+ return mask, raw_mask #in mask steht die invertierte nachbearbeitete Maske, in raw_mask die Rohmaske
289
 
290
  # ============================================================
291
  # BLOCK 2: FOCUS_CHANGE (KORRIGIERTE VERSION)