Mask To Points (ZIM)
Turn your brush strokes into clicks
- mask
- points
Mask To Points (ZIM) is the plumbing node that makes ZIM Segmenter usable without hand-typing coordinates. The ZIM matting model steers by clicks - positive points say "include this", negative points say "exclude this" - but nobody wants to type [[320, 210]] into a text box. So this node takes the mask you painted in ComfyUI's mask editor, finds the center of each painted region, and hands ZIM Segmenter a ready-to-use point list.
It's part of the same judian17/ComfyUI_ZIM pack as ZIM Segmenter, so install is the pack install - ComfyUI Manager, search "ComfyUI_ZIM", or:
cd ComfyUI/custom_nodes
git clone https://github.com/judian17/ComfyUI_ZIM
Then restart. Dependencies are zim_anything, onnxruntime-gpu, Pillow and a pinned numpy<=1.26.4 - nothing exotic. Note this node itself runs entirely in Python with OpenCV (which ComfyUI already ships); it doesn't touch the ZIM model at all. That's worth knowing because it means MaskToPoints works instantly with zero model downloads.
Inputs and output
One input, one output. Feed it any mask (MASK type) - painted in the mask editor, drawn in an image editor and loaded, or produced by another node. It outputs points, a single string containing JSON like [{"x": 100, "y": 150}, {"x": 220, "y": 90}], one point per disconnected white area of the mask.
Wire that string straight into ZIM Segmenter's positive_points input and queue. That's the whole job.
How it actually works
The mechanism is straightforward and worth understanding because it explains the failure modes. The mask is thresholded to a clean binary image, then OpenCV finds the contours of every white region. Each region's bounding rectangle gives a center point. Multiple blobs in your mask → multiple points, one per blob. Same image, same ZIM model - the segmenter will then get one positive click per object you painted over.
Gotchas
Two things to watch. First, the node only processes the first mask in the batch - a batched mask list silently drops everything after index zero. Second, an empty or all-black mask doesn't error; it returns [], which ZIM Segmenter then rejects with its "at least one positive point... must be provided" error. If you painted your region and the segmenter complains about missing points, your mask probably came through empty - check the preview before blaming the node.
There's also a subtler use of this: because the output is just a JSON string, you can chain it anywhere a point list is accepted, or even swap it into workflows that generate mask-based points for other promptable segmenters. For ZIM itself though, the path the author actually uses in the README's example workflows is mask editor → MaskToPoints → ZIM Segmenter. It's a tiny node, but it's the difference between "I clicked" and "I typed coordinates".
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| mask | MASK | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| points | STRING | — |