Upload reactor_swapper.py
Browse files
custom_nodes/comfyui-reactor-node/scripts/reactor_swapper.py
CHANGED
|
@@ -306,17 +306,13 @@ def run_hyperswap(session, source_face, target_face, target_img):
|
|
| 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` или бесконечности.
|
| 311 |
-
# Если матрица нулевая или искаженная — проблема в точках `target_landmarks_5`.
|
| 312 |
-
|
| 313 |
# Применяем аффинное преобразование с новой матрицей M
|
| 314 |
crop = cv2.warpAffine(target_img, M, (256, 256), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REFLECT)
|
| 315 |
|
| 316 |
# Визуализация crop перед инференсом
|
| 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) # Отображает изображение
|
|
@@ -338,30 +334,44 @@ def run_hyperswap(session, source_face, target_face, target_img):
|
|
| 338 |
logger.error("Ошибка выполнения модели: %s", e)
|
| 339 |
return target_img
|
| 340 |
|
| 341 |
-
#
|
| 342 |
-
#
|
| 343 |
-
#
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 349 |
output = output.transpose(1, 2, 0) # CHW -> HWC
|
| 350 |
-
output = output[:, :, ::-1] #
|
| 351 |
|
| 352 |
# Визуализация после денормализации
|
| 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.
|
| 361 |
# Мы больше не вызываем warp_and_paste_face отсюда.
|
| 362 |
# return result
|
| 363 |
|
| 364 |
-
return output, M
|
| 365 |
|
| 366 |
def sort_by_order(face, order: str):
|
| 367 |
if order == "left-right":
|
|
|
|
| 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 |
# Применяем аффинное преобразование с новой матрицей M
|
| 310 |
crop = cv2.warpAffine(target_img, M, (256, 256), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REFLECT)
|
| 311 |
|
| 312 |
# Визуализация crop перед инференсом
|
| 313 |
#### Что проверить:
|
| 314 |
+
# Окно `"Crop Before Inference"` должно показывать лицо, вырезанное по аффинному преобразованию.
|
| 315 |
+
# Если изображение черное — проблема в `M` или `target_landmarks_5`.
|
| 316 |
logger.debug("Crop shape: %s | Min: %s | Max: %s", crop.shape, crop.min(), crop.max())
|
| 317 |
# cv2.imshow("Crop Before Inference", crop)
|
| 318 |
# cv2.waitKey(1) # Отображает изображение
|
|
|
|
| 334 |
logger.error("Ошибка выполнения модели: %s", e)
|
| 335 |
return target_img
|
| 336 |
|
| 337 |
+
# --- CPU FLOAT NORMALIZATION FIX ---
|
| 338 |
+
# предотвращает появление "синей кожи" и "шума" при работе на CPU
|
| 339 |
+
# (адаптировано из патча patch_cpu_fix.diff)
|
| 340 |
+
if isinstance(output, np.ndarray):
|
| 341 |
+
# устранение NaN и бесконечностей
|
| 342 |
+
output = np.nan_to_num(output, nan=0.0, posinf=255.0, neginf=0.0)
|
| 343 |
+
|
| 344 |
+
# если диапазон похож на [-1,1] → нормализуем в [0,255]
|
| 345 |
+
if output.min() < 0.0 or output.max() <= 1.5:
|
| 346 |
+
output = ((output + 1.0) / 2.0 * 255.0)
|
| 347 |
+
|
| 348 |
+
# жёсткое ограничение диапазона и тип для OpenCV
|
| 349 |
+
output = np.clip(output, 0, 255).astype(np.uint8).copy()
|
| 350 |
+
|
| 351 |
+
# защита от повторного использования буфера (inplace CPU bug)
|
| 352 |
+
try:
|
| 353 |
+
output.setflags(write=True)
|
| 354 |
+
except Exception:
|
| 355 |
+
pass
|
| 356 |
+
|
| 357 |
+
# 6. Обратная нормализация (теперь output уже uint8, просто transpose и BGR)
|
| 358 |
+
# (ваш код без изменений, но без старой денормализации)
|
| 359 |
output = output.transpose(1, 2, 0) # CHW -> HWC
|
| 360 |
+
output = output[:, :, ::-1] # RGB -> BGR (Убедитесь, что это BGR, если вход был BGR)
|
| 361 |
|
| 362 |
# Визуализация после денормализации
|
| 363 |
+
#### Что проверить:
|
| 364 |
+
# `output` должен быть в диапазоне `[0..255]` и содержать лицо.
|
| 365 |
+
# Если `output` черный — проблема в нормализации/денормализации или в самой модели.
|
| 366 |
logger.debug("Output after denormalization: Min: %s | Max: %s", output.min(), output.max())
|
| 367 |
# cv2.imshow("Output After Denormalization", output)
|
| 368 |
# cv2.waitKey(1)
|
| 369 |
|
| 370 |
+
# 7. Возвращаем результат 256x256 И матрицу M
|
| 371 |
# Мы больше не вызываем warp_and_paste_face отсюда.
|
| 372 |
# return result
|
| 373 |
|
| 374 |
+
return output, M # Возвращаем лицо (256x256) и матрицу M
|
| 375 |
|
| 376 |
def sort_by_order(face, order: str):
|
| 377 |
if order == "left-right":
|