Calculate mask bound
Turn a Mask Into Crop Coordinates Your Crop Node Can Use
- mask
- INT
- INT
- INT
- INT
- INT
- INT
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 matcheswidth = 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:
min_col- left xmin_row- top ywidth(max_col − min_col)height(max_row − min_row)max_col- right x2max_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.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| mask | MASK | — | |
| padding | INT | 0 | — |
| ratio | FLOAT | 1.00.7–1.5 | — |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| INT | INT | — |
| INT | INT | — |
| INT | INT | — |
| INT | INT | — |
| INT | INT | — |
| INT | INT | — |