🖼️ NL Fit Frame
Stop hand-rolling crop math — fit your subject to the frame
- image
- mask
- image
- mask
- image_info_json
- fit_frame_json
NL Fit Frame is the "framing" utility from NOLABEL-Nodes, and it solves a boring problem that eats real time: you've got an image or a sequence where the subject is floating in empty space, and you need it cropped and centered on a consistent frame before feeding it downstream. It detects the bounds of your subject - from a mask if you have one, or by analyzing the image's background - then crops or fits it into the frame with a configurable margin.
Where this shines is batch work. The canonical use is video: you extract a moving subject, and every frame's bounds are slightly different. If you crop each frame to its own bounds, the subject visibly jumps around. That's exactly what bounds_mode is for.
How it works
Two decisions drive everything:
mode-fitorcrop.fitscales the subject down to fit inside the frame with border;cropscales it up to fill the frame, cropping the overflow. Themargin_percentbecomes padding in fit mode or a safety border in crop mode.bounds_mode-per_frameorbatch_union. Per-frame is fine for stills. For a sequence,batch_unioncomputes one bounding box across the whole batch so the subject stays rock-steady instead of bouncing.
When you don't supply a mask, it does background detection on the image itself: mask_threshold is the mask value above which a pixel counts as "subject," and background_tolerance controls how strict the solid-background detection is (i.e., how much border variation it tolerates before deciding the background isn't flat). Plug in an actual mask and it takes priority - that's the more reliable path for anything that isn't shot against a clean background.
Inputs: image (a still or sequence), optional mask, and image_info_json to keep the color metadata alive. Outputs: the reframed image, the corresponding mask, the passthrough image_info_json, and fit_frame_json - a string describing the detected framing, which is genuinely handy when you're debugging why a crop went sideways.
Install and gotchas
It's part of the ComfyUI-NL_Nodes pack, so the install is the shared one:
cd ComfyUI/custom_nodes
git clone https://github.com/NOLABEL-VFX/ComfyUI-NL_Nodes
or ComfyUI Manager → search "ComfyUI-NL_Nodes". Restart, and the node lives under NOLABEL/Utilities. Nothing heavy here - no models to download, no ffmpeg dependency; it's pure tensor math.
The trap to watch: forgetting bounds_mode for sequences. Leave it on per_frame and your "steadied" footage will be steadier than you wanted in the worst way. Also, fit_frame_json is there for a reason - if a crop looks off, inspect it before you blame the node. For stills with a messy background, don't fight the background detection; generate a rough mask and plug it in. It costs one extra node and saves a lot of fiddling.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| mode | COMBO | fit | 2 options: fit, crop |
| bounds_mode | COMBO | per_frame | 2 options: per_frame, batch_union |
| margin_percent | FLOAT | 5.00–100 | Crop padding or final-frame border, as a percentage. |
| mask_threshold | FLOAT | 0.0100–1 | Mask value above which a pixel counts as object. |
| background_tolerance | FLOAT | 0.0200–10 | Maximum border variation for solid-background detection. |
| imageopt | IMAGE | Image or image sequence to frame. | |
| maskopt | MASK | Optional object mask; takes priority over image-background detection. | |
| image_info_jsonopt | STRING | Optional serialized image metadata to pass through unchanged. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| mask | MASK | — |
| image_info_json | STRING | — |
| fit_frame_json | STRING | — |