fix: 修复 GPU 视频无声 + GFPGAN 紫色色块 #2010
@@ -526,13 +526,12 @@ def _load_musetalk_models():
|
||||
gfpgan_key = "params_ema" if "params_ema" in gfpgan_ckpt else "params"
|
||||
gfpgan_model.load_state_dict(gfpgan_ckpt[gfpgan_key], strict=True)
|
||||
gfpgan_model.eval()
|
||||
if Config.use_float16:
|
||||
gfpgan_model = gfpgan_model.half()
|
||||
# GFPGAN 始终使用 FP32 推理,避免 FP16 色偏导致紫/灰色块
|
||||
gfpgan_model = gfpgan_model.to(device)
|
||||
del gfpgan_ckpt
|
||||
_gfpgan_loaded = True
|
||||
_gfpgan_load_error = None
|
||||
logger.info("GFPGAN 加载完成 (FP16=%s)", Config.use_float16)
|
||||
logger.info("GFPGAN 加载完成 (FP32,避免色偏)")
|
||||
else:
|
||||
_gfpgan_loaded = False
|
||||
_gfpgan_load_error = f"模型文件不存在: {gfpgan_path}"
|
||||
@@ -920,25 +919,35 @@ def _run_inference(
|
||||
_ff_proc.stdin.write(ori_frame.tobytes())
|
||||
continue
|
||||
|
||||
# GFPGAN 人脸超分增强
|
||||
# GFPGAN 人脸超分增强(FP32 + 色彩校正,避免 FP16 色偏)
|
||||
if gfpgan_enhancer is not None:
|
||||
try:
|
||||
_fh, _fw = res_frame_resized.shape[:2]
|
||||
_face_up = cv2.resize(res_frame_resized, (512, 512),
|
||||
interpolation=cv2.INTER_LANCZOS4)
|
||||
# 保存原始人脸区域用于色彩校正
|
||||
_face_original_bgr = _face_up.copy()
|
||||
_face_rgb = cv2.cvtColor(_face_up, cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0
|
||||
_face_t = torch.from_numpy(_face_rgb.transpose(2,0,1)).unsqueeze(0)
|
||||
# GFPGAN 始终 FP32,避免 FP16 精度导致色偏;归一化到 [-1, 1]
|
||||
_face_t = ((_face_t - 0.5) / 0.5).to(device)
|
||||
if Config.use_float16:
|
||||
_face_t = _face_t.half()
|
||||
with torch.no_grad():
|
||||
_out = gfpgan_enhancer(_face_t, return_rgb=False, weight=0.5)[0]
|
||||
_out = gfpgan_enhancer(_face_t, return_rgb=False, weight=0.35)[0]
|
||||
_out = _out.squeeze(0).float().cpu().clamp_(-1,1)
|
||||
_out = ((_out + 1)/2*255).numpy().transpose(1,2,0)
|
||||
_out_bgr = cv2.cvtColor(_out.astype(np.uint8), cv2.COLOR_RGB2BGR)
|
||||
|
||||
# 色彩校正:将增强结果的均值/标准差对齐到原始人脸,消除色调偏移
|
||||
_orig_mean = _face_original_bgr.mean(axis=(0, 1))
|
||||
_orig_std = _face_original_bgr.std(axis=(0, 1)) + 1e-6
|
||||
_enh_mean = _out_bgr.mean(axis=(0, 1))
|
||||
_enh_std = _out_bgr.std(axis=(0, 1)) + 1e-6
|
||||
_out_bgr = ((_out_bgr.astype(np.float32) - _enh_mean) * (_orig_std / _enh_std) + _orig_mean)
|
||||
_out_bgr = np.clip(_out_bgr, 0, 255).astype(np.uint8)
|
||||
|
||||
res_frame_resized = cv2.resize(_out_bgr, (_fw, _fh),
|
||||
interpolation=cv2.INTER_LANCZOS4)
|
||||
del _face_t, _out, _out_bgr
|
||||
del _face_t, _out, _out_bgr, _face_original_bgr
|
||||
except Exception as _gfpgan_err:
|
||||
logger.warning("GFPGAN 增强失败(帧 %d),使用原图: %s", i, _gfpgan_err)
|
||||
|
||||
@@ -985,7 +994,7 @@ def _run_inference(
|
||||
if video_downsampled:
|
||||
logger.info("输入视频 %.1f fps,降帧至 %.1f fps 推理后直接输出(不做插帧还原)", original_fps, inference_fps)
|
||||
|
||||
shutil.copy2(str(final_video), str(output_path))
|
||||
_mux_video_with_audio(final_video, audio_path, output_path)
|
||||
|
||||
try:
|
||||
torch.cuda.empty_cache()
|
||||
|
||||
Reference in New Issue
Block a user