GPU Frequency Separation
The Photoshop retoucher's trick, running on your GPU
- image
- low
- high
If you've ever watched a professional retoucher work, half their moves are frequency separation. The trick: split the image into a low layer (color, form, smooth gradients) and a high layer (pores, texture, edges), then fix each one separately. Smooth skin on the low layer without turning the face into a doll, because the texture lives on the high layer and stays untouched. It's a Photoshop staple, and people have been asking for it in ComfyUI for a long time - which is exactly the gap this pack exists to fill.
JHPixelProFrequencySeparation does it as a pure tensor op on your GPU: the low output is a Gaussian blur of the input, and high is the difference (input minus low). That's the whole mechanism, and it's why the math invariant matters so much: low + high = original, losslessly, at float32 precision. Retouch the low layer with your favorite filters, leave high alone (or add detail back), and recombine with a non-clamping add - you get the smoothed look without ever destroying texture.
The two outputs, and the trap
low- the blurred, smooth version. This is where you apply skin smoothing, color grading, dodge/burn.high- the detail layer, and here's the trap: it's centered around zero and contains negative values. If you preview it withPreviewImageyou'll see a weird, miscolored mess. That's expected, not a bug. The README says it plainly, and it's the #1 way people think this node is broken.
Reconstructing also trips people up. ComfyUI's built-in ImageBlend clamps to [0,1], which silently destroys the high-frequency info. You need a non-clamping image add to reconstruct - the pack's own README notes that an ImageAdd-style node was planned and points you to an external one. An ImageAdd from any utility pack works; just verify it doesn't clamp.
The two widget inputs you'll actually touch: radius (default 8, the Gaussian blur radius - bigger = smoother low layer, but detail layer gets more aggressive) and sigma (0.0 = auto radius/2, the Photoshop convention; override only if you know why). precision is float32 by default for lossless reconstruction; float16 is ~2× faster on GPU with a reconstruction error around 1e-3 - fine for previews, keep float32 for the final render.
Install
ComfyUI Manager → search ComfyUI-JH-PixelPro, or:
cd ComfyUI/custom_nodes
git clone https://github.com/jetthuangai/ComfyUI-JH-PixelPro.git
cd ComfyUI-JH-PixelPro
pip install -r requirements.txt
Restart ComfyUI; it lives under ComfyUI-JH-PixelPro/filters. The pack needs ComfyUI ≥ 0.43.x, Python ≥ 3.10, plus kornia, mediapipe, opencv-python-headless, and scipy from requirements.txt.
A couple of practical notes. First, this node is the perfect pre-workflow for the pack's JHPixelProHighFreqDetailMasker, which reuses the same high-pass path to build a detail-preservation mask for inpaint - so you can keep pores and eyebrows intact while the model repaints everything else. Second, don't chain the round-trip: because reconstruction goes through an add, each blur/add cycle is fine, but stacking multiple separations compounds softening. One split, retouch the middle, reconstruct. That's the whole trick, and now it runs on your GPU without leaving ComfyUI.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| radius | INT | 81–128 | Gaussian blur radius in pixels. |
| sigma | FLOAT | 0.00–50 | Sigma override. 0.0 = auto-compute radius/2 (Photoshop convention). |
| precision | COMBO | float32 | float32 = lossless reconstruction (atol 1e-5); float16 = ~2x faster on modern GPU, reconstruction error ~1e-3. 'high' may contain negative values — use ImageAdd to reconstruct, preview may look wrong. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| low | IMAGE | — |
| high | IMAGE | — |