DOGMA Protect Semantic Masks v13
Stop the road pass from eating your cars
- mask_1
- mask_2
- mask_3
- mask_4
- mask_5
- mask_6
- mask_1
- mask_2
- mask_3
- mask_4
- mask_5
- mask_6
- summary
Six masks in, six masks out, and the trick is what got removed. DOGMAProtectedMasksV13 stops your broad-surface passes - road, vegetation, architecture, sky, water - from overlapping the higher-value discrete objects sitting inside them.
It's a genuinely underrated class of bug. Your SAM run returns a big confident road mask and a dozen small car masks. The road crop is generated at low denoise and lightly cleaned; the car crops get repaired properly. But the road mask's boundary ran through the cars, because SAM's road region doesn't know to stop at a wheel. Now two passes overlap, the later one wins, and you've got a half-repaired car with a smeared arch. Nobody looks at the road pass as the culprit.
How it works
mask_1 through mask_6 are your MASKs, category_1 through category_6 are the matching strings from your planner, and protect_radius (default 14, 0–128) is how far the protection extends past the blocking mask.
Each incoming mask is collapsed to a single plane if it's batched, then all six are normalised to the same resolution - the node's own comment notes it has no reference_image input, so it can only use the masks to agree on a size. Each category is then mapped to a family: roadway people, sidewalk people, signage, street objects, vehicles, people, architecture, vegetation, road, sky, water, animals, or a plain other. That family mapping is what makes the node slot-agnostic - it doesn't care which of the six sockets holds which class.
Then the subtraction. Broad families carry a blocker list:
- road protects against vehicles, roadway people, sidewalk people, people, signage, street objects and animals
- vegetation protects against all of those plus architecture
- architecture protects against vehicles, people, signage, street objects and animals
- sky protects against architecture, signage, street objects, vehicles and people
- water protects against vehicles, people and animals
Any mask whose family is on the list gets unioned, dilated by protect_radius with a max-pool, and multiplied out of the surface mask as mask × (1 − protection). Objects are never subtracted from each other, so your car mask comes out untouched; the road mask comes back with car-shaped holes. Outputs are mask_1…mask_6 plus a summary listing exactly what each slot was protected from - which is the line to read when a pass mysteriously changed nothing.
Install
ComfyUI Manager → search DOGMA Nodes, or:
cd ComfyUI/custom_nodes
git clone https://github.com/axior/ComfyUI-DOGMA-Nodes
# restart ComfyUI
No Python dependencies - masks and max-pools, nothing else. Undocumented in the README, like the rest of the semantic family.
Gotchas
Categories are guessed from text. The family classifier is substring matching on the category string. Call something "objects" and it lands in other, which is never protected and never protects. If your road pass keeps eating cars, read summary first: it prints slot 1 road: protected from vehicles or, if the mapping failed, slot 1 other: no protection subtraction.
protect_radius too high carves holes you can see. A 128px dilation around every car will gouge wide ellipses out of the road mask, and then your road pass simply doesn't smooth near cars - which looks like blotchy asphalt. 12–20 is the useful range; v13 defaults to 14.
All six masks must be the same size in the end. They're resized to the largest one, which is fine for masks derived from the same SAM run, and wrong if you mix sources at different aspect ratios. Resize before you get here, not after.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| mask_1 | MASK | — | |
| category_1 | STRING | — | |
| mask_2 | MASK | — | |
| category_2 | STRING | — | |
| mask_3 | MASK | — | |
| category_3 | STRING | — | |
| mask_4 | MASK | — | |
| category_4 | STRING | — | |
| mask_5 | MASK | — | |
| category_5 | STRING | — | |
| mask_6 | MASK | — | |
| category_6 | STRING | — | |
| protect_radius | INT | 140–128 | — |
Outputs (7)
| Name | Type | Description |
|---|---|---|
| mask_1 | MASK | — |
| mask_2 | MASK | — |
| mask_3 | MASK | — |
| mask_4 | MASK | — |
| mask_5 | MASK | — |
| mask_6 | MASK | — |
| summary | STRING | — |