Nodes/ComfyUI-DAELab-Custom-Nodes-Library/Badge Material Region Merge V1 (DAELab)
ComfyUI Node

Badge Material Region Merge V1 (DAELab)

Four material edits, zero overlap, one badge

By TeutonicMepheles·Created 4 months ago·Updated 6 days ago· 0
Badge Material Region Merge V1 (DAELab)
  • base_image
  • region_1_image
  • region_1_mask
  • region_2_image
  • region_2_mask
  • region_3_image
  • region_3_mask
  • region_4_image
  • region_4_mask
  • image
  • report
◄region_1_status—►
◄region_2_status—►
◄region_3_status—►
◄region_4_status—►

What it is and why you'd reach for it

Once you've stopped doing four material regions as one opaque loop and split them into four visible channels, something has to put the badge back together. That's this node - and the interesting thing about it is how little it's willing to forgive.

Four region edits against one immutable base gives you four full-size candidate images that are each correct in exactly one place. Merging them naively (paste region 2 over region 1) means every downstream pixel depends on wiring order. Merging them with a weighted average means a boundary between two materials gets a band of neither. And if two masks overlap at all, whichever way you resolve it, one material silently loses. Badge Material Region Merge V1's answer: refuse to merge an overlap.

How it works

Twelve required inputs, no widgets - four triples of region_N_image, region_N_mask, region_N_status. All images must match base_image's canvas exactly (no resizing here); masks are broadcast to the batch.

The composite is straightforward: start from the base, and for each channel do result = result * (1 - weight) + image * weight. Outside all masks, weight is zero, so the base pixels are carried through bit-identically. The node then verifies that: outside_max_abs_diff is computed over every pixel with zero total weight, and it reports as a hard 0 in a working graph.

Then the part that earns the node its keep. It accumulates total weight across channels and raises if the maximum exceeds 1.0 by more than a hair:

Visible material channel masks overlap by 0.00000012; merge stopped.

In other words, mutual exclusivity is enforced, not documented. If two of your material rules both match the same source colour, you find out here instead of discovering a half-applied material three renders later. Fix it upstream in the material region configuration - its diagnostic preview shows overlapping matches - rather than trimming masks by hand.

report returns the audit: how many channels actually used a GPT node, the maximum channel overlap, the outside diff, the native node type, a billing note that cache hits don't cost anything, and each channel's status blob. That count is the most operationally useful number in the pack's material branch: four channels wired, two active regions, and the report says 2.

Inputs and outputs that matter

base_image plus the four triples. The status strings aren't optional decoration - the merge needs them to report GPT usage, and because they're force-inputs, an unwired slot is a connection error rather than a silent zero. Unused slots get the zero-mask, base-image output from their channel.

Outputs: image is the merged badge, ready for the height material pass to continue or for the studio composite. report is the JSON above.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/TeutonicMepheles/ComfyUI-DAELab-Custom-Nodes-Library

Restart ComfyUI. This one is a V3-schema node, so an older core fails to register it (No module named 'comfy_api' - update core, don't pip-install anything by that name). The module imports OpenCV; the pack's requirements.txt doesn't list it, so pip install opencv-python-headless if the node is missing from the menu.

Common issues

  • masks overlap … merge stopped. Two material regions claim the same pixels. Look at the region node's diagnostic preview, tighten the colour thresholds, or delete a rule.
  • region_N_image must match base_image dimensions. A GPT channel returned a different size - usually because a channel's constraint node fell back to a resized candidate. Every input to this node has to be 1024²-native.
  • You wired three channels and left the fourth dangling. The status inputs are forced, so the graph won't validate. Wire the fourth channel even if its slot is empty; it'll return a zero mask and add nothing.
  • The merged badge has a visible band at a material boundary. Overlap is impossible here, so what you're seeing is the constraint node's zero-weight guard ring against a sharply different base colour. That's a design decision, not a merge bug.
CategoryDAELab/Badge/Strict

Inputs (13)

NameTypeDefaultDescription
base_imageIMAGE—
region_1_imageIMAGE—
region_1_maskMASK—
region_1_statusSTRING—
region_2_imageIMAGE—
region_2_maskMASK—
region_2_statusSTRING—
region_3_imageIMAGE—
region_3_maskMASK—
region_3_statusSTRING—
region_4_imageIMAGE—
region_4_maskMASK—
region_4_statusSTRING—

Outputs (2)

NameTypeDescription
imageIMAGE—
reportSTRING—