DOGMA Semantic Macro Crops v10
One union mask, a handful of big crops, no per-instance loop
- image
- masks
- crops
- crop_masks
- stitch
- info
What it is
The step between "SAM found your objects" and "something re-renders them." DOGMASemanticMacroCropsV10 takes your image plus the masks for one semantic category, and emits a small number of large, resized crops with matching masks and the metadata to put them back.
The name is the design argument. Macro, not per-instance. A classic detailer crops each detected object separately and re-renders it in isolation - that's what FaceDetailer does for faces, and it works because each face is its own little universe. Do that to 140 windows and 80 cars in a 4K street scene and you get hundreds of tiny samples, each one re-imagined with no idea what its neighbours look like. DOGMA's bet is that semantic regions - clusters of like objects with their surroundings - produce more coherent results, with a fraction of the compute.
It's the pack's answer to the seam problem too: the KB's detailing doc makes the point that crops are only as good as the paste-back, and the paste-back is only invisible if the crop carried enough neighbouring context to match. Big regions with 192px of context rings carry much more of that than tight object crops do.
How it works
The mask handling is the clever bit. All incoming masks are max-combined into a single union, thresholded at mask_threshold, then downsampled to a 512px preview before any analysis. On that proxy:
group_radiusbecomes a grayscale dilation - a max-pool with a kernel of2r+1- which merges instances that sit near each other into one blob.- Connected components are found on the dilated proxy, each giving a bounding box in proxy space.
- Boxes are mapped back to source coordinates and expanded by
context_pxon each side. - If there are more regions than
max_crops, the two closest are merged, repeatedly, until the count fits.
That last part is the important one. Merging is by bounding-box gap, so the two regions joined are always the nearest pair. Then each region is split into ownership windows - the inner rectangle that region is responsible for, with context-only strips around it. Ownership windows don't overlap, which is the mechanism that stops the same semantic pixels from being edited twice when neighbouring crops share context.
Crops are padded out to 16px alignment, resized so the long side hits target_long_side, and the local mask is resized along with them.
Inputs and outputs
image and masks (one image, one or more masks). Then six knobs:
group_radius(default 480) - how aggressively to fuse nearby instances into one region. This is the dial that decides whether "all the cars on this street" is one crop or six.context_px(default 192) - the context ring around each region. More context means better blending and more sampling cost.max_source_side(default 3600) - the largest source region allowed before it's split.target_long_side(default 1344) - what the model actually sees. This is your VRAM dial.max_crops(default 6) - the budget.mask_threshold(default 0.5) - how confident a mask pixel must be to count.
Outputs are three parallel lists plus a string: crops (IMAGE), crop_masks (MASK), stitch (DOGMA_STITCH - the x/y/width/height metadata each patch needs to be pasted back), and info. Crops go to your editing model, masks localize the edit, stitch goes into a stitch node such as DOGMAStitchCrops.
There's a deliberate no-op path: if the union mask is empty, you get one centre square, a zero mask, a region marked noop: True, and an info string saying "safe no-op." The stitch nodes skip noop entries, so a category that detected nothing doesn't break your graph.
Install
ComfyUI Manager → search DOGMA Nodes, or:
cd ComfyUI/custom_nodes
git clone https://github.com/axior/ComfyUI-DOGMA-Nodes
# restart ComfyUI
No dependencies, no model files, no API keys - requirements.txt is an empty-of-content comment and the code is PyTorch plus numpy, which ComfyUI already ships.
Gotchas
- It will raise rather than drop work. If the region set needs more split crops than
max_cropsallows, you get aValueErrortelling you to raisemax_source_sideormax_crops- explicitly, "No region was discarded." That's a design choice: silent dropping in a detailer means silently un-repaired areas. group_radiusis applied at proxy scale internally, so a value of 480 doesn't mean 480px on a 6K master. It's a region-grouping hint, not a pixel distance.- The pack has no community footprint - zero reddit threads name it - and the README documents only the WAN VACE prep nodes and samplers, so there's no tutorial to fall back on.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| masks | MASK | — | |
| group_radius | INT | 4800–2048 | — |
| context_px | INT | 1920–2048 | — |
| max_source_side | INT | 3600512–8192 | — |
| target_long_side | INT | 1344512–2048 | — |
| max_crops | INT | 61–24 | — |
| mask_threshold | FLOAT | 0.500.01–0.99 | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| crops | IMAGE | — |
| crop_masks | MASK | — |
| stitch | DOGMA_STITCH | — |
| info | STRING | — |