凤希AI - 人脸精修 · 轻量链 V2(全脸)
Fix Every Smudged Face in the Frame — Without Swapping In a Stranger
- 输入帧
- 参考图
- 处理后帧
- 处理报告
You rendered a wide shot - three people in a field, camera 20 metres back - and every face in it is a smear. A face occupying 70 pixels of a 1024px frame has no latent budget to spend, which is exactly why the detect-crop-upscale-repaint loop ("face detailer") exists.
The usual version of that loop has a side effect nobody warns beginners about: the repaint is a diffusion pass, so it invents a plausible face and you lose the person you actually rendered. FxAiFaceRestoreLiteV2 (凤希AI - 人脸精修 · 轻量链 V2(全脸)) does the same loop with the repaint swapped for a one-step generative superresolution pass, and then, if you give it reference photos, pins each face back to the identity it belongs to. "全脸" in the name means all the small faces, not just one designated protagonist.
The loop, mechanically
Detection is InsightFace's buffalo_l - the same backbone under InstantID, PuLID and every face-swap tool you've used. The pack adds ROI tracking: after the first frame it only re-detects a 2.2× crop around the previous box, which beats scanning a whole 1280×768 frame for a 43px face. It also pre-scans the clip once and caches boxes and embeddings.
Then the gate. 处理脸宽上限 defaults to 96: any detected face narrower than that gets processed, anything at or above it passes through untouched. That single number is the speed dial for the whole node - a clear face needs no repair, so don't pay for it. Set it to 0 and every face in every frame goes through.
Each face is cropped by its own width (1.5×, snapped up to 128/256/512), and the upscale factor is chosen so crop × factor lands exactly on 512 - the native training resolution of the VOSR2 superres engine. Then the reconstructed patch goes back through an ellipse mask (遮罩比例, 0.70 of face width) feathered at 羽化半径 (0.045 of the crop). Small numbers, but they're the difference between a repaired face and a visible pasted square.
Around the threshold there's a 15% hysteresis band keyed to the previous frame's box overlap: a face already being fixed has to grow to 1.15× before it stops, one already skipped has to shrink to 0.85× before it starts. Without it, a face hovering at 96px flickers - fixed, skipped, fixed - and reads as a twitch in the final video.
Identity: the swap isn't a face swap
This is the part that's easy to misread. 参考图 is optional: one image per character you want recognised. Every detected face is compared against all of them by cosine similarity, and the closest match above 身份相似度阈值 (default 0.10) is treated as that character - then swapped toward that person's own reference photo, not toward someone else. No protagonist slot; each character keeps their own face. Leave 参考图 unconnected and the node only superresolves, which is a perfectly good way to run it.
身份相似度阈值 is the one to tune from the report. Distant small faces realistically score 0.02–0.20, so 0.10 sits mid-range; drop to 0.06 or 0.04 when faces stop being written back, raise to 0.2 or 0.3 when the wrong person gets picked. 默认人物 (default 1) is a narrow fallback: one face in the frame and nothing clearing the threshold, write back reference #1 anyway.
换脸强度, 肤色回拉 and 纹理保留 clean up the swap afterwards. Skin pull-back matters more than it sounds: swap models inherit the target image's skin tone, and without pulling it back a face lit warm or dim comes out as a pale mask.
Outputs
处理后帧 is the whole batch, same order and resolution - wire it into a save node. 处理报告 is a multi-line string: frames processed, faces skipped as too clear, faces attributed per reference, plus every warning. Put it through a text preview on your first run - it's the only place the node admits it degraded.
Installing it
ComfyUI Manager, search fxai-toolkit (or 凤希), or:
cd ComfyUI/custom_nodes
git clone https://github.com/fxai666/fxai-toolkit
# restart ComfyUI
There is no requirements.txt; pyproject.toml lists no dependencies, and the pack's __init__.py pip-installs exactly soundfile and psutil on startup. Everything this node needs, you supply:
pip install insightface onnxruntime-gpuinto the same Python that runs ComfyUI (Windows portable:python_embeded\python.exe -m pip ...).buffalo_lintoComfyUI/models/insightface/models/buffalo_l/- five.onnxfiles. Without it the node falls back to downloading, which is where runs mysteriously "hang while fetching a model".- The VOSR2 bundle into
ComfyUI/models/vosr2/VOSR2/:args.json,checkpoints/ema_model.safetensors, aQwen-Image-vae-2d/folder,dinov2_vitl14.safetensors. - For the identity pass,
inswapper_128.onnxor preferablyhyperswap_1a_256.onnxinComfyUI/models/insightface/models/- the pack prefers the 256 model when both exist. Optional; the node runs without it.
Where people get burned
Missing VOSR2 keys don't error, they downgrade. If the bundle is absent or VRAM runs out, you don't get a crash - you get Lanczos interpolation, i.e. bigger blur. Flip 超分引擎 to 纯插值 (Lanczos) deliberately if you want that; if you didn't ask for it, read the report line before blaming the model.
It needs roughly 6.2 GiB free for VOSR2 + swap model + detector together, and only frees other models when memory is actually short - awkward if you launch with --disable-smart-memory, where ComfyUI won't unload your video sampler.
ONNX on CPU without saying so. If onnxruntime-gpu can't load cudnn64_9.dll, detection silently drops to CPU: the console prints 人脸检测 GPU 不可用,退回 CPU and per-frame time triples. Environment problem, not a settings problem.
Faces under 16px are ignored entirely, 换脸脸宽上限 is clamped to 处理脸宽上限 if you set it higher, and on Windows 显卡编号 above 0 won't take effect unless ComfyUI starts with --cuda-device all.
One last thing worth knowing before you put this in anything commercial: the InsightFace models are non-commercial, and HyperSwap ships under a research licence. Same trap as every other identity pipeline in the ecosystem - the code is permissive, the weights are not.
Inputs (17)
| Name | Type | Default | Description |
|---|---|---|---|
| 输入帧 | IMAGE | — | |
| 处理脸宽上限 | INT | 960–4096 | **唯一的总闸**:脸宽 ≥ 这个值就跳过,不裁、不超分、不贴回,原样输出。默认 96 —— 本来清楚的脸不去动它,省掉大部分算力。 0 = 全片每张脸都处理。 V2 是「所有小于这个值的脸都修」,不是只修一张。 阈值附近有 15% 滞回:已经在修的胖到 ×1.15 才停,已经跳过的瘦到 ×0.85 才开修,防止脸在阈值上下抖时闪帧。 |
| 裁切框边长 | INT | 00–512 | 裁切框边长(原图尺度)。**0 = 自动**:每张脸按自己的宽度算,取 1.5 倍脸宽并向上对齐到 128/256/512,超分倍数自动配套,保证 裁切框 × 超分倍数 正好 512(VOSR2 训练分辨率)。 手填时所有脸共用一个框,只允许 128/256/512。 |
| 超分倍数 | INT | 41–4 | 超分倍数。有效放大倍数 = 512 / 裁切框边长。裁切框边长 = 0(自动)时由程序配套设定,这一项不生效。 |
| 超分引擎 | COMBO | 自研超分 (VOSR2) | 自研超分 (VOSR2) = 生成式超分,能把糊掉的五官重建出来; 纯插值 (Lanczos) = 只放大不救细节(没装模型时用)。 |
| 遮罩比例 | FLOAT | 0.700.4–1.2 | 椭圆 mask 相对脸宽的比例。脸大就调小,贴回区域收到脸部。 |
| 羽化半径 | FLOAT | 0.0450–0.2 | 羽化半径(相对裁切框)。调大接缝更软,但会削弱修脸力度。 |
| 身份相似度阈值 | FLOAT | 0.100.02–0.8 | **认人判定线**:每帧最像参考图的那张脸,相似度 ≥ 这个值才写回。 **它不决定修不修** —— 修不修只看 处理脸宽上限。 远景小脸(35~50px)与参考图的相似度常在 0.02~0.20,默认 0.10。 漏写回往下调 0.06 / 0.04;认错人往上调 0.20 / 0.30。 **认不出时**:整帧只有一张脸、又没过线,按 默认人物 那张写回。 没接参考图时这一项不生效。 |
| 默认人物 | INT | 10–15 | **认不出是谁的时候,当成第几张参考图里那个人。** 正常流程是每张脸跟所有参考图比一次、最像谁就归谁,用不到这一项。 只有「整帧一张脸、又一张都没过判定线」时才拿它写回。 1 = 第 1 张(默认),2 = 第 2 张,以此类推。 0 = 不写回,认不出就只超分。 多人同框不启用 —— 认不出谁是谁的时候贴上去就是贴错人。 参考图里有多张脸时,取面积最大的那张。 |
| 换脸脸宽上限 | INT | 960–4096 | **换脸的分界线**:脸宽小于它才换,大于它只超分。默认 96。 ⚠️ 必须 ≤ 处理脸宽上限,否则自动按处理上限算。 判据:46px 脸 纯超分 +12.7% / 换脸 **+15.1%**,换脸占优; 121px 脸 纯超分 **+31.6%** / 换脸 −27.1%,换脸毁图。 脸 ≤85px 走 128 裁切框、放大 4 倍,超分信息不足; 脸 >85px 走 256 裁切框、放大 2 倍,超分自身够用。 0 = 不判断,脸多大都换(不推荐)。 |
| 换脸强度 | FLOAT | 1.000–1 | 换脸结果的合成强度。1.0 = 完全用换脸结果;0.7 左右 = 与超分结果混合,身份弱一点但更贴原画面。 |
| 肤色回拉 | FLOAT | 0.600–1 | 把换脸后的肤色拉回原脸。换脸模型的肤色跟着目标图走,暗光/暖光镜头不拉会变成一张发白的面具。 |
| 纹理保留 | FLOAT | 0.900–1 | 把超分救回来的高频(皮肤质感、发丝)叠回换脸结果。默认 0.9。 换脸输出的信息量有上限(256 模型 256 空间 / 128 模型 128 空间),不叠会明显偏糊。 判据(60px 脸):纹理 0.5 比纯超分低 7.5%,0.9 高 50%; 80px:0.5 低 12.4%,0.9 高 33.8%。 |
| 随机种子 | INT | 420–2147483647 | — |
| 批大小 | INT | 41–32 | 一次送进超分引擎的裁切块数量。4 最快;batch 8 会因显存挤占掉速。 |
| 显卡编号 | INT | 00–7 | 用第几张显卡。 ⚠️ ComfyUI 在 Windows 上默认把 CUDA_VISIBLE_DEVICES 锁成 0,填 1 会自动改用 0 号卡并给出提示。真想用第二张,启动时加 --cuda-device all。 |
| 参考图opt | IMAGE | **认人用**:接一张 = 一个角色;接多张 = 多个角色,各换各的。 **不影响修不修** —— 所有 <处理脸宽上限 的脸都会超分; 它决定「这张脸算哪个角色」,也就是换成谁的脸。 不接也能正常跑:全部只超分,不换脸。 |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| 处理后帧 | IMAGE | — |
| 处理报告 | STRING | — |