Astridkraft commited on
Commit
2259119
·
verified ·
1 Parent(s): 6587cd4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +113 -31
app.py CHANGED
@@ -231,72 +231,152 @@ def scale_image_and_mask_together(image, mask, target_size=512):
231
 
232
  return padded_image, padded_mask, padding_info
233
 
234
- # === KORREKTE COMPOSITING-FUNKTION ===
235
- def composite_edited_region(original_image, inpaint_result, original_mask, padding_info):
 
236
  """
237
- KORREKTER COMPOSITING-WORKFLOW:
238
- - Schneidet den bearbeiteten Bereich aus dem Inpaint-Ergebnis
239
- - Fügt ihn nahtlos in das Originalbild ein
 
240
 
241
  Parameter:
242
  - original_image: Originalbild in Originalgröße
243
- - inpaint_result: 512x512 Inpaint-Ergebnis
244
  - original_mask: Originalmaske (vor Skalierung)
245
- - padding_info: Skalierungsinformationen von scale_image_and_mask_together()
 
 
246
 
247
  Returns:
248
- - composited_image: Finales Bild mit bearbeiteter Region
249
  """
250
- print(f"🎨 Starte korrektes Compositing...")
251
 
252
- # 1. Extrahiere den bearbeiteten Bereich (die Veränderung) aus dem Inpaint-Ergebnis (ohne Padding)
253
  x_offset = padding_info['x_offset']
254
  y_offset = padding_info['y_offset']
255
  scaled_width = padding_info['scaled_width']
256
  scaled_height = padding_info['scaled_height']
257
 
258
- # Bereich im 512x512 Inpaint-Ergebnis, der dem originalen Bild entspricht
259
- unpainted_region = inpaint_result.crop(
260
  (x_offset, y_offset, x_offset + scaled_width, y_offset + scaled_height)
261
  )
 
262
 
263
- print(f" Bearbeiteter Bereich extrahiert: {unpainted_region.size}")
 
 
 
 
264
 
265
- # 2. Skaliere den bearbeiteten Bereich zurück auf Originalgröße .resize() ist eine Python Funktion, aus der Pillow-Bibliothek die das skaliert.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  original_size = (padding_info['original_width'], padding_info['original_height'])
267
- edited_region_fullsize = unpainted_region.resize(original_size, Image.Resampling.LANCZOS)
268
 
269
- print(f" Auf Originalgröße skaliert: {edited_region_fullsize.size}")
 
 
 
 
 
 
 
 
 
270
 
271
- # 3. Erstelle eine weiche Maske für nahtloses Einfügen
272
- # Erweitere die Originalmaske leicht für weiche Übergänge
273
- # Dieser gesamte Codeblock erzeugt weiche Übergänge, damit der bearbeitete Bereich nicht wie eine harte, ausgeschnittene "Collage" im Originalbild aussieht. Die Kombination aus MaxFilter (erweitert die Maske) und GaussianBlur (verwischt die Kante) erzeugt eine weiche Alpha-Maske für sanftes Alpha Blending.
274
- soft_mask = original_mask.copy()
 
 
 
275
 
276
- # Für weiche Kanten: Erweitere die Maske um 5 Pixel
 
277
  from PIL import ImageFilter
278
- soft_mask = soft_mask.filter(ImageFilter.MaxFilter(5))
279
- soft_mask = soft_mask.filter(ImageFilter.GaussianBlur(3))
280
 
281
- # 4. Compositing: Kombiniere Originalbild und bearbeiteten Bereich
282
- final_image = original_image.copy()
 
283
 
284
- # Konvertiere für alpha blending
 
285
  edited_rgba = edited_region_fullsize.convert("RGBA")
286
  soft_mask_rgba = soft_mask.convert("L")
287
 
288
- # Erstelle ein temporäres Bild mit Alpha-Kanal
289
  temp_image = Image.new("RGBA", original_size, (0, 0, 0, 0))
290
  temp_image.paste(edited_rgba, (0, 0), soft_mask_rgba)
291
 
292
- # Kombiniere mit Original
293
  final_image = Image.alpha_composite(final_image.convert("RGBA"), temp_image)
294
  final_image = final_image.convert("RGB")
295
 
296
  print(f"✅ Compositing abgeschlossen. Finale Größe: {final_image.size}")
