Unblend Assign Masks (SAM → CHARn by points)
Your SAM masks are anonymous. This node names them.
- masks
- char_masks
- mask_preview
- info
If you've ever wired a SAM node into a multi-character workflow, you know the feeling: the masks come out gorgeous, clean, instance-perfect - and completely anonymous. Nothing tells you which blob is character one and which is character two. UnblendAssignMasks exists to fix exactly that gap, and it does one thing, quietly.
It's the bridge in the Unblend two-pass pipeline. The composition pass (Unblend Dynamic Sampler) generates two separated characters. An external SAM node produces clean instance masks - great geometry, zero identities. Assign Masks labels them. Its display name spells out the whole job: SAM → CHARn by points.
How it works
You feed it the mask stack and a list of char_points - normalized 0..1 coordinates in CHAR1..CHARn order. "0.25,0.5; 0.75,0.5" means CHAR1 sits left-center, CHAR2 right-center. For each point, the node finds the instance mask that contains it and assigns that mask to the matching character. That's the whole mechanism, and it's deliberately dumb - which is the point. SAM decides where the bodies are; your points decide who's who. Because assignment happens by point rather than by comparing mask shapes, it survives occlusion: two characters can be hugging and the anchor still picks the right silhouette.
There's a solo fallback so the node doesn't break the graph on a single subject: one point → one character, and with no points at all it just takes the largest mask as CHAR1.
The inputs that matter
masks- the MASK stack from your SAM / segmentation node. SAM 2 (kijai) and SAM 3 packs both work, per the README.char_points- the anchors, in character order. This is the whole job, so it's also where mistakes live: get a point wrong and two masks silently swap identities.
Everything else is output. char_masks is the ordered, per-character mask stack that Sequential Refine wants as its input. mask_preview is an image you should glance at exactly once before queueing a hundred refinements. info is a text log telling you precisely what got assigned to what (CHAR2<-mask#3 and the like).
Install
Install the whole pack once - this node ships inside it. ComfyUI Manager is the easy path: search "Unblend", Install, restart, and the Python dependencies resolve automatically. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/LatentDesireAI/ComfyUI-Unblend
pip install -r ComfyUI-Unblend/requirements.txt
Then restart ComfyUI (Windows portable: python_embeded\python.exe -m pip install -r ComfyUI-Unblend\requirements.txt).
One thing to know before you wire this in: SAM is not part of ComfyUI core. Install a segment-anything pack through the Manager first, or Assign Masks has nothing to chew on. And keep expectations right-sized - this node only labels masks. The separation happens upstream in the Dynamic Sampler, the detail work happens downstream in Sequential Refine. This is the quiet middle step, and that's fine.
When things go wrong
Read the info string; it's genuinely informative. CHAR1: mask not found means your point landed on background or inside another character's mask - nudge the coordinate. Two characters swapped means your points are in the wrong order (or the char_points string doesn't match the prompt's CHAR order). And if you get "no masks and no points", you've wired in an empty stack. The mask_preview is your friend here: one glance beats a paragraph of debugging.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| masks | MASK | — | |
| char_points | STRING | 0.25,0.5; 0.75,0.5 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| char_masks | MASK | — |
| mask_preview | IMAGE | — |
| info | STRING | — |