Nodes/ComfyUI-Utility-Suite/Mask to Bounding Box
ComfyUI Node

Mask to Bounding Box

Crop to the pixels that are actually on, then put them back

By tom-m-2020·Created about a month ago·Updated 7 days ago· 1
Mask to Bounding Box
  • mask
  • image_optional
  • MASK
  • IMAGE
  • x
  • y
  • width
  • height
  • bbox
  • bounding_box
◄padding0►

The single biggest quality win in inpainting is not a model, it's resolution budget. A 70-pixel face in a 1024px frame gets 70 pixels' worth of model attention and comes out a smear; crop that region, render it at 1024, and paste it back. Every detailer does exactly this under the hood, and masking-detection-detailing.md says the quiet part out loud: "All detailers are doing is zooming in on a mask, upscaling the image, and then diffusing the upscaled image to add details."

Mask to Bounding Box gives you that crop by hand. Give it a mask, get back the mask and image cropped to the mask's nonzero bounds, plus the coordinates you need to put the result back where it came from.

How it works

It measures, it doesn't blur. torch.nonzero on the mask gives the true extent of nonzero pixels; the coordinate convention is exclusive-end (x1/y1 is inside the box, x2/y2 is one past it), which is the same convention Impact-style SEGS bboxes use, so the numbers transfer without arithmetic. padding then grows the box outward and gets clipped to the canvas - so a mask touching the frame edge won't produce negative coordinates.

Three behaviours in the source that the node name doesn't advertise:

  • If you leave image_optional unwired, the node manufactures a three-channel image from the mask and returns that. You always get an IMAGE out of the IMAGE socket, even when nothing was wired in. Handy for debugging, easy to confuse with a real image.
  • If the image's H/W doesn't match the mask's, it bicubic-upscales the image to the mask's dimensions rather than failing. Center crop, common_upscale. Convenient, and a silent way to get the wrong framing.
  • It reconciles batch sizes: a shorter image batch is extended by repeating the last frame, a longer one is sliced to the mask's count.

Inputs and outputs

  • mask - required. A fully empty mask is an error, not a no-op: "Mask to Bounding Box requires at least one nonzero mask pixel." Any workflow where the mask might come back empty needs a branch in front of this.
  • padding - 0 to 4096. Start at 0 for a tight crop; add 32–128 when the crop is heading for a sampler, because a mask-plus-image crop with no margin leaves the model no context and you get the classic hard-edged "pasted on" patch.
  • image_optional - the thing you want cropped alongside the mask, usually the source photo at the same dimensions.

Outputs: MASK and IMAGE, both cropped; x, y, width, height as plain integers; and bbox (a BBOX list) plus bounding_box (a BOUNDING_BOX list) for nodes that take the newer rectangle types. The integers are the important ones - x/y are what you feed to ImageCompositeMasked (with x, y and resize_source off) to paste the refined crop back, and what a crop-and-stitch pair would take if it accepted loose ints.

The workflow it's built for

Detect or paint a mask → Mask to Bounding Box → img2img with the crop and the mask at native resolution, low-ish denoise → composite back at x, y → upscale the full frame afterwards. Note the order: detail first, then upscale. Doing it the other way bakes the broken face into more pixels and costs you more render time to repair, which is the same ordering the detailing doc insists on.

Install

Manager: search ComfyUI Utility Suite (publisher tom-m) → install → restart. Manual:

cd ComfyUI/custom_nodes
git clone https://github.com/tom-m-2020/ComfyUI-Utility-Suite

No checkpoints, no downloads - the pack's only requirement is opencv-python-headless, and this node doesn't use it. It's built on ComfyUI's V3 node API, so keep ComfyUI reasonably current; on an old build the pack imports and registers nothing.

Troubleshooting

"requires at least one nonzero mask pixel." Your mask is empty at the moment of execution. Common causes: an inverted mask, a composite that masked away everything, or a detector that found nothing this frame. Guard the branch.

The crop is the right place but the paste lands wrong. Two suspects, both boring: you resized the crop between here and the composite (the coordinates no longer apply to the resized image), or you're pasting at x/y without turning off the composite's resizing option.

The crop is a giant rectangle around two small blobs. Correct behaviour. The bbox is the bounding box of all nonzero pixels, so scattered content gives one big box. Separate the regions first - Mask to Mask Batch is the pack's tool for that - and run Mask to Bounding Box per region.

CategoryUtility Suite/Mask

Inputs (3)

NameTypeDefaultDescription
maskMASK—
paddingINT00–4096—
image_optionaloptIMAGE—

Outputs (8)

NameTypeDescription
MASKMASK—
IMAGEIMAGE—
xINT—
yINT—
widthINT—
heightINT—
bboxBBOX—
bounding_boxBOUNDING_BOX—