Nodes/MaskVidExperiments/MVEx Subject Crop (Advanced)
ComfyUI Node

MVEx Subject Crop (Advanced)

Subject Crop, but Every Internal Dial Is Now Yours

By drozbay·Created 28 days ago·Updated 8 days ago· 126
MVEx Subject Crop (Advanced)
  • original_images
  • masks
  • cropped_images
  • cropped_masks
  • bboxes
  • debug
mode
mask_threshold0.10
divisible_by16
upscale_megapixels0.00

The standard MVEx Subject Crop gives you three modes and a couple of high-level choices, which is the right amount of control for most clips. This is the version for when it isn't. Every dial the planner actually uses internally is exposed here, and - this is the part people miss - the standard node's padding and prefer settings are just presets over these same knobs. The Advanced defaults reproduce its "firm / stillness" cell, so switching to this node doesn't change your results until you touch something.

How it works

Under the hood, Subject Crop is not a bounding-box tracker. It's an optimizer: the planner builds a sparse linear program over the whole clip and solves for the box path that minimizes costs. Position is a decision variable, size is a decision variable, and shape is swept as a candidate set. That's the mechanism that makes the crop "hold still through mask noise" - jitter is literally the thing being minimized.

The Advanced node drops you into that cost model. Two modes, both a superset of the standard ones:

  • tracked - one constant-size crop, pixel-exact slices, shape part of the plan.
  • zoomed - position and size planned jointly, crops resampled to one output resolution.

The dials that actually matter

You don't need all fourteen knobs. The ones with real leverage:

  • movement_cost - how much the crop resists moving; the yardstick everything else trades against. Near 0 it glues itself to the subject; at 16 it approaches one static box.
  • resize_cost (zoomed only) - how much it resists changing size relative to moving. Near 0 it rescales freely; high values make it move or run large instead.
  • min_padding_allowed - the padding you always get as a fraction of the promise: 0 is fully flexible, 1 means only the image edge can break it, 0.7 is the standard "firm". Set 1 only after cleaning masks, since mask noise counts as subject.
  • seamless_loop - plans the crop path so the last frame wraps into the first. Only turn this on for clips that genuinely loop; it disables the end holds.

Two more are worth knowing because they're the "calm" controls: pad_surplus_tol keeps a roomier-than-needed crop for a few frames rather than chasing every size dip (ride out occlusions at a steady size), and end_tightening / end_tightening_window hold the crop settled at the start and end of a clip, so you don't begin and end on a drift. If a clip's first and last seconds look uneasy with the standard node, these are the dials.

Also new here: mask_threshold (default 0.1) controls what counts as subject when measuring extents - near 0 even faint feathered edges steer the crop, near 1 only solid mask cores do. Same inputs and outputs as the standard node: cropped_images, cropped_masks, bboxes for Subject Uncrop, and a debug string summarizing what the planner chose.

When to reach for it

Start on the standard node. The Advanced version earns its keep on the specific clips that fight back: a subject whose size swings wildly (set max_zoom_rate to cap rescale speed so the zoom lags smoothly), a clip where the default stillness/tightness trade is wrong, or a repetitive clip you want a seamless loop on. On an average clip it's 14 dials that reproduce the default you already had - the temptation to fiddle is the real cost.

Same install as the rest of the pack, since it's part of MaskVidExperiments - one clone gets you both. Manager search "MaskVidExperiments", or:

cd ComfyUI/custom_nodes
git clone https://github.com/drozbay/MaskVidExperiments

restart, done. No model downloads; just ComfyUI v0.15.0+ (the pack uses the newer node API). And the usual caveat: if the crop is jumpy, the first suspect is your masks, not the planner - run them through Mask Cleanup before blaming the optimizer.

CategoryMaskVidExperiments

Inputs (6)

NameTypeDefaultDescription
original_imagesIMAGEVideo frames as a batch.
masksMASKSubject masks, one per frame.
modeCOMBOtracked: one constant-size crop, pixel-exact slices, its shape part of the plan. zoomed: position and size planned jointly, the shape swept as a candidate set, crops resampled to one resolution.
mask_thresholdFLOAT0.100–1Mask values above this count as subject when measuring extents. Near 0 even faint feathered edges steer the crop; near 1 only solid mask cores do.
divisible_byINT16Crop width and height are rounded up to a multiple of this.
upscale_megapixelsFLOAT0.00-16–16Upscale the cropped images/masks to this many megapixels, on the divisible_by grid, using bicubic for images and nearest exact for masks. Set to 0.0 to disable. (Use a negative value to allow scaling down as well as up.)

Outputs (4)

NameTypeDescription
cropped_imagesIMAGEConstant-size crops, one per frame.
cropped_masksMASKThe input masks cropped to the same boxes. Feed to Subject Uncrop to confine the paste to the subject.
bboxesBOUNDING_BOXOne box per frame, for Subject Uncrop.
debugSTRINGSummary of the plan: chosen shape, box sizes, movement, and how much of the padding promise was kept.