Nodes/ComfyUI-DetailedRegionInpaint/Restore Inpaint Region
ComfyUI Node

Restore Inpaint Region

The node that makes 'nothing else moved' literally true

By ArtemKo7v·Created about 14 hours ago·Updated about 12 hours ago· 0
Restore Inpaint Region
  • original_image
  • inpainted_image
  • original_mask
  • region_data
  • image

What it's for

Restore Inpaint Region is the second half of ArtemKo7v's ComfyUI-DetailedRegionInpaint pack, and it's the half that keeps the promise. Prepare Inpaint Region cropped and enlarged the region you're fixing, your sampler repainted it, and Restore drops the repainted crop back into the original. Nothing else moves - not "nearly identical", not "close after a VAE round trip", but the same pixels, because the node copies the original tensor and writes into one rectangle of it.

That's worth more than it sounds. The loudest inpainting advice the community ever produced was composite your image after inpainting - the November 2024 post everyone quotes about how a handful of uncomposited passes turn an image to trash. The usual way you obey it is to remember to slap an ImageCompositeMasked on the end. This pair removes the remembering: the only pixels that ever touch a VAE are the crop's, so the drift that rule exists to prevent can't happen.

How it works

Four required inputs, one output, and the plumbing does the interesting part:

  1. Validate region_data: all integers, source_width/source_height matching original_image, stored crop inside the frame. Bad metadata raises instead of producing a garbage image, which I'll take.
  2. Resize inpainted_image back to the stored crop dimensions, same bicubic-with-antialias path Prepare used.
  3. Slice the crop rectangle out of original_image and original_mask, blend original * (1 - mask) + resized * mask.
  4. Write that blend into a clone of the original. Pixels outside the rectangle are the input tensor, verbatim.

Two details there change how you build the graph.

The resize means the result doesn't have to come back at crop size. Sample the crop, upscale it 1.5×, run another detail pass - Restore fits whatever you give it into the hole. Handy, and it also means a wrong-sized input fails quietly rather than throwing, so eyeball the output.

The blend uses your original mask exactly. Values from 0 to 1 are preserved for soft compositing, so a soft brush edge gives a soft blend and a half-opacity mask gives you a ghost of the original pixel at half strength. Where the mask is exactly zero the source value is kept, and the code enforces that even if your sampled crop contains NaNs in those spots - a small, thoughtful touch from someone who has debugged black-square reports.

And the assumption people most often arrive with: mask_blur from Prepare does not feather this composite. It only shapes the mask the sampler sees. Want a soft seam? The softness has to be in the original mask.

The four inputs

  • original_image - the exact image you sent to Prepare. Same dimensions, batch of one, or it raises.
  • inpainted_image - the crop, not the full frame. This is the trap.
  • original_mask - the full-frame mask from your loader or mask editor. Not Prepare's output.
  • region_data - the DETAILED_REGION socket straight off Prepare.

The output is a single image: your original with the region replaced. Preview or save it - it's the finished article, no second composite step needed.

The traps

Feeding the full frame as inpainted_image. Restore has no way to tell. It resizes your whole 4K image down to crop dimensions and blends that squeezed mini-scene into the hole using the crop mask. No error, just a garbled rectangle. If your output looks like a tiny version of the entire picture pasted into the region, this is why.

"invalid region_data" / "original_image dimensions do not match region_data". Something resized or replaced the image between the two nodes - an upscale mid-chain is the usual culprit - or they're looking at different sources. The check exists because the alternative is silently pasting into the wrong place. Give both the same image.

Handing Prepare's mask to original_mask. It's crop-sized and Restore wants full dimensions, so it errors - the useful failure mode. Both inputs should come from the same loader.

Batch size 1, and channels must match. Two images in, two out is unsupported; inpainted_image must also have the same channel count as the original, which is where a 4-channel RGBA crop against a 3-channel base bites.

A visible rectangle edge. That's your mask, not the node. Restore honours exactly what you painted, and a rectangle-shaped mask makes a rectangle-shaped blend - the same reason bbox detectors seam worse than segmentation ones. Soften the mask, or derive it from something that follows the subject.

It will not outpaint. Prepare clips padding to the source image, so there's no canvas extension in this pack. Extending an image needs lquesada's Inpaint Crop and Stitch, which handles outpainting natively, or an instruction model given a padded canvas.

Install

ComfyUI Manager → search "ComfyUI Detailed Region Inpaint" (publisher artemko7v) → install → restart. Manual route:

cd ComfyUI/custom_nodes
git clone https://github.com/ArtemKo7v/ComfyUI-DetailedRegionInpaint
# restart ComfyUI

No models to download, no Python dependencies: pyproject.toml lists an empty dependency set and PyTorch comes from ComfyUI. The pack ships unit tests covering exactly the edge cases above - soft masks, empty masks, metadata validation, and an unchanged-image round trip - and they run without a GPU:

cd ComfyUI/custom_nodes/ComfyUI-DetailedRegionInpaint
python -m unittest discover -s tests -v

That last test is the one to notice: send Prepare's output straight into Restore with no sampling in between and you should get your input image back, pixel for pixel.

CategoryArtemKo7v/inpaint

Inputs (4)

NameTypeDefaultDescription
original_imageIMAGE—
inpainted_imageIMAGE—
original_maskMASK—
region_dataDETAILED_REGION—

Outputs (1)

NameTypeDescription
imageIMAGE—