CMK Face Restore
Face Restore that is not GFPGAN — and that's the interesting part
- image
- selected_face
- mask
- image
- selected_face
- diagnostic
"Face Restore" in ComfyUI means one of two things: GFPGAN/CodeFormer, which runs a neural network over an aligned face crop, or the thing this node does. CMK Face Restore is the second kind: a mask-aware sharpening and local-contrast pass built out of OpenCV primitives. No model download, no InsightFace, no VRAM, essentially no runtime.
If you came here expecting CodeFormer, that's the first thing to fix in your head. Read the next section before you use it.
What it actually does
Given an image, a selected_face, and a mask, it applies one of three deterministic filters to the whole frame and then blends the filtered version back through your mask:
Detail(default) - mild unsharp masking plus local contrast. Fine detail from a small blur radius, mid-frequency local contrast from a large one. This is the "make the skin and eyes look a little crisper" mode.Sharpen- straight unsharp mask. Blur a copy, subtract, add the difference back scaled by strength. Classic, and it produces halos if you pushrestore_strength.Smooth- blends toward a blurred copy, which is the opposite of restoration and is genuinely useful: it's how you knock back the overcooked, over-textured look that a heavy detailer pass leaves behind.
restore_strength (default 0.65, range 0–2) scales the effect, blend (default 0.75, 0–1) caps how much of the filtered version reaches the output, and the mask decides where. So the effective alpha is mask × blend. Wire the mask output of CMK Face Mask into this and you get a soft-edged local enhancement that never touches the background.
If the mask is missing or the wrong size for the frame, the node doesn't fail: it falls back to an ellipse built from the face box (fallback_padding, default 0.25) and softens it. The log records which path it took (input_mask versus fallback_face_ellipse), which is a nice touch when you're wondering why a mask change didn't seem to matter.
Outputs: image, selected_face (pass-through, so you can chain), and a diagnostic with a changed_avg metric - the mean absolute pixel difference between input and output. If that number is ~0, your restore isn't doing anything, for reasons that are usually enabled or blend.
preview_mode (Off, Result, Difference, Comparison, Mask, default Comparison) is how you judge it. Difference amplifies the delta by 4× because the native pass is deliberately subtle - the comment says as much - and Comparison puts original and result side by side.
When to reach for it, and when not to
Reach for it as a finishing pass. After a detailer has re-rendered faces, the result is often slightly soft or slightly plastic; a Smooth at low blend, or a Detail at low strength, is a $0 fix that runs in milliseconds. The KB's post-processing lesson applies directly: don't spend a diffusion pass on work a lookup table does perfectly.
Don't reach for it to fix a face that is genuinely destroyed. It cannot invent detail. A 70-pixel face in a 1024px frame stays a smear - that's a resolution problem, and the answer is a detector plus a re-render at higher resolution, which is exactly what a detailer does. If you need actual learned restoration, install GFPGAN or CodeFormer and use the FaceProcess node, which routes to those backends.
Install
Manager: search CMK Flow, install the CMKFlow entry, restart. Manual, from the folder containing main.py:
git clone https://github.com/CMKFlow/cmk_nodes.git custom_nodes/cmk_nodes
python3 custom_nodes/cmk_nodes/scripts/install_cmk_requirements.py
Wait for CMK dependency check: OK. This node needs opencv-python and a face selection upstream; the pack's heavier dependencies (insightface, ultralytics, onnxruntime, segment-anything, nudenet==3.4.2) come along regardless because CMK installs as one unit. CMK Flow is a single-author GPL-3.0 project (Carsten Kirschner) open-sourced in July 2026, small and self-contained rather than a wrapper around other packs.
Issues worth knowing
enabled defaults to True, but a workflow saved with it off will happily pass your image through untouched while reporting success. Check changed_avg in the diagnostic if you're not sure.
Feather is baked at a fixed 4-pixel softening on an incoming mask, and the fallback ellipse uses a radius of 10, so the two paths produce slightly different softness. If you're comparing results between "I wired a mask" and "I didn't," that's part of the difference.
And be honest about the halo: Sharpen is unsharp masking, and unsharp masking at strength above about 1.0 gives you bright rims around eyes and lips. Detail at default strength is the setting the node was built around.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| selected_face | CMK_SELECTED_FACE | — | |
| mask | MASK | — | |
| enabled | BOOLEAN | true | — |
| method | COMBO | Detail | 3 options: Detail, Sharpen, Smooth |
| restore_strength | FLOAT | 0.650–2 | — |
| blend | FLOAT | 0.750–1 | — |
| fallback_padding | FLOAT | 0.250–2 | — |
| preview_mode | COMBO | Comparison | 5 options: Off, Result, Difference, Comparison, Mask |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| selected_face | CMK_SELECTED_FACE | — |
| diagnostic | CMK_DIAGNOSTIC | — |