DOGMA Native Clustered Mask Crops
Cutting a 4K frame into crops that actually line up when you paste them back
- image
- masks
- crops
- crop_masks
- stitch
This is the node that decides what "a repair job" even is. DOGMANativeClusteredMaskCrops turns your stacked masks into a small number of crops - one per region worth a generation pass - and emits the metadata the stitch node needs to put each one back where it came from.
Why clustering, not one-crop-per-mask
Naive detailing is one crop per detected instance. That's fine for three faces and terrible for a street with forty cars and a crowd - forty generation passes, each with its own prompt and its own chance to drift.
The better unit is the scene region: three cars parked nose to tail are one job, since they're touching and one pass at that crop sees all three. The far wall is another job. This node works out those regions for you.
How it groups
It takes each mask's bounding box, throws away anything smaller than min_mask_area, then does a union-find pass over what's left: two boxes merge if they're within merge_distance pixels of each other (default 512). That's a distance between boxes, not an overlap requirement - which is the parameter that changes your output most. Big values pull the whole frame into one enormous crop; small values give you back instance-per-crop.
Groups are then sorted by total masked area, split if a single group would exceed max_crop_side (default 4096), and cut down to max_groups (default 12). Each surviving group's bounding box is expanded by context_factor - 1.15 means 15% more context on each side, so the model can see what the object is next to - with min_crop_side (1024) as a floor so a small repair still gets a decent canvas of surrounding pixels to blend into.
The detail that makes the stitch work
Every crop's rectangle and its width and height are snapped to multiples of 16. That's not tidiness, it's alignment: a diffusion model whose latents are divided by 8 or 16 needs crop origins that land on that grid, or adjacent crops land on different latent cells and the seam shows no matter how well you feather. The pack has a whole node (DOGMAAlignedDacPrepareV35) for the same problem in its tiled-upscale path.
And it publishes the geometry: the stitch output carries each crop's source coordinates, source size, group id and member mask indices, including a noop flag. The matching stitch node reads that and composites the patch back at the right offset. You don't compute coordinates; you pass the list.
The no-op sentinel, which you'll meet on day one
If nothing passes min_mask_area, the node does not error. It returns one crop - a centred square, clamped to the image and snapped to 16 - with a zero mask and a stitch entry marked noop. Downstream, a zero mask means nothing is selected, so nothing gets inpainted and the stitch node skips it. A category that isn't in the frame costs one wasted crop-shaped tensor and no GPU time. That's what makes a "run all six categories on every image" graph viable.
Inputs and outputs
image, masks, and eight settings: merge_distance, context_factor, min_mask_area, min_crop_side, max_crop_side, max_groups, mask_threshold (default 0.5, the cutoff for deciding a pixel is in the mask), plus nothing else. Outputs are crops (IMAGE, a list), crop_masks (MASK, a list) and stitch (the pack's DOGMA_STITCH list).
The word Native in the name matters: crops are cut at source resolution and not resized. If you feed it a 4K frame, every crop is native 4K pixels - which is usually what you want for detail work, and a reason to check your VRAM before feeding it a 6K scan.
Install
ComfyUI Manager → search DOGMA Nodes, or:
cd ComfyUI/custom_nodes
git clone https://github.com/axior/ComfyUI-DOGMA-Nodes
Restart. No pip installs - the pack declares no dependencies - and no model downloads. Everything here is tensor cropping and bounding-box arithmetic.
Where it bites
The outputs are lists, and the pack's own downstream nodes know that; core ComfyUI crop-and-paste nodes don't take a DOGMA_STITCH. That's why each crops node in this pack has a matching stitch node, and why the VLM barrier exists to carry the lists across a model swap. Mixing families is where people lose an afternoon.
merge_distance at its 512 default is aggressive on a 4K frame - it's a fifth of a 2560-wide image, so distant objects end up sharing a crop. Drop it to 128–256 if you want more, smaller, more independent jobs; raise it if you're hitting max_groups and losing regions to the cap.
And max_groups silently truncates. Groups are ranked by masked area, so the smallest categories - the pigeons, the signage - are the ones that quietly vanish. If a category you expected shows no crop at all, that cap is the first thing to check.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| masks | MASK | — | |
| merge_distance | INT | 5120–4096 | — |
| context_factor | FLOAT | 1.151–3 | — |
| min_mask_area | INT | 121–1000000 | — |
| min_crop_side | INT | 1024128–8192 | — |
| max_crop_side | INT | 4096512–8192 | — |
| max_groups | INT | 121–128 | — |
| mask_threshold | FLOAT | 0.500.01–0.99 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| crops | IMAGE | — |
| crop_masks | MASK | — |
| stitch | DOGMA_STITCH | — |