Astridkraft commited on
Commit
3a6d54d
·
verified ·
1 Parent(s): f3ad55c

Update controlnet_module.py

Browse files
Files changed (1) hide show
  1. controlnet_module.py +88 -70
controlnet_module.py CHANGED
@@ -25,7 +25,7 @@ class ControlNetProgressCallback:
25
  print(f"ControlNet Fortschritt: {self.current_step}/{self.total_steps} ({progress_percentage:.1%})")
26
  return callback_kwargs
27
 
28
- #Initialisierung
29
  class ControlNetProcessor:
30
  def __init__(self, device="cuda", torch_dtype=torch.float32):
31
  self.device = device
@@ -39,9 +39,6 @@ class ControlNetProcessor:
39
  self.pipe_depth = None
40
  self.pipe_multi_inside = None # OpenPose + Canny für Inside-Box
41
  self.pipe_multi_outside = None # Depth + Canny für Outside-Box
42
- self.conditioning_maps = None
43
- self.controlnet_type = None
44
- self.controlnet_scales = None
45
 
46
  def load_pose_detector(self):
47
  """Lädt nur den Pose-Detector"""
@@ -257,75 +254,96 @@ class ControlNetProcessor:
257
  raise
258
  return self.pipe_multi_outside
259
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
 
261
- def prepare_conditioning_maps(self, image, keep_environment=False):
262
- """
263
- NEUE METHODE: Erstellt und speichert Conditioning-Maps basierend auf Bild und Modus.
264
- Wird von app.py EINMAL am Anfang aufgerufen.
265
- """
266
- print("🎯 ControlNet: Erstelle und speichere Conditioning-Maps...")
267
-
268
- if keep_environment:
269
- # FALL: Umgebung ändern oder nur Gesicht -> Depth + Canny
270
- print(" Modus: Depth + Canny")
271
- self.conditioning_maps = [
272
- self.extract_depth_map(image),
273
- self.extract_canny_edges(image)
274
- ]
275
- self.controlnet_type = "multi_outside"
276
- self.controlnet_scales = [0.6, 0.4] # Gewichtung Depth vs Canny
277
- else:
278
- # FALL: Focus verändern -> OpenPose + Canny
279
- print(" Modus: OpenPose + Canny")
280
- self.conditioning_maps = [
281
- self.extract_pose(image),
282
- self.extract_canny_edges(image)
283
- ]
284
- self.controlnet_type = "multi_inside"
285
- self.controlnet_scales = [0.7, 0.3] # Gewichtung Pose vs Canny
286
-
287
- print(f"✅ {len(self.conditioning_maps)} Conditioning-Maps gespeichert.")
288
- return self.conditioning_maps
289
-
290
- def get_controlnet_conditioning(self, noisy_latents, timestep, prompt_embeds, controlnet_strength=1.0):
291
- """
292
- NEUE KERNMETHODE: Berechnet Steuersignale für einen spezifischen Denoising-Step.
293
- Wird von app.py in JEDEM Denoising-Schritt aufgerufen.
294
-
295
- Args:
296
- noisy_latents: Aktuelle verrauschte Latents (Shape: [1, 4, 64, 64])
297
- timestep: Aktueller Timestep (z.B. tensor([818]))
298
- prompt_embeds: Embeddings des Prompts
299
- controlnet_strength: Globale Stärke der ControlNet-Wirkung
300
-
301
- Returns:
302
- controlnet_outputs: Steuersignale, die an UNet übergeben werden
303
- """
304
- if not hasattr(self, 'conditioning_maps') or self.conditioning_maps is None:
305
- raise ValueError("Conditioning-Maps nicht vorhanden. Rufen Sie zuerst prepare_conditioning_maps() auf.")
306
-
307
- # Lade die passende Multi-ControlNet Pipeline
308
- pipe = self.load_controlnet_pipeline(self.controlnet_type)
309
-
310
- # Skaliere die Conditioning-Stärken mit der globalen controlnet_strength
311
- scaled_conditioning_scales = [scale * controlnet_strength for scale in self.controlnet_scales]
312
-
313
- # WICHTIG: ControlNet-Aufruf für EINEN Step
314
- # Die Pipeline muss im "Single-Step-Modus" konfiguriert sein
315
- with torch.no_grad():
316
- controlnet_outputs = pipe.controlnet(
317
- noisy_latents,
318
- timestep,
319
- encoder_hidden_states=prompt_embeds,
320
- controlnet_cond=self.conditioning_maps,
321
- conditioning_scale=scaled_conditioning_scales,
322
- return_dict=True,
323
- )
324
-
325
- # Gib die Steuersignale zurück (z.B. mid_block_res_sample, down_block_res_samples)
326
- return controlnet_outputs
327
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
 
 
 
 
 
 
 
 
 
 
 
 
329
 
330
  def prepare_inpaint_input(self, image, keep_environment=False):
