Real-ESRGAN 在放大动漫插画、自然风景或建筑照片时表现稳定,但一旦画面中出现清晰可辨的人脸,输出结果往往令人失望:眼睛一只大一只小、牙齿排列异常、皮肤出现塑料质感或网格状伪影。这个问题在低分辨率老照片修复、监控截图增强、游戏角色立绘放大等场景中尤为突出。单纯提高迭代次数或切换 Real-ESRGAN 的版本并不能根治,因为人脸崩坏的根源在于通用超分模型对人脸结构的几何约束和纹理先验都不够强。

FaceFixer 插件正是针对这一短板设计的。它不替换 Real-ESRGAN,而是在其输出结果上叠加一道专用人脸修复工序,让背景保持 Real-ESRGAN 的锐利细节,人脸区域则由 GFPGAN 或 CodeFormer 等模型重新生成。接下来从崩坏成因、工作流程、集成方式到调优技巧逐步拆解。
为什么 Real-ESRGAN 会把人脸放大崩坏
Real-ESRGAN 的训练目标是在大量通用图像上学习从低分辨率到高分辨率的映射关系。它的生成器擅长恢复边缘、纹理和重复性结构,但人脸并不是简单的纹理集合。人眼对人脸的几何比例非常敏感,两只眼睛的间距、鼻梁的线条、嘴唇的对称性只要出现微小偏差,就会立刻被感知为“崩坏”。而通用超分模型没有专门的人脸关键点约束,在低分辨率输入下人脸区域信息严重不足,模型只能根据局部纹理猜测五官形状,于是出现了左右眼不对称、牙齿变成白色块状、瞳孔高光位置错乱等问题。
另一个重要原因是训练数据分布偏差。Real-ESRGAN 的训练集中虽然包含人像,但比例远低于风景、建筑、动物、文字等类别,而且大部分人脸样本的清晰度并不足以让模型学到精细的五官结构。相比之下,GFPGAN、CodeFormer、RestoreFormer 等专用人脸修复模型在训练时使用了大量高质量人脸数据集,并通过面部成分字典、Transformer 注意力或矢量量化编码等方式显式建模人脸先验。它们知道眼睛应该长什么样、嘴唇边缘应该如何过渡,因此在修复崩坏的人脸时表现远好于通用超分模型。
还有一个容易被忽略的因素是融合区域的处理。如果把整张图像直接交给专用人脸修复模型,背景会丢失 Real-ESRGAN 的增强效果,而如果只处理人脸区域但边缘融合不当,又会出现明显的拼接痕迹。FaceFixer 的价值就在于把“通用放大”和“专用修复”这两件事用可控制的流水线组合起来,既避免全局二次处理带来的性能损耗,也解决局部修复的边界一致性问题。
FaceFixer 插件的工作流程与核心模块
FaceFixer 的典型流水线可以拆成四个步骤:人脸检测、区域裁剪、人脸修复、羽化融合。首先使用轻量级人脸检测器在 Real-ESRGAN 的输出图像上定位所有人脸框,常见的检测器包括 YuNet、RetinaFace 和 SCRFD。检测到的框通常会向外扩展一定比例,例如上下左右各扩展 20% 到 30%,以保证额头、下巴和耳朵边缘也能被完整纳入修复范围。扩展后的框还要根据图像边界进行裁剪,避免越界。
第二步是根据扩展后的人脸框从原图中裁出人脸子图,并将子图缩放到修复模型期望的输入尺寸。GFPGAN 通常需要 512x512 的输入,CodeFormer 也类似,因此需要根据原始框的宽高比做等比缩放并填充。第三步调用人脸修复模型生成修复后的人脸子图,这一步可以选择只使用 GFPGAN 的生成结果,也可以混合 CodeFormer 和原始 Real-ESRGAN 输出,以控制修复强度。最后一步是融合,把修复后的人脸子图缩放回原始框大小,再通过羽化蒙版贴回原图。羽化蒙版的作用是让修复区域与周围背景平滑过渡,避免出现矩形边缘。
下面是一段简化后的 FaceFixer 流水线伪代码,展示了四个步骤之间的数据流:
def face_fixer_pipeline(img, detector, restorer, margin=0.3):
boxes = detector.detect(img)
if not boxes:
return img
mask = np.zeros(img.shape[:2], dtype=np.uint8)
for box in boxes:
x1, y1, x2, y2 = expand_box(box, img.shape, margin)
face_crop = img[y1:y2, x1:x2]
# 调用人脸修复模型,weight 控制修复强度
restored = restorer.enhance(face_crop, weight=0.7)
# 羽化融合回原图
img = blend_restored(img, restored, (x1, y1, x2, y2), mask)
return img
实际实现中,检测器输出的人脸框通常会附带置信度分数,低于阈值的检测结果应该丢弃,否则可能把背景中的圆形物体误判为人脸,导致错误修复。融合阶段还可以引入色彩传递算法,将修复后人脸子图的颜色分布向原图对齐,进一步降低色差。对于多人脸图像,需要逐个人脸独立处理,并注意重叠区域的处理顺序。
在 Stable Diffusion WebUI 中集成 FaceFixer
如果你使用 Stable Diffusion WebUI 进行图像放大,FaceFixer 通常以扩展脚本的形式集成。安装方式与普通扩展一致:在扩展管理界面中搜索 FaceFixer 并安装,或手动将扩展目录放入 extensions 文件夹后重启 WebUI。安装完成后,在图生图或后期处理界面会出现 FaceFixer 相关的选项,勾选启用后,它会自动在 Real-ESRGAN 放大流程结束后执行人脸修复。
常见的可调参数包括修复模型选择、修复强度、检测置信度和羽化半径。修复模型可以在 GFPGAN、CodeFormer 和 RestoreFormer 之间切换,其中 CodeFormer 对严重崩坏的人脸修复能力更强,但有时会改变人物身份特征;GFPGAN 更保守,保留原图信息更多。修复强度通常用一个 0 到 1 之间的权重控制,0 表示完全保留 Real-ESRGAN 输出,1 表示完全使用修复模型结果。建议从 0.5 到 0.7 开始尝试。
下面是一个 WebUI 扩展配置片段的示例,用于说明参数是如何组织在一起的:
facefixer: enabled: true restorer: CodeFormer weight: 0.65 confidence_threshold: 0.5 feather_radius: 8 target_size: 512 blend_mode: poisson
如果在 WebUI 中启用 FaceFixer 后没有效果,优先检查控制台日志中是否有检测器或修复模型加载失败的信息。部分扩展依赖 onnxruntime 或特定版本的 torch,需要根据扩展说明安装对应依赖。另外,处理超大分辨率图像时,建议先使用 Real-ESRGAN 放大到中等尺寸,再让人脸修复模块运行,否则 GPU 显存可能不足。可以在设置中开启“分块处理”或降低修复子图的目标尺寸来缓解。
手写 Python 脚本实现 FaceFixer 效果
如果不想依赖 WebUI 的扩展系统,也可以自己编写脚本实现同样的流水线。核心依赖包括 OpenCV、NumPy、onnxruntime 以及 GFPGAN 或 CodeFormer 的 Python 接口。检测器可以使用 OpenCV 自带的 YuNet 人脸检测模型,它基于 ONNX 格式,加载后即可在 CPU 上快速运行。修复模型则需要下载对应的预训练权重,并按照官方示例初始化。
下面是一个完整的脚本示例,它读取一张已经过 Real-ESRGAN 放大的图像,检测人脸并逐一修复,最后保存融合结果。代码中保留了关键注释,方便按需修改:
import cv2
import numpy as np
# 初始化 YuNet 检测器
detector = cv2.FaceDetectorYN.create(
"face_detection_yunet.onnx",
"",
(320, 320),
0.6,
0.3,
5000
)
# 这里用简单的占位函数代表 GFPGAN/CodeFormer 修复
def restore_face(face_img, weight=0.65):
# 实际使用时加载修复模型并推理
return face_img
def expand_box(box, img_w, img_h, margin=0.25):
x, y, w, h = box.astype(int)
mx = int(w * margin)
my = int(h * margin)
x1 = max(0, x - mx)
y1 = max(0, y - my)
x2 = min(img_w, x + w + mx)
y2 = min(img_h, y + h + my)
return x1, y1, x2, y2
def blend_face(original, restored, box, feather=8):
x1, y1, x2, y2 = box
face_w = x2 - x1
face_h = y2 - y1
restored_resized = cv2.resize(restored, (face_w, face_h))
mask = np.zeros((face_h, face_w), dtype=np.float32)
cv2.rectangle(mask, (0, 0), (face_w, face_h), 1.0, -1)
mask = cv2.GaussianBlur(mask, (feather * 2 + 1, feather * 2 + 1), 0)
roi = original[y1:y2, x1:x2].astype(np.float32)
roi = roi * (1 - mask[..., None]) + restored_resized.astype(np.float32) * mask[..., None]
original[y1:y2, x1:x2] = roi.astype(np.uint8)
def facefixer_pipeline(image_path, output_path):
img = cv2.imread(image_path)
if img is None:
raise FileNotFoundError("无法读取图像")
img_h, img_w = img.shape[:2]
detector.setInputSize((img_w, img_h))
_, faces = detector.detect(img)
if faces is None:
print("未检测到人脸,直接保存原图")
cv2.imwrite(output_path, img)
return
for face in faces:
box = face[:4]
conf = float(face[-1])
if conf < 0.5:
continue
x1, y1, x2, y2 = expand_box(box, img_w, img_h, margin=0.3)
face_crop = img[y1:y2, x1:x2]
restored_face = restore_face(face_crop, weight=0.65)
blend_face(img, restored_face, (x1, y1, x2, y2), feather=8)
cv2.imwrite(output_path, img)
print("处理完成,结果已保存至", output_path)
if __name__ == "__main__":
facefixer_pipeline("input.png", "output.png")
这段代码展示了检测、裁剪、修复、融合四个环节的最小闭环。实际项目中,restore_face 函数需要替换为具体的 GFPGAN 或 CodeFormer 推理调用,并且要注意修复模型的输入输出均为 RGB 格式,而 OpenCV 读取的图像是 BGR 格式,需要先进行通道转换。融合时使用的羽化半径越大,边缘过渡越自然,但过大会导致修复区域边缘模糊,一般设置在 4 到 12 像素之间比较合适。
效果评估与参数调优建议
评估 FaceFixer 的效果不能只看人脸是否变清晰,还要观察三个维度:五官几何是否正确、肤色和光影是否与周围一致、边缘是否有拼接感。一个好的修复结果应当让人感觉这张脸本来就是这样,而不是被单独处理过。可以把修复前后的图像放在同一画布上放大对比,重点查看眼睛轮廓、鼻翼边缘和嘴唇边缘这些高敏感区域。
调优时先从修复强度入手。如果 Real-ESRGAN 输出的人脸只是轻微模糊,没有明显几何错误,可以把 weight 设置在 0.4 到 0.5,保留更多原始纹理;如果已经出现眼睛错位、牙齿崩坏,则需要把 weight 提高到 0.7 以上,并优先选择 CodeFormer。检测置信度阈值不宜设得太高,否则会漏掉侧脸或小尺寸人脸;设得太低又容易把背景中的相似形状误检。通常 0.5 是一个安全的起点。
多人脸场景下,可以对不同尺寸的人脸使用不同的修复强度。远处的小人脸由于信息量少,修复模型容易产生身份漂移,此时应适当降低 weight 或增大羽化半径,让融合更保守。对于同一张照片中的人脸,如果修复后与真人身份差异明显,可以尝试换用 GFPGAN 或减小修复子图的输入尺寸,因为过大的输入会让模型产生更多不符合原图的细节幻觉。最后,如果显存允许,建议保留 Real-ESRGAN 的原始输出作为备份,便于对比和回退。
Real-ESRGANFaceFixer人脸修复修改时间:2026-08-19 23:17:55