Astridkraft commited on
Commit
e652b80
·
verified ·
1 Parent(s): 06406ce

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +192 -48
app.py CHANGED
@@ -152,6 +152,77 @@ class ImageToImageProgressCallback:
152
  self.progress(progress_percent / 100, desc="Generierung läuft - CPU benötigt bis zu 20 Minuten!")
153
  return callback_kwargs
154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  # === FUNKTIONEN ===
156
  def text_to_image(prompt, steps, guidance_scale, progress=gr.Progress()):
157
  try:
@@ -376,11 +447,32 @@ def main_ui():
376
  .image-upload .svelte-1p4f8co {
377
  display: block !important;
378
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  """
380
  ) as demo:
381
 
382
-
383
-
384
  # --- Hauptanwendungsbereich (zunächst versteckt) ---
385
  with gr.Column(visible=True) as content_area:
386
  with gr.Tab("Text zu Bild"):
@@ -425,14 +517,64 @@ def main_ui():
425
  with gr.Tab("Bild zu Bild"):
426
  gr.Markdown("**Lade ein Bild hoch und beschreibe die gewünschte Veränderung:**")
427
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
428
  with gr.Row():
429
- img_input = gr.Image(
430
- type="pil",
431
- label="Eingabebild",
432
- height=300,
433
- sources=["upload"] # Nur Upload-Button anzeigen
434
  )
435
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
  with gr.Row():
437
  with gr.Column():
438
  img_prompt = gr.Textbox(
@@ -449,6 +591,7 @@ def main_ui():
449
  info="Was soll vermieden werden? Unerwünschte Elemente auflisten."
450
  )
451
 
 
452
  with gr.Row():
453
  with gr.Column():
454
  strength_slider = gr.Slider(
@@ -468,48 +611,13 @@ def main_ui():
468
  label="Prompt-Stärke",
469
  info="Einfluss des Prompts auf das Ergebnis (6-10 für natürliche Ergebnisse)"
470
  )
471
-
472
- # GESICHTSOPTIONEN
473
- with gr.Row():
474
- face_preserve = gr.Checkbox(
475
- label="Gesicht, Tier, Gegenstand beibehalten",
476
- value=True,
477
- info="Aktiviert: Bildelement bleibt erhalten, Hintergrund wird verändert | Deaktiviert: Nur Bildelement wird verändert"
478
- )
479
-
480
- with gr.Row():
481
- gr.Markdown("**Bildelementbereich anpassen**")
482
-
483
- with gr.Row():
484
- bbox_x1 = gr.Number(
485
- label="Links (x1)",
486
- value=100,
487
- precision=0,
488
- info="Linke Kante des Gesichtsbereichs"
489
- )
490
- bbox_y1 = gr.Number(
491
- label="Oben (y1)",
492
- value=100,
493
- precision=0,
494
- info="Obere Kante des Gesichtsbereichs"
495
- )
496
- bbox_x2 = gr.Number(
497
- label="Rechts (x2)",
498
- value=300,
499
- precision=0,
500
- info="Rechte Kante des Gesichtsbereichs"
501
- )
502
- bbox_y2 = gr.Number(
503
- label="Unten (y2)",
504
- value=300,
505
- precision=0,
506
- info="Untere Kante des Gesichtsbereichs"
507
- )
508
 
509
  with gr.Row():
510
  gr.Markdown(
511
  "**Achtung:**\n"
512
- "• **Automatische Bildelementerkennung** setzt Koordinaten beim Upload\n"
 
 
513
  "• **Koordinaten nur bei erkennbaren Verzerrungen anpassen** (Bereiche leicht verschieben)"
514
  )
515
 
@@ -523,13 +631,49 @@ def main_ui():
523
  type="pil"
524
  )
525
 
526
- # Event-Handler für Bild-Upload
 
527
  img_input.change(
528
- fn=update_bbox_from_image,
529
  inputs=[img_input],
530
- outputs=[bbox_x1, bbox_y1, bbox_x2, bbox_y2]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
531
  )
532
 
 
533
  transform_btn.click(
534
  fn=img_to_image,
535
  inputs=[
 
152
  self.progress(progress_percent / 100, desc="Generierung läuft - CPU benötigt bis zu 20 Minuten!")
153
  return callback_kwargs
154
 
155
+ # === NEUE FUNKTIONEN FÜR DIE FEATURES ===
156
+ def create_preview_image(image, bbox_coords, face_preserve, mode_color):
157
+ """Erstellt eine Vorschau mit farbigem Rahmen basierend auf dem Modus"""
158
+ if image is None:
159
+ return None
160
+
161
+ # Erstelle eine Kopie für die Vorschau
162
+ preview = image.copy()
163
+ draw = ImageDraw.Draw(preview)
164
+
165
+ # Rahmenfarbe basierend auf Modus
166
+ if mode_color == "red":
167
+ border_color = (255, 0, 0, 180) # Rot mit Transparenz
168
+ mode_text = "NUR BILDELEMENT VERÄNDERN"
169
+ else:
170
+ border_color = (0, 255, 0, 180) # Grün mit Transparenz
171
+ mode_text = "BILDELEMENT BEIBEHALTEN"
172
+
173
+ # Zeichne den Rahmen um das gesamte Bild
174
+ border_width = 8
175
+ draw.rectangle([0, 0, preview.width-1, preview.height-1],
176
+ outline=border_color, width=border_width)
177
+
178
+ # Zeichne Bounding Box wenn Koordinaten vorhanden
179
+ if bbox_coords and all(coord is not None for coord in bbox_coords):
180
+ x1, y1, x2, y2 = bbox_coords
181
+
182
+ # Rahmen für Bounding Box
183
+ box_color = (255, 255, 0, 200) # Gelb für Bounding Box
184
+ draw.rectangle([x1, y1, x2, y2], outline=box_color, width=3)
185
+
186
+ # Text-Label für den Modus
187
+ text_color = (255, 255, 255)
188
+ bg_color = (0, 0, 0, 160)
189
+
190
+ # Hintergrund für Text
191
+ text_bbox = draw.textbbox((x1, y1 - 25), mode_text)
192
+ draw.rectangle([text_bbox[0]-5, text_bbox[1]-2, text_bbox[2]+5, text_bbox[3]+2],
193
+ fill=bg_color)
194
+
195
+ # Text zeichnen
196
+ draw.text((x1, y1 - 25), mode_text, fill=text_color)
197
+
198
+ return preview
199
+
200
+ def update_live_preview(image, bbox_x1, bbox_y1, bbox_x2, bbox_y2, face_preserve):
201
+ """Aktualisiert die Live-Vorschau bei Koordinaten-Änderungen"""
202
+ if image is None:
203
+ return None
204
+
205
+ bbox_coords = [bbox_x1, bbox_y1, bbox_x2, bbox_y2]
206
+
207
+ # Bestimme Rahmenfarbe basierend auf Modus
208
+ mode_color = "green" if face_preserve else "red"
209
+
210
+ return create_preview_image(image, bbox_coords, face_preserve, mode_color)
211
+
212
+ def process_image_upload(image):
213
+ """Verarbeitet Bild-Upload und gibt Bild + Koordinaten zurück"""
214
+ if image is None:
215
+ return None, None, None, None, None
216
+
217
+ # Auto-Koordinaten generieren
218
+ bbox = auto_detect_face_area(image)
219
+ bbox_x1, bbox_y1, bbox_x2, bbox_y2 = bbox
220
+
221
+ # Vorschau mit grünem Rahmen (Standard: Gesicht beibehalten)
222
+ preview = create_preview_image(image, bbox, True, "green")
223
+
224
+ return preview, bbox_x1, bbox_y1, bbox_x2, bbox_y2
225
+
226
  # === FUNKTIONEN ===
227
  def text_to_image(prompt, steps, guidance_scale, progress=gr.Progress()):
228
  try:
 
447
  .image-upload .svelte-1p4f8co {
448
  display: block !important;
449
  }
450
+ .preview-box {
451
+ border: 2px dashed #ccc;
452
+ padding: 10px;
453
+ border-radius: 8px;
454
+ margin: 10px 0;
455
+ }
456
+ .mode-red {
457
+ border: 3px solid #ff4444 !important;
458
+ }
459
+ .mode-green {
460
+ border: 3px solid #44ff44 !important;
461
+ }
462
+ .coordinate-sliders {
463
+ background: #f8f9fa;
464
+ padding: 15px;
465
+ border-radius: 8px;
466
+ margin: 10px 0;
467
+ }
468
+ .gr-checkbox .wrap .text-gray {
469
+ font-size: 14px !important;
470
+ font-weight: 600 !important;
471
+ line-height: 1.4 !important;
472
+ }
473
  """
474
  ) as demo:
