Nodes/ComfyUI-JH-PixelPro/High-Frequency Detail Masker
ComfyUI Node

High-Frequency Detail Masker

Keep the pores and eyebrows when the model repaints the face

By jetthuangai·Created 5 months ago·Updated 4 months ago· 5
High-Frequency Detail Masker
  • image
  • mask
  • mask_detail
kernel_typelaplacian
sensitivity0.50
threshold_moderelative_percentile

Here's a workflow problem that'll feel familiar: you inpaint or upscale a face, and the model repaints the details - which means it also destroys them. Pores vanish, eyebrows turn to smooth plastic, hair strands blur into a single sheen. The usual fix is a denoise mask, but a denoise mask that says "protect everything" protects nothing. What you actually want is a mask that says "protect the texture."

That's the entire job of JHPixelProHighFreqDetailMasker. It measures high-frequency energy in the image - the stuff that carries pore texture, eyebrow strokes, fabric weave, eyelashes - and turns it into a binary detail-preservation mask. Feed that mask into a SetLatentNoiseMask, an ImageBlend, or a MaskCompose, and the AI pass keeps the detailed regions intact while the flat parts of the face get freely repainted.

How it decides what's "detail"

It runs a high-pass operator over the image and thresholds the result into a mask. Three operators are selectable via kernel_type:

  • laplacian (default): scale-invariant and isotropic - good all-rounder for texture detection.
  • sobel: directional, emphasizes edges in a specific orientation. Reach for it when you care about a particular edge family (say, hair strands running one way).
  • fs_gaussian: reuses the pack's JHPixelProFrequencySeparation high-pass path - handy when you're already splitting frequencies in the same graph.

Then sensitivity (default 0.5) decides the fraction of pixels that count as detail - it's a percentile, not a luma threshold, so the same value adapts across images with different noise floors. threshold_mode has relative_percentile (adaptive, robust - keep this) and absolute (normalized to the per-image max, more deterministic but outlier-sensitive). The optional mask input zeroes out detail outside a region - pair it with a skin mask from SAM/rembg to say "only protect detail on the skin."

Output is a single mask_detail MASK. Note: it's a mask, not an image - you'll want a MaskPreview to look at it, and it does nothing until you wire it into a consumer node.

The two moves you'll actually use

Post-AI texture protection: compose the detail mask into a SetLatentNoiseMask so the denoise pass leaves high-frequency regions alone. Or the simpler one: inpaint the face, then blend the original hair/eyelash regions back on top using the detail mask as alpha. Both are the same instinct - "fix the geometry, keep the texture" - and this node gives you the second half of that sentence.

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's under ComfyUI-JH-PixelPro/mask. The pack wants ComfyUI ≥ 0.43.x, Python ≥ 3.10, and installs kornia, mediapipe, opencv-python-headless, and scipy.

The honest caveat: sensitivity is a fraction-of-pixels control, so there's no "right" value that transfers between images - two photos with different noise floors will need different settings even if they look identical to you. That's the point of the percentile approach, but it means you'll dial it per shot. Start at 0.5, look at the mask preview, adjust. It's a fiddly knob for a real payoff: the difference between a face that got rebuilt and a face that got retouched.

CategoryComfyUI-JH-PixelPro/mask

Inputs (5)

NameTypeDefaultDescription
imageIMAGE
kernel_typeCOMBOlaplacianHigh-pass operator. 'laplacian' is scale-invariant and isotropic (default). 'sobel' is directional (emphasizes edges). 'fs_gaussian' reuses the N-01 Frequency Separation high-pass path.
sensitivityFLOAT0.500–1Fraction of pixels kept as detail. Higher = more pixels pass. 0 → empty mask, 1 → full mask. Typical retoucher dose 0.3–0.6.
threshold_modeCOMBOrelative_percentile'relative_percentile' adapts per image (robust cross-image). 'absolute' normalizes by per-image max (deterministic but more sensitive to outliers).
maskoptMASK

Outputs (1)

NameTypeDescription
mask_detailMASK