Smart Image Crop
That 200px face deserves 1024px of the model's attention
- image
- mask
- crop_image
- crop_mask
- stitcher
- preview_overlay
- info
Why crop at all
The argument in the KB's inpainting doc is the one that matters: whole-frame editing can't spend generation budget locally. A face occupying 200 pixels of a 2048px render has 200 pixels' worth of latent to work with, no matter how good the checkpoint is. Crop it out, render the crop at 1024, paste it back, and that face gets the model's full attention. That's the loop every automatic detailer runs - detect, crop, re-render, paste back - and Smart Image Crop is the middle two steps for stills.
It's a port of ComfyUI-Smart-Image-Crop-and-Stitch, itself a rework of lquesada's Inpaint-CropAndStitch, and it does four things the older lineage doesn't, all four of which come from real complaints: a very light grey mask still counts as a mask, holes get filled, the crop is taken at the target aspect rather than cropped-then-squashed, and dimensions snap to a VAE-friendly multiple. If you already use Inpaint Crop Pro (MEC) from this same pack, that's the video-aware sibling with a canvas; this is the stills path.
What it does, step by step
It takes the tight bounding box of everything above 1/255 in the mask (a faint mask is still a mask - testing for exactly 1.0 throws away real selections and crops the whole frame, which looks like the node ignoring you), grows the mask by mask_grow_pixels before measuring, fills enclosed holes if patch_mask_holes is on, widens the box to the output aspect, snaps the output size to force_divisibility, and resamples. Up-scaling uses bicubic, down-scaling uses area, which is the correct pair and not something every crop node bothers with.
The crop window is centred on the region and may run past the frame edge - where it does, the edge pixel is repeated, and the stitcher records the pad offset so the stitch can undo it. A crop entirely outside the frame comes back blank instead of erroring.
Inputs
- image, mask - required. Faint masks count; a genuinely empty one triggers
no_mask_mode. - resolution_mode -
Automatic(size derived from the crop, clamped) orManual(usemanual_width/manual_heightexactly). - min_resolution (default 768) and max_resolution (default 2048) - the whole point. A crop whose short side is below
min_resolutionis scaled up; a long side abovemax_resolutionis scaled down. Set them the other way round and the node refuses with a clear error rather than silently picking one. - manual_width / manual_height - Manual mode only.
- mask_grow_pixels - default 32, and it can be negative to shrink. This is your "how much context around the subject does the model get" control. Zero gives a tight cut-out, which is how you get the model painting a fresh background around your subject's chin.
- patch_mask_holes - leave this on. A subject mask with holes regenerates those holes as background: the hole-in-the-face result. The info string tells you which backend did the filling; without OpenCV installed it degrades to a torch flood fill that gives up on holes wider than ~128px, and it says so.
- no_mask_mode -
Bypass(default),Resize Full Image,Crop Full Image. Bypass is the right default for a batch where only some frames have a mask. - force_divisibility - 8/16/32/64/112/128/256, default 128. A VAE silently pads anything that isn't a multiple of 8 (and 112 for some architectures), which shifts your crop a few pixels and shows up later as a misaligned stitch. Snap it here, deliberately, rather than discovering it at the seam. 112 is in the list for a reason - that's the Qwen-Image / edit-model multiple the KB's inpainting doc calls out.
Outputs
crop_image and crop_mask (the crop and its mask, same size, ready for any sampler), stitcher (a STITCHER typed payload - not a raw dict, deliberately, so it can't be wired into the wrong socket and fail somewhere far away), preview_overlay (red tint over the mask, green box for the crop rect - the fastest way to see whether the crop is where you think it is), and info.
One batch behaviour worth knowing: the batch gets one target size, taken from the largest region in it, because a single tensor can't hold differently-sized crops. Frames with no mask get a centred full-frame window rather than being dropped, so the batch length survives.
Install
ComfyUI Manager → search "CustomNodePacks", or:
cd ComfyUI/custom_nodes
git clone https://github.com/Code2Collapse/ComfyUI-CustomNodePacks
Restart ComfyUI. Install opencv-python if you can - hole filling uses it, and the torch fallback is honest about its limits. No models, no VRAM. And the README's standing warning: check pip list rather than running pip install -r requirements.txt blind, since it lists packages ComfyUI already provides.
Common issues
- "It cropped the whole frame." The mask was empty (or effectively empty) and
no_mask_modedid its job. Check the info string. - The stitched result is offset by a few pixels. Divisibility mismatch or a resized full image. Check
force_divisibilityand make sureSmart Image Stitchis gettingresize_full_image_outputright. - A hole survived in the output. The image was regenerated with the hole as background because hole filling was off, or the hole was wider than the torch fallback's limit. Turn
patch_mask_holeson and install OpenCV.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| mask | MASK | — | |
| resolution_mode | COMBO | Automatic | 2 options: Automatic, Manual |
| max_resolution | INT | 2048256–16384 | Upper limit on the longest side. A crop larger than this is scaled DOWN to fit. |
| min_resolution | INT | 76864–2048 | Lower limit on the shortest side. A crop smaller than this is scaled UP, which is the whole point of cropping - a 200px face gets the model's full attention. |
| manual_width | INT | 102464–8192 | — |
| manual_height | INT | 102464–8192 | — |
| mask_grow_pixels | INT | 32-1024–1024 | Grow (or shrink) the mask before measuring the crop, so the model sees context around the region rather than a tight cut-out. |
| patch_mask_holes | BOOLEAN | true | Close gaps and fill enclosed holes. A subject mask with holes regenerates those holes as background - the hole-in-the-face result. |
| no_mask_mode | COMBO | Bypass | What to do when the mask is empty. Bypass passes the image through untouched, which is the safe default for a batch where only some frames have a mask. |
| force_divisibility | COMBO | 128 | Snap output dimensions to this multiple. A VAE silently pads anything else, which shifts the crop by a few pixels and breaks the stitch. |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| crop_image | IMAGE | — |
| crop_mask | MASK | — |
| stitcher | STITCHER | — |
| preview_overlay | IMAGE | — |
| info | STRING | — |