331
  """
 
25
  print(f"ControlNet Fortschritt: {self.current_step}/{self.total_steps} ({progress_percentage:.1%})")
26
  return callback_kwargs
27
 
28
+
29
  class ControlNetProcessor:
30
  def __init__(self, device="cuda", torch_dtype=torch.float32):
31
  self.device = device
 
39
  self.pipe_depth = None
40
  self.pipe_multi_inside = None # OpenPose + Canny für Inside-Box
41
  self.pipe_multi_outside = None # Depth + Canny für Outside-Box
 
 
 
42
 
43
  def load_pose_detector(self):
44
  """Lädt nur den Pose-Detector"""
 
254
  raise
255
  return self.pipe_multi_outside
256
 
257
+ def generate_with_controlnet(
258
+ self, image, prompt, negative_prompt,
259
+ steps, guidance_scale, controlnet_strength,
260
+ progress=None, keep_environment=False
261
+ ):
262
+ """
263
+ GENERIERT BILD MIT CONTROLNET
264
+ WICHTIG: Diese Funktion wird von app.py aufgerufen
265
+
266
+ Parameter keep_environment bestimmt:
267
+ - True: "Umgebung ändern" und "Ausschließlich Gesicht" → Depth+Canny
268
+ - False: "Focus verändern" → OpenPose+Canny
269
+
270
+ Die eigentliche Maskenlogik wird in app.py (create_face_mask) gehandhabt
271
+ """
272
+ try:
273
+ # --- LOGIK FÜR 3 MODI (VON APP.PY GESTEUERT) ---
274
+ if keep_environment:
275
+ # FALL 1 & 3: Umgebung ändern ODER Ausschließlich Gesicht → Depth + Canny
276
+ print("🎯 ControlNet: Depth + Canny (keep_environment=True)")
277
+
278
+ # Beide Conditioning Maps erstellen
279
+ depth_image = self.extract_depth_map(image)
280
+ canny_image = self.extract_canny_edges(image)
281
+ print("✅ Depth + Canny Maps für Outside/Inside-Box erstellt")
282
+
283
+ # Multi-ControlNet für Outside verwenden
284
+ conditioning_images = [depth_image, canny_image]
285
+ controlnet_type = "multi_outside"
286
+
287
+ # Gewichtung: Depth 60%, Canny 40%
288
+ controlnet_conditioning_scale = [controlnet_strength * 0.6, # Depth: 60% für räumliche Tiefe
289
+ controlnet_strength * 0.4] # Canny: 40% für Strukturen
290
+
291
+ else:
292
+ # FALL 2: Focus verändern → OpenPose + Canny
293
+ print("🎯 ControlNet: OpenPose + Canny (keep_environment=False)")
294
+
295
+ # Beide Conditioning Maps erstellen
296
+ pose_image = self.extract_pose(image)
297
+ canny_image = self.extract_canny_edges(image)
298
+ print("✅ OpenPose + Canny Maps für Inside-Box erstellt")
299
+
300
+ # Multi-ControlNet für Inside verwenden
301
+ conditioning_images = [pose_image, canny_image]
302
+ controlnet_type = "multi_inside"
303
+
304
+ # Gewichtung: OpenPose 70%, Canny 30%
305
+ controlnet_conditioning_scale = [controlnet_strength * 0.7, # OpenPose: 70% für Person
306
+ controlnet_strength * 0.3] # Canny: 30% für Konturen
307
+
308
+ # Zufälliger Seed
309
+ seed = random.randint(0, 2**32 - 1)
310
+ generator = torch.Generator(device=self.device).manual_seed(seed)
311
+ print(f"ControlNet Seed: {seed}")
312
+
313
+ pipe = self.load_controlnet_pipeline(controlnet_type)
314
+
315
+ # Fortschritt-Callback
316
+ callback = ControlNetProgressCallback(progress, int(steps)) if progress is not None else None
317
 
318
+ print("🔄 ControlNet: Starte Pipeline...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
 
320
+ # ControlNet Generierung
321
+ result = pipe(
322
+ prompt=prompt,
323
+ image=conditioning_images,
324
+ negative_prompt=negative_prompt,
325
+ num_inference_steps=int(steps),
326
+ guidance_scale=guidance_scale,
327
+ generator=generator,
328
+ controlnet_conditioning_scale=controlnet_conditioning_scale,
329
+ height=512,
330
+ width=512,
331
+ output_type="pil",
332
+ callback_on_step_end=callback,
333
+ callback_on_step_end_tensor_inputs=[],
334
+ )
335
 
336
+ print("✅ ControlNet abgeschlossen!")
337
+
338
+ # Rückgabe: ControlNet-Output + Originalbild (für Inpaint)
339
+ return result.images[0], image
340
+
341
+ except Exception as e:
342
+ print(f"❌ Fehler in ControlNet: {e}")
343
+ import traceback
344
+ traceback.print_exc()
345
+ error_image = image.convert("RGB").resize((512, 512))
346
+ return error_image, error_image
347
 
348
  def prepare_inpaint_input(self, image, keep_environment=False):
349
  """