DegMaTsu commited on
Commit
c53fc7a
·
verified ·
1 Parent(s): 99c9e8c

Upload reactor_swapper.py

Browse files
custom_nodes/comfyui-reactor-node/scripts/reactor_swapper.py CHANGED
@@ -14,13 +14,14 @@ from insightface.app.common import Face
14
  # except:
15
  # cuda = None
16
  import torch
 
17
 
18
  import folder_paths
19
  import comfy.model_management as model_management
20
  from modules.shared import state
21
 
22
  # 1. Добавьте импорт logging наверху файла, если его там нет:
23
- import logging
24
  from scripts.reactor_logger import logger
25
  from reactor_utils import (
26
  move_path,
@@ -126,9 +127,21 @@ def getFaceSwapModel(model_path: str):
126
  if FS_MODEL is None or CURRENT_FS_MODEL_PATH is None or CURRENT_FS_MODEL_PATH != model_path:
127
  CURRENT_FS_MODEL_PATH = model_path
128
  FS_MODEL = unload_model(FS_MODEL)
129
- if "hyperswap" in model_path.lower():
130
- FS_MODEL = ort.InferenceSession(model_path, providers=providers)
 
 
 
 
 
 
 
 
 
 
 
131
  else:
 
132
  FS_MODEL = insightface.model_zoo.get_model(model_path, providers=providers)
133
  return FS_MODEL
134
 
@@ -137,10 +150,10 @@ def get_landmarks_5(face):
137
  # face.landmark_5: np.ndarray shape (5,2)
138
  # Если нет, попробуй face.kps или face.landmark
139
  if hasattr(face, 'landmark_5') and face.landmark_5 is not None:
140
- logger.debug("landmark_5: %s", face.landmark_5)
141
  return face.landmark_5
142
  elif hasattr(face, 'kps') and face.kps is not None:
143
- logger.debug("kps: %s", face.kps)
144
  return face.kps
145
  elif hasattr(face, 'landmark') and face.landmark is not None:
146
  # 68-точечная разметка, берём нужные индексы
@@ -148,9 +161,9 @@ def get_landmarks_5(face):
148
  # Пример: [36, 45, 30, 48, 54] — левый/правый глаз, нос, левый/правый рот
149
  if face.landmark.shape[0] >= 68:
150
  idxs = [36, 45, 30, 48, 54]
151
- logger.debug("landmark (68 точек): %s", face.landmark[idxs])
152
  return face.landmark[idxs]
153
- logger.warning("Нет подходящих точек в объекте Face. Доступные атрибуты: %s", dir(face))
154
  return None
155
 
156
  #### Что проверить:
@@ -178,14 +191,14 @@ def create_gradient_mask(crop_size=256):
178
 
179
  # 3. Рисуем эллипс (заполняем белым цветом, значение=1.0)
180
  cv2.ellipse(
181
- mask,
182
- center,
183
- axes,
184
- angle=0,
185
- startAngle=0,
186
- endAngle=360,
187
- color=1.0,
188
- thickness=-1
189
  )
190
 
191
  # 4. Применяем размытие для плавных краёв
@@ -212,7 +225,7 @@ def paste_back(target_img, swapped_face, M, crop_size=256):
212
  mask = create_gradient_mask(crop_size)
213
 
214
  # Сохраняем для отладки
215
- cv2.imwrite("debug_original_mask.png", (mask * 255).astype(np.uint8))
216
 
217
  # Преобразуем в трехканальную маску
218
  mask_3c = np.stack([mask] * 3, axis=2)
@@ -223,7 +236,7 @@ def paste_back(target_img, swapped_face, M, crop_size=256):
223
  # 3. Обратное преобразование (WARP_INVERSE_MAP) для лица И маски
224
  # Для лица (INTER_LANCZOS4 — высококачественная интерполяция)
225
  inv_face = cv2.warpAffine(
226
- swapped_face.astype(np.float32),
227
  M,
228
  (w, h),
229
  flags=cv2.INTER_LANCZOS4 | cv2.WARP_INVERSE_MAP,
@@ -246,13 +259,13 @@ def paste_back(target_img, swapped_face, M, crop_size=256):
246
  inv_mask = cv2.GaussianBlur(inv_mask, (3, 3), 0)
247
 
248
  # Отладка
249
- logger.debug("Warped face shape: %s | Min: %s | Max: %s", inv_face.shape, inv_face.min(), inv_face.max())
250
- logger.debug("Warped mask shape: %s | Min: %s | Max: %s", inv_mask.shape, inv_mask.min(), inv_mask.max())
251
 
252
  # Визуализация
253
- # cv2.imshow("Warped Face", inv_face.astype(np.uint8))
254
- # cv2.imshow("Warped Mask", (inv_mask * 255).astype(np.uint8))
255
- # cv2.waitKey(1)
256
 
257
  # 6. Плавное наложение
258
  target_img_float = target_img.astype(np.float32)
@@ -263,7 +276,7 @@ def paste_back(target_img, swapped_face, M, crop_size=256):
263
  result = np.clip(result, 0, 255).astype(np.uint8)
264
 
265
  # Сохраняем результат
266
- cv2.imwrite("debug_result.png", result)
267
 
268
  return result
269
 
@@ -276,8 +289,8 @@ def visualize_points(img, points, color=(0, 255, 0)):
276
  img = img.copy()
277
  for p in points:
278
  cv2.circle(img, tuple(p.astype(int)), 3, color, -1)
279
- # cv2.imshow("Face Points", img)
280
- # cv2.waitKey(1)
281
 
282
  # Итоговая функция run_hyperswap с аффинным преобразованием
283
  def run_hyperswap(session, source_face, target_face, target_img):
@@ -289,7 +302,7 @@ def run_hyperswap(session, source_face, target_face, target_img):
289
  visualize_points(target_img, target_landmarks_5, (0, 255, 0)) # Зеленые точки
290
 
291
  if target_landmarks_5 is None:
292
- logger.error("Не удалось получить 5 точек для целевого лица")
293
  # Важно: Если ошибка, возвращаем None и исходную матрицу (или обрабатываем ошибку иначе)
294
  return None, None
295
 
@@ -304,7 +317,7 @@ def run_hyperswap(session, source_face, target_face, target_img):
304
 
305
  # Вычисляем аффинную матрицу
306
  M = get_affine_transform(target_landmarks_5.astype(np.float32), std_landmarks_256)
307
- logger.debug("Affine Matrix M (used for cropping):\n%s", M)
308
 
309
  #### Что проверить:
310
  # Матрица `M` не должна содержать `NaN` или бесконечности.
@@ -317,9 +330,9 @@ def run_hyperswap(session, source_face, target_face, target_img):
317
  #### Что проверить:
318
  # Окно `"Crop Before Inference"` должно показывать лицо, вырезанное по аффинному преобразованию.
319
  # Если изображение черное — проблема в `M` или `target_landmarks_5`.
320
- logger.debug("Crop shape: %s | Min: %s | Max: %s", crop.shape, crop.min(), crop.max())
321
- # cv2.imshow("Crop Before Inference", crop)
322
- # cv2.waitKey(1) # Отображает изображение
323
 
324
  # 4. Преобразуем crop для модели
325
  # crop_input = crop[:, :, ::-1] / 255.0
@@ -333,9 +346,9 @@ def run_hyperswap(session, source_face, target_face, target_img):
333
  # 5. Инференс
334
  try:
335
  output = session.run(None, {'source': source_embedding, 'target': crop_input})[0][0]
336
- logger.debug("Model output shape: %s | Min: %s | Max: %s", output.shape, output.min(), output.max())
337
  except Exception as e:
338
- logger.error("Ошибка выполнения модели: %s", e)
339
  return target_img
340
 
341
  # 6. Обратная нормализация
@@ -353,15 +366,21 @@ def run_hyperswap(session, source_face, target_face, target_img):
353
  #### Что проверить:
354
  # `output` должен быть в диапазоне `[0..255]` и содержать лицо.
355
  # Если `output` черный — проблема в нормализации/денормализации или в самой модели.
356
- logger.debug("Output after denormalization: Min: %s | Max: %s", output.min(), output.max())
357
- # cv2.imshow("Output After Denormalization", output)
358
- # cv2.waitKey(1)
359
 
360
  # 7. ИЗМЕНЕНИЕ: Возвращаем результат 256x256 И матрицу M
361
  # Мы больше не вызываем warp_and_paste_face отсюда.
362
  # return result
363
 
364
- return output, M # Возвращаем лицо (256x256) и матрицу M
 
 
 
 
 
 
365
 
366
  def sort_by_order(face, order: str):
367
  if order == "left-right":
@@ -456,13 +475,13 @@ def get_face_single(img_data: np.ndarray, face, face_index=0, det_size=(640, 640
456
  try:
457
  faces_sorted = sort_by_order(face, order)
458
  selected_face = faces_sorted[face_index]
459
- logger.debug("Выбрано лицо: bbox=%s, landmark_5=%s, kps=%s, landmark=%s",
460
- selected_face.bbox,
461
- hasattr(selected_face, "landmark_5"),
462
- hasattr(selected_face, "kps"),
463
- hasattr(selected_face, "landmark"))
464
  return selected_face, 0
465
- return faces_sorted[face_index], 0
466
  # return sorted(face, key=lambda x: x.bbox[0])[face_index], 0
467
  except IndexError:
468
  return None, 0
@@ -484,14 +503,14 @@ def swap_face(
484
  codeformer_weight: float = 0.5,
485
  interpolation: str = "Bicubic",
486
  ):
487
- # >>>>> РЕШЕНИЕ: Принудительная установка уровня DEBUG <<<<<
488
- if logger.getEffectiveLevel() != logging.DEBUG:
489
- print("\n--- [ReActor Debug] Принудительная установка уровня логирования на DEBUG (10) в swap_face ---")
490
- logger.setLevel(logging.DEBUG)
491
 
492
- # Проверочное сообщение (теперь оно должно появиться)
493
- logger.debug("--- ТЕСТ: swap_face запущена, уровень логирования DEBUG активен. ---")
494
- # >>>>> КОНЕЦ РЕШЕНИЯ <<<<<
495
 
496
  global SOURCE_FACES, SOURCE_IMAGE_HASH, TARGET_FACES, TARGET_IMAGE_HASH
497
  result_image = target_img
@@ -607,13 +626,19 @@ def swap_face(
607
  if len(source_faces_index) > 1 and source_face_idx > 0:
608
  source_face, src_wrong_gender = get_face_single(source_img, source_faces, face_index=source_faces_index[source_face_idx], gender_source=gender_source, order=faces_order[1])
609
  source_face_idx += 1
 
 
 
 
 
 
610
 
611
  if source_face is not None and src_wrong_gender == 0:
612
  target_face, wrong_gender = get_face_single(target_img, target_faces, face_index=face_num, gender_target=gender_target, order=faces_order[0])
613
  if target_face is not None and wrong_gender == 0:
614
  logger.status(f"Swapping...")
615
  if "hyperswap" in model:
616
- logger.status(f"Swapping with Hyperswap...")
617
  swapped_face_256, M = run_hyperswap(face_swapper, source_face, target_face, result)
618
  if swapped_face_256 is not None:
619
  result = paste_back(result, swapped_face_256, M, crop_size=256)
@@ -799,7 +824,17 @@ def swap_face_many(
799
  logger.status(f'Source Faces must have no entries (default=0), one entry, or same number of entries as target faces.')
800
  elif source_face is not None:
801
  results = target_imgs
802
- model_path = model_path = os.path.join(insightface_path, model)
 
 
 
 
 
 
 
 
 
 
803
  face_swapper = getFaceSwapModel(model_path)
804
 
805
  source_face_idx = 0
@@ -823,16 +858,23 @@ def swap_face_many(
823
  target_face_single, wrong_gender = get_face_single(target_img, target_face, face_index=face_num, gender_target=gender_target, order=faces_order[0])
824
  if target_face_single is not None and wrong_gender == 0:
825
  result = target_img
826
- # logger.status(f"Swapping {i}...")
827
- if face_boost_enabled:
 
 
 
 
 
 
828
  logger.status(f"Face Boost is enabled")
829
  bgr_fake, M = face_swapper.get(target_img, target_face_single, source_face, paste_back=False)
830
  bgr_fake, scale = restorer.get_restored_face(bgr_fake, face_restore_model, face_restore_visibility, codeformer_weight, interpolation)
831
  M *= scale
832
  result = swapper.in_swap(target_img, bgr_fake, M)
833
  else:
834
- # logger.status(f"Swapping as-is")
835
  result = face_swapper.get(target_img, target_face_single, source_face)
 
836
  results[i] = result
837
  pbar.update(1)
838
  elif wrong_gender == 1:
 
14
  # except:
15
  # cuda = None
16
  import torch
17
+ import gc # для очистки кэша
18
 
19
  import folder_paths
20
  import comfy.model_management as model_management
21
  from modules.shared import state
22
 
23
  # 1. Добавьте импорт logging наверху файла, если его там нет:
24
+ # import logging - закомментирован
25
  from scripts.reactor_logger import logger
26
  from reactor_utils import (
27
  move_path,
 
127
  if FS_MODEL is None or CURRENT_FS_MODEL_PATH is None or CURRENT_FS_MODEL_PATH != model_path:
128
  CURRENT_FS_MODEL_PATH = model_path
129
  FS_MODEL = unload_model(FS_MODEL)
130
+
131
+ # Извлекаем имя файла модели из пути
132
+ model_filename = os.path.basename(model_path)
133
+
134
+ # Определяем правильный путь в зависимости от типа модели
135
+ if "hyperswap" in model_filename.lower():
136
+ # Ищем в директории hyperswap
137
+ correct_path = os.path.join(folder_paths.models_dir, "hyperswap", model_filename)
138
+ FS_MODEL = ort.InferenceSession(correct_path, providers=providers)
139
+ elif "reswapper" in model_filename.lower():
140
+ # Ищем в директории reswapper
141
+ correct_path = os.path.join(folder_paths.models_dir, "reswapper", model_filename)
142
+ FS_MODEL = insightface.model_zoo.get_model(correct_path, providers=providers)
143
  else:
144
+ # Для моделей insightface используем оригинальный путь
145
  FS_MODEL = insightface.model_zoo.get_model(model_path, providers=providers)
146
  return FS_MODEL
147
 
 
150
  # face.landmark_5: np.ndarray shape (5,2)
151
  # Если нет, попробуй face.kps или face.landmark
152
  if hasattr(face, 'landmark_5') and face.landmark_5 is not None:
153
+ # logger.debug("landmark_5: %s", face.landmark_5)
154
  return face.landmark_5
155
  elif hasattr(face, 'kps') and face.kps is not None:
156
+ # logger.debug("kps: %s", face.kps)
157
  return face.kps
158
  elif hasattr(face, 'landmark') and face.landmark is not None:
159
  # 68-точечная разметка, берём нужные индексы
 
161
  # Пример: [36, 45, 30, 48, 54] — левый/правый глаз, нос, левый/правый рот
162
  if face.landmark.shape[0] >= 68:
163
  idxs = [36, 45, 30, 48, 54]
164
+ # logger.debug("landmark (68 точек): %s", face.landmark[idxs])
165
  return face.landmark[idxs]
166
+ # logger.warning("Нет подходящих точек в объекте Face. Доступные атрибуты: %s", dir(face))
167
  return None
168
 
169
  #### Что проверить:
 
191
 
192
  # 3. Рисуем эллипс (заполняем белым цветом, значение=1.0)
193
  cv2.ellipse(
194
+ mask, # Массив для рисования
195
+ center, # Центр эллипса
196
+ axes, # Полуоси (ширина, высота)
197
+ angle=0, # Угол поворота
198
+ startAngle=0, # Начальный угол дуги
199
+ endAngle=360, # Конечный угол дуги (360 = полный эллипс)
200
+ color=1.0, # Значение для заполнения (белый = 1.0)
201
+ thickness=-1 # -1 = заполнить всю область эллипса
202
  )
203
 
204
  # 4. Применяем размытие для плавных краёв
 
225
  mask = create_gradient_mask(crop_size)
226
 
227
  # Сохраняем для отладки
228
+ # cv2.imwrite("debug_original_mask.png", (mask * 255).astype(np.uint8))
229
 
230
  # Преобразуем в трехканальную маску
231
  mask_3c = np.stack([mask] * 3, axis=2)
 
236
  # 3. Обратное преобразование (WARP_INVERSE_MAP) для лица И маски
237
  # Для лица (INTER_LANCZOS4 — высококачественная интерполяция)
238
  inv_face = cv2.warpAffine(
239
+ swapped_face.astype(np.float32).copy(),
240
  M,
241
  (w, h),
242
  flags=cv2.INTER_LANCZOS4 | cv2.WARP_INVERSE_MAP,
 
259
  inv_mask = cv2.GaussianBlur(inv_mask, (3, 3), 0)
260
 
261
  # Отладка
262
+ # logger.debug("Warped face shape: %s | Min: %s | Max: %s", inv_face.shape, inv_face.min(), inv_face.max())
263
+ # logger.debug("Warped mask shape: %s | Min: %s | Max: %s", inv_mask.shape, inv_mask.min(), inv_mask.max())
264
 
265
  # Визуализация
266
+ # cv2.imshow("Warped Face", inv_face.astype(np.uint8))
267
+ # cv2.imshow("Warped Mask", (inv_mask * 255).astype(np.uint8))
268
+ # cv2.waitKey(1)
269
 
270
  # 6. Плавное наложение
271
  target_img_float = target_img.astype(np.float32)
 
276
  result = np.clip(result, 0, 255).astype(np.uint8)
277
 
278
  # Сохраняем результат
279
+ # cv2.imwrite("debug_result.png", result)
280
 
281
  return result
282
 
 
289
  img = img.copy()
290
  for p in points:
291
  cv2.circle(img, tuple(p.astype(int)), 3, color, -1)
292
+ # cv2.imshow("Face Points", img)
293
+ # cv2.waitKey(1)
294
 
295
  # Итоговая функция run_hyperswap с аффинным преобразованием
296
  def run_hyperswap(session, source_face, target_face, target_img):
 
302
  visualize_points(target_img, target_landmarks_5, (0, 255, 0)) # Зеленые точки
303
 
304
  if target_landmarks_5 is None:
305
+ # logger.error("Не удалось получить 5 точек для целевого лица")
306
  # Важно: Если ошибка, возвращаем None и исходную матрицу (или обрабатываем ошибку иначе)
307
  return None, None
308
 
 
317
 
318
  # Вычисляем аффинную матрицу
319
  M = get_affine_transform(target_landmarks_5.astype(np.float32), std_landmarks_256)
320
+ # logger.debug("Affine Matrix M (used for cropping):\n%s", M)
321
 
322
  #### Что проверить:
323
  # Матрица `M` не должна содержать `NaN` или бесконечности.
 
330
  #### Что проверить:
331
  # Окно `"Crop Before Inference"` должно показывать лицо, вырезанное по аффинному преобразованию.
332
  # Если изображение черное — проблема в `M` или `target_landmarks_5`.
333
+ # logger.debug("Crop shape: %s | Min: %s | Max: %s", crop.shape, crop.min(), crop.max())
334
+ # cv2.imshow("Crop Before Inference", crop)
335
+ # cv2.waitKey(1) # Отображает изображение
336
 
337
  # 4. Преобразуем crop для модели
338
  # crop_input = crop[:, :, ::-1] / 255.0
 
346
  # 5. Инференс
347
  try:
348
  output = session.run(None, {'source': source_embedding, 'target': crop_input})[0][0]
349
+ # logger.debug("Model output shape: %s | Min: %s | Max: %s", output.shape, output.min(), output.max())
350
  except Exception as e:
351
+ # logger.error("Ошибка выполнения модели: %s", e)
352
  return target_img
353
 
354
  # 6. Обратная нормализация
 
366
  #### Что проверить:
367
  # `output` должен быть в диапазоне `[0..255]` и содержать лицо.
368
  # Если `output` черный — проблема в нормализации/денормализации или в самой модели.
369
+ # logger.debug("Output after denormalization: Min: %s | Max: %s", output.min(), output.max())
370
+ # cv2.imshow("Output After Denormalization", output)
371
+ # cv2.waitKey(1)
372
 
373
  # 7. ИЗМЕНЕНИЕ: Возвращаем результат 256x256 И матрицу M
374
  # Мы больше не вызываем warp_and_paste_face отсюда.
375
  # return result
376
 
377
+ # --- Безопасное преобразование перед возвратом ---
378
+ # Убедимся, что результат всегда float32 в диапазоне [0..255]
379
+ output = output.astype(np.float32)
380
+ output = np.clip(output, 0, 255)
381
+ torch.cuda.empty_cache()
382
+ gc.collect()
383
+ return output, M # Возвращаем лицо (256x256) и матрицу M
384
 
385
  def sort_by_order(face, order: str):
386
  if order == "left-right":
 
475
  try:
476
  faces_sorted = sort_by_order(face, order)
477
  selected_face = faces_sorted[face_index]
478
+ # logger.debug("Выбрано лицо: bbox=%s, landmark_5=%s, kps=%s, landmark=%s",
479
+ # selected_face.bbox,
480
+ # hasattr(selected_face, "landmark_5"),
481
+ # hasattr(selected_face, "kps"),
482
+ # hasattr(selected_face, "landmark"))
483
  return selected_face, 0
484
+ # return faces_sorted[face_index], 0
485
  # return sorted(face, key=lambda x: x.bbox[0])[face_index], 0
486
  except IndexError:
487
  return None, 0
 
503
  codeformer_weight: float = 0.5,
504
  interpolation: str = "Bicubic",
505
  ):
506
+ # >>>>> РЕШЕНИЕ: Принудительная установка уровня DEBUG <<<<<
507
+ # if logger.getEffectiveLevel() != logging.DEBUG:
508
+ # print("\n--- [ReActor Debug] Принудительная установка уровня логирования на DEBUG (10) в swap_face ---")
509
+ # logger.setLevel(logging.DEBUG)
510
 
511
+ # Проверочное сообщение (теперь оно должно появиться)
512
+ # logger.debug("--- ТЕСТ: swap_face запущена, уровень логирования DEBUG активен. ---")
513
+ # >>>>> КОНЕЦ РЕШЕНИЯ <<<<<
514
 
515
  global SOURCE_FACES, SOURCE_IMAGE_HASH, TARGET_FACES, TARGET_IMAGE_HASH
516
  result_image = target_img
 
626
  if len(source_faces_index) > 1 and source_face_idx > 0:
627
  source_face, src_wrong_gender = get_face_single(source_img, source_faces, face_index=source_faces_index[source_face_idx], gender_source=gender_source, order=faces_order[1])
628
  source_face_idx += 1
629
+
630
+ # очистка кэша и памяти перед каждым Hyperswap вызовом
631
+ torch.cuda.empty_cache()
632
+ gc.collect()
633
+ SOURCE_FACES = None
634
+ TARGET_FACES = None
635
 
636
  if source_face is not None and src_wrong_gender == 0:
637
  target_face, wrong_gender = get_face_single(target_img, target_faces, face_index=face_num, gender_target=gender_target, order=faces_order[0])
638
  if target_face is not None and wrong_gender == 0:
639
  logger.status(f"Swapping...")
640
  if "hyperswap" in model:
641
+ # logger.status(f"Swapping with Hyperswap...")
642
  swapped_face_256, M = run_hyperswap(face_swapper, source_face, target_face, result)
643
  if swapped_face_256 is not None:
644
  result = paste_back(result, swapped_face_256, M, crop_size=256)
 
824
  logger.status(f'Source Faces must have no entries (default=0), one entry, or same number of entries as target faces.')
825
  elif source_face is not None:
826
  results = target_imgs
827
+
828
+ # Определяем путь к модели в зависимости от типа
829
+ if "inswapper" in model:
830
+ model_path = os.path.join(insightface_path, model)
831
+ elif "reswapper" in model:
832
+ model_path = os.path.join(reswapper_path, model)
833
+ elif "hyperswap" in model:
834
+ model_path = os.path.join(hyperswap_path, model)
835
+ else:
836
+ model_path = os.path.join(insightface_path, model)
837
+
838
  face_swapper = getFaceSwapModel(model_path)
839
 
840
  source_face_idx = 0
 
858
  target_face_single, wrong_gender = get_face_single(target_img, target_face, face_index=face_num, gender_target=gender_target, order=faces_order[0])
859
  if target_face_single is not None and wrong_gender == 0:
860
  result = target_img
861
+
862
+ # Обработка в зависимости от типа модели
863
+ if "hyperswap" in model:
864
+ # Для Hyperswap используем специальную функцию
865
+ swapped_face_256, M = run_hyperswap(face_swapper, source_face, target_face_single, result)
866
+ if swapped_face_256 is not None:
867
+ result = paste_back(result, swapped_face_256, M, crop_size=256)
868
+ elif face_boost_enabled:
869
  logger.status(f"Face Boost is enabled")
870
  bgr_fake, M = face_swapper.get(target_img, target_face_single, source_face, paste_back=False)
871
  bgr_fake, scale = restorer.get_restored_face(bgr_fake, face_restore_model, face_restore_visibility, codeformer_weight, interpolation)
872
  M *= scale
873
  result = swapper.in_swap(target_img, bgr_fake, M)
874
  else:
875
+ # Для остальных моделей используем метод get()
876
  result = face_swapper.get(target_img, target_face_single, source_face)
877
+
878
  results[i] = result
879
  pbar.update(1)
880
  elif wrong_gender == 1: