Astridkraft commited on
Commit
9d87026
·
verified ·
1 Parent(s): c6a4833

Update controlnet_module.py

Browse files
Files changed (1) hide show
  1. controlnet_module.py +79 -75
controlnet_module.py CHANGED
@@ -293,91 +293,95 @@ class ControlNetProcessor:
293
  cv2.rectangle(mask_array, (fb_x1, fb_y1), (fb_x2, fb_y2), 0, -1)
294
 
295
  # Damit wird die Rohmaske für die UI-Anzeige gespeichert
296
- raw_mask_array = mask_array.copy()
297
 
 
 
 
298
  print("🌳 ENVIRONMENT-CHANGE POSTPROCESSING")
299
 
300
  # Konvertierung zu PIL, hochskalieren auf Originalgröße (korrekte Überlagerung mit O-Bild),
301
  # Konvertierung NumPy für weitere Verarbeitung da mathematisch korrekter als PIL.
302
- if image.size != original_image.size:
303
  print(f" ⚠️ Bildgröße angepasst: {image.size} → {original_image.size}")
304
- temp_mask = Image.fromarray(mask_array).convert("L")
305
- temp_mask = temp_mask.resize(original_image.size, Image.Resampling.NEAREST)
306
- mask_array = np.array(temp_mask)
307
  print(f" ✅ Maske auf Originalgröße skaliert: {mask_array.shape}")
308
-
309
- # Maske invertieren (Person wird schwarz, Hintergrund weiß)
310
- mask_array = 255 - mask_array
311
- print(" ✅ Maske invertiert (Person schwarz, Hintergrund weiß)")
312
-
313
- # Weiße Punkte in der Person (schwarz) entfernen
314
- print("🧹 Entferne weiße Punkte in der Person...")
315
- kernel_open = np.ones((3, 3), np.uint8)
316
- mask_array = cv2.morphologyEx(mask_array, cv2.MORPH_OPEN, kernel_open, iterations=3)
317
- print(" ✅ MORPH_OPEN entfernt weiße Punkte in der Person")
318
-
319
- # DEBUG nach MORPH_OPEN
320
- print(f" Nach MORPH_OPEN - Weiße Pixel: {np.sum(mask_array > 127)}")
321
-
322
- # Morphologische Operationen für saubere Umgebung - entfernt schwarze Pixel aus Umgebung
323
- print("🔧 Verbessere Umgebungsmaske...")
324
- kernel_close = np.ones((5, 5), np.uint8)
325
- mask_array = cv2.morphologyEx(mask_array, cv2.MORPH_CLOSE, kernel_close)
326
- print(" ✅ MORPH_CLOSE für zusammenhängende Umgebung")
327
-
328
- # DEBUG nach MORPH_CLOSE
329
- print(f" Nach MORPH_CLOSE - Weiße Pixel: {np.sum(mask_array > 127)}")
330
-
331
- # Weiche Ränder für bessere Integration der Person
332
- print("🌈 Erstelle weiche Übergänge...")
333
- mask_array = cv2.GaussianBlur(mask_array, (9, 9), 2.0) #2.0 bestimmt wie stark die Unschärfe ist
334
- print(" ✅ Gaussian Blur für weiche Übergänge")
335
-
336
- # DEBUG nach Gaussian Blur
337
- print(f" Nach Gaussian Blur - Min/Max: {mask_array.min()}/{mask_array.max()}")
338
- print(f" Nach Gaussian Blur - dtype: {mask_array.dtype}")
339
-
340
- # Gamma-Korrektur für präzisere Ränder
341
- print("🎛️ Wende Gamma-Korrektur an...")
342
- mask_array = mask_array.astype(np.float32) / 255.0
343
- print(f" Konvertiert zu Float32: Min={mask_array.min():.3f}, Max={mask_array.max():.3f}")
344
-
345
- mask_array = np.clip(mask_array, 0.0, 1.0) #begrenzt alle Werte auf 0 und 1
346
- mask_array = mask_array ** 0.85 # Gamma-Korrektur Werte > 0.5 werden abgedunkelt, <0.5 aufgehellt-erzeugt natürliche Maskenübergänge
347
- print(f" Nach Gamma 0.85: Min={mask_array.min():.3f}, Max={mask_array.max():.3f}")
348
-
349
- mask_array = (mask_array * 255).astype(np.uint8)
350
- print(" ✅ Gamma-Korrektur (0.85) gegen milchige Ränder")
351
-
352
- # FINALE QUALITÄTSKONTROLLE
353
- print("-" * 60)
354
- print("📊 FINALE MASKEN-STATISTIK (ENVIRONMENT_CHANGE)")
355
-
356
- white_pixels = np.sum(mask_array > 127)
357
- black_pixels = np.sum(mask_array <= 127)
358
- total_pixels = mask_array.size
359
-
360
- white_ratio = white_pixels / total_pixels * 100
361
- black_ratio = black_pixels / total_pixels * 100
362
 
