Astridkraft commited on
Commit
27f27a1
·
verified ·
1 Parent(s): c30ac03

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +192 -0
app.py CHANGED
@@ -245,6 +245,198 @@ def scale_image_and_mask_together(image, mask, target_size=512, bbox_coords=None
245
 
246
 
247
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  # Composition Workflow nach Ausgabe ControlnetInpaint-Pipeline
249
  def enhanced_composite_with_sam(original_image, inpaint_result, original_mask,
250
  padding_info, bbox_coords, mode):
 
245
 
246
 
247
 
248
+ def enhanced_composite_with_sam(original_image, inpaint_result, original_mask,
249
+ padding_info, bbox_coords, mode):
250
+ """
251
+ COMPOSITING MIT SAM-MASKEN (MASKE-BASIERT)
252
+ Berücksichtigt die präzisen/erweiterten Kanten der SAM-Maske
253
+ """
254
+ print(f"🎨 Verbessertes Compositing für Modus: {mode}")
255
+
256
+ # Extrahiere Padding-Info
257
+ x_offset = padding_info['x_offset']
258
+ y_offset = padding_info['y_offset']
259
+ scaled_width = padding_info['scaled_width']
260
+ scaled_height = padding_info['scaled_height']
261
+ scale_factor = padding_info['scale_factor']
262
+ original_width = padding_info['original_width']
263
+ original_height = padding_info['original_height']
264
+
265
+ # ==============================================
266
+ # FALL 1: Bild war bereits 512×512 (keine Skalierung)
267
+ # ==============================================
268
+ if scale_factor == 1.0 and x_offset == 0 and y_offset == 0:
269
+ print(f"✅ FALL 1: Bild 512×512 - einfaches Compositing")
270
+
271
+ if mode == "environment_change":
272
+ # Umgebung ändern: SAM-Maske invertieren (Objekt schützen)
273
+ mask_inverted = Image.eval(original_mask, lambda x: 255 - x)
274
+ soft_mask = mask_inverted.filter(ImageFilter.GaussianBlur(5))
275
+
276
+ original_with_alpha = original_image.copy().convert("RGBA")
277
+ original_with_alpha.putalpha(soft_mask)
278
+
279
+ final_image = inpaint_result.copy().convert("RGBA")
280
+ final_image.paste(original_with_alpha, (0, 0), original_with_alpha)
281
+ return final_image.convert("RGB")
282
+
283
+ else:
284
+ # Focus/Face: Direktes Alpha-Compositing
285
+ soft_mask = original_mask.filter(ImageFilter.GaussianBlur(5))
286
+
287
+ inpaint_rgba = inpaint_result.convert("RGBA")
288
+ mask_alpha = soft_mask.convert("L")
289
+ inpaint_rgba.putalpha(mask_alpha)
290
+
291
+ original_rgba = original_image.convert("RGBA")
292
+
293
+ # Composite
294
+ final_image = Image.new("RGBA", original_image.size, (0, 0, 0, 0))
295
+ final_image.paste(original_rgba, (0, 0))
296
+ final_image.paste(inpaint_rgba, (0, 0), inpaint_rgba)
297
+ return final_image.convert("RGB")
298
+
299
+ # ==============================================
300
+ # FALL 2 & 3: Bild wurde skaliert - MASKE-BASIERTES COMPOSITING
301
+ # ==============================================
302
+ print(f"🔄 FALL 2/3: Bild skaliert - MASKE-BASIERTES COMPOSITING")
303
+
304
+ # 1. PADDING ENTFERNEN von 512×512 Ergebnis
305
+ downscaled_result = inpaint_result.crop(
306
+ (x_offset, y_offset, x_offset + scaled_width, y_offset + scaled_height)
307
+ )
308
+
309
+ # 2. AUF ORIGINALGRÖßE SKALIEREN (Bearbeitetes Bild)
310
+ new_background = downscaled_result.resize(
311
+ (original_width, original_height),
312
+ Image.Resampling.LANCZOS
313
+ )
314
+
315
+ # 3. SAM-MASKE FÜR KOMPOSITING VORBEREITEN
316
+ print(f"📐 SAM-Maske Größe: {original_mask.size}")
317
+
318
+ if mode == "environment_change":
319
+ # ==============================================
320
+ # MODUS: UMWELT ÄNDERN (Objekt bleibt original)
321
+ # ==============================================
322
+ print("🌳 Modus: Umwelt ändern mit SAM-Maske")
323
+
324
+ # Invertierte Maske für Objekterhalt
325
+ mask_inverted = Image.eval(original_mask, lambda x: 255 - x)
326
+
327
+ # Weiche Kanten für natürlichen Übergang
328
+ soft_mask = mask_inverted.filter(ImageFilter.GaussianBlur(5))
329
+
330
+ # Originalbild mit Alpha-Kanal
331
+ original_with_alpha = original_image.copy().convert("RGBA")
332
+ original_with_alpha.putalpha(soft_mask)
333
+
334
+ # Compositing
335
+ final_image = new_background.copy().convert("RGBA")
336
+ final_image.paste(original_with_alpha, (0, 0), original_with_alpha)
337
+
338
+ print(f"✅ Umwelt-Compositing abgeschlossen")
339
+
340
+ else:
341
+ # ==============================================
342
+ # MODUS: FOCUS oder GESICHT ÄNDERN (MASKE-BASIERT)
343
+ # ==============================================
344
+ mode_name = "Focus" if mode == "focus_change" else "Gesicht"
345
+ print(f"👤 Modus: {mode_name} ändern - MASKE-BASIERT")
346
+
347
+ # WICHTIG: MASKE-BASIERTES AUSSCHNEIDEN
348
+ # 3a. SAM-Maske auf 512px skalieren
349
+ mask_on_512 = original_mask.resize((512, 512), Image.Resampling.LANCZOS)
350
+
351
+ # 3b. Bounding Box der Maske auf 512px finden
352
+ mask_array = np.array(mask_on_512)
353
+ white_pixels = np.where(mask_array > 128)
354
+
355
+ if len(white_pixels[0]) == 0:
356
+ print("⚠️ Keine weißen Pixel in Maske → Fallback auf BBox")
357
+ if bbox_coords and all(c is not None for c in bbox_coords):
358
+ # Fallback: User-BBox verwenden
359
+ mask_bbox_512 = (
360
+ int(bbox_coords[0] * scale_factor) + x_offset,
361
+ int(bbox_coords[1] * scale_factor) + y_offset,
362
+ int(bbox_coords[2] * scale_factor) + x_offset,
363
+ int(bbox_coords[3] * scale_factor) + y_offset
364
+ )
365
+ else:
366
+ # Keine BBox → gesamtes Bild
367
+ final_image = new_background
368
+ return final_image.convert("RGB")
369
+ else:
370
+ # MASKE-BASIERTE BBOX berechnen
371
+ y_min, x_min = white_pixels[0].min(), white_pixels[1].min()
372
+ y_max, x_max = white_pixels[0].max(), white_pixels[1].max()
373
+
374
+ # Puffer für bessere Ergebnisse
375
+ buffer = 15
376
+ x_min = max(0, x_min - buffer)
377
+ y_min = max(0, y_min - buffer)
378
+ x_max = min(512, x_max + buffer)
379
+ y_max = min(512, y_max + buffer)
380
+
381
+ mask_bbox_512 = (x_min, y_min, x_max, y_max)
382
+
383
+ print(f" 🎯 Maske-basierte BBox auf 512px: {mask_bbox_512}")
384
+ print(f" 📏 Größe: {x_max-x_min}×{y_max-y_min} Pixel")
385
+
386
+ # 3c. Bearbeiteten Bereich aus 512×512 ausschneiden (MASKE-BASIERT)
387
+ edited_region_512 = inpaint_result.crop(mask_bbox_512)
388
+
389
+ # 3d. Auf Original-Maskengröße skalieren
390
+ mask_width = mask_bbox_512[2] - mask_bbox_512[0]
391
+ mask_height = mask_bbox_512[3] - mask_bbox_512[1]
392
+
393
+ # Maske auf Ausschnitt-Größe zuschneiden
394
+ mask_cropped = mask_on_512.crop(mask_bbox_512)
395
+
396
+ # Auf Originalgröße skalieren (mit Maske als Alpha)
397
+ mask_original_cropped = mask_cropped.resize(
398
+ (original_width, original_height),
399
+ Image.Resampling.LANCZOS
400
+ )
401
+
402
+ edited_region_fullsize = edited_region_512.resize(
403
+ (original_width, original_height),
404
+ Image.Resampling.LANCZOS
405
+ )
406
+
407
+ # 3e. Weiche Kanten für natürliche Übergänge
408
+ soft_mask = mask_original_cropped.filter(ImageFilter.GaussianBlur(5))
409
+
410
+ # 3f. Alpha-Compositing
411
+ edited_rgba = edited_region_fullsize.convert("RGBA")
412
+ edited_rgba.putalpha(soft_mask)
413
+
414
+ # 3g. MASKE-BASIERTE POSITION bestimmen
415
+ # BBox der Maske im Originalbild finden
416
+ mask_original_array = np.array(original_mask)
417
+ white_original = np.where(mask_original_array > 128)
418
+
419
+ if len(white_original[0]) > 0:
420
+ paste_x = white_original[1].min()
421
+ paste_y = white_original[0].min()
422
+ print(f" 📍 Einfüge-Position (maske-basiert): ({paste_x}, {paste_y})")
423
+ else:
424
+ # Fallback: Zentriert
425
+ paste_x = (original_width - edited_rgba.width) // 2
426
+ paste_y = (original_height - edited_rgba.height) // 2
427
+ print(f" 📍 Einfüge-Position (zentriert): ({paste_x}, {paste_y})")
428
+
429
+ # 3h. Finales Compositing
430
+ final_image = original_image.copy().convert("RGBA")
431
+ final_image.paste(edited_rgba, (paste_x, paste_y), edited_rgba)
432
+
433
+ print(f" ✅ {mode_name}-Compositing maskenbasiert abgeschlossen")
434
+
435
+ print(f"✅ Korrektes Compositing abgeschlossen. Finale Größe: {final_image.size}")
436
+
437
+ return final_image.convert("RGB")
438
+
439
+
440
  # Composition Workflow nach Ausgabe ControlnetInpaint-Pipeline
441
  def enhanced_composite_with_sam(original_image, inpaint_result, original_mask,
442
  padding_info, bbox_coords, mode):