297
-
298
  return final_image
299
 
 
300
  def auto_detect_face_area(image):
301
  """Optimierten Vorschlag für Gesichtsbereich ohne externe Bibliotheken"""
302
  width, height = image.size
@@ -1045,8 +1125,10 @@ def img_to_image(image, prompt, neg_prompt, strength, steps, guidance_scale,
1045
  original_image=image.convert("RGB"),
1046
  inpaint_result=generated_image,
1047
  original_mask=original_mask,
1048
- padding_info=padding_info
1049
- )
 
 
1050
  print(f"✅ Korrektes Compositing durchgeführt")
1051
  else:
1052
  # Keine Maske: Einfach das generierte Bild zurückgeben
 
231
 
232
  return padded_image, padded_mask, padding_info
233
 
234
+
235
+ # Composition Workflow nach Ausgabe ControlnetInpaint-Pipeline
236
+ def composite_edited_region(original_image, inpaint_result, original_mask, padding_info, bbox_coords=None, mode="environment_change"):
237
  """
238
+ KOMPLETT KORRIGIERTER COMPOSITING-WORKFLOW für alle 3 Modi:
239
+
240
+ 1. 'environment_change': Original-Focus in bearbeitetes Bild integrieren
241
+ 2. 'focus_change'/'face_only_change': Bearbeiteten Bereich in Originalbild integrieren
242
 
243
  Parameter:
244
  - original_image: Originalbild in Originalgröße
245
+ - inpaint_result: 512x512 Inpaint-Ergebnis MIT PADDING
246
  - original_mask: Originalmaske (vor Skalierung)
247
+ - padding_info: Skalierungsinformationen
248
+ - bbox_coords: [x1, y1, x2, y2] oder None
249
+ - mode: "environment_change", "focus_change", "face_only_change"
250
 
251
  Returns:
252
+ - composited_image: Finales Bild mit korrekt integrierter Region
253
  """
254
+ print(f"🎨 Starte Compositing für Modus: {mode}")
255
 
256
+ # 1. PADDING ENTFERNEN (512x512 herunterskaliertes Bild)
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
 
262
+ downscaled_result = inpaint_result.crop(
 
263
  (x_offset, y_offset, x_offset + scaled_width, y_offset + scaled_height)
264
  )
265
+ print(f"✅ Padding entfernt: {inpaint_result.size} → {downscaled_result.size}")
266
 
267
+ # Herunterskaliertes Originalbild für spätere Verwendung
268
+ original_downscaled = original_image.resize(
269
+ (scaled_width, scaled_height),
270
+ Image.Resampling.LANCZOS
271
+ )
272
 
273
+ # 2. MODUS-SPEZIFISCHE VORBEREITUNG
274
+ if mode == "environment_change":
275
+ # ==============================================
276
+ # MODUS: UMWELT ÄNDERN (Focus bleibt original)
277
+ # ==============================================
278
+ print("🔄 Modus: Umwelt ändern - Original-Focus in bearbeitetes Bild integrieren")
279
+
280
+ if bbox_coords and all(c is not None for c in bbox_coords):
281
+ x1, y1, x2, y2 = bbox_coords
282
+
283
+ # BBox-Bereiche für herunterskalierte Bilder berechnen
284
+ scale_factor = padding_info['scale_factor']
285
+ bbox_downscaled = (
286
+ int(x1 * scale_factor),
287
+ int(y1 * scale_factor),
288
+ int(x2 * scale_factor),
289
+ int(y2 * scale_factor)
290
+ )
291
+
292
+ # Original-Focus-Bereich ausschneiden
293
+ original_focus = original_downscaled.crop(bbox_downscaled)
294
+
295
+ # Original-Focus in das bearbeitete Bild einfügen
296
+ # (überschreibt den bearbeiteten BBox-Bereich mit dem Original)
297
+ downscaled_result.paste(original_focus, bbox_downscaled[:2])
298
+
299
+ print(f"✅ Original-Focus ({bbox_downscaled}) in bearbeitetes Bild integriert")
300
+
301
+ # Für Compositing: Das gesamte bearbeitete Bild (jetzt mit Original-Focus) verwenden
302
+ edited_region_downscaled = downscaled_result
303
+ target_for_compositing = original_image # Wird später überschrieben
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 - Bearbeiteten Bereich in Originalbild integrieren")
311
+
312
+ if bbox_coords and all(c is not None for c in bbox_coords):
313
+ x1, y1, x2, y2 = bbox_coords
314
+
315
+ # BBox-Bereich für herunterskaliertes Bild berechnen
316
+ scale_factor = padding_info['scale_factor']
317
+ bbox_downscaled = (
318
+ int(x1 * scale_factor),
319
+ int(y1 * scale_factor),
320
+ int(x2 * scale_factor),
321
+ int(y2 * scale_factor)
322
+ )
323
+
324
+ # Bearbeiteten BBox-Bereich ausschneiden
325
+ edited_region_downscaled = downscaled_result.crop(bbox_downscaled)
326
+ print(f"✅ Bearbeiteten {mode_name}-Bereich ausgeschnitten: {bbox_downscaled}")
327
+ else:
328
+ # Fallback: gesamtes Bild verwenden
329
+ edited_region_downscaled = downscaled_result
330
+
331
+ target_for_compositing = original_image
332
+
333
+ # 3. HOCHSKALIEREN auf Originalgröße
334
  original_size = (padding_info['original_width'], padding_info['original_height'])
 
