Compositing: Pyramid Blend
Compositing a Face Back In Without the Rectangle Showing
- image_a
- image_b
- mask
- image
Here's the thing nobody tells you about the detect-crop-inpaint-paste-back loop. The detection and the re-render are the fun parts. The step that actually ruins the image is the paste, because a plain masked composite shows its edge the moment the two images disagree in brightness or colour - and after an inpaint pass through a VAE, they always disagree a little.
Compositing: Pyramid Blend (JHPixelProPyramidBlend) is the node you reach for when the seam shows. It's multi-band blending - the Burt-Adelson Laplacian pyramid trick that compositors have used for decades - exposed as one node with one dial.
Why not just a mask multiply
A hard alpha composite switches every frequency at the same place. So you either feather it, and the transition goes mushy and ghosts across the whole face, or you keep it tight, and you get a visible brightness step where the two images meet.
Multi-band blending splits the difference by frequency. Both images get decomposed into detail bands plus a coarse residual. Each band is blended with a mask at a different blurriness: the finest bands switch over sharply (so eyes, lashes and fabric keep their crispness and nothing doubles), while the coarse bands - the ones carrying overall brightness and colour - cross-fade over a wide region, which is what makes the step invisible. That's the entire insight, and it's why this looks better than a feathered mask even though the feather is doing "the same thing" in theory.
If you've read up on detailing workflows, you'll recognise where this sits: the loop's step four is "paste back, blending the seam," and it's the step with the least tooling and the most visible failure. This is that tool, without leaving the graph for Photoshop.
Inputs and outputs
Four required inputs, no optional ones, no surprises:
image_a- the base, kept where the mask is 0.image_b- the overlay, taken where the mask is 1.mask- white takesimage_b, black keepsimage_a. Soft values blend.levels- pyramid depth, 1 to 10, default 5.
Output: image. Same size as the inputs.
levels is the only real decision. 1 is a plain alpha composite - that's your sanity check, and a useful way to see what the pyramid is actually buying you. 4 to 6 is the working range. Higher gives a wider, softer transition, which is what you want when the two images differ a lot in exposure or colour; it's also how you get colour halos if you push it too far around a subject with hard edges. If a seam persists, go up a level. If you get bleeding at the boundary, go down.
A hard mask is fine here - the pyramid does the feathering, so you don't need to pre-blur it. What you do want is a mask that follows the real subject, which means a segmentation-style mask rather than a bounding box; a rectangle is a rectangle no matter how smoothly you blend its edges.
How it works, briefly
Laplacian pyramids for image_a and image_b via Kornia's pyrdown / pyrup, a Gaussian pyramid for the mask, each band blended as band_a × (1 − mask) + band_b × mask, then collapsed back. Two practical details worth knowing: images are replicate-padded up to a multiple of 2^(levels−1) and cropped back, so odd resolutions work; and levels is clamped automatically so the coarsest level stays at least 8 px on its short side, which is why a small crop quietly drops to fewer levels instead of erroring. All three inputs must share height and width, and a batch of 1 on any of them broadcasts against the others.
Identical inputs, an all-black mask or an all-white mask return the source unchanged - so when nothing happens, check the mask before you suspect the blend.
Install
Manager: search ComfyUI-JH-PixelPro, install, restart. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/jetthuangai/ComfyUI-JH-PixelPro.git
cd ComfyUI-JH-PixelPro
pip install -r requirements.txt
Restart, then find it under Add Node → ComfyUI-JH-PixelPro → compositing. The pack is 64 nodes by one maintainer (@jetthuangai), Apache-2.0, built on PyTorch plus Kornia - with kornia>=0.7, MediaPipe, OpenCV headless and SciPy in requirements.txt. Nothing to download for this node; there are no models involved in pyramid blending.
Common issues
No visible change at all. Mask is empty or fully white, or image_a and image_b are the same tensor (a common accident when you tap the same loader twice). Both cases pass through silently by design.
"image_a, image_b and mask spatial shapes must match". The mask is at a different size than the images. If your mask came out of a proxy-resolution node, resize it. This is the single most common wiring error in this loop.
Colour halos at the seam. Too many levels. Drop from 6 to 3 and look again - the coarse bands are cross-fading too widely.
Mushy, ghosty detail. The opposite problem: the mask is too soft and the fine bands are averaging alongside the coarse ones. Feed it a crisper cut-out shape (Mask Cleanup or an edge-aware refiner first) and keep levels moderate.
One honest note on the pack itself: there's no Reddit chatter on it at all, so you won't find a thread where someone solved your problem. What you get instead is unusually complete per-node documentation - including a "under the hood" section per node - and a claimed 800+ test suite. Read the docs before assuming it works like the compositing pack you already know.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image_a | IMAGE | Base image, kept where mask is 0. | |
| image_b | IMAGE | Overlay image, taken where mask is 1. | |
| mask | MASK | 1 takes image_b, 0 keeps image_a. | |
| levels | INT | 51–10 | Pyramid depth. Higher = wider, smoother seam. 1 = plain alpha composite. Auto-reduced on small images. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |