Nodes/ComfyUI-off-suite/Calculate mask bound
ComfyUI Node

Calculate mask bound

Turn a Mask Into Crop Coordinates Your Crop Node Can Use

By Off-Live·Created 3 years ago·Updated 2 years ago· 0
Calculate mask bound
  • mask
  • INT
  • INT
  • INT
  • INT
  • INT
  • INT
padding0
ratio1.0

You've got a mask and you want to crop to whatever's inside it. That's a bounding-box computation, and normally you'd either eyeball coordinates or write a tiny Python node. This node does it for you: find the nonzero region of the mask, pad it, force it to an aspect ratio, and hand back six integers you can feed straight into a crop node.

It's part of ComfyUI-off-suite, Off-Live's grab-bag of mask and face utilities. Not famous, not flashy, but it's exactly the kind of plumbing that saves you from mathing out crop regions by hand.

What you plug in

  • mask - any MASK. The node finds where the mask is nonzero (np.where(mask[0])) and computes the bounding box around it. Note it looks at the first frame of the batch.
  • padding - extra pixels added around the bound, default 0. Throw in 16–32 when you're cropping for an inpaint pass and want context around the object, not a skin-tight box.
  • ratio - the width-to-height ratio of the resulting crop, default 1.0 (square), range 0.7–1.5. It takes the larger of the box's width or height, scales so the box matches width = height × ratio, and re-centers.

What comes out - and the order matters

Six INT outputs, and the names are generic so you need to remember the order: (x, y, width, height, x2, y2). Specifically the code returns:

  1. min_col - left x
  2. min_row - top y
  3. width (max_col − min_col)
  4. height (max_row − min_row)
  5. max_col - right x2
  6. max_row - bottom y2

So the first two are the top-left corner, the middle two are the size, and the last two are the bottom-right corner. The top-left + width/height pair is what most crop nodes want; the x2/y2 pair is what you'd use with CROP_DATA-style workflows or a second crop node. Confusingly, a node named "calculate mask bound" that returns six ints with no names is exactly the sort of thing that gets wired wrong once and memorized forever after.

Where it fits

The classic use is mask-driven inpainting: mask a face or an object, run this to get a padded, ratio-correct box, crop to it, do your inpaint or detail pass, paste back. The ratio control matters there because diffusion models are happiest at certain aspect ratios - forcing the crop to 1:1 before a VAE encode is the difference between clean output and a dimension headache. It also plays nice with the rest of off-suite's mask family (Safe Mask to Image for previews, VAE Encode For Inpaint V2 for the encode itself).

Gotchas

  • Empty mask = crash. np.where(mask[0]) on an all-black mask finds no indices, and .min() on an empty array throws. Don't feed it a fully-empty mask without guarding upstream.
  • It only inspects mask[0], so a batched mask gets its box computed from the first frame only.
  • The boundary clamping at the edges can shift the box (it repositions rather than clips), which is usually the right behavior - just don't be surprised when a crop near the image edge isn't exactly centered on the original box.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/Off-Live/ComfyUI-off-suite
# or: ComfyUI Manager → search "ComfyUI-off-suite"

No extra dependencies, no models. Part of the same stable-but-frozen pack - quiet since mid-2024, but for a bounding-box helper that's genuinely fine.

CategoryOFF

Inputs (3)

NameTypeDefaultDescription
maskMASK
paddingINT0
ratioFLOAT1.00.7–1.5

Outputs (6)

NameTypeDescription
INTINT
INTINT
INTINT
INTINT
INTINT
INTINT