335
 
336
+ if mode == "environment_change":
337
+ # Das gesamte bearbeitete Bild (mit Original-Focus) hochskalieren
338
+ edited_region_fullsize = edited_region_downscaled.resize(
339
+ original_size,
340
+ Image.Resampling.LANCZOS
341
+ )
342
+ print(f"✅ Komplettes Bild auf Originalgröße skaliert: {edited_region_fullsize.size}")
343
+
344
+ # Bei environment_change ist das Ergebnis bereits komplett
345
+ return edited_region_fullsize.convert("RGB")
346
 
347
+ else:
348
+ # Nur den bearbeiteten BBox-Bereich hochskalieren
349
+ edited_region_fullsize = edited_region_downscaled.resize(
350
+ original_size,
351
+ Image.Resampling.LANCZOS
352
+ )
353
+ print(f"✅ Bearbeiteter Bereich auf Originalgröße skaliert: {edited_region_fullsize.size}")
354
 
355
+ # 4. COMPOSITING mit weicher Maske (nur für focus_change/face_only_change)
356
+ # Weiche Maske erstellen für sanfte Übergänge
357
  from PIL import ImageFilter
 
 
358
 
359
+ soft_mask = original_mask.copy()
360
+ soft_mask = soft_mask.filter(ImageFilter.MaxFilter(5)) # Maske leicht erweitern
361
+ soft_mask = soft_mask.filter(ImageFilter.GaussianBlur(3)) # Weiche Kanten
362
 
363
+ # Alpha-Blending vorbereiten
364
+ final_image = original_image.copy()
365
  edited_rgba = edited_region_fullsize.convert("RGBA")
366
  soft_mask_rgba = soft_mask.convert("L")
367
 
368
+ # Temporäres Bild mit Alpha-Kanal
369
  temp_image = Image.new("RGBA", original_size, (0, 0, 0, 0))
370
  temp_image.paste(edited_rgba, (0, 0), soft_mask_rgba)
371
 
372
+ # Finales Compositing
373
  final_image = Image.alpha_composite(final_image.convert("RGBA"), temp_image)
374
  final_image = final_image.convert("RGB")
375
 
376
  print(f"✅ Compositing abgeschlossen. Finale Größe: {final_image.size}")
 
377
  return final_image
378
 
379
+
380
  def auto_detect_face_area(image):
381
  """Optimierten Vorschlag für Gesichtsbereich ohne externe Bibliotheken"""
382
  width, height = image.size
 
1125
  original_image=image.convert("RGB"),
1126
  inpaint_result=generated_image,
1127
  original_mask=original_mask,
1128
+ padding_info=padding_info,
1129
+ bbox_coords=(bbox_x1, bbox_y1, bbox_x2, bbox_y2), # NEU!
1130
+ mode=mode # NEU!
1131
+ )
1132
  print(f"✅ Korrektes Compositing durchgeführt")
1133
  else:
1134
  # Keine Maske: Einfach das generierte Bild zurückgeben