ComfyUI Node

VS Mask Crop

Give the glass neck its own generation budget

By andrewclass1·Created 4 days ago·Updated 4 days ago· 0
VS Mask Crop
  • image
  • mask
  • image
  • mask
  • crop
◄padding_px96►
◄target_long_side1024►

The neck of a bottle on a 4096-tall canvas might be 200 pixels of actual glass. Ask Flux Fill to regenerate that in place on the full frame and the model gets a 200-pixel-tall problem with 4096 pixels of irrelevant context around it - it will do something, and what it does will be soft. VS Mask Crop takes the masked region, pads it, and resizes it up so the long side lands at a resolution the model actually has pixels for. VS Mask Stitch puts the result back. It's the same insight as the crop-and-stitch pattern that took over inpainting in 2026, applied to one specific job.

What it does

It measures the extent of your mask (threshold 0.01, ignoring rows and columns with no real coverage), expands the box by padding_px in each direction, clamps to the image, crops, then resizes so the crop's long side equals target_long_side - rounding the result to a multiple of 16, which is what most diffusion models want. You get back the cropped image, the cropped mask, and a crop output.

That third output is a custom type, VS_CROP. It's a small dictionary holding the box coordinates and the original image size, and - this is the bit that catches people - it only means anything to VS Mask Stitch in the same pack. You can't inspect it, preview it, or feed it to a core node. It's a receipt.

The defaults are sensible for this pipeline: padding_px 96 gives the model context on all sides without dragging in half the bottle, and target_long_side 1024 is the working resolution of most inpaint models. On a tall, narrow crop - which is exactly what a glass band is - the short side ends up small, and Flux Fill will cope; that's still a huge improvement over the alternative.

Why crop at all

Three real reasons, none of them theoretical:

  • Detail budget. You're spending the model's native resolution on the region you actually care about instead of on the whole frame. This is the only way to get high-frequency detail into a small region.
  • Speed. Sampling a 1024 crop is far cheaper than sampling a 4096 frame.
  • Containment. The model can only change pixels inside the crop. Rotate a bottle's reflections in a 300-pixel window and the rest of the image is untouched by construction.

Scale consistency is the price. A crop that's been upscaled 6× to reach 1024 is now a different apparent scale than the surrounding pixels, and if the stitched result is seam-free but slightly too sharp, that's why.

Install

Manager → VS Glass Matte. Or:

cd ComfyUI/custom_nodes
git clone https://github.com/andrewclass1/comfyui-vs-glassmatte
# restart ComfyUI

Torch and numpy, no dependencies declared, no weights.

Where people get burned

VS_CROP is only valid for the run that made it. It holds absolute pixel coordinates and the original image dimensions. If you change padding_px or the canvas size and then re-run only the downstream half of the graph, the receipt lies and VS Mask Stitch pastes the patch into the wrong place - or resizes it to a box from a different frame. ComfyUI's cache will happily serve you a stale crop if nothing upstream of the crop node changed, so if you're iterating on padding, make sure the whole chain re-executes (or just re-queue the whole graph).

Second: padding_px at 0 means the crop is exactly the mask extent, and a mask that touches the frame edge gives the model no context at all. You'll get a patch with hard edges and a visible seam. Keep some padding.

Third, and it's the one that wastes the most time: if the mask is empty, this node throws. The error text points upstream (check the BiRefNet / alpha input) because an empty mask almost always means the segmentation failed or the plate/glass band order got swapped. Read it as "your mask source is broken", not "this node is broken".

CategoryView Source/Glass Matte

Inputs (4)

NameTypeDefaultDescription
imageIMAGE—
maskMASK—
padding_pxINT960–2048—
target_long_sideINT1024256–2048—

Outputs (3)

NameTypeDescription
imageIMAGE—
maskMASK—
cropVS_CROP—