Astridkraft commited on
Commit
dafad2c
·
verified ·
1 Parent(s): ca76d8b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -90
app.py CHANGED
@@ -236,14 +236,16 @@ def scale_image_and_mask_together(image, mask, target_size=512):
236
  return padded_image, padded_mask, padding_info
237
 
238
 
 
 
239
  # Composition Workflow nach Ausgabe ControlnetInpaint-Pipeline
240
- def composite_edited_region(original_image, inpaint_result, original_mask, padding_info, bbox_coords=None, mode="environment_change"):
 
241
  """
242
- OPTIMIERTER COMPOSITING-WORKFLOW für alle Bildgrößen
 
243
  """
244
- print(f"🎨 Starte Compositing für Modus: {mode}")
245
- print(f"📏 Originalgröße: {original_image.size}")
246
- print(f"📏 Inpaint-Result-Größe: {inpaint_result.size}")
247
 
248
  # Extrahiere Padding-Info
249
  x_offset = padding_info['x_offset']
@@ -254,94 +256,69 @@ def composite_edited_region(original_image, inpaint_result, original_mask, paddi
254
  original_width = padding_info['original_width']
255
  original_height = padding_info['original_height']
256
 
257
- print(f"📊 Skalierungsfaktor: {scale_factor:.4f}")
258
- print(f"📊 Offsets: x={x_offset}, y={y_offset}")
259
- print(f"📊 Skalierte Größe: {scaled_width}x{scaled_height}")
260
-
261
- if bbox_coords:
262
- print(f"🎯 BBox Original: {bbox_coords}")
263
-
264
  # ==============================================
265
- # FALL 1: Bild war bereits 512×512 (keine Skalierung, kein Padding)
266
- # ControlNet-Inpaint hat bereits komplettes Bild bearbeitet
267
  # ==============================================
268
  if scale_factor == 1.0 and x_offset == 0 and y_offset == 0:
269
- print(f"✅ FALL 1: Bild 512×512 - direktes ControlNet-Inpaint Result")
270
- print(f" Kein Compositing nötig für {mode}")
271
  return inpaint_result
272
 
273
  # ==============================================
274
- # FALL 2 & 3: Bild wurde skaliert (größer/kleiner als 512×512)
275
  # ==============================================
276
- print(f"🔄 FALL 2/3: Bild skaliert - Compositing Workflow")
277
 
278
  # 1. PADDING ENTFERNEN von 512×512 Ergebnis
279
  downscaled_result = inpaint_result.crop(
280
  (x_offset, y_offset, x_offset + scaled_width, y_offset + scaled_height)
281
  )
282
- print(f"✅ Padding entfernt: {inpaint_result.size} → {downscaled_result.size}")
283
 
284
- # 2. MODUS-SPEZIFISCHE LOGIK
285
- original_size = (original_width, original_height)
286
 
287
  if mode == "environment_change":
288
  # ==============================================
289
- # MODUS: UMWELT ÄNDERN (Focus bleibt original)
290
  # ==============================================
291
- print("🌳 Modus: Umwelt ändern")
292
 
293
  # Gesamtes bearbeitetes Bild hochskalieren
294
- final_image = downscaled_result.resize(original_size, Image.Resampling.LANCZOS)
 
 
 
295
 
296
- # Original-Focus zurück einfügen
297
- if bbox_coords and all(c is not None for c in bbox_coords):
298
- x1, y1, x2, y2 = bbox_coords
299
-
300
- # Skalierte BBox berechnen
301
- bbox_scaled = (
302
- int(x1 * scale_factor),
303
- int(y1 * scale_factor),
304
- int(x2 * scale_factor),
305
- int(y2 * scale_factor)
306
- )
307
-
308
- # Original-Focus ausschneiden (von original_downscaled)
309
- original_downscaled = original_image.resize(
310
- (scaled_width, scaled_height),
311
- Image.Resampling.LANCZOS
312
- )
313
- original_focus = original_downscaled.crop(bbox_scaled)
314
-
315
- # Focus auf Originalgröße skalieren
316
- focus_original_size = (x2 - x1, y2 - y1)
317
- original_focus_fullsize = original_focus.resize(
318
- focus_original_size,
319
- Image.Resampling.LANCZOS
320
- )
321
-
322
- # In finales Bild einfügen
323
- final_image.paste(original_focus_fullsize, (x1, y1))
324
- print(f"✅ Original-Focus eingefügt: {bbox_scaled} → {x1},{y1}")
325
 
326
- print(f"✅ Finales Bild: {final_image.size}")
327
- return final_image.convert("RGB")
328
-
329
  else:
330
  # ==============================================
331
  # MODUS: FOCUS oder GESICHT ÄNDERN
332
  # ==============================================
333
  mode_name = "Focus" if mode == "focus_change" else "Gesicht"
334
- print(f"👤 Modus: {mode_name} ändern")
335
 
336
  if not bbox_coords or not all(c is not None for c in bbox_coords):
337
  # Keine BBox: gesamtes Bild zurückgeben
338
- final_image = downscaled_result.resize(original_size, Image.Resampling.LANCZOS)
339
- print(f"⚠️ Keine BBox - gesamtes Bild skaliert")
 
 
340
  return final_image.convert("RGB")
341
 
 
342
  x1, y1, x2, y2 = bbox_coords
343
-
344
- # Skalierte BBox für downscaled_result
345
  bbox_scaled = (
346
  int(x1 * scale_factor),
347
  int(y1 * scale_factor),
@@ -349,38 +326,59 @@ def composite_edited_region(original_image, inpaint_result, original_mask, paddi
349
  int(y2 * scale_factor)
350
  )
351
 
352
- # Bearbeiteten Bereich ausschneiden
353
- edited_region = downscaled_result.crop(bbox_scaled)
354
- print(f"✅ Bearbeiteter Bereich: {bbox_scaled} → {edited_region.size}")
355
-
356
- # Auf ORIGINAL-BBox-Größe skalieren (nicht Gesamtbild!)
357
- original_bbox_size = (x2 - x1, y2 - y1)
358
- edited_region_fullsize = edited_region.resize(
359
- original_bbox_size,
360
- Image.Resampling.LANCZOS
361
  )
362
- print(f"✅ Auf BBox-Größe skaliert: {edited_region.size} → {edited_region_fullsize.size}")
363
-
364
- # 3. COMPOSITING mit weicher Maske
365
- from PIL import ImageFilter
366
 
367
- # Maske zuschneiden und weichzeichnen
368
- mask_cropped = original_mask.crop((x1, y1, x2, y2))
369
- soft_mask = mask_cropped.filter(ImageFilter.GaussianBlur(3))
370
-
371
- # Alpha-Compositing
372
- final_image = original_image.copy()
373
- edited_rgba = edited_region_fullsize.convert("RGBA")
374
- mask_rgba = soft_mask.convert("L")
375
-
376
- temp_image = Image.new("RGBA", original_bbox_size, (0, 0, 0, 0))
377
- temp_image.paste(edited_rgba, (0, 0), mask_rgba)
378
-
379
- final_image.paste(temp_image, (x1, y1), temp_image)
380
-
381
- print(f"✅ Compositing abgeschlossen. Finale Größe: {final_image.size}")
382
- return final_image.convert("RGB")
 
 
 
 
 
 
383
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
 
385
  def auto_detect_face_area(image):
386
  """Optimierten Vorschlag für Gesichtsbereich ohne externe Bibliotheken"""
 
236
  return padded_image, padded_mask, padding_info
237
 
238
 
239
+
240
+
241
  # Composition Workflow nach Ausgabe ControlnetInpaint-Pipeline
242
+ def enhanced_composite_with_sam(original_image, inpaint_result, original_mask,
243
+ padding_info, bbox_coords, mode):
244
  """
245
+ VERBESSERTES COMPOSITING MIT SAM-MASKEN
246
+ Berücksichtigt die präzisen Kanten der SAM-Maske
247
  """
248
+ print(f"🎨 Verbessertes Compositing für Modus: {mode}")
 
 
249
 
250
  # Extrahiere Padding-Info
251
  x_offset = padding_info['x_offset']
 
256
  original_width = padding_info['original_width']
257
  original_height = padding_info['original_height']
258
 
 
 
 
 
 
 
 
259
  # ==============================================
260
+ # FALL 1: Bild war bereits 512×512 (keine Skalierung)
 
261
  # ==============================================
262
  if scale_factor == 1.0 and x_offset == 0 and y_offset == 0:
263
+ print(f"✅ FALL 1: Bild 512×512 - kein Compositing nötig")
 
264
  return inpaint_result
265
 
266
  # ==============================================
267
+ # FALL 2 & 3: Bild wurde skaliert
268
  # ==============================================
269
+ print(f"🔄 FALL 2/3: Bild skaliert - Compositing mit SAM-Maske")
270
 
271
  # 1. PADDING ENTFERNEN von 512×512 Ergebnis
272
  downscaled_result = inpaint_result.crop(
273
  (x_offset, y_offset, x_offset + scaled_width, y_offset + scaled_height)
274
  )
 
275
 
276
+ # 2. AUF ORIGINALGRÖßE SKALIEREN
277
+ final_image = original_image.copy()
278
 
279
  if mode == "environment_change":
280
  # ==============================================
281
+ # MODUS: UMWELT ÄNDERN (Objekt bleibt original)
282
  # ==============================================
283
+ print("🌳 Modus: Umwelt ändern mit SAM-Maske")
284
 
285
  # Gesamtes bearbeitetes Bild hochskalieren
286
+ new_background = downscaled_result.resize(
287
+ (original_width, original_height),
288
+ Image.Resampling.LANCZOS
289
+ )
290
 
291
+ # Originalbild mit SAM-Maske einfügen
292
+ original_with_alpha = original_image.copy().convert("RGBA")
293
+
294
+ # Invertierte Maske für Objekterhalt
295
+ mask_inverted = Image.eval(original_mask, lambda x: 255 - x)
296
+
297
+ # Weiche Kanten für natürlichen Übergang
298
+ soft_mask = mask_inverted.filter(ImageFilter.GaussianBlur(3))
299
+ original_with_alpha.putalpha(soft_mask)
300
+
301
+ # Compositing
302
+ final_image = new_background.copy().convert("RGBA")
303
+ final_image.paste(original_with_alpha, (0, 0), original_with_alpha)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
 
 
 
 
305
  else:
306
  # ==============================================
307
  # MODUS: FOCUS oder GESICHT ÄNDERN
308
  # ==============================================
309
  mode_name = "Focus" if mode == "focus_change" else "Gesicht"
310
+ print(f"👤 Modus: {mode_name} ändern mit SAM-Maske")
311
 
312
  if not bbox_coords or not all(c is not None for c in bbox_coords):
313
  # Keine BBox: gesamtes Bild zurückgeben
314
+ final_image = downscaled_result.resize(
315
+ (original_width, original_height),
316
+ Image.Resampling.LANCZOS
317
+ )
318
  return final_image.convert("RGB")
319
 
320
+ # Bearbeiteten Bereich ausschneiden und hochskalieren
321
  x1, y1, x2, y2 = bbox_coords
 
 
322
  bbox_scaled = (
323
  int(x1 * scale_factor),
324
  int(y1 * scale_factor),
 
326
  int(y2 * scale_factor)
327
  )
328
 
329
+ # Sicherstellen, dass BBox gültig ist
330
+ bbox_scaled = (
331
+ max(0, bbox_scaled[0]),
332
+ max(0, bbox_scaled[1]),
333
+ min(scaled_width, bbox_scaled[2]),
334
+ min(scaled_height, bbox_scaled[3])
 
 
 
335
  )
 
 
 
 
336
 
337
+ if bbox_scaled[2] > bbox_scaled[0] and bbox_scaled[3] > bbox_scaled[1]:
338
+ edited_region = downscaled_result.crop(bbox_scaled)
339
+
340
+ # Auf ORIGINAL-BBox-Größe skalieren
341
+ original_bbox_size = (x2 - x1, y2 - y1)
342
+ edited_region_fullsize = edited_region.resize(
343
+ original_bbox_size,
344
+ Image.Resampling.LANCZOS
345
+ )
346
+
347
+ # SAM-Maske für den Bereich zuschneiden und weichzeichnen
348
+ mask_cropped = original_mask.crop((x1, y1, x2, y2))
349
+ soft_mask = mask_cropped.filter(ImageFilter.GaussianBlur(3))
350
+
351
+ # Alpha-Compositing mit präziser SAM-Maske
352
+ edited_rgba = edited_region_fullsize.convert("RGBA")
353
+ mask_rgba = soft_mask.convert("L")
354
+
355
+ temp_image = Image.new("RGBA", original_bbox_size, (0, 0, 0, 0))
356
+ temp_image.paste(edited_rgba, (0, 0), mask_rgba)
357
+
358
+ final_image.paste(temp_image, (x1, y1), temp_image)
359
 
360
+ print(f"✅ Verbessertes Compositing abgeschlossen. Finale Größe: {final_image.size}")
361
+ return final_image.convert("RGB")
362
+
363
+
364
+ # Und in der img_to_image() Funktion ersetzen Sie das Compositing:
365
+ # Statt:
366
+ # final_image = composite_edited_region(...)
367
+
368
+ # Verwenden Sie:
369
+ if original_mask is not None and padding_info is not None:
370
+ # Verbessertes Compositing mit SAM-Masken
371
+ final_image = enhanced_composite_with_sam(
372
+ original_image=image.convert("RGB"),
373
+ inpaint_result=generated_image,
374
+ original_mask=original_mask,
375
+ padding_info=padding_info,
376
+ bbox_coords=(bbox_x1, bbox_y1, bbox_x2, bbox_y2),
377
+ mode=mode
378
+ )
379
+
380
+
381
+
382
 
383
  def auto_detect_face_area(image):
384
  """Optimierten Vorschlag für Gesichtsbereich ohne externe Bibliotheken"""