Badge 8.7 Material Mask Alignment (DAELab)
Snapping an old mask onto the new render
- source_image
- target_image
- source_mask
- target_mask
- color_reference
- alignment_report
What this is for
You drew a mask on the flat artwork. Then the model rendered the badge and shifted the whole thing four pixels left, scaled it 3% and nudged the outline. Your mask is now pointing at the wrong pixels. Every masked edit from here on is off by that drift, and if you feed the paid edit a mask that's offset, you get a paid edit that's offset.
Badge 8.7 Material Mask Alignment re-registers that mask into the generated image's coordinate system. You give it the flat source, the render, and the source-space mask; you get back a mask expressed in render space, a color-reference image, and a small report card saying how good the fit was.
One honest caveat before you get attached: as of the current pack, the 8.7 workflow entry point no longer calls this node - it's kept registered so old saved workflows keep loading. If you're building fresh, the pack points you at Badge Render-Space Mask Align V1, which is the fuller version with QA overlays and a per-color ID map. This one is the small, blunt ancestor: translation, uniform scale, rotation deliberately locked.
How it works
Per image in the batch it does four things.
It extracts the badge silhouette from both images by sampling a 24-pixel border to estimate the background, then taking what isn't background as foreground. If either image yields an empty silhouette it stops with an error rather than guessing.
It fits a similarity transform from source foreground to target foreground, with the maximum rotation clamped to 0 and scale delta capped around 0.35. The comment in the source is refreshingly candid about why rotation is locked: a round pin silhouette can't tell you its own rotation, so letting the fitter search for an angle will happily rotate your inner regions for no reason.
If the fit is worse than an IoU of 0.65 it refuses - that's the "the render didn't land anywhere near the design, don't spend money on this" gate. Otherwise it warps your mask with nearest-neighbour (you do not want a resampled mask), intersects it with the target foreground, then runs a watershed snap so the mask edge follows the actual edge in the render instead of the warped approximation. Under 16 surviving pixels and it errors out.
Finally it builds color_reference: a copy of the render with the snapped region repainted in the median color of your selected source pixels. That's the preserve-color hint - it tells a downstream model "whatever you do with surface, this is the hue that region should end up".
The inputs and outputs
Three inputs, no widgets: source_image (the flat artwork), target_image (the generated render - this is the coordinate authority), source_mask (your selection in source space). Images must be the same shape and the mask must match the canvas; batch size has to line up.
Three outputs:
target_mask- the snapped mask in render space. Wire into your edit node's mask input.color_reference- the render with the region tinted to its source hue. Use as the preserve-color reference.alignment_report- JSON withiou,source_pixels,target_pixelsper image. Read this. IoU down at 0.66 means the geometry is marginal even though it passed.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/TeutonicMepheles/ComfyUI-DAELab-Custom-Nodes-Library.git
# restart ComfyUI
The node imports cv2 (OpenCV) at call time and pulls its registration helpers from the pack's badge_render_space_mask module, which is where the scipy/cv2 heavy lifting lives. Neither is declared in the pack's requirements.txt, since ComfyUI core usually provides them. If you get ModuleNotFoundError: No module named 'cv2':
ComfyUI/python_embeded/python.exe -m pip install opencv-python-headless scipy
Where people get burned
Expecting it to fix real deformation. It's translation, scale and a boundary snap - the README is explicit that it does not recover structure the model deleted or redesigned. If your render moved a pointer, no amount of registration will put it back; fix the prompt or the reference.
Background extraction assumes a fairly clean, low-transparency backdrop. A photographic backdrop with gradient and grain will produce a nonsense silhouette, and then you'll hit the IoU rejection with an error that looks like a mask problem but is a background problem.
And the classic: passing a source mask drawn on a previous render rather than on the flat art. The node assumes source space means the design. Register from the wrong authority and everything downstream inherits the error silently, because a plausible-looking mask is still plausible-looking when it's wrong.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| source_image | IMAGE | — | |
| target_image | IMAGE | — | |
| source_mask | MASK | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| target_mask | MASK | — |
| color_reference | IMAGE | — |
| alignment_report | STRING | — |