Nodes/ComfyUI CV/cv2.hasNonZero
ComfyUI Node

cv2.hasNonZero

Is there anything in this mask? cv2.hasNonZero, the cheapest branch in your graph

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
cv2.hasNonZero
  • src
  • bool

One input, one boolean out: does this array contain any pixel that is not zero? That is the entire node, and it is more useful than it sounds, because "empty mask" is the single most common silent failure in a ComfyUI detection pipeline. A threshold that found nothing, a colour range that matched nothing, a YOLO pass over an image with no faces - all of them hand you a mask of zeros, and downstream nodes will happily consume that all-zero mask and produce a slightly-wrong image with no error at all.

cv2.hasNonZero is the gate that lets you notice. It is a plumbing node in the truest sense: no pixels touched, one comparison, and the boolean it emits is what you branch on (comfyui-node-plumbing.md is the map of that whole layer, and it is the layer you are working in here).

How it works

OpenCV's hasNonZero(src) scans a single-channel array and returns true the moment it finds a non-zero element. In practice on binary masks, that means "any white pixel at all." Note the small but real distinction from its sibling cv2.countNonZero, which is also registered in this pack: that one gives you the pixel count as an integer, which you want when "how much" matters - an overlay covering 0.4% of the frame is technically non-empty but probably noise. Use hasNonZero for a yes/no gate, countNonZero when you are about to threshold the area.

It is cheap. Vectorised, no allocation, faster than the node's own schema validation.

Inputs and output

  • src - a single-channel array. The socket accepts an IMAGE, a MASK, or an NPARRAY, and the generic tooltip says IMAGE/MASK frame 0 of a batch. But this function is not in the pack's grayscale-conversion list, so a 3-channel IMAGE handed straight in goes to cv2 as three channels and fails - cv2 wants one plane. Feed it a MASK (which is what you have, if you are asking "did the detector find anything"), or a single-channel NPARRAY. If you must start from a colour IMAGE, run it through the raw cv2.cvtColor node or cv2.inRange first.

Output is a single bool. On a multi-frame input it reflects frame 0 only; per-frame emptiness for a whole batch needs an explicit loop or a split first.

Where does the boolean go? Any conditional node - the community-standard pairing is a first-non-null or if/else node, so that an empty mask routes to a "skip the inpaint" branch instead of producing a soft, pointless re-render. CV GrabCut's success output and the count outputs on the curated Draw/filter nodes are the curated equivalents of this same idea; this node is the general-purpose version you can bolt onto any mask at all.

Install

Manager → search comfyui_cv (bmad4ever), or:

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"

Python ≥ 3.12, a recent ComfyUI on the V3 node API, one dependency, no models.

One wrinkle worth knowing: the pack's node registry is generated from the installed OpenCV build and probes each entry against it, so a function your cv2 does not have simply yields no node. This pack pins opencv-contrib-python-headless~=5.0.0.93. If cv2.hasNonZero is missing from your node list entirely, you are running something older and the wrapper was skipped on purpose rather than failing mysteriously.

When it goes wrong

  • "It says true, but my mask is junk." Non-zero is not the same as meaningful. Antialiased edges, a single stray pixel, or a mask that is 255 everywhere all pass the test. Pair it with countNonZero and an area threshold, or with CV Array Statistic, when you need a sanity check rather than a gate.
  • Three-channel input throws where you expected a boolean. As above: this one never auto-grayscales. The error comes from cv2 with an assertion about channels, which does not obviously point at the node.
  • The boolean is not a mask. Beginners occasionally wire it somewhere expecting pixels. It is a Python bool; it goes to logic nodes, not to VAEEncode or a MaskBlur.
  • Watch the contrib wheel. Every OpenCV distribution shares one site-packages/cv2, so a later pip install opencv-python from another pack can quietly strip the contrib submodules and half this pack's nodes disappear from the UI. tools/repair_opencv_contrib.py --check diagnoses it; --apply fixes it.
Categoryimage/CV/low-level/cv2 H

Inputs (1)

NameTypeDefaultDescription
srcNPARRAY,IMAGE,MASKsingle-channel array. Accepts a ComfyUI IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY. Arithmetic ops (add, multiply, etc.) process the full IMAGE batch when both inputs have the same batch size.

Outputs (1)

NameTypeDescription
boolBOOLEAN—