Mask Analyze (Swwan)
Turn a blob of mask into numbers you can branch on
- mask
- mask
- canvas_width
- canvas_height
- mask_width
- mask_height
- center_x
- center_y
- has_mask
What it's for
Most mask nodes change pixels. This one measures them. Feed it a mask and you get back the canvas size, the size and centre of the region that isn't black, and a boolean saying whether the region is big enough to be worth bothering with.
That boolean is the reason to install it. In an automated workflow you constantly need "did the detector actually find a face, or is this mask empty?" - and has_mask answers it without a second detector pass. Wire it into a switch node and you can route an empty frame straight past the whole detailing chain instead of burning a sampler pass on nothing.
It's one of the pack's five Advanced mask tools, adapted from Goohaitools, and - this is the good part - it runs no model at all. No SAM, no YOLO, no Ultralytics. It's arithmetic on a tensor you already have.
What you get out
The mask output is not your input passed through unchanged: it's a filled-in rectangle covering the analysed region. Concretely, the node finds the bounding box of everything ≥ 0.5 (using the first mask in the batch), applies your percentage expansion, and returns a mask that's solid 1.0 inside the resulting box and 0 outside. That's a region mask, not a segmentation - pass your original mask through separately if you need the shape.
If the mask is empty, it falls back to reference behaviour: the input mask comes back and the geometry outputs report the full canvas with the centre of the frame - no error, just a "nothing here" answer. Which is precisely why has_mask exists.
The four optional knobs - top_percent, bottom_percent, left_percent, right_percent, all defaulting to 0 - grow the box outward by a percentage of the region's own size, not of the canvas. Positive values pad; negative values shrink, and the code has a safety catch that clamps the total shrink to 90% of the region so you can't collapse it to nothing (and if the shrink would invert the box, it quietly reverts to the unshrunk bounds). A positive top_percent=50 on a 200px-tall mask adds 100px of headroom, which is usually what you want before cropping for a detail pass.
minimum_area_percent (default 3.0, range 0–10) is the gate for has_mask: it's the fraction of the whole canvas the detected area must cover, counted across all masks in the batch at > 0.5. Set it to 0 and any single lit pixel makes has_mask true - useful as a "did the mask survive upstream" check, useless as a quality filter.
Alongside the mask you get canvas_width, canvas_height, mask_width, mask_height, center_x, center_y and has_mask. All integers except the boolean, so they drop straight into maths nodes, seeds, filename templates or a crop rectangle you build by hand.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/aining2022/ComfyUI_Swwan
cd ComfyUI_Swwan
python -m pip install -r requirements.txt
Restart, refresh, search Swwan. Needs numpy and torch only - this is one of the pack's model-free tools, so a CPU-only install runs it fine. Note the pack's headline claim is worth trusting most of the way: it genuinely doesn't need Impact Pack, KJNodes or LayerStyle installed for the mask tools, and its Impact-style mask tooling is reimplemented rather than imported. But it isn't dependency-free of everything: Load Videos From Folder still wants VideoHelperSuite.
Common issues
Mask Analyze expects a non-empty [B,H,W] mask batch. You fed it something with a zero-length batch or a 4D [B,1,H,W] mask that didn't squeeze. Some upstream nodes emit the extra channel dimension; a batch-slice or squeeze node in front fixes it.
has_mask is always false. Either the mask genuinely has nothing above 0.5, or minimum_area_percent is set high relative to a small region. Try 0 to distinguish the two cases.
The output mask is a rectangle. By design. If you wanted the original silhouette, take a second wire off the mask source.
The centre coordinates are odd numbers. They're an integer floor of the box centre. For even-only geometry (common before a latent round-trip), pair this with a maths node and round down to a multiple of 8.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| mask | MASK | — | |
| top_percentopt | INT | 0-90–1000 | — |
| bottom_percentopt | INT | 0-90–1000 | — |
| left_percentopt | INT | 0-90–1000 | — |
| right_percentopt | INT | 0-90–1000 | — |
| minimum_area_percentopt | FLOAT | 3.00–10 | — |
Outputs (8)
| Name | Type | Description |
|---|---|---|
| mask | MASK | — |
| canvas_width | INT | — |
| canvas_height | INT | — |
| mask_width | INT | — |
| mask_height | INT | — |
| center_x | INT | — |
| center_y | INT | — |
| has_mask | BOOLEAN | — |