Nodes/ComfyUI-Portrait-Maker/ReplaceBoxImg PM
ComfyUI Node

ReplaceBoxImg PM

Paste a face crop back onto the photo — ReplaceBoxImg PM

By THtianhao·Created 3 years ago·Updated 2 years ago· 201
ReplaceBoxImg PM
  • origin_image
  • box_area
  • replace_image
  • IMAGE

Every face pipeline has the same final step in disguise: you generated a new face in a crop, and now you have to get it back onto the original photo without re-generating the whole image. ReplaceBoxImg PM is that step - it takes an image, a rectangle, and a replacement image, and overwrites the rectangle with the replacement. No blending, no alpha, no magic. Just paste, exactly where the box says.

This is the pack's "put the face back" node, and in the shipped EasyPhoto workflow it appears multiple times: after FaceFusion merges a face and after the generated crop comes out of the sampler, the crop gets written back into the original portrait at the detected face location. Understand this node and the whole EasyPhoto graph suddenly reads clearly.

How it works

The box defines a rectangle as (x1, y1, x2, y2) - left, top, right, bottom - and the node does a plain tensor slice-assignment:

origin_image[:, y1:y2, x1:x2, :] = replace_image

The box_area (BOX) input is the interesting one because BOX isn't a native ComfyUI type - it comes from this pack's own face nodes. PM_RetinaFace outputs a crop_box for every detected face, and PM_ExpandMaskBox will widen that box if you want a bit more context around the face. Wire either of those in and you're done. The exact dimensions matter, which brings us to the constraint.

The one requirement that bites

The replacement image must exactly match the box's width × height - the README says it in so many words ("ensure the resolution matches box_area"), and the code will throw a shape error or quietly produce garbage if it doesn't. Nothing resizes for you. The common pattern is to run the replacement through PM_ImageResizeTarget, feeding it the box's width and height pulled from PM_GetImageInfo or computed from the box values. Or just make sure whatever generated your face crop was set to the same size as the detection box in the first place.

Output and wiring

Output is a single IMAGE: the original with the region replaced. Everything else in the frame stays untouched, which is the whole point - the background, lighting, and body all keep their original pixels.

Two practical notes. First, this is a hard-edged paste: the seam is visible at the box boundary unless you've expanded the box a little and are pasting a crop with some context, or you follow up with color matching (the pack has PM_ColorTransfer / PM_SuperColorTransfer for exactly that). Second, for the face-swap use case this is the "post-process" half of the story - the identity-preservation logic (IP-Adapter, FaceID, InstantID) lives upstream in the graph; this node just handles the final compositing.

Installing

Via ComfyUI Manager (search "ComfyUI-Portrait-Maker") or:

cd ComfyUI/custom_nodes
git clone https://github.com/THtianhao/ComfyUI-Portrait-Maker.git

then restart. The usual pack caveats apply: first launch downloads the full EasyPhoto model set with no hash verification, and the requirements (modelscope, tensorflow, insightface, diffusers==0.18.2) are heavy. None of that matters for this specific node, but it's the price of admission.

Common issues

The almost universal failure is a resolution mismatch - crop doesn't match box, and you get a tensor shape error or a stretched-looking paste. If the paste looks right but has harsh edges, that's not a bug, it's the node working as designed; add box expansion or color matching around it. Also note the pack's nodes appear under a "protrait" category in the menu - yes, misspelled in the code, you're not looking in the wrong place.

Categoryprotrait/model

Inputs (3)

NameTypeDefaultDescription
origin_imageIMAGE
box_areaBOX
replace_imageIMAGE

Outputs (1)

NameTypeDescription
IMAGEIMAGE