475
 
 
 
476
  # --- Hauptanwendungsbereich (zunächst versteckt) ---
477
  with gr.Column(visible=True) as content_area:
478
  with gr.Tab("Text zu Bild"):
 
517
  with gr.Tab("Bild zu Bild"):
518
  gr.Markdown("**Lade ein Bild hoch und beschreibe die gewünschte Veränderung:**")
519
 
520
+ # NEUE ANORDNUNG: Eingabebild und Live-Vorschau nebeneinander
521
+ with gr.Row():
522
+ with gr.Column():
523
+ img_input = gr.Image(
524
+ type="pil",
525
+ label="Eingabebild",
526
+ height=300,
527
+ sources=["upload"],
528
+ elem_id="image-upload"
529
+ )
530
+ with gr.Column():
531
+ preview_output = gr.Image(
532
+ label="🎯 Live-Vorschau mit Maske",
533
+ height=300,
534
+ interactive=False,
535
+ show_download_button=False
536
+ )
537
+
538
+ # DARUNTER: Checkbox Gesicht/Person oder Umgebung ändern
539
  with gr.Row():
540
+ face_preserve = gr.Checkbox(
541
+ label="Schutz",
542
+ value=True,
543
+ info="🟢 Checkbox AN: Alles AUSSERHALB des gelben Rahmens verändern | 🔴 Checkbox AUS: Nur INNERHALB des gelben Rahmens verändern"
 
544
  )
545
 
546
+ # DARUNTER: Bildelementbereich anpassen
547
+ with gr.Row():
548
+ gr.Markdown("**Bildelementbereich anpassen**")
549
+
550
+ with gr.Row():
551
+ with gr.Column():
552
+ bbox_x1 = gr.Slider(
553
+ label="Links (x1)",
554
+ minimum=0, maximum=512, value=100, step=1,
555
+ info="Linke Kante des Bildelementbereichs"
556
+ )
557
+ with gr.Column():
558
+ bbox_y1 = gr.Slider(
559
+ label="Oben (y1)",
560
+ minimum=0, maximum=512, value=100, step=1,
561
+ info="Obere Kante des Bildelementbereichs"
562
+ )
563
+ with gr.Row():
564
+ with gr.Column():
565
+ bbox_x2 = gr.Slider(
566
+ label="Rechts (x2)",
567
+ minimum=0, maximum=512, value=300, step=1,
568
+ info="Rechte Kante des Bildelementbereichs"
569
+ )
570
+ with gr.Column():
571
+ bbox_y2 = gr.Slider(
572
+ label="Unten (y2)",
573
+ minimum=0, maximum=512, value=300, step=1,
574
+ info="Untere Kante des Bildelementbereichs"
575
+ )
576
+
577
+ # DARUNTER: Prompt und Negativ-Prompt
578
  with gr.Row():
579
  with gr.Column():
580
  img_prompt = gr.Textbox(
 
591
  info="Was soll vermieden werden? Unerwünschte Elemente auflisten."
592
  )
593
 
594
+ # DARUNTER: Veränderungsstärke, Inferenzschritte, Promptstärke
595
  with gr.Row():
596
  with gr.Column():
597
  strength_slider = gr.Slider(
 
611
  label="Prompt-Stärke",
612
  info="Einfluss des Prompts auf das Ergebnis (6-10 für natürliche Ergebnisse)"
613
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
614
 
615
  with gr.Row():
616
  gr.Markdown(
617
  "**Achtung:**\n"
618
+ "• **🆕 Automatische Bildelementerkennung** setzt Koordinaten beim Upload\n"
619
+ "• **🆕 Live-Vorschau** zeigt farbige Rahmen je nach Modus (🔴 Rot / 🟢 Grün)\n"
620
+ "• **🆕 Koordinaten-Schieberegler** für präzise Anpassung mit Live-Update\n"
621
  "• **Koordinaten nur bei erkennbaren Verzerrungen anpassen** (Bereiche leicht verschieben)"
622
  )
623
 
 
631
  type="pil"
632
  )
633
 
634
+ # NEUE: Event-Handler für alle Live-Updates
635
+ # Bild-Upload: Auto-Koordinaten + Vorschau
636
  img_input.change(
637
+ fn=process_image_upload,
638
  inputs=[img_input],
639
+ outputs=[preview_output, bbox_x1, bbox_y1, bbox_x2, bbox_y2]
640
+ )
641
+
642
+ # Live-Updates bei Koordinaten-Änderungen
643
+ coordinate_inputs = [img_input, bbox_x1, bbox_y1, bbox_x2, bbox_y2, face_preserve]
644
+
645
+ bbox_x1.change(
646
+ fn=update_live_preview,
647
+ inputs=coordinate_inputs,
648
+ outputs=preview_output
649
+ )
650
+
651
+ bbox_y1.change(
652
+ fn=update_live_preview,
653
+ inputs=coordinate_inputs,
654
+ outputs=preview_output
655
+ )
656
+
657
+ bbox_x2.change(
658
+ fn=update_live_preview,
659
+ inputs=coordinate_inputs,
660
+ outputs=preview_output
661
+ )
662
+
663
+ bbox_y2.change(
664
+ fn=update_live_preview,
665
+ inputs=coordinate_inputs,
666
+ outputs=preview_output
667
+ )
668
+
669
+ # Live-Update bei Modus-Änderung
670
+ face_preserve.change(
671
+ fn=update_live_preview,
672
+ inputs=coordinate_inputs,
673
+ outputs=preview_output
674
  )
675
 
676
+ # Transform-Button (UNVERÄNDERT - gibt OUTPUT zurück)
677
  transform_btn.click(
678
  fn=img_to_image,
679
  inputs=[