ZML_遮罩分离-三
One mask, three outputs, plus a leftover bucket for what doesn't fit
- 输入遮罩
- 遮罩1_靠左
- 遮罩2_中间
- 遮罩3_靠右
- 剩余遮罩
The three-way version of ZML's mask-separation family. Where ZML_MaskSeparateDistance gives you left and right, this one tries to hand you left, middle, and right - and when the mask doesn't cooperate, it's honest about it and dumps everything into a 剩余遮罩 (remaining mask) output instead of guessing wrong.
The mechanism is the same connected-components approach as its two-way sibling: the mask is thresholded, blobs are found with OpenCV, small ones get filtered by 最小面积比例, and the survivors are sorted left-to-right by centroid position. Then instead of finding one split, it finds the two largest gaps between consecutive pieces and checks them against two separate thresholds.
Two thresholds, not one
That's the part to wrap your head around, because it's the difference between this node and just running the two-way version twice:
- 分离阈值_1 gates the first (leftmost) split.
- 分离阈值_2 gates the second split.
If you have three distinct groups of pieces and both gaps clear their thresholds, you get 遮罩1_靠左, 遮罩2_中间, and 遮罩3_靠右 - three clean masks. But the node is defensive by design:
- One significant piece → everything to 遮罩1, others empty.
- Two pieces → they split between 遮罩1 and 遮罩2, middle and right stay empty.
- Three or more pieces but a gap too small for its threshold → all the pieces land in
剩余遮罩, and the three main outputs stay empty.
That last behavior is the thing that surprises people. You'd think "failed to split" would mean "everything on the left," like the two-way node does. Instead this node parks the whole thing in the remainder output. It's actually the more useful contract - you can chain 剩余遮罩 into another separator, or treat "something landed in 剩余遮罩" as a signal that the mask needs cleaning up first.
The inputs
- 输入遮罩 - the MASK to separate.
- 分离阈值_1 / 分离阈值_2 (0–1, default 0.1 each) - minimum gap, as a fraction of image width, for each split point. Tune 阈值_1 to be stricter about the left split than the right one if your layout is asymmetric.
- 最小面积比例 (0–1, default 0.01) - ignore blobs smaller than this fraction of the image.
Outputs are the three 遮罩* masks plus 剩余遮罩, all full resolution and ready to wire into any mask consumer - regional inpaint, per-region detailers, SetLatentNoiseMask, whatever your workflow does with a split mask.
Install & the usual pack caveats
It's part of ComfyUI-ZML-Image:
cd ComfyUI/custom_nodes
git clone https://github.com/zml-w/ComfyUI-ZML-Image
# restart ComfyUI
Or search "ComfyUI-ZML-Image" in ComfyUI Manager. The pack needs opencv-python (this node won't run without it) plus the usual numpy/torch/Pillow - Manager handles it. The UI is Chinese-first; English speakers should grab the translation patch at https://github.com/zml-w/ZZZ_ZML_English_Patch.
Same one-person-project caveat as every node in this pack: the author builds for his own workflows and accepts issues/PRs happily. This one is a recent addition and has fewer battle-tested community workflows behind it than the pack's text or lora nodes - if a split behaves oddly, the first thing to check is whether your mask's regions are actually separate blobs, because no connected-components splitter can divide a single connected region.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| 输入遮罩 | MASK | — | |
| 分离阈值_1 | FLOAT | 0.100–1 | — |
| 分离阈值_2 | FLOAT | 0.100–1 | — |
| 最小面积比例 | FLOAT | 0.0100–1 | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| 遮罩1_靠左 | MASK | — |
| 遮罩2_中间 | MASK | — |
| 遮罩3_靠右 | MASK | — |
| 剩余遮罩 | MASK | — |