363
- print(f" Weiße Pixel (HINTERGRUND - Veränderung): {white_pixels:,} ({white_ratio:.1f}%)")
364
- print(f" Schwarze Pixel (PERSON - Erhaltung): {black_pixels:,} ({black_ratio:.1f}%)")
365
- print(f" Gesamtpixel: {total_pixels:,}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
366
 
367
- # Warnungen basierend auf Verhältnis
368
- if white_ratio < 30:
369
- print(f" ⚠️ WARNUNG: Sehr wenig Hintergrund ({white_ratio:.1f}%)")
370
- print(f" ℹ️ Das könnte bedeuten, dass die Person zu groß segmentiert wurde")
371
- elif white_ratio > 90:
372
- print(f" ⚠️ WARNUNG: Sehr viel Hintergrund ({white_ratio:.1f}%)")
373
- print(f" ℹ️ Das könnte bedeuten, dass die Person zu klein segmentiert wurde")
374
- elif 50 <= white_ratio <= 80:
375
- print(f" ✅ OPTIMALES Verhältnis ({white_ratio:.1f}%)")
376
- else:
377
- print(f" ℹ️ Normales Verhältnis ({white_ratio:.1f}%)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
 
379
  # Zurück zu PIL Image
380
- mask = Image.fromarray(mask_array).convert("L")
381
  raw_mask = Image.fromarray(raw_mask_array).convert("L")
382
 
383
  print("#" * 80)
@@ -386,7 +390,7 @@ class ControlNetProcessor:
386
  print(f"🎛️ Verwendeter Modus: {mode}")
387
  print("#" * 80)
388
 
389
- return mask, raw_mask # in mask steht die invertierte nachbearbeitete Maske, in raw_mask die Rohmaske. In app.py wird mask immer auf 512 skaliert.
390
 
391
  # ============================================================
392
  # BLOCK 2: FOCUS_CHANGE
 
293
  cv2.rectangle(mask_array, (fb_x1, fb_y1), (fb_x2, fb_y2), 0, -1)
294
 
295
  # Damit wird die Rohmaske für die UI-Anzeige gespeichert
296
+ raw_mask_array = mask_array.copy()
297
 
298
+ ##########################################################
299
+ # POSTPROCESSING
300
+ ##########################################################
301
  print("🌳 ENVIRONMENT-CHANGE POSTPROCESSING")
302
 
303
  # Konvertierung zu PIL, hochskalieren auf Originalgröße (korrekte Überlagerung mit O-Bild),
304
  # Konvertierung NumPy für weitere Verarbeitung da mathematisch korrekter als PIL.
305
+ if image.size != original_image.size: #Vergleich SAM-Maskengröße und Original-Bildgröße
306
  print(f" ⚠️ Bildgröße angepasst: {image.size} → {original_image.size}")
307
+ temp_mask = Image.fromarray(mask_array).convert("L") #wandelt NumPy-Array in PIL-Bild
308
+ temp_mask = temp_mask.resize(original_image.size, Image.Resampling.NEAREST) #skaliert auf Originalgröße
309
+ mask_array = np.array(temp_mask) #np. heißt mache aus PIL-Image wieder numPy-Array
310
  print(f" ✅ Maske auf Originalgröße skaliert: {mask_array.shape}")
311
+
312
+
313
+ # DILATE auf der weißen Person - daduch wird Person etwas vergrößert
314
+ kernel_dilate = np.ones((5, 5), np.uint8)
315
+ working_mask = cv2.dilate(working_mask, kernel_dilate, iterations=1)
316
+ print(f" ✅ Dilate (5x5) - Person leicht erweitert")
317
+
318
+
319
+ # MORPH_CLOSE auf dem schwarzen Hintergrund (feine Löcher)- kleiner Kernel filigrane Heranarbeitung an Person,
320
+ # es werden aber nur kleine Löcher in Umgebung von weiß nach schwarz geändert!
321
+ kernel_close_small = np.ones((3, 3), np.uint8)
322
+ working_mask = cv2.morphologyEx(working_mask, cv2.MORPH_CLOSE, kernel_close_small, iterations=1)
323
+ print(f" MORPH_CLOSE (3x3) - Feine Löcher im Hintergrund geschlossen")
324
+
325
+
326
+ # KONTURENFILTER auf der weißen Person - arbeitet filigraner als MORPH-CLOSE
327
+ # Finde Konturen (nur äußere)
328
+ contours, _ = cv2.findContours(working_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
 
330
+ if len(contours) > 0:
331
+ # Finde die größte Kontur (sollte die Person sein)
332
+ largest_contour = max(contours, key=cv2.contourArea)
333
+
334
+ # Erstelle eine saubere Maske mit nur der größten Kontur
335
+ clean_mask = np.zeros_like(working_mask)
336
+ cv2.drawContours(clean_mask, [largest_contour], -1, 255, -1)
337
+
338
+ # Optional: Kleine weiße Punkte IN der Person entfernen
339
+ # Dazu invertieren wir temporär, um "Löcher" (schwarze Pixel) in der Person zu finden
340
+ temp_inverted = 255 - clean_mask
341
+ hole_contours, _ = cv2.findContours(temp_inverted, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
342
+
343
+ for hole in hole_contours:
344
+ area = cv2.contourArea(hole)
345
+ if area < 100: # Sehr kleine Löcher füllen
346
+ cv2.drawContours(clean_mask, [hole], -1, 255, -1)
347
+
348
+ working_mask = clean_mask
349
+ print(f" ✅ Konturenfilter - Größte Kontur behalten, {len(contours)-1} kleine entfernt")
350
+
351
+
352
 
353
+ # Gaussian-BLUR für weiche Kanten
354
+ working_mask = cv2.GaussianBlur(working_mask, (5, 5), 1.2)
355
+ print(f" Gaussian Blur (5x5, sigma=1.2) für weiche Kanten")
356
+
357
+
358
+
359
+ # GAMMA-Korrektur für präzisere Ränder
360
+ working_mask_float = working_mask.astype(np.float32) / 255.0
361
+ working_mask_float = np.clip(working_mask_float, 0.0, 1.0)
362
+ working_mask_float = working_mask_float ** 0.85 # Gamma 0.85
363
+ working_mask = (working_mask_float * 255).astype(np.uint8)
364
+ print(f" ✅ Gamma-Korrektur (0.85) gegen milchige Ränder")
365
+
366
+
367
+
368
+ # Für environment_change: JETZT invertieren
369
+ final_mask = 255 - working_mask
370
+ print(f" ✅ Finale Invertierung für environment_change")
371
+
372
+
373
+ # Qualitätskontrolle - Debug
374
+ white_pixels = np.sum(final_mask > 127)
375
+ black_pixels = np.sum(final_mask <= 127)
376
+ total_pixels = final_mask.size
377
+
378
+ print(f" 📊 FINALE MASKE:")
379
+ print(f" • Weiße Pixel (Hintergrund): {white_pixels:,} ({white_pixels/total_pixels*100:.1f}%)")
380
+ print(f" • Schwarze Pixel (Person): {black_pixels:,} ({black_pixels/total_pixels*100:.1f}%)")
381
+
382
 
383
  # Zurück zu PIL Image
384
+ mask = Image.fromarray(final_mask).convert("L")
385
  raw_mask = Image.fromarray(raw_mask_array).convert("L")
386
 
387
  print("#" * 80)
 
390
  print(f"🎛️ Verwendeter Modus: {mode}")
391
  print("#" * 80)
392
 
393
+ return mask, raw_mask # in mask steht die invertierte nachbearbeitete Maske, in raw_mask die Rohmaske. In app.py wird mask immer auf 512 skaliert
394
 
395
  # ============================================================
396
  # BLOCK 2: FOCUS_CHANGE